@bakers-build/conductor 0.0.0-stage → 0.1.0-next.42

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 (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +4 -2
  3. package/dist/src/bakers-project-context.d.ts +12 -0
  4. package/dist/src/bakers-project-context.js +59 -0
  5. package/dist/src/cli/config-plan.d.ts +35 -0
  6. package/dist/src/cli/config-plan.js +1264 -0
  7. package/dist/src/cli/config-schema.d.ts +137 -0
  8. package/dist/src/cli/config-schema.js +239 -0
  9. package/dist/src/cli/config-source-edit.d.ts +17 -0
  10. package/dist/src/cli/config-source-edit.js +95 -0
  11. package/dist/src/cli/config-templates.d.ts +43 -0
  12. package/dist/src/cli/config-templates.js +130 -0
  13. package/dist/src/cli/config-validation.d.ts +12 -0
  14. package/dist/src/cli/config-validation.js +353 -0
  15. package/dist/src/cli/migrate-addon-names.d.ts +82 -0
  16. package/dist/src/cli/migrate-addon-names.js +334 -0
  17. package/dist/src/cli/project-context.d.ts +21 -0
  18. package/dist/src/cli/project-context.js +105 -0
  19. package/dist/src/commands/conductor.d.ts +91 -0
  20. package/dist/src/commands/conductor.js +843 -0
  21. package/dist/src/config.d.ts +109 -0
  22. package/dist/src/config.js +712 -0
  23. package/dist/src/contract.d.ts +13 -0
  24. package/dist/src/contract.js +19 -0
  25. package/dist/src/core/action-queue.d.ts +31 -0
  26. package/dist/src/core/action-queue.js +69 -0
  27. package/dist/src/core/attempt.d.ts +25 -0
  28. package/dist/src/core/attempt.js +41 -0
  29. package/dist/src/core/conductor.d.ts +236 -0
  30. package/dist/src/core/conductor.js +1293 -0
  31. package/dist/src/core/host-key.d.ts +19 -0
  32. package/dist/src/core/host-key.js +27 -0
  33. package/dist/src/core/inbox-runtime.d.ts +48 -0
  34. package/dist/src/core/inbox-runtime.js +180 -0
  35. package/dist/src/core/mr-changes.d.ts +18 -0
  36. package/dist/src/core/mr-changes.js +47 -0
  37. package/dist/src/index.d.ts +8 -0
  38. package/dist/src/index.js +27 -0
  39. package/dist/src/plugins/agent-args.d.ts +43 -0
  40. package/dist/src/plugins/agent-args.js +221 -0
  41. package/dist/src/plugins/agent.d.ts +121 -0
  42. package/dist/src/plugins/agent.js +12 -0
  43. package/dist/src/plugins/executor.d.ts +182 -0
  44. package/dist/src/plugins/executor.js +1 -0
  45. package/dist/src/plugins/message.d.ts +61 -0
  46. package/dist/src/plugins/message.js +47 -0
  47. package/dist/src/plugins/plugins.d.ts +96 -0
  48. package/dist/src/plugins/plugins.js +120 -0
  49. package/dist/src/plugins/preset.d.ts +61 -0
  50. package/dist/src/plugins/preset.js +23 -0
  51. package/dist/src/plugins/process-host.d.ts +7 -0
  52. package/dist/src/plugins/process-host.js +1 -0
  53. package/dist/src/plugins/remote.d.ts +420 -0
  54. package/dist/src/plugins/remote.js +1 -0
  55. package/dist/src/plugins/workspace.d.ts +69 -0
  56. package/dist/src/plugins/workspace.js +1 -0
  57. package/dist/src/preset.d.ts +2 -0
  58. package/dist/src/preset.js +8 -0
  59. package/dist/src/types.d.ts +132 -0
  60. package/dist/src/types.js +6 -0
  61. package/package.json +38 -4
@@ -0,0 +1,12 @@
1
+ import { type ConfigFileReport, type ConfigInventoryOptions, type ConfigReport } from '@bakers-build/core';
2
+ /**
3
+ * Known addons and the CONDUCTOR slots each fills. An empty list means "known
4
+ * addon, fills no conductor slot" — a UI-only addon (BB-562) belongs in a
5
+ * conductor `addons[]` but contributes a cockpit tab, not a slot. Listing it is
6
+ * not cosmetic: an UNKNOWN specifier sets `addonsAreOpaque` below, which
7
+ * downgrades a genuinely missing remote/executor/workspace from
8
+ * `missing_required_key` to `unknown_value`.
9
+ */
10
+ export declare const CONDUCTOR_ADDON_SLOTS: Record<string, string[]>;
11
+ /** Resolve only documented generated wiring and primitive const bindings. Never execute code. */
12
+ export declare function validateConfigSources(options: ConfigInventoryOptions, texts: Map<string, string | null>, files: ConfigFileReport[]): ConfigReport;
@@ -0,0 +1,353 @@
1
+ import { configRecheckCommand, inventoryConfig, shellQuote, } from '@bakers-build/core';
2
+ import { ConfigSourceEditor } from './config-source-edit.js';
3
+ /**
4
+ * Known addons and the CONDUCTOR slots each fills. An empty list means "known
5
+ * addon, fills no conductor slot" — a UI-only addon (BB-562) belongs in a
6
+ * conductor `addons[]` but contributes a cockpit tab, not a slot. Listing it is
7
+ * not cosmetic: an UNKNOWN specifier sets `addonsAreOpaque` below, which
8
+ * downgrades a genuinely missing remote/executor/workspace from
9
+ * `missing_required_key` to `unknown_value`.
10
+ */
11
+ export const CONDUCTOR_ADDON_SLOTS = {
12
+ '@bakers-build/addon-remote-drupal': ['remote'],
13
+ '@bakers-build/addon-herdr': ['executor', 'workspace'],
14
+ '@bakers-build/addon-fake': ['remote', 'executor', 'workspace'],
15
+ '@bakers-build/addon-workspace-git': ['workspace'],
16
+ '@bakers-build/addon-claude': ['agent'],
17
+ '@bakers-build/addon-codex': ['agent'],
18
+ '@bakers-build/addon-grok': ['agent'],
19
+ '@bakers-build/addon-kimi': ['agent'],
20
+ '@bakers-build/addon-opencode': ['agent'],
21
+ '@bakers-build/addon-pi': ['agent'],
22
+ '@bakers-build/addon-ports': [],
23
+ '@bakers-build/addon-ports-cloudflare': [],
24
+ '@bakers-build/addon-ports-cloudflare-quick': [],
25
+ '@bakers-build/addon-ports-frp': [],
26
+ '@bakers-build/addon-bakers-ui': [],
27
+ '@bakers-build/addon-bakers-ui-artifacts': [],
28
+ '@bakers-build/addon-agents': [],
29
+ '@bakers-build/addon-auth-basic': [],
30
+ '@bakers-build/addon-ddev': [],
31
+ '@bakers-build/addon-deployment': [],
32
+ '@bakers-build/addon-docker-compose': [],
33
+ '@bakers-build/addon-dropsh': [],
34
+ '@bakers-build/addon-essentials': [],
35
+ '@bakers-build/addon-info': [],
36
+ '@bakers-build/addon-name-refs': [],
37
+ '@bakers-build/addon-track': [],
38
+ '@bakers-build/addon-workspace': [],
39
+ };
40
+ function validateConductorSources(options, editors, report) {
41
+ const recheck = configRecheckCommand((options.scope ?? 'all'), report.roots.project);
42
+ const localFile = report.files.find((candidate) => candidate.kind === 'local');
43
+ const localEditor = localFile ? editors.get(localFile.path) : undefined;
44
+ for (const file of report.files.filter((candidate) => candidate.selected && candidate.kind === 'conductor')) {
45
+ const editor = editors.get(file.path);
46
+ if (editor?.source.shape !== 'object')
47
+ continue;
48
+ const start = report.findings.length;
49
+ const add = (code, key, expected, property = editor.property(key), findingPath = file.path) => {
50
+ const unknown = code === 'unknown_value';
51
+ report.findings.push({
52
+ code,
53
+ severity: unknown ? 'warning' : 'error',
54
+ stage: 'schema',
55
+ path: findingPath,
56
+ key,
57
+ expected,
58
+ observed: unknown ? '[COMPUTED]' : (property?.value ?? null),
59
+ owner: 'project',
60
+ related: [],
61
+ statically_determined: property?.staticallyDetermined ?? false,
62
+ remediation: `${unknown ? 'Determine' : 'Set'} ${key} in ${shellQuote(findingPath)}, then run ${recheck}.`,
63
+ recheck,
64
+ ...(property ? { line: property.line, column: property.column } : {}),
65
+ });
66
+ };
67
+ for (const legacy of ['project', 'bb_workspace']) {
68
+ if (!editor.property(legacy))
69
+ continue;
70
+ add('misplaced_key', legacy, `Committed bakers.build identity belongs under bakers.${legacy === 'project' ? 'project' : 'workspace'}.`);
71
+ const finding = report.findings.at(-1);
72
+ if (finding)
73
+ finding.remediation = `Run bakers config upgrade --scope project, then ${recheck}.`;
74
+ }
75
+ const bakers = editor.property('bakers');
76
+ const bakersExpression = editor.expression('bakers');
77
+ if (bakers &&
78
+ (bakers.nodeType !== 'ObjectExpression' ||
79
+ (bakersExpression &&
80
+ new ConfigSourceEditor(`export default ${bakersExpression};`).source
81
+ .unknownKeys))) {
82
+ add('unsupported_source_shape', 'bakers', 'A statically inspectable bakers object without spreads is required.');
83
+ const finding = report.findings.at(-1);
84
+ if (finding)
85
+ finding.remediation = `Run bakers config upgrade --scope project, then ${recheck}.`;
86
+ }
87
+ const validateIdentity = (key) => {
88
+ const property = editor.property(key) ??
89
+ (key === 'conductor_id' ? editor.property('machine_id') : undefined);
90
+ const expression = property ? editor.expression(property.key) : undefined;
91
+ const generatedConductor = key === 'conductor_id' &&
92
+ /^(?:local\.(?:conductor_id|machine_id)\s*\?\?\s*)+(?:composedConductorId|composedMachineId)$/.test(expression ?? '') &&
93
+ /const composed(?:Conductor|Machine)Id\s*=/.test(editor.text) &&
94
+ /machine\.user_id/.test(editor.text) &&
95
+ /machine\.machine_id/.test(editor.text);
96
+ if (generatedConductor) {
97
+ if (!localEditor)
98
+ return;
99
+ const localMatches = (expression ?? '').matchAll(/local\.(conductor_id|machine_id)\s*\?\?/g);
100
+ for (const match of localMatches) {
101
+ const localKey = match[1];
102
+ if (!localKey)
103
+ continue;
104
+ const override = localEditor.property(localKey);
105
+ if (!override) {
106
+ if (!localEditor.source.unknownKeys)
107
+ continue;
108
+ add('unknown_value', localKey, 'A nonempty effective conductor identity.', undefined, localFile?.path ?? file.path);
109
+ return;
110
+ }
111
+ if (override.staticallyDetermined && override.value === null)
112
+ continue;
113
+ if (override.staticallyDetermined &&
114
+ typeof override.value === 'string' &&
115
+ override.value.trim() !== '')
116
+ return;
117
+ add(override.staticallyDetermined ? 'invalid_value' : 'unknown_value', localKey, 'A nonempty effective conductor identity.', override, localFile?.path ?? file.path);
118
+ return;
119
+ }
120
+ return;
121
+ }
122
+ if (!property) {
123
+ add(editor.source.unknownKeys ? 'unknown_value' : 'missing_required_key', key, `A nonempty conductor ${key === 'bakers.project' ? 'project' : 'identity'}.`);
124
+ }
125
+ else if (property.staticallyDetermined &&
126
+ typeof property.value === 'string' &&
127
+ property.value.trim() !== '') {
128
+ return;
129
+ }
130
+ else {
131
+ add(property.staticallyDetermined ? 'invalid_value' : 'unknown_value', key, `A nonempty conductor ${key === 'bakers.project' ? 'project' : 'identity'}.`, property);
132
+ }
133
+ };
134
+ validateIdentity('bakers.project');
135
+ validateIdentity('conductor_id');
136
+ const addon = editor.property('addons');
137
+ const addonSlots = new Set();
138
+ let addonsAreOpaque = false;
139
+ if (addon) {
140
+ if (addon.nodeType !== 'ArrayExpression')
141
+ addonsAreOpaque = true;
142
+ else
143
+ for (let index = 0; index < (addon.arrayLength ?? 0); index++) {
144
+ const entry = `addons[${index}]`;
145
+ const specifier = editor.property(entry)?.value ??
146
+ editor.property(`${entry}.use`)?.value;
147
+ if (typeof specifier !== 'string')
148
+ addonsAreOpaque = true;
149
+ else {
150
+ const contributions = CONDUCTOR_ADDON_SLOTS[specifier];
151
+ if (!contributions)
152
+ addonsAreOpaque = true;
153
+ else
154
+ for (const slot of contributions)
155
+ addonSlots.add(slot);
156
+ }
157
+ }
158
+ }
159
+ // The `agent` slot is intentionally excluded: agent ownership now belongs to
160
+ // machine.config.js (machine schema v3+). A conductor config that declares
161
+ // no agent slot or no agent-contributing addons is valid — machine.config.js
162
+ // provides the candidates at runtime. Existing pre-migration configs that
163
+ // still carry agent addons continue to validate until the conductor 0→1
164
+ // migration removes them.
165
+ for (const slot of ['remote', 'executor', 'workspace']) {
166
+ const property = editor.property(slot);
167
+ if (slot === 'workspace' &&
168
+ property?.staticallyDetermined &&
169
+ typeof property.value === 'string' &&
170
+ property.value.trim() !== '' &&
171
+ addonSlots.has('workspace'))
172
+ continue;
173
+ if (!property) {
174
+ if (addonSlots.has(slot))
175
+ continue;
176
+ add(addon && addonsAreOpaque ? 'unknown_value' : 'missing_required_key', slot, `A conductor ${slot} plugin supplied by an explicit slot or known addon.`);
177
+ continue;
178
+ }
179
+ if (!property.staticallyDetermined) {
180
+ add('unknown_value', slot, `A conductor ${slot} plugin supplied by an explicit slot or known addon.`, property);
181
+ continue;
182
+ }
183
+ const descriptor = (prefix, kind) => {
184
+ const plugin = editor.property(`${prefix}.plugin`)?.value;
185
+ return ((typeof plugin === 'string' && plugin.trim() !== '') ||
186
+ editor.property(`${prefix}.kind`)?.value === kind);
187
+ };
188
+ if (slot === 'agent' && property.nodeType === 'ArrayExpression') {
189
+ let unknownCandidate = false;
190
+ let invalidCandidate = (property.arrayLength ?? 0) === 0;
191
+ for (let index = 0; index < (property.arrayLength ?? 0); index++) {
192
+ const prefix = `agent[${index}]`;
193
+ const candidate = editor.property(prefix);
194
+ const wrapped = editor.property(`${prefix}.agent`);
195
+ if (!candidate?.staticallyDetermined ||
196
+ wrapped?.staticallyDetermined === false)
197
+ unknownCandidate = true;
198
+ else if (!descriptor(prefix, 'agent') &&
199
+ !descriptor(`${prefix}.agent`, 'agent'))
200
+ invalidCandidate = true;
201
+ }
202
+ if (unknownCandidate)
203
+ add('unknown_value', slot, `A conductor ${slot} plugin supplied by an explicit slot or known addon.`, property);
204
+ else if (invalidCandidate)
205
+ add('invalid_value', slot, `A conductor ${slot} plugin supplied by an explicit slot or known addon.`, property);
206
+ continue;
207
+ }
208
+ if (property.nodeType !== 'ObjectExpression' || !descriptor(slot, slot))
209
+ add('invalid_value', slot, `A conductor ${slot} plugin supplied by an explicit slot or known addon.`, property);
210
+ }
211
+ const findings = report.findings.slice(start);
212
+ if (findings.some((finding) => finding.severity === 'error'))
213
+ file.state = 'partial';
214
+ else if (findings.some((finding) => finding.code === 'unknown_value'))
215
+ file.state = 'computed';
216
+ }
217
+ }
218
+ /** Resolve only documented generated wiring and primitive const bindings. Never execute code. */
219
+ export function validateConfigSources(options, texts, files) {
220
+ const editors = new Map([...texts]
221
+ .filter((entry) => entry[1] !== null)
222
+ .map(([path, text]) => [path, new ConfigSourceEditor(text)]));
223
+ const resolved = new Set();
224
+ const global = files.find((f) => f.kind === 'connection');
225
+ const local = files.find((f) => f.kind === 'local');
226
+ const globalEditor = global ? editors.get(global.path) : undefined;
227
+ const localEditor = local ? editors.get(local.path) : undefined;
228
+ const primitive = (e, key) => {
229
+ const p = e?.property(key);
230
+ return p?.staticallyDetermined && p.value !== undefined
231
+ ? JSON.stringify(p.value)
232
+ : undefined;
233
+ };
234
+ const fallback = (localKey, defaultExpression) => {
235
+ const p = localEditor?.property(localKey);
236
+ if (!p || (p.staticallyDetermined && p.value === null))
237
+ return defaultExpression;
238
+ return primitive(localEditor, localKey);
239
+ };
240
+ let inherits = false;
241
+ for (const file of files) {
242
+ const e = editors.get(file.path);
243
+ if (!e)
244
+ continue;
245
+ const declarations = new Map();
246
+ for (const name of ['baseUrl', 'clientId', 'clientSecret', 'workspaceId']) {
247
+ const match = new RegExp(`const ${name} = ([^;]+);`).exec(e.text);
248
+ if (!match)
249
+ continue;
250
+ const value = primitive(new ConfigSourceEditor(`export default {value:${match[1]}};`), 'value');
251
+ if (value !== undefined)
252
+ declarations.set(name, value);
253
+ }
254
+ const isProject = file.kind === 'project-connection';
255
+ const generated = isProject &&
256
+ (e.text.includes('const connection = (await import(') ||
257
+ e.text.includes('const connection = await loadConnection();'));
258
+ if (generated) {
259
+ inherits ||= file.selected;
260
+ const auth = [...(globalEditor?.source.properties ?? [])]
261
+ .find(([key, p]) => /^plugins\[\d+\]\.plugin$/.test(key) &&
262
+ p.value === '@dropsh/plugin-oauth2')?.[0]
263
+ .replace(/\.plugin$/, '');
264
+ const values = {
265
+ baseUrl: fallback('base_url', primitive(globalEditor, 'site.base_url')),
266
+ workspaceId: fallback('workspace_id', primitive(globalEditor, 'workspace_id')),
267
+ clientId: fallback('oauth.client_id', auth ? primitive(globalEditor, `${auth}.with.client_id`) : undefined),
268
+ clientSecret: fallback('oauth.client_secret', auth
269
+ ? primitive(globalEditor, `${auth}.with.client_secret`)
270
+ : undefined),
271
+ };
272
+ for (const [name, value] of Object.entries(values))
273
+ if (value !== undefined)
274
+ declarations.set(name, value);
275
+ for (const [key, name] of [
276
+ ['site.base_url', 'baseUrl'],
277
+ ['workspace_id', 'workspaceId'],
278
+ ]) {
279
+ const expr = e.expression(key);
280
+ if (expr === name ||
281
+ expr ===
282
+ `local.${name === 'baseUrl' ? 'base_url' : 'workspace_id'} ?? connection.${name === 'baseUrl' ? 'site.base_url' : 'workspace_id'}`) {
283
+ const value = values[name];
284
+ if (value !== undefined) {
285
+ e.set(key, value);
286
+ resolved.add(`${file.path}:${key}`);
287
+ }
288
+ }
289
+ }
290
+ if (e.expression('plugins')?.includes('connection.plugins.map(') &&
291
+ globalEditor?.property('plugins')?.nodeType === 'ArrayExpression') {
292
+ e.set('plugins', globalEditor.expression('plugins'));
293
+ resolved.add(`${file.path}:plugins`);
294
+ if (auth)
295
+ for (const [name, value] of [
296
+ ['client_id', values.clientId],
297
+ ['client_secret', values.clientSecret],
298
+ ]) {
299
+ const key = `${auth}.with.${name}`;
300
+ e.set(key, value ?? 'unknownLocalValue');
301
+ resolved.add(`${file.path}:${key}`);
302
+ }
303
+ }
304
+ }
305
+ for (const key of [...e.source.properties.keys()]) {
306
+ const expression = e.expression(key);
307
+ let value = expression ? declarations.get(expression) : undefined;
308
+ if (expression === 'local.oauth?.client_secret')
309
+ value = primitive(localEditor, 'oauth.client_secret');
310
+ if (value !== undefined) {
311
+ e.set(key, value);
312
+ resolved.add(`${file.path}:${key}`);
313
+ }
314
+ }
315
+ }
316
+ const overlay = new Map(texts);
317
+ for (const [path, e] of editors)
318
+ overlay.set(path, e.text);
319
+ const report = inventoryConfig({ ...options, sourceTexts: overlay }).report;
320
+ validateConductorSources(options, editors, report);
321
+ // Literal values resolved from the local file are not secrets stored in the committed file.
322
+ report.findings = report.findings.filter((f) => !(f.code === 'misplaced_key' &&
323
+ f.key?.endsWith('client_secret') &&
324
+ resolved.has(`${f.path}:${f.key}`)));
325
+ // Project operations validate selected prerequisites, attributing defects to the real owner.
326
+ if (report.resolved_scopes.includes('project')) {
327
+ const hasProject = files.some((f) => f.kind === 'project-connection' && editors.has(f.path));
328
+ for (const layer of ['machine', 'connection']) {
329
+ if (layer === 'connection' && hasProject && !inherits)
330
+ continue;
331
+ const prerequisites = inventoryConfig({
332
+ ...options,
333
+ scope: layer,
334
+ sourceTexts: overlay,
335
+ }).report;
336
+ report.findings.push(...prerequisites.findings.filter((f) => !report.findings.some((p) => p.path === f.path && p.key === f.key && p.code === f.code)));
337
+ }
338
+ }
339
+ // Preserve real locations; offsets in the validation-only rendering are not source locations.
340
+ for (const f of report.findings) {
341
+ const raw = texts.get(f.path);
342
+ const p = raw && f.key ? new ConfigSourceEditor(raw).property(f.key) : undefined;
343
+ if (p) {
344
+ f.line = p.line;
345
+ f.column = p.column;
346
+ }
347
+ else {
348
+ delete f.line;
349
+ delete f.column;
350
+ }
351
+ }
352
+ return report;
353
+ }
@@ -0,0 +1,82 @@
1
+ /** Suffix of the pre-rewrite backup a real (non-dry) rewrite leaves behind. */
2
+ export declare const ADDON_RENAME_BAK_SUFFIX = ".pre-addon-rename.bak";
3
+ /**
4
+ * The 14 addon packages renamed by BB-224 (spec v3 decision 14), including
5
+ * the BB-220 `pi` agent addon merged in from develop. A CLOSED
6
+ * set — the pass rewrites only these exact specifiers, so an unknown
7
+ * `@bakers-build/plugin-something` is left alone rather than silently retargeted at a
8
+ * package that does not exist.
9
+ */
10
+ export declare const RENAMED_ADDONS: readonly ["auth-basic", "claude", "codex", "deployment", "dropsh", "essentials", "fake", "bakers-ui", "herdr", "kimi", "opencode", "pi", "remote-drupal", "workspace-git"];
11
+ /**
12
+ * Where each export of the host barrels lives now — the DELETED
13
+ * `@bakers-build/core/plugins` and (BB-230) the meta package's
14
+ * `@bakers-build/bakers/plugins`, which is unresolvable from a dev-clone install.
15
+ *
16
+ * The key set is the barrel's own export list — `core/src/plugins/registry-exports.ts`
17
+ * as of the commit that deleted it — re-pointed at the addon that owns each
18
+ * factory today. `defaultExport` records whether the target package
19
+ * DEFAULT-exports exactly that factory; when it does, the descriptor's `export:`
20
+ * becomes redundant and is dropped.
21
+ *
22
+ * Deliberately absent, so they are left untouched:
23
+ * - `selectRemote`/`selectWorkspace`/`selectExecutor`/`selectAgent(s)` — moved
24
+ * to `@bakers-build/conductor/contract`, but they are config-shape SELECTORS, not
25
+ * plugin factories, so no descriptor can legitimately name them;
26
+ * - any other/unknown export name — a config naming one is reported by the
27
+ * loader rather than silently retargeted at a package that may not have it.
28
+ */
29
+ export declare const CORE_PLUGINS_BARREL_EXPORTS: Readonly<Record<string, {
30
+ target: string;
31
+ defaultExport: boolean;
32
+ }>>;
33
+ /**
34
+ * The host-barrel specifiers a descriptor may name. Both map through
35
+ * `CORE_PLUGINS_BARREL_EXPORTS`: `@bakers-build/core/plugins` is DELETED, and
36
+ * `@bakers-build/bakers/plugins` (BB-230) is unresolvable from a dev-clone install
37
+ * because the meta package that exports it is the workspace's leaf sink.
38
+ */
39
+ export declare const HOST_BARREL_PATHS: readonly ["@bakers-build/core/plugins", "@bakers-build/bakers/plugins"];
40
+ /** Which surface a config file speaks — decides the ambiguous builtins mapping. */
41
+ export type ConfigSurface = 'connection' | 'engine';
42
+ /**
43
+ * Rewrite the legacy specifiers in one config's SOURCE TEXT — all of them: the
44
+ * renamed `@bakers-build/plugin-*` packages, the deleted `@bakers-build/core/builtins`
45
+ * preset, and the host-barrel descriptors naming either `@bakers-build/core/plugins`
46
+ * (deleted) or `@bakers-build/bakers/plugins` (BB-230). Pure; line
47
+ * count is preserved (every replacement is line-local), which is what lets the
48
+ * reported diff be a plain index-aligned line diff.
49
+ */
50
+ export declare function migrateAddonNames(text: string, surface: ConfigSurface): {
51
+ text: string;
52
+ count: number;
53
+ };
54
+ /** The outcome of the rename pass over a single config file. */
55
+ export interface AddonRenameResult {
56
+ /** Report line, in the shape of the other upgrade steps. */
57
+ action: string;
58
+ /** `- old` / `+ new` lines for the rewritten specifiers. */
59
+ diff: string[];
60
+ /** Number of rewritten specifiers. */
61
+ count: number;
62
+ }
63
+ /**
64
+ * Rename pass over ONE config file. Returns `undefined` when the file is absent
65
+ * or already on the new names (idempotency: no write, no backup, no report
66
+ * line — the file stays byte-identical).
67
+ */
68
+ export declare function migrateAddonNamesInFile(path: string, surface: ConfigSurface, opts?: {
69
+ dryRun?: boolean;
70
+ }): AddonRenameResult | undefined;
71
+ /**
72
+ * Rename pass over every recognised config in the given `.bakers/` dirs (project
73
+ * + home). Emits report lines ONLY for files it actually rewrites, so an install
74
+ * already on `addon-*` adds no noise to the upgrade report.
75
+ */
76
+ export declare function runAddonRenameMigration(opts?: {
77
+ bakersDirs: string[];
78
+ dryRun?: boolean;
79
+ }): {
80
+ actions: string[];
81
+ changed: boolean;
82
+ };