coder-config 0.52.3-beta → 0.53.2-beta

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.
@@ -19,7 +19,7 @@
19
19
 
20
20
  <!-- PWA Manifest -->
21
21
  <link rel="manifest" href="/manifest.json">
22
- <script type="module" crossorigin src="/assets/index-CG-MVxBS.js"></script>
22
+ <script type="module" crossorigin src="/assets/index-C8HMhykN.js"></script>
23
23
  <link rel="stylesheet" crossorigin href="/assets/index-BiF3i3y5.css">
24
24
  </head>
25
25
  <body>
@@ -93,6 +93,7 @@ function scanFolderForExplorer(dir, manager, label = null) {
93
93
  name: 'AGENTS.md (root)',
94
94
  path: rootAgentsMd,
95
95
  type: 'agentsmd',
96
+ tool: 'codex',
96
97
  size: fs.statSync(rootAgentsMd).size,
97
98
  isRoot: true
98
99
  });
@@ -105,6 +106,8 @@ function scanFolderForExplorer(dir, manager, label = null) {
105
106
  name: 'AGENTS.override.md (root)',
106
107
  path: rootAgentsOverrideMd,
107
108
  type: 'agentsmd',
109
+ tool: 'codex',
110
+ isOverride: true,
108
111
  size: fs.statSync(rootAgentsOverrideMd).size,
109
112
  isRoot: true
110
113
  });
@@ -456,6 +459,10 @@ function createClaudeFile(body) {
456
459
  filePath = path.join(dir, 'AGENTS.md');
457
460
  initialContent = content || '# Project Instructions\n\nInstructions for Codex CLI.\n';
458
461
  break;
462
+ case 'agentsoverridemd':
463
+ filePath = path.join(dir, 'AGENTS.override.md');
464
+ initialContent = content || '# Local Overrides\n\nLocal instructions that override AGENTS.md (gitignored).\n';
465
+ break;
459
466
  default:
460
467
  filePath = path.join(dir, '.claude', name);
461
468
  }
@@ -470,6 +477,21 @@ function createClaudeFile(body) {
470
477
  }
471
478
 
472
479
  fs.writeFileSync(filePath, initialContent, 'utf8');
480
+
481
+ // Auto-add AGENTS.override.md to .gitignore when created
482
+ if (type === 'agentsoverridemd') {
483
+ const gitignorePath = path.join(dir, '.gitignore');
484
+ const entry = 'AGENTS.override.md';
485
+ let gitignore = '';
486
+ if (fs.existsSync(gitignorePath)) {
487
+ gitignore = fs.readFileSync(gitignorePath, 'utf8');
488
+ }
489
+ if (!gitignore.split('\n').some(line => line.trim() === entry)) {
490
+ const separator = gitignore && !gitignore.endsWith('\n') ? '\n' : '';
491
+ fs.writeFileSync(gitignorePath, gitignore + separator + entry + '\n', 'utf8');
492
+ }
493
+ }
494
+
473
495
  return { success: true, path: filePath, content: initialContent };
474
496
  }
475
497
 
@@ -821,6 +843,81 @@ function getFileHashes(manager, projectDir, config = {}) {
821
843
  return { hashes };
822
844
  }
823
845
 
846
+ /**
847
+ * Discover instruction file hierarchy for a project directory.
848
+ * Walks from dir up to root (or home), finding CLAUDE.md, GEMINI.md, AGENTS.md at each level.
849
+ * Returns the chain of discovered files in priority order.
850
+ */
851
+ function getInstructionHierarchy(dir) {
852
+ const home = os.homedir();
853
+ const hierarchy = { dir: path.resolve(dir), claude: [], gemini: [], codex: [] };
854
+
855
+ // Walk from dir up to HOME (don't traverse above home directory)
856
+ let current = path.resolve(dir);
857
+ const seen = new Set();
858
+
859
+ while (current && !seen.has(current)) {
860
+ seen.add(current);
861
+
862
+ // CLAUDE.md — check root and .claude/ subfolder
863
+ for (const candidate of [
864
+ path.join(current, 'CLAUDE.md'),
865
+ path.join(current, '.claude', 'CLAUDE.md'),
866
+ ]) {
867
+ if (fs.existsSync(candidate)) {
868
+ const rel = current === home ? '~' : (current.startsWith(home + '/') ? '~' + current.slice(home.length) : current);
869
+ hierarchy.claude.push({ path: candidate, dir: rel, size: fs.statSync(candidate).size });
870
+ }
871
+ }
872
+
873
+ // GEMINI.md — check root and .gemini/ subfolder
874
+ for (const candidate of [
875
+ path.join(current, 'GEMINI.md'),
876
+ path.join(current, '.gemini', 'GEMINI.md'),
877
+ ]) {
878
+ if (fs.existsSync(candidate)) {
879
+ const rel = current === home ? '~' : (current.startsWith(home + '/') ? '~' + current.slice(home.length) : current);
880
+ hierarchy.gemini.push({ path: candidate, dir: rel, size: fs.statSync(candidate).size });
881
+ }
882
+ }
883
+
884
+ // AGENTS.md — check root (Codex walks directories looking for AGENTS.md or AGENTS.override.md)
885
+ for (const candidate of [
886
+ path.join(current, 'AGENTS.override.md'),
887
+ path.join(current, 'AGENTS.md'),
888
+ ]) {
889
+ if (fs.existsSync(candidate)) {
890
+ const rel = current === home ? '~' : (current.startsWith(home + '/') ? '~' + current.slice(home.length) : current);
891
+ hierarchy.codex.push({ path: candidate, dir: rel, name: path.basename(candidate), size: fs.statSync(candidate).size });
892
+ }
893
+ }
894
+
895
+ // Stop at HOME directory (don't walk above it)
896
+ if (current === home) break;
897
+ const parent = path.dirname(current);
898
+ if (parent === current) break;
899
+ current = parent;
900
+ }
901
+
902
+ // Always check home directory last (global scope)
903
+ if (!seen.has(home)) {
904
+ const globalClaudeMd = path.join(home, '.claude', 'CLAUDE.md');
905
+ if (fs.existsSync(globalClaudeMd)) {
906
+ hierarchy.claude.push({ path: globalClaudeMd, dir: '~/.claude', size: fs.statSync(globalClaudeMd).size });
907
+ }
908
+ const globalGeminiMd = path.join(home, '.gemini', 'GEMINI.md');
909
+ if (fs.existsSync(globalGeminiMd)) {
910
+ hierarchy.gemini.push({ path: globalGeminiMd, dir: '~/.gemini', size: fs.statSync(globalGeminiMd).size });
911
+ }
912
+ const globalAgentsMd = path.join(home, '.codex', 'AGENTS.md');
913
+ if (fs.existsSync(globalAgentsMd)) {
914
+ hierarchy.codex.push({ path: globalAgentsMd, dir: '~/.codex', name: 'AGENTS.md', size: fs.statSync(globalAgentsMd).size });
915
+ }
916
+ }
917
+
918
+ return hierarchy;
919
+ }
920
+
824
921
  module.exports = {
825
922
  scanFolderForExplorer,
826
923
  getIntermediatePaths,
@@ -835,4 +932,5 @@ module.exports = {
835
932
  moveClaudeItem,
836
933
  scanMcpTools,
837
934
  getFileHashes,
935
+ getInstructionHierarchy,
838
936
  };
package/ui/server.cjs CHANGED
@@ -573,6 +573,9 @@ class ConfigUIServer {
573
573
  case '/api/file-hashes':
574
574
  return this.json(res, routes.fileExplorer.getFileHashes(this.manager, this.projectDir, this.config));
575
575
 
576
+ case '/api/instruction-hierarchy':
577
+ return this.json(res, routes.fileExplorer.getInstructionHierarchy(query.dir || this.projectDir));
578
+
576
579
  case '/api/version-check':
577
580
  return this.json(res, await routes.updates.checkForUpdates(this.manager, __dirname, this.config?.releaseChannel || 'stable'));
578
581