@sunasteriskrnd/takumi 1.0.0-dev.61 → 1.0.0-dev.62

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 +1064 -587
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -19815,7 +19815,7 @@ var package_default;
19815
19815
  var init_package = __esm(() => {
19816
19816
  package_default = {
19817
19817
  name: "@sunasteriskrnd/takumi",
19818
- version: "1.0.0-dev.61",
19818
+ version: "1.0.0-dev.62",
19819
19819
  description: "CLI tool for bootstrapping and managing Takumi projects",
19820
19820
  type: "module",
19821
19821
  repository: {
@@ -20012,7 +20012,7 @@ function getLegacyManifestPath(providerRoot) {
20012
20012
  return join4(providerRoot, LEGACY_MANIFEST_FILENAME);
20013
20013
  }
20014
20014
  function getCliVersion() {
20015
- return "1.0.0-dev.61"?.trim() || process.env.npm_package_version?.trim() || "unknown";
20015
+ return "1.0.0-dev.62"?.trim() || process.env.npm_package_version?.trim() || "unknown";
20016
20016
  }
20017
20017
  function getCliUserAgent() {
20018
20018
  return `${TAKUMI_CLI_NPM_PACKAGE_NAME}/${getCliVersion()}`;
@@ -22554,7 +22554,7 @@ function normalizeTakumiConfigInput(value) {
22554
22554
  }
22555
22555
  return normalized;
22556
22556
  }
22557
- var PlanValidationModeSchema, PlanFocusAreaSchema, PlanResolutionOrderSchema, ProjectTypeSchema, PackageManagerSchema, FrameworkSchema, GEMINI_MODEL_VALUES, LEGACY_GEMINI_MODEL_ALIASES, GeminiModelSchema, StatuslineModeSchema, StatuslineSectionIdSchema, StatuslineSectionConfigSchema, StatuslineThemeSchema, StatuslineLayoutSchema, StatuslineBarStyleSchema, StatuslineConfigSchema, CodingLevelSchema, PlanResolutionSchema, PlanValidationSchema, SkPlanConfigSchema, SkDocsConfigSchema, SkPathsConfigSchema, SkLocaleConfigSchema, SkTrustConfigSchema, SkGraphifyConfigSchema, SkProjectConfigSchema, SkGeminiConfigSchema, SkSkillsConfigSchema, SkSkillExtensionsConfigSchema, UpdatePipelineSchema, ResolvedModelConfigSchema, ModelTierMapSchema, SkModelTaxonomySchema, SkAssertionSchema, SkHooksConfigSchema, TakumiConfigSchema, DEFAULT_TAKUMI_CONFIG, TAKUMI_HOOK_NAMES;
22557
+ var PlanValidationModeSchema, PlanFocusAreaSchema, PlanResolutionOrderSchema, ProjectTypeSchema, PackageManagerSchema, FrameworkSchema, GEMINI_MODEL_VALUES, LEGACY_GEMINI_MODEL_ALIASES, GeminiModelSchema, StatuslineModeSchema, StatuslineSectionIdSchema, StatuslineSectionConfigSchema, StatuslineThemeSchema, StatuslineLayoutSchema, StatuslineBarStyleSchema, StatuslineConfigSchema, CodingLevelSchema, PlanResolutionSchema, PlanValidationSchema, SkPlanConfigSchema, SkDocsConfigSchema, SkPathsConfigSchema, SkLocaleConfigSchema, SkTrustConfigSchema, SkGraphifyConfigSchema, SkProjectConfigSchema, SkGeminiConfigSchema, SkSkillsConfigSchema, SkSkillExtensionsConfigSchema, SkTakumiConfigSchema, SkSubagentAgentConfigSchema, SkSubagentConfigSchema, UpdatePipelineSchema, ResolvedModelConfigSchema, ModelTierMapSchema, SkModelTaxonomySchema, SkAssertionSchema, SkHooksConfigSchema, TakumiConfigSchema, DEFAULT_TAKUMI_CONFIG, TAKUMI_HOOK_NAMES;
22558
22558
  var init_takumi_config = __esm(() => {
22559
22559
  init_zod();
22560
22560
  PlanValidationModeSchema = exports_external.enum(["prompt", "auto", "strict", "none"]);
@@ -22739,6 +22739,15 @@ var init_takumi_config = __esm(() => {
22739
22739
  SkSkillExtensionsConfigSchema = exports_external.object({
22740
22740
  sharedDir: exports_external.string().optional()
22741
22741
  }).passthrough();
22742
+ SkTakumiConfigSchema = exports_external.object({
22743
+ sddMode: exports_external.enum(["ask", "on", "off"]).optional()
22744
+ }).passthrough();
22745
+ SkSubagentAgentConfigSchema = exports_external.object({
22746
+ contextPrefix: exports_external.string().optional()
22747
+ }).passthrough();
22748
+ SkSubagentConfigSchema = exports_external.object({
22749
+ agents: exports_external.record(exports_external.string(), SkSubagentAgentConfigSchema).optional()
22750
+ }).passthrough();
22742
22751
  UpdatePipelineSchema = exports_external.object({
22743
22752
  autoInitAfterUpdate: exports_external.boolean().default(false)
22744
22753
  });
@@ -22787,6 +22796,8 @@ var init_takumi_config = __esm(() => {
22787
22796
  gemini: SkGeminiConfigSchema.optional(),
22788
22797
  skills: SkSkillsConfigSchema.optional(),
22789
22798
  skillExtensions: SkSkillExtensionsConfigSchema.optional(),
22799
+ takumi: SkTakumiConfigSchema.optional(),
22800
+ subagent: SkSubagentConfigSchema.optional(),
22790
22801
  assertions: exports_external.array(SkAssertionSchema).optional(),
22791
22802
  hooks: SkHooksConfigSchema.optional(),
22792
22803
  updatePipeline: UpdatePipelineSchema.optional(),
@@ -33976,17 +33987,13 @@ var init_settings_merger = __esm(() => {
33976
33987
  });
33977
33988
 
33978
33989
  // src/domains/installation/merger/settings-processor.ts
33979
- import { execSync } from "node:child_process";
33980
-
33981
33990
  class SettingsProcessor {
33982
- static MIN_TEAM_HOOKS_VERSION = "2.1.33";
33983
33991
  isGlobal = false;
33984
33992
  forceOverwriteSettings = false;
33985
33993
  projectDir = "";
33986
33994
  kitName = "engineer";
33987
33995
  tracker = null;
33988
33996
  installingKit;
33989
- cachedVersion = undefined;
33990
33997
  deletionPatterns = [];
33991
33998
  setGlobalFlag(isGlobal) {
33992
33999
  this.isGlobal = isGlobal;
@@ -34052,7 +34059,6 @@ class SettingsProcessor {
34052
34059
  const formattedContent = this.formatJsonContent(transformedSource);
34053
34060
  await import_fs_extra11.writeFile(destFile, formattedContent, "utf-8");
34054
34061
  }
34055
- await this.injectTeamHooksIfSupported(destFile);
34056
34062
  }
34057
34063
  } catch (error) {
34058
34064
  logger.error(`Failed to process settings.json: ${error}`);
@@ -34122,7 +34128,6 @@ class SettingsProcessor {
34122
34128
  }
34123
34129
  await SettingsMerger.writeSettingsFile(destFile, mergeResult.merged);
34124
34130
  logger.success("Merged settings.json (user customizations preserved)");
34125
- await this.injectTeamHooksIfSupported(destFile, mergeResult.merged);
34126
34131
  }
34127
34132
  migrateDeprecatedMatchers(destSettings, sourceSettings) {
34128
34133
  if (!destSettings.hooks || !sourceSettings.hooks)
@@ -34389,87 +34394,13 @@ class SettingsProcessor {
34389
34394
  return capturedVar;
34390
34395
  }
34391
34396
  }
34392
- detectClaudeCodeVersion() {
34393
- if (this.cachedVersion !== undefined)
34394
- return this.cachedVersion;
34395
- try {
34396
- const output2 = execSync("claude --version", {
34397
- encoding: "utf-8",
34398
- timeout: 5000,
34399
- stdio: ["ignore", "pipe", "ignore"]
34400
- });
34401
- const match = output2.match(/(\d+\.\d+\.\d+)/);
34402
- this.cachedVersion = match ? match[1] : null;
34403
- } catch {
34404
- this.cachedVersion = null;
34405
- }
34406
- return this.cachedVersion;
34407
- }
34408
- isVersionAtLeast(version3, minimum) {
34409
- const coerced = import_semver2.default.coerce(version3);
34410
- if (!coerced)
34411
- return false;
34412
- return import_semver2.default.gte(coerced, minimum);
34413
- }
34414
- async injectTeamHooksIfSupported(destFile, existingSettings) {
34415
- const version3 = this.detectClaudeCodeVersion();
34416
- if (!version3) {
34417
- logger.debug("Claude Code version not detected, skipping team hooks injection");
34418
- return;
34419
- }
34420
- if (!this.isVersionAtLeast(version3, SettingsProcessor.MIN_TEAM_HOOKS_VERSION)) {
34421
- logger.debug(`Claude Code ${version3} does not support team hooks (requires >= 2.1.33), skipping injection`);
34422
- return;
34423
- }
34424
- logger.debug(`Claude Code ${version3} detected, checking team hooks`);
34425
- const settings = existingSettings ?? await SettingsMerger.readSettingsFile(destFile);
34426
- if (!settings) {
34427
- logger.warning("Failed to read settings file for team hooks injection");
34428
- return;
34429
- }
34430
- if (!settings.hooks) {
34431
- settings.hooks = {};
34432
- }
34433
- let injected = false;
34434
- const installedSettings = this.tracker ? await this.tracker.loadInstalledSettings() : { hooks: [], mcpServers: [] };
34435
- const teamHooks = [
34436
- { event: "TaskCompleted", handler: "task-completed-handler.cjs" },
34437
- { event: "TeammateIdle", handler: "teammate-idle-handler.cjs" }
34438
- ];
34439
- for (const { event, handler } of teamHooks) {
34440
- const hookCommand = this.formatCommandPath("node ", this.isGlobal ? "$HOME" : "$CLAUDE_PROJECT_DIR", `.claude/hooks/${handler}`);
34441
- const eventHooks = settings.hooks[event];
34442
- if (eventHooks && eventHooks.length > 0)
34443
- continue;
34444
- if (this.tracker?.wasHookInstalled(hookCommand, installedSettings)) {
34445
- logger.debug(`Skipping ${event} hook injection (previously removed by user)`);
34446
- continue;
34447
- }
34448
- settings.hooks[event] = [{ hooks: [{ type: "command", command: hookCommand }] }];
34449
- logger.info(`Injected ${event} hook`);
34450
- injected = true;
34451
- if (this.tracker) {
34452
- this.tracker.trackHook(hookCommand, installedSettings);
34453
- }
34454
- }
34455
- if (injected) {
34456
- await SettingsMerger.writeSettingsFile(destFile, settings);
34457
- if (this.tracker) {
34458
- await this.tracker.saveInstalledSettings(installedSettings);
34459
- }
34460
- logger.success("Team hooks injected successfully");
34461
- } else {
34462
- logger.debug("Team hooks already present, no injection needed");
34463
- }
34464
- }
34465
34397
  }
34466
- var import_fs_extra11, import_semver2;
34398
+ var import_fs_extra11;
34467
34399
  var init_settings_processor = __esm(() => {
34468
34400
  init_installed_settings_tracker();
34469
34401
  init_settings_merger();
34470
34402
  init_logger();
34471
34403
  import_fs_extra11 = __toESM(require_lib(), 1);
34472
- import_semver2 = __toESM(require_semver2(), 1);
34473
34404
  });
34474
34405
 
34475
34406
  // src/domains/installation/merger/copy-executor.ts
@@ -40953,7 +40884,7 @@ async function loadPortableManifest(kitPath) {
40953
40884
  }
40954
40885
  }
40955
40886
  function getApplicableEntries(entries, appliedVersion, currentVersion) {
40956
- const normalizedCurrentVersionRaw = import_semver3.default.valid(currentVersion);
40887
+ const normalizedCurrentVersionRaw = import_semver2.default.valid(currentVersion);
40957
40888
  if (!normalizedCurrentVersionRaw) {
40958
40889
  logger.verbose(`Invalid manifest current version "${currentVersion}" — skipping manifest entries safely`);
40959
40890
  return [];
@@ -40961,34 +40892,34 @@ function getApplicableEntries(entries, appliedVersion, currentVersion) {
40961
40892
  const normalizedCurrentVersion = normalizedCurrentVersionRaw;
40962
40893
  let normalizedAppliedVersion;
40963
40894
  if (appliedVersion) {
40964
- const normalizedAppliedVersionRaw = import_semver3.default.valid(appliedVersion);
40895
+ const normalizedAppliedVersionRaw = import_semver2.default.valid(appliedVersion);
40965
40896
  if (!normalizedAppliedVersionRaw) {
40966
40897
  logger.verbose(`Invalid applied manifest version "${appliedVersion}" — skipping manifest entries safely`);
40967
40898
  return [];
40968
40899
  }
40969
40900
  normalizedAppliedVersion = normalizedAppliedVersionRaw;
40970
- if (import_semver3.default.gt(normalizedAppliedVersion, normalizedCurrentVersion)) {
40901
+ if (import_semver2.default.gt(normalizedAppliedVersion, normalizedCurrentVersion)) {
40971
40902
  logger.verbose(`Applied manifest version ${normalizedAppliedVersion} is newer than current ${normalizedCurrentVersion} — skipping manifest entries safely`);
40972
40903
  return [];
40973
40904
  }
40974
40905
  }
40975
40906
  return entries.filter((entry) => {
40976
- const normalizedSince = import_semver3.default.valid(entry.since);
40907
+ const normalizedSince = import_semver2.default.valid(entry.since);
40977
40908
  if (!normalizedSince) {
40978
40909
  logger.verbose(`Skipping manifest entry with invalid "since" version: ${entry.since}`);
40979
40910
  return false;
40980
40911
  }
40981
40912
  if (!normalizedAppliedVersion) {
40982
- return import_semver3.default.lte(normalizedSince, normalizedCurrentVersion);
40913
+ return import_semver2.default.lte(normalizedSince, normalizedCurrentVersion);
40983
40914
  }
40984
- return import_semver3.default.gt(normalizedSince, normalizedAppliedVersion) && import_semver3.default.lte(normalizedSince, normalizedCurrentVersion);
40915
+ return import_semver2.default.gt(normalizedSince, normalizedAppliedVersion) && import_semver2.default.lte(normalizedSince, normalizedCurrentVersion);
40985
40916
  });
40986
40917
  }
40987
- var import_semver3, safeRelativePath, RenameEntrySchema, ProviderPathMigrationSchema, SectionRenameSchema, PortableManifestSchema;
40918
+ var import_semver2, safeRelativePath, RenameEntrySchema, ProviderPathMigrationSchema, SectionRenameSchema, PortableManifestSchema;
40988
40919
  var init_portable_manifest = __esm(() => {
40989
40920
  init_zod();
40990
40921
  init_logger();
40991
- import_semver3 = __toESM(require_semver2(), 1);
40922
+ import_semver2 = __toESM(require_semver2(), 1);
40992
40923
  safeRelativePath = exports_external.string().min(1).refine((p) => !p.includes("..") && !path2.isAbsolute(p), {
40993
40924
  message: "Path must be relative without traversal"
40994
40925
  });
@@ -41300,26 +41231,26 @@ function findCapabilitiesForVersion(version3) {
41300
41231
  const exact = CODEX_CAPABILITY_TABLE.find((entry) => entry.version === version3);
41301
41232
  if (exact)
41302
41233
  return exact;
41303
- const coercedDetected = import_semver4.default.coerce(version3);
41234
+ const coercedDetected = import_semver3.default.coerce(version3);
41304
41235
  if (!coercedDetected)
41305
41236
  return null;
41306
41237
  for (const entry of CODEX_CAPABILITY_TABLE) {
41307
- const coercedEntry = import_semver4.default.coerce(entry.version);
41238
+ const coercedEntry = import_semver3.default.coerce(entry.version);
41308
41239
  if (!coercedEntry)
41309
41240
  continue;
41310
41241
  if (coercedDetected.major === coercedEntry.major && coercedDetected.minor === coercedEntry.minor) {
41311
41242
  return entry;
41312
41243
  }
41313
- if (import_semver4.default.gte(coercedDetected, coercedEntry)) {
41244
+ if (import_semver3.default.gte(coercedDetected, coercedEntry)) {
41314
41245
  return entry;
41315
41246
  }
41316
41247
  }
41317
41248
  return null;
41318
41249
  }
41319
- var import_semver4, execFileAsync2, CODEX_CAPABILITY_TABLE, FALLBACK_CAPABILITIES, CODEX_SUPPORTED_EVENTS;
41250
+ var import_semver3, execFileAsync2, CODEX_CAPABILITY_TABLE, FALLBACK_CAPABILITIES, CODEX_SUPPORTED_EVENTS;
41320
41251
  var init_capabilities = __esm(() => {
41321
41252
  init_logger();
41322
- import_semver4 = __toESM(require_semver2(), 1);
41253
+ import_semver3 = __toESM(require_semver2(), 1);
41323
41254
  execFileAsync2 = promisify2(execFile2);
41324
41255
  CODEX_CAPABILITY_TABLE = [
41325
41256
  {
@@ -41432,9 +41363,9 @@ var init_capabilities = __esm(() => {
41432
41363
  ];
41433
41364
  if (CODEX_CAPABILITY_TABLE.length > 1) {
41434
41365
  for (let i = 0;i < CODEX_CAPABILITY_TABLE.length - 1; i++) {
41435
- const newer = import_semver4.default.coerce(CODEX_CAPABILITY_TABLE[i].version);
41436
- const older = import_semver4.default.coerce(CODEX_CAPABILITY_TABLE[i + 1].version);
41437
- if (newer && older && !import_semver4.default.gte(newer, older)) {
41366
+ const newer = import_semver3.default.coerce(CODEX_CAPABILITY_TABLE[i].version);
41367
+ const older = import_semver3.default.coerce(CODEX_CAPABILITY_TABLE[i + 1].version);
41368
+ if (newer && older && !import_semver3.default.gte(newer, older)) {
41438
41369
  throw new Error(`[ck] CODEX_CAPABILITY_TABLE ordering violation: entry[${i}] (${CODEX_CAPABILITY_TABLE[i].version}) must be >= entry[${i + 1}] (${CODEX_CAPABILITY_TABLE[i + 1].version}). Table must be sorted newest-first.`);
41439
41370
  }
41440
41371
  }
@@ -44296,6 +44227,23 @@ var init_agent_prune = __esm(() => {
44296
44227
  init_post_pipeline();
44297
44228
  });
44298
44229
 
44230
+ // src/domains/installers/codex/codex-paths.ts
44231
+ import { homedir as homedir16 } from "node:os";
44232
+ import { join as join60 } from "node:path";
44233
+ function codexGlobalRoot() {
44234
+ const testHome = process.env.TAKUMI_TEST_HOME;
44235
+ if (testHome && testHome.trim() !== "")
44236
+ return join60(testHome, ".codex");
44237
+ const codexHome = process.env.CODEX_HOME;
44238
+ if (codexHome && codexHome.trim() !== "" && !codexHome.includes(".."))
44239
+ return codexHome;
44240
+ const xdg = process.env.XDG_CONFIG_HOME;
44241
+ if (xdg && xdg.trim() !== "" && !xdg.includes(".."))
44242
+ return join60(xdg, "codex");
44243
+ return join60(homedir16(), ".codex");
44244
+ }
44245
+ var init_codex_paths = () => {};
44246
+
44299
44247
  // src/commands/portable/output-sanitizer.ts
44300
44248
  function isDisallowedControlCode(codePoint) {
44301
44249
  return codePoint >= 0 && codePoint <= 8 || codePoint >= 11 && codePoint <= 26 || codePoint >= 28 && codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
@@ -44916,7 +44864,7 @@ var init_reconciler = __esm(() => {
44916
44864
 
44917
44865
  // src/domains/installers/codex/codex-env-marker.ts
44918
44866
  import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "node:fs";
44919
- import { join as join60 } from "node:path";
44867
+ import { join as join61 } from "node:path";
44920
44868
  function writeCodexEnvMarker(global3, projectRoot) {
44921
44869
  try {
44922
44870
  const pathConfig = providers.codex.hooks;
@@ -44925,10 +44873,10 @@ function writeCodexEnvMarker(global3, projectRoot) {
44925
44873
  const scopedPath = global3 ? pathConfig.globalPath : pathConfig.projectPath;
44926
44874
  if (!scopedPath)
44927
44875
  return;
44928
- const targetHooksDir = global3 ? scopedPath : join60(projectRoot ?? process.cwd(), scopedPath);
44929
- const libDir = join60(targetHooksDir, "lib");
44876
+ const targetHooksDir = global3 ? scopedPath : join61(projectRoot ?? process.cwd(), scopedPath);
44877
+ const libDir = join61(targetHooksDir, "lib");
44930
44878
  mkdirSync3(libDir, { recursive: true });
44931
- writeFileSync5(join60(libDir, "env.cjs"), CODEX_ENV_MARKER);
44879
+ writeFileSync5(join61(libDir, "env.cjs"), CODEX_ENV_MARKER);
44932
44880
  } catch (e2) {
44933
44881
  logger.debug(`[init/codex] writeCodexEnvMarker failed: ${String(e2)}`);
44934
44882
  }
@@ -44942,7 +44890,7 @@ var init_codex_env_marker = __esm(() => {
44942
44890
 
44943
44891
  // src/domains/installers/shared/writers/install-one-file.ts
44944
44892
  import { writeFile as writeFile18 } from "node:fs/promises";
44945
- import { dirname as dirname18, join as join61, resolve as resolve15, sep as sep5 } from "node:path";
44893
+ import { dirname as dirname18, join as join62, resolve as resolve15, sep as sep5 } from "node:path";
44946
44894
  async function installOneFile(item, provider, kind, options2) {
44947
44895
  const config = providers[provider];
44948
44896
  const typeKey = getProviderPathKey(kind);
@@ -44998,7 +44946,7 @@ async function installOneFile(item, provider, kind, options2) {
44998
44946
  const nameWithoutExt = extIdx >= 0 ? resolvedFilename.substring(0, extIdx) : resolvedFilename;
44999
44947
  resolvedFilename = `${nameWithoutExt.replace(/\//g, "-")}${ext}`;
45000
44948
  }
45001
- targetPath = pathConfig.writeStrategy === "single-file" ? basePath : join61(basePath, resolvedFilename);
44949
+ targetPath = pathConfig.writeStrategy === "single-file" ? basePath : join62(basePath, resolvedFilename);
45002
44950
  const resolvedTarget = resolve15(targetPath);
45003
44951
  const resolvedBase = pathConfig.writeStrategy === "single-file" ? resolve15(dirname18(basePath)) : resolve15(basePath);
45004
44952
  if (!resolvedTarget.startsWith(resolvedBase + sep5) && resolvedTarget !== resolvedBase) {
@@ -45638,7 +45586,7 @@ var init_install_items = __esm(() => {
45638
45586
  // src/domains/installers/shared/skill-directory-installer.ts
45639
45587
  import { existsSync as existsSync25 } from "node:fs";
45640
45588
  import { cp as cp3, mkdir as mkdir13, rename as rename6, rm as rm5 } from "node:fs/promises";
45641
- import { join as join62, resolve as resolve16 } from "node:path";
45589
+ import { join as join63, resolve as resolve16 } from "node:path";
45642
45590
  async function installSkillDirectories(skills, targetProviders, options2) {
45643
45591
  const results = [];
45644
45592
  for (const provider of targetProviders) {
@@ -45667,7 +45615,7 @@ async function installSkillDirectories(skills, targetProviders, options2) {
45667
45615
  }
45668
45616
  const basePath = resolveInstallBasePath(rawBasePath, options2);
45669
45617
  for (const skill of skills) {
45670
- const targetDir = join62(basePath, skill.name);
45618
+ const targetDir = join63(basePath, skill.name);
45671
45619
  if (resolve16(skill.path) === resolve16(targetDir)) {
45672
45620
  results.push({
45673
45621
  provider,
@@ -46030,19 +45978,19 @@ var init_reconcile_helpers = __esm(() => {
46030
45978
  // src/commands/portable/config-discovery.ts
46031
45979
  import { existsSync as existsSync27 } from "node:fs";
46032
45980
  import { readFile as readFile31, readdir as readdir20 } from "node:fs/promises";
46033
- import { homedir as homedir16 } from "node:os";
46034
- import { extname as extname4, join as join63, relative as relative12, sep as sep6 } from "node:path";
45981
+ import { homedir as homedir17 } from "node:os";
45982
+ import { extname as extname4, join as join64, relative as relative12, sep as sep6 } from "node:path";
46035
45983
  function getConfigSourcePath() {
46036
45984
  return findExistingProjectConfigPath(process.cwd()) ?? getGlobalConfigSourcePath();
46037
45985
  }
46038
45986
  function getGlobalConfigSourcePath() {
46039
- return join63(homedir16(), ".claude", "CLAUDE.md");
45987
+ return join64(homedir17(), ".claude", "CLAUDE.md");
46040
45988
  }
46041
45989
  function getRulesSourcePath() {
46042
- return findExistingProjectLayoutPath(process.cwd(), "rules") ?? join63(homedir16(), ".claude", "rules");
45990
+ return findExistingProjectLayoutPath(process.cwd(), "rules") ?? join64(homedir17(), ".claude", "rules");
46043
45991
  }
46044
45992
  function getHooksSourcePath() {
46045
- return findExistingProjectLayoutPath(process.cwd(), "hooks") ?? join63(homedir16(), ".claude", "hooks");
45993
+ return findExistingProjectLayoutPath(process.cwd(), "hooks") ?? join64(homedir17(), ".claude", "hooks");
46046
45994
  }
46047
45995
  async function discoverConfig(sourcePath) {
46048
45996
  const path5 = sourcePath ?? getConfigSourcePath();
@@ -46094,7 +46042,7 @@ async function discoverHooks(sourcePath) {
46094
46042
  }
46095
46043
  if (!HOOK_EXTENSIONS.has(ext))
46096
46044
  continue;
46097
- const fullPath = join63(path5, entry.name);
46045
+ const fullPath = join64(path5, entry.name);
46098
46046
  try {
46099
46047
  const content = await readFile31(fullPath, "utf-8");
46100
46048
  items.push({
@@ -46120,7 +46068,7 @@ async function discoverPortableFiles(dir, baseDir, options2) {
46120
46068
  for (const entry of entries) {
46121
46069
  if (entry.name.startsWith("."))
46122
46070
  continue;
46123
- const fullPath = join63(dir, entry.name);
46071
+ const fullPath = join64(dir, entry.name);
46124
46072
  if (entry.isSymbolicLink()) {
46125
46073
  continue;
46126
46074
  }
@@ -46163,12 +46111,12 @@ var init_config_discovery = __esm(() => {
46163
46111
 
46164
46112
  // src/domains/installers/shared/commands-discovery.ts
46165
46113
  import { readdir as readdir21 } from "node:fs/promises";
46166
- import { homedir as homedir17 } from "node:os";
46167
- import { join as join64, relative as relative13 } from "node:path";
46114
+ import { homedir as homedir18 } from "node:os";
46115
+ import { join as join65, relative as relative13 } from "node:path";
46168
46116
  function getCommandSourcePath() {
46169
46117
  return findFirstExistingPath([
46170
46118
  ...getProjectLayoutCandidates(process.cwd(), "commands"),
46171
- join64(home5, ".claude/commands")
46119
+ join65(home5, ".claude/commands")
46172
46120
  ]);
46173
46121
  }
46174
46122
  async function scanCommandDir(dir, rootDir) {
@@ -46176,7 +46124,7 @@ async function scanCommandDir(dir, rootDir) {
46176
46124
  try {
46177
46125
  const entries = await readdir21(dir, { withFileTypes: true });
46178
46126
  for (const entry of entries) {
46179
- const fullPath = join64(dir, entry.name);
46127
+ const fullPath = join65(dir, entry.name);
46180
46128
  if (entry.isDirectory()) {
46181
46129
  if (SKIP_DIRS2.includes(entry.name))
46182
46130
  continue;
@@ -46219,7 +46167,7 @@ var init_commands_discovery = __esm(() => {
46219
46167
  init_frontmatter_parser();
46220
46168
  init_kit_layout();
46221
46169
  init_logger();
46222
- home5 = homedir17();
46170
+ home5 = homedir18();
46223
46171
  SKIP_DIRS2 = ["node_modules", ".git", "dist", "build"];
46224
46172
  });
46225
46173
 
@@ -46328,8 +46276,8 @@ __export(exports_takumi_config_manager, {
46328
46276
  });
46329
46277
  import { existsSync as existsSync28 } from "node:fs";
46330
46278
  import { mkdir as mkdir14, readFile as readFile33, writeFile as writeFile20 } from "node:fs/promises";
46331
- import { homedir as homedir18 } from "node:os";
46332
- import { join as join65 } from "node:path";
46279
+ import { homedir as homedir19 } from "node:os";
46280
+ import { join as join66 } from "node:path";
46333
46281
  function getNestedValue(obj, path5) {
46334
46282
  if (!obj || typeof obj !== "object")
46335
46283
  return;
@@ -46403,25 +46351,25 @@ function valuesEqual(a3, b3) {
46403
46351
 
46404
46352
  class TakumiConfigManager {
46405
46353
  static getGlobalConfigDir() {
46406
- return join65(homedir18(), ".claude");
46354
+ return join66(homedir19(), ".claude");
46407
46355
  }
46408
46356
  static resolveConfigPath(dir) {
46409
- const preferred = join65(dir, TAKUMI_CONFIG_FILE);
46357
+ const preferred = join66(dir, TAKUMI_CONFIG_FILE);
46410
46358
  if (existsSync28(preferred))
46411
46359
  return preferred;
46412
- const legacy = join65(dir, LEGACY_TAKUMI_CONFIG_FILE);
46360
+ const legacy = join66(dir, LEGACY_TAKUMI_CONFIG_FILE);
46413
46361
  if (existsSync28(legacy))
46414
46362
  return legacy;
46415
46363
  return preferred;
46416
46364
  }
46417
46365
  static configFileExistsIn(dir) {
46418
- return existsSync28(join65(dir, TAKUMI_CONFIG_FILE)) || existsSync28(join65(dir, LEGACY_TAKUMI_CONFIG_FILE));
46366
+ return existsSync28(join66(dir, TAKUMI_CONFIG_FILE)) || existsSync28(join66(dir, LEGACY_TAKUMI_CONFIG_FILE));
46419
46367
  }
46420
46368
  static getGlobalConfigPath() {
46421
46369
  return TakumiConfigManager.resolveConfigPath(TakumiConfigManager.getGlobalConfigDir());
46422
46370
  }
46423
46371
  static getProjectConfigDir(projectDir) {
46424
- return join65(projectDir, ".claude");
46372
+ return join66(projectDir, ".claude");
46425
46373
  }
46426
46374
  static getProjectConfigPath(projectDir) {
46427
46375
  return TakumiConfigManager.resolveConfigPath(TakumiConfigManager.getProjectConfigDir(projectDir));
@@ -46703,7 +46651,7 @@ var init_install_pipeline = __esm(() => {
46703
46651
  });
46704
46652
 
46705
46653
  // src/domains/installers/codex/skills-paths.ts
46706
- import { homedir as homedir19 } from "node:os";
46654
+ import { homedir as homedir20 } from "node:os";
46707
46655
  import { resolve as resolve17 } from "node:path";
46708
46656
  function getCodexSkillsTargetDir(global3, projectRoot) {
46709
46657
  const cfg = providers.codex.skills;
@@ -46716,7 +46664,7 @@ function getCodexSkillsTargetDir(global3, projectRoot) {
46716
46664
  }
46717
46665
  const projectBase = projectRoot ?? process.cwd();
46718
46666
  const resolved = global3 ? resolve17(path5) : resolve17(projectBase, path5);
46719
- const boundary = global3 ? homedir19() : projectBase;
46667
+ const boundary = global3 ? homedir20() : projectBase;
46720
46668
  if (!isPathWithinBoundary(resolved, boundary)) {
46721
46669
  throw new Error(`[codex] resolved skills path "${resolved}" escapes boundary "${boundary}"`);
46722
46670
  }
@@ -46728,7 +46676,7 @@ var init_skills_paths = __esm(() => {
46728
46676
  });
46729
46677
 
46730
46678
  // src/domains/installers/codex/scan-codex-directory.ts
46731
- import { join as join66 } from "node:path";
46679
+ import { join as join67 } from "node:path";
46732
46680
  async function scanCodexDirectory(root, opts = {}) {
46733
46681
  const counts = { agents: 0, commands: 0, rules: 0, skills: 0 };
46734
46682
  try {
@@ -46736,11 +46684,11 @@ async function scanCodexDirectory(root, opts = {}) {
46736
46684
  return counts;
46737
46685
  const items = await import_fs_extra32.readdir(root);
46738
46686
  if (items.includes("agents")) {
46739
- const files = await import_fs_extra32.readdir(join66(root, "agents")).catch(() => []);
46687
+ const files = await import_fs_extra32.readdir(join67(root, "agents")).catch(() => []);
46740
46688
  counts.agents = files.filter((f3) => f3.endsWith(".toml")).length;
46741
46689
  }
46742
46690
  if (items.includes("prompts")) {
46743
- const files = await import_fs_extra32.readdir(join66(root, "prompts")).catch(() => []);
46691
+ const files = await import_fs_extra32.readdir(join67(root, "prompts")).catch(() => []);
46744
46692
  counts.commands = files.filter((f3) => f3.endsWith(".md")).length;
46745
46693
  }
46746
46694
  if (items.includes("AGENTS.md"))
@@ -46749,7 +46697,7 @@ async function scanCodexDirectory(root, opts = {}) {
46749
46697
  if (await import_fs_extra32.pathExists(skillsRoot)) {
46750
46698
  const dirs = await import_fs_extra32.readdir(skillsRoot).catch(() => []);
46751
46699
  for (const d3 of dirs) {
46752
- const skillDir = join66(skillsRoot, d3);
46700
+ const skillDir = join67(skillsRoot, d3);
46753
46701
  const entries = await import_fs_extra32.readdir(skillDir).catch(() => null);
46754
46702
  if (entries?.includes("SKILL.md"))
46755
46703
  counts.skills++;
@@ -46766,7 +46714,7 @@ var init_scan_codex_directory = __esm(() => {
46766
46714
 
46767
46715
  // src/domains/installers/codex/source-resolver.ts
46768
46716
  import { existsSync as existsSync29 } from "node:fs";
46769
- import { join as join67 } from "node:path";
46717
+ import { join as join68 } from "node:path";
46770
46718
  function resolveCodexSources(extractDir) {
46771
46719
  return {
46772
46720
  agents: findExistingProjectLayoutPath(extractDir, "agents"),
@@ -46778,7 +46726,7 @@ function resolveCodexSources(extractDir) {
46778
46726
  };
46779
46727
  }
46780
46728
  function resolveConfigSource(extractDir) {
46781
- const rootClaudeMd = join67(extractDir, "CLAUDE.md");
46729
+ const rootClaudeMd = join68(extractDir, "CLAUDE.md");
46782
46730
  if (existsSync29(rootClaudeMd))
46783
46731
  return rootClaudeMd;
46784
46732
  return findExistingProjectConfigPath(extractDir);
@@ -46791,7 +46739,7 @@ var init_source_resolver = __esm(() => {
46791
46739
  });
46792
46740
 
46793
46741
  // src/domains/installers/codex/manifest-helpers.ts
46794
- import { join as join68, relative as relative14, sep as sep7 } from "node:path";
46742
+ import { join as join69, relative as relative14, sep as sep7 } from "node:path";
46795
46743
  async function collectCodexInstalledFiles(results, codexRoot) {
46796
46744
  const out = [];
46797
46745
  const toPosix = (p) => p.split(sep7).join("/");
@@ -46814,7 +46762,7 @@ async function collectCodexInstalledFiles(results, codexRoot) {
46814
46762
  async function walkDir(dir, root, out, toPosix) {
46815
46763
  const entries = await import_fs_extra33.readdir(dir, { withFileTypes: true }).catch(() => []);
46816
46764
  for (const e2 of entries) {
46817
- const p = join68(dir, e2.name);
46765
+ const p = join69(dir, e2.name);
46818
46766
  if (e2.isDirectory()) {
46819
46767
  await walkDir(p, root, out, toPosix);
46820
46768
  } else if (e2.isFile()) {
@@ -46857,22 +46805,9 @@ var init_write_codex_manifest = __esm(() => {
46857
46805
  // src/domains/installers/codex/installer.ts
46858
46806
  import { existsSync as existsSync30 } from "node:fs";
46859
46807
  import { rm as rm6 } from "node:fs/promises";
46860
- import { homedir as homedir20 } from "node:os";
46861
- import { join as join69 } from "node:path";
46862
- function codexGlobalRoot() {
46863
- const testHome = process.env.TAKUMI_TEST_HOME;
46864
- if (testHome && testHome.trim() !== "")
46865
- return join69(testHome, ".codex");
46866
- const codexHome = process.env.CODEX_HOME;
46867
- if (codexHome && codexHome.trim() !== "" && !codexHome.includes(".."))
46868
- return codexHome;
46869
- const xdg = process.env.XDG_CONFIG_HOME;
46870
- if (xdg && xdg.trim() !== "" && !xdg.includes(".."))
46871
- return join69(xdg, "codex");
46872
- return join69(homedir20(), ".codex");
46873
- }
46808
+ import { join as join70 } from "node:path";
46874
46809
  function resolveCodexRoot(ctx) {
46875
- return ctx.options.global ? codexGlobalRoot() : join69(ctx.resolvedDir ?? process.cwd(), ".codex");
46810
+ return ctx.options.global ? codexGlobalRoot() : join70(ctx.resolvedDir ?? process.cwd(), ".codex");
46876
46811
  }
46877
46812
  async function resolveCodexEffectiveSelection(ctx, codexRoot) {
46878
46813
  if (ctx.kitType === BASE_KIT) {
@@ -46900,7 +46835,7 @@ async function syncCodexSkillsLedger(args) {
46900
46835
  }
46901
46836
  const claims = [];
46902
46837
  for (const name of args.keptSkills) {
46903
- const dir = join69(skillsRoot, name);
46838
+ const dir = join70(skillsRoot, name);
46904
46839
  try {
46905
46840
  if (!existsSync30(dir))
46906
46841
  continue;
@@ -46955,7 +46890,7 @@ async function wipeCodexTargets(global3, projectRoot) {
46955
46890
  global3 ? codexConfig.config?.globalPath : codexConfig.config?.projectPath
46956
46891
  ].filter((p) => Boolean(p));
46957
46892
  const projectBase = projectRoot ?? process.cwd();
46958
- const targetPaths = rawPaths.map((p) => global3 ? p : join69(projectBase, p));
46893
+ const targetPaths = rawPaths.map((p) => global3 ? p : join70(projectBase, p));
46959
46894
  for (const path5 of targetPaths) {
46960
46895
  if (existsSync30(path5)) {
46961
46896
  try {
@@ -46982,6 +46917,7 @@ var init_installer2 = __esm(() => {
46982
46917
  init_types2();
46983
46918
  init_dist2();
46984
46919
  init_agent_prune();
46920
+ init_codex_paths();
46985
46921
  init_install_pipeline();
46986
46922
  init_scan_codex_directory();
46987
46923
  init_skills_paths();
@@ -46996,7 +46932,7 @@ var init_installer2 = __esm(() => {
46996
46932
  const root = this.globalRoot();
46997
46933
  if (!existsSync30(root))
46998
46934
  return false;
46999
- return findManifestPathSync(root) !== null || existsSync30(join69(root, "AGENTS.md")) || existsSync30(join69(root, "agents")) || existsSync30(join69(root, "config.toml")) || existsSync30(join69(root, "prompts"));
46935
+ return findManifestPathSync(root) !== null || existsSync30(join70(root, "AGENTS.md")) || existsSync30(join70(root, "agents")) || existsSync30(join70(root, "config.toml")) || existsSync30(join70(root, "prompts"));
47000
46936
  },
47001
46937
  async detectGlobalSetup() {
47002
46938
  const root = this.globalRoot();
@@ -47195,12 +47131,12 @@ var require_umd = __commonJS((exports, module) => {
47195
47131
  (function(global3, factory) {
47196
47132
  typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global3 = typeof globalThis !== "undefined" ? globalThis : global3 || self, factory(global3.compareVersions = {}));
47197
47133
  })(exports, function(exports2) {
47198
- const semver5 = /^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;
47134
+ const semver4 = /^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;
47199
47135
  const validateAndParse = (version3) => {
47200
47136
  if (typeof version3 !== "string") {
47201
47137
  throw new TypeError("Invalid argument expected string");
47202
47138
  }
47203
- const match = version3.match(semver5);
47139
+ const match = version3.match(semver4);
47204
47140
  if (!match) {
47205
47141
  throw new Error(`Invalid argument not valid semver ('${version3}' received)`);
47206
47142
  }
@@ -47302,7 +47238,7 @@ var require_umd = __commonJS((exports, module) => {
47302
47238
  return false;
47303
47239
  return true;
47304
47240
  };
47305
- const validate2 = (version3) => typeof version3 === "string" && /^[v\d]/.test(version3) && semver5.test(version3);
47241
+ const validate2 = (version3) => typeof version3 === "string" && /^[v\d]/.test(version3) && semver4.test(version3);
47306
47242
  const validateStrict = (version3) => typeof version3 === "string" && /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/.test(version3);
47307
47243
  exports2.compare = compare;
47308
47244
  exports2.compareVersions = compareVersions;
@@ -47362,7 +47298,7 @@ var init_version_utils = __esm(() => {
47362
47298
  });
47363
47299
 
47364
47300
  // src/domains/github/github-auth.ts
47365
- import { execSync as execSync2 } from "node:child_process";
47301
+ import { execSync } from "node:child_process";
47366
47302
 
47367
47303
  class AuthManager {
47368
47304
  static token = null;
@@ -47446,7 +47382,7 @@ Note: Do NOT use 'Paste an authentication token' - use web browser login.`);
47446
47382
  static runDiagnostic() {
47447
47383
  const info = [];
47448
47384
  try {
47449
- const version3 = execSync2("gh --version", {
47385
+ const version3 = execSync("gh --version", {
47450
47386
  encoding: "utf-8",
47451
47387
  stdio: ["pipe", "pipe", "pipe"],
47452
47388
  timeout: 3000
@@ -47457,7 +47393,7 @@ Note: Do NOT use 'Paste an authentication token' - use web browser login.`);
47457
47393
  info.push(" gh version: failed to retrieve");
47458
47394
  }
47459
47395
  try {
47460
- const status = execSync2("gh auth status -h github.com", {
47396
+ const status = execSync("gh auth status -h github.com", {
47461
47397
  encoding: "utf-8",
47462
47398
  stdio: ["pipe", "pipe", "pipe"],
47463
47399
  timeout: 5000
@@ -47483,7 +47419,7 @@ Note: Do NOT use 'Paste an authentication token' - use web browser login.`);
47483
47419
  return AuthManager.ghCliInstalled;
47484
47420
  }
47485
47421
  try {
47486
- execSync2("gh --version", {
47422
+ execSync("gh --version", {
47487
47423
  stdio: "ignore",
47488
47424
  timeout: 5000
47489
47425
  });
@@ -47496,7 +47432,7 @@ Note: Do NOT use 'Paste an authentication token' - use web browser login.`);
47496
47432
  }
47497
47433
  static getFromGhCli() {
47498
47434
  try {
47499
- const token = execSync2("gh auth token -h github.com", {
47435
+ const token = execSync("gh auth token -h github.com", {
47500
47436
  encoding: "utf-8",
47501
47437
  stdio: ["pipe", "pipe", "pipe"],
47502
47438
  timeout: 5000
@@ -47511,7 +47447,7 @@ Note: Do NOT use 'Paste an authentication token' - use web browser login.`);
47511
47447
  logger.debug(`gh auth token stderr: ${error.stderr.toString().trim()}`);
47512
47448
  }
47513
47449
  try {
47514
- const token = execSync2("gh auth token", {
47450
+ const token = execSync("gh auth token", {
47515
47451
  encoding: "utf-8",
47516
47452
  stdio: ["pipe", "pipe", "pipe"],
47517
47453
  timeout: 5000
@@ -47807,7 +47743,7 @@ var init_error_handler = __esm(() => {
47807
47743
  // src/domains/versioning/release-cache.ts
47808
47744
  import { existsSync as existsSync31 } from "node:fs";
47809
47745
  import { mkdir as mkdir15, readFile as readFile34, unlink as unlink7, writeFile as writeFile21 } from "node:fs/promises";
47810
- import { join as join70 } from "node:path";
47746
+ import { join as join71 } from "node:path";
47811
47747
  var ReleaseCacheEntrySchema, ReleaseCache;
47812
47748
  var init_release_cache = __esm(() => {
47813
47749
  init_logger();
@@ -47822,7 +47758,7 @@ var init_release_cache = __esm(() => {
47822
47758
  static CACHE_TTL_SECONDS = Number(process.env.TAKUMI_CACHE_TTL) || 3600;
47823
47759
  cacheDir;
47824
47760
  constructor() {
47825
- this.cacheDir = join70(PathResolver.getCacheDir(false), ReleaseCache.CACHE_DIR);
47761
+ this.cacheDir = join71(PathResolver.getCacheDir(false), ReleaseCache.CACHE_DIR);
47826
47762
  }
47827
47763
  async get(key) {
47828
47764
  const cacheFile = this.getCachePath(key);
@@ -47880,7 +47816,7 @@ var init_release_cache = __esm(() => {
47880
47816
  const files = await readdir24(this.cacheDir);
47881
47817
  for (const file of files) {
47882
47818
  if (file.endsWith(".json")) {
47883
- await unlink7(join70(this.cacheDir, file));
47819
+ await unlink7(join71(this.cacheDir, file));
47884
47820
  }
47885
47821
  }
47886
47822
  logger.debug("All release cache cleared");
@@ -47891,7 +47827,7 @@ var init_release_cache = __esm(() => {
47891
47827
  }
47892
47828
  getCachePath(key) {
47893
47829
  const safeKey = key.replace(/[^a-zA-Z0-9_-]/g, "_");
47894
- return join70(this.cacheDir, `${safeKey}.json`);
47830
+ return join71(this.cacheDir, `${safeKey}.json`);
47895
47831
  }
47896
47832
  isExpired(timestamp) {
47897
47833
  const now = Date.now();
@@ -48541,7 +48477,7 @@ var init_github_client = __esm(() => {
48541
48477
  // src/domains/versioning/version-cache.ts
48542
48478
  import { existsSync as existsSync32 } from "node:fs";
48543
48479
  import { mkdir as mkdir16, readFile as readFile35, writeFile as writeFile22 } from "node:fs/promises";
48544
- import { join as join71 } from "node:path";
48480
+ import { join as join72 } from "node:path";
48545
48481
  var VersionCacheManager;
48546
48482
  var init_version_cache = __esm(() => {
48547
48483
  init_logger();
@@ -48551,7 +48487,7 @@ var init_version_cache = __esm(() => {
48551
48487
  static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
48552
48488
  static getCacheFile() {
48553
48489
  const cacheDir = PathResolver.getCacheDir(false);
48554
- return join71(cacheDir, VersionCacheManager.CACHE_FILENAME);
48490
+ return join72(cacheDir, VersionCacheManager.CACHE_FILENAME);
48555
48491
  }
48556
48492
  static async load() {
48557
48493
  const cacheFile = VersionCacheManager.getCacheFile();
@@ -49007,18 +48943,18 @@ var init_version_display = __esm(() => {
49007
48943
 
49008
48944
  // src/domains/auth/paths.ts
49009
48945
  import { homedir as homedir21 } from "node:os";
49010
- import { join as join72 } from "node:path";
48946
+ import { join as join73 } from "node:path";
49011
48947
  function getConfigDir() {
49012
48948
  const override = process.env.TAKUMI_HOME;
49013
48949
  if (override && override.trim().length > 0)
49014
48950
  return override;
49015
- return join72(homedir21(), STATE_DIRNAME);
48951
+ return join73(homedir21(), STATE_DIRNAME);
49016
48952
  }
49017
48953
  function getAuthDir() {
49018
- return join72(getConfigDir(), "auth");
48954
+ return join73(getConfigDir(), "auth");
49019
48955
  }
49020
48956
  function getTokenPath() {
49021
- return join72(getAuthDir(), "token.json");
48957
+ return join73(getAuthDir(), "token.json");
49022
48958
  }
49023
48959
  var init_paths2 = __esm(() => {
49024
48960
  init_build_config();
@@ -49026,9 +48962,9 @@ var init_paths2 = __esm(() => {
49026
48962
 
49027
48963
  // src/domains/auth/config-cache.ts
49028
48964
  import { promises as fs } from "node:fs";
49029
- import { join as join73 } from "node:path";
48965
+ import { join as join74 } from "node:path";
49030
48966
  function getCachePath() {
49031
- return join73(getConfigDir(), "auth", "config.json");
48967
+ return join74(getConfigDir(), "auth", "config.json");
49032
48968
  }
49033
48969
  async function readCachedConfig() {
49034
48970
  try {
@@ -49052,7 +48988,7 @@ async function readCachedConfig() {
49052
48988
  }
49053
48989
  async function writeCachedConfig(config) {
49054
48990
  const path5 = getCachePath();
49055
- const dir = join73(getConfigDir(), "auth");
48991
+ const dir = join74(getConfigDir(), "auth");
49056
48992
  await fs.mkdir(dir, { recursive: true, mode: 448 });
49057
48993
  const body = { ...config, cachedAt: Date.now() };
49058
48994
  const fh = await fs.open(path5, "w", 384);
@@ -50611,12 +50547,12 @@ import {
50611
50547
  rmSync as rmSync4,
50612
50548
  writeFileSync as writeFileSync9
50613
50549
  } from "node:fs";
50614
- import { join as join103 } from "node:path";
50550
+ import { join as join104 } from "node:path";
50615
50551
  function getStatuslineCacheDir() {
50616
- return join103(getConfigDir(), "cache", "statusline");
50552
+ return join104(getConfigDir(), "cache", "statusline");
50617
50553
  }
50618
50554
  function getStatuslineCachePath(fileName) {
50619
- return join103(getStatuslineCacheDir(), fileName);
50555
+ return join104(getStatuslineCacheDir(), fileName);
50620
50556
  }
50621
50557
  function ensureStatuslineCacheDir() {
50622
50558
  try {
@@ -50682,7 +50618,7 @@ var init_cache_dir = __esm(() => {
50682
50618
  import { execFileSync as execFileSync2 } from "node:child_process";
50683
50619
  import { closeSync as closeSync6, constants as fsConstants4, fstatSync as fstatSync2, openSync as openSync7, readFileSync as readFileSync15 } from "node:fs";
50684
50620
  import { homedir as homedir28, platform as platform8 } from "node:os";
50685
- import { join as join104 } from "node:path";
50621
+ import { join as join105 } from "node:path";
50686
50622
  function hasAnthropicRuntimeOverride(env2 = process.env) {
50687
50623
  return OVERRIDE_ENV_KEYS.some((key) => {
50688
50624
  const value = env2[key];
@@ -50732,7 +50668,7 @@ function readTrustedFile(path10) {
50732
50668
  }
50733
50669
  }
50734
50670
  function fromCredentialsFile() {
50735
- const raw = readTrustedFile(join104(homedir28(), ".claude", ".credentials.json"));
50671
+ const raw = readTrustedFile(join105(homedir28(), ".claude", ".credentials.json"));
50736
50672
  if (!raw)
50737
50673
  return null;
50738
50674
  try {
@@ -50890,14 +50826,14 @@ var exports_monorepo_resolver = {};
50890
50826
  __export(exports_monorepo_resolver, {
50891
50827
  resolveMonorepoRoot: () => resolveMonorepoRoot
50892
50828
  });
50893
- import { existsSync as existsSync60, readFileSync as readFileSync23 } from "node:fs";
50894
- import { dirname as dirname34, join as join124, resolve as resolve29 } from "node:path";
50829
+ import { existsSync as existsSync60, readFileSync as readFileSync26 } from "node:fs";
50830
+ import { dirname as dirname34, join as join130, resolve as resolve29 } from "node:path";
50895
50831
  import { fileURLToPath as fileURLToPath3 } from "node:url";
50896
50832
  function parseMetadataAt(metadataPath) {
50897
50833
  if (!existsSync60(metadataPath))
50898
50834
  return null;
50899
50835
  try {
50900
- const raw = readFileSync23(metadataPath, "utf-8");
50836
+ const raw = readFileSync26(metadataPath, "utf-8");
50901
50837
  const parsed = JSON.parse(raw);
50902
50838
  if (typeof parsed.name !== "string" || typeof parsed.version !== "string" || !ACCEPTED_METADATA_NAMES.has(parsed.name)) {
50903
50839
  return null;
@@ -50908,11 +50844,11 @@ function parseMetadataAt(metadataPath) {
50908
50844
  }
50909
50845
  }
50910
50846
  function readSourceDirFromPackageJson(candidateRoot) {
50911
- const packageJsonPath = join124(candidateRoot, "package.json");
50847
+ const packageJsonPath = join130(candidateRoot, "package.json");
50912
50848
  if (!existsSync60(packageJsonPath))
50913
50849
  return null;
50914
50850
  try {
50915
- const parsed = JSON.parse(readFileSync23(packageJsonPath, "utf-8"));
50851
+ const parsed = JSON.parse(readFileSync26(packageJsonPath, "utf-8"));
50916
50852
  const kitCfg = parsed.takumi;
50917
50853
  if (kitCfg && typeof kitCfg.sourceDir === "string" && kitCfg.sourceDir.length > 0) {
50918
50854
  return kitCfg.sourceDir;
@@ -50931,7 +50867,7 @@ function tryReadAtCandidate(candidateRoot) {
50931
50867
  };
50932
50868
  }
50933
50869
  const sourceDir = readSourceDirFromPackageJson(candidateRoot) ?? "claude";
50934
- const sourceRoot = join124(candidateRoot, sourceDir);
50870
+ const sourceRoot = join130(candidateRoot, sourceDir);
50935
50871
  const nestedMetadata = parseMetadataAt(getManifestPath(sourceRoot)) ?? parseMetadataAt(getLegacyManifestPath(sourceRoot));
50936
50872
  if (nestedMetadata) {
50937
50873
  return {
@@ -54082,9 +54018,9 @@ import { promises as fs9 } from "node:fs";
54082
54018
 
54083
54019
  // src/domains/artifact/paths.ts
54084
54020
  init_paths2();
54085
- import { join as join74 } from "node:path";
54021
+ import { join as join75 } from "node:path";
54086
54022
  function getManifestPath2() {
54087
- return join74(getConfigDir(), "artifacts.json");
54023
+ return join75(getConfigDir(), "artifacts.json");
54088
54024
  }
54089
54025
 
54090
54026
  // src/domains/artifact/manifest-store.ts
@@ -54277,13 +54213,13 @@ import { basename as basename11, resolve as resolve18 } from "node:path";
54277
54213
 
54278
54214
  // src/domains/artifact/folder-download.ts
54279
54215
  import { promises as fs10 } from "node:fs";
54280
- import { dirname as dirname19, isAbsolute as isAbsolute4, join as join75, normalize as normalize5 } from "node:path";
54216
+ import { dirname as dirname19, isAbsolute as isAbsolute4, join as join76, normalize as normalize5 } from "node:path";
54281
54217
  var CONCURRENCY = 6;
54282
54218
  function sanitizeFilePath(filePath, destDir) {
54283
54219
  if (isAbsolute4(filePath)) {
54284
54220
  throw new Error(`Path traversal rejected: absolute path "${filePath}"`);
54285
54221
  }
54286
- const resolved = normalize5(join75(destDir, filePath));
54222
+ const resolved = normalize5(join76(destDir, filePath));
54287
54223
  const safeBase = normalize5(destDir);
54288
54224
  if (resolved !== safeBase && !resolved.startsWith(`${safeBase}/`)) {
54289
54225
  throw new Error(`Path traversal rejected: "${filePath}" escapes destination directory`);
@@ -54697,7 +54633,7 @@ import { basename as basename12, extname as extname6, resolve as resolve19 } fro
54697
54633
  // src/domains/artifact/folder-walk.ts
54698
54634
  var import_ignore4 = __toESM(require_ignore(), 1);
54699
54635
  import { promises as fs12 } from "node:fs";
54700
- import { join as join76, relative as relative15 } from "node:path";
54636
+ import { join as join77, relative as relative15 } from "node:path";
54701
54637
  var MAX_FILE_BYTES = 20 * 1024 * 1024;
54702
54638
  var IGNORE_FILES = [".gitignore", ".tkmignore"];
54703
54639
  var HARD_IGNORES = [".git", ".gitignore", ".tkmignore"];
@@ -54713,7 +54649,7 @@ async function buildIgnoreMatcher(rootDir) {
54713
54649
  const ig = import_ignore4.default();
54714
54650
  for (const file of IGNORE_FILES) {
54715
54651
  try {
54716
- ig.add(await fs12.readFile(join76(rootDir, file), "utf8"));
54652
+ ig.add(await fs12.readFile(join77(rootDir, file), "utf8"));
54717
54653
  } catch {}
54718
54654
  }
54719
54655
  ig.add(HARD_IGNORES);
@@ -54745,7 +54681,7 @@ async function walk2(rootDir, dir, ig, out, skipped) {
54745
54681
  if (dirent.isSymbolicLink())
54746
54682
  continue;
54747
54683
  const name = String(dirent.name);
54748
- const absPath = join76(dir, name);
54684
+ const absPath = join77(dir, name);
54749
54685
  const relPath = relative15(rootDir, absPath).split("\\").join("/");
54750
54686
  if (dirent.isDirectory()) {
54751
54687
  if (ig.ignores(`${relPath}/`)) {
@@ -55295,14 +55231,14 @@ import { existsSync as existsSync33 } from "node:fs";
55295
55231
  import { copyFile as copyFile4, mkdir as mkdir17, readFile as readFile36, rename as rename7, rm as rm7, writeFile as writeFile23 } from "node:fs/promises";
55296
55232
  import { chmod as chmod2 } from "node:fs/promises";
55297
55233
  import { homedir as homedir22, platform as platform4 } from "node:os";
55298
- import { join as join77 } from "node:path";
55234
+ import { join as join78 } from "node:path";
55299
55235
  var PROJECT_CONFIG_FILE = ".takumi.json";
55300
55236
 
55301
55237
  class ConfigManager {
55302
55238
  static config = null;
55303
55239
  static globalFlag = false;
55304
55240
  static getProjectConfigDir(projectDir, global3) {
55305
- return global3 ? projectDir : join77(projectDir, ".claude");
55241
+ return global3 ? projectDir : join78(projectDir, ".claude");
55306
55242
  }
55307
55243
  static setGlobalFlag(global3) {
55308
55244
  ConfigManager.globalFlag = global3;
@@ -55316,7 +55252,7 @@ class ConfigManager {
55316
55252
  return;
55317
55253
  const testHome = process.env.TAKUMI_TEST_HOME;
55318
55254
  const base = testHome && testHome.trim() !== "" ? testHome : homedir22();
55319
- const legacyFile = join77(base, ".sunagentkit", "config.json");
55255
+ const legacyFile = join78(base, ".sunagentkit", "config.json");
55320
55256
  if (!existsSync33(legacyFile))
55321
55257
  return;
55322
55258
  const targetFile = PathResolver.getConfigFile(false);
@@ -55401,7 +55337,7 @@ class ConfigManager {
55401
55337
  }
55402
55338
  static async loadProjectConfig(projectDir, global3 = false) {
55403
55339
  const configDir = ConfigManager.getProjectConfigDir(projectDir, global3);
55404
- const configPath = join77(configDir, PROJECT_CONFIG_FILE);
55340
+ const configPath = join78(configDir, PROJECT_CONFIG_FILE);
55405
55341
  try {
55406
55342
  if (existsSync33(configPath)) {
55407
55343
  const content = await readFile36(configPath, "utf-8");
@@ -55417,7 +55353,7 @@ class ConfigManager {
55417
55353
  }
55418
55354
  static async saveProjectConfig(projectDir, folders, global3 = false) {
55419
55355
  const configDir = ConfigManager.getProjectConfigDir(projectDir, global3);
55420
- const configPath = join77(configDir, PROJECT_CONFIG_FILE);
55356
+ const configPath = join78(configDir, PROJECT_CONFIG_FILE);
55421
55357
  try {
55422
55358
  if (!existsSync33(configDir)) {
55423
55359
  await mkdir17(configDir, { recursive: true });
@@ -55466,11 +55402,11 @@ class ConfigManager {
55466
55402
  }
55467
55403
  static projectConfigExists(projectDir, global3 = false) {
55468
55404
  const configDir = ConfigManager.getProjectConfigDir(projectDir, global3);
55469
- return existsSync33(join77(configDir, PROJECT_CONFIG_FILE));
55405
+ return existsSync33(join78(configDir, PROJECT_CONFIG_FILE));
55470
55406
  }
55471
55407
  static async migrateNestedConfig(globalDir) {
55472
- const correctPath = join77(globalDir, PROJECT_CONFIG_FILE);
55473
- const incorrectPath = join77(globalDir, ".claude", PROJECT_CONFIG_FILE);
55408
+ const correctPath = join78(globalDir, PROJECT_CONFIG_FILE);
55409
+ const incorrectPath = join78(globalDir, ".claude", PROJECT_CONFIG_FILE);
55474
55410
  if (existsSync33(correctPath)) {
55475
55411
  logger.debug("Config already exists at correct location, skipping migration");
55476
55412
  return false;
@@ -55480,7 +55416,7 @@ class ConfigManager {
55480
55416
  logger.info("Migrating .takumi.json from nested location to correct location...");
55481
55417
  await rename7(incorrectPath, correctPath);
55482
55418
  logger.success(`Migrated ${PROJECT_CONFIG_FILE} to ${correctPath}`);
55483
- const nestedClaudeDir = join77(globalDir, ".claude");
55419
+ const nestedClaudeDir = join78(globalDir, ".claude");
55484
55420
  try {
55485
55421
  await rm7(nestedClaudeDir, { recursive: false });
55486
55422
  logger.debug("Removed empty nested .claude directory");
@@ -57180,7 +57116,7 @@ function filterSessionMetas(metas, filter) {
57180
57116
  // src/domains/sessions/store/ingest.ts
57181
57117
  import { createHash as createHash10 } from "node:crypto";
57182
57118
  import { closeSync as closeSync4, openSync as openSync4, readSync as readSync4, readdirSync as readdirSync7, statSync as statSync5 } from "node:fs";
57183
- import { basename as basename15, dirname as dirname21, join as join81 } from "node:path";
57119
+ import { basename as basename15, dirname as dirname21, join as join82 } from "node:path";
57184
57120
 
57185
57121
  // node_modules/kysely/dist/util/object-utils.js
57186
57122
  function isUndefined(obj) {
@@ -58612,10 +58548,10 @@ var QueryNode = freeze({
58612
58548
  where: node.where ? WhereNode.cloneWithOperation(node.where, "And", operation) : WhereNode.create(operation)
58613
58549
  });
58614
58550
  },
58615
- cloneWithJoin(node, join80) {
58551
+ cloneWithJoin(node, join81) {
58616
58552
  return freeze({
58617
58553
  ...node,
58618
- joins: node.joins ? freeze([...node.joins, join80]) : freeze([join80])
58554
+ joins: node.joins ? freeze([...node.joins, join81]) : freeze([join81])
58619
58555
  });
58620
58556
  },
58621
58557
  cloneWithReturning(node, selections) {
@@ -61166,8 +61102,8 @@ class WithSchemaTransformer extends OperationNodeTransformer {
61166
61102
  this.#collectSchemableIdsFromTableExpr(node.table, schemableIds);
61167
61103
  }
61168
61104
  if ("joins" in node && node.joins) {
61169
- for (const join80 of node.joins) {
61170
- this.#collectSchemableIdsFromTableExpr(join80.table, schemableIds);
61105
+ for (const join81 of node.joins) {
61106
+ this.#collectSchemableIdsFromTableExpr(join81.table, schemableIds);
61171
61107
  }
61172
61108
  }
61173
61109
  if ("using" in node && node.using) {
@@ -66439,7 +66375,7 @@ var import_proper_lockfile8 = __toESM(require_proper_lockfile(), 1);
66439
66375
 
66440
66376
  // src/domains/sessions/store/db.ts
66441
66377
  import { promises as fs17 } from "node:fs";
66442
- import { join as join80 } from "node:path";
66378
+ import { join as join81 } from "node:path";
66443
66379
  init_logger();
66444
66380
  init_paths2();
66445
66381
 
@@ -66534,10 +66470,10 @@ class StoreUnavailableError extends Error {
66534
66470
 
66535
66471
  // src/domains/sessions/store/db.ts
66536
66472
  function getConsoleStoreDir() {
66537
- return join80(getConfigDir(), "console");
66473
+ return join81(getConfigDir(), "console");
66538
66474
  }
66539
66475
  function getConsoleStorePath() {
66540
- return join80(getConsoleStoreDir(), "store.sqlite");
66476
+ return join81(getConsoleStoreDir(), "store.sqlite");
66541
66477
  }
66542
66478
  async function chmodSafe2(path8, mode) {
66543
66479
  try {
@@ -66806,7 +66742,7 @@ async function ingestFile(handle, target) {
66806
66742
  }
66807
66743
  function subagentDirFor(mainPath) {
66808
66744
  const stem = basename15(mainPath).replace(/\.jsonl$/i, "");
66809
- return join81(dirname21(mainPath), stem, "subagents");
66745
+ return join82(dirname21(mainPath), stem, "subagents");
66810
66746
  }
66811
66747
  async function enumerateTargets(refresh2 = false) {
66812
66748
  const sessions = await list({ refresh: refresh2 });
@@ -66828,7 +66764,7 @@ async function enumerateTargets(refresh2 = false) {
66828
66764
  } catch {}
66829
66765
  for (const f3 of files) {
66830
66766
  targets.push({
66831
- path: join81(dir, f3),
66767
+ path: join82(dir, f3),
66832
66768
  adapter: "claude",
66833
66769
  sessionId: s.id,
66834
66770
  project: s.project,
@@ -66839,7 +66775,7 @@ async function enumerateTargets(refresh2 = false) {
66839
66775
  return targets;
66840
66776
  }
66841
66777
  async function withIngestLock(fn) {
66842
- const lockPath = join81(getConsoleStoreDir(), "ingest");
66778
+ const lockPath = join82(getConsoleStoreDir(), "ingest");
66843
66779
  let release;
66844
66780
  try {
66845
66781
  release = await import_proper_lockfile8.default.lock(lockPath, { stale: 60000, retries: 0, realpath: false });
@@ -68647,7 +68583,7 @@ init_takumi_constants();
68647
68583
  import { existsSync as existsSync38, realpathSync } from "node:fs";
68648
68584
  import { chmod as chmod3, mkdir as mkdir18, readFile as readFile37, writeFile as writeFile24 } from "node:fs/promises";
68649
68585
  import { platform as platform5 } from "node:os";
68650
- import { join as join82 } from "node:path";
68586
+ import { join as join83 } from "node:path";
68651
68587
  var CACHE_FILE = "install-info.json";
68652
68588
  var CACHE_TTL = 30 * 24 * 60 * 60 * 1000;
68653
68589
  function detectFromBinaryPath() {
@@ -68731,7 +68667,7 @@ function detectFromEnv() {
68731
68667
  }
68732
68668
  async function readCachedPm() {
68733
68669
  try {
68734
- const cacheFile = join82(PathResolver.getConfigDir(false), CACHE_FILE);
68670
+ const cacheFile = join83(PathResolver.getConfigDir(false), CACHE_FILE);
68735
68671
  if (!existsSync38(cacheFile)) {
68736
68672
  return null;
68737
68673
  }
@@ -68762,7 +68698,7 @@ async function saveCachedPm(pm, getVersion) {
68762
68698
  return;
68763
68699
  try {
68764
68700
  const configDir = PathResolver.getConfigDir(false);
68765
- const cacheFile = join82(configDir, CACHE_FILE);
68701
+ const cacheFile = join83(configDir, CACHE_FILE);
68766
68702
  if (!existsSync38(configDir)) {
68767
68703
  await mkdir18(configDir, { recursive: true });
68768
68704
  if (platform5() !== "win32") {
@@ -68825,7 +68761,7 @@ async function findOwningPm() {
68825
68761
  async function clearCache() {
68826
68762
  try {
68827
68763
  const { unlink: unlink8 } = await import("node:fs/promises");
68828
- const cacheFile = join82(PathResolver.getConfigDir(false), CACHE_FILE);
68764
+ const cacheFile = join83(PathResolver.getConfigDir(false), CACHE_FILE);
68829
68765
  if (existsSync38(cacheFile)) {
68830
68766
  await unlink8(cacheFile);
68831
68767
  logger.debug("Package manager cache cleared");
@@ -69087,17 +69023,17 @@ async function checkCliVersion() {
69087
69023
  init_paths();
69088
69024
  init_registry();
69089
69025
  import { existsSync as existsSync39, statSync as statSync7 } from "node:fs";
69090
- import { join as join83 } from "node:path";
69026
+ import { join as join84 } from "node:path";
69091
69027
  function checkClaudeMd(setup, projectDir) {
69092
69028
  const results = [];
69093
69029
  const claudeCodeInstaller2 = getInstaller("claude-code");
69094
69030
  if (claudeCodeInstaller2?.isInstalledGlobally()) {
69095
69031
  const claudeGlobal = setup.globals.find((g2) => g2.provider === "claude-code") ?? setup.globals[0];
69096
69032
  const globalPath = claudeGlobal?.path ?? claudeCodeInstaller2.globalRoot();
69097
- const globalClaudeMd = join83(globalPath, "CLAUDE.md");
69033
+ const globalClaudeMd = join84(globalPath, "CLAUDE.md");
69098
69034
  results.push(checkClaudeMdFile(globalClaudeMd, "Global CLAUDE.md", "tkm-global-claude-md"));
69099
69035
  }
69100
- const projectClaudeMd = join83(getLocalClaudeDir(projectDir), "CLAUDE.md");
69036
+ const projectClaudeMd = join84(getLocalClaudeDir(projectDir), "CLAUDE.md");
69101
69037
  results.push(checkClaudeMdFile(projectClaudeMd, "Project CLAUDE.md", "tkm-project-claude-md"));
69102
69038
  return results;
69103
69039
  }
@@ -69156,9 +69092,9 @@ function checkClaudeMdFile(path8, name2, id) {
69156
69092
  }
69157
69093
  // src/domains/health-checks/checkers/active-plan-checker.ts
69158
69094
  import { existsSync as existsSync40, readFileSync as readFileSync10 } from "node:fs";
69159
- import { join as join84 } from "node:path";
69095
+ import { join as join85 } from "node:path";
69160
69096
  function checkActivePlan(projectDir) {
69161
- const activePlanPath = join84(projectDir, ".claude", "active-plan");
69097
+ const activePlanPath = join85(projectDir, ".claude", "active-plan");
69162
69098
  if (!existsSync40(activePlanPath)) {
69163
69099
  return {
69164
69100
  id: "tkm-active-plan",
@@ -69172,7 +69108,7 @@ function checkActivePlan(projectDir) {
69172
69108
  }
69173
69109
  try {
69174
69110
  const targetPath = readFileSync10(activePlanPath, "utf-8").trim();
69175
- const fullPath = join84(projectDir, targetPath);
69111
+ const fullPath = join85(projectDir, targetPath);
69176
69112
  if (!existsSync40(fullPath)) {
69177
69113
  return {
69178
69114
  id: "tkm-active-plan",
@@ -69238,7 +69174,7 @@ function checkComponentCounts(setup) {
69238
69174
  init_registry();
69239
69175
  init_logger();
69240
69176
  import { constants, access, unlink as unlink8, writeFile as writeFile25 } from "node:fs/promises";
69241
- import { join as join85 } from "node:path";
69177
+ import { join as join86 } from "node:path";
69242
69178
 
69243
69179
  // src/domains/health-checks/checkers/shared.ts
69244
69180
  init_registry();
@@ -69313,7 +69249,7 @@ async function checkGlobalDirWritable(provider) {
69313
69249
  }
69314
69250
  const timestamp = Date.now();
69315
69251
  const random = Math.random().toString(36).substring(2);
69316
- const testFile = join85(globalDir, `.tkm-write-test-${timestamp}-${random}`);
69252
+ const testFile = join86(globalDir, `.tkm-write-test-${timestamp}-${random}`);
69317
69253
  try {
69318
69254
  await writeFile25(testFile, "test", { encoding: "utf-8", flag: "wx" });
69319
69255
  } catch (_error) {
@@ -69350,7 +69286,7 @@ init_paths();
69350
69286
  init_registry();
69351
69287
  import { existsSync as existsSync41 } from "node:fs";
69352
69288
  import { readdir as readdir24 } from "node:fs/promises";
69353
- import { join as join86 } from "node:path";
69289
+ import { join as join87 } from "node:path";
69354
69290
 
69355
69291
  // src/domains/health-checks/utils/path-normalizer.ts
69356
69292
  import { normalize as normalize6 } from "node:path";
@@ -69362,8 +69298,8 @@ function normalizePath(filePath) {
69362
69298
 
69363
69299
  // src/domains/health-checks/checkers/hooks-checker.ts
69364
69300
  async function checkHooksExist(projectDir) {
69365
- const globalHooksDir = join86(getInstaller("claude-code")?.globalRoot() ?? "", "hooks");
69366
- const projectHooksDir = join86(getLocalClaudeDir(projectDir), "hooks");
69301
+ const globalHooksDir = join87(getInstaller("claude-code")?.globalRoot() ?? "", "hooks");
69302
+ const projectHooksDir = join87(getLocalClaudeDir(projectDir), "hooks");
69367
69303
  const globalExists = existsSync41(globalHooksDir);
69368
69304
  const projectExists = existsSync41(projectHooksDir);
69369
69305
  let hookCount = 0;
@@ -69372,7 +69308,7 @@ async function checkHooksExist(projectDir) {
69372
69308
  const files = await readdir24(globalHooksDir, { withFileTypes: false });
69373
69309
  const hooks = files.filter((f3) => HOOK_EXTENSIONS2.some((ext) => f3.endsWith(ext)));
69374
69310
  hooks.forEach((hook) => {
69375
- const fullPath = join86(globalHooksDir, hook);
69311
+ const fullPath = join87(globalHooksDir, hook);
69376
69312
  checkedFiles.add(normalizePath(fullPath));
69377
69313
  });
69378
69314
  }
@@ -69382,7 +69318,7 @@ async function checkHooksExist(projectDir) {
69382
69318
  const files = await readdir24(projectHooksDir, { withFileTypes: false });
69383
69319
  const hooks = files.filter((f3) => HOOK_EXTENSIONS2.some((ext) => f3.endsWith(ext)));
69384
69320
  hooks.forEach((hook) => {
69385
- const fullPath = join86(projectHooksDir, hook);
69321
+ const fullPath = join87(projectHooksDir, hook);
69386
69322
  checkedFiles.add(normalizePath(fullPath));
69387
69323
  });
69388
69324
  }
@@ -69413,14 +69349,14 @@ async function checkHooksExist(projectDir) {
69413
69349
  init_registry();
69414
69350
  import { existsSync as existsSync42 } from "node:fs";
69415
69351
  import { readFile as readFile38 } from "node:fs/promises";
69416
- import { join as join87 } from "node:path";
69352
+ import { join as join88 } from "node:path";
69417
69353
  async function checkCodexHooksHealth() {
69418
69354
  const codex = getInstaller("codex");
69419
69355
  if (!codex?.isInstalledGlobally())
69420
69356
  return [];
69421
69357
  const codexRoot = codex.globalRoot();
69422
- const configTomlPath = join87(codexRoot, "config.toml");
69423
- const hooksJsonPath = join87(codexRoot, "hooks.json");
69358
+ const configTomlPath = join88(codexRoot, "config.toml");
69359
+ const hooksJsonPath = join88(codexRoot, "hooks.json");
69424
69360
  if (!existsSync42(hooksJsonPath))
69425
69361
  return [];
69426
69362
  const results = [];
@@ -69532,10 +69468,10 @@ init_registry();
69532
69468
  init_logger();
69533
69469
  import { existsSync as existsSync43 } from "node:fs";
69534
69470
  import { readFile as readFile39 } from "node:fs/promises";
69535
- import { join as join88 } from "node:path";
69471
+ import { join as join89 } from "node:path";
69536
69472
  async function checkSettingsValid(projectDir) {
69537
- const globalSettings = join88(getInstaller("claude-code")?.globalRoot() ?? "", "settings.json");
69538
- const projectSettings = join88(getLocalClaudeDir(projectDir), "settings.json");
69473
+ const globalSettings = join89(getInstaller("claude-code")?.globalRoot() ?? "", "settings.json");
69474
+ const projectSettings = join89(getLocalClaudeDir(projectDir), "settings.json");
69539
69475
  const settingsPath = existsSync43(globalSettings) ? globalSettings : existsSync43(projectSettings) ? projectSettings : null;
69540
69476
  if (!settingsPath) {
69541
69477
  return {
@@ -69609,10 +69545,10 @@ init_logger();
69609
69545
  import { existsSync as existsSync44 } from "node:fs";
69610
69546
  import { readFile as readFile40 } from "node:fs/promises";
69611
69547
  import { homedir as homedir25 } from "node:os";
69612
- import { dirname as dirname22, join as join89, normalize as normalize7, resolve as resolve22 } from "node:path";
69548
+ import { dirname as dirname22, join as join90, normalize as normalize7, resolve as resolve22 } from "node:path";
69613
69549
  async function checkPathRefsValid(projectDir) {
69614
- const globalClaudeMd = join89(getInstaller("claude-code")?.globalRoot() ?? "", "CLAUDE.md");
69615
- const projectClaudeMd = join89(getLocalClaudeDir(projectDir), "CLAUDE.md");
69550
+ const globalClaudeMd = join90(getInstaller("claude-code")?.globalRoot() ?? "", "CLAUDE.md");
69551
+ const projectClaudeMd = join90(getLocalClaudeDir(projectDir), "CLAUDE.md");
69616
69552
  const claudeMdPath = existsSync44(globalClaudeMd) ? globalClaudeMd : existsSync44(projectClaudeMd) ? projectClaudeMd : null;
69617
69553
  if (!claudeMdPath) {
69618
69554
  return {
@@ -69708,7 +69644,7 @@ async function checkPathRefsValid(projectDir) {
69708
69644
  init_paths();
69709
69645
  import { existsSync as existsSync45 } from "node:fs";
69710
69646
  import { readdir as readdir25 } from "node:fs/promises";
69711
- import { join as join90 } from "node:path";
69647
+ import { join as join91 } from "node:path";
69712
69648
  async function checkProjectConfigCompleteness(setup, projectDir) {
69713
69649
  if (setup.globals.some((g2) => g2.path === setup.project.path)) {
69714
69650
  return {
@@ -69725,12 +69661,12 @@ async function checkProjectConfigCompleteness(setup, projectDir) {
69725
69661
  const requiredDirs = ["agents", "commands", "skills"];
69726
69662
  const missingDirs = [];
69727
69663
  for (const dir of requiredDirs) {
69728
- const dirPath = join90(projectClaudeDir, dir);
69664
+ const dirPath = join91(projectClaudeDir, dir);
69729
69665
  if (!existsSync45(dirPath)) {
69730
69666
  missingDirs.push(dir);
69731
69667
  }
69732
69668
  }
69733
- const hasRulesOrWorkflows = existsSync45(join90(projectClaudeDir, "rules")) || existsSync45(join90(projectClaudeDir, "workflows"));
69669
+ const hasRulesOrWorkflows = existsSync45(join91(projectClaudeDir, "rules")) || existsSync45(join91(projectClaudeDir, "workflows"));
69734
69670
  if (!hasRulesOrWorkflows) {
69735
69671
  missingDirs.push("rules");
69736
69672
  }
@@ -69829,7 +69765,7 @@ import { spawnSync as spawnSync3 } from "node:child_process";
69829
69765
  // src/domains/installation/git-clone-manager.ts
69830
69766
  init_build_config();
69831
69767
  init_logger();
69832
- import { execSync as execSync3 } from "node:child_process";
69768
+ import { execSync as execSync2 } from "node:child_process";
69833
69769
  import * as fs19 from "node:fs";
69834
69770
  import * as os6 from "node:os";
69835
69771
  import * as path8 from "node:path";
@@ -69868,7 +69804,7 @@ Check disk space and directory permissions.`);
69868
69804
  const quotedUrl = `"${url}"`;
69869
69805
  const quotedDir = `"${tempDir}"`;
69870
69806
  try {
69871
- execSync3(`git clone --depth 1 --branch "${tag}" ${quotedUrl} ${quotedDir}`, {
69807
+ execSync2(`git clone --depth 1 --branch "${tag}" ${quotedUrl} ${quotedDir}`, {
69872
69808
  stdio: ["pipe", "pipe", "pipe"],
69873
69809
  timeout,
69874
69810
  encoding: "utf-8"
@@ -69879,12 +69815,12 @@ Check disk space and directory permissions.`);
69879
69815
  logger.debug(`Shallow clone failed for tag ${tag}, trying full clone...`);
69880
69816
  await fs19.promises.rm(tempDir, { recursive: true, force: true }).catch(() => {});
69881
69817
  await fs19.promises.mkdir(tempDir, { recursive: true });
69882
- execSync3(`git clone --no-checkout ${quotedUrl} ${quotedDir}`, {
69818
+ execSync2(`git clone --no-checkout ${quotedUrl} ${quotedDir}`, {
69883
69819
  stdio: ["pipe", "pipe", "pipe"],
69884
69820
  timeout,
69885
69821
  encoding: "utf-8"
69886
69822
  });
69887
- execSync3(`git -C ${quotedDir} checkout "tags/${tag}"`, {
69823
+ execSync2(`git -C ${quotedDir} checkout "tags/${tag}"`, {
69888
69824
  stdio: ["pipe", "pipe", "pipe"],
69889
69825
  timeout: 30000,
69890
69826
  encoding: "utf-8"
@@ -69932,7 +69868,7 @@ Ensure you have access to the repository and your git credentials are configured
69932
69868
  }
69933
69869
  static isGitInstalled() {
69934
69870
  try {
69935
- execSync3("git --version", { stdio: "ignore", timeout: 5000 });
69871
+ execSync2("git --version", { stdio: "ignore", timeout: 5000 });
69936
69872
  return true;
69937
69873
  } catch {
69938
69874
  return false;
@@ -69957,7 +69893,7 @@ Ensure you have access to the repository and your git credentials are configured
69957
69893
  }
69958
69894
  static async testSshConnection() {
69959
69895
  try {
69960
- execSync3("ssh -T git@github.com 2>&1 || true", {
69896
+ execSync2("ssh -T git@github.com 2>&1 || true", {
69961
69897
  encoding: "utf-8",
69962
69898
  timeout: 1e4
69963
69899
  });
@@ -70172,7 +70108,7 @@ init_registry();
70172
70108
  init_environment();
70173
70109
  import { constants as constants2, access as access2, mkdir as mkdir19, readFile as readFile41, unlink as unlink9, writeFile as writeFile26 } from "node:fs/promises";
70174
70110
  import { arch as arch2, homedir as homedir26, platform as platform6 } from "node:os";
70175
- import { join as join92, normalize as normalize8 } from "node:path";
70111
+ import { join as join93, normalize as normalize8 } from "node:path";
70176
70112
  function shouldSkipExpensiveOperations4() {
70177
70113
  return shouldSkipExpensiveOperations();
70178
70114
  }
@@ -70265,7 +70201,7 @@ async function checkGlobalDirAccess(provider) {
70265
70201
  autoFixable: false
70266
70202
  };
70267
70203
  }
70268
- const testFile = join92(globalDir, ".tkm-doctor-access-test");
70204
+ const testFile = join93(globalDir, ".tkm-doctor-access-test");
70269
70205
  try {
70270
70206
  await mkdir19(globalDir, { recursive: true });
70271
70207
  await writeFile26(testFile, "test", "utf-8");
@@ -70343,7 +70279,7 @@ async function checkWSLBoundary() {
70343
70279
  // src/domains/health-checks/platform/windows-checker.ts
70344
70280
  init_registry();
70345
70281
  import { mkdir as mkdir20, symlink as symlink2, unlink as unlink10, writeFile as writeFile27 } from "node:fs/promises";
70346
- import { join as join93 } from "node:path";
70282
+ import { join as join94 } from "node:path";
70347
70283
  async function checkLongPathSupport() {
70348
70284
  if (shouldSkipExpensiveOperations4()) {
70349
70285
  return {
@@ -70357,8 +70293,8 @@ async function checkLongPathSupport() {
70357
70293
  };
70358
70294
  }
70359
70295
  try {
70360
- const { execSync: execSync4 } = await import("node:child_process");
70361
- const result = execSync4('reg query "HKLM\\SYSTEM\\CurrentControlSet\\Control\\FileSystem" /v LongPathsEnabled', { encoding: "utf-8", timeout: 2000 });
70296
+ const { execSync: execSync3 } = await import("node:child_process");
70297
+ const result = execSync3('reg query "HKLM\\SYSTEM\\CurrentControlSet\\Control\\FileSystem" /v LongPathsEnabled', { encoding: "utf-8", timeout: 2000 });
70362
70298
  const enabled = result.includes("0x1");
70363
70299
  return {
70364
70300
  id: "long-path-support",
@@ -70395,8 +70331,8 @@ async function checkSymlinkSupport() {
70395
70331
  };
70396
70332
  }
70397
70333
  const testDir = getInstaller("claude-code")?.globalRoot() ?? "";
70398
- const target = join93(testDir, ".tkm-symlink-test-target");
70399
- const link = join93(testDir, ".tkm-symlink-test-link");
70334
+ const target = join94(testDir, ".tkm-symlink-test-target");
70335
+ const link = join94(testDir, ".tkm-symlink-test-link");
70400
70336
  try {
70401
70337
  await mkdir20(testDir, { recursive: true });
70402
70338
  await writeFile27(target, "test", "utf-8");
@@ -70689,10 +70625,10 @@ class AutoHealer {
70689
70625
  }
70690
70626
  }
70691
70627
  // src/domains/health-checks/report-generator.ts
70692
- import { execSync as execSync4, spawnSync as spawnSync4 } from "node:child_process";
70628
+ import { execSync as execSync3, spawnSync as spawnSync4 } from "node:child_process";
70693
70629
  import { readFileSync as readFileSync11, unlinkSync as unlinkSync5, writeFileSync as writeFileSync6 } from "node:fs";
70694
70630
  import { tmpdir as tmpdir2 } from "node:os";
70695
- import { dirname as dirname23, join as join94 } from "node:path";
70631
+ import { dirname as dirname23, join as join95 } from "node:path";
70696
70632
  import { fileURLToPath as fileURLToPath2 } from "node:url";
70697
70633
  init_environment();
70698
70634
  init_logger();
@@ -70700,7 +70636,7 @@ init_dist2();
70700
70636
  function getCliVersion3() {
70701
70637
  try {
70702
70638
  const __dirname3 = dirname23(fileURLToPath2(import.meta.url));
70703
- const pkgPath = join94(__dirname3, "../../../package.json");
70639
+ const pkgPath = join95(__dirname3, "../../../package.json");
70704
70640
  const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
70705
70641
  return pkg.version || "unknown";
70706
70642
  } catch (err) {
@@ -70825,7 +70761,7 @@ class ReportGenerator {
70825
70761
  }
70826
70762
  async uploadToGist(report) {
70827
70763
  try {
70828
- execSync4("gh --version", { stdio: "ignore" });
70764
+ execSync3("gh --version", { stdio: "ignore" });
70829
70765
  } catch {
70830
70766
  logger.warning("GitHub CLI not installed, skipping gist upload");
70831
70767
  return null;
@@ -70839,7 +70775,7 @@ class ReportGenerator {
70839
70775
  return null;
70840
70776
  }
70841
70777
  }
70842
- const tmpFile = join94(tmpdir2(), `tkm-report-${Date.now()}.txt`);
70778
+ const tmpFile = join95(tmpdir2(), `tkm-report-${Date.now()}.txt`);
70843
70779
  writeFileSync6(tmpFile, report);
70844
70780
  try {
70845
70781
  const result = spawnSync4("gh", ["gist", "create", tmpFile, "--desc", "Takumi Diagnostic Report"], {
@@ -71159,12 +71095,12 @@ var conventionDescriptiveName = {
71159
71095
  };
71160
71096
 
71161
71097
  // src/domains/hooks/handlers/convention-quality-gate/command-runner.ts
71162
- import { execSync as execSync5 } from "node:child_process";
71098
+ import { execSync as execSync4 } from "node:child_process";
71163
71099
 
71164
71100
  // src/domains/hooks/handlers/_shared/env-file.ts
71165
71101
  import { randomUUID as randomUUID2 } from "node:crypto";
71166
71102
  import { renameSync as renameSync2, unlinkSync as unlinkSync6, writeFileSync as writeFileSync7 } from "node:fs";
71167
- import { basename as basename16, dirname as dirname24, join as join95 } from "node:path";
71103
+ import { basename as basename16, dirname as dirname24, join as join96 } from "node:path";
71168
71104
  function hexEscape(code) {
71169
71105
  return `\\x${code.toString(16).padStart(2, "0")}`;
71170
71106
  }
@@ -71217,7 +71153,7 @@ function renderEnvFile(entries) {
71217
71153
  function writeEnvFile(filePath, entries) {
71218
71154
  const content = renderEnvFile(entries);
71219
71155
  const dir = dirname24(filePath);
71220
- const tmpPath = join95(dir, `.${basename16(filePath)}.${randomUUID2()}.tmp`);
71156
+ const tmpPath = join96(dir, `.${basename16(filePath)}.${randomUUID2()}.tmp`);
71221
71157
  try {
71222
71158
  writeFileSync7(tmpPath, content, { encoding: "utf8", mode: 384 });
71223
71159
  } catch (err) {
@@ -71244,7 +71180,7 @@ function substituteFileToken(command, filePath) {
71244
71180
  }
71245
71181
  var defaultCommandRunner = (command, opts) => {
71246
71182
  try {
71247
- execSync5(command, {
71183
+ execSync4(command, {
71248
71184
  cwd: opts.cwd,
71249
71185
  timeout: opts.timeoutMs,
71250
71186
  encoding: "utf8",
@@ -71265,10 +71201,10 @@ var defaultCommandRunner = (command, opts) => {
71265
71201
  // src/domains/hooks/handlers/convention-quality-gate/debounce.ts
71266
71202
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "node:fs";
71267
71203
  import { tmpdir as tmpdir3 } from "node:os";
71268
- import { join as join96 } from "node:path";
71204
+ import { join as join97 } from "node:path";
71269
71205
  function stateFilePath(sessionId) {
71270
71206
  const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 128) || "default";
71271
- return join96(tmpdir3(), `takumi-guardrail-${safe}.json`);
71207
+ return join97(tmpdir3(), `takumi-guardrail-${safe}.json`);
71272
71208
  }
71273
71209
  function isWithinDebounce(sessionId, debounceMs, now) {
71274
71210
  try {
@@ -71416,6 +71352,7 @@ var conventionQualityGate = {
71416
71352
 
71417
71353
  // src/domains/hooks/handlers/extension-skill/handler.ts
71418
71354
  import fs20 from "node:fs";
71355
+ import os7 from "node:os";
71419
71356
  import path9 from "node:path";
71420
71357
  var CONFIG_KEY2 = "skill-extension-loader";
71421
71358
  var SKILLS_ROOT_SEGMENTS = [".claude", "skills"];
@@ -71470,9 +71407,9 @@ function readFrontmatter(raw) {
71470
71407
  `).trim()
71471
71408
  };
71472
71409
  }
71473
- function renderBlock(skill, relBase, kept, skipped) {
71410
+ function renderBlock(skill, kept, skipped) {
71474
71411
  const parts = [
71475
- `Skill extensions for "${skill}" (user-owned, from ${relBase}/)`,
71412
+ `Skill extensions for "${skill}" (user-owned, local + team-shared)`,
71476
71413
  "Apply order: pre → override → post. The entries below are already in that order; layer them on top of the shipped skill instructions."
71477
71414
  ];
71478
71415
  const totalChars = kept.reduce((n, e2) => n + e2.body.length, 0);
@@ -71495,36 +71432,54 @@ ${refs}`);
71495
71432
 
71496
71433
  `);
71497
71434
  }
71498
- function loadExtensions(input, ctx) {
71499
- if (input.tool_name !== "Skill")
71500
- return NO_OP2;
71501
- const toolInput = input.tool_input;
71502
- const skill = toolInput && typeof toolInput.skill === "string" ? toolInput.skill.trim() : "";
71503
- if (!skill)
71504
- return NO_OP2;
71505
- const cwd2 = typeof input.cwd === "string" && input.cwd ? input.cwd : ctx.cwd;
71506
- const skillDir = baseSkillName(skill);
71507
- if (!skillDir)
71508
- return NO_OP2;
71509
- const skillsRoot = path9.resolve(cwd2, ...SKILLS_ROOT_SEGMENTS);
71510
- const extDir = path9.resolve(skillsRoot, skillDir, "extensions");
71511
- if (extDir !== skillsRoot && !extDir.startsWith(skillsRoot + path9.sep))
71512
- return NO_OP2;
71435
+ function displayRel(cwd2, filePath) {
71436
+ const rel = path9.relative(cwd2, filePath);
71437
+ return rel.startsWith("..") ? filePath : rel;
71438
+ }
71439
+ function resolveLocalExtDir(skillDir, roots) {
71440
+ const seen = new Set;
71441
+ for (const root of roots) {
71442
+ if (!root || seen.has(root))
71443
+ continue;
71444
+ seen.add(root);
71445
+ const skillsRoot = path9.resolve(root, ...SKILLS_ROOT_SEGMENTS);
71446
+ const extDir = path9.resolve(skillsRoot, skillDir, "extensions");
71447
+ if (extDir !== skillsRoot && !extDir.startsWith(skillsRoot + path9.sep))
71448
+ continue;
71449
+ if (fs20.existsSync(extDir))
71450
+ return extDir;
71451
+ }
71452
+ return null;
71453
+ }
71454
+ function resolveSharedExtDir(skillDir, sharedDirRaw, projectRoot) {
71455
+ const raw = typeof sharedDirRaw === "string" ? sharedDirRaw.trim() : "";
71456
+ if (!raw)
71457
+ return null;
71458
+ const sharedRoot = path9.isAbsolute(raw) ? raw : path9.resolve(projectRoot, raw);
71459
+ if (!path9.isAbsolute(raw) && sharedRoot !== projectRoot && !sharedRoot.startsWith(projectRoot + path9.sep)) {
71460
+ return null;
71461
+ }
71462
+ const cand = path9.resolve(sharedRoot, skillDir);
71463
+ if (cand !== sharedRoot && !cand.startsWith(sharedRoot + path9.sep))
71464
+ return null;
71465
+ return fs20.existsSync(cand) ? cand : null;
71466
+ }
71467
+ function readExtensionsFromDir(extDir, skillDir, cwd2) {
71468
+ const kept = [];
71469
+ const skipped = [];
71513
71470
  let entries;
71514
71471
  try {
71515
71472
  entries = fs20.readdirSync(extDir, { withFileTypes: true });
71516
71473
  } catch {
71517
- return NO_OP2;
71474
+ return { kept, skipped };
71518
71475
  }
71519
- const relBase = `.claude/skills/${skillDir}/extensions`;
71520
- const kept = [];
71521
- const skipped = [];
71522
71476
  for (const entry of entries) {
71523
71477
  if (!entry.isFile() || !entry.name.toLowerCase().endsWith(".md"))
71524
71478
  continue;
71479
+ const absPath = path9.join(extDir, entry.name);
71525
71480
  let raw;
71526
71481
  try {
71527
- raw = fs20.readFileSync(path9.join(extDir, entry.name), "utf8");
71482
+ raw = fs20.readFileSync(absPath, "utf8");
71528
71483
  } catch {
71529
71484
  skipped.push(entry.name);
71530
71485
  continue;
@@ -71536,12 +71491,37 @@ function loadExtensions(input, ctx) {
71536
71491
  skipped.push(entry.name);
71537
71492
  continue;
71538
71493
  }
71539
- kept.push({ file: entry.name, relPath: `${relBase}/${entry.name}`, type, body: parsed.body });
71494
+ kept.push({ file: entry.name, relPath: displayRel(cwd2, absPath), type, body: parsed.body });
71540
71495
  }
71496
+ return { kept, skipped };
71497
+ }
71498
+ function loadExtensions(input, ctx) {
71499
+ if (input.tool_name !== "Skill")
71500
+ return NO_OP2;
71501
+ const toolInput = input.tool_input;
71502
+ const skill = toolInput && typeof toolInput.skill === "string" ? toolInput.skill.trim() : "";
71503
+ if (!skill)
71504
+ return NO_OP2;
71505
+ const cwd2 = typeof input.cwd === "string" && input.cwd ? input.cwd : ctx.cwd;
71506
+ const skillDir = baseSkillName(skill);
71507
+ if (!skillDir)
71508
+ return NO_OP2;
71509
+ const projectDir = process.env.CLAUDE_PROJECT_DIR ?? "";
71510
+ const home6 = os7.homedir();
71511
+ const primaryRoot = projectDir || cwd2;
71512
+ const localExtDir = resolveLocalExtDir(skillDir, [projectDir, cwd2, home6]);
71513
+ const sharedExtDir = resolveSharedExtDir(skillDir, ctx.config?.skillExtensions?.sharedDir, primaryRoot);
71514
+ if (!localExtDir && !sharedExtDir)
71515
+ return NO_OP2;
71516
+ const local = localExtDir ? readExtensionsFromDir(localExtDir, skillDir, cwd2) : { kept: [], skipped: [] };
71517
+ const shared = sharedExtDir ? readExtensionsFromDir(sharedExtDir, skillDir, cwd2) : { kept: [], skipped: [] };
71518
+ const localNames = new Set(local.kept.map((e2) => e2.file));
71519
+ const kept = [...local.kept, ...shared.kept.filter((e2) => !localNames.has(e2.file))];
71520
+ const skipped = [...local.skipped, ...shared.skipped];
71541
71521
  if (kept.length === 0)
71542
71522
  return NO_OP2;
71543
71523
  kept.sort((a3, b3) => a3.type.order - b3.type.order || a3.file.localeCompare(b3.file));
71544
- return { status: "context", output: renderBlock(skill, relBase, kept, skipped), timingMs: 0 };
71524
+ return { status: "context", output: renderBlock(skill, kept, skipped), timingMs: 0 };
71545
71525
  }
71546
71526
  var extensionSkill = {
71547
71527
  name: "extension-skill",
@@ -71693,7 +71673,7 @@ function detectBroadGlob(pattern, pathHint) {
71693
71673
  // src/domains/hooks/handlers/guard-breadth-scout/check-ignore.ts
71694
71674
  var import_ignore5 = __toESM(require_ignore(), 1);
71695
71675
  import { existsSync as existsSync47, readFileSync as readFileSync13 } from "node:fs";
71696
- import { dirname as dirname25, join as join97 } from "node:path";
71676
+ import { dirname as dirname25, join as join98 } from "node:path";
71697
71677
  var BUILTIN_HEAVY_DIR_LINES = [
71698
71678
  "node_modules",
71699
71679
  ".pnp",
@@ -71730,7 +71710,7 @@ var BUILTIN_HEAVY_DIR_LINES = [
71730
71710
  function findGitRoot(startDir) {
71731
71711
  let dir = startDir;
71732
71712
  while (true) {
71733
- if (existsSync47(join97(dir, ".git")))
71713
+ if (existsSync47(join98(dir, ".git")))
71734
71714
  return dir;
71735
71715
  const parent = dirname25(dir);
71736
71716
  if (parent === dir)
@@ -71760,9 +71740,9 @@ function loadIgnoreConfig(cwd2) {
71760
71740
  const gitRoot = findGitRoot(cwd2);
71761
71741
  const candidatePaths = [];
71762
71742
  if (gitRoot) {
71763
- candidatePaths.push(join97(gitRoot, ".claude", ".tkmignore"));
71743
+ candidatePaths.push(join98(gitRoot, ".claude", ".tkmignore"));
71764
71744
  }
71765
- candidatePaths.push(join97(cwd2, ".claude", ".tkmignore"));
71745
+ candidatePaths.push(join98(cwd2, ".claude", ".tkmignore"));
71766
71746
  for (const candidate of candidatePaths) {
71767
71747
  const lines = readIgnoreFile(candidate);
71768
71748
  if (lines !== null) {
@@ -72167,7 +72147,10 @@ var guardJailbreak = {
72167
72147
  events: ["PreToolUse"],
72168
72148
  matchers: { PreToolUse: "Bash|Glob|Grep|Read|Edit|Write" },
72169
72149
  denyOnTimeout: true,
72170
- run(input) {
72150
+ run(input, ctx) {
72151
+ if (!isHandlerEnabled(ctx, "guard-jailbreak")) {
72152
+ return NO_OP3;
72153
+ }
72171
72154
  if (typeof input?.tool_name !== "string" || input.tool_name.length === 0) {
72172
72155
  return ALLOW;
72173
72156
  }
@@ -72458,7 +72441,7 @@ function resolveEndpoint() {
72458
72441
  init_manifest_path_resolver();
72459
72442
  import { existsSync as existsSync48, readFileSync as readFileSync14 } from "node:fs";
72460
72443
  import { homedir as homedir27 } from "node:os";
72461
- import { dirname as dirname26, join as join98, resolve as resolve23 } from "node:path";
72444
+ import { dirname as dirname26, join as join99, resolve as resolve23 } from "node:path";
72462
72445
  var PROVIDER_DIRS = [".claude", ".codex"];
72463
72446
  var MAX_WALK = 6;
72464
72447
  function readManifestRaw(path10) {
@@ -72477,7 +72460,7 @@ function findManifest(cwd2) {
72477
72460
  let dir = resolve23(cwd2);
72478
72461
  for (let i = 0;i < MAX_WALK; i++) {
72479
72462
  for (const provider of PROVIDER_DIRS) {
72480
- const providerRoot = join98(dir, provider);
72463
+ const providerRoot = join99(dir, provider);
72481
72464
  if (existsSync48(providerRoot)) {
72482
72465
  const path10 = findManifestInProviderDir(providerRoot);
72483
72466
  if (path10)
@@ -72491,11 +72474,11 @@ function findManifest(cwd2) {
72491
72474
  }
72492
72475
  const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT;
72493
72476
  if (pluginRoot) {
72494
- const pluginPath = findManifestInProviderDir(join98(pluginRoot, ".claude"));
72477
+ const pluginPath = findManifestInProviderDir(join99(pluginRoot, ".claude"));
72495
72478
  if (pluginPath)
72496
72479
  return pluginPath;
72497
72480
  }
72498
- const globalPath = findManifestInProviderDir(join98(homedir27(), ".claude"));
72481
+ const globalPath = findManifestInProviderDir(join99(homedir27(), ".claude"));
72499
72482
  if (globalPath)
72500
72483
  return globalPath;
72501
72484
  return null;
@@ -72651,7 +72634,7 @@ function bucketTokens(records) {
72651
72634
  // src/domains/hooks/telemetry/lib/session-lock.ts
72652
72635
  var import_proper_lockfile9 = __toESM(require_proper_lockfile(), 1);
72653
72636
  import { promises as fs21 } from "node:fs";
72654
- import { join as join99 } from "node:path";
72637
+ import { join as join100 } from "node:path";
72655
72638
  var LOCK_RESOURCE = "summary.json";
72656
72639
  var DEFAULT_TIMEOUT_MS3 = 2000;
72657
72640
  var RETRY_INTERVAL_MS = 100;
@@ -72659,7 +72642,7 @@ var DEFAULT_STALE_AFTER_MS = 1e4;
72659
72642
  async function withSummaryLock(sessionDir, fn, options2 = {}) {
72660
72643
  const timeoutMs = options2.timeoutMs ?? DEFAULT_TIMEOUT_MS3;
72661
72644
  const staleAfterMs = options2.staleAfterMs ?? DEFAULT_STALE_AFTER_MS;
72662
- const resource = join99(sessionDir, LOCK_RESOURCE);
72645
+ const resource = join100(sessionDir, LOCK_RESOURCE);
72663
72646
  try {
72664
72647
  await fs21.mkdir(sessionDir, { recursive: true });
72665
72648
  } catch {
@@ -72695,13 +72678,13 @@ import { promises as fs22 } from "node:fs";
72695
72678
 
72696
72679
  // src/domains/hooks/telemetry/lib/session-paths.ts
72697
72680
  init_paths2();
72698
- import { join as join101 } from "node:path";
72681
+ import { join as join102 } from "node:path";
72699
72682
 
72700
72683
  // src/shared/project-paths.ts
72701
72684
  init_paths2();
72702
72685
  import { createHash as createHash11 } from "node:crypto";
72703
72686
  import { realpathSync as realpathSync2 } from "node:fs";
72704
- import { basename as basename17, join as join100 } from "node:path";
72687
+ import { basename as basename17, join as join101 } from "node:path";
72705
72688
  function encodeCwd(cwd2) {
72706
72689
  const stripped = cwd2.replace(/^\/+/, "");
72707
72690
  const sanitized = stripped.replace(/[^a-zA-Z0-9-]/g, "-");
@@ -72720,10 +72703,10 @@ function getProjectLabel(cwd2) {
72720
72703
  return basename17(cwd2) || "";
72721
72704
  }
72722
72705
  function getProjectsRoot() {
72723
- return join100(getConfigDir(), "projects");
72706
+ return join101(getConfigDir(), "projects");
72724
72707
  }
72725
72708
  function getProjectDir(args) {
72726
- return join100(getProjectsRoot(), encodeCwd(args.cwd), args.agent);
72709
+ return join101(getProjectsRoot(), encodeCwd(args.cwd), args.agent);
72727
72710
  }
72728
72711
 
72729
72712
  // src/domains/hooks/telemetry/lib/session-paths.ts
@@ -72735,35 +72718,35 @@ function safeSessionSegment(sessionId) {
72735
72718
  return cleaned.length > 0 ? cleaned.slice(0, MAX_SESSION_ID_LEN) : null;
72736
72719
  }
72737
72720
  function getSessionsRoot() {
72738
- return join101(getConfigDir(), "sessions");
72721
+ return join102(getConfigDir(), "sessions");
72739
72722
  }
72740
72723
  function getSessionDirV2(args) {
72741
72724
  const segment = safeSessionSegment(args.sessionId);
72742
72725
  if (!segment)
72743
72726
  return null;
72744
- return join101(getProjectDir({ agent: args.agent, cwd: args.cwd }), "sessions", segment);
72727
+ return join102(getProjectDir({ agent: args.agent, cwd: args.cwd }), "sessions", segment);
72745
72728
  }
72746
72729
  function getEventsFile(sessionDir) {
72747
- return join101(sessionDir, "events.jsonl");
72730
+ return join102(sessionDir, "events.jsonl");
72748
72731
  }
72749
72732
  function getSummaryFile(sessionDir) {
72750
- return join101(sessionDir, "summary.json");
72733
+ return join102(sessionDir, "summary.json");
72751
72734
  }
72752
72735
  function getLastPushFile(sessionDir) {
72753
- return join101(sessionDir, "last_push.txt");
72736
+ return join102(sessionDir, "last_push.txt");
72754
72737
  }
72755
72738
  var OBSERVATIONS_FILENAME = "observations.jsonl";
72756
72739
  function getObservationsFile(sessionDir) {
72757
- return join101(sessionDir, OBSERVATIONS_FILENAME);
72740
+ return join102(sessionDir, OBSERVATIONS_FILENAME);
72758
72741
  }
72759
72742
  function getObservationsFlushingFile(sessionDir) {
72760
- return join101(sessionDir, `${OBSERVATIONS_FILENAME}.flushing`);
72743
+ return join102(sessionDir, `${OBSERVATIONS_FILENAME}.flushing`);
72761
72744
  }
72762
72745
  function getObservationsPushedFile(sessionDir) {
72763
- return join101(sessionDir, "obs_pushed.txt");
72746
+ return join102(sessionDir, "obs_pushed.txt");
72764
72747
  }
72765
72748
  function getMetaFile(sessionDir) {
72766
- return join101(sessionDir, "meta.json");
72749
+ return join102(sessionDir, "meta.json");
72767
72750
  }
72768
72751
 
72769
72752
  // src/domains/hooks/telemetry/lib/summary.ts
@@ -72985,7 +72968,7 @@ async function applyClaudeTranscriptDelta(args) {
72985
72968
  // src/domains/hooks/telemetry/lib/detached-put.ts
72986
72969
  import { spawn as spawn2 } from "node:child_process";
72987
72970
  import { openSync as openSync5 } from "node:fs";
72988
- import { dirname as dirname27, join as join102 } from "node:path";
72971
+ import { dirname as dirname27, join as join103 } from "node:path";
72989
72972
  var ALLOWED_ENV_PREFIXES = ["TKM_", "TAKUMI_"];
72990
72973
  var ALLOWED_ENV_KEYS = new Set(["HOME", "USERPROFILE", "PATH", "NODE_ENV"]);
72991
72974
  var DETACH_DEBUG_LOG_NAME = "detach-debug.log";
@@ -72993,7 +72976,7 @@ function effectiveDetachMode(flags) {
72993
72976
  return flags.noDetach ? "inline" : "detached";
72994
72977
  }
72995
72978
  function sessionDebugLogPath(sessionDir) {
72996
- return join102(sessionDir, DETACH_DEBUG_LOG_NAME);
72979
+ return join103(sessionDir, DETACH_DEBUG_LOG_NAME);
72997
72980
  }
72998
72981
  var BUNFS_PREFIX = "/$bunfs/";
72999
72982
  var REENTRY_VERBS = ["hooks", "hook-exec"];
@@ -73013,8 +72996,7 @@ function resolveInvocationPrefix() {
73013
72996
  if (verbIdx === -1) {
73014
72997
  if (isCompiledBunBinary)
73015
72998
  return { command, prefixArgs: [] };
73016
- const isScriptEntry = typeof entry === "string" && (entry.endsWith(".ts") || entry.endsWith(".js"));
73017
- return { command, prefixArgs: isScriptEntry ? [entry] : [] };
72999
+ return { command, prefixArgs: typeof entry === "string" && entry.length > 0 ? [entry] : [] };
73018
73000
  }
73019
73001
  if (isCompiledBunBinary) {
73020
73002
  return { command, prefixArgs: [] };
@@ -73034,7 +73016,7 @@ function resolvePreloadScript(entryPath) {
73034
73016
  try {
73035
73017
  const srcDir = dirname27(entryPath);
73036
73018
  const repoRoot = dirname27(srcDir);
73037
- return join102(repoRoot, "scripts", "preload-config-override.ts");
73019
+ return join103(repoRoot, "scripts", "preload-config-override.ts");
73038
73020
  } catch {
73039
73021
  return null;
73040
73022
  }
@@ -73318,8 +73300,8 @@ async function runSessionEndFlush(data, ctx) {
73318
73300
  session_end_raw: data
73319
73301
  };
73320
73302
  const { promises: fs25 } = await import("node:fs");
73321
- const { join: join105 } = await import("node:path");
73322
- const target = join105(sessionDir, "meta.json");
73303
+ const { join: join106 } = await import("node:path");
73304
+ const target = join106(sessionDir, "meta.json");
73323
73305
  const tmp = `${target}.tmp`;
73324
73306
  await fs25.writeFile(tmp, JSON.stringify(updated), "utf8");
73325
73307
  await fs25.rename(tmp, target);
@@ -73807,11 +73789,11 @@ async function handleStop(agent, flags = {}) {
73807
73789
  // src/domains/hooks/telemetry/otlp/observations-export.ts
73808
73790
  init_paths2();
73809
73791
  import { promises as fs30, openSync as openSync9 } from "node:fs";
73810
- import { join as join106 } from "node:path";
73792
+ import { join as join107 } from "node:path";
73811
73793
 
73812
73794
  // src/domains/hooks/telemetry/lib/retention.ts
73813
73795
  import { promises as fs27 } from "node:fs";
73814
- import { join as join105 } from "node:path";
73796
+ import { join as join106 } from "node:path";
73815
73797
  async function pathExists25(path10) {
73816
73798
  try {
73817
73799
  await fs27.access(path10);
@@ -73846,7 +73828,7 @@ async function decideDelete(dir, args) {
73846
73828
  async function listChildren(dir) {
73847
73829
  try {
73848
73830
  const names = await fs27.readdir(dir);
73849
- return names.map((n2) => join105(dir, n2));
73831
+ return names.map((n2) => join106(dir, n2));
73850
73832
  } catch {
73851
73833
  return [];
73852
73834
  }
@@ -73857,7 +73839,7 @@ async function collectV2Sessions() {
73857
73839
  const sessions = [];
73858
73840
  for (const projectDir of projects) {
73859
73841
  for (const agentDir of await listChildren(projectDir)) {
73860
- for (const sessionDir of await listChildren(join105(agentDir, "sessions"))) {
73842
+ for (const sessionDir of await listChildren(join106(agentDir, "sessions"))) {
73861
73843
  sessions.push(sessionDir);
73862
73844
  }
73863
73845
  }
@@ -74286,7 +74268,7 @@ async function exportSessionObservations(sessionDir, opts = {}, deps = {}) {
74286
74268
  }
74287
74269
  }
74288
74270
  function lockPath() {
74289
- return join106(getConfigDir(), "obs-flush.lock");
74271
+ return join107(getConfigDir(), "obs-flush.lock");
74290
74272
  }
74291
74273
  async function acquireSweepLock(now) {
74292
74274
  const path10 = lockPath();
@@ -74925,7 +74907,7 @@ var metricsRecord = {
74925
74907
 
74926
74908
  // src/domains/statusline/activity-cache.ts
74927
74909
  import { readdirSync as readdirSync8, rmSync as rmSync5, statSync as statSync8 } from "node:fs";
74928
- import { join as join107 } from "node:path";
74910
+ import { join as join108 } from "node:path";
74929
74911
 
74930
74912
  // src/domains/statusline/activity-snapshot.ts
74931
74913
  import { existsSync as existsSync51 } from "node:fs";
@@ -75385,7 +75367,7 @@ function cleanupStaleActivity(now = Date.now()) {
75385
75367
  for (const entry of entries) {
75386
75368
  if (!entry.startsWith(FILE_PREFIX) || !entry.endsWith(FILE_SUFFIX))
75387
75369
  continue;
75388
- const full = join107(getStatuslineCacheDir(), entry);
75370
+ const full = join108(getStatuslineCacheDir(), entry);
75389
75371
  try {
75390
75372
  if (now - statSync8(full).mtimeMs > ACTIVITY_TTL_MS)
75391
75373
  rmSync5(full, { force: true });
@@ -75450,11 +75432,11 @@ var sessionActivity = {
75450
75432
 
75451
75433
  // src/domains/hooks/handlers/session-init/handler.ts
75452
75434
  import { mkdirSync as mkdirSync6 } from "node:fs";
75453
- import { dirname as dirname29, join as join111 } from "node:path";
75435
+ import { dirname as dirname29, join as join113 } from "node:path";
75454
75436
 
75455
75437
  // src/domains/hooks/handlers/_shared/project-detector.ts
75456
75438
  import { existsSync as existsSync52, readFileSync as readFileSync16 } from "node:fs";
75457
- import { join as join108 } from "node:path";
75439
+ import { join as join109 } from "node:path";
75458
75440
  var LOCKFILE_PRIORITY = [
75459
75441
  { manager: "bun", files: ["bun.lockb", "bun.lock"] },
75460
75442
  { manager: "pnpm", files: ["pnpm-lock.yaml"] },
@@ -75489,14 +75471,14 @@ var APP_FRAMEWORKS = new Set([
75489
75471
  var WORKSPACE_MARKER_FILES = ["pnpm-workspace.yaml", "turbo.json", "lerna.json"];
75490
75472
  function fileExists(cwd2, name2) {
75491
75473
  try {
75492
- return existsSync52(join108(cwd2, name2));
75474
+ return existsSync52(join109(cwd2, name2));
75493
75475
  } catch {
75494
75476
  return false;
75495
75477
  }
75496
75478
  }
75497
75479
  function readPackageJson(cwd2) {
75498
75480
  try {
75499
- const raw = readFileSync16(join108(cwd2, "package.json"), "utf8");
75481
+ const raw = readFileSync16(join109(cwd2, "package.json"), "utf8");
75500
75482
  const parsed = JSON.parse(raw);
75501
75483
  if (parsed && typeof parsed === "object")
75502
75484
  return parsed;
@@ -75577,14 +75559,86 @@ function detectProject(cwd2) {
75577
75559
  };
75578
75560
  }
75579
75561
 
75562
+ // src/domains/hooks/handlers/session-init/context-blocks.ts
75563
+ import { readFileSync as readFileSync17 } from "node:fs";
75564
+ import { join as join110 } from "node:path";
75565
+ var CODING_LEVEL_STYLE_FILES = {
75566
+ 0: "coding-level-0-eli5",
75567
+ 1: "coding-level-1-junior",
75568
+ 2: "coding-level-2-middle",
75569
+ 3: "coding-level-3-senior",
75570
+ 4: "coding-level-4-expert",
75571
+ 5: "coding-level-5-principal"
75572
+ };
75573
+ function compactionApprovalWarning(source) {
75574
+ if (source !== "compact")
75575
+ return null;
75576
+ return [
75577
+ "⚠️ CONTEXT COMPACTED - APPROVAL STATE CHECK:",
75578
+ "If you were waiting for user approval via AskUserQuestion (e.g., a review gate),",
75579
+ "you MUST re-confirm with the user before proceeding. Do NOT assume approval was given.",
75580
+ 'Use AskUserQuestion to verify: "Context was compacted. Please confirm approval to continue."'
75581
+ ].join(`
75582
+ `);
75583
+ }
75584
+ function codingLevelGuidelines(codingLevel, settingsDir) {
75585
+ if (typeof codingLevel !== "number")
75586
+ return null;
75587
+ const styleFile = CODING_LEVEL_STYLE_FILES[codingLevel];
75588
+ if (!styleFile)
75589
+ return null;
75590
+ try {
75591
+ const stylePath = join110(settingsDir, "output-styles", `${styleFile}.md`);
75592
+ const content = readFileSync17(stylePath, "utf8");
75593
+ const withoutFrontmatter = content.replace(/^---[\s\S]*?---\n*/, "").trim();
75594
+ return withoutFrontmatter.length > 0 ? withoutFrontmatter : null;
75595
+ } catch {
75596
+ return null;
75597
+ }
75598
+ }
75599
+ function renderAssertion(assertion) {
75600
+ if (typeof assertion === "string")
75601
+ return assertion;
75602
+ if (assertion && typeof assertion === "object") {
75603
+ const a3 = assertion;
75604
+ const text = typeof a3.message === "string" ? a3.message : typeof a3.rule === "string" ? a3.rule : "";
75605
+ const pattern = typeof a3.pattern === "string" && a3.pattern.length > 0 ? ` (${a3.pattern})` : "";
75606
+ if (text)
75607
+ return `${text}${pattern}`;
75608
+ }
75609
+ return String(assertion);
75610
+ }
75611
+ function userAssertions(assertions) {
75612
+ if (!Array.isArray(assertions) || assertions.length === 0)
75613
+ return null;
75614
+ const lines = ["User Assertions:"];
75615
+ assertions.forEach((assertion, i) => {
75616
+ lines.push(` ${i + 1}. ${renderAssertion(assertion)}`);
75617
+ });
75618
+ return lines.join(`
75619
+ `);
75620
+ }
75621
+ function renderContextBlocks(source, ctx, settingsDir) {
75622
+ const config = ctx.config ?? {};
75623
+ const blocks = [
75624
+ compactionApprovalWarning(source),
75625
+ codingLevelGuidelines(config.codingLevel, settingsDir),
75626
+ userAssertions(config.assertions)
75627
+ ].filter((b3) => b3 !== null);
75628
+ return blocks.length > 0 ? `
75629
+ ${blocks.join(`
75630
+
75631
+ `)}` : "";
75632
+ }
75633
+
75580
75634
  // src/domains/hooks/handlers/session-init/env-entries.ts
75581
75635
  import { createHash as createHash14 } from "node:crypto";
75582
75636
  import { platform as platform9, userInfo } from "node:os";
75583
- import { join as join110 } from "node:path";
75637
+ import { join as join112 } from "node:path";
75584
75638
 
75585
75639
  // src/domains/hooks/handlers/session-init/plan-resolver.ts
75586
- import { existsSync as existsSync53, readFileSync as readFileSync17, readdirSync as readdirSync9 } from "node:fs";
75587
- import { join as join109 } from "node:path";
75640
+ import { existsSync as existsSync53, readFileSync as readFileSync18, readdirSync as readdirSync9 } from "node:fs";
75641
+ import { join as join111 } from "node:path";
75588
75642
  var MAX_PLAN_DIRS = 100;
75589
75643
  var MAX_PLAN_FILE_BYTES = 64 * 1024;
75590
75644
  function listPlanDirs(plansPath) {
@@ -75598,10 +75652,10 @@ function listPlanDirs(plansPath) {
75598
75652
  }
75599
75653
  function planFileMentionsSession(planDir, sessionId) {
75600
75654
  try {
75601
- const planFile = join109(planDir, "plan.md");
75655
+ const planFile = join111(planDir, "plan.md");
75602
75656
  if (!existsSync53(planFile))
75603
75657
  return false;
75604
- const body = readFileSync17(planFile, { encoding: "utf8" });
75658
+ const body = readFileSync18(planFile, { encoding: "utf8" });
75605
75659
  if (body.length > MAX_PLAN_FILE_BYTES)
75606
75660
  return false;
75607
75661
  return body.includes(sessionId);
@@ -75613,7 +75667,7 @@ function resolveActivePlan(plansPath, sessionId) {
75613
75667
  if (!sessionId)
75614
75668
  return "";
75615
75669
  for (const name2 of listPlanDirs(plansPath)) {
75616
- const dir = join109(plansPath, name2);
75670
+ const dir = join111(plansPath, name2);
75617
75671
  if (name2.includes(sessionId) || planFileMentionsSession(dir, sessionId)) {
75618
75672
  return dir;
75619
75673
  }
@@ -75634,7 +75688,7 @@ function resolveSuggestedPlan(plansPath, branch, branchPattern) {
75634
75688
  return "";
75635
75689
  for (const name2 of listPlanDirs(plansPath)) {
75636
75690
  if (name2.includes(slug))
75637
- return join109(plansPath, name2);
75691
+ return join111(plansPath, name2);
75638
75692
  }
75639
75693
  return "";
75640
75694
  }
@@ -75688,11 +75742,11 @@ function buildEnvEntries(params) {
75688
75742
  const plan = config.plan ?? {};
75689
75743
  const locale = config.locale ?? {};
75690
75744
  const validation = plan.validation ?? {};
75691
- const settingsDir = join110(projectRoot, ".claude");
75692
- const docsPath = join110(projectRoot, paths.docs ?? "docs");
75693
- const plansPath = join110(projectRoot, paths.plans ?? "plans");
75745
+ const settingsDir = join112(projectRoot, ".claude");
75746
+ const docsPath = join112(projectRoot, paths.docs ?? "docs");
75747
+ const plansPath = join112(projectRoot, paths.plans ?? "plans");
75694
75748
  const reportsDir = plan.reportsDir ?? "reports";
75695
- const reportsPath = join110(plansPath, reportsDir);
75749
+ const reportsPath = join112(plansPath, reportsDir);
75696
75750
  const namingFormat = plan.namingFormat ?? "";
75697
75751
  const activePlan = resolveActivePlan(plansPath, ctx.sessionId);
75698
75752
  const suggestedPlan = resolveSuggestedPlan(plansPath, branch, plan.resolution?.branchPattern ?? "");
@@ -75724,7 +75778,7 @@ function buildEnvEntries(params) {
75724
75778
  TKM_CODING_LEVEL_STYLE: codingLevelStyle(config.codingLevel),
75725
75779
  TKM_THINKING_LANGUAGE: locale.thinkingLanguage ?? "",
75726
75780
  TKM_RESPONSE_LANGUAGE: locale.responseLanguage ?? "",
75727
- TKM_SDD_MODE: "",
75781
+ TKM_SDD_MODE: config.takumi?.sddMode ?? "ask",
75728
75782
  TKM_VALIDATION_MODE: validation.mode ?? "",
75729
75783
  TKM_VALIDATION_MIN_QUESTIONS: numberString(validation.minQuestions),
75730
75784
  TKM_VALIDATION_MAX_QUESTIONS: numberString(validation.maxQuestions),
@@ -75781,7 +75835,7 @@ function resolveEnvFilePath(settingsDir) {
75781
75835
  const override = process.env.CLAUDE_ENV_FILE;
75782
75836
  if (override && override.trim().length > 0)
75783
75837
  return override;
75784
- return join111(settingsDir, DEFAULT_ENV_FILE);
75838
+ return join113(settingsDir, DEFAULT_ENV_FILE);
75785
75839
  }
75786
75840
  function persistEntries(envFilePath, entries) {
75787
75841
  try {
@@ -75826,7 +75880,8 @@ var sessionInit = {
75826
75880
  if (!persistEntries(envFilePath, entries)) {
75827
75881
  return { status: "no-op", timingMs: 0 };
75828
75882
  }
75829
- return { status: "context", output: renderBanner(source, entries), timingMs: 0 };
75883
+ const output2 = renderBanner(source, entries) + renderContextBlocks(source, ctx, entries.TKM_CLAUDE_SETTINGS_DIR ?? "");
75884
+ return { status: "context", output: output2, timingMs: 0 };
75830
75885
  } catch {
75831
75886
  return { status: "no-op", timingMs: 0 };
75832
75887
  }
@@ -75836,9 +75891,9 @@ var sessionInit = {
75836
75891
  // src/domains/hooks/handlers/_shared/context-assembler.ts
75837
75892
  import { execFileSync as execFileSync4 } from "node:child_process";
75838
75893
  import { createHash as createHash15 } from "node:crypto";
75839
- import { existsSync as existsSync54, mkdirSync as mkdirSync7, readFileSync as readFileSync18, rmSync as rmSync6, statSync as statSync9, writeFileSync as writeFileSync10 } from "node:fs";
75894
+ import { existsSync as existsSync54, mkdirSync as mkdirSync7, readFileSync as readFileSync19, rmSync as rmSync6, statSync as statSync9, writeFileSync as writeFileSync10 } from "node:fs";
75840
75895
  import { homedir as homedir29, platform as platform10, tmpdir as tmpdir4 } from "node:os";
75841
- import { basename as basename18, join as join112, resolve as resolve24 } from "node:path";
75896
+ import { basename as basename18, join as join114, resolve as resolve24 } from "node:path";
75842
75897
  var INJECTED_TTL_MS = 12 * 60 * 60 * 1000;
75843
75898
  var RESERVATION_TTL_MS = 60 * 1000;
75844
75899
  function gitBranch(dir) {
@@ -75915,18 +75970,18 @@ function scopeKey(baseDir) {
75915
75970
  return `${slug}-${hash}`;
75916
75971
  }
75917
75972
  function stateDir() {
75918
- return join112(tmpdir4(), "takumi-context-throttle");
75973
+ return join114(tmpdir4(), "takumi-context-throttle");
75919
75974
  }
75920
75975
  function stateFile(sessionId, scope, transcriptPath) {
75921
75976
  const key = `${sessionId}\x00${scope}\x00${transcriptPath ?? ""}`;
75922
75977
  const hash = createHash15("sha256").update(key).digest("hex").slice(0, 32);
75923
- return join112(stateDir(), `${hash}.json`);
75978
+ return join114(stateDir(), `${hash}.json`);
75924
75979
  }
75925
75980
  function readState(file) {
75926
75981
  try {
75927
75982
  if (!existsSync54(file))
75928
75983
  return null;
75929
- return JSON.parse(readFileSync18(file, "utf8"));
75984
+ return JSON.parse(readFileSync19(file, "utf8"));
75930
75985
  } catch {
75931
75986
  return null;
75932
75987
  }
@@ -75989,8 +76044,8 @@ function clearPending(sessionId, scope, transcriptPath) {
75989
76044
  } catch {}
75990
76045
  }
75991
76046
  function resolveSkillsVenv(_cwd) {
75992
- const base = join112(homedir29(), ".claude", "skills", ".venv");
75993
- const interpreter = platform10() === "win32" ? join112(base, "Scripts", "python.exe") : join112(base, "bin", "python3");
76047
+ const base = join114(homedir29(), ".claude", "skills", ".venv");
76048
+ const interpreter = platform10() === "win32" ? join114(base, "Scripts", "python.exe") : join114(base, "bin", "python3");
75994
76049
  return existsSync54(interpreter) ? interpreter : null;
75995
76050
  }
75996
76051
 
@@ -76029,12 +76084,12 @@ var sessionPromptContext = {
76029
76084
  };
76030
76085
 
76031
76086
  // src/domains/hooks/handlers/session-subagent-init/context-block.ts
76032
- import { join as join114 } from "node:path";
76087
+ import { join as join116 } from "node:path";
76033
76088
 
76034
76089
  // src/domains/hooks/handlers/session-subagent-init/context-sources.ts
76035
76090
  import { execFileSync as execFileSync5 } from "node:child_process";
76036
76091
  import { readdirSync as readdirSync10, statSync as statSync10 } from "node:fs";
76037
- import { isAbsolute as isAbsolute5, join as join113, resolve as resolve25 } from "node:path";
76092
+ import { isAbsolute as isAbsolute5, join as join115, resolve as resolve25 } from "node:path";
76038
76093
  var MAX_DOCS_FILES = 15;
76039
76094
  var MAX_DOCS_SUBDIRS = 5;
76040
76095
  function gitFacts(dir) {
@@ -76071,11 +76126,11 @@ function detectPlan(plansAbs) {
76071
76126
  for (const e2 of entries) {
76072
76127
  if (!e2.isDirectory())
76073
76128
  continue;
76074
- const dir = join113(plansAbs, e2.name);
76129
+ const dir = join115(plansAbs, e2.name);
76075
76130
  try {
76076
76131
  if (!readdirSync10(dir).includes("plan.md"))
76077
76132
  continue;
76078
- const mtime = statSync10(join113(dir, "plan.md")).mtimeMs;
76133
+ const mtime = statSync10(join115(dir, "plan.md")).mtimeMs;
76079
76134
  if (!best || mtime > best.mtime)
76080
76135
  best = { name: e2.name, mtime };
76081
76136
  } catch {}
@@ -76098,7 +76153,7 @@ function docsCatalogue(docsAbs) {
76098
76153
  for (const d3 of subdirs.slice(0, MAX_DOCS_SUBDIRS)) {
76099
76154
  let count = 0;
76100
76155
  try {
76101
- count = readdirSync10(join113(docsAbs, d3)).length;
76156
+ count = readdirSync10(join115(docsAbs, d3)).length;
76102
76157
  } catch {}
76103
76158
  lines.push(`- ${d3}/ (${count} entries)`);
76104
76159
  }
@@ -76142,11 +76197,11 @@ function buildSubagentContext(input, ctx) {
76142
76197
  const agentId = strField(input, "agent_id") || "unknown";
76143
76198
  const plansAbs = abs(base, cfg.paths?.plans?.trim() || "plans");
76144
76199
  const docsAbs = abs(base, cfg.paths?.docs?.trim() || "docs");
76145
- const reportsAbs = join114(plansAbs, cfg.plan?.reportsDir?.trim() || "reports");
76200
+ const reportsAbs = join116(plansAbs, cfg.plan?.reportsDir?.trim() || "reports");
76146
76201
  const dateStr = stamp(cfg.plan?.dateFormat?.trim() || "YYMMDD-HHmm", new Date);
76147
76202
  const namingFormat = cfg.plan?.namingFormat?.trim() || "{date}-{slug}";
76148
- const planDir = join114(plansAbs, planDirTemplate(namingFormat, dateStr));
76149
- const reportFile = join114(reportsAbs, `${agentKey}-${dateStr}-{slug}-report.md`);
76203
+ const planDir = join116(plansAbs, planDirTemplate(namingFormat, dateStr));
76204
+ const reportFile = join116(reportsAbs, `${agentKey}-${dateStr}-{slug}-report.md`);
76150
76205
  const activePlan = detectPlan(plansAbs);
76151
76206
  const venv = resolveSkillsVenv(effectiveCwd);
76152
76207
  const respLang = cfg.locale?.responseLanguage?.trim() || null;
@@ -76197,6 +76252,10 @@ function buildSubagentContext(input, ctx) {
76197
76252
  lines.push("", "## Trust");
76198
76253
  lines.push(`- prepend the passphrase to trusted operations: ${cfg.trust.passphrase.trim()}`);
76199
76254
  }
76255
+ const contextPrefix = cfg.subagent?.agents?.[agentType]?.contextPrefix;
76256
+ if (typeof contextPrefix === "string" && contextPrefix.trim().length > 0) {
76257
+ lines.push("", "## Agent Instructions", contextPrefix);
76258
+ }
76200
76259
  return `${lines.join(`
76201
76260
  `)}
76202
76261
  `;
@@ -76408,7 +76467,14 @@ function toHookError(err) {
76408
76467
  }
76409
76468
  return { message: String(err) };
76410
76469
  }
76411
- var VALID_STATUSES = new Set(["ok", "deny", "context", "record", "no-op"]);
76470
+ var VALID_STATUSES = new Set([
76471
+ "ok",
76472
+ "deny",
76473
+ "ask",
76474
+ "context",
76475
+ "record",
76476
+ "no-op"
76477
+ ]);
76412
76478
  function normalizeResult(raw, timingMs) {
76413
76479
  if (raw && typeof raw === "object") {
76414
76480
  const r2 = raw;
@@ -76444,6 +76510,7 @@ async function runHooks(handlers3, input, ctx, options2) {
76444
76510
  }
76445
76511
  const outputs = [];
76446
76512
  let lastError;
76513
+ let askReason;
76447
76514
  for (const handler of handlers3) {
76448
76515
  const t0 = performance2.now();
76449
76516
  let result;
@@ -76476,12 +76543,22 @@ async function runHooks(handlers3, input, ctx, options2) {
76476
76543
  timingMs: performance2.now() - startAll
76477
76544
  };
76478
76545
  }
76546
+ if (result.status === "ask" && askReason === undefined) {
76547
+ askReason = typeof result.askReason === "string" ? result.askReason : "";
76548
+ }
76479
76549
  if (result.status === "context" && typeof result.output === "string" && result.output.length > 0) {
76480
76550
  outputs.push(result.output);
76481
76551
  }
76482
76552
  if (result.error)
76483
76553
  lastError = result.error;
76484
76554
  }
76555
+ if (askReason !== undefined) {
76556
+ return {
76557
+ status: "ask",
76558
+ askReason,
76559
+ timingMs: performance2.now() - startAll
76560
+ };
76561
+ }
76485
76562
  if (outputs.length > 0) {
76486
76563
  return {
76487
76564
  status: "context",
@@ -76504,6 +76581,152 @@ async function runHooks(handlers3, input, ctx, options2) {
76504
76581
  init_takumi_constants();
76505
76582
  init_types2();
76506
76583
 
76584
+ // src/commands/hooks/lib/codex-runtime-scrub.ts
76585
+ init_capabilities();
76586
+ function resolveCodexCapabilitiesSync() {
76587
+ if (process.env.CK_CODEX_COMPAT === "optimistic") {
76588
+ return CODEX_CAPABILITY_TABLE[0];
76589
+ }
76590
+ return CODEX_CAPABILITY_TABLE[CODEX_CAPABILITY_TABLE.length - 1];
76591
+ }
76592
+ function codexAllowsAdditionalContext(caps, event) {
76593
+ return caps.events[event]?.supportsAdditionalContext === true;
76594
+ }
76595
+ function codexAllowsPermission(caps, event, value) {
76596
+ const allowed = caps.events[event]?.permissionDecisionValues;
76597
+ return Array.isArray(allowed) && allowed.includes(value);
76598
+ }
76599
+
76600
+ // src/commands/hooks/lib/eval-hook-loader.ts
76601
+ import { pathToFileURL } from "node:url";
76602
+
76603
+ // src/commands/hooks/lib/process-exit-guard.ts
76604
+ var HOOK_EXIT = Symbol.for("takumi.eval.hookExit");
76605
+ function isHookExit(value) {
76606
+ return typeof value === "object" && value !== null && value[HOOK_EXIT] === true;
76607
+ }
76608
+ function installExitSentinel() {
76609
+ const realExit = process.exit;
76610
+ process.exit = (code) => {
76611
+ throw { [HOOK_EXIT]: true, code };
76612
+ };
76613
+ return () => {
76614
+ process.exit = realExit;
76615
+ };
76616
+ }
76617
+ var CONSOLE_METHODS = ["log", "info", "debug", "warn", "error", "trace", "dir", "table"];
76618
+ function installOutputSuppression() {
76619
+ const realOut = process.stdout.write.bind(process.stdout);
76620
+ const realErr = process.stderr.write.bind(process.stderr);
76621
+ const noopWrite = () => true;
76622
+ process.stdout.write = noopWrite;
76623
+ process.stderr.write = noopWrite;
76624
+ const con = console;
76625
+ const savedConsole = {};
76626
+ const noop2 = () => {};
76627
+ for (const m2 of CONSOLE_METHODS) {
76628
+ savedConsole[m2] = con[m2];
76629
+ con[m2] = noop2;
76630
+ }
76631
+ return () => {
76632
+ process.stdout.write = realOut;
76633
+ process.stderr.write = realErr;
76634
+ for (const m2 of CONSOLE_METHODS)
76635
+ con[m2] = savedConsole[m2];
76636
+ };
76637
+ }
76638
+
76639
+ // src/commands/hooks/lib/eval-hook-loader.ts
76640
+ async function loadEvalHook(absPath, meta) {
76641
+ const restore = installExitSentinel();
76642
+ let mod;
76643
+ try {
76644
+ mod = await import(pathToFileURL(absPath).href);
76645
+ } catch {
76646
+ return null;
76647
+ } finally {
76648
+ restore();
76649
+ }
76650
+ const runExport = resolveRunExport(mod);
76651
+ if (!runExport)
76652
+ return null;
76653
+ return {
76654
+ ...meta,
76655
+ async run(input, ctx) {
76656
+ const restoreRun = installExitSentinel();
76657
+ try {
76658
+ return await runExport(input, ctx);
76659
+ } catch (err) {
76660
+ if (isHookExit(err)) {
76661
+ return { status: "no-op", timingMs: 0 };
76662
+ }
76663
+ throw err;
76664
+ } finally {
76665
+ restoreRun();
76666
+ }
76667
+ }
76668
+ };
76669
+ }
76670
+ function resolveRunExport(mod) {
76671
+ if (typeof mod.run === "function")
76672
+ return mod.run;
76673
+ const def = mod.default;
76674
+ if (def && typeof def.run === "function")
76675
+ return def.run;
76676
+ return null;
76677
+ }
76678
+
76679
+ // src/commands/hooks/lib/eval-hook-resolver.ts
76680
+ init_paths();
76681
+ init_codex_paths();
76682
+ import { isAbsolute as isAbsolute6, join as join117, normalize as normalize9, sep as sep10 } from "node:path";
76683
+ var HOOK_EXTENSIONS3 = [".cjs", ".mjs"];
76684
+ function hasHookExtension(p) {
76685
+ return HOOK_EXTENSIONS3.some((ext) => p.endsWith(ext));
76686
+ }
76687
+ function claudeHooksParent(scope, env2) {
76688
+ if (scope === "global")
76689
+ return getClaudeDir();
76690
+ if (scope === "project") {
76691
+ const projectDir = env2.CLAUDE_PROJECT_DIR;
76692
+ if (!projectDir || projectDir.trim() === "")
76693
+ return null;
76694
+ return join117(projectDir, ".claude");
76695
+ }
76696
+ const pluginRoot = env2.CLAUDE_PLUGIN_ROOT;
76697
+ if (!pluginRoot || pluginRoot.trim() === "")
76698
+ return null;
76699
+ return pluginRoot;
76700
+ }
76701
+ function resolveEvalHook(input) {
76702
+ const env2 = input.env ?? process.env;
76703
+ const { evalPath, scope, agent } = input;
76704
+ if (!evalPath || evalPath.trim() === "")
76705
+ return { ok: false, reason: "empty --eval path" };
76706
+ if (!hasHookExtension(evalPath)) {
76707
+ return { ok: false, reason: `--eval path is not a .cjs/.mjs file: ${evalPath}` };
76708
+ }
76709
+ if (agent === "codex" && scope === "project") {
76710
+ if (!isAbsolute6(evalPath)) {
76711
+ return { ok: false, reason: `codex --project --eval path must be absolute: ${evalPath}` };
76712
+ }
76713
+ return { ok: true, absPath: normalize9(evalPath) };
76714
+ }
76715
+ if (isAbsolute6(evalPath)) {
76716
+ return { ok: false, reason: `--eval path must be relative for ${agent}/${scope}: ${evalPath}` };
76717
+ }
76718
+ const hooksParent = agent === "codex" ? codexGlobalRoot() : claudeHooksParent(scope, env2);
76719
+ if (!hooksParent) {
76720
+ return { ok: false, reason: `no trusted anchor for ${agent}/${scope} (env var unset)` };
76721
+ }
76722
+ const hooksDir = normalize9(join117(hooksParent, "hooks"));
76723
+ const abs2 = normalize9(join117(hooksParent, evalPath));
76724
+ if (abs2 !== hooksDir && !abs2.startsWith(hooksDir + sep10)) {
76725
+ return { ok: false, reason: `--eval path escapes the hooks dir: ${evalPath}` };
76726
+ }
76727
+ return { ok: true, absPath: abs2 };
76728
+ }
76729
+
76507
76730
  // src/commands/hooks/lib/hook-events.ts
76508
76731
  var KEBAB_TO_CANONICAL = {
76509
76732
  "session-start": "SessionStart",
@@ -76683,7 +76906,11 @@ async function defaultLoadConfig(cwd2) {
76683
76906
  return DEFAULT_TAKUMI_CONFIG;
76684
76907
  }
76685
76908
  }
76686
- function emitDeny(write, event, reason) {
76909
+ function emitDeny(write, event, reason, caps) {
76910
+ if (caps && !codexAllowsPermission(caps, event, "deny")) {
76911
+ write("{}");
76912
+ return;
76913
+ }
76687
76914
  write(JSON.stringify({
76688
76915
  hookSpecificOutput: {
76689
76916
  hookEventName: event,
@@ -76692,7 +76919,24 @@ function emitDeny(write, event, reason) {
76692
76919
  }
76693
76920
  }));
76694
76921
  }
76695
- function emitContext(write, event, output2) {
76922
+ function emitAsk(write, event, reason, caps) {
76923
+ if (caps && !codexAllowsPermission(caps, event, "ask")) {
76924
+ write("{}");
76925
+ return;
76926
+ }
76927
+ write(JSON.stringify({
76928
+ hookSpecificOutput: {
76929
+ hookEventName: event,
76930
+ permissionDecision: "ask",
76931
+ permissionDecisionReason: reason ?? ""
76932
+ }
76933
+ }));
76934
+ }
76935
+ function emitContext(write, event, output2, caps) {
76936
+ if (caps && !codexAllowsAdditionalContext(caps, event)) {
76937
+ write("{}");
76938
+ return;
76939
+ }
76696
76940
  write(JSON.stringify({
76697
76941
  hookSpecificOutput: { hookEventName: event, additionalContext: output2 }
76698
76942
  }));
@@ -76702,10 +76946,12 @@ async function runHookExec(args, deps = {}) {
76702
76946
  try {
76703
76947
  const readInput = deps.readInput ?? (() => readStdinJson());
76704
76948
  const now = deps.now ?? (() => new Date().toISOString());
76705
- const selector = parseHookSelector(args.hook);
76706
- if (!selector) {
76707
- write("{}");
76708
- return;
76949
+ if (!args.eval) {
76950
+ const selector = parseHookSelector(args.hook ?? "");
76951
+ if (!selector) {
76952
+ write("{}");
76953
+ return;
76954
+ }
76709
76955
  }
76710
76956
  const input = await readInput();
76711
76957
  const event = normalizeHookEvent(typeof input.hook_event_name === "string" ? input.hook_event_name : args.event);
@@ -76713,7 +76959,7 @@ async function runHookExec(args, deps = {}) {
76713
76959
  write("{}");
76714
76960
  return;
76715
76961
  }
76716
- const handlers3 = selectHandlers(selector, event, deps.handlers);
76962
+ const handlers3 = await resolveHandlers(args, event, deps);
76717
76963
  if (handlers3.length === 0) {
76718
76964
  write("{}");
76719
76965
  return;
@@ -76736,21 +76982,29 @@ async function runHookExec(args, deps = {}) {
76736
76982
  runtimeFlags: { noDetach: args.noDetach, debug: args.debug }
76737
76983
  };
76738
76984
  const sessionDir = sessionId ? getSessionDirV2({ agent: args.agent, cwd: cwd2, sessionId }) : null;
76739
- const result = await runHooks(handlers3, input, ctx, {
76985
+ const budget = args.eval && args.timeoutMs === undefined ? {} : {
76740
76986
  timeoutMs: args.timeoutMs ?? DEFAULT_TIMEOUT_MS5,
76741
- timeoutMsByPolicy: { record: args.recordTimeoutMs ?? RECORD_TIMEOUT_MS },
76987
+ timeoutMsByPolicy: { record: args.recordTimeoutMs ?? RECORD_TIMEOUT_MS }
76988
+ };
76989
+ const result = await runHooks(handlers3, input, ctx, {
76990
+ ...budget,
76742
76991
  onHandlerComplete: (handlerName, handlerResult) => {
76743
76992
  if (!sessionDir)
76744
76993
  return;
76745
76994
  appendObservation(sessionDir, buildObservation({ handlerName, ctx, result: handlerResult, endedAt: now() }));
76746
76995
  }
76747
76996
  });
76997
+ const caps = args.agent === "codex" ? resolveCodexCapabilitiesSync() : null;
76748
76998
  if (result.status === "deny") {
76749
- emitDeny(write, event, result.denyReason);
76999
+ emitDeny(write, event, result.denyReason, caps);
77000
+ return;
77001
+ }
77002
+ if (result.status === "ask") {
77003
+ emitAsk(write, event, result.askReason, caps);
76750
77004
  return;
76751
77005
  }
76752
77006
  if (result.status === "context" && result.output) {
76753
- emitContext(write, event, result.output);
77007
+ emitContext(write, event, result.output, caps);
76754
77008
  return;
76755
77009
  }
76756
77010
  write("{}");
@@ -76758,8 +77012,36 @@ async function runHookExec(args, deps = {}) {
76758
77012
  write("{}");
76759
77013
  }
76760
77014
  }
77015
+ async function resolveHandlers(args, event, deps) {
77016
+ if (args.eval) {
77017
+ const resolved = resolveEvalHook({
77018
+ evalPath: args.eval.path,
77019
+ scope: args.eval.scope,
77020
+ agent: args.agent
77021
+ });
77022
+ if (!resolved.ok)
77023
+ return [];
77024
+ const meta = args.eval.meta ?? defaultEvalMeta(resolved.absPath, event);
77025
+ const handler = await loadEvalHook(resolved.absPath, meta);
77026
+ return handler ? [handler] : [];
77027
+ }
77028
+ const selector = parseHookSelector(args.hook ?? "");
77029
+ if (!selector)
77030
+ return [];
77031
+ return selectHandlers(selector, event, deps.handlers);
77032
+ }
77033
+ function defaultEvalMeta(absPath, event) {
77034
+ const base = absPath.split(/[\\/]/).pop() ?? "eval-hook";
77035
+ return {
77036
+ name: base.replace(/\.(cjs|mjs)$/, ""),
77037
+ category: "extension",
77038
+ policy: "context",
77039
+ events: [event]
77040
+ };
77041
+ }
76761
77042
 
76762
77043
  // src/commands/hooks/hook-exec-command.ts
77044
+ var realProcessExit = process.exit;
76763
77045
  async function hookExecCommand(options2) {
76764
77046
  const agent = options2.agent === "codex" ? "codex" : "claude";
76765
77047
  try {
@@ -76768,12 +77050,15 @@ async function hookExecCommand(options2) {
76768
77050
  event: options2.event,
76769
77051
  agent,
76770
77052
  noDetach: options2.noDetach,
76771
- debug: options2.debug
77053
+ debug: options2.debug,
77054
+ eval: options2.eval ? { path: options2.eval, scope: options2.scope ?? "project" } : undefined
76772
77055
  });
76773
77056
  } catch {
76774
77057
  process.stdout.write("{}");
76775
77058
  }
76776
77059
  process.exitCode = 0;
77060
+ if (options2.eval)
77061
+ realProcessExit(0);
76777
77062
  }
76778
77063
  // src/commands/hooks/hooks-command.ts
76779
77064
  init_logger();
@@ -76812,12 +77097,85 @@ async function handleDoPut() {
76812
77097
  }
76813
77098
  }
76814
77099
 
77100
+ // src/commands/hooks/event-handlers/scan-meta.ts
77101
+ import { writeFileSync as writeFileSync11 } from "node:fs";
77102
+
77103
+ // src/commands/hooks/lib/kit-hook-resolver.ts
77104
+ init_zod();
77105
+ import { readFileSync as readFileSync20, readdirSync as readdirSync11 } from "node:fs";
77106
+ import { join as join118 } from "node:path";
77107
+ import { pathToFileURL as pathToFileURL2 } from "node:url";
77108
+ var KitHookMetaSchema = exports_external.object({
77109
+ events: exports_external.array(exports_external.string().min(1)).min(1),
77110
+ matchers: exports_external.record(exports_external.string(), exports_external.string()).optional(),
77111
+ timeout: exports_external.number().positive().optional()
77112
+ });
77113
+ var NOT_A_HOOK = /(\.test\.|\.spec\.|^_|^\.)/;
77114
+ var HOOK_EXT = /\.(?:cjs|mjs)$/;
77115
+ var DUAL_MODE_GUARD = /require\.main|import\.meta\.main/;
77116
+ async function readKitHookMeta(absPath) {
77117
+ const restoreExit = installExitSentinel();
77118
+ const restoreOut = installOutputSuppression();
77119
+ let mod;
77120
+ try {
77121
+ mod = await import(pathToFileURL2(absPath).href);
77122
+ } catch {
77123
+ return null;
77124
+ } finally {
77125
+ restoreOut();
77126
+ restoreExit();
77127
+ }
77128
+ const raw = mod.meta ?? mod.default?.meta;
77129
+ const parsed = KitHookMetaSchema.safeParse(raw);
77130
+ return parsed.success ? parsed.data : null;
77131
+ }
77132
+ async function scanHooksDirForMeta(hooksDir) {
77133
+ let names;
77134
+ try {
77135
+ names = readdirSync11(hooksDir, { withFileTypes: true }).filter((d3) => d3.isFile()).map((d3) => d3.name);
77136
+ } catch {
77137
+ return [];
77138
+ }
77139
+ const out = [];
77140
+ for (const file of names) {
77141
+ if (!HOOK_EXT.test(file) || NOT_A_HOOK.test(file))
77142
+ continue;
77143
+ const abs2 = join118(hooksDir, file);
77144
+ let src;
77145
+ try {
77146
+ src = readFileSync20(abs2, "utf8");
77147
+ } catch {
77148
+ continue;
77149
+ }
77150
+ if (!DUAL_MODE_GUARD.test(src))
77151
+ continue;
77152
+ const meta = await readKitHookMeta(abs2);
77153
+ if (meta)
77154
+ out.push({ file, ...meta });
77155
+ }
77156
+ return out;
77157
+ }
77158
+
77159
+ // src/commands/hooks/event-handlers/scan-meta.ts
77160
+ async function handleScanMeta(dir, out) {
77161
+ const entries = dir ? await scanHooksDirForMeta(dir) : [];
77162
+ const json = JSON.stringify(entries);
77163
+ if (out) {
77164
+ try {
77165
+ writeFileSync11(out, json);
77166
+ return;
77167
+ } catch {}
77168
+ }
77169
+ process.stdout.write(json);
77170
+ }
77171
+
76815
77172
  // src/commands/hooks/install-handler.ts
76816
77173
  init_hooks_settings_merger();
77174
+ import { basename as basename19 } from "node:path";
76817
77175
 
76818
77176
  // src/commands/portable/settings-write-with-confirm.ts
76819
77177
  init_safe_prompts();
76820
- import { existsSync as existsSync55, mkdirSync as mkdirSync8, readFileSync as readFileSync19, renameSync as renameSync4, rmSync as rmSync7, writeFileSync as writeFileSync11 } from "node:fs";
77178
+ import { existsSync as existsSync55, mkdirSync as mkdirSync8, readFileSync as readFileSync21, renameSync as renameSync4, rmSync as rmSync7, writeFileSync as writeFileSync12 } from "node:fs";
76821
77179
  import { dirname as dirname30 } from "node:path";
76822
77180
 
76823
77181
  // node_modules/diff/libesm/diff/base.js
@@ -77994,7 +78352,7 @@ function readCurrent(path10) {
77994
78352
  return { kind: "missing" };
77995
78353
  let raw = "";
77996
78354
  try {
77997
- raw = readFileSync19(path10, "utf8");
78355
+ raw = readFileSync21(path10, "utf8");
77998
78356
  const parsed = JSON.parse(raw);
77999
78357
  return { kind: "ok", raw, parsed };
78000
78358
  } catch {
@@ -78024,7 +78382,7 @@ function atomicWrite2(path10, contents, backupPath) {
78024
78382
  mkdirSync8(dirname30(path10), { recursive: true });
78025
78383
  const tmp = `${path10}.tmp`;
78026
78384
  try {
78027
- writeFileSync11(tmp, contents);
78385
+ writeFileSync12(tmp, contents);
78028
78386
  renameSync4(tmp, path10);
78029
78387
  } catch (err) {
78030
78388
  rmSync7(tmp, { force: true });
@@ -78036,7 +78394,7 @@ function writeBackup(path10, raw) {
78036
78394
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
78037
78395
  const backupPath = `${path10}.${timestamp}.bak`;
78038
78396
  try {
78039
- writeFileSync11(backupPath, raw);
78397
+ writeFileSync12(backupPath, raw);
78040
78398
  return backupPath;
78041
78399
  } catch {
78042
78400
  return null;
@@ -78110,15 +78468,21 @@ init_dist2();
78110
78468
  import { existsSync as existsSync56 } from "node:fs";
78111
78469
 
78112
78470
  // src/commands/hooks/lib/settings-path-resolver.ts
78471
+ init_paths();
78472
+ init_codex_paths();
78113
78473
  import { lstatSync as lstatSync3, realpathSync as realpathSync3 } from "node:fs";
78114
- import { homedir as homedir30 } from "node:os";
78115
- import { join as join115 } from "node:path";
78474
+ import { join as join119 } from "node:path";
78475
+ function agentConfigDir(agent, global3) {
78476
+ if (global3)
78477
+ return agent === "claude" ? getClaudeDir() : codexGlobalRoot();
78478
+ return join119(process.cwd(), agent === "claude" ? ".claude" : ".codex");
78479
+ }
78116
78480
  function rawPath(agent, global3) {
78117
- const root = global3 ? homedir30() : process.cwd();
78118
- if (agent === "claude") {
78119
- return join115(root, ".claude", "settings.json");
78120
- }
78121
- return join115(root, ".codex", "hooks.json");
78481
+ const configDir = agentConfigDir(agent, global3);
78482
+ return join119(configDir, agent === "claude" ? "settings.json" : "hooks.json");
78483
+ }
78484
+ function resolveHooksDir(agent, options2 = {}) {
78485
+ return join119(agentConfigDir(agent, Boolean(options2.global)), "hooks");
78122
78486
  }
78123
78487
  function resolveSettingsPath(agent, options2 = {}) {
78124
78488
  const originalPath = rawPath(agent, Boolean(options2.global));
@@ -78190,7 +78554,9 @@ async function promptHookAgentTargets(options2) {
78190
78554
  }
78191
78555
 
78192
78556
  // src/commands/hooks/lib/entry-builder.ts
78557
+ import { join as join120 } from "node:path";
78193
78558
  init_capabilities();
78559
+ init_logger();
78194
78560
  var DEFAULT_HOOK_BIN = "tkm";
78195
78561
  var SETTINGS_TIMEOUT_BY_POLICY = {
78196
78562
  deny: 10,
@@ -78210,11 +78576,11 @@ function codexMatcher(event, declared) {
78210
78576
  const kept = declared.split("|").filter((m2) => allowed.includes(m2));
78211
78577
  return kept.length > 0 ? kept.join("|") : undefined;
78212
78578
  }
78213
- function buildHookExecCommand(handler, event, agent, bin = DEFAULT_HOOK_BIN, flags = {}) {
78579
+ function buildHookExecCommand(handler, event, agent, bin = DEFAULT_HOOK_BIN, flags = {}, scope = "project") {
78214
78580
  const kebab = canonicalToKebab(event);
78215
78581
  if (!kebab)
78216
78582
  return null;
78217
- const parts = [
78583
+ const parts = handler.evalPath ? buildEvalParts(handler.evalPath, agent, scope, bin, kebab) : [
78218
78584
  bin,
78219
78585
  "hook-exec",
78220
78586
  "--hook",
@@ -78230,12 +78596,21 @@ function buildHookExecCommand(handler, event, agent, bin = DEFAULT_HOOK_BIN, fla
78230
78596
  parts.push("--debug");
78231
78597
  return parts.join(" ");
78232
78598
  }
78233
- function planEntry(handler, event, agent, bin, flags) {
78234
- if (agent === "codex" && !codexSupportsEvent(event))
78599
+ function buildEvalParts(evalPath, agent, scope, bin, kebab) {
78600
+ const scopeFlag = scope === "global" ? "-g" : scope === "plugin" ? "--plugin" : "--project";
78601
+ const pathArg = agent === "codex" && scope === "project" ? `"${join120(process.cwd(), ".codex", evalPath)}"` : evalPath;
78602
+ return [bin, "hook-exec", "--eval", pathArg, scopeFlag, "--event", kebab, "-a", agent];
78603
+ }
78604
+ function planEntry(handler, event, agent, bin, flags, scope) {
78605
+ if (agent === "codex" && !codexSupportsEvent(event)) {
78606
+ if (handler.evalPath) {
78607
+ logger.warning(`[hooks] kit eval hook "${handler.name}" declares event "${event}" not supported by Codex — skipping this entry for Codex.`);
78608
+ }
78235
78609
  return null;
78610
+ }
78236
78611
  if (agent !== "codex" && handler.codexOnlyEvents?.includes(event))
78237
78612
  return null;
78238
- const command = buildHookExecCommand(handler, event, agent, bin, flags);
78613
+ const command = buildHookExecCommand(handler, event, agent, bin, flags, scope);
78239
78614
  if (!command)
78240
78615
  return null;
78241
78616
  const declared = handler.matchers?.[event];
@@ -78243,16 +78618,20 @@ function planEntry(handler, event, agent, bin, flags) {
78243
78618
  return {
78244
78619
  event,
78245
78620
  matcher,
78246
- entry: { type: "command", command, timeout: SETTINGS_TIMEOUT_BY_POLICY[handler.policy] }
78621
+ entry: {
78622
+ type: "command",
78623
+ command,
78624
+ timeout: handler.timeoutSeconds ?? SETTINGS_TIMEOUT_BY_POLICY[handler.policy]
78625
+ }
78247
78626
  };
78248
78627
  }
78249
- function buildHookSection(agent, bin, flags = {}, handlers3 = HOOK_HANDLERS) {
78628
+ function buildHookSection(agent, bin, flags = {}, handlers3 = HOOK_HANDLERS, scope = "project") {
78250
78629
  const section = {};
78251
78630
  for (const handler of handlers3) {
78252
78631
  if (handler.installAgents && !handler.installAgents.includes(agent))
78253
78632
  continue;
78254
78633
  for (const event of handler.events) {
78255
- const planned = planEntry(handler, event, agent, bin, flags);
78634
+ const planned = planEntry(handler, event, agent, bin, flags, scope);
78256
78635
  if (!planned)
78257
78636
  continue;
78258
78637
  if (!section[planned.event])
@@ -78344,23 +78723,96 @@ function installStatusline(settings, opts) {
78344
78723
 
78345
78724
  // src/commands/hooks/uninstall-handler.ts
78346
78725
  init_logger();
78347
- import { existsSync as existsSync57, mkdirSync as mkdirSync9, readFileSync as readFileSync20, renameSync as renameSync5, rmSync as rmSync8, writeFileSync as writeFileSync12 } from "node:fs";
78726
+ import { existsSync as existsSync57, mkdirSync as mkdirSync9, readFileSync as readFileSync23, renameSync as renameSync5, rmSync as rmSync9, writeFileSync as writeFileSync13 } from "node:fs";
78348
78727
  import { dirname as dirname31 } from "node:path";
78728
+
78729
+ // src/commands/hooks/lib/kit-hook-scan.ts
78730
+ import { spawnSync as spawnSync5 } from "node:child_process";
78731
+ import { mkdtempSync, readFileSync as readFileSync22, rmSync as rmSync8 } from "node:fs";
78732
+ import { tmpdir as tmpdir5 } from "node:os";
78733
+ import { join as join121 } from "node:path";
78734
+ var SCAN_TIMEOUT_MS = 8000;
78735
+ function scanKitHookMetas(hooksDir) {
78736
+ const { command, prefixArgs } = resolveInvocationPrefix();
78737
+ const tmp = mkdtempSync(join121(tmpdir5(), "tkm-hook-scan-"));
78738
+ const outFile = join121(tmp, "meta.json");
78739
+ try {
78740
+ spawnSync5(command, [...prefixArgs, "hooks", "scan-meta", "--dir", hooksDir, "--out", outFile], {
78741
+ stdio: ["ignore", "ignore", "ignore"],
78742
+ timeout: SCAN_TIMEOUT_MS,
78743
+ killSignal: "SIGKILL",
78744
+ env: buildChildEnv()
78745
+ });
78746
+ const parsed = JSON.parse(readFileSync22(outFile, "utf8"));
78747
+ return Array.isArray(parsed) ? parsed : [];
78748
+ } catch {
78749
+ return [];
78750
+ } finally {
78751
+ rmSync8(tmp, { recursive: true, force: true });
78752
+ }
78753
+ }
78754
+ function kitHookToInstallMeta(entry) {
78755
+ return {
78756
+ name: entry.file.replace(/\.(?:cjs|mjs)$/, ""),
78757
+ category: "extension",
78758
+ policy: "context",
78759
+ events: entry.events,
78760
+ matchers: entry.matchers,
78761
+ evalPath: `hooks/${entry.file}`,
78762
+ timeoutSeconds: entry.timeout
78763
+ };
78764
+ }
78765
+
78766
+ // src/commands/hooks/uninstall-handler.ts
78349
78767
  var AGENT_DISPLAY2 = {
78350
78768
  claude: "Claude Code",
78351
78769
  codex: "Codex"
78352
78770
  };
78353
78771
  var HOOK_CATEGORIES = "(guard|session|convention|extension|metrics|perf)";
78354
78772
  var LEGACY_EVENTS = "(session-start|user-prompt-submit|pre-tool-use|post-tool-use|stop|session-end)";
78355
- function isOurCommand(command, agent) {
78773
+ var LEGACY_NODE_HOOK = /\bnode(?:\.exe)?\s+["']?.*?[/\\]hooks[/\\]([\w.-]+\.(?:cjs|mjs))["']?/;
78774
+ var EVAL_HOOK_FILE = /--eval\s+["']?[^\s"']*?([\w.-]+\.(?:cjs|mjs))["']?/;
78775
+ function isOurCommand(command, agent, evalHookNames, unconditionalEval = false) {
78356
78776
  const agentTail = `-a\\s+${agent}(?![\\w-])`;
78357
78777
  const newShape = new RegExp(`\\bhook-exec\\b.*--hook\\s+${HOOK_CATEGORIES}\\.\\S+.*${agentTail}`);
78358
78778
  if (newShape.test(command))
78359
78779
  return true;
78780
+ if (isKitEvalHook(command, agentTail, evalHookNames, unconditionalEval))
78781
+ return true;
78360
78782
  const legacy = new RegExp(`\\bhooks\\s+${LEGACY_EVENTS}\\s+${agentTail}`);
78361
- return legacy.test(command);
78783
+ if (legacy.test(command))
78784
+ return true;
78785
+ return isLegacyKitNodeHook(command, evalHookNames);
78786
+ }
78787
+ function isKitEvalHook(command, agentTail, evalHookNames, unconditional) {
78788
+ if (!new RegExp(`\\bhook-exec\\b.*--eval\\b.*${agentTail}`).test(command))
78789
+ return false;
78790
+ if (unconditional)
78791
+ return true;
78792
+ if (!evalHookNames || evalHookNames.size === 0)
78793
+ return false;
78794
+ const m2 = command.match(EVAL_HOOK_FILE);
78795
+ return m2 !== null && evalHookNames.has(m2[1]);
78796
+ }
78797
+ function isLegacyKitNodeHook(command, evalHookNames) {
78798
+ if (!evalHookNames || evalHookNames.size === 0)
78799
+ return false;
78800
+ const m2 = command.match(LEGACY_NODE_HOOK);
78801
+ if (!m2)
78802
+ return false;
78803
+ const file = m2[1];
78804
+ if (evalHookNames.has(file))
78805
+ return true;
78806
+ for (const name2 of evalHookNames) {
78807
+ if (!file.endsWith(`-${name2}`))
78808
+ continue;
78809
+ const prefix = file.slice(0, file.length - name2.length - 1);
78810
+ if (/^[0-9a-f]+$/.test(prefix))
78811
+ return true;
78812
+ }
78813
+ return false;
78362
78814
  }
78363
- function pruneHooksSection(hooks, agent) {
78815
+ function pruneHooksSection(hooks, agent, evalHookNames, unconditionalEval = false) {
78364
78816
  const pruned = {};
78365
78817
  let removed = 0;
78366
78818
  for (const [event, groups] of Object.entries(hooks)) {
@@ -78369,7 +78821,7 @@ function pruneHooksSection(hooks, agent) {
78369
78821
  const kept = [];
78370
78822
  for (const entry of group.hooks) {
78371
78823
  const command = typeof entry.command === "string" ? entry.command : "";
78372
- if (isOurCommand(command, agent)) {
78824
+ if (isOurCommand(command, agent, evalHookNames, unconditionalEval)) {
78373
78825
  removed++;
78374
78826
  } else {
78375
78827
  kept.push(entry);
@@ -78389,10 +78841,10 @@ function writeAtomic(path10, contents) {
78389
78841
  mkdirSync9(dirname31(path10), { recursive: true });
78390
78842
  const tmp = `${path10}.tmp`;
78391
78843
  try {
78392
- writeFileSync12(tmp, contents);
78844
+ writeFileSync13(tmp, contents);
78393
78845
  renameSync5(tmp, path10);
78394
78846
  } catch (err) {
78395
- rmSync8(tmp, { force: true });
78847
+ rmSync9(tmp, { force: true });
78396
78848
  throw err;
78397
78849
  }
78398
78850
  }
@@ -78409,13 +78861,15 @@ async function uninstallForAgent(agent, options2) {
78409
78861
  }
78410
78862
  let parsed;
78411
78863
  try {
78412
- parsed = JSON.parse(readFileSync20(location2.realPath, "utf8"));
78864
+ parsed = JSON.parse(readFileSync23(location2.realPath, "utf8"));
78413
78865
  } catch {
78414
78866
  logger.warning(`[hooks] could not parse ${location2.realPath}; uninstall skipped to avoid clobbering`);
78415
78867
  return result;
78416
78868
  }
78417
78869
  const hooks = parsed.hooks ?? {};
78418
- const { pruned, removed } = pruneHooksSection(hooks, agent);
78870
+ const hooksDir = resolveHooksDir(agent, { global: options2.global });
78871
+ const evalHookNames = new Set(scanKitHookMetas(hooksDir).map((e2) => e2.file));
78872
+ const { pruned, removed } = pruneHooksSection(hooks, agent, evalHookNames, true);
78419
78873
  result.removed = removed;
78420
78874
  if (removed === 0)
78421
78875
  return result;
@@ -78473,11 +78927,14 @@ function eventsSummary(section) {
78473
78927
  }
78474
78928
  async function installForAgent(agent, options2, interactive, useStepUI) {
78475
78929
  const location2 = resolveSettingsPath(agent, { global: options2.global });
78930
+ const scope = options2.global ? "global" : "project";
78476
78931
  const handlers3 = selectHandlersForInstall(options2.categories);
78932
+ const evalMetas = options2.evalHooks ?? [];
78933
+ const evalHookNames = new Set(evalMetas.map((m2) => m2.evalPath ? basename19(m2.evalPath) : "").filter(Boolean));
78477
78934
  const section = buildHookSection(agent, options2.bin, {
78478
78935
  noDetach: options2.noDetach,
78479
78936
  debug: options2.debug
78480
- }, handlers3);
78937
+ }, [...handlers3, ...evalMetas], scope);
78481
78938
  const entriesPlanned = countEntries(section);
78482
78939
  const handlerNames = new Set(handlers3.map((h2) => h2.name));
78483
78940
  const result = await writeSettingsWithConfirm({
@@ -78486,7 +78943,7 @@ async function installForAgent(agent, options2, interactive, useStepUI) {
78486
78943
  transform: (current) => {
78487
78944
  const safeCurrent = current ?? {};
78488
78945
  const existingHooks = safeCurrent.hooks ?? {};
78489
- const { pruned } = pruneHooksSection(existingHooks, agent);
78946
+ const { pruned } = pruneHooksSection(existingHooks, agent, evalHookNames);
78490
78947
  const purged = { ...safeCurrent, hooks: pruned };
78491
78948
  const merged = mergeHooksObject(purged, section);
78492
78949
  return installStatusline(merged, {
@@ -78631,7 +79088,7 @@ async function installHook(options2) {
78631
79088
  // src/commands/hooks/status.ts
78632
79089
  init_takumi_config_manager();
78633
79090
  init_logger();
78634
- import { existsSync as existsSync58, readFileSync as readFileSync21 } from "node:fs";
79091
+ import { existsSync as existsSync58, readFileSync as readFileSync24 } from "node:fs";
78635
79092
  var AGENT_DISPLAY4 = { claude: "Claude Code", codex: "Codex" };
78636
79093
  var NEW_SHAPE = /\bhook-exec\b.*--hook\s+(guard|session|convention|extension|metrics|perf)\.(\S+).*-a\s+(claude|codex)(?![\w-])/;
78637
79094
  var LEGACY_SHAPE = /\bhooks\s+(?:session-start|user-prompt-submit|pre-tool-use|post-tool-use|stop|session-end)\s+-a\s+(claude|codex)(?![\w-])/;
@@ -78672,7 +79129,7 @@ async function statusForAgent(agent, options2, cwd2 = process.cwd()) {
78672
79129
  return result;
78673
79130
  let hooks;
78674
79131
  try {
78675
- const parsed = JSON.parse(readFileSync21(location2.realPath, "utf8"));
79132
+ const parsed = JSON.parse(readFileSync24(location2.realPath, "utf8"));
78676
79133
  hooks = parsed.hooks ?? {};
78677
79134
  } catch {
78678
79135
  return result;
@@ -78734,7 +79191,7 @@ var VALID_EVENTS = [
78734
79191
  "stop",
78735
79192
  "session-end"
78736
79193
  ];
78737
- var VALID_INTERNAL_EVENTS = ["_do-put", "_otlp-post"];
79194
+ var VALID_INTERNAL_EVENTS = ["_do-put", "_otlp-post", "scan-meta"];
78738
79195
  function isAction(token) {
78739
79196
  return VALID_ACTIONS.includes(token);
78740
79197
  }
@@ -78817,6 +79274,9 @@ async function hooksCommand(subcommand, options2 = {}) {
78817
79274
  case "_otlp-post":
78818
79275
  await handleOtlpPost();
78819
79276
  return;
79277
+ case "scan-meta":
79278
+ await handleScanMeta(options2.dir, options2.out);
79279
+ return;
78820
79280
  }
78821
79281
  }
78822
79282
  logger.error(`Unknown hooks subcommand: ${subcommand}`);
@@ -80002,20 +80462,20 @@ init_manifest_path_resolver();
80002
80462
  init_logger();
80003
80463
  init_takumi_constants();
80004
80464
  var import_fs_extra34 = __toESM(require_lib(), 1);
80005
- var import_semver5 = __toESM(require_semver2(), 1);
80006
- import { join as join116 } from "node:path";
80465
+ var import_semver4 = __toESM(require_semver2(), 1);
80466
+ import { join as join122 } from "node:path";
80007
80467
  function evaluateCliVersionGate(input) {
80008
80468
  const min = typeof input.minCliVersion === "string" ? input.minCliVersion.trim() : undefined;
80009
80469
  if (!min)
80010
80470
  return { allowed: true };
80011
- const coercedMin = import_semver5.default.coerce(min);
80471
+ const coercedMin = import_semver4.default.coerce(min);
80012
80472
  if (!coercedMin)
80013
80473
  return { allowed: true };
80014
80474
  const rawCli = (input.cliVersion ?? getCliVersion()).trim();
80015
- const coercedCli = import_semver5.default.coerce(rawCli);
80475
+ const coercedCli = import_semver4.default.coerce(rawCli);
80016
80476
  if (!coercedCli)
80017
80477
  return { allowed: true };
80018
- if (import_semver5.default.gte(coercedCli, coercedMin))
80478
+ if (import_semver4.default.gte(coercedCli, coercedMin))
80019
80479
  return { allowed: true };
80020
80480
  const reason = `This kit requires takumi CLI >= ${coercedMin.version}, but the installed CLI is ${rawCli}. Upgrade with \`${TAKUMI_CLI_GLOBAL_INSTALL_COMMAND}\`, or re-run with --force to install anyway.`;
80021
80481
  if (input.force)
@@ -80024,7 +80484,7 @@ function evaluateCliVersionGate(input) {
80024
80484
  }
80025
80485
  async function readKitMinCliVersion(extractDir) {
80026
80486
  try {
80027
- const resolved = await findManifestPath(join116(extractDir, ".claude"));
80487
+ const resolved = await findManifestPath(join122(extractDir, ".claude"));
80028
80488
  if (!resolved)
80029
80489
  return;
80030
80490
  const raw = await import_fs_extra34.readFile(resolved.path, "utf-8");
@@ -80039,6 +80499,7 @@ async function readKitMinCliVersion(extractDir) {
80039
80499
  // src/commands/init/init-command.ts
80040
80500
  init_manifest();
80041
80501
  init_environment();
80502
+ init_kit_layout();
80042
80503
  init_logger();
80043
80504
  init_process_lock();
80044
80505
  init_types2();
@@ -80220,8 +80681,8 @@ init_environment();
80220
80681
  init_logger();
80221
80682
  init_safe_spinner();
80222
80683
  import { mkdir as mkdir25, stat as stat10 } from "node:fs/promises";
80223
- import { tmpdir as tmpdir5 } from "node:os";
80224
- import { join as join122 } from "node:path";
80684
+ import { tmpdir as tmpdir6 } from "node:os";
80685
+ import { join as join128 } from "node:path";
80225
80686
 
80226
80687
  // src/shared/temp-cleanup.ts
80227
80688
  init_logger();
@@ -80238,9 +80699,9 @@ var import_ignore6 = __toESM(require_ignore(), 1);
80238
80699
  // src/domains/installation/download/file-downloader.ts
80239
80700
  init_logger();
80240
80701
  init_output_manager();
80241
- import { createWriteStream as createWriteStream2, rmSync as rmSync9 } from "node:fs";
80702
+ import { createWriteStream as createWriteStream2, rmSync as rmSync10 } from "node:fs";
80242
80703
  import { mkdir as mkdir21 } from "node:fs/promises";
80243
- import { join as join117 } from "node:path";
80704
+ import { join as join123 } from "node:path";
80244
80705
 
80245
80706
  // src/shared/progress-bar.ts
80246
80707
  init_output_manager();
@@ -80450,7 +80911,7 @@ var MAX_DOWNLOAD_SIZE = 500 * 1024 * 1024;
80450
80911
  class FileDownloader {
80451
80912
  async downloadAsset(asset, destDir) {
80452
80913
  try {
80453
- const destPath = join117(destDir, asset.name);
80914
+ const destPath = join123(destDir, asset.name);
80454
80915
  await mkdir21(destDir, { recursive: true });
80455
80916
  output.info(`Downloading ${asset.name} (${formatBytes(asset.size)})...`);
80456
80917
  logger.verbose("Download details", {
@@ -80508,7 +80969,7 @@ class FileDownloader {
80508
80969
  fileStream.end();
80509
80970
  await new Promise((resolve27) => fileStream.once("close", resolve27));
80510
80971
  try {
80511
- rmSync9(destPath, { force: true });
80972
+ rmSync10(destPath, { force: true });
80512
80973
  } catch (cleanupError) {
80513
80974
  const errorMsg = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
80514
80975
  logger.debug(`Failed to clean up partial download ${destPath}: ${errorMsg}`);
@@ -80522,7 +80983,7 @@ class FileDownloader {
80522
80983
  fileStream.end();
80523
80984
  await new Promise((resolve27) => fileStream.once("close", resolve27));
80524
80985
  try {
80525
- rmSync9(destPath, { force: true });
80986
+ rmSync10(destPath, { force: true });
80526
80987
  } catch (cleanupError) {
80527
80988
  const errorMsg = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
80528
80989
  logger.debug(`Failed to clean up partial download ${destPath}: ${errorMsg}`);
@@ -80535,7 +80996,7 @@ class FileDownloader {
80535
80996
  }
80536
80997
  async downloadFile(params) {
80537
80998
  const { url, name: name2, size, destDir, token } = params;
80538
- const destPath = join117(destDir, name2);
80999
+ const destPath = join123(destDir, name2);
80539
81000
  await mkdir21(destDir, { recursive: true });
80540
81001
  output.info(`Downloading ${name2}${size ? ` (${formatBytes(size)})` : ""}...`);
80541
81002
  const headers = {};
@@ -80605,7 +81066,7 @@ class FileDownloader {
80605
81066
  fileStream.end();
80606
81067
  await new Promise((resolve27) => fileStream.once("close", resolve27));
80607
81068
  try {
80608
- rmSync9(destPath, { force: true });
81069
+ rmSync10(destPath, { force: true });
80609
81070
  } catch (cleanupError) {
80610
81071
  const errorMsg = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
80611
81072
  logger.debug(`Failed to clean up partial download ${destPath}: ${errorMsg}`);
@@ -80623,7 +81084,7 @@ class FileDownloader {
80623
81084
  fileStream.end();
80624
81085
  await new Promise((resolve27) => fileStream.once("close", resolve27));
80625
81086
  try {
80626
- rmSync9(destPath, { force: true });
81087
+ rmSync10(destPath, { force: true });
80627
81088
  } catch (cleanupError) {
80628
81089
  const errorMsg = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
80629
81090
  logger.debug(`Failed to clean up partial download ${destPath}: ${errorMsg}`);
@@ -80638,7 +81099,7 @@ init_logger();
80638
81099
  init_types2();
80639
81100
  import { constants as constants3 } from "node:fs";
80640
81101
  import { access as access3, readdir as readdir26 } from "node:fs/promises";
80641
- import { join as join118 } from "node:path";
81102
+ import { join as join124 } from "node:path";
80642
81103
  async function validateExtraction(extractDir) {
80643
81104
  try {
80644
81105
  const entries = await readdir26(extractDir, { encoding: "utf8" });
@@ -80650,7 +81111,7 @@ async function validateExtraction(extractDir) {
80650
81111
  const missingPaths = [];
80651
81112
  for (const path10 of criticalPaths) {
80652
81113
  try {
80653
- await access3(join118(extractDir, path10), constants3.F_OK);
81114
+ await access3(join124(extractDir, path10), constants3.F_OK);
80654
81115
  logger.debug(`Found: ${path10}`);
80655
81116
  } catch {
80656
81117
  logger.warning(`Expected path not found: ${path10}`);
@@ -80672,7 +81133,7 @@ async function validateExtraction(extractDir) {
80672
81133
  // src/domains/installation/extraction/tar-extractor.ts
80673
81134
  init_logger();
80674
81135
  import { copyFile as copyFile6, mkdir as mkdir23, readdir as readdir28, rm as rm8, stat as stat8 } from "node:fs/promises";
80675
- import { join as join120 } from "node:path";
81136
+ import { join as join126 } from "node:path";
80676
81137
 
80677
81138
  // node_modules/tar/dist/esm/index.min.js
80678
81139
  import Kr from "events";
@@ -82704,7 +83165,7 @@ var ls = Symbol("readdir");
82704
83165
  var ai = Symbol("onreaddir");
82705
83166
  var li = Symbol("pipe");
82706
83167
  var ir = Symbol("entry");
82707
- var os7 = Symbol("entryOpt");
83168
+ var os8 = Symbol("entryOpt");
82708
83169
  var ci = Symbol("writeEntryClass");
82709
83170
  var rr = Symbol("write");
82710
83171
  var hs = Symbol("ondrain");
@@ -82767,7 +83228,7 @@ var Et = class extends D {
82767
83228
  t.resume();
82768
83229
  else {
82769
83230
  let i = new di(t.path, e2);
82770
- i.entry = new ri(t, this[os7](i)), i.entry.on("end", () => this[ns](i)), this[G2] += 1, this[W2].push(i);
83231
+ i.entry = new ri(t, this[os8](i)), i.entry.on("end", () => this[ns](i)), this[G2] += 1, this[W2].push(i);
82771
83232
  }
82772
83233
  this[Ft]();
82773
83234
  }
@@ -82836,13 +83297,13 @@ var Et = class extends D {
82836
83297
  }
82837
83298
  }
82838
83299
  }
82839
- [os7](t) {
83300
+ [os8](t) {
82840
83301
  return { onwarn: (e2, i, r2) => this.warn(e2, i, r2), noPax: this.noPax, cwd: this.cwd, absolute: t.absolute, preservePaths: this.preservePaths, maxReadSize: this.maxReadSize, strict: this.strict, portable: this.portable, linkCache: this.linkCache, statCache: this.statCache, noMtime: this.noMtime, mtime: this.mtime, prefix: this.prefix, onWriteEntry: this.onWriteEntry };
82841
83302
  }
82842
83303
  [ir](t) {
82843
83304
  this[G2] += 1;
82844
83305
  try {
82845
- return new this[ci](t.path, this[os7](t)).on("end", () => this[ns](t)).on("error", (i) => this.emit("error", i));
83306
+ return new this[ci](t.path, this[os8](t)).on("end", () => this[ns](t)).on("error", (i) => this.emit("error", i));
82846
83307
  } catch (e2) {
82847
83308
  this.emit("error", e2);
82848
83309
  }
@@ -83885,7 +84346,7 @@ function decodeFilePath(path10) {
83885
84346
  init_logger();
83886
84347
  init_types2();
83887
84348
  import { copyFile as copyFile5, lstat as lstat8, mkdir as mkdir22, readdir as readdir27 } from "node:fs/promises";
83888
- import { join as join119, relative as relative17 } from "node:path";
84349
+ import { join as join125, relative as relative17 } from "node:path";
83889
84350
  async function withRetry2(fn2, retries = 3) {
83890
84351
  for (let i = 0;i < retries; i++) {
83891
84352
  try {
@@ -83907,8 +84368,8 @@ async function moveDirectoryContents(sourceDir, destDir, shouldExclude, sizeTrac
83907
84368
  await mkdir22(destDir, { recursive: true });
83908
84369
  const entries = await readdir27(sourceDir, { encoding: "utf8" });
83909
84370
  for (const entry of entries) {
83910
- const sourcePath = join119(sourceDir, entry);
83911
- const destPath = join119(destDir, entry);
84371
+ const sourcePath = join125(sourceDir, entry);
84372
+ const destPath = join125(destDir, entry);
83912
84373
  const relativePath = relative17(sourceDir, sourcePath);
83913
84374
  if (!isPathSafe(destDir, destPath)) {
83914
84375
  logger.warning(`Skipping unsafe path: ${relativePath}`);
@@ -83935,8 +84396,8 @@ async function copyDirectory(sourceDir, destDir, shouldExclude, sizeTracker) {
83935
84396
  await mkdir22(destDir, { recursive: true });
83936
84397
  const entries = await readdir27(sourceDir, { encoding: "utf8" });
83937
84398
  for (const entry of entries) {
83938
- const sourcePath = join119(sourceDir, entry);
83939
- const destPath = join119(destDir, entry);
84399
+ const sourcePath = join125(sourceDir, entry);
84400
+ const destPath = join125(destDir, entry);
83940
84401
  const relativePath = relative17(sourceDir, sourcePath);
83941
84402
  if (!isPathSafe(destDir, destPath)) {
83942
84403
  logger.warning(`Skipping unsafe path: ${relativePath}`);
@@ -83991,7 +84452,7 @@ class TarExtractor {
83991
84452
  logger.debug(`Root entries: ${entries.join(", ")}`);
83992
84453
  if (entries.length === 1) {
83993
84454
  const rootEntry = entries[0];
83994
- const rootPath = join120(tempExtractDir, rootEntry);
84455
+ const rootPath = join126(tempExtractDir, rootEntry);
83995
84456
  const rootStat = await stat8(rootPath);
83996
84457
  if (rootStat.isDirectory()) {
83997
84458
  const rootContents = await readdir28(rootPath, { encoding: "utf8" });
@@ -84007,7 +84468,7 @@ class TarExtractor {
84007
84468
  }
84008
84469
  } else {
84009
84470
  await mkdir23(destDir, { recursive: true });
84010
- await copyFile6(rootPath, join120(destDir, rootEntry));
84471
+ await copyFile6(rootPath, join126(destDir, rootEntry));
84011
84472
  }
84012
84473
  } else {
84013
84474
  logger.debug("Multiple root entries - moving all");
@@ -84028,7 +84489,7 @@ class TarExtractor {
84028
84489
  init_logger();
84029
84490
  import { createWriteStream as createWriteStream3 } from "node:fs";
84030
84491
  import { chmod as chmod4, copyFile as copyFile7, mkdir as mkdir24, readdir as readdir29, rm as rm9, stat as stat9 } from "node:fs/promises";
84031
- import { dirname as dirname32, join as join121, resolve as resolve27 } from "node:path";
84492
+ import { dirname as dirname32, join as join127, resolve as resolve27 } from "node:path";
84032
84493
  import { pipeline } from "node:stream/promises";
84033
84494
  import yauzl from "yauzl-promise";
84034
84495
  class ZipExtractor {
@@ -84042,7 +84503,7 @@ class ZipExtractor {
84042
84503
  logger.debug(`Root entries: ${entries.join(", ")}`);
84043
84504
  if (entries.length === 1) {
84044
84505
  const rootEntry = entries[0];
84045
- const rootPath = join121(tempExtractDir, rootEntry);
84506
+ const rootPath = join127(tempExtractDir, rootEntry);
84046
84507
  const rootStat = await stat9(rootPath);
84047
84508
  if (rootStat.isDirectory()) {
84048
84509
  const rootContents = await readdir29(rootPath, { encoding: "utf8" });
@@ -84058,7 +84519,7 @@ class ZipExtractor {
84058
84519
  }
84059
84520
  } else {
84060
84521
  await mkdir24(destDir, { recursive: true });
84061
- await copyFile7(rootPath, join121(destDir, rootEntry));
84522
+ await copyFile7(rootPath, join127(destDir, rootEntry));
84062
84523
  }
84063
84524
  } else {
84064
84525
  logger.debug("Multiple root entries - moving all");
@@ -84187,7 +84648,7 @@ class DownloadManager {
84187
84648
  async createTempDir() {
84188
84649
  const timestamp = Date.now();
84189
84650
  const counter = DownloadManager.tempDirCounter++;
84190
- const primaryTempDir = join122(tmpdir5(), `takumi-${timestamp}-${counter}`);
84651
+ const primaryTempDir = join128(tmpdir6(), `takumi-${timestamp}-${counter}`);
84191
84652
  try {
84192
84653
  await mkdir25(primaryTempDir, { recursive: true });
84193
84654
  logger.debug(`Created temp directory: ${primaryTempDir}`);
@@ -84204,7 +84665,7 @@ Solutions:
84204
84665
  2. Set HOME environment variable
84205
84666
  3. Try running from a different directory`);
84206
84667
  }
84207
- const fallbackTempDir = join122(homeDir, STATE_DIRNAME, "tmp", `takumi-${timestamp}-${counter}`);
84668
+ const fallbackTempDir = join128(homeDir, STATE_DIRNAME, "tmp", `takumi-${timestamp}-${counter}`);
84208
84669
  try {
84209
84670
  await mkdir25(fallbackTempDir, { recursive: true });
84210
84671
  logger.debug(`Created temp directory (fallback): ${fallbackTempDir}`);
@@ -84932,7 +85393,7 @@ Re-run with explicit base kit, e.g. --kit ${BASE_KIT} --kit ${parsed2.join(" --k
84932
85393
  }
84933
85394
  // src/commands/init/phases/selection-handler.ts
84934
85395
  import { mkdir as mkdir26 } from "node:fs/promises";
84935
- import { join as join125, resolve as resolve30 } from "node:path";
85396
+ import { join as join131, resolve as resolve30 } from "node:path";
84936
85397
 
84937
85398
  // src/commands/shared/agent-selector.ts
84938
85399
  init_registry();
@@ -85246,7 +85707,7 @@ async function handleSelection(ctx) {
85246
85707
  }
85247
85708
  if (!ctx.options.fresh) {
85248
85709
  const prefix = PathResolver.getPathPrefix(ctx.options.global);
85249
- const claudeDir = prefix ? join125(resolvedDir, prefix) : resolvedDir;
85710
+ const claudeDir = prefix ? join131(resolvedDir, prefix) : resolvedDir;
85250
85711
  try {
85251
85712
  const existingMetadata = await readManifest(claudeDir);
85252
85713
  if (existingMetadata?.kits) {
@@ -85279,7 +85740,7 @@ async function handleSelection(ctx) {
85279
85740
  }
85280
85741
  if (ctx.options.fresh) {
85281
85742
  const prefix = PathResolver.getPathPrefix(ctx.options.global);
85282
- const claudeDir = prefix ? join125(resolvedDir, prefix) : resolvedDir;
85743
+ const claudeDir = prefix ? join131(resolvedDir, prefix) : resolvedDir;
85283
85744
  const canProceed = await handleFreshInstallation(claudeDir, ctx.prompts);
85284
85745
  if (!canProceed) {
85285
85746
  return { ...ctx, cancelled: true };
@@ -85299,7 +85760,7 @@ async function handleSelection(ctx) {
85299
85760
  let currentVersion = null;
85300
85761
  try {
85301
85762
  const prefix = PathResolver.getPathPrefix(ctx.options.global);
85302
- const claudeDir = prefix ? join125(resolvedDir, prefix) : resolvedDir;
85763
+ const claudeDir = prefix ? join131(resolvedDir, prefix) : resolvedDir;
85303
85764
  const existingMetadata = await readManifest(claudeDir);
85304
85765
  currentVersion = existingMetadata?.kits?.[kitType]?.version || null;
85305
85766
  if (currentVersion) {
@@ -85387,7 +85848,7 @@ async function handleSelection(ctx) {
85387
85848
  if (ctx.options.yes && !ctx.options.fresh && !ctx.options.force && releaseTag && !isOfflineMode) {
85388
85849
  try {
85389
85850
  const prefix = PathResolver.getPathPrefix(ctx.options.global);
85390
- const claudeDir = prefix ? join125(resolvedDir, prefix) : resolvedDir;
85851
+ const claudeDir = prefix ? join131(resolvedDir, prefix) : resolvedDir;
85391
85852
  const existingMetadata = await readManifest(claudeDir);
85392
85853
  const installedKitVersion = existingMetadata?.kits?.[kitType]?.version;
85393
85854
  if (installedKitVersion && versionsMatch(installedKitVersion, releaseTag)) {
@@ -85410,7 +85871,7 @@ async function handleSelection(ctx) {
85410
85871
  let currentSecondaryVersion = null;
85411
85872
  try {
85412
85873
  const prefix = PathResolver.getPathPrefix(ctx.options.global);
85413
- const claudeDir = prefix ? join125(resolvedDir, prefix) : resolvedDir;
85874
+ const claudeDir = prefix ? join131(resolvedDir, prefix) : resolvedDir;
85414
85875
  const existingMetadata = await readManifest(claudeDir);
85415
85876
  currentSecondaryVersion = existingMetadata?.kits?.[secondaryKit]?.version || null;
85416
85877
  } catch {}
@@ -85494,12 +85955,12 @@ function resolveGlobalTargetDir(targetAgents2) {
85494
85955
  // src/commands/init/phases/sync-handler.ts
85495
85956
  init_paths();
85496
85957
  import { copyFile as copyFile8, mkdir as mkdir28, open as open3, readFile as readFile45, rename as rename8, stat as stat12, unlink as unlink12, writeFile as writeFile29 } from "node:fs/promises";
85497
- import { dirname as dirname35, join as join128, resolve as resolve31 } from "node:path";
85958
+ import { dirname as dirname35, join as join134, resolve as resolve31 } from "node:path";
85498
85959
 
85499
85960
  // src/domains/sync/config-version-checker.ts
85500
85961
  init_auth_client();
85501
85962
  import { mkdir as mkdir27, readFile as readFile43, unlink as unlink11, writeFile as writeFile28 } from "node:fs/promises";
85502
- import { join as join126 } from "node:path";
85963
+ import { join as join132 } from "node:path";
85503
85964
  init_version_utils();
85504
85965
  init_logger();
85505
85966
  init_path_resolver();
@@ -85535,7 +85996,7 @@ var CACHE_FILENAME = "config-update-cache.json";
85535
85996
  class ConfigVersionChecker {
85536
85997
  static getCacheFilePath(kitType, global3) {
85537
85998
  const cacheDir = PathResolver.getCacheDir(global3);
85538
- return join126(cacheDir, `${kitType}-${CACHE_FILENAME}`);
85999
+ return join132(cacheDir, `${kitType}-${CACHE_FILENAME}`);
85539
86000
  }
85540
86001
  static async loadCache(kitType, global3) {
85541
86002
  try {
@@ -85655,7 +86116,7 @@ class ConfigVersionChecker {
85655
86116
  init_ownership_checker();
85656
86117
  init_logger();
85657
86118
  import { lstat as lstat9, readFile as readFile44, readlink, realpath as realpath3, stat as stat11 } from "node:fs/promises";
85658
- import { isAbsolute as isAbsolute6, join as join127, normalize as normalize9, relative as relative18 } from "node:path";
86119
+ import { isAbsolute as isAbsolute7, join as join133, normalize as normalize10, relative as relative18 } from "node:path";
85659
86120
  var MAX_SYNC_FILE_SIZE = 10 * 1024 * 1024;
85660
86121
  var MAX_SYMLINK_DEPTH = 20;
85661
86122
  async function validateSymlinkChain(path11, basePath, maxDepth = MAX_SYMLINK_DEPTH) {
@@ -85667,10 +86128,10 @@ async function validateSymlinkChain(path11, basePath, maxDepth = MAX_SYMLINK_DEP
85667
86128
  if (!stats.isSymbolicLink())
85668
86129
  break;
85669
86130
  const target = await readlink(current);
85670
- const resolvedTarget = isAbsolute6(target) ? target : join127(current, "..", target);
85671
- const normalizedTarget = normalize9(resolvedTarget);
86131
+ const resolvedTarget = isAbsolute7(target) ? target : join133(current, "..", target);
86132
+ const normalizedTarget = normalize10(resolvedTarget);
85672
86133
  const rel = relative18(basePath, normalizedTarget);
85673
- if (rel.startsWith("..") || isAbsolute6(rel)) {
86134
+ if (rel.startsWith("..") || isAbsolute7(rel)) {
85674
86135
  throw new Error(`Symlink chain escapes base directory at depth ${depth}: ${path11}`);
85675
86136
  }
85676
86137
  current = normalizedTarget;
@@ -85696,16 +86157,16 @@ async function validateSyncPath(basePath, filePath) {
85696
86157
  if (filePath.length > 1024) {
85697
86158
  throw new Error(`Path too long: ${filePath.slice(0, 50)}...`);
85698
86159
  }
85699
- const normalized = normalize9(filePath);
85700
- if (isAbsolute6(normalized)) {
86160
+ const normalized = normalize10(filePath);
86161
+ if (isAbsolute7(normalized)) {
85701
86162
  throw new Error(`Absolute paths not allowed: ${filePath}`);
85702
86163
  }
85703
86164
  if (normalized.startsWith("..") || normalized.includes("/../")) {
85704
86165
  throw new Error(`Path traversal not allowed: ${filePath}`);
85705
86166
  }
85706
- const fullPath = join127(basePath, normalized);
86167
+ const fullPath = join133(basePath, normalized);
85707
86168
  const rel = relative18(basePath, fullPath);
85708
- if (rel.startsWith("..") || isAbsolute6(rel)) {
86169
+ if (rel.startsWith("..") || isAbsolute7(rel)) {
85709
86170
  throw new Error(`Path escapes base directory: ${filePath}`);
85710
86171
  }
85711
86172
  await validateSymlinkChain(fullPath, basePath);
@@ -85713,17 +86174,17 @@ async function validateSyncPath(basePath, filePath) {
85713
86174
  const resolvedBase = await realpath3(basePath);
85714
86175
  const resolvedFull = await realpath3(fullPath);
85715
86176
  const resolvedRel = relative18(resolvedBase, resolvedFull);
85716
- if (resolvedRel.startsWith("..") || isAbsolute6(resolvedRel)) {
86177
+ if (resolvedRel.startsWith("..") || isAbsolute7(resolvedRel)) {
85717
86178
  throw new Error(`Symlink escapes base directory: ${filePath}`);
85718
86179
  }
85719
86180
  } catch (error) {
85720
86181
  if (error.code === "ENOENT") {
85721
- const parentPath = join127(fullPath, "..");
86182
+ const parentPath = join133(fullPath, "..");
85722
86183
  try {
85723
86184
  const resolvedBase = await realpath3(basePath);
85724
86185
  const resolvedParent = await realpath3(parentPath);
85725
86186
  const resolvedRel = relative18(resolvedBase, resolvedParent);
85726
- if (resolvedRel.startsWith("..") || isAbsolute6(resolvedRel)) {
86187
+ if (resolvedRel.startsWith("..") || isAbsolute7(resolvedRel)) {
85727
86188
  throw new Error(`Parent symlink escapes base directory: ${filePath}`);
85728
86189
  }
85729
86190
  } catch (parentError) {
@@ -86209,7 +86670,7 @@ function getLockTimeout() {
86209
86670
  var STALE_LOCK_THRESHOLD_MS = 5 * 60 * 1000;
86210
86671
  async function acquireSyncLock(global3) {
86211
86672
  const cacheDir = PathResolver.getCacheDir(global3);
86212
- const lockPath2 = join128(cacheDir, ".sync-lock");
86673
+ const lockPath2 = join134(cacheDir, ".sync-lock");
86213
86674
  const startTime = Date.now();
86214
86675
  const lockTimeout = getLockTimeout();
86215
86676
  await mkdir28(dirname35(lockPath2), { recursive: true });
@@ -86290,7 +86751,7 @@ async function executeSyncMerge(ctx) {
86290
86751
  try {
86291
86752
  const sourcePath = await validateSyncPath(upstreamDir, file.path);
86292
86753
  const targetPath = await validateSyncPath(ctx.claudeDir, file.path);
86293
- const targetDir = join128(targetPath, "..");
86754
+ const targetDir = join134(targetPath, "..");
86294
86755
  try {
86295
86756
  await mkdir28(targetDir, { recursive: true });
86296
86757
  } catch (mkdirError) {
@@ -86461,7 +86922,7 @@ async function createBackup(claudeDir, files, backupDir) {
86461
86922
  const sourcePath = await validateSyncPath(claudeDir, file.path);
86462
86923
  if (await import_fs_extra36.pathExists(sourcePath)) {
86463
86924
  const targetPath = await validateSyncPath(backupDir, file.path);
86464
- const targetDir = join128(targetPath, "..");
86925
+ const targetDir = join134(targetPath, "..");
86465
86926
  await mkdir28(targetDir, { recursive: true });
86466
86927
  await copyFile8(sourcePath, targetPath);
86467
86928
  }
@@ -86487,38 +86948,38 @@ init_logger();
86487
86948
  init_types2();
86488
86949
  var import_fs_extra37 = __toESM(require_lib(), 1);
86489
86950
  import { rename as rename9, rm as rm10 } from "node:fs/promises";
86490
- import { join as join129, relative as relative19 } from "node:path";
86951
+ import { join as join135, relative as relative19 } from "node:path";
86491
86952
  async function collectDirsToRename(extractDir, folders) {
86492
86953
  const dirsToRename = [];
86493
86954
  if (folders.docs !== DEFAULT_FOLDERS.docs) {
86494
- const docsPath = join129(extractDir, DEFAULT_FOLDERS.docs);
86955
+ const docsPath = join135(extractDir, DEFAULT_FOLDERS.docs);
86495
86956
  if (await import_fs_extra37.pathExists(docsPath)) {
86496
86957
  dirsToRename.push({
86497
86958
  from: docsPath,
86498
- to: join129(extractDir, folders.docs)
86959
+ to: join135(extractDir, folders.docs)
86499
86960
  });
86500
86961
  }
86501
- const claudeDocsPath = join129(extractDir, ".claude", DEFAULT_FOLDERS.docs);
86962
+ const claudeDocsPath = join135(extractDir, ".claude", DEFAULT_FOLDERS.docs);
86502
86963
  if (await import_fs_extra37.pathExists(claudeDocsPath)) {
86503
86964
  dirsToRename.push({
86504
86965
  from: claudeDocsPath,
86505
- to: join129(extractDir, ".claude", folders.docs)
86966
+ to: join135(extractDir, ".claude", folders.docs)
86506
86967
  });
86507
86968
  }
86508
86969
  }
86509
86970
  if (folders.plans !== DEFAULT_FOLDERS.plans) {
86510
- const plansPath = join129(extractDir, DEFAULT_FOLDERS.plans);
86971
+ const plansPath = join135(extractDir, DEFAULT_FOLDERS.plans);
86511
86972
  if (await import_fs_extra37.pathExists(plansPath)) {
86512
86973
  dirsToRename.push({
86513
86974
  from: plansPath,
86514
- to: join129(extractDir, folders.plans)
86975
+ to: join135(extractDir, folders.plans)
86515
86976
  });
86516
86977
  }
86517
- const claudePlansPath = join129(extractDir, ".claude", DEFAULT_FOLDERS.plans);
86978
+ const claudePlansPath = join135(extractDir, ".claude", DEFAULT_FOLDERS.plans);
86518
86979
  if (await import_fs_extra37.pathExists(claudePlansPath)) {
86519
86980
  dirsToRename.push({
86520
86981
  from: claudePlansPath,
86521
- to: join129(extractDir, ".claude", folders.plans)
86982
+ to: join135(extractDir, ".claude", folders.plans)
86522
86983
  });
86523
86984
  }
86524
86985
  }
@@ -86559,7 +87020,7 @@ async function renameFolders(dirsToRename, extractDir, options2) {
86559
87020
  init_logger();
86560
87021
  init_types2();
86561
87022
  import { readFile as readFile46, readdir as readdir30, writeFile as writeFile30 } from "node:fs/promises";
86562
- import { join as join130, relative as relative20 } from "node:path";
87023
+ import { join as join136, relative as relative20 } from "node:path";
86563
87024
  var TRANSFORMABLE_FILE_PATTERNS = [
86564
87025
  ".md",
86565
87026
  ".txt",
@@ -86612,7 +87073,7 @@ async function transformFileContents(dir, compiledReplacements, options2) {
86612
87073
  let replacementsCount = 0;
86613
87074
  const entries = await readdir30(dir, { withFileTypes: true });
86614
87075
  for (const entry of entries) {
86615
- const fullPath = join130(dir, entry.name);
87076
+ const fullPath = join136(dir, entry.name);
86616
87077
  if (entry.isDirectory()) {
86617
87078
  if (entry.name === "node_modules" || entry.name === ".git") {
86618
87079
  continue;
@@ -86749,7 +87210,7 @@ async function transformFolderPaths(extractDir, folders, options2 = {}) {
86749
87210
  init_logger();
86750
87211
  import { readFile as readFile47, readdir as readdir31, writeFile as writeFile31 } from "node:fs/promises";
86751
87212
  import { platform as platform12 } from "node:os";
86752
- import { extname as extname8, join as join131 } from "node:path";
87213
+ import { extname as extname8, join as join137 } from "node:path";
86753
87214
  var IS_WINDOWS3 = platform12() === "win32";
86754
87215
  var HOME_PREFIX = "$HOME";
86755
87216
  function getHomeDirPrefix() {
@@ -86838,8 +87299,8 @@ function transformContent(content) {
86838
87299
  }
86839
87300
  function shouldTransformFile3(filename) {
86840
87301
  const ext = extname8(filename).toLowerCase();
86841
- const basename19 = filename.split("/").pop() || filename;
86842
- return TRANSFORMABLE_EXTENSIONS3.has(ext) || ALWAYS_TRANSFORM_FILES.has(basename19);
87302
+ const basename20 = filename.split("/").pop() || filename;
87303
+ return TRANSFORMABLE_EXTENSIONS3.has(ext) || ALWAYS_TRANSFORM_FILES.has(basename20);
86843
87304
  }
86844
87305
  async function transformPathsForGlobalInstall(directory, options2 = {}) {
86845
87306
  let filesTransformed = 0;
@@ -86849,7 +87310,7 @@ async function transformPathsForGlobalInstall(directory, options2 = {}) {
86849
87310
  async function processDirectory2(dir) {
86850
87311
  const entries = await readdir31(dir, { withFileTypes: true });
86851
87312
  for (const entry of entries) {
86852
- const fullPath = join131(dir, entry.name);
87313
+ const fullPath = join137(dir, entry.name);
86853
87314
  if (entry.isDirectory()) {
86854
87315
  if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
86855
87316
  continue;
@@ -86940,8 +87401,16 @@ function mapAgentToHookAgent(agent) {
86940
87401
  return "codex";
86941
87402
  return null;
86942
87403
  }
86943
- async function installTkmHooksForAgents(targetAgents2, options2) {
86944
- const categories = options2.installHooks ? undefined : ["metrics"];
87404
+ function collectKitEvalHooks(extractDir, into) {
87405
+ const sourceHooksDir = findExistingProjectLayoutPath(extractDir, "hooks");
87406
+ if (!sourceHooksDir)
87407
+ return;
87408
+ for (const entry of scanKitHookMetas(sourceHooksDir)) {
87409
+ into.set(entry.file, kitHookToInstallMeta(entry));
87410
+ }
87411
+ }
87412
+ async function installTkmHooksForAgents(targetAgents2, options2, evalHooks) {
87413
+ const categories = undefined;
86945
87414
  for (const agent of targetAgents2) {
86946
87415
  const hookAgent = mapAgentToHookAgent(agent);
86947
87416
  if (!hookAgent)
@@ -86952,11 +87421,12 @@ async function installTkmHooksForAgents(targetAgents2, options2) {
86952
87421
  global: options2.global,
86953
87422
  dryRun: options2.dryRun,
86954
87423
  categories,
87424
+ evalHooks,
86955
87425
  yes: true
86956
87426
  });
86957
87427
  } catch (err) {
86958
87428
  const message = err instanceof Error ? err.message : String(err);
86959
- logger.warning(`[init] tkm hooks install for ${agent} failed: ${message}`);
87429
+ logger.error(`[init] tkm hooks install for ${agent} FAILED — guards/session hooks may be inactive; re-run \`tkm hooks install -a ${hookAgent}\`: ${message}`);
86960
87430
  }
86961
87431
  }
86962
87432
  }
@@ -87091,6 +87561,7 @@ async function executeInit(options2, prompts, deps) {
87091
87561
  return;
87092
87562
  }
87093
87563
  const aggregatedResults = [];
87564
+ const discoveredEvalHooks = new Map;
87094
87565
  let lastCtx = ctx;
87095
87566
  for (let i = 0;i < selectedKits.length; i++) {
87096
87567
  const currentKit = selectedKits[i];
@@ -87183,17 +87654,18 @@ async function executeInit(options2, prompts, deps) {
87183
87654
  aggregatedResults.push(...kitResults);
87184
87655
  if (kitResults.some((r2) => r2.cancelled))
87185
87656
  return;
87657
+ if (lastCtx.extractDir) {
87658
+ collectKitEvalHooks(lastCtx.extractDir, discoveredEvalHooks);
87659
+ }
87186
87660
  }
87187
87661
  ctx = lastCtx;
87188
87662
  const results = aggregatedResults;
87189
87663
  ctx.installerResults = results;
87190
- if (!isSyncMode) {
87191
- await installTkmHooksForAgents(targetAgents2, {
87192
- global: Boolean(ctx.options.global),
87193
- dryRun: Boolean(ctx.options.dryRun),
87194
- installHooks: Boolean(ctx.options.installHooks)
87195
- });
87196
- }
87664
+ await installTkmHooksForAgents(targetAgents2, {
87665
+ global: Boolean(ctx.options.global),
87666
+ dryRun: Boolean(ctx.options.dryRun),
87667
+ installHooks: Boolean(ctx.options.installHooks)
87668
+ }, [...discoveredEvalHooks.values()]);
87197
87669
  if (targetAgents2.length > 1) {
87198
87670
  displayMultiInstallerSummary(results);
87199
87671
  }
@@ -87268,10 +87740,10 @@ init_dist2();
87268
87740
  // src/domains/mcp/agent-detector.ts
87269
87741
  init_environment();
87270
87742
  import { existsSync as existsSync61 } from "node:fs";
87271
- import { join as join132 } from "node:path";
87743
+ import { join as join138 } from "node:path";
87272
87744
 
87273
87745
  // src/domains/mcp/shell-out.ts
87274
- import { spawnSync as spawnSync5 } from "node:child_process";
87746
+ import { spawnSync as spawnSync6 } from "node:child_process";
87275
87747
  var DEFAULT_TIMEOUT_MS7 = 60000;
87276
87748
  var PROBE_TIMEOUT_MS = 5000;
87277
87749
  var SERVICE_NAME_PATTERN = /^[a-z0-9-]+$/;
@@ -87279,7 +87751,7 @@ function isValidServiceName(name2) {
87279
87751
  return SERVICE_NAME_PATTERN.test(name2);
87280
87752
  }
87281
87753
  function runAgentCli(bin, args, timeoutMs = DEFAULT_TIMEOUT_MS7) {
87282
- const result = spawnSync5(bin, args, {
87754
+ const result = spawnSync6(bin, args, {
87283
87755
  timeout: timeoutMs,
87284
87756
  encoding: "utf-8",
87285
87757
  shell: false,
@@ -87302,7 +87774,7 @@ function runAgentCli(bin, args, timeoutMs = DEFAULT_TIMEOUT_MS7) {
87302
87774
  }
87303
87775
  function isBinaryOnPath(bin) {
87304
87776
  const probeCmd = process.platform === "win32" ? "where" : "which";
87305
- const result = spawnSync5(probeCmd, [bin], {
87777
+ const result = spawnSync6(probeCmd, [bin], {
87306
87778
  timeout: PROBE_TIMEOUT_MS,
87307
87779
  encoding: "utf-8",
87308
87780
  shell: false
@@ -87358,9 +87830,9 @@ function getAgentConfigPath(agent) {
87358
87830
  return null;
87359
87831
  switch (agent) {
87360
87832
  case "claude-code":
87361
- return join132(home6, ".claude.json");
87833
+ return join138(home6, ".claude.json");
87362
87834
  case "codex":
87363
- return join132(home6, ".codex", "config.toml");
87835
+ return join138(home6, ".codex", "config.toml");
87364
87836
  default: {
87365
87837
  const _exhaustive = agent;
87366
87838
  return _exhaustive;
@@ -87386,7 +87858,7 @@ var PROJECT_MARKERS = {
87386
87858
  codex: [".codex", "AGENTS.md"]
87387
87859
  };
87388
87860
  function detectProjectAgents(cwd2 = process.cwd(), exists2 = existsSync61) {
87389
- return ALL_MCP_AGENTS.filter((agent) => PROJECT_MARKERS[agent].some((marker) => exists2(join132(cwd2, marker))));
87861
+ return ALL_MCP_AGENTS.filter((agent) => PROJECT_MARKERS[agent].some((marker) => exists2(join138(cwd2, marker))));
87390
87862
  }
87391
87863
 
87392
87864
  // src/domains/mcp/registry-client.ts
@@ -87398,12 +87870,12 @@ init_auth_client();
87398
87870
  init_logger();
87399
87871
  init_paths2();
87400
87872
  import { promises as fs33 } from "node:fs";
87401
- import { join as join133 } from "node:path";
87873
+ import { join as join139 } from "node:path";
87402
87874
  function getCacheDir() {
87403
- return join133(getConfigDir(), "mcp");
87875
+ return join139(getConfigDir(), "mcp");
87404
87876
  }
87405
87877
  function getCachePath2() {
87406
- return join133(getCacheDir(), "registry-cache.json");
87878
+ return join139(getCacheDir(), "registry-cache.json");
87407
87879
  }
87408
87880
  async function readCachedRegistry() {
87409
87881
  try {
@@ -87534,14 +88006,14 @@ function resolveService(registry, name2) {
87534
88006
  // src/domains/mcp/writers/claude-config-file.ts
87535
88007
  import { existsSync as existsSync62 } from "node:fs";
87536
88008
  import { mkdir as mkdir29, writeFile as writeFile32 } from "node:fs/promises";
87537
- import { dirname as dirname36, join as join134 } from "node:path";
88009
+ import { dirname as dirname36, join as join140 } from "node:path";
87538
88010
  var AGENT = "claude-code";
87539
88011
  var LOCAL_SCOPE_FALLBACK_WARNING = "claude CLI not found; local scope isn't representable via direct file write, wrote to user-level ~/.claude.json instead";
87540
88012
  function userConfigPath() {
87541
88013
  return getAgentConfigPath(AGENT);
87542
88014
  }
87543
88015
  function projectConfigPath() {
87544
- return join134(process.cwd(), ".mcp.json");
88016
+ return join140(process.cwd(), ".mcp.json");
87545
88017
  }
87546
88018
  function configPathFor(scope) {
87547
88019
  return scope === "project" ? projectConfigPath() : userConfigPath();
@@ -88210,18 +88682,18 @@ async function mcpCommand(action, service, options2 = {}) {
88210
88682
  // src/commands/plan/plan-command.ts
88211
88683
  init_output_manager();
88212
88684
  import { existsSync as existsSync68, statSync as statSync12 } from "node:fs";
88213
- import { dirname as dirname42, join as join138, parse as parse4, resolve as resolve35 } from "node:path";
88685
+ import { dirname as dirname42, join as join144, parse as parse4, resolve as resolve35 } from "node:path";
88214
88686
 
88215
88687
  // src/commands/plan/plan-read-handlers.ts
88216
88688
  import { existsSync as existsSync67, statSync as statSync11 } from "node:fs";
88217
- import { basename as basename21, dirname as dirname41, join as join137, relative as relative21, resolve as resolve33 } from "node:path";
88689
+ import { basename as basename22, dirname as dirname41, join as join143, relative as relative21, resolve as resolve33 } from "node:path";
88218
88690
 
88219
88691
  // src/domains/plan-parser/index.ts
88220
88692
  import { dirname as dirname40 } from "node:path";
88221
88693
 
88222
88694
  // src/domains/plan-parser/plan-table-parser.ts
88223
88695
  var import_gray_matter6 = __toESM(require_gray_matter(), 1);
88224
- import { readFileSync as readFileSync24 } from "node:fs";
88696
+ import { readFileSync as readFileSync27 } from "node:fs";
88225
88697
  import { dirname as dirname37, resolve as resolve32 } from "node:path";
88226
88698
  function normalizeStatus(raw) {
88227
88699
  const s3 = raw.toLowerCase().trim();
@@ -88587,30 +89059,30 @@ function parsePhasesFromBody(body, dir, options2) {
88587
89059
  return parseFormat6(normalizedBody, dir, options2);
88588
89060
  }
88589
89061
  function parsePlanFile(planFilePath, options2) {
88590
- const content = readFileSync24(planFilePath, "utf8");
89062
+ const content = readFileSync27(planFilePath, "utf8");
88591
89063
  const dir = dirname37(planFilePath);
88592
89064
  const { data: frontmatter, content: body } = import_gray_matter6.default(content);
88593
89065
  const phases = parsePhasesFromBody(body, dir, options2);
88594
89066
  return { frontmatter, phases };
88595
89067
  }
88596
89068
  // src/domains/plan-parser/plan-scanner.ts
88597
- import { existsSync as existsSync64, readdirSync as readdirSync11 } from "node:fs";
88598
- import { join as join135 } from "node:path";
89069
+ import { existsSync as existsSync64, readdirSync as readdirSync12 } from "node:fs";
89070
+ import { join as join141 } from "node:path";
88599
89071
  function scanPlanDir(dir) {
88600
89072
  if (!existsSync64(dir))
88601
89073
  return [];
88602
89074
  try {
88603
- return readdirSync11(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join135(dir, entry.name, "plan.md")).filter(existsSync64);
89075
+ return readdirSync12(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join141(dir, entry.name, "plan.md")).filter(existsSync64);
88604
89076
  } catch {
88605
89077
  return [];
88606
89078
  }
88607
89079
  }
88608
89080
  // src/domains/plan-parser/plan-validator.ts
88609
89081
  var import_gray_matter7 = __toESM(require_gray_matter(), 1);
88610
- import { existsSync as existsSync65, readFileSync as readFileSync25 } from "node:fs";
88611
- import { basename as basename19, dirname as dirname38 } from "node:path";
89082
+ import { existsSync as existsSync65, readFileSync as readFileSync28 } from "node:fs";
89083
+ import { basename as basename20, dirname as dirname38 } from "node:path";
88612
89084
  function validatePlanFile(filePath, strict = false) {
88613
- const content = readFileSync25(filePath, "utf8");
89085
+ const content = readFileSync28(filePath, "utf8");
88614
89086
  const dir = dirname38(filePath);
88615
89087
  const issues = [];
88616
89088
  const lines = content.split(`
@@ -88648,13 +89120,13 @@ function validatePlanFile(filePath, strict = false) {
88648
89120
  }
88649
89121
  for (const phase of phases) {
88650
89122
  if (phase.file && !existsSync65(phase.file)) {
88651
- const fileBasename = basename19(phase.file);
89123
+ const fileBasename = basename20(phase.file);
88652
89124
  const refLine = lines.findIndex((l2) => l2.includes(fileBasename));
88653
89125
  issues.push({
88654
89126
  line: refLine >= 0 ? refLine + 1 : 1,
88655
89127
  severity: "warning",
88656
89128
  code: "missing-phase-file",
88657
- message: `Phase ${phase.phaseId} references '${basename19(phase.file)}' which doesn't exist`
89129
+ message: `Phase ${phase.phaseId} references '${basename20(phase.file)}' which doesn't exist`
88658
89130
  });
88659
89131
  }
88660
89132
  }
@@ -88667,9 +89139,9 @@ function validatePlanFile(filePath, strict = false) {
88667
89139
  }
88668
89140
  // src/domains/plan-parser/plan-writer.ts
88669
89141
  var import_gray_matter8 = __toESM(require_gray_matter(), 1);
88670
- import { mkdirSync as mkdirSync10, readFileSync as readFileSync26, writeFileSync as writeFileSync13 } from "node:fs";
89142
+ import { mkdirSync as mkdirSync10, readFileSync as readFileSync29, writeFileSync as writeFileSync14 } from "node:fs";
88671
89143
  import { existsSync as existsSync66 } from "node:fs";
88672
- import { basename as basename20, dirname as dirname39, join as join136 } from "node:path";
89144
+ import { basename as basename21, dirname as dirname39, join as join142 } from "node:path";
88673
89145
  function phaseNameToFilename(id, name2) {
88674
89146
  const numMatch = /^(\d+)([a-z]*)$/i.exec(id);
88675
89147
  const num4 = numMatch ? numMatch[1] : id;
@@ -88777,13 +89249,13 @@ function scaffoldPlan(options2) {
88777
89249
  mkdirSync10(dir, { recursive: true });
88778
89250
  const resolvedPhases = resolvePhaseIds(options2.phases);
88779
89251
  const optionsWithResolved = { ...options2, phases: resolvedPhases };
88780
- const planFile = join136(dir, "plan.md");
88781
- writeFileSync13(planFile, generatePlanMd(optionsWithResolved), "utf8");
89252
+ const planFile = join142(dir, "plan.md");
89253
+ writeFileSync14(planFile, generatePlanMd(optionsWithResolved), "utf8");
88782
89254
  const phaseFiles = [];
88783
89255
  for (const phase of resolvedPhases) {
88784
89256
  const filename = phaseNameToFilename(phase.id, phase.name);
88785
- const phaseFile = join136(dir, filename);
88786
- writeFileSync13(phaseFile, generatePhaseTemplate(phase), "utf8");
89257
+ const phaseFile = join142(dir, filename);
89258
+ writeFileSync14(phaseFile, generatePhaseTemplate(phase), "utf8");
88787
89259
  phaseFiles.push(phaseFile);
88788
89260
  }
88789
89261
  return { planFile, phaseFiles };
@@ -88807,7 +89279,7 @@ function isCanonicalFormat(content) {
88807
89279
  return /^\|\s*phase\s*\|\s*name\s*\|\s*status\s*\|/im.test(content);
88808
89280
  }
88809
89281
  function updatePhaseStatus(planFile, phaseId, newStatus) {
88810
- const raw = readFileSync26(planFile, "utf8").replace(/\r\n/g, `
89282
+ const raw = readFileSync29(planFile, "utf8").replace(/\r\n/g, `
88811
89283
  `);
88812
89284
  if (!isCanonicalFormat(raw)) {
88813
89285
  console.error("[!] plan.md is not in canonical format — skipping status update");
@@ -88847,7 +89319,7 @@ function updatePhaseStatus(planFile, phaseId, newStatus) {
88847
89319
  }
88848
89320
  const updatedFrontmatter = { ...frontmatter, status: planStatus };
88849
89321
  const updatedContent = import_gray_matter8.default.stringify(updatedBody, updatedFrontmatter);
88850
- writeFileSync13(planFile, updatedContent, "utf8");
89322
+ writeFileSync14(planFile, updatedContent, "utf8");
88851
89323
  const planDir = dirname39(planFile);
88852
89324
  const phaseFilename = phaseNameFilenameFromTableRow(updatedBody, phaseId, planDir);
88853
89325
  if (phaseFilename && existsSync66(phaseFilename)) {
@@ -88862,18 +89334,18 @@ function phaseNameFilenameFromTableRow(body, phaseId, planDir) {
88862
89334
  continue;
88863
89335
  const linkMatch = /\[([^\]]+)\]\(\.\/([^)]+)\)/.exec(row);
88864
89336
  if (linkMatch)
88865
- return join136(planDir, linkMatch[2]);
89337
+ return join142(planDir, linkMatch[2]);
88866
89338
  }
88867
89339
  return null;
88868
89340
  }
88869
89341
  function updatePhaseFileFrontmatter(phaseFile, newStatus) {
88870
- const raw = readFileSync26(phaseFile, "utf8");
89342
+ const raw = readFileSync29(phaseFile, "utf8");
88871
89343
  const { data: frontmatter, content: body } = import_gray_matter8.default(raw);
88872
89344
  const updated = { ...frontmatter, status: newStatus };
88873
- writeFileSync13(phaseFile, import_gray_matter8.default.stringify(body, updated), "utf8");
89345
+ writeFileSync14(phaseFile, import_gray_matter8.default.stringify(body, updated), "utf8");
88874
89346
  }
88875
89347
  function addPhase(planFile, name2, afterId) {
88876
- const raw = readFileSync26(planFile, "utf8").replace(/\r\n/g, `
89348
+ const raw = readFileSync29(planFile, "utf8").replace(/\r\n/g, `
88877
89349
  `);
88878
89350
  if (!isCanonicalFormat(raw)) {
88879
89351
  console.error("[!] plan.md is not in canonical format — cannot add phase");
@@ -88909,7 +89381,7 @@ function addPhase(planFile, name2, afterId) {
88909
89381
  insertIdx = i;
88910
89382
  }
88911
89383
  if (insertIdx === -1) {
88912
- throw new Error(`Phase ID "${afterId}" not found in ${basename20(planFile)}`);
89384
+ throw new Error(`Phase ID "${afterId}" not found in ${basename21(planFile)}`);
88913
89385
  }
88914
89386
  lines.splice(insertIdx + 1, 0, newRow);
88915
89387
  updatedBody = lines.join(`
@@ -88942,9 +89414,9 @@ function addPhase(planFile, name2, afterId) {
88942
89414
  updatedBody = lines.join(`
88943
89415
  `);
88944
89416
  }
88945
- writeFileSync13(planFile, import_gray_matter8.default.stringify(updatedBody, frontmatter), "utf8");
88946
- const phaseFilePath = join136(planDir, filename);
88947
- writeFileSync13(phaseFilePath, generatePhaseTemplate({ id: phaseId, name: name2 }), "utf8");
89417
+ writeFileSync14(planFile, import_gray_matter8.default.stringify(updatedBody, frontmatter), "utf8");
89418
+ const phaseFilePath = join142(planDir, filename);
89419
+ writeFileSync14(phaseFilePath, generatePhaseTemplate({ id: phaseId, name: name2 }), "utf8");
88948
89420
  return { phaseId, phaseFile: phaseFilePath };
88949
89421
  }
88950
89422
 
@@ -88992,7 +89464,7 @@ async function handleParse(target, options2) {
88992
89464
  console.log(JSON.stringify({ file: relative21(process.cwd(), planFile), frontmatter, phases }, null, 2));
88993
89465
  return;
88994
89466
  }
88995
- const title = typeof frontmatter.title === "string" ? frontmatter.title : basename21(dirname41(planFile));
89467
+ const title = typeof frontmatter.title === "string" ? frontmatter.title : basename22(dirname41(planFile));
88996
89468
  console.log();
88997
89469
  console.log(import_picocolors28.default.bold(` Plan: ${title}`));
88998
89470
  console.log(` File: ${planFile}`);
@@ -89047,7 +89519,7 @@ async function handleValidate(target, options2) {
89047
89519
  }
89048
89520
  async function handleStatus(target, options2) {
89049
89521
  const t = target ? resolve33(target) : null;
89050
- const plansDir = t && existsSync67(t) && statSync11(t).isDirectory() && !existsSync67(join137(t, "plan.md")) ? t : null;
89522
+ const plansDir = t && existsSync67(t) && statSync11(t).isDirectory() && !existsSync67(join143(t, "plan.md")) ? t : null;
89051
89523
  if (plansDir) {
89052
89524
  const planFiles = scanPlanDir(plansDir);
89053
89525
  if (planFiles.length === 0) {
@@ -89072,14 +89544,14 @@ async function handleStatus(target, options2) {
89072
89544
  try {
89073
89545
  const s3 = buildPlanSummary(pf);
89074
89546
  const bar = progressBar(s3.completed, s3.totalPhases);
89075
- const title2 = s3.title ?? basename21(dirname41(pf));
89547
+ const title2 = s3.title ?? basename22(dirname41(pf));
89076
89548
  console.log(` ${import_picocolors28.default.bold(title2)}`);
89077
89549
  console.log(` ${bar}`);
89078
89550
  if (s3.inProgress > 0)
89079
89551
  console.log(` [~] ${s3.inProgress} in progress`);
89080
89552
  console.log();
89081
89553
  } catch {
89082
- console.log(` [X] Failed to read: ${basename21(dirname41(pf))}`);
89554
+ console.log(` [X] Failed to read: ${basename22(dirname41(pf))}`);
89083
89555
  console.log();
89084
89556
  }
89085
89557
  }
@@ -89103,7 +89575,7 @@ async function handleStatus(target, options2) {
89103
89575
  console.log(JSON.stringify(summary, null, 2));
89104
89576
  return;
89105
89577
  }
89106
- const title = summary.title ?? basename21(dirname41(planFile));
89578
+ const title = summary.title ?? basename22(dirname41(planFile));
89107
89579
  console.log();
89108
89580
  console.log(import_picocolors28.default.bold(` ${title}`));
89109
89581
  if (summary.status)
@@ -89129,7 +89601,7 @@ async function handleKanban(target, _options) {
89129
89601
  }
89130
89602
 
89131
89603
  // src/commands/plan/plan-write-handlers.ts
89132
- import { basename as basename22, relative as relative22, resolve as resolve34 } from "node:path";
89604
+ import { basename as basename23, relative as relative22, resolve as resolve34 } from "node:path";
89133
89605
  init_output_manager();
89134
89606
  var import_picocolors29 = __toESM(require_picocolors(), 1);
89135
89607
  async function handleCreate(target, options2) {
@@ -89182,7 +89654,7 @@ async function handleCreate(target, options2) {
89182
89654
  console.log(` Directory: ${resolve34(dir)}`);
89183
89655
  console.log(` Phases: ${result.phaseFiles.length}`);
89184
89656
  for (const f4 of result.phaseFiles) {
89185
- console.log(` [ ] ${basename22(f4)}`);
89657
+ console.log(` [ ] ${basename23(f4)}`);
89186
89658
  }
89187
89659
  console.log();
89188
89660
  }
@@ -89282,7 +89754,7 @@ function resolvePlanFile(target) {
89282
89754
  const stat13 = statSync12(t);
89283
89755
  if (stat13.isFile())
89284
89756
  return t;
89285
- const candidate = join138(t, "plan.md");
89757
+ const candidate = join144(t, "plan.md");
89286
89758
  if (existsSync68(candidate))
89287
89759
  return candidate;
89288
89760
  }
@@ -89290,7 +89762,7 @@ function resolvePlanFile(target) {
89290
89762
  let dir = process.cwd();
89291
89763
  const root = parse4(dir).root;
89292
89764
  while (dir !== root) {
89293
- const candidate = join138(dir, "plan.md");
89765
+ const candidate = join144(dir, "plan.md");
89294
89766
  if (existsSync68(candidate))
89295
89767
  return candidate;
89296
89768
  dir = dirname42(dir);
@@ -89380,7 +89852,7 @@ async function planCommand(action, target, options2) {
89380
89852
  }
89381
89853
  // src/commands/statusline/statusline-command.ts
89382
89854
  import { appendFileSync as appendFileSync3 } from "node:fs";
89383
- import { homedir as homedir32 } from "node:os";
89855
+ import { homedir as homedir31 } from "node:os";
89384
89856
  init_cache_dir();
89385
89857
 
89386
89858
  // src/domains/statusline/config-loader.ts
@@ -89491,7 +89963,7 @@ function computeContextPercent(cw) {
89491
89963
 
89492
89964
  // src/domains/statusline/git-cache.ts
89493
89965
  import { createHash as createHash16 } from "node:crypto";
89494
- import { readFileSync as readFileSync27 } from "node:fs";
89966
+ import { readFileSync as readFileSync30 } from "node:fs";
89495
89967
  init_cache_dir();
89496
89968
  var GIT_CACHE_TTL_MS = 30000;
89497
89969
  var MAX_UNTRACKED_FILES = 200;
@@ -89572,7 +90044,7 @@ function untrackedInsertions(cwd2) {
89572
90044
  break;
89573
90045
  let buf;
89574
90046
  try {
89575
- buf = readFileSync27(`${cwd2}/${relative23}`);
90047
+ buf = readFileSync30(`${cwd2}/${relative23}`);
89576
90048
  } catch {
89577
90049
  continue;
89578
90050
  }
@@ -89754,7 +90226,7 @@ function quotaWindows(now = Date.now()) {
89754
90226
  }
89755
90227
 
89756
90228
  // src/domains/statusline/components.ts
89757
- import { homedir as homedir31 } from "node:os";
90229
+ import { homedir as homedir30 } from "node:os";
89758
90230
 
89759
90231
  // src/domains/statusline/colors.ts
89760
90232
  init_help_colors();
@@ -89983,13 +90455,13 @@ function shortenLeadingDirs(path11, keepFull) {
89983
90455
  return path11;
89984
90456
  const leadCount = segments.length - keepFull;
89985
90457
  const shortened = segments.map((seg, i) => i < leadCount ? Array.from(seg)[0] ?? seg : seg);
89986
- const sep10 = marker || leadingSlash ? "/" : "";
89987
- return `${marker}${sep10}${shortened.join("/")}`;
90458
+ const sep11 = marker || leadingSlash ? "/" : "";
90459
+ return `${marker}${sep11}${shortened.join("/")}`;
89988
90460
  }
89989
90461
  function renderDirectory(data, s3) {
89990
90462
  let path11 = data.cwd || process.cwd();
89991
90463
  if (s3.collapseHome) {
89992
- const home6 = homedir31();
90464
+ const home6 = homedir30();
89993
90465
  if (home6 && path11.startsWith(home6))
89994
90466
  path11 = `~${path11.slice(home6.length)}`;
89995
90467
  }
@@ -90076,11 +90548,11 @@ function renderStatusline(data, settings) {
90076
90548
  }
90077
90549
 
90078
90550
  // src/domains/statusline/versions.ts
90079
- import { join as join139 } from "node:path";
90551
+ import { join as join145 } from "node:path";
90080
90552
  async function resolveCoreVersion(cwd2) {
90081
90553
  try {
90082
90554
  const { readManifest: readManifest3 } = await Promise.resolve().then(() => (init_manifest(), exports_manifest));
90083
- const meta = await readManifest3(join139(cwd2, ".claude"));
90555
+ const meta = await readManifest3(join145(cwd2, ".claude"));
90084
90556
  if (!meta)
90085
90557
  return null;
90086
90558
  const kits = meta.kits;
@@ -90106,7 +90578,7 @@ function writeDebug(enabled, context, err) {
90106
90578
  } catch {}
90107
90579
  }
90108
90580
  function collapseHome(p2) {
90109
- const home6 = homedir32();
90581
+ const home6 = homedir31();
90110
90582
  return home6 && p2.startsWith(home6) ? `~${p2.slice(home6.length)}` : p2;
90111
90583
  }
90112
90584
  function fallbackLine(cwd2) {
@@ -90170,24 +90642,24 @@ init_logger();
90170
90642
  init_logger();
90171
90643
 
90172
90644
  // src/commands/telemetry/shared.ts
90173
- import { existsSync as existsSync69, readFileSync as readFileSync28, readdirSync as readdirSync12 } from "node:fs";
90174
- import { homedir as homedir33 } from "node:os";
90175
- import { join as join140 } from "node:path";
90645
+ import { existsSync as existsSync69, readFileSync as readFileSync31, readdirSync as readdirSync13 } from "node:fs";
90646
+ import { homedir as homedir32 } from "node:os";
90647
+ import { join as join146 } from "node:path";
90176
90648
  init_token_store();
90177
90649
  init_manifest_path_resolver();
90178
90650
  init_takumi_constants();
90179
- var USER_CACHE_PATH = join140(homedir33(), ".claude", "sk-user.json");
90180
- var EVENT_BUFFER_DIR = join140(homedir33(), ".claude", "sk-events");
90181
- var RATE_STATE_PATH = join140(homedir33(), ".claude", "sk-rate-state.json");
90182
- var TAKUMI_MANIFEST_PATH = join140(homedir33(), ".claude", MANIFEST_FILENAME);
90183
- var LEGACY_METADATA_PATH = join140(homedir33(), ".claude", LEGACY_MANIFEST_FILENAME);
90651
+ var USER_CACHE_PATH = join146(homedir32(), ".claude", "sk-user.json");
90652
+ var EVENT_BUFFER_DIR = join146(homedir32(), ".claude", "sk-events");
90653
+ var RATE_STATE_PATH = join146(homedir32(), ".claude", "sk-rate-state.json");
90654
+ var TAKUMI_MANIFEST_PATH = join146(homedir32(), ".claude", MANIFEST_FILENAME);
90655
+ var LEGACY_METADATA_PATH = join146(homedir32(), ".claude", LEGACY_MANIFEST_FILENAME);
90184
90656
  var TELEMETRY_HOOK_FIELD = "hooks.telemetry";
90185
90657
  var TOKEN_PLACEHOLDER = "__INJECT_AT_RELEASE__";
90186
90658
  function readUserCache() {
90187
90659
  try {
90188
90660
  if (!existsSync69(USER_CACHE_PATH))
90189
90661
  return null;
90190
- const parsed = JSON.parse(readFileSync28(USER_CACHE_PATH, "utf8"));
90662
+ const parsed = JSON.parse(readFileSync31(USER_CACHE_PATH, "utf8"));
90191
90663
  if (!parsed || typeof parsed !== "object")
90192
90664
  return null;
90193
90665
  return parsed;
@@ -90199,7 +90671,7 @@ function countBufferFiles() {
90199
90671
  try {
90200
90672
  if (!existsSync69(EVENT_BUFFER_DIR))
90201
90673
  return 0;
90202
- return readdirSync12(EVENT_BUFFER_DIR).filter((f4) => f4.endsWith(".jsonl")).length;
90674
+ return readdirSync13(EVENT_BUFFER_DIR).filter((f4) => f4.endsWith(".jsonl")).length;
90203
90675
  } catch {
90204
90676
  return 0;
90205
90677
  }
@@ -90209,9 +90681,9 @@ function readTelemetryConfig() {
90209
90681
  const envToken = process.env.TAKUMI_TELEMETRY_TOKEN;
90210
90682
  let metadata = null;
90211
90683
  try {
90212
- const resolved = findManifestPathSync(join140(homedir33(), ".claude"));
90684
+ const resolved = findManifestPathSync(join146(homedir32(), ".claude"));
90213
90685
  if (resolved) {
90214
- metadata = JSON.parse(readFileSync28(resolved.path, "utf8"));
90686
+ metadata = JSON.parse(readFileSync31(resolved.path, "utf8"));
90215
90687
  }
90216
90688
  } catch {
90217
90689
  metadata = null;
@@ -90386,8 +90858,8 @@ init_logger();
90386
90858
  init_safe_prompts();
90387
90859
  init_safe_spinner();
90388
90860
  var import_fs_extra39 = __toESM(require_lib(), 1);
90389
- import { readdirSync as readdirSync14, rmSync as rmSync11 } from "node:fs";
90390
- import { join as join142, resolve as resolve36, sep as sep10 } from "node:path";
90861
+ import { readdirSync as readdirSync15, rmSync as rmSync12 } from "node:fs";
90862
+ import { join as join148, resolve as resolve36, sep as sep11 } from "node:path";
90391
90863
 
90392
90864
  // src/commands/uninstall/analysis-handler.ts
90393
90865
  init_metadata_migration();
@@ -90397,8 +90869,8 @@ init_logger();
90397
90869
  init_safe_prompts();
90398
90870
  init_takumi_constants();
90399
90871
  var import_picocolors30 = __toESM(require_picocolors(), 1);
90400
- import { existsSync as existsSync70, readdirSync as readdirSync13, rmSync as rmSync10 } from "node:fs";
90401
- import { dirname as dirname43, join as join141 } from "node:path";
90872
+ import { existsSync as existsSync70, readdirSync as readdirSync14, rmSync as rmSync11 } from "node:fs";
90873
+ import { dirname as dirname43, join as join147 } from "node:path";
90402
90874
  function listPresentManifestNames(installPath) {
90403
90875
  const present = [];
90404
90876
  if (existsSync70(getManifestPath(installPath)))
@@ -90424,9 +90896,9 @@ async function cleanupEmptyDirectories3(filePath, installationRoot) {
90424
90896
  let currentDir = dirname43(filePath);
90425
90897
  while (currentDir !== installationRoot && currentDir.startsWith(installationRoot)) {
90426
90898
  try {
90427
- const entries = readdirSync13(currentDir);
90899
+ const entries = readdirSync14(currentDir);
90428
90900
  if (entries.length === 0) {
90429
- rmSync10(currentDir, { recursive: true });
90901
+ rmSync11(currentDir, { recursive: true });
90430
90902
  cleaned++;
90431
90903
  logger.debug(`Removed empty directory: ${currentDir}`);
90432
90904
  currentDir = dirname43(currentDir);
@@ -90451,7 +90923,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
90451
90923
  if (uninstallManifest.isMultiKit && kit && metadata?.kits?.[kit]) {
90452
90924
  const kitFiles = metadata.kits[kit].files || [];
90453
90925
  for (const trackedFile of kitFiles) {
90454
- const filePath = join141(installation.path, trackedFile.path);
90926
+ const filePath = join147(installation.path, trackedFile.path);
90455
90927
  if (uninstallManifest.filesToPreserve.includes(trackedFile.path)) {
90456
90928
  result.toPreserve.push({ path: trackedFile.path, reason: "shared with other kit" });
90457
90929
  continue;
@@ -90483,7 +90955,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
90483
90955
  return result;
90484
90956
  }
90485
90957
  for (const trackedFile of allTrackedFiles) {
90486
- const filePath = join141(installation.path, trackedFile.path);
90958
+ const filePath = join147(installation.path, trackedFile.path);
90487
90959
  const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
90488
90960
  if (!ownershipResult.exists)
90489
90961
  continue;
@@ -90541,7 +91013,7 @@ async function isPathSafeToRemove(filePath, baseDir) {
90541
91013
  try {
90542
91014
  const resolvedPath = resolve36(filePath);
90543
91015
  const resolvedBase = resolve36(baseDir);
90544
- if (!resolvedPath.startsWith(resolvedBase + sep10) && resolvedPath !== resolvedBase) {
91016
+ if (!resolvedPath.startsWith(resolvedBase + sep11) && resolvedPath !== resolvedBase) {
90545
91017
  logger.debug(`Path outside installation directory: ${filePath}`);
90546
91018
  return false;
90547
91019
  }
@@ -90549,7 +91021,7 @@ async function isPathSafeToRemove(filePath, baseDir) {
90549
91021
  if (stats.isSymbolicLink()) {
90550
91022
  const realPath = await import_fs_extra39.realpath(filePath);
90551
91023
  const resolvedReal = resolve36(realPath);
90552
- if (!resolvedReal.startsWith(resolvedBase + sep10) && resolvedReal !== resolvedBase) {
91024
+ if (!resolvedReal.startsWith(resolvedBase + sep11) && resolvedReal !== resolvedBase) {
90553
91025
  logger.debug(`Symlink points outside installation directory: ${filePath} -> ${realPath}`);
90554
91026
  return false;
90555
91027
  }
@@ -90582,7 +91054,7 @@ async function removeInstallations(installations, options2) {
90582
91054
  let removedCount = 0;
90583
91055
  let cleanedDirs = 0;
90584
91056
  for (const item of analysis.toDelete) {
90585
- const filePath = join142(installation.path, item.path);
91057
+ const filePath = join148(installation.path, item.path);
90586
91058
  if (!await import_fs_extra39.pathExists(filePath))
90587
91059
  continue;
90588
91060
  if (!await isPathSafeToRemove(filePath, installation.path)) {
@@ -90601,9 +91073,9 @@ async function removeInstallations(installations, options2) {
90601
91073
  await ManifestWriter.removeKitFromManifest(installation.path, options2.kit);
90602
91074
  }
90603
91075
  try {
90604
- const remaining = readdirSync14(installation.path);
91076
+ const remaining = readdirSync15(installation.path);
90605
91077
  if (remaining.length === 0) {
90606
- rmSync11(installation.path, { recursive: true });
91078
+ rmSync12(installation.path, { recursive: true });
90607
91079
  logger.debug(`Removed empty installation directory: ${installation.path}`);
90608
91080
  }
90609
91081
  } catch {}
@@ -91367,7 +91839,7 @@ function parsePositiveIntFlag(raw, label, example, max) {
91367
91839
  }
91368
91840
  var ARTIFACT_LIST_LIMIT_MAX = 100;
91369
91841
  function registerCommands(cli) {
91370
- cli.command("init", "Initialize or update Takumi project (with interactive version selection)").option("--dir <dir>", "Target directory (default: .)").option("--kit <kit>", "Kit(s) to install (core, extras). Repeat the flag to install multiple kits, e.g. --kit core --kit extras.").option("-r, --release <version>", "Skip version selection, use specific version (e.g., latest, v1.0.0)").option("--exclude <pattern>", "Exclude files matching glob pattern (can be used multiple times)").option("--only <pattern>", "Include only files matching glob pattern (can be used multiple times)").option("--skill-role <role>", "Install only skills tagged with these role(s) (comma-separated or repeatable). Combines with --skill-category as a union.").option("--skill-category <category>", "Install only skills in these categor(y/ies) (comma-separated or repeatable). Combines with --skill-role as a union.").option("-g, --global", "Use platform-specific user configuration directory").option("--fresh", "Full reset: remove takumi files, replace settings.json and CLAUDE.md, reinstall from scratch").option("--force", "Force reinstall even if already at latest version (use with --yes; re-onboards missing files without full reset)").option("--install-skills", "Install skills dependencies (non-interactive mode)").option("--install-hooks", "Install all agent hooks (guard, session, convention, extension). Default installs only telemetry hooks.").option("--with-sudo", "Include system packages requiring sudo (Linux: ffmpeg, imagemagick)").option("--prefix", "Add /tkm: prefix to all slash commands by moving them to commands/tkm/ subdirectory").option("--beta", "Show beta versions in selection prompt").option("--refresh", "Bypass release cache to fetch latest versions from GitHub").option("--dry-run", "Preview changes without applying them (requires --prefix)").option("--force-overwrite", "Override ownership protections and delete user-modified files (requires --prefix)").option("--force-overwrite-settings", "Fully replace settings.json instead of selective merge (destroys user customizations)").option("--docs-dir <name>", "Custom docs folder name (default: docs)").option("--plans-dir <name>", "Custom plans folder name (default: plans)").option("-y, --yes", "Non-interactive mode with sensible defaults (skip all prompts)").option("--sync", "Sync config files from upstream with interactive hunk-by-hunk merge").option("--use-git", "Use git clone instead of GitHub API (uses SSH/HTTPS credentials)").option("--archive <path>", "Use local archive file instead of downloading (zip/tar.gz)").option("--kit-path <path>", "Use local kit directory instead of downloading").option("--local", "Use local monorepo as kit source (auto-detects from CLI location)").option("--use-gh", "Force GitHub release source (bypass the Worker release distribution API; default uses Worker)").option("-a, --agent <agents...>", "Target agents (claude-code, codex). Default: claude-code").action(async (options2) => {
91842
+ cli.command("init", "Initialize or update Takumi project (with interactive version selection)").option("--dir <dir>", "Target directory (default: .)").option("--kit <kit>", "Kit(s) to install (core, extras). Repeat the flag to install multiple kits, e.g. --kit core --kit extras.").option("-r, --release <version>", "Skip version selection, use specific version (e.g., latest, v1.0.0)").option("--exclude <pattern>", "Exclude files matching glob pattern (can be used multiple times)").option("--only <pattern>", "Include only files matching glob pattern (can be used multiple times)").option("--skill-role <role>", "Install only skills tagged with these role(s) (comma-separated or repeatable). Combines with --skill-category as a union.").option("--skill-category <category>", "Install only skills in these categor(y/ies) (comma-separated or repeatable). Combines with --skill-role as a union.").option("-g, --global", "Use platform-specific user configuration directory").option("--fresh", "Full reset: remove takumi files, replace settings.json and CLAUDE.md, reinstall from scratch").option("--force", "Force reinstall even if already at latest version (use with --yes; re-onboards missing files without full reset)").option("--install-skills", "Install skills dependencies (non-interactive mode)").option("--install-hooks", "(deprecated: no-op) The full hook set (guard, session, convention, extension, metrics, perf) installs by default.").option("--with-sudo", "Include system packages requiring sudo (Linux: ffmpeg, imagemagick)").option("--prefix", "Add /tkm: prefix to all slash commands by moving them to commands/tkm/ subdirectory").option("--beta", "Show beta versions in selection prompt").option("--refresh", "Bypass release cache to fetch latest versions from GitHub").option("--dry-run", "Preview changes without applying them (requires --prefix)").option("--force-overwrite", "Override ownership protections and delete user-modified files (requires --prefix)").option("--force-overwrite-settings", "Fully replace settings.json instead of selective merge (destroys user customizations)").option("--docs-dir <name>", "Custom docs folder name (default: docs)").option("--plans-dir <name>", "Custom plans folder name (default: plans)").option("-y, --yes", "Non-interactive mode with sensible defaults (skip all prompts)").option("--sync", "Sync config files from upstream with interactive hunk-by-hunk merge").option("--use-git", "Use git clone instead of GitHub API (uses SSH/HTTPS credentials)").option("--archive <path>", "Use local archive file instead of downloading (zip/tar.gz)").option("--kit-path <path>", "Use local kit directory instead of downloading").option("--local", "Use local monorepo as kit source (auto-detects from CLI location)").option("--use-gh", "Force GitHub release source (bypass the Worker release distribution API; default uses Worker)").option("-a, --agent <agents...>", "Target agents (claude-code, codex). Default: claude-code").action(async (options2) => {
91371
91843
  if (options2.exclude && !Array.isArray(options2.exclude)) {
91372
91844
  options2.exclude = [options2.exclude];
91373
91845
  }
@@ -91439,7 +91911,7 @@ function registerCommands(cli) {
91439
91911
  cli.command("telemetry [action]", "Inspect or control Takumi telemetry").option("--json", "Output in JSON format (status)").action(async (action, options2) => {
91440
91912
  await telemetryCommand(action, options2);
91441
91913
  });
91442
- cli.command("hooks [event]", "Manage Takumi hook entries in agent settings (install|uninstall)").option("-a, --agent <agent>", "Target agent: claude or codex").option("-g, --global", "Use the user-level settings file instead of project-local").option("--dry-run", "Preview the diff without writing").option("-y, --yes", "Auto-approve diff prompts and create missing settings files").option("--bin <command>", "Override the leading binary in generated hook commands").option("--no-detach", "Force inline PUT; default behavior spawns a detached child for the network call").option("--debug", "Mirror hook logs into <sessionDir>/detach-debug.log for inspection").option("--job <data>", "Internal: base64 job payload for fork-detached PUT").action(async (event, options2 = {}) => {
91914
+ cli.command("hooks [event]", "Manage Takumi hook entries in agent settings (install|uninstall)").option("-a, --agent <agent>", "Target agent: claude or codex").option("-g, --global", "Use the user-level settings file instead of project-local").option("--dry-run", "Preview the diff without writing").option("-y, --yes", "Auto-approve diff prompts and create missing settings files").option("--bin <command>", "Override the leading binary in generated hook commands").option("--no-detach", "Force inline PUT; default behavior spawns a detached child for the network call").option("--debug", "Mirror hook logs into <sessionDir>/detach-debug.log for inspection").option("--job <data>", "Internal: base64 job payload for fork-detached PUT").option("--dir <path>", "Internal: hooks dir for the scan-meta eval-hook scan").option("--out <path>", "Internal: out-of-band result file for scan-meta").action(async (event, options2 = {}) => {
91443
91915
  const agent = options2.agent === "claude" || options2.agent === "codex" ? options2.agent : undefined;
91444
91916
  const noDetach = options2.detach === false;
91445
91917
  await hooksCommand(event, {
@@ -91449,13 +91921,18 @@ function registerCommands(cli) {
91449
91921
  yes: options2.yes,
91450
91922
  bin: options2.bin,
91451
91923
  noDetach,
91452
- debug: options2.debug
91924
+ debug: options2.debug,
91925
+ dir: options2.dir,
91926
+ out: options2.out
91453
91927
  });
91454
91928
  });
91455
- cli.command("hook-exec", "Run a Takumi hook handler for the piped stdin event (agent-invoked)").option("--hook <selector>", "Handler selector: <category>.<name> or <category>.* (wildcard)").option("--event <event>", "Fallback hook event (kebab-case); stdin hook_event_name wins").option("-a, --agent <agent>", "Target agent: claude or codex").option("--no-detach", "Force inline PUT instead of spawning a detached child").option("--debug", "Mirror hook logs into <sessionDir>/detach-debug.log").action(async (options2 = {}) => {
91929
+ cli.command("hook-exec", "Run a Takumi hook handler for the piped stdin event (agent-invoked)").option("--hook <selector>", "Handler selector: <category>.<name> or <category>.* (wildcard)").option("--eval <relpath>", "Run a kit JS hook file in-process (relative to the scope's hooks dir)").option("-g, --global", "Scope for --eval resolution: the global hooks dir").option("--project", "Scope for --eval resolution: the project hooks dir (default)").option("--plugin", "Scope for --eval resolution: the plugin hooks dir").option("--event <event>", "Fallback hook event (kebab-case); stdin hook_event_name wins").option("-a, --agent <agent>", "Target agent: claude or codex").option("--no-detach", "Force inline PUT instead of spawning a detached child").option("--debug", "Mirror hook logs into <sessionDir>/detach-debug.log").action(async (options2 = {}) => {
91456
91930
  const agent = options2.agent === "claude" || options2.agent === "codex" ? options2.agent : undefined;
91931
+ const scope = options2.global ? "global" : options2.plugin ? "plugin" : options2.project ? "project" : undefined;
91457
91932
  await hookExecCommand({
91458
91933
  hook: options2.hook,
91934
+ eval: options2.eval,
91935
+ scope,
91459
91936
  event: options2.event,
91460
91937
  agent,
91461
91938
  noDetach: options2.detach === false,
@@ -91522,8 +91999,8 @@ init_version_checker();
91522
91999
  init_manifest_path_resolver();
91523
92000
  init_logger();
91524
92001
  init_types2();
91525
- import { readFileSync as readFileSync29 } from "node:fs";
91526
- import { join as join143 } from "node:path";
92002
+ import { readFileSync as readFileSync32 } from "node:fs";
92003
+ import { join as join149 } from "node:path";
91527
92004
  var PROVIDER_LOCAL_SUBDIRS = {
91528
92005
  "claude-code": ".claude",
91529
92006
  codex: ".codex"
@@ -91578,7 +92055,7 @@ async function displayVersion() {
91578
92055
  const localSubdir = PROVIDER_LOCAL_SUBDIRS[provider];
91579
92056
  if (!localSubdir)
91580
92057
  continue;
91581
- const localRoot = join143(process.cwd(), localSubdir);
92058
+ const localRoot = join149(process.cwd(), localSubdir);
91582
92059
  if (localRoot === inst.globalRoot())
91583
92060
  continue;
91584
92061
  const resolved = findManifestPathSync(localRoot);
@@ -91588,7 +92065,7 @@ async function displayVersion() {
91588
92065
  }
91589
92066
  for (const { provider, path: metaPath } of localChecks) {
91590
92067
  try {
91591
- const rawMetadata = JSON.parse(readFileSync29(metaPath, "utf-8"));
92068
+ const rawMetadata = JSON.parse(readFileSync32(metaPath, "utf-8"));
91592
92069
  const metadata = MetadataSchema.parse(rawMetadata);
91593
92070
  const kitsDisplay = formatInstalledKits(metadata);
91594
92071
  if (kitsDisplay) {
@@ -91608,7 +92085,7 @@ async function displayVersion() {
91608
92085
  const resolved = findManifestPathSync(installPath);
91609
92086
  if (resolved) {
91610
92087
  try {
91611
- const rawMetadata = JSON.parse(readFileSync29(resolved.path, "utf-8"));
92088
+ const rawMetadata = JSON.parse(readFileSync32(resolved.path, "utf-8"));
91612
92089
  const metadata = MetadataSchema.parse(rawMetadata);
91613
92090
  const kitsDisplay = formatInstalledKits(metadata);
91614
92091
  if (kitsDisplay) {
@@ -91990,7 +92467,7 @@ var output2 = new OutputManager2;
91990
92467
  // src/shared/temp-cleanup.ts
91991
92468
  init_logger();
91992
92469
  var import_fs_extra41 = __toESM(require_lib(), 1);
91993
- import { rmSync as rmSync12 } from "node:fs";
92470
+ import { rmSync as rmSync13 } from "node:fs";
91994
92471
  var tempDirs2 = new Set;
91995
92472
  async function cleanup() {
91996
92473
  if (tempDirs2.size === 0)
@@ -92011,7 +92488,7 @@ function cleanupSync() {
92011
92488
  return;
92012
92489
  for (const dir of tempDirs2) {
92013
92490
  try {
92014
- rmSync12(dir, { recursive: true, force: true });
92491
+ rmSync13(dir, { recursive: true, force: true });
92015
92492
  } catch {}
92016
92493
  }
92017
92494
  tempDirs2.clear();