@netanelyasi/agent-ready 0.2.2 → 0.2.3

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/README.md CHANGED
@@ -14,7 +14,7 @@
14
14
 
15
15
  <p align="center">
16
16
  <img alt="Status" src="https://img.shields.io/badge/status-experimental-f59e0b?style=flat-square" />
17
- <img alt="Version" src="https://img.shields.io/badge/version-0.2.2-111827?style=flat-square" />
17
+ <img alt="Version" src="https://img.shields.io/badge/version-0.2.3-111827?style=flat-square" />
18
18
  <img alt="License" src="https://img.shields.io/badge/license-MIT-0f766e?style=flat-square" />
19
19
  <img alt="Runtime" src="https://img.shields.io/badge/runtime-Node.js-3c873a?style=flat-square" />
20
20
  <img alt="Built by BrainboxAI" src="https://img.shields.io/badge/by-BrainboxAI-111827?style=flat-square" />
@@ -429,7 +429,6 @@ Planned improvements:
429
429
  - richer monorepo workspace detection
430
430
  - generated `CONTRIBUTING.md` and `SECURITY.md` templates
431
431
  - optional AI-assisted repository summary mode
432
- - npm package release
433
432
  - plugin/export presets for Claude Code, Cursor, Codex, and other agents
434
433
  - CI mode for failing builds when agent readiness drops below a threshold
435
434
 
@@ -36,7 +36,7 @@ export async function scanProject(rootInput) {
36
36
  claudeSettings: await harnessFileState(root, path.join(".claude", "settings.json")),
37
37
  skillsDir: await pathExists(path.join(root, ".agent-ready", "skills")) || await pathExists(path.join(root, ".claude", "skills")),
38
38
  };
39
- const codeGraph = await analyzeCodeGraph(root, files, packages);
39
+ const codeGraph = await analyzeCodeGraph(root, files, packages, frameworks);
40
40
  return {
41
41
  root,
42
42
  name: rootPackage?.name ?? path.basename(root),
@@ -107,6 +107,8 @@ function detectFrameworks(files, deps) {
107
107
  found.add(deps.nuxt ? "Nuxt" : "Vue");
108
108
  if (deps.svelte || deps["@sveltejs/kit"])
109
109
  found.add(deps["@sveltejs/kit"] ? "SvelteKit" : "Svelte");
110
+ if (deps["@remix-run/react"] || deps["@remix-run/node"] || deps["@remix-run/server-runtime"] || files.includes("remix.config.js") || files.includes("remix.config.ts"))
111
+ found.add("Remix");
110
112
  if (deps.vite || files.some((file) => file.startsWith("vite.config.")))
111
113
  found.add("Vite");
112
114
  if (deps.express)
@@ -267,7 +269,7 @@ async function harnessFileState(root, relativePath) {
267
269
  const generatedByAgentReady = Boolean(text && /generated by `?agent-ready`?|agent-ready:|Generated by agent-ready/i.test(text));
268
270
  return { exists: true, generatedByAgentReady, countsAsMaintainerAuthored: !generatedByAgentReady };
269
271
  }
270
- async function analyzeCodeGraph(root, files, packages) {
272
+ async function analyzeCodeGraph(root, files, packages, frameworks) {
271
273
  const sourceFiles = files
272
274
  .filter((file) => /\.(tsx?|jsx?|mjs|cjs|py|go|rs|svelte)$/.test(file))
273
275
  .filter((file) => !file.endsWith(".d.ts"))
@@ -275,7 +277,7 @@ async function analyzeCodeGraph(root, files, packages) {
275
277
  .slice(0, 2000);
276
278
  const sourceSet = new Set(sourceFiles.map((file) => rel(root, file)));
277
279
  const goModulePath = await readGoModulePath(root);
278
- const entryPoints = detectEntryPoints(root, packages, sourceSet);
280
+ const entryPoints = detectEntryPoints(root, packages, sourceSet, frameworks);
279
281
  const importEdges = [];
280
282
  const externalImportMap = new Map();
281
283
  for (const file of sourceFiles) {
@@ -323,7 +325,7 @@ async function analyzeCodeGraph(root, files, packages) {
323
325
  unresolvedRelativeImports: importEdges.filter((edge) => !edge.resolved).slice(0, 30),
324
326
  };
325
327
  }
326
- function detectEntryPoints(root, packages, sourceSet) {
328
+ function detectEntryPoints(root, packages, sourceSet, frameworks) {
327
329
  const entries = new Map();
328
330
  for (const pkg of packages) {
329
331
  const dir = path.posix.dirname(pkg.path) === "." ? "." : path.posix.dirname(pkg.path);
@@ -360,7 +362,7 @@ function detectEntryPoints(root, packages, sourceSet) {
360
362
  if (!source.startsWith(packageRoot))
361
363
  continue;
362
364
  const local = source.slice(packageRoot.length);
363
- const frameworkEntry = frameworkEntryPoint(local);
365
+ const frameworkEntry = frameworkEntryPoint(local, frameworks);
364
366
  if (frameworkEntry)
365
367
  entries.set(source, { path: source, ...frameworkEntry });
366
368
  if (/^cmd\/[^/]+\/main\.go$/.test(local))
@@ -376,32 +378,42 @@ function detectEntryPoints(root, packages, sourceSet) {
376
378
  }
377
379
  return [...entries.values()].sort((a, b) => a.path.localeCompare(b.path)).slice(0, 40);
378
380
  }
379
- function frameworkEntryPoint(localPath) {
380
- if (/^(src\/)?app\/(page|layout|route)\.(tsx?|jsx?)$/.test(localPath)) {
381
- const file = localPath.includes("/layout.") ? "layout" : localPath.includes("/route.") ? "route handler" : "page";
382
- return { kind: `Next.js ${file}`, reason: "App Router root entry" };
381
+ function frameworkEntryPoint(localPath, frameworks) {
382
+ // Framework conventions like `pages/` and `app/` are generic folder names that
383
+ // also appear in Vite/React-Router apps. Only treat them as framework entry
384
+ // points when the framework is actually detected, or every such project is
385
+ // mislabeled (e.g. a Vite `src/pages/*.tsx` reported as a Next.js route).
386
+ if (frameworks.includes("Next.js")) {
387
+ if (/^(src\/)?app\/(page|layout|route)\.(tsx?|jsx?)$/.test(localPath)) {
388
+ const file = localPath.includes("/layout.") ? "layout" : localPath.includes("/route.") ? "route handler" : "page";
389
+ return { kind: `Next.js ${file}`, reason: "App Router root entry" };
390
+ }
391
+ if (/^(src\/)?app\/.+\/(page|layout|route|loading|error|not-found)\.(tsx?|jsx?)$/.test(localPath)) {
392
+ return { kind: "Next.js route", reason: "App Router route segment entry" };
393
+ }
394
+ if (/^(src\/)?pages\/index\.(tsx?|jsx?)$/.test(localPath))
395
+ return { kind: "Next.js route", reason: "Pages Router index" };
396
+ if (/^(src\/)?pages\/(api\/.+|.+)\.(tsx?|jsx?)$/.test(localPath))
397
+ return { kind: "Next.js route", reason: "Pages Router route/API entry" };
398
+ if (/^(src\/)?middleware\.(tsx?|jsx?)$/.test(localPath))
399
+ return { kind: "Next.js middleware", reason: "Next.js request middleware entry" };
400
+ if (/^next\.config\.(tsx?|jsx?|mjs|cjs)$/.test(localPath))
401
+ return { kind: "Next.js config", reason: "Next.js configuration entry" };
402
+ }
403
+ if (frameworks.includes("Remix")) {
404
+ if (/^app\/(root|entry\.(client|server))\.(tsx?|jsx?)$/.test(localPath))
405
+ return { kind: "Remix entry", reason: "Remix root/client/server entry" };
406
+ if (/^app\/routes\/.+\.(tsx?|jsx?)$/.test(localPath))
407
+ return { kind: "Remix route", reason: "Remix route module" };
383
408
  }
384
- if (/^(src\/)?app\/.+\/(page|layout|route|loading|error|not-found)\.(tsx?|jsx?)$/.test(localPath)) {
385
- return { kind: "Next.js route", reason: "App Router route segment entry" };
409
+ if (frameworks.includes("SvelteKit")) {
410
+ if (/^src\/routes\/(\+page|\+layout|\+server)\.(svelte|tsx?|jsx?)$/.test(localPath))
411
+ return { kind: "SvelteKit route", reason: "SvelteKit root route entry" };
412
+ if (/^src\/routes\/.+\/(\+page|\+layout|\+server)\.(svelte|tsx?|jsx?)$/.test(localPath))
413
+ return { kind: "SvelteKit route", reason: "SvelteKit route entry" };
414
+ if (/^src\/hooks(\.server)?\.(tsx?|jsx?)$/.test(localPath))
415
+ return { kind: "SvelteKit hook", reason: "SvelteKit lifecycle hook entry" };
386
416
  }
387
- if (/^(src\/)?pages\/index\.(tsx?|jsx?)$/.test(localPath))
388
- return { kind: "Next.js route", reason: "Pages Router index" };
389
- if (/^(src\/)?pages\/(api\/.+|.+)\.(tsx?|jsx?)$/.test(localPath))
390
- return { kind: "Next.js route", reason: "Pages Router route/API entry" };
391
- if (/^(src\/)?middleware\.(tsx?|jsx?)$/.test(localPath))
392
- return { kind: "Next.js middleware", reason: "Next.js request middleware entry" };
393
- if (/^next\.config\.(tsx?|jsx?|mjs|cjs)$/.test(localPath))
394
- return { kind: "Next.js config", reason: "Next.js configuration entry" };
395
- if (/^app\/(root|entry\.(client|server))\.(tsx?|jsx?)$/.test(localPath))
396
- return { kind: "Remix entry", reason: "Remix root/client/server entry" };
397
- if (/^app\/routes\/.+\.(tsx?|jsx?)$/.test(localPath))
398
- return { kind: "Remix route", reason: "Remix route module" };
399
- if (/^src\/routes\/(\+page|\+layout|\+server)\.(svelte|tsx?|jsx?)$/.test(localPath))
400
- return { kind: "SvelteKit route", reason: "SvelteKit root route entry" };
401
- if (/^src\/routes\/.+\/(\+page|\+layout|\+server)\.(svelte|tsx?|jsx?)$/.test(localPath))
402
- return { kind: "SvelteKit route", reason: "SvelteKit route entry" };
403
- if (/^src\/hooks(\.server)?\.(tsx?|jsx?)$/.test(localPath))
404
- return { kind: "SvelteKit hook", reason: "SvelteKit lifecycle hook entry" };
405
417
  return undefined;
406
418
  }
407
419
  function extractImportSpecifiers(text, from) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netanelyasi/agent-ready",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Generate an AI-agent harness for any codebase: CLAUDE.md, CODEMAP.md, skills, ignore rules, and readiness reports.",
5
5
  "type": "module",
6
6
  "bin": {