apero-kit-cli 2.0.0 → 2.2.0
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 +401 -63
- 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);
|
|
@@ -327,7 +359,7 @@ async function copyHooks(sourceDir, destDir, mergeMode = false) {
|
|
|
327
359
|
}
|
|
328
360
|
}
|
|
329
361
|
async function copyBaseFiles(sourceDir, destDir, mergeMode = false) {
|
|
330
|
-
const baseFiles = ["README.md", "settings.json", ".env.example"];
|
|
362
|
+
const baseFiles = ["README.md", "settings.json", ".env.example", "statusline.cjs", "statusline.ps1", "statusline.sh"];
|
|
331
363
|
const copied = [];
|
|
332
364
|
for (const file of baseFiles) {
|
|
333
365
|
const srcPath = join2(sourceDir, file);
|
|
@@ -342,6 +374,18 @@ async function copyBaseFiles(sourceDir, destDir, mergeMode = false) {
|
|
|
342
374
|
}
|
|
343
375
|
return copied;
|
|
344
376
|
}
|
|
377
|
+
async function copyDirectory(dirName, sourceDir, destDir, mergeMode = false) {
|
|
378
|
+
const srcPath = join2(sourceDir, dirName);
|
|
379
|
+
if (!fs.existsSync(srcPath)) {
|
|
380
|
+
return { success: false, error: `${dirName} directory not found` };
|
|
381
|
+
}
|
|
382
|
+
try {
|
|
383
|
+
await fs.copy(srcPath, join2(destDir, dirName), { overwrite: !mergeMode });
|
|
384
|
+
return { success: true };
|
|
385
|
+
} catch (err) {
|
|
386
|
+
return { success: false, error: err.message };
|
|
387
|
+
}
|
|
388
|
+
}
|
|
345
389
|
async function copyAgentsMd(agentsMdPath, projectDir, mergeMode = false) {
|
|
346
390
|
if (!agentsMdPath || !fs.existsSync(agentsMdPath)) {
|
|
347
391
|
return false;
|
|
@@ -366,9 +410,209 @@ function listAvailable(type, sourceDir) {
|
|
|
366
410
|
return { name, isDir, path: itemPath };
|
|
367
411
|
});
|
|
368
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
|
+
}
|
|
369
612
|
var init_copy = __esm({
|
|
370
613
|
"src/utils/copy.ts"() {
|
|
371
614
|
"use strict";
|
|
615
|
+
init_paths();
|
|
372
616
|
}
|
|
373
617
|
});
|
|
374
618
|
|
|
@@ -434,9 +678,19 @@ async function saveState(projectDir, state) {
|
|
|
434
678
|
await fs3.writeJson(statePath, state, { spaces: 2 });
|
|
435
679
|
}
|
|
436
680
|
async function createInitialState(projectDir, options) {
|
|
437
|
-
const { kit, source, target, installed } = options;
|
|
438
|
-
const
|
|
439
|
-
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
|
+
}
|
|
440
694
|
const state = {
|
|
441
695
|
version: "1.0.0",
|
|
442
696
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -444,8 +698,9 @@ async function createInitialState(projectDir, options) {
|
|
|
444
698
|
kit,
|
|
445
699
|
source,
|
|
446
700
|
target,
|
|
701
|
+
targets,
|
|
447
702
|
installed,
|
|
448
|
-
originalHashes:
|
|
703
|
+
originalHashes: allHashes
|
|
449
704
|
};
|
|
450
705
|
await saveState(projectDir, state);
|
|
451
706
|
return state;
|
|
@@ -527,6 +782,19 @@ async function promptKit() {
|
|
|
527
782
|
if (p.isCancel(kit)) process.exit(0);
|
|
528
783
|
return kit;
|
|
529
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
|
+
}
|
|
530
798
|
async function promptAgents(sourceDir) {
|
|
531
799
|
const available = listAvailable("agents", sourceDir);
|
|
532
800
|
if (available.length === 0) return [];
|
|
@@ -660,31 +928,47 @@ async function initCommand(projectName, options) {
|
|
|
660
928
|
} else {
|
|
661
929
|
projectDir = resolve2(process.cwd(), projectName);
|
|
662
930
|
}
|
|
663
|
-
let
|
|
664
|
-
if (
|
|
665
|
-
|
|
666
|
-
|
|
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();
|
|
667
943
|
}
|
|
668
|
-
const targetDir = getTargetDir(projectDir, target);
|
|
669
944
|
let existingAction = null;
|
|
670
|
-
|
|
671
|
-
|
|
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) {
|
|
672
956
|
const akDir = join5(projectDir, ".ak");
|
|
673
957
|
if (fs4.existsSync(akDir)) {
|
|
674
958
|
await fs4.remove(akDir);
|
|
675
959
|
}
|
|
676
|
-
console.log(pc2.cyan(
|
|
960
|
+
console.log(pc2.cyan(`Fresh install: removed existing files (${existingTargets.join(", ")})`));
|
|
677
961
|
existingAction = null;
|
|
678
|
-
} else if (
|
|
962
|
+
} else if (existingTargets.length > 0 && !options.force) {
|
|
679
963
|
if (!process.stdin.isTTY || options.yes) {
|
|
680
964
|
if (options.yes) {
|
|
681
965
|
existingAction = "override";
|
|
682
966
|
} else {
|
|
683
|
-
console.log(pc2.yellow(`${
|
|
967
|
+
console.log(pc2.yellow(`${existingTargets.join(", ")} already exists. Use --force to override.`));
|
|
684
968
|
return;
|
|
685
969
|
}
|
|
686
970
|
} else {
|
|
687
|
-
existingAction = await promptExistingTarget(
|
|
971
|
+
existingAction = await promptExistingTarget(existingTargets.join(", "));
|
|
688
972
|
if (existingAction === "skip") {
|
|
689
973
|
console.log(pc2.yellow("Skipped. No changes made."));
|
|
690
974
|
return;
|
|
@@ -751,7 +1035,7 @@ async function initCommand(projectName, options) {
|
|
|
751
1035
|
}
|
|
752
1036
|
console.log(pc2.cyan("\nWill create:"));
|
|
753
1037
|
console.log(pc2.white(` Project: ${projectName}/`));
|
|
754
|
-
console.log(pc2.white(`
|
|
1038
|
+
console.log(pc2.white(` Targets: ${cliTargets.map((t) => TARGETS[t]).join(", ")}/`));
|
|
755
1039
|
console.log(pc2.white(` Kit: ${kitName}`));
|
|
756
1040
|
if (Array.isArray(toInstall.agents)) {
|
|
757
1041
|
console.log(pc2.gray(` Agents: ${toInstall.agents.length}`));
|
|
@@ -772,50 +1056,78 @@ async function initCommand(projectName, options) {
|
|
|
772
1056
|
const spinner = ora("Creating project...").start();
|
|
773
1057
|
try {
|
|
774
1058
|
await fs4.ensureDir(projectDir);
|
|
775
|
-
const
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
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")) {
|
|
812
1122
|
await copyAgentsMd(source.agentsMd, projectDir, mergeMode);
|
|
813
1123
|
}
|
|
814
1124
|
spinner.text = "Saving state...";
|
|
815
1125
|
await createInitialState(projectDir, {
|
|
816
1126
|
kit: kitName,
|
|
817
1127
|
source: source.path,
|
|
818
|
-
|
|
1128
|
+
targets: cliTargets,
|
|
1129
|
+
target: TARGETS[cliTargets[0]],
|
|
1130
|
+
// Keep backward compat
|
|
819
1131
|
installed: {
|
|
820
1132
|
agents: toInstall.agents === "all" ? ["all"] : toInstall.agents,
|
|
821
1133
|
skills: toInstall.skills === "all" ? ["all"] : toInstall.skills,
|
|
@@ -831,10 +1143,9 @@ async function initCommand(projectName, options) {
|
|
|
831
1143
|
if (!isCurrentDir) {
|
|
832
1144
|
console.log(pc2.cyan("Next steps:"));
|
|
833
1145
|
console.log(pc2.white(` cd ${projectName}`));
|
|
834
|
-
console.log(pc2.white(" # Start coding with Claude Code"));
|
|
835
|
-
} else {
|
|
836
|
-
console.log(pc2.cyan("Ready to code with Claude Code!"));
|
|
837
1146
|
}
|
|
1147
|
+
const targetNames = cliTargets.map((t) => t === "gemini" ? "Gemini CLI" : "Claude Code").join(" & ");
|
|
1148
|
+
console.log(pc2.cyan(`Ready to code with ${targetNames}!`));
|
|
838
1149
|
console.log("");
|
|
839
1150
|
console.log(pc2.gray("Useful commands:"));
|
|
840
1151
|
console.log(pc2.gray(" ak status - Check file status"));
|
|
@@ -1541,6 +1852,33 @@ async function doctorCommand(options = {}) {
|
|
|
1541
1852
|
}
|
|
1542
1853
|
return {};
|
|
1543
1854
|
}
|
|
1855
|
+
},
|
|
1856
|
+
{
|
|
1857
|
+
name: "subdirs_scripts",
|
|
1858
|
+
label: "scripts/ exists",
|
|
1859
|
+
severity: "warning",
|
|
1860
|
+
check: () => {
|
|
1861
|
+
if (!targetDir) return false;
|
|
1862
|
+
return fs8.existsSync(join8(targetDir.dir, "scripts"));
|
|
1863
|
+
}
|
|
1864
|
+
},
|
|
1865
|
+
{
|
|
1866
|
+
name: "subdirs_hooks",
|
|
1867
|
+
label: "hooks/ exists",
|
|
1868
|
+
severity: "warning",
|
|
1869
|
+
check: () => {
|
|
1870
|
+
if (!targetDir) return false;
|
|
1871
|
+
return fs8.existsSync(join8(targetDir.dir, "hooks"));
|
|
1872
|
+
}
|
|
1873
|
+
},
|
|
1874
|
+
{
|
|
1875
|
+
name: "statusline",
|
|
1876
|
+
label: "statusline files exist",
|
|
1877
|
+
severity: "warning",
|
|
1878
|
+
check: () => {
|
|
1879
|
+
if (!targetDir) return false;
|
|
1880
|
+
return fs8.existsSync(join8(targetDir.dir, "statusline.cjs")) || fs8.existsSync(join8(targetDir.dir, "statusline.sh"));
|
|
1881
|
+
}
|
|
1544
1882
|
}
|
|
1545
1883
|
];
|
|
1546
1884
|
const results = await runChecks(checks, options);
|
|
@@ -2326,12 +2664,12 @@ var init_skills = __esm({
|
|
|
2326
2664
|
import cac from "cac";
|
|
2327
2665
|
import { readFileSync as readFileSync3 } from "fs";
|
|
2328
2666
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2329
|
-
import { dirname as
|
|
2667
|
+
import { dirname as dirname3, join as join13 } from "path";
|
|
2330
2668
|
import pc13 from "picocolors";
|
|
2331
2669
|
|
|
2332
2670
|
// src/cli/command-registry.ts
|
|
2333
2671
|
function registerCommands(cli2) {
|
|
2334
|
-
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
|
|
2672
|
+
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) => {
|
|
2335
2673
|
const { initCommand: initCommand2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
2336
2674
|
await initCommand2(projectName, options);
|
|
2337
2675
|
});
|
|
@@ -2410,7 +2748,7 @@ function isNewerVersion(current, latest) {
|
|
|
2410
2748
|
|
|
2411
2749
|
// src/index.ts
|
|
2412
2750
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
2413
|
-
var __dirname2 =
|
|
2751
|
+
var __dirname2 = dirname3(__filename2);
|
|
2414
2752
|
function getVersion() {
|
|
2415
2753
|
try {
|
|
2416
2754
|
const pkg = JSON.parse(readFileSync3(join13(__dirname2, "..", "package.json"), "utf-8"));
|