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.
Files changed (82) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +26 -15
  4. package/dist/cli/commands/compile.js +2 -47
  5. package/dist/cli/commands/context.d.ts +8 -0
  6. package/dist/cli/commands/context.js +63 -0
  7. package/dist/cli/commands/feedback.d.ts +3 -2
  8. package/dist/cli/commands/feedback.js +16 -5
  9. package/dist/cli/commands/init.js +11 -63
  10. package/dist/cli/commands/run.js +5 -4
  11. package/dist/cli/commands/show.js +2 -38
  12. package/dist/cli/commands/sync.d.ts +9 -6
  13. package/dist/cli/commands/sync.js +191 -186
  14. package/dist/cli/commands/templates.d.ts +10 -1
  15. package/dist/cli/commands/templates.js +50 -1
  16. package/dist/cli/commands/validate.js +15 -9
  17. package/dist/cli/commands/verify.d.ts +32 -0
  18. package/dist/cli/commands/verify.js +270 -31
  19. package/dist/cli/index.js +78 -11
  20. package/dist/compiler/activate.js +11 -6
  21. package/dist/compiler/cascade.d.ts +5 -1
  22. package/dist/compiler/cascade.js +74 -1
  23. package/dist/compiler/compile.js +38 -0
  24. package/dist/compiler/diagnostics.d.ts +17 -0
  25. package/dist/compiler/diagnostics.js +30 -0
  26. package/dist/compiler/index.d.ts +7 -0
  27. package/dist/compiler/index.js +13 -13
  28. package/dist/compiler/input-resolver.d.ts +32 -0
  29. package/dist/compiler/input-resolver.js +281 -0
  30. package/dist/compiler/provenance.d.ts +8 -0
  31. package/dist/compiler/provenance.js +127 -0
  32. package/dist/governance/index.d.ts +4 -3
  33. package/dist/governance/index.js +3 -4
  34. package/dist/governance/runtime-decision-event.d.ts +85 -0
  35. package/dist/governance/runtime-decision-event.js +231 -0
  36. package/dist/governance/types.d.ts +3 -3
  37. package/dist/governance/types.js +3 -3
  38. package/dist/hooks/cli.d.ts +10 -1
  39. package/dist/hooks/cli.js +199 -35
  40. package/dist/hooks/state.d.ts +5 -10
  41. package/dist/hooks/state.js +170 -2
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.js +1 -0
  44. package/dist/mcp/index.js +2 -0
  45. package/dist/mcp/tools-compile.js +18 -49
  46. package/dist/mcp/tools-context.d.ts +2 -0
  47. package/dist/mcp/tools-context.js +85 -0
  48. package/dist/mcp/tools-enforce.d.ts +2 -2
  49. package/dist/mcp/tools-enforce.js +19 -49
  50. package/dist/mcp/tools-observability.js +26 -2
  51. package/dist/mcp/tools-state.d.ts +1 -1
  52. package/dist/mcp/tools-state.js +17 -7
  53. package/dist/report/kernel-report.d.ts +27 -0
  54. package/dist/report/kernel-report.js +60 -19
  55. package/dist/report/kernel-signals.d.ts +5 -2
  56. package/dist/report/kernel-signals.js +87 -2
  57. package/dist/report/report-package.d.ts +64 -0
  58. package/dist/report/report-package.js +90 -0
  59. package/dist/runtime/agent-md.d.ts +1 -0
  60. package/dist/runtime/agent-md.js +21 -3
  61. package/dist/runtime/claude-sdk.d.ts +9 -4
  62. package/dist/runtime/claude-sdk.js +9 -0
  63. package/dist/runtime/context-sources.d.ts +14 -0
  64. package/dist/runtime/context-sources.js +60 -0
  65. package/dist/runtime/plugin-adapter.d.ts +5 -1
  66. package/dist/runtime/plugin-adapter.js +2 -0
  67. package/dist/runtime/skill-adapter.d.ts +32 -4
  68. package/dist/runtime/skill-adapter.js +184 -9
  69. package/dist/runtime/workflow-runner.d.ts +1 -1
  70. package/dist/runtime/workflow-runner.js +1 -1
  71. package/dist/schema/types.d.ts +84 -0
  72. package/dist/schema/validate.js +156 -2
  73. package/dist/schema/validators/controllers.js +16 -0
  74. package/dist/signals/index.d.ts +10 -0
  75. package/dist/signals/index.js +90 -5
  76. package/dist/templates/catalog.d.ts +19 -0
  77. package/dist/templates/catalog.js +57 -0
  78. package/dist/templates/flutter-rewrite.dna.yaml +2 -2
  79. package/package.json +1 -1
  80. package/spec/README.md +1 -1
  81. package/spec/foundation-hardening.md +2 -1
  82. package/spec/schema-spec.md +78 -1
@@ -9,7 +9,7 @@
9
9
  {
10
10
  "name": "intentdna",
11
11
  "description": "Declarative policy layer for AI agent behavior with plugin-managed hook runtime for Claude Code.",
12
- "version": "1.6.5",
12
+ "version": "1.7.4",
13
13
  "author": {
14
14
  "name": "Samuel"
15
15
  },
@@ -25,5 +25,5 @@
25
25
  ]
26
26
  }
27
27
  ],
28
- "version": "1.6.5"
28
+ "version": "1.7.4"
29
29
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intentdna",
3
- "version": "1.6.5",
3
+ "version": "1.7.4",
4
4
  "description": "Declarative policy layer for AI agent behavior",
5
5
  "author": {
6
6
  "name": "Samuel"
package/README.md CHANGED
@@ -1,26 +1,32 @@
1
1
  # Intent DNA
2
2
 
3
- **Declarative control plane for AI agent behavior.**
3
+ **Enterprise safety control plane for AI agent behavior.**
4
4
 
5
- Intent DNA turns intent, policy, and accumulated experience into enforceable agent constraints. Instead of relying on prompts alone, it compiles DNA into the native control surfaces of Claude Code and related harnesses. It governs how agents operate across existing tools and systems; it does not replace your business systems or act as a domain-specific automation runtime.
5
+ Intent DNA lets an organization declare safety policy once, cascade it through Species Enterprise Project Personal Role → Context → Task, and compile it into deterministic gates for every agent, project, and harness. It governs how agents operate across existing tools and systems; it does not replace your business systems or act as a domain-specific automation runtime.
6
6
 
7
7
  ---
8
8
 
9
9
  ## What It Is
10
10
 
11
- Intent DNA is a compiler and runtime toolkit for managing agent behavior across four layers:
11
+ Intent DNA is an enforcement-first control plane for organization-wide agent safety:
12
12
 
13
- - **Behavioral guidance** via generated prompt/context files
14
- - **Deterministic enforcement** via hooks and runtime checks
15
- - **Artifact handoff** via session-scoped manifests and resolver facts
16
- - **Feedback loops** via trace, audit, and epigenetic evolution
13
+ - **Enterprise / Species policy bundles** define shared red lines across projects and teams
14
+ - **Cascade governance** preserves provenance and prevents lower layers from relaxing organization thresholds
15
+ - **Constraint IR** carries policy provenance into hook, SDK-check, and CI strict gates
16
+ - **RuntimeDecisionEvent evidence** records who/what/why/from which policy for every allow/warn/block/escalate/validate decision
17
+ - **MCP, reports, state, trace, audit, and evolution** query or package evidence; they are not the policy source of truth
17
18
 
18
19
  It governs the agents operating on your systems rather than re-implementing the systems themselves.
19
20
 
20
21
  The core model is:
21
22
 
22
23
  ```text
23
- DNA config compiler pipeline → Constraint IR → harness-specific outputs
24
+ Enterprise / Species Policy Bundle
25
+ → Species→Enterprise→Project→Personal→Role→Context→Task Cascade
26
+ → Constraint IR + Provenance Manifest
27
+ → Hook / SDK-check / CI strict gate
28
+ → RuntimeDecisionEvent
29
+ → MCP / report / dashboard / evolution evidence layer
24
30
  ```
25
31
 
26
32
  For the architectural model and long-term design, see [DESIGN.md](DESIGN.md).
@@ -30,9 +36,10 @@ For the schema contract, see [spec/schema-spec.md](spec/schema-spec.md).
30
36
  ## Design Principles
31
37
 
32
38
  - Govern agents rather than re-implementing business systems.
33
- - Declare intent and boundaries first, then compile them into native control surfaces.
34
- - Combine guidance, enforcement, validation, and feedback into one governance loop.
35
- - Treat runtime state, validators, and signals as first-class governance assets.
39
+ - Declare enterprise safety red lines first, then compile them into native control surfaces.
40
+ - Treat Species and Enterprise thresholds as non-relaxable by Project, Personal, Role, Context, or Task layers.
41
+ - Keep enforcement points authoritative: hooks, SDK checks, and CI gates make decisions from compiled IR and provenance.
42
+ - Treat runtime state, validators, traces, reports, MCP queries, and signals as evidence assets, not policy truth.
36
43
  - Keep adapters and signal ingestion pluggable so the control plane outlives any single tool.
37
44
 
38
45
  ---
@@ -70,10 +77,10 @@ dna init --upgrade <template-name>
70
77
 
71
78
  ## How It Works
72
79
 
73
- Intent DNA compiles to your tool's native control surfaces:
80
+ Intent DNA compiles organization policy to your tool's native control surfaces:
74
81
 
75
82
  ```text
76
- DNA → Constraint IR → CLAUDE.md / settings / agents / skills / runtime state
83
+ DNA → Cascade provenance → Constraint IR → hooks / SDK checks / CI gates evidence
77
84
  ```
78
85
 
79
86
  Typical outputs include:
@@ -82,12 +89,14 @@ Typical outputs include:
82
89
  |--------|---------|
83
90
  | `CLAUDE.md` | Behavioral guidance |
84
91
  | `.dna/compiled/ir.json` | Runtime-readable compiled constraints |
92
+ | provenance manifest | Policy bundle, cascade layers, winners, and compiled IR hash |
93
+ | RuntimeDecisionEvent | Enterprise evidence for allow/warn/block/escalate/validate decisions |
85
94
  | `.dna/state/sessions/*/handoffs/*.json` | Local artifact manifests for workflow handoff facts |
86
95
  | `.claude/agents/*.md` | Role definitions |
87
96
  | `.claude/skills/*/SKILL.md` | Workflow entrypoints |
88
97
  | `.claude/settings.json` or plugin runtime | Hook wiring |
89
98
 
90
- **Key idea:** prompts can drift, but runtime constraints, resolver-backed handoffs, and feedback loops make behavior governable.
99
+ **Key idea:** prompts can drift, but non-relaxable enterprise thresholds, compiled gates, and provenance-backed runtime evidence make behavior governable.
91
100
 
92
101
  ---
93
102
 
@@ -95,11 +104,13 @@ Typical outputs include:
95
104
 
96
105
  Intent DNA currently focuses on:
97
106
 
107
+ - Enterprise Safety Slice: shared policy bundles, cascade provenance, and non-relaxable organization thresholds
98
108
  - Claude Code / Claude-style harnesses
99
109
  - Role-based agent workflows
100
110
  - Template-driven project bootstrap and upgrades
101
111
  - Deterministic guardrails and stateful enforcement
102
112
  - Resolver-backed artifact handoff between workflow steps
113
+ - Evidence-layer MCP/report/state/trace/audit surfaces
103
114
  - Dogfood-driven template iteration
104
115
 
105
116
  Adapter and ecosystem direction are tracked in [ROADMAP.md](ROADMAP.md), not duplicated here.
@@ -157,7 +168,7 @@ workflows:
157
168
  description: Review the implementation
158
169
  ```
159
170
 
160
- **Cascade:** DNA files inherit and override by priority. `threshold` codons (safety rules) can never be relaxed even by higher priority DNA.
171
+ **Cascade:** DNA files inherit and override by priority. `threshold` codons (safety rules) from Species or Enterprise are red lines: Project, Personal, Role, Context, and Task layers may add stricter rules but cannot relax them.
161
172
 
162
173
  **Genes:** Behavioral traits (attract/repel/threshold/weight/sense).
163
174
 
@@ -4,53 +4,8 @@
4
4
  * Compile DNA files to framework-specific configuration.
5
5
  */
6
6
  import { writeFile } from "node:fs/promises";
7
- import { resolve, dirname } from "node:path";
8
- import { fileURLToPath } from "node:url";
9
- import { compileFromFiles } from "../../compiler/index.js";
7
+ import { compileFromFiles, expandDNAInputFiles } from "../../compiler/index.js";
10
8
  import { compileForClaude } from "../../runtime/claude-sdk.js";
11
- /**
12
- * Resolve the species default DNA path relative to this module's location.
13
- */
14
- function resolveSpeciesPath(ref) {
15
- if (!ref.startsWith("species:"))
16
- return null;
17
- const name = ref.slice("species:".length);
18
- const thisDir = dirname(fileURLToPath(import.meta.url));
19
- // From dist/cli/commands/ -> dist/species/
20
- return resolve(thisDir, "..", "..", "species", `${name}.dna.json`);
21
- }
22
- /**
23
- * Expand species references in file list and add species default if any DNA inherits it.
24
- */
25
- async function expandFiles(files) {
26
- const { readFile } = await import("node:fs/promises");
27
- const expanded = [];
28
- const seen = new Set();
29
- // First pass: collect all files and check for species references
30
- for (const file of files) {
31
- const abs = resolve(file);
32
- if (seen.has(abs))
33
- continue;
34
- seen.add(abs);
35
- expanded.push(abs);
36
- // Check if this DNA inherits from species
37
- try {
38
- const raw = await readFile(abs, "utf-8");
39
- const dna = JSON.parse(raw);
40
- for (const ref of dna.cascade?.inherits ?? []) {
41
- const speciesPath = resolveSpeciesPath(ref);
42
- if (speciesPath && !seen.has(speciesPath)) {
43
- seen.add(speciesPath);
44
- expanded.unshift(speciesPath); // species goes first (lowest priority)
45
- }
46
- }
47
- }
48
- catch {
49
- // Will fail later during compilation with proper error
50
- }
51
- }
52
- return expanded;
53
- }
54
9
  export async function runCompile(opts) {
55
10
  if (opts.files.length === 0) {
56
11
  process.stderr.write("Error: no files specified\n");
@@ -62,7 +17,7 @@ export async function runCompile(opts) {
62
17
  return 2;
63
18
  }
64
19
  try {
65
- const expandedFiles = await expandFiles(opts.files);
20
+ const expandedFiles = await expandDNAInputFiles(opts.files);
66
21
  const ir = await compileFromFiles(expandedFiles, opts.context);
67
22
  let output;
68
23
  if (opts.ir) {
@@ -0,0 +1,8 @@
1
+ export interface ContextOptions {
2
+ subcommand: string;
3
+ query?: string;
4
+ id?: string;
5
+ files?: string[];
6
+ projectDir?: string;
7
+ }
8
+ export declare function runContext(opts: ContextOptions): Promise<number>;
@@ -0,0 +1,63 @@
1
+ import { resolve } from "node:path";
2
+ import { findContextSource, formatContextSource, loadContextSourceIndex, readContextSourceDocument, searchContextSources, } from "../../runtime/context-sources.js";
3
+ function usage() {
4
+ return "Usage: dna context <index|search|doc> [query|id] [files...]\n";
5
+ }
6
+ export async function runContext(opts) {
7
+ const projectDir = opts.projectDir ?? process.cwd();
8
+ const files = opts.files?.map((file) => resolve(projectDir, file));
9
+ const index = await loadContextSourceIndex(projectDir, files);
10
+ switch (opts.subcommand) {
11
+ case "index": {
12
+ if (index.sources.length === 0) {
13
+ process.stdout.write("No advisory context sources declared.\n");
14
+ return 0;
15
+ }
16
+ process.stdout.write(index.sources.map(formatContextSource).join("\n") + "\n");
17
+ if (index.planning_instructions.length > 0) {
18
+ process.stdout.write("\nPlanning instructions:\n");
19
+ for (const instruction of index.planning_instructions) {
20
+ process.stdout.write(`- ${instruction}\n`);
21
+ }
22
+ }
23
+ return 0;
24
+ }
25
+ case "search": {
26
+ const query = opts.query ?? "";
27
+ const matches = searchContextSources(index, query);
28
+ if (matches.length === 0) {
29
+ process.stdout.write(`No advisory context sources matched '${query}'.\n`);
30
+ return 1;
31
+ }
32
+ process.stdout.write(matches.map(formatContextSource).join("\n") + "\n");
33
+ return 0;
34
+ }
35
+ case "doc": {
36
+ const id = opts.id ?? "";
37
+ if (!id) {
38
+ process.stderr.write("Error: context doc requires a source id.\n");
39
+ process.stderr.write(usage());
40
+ return 2;
41
+ }
42
+ const source = findContextSource(index, id);
43
+ if (!source) {
44
+ process.stderr.write(`Error: unknown advisory context source '${id}'.\n`);
45
+ return 1;
46
+ }
47
+ const doc = await readContextSourceDocument(projectDir, source);
48
+ process.stdout.write(`${formatContextSource(source)}\n`);
49
+ process.stdout.write("Planning-only advisory context; does not satisfy enforcement, handoff, or ArtifactManifest requirements.\n");
50
+ if (doc.content !== undefined) {
51
+ process.stdout.write("\n---\n");
52
+ process.stdout.write(doc.content.endsWith("\n") ? doc.content : `${doc.content}\n`);
53
+ }
54
+ else {
55
+ process.stdout.write("No local document body is available for this source type.\n");
56
+ }
57
+ return 0;
58
+ }
59
+ default:
60
+ process.stderr.write(usage());
61
+ return 2;
62
+ }
63
+ }
@@ -1,13 +1,14 @@
1
1
  /**
2
2
  * dna feedback [--days <N>] [--json] [--evolve]
3
3
  *
4
- * Build a local kernel observability report from traces and verifier results.
5
- * With --evolve: include a preview-only marker diff derived from local signals.
4
+ * Build a local kernel observability report from RuntimeDecisionEvent evidence.
5
+ * Legacy traces and verifier results are included as diagnostic context only.
6
6
  */
7
7
  export interface FeedbackOptions {
8
8
  days: number;
9
9
  json: boolean;
10
10
  evolve: boolean;
11
11
  dnaId?: string;
12
+ packageReport?: boolean;
12
13
  }
13
14
  export declare function runFeedback(opts: FeedbackOptions): Promise<number>;
@@ -1,20 +1,31 @@
1
1
  /**
2
2
  * dna feedback [--days <N>] [--json] [--evolve]
3
3
  *
4
- * Build a local kernel observability report from traces and verifier results.
5
- * With --evolve: include a preview-only marker diff derived from local signals.
4
+ * Build a local kernel observability report from RuntimeDecisionEvent evidence.
5
+ * Legacy traces and verifier results are included as diagnostic context only.
6
6
  */
7
7
  import { buildKernelReport, formatKernelReport } from "../../report/kernel-report.js";
8
+ import { buildReportPackage } from "../../report/report-package.js";
8
9
  export async function runFeedback(opts) {
10
+ if (opts.packageReport) {
11
+ const reportPackage = await buildReportPackage({
12
+ projectDir: process.cwd(),
13
+ days: opts.days,
14
+ includeMarkerPreview: opts.evolve,
15
+ dnaId: opts.dnaId,
16
+ });
17
+ process.stdout.write(JSON.stringify(reportPackage, null, 2) + "\n");
18
+ return 0;
19
+ }
9
20
  const report = await buildKernelReport({
10
21
  projectDir: process.cwd(),
11
22
  days: opts.days,
12
23
  includeMarkerPreview: opts.evolve,
13
24
  dnaId: opts.dnaId,
14
25
  });
15
- if (report.summary.traces === 0 && report.summary.verifier_results === 0) {
16
- process.stderr.write(`No trace or verifier data found for the last ${opts.days} day(s).\n`);
17
- process.stderr.write("Signals are generated by dna-hook during Claude Code sessions.\n");
26
+ if (report.summary.runtime_decisions === 0 && report.summary.legacy_diagnostics === 0) {
27
+ process.stderr.write(`No RuntimeDecisionEvent evidence or legacy diagnostics found for the last ${opts.days} day(s).\n`);
28
+ process.stderr.write("RuntimeDecisionEvent evidence is generated by dna-hook during Claude Code sessions.\n");
18
29
  return 0;
19
30
  }
20
31
  if (opts.json) {
@@ -6,8 +6,8 @@
6
6
  import { writeFile, readFile, readdir, mkdir, copyFile, access } from "node:fs/promises";
7
7
  import { resolve, dirname, basename } from "node:path";
8
8
  import { fileURLToPath } from "node:url";
9
- import { createHash } from "node:crypto";
10
9
  import { parseYAML } from "../../schema/yaml-parser.js";
10
+ import { listTemplateCatalog, calculateTemplateContentHash } from "../../templates/catalog.js";
11
11
  import { sanitizeTemplateName } from "../util/version.js";
12
12
  import { validateDNA } from "../../schema/validate.js";
13
13
  import { askString, askChoice, askNumber, askYesNo, closePrompt } from "../util/prompt.js";
@@ -23,53 +23,20 @@ async function dirExists(path) {
23
23
  return false;
24
24
  }
25
25
  }
26
- /**
27
- * Extract namespace and display name from a template YAML file.
28
- */
29
- async function readTemplateMetadata(filePath) {
30
- try {
31
- const content = await readFile(filePath, "utf-8");
32
- const data = parseYAML(content);
33
- return {
34
- namespace: typeof data.namespace === "string" ? data.namespace : undefined,
35
- displayName: typeof data.name === "string" ? data.name : undefined,
36
- };
37
- }
38
- catch {
39
- return {};
40
- }
41
- }
42
26
  async function listTemplates() {
43
- const results = [];
44
- // Built-in templates
45
- try {
46
- const files = await readdir(TEMPLATES_DIR);
47
- for (const f of files.filter((f) => f.endsWith(".dna.yaml"))) {
48
- const name = f.replace(".dna.yaml", "");
49
- const meta = await readTemplateMetadata(resolve(TEMPLATES_DIR, f));
50
- results.push({ name, namespace: meta.namespace, displayName: meta.displayName, source: "builtin" });
51
- }
52
- }
53
- catch { /* no built-in templates */ }
54
- // Project-local templates
55
- if (await dirExists(PROJECT_TEMPLATES_DIR)) {
56
- try {
57
- const files = await readdir(PROJECT_TEMPLATES_DIR);
58
- for (const f of files.filter((f) => f.endsWith(".dna.yaml"))) {
59
- const name = f.replace(".dna.yaml", "");
60
- const meta = await readTemplateMetadata(resolve(PROJECT_TEMPLATES_DIR, f));
61
- results.push({ name, namespace: meta.namespace, displayName: meta.displayName, source: "project" });
62
- }
63
- }
64
- catch { /* no project templates */ }
65
- }
66
- return results;
27
+ const entries = await listTemplateCatalog();
28
+ return entries.map((entry) => ({
29
+ name: entry.name,
30
+ namespace: entry.namespace,
31
+ displayName: entry.displayName,
32
+ source: entry.source,
33
+ }));
67
34
  }
68
35
  /**
69
36
  * Calculate SHA256 hash of template content (truncated to 16 hex chars).
70
37
  */
71
38
  export function calculateTemplateHash(content) {
72
- return createHash("sha256").update(content, "utf-8").digest("hex").slice(0, 16);
39
+ return calculateTemplateContentHash(content);
73
40
  }
74
41
  /**
75
42
  * Inject _source_template, _template_version, and _template_content_hash fields after the namespace/type line in YAML content.
@@ -122,27 +89,8 @@ function inferTemplateName(id) {
122
89
  * Priority: .dna/configs/*.yaml (multi-config) > legacy single-config
123
90
  */
124
91
  async function autoDetectConfigsForUpgrade() {
125
- // Priority 1: .dna/configs/*.yaml (multi-config)
126
- try {
127
- const files = await readdir(MULTI_CONFIG_DIR);
128
- const yamls = files
129
- .filter(f => f.endsWith(".yaml") || f.endsWith(".yml"))
130
- .sort()
131
- .map(f => resolve(MULTI_CONFIG_DIR, f));
132
- if (yamls.length > 0)
133
- return yamls;
134
- }
135
- catch { /* dir doesn't exist */ }
136
- // Fallback: legacy single-config paths
137
- const candidates = [
138
- ".dna/config.yaml", ".dna/config.yml", ".dna/config.json",
139
- ".dna.yaml", ".dna.yml", ".dna.json",
140
- ];
141
- for (const name of candidates) {
142
- if (await dirExists(name))
143
- return [name];
144
- }
145
- return [];
92
+ const { detectDNAConfigs } = await import("../../compiler/index.js");
93
+ return detectDNAConfigs(process.cwd());
146
94
  }
147
95
  /**
148
96
  * Upgrade config from a newer template version while preserving user-filled variables.
@@ -9,7 +9,7 @@ import { spawn } from "node:child_process";
9
9
  import { mkdir, writeFile } from "node:fs/promises";
10
10
  import { join } from "node:path";
11
11
  import { randomUUID } from "node:crypto";
12
- import { loadDNA, compileFromFiles } from "../../compiler/index.js";
12
+ import { loadDNA, compileFromFiles, expandDNAInputFiles } from "../../compiler/index.js";
13
13
  import { cascadeDNA } from "../../compiler/cascade.js";
14
14
  import { compileWorkflow } from "../../compiler/workflow.js";
15
15
  import { compileAllRolesToAgentMD, writeAgentMDFiles, toKebabCase, } from "../../runtime/agent-md.js";
@@ -254,14 +254,15 @@ export async function runRun(opts) {
254
254
  return 2;
255
255
  }
256
256
  const maxBudget = opts.maxBudget ?? 5;
257
- const permissionMode = opts.permissionMode ?? "bypassPermissions";
257
+ const permissionMode = opts.permissionMode ?? "default";
258
258
  const agentsDir = opts.agentsDir ?? ".claude/agents";
259
259
  try {
260
260
  // ── Step 1: Load & compile DNA ───────────────────────
261
261
  log("Loading DNA files...");
262
- const dnas = await Promise.all(opts.dnaFiles.map(loadDNA));
262
+ const expandedDNAFiles = await expandDNAInputFiles(opts.dnaFiles);
263
+ const dnas = await Promise.all(expandedDNAFiles.map(loadDNA));
263
264
  const cascaded = cascadeDNA(dnas);
264
- const ir = await compileFromFiles(opts.dnaFiles, {
265
+ const ir = await compileFromFiles(expandedDNAFiles, {
265
266
  context: opts.context,
266
267
  });
267
268
  // ── Step 2: Find & compile workflow ──────────────────
@@ -3,51 +3,15 @@
3
3
  *
4
4
  * Show DNA gene expression state in human-readable format.
5
5
  */
6
- import { resolve, dirname } from "node:path";
7
- import { readFile } from "node:fs/promises";
8
- import { fileURLToPath } from "node:url";
9
- import { loadDNA, cascadeDNA, activateDNA } from "../../compiler/index.js";
6
+ import { loadDNA, cascadeDNA, activateDNA, expandDNAInputFiles } from "../../compiler/index.js";
10
7
  import { formatGene, bold } from "../util/format.js";
11
- function resolveSpeciesPath(ref) {
12
- if (!ref.startsWith("species:"))
13
- return null;
14
- const name = ref.slice("species:".length);
15
- const thisDir = dirname(fileURLToPath(import.meta.url));
16
- return resolve(thisDir, "..", "..", "species", `${name}.dna.json`);
17
- }
18
- async function expandFiles(files) {
19
- const expanded = [];
20
- const seen = new Set();
21
- for (const file of files) {
22
- const abs = resolve(file);
23
- if (seen.has(abs))
24
- continue;
25
- seen.add(abs);
26
- expanded.push(abs);
27
- try {
28
- const raw = await readFile(abs, "utf-8");
29
- const dna = JSON.parse(raw);
30
- for (const ref of dna.cascade?.inherits ?? []) {
31
- const speciesPath = resolveSpeciesPath(ref);
32
- if (speciesPath && !seen.has(speciesPath)) {
33
- seen.add(speciesPath);
34
- expanded.unshift(speciesPath);
35
- }
36
- }
37
- }
38
- catch {
39
- // Will fail later with proper error
40
- }
41
- }
42
- return expanded;
43
- }
44
8
  export async function runShow(opts) {
45
9
  if (opts.files.length === 0) {
46
10
  process.stderr.write("Error: no files specified\n");
47
11
  return 2;
48
12
  }
49
13
  try {
50
- const expandedFiles = await expandFiles(opts.files);
14
+ const expandedFiles = await expandDNAInputFiles(opts.files);
51
15
  const dnas = await Promise.all(expandedFiles.map(loadDNA));
52
16
  const cascaded = cascadeDNA(dnas);
53
17
  const activated = activateDNA(cascaded, opts.context ?? null);
@@ -10,6 +10,7 @@
10
10
  *
11
11
  * Targets: claude-md, soul-md, cursorrules, system-prompt
12
12
  */
13
+ export type SyncMode = "auto" | "plugin" | "bin";
13
14
  export interface SyncOptions {
14
15
  files: string[];
15
16
  target: string;
@@ -26,7 +27,10 @@ export interface SyncOptions {
26
27
  settingsPath?: string;
27
28
  lockFile?: string;
28
29
  remove: boolean;
30
+ mode?: SyncMode;
29
31
  plugin?: boolean;
32
+ dryRun?: boolean;
33
+ postSummary?: boolean;
30
34
  }
31
35
  /**
32
36
  * Detect whether intentdna is running as a Claude Code plugin or standalone binary.
@@ -47,8 +51,8 @@ export declare function detectMode(): Promise<"plugin" | "bin">;
47
51
  */
48
52
  export declare function cleanStaleDNAFiles(dir: string, type: "agents" | "skills", activeNamespaces: string[]): Promise<string[]>;
49
53
  /**
50
- * Auto-detect DNA configs: multi-config (.dna/configs/*.yaml) or legacy single-config.
51
- * Returns array of absolute paths.
54
+ * Auto-detect DNA config file in current directory (legacy single-config).
55
+ * Priority: .dna/config.yaml > .dna/config.yml > .dna/config.json > .dna.yaml > .dna.yml > .dna.json
52
56
  */
53
57
  export declare function autoDetectConfigs(): Promise<string[]>;
54
58
  /**
@@ -74,12 +78,11 @@ export interface TemplateUpgradeInfo {
74
78
  templateName: string;
75
79
  currentVersion: string;
76
80
  availableVersion: string;
81
+ reason: "version-update" | "missing-hash" | "content-drift";
77
82
  }
78
83
  /**
79
- * Check template versions against current template content hashes.
80
- * Returns upgrade info for changed configs and prints human-readable suggestions.
81
- *
82
- * Uses content hash comparison instead of semver — detects any template content change.
84
+ * Check stamped template metadata against the current template catalog.
85
+ * Version mismatch is the primary upgrade signal; content hash drift is a fallback.
83
86
  */
84
87
  export declare function checkTemplateVersions(configPaths: string[]): Promise<TemplateUpgradeInfo[]>;
85
88
  export declare function runSync(opts: SyncOptions): Promise<number>;