@dobby.ai/dobby 0.1.0 → 0.1.2

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 (156) hide show
  1. package/README.md +84 -39
  2. package/dist/src/agent/event-forwarder.js +185 -16
  3. package/dist/src/cli/commands/cron.js +39 -35
  4. package/dist/src/cli/commands/doctor.js +81 -2
  5. package/dist/src/cli/commands/extension.js +3 -1
  6. package/dist/src/cli/commands/init.js +43 -173
  7. package/dist/src/cli/commands/topology.js +38 -14
  8. package/dist/src/cli/program.js +15 -137
  9. package/dist/src/cli/shared/config-io.js +3 -31
  10. package/dist/src/cli/shared/config-mutators.js +33 -9
  11. package/dist/src/cli/shared/configure-sections.js +52 -12
  12. package/dist/src/cli/shared/init-catalog.js +89 -46
  13. package/dist/src/cli/shared/local-extension-specs.js +85 -0
  14. package/dist/src/cli/shared/schema-prompts.js +26 -2
  15. package/dist/src/core/gateway.js +3 -1
  16. package/dist/src/core/routing.js +53 -38
  17. package/dist/src/core/types.js +2 -0
  18. package/dist/src/cron/config.js +2 -2
  19. package/dist/src/cron/service.js +87 -23
  20. package/dist/src/cron/store.js +1 -1
  21. package/dist/src/main.js +0 -0
  22. package/dist/src/shared/dobby-repo.js +40 -0
  23. package/package.json +11 -4
  24. package/.env.example +0 -9
  25. package/AGENTS.md +0 -267
  26. package/ROADMAP.md +0 -34
  27. package/config/cron.example.json +0 -9
  28. package/config/gateway.example.json +0 -128
  29. package/config/models.custom.example.json +0 -27
  30. package/dist/src/agent/tests/event-forwarder.test.js +0 -113
  31. package/dist/src/cli/shared/config-path.js +0 -207
  32. package/dist/src/cli/shared/init-models-file.js +0 -65
  33. package/dist/src/cli/shared/presets.js +0 -86
  34. package/dist/src/cli/tests/config-command.test.js +0 -42
  35. package/dist/src/cli/tests/config-io.test.js +0 -64
  36. package/dist/src/cli/tests/config-mutators.test.js +0 -47
  37. package/dist/src/cli/tests/config-path.test.js +0 -21
  38. package/dist/src/cli/tests/discord-config.test.js +0 -23
  39. package/dist/src/cli/tests/doctor.test.js +0 -107
  40. package/dist/src/cli/tests/init-catalog.test.js +0 -87
  41. package/dist/src/cli/tests/presets.test.js +0 -41
  42. package/dist/src/cli/tests/program-options.test.js +0 -92
  43. package/dist/src/cli/tests/routing-config.test.js +0 -199
  44. package/dist/src/cli/tests/routing-legacy.test.js +0 -191
  45. package/dist/src/core/tests/control-command.test.js +0 -17
  46. package/dist/src/core/tests/gateway-update-strategy.test.js +0 -167
  47. package/dist/src/core/tests/runtime-registry.test.js +0 -116
  48. package/dist/src/core/tests/typing-controller.test.js +0 -103
  49. package/docs/BOXLITE_SANDBOX_FEASIBILITY.md +0 -175
  50. package/docs/CRON_SCHEDULER_DESIGN.md +0 -374
  51. package/docs/DOCKER_SANDBOX_vs_BOXLITE.md +0 -77
  52. package/docs/EXTENSION_SYSTEM_ARCHITECTURE.md +0 -119
  53. package/docs/MVP.md +0 -135
  54. package/docs/RUNBOOK.md +0 -242
  55. package/docs/TEAMWORK_HANDOFF_DESIGN.md +0 -440
  56. package/plugins/connector-discord/dobby.manifest.json +0 -18
  57. package/plugins/connector-discord/index.js +0 -1
  58. package/plugins/connector-discord/package-lock.json +0 -360
  59. package/plugins/connector-discord/package.json +0 -38
  60. package/plugins/connector-discord/src/connector.ts +0 -350
  61. package/plugins/connector-discord/src/contribution.ts +0 -21
  62. package/plugins/connector-discord/src/mapper.ts +0 -102
  63. package/plugins/connector-discord/tsconfig.json +0 -19
  64. package/plugins/connector-feishu/dobby.manifest.json +0 -18
  65. package/plugins/connector-feishu/index.js +0 -1
  66. package/plugins/connector-feishu/package-lock.json +0 -618
  67. package/plugins/connector-feishu/package.json +0 -38
  68. package/plugins/connector-feishu/src/connector.ts +0 -343
  69. package/plugins/connector-feishu/src/contribution.ts +0 -26
  70. package/plugins/connector-feishu/src/mapper.ts +0 -401
  71. package/plugins/connector-feishu/tsconfig.json +0 -19
  72. package/plugins/plugin-sdk/index.d.ts +0 -261
  73. package/plugins/plugin-sdk/index.js +0 -1
  74. package/plugins/plugin-sdk/package-lock.json +0 -12
  75. package/plugins/plugin-sdk/package.json +0 -22
  76. package/plugins/provider-claude/dobby.manifest.json +0 -17
  77. package/plugins/provider-claude/index.js +0 -1
  78. package/plugins/provider-claude/package-lock.json +0 -3398
  79. package/plugins/provider-claude/package.json +0 -39
  80. package/plugins/provider-claude/src/contribution.ts +0 -1018
  81. package/plugins/provider-claude/tsconfig.json +0 -19
  82. package/plugins/provider-claude-cli/dobby.manifest.json +0 -17
  83. package/plugins/provider-claude-cli/index.js +0 -1
  84. package/plugins/provider-claude-cli/package-lock.json +0 -2898
  85. package/plugins/provider-claude-cli/package.json +0 -38
  86. package/plugins/provider-claude-cli/src/contribution.ts +0 -1673
  87. package/plugins/provider-claude-cli/tsconfig.json +0 -19
  88. package/plugins/provider-pi/dobby.manifest.json +0 -17
  89. package/plugins/provider-pi/index.js +0 -1
  90. package/plugins/provider-pi/package-lock.json +0 -3877
  91. package/plugins/provider-pi/package.json +0 -40
  92. package/plugins/provider-pi/src/contribution.ts +0 -476
  93. package/plugins/provider-pi/tsconfig.json +0 -19
  94. package/plugins/sandbox-core/boxlite.js +0 -1
  95. package/plugins/sandbox-core/dobby.manifest.json +0 -17
  96. package/plugins/sandbox-core/docker.js +0 -1
  97. package/plugins/sandbox-core/package-lock.json +0 -136
  98. package/plugins/sandbox-core/package.json +0 -39
  99. package/plugins/sandbox-core/src/boxlite-context.ts +0 -2
  100. package/plugins/sandbox-core/src/boxlite-contribution.ts +0 -53
  101. package/plugins/sandbox-core/src/boxlite-executor.ts +0 -911
  102. package/plugins/sandbox-core/src/docker-contribution.ts +0 -43
  103. package/plugins/sandbox-core/src/docker-executor.ts +0 -217
  104. package/plugins/sandbox-core/tsconfig.json +0 -19
  105. package/scripts/local-extensions.mjs +0 -168
  106. package/src/agent/event-forwarder.ts +0 -414
  107. package/src/cli/commands/config.ts +0 -328
  108. package/src/cli/commands/configure.ts +0 -92
  109. package/src/cli/commands/cron.ts +0 -410
  110. package/src/cli/commands/doctor.ts +0 -230
  111. package/src/cli/commands/extension.ts +0 -205
  112. package/src/cli/commands/init.ts +0 -396
  113. package/src/cli/commands/start.ts +0 -223
  114. package/src/cli/commands/topology.ts +0 -383
  115. package/src/cli/index.ts +0 -9
  116. package/src/cli/program.ts +0 -465
  117. package/src/cli/shared/config-io.ts +0 -277
  118. package/src/cli/shared/config-mutators.ts +0 -440
  119. package/src/cli/shared/config-schema.ts +0 -228
  120. package/src/cli/shared/config-types.ts +0 -121
  121. package/src/cli/shared/configure-sections.ts +0 -551
  122. package/src/cli/shared/discord-config.ts +0 -14
  123. package/src/cli/shared/init-catalog.ts +0 -189
  124. package/src/cli/shared/init-models-file.ts +0 -77
  125. package/src/cli/shared/runtime.ts +0 -33
  126. package/src/cli/shared/schema-prompts.ts +0 -414
  127. package/src/cli/tests/config-command.test.ts +0 -56
  128. package/src/cli/tests/config-io.test.ts +0 -92
  129. package/src/cli/tests/config-mutators.test.ts +0 -59
  130. package/src/cli/tests/doctor.test.ts +0 -120
  131. package/src/cli/tests/init-catalog.test.ts +0 -96
  132. package/src/cli/tests/program-options.test.ts +0 -113
  133. package/src/cli/tests/routing-config.test.ts +0 -209
  134. package/src/core/control-command.ts +0 -12
  135. package/src/core/dedup-store.ts +0 -103
  136. package/src/core/gateway.ts +0 -607
  137. package/src/core/routing.ts +0 -379
  138. package/src/core/runtime-registry.ts +0 -141
  139. package/src/core/tests/control-command.test.ts +0 -20
  140. package/src/core/tests/runtime-registry.test.ts +0 -140
  141. package/src/core/tests/typing-controller.test.ts +0 -129
  142. package/src/core/types.ts +0 -318
  143. package/src/core/typing-controller.ts +0 -119
  144. package/src/cron/config.ts +0 -154
  145. package/src/cron/schedule.ts +0 -61
  146. package/src/cron/service.ts +0 -249
  147. package/src/cron/store.ts +0 -155
  148. package/src/cron/types.ts +0 -60
  149. package/src/extension/loader.ts +0 -145
  150. package/src/extension/manager.ts +0 -355
  151. package/src/extension/manifest.ts +0 -26
  152. package/src/extension/registry.ts +0 -229
  153. package/src/main.ts +0 -8
  154. package/src/sandbox/executor.ts +0 -44
  155. package/src/sandbox/host-executor.ts +0 -118
  156. package/tsconfig.json +0 -18
@@ -1,328 +0,0 @@
1
- import {
2
- cancel,
3
- intro,
4
- isCancel,
5
- multiselect,
6
- note,
7
- outro,
8
- } from "@clack/prompts";
9
- import { ensureGatewayConfigShape } from "../shared/config-mutators.js";
10
- import { requireRawConfig, resolveConfigPath, writeConfigWithValidation } from "../shared/config-io.js";
11
- import type { RawGatewayConfig } from "../shared/config-types.js";
12
- import {
13
- applyConfigureSection,
14
- isConfigureSection,
15
- normalizeConfigureSectionOrder,
16
- type ConfigureSection,
17
- } from "../shared/configure-sections.js";
18
- import {
19
- applyAndValidateContributionSchemas,
20
- getContributionSchema,
21
- loadContributionSchemaCatalog,
22
- listContributionSchemas,
23
- } from "../shared/config-schema.js";
24
-
25
- export const CONFIG_SECTION_VALUES = ["providers", "connectors", "routes", "bindings", "sandboxes", "data", "extensions"] as const;
26
-
27
- export type ConfigSection = (typeof CONFIG_SECTION_VALUES)[number];
28
-
29
- interface ConfigListEntry {
30
- key: string;
31
- type: string;
32
- children?: number;
33
- preview: string;
34
- }
35
-
36
- const EDITABLE_CONFIG_SECTIONS: ConfigureSection[] = ["provider", "connector", "route", "binding"];
37
-
38
- /**
39
- * Validates section identifiers accepted by `config show|list`.
40
- */
41
- export function isConfigSection(value: string): value is ConfigSection {
42
- return CONFIG_SECTION_VALUES.includes(value as ConfigSection);
43
- }
44
-
45
- /**
46
- * Returns a stable scalar/object/array type label for list output.
47
- */
48
- function describeValueType(value: unknown): string {
49
- if (value === null) {
50
- return "null";
51
- }
52
-
53
- if (Array.isArray(value)) {
54
- return "array";
55
- }
56
-
57
- return typeof value;
58
- }
59
-
60
- /**
61
- * Guards plain object-like values for preview/list summary generation.
62
- */
63
- function isRecord(value: unknown): value is Record<string, unknown> {
64
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
65
- }
66
-
67
- /**
68
- * Renders a compact preview string for list rows.
69
- */
70
- export function previewConfigValue(value: unknown, maxLength = 80): string {
71
- let raw: string;
72
- if (value === null) {
73
- raw = "null";
74
- } else if (typeof value === "string") {
75
- raw = JSON.stringify(value);
76
- } else if (typeof value === "number" || typeof value === "boolean") {
77
- raw = String(value);
78
- } else if (Array.isArray(value)) {
79
- const head = value.slice(0, 3).map((item) => previewConfigValue(item, 24)).join(", ");
80
- raw = `[${head}${value.length > 3 ? ", ..." : ""}]`;
81
- } else if (isRecord(value)) {
82
- const keys = Object.keys(value);
83
- const head = keys.slice(0, 3).join(", ");
84
- raw = `{${head}${keys.length > 3 ? ", ..." : ""}}`;
85
- } else {
86
- raw = String(value);
87
- }
88
-
89
- return raw.length > maxLength ? `${raw.slice(0, maxLength - 3)}...` : raw;
90
- }
91
-
92
- /**
93
- * Summarizes one object value into list-friendly rows.
94
- */
95
- export function buildConfigListEntries(value: unknown): ConfigListEntry[] {
96
- if (!isRecord(value)) {
97
- return [
98
- {
99
- key: "(value)",
100
- type: describeValueType(value),
101
- preview: previewConfigValue(value),
102
- },
103
- ];
104
- }
105
-
106
- return Object.entries(value)
107
- .sort((a, b) => a[0].localeCompare(b[0]))
108
- .map(([key, item]) => ({
109
- key,
110
- type: describeValueType(item),
111
- ...(isRecord(item) ? { children: Object.keys(item).length } : {}),
112
- ...(Array.isArray(item) ? { children: item.length } : {}),
113
- preview: previewConfigValue(item),
114
- }));
115
- }
116
-
117
- /**
118
- * Picks and validates a top-level config section.
119
- */
120
- function resolveConfigSection(section?: string): ConfigSection | undefined {
121
- if (!section) {
122
- return undefined;
123
- }
124
-
125
- if (!isConfigSection(section)) {
126
- throw new Error(`Unknown section '${section}'. Allowed: ${CONFIG_SECTION_VALUES.join(", ")}`);
127
- }
128
-
129
- return section;
130
- }
131
-
132
- /**
133
- * Pretty prints list rows for human-readable CLI output.
134
- */
135
- function printListEntries(entries: ConfigListEntry[]): void {
136
- if (entries.length === 0) {
137
- console.log("(empty)");
138
- return;
139
- }
140
-
141
- for (const entry of entries) {
142
- const children = entry.children !== undefined ? `, children=${entry.children}` : "";
143
- console.log(`${entry.key}: type=${entry.type}${children}, preview=${entry.preview}`);
144
- }
145
- }
146
-
147
- /**
148
- * Loads current config and normalizes missing sections to make read output stable.
149
- */
150
- async function loadNormalizedConfig(): Promise<RawGatewayConfig> {
151
- const configPath = resolveConfigPath();
152
- const rawConfig = await requireRawConfig(configPath);
153
- return ensureGatewayConfigShape(structuredClone(rawConfig));
154
- }
155
-
156
- /**
157
- * Prints full config or one top-level section.
158
- */
159
- export async function runConfigShowCommand(options: {
160
- section?: string;
161
- json?: boolean;
162
- }): Promise<void> {
163
- const normalized = await loadNormalizedConfig();
164
- const section = resolveConfigSection(options.section);
165
- const value = section ? normalized[section] : normalized;
166
-
167
- if (options.json) {
168
- console.log(JSON.stringify(value ?? null));
169
- return;
170
- }
171
-
172
- console.log(JSON.stringify(value ?? null, null, 2));
173
- }
174
-
175
- /**
176
- * Prints a typed summary for top-level config sections or one section's children.
177
- */
178
- export async function runConfigListCommand(options: {
179
- section?: string;
180
- json?: boolean;
181
- }): Promise<void> {
182
- const normalized = await loadNormalizedConfig();
183
- const section = resolveConfigSection(options.section);
184
- const entries = section
185
- ? buildConfigListEntries(normalized[section])
186
- : CONFIG_SECTION_VALUES.map((key) => ({
187
- key,
188
- type: describeValueType(normalized[key]),
189
- ...(isRecord(normalized[key]) ? { children: Object.keys(normalized[key] as Record<string, unknown>).length } : {}),
190
- ...(Array.isArray(normalized[key]) ? { children: (normalized[key] as unknown[]).length } : {}),
191
- preview: previewConfigValue(normalized[key]),
192
- }));
193
-
194
- if (options.json) {
195
- console.log(JSON.stringify(entries));
196
- return;
197
- }
198
-
199
- printListEntries(entries);
200
- }
201
-
202
- /**
203
- * Lists loaded contribution schema availability for installed/allow-listed extensions.
204
- */
205
- export async function runConfigSchemaListCommand(options: {
206
- json?: boolean;
207
- }): Promise<void> {
208
- const configPath = resolveConfigPath();
209
- const rawConfig = await requireRawConfig(configPath);
210
- const entries = await listContributionSchemas(configPath, rawConfig);
211
-
212
- if (options.json) {
213
- console.log(JSON.stringify(entries));
214
- return;
215
- }
216
-
217
- if (entries.length === 0) {
218
- console.log("(empty)");
219
- return;
220
- }
221
-
222
- for (const entry of entries) {
223
- console.log(
224
- `${entry.contributionId}: kind=${entry.kind}, package=${entry.packageName}, hasSchema=${entry.hasSchema ? "yes" : "no"}`,
225
- );
226
- }
227
- }
228
-
229
- /**
230
- * Prints one contribution JSON Schema by contributionId.
231
- */
232
- export async function runConfigSchemaShowCommand(options: {
233
- contributionId: string;
234
- json?: boolean;
235
- }): Promise<void> {
236
- const configPath = resolveConfigPath();
237
- const rawConfig = await requireRawConfig(configPath);
238
- const entry = await getContributionSchema(configPath, rawConfig, options.contributionId);
239
-
240
- if (!entry) {
241
- throw new Error(`Unknown contributionId '${options.contributionId}'. Run 'dobby config schema list' first.`);
242
- }
243
-
244
- if (!entry.configSchema) {
245
- throw new Error(`Contribution '${options.contributionId}' does not expose configSchema.`);
246
- }
247
-
248
- if (options.json) {
249
- console.log(JSON.stringify(entry.configSchema));
250
- return;
251
- }
252
-
253
- console.log(JSON.stringify(entry.configSchema, null, 2));
254
- }
255
-
256
- /**
257
- * Resolves interactive `config edit` target sections from flags or prompt.
258
- */
259
- async function resolveEditSections(sections: string[]): Promise<ConfigureSection[]> {
260
- if (sections.length > 0) {
261
- const normalized: ConfigureSection[] = [];
262
- for (const section of sections) {
263
- if (!isConfigureSection(section) || !EDITABLE_CONFIG_SECTIONS.includes(section)) {
264
- throw new Error(`Unknown --section '${section}'. Allowed: ${EDITABLE_CONFIG_SECTIONS.join(", ")}`);
265
- }
266
- normalized.push(section);
267
- }
268
- return normalized;
269
- }
270
-
271
- const picked = await multiselect({
272
- message: "Select sections to edit",
273
- options: EDITABLE_CONFIG_SECTIONS.map((section) => ({ value: section, label: section })),
274
- initialValues: ["provider", "connector", "route", "binding"],
275
- required: true,
276
- });
277
-
278
- if (isCancel(picked)) {
279
- cancel("Config edit cancelled.");
280
- throw new Error("Config edit cancelled.");
281
- }
282
-
283
- return picked as ConfigureSection[];
284
- }
285
-
286
- /**
287
- * Runs interactive high-frequency config editing with one validated atomic write.
288
- */
289
- export async function runConfigEditCommand(options: {
290
- sections: string[];
291
- }): Promise<void> {
292
- const configPath = resolveConfigPath();
293
- const rawConfig = await requireRawConfig(configPath);
294
- const next = ensureGatewayConfigShape(structuredClone(rawConfig));
295
-
296
- intro("dobby config edit");
297
-
298
- const requestedSections = await resolveEditSections(options.sections);
299
- const sections = normalizeConfigureSectionOrder(requestedSections);
300
- if (sections.join(",") !== requestedSections.join(",")) {
301
- await note(`Execution order: ${sections.join(" -> ")}`, "Info");
302
- }
303
-
304
- const catalog = await loadContributionSchemaCatalog(configPath, next);
305
- const schemaByContributionId = new Map(
306
- catalog
307
- .filter((item) => item.configSchema)
308
- .map((item) => [item.contributionId, item.configSchema!] as const),
309
- );
310
- const schemaStateByContributionId = new Map(
311
- catalog.map((item) => [item.contributionId, item.configSchema ? "with_schema" : "without_schema"] as const),
312
- );
313
-
314
- for (const section of sections) {
315
- await applyConfigureSection(section, next, { schemaByContributionId, schemaStateByContributionId });
316
- await note(`Section '${section}' prepared`, "Updated");
317
- }
318
-
319
- const validatedConfig = await applyAndValidateContributionSchemas(configPath, next);
320
-
321
- await writeConfigWithValidation(configPath, validatedConfig, {
322
- validate: true,
323
- createBackup: true,
324
- });
325
- await note(`Saved to ${configPath}`, "Saved");
326
-
327
- outro("Configuration updated.");
328
- }
@@ -1,92 +0,0 @@
1
- import {
2
- cancel,
3
- intro,
4
- isCancel,
5
- multiselect,
6
- note,
7
- outro,
8
- } from "@clack/prompts";
9
- import { ensureGatewayConfigShape } from "../shared/config-mutators.js";
10
- import { requireRawConfig, resolveConfigPath, writeConfigWithValidation } from "../shared/config-io.js";
11
- import {
12
- applyConfigureSection,
13
- CONFIGURE_SECTION_VALUES,
14
- isConfigureSection,
15
- normalizeConfigureSectionOrder,
16
- type ConfigureSection,
17
- } from "../shared/configure-sections.js";
18
- import { applyAndValidateContributionSchemas, loadContributionSchemaCatalog } from "../shared/config-schema.js";
19
-
20
- /**
21
- * Resolves target sections from CLI flags or interactive section picker.
22
- */
23
- async function resolveSections(sections: string[]): Promise<ConfigureSection[]> {
24
- if (sections.length > 0) {
25
- const normalized: ConfigureSection[] = [];
26
- for (const section of sections) {
27
- if (!isConfigureSection(section)) {
28
- throw new Error(`Unknown --section '${section}'. Allowed: ${CONFIGURE_SECTION_VALUES.join(", ")}`);
29
- }
30
- normalized.push(section);
31
- }
32
- return normalized;
33
- }
34
-
35
- const picked = await multiselect({
36
- message: "Select sections to configure",
37
- options: CONFIGURE_SECTION_VALUES.map((section) => ({ value: section, label: section })),
38
- initialValues: ["provider", "connector", "route", "binding"],
39
- required: true,
40
- });
41
-
42
- if (isCancel(picked)) {
43
- cancel("Configure cancelled.");
44
- throw new Error("Configure cancelled.");
45
- }
46
-
47
- return picked as ConfigureSection[];
48
- }
49
-
50
- /**
51
- * Executes interactive config updates and validates one final atomic save.
52
- */
53
- export async function runConfigureCommand(options: {
54
- sections: string[];
55
- }): Promise<void> {
56
- const configPath = resolveConfigPath();
57
- const rawConfig = await requireRawConfig(configPath);
58
- const next = ensureGatewayConfigShape(structuredClone(rawConfig));
59
-
60
- intro("dobby configure");
61
- const requestedSections = await resolveSections(options.sections);
62
- const sections = normalizeConfigureSectionOrder(requestedSections);
63
-
64
- if (sections.join(",") !== requestedSections.join(",")) {
65
- await note(`Execution order: ${sections.join(" -> ")}`, "Info");
66
- }
67
-
68
- const catalog = await loadContributionSchemaCatalog(configPath, next);
69
- const schemaByContributionId = new Map(
70
- catalog
71
- .filter((item) => item.configSchema)
72
- .map((item) => [item.contributionId, item.configSchema!] as const),
73
- );
74
- const schemaStateByContributionId = new Map(
75
- catalog.map((item) => [item.contributionId, item.configSchema ? "with_schema" : "without_schema"] as const),
76
- );
77
-
78
- for (const section of sections) {
79
- await applyConfigureSection(section, next, { schemaByContributionId, schemaStateByContributionId });
80
- await note(`Section '${section}' prepared`, "Updated");
81
- }
82
-
83
- const validatedConfig = await applyAndValidateContributionSchemas(configPath, next);
84
-
85
- await writeConfigWithValidation(configPath, validatedConfig, {
86
- validate: true,
87
- createBackup: true,
88
- });
89
- await note(`Saved to ${configPath}`, "Saved");
90
-
91
- outro("Configuration updated.");
92
- }