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