apero-kit-cli 2.2.5 → 2.4.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 +427 -14
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
- package/templates/discord/README.md +227 -0
- package/templates/discord/config.json5 +87 -0
- package/templates/discord/skills/auto-intent-router/SKILL.md +195 -0
- package/templates/discord/skills/train-prompt/SKILL.md +306 -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,379 @@ 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
|
+
}
|
|
826
|
+
function extractKeywords(content, commandName) {
|
|
827
|
+
const keywords = /* @__PURE__ */ new Set();
|
|
828
|
+
keywords.add(commandName);
|
|
829
|
+
keywords.add(commandName.replace(/-/g, " "));
|
|
830
|
+
const keywordPatterns = [
|
|
831
|
+
/keywords?:\s*([^\n]+)/gi,
|
|
832
|
+
/when.*(?:says?|mentions?|asks?).*["']([^"']+)["']/gi,
|
|
833
|
+
/trigger.*["']([^"']+)["']/gi
|
|
834
|
+
];
|
|
835
|
+
for (const pattern of keywordPatterns) {
|
|
836
|
+
const matches = content.matchAll(pattern);
|
|
837
|
+
for (const match of matches) {
|
|
838
|
+
match[1].split(/[,;]/).forEach((k) => keywords.add(k.trim().toLowerCase()));
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
const intentMap = {
|
|
842
|
+
"plan": ["plan", "design", "architect", "implement", "create plan"],
|
|
843
|
+
"brainstorm": ["brainstorm", "ideas", "options", "alternatives", "think"],
|
|
844
|
+
"fix": ["fix", "debug", "error", "broken", "issue", "bug"],
|
|
845
|
+
"code": ["code", "implement", "build", "develop", "write code"],
|
|
846
|
+
"review": ["review", "check", "audit", "look at"],
|
|
847
|
+
"test": ["test", "testing", "spec", "unit test"],
|
|
848
|
+
"cook": ["cook", "implement", "build feature", "develop"],
|
|
849
|
+
"scout": ["scout", "search", "find", "explore codebase"],
|
|
850
|
+
"debug": ["debug", "trace", "diagnose", "investigate"]
|
|
851
|
+
};
|
|
852
|
+
const baseName = commandName.split("/")[0].split(":")[0];
|
|
853
|
+
if (intentMap[baseName]) {
|
|
854
|
+
intentMap[baseName].forEach((k) => keywords.add(k));
|
|
855
|
+
}
|
|
856
|
+
return Array.from(keywords).slice(0, 10);
|
|
857
|
+
}
|
|
858
|
+
function convertCommandToSkill(mdContent, commandName) {
|
|
859
|
+
const { description, argumentHint, body } = parseFrontmatter(mdContent);
|
|
860
|
+
const prompt = body.replace(/\$ARGUMENTS/g, "{{args}}");
|
|
861
|
+
const keywords = extractKeywords(body, commandName);
|
|
862
|
+
const skillContent = `---
|
|
863
|
+
name: ${commandName.replace(/\//g, "-")}
|
|
864
|
+
description: ${description || `Execute ${commandName} task`}
|
|
865
|
+
user-invocable: true
|
|
866
|
+
disable-model-invocation: false
|
|
867
|
+
metadata: {"openclaw": {"always": true}}
|
|
868
|
+
---
|
|
869
|
+
|
|
870
|
+
# ${commandName.charAt(0).toUpperCase() + commandName.slice(1).replace(/-/g, " ")}
|
|
871
|
+
|
|
872
|
+
## Trigger Conditions
|
|
873
|
+
|
|
874
|
+
Activate when user mentions:
|
|
875
|
+
${keywords.map((k) => `- "${k}"`).join("\n")}
|
|
876
|
+
|
|
877
|
+
## Input
|
|
878
|
+
${argumentHint ? `Expected input: ${argumentHint.replace("$ARGUMENTS", "{{args}}")}` : "User provides task description in natural language."}
|
|
879
|
+
|
|
880
|
+
## Workflow
|
|
881
|
+
|
|
882
|
+
${prompt}
|
|
883
|
+
|
|
884
|
+
## Output Format
|
|
885
|
+
|
|
886
|
+
Provide clear, actionable response based on the workflow above.
|
|
887
|
+
`;
|
|
888
|
+
return skillContent;
|
|
889
|
+
}
|
|
890
|
+
async function convertCommandsToSkills(items, sourceDir, destDir, mergeMode = false) {
|
|
891
|
+
const typeDir = join2(sourceDir, "commands");
|
|
892
|
+
const destTypeDir = join2(destDir, "skills");
|
|
893
|
+
if (!fs.existsSync(typeDir)) {
|
|
894
|
+
return { copied: [], skipped: [], errors: [] };
|
|
895
|
+
}
|
|
896
|
+
await fs.ensureDir(destTypeDir);
|
|
897
|
+
const copied = [];
|
|
898
|
+
const skipped = [];
|
|
899
|
+
const errors = [];
|
|
900
|
+
let itemList;
|
|
901
|
+
if (items === "all") {
|
|
902
|
+
const entries = fs.readdirSync(typeDir);
|
|
903
|
+
itemList = entries.filter((e) => e.endsWith(".md") && e !== "README.md").map((e) => e.replace(/\.md$/, ""));
|
|
904
|
+
const dirs = entries.filter((e) => {
|
|
905
|
+
const fullPath = join2(typeDir, e);
|
|
906
|
+
return fs.statSync(fullPath).isDirectory();
|
|
907
|
+
});
|
|
908
|
+
itemList = [.../* @__PURE__ */ new Set([...itemList, ...dirs])];
|
|
909
|
+
} else {
|
|
910
|
+
itemList = items;
|
|
911
|
+
}
|
|
912
|
+
for (const item of itemList) {
|
|
913
|
+
try {
|
|
914
|
+
const srcPathMd = join2(typeDir, item + ".md");
|
|
915
|
+
const srcPathDir = join2(typeDir, item);
|
|
916
|
+
if (fs.existsSync(srcPathMd) && fs.statSync(srcPathMd).isFile()) {
|
|
917
|
+
const skillDir = join2(destTypeDir, item.replace(/\//g, "-"));
|
|
918
|
+
const skillPath = join2(skillDir, "SKILL.md");
|
|
919
|
+
if (mergeMode && fs.existsSync(skillPath)) {
|
|
920
|
+
skipped.push(item);
|
|
921
|
+
continue;
|
|
922
|
+
}
|
|
923
|
+
await fs.ensureDir(skillDir);
|
|
924
|
+
const mdContent = fs.readFileSync(srcPathMd, "utf-8");
|
|
925
|
+
const skillContent = convertCommandToSkill(mdContent, item);
|
|
926
|
+
await fs.writeFile(skillPath, skillContent, "utf-8");
|
|
927
|
+
copied.push(item);
|
|
928
|
+
}
|
|
929
|
+
if (fs.existsSync(srcPathDir) && fs.statSync(srcPathDir).isDirectory()) {
|
|
930
|
+
await convertNestedCommandsToSkills(srcPathDir, destTypeDir, item, mergeMode);
|
|
931
|
+
copied.push(item + "/*");
|
|
932
|
+
}
|
|
933
|
+
} catch (err) {
|
|
934
|
+
errors.push({ item, error: err.message });
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
return { copied, skipped, errors };
|
|
938
|
+
}
|
|
939
|
+
async function convertNestedCommandsToSkills(srcDir, destDir, parentName, mergeMode) {
|
|
940
|
+
const entries = fs.readdirSync(srcDir);
|
|
941
|
+
for (const entry of entries) {
|
|
942
|
+
const srcPath = join2(srcDir, entry);
|
|
943
|
+
const stat = fs.statSync(srcPath);
|
|
944
|
+
if (stat.isDirectory()) {
|
|
945
|
+
await convertNestedCommandsToSkills(
|
|
946
|
+
srcPath,
|
|
947
|
+
destDir,
|
|
948
|
+
`${parentName}-${entry}`,
|
|
949
|
+
mergeMode
|
|
950
|
+
);
|
|
951
|
+
} else if (entry.endsWith(".md") && entry !== "README.md") {
|
|
952
|
+
const skillName = `${parentName}-${entry.replace(/\.md$/, "")}`;
|
|
953
|
+
const skillDir = join2(destDir, skillName);
|
|
954
|
+
const skillPath = join2(skillDir, "SKILL.md");
|
|
955
|
+
if (mergeMode && fs.existsSync(skillPath)) {
|
|
956
|
+
continue;
|
|
957
|
+
}
|
|
958
|
+
await fs.ensureDir(skillDir);
|
|
959
|
+
const mdContent = fs.readFileSync(srcPath, "utf-8");
|
|
960
|
+
const skillContent = convertCommandToSkill(mdContent, skillName);
|
|
961
|
+
await fs.writeFile(skillPath, skillContent, "utf-8");
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
async function copyBundledSkillsForDiscord(destDir, mergeMode = false) {
|
|
966
|
+
const bundledSkillsDir = join2(CLI_ROOT, "templates", "discord", "skills");
|
|
967
|
+
const destSkillsDir = join2(destDir, "skills");
|
|
968
|
+
const copied = [];
|
|
969
|
+
if (!fs.existsSync(bundledSkillsDir)) {
|
|
970
|
+
return copied;
|
|
971
|
+
}
|
|
972
|
+
await fs.ensureDir(destSkillsDir);
|
|
973
|
+
const skills = fs.readdirSync(bundledSkillsDir);
|
|
974
|
+
for (const skill of skills) {
|
|
975
|
+
const srcPath = join2(bundledSkillsDir, skill);
|
|
976
|
+
const destPath = join2(destSkillsDir, skill);
|
|
977
|
+
if (fs.statSync(srcPath).isDirectory()) {
|
|
978
|
+
if (mergeMode && fs.existsSync(destPath)) {
|
|
979
|
+
continue;
|
|
980
|
+
}
|
|
981
|
+
await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
982
|
+
copied.push(skill);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
return copied;
|
|
986
|
+
}
|
|
613
987
|
var init_copy = __esm({
|
|
614
988
|
"src/utils/copy.ts"() {
|
|
615
989
|
"use strict";
|
|
@@ -784,19 +1158,18 @@ async function promptKit() {
|
|
|
784
1158
|
return kit;
|
|
785
1159
|
}
|
|
786
1160
|
async function promptCliTargets() {
|
|
787
|
-
const selection = await p.
|
|
788
|
-
message: "Select AI CLI target:",
|
|
1161
|
+
const selection = await p.multiselect({
|
|
1162
|
+
message: "Select AI CLI target(s):",
|
|
789
1163
|
options: [
|
|
790
|
-
{ value: "claude", label: "Claude Code
|
|
791
|
-
{ value: "gemini", label: "Gemini CLI
|
|
792
|
-
{ value: "
|
|
793
|
-
]
|
|
1164
|
+
{ value: "claude", label: "Claude Code", hint: ".claude/" },
|
|
1165
|
+
{ value: "gemini", label: "Gemini CLI", hint: ".gemini/" },
|
|
1166
|
+
{ value: "discord", label: "Discord + Clawbot", hint: ".discord/" }
|
|
1167
|
+
],
|
|
1168
|
+
initialValues: ["claude"],
|
|
1169
|
+
required: true
|
|
794
1170
|
});
|
|
795
1171
|
if (p.isCancel(selection)) process.exit(0);
|
|
796
|
-
|
|
797
|
-
return ["claude", "gemini"];
|
|
798
|
-
}
|
|
799
|
-
return [selection];
|
|
1172
|
+
return selection;
|
|
800
1173
|
}
|
|
801
1174
|
async function promptAgents(sourceDir) {
|
|
802
1175
|
const available = listAvailable("agents", sourceDir);
|
|
@@ -917,6 +1290,27 @@ function filterComponents(list, exclude, only) {
|
|
|
917
1290
|
}
|
|
918
1291
|
async function initCommand(projectName, options) {
|
|
919
1292
|
console.log("");
|
|
1293
|
+
if (options.password !== void 0) {
|
|
1294
|
+
if (String(options.password) !== INIT_PASSWORD) {
|
|
1295
|
+
console.log(pc2.red("Invalid access code. Access denied."));
|
|
1296
|
+
return;
|
|
1297
|
+
}
|
|
1298
|
+
} else if (process.stdin.isTTY && !options.yes) {
|
|
1299
|
+
const { password } = await import("@clack/prompts").then((p4) => ({
|
|
1300
|
+
password: p4.password
|
|
1301
|
+
}));
|
|
1302
|
+
const inputPassword = await password({
|
|
1303
|
+
message: "Enter access code:",
|
|
1304
|
+
mask: "*"
|
|
1305
|
+
});
|
|
1306
|
+
if (inputPassword !== INIT_PASSWORD) {
|
|
1307
|
+
console.log(pc2.red("Invalid access code. Access denied."));
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
} else {
|
|
1311
|
+
console.log(pc2.red("Access code required. Use --password <code>"));
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
920
1314
|
let projectDir;
|
|
921
1315
|
let isCurrentDir = false;
|
|
922
1316
|
if (options.global) {
|
|
@@ -934,7 +1328,7 @@ async function initCommand(projectName, options) {
|
|
|
934
1328
|
let cliTargets;
|
|
935
1329
|
if (options.target) {
|
|
936
1330
|
const targetsFromFlag = options.target.split(",").map((t) => t.trim());
|
|
937
|
-
cliTargets = targetsFromFlag.filter((t) => t === "claude" || t === "gemini");
|
|
1331
|
+
cliTargets = targetsFromFlag.filter((t) => t === "claude" || t === "gemini" || t === "discord");
|
|
938
1332
|
if (cliTargets.length === 0) {
|
|
939
1333
|
console.log(pc2.yellow(`Unknown target "${options.target}", using "claude"`));
|
|
940
1334
|
cliTargets = ["claude"];
|
|
@@ -1062,10 +1456,12 @@ async function initCommand(projectName, options) {
|
|
|
1062
1456
|
for (const target of cliTargets) {
|
|
1063
1457
|
const targetDir = getTargetDir(projectDir, target);
|
|
1064
1458
|
await fs4.ensureDir(targetDir);
|
|
1065
|
-
const targetLabel = target === "gemini" ? "Gemini" : "Claude";
|
|
1459
|
+
const targetLabel = target === "gemini" ? "Gemini" : target === "discord" ? "Discord" : "Claude";
|
|
1066
1460
|
spinner.text = mergeMode ? `Merging agents (${targetLabel})...` : `Copying agents (${targetLabel})...`;
|
|
1067
1461
|
if (target === "gemini") {
|
|
1068
1462
|
await copyAgentsForGemini(toInstall.agents, source.claudeDir, targetDir, mergeMode);
|
|
1463
|
+
} else if (target === "discord") {
|
|
1464
|
+
await copyAgentsForDiscord(toInstall.agents, source.claudeDir, targetDir, mergeMode);
|
|
1069
1465
|
} else {
|
|
1070
1466
|
if (toInstall.agents === "all") {
|
|
1071
1467
|
await copyAllOfType("agents", source.claudeDir, targetDir, mergeMode);
|
|
@@ -1076,6 +1472,8 @@ async function initCommand(projectName, options) {
|
|
|
1076
1472
|
spinner.text = mergeMode ? `Merging skills (${targetLabel})...` : `Copying skills (${targetLabel})...`;
|
|
1077
1473
|
if (target === "gemini") {
|
|
1078
1474
|
await copySkillsForGemini(toInstall.skills, source.claudeDir, targetDir, mergeMode);
|
|
1475
|
+
} else if (target === "discord") {
|
|
1476
|
+
await copySkillsForDiscord(toInstall.skills, source.claudeDir, targetDir, mergeMode);
|
|
1079
1477
|
} else {
|
|
1080
1478
|
if (toInstall.skills === "all") {
|
|
1081
1479
|
await copyAllOfType("skills", source.claudeDir, targetDir, mergeMode);
|
|
@@ -1086,6 +1484,12 @@ async function initCommand(projectName, options) {
|
|
|
1086
1484
|
spinner.text = mergeMode ? `Merging commands (${targetLabel})...` : `Copying commands (${targetLabel})...`;
|
|
1087
1485
|
if (target === "gemini") {
|
|
1088
1486
|
await copyCommandsForGemini(toInstall.commands, source.claudeDir, targetDir, mergeMode);
|
|
1487
|
+
} else if (target === "discord") {
|
|
1488
|
+
await copyCommandsForDiscord(toInstall.commands, source.claudeDir, targetDir, mergeMode);
|
|
1489
|
+
spinner.text = mergeMode ? `Converting commands to skills (${targetLabel})...` : `Converting commands to skills (${targetLabel})...`;
|
|
1490
|
+
await convertCommandsToSkills(toInstall.commands, source.claudeDir, targetDir, mergeMode);
|
|
1491
|
+
spinner.text = `Copying bundled skills (${targetLabel})...`;
|
|
1492
|
+
await copyBundledSkillsForDiscord(targetDir, mergeMode);
|
|
1089
1493
|
} else {
|
|
1090
1494
|
if (toInstall.commands === "all") {
|
|
1091
1495
|
await copyAllOfType("commands", source.claudeDir, targetDir, mergeMode);
|
|
@@ -1119,6 +1523,9 @@ async function initCommand(projectName, options) {
|
|
|
1119
1523
|
} else if (target === "gemini") {
|
|
1120
1524
|
spinner.text = mergeMode ? `Merging settings (${targetLabel})...` : `Copying settings (${targetLabel})...`;
|
|
1121
1525
|
await copyGeminiBaseFiles(targetDir, mergeMode);
|
|
1526
|
+
} else if (target === "discord") {
|
|
1527
|
+
spinner.text = mergeMode ? `Merging config (${targetLabel})...` : `Copying config (${targetLabel})...`;
|
|
1528
|
+
await copyDiscordBaseFiles(targetDir, mergeMode);
|
|
1122
1529
|
}
|
|
1123
1530
|
}
|
|
1124
1531
|
if (source.agentsMd && cliTargets.includes("claude")) {
|
|
@@ -1147,7 +1554,11 @@ async function initCommand(projectName, options) {
|
|
|
1147
1554
|
console.log(pc2.cyan("Next steps:"));
|
|
1148
1555
|
console.log(pc2.white(` cd ${projectName}`));
|
|
1149
1556
|
}
|
|
1150
|
-
const targetNames = cliTargets.map((t) =>
|
|
1557
|
+
const targetNames = cliTargets.map((t) => {
|
|
1558
|
+
if (t === "gemini") return "Gemini CLI";
|
|
1559
|
+
if (t === "discord") return "Discord + Clawbot";
|
|
1560
|
+
return "Claude Code";
|
|
1561
|
+
}).join(" & ");
|
|
1151
1562
|
console.log(pc2.cyan(`Ready to code with ${targetNames}!`));
|
|
1152
1563
|
console.log("");
|
|
1153
1564
|
console.log(pc2.gray("Useful commands:"));
|
|
@@ -1163,6 +1574,7 @@ async function initCommand(projectName, options) {
|
|
|
1163
1574
|
}
|
|
1164
1575
|
}
|
|
1165
1576
|
}
|
|
1577
|
+
var INIT_PASSWORD;
|
|
1166
1578
|
var init_init = __esm({
|
|
1167
1579
|
"src/commands/init.ts"() {
|
|
1168
1580
|
"use strict";
|
|
@@ -1171,6 +1583,7 @@ var init_init = __esm({
|
|
|
1171
1583
|
init_copy();
|
|
1172
1584
|
init_state();
|
|
1173
1585
|
init_prompts();
|
|
1586
|
+
INIT_PASSWORD = "6702";
|
|
1174
1587
|
}
|
|
1175
1588
|
});
|
|
1176
1589
|
|
|
@@ -2673,7 +3086,7 @@ import pc13 from "picocolors";
|
|
|
2673
3086
|
|
|
2674
3087
|
// src/cli/command-registry.ts
|
|
2675
3088
|
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
|
|
3089
|
+
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
3090
|
const { initCommand: initCommand2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
2678
3091
|
await initCommand2(projectName, options);
|
|
2679
3092
|
});
|