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/assets/core/core-assets/agents/commit-pr-pilot.md +2 -6
- package/dist/assets/core/core-assets/agents/explorer.md +2 -2
- package/dist/assets/core/core-assets/agents/implementer.md +1 -1
- package/dist/assets/core/core-assets/agents/leader.md +22 -1
- package/dist/assets/core/core-assets/agents/researcher.md +4 -3
- package/dist/assets/core/core-assets/agents/reviewer.md +1 -1
- package/dist/assets/core/core-assets/agents/ticket-audit.md +1 -1
- package/dist/assets/core/core-assets/managed/arranque-sesion.md +2 -2
- package/dist/assets/core/core-assets/managed/operaciones-seguras.md +1 -0
- package/dist/assets/core/core-assets/managed/orquestacion.md +15 -0
- package/dist/index.js +415 -207
- package/package.json +1 -1
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
|
|
6
|
-
import { dirname as
|
|
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
|
|
13
|
-
import { existsSync as
|
|
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
|
-
|
|
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
|
|
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 (!
|
|
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
|
|
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
|
-
|
|
3010
|
-
const
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
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
|
|
3033
|
-
written: engineResult
|
|
3034
|
-
languageFallbacks: engineResult
|
|
3035
|
-
updatesAvailable: engineResult
|
|
3036
|
-
backupPath: engineResult
|
|
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 (!
|
|
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
|
|
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 (!
|
|
3696
|
+
if (!existsSync14(path)) return [];
|
|
3522
3697
|
let parsed;
|
|
3523
3698
|
try {
|
|
3524
|
-
parsed = JSON.parse(
|
|
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
|
|
3539
|
-
import { join as
|
|
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 ?
|
|
3741
|
+
const currentAbs = currentRel ? join11(cwd, currentRel) : cwd;
|
|
3567
3742
|
if (head === "*") {
|
|
3568
|
-
if (!
|
|
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 =
|
|
3578
|
-
if (!
|
|
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 =
|
|
3591
|
-
if (!
|
|
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 (!
|
|
3847
|
+
if (!existsSync16(cwd)) {
|
|
3673
3848
|
p2.cancel(bootstrapT.dirNotFound(cwd));
|
|
3674
3849
|
process.exit(1);
|
|
3675
3850
|
}
|
|
3676
|
-
if (
|
|
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 (!
|
|
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 =
|
|
4310
|
-
const hookPath =
|
|
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 (
|
|
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
|
-
|
|
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
|
|
4550
|
-
import { join as
|
|
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
|
|
4554
|
-
import { join as
|
|
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 (!
|
|
4557
|
-
const content =
|
|
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 (
|
|
4777
|
+
if (existsSync17(join13(cwd, "CLAUDE.md"))) files.push("CLAUDE.md");
|
|
4603
4778
|
for (const dir of [".claude/agents", ".claude/skills"]) {
|
|
4604
|
-
const absDir =
|
|
4605
|
-
if (!
|
|
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 =
|
|
4790
|
+
const abs = join13(cwd, rel);
|
|
4616
4791
|
const fileContent = (() => {
|
|
4617
4792
|
try {
|
|
4618
|
-
return
|
|
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 (!
|
|
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 (!
|
|
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:
|
|
4755
|
-
agentsMdExists:
|
|
4756
|
-
claudeDirExists:
|
|
4757
|
-
progressDirExists:
|
|
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) => !
|
|
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 =
|
|
4905
|
-
if (!
|
|
5079
|
+
const path = join14(cwd, ".claude/settings.json");
|
|
5080
|
+
if (!existsSync18(path)) return [];
|
|
4906
5081
|
try {
|
|
4907
|
-
JSON.parse(
|
|
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 (!
|
|
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 =
|
|
4964
|
-
if (
|
|
5138
|
+
const claudeMd = join14(cwd, "CLAUDE.md");
|
|
5139
|
+
if (existsSync18(claudeMd)) {
|
|
4965
5140
|
try {
|
|
4966
|
-
parts.push(
|
|
5141
|
+
parts.push(readFileSync15(claudeMd, "utf-8"));
|
|
4967
5142
|
} catch {
|
|
4968
5143
|
}
|
|
4969
5144
|
}
|
|
4970
|
-
const claudeDir =
|
|
4971
|
-
if (
|
|
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 =
|
|
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(
|
|
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
|
|
5020
|
-
import { resolve as resolve13, join as
|
|
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 (!
|
|
5240
|
+
if (!existsSync19(cwd)) {
|
|
5066
5241
|
p4.cancel(`Directory not found: ${cwd}`);
|
|
5067
5242
|
process.exit(1);
|
|
5068
5243
|
}
|
|
5069
|
-
if (!
|
|
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 =
|
|
5225
|
-
const existing =
|
|
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
|
|
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
|
|
5323
|
-
import { join as
|
|
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 =
|
|
5332
|
-
if (
|
|
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 (!
|
|
5583
|
+
if (!existsSync21(cwd)) {
|
|
5409
5584
|
p5.cancel(`Directory not found: ${cwd}`);
|
|
5410
5585
|
process.exit(1);
|
|
5411
5586
|
}
|
|
5412
|
-
if (!
|
|
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(
|
|
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
|
|
5532
|
-
import { join as
|
|
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 =
|
|
5569
|
-
if (!
|
|
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 (
|
|
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:
|
|
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
|
-
|
|
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 (
|
|
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 (!
|
|
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
|
|
6198
|
+
import { readFileSync as readFileSync19 } from "fs";
|
|
6024
6199
|
|
|
6025
6200
|
// src/lib/tickets.ts
|
|
6026
|
-
import { existsSync as
|
|
6027
|
-
import { join as
|
|
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
|
|
6211
|
+
return join18(workspaceDirectory(workspaceName), ws.ticketsDir);
|
|
6037
6212
|
}
|
|
6038
6213
|
function readTitle(path) {
|
|
6039
6214
|
try {
|
|
6040
|
-
const content =
|
|
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 (!
|
|
6228
|
+
if (!existsSync23(dir)) return [];
|
|
6054
6229
|
const out = [];
|
|
6055
6230
|
const collect = (folder, state) => {
|
|
6056
|
-
if (!
|
|
6231
|
+
if (!existsSync23(folder)) return;
|
|
6057
6232
|
for (const entry of readdirSync9(folder)) {
|
|
6058
6233
|
if (!entry.endsWith(".md")) continue;
|
|
6059
|
-
const full =
|
|
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(
|
|
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 =
|
|
6110
|
-
|
|
6111
|
-
const dest =
|
|
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 (!
|
|
6126
|
-
const path =
|
|
6127
|
-
if (
|
|
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 =
|
|
6143
|
-
if (!
|
|
6317
|
+
const current = join18(abs, "progress", "current.md");
|
|
6318
|
+
if (!existsSync23(current)) continue;
|
|
6144
6319
|
try {
|
|
6145
|
-
const content =
|
|
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 =
|
|
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(
|
|
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
|
|
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 (!
|
|
6567
|
+
if (!existsSync24(cwd)) fail(`Directory not found: ${cwd}`);
|
|
6393
6568
|
const configPath = resolve16(cwd, "navori.config.json");
|
|
6394
|
-
if (!
|
|
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(
|
|
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
|
|
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 (!
|
|
6974
|
+
if (!existsSync25(cwd)) {
|
|
6772
6975
|
p9.cancel(`Directory not found: ${cwd}`);
|
|
6773
6976
|
process.exit(1);
|
|
6774
6977
|
}
|
|
6775
|
-
if (!
|
|
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
|
|
6783
|
-
const
|
|
6784
|
-
|
|
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 (
|
|
6798
|
-
const
|
|
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 (${
|
|
7013
|
+
p9.log.info(`Managed block updates available (${updates.length}):
|
|
6802
7014
|
${lines.join("\n")}`);
|
|
6803
7015
|
}
|
|
6804
|
-
|
|
6805
|
-
|
|
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(
|
|
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.
|
|
7046
|
+
p9.outro("Config updated. Corre 'navori sync' para refrescar CLAUDE.md + .claude/.");
|
|
6831
7047
|
return;
|
|
6832
7048
|
}
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
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
|
|
6865
|
-
import { join as
|
|
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 (!
|
|
7076
|
+
if (!existsSync26(root)) return [];
|
|
6869
7077
|
const entries = [];
|
|
6870
7078
|
for (const name of readdirSync10(root)) {
|
|
6871
|
-
const full =
|
|
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 =
|
|
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 =
|
|
7160
|
+
const backupDir = join19(backupRoot(), ts);
|
|
6953
7161
|
p10.intro(brand(`backup restore ${accent(ts)}`));
|
|
6954
|
-
if (!
|
|
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 =
|
|
6977
|
-
const dest =
|
|
6978
|
-
|
|
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
|
|
7009
|
-
import { join as
|
|
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 (!
|
|
7220
|
+
if (!existsSync27(root)) return [];
|
|
7013
7221
|
const entries = [];
|
|
7014
7222
|
for (const ts of readdirSync11(root)) {
|
|
7015
|
-
const tsDir =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
7315
|
+
const migrationDir = join20(migrationsRoot(), ts, repoName);
|
|
7108
7316
|
p11.intro(brand(`migrations restore ${accent(`${ts}/${repoName}`)}`));
|
|
7109
|
-
if (!
|
|
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 =
|
|
7133
|
-
const dest =
|
|
7134
|
-
|
|
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
|
|
7166
|
-
import { join as
|
|
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 (
|
|
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
|
-
|
|
7261
|
-
|
|
7262
|
-
writeFileAtomic(
|
|
7263
|
-
writeFileAtomic(
|
|
7264
|
-
writeFileAtomic(
|
|
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 =
|
|
7274
|
-
if (
|
|
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
|
|
7509
|
+
import { existsSync as existsSync29 } from "fs";
|
|
7302
7510
|
function runScan(opts) {
|
|
7303
7511
|
const configPath = resolve21(opts.cwd, "navori.config.json");
|
|
7304
|
-
if (!
|
|
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
|
|
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 (!
|
|
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 =
|
|
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
|
|
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 (!
|
|
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 =
|
|
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(
|
|
7820
|
+
const pkg = JSON.parse(readFileSync22(candidate, "utf-8"));
|
|
7613
7821
|
if (pkg.version) return pkg.version;
|
|
7614
7822
|
} catch {
|
|
7615
7823
|
}
|