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.
- package/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/adapters/embedding/onnx.d.ts +32 -0
- package/dist/adapters/embedding/onnx.js +51 -0
- package/dist/adapters/filesystem/cache.d.ts +16 -0
- package/dist/adapters/filesystem/cache.js +113 -0
- package/dist/adapters/filesystem/index.d.ts +2 -0
- package/dist/adapters/filesystem/index.js +2 -0
- package/dist/adapters/filesystem/source.d.ts +82 -0
- package/dist/adapters/filesystem/source.js +357 -0
- package/dist/adapters/postgres/index.d.ts +2 -0
- package/dist/adapters/postgres/index.js +2 -0
- package/dist/adapters/postgres/migrations.d.ts +14 -0
- package/dist/adapters/postgres/migrations.js +88 -0
- package/dist/adapters/postgres/source.d.ts +172 -0
- package/dist/adapters/postgres/source.js +569 -0
- package/dist/adapters/resolvers/github.d.ts +12 -0
- package/dist/adapters/resolvers/github.js +47 -0
- package/dist/adapters/resolvers/http.d.ts +22 -0
- package/dist/adapters/resolvers/http.js +145 -0
- package/dist/adapters/resolvers/index.d.ts +3 -0
- package/dist/adapters/resolvers/index.js +3 -0
- package/dist/adapters/resolvers/local.d.ts +24 -0
- package/dist/adapters/resolvers/local.js +132 -0
- package/dist/adapters/search/driver.d.ts +45 -0
- package/dist/adapters/search/driver.js +138 -0
- package/dist/adapters/search/migrations.d.ts +26 -0
- package/dist/adapters/search/migrations.js +58 -0
- package/dist/adapters/search/rrf.d.ts +23 -0
- package/dist/adapters/search/rrf.js +42 -0
- package/dist/adapters/search/sqlite-vec.d.ts +66 -0
- package/dist/adapters/search/sqlite-vec.js +294 -0
- package/dist/bootstrap.d.ts +45 -0
- package/dist/bootstrap.js +134 -0
- package/dist/extensions/agentskills/DOCS.md +18 -0
- package/dist/extensions/agentskills.d.ts +28 -0
- package/dist/extensions/agentskills.js +252 -0
- package/dist/extensions/agentsmd/DOCS.md +18 -0
- package/dist/extensions/agentsmd.d.ts +22 -0
- package/dist/extensions/agentsmd.js +170 -0
- package/dist/extensions/audit/kinds/audit-log.kind.yaml +148 -0
- package/dist/extensions/audit.d.ts +25 -0
- package/dist/extensions/audit.js +62 -0
- package/dist/extensions/automation/kinds/automation.kind.yaml +296 -0
- package/dist/extensions/automation/query.d.ts +49 -0
- package/dist/extensions/automation/query.js +77 -0
- package/dist/extensions/automation/write-guards.d.ts +59 -0
- package/dist/extensions/automation/write-guards.js +153 -0
- package/dist/extensions/automation.d.ts +41 -0
- package/dist/extensions/automation.js +54 -0
- package/dist/extensions/collab.d.ts +16 -0
- package/dist/extensions/collab.js +79 -0
- package/dist/extensions/doc/kinds/doc.kind.yaml +118 -0
- package/dist/extensions/doc.d.ts +25 -0
- package/dist/extensions/doc.js +10 -0
- package/dist/extensions/eval/kinds/eval-baseline.kind.yaml +65 -0
- package/dist/extensions/eval/kinds/eval-case.kind.yaml +140 -0
- package/dist/extensions/eval/kinds/eval-run.kind.yaml +134 -0
- package/dist/extensions/eval/kinds/eval-suite.kind.yaml +87 -0
- package/dist/extensions/eval.d.ts +24 -0
- package/dist/extensions/eval.js +31 -0
- package/dist/extensions/evidence/kinds/evidence.kind.yaml +92 -0
- package/dist/extensions/evidence.d.ts +17 -0
- package/dist/extensions/evidence.js +94 -0
- package/dist/extensions/federation.d.ts +22 -0
- package/dist/extensions/federation.js +173 -0
- package/dist/extensions/guardrails/DOCS.md +20 -0
- package/dist/extensions/guardrails.d.ts +31 -0
- package/dist/extensions/guardrails.js +228 -0
- package/dist/extensions/helix/DOCS-Actor.md +20 -0
- package/dist/extensions/helix/DOCS-Agent.md +20 -0
- package/dist/extensions/helix/DOCS-UseCase.md +20 -0
- package/dist/extensions/helix/layers.d.ts +12 -0
- package/dist/extensions/helix/layers.js +18 -0
- package/dist/extensions/helix/write-guards.d.ts +70 -0
- package/dist/extensions/helix/write-guards.js +172 -0
- package/dist/extensions/helix.d.ts +29 -0
- package/dist/extensions/helix.js +963 -0
- package/dist/extensions/helix_extras.d.ts +124 -0
- package/dist/extensions/helix_extras.js +328 -0
- package/dist/extensions/hooks.d.ts +31 -0
- package/dist/extensions/hooks.js +247 -0
- package/dist/extensions/kinddef/DOCS.md +24 -0
- package/dist/extensions/kinddef.d.ts +40 -0
- package/dist/extensions/kinddef.js +171 -0
- package/dist/extensions/lesson.d.ts +6 -0
- package/dist/extensions/lesson.js +194 -0
- package/dist/extensions/modelreg/kinds/model-profile.kind.yaml +155 -0
- package/dist/extensions/modelreg.d.ts +30 -0
- package/dist/extensions/modelreg.js +38 -0
- package/dist/extensions/recognizer.d.ts +34 -0
- package/dist/extensions/recognizer.js +272 -0
- package/dist/extensions/research.d.ts +32 -0
- package/dist/extensions/research.js +292 -0
- package/dist/extensions/safety.d.ts +33 -0
- package/dist/extensions/safety.js +230 -0
- package/dist/extensions/sdlc/kinds/adr.kind.yaml +136 -0
- package/dist/extensions/sdlc/kinds/archive-proposal.kind.yaml +107 -0
- package/dist/extensions/sdlc/kinds/changelog.kind.yaml +108 -0
- package/dist/extensions/sdlc/kinds/cognitive-policy.kind.yaml +470 -0
- package/dist/extensions/sdlc/kinds/forecast.kind.yaml +125 -0
- package/dist/extensions/sdlc/kinds/insight.kind.yaml +87 -0
- package/dist/extensions/sdlc/kinds/kaizen.kind.yaml +106 -0
- package/dist/extensions/sdlc/kinds/lesson-learned.kind.yaml +270 -0
- package/dist/extensions/sdlc/kinds/narrative.kind.yaml +189 -0
- package/dist/extensions/sdlc/kinds/pattern-insight.kind.yaml +204 -0
- package/dist/extensions/sdlc/kinds/postmortem.kind.yaml +168 -0
- package/dist/extensions/sdlc/kinds/pre-mortem.kind.yaml +145 -0
- package/dist/extensions/sdlc/kinds/prompt-template.kind.yaml +109 -0
- package/dist/extensions/sdlc/kinds/retrospective.kind.yaml +186 -0
- package/dist/extensions/sdlc/kinds/risk-register.kind.yaml +178 -0
- package/dist/extensions/sdlc/kinds/saved-view.kind.yaml +127 -0
- package/dist/extensions/sdlc/kinds/status-report.kind.yaml +129 -0
- package/dist/extensions/sdlc/kinds/synthesis-run.kind.yaml +279 -0
- package/dist/extensions/sdlc/kinds/synthesizer-state.kind.yaml +196 -0
- package/dist/extensions/sdlc/kinds/workflow-event.kind.yaml +195 -0
- package/dist/extensions/sdlc.d.ts +32 -0
- package/dist/extensions/sdlc.js +1318 -0
- package/dist/extensions/soulspec/DOCS.md +19 -0
- package/dist/extensions/soulspec.d.ts +22 -0
- package/dist/extensions/soulspec.js +287 -0
- package/dist/extensions/tenant.d.ts +6 -0
- package/dist/extensions/tenant.js +291 -0
- package/dist/extensions/testkit.d.ts +24 -0
- package/dist/extensions/testkit.js +211 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +102 -0
- package/dist/kernel/_text.d.ts +28 -0
- package/dist/kernel/_text.js +42 -0
- package/dist/kernel/bundle-handle.d.ts +83 -0
- package/dist/kernel/bundle-handle.js +184 -0
- package/dist/kernel/capabilities.d.ts +157 -0
- package/dist/kernel/capabilities.js +109 -0
- package/dist/kernel/collaborator-ports.d.ts +91 -0
- package/dist/kernel/collaborator-ports.js +1 -0
- package/dist/kernel/composition-resolver.d.ts +215 -0
- package/dist/kernel/composition-resolver.js +558 -0
- package/dist/kernel/composition.d.ts +10 -0
- package/dist/kernel/composition.js +1 -0
- package/dist/kernel/descriptor-loader.d.ts +13 -0
- package/dist/kernel/descriptor-loader.js +48 -0
- package/dist/kernel/document.d.ts +43 -0
- package/dist/kernel/document.js +71 -0
- package/dist/kernel/embedding.d.ts +28 -0
- package/dist/kernel/embedding.js +78 -0
- package/dist/kernel/errors.d.ts +62 -0
- package/dist/kernel/errors.js +82 -0
- package/dist/kernel/events.d.ts +6 -0
- package/dist/kernel/events.js +21 -0
- package/dist/kernel/evidence-capture.d.ts +69 -0
- package/dist/kernel/evidence-capture.js +138 -0
- package/dist/kernel/fs.d.ts +20 -0
- package/dist/kernel/fs.js +128 -0
- package/dist/kernel/generic-rw.d.ts +33 -0
- package/dist/kernel/generic-rw.js +235 -0
- package/dist/kernel/hooks.d.ts +172 -0
- package/dist/kernel/hooks.js +256 -0
- package/dist/kernel/index.d.ts +624 -0
- package/dist/kernel/index.js +1638 -0
- package/dist/kernel/instance.d.ts +211 -0
- package/dist/kernel/instance.js +487 -0
- package/dist/kernel/kind-registry.d.ts +183 -0
- package/dist/kernel/kind-registry.js +710 -0
- package/dist/kernel/kind_base.d.ts +106 -0
- package/dist/kernel/kind_base.js +244 -0
- package/dist/kernel/layer-resolver.d.ts +48 -0
- package/dist/kernel/layer-resolver.js +284 -0
- package/dist/kernel/lock-manager.d.ts +21 -0
- package/dist/kernel/lock-manager.js +43 -0
- package/dist/kernel/lock.d.ts +38 -0
- package/dist/kernel/lock.js +115 -0
- package/dist/kernel/meta.d.ts +135 -0
- package/dist/kernel/meta.js +817 -0
- package/dist/kernel/models.d.ts +3089 -0
- package/dist/kernel/models.js +764 -0
- package/dist/kernel/navigator.d.ts +36 -0
- package/dist/kernel/navigator.js +132 -0
- package/dist/kernel/port-surface.d.ts +33 -0
- package/dist/kernel/port-surface.js +180 -0
- package/dist/kernel/preview.d.ts +60 -0
- package/dist/kernel/preview.js +54 -0
- package/dist/kernel/prompt-budget.d.ts +39 -0
- package/dist/kernel/prompt-budget.js +43 -0
- package/dist/kernel/prompt-builder.d.ts +25 -0
- package/dist/kernel/prompt-builder.js +237 -0
- package/dist/kernel/protocols.d.ts +751 -0
- package/dist/kernel/protocols.js +493 -0
- package/dist/kernel/reports.d.ts +26 -0
- package/dist/kernel/reports.js +215 -0
- package/dist/kernel/resolver.d.ts +146 -0
- package/dist/kernel/resolver.js +232 -0
- package/dist/kernel/resource.d.ts +57 -0
- package/dist/kernel/resource.js +97 -0
- package/dist/kernel/runtime.d.ts +16 -0
- package/dist/kernel/runtime.js +18 -0
- package/dist/kernel/safety-scanner.d.ts +38 -0
- package/dist/kernel/safety-scanner.js +228 -0
- package/dist/kernel/serialize-to-files.d.ts +29 -0
- package/dist/kernel/serialize-to-files.js +23 -0
- package/dist/kernel/spec-access.d.ts +23 -0
- package/dist/kernel/spec-access.js +40 -0
- package/dist/kernel/studio_ui.d.ts +88 -0
- package/dist/kernel/studio_ui.js +135 -0
- package/dist/kernel/templates.d.ts +77 -0
- package/dist/kernel/templates.js +116 -0
- package/dist/kernel/tool-registry.d.ts +52 -0
- package/dist/kernel/tool-registry.js +89 -0
- package/dist/kernel/write-pipeline.d.ts +65 -0
- package/dist/kernel/write-pipeline.js +271 -0
- package/dist/kernel/writer-helpers.d.ts +24 -0
- package/dist/kernel/writer-helpers.js +42 -0
- package/dist/memory/decay.d.ts +31 -0
- package/dist/memory/decay.js +97 -0
- package/dist/memory/ecphory.d.ts +25 -0
- package/dist/memory/ecphory.js +178 -0
- package/dist/memory/encodingContext.d.ts +21 -0
- package/dist/memory/encodingContext.js +62 -0
- package/dist/memory/index.d.ts +23 -0
- package/dist/memory/index.js +23 -0
- package/dist/memory/memoryType.d.ts +7 -0
- package/dist/memory/memoryType.js +24 -0
- package/dist/memory/policy.d.ts +35 -0
- package/dist/memory/policy.js +35 -0
- package/dist/memory/retrieval.d.ts +21 -0
- package/dist/memory/retrieval.js +145 -0
- package/dist/testing/index.d.ts +8 -0
- package/dist/testing/index.js +8 -0
- package/dist/testing/recordSearchConformance.d.ts +43 -0
- package/dist/testing/recordSearchConformance.js +147 -0
- package/dist/viz/ascii.d.ts +7 -0
- package/dist/viz/ascii.js +60 -0
- package/dist/viz/health.d.ts +8 -0
- package/dist/viz/health.js +161 -0
- package/dist/viz/index.d.ts +10 -0
- package/dist/viz/index.js +10 -0
- package/dist/viz/matrix.d.ts +8 -0
- package/dist/viz/matrix.js +84 -0
- package/dist/viz/mermaid.d.ts +38 -0
- package/dist/viz/mermaid.js +706 -0
- 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";
|