intentdna 1.6.5 → 1.7.4
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +26 -15
- package/dist/cli/commands/compile.js +2 -47
- package/dist/cli/commands/context.d.ts +8 -0
- package/dist/cli/commands/context.js +63 -0
- package/dist/cli/commands/feedback.d.ts +3 -2
- package/dist/cli/commands/feedback.js +16 -5
- package/dist/cli/commands/init.js +11 -63
- package/dist/cli/commands/run.js +5 -4
- package/dist/cli/commands/show.js +2 -38
- package/dist/cli/commands/sync.d.ts +9 -6
- package/dist/cli/commands/sync.js +191 -186
- package/dist/cli/commands/templates.d.ts +10 -1
- package/dist/cli/commands/templates.js +50 -1
- package/dist/cli/commands/validate.js +15 -9
- package/dist/cli/commands/verify.d.ts +32 -0
- package/dist/cli/commands/verify.js +270 -31
- package/dist/cli/index.js +78 -11
- package/dist/compiler/activate.js +11 -6
- package/dist/compiler/cascade.d.ts +5 -1
- package/dist/compiler/cascade.js +74 -1
- package/dist/compiler/compile.js +38 -0
- package/dist/compiler/diagnostics.d.ts +17 -0
- package/dist/compiler/diagnostics.js +30 -0
- package/dist/compiler/index.d.ts +7 -0
- package/dist/compiler/index.js +13 -13
- package/dist/compiler/input-resolver.d.ts +32 -0
- package/dist/compiler/input-resolver.js +281 -0
- package/dist/compiler/provenance.d.ts +8 -0
- package/dist/compiler/provenance.js +127 -0
- package/dist/governance/index.d.ts +4 -3
- package/dist/governance/index.js +3 -4
- package/dist/governance/runtime-decision-event.d.ts +85 -0
- package/dist/governance/runtime-decision-event.js +231 -0
- package/dist/governance/types.d.ts +3 -3
- package/dist/governance/types.js +3 -3
- package/dist/hooks/cli.d.ts +10 -1
- package/dist/hooks/cli.js +199 -35
- package/dist/hooks/state.d.ts +5 -10
- package/dist/hooks/state.js +170 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp/index.js +2 -0
- package/dist/mcp/tools-compile.js +18 -49
- package/dist/mcp/tools-context.d.ts +2 -0
- package/dist/mcp/tools-context.js +85 -0
- package/dist/mcp/tools-enforce.d.ts +2 -2
- package/dist/mcp/tools-enforce.js +19 -49
- package/dist/mcp/tools-observability.js +26 -2
- package/dist/mcp/tools-state.d.ts +1 -1
- package/dist/mcp/tools-state.js +17 -7
- package/dist/report/kernel-report.d.ts +27 -0
- package/dist/report/kernel-report.js +60 -19
- package/dist/report/kernel-signals.d.ts +5 -2
- package/dist/report/kernel-signals.js +87 -2
- package/dist/report/report-package.d.ts +64 -0
- package/dist/report/report-package.js +90 -0
- package/dist/runtime/agent-md.d.ts +1 -0
- package/dist/runtime/agent-md.js +21 -3
- package/dist/runtime/claude-sdk.d.ts +9 -4
- package/dist/runtime/claude-sdk.js +9 -0
- package/dist/runtime/context-sources.d.ts +14 -0
- package/dist/runtime/context-sources.js +60 -0
- package/dist/runtime/plugin-adapter.d.ts +5 -1
- package/dist/runtime/plugin-adapter.js +2 -0
- package/dist/runtime/skill-adapter.d.ts +32 -4
- package/dist/runtime/skill-adapter.js +184 -9
- package/dist/runtime/workflow-runner.d.ts +1 -1
- package/dist/runtime/workflow-runner.js +1 -1
- package/dist/schema/types.d.ts +84 -0
- package/dist/schema/validate.js +156 -2
- package/dist/schema/validators/controllers.js +16 -0
- package/dist/signals/index.d.ts +10 -0
- package/dist/signals/index.js +90 -5
- package/dist/templates/catalog.d.ts +19 -0
- package/dist/templates/catalog.js +57 -0
- package/dist/templates/flutter-rewrite.dna.yaml +2 -2
- package/package.json +1 -1
- package/spec/README.md +1 -1
- package/spec/foundation-hardening.md +2 -1
- package/spec/schema-spec.md +78 -1
package/dist/cli/index.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* help Show this help message
|
|
13
13
|
*/
|
|
14
14
|
import { parseArgs } from "node:util";
|
|
15
|
-
const HELP = `Intent DNA CLI
|
|
15
|
+
const HELP = `Intent DNA CLI v1.7.0
|
|
16
16
|
|
|
17
17
|
Usage: dna <command> [options]
|
|
18
18
|
|
|
@@ -29,7 +29,8 @@ Commands:
|
|
|
29
29
|
show Show gene expression state
|
|
30
30
|
evolve Preview epigenetic marker changes from persisted outcomes
|
|
31
31
|
epigenetic Record outcomes, view markers and summaries
|
|
32
|
-
feedback Build local kernel report (--days <N>, --json, --evolve preview, --dna-id <id>)
|
|
32
|
+
feedback Build local kernel report (--days <N>, --json, --package, --evolve preview, --dna-id <id>)
|
|
33
|
+
context Inspect planning-only advisory context sources
|
|
33
34
|
templates Template management (deploy to global install)
|
|
34
35
|
|
|
35
36
|
Options:
|
|
@@ -68,15 +69,39 @@ Examples:
|
|
|
68
69
|
dna evolve my_dna_id Preview marker changes without persisting
|
|
69
70
|
dna evolve my_dna_id --apply Unsupported in this kernel; use sync --evolve for explicit mutation
|
|
70
71
|
`;
|
|
72
|
+
const COMMAND_HELP = {
|
|
73
|
+
sync: `Usage: dna sync [files...] [options]\n\nOptions:\n --mode auto|plugin|bin Sync mode (default: auto)\n --dry-run Print planned outputs without writing files\n --post-summary Print registry-backed output summary\n --target <target> Markdown target for injection\n --inject <path> File to inject markdown into\n --agents <dir> Generate agent files\n --skills <dir> Generate skill files\n --workflow <dir> Generate workflow shell scripts\n --settings <path> Write hook settings in bin mode\n --lock <path> Write lock file (default .dna/lock)\n`,
|
|
74
|
+
verify: `Usage: dna verify [--lock <path>] [--stats] [--health] [--strict]\n\nOptions:\n --health Comprehensive installation health check\n --stats Show hook call statistics\n --strict Require valid RuntimeDecisionEvent enterprise evidence\n --lock <path> Lock file path (default .dna/lock)\n`,
|
|
75
|
+
templates: `Usage: dna templates <list|show|deploy>\n\nSubcommands:\n list List built-in and project templates\n show <name> Show template metadata and YAML\n deploy Copy local templates to global install\n`,
|
|
76
|
+
context: `Usage: dna context <index|search|doc> [query|id] [files...]\n\nSubcommands:\n index List explicitly declared planning-only advisory context sources\n search <query> Search source metadata\n doc <id> Read a local file/doc source body\n`,
|
|
77
|
+
run: `Usage: dna run --dna <file> --workflow <name> --task <id> [options]\n\nOptions:\n --dry-run Print execution plan only\n --permission-mode <mode> Claude permission mode (default: default)\n`,
|
|
78
|
+
compile: `Usage: dna compile <files...> [--target claude-sdk] [--context <name>] [--output <path>] [--ir]\n`,
|
|
79
|
+
validate: `Usage: dna validate <files...> [--quiet]\n`,
|
|
80
|
+
show: `Usage: dna show <files...> [--context <name>] [--json]\n`,
|
|
81
|
+
init: `Usage: dna init [--template <name>|--template list|--register <path>|--upgrade <name>]\n`,
|
|
82
|
+
};
|
|
83
|
+
function commandHelp(command) {
|
|
84
|
+
return command ? COMMAND_HELP[command] : undefined;
|
|
85
|
+
}
|
|
71
86
|
async function main() {
|
|
72
87
|
const args = process.argv.slice(2);
|
|
73
88
|
const command = args[0];
|
|
74
|
-
if (!command || command === "
|
|
89
|
+
if (!command || command === "--help" || command === "-h") {
|
|
75
90
|
process.stderr.write(HELP);
|
|
76
91
|
process.exit(0);
|
|
77
92
|
}
|
|
93
|
+
if (command === "help") {
|
|
94
|
+
const help = commandHelp(args[1]);
|
|
95
|
+
process.stderr.write(help ?? HELP);
|
|
96
|
+
process.exit(0);
|
|
97
|
+
}
|
|
78
98
|
// Parse remaining args (after command)
|
|
79
99
|
const rest = args.slice(1);
|
|
100
|
+
if (rest.includes("--help") || rest.includes("-h")) {
|
|
101
|
+
const help = commandHelp(command);
|
|
102
|
+
process.stderr.write(help ?? HELP);
|
|
103
|
+
process.exit(help ? 0 : 2);
|
|
104
|
+
}
|
|
80
105
|
switch (command) {
|
|
81
106
|
case "sync": {
|
|
82
107
|
const { values, positionals } = parseArgs({
|
|
@@ -96,11 +121,19 @@ async function main() {
|
|
|
96
121
|
settings: { type: "string" },
|
|
97
122
|
lock: { type: "string", default: ".dna/lock" },
|
|
98
123
|
remove: { type: "boolean", default: false },
|
|
99
|
-
|
|
124
|
+
mode: { type: "string", default: "auto" },
|
|
125
|
+
plugin: { type: "boolean" },
|
|
126
|
+
"dry-run": { type: "boolean", default: false },
|
|
127
|
+
"post-summary": { type: "boolean", default: false },
|
|
100
128
|
},
|
|
101
129
|
allowPositionals: true,
|
|
102
130
|
strict: false,
|
|
103
131
|
});
|
|
132
|
+
const mode = values.mode;
|
|
133
|
+
if (!["auto", "plugin", "bin"].includes(mode)) {
|
|
134
|
+
process.stderr.write(`Error: --mode must be one of: auto, plugin, bin\n`);
|
|
135
|
+
process.exit(2);
|
|
136
|
+
}
|
|
104
137
|
const { runSync } = await import("./commands/sync.js");
|
|
105
138
|
const code = await runSync({
|
|
106
139
|
files: positionals,
|
|
@@ -118,7 +151,10 @@ async function main() {
|
|
|
118
151
|
settingsPath: values.settings,
|
|
119
152
|
lockFile: values.lock,
|
|
120
153
|
remove: values.remove,
|
|
154
|
+
mode: mode,
|
|
121
155
|
plugin: values.plugin,
|
|
156
|
+
dryRun: values["dry-run"],
|
|
157
|
+
postSummary: values["post-summary"],
|
|
122
158
|
});
|
|
123
159
|
process.exit(code);
|
|
124
160
|
break;
|
|
@@ -130,6 +166,7 @@ async function main() {
|
|
|
130
166
|
lock: { type: "string", default: ".dna/lock" },
|
|
131
167
|
stats: { type: "boolean", default: false },
|
|
132
168
|
health: { type: "boolean", default: false },
|
|
169
|
+
strict: { type: "boolean", default: false },
|
|
133
170
|
},
|
|
134
171
|
allowPositionals: true,
|
|
135
172
|
strict: false,
|
|
@@ -139,6 +176,7 @@ async function main() {
|
|
|
139
176
|
lockFile: verifyValues.lock,
|
|
140
177
|
stats: verifyValues.stats,
|
|
141
178
|
health: verifyValues.health,
|
|
179
|
+
strict: verifyValues.strict,
|
|
142
180
|
});
|
|
143
181
|
process.exit(code);
|
|
144
182
|
break;
|
|
@@ -413,6 +451,25 @@ async function main() {
|
|
|
413
451
|
process.exit(code);
|
|
414
452
|
break;
|
|
415
453
|
}
|
|
454
|
+
case "context": {
|
|
455
|
+
const subcommand = rest[0] ?? "index";
|
|
456
|
+
const contextRest = rest.slice(1);
|
|
457
|
+
const { positionals } = parseArgs({
|
|
458
|
+
args: contextRest,
|
|
459
|
+
options: {},
|
|
460
|
+
allowPositionals: true,
|
|
461
|
+
strict: false,
|
|
462
|
+
});
|
|
463
|
+
const { runContext } = await import("./commands/context.js");
|
|
464
|
+
const code = await runContext({
|
|
465
|
+
subcommand,
|
|
466
|
+
query: subcommand === "search" ? positionals[0] : undefined,
|
|
467
|
+
id: subcommand === "doc" ? positionals[0] : undefined,
|
|
468
|
+
files: subcommand === "index" ? positionals : positionals.slice(1),
|
|
469
|
+
});
|
|
470
|
+
process.exit(code);
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
416
473
|
case "feedback": {
|
|
417
474
|
const { values: fbValues } = parseArgs({
|
|
418
475
|
args: rest,
|
|
@@ -420,6 +477,7 @@ async function main() {
|
|
|
420
477
|
days: { type: "string", short: "d", default: "7" },
|
|
421
478
|
json: { type: "boolean", default: false },
|
|
422
479
|
evolve: { type: "boolean", default: false },
|
|
480
|
+
package: { type: "boolean", default: false },
|
|
423
481
|
"dna-id": { type: "string" },
|
|
424
482
|
},
|
|
425
483
|
strict: false,
|
|
@@ -429,20 +487,29 @@ async function main() {
|
|
|
429
487
|
days: parseInt(fbValues.days, 10) || 7,
|
|
430
488
|
json: fbValues.json,
|
|
431
489
|
evolve: fbValues.evolve,
|
|
490
|
+
packageReport: fbValues.package,
|
|
432
491
|
dnaId: fbValues["dna-id"],
|
|
433
492
|
});
|
|
434
493
|
process.exit(code);
|
|
435
494
|
break;
|
|
436
495
|
}
|
|
437
496
|
case "templates": {
|
|
438
|
-
const subcommand = rest[0] ?? "";
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
497
|
+
const subcommand = rest[0] ?? "list";
|
|
498
|
+
const { runTemplatesDeploy, runTemplatesList, runTemplatesShow } = await import("./commands/templates.js");
|
|
499
|
+
if (subcommand === "list") {
|
|
500
|
+
const code = await runTemplatesList();
|
|
501
|
+
process.exit(code);
|
|
442
502
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
503
|
+
if (subcommand === "show") {
|
|
504
|
+
const code = await runTemplatesShow({ name: rest[1] ?? "" });
|
|
505
|
+
process.exit(code);
|
|
506
|
+
}
|
|
507
|
+
if (subcommand === "deploy") {
|
|
508
|
+
const code = await runTemplatesDeploy();
|
|
509
|
+
process.exit(code);
|
|
510
|
+
}
|
|
511
|
+
process.stderr.write(COMMAND_HELP.templates);
|
|
512
|
+
process.exit(2);
|
|
446
513
|
break;
|
|
447
514
|
}
|
|
448
515
|
default:
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
/**
|
|
11
11
|
* Apply a modifier to a gene's expression level.
|
|
12
12
|
*/
|
|
13
|
-
function applyModifier(level, mod) {
|
|
13
|
+
function applyModifier(level, mod, protectedThreshold = false) {
|
|
14
|
+
if (protectedThreshold && (mod.action === "deactivate" || mod.action === "suppress"))
|
|
15
|
+
return Math.max(level, 1.0);
|
|
14
16
|
switch (mod.action) {
|
|
15
17
|
case "amplify":
|
|
16
18
|
return level * (mod.factor ?? 2.0);
|
|
@@ -28,7 +30,7 @@ function applyModifier(level, mod) {
|
|
|
28
30
|
* Apply epigenetic markers to gene expression levels.
|
|
29
31
|
* Markers decay over time based on their decay factor and age.
|
|
30
32
|
*/
|
|
31
|
-
function applyEpigeneticMarkers(genes, markers) {
|
|
33
|
+
function applyEpigeneticMarkers(genes, markers, protectedThresholdGenes) {
|
|
32
34
|
const now = Date.now();
|
|
33
35
|
for (const marker of markers) {
|
|
34
36
|
// Calculate decay based on time elapsed
|
|
@@ -40,6 +42,8 @@ function applyEpigeneticMarkers(genes, markers) {
|
|
|
40
42
|
continue; // marker too old, skip
|
|
41
43
|
for (const effect of marker.effects) {
|
|
42
44
|
if (effect.gene && genes[effect.gene] && effect.action && effect.factor) {
|
|
45
|
+
if (protectedThresholdGenes.has(effect.gene) && effect.action === "suppress")
|
|
46
|
+
continue;
|
|
43
47
|
const gene = genes[effect.gene];
|
|
44
48
|
const effectiveFactor = 1 + (effect.factor - 1) * decayedStrength;
|
|
45
49
|
if (effect.action === "amplify") {
|
|
@@ -77,18 +81,19 @@ export function activateDNA(cascaded, contextName = null, activeRole = null) {
|
|
|
77
81
|
role: gene.role,
|
|
78
82
|
};
|
|
79
83
|
}
|
|
84
|
+
const protectedThresholdGenes = new Set(cascaded.protected_threshold_genes ?? []);
|
|
80
85
|
// Apply context modifiers if a context is active
|
|
81
86
|
if (contextName && cascaded.contexts[contextName]) {
|
|
82
87
|
const ctx = cascaded.contexts[contextName];
|
|
83
88
|
// Apply gene modifiers
|
|
84
89
|
for (const mod of ctx.modifiers ?? []) {
|
|
85
90
|
if (activated[mod.gene]) {
|
|
86
|
-
activated[mod.gene].expression_level = applyModifier(activated[mod.gene].expression_level, mod);
|
|
91
|
+
activated[mod.gene].expression_level = applyModifier(activated[mod.gene].expression_level, mod, protectedThresholdGenes.has(mod.gene));
|
|
87
92
|
}
|
|
88
93
|
}
|
|
89
94
|
// Deactivate genes
|
|
90
95
|
for (const g of ctx.deactivate_genes ?? []) {
|
|
91
|
-
if (activated[g]) {
|
|
96
|
+
if (activated[g] && !protectedThresholdGenes.has(g)) {
|
|
92
97
|
activated[g].expression_level = 0;
|
|
93
98
|
}
|
|
94
99
|
}
|
|
@@ -125,13 +130,13 @@ export function activateDNA(cascaded, contextName = null, activeRole = null) {
|
|
|
125
130
|
}
|
|
126
131
|
// Suppress genes
|
|
127
132
|
for (const geneName of role.suppresses_genes ?? []) {
|
|
128
|
-
if (activated[geneName]) {
|
|
133
|
+
if (activated[geneName] && !protectedThresholdGenes.has(geneName)) {
|
|
129
134
|
activated[geneName].expression_level *= 0.1;
|
|
130
135
|
}
|
|
131
136
|
}
|
|
132
137
|
}
|
|
133
138
|
// Apply epigenetic markers
|
|
134
|
-
applyEpigeneticMarkers(activated, cascaded.epigenetic_markers);
|
|
139
|
+
applyEpigeneticMarkers(activated, cascaded.epigenetic_markers, protectedThresholdGenes);
|
|
135
140
|
return {
|
|
136
141
|
genes: activated,
|
|
137
142
|
active_context: contextName,
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - attract/repel: same target accumulates, different targets independent
|
|
11
11
|
* - amplify/suppress: factors multiply (1.5x × 2.0x = 3.0x)
|
|
12
12
|
*/
|
|
13
|
-
import type { IntentDNA, Gene, ContextRegion, EpigeneticMarker, RoleDef, WorkflowDef, LegibilityAssetMap, VerifierCommandPolicy, ControllerDef } from "../schema/types.js";
|
|
13
|
+
import type { IntentDNA, Gene, ContextRegion, EpigeneticMarker, RoleDef, WorkflowDef, LegibilityAssetMap, VerifierCommandPolicy, ControllerDef, AdvisoryContextSource, PlanningContext, CompiledProvenanceManifest } from "../schema/types.js";
|
|
14
14
|
export interface CascadedDNA {
|
|
15
15
|
genes: Record<string, Gene>;
|
|
16
16
|
contexts: Record<string, ContextRegion>;
|
|
@@ -27,7 +27,11 @@ export interface CascadedDNA {
|
|
|
27
27
|
per_role?: Record<string, string[]>;
|
|
28
28
|
per_workflow?: Record<string, string[]>;
|
|
29
29
|
};
|
|
30
|
+
context_sources?: AdvisoryContextSource[];
|
|
31
|
+
planning_context?: PlanningContext;
|
|
30
32
|
verifier_policy?: VerifierCommandPolicy;
|
|
33
|
+
provenance?: CompiledProvenanceManifest;
|
|
34
|
+
protected_threshold_genes?: string[];
|
|
31
35
|
}
|
|
32
36
|
/**
|
|
33
37
|
* Cascade multiple DNA layers into a single merged DNA.
|
package/dist/compiler/cascade.js
CHANGED
|
@@ -10,6 +10,21 @@
|
|
|
10
10
|
* - attract/repel: same target accumulates, different targets independent
|
|
11
11
|
* - amplify/suppress: factors multiply (1.5x × 2.0x = 3.0x)
|
|
12
12
|
*/
|
|
13
|
+
const PROTECTED_THRESHOLD_LAYERS = new Set(["species", "enterprise"]);
|
|
14
|
+
function originForDNA(dna) {
|
|
15
|
+
return {
|
|
16
|
+
source_dna_id: dna.id,
|
|
17
|
+
source_layer: dna.type,
|
|
18
|
+
cascade_priority: dna.cascade.priority,
|
|
19
|
+
protected_threshold: PROTECTED_THRESHOLD_LAYERS.has(dna.type),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function withCodonOrigins(gene, origin) {
|
|
23
|
+
return {
|
|
24
|
+
...gene,
|
|
25
|
+
codons: gene.codons.map((codon) => codon.type === "threshold" ? { ...codon, origin } : { ...codon }),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
13
28
|
/**
|
|
14
29
|
* Normalize workflow/workflows from an IntentDNA into a unified Record.
|
|
15
30
|
* Validation ensures workflow and workflows are mutually exclusive.
|
|
@@ -156,6 +171,47 @@ function mergeContextFiles(base, incoming) {
|
|
|
156
171
|
per_workflow: mergePrefixedRecords(base.per_workflow, incoming.per_workflow),
|
|
157
172
|
};
|
|
158
173
|
}
|
|
174
|
+
function prefixContextSources(sources, ns) {
|
|
175
|
+
if (!sources)
|
|
176
|
+
return undefined;
|
|
177
|
+
if (!ns)
|
|
178
|
+
return sources;
|
|
179
|
+
return sources.map((source) => ({ ...source, id: `${ns}_${source.id}` }));
|
|
180
|
+
}
|
|
181
|
+
function prefixPlanningContext(planning, ns) {
|
|
182
|
+
if (!planning)
|
|
183
|
+
return undefined;
|
|
184
|
+
if (!ns)
|
|
185
|
+
return planning;
|
|
186
|
+
return {
|
|
187
|
+
...planning,
|
|
188
|
+
sources: planning.sources.map((sourceId) => `${ns}_${sourceId}`),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function mergeContextSources(base, incoming) {
|
|
192
|
+
if (!base)
|
|
193
|
+
return incoming;
|
|
194
|
+
if (!incoming)
|
|
195
|
+
return base;
|
|
196
|
+
const merged = new Map();
|
|
197
|
+
for (const source of base)
|
|
198
|
+
merged.set(source.id, source);
|
|
199
|
+
for (const source of incoming)
|
|
200
|
+
merged.set(source.id, source);
|
|
201
|
+
return [...merged.values()];
|
|
202
|
+
}
|
|
203
|
+
function mergePlanningContext(base, incoming) {
|
|
204
|
+
if (!base)
|
|
205
|
+
return incoming;
|
|
206
|
+
if (!incoming)
|
|
207
|
+
return base;
|
|
208
|
+
return {
|
|
209
|
+
sources: incoming.sources,
|
|
210
|
+
instructions: incoming.instructions ?? base.instructions,
|
|
211
|
+
require_quotes: incoming.require_quotes ?? base.require_quotes,
|
|
212
|
+
require_attribution: incoming.require_attribution ?? base.require_attribution,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
159
215
|
function mergeVerifierPolicy(base, incoming) {
|
|
160
216
|
if (!base)
|
|
161
217
|
return incoming;
|
|
@@ -187,6 +243,7 @@ export function cascadeDNA(layers) {
|
|
|
187
243
|
const sorted = [...layers].sort((a, b) => a.cascade.priority - b.cascade.priority);
|
|
188
244
|
const mergedGenes = {};
|
|
189
245
|
const geneSourceNs = {}; // track which namespace defined each gene
|
|
246
|
+
const protectedThresholdGenes = new Set();
|
|
190
247
|
const mergedContexts = {};
|
|
191
248
|
const mergedRoles = {};
|
|
192
249
|
const mergedWorkflows = {};
|
|
@@ -198,7 +255,12 @@ export function cascadeDNA(layers) {
|
|
|
198
255
|
sourceIds.push(dna.id);
|
|
199
256
|
const ns = dna.namespace;
|
|
200
257
|
// Merge genes (cross-namespace: additive merge + warning)
|
|
201
|
-
|
|
258
|
+
const origin = originForDNA(dna);
|
|
259
|
+
for (const [name, rawGene] of Object.entries(dna.genes)) {
|
|
260
|
+
const gene = withCodonOrigins(rawGene, origin);
|
|
261
|
+
if (origin.protected_threshold && gene.codons.some((codon) => codon.type === "threshold")) {
|
|
262
|
+
protectedThresholdGenes.add(name);
|
|
263
|
+
}
|
|
202
264
|
if (mergedGenes[name]) {
|
|
203
265
|
const existingNs = geneSourceNs[name];
|
|
204
266
|
if (ns !== existingNs) {
|
|
@@ -257,6 +319,8 @@ export function cascadeDNA(layers) {
|
|
|
257
319
|
// legibility_assets/context_files: highest-priority DNA wins (last in sorted layers)
|
|
258
320
|
let legibilityAssets;
|
|
259
321
|
let contextFiles;
|
|
322
|
+
let contextSources;
|
|
323
|
+
let planningContext;
|
|
260
324
|
let verifierPolicy;
|
|
261
325
|
for (const dna of sorted) {
|
|
262
326
|
if (dna.legibility_assets) {
|
|
@@ -265,6 +329,12 @@ export function cascadeDNA(layers) {
|
|
|
265
329
|
if (dna.context_files) {
|
|
266
330
|
contextFiles = mergeContextFiles(contextFiles, prefixContextFiles(dna.context_files, dna.namespace));
|
|
267
331
|
}
|
|
332
|
+
if (dna.context_sources) {
|
|
333
|
+
contextSources = mergeContextSources(contextSources, prefixContextSources(dna.context_sources, dna.namespace));
|
|
334
|
+
}
|
|
335
|
+
if (dna.planning_context) {
|
|
336
|
+
planningContext = mergePlanningContext(planningContext, prefixPlanningContext(dna.planning_context, dna.namespace));
|
|
337
|
+
}
|
|
268
338
|
if (dna.verifier_policy) {
|
|
269
339
|
verifierPolicy = mergeVerifierPolicy(verifierPolicy, dna.verifier_policy);
|
|
270
340
|
}
|
|
@@ -280,6 +350,9 @@ export function cascadeDNA(layers) {
|
|
|
280
350
|
warnings: warnings.length > 0 ? warnings : undefined,
|
|
281
351
|
legibility_assets: legibilityAssets,
|
|
282
352
|
context_files: contextFiles,
|
|
353
|
+
context_sources: contextSources,
|
|
354
|
+
planning_context: planningContext,
|
|
283
355
|
verifier_policy: verifierPolicy,
|
|
356
|
+
protected_threshold_genes: protectedThresholdGenes.size > 0 ? [...protectedThresholdGenes].sort() : undefined,
|
|
284
357
|
};
|
|
285
358
|
}
|
package/dist/compiler/compile.js
CHANGED
|
@@ -105,6 +105,7 @@ function geneToGates(name, gene) {
|
|
|
105
105
|
action: "block",
|
|
106
106
|
message: `DNA threshold violation: ${codon.condition} (gene: ${name})`,
|
|
107
107
|
source_gene: name,
|
|
108
|
+
origin: codon.origin,
|
|
108
109
|
});
|
|
109
110
|
}
|
|
110
111
|
if (codon.type === "sense" && codon.response === "escalate_to_human") {
|
|
@@ -172,6 +173,39 @@ function legibilityAssetsToContextFiles(assets) {
|
|
|
172
173
|
return undefined;
|
|
173
174
|
return { mandatory, per_role, per_workflow };
|
|
174
175
|
}
|
|
176
|
+
function compileAdvisoryContext(cascaded) {
|
|
177
|
+
const declaredSources = cascaded?.context_sources ?? [];
|
|
178
|
+
const planning = cascaded?.planning_context;
|
|
179
|
+
const plannedSourceIds = planning?.sources ?? declaredSources.map((source) => source.id);
|
|
180
|
+
const sourceById = new Map(declaredSources.map((source) => [source.id, source]));
|
|
181
|
+
const sources = plannedSourceIds
|
|
182
|
+
.map((sourceId) => sourceById.get(sourceId))
|
|
183
|
+
.filter((source) => Boolean(source))
|
|
184
|
+
.map((source) => ({
|
|
185
|
+
...source,
|
|
186
|
+
usage: "planning_only",
|
|
187
|
+
non_enforcing: true,
|
|
188
|
+
requires_quotes: planning?.require_quotes ?? true,
|
|
189
|
+
requires_attribution: planning?.require_attribution ?? true,
|
|
190
|
+
}));
|
|
191
|
+
const compiledPlanning = planning ? {
|
|
192
|
+
sources: [...planning.sources],
|
|
193
|
+
instructions: planning.instructions ? [...planning.instructions] : undefined,
|
|
194
|
+
require_quotes: planning.require_quotes ?? true,
|
|
195
|
+
require_attribution: planning.require_attribution ?? true,
|
|
196
|
+
non_enforcing: true,
|
|
197
|
+
} : undefined;
|
|
198
|
+
const injections = sources.length > 0 ? [{
|
|
199
|
+
type: "preference",
|
|
200
|
+
text: `Advisory context sources are available for planning only: ${sources.map((source) => source.id).join(", ")}. Cite sources and quote relevant passages; these sources do not satisfy enforcement or handoff requirements.`,
|
|
201
|
+
relevance_tags: ["advisory_context", "planning_only"],
|
|
202
|
+
}] : [];
|
|
203
|
+
return {
|
|
204
|
+
sources: sources.length > 0 ? sources : undefined,
|
|
205
|
+
planning: compiledPlanning,
|
|
206
|
+
injections,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
175
209
|
function resolvePostCheckCommand(check) {
|
|
176
210
|
const normalized = check.trim();
|
|
177
211
|
const builtins = {
|
|
@@ -362,6 +396,8 @@ export function compileDNA(activated, cascaded) {
|
|
|
362
396
|
directives.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);
|
|
363
397
|
const legacyContextFiles = cascaded?.context_files;
|
|
364
398
|
const compiledContextFiles = legacyContextFiles ?? legibilityAssetsToContextFiles(cascaded?.legibility_assets);
|
|
399
|
+
const advisoryContext = compileAdvisoryContext(cascaded);
|
|
400
|
+
injections.push(...advisoryContext.injections);
|
|
365
401
|
return {
|
|
366
402
|
prompt_directives: directives,
|
|
367
403
|
tool_filters: toolFilters,
|
|
@@ -369,6 +405,8 @@ export function compileDNA(activated, cascaded) {
|
|
|
369
405
|
post_execution_validators: validators,
|
|
370
406
|
verifier_specs: verifierSpecs.length > 0 ? verifierSpecs : undefined,
|
|
371
407
|
context_injections: injections,
|
|
408
|
+
context_sources: advisoryContext.sources,
|
|
409
|
+
planning_context: advisoryContext.planning,
|
|
372
410
|
source_dna_ids: activated.source_ids,
|
|
373
411
|
compiled_at: new Date().toISOString(),
|
|
374
412
|
active_context: activated.active_context ?? undefined,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type DiagnosticSeverity = "error" | "warning" | "info";
|
|
2
|
+
export interface Diagnostic {
|
|
3
|
+
severity: DiagnosticSeverity;
|
|
4
|
+
code: string;
|
|
5
|
+
message: string;
|
|
6
|
+
file?: string;
|
|
7
|
+
path?: string;
|
|
8
|
+
hint?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class DNADiagnosticsError extends Error {
|
|
11
|
+
readonly diagnostics: Diagnostic[];
|
|
12
|
+
constructor(message: string, diagnostics: Diagnostic[]);
|
|
13
|
+
}
|
|
14
|
+
export declare function hasDiagnosticErrors(diagnostics: Diagnostic[]): boolean;
|
|
15
|
+
export declare function formatDiagnostic(diagnostic: Diagnostic): string;
|
|
16
|
+
export declare function formatDiagnostics(diagnostics: Diagnostic[]): string;
|
|
17
|
+
export declare function diagnosticsFromError(error: unknown, file?: string): Diagnostic[];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class DNADiagnosticsError extends Error {
|
|
2
|
+
diagnostics;
|
|
3
|
+
constructor(message, diagnostics) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "DNADiagnosticsError";
|
|
6
|
+
this.diagnostics = diagnostics;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function hasDiagnosticErrors(diagnostics) {
|
|
10
|
+
return diagnostics.some((diagnostic) => diagnostic.severity === "error");
|
|
11
|
+
}
|
|
12
|
+
export function formatDiagnostic(diagnostic) {
|
|
13
|
+
const location = [diagnostic.file, diagnostic.path].filter(Boolean).join(":");
|
|
14
|
+
const prefix = location ? `${location}: ` : "";
|
|
15
|
+
const hint = diagnostic.hint ? ` (${diagnostic.hint})` : "";
|
|
16
|
+
return `${diagnostic.severity.toUpperCase()} ${diagnostic.code}: ${prefix}${diagnostic.message}${hint}`;
|
|
17
|
+
}
|
|
18
|
+
export function formatDiagnostics(diagnostics) {
|
|
19
|
+
return diagnostics.map(formatDiagnostic).join("\n");
|
|
20
|
+
}
|
|
21
|
+
export function diagnosticsFromError(error, file) {
|
|
22
|
+
if (error instanceof DNADiagnosticsError)
|
|
23
|
+
return error.diagnostics;
|
|
24
|
+
return [{
|
|
25
|
+
severity: "error",
|
|
26
|
+
code: "unexpected_error",
|
|
27
|
+
message: error instanceof Error ? error.message : String(error),
|
|
28
|
+
file,
|
|
29
|
+
}];
|
|
30
|
+
}
|
package/dist/compiler/index.d.ts
CHANGED
|
@@ -9,7 +9,12 @@ export { cascadeDNA } from "./cascade.js";
|
|
|
9
9
|
export { activateDNA } from "./activate.js";
|
|
10
10
|
export { compileDNA } from "./compile.js";
|
|
11
11
|
export { compileWorkflow } from "./workflow.js";
|
|
12
|
+
export { PROVENANCE_LAYERS, PROVENANCE_SCHEMA_VERSION, attachProvenance, buildCascadeLayers, buildConstraintWinners, hashObject, hashString, } from "./provenance.js";
|
|
12
13
|
export type { CompileWorkflowOptions, CompileWorkflowResult, CompileWorkflowError, } from "./workflow.js";
|
|
14
|
+
export type { Diagnostic, DiagnosticSeverity } from "./diagnostics.js";
|
|
15
|
+
export { DNADiagnosticsError, formatDiagnostic, formatDiagnostics } from "./diagnostics.js";
|
|
16
|
+
export { assertNoNamespaceCollisions, checkNamespaceCollisions, detectDNAConfigs, expandDNAInputFiles, expandDNAInputs, loadDNAWithDiagnostics, resolveDNAInputs, resolveSpeciesReference, } from "./input-resolver.js";
|
|
17
|
+
export type { ExpandedDNAInput, ExpandDNAInputOptions } from "./input-resolver.js";
|
|
13
18
|
/**
|
|
14
19
|
* Load and parse a DNA file from disk.
|
|
15
20
|
*/
|
|
@@ -17,6 +22,8 @@ export declare function loadDNA(filePath: string): Promise<IntentDNA>;
|
|
|
17
22
|
export interface CompileOptions {
|
|
18
23
|
context?: string;
|
|
19
24
|
role?: string;
|
|
25
|
+
cwd?: string;
|
|
26
|
+
enterprisePolicyDirs?: string[];
|
|
20
27
|
/** Additional epigenetic markers from evolution store */
|
|
21
28
|
epigenetic_markers?: EpigeneticMarker[];
|
|
22
29
|
}
|
package/dist/compiler/index.js
CHANGED
|
@@ -4,29 +4,28 @@
|
|
|
4
4
|
* Full compilation pipeline:
|
|
5
5
|
* DNA files → parse → cascade → activate (+ epigenetic) → compile → IR
|
|
6
6
|
*/
|
|
7
|
-
import { readFile } from "node:fs/promises";
|
|
8
|
-
import { validateDNA } from "../schema/validate.js";
|
|
9
|
-
import { parseYAML } from "../schema/yaml-parser.js";
|
|
10
7
|
import { cascadeDNA } from "./cascade.js";
|
|
11
8
|
import { activateDNA } from "./activate.js";
|
|
12
9
|
import { compileDNA } from "./compile.js";
|
|
10
|
+
import { DNADiagnosticsError, formatDiagnostics } from "./diagnostics.js";
|
|
11
|
+
import { expandDNAInputs, loadDNAWithDiagnostics } from "./input-resolver.js";
|
|
12
|
+
import { attachProvenance } from "./provenance.js";
|
|
13
13
|
export { cascadeDNA } from "./cascade.js";
|
|
14
14
|
export { activateDNA } from "./activate.js";
|
|
15
15
|
export { compileDNA } from "./compile.js";
|
|
16
16
|
export { compileWorkflow } from "./workflow.js";
|
|
17
|
+
export { PROVENANCE_LAYERS, PROVENANCE_SCHEMA_VERSION, attachProvenance, buildCascadeLayers, buildConstraintWinners, hashObject, hashString, } from "./provenance.js";
|
|
18
|
+
export { DNADiagnosticsError, formatDiagnostic, formatDiagnostics } from "./diagnostics.js";
|
|
19
|
+
export { assertNoNamespaceCollisions, checkNamespaceCollisions, detectDNAConfigs, expandDNAInputFiles, expandDNAInputs, loadDNAWithDiagnostics, resolveDNAInputs, resolveSpeciesReference, } from "./input-resolver.js";
|
|
17
20
|
/**
|
|
18
21
|
* Load and parse a DNA file from disk.
|
|
19
22
|
*/
|
|
20
23
|
export async function loadDNA(filePath) {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const result = validateDNA(dna);
|
|
25
|
-
if (!result.valid) {
|
|
26
|
-
const messages = result.errors.map((e) => ` ${e.path}: ${e.message}`).join("\n");
|
|
27
|
-
throw new Error(`Invalid DNA file ${filePath}:\n${messages}`);
|
|
24
|
+
const result = await loadDNAWithDiagnostics(filePath);
|
|
25
|
+
if (!result.dna) {
|
|
26
|
+
throw new DNADiagnosticsError(`Invalid DNA file ${filePath}:\n${formatDiagnostics(result.diagnostics)}`, result.diagnostics);
|
|
28
27
|
}
|
|
29
|
-
return dna;
|
|
28
|
+
return result.dna;
|
|
30
29
|
}
|
|
31
30
|
/**
|
|
32
31
|
* Full compilation pipeline: load DNA files, cascade, activate context, compile to IR.
|
|
@@ -36,8 +35,9 @@ export async function compileFromFiles(filePaths, contextOrOptions) {
|
|
|
36
35
|
const opts = typeof contextOrOptions === "string"
|
|
37
36
|
? { context: contextOrOptions }
|
|
38
37
|
: contextOrOptions ?? {};
|
|
38
|
+
const expanded = await expandDNAInputs(filePaths, { cwd: opts.cwd, enterprisePolicyDirs: opts.enterprisePolicyDirs });
|
|
39
39
|
const dnas = [];
|
|
40
|
-
for (const path of
|
|
40
|
+
for (const path of expanded.files) {
|
|
41
41
|
dnas.push(await loadDNA(path));
|
|
42
42
|
}
|
|
43
43
|
const cascaded = cascadeDNA(dnas);
|
|
@@ -46,5 +46,5 @@ export async function compileFromFiles(filePaths, contextOrOptions) {
|
|
|
46
46
|
cascaded.epigenetic_markers.push(...opts.epigenetic_markers);
|
|
47
47
|
}
|
|
48
48
|
const activated = activateDNA(cascaded, opts.context ?? null, opts.role ?? null);
|
|
49
|
-
return compileDNA(activated, cascaded);
|
|
49
|
+
return attachProvenance(compileDNA(activated, cascaded), expanded.provenance);
|
|
50
50
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { DNASourceProvenance, IntentDNA } from "../schema/types.js";
|
|
2
|
+
import type { Diagnostic } from "./diagnostics.js";
|
|
3
|
+
export interface ResolveDNAInputOptions {
|
|
4
|
+
cwd?: string;
|
|
5
|
+
includeDiagnostics?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface ResolvedDNAInputs {
|
|
8
|
+
files: string[];
|
|
9
|
+
dnas: IntentDNA[];
|
|
10
|
+
diagnostics: Diagnostic[];
|
|
11
|
+
}
|
|
12
|
+
export declare function parseDNAFile(filePath: string): Promise<IntentDNA>;
|
|
13
|
+
export declare function resolveSpeciesReference(ref: string): string | null;
|
|
14
|
+
export declare function detectDNAConfigs(projectDir?: string): Promise<string[]>;
|
|
15
|
+
export interface ExpandDNAInputOptions {
|
|
16
|
+
cwd?: string;
|
|
17
|
+
enterprisePolicyDirs?: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface ExpandedDNAInput {
|
|
20
|
+
files: string[];
|
|
21
|
+
provenance: DNASourceProvenance[];
|
|
22
|
+
diagnostics: Diagnostic[];
|
|
23
|
+
}
|
|
24
|
+
export declare function expandDNAInputs(files: string[], options?: ExpandDNAInputOptions): Promise<ExpandedDNAInput>;
|
|
25
|
+
export declare function expandDNAInputFiles(files: string[], options?: ExpandDNAInputOptions): Promise<string[]>;
|
|
26
|
+
export declare function checkNamespaceCollisions(configPaths: string[]): Promise<Diagnostic[]>;
|
|
27
|
+
export declare function assertNoNamespaceCollisions(configPaths: string[]): Promise<void>;
|
|
28
|
+
export declare function loadDNAWithDiagnostics(filePath: string): Promise<{
|
|
29
|
+
dna?: IntentDNA;
|
|
30
|
+
diagnostics: Diagnostic[];
|
|
31
|
+
}>;
|
|
32
|
+
export declare function resolveDNAInputs(files: string[], options?: ResolveDNAInputOptions): Promise<ResolvedDNAInputs>;
|