archondev 1.5.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- 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/README.md
CHANGED
|
@@ -39,6 +39,7 @@ Copy governance files into any project. Works with your existing AI tools (Curso
|
|
|
39
39
|
- **Code Review Mode** — Structured code review without changing your code
|
|
40
40
|
- **Local Database** — Track atoms and learnings in SQLite (no CLI required)
|
|
41
41
|
- **Memory Management** — Context handoff protocol for long sessions
|
|
42
|
+
- **Task Extraction Protocol** — AI confirms all items before starting, nothing gets forgotten
|
|
42
43
|
- Works with any AI coding assistant
|
|
43
44
|
|
|
44
45
|
---
|
|
@@ -50,6 +51,7 @@ Copy governance files into any project. Works with your existing AI tools (Curso
|
|
|
50
51
|
| `archon` | Interactive mode — just run and follow prompts |
|
|
51
52
|
| `archon init` | Initialize in your project |
|
|
52
53
|
| `archon plan <description>` | Create a work item with AI planning |
|
|
54
|
+
| `archon plan` | Create a work item with AI planning (extracts and confirms multi-item requests) |
|
|
53
55
|
| `archon execute <atom-id>` | Execute with quality gates |
|
|
54
56
|
| `archon list` | List all work items |
|
|
55
57
|
| `archon show <atom-id>` | Show details |
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
// src/cli/init.ts
|
|
2
|
+
import { readdir, readFile, writeFile, mkdir } from "fs/promises";
|
|
3
|
+
import { existsSync } from "fs";
|
|
4
|
+
import { join, extname } from "path";
|
|
5
|
+
import { execSync } from "child_process";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import ora from "ora";
|
|
8
|
+
import readline from "readline";
|
|
9
|
+
function isInitialized(cwd) {
|
|
10
|
+
const archMdPath = join(cwd, "ARCHITECTURE.md");
|
|
11
|
+
const archonDir = join(cwd, ".archon");
|
|
12
|
+
return existsSync(archMdPath) || existsSync(archonDir);
|
|
13
|
+
}
|
|
14
|
+
var LANGUAGE_EXTENSIONS = {
|
|
15
|
+
".ts": "TypeScript",
|
|
16
|
+
".tsx": "TypeScript",
|
|
17
|
+
".js": "JavaScript",
|
|
18
|
+
".jsx": "JavaScript",
|
|
19
|
+
".py": "Python",
|
|
20
|
+
".go": "Go",
|
|
21
|
+
".rs": "Rust",
|
|
22
|
+
".java": "Java",
|
|
23
|
+
".rb": "Ruby",
|
|
24
|
+
".php": "PHP",
|
|
25
|
+
".cs": "C#",
|
|
26
|
+
".cpp": "C++",
|
|
27
|
+
".c": "C",
|
|
28
|
+
".swift": "Swift",
|
|
29
|
+
".kt": "Kotlin",
|
|
30
|
+
".vue": "Vue",
|
|
31
|
+
".svelte": "Svelte"
|
|
32
|
+
};
|
|
33
|
+
var IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
34
|
+
"node_modules",
|
|
35
|
+
".git",
|
|
36
|
+
"dist",
|
|
37
|
+
"build",
|
|
38
|
+
".next",
|
|
39
|
+
"coverage",
|
|
40
|
+
"__pycache__",
|
|
41
|
+
".venv",
|
|
42
|
+
"venv",
|
|
43
|
+
"target",
|
|
44
|
+
"vendor",
|
|
45
|
+
".archon"
|
|
46
|
+
]);
|
|
47
|
+
async function init(options = {}) {
|
|
48
|
+
const cwd = process.cwd();
|
|
49
|
+
const archMdPath = join(cwd, "ARCHITECTURE.md");
|
|
50
|
+
const archonDir = join(cwd, ".archon");
|
|
51
|
+
console.log(chalk.blue("\n\u{1F3DB}\uFE0F ArchonDev Initialization\n"));
|
|
52
|
+
if (existsSync(archMdPath)) {
|
|
53
|
+
const overwrite = await promptYesNo("ARCHITECTURE.md already exists. Overwrite?", false);
|
|
54
|
+
if (!overwrite) {
|
|
55
|
+
console.log(chalk.yellow("Initialization cancelled."));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const spinner = ora("Detecting project capabilities...").start();
|
|
60
|
+
const capabilities = await detectCapabilities(cwd);
|
|
61
|
+
spinner.succeed("Project capabilities detected");
|
|
62
|
+
spinner.start("Scanning codebase...");
|
|
63
|
+
const stats = await scanRepository(cwd);
|
|
64
|
+
spinner.succeed(`Scanned ${stats.totalFiles} files (${formatLines(stats.totalLines)} lines)`);
|
|
65
|
+
if (options.git !== false && !capabilities.hasGit) {
|
|
66
|
+
spinner.start("Initializing git repository...");
|
|
67
|
+
try {
|
|
68
|
+
execSync("git init", { cwd, stdio: "pipe" });
|
|
69
|
+
spinner.succeed("Git repository initialized");
|
|
70
|
+
} catch {
|
|
71
|
+
spinner.warn("Could not initialize git");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (!existsSync(archonDir)) {
|
|
75
|
+
await mkdir(archonDir, { recursive: true });
|
|
76
|
+
}
|
|
77
|
+
spinner.start("Generating ARCHITECTURE.md...");
|
|
78
|
+
const archContent = generateArchitectureMd(capabilities, stats, options.analyze);
|
|
79
|
+
await writeFile(archMdPath, archContent);
|
|
80
|
+
spinner.succeed("ARCHITECTURE.md created");
|
|
81
|
+
printSummary(capabilities, stats, options.analyze);
|
|
82
|
+
}
|
|
83
|
+
function promptYesNo(question, defaultValue) {
|
|
84
|
+
return new Promise((resolve) => {
|
|
85
|
+
const rl = readline.createInterface({
|
|
86
|
+
input: process.stdin,
|
|
87
|
+
output: process.stdout
|
|
88
|
+
});
|
|
89
|
+
const hint = defaultValue ? "(Y/n)" : "(y/N)";
|
|
90
|
+
rl.question(`${question} ${hint} `, (answer) => {
|
|
91
|
+
rl.close();
|
|
92
|
+
if (answer.trim() === "") {
|
|
93
|
+
resolve(defaultValue);
|
|
94
|
+
} else {
|
|
95
|
+
resolve(answer.toLowerCase().startsWith("y"));
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
async function detectCapabilities(cwd) {
|
|
101
|
+
const hasFile = (name) => existsSync(join(cwd, name));
|
|
102
|
+
const hasJsonDep = async (name) => {
|
|
103
|
+
try {
|
|
104
|
+
const pkg = JSON.parse(await readFile(join(cwd, "package.json"), "utf-8"));
|
|
105
|
+
return !!(pkg.dependencies?.[name] || pkg.devDependencies?.[name]);
|
|
106
|
+
} catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
let packageManager = null;
|
|
111
|
+
if (hasFile("pnpm-lock.yaml")) packageManager = "pnpm";
|
|
112
|
+
else if (hasFile("yarn.lock")) packageManager = "yarn";
|
|
113
|
+
else if (hasFile("bun.lockb")) packageManager = "bun";
|
|
114
|
+
else if (hasFile("package-lock.json")) packageManager = "npm";
|
|
115
|
+
const hasTypeScript = hasFile("tsconfig.json") || await hasJsonDep("typescript");
|
|
116
|
+
const hasESLint = hasFile(".eslintrc") || hasFile(".eslintrc.js") || hasFile("eslint.config.js") || await hasJsonDep("eslint");
|
|
117
|
+
const hasJest = hasFile("jest.config.js") || hasFile("jest.config.ts") || await hasJsonDep("jest") || await hasJsonDep("vitest");
|
|
118
|
+
const hasPrettier = hasFile(".prettierrc") || hasFile(".prettierrc.js") || await hasJsonDep("prettier");
|
|
119
|
+
const hasGit = hasFile(".git");
|
|
120
|
+
return {
|
|
121
|
+
hasTypeScript,
|
|
122
|
+
hasESLint,
|
|
123
|
+
hasJest,
|
|
124
|
+
hasPrettier,
|
|
125
|
+
hasGit,
|
|
126
|
+
packageManager,
|
|
127
|
+
primaryLanguage: hasTypeScript ? "TypeScript" : "JavaScript"
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
async function scanRepository(cwd) {
|
|
131
|
+
const stats = {
|
|
132
|
+
totalFiles: 0,
|
|
133
|
+
totalLines: 0,
|
|
134
|
+
languageBreakdown: {},
|
|
135
|
+
directories: []
|
|
136
|
+
};
|
|
137
|
+
async function scanDir(dir, depth = 0) {
|
|
138
|
+
if (depth > 10) return;
|
|
139
|
+
try {
|
|
140
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
141
|
+
for (const entry of entries) {
|
|
142
|
+
if (IGNORE_DIRS.has(entry.name)) continue;
|
|
143
|
+
if (entry.name.startsWith(".") && entry.name !== ".github") continue;
|
|
144
|
+
const fullPath = join(dir, entry.name);
|
|
145
|
+
if (entry.isDirectory()) {
|
|
146
|
+
if (depth < 2) {
|
|
147
|
+
const relativePath = fullPath.replace(cwd, "").replace(/^\//, "");
|
|
148
|
+
if (relativePath) {
|
|
149
|
+
stats.directories.push(relativePath);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
await scanDir(fullPath, depth + 1);
|
|
153
|
+
} else if (entry.isFile()) {
|
|
154
|
+
const ext = extname(entry.name).toLowerCase();
|
|
155
|
+
const language = LANGUAGE_EXTENSIONS[ext];
|
|
156
|
+
if (language) {
|
|
157
|
+
stats.totalFiles++;
|
|
158
|
+
try {
|
|
159
|
+
const content = await readFile(fullPath, "utf-8");
|
|
160
|
+
const lines = content.split("\n").length;
|
|
161
|
+
stats.totalLines += lines;
|
|
162
|
+
if (!stats.languageBreakdown[language]) {
|
|
163
|
+
stats.languageBreakdown[language] = { files: 0, lines: 0 };
|
|
164
|
+
}
|
|
165
|
+
stats.languageBreakdown[language].files++;
|
|
166
|
+
stats.languageBreakdown[language].lines += lines;
|
|
167
|
+
} catch {
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
await scanDir(cwd);
|
|
176
|
+
return stats;
|
|
177
|
+
}
|
|
178
|
+
function generateArchitectureMd(capabilities, stats, analyze) {
|
|
179
|
+
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
180
|
+
const suggestedComponents = stats.directories.filter((d) => !d.includes("/")).slice(0, 10).map((dir) => ({
|
|
181
|
+
id: dir.replace(/[^a-zA-Z0-9]/g, "-"),
|
|
182
|
+
name: dir.charAt(0).toUpperCase() + dir.slice(1),
|
|
183
|
+
path: `${dir}/**`
|
|
184
|
+
}));
|
|
185
|
+
const qualityGates = [];
|
|
186
|
+
if (capabilities.hasTypeScript) qualityGates.push("SYNTAX");
|
|
187
|
+
if (capabilities.hasESLint) qualityGates.push("LINT");
|
|
188
|
+
if (capabilities.hasJest) qualityGates.push("UNIT");
|
|
189
|
+
return `---
|
|
190
|
+
version: "1.0"
|
|
191
|
+
updatedAt: "${now}"
|
|
192
|
+
profile: "balanced"
|
|
193
|
+
strictMode: true
|
|
194
|
+
|
|
195
|
+
# System Goals
|
|
196
|
+
systemGoals:
|
|
197
|
+
- id: "GOAL-001"
|
|
198
|
+
title: "Maintain code quality"
|
|
199
|
+
description: "All changes must pass quality gates before merging"
|
|
200
|
+
priority: "HIGH"
|
|
201
|
+
|
|
202
|
+
- id: "GOAL-002"
|
|
203
|
+
title: "Preserve architectural boundaries"
|
|
204
|
+
description: "Components should not violate defined boundaries"
|
|
205
|
+
priority: "HIGH"
|
|
206
|
+
|
|
207
|
+
# Components & Boundaries
|
|
208
|
+
# Detected ${suggestedComponents.length} top-level directories
|
|
209
|
+
components:
|
|
210
|
+
${suggestedComponents.map((c) => ` - id: "${c.id}"
|
|
211
|
+
name: "${c.name}"
|
|
212
|
+
paths:
|
|
213
|
+
- "${c.path}"
|
|
214
|
+
boundary: "INTERNAL"
|
|
215
|
+
stability: "EVOLVING"`).join("\n\n")}
|
|
216
|
+
|
|
217
|
+
# Invariants (Rules to enforce)
|
|
218
|
+
invariants:
|
|
219
|
+
- id: "INV-001"
|
|
220
|
+
severity: "WARN"
|
|
221
|
+
rule: "Avoid console.log in production code"
|
|
222
|
+
match: "console\\\\.log"
|
|
223
|
+
scope: "src"
|
|
224
|
+
reason: "Use proper logging library instead"
|
|
225
|
+
|
|
226
|
+
# Protected Paths
|
|
227
|
+
protectedPaths:
|
|
228
|
+
- pattern: "package.json"
|
|
229
|
+
level: "SOFT"
|
|
230
|
+
reason: "Dependency changes should be reviewed"
|
|
231
|
+
|
|
232
|
+
${capabilities.hasTypeScript ? ` - pattern: "tsconfig.json"
|
|
233
|
+
level: "SOFT"
|
|
234
|
+
reason: "TypeScript config affects entire project"` : ""}
|
|
235
|
+
|
|
236
|
+
# Environment Configuration
|
|
237
|
+
environments:
|
|
238
|
+
development:
|
|
239
|
+
autoApprove: true
|
|
240
|
+
qualityGates:
|
|
241
|
+
- ARCHITECTURE
|
|
242
|
+
${qualityGates.map((g) => ` - ${g}`).join("\n")}
|
|
243
|
+
|
|
244
|
+
production:
|
|
245
|
+
autoApprove: false
|
|
246
|
+
requiresManualPromotion: true
|
|
247
|
+
qualityGates:
|
|
248
|
+
- ARCHITECTURE
|
|
249
|
+
${qualityGates.map((g) => ` - ${g}`).join("\n")}
|
|
250
|
+
- ACCEPTANCE
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
# Project Architecture
|
|
254
|
+
|
|
255
|
+
## Overview
|
|
256
|
+
|
|
257
|
+
This architecture document was auto-generated by ArchonDev on ${now}.
|
|
258
|
+
|
|
259
|
+
${analyze ? `## Codebase Analysis
|
|
260
|
+
|
|
261
|
+
- **Total Files:** ${stats.totalFiles}
|
|
262
|
+
- **Total Lines:** ${formatLines(stats.totalLines)}
|
|
263
|
+
- **Primary Language:** ${capabilities.primaryLanguage}
|
|
264
|
+
|
|
265
|
+
### Language Breakdown
|
|
266
|
+
|
|
267
|
+
${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")}
|
|
268
|
+
|
|
269
|
+
### Detected Capabilities
|
|
270
|
+
|
|
271
|
+
- TypeScript: ${capabilities.hasTypeScript ? "\u2705" : "\u274C"}
|
|
272
|
+
- ESLint: ${capabilities.hasESLint ? "\u2705" : "\u274C"}
|
|
273
|
+
- Testing: ${capabilities.hasJest ? "\u2705" : "\u274C"}
|
|
274
|
+
- Package Manager: ${capabilities.packageManager ?? "Not detected"}
|
|
275
|
+
` : ""}
|
|
276
|
+
## Components
|
|
277
|
+
|
|
278
|
+
${suggestedComponents.map((c) => `### ${c.name}
|
|
279
|
+
|
|
280
|
+
Path: \`${c.path}\`
|
|
281
|
+
|
|
282
|
+
TODO: Add description for this component.
|
|
283
|
+
`).join("\n")}
|
|
284
|
+
|
|
285
|
+
## Getting Started
|
|
286
|
+
|
|
287
|
+
1. Review and customize the components above
|
|
288
|
+
2. Add invariants for your specific rules
|
|
289
|
+
3. Define protected paths for sensitive files
|
|
290
|
+
4. Run \`archon plan <description>\` to create your first atom
|
|
291
|
+
|
|
292
|
+
## Architecture Decision Records
|
|
293
|
+
|
|
294
|
+
Document important architectural decisions here.
|
|
295
|
+
`;
|
|
296
|
+
}
|
|
297
|
+
function formatLines(n) {
|
|
298
|
+
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
299
|
+
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
300
|
+
return n.toString();
|
|
301
|
+
}
|
|
302
|
+
function printSummary(capabilities, stats, analyze) {
|
|
303
|
+
console.log();
|
|
304
|
+
console.log(chalk.green("\u2713 ArchonDev initialized successfully!"));
|
|
305
|
+
console.log();
|
|
306
|
+
console.log(chalk.bold("Detected Capabilities:"));
|
|
307
|
+
console.log(` ${capabilities.hasTypeScript ? chalk.green("\u2713") : chalk.gray("\u25CB")} TypeScript`);
|
|
308
|
+
console.log(` ${capabilities.hasESLint ? chalk.green("\u2713") : chalk.gray("\u25CB")} ESLint`);
|
|
309
|
+
console.log(` ${capabilities.hasJest ? chalk.green("\u2713") : chalk.gray("\u25CB")} Testing (Jest/Vitest)`);
|
|
310
|
+
console.log(` ${capabilities.packageManager ? chalk.green("\u2713") : chalk.gray("\u25CB")} Package Manager: ${capabilities.packageManager ?? "none"}`);
|
|
311
|
+
console.log();
|
|
312
|
+
console.log(chalk.bold("Codebase Summary:"));
|
|
313
|
+
console.log(` Files: ${stats.totalFiles}`);
|
|
314
|
+
console.log(` Lines: ${formatLines(stats.totalLines)}`);
|
|
315
|
+
console.log(` Directories: ${stats.directories.length}`);
|
|
316
|
+
console.log();
|
|
317
|
+
if (Object.keys(stats.languageBreakdown).length > 0) {
|
|
318
|
+
console.log(chalk.bold("Languages:"));
|
|
319
|
+
Object.entries(stats.languageBreakdown).sort((a, b) => b[1].lines - a[1].lines).slice(0, 5).forEach(([lang, data]) => {
|
|
320
|
+
const pct = Math.round(data.lines / stats.totalLines * 100);
|
|
321
|
+
console.log(` ${lang}: ${pct}%`);
|
|
322
|
+
});
|
|
323
|
+
console.log();
|
|
324
|
+
}
|
|
325
|
+
if (analyze && stats.directories.length > 0) {
|
|
326
|
+
console.log(chalk.bold("Suggested Boundaries:"));
|
|
327
|
+
stats.directories.filter((d) => !d.includes("/")).slice(0, 5).forEach((dir) => {
|
|
328
|
+
console.log(` \u2022 ${dir}/`);
|
|
329
|
+
});
|
|
330
|
+
console.log();
|
|
331
|
+
}
|
|
332
|
+
console.log(chalk.bold("Next Steps:"));
|
|
333
|
+
console.log(` 1. ${chalk.cyan("Review")} ARCHITECTURE.md and customize components`);
|
|
334
|
+
console.log(` 2. ${chalk.cyan("Run")} ${chalk.dim('archon plan "your first task"')} to create an atom`);
|
|
335
|
+
console.log(` 3. ${chalk.cyan("Execute")} ${chalk.dim("archon execute ATOM-001")} to implement it`);
|
|
336
|
+
console.log();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export {
|
|
340
|
+
isInitialized,
|
|
341
|
+
init
|
|
342
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
execute
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-S7UXMYWS.js";
|
|
4
|
+
import "./chunk-3AAQEUY6.js";
|
|
5
|
+
import "./chunk-SMR7JQK6.js";
|
|
5
6
|
import "./chunk-2CFO5GVH.js";
|
|
6
7
|
import "./chunk-MOZHC2GX.js";
|
|
7
8
|
import "./chunk-A7QU6JC6.js";
|
|
8
|
-
import "./chunk-SMR7JQK6.js";
|
|
9
9
|
import "./chunk-WCCBJSNI.js";
|
|
10
10
|
import "./chunk-QGM4M3NI.js";
|
|
11
11
|
export {
|