agents.yaml 0.1.0 → 0.2.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/AGENTS.md +3 -2
- package/README.md +4 -3
- package/dist/index.mjs +53 -15
- package/package.json +7 -10
- package/src/agents-file.ts +13 -5
- package/src/discover.test.ts +47 -4
- package/src/discover.ts +47 -4
- package/src/index.ts +0 -0
- package/src/run.ts +20 -10
package/AGENTS.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This package provides the `agents` CLI for maintaining an `agents.yaml` file.
|
|
4
4
|
|
|
5
|
-
`agents.yaml` is a curated table of contents for
|
|
5
|
+
`agents.yaml` is a curated table of contents for promoted agent-readable documentation. It does not define a new instruction language, replace `AGENTS.md`, or automatically load every dependency document.
|
|
6
6
|
|
|
7
7
|
The file format is intentionally small:
|
|
8
8
|
|
|
@@ -11,9 +11,10 @@ version: 1
|
|
|
11
11
|
|
|
12
12
|
documents:
|
|
13
13
|
- path: ./node_modules/example-package/AGENTS.md
|
|
14
|
+
description: Useful package context from example-package's package.json.
|
|
14
15
|
```
|
|
15
16
|
|
|
16
|
-
Agents should treat
|
|
17
|
+
Agents should treat paths listed in `documents` as promoted supplemental guidance for the project. Descriptions are human-readable breadcrumbs that explain why the package guidance may be relevant; they are not additional instructions.
|
|
17
18
|
|
|
18
19
|
The CLI can help discover package and local `AGENTS.md` files, add selected paths to `agents.yaml`, remove paths, initialize the root breadcrumb, and validate that referenced files still exist.
|
|
19
20
|
|
package/README.md
CHANGED
|
@@ -30,12 +30,13 @@ version: 1
|
|
|
30
30
|
|
|
31
31
|
documents:
|
|
32
32
|
- path: ./node_modules/react/AGENTS.md
|
|
33
|
+
description: React is a JavaScript library for building user interfaces.
|
|
33
34
|
```
|
|
34
35
|
|
|
36
|
+
Descriptions are optional breadcrumbs, usually copied from the package's `package.json`, that make lesser-known package guidance easier to recognize at a glance. Only `path` activates a supplemental guidance document.
|
|
37
|
+
|
|
35
38
|
Add this breadcrumb to your root `AGENTS.md`:
|
|
36
39
|
|
|
37
40
|
```md
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
Only the documents listed there should be considered active external guidance for this project.
|
|
41
|
+
Consult `./agents.yaml` when working with outside dependencies.
|
|
41
42
|
```
|
package/dist/index.mjs
CHANGED
|
@@ -20,11 +20,12 @@ function formatProjectPath(root, target) {
|
|
|
20
20
|
//#region src/agents-file.ts
|
|
21
21
|
const fileSchema = z.object({
|
|
22
22
|
version: z.literal(1),
|
|
23
|
-
documents: z.array(z.object({
|
|
23
|
+
documents: z.array(z.object({
|
|
24
|
+
path: z.string().min(1),
|
|
25
|
+
description: z.string().min(1).optional()
|
|
26
|
+
}))
|
|
24
27
|
});
|
|
25
|
-
const breadcrumb = `
|
|
26
|
-
|
|
27
|
-
Only the documents listed there should be considered active external guidance for this project.`;
|
|
28
|
+
const breadcrumb = `Consult \`./agents.yaml\` when working with outside dependencies.`;
|
|
28
29
|
async function loadAgentsFile(root) {
|
|
29
30
|
const filePath = agentsPath(root);
|
|
30
31
|
try {
|
|
@@ -43,14 +44,24 @@ async function loadAgentsFile(root) {
|
|
|
43
44
|
async function saveAgentsFile(root, file) {
|
|
44
45
|
const normalized = {
|
|
45
46
|
version: file.version,
|
|
46
|
-
documents: file.documents.map((doc) => ({
|
|
47
|
+
documents: file.documents.map((doc) => ({
|
|
48
|
+
path: doc.path,
|
|
49
|
+
...doc.description ? { description: doc.description } : {}
|
|
50
|
+
}))
|
|
47
51
|
};
|
|
48
52
|
await writeFile(agentsPath(root), YAML.stringify(normalized, { lineWidth: 0 }), "utf8");
|
|
49
53
|
}
|
|
50
54
|
async function addDocuments(root, documents) {
|
|
51
55
|
const file = await loadAgentsFile(root);
|
|
52
56
|
const byPath = new Map(file.documents.map((doc) => [doc.path, doc]));
|
|
53
|
-
for (const document of documents)
|
|
57
|
+
for (const document of documents) {
|
|
58
|
+
const existing = byPath.get(document.path);
|
|
59
|
+
byPath.set(document.path, {
|
|
60
|
+
path: document.path,
|
|
61
|
+
...existing?.description ? { description: existing.description } : {},
|
|
62
|
+
...document.description ? { description: document.description } : {}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
54
65
|
const next = {
|
|
55
66
|
version: 1,
|
|
56
67
|
documents: [...byPath.values()].sort((left, right) => left.path.localeCompare(right.path))
|
|
@@ -166,6 +177,10 @@ async function discoverAgentDocuments(root) {
|
|
|
166
177
|
await walk(root, root, found);
|
|
167
178
|
return found.filter((document) => document.path !== "./AGENTS.md").sort((left, right) => left.path.localeCompare(right.path));
|
|
168
179
|
}
|
|
180
|
+
async function describeAgentDocument(root, agentsDocumentPath) {
|
|
181
|
+
const absolutePath = resolveFromRoot(root, agentsDocumentPath);
|
|
182
|
+
return documentEntry(root, absolutePath, await readPackageDescription(path.dirname(absolutePath)));
|
|
183
|
+
}
|
|
169
184
|
async function walk(root, directory, found) {
|
|
170
185
|
let handle;
|
|
171
186
|
try {
|
|
@@ -183,7 +198,7 @@ async function walk(root, directory, found) {
|
|
|
183
198
|
if (!skippedDirectories.has(entry.name)) await walk(root, absolutePath, found);
|
|
184
199
|
continue;
|
|
185
200
|
}
|
|
186
|
-
if (entry.isFile() && entry.name === "AGENTS.md") found.push(
|
|
201
|
+
if (entry.isFile() && entry.name === "AGENTS.md") found.push(await documentEntry(root, absolutePath, await readPackageDescription(path.dirname(absolutePath))));
|
|
187
202
|
}
|
|
188
203
|
}
|
|
189
204
|
async function scanDirectNodeModules(root, nodeModulesPath, found) {
|
|
@@ -216,9 +231,29 @@ async function addPackageAgentsDocument(root, packagePath, found) {
|
|
|
216
231
|
const agentsPath = path.join(packagePath, "AGENTS.md");
|
|
217
232
|
try {
|
|
218
233
|
await access(agentsPath);
|
|
219
|
-
found.push(
|
|
234
|
+
found.push(await documentEntry(root, agentsPath, await readPackageDescription(packagePath)));
|
|
220
235
|
} catch {}
|
|
221
236
|
}
|
|
237
|
+
async function documentEntry(root, agentsPath, description) {
|
|
238
|
+
return {
|
|
239
|
+
path: formatProjectPath(root, agentsPath),
|
|
240
|
+
...description ? { description } : {}
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
async function readPackageDescription(packagePath) {
|
|
244
|
+
try {
|
|
245
|
+
const source = await readFile(path.join(packagePath, "package.json"), "utf8");
|
|
246
|
+
const parsed = JSON.parse(source);
|
|
247
|
+
if (!isPackageJson(parsed) || typeof parsed.description !== "string") return void 0;
|
|
248
|
+
const description = parsed.description.trim();
|
|
249
|
+
return description && description.length > 0 ? description : void 0;
|
|
250
|
+
} catch {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function isPackageJson(value) {
|
|
255
|
+
return typeof value === "object" && value !== null;
|
|
256
|
+
}
|
|
222
257
|
//#endregion
|
|
223
258
|
//#region src/run.ts
|
|
224
259
|
const helpText = `agents
|
|
@@ -231,7 +266,7 @@ Usage:
|
|
|
231
266
|
agents remove <path...>
|
|
232
267
|
agents validate [--json]
|
|
233
268
|
|
|
234
|
-
agents.yaml is a curated table of contents for
|
|
269
|
+
agents.yaml is a curated table of contents for promoted AGENTS.md guidance.`;
|
|
235
270
|
async function run(argv) {
|
|
236
271
|
const parsed = parseArgs(argv);
|
|
237
272
|
const root = cwd();
|
|
@@ -327,23 +362,26 @@ async function commandDiscover(root, json) {
|
|
|
327
362
|
clack.outro("No supplemental AGENTS.md files found.");
|
|
328
363
|
return;
|
|
329
364
|
}
|
|
330
|
-
clack.note(documents
|
|
365
|
+
clack.note(formatDocumentList(documents), `Found ${documents.length}`);
|
|
331
366
|
clack.outro("Use agents add <path> to enable one.");
|
|
332
367
|
}
|
|
333
368
|
async function commandAdd(root, paths) {
|
|
334
369
|
if (paths.length === 0) throw new Error("add requires at least one AGENTS.md path");
|
|
335
|
-
const documents = paths.map((path) => (
|
|
370
|
+
const documents = await Promise.all(paths.map((path) => describeAgentDocument(root, formatProjectPath(root, resolveFromRoot(root, path)))));
|
|
336
371
|
const file = await addDocuments(root, documents);
|
|
337
372
|
clack.intro("agents add");
|
|
338
|
-
clack.note(file.documents
|
|
373
|
+
clack.note(formatDocumentList(file.documents), "Promoted documents");
|
|
339
374
|
clack.outro(`Added ${documents.length} document${documents.length === 1 ? "" : "s"}.`);
|
|
340
375
|
}
|
|
376
|
+
function formatDocumentList(documents) {
|
|
377
|
+
return documents.map((doc) => doc.description ? `${doc.path}\n ${doc.description}` : doc.path).join("\n");
|
|
378
|
+
}
|
|
341
379
|
async function commandRemove(root, paths) {
|
|
342
380
|
if (paths.length === 0) throw new Error("remove requires at least one path");
|
|
343
381
|
const result = await removeDocuments(root, paths.map((path) => formatProjectPath(root, resolveFromRoot(root, path))));
|
|
344
382
|
clack.intro("agents remove");
|
|
345
|
-
clack.note(result.removed.join("\n") || "No matching documents were
|
|
346
|
-
clack.outro(`agents.yaml now has ${result.file.documents.length}
|
|
383
|
+
clack.note(result.removed.join("\n") || "No matching documents were listed.", "Removed");
|
|
384
|
+
clack.outro(`agents.yaml now has ${result.file.documents.length} promoted document${result.file.documents.length === 1 ? "" : "s"}.`);
|
|
347
385
|
}
|
|
348
386
|
async function commandValidate(root, json) {
|
|
349
387
|
const result = await validateAgentsFile(root);
|
|
@@ -391,7 +429,7 @@ async function interactive(root) {
|
|
|
391
429
|
const existing = await loadAgentsFile(root);
|
|
392
430
|
const candidates = (await discoverAgentDocuments(root)).filter((doc) => !existing.documents.some((active) => active.path === doc.path));
|
|
393
431
|
if (candidates.length === 0) {
|
|
394
|
-
clack.outro("No
|
|
432
|
+
clack.outro("No unlisted supplemental AGENTS.md files found.");
|
|
395
433
|
return;
|
|
396
434
|
}
|
|
397
435
|
const selected = await clack.multiselect({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agents.yaml",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A CLI for discovering and curating agent-readable documentation in agents.yaml.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,12 +16,6 @@
|
|
|
16
16
|
"AGENTS.md"
|
|
17
17
|
],
|
|
18
18
|
"type": "module",
|
|
19
|
-
"scripts": {
|
|
20
|
-
"build": "tsdown",
|
|
21
|
-
"dev": "src/index.ts",
|
|
22
|
-
"typecheck": "tsc --noEmit",
|
|
23
|
-
"check": "tsc --noEmit && tsdown"
|
|
24
|
-
},
|
|
25
19
|
"dependencies": {
|
|
26
20
|
"@clack/prompts": "1.5.1",
|
|
27
21
|
"yaml": "2.9.0",
|
|
@@ -29,12 +23,15 @@
|
|
|
29
23
|
},
|
|
30
24
|
"devDependencies": {
|
|
31
25
|
"@types/node": "25.9.2",
|
|
32
|
-
"tsdown": "0.22.2",
|
|
33
26
|
"typescript": "6.0.3"
|
|
34
27
|
},
|
|
35
28
|
"engines": {
|
|
36
29
|
"node": "26.3.0",
|
|
37
30
|
"pnpm": "11.5.2"
|
|
38
31
|
},
|
|
39
|
-
"
|
|
40
|
-
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "vp pack",
|
|
34
|
+
"dev": "src/index.ts",
|
|
35
|
+
"test": "vp test"
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/agents-file.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { resolveFromRoot } from './paths.ts'
|
|
|
6
6
|
|
|
7
7
|
export type AgentsDocumentEntry = {
|
|
8
8
|
path: string
|
|
9
|
+
description?: string | undefined
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export type AgentsFile = {
|
|
@@ -24,13 +25,12 @@ const fileSchema = z.object({
|
|
|
24
25
|
documents: z.array(
|
|
25
26
|
z.object({
|
|
26
27
|
path: z.string().min(1),
|
|
28
|
+
description: z.string().min(1).optional(),
|
|
27
29
|
}),
|
|
28
30
|
),
|
|
29
31
|
})
|
|
30
32
|
|
|
31
|
-
const breadcrumb = `
|
|
32
|
-
|
|
33
|
-
Only the documents listed there should be considered active external guidance for this project.`
|
|
33
|
+
const breadcrumb = `Consult \`./agents.yaml\` when working with outside dependencies.`
|
|
34
34
|
|
|
35
35
|
export async function loadAgentsFile(root: string): Promise<AgentsFile> {
|
|
36
36
|
const filePath = agentsPath(root)
|
|
@@ -57,7 +57,10 @@ export async function loadAgentsFile(root: string): Promise<AgentsFile> {
|
|
|
57
57
|
export async function saveAgentsFile(root: string, file: AgentsFile): Promise<void> {
|
|
58
58
|
const normalized = {
|
|
59
59
|
version: file.version,
|
|
60
|
-
documents: file.documents.map((doc) => ({
|
|
60
|
+
documents: file.documents.map((doc) => ({
|
|
61
|
+
path: doc.path,
|
|
62
|
+
...(doc.description ? { description: doc.description } : {}),
|
|
63
|
+
})),
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
await writeFile(agentsPath(root), YAML.stringify(normalized, { lineWidth: 0 }), 'utf8')
|
|
@@ -71,7 +74,12 @@ export async function addDocuments(
|
|
|
71
74
|
const byPath = new Map(file.documents.map((doc) => [doc.path, doc]))
|
|
72
75
|
|
|
73
76
|
for (const document of documents) {
|
|
74
|
-
byPath.
|
|
77
|
+
const existing = byPath.get(document.path)
|
|
78
|
+
byPath.set(document.path, {
|
|
79
|
+
path: document.path,
|
|
80
|
+
...(existing?.description ? { description: existing.description } : {}),
|
|
81
|
+
...(document.description ? { description: document.description } : {}),
|
|
82
|
+
})
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
const next = {
|
package/src/discover.test.ts
CHANGED
|
@@ -17,21 +17,42 @@ describe('agents.yaml dependency discovery', () => {
|
|
|
17
17
|
const dependencyAgentsPath = path.join(root, 'node_modules', 'direct-lib', 'AGENTS.md')
|
|
18
18
|
await mkdir(path.dirname(dependencyAgentsPath), { recursive: true })
|
|
19
19
|
await writeFile(dependencyAgentsPath, '# Direct dependency guidance\n', 'utf8')
|
|
20
|
+
await writeFile(
|
|
21
|
+
path.join(root, 'node_modules', 'direct-lib', 'package.json'),
|
|
22
|
+
JSON.stringify({
|
|
23
|
+
name: 'direct-lib',
|
|
24
|
+
description: 'Direct fixtures for testing agent guidance.',
|
|
25
|
+
}),
|
|
26
|
+
'utf8',
|
|
27
|
+
)
|
|
20
28
|
|
|
21
29
|
const discovered = await discoverAgentDocuments(root)
|
|
22
|
-
expect(discovered).toEqual([
|
|
23
|
-
|
|
24
|
-
await addDocuments(root, [
|
|
30
|
+
expect(discovered).toEqual([
|
|
25
31
|
{
|
|
26
|
-
path:
|
|
32
|
+
path: './node_modules/direct-lib/AGENTS.md',
|
|
33
|
+
description: 'Direct fixtures for testing agent guidance.',
|
|
27
34
|
},
|
|
28
35
|
])
|
|
29
36
|
|
|
37
|
+
await addDocuments(root, [discovered[0]!])
|
|
38
|
+
|
|
30
39
|
await expect(loadAgentsFile(root)).resolves.toEqual({
|
|
31
40
|
version: 1,
|
|
32
41
|
documents: [
|
|
33
42
|
{
|
|
34
43
|
path: './node_modules/direct-lib/AGENTS.md',
|
|
44
|
+
description: 'Direct fixtures for testing agent guidance.',
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
await addDocuments(root, [{ path: './node_modules/direct-lib/AGENTS.md' }])
|
|
50
|
+
await expect(loadAgentsFile(root)).resolves.toEqual({
|
|
51
|
+
version: 1,
|
|
52
|
+
documents: [
|
|
53
|
+
{
|
|
54
|
+
path: './node_modules/direct-lib/AGENTS.md',
|
|
55
|
+
description: 'Direct fixtures for testing agent guidance.',
|
|
35
56
|
},
|
|
36
57
|
],
|
|
37
58
|
})
|
|
@@ -58,6 +79,28 @@ describe('agents.yaml dependency discovery', () => {
|
|
|
58
79
|
{ path: './node_modules/direct-lib/AGENTS.md' },
|
|
59
80
|
])
|
|
60
81
|
})
|
|
82
|
+
|
|
83
|
+
it('includes scoped package descriptions when present', async () => {
|
|
84
|
+
const root = await createTempProject()
|
|
85
|
+
const dependencyPath = path.join(root, 'node_modules', '@scope', 'direct-lib')
|
|
86
|
+
await mkdir(dependencyPath, { recursive: true })
|
|
87
|
+
await writeFile(path.join(dependencyPath, 'AGENTS.md'), '# Scoped guidance\n', 'utf8')
|
|
88
|
+
await writeFile(
|
|
89
|
+
path.join(dependencyPath, 'package.json'),
|
|
90
|
+
JSON.stringify({
|
|
91
|
+
name: '@scope/direct-lib',
|
|
92
|
+
description: 'Scoped package guidance breadcrumbs.',
|
|
93
|
+
}),
|
|
94
|
+
'utf8',
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
await expect(discoverAgentDocuments(root)).resolves.toEqual([
|
|
98
|
+
{
|
|
99
|
+
path: './node_modules/@scope/direct-lib/AGENTS.md',
|
|
100
|
+
description: 'Scoped package guidance breadcrumbs.',
|
|
101
|
+
},
|
|
102
|
+
])
|
|
103
|
+
})
|
|
61
104
|
})
|
|
62
105
|
|
|
63
106
|
async function createTempProject(): Promise<string> {
|
package/src/discover.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { access, opendir } from 'node:fs/promises'
|
|
1
|
+
import { access, opendir, readFile } from 'node:fs/promises'
|
|
2
2
|
import path from 'node:path'
|
|
3
|
-
import { formatProjectPath } from './paths.ts'
|
|
3
|
+
import { formatProjectPath, resolveFromRoot } from './paths.ts'
|
|
4
4
|
|
|
5
5
|
export type DiscoveredDocument = {
|
|
6
6
|
path: string
|
|
7
|
+
description?: string
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
const skippedDirectories = new Set([
|
|
@@ -25,6 +26,14 @@ export async function discoverAgentDocuments(root: string): Promise<DiscoveredDo
|
|
|
25
26
|
.sort((left, right) => left.path.localeCompare(right.path))
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
export async function describeAgentDocument(
|
|
30
|
+
root: string,
|
|
31
|
+
agentsDocumentPath: string,
|
|
32
|
+
): Promise<DiscoveredDocument> {
|
|
33
|
+
const absolutePath = resolveFromRoot(root, agentsDocumentPath)
|
|
34
|
+
return documentEntry(root, absolutePath, await readPackageDescription(path.dirname(absolutePath)))
|
|
35
|
+
}
|
|
36
|
+
|
|
28
37
|
async function walk(root: string, directory: string, found: DiscoveredDocument[]): Promise<void> {
|
|
29
38
|
let handle
|
|
30
39
|
try {
|
|
@@ -49,7 +58,13 @@ async function walk(root: string, directory: string, found: DiscoveredDocument[]
|
|
|
49
58
|
}
|
|
50
59
|
|
|
51
60
|
if (entry.isFile() && entry.name === 'AGENTS.md') {
|
|
52
|
-
found.push(
|
|
61
|
+
found.push(
|
|
62
|
+
await documentEntry(
|
|
63
|
+
root,
|
|
64
|
+
absolutePath,
|
|
65
|
+
await readPackageDescription(path.dirname(absolutePath)),
|
|
66
|
+
),
|
|
67
|
+
)
|
|
53
68
|
}
|
|
54
69
|
}
|
|
55
70
|
}
|
|
@@ -108,8 +123,36 @@ async function addPackageAgentsDocument(
|
|
|
108
123
|
const agentsPath = path.join(packagePath, 'AGENTS.md')
|
|
109
124
|
try {
|
|
110
125
|
await access(agentsPath)
|
|
111
|
-
found.push(
|
|
126
|
+
found.push(await documentEntry(root, agentsPath, await readPackageDescription(packagePath)))
|
|
112
127
|
} catch {
|
|
113
128
|
// Packages without AGENTS.md are simply not candidates.
|
|
114
129
|
}
|
|
115
130
|
}
|
|
131
|
+
|
|
132
|
+
async function documentEntry(
|
|
133
|
+
root: string,
|
|
134
|
+
agentsPath: string,
|
|
135
|
+
description: string | undefined,
|
|
136
|
+
): Promise<DiscoveredDocument> {
|
|
137
|
+
return {
|
|
138
|
+
path: formatProjectPath(root, agentsPath),
|
|
139
|
+
...(description ? { description } : {}),
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function readPackageDescription(packagePath: string): Promise<string | undefined> {
|
|
144
|
+
try {
|
|
145
|
+
const source = await readFile(path.join(packagePath, 'package.json'), 'utf8')
|
|
146
|
+
const parsed = JSON.parse(source) as unknown
|
|
147
|
+
if (!isPackageJson(parsed) || typeof parsed.description !== 'string') return undefined
|
|
148
|
+
|
|
149
|
+
const description = parsed.description.trim()
|
|
150
|
+
return description && description.length > 0 ? description : undefined
|
|
151
|
+
} catch {
|
|
152
|
+
return undefined
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function isPackageJson(value: unknown): value is Record<string, unknown> {
|
|
157
|
+
return typeof value === 'object' && value !== null
|
|
158
|
+
}
|
package/src/index.ts
CHANGED
|
File without changes
|
package/src/run.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
removeDocuments,
|
|
7
7
|
validateAgentsFile,
|
|
8
8
|
} from './agents-file.ts'
|
|
9
|
-
import { discoverAgentDocuments } from './discover.ts'
|
|
9
|
+
import { describeAgentDocument, discoverAgentDocuments } from './discover.ts'
|
|
10
10
|
import { cwd, formatProjectPath, resolveFromRoot } from './paths.ts'
|
|
11
11
|
|
|
12
12
|
type Command = 'add' | 'discover' | 'help' | 'init' | 'remove' | 'validate' | 'version'
|
|
@@ -27,7 +27,7 @@ Usage:
|
|
|
27
27
|
agents remove <path...>
|
|
28
28
|
agents validate [--json]
|
|
29
29
|
|
|
30
|
-
agents.yaml is a curated table of contents for
|
|
30
|
+
agents.yaml is a curated table of contents for promoted AGENTS.md guidance.`
|
|
31
31
|
|
|
32
32
|
export async function run(argv: string[]): Promise<void> {
|
|
33
33
|
const parsed = parseArgs(argv)
|
|
@@ -127,7 +127,7 @@ async function commandDiscover(root: string, json: boolean): Promise<void> {
|
|
|
127
127
|
return
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
clack.note(documents
|
|
130
|
+
clack.note(formatDocumentList(documents), `Found ${documents.length}`)
|
|
131
131
|
clack.outro('Use agents add <path> to enable one.')
|
|
132
132
|
}
|
|
133
133
|
|
|
@@ -136,16 +136,26 @@ async function commandAdd(root: string, paths: string[]): Promise<void> {
|
|
|
136
136
|
throw new Error('add requires at least one AGENTS.md path')
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
const documents =
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
const documents = await Promise.all(
|
|
140
|
+
paths.map((path) =>
|
|
141
|
+
describeAgentDocument(root, formatProjectPath(root, resolveFromRoot(root, path))),
|
|
142
|
+
),
|
|
143
|
+
)
|
|
142
144
|
|
|
143
145
|
const file = await addDocuments(root, documents)
|
|
144
146
|
clack.intro('agents add')
|
|
145
|
-
clack.note(file.documents
|
|
147
|
+
clack.note(formatDocumentList(file.documents), 'Promoted documents')
|
|
146
148
|
clack.outro(`Added ${documents.length} document${documents.length === 1 ? '' : 's'}.`)
|
|
147
149
|
}
|
|
148
150
|
|
|
151
|
+
function formatDocumentList(
|
|
152
|
+
documents: { path: string; description?: string | undefined }[],
|
|
153
|
+
): string {
|
|
154
|
+
return documents
|
|
155
|
+
.map((doc) => (doc.description ? `${doc.path}\n ${doc.description}` : doc.path))
|
|
156
|
+
.join('\n')
|
|
157
|
+
}
|
|
158
|
+
|
|
149
159
|
async function commandRemove(root: string, paths: string[]): Promise<void> {
|
|
150
160
|
if (paths.length === 0) {
|
|
151
161
|
throw new Error('remove requires at least one path')
|
|
@@ -154,9 +164,9 @@ async function commandRemove(root: string, paths: string[]): Promise<void> {
|
|
|
154
164
|
const normalizedPaths = paths.map((path) => formatProjectPath(root, resolveFromRoot(root, path)))
|
|
155
165
|
const result = await removeDocuments(root, normalizedPaths)
|
|
156
166
|
clack.intro('agents remove')
|
|
157
|
-
clack.note(result.removed.join('\n') || 'No matching documents were
|
|
167
|
+
clack.note(result.removed.join('\n') || 'No matching documents were listed.', 'Removed')
|
|
158
168
|
clack.outro(
|
|
159
|
-
`agents.yaml now has ${result.file.documents.length}
|
|
169
|
+
`agents.yaml now has ${result.file.documents.length} promoted document${result.file.documents.length === 1 ? '' : 's'}.`,
|
|
160
170
|
)
|
|
161
171
|
}
|
|
162
172
|
|
|
@@ -214,7 +224,7 @@ async function interactive(root: string): Promise<void> {
|
|
|
214
224
|
)
|
|
215
225
|
|
|
216
226
|
if (candidates.length === 0) {
|
|
217
|
-
clack.outro('No
|
|
227
|
+
clack.outro('No unlisted supplemental AGENTS.md files found.')
|
|
218
228
|
return
|
|
219
229
|
}
|
|
220
230
|
|