moicle 2.2.0 → 2.2.1
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.
- package/README.md +3 -2
- package/assets/architecture/hexagonal-architecture.md +128 -0
- package/assets/commands/bootstrap.md +4 -2
- package/dist/commands/install/generic-editor.d.ts +3 -0
- package/dist/commands/install/generic-editor.d.ts.map +1 -0
- package/dist/commands/install/generic-editor.js +41 -0
- package/dist/commands/install/generic-editor.js.map +1 -0
- package/dist/commands/install/index.d.ts +3 -0
- package/dist/commands/install/index.d.ts.map +1 -0
- package/dist/commands/install/index.js +71 -0
- package/dist/commands/install/index.js.map +1 -0
- package/dist/commands/install/native.d.ts +3 -0
- package/dist/commands/install/native.d.ts.map +1 -0
- package/dist/commands/install/native.js +75 -0
- package/dist/commands/install/native.js.map +1 -0
- package/dist/commands/install/print.d.ts +6 -0
- package/dist/commands/install/print.d.ts.map +1 -0
- package/dist/commands/install/print.js +31 -0
- package/dist/commands/install/print.js.map +1 -0
- package/dist/commands/install/prompts.d.ts +4 -0
- package/dist/commands/install/prompts.d.ts.map +1 -0
- package/dist/commands/install/prompts.js +40 -0
- package/dist/commands/install/prompts.js.map +1 -0
- package/dist/commands/install/skill-editor.d.ts +4 -0
- package/dist/commands/install/skill-editor.d.ts.map +1 -0
- package/dist/commands/install/skill-editor.js +130 -0
- package/dist/commands/install/skill-editor.js.map +1 -0
- package/dist/commands/install/transform.d.ts +15 -0
- package/dist/commands/install/transform.d.ts.map +1 -0
- package/dist/commands/install/transform.js +47 -0
- package/dist/commands/install/transform.js.map +1 -0
- package/dist/commands/install/usage.d.ts +3 -0
- package/dist/commands/install/usage.d.ts.map +1 -0
- package/dist/commands/install/usage.js +72 -0
- package/dist/commands/install/usage.js.map +1 -0
- package/dist/commands/install.d.ts +1 -2
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +1 -657
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/postinstall.d.ts.map +1 -1
- package/dist/commands/postinstall.js +4 -1
- package/dist/commands/postinstall.js.map +1 -1
- package/package.json +1 -1
package/dist/commands/install.js
CHANGED
|
@@ -1,658 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
import inquirer from 'inquirer';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import fs from 'fs';
|
|
5
|
-
import { ASSETS_DIR, EDITOR_CONFIGS, isSymlinkSupported, ensureDir, createSymlink, copyFile, copyDir, getAgentsDir, getCommandsDir, getSkillsDir, getArchitectureDir, getClaudeDir, getCodexDir, getAntigravityDir, getEditorDir, getEditorConfig, getFiles, getDirs, mergeAgentsToFile, } from '../utils/symlink.js';
|
|
6
|
-
import { addTarget } from '../utils/config.js';
|
|
7
|
-
const printHeader = () => {
|
|
8
|
-
console.log('');
|
|
9
|
-
console.log(chalk.cyan('════════════════════════════════════════'));
|
|
10
|
-
console.log(chalk.cyan(' MoiCle Installer'));
|
|
11
|
-
console.log(chalk.cyan('════════════════════════════════════════'));
|
|
12
|
-
console.log('');
|
|
13
|
-
};
|
|
14
|
-
const printSummary = (results) => {
|
|
15
|
-
const created = results.filter((r) => r.status === 'created').length;
|
|
16
|
-
const updated = results.filter((r) => r.status === 'updated').length;
|
|
17
|
-
const exists = results.filter((r) => r.status === 'exists').length;
|
|
18
|
-
const skipped = results.filter((r) => r.status === 'skipped').length;
|
|
19
|
-
const errors = results.filter((r) => r.status === 'error').length;
|
|
20
|
-
if (created > 0)
|
|
21
|
-
console.log(chalk.green(` Created: ${created}`));
|
|
22
|
-
if (updated > 0)
|
|
23
|
-
console.log(chalk.yellow(` Updated: ${updated}`));
|
|
24
|
-
if (exists > 0)
|
|
25
|
-
console.log(chalk.gray(` Already exists: ${exists}`));
|
|
26
|
-
if (skipped > 0)
|
|
27
|
-
console.log(chalk.gray(` Skipped: ${skipped}`));
|
|
28
|
-
if (errors > 0)
|
|
29
|
-
console.log(chalk.red(` Errors: ${errors}`));
|
|
30
|
-
};
|
|
31
|
-
const installAgents = async (targetDir, useSymlink = true) => {
|
|
32
|
-
const results = [];
|
|
33
|
-
ensureDir(targetDir);
|
|
34
|
-
const developersDir = path.join(ASSETS_DIR, 'agents', 'developers');
|
|
35
|
-
if (fs.existsSync(developersDir)) {
|
|
36
|
-
const files = getFiles(developersDir);
|
|
37
|
-
for (const file of files) {
|
|
38
|
-
const target = path.join(targetDir, path.basename(file));
|
|
39
|
-
const result = useSymlink ? createSymlink(file, target) : copyFile(file, target);
|
|
40
|
-
results.push(result);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
const utilitiesDir = path.join(ASSETS_DIR, 'agents', 'utilities');
|
|
44
|
-
if (fs.existsSync(utilitiesDir)) {
|
|
45
|
-
const files = getFiles(utilitiesDir);
|
|
46
|
-
for (const file of files) {
|
|
47
|
-
const target = path.join(targetDir, path.basename(file));
|
|
48
|
-
const result = useSymlink ? createSymlink(file, target) : copyFile(file, target);
|
|
49
|
-
results.push(result);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
console.log(chalk.green(` ✓ Agents installed to ${chalk.cyan(targetDir)}`));
|
|
53
|
-
printSummary(results);
|
|
54
|
-
return results;
|
|
55
|
-
};
|
|
56
|
-
const installCommands = async (targetDir, useSymlink = true) => {
|
|
57
|
-
const results = [];
|
|
58
|
-
ensureDir(targetDir);
|
|
59
|
-
const commandsDir = path.join(ASSETS_DIR, 'commands');
|
|
60
|
-
if (fs.existsSync(commandsDir)) {
|
|
61
|
-
const files = getFiles(commandsDir);
|
|
62
|
-
for (const file of files) {
|
|
63
|
-
const target = path.join(targetDir, path.basename(file));
|
|
64
|
-
const result = useSymlink ? createSymlink(file, target) : copyFile(file, target);
|
|
65
|
-
results.push(result);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
console.log(chalk.green(` ✓ Commands installed to ${chalk.cyan(targetDir)}`));
|
|
69
|
-
printSummary(results);
|
|
70
|
-
return results;
|
|
71
|
-
};
|
|
72
|
-
const installSkills = async (targetDir, useSymlink = true) => {
|
|
73
|
-
const results = [];
|
|
74
|
-
ensureDir(targetDir);
|
|
75
|
-
const skillsDir = path.join(ASSETS_DIR, 'skills');
|
|
76
|
-
if (fs.existsSync(skillsDir)) {
|
|
77
|
-
const dirs = getDirs(skillsDir);
|
|
78
|
-
for (const dir of dirs) {
|
|
79
|
-
const target = path.join(targetDir, path.basename(dir));
|
|
80
|
-
if (useSymlink) {
|
|
81
|
-
const result = createSymlink(dir, target);
|
|
82
|
-
results.push(result);
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
const result = copyDir(dir, target);
|
|
86
|
-
results.push(result);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
console.log(chalk.green(` ✓ Skills installed to ${chalk.cyan(targetDir)}`));
|
|
91
|
-
printSummary(results);
|
|
92
|
-
return results;
|
|
93
|
-
};
|
|
94
|
-
const installArchitecture = async (targetDir, useSymlink = true) => {
|
|
95
|
-
const results = [];
|
|
96
|
-
ensureDir(targetDir);
|
|
97
|
-
const archDir = path.join(ASSETS_DIR, 'architecture');
|
|
98
|
-
if (fs.existsSync(archDir)) {
|
|
99
|
-
const files = getFiles(archDir);
|
|
100
|
-
for (const file of files) {
|
|
101
|
-
const target = path.join(targetDir, path.basename(file));
|
|
102
|
-
const result = useSymlink ? createSymlink(file, target) : copyFile(file, target);
|
|
103
|
-
results.push(result);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
console.log(chalk.green(` ✓ Architecture installed to ${chalk.cyan(targetDir)}`));
|
|
107
|
-
printSummary(results);
|
|
108
|
-
return results;
|
|
109
|
-
};
|
|
110
|
-
const installScope = async (scope, useSymlink) => {
|
|
111
|
-
const isGlobal = scope === 'global';
|
|
112
|
-
const label = isGlobal ? 'Global' : 'Project';
|
|
113
|
-
const targetPath = isGlobal ? '~/.claude/' : `${process.cwd()}/.claude/`;
|
|
114
|
-
console.log('');
|
|
115
|
-
console.log(chalk.cyan(`>>> ${label} Installation`));
|
|
116
|
-
console.log(chalk.gray(` Target: ${targetPath}`));
|
|
117
|
-
console.log('');
|
|
118
|
-
const claudeDir = getClaudeDir(scope);
|
|
119
|
-
ensureDir(claudeDir);
|
|
120
|
-
await installAgents(getAgentsDir(scope), useSymlink);
|
|
121
|
-
if (isGlobal) {
|
|
122
|
-
await installCommands(getCommandsDir(scope), useSymlink);
|
|
123
|
-
}
|
|
124
|
-
await installSkills(getSkillsDir(scope), useSymlink);
|
|
125
|
-
await installArchitecture(getArchitectureDir(scope), useSymlink);
|
|
126
|
-
if (!isGlobal) {
|
|
127
|
-
console.log(chalk.gray(' Note: Commands are installed globally only'));
|
|
128
|
-
}
|
|
129
|
-
console.log('');
|
|
130
|
-
console.log(chalk.green(`✓ ${label} installation complete!`));
|
|
131
|
-
};
|
|
132
|
-
const rewriteClaudePaths = (content, target) => {
|
|
133
|
-
if (target === 'claude') {
|
|
134
|
-
return content;
|
|
135
|
-
}
|
|
136
|
-
if (target === 'antigravity') {
|
|
137
|
-
return content
|
|
138
|
-
.replace(/~\/\.claude\//g, '~/.gemini/')
|
|
139
|
-
.replace(/\.claude\//g, '.gemini/')
|
|
140
|
-
.replace(/Claude Code/g, 'Antigravity')
|
|
141
|
-
.replace(/CLAUDE\.md/g, 'GEMINI.md');
|
|
142
|
-
}
|
|
143
|
-
return content
|
|
144
|
-
.replace(/~\/\.claude\//g, '~/.codex/')
|
|
145
|
-
.replace(/\.claude\//g, '.codex/')
|
|
146
|
-
.replace(/Claude Code/g, 'Codex CLI')
|
|
147
|
-
.replace(/CLAUDE\.md/g, 'AGENTS.md');
|
|
148
|
-
};
|
|
149
|
-
const ensureCodexSkillDir = (baseDir, name) => {
|
|
150
|
-
const skillDir = path.join(baseDir, name);
|
|
151
|
-
ensureDir(skillDir);
|
|
152
|
-
return skillDir;
|
|
153
|
-
};
|
|
154
|
-
const installCodexSkillFolder = (sourceDir, targetSkillsDir) => {
|
|
155
|
-
const skillName = path.basename(sourceDir);
|
|
156
|
-
const targetDir = ensureCodexSkillDir(targetSkillsDir, skillName);
|
|
157
|
-
const sourceFiles = getFiles(sourceDir, 8);
|
|
158
|
-
let status = 'created';
|
|
159
|
-
for (const file of sourceFiles) {
|
|
160
|
-
const relativePath = path.relative(sourceDir, file);
|
|
161
|
-
const targetFile = path.join(targetDir, relativePath);
|
|
162
|
-
ensureDir(path.dirname(targetFile));
|
|
163
|
-
const content = rewriteClaudePaths(fs.readFileSync(file, 'utf-8'), 'codex');
|
|
164
|
-
const existed = fs.existsSync(targetFile);
|
|
165
|
-
if (existed && fs.readFileSync(targetFile, 'utf-8') === content) {
|
|
166
|
-
status = status === 'created' ? 'exists' : status;
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
fs.writeFileSync(targetFile, content);
|
|
170
|
-
if (existed) {
|
|
171
|
-
status = 'updated';
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
return { status, name: skillName };
|
|
175
|
-
};
|
|
176
|
-
const buildGeneratedCodexSkill = (name, description, body) => `---
|
|
177
|
-
name: ${name}
|
|
178
|
-
description: ${description}
|
|
179
|
-
---
|
|
180
|
-
|
|
181
|
-
${body}
|
|
182
|
-
`;
|
|
183
|
-
const extractFrontmatter = (content) => {
|
|
184
|
-
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
|
185
|
-
if (!match) {
|
|
186
|
-
return { frontmatter: null, body: content };
|
|
187
|
-
}
|
|
188
|
-
const frontmatter = match[1];
|
|
189
|
-
const body = match[2];
|
|
190
|
-
const descriptionMatch = frontmatter.match(/^description:\s*(.+)$/m);
|
|
191
|
-
return {
|
|
192
|
-
frontmatter,
|
|
193
|
-
body,
|
|
194
|
-
description: descriptionMatch?.[1]?.trim(),
|
|
195
|
-
};
|
|
196
|
-
};
|
|
197
|
-
const installGeneratedCodexSkill = (targetSkillsDir, name, description, body) => {
|
|
198
|
-
const skillDir = ensureCodexSkillDir(targetSkillsDir, name);
|
|
199
|
-
const targetFile = path.join(skillDir, 'SKILL.md');
|
|
200
|
-
const content = buildGeneratedCodexSkill(name, description, rewriteClaudePaths(body, 'codex'));
|
|
201
|
-
if (fs.existsSync(targetFile)) {
|
|
202
|
-
if (fs.readFileSync(targetFile, 'utf-8') === content) {
|
|
203
|
-
return { status: 'exists', name };
|
|
204
|
-
}
|
|
205
|
-
fs.writeFileSync(targetFile, content);
|
|
206
|
-
return { status: 'updated', name };
|
|
207
|
-
}
|
|
208
|
-
fs.writeFileSync(targetFile, content);
|
|
209
|
-
return { status: 'created', name };
|
|
210
|
-
};
|
|
211
|
-
const installDirectCodexSkill = (targetSkillsDir, name, content) => {
|
|
212
|
-
const skillDir = ensureCodexSkillDir(targetSkillsDir, name);
|
|
213
|
-
const targetFile = path.join(skillDir, 'SKILL.md');
|
|
214
|
-
const rewritten = rewriteClaudePaths(content, 'codex');
|
|
215
|
-
if (fs.existsSync(targetFile)) {
|
|
216
|
-
if (fs.readFileSync(targetFile, 'utf-8') === rewritten) {
|
|
217
|
-
return { status: 'exists', name };
|
|
218
|
-
}
|
|
219
|
-
fs.writeFileSync(targetFile, rewritten);
|
|
220
|
-
return { status: 'updated', name };
|
|
221
|
-
}
|
|
222
|
-
fs.writeFileSync(targetFile, rewritten);
|
|
223
|
-
return { status: 'created', name };
|
|
224
|
-
};
|
|
225
|
-
const installCodexArchitecture = (targetDir) => {
|
|
226
|
-
const results = [];
|
|
227
|
-
const archDir = path.join(ASSETS_DIR, 'architecture');
|
|
228
|
-
const targetArchDir = path.join(targetDir, 'architecture');
|
|
229
|
-
ensureDir(targetArchDir);
|
|
230
|
-
if (!fs.existsSync(archDir)) {
|
|
231
|
-
return results;
|
|
232
|
-
}
|
|
233
|
-
for (const file of getFiles(archDir)) {
|
|
234
|
-
const targetFile = path.join(targetArchDir, path.basename(file));
|
|
235
|
-
const content = rewriteClaudePaths(fs.readFileSync(file, 'utf-8'), 'codex');
|
|
236
|
-
if (fs.existsSync(targetFile)) {
|
|
237
|
-
if (fs.readFileSync(targetFile, 'utf-8') === content) {
|
|
238
|
-
results.push({ status: 'exists', name: path.basename(file) });
|
|
239
|
-
continue;
|
|
240
|
-
}
|
|
241
|
-
fs.writeFileSync(targetFile, content);
|
|
242
|
-
results.push({ status: 'updated', name: path.basename(file) });
|
|
243
|
-
continue;
|
|
244
|
-
}
|
|
245
|
-
fs.writeFileSync(targetFile, content);
|
|
246
|
-
results.push({ status: 'created', name: path.basename(file) });
|
|
247
|
-
}
|
|
248
|
-
return results;
|
|
249
|
-
};
|
|
250
|
-
const installCodexSkills = (targetDir) => {
|
|
251
|
-
const results = [];
|
|
252
|
-
const targetSkillsDir = path.join(targetDir, 'skills');
|
|
253
|
-
ensureDir(targetSkillsDir);
|
|
254
|
-
const skillsDir = path.join(ASSETS_DIR, 'skills');
|
|
255
|
-
if (fs.existsSync(skillsDir)) {
|
|
256
|
-
for (const dir of getDirs(skillsDir)) {
|
|
257
|
-
results.push(installCodexSkillFolder(dir, targetSkillsDir));
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
const commandsDir = path.join(ASSETS_DIR, 'commands');
|
|
261
|
-
if (fs.existsSync(commandsDir)) {
|
|
262
|
-
for (const file of getFiles(commandsDir)) {
|
|
263
|
-
const name = path.basename(file, '.md');
|
|
264
|
-
const content = fs.readFileSync(file, 'utf-8');
|
|
265
|
-
results.push(installDirectCodexSkill(targetSkillsDir, name, content));
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
const agentDirs = ['developers', 'utilities'];
|
|
269
|
-
for (const dirName of agentDirs) {
|
|
270
|
-
const sourceDir = path.join(ASSETS_DIR, 'agents', dirName);
|
|
271
|
-
if (!fs.existsSync(sourceDir)) {
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
274
|
-
for (const file of getFiles(sourceDir)) {
|
|
275
|
-
const name = path.basename(file, '.md');
|
|
276
|
-
const rawContent = fs.readFileSync(file, 'utf-8');
|
|
277
|
-
const parsed = extractFrontmatter(rawContent);
|
|
278
|
-
const description = parsed.description
|
|
279
|
-
? parsed.description
|
|
280
|
-
: dirName === 'developers'
|
|
281
|
-
? `Imported MoiCle developer persona for ${name}. Use when the task matches this stack specialist.`
|
|
282
|
-
: `Imported MoiCle utility persona for ${name}. Use when the task matches this specialist.`;
|
|
283
|
-
results.push(installGeneratedCodexSkill(targetSkillsDir, name, description, parsed.body.trimStart()));
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
return results;
|
|
287
|
-
};
|
|
288
|
-
const installCodexScope = async (scope) => {
|
|
289
|
-
const isGlobal = scope === 'global';
|
|
290
|
-
const label = isGlobal ? 'Global' : 'Project';
|
|
291
|
-
const targetPath = isGlobal ? '~/.codex/' : `${process.cwd()}/.codex/`;
|
|
292
|
-
console.log('');
|
|
293
|
-
console.log(chalk.cyan(`>>> ${label} Codex Installation`));
|
|
294
|
-
console.log(chalk.gray(` Target: ${targetPath}`));
|
|
295
|
-
console.log('');
|
|
296
|
-
const codexDir = getCodexDir(scope);
|
|
297
|
-
ensureDir(codexDir);
|
|
298
|
-
const archResults = installCodexArchitecture(codexDir);
|
|
299
|
-
console.log(chalk.green(` ✓ Architecture installed to ${chalk.cyan(path.join(codexDir, 'architecture'))}`));
|
|
300
|
-
printSummary(archResults);
|
|
301
|
-
const skillResults = installCodexSkills(codexDir);
|
|
302
|
-
console.log(chalk.green(` ✓ Codex skills installed to ${chalk.cyan(path.join(codexDir, 'skills'))}`));
|
|
303
|
-
printSummary(skillResults);
|
|
304
|
-
console.log('');
|
|
305
|
-
console.log(chalk.green(`✓ ${label} Codex installation complete!`));
|
|
306
|
-
};
|
|
307
|
-
const ensureAntigravitySkillDir = (baseDir, name) => {
|
|
308
|
-
const skillDir = path.join(baseDir, name);
|
|
309
|
-
ensureDir(skillDir);
|
|
310
|
-
return skillDir;
|
|
311
|
-
};
|
|
312
|
-
const installAntigravitySkillFolder = (sourceDir, targetSkillsDir) => {
|
|
313
|
-
const skillName = path.basename(sourceDir);
|
|
314
|
-
const targetDir = ensureAntigravitySkillDir(targetSkillsDir, skillName);
|
|
315
|
-
const sourceFiles = getFiles(sourceDir, 8);
|
|
316
|
-
let status = 'created';
|
|
317
|
-
for (const file of sourceFiles) {
|
|
318
|
-
const relativePath = path.relative(sourceDir, file);
|
|
319
|
-
const targetFile = path.join(targetDir, relativePath);
|
|
320
|
-
ensureDir(path.dirname(targetFile));
|
|
321
|
-
const content = rewriteClaudePaths(fs.readFileSync(file, 'utf-8'), 'antigravity');
|
|
322
|
-
const existed = fs.existsSync(targetFile);
|
|
323
|
-
if (existed && fs.readFileSync(targetFile, 'utf-8') === content) {
|
|
324
|
-
status = status === 'created' ? 'exists' : status;
|
|
325
|
-
continue;
|
|
326
|
-
}
|
|
327
|
-
fs.writeFileSync(targetFile, content);
|
|
328
|
-
if (existed) {
|
|
329
|
-
status = 'updated';
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
return { status, name: skillName };
|
|
333
|
-
};
|
|
334
|
-
const buildGeneratedAntigravitySkill = (name, description, body) => `---
|
|
335
|
-
name: ${name}
|
|
336
|
-
description: ${description}
|
|
337
|
-
---
|
|
338
|
-
|
|
339
|
-
${body}
|
|
340
|
-
`;
|
|
341
|
-
const installGeneratedAntigravitySkill = (targetSkillsDir, name, description, body) => {
|
|
342
|
-
const skillDir = ensureAntigravitySkillDir(targetSkillsDir, name);
|
|
343
|
-
const targetFile = path.join(skillDir, 'SKILL.md');
|
|
344
|
-
const content = buildGeneratedAntigravitySkill(name, description, rewriteClaudePaths(body, 'antigravity'));
|
|
345
|
-
if (fs.existsSync(targetFile)) {
|
|
346
|
-
if (fs.readFileSync(targetFile, 'utf-8') === content) {
|
|
347
|
-
return { status: 'exists', name };
|
|
348
|
-
}
|
|
349
|
-
fs.writeFileSync(targetFile, content);
|
|
350
|
-
return { status: 'updated', name };
|
|
351
|
-
}
|
|
352
|
-
fs.writeFileSync(targetFile, content);
|
|
353
|
-
return { status: 'created', name };
|
|
354
|
-
};
|
|
355
|
-
const installDirectAntigravitySkill = (targetSkillsDir, name, content) => {
|
|
356
|
-
const skillDir = ensureAntigravitySkillDir(targetSkillsDir, name);
|
|
357
|
-
const targetFile = path.join(skillDir, 'SKILL.md');
|
|
358
|
-
const rewritten = rewriteClaudePaths(content, 'antigravity');
|
|
359
|
-
if (fs.existsSync(targetFile)) {
|
|
360
|
-
if (fs.readFileSync(targetFile, 'utf-8') === rewritten) {
|
|
361
|
-
return { status: 'exists', name };
|
|
362
|
-
}
|
|
363
|
-
fs.writeFileSync(targetFile, rewritten);
|
|
364
|
-
return { status: 'updated', name };
|
|
365
|
-
}
|
|
366
|
-
fs.writeFileSync(targetFile, rewritten);
|
|
367
|
-
return { status: 'created', name };
|
|
368
|
-
};
|
|
369
|
-
const installAntigravityArchitecture = (targetDir) => {
|
|
370
|
-
const results = [];
|
|
371
|
-
const archDir = path.join(ASSETS_DIR, 'architecture');
|
|
372
|
-
const targetArchDir = path.join(targetDir, 'architecture');
|
|
373
|
-
ensureDir(targetArchDir);
|
|
374
|
-
if (!fs.existsSync(archDir)) {
|
|
375
|
-
return results;
|
|
376
|
-
}
|
|
377
|
-
for (const file of getFiles(archDir)) {
|
|
378
|
-
const targetFile = path.join(targetArchDir, path.basename(file));
|
|
379
|
-
const content = rewriteClaudePaths(fs.readFileSync(file, 'utf-8'), 'antigravity');
|
|
380
|
-
if (fs.existsSync(targetFile)) {
|
|
381
|
-
if (fs.readFileSync(targetFile, 'utf-8') === content) {
|
|
382
|
-
results.push({ status: 'exists', name: path.basename(file) });
|
|
383
|
-
continue;
|
|
384
|
-
}
|
|
385
|
-
fs.writeFileSync(targetFile, content);
|
|
386
|
-
results.push({ status: 'updated', name: path.basename(file) });
|
|
387
|
-
continue;
|
|
388
|
-
}
|
|
389
|
-
fs.writeFileSync(targetFile, content);
|
|
390
|
-
results.push({ status: 'created', name: path.basename(file) });
|
|
391
|
-
}
|
|
392
|
-
return results;
|
|
393
|
-
};
|
|
394
|
-
const installAntigravitySkills = (targetDir) => {
|
|
395
|
-
const results = [];
|
|
396
|
-
const targetSkillsDir = path.join(targetDir, 'skills');
|
|
397
|
-
ensureDir(targetSkillsDir);
|
|
398
|
-
const skillsDir = path.join(ASSETS_DIR, 'skills');
|
|
399
|
-
if (fs.existsSync(skillsDir)) {
|
|
400
|
-
for (const dir of getDirs(skillsDir)) {
|
|
401
|
-
results.push(installAntigravitySkillFolder(dir, targetSkillsDir));
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
const commandsDir = path.join(ASSETS_DIR, 'commands');
|
|
405
|
-
if (fs.existsSync(commandsDir)) {
|
|
406
|
-
for (const file of getFiles(commandsDir)) {
|
|
407
|
-
const name = path.basename(file, '.md');
|
|
408
|
-
const content = fs.readFileSync(file, 'utf-8');
|
|
409
|
-
results.push(installDirectAntigravitySkill(targetSkillsDir, name, content));
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
const agentDirs = ['developers', 'utilities'];
|
|
413
|
-
for (const dirName of agentDirs) {
|
|
414
|
-
const sourceDir = path.join(ASSETS_DIR, 'agents', dirName);
|
|
415
|
-
if (!fs.existsSync(sourceDir)) {
|
|
416
|
-
continue;
|
|
417
|
-
}
|
|
418
|
-
for (const file of getFiles(sourceDir)) {
|
|
419
|
-
const name = path.basename(file, '.md');
|
|
420
|
-
const rawContent = fs.readFileSync(file, 'utf-8');
|
|
421
|
-
const parsed = extractFrontmatter(rawContent);
|
|
422
|
-
const description = parsed.description
|
|
423
|
-
? parsed.description
|
|
424
|
-
: dirName === 'developers'
|
|
425
|
-
? `Imported MoiCle developer persona for ${name}. Use when the task matches this stack specialist.`
|
|
426
|
-
: `Imported MoiCle utility persona for ${name}. Use when the task matches this specialist.`;
|
|
427
|
-
results.push(installGeneratedAntigravitySkill(targetSkillsDir, name, description, parsed.body.trimStart()));
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
return results;
|
|
431
|
-
};
|
|
432
|
-
const installAntigravityScope = async (scope) => {
|
|
433
|
-
const isGlobal = scope === 'global';
|
|
434
|
-
const label = isGlobal ? 'Global' : 'Project';
|
|
435
|
-
const targetPath = isGlobal ? '~/.gemini/' : `${process.cwd()}/.gemini/`;
|
|
436
|
-
console.log('');
|
|
437
|
-
console.log(chalk.cyan(`>>> ${label} Antigravity Installation`));
|
|
438
|
-
console.log(chalk.gray(` Target: ${targetPath}`));
|
|
439
|
-
console.log('');
|
|
440
|
-
const antigravityDir = getAntigravityDir(scope);
|
|
441
|
-
ensureDir(antigravityDir);
|
|
442
|
-
const archResults = installAntigravityArchitecture(antigravityDir);
|
|
443
|
-
console.log(chalk.green(` ✓ Architecture installed to ${chalk.cyan(path.join(antigravityDir, 'architecture'))}`));
|
|
444
|
-
printSummary(archResults);
|
|
445
|
-
const skillResults = installAntigravitySkills(antigravityDir);
|
|
446
|
-
console.log(chalk.green(` ✓ Antigravity skills installed to ${chalk.cyan(path.join(antigravityDir, 'skills'))}`));
|
|
447
|
-
printSummary(skillResults);
|
|
448
|
-
console.log('');
|
|
449
|
-
console.log(chalk.green(`✓ ${label} Antigravity installation complete!`));
|
|
450
|
-
};
|
|
451
|
-
const showTargetMenu = async () => {
|
|
452
|
-
const { target } = await inquirer.prompt([
|
|
453
|
-
{
|
|
454
|
-
type: 'list',
|
|
455
|
-
name: 'target',
|
|
456
|
-
message: 'Which editor would you like to configure?',
|
|
457
|
-
choices: [
|
|
458
|
-
{ name: 'Claude Code', value: 'claude' },
|
|
459
|
-
{ name: 'Codex CLI', value: 'codex' },
|
|
460
|
-
{ name: 'Antigravity', value: 'antigravity' },
|
|
461
|
-
],
|
|
462
|
-
},
|
|
463
|
-
]);
|
|
464
|
-
return target;
|
|
465
|
-
};
|
|
466
|
-
const showInteractiveMenu = async (target) => {
|
|
467
|
-
const globalPath = target === 'claude' ? '~/.claude/' : target === 'codex' ? '~/.codex/' : '~/.gemini/';
|
|
468
|
-
const projectPath = target === 'claude' ? './.claude/' : target === 'codex' ? './.codex/' : './.gemini/';
|
|
469
|
-
const { installType } = await inquirer.prompt([
|
|
470
|
-
{
|
|
471
|
-
type: 'list',
|
|
472
|
-
name: 'installType',
|
|
473
|
-
message: 'Where would you like to install?',
|
|
474
|
-
choices: [
|
|
475
|
-
{ name: `Global (${globalPath}) - Available for all projects`, value: 'global' },
|
|
476
|
-
{ name: `Project (${projectPath}) - This project only`, value: 'project' },
|
|
477
|
-
{ name: 'Both - Global and current project', value: 'all' },
|
|
478
|
-
],
|
|
479
|
-
},
|
|
480
|
-
]);
|
|
481
|
-
return installType;
|
|
482
|
-
};
|
|
483
|
-
const installArchitectureForEditor = (targetDir) => {
|
|
484
|
-
const results = [];
|
|
485
|
-
const archDir = path.join(ASSETS_DIR, 'architecture');
|
|
486
|
-
const targetArchDir = path.join(targetDir, 'architecture');
|
|
487
|
-
ensureDir(targetArchDir);
|
|
488
|
-
if (fs.existsSync(archDir)) {
|
|
489
|
-
const files = getFiles(archDir);
|
|
490
|
-
for (const file of files) {
|
|
491
|
-
const target = path.join(targetArchDir, path.basename(file));
|
|
492
|
-
const result = copyFile(file, target);
|
|
493
|
-
results.push(result);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
return results;
|
|
497
|
-
};
|
|
498
|
-
const installForOtherEditor = async (target, scope) => {
|
|
499
|
-
const config = getEditorConfig(target);
|
|
500
|
-
const results = [];
|
|
501
|
-
console.log('');
|
|
502
|
-
console.log(chalk.cyan(`>>> ${config.name} Installation`));
|
|
503
|
-
console.log(chalk.gray(` Target: ${getEditorDir(target, scope)}`));
|
|
504
|
-
console.log('');
|
|
505
|
-
const targetDir = getEditorDir(target, scope);
|
|
506
|
-
ensureDir(targetDir);
|
|
507
|
-
const archResults = installArchitectureForEditor(targetDir);
|
|
508
|
-
results.push(...archResults);
|
|
509
|
-
console.log(chalk.green(` ✓ Architecture installed to ${chalk.cyan(targetDir + '/architecture')}`));
|
|
510
|
-
if (config.rulesFile) {
|
|
511
|
-
const rulesFilePath = path.join(targetDir, config.rulesFile);
|
|
512
|
-
const result = mergeAgentsToFile(rulesFilePath, target);
|
|
513
|
-
results.push(result);
|
|
514
|
-
console.log(chalk.green(` ✓ Agents merged to ${chalk.cyan(config.rulesFile)}`));
|
|
515
|
-
}
|
|
516
|
-
printSummary(results);
|
|
517
|
-
console.log('');
|
|
518
|
-
console.log(chalk.green(`✓ ${config.name} installation complete!`));
|
|
519
|
-
return results;
|
|
520
|
-
};
|
|
521
|
-
export const installCommand = async (options) => {
|
|
522
|
-
printHeader();
|
|
523
|
-
if (!fs.existsSync(ASSETS_DIR)) {
|
|
524
|
-
console.log(chalk.red('Error: Assets directory not found.'));
|
|
525
|
-
console.log(chalk.gray(`Expected: ${ASSETS_DIR}`));
|
|
526
|
-
process.exit(1);
|
|
527
|
-
}
|
|
528
|
-
let targets = [];
|
|
529
|
-
let useSymlink;
|
|
530
|
-
if (options.symlink === true) {
|
|
531
|
-
useSymlink = true;
|
|
532
|
-
}
|
|
533
|
-
else if (options.symlink === false) {
|
|
534
|
-
useSymlink = false;
|
|
535
|
-
}
|
|
536
|
-
else {
|
|
537
|
-
useSymlink = isSymlinkSupported();
|
|
538
|
-
}
|
|
539
|
-
const strategyLabel = useSymlink ? 'symlinks' : 'file copy';
|
|
540
|
-
const isAutoDetected = options.symlink === undefined;
|
|
541
|
-
if (isAutoDetected) {
|
|
542
|
-
console.log(chalk.gray(` Auto-detected file strategy: ${strategyLabel} (${process.platform})`));
|
|
543
|
-
}
|
|
544
|
-
else {
|
|
545
|
-
console.log(chalk.gray(` File strategy: ${strategyLabel} (user override)`));
|
|
546
|
-
}
|
|
547
|
-
console.log('');
|
|
548
|
-
if (options.target) {
|
|
549
|
-
targets = [options.target];
|
|
550
|
-
}
|
|
551
|
-
else {
|
|
552
|
-
targets = [await showTargetMenu()];
|
|
553
|
-
}
|
|
554
|
-
for (const target of targets) {
|
|
555
|
-
addTarget(target);
|
|
556
|
-
if (target === 'claude' || target === 'codex' || target === 'antigravity') {
|
|
557
|
-
let installType;
|
|
558
|
-
if (options.global) {
|
|
559
|
-
installType = 'global';
|
|
560
|
-
}
|
|
561
|
-
else if (options.project) {
|
|
562
|
-
installType = 'project';
|
|
563
|
-
}
|
|
564
|
-
else if (options.all) {
|
|
565
|
-
installType = 'all';
|
|
566
|
-
}
|
|
567
|
-
else {
|
|
568
|
-
installType = await showInteractiveMenu(target);
|
|
569
|
-
}
|
|
570
|
-
switch (installType) {
|
|
571
|
-
case 'global':
|
|
572
|
-
if (target === 'claude') {
|
|
573
|
-
await installScope('global', useSymlink);
|
|
574
|
-
}
|
|
575
|
-
else if (target === 'codex') {
|
|
576
|
-
await installCodexScope('global');
|
|
577
|
-
}
|
|
578
|
-
else {
|
|
579
|
-
await installAntigravityScope('global');
|
|
580
|
-
}
|
|
581
|
-
break;
|
|
582
|
-
case 'project':
|
|
583
|
-
if (target === 'claude') {
|
|
584
|
-
await installScope('project', false);
|
|
585
|
-
}
|
|
586
|
-
else if (target === 'codex') {
|
|
587
|
-
await installCodexScope('project');
|
|
588
|
-
}
|
|
589
|
-
else {
|
|
590
|
-
await installAntigravityScope('project');
|
|
591
|
-
}
|
|
592
|
-
break;
|
|
593
|
-
case 'all':
|
|
594
|
-
if (target === 'claude') {
|
|
595
|
-
await installScope('global', useSymlink);
|
|
596
|
-
await installScope('project', false);
|
|
597
|
-
}
|
|
598
|
-
else if (target === 'codex') {
|
|
599
|
-
await installCodexScope('global');
|
|
600
|
-
await installCodexScope('project');
|
|
601
|
-
}
|
|
602
|
-
else {
|
|
603
|
-
await installAntigravityScope('global');
|
|
604
|
-
await installAntigravityScope('project');
|
|
605
|
-
}
|
|
606
|
-
break;
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
else {
|
|
610
|
-
await installForOtherEditor(target, 'global');
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
console.log('');
|
|
614
|
-
console.log(chalk.cyan('════════════════════════════════════════'));
|
|
615
|
-
console.log(chalk.cyan(' Usage'));
|
|
616
|
-
console.log(chalk.cyan('════════════════════════════════════════'));
|
|
617
|
-
console.log('');
|
|
618
|
-
if (targets.includes('claude')) {
|
|
619
|
-
console.log(chalk.bold(' Claude Code:'));
|
|
620
|
-
console.log(' Agents:');
|
|
621
|
-
console.log(chalk.gray(' @clean-architect Clean Architecture expert'));
|
|
622
|
-
console.log(chalk.gray(' @code-reviewer Code review expert'));
|
|
623
|
-
console.log(chalk.gray(' @test-writer Test writing expert'));
|
|
624
|
-
console.log('');
|
|
625
|
-
console.log(' Commands:');
|
|
626
|
-
console.log(chalk.gray(' /bootstrap Create new project'));
|
|
627
|
-
console.log(chalk.gray(' /brainstorm Brainstorm ideas'));
|
|
628
|
-
console.log(chalk.gray(' /doc Generate documentation'));
|
|
629
|
-
console.log('');
|
|
630
|
-
console.log(' Skills (auto-triggered):');
|
|
631
|
-
console.log(chalk.gray(' new-feature Feature development'));
|
|
632
|
-
console.log(chalk.gray(' hotfix Bug fix with rollback'));
|
|
633
|
-
console.log('');
|
|
634
|
-
}
|
|
635
|
-
if (targets.includes('codex')) {
|
|
636
|
-
console.log(chalk.bold(' Codex CLI:'));
|
|
637
|
-
console.log(chalk.gray(' Skills installed under ~/.codex/skills or ./.codex/skills'));
|
|
638
|
-
console.log(chalk.gray(' Architecture docs installed under ~/.codex/architecture or ./.codex/architecture'));
|
|
639
|
-
console.log(chalk.gray(' Restart Codex after global skill installation to pick up new skills'));
|
|
640
|
-
console.log('');
|
|
641
|
-
}
|
|
642
|
-
if (targets.includes('antigravity')) {
|
|
643
|
-
console.log(chalk.bold(' Antigravity:'));
|
|
644
|
-
console.log(chalk.gray(' Skills installed under ~/.gemini/skills or ./.gemini/skills'));
|
|
645
|
-
console.log(chalk.gray(' Architecture docs installed under ~/.gemini/architecture or ./.gemini/architecture'));
|
|
646
|
-
console.log('');
|
|
647
|
-
}
|
|
648
|
-
const otherTargets = targets.filter((t) => t !== 'claude' && t !== 'codex' && t !== 'antigravity');
|
|
649
|
-
if (otherTargets.length > 0) {
|
|
650
|
-
console.log(chalk.bold(' Other Editors:'));
|
|
651
|
-
for (const target of otherTargets) {
|
|
652
|
-
const config = EDITOR_CONFIGS[target];
|
|
653
|
-
console.log(chalk.gray(` ${config.name}: Agents merged into ${config.rulesFile}`));
|
|
654
|
-
}
|
|
655
|
-
console.log('');
|
|
656
|
-
}
|
|
657
|
-
};
|
|
1
|
+
export { installCommand } from './install/index.js';
|
|
658
2
|
//# sourceMappingURL=install.js.map
|