archondev 2.19.56 → 3.0.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 +63 -47
- package/dist/{auth-XRKCCFJ3.js → auth-T4C7OQWO.js} +1 -1
- package/dist/{chunk-F3DZZHZB.js → chunk-43IIEFB2.js} +1 -1
- package/dist/{chunk-4K3XNRU6.js → chunk-45T2VB5R.js} +14 -4
- package/dist/{chunk-6TBYNRNF.js → chunk-57NSGWWD.js} +9 -7
- package/dist/{chunk-OHIN6OHU.js → chunk-7RXZTPXY.js} +14 -4
- package/dist/chunk-AJNKSFHL.js +491 -0
- package/dist/chunk-I3BBA7MB.js +150 -0
- package/dist/{chunk-L6VHJQ6M.js → chunk-PQS3TQB6.js} +128 -379
- package/dist/{chunk-LU4DXW3J.js → chunk-YK5Z6U5A.js} +489 -100
- package/dist/{execute-C3NFIEEI.js → execute-HWUL2M3B.js} +3 -3
- package/dist/index.js +1876 -1721
- package/dist/{list-ULMKVK7D.js → list-7IBMJCCF.js} +3 -3
- package/dist/{parallel-T37FF7GD.js → parallel-4PXJA2QD.js} +3 -3
- package/dist/{plan-WBNGP2UE.js → plan-HBAUG3KD.js} +2 -2
- package/dist/{preferences-PELPR2MO.js → preferences-VVFGRNPD.js} +2 -6
- package/dist/ship-KHL6NVC2.js +7 -0
- package/package.json +1 -1
- package/dist/chunk-R664NEAA.js +0 -66
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadAtom,
|
|
3
3
|
loadRoleOverrides
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-7RXZTPXY.js";
|
|
5
5
|
import {
|
|
6
|
+
appendLocalUsageEntry,
|
|
6
7
|
debugLog,
|
|
7
8
|
getDebugLogPath
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-I3BBA7MB.js";
|
|
9
10
|
import {
|
|
10
11
|
ArchitectureParser
|
|
11
12
|
} from "./chunk-5EVHUDQX.js";
|
|
@@ -21,6 +22,10 @@ import {
|
|
|
21
22
|
import {
|
|
22
23
|
KeyManager
|
|
23
24
|
} from "./chunk-RDG5BUED.js";
|
|
25
|
+
import {
|
|
26
|
+
loadConfig,
|
|
27
|
+
saveConfig
|
|
28
|
+
} from "./chunk-GGRW4NTA.js";
|
|
24
29
|
import {
|
|
25
30
|
__commonJS,
|
|
26
31
|
__require,
|
|
@@ -2851,10 +2856,10 @@ var require_js_yaml2 = __commonJS({
|
|
|
2851
2856
|
});
|
|
2852
2857
|
|
|
2853
2858
|
// src/cli/execute.ts
|
|
2854
|
-
import
|
|
2855
|
-
import { existsSync as
|
|
2859
|
+
import chalk3 from "chalk";
|
|
2860
|
+
import { existsSync as existsSync9 } from "fs";
|
|
2856
2861
|
import { readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
|
|
2857
|
-
import { join as
|
|
2862
|
+
import { join as join4 } from "path";
|
|
2858
2863
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
2859
2864
|
import { createInterface } from "readline";
|
|
2860
2865
|
|
|
@@ -4512,6 +4517,208 @@ function getDefaultModelForRole(role, provider) {
|
|
|
4512
4517
|
return "claude-sonnet-4-6";
|
|
4513
4518
|
}
|
|
4514
4519
|
|
|
4520
|
+
// src/core/risk/scorer.ts
|
|
4521
|
+
function computeRiskScore(filesToModify, schema, depCheck) {
|
|
4522
|
+
const factors = [];
|
|
4523
|
+
let score = 0;
|
|
4524
|
+
for (const pp of schema.protectedPaths) {
|
|
4525
|
+
if (pp.level === "HARD") {
|
|
4526
|
+
const matched = filesToModify.filter((f) => matchesPattern(f, pp.pattern));
|
|
4527
|
+
if (matched.length > 0) {
|
|
4528
|
+
const pts = 20 * matched.length;
|
|
4529
|
+
score += pts;
|
|
4530
|
+
factors.push({ label: "HARD protected path", points: pts, detail: pp.pattern });
|
|
4531
|
+
}
|
|
4532
|
+
}
|
|
4533
|
+
}
|
|
4534
|
+
for (const pp of schema.protectedPaths) {
|
|
4535
|
+
if (pp.level === "SOFT") {
|
|
4536
|
+
const matched = filesToModify.filter((f) => matchesPattern(f, pp.pattern));
|
|
4537
|
+
if (matched.length > 0) {
|
|
4538
|
+
const pts = 10 * matched.length;
|
|
4539
|
+
score += pts;
|
|
4540
|
+
factors.push({ label: "SOFT protected path", points: pts, detail: pp.pattern });
|
|
4541
|
+
}
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
for (const cp of schema.cautiousPaths ?? []) {
|
|
4545
|
+
const matched = filesToModify.filter((f) => matchesPattern(f, cp.pattern));
|
|
4546
|
+
if (matched.length > 0) {
|
|
4547
|
+
const pts = 10 * matched.length;
|
|
4548
|
+
score += pts;
|
|
4549
|
+
factors.push({ label: "Cautious path", points: pts, detail: cp.pattern });
|
|
4550
|
+
}
|
|
4551
|
+
}
|
|
4552
|
+
for (const comp of schema.components) {
|
|
4553
|
+
if (comp.stability === "STABLE") {
|
|
4554
|
+
const touchesStable = filesToModify.some(
|
|
4555
|
+
(f) => comp.paths.some((p) => matchesPattern(f, p))
|
|
4556
|
+
);
|
|
4557
|
+
if (touchesStable) {
|
|
4558
|
+
score += 5;
|
|
4559
|
+
factors.push({ label: "STABLE component", points: 5, detail: comp.name });
|
|
4560
|
+
}
|
|
4561
|
+
}
|
|
4562
|
+
}
|
|
4563
|
+
if (depCheck) {
|
|
4564
|
+
for (const impact of depCheck.impacts) {
|
|
4565
|
+
const pts = impact.rule.severity === "BLOCKER" ? 3 : impact.rule.severity === "WARNING" ? 2 : 0;
|
|
4566
|
+
if (pts > 0) {
|
|
4567
|
+
score += pts;
|
|
4568
|
+
factors.push({
|
|
4569
|
+
label: `${impact.rule.severity} dependency`,
|
|
4570
|
+
points: pts,
|
|
4571
|
+
detail: impact.rule.id
|
|
4572
|
+
});
|
|
4573
|
+
}
|
|
4574
|
+
}
|
|
4575
|
+
}
|
|
4576
|
+
const fileCount = filesToModify.length;
|
|
4577
|
+
if (fileCount > 5) {
|
|
4578
|
+
const pts = fileCount - 5;
|
|
4579
|
+
score += pts;
|
|
4580
|
+
factors.push({ label: "File complexity", points: pts, detail: `${fileCount} files (>${5})` });
|
|
4581
|
+
}
|
|
4582
|
+
score = Math.min(score, 100);
|
|
4583
|
+
const level = scoreToLevel(score);
|
|
4584
|
+
const summary = buildSummary(fileCount, factors, score, level);
|
|
4585
|
+
return { score, level, factors, fileCount, summary };
|
|
4586
|
+
}
|
|
4587
|
+
function scoreToLevel(score) {
|
|
4588
|
+
if (score <= 25) return "LOW";
|
|
4589
|
+
if (score <= 50) return "MEDIUM";
|
|
4590
|
+
if (score <= 75) return "HIGH";
|
|
4591
|
+
return "CRITICAL";
|
|
4592
|
+
}
|
|
4593
|
+
function shouldAskConfirmation(level, approvalPolicy) {
|
|
4594
|
+
if (approvalPolicy === "full_autopilot") return false;
|
|
4595
|
+
if (level === "CRITICAL") return true;
|
|
4596
|
+
if (level === "HIGH" && approvalPolicy !== "always_approve_safe_ops") return true;
|
|
4597
|
+
return false;
|
|
4598
|
+
}
|
|
4599
|
+
function buildSummary(fileCount, factors, score, level) {
|
|
4600
|
+
const parts = [`${fileCount} file${fileCount !== 1 ? "s" : ""}`];
|
|
4601
|
+
const protectedCount = factors.filter(
|
|
4602
|
+
(f) => f.label.includes("protected") || f.label.includes("Cautious")
|
|
4603
|
+
).length;
|
|
4604
|
+
if (protectedCount > 0) {
|
|
4605
|
+
parts.push(`${protectedCount} protected path${protectedCount !== 1 ? "s" : ""}`);
|
|
4606
|
+
} else {
|
|
4607
|
+
parts.push("no protected paths");
|
|
4608
|
+
}
|
|
4609
|
+
const depFactors = factors.filter((f) => f.label.includes("dependency"));
|
|
4610
|
+
if (depFactors.length > 0) {
|
|
4611
|
+
parts.push(`${depFactors.length} dep warning${depFactors.length !== 1 ? "s" : ""}`);
|
|
4612
|
+
}
|
|
4613
|
+
return parts.join(", ");
|
|
4614
|
+
}
|
|
4615
|
+
function matchesPattern(filePath, pattern) {
|
|
4616
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
4617
|
+
const normalizedPattern = pattern.replace(/\\/g, "/");
|
|
4618
|
+
if (normalizedPattern.includes("*")) {
|
|
4619
|
+
const regex = normalizedPattern.replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
4620
|
+
return new RegExp(`^${regex}`).test(normalized) || new RegExp(regex).test(normalized);
|
|
4621
|
+
}
|
|
4622
|
+
return normalized.startsWith(normalizedPattern) || normalized.includes(`/${normalizedPattern}`);
|
|
4623
|
+
}
|
|
4624
|
+
|
|
4625
|
+
// src/cli/policy.ts
|
|
4626
|
+
import chalk2 from "chalk";
|
|
4627
|
+
var DEFAULT_POLICY = {
|
|
4628
|
+
approval: "approve_this_task",
|
|
4629
|
+
sentinel: "plan_batch_only",
|
|
4630
|
+
routing: "balanced"
|
|
4631
|
+
};
|
|
4632
|
+
async function loadRuntimePolicy() {
|
|
4633
|
+
const config = await loadConfig();
|
|
4634
|
+
return {
|
|
4635
|
+
approval: config.approvalPolicy ?? DEFAULT_POLICY.approval,
|
|
4636
|
+
sentinel: config.sentinelPolicy ?? DEFAULT_POLICY.sentinel,
|
|
4637
|
+
routing: config.routingProfile ?? DEFAULT_POLICY.routing
|
|
4638
|
+
};
|
|
4639
|
+
}
|
|
4640
|
+
async function setRuntimePolicy(update) {
|
|
4641
|
+
const config = await loadConfig();
|
|
4642
|
+
const next = {
|
|
4643
|
+
approval: update.approval ?? config.approvalPolicy ?? DEFAULT_POLICY.approval,
|
|
4644
|
+
sentinel: update.sentinel ?? config.sentinelPolicy ?? DEFAULT_POLICY.sentinel,
|
|
4645
|
+
routing: update.routing ?? config.routingProfile ?? DEFAULT_POLICY.routing
|
|
4646
|
+
};
|
|
4647
|
+
await saveConfig({
|
|
4648
|
+
...config,
|
|
4649
|
+
approvalPolicy: next.approval,
|
|
4650
|
+
sentinelPolicy: next.sentinel,
|
|
4651
|
+
routingProfile: next.routing
|
|
4652
|
+
});
|
|
4653
|
+
return next;
|
|
4654
|
+
}
|
|
4655
|
+
async function showPolicy() {
|
|
4656
|
+
const policy = await loadRuntimePolicy();
|
|
4657
|
+
console.log(chalk2.green("Runtime Policy:"));
|
|
4658
|
+
console.log();
|
|
4659
|
+
console.log(` ${chalk2.blue("Approval:")} ${policy.approval}`);
|
|
4660
|
+
console.log(` ${chalk2.blue("Sentinel:")} ${policy.sentinel}`);
|
|
4661
|
+
console.log(` ${chalk2.blue("Routing:")} ${policy.routing}`);
|
|
4662
|
+
}
|
|
4663
|
+
async function setPolicy(scope, value) {
|
|
4664
|
+
if (scope === "approval") {
|
|
4665
|
+
const allowed = [
|
|
4666
|
+
"ask_every_time",
|
|
4667
|
+
"approve_this_task",
|
|
4668
|
+
"approve_this_session",
|
|
4669
|
+
"always_approve_safe_ops",
|
|
4670
|
+
"full_autopilot"
|
|
4671
|
+
];
|
|
4672
|
+
if (!allowed.includes(value)) {
|
|
4673
|
+
console.error(chalk2.red(`Invalid approval policy: ${value}`));
|
|
4674
|
+
console.log(chalk2.dim(`Valid values: ${allowed.join(", ")}`));
|
|
4675
|
+
process.exit(1);
|
|
4676
|
+
}
|
|
4677
|
+
await setRuntimePolicy({ approval: value });
|
|
4678
|
+
console.log(chalk2.green(`\u2713 approval policy set to ${value}`));
|
|
4679
|
+
return;
|
|
4680
|
+
}
|
|
4681
|
+
if (scope === "sentinel") {
|
|
4682
|
+
const allowed = ["every_atom", "plan_batch_only", "manual_only"];
|
|
4683
|
+
if (!allowed.includes(value)) {
|
|
4684
|
+
console.error(chalk2.red(`Invalid sentinel policy: ${value}`));
|
|
4685
|
+
console.log(chalk2.dim(`Valid values: ${allowed.join(", ")}`));
|
|
4686
|
+
process.exit(1);
|
|
4687
|
+
}
|
|
4688
|
+
await setRuntimePolicy({ sentinel: value });
|
|
4689
|
+
console.log(chalk2.green(`\u2713 sentinel policy set to ${value}`));
|
|
4690
|
+
return;
|
|
4691
|
+
}
|
|
4692
|
+
if (scope === "routing") {
|
|
4693
|
+
const allowed = ["cheap", "balanced", "max_quality"];
|
|
4694
|
+
if (!allowed.includes(value)) {
|
|
4695
|
+
console.error(chalk2.red(`Invalid routing profile: ${value}`));
|
|
4696
|
+
console.log(chalk2.dim(`Valid values: ${allowed.join(", ")}`));
|
|
4697
|
+
process.exit(1);
|
|
4698
|
+
}
|
|
4699
|
+
await setRuntimePolicy({ routing: value });
|
|
4700
|
+
console.log(chalk2.green(`\u2713 routing profile set to ${value}`));
|
|
4701
|
+
return;
|
|
4702
|
+
}
|
|
4703
|
+
console.error(chalk2.red(`Invalid policy scope: ${scope}`));
|
|
4704
|
+
console.log(chalk2.dim("Valid scopes: approval, sentinel, routing"));
|
|
4705
|
+
process.exit(1);
|
|
4706
|
+
}
|
|
4707
|
+
|
|
4708
|
+
// src/core/code-review/scope-drift.ts
|
|
4709
|
+
function detectScopeDrift(plannedFiles, actualFiles) {
|
|
4710
|
+
const plannedSet = new Set(plannedFiles.map((f) => f.replace(/\\/g, "/")));
|
|
4711
|
+
const unexpectedFiles = actualFiles.map((f) => f.replace(/\\/g, "/")).filter((f) => !plannedSet.has(f));
|
|
4712
|
+
if (unexpectedFiles.length === 0) return null;
|
|
4713
|
+
const driftPercentage = actualFiles.length > 0 ? unexpectedFiles.length / actualFiles.length * 100 : 0;
|
|
4714
|
+
return {
|
|
4715
|
+
plannedFiles,
|
|
4716
|
+
actualFiles,
|
|
4717
|
+
unexpectedFiles,
|
|
4718
|
+
driftPercentage
|
|
4719
|
+
};
|
|
4720
|
+
}
|
|
4721
|
+
|
|
4515
4722
|
// src/core/git/rollback.ts
|
|
4516
4723
|
import { spawnSync } from "child_process";
|
|
4517
4724
|
function rollbackFiles(cwd, files) {
|
|
@@ -4737,6 +4944,111 @@ var EnvironmentValidator = class {
|
|
|
4737
4944
|
}
|
|
4738
4945
|
};
|
|
4739
4946
|
|
|
4947
|
+
// src/core/skills/registry.ts
|
|
4948
|
+
import { existsSync as existsSync8, readdirSync } from "fs";
|
|
4949
|
+
import { join as join3, basename } from "path";
|
|
4950
|
+
import matter2 from "gray-matter";
|
|
4951
|
+
var DEFAULT_SKILL_DIRS = [
|
|
4952
|
+
join3("archondev-lite", "base", "archondev-skills"),
|
|
4953
|
+
join3(".archon", "skills")
|
|
4954
|
+
];
|
|
4955
|
+
var FRONTEND_FILE_PATTERN = /\.(tsx|jsx|css|scss|sass|html|astro|vue|svelte)$/i;
|
|
4956
|
+
var PUBLIC_WEB_FILE_PATTERN = /(?:^|\/)(?:website|web|site|public|pages|src\/pages|src\/app)(?:\/|$)|\.(?:html|astro)$/i;
|
|
4957
|
+
var API_AUTH_FILE_PATTERN = /(?:^|\/)(?:api|auth|middleware|routes|server)(?:\/|$)|\.(?:ts|tsx|js|jsx)$/i;
|
|
4958
|
+
function loadSkillRegistry(cwd) {
|
|
4959
|
+
const skills = /* @__PURE__ */ new Map();
|
|
4960
|
+
for (const relativeDir of DEFAULT_SKILL_DIRS) {
|
|
4961
|
+
const dir = join3(cwd, relativeDir);
|
|
4962
|
+
if (!existsSync8(dir)) continue;
|
|
4963
|
+
for (const entry of readdirSync(dir)) {
|
|
4964
|
+
if (!entry.endsWith(".md")) continue;
|
|
4965
|
+
const filePath = join3(dir, entry);
|
|
4966
|
+
try {
|
|
4967
|
+
const parsed = matter2.read(filePath);
|
|
4968
|
+
const slug = basename(entry, ".md");
|
|
4969
|
+
skills.set(slug, {
|
|
4970
|
+
slug,
|
|
4971
|
+
name: typeof parsed.data["name"] === "string" ? parsed.data["name"] : slug,
|
|
4972
|
+
description: typeof parsed.data["description"] === "string" ? parsed.data["description"] : "",
|
|
4973
|
+
trigger: typeof parsed.data["trigger"] === "string" ? parsed.data["trigger"] : void 0,
|
|
4974
|
+
category: typeof parsed.data["category"] === "string" ? parsed.data["category"] : void 0,
|
|
4975
|
+
filePath
|
|
4976
|
+
});
|
|
4977
|
+
} catch {
|
|
4978
|
+
}
|
|
4979
|
+
}
|
|
4980
|
+
}
|
|
4981
|
+
return Array.from(skills.values());
|
|
4982
|
+
}
|
|
4983
|
+
function suggestSkills(context) {
|
|
4984
|
+
const registry = loadSkillRegistry(context.cwd);
|
|
4985
|
+
const changedFiles = context.changedFiles ?? [];
|
|
4986
|
+
const normalizedInput = (context.input ?? "").toLowerCase();
|
|
4987
|
+
const hasFrontendChanges = changedFiles.some((file) => FRONTEND_FILE_PATTERN.test(file));
|
|
4988
|
+
const hasPublicWebChanges = changedFiles.some((file) => PUBLIC_WEB_FILE_PATTERN.test(file));
|
|
4989
|
+
const hasApiOrAuthChanges = changedFiles.some((file) => API_AUTH_FILE_PATTERN.test(file));
|
|
4990
|
+
const wantsColor = /\b(color|colour|palette|theme|branding|design tokens)\b/.test(normalizedInput);
|
|
4991
|
+
const deployIntent = /\b(deploy|ship|publish|launch|go live|release)\b/.test(normalizedInput);
|
|
4992
|
+
const reviewIntent = /\b(review|audit|qa|quality check|code review)\b/.test(normalizedInput);
|
|
4993
|
+
const debugIntent = /\b(debug|bug|broken|fix|crash|error|failing|failure|stack trace|not working)\b/.test(normalizedInput);
|
|
4994
|
+
const seoIntent = /\b(seo|meta tags|open graph|twitter cards|search visibility|google)\b/.test(normalizedInput);
|
|
4995
|
+
const geoIntent = /\b(geo|ai search|ai citations|generative engine optimization|perplexity|ai overviews)\b/.test(normalizedInput);
|
|
4996
|
+
const strategyIntent = /\b(strategy|scope|plan the project|roadmap|direction)\b/.test(normalizedInput);
|
|
4997
|
+
const suggested = /* @__PURE__ */ new Map();
|
|
4998
|
+
const scores = /* @__PURE__ */ new Map();
|
|
4999
|
+
const add = (slug, weight = 1) => {
|
|
5000
|
+
const skill = registry.find((item) => item.slug === slug);
|
|
5001
|
+
if (!skill) return;
|
|
5002
|
+
suggested.set(slug, skill);
|
|
5003
|
+
scores.set(slug, (scores.get(slug) ?? 0) + weight);
|
|
5004
|
+
};
|
|
5005
|
+
if (hasFrontendChanges) {
|
|
5006
|
+
add("design-review", 3);
|
|
5007
|
+
add("accessibility-audit", 2);
|
|
5008
|
+
}
|
|
5009
|
+
if (wantsColor) {
|
|
5010
|
+
add("color-scheme-picker", 5);
|
|
5011
|
+
}
|
|
5012
|
+
if ((deployIntent || hasFrontendChanges) && context.isWebProject) {
|
|
5013
|
+
add("accessibility-audit", 2);
|
|
5014
|
+
}
|
|
5015
|
+
if (reviewIntent) {
|
|
5016
|
+
add("code-review", 5);
|
|
5017
|
+
if (context.isWebProject || hasFrontendChanges) {
|
|
5018
|
+
add("design-review", 2);
|
|
5019
|
+
}
|
|
5020
|
+
}
|
|
5021
|
+
if (debugIntent) {
|
|
5022
|
+
add("systematic-debugging", 6);
|
|
5023
|
+
if (hasApiOrAuthChanges) {
|
|
5024
|
+
add("code-review", 2);
|
|
5025
|
+
}
|
|
5026
|
+
}
|
|
5027
|
+
if (deployIntent) {
|
|
5028
|
+
add("ship-readiness", 8);
|
|
5029
|
+
add("code-review", 3);
|
|
5030
|
+
if (context.isWebProject || hasFrontendChanges || hasPublicWebChanges) {
|
|
5031
|
+
add("accessibility-audit", 3);
|
|
5032
|
+
add("design-review", 2);
|
|
5033
|
+
}
|
|
5034
|
+
}
|
|
5035
|
+
if ((seoIntent || geoIntent) && (context.isWebProject || hasPublicWebChanges)) {
|
|
5036
|
+
add("seo-optimization", 5);
|
|
5037
|
+
}
|
|
5038
|
+
if (geoIntent && (context.isWebProject || hasPublicWebChanges)) {
|
|
5039
|
+
add("geo-optimization", 5);
|
|
5040
|
+
}
|
|
5041
|
+
if (strategyIntent) {
|
|
5042
|
+
add("project-strategy", 5);
|
|
5043
|
+
add("scope-review", 4);
|
|
5044
|
+
}
|
|
5045
|
+
return Array.from(suggested.values()).sort((a, b) => {
|
|
5046
|
+
const scoreDelta = (scores.get(b.slug) ?? 0) - (scores.get(a.slug) ?? 0);
|
|
5047
|
+
if (scoreDelta !== 0) return scoreDelta;
|
|
5048
|
+
return a.name.localeCompare(b.name);
|
|
5049
|
+
});
|
|
5050
|
+
}
|
|
5051
|
+
|
|
4740
5052
|
// src/cli/execute.ts
|
|
4741
5053
|
var ATOMS_DIR = ".archon/atoms";
|
|
4742
5054
|
function isGovernanceViolation(errorMessage) {
|
|
@@ -4766,7 +5078,7 @@ async function attemptPathScopeAutoRecovery(atom, cwd, parseSchema, options) {
|
|
|
4766
5078
|
if (allowedPaths.length === 0) {
|
|
4767
5079
|
return false;
|
|
4768
5080
|
}
|
|
4769
|
-
const { listLocalAtoms, plan } = await import("./plan-
|
|
5081
|
+
const { listLocalAtoms, plan } = await import("./plan-HBAUG3KD.js");
|
|
4770
5082
|
const before = await listLocalAtoms();
|
|
4771
5083
|
const recoveryStartedAt = Date.now();
|
|
4772
5084
|
const recoverySource = atom.description ?? atom.title;
|
|
@@ -4785,7 +5097,7 @@ Hard Constraints:
|
|
|
4785
5097
|
- Do not create files outside this base path.
|
|
4786
5098
|
- If this cannot satisfy the task, return a minimal architecture path update proposal instead of writing out-of-scope files.`;
|
|
4787
5099
|
const phaseLabel = recoveryDepth === 0 ? "scope-constrained retry" : "forced-base-path retry";
|
|
4788
|
-
console.log(
|
|
5100
|
+
console.log(chalk3.dim(`
|
|
4789
5101
|
Auto-recovery: re-planning with ${phaseLabel}...
|
|
4790
5102
|
`));
|
|
4791
5103
|
await plan(scopedRequest, { conversational: true });
|
|
@@ -4805,10 +5117,10 @@ Auto-recovery: re-planning with ${phaseLabel}...
|
|
|
4805
5117
|
replacement = after.filter((entry) => entry.status === "READY" && entry.externalId !== atom.externalId).sort(byMostRecent)[0];
|
|
4806
5118
|
}
|
|
4807
5119
|
if (!replacement) {
|
|
4808
|
-
console.log(
|
|
5120
|
+
console.log(chalk3.yellow("Auto-recovery could not find a replacement READY atom to retry."));
|
|
4809
5121
|
return false;
|
|
4810
5122
|
}
|
|
4811
|
-
console.log(
|
|
5123
|
+
console.log(chalk3.dim(`Auto-recovery: retrying with ${replacement.externalId}...
|
|
4812
5124
|
`));
|
|
4813
5125
|
await execute(replacement.externalId, { ...options, autoRecoverDepth: recoveryDepth + 1, nonTerminating: true });
|
|
4814
5126
|
return true;
|
|
@@ -4834,7 +5146,7 @@ async function execute(atomId, options) {
|
|
|
4834
5146
|
process.exit(1);
|
|
4835
5147
|
};
|
|
4836
5148
|
if (options.parallel && options.parallel.length > 0) {
|
|
4837
|
-
const { parallelExecute } = await import("./parallel-
|
|
5149
|
+
const { parallelExecute } = await import("./parallel-4PXJA2QD.js");
|
|
4838
5150
|
const allAtomIds = [atomId, ...options.parallel];
|
|
4839
5151
|
await parallelExecute(allAtomIds, { skipGates: options.skipGates === true });
|
|
4840
5152
|
return;
|
|
@@ -4844,50 +5156,50 @@ async function execute(atomId, options) {
|
|
|
4844
5156
|
const concise = options.conciseOutput === true;
|
|
4845
5157
|
const debugPath = getDebugLogPath();
|
|
4846
5158
|
if (debugPath) {
|
|
4847
|
-
console.log(
|
|
5159
|
+
console.log(chalk3.dim(`Debug logging enabled: ${debugPath}`));
|
|
4848
5160
|
}
|
|
4849
5161
|
debugLog("execute", "start", "Execute command started", { atomId, options });
|
|
4850
5162
|
try {
|
|
4851
5163
|
if (options.cloud) {
|
|
4852
|
-
console.log(
|
|
4853
|
-
console.log(
|
|
5164
|
+
console.log(chalk3.yellow("\nCloud execution is disabled in the free/BYOK model."));
|
|
5165
|
+
console.log(chalk3.dim("Run without --cloud to execute locally using your configured provider keys."));
|
|
4854
5166
|
return;
|
|
4855
5167
|
}
|
|
4856
5168
|
if (!concise) {
|
|
4857
|
-
console.log(
|
|
5169
|
+
console.log(chalk3.dim(`Loading atom ${atomId}...`));
|
|
4858
5170
|
}
|
|
4859
5171
|
let atom = await loadAtom(atomId);
|
|
4860
5172
|
if (!atom) {
|
|
4861
|
-
console.error(
|
|
4862
|
-
console.log(
|
|
5173
|
+
console.error(chalk3.red(`Atom ${atomId} not found.`));
|
|
5174
|
+
console.log(chalk3.dim(`Use "archon list" to see available atoms.`));
|
|
4863
5175
|
return fail();
|
|
4864
5176
|
}
|
|
4865
5177
|
const envLoader = new EnvironmentConfigLoader(cwd);
|
|
4866
5178
|
const targetEnvName = options.env ?? "development";
|
|
4867
5179
|
if (!envLoader.isValidEnvironment(targetEnvName)) {
|
|
4868
|
-
console.error(
|
|
4869
|
-
console.log(
|
|
5180
|
+
console.error(chalk3.red(`Invalid environment: ${targetEnvName}`));
|
|
5181
|
+
console.log(chalk3.dim("Valid environments: development, staging, production"));
|
|
4870
5182
|
return fail();
|
|
4871
5183
|
}
|
|
4872
5184
|
const envConfigs = await envLoader.loadConfig();
|
|
4873
5185
|
const envConfig = envLoader.getEnvironmentConfig(envConfigs, targetEnvName);
|
|
4874
5186
|
const validator = new EnvironmentValidator(envConfigs);
|
|
4875
5187
|
if (!concise) {
|
|
4876
|
-
console.log(
|
|
5188
|
+
console.log(chalk3.dim(`Environment: ${targetEnvName}`));
|
|
4877
5189
|
}
|
|
4878
5190
|
const envState = await loadAtomEnvironmentState(atomId, cwd);
|
|
4879
5191
|
const executionCheck = validator.canExecuteInEnvironment(atom, targetEnvName, envState?.lastExecutedEnv);
|
|
4880
5192
|
if (!executionCheck.allowed) {
|
|
4881
|
-
console.error(
|
|
5193
|
+
console.error(chalk3.red(executionCheck.reason ?? "Execution not allowed"));
|
|
4882
5194
|
return fail();
|
|
4883
5195
|
}
|
|
4884
5196
|
if (atom.status === "DONE" && targetEnvName === envState?.lastExecutedEnv) {
|
|
4885
|
-
console.log(
|
|
5197
|
+
console.log(chalk3.yellow(`Atom ${atomId} has already been executed in ${targetEnvName}.`));
|
|
4886
5198
|
return;
|
|
4887
5199
|
}
|
|
4888
5200
|
if (atom.status === "IN_PROGRESS") {
|
|
4889
5201
|
if (!options.resumeInProgress) {
|
|
4890
|
-
console.log(
|
|
5202
|
+
console.log(chalk3.yellow(`Atom ${atomId} is already in progress.`));
|
|
4891
5203
|
const answer = await prompt.ask("Continue anyway? (y/N): ");
|
|
4892
5204
|
if (answer.toLowerCase() !== "y") {
|
|
4893
5205
|
return;
|
|
@@ -4895,39 +5207,77 @@ async function execute(atomId, options) {
|
|
|
4895
5207
|
}
|
|
4896
5208
|
}
|
|
4897
5209
|
if (atom.status !== "READY" && atom.status !== "IN_PROGRESS" && atom.status !== "DONE") {
|
|
4898
|
-
console.error(
|
|
4899
|
-
console.log(
|
|
5210
|
+
console.error(chalk3.red(`Atom ${atomId} is not ready for execution.`));
|
|
5211
|
+
console.log(chalk3.dim(`Status: ${atom.status}. Only READY or DONE atoms can be executed.`));
|
|
4900
5212
|
return fail();
|
|
4901
5213
|
}
|
|
4902
5214
|
if (!atom.plan) {
|
|
4903
|
-
console.error(
|
|
4904
|
-
console.log(
|
|
5215
|
+
console.error(chalk3.red(`Atom ${atomId} has no plan.`));
|
|
5216
|
+
console.log(chalk3.dim(`Run "archon plan" to create a plan first.`));
|
|
4905
5217
|
return fail();
|
|
4906
5218
|
}
|
|
4907
5219
|
const atomContext = atom.context;
|
|
4908
5220
|
const designApproved = atomContext?.["designApproved"] === true;
|
|
4909
5221
|
if (!designApproved) {
|
|
4910
|
-
console.log(
|
|
5222
|
+
console.log(chalk3.yellow("\n[!] This atom does not record explicit design approval metadata."));
|
|
4911
5223
|
const proceed = await prompt.ask("Proceed with execution anyway? (y/N): ");
|
|
4912
5224
|
if (proceed.trim().toLowerCase() !== "y") {
|
|
4913
|
-
console.log(
|
|
5225
|
+
console.log(chalk3.dim("Execution cancelled. Re-run planning and approve design first."));
|
|
4914
5226
|
return;
|
|
4915
5227
|
}
|
|
4916
5228
|
}
|
|
4917
|
-
const archPath =
|
|
4918
|
-
if (!
|
|
4919
|
-
console.error(
|
|
5229
|
+
const archPath = join4(cwd, "ARCHITECTURE.md");
|
|
5230
|
+
if (!existsSync9(archPath)) {
|
|
5231
|
+
console.error(chalk3.red("ARCHITECTURE.md not found."));
|
|
4920
5232
|
return fail();
|
|
4921
5233
|
}
|
|
4922
5234
|
const parser = new ArchitectureParser(archPath);
|
|
4923
5235
|
const parseResult = await parser.parse();
|
|
4924
5236
|
if (!parseResult.success || !parseResult.schema) {
|
|
4925
|
-
console.error(
|
|
5237
|
+
console.error(chalk3.red("Failed to parse ARCHITECTURE.md."));
|
|
4926
5238
|
return fail();
|
|
4927
5239
|
}
|
|
5240
|
+
if (atom.plan?.files_to_modify) {
|
|
5241
|
+
let depCheckResult;
|
|
5242
|
+
try {
|
|
5243
|
+
const depParser = new DependencyParser(cwd);
|
|
5244
|
+
if (depParser.exists()) {
|
|
5245
|
+
depCheckResult = await depParser.checkFiles(atom.plan.files_to_modify);
|
|
5246
|
+
}
|
|
5247
|
+
} catch {
|
|
5248
|
+
}
|
|
5249
|
+
const riskAssessment = computeRiskScore(
|
|
5250
|
+
atom.plan.files_to_modify,
|
|
5251
|
+
parseResult.schema,
|
|
5252
|
+
depCheckResult
|
|
5253
|
+
);
|
|
5254
|
+
const riskColors = {
|
|
5255
|
+
LOW: chalk3.green,
|
|
5256
|
+
MEDIUM: chalk3.yellow,
|
|
5257
|
+
HIGH: chalk3.hex("#FF8C00"),
|
|
5258
|
+
CRITICAL: chalk3.red
|
|
5259
|
+
};
|
|
5260
|
+
const colorFn = riskColors[riskAssessment.level] ?? chalk3.dim;
|
|
5261
|
+
if (!concise) {
|
|
5262
|
+
console.log(colorFn(`Risk: ${riskAssessment.score}/100 (${riskAssessment.level}) \u2014 ${riskAssessment.summary}`));
|
|
5263
|
+
}
|
|
5264
|
+
if (shouldAskConfirmation(riskAssessment.level, "ask_every_time")) {
|
|
5265
|
+
try {
|
|
5266
|
+
const policy = await loadRuntimePolicy();
|
|
5267
|
+
if (shouldAskConfirmation(riskAssessment.level, policy.approval)) {
|
|
5268
|
+
const answer = await prompt.ask("High-risk execution. Proceed? (Y/n): ");
|
|
5269
|
+
if (answer.toLowerCase() === "n") {
|
|
5270
|
+
console.log(chalk3.dim("Execution aborted."));
|
|
5271
|
+
return;
|
|
5272
|
+
}
|
|
5273
|
+
}
|
|
5274
|
+
} catch {
|
|
5275
|
+
}
|
|
5276
|
+
}
|
|
5277
|
+
}
|
|
4928
5278
|
if (!options.skipConflictCheck) {
|
|
4929
5279
|
if (!concise) {
|
|
4930
|
-
console.log(
|
|
5280
|
+
console.log(chalk3.dim("\nChecking for conflicts..."));
|
|
4931
5281
|
}
|
|
4932
5282
|
const conflictChecker = new ConflictChecker(parseResult.schema);
|
|
4933
5283
|
const conflictReport = await conflictChecker.checkConflicts(atom.plan, {
|
|
@@ -4935,48 +5285,48 @@ async function execute(atomId, options) {
|
|
|
4935
5285
|
planCreatedAt: atom.createdAt
|
|
4936
5286
|
});
|
|
4937
5287
|
if (conflictReport.hasConflicts) {
|
|
4938
|
-
console.log(
|
|
5288
|
+
console.log(chalk3.yellow(`
|
|
4939
5289
|
[!] ${conflictReport.conflicts.length} conflict(s) detected:`));
|
|
4940
5290
|
for (const conflict of conflictReport.conflicts) {
|
|
4941
|
-
const icon = conflict.severity === "BLOCKER" ?
|
|
5291
|
+
const icon = conflict.severity === "BLOCKER" ? chalk3.red("\u2717") : chalk3.yellow("[!]");
|
|
4942
5292
|
console.log(` ${icon} [${conflict.type}] ${conflict.message}`);
|
|
4943
5293
|
}
|
|
4944
5294
|
if (conflictReport.blockerCount > 0) {
|
|
4945
|
-
console.log(
|
|
5295
|
+
console.log(chalk3.red(`
|
|
4946
5296
|
${conflictReport.blockerCount} blocking conflict(s) found.`));
|
|
4947
5297
|
const answer = await prompt.ask("Continue anyway? (y/N): ");
|
|
4948
5298
|
if (answer.toLowerCase() !== "y") {
|
|
4949
|
-
console.log(
|
|
5299
|
+
console.log(chalk3.dim("Execution aborted."));
|
|
4950
5300
|
return;
|
|
4951
5301
|
}
|
|
4952
5302
|
} else {
|
|
4953
|
-
console.log(
|
|
5303
|
+
console.log(chalk3.dim("\nRecommendations:"));
|
|
4954
5304
|
for (const rec of conflictReport.recommendations) {
|
|
4955
|
-
console.log(
|
|
5305
|
+
console.log(chalk3.dim(` - ${rec}`));
|
|
4956
5306
|
}
|
|
4957
5307
|
}
|
|
4958
5308
|
} else if (!concise) {
|
|
4959
|
-
console.log(
|
|
5309
|
+
console.log(chalk3.green("\u2713 No conflicts detected"));
|
|
4960
5310
|
}
|
|
4961
5311
|
}
|
|
4962
5312
|
try {
|
|
4963
5313
|
atom = transitionAtom(atom, "IN_PROGRESS");
|
|
4964
5314
|
} catch (error) {
|
|
4965
|
-
console.error(
|
|
4966
|
-
console.error(
|
|
5315
|
+
console.error(chalk3.red("Failed to update atom status."));
|
|
5316
|
+
console.error(chalk3.dim(error instanceof Error ? error.message : "Unknown error"));
|
|
4967
5317
|
return fail();
|
|
4968
5318
|
}
|
|
4969
5319
|
await saveAtom(atom);
|
|
4970
5320
|
if (!concise) {
|
|
4971
|
-
console.log(
|
|
5321
|
+
console.log(chalk3.blue("\n\u{1F680} Executing plan..."));
|
|
4972
5322
|
}
|
|
4973
5323
|
const roleOverrides = await loadRoleOverrides(cwd);
|
|
4974
5324
|
const keyManager = new KeyManager();
|
|
4975
5325
|
const apiKeys = await resolveApiKeys(keyManager);
|
|
4976
5326
|
const hasAnyKey = !!apiKeys.anthropic || !!apiKeys.openai || !!apiKeys.google;
|
|
4977
5327
|
if (!hasAnyKey) {
|
|
4978
|
-
console.log(
|
|
4979
|
-
console.log(
|
|
5328
|
+
console.log(chalk3.red("\nNo API key configured for execution."));
|
|
5329
|
+
console.log(chalk3.dim("Add a provider key with: archon keys add"));
|
|
4980
5330
|
return fail();
|
|
4981
5331
|
}
|
|
4982
5332
|
const defaultProvider = pickDefaultProvider(apiKeys, roleOverrides?.executor?.provider);
|
|
@@ -4988,8 +5338,8 @@ ${conflictReport.blockerCount} blocking conflict(s) found.`));
|
|
|
4988
5338
|
);
|
|
4989
5339
|
const safeProvider = pickAvailableProvider(apiKeys, executorProvider);
|
|
4990
5340
|
if (!safeProvider) {
|
|
4991
|
-
console.log(
|
|
4992
|
-
console.log(
|
|
5341
|
+
console.log(chalk3.red("\nNo valid API key available for execution."));
|
|
5342
|
+
console.log(chalk3.dim("Add a provider key with: archon keys add"));
|
|
4993
5343
|
return fail();
|
|
4994
5344
|
}
|
|
4995
5345
|
const executorModel = normalizeModelForProvider(roleOverrides?.executor?.model, safeProvider);
|
|
@@ -4999,6 +5349,16 @@ ${conflictReport.blockerCount} blocking conflict(s) found.`));
|
|
|
4999
5349
|
};
|
|
5000
5350
|
const executor = new ExecutorAgent(executorConfig, apiKeys);
|
|
5001
5351
|
const executionResult = await executor.executeAtom(atom, atom.plan, parseResult.schema, cwd);
|
|
5352
|
+
await appendLocalUsageEntry({
|
|
5353
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5354
|
+
projectPath: cwd,
|
|
5355
|
+
model: executorModel,
|
|
5356
|
+
provider: safeProvider,
|
|
5357
|
+
operation: "EXECUTION",
|
|
5358
|
+
inputTokens: executionResult.usage.inputTokens,
|
|
5359
|
+
outputTokens: executionResult.usage.outputTokens,
|
|
5360
|
+
baseCost: executionResult.usage.baseCost
|
|
5361
|
+
});
|
|
5002
5362
|
debugLog("execute", "result.received", "Executor returned execution result", {
|
|
5003
5363
|
success: executionResult.success,
|
|
5004
5364
|
rollbackPerformed: executionResult.rollbackPerformed,
|
|
@@ -5016,27 +5376,27 @@ ${conflictReport.blockerCount} blocking conflict(s) found.`));
|
|
|
5016
5376
|
plannedFiles: atom.plan.files_to_modify,
|
|
5017
5377
|
violations: extractGovernanceViolations(executionResult.errorMessage)
|
|
5018
5378
|
});
|
|
5019
|
-
console.log(
|
|
5020
|
-
console.log(
|
|
5379
|
+
console.log(chalk3.yellow("\n\u26A0\uFE0F Execution paused by governance guidance"));
|
|
5380
|
+
console.log(chalk3.dim("No changes were committed. Update the plan/path scope, then continue."));
|
|
5021
5381
|
const violations = extractGovernanceViolations(executionResult.errorMessage);
|
|
5022
5382
|
const pathScopeBlocked = violations.some((violation) => violation.toLowerCase().includes("outside the allowed paths"));
|
|
5023
5383
|
if (violations.length > 0) {
|
|
5024
|
-
console.log(
|
|
5384
|
+
console.log(chalk3.yellow("\nGovernance guidance:"));
|
|
5025
5385
|
for (const violation of violations) {
|
|
5026
|
-
console.log(
|
|
5386
|
+
console.log(chalk3.dim(` - ${violation}`));
|
|
5027
5387
|
}
|
|
5028
5388
|
if (pathScopeBlocked) {
|
|
5029
|
-
console.log(
|
|
5389
|
+
console.log(chalk3.dim('\nTry in chat: "adjust this task to allowed paths", then "continue".'));
|
|
5030
5390
|
}
|
|
5031
5391
|
} else {
|
|
5032
|
-
console.log(
|
|
5392
|
+
console.log(chalk3.yellow(executionResult.errorMessage ?? "Architecture constraints were not satisfied."));
|
|
5033
5393
|
}
|
|
5034
5394
|
} else {
|
|
5035
|
-
console.log(
|
|
5036
|
-
console.log(
|
|
5395
|
+
console.log(chalk3.red("\n\u274C Execution failed"));
|
|
5396
|
+
console.log(chalk3.red(executionResult.errorMessage ?? "Unknown error"));
|
|
5037
5397
|
}
|
|
5038
5398
|
if (executionResult.rollbackPerformed) {
|
|
5039
|
-
console.log(
|
|
5399
|
+
console.log(chalk3.yellow("Changes have been rolled back."));
|
|
5040
5400
|
}
|
|
5041
5401
|
if (isGovernanceViolation(executionResult.errorMessage)) {
|
|
5042
5402
|
atom = transitionAtom(atom, "BLOCKED");
|
|
@@ -5086,18 +5446,32 @@ ${conflictReport.blockerCount} blocking conflict(s) found.`));
|
|
|
5086
5446
|
return fail();
|
|
5087
5447
|
}
|
|
5088
5448
|
if (!concise) {
|
|
5089
|
-
console.log(
|
|
5090
|
-
console.log(
|
|
5449
|
+
console.log(chalk3.green("\u2713 Plan executed successfully"));
|
|
5450
|
+
console.log(chalk3.dim(`Files modified: ${filesChanged.length}`));
|
|
5091
5451
|
for (const file of filesChanged) {
|
|
5092
|
-
console.log(
|
|
5452
|
+
console.log(chalk3.dim(` - ${file}`));
|
|
5093
5453
|
}
|
|
5094
5454
|
}
|
|
5095
5455
|
await printDeliverablePreview(cwd, filesChanged, concise);
|
|
5456
|
+
if (atom.plan?.files_to_modify) {
|
|
5457
|
+
const drift = detectScopeDrift(atom.plan.files_to_modify, filesChanged);
|
|
5458
|
+
if (drift) {
|
|
5459
|
+
console.log(chalk3.yellow(`Scope drift: ${drift.unexpectedFiles.length} file(s) outside plan (${drift.driftPercentage.toFixed(0)}%)`));
|
|
5460
|
+
for (const f of drift.unexpectedFiles.slice(0, 5)) {
|
|
5461
|
+
console.log(chalk3.dim(` + ${f}`));
|
|
5462
|
+
}
|
|
5463
|
+
if (drift.unexpectedFiles.length > 5) {
|
|
5464
|
+
console.log(chalk3.dim(` ... and ${drift.unexpectedFiles.length - 5} more`));
|
|
5465
|
+
}
|
|
5466
|
+
} else if (!concise) {
|
|
5467
|
+
console.log(chalk3.green("\u2713 Scope check: clean"));
|
|
5468
|
+
}
|
|
5469
|
+
}
|
|
5096
5470
|
if (!options.skipGates) {
|
|
5097
5471
|
if (!concise) {
|
|
5098
|
-
console.log(
|
|
5472
|
+
console.log(chalk3.dim(`
|
|
5099
5473
|
Running quality gates for ${targetEnvName}...`));
|
|
5100
|
-
console.log(
|
|
5474
|
+
console.log(chalk3.dim(`Gates: ${envConfig.qualityGates.join(", ")}`));
|
|
5101
5475
|
}
|
|
5102
5476
|
const gateRunner = new QualityGateRunner({ cwd, verbose: false });
|
|
5103
5477
|
const gateResult = await gateRunner.runGates(envConfig.qualityGates);
|
|
@@ -5105,14 +5479,14 @@ Running quality gates for ${targetEnvName}...`));
|
|
|
5105
5479
|
gateRunner.printResults(gateResult);
|
|
5106
5480
|
}
|
|
5107
5481
|
if (!gateResult.allPassed) {
|
|
5108
|
-
console.log(
|
|
5109
|
-
console.log(
|
|
5482
|
+
console.log(chalk3.red("\n\u274C Quality gates failed"));
|
|
5483
|
+
console.log(chalk3.yellow("Rolling back changes..."));
|
|
5110
5484
|
try {
|
|
5111
5485
|
rollbackFiles(cwd, filesChanged);
|
|
5112
|
-
console.log(
|
|
5486
|
+
console.log(chalk3.yellow("Changes rolled back (scoped to atom files)."));
|
|
5113
5487
|
} catch (error) {
|
|
5114
|
-
console.log(
|
|
5115
|
-
console.log(
|
|
5488
|
+
console.log(chalk3.red("Failed to rollback. Please manually revert changes."));
|
|
5489
|
+
console.log(chalk3.dim(error instanceof Error ? error.message : "Unknown rollback error"));
|
|
5116
5490
|
}
|
|
5117
5491
|
atom = transitionAtom(atom, "FAILED");
|
|
5118
5492
|
atom.errorMessage = `Quality gate failed: ${gateResult.failedAt}`;
|
|
@@ -5133,7 +5507,7 @@ Running quality gates for ${targetEnvName}...`));
|
|
|
5133
5507
|
}
|
|
5134
5508
|
}
|
|
5135
5509
|
if (!concise) {
|
|
5136
|
-
console.log(
|
|
5510
|
+
console.log(chalk3.dim("\nCommitting changes..."));
|
|
5137
5511
|
}
|
|
5138
5512
|
try {
|
|
5139
5513
|
const commitMessage = `feat: [${atom.externalId}] - ${atom.title}`;
|
|
@@ -5146,10 +5520,10 @@ Running quality gates for ${targetEnvName}...`));
|
|
|
5146
5520
|
throw new Error(commitResult.stderr?.toString() || "git commit failed");
|
|
5147
5521
|
}
|
|
5148
5522
|
if (!concise) {
|
|
5149
|
-
console.log(
|
|
5523
|
+
console.log(chalk3.green(`\u2713 Committed: ${commitMessage}`));
|
|
5150
5524
|
}
|
|
5151
5525
|
} catch (error) {
|
|
5152
|
-
console.log(
|
|
5526
|
+
console.log(chalk3.yellow("No changes to commit or git commit failed."));
|
|
5153
5527
|
}
|
|
5154
5528
|
atom = transitionAtom(atom, "TESTING");
|
|
5155
5529
|
atom = transitionAtom(atom, "DONE");
|
|
@@ -5159,7 +5533,7 @@ Running quality gates for ${targetEnvName}...`));
|
|
|
5159
5533
|
promotedTo: envState?.promotedTo ?? []
|
|
5160
5534
|
});
|
|
5161
5535
|
if (!concise) {
|
|
5162
|
-
console.log(
|
|
5536
|
+
console.log(chalk3.dim("\nCapturing learnings..."));
|
|
5163
5537
|
}
|
|
5164
5538
|
const executionSummary = {
|
|
5165
5539
|
atomId: atom.id,
|
|
@@ -5173,9 +5547,9 @@ Running quality gates for ${targetEnvName}...`));
|
|
|
5173
5547
|
const verifyLearning = options.verifyLearning !== false;
|
|
5174
5548
|
if (verifyLearning && !concise) {
|
|
5175
5549
|
if (learningResult.success && learningResult.entriesAdded > 0) {
|
|
5176
|
-
console.log(
|
|
5550
|
+
console.log(chalk3.green("\u2713 Learning captured to progress.txt"));
|
|
5177
5551
|
} else {
|
|
5178
|
-
console.log(
|
|
5552
|
+
console.log(chalk3.yellow("[!] No learnings captured to progress.txt"));
|
|
5179
5553
|
}
|
|
5180
5554
|
}
|
|
5181
5555
|
const agentsMdUpdater = new AgentsMdUpdater(cwd);
|
|
@@ -5183,20 +5557,31 @@ Running quality gates for ${targetEnvName}...`));
|
|
|
5183
5557
|
if (verifyLearning && !concise) {
|
|
5184
5558
|
const agentsMdCount = agentsMdResult.filesCreated.length + agentsMdResult.filesUpdated.length;
|
|
5185
5559
|
if (agentsMdCount === 0) {
|
|
5186
|
-
console.log(
|
|
5560
|
+
console.log(chalk3.yellow("[!] No AGENTS.md updates (no reusable patterns found)"));
|
|
5187
5561
|
} else {
|
|
5188
|
-
console.log(
|
|
5562
|
+
console.log(chalk3.green(`\u2713 Updated ${agentsMdCount} AGENTS.md file(s)`));
|
|
5189
5563
|
}
|
|
5190
5564
|
} else if (!concise && (agentsMdResult.filesCreated.length > 0 || agentsMdResult.filesUpdated.length > 0)) {
|
|
5191
|
-
console.log(
|
|
5565
|
+
console.log(chalk3.dim(`Updated ${agentsMdResult.filesUpdated.length + agentsMdResult.filesCreated.length} AGENTS.md file(s)`));
|
|
5566
|
+
}
|
|
5567
|
+
const suggestedSkills = suggestSkills({
|
|
5568
|
+
cwd,
|
|
5569
|
+
changedFiles: filesChanged,
|
|
5570
|
+
isWebProject: filesChanged.some((file) => /\.(tsx|jsx|css|scss|sass|html|astro|vue|svelte)$/i.test(file))
|
|
5571
|
+
});
|
|
5572
|
+
if (!concise && suggestedSkills.length > 0) {
|
|
5573
|
+
console.log(chalk3.dim("\nHelpful skills you may want next:"));
|
|
5574
|
+
for (const skill of suggestedSkills.slice(0, 3)) {
|
|
5575
|
+
console.log(chalk3.dim(` - ${skill.name}: ${skill.description}`));
|
|
5576
|
+
}
|
|
5192
5577
|
}
|
|
5193
5578
|
if (concise) {
|
|
5194
|
-
console.log(
|
|
5579
|
+
console.log(chalk3.green("\n\u2713 Done."));
|
|
5195
5580
|
} else {
|
|
5196
|
-
console.log(
|
|
5197
|
-
console.log(
|
|
5198
|
-
console.log(
|
|
5199
|
-
console.log(
|
|
5581
|
+
console.log(chalk3.green("\n\u2705 Atom executed successfully!"));
|
|
5582
|
+
console.log(chalk3.dim(`Atom: ${atom.externalId}`));
|
|
5583
|
+
console.log(chalk3.dim(`Status: ${atom.status}`));
|
|
5584
|
+
console.log(chalk3.dim(`Files changed: ${filesChanged.length}`));
|
|
5200
5585
|
printExecuteNextActions(atom.externalId, true);
|
|
5201
5586
|
}
|
|
5202
5587
|
} finally {
|
|
@@ -5265,27 +5650,27 @@ function normalizeApiKey(value) {
|
|
|
5265
5650
|
}
|
|
5266
5651
|
function printExecuteNextActions(atomExternalId, success, context = "generic") {
|
|
5267
5652
|
console.log();
|
|
5268
|
-
console.log(
|
|
5653
|
+
console.log(chalk3.bold("Next best action:"));
|
|
5269
5654
|
if (success) {
|
|
5270
|
-
console.log(
|
|
5655
|
+
console.log(chalk3.dim(` \u2022 Run ${chalk3.cyan("archon list")} to select your next task.`));
|
|
5271
5656
|
} else {
|
|
5272
5657
|
if (context === "governance_path") {
|
|
5273
|
-
console.log(
|
|
5274
|
-
console.log(
|
|
5275
|
-
console.log(
|
|
5658
|
+
console.log(chalk3.dim(` \u2022 In chat, say ${chalk3.cyan('"adjust this task to allowed paths"')} to re-scope automatically.`));
|
|
5659
|
+
console.log(chalk3.dim(` \u2022 Then say ${chalk3.cyan('"continue"')} to execute the re-scoped task.`));
|
|
5660
|
+
console.log(chalk3.dim(` \u2022 Run ${chalk3.cyan(`archon show ${atomExternalId}`)} to inspect the blocked task.`));
|
|
5276
5661
|
return;
|
|
5277
5662
|
}
|
|
5278
|
-
console.log(
|
|
5663
|
+
console.log(chalk3.dim(` \u2022 Run ${chalk3.cyan(`archon show ${atomExternalId}`)} to inspect this task.`));
|
|
5279
5664
|
}
|
|
5280
|
-
console.log(
|
|
5281
|
-
console.log(
|
|
5665
|
+
console.log(chalk3.dim(` \u2022 Run ${chalk3.cyan("archon config ai")} to add/rotate provider keys.`));
|
|
5666
|
+
console.log(chalk3.dim(` \u2022 Run ${chalk3.cyan("archon preferences")} to tune model routing.`));
|
|
5282
5667
|
}
|
|
5283
5668
|
async function printDeliverablePreview(cwd, filesChanged, concise = false) {
|
|
5284
5669
|
const previewTarget = filesChanged.find((file) => /\.md$/i.test(file));
|
|
5285
5670
|
if (!previewTarget) {
|
|
5286
5671
|
return;
|
|
5287
5672
|
}
|
|
5288
|
-
const absolutePath =
|
|
5673
|
+
const absolutePath = join4(cwd, previewTarget);
|
|
5289
5674
|
try {
|
|
5290
5675
|
const content = await readFile7(absolutePath, "utf-8");
|
|
5291
5676
|
const previewLines = content.split("\n").map((line) => line.trimEnd()).filter((line) => line.trim().length > 0).slice(0, 8);
|
|
@@ -5293,20 +5678,20 @@ async function printDeliverablePreview(cwd, filesChanged, concise = false) {
|
|
|
5293
5678
|
return;
|
|
5294
5679
|
}
|
|
5295
5680
|
if (concise) {
|
|
5296
|
-
console.log(
|
|
5681
|
+
console.log(chalk3.dim(`Output: ${absolutePath}`));
|
|
5297
5682
|
return;
|
|
5298
5683
|
}
|
|
5299
|
-
console.log(
|
|
5300
|
-
console.log(
|
|
5684
|
+
console.log(chalk3.bold("\nDeliverable preview:"));
|
|
5685
|
+
console.log(chalk3.dim(` Output file: ${absolutePath}`));
|
|
5301
5686
|
for (const line of previewLines) {
|
|
5302
|
-
console.log(
|
|
5687
|
+
console.log(chalk3.dim(` ${line}`));
|
|
5303
5688
|
}
|
|
5304
5689
|
} catch {
|
|
5305
5690
|
}
|
|
5306
5691
|
}
|
|
5307
5692
|
async function saveAtom(atom) {
|
|
5308
|
-
const atomsDir =
|
|
5309
|
-
const atomFile =
|
|
5693
|
+
const atomsDir = join4(process.cwd(), ATOMS_DIR);
|
|
5694
|
+
const atomFile = join4(atomsDir, `${atom.externalId}.json`);
|
|
5310
5695
|
await writeFile4(atomFile, JSON.stringify(atom, null, 2));
|
|
5311
5696
|
}
|
|
5312
5697
|
async function captureLearnings(atom, execution, concise = false) {
|
|
@@ -5314,12 +5699,12 @@ async function captureLearnings(atom, execution, concise = false) {
|
|
|
5314
5699
|
const learningCapture = new LearningCapture("progress.txt");
|
|
5315
5700
|
const result = await learningCapture.appendLearning(atom, execution);
|
|
5316
5701
|
if (result.success && !concise) {
|
|
5317
|
-
console.log(
|
|
5702
|
+
console.log(chalk3.dim(`Learnings captured: ${result.entriesAdded} entries, ${result.patternsAdded} patterns`));
|
|
5318
5703
|
}
|
|
5319
5704
|
return result;
|
|
5320
5705
|
} catch (error) {
|
|
5321
5706
|
if (!concise) {
|
|
5322
|
-
console.log(
|
|
5707
|
+
console.log(chalk3.dim("Failed to capture learnings (non-critical)."));
|
|
5323
5708
|
}
|
|
5324
5709
|
return {
|
|
5325
5710
|
success: false,
|
|
@@ -5331,21 +5716,25 @@ async function captureLearnings(atom, execution, concise = false) {
|
|
|
5331
5716
|
}
|
|
5332
5717
|
}
|
|
5333
5718
|
async function loadAtomEnvironmentState(atomId, cwd) {
|
|
5334
|
-
const stateFile =
|
|
5335
|
-
if (!
|
|
5719
|
+
const stateFile = join4(cwd, ATOMS_DIR, `${atomId}.env.json`);
|
|
5720
|
+
if (!existsSync9(stateFile)) {
|
|
5336
5721
|
return null;
|
|
5337
5722
|
}
|
|
5338
5723
|
const content = await readFile7(stateFile, "utf-8");
|
|
5339
5724
|
return JSON.parse(content);
|
|
5340
5725
|
}
|
|
5341
5726
|
async function saveAtomEnvironmentState(atomId, cwd, state) {
|
|
5342
|
-
const stateFile =
|
|
5727
|
+
const stateFile = join4(cwd, ATOMS_DIR, `${atomId}.env.json`);
|
|
5343
5728
|
await writeFile4(stateFile, JSON.stringify(state, null, 2));
|
|
5344
5729
|
}
|
|
5345
5730
|
|
|
5346
5731
|
export {
|
|
5347
5732
|
DependencyParser,
|
|
5733
|
+
loadRuntimePolicy,
|
|
5734
|
+
showPolicy,
|
|
5735
|
+
setPolicy,
|
|
5348
5736
|
EnvironmentConfigLoader,
|
|
5349
5737
|
EnvironmentValidator,
|
|
5738
|
+
suggestSkills,
|
|
5350
5739
|
execute
|
|
5351
5740
|
};
|