@kood/claude-code 0.7.8 → 0.7.9

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.
Files changed (2) hide show
  1. package/dist/index.js +63 -55
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -23,7 +23,8 @@ var banner = () => {
23
23
 
24
24
  // src/commands/init.ts
25
25
  import fs9 from "fs-extra";
26
- import os2 from "os";
26
+ import os from "os";
27
+ import path11 from "path";
27
28
 
28
29
  // src/features/templates/template-path-resolver.ts
29
30
  import path2 from "path";
@@ -689,7 +690,7 @@ async function promptScopeSelection(options) {
689
690
  return { scope: response.value };
690
691
  }
691
692
  async function promptCodexSync(options) {
692
- const { providedSyncCodex } = options;
693
+ const { providedSyncCodex, codexSkillsPath } = options;
693
694
  if (providedSyncCodex !== void 0) {
694
695
  return { syncCodex: providedSyncCodex };
695
696
  }
@@ -697,8 +698,9 @@ async function promptCodexSync(options) {
697
698
  return { syncCodex: false };
698
699
  }
699
700
  logger.blank();
701
+ const pathHint = codexSkillsPath ? ` (${codexSkillsPath})` : "";
700
702
  const result = await promptConfirm(
701
- "Also sync with Codex now? (~/.codex/skills/)",
703
+ `Also sync with Codex now?${pathHint}`,
702
704
  false
703
705
  );
704
706
  return { syncCodex: result.confirmed };
@@ -720,6 +722,7 @@ var CLAUDE_GENERATED_FOLDERS = [
720
722
  ".claude/research/",
721
723
  ".claude/validation-results/"
722
724
  ];
725
+ var CODEX_GENERATED_FOLDERS = [".codex/"];
723
726
  function normalizeIgnorePattern(pattern) {
724
727
  return pattern.replace(/\\/g, "/").replace(/^\.?\//, "").replace(/\/+$/, "").trim();
725
728
  }
@@ -732,9 +735,11 @@ function parseIgnoreLine(line) {
732
735
  const normalized = normalizeIgnorePattern(rawPattern);
733
736
  return normalized || null;
734
737
  }
735
- async function updateGitignore(targetDir) {
738
+ async function updateGitignore(targetDir, options = {}) {
739
+ const { includeCodex = false } = options;
736
740
  const gitignorePath = path9.join(targetDir, ".gitignore");
737
741
  const sectionComment = "# Claude Code generated files";
742
+ const targetFolders = includeCodex ? [...CLAUDE_GENERATED_FOLDERS, ...CODEX_GENERATED_FOLDERS] : CLAUDE_GENERATED_FOLDERS;
738
743
  let content = "";
739
744
  let hasGitignore = false;
740
745
  try {
@@ -748,7 +753,7 @@ async function updateGitignore(targetDir) {
748
753
  const existingPatterns = new Set(
749
754
  lines.map((line) => parseIgnoreLine(line)).filter((pattern) => Boolean(pattern))
750
755
  );
751
- const linesToAdd = CLAUDE_GENERATED_FOLDERS.filter(
756
+ const linesToAdd = targetFolders.filter(
752
757
  (folder) => !existingPatterns.has(normalizeIgnorePattern(folder))
753
758
  );
754
759
  if (linesToAdd.length === 0) {
@@ -781,15 +786,8 @@ async function updateGitignore(targetDir) {
781
786
 
782
787
  // src/features/codex-sync/codex-sync.ts
783
788
  import fs8 from "fs-extra";
784
- import os from "os";
785
789
  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
- }
790
+ var RESERVED_CODEX_SKILL_DIRS = /* @__PURE__ */ new Set([".system", "claude-commands"]);
793
791
  function normalizeLineEndings(content) {
794
792
  return content.replace(/\r\n/g, "\n");
795
793
  }
@@ -836,35 +834,44 @@ ${normalizedCommand}
836
834
  `;
837
835
  }
838
836
  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) {
837
+ await fs8.ensureDir(codexSkillsDir);
838
+ let sourceSkillNames = [];
839
+ if (await fs8.pathExists(claudeSkillsDir)) {
840
+ const sourceEntries = await fs8.readdir(claudeSkillsDir, { withFileTypes: true });
841
+ sourceSkillNames = sourceEntries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => name !== ".system");
842
+ }
843
+ const sourceSkillSet = new Set(sourceSkillNames);
844
+ const codexEntries = await fs8.readdir(codexSkillsDir, { withFileTypes: true });
845
+ for (const entry of codexEntries) {
845
846
  if (!entry.isDirectory()) {
846
847
  continue;
847
848
  }
848
- if (entry.name === ".system") {
849
+ if (RESERVED_CODEX_SKILL_DIRS.has(entry.name)) {
849
850
  continue;
850
851
  }
851
- const src = path10.join(claudeSkillsDir, entry.name);
852
- const dest = path10.join(codexSkillsDir, entry.name);
852
+ if (!sourceSkillSet.has(entry.name)) {
853
+ await fs8.remove(path10.join(codexSkillsDir, entry.name));
854
+ }
855
+ }
856
+ for (const skillName of sourceSkillNames) {
857
+ const src = path10.join(claudeSkillsDir, skillName);
858
+ const dest = path10.join(codexSkillsDir, skillName);
853
859
  if (await fs8.pathExists(dest)) {
854
860
  await fs8.remove(dest);
855
861
  }
856
862
  await copyRecursive(src, dest, { files: 0, directories: 0 });
857
- syncedSkills++;
858
863
  }
859
- return syncedSkills;
864
+ return sourceSkillNames.length;
860
865
  }
861
866
  async function syncCommands(claudeCommandsDir, codexCommandsDir) {
862
867
  if (!await fs8.pathExists(claudeCommandsDir)) {
868
+ await fs8.remove(codexCommandsDir);
863
869
  return 0;
864
870
  }
865
871
  const entries = await fs8.readdir(claudeCommandsDir, { withFileTypes: true });
866
872
  const commandFiles = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => entry.name).sort((a, b) => a.localeCompare(b));
867
873
  if (commandFiles.length === 0) {
874
+ await fs8.remove(codexCommandsDir);
868
875
  return 0;
869
876
  }
870
877
  await fs8.remove(codexCommandsDir);
@@ -881,7 +888,7 @@ async function syncCommands(claudeCommandsDir, codexCommandsDir) {
881
888
  return commandFiles.length;
882
889
  }
883
890
  async function syncWithCodex(targetDir) {
884
- const codexHome = resolveCodexHome();
891
+ const codexHome = path10.resolve(targetDir, ".codex");
885
892
  const codexSkillsDir = path10.join(codexHome, "skills");
886
893
  const codexCommandsDir = path10.join(codexSkillsDir, "claude-commands");
887
894
  await fs8.ensureDir(codexSkillsDir);
@@ -1049,7 +1056,7 @@ var init = async (options) => {
1049
1056
  const { scope } = await promptScopeSelection({
1050
1057
  providedScope: options.scope
1051
1058
  });
1052
- const targetDir = scope === "user" ? os2.homedir() : projectDir;
1059
+ const targetDir = scope === "user" ? os.homedir() : projectDir;
1053
1060
  const isUserScope = scope === "user";
1054
1061
  if (isUserScope) {
1055
1062
  logger.blank();
@@ -1095,54 +1102,55 @@ var init = async (options) => {
1095
1102
  hasScripts,
1096
1103
  scope
1097
1104
  );
1098
- if (!isUserScope) {
1105
+ const codexSkillsPath = path11.join(targetDir, ".codex", "skills");
1106
+ const { syncCodex } = await promptCodexSync({
1107
+ providedSyncCodex: options.syncCodex,
1108
+ codexSkillsPath
1109
+ });
1110
+ if (syncCodex) {
1111
+ logger.blank();
1112
+ logger.info("Syncing .claude skills/commands to Codex...");
1099
1113
  try {
1100
- await updateGitignore(targetDir);
1114
+ const result = await syncWithCodex(targetDir);
1115
+ if (result.syncedSkills > 0) {
1116
+ logger.step(`Skills synced: ${result.syncedSkills}`);
1117
+ }
1118
+ if (result.syncedCommands > 0) {
1119
+ logger.step(`Commands synced: ${result.syncedCommands}`);
1120
+ }
1121
+ if (result.syncedSkills === 0 && result.syncedCommands === 0) {
1122
+ logger.warn(
1123
+ "Nothing was synced. .claude/skills and .claude/commands were not found."
1124
+ );
1125
+ } else {
1126
+ logger.success(`Codex sync complete: ${result.codexSkillsDir}`);
1127
+ }
1101
1128
  } catch (error) {
1102
1129
  logger.warn(
1103
- `Failed to update .gitignore: ${error instanceof Error ? error.message : "Unknown error"}`
1130
+ `Codex sync failed: ${error instanceof Error ? error.message : "Unknown error"}`
1104
1131
  );
1105
1132
  }
1106
1133
  }
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) {
1134
+ if (!isUserScope) {
1135
+ try {
1136
+ await updateGitignore(targetDir, { includeCodex: syncCodex });
1137
+ } catch (error) {
1124
1138
  logger.warn(
1125
- "Nothing was synced. .claude/skills and .claude/commands were not found."
1139
+ `Failed to update .gitignore: ${error instanceof Error ? error.message : "Unknown error"}`
1126
1140
  );
1127
- } else {
1128
- logger.success(`Codex sync complete: ${result.codexSkillsDir}`);
1129
1141
  }
1130
- } catch (error) {
1131
- logger.warn(
1132
- `Codex sync failed: ${error instanceof Error ? error.message : "Unknown error"}`
1133
- );
1134
1142
  }
1135
1143
  };
1136
1144
 
1137
1145
  // src/index.ts
1138
1146
  var program = new Command();
1139
- program.name("claude-code").description("Claude Code documentation installer for projects").version("0.7.8");
1147
+ program.name("claude-code").description("Claude Code documentation installer for projects").version("0.7.9");
1140
1148
  program.option(
1141
1149
  "-t, --template <names>",
1142
1150
  "template names (comma-separated: tanstack-start,hono)"
1143
1151
  ).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
1152
  "--sync-codex",
1145
- "sync installed .claude skills/commands to Codex (~/.codex/skills/)"
1153
+ "sync installed .claude skills/commands to selected-scope .codex/skills/"
1146
1154
  ).option("--scope <scope>", "installation scope (project|user)").action(async (options) => {
1147
1155
  banner();
1148
1156
  if (options.list) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kood/claude-code",
3
- "version": "0.7.8",
3
+ "version": "0.7.9",
4
4
  "description": "Claude Code documentation installer for projects",
5
5
  "type": "module",
6
6
  "bin": "./dist/index.js",