navori 0.2.2 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { defineCommand as defineCommand16, runMain } from "citty";
5
- import { readFileSync as readFileSync21 } from "fs";
6
- import { dirname as dirname9, resolve as resolve24 } from "path";
5
+ import { readFileSync as readFileSync22 } from "fs";
6
+ import { dirname as dirname10, resolve as resolve24 } from "path";
7
7
  import { fileURLToPath as fileURLToPath2 } from "url";
8
8
 
9
9
  // src/commands/init.ts
10
10
  import { defineCommand as defineCommand2 } from "citty";
11
11
  import * as p2 from "@clack/prompts";
12
- import { resolve as resolve11, join as join11, dirname as dirname6, relative as relative3 } from "path";
13
- import { existsSync as existsSync15, mkdirSync as mkdirSync5, chmodSync as chmodSync2 } from "fs";
12
+ import { resolve as resolve11, join as join12, dirname as dirname7, relative as relative3 } from "path";
13
+ import { existsSync as existsSync16, mkdirSync as mkdirSync6, chmodSync as chmodSync2 } from "fs";
14
14
  import { spawnSync as spawnSync2 } from "child_process";
15
15
 
16
16
  // src/lib/config.ts
@@ -946,7 +946,9 @@ function pickPresetCandidate(stack, monorepo) {
946
946
  if (fw === "fastify") return "fastify";
947
947
  if (fw === "hono") return "hono";
948
948
  if (fw === "elysia") return "elysia";
949
- if (stack.worker && (fw === "express" || fw === null)) return "background-worker";
949
+ const usesMongoose = stack.deps.includes("mongoose");
950
+ if (stack.worker && fw === "express" && !usesMongoose) return "background-worker";
951
+ if (stack.worker && fw === null) return "background-worker";
950
952
  if (fw === "express") return "express-mongoose";
951
953
  return "custom";
952
954
  }
@@ -1372,7 +1374,7 @@ function writeWorkspace(workspace) {
1372
1374
  // src/commands/render.ts
1373
1375
  import { defineCommand } from "citty";
1374
1376
  import * as p from "@clack/prompts";
1375
- import { existsSync as existsSync12 } from "fs";
1377
+ import { existsSync as existsSync13 } from "fs";
1376
1378
  import { resolve as resolve9 } from "path";
1377
1379
 
1378
1380
  // src/engines/claude/index.ts
@@ -1675,6 +1677,7 @@ function placeholderFallback(path) {
1675
1677
  // src/lib/render-plan.ts
1676
1678
  var CORE_SOURCE_ID = "@navori/core";
1677
1679
  var CORE_MANAGED_ASSETS = [
1680
+ { id: "orquestacion", relPath: "core-assets/managed/orquestacion.md", availableLanguages: ["es"] },
1678
1681
  { id: "idioma-rol", relPath: "core-assets/managed/idioma-rol.md", availableLanguages: ["es"] },
1679
1682
  { id: "formato-respuesta", relPath: "core-assets/managed/formato-respuesta.md", availableLanguages: ["es"] },
1680
1683
  { id: "tipado-fuerte", relPath: "core-assets/managed/tipado-fuerte.md", availableLanguages: ["es"], condition: "project.typedLanguage" },
@@ -2337,6 +2340,34 @@ function buildSkillsIndexBody(config, localSkills, repoRoot) {
2337
2340
  ""
2338
2341
  ].join("\n");
2339
2342
  }
2343
+ var AGENTS_INDEX_ID = "agentes-disponibles";
2344
+ var AGENT_WHEN = {
2345
+ implementer: "Escribe c\xF3digo y tests de UNA tarea acotada con scope claro.",
2346
+ reviewer: "Valida un diff contra spec y calidad antes de cerrar (APPROVED / CHANGES_REQUESTED).",
2347
+ researcher: "Responde una pregunta concreta del repo (\xBFpasa Y? \xBFqu\xE9 consume X?) con evidencia citada.",
2348
+ explorer: "Mapea un \xE1rea o m\xF3dulo amplio: estructura, entry points, dependencias.",
2349
+ "ticket-audit": "Analiza a fondo un ticket complejo (bug cr\xEDtico, migraci\xF3n, feature multi-capa) antes de descomponer.",
2350
+ "commit-pr-pilot": "Redacta commits Conventional y abre el PR tras la aprobaci\xF3n del reviewer."
2351
+ };
2352
+ function buildAgentsIndexBody(config) {
2353
+ const rows = [];
2354
+ for (const agent of CORE_AGENTS) {
2355
+ if (agent.id === "leader") continue;
2356
+ if (!isAgentEnabled(config, agent.harnessKey)) continue;
2357
+ const when = AGENT_WHEN[agent.id];
2358
+ if (!when) continue;
2359
+ rows.push(`- \`${agent.id}\` \u2014 ${when}`);
2360
+ }
2361
+ if (rows.length === 0) return null;
2362
+ return [
2363
+ "## Agentes disponibles",
2364
+ "",
2365
+ 'Subagentes que puedes lanzar v\xEDa la tool `Agent` (t\xFA eres el orquestador; ver "## Rol: orquestador"). Investigaci\xF3n y review son read-only \u2192 paralel\xEDzalos sin miedo.',
2366
+ "",
2367
+ ...rows,
2368
+ ""
2369
+ ].join("\n");
2370
+ }
2340
2371
  var CONTEXTO_PROYECTO_ID = "contexto-proyecto";
2341
2372
  function buildContextoProyectoBody(config) {
2342
2373
  const proj = config.project ?? {};
@@ -2420,6 +2451,26 @@ function renderClaudeEngine(cwd, inputConfig, options = {}) {
2420
2451
  } else {
2421
2452
  claudeMdContent = removeManagedSection(claudeMdContent, SKILLS_INDEX_ID);
2422
2453
  }
2454
+ const agentsIndexBody = buildAgentsIndexBody(config);
2455
+ if (agentsIndexBody !== null) {
2456
+ const result = injectManagedSection(
2457
+ claudeMdContent,
2458
+ AGENTS_INDEX_ID,
2459
+ agentsIndexBody,
2460
+ CORE_META,
2461
+ "html",
2462
+ options.forceIds?.has(AGENTS_INDEX_ID) ?? false
2463
+ );
2464
+ claudeMdContent = result.output;
2465
+ claudeMdPlan.entries.push({
2466
+ asset: { id: AGENTS_INDEX_ID, relPath: "(computed)" },
2467
+ source: "core",
2468
+ status: result.status,
2469
+ newContent: null
2470
+ });
2471
+ } else {
2472
+ claudeMdContent = removeManagedSection(claudeMdContent, AGENTS_INDEX_ID);
2473
+ }
2423
2474
  const contextoBody = buildContextoProyectoBody(config);
2424
2475
  if (contextoBody !== null) {
2425
2476
  const result = injectManagedSection(
@@ -2844,6 +2895,96 @@ function planPluginScript(cwd, script, config) {
2844
2895
  };
2845
2896
  }
2846
2897
 
2898
+ // src/engines/agents-md/index.ts
2899
+ import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync12 } from "fs";
2900
+ import { basename as basename4, dirname as dirname6, join as join10 } from "path";
2901
+ var MANAGED_ID = "navori-agents";
2902
+ var CORE_META2 = { source: "@navori/core", version: readBundledCoreVersion() };
2903
+ var CORE_SKILLS2 = ["verify-before-done", "loop-back-debug", "review-diff"];
2904
+ var HEADER = "# AGENTS.md\n";
2905
+ var USER_SECTION = "\n<!-- navori:user-section -->\n## Reglas del repo (tuyas)\n\n<!-- Agrega ac\xE1 lo espec\xEDfico de tu repo; navori no toca esta secci\xF3n. -->\n";
2906
+ function buildSkillsSection(config, repoRoot) {
2907
+ const rows = [];
2908
+ const listed = /* @__PURE__ */ new Set();
2909
+ for (const id of CORE_SKILLS2) {
2910
+ rows.push(`- \`${id}\` \u2014 navori`);
2911
+ listed.add(id);
2912
+ }
2913
+ if (config.preset && config.preset !== "custom") {
2914
+ try {
2915
+ const loaded = loadPreset(config.preset, repoRoot);
2916
+ for (const e of loaded?.def.extras.skills ?? []) {
2917
+ if (e.condition) continue;
2918
+ const name = basename4(e.destRelPath).replace(/\.md$/, "");
2919
+ if (listed.has(name)) continue;
2920
+ rows.push(`- \`${name}\` \u2014 preset (\`${config.preset}\`)`);
2921
+ listed.add(name);
2922
+ }
2923
+ } catch {
2924
+ }
2925
+ }
2926
+ for (const id of config.project?.libraries ?? []) {
2927
+ if (listed.has(id) || !librarySkillById(id)) continue;
2928
+ rows.push(`- \`${id}\` \u2014 library (detected)`);
2929
+ listed.add(id);
2930
+ }
2931
+ if (rows.length === 0) return null;
2932
+ return ["## Skills disponibles", "", ...rows, ""].join("\n");
2933
+ }
2934
+ function buildWorkflowSection() {
2935
+ return [
2936
+ "## Flujo de trabajo",
2937
+ "",
2938
+ "- Para tareas no triviales: an\xE1lisis \u2192 plan \u2192 implementaci\xF3n. De una en una.",
2939
+ "- Antes de codear: \xBFes lo m\xE1s simple? \xBFlegible en 6 meses? \xBFmantiene el patr\xF3n existente?",
2940
+ "- Busca con herramientas read-only (no leas el repo entero); cita `archivo:l\xEDnea`.",
2941
+ "- Cierra con el quality gate del proyecto en verde antes de dar por terminado.",
2942
+ ""
2943
+ ].join("\n");
2944
+ }
2945
+ function buildManagedBody(config, repoRoot) {
2946
+ const plan = computeRenderPlan("", config, repoRoot);
2947
+ const ruleBlocks = plan.entries.filter(
2948
+ (e) => e.newContent != null && e.status !== "removed-condition-false" && e.asset.id !== "orquestacion" && (e.source === "core" || e.source === config.preset)
2949
+ ).map((e) => e.newContent.trim());
2950
+ const skills = buildSkillsSection(config, repoRoot);
2951
+ const sections = [
2952
+ "> Contexto del proyecto generado por navori. Lo leen Cursor, Codex, Gemini y Copilot.",
2953
+ ...ruleBlocks,
2954
+ ...skills ? [skills] : [],
2955
+ buildWorkflowSection()
2956
+ ];
2957
+ return sections.join("\n\n").trim() + "\n";
2958
+ }
2959
+ function renderAgentsMdEngine(cwd, inputConfig, options = {}) {
2960
+ const config = effectiveConfig(inputConfig);
2961
+ const repoRoot = options.repoRoot ?? cwd;
2962
+ const agentsMdPath = join10(cwd, "AGENTS.md");
2963
+ const firstRender = !existsSync12(agentsMdPath);
2964
+ const existing = firstRender ? HEADER : readFileSync12(agentsMdPath, "utf-8");
2965
+ const body = buildManagedBody(config, repoRoot);
2966
+ const result = injectManagedSection(existing, MANAGED_ID, body, CORE_META2, "html");
2967
+ const output = firstRender ? result.output + USER_SECTION : result.output;
2968
+ const written = [];
2969
+ const skipped = [];
2970
+ let backupPath = null;
2971
+ if (result.status === "user-modified-skipped") {
2972
+ skipped.push({ path: "AGENTS.md", reason: "managed block edited by hand" });
2973
+ } else if (result.status === "unchanged") {
2974
+ } else {
2975
+ written.push({ path: "AGENTS.md", status: result.status });
2976
+ if (!options.dryRun) {
2977
+ if (!firstRender) {
2978
+ const handle = createBackup(cwd, ["AGENTS.md"]);
2979
+ if (handle.files.length > 0) backupPath = handle.path;
2980
+ }
2981
+ mkdirSync5(dirname6(agentsMdPath), { recursive: true });
2982
+ writeFileAtomic(agentsMdPath, output);
2983
+ }
2984
+ }
2985
+ return { written, skipped, warnings: [], backupPath };
2986
+ }
2987
+
2847
2988
  // src/lib/style.ts
2848
2989
  import pc from "picocolors";
2849
2990
  var color = pc;
@@ -2921,6 +3062,25 @@ function effectiveConfigForWorkspace(root, workspace) {
2921
3062
  }
2922
3063
 
2923
3064
  // src/commands/render.ts
3065
+ function renderNonClaudeEngines(cwd, config, engines, dryRun) {
3066
+ const out = [];
3067
+ for (const eng of engines) {
3068
+ if (eng === "claude") continue;
3069
+ if (eng === "agents-md") {
3070
+ const r = renderAgentsMdEngine(cwd, config, { dryRun, repoRoot: cwd });
3071
+ out.push({ engine: eng, ...r });
3072
+ } else {
3073
+ out.push({
3074
+ engine: eng,
3075
+ written: [],
3076
+ skipped: [],
3077
+ warnings: [`El engine '${eng}' todav\xEDa no tiene adapter en navori; se omiti\xF3.`],
3078
+ backupPath: null
3079
+ });
3080
+ }
3081
+ }
3082
+ return out;
3083
+ }
2924
3084
  function runRender(cwd, dryRunOrOptions = false, force = false) {
2925
3085
  const opts = typeof dryRunOrOptions === "boolean" ? { dryRun: dryRunOrOptions, force } : dryRunOrOptions;
2926
3086
  const dryRun = Boolean(opts.dryRun);
@@ -2928,7 +3088,7 @@ function runRender(cwd, dryRunOrOptions = false, force = false) {
2928
3088
  const workspaceFilter = opts.workspaceFilter ?? null;
2929
3089
  const configPath = `${cwd}/navori.config.json`;
2930
3090
  const claudeMdPath = `${cwd}/CLAUDE.md`;
2931
- if (!existsSync12(configPath)) {
3091
+ if (!existsSync13(configPath)) {
2932
3092
  return {
2933
3093
  ok: false,
2934
3094
  reason: `No navori.config.json at ${configPath}`,
@@ -3004,38 +3164,44 @@ function runRender(cwd, dryRunOrOptions = false, force = false) {
3004
3164
  ]
3005
3165
  };
3006
3166
  }
3007
- const engineResult = renderClaudeEngine(cwd, config, { dryRun, force: forceFlag });
3167
+ const engines = config.engines ?? ["claude"];
3168
+ const renderClaude = engines.includes("claude");
3169
+ const engineResult = renderClaude ? renderClaudeEngine(cwd, config, { dryRun, force: forceFlag }) : void 0;
3008
3170
  const workspaces = [];
3009
- for (const ws of config.monorepo?.workspaces ?? []) {
3010
- const wsCwd = resolve9(cwd, ws.path);
3011
- const wsConfig = effectiveConfigForWorkspace(config, ws);
3012
- const wsResult = renderClaudeEngine(wsCwd, wsConfig, {
3013
- dryRun,
3014
- force: forceFlag,
3015
- repoRoot: cwd
3016
- });
3017
- workspaces.push({
3018
- workspacePath: ws.path,
3019
- workspaceName: ws.name,
3020
- filePath: `${wsCwd}/CLAUDE.md`,
3021
- entries: wsResult.claudeMdEntries,
3022
- written: wsResult.written.length > 0,
3023
- languageFallbacks: wsResult.languageFallbacks,
3024
- updatesAvailable: wsResult.updatesAvailable,
3025
- backupPath: wsResult.backupPath,
3026
- engineResult: wsResult
3027
- });
3171
+ if (renderClaude) {
3172
+ for (const ws of config.monorepo?.workspaces ?? []) {
3173
+ const wsCwd = resolve9(cwd, ws.path);
3174
+ const wsConfig = effectiveConfigForWorkspace(config, ws);
3175
+ const wsResult = renderClaudeEngine(wsCwd, wsConfig, {
3176
+ dryRun,
3177
+ force: forceFlag,
3178
+ repoRoot: cwd
3179
+ });
3180
+ workspaces.push({
3181
+ workspacePath: ws.path,
3182
+ workspaceName: ws.name,
3183
+ filePath: `${wsCwd}/CLAUDE.md`,
3184
+ entries: wsResult.claudeMdEntries,
3185
+ written: wsResult.written.length > 0,
3186
+ languageFallbacks: wsResult.languageFallbacks,
3187
+ updatesAvailable: wsResult.updatesAvailable,
3188
+ backupPath: wsResult.backupPath,
3189
+ engineResult: wsResult
3190
+ });
3191
+ }
3028
3192
  }
3193
+ const extraEngines = renderNonClaudeEngines(cwd, config, engines, dryRun);
3029
3194
  return {
3030
3195
  ok: true,
3031
3196
  filePath: claudeMdPath,
3032
- entries: engineResult.claudeMdEntries,
3033
- written: engineResult.written.length > 0,
3034
- languageFallbacks: engineResult.languageFallbacks,
3035
- updatesAvailable: engineResult.updatesAvailable,
3036
- backupPath: engineResult.backupPath,
3197
+ entries: engineResult?.claudeMdEntries ?? [],
3198
+ written: (engineResult?.written.length ?? 0) > 0,
3199
+ languageFallbacks: engineResult?.languageFallbacks ?? [],
3200
+ updatesAvailable: engineResult?.updatesAvailable ?? [],
3201
+ backupPath: engineResult?.backupPath ?? null,
3037
3202
  engineResult,
3038
- workspaces
3203
+ workspaces,
3204
+ extraEngines
3039
3205
  };
3040
3206
  }
3041
3207
  var renderCommand = defineCommand({
@@ -3066,7 +3232,7 @@ var renderCommand = defineCommand({
3066
3232
  benchStart();
3067
3233
  const cwd = resolve9(args.cwd ?? process.cwd());
3068
3234
  p.intro(brand("render"));
3069
- if (!existsSync12(cwd)) {
3235
+ if (!existsSync13(cwd)) {
3070
3236
  p.cancel(`Directory not found: ${cwd}`);
3071
3237
  process.exit(1);
3072
3238
  }
@@ -3111,8 +3277,17 @@ var renderCommand = defineCommand({
3111
3277
  p.log.message(`${dim("Backup:")} ${ws.backupPath}`);
3112
3278
  }
3113
3279
  }
3280
+ for (const ee of result.extraEngines ?? []) {
3281
+ p.log.message(`${dim("engine")} ${color.cyan(ee.engine)}`);
3282
+ for (const w of ee.written) {
3283
+ p.log.message(` ${renderStatusSymbol(w.status)} ${w.path} ${dim("(")}${renderStatusLabel(w.status)}${dim(")")}`);
3284
+ }
3285
+ for (const s of ee.skipped) p.log.warn(` ${s.path}: ${s.reason}`);
3286
+ for (const warn of ee.warnings) p.log.warn(` ${warn}`);
3287
+ if (ee.backupPath) p.log.message(` ${dim("Backup:")} ${ee.backupPath}`);
3288
+ }
3114
3289
  const allEntries = result.entries.concat(...result.workspaces.map((w) => w.entries));
3115
- const anyPending = result.written || result.workspaces.some((w) => w.written);
3290
+ const anyPending = result.written || result.workspaces.some((w) => w.written) || (result.extraEngines ?? []).some((e) => e.written.length > 0);
3116
3291
  const summary = summarize(allEntries);
3117
3292
  if (preview) {
3118
3293
  if (anyPending) {
@@ -3478,7 +3653,7 @@ function formatWorkspaceSummary(ws, lang = "es") {
3478
3653
  }
3479
3654
 
3480
3655
  // src/engines/claude/prompts-loader.ts
3481
- import { readFileSync as readFileSync12, existsSync as existsSync13 } from "fs";
3656
+ import { readFileSync as readFileSync13, existsSync as existsSync14 } from "fs";
3482
3657
  import { resolve as resolve10 } from "path";
3483
3658
  import { z as z7 } from "zod";
3484
3659
  var SelectOptionSchema = z7.object({
@@ -3518,10 +3693,10 @@ function loadPrompts(enabledPlugins) {
3518
3693
  }
3519
3694
  function loadCorePrompts(warnings) {
3520
3695
  const path = resolve10(getCoreRoot(), CORE_PROMPTS_REL);
3521
- if (!existsSync13(path)) return [];
3696
+ if (!existsSync14(path)) return [];
3522
3697
  let parsed;
3523
3698
  try {
3524
- parsed = JSON.parse(readFileSync12(path, "utf-8"));
3699
+ parsed = JSON.parse(readFileSync13(path, "utf-8"));
3525
3700
  } catch (err) {
3526
3701
  warnings.push(`core prompts.json no parsea: ${err.message}`);
3527
3702
  return [];
@@ -3535,8 +3710,8 @@ function loadCorePrompts(warnings) {
3535
3710
  }
3536
3711
 
3537
3712
  // src/lib/scan.ts
3538
- import { existsSync as existsSync14, readdirSync as readdirSync6 } from "fs";
3539
- import { join as join10 } from "path";
3713
+ import { existsSync as existsSync15, readdirSync as readdirSync6 } from "fs";
3714
+ import { join as join11 } from "path";
3540
3715
  function scanMonorepoWorkspaces(cwd) {
3541
3716
  const patterns = collectWorkspacePatterns(cwd);
3542
3717
  if (patterns.length === 0) return [];
@@ -3563,9 +3738,9 @@ function walk(cwd, accum, remaining) {
3563
3738
  }
3564
3739
  const [head, ...tail] = remaining;
3565
3740
  const currentRel = accum.join("/");
3566
- const currentAbs = currentRel ? join10(cwd, currentRel) : cwd;
3741
+ const currentAbs = currentRel ? join11(cwd, currentRel) : cwd;
3567
3742
  if (head === "*") {
3568
- if (!existsSync14(currentAbs)) return [];
3743
+ if (!existsSync15(currentAbs)) return [];
3569
3744
  let entries;
3570
3745
  try {
3571
3746
  entries = readdirSync6(currentAbs, { withFileTypes: true });
@@ -3574,8 +3749,8 @@ function walk(cwd, accum, remaining) {
3574
3749
  }
3575
3750
  return entries.filter((d) => d.isDirectory() && !d.name.startsWith(".")).flatMap((d) => walk(cwd, [...accum, d.name], tail));
3576
3751
  }
3577
- const next = join10(currentAbs, head);
3578
- if (!existsSync14(next)) return [];
3752
+ const next = join11(currentAbs, head);
3753
+ if (!existsSync15(next)) return [];
3579
3754
  return walk(cwd, [...accum, head], tail);
3580
3755
  }
3581
3756
  function diffWorkspaces(detected, configured) {
@@ -3587,8 +3762,8 @@ function diffWorkspaces(detected, configured) {
3587
3762
  return { added, existing, orphan };
3588
3763
  }
3589
3764
  function describeWorkspace(cwd, relPath) {
3590
- const abs = join10(cwd, relPath);
3591
- if (!existsSync14(join10(abs, "package.json"))) return null;
3765
+ const abs = join11(cwd, relPath);
3766
+ if (!existsSync15(join11(abs, "package.json"))) return null;
3592
3767
  const project = detectProject(abs);
3593
3768
  return {
3594
3769
  name: project.name ?? relPath.split("/").pop(),
@@ -3669,11 +3844,11 @@ var initCommand = defineCommand2({
3669
3844
  p2.intro(brand("init"));
3670
3845
  const bootstrapLang = normalizeLang(args.lang) ?? "es";
3671
3846
  const bootstrapT = t(bootstrapLang);
3672
- if (!existsSync15(cwd)) {
3847
+ if (!existsSync16(cwd)) {
3673
3848
  p2.cancel(bootstrapT.dirNotFound(cwd));
3674
3849
  process.exit(1);
3675
3850
  }
3676
- if (existsSync15(configPath)) {
3851
+ if (existsSync16(configPath)) {
3677
3852
  p2.cancel(bootstrapT.configExists(configPath));
3678
3853
  process.exit(1);
3679
3854
  }
@@ -4287,7 +4462,7 @@ ${lines}${more}`);
4287
4462
  }
4288
4463
  }
4289
4464
  async function offerPreCommitHook(cwd, opts) {
4290
- if (!existsSync15(join11(cwd, ".git"))) return;
4465
+ if (!existsSync16(join12(cwd, ".git"))) return;
4291
4466
  let wanted = opts.force;
4292
4467
  if (!wanted && !opts.autoYes) {
4293
4468
  const answer = await p2.confirm({
@@ -4306,10 +4481,10 @@ async function offerPreCommitHook(cwd, opts) {
4306
4481
  }
4307
4482
  }
4308
4483
  function writePreCommitHook(cwd) {
4309
- const huskyDir = join11(cwd, ".husky");
4310
- const hookPath = existsSync15(huskyDir) ? join11(huskyDir, "pre-commit") : join11(cwd, ".git", "hooks", "pre-commit");
4484
+ const huskyDir = join12(cwd, ".husky");
4485
+ const hookPath = existsSync16(huskyDir) ? join12(huskyDir, "pre-commit") : join12(cwd, ".git", "hooks", "pre-commit");
4311
4486
  const relPath = relative3(cwd, hookPath);
4312
- if (existsSync15(hookPath)) return { ok: false, path: relPath };
4487
+ if (existsSync16(hookPath)) return { ok: false, path: relPath };
4313
4488
  const body = [
4314
4489
  "#!/usr/bin/env sh",
4315
4490
  "# navori pre-commit drift gate \u2014 scaffolded by 'navori init' (opt-in).",
@@ -4321,7 +4496,7 @@ function writePreCommitHook(cwd) {
4321
4496
  "fi",
4322
4497
  ""
4323
4498
  ].join("\n");
4324
- mkdirSync5(dirname6(hookPath), { recursive: true });
4499
+ mkdirSync6(dirname7(hookPath), { recursive: true });
4325
4500
  writeFileAtomic(hookPath, body);
4326
4501
  try {
4327
4502
  chmodSync2(hookPath, 493);
@@ -4546,15 +4721,15 @@ function formatProjectValue(v) {
4546
4721
  // src/commands/doctor.ts
4547
4722
  import { defineCommand as defineCommand3 } from "citty";
4548
4723
  import * as p3 from "@clack/prompts";
4549
- import { existsSync as existsSync17, readFileSync as readFileSync14, readdirSync as readdirSync8 } from "fs";
4550
- import { join as join13, resolve as resolve12, relative as relative4 } from "path";
4724
+ import { existsSync as existsSync18, readFileSync as readFileSync15, readdirSync as readdirSync8 } from "fs";
4725
+ import { join as join14, resolve as resolve12, relative as relative4 } from "path";
4551
4726
 
4552
4727
  // src/lib/health.ts
4553
- import { existsSync as existsSync16, readFileSync as readFileSync13, readdirSync as readdirSync7 } from "fs";
4554
- import { join as join12 } from "path";
4728
+ import { existsSync as existsSync17, readFileSync as readFileSync14, readdirSync as readdirSync7 } from "fs";
4729
+ import { join as join13 } from "path";
4555
4730
  function listMarkers(filePath) {
4556
- if (!existsSync16(filePath)) return [];
4557
- const content = readFileSync13(filePath, "utf-8");
4731
+ if (!existsSync17(filePath)) return [];
4732
+ const content = readFileSync14(filePath, "utf-8");
4558
4733
  const re = /<!-- navori:managed [^>]*-->/g;
4559
4734
  const result = [];
4560
4735
  for (const match of content.matchAll(re)) {
@@ -4599,10 +4774,10 @@ function scanManagedDrift(cwd, config) {
4599
4774
  }
4600
4775
  }
4601
4776
  const files = [];
4602
- if (existsSync16(join12(cwd, "CLAUDE.md"))) files.push("CLAUDE.md");
4777
+ if (existsSync17(join13(cwd, "CLAUDE.md"))) files.push("CLAUDE.md");
4603
4778
  for (const dir of [".claude/agents", ".claude/skills"]) {
4604
- const absDir = join12(cwd, dir);
4605
- if (!existsSync16(absDir)) continue;
4779
+ const absDir = join13(cwd, dir);
4780
+ if (!existsSync17(absDir)) continue;
4606
4781
  try {
4607
4782
  for (const file of readdirSync7(absDir)) {
4608
4783
  if (file.endsWith(".md")) files.push(`${dir}/${file}`);
@@ -4612,10 +4787,10 @@ function scanManagedDrift(cwd, config) {
4612
4787
  }
4613
4788
  }
4614
4789
  for (const rel of files) {
4615
- const abs = join12(cwd, rel);
4790
+ const abs = join13(cwd, rel);
4616
4791
  const fileContent = (() => {
4617
4792
  try {
4618
- return readFileSync13(abs, "utf-8");
4793
+ return readFileSync14(abs, "utf-8");
4619
4794
  } catch {
4620
4795
  return null;
4621
4796
  }
@@ -4697,7 +4872,7 @@ var doctorCommand = defineCommand3({
4697
4872
  const configPath = `${cwd}/navori.config.json`;
4698
4873
  const claudeMdPath = `${cwd}/CLAUDE.md`;
4699
4874
  if (!args.json) p3.intro(brand("doctor"));
4700
- if (!existsSync17(cwd)) {
4875
+ if (!existsSync18(cwd)) {
4701
4876
  if (args.json) {
4702
4877
  console.log(JSON.stringify({ ok: false, error: "directory-missing", cwd }));
4703
4878
  } else {
@@ -4705,7 +4880,7 @@ var doctorCommand = defineCommand3({
4705
4880
  }
4706
4881
  process.exit(1);
4707
4882
  }
4708
- if (!existsSync17(configPath)) {
4883
+ if (!existsSync18(configPath)) {
4709
4884
  if (args.json) {
4710
4885
  console.log(JSON.stringify({ ok: false, error: "config-missing", configPath }));
4711
4886
  } else {
@@ -4751,10 +4926,10 @@ var doctorCommand = defineCommand3({
4751
4926
  configPath,
4752
4927
  config,
4753
4928
  checks: {
4754
- claudeMdExists: existsSync17(claudeMdPath),
4755
- agentsMdExists: existsSync17(`${cwd}/AGENTS.md`),
4756
- claudeDirExists: existsSync17(`${cwd}/.claude`),
4757
- progressDirExists: existsSync17(`${cwd}/${config.progress?.dir ?? "progress"}`)
4929
+ claudeMdExists: existsSync18(claudeMdPath),
4930
+ agentsMdExists: existsSync18(`${cwd}/AGENTS.md`),
4931
+ claudeDirExists: existsSync18(`${cwd}/.claude`),
4932
+ progressDirExists: existsSync18(`${cwd}/${config.progress?.dir ?? "progress"}`)
4758
4933
  },
4759
4934
  managedBlocks: markers,
4760
4935
  missingPlugins,
@@ -4842,7 +5017,7 @@ ${lines.join("\n")}`
4842
5017
  );
4843
5018
  }
4844
5019
  const missingLocalSkills = (config.project?.localSkills ?? []).filter(
4845
- (name) => !existsSync17(join13(cwd, ".claude/skills", `${name}.md`))
5020
+ (name) => !existsSync18(join14(cwd, ".claude/skills", `${name}.md`))
4846
5021
  );
4847
5022
  if (missingLocalSkills.length > 0) {
4848
5023
  const lines = missingLocalSkills.map(
@@ -4901,10 +5076,10 @@ ${lines.join("\n")}`
4901
5076
  }
4902
5077
  });
4903
5078
  function scanCorruptedSettings(cwd) {
4904
- const path = join13(cwd, ".claude/settings.json");
4905
- if (!existsSync17(path)) return [];
5079
+ const path = join14(cwd, ".claude/settings.json");
5080
+ if (!existsSync18(path)) return [];
4906
5081
  try {
4907
- JSON.parse(readFileSync14(path, "utf-8"));
5082
+ JSON.parse(readFileSync15(path, "utf-8"));
4908
5083
  return [];
4909
5084
  } catch (err) {
4910
5085
  return [{ path: ".claude/settings.json", error: err.message }];
@@ -4924,7 +5099,7 @@ function scanMissingPresetFiles(cwd, config) {
4924
5099
  const missing = [];
4925
5100
  for (const e of [...managed, ...agents, ...skills, ...hooks]) {
4926
5101
  const abs = resolve12(loaded.assetRoot, e.relPath);
4927
- if (!existsSync17(abs)) missing.push({ id: e.id, path: relative4(cwd, abs) });
5102
+ if (!existsSync18(abs)) missing.push({ id: e.id, path: relative4(cwd, abs) });
4928
5103
  }
4929
5104
  return missing;
4930
5105
  }
@@ -4960,15 +5135,15 @@ function scanMissingInvariants(cwd, config) {
4960
5135
  }
4961
5136
  function readRenderedText(cwd) {
4962
5137
  const parts = [];
4963
- const claudeMd = join13(cwd, "CLAUDE.md");
4964
- if (existsSync17(claudeMd)) {
5138
+ const claudeMd = join14(cwd, "CLAUDE.md");
5139
+ if (existsSync18(claudeMd)) {
4965
5140
  try {
4966
- parts.push(readFileSync14(claudeMd, "utf-8"));
5141
+ parts.push(readFileSync15(claudeMd, "utf-8"));
4967
5142
  } catch {
4968
5143
  }
4969
5144
  }
4970
- const claudeDir = join13(cwd, ".claude");
4971
- if (existsSync17(claudeDir)) collectText(claudeDir, parts);
5145
+ const claudeDir = join14(cwd, ".claude");
5146
+ if (existsSync18(claudeDir)) collectText(claudeDir, parts);
4972
5147
  return parts.join("\n");
4973
5148
  }
4974
5149
  function collectText(dir, parts) {
@@ -4979,12 +5154,12 @@ function collectText(dir, parts) {
4979
5154
  return;
4980
5155
  }
4981
5156
  for (const entry of entries) {
4982
- const abs = join13(dir, entry.name);
5157
+ const abs = join14(dir, entry.name);
4983
5158
  if (entry.isDirectory()) {
4984
5159
  collectText(abs, parts);
4985
5160
  } else if (entry.isFile() && TEXT_EXTENSIONS.some((e) => entry.name.endsWith(e))) {
4986
5161
  try {
4987
- parts.push(readFileSync14(abs, "utf-8"));
5162
+ parts.push(readFileSync15(abs, "utf-8"));
4988
5163
  } catch {
4989
5164
  }
4990
5165
  }
@@ -5016,8 +5191,8 @@ function collectAssignments(config) {
5016
5191
  // src/commands/sync.ts
5017
5192
  import { defineCommand as defineCommand4 } from "citty";
5018
5193
  import * as p4 from "@clack/prompts";
5019
- import { existsSync as existsSync18, readFileSync as readFileSync15 } from "fs";
5020
- import { resolve as resolve13, join as join14 } from "path";
5194
+ import { existsSync as existsSync19, readFileSync as readFileSync16 } from "fs";
5195
+ import { resolve as resolve13, join as join15 } from "path";
5021
5196
 
5022
5197
  // src/lib/diff.ts
5023
5198
  function formatLineDiff(current, proposed, _options = {}) {
@@ -5062,11 +5237,11 @@ var syncCommand = defineCommand4({
5062
5237
  const cwd = resolve13(args.cwd ?? process.cwd());
5063
5238
  const configPath = `${cwd}/navori.config.json`;
5064
5239
  p4.intro(brand("sync"));
5065
- if (!existsSync18(cwd)) {
5240
+ if (!existsSync19(cwd)) {
5066
5241
  p4.cancel(`Directory not found: ${cwd}`);
5067
5242
  process.exit(1);
5068
5243
  }
5069
- if (!existsSync18(configPath)) {
5244
+ if (!existsSync19(configPath)) {
5070
5245
  p4.cancel(`No navori.config.json at ${configPath}. Run 'navori init' first.`);
5071
5246
  process.exit(1);
5072
5247
  }
@@ -5221,8 +5396,8 @@ async function resolveConflictsInteractively(plans) {
5221
5396
  (e) => e.status === "user-modified-skipped"
5222
5397
  );
5223
5398
  if (cmConflicts.length === 0) continue;
5224
- const claudeMdPath = join14(tp.target.cwd, "CLAUDE.md");
5225
- const existing = existsSync18(claudeMdPath) ? readFileSync15(claudeMdPath, "utf-8") : "";
5399
+ const claudeMdPath = join15(tp.target.cwd, "CLAUDE.md");
5400
+ const existing = existsSync19(claudeMdPath) ? readFileSync16(claudeMdPath, "utf-8") : "";
5226
5401
  const skipIds = /* @__PURE__ */ new Set();
5227
5402
  const forceIds = /* @__PURE__ */ new Set();
5228
5403
  for (const e of cmConflicts) {
@@ -5314,13 +5489,13 @@ function summarize2(writtenCount, conflictCount) {
5314
5489
  // src/commands/add.ts
5315
5490
  import { defineCommand as defineCommand5 } from "citty";
5316
5491
  import * as p5 from "@clack/prompts";
5317
- import { existsSync as existsSync20, readFileSync as readFileSync16 } from "fs";
5492
+ import { existsSync as existsSync21, readFileSync as readFileSync17 } from "fs";
5318
5493
  import { resolve as resolve14 } from "path";
5319
5494
  import { spawnSync as spawnSync3 } from "child_process";
5320
5495
 
5321
5496
  // src/lib/which.ts
5322
- import { existsSync as existsSync19, statSync as statSync6 } from "fs";
5323
- import { join as join15 } from "path";
5497
+ import { existsSync as existsSync20, statSync as statSync6 } from "fs";
5498
+ import { join as join16 } from "path";
5324
5499
  function hasBinary(name) {
5325
5500
  const pathEnv = process.env.PATH ?? "";
5326
5501
  const sep2 = process.platform === "win32" ? ";" : ":";
@@ -5328,8 +5503,8 @@ function hasBinary(name) {
5328
5503
  const exts = process.platform === "win32" ? (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";") : [""];
5329
5504
  for (const dir of dirs) {
5330
5505
  for (const ext of exts) {
5331
- const candidate = join15(dir, name + ext);
5332
- if (existsSync19(candidate)) {
5506
+ const candidate = join16(dir, name + ext);
5507
+ if (existsSync20(candidate)) {
5333
5508
  try {
5334
5509
  if (statSync6(candidate).isFile()) return true;
5335
5510
  } catch {
@@ -5405,11 +5580,11 @@ var addCommand = defineCommand5({
5405
5580
  } else {
5406
5581
  p5.intro(brand(`add ${accent(args.plugin)}`));
5407
5582
  }
5408
- if (!existsSync20(cwd)) {
5583
+ if (!existsSync21(cwd)) {
5409
5584
  p5.cancel(`Directory not found: ${cwd}`);
5410
5585
  process.exit(1);
5411
5586
  }
5412
- if (!existsSync20(configPath)) {
5587
+ if (!existsSync21(configPath)) {
5413
5588
  p5.cancel(`No navori.config.json at ${configPath}. Run 'navori init' first.`);
5414
5589
  process.exit(1);
5415
5590
  }
@@ -5443,7 +5618,7 @@ var addCommand = defineCommand5({
5443
5618
  ...config.plugins ?? {},
5444
5619
  [plugin.manifest.id]: { enabled: true }
5445
5620
  };
5446
- const raw = JSON.parse(readFileSync16(configPath, "utf-8"));
5621
+ const raw = JSON.parse(readFileSync17(configPath, "utf-8"));
5447
5622
  writeConfig(configPath, { ...raw, plugins: updatedPlugins });
5448
5623
  p5.log.success(`Added '${plugin.manifest.id}' to ${configPath}`);
5449
5624
  }
@@ -5528,8 +5703,8 @@ function printSuggestions(cwd, configPath) {
5528
5703
  // src/commands/workspace.ts
5529
5704
  import { defineCommand as defineCommand6 } from "citty";
5530
5705
  import * as p6 from "@clack/prompts";
5531
- import { existsSync as existsSync21 } from "fs";
5532
- import { join as join16 } from "path";
5706
+ import { existsSync as existsSync22 } from "fs";
5707
+ import { join as join17 } from "path";
5533
5708
 
5534
5709
  // src/lib/workspace-defaults.ts
5535
5710
  var VALID_DEFAULT_KEYS = "branchBase, prTarget, commits, language, engines, plugins.<id>.enabled";
@@ -5565,8 +5740,8 @@ function applyDefault(current, key, rawValue) {
5565
5740
 
5566
5741
  // src/commands/workspace.ts
5567
5742
  function readRepoConfigName(repoPath) {
5568
- const cfgPath = join16(repoPath, "navori.config.json");
5569
- if (!existsSync21(cfgPath)) return null;
5743
+ const cfgPath = join17(repoPath, "navori.config.json");
5744
+ if (!existsSync22(cfgPath)) return null;
5570
5745
  try {
5571
5746
  return readConfig(cfgPath).name;
5572
5747
  } catch {
@@ -5590,7 +5765,7 @@ var initSubCommand = defineCommand6({
5590
5765
  process.exit(1);
5591
5766
  }
5592
5767
  const path = workspacePath(name);
5593
- if (existsSync21(path)) {
5768
+ if (existsSync22(path)) {
5594
5769
  console.error(`Workspace '${name}' already exists at ${path}`);
5595
5770
  process.exit(1);
5596
5771
  }
@@ -5831,14 +6006,14 @@ var deleteSubCommand = defineCommand6({
5831
6006
  return;
5832
6007
  }
5833
6008
  }
5834
- const { renameSync: renameSync3, existsSync: existsSync31, mkdirSync: mkdirSync10 } = await import("fs");
6009
+ const { renameSync: renameSync3, existsSync: existsSync32, mkdirSync: mkdirSync11 } = await import("fs");
5835
6010
  const { join: joinPath } = await import("path");
5836
6011
  const { homedir: homedir2 } = await import("os");
5837
6012
  const trashRoot = joinPath(homedir2(), ".navori", ".trash");
5838
- mkdirSync10(trashRoot, { recursive: true });
6013
+ mkdirSync11(trashRoot, { recursive: true });
5839
6014
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
5840
6015
  const dest = joinPath(trashRoot, `${name}-${ts}`);
5841
- if (existsSync31(dir)) renameSync3(dir, dest);
6016
+ if (existsSync32(dir)) renameSync3(dir, dest);
5842
6017
  p6.outro(`Moved to ${dest}. Restore manually if needed.`);
5843
6018
  }
5844
6019
  });
@@ -5946,7 +6121,7 @@ var renderSubCommand = defineCommand6({
5946
6121
  }
5947
6122
  const rows = [];
5948
6123
  for (const repo of ws.repos) {
5949
- if (!existsSync21(repo.path)) {
6124
+ if (!existsSync22(repo.path)) {
5950
6125
  rows.push({ name: repo.name, status: "missing", detail: repo.path });
5951
6126
  continue;
5952
6127
  }
@@ -6020,11 +6195,11 @@ var workspaceCommand = defineCommand6({
6020
6195
  // src/commands/ticket.ts
6021
6196
  import { defineCommand as defineCommand7 } from "citty";
6022
6197
  import * as p7 from "@clack/prompts";
6023
- import { readFileSync as readFileSync18 } from "fs";
6198
+ import { readFileSync as readFileSync19 } from "fs";
6024
6199
 
6025
6200
  // src/lib/tickets.ts
6026
- import { existsSync as existsSync22, readFileSync as readFileSync17, readdirSync as readdirSync9, statSync as statSync7, mkdirSync as mkdirSync6, renameSync as renameSync2, rmSync as rmSync5 } from "fs";
6027
- import { join as join17, resolve as resolve15 } from "path";
6201
+ import { existsSync as existsSync23, readFileSync as readFileSync18, readdirSync as readdirSync9, statSync as statSync7, mkdirSync as mkdirSync7, renameSync as renameSync2, rmSync as rmSync5 } from "fs";
6202
+ import { join as join18, resolve as resolve15 } from "path";
6028
6203
  var TicketError = class extends NavoriError {
6029
6204
  constructor(message) {
6030
6205
  super("ticket-error", message);
@@ -6033,11 +6208,11 @@ var TicketError = class extends NavoriError {
6033
6208
  function ticketsDir(workspaceName) {
6034
6209
  const ws = loadWorkspace(workspaceName);
6035
6210
  if (!ws) throw new TicketError(`Workspace '${workspaceName}' not found`);
6036
- return join17(workspaceDirectory(workspaceName), ws.ticketsDir);
6211
+ return join18(workspaceDirectory(workspaceName), ws.ticketsDir);
6037
6212
  }
6038
6213
  function readTitle(path) {
6039
6214
  try {
6040
- const content = readFileSync17(path, "utf-8").split("\n");
6215
+ const content = readFileSync18(path, "utf-8").split("\n");
6041
6216
  for (const line of content) {
6042
6217
  const trimmed = line.trim();
6043
6218
  if (!trimmed) continue;
@@ -6050,13 +6225,13 @@ function readTitle(path) {
6050
6225
  }
6051
6226
  function listTickets(workspaceName) {
6052
6227
  const dir = ticketsDir(workspaceName);
6053
- if (!existsSync22(dir)) return [];
6228
+ if (!existsSync23(dir)) return [];
6054
6229
  const out = [];
6055
6230
  const collect = (folder, state) => {
6056
- if (!existsSync22(folder)) return;
6231
+ if (!existsSync23(folder)) return;
6057
6232
  for (const entry of readdirSync9(folder)) {
6058
6233
  if (!entry.endsWith(".md")) continue;
6059
- const full = join17(folder, entry);
6234
+ const full = join18(folder, entry);
6060
6235
  try {
6061
6236
  if (!statSync7(full).isFile()) continue;
6062
6237
  } catch {
@@ -6071,7 +6246,7 @@ function listTickets(workspaceName) {
6071
6246
  }
6072
6247
  };
6073
6248
  collect(dir, "active");
6074
- collect(join17(dir, "_archive"), "archive");
6249
+ collect(join18(dir, "_archive"), "archive");
6075
6250
  return out;
6076
6251
  }
6077
6252
  function findTicket(workspaceName, id) {
@@ -6106,9 +6281,9 @@ function archiveTicket(workspaceName, id) {
6106
6281
  if (!summary) throw new TicketError(`Ticket '${id}' not found in workspace '${workspaceName}'`);
6107
6282
  if (summary.state === "archive") return summary;
6108
6283
  const dir = ticketsDir(workspaceName);
6109
- const archiveDir = join17(dir, "_archive");
6110
- mkdirSync6(archiveDir, { recursive: true });
6111
- const dest = join17(archiveDir, `${id}.md`);
6284
+ const archiveDir = join18(dir, "_archive");
6285
+ mkdirSync7(archiveDir, { recursive: true });
6286
+ const dest = join18(archiveDir, `${id}.md`);
6112
6287
  renameSync2(summary.path, dest);
6113
6288
  return { id, path: dest, title: summary.title, state: "archive" };
6114
6289
  }
@@ -6122,9 +6297,9 @@ function createTicket(workspaceName, id, title) {
6122
6297
  throw new TicketError(`Invalid ticket id '${id}'. Use letters, digits, hyphens, underscores.`);
6123
6298
  }
6124
6299
  const dir = ticketsDir(workspaceName);
6125
- if (!existsSync22(dir)) throw new TicketError(`Tickets directory does not exist: ${dir}`);
6126
- const path = join17(dir, `${id}.md`);
6127
- if (existsSync22(path)) throw new TicketError(`Ticket '${id}' already exists at ${path}`);
6300
+ if (!existsSync23(dir)) throw new TicketError(`Tickets directory does not exist: ${dir}`);
6301
+ const path = join18(dir, `${id}.md`);
6302
+ if (existsSync23(path)) throw new TicketError(`Ticket '${id}' already exists at ${path}`);
6128
6303
  const finalTitle = title?.trim() || id;
6129
6304
  writeFileAtomic(path, defaultTemplate(id, finalTitle));
6130
6305
  return {
@@ -6139,10 +6314,10 @@ function findReferencingRepos(repoPaths, ticketId) {
6139
6314
  const idPattern = new RegExp(`\\b${ticketId}\\b`);
6140
6315
  for (const repoPath of repoPaths) {
6141
6316
  const abs = resolve15(repoPath);
6142
- const current = join17(abs, "progress", "current.md");
6143
- if (!existsSync22(current)) continue;
6317
+ const current = join18(abs, "progress", "current.md");
6318
+ if (!existsSync23(current)) continue;
6144
6319
  try {
6145
- const content = readFileSync17(current, "utf-8");
6320
+ const content = readFileSync18(current, "utf-8");
6146
6321
  const matches = [];
6147
6322
  for (const line of content.split("\n")) {
6148
6323
  if (idPattern.test(line)) matches.push(line.trim());
@@ -6229,7 +6404,7 @@ Create it with: navori ticket new ${args.workspace} ${args.id}
6229
6404
  const repoPaths = (ws?.repos ?? []).map((r) => r.path);
6230
6405
  const referencing = findReferencingRepos(repoPaths, args.id);
6231
6406
  if (args.json) {
6232
- const content = readFileSync18(ticket.path, "utf-8");
6407
+ const content = readFileSync19(ticket.path, "utf-8");
6233
6408
  console.log(JSON.stringify({ ticket, referencing, content }, null, 2));
6234
6409
  return;
6235
6410
  }
@@ -6241,7 +6416,7 @@ Create it with: navori ticket new ${args.workspace} ${args.id}
6241
6416
  ["path", ticket.path]
6242
6417
  ])
6243
6418
  );
6244
- p7.note(readFileSync18(ticket.path, "utf-8"), "Content");
6419
+ p7.note(readFileSync19(ticket.path, "utf-8"), "Content");
6245
6420
  if (referencing.length === 0) {
6246
6421
  p7.log.message(dim("Referenced in: (no repo's progress/current.md mentions this ticket)"));
6247
6422
  } else {
@@ -6375,7 +6550,7 @@ var ticketCommand = defineCommand7({
6375
6550
  // src/commands/configure.ts
6376
6551
  import { defineCommand as defineCommand8 } from "citty";
6377
6552
  import * as p8 from "@clack/prompts";
6378
- import { existsSync as existsSync23, readFileSync as readFileSync19 } from "fs";
6553
+ import { existsSync as existsSync24, readFileSync as readFileSync20 } from "fs";
6379
6554
  import { resolve as resolve16 } from "path";
6380
6555
  var ENGINE_OPTIONS2 = [
6381
6556
  { value: "claude", label: "Claude Code (.claude/)" },
@@ -6389,11 +6564,11 @@ function fail(msg) {
6389
6564
  process.exit(1);
6390
6565
  }
6391
6566
  function loadOrExit(cwd) {
6392
- if (!existsSync23(cwd)) fail(`Directory not found: ${cwd}`);
6567
+ if (!existsSync24(cwd)) fail(`Directory not found: ${cwd}`);
6393
6568
  const configPath = resolve16(cwd, "navori.config.json");
6394
- if (!existsSync23(configPath)) fail(`No navori.config.json at ${configPath}. Run 'navori init' first.`);
6569
+ if (!existsSync24(configPath)) fail(`No navori.config.json at ${configPath}. Run 'navori init' first.`);
6395
6570
  const config = readConfig(configPath);
6396
- const raw = JSON.parse(readFileSync19(configPath, "utf-8"));
6571
+ const raw = JSON.parse(readFileSync20(configPath, "utf-8"));
6397
6572
  return { config, path: configPath, raw };
6398
6573
  }
6399
6574
  function persist(path, raw) {
@@ -6707,8 +6882,17 @@ var configureCommand = defineCommand8({
6707
6882
  // src/commands/update.ts
6708
6883
  import { defineCommand as defineCommand9 } from "citty";
6709
6884
  import * as p9 from "@clack/prompts";
6710
- import { existsSync as existsSync24, readFileSync as readFileSync20 } from "fs";
6885
+ import { existsSync as existsSync25, readFileSync as readFileSync21 } from "fs";
6711
6886
  import { resolve as resolve17 } from "path";
6887
+ function sameSet(a, b) {
6888
+ if (a.length !== b.length) return false;
6889
+ const seen = new Set(a);
6890
+ return b.every((x) => seen.has(x));
6891
+ }
6892
+ function withProject(current, patch) {
6893
+ const base = current && typeof current === "object" ? current : {};
6894
+ return { ...base, ...patch };
6895
+ }
6712
6896
  function diffConfig(current, detected) {
6713
6897
  const out = [];
6714
6898
  if (current.preset !== detected.suggestedPreset && detected.suggestedPreset !== "custom") {
@@ -6736,6 +6920,21 @@ function diffConfig(current, detected) {
6736
6920
  after: [...current.engines, ...newlyDetected].join(", ")
6737
6921
  });
6738
6922
  }
6923
+ const currentLibs = current.project?.libraries ?? [];
6924
+ if (!sameSet(currentLibs, detected.libraries)) {
6925
+ out.push({
6926
+ field: "project.libraries",
6927
+ before: currentLibs.length ? currentLibs.join(", ") : "(none)",
6928
+ after: detected.libraries.length ? detected.libraries.join(", ") : "(none)"
6929
+ });
6930
+ }
6931
+ const detectedLang = detected.stack.language;
6932
+ if (detectedLang && detectedLang !== "unknown") {
6933
+ const currentLang = current.project?.codeLanguage;
6934
+ if (currentLang !== detectedLang) {
6935
+ out.push({ field: "project.codeLanguage", before: currentLang ?? "(none)", after: detectedLang });
6936
+ }
6937
+ }
6739
6938
  return out;
6740
6939
  }
6741
6940
  function applyDiffs(raw, detected, diffs) {
@@ -6750,6 +6949,10 @@ function applyDiffs(raw, detected, diffs) {
6750
6949
  const currentEngines = new Set(raw.engines ?? []);
6751
6950
  for (const e of detected.existingEngines) currentEngines.add(e);
6752
6951
  raw.engines = [...currentEngines];
6952
+ } else if (d.field === "project.libraries") {
6953
+ raw.project = withProject(raw.project, { libraries: detected.libraries });
6954
+ } else if (d.field === "project.codeLanguage") {
6955
+ raw.project = withProject(raw.project, { codeLanguage: detected.stack.language });
6753
6956
  }
6754
6957
  }
6755
6958
  }
@@ -6768,20 +6971,22 @@ var updateCommand = defineCommand9({
6768
6971
  const cwd = resolve17(args.cwd ?? process.cwd());
6769
6972
  const configPath = `${cwd}/navori.config.json`;
6770
6973
  p9.intro(brand("update"));
6771
- if (!existsSync24(cwd)) {
6974
+ if (!existsSync25(cwd)) {
6772
6975
  p9.cancel(`Directory not found: ${cwd}`);
6773
6976
  process.exit(1);
6774
6977
  }
6775
- if (!existsSync24(configPath)) {
6978
+ if (!existsSync25(configPath)) {
6776
6979
  p9.cancel(`No navori.config.json at ${configPath}. Run 'navori init' first.`);
6777
6980
  process.exit(1);
6778
6981
  }
6779
6982
  const config = readConfig(configPath);
6780
6983
  const detected = detectProject(cwd);
6781
6984
  const diffs = diffConfig(config, detected);
6782
- const claudeMd = existsSync24(`${cwd}/CLAUDE.md`) ? readFileSync20(`${cwd}/CLAUDE.md`, "utf-8") : "";
6783
- const plan = computeRenderPlan(claudeMd, config, cwd);
6784
- if (diffs.length === 0 && !plan.changed && plan.updatesAvailable.length === 0) {
6985
+ const preview = runRender(cwd, true);
6986
+ const previewWrites = preview.engineResult?.written ?? [];
6987
+ const previewConflicts = preview.engineResult?.skipped ?? [];
6988
+ const updates = preview.updatesAvailable ?? [];
6989
+ if (diffs.length === 0 && previewWrites.length === 0 && previewConflicts.length === 0) {
6785
6990
  p9.outro("Up to date \u2014 nothing to update");
6786
6991
  return;
6787
6992
  }
@@ -6794,24 +6999,35 @@ ${lines.join("\n")}`);
6794
6999
  } else {
6795
7000
  p9.log.info("Config is in sync with the repo");
6796
7001
  }
6797
- if (plan.updatesAvailable.length > 0) {
6798
- const lines = plan.updatesAvailable.map(
7002
+ if (previewWrites.length > 0) {
7003
+ const shown = previewWrites.slice(0, 12).map((w) => ` ${color.cyan(sym.update)} ${w.path} ${dim(`(${w.status})`)}`);
7004
+ const more = previewWrites.length > 12 ? `
7005
+ ${dim(`\u2026 +${previewWrites.length - 12} m\xE1s`)}` : "";
7006
+ p9.log.info(`Archivos que se actualizar\xEDan (${previewWrites.length}):
7007
+ ${shown.join("\n")}${more}`);
7008
+ }
7009
+ if (updates.length > 0) {
7010
+ const lines = updates.map(
6799
7011
  (u) => ` ${color.cyan(sym.update)} ${u.id} ${dim(`(${u.source} ${u.fromVersion} \u2192 ${u.toVersion})`)}`
6800
7012
  );
6801
- p9.log.info(`Managed block updates available (${plan.updatesAvailable.length}):
7013
+ p9.log.info(`Managed block updates available (${updates.length}):
6802
7014
  ${lines.join("\n")}`);
6803
7015
  }
6804
- const conflicts = plan.entries.filter((e) => e.status === "user-modified-skipped");
6805
- if (conflicts.length > 0) {
6806
- p9.log.warn(`${conflicts.length} conflict(s) in managed blocks \u2014 sync will need a decision`);
7016
+ if (previewConflicts.length > 0) {
7017
+ p9.log.warn(`${previewConflicts.length} archivo(s) con ediciones tuyas \u2014 'navori sync' los resuelve interactivamente`);
6807
7018
  }
6808
7019
  if (args["dry-run"]) {
7020
+ if (diffs.some((d) => d.field === "project.libraries")) {
7021
+ p9.log.message(
7022
+ dim("Nota: aplicar el diff de project.libraries materializa las library skills (el preview de arriba refleja el config actual).")
7023
+ );
7024
+ }
6809
7025
  p9.outro("Dry-run complete (no files written)");
6810
7026
  return;
6811
7027
  }
6812
7028
  if (!args.yes && diffs.length > 0) {
6813
7029
  const ok = await p9.confirm({
6814
- message: `Apply ${diffs.length} config update${diffs.length === 1 ? "" : "s"}?`,
7030
+ message: `Apply ${diffs.length} config update${diffs.length === 1 ? "" : "s"} + re-render?`,
6815
7031
  initialValue: true
6816
7032
  });
6817
7033
  if (p9.isCancel(ok) || !ok) {
@@ -6820,39 +7036,31 @@ ${lines.join("\n")}`);
6820
7036
  }
6821
7037
  }
6822
7038
  if (diffs.length > 0) {
6823
- const raw = JSON.parse(readFileSync20(configPath, "utf-8"));
7039
+ const raw = JSON.parse(readFileSync21(configPath, "utf-8"));
6824
7040
  delete raw.$schema;
6825
7041
  applyDiffs(raw, detected, diffs);
6826
7042
  writeConfig(configPath, raw);
6827
7043
  p9.log.success(`Updated ${configPath}`);
6828
7044
  }
6829
7045
  if (args["config-only"]) {
6830
- p9.outro("Config updated. Run 'navori sync' when ready to refresh CLAUDE.md.");
7046
+ p9.outro("Config updated. Corre 'navori sync' para refrescar CLAUDE.md + .claude/.");
6831
7047
  return;
6832
7048
  }
6833
- if (plan.changed || plan.updatesAvailable.length > 0 || diffs.length > 0) {
6834
- const freshConfig = readConfig(configPath);
6835
- const claudeMdNow = existsSync24(`${cwd}/CLAUDE.md`) ? readFileSync20(`${cwd}/CLAUDE.md`, "utf-8") : "";
6836
- const freshPlan = computeRenderPlan(claudeMdNow, freshConfig, cwd);
6837
- const fresheConflicts = freshPlan.entries.filter((e) => e.status === "user-modified-skipped");
6838
- if (fresheConflicts.length > 0 && !args.yes) {
6839
- p9.log.warn(
6840
- `${fresheConflicts.length} conflict(s) detected \u2014 run 'navori sync' to resolve interactively`
6841
- );
6842
- p9.outro("Done (config updated, sync deferred due to conflicts)");
6843
- return;
6844
- }
6845
- if (freshPlan.changed) {
6846
- if (existsSync24(`${cwd}/CLAUDE.md`)) {
6847
- const handle = createBackup(cwd, ["CLAUDE.md"]);
6848
- purgeOldBackups();
6849
- p9.log.message(`Backup: ${handle.path}`);
6850
- }
6851
- writeFileAtomic(`${cwd}/CLAUDE.md`, freshPlan.next);
6852
- p9.log.success(`Re-rendered ${cwd}/CLAUDE.md`);
6853
- } else {
6854
- p9.log.info("No re-render needed");
6855
- }
7049
+ const result = runRender(cwd, false);
7050
+ if (!result.ok) {
7051
+ p9.log.error(result.reason ?? "Render failed");
7052
+ p9.outro("Done (config actualizado, pero el render fall\xF3)");
7053
+ return;
7054
+ }
7055
+ const written = result.engineResult?.written ?? [];
7056
+ const skipped = result.engineResult?.skipped ?? [];
7057
+ if (skipped.length > 0) {
7058
+ p9.log.warn(`${skipped.length} archivo(s) con ediciones tuyas no se tocaron \u2014 'navori sync' para resolver`);
7059
+ }
7060
+ if (written.length > 0) {
7061
+ p9.log.success(`Re-rendered ${written.length} archivo(s) (CLAUDE.md + .claude/)`);
7062
+ } else {
7063
+ p9.log.info("No re-render needed");
6856
7064
  }
6857
7065
  p9.outro("Done");
6858
7066
  }
@@ -6861,14 +7069,14 @@ ${lines.join("\n")}`);
6861
7069
  // src/commands/backup.ts
6862
7070
  import { defineCommand as defineCommand10 } from "citty";
6863
7071
  import * as p10 from "@clack/prompts";
6864
- import { existsSync as existsSync25, readdirSync as readdirSync10, statSync as statSync8, copyFileSync as copyFileSync4, mkdirSync as mkdirSync7 } from "fs";
6865
- import { join as join18, relative as relative5, resolve as resolve18, dirname as dirname7 } from "path";
7072
+ import { existsSync as existsSync26, readdirSync as readdirSync10, statSync as statSync8, copyFileSync as copyFileSync4, mkdirSync as mkdirSync8 } from "fs";
7073
+ import { join as join19, relative as relative5, resolve as resolve18, dirname as dirname8 } from "path";
6866
7074
  function listBackups() {
6867
7075
  const root = backupRoot();
6868
- if (!existsSync25(root)) return [];
7076
+ if (!existsSync26(root)) return [];
6869
7077
  const entries = [];
6870
7078
  for (const name of readdirSync10(root)) {
6871
- const full = join18(root, name);
7079
+ const full = join19(root, name);
6872
7080
  try {
6873
7081
  const stat = statSync8(full);
6874
7082
  if (!stat.isDirectory()) continue;
@@ -6883,7 +7091,7 @@ function listBackups() {
6883
7091
  function collectFiles(root, dir) {
6884
7092
  const out = [];
6885
7093
  for (const entry of readdirSync10(dir)) {
6886
- const full = join18(dir, entry);
7094
+ const full = join19(dir, entry);
6887
7095
  try {
6888
7096
  const stat = statSync8(full);
6889
7097
  if (stat.isDirectory()) {
@@ -6949,9 +7157,9 @@ var restoreSubCommand = defineCommand10({
6949
7157
  async run({ args }) {
6950
7158
  const ts = args.timestamp;
6951
7159
  const cwd = resolve18(args.cwd ?? process.cwd());
6952
- const backupDir = join18(backupRoot(), ts);
7160
+ const backupDir = join19(backupRoot(), ts);
6953
7161
  p10.intro(brand(`backup restore ${accent(ts)}`));
6954
- if (!existsSync25(backupDir)) {
7162
+ if (!existsSync26(backupDir)) {
6955
7163
  p10.cancel(`Backup not found: ${backupDir}`);
6956
7164
  process.exit(1);
6957
7165
  }
@@ -6973,9 +7181,9 @@ var restoreSubCommand = defineCommand10({
6973
7181
  }
6974
7182
  }
6975
7183
  for (const rel of files) {
6976
- const src = join18(backupDir, rel);
6977
- const dest = join18(cwd, rel);
6978
- mkdirSync7(dirname7(dest), { recursive: true });
7184
+ const src = join19(backupDir, rel);
7185
+ const dest = join19(cwd, rel);
7186
+ mkdirSync8(dirname8(dest), { recursive: true });
6979
7187
  copyFileSync4(src, dest);
6980
7188
  }
6981
7189
  p10.outro(`Restored ${files.length} file(s)`);
@@ -7005,19 +7213,19 @@ var backupCommand = defineCommand10({
7005
7213
  // src/commands/migrations.ts
7006
7214
  import { defineCommand as defineCommand11 } from "citty";
7007
7215
  import * as p11 from "@clack/prompts";
7008
- import { existsSync as existsSync26, readdirSync as readdirSync11, statSync as statSync9, copyFileSync as copyFileSync5, mkdirSync as mkdirSync8 } from "fs";
7009
- import { join as join19, relative as relative6, resolve as resolve19, dirname as dirname8 } from "path";
7216
+ import { existsSync as existsSync27, readdirSync as readdirSync11, statSync as statSync9, copyFileSync as copyFileSync5, mkdirSync as mkdirSync9 } from "fs";
7217
+ import { join as join20, relative as relative6, resolve as resolve19, dirname as dirname9 } from "path";
7010
7218
  function listMigrations() {
7011
7219
  const root = migrationsRoot();
7012
- if (!existsSync26(root)) return [];
7220
+ if (!existsSync27(root)) return [];
7013
7221
  const entries = [];
7014
7222
  for (const ts of readdirSync11(root)) {
7015
- const tsDir = join19(root, ts);
7223
+ const tsDir = join20(root, ts);
7016
7224
  try {
7017
7225
  const stat = statSync9(tsDir);
7018
7226
  if (!stat.isDirectory()) continue;
7019
7227
  for (const repoName of readdirSync11(tsDir)) {
7020
- const repoDir = join19(tsDir, repoName);
7228
+ const repoDir = join20(tsDir, repoName);
7021
7229
  try {
7022
7230
  const repoStat = statSync9(repoDir);
7023
7231
  if (!repoStat.isDirectory()) continue;
@@ -7035,7 +7243,7 @@ function listMigrations() {
7035
7243
  function collectFiles2(root, dir) {
7036
7244
  const out = [];
7037
7245
  for (const entry of readdirSync11(dir)) {
7038
- const full = join19(dir, entry);
7246
+ const full = join20(dir, entry);
7039
7247
  try {
7040
7248
  const stat = statSync9(full);
7041
7249
  if (stat.isDirectory()) {
@@ -7104,9 +7312,9 @@ var restoreSubCommand2 = defineCommand11({
7104
7312
  const ts = args.timestamp;
7105
7313
  const repoName = args.repo;
7106
7314
  const cwd = resolve19(args.cwd ?? process.cwd());
7107
- const migrationDir = join19(migrationsRoot(), ts, repoName);
7315
+ const migrationDir = join20(migrationsRoot(), ts, repoName);
7108
7316
  p11.intro(brand(`migrations restore ${accent(`${ts}/${repoName}`)}`));
7109
- if (!existsSync26(migrationDir)) {
7317
+ if (!existsSync27(migrationDir)) {
7110
7318
  p11.cancel(`Migration not found: ${migrationDir}`);
7111
7319
  process.exit(1);
7112
7320
  }
@@ -7129,9 +7337,9 @@ var restoreSubCommand2 = defineCommand11({
7129
7337
  }
7130
7338
  }
7131
7339
  for (const rel of files) {
7132
- const src = join19(migrationDir, rel);
7133
- const dest = join19(cwd, rel);
7134
- mkdirSync8(dirname8(dest), { recursive: true });
7340
+ const src = join20(migrationDir, rel);
7341
+ const dest = join20(cwd, rel);
7342
+ mkdirSync9(dirname9(dest), { recursive: true });
7135
7343
  copyFileSync5(src, dest);
7136
7344
  }
7137
7345
  p11.outro(`Restored ${files.length} file(s)`);
@@ -7162,8 +7370,8 @@ var migrationsCommand = defineCommand11({
7162
7370
  // src/commands/preset.ts
7163
7371
  import { defineCommand as defineCommand12 } from "citty";
7164
7372
  import * as p12 from "@clack/prompts";
7165
- import { existsSync as existsSync27, mkdirSync as mkdirSync9 } from "fs";
7166
- import { join as join20, resolve as resolve20 } from "path";
7373
+ import { existsSync as existsSync28, mkdirSync as mkdirSync10 } from "fs";
7374
+ import { join as join21, resolve as resolve20 } from "path";
7167
7375
  var PRESET_ID_RE = /^[a-z0-9][a-z0-9-]*$/;
7168
7376
  function stackTemplate(id) {
7169
7377
  return [
@@ -7231,7 +7439,7 @@ var initSubCommand2 = defineCommand12({
7231
7439
  process.exit(1);
7232
7440
  }
7233
7441
  const presetDir = resolve20(cwd, ".navori/presets", id);
7234
- if (existsSync27(presetDir)) {
7442
+ if (existsSync28(presetDir)) {
7235
7443
  p12.cancel(
7236
7444
  `Ya existe .navori/presets/${id}/ \u2014 b\xF3rralo o usa otro id si quieres regenerarlo.`
7237
7445
  );
@@ -7257,11 +7465,11 @@ var initSubCommand2 = defineCommand12({
7257
7465
  },
7258
7466
  invariants: []
7259
7467
  };
7260
- mkdirSync9(join20(presetDir, "managed"), { recursive: true });
7261
- mkdirSync9(join20(presetDir, "skills"), { recursive: true });
7262
- writeFileAtomic(join20(presetDir, `${id}.json`), JSON.stringify(manifest, null, 2) + "\n");
7263
- writeFileAtomic(join20(presetDir, "managed", "stack.md"), stackTemplate(id));
7264
- writeFileAtomic(join20(presetDir, "skills", `${skillId}.md`), skillTemplate(skillId));
7468
+ mkdirSync10(join21(presetDir, "managed"), { recursive: true });
7469
+ mkdirSync10(join21(presetDir, "skills"), { recursive: true });
7470
+ writeFileAtomic(join21(presetDir, `${id}.json`), JSON.stringify(manifest, null, 2) + "\n");
7471
+ writeFileAtomic(join21(presetDir, "managed", "stack.md"), stackTemplate(id));
7472
+ writeFileAtomic(join21(presetDir, "skills", `${skillId}.md`), skillTemplate(skillId));
7265
7473
  p12.log.success(`Creado .navori/presets/${id}/`);
7266
7474
  p12.log.message(
7267
7475
  [
@@ -7270,8 +7478,8 @@ var initSubCommand2 = defineCommand12({
7270
7478
  ` ${dim("\xB7")} skills/${skillId}.md`
7271
7479
  ].join("\n")
7272
7480
  );
7273
- const configPath = join20(cwd, "navori.config.json");
7274
- if (existsSync27(configPath)) {
7481
+ const configPath = join21(cwd, "navori.config.json");
7482
+ if (existsSync28(configPath)) {
7275
7483
  const config = readConfig(configPath);
7276
7484
  writeConfig(configPath, { ...config, preset: id });
7277
7485
  p12.log.success(`navori.config.json \u2192 preset: ${accent(id)}`);
@@ -7298,10 +7506,10 @@ var presetCommand = defineCommand12({
7298
7506
  import { defineCommand as defineCommand13 } from "citty";
7299
7507
  import * as p13 from "@clack/prompts";
7300
7508
  import { resolve as resolve21 } from "path";
7301
- import { existsSync as existsSync28 } from "fs";
7509
+ import { existsSync as existsSync29 } from "fs";
7302
7510
  function runScan(opts) {
7303
7511
  const configPath = resolve21(opts.cwd, "navori.config.json");
7304
- if (!existsSync28(configPath)) {
7512
+ if (!existsSync29(configPath)) {
7305
7513
  return { kind: "no-config", configPath };
7306
7514
  }
7307
7515
  const config = readConfig(configPath);
@@ -7472,7 +7680,7 @@ async function collectPresetOverrides(added) {
7472
7680
  // src/commands/status.ts
7473
7681
  import { defineCommand as defineCommand14 } from "citty";
7474
7682
  import * as p14 from "@clack/prompts";
7475
- import { existsSync as existsSync29 } from "fs";
7683
+ import { existsSync as existsSync30 } from "fs";
7476
7684
  import { resolve as resolve22 } from "path";
7477
7685
  var statusCommand = defineCommand14({
7478
7686
  meta: {
@@ -7486,7 +7694,7 @@ var statusCommand = defineCommand14({
7486
7694
  async run({ args }) {
7487
7695
  const cwd = resolve22(args.cwd ?? process.cwd());
7488
7696
  const configPath = `${cwd}/navori.config.json`;
7489
- if (!existsSync29(configPath)) {
7697
+ if (!existsSync30(configPath)) {
7490
7698
  if (args.json) {
7491
7699
  console.log(JSON.stringify({ ok: false, error: "config-missing", configPath }));
7492
7700
  } else {
@@ -7510,7 +7718,7 @@ var statusCommand = defineCommand14({
7510
7718
  }
7511
7719
  throw err;
7512
7720
  }
7513
- const claudeMdExists = existsSync29(`${cwd}/CLAUDE.md`);
7721
+ const claudeMdExists = existsSync30(`${cwd}/CLAUDE.md`);
7514
7722
  const missingPlugins = collectMissingPlugins(config);
7515
7723
  const drifts = scanManagedDrift(cwd, config);
7516
7724
  const enabledPlugins = Object.entries(config.plugins ?? {}).filter(([, v]) => v.enabled === true).map(([k]) => k);
@@ -7558,7 +7766,7 @@ var statusCommand = defineCommand14({
7558
7766
  import { defineCommand as defineCommand15 } from "citty";
7559
7767
  import * as p15 from "@clack/prompts";
7560
7768
  import { performance as performance2 } from "perf_hooks";
7561
- import { existsSync as existsSync30 } from "fs";
7769
+ import { existsSync as existsSync31 } from "fs";
7562
7770
  import { resolve as resolve23 } from "path";
7563
7771
  var benchCommand = defineCommand15({
7564
7772
  meta: {
@@ -7572,7 +7780,7 @@ var benchCommand = defineCommand15({
7572
7780
  async run({ args }) {
7573
7781
  const cwd = resolve23(args.cwd ?? process.cwd());
7574
7782
  p15.intro(brand("bench"));
7575
- if (!existsSync30(`${cwd}/navori.config.json`)) {
7783
+ if (!existsSync31(`${cwd}/navori.config.json`)) {
7576
7784
  p15.cancel(`No navori.config.json at ${cwd}. Run 'navori init' first.`);
7577
7785
  process.exit(1);
7578
7786
  }
@@ -7603,13 +7811,13 @@ var benchCommand = defineCommand15({
7603
7811
 
7604
7812
  // src/index.ts
7605
7813
  function readVersion() {
7606
- const here = dirname9(fileURLToPath2(import.meta.url));
7814
+ const here = dirname10(fileURLToPath2(import.meta.url));
7607
7815
  for (const candidate of [
7608
7816
  resolve24(here, "..", "package.json"),
7609
7817
  resolve24(here, "package.json")
7610
7818
  ]) {
7611
7819
  try {
7612
- const pkg = JSON.parse(readFileSync21(candidate, "utf-8"));
7820
+ const pkg = JSON.parse(readFileSync22(candidate, "utf-8"));
7613
7821
  if (pkg.version) return pkg.version;
7614
7822
  } catch {
7615
7823
  }