archondev 1.2.1 → 1.6.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,6 +1,6 @@
1
1
  import {
2
2
  loadAtom
3
- } from "./chunk-EDP55FCI.js";
3
+ } from "./chunk-3AAQEUY6.js";
4
4
  import {
5
5
  ArchitectureParser
6
6
  } from "./chunk-2CFO5GVH.js";
@@ -2842,7 +2842,7 @@ var require_js_yaml2 = __commonJS({
2842
2842
 
2843
2843
  // src/cli/execute.ts
2844
2844
  import chalk2 from "chalk";
2845
- import { existsSync as existsSync7 } from "fs";
2845
+ import { existsSync as existsSync8 } from "fs";
2846
2846
  import { readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
2847
2847
  import { join as join3 } from "path";
2848
2848
  import { execSync as execSync3 } from "child_process";
@@ -2850,7 +2850,157 @@ import { createInterface } from "readline";
2850
2850
 
2851
2851
  // src/core/conflicts/checker.ts
2852
2852
  import { stat } from "fs/promises";
2853
+ import { existsSync as existsSync2 } from "fs";
2854
+
2855
+ // src/core/dependencies/parser.ts
2856
+ import { readFile } from "fs/promises";
2853
2857
  import { existsSync } from "fs";
2858
+ import matter from "gray-matter";
2859
+ var DEFAULT_DEPENDENCIES_FILENAME = "DEPENDENCIES.md";
2860
+ var DependencyParser = class {
2861
+ cwd;
2862
+ filePath;
2863
+ constructor(cwd = process.cwd(), filename = DEFAULT_DEPENDENCIES_FILENAME) {
2864
+ this.cwd = cwd;
2865
+ this.filePath = `${cwd}/${filename}`;
2866
+ }
2867
+ /**
2868
+ * Check if DEPENDENCIES.md exists
2869
+ */
2870
+ exists() {
2871
+ return existsSync(this.filePath);
2872
+ }
2873
+ /**
2874
+ * Parse DEPENDENCIES.md and return the document
2875
+ */
2876
+ async parse() {
2877
+ if (!this.exists()) {
2878
+ return {
2879
+ success: true,
2880
+ document: {
2881
+ version: "1.0",
2882
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString().split("T")[0] ?? "",
2883
+ rules: []
2884
+ }
2885
+ };
2886
+ }
2887
+ try {
2888
+ const content = await readFile(this.filePath, "utf-8");
2889
+ const { data } = matter(content);
2890
+ const document = this.validateAndNormalize(data);
2891
+ return { success: true, document };
2892
+ } catch (error) {
2893
+ return {
2894
+ success: false,
2895
+ error: error instanceof Error ? error.message : "Unknown parse error"
2896
+ };
2897
+ }
2898
+ }
2899
+ /**
2900
+ * Validate and normalize parsed YAML data
2901
+ */
2902
+ validateAndNormalize(data) {
2903
+ const raw = data;
2904
+ const version = typeof raw["version"] === "string" ? raw["version"] : "1.0";
2905
+ const updatedAt = typeof raw["updatedAt"] === "string" ? raw["updatedAt"] : (/* @__PURE__ */ new Date()).toISOString().split("T")[0] ?? "";
2906
+ const rawRules = Array.isArray(raw["rules"]) ? raw["rules"] : [];
2907
+ const rules = [];
2908
+ for (const rawRule of rawRules) {
2909
+ if (typeof rawRule !== "object" || rawRule === null) continue;
2910
+ const r = rawRule;
2911
+ const id = typeof r["id"] === "string" ? r["id"] : `DEP-${rules.length + 1}`;
2912
+ const source = typeof r["source"] === "string" ? r["source"] : "";
2913
+ const dependents = Array.isArray(r["dependents"]) ? r["dependents"].filter((d) => typeof d === "string") : [];
2914
+ const severity = this.parseSeverity(r["severity"]);
2915
+ const reason = typeof r["reason"] === "string" ? r["reason"] : "";
2916
+ const symbols = Array.isArray(r["symbols"]) ? r["symbols"].filter((s) => typeof s === "string") : void 0;
2917
+ const mustTest = Array.isArray(r["mustTest"]) ? r["mustTest"].filter((t) => typeof t === "string") : void 0;
2918
+ if (source && dependents.length > 0) {
2919
+ rules.push({ id, source, dependents, severity, reason, symbols, mustTest });
2920
+ }
2921
+ }
2922
+ return { version, updatedAt, rules };
2923
+ }
2924
+ parseSeverity(value) {
2925
+ if (typeof value === "string") {
2926
+ const upper = value.toUpperCase();
2927
+ if (upper === "BLOCKER" || upper === "WARNING" || upper === "INFO") {
2928
+ return upper;
2929
+ }
2930
+ }
2931
+ return "WARNING";
2932
+ }
2933
+ /**
2934
+ * Check which dependency rules are triggered by a set of files
2935
+ */
2936
+ async checkFiles(files) {
2937
+ const parseResult = await this.parse();
2938
+ if (!parseResult.success || !parseResult.document) {
2939
+ return {
2940
+ filesChecked: files,
2941
+ impacts: [],
2942
+ totalImpacts: 0,
2943
+ hasBlockers: false
2944
+ };
2945
+ }
2946
+ const impacts = [];
2947
+ for (const file of files) {
2948
+ for (const rule of parseResult.document.rules) {
2949
+ if (this.matchesPattern(file, rule.source)) {
2950
+ impacts.push({
2951
+ rule,
2952
+ matchedSource: file,
2953
+ affectedDependents: rule.dependents
2954
+ });
2955
+ }
2956
+ }
2957
+ }
2958
+ return {
2959
+ filesChecked: files,
2960
+ impacts,
2961
+ totalImpacts: impacts.reduce((sum, i) => sum + i.affectedDependents.length, 0),
2962
+ hasBlockers: impacts.some((i) => i.rule.severity === "BLOCKER")
2963
+ };
2964
+ }
2965
+ /**
2966
+ * Match a file path against a glob pattern
2967
+ * Reuses the same logic as ConflictChecker for consistency
2968
+ */
2969
+ matchesPattern(path, pattern) {
2970
+ const regexPattern = pattern.replace(/\*\*/g, "<<<GLOBSTAR>>>").replace(/\*/g, "[^/]*").replace(/<<<GLOBSTAR>>>/g, ".*").replace(/\//g, "\\/");
2971
+ return new RegExp(`^${regexPattern}$`).test(path);
2972
+ }
2973
+ /**
2974
+ * Generate Mermaid diagram of dependencies
2975
+ */
2976
+ async generateGraph() {
2977
+ const parseResult = await this.parse();
2978
+ if (!parseResult.success || !parseResult.document || parseResult.document.rules.length === 0) {
2979
+ return 'graph LR\n empty["No dependencies defined"]';
2980
+ }
2981
+ const lines = ["graph LR"];
2982
+ const nodeIds = /* @__PURE__ */ new Map();
2983
+ let nodeCounter = 0;
2984
+ const getNodeId = (path) => {
2985
+ if (!nodeIds.has(path)) {
2986
+ nodeIds.set(path, `n${nodeCounter++}`);
2987
+ }
2988
+ return nodeIds.get(path);
2989
+ };
2990
+ for (const rule of parseResult.document.rules) {
2991
+ const sourceId = getNodeId(rule.source);
2992
+ const sourceLabel = rule.source.replace(/"/g, "'");
2993
+ for (const dependent of rule.dependents) {
2994
+ const depId = getNodeId(dependent);
2995
+ const depLabel = dependent.replace(/"/g, "'");
2996
+ lines.push(` ${sourceId}["${sourceLabel}"] --> ${depId}["${depLabel}"]`);
2997
+ }
2998
+ }
2999
+ return lines.join("\n");
3000
+ }
3001
+ };
3002
+
3003
+ // src/core/conflicts/checker.ts
2854
3004
  var ConflictChecker = class {
2855
3005
  architecture;
2856
3006
  constructor(architecture) {
@@ -2877,6 +3027,10 @@ var ConflictChecker = class {
2877
3027
  }
2878
3028
  const semanticConflicts = this.checkSemanticConflicts(plan);
2879
3029
  conflicts.push(...semanticConflicts);
3030
+ if (options.checkFileDependencies !== false) {
3031
+ const fileDepsConflicts = await this.checkFileLevelDependencies(plan.files_to_modify, cwd);
3032
+ conflicts.push(...fileDepsConflicts);
3033
+ }
2880
3034
  if (conflicts.some((c) => c.type === "FILE_MODIFIED")) {
2881
3035
  recommendations.push("Review modified files and re-plan if necessary");
2882
3036
  }
@@ -2902,7 +3056,7 @@ var ConflictChecker = class {
2902
3056
  const conflicts = [];
2903
3057
  for (const filePath of files) {
2904
3058
  const fullPath = `${cwd}/${filePath}`;
2905
- if (!existsSync(fullPath)) {
3059
+ if (!existsSync2(fullPath)) {
2906
3060
  continue;
2907
3061
  }
2908
3062
  try {
@@ -3035,12 +3189,42 @@ var ConflictChecker = class {
3035
3189
  if (!scope || scope === "*") return true;
3036
3190
  return this.matchesPattern(path, scope) || path.startsWith(scope);
3037
3191
  }
3192
+ /**
3193
+ * Check file-level dependencies from DEPENDENCIES.md
3194
+ */
3195
+ async checkFileLevelDependencies(files, cwd) {
3196
+ const conflicts = [];
3197
+ try {
3198
+ const parser = new DependencyParser(cwd);
3199
+ if (!parser.exists()) {
3200
+ return [];
3201
+ }
3202
+ const result = await parser.checkFiles(files);
3203
+ for (const impact of result.impacts) {
3204
+ const severity = impact.rule.severity === "BLOCKER" ? "BLOCKER" : impact.rule.severity === "WARNING" ? "WARNING" : "INFO";
3205
+ conflicts.push({
3206
+ type: "DEPENDENCY",
3207
+ severity,
3208
+ path: impact.matchedSource,
3209
+ message: `Changing ${impact.matchedSource} may impact: ${impact.affectedDependents.join(", ")}`,
3210
+ recommendation: impact.rule.reason || "Review dependent files before proceeding"
3211
+ });
3212
+ }
3213
+ } catch {
3214
+ conflicts.push({
3215
+ type: "DEPENDENCY",
3216
+ severity: "INFO",
3217
+ message: "DEPENDENCIES.md could not be parsed; file-level dependency checks skipped"
3218
+ });
3219
+ }
3220
+ return conflicts;
3221
+ }
3038
3222
  };
3039
3223
 
3040
3224
  // src/core/gates/runner.ts
3041
3225
  import { execSync } from "child_process";
3042
3226
  import { readFile as readFile2 } from "fs/promises";
3043
- import { existsSync as existsSync2 } from "fs";
3227
+ import { existsSync as existsSync3 } from "fs";
3044
3228
  import chalk from "chalk";
3045
3229
  var QualityGateRunner = class {
3046
3230
  cwd;
@@ -3125,7 +3309,7 @@ var QualityGateRunner = class {
3125
3309
  */
3126
3310
  async runArchitectureGate() {
3127
3311
  const archPath = `${this.cwd}/ARCHITECTURE.md`;
3128
- if (!existsSync2(archPath)) {
3312
+ if (!existsSync3(archPath)) {
3129
3313
  return "No ARCHITECTURE.md found - skipping";
3130
3314
  }
3131
3315
  return "Architecture constraints checked";
@@ -3135,13 +3319,13 @@ var QualityGateRunner = class {
3135
3319
  */
3136
3320
  async runSyntaxGate() {
3137
3321
  const pkgPath = `${this.cwd}/package.json`;
3138
- if (!existsSync2(pkgPath)) {
3322
+ if (!existsSync3(pkgPath)) {
3139
3323
  return "No package.json found - skipping syntax check";
3140
3324
  }
3141
3325
  const pkg = JSON.parse(await readFile2(pkgPath, "utf-8"));
3142
3326
  if (pkg.scripts?.["typecheck"]) {
3143
3327
  return this.runCommand("npm run typecheck");
3144
- } else if (existsSync2(`${this.cwd}/tsconfig.json`)) {
3328
+ } else if (existsSync3(`${this.cwd}/tsconfig.json`)) {
3145
3329
  return this.runCommand("npx tsc --noEmit");
3146
3330
  }
3147
3331
  return "No TypeScript configuration found - skipping";
@@ -3151,7 +3335,7 @@ var QualityGateRunner = class {
3151
3335
  */
3152
3336
  async runLintGate() {
3153
3337
  const pkgPath = `${this.cwd}/package.json`;
3154
- if (!existsSync2(pkgPath)) {
3338
+ if (!existsSync3(pkgPath)) {
3155
3339
  return "No package.json found - skipping lint";
3156
3340
  }
3157
3341
  const pkg = JSON.parse(await readFile2(pkgPath, "utf-8"));
@@ -3165,7 +3349,7 @@ var QualityGateRunner = class {
3165
3349
  */
3166
3350
  async runUnitGate() {
3167
3351
  const pkgPath = `${this.cwd}/package.json`;
3168
- if (!existsSync2(pkgPath)) {
3352
+ if (!existsSync3(pkgPath)) {
3169
3353
  return "No package.json found - skipping tests";
3170
3354
  }
3171
3355
  const pkg = JSON.parse(await readFile2(pkgPath, "utf-8"));
@@ -3179,7 +3363,7 @@ var QualityGateRunner = class {
3179
3363
  */
3180
3364
  async runIntegrationGate() {
3181
3365
  const pkgPath = `${this.cwd}/package.json`;
3182
- if (!existsSync2(pkgPath)) {
3366
+ if (!existsSync3(pkgPath)) {
3183
3367
  return "No package.json found - skipping integration tests";
3184
3368
  }
3185
3369
  const pkg = JSON.parse(await readFile2(pkgPath, "utf-8"));
@@ -3193,7 +3377,7 @@ var QualityGateRunner = class {
3193
3377
  */
3194
3378
  async runE2EGate() {
3195
3379
  const pkgPath = `${this.cwd}/package.json`;
3196
- if (!existsSync2(pkgPath)) {
3380
+ if (!existsSync3(pkgPath)) {
3197
3381
  return "No package.json found - skipping E2E tests";
3198
3382
  }
3199
3383
  const pkg = JSON.parse(await readFile2(pkgPath, "utf-8"));
@@ -3243,7 +3427,7 @@ var QualityGateRunner = class {
3243
3427
 
3244
3428
  // src/core/learning/capture.ts
3245
3429
  import { readFile as readFile3, writeFile, appendFile } from "fs/promises";
3246
- import { existsSync as existsSync3 } from "fs";
3430
+ import { existsSync as existsSync4 } from "fs";
3247
3431
  var PROGRESS_HEADER = `# ArchonDev Progress Log
3248
3432
 
3249
3433
  Started: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
@@ -3294,7 +3478,7 @@ var LearningCapture = class {
3294
3478
  * Ensure progress.txt exists with initial header
3295
3479
  */
3296
3480
  async ensureProgressFile() {
3297
- if (!existsSync3(this.progressPath)) {
3481
+ if (!existsSync4(this.progressPath)) {
3298
3482
  await writeFile(this.progressPath, PROGRESS_HEADER);
3299
3483
  }
3300
3484
  }
@@ -3536,7 +3720,7 @@ var LearningCapture = class {
3536
3720
 
3537
3721
  // src/core/learning/agents-md.ts
3538
3722
  import { readFile as readFile4, writeFile as writeFile2, appendFile as appendFile2, mkdir } from "fs/promises";
3539
- import { existsSync as existsSync4 } from "fs";
3723
+ import { existsSync as existsSync5 } from "fs";
3540
3724
  import { dirname, join } from "path";
3541
3725
  var AGENTS_MD_HEADER = `# AGENTS.md
3542
3726
 
@@ -3771,7 +3955,7 @@ var AgentsMdUpdater = class {
3771
3955
  const agentsMdPath = join(this.cwd, dir, "AGENTS.md");
3772
3956
  const parentAgentsMd = await this.findParentAgentsMd(dir);
3773
3957
  let learningsAdded = 0;
3774
- if (existsSync4(agentsMdPath)) {
3958
+ if (existsSync5(agentsMdPath)) {
3775
3959
  learningsAdded = await this.appendToAgentsMd(agentsMdPath, knowledge);
3776
3960
  return { path: agentsMdPath, updated: true, created: false, learningsAdded };
3777
3961
  }
@@ -3794,7 +3978,7 @@ var AgentsMdUpdater = class {
3794
3978
  let currentDir = dirname(dir);
3795
3979
  while (currentDir && currentDir !== "." && currentDir !== "/") {
3796
3980
  const agentsMdPath = join(this.cwd, currentDir, "AGENTS.md");
3797
- if (existsSync4(agentsMdPath)) {
3981
+ if (existsSync5(agentsMdPath)) {
3798
3982
  return agentsMdPath;
3799
3983
  }
3800
3984
  currentDir = dirname(currentDir);
@@ -3896,7 +4080,7 @@ var AgentsMdUpdater = class {
3896
4080
  parts.push("");
3897
4081
  }
3898
4082
  const dir = dirname(path);
3899
- if (!existsSync4(dir)) {
4083
+ if (!existsSync5(dir)) {
3900
4084
  await mkdir(dir, { recursive: true });
3901
4085
  }
3902
4086
  await writeFile2(path, parts.join("\n"));
@@ -3905,7 +4089,7 @@ var AgentsMdUpdater = class {
3905
4089
 
3906
4090
  // src/agents/executor.ts
3907
4091
  import { readFile as readFile5, writeFile as writeFile3, mkdir as mkdir2 } from "fs/promises";
3908
- import { existsSync as existsSync5 } from "fs";
4092
+ import { existsSync as existsSync6 } from "fs";
3909
4093
  import { dirname as dirname2 } from "path";
3910
4094
  import { execSync as execSync2 } from "child_process";
3911
4095
  var SYSTEM_PROMPT = `You are the Executor, an expert software engineer responsible for implementing approved plans.
@@ -3972,7 +4156,7 @@ var ExecutorAgent = class {
3972
4156
  try {
3973
4157
  for (const diff of diffs) {
3974
4158
  const fullPath = `${cwd}/${diff.path}`;
3975
- if (existsSync5(fullPath)) {
4159
+ if (existsSync6(fullPath)) {
3976
4160
  originalContents.set(diff.path, await readFile5(fullPath, "utf-8"));
3977
4161
  } else {
3978
4162
  originalContents.set(diff.path, null);
@@ -3984,7 +4168,7 @@ var ExecutorAgent = class {
3984
4168
  continue;
3985
4169
  }
3986
4170
  const dir = dirname2(fullPath);
3987
- if (!existsSync5(dir)) {
4171
+ if (!existsSync6(dir)) {
3988
4172
  await mkdir2(dir, { recursive: true });
3989
4173
  }
3990
4174
  await writeFile3(fullPath, diff.newContent);
@@ -4042,7 +4226,7 @@ var ExecutorAgent = class {
4042
4226
  parts.push("# Current File Contents");
4043
4227
  for (const filePath of plan.files_to_modify) {
4044
4228
  const fullPath = `${cwd}/${filePath}`;
4045
- if (existsSync5(fullPath)) {
4229
+ if (existsSync6(fullPath)) {
4046
4230
  try {
4047
4231
  const content = await readFile5(fullPath, "utf-8");
4048
4232
  parts.push(`
@@ -4167,7 +4351,7 @@ var ExecutorAgent = class {
4167
4351
  async runQualityChecks(cwd) {
4168
4352
  try {
4169
4353
  const pkgPath = `${cwd}/package.json`;
4170
- if (existsSync5(pkgPath)) {
4354
+ if (existsSync6(pkgPath)) {
4171
4355
  const pkg = JSON.parse(await readFile5(pkgPath, "utf-8"));
4172
4356
  if (pkg.scripts?.["typecheck"]) {
4173
4357
  execSync2("npm run typecheck", { cwd, stdio: "pipe" });
@@ -4219,7 +4403,7 @@ var DEFAULT_ENVIRONMENTS = {
4219
4403
 
4220
4404
  // src/core/environments/config.ts
4221
4405
  var import_js_yaml = __toESM(require_js_yaml2(), 1);
4222
- import { existsSync as existsSync6 } from "fs";
4406
+ import { existsSync as existsSync7 } from "fs";
4223
4407
  import { readFile as readFile6 } from "fs/promises";
4224
4408
  import { join as join2 } from "path";
4225
4409
  var VALID_GATES = [
@@ -4239,11 +4423,11 @@ var EnvironmentConfigLoader = class {
4239
4423
  }
4240
4424
  async loadConfig() {
4241
4425
  const configPath = join2(this.cwd, "archon.config.yaml");
4242
- if (existsSync6(configPath)) {
4426
+ if (existsSync7(configPath)) {
4243
4427
  return this.loadFromConfigFile(configPath);
4244
4428
  }
4245
4429
  const archPath = join2(this.cwd, "ARCHITECTURE.md");
4246
- if (existsSync6(archPath)) {
4430
+ if (existsSync7(archPath)) {
4247
4431
  return this.loadFromArchitecture(archPath);
4248
4432
  }
4249
4433
  return DEFAULT_ENVIRONMENTS;
@@ -4462,7 +4646,7 @@ async function execute(atomId, options) {
4462
4646
  process.exit(1);
4463
4647
  }
4464
4648
  const archPath = join3(cwd, "ARCHITECTURE.md");
4465
- if (!existsSync7(archPath)) {
4649
+ if (!existsSync8(archPath)) {
4466
4650
  console.error(chalk2.red("ARCHITECTURE.md not found."));
4467
4651
  process.exit(1);
4468
4652
  }
@@ -4630,7 +4814,7 @@ async function captureLearnings(atom, execution) {
4630
4814
  }
4631
4815
  async function loadAtomEnvironmentState(atomId, cwd) {
4632
4816
  const stateFile = join3(cwd, ATOMS_DIR, `${atomId}.env.json`);
4633
- if (!existsSync7(stateFile)) {
4817
+ if (!existsSync8(stateFile)) {
4634
4818
  return null;
4635
4819
  }
4636
4820
  const content = await readFile7(stateFile, "utf-8");
@@ -4642,6 +4826,7 @@ async function saveAtomEnvironmentState(atomId, cwd, state) {
4642
4826
  }
4643
4827
 
4644
4828
  export {
4829
+ DependencyParser,
4645
4830
  EnvironmentConfigLoader,
4646
4831
  EnvironmentValidator,
4647
4832
  execute