agents-md-gen 0.1.1 → 0.3.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 +20 -0
- package/bin/cli.js +21 -0
- package/package.json +4 -1
- package/src/detect.js +51 -1
- package/src/index.js +8 -1
package/README.md
CHANGED
|
@@ -20,8 +20,22 @@ on immediately.
|
|
|
20
20
|
- **Rust** — Cargo, workspaces, clippy
|
|
21
21
|
- **Go** — go.mod, golangci-lint
|
|
22
22
|
- **Ruby** — Bundler, RSpec
|
|
23
|
+
- **Java/Kotlin** — Maven, Gradle (with wrapper detection)
|
|
23
24
|
- CI (GitHub Actions), license, and top-level project structure
|
|
24
25
|
|
|
26
|
+
## GitHub Action
|
|
27
|
+
|
|
28
|
+
Use it directly in CI without installing anything:
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
- uses: Peshino2012/PD1@claude/busy-newton-5h97oh
|
|
32
|
+
with:
|
|
33
|
+
directory: .
|
|
34
|
+
also-claude-md: 'true'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
(pin to a tagged release instead of a branch once one exists)
|
|
38
|
+
|
|
25
39
|
A repo can match more than one of these (e.g. a Python backend next to a
|
|
26
40
|
Node frontend) — each detected stack gets its own section.
|
|
27
41
|
|
|
@@ -33,12 +47,18 @@ npx agents-md-gen ./some/repo # target a different directory
|
|
|
33
47
|
npx agents-md-gen --also-claude-md
|
|
34
48
|
npx agents-md-gen --dry-run # print instead of writing
|
|
35
49
|
npx agents-md-gen --force # overwrite an existing file
|
|
50
|
+
npx agents-md-gen --check # exit 1 if missing/stale, writes nothing (CI)
|
|
36
51
|
```
|
|
37
52
|
|
|
38
53
|
It won't overwrite an existing `AGENTS.md`/`CLAUDE.md` unless you pass
|
|
39
54
|
`--force` — this is meant to bootstrap a file you then edit by hand, not to
|
|
40
55
|
clobber one you already wrote.
|
|
41
56
|
|
|
57
|
+
`--check` is for CI: it fails the build if `AGENTS.md` doesn't exist or no
|
|
58
|
+
longer matches what the repo would generate, so a stale file (say, a new
|
|
59
|
+
test framework got added but nobody regenerated it) gets caught instead of
|
|
60
|
+
silently rotting. Pair it with the GitHub Action below.
|
|
61
|
+
|
|
42
62
|
## Example
|
|
43
63
|
|
|
44
64
|
Real output — this is what `npx agents-md-gen` produces when run against
|
package/bin/cli.js
CHANGED
|
@@ -11,6 +11,7 @@ function main() {
|
|
|
11
11
|
'also-claude-md': { type: 'boolean', default: false },
|
|
12
12
|
force: { type: 'boolean', short: 'f', default: false },
|
|
13
13
|
'dry-run': { type: 'boolean', default: false },
|
|
14
|
+
check: { type: 'boolean', default: false },
|
|
14
15
|
help: { type: 'boolean', short: 'h', default: false },
|
|
15
16
|
},
|
|
16
17
|
allowPositionals: true,
|
|
@@ -26,6 +27,7 @@ Options:
|
|
|
26
27
|
--also-claude-md Also write an identical CLAUDE.md
|
|
27
28
|
-f, --force Overwrite existing file(s)
|
|
28
29
|
--dry-run Print to stdout instead of writing
|
|
30
|
+
--check Exit 1 if the file is missing or out of date (CI use, writes nothing)
|
|
29
31
|
-h, --help Show this help
|
|
30
32
|
`);
|
|
31
33
|
return;
|
|
@@ -33,6 +35,25 @@ Options:
|
|
|
33
35
|
|
|
34
36
|
const cwd = positionals[0] ? path.resolve(positionals[0]) : process.cwd();
|
|
35
37
|
|
|
38
|
+
if (values.check) {
|
|
39
|
+
const { upToDate, existed, target } = run({
|
|
40
|
+
cwd,
|
|
41
|
+
output: values.output,
|
|
42
|
+
check: true,
|
|
43
|
+
});
|
|
44
|
+
if (upToDate) {
|
|
45
|
+
console.log(`${target} is up to date`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
console.error(
|
|
49
|
+
existed
|
|
50
|
+
? `${target} is out of date - run agents-md-gen --force to update it`
|
|
51
|
+
: `${target} does not exist - run agents-md-gen to create it`
|
|
52
|
+
);
|
|
53
|
+
process.exitCode = 1;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
36
57
|
const { written, skipped } = run({
|
|
37
58
|
cwd,
|
|
38
59
|
output: values.output,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agents-md-gen",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Generate a solid AGENTS.md / CLAUDE.md for any repo by detecting its stack, commands, and structure",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
"github-copilot",
|
|
27
27
|
"openai-codex",
|
|
28
28
|
"readme-generator",
|
|
29
|
+
"java",
|
|
30
|
+
"maven",
|
|
31
|
+
"gradle",
|
|
29
32
|
"cli",
|
|
30
33
|
"codegen",
|
|
31
34
|
"developer-tools"
|
package/src/detect.js
CHANGED
|
@@ -165,6 +165,50 @@ function detectGo(root) {
|
|
|
165
165
|
};
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
function detectJava(root) {
|
|
169
|
+
const hasGradle = exists(root, 'build.gradle') || exists(root, 'build.gradle.kts');
|
|
170
|
+
const hasMaven = exists(root, 'pom.xml');
|
|
171
|
+
if (!hasGradle && !hasMaven) return null;
|
|
172
|
+
|
|
173
|
+
if (hasGradle) {
|
|
174
|
+
const gradleCmd = exists(root, 'gradlew') ? './gradlew' : 'gradle';
|
|
175
|
+
return {
|
|
176
|
+
ecosystem: 'Java/Kotlin (Gradle)',
|
|
177
|
+
name: null,
|
|
178
|
+
description: null,
|
|
179
|
+
packageManager: 'gradle',
|
|
180
|
+
frameworks: [],
|
|
181
|
+
testFramework: null,
|
|
182
|
+
commands: {
|
|
183
|
+
install: `${gradleCmd} build`,
|
|
184
|
+
build: `${gradleCmd} build`,
|
|
185
|
+
test: `${gradleCmd} test`,
|
|
186
|
+
lint: null,
|
|
187
|
+
dev: null,
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const pom = readText(root, 'pom.xml') || '';
|
|
193
|
+
const nameMatch = pom.match(/<artifactId>([^<]+)<\/artifactId>/);
|
|
194
|
+
const mvnCmd = exists(root, 'mvnw') ? './mvnw' : 'mvn';
|
|
195
|
+
return {
|
|
196
|
+
ecosystem: 'Java (Maven)',
|
|
197
|
+
name: nameMatch ? nameMatch[1] : null,
|
|
198
|
+
description: null,
|
|
199
|
+
packageManager: 'maven',
|
|
200
|
+
frameworks: [],
|
|
201
|
+
testFramework: null,
|
|
202
|
+
commands: {
|
|
203
|
+
install: `${mvnCmd} install`,
|
|
204
|
+
build: `${mvnCmd} package`,
|
|
205
|
+
test: `${mvnCmd} test`,
|
|
206
|
+
lint: null,
|
|
207
|
+
dev: null,
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
168
212
|
function detectRuby(root) {
|
|
169
213
|
if (!exists(root, 'Gemfile')) return null;
|
|
170
214
|
const hasRspec = exists(root, '.rspec') || exists(root, 'spec');
|
|
@@ -185,6 +229,11 @@ function detectRuby(root) {
|
|
|
185
229
|
};
|
|
186
230
|
}
|
|
187
231
|
|
|
232
|
+
// Excluded so re-running the generator doesn't see its own prior output as
|
|
233
|
+
// part of the repo's structure - otherwise the file it just wrote would
|
|
234
|
+
// never match a freshly rendered one, breaking `--check`.
|
|
235
|
+
const OWN_OUTPUT_FILES = new Set(['AGENTS.md', 'CLAUDE.md']);
|
|
236
|
+
|
|
188
237
|
function listStructure(root) {
|
|
189
238
|
let entries;
|
|
190
239
|
try {
|
|
@@ -195,6 +244,7 @@ function listStructure(root) {
|
|
|
195
244
|
return entries
|
|
196
245
|
.filter((e) => !e.name.startsWith('.') || e.name === '.github')
|
|
197
246
|
.filter((e) => !IGNORE_DIRS.has(e.name))
|
|
247
|
+
.filter((e) => !OWN_OUTPUT_FILES.has(e.name))
|
|
198
248
|
.map((e) => (e.isDirectory() ? `${e.name}/` : e.name))
|
|
199
249
|
.sort();
|
|
200
250
|
}
|
|
@@ -223,7 +273,7 @@ function detectLicense(root) {
|
|
|
223
273
|
}
|
|
224
274
|
|
|
225
275
|
function detectProject(root) {
|
|
226
|
-
const detectors = [detectNode, detectPython, detectRust, detectGo, detectRuby];
|
|
276
|
+
const detectors = [detectNode, detectPython, detectRust, detectGo, detectRuby, detectJava];
|
|
227
277
|
const stacks = detectors.map((fn) => fn(root)).filter(Boolean);
|
|
228
278
|
|
|
229
279
|
return {
|
package/src/index.js
CHANGED
|
@@ -4,7 +4,7 @@ const path = require('path');
|
|
|
4
4
|
const { detectProject } = require('./detect');
|
|
5
5
|
const { renderAgentsMd } = require('./render');
|
|
6
6
|
|
|
7
|
-
function run({ cwd, output, alsoClaudeMd, force, dryRun }) {
|
|
7
|
+
function run({ cwd, output, alsoClaudeMd, force, dryRun, check }) {
|
|
8
8
|
const project = detectProject(cwd);
|
|
9
9
|
const content = renderAgentsMd(project);
|
|
10
10
|
|
|
@@ -13,6 +13,13 @@ function run({ cwd, output, alsoClaudeMd, force, dryRun }) {
|
|
|
13
13
|
return { written: [], skipped: [] };
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
if (check) {
|
|
17
|
+
const fullPath = path.join(cwd, output);
|
|
18
|
+
const existing = fs.existsSync(fullPath) ? fs.readFileSync(fullPath, 'utf8') : null;
|
|
19
|
+
const upToDate = existing === content;
|
|
20
|
+
return { upToDate, existed: existing !== null, target: output };
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
const targets = [output];
|
|
17
24
|
if (alsoClaudeMd && !targets.includes('CLAUDE.md')) targets.push('CLAUDE.md');
|
|
18
25
|
|