@dzhechkov/adapter-agents-md 0.1.1
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/LICENSE +21 -0
- package/README.md +38 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +79 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
- package/src/index.ts +94 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dzhechko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# @dzhechkov/adapter-agents-md
|
|
2
|
+
|
|
3
|
+
The **AGENTS.md** platform adapter for [DZ Harness Hub](https://github.com/djd1m/dz-harness-hub) — flattens canonical skills into a single, root-level `AGENTS.md`.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
dz init --target agents-md --select design-thinking
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## What it emits
|
|
10
|
+
|
|
11
|
+
`AGENTS.md` is the emerging cross-tool convention read by ~15 agents (Cursor, Zed, Warp, Aider, goose, Gemini CLI, RooCode, Kilo, Junie, Trae, Augment, Devin, pi, Windsurf, …). It is one **root-level, plain-Markdown** file — no YAML frontmatter, no per-skill directory:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
AGENTS.md # a plain-Markdown "## <skill>" section per selected skill, inside a dz-managed fenced block
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Unlike the skill-tree adapters (one directory per skill) and unlike copilot (one instruction file **per** skill), one `AGENTS.md` holds **all** selected skills.
|
|
18
|
+
|
|
19
|
+
## Intentionally lossy — and merge-not-overwrite
|
|
20
|
+
|
|
21
|
+
Like copilot, this is a **lossy** adapter. AGENTS.md loses:
|
|
22
|
+
|
|
23
|
+
- **YAML frontmatter** — the section is plain Markdown;
|
|
24
|
+
- **progressive disclosure** — the whole section is always-on;
|
|
25
|
+
- **per-skill file boundaries** — every skill collapses into one file;
|
|
26
|
+
- **assets** — `scripts/`/`references/` are not carried.
|
|
27
|
+
|
|
28
|
+
Because `AGENTS.md` is often **hand-authored**, aggregation into the real file (at the operations layer) uses `@dzhechkov/core`'s `mergeAgentsMd`, which owns only a fenced block:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
<!-- dz:skills BEGIN (managed by dz — do not edit) -->
|
|
32
|
+
…skill sections…
|
|
33
|
+
<!-- dz:skills END -->
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Everything **outside** the fence is preserved byte-for-byte. The merge is idempotent.
|
|
37
|
+
|
|
38
|
+
Per the `@dzhechkov/core` `Adapter` contract the loss surfaces as a **warning**; under `strict` the adapter **throws**. The canonical skill stays the lossless source of truth — recompiling to `claude` is still full fidelity.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@dzhechkov/adapter-agents-md` — the `AGENTS.md` platform adapter.
|
|
3
|
+
*
|
|
4
|
+
* `AGENTS.md` is the emerging cross-tool convention read by ~15 agents (Cursor,
|
|
5
|
+
* Zed, Warp, Aider, goose, Gemini CLI, RooCode, Kilo, Junie, Trae, Augment,
|
|
6
|
+
* Devin, pi, Windsurf, …): a SINGLE, root-level, PLAIN-Markdown file — NO YAML
|
|
7
|
+
* frontmatter, NO per-skill directory.
|
|
8
|
+
*
|
|
9
|
+
* Like {@link https://github.com/features/copilot | copilot} this is an
|
|
10
|
+
* intentionally **lossy** adapter (frontmatter + progressive disclosure +
|
|
11
|
+
* per-skill file boundaries are flattened away). UNLIKE copilot — which emits
|
|
12
|
+
* one instruction file PER skill — AGENTS.md is ONE file for ALL selected
|
|
13
|
+
* skills. This adapter's `compile` therefore emits just the rendered SECTION for
|
|
14
|
+
* a single skill at path `AGENTS.md`; the aggregation across skills and the
|
|
15
|
+
* merge-not-overwrite into any user-authored AGENTS.md happens at the
|
|
16
|
+
* operations layer via `core`'s {@link mergeAgentsMd}.
|
|
17
|
+
*
|
|
18
|
+
* Per the {@link Adapter} contract, loss surfaces as a warning; under `strict`
|
|
19
|
+
* it throws. The canonical skill stays the lossless source of truth.
|
|
20
|
+
*
|
|
21
|
+
* @packageDocumentation
|
|
22
|
+
*/
|
|
23
|
+
import type { Adapter } from '@dzhechkov/core';
|
|
24
|
+
/** The single, root-level file every AGENTS.md-aware tool reads. */
|
|
25
|
+
export declare const AGENTS_MD_PATH = "AGENTS.md";
|
|
26
|
+
/** Package version. Kept in sync with `package.json`. */
|
|
27
|
+
export declare const ADAPTER_AGENTS_MD_VERSION = "0.1.0";
|
|
28
|
+
/**
|
|
29
|
+
* The `AGENTS.md` adapter — an intentionally **lossy**, **flattening**
|
|
30
|
+
* {@link Adapter}. `compile` renders ONE skill as a plain-Markdown section at
|
|
31
|
+
* `AGENTS.md`; the ops layer aggregates + merges these into the real file.
|
|
32
|
+
*/
|
|
33
|
+
export declare const agentsMdAdapter: Adapter;
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EACV,OAAO,EAMR,MAAM,iBAAiB,CAAC;AAEzB,oEAAoE;AACpE,eAAO,MAAM,cAAc,cAAc,CAAC;AAE1C,yDAAyD;AACzD,eAAO,MAAM,yBAAyB,UAAU,CAAC;AAEjD;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,OAiD7B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@dzhechkov/adapter-agents-md` — the `AGENTS.md` platform adapter.
|
|
3
|
+
*
|
|
4
|
+
* `AGENTS.md` is the emerging cross-tool convention read by ~15 agents (Cursor,
|
|
5
|
+
* Zed, Warp, Aider, goose, Gemini CLI, RooCode, Kilo, Junie, Trae, Augment,
|
|
6
|
+
* Devin, pi, Windsurf, …): a SINGLE, root-level, PLAIN-Markdown file — NO YAML
|
|
7
|
+
* frontmatter, NO per-skill directory.
|
|
8
|
+
*
|
|
9
|
+
* Like {@link https://github.com/features/copilot | copilot} this is an
|
|
10
|
+
* intentionally **lossy** adapter (frontmatter + progressive disclosure +
|
|
11
|
+
* per-skill file boundaries are flattened away). UNLIKE copilot — which emits
|
|
12
|
+
* one instruction file PER skill — AGENTS.md is ONE file for ALL selected
|
|
13
|
+
* skills. This adapter's `compile` therefore emits just the rendered SECTION for
|
|
14
|
+
* a single skill at path `AGENTS.md`; the aggregation across skills and the
|
|
15
|
+
* merge-not-overwrite into any user-authored AGENTS.md happens at the
|
|
16
|
+
* operations layer via `core`'s {@link mergeAgentsMd}.
|
|
17
|
+
*
|
|
18
|
+
* Per the {@link Adapter} contract, loss surfaces as a warning; under `strict`
|
|
19
|
+
* it throws. The canonical skill stays the lossless source of truth.
|
|
20
|
+
*
|
|
21
|
+
* @packageDocumentation
|
|
22
|
+
*/
|
|
23
|
+
import { assertSafeId, renderAgentsMdSection } from '@dzhechkov/core';
|
|
24
|
+
/** The single, root-level file every AGENTS.md-aware tool reads. */
|
|
25
|
+
export const AGENTS_MD_PATH = 'AGENTS.md';
|
|
26
|
+
/** Package version. Kept in sync with `package.json`. */
|
|
27
|
+
export const ADAPTER_AGENTS_MD_VERSION = '0.1.0';
|
|
28
|
+
/**
|
|
29
|
+
* The `AGENTS.md` adapter — an intentionally **lossy**, **flattening**
|
|
30
|
+
* {@link Adapter}. `compile` renders ONE skill as a plain-Markdown section at
|
|
31
|
+
* `AGENTS.md`; the ops layer aggregates + merges these into the real file.
|
|
32
|
+
*/
|
|
33
|
+
export const agentsMdAdapter = {
|
|
34
|
+
platform: 'agents-md',
|
|
35
|
+
compile(skill, ctx) {
|
|
36
|
+
// Defend at the adapter boundary — ids are not guaranteed safe at this layer.
|
|
37
|
+
try {
|
|
38
|
+
assertSafeId(skill.id);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
return Promise.reject(err instanceof Error ? err : new Error(String(err)));
|
|
42
|
+
}
|
|
43
|
+
const files = [
|
|
44
|
+
{
|
|
45
|
+
path: AGENTS_MD_PATH,
|
|
46
|
+
encoding: 'utf-8',
|
|
47
|
+
content: renderAgentsMdSection(skill),
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
const lossy = `agents-md is a lossy target: "${skill.id}" is flattened into a plain-Markdown ` +
|
|
51
|
+
`section of a single root-level AGENTS.md (YAML frontmatter, progressive disclosure, ` +
|
|
52
|
+
`and per-skill file boundaries are dropped; scripts/ and other assets are not carried).`;
|
|
53
|
+
if (ctx.strict === true) {
|
|
54
|
+
return Promise.reject(new Error(`adapter-agents-md: refusing lossy compile under strict mode — ${lossy}`));
|
|
55
|
+
}
|
|
56
|
+
return Promise.resolve({ files, warnings: [lossy] });
|
|
57
|
+
},
|
|
58
|
+
verify(emit) {
|
|
59
|
+
const errors = [];
|
|
60
|
+
// Carry the lossy-compile warning(s) through so `dz verify --target agents-md`
|
|
61
|
+
// never reports skills as clean with no loss notice (mirrors copilot).
|
|
62
|
+
const warnings = [...emit.warnings];
|
|
63
|
+
const file = emit.files.find((f) => f.path === AGENTS_MD_PATH);
|
|
64
|
+
if (!file) {
|
|
65
|
+
errors.push(`no ${AGENTS_MD_PATH} was emitted`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
if (file.content.trim().length === 0) {
|
|
69
|
+
errors.push(`${AGENTS_MD_PATH} is empty`);
|
|
70
|
+
}
|
|
71
|
+
// AGENTS.md is PLAIN Markdown — it must NOT open with a YAML frontmatter fence.
|
|
72
|
+
if (/^?---[ \t]*\r?\n/.test(file.content)) {
|
|
73
|
+
errors.push(`${AGENTS_MD_PATH} must be plain Markdown with no leading "---" frontmatter fence`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return Promise.resolve({ ok: errors.length === 0, errors, warnings });
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAUtE,oEAAoE;AACpE,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC;AAE1C,yDAAyD;AACzD,MAAM,CAAC,MAAM,yBAAyB,GAAG,OAAO,CAAC;AAEjD;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAY;IACtC,QAAQ,EAAE,WAAW;IACrB,OAAO,CAAC,KAAqB,EAAE,GAAmB;QAChD,8EAA8E;QAC9E,IAAI,CAAC;YACH,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACzB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,OAAO,CAAC,MAAM,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC7E,CAAC;QAED,MAAM,KAAK,GAAiB;YAC1B;gBACE,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,OAAO;gBACjB,OAAO,EAAE,qBAAqB,CAAC,KAAK,CAAC;aACtC;SACF,CAAC;QAEF,MAAM,KAAK,GACT,iCAAiC,KAAK,CAAC,EAAE,uCAAuC;YAChF,sFAAsF;YACtF,wFAAwF,CAAC;QAC3F,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YACxB,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,iEAAiE,KAAK,EAAE,CAAC,CAAC,CAAC;QAC7G,CAAC;QACD,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,CAAC,IAAgB;QACrB,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,+EAA+E;QAC/E,uEAAuE;QACvE,MAAM,QAAQ,GAAa,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE9C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC;QAC/D,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,CAAC,IAAI,CAAC,MAAM,cAAc,cAAc,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACrC,MAAM,CAAC,IAAI,CAAC,GAAG,cAAc,WAAW,CAAC,CAAC;YAC5C,CAAC;YACD,gFAAgF;YAChF,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3C,MAAM,CAAC,IAAI,CAAC,GAAG,cAAc,iEAAiE,CAAC,CAAC;YAClG,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACxE,CAAC;CACF,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dzhechkov/adapter-agents-md",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "AGENTS.md platform adapter - flattens canonical skills into a single root-level AGENTS.md (plain Markdown, no frontmatter; intentionally lossy, merge-not-overwrite).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "dzhechko",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"agent-skills",
|
|
10
|
+
"agents-md",
|
|
11
|
+
"agents.md",
|
|
12
|
+
"adapter",
|
|
13
|
+
"harness"
|
|
14
|
+
],
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"src",
|
|
26
|
+
"README.md"
|
|
27
|
+
],
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@dzhechkov/core": "0.2.6"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^25.6.0",
|
|
33
|
+
"typescript": "^5.7.0",
|
|
34
|
+
"vitest": "^3.0.0",
|
|
35
|
+
"yaml": "^2.0.0"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=20"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "https://github.com/djd1m/dz-harness-hub.git",
|
|
46
|
+
"directory": "packages/@dzhechkov/adapter-agents-md"
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://github.com/djd1m/dz-harness-hub/tree/main/packages/@dzhechkov/adapter-agents-md#readme",
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsc -p tsconfig.json",
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"test:watch": "vitest",
|
|
53
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
54
|
+
"lint": "tsc -p tsconfig.json --noEmit"
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@dzhechkov/adapter-agents-md` — the `AGENTS.md` platform adapter.
|
|
3
|
+
*
|
|
4
|
+
* `AGENTS.md` is the emerging cross-tool convention read by ~15 agents (Cursor,
|
|
5
|
+
* Zed, Warp, Aider, goose, Gemini CLI, RooCode, Kilo, Junie, Trae, Augment,
|
|
6
|
+
* Devin, pi, Windsurf, …): a SINGLE, root-level, PLAIN-Markdown file — NO YAML
|
|
7
|
+
* frontmatter, NO per-skill directory.
|
|
8
|
+
*
|
|
9
|
+
* Like {@link https://github.com/features/copilot | copilot} this is an
|
|
10
|
+
* intentionally **lossy** adapter (frontmatter + progressive disclosure +
|
|
11
|
+
* per-skill file boundaries are flattened away). UNLIKE copilot — which emits
|
|
12
|
+
* one instruction file PER skill — AGENTS.md is ONE file for ALL selected
|
|
13
|
+
* skills. This adapter's `compile` therefore emits just the rendered SECTION for
|
|
14
|
+
* a single skill at path `AGENTS.md`; the aggregation across skills and the
|
|
15
|
+
* merge-not-overwrite into any user-authored AGENTS.md happens at the
|
|
16
|
+
* operations layer via `core`'s {@link mergeAgentsMd}.
|
|
17
|
+
*
|
|
18
|
+
* Per the {@link Adapter} contract, loss surfaces as a warning; under `strict`
|
|
19
|
+
* it throws. The canonical skill stays the lossless source of truth.
|
|
20
|
+
*
|
|
21
|
+
* @packageDocumentation
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { assertSafeId, renderAgentsMdSection } from '@dzhechkov/core';
|
|
25
|
+
import type {
|
|
26
|
+
Adapter,
|
|
27
|
+
CanonicalSkill,
|
|
28
|
+
CompileContext,
|
|
29
|
+
EmitResult,
|
|
30
|
+
SkillAsset,
|
|
31
|
+
VerifyResult,
|
|
32
|
+
} from '@dzhechkov/core';
|
|
33
|
+
|
|
34
|
+
/** The single, root-level file every AGENTS.md-aware tool reads. */
|
|
35
|
+
export const AGENTS_MD_PATH = 'AGENTS.md';
|
|
36
|
+
|
|
37
|
+
/** Package version. Kept in sync with `package.json`. */
|
|
38
|
+
export const ADAPTER_AGENTS_MD_VERSION = '0.1.0';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The `AGENTS.md` adapter — an intentionally **lossy**, **flattening**
|
|
42
|
+
* {@link Adapter}. `compile` renders ONE skill as a plain-Markdown section at
|
|
43
|
+
* `AGENTS.md`; the ops layer aggregates + merges these into the real file.
|
|
44
|
+
*/
|
|
45
|
+
export const agentsMdAdapter: Adapter = {
|
|
46
|
+
platform: 'agents-md',
|
|
47
|
+
compile(skill: CanonicalSkill, ctx: CompileContext): Promise<EmitResult> {
|
|
48
|
+
// Defend at the adapter boundary — ids are not guaranteed safe at this layer.
|
|
49
|
+
try {
|
|
50
|
+
assertSafeId(skill.id);
|
|
51
|
+
} catch (err) {
|
|
52
|
+
return Promise.reject(err instanceof Error ? err : new Error(String(err)));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const files: SkillAsset[] = [
|
|
56
|
+
{
|
|
57
|
+
path: AGENTS_MD_PATH,
|
|
58
|
+
encoding: 'utf-8',
|
|
59
|
+
content: renderAgentsMdSection(skill),
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
const lossy =
|
|
64
|
+
`agents-md is a lossy target: "${skill.id}" is flattened into a plain-Markdown ` +
|
|
65
|
+
`section of a single root-level AGENTS.md (YAML frontmatter, progressive disclosure, ` +
|
|
66
|
+
`and per-skill file boundaries are dropped; scripts/ and other assets are not carried).`;
|
|
67
|
+
if (ctx.strict === true) {
|
|
68
|
+
return Promise.reject(new Error(`adapter-agents-md: refusing lossy compile under strict mode — ${lossy}`));
|
|
69
|
+
}
|
|
70
|
+
return Promise.resolve({ files, warnings: [lossy] });
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
verify(emit: EmitResult): Promise<VerifyResult> {
|
|
74
|
+
const errors: string[] = [];
|
|
75
|
+
// Carry the lossy-compile warning(s) through so `dz verify --target agents-md`
|
|
76
|
+
// never reports skills as clean with no loss notice (mirrors copilot).
|
|
77
|
+
const warnings: string[] = [...emit.warnings];
|
|
78
|
+
|
|
79
|
+
const file = emit.files.find((f) => f.path === AGENTS_MD_PATH);
|
|
80
|
+
if (!file) {
|
|
81
|
+
errors.push(`no ${AGENTS_MD_PATH} was emitted`);
|
|
82
|
+
} else {
|
|
83
|
+
if (file.content.trim().length === 0) {
|
|
84
|
+
errors.push(`${AGENTS_MD_PATH} is empty`);
|
|
85
|
+
}
|
|
86
|
+
// AGENTS.md is PLAIN Markdown — it must NOT open with a YAML frontmatter fence.
|
|
87
|
+
if (/^?---[ \t]*\r?\n/.test(file.content)) {
|
|
88
|
+
errors.push(`${AGENTS_MD_PATH} must be plain Markdown with no leading "---" frontmatter fence`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return Promise.resolve({ ok: errors.length === 0, errors, warnings });
|
|
93
|
+
},
|
|
94
|
+
};
|