@ncoderz/awa 1.0.0 → 1.2.0

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 (128) hide show
  1. package/README.md +96 -16
  2. package/dist/chunk-3SSUJFKN.js +625 -0
  3. package/dist/chunk-3SSUJFKN.js.map +1 -0
  4. package/dist/config-2TOQATI3.js +10 -0
  5. package/dist/config-2TOQATI3.js.map +1 -0
  6. package/dist/index.js +2190 -414
  7. package/dist/index.js.map +1 -1
  8. package/package.json +10 -4
  9. package/templates/awa/.agent/skills/awa-align/SKILL.md +3 -0
  10. package/templates/awa/.agent/skills/awa-check/SKILL.md +4 -0
  11. package/templates/awa/.agent/skills/awa-usage/SKILL.md +3 -0
  12. package/templates/awa/.agent/workflows/awa-align.md +3 -0
  13. package/templates/awa/.agent/workflows/awa-check.md +4 -0
  14. package/templates/awa/.agents/skills/awa-align/SKILL.md +3 -0
  15. package/templates/awa/.agents/skills/awa-check/SKILL.md +4 -0
  16. package/templates/awa/.agents/skills/awa-usage/SKILL.md +3 -0
  17. package/templates/awa/.awa/.agent/schemas/ALIGN_REPORT.schema.yaml +83 -0
  18. package/templates/awa/.awa/.agent/schemas/API.schema.yaml +7 -0
  19. package/templates/awa/.awa/.agent/schemas/ARCHITECTURE.schema.yaml +260 -0
  20. package/templates/awa/.awa/.agent/schemas/DESIGN.schema.yaml +361 -0
  21. package/templates/awa/.awa/.agent/schemas/EXAMPLES.schema.yaml +98 -0
  22. package/templates/awa/.awa/.agent/schemas/FEAT.schema.yaml +143 -0
  23. package/templates/awa/.awa/.agent/schemas/PLAN.schema.yaml +151 -0
  24. package/templates/awa/.awa/.agent/schemas/README.schema.yaml +137 -0
  25. package/templates/awa/.awa/.agent/schemas/REQ.schema.yaml +169 -0
  26. package/templates/awa/.awa/.agent/schemas/TASK.schema.yaml +200 -0
  27. package/templates/awa/.claude/agents/awa.md +2 -2
  28. package/templates/awa/.claude/skills/awa-align/SKILL.md +3 -0
  29. package/templates/awa/.claude/skills/awa-check/SKILL.md +4 -0
  30. package/templates/awa/.claude/skills/awa-usage/SKILL.md +3 -0
  31. package/templates/awa/.codex/prompts/awa-align.md +3 -0
  32. package/templates/awa/.codex/prompts/awa-check.md +4 -0
  33. package/templates/awa/.cursor/rules/awa-agent.md +1 -1
  34. package/templates/awa/.cursor/rules/awa-align.md +8 -0
  35. package/templates/awa/.cursor/rules/awa-check.md +9 -0
  36. package/templates/awa/.gemini/commands/awa-align.md +3 -0
  37. package/templates/awa/.gemini/commands/awa-check.md +4 -0
  38. package/templates/awa/.gemini/skills/awa-align/SKILL.md +3 -0
  39. package/templates/awa/.gemini/skills/awa-check/SKILL.md +4 -0
  40. package/templates/awa/.gemini/skills/awa-usage/SKILL.md +3 -0
  41. package/templates/awa/.github/agents/awa.agent.md +2 -2
  42. package/templates/awa/.github/prompts/awa.align.prompt.md +8 -0
  43. package/templates/awa/.github/prompts/awa.check.prompt.md +9 -0
  44. package/templates/awa/.github/skills/awa-align/SKILL.md +8 -0
  45. package/templates/awa/.github/skills/awa-check/SKILL.md +9 -0
  46. package/templates/awa/.github/skills/awa-usage/SKILL.md +8 -0
  47. package/templates/awa/.kilocode/rules/awa-agent.md +1 -1
  48. package/templates/awa/.kilocode/skills/awa-align/SKILL.md +3 -0
  49. package/templates/awa/.kilocode/skills/awa-check/SKILL.md +4 -0
  50. package/templates/awa/.kilocode/skills/awa-usage/SKILL.md +3 -0
  51. package/templates/awa/.kilocode/workflows/awa-align.md +3 -0
  52. package/templates/awa/.kilocode/workflows/awa-check.md +4 -0
  53. package/templates/awa/.opencode/agents/awa.md +2 -2
  54. package/templates/awa/.opencode/commands/awa-align.md +3 -0
  55. package/templates/awa/.opencode/commands/awa-check.md +4 -0
  56. package/templates/awa/.opencode/skills/awa-align/SKILL.md +3 -0
  57. package/templates/awa/.opencode/skills/awa-check/SKILL.md +4 -0
  58. package/templates/awa/.opencode/skills/awa-usage/SKILL.md +3 -0
  59. package/templates/awa/.qwen/commands/awa-align.md +3 -0
  60. package/templates/awa/.qwen/commands/awa-check.md +4 -0
  61. package/templates/awa/.qwen/skills/awa-align/SKILL.md +3 -0
  62. package/templates/awa/.qwen/skills/awa-check/SKILL.md +4 -0
  63. package/templates/awa/.qwen/skills/awa-usage/SKILL.md +3 -0
  64. package/templates/awa/.roo/rules/awa-agent.md +1 -1
  65. package/templates/awa/.roo/skills/awa-align/SKILL.md +3 -0
  66. package/templates/awa/.roo/skills/awa-check/SKILL.md +4 -0
  67. package/templates/awa/.roo/skills/awa-usage/SKILL.md +3 -0
  68. package/templates/awa/.windsurf/rules/awa-agent.md +1 -1
  69. package/templates/awa/.windsurf/skills/awa-align/SKILL.md +3 -0
  70. package/templates/awa/.windsurf/skills/awa-check/SKILL.md +4 -0
  71. package/templates/awa/.windsurf/skills/awa-usage/SKILL.md +3 -0
  72. package/templates/awa/AGENTS.md +1 -1
  73. package/templates/awa/CLAUDE.md +1 -1
  74. package/templates/awa/GEMINI.md +1 -1
  75. package/templates/awa/QWEN.md +1 -1
  76. package/templates/awa/_README.md +3 -2
  77. package/templates/awa/_delete.txt +49 -0
  78. package/templates/awa/_partials/{_cmd.awa-validate-alignment.md → _cmd.awa-align.md} +1 -1
  79. package/templates/awa/_partials/_cmd.awa-check.md +6 -0
  80. package/templates/awa/_partials/_skill.awa-align.md +6 -0
  81. package/templates/awa/_partials/_skill.awa-check.md +6 -0
  82. package/templates/awa/_partials/_skill.awa-usage.md +6 -0
  83. package/templates/awa/_partials/{awa.validate-alignment.md → awa.align.md} +2 -2
  84. package/templates/awa/_partials/awa.architecture.md +1 -1
  85. package/templates/awa/_partials/awa.check.md +73 -0
  86. package/templates/awa/_partials/awa.code.md +1 -0
  87. package/templates/awa/_partials/awa.core.md +24 -10
  88. package/templates/awa/_partials/awa.design.md +3 -2
  89. package/templates/awa/_partials/awa.documentation.md +1 -1
  90. package/templates/awa/_partials/awa.examples.md +1 -1
  91. package/templates/awa/_partials/awa.feature.md +1 -1
  92. package/templates/awa/_partials/awa.plan.md +1 -1
  93. package/templates/awa/_partials/awa.refactor.md +1 -0
  94. package/templates/awa/_partials/awa.requirements.md +2 -1
  95. package/templates/awa/_partials/awa.tasks.md +3 -3
  96. package/templates/awa/_partials/awa.upgrade.md +13 -12
  97. package/templates/awa/_partials/awa.usage.md +265 -0
  98. package/templates/awa/_tests/claude.toml +7 -0
  99. package/templates/awa/_tests/copilot.toml +6 -0
  100. package/templates/awa/.agent/skills/awa-validate-alignment/SKILL.md +0 -3
  101. package/templates/awa/.agent/workflows/awa-validate-alignment.md +0 -3
  102. package/templates/awa/.agents/skills/awa-validate-alignment/SKILL.md +0 -3
  103. package/templates/awa/.awa/.agent/schemas/ALIGN_REPORT.schema.md +0 -156
  104. package/templates/awa/.awa/.agent/schemas/API.schema.md +0 -4
  105. package/templates/awa/.awa/.agent/schemas/ARCHITECTURE.schema.md +0 -176
  106. package/templates/awa/.awa/.agent/schemas/DESIGN.schema.md +0 -253
  107. package/templates/awa/.awa/.agent/schemas/EXAMPLES.schema.md +0 -51
  108. package/templates/awa/.awa/.agent/schemas/FEAT.schema.md +0 -61
  109. package/templates/awa/.awa/.agent/schemas/PLAN.schema.md +0 -8
  110. package/templates/awa/.awa/.agent/schemas/README.schema.md +0 -133
  111. package/templates/awa/.awa/.agent/schemas/REQ.schema.md +0 -125
  112. package/templates/awa/.awa/.agent/schemas/TASK.schema.md +0 -137
  113. package/templates/awa/.claude/skills/awa-validate-alignment/SKILL.md +0 -3
  114. package/templates/awa/.codex/prompts/awa-validate-alignment.md +0 -3
  115. package/templates/awa/.cursor/rules/awa-validate-alignment.md +0 -8
  116. package/templates/awa/.gemini/commands/awa-validate-alignment.md +0 -3
  117. package/templates/awa/.gemini/skills/awa-validate-alignment/SKILL.md +0 -3
  118. package/templates/awa/.github/prompts/awa.validate-alignment.prompt.md +0 -8
  119. package/templates/awa/.github/skills/awa-validate-alignment/SKILL.md +0 -8
  120. package/templates/awa/.kilocode/skills/awa-validate-alignment/SKILL.md +0 -3
  121. package/templates/awa/.kilocode/workflows/awa-validate-alignment.md +0 -3
  122. package/templates/awa/.opencode/commands/awa-validate-alignment.md +0 -3
  123. package/templates/awa/.opencode/skills/awa-validate-alignment/SKILL.md +0 -3
  124. package/templates/awa/.qwen/commands/awa-validate-alignment.md +0 -3
  125. package/templates/awa/.qwen/skills/awa-validate-alignment/SKILL.md +0 -3
  126. package/templates/awa/.roo/skills/awa-validate-alignment/SKILL.md +0 -3
  127. package/templates/awa/.windsurf/skills/awa-validate-alignment/SKILL.md +0 -3
  128. package/templates/awa/_partials/_skill.awa-validate-alignment.md +0 -6
@@ -0,0 +1,625 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/core/config.ts
4
+ import { parse } from "smol-toml";
5
+
6
+ // src/types/index.ts
7
+ var DiffError = class extends Error {
8
+ constructor(message) {
9
+ super(message);
10
+ this.name = "DiffError";
11
+ }
12
+ };
13
+ var ConfigError = class extends Error {
14
+ constructor(message, code, filePath) {
15
+ super(message);
16
+ this.code = code;
17
+ this.filePath = filePath;
18
+ this.name = "ConfigError";
19
+ }
20
+ };
21
+ var TemplateError = class extends Error {
22
+ constructor(message, code, source) {
23
+ super(message);
24
+ this.code = code;
25
+ this.source = source;
26
+ this.name = "TemplateError";
27
+ }
28
+ };
29
+ var GenerationError = class extends Error {
30
+ constructor(message, code) {
31
+ super(message);
32
+ this.code = code;
33
+ this.name = "GenerationError";
34
+ }
35
+ };
36
+
37
+ // src/utils/fs.ts
38
+ import { mkdir, readdir, readFile, rm, stat, writeFile } from "fs/promises";
39
+ import { homedir } from "os";
40
+ import { dirname, join } from "path";
41
+ import { fileURLToPath } from "url";
42
+ async function ensureDir(dirPath) {
43
+ await mkdir(dirPath, { recursive: true });
44
+ }
45
+ async function pathExists(path) {
46
+ try {
47
+ await stat(path);
48
+ return true;
49
+ } catch {
50
+ return false;
51
+ }
52
+ }
53
+ async function readTextFile(path) {
54
+ return readFile(path, "utf-8");
55
+ }
56
+ async function readBinaryFile(path) {
57
+ return readFile(path);
58
+ }
59
+ async function writeTextFile(path, content) {
60
+ await ensureDir(dirname(path));
61
+ await writeFile(path, content, "utf-8");
62
+ }
63
+ async function* walkDirectory(dir) {
64
+ const entries = await readdir(dir, { withFileTypes: true });
65
+ for (const entry of entries) {
66
+ const fullPath = join(dir, entry.name);
67
+ if (entry.isDirectory()) {
68
+ if (entry.name.startsWith("_")) {
69
+ continue;
70
+ }
71
+ yield* walkDirectory(fullPath);
72
+ } else if (entry.isFile()) {
73
+ if (entry.name.startsWith("_")) {
74
+ continue;
75
+ }
76
+ yield fullPath;
77
+ }
78
+ }
79
+ }
80
+ function getCacheDir() {
81
+ return join(homedir(), ".cache", "awa", "templates");
82
+ }
83
+ function getTemplateDir() {
84
+ const currentFile = fileURLToPath(import.meta.url);
85
+ const currentDir = dirname(currentFile);
86
+ if (currentDir.includes("/dist")) {
87
+ return join(dirname(currentDir), "templates");
88
+ }
89
+ return join(currentDir, "..", "..", "templates");
90
+ }
91
+ async function rmDir(dirPath) {
92
+ await rm(dirPath, { recursive: true, force: true });
93
+ }
94
+ async function deleteFile(filePath) {
95
+ await rm(filePath, { force: true });
96
+ }
97
+
98
+ // src/utils/logger.ts
99
+ import chalk from "chalk";
100
+ var Logger = class {
101
+ info(message) {
102
+ console.log(chalk.blue("\u2139"), message);
103
+ }
104
+ success(message) {
105
+ console.log(chalk.green("\u2714"), message);
106
+ }
107
+ warn(message) {
108
+ console.warn(chalk.yellow("\u26A0"), message);
109
+ }
110
+ error(message) {
111
+ console.error(chalk.red("\u2716"), message);
112
+ }
113
+ fileAction(action) {
114
+ const { type, outputPath } = action;
115
+ switch (type) {
116
+ case "create":
117
+ console.log(chalk.green(" + "), chalk.dim(outputPath));
118
+ break;
119
+ case "overwrite":
120
+ console.log(chalk.yellow(" ~ "), chalk.dim(outputPath));
121
+ break;
122
+ case "skip-user":
123
+ console.log(chalk.blue(" - "), chalk.dim(outputPath), chalk.dim("(skipped)"));
124
+ break;
125
+ case "skip-empty":
126
+ console.log(chalk.dim(" \xB7 "), chalk.dim(outputPath), chalk.dim("(empty)"));
127
+ break;
128
+ case "skip-equal":
129
+ console.log(chalk.dim(" = "), chalk.dim(outputPath), chalk.dim("(unchanged)"));
130
+ break;
131
+ case "delete":
132
+ console.log(chalk.red(" \u2716 "), chalk.dim(outputPath), chalk.red("(deleted)"));
133
+ break;
134
+ }
135
+ }
136
+ // @awa-impl: GEN-9_AC-1, GEN-9_AC-2, GEN-9_AC-3, GEN-9_AC-4, GEN-9_AC-5, GEN-9_AC-6
137
+ summary(result) {
138
+ console.log("");
139
+ console.log(chalk.bold("Summary:"));
140
+ if (result.created === 0 && result.overwritten === 0 && result.deleted === 0) {
141
+ console.log(chalk.yellow(" \u26A0 No files were created, overwritten, or deleted"));
142
+ }
143
+ if (result.created > 0) {
144
+ console.log(chalk.green(` Created: ${result.created}`));
145
+ }
146
+ if (result.overwritten > 0) {
147
+ console.log(chalk.yellow(` Overwritten: ${result.overwritten}`));
148
+ }
149
+ if (result.deleted > 0) {
150
+ console.log(chalk.red(` Deleted: ${result.deleted}`));
151
+ }
152
+ if (result.skippedEqual > 0) {
153
+ console.log(chalk.dim(` Skipped (equal): ${result.skippedEqual}`));
154
+ }
155
+ if (result.skippedUser > 0) {
156
+ console.log(chalk.blue(` Skipped (user): ${result.skippedUser}`));
157
+ }
158
+ if (result.skippedEmpty > 0) {
159
+ console.log(chalk.dim(` Skipped (empty): ${result.skippedEmpty}`));
160
+ }
161
+ console.log("");
162
+ }
163
+ // @awa-impl: DIFF-4_AC-3
164
+ diffLine(line, type) {
165
+ switch (type) {
166
+ case "add":
167
+ console.log(chalk.green(line));
168
+ break;
169
+ case "remove":
170
+ console.log(chalk.red(line));
171
+ break;
172
+ case "context":
173
+ console.log(chalk.dim(line));
174
+ break;
175
+ }
176
+ }
177
+ // @awa-impl: DIFF-4_AC-4, DIFF-4_AC-5
178
+ diffSummary(result) {
179
+ console.log("");
180
+ const filesCompared = result.identical + result.modified + result.newFiles + result.extraFiles + result.binaryDiffers + result.deleteListed;
181
+ const differences = result.modified + result.newFiles + result.extraFiles + result.binaryDiffers + result.deleteListed;
182
+ console.log(chalk.bold(`${filesCompared} files compared, ${differences} differences`));
183
+ if (!result.hasDifferences) {
184
+ console.log(chalk.green("\u2714 No differences found"));
185
+ }
186
+ console.log(chalk.bold("Summary:"));
187
+ console.log(chalk.dim(` Identical: ${result.identical}`));
188
+ if (result.modified > 0) {
189
+ console.log(chalk.yellow(` Modified: ${result.modified}`));
190
+ }
191
+ if (result.newFiles > 0) {
192
+ console.log(chalk.green(` New: ${result.newFiles}`));
193
+ }
194
+ if (result.extraFiles > 0) {
195
+ console.log(chalk.red(` Extra: ${result.extraFiles}`));
196
+ }
197
+ if (result.binaryDiffers > 0) {
198
+ console.log(chalk.red(` Binary differs: ${result.binaryDiffers}`));
199
+ }
200
+ if (result.deleteListed > 0) {
201
+ console.log(chalk.red(` Delete listed: ${result.deleteListed}`));
202
+ }
203
+ console.log("");
204
+ }
205
+ };
206
+ var logger = new Logger();
207
+
208
+ // src/core/config.ts
209
+ var DEFAULT_CONFIG_PATH = ".awa.toml";
210
+ var ConfigLoader = class {
211
+ // @awa-impl: CFG-1_AC-1, CFG-1_AC-2, CFG-1_AC-3, CFG-1_AC-4
212
+ async load(configPath) {
213
+ const pathToLoad = configPath ?? DEFAULT_CONFIG_PATH;
214
+ const exists = await pathExists(pathToLoad);
215
+ if (configPath && !exists) {
216
+ throw new ConfigError(
217
+ `Configuration file not found: ${configPath}`,
218
+ "FILE_NOT_FOUND",
219
+ configPath
220
+ );
221
+ }
222
+ if (!configPath && !exists) {
223
+ return null;
224
+ }
225
+ try {
226
+ const content = await readTextFile(pathToLoad);
227
+ const parsed = parse(content);
228
+ const config = {};
229
+ if (parsed.output !== void 0) {
230
+ if (typeof parsed.output !== "string") {
231
+ throw new ConfigError(
232
+ `Invalid type for 'output': expected string, got ${typeof parsed.output}`,
233
+ "INVALID_TYPE",
234
+ pathToLoad
235
+ );
236
+ }
237
+ config.output = parsed.output;
238
+ }
239
+ if (parsed.template !== void 0) {
240
+ if (typeof parsed.template !== "string") {
241
+ throw new ConfigError(
242
+ `Invalid type for 'template': expected string, got ${typeof parsed.template}`,
243
+ "INVALID_TYPE",
244
+ pathToLoad
245
+ );
246
+ }
247
+ config.template = parsed.template;
248
+ }
249
+ if (parsed.features !== void 0) {
250
+ if (!Array.isArray(parsed.features) || !parsed.features.every((f) => typeof f === "string")) {
251
+ throw new ConfigError(
252
+ `Invalid type for 'features': expected array of strings`,
253
+ "INVALID_TYPE",
254
+ pathToLoad
255
+ );
256
+ }
257
+ config.features = parsed.features;
258
+ }
259
+ if (parsed.preset !== void 0) {
260
+ if (!Array.isArray(parsed.preset) || !parsed.preset.every((p) => typeof p === "string")) {
261
+ throw new ConfigError(
262
+ `Invalid type for 'preset': expected array of strings`,
263
+ "INVALID_TYPE",
264
+ pathToLoad
265
+ );
266
+ }
267
+ config.preset = parsed.preset;
268
+ }
269
+ if (parsed["remove-features"] !== void 0) {
270
+ if (!Array.isArray(parsed["remove-features"]) || !parsed["remove-features"].every((f) => typeof f === "string")) {
271
+ throw new ConfigError(
272
+ `Invalid type for 'remove-features': expected array of strings`,
273
+ "INVALID_TYPE",
274
+ pathToLoad
275
+ );
276
+ }
277
+ config["remove-features"] = parsed["remove-features"];
278
+ }
279
+ if (parsed.force !== void 0) {
280
+ if (typeof parsed.force !== "boolean") {
281
+ throw new ConfigError(
282
+ `Invalid type for 'force': expected boolean, got ${typeof parsed.force}`,
283
+ "INVALID_TYPE",
284
+ pathToLoad
285
+ );
286
+ }
287
+ config.force = parsed.force;
288
+ }
289
+ if (parsed["dry-run"] !== void 0) {
290
+ if (typeof parsed["dry-run"] !== "boolean") {
291
+ throw new ConfigError(
292
+ `Invalid type for 'dry-run': expected boolean, got ${typeof parsed["dry-run"]}`,
293
+ "INVALID_TYPE",
294
+ pathToLoad
295
+ );
296
+ }
297
+ config["dry-run"] = parsed["dry-run"];
298
+ }
299
+ if (parsed.delete !== void 0) {
300
+ if (typeof parsed.delete !== "boolean") {
301
+ throw new ConfigError(
302
+ `Invalid type for 'delete': expected boolean, got ${typeof parsed.delete}`,
303
+ "INVALID_TYPE",
304
+ pathToLoad
305
+ );
306
+ }
307
+ config.delete = parsed.delete;
308
+ }
309
+ if (parsed.refresh !== void 0) {
310
+ if (typeof parsed.refresh !== "boolean") {
311
+ throw new ConfigError(
312
+ `Invalid type for 'refresh': expected boolean, got ${typeof parsed.refresh}`,
313
+ "INVALID_TYPE",
314
+ pathToLoad
315
+ );
316
+ }
317
+ config.refresh = parsed.refresh;
318
+ }
319
+ if (parsed.presets !== void 0) {
320
+ if (parsed.presets === null || typeof parsed.presets !== "object" || Array.isArray(parsed.presets)) {
321
+ throw new ConfigError(
322
+ `Invalid type for 'presets': expected table of string arrays`,
323
+ "INVALID_PRESET",
324
+ pathToLoad
325
+ );
326
+ }
327
+ const defs = {};
328
+ for (const [presetName, value] of Object.entries(
329
+ parsed.presets
330
+ )) {
331
+ if (!Array.isArray(value) || !value.every((v) => typeof v === "string")) {
332
+ throw new ConfigError(
333
+ `Invalid preset '${presetName}': expected array of strings`,
334
+ "INVALID_PRESET",
335
+ pathToLoad
336
+ );
337
+ }
338
+ defs[presetName] = value;
339
+ }
340
+ config.presets = defs;
341
+ }
342
+ if (parsed["list-unknown"] !== void 0) {
343
+ if (typeof parsed["list-unknown"] !== "boolean") {
344
+ throw new ConfigError(
345
+ `Invalid type for 'list-unknown': expected boolean, got ${typeof parsed["list-unknown"]}`,
346
+ "INVALID_TYPE",
347
+ pathToLoad
348
+ );
349
+ }
350
+ config["list-unknown"] = parsed["list-unknown"];
351
+ }
352
+ if (parsed.check !== void 0) {
353
+ if (parsed.check === null || typeof parsed.check !== "object" || Array.isArray(parsed.check)) {
354
+ throw new ConfigError(
355
+ `Invalid type for 'check': expected table`,
356
+ "INVALID_TYPE",
357
+ pathToLoad
358
+ );
359
+ }
360
+ config.check = parsed.check;
361
+ }
362
+ if (parsed.overlay !== void 0) {
363
+ if (!Array.isArray(parsed.overlay) || !parsed.overlay.every((o) => typeof o === "string")) {
364
+ throw new ConfigError(
365
+ `Invalid type for 'overlay': expected array of strings`,
366
+ "INVALID_TYPE",
367
+ pathToLoad
368
+ );
369
+ }
370
+ config.overlay = parsed.overlay;
371
+ }
372
+ if (parsed["update-check"] !== void 0) {
373
+ if (parsed["update-check"] === null || typeof parsed["update-check"] !== "object" || Array.isArray(parsed["update-check"])) {
374
+ throw new ConfigError(
375
+ `Invalid type for 'update-check': expected table`,
376
+ "INVALID_TYPE",
377
+ pathToLoad
378
+ );
379
+ }
380
+ const raw = parsed["update-check"];
381
+ const updateCheckConfig = {};
382
+ if (raw.enabled !== void 0) {
383
+ if (typeof raw.enabled !== "boolean") {
384
+ throw new ConfigError(
385
+ `Invalid type for 'update-check.enabled': expected boolean, got ${typeof raw.enabled}`,
386
+ "INVALID_TYPE",
387
+ pathToLoad
388
+ );
389
+ }
390
+ updateCheckConfig.enabled = raw.enabled;
391
+ }
392
+ if (raw.interval !== void 0) {
393
+ if (typeof raw.interval !== "number") {
394
+ throw new ConfigError(
395
+ `Invalid type for 'update-check.interval': expected number, got ${typeof raw.interval}`,
396
+ "INVALID_TYPE",
397
+ pathToLoad
398
+ );
399
+ }
400
+ updateCheckConfig.interval = raw.interval;
401
+ }
402
+ config["update-check"] = updateCheckConfig;
403
+ }
404
+ if (parsed.targets !== void 0) {
405
+ if (parsed.targets === null || typeof parsed.targets !== "object" || Array.isArray(parsed.targets)) {
406
+ throw new ConfigError(
407
+ `Invalid type for 'targets': expected table of target sections`,
408
+ "INVALID_TYPE",
409
+ pathToLoad
410
+ );
411
+ }
412
+ const targets = {};
413
+ for (const [targetName, targetValue] of Object.entries(
414
+ parsed.targets
415
+ )) {
416
+ if (targetValue === null || typeof targetValue !== "object" || Array.isArray(targetValue)) {
417
+ throw new ConfigError(
418
+ `Invalid target '${targetName}': expected table`,
419
+ "INVALID_TYPE",
420
+ pathToLoad
421
+ );
422
+ }
423
+ targets[targetName] = this.parseTargetSection(
424
+ targetValue,
425
+ targetName,
426
+ pathToLoad
427
+ );
428
+ }
429
+ config.targets = targets;
430
+ }
431
+ const knownKeys = /* @__PURE__ */ new Set([
432
+ "output",
433
+ "template",
434
+ "features",
435
+ "preset",
436
+ "remove-features",
437
+ "presets",
438
+ "force",
439
+ "dry-run",
440
+ "delete",
441
+ "refresh",
442
+ "list-unknown",
443
+ "check",
444
+ "targets",
445
+ "overlay",
446
+ "update-check"
447
+ ]);
448
+ for (const key of Object.keys(parsed)) {
449
+ if (!knownKeys.has(key)) {
450
+ logger.warn(`Unknown configuration option: '${key}'`);
451
+ }
452
+ }
453
+ return config;
454
+ } catch (error) {
455
+ if (error instanceof ConfigError) {
456
+ throw error;
457
+ }
458
+ throw new ConfigError(
459
+ `Failed to parse TOML configuration: ${error instanceof Error ? error.message : String(error)}`,
460
+ "PARSE_ERROR",
461
+ pathToLoad
462
+ );
463
+ }
464
+ }
465
+ // @awa-impl: CFG-4_AC-1, CFG-4_AC-2, CFG-4_AC-3, CFG-4_AC-4
466
+ // @awa-impl: CLI-2_AC-2, CLI-2_AC-3, CLI-2_AC-4
467
+ merge(cli, file) {
468
+ const output = cli.output ?? file?.output;
469
+ if (!output) {
470
+ throw new ConfigError(
471
+ "Output directory is required. Provide it as a positional argument or in the config file.",
472
+ "MISSING_OUTPUT",
473
+ null
474
+ );
475
+ }
476
+ const template = cli.template ?? file?.template ?? null;
477
+ const features = cli.features ?? file?.features ?? [];
478
+ const preset = cli.preset ?? file?.preset ?? [];
479
+ const removeFeatures = cli.removeFeatures ?? file?.["remove-features"] ?? [];
480
+ const presets = file?.presets ?? {};
481
+ const force = cli.force ?? file?.force ?? false;
482
+ const dryRun = cli.dryRun ?? file?.["dry-run"] ?? false;
483
+ const enableDelete = cli.delete ?? file?.delete ?? false;
484
+ const refresh = cli.refresh ?? file?.refresh ?? false;
485
+ const listUnknown = cli.listUnknown ?? file?.["list-unknown"] ?? false;
486
+ const overlay = cli.overlay ?? file?.overlay ?? [];
487
+ const json = cli.json ?? false;
488
+ const summary = cli.summary ?? false;
489
+ return {
490
+ output,
491
+ template,
492
+ features,
493
+ preset,
494
+ removeFeatures,
495
+ force,
496
+ dryRun,
497
+ delete: enableDelete,
498
+ refresh,
499
+ presets,
500
+ listUnknown,
501
+ overlay,
502
+ json,
503
+ summary
504
+ };
505
+ }
506
+ // Parse a [targets.<name>] section, validating allowed keys and types
507
+ parseTargetSection(section, targetName, configPath) {
508
+ const target = {};
509
+ const allowedKeys = /* @__PURE__ */ new Set(["output", "template", "features", "preset", "remove-features"]);
510
+ for (const key of Object.keys(section)) {
511
+ if (!allowedKeys.has(key)) {
512
+ logger.warn(`Unknown option in target '${targetName}': '${key}'`);
513
+ }
514
+ }
515
+ if (section.output !== void 0) {
516
+ if (typeof section.output !== "string") {
517
+ throw new ConfigError(
518
+ `Invalid type for 'targets.${targetName}.output': expected string, got ${typeof section.output}`,
519
+ "INVALID_TYPE",
520
+ configPath
521
+ );
522
+ }
523
+ target.output = section.output;
524
+ }
525
+ if (section.template !== void 0) {
526
+ if (typeof section.template !== "string") {
527
+ throw new ConfigError(
528
+ `Invalid type for 'targets.${targetName}.template': expected string, got ${typeof section.template}`,
529
+ "INVALID_TYPE",
530
+ configPath
531
+ );
532
+ }
533
+ target.template = section.template;
534
+ }
535
+ if (section.features !== void 0) {
536
+ if (!Array.isArray(section.features) || !section.features.every((f) => typeof f === "string")) {
537
+ throw new ConfigError(
538
+ `Invalid type for 'targets.${targetName}.features': expected array of strings`,
539
+ "INVALID_TYPE",
540
+ configPath
541
+ );
542
+ }
543
+ target.features = section.features;
544
+ }
545
+ if (section.preset !== void 0) {
546
+ if (!Array.isArray(section.preset) || !section.preset.every((p) => typeof p === "string")) {
547
+ throw new ConfigError(
548
+ `Invalid type for 'targets.${targetName}.preset': expected array of strings`,
549
+ "INVALID_TYPE",
550
+ configPath
551
+ );
552
+ }
553
+ target.preset = section.preset;
554
+ }
555
+ if (section["remove-features"] !== void 0) {
556
+ if (!Array.isArray(section["remove-features"]) || !section["remove-features"].every((f) => typeof f === "string")) {
557
+ throw new ConfigError(
558
+ `Invalid type for 'targets.${targetName}.remove-features': expected array of strings`,
559
+ "INVALID_TYPE",
560
+ configPath
561
+ );
562
+ }
563
+ target["remove-features"] = section["remove-features"];
564
+ }
565
+ return target;
566
+ }
567
+ // Resolve a target by merging target config with root config (target overrides root via nullish coalescing)
568
+ resolveTarget(targetName, fileConfig) {
569
+ const targets = fileConfig.targets;
570
+ if (!targets || Object.keys(targets).length === 0) {
571
+ throw new ConfigError(
572
+ "No targets defined in configuration. Add [targets.<name>] sections to .awa.toml.",
573
+ "NO_TARGETS",
574
+ null
575
+ );
576
+ }
577
+ const target = targets[targetName];
578
+ if (!target) {
579
+ throw new ConfigError(
580
+ `Unknown target: '${targetName}'. Available targets: ${Object.keys(targets).join(", ")}`,
581
+ "UNKNOWN_TARGET",
582
+ null
583
+ );
584
+ }
585
+ return {
586
+ ...fileConfig,
587
+ output: target.output ?? fileConfig.output,
588
+ template: target.template ?? fileConfig.template,
589
+ features: target.features ?? fileConfig.features,
590
+ preset: target.preset ?? fileConfig.preset,
591
+ "remove-features": target["remove-features"] ?? fileConfig["remove-features"],
592
+ targets: void 0
593
+ // Don't propagate targets into resolved config
594
+ };
595
+ }
596
+ // Get all target names from config
597
+ getTargetNames(fileConfig) {
598
+ if (!fileConfig?.targets) {
599
+ return [];
600
+ }
601
+ return Object.keys(fileConfig.targets);
602
+ }
603
+ };
604
+ var configLoader = new ConfigLoader();
605
+
606
+ export {
607
+ DiffError,
608
+ ConfigError,
609
+ TemplateError,
610
+ GenerationError,
611
+ ensureDir,
612
+ pathExists,
613
+ readTextFile,
614
+ readBinaryFile,
615
+ writeTextFile,
616
+ walkDirectory,
617
+ getCacheDir,
618
+ getTemplateDir,
619
+ rmDir,
620
+ deleteFile,
621
+ logger,
622
+ ConfigLoader,
623
+ configLoader
624
+ };
625
+ //# sourceMappingURL=chunk-3SSUJFKN.js.map