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
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* - dna_status: Overview of DNA state
|
|
6
6
|
* - dna_workflow_read: Read current workflow state
|
|
7
7
|
* - dna_workflow_write: Update workflow state
|
|
8
|
-
* - dna_trace_query: Query trace data with filters
|
|
8
|
+
* - dna_trace_query: Query legacy diagnostic trace data with filters
|
|
9
9
|
*/
|
|
10
10
|
import type { ToolDef } from "./server.js";
|
|
11
11
|
export declare function createStateTools(projectDir: string): ToolDef[];
|
package/dist/mcp/tools-state.js
CHANGED
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
* - dna_status: Overview of DNA state
|
|
6
6
|
* - dna_workflow_read: Read current workflow state
|
|
7
7
|
* - dna_workflow_write: Update workflow state
|
|
8
|
-
* - dna_trace_query: Query trace data with filters
|
|
8
|
+
* - dna_trace_query: Query legacy diagnostic trace data with filters
|
|
9
9
|
*/
|
|
10
10
|
import { resolve } from "node:path";
|
|
11
|
-
import { readWorkflowState, writeWorkflowState, readTraces, listSessions } from "../hooks/state.js";
|
|
11
|
+
import { readWorkflowState, writeWorkflowState, readRuntimeDecisionEvents, readTraces, listSessions } from "../hooks/state.js";
|
|
12
|
+
import { validateRuntimeDecisionEvent } from "../governance/index.js";
|
|
12
13
|
import { loadCompiledIR } from "../runtime/plugin-adapter.js";
|
|
13
14
|
import { textResult } from "./server.js";
|
|
14
15
|
function isStringRecord(value) {
|
|
@@ -20,7 +21,7 @@ export function createStateTools(projectDir) {
|
|
|
20
21
|
// ── dna_status ────────────────────────────────────────
|
|
21
22
|
{
|
|
22
23
|
name: "dna_status",
|
|
23
|
-
description: "Overview of DNA governance state: compiled IR info, active workflow,
|
|
24
|
+
description: "Overview of DNA governance state: compiled IR info, active workflow, sessions, RuntimeDecisionEvent evidence, and legacy diagnostic trace stats",
|
|
24
25
|
inputSchema: { type: "object", properties: {} },
|
|
25
26
|
handler: async () => {
|
|
26
27
|
const lines = [];
|
|
@@ -58,12 +59,21 @@ export function createStateTools(projectDir) {
|
|
|
58
59
|
const preview = sessions.slice(0, 5).join(", ");
|
|
59
60
|
lines.push(`\nSessions: ${sessions.length} (${preview}${sessions.length > 5 ? "..." : ""})`);
|
|
60
61
|
}
|
|
62
|
+
// Recent RuntimeDecisionEvent stats
|
|
63
|
+
const runtimeDecisions = await readRuntimeDecisionEvents(projectDir, 1);
|
|
64
|
+
if (runtimeDecisions.length > 0) {
|
|
65
|
+
const enterprise = runtimeDecisions.filter(e => validateRuntimeDecisionEvent(e).classification === "enterprise_evidence");
|
|
66
|
+
const blocks = enterprise.filter(e => e.decision === "block").length;
|
|
67
|
+
const warns = enterprise.filter(e => e.decision === "warn").length;
|
|
68
|
+
const escalates = enterprise.filter(e => e.decision === "escalate").length;
|
|
69
|
+
lines.push(`\nRuntimeDecisionEvent (24h): ${runtimeDecisions.length} events, ${enterprise.length} enterprise evidence, ${blocks} blocks, ${warns} warns, ${escalates} escalates`);
|
|
70
|
+
}
|
|
61
71
|
// Recent trace stats
|
|
62
72
|
const traces = await readTraces(projectDir, 1);
|
|
63
73
|
if (traces.length > 0) {
|
|
64
74
|
const blocks = traces.filter(t => t.decision === "block").length;
|
|
65
75
|
const warns = traces.filter(t => t.decision === "warn").length;
|
|
66
|
-
lines.push(`\
|
|
76
|
+
lines.push(`\nLegacy trace diagnostics (24h): ${traces.length} events, ${blocks} blocks, ${warns} warns`);
|
|
67
77
|
}
|
|
68
78
|
return textResult(lines.join("\n"));
|
|
69
79
|
},
|
|
@@ -71,7 +81,7 @@ export function createStateTools(projectDir) {
|
|
|
71
81
|
// ── dna_workflow_read ─────────────────────────────────
|
|
72
82
|
{
|
|
73
83
|
name: "dna_workflow_read",
|
|
74
|
-
description: "Read current workflow state (
|
|
84
|
+
description: "Read current workflow runtime state (diagnostic/cache only; not enterprise evidence)",
|
|
75
85
|
inputSchema: {
|
|
76
86
|
type: "object",
|
|
77
87
|
properties: {
|
|
@@ -126,7 +136,7 @@ export function createStateTools(projectDir) {
|
|
|
126
136
|
// ── dna_trace_query ──────────────────────────────────
|
|
127
137
|
{
|
|
128
138
|
name: "dna_trace_query",
|
|
129
|
-
description: "Query enforcement trace data with filters
|
|
139
|
+
description: "Query legacy diagnostic enforcement trace data with filters. Trace records are not enterprise evidence unless referenced by RuntimeDecisionEvent.",
|
|
130
140
|
inputSchema: {
|
|
131
141
|
type: "object",
|
|
132
142
|
properties: {
|
|
@@ -150,7 +160,7 @@ export function createStateTools(projectDir) {
|
|
|
150
160
|
traces = traces.filter(t => t.tool_name === toolName);
|
|
151
161
|
const total = traces.length;
|
|
152
162
|
traces = traces.slice(-limit);
|
|
153
|
-
const lines = [`
|
|
163
|
+
const lines = [`Legacy diagnostic trace: ${total} matching entries (showing last ${traces.length}); not enterprise evidence unless referenced by RuntimeDecisionEvent`];
|
|
154
164
|
for (const t of traces) {
|
|
155
165
|
const parts = [t.timestamp.slice(11, 19), t.event, t.decision];
|
|
156
166
|
if (t.tool_name)
|
|
@@ -18,6 +18,9 @@ export interface KernelReport {
|
|
|
18
18
|
period_days: number;
|
|
19
19
|
};
|
|
20
20
|
summary: {
|
|
21
|
+
runtime_decisions: number;
|
|
22
|
+
enterprise_evidence: number;
|
|
23
|
+
legacy_diagnostics: number;
|
|
21
24
|
traces: number;
|
|
22
25
|
verifier_results: number;
|
|
23
26
|
signals: number;
|
|
@@ -32,9 +35,33 @@ export interface KernelReport {
|
|
|
32
35
|
blocks: number;
|
|
33
36
|
warns: number;
|
|
34
37
|
allows: number;
|
|
38
|
+
escalates: number;
|
|
39
|
+
validates: number;
|
|
35
40
|
policy_denied_verifiers: number;
|
|
36
41
|
};
|
|
37
42
|
signals: ClassifiedSignal[];
|
|
43
|
+
runtime_decision_summary: {
|
|
44
|
+
total: number;
|
|
45
|
+
enterprise_evidence: number;
|
|
46
|
+
diagnostics: number;
|
|
47
|
+
blocks: number;
|
|
48
|
+
warns: number;
|
|
49
|
+
allows: number;
|
|
50
|
+
escalates: number;
|
|
51
|
+
validates: number;
|
|
52
|
+
top_policy_bundles: Array<{
|
|
53
|
+
policy_bundle_id: string;
|
|
54
|
+
count: number;
|
|
55
|
+
}>;
|
|
56
|
+
top_constraints: Array<{
|
|
57
|
+
constraint_id: string;
|
|
58
|
+
count: number;
|
|
59
|
+
}>;
|
|
60
|
+
top_decision_reasons: Array<{
|
|
61
|
+
reason: string;
|
|
62
|
+
count: number;
|
|
63
|
+
}>;
|
|
64
|
+
};
|
|
38
65
|
verifier_summary: {
|
|
39
66
|
total: number;
|
|
40
67
|
passes: number;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { readTraces, readVerifierResults, safePathComponent } from "../hooks/state.js";
|
|
3
|
+
import { readRuntimeDecisionEvents, readTraces, readVerifierResults, safePathComponent } from "../hooks/state.js";
|
|
4
|
+
import { validateRuntimeDecisionEvent } from "../governance/index.js";
|
|
4
5
|
import { describeMarkerChanges } from "../evolution/marker-gen.js";
|
|
5
6
|
import { classifiedSignalsToOutcomes, classifyKernelSignals, } from "./kernel-signals.js";
|
|
6
7
|
const CLASSIFICATIONS = [
|
|
@@ -50,6 +51,30 @@ function buildVerifierSummary(results) {
|
|
|
50
51
|
failures: results.filter((result) => result.status === "fail").length,
|
|
51
52
|
};
|
|
52
53
|
}
|
|
54
|
+
function buildRuntimeDecisionSummary(events) {
|
|
55
|
+
const enterpriseEvidence = events.filter((event) => validateRuntimeDecisionEvent(event).classification === "enterprise_evidence");
|
|
56
|
+
const blocks = enterpriseEvidence.filter((event) => event.decision === "block");
|
|
57
|
+
const warns = enterpriseEvidence.filter((event) => event.decision === "warn").length;
|
|
58
|
+
const allows = enterpriseEvidence.filter((event) => event.decision === "allow").length;
|
|
59
|
+
const escalates = enterpriseEvidence.filter((event) => event.decision === "escalate").length;
|
|
60
|
+
const validates = enterpriseEvidence.filter((event) => event.decision === "validate").length;
|
|
61
|
+
const reasons = blocks
|
|
62
|
+
.map((event) => event.decision_reason.split("\n")[0].replace(/^\[Intent DNA\]\s*/, "").slice(0, 100))
|
|
63
|
+
.filter((reason) => Boolean(reason));
|
|
64
|
+
return {
|
|
65
|
+
total: events.length,
|
|
66
|
+
enterprise_evidence: enterpriseEvidence.length,
|
|
67
|
+
diagnostics: events.length - enterpriseEvidence.length,
|
|
68
|
+
blocks: blocks.length,
|
|
69
|
+
warns,
|
|
70
|
+
allows,
|
|
71
|
+
escalates,
|
|
72
|
+
validates,
|
|
73
|
+
top_policy_bundles: sortedCounts(enterpriseEvidence.map((event) => event.policy_bundle_id), 5, "policy_bundle_id"),
|
|
74
|
+
top_constraints: sortedCounts(enterpriseEvidence.map((event) => event.winning_constraint.constraint_id), 5, "constraint_id"),
|
|
75
|
+
top_decision_reasons: sortedCounts(reasons, 5, "reason"),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
53
78
|
async function readCompiledSourceIds(projectDir) {
|
|
54
79
|
try {
|
|
55
80
|
const raw = await readFile(join(projectDir, ".dna", "compiled", "ir.json"), "utf-8");
|
|
@@ -136,13 +161,15 @@ async function buildMarkerPreview(projectDir, explicitDnaId, signals) {
|
|
|
136
161
|
}
|
|
137
162
|
export async function buildKernelReport(options) {
|
|
138
163
|
const days = options.days ?? 7;
|
|
164
|
+
const runtimeDecisions = await readRuntimeDecisionEvents(options.projectDir, days, options.sessionId);
|
|
139
165
|
const traces = await readTraces(options.projectDir, days, options.sessionId);
|
|
140
166
|
const verifierResults = (await readVerifierResults(options.projectDir, options.sessionId))
|
|
141
167
|
.filter((result) => withinDays(result.timestamp, days));
|
|
142
|
-
const signals = classifyKernelSignals({ traces, verifierResults });
|
|
168
|
+
const signals = classifyKernelSignals({ runtimeDecisions, traces, verifierResults });
|
|
143
169
|
const classifications = Object.fromEntries(CLASSIFICATIONS.map((classification) => [classification, 0]));
|
|
144
170
|
for (const signal of signals)
|
|
145
171
|
classifications[signal.classification]++;
|
|
172
|
+
const runtimeDecisionSummary = buildRuntimeDecisionSummary(runtimeDecisions);
|
|
146
173
|
const traceSummary = buildTraceSummary(traces);
|
|
147
174
|
const verifierSummary = buildVerifierSummary(verifierResults);
|
|
148
175
|
const markerPreview = options.includeMarkerPreview
|
|
@@ -159,6 +186,9 @@ export async function buildKernelReport(options) {
|
|
|
159
186
|
period_days: days,
|
|
160
187
|
},
|
|
161
188
|
summary: {
|
|
189
|
+
runtime_decisions: runtimeDecisions.length,
|
|
190
|
+
enterprise_evidence: runtimeDecisionSummary.enterprise_evidence,
|
|
191
|
+
legacy_diagnostics: traces.length + verifierResults.length + runtimeDecisionSummary.diagnostics,
|
|
162
192
|
traces: traces.length,
|
|
163
193
|
verifier_results: verifierResults.length,
|
|
164
194
|
signals: signals.length,
|
|
@@ -166,16 +196,19 @@ export async function buildKernelReport(options) {
|
|
|
166
196
|
},
|
|
167
197
|
classifications,
|
|
168
198
|
quality: {
|
|
169
|
-
quality_positive:
|
|
170
|
-
quality_negative:
|
|
199
|
+
quality_positive: 0,
|
|
200
|
+
quality_negative: 0,
|
|
171
201
|
},
|
|
172
202
|
enforcement: {
|
|
173
|
-
blocks:
|
|
174
|
-
warns:
|
|
175
|
-
allows:
|
|
176
|
-
|
|
203
|
+
blocks: runtimeDecisionSummary.blocks,
|
|
204
|
+
warns: runtimeDecisionSummary.warns,
|
|
205
|
+
allows: runtimeDecisionSummary.allows,
|
|
206
|
+
escalates: runtimeDecisionSummary.escalates,
|
|
207
|
+
validates: runtimeDecisionSummary.validates,
|
|
208
|
+
policy_denied_verifiers: 0,
|
|
177
209
|
},
|
|
178
210
|
signals,
|
|
211
|
+
runtime_decision_summary: runtimeDecisionSummary,
|
|
179
212
|
verifier_summary: verifierSummary,
|
|
180
213
|
trace_summary: traceSummary,
|
|
181
214
|
marker_preview: markerPreview,
|
|
@@ -194,15 +227,23 @@ export function formatKernelReport(report) {
|
|
|
194
227
|
lines.push("=".repeat(50));
|
|
195
228
|
lines.push("");
|
|
196
229
|
lines.push(`Schema: ${report.schema_version}`);
|
|
197
|
-
lines.push(`
|
|
198
|
-
lines.push(`
|
|
199
|
-
lines.push(`
|
|
200
|
-
lines.push(`
|
|
230
|
+
lines.push(`RuntimeDecisionEvents: ${report.runtime_decision_summary.total}`);
|
|
231
|
+
lines.push(` Enterprise evidence: ${report.runtime_decision_summary.enterprise_evidence}`);
|
|
232
|
+
lines.push(` Diagnostic-only events: ${report.runtime_decision_summary.diagnostics}`);
|
|
233
|
+
lines.push(` Allowed: ${report.runtime_decision_summary.allows}`);
|
|
234
|
+
lines.push(` Blocked: ${report.runtime_decision_summary.blocks}`);
|
|
235
|
+
lines.push(` Warned: ${report.runtime_decision_summary.warns}`);
|
|
236
|
+
lines.push(` Escalated: ${report.runtime_decision_summary.escalates}`);
|
|
237
|
+
lines.push(` Validated: ${report.runtime_decision_summary.validates}`);
|
|
201
238
|
lines.push("");
|
|
202
|
-
if (report.verifier_summary.total > 0) {
|
|
203
|
-
lines.push(
|
|
204
|
-
lines.push(`
|
|
205
|
-
lines.push(`
|
|
239
|
+
if (report.trace_summary.total > 0 || report.verifier_summary.total > 0) {
|
|
240
|
+
lines.push("Legacy diagnostics (not enterprise evidence without RuntimeDecisionEvent provenance):");
|
|
241
|
+
lines.push(` Traces: ${report.trace_summary.total}`);
|
|
242
|
+
lines.push(` Verifier results: ${report.verifier_summary.total}`);
|
|
243
|
+
if (report.verifier_summary.total > 0) {
|
|
244
|
+
lines.push(` Passed: ${report.verifier_summary.passes}`);
|
|
245
|
+
lines.push(` Failed: ${report.verifier_summary.failures}`);
|
|
246
|
+
}
|
|
206
247
|
lines.push("");
|
|
207
248
|
}
|
|
208
249
|
lines.push(`Classified signals: ${report.summary.signals}`);
|
|
@@ -214,19 +255,19 @@ export function formatKernelReport(report) {
|
|
|
214
255
|
lines.push(` Unknown: ${report.classifications.unknown}`);
|
|
215
256
|
lines.push("");
|
|
216
257
|
if (report.trace_summary.top_blocked_tools.length > 0) {
|
|
217
|
-
lines.push("
|
|
258
|
+
lines.push("Legacy diagnostic top blocked tools:");
|
|
218
259
|
for (const item of report.trace_summary.top_blocked_tools)
|
|
219
260
|
lines.push(` ${item.tool}: ${item.count}`);
|
|
220
261
|
lines.push("");
|
|
221
262
|
}
|
|
222
263
|
if (report.trace_summary.top_blocked_paths.length > 0) {
|
|
223
|
-
lines.push("
|
|
264
|
+
lines.push("Legacy diagnostic top blocked paths:");
|
|
224
265
|
for (const item of report.trace_summary.top_blocked_paths)
|
|
225
266
|
lines.push(` ${item.path}: ${item.count}`);
|
|
226
267
|
lines.push("");
|
|
227
268
|
}
|
|
228
269
|
if (report.trace_summary.top_block_reasons.length > 0) {
|
|
229
|
-
lines.push("
|
|
270
|
+
lines.push("Legacy diagnostic top block reasons:");
|
|
230
271
|
for (const item of report.trace_summary.top_block_reasons)
|
|
231
272
|
lines.push(` \"${item.reason}\": ${item.count}`);
|
|
232
273
|
lines.push("");
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { TraceEntry, VerifierResultEntry } from "../hooks/state.js";
|
|
2
2
|
import type { ExecutionOutcome } from "../evolution/types.js";
|
|
3
|
+
import { type RuntimeDecisionEvent } from "../governance/index.js";
|
|
3
4
|
export type KernelSignalClassification = "protective" | "friction" | "positive" | "negative" | "neutral" | "unknown";
|
|
4
5
|
export type KernelEvolutionEffect = "helped" | "hindered" | "neutral";
|
|
5
|
-
export type KernelSignalSemantic = "quality-positive" | "quality-negative" | "enforcement-block" | "enforcement-warn" | "enforcement-allow" | "policy-denied-verifier" | "external";
|
|
6
|
+
export type KernelSignalSemantic = "quality-positive" | "quality-negative" | "enforcement-block" | "enforcement-warn" | "enforcement-allow" | "enforcement-escalate" | "enforcement-validate" | "policy-denied-verifier" | "external";
|
|
6
7
|
export interface ClassifiedSignal {
|
|
7
8
|
id: string;
|
|
8
|
-
source_type: "trace" | "verifier" | "external";
|
|
9
|
+
source_type: "runtime_decision" | "trace" | "verifier" | "external";
|
|
9
10
|
source_ref: string;
|
|
10
11
|
timestamp: string;
|
|
11
12
|
gene?: string;
|
|
@@ -22,11 +23,13 @@ export interface KernelSignalContext {
|
|
|
22
23
|
friction_verifier_ids?: string[];
|
|
23
24
|
}
|
|
24
25
|
export interface ClassifyKernelSignalsInput {
|
|
26
|
+
runtimeDecisions?: RuntimeDecisionEvent[];
|
|
25
27
|
traces?: TraceEntry[];
|
|
26
28
|
verifierResults?: VerifierResultEntry[];
|
|
27
29
|
context?: KernelSignalContext;
|
|
28
30
|
}
|
|
29
31
|
export declare function classifyVerifierResult(result: VerifierResultEntry, context?: KernelSignalContext): ClassifiedSignal[];
|
|
32
|
+
export declare function classifyRuntimeDecisionEvent(event: RuntimeDecisionEvent): ClassifiedSignal;
|
|
30
33
|
export declare function classifyTraceEntry(trace: TraceEntry, context?: KernelSignalContext): ClassifiedSignal;
|
|
31
34
|
export declare function classifyKernelSignals(input: ClassifyKernelSignalsInput): ClassifiedSignal[];
|
|
32
35
|
export declare function classifiedSignalsToOutcomes(signals: ClassifiedSignal[], dnaId: string): {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { validateRuntimeDecisionEvent } from "../governance/index.js";
|
|
1
2
|
function extractGeneFromReason(reason) {
|
|
2
3
|
if (!reason)
|
|
3
4
|
return undefined;
|
|
@@ -11,6 +12,8 @@ function extractGeneFromReason(reason) {
|
|
|
11
12
|
return sourceMatch?.[1];
|
|
12
13
|
}
|
|
13
14
|
function verifierSourceRef(result) {
|
|
15
|
+
if (result.result_id)
|
|
16
|
+
return `verifier:${result.result_id}`;
|
|
14
17
|
return [
|
|
15
18
|
"verifier",
|
|
16
19
|
result.workflow ?? "unknown-workflow",
|
|
@@ -21,6 +24,7 @@ function verifierSourceRef(result) {
|
|
|
21
24
|
}
|
|
22
25
|
function verifierEvidencePayload(result) {
|
|
23
26
|
const payload = {
|
|
27
|
+
result_id: result.result_id,
|
|
24
28
|
verifier_id: result.verifier_id,
|
|
25
29
|
when: result.when,
|
|
26
30
|
severity: result.severity,
|
|
@@ -58,6 +62,55 @@ function traceEvidencePayload(trace) {
|
|
|
58
62
|
}
|
|
59
63
|
return Object.keys(payload).length > 0 ? payload : undefined;
|
|
60
64
|
}
|
|
65
|
+
function runtimeDecisionEvidencePayload(event) {
|
|
66
|
+
return {
|
|
67
|
+
event_id: event.event_id,
|
|
68
|
+
decision: event.decision,
|
|
69
|
+
decision_reason: event.decision_reason,
|
|
70
|
+
policy_bundle_id: event.policy_bundle_id,
|
|
71
|
+
policy_bundle_version: event.policy_bundle_version,
|
|
72
|
+
compiled_ir_hash: event.compiled_ir_hash,
|
|
73
|
+
winning_constraint: event.winning_constraint,
|
|
74
|
+
evidence_refs: event.evidence_refs,
|
|
75
|
+
classification: validateRuntimeDecisionEvent(event).classification,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function semanticForRuntimeDecision(event) {
|
|
79
|
+
if (event.decision === "block")
|
|
80
|
+
return "enforcement-block";
|
|
81
|
+
if (event.decision === "warn")
|
|
82
|
+
return "enforcement-warn";
|
|
83
|
+
if (event.decision === "escalate")
|
|
84
|
+
return "enforcement-escalate";
|
|
85
|
+
if (event.decision === "validate")
|
|
86
|
+
return "enforcement-validate";
|
|
87
|
+
return "enforcement-allow";
|
|
88
|
+
}
|
|
89
|
+
function classificationForRuntimeDecision(event) {
|
|
90
|
+
const validation = validateRuntimeDecisionEvent(event);
|
|
91
|
+
if (validation.classification !== "enterprise_evidence") {
|
|
92
|
+
return {
|
|
93
|
+
classification: "unknown",
|
|
94
|
+
classification_reason: "RuntimeDecisionEvent is diagnostic-only because enterprise provenance is incomplete",
|
|
95
|
+
evolution_effect: "neutral",
|
|
96
|
+
eligible_for_marker_preview: false,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (event.decision === "block") {
|
|
100
|
+
return {
|
|
101
|
+
classification: "protective",
|
|
102
|
+
classification_reason: "enterprise RuntimeDecisionEvent block is protective evidence",
|
|
103
|
+
evolution_effect: "neutral",
|
|
104
|
+
eligible_for_marker_preview: false,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
classification: "neutral",
|
|
109
|
+
classification_reason: "enterprise RuntimeDecisionEvent is primary evidence but not marker-preview feedback by default",
|
|
110
|
+
evolution_effect: "neutral",
|
|
111
|
+
eligible_for_marker_preview: false,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
61
114
|
function isPolicyDeniedVerifier(result) {
|
|
62
115
|
return result.evidence === "policy_denied" || result.exit_code === 126;
|
|
63
116
|
}
|
|
@@ -118,6 +171,21 @@ export function classifyVerifierResult(result, context = {}) {
|
|
|
118
171
|
};
|
|
119
172
|
});
|
|
120
173
|
}
|
|
174
|
+
export function classifyRuntimeDecisionEvent(event) {
|
|
175
|
+
const sourceRef = `runtime_decision:${event.event_id}`;
|
|
176
|
+
const gene = event.winning_constraint.gene_id === "unknown" ? undefined : event.winning_constraint.gene_id;
|
|
177
|
+
return {
|
|
178
|
+
id: sourceRef,
|
|
179
|
+
source_type: "runtime_decision",
|
|
180
|
+
source_ref: sourceRef,
|
|
181
|
+
timestamp: event.timestamp,
|
|
182
|
+
gene,
|
|
183
|
+
semantic: semanticForRuntimeDecision(event),
|
|
184
|
+
...classificationForRuntimeDecision(event),
|
|
185
|
+
evidence_ref: sourceRef,
|
|
186
|
+
evidence_payload: runtimeDecisionEvidencePayload(event),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
121
189
|
export function classifyTraceEntry(trace, context = {}) {
|
|
122
190
|
const gene = extractGeneFromReason(trace.reason);
|
|
123
191
|
const sourceRef = `trace:${trace.trace_id}`;
|
|
@@ -172,11 +240,28 @@ export function classifyTraceEntry(trace, context = {}) {
|
|
|
172
240
|
};
|
|
173
241
|
}
|
|
174
242
|
export function classifyKernelSignals(input) {
|
|
243
|
+
const runtimeDecisions = input.runtimeDecisions ?? [];
|
|
175
244
|
const traces = input.traces ?? [];
|
|
176
245
|
const verifierResults = input.verifierResults ?? [];
|
|
177
246
|
return [
|
|
178
|
-
...
|
|
179
|
-
...
|
|
247
|
+
...runtimeDecisions.map((event) => classifyRuntimeDecisionEvent(event)),
|
|
248
|
+
...traces.map((trace) => {
|
|
249
|
+
const signal = classifyTraceEntry(trace, input.context);
|
|
250
|
+
return {
|
|
251
|
+
...signal,
|
|
252
|
+
classification: "unknown",
|
|
253
|
+
classification_reason: `legacy diagnostic trace only: ${signal.classification_reason}`,
|
|
254
|
+
evolution_effect: "neutral",
|
|
255
|
+
eligible_for_marker_preview: false,
|
|
256
|
+
};
|
|
257
|
+
}),
|
|
258
|
+
...verifierResults.flatMap((result) => classifyVerifierResult(result, input.context).map((signal) => ({
|
|
259
|
+
...signal,
|
|
260
|
+
classification: "unknown",
|
|
261
|
+
classification_reason: `legacy diagnostic verifier only: ${signal.classification_reason}`,
|
|
262
|
+
evolution_effect: "neutral",
|
|
263
|
+
eligible_for_marker_preview: false,
|
|
264
|
+
}))),
|
|
180
265
|
].sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
181
266
|
}
|
|
182
267
|
export function classifiedSignalsToOutcomes(signals, dnaId) {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { DNAWorkflowState, TraceEntry, VerifierResultEntry } from "../hooks/state.js";
|
|
2
|
+
import type { CompletedArtifactEntry } from "../schema/types.js";
|
|
3
|
+
import { type RuntimeDecisionEvent } from "../governance/index.js";
|
|
4
|
+
import { type KernelReport, type KernelReportOptions } from "./kernel-report.js";
|
|
5
|
+
export type EvidenceRef = {
|
|
6
|
+
type: "runtime_decision";
|
|
7
|
+
event_id: string;
|
|
8
|
+
} | {
|
|
9
|
+
type: "trace";
|
|
10
|
+
trace_id: string;
|
|
11
|
+
} | {
|
|
12
|
+
type: "audit";
|
|
13
|
+
audit_id: string;
|
|
14
|
+
} | {
|
|
15
|
+
type: "verifier_result";
|
|
16
|
+
result_id: string;
|
|
17
|
+
} | {
|
|
18
|
+
type: "artifact";
|
|
19
|
+
artifact_id: string;
|
|
20
|
+
path?: string;
|
|
21
|
+
};
|
|
22
|
+
export interface CriticalDecision {
|
|
23
|
+
decision_id: string;
|
|
24
|
+
kind: "block" | "warn" | "escalate" | "verifier_failure" | "handoff_gate";
|
|
25
|
+
summary: string;
|
|
26
|
+
refs: EvidenceRef[];
|
|
27
|
+
}
|
|
28
|
+
export interface ReportPackage {
|
|
29
|
+
schema_version: "intentdna.report_package.v1";
|
|
30
|
+
generated_at: string;
|
|
31
|
+
source: KernelReport["source"];
|
|
32
|
+
kernel_report: KernelReport;
|
|
33
|
+
runtime_decisions: RuntimeDecisionEvent[];
|
|
34
|
+
traces: TraceEntry[];
|
|
35
|
+
verifier_results: VerifierResultEntry[];
|
|
36
|
+
handoffs: {
|
|
37
|
+
workflow_state?: DNAWorkflowState;
|
|
38
|
+
completed_artifacts: CompletedArtifactEntry[];
|
|
39
|
+
artifact_refs: Array<{
|
|
40
|
+
artifact_id: string;
|
|
41
|
+
path: string;
|
|
42
|
+
metadata?: Record<string, unknown>;
|
|
43
|
+
}>;
|
|
44
|
+
};
|
|
45
|
+
diagnostics: Array<{
|
|
46
|
+
severity: "error" | "warning" | "info";
|
|
47
|
+
message: string;
|
|
48
|
+
code?: string;
|
|
49
|
+
}>;
|
|
50
|
+
deferrals: Array<{
|
|
51
|
+
id: string;
|
|
52
|
+
reason: string;
|
|
53
|
+
refs: EvidenceRef[];
|
|
54
|
+
}>;
|
|
55
|
+
critical_decisions: CriticalDecision[];
|
|
56
|
+
mutation: {
|
|
57
|
+
command_class: "read-only" | "preview-only";
|
|
58
|
+
wrote_state: false;
|
|
59
|
+
wrote_evolution: false;
|
|
60
|
+
persisted_outcomes: false;
|
|
61
|
+
mutated_markers: false;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export declare function buildReportPackage(options: KernelReportOptions): Promise<ReportPackage>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { readRuntimeDecisionEvents, readTraces, readVerifierResults, readWorkflowState } from "../hooks/state.js";
|
|
2
|
+
import { validateRuntimeDecisionEvent } from "../governance/index.js";
|
|
3
|
+
import { buildKernelReport } from "./kernel-report.js";
|
|
4
|
+
function withinDays(timestamp, days) {
|
|
5
|
+
const parsed = Date.parse(timestamp);
|
|
6
|
+
if (Number.isNaN(parsed))
|
|
7
|
+
return true;
|
|
8
|
+
return parsed >= Date.now() - days * 24 * 60 * 60 * 1000;
|
|
9
|
+
}
|
|
10
|
+
function artifactRefs(completed) {
|
|
11
|
+
const refs = [];
|
|
12
|
+
for (const entry of completed) {
|
|
13
|
+
for (const artifact of entry.artifacts) {
|
|
14
|
+
refs.push({
|
|
15
|
+
artifact_id: artifact.artifact_id ?? `${entry.step_id}:${artifact.type}:${artifact.path}`,
|
|
16
|
+
path: artifact.path,
|
|
17
|
+
metadata: artifact.metadata,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return refs;
|
|
22
|
+
}
|
|
23
|
+
function refsForRuntimeDecision(event) {
|
|
24
|
+
const refs = [{ type: "runtime_decision", event_id: event.event_id }];
|
|
25
|
+
for (const ref of event.evidence_refs) {
|
|
26
|
+
if (ref.type === "trace")
|
|
27
|
+
refs.push({ type: "trace", trace_id: ref.ref });
|
|
28
|
+
if (ref.type === "audit")
|
|
29
|
+
refs.push({ type: "audit", audit_id: ref.ref });
|
|
30
|
+
if (ref.type === "verifier")
|
|
31
|
+
refs.push({ type: "verifier_result", result_id: ref.ref });
|
|
32
|
+
if (ref.type === "artifact" || ref.type === "handoff")
|
|
33
|
+
refs.push({ type: "artifact", artifact_id: ref.ref });
|
|
34
|
+
}
|
|
35
|
+
return refs;
|
|
36
|
+
}
|
|
37
|
+
function buildCriticalDecisions(runtimeDecisions) {
|
|
38
|
+
const decisions = [];
|
|
39
|
+
for (const event of runtimeDecisions) {
|
|
40
|
+
if (validateRuntimeDecisionEvent(event).classification !== "enterprise_evidence")
|
|
41
|
+
continue;
|
|
42
|
+
if (event.decision !== "block" && event.decision !== "warn" && event.decision !== "escalate")
|
|
43
|
+
continue;
|
|
44
|
+
decisions.push({
|
|
45
|
+
decision_id: `${event.decision}:${event.event_id}`,
|
|
46
|
+
kind: event.decision,
|
|
47
|
+
summary: event.decision_reason.split("\n")[0] || `${event.decision} decision`,
|
|
48
|
+
refs: refsForRuntimeDecision(event),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return decisions;
|
|
52
|
+
}
|
|
53
|
+
export async function buildReportPackage(options) {
|
|
54
|
+
const days = options.days ?? 7;
|
|
55
|
+
const kernelReport = await buildKernelReport(options);
|
|
56
|
+
const runtimeDecisions = await readRuntimeDecisionEvents(options.projectDir, days, options.sessionId);
|
|
57
|
+
const traces = await readTraces(options.projectDir, days, options.sessionId);
|
|
58
|
+
const verifierResults = (await readVerifierResults(options.projectDir, options.sessionId))
|
|
59
|
+
.filter((result) => withinDays(result.timestamp, days));
|
|
60
|
+
const workflowState = await readWorkflowState(options.projectDir, options.sessionId, 0) ?? undefined;
|
|
61
|
+
const completedArtifacts = workflowState?.completed_artifacts ?? [];
|
|
62
|
+
return {
|
|
63
|
+
schema_version: "intentdna.report_package.v1",
|
|
64
|
+
generated_at: new Date().toISOString(),
|
|
65
|
+
source: kernelReport.source,
|
|
66
|
+
kernel_report: kernelReport,
|
|
67
|
+
runtime_decisions: runtimeDecisions,
|
|
68
|
+
traces,
|
|
69
|
+
verifier_results: verifierResults,
|
|
70
|
+
handoffs: {
|
|
71
|
+
workflow_state: workflowState,
|
|
72
|
+
completed_artifacts: completedArtifacts,
|
|
73
|
+
artifact_refs: artifactRefs(completedArtifacts),
|
|
74
|
+
},
|
|
75
|
+
diagnostics: [
|
|
76
|
+
...(traces.length > 0 ? [{ severity: "info", code: "legacy_trace_diagnostic", message: `${traces.length} trace record(s) included as diagnostic-only evidence` }] : []),
|
|
77
|
+
...(verifierResults.length > 0 ? [{ severity: "info", code: "legacy_verifier_diagnostic", message: `${verifierResults.length} verifier result(s) included as diagnostic-only evidence` }] : []),
|
|
78
|
+
...(completedArtifacts.length > 0 ? [{ severity: "info", code: "workflow_state_diagnostic", message: `${completedArtifacts.length} workflow handoff entry group(s) included as diagnostic-only evidence` }] : []),
|
|
79
|
+
],
|
|
80
|
+
deferrals: [],
|
|
81
|
+
critical_decisions: buildCriticalDecisions(runtimeDecisions),
|
|
82
|
+
mutation: {
|
|
83
|
+
command_class: options.includeMarkerPreview ? "preview-only" : "read-only",
|
|
84
|
+
wrote_state: false,
|
|
85
|
+
wrote_evolution: false,
|
|
86
|
+
persisted_outcomes: false,
|
|
87
|
+
mutated_markers: false,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -31,6 +31,7 @@ export interface AgentMDResult {
|
|
|
31
31
|
* Convert camelCase or snake_case to kebab-case.
|
|
32
32
|
*/
|
|
33
33
|
export declare function toKebabCase(name: string): string;
|
|
34
|
+
export declare function assertSafeGeneratedName(name: string, label?: string): void;
|
|
34
35
|
/**
|
|
35
36
|
* Compile a single RoleDef into an agent MD file.
|
|
36
37
|
* Pure function, no side effects.
|
package/dist/runtime/agent-md.js
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* Output directory: .claude/agents/<name>.md
|
|
10
10
|
*/
|
|
11
11
|
import { mkdir, writeFile, readFile, readdir, rm } from "node:fs/promises";
|
|
12
|
-
import { join } from "node:path";
|
|
12
|
+
import { join, resolve, sep } from "node:path";
|
|
13
13
|
const SENTINEL_COMMENT = "<!-- intentdna:managed — do not edit manually -->";
|
|
14
|
+
const SAFE_GENERATED_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
14
15
|
// ── Helpers ────────────────────────────────────────────────
|
|
15
16
|
/**
|
|
16
17
|
* Convert camelCase or snake_case to kebab-case.
|
|
@@ -23,12 +24,26 @@ export function toKebabCase(name) {
|
|
|
23
24
|
.replace(/[_\s]+/g, "-")
|
|
24
25
|
.toLowerCase();
|
|
25
26
|
}
|
|
27
|
+
export function assertSafeGeneratedName(name, label = "generated name") {
|
|
28
|
+
if (!SAFE_GENERATED_NAME.test(name)) {
|
|
29
|
+
throw new Error(`${label} '${name}' must contain only lowercase letters, digits, and single hyphens`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function resolveContainedPath(baseDir, ...segments) {
|
|
33
|
+
const base = resolve(baseDir);
|
|
34
|
+
const target = resolve(baseDir, ...segments);
|
|
35
|
+
if (target !== base && !target.startsWith(`${base}${sep}`)) {
|
|
36
|
+
throw new Error(`generated path escapes output directory: ${target}`);
|
|
37
|
+
}
|
|
38
|
+
return target;
|
|
39
|
+
}
|
|
26
40
|
/**
|
|
27
41
|
* Render YAML frontmatter string (without --- delimiters).
|
|
28
42
|
*/
|
|
29
43
|
function renderFrontmatter(name, role, options) {
|
|
30
44
|
const prefix = options?.namePrefix ?? "dna-";
|
|
31
45
|
const fullName = `${prefix}${toKebabCase(name)}`;
|
|
46
|
+
assertSafeGeneratedName(fullName, "agent name");
|
|
32
47
|
const lines = [];
|
|
33
48
|
lines.push(`name: ${fullName}`);
|
|
34
49
|
lines.push(`description: "${escapeYamlString(role.description)}"`);
|
|
@@ -65,6 +80,7 @@ function renderConstraints(ir) {
|
|
|
65
80
|
function renderBody(name, role, ir, options) {
|
|
66
81
|
const prefix = options?.namePrefix ?? "dna-";
|
|
67
82
|
const fullName = `${prefix}${toKebabCase(name)}`;
|
|
83
|
+
assertSafeGeneratedName(fullName, "agent name");
|
|
68
84
|
const compiledAt = new Date().toISOString();
|
|
69
85
|
const includeDNA = options?.includeDNAGuidelines ?? true;
|
|
70
86
|
const sections = [];
|
|
@@ -184,7 +200,9 @@ function renderBody(name, role, ir, options) {
|
|
|
184
200
|
export function compileRoleToAgentMD(roleName, role, ir, options) {
|
|
185
201
|
const prefix = options?.namePrefix ?? "dna-";
|
|
186
202
|
const kebabName = toKebabCase(roleName);
|
|
187
|
-
const
|
|
203
|
+
const fullName = `${prefix}${kebabName}`;
|
|
204
|
+
assertSafeGeneratedName(fullName, "agent name");
|
|
205
|
+
const fileName = `${fullName}.md`;
|
|
188
206
|
const frontmatter = renderFrontmatter(roleName, role, options);
|
|
189
207
|
const body = renderBody(roleName, role, ir, options);
|
|
190
208
|
const content = `---\n${frontmatter}\n---\n\n${body}`;
|
|
@@ -207,7 +225,7 @@ export async function writeAgentMDFiles(results, outputDir) {
|
|
|
207
225
|
await mkdir(outputDir, { recursive: true });
|
|
208
226
|
const written = [];
|
|
209
227
|
for (const result of results) {
|
|
210
|
-
const path =
|
|
228
|
+
const path = resolveContainedPath(outputDir, result.fileName);
|
|
211
229
|
await writeFile(path, result.content, "utf-8");
|
|
212
230
|
written.push(path);
|
|
213
231
|
}
|