@sunasteriskrnd/takumi 1.0.0-dev.16 → 1.0.0-dev.17

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 +80 -47
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -43742,10 +43742,11 @@ async function handleConflicts(ctx) {
43742
43742
  return ctx;
43743
43743
  if (!ctx.options.global)
43744
43744
  return ctx;
43745
- if (isLocalSameAsGlobal()) {
43745
+ const projectRoot = ctx.resolvedDir ?? process.cwd();
43746
+ if (isLocalSameAsGlobal(projectRoot)) {
43746
43747
  return ctx;
43747
43748
  }
43748
- const localSettingsPath = join13(process.cwd(), ".claude", "settings.json");
43749
+ const localSettingsPath = join13(projectRoot, ".claude", "settings.json");
43749
43750
  if (!await import_fs_extra6.pathExists(localSettingsPath)) {
43750
43751
  return ctx;
43751
43752
  }
@@ -43760,7 +43761,7 @@ async function handleConflicts(ctx) {
43760
43761
  return { ...ctx, cancelled: true };
43761
43762
  }
43762
43763
  if (choice === "remove") {
43763
- const localClaudeDir = join13(process.cwd(), ".claude");
43764
+ const localClaudeDir = join13(projectRoot, ".claude");
43764
43765
  try {
43765
43766
  await import_fs_extra6.remove(localClaudeDir);
43766
43767
  logger.success("Removed local .claude/ directory");
@@ -51621,7 +51622,7 @@ import { join as join48 } from "node:path";
51621
51622
  init_logger();
51622
51623
  var CODEX_ENV_MARKER = `module.exports = { agent: 'codex' };
51623
51624
  `;
51624
- function writeCodexEnvMarker(global3) {
51625
+ function writeCodexEnvMarker(global3, projectRoot) {
51625
51626
  try {
51626
51627
  const pathConfig = providers.codex.hooks;
51627
51628
  if (!pathConfig)
@@ -51629,7 +51630,7 @@ function writeCodexEnvMarker(global3) {
51629
51630
  const scopedPath = global3 ? pathConfig.globalPath : pathConfig.projectPath;
51630
51631
  if (!scopedPath)
51631
51632
  return;
51632
- const targetHooksDir = global3 ? scopedPath : join48(process.cwd(), scopedPath);
51633
+ const targetHooksDir = global3 ? scopedPath : join48(projectRoot ?? process.cwd(), scopedPath);
51633
51634
  const libDir = join48(targetHooksDir, "lib");
51634
51635
  mkdirSync(libDir, { recursive: true });
51635
51636
  writeFileSync2(join48(libDir, "env.cjs"), CODEX_ENV_MARKER);
@@ -52589,8 +52590,16 @@ function isPathWithinBoundary(targetPath, boundaryPath) {
52589
52590
  const resolvedBoundary = resolve6(boundaryPath);
52590
52591
  return resolvedTarget === resolvedBoundary || resolvedTarget.startsWith(`${resolvedBoundary}${sep3}`);
52591
52592
  }
52593
+ function getProjectBoundary(options2) {
52594
+ return options2.projectRoot ?? process.cwd();
52595
+ }
52596
+ function resolveInstallBasePath(rawPath, options2) {
52597
+ if (options2.global)
52598
+ return rawPath;
52599
+ return resolve6(getProjectBoundary(options2), rawPath);
52600
+ }
52592
52601
  function validateStrategyTargetPath(targetPath, options2) {
52593
- const boundary = options2.global ? homedir11() : process.cwd();
52602
+ const boundary = options2.global ? homedir11() : getProjectBoundary(options2);
52594
52603
  if (!isPathWithinBoundary(targetPath, boundary)) {
52595
52604
  return `Unsafe path: target escapes ${options2.global ? "home" : "project"} directory`;
52596
52605
  }
@@ -52724,8 +52733,8 @@ async function installOneFile(item, provider, kind, options2) {
52724
52733
  error: `${config.displayName} does not support ${kind}s`
52725
52734
  };
52726
52735
  }
52727
- const basePath = options2.global ? pathConfig.globalPath : pathConfig.projectPath;
52728
- if (!basePath) {
52736
+ const rawBasePath = options2.global ? pathConfig.globalPath : pathConfig.projectPath;
52737
+ if (!rawBasePath) {
52729
52738
  return {
52730
52739
  provider,
52731
52740
  providerDisplayName: config.displayName,
@@ -52734,6 +52743,7 @@ async function installOneFile(item, provider, kind, options2) {
52734
52743
  error: `${config.displayName} does not support ${options2.global ? "global" : "project"}-level ${kind}s`
52735
52744
  };
52736
52745
  }
52746
+ const basePath = resolveInstallBasePath(rawBasePath, options2);
52737
52747
  const segmentError = validatePortableItemSegments(item);
52738
52748
  if (segmentError) {
52739
52749
  return {
@@ -53124,8 +53134,8 @@ async function installMergeSingle(items, provider, kind, options2) {
53124
53134
  error: `${config.displayName} does not support ${kind}s`
53125
53135
  };
53126
53136
  }
53127
- const targetPath = options2.global ? pathConfig.globalPath : pathConfig.projectPath;
53128
- if (!targetPath) {
53137
+ const rawTargetPath = options2.global ? pathConfig.globalPath : pathConfig.projectPath;
53138
+ if (!rawTargetPath) {
53129
53139
  return {
53130
53140
  provider,
53131
53141
  providerDisplayName: config.displayName,
@@ -53134,6 +53144,7 @@ async function installMergeSingle(items, provider, kind, options2) {
53134
53144
  error: `${config.displayName} does not support ${options2.global ? "global" : "project"}-level ${kind}s`
53135
53145
  };
53136
53146
  }
53147
+ const targetPath = resolveInstallBasePath(rawTargetPath, options2);
53137
53148
  const targetPathError = validateStrategyTargetPath(targetPath, options2);
53138
53149
  if (targetPathError) {
53139
53150
  return {
@@ -53587,8 +53598,8 @@ async function installCodexToml(items, provider, kind, options2, deps) {
53587
53598
  error: `${config.displayName} does not support agents`
53588
53599
  };
53589
53600
  }
53590
- const basePath = options2.global ? pathConfig.globalPath : pathConfig.projectPath;
53591
- if (!basePath) {
53601
+ const rawBasePath = options2.global ? pathConfig.globalPath : pathConfig.projectPath;
53602
+ if (!rawBasePath) {
53592
53603
  return {
53593
53604
  provider,
53594
53605
  providerDisplayName: config.displayName,
@@ -53597,8 +53608,8 @@ async function installCodexToml(items, provider, kind, options2, deps) {
53597
53608
  error: `${config.displayName} does not support ${options2.global ? "global" : "project"}-level agents`
53598
53609
  };
53599
53610
  }
53600
- const boundary = options2.global ? homedir12() : process.cwd();
53601
- const agentsDir = resolve8(basePath);
53611
+ const boundary = options2.global ? homedir12() : getProjectBoundary(options2);
53612
+ const agentsDir = resolveInstallBasePath(rawBasePath, options2);
53602
53613
  const configTomlPath = join51(dirname12(agentsDir), "config.toml");
53603
53614
  if (!isPathWithinBoundary2(agentsDir, boundary)) {
53604
53615
  return {
@@ -53811,10 +53822,10 @@ async function cleanupStaleCodexConfigEntries(options2) {
53811
53822
  const pathConfig = config.agents;
53812
53823
  if (!pathConfig)
53813
53824
  return [];
53814
- const basePath = options2.global ? pathConfig.globalPath : pathConfig.projectPath;
53815
- if (!basePath)
53825
+ const rawBasePath = options2.global ? pathConfig.globalPath : pathConfig.projectPath;
53826
+ if (!rawBasePath)
53816
53827
  return [];
53817
- const agentsDir = resolve8(basePath);
53828
+ const agentsDir = resolveInstallBasePath(rawBasePath, options2);
53818
53829
  const configTomlPath = join51(dirname12(agentsDir), "config.toml");
53819
53830
  if (!existsSync21(configTomlPath))
53820
53831
  return [];
@@ -53948,8 +53959,8 @@ async function installSkillDirectories(skills, targetProviders, options2) {
53948
53959
  });
53949
53960
  continue;
53950
53961
  }
53951
- const basePath = options2.global ? skillConfig.globalPath : skillConfig.projectPath;
53952
- if (!basePath) {
53962
+ const rawBasePath = options2.global ? skillConfig.globalPath : skillConfig.projectPath;
53963
+ if (!rawBasePath) {
53953
53964
  results.push({
53954
53965
  provider,
53955
53966
  providerDisplayName: config.displayName,
@@ -53959,6 +53970,7 @@ async function installSkillDirectories(skills, targetProviders, options2) {
53959
53970
  });
53960
53971
  continue;
53961
53972
  }
53973
+ const basePath = resolveInstallBasePath(rawBasePath, options2);
53962
53974
  for (const skill of skills) {
53963
53975
  const targetDir = join52(basePath, skill.name);
53964
53976
  if (resolve9(skill.path) === resolve9(targetDir)) {
@@ -55052,9 +55064,11 @@ async function migrateCodexHooksSettings(options2) {
55052
55064
  installedHookFiles,
55053
55065
  installedHookAbsolutePaths,
55054
55066
  global: isGlobal,
55067
+ projectRoot,
55055
55068
  sourceSettingsPathOverride,
55056
55069
  sourceHooksDirOverride
55057
55070
  } = options2;
55071
+ const projectBase = projectRoot ?? process.cwd();
55058
55072
  if (installedHookFiles.length === 0) {
55059
55073
  return {
55060
55074
  status: "no-installed-files",
@@ -55095,8 +55109,8 @@ async function migrateCodexHooksSettings(options2) {
55095
55109
  codexCapabilitiesVersion: capabilities.version
55096
55110
  };
55097
55111
  }
55098
- const resolvedSourcePath = sourceSettingsPathOverride ? sourceSettingsPathOverride : isGlobal ? sourceSettingsPath : join56(process.cwd(), sourceSettingsPath);
55099
- const resolvedTargetPath = isGlobal ? targetSettingsPath : join56(process.cwd(), targetSettingsPath);
55112
+ const resolvedSourcePath = sourceSettingsPathOverride ? sourceSettingsPathOverride : isGlobal ? sourceSettingsPath : join56(projectBase, sourceSettingsPath);
55113
+ const resolvedTargetPath = isGlobal ? targetSettingsPath : join56(projectBase, targetSettingsPath);
55100
55114
  const sourceHooksResult = await inspectHooksSettings(resolvedSourcePath);
55101
55115
  if (sourceHooksResult.status === "missing-file") {
55102
55116
  return {
@@ -55143,8 +55157,8 @@ async function migrateCodexHooksSettings(options2) {
55143
55157
  const wrapperPaths = [];
55144
55158
  const commandSubstitutions = new Map;
55145
55159
  if (targetHooksDir) {
55146
- const absSourceHooksDir = sourceHooksDir ? isAbsolute2(sourceHooksDir) ? sourceHooksDir : resolve13(sourceHooksDir) : "";
55147
- const absTargetHooksDir = isAbsolute2(targetHooksDir) ? targetHooksDir : resolve13(targetHooksDir);
55160
+ const absSourceHooksDir = sourceHooksDir ? isAbsolute2(sourceHooksDir) ? sourceHooksDir : resolve13(projectBase, sourceHooksDir) : "";
55161
+ const absTargetHooksDir = isAbsolute2(targetHooksDir) ? targetHooksDir : resolve13(projectBase, targetHooksDir);
55148
55162
  const targetAbsolutePaths = installedHookAbsolutePaths && installedHookAbsolutePaths.length > 0 ? installedHookAbsolutePaths.filter(isCodexWrappableHookPath) : installedHookFiles.filter(isCodexWrappableHookPath).map((basenameOrPath) => basenameOrPath.includes("/") || basenameOrPath.includes("\\") ? basenameOrPath : join56(absTargetHooksDir, basenameOrPath));
55149
55163
  const wrapperResults = generateCodexHookWrappers(targetAbsolutePaths, absTargetHooksDir, capabilities);
55150
55164
  for (const wr of wrapperResults) {
@@ -55206,7 +55220,7 @@ async function migrateCodexHooksSettings(options2) {
55206
55220
  }
55207
55221
  let featureFlagWritten = false;
55208
55222
  if (capabilities.requiresFeatureFlag) {
55209
- const configTomlPath = isGlobal ? join56(homedir15(), ".codex", "config.toml") : join56(process.cwd(), ".codex", "config.toml");
55223
+ const configTomlPath = isGlobal ? join56(homedir15(), ".codex", "config.toml") : join56(projectBase, ".codex", "config.toml");
55210
55224
  const flagResult = await ensureCodexHooksFeatureFlag(configTomlPath, isGlobal);
55211
55225
  featureFlagWritten = flagResult.status === "written" || flagResult.status === "updated";
55212
55226
  }
@@ -55321,7 +55335,7 @@ function pruneDeletedHooks(userHooksJson, deletions, wrapperDir) {
55321
55335
 
55322
55336
  // src/domains/installers/codex/post-pipeline.ts
55323
55337
  var HOOK_SUPPORT_SKIP_DIRS = new Set(["__tests__", "tests", "docs"]);
55324
- function installCodexHookSupportDirs(hookItems, global3) {
55338
+ function installCodexHookSupportDirs(hookItems, global3, projectRoot) {
55325
55339
  const firstSource = hookItems[0]?.sourcePath;
55326
55340
  if (!firstSource)
55327
55341
  return;
@@ -55333,7 +55347,7 @@ function installCodexHookSupportDirs(hookItems, global3) {
55333
55347
  const scopedPath = global3 ? pathConfig.globalPath : pathConfig.projectPath;
55334
55348
  if (!scopedPath)
55335
55349
  return;
55336
- const targetHooksDir = global3 ? scopedPath : join58(process.cwd(), scopedPath);
55350
+ const targetHooksDir = global3 ? scopedPath : join58(projectRoot ?? process.cwd(), scopedPath);
55337
55351
  for (const entry of readdirSync3(sourceHooksDir, { withFileTypes: true })) {
55338
55352
  if (!entry.isDirectory() || HOOK_SUPPORT_SKIP_DIRS.has(entry.name))
55339
55353
  continue;
@@ -55349,13 +55363,14 @@ function installCodexHookSupportDirs(hookItems, global3) {
55349
55363
  logger.debug(`[init/codex] hook support-dir copy failed: ${String(e2)}`);
55350
55364
  }
55351
55365
  }
55352
- async function mergeInstalledHooks(hookFiles, global3, kitSource) {
55366
+ async function mergeInstalledHooks(hookFiles, global3, kitSource, projectRoot) {
55353
55367
  if (hookFiles.length === 0)
55354
55368
  return;
55355
55369
  const merge = await migrateCodexHooksSettings({
55356
55370
  sourceProvider: "claude-code",
55357
55371
  installedHookFiles: hookFiles,
55358
55372
  global: global3,
55373
+ projectRoot,
55359
55374
  sourceSettingsPathOverride: kitSource?.settingsPath,
55360
55375
  sourceHooksDirOverride: kitSource?.hooksDir
55361
55376
  });
@@ -55374,9 +55389,13 @@ function deriveKitHookSource(items) {
55374
55389
  hooksDir: ".claude/hooks"
55375
55390
  };
55376
55391
  }
55377
- async function cleanupStaleCodexToml(global3) {
55392
+ async function cleanupStaleCodexToml(global3, projectRoot) {
55378
55393
  try {
55379
- const staleSlugs = await cleanupStaleCodexConfigEntries({ global: global3, provider: "codex" });
55394
+ const staleSlugs = await cleanupStaleCodexConfigEntries({
55395
+ global: global3,
55396
+ projectRoot,
55397
+ provider: "codex"
55398
+ });
55380
55399
  if (staleSlugs.length > 0) {
55381
55400
  const staleSet = new Set(staleSlugs.map((s) => `${s}.toml`));
55382
55401
  await removeInstallationsByFilter((i) => i.type === "agent" && i.provider === "codex" && i.global === global3 && staleSet.has(basename8(i.path)));
@@ -55392,7 +55411,7 @@ async function healRegistryChecksums(actions, registry) {
55392
55411
  logger.debug("[init/codex] backfill checksums failed");
55393
55412
  }
55394
55413
  }
55395
- async function pruneCodexDeletedHooks(items, global3) {
55414
+ async function pruneCodexDeletedHooks(items, global3, projectRoot) {
55396
55415
  try {
55397
55416
  const kitRoot = items.agents[0]?.sourcePath?.split(/[/\\]agents[/\\]/)[0] ?? items.commands[0]?.sourcePath?.split(/[/\\]commands[/\\]/)[0] ?? items.hooks[0]?.sourcePath?.split(/[/\\]hooks[/\\]/)[0] ?? null;
55398
55417
  if (!kitRoot)
@@ -55406,10 +55425,11 @@ async function pruneCodexDeletedHooks(items, global3) {
55406
55425
  if (deletions.length === 0)
55407
55426
  return;
55408
55427
  const codex = providers.codex;
55409
- const hooksJsonPath = global3 ? codex.settingsJsonPath?.globalPath : codex.settingsJsonPath?.projectPath ? join58(process.cwd(), codex.settingsJsonPath.projectPath) : null;
55428
+ const root = projectRoot ?? process.cwd();
55429
+ const hooksJsonPath = global3 ? codex.settingsJsonPath?.globalPath : codex.settingsJsonPath?.projectPath ? join58(root, codex.settingsJsonPath.projectPath) : null;
55410
55430
  if (!hooksJsonPath || !existsSync26(hooksJsonPath))
55411
55431
  return;
55412
- const wrapperDir = global3 ? codex.hooks?.globalPath : codex.hooks?.projectPath ? join58(process.cwd(), codex.hooks.projectPath) : null;
55432
+ const wrapperDir = global3 ? codex.hooks?.globalPath : codex.hooks?.projectPath ? join58(root, codex.hooks.projectPath) : null;
55413
55433
  if (!wrapperDir)
55414
55434
  return;
55415
55435
  const userJson = JSON.parse(readFileSync7(hooksJsonPath, "utf-8"));
@@ -56109,7 +56129,7 @@ async function discoverFromSources(sources) {
56109
56129
  async function executeCodexPipeline(items, options2) {
56110
56130
  const ui = new InstallerStepUI("codex");
56111
56131
  const { TakumiConfigManager: TakumiConfigManager2 } = await Promise.resolve().then(() => (init_takumi_config_manager(), exports_takumi_config_manager));
56112
- const ckConfigResult = await TakumiConfigManager2.loadFull(process.cwd());
56132
+ const ckConfigResult = await TakumiConfigManager2.loadFull(options2.projectRoot ?? process.cwd());
56113
56133
  setTaxonomyOverrides(ckConfigResult.config.modelTaxonomy);
56114
56134
  ui.phase("Discovering kit sources");
56115
56135
  const totalItems = items.agents.length + items.commands.length + items.skills.length + items.rules.length + items.hooks.length + (items.config ? 1 : 0);
@@ -56149,7 +56169,7 @@ async function executeCodexPipeline(items, options2) {
56149
56169
  ui.success(`Resolved ${conflicts.length} conflict(s)`);
56150
56170
  }
56151
56171
  const planned = plan.actions.filter(shouldExecuteAction).sort((a3, b3) => (TYPE_PRIORITY[a3.type] ?? 99) - (TYPE_PRIORITY[b3.type] ?? 99));
56152
- const installOpts = { global: options2.global };
56172
+ const installOpts = { global: options2.global, projectRoot: options2.projectRoot };
56153
56173
  const results = [];
56154
56174
  const successfulHookFiles = [];
56155
56175
  const byName = {
@@ -56226,12 +56246,12 @@ async function executeCodexPipeline(items, options2) {
56226
56246
  ui.success(`Installed ${execSummary.applied} file(s)${execSummary.skipped > 0 ? `, skipped ${execSummary.skipped}` : ""}`);
56227
56247
  ui.phase("Finalizing post-install");
56228
56248
  if (items.hooks.length > 0) {
56229
- installCodexHookSupportDirs(items.hooks, options2.global);
56230
- writeCodexEnvMarker(options2.global);
56249
+ installCodexHookSupportDirs(items.hooks, options2.global, options2.projectRoot);
56250
+ writeCodexEnvMarker(options2.global, options2.projectRoot);
56231
56251
  }
56232
- await pruneCodexDeletedHooks(items, options2.global);
56233
- await mergeInstalledHooks(successfulHookFiles, options2.global, deriveKitHookSource(items));
56234
- await cleanupStaleCodexToml(options2.global);
56252
+ await pruneCodexDeletedHooks(items, options2.global, options2.projectRoot);
56253
+ await mergeInstalledHooks(successfulHookFiles, options2.global, deriveKitHookSource(items), options2.projectRoot);
56254
+ await cleanupStaleCodexToml(options2.global, options2.projectRoot);
56235
56255
  await healRegistryChecksums(plan.actions, registry);
56236
56256
  await bumpAppliedManifestVersion(items);
56237
56257
  ui.success("Hooks merged, registry healed");
@@ -56252,7 +56272,7 @@ import { join as join64 } from "node:path";
56252
56272
  // src/domains/installers/codex/skills-paths.ts
56253
56273
  import { homedir as homedir20 } from "node:os";
56254
56274
  import { resolve as resolve15 } from "node:path";
56255
- function getCodexSkillsTargetDir(global3) {
56275
+ function getCodexSkillsTargetDir(global3, projectRoot) {
56256
56276
  const cfg = providers.codex.skills;
56257
56277
  if (!cfg) {
56258
56278
  throw new Error("[codex] skills configuration missing from provider registry");
@@ -56261,8 +56281,9 @@ function getCodexSkillsTargetDir(global3) {
56261
56281
  if (!path7) {
56262
56282
  throw new Error(`[codex] no ${global3 ? "global" : "project"}-level skills path configured`);
56263
56283
  }
56264
- const resolved = resolve15(path7);
56265
- const boundary = global3 ? homedir20() : process.cwd();
56284
+ const projectBase = projectRoot ?? process.cwd();
56285
+ const resolved = global3 ? resolve15(path7) : resolve15(projectBase, path7);
56286
+ const boundary = global3 ? homedir20() : projectBase;
56266
56287
  if (!isPathWithinBoundary3(resolved, boundary)) {
56267
56288
  throw new Error(`[codex] resolved skills path "${resolved}" escapes boundary "${boundary}"`);
56268
56289
  }
@@ -56437,6 +56458,7 @@ var codexInstaller = {
56437
56458
  items = { ...items, commands: [] };
56438
56459
  }
56439
56460
  }
56461
+ const projectRoot = ctx.resolvedDir;
56440
56462
  if (ctx.options.fresh) {
56441
56463
  const confirmed = await confirmFresh(ctx, installGlobally);
56442
56464
  if (!confirmed) {
@@ -56448,12 +56470,13 @@ var codexInstaller = {
56448
56470
  cancelled: true
56449
56471
  };
56450
56472
  }
56451
- await wipeCodexTargets(installGlobally);
56473
+ await wipeCodexTargets(installGlobally, projectRoot);
56452
56474
  }
56453
56475
  const interactive = !ctx.isNonInteractive && Boolean(process.stdout.isTTY);
56454
56476
  const useColor = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;
56455
56477
  const { results } = await executeCodexPipeline(items, {
56456
56478
  global: installGlobally,
56479
+ projectRoot,
56457
56480
  force: ctx.options.force,
56458
56481
  dryRun: ctx.options.dryRun,
56459
56482
  interactive,
@@ -56463,7 +56486,7 @@ var codexInstaller = {
56463
56486
  return { provider: "codex", success: true, installedFiles: [], cancelled: true };
56464
56487
  }
56465
56488
  const hasSkills = items.skills.length > 0;
56466
- const codexSkillsDir = hasSkills ? getCodexSkillsTargetDir(installGlobally) : null;
56489
+ const codexSkillsDir = hasSkills ? getCodexSkillsTargetDir(installGlobally, projectRoot) : null;
56467
56490
  let auxCopySucceeded = false;
56468
56491
  if (hasSkills && sources.skills && codexSkillsDir) {
56469
56492
  try {
@@ -56542,15 +56565,17 @@ async function confirmFresh(ctx, global3) {
56542
56565
  return false;
56543
56566
  return Boolean(result);
56544
56567
  }
56545
- async function wipeCodexTargets(global3) {
56568
+ async function wipeCodexTargets(global3, projectRoot) {
56546
56569
  const codexConfig = providers.codex;
56547
- const targetPaths = [
56570
+ const rawPaths = [
56548
56571
  global3 ? codexConfig.agents?.globalPath : codexConfig.agents?.projectPath,
56549
56572
  global3 ? codexConfig.commands?.globalPath : codexConfig.commands?.projectPath,
56550
56573
  global3 ? codexConfig.hooks?.globalPath : codexConfig.hooks?.projectPath,
56551
56574
  global3 ? codexConfig.settingsJsonPath?.globalPath : codexConfig.settingsJsonPath?.projectPath,
56552
56575
  global3 ? codexConfig.config?.globalPath : codexConfig.config?.projectPath
56553
56576
  ].filter((p) => Boolean(p));
56577
+ const projectBase = projectRoot ?? process.cwd();
56578
+ const targetPaths = rawPaths.map((p) => global3 ? p : join67(projectBase, p));
56554
56579
  for (const path7 of targetPaths) {
56555
56580
  if (existsSync31(path7)) {
56556
56581
  try {
@@ -65058,6 +65083,14 @@ async function resolveOptions(ctx) {
65058
65083
  validOptions.agents = Array.from(new Set(validOptions.agents));
65059
65084
  }
65060
65085
  ConfigManager.setGlobalFlag(validOptions.global);
65086
+ if (validOptions.global && explicitDir) {
65087
+ throw new Error(`Options --global and --dir are mutually exclusive.
65088
+
65089
+ ` + ` --global: Install to ~/.claude (or ~/.codex) — platform-wide
65090
+ ` + ` --dir: Install to a specific project root
65091
+
65092
+ ` + "Choose one.");
65093
+ }
65061
65094
  if (validOptions.global) {
65062
65095
  logger.info("Global mode enabled - using platform-specific user configuration");
65063
65096
  }
@@ -70906,7 +70939,7 @@ var import_fs_extra37 = __toESM(require_lib(), 1);
70906
70939
  // package.json
70907
70940
  var package_default = {
70908
70941
  name: "@sunasteriskrnd/takumi",
70909
- version: "1.0.0-dev.16",
70942
+ version: "1.0.0-dev.17",
70910
70943
  description: "CLI tool for bootstrapping and managing Takumi projects",
70911
70944
  type: "module",
70912
70945
  repository: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sunasteriskrnd/takumi",
3
- "version": "1.0.0-dev.16",
3
+ "version": "1.0.0-dev.17",
4
4
  "description": "CLI tool for bootstrapping and managing Takumi projects",
5
5
  "type": "module",
6
6
  "repository": {