navori 0.2.16 → 0.2.17

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.
@@ -0,0 +1,11 @@
1
+ ## Stack — Monorepo (Turborepo + pnpm)
2
+
3
+ Este directorio es la **raíz de un monorepo**: orquesta, no aloja producto. El código real vive en los workspaces (`apps/*`, `packages/*`), y **cada workspace tiene su propio harness** (su `CLAUDE.md` + `.claude/`) con el preset de su stack. El mapa de workspaces vivos está en el bloque "## Monorepo — raíz".
4
+
5
+ Regla de oro: **enruta el trabajo al workspace dueño**. Un cambio de producto se hace desde el `CLAUDE.md` de su app, no desde aquí. La raíz solo se toca para lo transversal: `turbo.json`, `pnpm-workspace.yaml`, tsconfig/eslint base, scripts de CI, deps compartidas.
6
+
7
+ - **Tareas scopeadas, no globales.** Corre por workspace con el filtro de Turbo: `pnpm turbo run <task> --filter=<workspace>` (o `--filter=./apps/<x>`). Evita correr el pipeline entero cuando solo tocaste un app.
8
+ - **No cruces imports entre workspaces por ruta relativa** (`../../otro-app`). Consume un hermano por su nombre de paquete con el protocolo `workspace:*`; si no es un paquete publicable, probablemente el código debería vivir en un `packages/*` compartido.
9
+ - **La dep va en el `package.json` del workspace que la usa**, no en la raíz. Deps en la raíz son solo tooling del monorepo (turbo, changesets, linters compartidos).
10
+
11
+ Antes de tocar `turbo.json`, `pnpm-workspace.yaml` o mover deps entre workspaces, aplica el skill `turbo-workspaces`.
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: turbo-workspaces
3
+ description: Cómo navegar y operar un monorepo Turborepo + pnpm — correr tareas scopeadas, agregar deps al workspace correcto, compartir código sin acoplar. Aplica antes de tocar turbo.json, pnpm-workspace.yaml o mover deps.
4
+ type: reference
5
+ ---
6
+
7
+ # Turborepo + pnpm — operación del monorepo
8
+
9
+ ## Cuándo usar este skill
10
+
11
+ Antes de: correr tareas de build/test/lint, agregar o mover una dependencia, crear un workspace nuevo, o editar `turbo.json` / `pnpm-workspace.yaml`. En un monorepo, "dónde" vive un cambio importa tanto como "qué" cambia.
12
+
13
+ ## Correr tareas (siempre scopeadas)
14
+
15
+ ```bash
16
+ # Una tarea en UN workspace (por nombre de paquete o por ruta)
17
+ pnpm turbo run build --filter=@scope/backend
18
+ pnpm turbo run test --filter=./apps/storefront
19
+
20
+ # Un workspace y todo lo que depende de él (aguas abajo)
21
+ pnpm turbo run build --filter=@scope/backend...
22
+
23
+ # Solo lo afectado por tu diff vs una base
24
+ pnpm turbo run test --filter='...[origin/main]'
25
+ ```
26
+
27
+ Regla: no corras el pipeline entero (`turbo run build`) si solo tocaste un app. Turbo cachea, pero el ruido de logs y el tiempo de arranque sí cuestan. Deja el run global para CI.
28
+
29
+ ## Agregar dependencias (al workspace correcto)
30
+
31
+ ```bash
32
+ # Dep de un app concreto — NO en la raíz
33
+ pnpm add zod --filter @scope/backend
34
+
35
+ # Dep de tooling del monorepo (turbo, changesets, prettier) — esa sí va en la raíz
36
+ pnpm add -Dw turbo
37
+ ```
38
+
39
+ - Una lib de producto (`stripe`, `@tanstack/react-query`, …) va en el `package.json` del app que la importa. Si aparece en la raíz, el harness de ese app no la "ve" y su skill no se materializa donde corresponde.
40
+ - Consumir un workspace hermano se declara explícito: `"@scope/ui": "workspace:*"` en el `package.json` del consumidor. Nunca por `import '../../ui/src/...'`.
41
+
42
+ ## Compartir código sin acoplar
43
+
44
+ - Código usado por ≥2 apps → extráelo a un `packages/*` con su propio `package.json` y su preset (`navori scan` lo detecta como workspace nuevo).
45
+ - Tipos/utilidades cross-app también van en un `packages/*`, no en `apps/*`. Un app nunca es dependencia de otro app.
46
+
47
+ ## turbo.json — lo esencial
48
+
49
+ - Cada `task` declara sus `dependsOn` (`^build` = build de las deps primero) y sus `outputs` (para cachear). Un output mal declarado = cache que no invalida o que no cachea.
50
+ - Antes de editar el pipeline, verifica el efecto con `pnpm turbo run <task> --dry-run` (lista qué correría y desde qué caché) antes de correrlo de verdad.
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://navori.dev/schema/navori.preset.v1.json",
3
+ "id": "monorepo-turbopnpm",
4
+ "displayName": "Monorepo (Turborepo + pnpm)",
5
+ "extends": "core",
6
+ "extras": {
7
+ "managed": [
8
+ {
9
+ "id": "stack-monorepo-turbopnpm",
10
+ "relPath": "presets/monorepo-turbopnpm/managed/stack.md"
11
+ }
12
+ ],
13
+ "agents": [],
14
+ "skills": [
15
+ {
16
+ "id": "turbo-workspaces",
17
+ "relPath": "presets/monorepo-turbopnpm/skills/turbo-workspaces.md",
18
+ "destRelPath": ".claude/skills/turbo-workspaces.md"
19
+ }
20
+ ],
21
+ "hooks": []
22
+ }
23
+ }
package/dist/index.js CHANGED
@@ -129,7 +129,16 @@ var MonorepoWorkspaceSchema = z2.object({
129
129
  name: z2.string().min(1),
130
130
  path: safeRelPath,
131
131
  preset: z2.string().optional(),
132
- qualityGate: QualityGateSchema.optional()
132
+ qualityGate: QualityGateSchema.optional(),
133
+ /** Library-skill ids detected in THIS workspace's own deps. Scopes library
134
+ * skills per workspace so an app only gets the skills for the libs it ships —
135
+ * without this the root's aggregated list would spray every skill into every
136
+ * workspace (e.g. a Stripe skill in a backend that never imports Stripe). */
137
+ libraries: z2.array(z2.string()).optional(),
138
+ /** Active dependency migrations detected in THIS workspace's own deps. Scoped
139
+ * per workspace for the same reason as `libraries` — a mid-migration rule
140
+ * belongs only to the app whose package.json ships both sides of the pair. */
141
+ libraryMigrations: z2.array(z2.object({ legacy: z2.string(), preferred: z2.string(), domain: z2.string() })).optional()
133
142
  });
134
143
  var MonorepoSchema = z2.object({
135
144
  enabled: z2.boolean(),
@@ -821,12 +830,10 @@ function detectProject(cwd) {
821
830
  const monorepo = detectMonorepo(cwd);
822
831
  const stack = detectStack(cwd, pkg, pyproject, cargo);
823
832
  const libraryDeps = new Set(stack.deps);
824
- if (monorepo) {
825
- for (const dep of collectMonorepoWorkspaceDeps(cwd)) libraryDeps.add(dep);
826
- }
827
833
  const libraries = detectLibrarySkills([...libraryDeps]);
828
834
  const migrations = detectMigrations([...libraryDeps]);
829
- const { preset: suggestedPreset, gap: suggestedPresetGap } = suggestPreset(stack, monorepo);
835
+ const usesPnpm = packageManager === "pnpm" || existsSync6(join6(cwd, "pnpm-workspace.yaml"));
836
+ const { preset: suggestedPreset, gap: suggestedPresetGap } = suggestPreset(stack, monorepo, usesPnpm);
830
837
  const qualityGate = guessQualityGate(pkg, packageManager, stack);
831
838
  const claudeInfra = detectClaudeInfra(cwd);
832
839
  return {
@@ -1076,18 +1083,6 @@ function collectNodeDeps(pkg) {
1076
1083
  ...Object.keys(pkg.peerDependencies ?? {})
1077
1084
  ];
1078
1085
  }
1079
- function collectMonorepoWorkspaceDeps(cwd) {
1080
- const deps = /* @__PURE__ */ new Set();
1081
- const seen = /* @__PURE__ */ new Set();
1082
- for (const pattern of collectWorkspacePatterns(cwd)) {
1083
- for (const rel of expandPattern(cwd, pattern)) {
1084
- if (seen.has(rel)) continue;
1085
- seen.add(rel);
1086
- for (const dep of collectNodeDeps(readPackageJson(join6(cwd, rel)))) deps.add(dep);
1087
- }
1088
- }
1089
- return [...deps];
1090
- }
1091
1086
  function pick(deps, ...candidates) {
1092
1087
  for (const c of candidates) {
1093
1088
  if (deps.has(c)) return c;
@@ -1171,15 +1166,15 @@ function detectStack(cwd, pkg, pyproject, cargo) {
1171
1166
  deps: Array.from(nodeDeps)
1172
1167
  };
1173
1168
  }
1174
- function suggestPreset(stack, monorepo) {
1175
- const candidate = pickPresetCandidate(stack, monorepo);
1169
+ function suggestPreset(stack, monorepo, usesPnpm) {
1170
+ const candidate = pickPresetCandidate(stack, monorepo, usesPnpm);
1176
1171
  if (candidate === "custom") return { preset: "custom", gap: null };
1177
1172
  if (presetExists(candidate)) return { preset: candidate, gap: null };
1178
1173
  return { preset: "custom", gap: candidate };
1179
1174
  }
1180
- function pickPresetCandidate(stack, monorepo) {
1175
+ function pickPresetCandidate(stack, monorepo, usesPnpm) {
1181
1176
  if (monorepo) {
1182
- if (monorepo.tool === "turbo") return "monorepo-turbopnpm";
1177
+ if (monorepo.tool === "turbo") return usesPnpm ? "monorepo-turbopnpm" : "custom";
1183
1178
  if (monorepo.tool === "pnpm") return "monorepo-pnpm";
1184
1179
  if (monorepo.tool === "npm" || monorepo.tool === "lerna") return "monorepo-npm";
1185
1180
  }
@@ -2419,6 +2414,7 @@ function computeRenderPlan(existing, inputConfig, repoRoot, options = {}) {
2419
2414
  var CLAUDE_COMPUTED_BLOCK_IDS = [
2420
2415
  "skills-index",
2421
2416
  "agentes-disponibles",
2417
+ "contexto-monorepo",
2422
2418
  "contexto-proyecto"
2423
2419
  ];
2424
2420
  function canonicalManagedOrder(config, repoRoot, omitRootOnly = false) {
@@ -3038,6 +3034,48 @@ function buildAgentsIndexBody(config) {
3038
3034
  ].join("\n");
3039
3035
  }
3040
3036
  var CONTEXTO_PROYECTO_ID = "contexto-proyecto";
3037
+ var CONTEXTO_MONOREPO_ID = "contexto-monorepo";
3038
+ function buildContextoMonorepoBody(config, mono, isWorkspace) {
3039
+ if (isWorkspace) {
3040
+ if (!mono) return null;
3041
+ const tool2 = mono.tool ?? "pnpm";
3042
+ const lines2 = [
3043
+ `## Monorepo \u2014 workspace \`${mono.currentName}\``,
3044
+ "",
3045
+ `Eres el workspace **\`${mono.currentName}\`** (\`${mono.currentPath}\`) de un monorepo \`${tool2}\`. Tienes tu propio harness (este \`CLAUDE.md\` + \`.claude/\`); la config ra\xEDz y los archivos transversales (\`turbo.json\`, \`pnpm-workspace.yaml\`, tsconfig/eslint base) viven en el repo root.`,
3046
+ ""
3047
+ ];
3048
+ if (mono.siblings.length > 0) {
3049
+ lines2.push("Workspaces hermanos \u2014 no los edites desde aqu\xED; el trabajo en un hermano se hace desde su propio harness:");
3050
+ for (const s of mono.siblings) {
3051
+ lines2.push(`- \`${s.name}\` \u2014 \`${s.path}\`${s.preset ? ` (${s.preset})` : ""}`);
3052
+ }
3053
+ } else {
3054
+ lines2.push("Por ahora es el \xFAnico workspace declarado.");
3055
+ }
3056
+ lines2.push("");
3057
+ lines2.push(
3058
+ `Corre tareas scopeadas con \`--filter=${mono.currentName}\`. No importes c\xF3digo de un hermano por ruta relativa; cons\xFAmelo como paquete (\`workspace:*\`).`
3059
+ );
3060
+ lines2.push("");
3061
+ return lines2.join("\n");
3062
+ }
3063
+ const workspaces = config.monorepo?.workspaces ?? [];
3064
+ if (workspaces.length === 0) return null;
3065
+ const tool = config.monorepo?.tool ?? "pnpm";
3066
+ const lines = [
3067
+ "## Monorepo \u2014 ra\xEDz",
3068
+ "",
3069
+ `Este repo es un monorepo \`${tool}\`. El c\xF3digo real vive en los workspaces, cada uno con su propio harness (\`CLAUDE.md\` + \`.claude/\`). Al orquestar, **enruta cada tarea al workspace due\xF1o** y trabaja desde su \`CLAUDE.md\`, no desde aqu\xED.`,
3070
+ "",
3071
+ "Workspaces:"
3072
+ ];
3073
+ for (const w of workspaces) {
3074
+ lines.push(`- \`${w.name}\` \u2014 \`${w.path}\`${w.preset ? ` (${w.preset})` : ""}`);
3075
+ }
3076
+ lines.push("");
3077
+ return lines.join("\n");
3078
+ }
3041
3079
  function buildContextoProyectoBody(config) {
3042
3080
  const proj = config.project ?? {};
3043
3081
  const rows = [];
@@ -3169,6 +3207,26 @@ function renderClaudeEngine(cwd, inputConfig, options = {}) {
3169
3207
  } else {
3170
3208
  claudeMdContent = removeManagedSection(claudeMdContent, CONTEXTO_PROYECTO_ID);
3171
3209
  }
3210
+ const monorepoBody = buildContextoMonorepoBody(config, options.monorepoContext, isWorkspace);
3211
+ if (monorepoBody !== null) {
3212
+ const result = injectManagedSection(
3213
+ claudeMdContent,
3214
+ CONTEXTO_MONOREPO_ID,
3215
+ monorepoBody,
3216
+ CORE_META,
3217
+ "html",
3218
+ options.forceIds?.has(CONTEXTO_MONOREPO_ID) ?? false
3219
+ );
3220
+ claudeMdContent = result.output;
3221
+ claudeMdPlan.entries.push({
3222
+ asset: { id: CONTEXTO_MONOREPO_ID, relPath: "(computed)" },
3223
+ source: "core",
3224
+ status: result.status,
3225
+ newContent: null
3226
+ });
3227
+ } else {
3228
+ claudeMdContent = removeManagedSection(claudeMdContent, CONTEXTO_MONOREPO_ID);
3229
+ }
3172
3230
  const reorder = reorderManagedBlocks(claudeMdContent, canonicalManagedOrder(config, repoRoot, isWorkspace));
3173
3231
  claudeMdContent = reorder.output;
3174
3232
  if (reorder.blockedByInterleaving) {
@@ -3888,6 +3946,15 @@ function kv(rows, opts = {}) {
3888
3946
  }
3889
3947
 
3890
3948
  // src/lib/monorepo.ts
3949
+ function buildMonorepoContext(config, current) {
3950
+ const all = config.monorepo?.workspaces ?? [];
3951
+ return {
3952
+ tool: config.monorepo?.tool,
3953
+ currentName: current.name,
3954
+ currentPath: current.path,
3955
+ siblings: all.filter((w) => w.path !== current.path).map((w) => ({ name: w.name, path: w.path, preset: w.preset }))
3956
+ };
3957
+ }
3891
3958
  function effectiveConfigForWorkspace(root, workspace) {
3892
3959
  const { monorepo: _monorepo, ...rest } = root;
3893
3960
  const merged = { ...rest };
@@ -3897,6 +3964,10 @@ function effectiveConfigForWorkspace(root, workspace) {
3897
3964
  if (workspace.qualityGate !== void 0) {
3898
3965
  merged.qualityGate = workspace.qualityGate;
3899
3966
  }
3967
+ const project = { ...merged.project ?? {} };
3968
+ project.libraries = workspace.libraries ?? [];
3969
+ project.libraryMigrations = workspace.libraryMigrations ?? [];
3970
+ merged.project = project;
3900
3971
  return merged;
3901
3972
  }
3902
3973
 
@@ -3984,7 +4055,8 @@ function runRender(cwd, dryRunOrOptions = false, force = false) {
3984
4055
  const wsResult = renderClaude ? renderClaudeEngine(wsCwd, wsConfig, {
3985
4056
  dryRun,
3986
4057
  force: forceFlag,
3987
- repoRoot: cwd
4058
+ repoRoot: cwd,
4059
+ monorepoContext: buildMonorepoContext(config, match)
3988
4060
  }) : void 0;
3989
4061
  const wsExtraEngines = renderNonClaudeEngines(wsCwd, wsConfig, engines, dryRun, {
3990
4062
  repoRoot: cwd
@@ -4030,7 +4102,8 @@ function runRender(cwd, dryRunOrOptions = false, force = false) {
4030
4102
  const wsResult = renderClaude ? renderClaudeEngine(wsCwd, wsConfig, {
4031
4103
  dryRun,
4032
4104
  force: forceFlag,
4033
- repoRoot: cwd
4105
+ repoRoot: cwd,
4106
+ monorepoContext: buildMonorepoContext(config, ws)
4034
4107
  }) : void 0;
4035
4108
  const wsExtraEngines = renderNonClaudeEngines(wsCwd, wsConfig, engines, dryRun, {
4036
4109
  repoRoot: cwd,
@@ -4654,7 +4727,9 @@ function describeWorkspace(cwd, relPath) {
4654
4727
  name: project.name ?? relPath.split("/").pop(),
4655
4728
  path: relPath,
4656
4729
  suggestedPreset: project.suggestedPreset,
4657
- framework: project.stack.framework
4730
+ framework: project.stack.framework,
4731
+ libraries: project.libraries,
4732
+ migrations: project.migrations
4658
4733
  };
4659
4734
  }
4660
4735
 
@@ -6379,6 +6454,12 @@ function buildWorkspaceEntry(detected, rootPreset, preset) {
6379
6454
  if (preset && preset !== rootPreset) {
6380
6455
  entry.preset = preset;
6381
6456
  }
6457
+ if (detected.libraries.length > 0) {
6458
+ entry.libraries = detected.libraries;
6459
+ }
6460
+ if (detected.migrations.length > 0) {
6461
+ entry.libraryMigrations = detected.migrations;
6462
+ }
6382
6463
  return entry;
6383
6464
  }
6384
6465
  function formatProjectValue(v) {
@@ -6455,7 +6536,11 @@ var syncCommand = defineCommand4({
6455
6536
  const targets = targetsResult.targets;
6456
6537
  const plans = targets.map((t2) => ({
6457
6538
  target: t2,
6458
- plan: renderClaudeEngine(t2.cwd, t2.config, { dryRun: true, repoRoot: t2.repoRoot })
6539
+ plan: renderClaudeEngine(t2.cwd, t2.config, {
6540
+ dryRun: true,
6541
+ repoRoot: t2.repoRoot,
6542
+ monorepoContext: t2.monorepoContext
6543
+ })
6459
6544
  }));
6460
6545
  reportPlans(plans);
6461
6546
  const conflicts = collectAllConflicts(plans);
@@ -6538,7 +6623,8 @@ ${lines}`
6538
6623
  const applied = renderClaudeEngine(t2.cwd, t2.config, {
6539
6624
  skipIds: res?.skipIds,
6540
6625
  forceIds: res?.forceIds,
6541
- repoRoot: t2.repoRoot
6626
+ repoRoot: t2.repoRoot,
6627
+ monorepoContext: t2.monorepoContext
6542
6628
  });
6543
6629
  writtenTotal += applied.written.length;
6544
6630
  if (applied.backupPath) {
@@ -6573,7 +6659,8 @@ function resolveSyncTargets(cwd, config, workspaceFilter) {
6573
6659
  label: `workspace:${match.name}`,
6574
6660
  cwd: resolve15(cwd, match.path),
6575
6661
  repoRoot: cwd,
6576
- config: effectiveConfigForWorkspace(config, match)
6662
+ config: effectiveConfigForWorkspace(config, match),
6663
+ monorepoContext: buildMonorepoContext(config, match)
6577
6664
  }
6578
6665
  ]
6579
6666
  };
@@ -6584,7 +6671,8 @@ function resolveSyncTargets(cwd, config, workspaceFilter) {
6584
6671
  label: `workspace:${ws.name}`,
6585
6672
  cwd: resolve15(cwd, ws.path),
6586
6673
  repoRoot: cwd,
6587
- config: effectiveConfigForWorkspace(config, ws)
6674
+ config: effectiveConfigForWorkspace(config, ws),
6675
+ monorepoContext: buildMonorepoContext(config, ws)
6588
6676
  });
6589
6677
  }
6590
6678
  return { ok: true, targets };
@@ -8318,6 +8406,29 @@ function withProject(current, patch) {
8318
8406
  const base = current && typeof current === "object" ? current : {};
8319
8407
  return { ...base, ...patch };
8320
8408
  }
8409
+ function refreshWorkspaceScopes(raw, cwd) {
8410
+ const mono = raw.monorepo;
8411
+ if (!mono?.workspaces?.length) return false;
8412
+ const byPath = new Map(scanMonorepoWorkspaces(cwd).map((s) => [s.path, s]));
8413
+ let changed = false;
8414
+ for (const ws of mono.workspaces) {
8415
+ const det = byPath.get(ws.path);
8416
+ if (!det) continue;
8417
+ const curLibs = ws.libraries ?? [];
8418
+ if (!sameSet(curLibs, det.libraries)) {
8419
+ if (det.libraries.length > 0) ws.libraries = det.libraries;
8420
+ else delete ws.libraries;
8421
+ changed = true;
8422
+ }
8423
+ const curMigs = ws.libraryMigrations ?? [];
8424
+ if (!sameMigrations(curMigs, det.migrations)) {
8425
+ if (det.migrations.length > 0) ws.libraryMigrations = det.migrations;
8426
+ else delete ws.libraryMigrations;
8427
+ changed = true;
8428
+ }
8429
+ }
8430
+ return changed;
8431
+ }
8321
8432
  function diffConfig(current, detected) {
8322
8433
  const out = [];
8323
8434
  if (current.preset !== detected.suggestedPreset && detected.suggestedPreset !== "custom") {
@@ -8420,7 +8531,8 @@ var updateCommand = defineCommand10({
8420
8531
  const diffs = diffConfig(config, detected);
8421
8532
  const rawConfig = JSON.parse(readFileSync23(configPath, "utf-8"));
8422
8533
  const deadKeys = deadProgressKeys(rawConfig);
8423
- const willWriteConfig = diffs.length > 0 || deadKeys.length > 0;
8534
+ const wsScopesChanged = refreshWorkspaceScopes(rawConfig, cwd);
8535
+ const willWriteConfig = diffs.length > 0 || deadKeys.length > 0 || wsScopesChanged;
8424
8536
  const preview = runRender(cwd, true);
8425
8537
  const agg = aggregateRender(preview);
8426
8538
  if (!willWriteConfig && agg.writes.length === 0 && agg.conflicts.length === 0 && agg.downgrades.length === 0) {
@@ -8433,9 +8545,12 @@ var updateCommand = defineCommand10({
8433
8545
  );
8434
8546
  p11.log.info(`Config drift detected (${diffs.length}):
8435
8547
  ${lines.join("\n")}`);
8436
- } else {
8548
+ } else if (!wsScopesChanged) {
8437
8549
  p11.log.info("Config is in sync with the repo");
8438
8550
  }
8551
+ if (wsScopesChanged) {
8552
+ p11.log.info("Re-homed per-workspace library skills onto monorepo.workspaces[] (scoping migration)");
8553
+ }
8439
8554
  if (deadKeys.length > 0) {
8440
8555
  p11.log.info(`Claves obsoletas en "progress" que se limpiar\xE1n: ${deadKeys.join(", ")}`);
8441
8556
  }
@@ -9011,6 +9126,12 @@ function buildMonorepoWorkspace(detected, preset, config) {
9011
9126
  if (preset && preset !== config.preset) {
9012
9127
  entry.preset = preset;
9013
9128
  }
9129
+ if (detected.libraries.length > 0) {
9130
+ entry.libraries = detected.libraries;
9131
+ }
9132
+ if (detected.migrations.length > 0) {
9133
+ entry.libraryMigrations = detected.migrations;
9134
+ }
9014
9135
  return entry;
9015
9136
  }
9016
9137
  var scanCommand = defineCommand14({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "navori",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "description": "Multi-agent harness + SDD scaffolder for Claude Code and other AI engines",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,7 +21,7 @@
21
21
  ],
22
22
  "features": {
23
23
  "plugins": 6,
24
- "presets": 11,
24
+ "presets": 12,
25
25
  "coreAgents": 8,
26
26
  "coreSkills": 6,
27
27
  "librarySkills": 12