apero-kit-cli 2.2.5 → 2.3.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 +262 -14
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
- package/templates/discord/README.md +150 -0
- package/templates/discord/config.json5 +87 -0
package/dist/index.js
CHANGED
|
@@ -244,6 +244,7 @@ var init_paths = __esm({
|
|
|
244
244
|
TARGETS = {
|
|
245
245
|
claude: ".claude",
|
|
246
246
|
gemini: ".gemini",
|
|
247
|
+
discord: ".discord",
|
|
247
248
|
opencode: ".opencode",
|
|
248
249
|
generic: ".agent"
|
|
249
250
|
};
|
|
@@ -610,6 +611,218 @@ async function copyGeminiBaseFiles(destDir, mergeMode = false) {
|
|
|
610
611
|
}
|
|
611
612
|
return copied;
|
|
612
613
|
}
|
|
614
|
+
function convertCommandForDiscord(mdContent, commandName) {
|
|
615
|
+
const { description, body } = parseFrontmatter(mdContent);
|
|
616
|
+
const prompt = body.replace(/\$ARGUMENTS/g, "{{args}}");
|
|
617
|
+
return {
|
|
618
|
+
name: commandName,
|
|
619
|
+
description: description || `Execute ${commandName} command`,
|
|
620
|
+
prompt
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
function convertAgentForDiscord(mdContent) {
|
|
624
|
+
const frontmatterMatch = mdContent.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
625
|
+
if (!frontmatterMatch) return mdContent;
|
|
626
|
+
let frontmatter = frontmatterMatch[1];
|
|
627
|
+
const body = frontmatterMatch[2];
|
|
628
|
+
const modelMap = {
|
|
629
|
+
"opus": "claude-3-opus",
|
|
630
|
+
"sonnet": "claude-3-sonnet",
|
|
631
|
+
"haiku": "claude-3-haiku",
|
|
632
|
+
"inherit": ""
|
|
633
|
+
// Remove inherit
|
|
634
|
+
};
|
|
635
|
+
for (const [claudeModel, discordModel] of Object.entries(modelMap)) {
|
|
636
|
+
const regex = new RegExp(`^model:\\s*${claudeModel}\\s*$`, "m");
|
|
637
|
+
if (discordModel) {
|
|
638
|
+
frontmatter = frontmatter.replace(regex, `model: ${discordModel}`);
|
|
639
|
+
} else {
|
|
640
|
+
frontmatter = frontmatter.replace(regex, "");
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
frontmatter = frontmatter.replace(/^tools:\s*.+$/m, "");
|
|
644
|
+
if (!frontmatter.includes("kind:")) {
|
|
645
|
+
frontmatter = frontmatter.trim() + "\nkind: local";
|
|
646
|
+
}
|
|
647
|
+
return `---
|
|
648
|
+
${frontmatter.trim()}
|
|
649
|
+
---
|
|
650
|
+
${body}`;
|
|
651
|
+
}
|
|
652
|
+
async function copyAgentsForDiscord(items, sourceDir, destDir, mergeMode = false) {
|
|
653
|
+
const typeDir = join2(sourceDir, "agents");
|
|
654
|
+
const destTypeDir = join2(destDir, "agents");
|
|
655
|
+
if (!fs.existsSync(typeDir)) {
|
|
656
|
+
return { copied: [], skipped: [], errors: [] };
|
|
657
|
+
}
|
|
658
|
+
await fs.ensureDir(destTypeDir);
|
|
659
|
+
const copied = [];
|
|
660
|
+
const skipped = [];
|
|
661
|
+
const errors = [];
|
|
662
|
+
let agentList;
|
|
663
|
+
if (items === "all") {
|
|
664
|
+
const entries = fs.readdirSync(typeDir);
|
|
665
|
+
agentList = entries.filter((e) => e.endsWith(".md") && e !== "README.md").map((e) => e.replace(/\.md$/, ""));
|
|
666
|
+
} else {
|
|
667
|
+
agentList = items;
|
|
668
|
+
}
|
|
669
|
+
for (const agent of agentList) {
|
|
670
|
+
try {
|
|
671
|
+
const srcPath = join2(typeDir, agent + ".md");
|
|
672
|
+
if (!fs.existsSync(srcPath)) {
|
|
673
|
+
skipped.push(agent);
|
|
674
|
+
continue;
|
|
675
|
+
}
|
|
676
|
+
const destPath = join2(destTypeDir, agent + ".md");
|
|
677
|
+
if (mergeMode && fs.existsSync(destPath)) {
|
|
678
|
+
skipped.push(agent);
|
|
679
|
+
continue;
|
|
680
|
+
}
|
|
681
|
+
const mdContent = fs.readFileSync(srcPath, "utf-8");
|
|
682
|
+
const convertedContent = convertAgentForDiscord(mdContent);
|
|
683
|
+
await fs.writeFile(destPath, convertedContent, "utf-8");
|
|
684
|
+
copied.push(agent);
|
|
685
|
+
} catch (err) {
|
|
686
|
+
errors.push({ item: agent, error: err.message });
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return { copied, skipped, errors };
|
|
690
|
+
}
|
|
691
|
+
async function copyCommandsForDiscord(items, sourceDir, destDir, mergeMode = false) {
|
|
692
|
+
const typeDir = join2(sourceDir, "commands");
|
|
693
|
+
const destTypeDir = join2(destDir, "commands");
|
|
694
|
+
if (!fs.existsSync(typeDir)) {
|
|
695
|
+
return { copied: [], skipped: [], errors: [] };
|
|
696
|
+
}
|
|
697
|
+
await fs.ensureDir(destTypeDir);
|
|
698
|
+
const copied = [];
|
|
699
|
+
const skipped = [];
|
|
700
|
+
const errors = [];
|
|
701
|
+
const commandsConfig = {};
|
|
702
|
+
let itemList;
|
|
703
|
+
if (items === "all") {
|
|
704
|
+
const entries = fs.readdirSync(typeDir);
|
|
705
|
+
itemList = entries.map((e) => e.replace(/\.md$/, ""));
|
|
706
|
+
itemList = [...new Set(itemList)];
|
|
707
|
+
} else {
|
|
708
|
+
itemList = items;
|
|
709
|
+
}
|
|
710
|
+
for (const item of itemList) {
|
|
711
|
+
try {
|
|
712
|
+
const srcPathMd = join2(typeDir, item + ".md");
|
|
713
|
+
const srcPathDir = join2(typeDir, item);
|
|
714
|
+
let copiedSomething = false;
|
|
715
|
+
if (fs.existsSync(srcPathMd) && fs.statSync(srcPathMd).isFile()) {
|
|
716
|
+
const destPath = join2(destTypeDir, item + ".md");
|
|
717
|
+
if (!(mergeMode && fs.existsSync(destPath))) {
|
|
718
|
+
await fs.ensureDir(dirname2(destPath));
|
|
719
|
+
const mdContent = fs.readFileSync(srcPathMd, "utf-8");
|
|
720
|
+
await fs.copy(srcPathMd, destPath, { overwrite: !mergeMode });
|
|
721
|
+
const cmd = convertCommandForDiscord(mdContent, item);
|
|
722
|
+
commandsConfig[item] = {
|
|
723
|
+
description: cmd.description,
|
|
724
|
+
prompt: cmd.prompt
|
|
725
|
+
};
|
|
726
|
+
copiedSomething = true;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
if (fs.existsSync(srcPathDir) && fs.statSync(srcPathDir).isDirectory()) {
|
|
730
|
+
await copyDirectoryForDiscord(srcPathDir, join2(destTypeDir, item), mergeMode, commandsConfig, item);
|
|
731
|
+
copiedSomething = true;
|
|
732
|
+
}
|
|
733
|
+
if (copiedSomething) {
|
|
734
|
+
copied.push(item);
|
|
735
|
+
} else {
|
|
736
|
+
skipped.push(item);
|
|
737
|
+
}
|
|
738
|
+
} catch (err) {
|
|
739
|
+
errors.push({ item, error: err.message });
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
const configPath = join2(destDir, "commands.json5");
|
|
743
|
+
if (Object.keys(commandsConfig).length > 0 && !(mergeMode && fs.existsSync(configPath))) {
|
|
744
|
+
const json5Content = generateCommandsJson5(commandsConfig);
|
|
745
|
+
await fs.writeFile(configPath, json5Content, "utf-8");
|
|
746
|
+
}
|
|
747
|
+
return { copied, skipped, errors };
|
|
748
|
+
}
|
|
749
|
+
async function copyDirectoryForDiscord(srcDir, destDir, mergeMode, commandsConfig, parentName) {
|
|
750
|
+
await fs.ensureDir(destDir);
|
|
751
|
+
const entries = fs.readdirSync(srcDir);
|
|
752
|
+
for (const entry of entries) {
|
|
753
|
+
const srcPath = join2(srcDir, entry);
|
|
754
|
+
const stat = fs.statSync(srcPath);
|
|
755
|
+
if (stat.isDirectory()) {
|
|
756
|
+
await copyDirectoryForDiscord(
|
|
757
|
+
srcPath,
|
|
758
|
+
join2(destDir, entry),
|
|
759
|
+
mergeMode,
|
|
760
|
+
commandsConfig,
|
|
761
|
+
`${parentName}/${entry}`
|
|
762
|
+
);
|
|
763
|
+
} else if (entry.endsWith(".md")) {
|
|
764
|
+
const destPath = join2(destDir, entry);
|
|
765
|
+
if (mergeMode && fs.existsSync(destPath)) {
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
const mdContent = fs.readFileSync(srcPath, "utf-8");
|
|
769
|
+
await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
770
|
+
const cmdName = `${parentName}/${entry.replace(/\.md$/, "")}`;
|
|
771
|
+
const cmd = convertCommandForDiscord(mdContent, cmdName);
|
|
772
|
+
commandsConfig[cmdName] = {
|
|
773
|
+
description: cmd.description,
|
|
774
|
+
prompt: cmd.prompt
|
|
775
|
+
};
|
|
776
|
+
} else {
|
|
777
|
+
const destPath = join2(destDir, entry);
|
|
778
|
+
if (mergeMode && fs.existsSync(destPath)) {
|
|
779
|
+
continue;
|
|
780
|
+
}
|
|
781
|
+
await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
function generateCommandsJson5(commands) {
|
|
786
|
+
const lines = [
|
|
787
|
+
"// Clawbot Commands Configuration",
|
|
788
|
+
"// Generated by Apero Kit CLI",
|
|
789
|
+
"// These commands can be used as slash commands in Discord",
|
|
790
|
+
"{",
|
|
791
|
+
' "commands": {'
|
|
792
|
+
];
|
|
793
|
+
const cmdEntries = Object.entries(commands);
|
|
794
|
+
cmdEntries.forEach(([name, cmd], index) => {
|
|
795
|
+
const safeName = name.replace(/\//g, ":");
|
|
796
|
+
const isLast = index === cmdEntries.length - 1;
|
|
797
|
+
lines.push(` "${safeName}": {`);
|
|
798
|
+
lines.push(` "description": ${JSON.stringify(cmd.description)},`);
|
|
799
|
+
lines.push(` "prompt": ${JSON.stringify(cmd.prompt)}`);
|
|
800
|
+
lines.push(` }${isLast ? "" : ","}`);
|
|
801
|
+
});
|
|
802
|
+
lines.push(" }");
|
|
803
|
+
lines.push("}");
|
|
804
|
+
return lines.join("\n");
|
|
805
|
+
}
|
|
806
|
+
async function copySkillsForDiscord(items, sourceDir, destDir, mergeMode = false) {
|
|
807
|
+
return copySkillsForGemini(items, sourceDir, destDir, mergeMode);
|
|
808
|
+
}
|
|
809
|
+
async function copyDiscordBaseFiles(destDir, mergeMode = false) {
|
|
810
|
+
const discordTemplates = join2(CLI_ROOT, "templates", "discord");
|
|
811
|
+
const copied = [];
|
|
812
|
+
const filesToCopy = ["config.json5", "README.md"];
|
|
813
|
+
for (const file of filesToCopy) {
|
|
814
|
+
const srcPath = join2(discordTemplates, file);
|
|
815
|
+
const destPath = join2(destDir, file);
|
|
816
|
+
if (fs.existsSync(srcPath)) {
|
|
817
|
+
if (mergeMode && fs.existsSync(destPath)) {
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
820
|
+
await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
821
|
+
copied.push(file);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
return copied;
|
|
825
|
+
}
|
|
613
826
|
var init_copy = __esm({
|
|
614
827
|
"src/utils/copy.ts"() {
|
|
615
828
|
"use strict";
|
|
@@ -784,19 +997,18 @@ async function promptKit() {
|
|
|
784
997
|
return kit;
|
|
785
998
|
}
|
|
786
999
|
async function promptCliTargets() {
|
|
787
|
-
const selection = await p.
|
|
788
|
-
message: "Select AI CLI target:",
|
|
1000
|
+
const selection = await p.multiselect({
|
|
1001
|
+
message: "Select AI CLI target(s):",
|
|
789
1002
|
options: [
|
|
790
|
-
{ value: "claude", label: "Claude Code
|
|
791
|
-
{ value: "gemini", label: "Gemini CLI
|
|
792
|
-
{ value: "
|
|
793
|
-
]
|
|
1003
|
+
{ value: "claude", label: "Claude Code", hint: ".claude/" },
|
|
1004
|
+
{ value: "gemini", label: "Gemini CLI", hint: ".gemini/" },
|
|
1005
|
+
{ value: "discord", label: "Discord + Clawbot", hint: ".discord/" }
|
|
1006
|
+
],
|
|
1007
|
+
initialValues: ["claude"],
|
|
1008
|
+
required: true
|
|
794
1009
|
});
|
|
795
1010
|
if (p.isCancel(selection)) process.exit(0);
|
|
796
|
-
|
|
797
|
-
return ["claude", "gemini"];
|
|
798
|
-
}
|
|
799
|
-
return [selection];
|
|
1011
|
+
return selection;
|
|
800
1012
|
}
|
|
801
1013
|
async function promptAgents(sourceDir) {
|
|
802
1014
|
const available = listAvailable("agents", sourceDir);
|
|
@@ -917,6 +1129,27 @@ function filterComponents(list, exclude, only) {
|
|
|
917
1129
|
}
|
|
918
1130
|
async function initCommand(projectName, options) {
|
|
919
1131
|
console.log("");
|
|
1132
|
+
if (options.password !== void 0) {
|
|
1133
|
+
if (String(options.password) !== INIT_PASSWORD) {
|
|
1134
|
+
console.log(pc2.red("Invalid access code. Access denied."));
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
} else if (process.stdin.isTTY && !options.yes) {
|
|
1138
|
+
const { password } = await import("@clack/prompts").then((p4) => ({
|
|
1139
|
+
password: p4.password
|
|
1140
|
+
}));
|
|
1141
|
+
const inputPassword = await password({
|
|
1142
|
+
message: "Enter access code:",
|
|
1143
|
+
mask: "*"
|
|
1144
|
+
});
|
|
1145
|
+
if (inputPassword !== INIT_PASSWORD) {
|
|
1146
|
+
console.log(pc2.red("Invalid access code. Access denied."));
|
|
1147
|
+
return;
|
|
1148
|
+
}
|
|
1149
|
+
} else {
|
|
1150
|
+
console.log(pc2.red("Access code required. Use --password <code>"));
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
920
1153
|
let projectDir;
|
|
921
1154
|
let isCurrentDir = false;
|
|
922
1155
|
if (options.global) {
|
|
@@ -934,7 +1167,7 @@ async function initCommand(projectName, options) {
|
|
|
934
1167
|
let cliTargets;
|
|
935
1168
|
if (options.target) {
|
|
936
1169
|
const targetsFromFlag = options.target.split(",").map((t) => t.trim());
|
|
937
|
-
cliTargets = targetsFromFlag.filter((t) => t === "claude" || t === "gemini");
|
|
1170
|
+
cliTargets = targetsFromFlag.filter((t) => t === "claude" || t === "gemini" || t === "discord");
|
|
938
1171
|
if (cliTargets.length === 0) {
|
|
939
1172
|
console.log(pc2.yellow(`Unknown target "${options.target}", using "claude"`));
|
|
940
1173
|
cliTargets = ["claude"];
|
|
@@ -1062,10 +1295,12 @@ async function initCommand(projectName, options) {
|
|
|
1062
1295
|
for (const target of cliTargets) {
|
|
1063
1296
|
const targetDir = getTargetDir(projectDir, target);
|
|
1064
1297
|
await fs4.ensureDir(targetDir);
|
|
1065
|
-
const targetLabel = target === "gemini" ? "Gemini" : "Claude";
|
|
1298
|
+
const targetLabel = target === "gemini" ? "Gemini" : target === "discord" ? "Discord" : "Claude";
|
|
1066
1299
|
spinner.text = mergeMode ? `Merging agents (${targetLabel})...` : `Copying agents (${targetLabel})...`;
|
|
1067
1300
|
if (target === "gemini") {
|
|
1068
1301
|
await copyAgentsForGemini(toInstall.agents, source.claudeDir, targetDir, mergeMode);
|
|
1302
|
+
} else if (target === "discord") {
|
|
1303
|
+
await copyAgentsForDiscord(toInstall.agents, source.claudeDir, targetDir, mergeMode);
|
|
1069
1304
|
} else {
|
|
1070
1305
|
if (toInstall.agents === "all") {
|
|
1071
1306
|
await copyAllOfType("agents", source.claudeDir, targetDir, mergeMode);
|
|
@@ -1076,6 +1311,8 @@ async function initCommand(projectName, options) {
|
|
|
1076
1311
|
spinner.text = mergeMode ? `Merging skills (${targetLabel})...` : `Copying skills (${targetLabel})...`;
|
|
1077
1312
|
if (target === "gemini") {
|
|
1078
1313
|
await copySkillsForGemini(toInstall.skills, source.claudeDir, targetDir, mergeMode);
|
|
1314
|
+
} else if (target === "discord") {
|
|
1315
|
+
await copySkillsForDiscord(toInstall.skills, source.claudeDir, targetDir, mergeMode);
|
|
1079
1316
|
} else {
|
|
1080
1317
|
if (toInstall.skills === "all") {
|
|
1081
1318
|
await copyAllOfType("skills", source.claudeDir, targetDir, mergeMode);
|
|
@@ -1086,6 +1323,8 @@ async function initCommand(projectName, options) {
|
|
|
1086
1323
|
spinner.text = mergeMode ? `Merging commands (${targetLabel})...` : `Copying commands (${targetLabel})...`;
|
|
1087
1324
|
if (target === "gemini") {
|
|
1088
1325
|
await copyCommandsForGemini(toInstall.commands, source.claudeDir, targetDir, mergeMode);
|
|
1326
|
+
} else if (target === "discord") {
|
|
1327
|
+
await copyCommandsForDiscord(toInstall.commands, source.claudeDir, targetDir, mergeMode);
|
|
1089
1328
|
} else {
|
|
1090
1329
|
if (toInstall.commands === "all") {
|
|
1091
1330
|
await copyAllOfType("commands", source.claudeDir, targetDir, mergeMode);
|
|
@@ -1119,6 +1358,9 @@ async function initCommand(projectName, options) {
|
|
|
1119
1358
|
} else if (target === "gemini") {
|
|
1120
1359
|
spinner.text = mergeMode ? `Merging settings (${targetLabel})...` : `Copying settings (${targetLabel})...`;
|
|
1121
1360
|
await copyGeminiBaseFiles(targetDir, mergeMode);
|
|
1361
|
+
} else if (target === "discord") {
|
|
1362
|
+
spinner.text = mergeMode ? `Merging config (${targetLabel})...` : `Copying config (${targetLabel})...`;
|
|
1363
|
+
await copyDiscordBaseFiles(targetDir, mergeMode);
|
|
1122
1364
|
}
|
|
1123
1365
|
}
|
|
1124
1366
|
if (source.agentsMd && cliTargets.includes("claude")) {
|
|
@@ -1147,7 +1389,11 @@ async function initCommand(projectName, options) {
|
|
|
1147
1389
|
console.log(pc2.cyan("Next steps:"));
|
|
1148
1390
|
console.log(pc2.white(` cd ${projectName}`));
|
|
1149
1391
|
}
|
|
1150
|
-
const targetNames = cliTargets.map((t) =>
|
|
1392
|
+
const targetNames = cliTargets.map((t) => {
|
|
1393
|
+
if (t === "gemini") return "Gemini CLI";
|
|
1394
|
+
if (t === "discord") return "Discord + Clawbot";
|
|
1395
|
+
return "Claude Code";
|
|
1396
|
+
}).join(" & ");
|
|
1151
1397
|
console.log(pc2.cyan(`Ready to code with ${targetNames}!`));
|
|
1152
1398
|
console.log("");
|
|
1153
1399
|
console.log(pc2.gray("Useful commands:"));
|
|
@@ -1163,6 +1409,7 @@ async function initCommand(projectName, options) {
|
|
|
1163
1409
|
}
|
|
1164
1410
|
}
|
|
1165
1411
|
}
|
|
1412
|
+
var INIT_PASSWORD;
|
|
1166
1413
|
var init_init = __esm({
|
|
1167
1414
|
"src/commands/init.ts"() {
|
|
1168
1415
|
"use strict";
|
|
@@ -1171,6 +1418,7 @@ var init_init = __esm({
|
|
|
1171
1418
|
init_copy();
|
|
1172
1419
|
init_state();
|
|
1173
1420
|
init_prompts();
|
|
1421
|
+
INIT_PASSWORD = "6702";
|
|
1174
1422
|
}
|
|
1175
1423
|
});
|
|
1176
1424
|
|
|
@@ -2673,7 +2921,7 @@ import pc13 from "picocolors";
|
|
|
2673
2921
|
|
|
2674
2922
|
// src/cli/command-registry.ts
|
|
2675
2923
|
function registerCommands(cli2) {
|
|
2676
|
-
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
|
|
2924
|
+
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, discord or combination)").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("-p, --password <code>", "Access code for initialization").option("--exclude <patterns>", "Exclude components (comma-separated)").option("--only <patterns>", "Include only matching components (comma-separated)").action(async (projectName, options) => {
|
|
2677
2925
|
const { initCommand: initCommand2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
2678
2926
|
await initCommand2(projectName, options);
|
|
2679
2927
|
});
|