navori 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +122 -11
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -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;
|
|
@@ -1885,6 +1930,16 @@ function computeRenderPlan(existing, inputConfig, repoRoot, options = {}) {
|
|
|
1885
1930
|
updatesAvailable
|
|
1886
1931
|
};
|
|
1887
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
|
+
}
|
|
1888
1943
|
|
|
1889
1944
|
// src/engines/claude/settings-detection.ts
|
|
1890
1945
|
var NAVORI_OWNERSHIP_MARKER = "$navori";
|
|
@@ -2491,6 +2546,13 @@ function renderClaudeEngine(cwd, inputConfig, options = {}) {
|
|
|
2491
2546
|
} else {
|
|
2492
2547
|
claudeMdContent = removeManagedSection(claudeMdContent, CONTEXTO_PROYECTO_ID);
|
|
2493
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
|
+
}
|
|
2494
2556
|
if (claudeMdContent !== claudeMdExisting) {
|
|
2495
2557
|
pending.push({
|
|
2496
2558
|
path: claudeMdPath,
|
|
@@ -3446,6 +3508,7 @@ var ES = {
|
|
|
3446
3508
|
detectionFailedYes: "No detect\xE9 el nombre del proyecto. Corre sin --yes/--recommended para darlo.",
|
|
3447
3509
|
wroteConfig: (path) => `Escrib\xED ${path}`,
|
|
3448
3510
|
recPluginsEnabled: (list) => `Plugins recomendados activados: ${list}`,
|
|
3511
|
+
pluginsAlwaysOn: (list) => `Incluidos siempre con navori: ${list} (no hace falta elegirlos)`,
|
|
3449
3512
|
presetGapNotice: (stack) => `Detect\xE9 un proyecto '${stack}', pero todav\xEDa no hay un preset oficial para ese stack. Se instala el harness completo (agentes, gates, protocolo, SDD) y funciona desde ya; lo \xFAnico que falta son skills espec\xEDficas de '${stack}'. Quedas con el baseline (preset: custom). Para cubrir el hueco: crea tu preset local con 'navori preset init ${stack}', o agrega skills sueltas en project.localSkills.`,
|
|
3450
3513
|
placeholderNameNotice: (name) => `El name '${name}' parece un placeholder de scaffold (heredado del package.json sin renombrar). Ren\xF3mbralo en package.json o edita "name" en navori.config.json si no es el nombre real del repo.`,
|
|
3451
3514
|
workspaceDefaultsTitle: (name) => `Defaults del workspace \xB7 ${name}`,
|
|
@@ -3553,6 +3616,7 @@ var EN = {
|
|
|
3553
3616
|
detectionFailedYes: "Could not detect project name. Run without --yes/--recommended to provide one.",
|
|
3554
3617
|
wroteConfig: (path) => `Wrote ${path}`,
|
|
3555
3618
|
recPluginsEnabled: (list) => `Recommended plugins enabled: ${list}`,
|
|
3619
|
+
pluginsAlwaysOn: (list) => `Always included with navori: ${list} (no need to pick them)`,
|
|
3556
3620
|
presetGapNotice: (stack) => `Detected a '${stack}' project, but there's no official preset for that stack yet. The full harness installs (agents, gates, protocol, SDD) and works right away; the only thing missing are '${stack}'-specific skills. You stay on the baseline (preset: custom). To cover the gap: scaffold your local preset with 'navori preset init ${stack}', or add individual skills via project.localSkills.`,
|
|
3557
3621
|
placeholderNameNotice: (name) => `The name '${name}' looks like a scaffold placeholder (carried over from an un-renamed package.json). Rename it in package.json or edit "name" in navori.config.json if it isn't the repo's real name.`,
|
|
3558
3622
|
workspaceDefaultsTitle: (name) => `Workspace defaults \xB7 ${name}`,
|
|
@@ -3919,7 +3983,8 @@ var initCommand = defineCommand2({
|
|
|
3919
3983
|
}
|
|
3920
3984
|
const wsPlugins2 = wsDefaults?.plugins ?? {};
|
|
3921
3985
|
const recommendedPlugins = args.recommended ? buildRecommendedPlugins(cwd) : {};
|
|
3922
|
-
const mergedPlugins2 = { ...wsPlugins2, ...recommendedPlugins };
|
|
3986
|
+
const mergedPlugins2 = { ...ALWAYS_ON_PLUGINS, ...wsPlugins2, ...recommendedPlugins };
|
|
3987
|
+
p2.log.info(tr.pluginsAlwaysOn(Object.keys(ALWAYS_ON_PLUGINS).join(", ")));
|
|
3923
3988
|
if (args.recommended && Object.keys(recommendedPlugins).length > 0) {
|
|
3924
3989
|
p2.log.info(tr.recPluginsEnabled(Object.keys(recommendedPlugins).join(", ")));
|
|
3925
3990
|
}
|
|
@@ -4236,7 +4301,7 @@ var initCommand = defineCommand2({
|
|
|
4236
4301
|
}
|
|
4237
4302
|
}
|
|
4238
4303
|
const wsPlugins = wsDefaults?.plugins ?? {};
|
|
4239
|
-
const mergedPlugins = { ...wsPlugins, ...pluginsConfig };
|
|
4304
|
+
const mergedPlugins = { ...ALWAYS_ON_PLUGINS, ...wsPlugins, ...pluginsConfig };
|
|
4240
4305
|
const monorepoBlock = await buildMonorepoBlock(cwd, detected, {
|
|
4241
4306
|
scanMonorepo: Boolean(args["scan-monorepo"]),
|
|
4242
4307
|
autoYes: false,
|
|
@@ -4298,6 +4363,7 @@ async function chooseAdoptionMode(cwd, infra, projectName, args) {
|
|
|
4298
4363
|
const tr = t(args.lang);
|
|
4299
4364
|
if (args.yes) {
|
|
4300
4365
|
p2.log.warn(tr.existingInfraYesMode);
|
|
4366
|
+
p2.note(formatInfraSummary(infra, args.lang), tr.filesFoundTitle);
|
|
4301
4367
|
return "coexist";
|
|
4302
4368
|
}
|
|
4303
4369
|
p2.log.warn(tr.existingInfraDetected);
|
|
@@ -4326,7 +4392,9 @@ async function chooseAdoptionMode(cwd, infra, projectName, args) {
|
|
|
4326
4392
|
return "coexist";
|
|
4327
4393
|
}
|
|
4328
4394
|
async function pickPlugins(lang) {
|
|
4329
|
-
const
|
|
4395
|
+
const alwaysOn = Object.keys(ALWAYS_ON_PLUGINS);
|
|
4396
|
+
p2.log.info(t(lang).pluginsAlwaysOn(alwaysOn.join(", ")));
|
|
4397
|
+
const ids = listKnownPluginIds().filter((id) => !(id in ALWAYS_ON_PLUGINS));
|
|
4330
4398
|
if (ids.length === 0) return [];
|
|
4331
4399
|
const options = ids.map((id) => {
|
|
4332
4400
|
const plugin = (() => {
|
|
@@ -4405,10 +4473,11 @@ ${summary}`);
|
|
|
4405
4473
|
}
|
|
4406
4474
|
return overrides;
|
|
4407
4475
|
}
|
|
4476
|
+
var ALWAYS_ON_PLUGINS = {
|
|
4477
|
+
engram: { enabled: true }
|
|
4478
|
+
};
|
|
4408
4479
|
function buildRecommendedPlugins(cwd) {
|
|
4409
|
-
const result = {
|
|
4410
|
-
engram: { enabled: true }
|
|
4411
|
-
};
|
|
4480
|
+
const result = {};
|
|
4412
4481
|
if (isGitHubRepo(cwd)) {
|
|
4413
4482
|
result.gh = { enabled: true };
|
|
4414
4483
|
}
|
|
@@ -4831,21 +4900,45 @@ function scanManagedDrift(cwd, config) {
|
|
|
4831
4900
|
}
|
|
4832
4901
|
return out;
|
|
4833
4902
|
}
|
|
4903
|
+
function scanManagedOrder(cwd, config) {
|
|
4904
|
+
const claudeMdPath = join13(cwd, "CLAUDE.md");
|
|
4905
|
+
if (!existsSync17(claudeMdPath)) return null;
|
|
4906
|
+
const content = readFileSync14(claudeMdPath, "utf-8");
|
|
4907
|
+
const current = listMarkers(claudeMdPath).map((m) => m.id);
|
|
4908
|
+
if (current.length < 2) return null;
|
|
4909
|
+
const canonical = canonicalManagedOrder(config, cwd);
|
|
4910
|
+
const result = reorderManagedBlocks(content, canonical);
|
|
4911
|
+
if (!result.reordered && !result.blockedByInterleaving) return null;
|
|
4912
|
+
const rank = /* @__PURE__ */ new Map();
|
|
4913
|
+
canonical.forEach((id, i) => {
|
|
4914
|
+
if (!rank.has(id)) rank.set(id, i);
|
|
4915
|
+
});
|
|
4916
|
+
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);
|
|
4917
|
+
return { current, expected, interleaved: result.blockedByInterleaving };
|
|
4918
|
+
}
|
|
4834
4919
|
function suggestNextSteps(state) {
|
|
4835
4920
|
const steps = [];
|
|
4836
4921
|
if (!state.claudeMdExists) {
|
|
4837
|
-
steps.push("
|
|
4922
|
+
steps.push("Corre 'navori render --apply' para generar CLAUDE.md + .claude/.");
|
|
4838
4923
|
}
|
|
4839
4924
|
if (state.missingPlugins.length > 0) {
|
|
4840
4925
|
steps.push(
|
|
4841
|
-
`
|
|
4926
|
+
`Resuelve ${state.missingPlugins.length} plugin(s) faltante(s): inst\xE1lalos o qu\xEDtalos del config.`
|
|
4842
4927
|
);
|
|
4843
4928
|
}
|
|
4844
4929
|
if (state.drifts.some((d) => d.kind === "content")) {
|
|
4845
|
-
steps.push("
|
|
4930
|
+
steps.push("Corre 'navori sync --interactive' para resolver bloques editados a mano.");
|
|
4846
4931
|
}
|
|
4847
4932
|
if (state.drifts.some((d) => d.kind === "version")) {
|
|
4848
|
-
steps.push("
|
|
4933
|
+
steps.push("Corre 'navori render --apply' para traer los bloques a la \xFAltima versi\xF3n.");
|
|
4934
|
+
}
|
|
4935
|
+
if (state.orderReport && !state.orderReport.interleaved) {
|
|
4936
|
+
steps.push("Corre 'navori render --apply' para reordenar los bloques de CLAUDE.md al orden can\xF3nico.");
|
|
4937
|
+
}
|
|
4938
|
+
if (state.orderReport?.interleaved) {
|
|
4939
|
+
steps.push(
|
|
4940
|
+
"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."
|
|
4941
|
+
);
|
|
4849
4942
|
}
|
|
4850
4943
|
if (steps.length === 0) {
|
|
4851
4944
|
steps.push("Todo al d\xEDa \u2014 sin acciones pendientes.");
|
|
@@ -4910,6 +5003,7 @@ var doctorCommand = defineCommand3({
|
|
|
4910
5003
|
const markers = listMarkers(claudeMdPath);
|
|
4911
5004
|
const missingPlugins = collectMissingPlugins(config);
|
|
4912
5005
|
const drifts = scanManagedDrift(cwd, config);
|
|
5006
|
+
const orderReport = scanManagedOrder(cwd, config);
|
|
4913
5007
|
const corruptedSettings = scanCorruptedSettings(cwd);
|
|
4914
5008
|
const missingInvariants = scanMissingInvariants(cwd, config);
|
|
4915
5009
|
const resolvedPreset = config.preset !== "custom" ? resolvePreset(config.preset, cwd) : null;
|
|
@@ -4934,6 +5028,7 @@ var doctorCommand = defineCommand3({
|
|
|
4934
5028
|
managedBlocks: markers,
|
|
4935
5029
|
missingPlugins,
|
|
4936
5030
|
drifts,
|
|
5031
|
+
orderReport,
|
|
4937
5032
|
corruptedSettings,
|
|
4938
5033
|
missingInvariants,
|
|
4939
5034
|
missingPreset,
|
|
@@ -5057,10 +5152,26 @@ ${lines.join("\n")}`
|
|
|
5057
5152
|
${lines.join("\n")}`
|
|
5058
5153
|
);
|
|
5059
5154
|
}
|
|
5155
|
+
if (orderReport) {
|
|
5156
|
+
if (orderReport.interleaved) {
|
|
5157
|
+
p3.log.warn(
|
|
5158
|
+
`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'.
|
|
5159
|
+
orden actual: ${orderReport.current.join(", ")}
|
|
5160
|
+
orden can\xF3nico: ${orderReport.expected.join(", ")}`
|
|
5161
|
+
);
|
|
5162
|
+
} else {
|
|
5163
|
+
p3.log.warn(
|
|
5164
|
+
`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).
|
|
5165
|
+
orden actual: ${orderReport.current.join(", ")}
|
|
5166
|
+
orden can\xF3nico: ${orderReport.expected.join(", ")}`
|
|
5167
|
+
);
|
|
5168
|
+
}
|
|
5169
|
+
}
|
|
5060
5170
|
const nextSteps = suggestNextSteps({
|
|
5061
5171
|
claudeMdExists: report.checks.claudeMdExists,
|
|
5062
5172
|
missingPlugins,
|
|
5063
|
-
drifts
|
|
5173
|
+
drifts,
|
|
5174
|
+
orderReport
|
|
5064
5175
|
});
|
|
5065
5176
|
p3.note(
|
|
5066
5177
|
nextSteps.map((s) => ` ${color.cyan(sym.bullet)} ${s}`).join("\n"),
|