fix: stop home installs copying .agents into ~/.claude and ~/.codex

This commit is contained in:
Affaan Mustafa
2026-09-18 18:37:05 -04:00
parent b15f7d8171
commit da214d73b7
4 changed files with 76 additions and 4 deletions
+3 -1
View File
@@ -1,6 +1,7 @@
const path = require('path');
const {
HOME_INSTALL_EXCLUDED_SOURCE_PATHS,
createInstallTargetAdapter,
createRemappedOperation,
isForeignPlatformPath,
@@ -52,6 +53,7 @@ module.exports = createInstallTargetAdapter({
kind: 'home',
rootSegments: ['.claude'],
installStatePathSegments: ['ecc', 'install-state.json'],
excludedSourcePaths: HOME_INSTALL_EXCLUDED_SOURCE_PATHS,
nativeRootRelativePath: '.claude-plugin',
planOperations(input, adapter) {
const modules = Array.isArray(input.modules)
@@ -66,7 +68,7 @@ module.exports = createInstallTargetAdapter({
return modules.flatMap(module => {
const paths = Array.isArray(module.paths) ? module.paths : [];
return paths
.filter(p => !isForeignPlatformPath(p, adapter.target))
.filter(p => !isForeignPlatformPath(p, adapter.target) && !adapter.excludesSourcePath(p))
.flatMap(sourceRelativePath => {
if (
module.id === 'hooks-runtime'
+2 -1
View File
@@ -1,4 +1,4 @@
const { createInstallTargetAdapter } = require('./helpers');
const { HOME_INSTALL_EXCLUDED_SOURCE_PATHS, createInstallTargetAdapter } = require('./helpers');
module.exports = createInstallTargetAdapter({
id: 'codex-home',
@@ -7,4 +7,5 @@ module.exports = createInstallTargetAdapter({
rootSegments: ['.codex'],
installStatePathSegments: ['ecc-install-state.json'],
nativeRootRelativePath: '.codex',
excludedSourcePaths: HOME_INSTALL_EXCLUDED_SOURCE_PATHS,
});
+23 -2
View File
@@ -24,6 +24,14 @@ const PLATFORM_SOURCE_PATH_OWNERS = Object.freeze({
'.adal': 'adal',
});
// Source paths that home installs must never copy into a harness home
// directory. `.agents` is ECC's repo-local skills/plugins staging area:
// project targets such as kimi and antigravity consume it, but neither
// Claude Code nor Codex reads a `.agents` directory under ~/.claude or
// ~/.codex, so copying it there produces unread files that doctor flags as
// drift and repair keeps restoring.
const HOME_INSTALL_EXCLUDED_SOURCE_PATHS = Object.freeze(['.agents']);
function normalizeRelativePath(relativePath) {
return String(relativePath || '')
.replace(/\\/g, '/')
@@ -43,6 +51,14 @@ function isForeignPlatformPath(sourceRelativePath, adapterTarget) {
return false;
}
function isExcludedSourcePath(sourceRelativePath, excludedSourcePaths = []) {
const normalizedPath = normalizeRelativePath(sourceRelativePath);
return excludedSourcePaths.some(excluded => {
const prefix = normalizeRelativePath(excluded);
return prefix !== '' && (normalizedPath === prefix || normalizedPath.startsWith(`${prefix}/`));
});
}
function resolveBaseRoot(scope, input = {}) {
if (scope === 'home') {
return input.homeDir || os.homedir();
@@ -351,6 +367,9 @@ function createInstallTargetAdapter(config) {
strategy: adapter.determineStrategy(normalizedSourcePath),
});
},
excludesSourcePath(sourceRelativePath) {
return isExcludedSourcePath(sourceRelativePath, config.excludedSourcePaths);
},
planOperations(input = {}) {
if (typeof config.planOperations === 'function') {
return config.planOperations(input, adapter);
@@ -360,7 +379,7 @@ function createInstallTargetAdapter(config) {
return input.modules.flatMap(module => {
const paths = Array.isArray(module.paths) ? module.paths : [];
return paths
.filter(p => !isForeignPlatformPath(p, config.target))
.filter(p => !isForeignPlatformPath(p, config.target) && !adapter.excludesSourcePath(p))
.map(sourceRelativePath => adapter.createScaffoldOperation(
module.id,
sourceRelativePath,
@@ -372,7 +391,7 @@ function createInstallTargetAdapter(config) {
const module = input.module || {};
const paths = Array.isArray(module.paths) ? module.paths : [];
return paths
.filter(p => !isForeignPlatformPath(p, config.target))
.filter(p => !isForeignPlatformPath(p, config.target) && !adapter.excludesSourcePath(p))
.map(sourceRelativePath => adapter.createScaffoldOperation(
module.id,
sourceRelativePath,
@@ -399,6 +418,8 @@ function createInstallTargetAdapter(config) {
}
module.exports = {
HOME_INSTALL_EXCLUDED_SOURCE_PATHS,
isExcludedSourcePath,
buildValidationIssue,
createFlatFileOperations,
createFlatRuleOperations,