archondev 0.1.0 → 1.2.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.
@@ -0,0 +1,351 @@
1
+ import {
2
+ AnthropicClient,
3
+ generateId,
4
+ getDefaultModel
5
+ } from "./chunk-A7QU6JC6.js";
6
+
7
+ // src/core/atoms/types.ts
8
+ var ATOM_TRANSITIONS = {
9
+ DRAFT: ["READY"],
10
+ READY: ["IN_PROGRESS", "BLOCKED"],
11
+ IN_PROGRESS: ["TESTING", "FAILED"],
12
+ TESTING: ["DONE", "FAILED"],
13
+ DONE: [],
14
+ // Terminal state
15
+ FAILED: ["IN_PROGRESS", "BLOCKED"],
16
+ // Can retry or escalate
17
+ BLOCKED: ["READY"]
18
+ // Can unblock and retry
19
+ };
20
+ var MAX_RETRIES = 3;
21
+
22
+ // src/core/atoms/atoms.ts
23
+ var MAX_RETRIES2 = MAX_RETRIES;
24
+ var atomCounter = 0;
25
+ function generateAtomId() {
26
+ atomCounter++;
27
+ return `ATOM-${String(atomCounter).padStart(3, "0")}`;
28
+ }
29
+ function createAtom(input, context) {
30
+ const now = /* @__PURE__ */ new Date();
31
+ const externalId = generateAtomId();
32
+ return {
33
+ id: generateId("atom"),
34
+ externalId,
35
+ title: input.title,
36
+ description: input.description ?? null,
37
+ goals: input.goals ?? [],
38
+ acceptanceCriteria: input.acceptanceCriteria,
39
+ ownershipPaths: input.ownershipPaths ?? [],
40
+ status: "DRAFT",
41
+ priority: input.priority ?? 100,
42
+ plan: null,
43
+ diffContract: null,
44
+ retryCount: 0,
45
+ errorMessage: null,
46
+ tags: input.tags ?? [],
47
+ metadata: input.metadata ?? {},
48
+ context: context ?? {},
49
+ createdAt: now,
50
+ updatedAt: now
51
+ };
52
+ }
53
+ function validateAtom(atom) {
54
+ const errors = [];
55
+ if (!atom.title || atom.title.trim() === "") {
56
+ errors.push({
57
+ field: "title",
58
+ message: "Title is required",
59
+ code: "REQUIRED"
60
+ });
61
+ }
62
+ if (!atom.acceptanceCriteria || atom.acceptanceCriteria.length === 0) {
63
+ errors.push({
64
+ field: "acceptanceCriteria",
65
+ message: "At least one acceptance criterion is required",
66
+ code: "REQUIRED"
67
+ });
68
+ }
69
+ atom.acceptanceCriteria.forEach((criterion, index) => {
70
+ if (typeof criterion !== "string" || criterion.trim() === "") {
71
+ errors.push({
72
+ field: `acceptanceCriteria[${index}]`,
73
+ message: "Acceptance criterion must be a non-empty string",
74
+ code: "INVALID_FORMAT"
75
+ });
76
+ }
77
+ });
78
+ if (atom.priority < 0) {
79
+ errors.push({
80
+ field: "priority",
81
+ message: "Priority must be a non-negative number",
82
+ code: "INVALID_VALUE"
83
+ });
84
+ }
85
+ const validStatuses = [
86
+ "DRAFT",
87
+ "READY",
88
+ "IN_PROGRESS",
89
+ "TESTING",
90
+ "DONE",
91
+ "FAILED",
92
+ "BLOCKED"
93
+ ];
94
+ if (!validStatuses.includes(atom.status)) {
95
+ errors.push({
96
+ field: "status",
97
+ message: `Invalid status: ${atom.status}`,
98
+ code: "INVALID_VALUE"
99
+ });
100
+ }
101
+ return {
102
+ valid: errors.length === 0,
103
+ errors
104
+ };
105
+ }
106
+ function validateTransition(currentStatus, newStatus) {
107
+ const allowedTransitions = ATOM_TRANSITIONS[currentStatus];
108
+ if (!allowedTransitions) {
109
+ return {
110
+ valid: false,
111
+ errors: [
112
+ {
113
+ field: "status",
114
+ message: `Unknown current status: ${currentStatus}`,
115
+ code: "INVALID_VALUE"
116
+ }
117
+ ]
118
+ };
119
+ }
120
+ if (!allowedTransitions.includes(newStatus)) {
121
+ return {
122
+ valid: false,
123
+ errors: [
124
+ {
125
+ field: "status",
126
+ message: `Cannot transition from ${currentStatus} to ${newStatus}. Allowed: ${allowedTransitions.join(", ") || "none"}`,
127
+ code: "INVALID_TRANSITION"
128
+ }
129
+ ]
130
+ };
131
+ }
132
+ return { valid: true, errors: [] };
133
+ }
134
+ function transitionAtom(atom, newStatus, errorMessage) {
135
+ const validation = validateTransition(atom.status, newStatus);
136
+ if (!validation.valid) {
137
+ const error = validation.errors[0];
138
+ throw new Error(error?.message ?? "Invalid transition");
139
+ }
140
+ const now = /* @__PURE__ */ new Date();
141
+ const updates = {
142
+ status: newStatus,
143
+ updatedAt: now
144
+ };
145
+ if (newStatus === "FAILED") {
146
+ updates.retryCount = atom.retryCount + 1;
147
+ updates.errorMessage = errorMessage ?? null;
148
+ if (updates.retryCount >= MAX_RETRIES2) {
149
+ updates.status = "BLOCKED";
150
+ }
151
+ }
152
+ if (newStatus === "IN_PROGRESS" && atom.status === "FAILED") {
153
+ updates.errorMessage = null;
154
+ }
155
+ return { ...atom, ...updates };
156
+ }
157
+
158
+ // src/agents/architect.ts
159
+ import { readFile } from "fs/promises";
160
+ import { existsSync } from "fs";
161
+ var SYSTEM_PROMPT = `You are the Architect, an expert software engineer responsible for creating detailed implementation plans.
162
+
163
+ Your role:
164
+ - Analyze the atom's goals and acceptance criteria
165
+ - Review the architecture constraints and boundaries
166
+ - Generate a step-by-step implementation plan
167
+ - Identify files to modify and potential risks
168
+ - Consider learnings from previous iterations
169
+
170
+ Output your plan in the following JSON format:
171
+ {
172
+ "steps": ["Step 1: ...", "Step 2: ...", ...],
173
+ "files_to_modify": ["path/to/file1.ts", "path/to/file2.ts", ...],
174
+ "dependencies": ["dependency1", "dependency2", ...],
175
+ "risks": ["Risk 1: ...", "Risk 2: ...", ...],
176
+ "estimated_complexity": "LOW" | "MEDIUM" | "HIGH",
177
+ "reasoning": "Brief explanation of your approach..."
178
+ }
179
+
180
+ Guidelines:
181
+ - Keep steps atomic and verifiable
182
+ - List ALL files that will be modified
183
+ - Identify any external dependencies needed
184
+ - Flag security, performance, or breaking change risks
185
+ - Be conservative with complexity estimates`;
186
+ var ArchitectAgent = class {
187
+ client;
188
+ config;
189
+ constructor(config, apiKey) {
190
+ this.config = {
191
+ provider: "anthropic",
192
+ model: config?.model ?? getDefaultModel("architect"),
193
+ maxTokens: config?.maxTokens ?? 4096,
194
+ temperature: config?.temperature ?? 0.7
195
+ };
196
+ this.client = new AnthropicClient(this.config, apiKey);
197
+ }
198
+ /**
199
+ * Generate an implementation plan for an atom
200
+ */
201
+ async generatePlan(atom, architecture, context) {
202
+ const userMessage = await this.buildPrompt(atom, architecture, context);
203
+ const response = await this.client.chat(SYSTEM_PROMPT, userMessage, {
204
+ temperature: 0.7,
205
+ maxTokens: 4096
206
+ });
207
+ const plan = this.parsePlanResponse(response.content);
208
+ return {
209
+ plan,
210
+ reasoning: this.extractReasoning(response.content),
211
+ usage: response.usage
212
+ };
213
+ }
214
+ /**
215
+ * Build the prompt with all necessary context
216
+ */
217
+ async buildPrompt(atom, architecture, context) {
218
+ const parts = [];
219
+ parts.push("# Atom to Implement");
220
+ parts.push(`**Title:** ${atom.title}`);
221
+ parts.push(`**Description:** ${atom.description ?? "No description"}`);
222
+ parts.push("");
223
+ parts.push("**Goals:**");
224
+ atom.goals.forEach((g, i) => parts.push(`${i + 1}. ${g}`));
225
+ parts.push("");
226
+ parts.push("**Acceptance Criteria:**");
227
+ atom.acceptanceCriteria.forEach((ac, i) => parts.push(`${i + 1}. ${ac}`));
228
+ parts.push("");
229
+ if (atom.ownershipPaths.length > 0) {
230
+ parts.push("**Ownership Paths (files this atom can modify):**");
231
+ atom.ownershipPaths.forEach((p) => parts.push(`- ${p}`));
232
+ parts.push("");
233
+ }
234
+ parts.push("# Architecture Constraints");
235
+ parts.push(`**Profile:** ${architecture.profile}`);
236
+ parts.push(`**Strict Mode:** ${architecture.strictMode}`);
237
+ parts.push("");
238
+ if (architecture.components.length > 0) {
239
+ parts.push("**Components:**");
240
+ architecture.components.forEach((c) => {
241
+ parts.push(`- ${c.name} (${c.id}): ${c.paths.join(", ")}`);
242
+ });
243
+ parts.push("");
244
+ }
245
+ if (architecture.invariants.length > 0) {
246
+ parts.push("**Invariants (rules that must NOT be violated):**");
247
+ architecture.invariants.forEach((inv) => {
248
+ parts.push(`- [${inv.severity}] ${inv.rule}`);
249
+ });
250
+ parts.push("");
251
+ }
252
+ if (architecture.protectedPaths.length > 0) {
253
+ parts.push("**Protected Paths:**");
254
+ architecture.protectedPaths.forEach((p) => {
255
+ parts.push(`- ${p.pattern} (${p.level}): ${p.reason}`);
256
+ });
257
+ parts.push("");
258
+ }
259
+ if (context?.codebasePatterns && context.codebasePatterns.length > 0) {
260
+ parts.push("# Codebase Patterns (from previous iterations)");
261
+ context.codebasePatterns.forEach((p) => parts.push(`- ${p}`));
262
+ parts.push("");
263
+ }
264
+ if (context?.recentLearnings && context.recentLearnings.length > 0) {
265
+ parts.push("# Recent Learnings");
266
+ context.recentLearnings.slice(0, 5).forEach((l) => parts.push(`- ${l}`));
267
+ parts.push("");
268
+ }
269
+ if (context?.progressPath && existsSync(context.progressPath)) {
270
+ try {
271
+ const progressContent = await readFile(context.progressPath, "utf-8");
272
+ const patterns = this.extractCodebasePatterns(progressContent);
273
+ if (patterns.length > 0) {
274
+ parts.push("# Additional Codebase Patterns (from progress.txt)");
275
+ patterns.forEach((p) => parts.push(`- ${p}`));
276
+ parts.push("");
277
+ }
278
+ } catch {
279
+ }
280
+ }
281
+ parts.push("# Instructions");
282
+ parts.push("Generate a detailed implementation plan for this atom.");
283
+ parts.push("Ensure your plan respects all architecture constraints.");
284
+ parts.push("Output your response as valid JSON.");
285
+ return parts.join("\n");
286
+ }
287
+ /**
288
+ * Parse the plan from AI response
289
+ */
290
+ parsePlanResponse(content) {
291
+ const jsonMatch = content.match(/\{[\s\S]*\}/);
292
+ if (!jsonMatch) {
293
+ throw new Error("Failed to parse plan: no JSON found in response");
294
+ }
295
+ try {
296
+ const parsed = JSON.parse(jsonMatch[0]);
297
+ return {
298
+ steps: parsed.steps ?? [],
299
+ files_to_modify: parsed.files_to_modify ?? [],
300
+ dependencies: parsed.dependencies ?? [],
301
+ risks: parsed.risks ?? [],
302
+ estimated_complexity: this.normalizeComplexity(parsed.estimated_complexity)
303
+ };
304
+ } catch (error) {
305
+ throw new Error(`Failed to parse plan JSON: ${error instanceof Error ? error.message : "Unknown error"}`);
306
+ }
307
+ }
308
+ normalizeComplexity(value) {
309
+ const normalized = value?.toUpperCase();
310
+ if (normalized === "LOW" || normalized === "MEDIUM" || normalized === "HIGH") {
311
+ return normalized;
312
+ }
313
+ return "MEDIUM";
314
+ }
315
+ extractReasoning(content) {
316
+ try {
317
+ const jsonMatch = content.match(/\{[\s\S]*\}/);
318
+ if (jsonMatch) {
319
+ const parsed = JSON.parse(jsonMatch[0]);
320
+ return parsed.reasoning ?? "";
321
+ }
322
+ } catch {
323
+ }
324
+ return "";
325
+ }
326
+ extractCodebasePatterns(progressContent) {
327
+ const patterns = [];
328
+ const lines = progressContent.split("\n");
329
+ let inPatternsSection = false;
330
+ for (const line of lines) {
331
+ if (line.includes("## Codebase Patterns")) {
332
+ inPatternsSection = true;
333
+ continue;
334
+ }
335
+ if (line.startsWith("## ") && inPatternsSection) {
336
+ break;
337
+ }
338
+ if (inPatternsSection && line.startsWith("- ")) {
339
+ patterns.push(line.substring(2).trim());
340
+ }
341
+ }
342
+ return patterns;
343
+ }
344
+ };
345
+
346
+ export {
347
+ createAtom,
348
+ validateAtom,
349
+ transitionAtom,
350
+ ArchitectAgent
351
+ };
@@ -0,0 +1,91 @@
1
+ import {
2
+ listLocalAtoms
3
+ } from "./chunk-EDP55FCI.js";
4
+
5
+ // src/cli/list.ts
6
+ import chalk from "chalk";
7
+ var STATUS_COLORS = {
8
+ DRAFT: chalk.gray,
9
+ READY: chalk.blue,
10
+ IN_PROGRESS: chalk.yellow,
11
+ TESTING: chalk.cyan,
12
+ DONE: chalk.green,
13
+ FAILED: chalk.red,
14
+ BLOCKED: chalk.magenta
15
+ };
16
+ async function list(options) {
17
+ const atoms = await listLocalAtoms();
18
+ if (atoms.length === 0) {
19
+ console.log(chalk.dim("No atoms found."));
20
+ console.log(chalk.dim("Create one with: archon plan <description>"));
21
+ return;
22
+ }
23
+ let filteredAtoms = atoms;
24
+ if (options.status) {
25
+ const statusFilter = options.status.toUpperCase();
26
+ filteredAtoms = atoms.filter((a) => a.status === statusFilter);
27
+ if (filteredAtoms.length === 0) {
28
+ console.log(chalk.dim(`No atoms with status "${options.status}" found.`));
29
+ return;
30
+ }
31
+ }
32
+ const sortBy = options.sortBy ?? "priority";
33
+ filteredAtoms.sort((a, b) => {
34
+ switch (sortBy) {
35
+ case "priority":
36
+ return a.priority - b.priority;
37
+ case "created":
38
+ return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
39
+ case "updated":
40
+ return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();
41
+ case "status":
42
+ return a.status.localeCompare(b.status);
43
+ default:
44
+ return a.priority - b.priority;
45
+ }
46
+ });
47
+ console.log("");
48
+ console.log(
49
+ chalk.bold(
50
+ padRight("ID", 12) + padRight("Title", 40) + padRight("Status", 14) + padRight("Priority", 10) + "Created"
51
+ )
52
+ );
53
+ console.log(chalk.dim("\u2500".repeat(90)));
54
+ for (const atom of filteredAtoms) {
55
+ const colorFn = STATUS_COLORS[atom.status] ?? chalk.white;
56
+ const createdDate = formatDate(atom.createdAt);
57
+ console.log(
58
+ padRight(atom.externalId, 12) + padRight(truncate(atom.title, 38), 40) + colorFn(padRight(atom.status, 14)) + padRight(String(atom.priority), 10) + chalk.dim(createdDate)
59
+ );
60
+ }
61
+ console.log(chalk.dim("\u2500".repeat(90)));
62
+ const statusCounts = countByStatus(filteredAtoms);
63
+ const summaryParts = [];
64
+ for (const [status, count] of Object.entries(statusCounts)) {
65
+ const colorFn = STATUS_COLORS[status] ?? chalk.white;
66
+ summaryParts.push(`${count} ${colorFn(status.toLowerCase())}`);
67
+ }
68
+ console.log(`Showing ${filteredAtoms.length} atom(s): ${summaryParts.join(", ")}`);
69
+ }
70
+ function padRight(str, width) {
71
+ return str.padEnd(width);
72
+ }
73
+ function truncate(str, maxLen) {
74
+ if (str.length <= maxLen) return str;
75
+ return str.substring(0, maxLen - 1) + "\u2026";
76
+ }
77
+ function formatDate(date) {
78
+ const d = typeof date === "string" ? new Date(date) : date;
79
+ return d.toISOString().split("T")[0] ?? "";
80
+ }
81
+ function countByStatus(atoms) {
82
+ const counts = {};
83
+ for (const atom of atoms) {
84
+ counts[atom.status] = (counts[atom.status] ?? 0) + 1;
85
+ }
86
+ return counts;
87
+ }
88
+
89
+ export {
90
+ list
91
+ };
@@ -0,0 +1,37 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
+ }) : x)(function(x) {
10
+ if (typeof require !== "undefined") return require.apply(this, arguments);
11
+ throw Error('Dynamic require of "' + x + '" is not supported');
12
+ });
13
+ var __commonJS = (cb, mod) => function __require2() {
14
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+
33
+ export {
34
+ __require,
35
+ __commonJS,
36
+ __toESM
37
+ };