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.
- package/README.md +84 -51
- package/dist/auth-2QIFQZTL.js +12 -0
- package/dist/bug-DXLBBW3U.js +10 -0
- package/dist/{chunk-R6IMTNKV.js → chunk-2CFO5GVH.js} +0 -35
- package/dist/chunk-A7QU6JC6.js +119 -0
- package/dist/chunk-CAYCSBNX.js +202 -0
- package/dist/chunk-EDP55FCI.js +485 -0
- package/dist/chunk-I4ZVNLNO.js +4648 -0
- package/dist/chunk-IMZN36GC.js +159 -0
- package/dist/chunk-JBKFAD4M.js +650 -0
- package/dist/chunk-MOZHC2GX.js +351 -0
- package/dist/chunk-PK3OQVBG.js +91 -0
- package/dist/chunk-QGM4M3NI.js +37 -0
- package/dist/chunk-SMR7JQK6.js +399 -0
- package/dist/chunk-UDBFDXJI.js +696 -0
- package/dist/chunk-UG2ZZ7CM.js +737 -0
- package/dist/chunk-VKM3HAHW.js +832 -0
- package/dist/chunk-WCCBJSNI.js +62 -0
- package/dist/code-review-FSTYDHNG.js +16 -0
- package/dist/execute-LYID2ODD.js +13 -0
- package/dist/index.js +1250 -7206
- package/dist/keys-EL3FUM5O.js +15 -0
- package/dist/list-VXMVEIL5.js +13 -0
- package/dist/{parser-D6PBQUJH.js → parser-M4DI7A24.js} +2 -1
- package/dist/plan-7VSFESVD.js +16 -0
- package/dist/preferences-PL2ON5VY.js +17 -0
- package/dist/review-3R6QXAXQ.js +27 -0
- package/package.json +21 -1
|
@@ -0,0 +1,650 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ArchitectAgent,
|
|
3
|
+
createAtom
|
|
4
|
+
} from "./chunk-MOZHC2GX.js";
|
|
5
|
+
import {
|
|
6
|
+
loadConfig
|
|
7
|
+
} from "./chunk-WCCBJSNI.js";
|
|
8
|
+
|
|
9
|
+
// src/cli/bug.ts
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
import { existsSync as existsSync3 } from "fs";
|
|
12
|
+
import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
13
|
+
import { join as join3 } from "path";
|
|
14
|
+
import { createInterface } from "readline";
|
|
15
|
+
|
|
16
|
+
// src/core/bugs/manager.ts
|
|
17
|
+
import { existsSync } from "fs";
|
|
18
|
+
import { readFile, writeFile, mkdir, readdir } from "fs/promises";
|
|
19
|
+
import { join } from "path";
|
|
20
|
+
import * as yaml from "yaml";
|
|
21
|
+
var BUGS_DIR = "bugs";
|
|
22
|
+
var bugCounter = 0;
|
|
23
|
+
function generateBugId() {
|
|
24
|
+
bugCounter++;
|
|
25
|
+
return `BUG-${String(bugCounter).padStart(3, "0")}`;
|
|
26
|
+
}
|
|
27
|
+
async function initializeBugCounter(projectPath) {
|
|
28
|
+
const bugsDir = join(projectPath, BUGS_DIR);
|
|
29
|
+
if (!existsSync(bugsDir)) {
|
|
30
|
+
bugCounter = 0;
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const files = await readdir(bugsDir);
|
|
34
|
+
const bugFiles = files.filter((f) => f.startsWith("BUG-") && f.endsWith(".yaml"));
|
|
35
|
+
let maxId = 0;
|
|
36
|
+
for (const file of bugFiles) {
|
|
37
|
+
const match = file.match(/BUG-(\d+)\.yaml/);
|
|
38
|
+
if (match?.[1]) {
|
|
39
|
+
const id = parseInt(match[1], 10);
|
|
40
|
+
if (id > maxId) {
|
|
41
|
+
maxId = id;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
bugCounter = maxId;
|
|
46
|
+
}
|
|
47
|
+
var BugManager = class {
|
|
48
|
+
projectPath;
|
|
49
|
+
constructor(projectPath) {
|
|
50
|
+
this.projectPath = projectPath;
|
|
51
|
+
}
|
|
52
|
+
async initialize() {
|
|
53
|
+
await initializeBugCounter(this.projectPath);
|
|
54
|
+
const bugsDir = join(this.projectPath, BUGS_DIR);
|
|
55
|
+
if (!existsSync(bugsDir)) {
|
|
56
|
+
await mkdir(bugsDir, { recursive: true });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async createBug(input) {
|
|
60
|
+
const now = /* @__PURE__ */ new Date();
|
|
61
|
+
const id = generateBugId();
|
|
62
|
+
const bug = {
|
|
63
|
+
id,
|
|
64
|
+
title: input.title,
|
|
65
|
+
description: input.description,
|
|
66
|
+
stepsToReproduce: input.stepsToReproduce,
|
|
67
|
+
expectedBehavior: input.expectedBehavior,
|
|
68
|
+
actualBehavior: input.actualBehavior,
|
|
69
|
+
severity: input.severity,
|
|
70
|
+
affectedComponents: [],
|
|
71
|
+
triageResult: null,
|
|
72
|
+
rcaResult: null,
|
|
73
|
+
atomId: null,
|
|
74
|
+
status: "REPORTED",
|
|
75
|
+
createdAt: now,
|
|
76
|
+
updatedAt: now
|
|
77
|
+
};
|
|
78
|
+
await this.saveBug(bug);
|
|
79
|
+
return bug;
|
|
80
|
+
}
|
|
81
|
+
async saveBug(bug) {
|
|
82
|
+
const bugsDir = join(this.projectPath, BUGS_DIR);
|
|
83
|
+
if (!existsSync(bugsDir)) {
|
|
84
|
+
await mkdir(bugsDir, { recursive: true });
|
|
85
|
+
}
|
|
86
|
+
const bugFile = join(bugsDir, `${bug.id}.yaml`);
|
|
87
|
+
const content = yaml.stringify(this.serializeBug(bug));
|
|
88
|
+
await writeFile(bugFile, content);
|
|
89
|
+
}
|
|
90
|
+
async loadBug(bugId) {
|
|
91
|
+
const bugFile = join(this.projectPath, BUGS_DIR, `${bugId}.yaml`);
|
|
92
|
+
if (!existsSync(bugFile)) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
const content = await readFile(bugFile, "utf-8");
|
|
96
|
+
const data = yaml.parse(content);
|
|
97
|
+
return this.deserializeBug(data);
|
|
98
|
+
}
|
|
99
|
+
async listBugs() {
|
|
100
|
+
const bugsDir = join(this.projectPath, BUGS_DIR);
|
|
101
|
+
if (!existsSync(bugsDir)) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
const files = await readdir(bugsDir);
|
|
105
|
+
const bugs = [];
|
|
106
|
+
for (const file of files) {
|
|
107
|
+
if (file.endsWith(".yaml")) {
|
|
108
|
+
const bugId = file.replace(".yaml", "");
|
|
109
|
+
const bug = await this.loadBug(bugId);
|
|
110
|
+
if (bug) {
|
|
111
|
+
bugs.push(bug);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return bugs.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
116
|
+
}
|
|
117
|
+
async updateTriageResult(bugId, triageResult) {
|
|
118
|
+
const bug = await this.loadBug(bugId);
|
|
119
|
+
if (!bug) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
bug.triageResult = triageResult;
|
|
123
|
+
bug.affectedComponents = triageResult.affectedComponents;
|
|
124
|
+
bug.status = "TRIAGED";
|
|
125
|
+
bug.updatedAt = /* @__PURE__ */ new Date();
|
|
126
|
+
await this.saveBug(bug);
|
|
127
|
+
return bug;
|
|
128
|
+
}
|
|
129
|
+
async updateRCAResult(bugId, rcaResult) {
|
|
130
|
+
const bug = await this.loadBug(bugId);
|
|
131
|
+
if (!bug) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
bug.rcaResult = rcaResult;
|
|
135
|
+
bug.status = "ANALYZED";
|
|
136
|
+
bug.updatedAt = /* @__PURE__ */ new Date();
|
|
137
|
+
await this.saveBug(bug);
|
|
138
|
+
return bug;
|
|
139
|
+
}
|
|
140
|
+
async linkAtom(bugId, atomId) {
|
|
141
|
+
const bug = await this.loadBug(bugId);
|
|
142
|
+
if (!bug) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
bug.atomId = atomId;
|
|
146
|
+
bug.status = "IN_PROGRESS";
|
|
147
|
+
bug.updatedAt = /* @__PURE__ */ new Date();
|
|
148
|
+
await this.saveBug(bug);
|
|
149
|
+
return bug;
|
|
150
|
+
}
|
|
151
|
+
serializeBug(bug) {
|
|
152
|
+
return {
|
|
153
|
+
id: bug.id,
|
|
154
|
+
title: bug.title,
|
|
155
|
+
description: bug.description,
|
|
156
|
+
stepsToReproduce: bug.stepsToReproduce,
|
|
157
|
+
expectedBehavior: bug.expectedBehavior,
|
|
158
|
+
actualBehavior: bug.actualBehavior,
|
|
159
|
+
severity: bug.severity,
|
|
160
|
+
affectedComponents: bug.affectedComponents,
|
|
161
|
+
triageResult: bug.triageResult,
|
|
162
|
+
rcaResult: bug.rcaResult,
|
|
163
|
+
atomId: bug.atomId,
|
|
164
|
+
status: bug.status,
|
|
165
|
+
createdAt: bug.createdAt.toISOString(),
|
|
166
|
+
updatedAt: bug.updatedAt.toISOString()
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
deserializeBug(data) {
|
|
170
|
+
return {
|
|
171
|
+
id: data["id"],
|
|
172
|
+
title: data["title"],
|
|
173
|
+
description: data["description"],
|
|
174
|
+
stepsToReproduce: data["stepsToReproduce"],
|
|
175
|
+
expectedBehavior: data["expectedBehavior"],
|
|
176
|
+
actualBehavior: data["actualBehavior"],
|
|
177
|
+
severity: data["severity"],
|
|
178
|
+
affectedComponents: data["affectedComponents"],
|
|
179
|
+
triageResult: data["triageResult"],
|
|
180
|
+
rcaResult: data["rcaResult"],
|
|
181
|
+
atomId: data["atomId"],
|
|
182
|
+
status: data["status"],
|
|
183
|
+
createdAt: new Date(data["createdAt"]),
|
|
184
|
+
updatedAt: new Date(data["updatedAt"])
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// src/core/bugs/triage.ts
|
|
190
|
+
import { existsSync as existsSync2 } from "fs";
|
|
191
|
+
import { join as join2 } from "path";
|
|
192
|
+
var AutoTriage = class {
|
|
193
|
+
architecture;
|
|
194
|
+
constructor(architecture) {
|
|
195
|
+
this.architecture = architecture ?? null;
|
|
196
|
+
}
|
|
197
|
+
async analyzeBug(bug) {
|
|
198
|
+
const keywords = this.extractKeywords(bug);
|
|
199
|
+
const affectedComponents = this.identifyAffectedComponents(bug, keywords);
|
|
200
|
+
const relatedFiles = this.identifyRelatedFiles(bug, keywords);
|
|
201
|
+
const estimatedSeverity = this.estimateSeverity(bug, affectedComponents);
|
|
202
|
+
const suggestedPriority = this.calculatePriority(estimatedSeverity, affectedComponents.length);
|
|
203
|
+
const confidence = this.calculateConfidence(keywords, affectedComponents);
|
|
204
|
+
return {
|
|
205
|
+
affectedComponents,
|
|
206
|
+
estimatedSeverity,
|
|
207
|
+
suggestedPriority,
|
|
208
|
+
keywords,
|
|
209
|
+
relatedFiles,
|
|
210
|
+
confidence
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
extractKeywords(bug) {
|
|
214
|
+
const text = [
|
|
215
|
+
bug.title,
|
|
216
|
+
bug.description,
|
|
217
|
+
...bug.stepsToReproduce,
|
|
218
|
+
bug.expectedBehavior,
|
|
219
|
+
bug.actualBehavior
|
|
220
|
+
].join(" ").toLowerCase();
|
|
221
|
+
const commonPatterns = [
|
|
222
|
+
"error",
|
|
223
|
+
"crash",
|
|
224
|
+
"fail",
|
|
225
|
+
"broken",
|
|
226
|
+
"null",
|
|
227
|
+
"undefined",
|
|
228
|
+
"timeout",
|
|
229
|
+
"hang",
|
|
230
|
+
"freeze",
|
|
231
|
+
"slow",
|
|
232
|
+
"memory",
|
|
233
|
+
"leak",
|
|
234
|
+
"security",
|
|
235
|
+
"auth",
|
|
236
|
+
"login",
|
|
237
|
+
"permission",
|
|
238
|
+
"access",
|
|
239
|
+
"database",
|
|
240
|
+
"api",
|
|
241
|
+
"network",
|
|
242
|
+
"connection",
|
|
243
|
+
"socket",
|
|
244
|
+
"file",
|
|
245
|
+
"path",
|
|
246
|
+
"directory",
|
|
247
|
+
"config",
|
|
248
|
+
"env",
|
|
249
|
+
"cli",
|
|
250
|
+
"command",
|
|
251
|
+
"parse",
|
|
252
|
+
"validation",
|
|
253
|
+
"schema"
|
|
254
|
+
];
|
|
255
|
+
const foundKeywords = [];
|
|
256
|
+
for (const pattern of commonPatterns) {
|
|
257
|
+
if (text.includes(pattern)) {
|
|
258
|
+
foundKeywords.push(pattern);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const technicalTerms = text.match(/\b[A-Z][a-zA-Z]+(?:Error|Exception|Failure|Handler|Manager|Service|Client|Agent)\b/gi);
|
|
262
|
+
if (technicalTerms) {
|
|
263
|
+
foundKeywords.push(...technicalTerms.map((t) => t.toLowerCase()));
|
|
264
|
+
}
|
|
265
|
+
const filePatterns = text.match(/\b[\w/-]+\.(ts|js|json|yaml|md)\b/gi);
|
|
266
|
+
if (filePatterns) {
|
|
267
|
+
foundKeywords.push(...filePatterns);
|
|
268
|
+
}
|
|
269
|
+
return [...new Set(foundKeywords)];
|
|
270
|
+
}
|
|
271
|
+
identifyAffectedComponents(bug, keywords) {
|
|
272
|
+
if (!this.architecture) {
|
|
273
|
+
return this.inferComponentsFromKeywords(keywords);
|
|
274
|
+
}
|
|
275
|
+
const text = [
|
|
276
|
+
bug.title,
|
|
277
|
+
bug.description,
|
|
278
|
+
...bug.stepsToReproduce
|
|
279
|
+
].join(" ").toLowerCase();
|
|
280
|
+
const affected = [];
|
|
281
|
+
for (const component of this.architecture.components) {
|
|
282
|
+
if (this.componentMatchesBug(component, text, keywords)) {
|
|
283
|
+
affected.push(component.id);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (affected.length === 0) {
|
|
287
|
+
return this.inferComponentsFromKeywords(keywords);
|
|
288
|
+
}
|
|
289
|
+
return affected;
|
|
290
|
+
}
|
|
291
|
+
componentMatchesBug(component, text, keywords) {
|
|
292
|
+
if (text.includes(component.name.toLowerCase())) {
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
if (text.includes(component.id.toLowerCase())) {
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
for (const path of component.paths) {
|
|
299
|
+
const pathParts = path.split("/").filter((p) => p && p !== "*");
|
|
300
|
+
for (const part of pathParts) {
|
|
301
|
+
if (text.includes(part.toLowerCase())) {
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
inferComponentsFromKeywords(keywords) {
|
|
309
|
+
const componentMap = {
|
|
310
|
+
"cli": ["cli", "command", "parse", "prompt"],
|
|
311
|
+
"agents": ["agent", "architect", "sentinel", "executor", "planner"],
|
|
312
|
+
"core": ["core", "parser", "validation", "schema"],
|
|
313
|
+
"database": ["database", "db", "supabase", "query", "sql"],
|
|
314
|
+
"api": ["api", "endpoint", "route", "request", "response"],
|
|
315
|
+
"auth": ["auth", "login", "permission", "token", "session"]
|
|
316
|
+
};
|
|
317
|
+
const inferred = [];
|
|
318
|
+
for (const [component, patterns] of Object.entries(componentMap)) {
|
|
319
|
+
for (const pattern of patterns) {
|
|
320
|
+
if (keywords.includes(pattern)) {
|
|
321
|
+
inferred.push(component);
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return [...new Set(inferred)];
|
|
327
|
+
}
|
|
328
|
+
identifyRelatedFiles(bug, keywords) {
|
|
329
|
+
const files = [];
|
|
330
|
+
const filePatterns = keywords.filter((k) => k.match(/\.(ts|js|json|yaml|md)$/i));
|
|
331
|
+
files.push(...filePatterns);
|
|
332
|
+
for (const keyword of keywords) {
|
|
333
|
+
if (keyword === "cli") {
|
|
334
|
+
files.push("src/cli/");
|
|
335
|
+
} else if (keyword === "agent" || keyword === "architect" || keyword === "sentinel") {
|
|
336
|
+
files.push("src/agents/");
|
|
337
|
+
} else if (keyword === "parser" || keyword === "schema") {
|
|
338
|
+
files.push("src/core/parser/");
|
|
339
|
+
} else if (keyword === "database" || keyword === "db") {
|
|
340
|
+
files.push("src/db/");
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return [...new Set(files)];
|
|
344
|
+
}
|
|
345
|
+
estimateSeverity(bug, affectedComponents) {
|
|
346
|
+
const criticalKeywords = ["security", "auth", "data loss", "corruption", "crash"];
|
|
347
|
+
const highKeywords = ["error", "fail", "broken", "cannot", "unable"];
|
|
348
|
+
const mediumKeywords = ["slow", "timeout", "unexpected", "incorrect"];
|
|
349
|
+
const text = [bug.title, bug.description, bug.actualBehavior].join(" ").toLowerCase();
|
|
350
|
+
for (const keyword of criticalKeywords) {
|
|
351
|
+
if (text.includes(keyword)) {
|
|
352
|
+
return "CRITICAL";
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
if (bug.severity === "CRITICAL" || bug.severity === "HIGH") {
|
|
356
|
+
return bug.severity;
|
|
357
|
+
}
|
|
358
|
+
const hasHighKeyword = highKeywords.some((k) => text.includes(k));
|
|
359
|
+
const hasManyComponents = affectedComponents.length > 2;
|
|
360
|
+
if (hasHighKeyword && hasManyComponents) {
|
|
361
|
+
return "HIGH";
|
|
362
|
+
}
|
|
363
|
+
if (hasHighKeyword || hasManyComponents) {
|
|
364
|
+
return "MEDIUM";
|
|
365
|
+
}
|
|
366
|
+
if (mediumKeywords.some((k) => text.includes(k))) {
|
|
367
|
+
return "MEDIUM";
|
|
368
|
+
}
|
|
369
|
+
return "LOW";
|
|
370
|
+
}
|
|
371
|
+
calculatePriority(severity, componentCount) {
|
|
372
|
+
const severityScore = {
|
|
373
|
+
CRITICAL: 1,
|
|
374
|
+
HIGH: 2,
|
|
375
|
+
MEDIUM: 5,
|
|
376
|
+
LOW: 10
|
|
377
|
+
};
|
|
378
|
+
let priority = severityScore[severity];
|
|
379
|
+
priority = Math.max(1, priority - componentCount);
|
|
380
|
+
return priority;
|
|
381
|
+
}
|
|
382
|
+
calculateConfidence(keywords, affectedComponents) {
|
|
383
|
+
let confidence = 0.5;
|
|
384
|
+
if (keywords.length > 3) {
|
|
385
|
+
confidence += 0.2;
|
|
386
|
+
}
|
|
387
|
+
if (affectedComponents.length > 0) {
|
|
388
|
+
confidence += 0.2;
|
|
389
|
+
}
|
|
390
|
+
if (keywords.some((k) => k.match(/\.(ts|js)$/))) {
|
|
391
|
+
confidence += 0.1;
|
|
392
|
+
}
|
|
393
|
+
return Math.min(1, confidence);
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
async function loadArchitectureForTriage(projectPath) {
|
|
397
|
+
const archPath = join2(projectPath, "ARCHITECTURE.md");
|
|
398
|
+
if (!existsSync2(archPath)) {
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
try {
|
|
402
|
+
const { ArchitectureParser } = await import("./parser-M4DI7A24.js");
|
|
403
|
+
const parser = new ArchitectureParser(archPath);
|
|
404
|
+
const result = await parser.parse();
|
|
405
|
+
return result.success ? result.schema ?? null : null;
|
|
406
|
+
} catch {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// src/cli/bug.ts
|
|
412
|
+
var ATOMS_DIR = ".archon/atoms";
|
|
413
|
+
function createPrompt() {
|
|
414
|
+
const rl = createInterface({
|
|
415
|
+
input: process.stdin,
|
|
416
|
+
output: process.stdout
|
|
417
|
+
});
|
|
418
|
+
return {
|
|
419
|
+
ask: (question) => new Promise((resolve) => {
|
|
420
|
+
rl.question(question, resolve);
|
|
421
|
+
}),
|
|
422
|
+
close: () => rl.close()
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
function parseSeverity(input) {
|
|
426
|
+
const normalized = input.toUpperCase().trim();
|
|
427
|
+
if (normalized === "LOW" || normalized === "MEDIUM" || normalized === "HIGH" || normalized === "CRITICAL") {
|
|
428
|
+
return normalized;
|
|
429
|
+
}
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
async function bugReport(title, options) {
|
|
433
|
+
const prompt = createPrompt();
|
|
434
|
+
const projectPath = process.cwd();
|
|
435
|
+
try {
|
|
436
|
+
console.log(chalk.blue("\n\u{1F4CB} Bug Report: ") + chalk.bold(title));
|
|
437
|
+
console.log(chalk.dim("\u2500".repeat(40)));
|
|
438
|
+
const description = await prompt.ask(chalk.cyan("Description: "));
|
|
439
|
+
console.log(chalk.cyan("Steps to reproduce (enter each step, empty line to finish):"));
|
|
440
|
+
const stepsToReproduce = [];
|
|
441
|
+
let stepNum = 1;
|
|
442
|
+
let step = await prompt.ask(chalk.dim(` ${stepNum}. `));
|
|
443
|
+
while (step.trim() !== "") {
|
|
444
|
+
stepsToReproduce.push(step.trim());
|
|
445
|
+
stepNum++;
|
|
446
|
+
step = await prompt.ask(chalk.dim(` ${stepNum}. `));
|
|
447
|
+
}
|
|
448
|
+
if (stepsToReproduce.length === 0) {
|
|
449
|
+
stepsToReproduce.push("No steps provided");
|
|
450
|
+
}
|
|
451
|
+
const expectedBehavior = await prompt.ask(chalk.cyan("Expected behavior: "));
|
|
452
|
+
const actualBehavior = await prompt.ask(chalk.cyan("Actual behavior: "));
|
|
453
|
+
let severity = null;
|
|
454
|
+
while (!severity) {
|
|
455
|
+
const severityInput = await prompt.ask(chalk.cyan("Severity (LOW/MEDIUM/HIGH/CRITICAL): "));
|
|
456
|
+
severity = parseSeverity(severityInput);
|
|
457
|
+
if (!severity) {
|
|
458
|
+
console.log(chalk.yellow("Invalid severity. Please enter LOW, MEDIUM, HIGH, or CRITICAL."));
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
const manager = new BugManager(projectPath);
|
|
462
|
+
await manager.initialize();
|
|
463
|
+
const bug = await manager.createBug({
|
|
464
|
+
title,
|
|
465
|
+
description,
|
|
466
|
+
stepsToReproduce,
|
|
467
|
+
expectedBehavior,
|
|
468
|
+
actualBehavior,
|
|
469
|
+
severity
|
|
470
|
+
});
|
|
471
|
+
console.log(chalk.green(`
|
|
472
|
+
\u2705 Bug created: ${bug.id}`));
|
|
473
|
+
console.log(chalk.blue("\n\u{1F50D} Running automated triage..."));
|
|
474
|
+
const architecture = await loadArchitectureForTriage(projectPath);
|
|
475
|
+
const triage = new AutoTriage(architecture ?? void 0);
|
|
476
|
+
const triageResult = await triage.analyzeBug(bug);
|
|
477
|
+
await manager.updateTriageResult(bug.id, triageResult);
|
|
478
|
+
console.log(chalk.dim("\nTriage Results:"));
|
|
479
|
+
console.log(chalk.dim(` Affected Components: ${triageResult.affectedComponents.join(", ") || "Unknown"}`));
|
|
480
|
+
console.log(chalk.dim(` Estimated Severity: ${triageResult.estimatedSeverity}`));
|
|
481
|
+
console.log(chalk.dim(` Suggested Priority: ${triageResult.suggestedPriority}`));
|
|
482
|
+
console.log(chalk.dim(` Confidence: ${(triageResult.confidence * 100).toFixed(0)}%`));
|
|
483
|
+
if (triageResult.keywords.length > 0) {
|
|
484
|
+
console.log(chalk.dim(` Keywords: ${triageResult.keywords.slice(0, 5).join(", ")}`));
|
|
485
|
+
}
|
|
486
|
+
let rcaResult = null;
|
|
487
|
+
if (!options.skipRca) {
|
|
488
|
+
const config = await loadConfig();
|
|
489
|
+
const hasApiKey = !!process.env["ANTHROPIC_API_KEY"] || config.tier === "BYOK";
|
|
490
|
+
if (hasApiKey) {
|
|
491
|
+
console.log(chalk.blue("\n\u{1F52C} Generating Root Cause Analysis..."));
|
|
492
|
+
try {
|
|
493
|
+
rcaResult = await generateRCA(bug.id, bug.title, bug.description, bug.actualBehavior, triageResult.affectedComponents);
|
|
494
|
+
await manager.updateRCAResult(bug.id, rcaResult);
|
|
495
|
+
console.log(chalk.dim("\nRoot Cause Analysis:"));
|
|
496
|
+
console.log(chalk.dim(` Likely Cause: ${rcaResult.likelyCause}`));
|
|
497
|
+
console.log(chalk.dim(` Suggested Fix: ${rcaResult.suggestedFix}`));
|
|
498
|
+
console.log(chalk.dim(` Complexity: ${rcaResult.complexity}`));
|
|
499
|
+
if (rcaResult.affectedFiles.length > 0) {
|
|
500
|
+
console.log(chalk.dim(` Affected Files: ${rcaResult.affectedFiles.slice(0, 3).join(", ")}`));
|
|
501
|
+
}
|
|
502
|
+
} catch (error) {
|
|
503
|
+
console.log(chalk.yellow(`
|
|
504
|
+
\u26A0 RCA generation failed: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
505
|
+
console.log(chalk.dim("Continuing without RCA..."));
|
|
506
|
+
}
|
|
507
|
+
} else {
|
|
508
|
+
console.log(chalk.yellow("\n\u26A0 No API key configured. Skipping RCA."));
|
|
509
|
+
console.log(chalk.dim('Set ANTHROPIC_API_KEY or use "archon keys add anthropic"'));
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
console.log(chalk.blue("\n\u{1F4E6} Creating fix atom..."));
|
|
513
|
+
const acceptanceCriteria = [
|
|
514
|
+
`Bug ${bug.id} is fixed`,
|
|
515
|
+
"Regression test added to prevent recurrence",
|
|
516
|
+
"Typecheck passes",
|
|
517
|
+
"All tests pass"
|
|
518
|
+
];
|
|
519
|
+
if (rcaResult) {
|
|
520
|
+
acceptanceCriteria.push(`Fix addresses: ${rcaResult.likelyCause}`);
|
|
521
|
+
}
|
|
522
|
+
const atom = createAtom({
|
|
523
|
+
title: `Fix ${bug.id}: ${bug.title}`,
|
|
524
|
+
description: buildAtomDescription(bug.id, bug.description, bug.actualBehavior, rcaResult),
|
|
525
|
+
goals: [`Fix bug ${bug.id}`],
|
|
526
|
+
acceptanceCriteria,
|
|
527
|
+
ownershipPaths: rcaResult?.affectedFiles ?? triageResult.relatedFiles,
|
|
528
|
+
priority: triageResult.suggestedPriority,
|
|
529
|
+
tags: ["bug-fix", bug.id],
|
|
530
|
+
metadata: { bugId: bug.id }
|
|
531
|
+
});
|
|
532
|
+
await saveAtom(atom);
|
|
533
|
+
await manager.linkAtom(bug.id, atom.externalId);
|
|
534
|
+
console.log(chalk.green(`
|
|
535
|
+
\u2705 Atom created: ${atom.externalId}`));
|
|
536
|
+
console.log(chalk.dim(` Linked to: ${bug.id}`));
|
|
537
|
+
console.log(chalk.bold("\n\u{1F4CB} Summary"));
|
|
538
|
+
console.log(chalk.dim("\u2500".repeat(40)));
|
|
539
|
+
console.log(`Bug ID: ${chalk.cyan(bug.id)}`);
|
|
540
|
+
console.log(`Atom ID: ${chalk.cyan(atom.externalId)}`);
|
|
541
|
+
console.log(`Severity: ${formatSeverity(bug.severity)}`);
|
|
542
|
+
console.log(`Status: ${chalk.yellow("IN_PROGRESS")}`);
|
|
543
|
+
console.log(chalk.dim("\nNext steps:"));
|
|
544
|
+
console.log(chalk.dim(` - Plan: archon plan ${atom.externalId} --continue`));
|
|
545
|
+
console.log(chalk.dim(` - Execute: archon execute ${atom.externalId}`));
|
|
546
|
+
} finally {
|
|
547
|
+
prompt.close();
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
function formatSeverity(severity) {
|
|
551
|
+
switch (severity) {
|
|
552
|
+
case "CRITICAL":
|
|
553
|
+
return chalk.red.bold(severity);
|
|
554
|
+
case "HIGH":
|
|
555
|
+
return chalk.red(severity);
|
|
556
|
+
case "MEDIUM":
|
|
557
|
+
return chalk.yellow(severity);
|
|
558
|
+
case "LOW":
|
|
559
|
+
return chalk.green(severity);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
function buildAtomDescription(bugId, description, actualBehavior, rcaResult) {
|
|
563
|
+
const parts = [
|
|
564
|
+
`Fix for ${bugId}`,
|
|
565
|
+
"",
|
|
566
|
+
`**Problem:** ${description}`,
|
|
567
|
+
"",
|
|
568
|
+
`**Actual Behavior:** ${actualBehavior}`
|
|
569
|
+
];
|
|
570
|
+
if (rcaResult) {
|
|
571
|
+
parts.push("");
|
|
572
|
+
parts.push(`**Root Cause:** ${rcaResult.likelyCause}`);
|
|
573
|
+
parts.push("");
|
|
574
|
+
parts.push(`**Suggested Fix:** ${rcaResult.suggestedFix}`);
|
|
575
|
+
}
|
|
576
|
+
return parts.join("\n");
|
|
577
|
+
}
|
|
578
|
+
async function generateRCA(bugId, title, description, actualBehavior, affectedComponents) {
|
|
579
|
+
const architect = new ArchitectAgent();
|
|
580
|
+
const prompt = buildRCAPrompt(bugId, title, description, actualBehavior, affectedComponents);
|
|
581
|
+
const dummyAtom = createAtom({
|
|
582
|
+
title: `RCA for ${bugId}`,
|
|
583
|
+
acceptanceCriteria: ["Identify root cause"]
|
|
584
|
+
});
|
|
585
|
+
const dummyArchitecture = {
|
|
586
|
+
version: "1.0.0",
|
|
587
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
588
|
+
profile: "balanced",
|
|
589
|
+
strictMode: false,
|
|
590
|
+
systemGoals: [],
|
|
591
|
+
components: [],
|
|
592
|
+
invariants: [],
|
|
593
|
+
protectedPaths: [],
|
|
594
|
+
cautiousPaths: [],
|
|
595
|
+
temporaryOverrides: [],
|
|
596
|
+
environments: {},
|
|
597
|
+
rawYaml: {},
|
|
598
|
+
markdownBody: ""
|
|
599
|
+
};
|
|
600
|
+
const response = await architect.generatePlan(dummyAtom, dummyArchitecture, {
|
|
601
|
+
codebasePatterns: [`Bug analysis for ${bugId}`]
|
|
602
|
+
});
|
|
603
|
+
return parseRCAResponse(response.reasoning, response.plan);
|
|
604
|
+
}
|
|
605
|
+
function buildRCAPrompt(bugId, title, description, actualBehavior, affectedComponents) {
|
|
606
|
+
return [
|
|
607
|
+
`# Root Cause Analysis for ${bugId}`,
|
|
608
|
+
"",
|
|
609
|
+
`**Title:** ${title}`,
|
|
610
|
+
`**Description:** ${description}`,
|
|
611
|
+
`**Actual Behavior:** ${actualBehavior}`,
|
|
612
|
+
`**Affected Components:** ${affectedComponents.join(", ") || "Unknown"}`,
|
|
613
|
+
"",
|
|
614
|
+
"Analyze this bug and identify:",
|
|
615
|
+
"1. The likely root cause",
|
|
616
|
+
"2. Which files are probably affected",
|
|
617
|
+
"3. A suggested fix approach",
|
|
618
|
+
"4. Risk assessment for the fix",
|
|
619
|
+
"5. Complexity estimate (LOW/MEDIUM/HIGH)"
|
|
620
|
+
].join("\n");
|
|
621
|
+
}
|
|
622
|
+
function parseRCAResponse(reasoning, plan) {
|
|
623
|
+
return {
|
|
624
|
+
likelyCause: reasoning || "Unable to determine root cause",
|
|
625
|
+
affectedFiles: plan.files_to_modify,
|
|
626
|
+
suggestedFix: plan.steps.join("; ") || "Further investigation needed",
|
|
627
|
+
riskAssessment: plan.risks.join("; ") || "No specific risks identified",
|
|
628
|
+
complexity: normalizeComplexity(plan.estimated_complexity),
|
|
629
|
+
reasoning
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
function normalizeComplexity(value) {
|
|
633
|
+
const normalized = value?.toUpperCase();
|
|
634
|
+
if (normalized === "LOW" || normalized === "MEDIUM" || normalized === "HIGH") {
|
|
635
|
+
return normalized;
|
|
636
|
+
}
|
|
637
|
+
return "MEDIUM";
|
|
638
|
+
}
|
|
639
|
+
async function saveAtom(atom) {
|
|
640
|
+
const atomsDir = join3(process.cwd(), ATOMS_DIR);
|
|
641
|
+
if (!existsSync3(atomsDir)) {
|
|
642
|
+
await mkdir2(atomsDir, { recursive: true });
|
|
643
|
+
}
|
|
644
|
+
const atomFile = join3(atomsDir, `${atom.externalId}.json`);
|
|
645
|
+
await writeFile2(atomFile, JSON.stringify(atom, null, 2));
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
export {
|
|
649
|
+
bugReport
|
|
650
|
+
};
|