navori 0.2.3 → 0.2.6
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 +454 -177
- 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
|
|
@@ -1374,7 +1374,7 @@ function writeWorkspace(workspace) {
|
|
|
1374
1374
|
// src/commands/render.ts
|
|
1375
1375
|
import { defineCommand } from "citty";
|
|
1376
1376
|
import * as p from "@clack/prompts";
|
|
1377
|
-
import { existsSync as
|
|
1377
|
+
import { existsSync as existsSync13 } from "fs";
|
|
1378
1378
|
import { resolve as resolve9 } from "path";
|
|
1379
1379
|
|
|
1380
1380
|
// src/engines/claude/index.ts
|
|
@@ -1653,6 +1653,51 @@ function extractManagedContent(existing, id, commentStyle = "html") {
|
|
|
1653
1653
|
const match = findMarker(existing, id, syntax);
|
|
1654
1654
|
return match ? match.content : null;
|
|
1655
1655
|
}
|
|
1656
|
+
function locateManagedBlocks(content, syntax) {
|
|
1657
|
+
const openRegex = new RegExp(
|
|
1658
|
+
`${escapeRegex(syntax.openPrefix)}\\s+id="([^"]+)"${syntax.attrsAndTerminatorPattern}`,
|
|
1659
|
+
"g"
|
|
1660
|
+
);
|
|
1661
|
+
const blocks = [];
|
|
1662
|
+
for (const m of content.matchAll(openRegex)) {
|
|
1663
|
+
if (m.index === void 0) continue;
|
|
1664
|
+
const id = m[1];
|
|
1665
|
+
const close = closeMarker(id, syntax);
|
|
1666
|
+
const closeStart = content.indexOf(close, m.index + m[0].length);
|
|
1667
|
+
if (closeStart < 0) continue;
|
|
1668
|
+
blocks.push({ id, openStart: m.index, closeEnd: closeStart + close.length });
|
|
1669
|
+
}
|
|
1670
|
+
return blocks;
|
|
1671
|
+
}
|
|
1672
|
+
function reorderManagedBlocks(content, canonicalOrder, commentStyle = "html") {
|
|
1673
|
+
const syntax = syntaxFor(commentStyle);
|
|
1674
|
+
const blocks = locateManagedBlocks(content, syntax);
|
|
1675
|
+
if (blocks.length < 2) {
|
|
1676
|
+
return { output: content, reordered: false, blockedByInterleaving: false };
|
|
1677
|
+
}
|
|
1678
|
+
const rank = /* @__PURE__ */ new Map();
|
|
1679
|
+
canonicalOrder.forEach((id, i) => {
|
|
1680
|
+
if (!rank.has(id)) rank.set(id, i);
|
|
1681
|
+
});
|
|
1682
|
+
const unknownBase = canonicalOrder.length;
|
|
1683
|
+
const desired = blocks.map((b, i) => ({ b, i, key: rank.has(b.id) ? rank.get(b.id) : unknownBase + i })).sort((a, z8) => a.key - z8.key || a.i - z8.i).map((x) => x.b);
|
|
1684
|
+
if (desired.every((b, i) => b === blocks[i])) {
|
|
1685
|
+
return { output: content, reordered: false, blockedByInterleaving: false };
|
|
1686
|
+
}
|
|
1687
|
+
for (let i = 0; i < blocks.length - 1; i++) {
|
|
1688
|
+
const gap = content.slice(blocks[i].closeEnd, blocks[i + 1].openStart);
|
|
1689
|
+
if (gap.trim() !== "") {
|
|
1690
|
+
return { output: content, reordered: false, blockedByInterleaving: true };
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
const first = blocks[0];
|
|
1694
|
+
const last = blocks[blocks.length - 1];
|
|
1695
|
+
const preamble = content.slice(0, first.openStart);
|
|
1696
|
+
const suffix = content.slice(last.closeEnd);
|
|
1697
|
+
const body = desired.map((b) => content.slice(b.openStart, b.closeEnd)).join("\n\n");
|
|
1698
|
+
const pre = preamble === "" ? "" : preamble.replace(/\n*$/, "\n\n");
|
|
1699
|
+
return { output: pre + body + suffix, reordered: true, blockedByInterleaving: false };
|
|
1700
|
+
}
|
|
1656
1701
|
function resolveCondition(config, path) {
|
|
1657
1702
|
const segments = path.split(".");
|
|
1658
1703
|
let cursor = config;
|
|
@@ -1677,6 +1722,7 @@ function placeholderFallback(path) {
|
|
|
1677
1722
|
// src/lib/render-plan.ts
|
|
1678
1723
|
var CORE_SOURCE_ID = "@navori/core";
|
|
1679
1724
|
var CORE_MANAGED_ASSETS = [
|
|
1725
|
+
{ id: "orquestacion", relPath: "core-assets/managed/orquestacion.md", availableLanguages: ["es"] },
|
|
1680
1726
|
{ id: "idioma-rol", relPath: "core-assets/managed/idioma-rol.md", availableLanguages: ["es"] },
|
|
1681
1727
|
{ id: "formato-respuesta", relPath: "core-assets/managed/formato-respuesta.md", availableLanguages: ["es"] },
|
|
1682
1728
|
{ id: "tipado-fuerte", relPath: "core-assets/managed/tipado-fuerte.md", availableLanguages: ["es"], condition: "project.typedLanguage" },
|
|
@@ -1884,6 +1930,16 @@ function computeRenderPlan(existing, inputConfig, repoRoot, options = {}) {
|
|
|
1884
1930
|
updatesAvailable
|
|
1885
1931
|
};
|
|
1886
1932
|
}
|
|
1933
|
+
var CLAUDE_COMPUTED_BLOCK_IDS = [
|
|
1934
|
+
"skills-index",
|
|
1935
|
+
"agentes-disponibles",
|
|
1936
|
+
"contexto-proyecto"
|
|
1937
|
+
];
|
|
1938
|
+
function canonicalManagedOrder(config, repoRoot) {
|
|
1939
|
+
const plan = computeRenderPlan("", config, repoRoot);
|
|
1940
|
+
const ids = plan.entries.filter((entry) => entry.newContent !== null).map((entry) => entry.asset.id);
|
|
1941
|
+
return [...ids, ...CLAUDE_COMPUTED_BLOCK_IDS];
|
|
1942
|
+
}
|
|
1887
1943
|
|
|
1888
1944
|
// src/engines/claude/settings-detection.ts
|
|
1889
1945
|
var NAVORI_OWNERSHIP_MARKER = "$navori";
|
|
@@ -2339,6 +2395,34 @@ function buildSkillsIndexBody(config, localSkills, repoRoot) {
|
|
|
2339
2395
|
""
|
|
2340
2396
|
].join("\n");
|
|
2341
2397
|
}
|
|
2398
|
+
var AGENTS_INDEX_ID = "agentes-disponibles";
|
|
2399
|
+
var AGENT_WHEN = {
|
|
2400
|
+
implementer: "Escribe c\xF3digo y tests de UNA tarea acotada con scope claro.",
|
|
2401
|
+
reviewer: "Valida un diff contra spec y calidad antes de cerrar (APPROVED / CHANGES_REQUESTED).",
|
|
2402
|
+
researcher: "Responde una pregunta concreta del repo (\xBFpasa Y? \xBFqu\xE9 consume X?) con evidencia citada.",
|
|
2403
|
+
explorer: "Mapea un \xE1rea o m\xF3dulo amplio: estructura, entry points, dependencias.",
|
|
2404
|
+
"ticket-audit": "Analiza a fondo un ticket complejo (bug cr\xEDtico, migraci\xF3n, feature multi-capa) antes de descomponer.",
|
|
2405
|
+
"commit-pr-pilot": "Redacta commits Conventional y abre el PR tras la aprobaci\xF3n del reviewer."
|
|
2406
|
+
};
|
|
2407
|
+
function buildAgentsIndexBody(config) {
|
|
2408
|
+
const rows = [];
|
|
2409
|
+
for (const agent of CORE_AGENTS) {
|
|
2410
|
+
if (agent.id === "leader") continue;
|
|
2411
|
+
if (!isAgentEnabled(config, agent.harnessKey)) continue;
|
|
2412
|
+
const when = AGENT_WHEN[agent.id];
|
|
2413
|
+
if (!when) continue;
|
|
2414
|
+
rows.push(`- \`${agent.id}\` \u2014 ${when}`);
|
|
2415
|
+
}
|
|
2416
|
+
if (rows.length === 0) return null;
|
|
2417
|
+
return [
|
|
2418
|
+
"## Agentes disponibles",
|
|
2419
|
+
"",
|
|
2420
|
+
'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.',
|
|
2421
|
+
"",
|
|
2422
|
+
...rows,
|
|
2423
|
+
""
|
|
2424
|
+
].join("\n");
|
|
2425
|
+
}
|
|
2342
2426
|
var CONTEXTO_PROYECTO_ID = "contexto-proyecto";
|
|
2343
2427
|
function buildContextoProyectoBody(config) {
|
|
2344
2428
|
const proj = config.project ?? {};
|
|
@@ -2422,6 +2506,26 @@ function renderClaudeEngine(cwd, inputConfig, options = {}) {
|
|
|
2422
2506
|
} else {
|
|
2423
2507
|
claudeMdContent = removeManagedSection(claudeMdContent, SKILLS_INDEX_ID);
|
|
2424
2508
|
}
|
|
2509
|
+
const agentsIndexBody = buildAgentsIndexBody(config);
|
|
2510
|
+
if (agentsIndexBody !== null) {
|
|
2511
|
+
const result = injectManagedSection(
|
|
2512
|
+
claudeMdContent,
|
|
2513
|
+
AGENTS_INDEX_ID,
|
|
2514
|
+
agentsIndexBody,
|
|
2515
|
+
CORE_META,
|
|
2516
|
+
"html",
|
|
2517
|
+
options.forceIds?.has(AGENTS_INDEX_ID) ?? false
|
|
2518
|
+
);
|
|
2519
|
+
claudeMdContent = result.output;
|
|
2520
|
+
claudeMdPlan.entries.push({
|
|
2521
|
+
asset: { id: AGENTS_INDEX_ID, relPath: "(computed)" },
|
|
2522
|
+
source: "core",
|
|
2523
|
+
status: result.status,
|
|
2524
|
+
newContent: null
|
|
2525
|
+
});
|
|
2526
|
+
} else {
|
|
2527
|
+
claudeMdContent = removeManagedSection(claudeMdContent, AGENTS_INDEX_ID);
|
|
2528
|
+
}
|
|
2425
2529
|
const contextoBody = buildContextoProyectoBody(config);
|
|
2426
2530
|
if (contextoBody !== null) {
|
|
2427
2531
|
const result = injectManagedSection(
|
|
@@ -2442,6 +2546,13 @@ function renderClaudeEngine(cwd, inputConfig, options = {}) {
|
|
|
2442
2546
|
} else {
|
|
2443
2547
|
claudeMdContent = removeManagedSection(claudeMdContent, CONTEXTO_PROYECTO_ID);
|
|
2444
2548
|
}
|
|
2549
|
+
const reorder = reorderManagedBlocks(claudeMdContent, canonicalManagedOrder(config, repoRoot));
|
|
2550
|
+
claudeMdContent = reorder.output;
|
|
2551
|
+
if (reorder.blockedByInterleaving) {
|
|
2552
|
+
warnings.push(
|
|
2553
|
+
"CLAUDE.md: los bloques managed est\xE1n fuera del orden can\xF3nico, pero hay texto tuyo intercalado entre bloques, as\xED que no los reorden\xE9. Mueve ese texto arriba del primer bloque managed o abajo del \xFAltimo para que navori pueda ordenarlos."
|
|
2554
|
+
);
|
|
2555
|
+
}
|
|
2445
2556
|
if (claudeMdContent !== claudeMdExisting) {
|
|
2446
2557
|
pending.push({
|
|
2447
2558
|
path: claudeMdPath,
|
|
@@ -2846,6 +2957,96 @@ function planPluginScript(cwd, script, config) {
|
|
|
2846
2957
|
};
|
|
2847
2958
|
}
|
|
2848
2959
|
|
|
2960
|
+
// src/engines/agents-md/index.ts
|
|
2961
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync12 } from "fs";
|
|
2962
|
+
import { basename as basename4, dirname as dirname6, join as join10 } from "path";
|
|
2963
|
+
var MANAGED_ID = "navori-agents";
|
|
2964
|
+
var CORE_META2 = { source: "@navori/core", version: readBundledCoreVersion() };
|
|
2965
|
+
var CORE_SKILLS2 = ["verify-before-done", "loop-back-debug", "review-diff"];
|
|
2966
|
+
var HEADER = "# AGENTS.md\n";
|
|
2967
|
+
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";
|
|
2968
|
+
function buildSkillsSection(config, repoRoot) {
|
|
2969
|
+
const rows = [];
|
|
2970
|
+
const listed = /* @__PURE__ */ new Set();
|
|
2971
|
+
for (const id of CORE_SKILLS2) {
|
|
2972
|
+
rows.push(`- \`${id}\` \u2014 navori`);
|
|
2973
|
+
listed.add(id);
|
|
2974
|
+
}
|
|
2975
|
+
if (config.preset && config.preset !== "custom") {
|
|
2976
|
+
try {
|
|
2977
|
+
const loaded = loadPreset(config.preset, repoRoot);
|
|
2978
|
+
for (const e of loaded?.def.extras.skills ?? []) {
|
|
2979
|
+
if (e.condition) continue;
|
|
2980
|
+
const name = basename4(e.destRelPath).replace(/\.md$/, "");
|
|
2981
|
+
if (listed.has(name)) continue;
|
|
2982
|
+
rows.push(`- \`${name}\` \u2014 preset (\`${config.preset}\`)`);
|
|
2983
|
+
listed.add(name);
|
|
2984
|
+
}
|
|
2985
|
+
} catch {
|
|
2986
|
+
}
|
|
2987
|
+
}
|
|
2988
|
+
for (const id of config.project?.libraries ?? []) {
|
|
2989
|
+
if (listed.has(id) || !librarySkillById(id)) continue;
|
|
2990
|
+
rows.push(`- \`${id}\` \u2014 library (detected)`);
|
|
2991
|
+
listed.add(id);
|
|
2992
|
+
}
|
|
2993
|
+
if (rows.length === 0) return null;
|
|
2994
|
+
return ["## Skills disponibles", "", ...rows, ""].join("\n");
|
|
2995
|
+
}
|
|
2996
|
+
function buildWorkflowSection() {
|
|
2997
|
+
return [
|
|
2998
|
+
"## Flujo de trabajo",
|
|
2999
|
+
"",
|
|
3000
|
+
"- Para tareas no triviales: an\xE1lisis \u2192 plan \u2192 implementaci\xF3n. De una en una.",
|
|
3001
|
+
"- Antes de codear: \xBFes lo m\xE1s simple? \xBFlegible en 6 meses? \xBFmantiene el patr\xF3n existente?",
|
|
3002
|
+
"- Busca con herramientas read-only (no leas el repo entero); cita `archivo:l\xEDnea`.",
|
|
3003
|
+
"- Cierra con el quality gate del proyecto en verde antes de dar por terminado.",
|
|
3004
|
+
""
|
|
3005
|
+
].join("\n");
|
|
3006
|
+
}
|
|
3007
|
+
function buildManagedBody(config, repoRoot) {
|
|
3008
|
+
const plan = computeRenderPlan("", config, repoRoot);
|
|
3009
|
+
const ruleBlocks = plan.entries.filter(
|
|
3010
|
+
(e) => e.newContent != null && e.status !== "removed-condition-false" && e.asset.id !== "orquestacion" && (e.source === "core" || e.source === config.preset)
|
|
3011
|
+
).map((e) => e.newContent.trim());
|
|
3012
|
+
const skills = buildSkillsSection(config, repoRoot);
|
|
3013
|
+
const sections = [
|
|
3014
|
+
"> Contexto del proyecto generado por navori. Lo leen Cursor, Codex, Gemini y Copilot.",
|
|
3015
|
+
...ruleBlocks,
|
|
3016
|
+
...skills ? [skills] : [],
|
|
3017
|
+
buildWorkflowSection()
|
|
3018
|
+
];
|
|
3019
|
+
return sections.join("\n\n").trim() + "\n";
|
|
3020
|
+
}
|
|
3021
|
+
function renderAgentsMdEngine(cwd, inputConfig, options = {}) {
|
|
3022
|
+
const config = effectiveConfig(inputConfig);
|
|
3023
|
+
const repoRoot = options.repoRoot ?? cwd;
|
|
3024
|
+
const agentsMdPath = join10(cwd, "AGENTS.md");
|
|
3025
|
+
const firstRender = !existsSync12(agentsMdPath);
|
|
3026
|
+
const existing = firstRender ? HEADER : readFileSync12(agentsMdPath, "utf-8");
|
|
3027
|
+
const body = buildManagedBody(config, repoRoot);
|
|
3028
|
+
const result = injectManagedSection(existing, MANAGED_ID, body, CORE_META2, "html");
|
|
3029
|
+
const output = firstRender ? result.output + USER_SECTION : result.output;
|
|
3030
|
+
const written = [];
|
|
3031
|
+
const skipped = [];
|
|
3032
|
+
let backupPath = null;
|
|
3033
|
+
if (result.status === "user-modified-skipped") {
|
|
3034
|
+
skipped.push({ path: "AGENTS.md", reason: "managed block edited by hand" });
|
|
3035
|
+
} else if (result.status === "unchanged") {
|
|
3036
|
+
} else {
|
|
3037
|
+
written.push({ path: "AGENTS.md", status: result.status });
|
|
3038
|
+
if (!options.dryRun) {
|
|
3039
|
+
if (!firstRender) {
|
|
3040
|
+
const handle = createBackup(cwd, ["AGENTS.md"]);
|
|
3041
|
+
if (handle.files.length > 0) backupPath = handle.path;
|
|
3042
|
+
}
|
|
3043
|
+
mkdirSync5(dirname6(agentsMdPath), { recursive: true });
|
|
3044
|
+
writeFileAtomic(agentsMdPath, output);
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
return { written, skipped, warnings: [], backupPath };
|
|
3048
|
+
}
|
|
3049
|
+
|
|
2849
3050
|
// src/lib/style.ts
|
|
2850
3051
|
import pc from "picocolors";
|
|
2851
3052
|
var color = pc;
|
|
@@ -2923,6 +3124,25 @@ function effectiveConfigForWorkspace(root, workspace) {
|
|
|
2923
3124
|
}
|
|
2924
3125
|
|
|
2925
3126
|
// src/commands/render.ts
|
|
3127
|
+
function renderNonClaudeEngines(cwd, config, engines, dryRun) {
|
|
3128
|
+
const out = [];
|
|
3129
|
+
for (const eng of engines) {
|
|
3130
|
+
if (eng === "claude") continue;
|
|
3131
|
+
if (eng === "agents-md") {
|
|
3132
|
+
const r = renderAgentsMdEngine(cwd, config, { dryRun, repoRoot: cwd });
|
|
3133
|
+
out.push({ engine: eng, ...r });
|
|
3134
|
+
} else {
|
|
3135
|
+
out.push({
|
|
3136
|
+
engine: eng,
|
|
3137
|
+
written: [],
|
|
3138
|
+
skipped: [],
|
|
3139
|
+
warnings: [`El engine '${eng}' todav\xEDa no tiene adapter en navori; se omiti\xF3.`],
|
|
3140
|
+
backupPath: null
|
|
3141
|
+
});
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
return out;
|
|
3145
|
+
}
|
|
2926
3146
|
function runRender(cwd, dryRunOrOptions = false, force = false) {
|
|
2927
3147
|
const opts = typeof dryRunOrOptions === "boolean" ? { dryRun: dryRunOrOptions, force } : dryRunOrOptions;
|
|
2928
3148
|
const dryRun = Boolean(opts.dryRun);
|
|
@@ -2930,7 +3150,7 @@ function runRender(cwd, dryRunOrOptions = false, force = false) {
|
|
|
2930
3150
|
const workspaceFilter = opts.workspaceFilter ?? null;
|
|
2931
3151
|
const configPath = `${cwd}/navori.config.json`;
|
|
2932
3152
|
const claudeMdPath = `${cwd}/CLAUDE.md`;
|
|
2933
|
-
if (!
|
|
3153
|
+
if (!existsSync13(configPath)) {
|
|
2934
3154
|
return {
|
|
2935
3155
|
ok: false,
|
|
2936
3156
|
reason: `No navori.config.json at ${configPath}`,
|
|
@@ -3006,38 +3226,44 @@ function runRender(cwd, dryRunOrOptions = false, force = false) {
|
|
|
3006
3226
|
]
|
|
3007
3227
|
};
|
|
3008
3228
|
}
|
|
3009
|
-
const
|
|
3229
|
+
const engines = config.engines ?? ["claude"];
|
|
3230
|
+
const renderClaude = engines.includes("claude");
|
|
3231
|
+
const engineResult = renderClaude ? renderClaudeEngine(cwd, config, { dryRun, force: forceFlag }) : void 0;
|
|
3010
3232
|
const workspaces = [];
|
|
3011
|
-
|
|
3012
|
-
const
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3233
|
+
if (renderClaude) {
|
|
3234
|
+
for (const ws of config.monorepo?.workspaces ?? []) {
|
|
3235
|
+
const wsCwd = resolve9(cwd, ws.path);
|
|
3236
|
+
const wsConfig = effectiveConfigForWorkspace(config, ws);
|
|
3237
|
+
const wsResult = renderClaudeEngine(wsCwd, wsConfig, {
|
|
3238
|
+
dryRun,
|
|
3239
|
+
force: forceFlag,
|
|
3240
|
+
repoRoot: cwd
|
|
3241
|
+
});
|
|
3242
|
+
workspaces.push({
|
|
3243
|
+
workspacePath: ws.path,
|
|
3244
|
+
workspaceName: ws.name,
|
|
3245
|
+
filePath: `${wsCwd}/CLAUDE.md`,
|
|
3246
|
+
entries: wsResult.claudeMdEntries,
|
|
3247
|
+
written: wsResult.written.length > 0,
|
|
3248
|
+
languageFallbacks: wsResult.languageFallbacks,
|
|
3249
|
+
updatesAvailable: wsResult.updatesAvailable,
|
|
3250
|
+
backupPath: wsResult.backupPath,
|
|
3251
|
+
engineResult: wsResult
|
|
3252
|
+
});
|
|
3253
|
+
}
|
|
3030
3254
|
}
|
|
3255
|
+
const extraEngines = renderNonClaudeEngines(cwd, config, engines, dryRun);
|
|
3031
3256
|
return {
|
|
3032
3257
|
ok: true,
|
|
3033
3258
|
filePath: claudeMdPath,
|
|
3034
|
-
entries: engineResult
|
|
3035
|
-
written: engineResult
|
|
3036
|
-
languageFallbacks: engineResult
|
|
3037
|
-
updatesAvailable: engineResult
|
|
3038
|
-
backupPath: engineResult
|
|
3259
|
+
entries: engineResult?.claudeMdEntries ?? [],
|
|
3260
|
+
written: (engineResult?.written.length ?? 0) > 0,
|
|
3261
|
+
languageFallbacks: engineResult?.languageFallbacks ?? [],
|
|
3262
|
+
updatesAvailable: engineResult?.updatesAvailable ?? [],
|
|
3263
|
+
backupPath: engineResult?.backupPath ?? null,
|
|
3039
3264
|
engineResult,
|
|
3040
|
-
workspaces
|
|
3265
|
+
workspaces,
|
|
3266
|
+
extraEngines
|
|
3041
3267
|
};
|
|
3042
3268
|
}
|
|
3043
3269
|
var renderCommand = defineCommand({
|
|
@@ -3068,7 +3294,7 @@ var renderCommand = defineCommand({
|
|
|
3068
3294
|
benchStart();
|
|
3069
3295
|
const cwd = resolve9(args.cwd ?? process.cwd());
|
|
3070
3296
|
p.intro(brand("render"));
|
|
3071
|
-
if (!
|
|
3297
|
+
if (!existsSync13(cwd)) {
|
|
3072
3298
|
p.cancel(`Directory not found: ${cwd}`);
|
|
3073
3299
|
process.exit(1);
|
|
3074
3300
|
}
|
|
@@ -3113,8 +3339,17 @@ var renderCommand = defineCommand({
|
|
|
3113
3339
|
p.log.message(`${dim("Backup:")} ${ws.backupPath}`);
|
|
3114
3340
|
}
|
|
3115
3341
|
}
|
|
3342
|
+
for (const ee of result.extraEngines ?? []) {
|
|
3343
|
+
p.log.message(`${dim("engine")} ${color.cyan(ee.engine)}`);
|
|
3344
|
+
for (const w of ee.written) {
|
|
3345
|
+
p.log.message(` ${renderStatusSymbol(w.status)} ${w.path} ${dim("(")}${renderStatusLabel(w.status)}${dim(")")}`);
|
|
3346
|
+
}
|
|
3347
|
+
for (const s of ee.skipped) p.log.warn(` ${s.path}: ${s.reason}`);
|
|
3348
|
+
for (const warn of ee.warnings) p.log.warn(` ${warn}`);
|
|
3349
|
+
if (ee.backupPath) p.log.message(` ${dim("Backup:")} ${ee.backupPath}`);
|
|
3350
|
+
}
|
|
3116
3351
|
const allEntries = result.entries.concat(...result.workspaces.map((w) => w.entries));
|
|
3117
|
-
const anyPending = result.written || result.workspaces.some((w) => w.written);
|
|
3352
|
+
const anyPending = result.written || result.workspaces.some((w) => w.written) || (result.extraEngines ?? []).some((e) => e.written.length > 0);
|
|
3118
3353
|
const summary = summarize(allEntries);
|
|
3119
3354
|
if (preview) {
|
|
3120
3355
|
if (anyPending) {
|
|
@@ -3480,7 +3715,7 @@ function formatWorkspaceSummary(ws, lang = "es") {
|
|
|
3480
3715
|
}
|
|
3481
3716
|
|
|
3482
3717
|
// src/engines/claude/prompts-loader.ts
|
|
3483
|
-
import { readFileSync as
|
|
3718
|
+
import { readFileSync as readFileSync13, existsSync as existsSync14 } from "fs";
|
|
3484
3719
|
import { resolve as resolve10 } from "path";
|
|
3485
3720
|
import { z as z7 } from "zod";
|
|
3486
3721
|
var SelectOptionSchema = z7.object({
|
|
@@ -3520,10 +3755,10 @@ function loadPrompts(enabledPlugins) {
|
|
|
3520
3755
|
}
|
|
3521
3756
|
function loadCorePrompts(warnings) {
|
|
3522
3757
|
const path = resolve10(getCoreRoot(), CORE_PROMPTS_REL);
|
|
3523
|
-
if (!
|
|
3758
|
+
if (!existsSync14(path)) return [];
|
|
3524
3759
|
let parsed;
|
|
3525
3760
|
try {
|
|
3526
|
-
parsed = JSON.parse(
|
|
3761
|
+
parsed = JSON.parse(readFileSync13(path, "utf-8"));
|
|
3527
3762
|
} catch (err) {
|
|
3528
3763
|
warnings.push(`core prompts.json no parsea: ${err.message}`);
|
|
3529
3764
|
return [];
|
|
@@ -3537,8 +3772,8 @@ function loadCorePrompts(warnings) {
|
|
|
3537
3772
|
}
|
|
3538
3773
|
|
|
3539
3774
|
// src/lib/scan.ts
|
|
3540
|
-
import { existsSync as
|
|
3541
|
-
import { join as
|
|
3775
|
+
import { existsSync as existsSync15, readdirSync as readdirSync6 } from "fs";
|
|
3776
|
+
import { join as join11 } from "path";
|
|
3542
3777
|
function scanMonorepoWorkspaces(cwd) {
|
|
3543
3778
|
const patterns = collectWorkspacePatterns(cwd);
|
|
3544
3779
|
if (patterns.length === 0) return [];
|
|
@@ -3565,9 +3800,9 @@ function walk(cwd, accum, remaining) {
|
|
|
3565
3800
|
}
|
|
3566
3801
|
const [head, ...tail] = remaining;
|
|
3567
3802
|
const currentRel = accum.join("/");
|
|
3568
|
-
const currentAbs = currentRel ?
|
|
3803
|
+
const currentAbs = currentRel ? join11(cwd, currentRel) : cwd;
|
|
3569
3804
|
if (head === "*") {
|
|
3570
|
-
if (!
|
|
3805
|
+
if (!existsSync15(currentAbs)) return [];
|
|
3571
3806
|
let entries;
|
|
3572
3807
|
try {
|
|
3573
3808
|
entries = readdirSync6(currentAbs, { withFileTypes: true });
|
|
@@ -3576,8 +3811,8 @@ function walk(cwd, accum, remaining) {
|
|
|
3576
3811
|
}
|
|
3577
3812
|
return entries.filter((d) => d.isDirectory() && !d.name.startsWith(".")).flatMap((d) => walk(cwd, [...accum, d.name], tail));
|
|
3578
3813
|
}
|
|
3579
|
-
const next =
|
|
3580
|
-
if (!
|
|
3814
|
+
const next = join11(currentAbs, head);
|
|
3815
|
+
if (!existsSync15(next)) return [];
|
|
3581
3816
|
return walk(cwd, [...accum, head], tail);
|
|
3582
3817
|
}
|
|
3583
3818
|
function diffWorkspaces(detected, configured) {
|
|
@@ -3589,8 +3824,8 @@ function diffWorkspaces(detected, configured) {
|
|
|
3589
3824
|
return { added, existing, orphan };
|
|
3590
3825
|
}
|
|
3591
3826
|
function describeWorkspace(cwd, relPath) {
|
|
3592
|
-
const abs =
|
|
3593
|
-
if (!
|
|
3827
|
+
const abs = join11(cwd, relPath);
|
|
3828
|
+
if (!existsSync15(join11(abs, "package.json"))) return null;
|
|
3594
3829
|
const project = detectProject(abs);
|
|
3595
3830
|
return {
|
|
3596
3831
|
name: project.name ?? relPath.split("/").pop(),
|
|
@@ -3671,11 +3906,11 @@ var initCommand = defineCommand2({
|
|
|
3671
3906
|
p2.intro(brand("init"));
|
|
3672
3907
|
const bootstrapLang = normalizeLang(args.lang) ?? "es";
|
|
3673
3908
|
const bootstrapT = t(bootstrapLang);
|
|
3674
|
-
if (!
|
|
3909
|
+
if (!existsSync16(cwd)) {
|
|
3675
3910
|
p2.cancel(bootstrapT.dirNotFound(cwd));
|
|
3676
3911
|
process.exit(1);
|
|
3677
3912
|
}
|
|
3678
|
-
if (
|
|
3913
|
+
if (existsSync16(configPath)) {
|
|
3679
3914
|
p2.cancel(bootstrapT.configExists(configPath));
|
|
3680
3915
|
process.exit(1);
|
|
3681
3916
|
}
|
|
@@ -4289,7 +4524,7 @@ ${lines}${more}`);
|
|
|
4289
4524
|
}
|
|
4290
4525
|
}
|
|
4291
4526
|
async function offerPreCommitHook(cwd, opts) {
|
|
4292
|
-
if (!
|
|
4527
|
+
if (!existsSync16(join12(cwd, ".git"))) return;
|
|
4293
4528
|
let wanted = opts.force;
|
|
4294
4529
|
if (!wanted && !opts.autoYes) {
|
|
4295
4530
|
const answer = await p2.confirm({
|
|
@@ -4308,10 +4543,10 @@ async function offerPreCommitHook(cwd, opts) {
|
|
|
4308
4543
|
}
|
|
4309
4544
|
}
|
|
4310
4545
|
function writePreCommitHook(cwd) {
|
|
4311
|
-
const huskyDir =
|
|
4312
|
-
const hookPath =
|
|
4546
|
+
const huskyDir = join12(cwd, ".husky");
|
|
4547
|
+
const hookPath = existsSync16(huskyDir) ? join12(huskyDir, "pre-commit") : join12(cwd, ".git", "hooks", "pre-commit");
|
|
4313
4548
|
const relPath = relative3(cwd, hookPath);
|
|
4314
|
-
if (
|
|
4549
|
+
if (existsSync16(hookPath)) return { ok: false, path: relPath };
|
|
4315
4550
|
const body = [
|
|
4316
4551
|
"#!/usr/bin/env sh",
|
|
4317
4552
|
"# navori pre-commit drift gate \u2014 scaffolded by 'navori init' (opt-in).",
|
|
@@ -4323,7 +4558,7 @@ function writePreCommitHook(cwd) {
|
|
|
4323
4558
|
"fi",
|
|
4324
4559
|
""
|
|
4325
4560
|
].join("\n");
|
|
4326
|
-
|
|
4561
|
+
mkdirSync6(dirname7(hookPath), { recursive: true });
|
|
4327
4562
|
writeFileAtomic(hookPath, body);
|
|
4328
4563
|
try {
|
|
4329
4564
|
chmodSync2(hookPath, 493);
|
|
@@ -4548,15 +4783,15 @@ function formatProjectValue(v) {
|
|
|
4548
4783
|
// src/commands/doctor.ts
|
|
4549
4784
|
import { defineCommand as defineCommand3 } from "citty";
|
|
4550
4785
|
import * as p3 from "@clack/prompts";
|
|
4551
|
-
import { existsSync as
|
|
4552
|
-
import { join as
|
|
4786
|
+
import { existsSync as existsSync18, readFileSync as readFileSync15, readdirSync as readdirSync8 } from "fs";
|
|
4787
|
+
import { join as join14, resolve as resolve12, relative as relative4 } from "path";
|
|
4553
4788
|
|
|
4554
4789
|
// src/lib/health.ts
|
|
4555
|
-
import { existsSync as
|
|
4556
|
-
import { join as
|
|
4790
|
+
import { existsSync as existsSync17, readFileSync as readFileSync14, readdirSync as readdirSync7 } from "fs";
|
|
4791
|
+
import { join as join13 } from "path";
|
|
4557
4792
|
function listMarkers(filePath) {
|
|
4558
|
-
if (!
|
|
4559
|
-
const content =
|
|
4793
|
+
if (!existsSync17(filePath)) return [];
|
|
4794
|
+
const content = readFileSync14(filePath, "utf-8");
|
|
4560
4795
|
const re = /<!-- navori:managed [^>]*-->/g;
|
|
4561
4796
|
const result = [];
|
|
4562
4797
|
for (const match of content.matchAll(re)) {
|
|
@@ -4601,10 +4836,10 @@ function scanManagedDrift(cwd, config) {
|
|
|
4601
4836
|
}
|
|
4602
4837
|
}
|
|
4603
4838
|
const files = [];
|
|
4604
|
-
if (
|
|
4839
|
+
if (existsSync17(join13(cwd, "CLAUDE.md"))) files.push("CLAUDE.md");
|
|
4605
4840
|
for (const dir of [".claude/agents", ".claude/skills"]) {
|
|
4606
|
-
const absDir =
|
|
4607
|
-
if (!
|
|
4841
|
+
const absDir = join13(cwd, dir);
|
|
4842
|
+
if (!existsSync17(absDir)) continue;
|
|
4608
4843
|
try {
|
|
4609
4844
|
for (const file of readdirSync7(absDir)) {
|
|
4610
4845
|
if (file.endsWith(".md")) files.push(`${dir}/${file}`);
|
|
@@ -4614,10 +4849,10 @@ function scanManagedDrift(cwd, config) {
|
|
|
4614
4849
|
}
|
|
4615
4850
|
}
|
|
4616
4851
|
for (const rel of files) {
|
|
4617
|
-
const abs =
|
|
4852
|
+
const abs = join13(cwd, rel);
|
|
4618
4853
|
const fileContent = (() => {
|
|
4619
4854
|
try {
|
|
4620
|
-
return
|
|
4855
|
+
return readFileSync14(abs, "utf-8");
|
|
4621
4856
|
} catch {
|
|
4622
4857
|
return null;
|
|
4623
4858
|
}
|
|
@@ -4658,21 +4893,45 @@ function scanManagedDrift(cwd, config) {
|
|
|
4658
4893
|
}
|
|
4659
4894
|
return out;
|
|
4660
4895
|
}
|
|
4896
|
+
function scanManagedOrder(cwd, config) {
|
|
4897
|
+
const claudeMdPath = join13(cwd, "CLAUDE.md");
|
|
4898
|
+
if (!existsSync17(claudeMdPath)) return null;
|
|
4899
|
+
const content = readFileSync14(claudeMdPath, "utf-8");
|
|
4900
|
+
const current = listMarkers(claudeMdPath).map((m) => m.id);
|
|
4901
|
+
if (current.length < 2) return null;
|
|
4902
|
+
const canonical = canonicalManagedOrder(config, cwd);
|
|
4903
|
+
const result = reorderManagedBlocks(content, canonical);
|
|
4904
|
+
if (!result.reordered && !result.blockedByInterleaving) return null;
|
|
4905
|
+
const rank = /* @__PURE__ */ new Map();
|
|
4906
|
+
canonical.forEach((id, i) => {
|
|
4907
|
+
if (!rank.has(id)) rank.set(id, i);
|
|
4908
|
+
});
|
|
4909
|
+
const expected = current.map((id, i) => ({ id, i, key: rank.has(id) ? rank.get(id) : canonical.length + i })).sort((a, z8) => a.key - z8.key || a.i - z8.i).map((x) => x.id);
|
|
4910
|
+
return { current, expected, interleaved: result.blockedByInterleaving };
|
|
4911
|
+
}
|
|
4661
4912
|
function suggestNextSteps(state) {
|
|
4662
4913
|
const steps = [];
|
|
4663
4914
|
if (!state.claudeMdExists) {
|
|
4664
|
-
steps.push("
|
|
4915
|
+
steps.push("Corre 'navori render --apply' para generar CLAUDE.md + .claude/.");
|
|
4665
4916
|
}
|
|
4666
4917
|
if (state.missingPlugins.length > 0) {
|
|
4667
4918
|
steps.push(
|
|
4668
|
-
`
|
|
4919
|
+
`Resuelve ${state.missingPlugins.length} plugin(s) faltante(s): inst\xE1lalos o qu\xEDtalos del config.`
|
|
4669
4920
|
);
|
|
4670
4921
|
}
|
|
4671
4922
|
if (state.drifts.some((d) => d.kind === "content")) {
|
|
4672
|
-
steps.push("
|
|
4923
|
+
steps.push("Corre 'navori sync --interactive' para resolver bloques editados a mano.");
|
|
4673
4924
|
}
|
|
4674
4925
|
if (state.drifts.some((d) => d.kind === "version")) {
|
|
4675
|
-
steps.push("
|
|
4926
|
+
steps.push("Corre 'navori render --apply' para traer los bloques a la \xFAltima versi\xF3n.");
|
|
4927
|
+
}
|
|
4928
|
+
if (state.orderReport && !state.orderReport.interleaved) {
|
|
4929
|
+
steps.push("Corre 'navori render --apply' para reordenar los bloques de CLAUDE.md al orden can\xF3nico.");
|
|
4930
|
+
}
|
|
4931
|
+
if (state.orderReport?.interleaved) {
|
|
4932
|
+
steps.push(
|
|
4933
|
+
"Mueve el texto que tienes entre bloques managed de CLAUDE.md arriba del primer bloque o abajo del \xFAltimo; luego corre 'navori render --apply' para reordenarlos."
|
|
4934
|
+
);
|
|
4676
4935
|
}
|
|
4677
4936
|
if (steps.length === 0) {
|
|
4678
4937
|
steps.push("Todo al d\xEDa \u2014 sin acciones pendientes.");
|
|
@@ -4699,7 +4958,7 @@ var doctorCommand = defineCommand3({
|
|
|
4699
4958
|
const configPath = `${cwd}/navori.config.json`;
|
|
4700
4959
|
const claudeMdPath = `${cwd}/CLAUDE.md`;
|
|
4701
4960
|
if (!args.json) p3.intro(brand("doctor"));
|
|
4702
|
-
if (!
|
|
4961
|
+
if (!existsSync18(cwd)) {
|
|
4703
4962
|
if (args.json) {
|
|
4704
4963
|
console.log(JSON.stringify({ ok: false, error: "directory-missing", cwd }));
|
|
4705
4964
|
} else {
|
|
@@ -4707,7 +4966,7 @@ var doctorCommand = defineCommand3({
|
|
|
4707
4966
|
}
|
|
4708
4967
|
process.exit(1);
|
|
4709
4968
|
}
|
|
4710
|
-
if (!
|
|
4969
|
+
if (!existsSync18(configPath)) {
|
|
4711
4970
|
if (args.json) {
|
|
4712
4971
|
console.log(JSON.stringify({ ok: false, error: "config-missing", configPath }));
|
|
4713
4972
|
} else {
|
|
@@ -4737,6 +4996,7 @@ var doctorCommand = defineCommand3({
|
|
|
4737
4996
|
const markers = listMarkers(claudeMdPath);
|
|
4738
4997
|
const missingPlugins = collectMissingPlugins(config);
|
|
4739
4998
|
const drifts = scanManagedDrift(cwd, config);
|
|
4999
|
+
const orderReport = scanManagedOrder(cwd, config);
|
|
4740
5000
|
const corruptedSettings = scanCorruptedSettings(cwd);
|
|
4741
5001
|
const missingInvariants = scanMissingInvariants(cwd, config);
|
|
4742
5002
|
const resolvedPreset = config.preset !== "custom" ? resolvePreset(config.preset, cwd) : null;
|
|
@@ -4753,14 +5013,15 @@ var doctorCommand = defineCommand3({
|
|
|
4753
5013
|
configPath,
|
|
4754
5014
|
config,
|
|
4755
5015
|
checks: {
|
|
4756
|
-
claudeMdExists:
|
|
4757
|
-
agentsMdExists:
|
|
4758
|
-
claudeDirExists:
|
|
4759
|
-
progressDirExists:
|
|
5016
|
+
claudeMdExists: existsSync18(claudeMdPath),
|
|
5017
|
+
agentsMdExists: existsSync18(`${cwd}/AGENTS.md`),
|
|
5018
|
+
claudeDirExists: existsSync18(`${cwd}/.claude`),
|
|
5019
|
+
progressDirExists: existsSync18(`${cwd}/${config.progress?.dir ?? "progress"}`)
|
|
4760
5020
|
},
|
|
4761
5021
|
managedBlocks: markers,
|
|
4762
5022
|
missingPlugins,
|
|
4763
5023
|
drifts,
|
|
5024
|
+
orderReport,
|
|
4764
5025
|
corruptedSettings,
|
|
4765
5026
|
missingInvariants,
|
|
4766
5027
|
missingPreset,
|
|
@@ -4844,7 +5105,7 @@ ${lines.join("\n")}`
|
|
|
4844
5105
|
);
|
|
4845
5106
|
}
|
|
4846
5107
|
const missingLocalSkills = (config.project?.localSkills ?? []).filter(
|
|
4847
|
-
(name) => !
|
|
5108
|
+
(name) => !existsSync18(join14(cwd, ".claude/skills", `${name}.md`))
|
|
4848
5109
|
);
|
|
4849
5110
|
if (missingLocalSkills.length > 0) {
|
|
4850
5111
|
const lines = missingLocalSkills.map(
|
|
@@ -4884,10 +5145,26 @@ ${lines.join("\n")}`
|
|
|
4884
5145
|
${lines.join("\n")}`
|
|
4885
5146
|
);
|
|
4886
5147
|
}
|
|
5148
|
+
if (orderReport) {
|
|
5149
|
+
if (orderReport.interleaved) {
|
|
5150
|
+
p3.log.warn(
|
|
5151
|
+
`Bloques managed de CLAUDE.md fuera del orden can\xF3nico \u2014 NO se pueden reordenar autom\xE1ticamente porque hay texto tuyo entre bloques. Mueve ese texto arriba del primer bloque managed o abajo del \xFAltimo; luego corre 'navori render --apply'.
|
|
5152
|
+
orden actual: ${orderReport.current.join(", ")}
|
|
5153
|
+
orden can\xF3nico: ${orderReport.expected.join(", ")}`
|
|
5154
|
+
);
|
|
5155
|
+
} else {
|
|
5156
|
+
p3.log.warn(
|
|
5157
|
+
`Bloques managed de CLAUDE.md fuera del orden can\xF3nico \u2014 corre 'navori render --apply' o 'navori sync' para reordenarlos (el primer bloque marca el centro de gravedad del harness).
|
|
5158
|
+
orden actual: ${orderReport.current.join(", ")}
|
|
5159
|
+
orden can\xF3nico: ${orderReport.expected.join(", ")}`
|
|
5160
|
+
);
|
|
5161
|
+
}
|
|
5162
|
+
}
|
|
4887
5163
|
const nextSteps = suggestNextSteps({
|
|
4888
5164
|
claudeMdExists: report.checks.claudeMdExists,
|
|
4889
5165
|
missingPlugins,
|
|
4890
|
-
drifts
|
|
5166
|
+
drifts,
|
|
5167
|
+
orderReport
|
|
4891
5168
|
});
|
|
4892
5169
|
p3.note(
|
|
4893
5170
|
nextSteps.map((s) => ` ${color.cyan(sym.bullet)} ${s}`).join("\n"),
|
|
@@ -4903,10 +5180,10 @@ ${lines.join("\n")}`
|
|
|
4903
5180
|
}
|
|
4904
5181
|
});
|
|
4905
5182
|
function scanCorruptedSettings(cwd) {
|
|
4906
|
-
const path =
|
|
4907
|
-
if (!
|
|
5183
|
+
const path = join14(cwd, ".claude/settings.json");
|
|
5184
|
+
if (!existsSync18(path)) return [];
|
|
4908
5185
|
try {
|
|
4909
|
-
JSON.parse(
|
|
5186
|
+
JSON.parse(readFileSync15(path, "utf-8"));
|
|
4910
5187
|
return [];
|
|
4911
5188
|
} catch (err) {
|
|
4912
5189
|
return [{ path: ".claude/settings.json", error: err.message }];
|
|
@@ -4926,7 +5203,7 @@ function scanMissingPresetFiles(cwd, config) {
|
|
|
4926
5203
|
const missing = [];
|
|
4927
5204
|
for (const e of [...managed, ...agents, ...skills, ...hooks]) {
|
|
4928
5205
|
const abs = resolve12(loaded.assetRoot, e.relPath);
|
|
4929
|
-
if (!
|
|
5206
|
+
if (!existsSync18(abs)) missing.push({ id: e.id, path: relative4(cwd, abs) });
|
|
4930
5207
|
}
|
|
4931
5208
|
return missing;
|
|
4932
5209
|
}
|
|
@@ -4962,15 +5239,15 @@ function scanMissingInvariants(cwd, config) {
|
|
|
4962
5239
|
}
|
|
4963
5240
|
function readRenderedText(cwd) {
|
|
4964
5241
|
const parts = [];
|
|
4965
|
-
const claudeMd =
|
|
4966
|
-
if (
|
|
5242
|
+
const claudeMd = join14(cwd, "CLAUDE.md");
|
|
5243
|
+
if (existsSync18(claudeMd)) {
|
|
4967
5244
|
try {
|
|
4968
|
-
parts.push(
|
|
5245
|
+
parts.push(readFileSync15(claudeMd, "utf-8"));
|
|
4969
5246
|
} catch {
|
|
4970
5247
|
}
|
|
4971
5248
|
}
|
|
4972
|
-
const claudeDir =
|
|
4973
|
-
if (
|
|
5249
|
+
const claudeDir = join14(cwd, ".claude");
|
|
5250
|
+
if (existsSync18(claudeDir)) collectText(claudeDir, parts);
|
|
4974
5251
|
return parts.join("\n");
|
|
4975
5252
|
}
|
|
4976
5253
|
function collectText(dir, parts) {
|
|
@@ -4981,12 +5258,12 @@ function collectText(dir, parts) {
|
|
|
4981
5258
|
return;
|
|
4982
5259
|
}
|
|
4983
5260
|
for (const entry of entries) {
|
|
4984
|
-
const abs =
|
|
5261
|
+
const abs = join14(dir, entry.name);
|
|
4985
5262
|
if (entry.isDirectory()) {
|
|
4986
5263
|
collectText(abs, parts);
|
|
4987
5264
|
} else if (entry.isFile() && TEXT_EXTENSIONS.some((e) => entry.name.endsWith(e))) {
|
|
4988
5265
|
try {
|
|
4989
|
-
parts.push(
|
|
5266
|
+
parts.push(readFileSync15(abs, "utf-8"));
|
|
4990
5267
|
} catch {
|
|
4991
5268
|
}
|
|
4992
5269
|
}
|
|
@@ -5018,8 +5295,8 @@ function collectAssignments(config) {
|
|
|
5018
5295
|
// src/commands/sync.ts
|
|
5019
5296
|
import { defineCommand as defineCommand4 } from "citty";
|
|
5020
5297
|
import * as p4 from "@clack/prompts";
|
|
5021
|
-
import { existsSync as
|
|
5022
|
-
import { resolve as resolve13, join as
|
|
5298
|
+
import { existsSync as existsSync19, readFileSync as readFileSync16 } from "fs";
|
|
5299
|
+
import { resolve as resolve13, join as join15 } from "path";
|
|
5023
5300
|
|
|
5024
5301
|
// src/lib/diff.ts
|
|
5025
5302
|
function formatLineDiff(current, proposed, _options = {}) {
|
|
@@ -5064,11 +5341,11 @@ var syncCommand = defineCommand4({
|
|
|
5064
5341
|
const cwd = resolve13(args.cwd ?? process.cwd());
|
|
5065
5342
|
const configPath = `${cwd}/navori.config.json`;
|
|
5066
5343
|
p4.intro(brand("sync"));
|
|
5067
|
-
if (!
|
|
5344
|
+
if (!existsSync19(cwd)) {
|
|
5068
5345
|
p4.cancel(`Directory not found: ${cwd}`);
|
|
5069
5346
|
process.exit(1);
|
|
5070
5347
|
}
|
|
5071
|
-
if (!
|
|
5348
|
+
if (!existsSync19(configPath)) {
|
|
5072
5349
|
p4.cancel(`No navori.config.json at ${configPath}. Run 'navori init' first.`);
|
|
5073
5350
|
process.exit(1);
|
|
5074
5351
|
}
|
|
@@ -5223,8 +5500,8 @@ async function resolveConflictsInteractively(plans) {
|
|
|
5223
5500
|
(e) => e.status === "user-modified-skipped"
|
|
5224
5501
|
);
|
|
5225
5502
|
if (cmConflicts.length === 0) continue;
|
|
5226
|
-
const claudeMdPath =
|
|
5227
|
-
const existing =
|
|
5503
|
+
const claudeMdPath = join15(tp.target.cwd, "CLAUDE.md");
|
|
5504
|
+
const existing = existsSync19(claudeMdPath) ? readFileSync16(claudeMdPath, "utf-8") : "";
|
|
5228
5505
|
const skipIds = /* @__PURE__ */ new Set();
|
|
5229
5506
|
const forceIds = /* @__PURE__ */ new Set();
|
|
5230
5507
|
for (const e of cmConflicts) {
|
|
@@ -5316,13 +5593,13 @@ function summarize2(writtenCount, conflictCount) {
|
|
|
5316
5593
|
// src/commands/add.ts
|
|
5317
5594
|
import { defineCommand as defineCommand5 } from "citty";
|
|
5318
5595
|
import * as p5 from "@clack/prompts";
|
|
5319
|
-
import { existsSync as
|
|
5596
|
+
import { existsSync as existsSync21, readFileSync as readFileSync17 } from "fs";
|
|
5320
5597
|
import { resolve as resolve14 } from "path";
|
|
5321
5598
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
5322
5599
|
|
|
5323
5600
|
// src/lib/which.ts
|
|
5324
|
-
import { existsSync as
|
|
5325
|
-
import { join as
|
|
5601
|
+
import { existsSync as existsSync20, statSync as statSync6 } from "fs";
|
|
5602
|
+
import { join as join16 } from "path";
|
|
5326
5603
|
function hasBinary(name) {
|
|
5327
5604
|
const pathEnv = process.env.PATH ?? "";
|
|
5328
5605
|
const sep2 = process.platform === "win32" ? ";" : ":";
|
|
@@ -5330,8 +5607,8 @@ function hasBinary(name) {
|
|
|
5330
5607
|
const exts = process.platform === "win32" ? (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";") : [""];
|
|
5331
5608
|
for (const dir of dirs) {
|
|
5332
5609
|
for (const ext of exts) {
|
|
5333
|
-
const candidate =
|
|
5334
|
-
if (
|
|
5610
|
+
const candidate = join16(dir, name + ext);
|
|
5611
|
+
if (existsSync20(candidate)) {
|
|
5335
5612
|
try {
|
|
5336
5613
|
if (statSync6(candidate).isFile()) return true;
|
|
5337
5614
|
} catch {
|
|
@@ -5407,11 +5684,11 @@ var addCommand = defineCommand5({
|
|
|
5407
5684
|
} else {
|
|
5408
5685
|
p5.intro(brand(`add ${accent(args.plugin)}`));
|
|
5409
5686
|
}
|
|
5410
|
-
if (!
|
|
5687
|
+
if (!existsSync21(cwd)) {
|
|
5411
5688
|
p5.cancel(`Directory not found: ${cwd}`);
|
|
5412
5689
|
process.exit(1);
|
|
5413
5690
|
}
|
|
5414
|
-
if (!
|
|
5691
|
+
if (!existsSync21(configPath)) {
|
|
5415
5692
|
p5.cancel(`No navori.config.json at ${configPath}. Run 'navori init' first.`);
|
|
5416
5693
|
process.exit(1);
|
|
5417
5694
|
}
|
|
@@ -5445,7 +5722,7 @@ var addCommand = defineCommand5({
|
|
|
5445
5722
|
...config.plugins ?? {},
|
|
5446
5723
|
[plugin.manifest.id]: { enabled: true }
|
|
5447
5724
|
};
|
|
5448
|
-
const raw = JSON.parse(
|
|
5725
|
+
const raw = JSON.parse(readFileSync17(configPath, "utf-8"));
|
|
5449
5726
|
writeConfig(configPath, { ...raw, plugins: updatedPlugins });
|
|
5450
5727
|
p5.log.success(`Added '${plugin.manifest.id}' to ${configPath}`);
|
|
5451
5728
|
}
|
|
@@ -5530,8 +5807,8 @@ function printSuggestions(cwd, configPath) {
|
|
|
5530
5807
|
// src/commands/workspace.ts
|
|
5531
5808
|
import { defineCommand as defineCommand6 } from "citty";
|
|
5532
5809
|
import * as p6 from "@clack/prompts";
|
|
5533
|
-
import { existsSync as
|
|
5534
|
-
import { join as
|
|
5810
|
+
import { existsSync as existsSync22 } from "fs";
|
|
5811
|
+
import { join as join17 } from "path";
|
|
5535
5812
|
|
|
5536
5813
|
// src/lib/workspace-defaults.ts
|
|
5537
5814
|
var VALID_DEFAULT_KEYS = "branchBase, prTarget, commits, language, engines, plugins.<id>.enabled";
|
|
@@ -5567,8 +5844,8 @@ function applyDefault(current, key, rawValue) {
|
|
|
5567
5844
|
|
|
5568
5845
|
// src/commands/workspace.ts
|
|
5569
5846
|
function readRepoConfigName(repoPath) {
|
|
5570
|
-
const cfgPath =
|
|
5571
|
-
if (!
|
|
5847
|
+
const cfgPath = join17(repoPath, "navori.config.json");
|
|
5848
|
+
if (!existsSync22(cfgPath)) return null;
|
|
5572
5849
|
try {
|
|
5573
5850
|
return readConfig(cfgPath).name;
|
|
5574
5851
|
} catch {
|
|
@@ -5592,7 +5869,7 @@ var initSubCommand = defineCommand6({
|
|
|
5592
5869
|
process.exit(1);
|
|
5593
5870
|
}
|
|
5594
5871
|
const path = workspacePath(name);
|
|
5595
|
-
if (
|
|
5872
|
+
if (existsSync22(path)) {
|
|
5596
5873
|
console.error(`Workspace '${name}' already exists at ${path}`);
|
|
5597
5874
|
process.exit(1);
|
|
5598
5875
|
}
|
|
@@ -5833,14 +6110,14 @@ var deleteSubCommand = defineCommand6({
|
|
|
5833
6110
|
return;
|
|
5834
6111
|
}
|
|
5835
6112
|
}
|
|
5836
|
-
const { renameSync: renameSync3, existsSync:
|
|
6113
|
+
const { renameSync: renameSync3, existsSync: existsSync32, mkdirSync: mkdirSync11 } = await import("fs");
|
|
5837
6114
|
const { join: joinPath } = await import("path");
|
|
5838
6115
|
const { homedir: homedir2 } = await import("os");
|
|
5839
6116
|
const trashRoot = joinPath(homedir2(), ".navori", ".trash");
|
|
5840
|
-
|
|
6117
|
+
mkdirSync11(trashRoot, { recursive: true });
|
|
5841
6118
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
5842
6119
|
const dest = joinPath(trashRoot, `${name}-${ts}`);
|
|
5843
|
-
if (
|
|
6120
|
+
if (existsSync32(dir)) renameSync3(dir, dest);
|
|
5844
6121
|
p6.outro(`Moved to ${dest}. Restore manually if needed.`);
|
|
5845
6122
|
}
|
|
5846
6123
|
});
|
|
@@ -5948,7 +6225,7 @@ var renderSubCommand = defineCommand6({
|
|
|
5948
6225
|
}
|
|
5949
6226
|
const rows = [];
|
|
5950
6227
|
for (const repo of ws.repos) {
|
|
5951
|
-
if (!
|
|
6228
|
+
if (!existsSync22(repo.path)) {
|
|
5952
6229
|
rows.push({ name: repo.name, status: "missing", detail: repo.path });
|
|
5953
6230
|
continue;
|
|
5954
6231
|
}
|
|
@@ -6022,11 +6299,11 @@ var workspaceCommand = defineCommand6({
|
|
|
6022
6299
|
// src/commands/ticket.ts
|
|
6023
6300
|
import { defineCommand as defineCommand7 } from "citty";
|
|
6024
6301
|
import * as p7 from "@clack/prompts";
|
|
6025
|
-
import { readFileSync as
|
|
6302
|
+
import { readFileSync as readFileSync19 } from "fs";
|
|
6026
6303
|
|
|
6027
6304
|
// src/lib/tickets.ts
|
|
6028
|
-
import { existsSync as
|
|
6029
|
-
import { join as
|
|
6305
|
+
import { existsSync as existsSync23, readFileSync as readFileSync18, readdirSync as readdirSync9, statSync as statSync7, mkdirSync as mkdirSync7, renameSync as renameSync2, rmSync as rmSync5 } from "fs";
|
|
6306
|
+
import { join as join18, resolve as resolve15 } from "path";
|
|
6030
6307
|
var TicketError = class extends NavoriError {
|
|
6031
6308
|
constructor(message) {
|
|
6032
6309
|
super("ticket-error", message);
|
|
@@ -6035,11 +6312,11 @@ var TicketError = class extends NavoriError {
|
|
|
6035
6312
|
function ticketsDir(workspaceName) {
|
|
6036
6313
|
const ws = loadWorkspace(workspaceName);
|
|
6037
6314
|
if (!ws) throw new TicketError(`Workspace '${workspaceName}' not found`);
|
|
6038
|
-
return
|
|
6315
|
+
return join18(workspaceDirectory(workspaceName), ws.ticketsDir);
|
|
6039
6316
|
}
|
|
6040
6317
|
function readTitle(path) {
|
|
6041
6318
|
try {
|
|
6042
|
-
const content =
|
|
6319
|
+
const content = readFileSync18(path, "utf-8").split("\n");
|
|
6043
6320
|
for (const line of content) {
|
|
6044
6321
|
const trimmed = line.trim();
|
|
6045
6322
|
if (!trimmed) continue;
|
|
@@ -6052,13 +6329,13 @@ function readTitle(path) {
|
|
|
6052
6329
|
}
|
|
6053
6330
|
function listTickets(workspaceName) {
|
|
6054
6331
|
const dir = ticketsDir(workspaceName);
|
|
6055
|
-
if (!
|
|
6332
|
+
if (!existsSync23(dir)) return [];
|
|
6056
6333
|
const out = [];
|
|
6057
6334
|
const collect = (folder, state) => {
|
|
6058
|
-
if (!
|
|
6335
|
+
if (!existsSync23(folder)) return;
|
|
6059
6336
|
for (const entry of readdirSync9(folder)) {
|
|
6060
6337
|
if (!entry.endsWith(".md")) continue;
|
|
6061
|
-
const full =
|
|
6338
|
+
const full = join18(folder, entry);
|
|
6062
6339
|
try {
|
|
6063
6340
|
if (!statSync7(full).isFile()) continue;
|
|
6064
6341
|
} catch {
|
|
@@ -6073,7 +6350,7 @@ function listTickets(workspaceName) {
|
|
|
6073
6350
|
}
|
|
6074
6351
|
};
|
|
6075
6352
|
collect(dir, "active");
|
|
6076
|
-
collect(
|
|
6353
|
+
collect(join18(dir, "_archive"), "archive");
|
|
6077
6354
|
return out;
|
|
6078
6355
|
}
|
|
6079
6356
|
function findTicket(workspaceName, id) {
|
|
@@ -6108,9 +6385,9 @@ function archiveTicket(workspaceName, id) {
|
|
|
6108
6385
|
if (!summary) throw new TicketError(`Ticket '${id}' not found in workspace '${workspaceName}'`);
|
|
6109
6386
|
if (summary.state === "archive") return summary;
|
|
6110
6387
|
const dir = ticketsDir(workspaceName);
|
|
6111
|
-
const archiveDir =
|
|
6112
|
-
|
|
6113
|
-
const dest =
|
|
6388
|
+
const archiveDir = join18(dir, "_archive");
|
|
6389
|
+
mkdirSync7(archiveDir, { recursive: true });
|
|
6390
|
+
const dest = join18(archiveDir, `${id}.md`);
|
|
6114
6391
|
renameSync2(summary.path, dest);
|
|
6115
6392
|
return { id, path: dest, title: summary.title, state: "archive" };
|
|
6116
6393
|
}
|
|
@@ -6124,9 +6401,9 @@ function createTicket(workspaceName, id, title) {
|
|
|
6124
6401
|
throw new TicketError(`Invalid ticket id '${id}'. Use letters, digits, hyphens, underscores.`);
|
|
6125
6402
|
}
|
|
6126
6403
|
const dir = ticketsDir(workspaceName);
|
|
6127
|
-
if (!
|
|
6128
|
-
const path =
|
|
6129
|
-
if (
|
|
6404
|
+
if (!existsSync23(dir)) throw new TicketError(`Tickets directory does not exist: ${dir}`);
|
|
6405
|
+
const path = join18(dir, `${id}.md`);
|
|
6406
|
+
if (existsSync23(path)) throw new TicketError(`Ticket '${id}' already exists at ${path}`);
|
|
6130
6407
|
const finalTitle = title?.trim() || id;
|
|
6131
6408
|
writeFileAtomic(path, defaultTemplate(id, finalTitle));
|
|
6132
6409
|
return {
|
|
@@ -6141,10 +6418,10 @@ function findReferencingRepos(repoPaths, ticketId) {
|
|
|
6141
6418
|
const idPattern = new RegExp(`\\b${ticketId}\\b`);
|
|
6142
6419
|
for (const repoPath of repoPaths) {
|
|
6143
6420
|
const abs = resolve15(repoPath);
|
|
6144
|
-
const current =
|
|
6145
|
-
if (!
|
|
6421
|
+
const current = join18(abs, "progress", "current.md");
|
|
6422
|
+
if (!existsSync23(current)) continue;
|
|
6146
6423
|
try {
|
|
6147
|
-
const content =
|
|
6424
|
+
const content = readFileSync18(current, "utf-8");
|
|
6148
6425
|
const matches = [];
|
|
6149
6426
|
for (const line of content.split("\n")) {
|
|
6150
6427
|
if (idPattern.test(line)) matches.push(line.trim());
|
|
@@ -6231,7 +6508,7 @@ Create it with: navori ticket new ${args.workspace} ${args.id}
|
|
|
6231
6508
|
const repoPaths = (ws?.repos ?? []).map((r) => r.path);
|
|
6232
6509
|
const referencing = findReferencingRepos(repoPaths, args.id);
|
|
6233
6510
|
if (args.json) {
|
|
6234
|
-
const content =
|
|
6511
|
+
const content = readFileSync19(ticket.path, "utf-8");
|
|
6235
6512
|
console.log(JSON.stringify({ ticket, referencing, content }, null, 2));
|
|
6236
6513
|
return;
|
|
6237
6514
|
}
|
|
@@ -6243,7 +6520,7 @@ Create it with: navori ticket new ${args.workspace} ${args.id}
|
|
|
6243
6520
|
["path", ticket.path]
|
|
6244
6521
|
])
|
|
6245
6522
|
);
|
|
6246
|
-
p7.note(
|
|
6523
|
+
p7.note(readFileSync19(ticket.path, "utf-8"), "Content");
|
|
6247
6524
|
if (referencing.length === 0) {
|
|
6248
6525
|
p7.log.message(dim("Referenced in: (no repo's progress/current.md mentions this ticket)"));
|
|
6249
6526
|
} else {
|
|
@@ -6377,7 +6654,7 @@ var ticketCommand = defineCommand7({
|
|
|
6377
6654
|
// src/commands/configure.ts
|
|
6378
6655
|
import { defineCommand as defineCommand8 } from "citty";
|
|
6379
6656
|
import * as p8 from "@clack/prompts";
|
|
6380
|
-
import { existsSync as
|
|
6657
|
+
import { existsSync as existsSync24, readFileSync as readFileSync20 } from "fs";
|
|
6381
6658
|
import { resolve as resolve16 } from "path";
|
|
6382
6659
|
var ENGINE_OPTIONS2 = [
|
|
6383
6660
|
{ value: "claude", label: "Claude Code (.claude/)" },
|
|
@@ -6391,11 +6668,11 @@ function fail(msg) {
|
|
|
6391
6668
|
process.exit(1);
|
|
6392
6669
|
}
|
|
6393
6670
|
function loadOrExit(cwd) {
|
|
6394
|
-
if (!
|
|
6671
|
+
if (!existsSync24(cwd)) fail(`Directory not found: ${cwd}`);
|
|
6395
6672
|
const configPath = resolve16(cwd, "navori.config.json");
|
|
6396
|
-
if (!
|
|
6673
|
+
if (!existsSync24(configPath)) fail(`No navori.config.json at ${configPath}. Run 'navori init' first.`);
|
|
6397
6674
|
const config = readConfig(configPath);
|
|
6398
|
-
const raw = JSON.parse(
|
|
6675
|
+
const raw = JSON.parse(readFileSync20(configPath, "utf-8"));
|
|
6399
6676
|
return { config, path: configPath, raw };
|
|
6400
6677
|
}
|
|
6401
6678
|
function persist(path, raw) {
|
|
@@ -6709,7 +6986,7 @@ var configureCommand = defineCommand8({
|
|
|
6709
6986
|
// src/commands/update.ts
|
|
6710
6987
|
import { defineCommand as defineCommand9 } from "citty";
|
|
6711
6988
|
import * as p9 from "@clack/prompts";
|
|
6712
|
-
import { existsSync as
|
|
6989
|
+
import { existsSync as existsSync25, readFileSync as readFileSync21 } from "fs";
|
|
6713
6990
|
import { resolve as resolve17 } from "path";
|
|
6714
6991
|
function sameSet(a, b) {
|
|
6715
6992
|
if (a.length !== b.length) return false;
|
|
@@ -6798,11 +7075,11 @@ var updateCommand = defineCommand9({
|
|
|
6798
7075
|
const cwd = resolve17(args.cwd ?? process.cwd());
|
|
6799
7076
|
const configPath = `${cwd}/navori.config.json`;
|
|
6800
7077
|
p9.intro(brand("update"));
|
|
6801
|
-
if (!
|
|
7078
|
+
if (!existsSync25(cwd)) {
|
|
6802
7079
|
p9.cancel(`Directory not found: ${cwd}`);
|
|
6803
7080
|
process.exit(1);
|
|
6804
7081
|
}
|
|
6805
|
-
if (!
|
|
7082
|
+
if (!existsSync25(configPath)) {
|
|
6806
7083
|
p9.cancel(`No navori.config.json at ${configPath}. Run 'navori init' first.`);
|
|
6807
7084
|
process.exit(1);
|
|
6808
7085
|
}
|
|
@@ -6863,7 +7140,7 @@ ${lines.join("\n")}`);
|
|
|
6863
7140
|
}
|
|
6864
7141
|
}
|
|
6865
7142
|
if (diffs.length > 0) {
|
|
6866
|
-
const raw = JSON.parse(
|
|
7143
|
+
const raw = JSON.parse(readFileSync21(configPath, "utf-8"));
|
|
6867
7144
|
delete raw.$schema;
|
|
6868
7145
|
applyDiffs(raw, detected, diffs);
|
|
6869
7146
|
writeConfig(configPath, raw);
|
|
@@ -6896,14 +7173,14 @@ ${lines.join("\n")}`);
|
|
|
6896
7173
|
// src/commands/backup.ts
|
|
6897
7174
|
import { defineCommand as defineCommand10 } from "citty";
|
|
6898
7175
|
import * as p10 from "@clack/prompts";
|
|
6899
|
-
import { existsSync as
|
|
6900
|
-
import { join as
|
|
7176
|
+
import { existsSync as existsSync26, readdirSync as readdirSync10, statSync as statSync8, copyFileSync as copyFileSync4, mkdirSync as mkdirSync8 } from "fs";
|
|
7177
|
+
import { join as join19, relative as relative5, resolve as resolve18, dirname as dirname8 } from "path";
|
|
6901
7178
|
function listBackups() {
|
|
6902
7179
|
const root = backupRoot();
|
|
6903
|
-
if (!
|
|
7180
|
+
if (!existsSync26(root)) return [];
|
|
6904
7181
|
const entries = [];
|
|
6905
7182
|
for (const name of readdirSync10(root)) {
|
|
6906
|
-
const full =
|
|
7183
|
+
const full = join19(root, name);
|
|
6907
7184
|
try {
|
|
6908
7185
|
const stat = statSync8(full);
|
|
6909
7186
|
if (!stat.isDirectory()) continue;
|
|
@@ -6918,7 +7195,7 @@ function listBackups() {
|
|
|
6918
7195
|
function collectFiles(root, dir) {
|
|
6919
7196
|
const out = [];
|
|
6920
7197
|
for (const entry of readdirSync10(dir)) {
|
|
6921
|
-
const full =
|
|
7198
|
+
const full = join19(dir, entry);
|
|
6922
7199
|
try {
|
|
6923
7200
|
const stat = statSync8(full);
|
|
6924
7201
|
if (stat.isDirectory()) {
|
|
@@ -6984,9 +7261,9 @@ var restoreSubCommand = defineCommand10({
|
|
|
6984
7261
|
async run({ args }) {
|
|
6985
7262
|
const ts = args.timestamp;
|
|
6986
7263
|
const cwd = resolve18(args.cwd ?? process.cwd());
|
|
6987
|
-
const backupDir =
|
|
7264
|
+
const backupDir = join19(backupRoot(), ts);
|
|
6988
7265
|
p10.intro(brand(`backup restore ${accent(ts)}`));
|
|
6989
|
-
if (!
|
|
7266
|
+
if (!existsSync26(backupDir)) {
|
|
6990
7267
|
p10.cancel(`Backup not found: ${backupDir}`);
|
|
6991
7268
|
process.exit(1);
|
|
6992
7269
|
}
|
|
@@ -7008,9 +7285,9 @@ var restoreSubCommand = defineCommand10({
|
|
|
7008
7285
|
}
|
|
7009
7286
|
}
|
|
7010
7287
|
for (const rel of files) {
|
|
7011
|
-
const src =
|
|
7012
|
-
const dest =
|
|
7013
|
-
|
|
7288
|
+
const src = join19(backupDir, rel);
|
|
7289
|
+
const dest = join19(cwd, rel);
|
|
7290
|
+
mkdirSync8(dirname8(dest), { recursive: true });
|
|
7014
7291
|
copyFileSync4(src, dest);
|
|
7015
7292
|
}
|
|
7016
7293
|
p10.outro(`Restored ${files.length} file(s)`);
|
|
@@ -7040,19 +7317,19 @@ var backupCommand = defineCommand10({
|
|
|
7040
7317
|
// src/commands/migrations.ts
|
|
7041
7318
|
import { defineCommand as defineCommand11 } from "citty";
|
|
7042
7319
|
import * as p11 from "@clack/prompts";
|
|
7043
|
-
import { existsSync as
|
|
7044
|
-
import { join as
|
|
7320
|
+
import { existsSync as existsSync27, readdirSync as readdirSync11, statSync as statSync9, copyFileSync as copyFileSync5, mkdirSync as mkdirSync9 } from "fs";
|
|
7321
|
+
import { join as join20, relative as relative6, resolve as resolve19, dirname as dirname9 } from "path";
|
|
7045
7322
|
function listMigrations() {
|
|
7046
7323
|
const root = migrationsRoot();
|
|
7047
|
-
if (!
|
|
7324
|
+
if (!existsSync27(root)) return [];
|
|
7048
7325
|
const entries = [];
|
|
7049
7326
|
for (const ts of readdirSync11(root)) {
|
|
7050
|
-
const tsDir =
|
|
7327
|
+
const tsDir = join20(root, ts);
|
|
7051
7328
|
try {
|
|
7052
7329
|
const stat = statSync9(tsDir);
|
|
7053
7330
|
if (!stat.isDirectory()) continue;
|
|
7054
7331
|
for (const repoName of readdirSync11(tsDir)) {
|
|
7055
|
-
const repoDir =
|
|
7332
|
+
const repoDir = join20(tsDir, repoName);
|
|
7056
7333
|
try {
|
|
7057
7334
|
const repoStat = statSync9(repoDir);
|
|
7058
7335
|
if (!repoStat.isDirectory()) continue;
|
|
@@ -7070,7 +7347,7 @@ function listMigrations() {
|
|
|
7070
7347
|
function collectFiles2(root, dir) {
|
|
7071
7348
|
const out = [];
|
|
7072
7349
|
for (const entry of readdirSync11(dir)) {
|
|
7073
|
-
const full =
|
|
7350
|
+
const full = join20(dir, entry);
|
|
7074
7351
|
try {
|
|
7075
7352
|
const stat = statSync9(full);
|
|
7076
7353
|
if (stat.isDirectory()) {
|
|
@@ -7139,9 +7416,9 @@ var restoreSubCommand2 = defineCommand11({
|
|
|
7139
7416
|
const ts = args.timestamp;
|
|
7140
7417
|
const repoName = args.repo;
|
|
7141
7418
|
const cwd = resolve19(args.cwd ?? process.cwd());
|
|
7142
|
-
const migrationDir =
|
|
7419
|
+
const migrationDir = join20(migrationsRoot(), ts, repoName);
|
|
7143
7420
|
p11.intro(brand(`migrations restore ${accent(`${ts}/${repoName}`)}`));
|
|
7144
|
-
if (!
|
|
7421
|
+
if (!existsSync27(migrationDir)) {
|
|
7145
7422
|
p11.cancel(`Migration not found: ${migrationDir}`);
|
|
7146
7423
|
process.exit(1);
|
|
7147
7424
|
}
|
|
@@ -7164,9 +7441,9 @@ var restoreSubCommand2 = defineCommand11({
|
|
|
7164
7441
|
}
|
|
7165
7442
|
}
|
|
7166
7443
|
for (const rel of files) {
|
|
7167
|
-
const src =
|
|
7168
|
-
const dest =
|
|
7169
|
-
|
|
7444
|
+
const src = join20(migrationDir, rel);
|
|
7445
|
+
const dest = join20(cwd, rel);
|
|
7446
|
+
mkdirSync9(dirname9(dest), { recursive: true });
|
|
7170
7447
|
copyFileSync5(src, dest);
|
|
7171
7448
|
}
|
|
7172
7449
|
p11.outro(`Restored ${files.length} file(s)`);
|
|
@@ -7197,8 +7474,8 @@ var migrationsCommand = defineCommand11({
|
|
|
7197
7474
|
// src/commands/preset.ts
|
|
7198
7475
|
import { defineCommand as defineCommand12 } from "citty";
|
|
7199
7476
|
import * as p12 from "@clack/prompts";
|
|
7200
|
-
import { existsSync as
|
|
7201
|
-
import { join as
|
|
7477
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync10 } from "fs";
|
|
7478
|
+
import { join as join21, resolve as resolve20 } from "path";
|
|
7202
7479
|
var PRESET_ID_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
7203
7480
|
function stackTemplate(id) {
|
|
7204
7481
|
return [
|
|
@@ -7266,7 +7543,7 @@ var initSubCommand2 = defineCommand12({
|
|
|
7266
7543
|
process.exit(1);
|
|
7267
7544
|
}
|
|
7268
7545
|
const presetDir = resolve20(cwd, ".navori/presets", id);
|
|
7269
|
-
if (
|
|
7546
|
+
if (existsSync28(presetDir)) {
|
|
7270
7547
|
p12.cancel(
|
|
7271
7548
|
`Ya existe .navori/presets/${id}/ \u2014 b\xF3rralo o usa otro id si quieres regenerarlo.`
|
|
7272
7549
|
);
|
|
@@ -7292,11 +7569,11 @@ var initSubCommand2 = defineCommand12({
|
|
|
7292
7569
|
},
|
|
7293
7570
|
invariants: []
|
|
7294
7571
|
};
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
writeFileAtomic(
|
|
7298
|
-
writeFileAtomic(
|
|
7299
|
-
writeFileAtomic(
|
|
7572
|
+
mkdirSync10(join21(presetDir, "managed"), { recursive: true });
|
|
7573
|
+
mkdirSync10(join21(presetDir, "skills"), { recursive: true });
|
|
7574
|
+
writeFileAtomic(join21(presetDir, `${id}.json`), JSON.stringify(manifest, null, 2) + "\n");
|
|
7575
|
+
writeFileAtomic(join21(presetDir, "managed", "stack.md"), stackTemplate(id));
|
|
7576
|
+
writeFileAtomic(join21(presetDir, "skills", `${skillId}.md`), skillTemplate(skillId));
|
|
7300
7577
|
p12.log.success(`Creado .navori/presets/${id}/`);
|
|
7301
7578
|
p12.log.message(
|
|
7302
7579
|
[
|
|
@@ -7305,8 +7582,8 @@ var initSubCommand2 = defineCommand12({
|
|
|
7305
7582
|
` ${dim("\xB7")} skills/${skillId}.md`
|
|
7306
7583
|
].join("\n")
|
|
7307
7584
|
);
|
|
7308
|
-
const configPath =
|
|
7309
|
-
if (
|
|
7585
|
+
const configPath = join21(cwd, "navori.config.json");
|
|
7586
|
+
if (existsSync28(configPath)) {
|
|
7310
7587
|
const config = readConfig(configPath);
|
|
7311
7588
|
writeConfig(configPath, { ...config, preset: id });
|
|
7312
7589
|
p12.log.success(`navori.config.json \u2192 preset: ${accent(id)}`);
|
|
@@ -7333,10 +7610,10 @@ var presetCommand = defineCommand12({
|
|
|
7333
7610
|
import { defineCommand as defineCommand13 } from "citty";
|
|
7334
7611
|
import * as p13 from "@clack/prompts";
|
|
7335
7612
|
import { resolve as resolve21 } from "path";
|
|
7336
|
-
import { existsSync as
|
|
7613
|
+
import { existsSync as existsSync29 } from "fs";
|
|
7337
7614
|
function runScan(opts) {
|
|
7338
7615
|
const configPath = resolve21(opts.cwd, "navori.config.json");
|
|
7339
|
-
if (!
|
|
7616
|
+
if (!existsSync29(configPath)) {
|
|
7340
7617
|
return { kind: "no-config", configPath };
|
|
7341
7618
|
}
|
|
7342
7619
|
const config = readConfig(configPath);
|
|
@@ -7507,7 +7784,7 @@ async function collectPresetOverrides(added) {
|
|
|
7507
7784
|
// src/commands/status.ts
|
|
7508
7785
|
import { defineCommand as defineCommand14 } from "citty";
|
|
7509
7786
|
import * as p14 from "@clack/prompts";
|
|
7510
|
-
import { existsSync as
|
|
7787
|
+
import { existsSync as existsSync30 } from "fs";
|
|
7511
7788
|
import { resolve as resolve22 } from "path";
|
|
7512
7789
|
var statusCommand = defineCommand14({
|
|
7513
7790
|
meta: {
|
|
@@ -7521,7 +7798,7 @@ var statusCommand = defineCommand14({
|
|
|
7521
7798
|
async run({ args }) {
|
|
7522
7799
|
const cwd = resolve22(args.cwd ?? process.cwd());
|
|
7523
7800
|
const configPath = `${cwd}/navori.config.json`;
|
|
7524
|
-
if (!
|
|
7801
|
+
if (!existsSync30(configPath)) {
|
|
7525
7802
|
if (args.json) {
|
|
7526
7803
|
console.log(JSON.stringify({ ok: false, error: "config-missing", configPath }));
|
|
7527
7804
|
} else {
|
|
@@ -7545,7 +7822,7 @@ var statusCommand = defineCommand14({
|
|
|
7545
7822
|
}
|
|
7546
7823
|
throw err;
|
|
7547
7824
|
}
|
|
7548
|
-
const claudeMdExists =
|
|
7825
|
+
const claudeMdExists = existsSync30(`${cwd}/CLAUDE.md`);
|
|
7549
7826
|
const missingPlugins = collectMissingPlugins(config);
|
|
7550
7827
|
const drifts = scanManagedDrift(cwd, config);
|
|
7551
7828
|
const enabledPlugins = Object.entries(config.plugins ?? {}).filter(([, v]) => v.enabled === true).map(([k]) => k);
|
|
@@ -7593,7 +7870,7 @@ var statusCommand = defineCommand14({
|
|
|
7593
7870
|
import { defineCommand as defineCommand15 } from "citty";
|
|
7594
7871
|
import * as p15 from "@clack/prompts";
|
|
7595
7872
|
import { performance as performance2 } from "perf_hooks";
|
|
7596
|
-
import { existsSync as
|
|
7873
|
+
import { existsSync as existsSync31 } from "fs";
|
|
7597
7874
|
import { resolve as resolve23 } from "path";
|
|
7598
7875
|
var benchCommand = defineCommand15({
|
|
7599
7876
|
meta: {
|
|
@@ -7607,7 +7884,7 @@ var benchCommand = defineCommand15({
|
|
|
7607
7884
|
async run({ args }) {
|
|
7608
7885
|
const cwd = resolve23(args.cwd ?? process.cwd());
|
|
7609
7886
|
p15.intro(brand("bench"));
|
|
7610
|
-
if (!
|
|
7887
|
+
if (!existsSync31(`${cwd}/navori.config.json`)) {
|
|
7611
7888
|
p15.cancel(`No navori.config.json at ${cwd}. Run 'navori init' first.`);
|
|
7612
7889
|
process.exit(1);
|
|
7613
7890
|
}
|
|
@@ -7638,13 +7915,13 @@ var benchCommand = defineCommand15({
|
|
|
7638
7915
|
|
|
7639
7916
|
// src/index.ts
|
|
7640
7917
|
function readVersion() {
|
|
7641
|
-
const here =
|
|
7918
|
+
const here = dirname10(fileURLToPath2(import.meta.url));
|
|
7642
7919
|
for (const candidate of [
|
|
7643
7920
|
resolve24(here, "..", "package.json"),
|
|
7644
7921
|
resolve24(here, "package.json")
|
|
7645
7922
|
]) {
|
|
7646
7923
|
try {
|
|
7647
|
-
const pkg = JSON.parse(
|
|
7924
|
+
const pkg = JSON.parse(readFileSync22(candidate, "utf-8"));
|
|
7648
7925
|
if (pkg.version) return pkg.version;
|
|
7649
7926
|
} catch {
|
|
7650
7927
|
}
|