@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.
- package/README.md +96 -16
- package/dist/chunk-3SSUJFKN.js +625 -0
- package/dist/chunk-3SSUJFKN.js.map +1 -0
- package/dist/config-2TOQATI3.js +10 -0
- package/dist/config-2TOQATI3.js.map +1 -0
- package/dist/index.js +2190 -414
- package/dist/index.js.map +1 -1
- package/package.json +10 -4
- package/templates/awa/.agent/skills/awa-align/SKILL.md +3 -0
- package/templates/awa/.agent/skills/awa-check/SKILL.md +4 -0
- package/templates/awa/.agent/skills/awa-usage/SKILL.md +3 -0
- package/templates/awa/.agent/workflows/awa-align.md +3 -0
- package/templates/awa/.agent/workflows/awa-check.md +4 -0
- package/templates/awa/.agents/skills/awa-align/SKILL.md +3 -0
- package/templates/awa/.agents/skills/awa-check/SKILL.md +4 -0
- package/templates/awa/.agents/skills/awa-usage/SKILL.md +3 -0
- package/templates/awa/.awa/.agent/schemas/ALIGN_REPORT.schema.yaml +83 -0
- package/templates/awa/.awa/.agent/schemas/API.schema.yaml +7 -0
- package/templates/awa/.awa/.agent/schemas/ARCHITECTURE.schema.yaml +260 -0
- package/templates/awa/.awa/.agent/schemas/DESIGN.schema.yaml +361 -0
- package/templates/awa/.awa/.agent/schemas/EXAMPLES.schema.yaml +98 -0
- package/templates/awa/.awa/.agent/schemas/FEAT.schema.yaml +143 -0
- package/templates/awa/.awa/.agent/schemas/PLAN.schema.yaml +151 -0
- package/templates/awa/.awa/.agent/schemas/README.schema.yaml +137 -0
- package/templates/awa/.awa/.agent/schemas/REQ.schema.yaml +169 -0
- package/templates/awa/.awa/.agent/schemas/TASK.schema.yaml +200 -0
- package/templates/awa/.claude/agents/awa.md +2 -2
- package/templates/awa/.claude/skills/awa-align/SKILL.md +3 -0
- package/templates/awa/.claude/skills/awa-check/SKILL.md +4 -0
- package/templates/awa/.claude/skills/awa-usage/SKILL.md +3 -0
- package/templates/awa/.codex/prompts/awa-align.md +3 -0
- package/templates/awa/.codex/prompts/awa-check.md +4 -0
- package/templates/awa/.cursor/rules/awa-agent.md +1 -1
- package/templates/awa/.cursor/rules/awa-align.md +8 -0
- package/templates/awa/.cursor/rules/awa-check.md +9 -0
- package/templates/awa/.gemini/commands/awa-align.md +3 -0
- package/templates/awa/.gemini/commands/awa-check.md +4 -0
- package/templates/awa/.gemini/skills/awa-align/SKILL.md +3 -0
- package/templates/awa/.gemini/skills/awa-check/SKILL.md +4 -0
- package/templates/awa/.gemini/skills/awa-usage/SKILL.md +3 -0
- package/templates/awa/.github/agents/awa.agent.md +2 -2
- package/templates/awa/.github/prompts/awa.align.prompt.md +8 -0
- package/templates/awa/.github/prompts/awa.check.prompt.md +9 -0
- package/templates/awa/.github/skills/awa-align/SKILL.md +8 -0
- package/templates/awa/.github/skills/awa-check/SKILL.md +9 -0
- package/templates/awa/.github/skills/awa-usage/SKILL.md +8 -0
- package/templates/awa/.kilocode/rules/awa-agent.md +1 -1
- package/templates/awa/.kilocode/skills/awa-align/SKILL.md +3 -0
- package/templates/awa/.kilocode/skills/awa-check/SKILL.md +4 -0
- package/templates/awa/.kilocode/skills/awa-usage/SKILL.md +3 -0
- package/templates/awa/.kilocode/workflows/awa-align.md +3 -0
- package/templates/awa/.kilocode/workflows/awa-check.md +4 -0
- package/templates/awa/.opencode/agents/awa.md +2 -2
- package/templates/awa/.opencode/commands/awa-align.md +3 -0
- package/templates/awa/.opencode/commands/awa-check.md +4 -0
- package/templates/awa/.opencode/skills/awa-align/SKILL.md +3 -0
- package/templates/awa/.opencode/skills/awa-check/SKILL.md +4 -0
- package/templates/awa/.opencode/skills/awa-usage/SKILL.md +3 -0
- package/templates/awa/.qwen/commands/awa-align.md +3 -0
- package/templates/awa/.qwen/commands/awa-check.md +4 -0
- package/templates/awa/.qwen/skills/awa-align/SKILL.md +3 -0
- package/templates/awa/.qwen/skills/awa-check/SKILL.md +4 -0
- package/templates/awa/.qwen/skills/awa-usage/SKILL.md +3 -0
- package/templates/awa/.roo/rules/awa-agent.md +1 -1
- package/templates/awa/.roo/skills/awa-align/SKILL.md +3 -0
- package/templates/awa/.roo/skills/awa-check/SKILL.md +4 -0
- package/templates/awa/.roo/skills/awa-usage/SKILL.md +3 -0
- package/templates/awa/.windsurf/rules/awa-agent.md +1 -1
- package/templates/awa/.windsurf/skills/awa-align/SKILL.md +3 -0
- package/templates/awa/.windsurf/skills/awa-check/SKILL.md +4 -0
- package/templates/awa/.windsurf/skills/awa-usage/SKILL.md +3 -0
- package/templates/awa/AGENTS.md +1 -1
- package/templates/awa/CLAUDE.md +1 -1
- package/templates/awa/GEMINI.md +1 -1
- package/templates/awa/QWEN.md +1 -1
- package/templates/awa/_README.md +3 -2
- package/templates/awa/_delete.txt +49 -0
- package/templates/awa/_partials/{_cmd.awa-validate-alignment.md → _cmd.awa-align.md} +1 -1
- package/templates/awa/_partials/_cmd.awa-check.md +6 -0
- package/templates/awa/_partials/_skill.awa-align.md +6 -0
- package/templates/awa/_partials/_skill.awa-check.md +6 -0
- package/templates/awa/_partials/_skill.awa-usage.md +6 -0
- package/templates/awa/_partials/{awa.validate-alignment.md → awa.align.md} +2 -2
- package/templates/awa/_partials/awa.architecture.md +1 -1
- package/templates/awa/_partials/awa.check.md +73 -0
- package/templates/awa/_partials/awa.code.md +1 -0
- package/templates/awa/_partials/awa.core.md +24 -10
- package/templates/awa/_partials/awa.design.md +3 -2
- package/templates/awa/_partials/awa.documentation.md +1 -1
- package/templates/awa/_partials/awa.examples.md +1 -1
- package/templates/awa/_partials/awa.feature.md +1 -1
- package/templates/awa/_partials/awa.plan.md +1 -1
- package/templates/awa/_partials/awa.refactor.md +1 -0
- package/templates/awa/_partials/awa.requirements.md +2 -1
- package/templates/awa/_partials/awa.tasks.md +3 -3
- package/templates/awa/_partials/awa.upgrade.md +13 -12
- package/templates/awa/_partials/awa.usage.md +265 -0
- package/templates/awa/_tests/claude.toml +7 -0
- package/templates/awa/_tests/copilot.toml +6 -0
- package/templates/awa/.agent/skills/awa-validate-alignment/SKILL.md +0 -3
- package/templates/awa/.agent/workflows/awa-validate-alignment.md +0 -3
- package/templates/awa/.agents/skills/awa-validate-alignment/SKILL.md +0 -3
- package/templates/awa/.awa/.agent/schemas/ALIGN_REPORT.schema.md +0 -156
- package/templates/awa/.awa/.agent/schemas/API.schema.md +0 -4
- package/templates/awa/.awa/.agent/schemas/ARCHITECTURE.schema.md +0 -176
- package/templates/awa/.awa/.agent/schemas/DESIGN.schema.md +0 -253
- package/templates/awa/.awa/.agent/schemas/EXAMPLES.schema.md +0 -51
- package/templates/awa/.awa/.agent/schemas/FEAT.schema.md +0 -61
- package/templates/awa/.awa/.agent/schemas/PLAN.schema.md +0 -8
- package/templates/awa/.awa/.agent/schemas/README.schema.md +0 -133
- package/templates/awa/.awa/.agent/schemas/REQ.schema.md +0 -125
- package/templates/awa/.awa/.agent/schemas/TASK.schema.md +0 -137
- package/templates/awa/.claude/skills/awa-validate-alignment/SKILL.md +0 -3
- package/templates/awa/.codex/prompts/awa-validate-alignment.md +0 -3
- package/templates/awa/.cursor/rules/awa-validate-alignment.md +0 -8
- package/templates/awa/.gemini/commands/awa-validate-alignment.md +0 -3
- package/templates/awa/.gemini/skills/awa-validate-alignment/SKILL.md +0 -3
- package/templates/awa/.github/prompts/awa.validate-alignment.prompt.md +0 -8
- package/templates/awa/.github/skills/awa-validate-alignment/SKILL.md +0 -8
- package/templates/awa/.kilocode/skills/awa-validate-alignment/SKILL.md +0 -3
- package/templates/awa/.kilocode/workflows/awa-validate-alignment.md +0 -3
- package/templates/awa/.opencode/commands/awa-validate-alignment.md +0 -3
- package/templates/awa/.opencode/skills/awa-validate-alignment/SKILL.md +0 -3
- package/templates/awa/.qwen/commands/awa-validate-alignment.md +0 -3
- package/templates/awa/.qwen/skills/awa-validate-alignment/SKILL.md +0 -3
- package/templates/awa/.roo/skills/awa-validate-alignment/SKILL.md +0 -3
- package/templates/awa/.windsurf/skills/awa-validate-alignment/SKILL.md +0 -3
- 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
|