archondev 2.17.0 → 2.18.1
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 +1 -0
- package/dist/a11y-O35BAA25.js +14 -0
- package/dist/{auth-KUFS3PBS.js → auth-7AUNKGQW.js} +3 -3
- package/dist/bug-PH2E6GQT.js +13 -0
- package/dist/{chunk-HTJOCKVV.js → chunk-23IS6N63.js} +5 -5
- package/dist/{chunk-ER4ADSWH.js → chunk-2NSWZDP7.js} +1 -156
- package/dist/chunk-3ASILTFB.js +73 -0
- package/dist/{chunk-E7ZTIAQM.js → chunk-4KJJ6MSQ.js} +108 -258
- package/dist/{chunk-QGM4M3NI.js → chunk-4VNS5WPM.js} +5 -0
- package/dist/{chunk-DUJOT5B6.js → chunk-4VWKGOBQ.js} +7 -7
- package/dist/chunk-5CFGPXQ3.js +160 -0
- package/dist/chunk-67ZTMWP4.js +495 -0
- package/dist/{chunk-FGH2UX3E.js → chunk-BFPWDOMA.js} +1 -1
- package/dist/{chunk-LHCXE6UL.js → chunk-BKJISQXP.js} +5 -3
- package/dist/chunk-FWLLGLD5.js +353 -0
- package/dist/{chunk-BDPGWWQC.js → chunk-HGLPIM7J.js} +1 -1
- package/dist/{chunk-NIKN37AY.js → chunk-HJARQDQR.js} +1 -1
- package/dist/{chunk-WZIRUPMP.js → chunk-HKSVJWMI.js} +1 -1
- package/dist/{chunk-LPSS2U5V.js → chunk-JAWG5QX4.js} +65 -2
- package/dist/chunk-JF7JCK6H.js +485 -0
- package/dist/chunk-KY2HKRC2.js +175 -0
- package/dist/{chunk-2QIXLBAC.js → chunk-OQUWPU5F.js} +5 -3
- package/dist/{chunk-TRLP7RMZ.js → chunk-RPVPOUH3.js} +1 -1
- package/dist/{chunk-FA2GAZ7L.js → chunk-U2ZTHVDD.js} +1 -1
- package/dist/{chunk-LXXTCZ2Q.js → chunk-UFR2LX6G.js} +216 -14
- package/dist/{code-review-ORCNXANW.js → code-review-6MU4UE5M.js} +4 -4
- package/dist/{config-USLUSE4N.js → config-UARQV6FG.js} +1 -1
- package/dist/{constants-AHP5F7HW.js → constants-XDIWFFPN.js} +1 -1
- package/dist/execute-6SJL5POT.js +18 -0
- package/dist/geo-RP6HKLKZ.js +21 -0
- package/dist/index.js +917 -1823
- package/dist/{init-PSMJLDEZ.js → init-5RS332ZH.js} +1 -1
- package/dist/{interviewer-Q6PFSAGT.js → interviewer-Z7K4IZYG.js} +4 -4
- package/dist/{keys-SXJ6MKPY.js → keys-THCHXIFD.js} +1 -1
- package/dist/{keys-VLK3EWSN.js → keys-XE2D6I24.js} +2 -2
- package/dist/list-PCDSX4UI.js +17 -0
- package/dist/{manager-32P6ZZBP.js → manager-YSNTH2DG.js} +1 -1
- package/dist/models-UTFGCHAY.js +33 -0
- package/dist/{orchestration-X6LHSHBJ.js → orchestration-HIF3KP25.js} +1 -1
- package/dist/{parallel-WHFKRBPR.js → parallel-IRFNVIB6.js} +10 -6
- package/dist/{parser-4KJH2PT5.js → parser-BFHETZ5B.js} +1 -1
- package/dist/{plan-X77BUKNE.js → plan-RE5A3E2J.js} +6 -5
- package/dist/{preferences-TWEK2RWY.js → preferences-QAM5QKAQ.js} +5 -5
- package/dist/{review-T4ID2QUF.js → review-AUG6GIL6.js} +5 -5
- package/dist/seo-PMI42KRZ.js +10 -0
- package/dist/{tier-selection-Z2RFHZUX.js → tier-selection-2W6JWJUN.js} +2 -2
- package/dist/web-checks-4BSYXWDF.js +13 -0
- package/package.json +1 -1
- package/dist/bug-BJH4X5LI.js +0 -12
- package/dist/execute-73QW4ZEZ.js +0 -16
- package/dist/list-MMKB5TGX.js +0 -16
|
@@ -2,14 +2,16 @@ import {
|
|
|
2
2
|
ArchitectureParser
|
|
3
3
|
} from "./chunk-5EVHUDQX.js";
|
|
4
4
|
import {
|
|
5
|
-
ArchitectAgent,
|
|
6
5
|
createAtom,
|
|
7
6
|
validateAtom
|
|
8
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-5CFGPXQ3.js";
|
|
8
|
+
import {
|
|
9
|
+
ArchitectAgent
|
|
10
|
+
} from "./chunk-2NSWZDP7.js";
|
|
9
11
|
import {
|
|
10
12
|
AnthropicClient,
|
|
11
13
|
getDefaultModel
|
|
12
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-HJARQDQR.js";
|
|
13
15
|
import {
|
|
14
16
|
KeyManager
|
|
15
17
|
} from "./chunk-RDG5BUED.js";
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import {
|
|
2
|
+
recordWebCheckResult
|
|
3
|
+
} from "./chunk-3ASILTFB.js";
|
|
4
|
+
|
|
5
|
+
// src/cli/a11y.ts
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import { existsSync } from "fs";
|
|
8
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
9
|
+
import { join } from "path";
|
|
10
|
+
import { createInterface } from "readline";
|
|
11
|
+
import { glob } from "glob";
|
|
12
|
+
var ACCESSIBILITY_CHECKS = {
|
|
13
|
+
contrast: {
|
|
14
|
+
name: "Color Contrast",
|
|
15
|
+
wcag: "1.4.3, 1.4.11",
|
|
16
|
+
description: "Text and UI components have sufficient contrast ratios",
|
|
17
|
+
patterns: [
|
|
18
|
+
{ regex: /text-primary\/[0-9]+/g, issue: "Opacity-based text colors may have insufficient contrast" },
|
|
19
|
+
{ regex: /opacity-[0-9]+/g, issue: "Low opacity text may not meet contrast requirements" },
|
|
20
|
+
{ regex: /text-gray-[3-4]00/g, issue: "Light gray text often fails contrast requirements" }
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
images: {
|
|
24
|
+
name: "Image Alt Text",
|
|
25
|
+
wcag: "1.1.1",
|
|
26
|
+
description: "All meaningful images have alt text",
|
|
27
|
+
patterns: [
|
|
28
|
+
{ regex: /<img(?![^>]*alt=)[^>]*>/gi, issue: "Image missing alt attribute" },
|
|
29
|
+
{ regex: /<img[^>]*alt=["']\s*["'][^>]*>/gi, issue: "Image has empty alt text (verify if decorative)" }
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
forms: {
|
|
33
|
+
name: "Form Labels",
|
|
34
|
+
wcag: "1.3.1, 4.1.2",
|
|
35
|
+
description: "Form inputs have associated labels",
|
|
36
|
+
patterns: [
|
|
37
|
+
{ regex: /<input(?![^>]*aria-label)[^>]*(?<![^>]*id=)[^>]*>/gi, issue: "Input without label association" }
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
keyboard: {
|
|
41
|
+
name: "Keyboard Navigation",
|
|
42
|
+
wcag: "2.1.1, 2.4.7",
|
|
43
|
+
description: "All interactive elements are keyboard accessible with visible focus",
|
|
44
|
+
patterns: [
|
|
45
|
+
{ regex: /outline:\s*none|outline:\s*0/gi, issue: "Focus outline removed - may break keyboard navigation" },
|
|
46
|
+
{ regex: /tabindex=["']-1["']/gi, issue: "Negative tabindex removes element from tab order" }
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
structure: {
|
|
50
|
+
name: "Document Structure",
|
|
51
|
+
wcag: "1.3.1, 2.4.1",
|
|
52
|
+
description: "Proper heading hierarchy and landmarks",
|
|
53
|
+
patterns: [
|
|
54
|
+
{ regex: /<html(?![^>]*lang=)[^>]*>/gi, issue: "HTML element missing lang attribute" }
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
aria: {
|
|
58
|
+
name: "ARIA Usage",
|
|
59
|
+
wcag: "4.1.2",
|
|
60
|
+
description: "ARIA attributes are used correctly",
|
|
61
|
+
patterns: [
|
|
62
|
+
{ regex: /role=["']button["'](?![^>]*tabindex)/gi, issue: "Custom button missing tabindex" }
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
function createPrompt() {
|
|
67
|
+
const rl = createInterface({
|
|
68
|
+
input: process.stdin,
|
|
69
|
+
output: process.stdout
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
ask: (question) => new Promise((resolve) => {
|
|
73
|
+
rl.question(question, resolve);
|
|
74
|
+
}),
|
|
75
|
+
close: () => rl.close()
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
async function scanForIssues(files) {
|
|
79
|
+
const issues = [];
|
|
80
|
+
for (const file of files) {
|
|
81
|
+
try {
|
|
82
|
+
const content = await readFile(file, "utf-8");
|
|
83
|
+
const lines = content.split("\n");
|
|
84
|
+
for (const [checkId, check] of Object.entries(ACCESSIBILITY_CHECKS)) {
|
|
85
|
+
for (const pattern of check.patterns) {
|
|
86
|
+
for (let i = 0; i < lines.length; i++) {
|
|
87
|
+
const line = lines[i];
|
|
88
|
+
if (line && pattern.regex.test(line)) {
|
|
89
|
+
pattern.regex.lastIndex = 0;
|
|
90
|
+
issues.push({
|
|
91
|
+
file: file.replace(process.cwd() + "/", ""),
|
|
92
|
+
line: i + 1,
|
|
93
|
+
check: check.name,
|
|
94
|
+
wcag: check.wcag,
|
|
95
|
+
severity: checkId === "contrast" || checkId === "keyboard" ? "critical" : "major",
|
|
96
|
+
message: pattern.issue
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
pattern.regex.lastIndex = 0;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} catch {
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return issues;
|
|
107
|
+
}
|
|
108
|
+
async function a11yCheck(options) {
|
|
109
|
+
console.log(chalk.blue("\n\u267F Pre-Deploy Accessibility Check\n"));
|
|
110
|
+
console.log(chalk.dim("Scanning for WCAG 2.2 AA compliance issues...\n"));
|
|
111
|
+
const patterns = [
|
|
112
|
+
"**/*.html",
|
|
113
|
+
"**/*.htm",
|
|
114
|
+
"**/*.jsx",
|
|
115
|
+
"**/*.tsx",
|
|
116
|
+
"**/*.astro",
|
|
117
|
+
"**/*.svelte",
|
|
118
|
+
"**/*.vue"
|
|
119
|
+
];
|
|
120
|
+
const ignorePatterns = ["**/node_modules/**", "**/dist/**", "**/build/**", "**/.next/**"];
|
|
121
|
+
let allFiles = [];
|
|
122
|
+
for (const pattern of patterns) {
|
|
123
|
+
const files = await glob(pattern, { cwd: process.cwd(), ignore: ignorePatterns });
|
|
124
|
+
allFiles = allFiles.concat(files.map((f) => join(process.cwd(), f)));
|
|
125
|
+
}
|
|
126
|
+
if (allFiles.length === 0) {
|
|
127
|
+
console.log(chalk.yellow("No web files found to check."));
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
console.log(chalk.dim(`Scanning ${allFiles.length} files...
|
|
131
|
+
`));
|
|
132
|
+
const issues = await scanForIssues(allFiles);
|
|
133
|
+
const report = {
|
|
134
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
135
|
+
totalFiles: allFiles.length,
|
|
136
|
+
issuesFound: issues.length,
|
|
137
|
+
issues,
|
|
138
|
+
passed: issues.length === 0
|
|
139
|
+
};
|
|
140
|
+
const archonDir = join(process.cwd(), ".archon");
|
|
141
|
+
if (!existsSync(archonDir)) {
|
|
142
|
+
await mkdir(archonDir, { recursive: true });
|
|
143
|
+
}
|
|
144
|
+
await writeFile(join(archonDir, "a11y-report.json"), JSON.stringify(report, null, 2));
|
|
145
|
+
await recordWebCheckResult(process.cwd(), "a11y", report.passed);
|
|
146
|
+
if (issues.length === 0) {
|
|
147
|
+
console.log(chalk.green("\u2705 Accessibility Audit Passed\n"));
|
|
148
|
+
console.log(chalk.dim("Your site meets WCAG 2.2 AA requirements based on static analysis."));
|
|
149
|
+
console.log(chalk.dim("Note: Run manual testing with screen readers for full compliance.\n"));
|
|
150
|
+
return report;
|
|
151
|
+
}
|
|
152
|
+
console.log(chalk.red(`[!] ${issues.length} Accessibility Issues Found
|
|
153
|
+
`));
|
|
154
|
+
const criticalCount = issues.filter((i) => i.severity === "critical").length;
|
|
155
|
+
const majorCount = issues.filter((i) => i.severity === "major").length;
|
|
156
|
+
const minorCount = issues.filter((i) => i.severity === "minor").length;
|
|
157
|
+
console.log(chalk.dim("Summary:"));
|
|
158
|
+
if (criticalCount > 0) console.log(chalk.red(` \u2022 ${criticalCount} critical`));
|
|
159
|
+
if (majorCount > 0) console.log(chalk.yellow(` \u2022 ${majorCount} major`));
|
|
160
|
+
if (minorCount > 0) console.log(chalk.dim(` \u2022 ${minorCount} minor`));
|
|
161
|
+
console.log();
|
|
162
|
+
console.log(chalk.bold("Issues:\n"));
|
|
163
|
+
const issuesByFile = /* @__PURE__ */ new Map();
|
|
164
|
+
for (const issue of issues) {
|
|
165
|
+
const existing = issuesByFile.get(issue.file) || [];
|
|
166
|
+
existing.push(issue);
|
|
167
|
+
issuesByFile.set(issue.file, existing);
|
|
168
|
+
}
|
|
169
|
+
for (const [file, fileIssues] of issuesByFile) {
|
|
170
|
+
console.log(chalk.cyan(` ${file}`));
|
|
171
|
+
for (const issue of fileIssues.slice(0, 5)) {
|
|
172
|
+
const color = issue.severity === "critical" ? chalk.red : issue.severity === "major" ? chalk.yellow : chalk.dim;
|
|
173
|
+
console.log(color(` Line ${issue.line}: ${issue.message} (WCAG ${issue.wcag})`));
|
|
174
|
+
}
|
|
175
|
+
if (fileIssues.length > 5) {
|
|
176
|
+
console.log(chalk.dim(` ... and ${fileIssues.length - 5} more issues`));
|
|
177
|
+
}
|
|
178
|
+
console.log();
|
|
179
|
+
}
|
|
180
|
+
console.log(chalk.bold.yellow("\n[LEGAL] Notice\n"));
|
|
181
|
+
console.log(chalk.dim("Websites that don't meet accessibility standards may violate:"));
|
|
182
|
+
console.log(chalk.dim(" \u2022 ADA (Americans with Disabilities Act) \u2014 US"));
|
|
183
|
+
console.log(chalk.dim(" \u2022 EAA (European Accessibility Act) \u2014 EU, effective June 2025"));
|
|
184
|
+
console.log(chalk.dim(" \u2022 Section 508 \u2014 US federal agencies and contractors"));
|
|
185
|
+
console.log(chalk.dim(" \u2022 AODA (Accessibility for Ontarians) \u2014 Ontario, Canada"));
|
|
186
|
+
console.log();
|
|
187
|
+
console.log(chalk.dim("Non-compliance can result in lawsuits, fines, and reputational damage."));
|
|
188
|
+
console.log(chalk.dim("In 2023, over 4,600 ADA web accessibility lawsuits were filed in the US.\n"));
|
|
189
|
+
console.log(chalk.dim(`Full report saved to: .archon/a11y-report.json`));
|
|
190
|
+
return report;
|
|
191
|
+
}
|
|
192
|
+
async function a11yFix(options) {
|
|
193
|
+
const prompt = createPrompt();
|
|
194
|
+
try {
|
|
195
|
+
console.log(chalk.blue("\n\u267F Accessibility Auto-Fix\n"));
|
|
196
|
+
const reportPath = join(process.cwd(), ".archon/a11y-report.json");
|
|
197
|
+
if (!existsSync(reportPath)) {
|
|
198
|
+
console.log(chalk.yellow("No accessibility report found. Running check first...\n"));
|
|
199
|
+
await a11yCheck({});
|
|
200
|
+
}
|
|
201
|
+
const reportContent = await readFile(reportPath, "utf-8");
|
|
202
|
+
const report = JSON.parse(reportContent);
|
|
203
|
+
if (report.passed || report.issues.length === 0) {
|
|
204
|
+
console.log(chalk.green("No issues to fix!"));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
console.log(chalk.dim(`Found ${report.issues.length} issues from last check.
|
|
208
|
+
`));
|
|
209
|
+
const fixablePatterns = [
|
|
210
|
+
{
|
|
211
|
+
pattern: /text-primary\/60/g,
|
|
212
|
+
replacement: "text-text-muted",
|
|
213
|
+
description: "Replace low-opacity text with accessible color"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
pattern: /text-primary\/70/g,
|
|
217
|
+
replacement: "text-text-muted",
|
|
218
|
+
description: "Replace low-opacity text with accessible color"
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
pattern: /outline:\s*none/gi,
|
|
222
|
+
replacement: "outline: 2px solid transparent",
|
|
223
|
+
description: "Replace outline:none with accessible alternative"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
pattern: /<html>/gi,
|
|
227
|
+
replacement: '<html lang="en">',
|
|
228
|
+
description: "Add lang attribute to html element"
|
|
229
|
+
}
|
|
230
|
+
];
|
|
231
|
+
let totalFixes = 0;
|
|
232
|
+
for (const fix of fixablePatterns) {
|
|
233
|
+
const patterns = ["**/*.html", "**/*.jsx", "**/*.tsx", "**/*.astro", "**/*.svelte", "**/*.vue", "**/*.css"];
|
|
234
|
+
const ignorePatterns = ["**/node_modules/**", "**/dist/**", "**/build/**"];
|
|
235
|
+
for (const pattern of patterns) {
|
|
236
|
+
const files = await glob(pattern, { cwd: process.cwd(), ignore: ignorePatterns });
|
|
237
|
+
for (const file of files) {
|
|
238
|
+
const filePath = join(process.cwd(), file);
|
|
239
|
+
try {
|
|
240
|
+
const content = await readFile(filePath, "utf-8");
|
|
241
|
+
if (fix.pattern.test(content)) {
|
|
242
|
+
fix.pattern.lastIndex = 0;
|
|
243
|
+
const matches = content.match(fix.pattern);
|
|
244
|
+
const count = matches?.length || 0;
|
|
245
|
+
if (count > 0) {
|
|
246
|
+
console.log(chalk.cyan(` ${file}: ${count} fixes (${fix.description})`));
|
|
247
|
+
totalFixes += count;
|
|
248
|
+
if (!options.dryRun) {
|
|
249
|
+
const newContent = content.replace(fix.pattern, fix.replacement);
|
|
250
|
+
await writeFile(filePath, newContent);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
} catch {
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (totalFixes === 0) {
|
|
260
|
+
console.log(chalk.dim("No auto-fixable issues found. Some issues require manual fixes."));
|
|
261
|
+
} else if (options.dryRun) {
|
|
262
|
+
console.log(chalk.yellow(`
|
|
263
|
+
${totalFixes} fixes would be applied. Run without --dry-run to apply.`));
|
|
264
|
+
} else {
|
|
265
|
+
console.log(chalk.green(`
|
|
266
|
+
\u2705 Applied ${totalFixes} fixes.`));
|
|
267
|
+
console.log(chalk.dim('Run "archon a11y check" to verify fixes.'));
|
|
268
|
+
}
|
|
269
|
+
} finally {
|
|
270
|
+
prompt.close();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
async function a11yBadge(options) {
|
|
274
|
+
console.log(chalk.blue("\n\u267F Accessibility Badge\n"));
|
|
275
|
+
const badgeHtml = `<!-- WCAG 2.2 AA Compliance Badge -->
|
|
276
|
+
<div class="flex items-center gap-2 text-xs text-text-muted dark:text-cream-300">
|
|
277
|
+
<svg class="h-4 w-4" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
|
|
278
|
+
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
|
279
|
+
</svg>
|
|
280
|
+
<span>WCAG 2.2 AA Accessible</span>
|
|
281
|
+
</div>`;
|
|
282
|
+
const footerPatterns = ["**/Footer.{jsx,tsx,astro,svelte,vue}", "**/footer.{jsx,tsx,astro,svelte,vue,html}"];
|
|
283
|
+
let footerFiles = [];
|
|
284
|
+
for (const pattern of footerPatterns) {
|
|
285
|
+
const files = await glob(pattern, { cwd: process.cwd(), ignore: ["**/node_modules/**"] });
|
|
286
|
+
footerFiles = footerFiles.concat(files);
|
|
287
|
+
}
|
|
288
|
+
if (footerFiles.length === 0) {
|
|
289
|
+
console.log(chalk.yellow("No footer files found."));
|
|
290
|
+
console.log(chalk.dim("\nManually add this badge to your footer:\n"));
|
|
291
|
+
console.log(badgeHtml);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
console.log(chalk.dim(`Found ${footerFiles.length} footer file(s):
|
|
295
|
+
`));
|
|
296
|
+
for (const file of footerFiles) {
|
|
297
|
+
console.log(chalk.cyan(` ${file}`));
|
|
298
|
+
}
|
|
299
|
+
if (options.remove) {
|
|
300
|
+
console.log(chalk.yellow("\nRemoving accessibility badge..."));
|
|
301
|
+
console.log(chalk.dim("Badge removal not yet implemented. Manually remove the WCAG badge comment block."));
|
|
302
|
+
} else {
|
|
303
|
+
console.log(chalk.dim("\nTo add the badge, insert this code before the closing </footer> tag:\n"));
|
|
304
|
+
console.log(chalk.green(badgeHtml));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
async function a11yPreDeploy() {
|
|
308
|
+
const prompt = createPrompt();
|
|
309
|
+
try {
|
|
310
|
+
console.log(chalk.blue("\n[CHECK] Pre-Deploy Accessibility\n"));
|
|
311
|
+
console.log(chalk.dim("Before deploying a live website, accessibility compliance is required.\n"));
|
|
312
|
+
await a11yCheck({});
|
|
313
|
+
const reportPath = join(process.cwd(), ".archon/a11y-report.json");
|
|
314
|
+
if (!existsSync(reportPath)) {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
const reportContent = await readFile(reportPath, "utf-8");
|
|
318
|
+
const report = JSON.parse(reportContent);
|
|
319
|
+
if (report.passed) {
|
|
320
|
+
const addBadge = await prompt.ask("\nWould you like to add a WCAG 2.2 AA badge to your footer? (y/N): ");
|
|
321
|
+
if (addBadge.toLowerCase() === "y") {
|
|
322
|
+
await a11yBadge({});
|
|
323
|
+
}
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
console.log(chalk.bold("\nOptions:\n"));
|
|
327
|
+
console.log(" 1) Fix issues now (recommended)");
|
|
328
|
+
console.log(" 2) Deploy anyway (not recommended)");
|
|
329
|
+
console.log(" 3) Cancel deployment\n");
|
|
330
|
+
const choice = await prompt.ask("Which would you like to do? (1/2/3): ");
|
|
331
|
+
if (choice === "1") {
|
|
332
|
+
await a11yFix({});
|
|
333
|
+
await a11yCheck({});
|
|
334
|
+
return true;
|
|
335
|
+
} else if (choice === "2") {
|
|
336
|
+
console.log(chalk.yellow("\n[!] Acknowledged. Proceeding without full accessibility compliance."));
|
|
337
|
+
console.log(chalk.dim("Consider addressing these issues in a future session.\n"));
|
|
338
|
+
return true;
|
|
339
|
+
} else {
|
|
340
|
+
console.log(chalk.dim("\nDeployment cancelled."));
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
} finally {
|
|
344
|
+
prompt.close();
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export {
|
|
349
|
+
a11yCheck,
|
|
350
|
+
a11yFix,
|
|
351
|
+
a11yBadge,
|
|
352
|
+
a11yPreDeploy
|
|
353
|
+
};
|
|
@@ -1,14 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getGitBranch,
|
|
3
|
+
getGitRemoteUrl,
|
|
4
|
+
queueCloudExecution
|
|
5
|
+
} from "./chunk-KY2HKRC2.js";
|
|
1
6
|
import {
|
|
2
7
|
listLocalAtoms,
|
|
3
8
|
loadAtom
|
|
4
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-BKJISQXP.js";
|
|
10
|
+
import {
|
|
11
|
+
loadConfig
|
|
12
|
+
} from "./chunk-SUGIWSCB.js";
|
|
5
13
|
|
|
6
14
|
// src/cli/parallel.ts
|
|
7
15
|
import chalk from "chalk";
|
|
8
16
|
import { spawn } from "child_process";
|
|
9
17
|
import { existsSync as existsSync2 } from "fs";
|
|
10
18
|
import { readFile, writeFile } from "fs/promises";
|
|
11
|
-
import { join as join2 } from "path";
|
|
19
|
+
import { join as join2, basename } from "path";
|
|
12
20
|
|
|
13
21
|
// src/core/parallel/worktree.ts
|
|
14
22
|
import { execSync } from "child_process";
|
|
@@ -440,6 +448,60 @@ Parallel execution complete:`));
|
|
|
440
448
|
Run "archon parallel status" to see details.`));
|
|
441
449
|
console.log(chalk.dim(`Run "archon parallel merge" to merge completed worktrees.`));
|
|
442
450
|
}
|
|
451
|
+
async function parallelExecuteCloud(atomIds) {
|
|
452
|
+
const cwd = process.cwd();
|
|
453
|
+
const config = await loadConfig();
|
|
454
|
+
const tier = config.tier ?? "FREE";
|
|
455
|
+
if (tier !== "CREDITS") {
|
|
456
|
+
console.log(chalk.red("\n\u274C Cloud execution requires Credits tier"));
|
|
457
|
+
console.log(chalk.dim("BYOK and Free tiers run locally only."));
|
|
458
|
+
console.log(chalk.dim("Upgrade with: archon upgrade"));
|
|
459
|
+
process.exit(1);
|
|
460
|
+
}
|
|
461
|
+
const projectName = basename(cwd);
|
|
462
|
+
const repoUrl = await getGitRemoteUrl(cwd);
|
|
463
|
+
const repoBranch = await getGitBranch(cwd);
|
|
464
|
+
if (!repoUrl) {
|
|
465
|
+
console.error(chalk.red("No git remote found. Cloud execution requires a GitHub repository."));
|
|
466
|
+
console.log(chalk.dim("Add a remote with: git remote add origin <url>"));
|
|
467
|
+
process.exit(1);
|
|
468
|
+
}
|
|
469
|
+
console.log(chalk.blue(`
|
|
470
|
+
\u2601\uFE0F Queueing ${atomIds.length} cloud execution(s)...
|
|
471
|
+
`));
|
|
472
|
+
const queued = [];
|
|
473
|
+
for (const atomId of atomIds) {
|
|
474
|
+
const atom = await loadAtom(atomId);
|
|
475
|
+
if (!atom) {
|
|
476
|
+
console.error(chalk.red(`Atom ${atomId} not found. Skipping.`));
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
if (atom.status !== "READY") {
|
|
480
|
+
console.log(chalk.yellow(`Atom ${atomId} is not READY (status: ${atom.status}). Skipping.`));
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
try {
|
|
484
|
+
const executionId = await queueCloudExecution(atomId, projectName, {
|
|
485
|
+
repoUrl,
|
|
486
|
+
repoBranch,
|
|
487
|
+
atomData: atom
|
|
488
|
+
});
|
|
489
|
+
queued.push({ atomId, executionId });
|
|
490
|
+
console.log(chalk.green(`\u2713 ${atomId} queued (${executionId.slice(0, 8)})`));
|
|
491
|
+
} catch (error) {
|
|
492
|
+
console.error(chalk.red(`Failed to queue ${atomId}:`));
|
|
493
|
+
console.error(chalk.dim(error instanceof Error ? error.message : "Unknown error"));
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
if (queued.length === 0) {
|
|
497
|
+
console.log(chalk.dim("\nNo executions were queued."));
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
console.log(chalk.dim("\nCheck progress with:"));
|
|
501
|
+
console.log(chalk.bold(" archon cloud status"));
|
|
502
|
+
console.log(chalk.dim("View logs with:"));
|
|
503
|
+
console.log(chalk.bold(" archon cloud logs <id>"));
|
|
504
|
+
}
|
|
443
505
|
async function parallelStatus() {
|
|
444
506
|
const cwd = process.cwd();
|
|
445
507
|
const state = await loadParallelState(cwd);
|
|
@@ -670,6 +732,7 @@ async function executeAtomInWorktree(atomId, worktreePath) {
|
|
|
670
732
|
|
|
671
733
|
export {
|
|
672
734
|
parallelExecute,
|
|
735
|
+
parallelExecuteCloud,
|
|
673
736
|
parallelStatus,
|
|
674
737
|
parallelMerge,
|
|
675
738
|
parallelClean,
|