mirror of
https://github.com/affaan-m/ECC.git
synced 2026-08-20 06:25:43 +02:00
* feat(install): add guided Claude plugin setup * fix: support Claude command shims on Windows * feat: support safe Claude plugin scope migration * fix(install): preserve interactive setup terminal * fix(install): auto-migrate setup scope changes * feat(install): add guided multi-harness installer * fix(install): sync Yarn binary metadata * fix(install): handle wizard EOF on Node 18 * ci: allow installer matrix tests to finish * test(install): allow slower PowerShell delegation * fix(install): harden guided provider reconciliation * test(install): harden packaged and local compatibility * chore: prepare guided installer release 2.2.0 * fix(install): report refreshed Codex marketplace state * fix(install): verify managed content provenance * test(install): allow empty Yarn smoke fixture * test(install): invoke Windows package shims safely * fix(install): close cross-platform release gaps * fix(install): require trusted GitHub origins * fix(install): preserve hook profile precedence * refactor(install): centralize trusted GitHub origins * ci: retrigger workflow run after merge of main Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
110 lines
3.5 KiB
JavaScript
110 lines
3.5 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const {
|
|
createInstallTargetAdapter,
|
|
createManagedOperation,
|
|
isForeignPlatformPath,
|
|
} = require('./helpers');
|
|
|
|
function readJsonObject(filePath, label) {
|
|
let parsed;
|
|
try {
|
|
parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
} catch (error) {
|
|
throw new Error(`Failed to parse ${label} at ${filePath}: ${error.message}`);
|
|
}
|
|
|
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
throw new Error(`Invalid ${label} at ${filePath}: expected a JSON object`);
|
|
}
|
|
|
|
return parsed;
|
|
}
|
|
|
|
function createMcpMergeOperation(moduleId, repoRoot, targetRoot) {
|
|
if (!repoRoot) {
|
|
throw new Error('repoRoot is required to plan Kimi MCP configuration');
|
|
}
|
|
|
|
const sourceRelativePath = '.mcp.json';
|
|
const sourcePath = path.join(repoRoot, sourceRelativePath);
|
|
if (!fs.existsSync(sourcePath) || !fs.statSync(sourcePath).isFile()) {
|
|
return null;
|
|
}
|
|
|
|
return createManagedOperation({
|
|
kind: 'merge-json',
|
|
moduleId,
|
|
sourceRelativePath,
|
|
destinationPath: path.join(targetRoot, 'mcp.json'),
|
|
strategy: 'merge-json',
|
|
scaffoldOnly: false,
|
|
mergePayload: readJsonObject(sourcePath, sourceRelativePath),
|
|
});
|
|
}
|
|
|
|
module.exports = createInstallTargetAdapter({
|
|
id: 'kimi-project',
|
|
target: 'kimi',
|
|
kind: 'project',
|
|
rootSegments: ['.kimi-code'],
|
|
installStatePathSegments: ['ecc-install-state.json'],
|
|
nativeRootRelativePath: '.kimi-code',
|
|
planOperations(input, adapter) {
|
|
const modules = Array.isArray(input.modules)
|
|
? input.modules
|
|
: (input.module ? [input.module] : []);
|
|
const planningInput = {
|
|
repoRoot: input.repoRoot,
|
|
projectRoot: input.projectRoot,
|
|
homeDir: input.homeDir,
|
|
};
|
|
const targetRoot = adapter.resolveRoot(planningInput);
|
|
|
|
return modules.flatMap(module => {
|
|
const paths = Array.isArray(module.paths) ? module.paths : [];
|
|
|
|
return paths
|
|
.filter(sourceRelativePath => !isForeignPlatformPath(sourceRelativePath, adapter.target))
|
|
.flatMap(sourceRelativePath => {
|
|
if (sourceRelativePath === '.kimi') {
|
|
// The repository's compatibility documentation still lives in
|
|
// .kimi/. Sync its children into the current native root without
|
|
// creating that obsolete directory in the destination project.
|
|
return [createManagedOperation({
|
|
moduleId: module.id,
|
|
sourceRelativePath,
|
|
destinationPath: targetRoot,
|
|
strategy: 'sync-root-children',
|
|
})];
|
|
}
|
|
|
|
if (sourceRelativePath === '.agents') {
|
|
const skillsSourcePath = path.join(input.repoRoot || '', '.agents', 'skills');
|
|
if (!input.repoRoot || !fs.existsSync(skillsSourcePath)) {
|
|
return [];
|
|
}
|
|
|
|
return [createManagedOperation({
|
|
moduleId: module.id,
|
|
sourceRelativePath: '.agents/skills',
|
|
destinationPath: path.join(targetRoot, 'skills'),
|
|
strategy: 'preserve-relative-path',
|
|
})];
|
|
}
|
|
|
|
if (sourceRelativePath === 'mcp-configs') {
|
|
const mcpMergeOperation = createMcpMergeOperation(module.id, input.repoRoot, targetRoot);
|
|
return [
|
|
adapter.createScaffoldOperation(module.id, sourceRelativePath, planningInput),
|
|
...(mcpMergeOperation ? [mcpMergeOperation] : []),
|
|
];
|
|
}
|
|
|
|
return [adapter.createScaffoldOperation(module.id, sourceRelativePath, planningInput)];
|
|
});
|
|
});
|
|
},
|
|
});
|