coder-config 0.52.2-beta → 0.53.1-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-OCQSqQs9.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>
@@ -456,6 +456,10 @@ function createClaudeFile(body) {
456
456
  filePath = path.join(dir, 'AGENTS.md');
457
457
  initialContent = content || '# Project Instructions\n\nInstructions for Codex CLI.\n';
458
458
  break;
459
+ case 'agentsoverridemd':
460
+ filePath = path.join(dir, 'AGENTS.override.md');
461
+ initialContent = content || '# Local Overrides\n\nLocal instructions that override AGENTS.md (gitignored).\n';
462
+ break;
459
463
  default:
460
464
  filePath = path.join(dir, '.claude', name);
461
465
  }
@@ -470,6 +474,21 @@ function createClaudeFile(body) {
470
474
  }
471
475
 
472
476
  fs.writeFileSync(filePath, initialContent, 'utf8');
477
+
478
+ // Auto-add AGENTS.override.md to .gitignore when created
479
+ if (type === 'agentsoverridemd') {
480
+ const gitignorePath = path.join(dir, '.gitignore');
481
+ const entry = 'AGENTS.override.md';
482
+ let gitignore = '';
483
+ if (fs.existsSync(gitignorePath)) {
484
+ gitignore = fs.readFileSync(gitignorePath, 'utf8');
485
+ }
486
+ if (!gitignore.split('\n').some(line => line.trim() === entry)) {
487
+ const separator = gitignore && !gitignore.endsWith('\n') ? '\n' : '';
488
+ fs.writeFileSync(gitignorePath, gitignore + separator + entry + '\n', 'utf8');
489
+ }
490
+ }
491
+
473
492
  return { success: true, path: filePath, content: initialContent };
474
493
  }
475
494
 
@@ -821,6 +840,71 @@ function getFileHashes(manager, projectDir, config = {}) {
821
840
  return { hashes };
822
841
  }
823
842
 
843
+ /**
844
+ * Discover instruction file hierarchy for a project directory.
845
+ * Walks from dir up to root (or home), finding CLAUDE.md, GEMINI.md, AGENTS.md at each level.
846
+ * Returns the chain of discovered files in priority order.
847
+ */
848
+ function getInstructionHierarchy(dir) {
849
+ const home = os.homedir();
850
+ const hierarchy = { claude: [], gemini: [], codex: [] };
851
+
852
+ // Walk from dir up to filesystem root
853
+ let current = path.resolve(dir);
854
+ const seen = new Set();
855
+
856
+ while (current && !seen.has(current)) {
857
+ seen.add(current);
858
+
859
+ // CLAUDE.md — check root and .claude/ subfolder
860
+ for (const candidate of [
861
+ path.join(current, 'CLAUDE.md'),
862
+ path.join(current, '.claude', 'CLAUDE.md'),
863
+ ]) {
864
+ if (fs.existsSync(candidate)) {
865
+ const rel = current === home ? '~' : (current.startsWith(home + '/') ? '~' + current.slice(home.length) : current);
866
+ hierarchy.claude.push({ path: candidate, dir: rel, size: fs.statSync(candidate).size });
867
+ }
868
+ }
869
+
870
+ // GEMINI.md — check root and .gemini/ subfolder
871
+ for (const candidate of [
872
+ path.join(current, 'GEMINI.md'),
873
+ path.join(current, '.gemini', 'GEMINI.md'),
874
+ ]) {
875
+ if (fs.existsSync(candidate)) {
876
+ const rel = current === home ? '~' : (current.startsWith(home + '/') ? '~' + current.slice(home.length) : current);
877
+ hierarchy.gemini.push({ path: candidate, dir: rel, size: fs.statSync(candidate).size });
878
+ }
879
+ }
880
+
881
+ // AGENTS.md — check root (Codex walks directories looking for AGENTS.md or AGENTS.override.md)
882
+ for (const candidate of [
883
+ path.join(current, 'AGENTS.override.md'),
884
+ path.join(current, 'AGENTS.md'),
885
+ ]) {
886
+ if (fs.existsSync(candidate)) {
887
+ const rel = current === home ? '~' : (current.startsWith(home + '/') ? '~' + current.slice(home.length) : current);
888
+ hierarchy.codex.push({ path: candidate, dir: rel, name: path.basename(candidate), size: fs.statSync(candidate).size });
889
+ }
890
+ }
891
+
892
+ // Also check ~/.codex/AGENTS.md for global Codex instructions
893
+ if (current === home) {
894
+ const globalAgents = path.join(home, '.codex', 'AGENTS.md');
895
+ if (fs.existsSync(globalAgents)) {
896
+ hierarchy.codex.push({ path: globalAgents, dir: '~/.codex', name: 'AGENTS.md', size: fs.statSync(globalAgents).size });
897
+ }
898
+ }
899
+
900
+ const parent = path.dirname(current);
901
+ if (parent === current) break;
902
+ current = parent;
903
+ }
904
+
905
+ return hierarchy;
906
+ }
907
+
824
908
  module.exports = {
825
909
  scanFolderForExplorer,
826
910
  getIntermediatePaths,
@@ -835,4 +919,5 @@ module.exports = {
835
919
  moveClaudeItem,
836
920
  scanMcpTools,
837
921
  getFileHashes,
922
+ getInstructionHierarchy,
838
923
  };
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