dna-sdk 0.1.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.
Files changed (240) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/adapters/embedding/onnx.d.ts +32 -0
  4. package/dist/adapters/embedding/onnx.js +51 -0
  5. package/dist/adapters/filesystem/cache.d.ts +16 -0
  6. package/dist/adapters/filesystem/cache.js +113 -0
  7. package/dist/adapters/filesystem/index.d.ts +2 -0
  8. package/dist/adapters/filesystem/index.js +2 -0
  9. package/dist/adapters/filesystem/source.d.ts +82 -0
  10. package/dist/adapters/filesystem/source.js +357 -0
  11. package/dist/adapters/postgres/index.d.ts +2 -0
  12. package/dist/adapters/postgres/index.js +2 -0
  13. package/dist/adapters/postgres/migrations.d.ts +14 -0
  14. package/dist/adapters/postgres/migrations.js +88 -0
  15. package/dist/adapters/postgres/source.d.ts +172 -0
  16. package/dist/adapters/postgres/source.js +569 -0
  17. package/dist/adapters/resolvers/github.d.ts +12 -0
  18. package/dist/adapters/resolvers/github.js +47 -0
  19. package/dist/adapters/resolvers/http.d.ts +22 -0
  20. package/dist/adapters/resolvers/http.js +145 -0
  21. package/dist/adapters/resolvers/index.d.ts +3 -0
  22. package/dist/adapters/resolvers/index.js +3 -0
  23. package/dist/adapters/resolvers/local.d.ts +24 -0
  24. package/dist/adapters/resolvers/local.js +132 -0
  25. package/dist/adapters/search/driver.d.ts +45 -0
  26. package/dist/adapters/search/driver.js +138 -0
  27. package/dist/adapters/search/migrations.d.ts +26 -0
  28. package/dist/adapters/search/migrations.js +58 -0
  29. package/dist/adapters/search/rrf.d.ts +23 -0
  30. package/dist/adapters/search/rrf.js +42 -0
  31. package/dist/adapters/search/sqlite-vec.d.ts +66 -0
  32. package/dist/adapters/search/sqlite-vec.js +294 -0
  33. package/dist/bootstrap.d.ts +45 -0
  34. package/dist/bootstrap.js +134 -0
  35. package/dist/extensions/agentskills/DOCS.md +18 -0
  36. package/dist/extensions/agentskills.d.ts +28 -0
  37. package/dist/extensions/agentskills.js +252 -0
  38. package/dist/extensions/agentsmd/DOCS.md +18 -0
  39. package/dist/extensions/agentsmd.d.ts +22 -0
  40. package/dist/extensions/agentsmd.js +170 -0
  41. package/dist/extensions/audit/kinds/audit-log.kind.yaml +148 -0
  42. package/dist/extensions/audit.d.ts +25 -0
  43. package/dist/extensions/audit.js +62 -0
  44. package/dist/extensions/automation/kinds/automation.kind.yaml +296 -0
  45. package/dist/extensions/automation/query.d.ts +49 -0
  46. package/dist/extensions/automation/query.js +77 -0
  47. package/dist/extensions/automation/write-guards.d.ts +59 -0
  48. package/dist/extensions/automation/write-guards.js +153 -0
  49. package/dist/extensions/automation.d.ts +41 -0
  50. package/dist/extensions/automation.js +54 -0
  51. package/dist/extensions/collab.d.ts +16 -0
  52. package/dist/extensions/collab.js +79 -0
  53. package/dist/extensions/doc/kinds/doc.kind.yaml +118 -0
  54. package/dist/extensions/doc.d.ts +25 -0
  55. package/dist/extensions/doc.js +10 -0
  56. package/dist/extensions/eval/kinds/eval-baseline.kind.yaml +65 -0
  57. package/dist/extensions/eval/kinds/eval-case.kind.yaml +140 -0
  58. package/dist/extensions/eval/kinds/eval-run.kind.yaml +134 -0
  59. package/dist/extensions/eval/kinds/eval-suite.kind.yaml +87 -0
  60. package/dist/extensions/eval.d.ts +24 -0
  61. package/dist/extensions/eval.js +31 -0
  62. package/dist/extensions/evidence/kinds/evidence.kind.yaml +92 -0
  63. package/dist/extensions/evidence.d.ts +17 -0
  64. package/dist/extensions/evidence.js +94 -0
  65. package/dist/extensions/federation.d.ts +22 -0
  66. package/dist/extensions/federation.js +173 -0
  67. package/dist/extensions/guardrails/DOCS.md +20 -0
  68. package/dist/extensions/guardrails.d.ts +31 -0
  69. package/dist/extensions/guardrails.js +228 -0
  70. package/dist/extensions/helix/DOCS-Actor.md +20 -0
  71. package/dist/extensions/helix/DOCS-Agent.md +20 -0
  72. package/dist/extensions/helix/DOCS-UseCase.md +20 -0
  73. package/dist/extensions/helix/layers.d.ts +12 -0
  74. package/dist/extensions/helix/layers.js +18 -0
  75. package/dist/extensions/helix/write-guards.d.ts +70 -0
  76. package/dist/extensions/helix/write-guards.js +172 -0
  77. package/dist/extensions/helix.d.ts +29 -0
  78. package/dist/extensions/helix.js +963 -0
  79. package/dist/extensions/helix_extras.d.ts +124 -0
  80. package/dist/extensions/helix_extras.js +328 -0
  81. package/dist/extensions/hooks.d.ts +31 -0
  82. package/dist/extensions/hooks.js +247 -0
  83. package/dist/extensions/kinddef/DOCS.md +24 -0
  84. package/dist/extensions/kinddef.d.ts +40 -0
  85. package/dist/extensions/kinddef.js +171 -0
  86. package/dist/extensions/lesson.d.ts +6 -0
  87. package/dist/extensions/lesson.js +194 -0
  88. package/dist/extensions/modelreg/kinds/model-profile.kind.yaml +155 -0
  89. package/dist/extensions/modelreg.d.ts +30 -0
  90. package/dist/extensions/modelreg.js +38 -0
  91. package/dist/extensions/recognizer.d.ts +34 -0
  92. package/dist/extensions/recognizer.js +272 -0
  93. package/dist/extensions/research.d.ts +32 -0
  94. package/dist/extensions/research.js +292 -0
  95. package/dist/extensions/safety.d.ts +33 -0
  96. package/dist/extensions/safety.js +230 -0
  97. package/dist/extensions/sdlc/kinds/adr.kind.yaml +136 -0
  98. package/dist/extensions/sdlc/kinds/archive-proposal.kind.yaml +107 -0
  99. package/dist/extensions/sdlc/kinds/changelog.kind.yaml +108 -0
  100. package/dist/extensions/sdlc/kinds/cognitive-policy.kind.yaml +470 -0
  101. package/dist/extensions/sdlc/kinds/forecast.kind.yaml +125 -0
  102. package/dist/extensions/sdlc/kinds/insight.kind.yaml +87 -0
  103. package/dist/extensions/sdlc/kinds/kaizen.kind.yaml +106 -0
  104. package/dist/extensions/sdlc/kinds/lesson-learned.kind.yaml +270 -0
  105. package/dist/extensions/sdlc/kinds/narrative.kind.yaml +189 -0
  106. package/dist/extensions/sdlc/kinds/pattern-insight.kind.yaml +204 -0
  107. package/dist/extensions/sdlc/kinds/postmortem.kind.yaml +168 -0
  108. package/dist/extensions/sdlc/kinds/pre-mortem.kind.yaml +145 -0
  109. package/dist/extensions/sdlc/kinds/prompt-template.kind.yaml +109 -0
  110. package/dist/extensions/sdlc/kinds/retrospective.kind.yaml +186 -0
  111. package/dist/extensions/sdlc/kinds/risk-register.kind.yaml +178 -0
  112. package/dist/extensions/sdlc/kinds/saved-view.kind.yaml +127 -0
  113. package/dist/extensions/sdlc/kinds/status-report.kind.yaml +129 -0
  114. package/dist/extensions/sdlc/kinds/synthesis-run.kind.yaml +279 -0
  115. package/dist/extensions/sdlc/kinds/synthesizer-state.kind.yaml +196 -0
  116. package/dist/extensions/sdlc/kinds/workflow-event.kind.yaml +195 -0
  117. package/dist/extensions/sdlc.d.ts +32 -0
  118. package/dist/extensions/sdlc.js +1318 -0
  119. package/dist/extensions/soulspec/DOCS.md +19 -0
  120. package/dist/extensions/soulspec.d.ts +22 -0
  121. package/dist/extensions/soulspec.js +287 -0
  122. package/dist/extensions/tenant.d.ts +6 -0
  123. package/dist/extensions/tenant.js +291 -0
  124. package/dist/extensions/testkit.d.ts +24 -0
  125. package/dist/extensions/testkit.js +211 -0
  126. package/dist/index.d.ts +80 -0
  127. package/dist/index.js +102 -0
  128. package/dist/kernel/_text.d.ts +28 -0
  129. package/dist/kernel/_text.js +42 -0
  130. package/dist/kernel/bundle-handle.d.ts +83 -0
  131. package/dist/kernel/bundle-handle.js +184 -0
  132. package/dist/kernel/capabilities.d.ts +157 -0
  133. package/dist/kernel/capabilities.js +109 -0
  134. package/dist/kernel/collaborator-ports.d.ts +91 -0
  135. package/dist/kernel/collaborator-ports.js +1 -0
  136. package/dist/kernel/composition-resolver.d.ts +215 -0
  137. package/dist/kernel/composition-resolver.js +558 -0
  138. package/dist/kernel/composition.d.ts +10 -0
  139. package/dist/kernel/composition.js +1 -0
  140. package/dist/kernel/descriptor-loader.d.ts +13 -0
  141. package/dist/kernel/descriptor-loader.js +48 -0
  142. package/dist/kernel/document.d.ts +43 -0
  143. package/dist/kernel/document.js +71 -0
  144. package/dist/kernel/embedding.d.ts +28 -0
  145. package/dist/kernel/embedding.js +78 -0
  146. package/dist/kernel/errors.d.ts +62 -0
  147. package/dist/kernel/errors.js +82 -0
  148. package/dist/kernel/events.d.ts +6 -0
  149. package/dist/kernel/events.js +21 -0
  150. package/dist/kernel/evidence-capture.d.ts +69 -0
  151. package/dist/kernel/evidence-capture.js +138 -0
  152. package/dist/kernel/fs.d.ts +20 -0
  153. package/dist/kernel/fs.js +128 -0
  154. package/dist/kernel/generic-rw.d.ts +33 -0
  155. package/dist/kernel/generic-rw.js +235 -0
  156. package/dist/kernel/hooks.d.ts +172 -0
  157. package/dist/kernel/hooks.js +256 -0
  158. package/dist/kernel/index.d.ts +624 -0
  159. package/dist/kernel/index.js +1638 -0
  160. package/dist/kernel/instance.d.ts +211 -0
  161. package/dist/kernel/instance.js +487 -0
  162. package/dist/kernel/kind-registry.d.ts +183 -0
  163. package/dist/kernel/kind-registry.js +710 -0
  164. package/dist/kernel/kind_base.d.ts +106 -0
  165. package/dist/kernel/kind_base.js +244 -0
  166. package/dist/kernel/layer-resolver.d.ts +48 -0
  167. package/dist/kernel/layer-resolver.js +284 -0
  168. package/dist/kernel/lock-manager.d.ts +21 -0
  169. package/dist/kernel/lock-manager.js +43 -0
  170. package/dist/kernel/lock.d.ts +38 -0
  171. package/dist/kernel/lock.js +115 -0
  172. package/dist/kernel/meta.d.ts +135 -0
  173. package/dist/kernel/meta.js +817 -0
  174. package/dist/kernel/models.d.ts +3089 -0
  175. package/dist/kernel/models.js +764 -0
  176. package/dist/kernel/navigator.d.ts +36 -0
  177. package/dist/kernel/navigator.js +132 -0
  178. package/dist/kernel/port-surface.d.ts +33 -0
  179. package/dist/kernel/port-surface.js +180 -0
  180. package/dist/kernel/preview.d.ts +60 -0
  181. package/dist/kernel/preview.js +54 -0
  182. package/dist/kernel/prompt-budget.d.ts +39 -0
  183. package/dist/kernel/prompt-budget.js +43 -0
  184. package/dist/kernel/prompt-builder.d.ts +25 -0
  185. package/dist/kernel/prompt-builder.js +237 -0
  186. package/dist/kernel/protocols.d.ts +751 -0
  187. package/dist/kernel/protocols.js +493 -0
  188. package/dist/kernel/reports.d.ts +26 -0
  189. package/dist/kernel/reports.js +215 -0
  190. package/dist/kernel/resolver.d.ts +146 -0
  191. package/dist/kernel/resolver.js +232 -0
  192. package/dist/kernel/resource.d.ts +57 -0
  193. package/dist/kernel/resource.js +97 -0
  194. package/dist/kernel/runtime.d.ts +16 -0
  195. package/dist/kernel/runtime.js +18 -0
  196. package/dist/kernel/safety-scanner.d.ts +38 -0
  197. package/dist/kernel/safety-scanner.js +228 -0
  198. package/dist/kernel/serialize-to-files.d.ts +29 -0
  199. package/dist/kernel/serialize-to-files.js +23 -0
  200. package/dist/kernel/spec-access.d.ts +23 -0
  201. package/dist/kernel/spec-access.js +40 -0
  202. package/dist/kernel/studio_ui.d.ts +88 -0
  203. package/dist/kernel/studio_ui.js +135 -0
  204. package/dist/kernel/templates.d.ts +77 -0
  205. package/dist/kernel/templates.js +116 -0
  206. package/dist/kernel/tool-registry.d.ts +52 -0
  207. package/dist/kernel/tool-registry.js +89 -0
  208. package/dist/kernel/write-pipeline.d.ts +65 -0
  209. package/dist/kernel/write-pipeline.js +271 -0
  210. package/dist/kernel/writer-helpers.d.ts +24 -0
  211. package/dist/kernel/writer-helpers.js +42 -0
  212. package/dist/memory/decay.d.ts +31 -0
  213. package/dist/memory/decay.js +97 -0
  214. package/dist/memory/ecphory.d.ts +25 -0
  215. package/dist/memory/ecphory.js +178 -0
  216. package/dist/memory/encodingContext.d.ts +21 -0
  217. package/dist/memory/encodingContext.js +62 -0
  218. package/dist/memory/index.d.ts +23 -0
  219. package/dist/memory/index.js +23 -0
  220. package/dist/memory/memoryType.d.ts +7 -0
  221. package/dist/memory/memoryType.js +24 -0
  222. package/dist/memory/policy.d.ts +35 -0
  223. package/dist/memory/policy.js +35 -0
  224. package/dist/memory/retrieval.d.ts +21 -0
  225. package/dist/memory/retrieval.js +145 -0
  226. package/dist/testing/index.d.ts +8 -0
  227. package/dist/testing/index.js +8 -0
  228. package/dist/testing/recordSearchConformance.d.ts +43 -0
  229. package/dist/testing/recordSearchConformance.js +147 -0
  230. package/dist/viz/ascii.d.ts +7 -0
  231. package/dist/viz/ascii.js +60 -0
  232. package/dist/viz/health.d.ts +8 -0
  233. package/dist/viz/health.js +161 -0
  234. package/dist/viz/index.d.ts +10 -0
  235. package/dist/viz/index.js +10 -0
  236. package/dist/viz/matrix.d.ts +8 -0
  237. package/dist/viz/matrix.js +84 -0
  238. package/dist/viz/mermaid.d.ts +38 -0
  239. package/dist/viz/mermaid.js +706 -0
  240. package/package.json +82 -0
@@ -0,0 +1,252 @@
1
+ /**
2
+ * AgentSkillsExtension — Skill kind + SkillReader.
3
+ *
4
+ * 1:1 parity with Python dna.v3.extensions.agentskills.
5
+ */
6
+ import yaml from "js-yaml";
7
+ import { deriveFirstLine } from "../kernel/_text.js";
8
+ import { SkillSchema, SkillSpecSchema, zodSpecToJsonSchema } from "../kernel/models.js";
9
+ import { KindBase } from "../kernel/kind_base.js";
10
+ import { SD } from "../kernel/protocols.js";
11
+ import { nodeFS, readTextSafe, collectDir } from "../kernel/fs.js";
12
+ // ---------------------------------------------------------------------------
13
+ // SkillKind
14
+ // ---------------------------------------------------------------------------
15
+ class SkillKind extends KindBase {
16
+ apiVersion = "agentskills.io/v1";
17
+ kind = "Skill";
18
+ alias = "agentskills-skill";
19
+ isSchemaAffecting = true;
20
+ origin = "agentskills.io";
21
+ isPromptTarget = false;
22
+ promptTargetPriority = 0;
23
+ flattenInContext = false;
24
+ descriptionFallbackField = "instruction";
25
+ storage = SD.bundle("skills", "SKILL.md");
26
+ graphStyle = { fill: "#10B981", stroke: "#059669", textColor: "#fff" };
27
+ asciiIcon = "📖";
28
+ displayLabel = "Skills";
29
+ _sourceUrl = import.meta.url;
30
+ docs = "A Skill is a modular, progressively-disclosed unit of know-how stored " +
31
+ "as a bundle rooted on SKILL.md with optional scripts/, references/, " +
32
+ "assets/. Skills are NOT flattened into prompts; the harness exposes a " +
33
+ "catalogue and agents read full SKILL.md on demand.";
34
+ uiSchema = {
35
+ instruction: {
36
+ widget: "markdown-toc",
37
+ label: "SKILL.md",
38
+ help: "The skill's instruction body (progressive disclosure, ≤500 lines).",
39
+ height: 520,
40
+ order: 10,
41
+ },
42
+ scripts: { widget: "readonly", label: "scripts/", help: "Bundled scripts directory. Edit on disk.", order: 20 },
43
+ references: { widget: "readonly", label: "references/", help: "Bundled reference files. Edit on disk.", order: 30 },
44
+ assets: { widget: "readonly", label: "assets/", help: "Binary/static assets. Edit on disk.", order: 40 },
45
+ };
46
+ schema() { return zodSpecToJsonSchema(SkillSpecSchema); }
47
+ parse(raw) {
48
+ return SkillSchema.parse(raw);
49
+ }
50
+ summary() { return null; }
51
+ preview(doc) {
52
+ const spec = (doc.spec ?? {});
53
+ const instruction = typeof spec.instruction === "string" ? spec.instruction : "";
54
+ if (!instruction) {
55
+ return [{ kind: "empty", title: "Skill (empty)" }];
56
+ }
57
+ return [
58
+ {
59
+ kind: "markdown",
60
+ title: "SKILL.md",
61
+ body: instruction,
62
+ },
63
+ ];
64
+ }
65
+ }
66
+ // ---------------------------------------------------------------------------
67
+ // SkillReader
68
+ // ---------------------------------------------------------------------------
69
+ const KNOWN_DIRS = new Set(["scripts", "references", "assets"]);
70
+ export class SkillReader {
71
+ fs;
72
+ constructor(fs) {
73
+ this.fs = fs;
74
+ }
75
+ detect(bundle) {
76
+ const path = bundle.path ?? "";
77
+ return this.fs.exists(`${path}/SKILL.md`);
78
+ }
79
+ read(bundle) {
80
+ const path = bundle.path ?? "";
81
+ const skillMd = this.fs.readFile(`${path}/SKILL.md`);
82
+ const metadata = parseFrontmatter(skillMd);
83
+ const name = (typeof metadata.name === "string" && metadata.name) ||
84
+ path.split("/").pop() ||
85
+ "";
86
+ const description = typeof metadata.description === "string" ? metadata.description : "";
87
+ // Extract body (after frontmatter) — F3 market fidelity: keep the
88
+ // tail byte-exact except the ONE leading newline the writer
89
+ // canonically re-emits ("---\\n\\n"). Trailing newlines and extra
90
+ // blank lines are part of the artifact.
91
+ const fmMatch = skillMd.match(/^---\n[\s\S]*?---(?:\n|$)/);
92
+ const tail = fmMatch ? skillMd.slice(fmMatch[0].length) : skillMd;
93
+ const body = tail.startsWith("\n") ? tail.slice(1) : tail;
94
+ const spec = { instruction: body };
95
+ // Collect known subdirectories (scripts/, references/, assets/)
96
+ for (const dirName of KNOWN_DIRS) {
97
+ const sub = `${path}/${dirName}`;
98
+ if (this.fs.isDirectory(sub)) {
99
+ const files = collectDir(this.fs, sub, sub);
100
+ if (Object.keys(files).length > 0) {
101
+ spec[dirName] = files;
102
+ }
103
+ }
104
+ }
105
+ // Single readDir call, reused for extras + root files
106
+ const entries = this.fs.readDir(path);
107
+ // Collect ALL other subdirectories as extra bundles
108
+ const extras = {};
109
+ for (const entry of entries) {
110
+ const full = `${path}/${entry}`;
111
+ if (!this.fs.isDirectory(full) || KNOWN_DIRS.has(entry))
112
+ continue;
113
+ const files = collectDir(this.fs, full, full);
114
+ if (Object.keys(files).length > 0) {
115
+ extras[entry] = files;
116
+ }
117
+ }
118
+ if (Object.keys(extras).length > 0) {
119
+ spec.extras = extras;
120
+ }
121
+ // Collect root-level extra files (not SKILL.md)
122
+ const rootFiles = {};
123
+ for (const entry of entries) {
124
+ const full = `${path}/${entry}`;
125
+ if (!this.fs.isFile(full) || entry === "SKILL.md")
126
+ continue;
127
+ const text = readTextSafe(this.fs, full);
128
+ if (text !== null) {
129
+ rootFiles[entry] = text;
130
+ }
131
+ }
132
+ if (Object.keys(rootFiles).length > 0) {
133
+ spec.root_files = rootFiles;
134
+ }
135
+ // Preserve all frontmatter keys (tags, owner, priority, …). SkillWriter
136
+ // already round-trips extras; spreading metadata first then overriding
137
+ // name/description defaults closes the asymmetry on the reader side.
138
+ return {
139
+ apiVersion: "agentskills.io/v1",
140
+ kind: "Skill",
141
+ metadata: { ...metadata, name, description },
142
+ spec,
143
+ };
144
+ }
145
+ }
146
+ function parseFrontmatter(text) {
147
+ const match = text.match(/^---\n([\s\S]*?)---\n?/);
148
+ if (!match)
149
+ return {};
150
+ try {
151
+ const parsed = yaml.load(match[1]);
152
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
153
+ return parsed;
154
+ }
155
+ }
156
+ catch { }
157
+ return {};
158
+ }
159
+ // ---------------------------------------------------------------------------
160
+ // SkillWriter
161
+ // ---------------------------------------------------------------------------
162
+ export class SkillWriter {
163
+ fs;
164
+ constructor(fs) {
165
+ this.fs = fs;
166
+ }
167
+ canWrite(raw) {
168
+ return raw.kind === "Skill";
169
+ }
170
+ write(bundle, raw) {
171
+ const path = bundle.path ?? "";
172
+ this.fs.mkdir(path);
173
+ for (const f of this.serialize(raw)) {
174
+ this.fs.writeFile(`${path}/${f.relativePath}`, f.content ?? "");
175
+ }
176
+ }
177
+ serialize(raw) {
178
+ const files = [];
179
+ const meta = (raw.metadata ?? {});
180
+ const spec = (raw.spec ?? {});
181
+ // SKILL.md with frontmatter + instruction body
182
+ const fm = {};
183
+ if (meta.name)
184
+ fm.name = meta.name;
185
+ if (meta.description)
186
+ fm.description = meta.description;
187
+ // Preserve extra metadata (e.g. tenant for RLS) — frontmatter is the
188
+ // authoritative metadata block for bundle kinds.
189
+ for (const [key, value] of Object.entries(meta)) {
190
+ if (key === "name" || key === "description")
191
+ continue;
192
+ if (value == null)
193
+ continue;
194
+ fm[key] = value;
195
+ }
196
+ // F3 market fidelity: metadata.description may have been ENRICHED at
197
+ // parse time (deriveFirstLine of the body). Persisting it would emit
198
+ // frontmatter the source bundle never had — elide when derivable.
199
+ if (typeof fm.description === "string" && fm.description === deriveFirstLine(spec.instruction ?? "")) {
200
+ delete fm.description;
201
+ }
202
+ // lineWidth: real marketplace skills author description as ONE long
203
+ // line — the default width 80 would wrap it (not byte-faithful).
204
+ const frontmatter = yaml.dump(fm, { flowLevel: -1, sortKeys: false, lineWidth: -1 });
205
+ const instruction = spec.instruction ?? "";
206
+ files.push({ relativePath: "SKILL.md", content: `---\n${frontmatter}---\n\n${instruction}` });
207
+ // Sub-directories: scripts, references, assets
208
+ for (const dirName of ["scripts", "references", "assets"]) {
209
+ const dirFiles = spec[dirName];
210
+ if (dirFiles != null && typeof dirFiles === "object") {
211
+ for (const [fname, fcontent] of Object.entries(dirFiles)) {
212
+ files.push({ relativePath: `${dirName}/${fname}`, content: fcontent });
213
+ }
214
+ }
215
+ }
216
+ // Extras
217
+ const extras = spec.extras;
218
+ if (extras != null && typeof extras === "object") {
219
+ for (const [dirName, dirFiles] of Object.entries(extras)) {
220
+ if (typeof dirFiles === "object") {
221
+ for (const [fname, fcontent] of Object.entries(dirFiles)) {
222
+ files.push({ relativePath: `${dirName}/${fname}`, content: fcontent });
223
+ }
224
+ }
225
+ }
226
+ }
227
+ // Root files
228
+ const rootFiles = spec.root_files;
229
+ if (rootFiles != null && typeof rootFiles === "object") {
230
+ for (const [fname, fcontent] of Object.entries(rootFiles)) {
231
+ files.push({ relativePath: fname, content: fcontent });
232
+ }
233
+ }
234
+ return files;
235
+ }
236
+ }
237
+ // ---------------------------------------------------------------------------
238
+ // Extension
239
+ // ---------------------------------------------------------------------------
240
+ export class AgentSkillsExtension {
241
+ fs;
242
+ name = "agentskills";
243
+ version = "1.0.0";
244
+ constructor(fs = nodeFS) {
245
+ this.fs = fs;
246
+ }
247
+ register(kernel) {
248
+ kernel.kind(new SkillKind());
249
+ kernel.reader(new SkillReader(this.fs));
250
+ kernel.writer(new SkillWriter(this.fs));
251
+ }
252
+ }
@@ -0,0 +1,18 @@
1
+ # AgentDefinition (AGENTS.md)
2
+
3
+ AgentDefinition wraps a standalone `AGENTS.md` file as a first-class document
4
+ kind. `AGENTS.md` is an emerging community convention
5
+ (https://agents.md) for giving coding agents repo-level instructions —
6
+ similar in spirit to `README.md` but targeted at autonomous agents rather than
7
+ human readers.
8
+
9
+ The AgentsMdExtension scans for a top-level `AGENTS.md` in the manifest scope
10
+ and exposes its content as a document. It is NOT a prompt target on its own;
11
+ it is context material that agents and tooling can surface when operating in
12
+ that repository.
13
+
14
+ **When to use:** drop an `AGENTS.md` alongside your module manifest to record
15
+ repo-wide conventions, coding style, test commands, or operational notes that
16
+ any agent working in the scope should respect. Unlike Souls (which describe
17
+ voice) and Skills (which describe procedures), AgentContext describes the
18
+ environment the agent is working in.
@@ -0,0 +1,22 @@
1
+ /**
2
+ * AgentsMdExtension — AgentDefinition kind + AgentDefinitionReader + Writer.
3
+ *
4
+ * 1:1 parity with Python dna.v3.extensions.agentsmd.
5
+ */
6
+ import type { BundleHandle } from "../kernel/bundle-handle.js";
7
+ import type { FSLike } from "../kernel/fs.js";
8
+ import type { ExtensionHost, Extension, SerializedFile, WriterPort } from "../kernel/protocols.js";
9
+ export declare class AgentDefinitionWriter implements WriterPort {
10
+ private fs;
11
+ constructor(fs?: FSLike);
12
+ canWrite(raw: Record<string, unknown>): boolean;
13
+ write(bundle: BundleHandle, raw: Record<string, unknown>): void;
14
+ serialize(raw: Record<string, unknown>): SerializedFile[];
15
+ }
16
+ export declare class AgentsMdExtension implements Extension {
17
+ private fs;
18
+ readonly name = "agentsmd";
19
+ readonly version = "1.0.0";
20
+ constructor(fs?: FSLike);
21
+ register(kernel: ExtensionHost): void;
22
+ }
@@ -0,0 +1,170 @@
1
+ /**
2
+ * AgentsMdExtension — AgentDefinition kind + AgentDefinitionReader + Writer.
3
+ *
4
+ * 1:1 parity with Python dna.v3.extensions.agentsmd.
5
+ */
6
+ import yaml from "js-yaml";
7
+ import { deriveFirstLine } from "../kernel/_text.js";
8
+ import { nodeFS } from "../kernel/fs.js";
9
+ import { KindBase } from "../kernel/kind_base.js";
10
+ import { AgentDefinitionSchema, AgentDefinitionSpecSchema, zodSpecToJsonSchema } from "../kernel/models.js";
11
+ import { SD } from "../kernel/protocols.js";
12
+ // ---------------------------------------------------------------------------
13
+ // Frontmatter helpers
14
+ // ---------------------------------------------------------------------------
15
+ function parseAgentsFrontmatter(text) {
16
+ const match = text.match(/^---\n([\s\S]*?)---\n?([\s\S]*)$/);
17
+ if (!match)
18
+ return { metadata: {}, body: text };
19
+ try {
20
+ const parsed = yaml.load(match[1]);
21
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
22
+ return {
23
+ metadata: parsed,
24
+ body: match[2].replace(/^\n+/, ""),
25
+ };
26
+ }
27
+ }
28
+ catch { }
29
+ return { metadata: {}, body: text };
30
+ }
31
+ // ---------------------------------------------------------------------------
32
+ // AgentDefinitionKind
33
+ // ---------------------------------------------------------------------------
34
+ class AgentDefinitionKind extends KindBase {
35
+ apiVersion = "agents.md/v1";
36
+ kind = "AgentDefinition";
37
+ alias = "agentsmd-agent";
38
+ origin = "agents.md";
39
+ isPromptTarget = true;
40
+ promptTargetPriority = 1;
41
+ flattenInContext = true;
42
+ descriptionFallbackField = "content";
43
+ storage = SD.standalone("AGENTS.md");
44
+ graphStyle = { fill: "#6366F1", stroke: "#4F46E5", textColor: "#fff" };
45
+ asciiIcon = "📝";
46
+ displayLabel = "AGENTS.md";
47
+ _sourceUrl = import.meta.url;
48
+ docs = "AgentDefinition wraps a standalone AGENTS.md file — the emerging " +
49
+ "community convention (https://agents.md) for repo-level coding-agent " +
50
+ "instructions. Flattened into context for agents working in the scope.";
51
+ schema() { return zodSpecToJsonSchema(AgentDefinitionSpecSchema); }
52
+ parse(raw) {
53
+ return AgentDefinitionSchema.parse(raw);
54
+ }
55
+ summary() { return null; }
56
+ promptTemplate() {
57
+ return "{{{content}}}";
58
+ }
59
+ preview(doc) {
60
+ const spec = (doc.spec ?? {});
61
+ const content = typeof spec.content === "string" ? spec.content : "";
62
+ if (!content) {
63
+ return [{ kind: "empty", title: "AGENTS.md (empty)" }];
64
+ }
65
+ return [{ kind: "markdown", title: "AGENTS.md", body: content }];
66
+ }
67
+ }
68
+ // ---------------------------------------------------------------------------
69
+ // AgentDefinitionReader
70
+ // ---------------------------------------------------------------------------
71
+ class AgentDefinitionReader {
72
+ fs;
73
+ constructor(fs) {
74
+ this.fs = fs;
75
+ }
76
+ detect(bundle) {
77
+ const path = bundle.path ?? "";
78
+ if (!this.fs.exists(`${path}/AGENTS.md`))
79
+ return false;
80
+ // Skip if inside a soul bundle
81
+ if (this.fs.exists(`${path}/SOUL.md`) || this.fs.exists(`${path}/soul.json`)) {
82
+ return false;
83
+ }
84
+ return true;
85
+ }
86
+ read(bundle) {
87
+ const path = bundle.path ?? "";
88
+ const text = this.fs.readFile(`${path}/AGENTS.md`);
89
+ const name = path.split("/").pop() || "";
90
+ const { metadata: fm, body } = parseAgentsFrontmatter(text);
91
+ const metadata = { ...fm };
92
+ if (metadata.name == null)
93
+ metadata.name = name;
94
+ // When no frontmatter was present, preserve the full original text
95
+ // (byte-compat). When frontmatter IS present, spec.content is the body
96
+ // after it.
97
+ const hasFm = Object.keys(fm).length > 0;
98
+ const content = hasFm ? body : text;
99
+ return {
100
+ apiVersion: "agents.md/v1",
101
+ kind: "AgentDefinition",
102
+ metadata,
103
+ spec: { content },
104
+ };
105
+ }
106
+ }
107
+ // ---------------------------------------------------------------------------
108
+ // AgentDefinitionWriter
109
+ // ---------------------------------------------------------------------------
110
+ export class AgentDefinitionWriter {
111
+ fs;
112
+ constructor(fs = nodeFS) {
113
+ this.fs = fs;
114
+ }
115
+ canWrite(raw) {
116
+ return raw.kind === "AgentDefinition";
117
+ }
118
+ write(bundle, raw) {
119
+ const path = bundle.path ?? "";
120
+ this.fs.mkdir(path);
121
+ for (const f of this.serialize(raw)) {
122
+ this.fs.writeFile(`${path}/${f.relativePath}`, f.content ?? "");
123
+ }
124
+ }
125
+ serialize(raw) {
126
+ const spec = (raw.spec ?? {});
127
+ const meta = (raw.metadata ?? {});
128
+ const body = (spec.content ?? "") || "";
129
+ // Drop null/undefined before deciding whether to emit frontmatter.
130
+ const fm = {};
131
+ for (const [k, v] of Object.entries(meta)) {
132
+ if (v == null)
133
+ continue;
134
+ fm[k] = v;
135
+ }
136
+ // F3 market fidelity: metadata.description may have been ENRICHED at
137
+ // parse time (deriveFirstLine of the body). Persisting it would emit
138
+ // frontmatter the source bundle never had — elide when derivable.
139
+ if (typeof fm.description === "string" && fm.description === deriveFirstLine(body)) {
140
+ delete fm.description;
141
+ }
142
+ const bodyHasFm = body.trimStart().startsWith("---");
143
+ const fmKeys = Object.keys(fm);
144
+ // Byte-compat for the simple "only name" case — previous writer emitted
145
+ // just the body. Keeps existing fixture AGENTS.md files from diffing.
146
+ const onlyName = fmKeys.length === 0 || (fmKeys.length === 1 && fmKeys[0] === "name");
147
+ const needsFm = fmKeys.length > 0 && !bodyHasFm && !onlyName;
148
+ if (needsFm) {
149
+ const fmBody = yaml.dump(fm, { flowLevel: -1, sortKeys: false, lineWidth: -1 }).replace(/\n+$/, "");
150
+ return [{ relativePath: "AGENTS.md", content: `---\n${fmBody}\n---\n${body}` }];
151
+ }
152
+ return [{ relativePath: "AGENTS.md", content: body }];
153
+ }
154
+ }
155
+ // ---------------------------------------------------------------------------
156
+ // Extension
157
+ // ---------------------------------------------------------------------------
158
+ export class AgentsMdExtension {
159
+ fs;
160
+ name = "agentsmd";
161
+ version = "1.0.0";
162
+ constructor(fs = nodeFS) {
163
+ this.fs = fs;
164
+ }
165
+ register(kernel) {
166
+ kernel.kind(new AgentDefinitionKind());
167
+ kernel.reader(new AgentDefinitionReader(this.fs));
168
+ kernel.writer(new AgentDefinitionWriter(this.fs));
169
+ }
170
+ }
@@ -0,0 +1,148 @@
1
+ # AuditLog — immutable record of a role-gated HTTP endpoint invocation
2
+ # (record plane, runtime artifact; written by emit_audit() from gated handlers).
3
+ #
4
+ # expr batch A (plan 2026-06-11-descriptor-expressiveness, Chunk 3): the
5
+ # twin AuditLogKind classes (Py+TS) were DELETED — this descriptor is the
6
+ # single source. First builtin Kind to carry the new D2 `ui:` descriptor
7
+ # field (StudioUIMetadata reconstructed by DeclarativeKindPort and served
8
+ # by kinds-api's /kinds/manifest verbatim — the class's `ui` block).
9
+ # PARITY-CRITICAL package data: the byte-identical mirror lives at
10
+ # packages/sdk-{py,ts}/{dna/extensions,src/extensions}/audit/kinds/
11
+ # audit-log.kind.yaml (tests/test_descriptor_hash_parity.py enforces).
12
+ # Equivalence with the extinct class frozen in
13
+ # tests/test_expr_batch_a_equivalence.py.
14
+ #
15
+ # tenant_scope: tenanted is DECLARED — the class set scope=TenantScope.TENANTED
16
+ # explicitly (each tenant sees only their own audit trail; platform admins
17
+ # query cross-tenant). This is NOT the permissive-undeclared case.
18
+ apiVersion: github.com/ruinosus/dna/core/v1
19
+ kind: KindDefinition
20
+ metadata:
21
+ name: audit-log
22
+ spec:
23
+ target_api_version: github.com/ruinosus/dna/audit/v1
24
+ target_kind: AuditLog
25
+ alias: audit-auditlog
26
+ origin: github.com/ruinosus/dna/audit
27
+ tenant_scope: tenanted
28
+ plane: record
29
+ prompt_target: false
30
+ flatten_in_context: false
31
+ prompt_target_priority: 0
32
+ is_runtime_artifact: true
33
+ storage:
34
+ type: yaml
35
+ container: audit-log
36
+ schema:
37
+ type: object
38
+ required:
39
+ - actor
40
+ - roles
41
+ - operation
42
+ - outcome
43
+ - captured_at
44
+ additionalProperties: true
45
+ properties:
46
+ actor:
47
+ type: string
48
+ description: Identity that made the request. From claims.email > claims.sub.
49
+ 'dev-user' in dev-bypass, 'test-user' in test-header mode.
50
+ roles:
51
+ type: array
52
+ items:
53
+ type: string
54
+ description: Roles claimed at request time (from JWT or DNA_DEV_ROLES). Snapshot
55
+ — does NOT reflect later role revocations.
56
+ operation:
57
+ type: string
58
+ description: HTTP method + path template, e.g. 'PUT /scopes/{scope}/docs/Agent/{name}'
59
+ or 'POST /assessments/{name}/run'.
60
+ target_kind:
61
+ type: string
62
+ description: Kind of doc affected (when applicable). Null for non-doc ops like
63
+ POST /sync/replicate.
64
+ target_name:
65
+ type: string
66
+ description: Name of doc affected, when applicable.
67
+ target_scope:
68
+ type: string
69
+ description: Scope of doc affected, when applicable.
70
+ target_tenant:
71
+ type:
72
+ - string
73
+ - 'null'
74
+ description: Tenant the operation routed to (claims.tenant + overrides resolved).
75
+ Null = base layer write.
76
+ outcome:
77
+ type: string
78
+ enum:
79
+ - success
80
+ - denied
81
+ - error
82
+ description: 'success = decorator + handler ran clean. denied = 403 from require_role.
83
+ error = handler raised (500/422/...).'
84
+ captured_at:
85
+ type: string
86
+ format: date-time
87
+ description: UTC ISO-8601 timestamp.
88
+ request_id:
89
+ type: string
90
+ description: Correlation ID (UUIDv4) — joins logs.
91
+ remote_ip:
92
+ type: string
93
+ description: Best-effort client IP (X-Forwarded-For aware).
94
+ user_agent:
95
+ type: string
96
+ description: HTTP User-Agent header.
97
+ detail:
98
+ type: object
99
+ description: 'Free-form context: which required roles failed, body size, durations,
100
+ errors. Defensive about PII — don''t include request bodies verbatim.'
101
+ # Curated list-endpoint projection. The extinct Py class declared NO
102
+ # summary() (KindBase whole-spec echo); the TS class returned null. Both
103
+ # are replaced by this curated projection (intentional delta — precedent
104
+ # VoiceEpisode/SynthesizerState in F3 lote-3). The manifest does NOT carry
105
+ # summary, so this choice is manifest-neutral.
106
+ summary:
107
+ actor: ''
108
+ operation: ''
109
+ outcome: ''
110
+ target_kind: ''
111
+ captured_at: ''
112
+ # P2L2 — AuditLog is Govern-mode (compliance + tenant-admin only). Sidebar
113
+ # entry visible to those roles. Read-only — no create/edit exposed in UI
114
+ # (writes happen via emit_audit() from gated handlers).
115
+ ui:
116
+ mode: govern
117
+ label:
118
+ en: Audit Log
119
+ pt-BR: Trilha de Auditoria
120
+ icon: 🔒
121
+ description:
122
+ en: Forensic trail of every role-gated mutation.
123
+ pt-BR: Trilha forense de toda mutação com role.
124
+ breadcrumb:
125
+ - Govern
126
+ - Audit Log
127
+ routes:
128
+ list: docs/AuditLog
129
+ detail: docs/AuditLog/:name
130
+ permissions:
131
+ list:
132
+ - compliance
133
+ - tenant-admin
134
+ detail:
135
+ - compliance
136
+ - tenant-admin
137
+ in_sidebar: true
138
+ display_order: 40
139
+ graph_style:
140
+ fill: '#475569'
141
+ stroke: '#334155'
142
+ text_color: '#fff'
143
+ ascii_icon: 🔍
144
+ display_label: Audit Log
145
+ docs: Immutable record of a role-gated HTTP endpoint invocation. Captures actor,
146
+ roles claimed, operation, target Kind/name, scope/tenant, request_id, outcome,
147
+ and timestamp. Used by compliance auditors + admins to answer 'who did what when'
148
+ without parsing application logs.
@@ -0,0 +1,25 @@
1
+ /**
2
+ * AuditExtension — RBAC audit-trail Kinds.
3
+ *
4
+ * 1:1 parity with Python dna.extensions.audit
5
+ * (s-port-missing-ts-extensions). Registers:
6
+ * - AuditLog (audit-auditlog) — immutable record of a role-gated endpoint
7
+ * call. MIGRATED to a descriptor in expr batch A (plan
8
+ * 2026-06-11-descriptor-expressiveness): the twin AuditLogKind classes
9
+ * (Py+TS) were DELETED — kinds/audit-log.kind.yaml is the single source,
10
+ * registered via the loadDescriptors loop in register(). The descriptor
11
+ * carries the D2 `ui:` block (now expressible Py↔TS), which the old TS
12
+ * class intentionally omitted — so the TS runtime now exposes the same
13
+ * Studio sidebar metadata the Python side always had.
14
+ * - UserRoleAssignment (audit-userroleassignment) — user→roles within a
15
+ * tenant (still a class).
16
+ *
17
+ * UserRoleAssignment is TENANTED (the KindBase default) with no reader/writer
18
+ * (plain YAML).
19
+ */
20
+ import type { ExtensionHost, Extension } from "../kernel/protocols.js";
21
+ export declare class AuditExtension implements Extension {
22
+ readonly name = "audit";
23
+ readonly version = "1.0.0";
24
+ register(kernel: ExtensionHost): void;
25
+ }