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,247 @@
1
+ /**
2
+ * HookExtension — Hook kind for declarative hook configuration.
3
+ *
4
+ * Hooks declared as YAML documents in the manifest. The kernel auto-registers
5
+ * them on the HookRegistry during instance creation.
6
+ */
7
+ import yaml from "js-yaml";
8
+ import { nodeFS } from "../kernel/fs.js";
9
+ import { KindBase } from "../kernel/kind_base.js";
10
+ import { HookSchema, HookSpecSchema, zodSpecToJsonSchema } from "../kernel/models.js";
11
+ import { SD } from "../kernel/protocols.js";
12
+ // ---------------------------------------------------------------------------
13
+ // HookKind
14
+ // ---------------------------------------------------------------------------
15
+ class HookKind extends KindBase {
16
+ apiVersion = "github.com/ruinosus/dna/v1";
17
+ kind = "Hook";
18
+ alias = "helix-hook";
19
+ isSchemaAffecting = true;
20
+ origin = "github.com/ruinosus/dna";
21
+ isPromptTarget = false;
22
+ promptTargetPriority = 0;
23
+ flattenInContext = false;
24
+ storage = SD.bundle("hooks", "HOOK.md", "text", "body");
25
+ graphStyle = { fill: "#F59E0B", stroke: "#D97706", textColor: "#fff" };
26
+ asciiIcon = "\u26A1";
27
+ displayLabel = "Hooks";
28
+ _sourceUrl = import.meta.url;
29
+ docs = "A Hook declares a middleware or event handler that the kernel auto-registers " +
30
+ "on the HookRegistry when the manifest is loaded. Hooks can inject fields into " +
31
+ "the prompt context (inject_fields), log events (log), or run custom scripts (script).";
32
+ uiSchema = {
33
+ target: {
34
+ widget: "select",
35
+ label: "Target Hook",
36
+ help: "Which kernel hook this attaches to",
37
+ options: ["pre_build_prompt", "post_build_prompt", "parse_error", "extension_error", "kinddef_conflict"],
38
+ order: 1,
39
+ },
40
+ type: {
41
+ widget: "select",
42
+ label: "Type",
43
+ help: "Middleware transforms context (returns modified ctx). Event is fire-and-forget.",
44
+ options: ["middleware", "event"],
45
+ order: 2,
46
+ },
47
+ action: {
48
+ widget: "select",
49
+ label: "Action",
50
+ help: "inject_fields: merge YAML key-value pairs into prompt context. log: log event to console. script: run custom code.",
51
+ options: ["inject_fields", "log", "script"],
52
+ order: 3,
53
+ },
54
+ fields: {
55
+ widget: "code",
56
+ language: "yaml",
57
+ label: "Injected Fields (YAML)",
58
+ help: "Key-value pairs merged into the prompt context when action is inject_fields",
59
+ height: 200,
60
+ order: 4,
61
+ },
62
+ body: {
63
+ widget: "code",
64
+ language: "javascript",
65
+ label: "Script",
66
+ help: "JavaScript function: (ctx) => { ... return ctx; } for middleware, or (ctx) => { ... } for events",
67
+ height: 300,
68
+ order: 5,
69
+ },
70
+ };
71
+ schema() { return zodSpecToJsonSchema(HookSpecSchema); }
72
+ parse(raw) {
73
+ return HookSchema.parse(raw);
74
+ }
75
+ describe(doc) {
76
+ const spec = (doc.spec ?? {});
77
+ return `Hook: ${doc.name} \u2192 ${spec.target} (${spec.action})`;
78
+ }
79
+ summary(doc) {
80
+ const spec = (doc.spec ?? {});
81
+ return {
82
+ target: spec.target ?? "",
83
+ type: spec.type ?? "middleware",
84
+ action: spec.action ?? "inject_fields",
85
+ };
86
+ }
87
+ preview(doc) {
88
+ const spec = (doc.spec ?? {});
89
+ const blocks = [];
90
+ blocks.push({
91
+ kind: "fields",
92
+ title: "Hook Configuration",
93
+ fields: [
94
+ { label: "Target", value: String(spec.target ?? "") },
95
+ { label: "Type", value: String(spec.type ?? "middleware") },
96
+ { label: "Action", value: String(spec.action ?? "inject_fields") },
97
+ ],
98
+ });
99
+ const action = spec.action;
100
+ if (action === "inject_fields") {
101
+ const fields = spec.fields;
102
+ if (fields && Object.keys(fields).length > 0) {
103
+ blocks.push({
104
+ kind: "code",
105
+ title: "Injected Fields",
106
+ body: JSON.stringify(fields, null, 2),
107
+ language: "json",
108
+ });
109
+ }
110
+ }
111
+ else if (action === "script") {
112
+ const body = spec.body;
113
+ if (body) {
114
+ blocks.push({
115
+ kind: "code",
116
+ title: "Script",
117
+ body,
118
+ language: "javascript",
119
+ });
120
+ }
121
+ }
122
+ return blocks.length > 0 ? blocks : [{ kind: "empty", title: "Hook (empty)" }];
123
+ }
124
+ }
125
+ // ---------------------------------------------------------------------------
126
+ // HookReader: detects HOOK.md and parses frontmatter + body
127
+ // ---------------------------------------------------------------------------
128
+ function parseFrontmatter(text) {
129
+ const match = text.match(/^---\n([\s\S]*?)---\n?/);
130
+ if (!match)
131
+ return [{}, text];
132
+ let fm = {};
133
+ try {
134
+ const parsed = yaml.load(match[1]);
135
+ if (typeof parsed === "object" && parsed !== null) {
136
+ fm = parsed;
137
+ }
138
+ }
139
+ catch { /* ignore */ }
140
+ const body = text.slice(match[0].length);
141
+ return [fm, body];
142
+ }
143
+ export class HookReader {
144
+ fs;
145
+ _marker = "HOOK.md";
146
+ constructor(fs = nodeFS) {
147
+ this.fs = fs;
148
+ }
149
+ detect(bundle) {
150
+ const path = bundle.path ?? "";
151
+ return this.fs.exists(`${path}/HOOK.md`);
152
+ }
153
+ read(bundle) {
154
+ const path = bundle.path ?? "";
155
+ const text = this.fs.readFile(`${path}/HOOK.md`);
156
+ const [fm, body] = parseFrontmatter(text);
157
+ const name = String(fm.name || "") || path.split("/").pop() || "";
158
+ const description = String(fm.description || "");
159
+ const spec = {
160
+ target: fm.target ?? "pre_build_prompt",
161
+ type: fm.type ?? "middleware",
162
+ action: fm.action ?? "inject_fields",
163
+ body: body.trim(),
164
+ };
165
+ // Parse body based on action type
166
+ const action = spec.action;
167
+ if (action === "inject_fields" && body.trim()) {
168
+ try {
169
+ const parsed = yaml.load(body.trim());
170
+ if (typeof parsed === "object" && parsed !== null) {
171
+ spec.fields = parsed;
172
+ }
173
+ }
174
+ catch {
175
+ // If YAML parse fails, treat as raw text
176
+ spec.fields = {};
177
+ }
178
+ }
179
+ return {
180
+ apiVersion: "github.com/ruinosus/dna/v1",
181
+ kind: "Hook",
182
+ metadata: { name, description },
183
+ spec,
184
+ };
185
+ }
186
+ }
187
+ // ---------------------------------------------------------------------------
188
+ // HookWriter: serializes Hook back to HOOK.md
189
+ // ---------------------------------------------------------------------------
190
+ export class HookWriter {
191
+ fs;
192
+ _kind = "Hook";
193
+ constructor(fs = nodeFS) {
194
+ this.fs = fs;
195
+ }
196
+ canWrite(raw) {
197
+ return raw.kind === "Hook";
198
+ }
199
+ write(bundle, raw) {
200
+ const path = bundle.path ?? "";
201
+ this.fs.mkdir(path);
202
+ for (const f of this.serialize(raw)) {
203
+ this.fs.writeFile(`${path}/${f.relativePath}`, f.content ?? "");
204
+ }
205
+ }
206
+ serialize(raw) {
207
+ const meta = (raw.metadata ?? {});
208
+ const spec = (raw.spec ?? {});
209
+ const fmParts = [];
210
+ if (meta.name)
211
+ fmParts.push(`name: ${meta.name}`);
212
+ if (meta.description)
213
+ fmParts.push(`description: ${meta.description}`);
214
+ fmParts.push(`target: ${spec.target ?? "pre_build_prompt"}`);
215
+ fmParts.push(`type: ${spec.type ?? "middleware"}`);
216
+ fmParts.push(`action: ${spec.action ?? "inject_fields"}`);
217
+ const frontmatter = fmParts.join("\n");
218
+ let body = "";
219
+ const action = spec.action;
220
+ if (action === "inject_fields" && spec.fields) {
221
+ body = yaml.dump(spec.fields, { flowLevel: -1 }).trim();
222
+ }
223
+ else if (action === "script" && spec.body) {
224
+ body = String(spec.body);
225
+ }
226
+ const content = body
227
+ ? `---\n${frontmatter}\n---\n\n${body}\n`
228
+ : `---\n${frontmatter}\n---\n`;
229
+ return [{ relativePath: "HOOK.md", content }];
230
+ }
231
+ }
232
+ // ---------------------------------------------------------------------------
233
+ // Extension
234
+ // ---------------------------------------------------------------------------
235
+ export class HookExtension {
236
+ fs;
237
+ name = "hooks";
238
+ version = "1.0.0";
239
+ constructor(fs = nodeFS) {
240
+ this.fs = fs;
241
+ }
242
+ register(kernel) {
243
+ kernel.kind(new HookKind());
244
+ kernel.reader(new HookReader(this.fs));
245
+ kernel.writer(new HookWriter(this.fs));
246
+ }
247
+ }
@@ -0,0 +1,24 @@
1
+ # KindDefinition
2
+
3
+ `KindDefinition` is the Helix meta-kind: a declarative way to register
4
+ brand-new kinds into a manifest without writing any extension code.
5
+
6
+ A KindDefinition document lives at
7
+ `.dna/<scope>/kinds/<name>/KIND.yaml` and carries:
8
+
9
+ - `target_api_version` — the apiVersion new documents of this kind will claim
10
+ - `target_kind` — the kind name (e.g. `Recipe`, `Meeting`)
11
+ - `alias` — the `<owner>-<kind>` alias used in dep_filters and prompts
12
+ - `origin` — provenance string
13
+ - `schema` — a JSON Schema that validates each document's `spec`
14
+ - `storage` — layout descriptor (`bundle`, `yaml`, `standalone`, `root`)
15
+ - `docs` — prose description surfaced by `describeKind`
16
+ - `is_root`, `prompt_target`, `flatten_in_context`, `dep_filters`,
17
+ `default_agent` — the same prompt + composition flags hand-written kinds
18
+ expose
19
+
20
+ At load time the kernel performs a 2-phase parse: KindDefinitions are
21
+ parsed first and each is wrapped in a synthesized `DeclarativeKindPort`
22
+ that's registered on the kernel before any other document is parsed. If a
23
+ KindDefinition claims the same `(apiVersion, kind)` as an extension-backed
24
+ kind, the extension wins and the KindDefinition is skipped with a warning.
@@ -0,0 +1,40 @@
1
+ /**
2
+ * KindDefinitionExtension — the built-in meta-kind extension.
3
+ *
4
+ * Ships the `KindDefinition` kind itself. Documents live at
5
+ * `.dna/<scope>/kinds/<name>/KIND.yaml` (bundle layout). The kernel's
6
+ * 2-phase loader parses these first and synthesizes a DeclarativeKindPort
7
+ * for each before parsing the rest of the manifest.
8
+ *
9
+ * 1:1 parity with Python dna.extensions.kinddef.
10
+ */
11
+ import type { BundleHandle } from "../kernel/bundle-handle.js";
12
+ import type { FSLike } from "../kernel/fs.js";
13
+ import type { Extension, ReaderPort, SerializedFile, WriterPort } from "../kernel/protocols.js";
14
+ import type { ExtensionHost } from "../kernel/protocols.js";
15
+ /** Reader for `kinds/<name>/KIND.yaml` — plain YAML, not frontmatter+body. */
16
+ export declare class KindDefinitionReader implements ReaderPort {
17
+ private fs;
18
+ /** Exposed for deferred-generic-registration detection. */
19
+ readonly _marker = "KIND.yaml";
20
+ constructor(fs?: FSLike);
21
+ detect(bundle: BundleHandle): boolean;
22
+ read(bundle: BundleHandle): Record<string, unknown>;
23
+ }
24
+ /** Writer for KindDefinition bundles — plain YAML. */
25
+ export declare class KindDefinitionWriter implements WriterPort {
26
+ private fs;
27
+ /** Exposed for deferred-generic-registration detection. */
28
+ readonly _kind = "KindDefinition";
29
+ constructor(fs?: FSLike);
30
+ canWrite(raw: Record<string, unknown>): boolean;
31
+ write(bundle: BundleHandle, raw: Record<string, unknown>): void;
32
+ serialize(raw: Record<string, unknown>): SerializedFile[];
33
+ }
34
+ export declare class KindDefinitionExtension implements Extension {
35
+ private fs;
36
+ readonly name = "kinddef";
37
+ readonly version = "1.0.0";
38
+ constructor(fs?: FSLike);
39
+ register(kernel: ExtensionHost): void;
40
+ }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * KindDefinitionExtension — the built-in meta-kind extension.
3
+ *
4
+ * Ships the `KindDefinition` kind itself. Documents live at
5
+ * `.dna/<scope>/kinds/<name>/KIND.yaml` (bundle layout). The kernel's
6
+ * 2-phase loader parses these first and synthesizes a DeclarativeKindPort
7
+ * for each before parsing the rest of the manifest.
8
+ *
9
+ * 1:1 parity with Python dna.extensions.kinddef.
10
+ */
11
+ import yaml from "js-yaml";
12
+ import { nodeFS } from "../kernel/fs.js";
13
+ import { KindBase } from "../kernel/kind_base.js";
14
+ import { KIND_DEFINITION_API_VERSION, KIND_DEFINITION_KIND, KindDefinitionSchema, KindDefinitionSpecSchema, zodSpecToJsonSchema, } from "../kernel/models.js";
15
+ import { SD } from "../kernel/protocols.js";
16
+ class KindDefinitionKind extends KindBase {
17
+ apiVersion = KIND_DEFINITION_API_VERSION;
18
+ kind = KIND_DEFINITION_KIND;
19
+ alias = "kinddef-kinddefinition";
20
+ isSchemaAffecting = true;
21
+ isOverlayable = false;
22
+ scopeInheritable = false;
23
+ origin = "github.com/ruinosus/dna/core";
24
+ isPromptTarget = false;
25
+ promptTargetPriority = 0;
26
+ flattenInContext = false;
27
+ storage = SD.bundle("kinds", "KIND.yaml");
28
+ visibleInBackend = true; // user-authored via wizard, not system-generated
29
+ graphStyle = { fill: "#A855F7", stroke: "#9333EA", textColor: "#fff" };
30
+ asciiIcon = "🧬";
31
+ displayLabel = "KindDefinitions";
32
+ _sourceUrl = import.meta.url;
33
+ docs = "A KindDefinition declaratively defines a brand-new kind without " +
34
+ "writing TypeScript code. Its spec carries the target apiVersion, kind " +
35
+ "name, alias, JSON Schema for the document spec, storage layout, and " +
36
+ "prompt flags. The kernel's 2-phase loader parses KindDefinitions first, " +
37
+ "synthesizes a DeclarativeKindPort for each, then parses the rest of " +
38
+ "the manifest so regular documents can reference the newly registered kind.";
39
+ depFilters() {
40
+ return null;
41
+ }
42
+ dependencies() {
43
+ return this.depFilters();
44
+ }
45
+ schema() {
46
+ return zodSpecToJsonSchema(KindDefinitionSpecSchema);
47
+ }
48
+ getDefaultAgentName(_doc) {
49
+ return null;
50
+ }
51
+ getLayerPolicies(_doc) {
52
+ return null;
53
+ }
54
+ parse(raw) {
55
+ return KindDefinitionSchema.parse(raw);
56
+ }
57
+ describe() {
58
+ return null;
59
+ }
60
+ summary() {
61
+ return null;
62
+ }
63
+ promptTemplate() {
64
+ return null;
65
+ }
66
+ preview(doc) {
67
+ const spec = (doc.spec ?? {});
68
+ const fields = [];
69
+ if (typeof spec.target_kind === "string")
70
+ fields.push({ label: "target_kind", value: spec.target_kind });
71
+ if (typeof spec.target_api_version === "string")
72
+ fields.push({ label: "target_api_version", value: spec.target_api_version });
73
+ if (typeof spec.alias === "string")
74
+ fields.push({ label: "alias", value: spec.alias });
75
+ if (typeof spec.origin === "string")
76
+ fields.push({ label: "origin", value: spec.origin });
77
+ for (const flag of ["is_root", "prompt_target", "flatten_in_context"]) {
78
+ if (spec[flag] != null) {
79
+ fields.push({ label: flag, value: String(spec[flag]) });
80
+ }
81
+ }
82
+ if (spec.storage) {
83
+ fields.push({
84
+ label: "storage",
85
+ value: JSON.stringify(spec.storage, null, 2),
86
+ });
87
+ }
88
+ if (spec.schema) {
89
+ fields.push({
90
+ label: "schema",
91
+ value: JSON.stringify(spec.schema, null, 2),
92
+ });
93
+ }
94
+ if (typeof spec.docs === "string" && spec.docs) {
95
+ fields.push({ label: "docs", value: spec.docs });
96
+ }
97
+ if (fields.length === 0) {
98
+ return [{ kind: "empty", title: `KindDefinition ${doc.name}` }];
99
+ }
100
+ return [{ kind: "fields", title: `KindDefinition ${doc.name}`, fields }];
101
+ }
102
+ }
103
+ /** Reader for `kinds/<name>/KIND.yaml` — plain YAML, not frontmatter+body. */
104
+ export class KindDefinitionReader {
105
+ fs;
106
+ /** Exposed for deferred-generic-registration detection. */
107
+ _marker = "KIND.yaml";
108
+ constructor(fs = nodeFS) {
109
+ this.fs = fs;
110
+ }
111
+ detect(bundle) {
112
+ const path = bundle.path ?? "";
113
+ return this.fs.exists(`${path}/KIND.yaml`);
114
+ }
115
+ read(bundle) {
116
+ const path = bundle.path ?? "";
117
+ const text = this.fs.readFile(`${path}/KIND.yaml`);
118
+ const doc = yaml.load(text);
119
+ if (doc == null || typeof doc !== "object") {
120
+ throw new Error(`${path}/KIND.yaml did not parse into a mapping`);
121
+ }
122
+ const raw = doc;
123
+ if (!raw.apiVersion)
124
+ raw.apiVersion = KIND_DEFINITION_API_VERSION;
125
+ if (!raw.kind)
126
+ raw.kind = KIND_DEFINITION_KIND;
127
+ const meta = raw.metadata ?? {};
128
+ if (!meta.name)
129
+ meta.name = path.split("/").pop() ?? "";
130
+ raw.metadata = meta;
131
+ return raw;
132
+ }
133
+ }
134
+ /** Writer for KindDefinition bundles — plain YAML. */
135
+ export class KindDefinitionWriter {
136
+ fs;
137
+ /** Exposed for deferred-generic-registration detection. */
138
+ _kind = KIND_DEFINITION_KIND;
139
+ constructor(fs = nodeFS) {
140
+ this.fs = fs;
141
+ }
142
+ canWrite(raw) {
143
+ return raw.kind === KIND_DEFINITION_KIND;
144
+ }
145
+ write(bundle, raw) {
146
+ const path = bundle.path ?? "";
147
+ this.fs.mkdir(path);
148
+ this.fs.writeFile(`${path}/KIND.yaml`, yaml.dump(raw, { sortKeys: false, flowLevel: -1 }));
149
+ }
150
+ serialize(raw) {
151
+ return [
152
+ {
153
+ relativePath: "KIND.yaml",
154
+ content: yaml.dump(raw, { sortKeys: false, flowLevel: -1 }),
155
+ },
156
+ ];
157
+ }
158
+ }
159
+ export class KindDefinitionExtension {
160
+ fs;
161
+ name = "kinddef";
162
+ version = "1.0.0";
163
+ constructor(fs = nodeFS) {
164
+ this.fs = fs;
165
+ }
166
+ register(kernel) {
167
+ kernel.kind(new KindDefinitionKind());
168
+ kernel.reader(new KindDefinitionReader(this.fs));
169
+ kernel.writer(new KindDefinitionWriter(this.fs));
170
+ }
171
+ }
@@ -0,0 +1,6 @@
1
+ import type { ExtensionHost, Extension } from "../kernel/protocols.js";
2
+ export declare class LessonExtension implements Extension {
3
+ name: string;
4
+ version: string;
5
+ register(kernel: ExtensionHost): void;
6
+ }
@@ -0,0 +1,194 @@
1
+ /**
2
+ * LessonExtension — declarative educational activity Kind (TS twin).
3
+ *
4
+ * 1:1 parity with python/dna/extensions/lesson/__init__.py.
5
+ * A Lesson is a short structured activity a child-companion agent runs. Bundle
6
+ * storage: LESSON.md (frontmatter = spec). GLOBAL — the catalog is per-scope.
7
+ */
8
+ import yaml from "js-yaml";
9
+ import { KindBase } from "../kernel/kind_base.js";
10
+ import { SD, TenantScope } from "../kernel/protocols.js";
11
+ import { writeEntriesToHandle } from "../kernel/writer-helpers.js";
12
+ const API_VERSION = "github.com/ruinosus/dna/lesson/v1";
13
+ function parseFrontmatter(text) {
14
+ const m = text.match(/^---\n([\s\S]*?)---\n?([\s\S]*)$/);
15
+ if (!m)
16
+ return { fm: {}, body: text };
17
+ try {
18
+ const parsed = yaml.load(m[1]);
19
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
20
+ return { fm: parsed, body: (m[2] ?? "").replace(/^\n+/, "") };
21
+ }
22
+ }
23
+ catch {
24
+ // fall through
25
+ }
26
+ return { fm: {}, body: text };
27
+ }
28
+ class LessonKind extends KindBase {
29
+ apiVersion = API_VERSION;
30
+ kind = "Lesson";
31
+ alias = "lesson-lesson";
32
+ origin = "github.com/ruinosus/dna/lesson";
33
+ isPromptTarget = false;
34
+ promptTargetPriority = 0;
35
+ flattenInContext = false;
36
+ // GLOBAL — the catalog is per-scope, not per-tenant.
37
+ scope = TenantScope.GLOBAL;
38
+ storage = SD.bundle("lessons", "LESSON.md");
39
+ graphStyle = { fill: "#F59E0B", stroke: "#D97706", textColor: "#fff" };
40
+ asciiIcon = "📚";
41
+ displayLabel = "Lessons";
42
+ docs = "A Lesson is a short, structured educational activity the agent can run with " +
43
+ "a pre-reader child. Declarative — content is in YAML, edited by caregivers " +
44
+ "in Studio, no code review. Tools: start_lesson(subject) picks one; " +
45
+ "record_attempt(concept, correct) tracks performance into LessonLearned docs.";
46
+ dependencies() { return null; }
47
+ schema() {
48
+ return {
49
+ type: "object",
50
+ required: ["subject", "target_concepts", "prompts"],
51
+ additionalProperties: true,
52
+ properties: {
53
+ subject: { type: "string", description: "Short concept group ('cores-basicas', 'animais-conhecidos', 'rotina-comer')." },
54
+ title: { type: "string", description: "Display title in PT-BR ('Cores básicas', 'Animais que você conhece')." },
55
+ skill: {
56
+ type: "string",
57
+ enum: ["reconhecer", "identificar", "parear", "repetir", "associar", "contar", "ordenar"],
58
+ default: "reconhecer",
59
+ },
60
+ modality: {
61
+ type: "array",
62
+ items: { type: "string", enum: ["visual", "audio", "interativo"] },
63
+ default: ["visual", "audio", "interativo"],
64
+ },
65
+ difficulty: { type: "integer", minimum: 1, maximum: 5, default: 1 },
66
+ duration_seconds_max: { type: "integer", default: 120, description: "Cap to respect TDAH attention budget. 60-180 typical for ages 8-12." },
67
+ target_concepts: { type: "array", items: { type: "string" }, description: "Concept slugs that match Pictogram.spec.concept (azul, vermelho, etc)." },
68
+ prompts: { type: "array", items: { type: "string" }, description: "DEPRECATED v2: legacy flat list of Lumi-spoken prompts. Use `steps` instead. Kept for back-compat with v1 seeds — if `steps` is missing, runtime synthesizes a 1-step-per-prompt timeline." },
69
+ steps: {
70
+ type: "array",
71
+ description: "Ordered list of LessonStep objects. Agent walks them in order, listening to Mateus between each, calling show_pictogram for visual anchor and record_attempt on test steps.",
72
+ items: {
73
+ type: "object",
74
+ required: ["kind", "prompt"],
75
+ additionalProperties: true,
76
+ properties: {
77
+ kind: {
78
+ type: "string",
79
+ enum: ["present", "repeat", "test", "celebrate", "review"],
80
+ description: "present = introduce concept; repeat = ask Mateus to repeat/imitate; test = ask Mateus to identify (calls record_attempt); celebrate = positive reinforcement; review = recap before next step.",
81
+ },
82
+ prompt: { type: "string", description: "Short PT-BR phrase Lumi speaks at this step. ≤6 words ideal." },
83
+ expected_concept: { type: "string", description: "Optional Pictogram concept slug to show via show_pictogram(). Required on `test` steps so record_attempt knows the target." },
84
+ on_correct: { type: "string", description: "Lumi's reaction on success. Default: 'Isso!' for test, advance otherwise." },
85
+ on_incorrect: { type: "string", description: "Lumi's reaction on failure. Default: gentle re-prompt + show pictogram again." },
86
+ hint_ladder: { type: "array", items: { type: "string" }, description: "Optional 1-3 progressively stronger hints if Mateus errs (silhouette → color → sound)." },
87
+ },
88
+ },
89
+ },
90
+ reinforcement: { type: "string", enum: ["celebrate", "gentle", "neutral"], default: "celebrate", description: "How Lumi reacts to correct answers. 'celebrate' = set_pose celebrating + warm phrase." },
91
+ on_no_response: { type: "string", default: "Vamos tentar outra coisa?", description: "Phrase Lumi says after ~30s of no input. Always gentle, never pressuring." },
92
+ success_criteria: { type: "object", additionalProperties: true, description: "How to mark this lesson 'done well'. Example: {matches: 3, duration_min: 30}." },
93
+ approved_by: { type: "array", items: { type: "string" }, default: [] },
94
+ labels: { type: "array", items: { type: "string" }, default: [] },
95
+ },
96
+ };
97
+ }
98
+ describe(doc) {
99
+ const spec = (doc.spec ?? {});
100
+ const title = spec.title || spec.subject || "?";
101
+ const diff = spec.difficulty ?? 1;
102
+ return `${title} (lv ${diff})`;
103
+ }
104
+ summary(doc) {
105
+ const spec = (doc.spec ?? {});
106
+ const concepts = spec.target_concepts ?? [];
107
+ const steps = spec.steps ?? [];
108
+ return {
109
+ subject: spec.subject ?? "",
110
+ skill: spec.skill ?? "",
111
+ difficulty: spec.difficulty ?? 1,
112
+ concept_count: concepts.length,
113
+ step_count: steps.length,
114
+ format: steps.length ? "multi-step" : "legacy-prompts",
115
+ };
116
+ }
117
+ }
118
+ class LessonReader {
119
+ async detect(bundle) {
120
+ return bundle.exists("LESSON.md");
121
+ }
122
+ async read(bundle) {
123
+ const text = await bundle.readText("LESSON.md");
124
+ const { fm } = parseFrontmatter(text);
125
+ if (fm && typeof fm === "object" && "spec" in fm && fm["spec"] && typeof fm["spec"] === "object") {
126
+ const metadata = fm["metadata"] ?? {};
127
+ if (!("name" in metadata))
128
+ metadata["name"] = bundle.name;
129
+ return {
130
+ apiVersion: fm["apiVersion"] ?? API_VERSION,
131
+ kind: fm["kind"] ?? "Lesson",
132
+ metadata,
133
+ spec: fm["spec"],
134
+ };
135
+ }
136
+ return {
137
+ apiVersion: API_VERSION,
138
+ kind: "Lesson",
139
+ metadata: { name: bundle.name },
140
+ spec: fm,
141
+ };
142
+ }
143
+ }
144
+ class LessonWriter {
145
+ canWrite(raw) {
146
+ return raw["kind"] === "Lesson";
147
+ }
148
+ serialize(raw) {
149
+ const spec = (raw["spec"] ?? {});
150
+ const meta = { ...(raw["metadata"] ?? {}) };
151
+ const cleanSpec = {};
152
+ for (const [k, v] of Object.entries(spec)) {
153
+ if (v === null || v === undefined || v === "")
154
+ continue;
155
+ if (Array.isArray(v) && v.length === 0)
156
+ continue;
157
+ if (typeof v === "object" && !Array.isArray(v) && Object.keys(v).length === 0)
158
+ continue;
159
+ cleanSpec[k] = v;
160
+ }
161
+ const cleanMeta = {};
162
+ for (const [k, v] of Object.entries(meta)) {
163
+ if (v !== null && v !== undefined)
164
+ cleanMeta[k] = v;
165
+ }
166
+ const envelope = {
167
+ apiVersion: raw["apiVersion"] ?? API_VERSION,
168
+ kind: raw["kind"] ?? "Lesson",
169
+ metadata: cleanMeta,
170
+ spec: cleanSpec,
171
+ };
172
+ const fmYaml = yaml.dump(envelope, { lineWidth: 100, noRefs: true, sortKeys: false }).trimEnd();
173
+ const title = cleanSpec["title"] || cleanSpec["subject"] || "?";
174
+ const skill = cleanSpec["skill"] ?? "reconhecer";
175
+ const diff = cleanSpec["difficulty"] ?? 1;
176
+ const subject = cleanSpec["subject"] ?? "?";
177
+ const body = `# Lesson — ${title} (skill: ${skill}, lv ${diff})\n\n` +
178
+ `Curated educational activity for child-companion agents. Run via ` +
179
+ `\`start_lesson(${subject})\`.\n`;
180
+ return [{ relativePath: "LESSON.md", content: `---\n${fmYaml}\n---\n\n${body}` }];
181
+ }
182
+ async write(bundle, raw) {
183
+ await writeEntriesToHandle(bundle, this.serialize(raw));
184
+ }
185
+ }
186
+ export class LessonExtension {
187
+ name = "lesson";
188
+ version = "1.0.0";
189
+ register(kernel) {
190
+ kernel.kind(new LessonKind());
191
+ kernel.reader(new LessonReader());
192
+ kernel.writer(new LessonWriter());
193
+ }
194
+ }