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,751 @@
1
+ /**
2
+ * v3 Kernel Protocols — the 5 ports + shared types.
3
+ *
4
+ * Parity with Python dna.kernel.protocols is SURFACE-TRACKED, not
5
+ * assumed (s-dna-port-surface-parity): every port's member list — and every
6
+ * INTENTIONAL asymmetry, with its justification — lives in the shared
7
+ * fixture `tests/parity-fixtures/port-surface-parity.json`, enforced by
8
+ * `tests/port-surface-parity.test.ts` (via the keyof-bound PORT_SURFACE
9
+ * manifest in `./port-surface.ts`) and by the Python twin
10
+ * `packages/sdk-py/tests/test_port_surface_parity.py` (real Protocol
11
+ * introspection). Adding/removing a member on either side without updating
12
+ * the fixture turns the suites red.
13
+ */
14
+ import type { BundleHandle } from "./bundle-handle.js";
15
+ import type { Document } from "./document.js";
16
+ import type { PreviewBlock } from "./preview.js";
17
+ import type { HookContext, HookNameArg, HookRegistry, VetoHandler } from "./hooks.js";
18
+ import type { CompositionProfile } from "./composition-resolver.js";
19
+ export type { BundleHandle };
20
+ export declare const LayerPolicy: {
21
+ readonly OPEN: "open";
22
+ readonly RESTRICTED: "restricted";
23
+ readonly LOCKED: "locked";
24
+ };
25
+ export type LayerPolicy = (typeof LayerPolicy)[keyof typeof LayerPolicy];
26
+ /**
27
+ * Whether a Kind's documents belong to a tenant or are globally shared.
28
+ *
29
+ * Mirrors the Kubernetes CRD `scope: Namespaced | Cluster` model. Each
30
+ * KindPort declares its scope; the kernel enforces it on every write.
31
+ *
32
+ * - `TENANTED` (default): documents belong to one tenant. Writing
33
+ * requires a tenant arg; reading is filtered by tenant.
34
+ * Agent, EvalCase, EvalRun, AssessmentRun, Finding, etc.
35
+ * - `GLOBAL`: documents are shared across all tenants. Writes must
36
+ * not pass a tenant; reads ignore the bound tenant.
37
+ * Doc, KindDefinition, Module-level configs, etc.
38
+ */
39
+ export declare const TenantScope: {
40
+ readonly TENANTED: "tenanted";
41
+ readonly GLOBAL: "global";
42
+ };
43
+ export type TenantScope = (typeof TenantScope)[keyof typeof TenantScope];
44
+ /** Reserved tenant slugs — never accepted as user input. */
45
+ export declare const RESERVED_TENANT_SLUGS: Set<string>;
46
+ /**
47
+ * Raised when a TENANTED kind is written without a tenant arg.
48
+ *
49
+ * Bind a tenant on construction (`new Kernel({ tenant: X })`) or
50
+ * per-call (`kernel.withTenant(X).writeDocument(...)`).
51
+ */
52
+ export declare class TenantRequired extends Error {
53
+ constructor(message?: string);
54
+ }
55
+ /**
56
+ * Raised when a GLOBAL kind is written with a tenant arg.
57
+ *
58
+ * Global kinds (Doc, KindDefinition, ...) are shared across
59
+ * tenants. Writes must explicitly omit `tenant`.
60
+ */
61
+ export declare class TenantNotAllowed extends Error {
62
+ constructor(message?: string);
63
+ }
64
+ /**
65
+ * Raised when `writeDocument` vetoes a doc whose `spec` violates the Kind's
66
+ * declared JSON Schema (`KindPort.schema()`).
67
+ *
68
+ * s-write-path-validation (i-008): the kernel used to validate schemas only
69
+ * at SCAN/read (the fail-soft `parse_error` channel) — a shape-broken doc
70
+ * would persist and explode later, far from the author. Now every
71
+ * `writeDocument` validates the spec at write time when the Kind declares a
72
+ * schema; Kinds without a schema stay permissive.
73
+ * Mode knob: `DNA_WRITE_VALIDATION=enforce|warn|off`.
74
+ */
75
+ export declare class SpecValidationError extends Error {
76
+ constructor(message?: string);
77
+ }
78
+ /** Raised when a tenant slug is reserved or empty. */
79
+ export declare class InvalidTenantSlug extends Error {
80
+ constructor(message?: string);
81
+ }
82
+ /**
83
+ * Validate a tenant slug.
84
+ *
85
+ * Phase 1 only checks the reserved set + non-empty/length. Character
86
+ * rules (DNS-label, lowercase) are NOT enforced at the kernel boundary
87
+ * so existing tests/data using uppercase ("T1", "Acme") keep working.
88
+ * Path-traversal safety lives in the adapter.
89
+ *
90
+ * Phase 2 may tighten to k8s namespace rules (`[a-z0-9-]{1,63}`) once
91
+ * the migration is complete.
92
+ */
93
+ export declare function validateTenantSlug(tenant: string | null | undefined): void;
94
+ /**
95
+ * Raised when a write to a layer violates the declared LayerPolicy in
96
+ * `Module.spec.layers`. Thrown by `Kernel.writeDocument` before the adapter
97
+ * is touched. Harness endpoints translate to HTTP 403.
98
+ */
99
+ export declare class LayerPolicyViolationError extends Error {
100
+ constructor(message: string);
101
+ }
102
+ export interface CompositionResult {
103
+ resolved: string[];
104
+ missing: string[];
105
+ warnings: string[];
106
+ /**
107
+ * Refs whose target Kind is plane="record" (two-planes F2.5, spec D6).
108
+ * Records are excluded from the MI materialization on the Py side, so
109
+ * the engine can't check them against the doc index — they resolve
110
+ * lazily via the kernel record plane at read time. Deferred refs are
111
+ * NOT missing: `isCompositionValid` ignores them.
112
+ */
113
+ deferred: string[];
114
+ }
115
+ export declare function isCompositionValid(result: CompositionResult): boolean;
116
+ export interface CacheItem {
117
+ name: string;
118
+ kind: string;
119
+ contentPath: string;
120
+ raw?: Record<string, unknown>;
121
+ }
122
+ export interface ResolvedItem {
123
+ name: string;
124
+ kind: string;
125
+ sourcePath: string;
126
+ }
127
+ /**
128
+ * Filter shape — dict of dotted `field_path` → expected value.
129
+ *
130
+ * { "status": "in-progress" } // shorthand equality
131
+ * { "status": { "in": ["todo", "done"] } } // operator form
132
+ * { "spec.priority": { "gte": 2 } }
133
+ *
134
+ * Unprefixed paths resolve under `spec.`; `name` is a reserved short for
135
+ * `metadata.name`. Implicit AND across keys; no OR (issue two queries).
136
+ */
137
+ export type QueryFilter = Record<string, unknown>;
138
+ /**
139
+ * Ordering — list of field paths optionally prefixed with `-` for
140
+ * descending. Applied in declaration order. `null`/missing values sort
141
+ * LAST regardless of direction (parity with PG `DESC NULLS LAST`; the Py
142
+ * side was fixed in i-121 — TS is born correct).
143
+ */
144
+ export type QueryOrder = string[];
145
+ /** Shape returned by `count()` — groups ordered by count DESC, then key
146
+ * ASC with `null` last. `groups` is `null` when no `groupBy` was asked. */
147
+ export interface CountResult {
148
+ total: number;
149
+ groups: Array<{
150
+ key: unknown;
151
+ count: number;
152
+ }> | null;
153
+ }
154
+ /**
155
+ * Raised when a query filter / order_by is malformed in a way the
156
+ * adapter can detect statically (unknown operator, …). 1:1 with the Py
157
+ * `QueryError`.
158
+ */
159
+ export declare class QueryError extends Error {
160
+ constructor(message?: string);
161
+ }
162
+ /** Operators recognized by `matchFilter` — the Py `_PG_OP_MAP` set + `in`. */
163
+ export declare const QUERY_OPS: ReadonlySet<string>;
164
+ /**
165
+ * Walk a dotted `fieldPath` through `doc`. Unprefixed paths resolve under
166
+ * `spec.`; `name` is a reserved short for `metadata.name`. Returns `null`
167
+ * when any segment is missing (never `undefined` — parity with Py `None`).
168
+ */
169
+ export declare function resolveFieldPath(doc: Record<string, unknown>, path: string): unknown;
170
+ /**
171
+ * Evaluate a `QueryFilter` against a single doc. Unknown operators throw
172
+ * `QueryError` so callers can debug instead of silently matching. 1:1
173
+ * port of the Py `_match_filter` (only single-key dicts enter the
174
+ * operator branch; anything else is shorthand equality).
175
+ */
176
+ export declare function matchFilter(doc: Record<string, unknown>, filter: QueryFilter): boolean;
177
+ /**
178
+ * Stable sort `rows` by each `orderBy` field, last-first to achieve the
179
+ * desired primary/secondary precedence. Prefixed `-` means descending.
180
+ * `null` values sort LAST regardless of direction: the None-flag is
181
+ * `(v === null) !== descending` — immune to the reversed comparator
182
+ * (i-121: parity with PG `DESC NULLS LAST`; a plain `v === null` flag
183
+ * would flip under reversal and shove nulls to the FRONT in DESC).
184
+ *
185
+ * Mixed-type values (number + string across rows on the same field) fall
186
+ * back to stringified compare to mirror the Py TypeError fallback. Does
187
+ * not mutate the input. Best-effort like the Py protocol-default —
188
+ * adapters with native push-down use the backend's type semantics.
189
+ */
190
+ export declare function applyOrderBy(rows: Record<string, unknown>[], orderBy: QueryOrder): Record<string, unknown>[];
191
+ /** Options accepted by the query half of the record-plane port (TS).
192
+ * NOTE: no `projection` on the TS surface — Py-only for now. */
193
+ export interface SourceQueryOpts {
194
+ filter?: QueryFilter;
195
+ limit?: number;
196
+ offset?: number;
197
+ orderBy?: QueryOrder;
198
+ tenant?: string;
199
+ }
200
+ /** Options accepted by the count half of the record-plane port (TS). */
201
+ export interface SourceCountOpts {
202
+ filter?: QueryFilter;
203
+ groupBy?: string;
204
+ tenant?: string;
205
+ }
206
+ /**
207
+ * In-memory query core — mirror of the Py `SourcePort.query`
208
+ * protocol-default minus the IO: kind filter first (cheap), then
209
+ * `matchFilter`, then `applyOrderBy`, then limit/offset paging.
210
+ * `FilesystemSource.query` is `loadAll` + this; the shared parity
211
+ * fixture drives it directly.
212
+ */
213
+ export declare function queryDocs(docs: Record<string, unknown>[], kind: string, opts?: Omit<SourceQueryOpts, "tenant">): Record<string, unknown>[];
214
+ /**
215
+ * In-memory count core — mirror of the Py `SourcePort.count`
216
+ * protocol-default: total of docs matching the filter, optionally
217
+ * grouped by a field path. Groups ordered by count DESC, then key ASC
218
+ * with `null` LAST (matches PG `ORDER BY count DESC, key ASC NULLS
219
+ * LAST` and the spirit of i-121).
220
+ */
221
+ export declare function countDocs(docs: Record<string, unknown>[], kind: string, opts?: Omit<SourceCountOpts, "tenant">): CountResult;
222
+ /**
223
+ * Two-planes F2 (spec D2): semantic search over record docs. The PG
224
+ * adapter (pgvector+RRF) lives in harness-shared (Py) and registers
225
+ * itself on the kernel at app boot — the kernel core gains NO
226
+ * LLM/embedding deps. Without a provider, `kernel.search()` degrades to
227
+ * an in-memory lexical scan (explicit `degraded: true` — never fake
228
+ * similarity). 1:1 with the Py `RecordSearchProvider` Protocol.
229
+ *
230
+ * Hit shape: the guaranteed intersection across providers and the
231
+ * lexical fallback is `{scope, kind, name, score}` — richer providers
232
+ * may carry extra fields that callers must treat as optional.
233
+ */
234
+ export interface RecordSearchProvider {
235
+ search(opts: {
236
+ scope: string;
237
+ queryText: string;
238
+ kind?: string | null;
239
+ k?: number;
240
+ tenant?: string;
241
+ }): Promise<Array<Record<string, unknown>>>;
242
+ }
243
+ /**
244
+ * Sibling port to `RecordSearchProvider` (rsh-memory-similarity-evolution →
245
+ * rec-embedding-port): turn text into dense vectors so the search plane can do
246
+ * real similarity instead of the lexical fallback. The kernel core gains NO ML
247
+ * deps — a real provider (ONNX all-MiniLM-L6-v2 via `@huggingface/transformers`,
248
+ * an optional peer dep) registers itself on the kernel at app boot; when none
249
+ * is registered, `kernel.embed()` uses the deterministic hash-based
250
+ * `FakeEmbeddingProvider` (the zero-dep offline floor that runs in CI).
251
+ *
252
+ * Parity: the FAKE is bit-exact Py↔TS by construction (integer feature-hashing
253
+ * + IEEE-754 ops — see `src/kernel/embedding.ts`); a real ONNX provider is
254
+ * parity-by-artifact (same model id, cosine ≈ 1). 1:1 with the Py
255
+ * `EmbeddingPort` Protocol.
256
+ *
257
+ * Contract:
258
+ * - `embed(texts)` returns one vector per input text, each of length `dims`,
259
+ * in input order. Empty input → empty array.
260
+ * - `dims` is the fixed output dimensionality (same for every vector).
261
+ * - `modelId` identifies the embedding space; vectors from providers with
262
+ * different `modelId` are NOT comparable.
263
+ */
264
+ export interface EmbeddingPort {
265
+ readonly modelId: string;
266
+ readonly dims: number;
267
+ embed(texts: string[]): Promise<number[][]>;
268
+ }
269
+ /**
270
+ * @deprecated s-sourceport-contract-cleanup — the record-plane contract was
271
+ * UNIFIED into `WritableSourcePort` (+ the `query`/`count` read half declared
272
+ * on `SourcePort`). This alias preserves the old name for existing importers;
273
+ * its shape is exactly the four ops the F2 D2 port formalized:
274
+ * `saveDocument`/`deleteDocument` (write half) + non-optional `query`/`count`
275
+ * (read half). The fifth record-plane operation, `search`, still lives on
276
+ * `RecordSearchProvider` registered on the kernel. New code should reference
277
+ * `WritableSourcePort` / `SourcePort` directly.
278
+ */
279
+ export type RecordStorePort = Pick<WritableSourcePort, "saveDocument" | "deleteDocument"> & Required<Pick<SourcePort, "query" | "count">>;
280
+ export declare class ResolveError extends Error {
281
+ constructor(message?: string);
282
+ }
283
+ export declare class ResolveNotFoundError extends ResolveError {
284
+ constructor(message?: string);
285
+ }
286
+ export declare class ResolveAuthError extends ResolveError {
287
+ constructor(message?: string);
288
+ }
289
+ export declare class ResolveNetworkError extends ResolveError {
290
+ constructor(message?: string);
291
+ }
292
+ export type StoragePattern = "bundle" | "yaml" | "root" | "standalone";
293
+ export type BodyMode = "text" | "list" | "sections";
294
+ export interface StorageDescriptor {
295
+ container: string;
296
+ pattern: StoragePattern;
297
+ marker?: string;
298
+ bodyAs?: BodyMode;
299
+ bodyField?: string;
300
+ bodyParser?: (body: string) => Record<string, unknown>;
301
+ }
302
+ export declare const SD: {
303
+ bundle(container: string, marker: string, bodyAs?: BodyMode, bodyField?: string): StorageDescriptor;
304
+ yaml(container: string): StorageDescriptor;
305
+ root(filename?: string): StorageDescriptor;
306
+ standalone(filename: string, bodyAs?: BodyMode, bodyField?: string): StorageDescriptor;
307
+ };
308
+ export declare function defaultVisibleInBackend(storage: StorageDescriptor | null | undefined): boolean;
309
+ export declare function resolveVisibleInBackend(kp: KindPort): boolean;
310
+ /** WHERE — load documents from storage.
311
+ *
312
+ * v1.0 async refactor: read methods return `Promise<...>` so adapters
313
+ * with non-local backends (Postgres, HTTP, S3) can implement them
314
+ * naturally. Filesystem adapter wraps sync impls in `Promise.resolve`
315
+ * for back-compat.
316
+ */
317
+ export interface SourcePort {
318
+ readonly supportsReaders: boolean;
319
+ /**
320
+ * Phase 16 — return the docs the kernel needs registered/parsed
321
+ * BEFORE ``loadAll`` fires (Genome + KindDefinition + LayerPolicy).
322
+ * Adapters that can filter cheaply (SQL ``WHERE kind IN (...)``)
323
+ * SHOULD do so. Filesystem adapters MAY return a superset.
324
+ *
325
+ * Tenant semantics: when ``opts.tenant`` is set, the tenant-published
326
+ * Genome shadows the platform Genome (Phase 9 multi-tenant
327
+ * publishing). KindDefinition + LayerPolicy stay platform-only
328
+ * (non-overlayable per Phase 16).
329
+ *
330
+ * 1:1 parity with Python ``SourcePort.load_bootstrap_docs``.
331
+ */
332
+ loadBootstrapDocs(scope: string, opts?: {
333
+ tenant?: string;
334
+ }): Promise<Record<string, unknown>[]>;
335
+ loadAll(scope: string, readers?: ReaderPort[]): Promise<Record<string, unknown>[]>;
336
+ resolveRef(scope: string, ref: string): Promise<string>;
337
+ loadLayer(scope: string, layerId: string, layerValue: string, readers?: ReaderPort[]): Promise<Record<string, unknown>[]>;
338
+ /**
339
+ * Release adapter-held resources (connection pools, file handles, …).
340
+ * Mirror of the Py `SourcePort.close` (a SOURCE_PORT_CORE_MEMBERS entry
341
+ * behind the Py boot gate). OPTIONAL on the TS interface — the kernel
342
+ * treats a missing `close` as a no-op: `FilesystemSource` implements a
343
+ * documented no-op (nothing to release), `PostgresSource` ends its
344
+ * owned pool.
345
+ */
346
+ close?(): Promise<void>;
347
+ /**
348
+ * OPTIONAL L1 granular access — `[kind, name]` refs of every doc in
349
+ * the scope, metadata only (no bundle entries, no parse). Mirror of
350
+ * the Py `SourcePort.list_doc_refs`. `opts.kind` filters; tenant is
351
+ * the union of base + overlay with the overlay shadowing base.
352
+ * Declared via `SourceCapabilities.granularList`
353
+ * (s-dna-port-surface-parity closed this TS gap).
354
+ */
355
+ listDocRefs?(scope: string, opts?: {
356
+ kind?: string | null;
357
+ tenant?: string | null;
358
+ }): Promise<Array<[string, string]>>;
359
+ /**
360
+ * Two-planes F2 — OPTIONAL record-plane reads. The Kernel consults the
361
+ * declared capabilities (`sourceCapabilities(src).queryPushdown`,
362
+ * s-sourceport-contract-cleanup) and raises a clear capability error
363
+ * otherwise. `FilesystemSource` implements both over `loadAll` + the
364
+ * pure helpers (`queryDocs`/`countDocs`); PG TS gets no push-down this
365
+ * phase (Py-only).
366
+ */
367
+ query?(scope: string, kind: string, opts?: SourceQueryOpts): AsyncIterable<Record<string, unknown>>;
368
+ count?(scope: string, kind: string, opts?: SourceCountOpts): Promise<CountResult>;
369
+ /**
370
+ * OPTIONAL L1 granular access — one raw doc for (scope, kind, name),
371
+ * tenant overlay shadowing base (mirror of the Py `SourcePort.load_one`).
372
+ * The Kernel consults `sourceCapabilities(src).granularOne`
373
+ * (s-sourceport-contract-cleanup) and falls back to `loadAll` + find
374
+ * (base layer only) when absent — same as the Python
375
+ * `_granular_doc_cached` legacy-adapter fallback.
376
+ */
377
+ loadOne?(scope: string, kind: string, name: string, opts?: {
378
+ readers?: ReaderPort[];
379
+ tenant?: string | null;
380
+ }): Promise<Record<string, unknown> | null>;
381
+ /**
382
+ * OPTIONAL explicit capability declaration (s-sourceport-contract-cleanup)
383
+ * — a literal `SourceCapabilities` from `kernel/capabilities.ts`. When
384
+ * absent, `sourceCapabilities()` derives structurally (deprecated path).
385
+ * Optional so existing third-party implementers stay source-compatible.
386
+ */
387
+ capabilities?(): import("./capabilities.js").SourceCapabilities;
388
+ }
389
+ /**
390
+ * Phase 16 — Kinds the kernel needs registered/parsed BEFORE
391
+ * ``loadAll`` fires. Order is meaningful: KindDefinition first
392
+ * (custom Kinds need to be registered before parsing other docs),
393
+ * LayerPolicy next (kernel reads at write-time), Genome last
394
+ * (root identity).
395
+ */
396
+ export declare const BOOTSTRAP_KIND_NAMES: readonly ["KindDefinition", "LayerPolicy", "Genome"];
397
+ /**
398
+ * Phase 16 helper — return the Genome doc for ``scope`` (or ``null``
399
+ * if missing). Pulls bootstrap docs and filters for the Genome Kind.
400
+ * Tenant-aware: when ``opts.tenant`` is set, the underlying adapter
401
+ * applies tenant-overlay routing (tenant-published Genome shadows
402
+ * platform).
403
+ *
404
+ * 1:1 parity with Python ``package_doc_for_scope``.
405
+ */
406
+ export declare function packageDocForScope(source: SourcePort, scope: string, opts?: {
407
+ tenant?: string;
408
+ }): Promise<Record<string, unknown> | null>;
409
+ /** WHERE — store/retrieve installed deps.
410
+ *
411
+ * v1.0: fully async. All four methods may do filesystem / network IO
412
+ * (FilesystemCache uses fs/promises; Redis/HTTP caches are inherently
413
+ * async). Hot path concerns about prompt-building are addressed by
414
+ * caching results in-memory at higher layers, not by sync IO. */
415
+ export interface CachePort {
416
+ has(scope: string, key: string): Promise<boolean>;
417
+ store(scope: string, key: string, items: CacheItem[]): Promise<void>;
418
+ loadKey(scope: string, key: string, readers?: ReaderPort[]): Promise<Record<string, unknown>[]>;
419
+ loadAll(scope: string, readers?: ReaderPort[]): Promise<Record<string, unknown>[]>;
420
+ }
421
+ /** FROM — fetch external deps. v1.0: async (network IO is inherently
422
+ * async; sync HTTP would block the event loop). */
423
+ export interface ResolverPort {
424
+ resolve(uri: string, dep: Record<string, unknown>): Promise<ResolvedItem[]>;
425
+ cacheKey(uri: string): string;
426
+ }
427
+ /** Reads a bundle directory and produces a raw dict.
428
+ *
429
+ * v1.0 BundleHandle migration: signatures take a `BundleHandle`
430
+ * instead of a filesystem path string, so adapters with non-FS
431
+ * backends (Postgres, in-memory) can rehydrate bundles uniformly.
432
+ *
433
+ * Methods are async because backends may need to fetch entries
434
+ * from a network/database. Filesystem readers can return
435
+ * `Promise.resolve(...)` if their existing impl is sync.
436
+ */
437
+ export interface ReaderPort {
438
+ detect(bundle: BundleHandle): boolean | Promise<boolean>;
439
+ read(bundle: BundleHandle): Record<string, unknown> | Promise<Record<string, unknown>>;
440
+ /** Container this Reader's Kind is rooted at (e.g. `"skills"`), or
441
+ * undefined for unscoped readers (tried as fallback in every
442
+ * container). Lets the scanner route bundles to the right Reader
443
+ * without trying every reader's `detect()` on every subdir — H3
444
+ * container-aware routing. Formal port member since
445
+ * s-dna-rw-roundtrip-suite (the scanner previously duck-typed it);
446
+ * Python twin: `ReaderPort._owner_container` (default None). */
447
+ readonly _ownerContainer?: string;
448
+ }
449
+ export interface SerializedFile {
450
+ relativePath: string;
451
+ /** Text content (UTF-8). Mutually exclusive with `contentBytes`. */
452
+ content?: string;
453
+ /** Binary content. Set when the entry is a non-text payload (PNG,
454
+ * audio, etc). Mutually exclusive with `content`. Introduced in L3
455
+ * (s-writer-binary-entries 2026-05-25) for parity with Python. */
456
+ contentBytes?: Uint8Array;
457
+ }
458
+ export interface SerializedDocument {
459
+ files: SerializedFile[];
460
+ }
461
+ export interface WritableSourcePort extends SourcePort {
462
+ /**
463
+ * Persist a raw document. Adapters decide their own serialization
464
+ * strategy (filesystem writes bundles, HTTP adapters POST raw JSON,
465
+ * DB adapters insert rows). Returns an opaque version id; adapters
466
+ * without real versioning return "1".
467
+ */
468
+ saveDocument(scope: string, kind: string, name: string, raw: Record<string, unknown>, options?: {
469
+ author?: string;
470
+ tenant?: string | null;
471
+ layer?: [string, string];
472
+ }): Promise<string>;
473
+ /**
474
+ * Delete a document. Adapters handle the mechanics (rm -rf for
475
+ * bundle filesystems, DELETE for HTTP, DELETE FROM for SQL, etc.).
476
+ */
477
+ deleteDocument(scope: string, kind: string, name: string, options?: {
478
+ author?: string;
479
+ tenant?: string | null;
480
+ layer?: [string, string];
481
+ }): Promise<void>;
482
+ /**
483
+ * Optional version history. Stub adapters return []; real adapters
484
+ * (Postgres, etc.) return { id: string }[] newest first.
485
+ */
486
+ listVersions?(scope: string, kind: string, name: string): Promise<Array<{
487
+ id: string;
488
+ }>>;
489
+ /**
490
+ * Optional single-version fetch (the `Versionable` capability;
491
+ * `PostgresSource` implements it). Mirror of the Py
492
+ * `WritableSourcePort.get_version`.
493
+ */
494
+ getVersion?(scope: string, kind: string, name: string, versionId: string): Promise<Record<string, unknown>>;
495
+ /**
496
+ * Optional draft→published promotion. Mirror of the Py
497
+ * `WritableSourcePort.publish`. The TS PG adapter is a documented
498
+ * single-step no-op (writes go live immediately; no draft state) —
499
+ * adapters with a real draft store return the published version id.
500
+ * The Py-only `save_manifest` / `load_drafts` / `list_scopes` half is
501
+ * a JUSTIFIED asymmetry — see
502
+ * tests/parity-fixtures/port-surface-parity.json.
503
+ */
504
+ publish?(scope: string, kind: string, name: string): Promise<string>;
505
+ }
506
+ /** Writes a raw dict back to a bundle directory. Inverse of ReaderPort.
507
+ *
508
+ * v1.0 BundleHandle migration: write signature takes BundleHandle
509
+ * (was: filesystem path string). Adapters provide the right handle
510
+ * for their backend; the writer's job is purely to format files into
511
+ * `bundle.writeText/writeBytes` calls.
512
+ *
513
+ * s-dna-rw-roundtrip-suite: `serialize` is REQUIRED — part of the
514
+ * contract (it was load-bearing but optional: `kernel.serializeDocument`
515
+ * consumed it behind a presence check, so a conforming writer could
516
+ * silently miss it and only fail at emission time). `write` and
517
+ * `serialize` must stay COHERENT: `write(bundle, raw)` must produce
518
+ * exactly the entries `serialize(raw)` returns. The round-trip
519
+ * conformance suite enforces this for every registered pair.
520
+ * Python twin: `WriterPort.serialize` returning
521
+ * `[{relativePath, content | content_bytes}]`.
522
+ */
523
+ export interface WriterPort {
524
+ canWrite(raw: Record<string, unknown>): boolean;
525
+ write(bundle: BundleHandle, raw: Record<string, unknown>): void | Promise<void>;
526
+ serialize(raw: Record<string, unknown>): SerializedFile[];
527
+ }
528
+ /**
529
+ * Optional presentation/UX capability of a Kind.
530
+ *
531
+ * Py twin: the `KindPresentation` capability Protocol in protocols.py —
532
+ * kept OFF Python's runtime_checkable `KindPort` so the H1 isinstance
533
+ * registration gate never requires these members on a minimal Kind
534
+ * (s-dna-kindport-descriptor-schema). TS interfaces express the same
535
+ * contract natively as optional members; `KindPort` extends this slice.
536
+ * The Py↔TS pairing is tracked in
537
+ * `tests/parity-fixtures/port-surface-parity.json` (KindPresentation port).
538
+ */
539
+ export interface KindPresentation {
540
+ /** Canonical prose documentation. May be overridden at load time by a DOCS.md file
541
+ * alongside the extension's source. Resolved prose is cached on `_resolvedDocs`. */
542
+ readonly docs?: string;
543
+ /** Spec field to derive metadata.description from when none was declared. */
544
+ readonly descriptionFallbackField?: string | null;
545
+ /** Per-field UI hints for Studio form rendering, keyed by spec field
546
+ * name (widget/label/help/language/height/order — see
547
+ * `docs/KIND-UI-HINTS.md`). When absent, consumers infer the widget
548
+ * from the value type. */
549
+ readonly uiSchema?: Record<string, Record<string, unknown>>;
550
+ /** Colors for mermaid diagrams, graph nodes, and other visualizations. */
551
+ readonly graphStyle?: {
552
+ fill: string;
553
+ stroke: string;
554
+ textColor: string;
555
+ };
556
+ /** Single emoji or character for ASCII tree / compact views. */
557
+ readonly asciiIcon?: string;
558
+ /** Human-friendly plural label (e.g. "Agents" for Agent). */
559
+ readonly displayLabel?: string;
560
+ /** Explicit backend-visibility override; unset/null falls back to
561
+ * `defaultVisibleInBackend(storage)` — see `resolveVisibleInBackend`. */
562
+ readonly visibleInBackend?: boolean | null;
563
+ /**
564
+ * Optional: returns renderable blocks for the Studio's preview pane.
565
+ * Each extension implements this for its own kinds. When undefined,
566
+ * the kernel falls back to `genericSpecDump` from preview.ts.
567
+ */
568
+ preview?(doc: Document): PreviewBlock[];
569
+ /** Per-doc annotations for graph rendering and health checks.
570
+ * e.g. Guardrail returns {severity, scope, rules}.
571
+ * Agent returns {model, soul, skills_count}. */
572
+ graphMeta?(doc: Document): Record<string, unknown> | null;
573
+ }
574
+ /** WHO — identity + composition role.
575
+ *
576
+ * Core contract + the optional `KindPresentation` slice. Python's twin
577
+ * keeps the two apart at runtime (`KindPort` runtime_checkable Protocol
578
+ * + `KindPresentation` typing-only capability); TS folds the optional
579
+ * slice in via `extends` — structural typing has no isinstance gate to
580
+ * protect. */
581
+ export interface KindPort extends KindPresentation {
582
+ readonly apiVersion: string;
583
+ readonly kind: string;
584
+ readonly alias: string;
585
+ readonly origin?: string;
586
+ /**
587
+ * Optional tenant scope declaration. When unset (Phase 1 default),
588
+ * the kernel treats the kind permissively (back-compat). Phase 2
589
+ * iterates through every Extension to set TENANTED or GLOBAL
590
+ * explicitly, flipping enforcement on per-Kind. See TenantScope.
591
+ */
592
+ readonly scope?: TenantScope;
593
+ readonly isRoot: boolean;
594
+ readonly isPromptTarget: boolean;
595
+ readonly promptTargetPriority: number;
596
+ readonly flattenInContext: boolean;
597
+ readonly storage: StorageDescriptor;
598
+ /**
599
+ * `true` for Kinds whose documents are produced by runtime workflows
600
+ * (eval engine, GAIA pipeline, autolab loop, evidence-capture hooks)
601
+ * rather than authored as source-of-truth. Tools that replicate "the
602
+ * inputs to the system" — filesystem→Postgres seed, catalog publish,
603
+ * manifest export — MUST skip Kinds where this is true so they don't
604
+ * re-inject historical execution data as canonical configuration.
605
+ * Default `false` (provided by KindBase) keeps existing extensions
606
+ * unchanged.
607
+ */
608
+ readonly isRuntimeArtifact: boolean;
609
+ readonly isSchemaAffecting?: boolean;
610
+ readonly isOverlayable?: boolean;
611
+ readonly scopeInheritable?: boolean;
612
+ readonly plane?: "record" | "composition";
613
+ depFilters(): Record<string, string> | null;
614
+ getDefaultAgentName(doc: Document): string | null;
615
+ getLayerPolicies(doc: Document): Record<string, LayerPolicy | string> | null;
616
+ parse(raw: Record<string, unknown>): unknown;
617
+ describe(doc: Document): string | null;
618
+ summary(doc: Document): Record<string, unknown> | null;
619
+ promptTemplate(): string | null;
620
+ /** JSON Schema for this kind's spec. Zod-based kinds convert their schema;
621
+ * declarative kinds return native JSON Schema. */
622
+ schema?(): Record<string, unknown> | null;
623
+ /** Which spec fields reference other kinds by alias.
624
+ * Clearer name for depFilters(). */
625
+ dependencies?(): Record<string, string> | null;
626
+ }
627
+ /**
628
+ * An invocable tool exposed to agents. This port carries the DNA discovery
629
+ * metadata (group, hitl, scope); the underlying callable stays framework-
630
+ * native and is never wrapped or serialized.
631
+ */
632
+ export interface ToolPort {
633
+ readonly name: string;
634
+ /** Tool group (cognitive | manifest | code | docs | web | write | eval |
635
+ * eval_lab | …). `null` = registered but not group-filterable (rare). */
636
+ readonly group: string | null;
637
+ /** Full docstring / long description. */
638
+ readonly description: string;
639
+ /** First paragraph of the description. */
640
+ readonly summary: string;
641
+ /** JSON Schema of the tool's arguments (best-effort; may be `{}`). */
642
+ readonly argsSchema: Record<string, unknown>;
643
+ /** Write tool that needs a HumanInTheLoop interrupt at the root graph. */
644
+ readonly hitl: boolean;
645
+ /** Layer-policy hint — "tenant" respects tenant overlay, "global"
646
+ * doesn't. Reserved for future use. */
647
+ readonly scope: string | null;
648
+ /** Module file name that defined the tool (best-effort). */
649
+ readonly source: string;
650
+ /** Return the underlying invocable (framework-native tool or function). */
651
+ getCallable(): unknown;
652
+ }
653
+ /**
654
+ * Concrete ToolPort implementation, stored in the kernel's ToolRegistry.
655
+ * Twin of the Py `ToolDefinition` dataclass — the `callable` init field
656
+ * holds the framework-native invocable; `getCallable()` is the canonical
657
+ * accessor (never serialize or wrap-replace it).
658
+ */
659
+ export declare class ToolDefinition implements ToolPort {
660
+ readonly name: string;
661
+ readonly group: string | null;
662
+ readonly description: string;
663
+ readonly summary: string;
664
+ readonly argsSchema: Record<string, unknown>;
665
+ readonly hitl: boolean;
666
+ readonly scope: string | null;
667
+ readonly source: string;
668
+ private readonly _callable;
669
+ constructor(init: {
670
+ name: string;
671
+ group?: string | null;
672
+ description?: string;
673
+ summary?: string;
674
+ argsSchema?: Record<string, unknown>;
675
+ hitl?: boolean;
676
+ scope?: string | null;
677
+ source?: string;
678
+ callable?: unknown;
679
+ });
680
+ getCallable(): unknown;
681
+ }
682
+ /**
683
+ * The registration-time surface the Kernel offers to `Extension.register()`.
684
+ *
685
+ * This is the *explicit contract* of what an extension may call while it is
686
+ * being loaded (s-dna-extension-host-contract). It is a narrow slice of the
687
+ * Kernel — the registration vocabulary — NOT the whole Kernel API. Derived
688
+ * from actual usage across every builtin extension:
689
+ *
690
+ * - `kind(kp)` — register a KindPort (identity + composition)
691
+ * - `kindFromDescriptor()` — register a record Kind from a
692
+ * `kinds/*.kind.yaml` descriptor (F3 — Kinds as
693
+ * data). Pair with `loadDescriptors()` from
694
+ * `./descriptor-loader.js`.
695
+ * - `reader(r)` — register a ReaderPort (detect/scan a format)
696
+ * - `writer(w)` — register a WriterPort (write a format)
697
+ * - `on(hook, fn)` — subscribe to an event (e.g. `post_save`)
698
+ * - `onVeto(hook, fn)` — register a veto listener (e.g. `pre_save`
699
+ * write guards — throwing vetoes the operation)
700
+ * - `tool(td)` — register a ToolDefinition (DNA tool discovery
701
+ * metadata; queried via `kernel.getTools()`)
702
+ * - `compositionProfile()` — register orchestrator kind wiring
703
+ * - `hooks` — the HookRegistry itself, for advanced listener
704
+ * management (`kernel.hooks.onVeto(..., {key})`)
705
+ *
706
+ * The real `Kernel` satisfies this interface structurally (statically
707
+ * asserted in `tests/extension-host-contract.test.ts`). Py twin:
708
+ * `ExtensionHost` in `dna/kernel/protocols.py`.
709
+ */
710
+ export interface ExtensionHost {
711
+ /** The HookRegistry the `on`/`onVeto` conveniences delegate to. */
712
+ readonly hooks: HookRegistry;
713
+ kind(kp: KindPort): void;
714
+ kindFromDescriptor(raw: Record<string, unknown>): KindPort;
715
+ reader(r: ReaderPort): void;
716
+ writer(w: WriterPort): void;
717
+ on(hook: HookNameArg, fn: (ctx: HookContext) => void): void;
718
+ onVeto(hook: HookNameArg, fn: VetoHandler, opts?: {
719
+ priority?: number;
720
+ key?: string;
721
+ }): void;
722
+ tool(td: ToolDefinition): void;
723
+ compositionProfile(profile: CompositionProfile): void;
724
+ }
725
+ /**
726
+ * Registers kinds, readers, and writers on the Kernel.
727
+ *
728
+ * The `templates?()` method is INTENTIONALLY OPTIONAL so extensions that
729
+ * predate Phase 0 (i.e. shipped before the Template contract existed)
730
+ * keep satisfying the `Extension` contract without modification. When
731
+ * present, `Kernel.listTemplates()` aggregates entries from every loaded
732
+ * extension so UIs (Tauri Studio, CLI) can offer `scaffold()` for any
733
+ * extension-shipped file tree. See `./templates.ts` for the payload
734
+ * shape.
735
+ */
736
+ export interface Extension {
737
+ readonly name: string;
738
+ readonly version: string;
739
+ /**
740
+ * Wire the extension into the kernel. `kernel.load(ext)` fail-loud
741
+ * validates the whole contract first (`name` non-empty string,
742
+ * `version` string, `register` callable → `ExtensionLoadError`
743
+ * otherwise), then calls `register()` with the registration-time
744
+ * host slice — see {@link ExtensionHost} for the exact vocabulary.
745
+ */
746
+ register(kernel: ExtensionHost): void;
747
+ /** Optional — return the file-tree scaffolds this extension ships. */
748
+ templates?(): Template[];
749
+ }
750
+ export type { Template, OnConflict, MaterializeOptions, } from "./templates.js";
751
+ import type { Template } from "./templates.js";