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.
Files changed (51) hide show
  1. package/README.md +1 -0
  2. package/dist/a11y-O35BAA25.js +14 -0
  3. package/dist/{auth-KUFS3PBS.js → auth-7AUNKGQW.js} +3 -3
  4. package/dist/bug-PH2E6GQT.js +13 -0
  5. package/dist/{chunk-HTJOCKVV.js → chunk-23IS6N63.js} +5 -5
  6. package/dist/{chunk-ER4ADSWH.js → chunk-2NSWZDP7.js} +1 -156
  7. package/dist/chunk-3ASILTFB.js +73 -0
  8. package/dist/{chunk-E7ZTIAQM.js → chunk-4KJJ6MSQ.js} +108 -258
  9. package/dist/{chunk-QGM4M3NI.js → chunk-4VNS5WPM.js} +5 -0
  10. package/dist/{chunk-DUJOT5B6.js → chunk-4VWKGOBQ.js} +7 -7
  11. package/dist/chunk-5CFGPXQ3.js +160 -0
  12. package/dist/chunk-67ZTMWP4.js +495 -0
  13. package/dist/{chunk-FGH2UX3E.js → chunk-BFPWDOMA.js} +1 -1
  14. package/dist/{chunk-LHCXE6UL.js → chunk-BKJISQXP.js} +5 -3
  15. package/dist/chunk-FWLLGLD5.js +353 -0
  16. package/dist/{chunk-BDPGWWQC.js → chunk-HGLPIM7J.js} +1 -1
  17. package/dist/{chunk-NIKN37AY.js → chunk-HJARQDQR.js} +1 -1
  18. package/dist/{chunk-WZIRUPMP.js → chunk-HKSVJWMI.js} +1 -1
  19. package/dist/{chunk-LPSS2U5V.js → chunk-JAWG5QX4.js} +65 -2
  20. package/dist/chunk-JF7JCK6H.js +485 -0
  21. package/dist/chunk-KY2HKRC2.js +175 -0
  22. package/dist/{chunk-2QIXLBAC.js → chunk-OQUWPU5F.js} +5 -3
  23. package/dist/{chunk-TRLP7RMZ.js → chunk-RPVPOUH3.js} +1 -1
  24. package/dist/{chunk-FA2GAZ7L.js → chunk-U2ZTHVDD.js} +1 -1
  25. package/dist/{chunk-LXXTCZ2Q.js → chunk-UFR2LX6G.js} +216 -14
  26. package/dist/{code-review-ORCNXANW.js → code-review-6MU4UE5M.js} +4 -4
  27. package/dist/{config-USLUSE4N.js → config-UARQV6FG.js} +1 -1
  28. package/dist/{constants-AHP5F7HW.js → constants-XDIWFFPN.js} +1 -1
  29. package/dist/execute-6SJL5POT.js +18 -0
  30. package/dist/geo-RP6HKLKZ.js +21 -0
  31. package/dist/index.js +917 -1823
  32. package/dist/{init-PSMJLDEZ.js → init-5RS332ZH.js} +1 -1
  33. package/dist/{interviewer-Q6PFSAGT.js → interviewer-Z7K4IZYG.js} +4 -4
  34. package/dist/{keys-SXJ6MKPY.js → keys-THCHXIFD.js} +1 -1
  35. package/dist/{keys-VLK3EWSN.js → keys-XE2D6I24.js} +2 -2
  36. package/dist/list-PCDSX4UI.js +17 -0
  37. package/dist/{manager-32P6ZZBP.js → manager-YSNTH2DG.js} +1 -1
  38. package/dist/models-UTFGCHAY.js +33 -0
  39. package/dist/{orchestration-X6LHSHBJ.js → orchestration-HIF3KP25.js} +1 -1
  40. package/dist/{parallel-WHFKRBPR.js → parallel-IRFNVIB6.js} +10 -6
  41. package/dist/{parser-4KJH2PT5.js → parser-BFHETZ5B.js} +1 -1
  42. package/dist/{plan-X77BUKNE.js → plan-RE5A3E2J.js} +6 -5
  43. package/dist/{preferences-TWEK2RWY.js → preferences-QAM5QKAQ.js} +5 -5
  44. package/dist/{review-T4ID2QUF.js → review-AUG6GIL6.js} +5 -5
  45. package/dist/seo-PMI42KRZ.js +10 -0
  46. package/dist/{tier-selection-Z2RFHZUX.js → tier-selection-2W6JWJUN.js} +2 -2
  47. package/dist/web-checks-4BSYXWDF.js +13 -0
  48. package/package.json +1 -1
  49. package/dist/bug-BJH4X5LI.js +0 -12
  50. package/dist/execute-73QW4ZEZ.js +0 -16
  51. package/dist/list-MMKB5TGX.js +0 -16
@@ -4,7 +4,7 @@ import {
4
4
  analyzeProject,
5
5
  featuresToTasks,
6
6
  readArchitectureContext
7
- } from "./chunk-BDPGWWQC.js";
7
+ } from "./chunk-HGLPIM7J.js";
8
8
 
9
9
  // src/cli/review.ts
10
10
  import chalk from "chalk";
@@ -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-ER4ADSWH.js";
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-NIKN37AY.js";
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,7 +1,7 @@
1
1
  import {
2
2
  AnthropicClient,
3
3
  getDefaultModel
4
- } from "./chunk-NIKN37AY.js";
4
+ } from "./chunk-HJARQDQR.js";
5
5
 
6
6
  // src/core/code-review/database.ts
7
7
  import Database from "better-sqlite3";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getModelCostWithFallback
3
- } from "./chunk-LXXTCZ2Q.js";
3
+ } from "./chunk-UFR2LX6G.js";
4
4
 
5
5
  // src/agents/clients/anthropic.ts
6
6
  import Anthropic from "@anthropic-ai/sdk";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  listLocalAtoms
3
- } from "./chunk-LHCXE6UL.js";
3
+ } from "./chunk-BKJISQXP.js";
4
4
 
5
5
  // src/cli/list.ts
6
6
  import chalk from "chalk";
@@ -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-LHCXE6UL.js";
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,