thanh-kit 2.5.9 → 2.5.11
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 +430 -316
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/codex/AGENTS.md +65 -0
- package/templates/codex/config.local.toml +17 -0
- package/templates/codex/config.toml +72 -0
- package/templates/gemini/GEMINI.md +44 -0
- package/templates/gemini/settings.json +103 -0
- package/templates/gemini/settings.local.json +51 -0
- package/templates/settings.local.json +1 -1
package/dist/index.js
CHANGED
|
@@ -175,9 +175,11 @@ function isAkProject(dir = process.cwd()) {
|
|
|
175
175
|
const akConfig = join(dir, ".ak", "state.json");
|
|
176
176
|
const claudeDir = join(dir, ".claude");
|
|
177
177
|
const geminiDir = join(dir, ".gemini");
|
|
178
|
+
const codexDir = join(dir, ".codex");
|
|
179
|
+
const agentsDir = join(dir, ".agents");
|
|
178
180
|
const opencodeDir = join(dir, ".opencode");
|
|
179
181
|
const agentDir = join(dir, ".agent");
|
|
180
|
-
return existsSync(akConfig) || existsSync(claudeDir) || existsSync(geminiDir) || existsSync(opencodeDir) || existsSync(agentDir);
|
|
182
|
+
return existsSync(akConfig) || existsSync(claudeDir) || existsSync(geminiDir) || existsSync(codexDir) || existsSync(agentsDir) || existsSync(opencodeDir) || existsSync(agentDir);
|
|
181
183
|
}
|
|
182
184
|
function getTargetDir(projectDir, target = "claude") {
|
|
183
185
|
const folder = TARGETS[target] || TARGETS.claude;
|
|
@@ -245,6 +247,8 @@ var init_paths = __esm({
|
|
|
245
247
|
TARGETS = {
|
|
246
248
|
claude: ".claude",
|
|
247
249
|
gemini: ".gemini",
|
|
250
|
+
codex: ".agents",
|
|
251
|
+
// Codex uses .agents for skills, .codex for config
|
|
248
252
|
discord: ".discord",
|
|
249
253
|
opencode: ".opencode",
|
|
250
254
|
generic: ".agent"
|
|
@@ -582,7 +586,7 @@ var init_claude_adapter = __esm({
|
|
|
582
586
|
|
|
583
587
|
// src/targets/gemini-adapter.ts
|
|
584
588
|
import fs3 from "fs-extra";
|
|
585
|
-
import { join as join4
|
|
589
|
+
import { join as join4 } from "path";
|
|
586
590
|
function parseFrontmatter(content) {
|
|
587
591
|
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
588
592
|
if (!match) {
|
|
@@ -590,9 +594,6 @@ function parseFrontmatter(content) {
|
|
|
590
594
|
}
|
|
591
595
|
return { frontmatter: match[1], body: match[2] };
|
|
592
596
|
}
|
|
593
|
-
function escapeTomlString(str) {
|
|
594
|
-
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\t/g, "\\t");
|
|
595
|
-
}
|
|
596
597
|
function convertAgentToGemini(mdContent) {
|
|
597
598
|
const { frontmatter, body } = parseFrontmatter(mdContent);
|
|
598
599
|
if (!frontmatter) return mdContent;
|
|
@@ -614,20 +615,6 @@ ${converted.trim()}
|
|
|
614
615
|
---
|
|
615
616
|
${body}`;
|
|
616
617
|
}
|
|
617
|
-
function convertCommandToToml(mdContent) {
|
|
618
|
-
const { frontmatter, body } = parseFrontmatter(mdContent);
|
|
619
|
-
const descMatch = frontmatter.match(/description:\s*(.+)/);
|
|
620
|
-
const description = descMatch ? descMatch[1].trim() : "";
|
|
621
|
-
const prompt = body.trim().replace(/\$ARGUMENTS/g, "{{args}}");
|
|
622
|
-
const lines = [];
|
|
623
|
-
if (description) {
|
|
624
|
-
lines.push(`description = "${escapeTomlString(description)}"`);
|
|
625
|
-
}
|
|
626
|
-
lines.push(`prompt = '''
|
|
627
|
-
${prompt}
|
|
628
|
-
'''`);
|
|
629
|
-
return lines.join("\n");
|
|
630
|
-
}
|
|
631
618
|
var MODEL_MAP, GeminiAdapter;
|
|
632
619
|
var init_gemini_adapter = __esm({
|
|
633
620
|
"src/targets/gemini-adapter.ts"() {
|
|
@@ -648,7 +635,8 @@ var init_gemini_adapter = __esm({
|
|
|
648
635
|
features: {
|
|
649
636
|
agents: true,
|
|
650
637
|
skills: true,
|
|
651
|
-
commands:
|
|
638
|
+
commands: false,
|
|
639
|
+
// Gemini uses skills, not commands
|
|
652
640
|
workflows: false,
|
|
653
641
|
router: false,
|
|
654
642
|
hooks: false,
|
|
@@ -740,88 +728,210 @@ var init_gemini_adapter = __esm({
|
|
|
740
728
|
}
|
|
741
729
|
return { copied, skipped, errors };
|
|
742
730
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
731
|
+
// Commands not supported - Gemini uses skills instead
|
|
732
|
+
async copyCommands(_items, _sourceDir, _targetDir, _mergeMode) {
|
|
733
|
+
return { copied: [], skipped: [], errors: [] };
|
|
734
|
+
}
|
|
735
|
+
async copyBaseFiles(targetDir, mergeMode) {
|
|
736
|
+
const { CLI_ROOT: CLI_ROOT2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
737
|
+
const geminiTemplates = join4(CLI_ROOT2, "templates", "gemini");
|
|
738
|
+
const copied = [];
|
|
739
|
+
const projectRoot = join4(targetDir, "..");
|
|
740
|
+
const settingsFiles = ["settings.json", "settings.local.json"];
|
|
741
|
+
for (const file of settingsFiles) {
|
|
742
|
+
const srcPath = join4(geminiTemplates, file);
|
|
743
|
+
const destPath = join4(targetDir, file);
|
|
744
|
+
if (fs3.existsSync(srcPath)) {
|
|
745
|
+
if (!(mergeMode && fs3.existsSync(destPath))) {
|
|
746
|
+
await fs3.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
747
|
+
copied.push(file);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
const geminiMdSrc = join4(geminiTemplates, "GEMINI.md");
|
|
752
|
+
const geminiMdDest = join4(projectRoot, "GEMINI.md");
|
|
753
|
+
if (fs3.existsSync(geminiMdSrc)) {
|
|
754
|
+
if (!(mergeMode && fs3.existsSync(geminiMdDest))) {
|
|
755
|
+
await fs3.copy(geminiMdSrc, geminiMdDest, { overwrite: !mergeMode });
|
|
756
|
+
copied.push("GEMINI.md (project root)");
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return copied;
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
// src/targets/codex-adapter.ts
|
|
766
|
+
import fs4 from "fs-extra";
|
|
767
|
+
import { join as join5 } from "path";
|
|
768
|
+
function parseFrontmatter2(content) {
|
|
769
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
770
|
+
if (!match) {
|
|
771
|
+
return { frontmatter: "", body: content };
|
|
772
|
+
}
|
|
773
|
+
return { frontmatter: match[1], body: match[2] };
|
|
774
|
+
}
|
|
775
|
+
function convertAgentToCodex(mdContent) {
|
|
776
|
+
const { frontmatter, body } = parseFrontmatter2(mdContent);
|
|
777
|
+
if (!frontmatter) return mdContent;
|
|
778
|
+
let converted = frontmatter;
|
|
779
|
+
for (const [claudeModel, codexModel] of Object.entries(MODEL_MAP2)) {
|
|
780
|
+
const regex = new RegExp(`^model:\\s*${claudeModel}\\s*$`, "m");
|
|
781
|
+
if (codexModel) {
|
|
782
|
+
converted = converted.replace(regex, `model: ${codexModel}`);
|
|
783
|
+
} else {
|
|
784
|
+
converted = converted.replace(regex, "");
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
converted = converted.replace(/^tools:\s*.+$/m, "");
|
|
788
|
+
return `---
|
|
789
|
+
${converted.trim()}
|
|
790
|
+
---
|
|
791
|
+
${body}`;
|
|
792
|
+
}
|
|
793
|
+
var MODEL_MAP2, CodexAdapter;
|
|
794
|
+
var init_codex_adapter = __esm({
|
|
795
|
+
"src/targets/codex-adapter.ts"() {
|
|
796
|
+
"use strict";
|
|
797
|
+
init_base_adapter();
|
|
798
|
+
MODEL_MAP2 = {
|
|
799
|
+
"opus": "o3",
|
|
800
|
+
"sonnet": "o4-mini",
|
|
801
|
+
"haiku": "gpt-4.1-mini",
|
|
802
|
+
"inherit": ""
|
|
803
|
+
// Remove inherit, let Codex use default
|
|
804
|
+
};
|
|
805
|
+
CodexAdapter = class extends BaseTargetAdapter {
|
|
806
|
+
config = {
|
|
807
|
+
name: "codex",
|
|
808
|
+
displayName: "Codex CLI",
|
|
809
|
+
directory: ".agents",
|
|
810
|
+
// Main directory for skills/agents
|
|
811
|
+
features: {
|
|
812
|
+
agents: true,
|
|
813
|
+
skills: true,
|
|
814
|
+
commands: false,
|
|
815
|
+
// Codex uses skills, not commands
|
|
816
|
+
workflows: false,
|
|
817
|
+
router: false,
|
|
818
|
+
hooks: false,
|
|
819
|
+
memory: false,
|
|
820
|
+
scripts: false,
|
|
821
|
+
"output-styles": false
|
|
822
|
+
}
|
|
823
|
+
};
|
|
824
|
+
async copyAgents(items, sourceDir, targetDir, mergeMode) {
|
|
825
|
+
const typeDir = join5(sourceDir, "agents");
|
|
826
|
+
const destTypeDir = join5(targetDir, "agents");
|
|
827
|
+
if (!fs4.existsSync(typeDir)) {
|
|
747
828
|
return { copied: [], skipped: [], errors: [] };
|
|
748
829
|
}
|
|
749
|
-
await
|
|
750
|
-
let
|
|
830
|
+
await fs4.ensureDir(destTypeDir);
|
|
831
|
+
let agentList;
|
|
751
832
|
if (items === "all") {
|
|
752
|
-
const entries =
|
|
753
|
-
|
|
833
|
+
const entries = fs4.readdirSync(typeDir);
|
|
834
|
+
agentList = entries.filter((e) => e.endsWith(".md") && e !== "README.md").map((e) => e.replace(".md", ""));
|
|
754
835
|
} else {
|
|
755
|
-
|
|
836
|
+
agentList = items;
|
|
756
837
|
}
|
|
757
838
|
const copied = [];
|
|
758
839
|
const skipped = [];
|
|
759
840
|
const errors = [];
|
|
760
|
-
for (const
|
|
841
|
+
for (const agent of agentList) {
|
|
761
842
|
try {
|
|
762
|
-
const
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
const destPath = join4(destTypeDir, item + ".toml");
|
|
767
|
-
if (!(mergeMode && fs3.existsSync(destPath))) {
|
|
768
|
-
await fs3.ensureDir(dirname3(destPath));
|
|
769
|
-
const mdContent = fs3.readFileSync(srcPathMd, "utf-8");
|
|
770
|
-
const tomlContent = convertCommandToToml(mdContent);
|
|
771
|
-
await fs3.writeFile(destPath, tomlContent, "utf-8");
|
|
772
|
-
copiedSomething = true;
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
if (fs3.existsSync(srcPathDir) && fs3.statSync(srcPathDir).isDirectory()) {
|
|
776
|
-
await this.convertDirectoryToToml(srcPathDir, join4(destTypeDir, item), mergeMode);
|
|
777
|
-
copiedSomething = true;
|
|
843
|
+
const srcPath = join5(typeDir, agent + ".md");
|
|
844
|
+
if (!fs4.existsSync(srcPath)) {
|
|
845
|
+
skipped.push(agent);
|
|
846
|
+
continue;
|
|
778
847
|
}
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
848
|
+
const destPath = join5(destTypeDir, agent + ".md");
|
|
849
|
+
if (mergeMode && fs4.existsSync(destPath)) {
|
|
850
|
+
skipped.push(agent);
|
|
851
|
+
continue;
|
|
783
852
|
}
|
|
853
|
+
const mdContent = fs4.readFileSync(srcPath, "utf-8");
|
|
854
|
+
const convertedContent = convertAgentToCodex(mdContent);
|
|
855
|
+
await fs4.writeFile(destPath, convertedContent, "utf-8");
|
|
856
|
+
copied.push(agent);
|
|
784
857
|
} catch (err) {
|
|
785
|
-
errors.push({ item, error: err.message });
|
|
858
|
+
errors.push({ item: agent, error: err.message });
|
|
786
859
|
}
|
|
787
860
|
}
|
|
788
861
|
return { copied, skipped, errors };
|
|
789
862
|
}
|
|
790
|
-
async
|
|
791
|
-
|
|
792
|
-
const
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
863
|
+
async copySkills(items, sourceDir, targetDir, mergeMode) {
|
|
864
|
+
const typeDir = join5(sourceDir, "skills");
|
|
865
|
+
const destTypeDir = join5(targetDir, "skills");
|
|
866
|
+
if (!fs4.existsSync(typeDir)) {
|
|
867
|
+
return { copied: [], skipped: [], errors: [] };
|
|
868
|
+
}
|
|
869
|
+
await fs4.ensureDir(destTypeDir);
|
|
870
|
+
let skillList;
|
|
871
|
+
if (items === "all") {
|
|
872
|
+
const entries = fs4.readdirSync(typeDir);
|
|
873
|
+
skillList = entries.filter((e) => {
|
|
874
|
+
const fullPath = join5(typeDir, e);
|
|
875
|
+
return fs4.statSync(fullPath).isDirectory() && fs4.existsSync(join5(fullPath, "SKILL.md"));
|
|
876
|
+
});
|
|
877
|
+
} else {
|
|
878
|
+
skillList = items;
|
|
879
|
+
}
|
|
880
|
+
const copied = [];
|
|
881
|
+
const skipped = [];
|
|
882
|
+
const errors = [];
|
|
883
|
+
for (const skill of skillList) {
|
|
884
|
+
try {
|
|
885
|
+
const srcPath = join5(typeDir, skill);
|
|
886
|
+
if (!fs4.existsSync(srcPath) || !fs4.statSync(srcPath).isDirectory()) {
|
|
887
|
+
skipped.push(skill);
|
|
801
888
|
continue;
|
|
802
889
|
}
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
await fs3.writeFile(destPath, tomlContent, "utf-8");
|
|
806
|
-
} else {
|
|
807
|
-
const destPath = join4(destDir, entry);
|
|
808
|
-
if (mergeMode && fs3.existsSync(destPath)) {
|
|
890
|
+
if (!fs4.existsSync(join5(srcPath, "SKILL.md"))) {
|
|
891
|
+
skipped.push(skill);
|
|
809
892
|
continue;
|
|
810
893
|
}
|
|
811
|
-
|
|
894
|
+
const destPath = join5(destTypeDir, skill);
|
|
895
|
+
if (mergeMode && fs4.existsSync(destPath)) {
|
|
896
|
+
skipped.push(skill);
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
899
|
+
await fs4.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
900
|
+
copied.push(skill);
|
|
901
|
+
} catch (err) {
|
|
902
|
+
errors.push({ item: skill, error: err.message });
|
|
812
903
|
}
|
|
813
904
|
}
|
|
905
|
+
return { copied, skipped, errors };
|
|
906
|
+
}
|
|
907
|
+
// Commands not supported - Codex uses skills instead
|
|
908
|
+
async copyCommands(_items, _sourceDir, _targetDir, _mergeMode) {
|
|
909
|
+
return { copied: [], skipped: [], errors: [] };
|
|
814
910
|
}
|
|
815
911
|
async copyBaseFiles(targetDir, mergeMode) {
|
|
816
912
|
const { CLI_ROOT: CLI_ROOT2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
817
|
-
const
|
|
913
|
+
const codexTemplates = join5(CLI_ROOT2, "templates", "codex");
|
|
818
914
|
const copied = [];
|
|
819
|
-
const
|
|
820
|
-
const
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
915
|
+
const projectRoot = join5(targetDir, "..");
|
|
916
|
+
const codexConfigDir = join5(projectRoot, ".codex");
|
|
917
|
+
await fs4.ensureDir(codexConfigDir);
|
|
918
|
+
const configFiles = ["config.toml", "config.local.toml"];
|
|
919
|
+
for (const file of configFiles) {
|
|
920
|
+
const srcPath = join5(codexTemplates, file);
|
|
921
|
+
const destPath = join5(codexConfigDir, file);
|
|
922
|
+
if (fs4.existsSync(srcPath)) {
|
|
923
|
+
if (!(mergeMode && fs4.existsSync(destPath))) {
|
|
924
|
+
await fs4.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
925
|
+
copied.push(`.codex/${file}`);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
const agentsMdSrc = join5(codexTemplates, "AGENTS.md");
|
|
930
|
+
const agentsMdDest = join5(projectRoot, "AGENTS.md");
|
|
931
|
+
if (fs4.existsSync(agentsMdSrc)) {
|
|
932
|
+
if (!(mergeMode && fs4.existsSync(agentsMdDest))) {
|
|
933
|
+
await fs4.copy(agentsMdSrc, agentsMdDest, { overwrite: !mergeMode });
|
|
934
|
+
copied.push("AGENTS.md");
|
|
825
935
|
}
|
|
826
936
|
}
|
|
827
937
|
return copied;
|
|
@@ -831,9 +941,9 @@ var init_gemini_adapter = __esm({
|
|
|
831
941
|
});
|
|
832
942
|
|
|
833
943
|
// src/targets/discord-adapter.ts
|
|
834
|
-
import
|
|
835
|
-
import { join as
|
|
836
|
-
function
|
|
944
|
+
import fs5 from "fs-extra";
|
|
945
|
+
import { join as join6, dirname as dirname3 } from "path";
|
|
946
|
+
function parseFrontmatter3(content) {
|
|
837
947
|
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
838
948
|
if (!match) {
|
|
839
949
|
return { frontmatter: "", body: content, description: "", argumentHint: "" };
|
|
@@ -850,10 +960,10 @@ function parseFrontmatter2(content) {
|
|
|
850
960
|
};
|
|
851
961
|
}
|
|
852
962
|
function convertAgentToDiscord(mdContent) {
|
|
853
|
-
const { frontmatter, body } =
|
|
963
|
+
const { frontmatter, body } = parseFrontmatter3(mdContent);
|
|
854
964
|
if (!frontmatter) return mdContent;
|
|
855
965
|
let converted = frontmatter;
|
|
856
|
-
for (const [claudeModel, discordModel] of Object.entries(
|
|
966
|
+
for (const [claudeModel, discordModel] of Object.entries(MODEL_MAP3)) {
|
|
857
967
|
const regex = new RegExp(`^model:\\s*${claudeModel}\\s*$`, "m");
|
|
858
968
|
if (discordModel) {
|
|
859
969
|
converted = converted.replace(regex, `model: ${discordModel}`);
|
|
@@ -891,7 +1001,7 @@ function extractKeywords(content, commandName) {
|
|
|
891
1001
|
return Array.from(keywords).slice(0, 10);
|
|
892
1002
|
}
|
|
893
1003
|
function convertCommandToSkill(mdContent, commandName) {
|
|
894
|
-
const { description, argumentHint, body } =
|
|
1004
|
+
const { description, argumentHint, body } = parseFrontmatter3(mdContent);
|
|
895
1005
|
const prompt = body.replace(/\$ARGUMENTS/g, "{{args}}");
|
|
896
1006
|
const keywords = extractKeywords(body, commandName);
|
|
897
1007
|
return `---
|
|
@@ -921,12 +1031,12 @@ ${prompt}
|
|
|
921
1031
|
Provide clear, actionable response based on the workflow above.
|
|
922
1032
|
`;
|
|
923
1033
|
}
|
|
924
|
-
var
|
|
1034
|
+
var MODEL_MAP3, DiscordAdapter;
|
|
925
1035
|
var init_discord_adapter = __esm({
|
|
926
1036
|
"src/targets/discord-adapter.ts"() {
|
|
927
1037
|
"use strict";
|
|
928
1038
|
init_base_adapter();
|
|
929
|
-
|
|
1039
|
+
MODEL_MAP3 = {
|
|
930
1040
|
"opus": "claude-3-opus",
|
|
931
1041
|
"sonnet": "claude-3-sonnet",
|
|
932
1042
|
"haiku": "claude-3-haiku",
|
|
@@ -950,15 +1060,15 @@ var init_discord_adapter = __esm({
|
|
|
950
1060
|
}
|
|
951
1061
|
};
|
|
952
1062
|
async copyAgents(items, sourceDir, targetDir, mergeMode) {
|
|
953
|
-
const typeDir =
|
|
954
|
-
const destTypeDir =
|
|
955
|
-
if (!
|
|
1063
|
+
const typeDir = join6(sourceDir, "agents");
|
|
1064
|
+
const destTypeDir = join6(targetDir, "agents");
|
|
1065
|
+
if (!fs5.existsSync(typeDir)) {
|
|
956
1066
|
return { copied: [], skipped: [], errors: [] };
|
|
957
1067
|
}
|
|
958
|
-
await
|
|
1068
|
+
await fs5.ensureDir(destTypeDir);
|
|
959
1069
|
let agentList;
|
|
960
1070
|
if (items === "all") {
|
|
961
|
-
const entries =
|
|
1071
|
+
const entries = fs5.readdirSync(typeDir);
|
|
962
1072
|
agentList = entries.filter((e) => e.endsWith(".md") && e !== "README.md").map((e) => e.replace(".md", ""));
|
|
963
1073
|
} else {
|
|
964
1074
|
agentList = items;
|
|
@@ -968,19 +1078,19 @@ var init_discord_adapter = __esm({
|
|
|
968
1078
|
const errors = [];
|
|
969
1079
|
for (const agent of agentList) {
|
|
970
1080
|
try {
|
|
971
|
-
const srcPath =
|
|
972
|
-
if (!
|
|
1081
|
+
const srcPath = join6(typeDir, agent + ".md");
|
|
1082
|
+
if (!fs5.existsSync(srcPath)) {
|
|
973
1083
|
skipped.push(agent);
|
|
974
1084
|
continue;
|
|
975
1085
|
}
|
|
976
|
-
const destPath =
|
|
977
|
-
if (mergeMode &&
|
|
1086
|
+
const destPath = join6(destTypeDir, agent + ".md");
|
|
1087
|
+
if (mergeMode && fs5.existsSync(destPath)) {
|
|
978
1088
|
skipped.push(agent);
|
|
979
1089
|
continue;
|
|
980
1090
|
}
|
|
981
|
-
const mdContent =
|
|
1091
|
+
const mdContent = fs5.readFileSync(srcPath, "utf-8");
|
|
982
1092
|
const convertedContent = convertAgentToDiscord(mdContent);
|
|
983
|
-
await
|
|
1093
|
+
await fs5.writeFile(destPath, convertedContent, "utf-8");
|
|
984
1094
|
copied.push(agent);
|
|
985
1095
|
} catch (err) {
|
|
986
1096
|
errors.push({ item: agent, error: err.message });
|
|
@@ -989,18 +1099,18 @@ var init_discord_adapter = __esm({
|
|
|
989
1099
|
return { copied, skipped, errors };
|
|
990
1100
|
}
|
|
991
1101
|
async copySkills(items, sourceDir, targetDir, mergeMode) {
|
|
992
|
-
const typeDir =
|
|
993
|
-
const destTypeDir =
|
|
994
|
-
if (!
|
|
1102
|
+
const typeDir = join6(sourceDir, "skills");
|
|
1103
|
+
const destTypeDir = join6(targetDir, "skills");
|
|
1104
|
+
if (!fs5.existsSync(typeDir)) {
|
|
995
1105
|
return { copied: [], skipped: [], errors: [] };
|
|
996
1106
|
}
|
|
997
|
-
await
|
|
1107
|
+
await fs5.ensureDir(destTypeDir);
|
|
998
1108
|
let skillList;
|
|
999
1109
|
if (items === "all") {
|
|
1000
|
-
const entries =
|
|
1110
|
+
const entries = fs5.readdirSync(typeDir);
|
|
1001
1111
|
skillList = entries.filter((e) => {
|
|
1002
|
-
const fullPath =
|
|
1003
|
-
return
|
|
1112
|
+
const fullPath = join6(typeDir, e);
|
|
1113
|
+
return fs5.statSync(fullPath).isDirectory() && fs5.existsSync(join6(fullPath, "SKILL.md"));
|
|
1004
1114
|
});
|
|
1005
1115
|
} else {
|
|
1006
1116
|
skillList = items;
|
|
@@ -1010,21 +1120,21 @@ var init_discord_adapter = __esm({
|
|
|
1010
1120
|
const errors = [];
|
|
1011
1121
|
for (const skill of skillList) {
|
|
1012
1122
|
try {
|
|
1013
|
-
const srcPath =
|
|
1014
|
-
if (!
|
|
1123
|
+
const srcPath = join6(typeDir, skill);
|
|
1124
|
+
if (!fs5.existsSync(srcPath) || !fs5.statSync(srcPath).isDirectory()) {
|
|
1015
1125
|
skipped.push(skill);
|
|
1016
1126
|
continue;
|
|
1017
1127
|
}
|
|
1018
|
-
if (!
|
|
1128
|
+
if (!fs5.existsSync(join6(srcPath, "SKILL.md"))) {
|
|
1019
1129
|
skipped.push(skill);
|
|
1020
1130
|
continue;
|
|
1021
1131
|
}
|
|
1022
|
-
const destPath =
|
|
1023
|
-
if (mergeMode &&
|
|
1132
|
+
const destPath = join6(destTypeDir, skill);
|
|
1133
|
+
if (mergeMode && fs5.existsSync(destPath)) {
|
|
1024
1134
|
skipped.push(skill);
|
|
1025
1135
|
continue;
|
|
1026
1136
|
}
|
|
1027
|
-
await
|
|
1137
|
+
await fs5.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
1028
1138
|
copied.push(skill);
|
|
1029
1139
|
} catch (err) {
|
|
1030
1140
|
errors.push({ item: skill, error: err.message });
|
|
@@ -1035,21 +1145,21 @@ var init_discord_adapter = __esm({
|
|
|
1035
1145
|
return { copied, skipped, errors };
|
|
1036
1146
|
}
|
|
1037
1147
|
async copyCommands(items, sourceDir, targetDir, mergeMode) {
|
|
1038
|
-
const typeDir =
|
|
1039
|
-
const destTypeDir =
|
|
1040
|
-
const destSkillsDir =
|
|
1041
|
-
if (!
|
|
1148
|
+
const typeDir = join6(sourceDir, "commands");
|
|
1149
|
+
const destTypeDir = join6(targetDir, "commands");
|
|
1150
|
+
const destSkillsDir = join6(targetDir, "skills");
|
|
1151
|
+
if (!fs5.existsSync(typeDir)) {
|
|
1042
1152
|
return { copied: [], skipped: [], errors: [] };
|
|
1043
1153
|
}
|
|
1044
|
-
await
|
|
1045
|
-
await
|
|
1154
|
+
await fs5.ensureDir(destTypeDir);
|
|
1155
|
+
await fs5.ensureDir(destSkillsDir);
|
|
1046
1156
|
let itemList;
|
|
1047
1157
|
if (items === "all") {
|
|
1048
|
-
const entries =
|
|
1158
|
+
const entries = fs5.readdirSync(typeDir);
|
|
1049
1159
|
itemList = entries.filter((e) => e.endsWith(".md") && e !== "README.md").map((e) => e.replace(".md", ""));
|
|
1050
1160
|
const dirs = entries.filter((e) => {
|
|
1051
|
-
const fullPath =
|
|
1052
|
-
return
|
|
1161
|
+
const fullPath = join6(typeDir, e);
|
|
1162
|
+
return fs5.statSync(fullPath).isDirectory();
|
|
1053
1163
|
});
|
|
1054
1164
|
itemList = [.../* @__PURE__ */ new Set([...itemList, ...dirs])];
|
|
1055
1165
|
} else {
|
|
@@ -1061,22 +1171,22 @@ var init_discord_adapter = __esm({
|
|
|
1061
1171
|
const commandsConfig = {};
|
|
1062
1172
|
for (const item of itemList) {
|
|
1063
1173
|
try {
|
|
1064
|
-
const srcPathMd =
|
|
1065
|
-
const srcPathDir =
|
|
1066
|
-
if (
|
|
1067
|
-
const destPath =
|
|
1068
|
-
const skillDir =
|
|
1069
|
-
const skillPath =
|
|
1070
|
-
if (!(mergeMode &&
|
|
1071
|
-
await
|
|
1072
|
-
const mdContent =
|
|
1073
|
-
await
|
|
1074
|
-
if (!(mergeMode &&
|
|
1075
|
-
await
|
|
1174
|
+
const srcPathMd = join6(typeDir, item + ".md");
|
|
1175
|
+
const srcPathDir = join6(typeDir, item);
|
|
1176
|
+
if (fs5.existsSync(srcPathMd) && fs5.statSync(srcPathMd).isFile()) {
|
|
1177
|
+
const destPath = join6(destTypeDir, item + ".md");
|
|
1178
|
+
const skillDir = join6(destSkillsDir, item.replace(/\//g, "-"));
|
|
1179
|
+
const skillPath = join6(skillDir, "SKILL.md");
|
|
1180
|
+
if (!(mergeMode && fs5.existsSync(destPath))) {
|
|
1181
|
+
await fs5.ensureDir(dirname3(destPath));
|
|
1182
|
+
const mdContent = fs5.readFileSync(srcPathMd, "utf-8");
|
|
1183
|
+
await fs5.copy(srcPathMd, destPath, { overwrite: !mergeMode });
|
|
1184
|
+
if (!(mergeMode && fs5.existsSync(skillPath))) {
|
|
1185
|
+
await fs5.ensureDir(skillDir);
|
|
1076
1186
|
const skillContent = convertCommandToSkill(mdContent, item);
|
|
1077
|
-
await
|
|
1187
|
+
await fs5.writeFile(skillPath, skillContent, "utf-8");
|
|
1078
1188
|
}
|
|
1079
|
-
const { description, body } =
|
|
1189
|
+
const { description, body } = parseFrontmatter3(mdContent);
|
|
1080
1190
|
commandsConfig[item] = {
|
|
1081
1191
|
description: description || `Execute ${item} command`,
|
|
1082
1192
|
prompt: body.replace(/\$ARGUMENTS/g, "{{args}}")
|
|
@@ -1086,7 +1196,7 @@ var init_discord_adapter = __esm({
|
|
|
1086
1196
|
skipped.push(item);
|
|
1087
1197
|
}
|
|
1088
1198
|
}
|
|
1089
|
-
if (
|
|
1199
|
+
if (fs5.existsSync(srcPathDir) && fs5.statSync(srcPathDir).isDirectory()) {
|
|
1090
1200
|
await this.copyNestedCommands(srcPathDir, destTypeDir, destSkillsDir, item, mergeMode, commandsConfig);
|
|
1091
1201
|
copied.push(item + "/*");
|
|
1092
1202
|
}
|
|
@@ -1094,20 +1204,20 @@ var init_discord_adapter = __esm({
|
|
|
1094
1204
|
errors.push({ item, error: err.message });
|
|
1095
1205
|
}
|
|
1096
1206
|
}
|
|
1097
|
-
const configPath =
|
|
1098
|
-
if (Object.keys(commandsConfig).length > 0 && !(mergeMode &&
|
|
1207
|
+
const configPath = join6(targetDir, "commands.json5");
|
|
1208
|
+
if (Object.keys(commandsConfig).length > 0 && !(mergeMode && fs5.existsSync(configPath))) {
|
|
1099
1209
|
const json5Content = this.generateCommandsJson5(commandsConfig);
|
|
1100
|
-
await
|
|
1210
|
+
await fs5.writeFile(configPath, json5Content, "utf-8");
|
|
1101
1211
|
}
|
|
1102
1212
|
return { copied, skipped, errors };
|
|
1103
1213
|
}
|
|
1104
1214
|
async copyNestedCommands(srcDir, destDir, destSkillsDir, parentName, mergeMode, commandsConfig) {
|
|
1105
|
-
const destTypeDir =
|
|
1106
|
-
await
|
|
1107
|
-
const entries =
|
|
1215
|
+
const destTypeDir = join6(destDir, parentName);
|
|
1216
|
+
await fs5.ensureDir(destTypeDir);
|
|
1217
|
+
const entries = fs5.readdirSync(srcDir);
|
|
1108
1218
|
for (const entry of entries) {
|
|
1109
|
-
const srcPath =
|
|
1110
|
-
const stat =
|
|
1219
|
+
const srcPath = join6(srcDir, entry);
|
|
1220
|
+
const stat = fs5.statSync(srcPath);
|
|
1111
1221
|
if (stat.isDirectory()) {
|
|
1112
1222
|
await this.copyNestedCommands(
|
|
1113
1223
|
srcPath,
|
|
@@ -1118,22 +1228,22 @@ var init_discord_adapter = __esm({
|
|
|
1118
1228
|
commandsConfig
|
|
1119
1229
|
);
|
|
1120
1230
|
} else if (entry.endsWith(".md") && entry !== "README.md") {
|
|
1121
|
-
const destPath =
|
|
1231
|
+
const destPath = join6(destTypeDir, entry);
|
|
1122
1232
|
const cmdName = `${parentName}/${entry.replace(".md", "")}`;
|
|
1123
1233
|
const skillName = cmdName.replace(/\//g, "-");
|
|
1124
|
-
const skillDir =
|
|
1125
|
-
const skillPath =
|
|
1126
|
-
if (mergeMode &&
|
|
1234
|
+
const skillDir = join6(destSkillsDir, skillName);
|
|
1235
|
+
const skillPath = join6(skillDir, "SKILL.md");
|
|
1236
|
+
if (mergeMode && fs5.existsSync(destPath)) {
|
|
1127
1237
|
continue;
|
|
1128
1238
|
}
|
|
1129
|
-
const mdContent =
|
|
1130
|
-
await
|
|
1131
|
-
if (!(mergeMode &&
|
|
1132
|
-
await
|
|
1239
|
+
const mdContent = fs5.readFileSync(srcPath, "utf-8");
|
|
1240
|
+
await fs5.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
1241
|
+
if (!(mergeMode && fs5.existsSync(skillPath))) {
|
|
1242
|
+
await fs5.ensureDir(skillDir);
|
|
1133
1243
|
const skillContent = convertCommandToSkill(mdContent, skillName);
|
|
1134
|
-
await
|
|
1244
|
+
await fs5.writeFile(skillPath, skillContent, "utf-8");
|
|
1135
1245
|
}
|
|
1136
|
-
const { description, body } =
|
|
1246
|
+
const { description, body } = parseFrontmatter3(mdContent);
|
|
1137
1247
|
commandsConfig[cmdName] = {
|
|
1138
1248
|
description: description || `Execute ${cmdName} command`,
|
|
1139
1249
|
prompt: body.replace(/\$ARGUMENTS/g, "{{args}}")
|
|
@@ -1163,22 +1273,22 @@ var init_discord_adapter = __esm({
|
|
|
1163
1273
|
}
|
|
1164
1274
|
async copyBundledSkills(targetDir, mergeMode) {
|
|
1165
1275
|
const { CLI_ROOT: CLI_ROOT2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
1166
|
-
const bundledSkillsDir =
|
|
1167
|
-
const destSkillsDir =
|
|
1276
|
+
const bundledSkillsDir = join6(CLI_ROOT2, "templates", "discord", "skills");
|
|
1277
|
+
const destSkillsDir = join6(targetDir, "skills");
|
|
1168
1278
|
const copied = [];
|
|
1169
|
-
if (!
|
|
1279
|
+
if (!fs5.existsSync(bundledSkillsDir)) {
|
|
1170
1280
|
return copied;
|
|
1171
1281
|
}
|
|
1172
|
-
await
|
|
1173
|
-
const skills =
|
|
1282
|
+
await fs5.ensureDir(destSkillsDir);
|
|
1283
|
+
const skills = fs5.readdirSync(bundledSkillsDir);
|
|
1174
1284
|
for (const skill of skills) {
|
|
1175
|
-
const srcPath =
|
|
1176
|
-
const destPath =
|
|
1177
|
-
if (
|
|
1178
|
-
if (mergeMode &&
|
|
1285
|
+
const srcPath = join6(bundledSkillsDir, skill);
|
|
1286
|
+
const destPath = join6(destSkillsDir, skill);
|
|
1287
|
+
if (fs5.statSync(srcPath).isDirectory()) {
|
|
1288
|
+
if (mergeMode && fs5.existsSync(destPath)) {
|
|
1179
1289
|
continue;
|
|
1180
1290
|
}
|
|
1181
|
-
await
|
|
1291
|
+
await fs5.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
1182
1292
|
copied.push(`bundled:${skill}`);
|
|
1183
1293
|
}
|
|
1184
1294
|
}
|
|
@@ -1186,17 +1296,17 @@ var init_discord_adapter = __esm({
|
|
|
1186
1296
|
}
|
|
1187
1297
|
async copyBaseFiles(targetDir, mergeMode) {
|
|
1188
1298
|
const { CLI_ROOT: CLI_ROOT2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
1189
|
-
const discordTemplates =
|
|
1299
|
+
const discordTemplates = join6(CLI_ROOT2, "templates", "discord");
|
|
1190
1300
|
const copied = [];
|
|
1191
1301
|
const filesToCopy = ["config.json5", "README.md"];
|
|
1192
1302
|
for (const file of filesToCopy) {
|
|
1193
|
-
const srcPath =
|
|
1194
|
-
const destPath =
|
|
1195
|
-
if (
|
|
1196
|
-
if (mergeMode &&
|
|
1303
|
+
const srcPath = join6(discordTemplates, file);
|
|
1304
|
+
const destPath = join6(targetDir, file);
|
|
1305
|
+
if (fs5.existsSync(srcPath)) {
|
|
1306
|
+
if (mergeMode && fs5.existsSync(destPath)) {
|
|
1197
1307
|
continue;
|
|
1198
1308
|
}
|
|
1199
|
-
await
|
|
1309
|
+
await fs5.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
1200
1310
|
copied.push(file);
|
|
1201
1311
|
}
|
|
1202
1312
|
}
|
|
@@ -1206,11 +1316,11 @@ var init_discord_adapter = __esm({
|
|
|
1206
1316
|
* Update Discord config with bot token
|
|
1207
1317
|
*/
|
|
1208
1318
|
async updateConfig(targetDir, token, guildId) {
|
|
1209
|
-
const configPath =
|
|
1210
|
-
if (!
|
|
1319
|
+
const configPath = join6(targetDir, "config.json5");
|
|
1320
|
+
if (!fs5.existsSync(configPath)) {
|
|
1211
1321
|
return;
|
|
1212
1322
|
}
|
|
1213
|
-
let content = await
|
|
1323
|
+
let content = await fs5.readFile(configPath, "utf-8");
|
|
1214
1324
|
content = content.replace(
|
|
1215
1325
|
'"token": "${DISCORD_BOT_TOKEN}"',
|
|
1216
1326
|
`"token": "${token}"`
|
|
@@ -1229,7 +1339,7 @@ var init_discord_adapter = __esm({
|
|
|
1229
1339
|
// Example guild configuration`
|
|
1230
1340
|
);
|
|
1231
1341
|
}
|
|
1232
|
-
await
|
|
1342
|
+
await fs5.writeFile(configPath, content, "utf-8");
|
|
1233
1343
|
}
|
|
1234
1344
|
/**
|
|
1235
1345
|
* Setup OpenClaw CLI configuration
|
|
@@ -1277,13 +1387,16 @@ var init_targets = __esm({
|
|
|
1277
1387
|
"use strict";
|
|
1278
1388
|
init_claude_adapter();
|
|
1279
1389
|
init_gemini_adapter();
|
|
1390
|
+
init_codex_adapter();
|
|
1280
1391
|
init_discord_adapter();
|
|
1281
1392
|
init_claude_adapter();
|
|
1282
1393
|
init_gemini_adapter();
|
|
1394
|
+
init_codex_adapter();
|
|
1283
1395
|
init_discord_adapter();
|
|
1284
1396
|
adapters = {
|
|
1285
1397
|
claude: new ClaudeAdapter(),
|
|
1286
1398
|
gemini: new GeminiAdapter(),
|
|
1399
|
+
codex: new CodexAdapter(),
|
|
1287
1400
|
discord: new DiscordAdapter()
|
|
1288
1401
|
};
|
|
1289
1402
|
}
|
|
@@ -1291,23 +1404,23 @@ var init_targets = __esm({
|
|
|
1291
1404
|
|
|
1292
1405
|
// src/utils/hash.ts
|
|
1293
1406
|
import { createHash } from "crypto";
|
|
1294
|
-
import
|
|
1295
|
-
import { join as
|
|
1407
|
+
import fs6 from "fs-extra";
|
|
1408
|
+
import { join as join7, relative } from "path";
|
|
1296
1409
|
function hashFile(filePath) {
|
|
1297
|
-
if (!
|
|
1410
|
+
if (!fs6.existsSync(filePath)) {
|
|
1298
1411
|
return null;
|
|
1299
1412
|
}
|
|
1300
|
-
const content =
|
|
1413
|
+
const content = fs6.readFileSync(filePath);
|
|
1301
1414
|
return createHash("md5").update(content).digest("hex");
|
|
1302
1415
|
}
|
|
1303
1416
|
async function hashDirectory(dirPath, baseDir = dirPath) {
|
|
1304
1417
|
const hashes = {};
|
|
1305
|
-
if (!
|
|
1418
|
+
if (!fs6.existsSync(dirPath)) {
|
|
1306
1419
|
return hashes;
|
|
1307
1420
|
}
|
|
1308
|
-
const items = await
|
|
1421
|
+
const items = await fs6.readdir(dirPath, { withFileTypes: true });
|
|
1309
1422
|
for (const item of items) {
|
|
1310
|
-
const itemPath =
|
|
1423
|
+
const itemPath = join7(dirPath, item.name);
|
|
1311
1424
|
const relativePath = relative(baseDir, itemPath);
|
|
1312
1425
|
if (item.isDirectory()) {
|
|
1313
1426
|
const subHashes = await hashDirectory(itemPath, baseDir);
|
|
@@ -1328,27 +1441,27 @@ var init_hash = __esm({
|
|
|
1328
1441
|
});
|
|
1329
1442
|
|
|
1330
1443
|
// src/utils/state.ts
|
|
1331
|
-
import
|
|
1332
|
-
import { join as
|
|
1444
|
+
import fs7 from "fs-extra";
|
|
1445
|
+
import { join as join8 } from "path";
|
|
1333
1446
|
function getStatePath(projectDir) {
|
|
1334
|
-
return
|
|
1447
|
+
return join8(projectDir, STATE_DIR, STATE_FILE);
|
|
1335
1448
|
}
|
|
1336
1449
|
async function loadState(projectDir) {
|
|
1337
1450
|
const statePath = getStatePath(projectDir);
|
|
1338
|
-
if (!
|
|
1451
|
+
if (!fs7.existsSync(statePath)) {
|
|
1339
1452
|
return null;
|
|
1340
1453
|
}
|
|
1341
1454
|
try {
|
|
1342
|
-
return await
|
|
1455
|
+
return await fs7.readJson(statePath);
|
|
1343
1456
|
} catch {
|
|
1344
1457
|
return null;
|
|
1345
1458
|
}
|
|
1346
1459
|
}
|
|
1347
1460
|
async function saveState(projectDir, state) {
|
|
1348
|
-
const stateDir =
|
|
1349
|
-
const statePath =
|
|
1350
|
-
await
|
|
1351
|
-
await
|
|
1461
|
+
const stateDir = join8(projectDir, STATE_DIR);
|
|
1462
|
+
const statePath = join8(stateDir, STATE_FILE);
|
|
1463
|
+
await fs7.ensureDir(stateDir);
|
|
1464
|
+
await fs7.writeJson(statePath, state, { spaces: 2 });
|
|
1352
1465
|
}
|
|
1353
1466
|
async function createInitialState(projectDir, options) {
|
|
1354
1467
|
const { kit, source, target, targets, installed } = options;
|
|
@@ -1356,8 +1469,8 @@ async function createInitialState(projectDir, options) {
|
|
|
1356
1469
|
const targetList = targets || [target.replace(".", "")];
|
|
1357
1470
|
for (const t of targetList) {
|
|
1358
1471
|
const targetDirName = t.startsWith(".") ? t : `.${t}`;
|
|
1359
|
-
const targetDir =
|
|
1360
|
-
if (
|
|
1472
|
+
const targetDir = join8(projectDir, targetDirName);
|
|
1473
|
+
if (fs7.existsSync(targetDir)) {
|
|
1361
1474
|
const hashes = await hashDirectory(targetDir);
|
|
1362
1475
|
for (const [path, hash] of Object.entries(hashes)) {
|
|
1363
1476
|
allHashes[`${targetDirName}/${path}`] = hash;
|
|
@@ -1383,7 +1496,7 @@ async function updateState(projectDir, updates) {
|
|
|
1383
1496
|
if (!state) {
|
|
1384
1497
|
throw new Error("No state found. Is this an ak project?");
|
|
1385
1498
|
}
|
|
1386
|
-
const targetDir =
|
|
1499
|
+
const targetDir = join8(projectDir, state.target || ".claude");
|
|
1387
1500
|
const newHashes = await hashDirectory(targetDir);
|
|
1388
1501
|
const updatedState = {
|
|
1389
1502
|
...state,
|
|
@@ -1399,7 +1512,7 @@ async function getFileStatuses(projectDir) {
|
|
|
1399
1512
|
if (!state) {
|
|
1400
1513
|
return { error: "No state found" };
|
|
1401
1514
|
}
|
|
1402
|
-
const targetDir =
|
|
1515
|
+
const targetDir = join8(projectDir, state.target || ".claude");
|
|
1403
1516
|
const currentHashes = await hashDirectory(targetDir);
|
|
1404
1517
|
const originalHashes = state.originalHashes || {};
|
|
1405
1518
|
const statuses = {
|
|
@@ -1439,38 +1552,38 @@ var init_state = __esm({
|
|
|
1439
1552
|
});
|
|
1440
1553
|
|
|
1441
1554
|
// src/utils/copy.ts
|
|
1442
|
-
import
|
|
1443
|
-
import { join as
|
|
1555
|
+
import fs8 from "fs-extra";
|
|
1556
|
+
import { join as join9, dirname as dirname4 } from "path";
|
|
1444
1557
|
async function copyItems(items, type, sourceDir, destDir, mergeMode = false) {
|
|
1445
|
-
const typeDir =
|
|
1446
|
-
const destTypeDir =
|
|
1447
|
-
if (!
|
|
1558
|
+
const typeDir = join9(sourceDir, type);
|
|
1559
|
+
const destTypeDir = join9(destDir, type);
|
|
1560
|
+
if (!fs8.existsSync(typeDir)) {
|
|
1448
1561
|
return { copied: [], skipped: items, errors: [] };
|
|
1449
1562
|
}
|
|
1450
|
-
await
|
|
1563
|
+
await fs8.ensureDir(destTypeDir);
|
|
1451
1564
|
const copied = [];
|
|
1452
1565
|
const skipped = [];
|
|
1453
1566
|
const errors = [];
|
|
1454
1567
|
for (const item of items) {
|
|
1455
1568
|
try {
|
|
1456
|
-
const itemPath =
|
|
1569
|
+
const itemPath = join9(typeDir, item);
|
|
1457
1570
|
const itemPathMd = itemPath + ".md";
|
|
1458
1571
|
let srcPath;
|
|
1459
|
-
if (
|
|
1572
|
+
if (fs8.existsSync(itemPath)) {
|
|
1460
1573
|
srcPath = itemPath;
|
|
1461
|
-
} else if (
|
|
1574
|
+
} else if (fs8.existsSync(itemPathMd)) {
|
|
1462
1575
|
srcPath = itemPathMd;
|
|
1463
1576
|
} else {
|
|
1464
1577
|
skipped.push(item);
|
|
1465
1578
|
continue;
|
|
1466
1579
|
}
|
|
1467
|
-
const stat =
|
|
1580
|
+
const stat = fs8.statSync(srcPath);
|
|
1468
1581
|
if (stat.isDirectory()) {
|
|
1469
|
-
await
|
|
1582
|
+
await fs8.copy(srcPath, join9(destTypeDir, item), { overwrite: !mergeMode });
|
|
1470
1583
|
} else {
|
|
1471
|
-
const destPath = srcPath.endsWith(".md") ?
|
|
1472
|
-
await
|
|
1473
|
-
await
|
|
1584
|
+
const destPath = srcPath.endsWith(".md") ? join9(destTypeDir, item + ".md") : join9(destTypeDir, item);
|
|
1585
|
+
await fs8.ensureDir(join9(destTypeDir, item.split("/").slice(0, -1).join("/")));
|
|
1586
|
+
await fs8.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
1474
1587
|
}
|
|
1475
1588
|
copied.push(item);
|
|
1476
1589
|
} catch (err) {
|
|
@@ -1480,25 +1593,25 @@ async function copyItems(items, type, sourceDir, destDir, mergeMode = false) {
|
|
|
1480
1593
|
return { copied, skipped, errors };
|
|
1481
1594
|
}
|
|
1482
1595
|
async function copyAgentsMd(agentsMdPath, projectDir, mergeMode = false) {
|
|
1483
|
-
if (!agentsMdPath || !
|
|
1596
|
+
if (!agentsMdPath || !fs8.existsSync(agentsMdPath)) {
|
|
1484
1597
|
return false;
|
|
1485
1598
|
}
|
|
1486
|
-
const destPath =
|
|
1487
|
-
if (mergeMode &&
|
|
1599
|
+
const destPath = join9(projectDir, "AGENTS.md");
|
|
1600
|
+
if (mergeMode && fs8.existsSync(destPath)) {
|
|
1488
1601
|
return false;
|
|
1489
1602
|
}
|
|
1490
|
-
await
|
|
1603
|
+
await fs8.copy(agentsMdPath, destPath, { overwrite: !mergeMode });
|
|
1491
1604
|
return true;
|
|
1492
1605
|
}
|
|
1493
1606
|
function listAvailable(type, sourceDir) {
|
|
1494
|
-
const typeDir =
|
|
1495
|
-
if (!
|
|
1607
|
+
const typeDir = join9(sourceDir, type);
|
|
1608
|
+
if (!fs8.existsSync(typeDir)) {
|
|
1496
1609
|
return [];
|
|
1497
1610
|
}
|
|
1498
|
-
const items =
|
|
1611
|
+
const items = fs8.readdirSync(typeDir);
|
|
1499
1612
|
return items.map((item) => {
|
|
1500
|
-
const itemPath =
|
|
1501
|
-
const isDir =
|
|
1613
|
+
const itemPath = join9(typeDir, item);
|
|
1614
|
+
const isDir = fs8.statSync(itemPath).isDirectory();
|
|
1502
1615
|
const name = item.replace(/\.md$/, "");
|
|
1503
1616
|
return { name, isDir, path: itemPath };
|
|
1504
1617
|
});
|
|
@@ -1533,6 +1646,7 @@ async function promptCliTargets() {
|
|
|
1533
1646
|
options: [
|
|
1534
1647
|
{ value: "claude", label: "Claude Code", hint: ".claude/" },
|
|
1535
1648
|
{ value: "gemini", label: "Gemini CLI", hint: ".gemini/" },
|
|
1649
|
+
{ value: "codex", label: "Codex CLI", hint: ".agents/ + .codex/" },
|
|
1536
1650
|
{ value: "discord", label: "Discord + Clawbot", hint: ".discord/" }
|
|
1537
1651
|
],
|
|
1538
1652
|
initialValues: ["claude"],
|
|
@@ -1648,10 +1762,10 @@ function isGeminiCliInstalled() {
|
|
|
1648
1762
|
}
|
|
1649
1763
|
function isGeminiCliLoggedIn() {
|
|
1650
1764
|
try {
|
|
1651
|
-
const
|
|
1765
|
+
const fs16 = __require("fs");
|
|
1652
1766
|
const path = __require("path");
|
|
1653
1767
|
const credsPath = path.join(process.env.HOME || "", ".gemini", "oauth_creds.json");
|
|
1654
|
-
return
|
|
1768
|
+
return fs16.existsSync(credsPath);
|
|
1655
1769
|
} catch {
|
|
1656
1770
|
return false;
|
|
1657
1771
|
}
|
|
@@ -1890,8 +2004,8 @@ var init_exports = {};
|
|
|
1890
2004
|
__export(init_exports, {
|
|
1891
2005
|
initCommand: () => initCommand
|
|
1892
2006
|
});
|
|
1893
|
-
import
|
|
1894
|
-
import { join as
|
|
2007
|
+
import fs9 from "fs-extra";
|
|
2008
|
+
import { join as join10, resolve as resolve2 } from "path";
|
|
1895
2009
|
import pc2 from "picocolors";
|
|
1896
2010
|
import ora from "ora";
|
|
1897
2011
|
function filterComponents(list, exclude, only) {
|
|
@@ -1965,18 +2079,18 @@ async function initCommand(projectName, options) {
|
|
|
1965
2079
|
let existingAction = null;
|
|
1966
2080
|
const existingTargets = [];
|
|
1967
2081
|
for (const target of cliTargets) {
|
|
1968
|
-
const targetDir =
|
|
1969
|
-
if (options.fresh &&
|
|
1970
|
-
await
|
|
2082
|
+
const targetDir = join10(projectDir, getTargetDirectory(target));
|
|
2083
|
+
if (options.fresh && fs9.existsSync(targetDir)) {
|
|
2084
|
+
await fs9.remove(targetDir);
|
|
1971
2085
|
existingTargets.push(getTargetDisplayName(target));
|
|
1972
|
-
} else if (
|
|
2086
|
+
} else if (fs9.existsSync(targetDir) && !options.force) {
|
|
1973
2087
|
existingTargets.push(getTargetDisplayName(target));
|
|
1974
2088
|
}
|
|
1975
2089
|
}
|
|
1976
2090
|
if (options.fresh && existingTargets.length > 0) {
|
|
1977
|
-
const akDir =
|
|
1978
|
-
if (
|
|
1979
|
-
await
|
|
2091
|
+
const akDir = join10(projectDir, ".ak");
|
|
2092
|
+
if (fs9.existsSync(akDir)) {
|
|
2093
|
+
await fs9.remove(akDir);
|
|
1980
2094
|
}
|
|
1981
2095
|
console.log(pc2.cyan(`Fresh install: removed existing files (${existingTargets.join(", ")})`));
|
|
1982
2096
|
existingAction = null;
|
|
@@ -1996,8 +2110,8 @@ async function initCommand(projectName, options) {
|
|
|
1996
2110
|
}
|
|
1997
2111
|
}
|
|
1998
2112
|
}
|
|
1999
|
-
if (!isCurrentDir &&
|
|
2000
|
-
const files =
|
|
2113
|
+
if (!isCurrentDir && fs9.existsSync(projectDir) && !options.force) {
|
|
2114
|
+
const files = fs9.readdirSync(projectDir);
|
|
2001
2115
|
if (files.length > 0 && !existingAction) {
|
|
2002
2116
|
console.log(pc2.red(`Directory "${projectName}" already exists and is not empty.`));
|
|
2003
2117
|
console.log(pc2.gray("Use --force to overwrite."));
|
|
@@ -2078,22 +2192,22 @@ async function initCommand(projectName, options) {
|
|
|
2078
2192
|
}
|
|
2079
2193
|
const spinner = ora("Creating project...").start();
|
|
2080
2194
|
try {
|
|
2081
|
-
await
|
|
2195
|
+
await fs9.ensureDir(projectDir);
|
|
2082
2196
|
for (const target of cliTargets) {
|
|
2083
2197
|
const adapter = getAdapter(target);
|
|
2084
|
-
const targetDir =
|
|
2085
|
-
await
|
|
2198
|
+
const targetDir = join10(projectDir, adapter.config.directory);
|
|
2199
|
+
await fs9.ensureDir(targetDir);
|
|
2086
2200
|
const targetLabel = adapter.config.displayName;
|
|
2087
2201
|
if (kitName === "full" && target === "claude") {
|
|
2088
2202
|
spinner.text = mergeMode ? `Merging full kit (${targetLabel})...` : `Copying full kit (${targetLabel})...`;
|
|
2089
|
-
const items = await
|
|
2203
|
+
const items = await fs9.readdir(source.claudeDir);
|
|
2090
2204
|
for (const item of items) {
|
|
2091
|
-
const srcPath =
|
|
2092
|
-
const destPath =
|
|
2093
|
-
if (mergeMode && await
|
|
2205
|
+
const srcPath = join10(source.claudeDir, item);
|
|
2206
|
+
const destPath = join10(targetDir, item);
|
|
2207
|
+
if (mergeMode && await fs9.pathExists(destPath)) {
|
|
2094
2208
|
continue;
|
|
2095
2209
|
}
|
|
2096
|
-
await
|
|
2210
|
+
await fs9.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
2097
2211
|
}
|
|
2098
2212
|
continue;
|
|
2099
2213
|
}
|
|
@@ -2218,8 +2332,8 @@ var add_exports = {};
|
|
|
2218
2332
|
__export(add_exports, {
|
|
2219
2333
|
addCommand: () => addCommand
|
|
2220
2334
|
});
|
|
2221
|
-
import
|
|
2222
|
-
import { join as
|
|
2335
|
+
import fs10 from "fs-extra";
|
|
2336
|
+
import { join as join11 } from "path";
|
|
2223
2337
|
import pc3 from "picocolors";
|
|
2224
2338
|
import ora2 from "ora";
|
|
2225
2339
|
async function addCommand(item, options = {}) {
|
|
@@ -2274,10 +2388,10 @@ async function addCommand(item, options = {}) {
|
|
|
2274
2388
|
return;
|
|
2275
2389
|
}
|
|
2276
2390
|
const targetFolder = state?.target || ".claude";
|
|
2277
|
-
const targetDir =
|
|
2278
|
-
const destPath =
|
|
2391
|
+
const targetDir = join11(projectDir, targetFolder);
|
|
2392
|
+
const destPath = join11(targetDir, normalizedType, name);
|
|
2279
2393
|
const destPathMd = destPath + ".md";
|
|
2280
|
-
if (
|
|
2394
|
+
if (fs10.existsSync(destPath) || fs10.existsSync(destPathMd)) {
|
|
2281
2395
|
console.log(pc3.yellow(`${type} "${name}" already exists in project.`));
|
|
2282
2396
|
console.log(pc3.gray('Use "tk update" to refresh from source.'));
|
|
2283
2397
|
return;
|
|
@@ -2493,8 +2607,8 @@ var update_exports = {};
|
|
|
2493
2607
|
__export(update_exports, {
|
|
2494
2608
|
updateCommand: () => updateCommand
|
|
2495
2609
|
});
|
|
2496
|
-
import
|
|
2497
|
-
import { join as
|
|
2610
|
+
import fs11 from "fs-extra";
|
|
2611
|
+
import { join as join12 } from "path";
|
|
2498
2612
|
import pc5 from "picocolors";
|
|
2499
2613
|
import ora3 from "ora";
|
|
2500
2614
|
async function updateCommand(options = {}) {
|
|
@@ -2533,8 +2647,8 @@ async function updateCommand(options = {}) {
|
|
|
2533
2647
|
if (options.commands) typesToUpdate = ["commands"];
|
|
2534
2648
|
const sourceHashes = {};
|
|
2535
2649
|
for (const type of typesToUpdate) {
|
|
2536
|
-
const typeDir =
|
|
2537
|
-
if (
|
|
2650
|
+
const typeDir = join12(source.claudeDir, type);
|
|
2651
|
+
if (fs11.existsSync(typeDir)) {
|
|
2538
2652
|
const hashes = await hashDirectory(typeDir);
|
|
2539
2653
|
for (const [path, hash] of Object.entries(hashes)) {
|
|
2540
2654
|
sourceHashes[`${type}/${path}`] = hash;
|
|
@@ -2545,9 +2659,9 @@ async function updateCommand(options = {}) {
|
|
|
2545
2659
|
const skipped = [];
|
|
2546
2660
|
const newFiles = [];
|
|
2547
2661
|
for (const [path, sourceHash] of Object.entries(sourceHashes)) {
|
|
2548
|
-
const currentPath =
|
|
2662
|
+
const currentPath = join12(targetDir, path);
|
|
2549
2663
|
const originalHash = state.originalHashes?.[path];
|
|
2550
|
-
const currentHash =
|
|
2664
|
+
const currentHash = fs11.existsSync(currentPath) ? hashFile(currentPath) : null;
|
|
2551
2665
|
if (!currentHash) {
|
|
2552
2666
|
newFiles.push(path);
|
|
2553
2667
|
} else if (currentHash === originalHash) {
|
|
@@ -2600,10 +2714,10 @@ async function updateCommand(options = {}) {
|
|
|
2600
2714
|
let failed = 0;
|
|
2601
2715
|
for (const path of [...toUpdate, ...newFiles]) {
|
|
2602
2716
|
try {
|
|
2603
|
-
const srcPath =
|
|
2604
|
-
const destPath =
|
|
2605
|
-
await
|
|
2606
|
-
await
|
|
2717
|
+
const srcPath = join12(source.claudeDir, path);
|
|
2718
|
+
const destPath = join12(targetDir, path);
|
|
2719
|
+
await fs11.ensureDir(join12(targetDir, path.split("/").slice(0, -1).join("/")));
|
|
2720
|
+
await fs11.copy(srcPath, destPath, { overwrite: true });
|
|
2607
2721
|
updated++;
|
|
2608
2722
|
} catch (err) {
|
|
2609
2723
|
failed++;
|
|
@@ -2653,7 +2767,7 @@ __export(status_exports, {
|
|
|
2653
2767
|
statusCommand: () => statusCommand
|
|
2654
2768
|
});
|
|
2655
2769
|
import pc6 from "picocolors";
|
|
2656
|
-
import
|
|
2770
|
+
import fs12 from "fs-extra";
|
|
2657
2771
|
async function statusCommand(options = {}) {
|
|
2658
2772
|
const projectDir = process.cwd();
|
|
2659
2773
|
if (!isAkProject(projectDir)) {
|
|
@@ -2734,7 +2848,7 @@ async function statusCommand(options = {}) {
|
|
|
2734
2848
|
if (hooks) console.log(pc6.gray(" Hooks: \u2713"));
|
|
2735
2849
|
console.log("");
|
|
2736
2850
|
}
|
|
2737
|
-
if (state.source && !
|
|
2851
|
+
if (state.source && !fs12.existsSync(state.source)) {
|
|
2738
2852
|
console.log(pc6.yellow("\u26A0 Source directory not found. Update may not work."));
|
|
2739
2853
|
console.log(pc6.gray(` Expected: ${state.source}`));
|
|
2740
2854
|
console.log("");
|
|
@@ -2753,15 +2867,15 @@ var doctor_exports = {};
|
|
|
2753
2867
|
__export(doctor_exports, {
|
|
2754
2868
|
doctorCommand: () => doctorCommand
|
|
2755
2869
|
});
|
|
2756
|
-
import
|
|
2757
|
-
import { join as
|
|
2870
|
+
import fs13 from "fs-extra";
|
|
2871
|
+
import { join as join13 } from "path";
|
|
2758
2872
|
import pc7 from "picocolors";
|
|
2759
2873
|
async function doctorCommand(options = {}) {
|
|
2760
2874
|
const projectDir = process.cwd();
|
|
2761
2875
|
let targetDir = null;
|
|
2762
2876
|
for (const [name, folder] of Object.entries(TARGETS)) {
|
|
2763
|
-
const dir =
|
|
2764
|
-
if (
|
|
2877
|
+
const dir = join13(projectDir, folder);
|
|
2878
|
+
if (fs13.existsSync(dir)) {
|
|
2765
2879
|
targetDir = { name, folder, dir };
|
|
2766
2880
|
break;
|
|
2767
2881
|
}
|
|
@@ -2774,7 +2888,7 @@ async function doctorCommand(options = {}) {
|
|
|
2774
2888
|
severity: "error",
|
|
2775
2889
|
check: () => isAkProject(projectDir),
|
|
2776
2890
|
fix: async () => {
|
|
2777
|
-
await
|
|
2891
|
+
await fs13.ensureDir(join13(projectDir, ".ak"));
|
|
2778
2892
|
}
|
|
2779
2893
|
},
|
|
2780
2894
|
{
|
|
@@ -2790,9 +2904,9 @@ async function doctorCommand(options = {}) {
|
|
|
2790
2904
|
if (targetDir) {
|
|
2791
2905
|
const dirs = ["agents", "skills", "commands", "workflows"];
|
|
2792
2906
|
for (const dir of dirs) {
|
|
2793
|
-
const fullPath =
|
|
2794
|
-
if (
|
|
2795
|
-
const items =
|
|
2907
|
+
const fullPath = join13(targetDir.dir, dir);
|
|
2908
|
+
if (fs13.existsSync(fullPath)) {
|
|
2909
|
+
const items = fs13.readdirSync(fullPath).filter((f) => !f.startsWith("."));
|
|
2796
2910
|
if (items.length > 0) {
|
|
2797
2911
|
installed[dir] = items;
|
|
2798
2912
|
}
|
|
@@ -2814,7 +2928,7 @@ async function doctorCommand(options = {}) {
|
|
|
2814
2928
|
name: "agents_md",
|
|
2815
2929
|
label: "AGENTS.md exists",
|
|
2816
2930
|
severity: "warning",
|
|
2817
|
-
check: () =>
|
|
2931
|
+
check: () => fs13.existsSync(join13(projectDir, "AGENTS.md"))
|
|
2818
2932
|
},
|
|
2819
2933
|
{
|
|
2820
2934
|
name: "source",
|
|
@@ -2822,7 +2936,7 @@ async function doctorCommand(options = {}) {
|
|
|
2822
2936
|
severity: "error",
|
|
2823
2937
|
check: () => {
|
|
2824
2938
|
if (!state || !state.source) return true;
|
|
2825
|
-
return
|
|
2939
|
+
return fs13.existsSync(state.source);
|
|
2826
2940
|
},
|
|
2827
2941
|
getMeta: () => state && state.source ? { source: state.source } : {}
|
|
2828
2942
|
},
|
|
@@ -2832,18 +2946,18 @@ async function doctorCommand(options = {}) {
|
|
|
2832
2946
|
severity: "warning",
|
|
2833
2947
|
check: () => {
|
|
2834
2948
|
if (!targetDir) return false;
|
|
2835
|
-
return
|
|
2949
|
+
return fs13.existsSync(join13(targetDir.dir, "agents"));
|
|
2836
2950
|
},
|
|
2837
2951
|
fix: async () => {
|
|
2838
2952
|
if (targetDir) {
|
|
2839
|
-
await
|
|
2953
|
+
await fs13.ensureDir(join13(targetDir.dir, "agents"));
|
|
2840
2954
|
}
|
|
2841
2955
|
},
|
|
2842
2956
|
getMeta: () => {
|
|
2843
2957
|
if (!targetDir) return {};
|
|
2844
|
-
const fullPath =
|
|
2845
|
-
if (
|
|
2846
|
-
const items =
|
|
2958
|
+
const fullPath = join13(targetDir.dir, "agents");
|
|
2959
|
+
if (fs13.existsSync(fullPath)) {
|
|
2960
|
+
const items = fs13.readdirSync(fullPath).length;
|
|
2847
2961
|
return { items };
|
|
2848
2962
|
}
|
|
2849
2963
|
return {};
|
|
@@ -2855,18 +2969,18 @@ async function doctorCommand(options = {}) {
|
|
|
2855
2969
|
severity: "warning",
|
|
2856
2970
|
check: () => {
|
|
2857
2971
|
if (!targetDir) return false;
|
|
2858
|
-
return
|
|
2972
|
+
return fs13.existsSync(join13(targetDir.dir, "commands"));
|
|
2859
2973
|
},
|
|
2860
2974
|
fix: async () => {
|
|
2861
2975
|
if (targetDir) {
|
|
2862
|
-
await
|
|
2976
|
+
await fs13.ensureDir(join13(targetDir.dir, "commands"));
|
|
2863
2977
|
}
|
|
2864
2978
|
},
|
|
2865
2979
|
getMeta: () => {
|
|
2866
2980
|
if (!targetDir) return {};
|
|
2867
|
-
const fullPath =
|
|
2868
|
-
if (
|
|
2869
|
-
const items =
|
|
2981
|
+
const fullPath = join13(targetDir.dir, "commands");
|
|
2982
|
+
if (fs13.existsSync(fullPath)) {
|
|
2983
|
+
const items = fs13.readdirSync(fullPath).length;
|
|
2870
2984
|
return { items };
|
|
2871
2985
|
}
|
|
2872
2986
|
return {};
|
|
@@ -2878,18 +2992,18 @@ async function doctorCommand(options = {}) {
|
|
|
2878
2992
|
severity: "warning",
|
|
2879
2993
|
check: () => {
|
|
2880
2994
|
if (!targetDir) return false;
|
|
2881
|
-
return
|
|
2995
|
+
return fs13.existsSync(join13(targetDir.dir, "skills"));
|
|
2882
2996
|
},
|
|
2883
2997
|
fix: async () => {
|
|
2884
2998
|
if (targetDir) {
|
|
2885
|
-
await
|
|
2999
|
+
await fs13.ensureDir(join13(targetDir.dir, "skills"));
|
|
2886
3000
|
}
|
|
2887
3001
|
},
|
|
2888
3002
|
getMeta: () => {
|
|
2889
3003
|
if (!targetDir) return {};
|
|
2890
|
-
const fullPath =
|
|
2891
|
-
if (
|
|
2892
|
-
const items =
|
|
3004
|
+
const fullPath = join13(targetDir.dir, "skills");
|
|
3005
|
+
if (fs13.existsSync(fullPath)) {
|
|
3006
|
+
const items = fs13.readdirSync(fullPath).length;
|
|
2893
3007
|
return { items };
|
|
2894
3008
|
}
|
|
2895
3009
|
return {};
|
|
@@ -2901,7 +3015,7 @@ async function doctorCommand(options = {}) {
|
|
|
2901
3015
|
severity: "warning",
|
|
2902
3016
|
check: () => {
|
|
2903
3017
|
if (!targetDir) return false;
|
|
2904
|
-
return
|
|
3018
|
+
return fs13.existsSync(join13(targetDir.dir, "scripts"));
|
|
2905
3019
|
}
|
|
2906
3020
|
},
|
|
2907
3021
|
{
|
|
@@ -2910,7 +3024,7 @@ async function doctorCommand(options = {}) {
|
|
|
2910
3024
|
severity: "warning",
|
|
2911
3025
|
check: () => {
|
|
2912
3026
|
if (!targetDir) return false;
|
|
2913
|
-
return
|
|
3027
|
+
return fs13.existsSync(join13(targetDir.dir, "hooks"));
|
|
2914
3028
|
}
|
|
2915
3029
|
},
|
|
2916
3030
|
{
|
|
@@ -2919,7 +3033,7 @@ async function doctorCommand(options = {}) {
|
|
|
2919
3033
|
severity: "warning",
|
|
2920
3034
|
check: () => {
|
|
2921
3035
|
if (!targetDir) return false;
|
|
2922
|
-
return
|
|
3036
|
+
return fs13.existsSync(join13(targetDir.dir, "statusline.cjs")) || fs13.existsSync(join13(targetDir.dir, "statusline.sh"));
|
|
2923
3037
|
}
|
|
2924
3038
|
}
|
|
2925
3039
|
];
|
|
@@ -3077,9 +3191,9 @@ async function outputReport(projectDir, results, options) {
|
|
|
3077
3191
|
}
|
|
3078
3192
|
}
|
|
3079
3193
|
}
|
|
3080
|
-
const reportPath =
|
|
3081
|
-
await
|
|
3082
|
-
await
|
|
3194
|
+
const reportPath = join13(projectDir, ".ak", "doctor-report.md");
|
|
3195
|
+
await fs13.ensureDir(join13(projectDir, ".ak"));
|
|
3196
|
+
await fs13.writeFile(reportPath, markdown, "utf-8");
|
|
3083
3197
|
if (!options.json) {
|
|
3084
3198
|
console.log(pc7.green(`
|
|
3085
3199
|
\u2713 Report saved to ${reportPath}
|
|
@@ -3152,7 +3266,7 @@ async function outputColored(projectDir, results, state, targetDir) {
|
|
|
3152
3266
|
if (!hasState && isProject) {
|
|
3153
3267
|
console.log(pc7.white(' \u2022 State file is missing. Re-run "tk init" or create manually'));
|
|
3154
3268
|
}
|
|
3155
|
-
if (state && state.source && !
|
|
3269
|
+
if (state && state.source && !fs13.existsSync(state.source)) {
|
|
3156
3270
|
console.log(pc7.white(" \u2022 Update source path: tk update --source <new-path>"));
|
|
3157
3271
|
}
|
|
3158
3272
|
console.log("");
|
|
@@ -3193,8 +3307,8 @@ var uninstall_exports = {};
|
|
|
3193
3307
|
__export(uninstall_exports, {
|
|
3194
3308
|
uninstallCommand: () => uninstallCommand
|
|
3195
3309
|
});
|
|
3196
|
-
import
|
|
3197
|
-
import { join as
|
|
3310
|
+
import fs14 from "fs-extra";
|
|
3311
|
+
import { join as join14 } from "path";
|
|
3198
3312
|
import pc9 from "picocolors";
|
|
3199
3313
|
import ora4 from "ora";
|
|
3200
3314
|
import * as p2 from "@clack/prompts";
|
|
@@ -3223,13 +3337,13 @@ async function uninstallFromDir(type, dir, options) {
|
|
|
3223
3337
|
const state = await loadState(dir);
|
|
3224
3338
|
const existingTargets = [];
|
|
3225
3339
|
for (const [name, folder] of Object.entries(TARGETS)) {
|
|
3226
|
-
const targetPath =
|
|
3227
|
-
if (
|
|
3340
|
+
const targetPath = join14(dir, folder);
|
|
3341
|
+
if (fs14.existsSync(targetPath)) {
|
|
3228
3342
|
existingTargets.push({ name, path: targetPath });
|
|
3229
3343
|
}
|
|
3230
3344
|
}
|
|
3231
|
-
const akDir =
|
|
3232
|
-
const hasAkState =
|
|
3345
|
+
const akDir = join14(dir, ".ak");
|
|
3346
|
+
const hasAkState = fs14.existsSync(akDir);
|
|
3233
3347
|
if (existingTargets.length === 0 && !hasAkState) {
|
|
3234
3348
|
spinner.warn(pc9.yellow(`No AK installation found in ${type}`));
|
|
3235
3349
|
return 0;
|
|
@@ -3238,8 +3352,8 @@ async function uninstallFromDir(type, dir, options) {
|
|
|
3238
3352
|
const removalList = [];
|
|
3239
3353
|
for (const target of existingTargets) {
|
|
3240
3354
|
for (const subdir of AK_SUBDIRS) {
|
|
3241
|
-
const subdirPath =
|
|
3242
|
-
if (
|
|
3355
|
+
const subdirPath = join14(target.path, subdir);
|
|
3356
|
+
if (fs14.existsSync(subdirPath)) {
|
|
3243
3357
|
removalList.push(subdirPath);
|
|
3244
3358
|
}
|
|
3245
3359
|
}
|
|
@@ -3320,7 +3434,7 @@ async function removeItems(paths, baseDir) {
|
|
|
3320
3434
|
continue;
|
|
3321
3435
|
}
|
|
3322
3436
|
try {
|
|
3323
|
-
await
|
|
3437
|
+
await fs14.remove(path);
|
|
3324
3438
|
result.removed.push(path);
|
|
3325
3439
|
} catch (error) {
|
|
3326
3440
|
result.errors.push({
|
|
@@ -3434,10 +3548,10 @@ import { execSync as execSync2 } from "child_process";
|
|
|
3434
3548
|
import pc11 from "picocolors";
|
|
3435
3549
|
import ora6 from "ora";
|
|
3436
3550
|
import { readFileSync } from "fs";
|
|
3437
|
-
import { join as
|
|
3551
|
+
import { join as join15 } from "path";
|
|
3438
3552
|
function getCurrentVersion() {
|
|
3439
3553
|
try {
|
|
3440
|
-
const pkg = JSON.parse(readFileSync(
|
|
3554
|
+
const pkg = JSON.parse(readFileSync(join15(CLI_ROOT, "package.json"), "utf-8"));
|
|
3441
3555
|
return pkg.version;
|
|
3442
3556
|
} catch {
|
|
3443
3557
|
return "0.0.0";
|
|
@@ -3497,8 +3611,8 @@ __export(skills_exports, {
|
|
|
3497
3611
|
skillsCommand: () => skillsCommand
|
|
3498
3612
|
});
|
|
3499
3613
|
import pc12 from "picocolors";
|
|
3500
|
-
import
|
|
3501
|
-
import { join as
|
|
3614
|
+
import fs15 from "fs-extra";
|
|
3615
|
+
import { join as join16 } from "path";
|
|
3502
3616
|
import * as p3 from "@clack/prompts";
|
|
3503
3617
|
async function skillsCommand(options) {
|
|
3504
3618
|
const { name, agent, list, installed, uninstall, yes } = options;
|
|
@@ -3576,8 +3690,8 @@ async function installSkill(skillName, agents, skipConfirm) {
|
|
|
3576
3690
|
console.log(pc12.red(`Error: ${source.error}`));
|
|
3577
3691
|
process.exit(1);
|
|
3578
3692
|
}
|
|
3579
|
-
const skillPath =
|
|
3580
|
-
if (!
|
|
3693
|
+
const skillPath = join16(source.claudeDir, "skills", skillName);
|
|
3694
|
+
if (!fs15.existsSync(skillPath)) {
|
|
3581
3695
|
console.log(pc12.red(`Error: Skill "${skillName}" not found in source`));
|
|
3582
3696
|
console.log(pc12.gray(`Available skills: ak skills --list`));
|
|
3583
3697
|
process.exit(1);
|
|
@@ -3594,9 +3708,9 @@ async function installSkill(skillName, agents, skipConfirm) {
|
|
|
3594
3708
|
const results = [];
|
|
3595
3709
|
for (const agent of agents) {
|
|
3596
3710
|
try {
|
|
3597
|
-
const targetPath =
|
|
3598
|
-
await
|
|
3599
|
-
await
|
|
3711
|
+
const targetPath = join16(process.cwd(), AGENT_SKILL_PATHS[agent], skillName);
|
|
3712
|
+
await fs15.ensureDir(join16(process.cwd(), AGENT_SKILL_PATHS[agent]));
|
|
3713
|
+
await fs15.copy(skillPath, targetPath, { overwrite: true });
|
|
3600
3714
|
results.push({ agent, success: true });
|
|
3601
3715
|
} catch (err) {
|
|
3602
3716
|
results.push({ agent, success: false, error: err.message });
|
|
@@ -3635,8 +3749,8 @@ async function uninstallSkill(skillName, agents, skipConfirm) {
|
|
|
3635
3749
|
const results = [];
|
|
3636
3750
|
for (const agent of installedIn) {
|
|
3637
3751
|
try {
|
|
3638
|
-
const targetPath =
|
|
3639
|
-
await
|
|
3752
|
+
const targetPath = join16(process.cwd(), AGENT_SKILL_PATHS[agent], skillName);
|
|
3753
|
+
await fs15.remove(targetPath);
|
|
3640
3754
|
results.push({ agent, success: true });
|
|
3641
3755
|
} catch (err) {
|
|
3642
3756
|
results.push({ agent, success: false, error: err.message });
|
|
@@ -3671,19 +3785,19 @@ function parseAgents(agentFlag) {
|
|
|
3671
3785
|
return valid;
|
|
3672
3786
|
}
|
|
3673
3787
|
function isSkillInstalled(skillName, agent) {
|
|
3674
|
-
const skillPath =
|
|
3675
|
-
return
|
|
3788
|
+
const skillPath = join16(process.cwd(), AGENT_SKILL_PATHS[agent], skillName);
|
|
3789
|
+
return fs15.existsSync(skillPath);
|
|
3676
3790
|
}
|
|
3677
3791
|
function getInstalledSkills(agent) {
|
|
3678
|
-
const skillsDir =
|
|
3679
|
-
if (!
|
|
3792
|
+
const skillsDir = join16(process.cwd(), AGENT_SKILL_PATHS[agent]);
|
|
3793
|
+
if (!fs15.existsSync(skillsDir)) {
|
|
3680
3794
|
return [];
|
|
3681
3795
|
}
|
|
3682
3796
|
try {
|
|
3683
|
-
const items =
|
|
3797
|
+
const items = fs15.readdirSync(skillsDir);
|
|
3684
3798
|
return items.filter((item) => {
|
|
3685
|
-
const itemPath =
|
|
3686
|
-
return
|
|
3799
|
+
const itemPath = join16(skillsDir, item);
|
|
3800
|
+
return fs15.statSync(itemPath).isDirectory();
|
|
3687
3801
|
});
|
|
3688
3802
|
} catch {
|
|
3689
3803
|
return [];
|
|
@@ -3707,7 +3821,7 @@ var init_skills = __esm({
|
|
|
3707
3821
|
import cac from "cac";
|
|
3708
3822
|
import { readFileSync as readFileSync3 } from "fs";
|
|
3709
3823
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3710
|
-
import { dirname as
|
|
3824
|
+
import { dirname as dirname5, join as join18 } from "path";
|
|
3711
3825
|
import pc13 from "picocolors";
|
|
3712
3826
|
|
|
3713
3827
|
// src/cli/command-registry.ts
|
|
@@ -3763,11 +3877,11 @@ function registerCommands(cli2) {
|
|
|
3763
3877
|
}
|
|
3764
3878
|
|
|
3765
3879
|
// src/utils/version-check.ts
|
|
3766
|
-
import { join as
|
|
3880
|
+
import { join as join17 } from "path";
|
|
3767
3881
|
import { homedir as homedir2 } from "os";
|
|
3768
3882
|
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
|
|
3769
|
-
var CACHE_DIR =
|
|
3770
|
-
var CACHE_FILE =
|
|
3883
|
+
var CACHE_DIR = join17(homedir2(), ".thanh-kit");
|
|
3884
|
+
var CACHE_FILE = join17(CACHE_DIR, "version-check.json");
|
|
3771
3885
|
var CACHE_TTL = 7 * 24 * 60 * 60 * 1e3;
|
|
3772
3886
|
function getCachedVersionNoFetch() {
|
|
3773
3887
|
try {
|
|
@@ -3791,10 +3905,10 @@ function isNewerVersion(current, latest) {
|
|
|
3791
3905
|
|
|
3792
3906
|
// src/index.ts
|
|
3793
3907
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
3794
|
-
var __dirname2 =
|
|
3908
|
+
var __dirname2 = dirname5(__filename2);
|
|
3795
3909
|
function getVersion() {
|
|
3796
3910
|
try {
|
|
3797
|
-
const pkg = JSON.parse(readFileSync3(
|
|
3911
|
+
const pkg = JSON.parse(readFileSync3(join18(__dirname2, "..", "package.json"), "utf-8"));
|
|
3798
3912
|
return pkg.version;
|
|
3799
3913
|
} catch {
|
|
3800
3914
|
return "0.0.0";
|