dna-sdk 0.4.0 → 0.5.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/dist/extensions/helix.js +45 -1
- package/dist/extensions/sdlc.js +162 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/kernel/errors.d.ts +17 -0
- package/dist/kernel/errors.js +26 -0
- package/dist/kernel/kind_base.d.ts +13 -0
- package/dist/kernel/kind_base.js +17 -0
- package/dist/kernel/models.d.ts +85 -0
- package/dist/kernel/models.js +19 -0
- package/dist/kernel/prompt-builder.js +15 -4
- package/package.json +1 -1
package/dist/extensions/helix.js
CHANGED
|
@@ -13,6 +13,33 @@ import { readSpecString, readSpecStringArray } from "../kernel/spec-access.js";
|
|
|
13
13
|
import { SettingKind, ThemeKind, UserProfileKind, CanvasKind } from "./helix_extras.js";
|
|
14
14
|
import { registerWriteGuards } from "./helix/write-guards.js";
|
|
15
15
|
const MOD_URL = import.meta.url;
|
|
16
|
+
// ── Named composition layouts (s-dx-named-layouts) ─────────────────────
|
|
17
|
+
//
|
|
18
|
+
// An author orders persona-vs-instruction by NAME (`layout:` in the Agent
|
|
19
|
+
// spec) instead of hand-writing raw Mustache with internal section names.
|
|
20
|
+
// Each preset resolves to one of these embedded templates via
|
|
21
|
+
// `AgentKind.layoutTemplate()`. 1:1 with Python `dna.extensions.helix`.
|
|
22
|
+
//
|
|
23
|
+
// The guardrails block is shared verbatim — guardrails are hard policy and
|
|
24
|
+
// always land LAST, after both the instruction and the soul, regardless of
|
|
25
|
+
// their relative order. (Aligns TS composition to Python, closing the
|
|
26
|
+
// pre-existing i-213/i-011 divergence where TS omitted the guardrails block.)
|
|
27
|
+
const GUARDRAILS_BLOCK = "{{#guardrails-guardrail}}" +
|
|
28
|
+
"## Guardrail: {{name}} ({{severity}})\n" +
|
|
29
|
+
"{{#description}}_{{description}}_\n\n{{/description}}" +
|
|
30
|
+
"{{#rules}}- {{{.}}}\n{{/rules}}\n" +
|
|
31
|
+
"{{/guardrails-guardrail}}";
|
|
32
|
+
// instruction-first (a.k.a. "default") — historic order: instruction, soul,
|
|
33
|
+
// guardrails. IS the kind default template.
|
|
34
|
+
const LAYOUT_INSTRUCTION_FIRST = "{{{agent.instruction}}}\n\n{{{soul_content}}}\n\n" + GUARDRAILS_BLOCK;
|
|
35
|
+
// persona-first — Soul leads, then instruction, then guardrails.
|
|
36
|
+
const LAYOUT_PERSONA_FIRST = "{{{soul_content}}}\n\n{{{agent.instruction}}}\n\n" + GUARDRAILS_BLOCK;
|
|
37
|
+
const AGENT_LAYOUTS = {
|
|
38
|
+
default: LAYOUT_INSTRUCTION_FIRST,
|
|
39
|
+
"instruction-first": LAYOUT_INSTRUCTION_FIRST,
|
|
40
|
+
"persona-first": LAYOUT_PERSONA_FIRST,
|
|
41
|
+
};
|
|
42
|
+
const AGENT_LAYOUT_NAMES = ["default", "instruction-first", "persona-first"];
|
|
16
43
|
// GenomeKind — Phase 16 (scope segregation)
|
|
17
44
|
//
|
|
18
45
|
// Replaces ModuleKind as the scope-root identity Kind. Carries catalog
|
|
@@ -253,6 +280,13 @@ class AgentKind extends KindBase {
|
|
|
253
280
|
},
|
|
254
281
|
objective: { widget: "textarea", label: "Objective", order: 15 },
|
|
255
282
|
model: { widget: "text", label: "Model", order: 20 },
|
|
283
|
+
layout: {
|
|
284
|
+
widget: "select",
|
|
285
|
+
label: "Layout",
|
|
286
|
+
options: ["default", "instruction-first", "persona-first"],
|
|
287
|
+
help: "Named composition order — 'persona-first' puts the Soul before the instruction. Leave empty for the default. A raw promptTemplate, if set, overrides this.",
|
|
288
|
+
order: 25,
|
|
289
|
+
},
|
|
256
290
|
soul: { widget: "text", label: "Soul", help: "Name of the Soul doc to flatten into the prompt.", order: 30 },
|
|
257
291
|
skills: { widget: "tags", label: "Skills", order: 40 },
|
|
258
292
|
actors: { widget: "tags", label: "Actors this agent serves", order: 50 },
|
|
@@ -305,7 +339,17 @@ class AgentKind extends KindBase {
|
|
|
305
339
|
return { skills: skills.length, soul: readSpecString(doc, "soul") ?? null };
|
|
306
340
|
}
|
|
307
341
|
promptTemplate() {
|
|
308
|
-
|
|
342
|
+
// IS the `instruction-first` / `default` named layout — the kind default
|
|
343
|
+
// template and the `default` layout are one string, so an agent with no
|
|
344
|
+
// `layout:` composes identically. (Now includes the guardrails block,
|
|
345
|
+
// matching Python — see the layout-constants comment above.)
|
|
346
|
+
return LAYOUT_INSTRUCTION_FIRST;
|
|
347
|
+
}
|
|
348
|
+
layoutTemplate(name) {
|
|
349
|
+
return AGENT_LAYOUTS[name] ?? null;
|
|
350
|
+
}
|
|
351
|
+
layoutNames() {
|
|
352
|
+
return [...AGENT_LAYOUT_NAMES];
|
|
309
353
|
}
|
|
310
354
|
preview(doc) {
|
|
311
355
|
const spec = (doc.spec ?? {});
|
package/dist/extensions/sdlc.js
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
import { KindBase } from "../kernel/kind_base.js";
|
|
28
28
|
import { SD, TenantScope } from "../kernel/protocols.js";
|
|
29
29
|
import { loadDescriptors } from "../kernel/descriptor-loader.js";
|
|
30
|
+
import { HtmlArtifactSchema } from "../kernel/models.js";
|
|
30
31
|
const API_VERSION = "github.com/ruinosus/dna/sdlc/v1";
|
|
31
32
|
// v1.3: MILESTONE_STATUSES → EPIC_STATUSES (Jira/ADO alignment).
|
|
32
33
|
const EPIC_STATUSES = ["planning", "in-progress", "done", "cancelled", "deprecated"];
|
|
@@ -1280,6 +1281,161 @@ const JOURNEY_METHODOLOGIES = [
|
|
|
1280
1281
|
// the old class is frozen in sdk-py tests/test_kaizen_descriptor_equivalence.py
|
|
1281
1282
|
// + tests/sdlc.test.ts.
|
|
1282
1283
|
// ---------------------------------------------------------------------------
|
|
1284
|
+
// ---------------------------------------------------------------------------
|
|
1285
|
+
// HtmlArtifact — an HTML page as a first-class work-item output (record plane)
|
|
1286
|
+
//
|
|
1287
|
+
// s-dx-html-artifact-kind. 1:1 parity with Python HtmlArtifactKind. Bundle
|
|
1288
|
+
// Kind: ARTIFACT.html holds the raw HTML VERBATIM (byte-faithful round-trip —
|
|
1289
|
+
// no frontmatter injection), plus an optional artifact.json companion with
|
|
1290
|
+
// structured metadata (title, description, source, created_at) — the same
|
|
1291
|
+
// mechanic as a Soul (SOUL.md + soul.json). Custom reader/writer (not the
|
|
1292
|
+
// generic marker-frontmatter path) because the marker is arbitrary HTML.
|
|
1293
|
+
// ---------------------------------------------------------------------------
|
|
1294
|
+
class HtmlArtifactKind extends KindBase {
|
|
1295
|
+
apiVersion = API_VERSION;
|
|
1296
|
+
kind = "HtmlArtifact";
|
|
1297
|
+
// alias GENERATED = "<owner>-<kebab(kind)>" = "sdlc-html-artifact".
|
|
1298
|
+
// s-alias-generated-not-typed: new Kinds must NOT type an explicit alias
|
|
1299
|
+
// (EXPLICIT_ALIAS_ALLOWLIST ratchet is shrink-only). Empty here + aliasOwner
|
|
1300
|
+
// triggers generation at load time (Py twin sets alias=None + alias_owner).
|
|
1301
|
+
alias = "";
|
|
1302
|
+
aliasOwner = "sdlc";
|
|
1303
|
+
origin = "github.com/ruinosus/dna/sdlc";
|
|
1304
|
+
isPromptTarget = false;
|
|
1305
|
+
promptTargetPriority = 0;
|
|
1306
|
+
flattenInContext = false;
|
|
1307
|
+
plane = "record";
|
|
1308
|
+
storage = SD.bundle("html-artifacts", "ARTIFACT.html");
|
|
1309
|
+
graphStyle = { fill: "#EA580C", stroke: "#C2410C", textColor: "#fff" };
|
|
1310
|
+
asciiIcon = "📄";
|
|
1311
|
+
displayLabel = "HTML Artifacts";
|
|
1312
|
+
uiSchema = {
|
|
1313
|
+
html: {
|
|
1314
|
+
widget: "code",
|
|
1315
|
+
language: "html",
|
|
1316
|
+
label: "ARTIFACT.html",
|
|
1317
|
+
help: "The raw HTML page (stored byte-faithful).",
|
|
1318
|
+
height: 520,
|
|
1319
|
+
order: 10,
|
|
1320
|
+
},
|
|
1321
|
+
artifact_json: {
|
|
1322
|
+
widget: "code",
|
|
1323
|
+
language: "json",
|
|
1324
|
+
label: "artifact.json",
|
|
1325
|
+
help: "Structured metadata (title, description, source, created_at).",
|
|
1326
|
+
height: 220,
|
|
1327
|
+
order: 20,
|
|
1328
|
+
},
|
|
1329
|
+
};
|
|
1330
|
+
docs = "An HtmlArtifact stores an HTML page as a first-class, linkable output " +
|
|
1331
|
+
"of a work item (Story/Feature/Epic/Spike). Bundle: ARTIFACT.html holds " +
|
|
1332
|
+
"the raw HTML verbatim (byte-faithful round-trip) plus an optional " +
|
|
1333
|
+
"artifact.json companion with structured metadata (title, description, " +
|
|
1334
|
+
"source, created_at) — the same shape as a Soul's SOUL.md + soul.json. " +
|
|
1335
|
+
"Attach one with `dna sdlc produces add <WiKind>/<wi> HtmlArtifact/<name>`.";
|
|
1336
|
+
schema() {
|
|
1337
|
+
return {
|
|
1338
|
+
type: "object",
|
|
1339
|
+
additionalProperties: false,
|
|
1340
|
+
properties: {
|
|
1341
|
+
html: { type: "string", description: "The raw HTML document (byte-faithful)." },
|
|
1342
|
+
artifact_json: {
|
|
1343
|
+
type: "object",
|
|
1344
|
+
additionalProperties: true,
|
|
1345
|
+
description: "Structured metadata: title, description, source, created_at.",
|
|
1346
|
+
},
|
|
1347
|
+
},
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1350
|
+
parse(raw) {
|
|
1351
|
+
return HtmlArtifactSchema.parse(raw);
|
|
1352
|
+
}
|
|
1353
|
+
summary(doc) {
|
|
1354
|
+
const spec = (doc.spec ?? {});
|
|
1355
|
+
const aj = spec.artifact_json ?? {};
|
|
1356
|
+
return {
|
|
1357
|
+
title: aj.title ?? null,
|
|
1358
|
+
source: aj.source ?? null,
|
|
1359
|
+
created_at: aj.created_at ?? null,
|
|
1360
|
+
html_bytes: (spec.html ?? "").length,
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
preview(doc) {
|
|
1364
|
+
const spec = (doc.spec ?? {});
|
|
1365
|
+
const blocks = [];
|
|
1366
|
+
if (typeof spec.html === "string" && spec.html) {
|
|
1367
|
+
blocks.push({ kind: "code", title: "ARTIFACT.html", body: spec.html, language: "html" });
|
|
1368
|
+
}
|
|
1369
|
+
if (spec.artifact_json && typeof spec.artifact_json === "object") {
|
|
1370
|
+
blocks.push({
|
|
1371
|
+
kind: "code",
|
|
1372
|
+
title: "artifact.json",
|
|
1373
|
+
body: JSON.stringify(spec.artifact_json, null, 2),
|
|
1374
|
+
language: "json",
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
if (blocks.length === 0) {
|
|
1378
|
+
return [{ kind: "empty", title: "HtmlArtifact (empty)" }];
|
|
1379
|
+
}
|
|
1380
|
+
return blocks;
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
class HtmlArtifactReader {
|
|
1384
|
+
async detect(bundle) {
|
|
1385
|
+
return bundle.exists("ARTIFACT.html");
|
|
1386
|
+
}
|
|
1387
|
+
async read(bundle) {
|
|
1388
|
+
const spec = {};
|
|
1389
|
+
const metadata = {};
|
|
1390
|
+
// ARTIFACT.html — read verbatim (byte-faithful; no frontmatter parse).
|
|
1391
|
+
if (await bundle.exists("ARTIFACT.html")) {
|
|
1392
|
+
spec.html = await bundle.readText("ARTIFACT.html");
|
|
1393
|
+
}
|
|
1394
|
+
// artifact.json companion — structured metadata.
|
|
1395
|
+
if (await bundle.exists("artifact.json")) {
|
|
1396
|
+
const aj = JSON.parse(await bundle.readText("artifact.json"));
|
|
1397
|
+
if (aj && typeof aj === "object" && !Array.isArray(aj)) {
|
|
1398
|
+
spec.artifact_json = aj;
|
|
1399
|
+
const desc = aj.description;
|
|
1400
|
+
if (typeof desc === "string" && desc && !metadata.description) {
|
|
1401
|
+
metadata.description = desc;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
if (metadata.name == null)
|
|
1406
|
+
metadata.name = bundle.name;
|
|
1407
|
+
return {
|
|
1408
|
+
apiVersion: API_VERSION,
|
|
1409
|
+
kind: "HtmlArtifact",
|
|
1410
|
+
metadata,
|
|
1411
|
+
spec,
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
class HtmlArtifactWriter {
|
|
1416
|
+
canWrite(raw) {
|
|
1417
|
+
return raw.kind === "HtmlArtifact";
|
|
1418
|
+
}
|
|
1419
|
+
serialize(raw) {
|
|
1420
|
+
const files = [];
|
|
1421
|
+
const spec = raw.spec ?? {};
|
|
1422
|
+
// ARTIFACT.html — verbatim HTML (byte-faithful).
|
|
1423
|
+
files.push({ relativePath: "ARTIFACT.html", content: spec.html ?? "" });
|
|
1424
|
+
// artifact.json — canonical JSON companion. metadata.description is a
|
|
1425
|
+
// DERIVED promotion of artifact_json.description on read, so it is NOT
|
|
1426
|
+
// re-emitted separately (no phantom frontmatter — F3 market-fidelity).
|
|
1427
|
+
const aj = spec.artifact_json;
|
|
1428
|
+
if (aj && typeof aj === "object") {
|
|
1429
|
+
files.push({ relativePath: "artifact.json", content: JSON.stringify(aj, null, 2) });
|
|
1430
|
+
}
|
|
1431
|
+
return files;
|
|
1432
|
+
}
|
|
1433
|
+
async write(bundle, raw) {
|
|
1434
|
+
for (const f of this.serialize(raw)) {
|
|
1435
|
+
await bundle.writeText(f.relativePath, f.content ?? "");
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1283
1439
|
export class SdlcExtension {
|
|
1284
1440
|
name = "sdlc";
|
|
1285
1441
|
// v1.14.0 — s-consolidate-cognitive-policies: the 9 cognitive policy
|
|
@@ -1302,6 +1458,12 @@ export class SdlcExtension {
|
|
|
1302
1458
|
// v1.10.0 — f-reference-citation-kind (ported from Python for
|
|
1303
1459
|
// s-alias-generated-not-typed: Spike.depFilters → "sdlc-reference").
|
|
1304
1460
|
kernel.kind(new ReferenceKind());
|
|
1461
|
+
// s-dx-html-artifact-kind — HTML page as a first-class work-item output.
|
|
1462
|
+
// Bundle Kind with a custom reader/writer for byte-faithful HTML,
|
|
1463
|
+
// mirroring the Soul (SOUL.md + soul.json) mechanic.
|
|
1464
|
+
kernel.kind(new HtmlArtifactKind());
|
|
1465
|
+
kernel.reader(new HtmlArtifactReader());
|
|
1466
|
+
kernel.writer(new HtmlArtifactWriter());
|
|
1305
1467
|
// expr batch B: PromptTemplate is a descriptor now — registered via the
|
|
1306
1468
|
// loadDescriptors loop below. s-consolidate-cognitive-policies: the
|
|
1307
1469
|
// cognitive policy family is ONE descriptor (cognitive-policy.kind.yaml).
|
package/dist/index.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export { ReportBuilder } from "./kernel/reports.js";
|
|
|
22
22
|
export { serializeRawToFiles } from "./kernel/serialize-to-files.js";
|
|
23
23
|
export * from "./viz/index.js";
|
|
24
24
|
export { createKernelWithBuiltins, quickInstance, createRuntimeWithBuiltins, quickManifest, fromConfig } from "./bootstrap.js";
|
|
25
|
-
export { AgentNotFound } from "./kernel/errors.js";
|
|
25
|
+
export { AgentNotFound, UnknownLayout } from "./kernel/errors.js";
|
|
26
26
|
export { PromptLibrary, loadPrompts } from "./prompts.js";
|
|
27
27
|
export { loadConfig, findConfig, CONFIG_FILENAME } from "./config.js";
|
|
28
28
|
export type { DnaConfig, SearchMode, EmbeddingMode } from "./config.js";
|
package/dist/index.js
CHANGED
|
@@ -27,7 +27,7 @@ export * from "./viz/index.js";
|
|
|
27
27
|
export { createKernelWithBuiltins, quickInstance, createRuntimeWithBuiltins, quickManifest, fromConfig } from "./bootstrap.js";
|
|
28
28
|
// DX consumer surface (s-dx-*): fail-loud prompt building + the collapse-the-
|
|
29
29
|
// shim helper + declarative port wiring.
|
|
30
|
-
export { AgentNotFound } from "./kernel/errors.js";
|
|
30
|
+
export { AgentNotFound, UnknownLayout } from "./kernel/errors.js";
|
|
31
31
|
export { PromptLibrary, loadPrompts } from "./prompts.js";
|
|
32
32
|
export { loadConfig, findConfig, CONFIG_FILENAME } from "./config.js";
|
|
33
33
|
export { sourceFromUrl, resolveDefaultFsUrl, UnsupportedSourceScheme } from "./adapters/source-url.js";
|
package/dist/kernel/errors.d.ts
CHANGED
|
@@ -31,6 +31,23 @@ export declare class AgentNotFound extends Error {
|
|
|
31
31
|
readonly agent: string | null;
|
|
32
32
|
constructor(agent: string | null);
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* `buildPrompt` hit an Agent whose `layout:` names a preset the Kind does not
|
|
36
|
+
* offer (s-dx-named-layouts).
|
|
37
|
+
*
|
|
38
|
+
* Fail-loud DX: a typo'd layout (`persona_first` for `persona-first`) must not
|
|
39
|
+
* silently fall through to the Kind default and compose in the wrong order —
|
|
40
|
+
* it throws with the valid names listed.
|
|
41
|
+
*
|
|
42
|
+
* 1:1 parity with python `dna.UnknownLayout` (a `ValueError` subclass).
|
|
43
|
+
* Exported publicly from the package root.
|
|
44
|
+
*/
|
|
45
|
+
export declare class UnknownLayout extends Error {
|
|
46
|
+
readonly layout: string;
|
|
47
|
+
readonly available: string[];
|
|
48
|
+
readonly agent: string | null;
|
|
49
|
+
constructor(layout: string, available?: string[], agent?: string | null);
|
|
50
|
+
}
|
|
34
51
|
/** Base class for kernel registration validation failures. */
|
|
35
52
|
export declare class KernelRegistrationError extends Error {
|
|
36
53
|
constructor(message?: string);
|
package/dist/kernel/errors.js
CHANGED
|
@@ -36,6 +36,32 @@ export class AgentNotFound extends Error {
|
|
|
36
36
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* `buildPrompt` hit an Agent whose `layout:` names a preset the Kind does not
|
|
41
|
+
* offer (s-dx-named-layouts).
|
|
42
|
+
*
|
|
43
|
+
* Fail-loud DX: a typo'd layout (`persona_first` for `persona-first`) must not
|
|
44
|
+
* silently fall through to the Kind default and compose in the wrong order —
|
|
45
|
+
* it throws with the valid names listed.
|
|
46
|
+
*
|
|
47
|
+
* 1:1 parity with python `dna.UnknownLayout` (a `ValueError` subclass).
|
|
48
|
+
* Exported publicly from the package root.
|
|
49
|
+
*/
|
|
50
|
+
export class UnknownLayout extends Error {
|
|
51
|
+
layout;
|
|
52
|
+
available;
|
|
53
|
+
agent;
|
|
54
|
+
constructor(layout, available = [], agent = null) {
|
|
55
|
+
const where = agent ? ` on agent '${agent}'` : "";
|
|
56
|
+
const hint = available.length ? ` — available: ${available.join(", ")}` : "";
|
|
57
|
+
super(`Unknown layout '${layout}'${where}${hint}`);
|
|
58
|
+
this.name = "UnknownLayout";
|
|
59
|
+
this.layout = layout;
|
|
60
|
+
this.available = available;
|
|
61
|
+
this.agent = agent;
|
|
62
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
39
65
|
/** Base class for kernel registration validation failures. */
|
|
40
66
|
export class KernelRegistrationError extends Error {
|
|
41
67
|
constructor(message) {
|
|
@@ -94,6 +94,19 @@ export declare abstract class KindBase implements Omit<KindPort, "apiVersion" |
|
|
|
94
94
|
describe(_doc: Document): string | null;
|
|
95
95
|
summary(doc: Document): Record<string, unknown> | null;
|
|
96
96
|
promptTemplate(): string | null;
|
|
97
|
+
/**
|
|
98
|
+
* Resolve a NAMED composition layout to an embedded template
|
|
99
|
+
* (s-dx-named-layouts). Prompt-target Kinds override this to expose
|
|
100
|
+
* author-friendly presets (persona-first, instruction-first) so the common
|
|
101
|
+
* case never hand-writes Mustache. Returns null for an unknown name (the
|
|
102
|
+
* prompt builder fails loud). Twin of Python ``KindBase.layout_template``.
|
|
103
|
+
*/
|
|
104
|
+
layoutTemplate(_name: string): string | null;
|
|
105
|
+
/**
|
|
106
|
+
* Public layout names this Kind offers (s-dx-named-layouts) — powers
|
|
107
|
+
* discovery + fail-loud error messages. Twin of Python ``layout_names``.
|
|
108
|
+
*/
|
|
109
|
+
layoutNames(): string[];
|
|
97
110
|
protected canonicalSpec(spec: Record<string, unknown>): Record<string, unknown>;
|
|
98
111
|
/** Stable SHA-256 of the doc's authored identity — basis for source
|
|
99
112
|
* diff/sync. Invariant to key order, formatting, volatile stamps, and
|
package/dist/kernel/kind_base.js
CHANGED
|
@@ -215,6 +215,23 @@ export class KindBase {
|
|
|
215
215
|
promptTemplate() {
|
|
216
216
|
return null;
|
|
217
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Resolve a NAMED composition layout to an embedded template
|
|
220
|
+
* (s-dx-named-layouts). Prompt-target Kinds override this to expose
|
|
221
|
+
* author-friendly presets (persona-first, instruction-first) so the common
|
|
222
|
+
* case never hand-writes Mustache. Returns null for an unknown name (the
|
|
223
|
+
* prompt builder fails loud). Twin of Python ``KindBase.layout_template``.
|
|
224
|
+
*/
|
|
225
|
+
layoutTemplate(_name) {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Public layout names this Kind offers (s-dx-named-layouts) — powers
|
|
230
|
+
* discovery + fail-loud error messages. Twin of Python ``layout_names``.
|
|
231
|
+
*/
|
|
232
|
+
layoutNames() {
|
|
233
|
+
return [];
|
|
234
|
+
}
|
|
218
235
|
// ---- Source-sync digest (s-sync-s1; twin of Python canonical_digest) ----
|
|
219
236
|
canonicalSpec(spec) {
|
|
220
237
|
const out = {};
|
package/dist/kernel/models.d.ts
CHANGED
|
@@ -384,6 +384,7 @@ export declare const AgentSpecSchema: z.ZodObject<{
|
|
|
384
384
|
tags: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
385
385
|
guardrails: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
386
386
|
promptTemplate: z.ZodOptional<z.ZodString>;
|
|
387
|
+
layout: z.ZodOptional<z.ZodString>;
|
|
387
388
|
tool_groups: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
388
389
|
mcp_servers: z.ZodDefault<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodObject<{
|
|
389
390
|
ref: z.ZodString;
|
|
@@ -481,6 +482,7 @@ export declare const AgentSpecSchema: z.ZodObject<{
|
|
|
481
482
|
reads: Record<string, Record<string, any>>;
|
|
482
483
|
type?: string | undefined;
|
|
483
484
|
promptTemplate?: string | undefined;
|
|
485
|
+
layout?: string | undefined;
|
|
484
486
|
model?: string | undefined;
|
|
485
487
|
instruction_file?: string | undefined;
|
|
486
488
|
soul?: string | undefined;
|
|
@@ -517,6 +519,7 @@ export declare const AgentSpecSchema: z.ZodObject<{
|
|
|
517
519
|
guardrails?: string[] | undefined;
|
|
518
520
|
instruction?: string | undefined;
|
|
519
521
|
promptTemplate?: string | undefined;
|
|
522
|
+
layout?: string | undefined;
|
|
520
523
|
model?: string | undefined;
|
|
521
524
|
instruction_file?: string | undefined;
|
|
522
525
|
tags?: string[] | undefined;
|
|
@@ -601,6 +604,7 @@ export declare const AgentSchema: z.ZodObject<{
|
|
|
601
604
|
tags: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
602
605
|
guardrails: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
603
606
|
promptTemplate: z.ZodOptional<z.ZodString>;
|
|
607
|
+
layout: z.ZodOptional<z.ZodString>;
|
|
604
608
|
tool_groups: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
605
609
|
mcp_servers: z.ZodDefault<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodObject<{
|
|
606
610
|
ref: z.ZodString;
|
|
@@ -698,6 +702,7 @@ export declare const AgentSchema: z.ZodObject<{
|
|
|
698
702
|
reads: Record<string, Record<string, any>>;
|
|
699
703
|
type?: string | undefined;
|
|
700
704
|
promptTemplate?: string | undefined;
|
|
705
|
+
layout?: string | undefined;
|
|
701
706
|
model?: string | undefined;
|
|
702
707
|
instruction_file?: string | undefined;
|
|
703
708
|
soul?: string | undefined;
|
|
@@ -734,6 +739,7 @@ export declare const AgentSchema: z.ZodObject<{
|
|
|
734
739
|
guardrails?: string[] | undefined;
|
|
735
740
|
instruction?: string | undefined;
|
|
736
741
|
promptTemplate?: string | undefined;
|
|
742
|
+
layout?: string | undefined;
|
|
737
743
|
model?: string | undefined;
|
|
738
744
|
instruction_file?: string | undefined;
|
|
739
745
|
tags?: string[] | undefined;
|
|
@@ -810,6 +816,7 @@ export declare const AgentSchema: z.ZodObject<{
|
|
|
810
816
|
reads: Record<string, Record<string, any>>;
|
|
811
817
|
type?: string | undefined;
|
|
812
818
|
promptTemplate?: string | undefined;
|
|
819
|
+
layout?: string | undefined;
|
|
813
820
|
model?: string | undefined;
|
|
814
821
|
instruction_file?: string | undefined;
|
|
815
822
|
soul?: string | undefined;
|
|
@@ -860,6 +867,7 @@ export declare const AgentSchema: z.ZodObject<{
|
|
|
860
867
|
guardrails?: string[] | undefined;
|
|
861
868
|
instruction?: string | undefined;
|
|
862
869
|
promptTemplate?: string | undefined;
|
|
870
|
+
layout?: string | undefined;
|
|
863
871
|
model?: string | undefined;
|
|
864
872
|
instruction_file?: string | undefined;
|
|
865
873
|
tags?: string[] | undefined;
|
|
@@ -1551,6 +1559,83 @@ export declare const SoulSchema: z.ZodObject<{
|
|
|
1551
1559
|
} | undefined;
|
|
1552
1560
|
}>;
|
|
1553
1561
|
export type TypedSoul = z.output<typeof SoulSchema>;
|
|
1562
|
+
export declare const HtmlArtifactSpecSchema: z.ZodObject<{
|
|
1563
|
+
html: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
1564
|
+
artifact_json: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1565
|
+
}, "strip", z.ZodTypeAny, {
|
|
1566
|
+
html: string;
|
|
1567
|
+
artifact_json?: Record<string, unknown> | undefined;
|
|
1568
|
+
}, {
|
|
1569
|
+
html?: string | undefined;
|
|
1570
|
+
artifact_json?: Record<string, unknown> | undefined;
|
|
1571
|
+
}>;
|
|
1572
|
+
export declare const HtmlArtifactSchema: z.ZodObject<{
|
|
1573
|
+
apiVersion: z.ZodLiteral<"github.com/ruinosus/dna/sdlc/v1">;
|
|
1574
|
+
kind: z.ZodLiteral<"HtmlArtifact">;
|
|
1575
|
+
metadata: z.ZodObject<{
|
|
1576
|
+
name: z.ZodString;
|
|
1577
|
+
description: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
1578
|
+
version: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
1579
|
+
icon: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
1580
|
+
group: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
1581
|
+
labels: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1582
|
+
}, "strip", z.ZodTypeAny, {
|
|
1583
|
+
name: string;
|
|
1584
|
+
description: string;
|
|
1585
|
+
version: string;
|
|
1586
|
+
icon: string;
|
|
1587
|
+
group: string;
|
|
1588
|
+
labels: Record<string, string>;
|
|
1589
|
+
}, {
|
|
1590
|
+
name: string;
|
|
1591
|
+
description?: string | undefined;
|
|
1592
|
+
version?: string | undefined;
|
|
1593
|
+
icon?: string | undefined;
|
|
1594
|
+
group?: string | undefined;
|
|
1595
|
+
labels?: Record<string, string> | undefined;
|
|
1596
|
+
}>;
|
|
1597
|
+
spec: z.ZodDefault<z.ZodObject<{
|
|
1598
|
+
html: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
1599
|
+
artifact_json: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1600
|
+
}, "strip", z.ZodTypeAny, {
|
|
1601
|
+
html: string;
|
|
1602
|
+
artifact_json?: Record<string, unknown> | undefined;
|
|
1603
|
+
}, {
|
|
1604
|
+
html?: string | undefined;
|
|
1605
|
+
artifact_json?: Record<string, unknown> | undefined;
|
|
1606
|
+
}>>;
|
|
1607
|
+
}, "strip", z.ZodTypeAny, {
|
|
1608
|
+
metadata: {
|
|
1609
|
+
name: string;
|
|
1610
|
+
description: string;
|
|
1611
|
+
version: string;
|
|
1612
|
+
icon: string;
|
|
1613
|
+
group: string;
|
|
1614
|
+
labels: Record<string, string>;
|
|
1615
|
+
};
|
|
1616
|
+
spec: {
|
|
1617
|
+
html: string;
|
|
1618
|
+
artifact_json?: Record<string, unknown> | undefined;
|
|
1619
|
+
};
|
|
1620
|
+
apiVersion: "github.com/ruinosus/dna/sdlc/v1";
|
|
1621
|
+
kind: "HtmlArtifact";
|
|
1622
|
+
}, {
|
|
1623
|
+
metadata: {
|
|
1624
|
+
name: string;
|
|
1625
|
+
description?: string | undefined;
|
|
1626
|
+
version?: string | undefined;
|
|
1627
|
+
icon?: string | undefined;
|
|
1628
|
+
group?: string | undefined;
|
|
1629
|
+
labels?: Record<string, string> | undefined;
|
|
1630
|
+
};
|
|
1631
|
+
apiVersion: "github.com/ruinosus/dna/sdlc/v1";
|
|
1632
|
+
kind: "HtmlArtifact";
|
|
1633
|
+
spec?: {
|
|
1634
|
+
html?: string | undefined;
|
|
1635
|
+
artifact_json?: Record<string, unknown> | undefined;
|
|
1636
|
+
} | undefined;
|
|
1637
|
+
}>;
|
|
1638
|
+
export type TypedHtmlArtifact = z.output<typeof HtmlArtifactSchema>;
|
|
1554
1639
|
export declare const AgentDefinitionSpecSchema: z.ZodObject<{
|
|
1555
1640
|
content: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
1556
1641
|
}, "strip", z.ZodTypeAny, {
|
package/dist/kernel/models.js
CHANGED
|
@@ -128,6 +128,12 @@ export const AgentSpecSchema = z.object({
|
|
|
128
128
|
tags: z.array(z.string()).default([]),
|
|
129
129
|
guardrails: z.array(z.string()).default([]),
|
|
130
130
|
promptTemplate: z.string().optional(),
|
|
131
|
+
// s-dx-named-layouts — pick the composition ORDER by name instead of
|
|
132
|
+
// hand-writing raw Mustache. "persona-first" puts the Soul before the
|
|
133
|
+
// instruction; "instruction-first" (a.k.a. "default") keeps the historic
|
|
134
|
+
// order. Resolved by the Kind's layoutTemplate() into an embedded preset.
|
|
135
|
+
// A raw promptTemplate still wins over layout when both are set.
|
|
136
|
+
layout: z.string().optional(),
|
|
131
137
|
// Phase 14x — tool-group specialization (TS parity with Python).
|
|
132
138
|
tool_groups: z.array(z.string()).default([]),
|
|
133
139
|
// s-mcp-servers-on-agent (2026-07-07, spec
|
|
@@ -393,6 +399,19 @@ export const SoulSchema = z.object({
|
|
|
393
399
|
spec: SoulSpecSchema.default({}),
|
|
394
400
|
});
|
|
395
401
|
// ---------------------------------------------------------------------------
|
|
402
|
+
// HtmlArtifact (github.com/ruinosus/dna/sdlc/v1)
|
|
403
|
+
// ---------------------------------------------------------------------------
|
|
404
|
+
export const HtmlArtifactSpecSchema = z.object({
|
|
405
|
+
html: z.string().optional().default(""),
|
|
406
|
+
artifact_json: z.record(z.unknown()).optional(),
|
|
407
|
+
});
|
|
408
|
+
export const HtmlArtifactSchema = z.object({
|
|
409
|
+
apiVersion: z.literal("github.com/ruinosus/dna/sdlc/v1"),
|
|
410
|
+
kind: z.literal("HtmlArtifact"),
|
|
411
|
+
metadata: MetadataSchema,
|
|
412
|
+
spec: HtmlArtifactSpecSchema.default({}),
|
|
413
|
+
});
|
|
414
|
+
// ---------------------------------------------------------------------------
|
|
396
415
|
// AgentDefinition (agents.md/v1)
|
|
397
416
|
// ---------------------------------------------------------------------------
|
|
398
417
|
export const AgentDefinitionSpecSchema = z.object({
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import Mustache from "mustache";
|
|
12
12
|
import { stripPromptBlock } from "./_text.js";
|
|
13
|
-
import { AgentNotFound } from "./errors.js";
|
|
13
|
+
import { AgentNotFound, UnknownLayout } from "./errors.js";
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
15
|
// PromptBuilder
|
|
16
16
|
// ---------------------------------------------------------------------------
|
|
@@ -206,22 +206,33 @@ export class PromptBuilder {
|
|
|
206
206
|
async _renderPrompt(ctx, agentDoc) {
|
|
207
207
|
const agentSpec = agentDoc.spec;
|
|
208
208
|
const kinds = this.host._kinds;
|
|
209
|
-
// 1. Agent-level template override
|
|
209
|
+
// 1. Agent-level raw template override (poweruser escape hatch).
|
|
210
210
|
const agentTemplate = agentSpec.promptTemplate ??
|
|
211
211
|
agentSpec.prompt_template ??
|
|
212
212
|
null;
|
|
213
213
|
if (agentTemplate) {
|
|
214
214
|
return await this._mustacheRender(agentTemplate, ctx);
|
|
215
215
|
}
|
|
216
|
-
// 2. Kind default template
|
|
217
216
|
const agentKp = kinds.get(`${agentDoc.apiVersion}\0${agentDoc.kind}`);
|
|
217
|
+
// 2. Named layout preset (s-dx-named-layouts) — author picks the
|
|
218
|
+
// composition order by NAME; the kernel resolves it to an embedded
|
|
219
|
+
// template so the common case never hand-writes Mustache.
|
|
220
|
+
const layout = agentSpec.layout;
|
|
221
|
+
if (layout && agentKp) {
|
|
222
|
+
const layoutTmpl = agentKp.layoutTemplate(layout);
|
|
223
|
+
if (layoutTmpl == null) {
|
|
224
|
+
throw new UnknownLayout(layout, agentKp.layoutNames(), agentDoc.name);
|
|
225
|
+
}
|
|
226
|
+
return await this._mustacheRender(layoutTmpl, ctx);
|
|
227
|
+
}
|
|
228
|
+
// 3. Kind default template
|
|
218
229
|
if (agentKp) {
|
|
219
230
|
const kindTemplate = agentKp.promptTemplate();
|
|
220
231
|
if (kindTemplate) {
|
|
221
232
|
return await this._mustacheRender(kindTemplate, ctx);
|
|
222
233
|
}
|
|
223
234
|
}
|
|
224
|
-
//
|
|
235
|
+
// 4. Fallback: agent instruction as plain text
|
|
225
236
|
const agent = ctx.agent;
|
|
226
237
|
return agent?.instruction ?? "";
|
|
227
238
|
}
|