apero-kit-cli 2.1.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/dist/index.js +364 -68
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/gemini/settings.json +12 -0
package/dist/index.js
CHANGED
|
@@ -182,9 +182,10 @@ function getGlobalInstallPath() {
|
|
|
182
182
|
function isAkProject(dir = process.cwd()) {
|
|
183
183
|
const akConfig = join(dir, ".ak", "state.json");
|
|
184
184
|
const claudeDir = join(dir, ".claude");
|
|
185
|
+
const geminiDir = join(dir, ".gemini");
|
|
185
186
|
const opencodeDir = join(dir, ".opencode");
|
|
186
187
|
const agentDir = join(dir, ".agent");
|
|
187
|
-
return existsSync(akConfig) || existsSync(claudeDir) || existsSync(opencodeDir) || existsSync(agentDir);
|
|
188
|
+
return existsSync(akConfig) || existsSync(claudeDir) || existsSync(geminiDir) || existsSync(opencodeDir) || existsSync(agentDir);
|
|
188
189
|
}
|
|
189
190
|
function getTargetDir(projectDir, target = "claude") {
|
|
190
191
|
const folder = TARGETS[target] || TARGETS.claude;
|
|
@@ -242,6 +243,7 @@ var init_paths = __esm({
|
|
|
242
243
|
TEMPLATES_DIR = join(CLI_ROOT, "templates");
|
|
243
244
|
TARGETS = {
|
|
244
245
|
claude: ".claude",
|
|
246
|
+
gemini: ".gemini",
|
|
245
247
|
opencode: ".opencode",
|
|
246
248
|
generic: ".agent"
|
|
247
249
|
};
|
|
@@ -250,7 +252,37 @@ var init_paths = __esm({
|
|
|
250
252
|
|
|
251
253
|
// src/utils/copy.ts
|
|
252
254
|
import fs from "fs-extra";
|
|
253
|
-
import { join as join2 } from "path";
|
|
255
|
+
import { join as join2, dirname as dirname2 } from "path";
|
|
256
|
+
function parseFrontmatter(content) {
|
|
257
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
258
|
+
if (!frontmatterMatch) {
|
|
259
|
+
return { description: "", argumentHint: "", body: content };
|
|
260
|
+
}
|
|
261
|
+
const frontmatter = frontmatterMatch[1];
|
|
262
|
+
const body = frontmatterMatch[2].trim();
|
|
263
|
+
const descMatch = frontmatter.match(/description:\s*(.+)/);
|
|
264
|
+
const argMatch = frontmatter.match(/argument-hint:\s*(.+)/);
|
|
265
|
+
return {
|
|
266
|
+
description: descMatch ? descMatch[1].trim() : "",
|
|
267
|
+
argumentHint: argMatch ? argMatch[1].trim() : "",
|
|
268
|
+
body
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
function escapeTomlString(str) {
|
|
272
|
+
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
273
|
+
}
|
|
274
|
+
function convertMdToToml(mdContent) {
|
|
275
|
+
const { description, body } = parseFrontmatter(mdContent);
|
|
276
|
+
const prompt = body.replace(/\$ARGUMENTS/g, "{{args}}");
|
|
277
|
+
const lines = [];
|
|
278
|
+
if (description) {
|
|
279
|
+
lines.push(`description = "${escapeTomlString(description)}"`);
|
|
280
|
+
}
|
|
281
|
+
lines.push(`prompt = """
|
|
282
|
+
${prompt}
|
|
283
|
+
"""`);
|
|
284
|
+
return lines.join("\n");
|
|
285
|
+
}
|
|
254
286
|
async function copyItems(items, type, sourceDir, destDir, mergeMode = false) {
|
|
255
287
|
const typeDir = join2(sourceDir, type);
|
|
256
288
|
const destTypeDir = join2(destDir, type);
|
|
@@ -378,9 +410,209 @@ function listAvailable(type, sourceDir) {
|
|
|
378
410
|
return { name, isDir, path: itemPath };
|
|
379
411
|
});
|
|
380
412
|
}
|
|
413
|
+
async function copyCommandsForGemini(items, sourceDir, destDir, mergeMode = false) {
|
|
414
|
+
const typeDir = join2(sourceDir, "commands");
|
|
415
|
+
const destTypeDir = join2(destDir, "commands");
|
|
416
|
+
if (!fs.existsSync(typeDir)) {
|
|
417
|
+
return { copied: [], skipped: [], errors: [] };
|
|
418
|
+
}
|
|
419
|
+
await fs.ensureDir(destTypeDir);
|
|
420
|
+
const copied = [];
|
|
421
|
+
const skipped = [];
|
|
422
|
+
const errors = [];
|
|
423
|
+
let itemList;
|
|
424
|
+
if (items === "all") {
|
|
425
|
+
const entries = fs.readdirSync(typeDir);
|
|
426
|
+
itemList = entries.map((e) => e.replace(/\.md$/, ""));
|
|
427
|
+
itemList = [...new Set(itemList)];
|
|
428
|
+
} else {
|
|
429
|
+
itemList = items;
|
|
430
|
+
}
|
|
431
|
+
for (const item of itemList) {
|
|
432
|
+
try {
|
|
433
|
+
const srcPathMd = join2(typeDir, item + ".md");
|
|
434
|
+
const srcPathDir = join2(typeDir, item);
|
|
435
|
+
let copiedSomething = false;
|
|
436
|
+
if (fs.existsSync(srcPathMd) && fs.statSync(srcPathMd).isFile()) {
|
|
437
|
+
const destPath = join2(destTypeDir, item + ".toml");
|
|
438
|
+
if (!(mergeMode && fs.existsSync(destPath))) {
|
|
439
|
+
await fs.ensureDir(dirname2(destPath));
|
|
440
|
+
const mdContent = fs.readFileSync(srcPathMd, "utf-8");
|
|
441
|
+
const tomlContent = convertMdToToml(mdContent);
|
|
442
|
+
await fs.writeFile(destPath, tomlContent, "utf-8");
|
|
443
|
+
copiedSomething = true;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
if (fs.existsSync(srcPathDir) && fs.statSync(srcPathDir).isDirectory()) {
|
|
447
|
+
await convertDirectoryToToml(srcPathDir, join2(destTypeDir, item), mergeMode);
|
|
448
|
+
copiedSomething = true;
|
|
449
|
+
}
|
|
450
|
+
if (copiedSomething) {
|
|
451
|
+
copied.push(item);
|
|
452
|
+
} else {
|
|
453
|
+
skipped.push(item);
|
|
454
|
+
}
|
|
455
|
+
} catch (err) {
|
|
456
|
+
errors.push({ item, error: err.message });
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return { copied, skipped, errors };
|
|
460
|
+
}
|
|
461
|
+
async function convertDirectoryToToml(srcDir, destDir, mergeMode = false) {
|
|
462
|
+
await fs.ensureDir(destDir);
|
|
463
|
+
const entries = fs.readdirSync(srcDir);
|
|
464
|
+
for (const entry of entries) {
|
|
465
|
+
const srcPath = join2(srcDir, entry);
|
|
466
|
+
const stat = fs.statSync(srcPath);
|
|
467
|
+
if (stat.isDirectory()) {
|
|
468
|
+
await convertDirectoryToToml(srcPath, join2(destDir, entry), mergeMode);
|
|
469
|
+
} else if (entry.endsWith(".md")) {
|
|
470
|
+
const destPath = join2(destDir, entry.replace(/\.md$/, ".toml"));
|
|
471
|
+
if (mergeMode && fs.existsSync(destPath)) {
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
const mdContent = fs.readFileSync(srcPath, "utf-8");
|
|
475
|
+
const tomlContent = convertMdToToml(mdContent);
|
|
476
|
+
await fs.writeFile(destPath, tomlContent, "utf-8");
|
|
477
|
+
} else {
|
|
478
|
+
const destPath = join2(destDir, entry);
|
|
479
|
+
if (mergeMode && fs.existsSync(destPath)) {
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
function convertAgentForGemini(mdContent) {
|
|
487
|
+
const frontmatterMatch = mdContent.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
488
|
+
if (!frontmatterMatch) return mdContent;
|
|
489
|
+
let frontmatter = frontmatterMatch[1];
|
|
490
|
+
const body = frontmatterMatch[2];
|
|
491
|
+
const modelMap = {
|
|
492
|
+
"opus": "gemini-2.5-pro",
|
|
493
|
+
"sonnet": "gemini-2.5-flash",
|
|
494
|
+
"haiku": "gemini-2.0-flash-lite",
|
|
495
|
+
"inherit": ""
|
|
496
|
+
// Remove inherit, let Gemini use default
|
|
497
|
+
};
|
|
498
|
+
for (const [claudeModel, geminiModel] of Object.entries(modelMap)) {
|
|
499
|
+
const regex = new RegExp(`^model:\\s*${claudeModel}\\s*$`, "m");
|
|
500
|
+
if (geminiModel) {
|
|
501
|
+
frontmatter = frontmatter.replace(regex, `model: ${geminiModel}`);
|
|
502
|
+
} else {
|
|
503
|
+
frontmatter = frontmatter.replace(regex, "");
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
if (!frontmatter.includes("kind:")) {
|
|
507
|
+
frontmatter = frontmatter.trim() + "\nkind: local";
|
|
508
|
+
}
|
|
509
|
+
return `---
|
|
510
|
+
${frontmatter.trim()}
|
|
511
|
+
---
|
|
512
|
+
${body}`;
|
|
513
|
+
}
|
|
514
|
+
async function copyAgentsForGemini(items, sourceDir, destDir, mergeMode = false) {
|
|
515
|
+
const typeDir = join2(sourceDir, "agents");
|
|
516
|
+
const destTypeDir = join2(destDir, "agents");
|
|
517
|
+
if (!fs.existsSync(typeDir)) {
|
|
518
|
+
return { copied: [], skipped: [], errors: [] };
|
|
519
|
+
}
|
|
520
|
+
await fs.ensureDir(destTypeDir);
|
|
521
|
+
const copied = [];
|
|
522
|
+
const skipped = [];
|
|
523
|
+
const errors = [];
|
|
524
|
+
let agentList;
|
|
525
|
+
if (items === "all") {
|
|
526
|
+
const entries = fs.readdirSync(typeDir);
|
|
527
|
+
agentList = entries.filter((e) => e.endsWith(".md") && e !== "README.md").map((e) => e.replace(/\.md$/, ""));
|
|
528
|
+
} else {
|
|
529
|
+
agentList = items;
|
|
530
|
+
}
|
|
531
|
+
for (const agent of agentList) {
|
|
532
|
+
try {
|
|
533
|
+
const srcPath = join2(typeDir, agent + ".md");
|
|
534
|
+
if (!fs.existsSync(srcPath)) {
|
|
535
|
+
skipped.push(agent);
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
const destPath = join2(destTypeDir, agent + ".md");
|
|
539
|
+
if (mergeMode && fs.existsSync(destPath)) {
|
|
540
|
+
skipped.push(agent);
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
const mdContent = fs.readFileSync(srcPath, "utf-8");
|
|
544
|
+
const convertedContent = convertAgentForGemini(mdContent);
|
|
545
|
+
await fs.writeFile(destPath, convertedContent, "utf-8");
|
|
546
|
+
copied.push(agent);
|
|
547
|
+
} catch (err) {
|
|
548
|
+
errors.push({ item: agent, error: err.message });
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
return { copied, skipped, errors };
|
|
552
|
+
}
|
|
553
|
+
async function copySkillsForGemini(items, sourceDir, destDir, mergeMode = false) {
|
|
554
|
+
const typeDir = join2(sourceDir, "skills");
|
|
555
|
+
const destTypeDir = join2(destDir, "skills");
|
|
556
|
+
if (!fs.existsSync(typeDir)) {
|
|
557
|
+
return { copied: [], skipped: [], errors: [] };
|
|
558
|
+
}
|
|
559
|
+
await fs.ensureDir(destTypeDir);
|
|
560
|
+
const copied = [];
|
|
561
|
+
const skipped = [];
|
|
562
|
+
const errors = [];
|
|
563
|
+
let skillList;
|
|
564
|
+
if (items === "all") {
|
|
565
|
+
const entries = fs.readdirSync(typeDir);
|
|
566
|
+
skillList = entries.filter((e) => {
|
|
567
|
+
const fullPath = join2(typeDir, e);
|
|
568
|
+
return fs.statSync(fullPath).isDirectory() && fs.existsSync(join2(fullPath, "SKILL.md"));
|
|
569
|
+
});
|
|
570
|
+
} else {
|
|
571
|
+
skillList = items;
|
|
572
|
+
}
|
|
573
|
+
for (const skill of skillList) {
|
|
574
|
+
try {
|
|
575
|
+
const srcPath = join2(typeDir, skill);
|
|
576
|
+
if (!fs.existsSync(srcPath) || !fs.statSync(srcPath).isDirectory()) {
|
|
577
|
+
skipped.push(skill);
|
|
578
|
+
continue;
|
|
579
|
+
}
|
|
580
|
+
const skillMdPath = join2(srcPath, "SKILL.md");
|
|
581
|
+
if (!fs.existsSync(skillMdPath)) {
|
|
582
|
+
skipped.push(skill);
|
|
583
|
+
continue;
|
|
584
|
+
}
|
|
585
|
+
const destPath = join2(destTypeDir, skill);
|
|
586
|
+
if (mergeMode && fs.existsSync(destPath)) {
|
|
587
|
+
skipped.push(skill);
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
590
|
+
await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
591
|
+
copied.push(skill);
|
|
592
|
+
} catch (err) {
|
|
593
|
+
errors.push({ skill, error: err.message });
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return { copied, skipped, errors };
|
|
597
|
+
}
|
|
598
|
+
async function copyGeminiBaseFiles(destDir, mergeMode = false) {
|
|
599
|
+
const geminiTemplates = join2(CLI_ROOT, "templates", "gemini");
|
|
600
|
+
const copied = [];
|
|
601
|
+
const settingsPath = join2(geminiTemplates, "settings.json");
|
|
602
|
+
const destSettingsPath = join2(destDir, "settings.json");
|
|
603
|
+
if (fs.existsSync(settingsPath)) {
|
|
604
|
+
if (mergeMode && fs.existsSync(destSettingsPath)) {
|
|
605
|
+
return copied;
|
|
606
|
+
}
|
|
607
|
+
await fs.copy(settingsPath, destSettingsPath, { overwrite: !mergeMode });
|
|
608
|
+
copied.push("settings.json");
|
|
609
|
+
}
|
|
610
|
+
return copied;
|
|
611
|
+
}
|
|
381
612
|
var init_copy = __esm({
|
|
382
613
|
"src/utils/copy.ts"() {
|
|
383
614
|
"use strict";
|
|
615
|
+
init_paths();
|
|
384
616
|
}
|
|
385
617
|
});
|
|
386
618
|
|
|
@@ -446,9 +678,19 @@ async function saveState(projectDir, state) {
|
|
|
446
678
|
await fs3.writeJson(statePath, state, { spaces: 2 });
|
|
447
679
|
}
|
|
448
680
|
async function createInitialState(projectDir, options) {
|
|
449
|
-
const { kit, source, target, installed } = options;
|
|
450
|
-
const
|
|
451
|
-
const
|
|
681
|
+
const { kit, source, target, targets, installed } = options;
|
|
682
|
+
const allHashes = {};
|
|
683
|
+
const targetList = targets || [target.replace(".", "")];
|
|
684
|
+
for (const t of targetList) {
|
|
685
|
+
const targetDirName = t.startsWith(".") ? t : `.${t}`;
|
|
686
|
+
const targetDir = join4(projectDir, targetDirName);
|
|
687
|
+
if (fs3.existsSync(targetDir)) {
|
|
688
|
+
const hashes = await hashDirectory(targetDir);
|
|
689
|
+
for (const [path, hash] of Object.entries(hashes)) {
|
|
690
|
+
allHashes[`${targetDirName}/${path}`] = hash;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
452
694
|
const state = {
|
|
453
695
|
version: "1.0.0",
|
|
454
696
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -456,8 +698,9 @@ async function createInitialState(projectDir, options) {
|
|
|
456
698
|
kit,
|
|
457
699
|
source,
|
|
458
700
|
target,
|
|
701
|
+
targets,
|
|
459
702
|
installed,
|
|
460
|
-
originalHashes:
|
|
703
|
+
originalHashes: allHashes
|
|
461
704
|
};
|
|
462
705
|
await saveState(projectDir, state);
|
|
463
706
|
return state;
|
|
@@ -539,6 +782,19 @@ async function promptKit() {
|
|
|
539
782
|
if (p.isCancel(kit)) process.exit(0);
|
|
540
783
|
return kit;
|
|
541
784
|
}
|
|
785
|
+
async function promptCliTargets() {
|
|
786
|
+
const targets = await p.multiselect({
|
|
787
|
+
message: "Select AI CLI targets:",
|
|
788
|
+
options: [
|
|
789
|
+
{ value: "claude", label: "Claude Code", hint: ".claude/ - Markdown commands" },
|
|
790
|
+
{ value: "gemini", label: "Gemini CLI", hint: ".gemini/ - TOML commands" }
|
|
791
|
+
],
|
|
792
|
+
initialValues: ["claude"],
|
|
793
|
+
required: true
|
|
794
|
+
});
|
|
795
|
+
if (p.isCancel(targets)) process.exit(0);
|
|
796
|
+
return targets;
|
|
797
|
+
}
|
|
542
798
|
async function promptAgents(sourceDir) {
|
|
543
799
|
const available = listAvailable("agents", sourceDir);
|
|
544
800
|
if (available.length === 0) return [];
|
|
@@ -672,31 +928,47 @@ async function initCommand(projectName, options) {
|
|
|
672
928
|
} else {
|
|
673
929
|
projectDir = resolve2(process.cwd(), projectName);
|
|
674
930
|
}
|
|
675
|
-
let
|
|
676
|
-
if (
|
|
677
|
-
|
|
678
|
-
|
|
931
|
+
let cliTargets;
|
|
932
|
+
if (options.target) {
|
|
933
|
+
const targetsFromFlag = options.target.split(",").map((t) => t.trim());
|
|
934
|
+
cliTargets = targetsFromFlag.filter((t) => t === "claude" || t === "gemini");
|
|
935
|
+
if (cliTargets.length === 0) {
|
|
936
|
+
console.log(pc2.yellow(`Unknown target "${options.target}", using "claude"`));
|
|
937
|
+
cliTargets = ["claude"];
|
|
938
|
+
}
|
|
939
|
+
} else if (!process.stdin.isTTY || options.yes) {
|
|
940
|
+
cliTargets = ["claude"];
|
|
941
|
+
} else {
|
|
942
|
+
cliTargets = await promptCliTargets();
|
|
679
943
|
}
|
|
680
|
-
const targetDir = getTargetDir(projectDir, target);
|
|
681
944
|
let existingAction = null;
|
|
682
|
-
|
|
683
|
-
|
|
945
|
+
const existingTargets = [];
|
|
946
|
+
for (const target of cliTargets) {
|
|
947
|
+
const targetDir = getTargetDir(projectDir, target);
|
|
948
|
+
if (options.fresh && fs4.existsSync(targetDir)) {
|
|
949
|
+
await fs4.remove(targetDir);
|
|
950
|
+
existingTargets.push(TARGETS[target]);
|
|
951
|
+
} else if (fs4.existsSync(targetDir) && !options.force) {
|
|
952
|
+
existingTargets.push(TARGETS[target]);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
if (options.fresh && existingTargets.length > 0) {
|
|
684
956
|
const akDir = join5(projectDir, ".ak");
|
|
685
957
|
if (fs4.existsSync(akDir)) {
|
|
686
958
|
await fs4.remove(akDir);
|
|
687
959
|
}
|
|
688
|
-
console.log(pc2.cyan(
|
|
960
|
+
console.log(pc2.cyan(`Fresh install: removed existing files (${existingTargets.join(", ")})`));
|
|
689
961
|
existingAction = null;
|
|
690
|
-
} else if (
|
|
962
|
+
} else if (existingTargets.length > 0 && !options.force) {
|
|
691
963
|
if (!process.stdin.isTTY || options.yes) {
|
|
692
964
|
if (options.yes) {
|
|
693
965
|
existingAction = "override";
|
|
694
966
|
} else {
|
|
695
|
-
console.log(pc2.yellow(`${
|
|
967
|
+
console.log(pc2.yellow(`${existingTargets.join(", ")} already exists. Use --force to override.`));
|
|
696
968
|
return;
|
|
697
969
|
}
|
|
698
970
|
} else {
|
|
699
|
-
existingAction = await promptExistingTarget(
|
|
971
|
+
existingAction = await promptExistingTarget(existingTargets.join(", "));
|
|
700
972
|
if (existingAction === "skip") {
|
|
701
973
|
console.log(pc2.yellow("Skipped. No changes made."));
|
|
702
974
|
return;
|
|
@@ -763,7 +1035,7 @@ async function initCommand(projectName, options) {
|
|
|
763
1035
|
}
|
|
764
1036
|
console.log(pc2.cyan("\nWill create:"));
|
|
765
1037
|
console.log(pc2.white(` Project: ${projectName}/`));
|
|
766
|
-
console.log(pc2.white(`
|
|
1038
|
+
console.log(pc2.white(` Targets: ${cliTargets.map((t) => TARGETS[t]).join(", ")}/`));
|
|
767
1039
|
console.log(pc2.white(` Kit: ${kitName}`));
|
|
768
1040
|
if (Array.isArray(toInstall.agents)) {
|
|
769
1041
|
console.log(pc2.gray(` Agents: ${toInstall.agents.length}`));
|
|
@@ -784,54 +1056,78 @@ async function initCommand(projectName, options) {
|
|
|
784
1056
|
const spinner = ora("Creating project...").start();
|
|
785
1057
|
try {
|
|
786
1058
|
await fs4.ensureDir(projectDir);
|
|
787
|
-
const
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
1059
|
+
for (const target of cliTargets) {
|
|
1060
|
+
const targetDir = getTargetDir(projectDir, target);
|
|
1061
|
+
await fs4.ensureDir(targetDir);
|
|
1062
|
+
const targetLabel = target === "gemini" ? "Gemini" : "Claude";
|
|
1063
|
+
spinner.text = mergeMode ? `Merging agents (${targetLabel})...` : `Copying agents (${targetLabel})...`;
|
|
1064
|
+
if (target === "gemini") {
|
|
1065
|
+
await copyAgentsForGemini(toInstall.agents, source.claudeDir, targetDir, mergeMode);
|
|
1066
|
+
} else {
|
|
1067
|
+
if (toInstall.agents === "all") {
|
|
1068
|
+
await copyAllOfType("agents", source.claudeDir, targetDir, mergeMode);
|
|
1069
|
+
} else if (toInstall.agents.length > 0) {
|
|
1070
|
+
await copyItems(toInstall.agents, "agents", source.claudeDir, targetDir, mergeMode);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
spinner.text = mergeMode ? `Merging skills (${targetLabel})...` : `Copying skills (${targetLabel})...`;
|
|
1074
|
+
if (target === "gemini") {
|
|
1075
|
+
await copySkillsForGemini(toInstall.skills, source.claudeDir, targetDir, mergeMode);
|
|
1076
|
+
} else {
|
|
1077
|
+
if (toInstall.skills === "all") {
|
|
1078
|
+
await copyAllOfType("skills", source.claudeDir, targetDir, mergeMode);
|
|
1079
|
+
} else if (toInstall.skills.length > 0) {
|
|
1080
|
+
await copyItems(toInstall.skills, "skills", source.claudeDir, targetDir, mergeMode);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
spinner.text = mergeMode ? `Merging commands (${targetLabel})...` : `Copying commands (${targetLabel})...`;
|
|
1084
|
+
if (target === "gemini") {
|
|
1085
|
+
await copyCommandsForGemini(toInstall.commands, source.claudeDir, targetDir, mergeMode);
|
|
1086
|
+
} else {
|
|
1087
|
+
if (toInstall.commands === "all") {
|
|
1088
|
+
await copyAllOfType("commands", source.claudeDir, targetDir, mergeMode);
|
|
1089
|
+
} else if (toInstall.commands.length > 0) {
|
|
1090
|
+
await copyItems(toInstall.commands, "commands", source.claudeDir, targetDir, mergeMode);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
if (target === "claude") {
|
|
1094
|
+
spinner.text = mergeMode ? `Merging workflows (${targetLabel})...` : `Copying workflows (${targetLabel})...`;
|
|
1095
|
+
if (toInstall.workflows === "all") {
|
|
1096
|
+
await copyAllOfType("workflows", source.claudeDir, targetDir, mergeMode);
|
|
1097
|
+
} else if (toInstall.workflows && toInstall.workflows.length > 0) {
|
|
1098
|
+
await copyItems(toInstall.workflows, "workflows", source.claudeDir, targetDir, mergeMode);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
if (target === "claude" && toInstall.includeRouter) {
|
|
1102
|
+
spinner.text = mergeMode ? `Merging router (${targetLabel})...` : `Copying router (${targetLabel})...`;
|
|
1103
|
+
await copyRouter(source.claudeDir, targetDir, mergeMode);
|
|
1104
|
+
}
|
|
1105
|
+
if (target === "claude" && toInstall.includeHooks) {
|
|
1106
|
+
spinner.text = mergeMode ? `Merging hooks (${targetLabel})...` : `Copying hooks (${targetLabel})...`;
|
|
1107
|
+
await copyHooks(source.claudeDir, targetDir, mergeMode);
|
|
1108
|
+
}
|
|
1109
|
+
if (target === "claude") {
|
|
1110
|
+
spinner.text = mergeMode ? `Merging extras (${targetLabel})...` : `Copying extras (${targetLabel})...`;
|
|
1111
|
+
await copyDirectory("memory", source.claudeDir, targetDir, mergeMode);
|
|
1112
|
+
await copyDirectory("output-styles", source.claudeDir, targetDir, mergeMode);
|
|
1113
|
+
await copyDirectory("scripts", source.claudeDir, targetDir, mergeMode);
|
|
1114
|
+
spinner.text = mergeMode ? `Merging base files (${targetLabel})...` : `Copying base files (${targetLabel})...`;
|
|
1115
|
+
await copyBaseFiles(source.claudeDir, targetDir, mergeMode);
|
|
1116
|
+
} else if (target === "gemini") {
|
|
1117
|
+
spinner.text = mergeMode ? `Merging settings (${targetLabel})...` : `Copying settings (${targetLabel})...`;
|
|
1118
|
+
await copyGeminiBaseFiles(targetDir, mergeMode);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
if (source.agentsMd && cliTargets.includes("claude")) {
|
|
828
1122
|
await copyAgentsMd(source.agentsMd, projectDir, mergeMode);
|
|
829
1123
|
}
|
|
830
1124
|
spinner.text = "Saving state...";
|
|
831
1125
|
await createInitialState(projectDir, {
|
|
832
1126
|
kit: kitName,
|
|
833
1127
|
source: source.path,
|
|
834
|
-
|
|
1128
|
+
targets: cliTargets,
|
|
1129
|
+
target: TARGETS[cliTargets[0]],
|
|
1130
|
+
// Keep backward compat
|
|
835
1131
|
installed: {
|
|
836
1132
|
agents: toInstall.agents === "all" ? ["all"] : toInstall.agents,
|
|
837
1133
|
skills: toInstall.skills === "all" ? ["all"] : toInstall.skills,
|
|
@@ -847,10 +1143,9 @@ async function initCommand(projectName, options) {
|
|
|
847
1143
|
if (!isCurrentDir) {
|
|
848
1144
|
console.log(pc2.cyan("Next steps:"));
|
|
849
1145
|
console.log(pc2.white(` cd ${projectName}`));
|
|
850
|
-
console.log(pc2.white(" # Start coding with Claude Code"));
|
|
851
|
-
} else {
|
|
852
|
-
console.log(pc2.cyan("Ready to code with Claude Code!"));
|
|
853
1146
|
}
|
|
1147
|
+
const targetNames = cliTargets.map((t) => t === "gemini" ? "Gemini CLI" : "Claude Code").join(" & ");
|
|
1148
|
+
console.log(pc2.cyan(`Ready to code with ${targetNames}!`));
|
|
854
1149
|
console.log("");
|
|
855
1150
|
console.log(pc2.gray("Useful commands:"));
|
|
856
1151
|
console.log(pc2.gray(" ak status - Check file status"));
|
|
@@ -2123,8 +2418,9 @@ async function updateCliCommand(options) {
|
|
|
2123
2418
|
console.log(`
|
|
2124
2419
|
Current: ${pc11.gray(current)}`);
|
|
2125
2420
|
console.log(` Latest: ${pc11.green(latest)}`);
|
|
2126
|
-
if (current === latest && !options.version) {
|
|
2421
|
+
if (current === latest && !options.version && !options.force) {
|
|
2127
2422
|
console.log(pc11.green("\nAlready up to date!"));
|
|
2423
|
+
console.log(pc11.gray("Use --force to reinstall anyway."));
|
|
2128
2424
|
return;
|
|
2129
2425
|
}
|
|
2130
2426
|
if (options.check) {
|
|
@@ -2369,12 +2665,12 @@ var init_skills = __esm({
|
|
|
2369
2665
|
import cac from "cac";
|
|
2370
2666
|
import { readFileSync as readFileSync3 } from "fs";
|
|
2371
2667
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2372
|
-
import { dirname as
|
|
2668
|
+
import { dirname as dirname3, join as join13 } from "path";
|
|
2373
2669
|
import pc13 from "picocolors";
|
|
2374
2670
|
|
|
2375
2671
|
// src/cli/command-registry.ts
|
|
2376
2672
|
function registerCommands(cli2) {
|
|
2377
|
-
cli2.command("init [project-name]", "Initialize a new project with an agent kit").option("-k, --kit <type>", "Kit type (engineer, researcher, designer, minimal, full, custom)").option("-t, --target <target>", "Target
|
|
2673
|
+
cli2.command("init [project-name]", "Initialize a new project with an agent kit").option("-k, --kit <type>", "Kit type (engineer, researcher, designer, minimal, full, custom)").option("-t, --target <target>", "Target CLI (claude, gemini or claude,gemini for both)").option("-s, --source <path>", "Custom source path for templates").option("-f, --force", "Overwrite existing directory").option("-g, --global", "Install to global ~/.claude/ directory").option("--fresh", "Remove existing installation before re-init").option("-y, --yes", "Skip prompts, use defaults").option("--exclude <patterns>", "Exclude components (comma-separated)").option("--only <patterns>", "Include only matching components (comma-separated)").action(async (projectName, options) => {
|
|
2378
2674
|
const { initCommand: initCommand2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
2379
2675
|
await initCommand2(projectName, options);
|
|
2380
2676
|
});
|
|
@@ -2414,7 +2710,7 @@ function registerCommands(cli2) {
|
|
|
2414
2710
|
const { versionsCommand: versionsCommand2 } = await Promise.resolve().then(() => (init_versions(), versions_exports));
|
|
2415
2711
|
await versionsCommand2(options);
|
|
2416
2712
|
});
|
|
2417
|
-
cli2.command("update-cli", "Update the CLI itself to latest version").option("--check", "Check for updates without installing").option("--version <version>", "Update to specific version").action(async (options) => {
|
|
2713
|
+
cli2.command("update-cli", "Update the CLI itself to latest version").option("--check", "Check for updates without installing").option("--version <version>", "Update to specific version").option("-f, --force", "Force reinstall even if already up to date").action(async (options) => {
|
|
2418
2714
|
const { updateCliCommand: updateCliCommand2 } = await Promise.resolve().then(() => (init_update_cli(), update_cli_exports));
|
|
2419
2715
|
await updateCliCommand2(options);
|
|
2420
2716
|
});
|
|
@@ -2453,7 +2749,7 @@ function isNewerVersion(current, latest) {
|
|
|
2453
2749
|
|
|
2454
2750
|
// src/index.ts
|
|
2455
2751
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
2456
|
-
var __dirname2 =
|
|
2752
|
+
var __dirname2 = dirname3(__filename2);
|
|
2457
2753
|
function getVersion() {
|
|
2458
2754
|
try {
|
|
2459
2755
|
const pkg = JSON.parse(readFileSync3(join13(__dirname2, "..", "package.json"), "utf-8"));
|