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,764 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed Zod schemas for each kind — used by KindPort.parse().
|
|
3
|
+
*
|
|
4
|
+
* 1:1 parity with Python dna.v3.kernel.models.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { UI_METADATA_FIELDS } from "./studio_ui.js";
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Shared
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
export const MetadataSchema = z.object({
|
|
12
|
+
name: z.string(),
|
|
13
|
+
description: z.string().optional().default(""),
|
|
14
|
+
version: z.string().optional().default(""),
|
|
15
|
+
icon: z.string().optional().default(""),
|
|
16
|
+
group: z.string().optional().default(""),
|
|
17
|
+
labels: z.record(z.string()).default({}),
|
|
18
|
+
});
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Genome (github.com/ruinosus/dna/v1) — Phase 16 (scope segregation)
|
|
21
|
+
//
|
|
22
|
+
// Replaces Module as the scope-root identity + runtime config doc.
|
|
23
|
+
// Catalog identity (owner, version, visibility) lives here. Layer policy
|
|
24
|
+
// moved out to ``LayerPolicy`` Kind. Custom Kinds moved out to
|
|
25
|
+
// ``KindDefinition`` Kind. Bill-of-materials inventory arrays
|
|
26
|
+
// (agents[], skills[], actors[], etc.) deleted — composition validation
|
|
27
|
+
// walks scanner output directly.
|
|
28
|
+
//
|
|
29
|
+
// Tenant overlay applies only to ``OVERLAYABLE_FIELDS`` declared on the
|
|
30
|
+
// GenomeKind class (see typescript/src/extensions/helix.ts). Identity
|
|
31
|
+
// (owner_tenant, version, visibility, deprecated*, repository,
|
|
32
|
+
// dependencies) is structurally non-overlayable.
|
|
33
|
+
//
|
|
34
|
+
// 1:1 parity with Python dna.kernel.models.GenomeSpec.
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
export const GenomeSpecSchema = z.object({
|
|
37
|
+
// Catalog identity — non-overlayable.
|
|
38
|
+
owner: z.string().nullish(),
|
|
39
|
+
owner_tenant: z.string().nullish(),
|
|
40
|
+
repository: z.string().nullish(),
|
|
41
|
+
visibility: z.enum(["public", "internal", "private"]).default("public"),
|
|
42
|
+
// i-112 OQ1 — a mandatory Catalog capability is installed-by-default +
|
|
43
|
+
// non-removable; global_scope = global runtime lookup (like the model
|
|
44
|
+
// registry). Catalog identity → NOT overlayable.
|
|
45
|
+
mandatory: z.boolean().default(false),
|
|
46
|
+
global_scope: z.boolean().default(false),
|
|
47
|
+
// Composition Engine V2 (Phase 17, s-comp-f1-schema, 2026-05-28):
|
|
48
|
+
// Declarative parent scope for cross-scope inheritance. null = root.
|
|
49
|
+
// Resolution walks the chain. Per-Kind composition_rules in
|
|
50
|
+
// LayerPolicy govern which Kinds inherit + merge_strategy.
|
|
51
|
+
parent_scope: z.string().nullish(),
|
|
52
|
+
// Versioning — non-overlayable.
|
|
53
|
+
version: z.string().nullish(),
|
|
54
|
+
changelog_url: z.string().nullish(),
|
|
55
|
+
deprecated: z.boolean().default(false),
|
|
56
|
+
deprecated_message: z.string().nullish(),
|
|
57
|
+
// Runtime defaults — overlayable per tenant.
|
|
58
|
+
default_agent: z.string().optional(),
|
|
59
|
+
default_llm: z.string().optional(),
|
|
60
|
+
budget: z.record(z.unknown()).nullish(),
|
|
61
|
+
tags: z.array(z.string()).default([]),
|
|
62
|
+
// i-112 ph2 — capability manifest: what this Genome PROVIDES. Each entry
|
|
63
|
+
// {kind, name, location}. Catalog identity → NOT overlayable. The resolver
|
|
64
|
+
// (Phase 3) reads this to load capabilities from installed packages.
|
|
65
|
+
capabilities: z.array(z.record(z.unknown())).default([]),
|
|
66
|
+
// External deps — non-overlayable (lockfile resolves).
|
|
67
|
+
dependencies: z.array(z.record(z.unknown())).default([]),
|
|
68
|
+
});
|
|
69
|
+
export const GenomeSchema = z.object({
|
|
70
|
+
apiVersion: z.literal("github.com/ruinosus/dna/v1"),
|
|
71
|
+
kind: z.literal("Genome"),
|
|
72
|
+
metadata: MetadataSchema,
|
|
73
|
+
spec: GenomeSpecSchema.default({}),
|
|
74
|
+
});
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// LayerPolicy (github.com/ruinosus/dna/policy/v1) — Phase 16
|
|
77
|
+
//
|
|
78
|
+
// One LayerPolicy doc per layer dimension (e.g. tenant, branch, region).
|
|
79
|
+
// Lives at ``<scope>/policies/<id>.yaml``. Replaces ``Module.spec.layers``.
|
|
80
|
+
// Read by the kernel in write-time enforcement; Some Kinds are
|
|
81
|
+
// structurally non-overlayable (Genome, KindDefinition, LayerPolicy
|
|
82
|
+
// itself) — their policy is always locked regardless of doc contents.
|
|
83
|
+
//
|
|
84
|
+
// Policy values: ``open`` (default — never raises),
|
|
85
|
+
// ``restricted`` (only override existing top-level spec keys),
|
|
86
|
+
// ``locked`` (any write raises).
|
|
87
|
+
//
|
|
88
|
+
// 1:1 parity with Python dna.kernel.models.LayerPolicySpec.
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// Composition Engine V2 (Phase 17, s-comp-f1-schema, 2026-05-28).
|
|
91
|
+
// 1:1 parity with Python CompositionRule.
|
|
92
|
+
export const CompositionRuleSchema = z.object({
|
|
93
|
+
scope_inheritance: z.enum(["enabled", "disabled"]).default("enabled"),
|
|
94
|
+
merge_strategy: z.enum(["override_full", "field_level"]).default("override_full"),
|
|
95
|
+
tenant_overlay: z.enum(["none", "field_level"]).default("field_level"),
|
|
96
|
+
});
|
|
97
|
+
export const LayerPolicySpecSchema = z.object({
|
|
98
|
+
layer_id: z.string().default(""),
|
|
99
|
+
// Map of kind alias → policy string. Values are normalized to
|
|
100
|
+
// lowercase by the parse hook on the KindPort (TypeScript Zod runs
|
|
101
|
+
// its own coercion via .transform on the LayerPolicyKind to mirror
|
|
102
|
+
// Python's LayerPolicySpec.from_raw normalization).
|
|
103
|
+
policies: z.record(z.string()).default({}),
|
|
104
|
+
// Composition Engine V2: per-Kind composition rules (1:1 parity
|
|
105
|
+
// with Python LayerPolicySpec.composition_rules). Absent Kinds fall
|
|
106
|
+
// back to opt-in defaults (no inheritance, no overlay).
|
|
107
|
+
composition_rules: z.record(CompositionRuleSchema).default({}),
|
|
108
|
+
});
|
|
109
|
+
export const LayerPolicySchema = z.object({
|
|
110
|
+
apiVersion: z.literal("github.com/ruinosus/dna/policy/v1"),
|
|
111
|
+
kind: z.literal("LayerPolicy"),
|
|
112
|
+
metadata: MetadataSchema,
|
|
113
|
+
spec: LayerPolicySpecSchema.default({}),
|
|
114
|
+
});
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// Agent (github.com/ruinosus/dna/v1)
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
export const AgentSpecSchema = z.object({
|
|
119
|
+
instruction: z.string().optional().default(""),
|
|
120
|
+
instruction_file: z.string().optional(),
|
|
121
|
+
objective: z.string().optional().default(""),
|
|
122
|
+
model: z.string().optional(),
|
|
123
|
+
type: z.string().optional(),
|
|
124
|
+
soul: z.string().optional(),
|
|
125
|
+
skills: z.array(z.string()).default([]),
|
|
126
|
+
tools: z.array(z.string()).default([]),
|
|
127
|
+
team_members: z.array(z.string()).default([]),
|
|
128
|
+
tags: z.array(z.string()).default([]),
|
|
129
|
+
guardrails: z.array(z.string()).default([]),
|
|
130
|
+
promptTemplate: z.string().optional(),
|
|
131
|
+
// Phase 14x — tool-group specialization (TS parity with Python).
|
|
132
|
+
tool_groups: z.array(z.string()).default([]),
|
|
133
|
+
// s-mcp-servers-on-agent (2026-07-07, spec
|
|
134
|
+
// 2026-07-07-mcp-first-tools-design.md §5.1) — external MCP servers
|
|
135
|
+
// this agent consumes. Each entry is EITHER a plain string ref
|
|
136
|
+
// ("drawio" ≡ {ref: "drawio"}) OR an object with per-agent overrides:
|
|
137
|
+
// ref (MCPFederation doc name, inherited from _lib), allowed_tools
|
|
138
|
+
// (per-agent allowlist ∩ the doc's own), timeout_s (call-timeout
|
|
139
|
+
// override). Runtime consumption is Python-only (make_mcp_tools);
|
|
140
|
+
// the TS SDK ships the schema for parity + Studio.
|
|
141
|
+
mcp_servers: z
|
|
142
|
+
.array(z.union([
|
|
143
|
+
z.string(),
|
|
144
|
+
z
|
|
145
|
+
.object({
|
|
146
|
+
ref: z.string(),
|
|
147
|
+
allowed_tools: z.array(z.string()).optional(),
|
|
148
|
+
timeout_s: z.number().optional(),
|
|
149
|
+
})
|
|
150
|
+
.passthrough(),
|
|
151
|
+
]))
|
|
152
|
+
.default([]),
|
|
153
|
+
// Phase 14w follow-up (2026-05-08) — per-agent shell sandbox
|
|
154
|
+
// opt-in (TS parity with Python). ``true`` forces the
|
|
155
|
+
// DeepAgents ``execute`` tool ON for this agent regardless of
|
|
156
|
+
// the scope-wide ``DNA_AGENT_SHELL_SANDBOX`` env. ``false``
|
|
157
|
+
// forces it OFF. Absent (the default) defers to the env.
|
|
158
|
+
shell_sandbox: z.boolean().optional(),
|
|
159
|
+
// Phase 3C (2026-05-15) — reflection pattern opt-in (TS parity
|
|
160
|
+
// with Python). When true, graph.py renders a "Reflection step
|
|
161
|
+
// (before tool calls)" block into the system prompt instructing
|
|
162
|
+
// the UA to enumerate its plan in one turn before issuing any
|
|
163
|
+
// write tool. Pattern from Anthropic Writing Tools for Agents —
|
|
164
|
+
// reduces uncreated rate for UAs with mandatory_tool_calls.
|
|
165
|
+
reflect_before_write: z.boolean().optional(),
|
|
166
|
+
// P2 architectural fix (2026-05-15) — declarative i18n bundle
|
|
167
|
+
// (TS parity with Python). Maps locale → {key: literal-string}.
|
|
168
|
+
// Callers resolving a PromptTemplate look up
|
|
169
|
+
// locale_strings[locale][key] instead of hardcoding strings in code.
|
|
170
|
+
locale_strings: z.record(z.string(), z.record(z.string(), z.string())).optional(),
|
|
171
|
+
// Phase 1.6 (s-toon-agent-prompts) — opt-in token-efficient
|
|
172
|
+
// encoding for context arrays. ``"toon"`` uses TOON (~40-60%
|
|
173
|
+
// fewer tokens for uniform arrays); ``"json"`` (default,
|
|
174
|
+
// back-compat) uses compact JSON. Runtime prompt
|
|
175
|
+
// helpers honor this.
|
|
176
|
+
prompt_format: z.enum(["json", "toon"]).optional(),
|
|
177
|
+
// s-per-agent-max-turns (2026-05-12) — per-agent recursion budget
|
|
178
|
+
// for delegation.call_agent. Single-turn JSON-gen agents
|
|
179
|
+
// (tool_groups: [none]) can ship max_turns: 3. Multi-turn cognitive
|
|
180
|
+
// scribes that call many read tools before write need 25-30.
|
|
181
|
+
// Absent → delegation.py default (25). LangGraph recursion_limit
|
|
182
|
+
// = max_turns * 4.
|
|
183
|
+
max_turns: z.number().int().positive().optional(),
|
|
184
|
+
// s-agent-kind-field-langgraph-react (2026-05-12) — pick agent
|
|
185
|
+
// harness. "deepagent" (default) = full create_deep_agent.
|
|
186
|
+
// "langgraph-react" = lightweight create_react_agent (no filesystem
|
|
187
|
+
// built-ins, no GP subagent). For simple read agents.
|
|
188
|
+
agent_kind: z.enum(["deepagent", "langgraph-react"]).optional(),
|
|
189
|
+
// s-ua-agent-contract-fields (2026-05-13) — structural agent
|
|
190
|
+
// contract. Replaces ad-hoc markdown copy-paste with typed fields
|
|
191
|
+
// validated at parse + graph-build time, rendered into the system
|
|
192
|
+
// prompt automatically.
|
|
193
|
+
//
|
|
194
|
+
// mandatory_tool_calls: tool slugs the UA MUST invoke before
|
|
195
|
+
// stopping. Validated by `s-ua-contract-graph-validation` —
|
|
196
|
+
// warn-loud when a slug isn't in `tools` or available via
|
|
197
|
+
// `tool_groups`. Renders into the system prompt as
|
|
198
|
+
// "Mandatory tool calls" by `s-ua-contract-prompt-injection`.
|
|
199
|
+
//
|
|
200
|
+
// input_schema: expected shape of the input the UA receives.
|
|
201
|
+
// Object = inline JSON schema; string = reference to a Skill
|
|
202
|
+
// or KindDefinition that describes the shape. Renders into the
|
|
203
|
+
// system prompt as "Expected Input" with a JSON example.
|
|
204
|
+
//
|
|
205
|
+
// invoked_by_engine: alias of the CognitiveEngine that
|
|
206
|
+
// typically dispatches this UA. Drives discovery — Studio +
|
|
207
|
+
// eval-lab link agents to their engine.
|
|
208
|
+
mandatory_tool_calls: z.array(z.string()).default([]),
|
|
209
|
+
input_schema: z.union([z.record(z.unknown()), z.string()]).optional(),
|
|
210
|
+
invoked_by_engine: z.string().optional(),
|
|
211
|
+
// JARVIS — opt-in voice persona block (e-jarvis-voice-module).
|
|
212
|
+
// Presence flips the UA from text-only to voice-reachable via
|
|
213
|
+
// POST /voice/sessions. Mirrors Python `VoicePersona` dataclass.
|
|
214
|
+
voice_persona: z.object({
|
|
215
|
+
voice: z.string().default("cedar"),
|
|
216
|
+
style: z.string().optional(),
|
|
217
|
+
archetype: z.string().optional(),
|
|
218
|
+
interruption_tolerance: z.enum(["high", "medium", "low"]).default("high"),
|
|
219
|
+
preamble: z.boolean().default(false),
|
|
220
|
+
mcp_egress: z.boolean().default(false),
|
|
221
|
+
wake_word: z.string().optional(),
|
|
222
|
+
budget: z.number().default(5.0),
|
|
223
|
+
}).optional(),
|
|
224
|
+
// s-jarvis-cross-scope (2026-05-26) — list of scopes this agent's
|
|
225
|
+
// READ tools (recall_*, ecphore, search_documents, list_documents)
|
|
226
|
+
// may iterate. Writes still land in the mounted scope. ``["*"]``
|
|
227
|
+
// means "every scope the source exposes" — used by JARVIS as the
|
|
228
|
+
// user-level personal assistant. Empty/undefined = legacy single-
|
|
229
|
+
// scope behaviour. Mirrors Python ``AgentSpec.target_scopes``.
|
|
230
|
+
target_scopes: z.array(z.string()).optional(),
|
|
231
|
+
// Kind-Writer mode (feat/kind-writer-pilot) — declarative contract for a
|
|
232
|
+
// UA that writes a Kind via structured emission (TS parity with Python).
|
|
233
|
+
// ``writes_kind`` is the target Kind name. ``creative_slots`` are spec
|
|
234
|
+
// fields the LLM fills with generated content. ``system_slots`` maps spec
|
|
235
|
+
// fields to deterministic sources (e.g. {"insight": "input.oracle_id"}).
|
|
236
|
+
// Spec fields only here — no behavior wired yet.
|
|
237
|
+
writes_kind: z.string().optional(),
|
|
238
|
+
creative_slots: z.array(z.string()).default([]),
|
|
239
|
+
system_slots: z.record(z.string(), z.string()).default({}),
|
|
240
|
+
// Multi-Kind mode (feat/kind-writer-multikind) — a UA that writes N Kinds
|
|
241
|
+
// per run (e.g. narrative-scribe → N ADRs + 1 Retrospective). Maps each
|
|
242
|
+
// target Kind name to its OWN {creative_slots, system_slots} block. An agent
|
|
243
|
+
// uses EITHER writes_kind (single) OR writes_kinds (multi), never both.
|
|
244
|
+
// (TS parity with Python AgentSpec.writes_kinds.)
|
|
245
|
+
writes_kinds: z
|
|
246
|
+
.record(z.string(), z.record(z.string(), z.any()))
|
|
247
|
+
.default({}),
|
|
248
|
+
// Declarative reads (feat/scribe-migrate-6) — symmetric to system_slots.
|
|
249
|
+
// ``reads`` maps a read-name to its params, e.g.
|
|
250
|
+
// {"oracle_verdicts": {"n": 3}, "engrams": {"n": 5}}. The SYSTEM fetches the
|
|
251
|
+
// data (reader registry, called directly — not via LLM tool-calls) and
|
|
252
|
+
// injects it into dna_input.reads AND the agent's prompt. The scribe becomes
|
|
253
|
+
// a pure composer (zero read tools).
|
|
254
|
+
reads: z.record(z.string(), z.record(z.string(), z.any())).default({}),
|
|
255
|
+
// s-delegation-declarative (2026-07-07) — declarative opt-in to the
|
|
256
|
+
// delegation surface (TS parity with Python ``DelegationTargetFor``).
|
|
257
|
+
// Replaces the hardcoded DELEGATION_CATALOG that used to live in
|
|
258
|
+
// dna_shared.manifest_tools.delegation_tools: a UA that wants to
|
|
259
|
+
// receive delegated work (e.g. from JARVIS via ``delegate_to``)
|
|
260
|
+
// declares this block — user-installed UAs opt in by declaration.
|
|
261
|
+
//
|
|
262
|
+
// Shape rationale: an object (not a bare list of delegator names)
|
|
263
|
+
// because the old catalog carried per-target metadata — ``format``
|
|
264
|
+
// is load-bearing (drives how delegate_to parses the subagent's
|
|
265
|
+
// output); ``typical_seconds`` + ``use_when`` drive the delegator's
|
|
266
|
+
// narration and target choice.
|
|
267
|
+
// agents: delegator allowlist; ["*"] = any agent may delegate here.
|
|
268
|
+
// format: return contract — "slug" (creates a doc, returns its
|
|
269
|
+
// slug) | "json" (structured JSON in final message) | "text"
|
|
270
|
+
// (free-form narrative, default).
|
|
271
|
+
// typical_seconds: rough wait so the delegator can warn the user.
|
|
272
|
+
// use_when: heuristic for when to pick THIS target.
|
|
273
|
+
// purpose: what the target is good at; consumers fall back to
|
|
274
|
+
// metadata.description when absent.
|
|
275
|
+
// Runtime consumption is Python-only (make_delegation_tools); the
|
|
276
|
+
// TS SDK ships the schema for parity + Studio.
|
|
277
|
+
delegation_target_for: z
|
|
278
|
+
.object({
|
|
279
|
+
agents: z.array(z.string()).default([]),
|
|
280
|
+
format: z.enum(["slug", "json", "text"]).default("text"),
|
|
281
|
+
typical_seconds: z.number().int().positive().optional(),
|
|
282
|
+
use_when: z.string().optional(),
|
|
283
|
+
purpose: z.string().optional(),
|
|
284
|
+
})
|
|
285
|
+
.optional(),
|
|
286
|
+
});
|
|
287
|
+
export const AgentSchema = z.object({
|
|
288
|
+
apiVersion: z.literal("github.com/ruinosus/dna/v1"),
|
|
289
|
+
kind: z.literal("Agent"),
|
|
290
|
+
metadata: MetadataSchema,
|
|
291
|
+
spec: AgentSpecSchema.default({}),
|
|
292
|
+
});
|
|
293
|
+
// ---------------------------------------------------------------------------
|
|
294
|
+
// Actor (github.com/ruinosus/dna/v1)
|
|
295
|
+
// ---------------------------------------------------------------------------
|
|
296
|
+
export const ActorSpecSchema = z.object({
|
|
297
|
+
instruction: z.string().optional().default(""),
|
|
298
|
+
traits: z.array(z.string()).default([]),
|
|
299
|
+
role: z.string().optional().default(""),
|
|
300
|
+
actorType: z.enum(["human", "system", "time"]).default("human"),
|
|
301
|
+
});
|
|
302
|
+
export const ActorSchema = z.object({
|
|
303
|
+
apiVersion: z.literal("github.com/ruinosus/dna/v1"),
|
|
304
|
+
kind: z.literal("Actor"),
|
|
305
|
+
metadata: MetadataSchema,
|
|
306
|
+
spec: ActorSpecSchema.default({}),
|
|
307
|
+
});
|
|
308
|
+
// ---------------------------------------------------------------------------
|
|
309
|
+
// UseCase (github.com/ruinosus/dna/v1)
|
|
310
|
+
// ---------------------------------------------------------------------------
|
|
311
|
+
export const UseCaseSpecSchema = z.object({
|
|
312
|
+
primary_actor: z.string().optional(),
|
|
313
|
+
supporting_actors: z.array(z.string()).default([]),
|
|
314
|
+
agents: z.array(z.string()).default([]),
|
|
315
|
+
tools: z.array(z.string()).default([]),
|
|
316
|
+
skills: z.array(z.string()).default([]),
|
|
317
|
+
soul: z.string().optional(),
|
|
318
|
+
guardrails: z.array(z.string()).default([]),
|
|
319
|
+
preconditions: z.array(z.string()).default([]),
|
|
320
|
+
main_flow: z.array(z.string()).default([]),
|
|
321
|
+
alternate_flows: z.array(z.record(z.unknown())).default([]),
|
|
322
|
+
postconditions: z.array(z.string()).default([]),
|
|
323
|
+
success_criteria: z.array(z.string()).default([]),
|
|
324
|
+
});
|
|
325
|
+
export const UseCaseSchema = z.object({
|
|
326
|
+
apiVersion: z.literal("github.com/ruinosus/dna/v1"),
|
|
327
|
+
kind: z.literal("UseCase"),
|
|
328
|
+
metadata: MetadataSchema,
|
|
329
|
+
spec: UseCaseSpecSchema.default({}),
|
|
330
|
+
});
|
|
331
|
+
// ---------------------------------------------------------------------------
|
|
332
|
+
// Tool (github.com/ruinosus/dna/v1)
|
|
333
|
+
//
|
|
334
|
+
// Declarative, invocable capability an agent can call. Bridges helix with
|
|
335
|
+
// OpenAI/Anthropic tool-calling conventions.
|
|
336
|
+
// ---------------------------------------------------------------------------
|
|
337
|
+
export const ToolTypeEnum = z.enum(["http", "mcp", "python", "shell", "builtin"]);
|
|
338
|
+
export const ToolAuthTypeEnum = z.enum(["none", "api_key", "bearer", "oauth2"]);
|
|
339
|
+
export const ToolSpecSchema = z.object({
|
|
340
|
+
type: ToolTypeEnum.default("builtin"),
|
|
341
|
+
endpoint: z.string().optional().default(""),
|
|
342
|
+
method: z.string().optional().default("POST"),
|
|
343
|
+
mcp_server: z.string().optional().default(""),
|
|
344
|
+
mcp_tool: z.string().optional().default(""),
|
|
345
|
+
python_module: z.string().optional().default(""),
|
|
346
|
+
python_callable: z.string().optional().default(""),
|
|
347
|
+
shell_command: z.string().optional().default(""),
|
|
348
|
+
input_schema: z.record(z.unknown()).default({}),
|
|
349
|
+
output_schema: z.record(z.unknown()).default({}),
|
|
350
|
+
auth_type: ToolAuthTypeEnum.default("none"),
|
|
351
|
+
auth_env_var: z.string().optional().default(""),
|
|
352
|
+
read_only: z.boolean().default(true),
|
|
353
|
+
requires_confirmation: z.boolean().default(false),
|
|
354
|
+
tags: z.array(z.string()).default([]),
|
|
355
|
+
examples: z.array(z.record(z.unknown())).default([]),
|
|
356
|
+
});
|
|
357
|
+
export const ToolSchema = z.object({
|
|
358
|
+
apiVersion: z.literal("github.com/ruinosus/dna/v1"),
|
|
359
|
+
kind: z.literal("Tool"),
|
|
360
|
+
metadata: MetadataSchema,
|
|
361
|
+
spec: ToolSpecSchema.default({}),
|
|
362
|
+
});
|
|
363
|
+
// ---------------------------------------------------------------------------
|
|
364
|
+
// Skill (agentskills.io/v1)
|
|
365
|
+
// ---------------------------------------------------------------------------
|
|
366
|
+
export const SkillSpecSchema = z.object({
|
|
367
|
+
instruction: z.string().optional().default(""),
|
|
368
|
+
scripts: z.record(z.string()).default({}),
|
|
369
|
+
references: z.record(z.string()).default({}),
|
|
370
|
+
assets: z.record(z.string()).default({}),
|
|
371
|
+
extras: z.record(z.record(z.string())).default({}),
|
|
372
|
+
root_files: z.record(z.string()).default({}),
|
|
373
|
+
});
|
|
374
|
+
export const SkillSchema = z.object({
|
|
375
|
+
apiVersion: z.literal("agentskills.io/v1"),
|
|
376
|
+
kind: z.literal("Skill"),
|
|
377
|
+
metadata: MetadataSchema,
|
|
378
|
+
spec: SkillSpecSchema.default({}),
|
|
379
|
+
});
|
|
380
|
+
// ---------------------------------------------------------------------------
|
|
381
|
+
// Soul (soulspec.org/v1)
|
|
382
|
+
// ---------------------------------------------------------------------------
|
|
383
|
+
export const SoulSpecSchema = z.object({
|
|
384
|
+
soul_content: z.string().optional().default(""),
|
|
385
|
+
soul_json: z.record(z.unknown()).optional(),
|
|
386
|
+
style_content: z.string().optional().default(""),
|
|
387
|
+
agents_content: z.string().optional().default(""),
|
|
388
|
+
});
|
|
389
|
+
export const SoulSchema = z.object({
|
|
390
|
+
apiVersion: z.literal("soulspec.org/v1"),
|
|
391
|
+
kind: z.literal("Soul"),
|
|
392
|
+
metadata: MetadataSchema,
|
|
393
|
+
spec: SoulSpecSchema.default({}),
|
|
394
|
+
});
|
|
395
|
+
// ---------------------------------------------------------------------------
|
|
396
|
+
// AgentDefinition (agents.md/v1)
|
|
397
|
+
// ---------------------------------------------------------------------------
|
|
398
|
+
export const AgentDefinitionSpecSchema = z.object({
|
|
399
|
+
content: z.string().optional().default(""),
|
|
400
|
+
});
|
|
401
|
+
export const AgentDefinitionSchema = z.object({
|
|
402
|
+
apiVersion: z.literal("agents.md/v1"),
|
|
403
|
+
kind: z.literal("AgentDefinition"),
|
|
404
|
+
metadata: MetadataSchema,
|
|
405
|
+
spec: AgentDefinitionSpecSchema.default({}),
|
|
406
|
+
});
|
|
407
|
+
// ---------------------------------------------------------------------------
|
|
408
|
+
// Guardrail (github.com/ruinosus/dna/v1)
|
|
409
|
+
// ---------------------------------------------------------------------------
|
|
410
|
+
export const GuardrailSpecSchema = z.object({
|
|
411
|
+
rules: z.array(z.string()).default([]),
|
|
412
|
+
severity: z.string().optional().default("warn"),
|
|
413
|
+
scope: z.string().optional().default("both"),
|
|
414
|
+
});
|
|
415
|
+
export const GuardrailSchema = z.object({
|
|
416
|
+
apiVersion: z.literal("github.com/ruinosus/dna/v1"),
|
|
417
|
+
kind: z.literal("Guardrail"),
|
|
418
|
+
metadata: MetadataSchema,
|
|
419
|
+
spec: GuardrailSpecSchema.default({}),
|
|
420
|
+
});
|
|
421
|
+
// ---------------------------------------------------------------------------
|
|
422
|
+
// KindDefinition (github.com/ruinosus/dna/core/v1) — meta-kind
|
|
423
|
+
// ---------------------------------------------------------------------------
|
|
424
|
+
export const KIND_DEFINITION_API_VERSION = "github.com/ruinosus/dna/core/v1";
|
|
425
|
+
export const KIND_DEFINITION_KIND = "KindDefinition";
|
|
426
|
+
export const KindDefinitionSpecSchema = z.object({
|
|
427
|
+
target_api_version: z.string().min(1),
|
|
428
|
+
target_kind: z.string().min(1),
|
|
429
|
+
alias: z.string().min(1),
|
|
430
|
+
origin: z.string().min(1),
|
|
431
|
+
is_root: z.boolean().default(false),
|
|
432
|
+
prompt_target: z.boolean().default(false),
|
|
433
|
+
flatten_in_context: z.boolean().default(false),
|
|
434
|
+
schema: z.record(z.unknown()).default({}),
|
|
435
|
+
docs: z.string().optional(),
|
|
436
|
+
storage: z.record(z.unknown()),
|
|
437
|
+
dep_filters: z.record(z.string()).nullable().optional(),
|
|
438
|
+
default_agent: z.string().nullable().optional(),
|
|
439
|
+
// UI hints — read by DeclarativeKindPort from the parsed spec. Python's
|
|
440
|
+
// KindDefinitionSpec carried these since the UI-hints feature; the TS zod
|
|
441
|
+
// object silently STRIPPED them (latent divergence — per-scope KIND.yaml
|
|
442
|
+
// styles fell back to the derived origin-hash color in TS). Exposed by
|
|
443
|
+
// the F3 descriptor pilot (kaizen.kind.yaml graph_style), fixed here.
|
|
444
|
+
graph_style: z.record(z.string()).nullable().optional(),
|
|
445
|
+
ascii_icon: z.string().nullable().optional(),
|
|
446
|
+
display_label: z.string().nullable().optional(),
|
|
447
|
+
// ---- F3 descriptor fields (spec 2026-06-10-kinds-descriptor-f3, D2) ----
|
|
448
|
+
// These close the gap between hand-written Kind classes and the
|
|
449
|
+
// declarative descriptor so builtin record Kinds can be expressed as
|
|
450
|
+
// `.kind.yaml` package data. Defaults preserve today's behavior.
|
|
451
|
+
// 1:1 parity with Python KindDefinitionSpec (models.py).
|
|
452
|
+
//
|
|
453
|
+
// `plane`: "composition" | "record" — mirrors KindBase.plane.
|
|
454
|
+
plane: z.enum(["composition", "record"]).default("composition"),
|
|
455
|
+
// `tenant_scope`: "tenanted" | "global" — mirrors TenantScope. Optional
|
|
456
|
+
// (no Zod default) so the normalizing transform below can record whether
|
|
457
|
+
// it was EXPLICITLY declared — undeclared kinds stay permissive
|
|
458
|
+
// (Phase 1 back-compat; see `tenant_scope_declared`).
|
|
459
|
+
tenant_scope: z.enum(["tenanted", "global"]).optional(),
|
|
460
|
+
// `summary`: declarative list-endpoint projection — {field: default}.
|
|
461
|
+
// List form ["a", "b"] is normalized by the transform below to a dict
|
|
462
|
+
// with per-schema-type defaults (array→[], boolean→false,
|
|
463
|
+
// number/integer→null, else ""). null/absent = no projection.
|
|
464
|
+
summary: z
|
|
465
|
+
.union([z.record(z.unknown()), z.array(z.string())])
|
|
466
|
+
.nullable()
|
|
467
|
+
.optional(),
|
|
468
|
+
// `embed`: source fields for embedding text (feeds D4 derivation).
|
|
469
|
+
embed: z.array(z.string()).nullable().optional(),
|
|
470
|
+
// `is_runtime_artifact`: docs generated by runtime workflows.
|
|
471
|
+
is_runtime_artifact: z.boolean().default(false),
|
|
472
|
+
// `prompt_target_priority`: was hardcoded 5 in DeclarativeKindPort —
|
|
473
|
+
// default 5 preserves that.
|
|
474
|
+
prompt_target_priority: z.number().int().default(5),
|
|
475
|
+
// Kernel classification flags — mirror KindBase defaults.
|
|
476
|
+
scope_inheritable: z.boolean().default(true),
|
|
477
|
+
is_overlayable: z.boolean().default(true),
|
|
478
|
+
// Extra volatile spec fields, unioned with KindBase volatileSpecFields.
|
|
479
|
+
volatile_spec_fields: z.array(z.string()).nullable().optional(),
|
|
480
|
+
// ---- Descriptor expressiveness fields (spec 2026-06-11, D1/D3-D7) -------
|
|
481
|
+
// All optional; absent → null/undefined preserves today's behavior. 1:1
|
|
482
|
+
// parity with Python KindDefinitionSpec (models.py). Consumed by
|
|
483
|
+
// DeclarativeKindPort (meta.ts).
|
|
484
|
+
//
|
|
485
|
+
// D1 `ui`: raw StudioUIMetadata mapping. Keys are validated ⊆
|
|
486
|
+
// StudioUIMetadata fields (strict — unknown key → ZodError); the allowed
|
|
487
|
+
// set is derived from UI_METADATA_FIELDS, the single source of truth (no
|
|
488
|
+
// second hardcoded list). The port reconstructs the real StudioUIMetadata
|
|
489
|
+
// so /kinds/manifest output is byte-identical to the deleted class.
|
|
490
|
+
ui: z
|
|
491
|
+
.record(z.unknown())
|
|
492
|
+
.refine((m) => Object.keys(m).every((k) => UI_METADATA_FIELDS.includes(k)), (m) => ({
|
|
493
|
+
message: "spec.ui has unknown key(s): " +
|
|
494
|
+
Object.keys(m)
|
|
495
|
+
.filter((k) => !UI_METADATA_FIELDS.includes(k))
|
|
496
|
+
.sort()
|
|
497
|
+
.join(", ") +
|
|
498
|
+
` (allowed: ${[...UI_METADATA_FIELDS].sort().join(", ")})`,
|
|
499
|
+
}))
|
|
500
|
+
.nullable()
|
|
501
|
+
.optional(),
|
|
502
|
+
// D3 `describe`: template string OR projection mapping ({path: field}).
|
|
503
|
+
describe: z.union([z.string(), z.record(z.unknown())]).nullable().optional(),
|
|
504
|
+
// D4 `ui_schema`: pass-through widget-hint bag, permissive (unknown keys ok).
|
|
505
|
+
ui_schema: z.record(z.unknown()).nullable().optional(),
|
|
506
|
+
// D5 `spec_defaults`: shallow-merge map applied before schema validation.
|
|
507
|
+
spec_defaults: z.record(z.unknown()).nullable().optional(),
|
|
508
|
+
// D6 `default_agent_field`: spec field returned VERBATIM by
|
|
509
|
+
// getDefaultAgentName.
|
|
510
|
+
default_agent_field: z.string().nullable().optional(),
|
|
511
|
+
// D7 `description_fallback_field`: pass-through string attr for Studio.
|
|
512
|
+
description_fallback_field: z.string().nullable().optional(),
|
|
513
|
+
});
|
|
514
|
+
/** Normalize spec.summary to its dict form (F3 spec D2).
|
|
515
|
+
*
|
|
516
|
+
* Dict form `{field: default}` passes through. List form `["a", "b"]`
|
|
517
|
+
* gets a default per the field's declared type in `schema.properties`:
|
|
518
|
+
* array→[], boolean→false, number/integer→null, anything else (incl.
|
|
519
|
+
* fields absent from the schema)→"". Mirrors Python
|
|
520
|
+
* KindDefinitionSpec._normalize_summary. */
|
|
521
|
+
function normalizeKindDefSummary(summary, schema) {
|
|
522
|
+
if (summary == null)
|
|
523
|
+
return null;
|
|
524
|
+
if (!Array.isArray(summary))
|
|
525
|
+
return summary;
|
|
526
|
+
const props = schema.properties ?? {};
|
|
527
|
+
const out = {};
|
|
528
|
+
for (const fieldName of summary) {
|
|
529
|
+
const prop = props[fieldName];
|
|
530
|
+
const ptype = prop != null && typeof prop === "object"
|
|
531
|
+
? prop.type
|
|
532
|
+
: undefined;
|
|
533
|
+
if (ptype === "array")
|
|
534
|
+
out[fieldName] = [];
|
|
535
|
+
else if (ptype === "boolean")
|
|
536
|
+
out[fieldName] = false;
|
|
537
|
+
else if (ptype === "number" || ptype === "integer")
|
|
538
|
+
out[fieldName] = null;
|
|
539
|
+
else
|
|
540
|
+
out[fieldName] = "";
|
|
541
|
+
}
|
|
542
|
+
return out;
|
|
543
|
+
}
|
|
544
|
+
// F3 (spec D2): normalized spec — adds `tenant_scope_declared` (true iff
|
|
545
|
+
// tenant_scope was explicitly present; NOT a user-facing field), defaults
|
|
546
|
+
// tenant_scope to "tenanted", and normalizes the list form of `summary`.
|
|
547
|
+
// The plain object schema stays exported above because zodSpecToJsonSchema
|
|
548
|
+
// needs `.shape` (ZodObject, not ZodEffects).
|
|
549
|
+
const KindDefinitionSpecNormalizedSchema = KindDefinitionSpecSchema.transform((s) => ({
|
|
550
|
+
...s,
|
|
551
|
+
tenant_scope: s.tenant_scope ?? "tenanted",
|
|
552
|
+
tenant_scope_declared: s.tenant_scope !== undefined,
|
|
553
|
+
summary: normalizeKindDefSummary(s.summary, s.schema),
|
|
554
|
+
}));
|
|
555
|
+
export const KindDefinitionSchema = z.object({
|
|
556
|
+
apiVersion: z.literal(KIND_DEFINITION_API_VERSION),
|
|
557
|
+
kind: z.literal(KIND_DEFINITION_KIND),
|
|
558
|
+
metadata: MetadataSchema,
|
|
559
|
+
spec: KindDefinitionSpecNormalizedSchema,
|
|
560
|
+
});
|
|
561
|
+
// ---------------------------------------------------------------------------
|
|
562
|
+
// Hook (github.com/ruinosus/dna/v1)
|
|
563
|
+
// ---------------------------------------------------------------------------
|
|
564
|
+
export const HookActionEnum = z.enum(["inject_fields", "log", "script"]);
|
|
565
|
+
export const HookSpecSchema = z.object({
|
|
566
|
+
target: z.string().min(1).default("pre_build_prompt"), // "pre_build_prompt", "post_build_prompt", etc.
|
|
567
|
+
type: z.enum(["middleware", "event"]).default("middleware"),
|
|
568
|
+
action: HookActionEnum.default("inject_fields"),
|
|
569
|
+
fields: z.record(z.unknown()).default({}), // For inject_fields action
|
|
570
|
+
body: z.string().optional().default(""), // Raw body (script code or YAML fields)
|
|
571
|
+
});
|
|
572
|
+
export const HookSchema = z.object({
|
|
573
|
+
apiVersion: z.literal("github.com/ruinosus/dna/v1"),
|
|
574
|
+
kind: z.literal("Hook"),
|
|
575
|
+
metadata: MetadataSchema,
|
|
576
|
+
spec: HookSpecSchema.default({}),
|
|
577
|
+
});
|
|
578
|
+
// ---------------------------------------------------------------------------
|
|
579
|
+
// Community channel — artifact allowlist
|
|
580
|
+
//
|
|
581
|
+
// Spec: docs/superpowers/specs/2026-05-18-source-as-distribution.md.
|
|
582
|
+
// The CommunityItem Kind was pruned (s-prune-speculative-extensions,
|
|
583
|
+
// recovery: git history); the FS install channel lives on and this
|
|
584
|
+
// allowlist mirrors Python COMMUNITY_ARTIFACT_KINDS. Adding a Kind
|
|
585
|
+
// here requires the same entry in python/dna/kernel/models.py.
|
|
586
|
+
// ---------------------------------------------------------------------------
|
|
587
|
+
export const CommunityArtifactKindEnum = z.enum([
|
|
588
|
+
"Skill",
|
|
589
|
+
"Soul",
|
|
590
|
+
"Agent",
|
|
591
|
+
"Hook",
|
|
592
|
+
"SafetyPolicy",
|
|
593
|
+
"Recognizer",
|
|
594
|
+
"Guardrail",
|
|
595
|
+
]);
|
|
596
|
+
// ---------------------------------------------------------------------------
|
|
597
|
+
// TextBlock + HtmlBlock (github.com/ruinosus/dna/v1) — generative blocks
|
|
598
|
+
//
|
|
599
|
+
// Spec: s-generative-blocks (2026-05-19). Mirrors Python's
|
|
600
|
+
// TextBlockSpec / HtmlBlockSpec in dna.kernel.models.
|
|
601
|
+
// ---------------------------------------------------------------------------
|
|
602
|
+
export const TextBlockSpecSchema = z.object({
|
|
603
|
+
title: z.string().default(""),
|
|
604
|
+
body: z.string().default(""),
|
|
605
|
+
area: z.string().default(""),
|
|
606
|
+
owner: z.string().nullable().default(null),
|
|
607
|
+
generated_by: z.string().default(""),
|
|
608
|
+
affect: z.string().default(""),
|
|
609
|
+
tags: z.array(z.string()).default([]),
|
|
610
|
+
created_at: z.string().default(""),
|
|
611
|
+
});
|
|
612
|
+
export const TextBlockSchema = z.object({
|
|
613
|
+
apiVersion: z.literal("github.com/ruinosus/dna/v1"),
|
|
614
|
+
kind: z.literal("TextBlock"),
|
|
615
|
+
metadata: MetadataSchema,
|
|
616
|
+
spec: TextBlockSpecSchema.default({}),
|
|
617
|
+
});
|
|
618
|
+
export const HtmlBlockSpecSchema = z.object({
|
|
619
|
+
title: z.string().default(""),
|
|
620
|
+
body: z.string().default(""),
|
|
621
|
+
area: z.string().default(""),
|
|
622
|
+
owner: z.string().nullable().default(null),
|
|
623
|
+
generated_by: z.string().default(""),
|
|
624
|
+
affect: z.string().default(""),
|
|
625
|
+
tags: z.array(z.string()).default([]),
|
|
626
|
+
created_at: z.string().default(""),
|
|
627
|
+
sandbox_features: z.string().default(""),
|
|
628
|
+
estimated_height_px: z.number().int().nonnegative().default(0),
|
|
629
|
+
});
|
|
630
|
+
export const HtmlBlockSchema = z.object({
|
|
631
|
+
apiVersion: z.literal("github.com/ruinosus/dna/v1"),
|
|
632
|
+
kind: z.literal("HtmlBlock"),
|
|
633
|
+
metadata: MetadataSchema,
|
|
634
|
+
spec: HtmlBlockSpecSchema.default({}),
|
|
635
|
+
});
|
|
636
|
+
// ---------------------------------------------------------------------------
|
|
637
|
+
// HtmlTemplate (github.com/ruinosus/dna/v1) — Mustache-templated reusable widget.
|
|
638
|
+
// Story: s-html-templates (2026-05-19).
|
|
639
|
+
// ---------------------------------------------------------------------------
|
|
640
|
+
export const HtmlTemplateSpecSchema = z.object({
|
|
641
|
+
title: z.string().default(""),
|
|
642
|
+
description: z.string().default(""),
|
|
643
|
+
body: z.string().default(""),
|
|
644
|
+
version: z.string().default("0.1.0"),
|
|
645
|
+
params: z.record(z.unknown()).default({}),
|
|
646
|
+
example: z.record(z.unknown()).default({}),
|
|
647
|
+
theme: z.string().default(""),
|
|
648
|
+
area: z.string().default(""),
|
|
649
|
+
owner: z.string().nullable().default(null),
|
|
650
|
+
generated_by: z.string().default(""),
|
|
651
|
+
tags: z.array(z.string()).default([]),
|
|
652
|
+
created_at: z.string().default(""),
|
|
653
|
+
});
|
|
654
|
+
export const HtmlTemplateSchema = z.object({
|
|
655
|
+
apiVersion: z.literal("github.com/ruinosus/dna/v1"),
|
|
656
|
+
kind: z.literal("HtmlTemplate"),
|
|
657
|
+
metadata: MetadataSchema,
|
|
658
|
+
spec: HtmlTemplateSpecSchema.default({}),
|
|
659
|
+
});
|
|
660
|
+
// ---------------------------------------------------------------------------
|
|
661
|
+
// SafetyPolicy (github.com/ruinosus/dna/v1)
|
|
662
|
+
// ---------------------------------------------------------------------------
|
|
663
|
+
export const SafetyRuleSchema = z.object({
|
|
664
|
+
type: z.enum(["pii", "content_safety", "topic_restriction", "prompt_injection", "banned_words", "custom_regex"]),
|
|
665
|
+
tier: z.enum(["regex", "ml", "api", "llm_judge"]).optional(),
|
|
666
|
+
entities: z.array(z.string()).optional(),
|
|
667
|
+
region: z.string().optional(),
|
|
668
|
+
categories: z.array(z.string()).optional(),
|
|
669
|
+
threshold: z.number().optional(),
|
|
670
|
+
allowed: z.array(z.string()).optional(),
|
|
671
|
+
denied: z.array(z.string()).optional(),
|
|
672
|
+
patterns: z.array(z.string()).optional(),
|
|
673
|
+
words: z.array(z.string()).optional(),
|
|
674
|
+
});
|
|
675
|
+
export const SafetyPolicySpecSchema = z.object({
|
|
676
|
+
scope: z.enum(["input", "output", "both"]).default("both"),
|
|
677
|
+
action: z.enum(["mask", "block", "log"]).default("mask"),
|
|
678
|
+
severity: z.enum(["error", "warn"]).default("error"),
|
|
679
|
+
rules: z.array(SafetyRuleSchema).default([]),
|
|
680
|
+
recognizers: z.array(z.string()).default([]),
|
|
681
|
+
// Phase 7 — ml-privacy-filter engine. All optional (backward-compatible).
|
|
682
|
+
engine: z.enum(["presidio", "ml-privacy-filter"]).default("presidio"),
|
|
683
|
+
model: z.string().default("openai/privacy-filter"),
|
|
684
|
+
backend: z.enum(["auto", "transformers", "onnxruntime"]).default("auto"),
|
|
685
|
+
threshold: z.number().min(0).max(1).default(0.8),
|
|
686
|
+
// T1 LOCKED valid values: account_number, private_address, private_email,
|
|
687
|
+
// private_person, private_phone, private_url, private_date, secret
|
|
688
|
+
categories: z.array(z.string()).nullable().default(null),
|
|
689
|
+
mask_char: z.string().default("[REDACTED]"),
|
|
690
|
+
budget_ms: z.number().default(1000),
|
|
691
|
+
});
|
|
692
|
+
export const SafetyPolicySchema = z.object({
|
|
693
|
+
apiVersion: z.literal("github.com/ruinosus/dna/v1"),
|
|
694
|
+
kind: z.literal("SafetyPolicy"),
|
|
695
|
+
metadata: MetadataSchema,
|
|
696
|
+
spec: SafetyPolicySpecSchema.default({}),
|
|
697
|
+
});
|
|
698
|
+
// ---------------------------------------------------------------------------
|
|
699
|
+
// Recognizer (presidio/v1)
|
|
700
|
+
// ---------------------------------------------------------------------------
|
|
701
|
+
export const RecognizerPatternSchema = z.object({
|
|
702
|
+
name: z.string(),
|
|
703
|
+
regex: z.string(),
|
|
704
|
+
score: z.number().min(0).max(1),
|
|
705
|
+
});
|
|
706
|
+
export const RecognizerSpecSchema = z.object({
|
|
707
|
+
entity_type: z.string().min(1),
|
|
708
|
+
language: z.string().default("en"),
|
|
709
|
+
patterns: z.array(RecognizerPatternSchema).default([]),
|
|
710
|
+
deny_list: z.array(z.string()).default([]),
|
|
711
|
+
context: z.array(z.string()).default([]),
|
|
712
|
+
});
|
|
713
|
+
export const RecognizerSchema = z.object({
|
|
714
|
+
apiVersion: z.literal("presidio/v1"),
|
|
715
|
+
kind: z.literal("Recognizer"),
|
|
716
|
+
metadata: MetadataSchema,
|
|
717
|
+
spec: RecognizerSpecSchema,
|
|
718
|
+
});
|
|
719
|
+
// ---------------------------------------------------------------------------
|
|
720
|
+
// Zod → JSON Schema helper
|
|
721
|
+
// ---------------------------------------------------------------------------
|
|
722
|
+
/** Convert a Zod object schema's .shape to a minimal JSON Schema.
|
|
723
|
+
* No external library — walks Zod internals directly. */
|
|
724
|
+
export function zodSpecToJsonSchema(zodSchema) {
|
|
725
|
+
const shape = zodSchema.shape;
|
|
726
|
+
const properties = {};
|
|
727
|
+
function typeOf(z) {
|
|
728
|
+
const def = z?._def;
|
|
729
|
+
const tn = def?.typeName;
|
|
730
|
+
if (tn === "ZodString")
|
|
731
|
+
return { type: "string" };
|
|
732
|
+
if (tn === "ZodNumber" || tn === "ZodInt")
|
|
733
|
+
return { type: "number" };
|
|
734
|
+
if (tn === "ZodBoolean")
|
|
735
|
+
return { type: "boolean" };
|
|
736
|
+
if (tn === "ZodEnum")
|
|
737
|
+
return { type: "string", enum: def.values };
|
|
738
|
+
if (tn === "ZodArray") {
|
|
739
|
+
const items = def.type ? typeOf(def.type) : { type: "string" };
|
|
740
|
+
return { type: "array", items };
|
|
741
|
+
}
|
|
742
|
+
if (tn === "ZodRecord")
|
|
743
|
+
return { type: "object" };
|
|
744
|
+
if (tn === "ZodOptional")
|
|
745
|
+
return typeOf(def.innerType);
|
|
746
|
+
if (tn === "ZodDefault")
|
|
747
|
+
return typeOf(def.innerType);
|
|
748
|
+
if (tn === "ZodObject")
|
|
749
|
+
return { type: "object" };
|
|
750
|
+
if (tn === "ZodUnknown" || tn === "ZodAny")
|
|
751
|
+
return {};
|
|
752
|
+
return {};
|
|
753
|
+
}
|
|
754
|
+
for (const [key, zodType] of Object.entries(shape)) {
|
|
755
|
+
properties[key] = typeOf(zodType);
|
|
756
|
+
}
|
|
757
|
+
return { type: "object", properties };
|
|
758
|
+
}
|
|
759
|
+
// ── DNA namespace ───────────────────────────────────────────────────────────
|
|
760
|
+
// Single authoritative namespace constant (spec §8: swapping the namespace
|
|
761
|
+
// is one commit + a golden regen). NOTE: literal-type positions (z.literal /
|
|
762
|
+
// *.kind.yaml descriptors) must stay in sync with this value — the
|
|
763
|
+
// descriptor + parity suites enforce it.
|
|
764
|
+
export const DNA_NAMESPACE = "github.com/ruinosus/dna";
|