@netanelyasi/agent-ready 0.2.1 → 0.2.2

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.0-111827?style=flat-square" />
17
+ <img alt="Version" src="https://img.shields.io/badge/version-0.2.2-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" />
@@ -4,7 +4,7 @@ export function generateFiles(scan, score, force) {
4
4
  add("CLAUDE.md", generateClaudeMd(scan));
5
5
  add("CODEMAP.md", generateCodemap(scan));
6
6
  add(".aiignore", generateAiIgnore(scan));
7
- add(".claude/settings.json", generateClaudeSettings(scan));
7
+ add(".claude/settings.json", generateClaudeSettings());
8
8
  add(".claude/hooks/prevent-destructive.mjs", generatePreventDestructiveHook());
9
9
  add(".claude/hooks/protect-generated.mjs", generateProtectGeneratedHook());
10
10
  add(".claude/hooks/suggest-validation.mjs", generateSuggestValidationHook(scan));
@@ -132,6 +132,20 @@ function commandLines(scan) {
132
132
  lines.push("- No standard validation commands were detected. Add project-specific commands here.");
133
133
  return lines;
134
134
  }
135
+ // Flat one-command-per-rule list for the validation skill, e.g. "test: `npm run test`".
136
+ // Unlike commandLines (which nests for CLAUDE.md), this stays flat so it renders
137
+ // correctly as a SKILL.md bullet list.
138
+ function validationSkillRules(scan) {
139
+ const order = ["dev", "build", "test", "lint", "typecheck", "format"];
140
+ const rules = [];
141
+ for (const name of order) {
142
+ for (const command of (scan.commands[name] ?? []).slice(0, 8))
143
+ rules.push(`${name}: \`${command}\``);
144
+ }
145
+ if (!rules.length)
146
+ rules.push("No standard validation commands were detected. Add project-specific commands here.");
147
+ return rules;
148
+ }
135
149
  function generateCodemap(scan) {
136
150
  return [
137
151
  `# ${scan.name} — CODEMAP`,
@@ -228,7 +242,7 @@ function generateAiIgnore(scan) {
228
242
  add(`${noisy}/`);
229
243
  return `${base.join("\n")}\n`;
230
244
  }
231
- function generateClaudeSettings(scan) {
245
+ function generateClaudeSettings() {
232
246
  const deniedPathPatterns = [
233
247
  "node_modules/**",
234
248
  ".next/**",
@@ -467,7 +481,7 @@ function hookRecommendations(scan) {
467
481
  function generateSkills(scan) {
468
482
  const skills = [
469
483
  { slug: "codebase-navigation", content: skill("codebase-navigation", "Use when starting work in this repository or when a task spans unfamiliar directories.", ["Read CODEMAP.md first.", "Use narrow searches from the relevant directory before global search.", "Prefer symbol/reference search when LSP is available.", "Do not inspect ignored/generated directories unless explicitly needed."]) },
470
- { slug: "validation", content: skill("validation", "Use after code edits or before declaring a task complete.", [...commandLines(scan).map((line) => line.replace(/^[- ]+/, "")), "Run the narrowest relevant command first.", "If validation cannot be run, report the exact reason."]) },
484
+ { slug: "validation", content: skill("validation", "Use after code edits or before declaring a task complete.", [...validationSkillRules(scan), "Run the narrowest relevant command first.", "If validation cannot be run, report the exact reason."]) },
471
485
  ];
472
486
  if (scan.frameworks.includes("Next.js"))
473
487
  skills.push({ slug: "nextjs-hydration", content: skill("nextjs-hydration", "Use when editing Next.js/React components, routes, or client/server boundaries.", ["Do not read localStorage/sessionStorage/window/document during server render or initial state.", "Use useEffect or guarded client-only code for browser APIs.", "Avoid Math.random() or new Date() in render paths that must hydrate identically.", "Keep server/client boundaries explicit."]) });
@@ -480,7 +494,28 @@ function generateSkills(scan) {
480
494
  return skills;
481
495
  }
482
496
  function skill(name, description, rules) {
483
- return [`# ${name}`, "", `Description: ${description}`, "", "## Rules", ...rules.map((rule) => `- ${rule}`), ""].join("\n");
497
+ return [
498
+ "---",
499
+ `name: ${name}`,
500
+ `description: ${yamlScalar(description)}`,
501
+ "---",
502
+ "",
503
+ `# ${name}`,
504
+ "",
505
+ description,
506
+ "",
507
+ "## Rules",
508
+ ...rules.map((rule) => `- ${rule}`),
509
+ "",
510
+ ].join("\n");
511
+ }
512
+ // Claude Code parses SKILL.md frontmatter as YAML. Quote scalars that contain
513
+ // characters YAML would otherwise treat as structure (`:`, leading `#`, etc.).
514
+ function yamlScalar(value) {
515
+ if (/^[^\s].*[:#]|^[#&*!|>%@`"']|:\s|\s#/.test(value)) {
516
+ return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
517
+ }
518
+ return value;
484
519
  }
485
520
  function list(items) {
486
521
  return items.length ? items.join(", ") : "none detected";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netanelyasi/agent-ready",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
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": {