archondev 2.19.57 → 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.
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  loadAtom,
3
3
  loadRoleOverrides
4
- } from "./chunk-OHIN6OHU.js";
4
+ } from "./chunk-7RXZTPXY.js";
5
5
  import {
6
+ appendLocalUsageEntry,
6
7
  debugLog,
7
8
  getDebugLogPath
8
- } from "./chunk-R664NEAA.js";
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 chalk2 from "chalk";
2855
- import { existsSync as existsSync8 } from "fs";
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 join3 } from "path";
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-WBNGP2UE.js");
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(chalk2.dim(`
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(chalk2.yellow("Auto-recovery could not find a replacement READY atom to retry."));
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(chalk2.dim(`Auto-recovery: retrying with ${replacement.externalId}...
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-T37FF7GD.js");
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(chalk2.dim(`Debug logging enabled: ${debugPath}`));
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(chalk2.yellow("\nCloud execution is disabled in the free/BYOK model."));
4853
- console.log(chalk2.dim("Run without --cloud to execute locally using your configured provider keys."));
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(chalk2.dim(`Loading atom ${atomId}...`));
5169
+ console.log(chalk3.dim(`Loading atom ${atomId}...`));
4858
5170
  }
4859
5171
  let atom = await loadAtom(atomId);
4860
5172
  if (!atom) {
4861
- console.error(chalk2.red(`Atom ${atomId} not found.`));
4862
- console.log(chalk2.dim(`Use "archon list" to see available atoms.`));
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(chalk2.red(`Invalid environment: ${targetEnvName}`));
4869
- console.log(chalk2.dim("Valid environments: development, staging, production"));
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(chalk2.dim(`Environment: ${targetEnvName}`));
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(chalk2.red(executionCheck.reason ?? "Execution not allowed"));
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(chalk2.yellow(`Atom ${atomId} has already been executed in ${targetEnvName}.`));
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(chalk2.yellow(`Atom ${atomId} is already in progress.`));
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(chalk2.red(`Atom ${atomId} is not ready for execution.`));
4899
- console.log(chalk2.dim(`Status: ${atom.status}. Only READY or DONE atoms can be executed.`));
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(chalk2.red(`Atom ${atomId} has no plan.`));
4904
- console.log(chalk2.dim(`Run "archon plan" to create a plan first.`));
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(chalk2.yellow("\n[!] This atom does not record explicit design approval metadata."));
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(chalk2.dim("Execution cancelled. Re-run planning and approve design first."));
5225
+ console.log(chalk3.dim("Execution cancelled. Re-run planning and approve design first."));
4914
5226
  return;
4915
5227
  }
4916
5228
  }
4917
- const archPath = join3(cwd, "ARCHITECTURE.md");
4918
- if (!existsSync8(archPath)) {
4919
- console.error(chalk2.red("ARCHITECTURE.md not found."));
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(chalk2.red("Failed to parse ARCHITECTURE.md."));
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(chalk2.dim("\nChecking for conflicts..."));
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(chalk2.yellow(`
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" ? chalk2.red("\u2717") : chalk2.yellow("[!]");
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(chalk2.red(`
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(chalk2.dim("Execution aborted."));
5299
+ console.log(chalk3.dim("Execution aborted."));
4950
5300
  return;
4951
5301
  }
4952
5302
  } else {
4953
- console.log(chalk2.dim("\nRecommendations:"));
5303
+ console.log(chalk3.dim("\nRecommendations:"));
4954
5304
  for (const rec of conflictReport.recommendations) {
4955
- console.log(chalk2.dim(` - ${rec}`));
5305
+ console.log(chalk3.dim(` - ${rec}`));
4956
5306
  }
4957
5307
  }
4958
5308
  } else if (!concise) {
4959
- console.log(chalk2.green("\u2713 No conflicts detected"));
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(chalk2.red("Failed to update atom status."));
4966
- console.error(chalk2.dim(error instanceof Error ? error.message : "Unknown 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(chalk2.blue("\n\u{1F680} Executing plan..."));
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(chalk2.red("\nNo API key configured for execution."));
4979
- console.log(chalk2.dim("Add a provider key with: archon keys add"));
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(chalk2.red("\nNo valid API key available for execution."));
4992
- console.log(chalk2.dim("Add a provider key with: archon keys add"));
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(chalk2.yellow("\n\u26A0\uFE0F Execution paused by governance guidance"));
5020
- console.log(chalk2.dim("No changes were committed. Update the plan/path scope, then continue."));
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(chalk2.yellow("\nGovernance guidance:"));
5384
+ console.log(chalk3.yellow("\nGovernance guidance:"));
5025
5385
  for (const violation of violations) {
5026
- console.log(chalk2.dim(` - ${violation}`));
5386
+ console.log(chalk3.dim(` - ${violation}`));
5027
5387
  }
5028
5388
  if (pathScopeBlocked) {
5029
- console.log(chalk2.dim('\nTry in chat: "adjust this task to allowed paths", then "continue".'));
5389
+ console.log(chalk3.dim('\nTry in chat: "adjust this task to allowed paths", then "continue".'));
5030
5390
  }
5031
5391
  } else {
5032
- console.log(chalk2.yellow(executionResult.errorMessage ?? "Architecture constraints were not satisfied."));
5392
+ console.log(chalk3.yellow(executionResult.errorMessage ?? "Architecture constraints were not satisfied."));
5033
5393
  }
5034
5394
  } else {
5035
- console.log(chalk2.red("\n\u274C Execution failed"));
5036
- console.log(chalk2.red(executionResult.errorMessage ?? "Unknown error"));
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(chalk2.yellow("Changes have been rolled back."));
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(chalk2.green("\u2713 Plan executed successfully"));
5090
- console.log(chalk2.dim(`Files modified: ${filesChanged.length}`));
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(chalk2.dim(` - ${file}`));
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(chalk2.dim(`
5472
+ console.log(chalk3.dim(`
5099
5473
  Running quality gates for ${targetEnvName}...`));
5100
- console.log(chalk2.dim(`Gates: ${envConfig.qualityGates.join(", ")}`));
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(chalk2.red("\n\u274C Quality gates failed"));
5109
- console.log(chalk2.yellow("Rolling back changes..."));
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(chalk2.yellow("Changes rolled back (scoped to atom files)."));
5486
+ console.log(chalk3.yellow("Changes rolled back (scoped to atom files)."));
5113
5487
  } catch (error) {
5114
- console.log(chalk2.red("Failed to rollback. Please manually revert changes."));
5115
- console.log(chalk2.dim(error instanceof Error ? error.message : "Unknown rollback error"));
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(chalk2.dim("\nCommitting changes..."));
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(chalk2.green(`\u2713 Committed: ${commitMessage}`));
5523
+ console.log(chalk3.green(`\u2713 Committed: ${commitMessage}`));
5150
5524
  }
5151
5525
  } catch (error) {
5152
- console.log(chalk2.yellow("No changes to commit or git commit failed."));
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(chalk2.dim("\nCapturing learnings..."));
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(chalk2.green("\u2713 Learning captured to progress.txt"));
5550
+ console.log(chalk3.green("\u2713 Learning captured to progress.txt"));
5177
5551
  } else {
5178
- console.log(chalk2.yellow("[!] No learnings captured to progress.txt"));
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(chalk2.yellow("[!] No AGENTS.md updates (no reusable patterns found)"));
5560
+ console.log(chalk3.yellow("[!] No AGENTS.md updates (no reusable patterns found)"));
5187
5561
  } else {
5188
- console.log(chalk2.green(`\u2713 Updated ${agentsMdCount} AGENTS.md file(s)`));
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(chalk2.dim(`Updated ${agentsMdResult.filesUpdated.length + agentsMdResult.filesCreated.length} AGENTS.md file(s)`));
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(chalk2.green("\n\u2713 Done."));
5579
+ console.log(chalk3.green("\n\u2713 Done."));
5195
5580
  } else {
5196
- console.log(chalk2.green("\n\u2705 Atom executed successfully!"));
5197
- console.log(chalk2.dim(`Atom: ${atom.externalId}`));
5198
- console.log(chalk2.dim(`Status: ${atom.status}`));
5199
- console.log(chalk2.dim(`Files changed: ${filesChanged.length}`));
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(chalk2.bold("Next best action:"));
5653
+ console.log(chalk3.bold("Next best action:"));
5269
5654
  if (success) {
5270
- console.log(chalk2.dim(` \u2022 Run ${chalk2.cyan("archon list")} to select your next task.`));
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(chalk2.dim(` \u2022 In chat, say ${chalk2.cyan('"adjust this task to allowed paths"')} to re-scope automatically.`));
5274
- console.log(chalk2.dim(` \u2022 Then say ${chalk2.cyan('"continue"')} to execute the re-scoped task.`));
5275
- console.log(chalk2.dim(` \u2022 Run ${chalk2.cyan(`archon show ${atomExternalId}`)} to inspect the blocked task.`));
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(chalk2.dim(` \u2022 Run ${chalk2.cyan(`archon show ${atomExternalId}`)} to inspect this task.`));
5663
+ console.log(chalk3.dim(` \u2022 Run ${chalk3.cyan(`archon show ${atomExternalId}`)} to inspect this task.`));
5279
5664
  }
5280
- console.log(chalk2.dim(` \u2022 Run ${chalk2.cyan("archon config ai")} to add/rotate provider keys.`));
5281
- console.log(chalk2.dim(` \u2022 Run ${chalk2.cyan("archon preferences")} to tune model routing.`));
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 = join3(cwd, previewTarget);
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(chalk2.dim(`Output: ${absolutePath}`));
5681
+ console.log(chalk3.dim(`Output: ${absolutePath}`));
5297
5682
  return;
5298
5683
  }
5299
- console.log(chalk2.bold("\nDeliverable preview:"));
5300
- console.log(chalk2.dim(` Output file: ${absolutePath}`));
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(chalk2.dim(` ${line}`));
5687
+ console.log(chalk3.dim(` ${line}`));
5303
5688
  }
5304
5689
  } catch {
5305
5690
  }
5306
5691
  }
5307
5692
  async function saveAtom(atom) {
5308
- const atomsDir = join3(process.cwd(), ATOMS_DIR);
5309
- const atomFile = join3(atomsDir, `${atom.externalId}.json`);
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(chalk2.dim(`Learnings captured: ${result.entriesAdded} entries, ${result.patternsAdded} patterns`));
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(chalk2.dim("Failed to capture learnings (non-critical)."));
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 = join3(cwd, ATOMS_DIR, `${atomId}.env.json`);
5335
- if (!existsSync8(stateFile)) {
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 = join3(cwd, ATOMS_DIR, `${atomId}.env.json`);
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
  };