intentdna 1.5.7 → 1.5.9

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.
@@ -9,7 +9,7 @@
9
9
  {
10
10
  "name": "intentdna",
11
11
  "description": "DNA template compilation + runtime enforcement",
12
- "version": "1.5.7",
12
+ "version": "1.5.9",
13
13
  "source": "./"
14
14
  }
15
15
  ]
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "intentdna",
3
- "version": "1.5.7",
3
+ "version": "1.5.9",
4
4
  "description": "Declarative policy layer for AI agent governance"
5
5
  }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * dna templates deploy — copy local src/templates/*.dna.yaml to global intentdna install
3
+ */
4
+ export interface TemplatesDeployOptions {
5
+ /** Override local templates dir (for testing) */
6
+ localDir?: string;
7
+ /** Override global target dir (for testing) */
8
+ globalDir?: string;
9
+ }
10
+ export declare function runTemplatesDeploy(opts?: TemplatesDeployOptions): Promise<number>;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * dna templates deploy — copy local src/templates/*.dna.yaml to global intentdna install
3
+ */
4
+ import { readdirSync, copyFileSync, existsSync, readFileSync, mkdirSync } from "node:fs";
5
+ import { resolve, join } from "node:path";
6
+ import { execSync } from "node:child_process";
7
+ /**
8
+ * Resolve the global intentdna templates directory.
9
+ * Strategy: npm root -g + /intentdna/dist/templates
10
+ */
11
+ function resolveGlobalTemplatesDir() {
12
+ let globalRoot;
13
+ try {
14
+ globalRoot = execSync("npm root -g", { encoding: "utf-8" }).trim();
15
+ }
16
+ catch {
17
+ throw new Error("Failed to resolve npm global root. Is npm installed?");
18
+ }
19
+ const globalPkg = join(globalRoot, "intentdna");
20
+ if (!existsSync(globalPkg)) {
21
+ throw new Error("intentdna not installed globally, run: npm install -g intentdna");
22
+ }
23
+ // Templates live in dist/templates after build, and src/templates in source
24
+ const distTemplates = join(globalPkg, "dist", "templates");
25
+ const srcTemplates = join(globalPkg, "src", "templates");
26
+ if (existsSync(distTemplates))
27
+ return distTemplates;
28
+ if (existsSync(srcTemplates))
29
+ return srcTemplates;
30
+ // Create dist/templates if neither exists (fresh install edge case)
31
+ mkdirSync(distTemplates, { recursive: true });
32
+ return distTemplates;
33
+ }
34
+ /**
35
+ * Verify we're in the intentdna project root.
36
+ */
37
+ function verifyProjectRoot(cwd) {
38
+ const pkgPath = join(cwd, "package.json");
39
+ if (!existsSync(pkgPath)) {
40
+ throw new Error("must run from intentdna project root (no package.json found)");
41
+ }
42
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
43
+ if (pkg.name !== "intentdna") {
44
+ throw new Error("must run from intentdna project root (package.json name is not 'intentdna')");
45
+ }
46
+ return cwd;
47
+ }
48
+ export async function runTemplatesDeploy(opts = {}) {
49
+ try {
50
+ const cwd = process.cwd();
51
+ const projectRoot = verifyProjectRoot(cwd);
52
+ const localDir = opts.localDir ?? resolve(projectRoot, "src", "templates");
53
+ const globalDir = opts.globalDir ?? resolveGlobalTemplatesDir();
54
+ if (!existsSync(localDir)) {
55
+ process.stderr.write(`Error: local templates dir not found: ${localDir}\n`);
56
+ return 1;
57
+ }
58
+ const files = readdirSync(localDir).filter((f) => f.endsWith(".dna.yaml"));
59
+ if (files.length === 0) {
60
+ process.stderr.write("No *.dna.yaml files found in local templates dir\n");
61
+ return 1;
62
+ }
63
+ let copied = 0;
64
+ for (const file of files) {
65
+ const src = join(localDir, file);
66
+ const dst = join(globalDir, file);
67
+ try {
68
+ copyFileSync(src, dst);
69
+ copied++;
70
+ }
71
+ catch (err) {
72
+ const msg = err instanceof Error ? err.message : String(err);
73
+ process.stderr.write(`Error copying ${file}: ${msg}\n`);
74
+ return 1;
75
+ }
76
+ }
77
+ process.stderr.write(`Copied ${copied} templates to ${globalDir}\n`);
78
+ return 0;
79
+ }
80
+ catch (err) {
81
+ const msg = err instanceof Error ? err.message : String(err);
82
+ process.stderr.write(`Error: ${msg}\n`);
83
+ return 1;
84
+ }
85
+ }
package/dist/cli/index.js CHANGED
@@ -30,6 +30,7 @@ Commands:
30
30
  evolve Generate epigenetic markers from outcomes
31
31
  epigenetic Record outcomes, view markers and summaries
32
32
  feedback Analyze trace data, suggest template optimizations (--days <N>, --json, --evolve)
33
+ templates Template management (deploy to global install)
33
34
 
34
35
  Options:
35
36
  --help, -h Show help for a command
@@ -428,6 +429,17 @@ async function main() {
428
429
  process.exit(code);
429
430
  break;
430
431
  }
432
+ case "templates": {
433
+ const subcommand = rest[0] ?? "";
434
+ if (subcommand !== "deploy") {
435
+ process.stderr.write(`Usage: dna templates deploy\n\nCopy local src/templates/*.dna.yaml to global intentdna install.\n`);
436
+ process.exit(subcommand ? 2 : 0);
437
+ }
438
+ const { runTemplatesDeploy } = await import("./commands/templates.js");
439
+ const code = await runTemplatesDeploy();
440
+ process.exit(code);
441
+ break;
442
+ }
431
443
  default:
432
444
  process.stderr.write(`Unknown command: ${command}\n\n`);
433
445
  process.stderr.write(HELP);
@@ -20,6 +20,7 @@ export interface ActivatedGene {
20
20
  codons: Codon[];
21
21
  tags: string[];
22
22
  expression_level: number;
23
+ role?: "constraint" | "workflow_hint";
23
24
  }
24
25
  /**
25
26
  * Activate a cascaded DNA for a given context and role.
@@ -74,6 +74,7 @@ export function activateDNA(cascaded, contextName = null, activeRole = null) {
74
74
  codons: [...gene.codons],
75
75
  tags: [...(gene.tags ?? [])],
76
76
  expression_level: 1.0,
77
+ role: gene.role,
77
78
  };
78
79
  }
79
80
  // Apply context modifiers if a context is active
@@ -55,6 +55,14 @@ function geneToDirectives(name, gene) {
55
55
  if (weights.length > 0) {
56
56
  parts.push(`Trade-offs: ${weights.join("; ")}.`);
57
57
  }
58
+ // For workflow_hint genes, threshold codons become prompt directives instead of gates
59
+ if (gene.role === "workflow_hint") {
60
+ for (const codon of gene.codons) {
61
+ if (codon.type === "threshold") {
62
+ parts.push(`Condition: ${codon.condition}.`);
63
+ }
64
+ }
65
+ }
58
66
  if (parts.length > 1) {
59
67
  directives.push({
60
68
  priority,
@@ -153,9 +161,11 @@ export function compileDNA(activated, cascaded) {
153
161
  const injections = [];
154
162
  for (const [name, gene] of Object.entries(activated.genes)) {
155
163
  directives.push(...geneToDirectives(name, gene));
156
- toolFilters.push(...geneToToolFilters(name, gene));
157
- gates.push(...geneToGates(name, gene));
158
- validators.push(...geneToValidators(name, gene));
164
+ if (gene.role !== "workflow_hint") {
165
+ toolFilters.push(...geneToToolFilters(name, gene));
166
+ gates.push(...geneToGates(name, gene));
167
+ validators.push(...geneToValidators(name, gene));
168
+ }
159
169
  }
160
170
  // Compile role constraints
161
171
  let roleToolPermissions;
@@ -37,6 +37,7 @@ export interface Gene {
37
37
  description: string;
38
38
  codons: Codon[];
39
39
  tags?: string[];
40
+ role?: "constraint" | "workflow_hint";
40
41
  }
41
42
  export type ModifierAction = "amplify" | "suppress" | "activate" | "deactivate";
42
43
  export interface GeneModifier {
@@ -0,0 +1,152 @@
1
+ version: "0.1.0"
2
+ id: template_code_cleanup
3
+ name: Code Cleanup (Regression-Safe)
4
+ type: project
5
+ namespace: cc
6
+
7
+ cascade:
8
+ inherits: ["species:default"]
9
+ priority: 100
10
+
11
+ genes:
12
+ test_between_passes:
13
+ description: Tests must pass between each cleanup pass
14
+ codons:
15
+ - type: threshold
16
+ condition: "tests_passing == true"
17
+ action: block
18
+ - type: attract
19
+ target: run_tests_after_each_pass
20
+
21
+ no_behavior_change:
22
+ description: Cleanup must not change observable behavior
23
+ codons:
24
+ - type: threshold
25
+ condition: "behavior_changed == false"
26
+ action: block
27
+ - type: repel
28
+ target: modify_public_api
29
+ - type: attract
30
+ target: same_inputs_same_outputs
31
+
32
+ smell_focused:
33
+ description: Clean by smell type in order - dead code, duplication, naming
34
+ role: workflow_hint
35
+ codons:
36
+ - type: attract
37
+ target: categorize_before_cleaning
38
+ - type: attract
39
+ target: one_smell_type_per_pass
40
+
41
+ minimal_cleanup:
42
+ description: Each pass focuses on one type of issue
43
+ codons:
44
+ - type: attract
45
+ target: single_concern_per_pass
46
+ - type: repel
47
+ target: mixed_cleanup_types
48
+ - type: threshold
49
+ condition: "files_changed_per_pass <= 10"
50
+ action: escalate
51
+
52
+ contexts: {}
53
+
54
+ roles:
55
+ analyzer:
56
+ description: Analyzes code for cleanup opportunities. Read-only.
57
+ tool_permissions:
58
+ allow: [Read, Grep, Glob, Bash]
59
+ deny: [Edit, Write, NotebookEdit]
60
+ scope:
61
+ read: ["**/*"]
62
+ write: []
63
+ instructions:
64
+ - Classify code smells by type (dead code, duplication, naming, complexity)
65
+ - Prioritize by impact and risk
66
+ - Do NOT suggest behavioral changes
67
+ - Output a categorized cleanup plan
68
+
69
+ cleaner:
70
+ description: Executes cleanup changes. Can modify code.
71
+ tool_permissions:
72
+ allow: [Read, Edit, Write, Grep, Glob, Bash]
73
+ scope:
74
+ read: ["**/*"]
75
+ write: ["src/**", "lib/**"]
76
+ instructions:
77
+ - Follow the analyzer's cleanup plan
78
+ - One smell type per pass
79
+ - Run tests after each file change
80
+ - Revert if tests fail
81
+ - Do not change public APIs or observable behavior
82
+ - Commit after each successful pass
83
+
84
+ reviewer:
85
+ description: Reviews cleanup changes for correctness. Read-only.
86
+ tool_permissions:
87
+ allow: [Read, Grep, Glob, Bash]
88
+ deny: [Edit, Write, NotebookEdit]
89
+ scope:
90
+ read: ["**/*"]
91
+ write: []
92
+ instructions:
93
+ - Review git diff for each cleanup pass
94
+ - Verify no behavioral changes
95
+ - Check test coverage unchanged
96
+ - "Verdict: APPROVE or REQUEST_CHANGES"
97
+
98
+ workflows:
99
+ cleanup:
100
+ name: Code Cleanup
101
+ description: "Regression-safe code cleanup: analyze, classify, clean by smell type, verify"
102
+ steps:
103
+ - id: lock_behavior
104
+ role: analyzer
105
+ description: "Assess current test coverage and establish behavior baseline."
106
+ prompt: |
107
+ Run existing tests to establish baseline.
108
+ Record: total tests, passing, failing.
109
+ If test coverage is insufficient, warn before proceeding.
110
+ Output: baseline test results + coverage assessment.
111
+
112
+ - id: classify
113
+ role: analyzer
114
+ depends_on: [lock_behavior]
115
+ description: "Scan codebase and categorize code smells."
116
+ prompt: |
117
+ Scan the codebase for code smells. Categorize:
118
+ 1. Dead code (unused imports, unreachable branches, commented-out code)
119
+ 2. Duplication (copy-paste patterns, similar functions)
120
+ 3. Naming (unclear names, inconsistent conventions)
121
+ 4. Complexity (long functions, deep nesting)
122
+
123
+ Prioritize: dead code first (safest), then duplication, then naming.
124
+ Output: categorized cleanup plan with file paths and line numbers.
125
+
126
+ - id: clean
127
+ role: cleaner
128
+ depends_on: [classify]
129
+ description: "Execute cleanup one smell type at a time."
130
+ prompt: |
131
+ Follow the cleanup plan. Rules:
132
+ - One smell type per pass (start with dead code)
133
+ - Run tests after each file change
134
+ - If tests fail: revert immediately, report the issue
135
+ - Maximum 10 files per pass
136
+ - Commit after each successful pass: "cleanup($TYPE): description"
137
+ - Do NOT change any public API signatures
138
+ - Do NOT rename exported symbols
139
+ - Do NOT modify test files (unless removing dead test helpers)
140
+
141
+ - id: verify
142
+ role: reviewer
143
+ depends_on: [clean]
144
+ description: "Verify cleanup preserved behavior."
145
+ prompt: |
146
+ Review all cleanup changes (git diff from baseline):
147
+ 1. Any behavioral changes? (API signatures, return values, side effects)
148
+ 2. Test count unchanged or increased?
149
+ 3. All tests still passing?
150
+ 4. No unintended file modifications?
151
+
152
+ Verdict: APPROVE (cleanup complete) or REQUEST_CHANGES (list issues)
@@ -168,7 +168,12 @@ roles:
168
168
  - Never suggest code changes
169
169
  - "If round > 1: review previous round's git diff first, judge if direction is correct"
170
170
  - "If previous fix produced 0 red→green transitions: warn 'no progress'"
171
- - "Categorize by severity: CRITICAL (compile errors) > HIGH (logic failures) > LOW (widget/style)"
171
+ - "Categorize by severity and type:"
172
+ - " CRITICAL: compile errors, import failures — blocks everything"
173
+ - " HIGH-INFRA: mock incomplete causing test hang — blocks behavior verification, fix mock infrastructure first"
174
+ - " HIGH-LOGIC: logic test failures (state/notifier) — behavior inconsistency"
175
+ - " MEDIUM: widget test failures (rendering/navigation)"
176
+ - "hung tests ≠ failed tests. hung = mock infrastructure problem (needs mock fix), failed = behavior inconsistency (needs v2 code fix)"
172
177
 
173
178
  surgeon:
174
179
  description: Fixes breakpoints and builds missing layers by understanding v1 intent and rewriting in v2 style.
@@ -248,8 +253,9 @@ workflows:
248
253
  Scenario 2 (re-run/incremental):
249
254
  - Read the incremental diff from behavior doc
250
255
  - Update existing tests incrementally — do NOT rewrite all tests (preserves rescue progress)
251
- - Run `flutter test {{test_path}}/$ARGUMENTS/` with NO timeout record baseline
252
- - Append baseline to behavior doc
256
+ - Run `flutter test {{test_path}}/$ARGUMENTS/ --timeout 30s`per-test safety net (hung tests marked fail, continues to next)
257
+ - Classify results: passed / failed (behavior mismatch) / hung (timed out = mock infrastructure issue, NOT behavior failure)
258
+ - Append baseline to behavior doc with hung/failed distinction
253
259
  - Git commit: "behavior-lock($ARGUMENTS): N tests (X green, Y red from behavior change)"
254
260
 
255
261
  BANNED patterns:
@@ -273,6 +279,13 @@ workflows:
273
279
  description: "Fix v2 module $ARGUMENTS — investigate, fix, review, verify, report. Max 10 rounds with convergence protection."
274
280
  max_rounds: 10
275
281
  convergence_rule: "2 consecutive rounds with 0 test progress (green count not increasing) → STOP. Output blocked items + analysis."
282
+ round_budget: "Max 5 files per round. Each round must produce at least 1 test transition (red/skip/hung → green), otherwise counted as no progress."
283
+ priority_order: |
284
+ Phase 1: Fix CRITICAL (compile errors) — unblocks everything
285
+ Phase 2: Fix HIGH-INFRA (mock infrastructure, make hung tests runnable) — unblocks behavior verification
286
+ Phase 3: Fix HIGH-LOGIC (logic tests, red → green) — behavior alignment
287
+ Phase 4: Fix MEDIUM (widget tests, red → green) — UI alignment
288
+ Complete each phase before moving to the next.
276
289
  steps:
277
290
  - id: investigate
278
291
  role: investigator
@@ -282,10 +295,13 @@ workflows:
282
295
  - If round > 1: review previous round's git diff first
283
296
  - If previous round had 0 test progress (no red→green or skip→green): warn "no progress" and consider changing approach
284
297
 
285
- Run tests in {{test_path}}/$ARGUMENTS/. Categorize all non-passing tests by severity:
286
- CRITICAL: compile errors, import failures — fix first
287
- HIGH: logic test failures (state/notifier/service) — fix second
288
- LOW: widget test failures (rendering/navigation) — fix after logic is done
298
+ Run tests in {{test_path}}/$ARGUMENTS/ --timeout 30s. Categorize all non-passing tests by severity:
299
+ CRITICAL: compile errors, import failures — blocks everything, fix first
300
+ HIGH-INFRA: mock incomplete causing test hang (timed out) — blocks behavior verification, fix mock infrastructure
301
+ HIGH-LOGIC: logic test failures (state/notifier/service) — behavior inconsistency, fix after infra
302
+ MEDIUM: widget test failures (rendering/navigation) — fix after logic
303
+
304
+ IMPORTANT: hung ≠ failed. A test that times out (hung) = mock infrastructure problem, NOT a v2 behavior issue. Classify separately.
289
305
 
290
306
  Pick highest severity batch. Trace: what does v1 do vs what does v2 do? Find the breakpoints.
291
307
  Report findings and the plan for this round.
@@ -348,7 +364,7 @@ workflows:
348
364
  description: "Independent test verification + regression check."
349
365
  prompt: |
350
366
  Run tests independently (do not trust surgeon's reported results):
351
- 1. `flutter test {{test_path}}/$ARGUMENTS/` (no timeout)
367
+ 1. `flutter test {{test_path}}/$ARGUMENTS/ --timeout 30s` (per-test safety net; hung = mock infra issue)
352
368
  2. `flutter analyze` (compilation check)
353
369
  3. Check for regressions in core module tests if applicable
354
370
 
@@ -0,0 +1,144 @@
1
+ version: "0.1.0"
2
+ id: template_persistent_executor
3
+ name: Persistent Executor (PRD-Driven)
4
+ type: project
5
+ namespace: pe
6
+
7
+ cascade:
8
+ inherits: ["species:default"]
9
+ priority: 100
10
+
11
+ genes:
12
+ prd_driven:
13
+ description: Every task must trace back to explicit acceptance criteria
14
+ codons:
15
+ - type: threshold
16
+ condition: "acceptance_criteria_defined == true"
17
+ action: block
18
+ - type: attract
19
+ target: reference_acceptance_criteria
20
+ - type: repel
21
+ target: work_without_spec
22
+
23
+ verify_before_done:
24
+ description: Never claim completion without passing acceptance criteria
25
+ codons:
26
+ - type: threshold
27
+ condition: "all_criteria_verified == true"
28
+ action: block
29
+ - type: attract
30
+ target: run_verification_before_reporting
31
+ - type: repel
32
+ target: claim_done_without_evidence
33
+
34
+ no_partial_completion:
35
+ description: Either fully complete a story or explicitly report what remains
36
+ codons:
37
+ - type: threshold
38
+ condition: "story_fully_complete == true"
39
+ action: escalate
40
+ - type: repel
41
+ target: silent_partial_delivery
42
+
43
+ small_increments:
44
+ description: One story per commit, verifiable increments
45
+ role: workflow_hint
46
+ codons:
47
+ - type: attract
48
+ target: one_story_one_commit
49
+ - type: repel
50
+ target: batch_multiple_stories
51
+ - type: attract
52
+ target: each_commit_passes_tests
53
+
54
+ contexts: {}
55
+
56
+ roles:
57
+ executor:
58
+ description: Implements stories from the PRD. Can modify code.
59
+ tool_permissions:
60
+ allow: [Read, Edit, Write, Grep, Glob, Bash]
61
+ scope:
62
+ read: ["**/*"]
63
+ write: ["src/**", "lib/**", "test/**"]
64
+ instructions:
65
+ - Pick the highest priority incomplete story
66
+ - Read acceptance criteria before starting
67
+ - Implement in small verifiable steps
68
+ - Run tests after each change
69
+ - Commit after each story completion
70
+ - "Commit message: feat($STORY): what was implemented"
71
+ - Do not move to next story until current one is verified
72
+
73
+ verifier:
74
+ description: Independently verifies story completion. Read-only + can run tests.
75
+ tool_permissions:
76
+ allow: [Read, Grep, Glob, Bash]
77
+ deny: [Edit, Write, NotebookEdit]
78
+ scope:
79
+ read: ["**/*"]
80
+ write: []
81
+ instructions:
82
+ - Read the acceptance criteria for the completed story
83
+ - Run tests independently (do not trust executor's output)
84
+ - Check each criterion individually
85
+ - "Mark each: VERIFIED / PARTIAL / MISSING"
86
+ - "Verdict: PASS (all verified) or FAIL (list what's missing)"
87
+ - On FAIL the executor must fix before proceeding
88
+
89
+ workflows:
90
+ persistent-execution:
91
+ name: Persistent Execution
92
+ description: "PRD-driven story execution: pick, implement, verify, repeat until all done"
93
+ steps:
94
+ - id: pick_story
95
+ role: executor
96
+ description: "Select next story from PRD by priority."
97
+ prompt: |
98
+ Read the PRD or task list.
99
+ Select the highest priority incomplete story.
100
+ Confirm: acceptance criteria are clear and testable.
101
+ If criteria are vague, ask for clarification before starting.
102
+ Output: story ID, title, acceptance criteria.
103
+
104
+ - id: implement
105
+ role: executor
106
+ depends_on: [pick_story]
107
+ description: "Implement the selected story."
108
+ prompt: |
109
+ Implement the story. Rules:
110
+ - Read acceptance criteria carefully
111
+ - Small steps: change → test → verify
112
+ - Maximum scope: what the story requires, nothing more
113
+ - Run tests after each meaningful change
114
+ - If stuck for 3 attempts on the same issue: STOP and report blocker
115
+ - Commit when story implementation is complete
116
+ - Do not start the next story
117
+
118
+ - id: verify
119
+ role: verifier
120
+ depends_on: [implement]
121
+ description: "Independent verification of story completion."
122
+ prompt: |
123
+ Verify the completed story independently:
124
+ 1. Read acceptance criteria
125
+ 2. Run all relevant tests (do not trust executor's results)
126
+ 3. Check each criterion: VERIFIED / PARTIAL / MISSING
127
+ 4. Run full test suite for regression check
128
+
129
+ PASS: All criteria verified → story complete, ready for next
130
+ FAIL: List what's missing → executor must fix
131
+
132
+ - id: report
133
+ role: verifier
134
+ depends_on: [verify]
135
+ description: "Report progress and determine next action."
136
+ prompt: |
137
+ Summary:
138
+ - Story: [ID] [title]
139
+ - Criteria: N/M verified
140
+ - Tests: X passing, Y failing
141
+ - Verdict: COMPLETE or NEEDS_FIX
142
+
143
+ If COMPLETE: "Story done. Pick next story to continue."
144
+ If NEEDS_FIX: "Story incomplete. Issues: [list]. Fix before proceeding."