navori 0.2.5 → 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.
Files changed (2) hide show
  1. package/dist/index.js +109 -5
  2. 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,
@@ -4831,21 +4893,45 @@ function scanManagedDrift(cwd, config) {
4831
4893
  }
4832
4894
  return out;
4833
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
+ }
4834
4912
  function suggestNextSteps(state) {
4835
4913
  const steps = [];
4836
4914
  if (!state.claudeMdExists) {
4837
- steps.push("Corr\xE9 'navori render --apply' para generar CLAUDE.md + .claude/.");
4915
+ steps.push("Corre 'navori render --apply' para generar CLAUDE.md + .claude/.");
4838
4916
  }
4839
4917
  if (state.missingPlugins.length > 0) {
4840
4918
  steps.push(
4841
- `Resolv\xE9 ${state.missingPlugins.length} plugin(s) faltante(s): instalalos o quitalos del config.`
4919
+ `Resuelve ${state.missingPlugins.length} plugin(s) faltante(s): inst\xE1lalos o qu\xEDtalos del config.`
4842
4920
  );
4843
4921
  }
4844
4922
  if (state.drifts.some((d) => d.kind === "content")) {
4845
- steps.push("Corr\xE9 'navori sync --interactive' para resolver bloques editados a mano.");
4923
+ steps.push("Corre 'navori sync --interactive' para resolver bloques editados a mano.");
4846
4924
  }
4847
4925
  if (state.drifts.some((d) => d.kind === "version")) {
4848
- steps.push("Corr\xE9 'navori render --apply' para traer los bloques a la \xFAltima versi\xF3n.");
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
+ );
4849
4935
  }
4850
4936
  if (steps.length === 0) {
4851
4937
  steps.push("Todo al d\xEDa \u2014 sin acciones pendientes.");
@@ -4910,6 +4996,7 @@ var doctorCommand = defineCommand3({
4910
4996
  const markers = listMarkers(claudeMdPath);
4911
4997
  const missingPlugins = collectMissingPlugins(config);
4912
4998
  const drifts = scanManagedDrift(cwd, config);
4999
+ const orderReport = scanManagedOrder(cwd, config);
4913
5000
  const corruptedSettings = scanCorruptedSettings(cwd);
4914
5001
  const missingInvariants = scanMissingInvariants(cwd, config);
4915
5002
  const resolvedPreset = config.preset !== "custom" ? resolvePreset(config.preset, cwd) : null;
@@ -4934,6 +5021,7 @@ var doctorCommand = defineCommand3({
4934
5021
  managedBlocks: markers,
4935
5022
  missingPlugins,
4936
5023
  drifts,
5024
+ orderReport,
4937
5025
  corruptedSettings,
4938
5026
  missingInvariants,
4939
5027
  missingPreset,
@@ -5057,10 +5145,26 @@ ${lines.join("\n")}`
5057
5145
  ${lines.join("\n")}`
5058
5146
  );
5059
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
+ }
5060
5163
  const nextSteps = suggestNextSteps({
5061
5164
  claudeMdExists: report.checks.claudeMdExists,
5062
5165
  missingPlugins,
5063
- drifts
5166
+ drifts,
5167
+ orderReport
5064
5168
  });
5065
5169
  p3.note(
5066
5170
  nextSteps.map((s) => ` ${color.cyan(sym.bullet)} ${s}`).join("\n"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "navori",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Multi-agent harness + SDD scaffolder for Claude Code and other AI engines",
5
5
  "type": "module",
6
6
  "bin": {