Merge remote-tracking branch 'upstream/next' into kimi-runtime-support
# Conflicts: # bin/install.js
This commit is contained in:
@@ -445,7 +445,7 @@ function cmdEffortSync(cwd: string, raw: boolean, opts?: { dryRun?: boolean; con
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/unbound-method
|
||||
const { getGlobalConfigDir } = require('./runtime-homes.cjs') as { getGlobalConfigDir(runtime: string): string };
|
||||
const { getGlobalConfigDir } = require('./runtime-homes.cjs') as { getGlobalConfigDir(runtime: string, explicitDir?: string | null): string };
|
||||
// Use install-time resolvers: they merge ~/.gsd/defaults.json with project config,
|
||||
// matching the exact logic used when agents were originally installed.
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/unbound-method
|
||||
|
||||
110
src/runtime-config-adapter-registry.cts
Normal file
110
src/runtime-config-adapter-registry.cts
Normal file
@@ -0,0 +1,110 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Runtime config adapter registry — explicit dispatch table for install-phase
|
||||
* config mutations (issue #60), replacing inline `runtime === '...'` branching
|
||||
* in bin/install.js.
|
||||
*
|
||||
* Design notes:
|
||||
* - `installSurface` selects which config handler install() runs:
|
||||
* 'settings-json' → fall through to the shared settings.json accumulation.
|
||||
* 'codex-toml' → early-return after writing codex.toml.
|
||||
* 'copilot-instructions' → early-return after writing .github/copilot-instructions.md.
|
||||
* 'cline-rules' → early-return after writing .clinerules.
|
||||
* 'profile-marker-only' → early-return after writing only the profile marker.
|
||||
* - `writesSharedSettings` is the finishInstall writeSettings gate:
|
||||
* false for codex / copilot / kilo / cursor / windsurf / trae / cline / kimi (legacy exclusion list).
|
||||
* true for all other runtimes.
|
||||
* - `finishPermissionWriter` names the finishInstall-phase dedicated config writer:
|
||||
* 'opencode' → writes BOTH shared settings AND its own permissions file.
|
||||
* 'kilo' → writes only its own permissions file.
|
||||
* null → no dedicated permission writer.
|
||||
*/
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type ConfigInstallSurface =
|
||||
| 'settings-json'
|
||||
| 'codex-toml'
|
||||
| 'copilot-instructions'
|
||||
| 'cline-rules'
|
||||
| 'profile-marker-only';
|
||||
|
||||
type FinishPermissionWriter = 'opencode' | 'kilo' | null;
|
||||
|
||||
interface RuntimeConfigIntent {
|
||||
runtime: string;
|
||||
installSurface: ConfigInstallSurface;
|
||||
writesSharedSettings: boolean;
|
||||
finishPermissionWriter: FinishPermissionWriter;
|
||||
}
|
||||
|
||||
interface RegistryEntry {
|
||||
installSurface: ConfigInstallSurface;
|
||||
writesSharedSettings: boolean;
|
||||
finishPermissionWriter: FinishPermissionWriter;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Registry
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const REGISTRY: Record<string, Readonly<RegistryEntry>> = Object.freeze({
|
||||
claude: Object.freeze({ installSurface: 'settings-json', writesSharedSettings: true, finishPermissionWriter: null } as const),
|
||||
gemini: Object.freeze({ installSurface: 'settings-json', writesSharedSettings: true, finishPermissionWriter: null } as const),
|
||||
antigravity: Object.freeze({ installSurface: 'settings-json', writesSharedSettings: true, finishPermissionWriter: null } as const),
|
||||
augment: Object.freeze({ installSurface: 'settings-json', writesSharedSettings: true, finishPermissionWriter: null } as const),
|
||||
qwen: Object.freeze({ installSurface: 'settings-json', writesSharedSettings: true, finishPermissionWriter: null } as const),
|
||||
hermes: Object.freeze({ installSurface: 'settings-json', writesSharedSettings: true, finishPermissionWriter: null } as const),
|
||||
codebuddy: Object.freeze({ installSurface: 'settings-json', writesSharedSettings: true, finishPermissionWriter: null } as const),
|
||||
opencode: Object.freeze({ installSurface: 'settings-json', writesSharedSettings: true, finishPermissionWriter: 'opencode' } as const),
|
||||
kilo: Object.freeze({ installSurface: 'settings-json', writesSharedSettings: false, finishPermissionWriter: 'kilo' } as const),
|
||||
codex: Object.freeze({ installSurface: 'codex-toml', writesSharedSettings: false, finishPermissionWriter: null } as const),
|
||||
copilot: Object.freeze({ installSurface: 'copilot-instructions', writesSharedSettings: false, finishPermissionWriter: null } as const),
|
||||
cline: Object.freeze({ installSurface: 'cline-rules', writesSharedSettings: false, finishPermissionWriter: null } as const),
|
||||
cursor: Object.freeze({ installSurface: 'profile-marker-only', writesSharedSettings: false, finishPermissionWriter: null } as const),
|
||||
windsurf: Object.freeze({ installSurface: 'profile-marker-only', writesSharedSettings: false, finishPermissionWriter: null } as const),
|
||||
trae: Object.freeze({ installSurface: 'profile-marker-only', writesSharedSettings: false, finishPermissionWriter: null } as const),
|
||||
kimi: Object.freeze({ installSurface: 'profile-marker-only', writesSharedSettings: false, finishPermissionWriter: null } as const),
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Exports
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** The complete set of 16 supported runtimes for config-adapter dispatch. */
|
||||
const ALLOWED_CONFIG_RUNTIMES: ReadonlySet<string> = new Set(Object.keys(REGISTRY));
|
||||
|
||||
/** All valid installSurface values. */
|
||||
const INSTALL_SURFACES: ReadonlyArray<ConfigInstallSurface> = Object.freeze([
|
||||
'settings-json',
|
||||
'codex-toml',
|
||||
'copilot-instructions',
|
||||
'cline-rules',
|
||||
'profile-marker-only',
|
||||
]);
|
||||
|
||||
/**
|
||||
* Resolve the config adapter intent for a given runtime.
|
||||
*
|
||||
* Returns a fresh object each call so callers cannot poison the registry by
|
||||
* mutating the returned value.
|
||||
*
|
||||
* @throws {TypeError} if runtime is not a known supported runtime.
|
||||
*/
|
||||
function resolveRuntimeConfigIntent(runtime: string): RuntimeConfigIntent {
|
||||
if (!Object.hasOwn(REGISTRY, runtime)) {
|
||||
throw new TypeError(`Unknown runtime for config adapter: ${runtime}`);
|
||||
}
|
||||
const entry = REGISTRY[runtime];
|
||||
return {
|
||||
runtime,
|
||||
installSurface: entry.installSurface,
|
||||
writesSharedSettings: entry.writesSharedSettings,
|
||||
finishPermissionWriter: entry.finishPermissionWriter,
|
||||
};
|
||||
}
|
||||
|
||||
export = { resolveRuntimeConfigIntent, ALLOWED_CONFIG_RUNTIMES, INSTALL_SURFACES };
|
||||
@@ -100,8 +100,15 @@ export function resolveKimiGlobalDir(opts: ResolveKimiOpts = {}): string {
|
||||
/**
|
||||
* Return the global config base directory for the given runtime.
|
||||
* Respects the same env-var overrides as bin/install.js getGlobalDir().
|
||||
*
|
||||
* @param runtime - The runtime identifier (e.g. 'claude', 'opencode').
|
||||
* @param explicitDir - If provided and non-empty, returned immediately after
|
||||
* tilde-expansion, overriding all env-var and default logic. This matches
|
||||
* the behaviour of bin/install.js getGlobalDir(runtime, explicitDir).
|
||||
*/
|
||||
export function getGlobalConfigDir(runtime: string): string {
|
||||
export function getGlobalConfigDir(runtime: string, explicitDir?: string | null): string {
|
||||
if (explicitDir) return expandTilde(explicitDir);
|
||||
|
||||
const home = os.homedir();
|
||||
const env = process.env as Record<string, string | undefined>;
|
||||
|
||||
@@ -172,6 +179,7 @@ export function getGlobalConfigDir(runtime: string): string {
|
||||
// ── OpenCode (XDG) ───────────────────────────────────────────────────────
|
||||
case 'opencode': {
|
||||
if (env['OPENCODE_CONFIG_DIR']) return expandTilde(env['OPENCODE_CONFIG_DIR']);
|
||||
if (env['OPENCODE_CONFIG']) return path.dirname(expandTilde(env['OPENCODE_CONFIG']));
|
||||
if (env['XDG_CONFIG_HOME']) return path.join(expandTilde(env['XDG_CONFIG_HOME']), 'opencode');
|
||||
return path.join(home, '.config', 'opencode');
|
||||
}
|
||||
@@ -179,6 +187,7 @@ export function getGlobalConfigDir(runtime: string): string {
|
||||
// ── Kilo (XDG) ───────────────────────────────────────────────────────────
|
||||
case 'kilo': {
|
||||
if (env['KILO_CONFIG_DIR']) return expandTilde(env['KILO_CONFIG_DIR']);
|
||||
if (env['KILO_CONFIG']) return path.dirname(expandTilde(env['KILO_CONFIG']));
|
||||
if (env['XDG_CONFIG_HOME']) return path.join(expandTilde(env['XDG_CONFIG_HOME']), 'kilo');
|
||||
return path.join(home, '.config', 'kilo');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user