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,184 @@
1
+ /**
2
+ * BundleHandle — source-agnostic interface for reading + writing a
3
+ * bundle's entries.
4
+ *
5
+ * 1:1 parity with python/dna/kernel/bundle_handle.py.
6
+ *
7
+ * Implementations:
8
+ * - `FilesystemBundleHandle` — wraps a real filesystem directory.
9
+ * - `DictBundleHandle` — in-memory, used by SQL/Postgres adapters
10
+ * (rehydrate bundle entries from `dna_bundle_entries` rows into
11
+ * a dict, hand to readers).
12
+ * - `PostgresBundleHandle` (Postgres adapter) — backed by
13
+ * `dna_bundle_entries` rows.
14
+ *
15
+ * Entry naming convention: a posix-style relative path inside the
16
+ * bundle. Top-level entries are bare names (`"SKILL.md"`,
17
+ * `"IDENTITY.md"`); nested entries use forward slashes
18
+ * (`"scripts/run.py"`, `"references/spec.md"`).
19
+ *
20
+ * v1.0 async refactor: read/write methods return `Promise<...>`.
21
+ * Async-everywhere is the contract — sync local-FS impls wrap their
22
+ * sync IO in `Promise.resolve` (true `fs/promises` migration is a
23
+ * v1.2 cleanup).
24
+ */
25
+ import { access, readFile, readdir, stat, writeFile, mkdir } from "node:fs/promises";
26
+ import { join, dirname, basename, posix } from "node:path";
27
+ /** True iff the path exists. fs/promises doesn't ship a boolean
28
+ * `exists`; this is the canonical workaround. */
29
+ async function pathExists(p) {
30
+ try {
31
+ await access(p);
32
+ return true;
33
+ }
34
+ catch {
35
+ return false;
36
+ }
37
+ }
38
+ // ---------------------------------------------------------------------------
39
+ // Filesystem implementation
40
+ // ---------------------------------------------------------------------------
41
+ export class FilesystemBundleHandle {
42
+ _root;
43
+ constructor(_root) {
44
+ this._root = _root;
45
+ }
46
+ get name() { return basename(this._root); }
47
+ get path() { return this._root; }
48
+ async exists(entry) {
49
+ return pathExists(join(this._root, entry));
50
+ }
51
+ async readText(entry, encoding = "utf-8") {
52
+ const p = join(this._root, entry);
53
+ try {
54
+ return await readFile(p, encoding);
55
+ }
56
+ catch (e) {
57
+ if (e.code === "ENOENT") {
58
+ const err = new Error(`Bundle entry not found: ${entry}`);
59
+ err.code = "ENOENT";
60
+ throw err;
61
+ }
62
+ throw e;
63
+ }
64
+ }
65
+ async readBytes(entry) {
66
+ const p = join(this._root, entry);
67
+ try {
68
+ return new Uint8Array(await readFile(p));
69
+ }
70
+ catch (e) {
71
+ if (e.code === "ENOENT") {
72
+ const err = new Error(`Bundle entry not found: ${entry}`);
73
+ err.code = "ENOENT";
74
+ throw err;
75
+ }
76
+ throw e;
77
+ }
78
+ }
79
+ async iterEntries(recursive = false) {
80
+ if (!(await pathExists(this._root)))
81
+ return [];
82
+ const out = [];
83
+ if (recursive) {
84
+ const walk = async (dir, prefix) => {
85
+ const entries = (await readdir(dir)).sort();
86
+ for (const entry of entries) {
87
+ const full = join(dir, entry);
88
+ const rel = prefix ? posix.join(prefix, entry) : entry;
89
+ const st = await stat(full);
90
+ if (st.isDirectory())
91
+ await walk(full, rel);
92
+ else
93
+ out.push(rel);
94
+ }
95
+ };
96
+ await walk(this._root, "");
97
+ }
98
+ else {
99
+ for (const entry of (await readdir(this._root)).sort())
100
+ out.push(entry);
101
+ }
102
+ return out;
103
+ }
104
+ async isFile(entry) {
105
+ const p = join(this._root, entry);
106
+ try {
107
+ return (await stat(p)).isFile();
108
+ }
109
+ catch {
110
+ return false;
111
+ }
112
+ }
113
+ async writeText(entry, content, encoding = "utf-8") {
114
+ const p = join(this._root, entry);
115
+ await mkdir(dirname(p), { recursive: true });
116
+ await writeFile(p, content, encoding);
117
+ }
118
+ async writeBytes(entry, content) {
119
+ const p = join(this._root, entry);
120
+ await mkdir(dirname(p), { recursive: true });
121
+ await writeFile(p, Buffer.from(content));
122
+ }
123
+ }
124
+ // ---------------------------------------------------------------------------
125
+ // In-memory implementation (used by tests + SQL adapters)
126
+ // ---------------------------------------------------------------------------
127
+ export class DictBundleHandle {
128
+ name;
129
+ _entries;
130
+ constructor(name, entries = {}) {
131
+ this.name = name;
132
+ this._entries = new Map(Object.entries(entries));
133
+ }
134
+ get path() { return null; }
135
+ async exists(entry) {
136
+ if (this._entries.has(entry))
137
+ return true;
138
+ // Treat parent paths as "directory entries" — true if any key
139
+ // starts with `entry/`.
140
+ const prefix = entry.endsWith("/") ? entry : `${entry}/`;
141
+ for (const k of this._entries.keys())
142
+ if (k.startsWith(prefix))
143
+ return true;
144
+ return false;
145
+ }
146
+ async readText(entry, _encoding = "utf-8") {
147
+ const v = this._entries.get(entry);
148
+ if (v === undefined) {
149
+ const err = new Error(`Bundle entry not found: ${entry}`);
150
+ err.code = "ENOENT";
151
+ throw err;
152
+ }
153
+ return typeof v === "string" ? v : new TextDecoder().decode(v);
154
+ }
155
+ async readBytes(entry) {
156
+ const v = this._entries.get(entry);
157
+ if (v === undefined) {
158
+ const err = new Error(`Bundle entry not found: ${entry}`);
159
+ err.code = "ENOENT";
160
+ throw err;
161
+ }
162
+ return typeof v === "string" ? new TextEncoder().encode(v) : v;
163
+ }
164
+ async iterEntries(recursive = false) {
165
+ if (recursive)
166
+ return Array.from(this._entries.keys()).sort();
167
+ // Direct children only — extract first segment, deduplicate
168
+ const directChildren = new Set();
169
+ for (const k of this._entries.keys()) {
170
+ const slash = k.indexOf("/");
171
+ directChildren.add(slash === -1 ? k : k.substring(0, slash));
172
+ }
173
+ return Array.from(directChildren).sort();
174
+ }
175
+ async isFile(entry) {
176
+ return this._entries.has(entry);
177
+ }
178
+ async writeText(entry, content, _encoding = "utf-8") {
179
+ this._entries.set(entry, content);
180
+ }
181
+ async writeBytes(entry, content) {
182
+ this._entries.set(entry, content);
183
+ }
184
+ }
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Optional capability interfaces for source/cache/etc adapters.
3
+ *
4
+ * 1:1 parity with python/dna/kernel/capabilities.py.
5
+ *
6
+ * H2 — Replaces ad-hoc structural checks (`"fetchBundleEntry" in src`)
7
+ * with discoverable, type-checkable interface assertions. A developer
8
+ * authoring a custom adapter sees the available capabilities by
9
+ * importing this module, instead of grepping the kernel source.
10
+ *
11
+ * Why these are separate from the core `SourcePort` interface:
12
+ *
13
+ * - The core interfaces (SourcePort, WritableSourcePort, CachePort,
14
+ * ...) define the **mandatory** contract every adapter must
15
+ * implement.
16
+ * - These capability interfaces define **optional** features —
17
+ * adapters can declare support by structurally matching the
18
+ * signature, OR omit the methods entirely without breaking the
19
+ * core contract.
20
+ *
21
+ * TypeScript's structural typing makes capability detection at runtime
22
+ * a method-presence check (`typeof src.fetchBundleEntry === "function"`).
23
+ * Use the helper guards (`isBundleEntryReadable`, etc.) for clarity.
24
+ *
25
+ * Adding a new capability:
26
+ * 1. Define `MyCapability` interface here.
27
+ * 2. Add an `isMyCapability(x): x is MyCapability` type guard.
28
+ * 3. Replace any `if ("method" in adapter)` checks with
29
+ * `if (isMyCapability(adapter))`.
30
+ * 4. Document the capability in `docs/PORT-CONTRACT.md`.
31
+ * 5. Cover it in `tests/portContract.test.ts`.
32
+ */
33
+ import type { Kernel } from "./index.js";
34
+ /**
35
+ * Source adapter capability: fetch a single bundle entry by name.
36
+ *
37
+ * The kernel uses this to read large binary payloads (graph.json,
38
+ * tree.json, ...) without rehydrating the whole bundle through the
39
+ * Reader pipeline. Implementing adapters store bundle entries in
40
+ * their backing store (filesystem dir, `dna_bundle_entries` SQL
41
+ * table) and serve byte payloads directly.
42
+ *
43
+ * Tenant overlay routing: when `tenant` is provided and the adapter
44
+ * supports it, the tenant-scoped copy is preferred over the base
45
+ * layer.
46
+ *
47
+ * Throws `Error` (with code `ENOENT` or message containing "not
48
+ * found") when the bundle or entry is absent.
49
+ */
50
+ export interface BundleEntryReadable {
51
+ fetchBundleEntry(scope: string, container: string, name: string, entry: string,
52
+ /**
53
+ * Optional knobs:
54
+ * - ``tenant`` — when set, prefer the tenant overlay row
55
+ * (with base-layer fallback).
56
+ * - ``kind`` — disambiguates SQL row collision when two
57
+ * Kinds share a bundle ``name`` in the same scope (e.g.
58
+ * a Skill ``foo`` and a GraphifyArtifact ``foo``).
59
+ * Filesystem adapters ignore this since each container
60
+ * is a directory namespace.
61
+ */
62
+ options?: {
63
+ tenant?: string | null;
64
+ kind?: string | null;
65
+ }): Promise<Uint8Array>;
66
+ }
67
+ export declare function isBundleEntryReadable(x: unknown): x is BundleEntryReadable;
68
+ /**
69
+ * Source adapter capability: accept post-init kernel wiring.
70
+ *
71
+ * H2 unification: `Kernel.auto({ source })` previously had a
72
+ * hardcoded `source instanceof FilesystemWritableSource` check that
73
+ * wired `_writers` and `setKernel(k)`. SQLite/Postgres adapters
74
+ * required the same wiring but only got it via the harness's
75
+ * source factory — leaving direct
76
+ * `new Kernel().writableSource(new SqliteSource(...))` callers with
77
+ * a half-broken kernel.
78
+ *
79
+ * Adapters now declare attachability by implementing
80
+ * `attachKernel(kernel)`. The kernel calls this method on every
81
+ * source it accepts — uniformly. Implementations install the
82
+ * kernel's `_writers`, `_readers`, and (optionally) a back-ref to
83
+ * the kernel itself for the source's save path to consult
84
+ * `storageForKind`.
85
+ *
86
+ * Idempotent: calling twice with the same kernel produces the same
87
+ * wired state.
88
+ */
89
+ export interface KernelAttachable {
90
+ attachKernel(kernel: Kernel): void;
91
+ }
92
+ export declare function isKernelAttachable(x: unknown): x is KernelAttachable;
93
+ /**
94
+ * Source adapter capability: per-Kind semver versioning.
95
+ *
96
+ * Backs the catalog versioning flow: a Kind that's `Versionable`
97
+ * supports `getVersion(scope, kind, name, versionId)` and
98
+ * `listVersions(...)`. The harness REST surface checks for this
99
+ * capability via `isVersionable` to decide whether to expose the
100
+ * `/catalog/{owner}/{name}/versions` endpoint (501 otherwise).
101
+ *
102
+ * Custom adapters that don't track per-doc versions can omit and
103
+ * the harness will degrade gracefully with a 501 response.
104
+ */
105
+ export interface Versionable {
106
+ getVersion(scope: string, kind: string, name: string, versionId: string): Promise<Record<string, unknown>>;
107
+ }
108
+ export declare function isVersionable(x: unknown): x is Versionable;
109
+ /**
110
+ * Typed view of what a source adapter supports — TS twin of the Py
111
+ * `SourceCapabilities` dataclass (s-sourceport-contract-cleanup).
112
+ *
113
+ * Adapters DECLARE this explicitly (`capabilities()` returns a literal);
114
+ * the kernel consults {@link sourceCapabilities} instead of scattering
115
+ * `typeof src.query === "function"` feature-tests. {@link deriveCapabilities}
116
+ * (structural probing) survives as (a) the conformance-test oracle that
117
+ * keeps declarations honest and (b) the deprecated fallback for external
118
+ * adapters that don't declare yet.
119
+ *
120
+ * Py-only fields with no TS meaning are omitted on purpose:
121
+ * `write_kwargs`/`delete_kwargs`/`tenant_layer_writes` exist in Python
122
+ * because optional kwargs must be probed via `inspect.signature`; the TS
123
+ * write surface is an options bag, so there is nothing to probe.
124
+ */
125
+ export interface SourceCapabilities {
126
+ /** Human-readable adapter label ("filesystem", "postgres", ...). */
127
+ source: string;
128
+ drafts: boolean;
129
+ versions: boolean;
130
+ layers: boolean;
131
+ bundleRead: boolean;
132
+ bundleWrite: boolean;
133
+ kernelAttachable: boolean;
134
+ /** Implements the L1 granular reads (independent flags on purpose —
135
+ * the TS FS source ships `loadOne` but not `listDocRefs`). */
136
+ granularList: boolean;
137
+ granularOne: boolean;
138
+ /** Implements `query`/`count` natively (FS: native but in-memory). */
139
+ queryPushdown: boolean;
140
+ }
141
+ /**
142
+ * Build a {@link SourceCapabilities} for `source` by structural probing —
143
+ * the reflection oracle. In-repo adapters declare literals instead; the
144
+ * conformance test asserts declaration == derivation.
145
+ */
146
+ export declare function deriveCapabilities(source: unknown, label: string): SourceCapabilities;
147
+ /**
148
+ * THE kernel-side accessor for a source's capabilities (TS twin of the
149
+ * Py `source_capabilities`). Resolution order (memoized per instance):
150
+ *
151
+ * 1. the adapter's own `capabilities()` returning a
152
+ * {@link SourceCapabilities} — the explicit declaration;
153
+ * 2. DEPRECATED fallback: {@link deriveCapabilities} structural probing,
154
+ * with a once-per-constructor console warning pointing at the
155
+ * migration (keeps external adapters working).
156
+ */
157
+ export declare function sourceCapabilities(source: object): SourceCapabilities;
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Optional capability interfaces for source/cache/etc adapters.
3
+ *
4
+ * 1:1 parity with python/dna/kernel/capabilities.py.
5
+ *
6
+ * H2 — Replaces ad-hoc structural checks (`"fetchBundleEntry" in src`)
7
+ * with discoverable, type-checkable interface assertions. A developer
8
+ * authoring a custom adapter sees the available capabilities by
9
+ * importing this module, instead of grepping the kernel source.
10
+ *
11
+ * Why these are separate from the core `SourcePort` interface:
12
+ *
13
+ * - The core interfaces (SourcePort, WritableSourcePort, CachePort,
14
+ * ...) define the **mandatory** contract every adapter must
15
+ * implement.
16
+ * - These capability interfaces define **optional** features —
17
+ * adapters can declare support by structurally matching the
18
+ * signature, OR omit the methods entirely without breaking the
19
+ * core contract.
20
+ *
21
+ * TypeScript's structural typing makes capability detection at runtime
22
+ * a method-presence check (`typeof src.fetchBundleEntry === "function"`).
23
+ * Use the helper guards (`isBundleEntryReadable`, etc.) for clarity.
24
+ *
25
+ * Adding a new capability:
26
+ * 1. Define `MyCapability` interface here.
27
+ * 2. Add an `isMyCapability(x): x is MyCapability` type guard.
28
+ * 3. Replace any `if ("method" in adapter)` checks with
29
+ * `if (isMyCapability(adapter))`.
30
+ * 4. Document the capability in `docs/PORT-CONTRACT.md`.
31
+ * 5. Cover it in `tests/portContract.test.ts`.
32
+ */
33
+ export function isBundleEntryReadable(x) {
34
+ return typeof x?.fetchBundleEntry === "function";
35
+ }
36
+ export function isKernelAttachable(x) {
37
+ return typeof x?.attachKernel === "function";
38
+ }
39
+ export function isVersionable(x) {
40
+ return typeof x?.getVersion === "function";
41
+ }
42
+ function _fn(x, name) {
43
+ return typeof x?.[name] === "function";
44
+ }
45
+ /**
46
+ * Build a {@link SourceCapabilities} for `source` by structural probing —
47
+ * the reflection oracle. In-repo adapters declare literals instead; the
48
+ * conformance test asserts declaration == derivation.
49
+ */
50
+ export function deriveCapabilities(source, label) {
51
+ return {
52
+ source: label,
53
+ drafts: _fn(source, "loadDrafts") && _fn(source, "publish"),
54
+ versions: _fn(source, "getVersion"),
55
+ layers: _fn(source, "loadLayer"),
56
+ bundleRead: _fn(source, "fetchBundleEntry"),
57
+ bundleWrite: _fn(source, "writeBundleEntry"),
58
+ kernelAttachable: _fn(source, "attachKernel"),
59
+ granularList: _fn(source, "listDocRefs"),
60
+ granularOne: _fn(source, "loadOne"),
61
+ queryPushdown: _fn(source, "query"),
62
+ };
63
+ }
64
+ const _capsCache = new WeakMap();
65
+ const _warnedUndeclared = new Set();
66
+ /**
67
+ * THE kernel-side accessor for a source's capabilities (TS twin of the
68
+ * Py `source_capabilities`). Resolution order (memoized per instance):
69
+ *
70
+ * 1. the adapter's own `capabilities()` returning a
71
+ * {@link SourceCapabilities} — the explicit declaration;
72
+ * 2. DEPRECATED fallback: {@link deriveCapabilities} structural probing,
73
+ * with a once-per-constructor console warning pointing at the
74
+ * migration (keeps external adapters working).
75
+ */
76
+ export function sourceCapabilities(source) {
77
+ const cached = _capsCache.get(source);
78
+ if (cached)
79
+ return cached;
80
+ let caps = null;
81
+ const fn = source.capabilities;
82
+ if (typeof fn === "function") {
83
+ try {
84
+ const declared = fn.call(source);
85
+ if (declared !== null && typeof declared === "object"
86
+ && typeof declared.source === "string"
87
+ && typeof declared.queryPushdown === "boolean") {
88
+ caps = declared;
89
+ }
90
+ }
91
+ catch {
92
+ caps = null; // a broken declaration degrades to derivation
93
+ }
94
+ }
95
+ if (caps === null) {
96
+ const ctor = source.constructor;
97
+ if (!_warnedUndeclared.has(ctor)) {
98
+ _warnedUndeclared.add(ctor);
99
+ const name = ctor?.name ?? "source";
100
+ console.warn(`[dna-sdk] ${name} does not declare SourceCapabilities via `
101
+ + `capabilities(); deriving structurally (deprecated, `
102
+ + `s-sourceport-contract-cleanup). Declare an explicit `
103
+ + `SourceCapabilities on the adapter to silence this.`);
104
+ }
105
+ caps = deriveCapabilities(source, (source.constructor?.name ?? "source"));
106
+ }
107
+ _capsCache.set(source, caps);
108
+ return caps;
109
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Narrow role-interfaces the kernel's back-ref collaborators depend on — the TS
3
+ * twin of Python's `dna/kernel/collaborator_ports.py`
4
+ * (`s-kernel-decomp-f1`, épico `e-kernel-decomposition`).
5
+ *
6
+ * A kernel collaborator that holds `this._k = kernel` should declare the NARROW
7
+ * slice of the kernel it actually uses, not the whole `Kernel` — otherwise the
8
+ * back-ref is a god-interface pushed one layer down (any collaborator can touch
9
+ * anything → nothing is testable in isolation). Structural typing means the
10
+ * `Kernel` still satisfies each interface, so the kernel keeps passing `this`
11
+ * when it wires the collaborator — zero runtime change.
12
+ *
13
+ * Parity note: the TS kernel decomposition tracks Python. Extracted as back-ref
14
+ * classes with a narrow host today: `CompositionResolver`
15
+ * (`CompositionResolverHost`) and `KindRegistry` (`RegistryHost`). The remaining
16
+ * inline collaborators (instance_builder, query_engine, bundle_io, source_sync,
17
+ * layer_policy, invalidation) gain their narrow interfaces as those extractions
18
+ * land, keeping the contract convergent per spec §6.
19
+ */
20
+ import type { HookRegistry } from "./hooks.js";
21
+ import type { KindPort, ReaderPort, SourcePort, WritableSourcePort } from "./protocols.js";
22
+ /**
23
+ * The kernel surface `CompositionResolver` consumes (twin of Py
24
+ * `CompositionResolverHost`, though TS is leaner: the resolution-chain walk +
25
+ * composition-rule read touch only these). The static `INHERIT_PARENT_SCOPE`
26
+ * is reached via `(k.constructor as typeof Kernel)` — an explicit cast that does
27
+ * not need to be part of this instance contract.
28
+ */
29
+ export interface CompositionResolverHost {
30
+ /** The active read source (getter). */
31
+ readonly activeSource: SourcePort | null;
32
+ /** Granular per-doc cache read: `[scope, kind, name, tenantOrEmpty]`. */
33
+ _granularDoc(key: [string, string, string, string]): Promise<Record<string, unknown> | null>;
34
+ /** The ordered Catalog scope set for a tenant (cached, fail-soft). */
35
+ _catalogScopes(tenant: string | null, opts?: {
36
+ exclude?: Set<string>;
37
+ }): Promise<Array<[string, string | null]>>;
38
+ /** Persist the materialized composition back through the writable source. */
39
+ writeDocument(scope: string, kind: string, name: string, raw: Record<string, unknown>, options?: {
40
+ skipHooks?: boolean;
41
+ author?: string;
42
+ tenant?: string | null;
43
+ layer?: [string, string];
44
+ }): Promise<string>;
45
+ }
46
+ /**
47
+ * The narrow slice of the Kernel the `KindRegistry` registration funnel needs
48
+ * (twin of Py `RegistryHost`, `s-kernel-decomp-f3-kindregistry`). The `kinds`
49
+ * map itself is OWNED by the registry — NOT reached through the host; this host
50
+ * is only the fan-out surface registration touches on the wider kernel: the
51
+ * hook registry (`kinddef_conflict` / `parse_error` events), the `_readers` list
52
+ * (the 2-phase-load rescan return gate), the generic reader/writer wiring, and
53
+ * the `_genericsResolved` flag it flips on every successful register. Every
54
+ * member is a genuine registration dependency; widening it is a code-review
55
+ * event (spec §3.1 / anti-goal §5.3).
56
+ *
57
+ * `_loadingExtOwner` (the per-`load()` alias-owner context) is read via
58
+ * optional chaining, so a kernel outside a `load()` call (where it is null) is
59
+ * still a valid host.
60
+ */
61
+ /**
62
+ * The narrow slice of the Kernel the `WritePipeline` consumes (twin of Py
63
+ * `WriteHost`, `s-kernel-decomp-f2-writepipeline` — the anti-cosmetic F1 rule,
64
+ * spec §3.1). The TS write path is thinner than Python's (no invalidate tiers /
65
+ * OTel / catalog / observer fan-out — those "live in Python"), so this host is
66
+ * smaller than the Py `WriteHost`: just tenant reconciliation, the writable-
67
+ * source guard, the layer-policy check, the hook registry (`pre_save` veto +
68
+ * `post_save`/`post_delete`), and Kind identity. Widening it is a code-review
69
+ * event (anti-goal §5.3).
70
+ */
71
+ export interface WriteHost {
72
+ readonly hooks: HookRegistry;
73
+ readonly tenant: string | null;
74
+ _kindScope(kind: string): string | null;
75
+ kindPortFor(kind: string, apiVersion?: string): KindPort | null;
76
+ _requireWritableSource(): WritableSourcePort;
77
+ _checkLayerPolicyAsync(scope: string, kind: string, name: string, raw: unknown, layer: [string, string]): Promise<void>;
78
+ }
79
+ export interface RegistryHost {
80
+ readonly hooks: HookRegistry;
81
+ /** The active reader list — read for the rescan gate; mutated by
82
+ * `_ensureGenericReadersWriters()`. */
83
+ _readers: ReaderPort[];
84
+ /** Flipped false on every successful register so the next
85
+ * `_ensureGenericReadersWriters()` re-resolves generic BUNDLE rw. */
86
+ _genericsResolved: boolean;
87
+ /** Per-`load()` alias-owner context (null outside a load). */
88
+ _loadingExtOwner: string | null;
89
+ /** Re-resolve generic BUNDLE readers/writers for newly registered kinds. */
90
+ _ensureGenericReadersWriters(): void;
91
+ }
@@ -0,0 +1 @@
1
+ export {};