agents-md-gen 0.4.2 → 0.6.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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.0
4
+
5
+ - Detect Swift packages (`Package.swift`, XCTest detection).
6
+
7
+ ## 0.5.0
8
+
9
+ - Detect PHP/Composer projects (Laravel/Symfony framework detection,
10
+ PHPUnit, PHPCS).
11
+ - Detect .NET/C# projects via `.csproj`/`.sln` (xUnit/NUnit/MSTest
12
+ detection).
13
+
3
14
  ## 0.4.2
4
15
 
5
16
  - Detect Docker (`Dockerfile`, `docker-compose.yml`/`compose.yml`) and
package/README.md CHANGED
@@ -60,6 +60,9 @@ docker run --rm -v "$PWD":/workdir ghcr.io/peshino2012/agents-md-gen
60
60
  - **Go** — go.mod, golangci-lint
61
61
  - **Ruby** — Bundler, RSpec
62
62
  - **Java/Kotlin** — Maven, Gradle (with wrapper detection)
63
+ - **PHP** — Composer, Laravel/Symfony detection, PHPUnit
64
+ - **.NET/C#** — NuGet, xUnit/NUnit/MSTest detection
65
+ - **Swift** — Swift Package Manager, XCTest detection
63
66
  - **Monorepos** — Turborepo, Nx, Lerna, npm/yarn/pnpm workspaces, listing
64
67
  each detected sub-package
65
68
  - CI (GitHub Actions), license, and top-level project structure
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agents-md-gen",
3
- "version": "0.4.2",
3
+ "version": "0.6.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
  "funding": {
@@ -37,6 +37,13 @@
37
37
  "monorepo",
38
38
  "turborepo",
39
39
  "nx",
40
+ "php",
41
+ "composer",
42
+ "laravel",
43
+ "dotnet",
44
+ "csharp",
45
+ "swift",
46
+ "swiftpm",
40
47
  "cli",
41
48
  "codegen",
42
49
  "developer-tools"
package/src/detect.js CHANGED
@@ -229,6 +229,94 @@ function detectRuby(root) {
229
229
  };
230
230
  }
231
231
 
232
+ function detectSwift(root) {
233
+ const manifest = readText(root, 'Package.swift');
234
+ if (!manifest) return null;
235
+ const nameMatch = manifest.match(/name:\s*"([^"]+)"/);
236
+ const usesXCTest = /XCTest/.test(manifest) || exists(root, 'Tests');
237
+
238
+ return {
239
+ ecosystem: 'Swift',
240
+ name: nameMatch ? nameMatch[1] : null,
241
+ description: null,
242
+ packageManager: 'swiftpm',
243
+ frameworks: [],
244
+ testFramework: usesXCTest ? 'XCTest' : null,
245
+ commands: {
246
+ install: 'swift package resolve',
247
+ build: 'swift build',
248
+ test: usesXCTest ? 'swift test' : null,
249
+ lint: exists(root, '.swiftlint.yml') ? 'swiftlint' : null,
250
+ dev: null,
251
+ },
252
+ };
253
+ }
254
+
255
+ function detectPhp(root) {
256
+ const composer = readJson(root, 'composer.json');
257
+ if (!composer) return null;
258
+
259
+ const deps = composer.require || {};
260
+ const devDeps = composer['require-dev'] || {};
261
+ const usesPhpunit = 'phpunit/phpunit' in devDeps || exists(root, 'phpunit.xml') || exists(root, 'phpunit.xml.dist');
262
+ const usesPhpcs = 'squizlabs/php_codesniffer' in devDeps || exists(root, 'phpcs.xml') || exists(root, 'phpcs.xml.dist');
263
+ const scripts = composer.scripts || {};
264
+
265
+ return {
266
+ ecosystem: 'PHP',
267
+ name: composer.name || null,
268
+ description: composer.description || null,
269
+ packageManager: 'composer',
270
+ frameworks: [
271
+ 'laravel/framework' in deps ? 'Laravel' : null,
272
+ 'symfony/framework-bundle' in deps ? 'Symfony' : null,
273
+ ].filter(Boolean),
274
+ testFramework: usesPhpunit ? 'PHPUnit' : null,
275
+ commands: {
276
+ install: 'composer install',
277
+ build: null,
278
+ test: scripts.test ? 'composer test' : (usesPhpunit ? 'vendor/bin/phpunit' : null),
279
+ lint: usesPhpcs ? 'vendor/bin/phpcs' : null,
280
+ dev: null,
281
+ },
282
+ };
283
+ }
284
+
285
+ function detectDotnet(root) {
286
+ let entries;
287
+ try {
288
+ entries = fs.readdirSync(root, { withFileTypes: true });
289
+ } catch {
290
+ return null;
291
+ }
292
+ const files = entries.filter((e) => e.isFile()).map((e) => e.name);
293
+ const sln = files.find((f) => f.endsWith('.sln'));
294
+ const csproj = files.find((f) => f.endsWith('.csproj'));
295
+ if (!sln && !csproj) return null;
296
+
297
+ const projectText = csproj ? (readText(root, csproj) || '') : '';
298
+ const testFramework = /xunit/i.test(projectText) ? 'xUnit'
299
+ : /nunit/i.test(projectText) ? 'NUnit'
300
+ : /Microsoft\.NET\.Test\.Sdk/i.test(projectText) ? 'MSTest'
301
+ : null;
302
+
303
+ return {
304
+ ecosystem: '.NET',
305
+ name: sln ? sln.replace(/\.sln$/, '') : (csproj ? csproj.replace(/\.csproj$/, '') : null),
306
+ description: null,
307
+ packageManager: 'nuget',
308
+ frameworks: [],
309
+ testFramework,
310
+ commands: {
311
+ install: 'dotnet restore',
312
+ build: 'dotnet build',
313
+ test: testFramework ? 'dotnet test' : null,
314
+ lint: 'dotnet format',
315
+ dev: null,
316
+ },
317
+ };
318
+ }
319
+
232
320
  // Excluded so re-running the generator doesn't see its own prior output as
233
321
  // part of the repo's structure - otherwise the file it just wrote would
234
322
  // never match a freshly rendered one, breaking `--check`.
@@ -325,7 +413,7 @@ function detectMonorepo(root) {
325
413
  }
326
414
 
327
415
  function detectProject(root) {
328
- const detectors = [detectNode, detectPython, detectRust, detectGo, detectRuby, detectJava];
416
+ const detectors = [detectNode, detectPython, detectRust, detectGo, detectRuby, detectJava, detectPhp, detectDotnet, detectSwift];
329
417
  const stacks = detectors.map((fn) => fn(root)).filter(Boolean);
330
418
 
331
419
  return {