@kood/claude-code 0.7.7 → 0.7.8
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 +183 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22,8 +22,8 @@ var banner = () => {
|
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
// src/commands/init.ts
|
|
25
|
-
import
|
|
26
|
-
import
|
|
25
|
+
import fs9 from "fs-extra";
|
|
26
|
+
import os2 from "os";
|
|
27
27
|
|
|
28
28
|
// src/features/templates/template-path-resolver.ts
|
|
29
29
|
import path2 from "path";
|
|
@@ -688,15 +688,37 @@ async function promptScopeSelection(options) {
|
|
|
688
688
|
}
|
|
689
689
|
return { scope: response.value };
|
|
690
690
|
}
|
|
691
|
+
async function promptCodexSync(options) {
|
|
692
|
+
const { providedSyncCodex } = options;
|
|
693
|
+
if (providedSyncCodex !== void 0) {
|
|
694
|
+
return { syncCodex: providedSyncCodex };
|
|
695
|
+
}
|
|
696
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
697
|
+
return { syncCodex: false };
|
|
698
|
+
}
|
|
699
|
+
logger.blank();
|
|
700
|
+
const result = await promptConfirm(
|
|
701
|
+
"Also sync with Codex now? (~/.codex/skills/)",
|
|
702
|
+
false
|
|
703
|
+
);
|
|
704
|
+
return { syncCodex: result.confirmed };
|
|
705
|
+
}
|
|
691
706
|
|
|
692
707
|
// src/shared/gitignore-manager.ts
|
|
693
708
|
import fs7 from "fs-extra";
|
|
694
709
|
import path9 from "path";
|
|
695
710
|
var CLAUDE_GENERATED_FOLDERS = [
|
|
711
|
+
".claude/brainstorms/",
|
|
712
|
+
".claude/crawler/",
|
|
713
|
+
".claude/first-principles/",
|
|
714
|
+
".claude/genius-ideas/",
|
|
696
715
|
".claude/plan/",
|
|
716
|
+
".claude/plans/",
|
|
697
717
|
".claude/ralph/",
|
|
698
718
|
".claude/refactor/",
|
|
699
|
-
".claude/prd/"
|
|
719
|
+
".claude/prd/",
|
|
720
|
+
".claude/research/",
|
|
721
|
+
".claude/validation-results/"
|
|
700
722
|
];
|
|
701
723
|
function normalizeIgnorePattern(pattern) {
|
|
702
724
|
return pattern.replace(/\\/g, "/").replace(/^\.?\//, "").replace(/\/+$/, "").trim();
|
|
@@ -757,6 +779,126 @@ async function updateGitignore(targetDir) {
|
|
|
757
779
|
}
|
|
758
780
|
}
|
|
759
781
|
|
|
782
|
+
// src/features/codex-sync/codex-sync.ts
|
|
783
|
+
import fs8 from "fs-extra";
|
|
784
|
+
import os from "os";
|
|
785
|
+
import path10 from "path";
|
|
786
|
+
function resolveCodexHome() {
|
|
787
|
+
const envCodexHome = process.env.CODEX_HOME?.trim();
|
|
788
|
+
if (envCodexHome) {
|
|
789
|
+
return path10.resolve(envCodexHome);
|
|
790
|
+
}
|
|
791
|
+
return path10.join(os.homedir(), ".codex");
|
|
792
|
+
}
|
|
793
|
+
function normalizeLineEndings(content) {
|
|
794
|
+
return content.replace(/\r\n/g, "\n");
|
|
795
|
+
}
|
|
796
|
+
function yamlQuote(value) {
|
|
797
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
798
|
+
}
|
|
799
|
+
function extractDescriptionFromFrontmatter(markdown) {
|
|
800
|
+
const frontmatterMatch = markdown.match(/^---\n([\s\S]*?)\n---\n?/);
|
|
801
|
+
if (!frontmatterMatch) {
|
|
802
|
+
return void 0;
|
|
803
|
+
}
|
|
804
|
+
const lines = frontmatterMatch[1].split("\n");
|
|
805
|
+
for (const rawLine of lines) {
|
|
806
|
+
const line = rawLine.trim();
|
|
807
|
+
if (!line.startsWith("description:")) {
|
|
808
|
+
continue;
|
|
809
|
+
}
|
|
810
|
+
const value = line.slice("description:".length).trim();
|
|
811
|
+
if (!value) {
|
|
812
|
+
return void 0;
|
|
813
|
+
}
|
|
814
|
+
return value.replace(/^['"]|['"]$/g, "");
|
|
815
|
+
}
|
|
816
|
+
return void 0;
|
|
817
|
+
}
|
|
818
|
+
function buildCommandSkillContent(commandPath, commandRaw) {
|
|
819
|
+
const commandName = path10.basename(commandPath, ".md");
|
|
820
|
+
const normalizedCommand = normalizeLineEndings(commandRaw).trim();
|
|
821
|
+
const sourcePath = path10.resolve(commandPath);
|
|
822
|
+
const description = extractDescriptionFromFrontmatter(normalizedCommand) || `${commandName} command imported from .claude/commands`;
|
|
823
|
+
return `---
|
|
824
|
+
name: ${yamlQuote(commandName)}
|
|
825
|
+
description: ${yamlQuote(description)}
|
|
826
|
+
---
|
|
827
|
+
|
|
828
|
+
Imported command source: ${sourcePath}
|
|
829
|
+
|
|
830
|
+
Use this as a command playbook. If scripts are referenced with .claude-relative paths,
|
|
831
|
+
resolve them from the current workspace first; if missing, ask for the intended repo root.
|
|
832
|
+
|
|
833
|
+
---
|
|
834
|
+
|
|
835
|
+
${normalizedCommand}
|
|
836
|
+
`;
|
|
837
|
+
}
|
|
838
|
+
async function syncSkills(claudeSkillsDir, codexSkillsDir) {
|
|
839
|
+
if (!await fs8.pathExists(claudeSkillsDir)) {
|
|
840
|
+
return 0;
|
|
841
|
+
}
|
|
842
|
+
const entries = await fs8.readdir(claudeSkillsDir, { withFileTypes: true });
|
|
843
|
+
let syncedSkills = 0;
|
|
844
|
+
for (const entry of entries) {
|
|
845
|
+
if (!entry.isDirectory()) {
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
848
|
+
if (entry.name === ".system") {
|
|
849
|
+
continue;
|
|
850
|
+
}
|
|
851
|
+
const src = path10.join(claudeSkillsDir, entry.name);
|
|
852
|
+
const dest = path10.join(codexSkillsDir, entry.name);
|
|
853
|
+
if (await fs8.pathExists(dest)) {
|
|
854
|
+
await fs8.remove(dest);
|
|
855
|
+
}
|
|
856
|
+
await copyRecursive(src, dest, { files: 0, directories: 0 });
|
|
857
|
+
syncedSkills++;
|
|
858
|
+
}
|
|
859
|
+
return syncedSkills;
|
|
860
|
+
}
|
|
861
|
+
async function syncCommands(claudeCommandsDir, codexCommandsDir) {
|
|
862
|
+
if (!await fs8.pathExists(claudeCommandsDir)) {
|
|
863
|
+
return 0;
|
|
864
|
+
}
|
|
865
|
+
const entries = await fs8.readdir(claudeCommandsDir, { withFileTypes: true });
|
|
866
|
+
const commandFiles = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => entry.name).sort((a, b) => a.localeCompare(b));
|
|
867
|
+
if (commandFiles.length === 0) {
|
|
868
|
+
return 0;
|
|
869
|
+
}
|
|
870
|
+
await fs8.remove(codexCommandsDir);
|
|
871
|
+
await fs8.ensureDir(codexCommandsDir);
|
|
872
|
+
for (const commandFile of commandFiles) {
|
|
873
|
+
const commandPath = path10.join(claudeCommandsDir, commandFile);
|
|
874
|
+
const commandRaw = await fs8.readFile(commandPath, "utf8");
|
|
875
|
+
const commandName = path10.basename(commandFile, ".md");
|
|
876
|
+
const skillDir = path10.join(codexCommandsDir, commandName);
|
|
877
|
+
const skillPath = path10.join(skillDir, "SKILL.md");
|
|
878
|
+
await fs8.ensureDir(skillDir);
|
|
879
|
+
await fs8.writeFile(skillPath, buildCommandSkillContent(commandPath, commandRaw));
|
|
880
|
+
}
|
|
881
|
+
return commandFiles.length;
|
|
882
|
+
}
|
|
883
|
+
async function syncWithCodex(targetDir) {
|
|
884
|
+
const codexHome = resolveCodexHome();
|
|
885
|
+
const codexSkillsDir = path10.join(codexHome, "skills");
|
|
886
|
+
const codexCommandsDir = path10.join(codexSkillsDir, "claude-commands");
|
|
887
|
+
await fs8.ensureDir(codexSkillsDir);
|
|
888
|
+
const claudeRootDir = path10.join(targetDir, ".claude");
|
|
889
|
+
const claudeSkillsDir = path10.join(claudeRootDir, "skills");
|
|
890
|
+
const claudeCommandsDir = path10.join(claudeRootDir, "commands");
|
|
891
|
+
const syncedSkills = await syncSkills(claudeSkillsDir, codexSkillsDir);
|
|
892
|
+
const syncedCommands = await syncCommands(claudeCommandsDir, codexCommandsDir);
|
|
893
|
+
return {
|
|
894
|
+
codexHome,
|
|
895
|
+
codexSkillsDir,
|
|
896
|
+
codexCommandsDir,
|
|
897
|
+
syncedSkills,
|
|
898
|
+
syncedCommands
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
|
|
760
902
|
// src/commands/init.ts
|
|
761
903
|
var TEMPLATE_DESCRIPTIONS = {
|
|
762
904
|
"tanstack-start": "TanStack Start + React \uD480\uC2A4\uD0DD \uD504\uB85C\uC81D\uD2B8",
|
|
@@ -766,7 +908,7 @@ var TEMPLATE_DESCRIPTIONS = {
|
|
|
766
908
|
};
|
|
767
909
|
async function validateTargetDirectory(targetDir) {
|
|
768
910
|
try {
|
|
769
|
-
const stat = await
|
|
911
|
+
const stat = await fs9.stat(targetDir);
|
|
770
912
|
if (!stat.isDirectory()) {
|
|
771
913
|
logger.error(`Target is not a directory: ${targetDir}`);
|
|
772
914
|
process.exit(1);
|
|
@@ -780,7 +922,7 @@ async function validateTargetDirectory(targetDir) {
|
|
|
780
922
|
process.exit(1);
|
|
781
923
|
}
|
|
782
924
|
try {
|
|
783
|
-
await
|
|
925
|
+
await fs9.access(targetDir, fs9.constants.W_OK);
|
|
784
926
|
} catch {
|
|
785
927
|
logger.error(`No write permission for: ${targetDir}`);
|
|
786
928
|
process.exit(1);
|
|
@@ -907,7 +1049,7 @@ var init = async (options) => {
|
|
|
907
1049
|
const { scope } = await promptScopeSelection({
|
|
908
1050
|
providedScope: options.scope
|
|
909
1051
|
});
|
|
910
|
-
const targetDir = scope === "user" ?
|
|
1052
|
+
const targetDir = scope === "user" ? os2.homedir() : projectDir;
|
|
911
1053
|
const isUserScope = scope === "user";
|
|
912
1054
|
if (isUserScope) {
|
|
913
1055
|
logger.blank();
|
|
@@ -962,15 +1104,46 @@ var init = async (options) => {
|
|
|
962
1104
|
);
|
|
963
1105
|
}
|
|
964
1106
|
}
|
|
1107
|
+
const { syncCodex } = await promptCodexSync({
|
|
1108
|
+
providedSyncCodex: options.syncCodex
|
|
1109
|
+
});
|
|
1110
|
+
if (!syncCodex) {
|
|
1111
|
+
return;
|
|
1112
|
+
}
|
|
1113
|
+
logger.blank();
|
|
1114
|
+
logger.info("Syncing .claude skills/commands to Codex...");
|
|
1115
|
+
try {
|
|
1116
|
+
const result = await syncWithCodex(targetDir);
|
|
1117
|
+
if (result.syncedSkills > 0) {
|
|
1118
|
+
logger.step(`Skills synced: ${result.syncedSkills}`);
|
|
1119
|
+
}
|
|
1120
|
+
if (result.syncedCommands > 0) {
|
|
1121
|
+
logger.step(`Commands synced: ${result.syncedCommands}`);
|
|
1122
|
+
}
|
|
1123
|
+
if (result.syncedSkills === 0 && result.syncedCommands === 0) {
|
|
1124
|
+
logger.warn(
|
|
1125
|
+
"Nothing was synced. .claude/skills and .claude/commands were not found."
|
|
1126
|
+
);
|
|
1127
|
+
} else {
|
|
1128
|
+
logger.success(`Codex sync complete: ${result.codexSkillsDir}`);
|
|
1129
|
+
}
|
|
1130
|
+
} catch (error) {
|
|
1131
|
+
logger.warn(
|
|
1132
|
+
`Codex sync failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
965
1135
|
};
|
|
966
1136
|
|
|
967
1137
|
// src/index.ts
|
|
968
1138
|
var program = new Command();
|
|
969
|
-
program.name("claude-code").description("Claude Code documentation installer for projects").version("0.7.
|
|
1139
|
+
program.name("claude-code").description("Claude Code documentation installer for projects").version("0.7.8");
|
|
970
1140
|
program.option(
|
|
971
1141
|
"-t, --template <names>",
|
|
972
1142
|
"template names (comma-separated: tanstack-start,hono)"
|
|
973
|
-
).option("-f, --force", "overwrite existing files without prompting").option("--cwd <path>", "target directory (default: current directory)").option("--list", "list available templates").option("-s, --skills", "install skills to .claude/skills/").option("-c, --commands", "install commands to .claude/commands/").option("-a, --agents", "install agents to .claude/agents/").option(
|
|
1143
|
+
).option("-f, --force", "overwrite existing files without prompting").option("--cwd <path>", "target directory (default: current directory)").option("--list", "list available templates").option("-s, --skills", "install skills to .claude/skills/").option("-c, --commands", "install commands to .claude/commands/").option("-a, --agents", "install agents to .claude/agents/").option(
|
|
1144
|
+
"--sync-codex",
|
|
1145
|
+
"sync installed .claude skills/commands to Codex (~/.codex/skills/)"
|
|
1146
|
+
).option("--scope <scope>", "installation scope (project|user)").action(async (options) => {
|
|
974
1147
|
banner();
|
|
975
1148
|
if (options.list) {
|
|
976
1149
|
const templates = await listAvailableTemplates();
|
|
@@ -986,7 +1159,8 @@ program.option(
|
|
|
986
1159
|
scope: options.scope,
|
|
987
1160
|
skills: options.skills,
|
|
988
1161
|
commands: options.commands,
|
|
989
|
-
agents: options.agents
|
|
1162
|
+
agents: options.agents,
|
|
1163
|
+
syncCodex: options.syncCodex
|
|
990
1164
|
});
|
|
991
1165
|
});
|
|
992
1166
|
program.parse();
|