intentdna 1.6.4 → 1.7.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- 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 +1 -0
- package/dist/cli/commands/feedback.js +11 -0
- package/dist/cli/commands/generate.js +5 -33
- 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 +209 -190
- 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.js +97 -25
- package/dist/cli/index.js +76 -11
- package/dist/compiler/cascade.d.ts +3 -1
- package/dist/compiler/cascade.js +51 -0
- package/dist/compiler/compile.js +37 -0
- package/dist/compiler/diagnostics.d.ts +17 -0
- package/dist/compiler/diagnostics.js +30 -0
- package/dist/compiler/index.d.ts +3 -0
- package/dist/compiler/index.js +8 -11
- package/dist/compiler/input-resolver.d.ts +25 -0
- package/dist/compiler/input-resolver.js +175 -0
- package/dist/hooks/cli.d.ts +10 -1
- package/dist/hooks/cli.js +39 -26
- package/dist/hooks/event-registry.d.ts +17 -0
- package/dist/hooks/event-registry.js +89 -0
- package/dist/hooks/protocol.d.ts +1 -1
- package/dist/hooks/schema.js +5 -1
- package/dist/hooks/state.d.ts +2 -0
- package/dist/hooks/state.js +23 -2
- 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 +21 -53
- package/dist/mcp/tools-observability.js +24 -0
- package/dist/report/kernel-signals.js +3 -0
- package/dist/report/report-package.d.ts +56 -0
- package/dist/report/report-package.js +85 -0
- package/dist/runtime/agent-md.d.ts +1 -0
- package/dist/runtime/agent-md.js +21 -3
- package/dist/runtime/context-sources.d.ts +14 -0
- package/dist/runtime/context-sources.js +60 -0
- package/dist/runtime/markdown-target-registry.d.ts +17 -0
- package/dist/runtime/markdown-target-registry.js +37 -0
- package/dist/runtime/markdown.d.ts +2 -1
- package/dist/runtime/markdown.js +9 -12
- package/dist/runtime/output-artifact-registry.d.ts +11 -0
- package/dist/runtime/output-artifact-registry.js +30 -0
- package/dist/runtime/settings-adapter.d.ts +2 -1
- package/dist/runtime/settings-adapter.js +4 -12
- package/dist/runtime/skill-adapter.d.ts +32 -4
- package/dist/runtime/skill-adapter.js +187 -10
- package/dist/runtime/workflow-runner.d.ts +1 -1
- package/dist/runtime/workflow-runner.js +1 -1
- package/dist/schema/controller-registry.d.ts +29 -0
- package/dist/schema/controller-registry.js +35 -0
- package/dist/schema/types.d.ts +33 -0
- package/dist/schema/validate.js +157 -138
- package/dist/schema/validators/controllers.d.ts +3 -0
- package/dist/schema/validators/controllers.js +156 -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/dist/templates/metadata.d.ts +6 -0
- package/dist/templates/metadata.js +32 -0
- package/package.json +1 -1
- package/spec/foundation-hardening.md +2 -1
package/dist/signals/index.js
CHANGED
|
@@ -1,4 +1,35 @@
|
|
|
1
1
|
import { extractGeneFromReason } from "../evolution/trace-bridge.js";
|
|
2
|
+
const SAFE_EXTERNAL_GENE = /^[A-Za-z0-9:_-]+$/;
|
|
3
|
+
function hasSafeExternalGene(gene) {
|
|
4
|
+
return typeof gene === "string" && SAFE_EXTERNAL_GENE.test(gene);
|
|
5
|
+
}
|
|
6
|
+
function hasNonBlankText(value) {
|
|
7
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
8
|
+
}
|
|
9
|
+
function isSignalStatus(value) {
|
|
10
|
+
return value === "positive" || value === "negative" || value === "neutral";
|
|
11
|
+
}
|
|
12
|
+
function isExternalSignalClassification(value) {
|
|
13
|
+
return value === undefined || value === "protective" || value === "friction" || value === "unknown";
|
|
14
|
+
}
|
|
15
|
+
function hasFiniteConfidence(value) {
|
|
16
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1;
|
|
17
|
+
}
|
|
18
|
+
function hasExternalSignalShape(signal) {
|
|
19
|
+
return isSignalStatus(signal.status) &&
|
|
20
|
+
hasNonBlankText(signal.source) &&
|
|
21
|
+
isExternalSignalClassification(signal.classification) &&
|
|
22
|
+
(signal.confidence === undefined || hasFiniteConfidence(signal.confidence));
|
|
23
|
+
}
|
|
24
|
+
function isRecord(value) {
|
|
25
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26
|
+
}
|
|
27
|
+
function asString(value) {
|
|
28
|
+
return typeof value === "string" ? value : undefined;
|
|
29
|
+
}
|
|
30
|
+
function asNumber(value) {
|
|
31
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
32
|
+
}
|
|
2
33
|
function toSignalEvidence(result) {
|
|
3
34
|
const payload = {
|
|
4
35
|
target: result.target,
|
|
@@ -6,23 +37,75 @@ function toSignalEvidence(result) {
|
|
|
6
37
|
exit_code: result.exit_code,
|
|
7
38
|
artifact: result.artifact,
|
|
8
39
|
message: result.message,
|
|
40
|
+
evidence_ref: "evidence_ref" in result ? result.evidence_ref : undefined,
|
|
9
41
|
};
|
|
10
42
|
return Object.values(payload).some((value) => value !== undefined) ? payload : undefined;
|
|
11
43
|
}
|
|
44
|
+
function hasExternalSignalInputContract(signal) {
|
|
45
|
+
return (hasExternalSignalShape(signal) &&
|
|
46
|
+
hasFiniteConfidence(signal.confidence) &&
|
|
47
|
+
hasNonBlankText(signal.mapping_policy) &&
|
|
48
|
+
hasNonBlankText(signal.evidence_ref) &&
|
|
49
|
+
hasSafeExternalGene(signal.gene));
|
|
50
|
+
}
|
|
51
|
+
function hasExternalSignalEnvelopeContract(signal) {
|
|
52
|
+
return (isSignalStatus(signal.status) &&
|
|
53
|
+
hasNonBlankText(signal.source) &&
|
|
54
|
+
isExternalSignalClassification(signal.classification) &&
|
|
55
|
+
hasFiniteConfidence(signal.confidence) &&
|
|
56
|
+
hasNonBlankText(signal.mapping_policy) &&
|
|
57
|
+
hasNonBlankText(signal.evidence_payload?.evidence_ref) &&
|
|
58
|
+
hasSafeExternalGene(signal.gene));
|
|
59
|
+
}
|
|
12
60
|
function normalizeExternalSignals(adapterName, payload) {
|
|
13
61
|
const items = Array.isArray(payload) ? payload : [payload];
|
|
14
|
-
return items.map((
|
|
15
|
-
const timestamp =
|
|
62
|
+
return items.map((raw, index) => {
|
|
63
|
+
const timestamp = isRecord(raw) ? asString(raw.timestamp) ?? new Date().toISOString() : new Date().toISOString();
|
|
64
|
+
if (!isRecord(raw)) {
|
|
65
|
+
return {
|
|
66
|
+
id: `${adapterName}:invalid:${timestamp}:${index}`,
|
|
67
|
+
kind: "external",
|
|
68
|
+
status: "neutral",
|
|
69
|
+
timestamp,
|
|
70
|
+
source: `${adapterName}.invalid`,
|
|
71
|
+
adapter: adapterName,
|
|
72
|
+
classification: "unknown",
|
|
73
|
+
evolution_eligible: false,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const item = {
|
|
77
|
+
id: asString(raw.id),
|
|
78
|
+
status: raw.status,
|
|
79
|
+
timestamp,
|
|
80
|
+
gene: asString(raw.gene),
|
|
81
|
+
source: asString(raw.source) ?? "",
|
|
82
|
+
detail: asString(raw.detail),
|
|
83
|
+
target: asString(raw.target),
|
|
84
|
+
evidence: asString(raw.evidence),
|
|
85
|
+
exit_code: asNumber(raw.exit_code),
|
|
86
|
+
artifact: asString(raw.artifact),
|
|
87
|
+
message: asString(raw.message),
|
|
88
|
+
evidence_ref: asString(raw.evidence_ref),
|
|
89
|
+
classification: raw.classification,
|
|
90
|
+
confidence: typeof raw.confidence === "number" ? raw.confidence : undefined,
|
|
91
|
+
mapping_policy: asString(raw.mapping_policy),
|
|
92
|
+
};
|
|
93
|
+
const shapeValid = hasExternalSignalShape(item);
|
|
94
|
+
const complete = hasExternalSignalInputContract(item);
|
|
16
95
|
return {
|
|
17
|
-
id: item.id ?? `${adapterName}:${item.source}:${timestamp}:${index}`,
|
|
96
|
+
id: item.id ?? `${adapterName}:${shapeValid ? item.source : "invalid"}:${timestamp}:${index}`,
|
|
18
97
|
kind: "external",
|
|
19
|
-
status: item.status,
|
|
98
|
+
status: shapeValid ? item.status : "neutral",
|
|
20
99
|
timestamp,
|
|
21
100
|
gene: item.gene,
|
|
22
|
-
source: item.source
|
|
101
|
+
source: hasNonBlankText(item.source) ? item.source : `${adapterName}.invalid`,
|
|
23
102
|
detail: item.detail ?? item.message ?? item.evidence,
|
|
24
103
|
adapter: adapterName,
|
|
25
104
|
evidence_payload: toSignalEvidence(item),
|
|
105
|
+
classification: isExternalSignalClassification(item.classification) ? (item.classification ?? "unknown") : "unknown",
|
|
106
|
+
confidence: hasFiniteConfidence(item.confidence) ? item.confidence : undefined,
|
|
107
|
+
mapping_policy: item.mapping_policy,
|
|
108
|
+
evolution_eligible: complete,
|
|
26
109
|
};
|
|
27
110
|
});
|
|
28
111
|
}
|
|
@@ -85,6 +168,8 @@ export function signalsToOutcomes(signals, dnaId = "default") {
|
|
|
85
168
|
for (const signal of signals) {
|
|
86
169
|
if (!signal.gene)
|
|
87
170
|
continue;
|
|
171
|
+
if (signal.kind === "external" && !hasExternalSignalEnvelopeContract(signal))
|
|
172
|
+
continue;
|
|
88
173
|
const effect = signal.status === "positive"
|
|
89
174
|
? "helped"
|
|
90
175
|
: signal.status === "negative"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const BUILTIN_TEMPLATES_DIR: string;
|
|
2
|
+
export declare const PROJECT_TEMPLATES_DIR = ".dna/templates";
|
|
3
|
+
export interface TemplateCatalogEntry {
|
|
4
|
+
name: string;
|
|
5
|
+
path: string;
|
|
6
|
+
namespace?: string;
|
|
7
|
+
displayName?: string;
|
|
8
|
+
version?: string;
|
|
9
|
+
contentHash: string;
|
|
10
|
+
source: "builtin" | "project";
|
|
11
|
+
keywords: readonly string[];
|
|
12
|
+
}
|
|
13
|
+
export declare function calculateTemplateContentHash(content: string): string;
|
|
14
|
+
export declare function listTemplateCatalog(options?: {
|
|
15
|
+
projectDir?: string;
|
|
16
|
+
}): Promise<TemplateCatalogEntry[]>;
|
|
17
|
+
export declare function findTemplateCatalogEntry(name: string, options?: {
|
|
18
|
+
projectDir?: string;
|
|
19
|
+
}): Promise<TemplateCatalogEntry | undefined>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { parseYAML } from "../schema/yaml-parser.js";
|
|
6
|
+
import { getTemplateMatchMetadata } from "./metadata.js";
|
|
7
|
+
export const BUILTIN_TEMPLATES_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "..", "templates");
|
|
8
|
+
export const PROJECT_TEMPLATES_DIR = ".dna/templates";
|
|
9
|
+
function calculateContentHash(content) {
|
|
10
|
+
return createHash("sha256").update(content, "utf-8").digest("hex").slice(0, 16);
|
|
11
|
+
}
|
|
12
|
+
async function readTemplateEntry(path, source) {
|
|
13
|
+
const content = await readFile(path, "utf-8");
|
|
14
|
+
const data = parseYAML(content);
|
|
15
|
+
const fileName = path.split("/").pop() ?? path;
|
|
16
|
+
const name = fileName.replace(/\.dna\.ya?ml$/, "");
|
|
17
|
+
const matchMetadata = getTemplateMatchMetadata(name);
|
|
18
|
+
return {
|
|
19
|
+
name,
|
|
20
|
+
path,
|
|
21
|
+
namespace: typeof data.namespace === "string" ? data.namespace : undefined,
|
|
22
|
+
displayName: typeof data.name === "string" ? data.name : undefined,
|
|
23
|
+
version: typeof data.version === "string" ? data.version : undefined,
|
|
24
|
+
contentHash: calculateContentHash(content),
|
|
25
|
+
source,
|
|
26
|
+
keywords: matchMetadata?.keywords ?? [],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
async function collectTemplates(dir, source) {
|
|
30
|
+
try {
|
|
31
|
+
const files = await readdir(dir);
|
|
32
|
+
const templateFiles = files
|
|
33
|
+
.filter((file) => file.endsWith(".dna.yaml") || file.endsWith(".dna.yml"))
|
|
34
|
+
.sort();
|
|
35
|
+
const entries = [];
|
|
36
|
+
for (const file of templateFiles) {
|
|
37
|
+
entries.push(await readTemplateEntry(resolve(dir, file), source));
|
|
38
|
+
}
|
|
39
|
+
return entries;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function calculateTemplateContentHash(content) {
|
|
46
|
+
return calculateContentHash(content);
|
|
47
|
+
}
|
|
48
|
+
export async function listTemplateCatalog(options) {
|
|
49
|
+
const projectDir = options?.projectDir ?? process.cwd();
|
|
50
|
+
const builtin = await collectTemplates(BUILTIN_TEMPLATES_DIR, "builtin");
|
|
51
|
+
const project = await collectTemplates(resolve(projectDir, PROJECT_TEMPLATES_DIR), "project");
|
|
52
|
+
return [...builtin, ...project];
|
|
53
|
+
}
|
|
54
|
+
export async function findTemplateCatalogEntry(name, options) {
|
|
55
|
+
const entries = await listTemplateCatalog(options);
|
|
56
|
+
return entries.find((entry) => entry.name === name || entry.displayName === name || entry.namespace === name);
|
|
57
|
+
}
|
|
@@ -335,8 +335,8 @@ controllers:
|
|
|
335
335
|
- "- MAX_ROUNDS: stop, report max rounds reached and next focus"
|
|
336
336
|
stop_report:
|
|
337
337
|
- "On REQUEST_CHANGES, BLOCKED, or MAX_ROUNDS, output exactly these Chinese sections:"
|
|
338
|
-
- "结论:state the direct stop trigger, current round, and current commit if one exists."
|
|
339
|
-
- "为什么停止:explain the workflow principle in plain language; if this is a current-round new red, explain that continuing would build on a bad baseline."
|
|
338
|
+
- "结论:state the direct stop trigger, current round, and current commit if one exists; cite verifier result_id, trace_id, or ArtifactManifest artifact id."
|
|
339
|
+
- "为什么停止:explain the workflow principle in plain language; if this is a current-round new red, explain that continuing would build on a bad baseline; prose-only claims are not sufficient."
|
|
340
340
|
- "是否回滚:say whether rollback/revert is recommended. If the commit direction looks wrong or the blast radius is unclear, recommend revert; if the failure is narrow and fixable, recommend fix-forward."
|
|
341
341
|
- "下一步:give one concrete next action. If recommending fix-forward, include a copy-paste single-fix prompt with current commit, exact failure, allowed scope, forbidden actions, verification command, commit expectation, and stop conditions."
|
|
342
342
|
constraints:
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface TemplateMatchMetadata {
|
|
2
|
+
name: string;
|
|
3
|
+
keywords: readonly string[];
|
|
4
|
+
}
|
|
5
|
+
export declare const TEMPLATE_MATCH_METADATA: readonly TemplateMatchMetadata[];
|
|
6
|
+
export declare function getTemplateMatchMetadata(name: string): TemplateMatchMetadata | undefined;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const TEMPLATE_MATCH_METADATA = [
|
|
2
|
+
{ name: "code-review-pipeline", keywords: ["review", "code review", "pr review", "pull request", "审查"] },
|
|
3
|
+
{ name: "safe-refactoring", keywords: ["refactor", "refactoring", "restructure", "rewrite safely", "重构"] },
|
|
4
|
+
{ name: "tdd-strict", keywords: ["tdd", "test driven", "test first", "red green", "测试驱动"] },
|
|
5
|
+
{ name: "full-pipeline", keywords: ["pipeline", "plan implement test", "full workflow", "完整流水线"] },
|
|
6
|
+
{ name: "systematic-debugging", keywords: ["debug", "debugging", "bug fix", "troubleshoot", "调试"] },
|
|
7
|
+
{ name: "verification-loop", keywords: ["verify", "verification", "validate", "check", "验证"] },
|
|
8
|
+
{ name: "secure-dev", keywords: ["security", "secure", "owasp", "vulnerability", "安全"] },
|
|
9
|
+
{ name: "enterprise-baseline", keywords: ["enterprise", "organization", "company", "corporate", "企业"] },
|
|
10
|
+
{ name: "frontend-quality", keywords: ["frontend", "react", "vue", "css", "ui", "前端"] },
|
|
11
|
+
{ name: "api-backend", keywords: ["api", "backend", "rest", "graphql", "server", "后端"] },
|
|
12
|
+
{ name: "mobile-dev", keywords: ["mobile", "ios", "android", "react native", "移动"] },
|
|
13
|
+
{ name: "documentation-writer", keywords: ["doc", "documentation", "readme", "wiki", "文档"] },
|
|
14
|
+
{ name: "devops-cicd", keywords: ["devops", "ci", "cd", "deploy", "pipeline", "运维"] },
|
|
15
|
+
{ name: "monorepo-governance", keywords: ["monorepo", "workspace", "packages", "governance"] },
|
|
16
|
+
{ name: "flutter-behavior-lock", keywords: ["flutter", "behavior lock", "behavior spec", "行为锁定"] },
|
|
17
|
+
{ name: "flutter-rewrite", keywords: ["flutter", "rewrite", "migration", "flutter rewrite"] },
|
|
18
|
+
{ name: "flutter-refactoring-rescue", keywords: ["flutter", "rescue", "refactoring rescue"] },
|
|
19
|
+
{ name: "multi-perspective-review", keywords: ["multi perspective", "multiple reviewer", "多角度"] },
|
|
20
|
+
{ name: "subagent-parallel", keywords: ["parallel", "subagent", "concurrent", "并行"] },
|
|
21
|
+
{ name: "yolo-with-guardrails", keywords: ["yolo", "fast", "guardrails", "move fast"] },
|
|
22
|
+
{ name: "brainstorming-first", keywords: ["brainstorm", "explore", "ideation", "探索"] },
|
|
23
|
+
{ name: "branch-finishing", keywords: ["branch", "finish", "cleanup", "pr prep"] },
|
|
24
|
+
{ name: "pr-submitter", keywords: ["pr", "pull request", "submit"] },
|
|
25
|
+
{ name: "migration-safety", keywords: ["migration", "migrate", "upgrade", "database migration", "dependency upgrade", "迁移"] },
|
|
26
|
+
{ name: "incident-response", keywords: ["incident", "production issue", "hotfix", "outage", "postmortem", "事故"] },
|
|
27
|
+
{ name: "performance-audit", keywords: ["performance", "profiling", "benchmark", "optimize", "latency", "性能"] },
|
|
28
|
+
];
|
|
29
|
+
const TEMPLATE_MATCH_METADATA_BY_NAME = new Map(TEMPLATE_MATCH_METADATA.map((entry) => [entry.name, entry]));
|
|
30
|
+
export function getTemplateMatchMetadata(name) {
|
|
31
|
+
return TEMPLATE_MATCH_METADATA_BY_NAME.get(name);
|
|
32
|
+
}
|
package/package.json
CHANGED