archondev 1.5.0 → 1.6.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/dist/{chunk-PK3OQVBG.js → chunk-NCJN4X5A.js} +1 -1
- package/dist/{chunk-74EEFKVP.js → chunk-S7UXMYWS.js} +1 -1
- package/dist/chunk-TJXGZB6T.js +342 -0
- package/dist/{execute-N6CCEJ5I.js → execute-6ZGARWT2.js} +3 -3
- package/dist/index.js +574 -559
- package/dist/init-YLAHY4CV.js +9 -0
- package/dist/{list-VXMVEIL5.js → list-UB4MOGRH.js} +3 -3
- package/dist/{plan-7VSFESVD.js → plan-WQUFH2WB.js} +2 -2
- package/package.json +1 -1
- package/dist/{chunk-EDP55FCI.js → chunk-3AAQEUY6.js} +3 -3
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from "./chunk-
|
|
3
|
+
addKey,
|
|
4
|
+
listKeys,
|
|
5
|
+
removeKey,
|
|
6
|
+
setPrimaryKey
|
|
7
|
+
} from "./chunk-IMZN36GC.js";
|
|
8
8
|
import {
|
|
9
9
|
reviewAnalyze,
|
|
10
10
|
reviewExport,
|
|
@@ -18,6 +18,12 @@ import {
|
|
|
18
18
|
reviewUpdate
|
|
19
19
|
} from "./chunk-UDBFDXJI.js";
|
|
20
20
|
import "./chunk-VKM3HAHW.js";
|
|
21
|
+
import {
|
|
22
|
+
listModels,
|
|
23
|
+
resetPreferences,
|
|
24
|
+
setPreference,
|
|
25
|
+
showPreferences
|
|
26
|
+
} from "./chunk-K2VBICW3.js";
|
|
21
27
|
import {
|
|
22
28
|
API_URL,
|
|
23
29
|
SUPABASE_ANON_KEY,
|
|
@@ -26,33 +32,31 @@ import {
|
|
|
26
32
|
logout,
|
|
27
33
|
status
|
|
28
34
|
} from "./chunk-CAYCSBNX.js";
|
|
35
|
+
import {
|
|
36
|
+
init,
|
|
37
|
+
isInitialized
|
|
38
|
+
} from "./chunk-TJXGZB6T.js";
|
|
29
39
|
import {
|
|
30
40
|
DependencyParser,
|
|
31
41
|
EnvironmentConfigLoader,
|
|
32
42
|
EnvironmentValidator,
|
|
33
43
|
execute
|
|
34
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-S7UXMYWS.js";
|
|
35
45
|
import {
|
|
36
46
|
list
|
|
37
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-NCJN4X5A.js";
|
|
38
48
|
import {
|
|
39
49
|
listLocalAtoms,
|
|
40
50
|
loadAtom,
|
|
41
51
|
plan
|
|
42
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-3AAQEUY6.js";
|
|
53
|
+
import "./chunk-SMR7JQK6.js";
|
|
43
54
|
import "./chunk-2CFO5GVH.js";
|
|
44
55
|
import {
|
|
45
56
|
bugReport
|
|
46
57
|
} from "./chunk-JBKFAD4M.js";
|
|
47
58
|
import "./chunk-MOZHC2GX.js";
|
|
48
59
|
import "./chunk-A7QU6JC6.js";
|
|
49
|
-
import {
|
|
50
|
-
addKey,
|
|
51
|
-
listKeys,
|
|
52
|
-
removeKey,
|
|
53
|
-
setPrimaryKey
|
|
54
|
-
} from "./chunk-IMZN36GC.js";
|
|
55
|
-
import "./chunk-SMR7JQK6.js";
|
|
56
60
|
import {
|
|
57
61
|
loadConfig
|
|
58
62
|
} from "./chunk-WCCBJSNI.js";
|
|
@@ -60,365 +64,27 @@ import "./chunk-QGM4M3NI.js";
|
|
|
60
64
|
|
|
61
65
|
// src/cli/index.ts
|
|
62
66
|
import { Command as Command2 } from "commander";
|
|
63
|
-
import
|
|
67
|
+
import chalk6 from "chalk";
|
|
64
68
|
import "dotenv/config";
|
|
65
69
|
|
|
66
|
-
// src/cli/init.ts
|
|
67
|
-
import { readdir, readFile, writeFile, mkdir } from "fs/promises";
|
|
68
|
-
import { existsSync } from "fs";
|
|
69
|
-
import { join, extname } from "path";
|
|
70
|
-
import { execSync } from "child_process";
|
|
71
|
-
import chalk from "chalk";
|
|
72
|
-
import ora from "ora";
|
|
73
|
-
import readline from "readline";
|
|
74
|
-
function isInitialized(cwd) {
|
|
75
|
-
const archMdPath = join(cwd, "ARCHITECTURE.md");
|
|
76
|
-
const archonDir = join(cwd, ".archon");
|
|
77
|
-
return existsSync(archMdPath) || existsSync(archonDir);
|
|
78
|
-
}
|
|
79
|
-
var LANGUAGE_EXTENSIONS = {
|
|
80
|
-
".ts": "TypeScript",
|
|
81
|
-
".tsx": "TypeScript",
|
|
82
|
-
".js": "JavaScript",
|
|
83
|
-
".jsx": "JavaScript",
|
|
84
|
-
".py": "Python",
|
|
85
|
-
".go": "Go",
|
|
86
|
-
".rs": "Rust",
|
|
87
|
-
".java": "Java",
|
|
88
|
-
".rb": "Ruby",
|
|
89
|
-
".php": "PHP",
|
|
90
|
-
".cs": "C#",
|
|
91
|
-
".cpp": "C++",
|
|
92
|
-
".c": "C",
|
|
93
|
-
".swift": "Swift",
|
|
94
|
-
".kt": "Kotlin",
|
|
95
|
-
".vue": "Vue",
|
|
96
|
-
".svelte": "Svelte"
|
|
97
|
-
};
|
|
98
|
-
var IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
99
|
-
"node_modules",
|
|
100
|
-
".git",
|
|
101
|
-
"dist",
|
|
102
|
-
"build",
|
|
103
|
-
".next",
|
|
104
|
-
"coverage",
|
|
105
|
-
"__pycache__",
|
|
106
|
-
".venv",
|
|
107
|
-
"venv",
|
|
108
|
-
"target",
|
|
109
|
-
"vendor",
|
|
110
|
-
".archon"
|
|
111
|
-
]);
|
|
112
|
-
async function init(options = {}) {
|
|
113
|
-
const cwd = process.cwd();
|
|
114
|
-
const archMdPath = join(cwd, "ARCHITECTURE.md");
|
|
115
|
-
const archonDir = join(cwd, ".archon");
|
|
116
|
-
console.log(chalk.blue("\n\u{1F3DB}\uFE0F ArchonDev Initialization\n"));
|
|
117
|
-
if (existsSync(archMdPath)) {
|
|
118
|
-
const overwrite = await promptYesNo("ARCHITECTURE.md already exists. Overwrite?", false);
|
|
119
|
-
if (!overwrite) {
|
|
120
|
-
console.log(chalk.yellow("Initialization cancelled."));
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
const spinner = ora("Detecting project capabilities...").start();
|
|
125
|
-
const capabilities = await detectCapabilities(cwd);
|
|
126
|
-
spinner.succeed("Project capabilities detected");
|
|
127
|
-
spinner.start("Scanning codebase...");
|
|
128
|
-
const stats = await scanRepository(cwd);
|
|
129
|
-
spinner.succeed(`Scanned ${stats.totalFiles} files (${formatLines(stats.totalLines)} lines)`);
|
|
130
|
-
if (options.git !== false && !capabilities.hasGit) {
|
|
131
|
-
spinner.start("Initializing git repository...");
|
|
132
|
-
try {
|
|
133
|
-
execSync("git init", { cwd, stdio: "pipe" });
|
|
134
|
-
spinner.succeed("Git repository initialized");
|
|
135
|
-
} catch {
|
|
136
|
-
spinner.warn("Could not initialize git");
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
if (!existsSync(archonDir)) {
|
|
140
|
-
await mkdir(archonDir, { recursive: true });
|
|
141
|
-
}
|
|
142
|
-
spinner.start("Generating ARCHITECTURE.md...");
|
|
143
|
-
const archContent = generateArchitectureMd(capabilities, stats, options.analyze);
|
|
144
|
-
await writeFile(archMdPath, archContent);
|
|
145
|
-
spinner.succeed("ARCHITECTURE.md created");
|
|
146
|
-
printSummary(capabilities, stats, options.analyze);
|
|
147
|
-
}
|
|
148
|
-
function promptYesNo(question, defaultValue) {
|
|
149
|
-
return new Promise((resolve) => {
|
|
150
|
-
const rl = readline.createInterface({
|
|
151
|
-
input: process.stdin,
|
|
152
|
-
output: process.stdout
|
|
153
|
-
});
|
|
154
|
-
const hint = defaultValue ? "(Y/n)" : "(y/N)";
|
|
155
|
-
rl.question(`${question} ${hint} `, (answer) => {
|
|
156
|
-
rl.close();
|
|
157
|
-
if (answer.trim() === "") {
|
|
158
|
-
resolve(defaultValue);
|
|
159
|
-
} else {
|
|
160
|
-
resolve(answer.toLowerCase().startsWith("y"));
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
async function detectCapabilities(cwd) {
|
|
166
|
-
const hasFile = (name) => existsSync(join(cwd, name));
|
|
167
|
-
const hasJsonDep = async (name) => {
|
|
168
|
-
try {
|
|
169
|
-
const pkg = JSON.parse(await readFile(join(cwd, "package.json"), "utf-8"));
|
|
170
|
-
return !!(pkg.dependencies?.[name] || pkg.devDependencies?.[name]);
|
|
171
|
-
} catch {
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
};
|
|
175
|
-
let packageManager = null;
|
|
176
|
-
if (hasFile("pnpm-lock.yaml")) packageManager = "pnpm";
|
|
177
|
-
else if (hasFile("yarn.lock")) packageManager = "yarn";
|
|
178
|
-
else if (hasFile("bun.lockb")) packageManager = "bun";
|
|
179
|
-
else if (hasFile("package-lock.json")) packageManager = "npm";
|
|
180
|
-
const hasTypeScript = hasFile("tsconfig.json") || await hasJsonDep("typescript");
|
|
181
|
-
const hasESLint = hasFile(".eslintrc") || hasFile(".eslintrc.js") || hasFile("eslint.config.js") || await hasJsonDep("eslint");
|
|
182
|
-
const hasJest = hasFile("jest.config.js") || hasFile("jest.config.ts") || await hasJsonDep("jest") || await hasJsonDep("vitest");
|
|
183
|
-
const hasPrettier = hasFile(".prettierrc") || hasFile(".prettierrc.js") || await hasJsonDep("prettier");
|
|
184
|
-
const hasGit = hasFile(".git");
|
|
185
|
-
return {
|
|
186
|
-
hasTypeScript,
|
|
187
|
-
hasESLint,
|
|
188
|
-
hasJest,
|
|
189
|
-
hasPrettier,
|
|
190
|
-
hasGit,
|
|
191
|
-
packageManager,
|
|
192
|
-
primaryLanguage: hasTypeScript ? "TypeScript" : "JavaScript"
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
async function scanRepository(cwd) {
|
|
196
|
-
const stats = {
|
|
197
|
-
totalFiles: 0,
|
|
198
|
-
totalLines: 0,
|
|
199
|
-
languageBreakdown: {},
|
|
200
|
-
directories: []
|
|
201
|
-
};
|
|
202
|
-
async function scanDir(dir, depth = 0) {
|
|
203
|
-
if (depth > 10) return;
|
|
204
|
-
try {
|
|
205
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
206
|
-
for (const entry of entries) {
|
|
207
|
-
if (IGNORE_DIRS.has(entry.name)) continue;
|
|
208
|
-
if (entry.name.startsWith(".") && entry.name !== ".github") continue;
|
|
209
|
-
const fullPath = join(dir, entry.name);
|
|
210
|
-
if (entry.isDirectory()) {
|
|
211
|
-
if (depth < 2) {
|
|
212
|
-
const relativePath = fullPath.replace(cwd, "").replace(/^\//, "");
|
|
213
|
-
if (relativePath) {
|
|
214
|
-
stats.directories.push(relativePath);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
await scanDir(fullPath, depth + 1);
|
|
218
|
-
} else if (entry.isFile()) {
|
|
219
|
-
const ext = extname(entry.name).toLowerCase();
|
|
220
|
-
const language = LANGUAGE_EXTENSIONS[ext];
|
|
221
|
-
if (language) {
|
|
222
|
-
stats.totalFiles++;
|
|
223
|
-
try {
|
|
224
|
-
const content = await readFile(fullPath, "utf-8");
|
|
225
|
-
const lines = content.split("\n").length;
|
|
226
|
-
stats.totalLines += lines;
|
|
227
|
-
if (!stats.languageBreakdown[language]) {
|
|
228
|
-
stats.languageBreakdown[language] = { files: 0, lines: 0 };
|
|
229
|
-
}
|
|
230
|
-
stats.languageBreakdown[language].files++;
|
|
231
|
-
stats.languageBreakdown[language].lines += lines;
|
|
232
|
-
} catch {
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
} catch {
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
await scanDir(cwd);
|
|
241
|
-
return stats;
|
|
242
|
-
}
|
|
243
|
-
function generateArchitectureMd(capabilities, stats, analyze) {
|
|
244
|
-
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
245
|
-
const suggestedComponents = stats.directories.filter((d) => !d.includes("/")).slice(0, 10).map((dir) => ({
|
|
246
|
-
id: dir.replace(/[^a-zA-Z0-9]/g, "-"),
|
|
247
|
-
name: dir.charAt(0).toUpperCase() + dir.slice(1),
|
|
248
|
-
path: `${dir}/**`
|
|
249
|
-
}));
|
|
250
|
-
const qualityGates = [];
|
|
251
|
-
if (capabilities.hasTypeScript) qualityGates.push("SYNTAX");
|
|
252
|
-
if (capabilities.hasESLint) qualityGates.push("LINT");
|
|
253
|
-
if (capabilities.hasJest) qualityGates.push("UNIT");
|
|
254
|
-
return `---
|
|
255
|
-
version: "1.0"
|
|
256
|
-
updatedAt: "${now}"
|
|
257
|
-
profile: "balanced"
|
|
258
|
-
strictMode: true
|
|
259
|
-
|
|
260
|
-
# System Goals
|
|
261
|
-
systemGoals:
|
|
262
|
-
- id: "GOAL-001"
|
|
263
|
-
title: "Maintain code quality"
|
|
264
|
-
description: "All changes must pass quality gates before merging"
|
|
265
|
-
priority: "HIGH"
|
|
266
|
-
|
|
267
|
-
- id: "GOAL-002"
|
|
268
|
-
title: "Preserve architectural boundaries"
|
|
269
|
-
description: "Components should not violate defined boundaries"
|
|
270
|
-
priority: "HIGH"
|
|
271
|
-
|
|
272
|
-
# Components & Boundaries
|
|
273
|
-
# Detected ${suggestedComponents.length} top-level directories
|
|
274
|
-
components:
|
|
275
|
-
${suggestedComponents.map((c) => ` - id: "${c.id}"
|
|
276
|
-
name: "${c.name}"
|
|
277
|
-
paths:
|
|
278
|
-
- "${c.path}"
|
|
279
|
-
boundary: "INTERNAL"
|
|
280
|
-
stability: "EVOLVING"`).join("\n\n")}
|
|
281
|
-
|
|
282
|
-
# Invariants (Rules to enforce)
|
|
283
|
-
invariants:
|
|
284
|
-
- id: "INV-001"
|
|
285
|
-
severity: "WARN"
|
|
286
|
-
rule: "Avoid console.log in production code"
|
|
287
|
-
match: "console\\\\.log"
|
|
288
|
-
scope: "src"
|
|
289
|
-
reason: "Use proper logging library instead"
|
|
290
|
-
|
|
291
|
-
# Protected Paths
|
|
292
|
-
protectedPaths:
|
|
293
|
-
- pattern: "package.json"
|
|
294
|
-
level: "SOFT"
|
|
295
|
-
reason: "Dependency changes should be reviewed"
|
|
296
|
-
|
|
297
|
-
${capabilities.hasTypeScript ? ` - pattern: "tsconfig.json"
|
|
298
|
-
level: "SOFT"
|
|
299
|
-
reason: "TypeScript config affects entire project"` : ""}
|
|
300
|
-
|
|
301
|
-
# Environment Configuration
|
|
302
|
-
environments:
|
|
303
|
-
development:
|
|
304
|
-
autoApprove: true
|
|
305
|
-
qualityGates:
|
|
306
|
-
- ARCHITECTURE
|
|
307
|
-
${qualityGates.map((g) => ` - ${g}`).join("\n")}
|
|
308
|
-
|
|
309
|
-
production:
|
|
310
|
-
autoApprove: false
|
|
311
|
-
requiresManualPromotion: true
|
|
312
|
-
qualityGates:
|
|
313
|
-
- ARCHITECTURE
|
|
314
|
-
${qualityGates.map((g) => ` - ${g}`).join("\n")}
|
|
315
|
-
- ACCEPTANCE
|
|
316
|
-
---
|
|
317
|
-
|
|
318
|
-
# Project Architecture
|
|
319
|
-
|
|
320
|
-
## Overview
|
|
321
|
-
|
|
322
|
-
This architecture document was auto-generated by ArchonDev on ${now}.
|
|
323
|
-
|
|
324
|
-
${analyze ? `## Codebase Analysis
|
|
325
|
-
|
|
326
|
-
- **Total Files:** ${stats.totalFiles}
|
|
327
|
-
- **Total Lines:** ${formatLines(stats.totalLines)}
|
|
328
|
-
- **Primary Language:** ${capabilities.primaryLanguage}
|
|
329
|
-
|
|
330
|
-
### Language Breakdown
|
|
331
|
-
|
|
332
|
-
${Object.entries(stats.languageBreakdown).sort((a, b) => b[1].lines - a[1].lines).map(([lang, data]) => `- ${lang}: ${data.files} files, ${formatLines(data.lines)} lines`).join("\n")}
|
|
333
|
-
|
|
334
|
-
### Detected Capabilities
|
|
335
|
-
|
|
336
|
-
- TypeScript: ${capabilities.hasTypeScript ? "\u2705" : "\u274C"}
|
|
337
|
-
- ESLint: ${capabilities.hasESLint ? "\u2705" : "\u274C"}
|
|
338
|
-
- Testing: ${capabilities.hasJest ? "\u2705" : "\u274C"}
|
|
339
|
-
- Package Manager: ${capabilities.packageManager ?? "Not detected"}
|
|
340
|
-
` : ""}
|
|
341
|
-
## Components
|
|
342
|
-
|
|
343
|
-
${suggestedComponents.map((c) => `### ${c.name}
|
|
344
|
-
|
|
345
|
-
Path: \`${c.path}\`
|
|
346
|
-
|
|
347
|
-
TODO: Add description for this component.
|
|
348
|
-
`).join("\n")}
|
|
349
|
-
|
|
350
|
-
## Getting Started
|
|
351
|
-
|
|
352
|
-
1. Review and customize the components above
|
|
353
|
-
2. Add invariants for your specific rules
|
|
354
|
-
3. Define protected paths for sensitive files
|
|
355
|
-
4. Run \`archon plan <description>\` to create your first atom
|
|
356
|
-
|
|
357
|
-
## Architecture Decision Records
|
|
358
|
-
|
|
359
|
-
Document important architectural decisions here.
|
|
360
|
-
`;
|
|
361
|
-
}
|
|
362
|
-
function formatLines(n) {
|
|
363
|
-
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
364
|
-
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
365
|
-
return n.toString();
|
|
366
|
-
}
|
|
367
|
-
function printSummary(capabilities, stats, analyze) {
|
|
368
|
-
console.log();
|
|
369
|
-
console.log(chalk.green("\u2713 ArchonDev initialized successfully!"));
|
|
370
|
-
console.log();
|
|
371
|
-
console.log(chalk.bold("Detected Capabilities:"));
|
|
372
|
-
console.log(` ${capabilities.hasTypeScript ? chalk.green("\u2713") : chalk.gray("\u25CB")} TypeScript`);
|
|
373
|
-
console.log(` ${capabilities.hasESLint ? chalk.green("\u2713") : chalk.gray("\u25CB")} ESLint`);
|
|
374
|
-
console.log(` ${capabilities.hasJest ? chalk.green("\u2713") : chalk.gray("\u25CB")} Testing (Jest/Vitest)`);
|
|
375
|
-
console.log(` ${capabilities.packageManager ? chalk.green("\u2713") : chalk.gray("\u25CB")} Package Manager: ${capabilities.packageManager ?? "none"}`);
|
|
376
|
-
console.log();
|
|
377
|
-
console.log(chalk.bold("Codebase Summary:"));
|
|
378
|
-
console.log(` Files: ${stats.totalFiles}`);
|
|
379
|
-
console.log(` Lines: ${formatLines(stats.totalLines)}`);
|
|
380
|
-
console.log(` Directories: ${stats.directories.length}`);
|
|
381
|
-
console.log();
|
|
382
|
-
if (Object.keys(stats.languageBreakdown).length > 0) {
|
|
383
|
-
console.log(chalk.bold("Languages:"));
|
|
384
|
-
Object.entries(stats.languageBreakdown).sort((a, b) => b[1].lines - a[1].lines).slice(0, 5).forEach(([lang, data]) => {
|
|
385
|
-
const pct = Math.round(data.lines / stats.totalLines * 100);
|
|
386
|
-
console.log(` ${lang}: ${pct}%`);
|
|
387
|
-
});
|
|
388
|
-
console.log();
|
|
389
|
-
}
|
|
390
|
-
if (analyze && stats.directories.length > 0) {
|
|
391
|
-
console.log(chalk.bold("Suggested Boundaries:"));
|
|
392
|
-
stats.directories.filter((d) => !d.includes("/")).slice(0, 5).forEach((dir) => {
|
|
393
|
-
console.log(` \u2022 ${dir}/`);
|
|
394
|
-
});
|
|
395
|
-
console.log();
|
|
396
|
-
}
|
|
397
|
-
console.log(chalk.bold("Next Steps:"));
|
|
398
|
-
console.log(` 1. ${chalk.cyan("Review")} ARCHITECTURE.md and customize components`);
|
|
399
|
-
console.log(` 2. ${chalk.cyan("Run")} ${chalk.dim('archon plan "your first task"')} to create an atom`);
|
|
400
|
-
console.log(` 3. ${chalk.cyan("Execute")} ${chalk.dim("archon execute ATOM-001")} to implement it`);
|
|
401
|
-
console.log();
|
|
402
|
-
}
|
|
403
|
-
|
|
404
70
|
// src/cli/promote.ts
|
|
405
|
-
import
|
|
406
|
-
import { existsSync
|
|
407
|
-
import { readFile
|
|
408
|
-
import { join
|
|
71
|
+
import chalk from "chalk";
|
|
72
|
+
import { existsSync } from "fs";
|
|
73
|
+
import { readFile, writeFile } from "fs/promises";
|
|
74
|
+
import { join } from "path";
|
|
409
75
|
var ATOMS_DIR = ".archon/atoms";
|
|
410
76
|
async function promote(atomId, options) {
|
|
411
77
|
const cwd = process.cwd();
|
|
412
78
|
const atom = await loadAtom(atomId);
|
|
413
79
|
if (!atom) {
|
|
414
|
-
console.error(
|
|
415
|
-
console.log(
|
|
80
|
+
console.error(chalk.red(`Atom ${atomId} not found.`));
|
|
81
|
+
console.log(chalk.dim(`Use "archon list" to see available atoms.`));
|
|
416
82
|
process.exit(1);
|
|
417
83
|
}
|
|
418
84
|
const envLoader = new EnvironmentConfigLoader(cwd);
|
|
419
85
|
if (!envLoader.isValidEnvironment(options.to)) {
|
|
420
|
-
console.error(
|
|
421
|
-
console.log(
|
|
86
|
+
console.error(chalk.red(`Invalid target environment: ${options.to}`));
|
|
87
|
+
console.log(chalk.dim("Valid environments: development, staging, production"));
|
|
422
88
|
process.exit(1);
|
|
423
89
|
}
|
|
424
90
|
const targetEnv = options.to;
|
|
@@ -428,185 +94,185 @@ async function promote(atomId, options) {
|
|
|
428
94
|
const currentEnv = envState?.lastExecutedEnv ?? "development";
|
|
429
95
|
const result = validator.validatePromotion(atom, targetEnv, currentEnv);
|
|
430
96
|
if (!result.success) {
|
|
431
|
-
console.error(
|
|
432
|
-
console.error(
|
|
97
|
+
console.error(chalk.red("Promotion failed:"));
|
|
98
|
+
console.error(chalk.red(result.message));
|
|
433
99
|
process.exit(1);
|
|
434
100
|
}
|
|
435
101
|
await saveAtomEnvironmentState(atomId, cwd, {
|
|
436
102
|
lastExecutedEnv: currentEnv,
|
|
437
103
|
promotedTo: [...envState?.promotedTo ?? [], targetEnv]
|
|
438
104
|
});
|
|
439
|
-
console.log(
|
|
440
|
-
console.log(
|
|
105
|
+
console.log(chalk.green(`\u2713 ${result.message}`));
|
|
106
|
+
console.log(chalk.dim(`
|
|
441
107
|
To execute in ${targetEnv}:`));
|
|
442
|
-
console.log(
|
|
108
|
+
console.log(chalk.cyan(` archon execute ${atomId} --env=${targetEnv}`));
|
|
443
109
|
}
|
|
444
110
|
async function loadAtomEnvironmentState(atomId, cwd) {
|
|
445
|
-
const stateFile =
|
|
446
|
-
if (!
|
|
111
|
+
const stateFile = join(cwd, ATOMS_DIR, `${atomId}.env.json`);
|
|
112
|
+
if (!existsSync(stateFile)) {
|
|
447
113
|
return null;
|
|
448
114
|
}
|
|
449
|
-
const content = await
|
|
115
|
+
const content = await readFile(stateFile, "utf-8");
|
|
450
116
|
return JSON.parse(content);
|
|
451
117
|
}
|
|
452
118
|
async function saveAtomEnvironmentState(atomId, cwd, state) {
|
|
453
|
-
const stateFile =
|
|
454
|
-
await
|
|
119
|
+
const stateFile = join(cwd, ATOMS_DIR, `${atomId}.env.json`);
|
|
120
|
+
await writeFile(stateFile, JSON.stringify(state, null, 2));
|
|
455
121
|
}
|
|
456
122
|
|
|
457
123
|
// src/cli/show.ts
|
|
458
|
-
import
|
|
124
|
+
import chalk2 from "chalk";
|
|
459
125
|
var STATUS_COLORS = {
|
|
460
|
-
DRAFT:
|
|
461
|
-
READY:
|
|
462
|
-
IN_PROGRESS:
|
|
463
|
-
TESTING:
|
|
464
|
-
DONE:
|
|
465
|
-
FAILED:
|
|
466
|
-
BLOCKED:
|
|
126
|
+
DRAFT: chalk2.gray,
|
|
127
|
+
READY: chalk2.blue,
|
|
128
|
+
IN_PROGRESS: chalk2.yellow,
|
|
129
|
+
TESTING: chalk2.cyan,
|
|
130
|
+
DONE: chalk2.green,
|
|
131
|
+
FAILED: chalk2.red,
|
|
132
|
+
BLOCKED: chalk2.magenta
|
|
467
133
|
};
|
|
468
134
|
async function show(atomId) {
|
|
469
135
|
const atom = await loadAtom(atomId);
|
|
470
136
|
if (!atom) {
|
|
471
|
-
console.error(
|
|
472
|
-
console.log(
|
|
137
|
+
console.error(chalk2.red(`Atom ${atomId} not found.`));
|
|
138
|
+
console.log(chalk2.dim('Use "archon list" to see available atoms.'));
|
|
473
139
|
process.exit(1);
|
|
474
140
|
}
|
|
475
|
-
const colorFn = STATUS_COLORS[atom.status] ??
|
|
141
|
+
const colorFn = STATUS_COLORS[atom.status] ?? chalk2.white;
|
|
476
142
|
console.log("");
|
|
477
|
-
console.log(
|
|
478
|
-
console.log(
|
|
143
|
+
console.log(chalk2.bold(`Atom: ${atom.externalId}`));
|
|
144
|
+
console.log(chalk2.dim("\u2550".repeat(60)));
|
|
479
145
|
console.log("");
|
|
480
|
-
console.log(
|
|
146
|
+
console.log(chalk2.bold("Title:"), atom.title);
|
|
481
147
|
if (atom.description) {
|
|
482
|
-
console.log(
|
|
148
|
+
console.log(chalk2.bold("Description:"), atom.description);
|
|
483
149
|
}
|
|
484
|
-
console.log(
|
|
485
|
-
console.log(
|
|
486
|
-
console.log(
|
|
487
|
-
console.log(
|
|
150
|
+
console.log(chalk2.bold("Status:"), colorFn(atom.status));
|
|
151
|
+
console.log(chalk2.bold("Priority:"), atom.priority);
|
|
152
|
+
console.log(chalk2.bold("Created:"), formatDateTime(atom.createdAt));
|
|
153
|
+
console.log(chalk2.bold("Updated:"), formatDateTime(atom.updatedAt));
|
|
488
154
|
if (atom.goals && atom.goals.length > 0) {
|
|
489
155
|
console.log("");
|
|
490
|
-
console.log(
|
|
156
|
+
console.log(chalk2.bold("Goals:"));
|
|
491
157
|
for (const goal of atom.goals) {
|
|
492
158
|
console.log(` \u2022 ${goal}`);
|
|
493
159
|
}
|
|
494
160
|
}
|
|
495
161
|
if (atom.acceptanceCriteria && atom.acceptanceCriteria.length > 0) {
|
|
496
162
|
console.log("");
|
|
497
|
-
console.log(
|
|
163
|
+
console.log(chalk2.bold("Acceptance Criteria:"));
|
|
498
164
|
for (let i = 0; i < atom.acceptanceCriteria.length; i++) {
|
|
499
165
|
console.log(` ${i + 1}. ${atom.acceptanceCriteria[i]}`);
|
|
500
166
|
}
|
|
501
167
|
}
|
|
502
168
|
if (atom.tags && atom.tags.length > 0) {
|
|
503
169
|
console.log("");
|
|
504
|
-
console.log(
|
|
170
|
+
console.log(chalk2.bold("Tags:"), atom.tags.join(", "));
|
|
505
171
|
}
|
|
506
172
|
if (atom.plan) {
|
|
507
173
|
console.log("");
|
|
508
|
-
console.log(
|
|
509
|
-
console.log(
|
|
510
|
-
console.log(
|
|
174
|
+
console.log(chalk2.bold("Implementation Plan:"));
|
|
175
|
+
console.log(chalk2.dim("\u2500".repeat(40)));
|
|
176
|
+
console.log(chalk2.bold("Steps:"));
|
|
511
177
|
for (let i = 0; i < atom.plan.steps.length; i++) {
|
|
512
178
|
console.log(` ${i + 1}. ${atom.plan.steps[i]}`);
|
|
513
179
|
}
|
|
514
180
|
if (atom.plan.files_to_modify.length > 0) {
|
|
515
181
|
console.log("");
|
|
516
|
-
console.log(
|
|
182
|
+
console.log(chalk2.bold("Files to modify:"));
|
|
517
183
|
for (const file of atom.plan.files_to_modify) {
|
|
518
184
|
console.log(` \u2022 ${file}`);
|
|
519
185
|
}
|
|
520
186
|
}
|
|
521
187
|
if (atom.plan.dependencies.length > 0) {
|
|
522
188
|
console.log("");
|
|
523
|
-
console.log(
|
|
189
|
+
console.log(chalk2.bold("Dependencies:"));
|
|
524
190
|
for (const dep of atom.plan.dependencies) {
|
|
525
191
|
console.log(` \u2022 ${dep}`);
|
|
526
192
|
}
|
|
527
193
|
}
|
|
528
194
|
if (atom.plan.risks.length > 0) {
|
|
529
195
|
console.log("");
|
|
530
|
-
console.log(
|
|
196
|
+
console.log(chalk2.bold("Risks:"));
|
|
531
197
|
for (const risk of atom.plan.risks) {
|
|
532
|
-
console.log(
|
|
198
|
+
console.log(chalk2.yellow(` \u26A0 ${risk}`));
|
|
533
199
|
}
|
|
534
200
|
}
|
|
535
201
|
console.log("");
|
|
536
|
-
console.log(
|
|
202
|
+
console.log(chalk2.bold("Estimated Complexity:"), atom.plan.estimated_complexity);
|
|
537
203
|
}
|
|
538
204
|
if (atom.status === "FAILED" && atom.errorMessage) {
|
|
539
205
|
console.log("");
|
|
540
|
-
console.log(
|
|
541
|
-
console.log(
|
|
206
|
+
console.log(chalk2.bold("Error:"));
|
|
207
|
+
console.log(chalk2.red(` ${atom.errorMessage}`));
|
|
542
208
|
}
|
|
543
209
|
if (atom.retryCount > 0) {
|
|
544
210
|
console.log("");
|
|
545
|
-
console.log(
|
|
211
|
+
console.log(chalk2.bold("Retry Count:"), chalk2.yellow(String(atom.retryCount)));
|
|
546
212
|
}
|
|
547
213
|
if (atom.ownershipPaths && atom.ownershipPaths.length > 0) {
|
|
548
214
|
console.log("");
|
|
549
|
-
console.log(
|
|
215
|
+
console.log(chalk2.bold("Ownership Paths:"));
|
|
550
216
|
for (const path2 of atom.ownershipPaths) {
|
|
551
217
|
console.log(` \u2022 ${path2}`);
|
|
552
218
|
}
|
|
553
219
|
}
|
|
554
220
|
if (atom.diffContract) {
|
|
555
221
|
console.log("");
|
|
556
|
-
console.log(
|
|
222
|
+
console.log(chalk2.bold("Diff Contract:"));
|
|
557
223
|
if (atom.diffContract.allowed_paths.length > 0) {
|
|
558
|
-
console.log(
|
|
224
|
+
console.log(chalk2.dim(" Allowed paths:"));
|
|
559
225
|
for (const path2 of atom.diffContract.allowed_paths) {
|
|
560
226
|
console.log(` \u2713 ${path2}`);
|
|
561
227
|
}
|
|
562
228
|
}
|
|
563
229
|
if (atom.diffContract.forbidden_paths.length > 0) {
|
|
564
|
-
console.log(
|
|
230
|
+
console.log(chalk2.dim(" Forbidden paths:"));
|
|
565
231
|
for (const path2 of atom.diffContract.forbidden_paths) {
|
|
566
|
-
console.log(
|
|
232
|
+
console.log(chalk2.red(` \u2717 ${path2}`));
|
|
567
233
|
}
|
|
568
234
|
}
|
|
569
235
|
}
|
|
570
236
|
if (atom.context && Object.keys(atom.context).length > 0) {
|
|
571
237
|
console.log("");
|
|
572
|
-
console.log(
|
|
238
|
+
console.log(chalk2.bold("Context:"));
|
|
573
239
|
if (atom.context.relevantFiles && atom.context.relevantFiles.length > 0) {
|
|
574
|
-
console.log(
|
|
240
|
+
console.log(chalk2.dim(" Relevant files:"));
|
|
575
241
|
for (const file of atom.context.relevantFiles) {
|
|
576
242
|
console.log(` \u2022 ${file}`);
|
|
577
243
|
}
|
|
578
244
|
}
|
|
579
245
|
if (atom.context.recentLearnings && atom.context.recentLearnings.length > 0) {
|
|
580
|
-
console.log(
|
|
246
|
+
console.log(chalk2.dim(" Recent learnings:"));
|
|
581
247
|
for (const learning of atom.context.recentLearnings) {
|
|
582
248
|
console.log(` \u2022 ${learning}`);
|
|
583
249
|
}
|
|
584
250
|
}
|
|
585
251
|
}
|
|
586
252
|
console.log("");
|
|
587
|
-
console.log(
|
|
588
|
-
console.log(
|
|
253
|
+
console.log(chalk2.dim("\u2500".repeat(60)));
|
|
254
|
+
console.log(chalk2.bold("Next Steps:"));
|
|
589
255
|
switch (atom.status) {
|
|
590
256
|
case "DRAFT":
|
|
591
|
-
console.log(
|
|
257
|
+
console.log(chalk2.dim(` Run "archon plan ${atom.externalId} --continue" to finalize the plan`));
|
|
592
258
|
break;
|
|
593
259
|
case "READY":
|
|
594
|
-
console.log(
|
|
260
|
+
console.log(chalk2.dim(` Run "archon execute ${atom.externalId}" to implement`));
|
|
595
261
|
break;
|
|
596
262
|
case "IN_PROGRESS":
|
|
597
|
-
console.log(
|
|
263
|
+
console.log(chalk2.dim(" Execution is in progress..."));
|
|
598
264
|
break;
|
|
599
265
|
case "TESTING":
|
|
600
|
-
console.log(
|
|
266
|
+
console.log(chalk2.dim(" Waiting for quality gates to complete..."));
|
|
601
267
|
break;
|
|
602
268
|
case "DONE":
|
|
603
|
-
console.log(
|
|
269
|
+
console.log(chalk2.green(" \u2713 Atom completed successfully!"));
|
|
604
270
|
break;
|
|
605
271
|
case "FAILED":
|
|
606
|
-
console.log(
|
|
272
|
+
console.log(chalk2.dim(` Review the error and run "archon execute ${atom.externalId}" to retry`));
|
|
607
273
|
break;
|
|
608
274
|
case "BLOCKED":
|
|
609
|
-
console.log(
|
|
275
|
+
console.log(chalk2.dim(" This atom is blocked. Manual intervention required."));
|
|
610
276
|
break;
|
|
611
277
|
}
|
|
612
278
|
console.log("");
|
|
@@ -617,47 +283,34 @@ function formatDateTime(date) {
|
|
|
617
283
|
}
|
|
618
284
|
|
|
619
285
|
// src/cli/start.ts
|
|
620
|
-
import
|
|
621
|
-
import
|
|
622
|
-
import { existsSync as
|
|
623
|
-
import { join as
|
|
286
|
+
import chalk3 from "chalk";
|
|
287
|
+
import readline from "readline";
|
|
288
|
+
import { existsSync as existsSync2, readFileSync, readdirSync, appendFileSync } from "fs";
|
|
289
|
+
import { join as join2 } from "path";
|
|
624
290
|
async function start() {
|
|
625
291
|
const cwd = process.cwd();
|
|
626
|
-
console.log(
|
|
627
|
-
console.log(
|
|
628
|
-
console.log(
|
|
292
|
+
console.log(chalk3.blue("\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
|
|
293
|
+
console.log(chalk3.bold.white(" ArchonDev - AI-Powered Development Governance"));
|
|
294
|
+
console.log(chalk3.blue("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n"));
|
|
629
295
|
const projectState = detectProjectState(cwd);
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
];
|
|
641
|
-
console.log(chalk4.bold("What would you like to do?\n"));
|
|
642
|
-
for (const choice2 of choices) {
|
|
643
|
-
console.log(` ${chalk4.cyan(choice2.key)}) ${choice2.label}`);
|
|
644
|
-
}
|
|
645
|
-
console.log();
|
|
646
|
-
const selected = await prompt("Enter choice");
|
|
647
|
-
const choice = choices.find((c) => c.key === selected.toLowerCase());
|
|
648
|
-
if (choice) {
|
|
649
|
-
await choice.action();
|
|
650
|
-
} else {
|
|
651
|
-
console.log(chalk4.yellow("Invalid choice. Please try again."));
|
|
652
|
-
await start();
|
|
296
|
+
switch (projectState.scenario) {
|
|
297
|
+
case "NEW_PROJECT":
|
|
298
|
+
await handleNewProject(cwd, projectState);
|
|
299
|
+
break;
|
|
300
|
+
case "ADAPT_EXISTING":
|
|
301
|
+
await handleAdaptExisting(cwd, projectState);
|
|
302
|
+
break;
|
|
303
|
+
case "CONTINUE_SESSION":
|
|
304
|
+
await handleContinueSession(cwd, projectState);
|
|
305
|
+
break;
|
|
653
306
|
}
|
|
654
307
|
}
|
|
655
308
|
function detectProjectState(cwd) {
|
|
656
|
-
const sourceDirs = ["src", "lib", "app", "packages", "components"];
|
|
657
|
-
const sourceExtensions = [".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java"];
|
|
309
|
+
const sourceDirs = ["src", "lib", "app", "packages", "components", "pages", "api"];
|
|
310
|
+
const sourceExtensions = [".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java", ".rb", ".php"];
|
|
658
311
|
let hasSourceFiles = false;
|
|
659
312
|
for (const dir of sourceDirs) {
|
|
660
|
-
if (
|
|
313
|
+
if (existsSync2(join2(cwd, dir))) {
|
|
661
314
|
hasSourceFiles = true;
|
|
662
315
|
break;
|
|
663
316
|
}
|
|
@@ -671,29 +324,351 @@ function detectProjectState(cwd) {
|
|
|
671
324
|
} catch {
|
|
672
325
|
}
|
|
673
326
|
}
|
|
327
|
+
const projectMarkers = ["package.json", "Cargo.toml", "pyproject.toml", "go.mod", "pom.xml", "build.gradle"];
|
|
328
|
+
if (!hasSourceFiles) {
|
|
329
|
+
hasSourceFiles = projectMarkers.some((marker) => existsSync2(join2(cwd, marker)));
|
|
330
|
+
}
|
|
331
|
+
const hasArchitecture = existsSync2(join2(cwd, "ARCHITECTURE.md"));
|
|
332
|
+
const hasProgress = existsSync2(join2(cwd, "progress.txt"));
|
|
333
|
+
const hasReviewDb = existsSync2(join2(cwd, "docs", "code-review", "review-tasks.db"));
|
|
334
|
+
let hasProgressEntries = false;
|
|
335
|
+
let lastProgressEntry;
|
|
336
|
+
if (hasProgress) {
|
|
337
|
+
try {
|
|
338
|
+
const progressContent = readFileSync(join2(cwd, "progress.txt"), "utf-8");
|
|
339
|
+
const entries = progressContent.match(/^## \d{4}-\d{2}-\d{2}/gm);
|
|
340
|
+
hasProgressEntries = entries !== null && entries.length > 0;
|
|
341
|
+
if (hasProgressEntries) {
|
|
342
|
+
const lastMatch = progressContent.match(/## \d{4}-\d{2}-\d{2}[^\n]*\n([^#]*)/g);
|
|
343
|
+
if (lastMatch && lastMatch.length > 0) {
|
|
344
|
+
const last = lastMatch[lastMatch.length - 1] ?? "";
|
|
345
|
+
lastProgressEntry = last.split("\n").slice(0, 3).join("\n").trim();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
} catch {
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
let scenario;
|
|
352
|
+
if (hasProgressEntries) {
|
|
353
|
+
scenario = "CONTINUE_SESSION";
|
|
354
|
+
} else if (hasSourceFiles) {
|
|
355
|
+
scenario = "ADAPT_EXISTING";
|
|
356
|
+
} else {
|
|
357
|
+
scenario = "NEW_PROJECT";
|
|
358
|
+
}
|
|
674
359
|
return {
|
|
360
|
+
scenario,
|
|
675
361
|
hasSourceFiles,
|
|
676
|
-
hasArchitecture
|
|
677
|
-
|
|
362
|
+
hasArchitecture,
|
|
363
|
+
hasProgress,
|
|
364
|
+
hasProgressEntries,
|
|
365
|
+
hasReviewDb,
|
|
366
|
+
lastProgressEntry
|
|
678
367
|
};
|
|
679
368
|
}
|
|
680
|
-
async function
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
369
|
+
async function handleNewProject(cwd, state) {
|
|
370
|
+
console.log(chalk3.yellow("\u{1F389}") + chalk3.bold(" Starting a new project? Great!\n"));
|
|
371
|
+
console.log(chalk3.dim("I'll ask you a few quick questions to set things up right."));
|
|
372
|
+
console.log(chalk3.dim("Answer as much or as little as you want \u2014 you can always refine later.\n"));
|
|
373
|
+
console.log(chalk3.bold("What would you like to do?\n"));
|
|
374
|
+
console.log(` ${chalk3.cyan("1")}) ${chalk3.bold("Start interview")} \u2014 I'll ask questions to understand your project`);
|
|
375
|
+
console.log(` ${chalk3.cyan("2")}) ${chalk3.bold("Quick start")} \u2014 Just create basic governance files`);
|
|
376
|
+
console.log(` ${chalk3.cyan("3")}) ${chalk3.bold("Import from template")} \u2014 Use a predefined project template`);
|
|
377
|
+
console.log(` ${chalk3.cyan("q")}) ${chalk3.dim("Quit")}`);
|
|
378
|
+
console.log();
|
|
379
|
+
const choice = await prompt("Enter choice");
|
|
380
|
+
switch (choice.toLowerCase()) {
|
|
381
|
+
case "1":
|
|
382
|
+
await runNewProjectInterview(cwd);
|
|
383
|
+
break;
|
|
384
|
+
case "2":
|
|
385
|
+
await quickStart(cwd);
|
|
386
|
+
break;
|
|
387
|
+
case "3":
|
|
388
|
+
console.log(chalk3.yellow("\nTemplates coming soon! Using quick start for now.\n"));
|
|
389
|
+
await quickStart(cwd);
|
|
390
|
+
break;
|
|
391
|
+
case "q":
|
|
392
|
+
process.exit(0);
|
|
393
|
+
default:
|
|
394
|
+
console.log(chalk3.yellow("Invalid choice. Please try again."));
|
|
395
|
+
await handleNewProject(cwd, state);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
async function runNewProjectInterview(cwd) {
|
|
399
|
+
console.log(chalk3.blue("\n\u2501\u2501\u2501 Project Interview \u2501\u2501\u2501\n"));
|
|
400
|
+
console.log(chalk3.bold("Phase 1: The Vision\n"));
|
|
401
|
+
const projectName = await prompt("What's the project name?");
|
|
402
|
+
const projectDescription = await prompt("In one sentence, what does this project do?");
|
|
403
|
+
const audience = await promptChoice("Who is it for?", [
|
|
404
|
+
{ key: "1", label: "Just me (personal project)" },
|
|
405
|
+
{ key: "2", label: "My team (internal tool)" },
|
|
406
|
+
{ key: "3", label: "End users (product)" }
|
|
407
|
+
]);
|
|
408
|
+
const experience = await promptChoice("Your experience level with this tech stack?", [
|
|
409
|
+
{ key: "1", label: "\u{1F7E2} Expert \u2014 I know this well" },
|
|
410
|
+
{ key: "2", label: "\u{1F7E1} Intermediate \u2014 I've done similar work" },
|
|
411
|
+
{ key: "3", label: "\u{1F534} Learning \u2014 This is new to me" }
|
|
412
|
+
]);
|
|
413
|
+
console.log(chalk3.bold("\nPhase 2: Tech Stack\n"));
|
|
414
|
+
const language = await promptChoice("Primary language/framework?", [
|
|
415
|
+
{ key: "1", label: "TypeScript / JavaScript" },
|
|
416
|
+
{ key: "2", label: "Python" },
|
|
417
|
+
{ key: "3", label: "Go" },
|
|
418
|
+
{ key: "4", label: "Rust" },
|
|
419
|
+
{ key: "5", label: "Other" }
|
|
420
|
+
]);
|
|
421
|
+
const projectType = await promptChoice("Project type?", [
|
|
422
|
+
{ key: "1", label: "Frontend only (web UI)" },
|
|
423
|
+
{ key: "2", label: "Backend only (API, CLI, service)" },
|
|
424
|
+
{ key: "3", label: "Full-stack (both)" },
|
|
425
|
+
{ key: "4", label: "Library/package" }
|
|
426
|
+
]);
|
|
427
|
+
console.log(chalk3.bold("\nPhase 3: Preferences ") + chalk3.dim("(press Enter to skip)\n"));
|
|
428
|
+
const protectedFiles = await prompt("Any files AI should NEVER modify without asking? (comma-separated)");
|
|
429
|
+
const noNoPatterns = await prompt('Anything AI should NEVER do? (e.g., "no console.log")');
|
|
430
|
+
console.log(chalk3.blue("\n\u2501\u2501\u2501 Generating Project Files \u2501\u2501\u2501\n"));
|
|
431
|
+
const { init: init2 } = await import("./init-YLAHY4CV.js");
|
|
432
|
+
await init2({ analyze: false, git: true });
|
|
433
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
434
|
+
const progressEntry = `
|
|
435
|
+
## ${today} - Project Initialized via Interview
|
|
436
|
+
|
|
437
|
+
### Vision
|
|
438
|
+
- **Name:** ${projectName || "Unnamed Project"}
|
|
439
|
+
- **Description:** ${projectDescription || "No description provided"}
|
|
440
|
+
- **Audience:** ${["Personal", "Team", "End Users"][parseInt(audience) - 1] || "Not specified"}
|
|
441
|
+
- **Experience Level:** ${["Expert", "Intermediate", "Learning"][parseInt(experience) - 1] || "Not specified"}
|
|
442
|
+
|
|
443
|
+
### Stack
|
|
444
|
+
- **Language:** ${["TypeScript/JavaScript", "Python", "Go", "Rust", "Other"][parseInt(language) - 1] || "Not specified"}
|
|
445
|
+
- **Type:** ${["Frontend", "Backend", "Full-stack", "Library"][parseInt(projectType) - 1] || "Not specified"}
|
|
446
|
+
|
|
447
|
+
### Preferences
|
|
448
|
+
${protectedFiles ? `- **Protected files:** ${protectedFiles}` : "- No protected files specified"}
|
|
449
|
+
${noNoPatterns ? `- **Forbidden patterns:** ${noNoPatterns}` : "- No forbidden patterns specified"}
|
|
450
|
+
|
|
451
|
+
### Files Created
|
|
452
|
+
- ARCHITECTURE.md
|
|
453
|
+
- .archon/config.yaml
|
|
454
|
+
- progress.txt
|
|
455
|
+
`;
|
|
456
|
+
const progressPath = join2(cwd, "progress.txt");
|
|
457
|
+
if (!existsSync2(progressPath)) {
|
|
458
|
+
const { writeFileSync } = await import("fs");
|
|
459
|
+
writeFileSync(progressPath, "# ArchonDev Progress Log\n\nThis file tracks learnings and decisions across sessions.\n");
|
|
460
|
+
}
|
|
461
|
+
appendFileSync(progressPath, progressEntry);
|
|
462
|
+
console.log(chalk3.green("\n\u2713 Project initialized!\n"));
|
|
463
|
+
console.log(chalk3.bold("Next steps:"));
|
|
464
|
+
console.log(` 1. ${chalk3.cyan("Review")} ARCHITECTURE.md and customize if needed`);
|
|
465
|
+
console.log(` 2. ${chalk3.cyan("Run")} ${chalk3.dim('archon plan "your first task"')} to create an atom`);
|
|
466
|
+
console.log();
|
|
467
|
+
const continueChoice = await promptYesNo("Would you like to plan your first task now?", true);
|
|
468
|
+
if (continueChoice) {
|
|
469
|
+
const description = await prompt("Describe what you want to build first");
|
|
470
|
+
if (description.trim()) {
|
|
471
|
+
const { plan: plan2 } = await import("./plan-WQUFH2WB.js");
|
|
472
|
+
await plan2(description, {});
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
async function quickStart(cwd) {
|
|
477
|
+
console.log(chalk3.blue("\n\u2501\u2501\u2501 Quick Start \u2501\u2501\u2501\n"));
|
|
478
|
+
const { init: init2 } = await import("./init-YLAHY4CV.js");
|
|
479
|
+
await init2({ analyze: false, git: true });
|
|
480
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
481
|
+
const progressPath = join2(cwd, "progress.txt");
|
|
482
|
+
if (!existsSync2(progressPath)) {
|
|
483
|
+
const { writeFileSync } = await import("fs");
|
|
484
|
+
writeFileSync(progressPath, `# ArchonDev Progress Log
|
|
485
|
+
|
|
486
|
+
This file tracks learnings and decisions across sessions.
|
|
487
|
+
|
|
488
|
+
## ${today} - Project Initialized (Quick Start)
|
|
489
|
+
|
|
490
|
+
### What was done
|
|
491
|
+
- Created ARCHITECTURE.md with default template
|
|
492
|
+
- Initialized .archon directory
|
|
493
|
+
- Created this progress.txt
|
|
494
|
+
|
|
495
|
+
### Next Steps
|
|
496
|
+
1. Customize ARCHITECTURE.md for your project
|
|
497
|
+
2. Run \`archon plan "your first task"\` to create an atom
|
|
498
|
+
`);
|
|
499
|
+
}
|
|
500
|
+
console.log();
|
|
501
|
+
await showMainMenu();
|
|
502
|
+
}
|
|
503
|
+
async function handleAdaptExisting(cwd, state) {
|
|
504
|
+
console.log(chalk3.yellow("\u{1F4C1}") + chalk3.bold(" Existing project detected!\n"));
|
|
505
|
+
console.log(chalk3.dim("I can analyze your codebase and adapt the governance files to match your structure."));
|
|
506
|
+
console.log(chalk3.dim("This helps me understand your architecture without changing any code.\n"));
|
|
507
|
+
console.log(chalk3.bold("What would you like to do?\n"));
|
|
508
|
+
console.log(` ${chalk3.cyan("1")}) ${chalk3.bold("Analyze and adapt")} \u2014 I'll scan your project and update ARCHITECTURE.md`);
|
|
509
|
+
console.log(` ${chalk3.cyan("2")}) ${chalk3.bold("Code review first")} \u2014 Review code for issues before setting up governance`);
|
|
510
|
+
console.log(` ${chalk3.cyan("3")}) ${chalk3.bold("Manual setup")} \u2014 Keep template files, customize manually`);
|
|
511
|
+
console.log(` ${chalk3.cyan("4")}) ${chalk3.bold("Just start working")} \u2014 Skip setup, use defaults`);
|
|
512
|
+
console.log(` ${chalk3.cyan("q")}) ${chalk3.dim("Quit")}`);
|
|
513
|
+
console.log();
|
|
514
|
+
const choice = await prompt("Enter choice");
|
|
515
|
+
switch (choice.toLowerCase()) {
|
|
516
|
+
case "1":
|
|
517
|
+
await analyzeAndAdapt(cwd);
|
|
518
|
+
break;
|
|
519
|
+
case "2":
|
|
520
|
+
await codeReviewFirst(cwd);
|
|
521
|
+
break;
|
|
522
|
+
case "3":
|
|
523
|
+
await manualSetup(cwd);
|
|
524
|
+
break;
|
|
525
|
+
case "4":
|
|
526
|
+
await quickAdapt(cwd);
|
|
527
|
+
break;
|
|
528
|
+
case "q":
|
|
529
|
+
process.exit(0);
|
|
530
|
+
default:
|
|
531
|
+
console.log(chalk3.yellow("Invalid choice. Please try again."));
|
|
532
|
+
await handleAdaptExisting(cwd, state);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
async function analyzeAndAdapt(cwd) {
|
|
536
|
+
console.log(chalk3.blue("\n\u2501\u2501\u2501 Analyzing Project \u2501\u2501\u2501\n"));
|
|
537
|
+
const { init: init2 } = await import("./init-YLAHY4CV.js");
|
|
538
|
+
await init2({ analyze: true, git: true });
|
|
539
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
540
|
+
const progressPath = join2(cwd, "progress.txt");
|
|
541
|
+
if (!existsSync2(progressPath)) {
|
|
542
|
+
const { writeFileSync } = await import("fs");
|
|
543
|
+
writeFileSync(progressPath, "# ArchonDev Progress Log\n\nThis file tracks learnings and decisions across sessions.\n");
|
|
544
|
+
}
|
|
545
|
+
appendFileSync(progressPath, `
|
|
546
|
+
## ${today} - ArchonDev Adapted to Existing Project
|
|
547
|
+
|
|
548
|
+
### What was done
|
|
549
|
+
- Analyzed existing codebase structure
|
|
550
|
+
- Generated ARCHITECTURE.md based on detected components
|
|
551
|
+
- Created .archon configuration
|
|
552
|
+
|
|
553
|
+
### Governance Files Created
|
|
554
|
+
- ARCHITECTURE.md - Customized to match project structure
|
|
555
|
+
- .archon/config.yaml - Build commands configured
|
|
556
|
+
- progress.txt - This file
|
|
557
|
+
`);
|
|
558
|
+
console.log(chalk3.green("\n\u2713 Governance files adapted!\n"));
|
|
559
|
+
await showMainMenu();
|
|
560
|
+
}
|
|
561
|
+
async function codeReviewFirst(cwd) {
|
|
562
|
+
console.log(chalk3.blue("\n\u2501\u2501\u2501 Code Review Mode \u2501\u2501\u2501\n"));
|
|
563
|
+
console.log(chalk3.dim("I'll analyze your code for issues without making any changes.\n"));
|
|
564
|
+
const { reviewInit: reviewInit2, reviewAnalyze: reviewAnalyze2, reviewRun: reviewRun2 } = await import("./review-3R6QXAXQ.js");
|
|
565
|
+
const reviewDbPath = join2(cwd, "docs", "code-review", "review-tasks.db");
|
|
566
|
+
if (!existsSync2(reviewDbPath)) {
|
|
567
|
+
await reviewInit2();
|
|
568
|
+
}
|
|
569
|
+
await reviewAnalyze2();
|
|
570
|
+
const runReview = await promptYesNo("Would you like to run the AI-powered review now?", true);
|
|
571
|
+
if (runReview) {
|
|
572
|
+
await reviewRun2({ all: true });
|
|
573
|
+
}
|
|
574
|
+
console.log(chalk3.dim("\nAfter reviewing, you can run ") + chalk3.cyan("archon") + chalk3.dim(" again to set up governance.\n"));
|
|
575
|
+
}
|
|
576
|
+
async function manualSetup(cwd) {
|
|
577
|
+
console.log(chalk3.blue("\n\u2501\u2501\u2501 Manual Setup \u2501\u2501\u2501\n"));
|
|
578
|
+
console.log(chalk3.dim("Creating template files. You can customize them manually.\n"));
|
|
579
|
+
const { init: init2 } = await import("./init-YLAHY4CV.js");
|
|
580
|
+
await init2({ analyze: false, git: true });
|
|
581
|
+
console.log(chalk3.bold("\nWhat to customize:\n"));
|
|
582
|
+
console.log(` ${chalk3.cyan("1. ARCHITECTURE.md")} \u2014 Update components to match your folders`);
|
|
583
|
+
console.log(` ${chalk3.cyan("2. .archon/config.yaml")} \u2014 Change build/test/lint commands`);
|
|
584
|
+
console.log(` ${chalk3.cyan("3. progress.txt")} \u2014 Add project-specific patterns`);
|
|
585
|
+
console.log();
|
|
586
|
+
await showMainMenu();
|
|
587
|
+
}
|
|
588
|
+
async function quickAdapt(cwd) {
|
|
589
|
+
console.log(chalk3.blue("\n\u26A1 Using defaults \u2014 let's go!\n"));
|
|
590
|
+
const { init: init2 } = await import("./init-YLAHY4CV.js");
|
|
591
|
+
await init2({ analyze: true, git: true });
|
|
592
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
593
|
+
const progressPath = join2(cwd, "progress.txt");
|
|
594
|
+
if (!existsSync2(progressPath)) {
|
|
595
|
+
const { writeFileSync } = await import("fs");
|
|
596
|
+
writeFileSync(progressPath, "# ArchonDev Progress Log\n\nThis file tracks learnings and decisions across sessions.\n");
|
|
597
|
+
}
|
|
598
|
+
appendFileSync(progressPath, `
|
|
599
|
+
## ${today} - Quick Adapt (Defaults)
|
|
600
|
+
|
|
601
|
+
### What was done
|
|
602
|
+
- Used default governance rules
|
|
603
|
+
- You can customize later by editing ARCHITECTURE.md
|
|
604
|
+
`);
|
|
605
|
+
await showMainMenu();
|
|
606
|
+
}
|
|
607
|
+
async function handleContinueSession(cwd, state) {
|
|
608
|
+
console.log(chalk3.green("\u{1F44B}") + chalk3.bold(" Welcome back!\n"));
|
|
609
|
+
if (state.lastProgressEntry) {
|
|
610
|
+
console.log(chalk3.dim("Last activity:"));
|
|
611
|
+
console.log(chalk3.dim(" " + state.lastProgressEntry.split("\n")[0]));
|
|
684
612
|
console.log();
|
|
685
613
|
}
|
|
686
|
-
|
|
687
|
-
|
|
614
|
+
const handoff = checkForHandoff(cwd);
|
|
615
|
+
if (handoff) {
|
|
616
|
+
console.log(chalk3.yellow("\u{1F4CB} Found handoff from last session:\n"));
|
|
617
|
+
console.log(chalk3.dim(handoff.nextSteps));
|
|
618
|
+
console.log();
|
|
619
|
+
const continueHandoff = await promptYesNo("Continue from handoff?", true);
|
|
620
|
+
if (continueHandoff) {
|
|
621
|
+
console.log(chalk3.dim("\nPicking up where you left off...\n"));
|
|
622
|
+
}
|
|
688
623
|
}
|
|
689
624
|
if (state.hasReviewDb) {
|
|
690
625
|
await showReviewProgress(cwd);
|
|
691
626
|
}
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
627
|
+
await showMainMenu();
|
|
628
|
+
}
|
|
629
|
+
function checkForHandoff(cwd) {
|
|
630
|
+
try {
|
|
631
|
+
const progressPath = join2(cwd, "progress.txt");
|
|
632
|
+
if (!existsSync2(progressPath)) return null;
|
|
633
|
+
const content = readFileSync(progressPath, "utf-8");
|
|
634
|
+
const handoffMatch = content.match(/## Context Handoff[^\n]*\n([\s\S]*?)(?=\n## |\n*$)/);
|
|
635
|
+
if (handoffMatch && handoffMatch[1]) {
|
|
636
|
+
const handoffContent = handoffMatch[1];
|
|
637
|
+
const nextStepsMatch = handoffContent.match(/### Next Steps[^\n]*\n([\s\S]*?)(?=\n### |$)/);
|
|
638
|
+
if (nextStepsMatch && nextStepsMatch[1]) {
|
|
639
|
+
return { nextSteps: nextStepsMatch[1].trim() };
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
} catch {
|
|
643
|
+
}
|
|
644
|
+
return null;
|
|
645
|
+
}
|
|
646
|
+
async function showMainMenu() {
|
|
647
|
+
const cwd = process.cwd();
|
|
648
|
+
const state = detectProjectState(cwd);
|
|
649
|
+
console.log(chalk3.bold("What would you like to do?\n"));
|
|
650
|
+
const choices = [
|
|
651
|
+
{ key: "1", label: "Plan a new task", action: () => planTask() },
|
|
652
|
+
{ key: "2", label: "List atoms", action: () => listAtoms() },
|
|
653
|
+
{ key: "3", label: "Execute next atom", action: () => executeNext() },
|
|
654
|
+
{ key: "4", label: "Report a bug", action: () => reportBug() },
|
|
655
|
+
{ key: "5", label: "View status", action: () => viewStatus() },
|
|
656
|
+
{ key: "6", label: "Code Review", action: () => reviewCode() },
|
|
657
|
+
{ key: "7", label: "Settings & Preferences", action: () => settingsMenu() },
|
|
658
|
+
{ key: "q", label: "Quit", action: async () => process.exit(0) }
|
|
659
|
+
];
|
|
660
|
+
for (const choice2 of choices) {
|
|
661
|
+
console.log(` ${chalk3.cyan(choice2.key)}) ${choice2.label}`);
|
|
695
662
|
}
|
|
696
663
|
console.log();
|
|
664
|
+
const selected = await prompt("Enter choice");
|
|
665
|
+
const choice = choices.find((c) => c.key === selected.toLowerCase());
|
|
666
|
+
if (choice) {
|
|
667
|
+
await choice.action();
|
|
668
|
+
} else {
|
|
669
|
+
console.log(chalk3.yellow("Invalid choice. Please try again."));
|
|
670
|
+
await showMainMenu();
|
|
671
|
+
}
|
|
697
672
|
}
|
|
698
673
|
async function showReviewProgress(cwd) {
|
|
699
674
|
try {
|
|
@@ -707,29 +682,30 @@ async function showReviewProgress(cwd) {
|
|
|
707
682
|
const pending = stats.pending + stats.inReview;
|
|
708
683
|
const needsFix = stats.needsFix;
|
|
709
684
|
console.log(
|
|
710
|
-
|
|
685
|
+
chalk3.blue("\u{1F4CA} Review Progress:") + chalk3.dim(` ${completed}/${total} completed`) + (needsFix > 0 ? chalk3.red(` (${needsFix} need fixes)`) : "") + (pending > 0 ? chalk3.yellow(` (${pending} pending)`) : "")
|
|
711
686
|
);
|
|
687
|
+
console.log();
|
|
712
688
|
} catch {
|
|
713
689
|
}
|
|
714
690
|
}
|
|
715
691
|
async function planTask() {
|
|
716
|
-
const { plan: plan2 } = await import("./plan-
|
|
692
|
+
const { plan: plan2 } = await import("./plan-WQUFH2WB.js");
|
|
717
693
|
const description = await prompt("Describe what you want to build");
|
|
718
694
|
if (description.trim()) {
|
|
719
695
|
await plan2(description, {});
|
|
720
696
|
}
|
|
721
697
|
}
|
|
722
698
|
async function listAtoms() {
|
|
723
|
-
const { list: list2 } = await import("./list-
|
|
699
|
+
const { list: list2 } = await import("./list-UB4MOGRH.js");
|
|
724
700
|
await list2({});
|
|
725
701
|
}
|
|
726
702
|
async function executeNext() {
|
|
727
703
|
const atomId = await prompt("Enter atom ID to execute (or press Enter for next planned)");
|
|
728
704
|
if (atomId.trim()) {
|
|
729
|
-
const { execute: execute2 } = await import("./execute-
|
|
705
|
+
const { execute: execute2 } = await import("./execute-6ZGARWT2.js");
|
|
730
706
|
await execute2(atomId.trim(), {});
|
|
731
707
|
} else {
|
|
732
|
-
console.log(
|
|
708
|
+
console.log(chalk3.yellow('No atom ID provided. Use "archon list" to see available atoms.'));
|
|
733
709
|
}
|
|
734
710
|
}
|
|
735
711
|
async function reportBug() {
|
|
@@ -746,23 +722,24 @@ async function viewStatus() {
|
|
|
746
722
|
async function settingsMenu() {
|
|
747
723
|
const { interactiveSettings } = await import("./preferences-QEFXVCZN.js");
|
|
748
724
|
await interactiveSettings();
|
|
749
|
-
await
|
|
725
|
+
await showMainMenu();
|
|
750
726
|
}
|
|
751
727
|
async function reviewCode() {
|
|
752
728
|
const cwd = process.cwd();
|
|
753
|
-
const reviewDbPath =
|
|
754
|
-
if (!
|
|
755
|
-
console.log(
|
|
729
|
+
const reviewDbPath = join2(cwd, "docs", "code-review", "review-tasks.db");
|
|
730
|
+
if (!existsSync2(reviewDbPath)) {
|
|
731
|
+
console.log(chalk3.dim("Code review not initialized. Starting setup...\n"));
|
|
756
732
|
const { reviewInit: reviewInit2 } = await import("./review-3R6QXAXQ.js");
|
|
757
733
|
await reviewInit2();
|
|
758
734
|
console.log();
|
|
759
735
|
}
|
|
760
|
-
console.log(
|
|
761
|
-
console.log(` ${
|
|
762
|
-
console.log(` ${
|
|
763
|
-
console.log(` ${
|
|
764
|
-
console.log(` ${
|
|
765
|
-
console.log(` ${
|
|
736
|
+
console.log(chalk3.bold("\nCode Review Options:\n"));
|
|
737
|
+
console.log(` ${chalk3.cyan("1")}) Analyze project`);
|
|
738
|
+
console.log(` ${chalk3.cyan("2")}) Show review status`);
|
|
739
|
+
console.log(` ${chalk3.cyan("3")}) Review next file`);
|
|
740
|
+
console.log(` ${chalk3.cyan("4")}) List all tasks`);
|
|
741
|
+
console.log(` ${chalk3.cyan("5")}) Run AI review on all pending`);
|
|
742
|
+
console.log(` ${chalk3.cyan("b")}) Back to main menu`);
|
|
766
743
|
console.log();
|
|
767
744
|
const choice = await prompt("Enter choice");
|
|
768
745
|
switch (choice.toLowerCase()) {
|
|
@@ -786,30 +763,68 @@ async function reviewCode() {
|
|
|
786
763
|
await reviewList2({});
|
|
787
764
|
break;
|
|
788
765
|
}
|
|
766
|
+
case "5": {
|
|
767
|
+
const { reviewRun: reviewRun2 } = await import("./review-3R6QXAXQ.js");
|
|
768
|
+
await reviewRun2({ all: true });
|
|
769
|
+
break;
|
|
770
|
+
}
|
|
789
771
|
case "b":
|
|
790
|
-
await
|
|
772
|
+
await showMainMenu();
|
|
791
773
|
return;
|
|
792
774
|
default:
|
|
793
|
-
console.log(
|
|
775
|
+
console.log(chalk3.yellow("Invalid choice."));
|
|
794
776
|
}
|
|
795
777
|
await reviewCode();
|
|
796
778
|
}
|
|
797
779
|
function prompt(question) {
|
|
798
780
|
return new Promise((resolve) => {
|
|
799
|
-
const rl =
|
|
781
|
+
const rl = readline.createInterface({
|
|
800
782
|
input: process.stdin,
|
|
801
783
|
output: process.stdout
|
|
802
784
|
});
|
|
803
|
-
rl.question(`${
|
|
785
|
+
rl.question(`${chalk3.cyan("?")} ${question}: `, (answer) => {
|
|
804
786
|
rl.close();
|
|
805
787
|
resolve(answer);
|
|
806
788
|
});
|
|
807
789
|
});
|
|
808
790
|
}
|
|
791
|
+
function promptYesNo(question, defaultValue) {
|
|
792
|
+
return new Promise((resolve) => {
|
|
793
|
+
const rl = readline.createInterface({
|
|
794
|
+
input: process.stdin,
|
|
795
|
+
output: process.stdout
|
|
796
|
+
});
|
|
797
|
+
const hint = defaultValue ? "(Y/n)" : "(y/N)";
|
|
798
|
+
rl.question(`${chalk3.cyan("?")} ${question} ${hint}: `, (answer) => {
|
|
799
|
+
rl.close();
|
|
800
|
+
if (answer.trim() === "") {
|
|
801
|
+
resolve(defaultValue);
|
|
802
|
+
} else {
|
|
803
|
+
resolve(answer.toLowerCase().startsWith("y"));
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
function promptChoice(question, options) {
|
|
809
|
+
return new Promise((resolve) => {
|
|
810
|
+
console.log(`${chalk3.cyan("?")} ${question}`);
|
|
811
|
+
for (const opt of options) {
|
|
812
|
+
console.log(` ${chalk3.dim(opt.key)}) ${opt.label}`);
|
|
813
|
+
}
|
|
814
|
+
const rl = readline.createInterface({
|
|
815
|
+
input: process.stdin,
|
|
816
|
+
output: process.stdout
|
|
817
|
+
});
|
|
818
|
+
rl.question(` ${chalk3.dim("Enter choice")}: `, (answer) => {
|
|
819
|
+
rl.close();
|
|
820
|
+
resolve(answer.trim() || "1");
|
|
821
|
+
});
|
|
822
|
+
});
|
|
823
|
+
}
|
|
809
824
|
|
|
810
825
|
// src/cli/credits.ts
|
|
811
|
-
import
|
|
812
|
-
import
|
|
826
|
+
import chalk4 from "chalk";
|
|
827
|
+
import ora from "ora";
|
|
813
828
|
import open from "open";
|
|
814
829
|
import { createClient } from "@supabase/supabase-js";
|
|
815
830
|
function getSupabaseClient(accessToken) {
|
|
@@ -818,7 +833,7 @@ function getSupabaseClient(accessToken) {
|
|
|
818
833
|
});
|
|
819
834
|
}
|
|
820
835
|
async function showCredits() {
|
|
821
|
-
const spinner =
|
|
836
|
+
const spinner = ora("Fetching credit balance...").start();
|
|
822
837
|
try {
|
|
823
838
|
const config = await loadConfig();
|
|
824
839
|
if (!config.accessToken || !config.userId) {
|
|
@@ -834,21 +849,21 @@ async function showCredits() {
|
|
|
834
849
|
const profile = data;
|
|
835
850
|
spinner.stop();
|
|
836
851
|
console.log();
|
|
837
|
-
console.log(
|
|
852
|
+
console.log(chalk4.bold("\u{1F4B0} Credit Balance"));
|
|
838
853
|
console.log();
|
|
839
854
|
const balance = (profile.credit_balance_cents || 0) / 100;
|
|
840
855
|
console.log(` Tier: ${formatTier(profile.tier)}`);
|
|
841
|
-
console.log(` Balance: ${
|
|
856
|
+
console.log(` Balance: ${chalk4.green(`$${balance.toFixed(2)}`)}`);
|
|
842
857
|
if (profile.tier === "FREE") {
|
|
843
858
|
console.log(` Atoms: ${profile.atoms_used_this_month}/10,000 this month`);
|
|
844
859
|
console.log();
|
|
845
|
-
console.log(
|
|
860
|
+
console.log(chalk4.dim(" Upgrade to Credits tier: archon credits add"));
|
|
846
861
|
} else if (profile.tier === "CREDITS") {
|
|
847
862
|
console.log();
|
|
848
|
-
console.log(
|
|
863
|
+
console.log(chalk4.dim(" Add more credits: archon credits add"));
|
|
849
864
|
} else if (profile.tier === "BYOK") {
|
|
850
865
|
console.log();
|
|
851
|
-
console.log(
|
|
866
|
+
console.log(chalk4.dim(" Using your own API keys - no credit charges"));
|
|
852
867
|
}
|
|
853
868
|
console.log();
|
|
854
869
|
} catch (err) {
|
|
@@ -857,7 +872,7 @@ async function showCredits() {
|
|
|
857
872
|
}
|
|
858
873
|
}
|
|
859
874
|
async function addCredits(options = {}) {
|
|
860
|
-
const spinner =
|
|
875
|
+
const spinner = ora("Preparing checkout...").start();
|
|
861
876
|
try {
|
|
862
877
|
const config = await loadConfig();
|
|
863
878
|
if (!config.accessToken || !config.userId) {
|
|
@@ -894,18 +909,18 @@ async function addCredits(options = {}) {
|
|
|
894
909
|
}
|
|
895
910
|
spinner.succeed("Checkout ready");
|
|
896
911
|
console.log();
|
|
897
|
-
console.log(
|
|
912
|
+
console.log(chalk4.bold("\u{1F6D2} Add Credits"));
|
|
898
913
|
console.log();
|
|
899
|
-
console.log(` Amount: ${
|
|
914
|
+
console.log(` Amount: ${chalk4.green(`$${amountDollars.toFixed(2)}`)}`);
|
|
900
915
|
console.log();
|
|
901
916
|
console.log(" Opening checkout in browser...");
|
|
902
917
|
console.log();
|
|
903
|
-
console.log(
|
|
918
|
+
console.log(chalk4.dim(` Or visit: ${checkoutUrl}`));
|
|
904
919
|
console.log();
|
|
905
920
|
try {
|
|
906
921
|
await open(checkoutUrl);
|
|
907
922
|
} catch {
|
|
908
|
-
console.log(
|
|
923
|
+
console.log(chalk4.yellow(" Could not open browser. Please visit the URL above."));
|
|
909
924
|
}
|
|
910
925
|
} catch (err) {
|
|
911
926
|
spinner.fail("Error preparing checkout");
|
|
@@ -913,7 +928,7 @@ async function addCredits(options = {}) {
|
|
|
913
928
|
}
|
|
914
929
|
}
|
|
915
930
|
async function showHistory(options = {}) {
|
|
916
|
-
const spinner =
|
|
931
|
+
const spinner = ora("Fetching usage history...").start();
|
|
917
932
|
try {
|
|
918
933
|
const config = await loadConfig();
|
|
919
934
|
if (!config.accessToken || !config.userId) {
|
|
@@ -930,15 +945,15 @@ async function showHistory(options = {}) {
|
|
|
930
945
|
const usage = data;
|
|
931
946
|
spinner.stop();
|
|
932
947
|
console.log();
|
|
933
|
-
console.log(
|
|
948
|
+
console.log(chalk4.bold("\u{1F4CA} Usage History"));
|
|
934
949
|
console.log();
|
|
935
950
|
if (!usage || usage.length === 0) {
|
|
936
|
-
console.log(
|
|
951
|
+
console.log(chalk4.dim(" No usage recorded yet."));
|
|
937
952
|
console.log();
|
|
938
953
|
return;
|
|
939
954
|
}
|
|
940
|
-
console.log(
|
|
941
|
-
console.log(
|
|
955
|
+
console.log(chalk4.dim(" Model Tokens Cost Date"));
|
|
956
|
+
console.log(chalk4.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
942
957
|
for (const row of usage) {
|
|
943
958
|
const model = row.model.padEnd(30).slice(0, 30);
|
|
944
959
|
const tokens = (row.input_tokens + row.output_tokens).toString().padStart(8);
|
|
@@ -948,9 +963,9 @@ async function showHistory(options = {}) {
|
|
|
948
963
|
}
|
|
949
964
|
const totalCost = usage.reduce((sum, r) => sum + r.base_cost, 0);
|
|
950
965
|
const totalTokens = usage.reduce((sum, r) => sum + r.input_tokens + r.output_tokens, 0);
|
|
951
|
-
console.log(
|
|
966
|
+
console.log(chalk4.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
952
967
|
console.log(
|
|
953
|
-
` ${"Total".padEnd(30)} ${totalTokens.toString().padStart(8)} ${
|
|
968
|
+
` ${"Total".padEnd(30)} ${totalTokens.toString().padStart(8)} ${chalk4.green(`$${totalCost.toFixed(4)}`.padStart(10))}`
|
|
954
969
|
);
|
|
955
970
|
console.log();
|
|
956
971
|
} catch (err) {
|
|
@@ -959,7 +974,7 @@ async function showHistory(options = {}) {
|
|
|
959
974
|
}
|
|
960
975
|
}
|
|
961
976
|
async function manageBudget(options = {}) {
|
|
962
|
-
const spinner =
|
|
977
|
+
const spinner = ora("Fetching budget settings...").start();
|
|
963
978
|
try {
|
|
964
979
|
const config = await loadConfig();
|
|
965
980
|
if (!config.accessToken || !config.userId) {
|
|
@@ -1016,24 +1031,24 @@ async function manageBudget(options = {}) {
|
|
|
1016
1031
|
}
|
|
1017
1032
|
spinner.stop();
|
|
1018
1033
|
console.log();
|
|
1019
|
-
console.log(
|
|
1034
|
+
console.log(chalk4.bold("\u{1F4CA} Monthly Budget"));
|
|
1020
1035
|
console.log();
|
|
1021
1036
|
if (profile.monthly_budget_cents === null) {
|
|
1022
|
-
console.log(` Budget: ${
|
|
1037
|
+
console.log(` Budget: ${chalk4.dim("No limit set")}`);
|
|
1023
1038
|
} else {
|
|
1024
1039
|
const budget = profile.monthly_budget_cents / 100;
|
|
1025
1040
|
const spend = (profile.monthly_spend_cents || 0) / 100;
|
|
1026
1041
|
const remaining = budget - spend;
|
|
1027
1042
|
const percent = budget > 0 ? Math.round(spend / budget * 100) : 0;
|
|
1028
|
-
console.log(` Budget: ${
|
|
1043
|
+
console.log(` Budget: ${chalk4.green(`$${budget.toFixed(2)}`)} / month`);
|
|
1029
1044
|
console.log(` Spent: $${spend.toFixed(2)} (${percent}%)`);
|
|
1030
|
-
console.log(` Remaining: ${remaining >= 0 ?
|
|
1045
|
+
console.log(` Remaining: ${remaining >= 0 ? chalk4.green(`$${remaining.toFixed(2)}`) : chalk4.red(`-$${Math.abs(remaining).toFixed(2)}`)}`);
|
|
1031
1046
|
}
|
|
1032
1047
|
console.log(` Alert at: ${profile.budget_alert_threshold_percent}% of budget`);
|
|
1033
1048
|
console.log();
|
|
1034
|
-
console.log(
|
|
1035
|
-
console.log(
|
|
1036
|
-
console.log(
|
|
1049
|
+
console.log(chalk4.dim(" Set budget: archon credits budget --set 50"));
|
|
1050
|
+
console.log(chalk4.dim(" Clear budget: archon credits budget --clear"));
|
|
1051
|
+
console.log(chalk4.dim(" Set alert: archon credits budget --alert 80"));
|
|
1037
1052
|
console.log();
|
|
1038
1053
|
} catch (err) {
|
|
1039
1054
|
spinner.fail("Error managing budget");
|
|
@@ -1041,7 +1056,7 @@ async function manageBudget(options = {}) {
|
|
|
1041
1056
|
}
|
|
1042
1057
|
}
|
|
1043
1058
|
async function manageAutoRecharge(options = {}) {
|
|
1044
|
-
const spinner =
|
|
1059
|
+
const spinner = ora("Fetching auto-recharge settings...").start();
|
|
1045
1060
|
try {
|
|
1046
1061
|
const config = await loadConfig();
|
|
1047
1062
|
if (!config.accessToken || !config.userId) {
|
|
@@ -1095,12 +1110,12 @@ async function manageAutoRecharge(options = {}) {
|
|
|
1095
1110
|
}
|
|
1096
1111
|
spinner.stop();
|
|
1097
1112
|
console.log();
|
|
1098
|
-
console.log(
|
|
1113
|
+
console.log(chalk4.bold("\u{1F504} Auto-Recharge"));
|
|
1099
1114
|
console.log();
|
|
1100
1115
|
if (!profile.auto_recharge_enabled) {
|
|
1101
|
-
console.log(` Status: ${
|
|
1116
|
+
console.log(` Status: ${chalk4.dim("Disabled")}`);
|
|
1102
1117
|
} else {
|
|
1103
|
-
console.log(` Status: ${
|
|
1118
|
+
console.log(` Status: ${chalk4.green("Enabled")}`);
|
|
1104
1119
|
if (profile.auto_recharge_threshold_cents !== null) {
|
|
1105
1120
|
console.log(` When: Balance drops below $${(profile.auto_recharge_threshold_cents / 100).toFixed(2)}`);
|
|
1106
1121
|
}
|
|
@@ -1108,10 +1123,10 @@ async function manageAutoRecharge(options = {}) {
|
|
|
1108
1123
|
console.log(` Amount: $${(profile.auto_recharge_amount_cents / 100).toFixed(2)}`);
|
|
1109
1124
|
}
|
|
1110
1125
|
}
|
|
1111
|
-
console.log(` Payment: ${profile.stripe_payment_method_id ?
|
|
1126
|
+
console.log(` Payment: ${profile.stripe_payment_method_id ? chalk4.green("Card saved") : chalk4.dim("No card saved")}`);
|
|
1112
1127
|
console.log();
|
|
1113
|
-
console.log(
|
|
1114
|
-
console.log(
|
|
1128
|
+
console.log(chalk4.dim(" Enable: archon credits auto-recharge --enable --threshold 5 --amount 20"));
|
|
1129
|
+
console.log(chalk4.dim(" Disable: archon credits auto-recharge --disable"));
|
|
1115
1130
|
console.log();
|
|
1116
1131
|
} catch (err) {
|
|
1117
1132
|
spinner.fail("Error managing auto-recharge");
|
|
@@ -1121,11 +1136,11 @@ async function manageAutoRecharge(options = {}) {
|
|
|
1121
1136
|
function formatTier(tier) {
|
|
1122
1137
|
switch (tier) {
|
|
1123
1138
|
case "FREE":
|
|
1124
|
-
return
|
|
1139
|
+
return chalk4.blue("Free (10k atoms/month)");
|
|
1125
1140
|
case "CREDITS":
|
|
1126
|
-
return
|
|
1141
|
+
return chalk4.green("Credits (Pay-as-you-go)");
|
|
1127
1142
|
case "BYOK":
|
|
1128
|
-
return
|
|
1143
|
+
return chalk4.magenta("BYOK (Bring Your Own Key)");
|
|
1129
1144
|
default:
|
|
1130
1145
|
return tier;
|
|
1131
1146
|
}
|
|
@@ -1402,9 +1417,9 @@ async function watch() {
|
|
|
1402
1417
|
|
|
1403
1418
|
// src/cli/deps.ts
|
|
1404
1419
|
import { Command } from "commander";
|
|
1405
|
-
import
|
|
1406
|
-
import { readFile as
|
|
1407
|
-
import { existsSync as
|
|
1420
|
+
import chalk5 from "chalk";
|
|
1421
|
+
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
1422
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1408
1423
|
var DEPENDENCIES_FILENAME = "DEPENDENCIES.md";
|
|
1409
1424
|
function createDepsCommand() {
|
|
1410
1425
|
const deps = new Command("deps").description("Manage file-level dependencies (DEPENDENCIES.md)").addHelpText(
|
|
@@ -1420,30 +1435,30 @@ Examples:
|
|
|
1420
1435
|
deps.command("list").description("List all dependency rules").option("-v, --verbose", "Show detailed information").action(async (options) => {
|
|
1421
1436
|
const parser = new DependencyParser();
|
|
1422
1437
|
if (!parser.exists()) {
|
|
1423
|
-
console.log(
|
|
1424
|
-
console.log(
|
|
1438
|
+
console.log(chalk5.yellow("No DEPENDENCIES.md found."));
|
|
1439
|
+
console.log(chalk5.dim("Create one with: archon deps add --source <path> --dependent <path>"));
|
|
1425
1440
|
return;
|
|
1426
1441
|
}
|
|
1427
1442
|
const result = await parser.parse();
|
|
1428
1443
|
if (!result.success) {
|
|
1429
|
-
console.log(
|
|
1444
|
+
console.log(chalk5.red(`Parse error: ${result.error}`));
|
|
1430
1445
|
return;
|
|
1431
1446
|
}
|
|
1432
1447
|
const rules = result.document?.rules ?? [];
|
|
1433
1448
|
if (rules.length === 0) {
|
|
1434
|
-
console.log(
|
|
1449
|
+
console.log(chalk5.dim("No dependency rules defined."));
|
|
1435
1450
|
return;
|
|
1436
1451
|
}
|
|
1437
|
-
console.log(
|
|
1452
|
+
console.log(chalk5.bold(`
|
|
1438
1453
|
\u{1F4E6} Dependency Rules (${rules.length})
|
|
1439
1454
|
`));
|
|
1440
1455
|
for (const rule of rules) {
|
|
1441
|
-
const severityColor = rule.severity === "BLOCKER" ?
|
|
1442
|
-
console.log(`${severityColor(`[${rule.severity}]`)} ${
|
|
1443
|
-
console.log(` Source: ${
|
|
1444
|
-
console.log(` Dependents: ${rule.dependents.map((d) =>
|
|
1456
|
+
const severityColor = rule.severity === "BLOCKER" ? chalk5.red : rule.severity === "WARNING" ? chalk5.yellow : chalk5.blue;
|
|
1457
|
+
console.log(`${severityColor(`[${rule.severity}]`)} ${chalk5.bold(rule.id)}`);
|
|
1458
|
+
console.log(` Source: ${chalk5.cyan(rule.source)}`);
|
|
1459
|
+
console.log(` Dependents: ${rule.dependents.map((d) => chalk5.dim(d)).join(", ")}`);
|
|
1445
1460
|
if (rule.reason && options.verbose) {
|
|
1446
|
-
console.log(` Reason: ${
|
|
1461
|
+
console.log(` Reason: ${chalk5.dim(rule.reason)}`);
|
|
1447
1462
|
}
|
|
1448
1463
|
if (rule.mustTest && options.verbose) {
|
|
1449
1464
|
console.log(` Must test: ${rule.mustTest.join(", ")}`);
|
|
@@ -1455,29 +1470,29 @@ Examples:
|
|
|
1455
1470
|
const files = options.files.split(",").map((f) => f.trim());
|
|
1456
1471
|
const parser = new DependencyParser();
|
|
1457
1472
|
if (!parser.exists()) {
|
|
1458
|
-
console.log(
|
|
1473
|
+
console.log(chalk5.dim("No DEPENDENCIES.md found. No dependency checks performed."));
|
|
1459
1474
|
process.exit(0);
|
|
1460
1475
|
}
|
|
1461
1476
|
const result = await parser.checkFiles(files);
|
|
1462
1477
|
if (result.impacts.length === 0) {
|
|
1463
|
-
console.log(
|
|
1478
|
+
console.log(chalk5.green("\u2705 No downstream dependency impacts found."));
|
|
1464
1479
|
process.exit(0);
|
|
1465
1480
|
}
|
|
1466
|
-
console.log(
|
|
1481
|
+
console.log(chalk5.yellow(`
|
|
1467
1482
|
\u26A0\uFE0F Found ${result.impacts.length} dependency impact(s):
|
|
1468
1483
|
`));
|
|
1469
1484
|
for (const impact of result.impacts) {
|
|
1470
|
-
const severityColor = impact.rule.severity === "BLOCKER" ?
|
|
1485
|
+
const severityColor = impact.rule.severity === "BLOCKER" ? chalk5.red : impact.rule.severity === "WARNING" ? chalk5.yellow : chalk5.blue;
|
|
1471
1486
|
console.log(severityColor(`[${impact.rule.severity}] ${impact.rule.id}`));
|
|
1472
|
-
console.log(` Changing: ${
|
|
1487
|
+
console.log(` Changing: ${chalk5.cyan(impact.matchedSource)}`);
|
|
1473
1488
|
console.log(` May impact: ${impact.affectedDependents.join(", ")}`);
|
|
1474
1489
|
if (impact.rule.reason) {
|
|
1475
|
-
console.log(` Reason: ${
|
|
1490
|
+
console.log(` Reason: ${chalk5.dim(impact.rule.reason)}`);
|
|
1476
1491
|
}
|
|
1477
1492
|
console.log("");
|
|
1478
1493
|
}
|
|
1479
1494
|
if (result.hasBlockers) {
|
|
1480
|
-
console.log(
|
|
1495
|
+
console.log(chalk5.red("\u274C BLOCKER-level impacts found. Review before proceeding."));
|
|
1481
1496
|
process.exit(1);
|
|
1482
1497
|
}
|
|
1483
1498
|
process.exit(0);
|
|
@@ -1491,7 +1506,7 @@ Examples:
|
|
|
1491
1506
|
let existingRules = [];
|
|
1492
1507
|
let markdownBody = "";
|
|
1493
1508
|
if (parser.exists()) {
|
|
1494
|
-
const content = await
|
|
1509
|
+
const content = await readFile2(DEPENDENCIES_FILENAME, "utf-8");
|
|
1495
1510
|
const result = await parser.parse();
|
|
1496
1511
|
if (result.success && result.document) {
|
|
1497
1512
|
existingRules = result.document.rules;
|
|
@@ -1519,7 +1534,7 @@ Examples:
|
|
|
1519
1534
|
(r) => r.source === source && r.dependents.includes(dependent)
|
|
1520
1535
|
);
|
|
1521
1536
|
if (existingRule) {
|
|
1522
|
-
console.log(
|
|
1537
|
+
console.log(chalk5.yellow(`Rule already exists: ${existingRule.id}`));
|
|
1523
1538
|
return;
|
|
1524
1539
|
}
|
|
1525
1540
|
const newRule = {
|
|
@@ -1531,22 +1546,22 @@ Examples:
|
|
|
1531
1546
|
};
|
|
1532
1547
|
existingRules.push(newRule);
|
|
1533
1548
|
const yaml = generateYamlFrontmatter(existingRules);
|
|
1534
|
-
await
|
|
1549
|
+
await writeFile2(DEPENDENCIES_FILENAME, `---
|
|
1535
1550
|
${yaml}---${markdownBody}`, "utf-8");
|
|
1536
|
-
console.log(
|
|
1537
|
-
console.log(` Source: ${
|
|
1538
|
-
console.log(` Dependent: ${
|
|
1551
|
+
console.log(chalk5.green(`\u2705 Added dependency rule: ${nextId}`));
|
|
1552
|
+
console.log(` Source: ${chalk5.cyan(source)}`);
|
|
1553
|
+
console.log(` Dependent: ${chalk5.dim(dependent)}`);
|
|
1539
1554
|
});
|
|
1540
1555
|
deps.command("graph").description("Generate Mermaid diagram of dependencies").option("--output <file>", "Write to file instead of stdout").action(async (options) => {
|
|
1541
1556
|
const parser = new DependencyParser();
|
|
1542
1557
|
if (!parser.exists()) {
|
|
1543
|
-
console.log(
|
|
1558
|
+
console.log(chalk5.yellow("No DEPENDENCIES.md found."));
|
|
1544
1559
|
return;
|
|
1545
1560
|
}
|
|
1546
1561
|
const mermaid = await parser.generateGraph();
|
|
1547
1562
|
if (options.output) {
|
|
1548
|
-
await
|
|
1549
|
-
console.log(
|
|
1563
|
+
await writeFile2(options.output, mermaid, "utf-8");
|
|
1564
|
+
console.log(chalk5.green(`\u2705 Graph written to ${options.output}`));
|
|
1550
1565
|
} else {
|
|
1551
1566
|
console.log("\n```mermaid");
|
|
1552
1567
|
console.log(mermaid);
|
|
@@ -1554,8 +1569,8 @@ ${yaml}---${markdownBody}`, "utf-8");
|
|
|
1554
1569
|
}
|
|
1555
1570
|
});
|
|
1556
1571
|
deps.command("init").description("Create a starter DEPENDENCIES.md file").action(async () => {
|
|
1557
|
-
if (
|
|
1558
|
-
console.log(
|
|
1572
|
+
if (existsSync4(DEPENDENCIES_FILENAME)) {
|
|
1573
|
+
console.log(chalk5.yellow("DEPENDENCIES.md already exists."));
|
|
1559
1574
|
return;
|
|
1560
1575
|
}
|
|
1561
1576
|
const template = `---
|
|
@@ -1601,9 +1616,9 @@ rules:
|
|
|
1601
1616
|
|
|
1602
1617
|
*Powered by [ArchonDev](https://archondev.io)*
|
|
1603
1618
|
`;
|
|
1604
|
-
await
|
|
1605
|
-
console.log(
|
|
1606
|
-
console.log(
|
|
1619
|
+
await writeFile2(DEPENDENCIES_FILENAME, template, "utf-8");
|
|
1620
|
+
console.log(chalk5.green("\u2705 Created DEPENDENCIES.md"));
|
|
1621
|
+
console.log(chalk5.dim("Add your first rule with: archon deps add --source <path> --dependent <path>"));
|
|
1607
1622
|
});
|
|
1608
1623
|
return deps;
|
|
1609
1624
|
}
|
|
@@ -1644,7 +1659,7 @@ var program = new Command2();
|
|
|
1644
1659
|
program.name("archon").description("Local-first AI-powered development governance").version("1.1.0").action(async () => {
|
|
1645
1660
|
const cwd = process.cwd();
|
|
1646
1661
|
if (!isInitialized(cwd)) {
|
|
1647
|
-
console.log(
|
|
1662
|
+
console.log(chalk6.blue("\nArchonDev is not initialized in this folder.\n"));
|
|
1648
1663
|
await init({ analyze: true, git: true });
|
|
1649
1664
|
}
|
|
1650
1665
|
await start();
|
|
@@ -1652,7 +1667,7 @@ program.name("archon").description("Local-first AI-powered development governanc
|
|
|
1652
1667
|
program.command("login").description("Authenticate with ArchonDev").option("-p, --provider <provider>", "OAuth provider (github or google)", "github").action(async (options) => {
|
|
1653
1668
|
const provider = options.provider;
|
|
1654
1669
|
if (provider !== "github" && provider !== "google") {
|
|
1655
|
-
console.error(
|
|
1670
|
+
console.error(chalk6.red('Invalid provider. Use "github" or "google"'));
|
|
1656
1671
|
process.exit(1);
|
|
1657
1672
|
}
|
|
1658
1673
|
await login(provider);
|