compose-agentsmd 3.3.1 → 3.4.0

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
@@ -2,6 +2,10 @@
2
2
 
3
3
  This repository contains CLI tooling for composing per-project `AGENTS.md` files from modular rule sets.
4
4
 
5
+ ## Compatibility
6
+
7
+ - Node.js >= 20
8
+
5
9
  ## Release notes
6
10
 
7
11
  See `CHANGELOG.md` for release notes.
@@ -147,11 +151,16 @@ npm install
147
151
  npm run lint
148
152
  npm run build
149
153
  npm test
150
- ```
151
-
152
- ## Overview
153
- This repository contains the compose-agentsmd project.
154
-
155
- ## Requirements and Configuration
156
- - No required environment variables are documented.
157
-
154
+ ```
155
+
156
+ ## Overview
157
+
158
+ This repository contains the compose-agentsmd project.
159
+
160
+ ## Documentation
161
+
162
+ - [CHANGELOG.md](CHANGELOG.md)
163
+ - [CONTRIBUTING.md](CONTRIBUTING.md)
164
+ - [SECURITY.md](SECURITY.md)
165
+ - [LICENSE](LICENSE)
166
+ - [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
@@ -252,7 +252,7 @@ const stripJsonComments = (input) => {
252
252
  i += 1;
253
253
  continue;
254
254
  }
255
- if (char === "\"" || char === "'") {
255
+ if (char === '"' || char === "'") {
256
256
  inString = true;
257
257
  stringChar = char;
258
258
  output += char;
@@ -435,7 +435,9 @@ const resolveGithubRulesRoot = (source, refresh) => {
435
435
  if (!resolvedHash && !looksLikeCommitHash(resolvedRef)) {
436
436
  throw new Error(`Unable to resolve ref ${resolvedRef} for ${parsed.url}`);
437
437
  }
438
- const cacheSegment = resolvedRef === "HEAD" ? sanitizeCacheSegment(resolvedHash ?? resolvedRef) : sanitizeCacheSegment(resolvedRef);
438
+ const cacheSegment = resolvedRef === "HEAD"
439
+ ? sanitizeCacheSegment(resolvedHash ?? resolvedRef)
440
+ : sanitizeCacheSegment(resolvedRef);
439
441
  const cacheDir = path.join(DEFAULT_CACHE_ROOT, parsed.owner, parsed.repo, cacheSegment);
440
442
  if (refresh && fs.existsSync(cacheDir)) {
441
443
  fs.rmSync(cacheDir, { recursive: true, force: true });
@@ -531,7 +533,8 @@ const resolveOutputPaths = (rulesetDir, projectRuleset) => {
531
533
  const claude = projectRuleset.claude ?? {};
532
534
  const companionEnabled = claude.enabled !== false;
533
535
  const configuredCompanionPath = resolveFrom(rulesetDir, claude.output ?? DEFAULT_CLAUDE_OUTPUT);
534
- if (!companionEnabled || path.resolve(primaryOutputPath) === path.resolve(configuredCompanionPath)) {
536
+ if (!companionEnabled ||
537
+ path.resolve(primaryOutputPath) === path.resolve(configuredCompanionPath)) {
535
538
  return { primaryOutputPath };
536
539
  }
537
540
  return { primaryOutputPath, companionOutputPath: configuredCompanionPath };
@@ -585,7 +588,9 @@ const composeRuleset = (rulesetPath, rootDir, options) => {
585
588
  }
586
589
  let agentsMdDiff;
587
590
  if (options.emitAgentsMdDiff && path.basename(primaryOutputPath) === DEFAULT_OUTPUT) {
588
- const before = fs.existsSync(primaryOutputPath) ? fs.readFileSync(primaryOutputPath, "utf8") : "";
591
+ const before = fs.existsSync(primaryOutputPath)
592
+ ? fs.readFileSync(primaryOutputPath, "utf8")
593
+ : "";
589
594
  if (before === primaryOutputContent) {
590
595
  agentsMdDiff = { status: "unchanged" };
591
596
  }
@@ -658,23 +663,23 @@ const formatInitRuleset = (ruleset) => {
658
663
  const claudeOutput = ruleset.claude?.output ?? DEFAULT_CLAUDE_OUTPUT;
659
664
  const lines = [
660
665
  "{",
661
- ' // Rules source. Use github:owner/repo@ref or a local path.',
666
+ " // Rules source. Use github:owner/repo@ref or a local path.",
662
667
  ` "source": "${ruleset.source}",`,
663
- ' // Domain folders under rules/domains.',
668
+ " // Domain folders under rules/domains.",
664
669
  ` "domains": ${domainsValue},`,
665
- ' // Additional local rule files to append.',
670
+ " // Additional local rule files to append.",
666
671
  ` "extra": ${extraValue},`
667
672
  ];
668
673
  if (ruleset.global === false) {
669
- lines.push(' // Include rules/global from the source.');
674
+ lines.push(" // Include rules/global from the source.");
670
675
  lines.push(' "global": false,');
671
676
  }
672
- lines.push(' // Claude Code companion output settings.');
677
+ lines.push(" // Claude Code companion output settings.");
673
678
  lines.push(' "claude": {');
674
679
  lines.push(` "enabled": ${claudeEnabled ? "true" : "false"},`);
675
680
  lines.push(` "output": "${claudeOutput}"`);
676
681
  lines.push(" },");
677
- lines.push(' // Output file name.');
682
+ lines.push(" // Output file name.");
678
683
  lines.push(` "output": "${ruleset.output ?? DEFAULT_OUTPUT}"`);
679
684
  lines.push("}");
680
685
  return `${lines.join("\n")}\n`;
@@ -700,7 +705,9 @@ const confirmInit = async (args) => {
700
705
  }
701
706
  };
702
707
  const initProject = async (args, rootDir, rulesetName) => {
703
- const rulesetPath = args.ruleset ? resolveFrom(rootDir, args.ruleset) : path.join(rootDir, rulesetName);
708
+ const rulesetPath = args.ruleset
709
+ ? resolveFrom(rootDir, args.ruleset)
710
+ : path.join(rootDir, rulesetName);
704
711
  const rulesetDir = path.dirname(rulesetPath);
705
712
  const ruleset = buildInitRuleset(args);
706
713
  const outputPaths = resolveOutputPaths(rulesetDir, ruleset);
@@ -892,9 +899,7 @@ const main = async () => {
892
899
  const expectedPath = normalizePath(path.join(rootDir, rulesetName));
893
900
  throw new Error(`Missing ruleset file: ${expectedPath}`);
894
901
  }
895
- const outputs = rulesetFiles
896
- .sort()
897
- .map((rulesetPath) => composeRuleset(rulesetPath, rootDir, {
902
+ const outputs = rulesetFiles.sort().map((rulesetPath) => composeRuleset(rulesetPath, rootDir, {
898
903
  refresh: args.refresh,
899
904
  dryRun: args.dryRun,
900
905
  emitAgentsMdDiff: !args.quiet && !args.json
@@ -903,7 +908,10 @@ const main = async () => {
903
908
  process.stdout.write(JSON.stringify({ composed: outputs.flatMap((result) => result.outputs), dryRun: !!args.dryRun }, null, 2) + "\n");
904
909
  }
905
910
  else if (!args.quiet) {
906
- process.stdout.write(`Composed AGENTS.md:\n${outputs.flatMap((result) => result.outputs).map((filePath) => `- ${filePath}`).join("\n")}\n`);
911
+ process.stdout.write(`Composed AGENTS.md:\n${outputs
912
+ .flatMap((result) => result.outputs)
913
+ .map((filePath) => `- ${filePath}`)
914
+ .join("\n")}\n`);
907
915
  for (const result of outputs) {
908
916
  printAgentsMdDiffIfPresent(result);
909
917
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compose-agentsmd",
3
- "version": "3.3.1",
3
+ "version": "3.4.0",
4
4
  "description": "CLI tools for composing per-project AGENTS.md files from modular rule sets",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -34,18 +34,29 @@
34
34
  },
35
35
  "scripts": {
36
36
  "build": "tsc -p tsconfig.json",
37
- "lint": "tsc -p tsconfig.json --noEmit",
37
+ "lint": "eslint . && tsc -p tsconfig.json --noEmit",
38
+ "format": "prettier --write .",
39
+ "format:check": "prettier --check .",
38
40
  "prepare": "npm run build",
39
41
  "prepack": "npm run build",
40
- "test": "npm run build && node --test",
42
+ "test": "npm run build && vitest run",
43
+ "verify": "npm run lint && npm run format:check && npm test",
41
44
  "compose": "npm run build && node dist/compose-agents.js"
42
45
  },
43
46
  "engines": {
44
47
  "node": ">=20"
45
48
  },
46
49
  "devDependencies": {
50
+ "@eslint/js": "^10.0.1",
51
+ "@types/diff": "^7.0.2",
47
52
  "@types/node": "^25.1.0",
48
- "typescript": "^5.7.3"
53
+ "@typescript-eslint/eslint-plugin": "^8.56.0",
54
+ "@typescript-eslint/parser": "^8.56.0",
55
+ "eslint": "^10.0.1",
56
+ "globals": "^17.3.0",
57
+ "prettier": "^3.8.1",
58
+ "typescript": "^5.7.3",
59
+ "vitest": "^4.0.18"
49
60
  },
50
61
  "dependencies": {
51
62
  "ajv": "^8.17.1",
@@ -1,13 +1,12 @@
1
1
  # Tool Rules (compose-agentsmd)
2
+
2
3
  - Before starting any work, run `compose-agentsmd` from the project root.
3
4
  - `compose-agentsmd` intentionally regenerates `AGENTS.md`; any resulting `AGENTS.md` diff is expected and must not be treated as an unexpected external change.
4
5
  - If `compose-agentsmd` is not available, install it via npm: `npm install -g compose-agentsmd`.
5
- - To update shared rules, run `compose-agentsmd edit-rules`, edit the workspace rules, then run `compose-agentsmd apply-rules`.
6
+ - To update shared/global rules, use `compose-agentsmd edit-rules` to locate the writable rules workspace, make changes only in that workspace, then run `compose-agentsmd apply-rules` (do not manually clone or edit the rules source repo outside this workflow).
7
+ - If you find an existing clone of the rules source repo elsewhere, do not assume it is the correct rules workspace; always treat `compose-agentsmd edit-rules` output as the source of truth.
6
8
  - `compose-agentsmd apply-rules` pushes the rules workspace when `source` is GitHub (if the workspace is clean), then regenerates `AGENTS.md` with refreshed rules.
7
9
  - Do not edit `AGENTS.md` directly; update the source rules and regenerate.
8
10
  - `tools/tool-rules.md` is the shared rule source for all repositories that use compose-agentsmd.
9
- - Before applying any rule updates, present the planned changes first (prefer a colorized diff-style preview), ask for explicit approval, then make the edits.
10
- - These tool rules live in tools/tool-rules.md in the compose-agentsmd repository; do not duplicate them in global rule modules.
11
- - When updating rules, include a colorized diff-style summary in the final response. Use `git diff --stat` first, then include the raw ANSI-colored output of `git diff --color=always` (no sanitizing or reformatting), and limit the output to the rule files that changed.
12
- - Also provide a short, copy-pasteable command the user can run to view the diff in the same format. Use absolute paths so it works regardless of the current working directory, and scope it to the changed rule files.
13
- - If a diff is provided, a separate detailed summary is not required. If a diff is not possible, include a detailed summary of what changed (added/removed/modified items).
11
+ - Before applying any rule updates, present the planned changes first with an ANSI-colored diff-style preview, ask for explicit approval, then make the edits.
12
+ - These tool rules live in tools/tool-rules.md in the compose-agentsmd repository; do not duplicate them in other rule modules.