intentdna 1.5.7 → 1.5.8

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.8",
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.8",
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);
@@ -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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intentdna",
3
- "version": "1.5.7",
3
+ "version": "1.5.8",
4
4
  "description": "Intent DNA — Declarative policy layer for AI agent behavior",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,5 +1,15 @@
1
1
  # Spec: flutter-rewrite 模板优化
2
2
 
3
+ ## 最终目标
4
+
5
+ **把 v1 (GetX) 重写为 v2 (Riverpod),行为完全一致。**
6
+
7
+ - behavior-lock: 写测试 = 定义"v1 的行为是什么"
8
+ - rescue: 写代码让测试通过 = "v2 的行为和 v1 一样"
9
+ - 完成标志: 所有测试 green = 重写成功,行为完全一致
10
+
11
+ 所有设计决策必须服务于这个目标。timeout 是安全网(防卡死),不是解法。挂死的测试意味着行为没被验证——rescue 必须修复它们,不能跳过。
12
+
3
13
  ## 问题
4
14
 
5
15
  flutter-rewrite 模板的 behavior-lock 和 rescue 工作流都有设计缺陷,导致:
@@ -47,14 +57,19 @@ commit: "behavior-lock($MODULE): N tests (X green, Y red from behavior change)"
47
57
  3. 增量更新
48
58
  4. 输出 diff 摘要
49
59
 
50
- ### 禁止的模式
60
+ ### 超时策略
51
61
 
52
- | 禁止 | 原因 | 替代 |
53
- |------|------|------|
54
- | `sleep N && check` 轮询 | 浪费时间 | 前台跑 |
55
- | `timeout Nm flutter test` | 测试可能需要很久 | 不设超时 |
56
- | 全量重写已有测试 | 丢失 rescue 成果 | 增量更新 |
57
- | 首次跑 `flutter test` | 没实现,编译不过 | `flutter analyze` |
62
+ | 操作 | 允许? | 原因 |
63
+ |------|--------|------|
64
+ | `flutter test --timeout 30s` | **允许** | per-test 安全网,挂死标 fail 继续下一个 |
65
+ | `timeout Nm flutter test` | 禁止 | 外部杀进程,丢失所有结果 |
66
+ | `sleep N && check` 轮询 | 禁止 | 浪费时间 |
67
+ | 全量重写已有测试 | 禁止 | 丢失 rescue 成果 |
68
+ | 首次跑 `flutter test` | 禁止 | 没实现,编译不过,用 `flutter analyze` |
69
+
70
+ **挂死的测试分类**:标记为 `hung: needs mock infrastructure`,不是 `failed`。区别:
71
+ - `failed` = 行为不一致,rescue 修 v2 代码
72
+ - `hung` = mock 不完整,rescue 先修测试基础设施
58
73
 
59
74
  ---
60
75
 
@@ -131,7 +146,13 @@ investigator:
131
146
  # 现有的保留,新增:
132
147
  - 非首轮:先 review 上轮 git diff,判断方向是否正确
133
148
  - 如果上轮 fix 没有让任何测试从 red→green,警告"无进展"
134
- - 分类时标注严重度:CRITICAL(编译不过)> HIGH(逻辑错误)> LOW(widget 样式)
149
+ - 分类时标注严重度和类型:
150
+ CRITICAL: 编译错误(阻塞一切)
151
+ HIGH-INFRA: mock 不完整导致 test hang(阻塞行为验证,rescue 优先修)
152
+ HIGH-LOGIC: 逻辑测试 fail(行为不一致)
153
+ MEDIUM: widget 测试 fail(渲染/导航差异)
154
+ LOW: 样式差异
155
+ - hung 测试 ≠ failed 测试。hung = mock 基础设施问题,不是 v2 行为问题
135
156
  ```
136
157
 
137
158
  ### 收敛保护
@@ -144,9 +165,19 @@ rescue:
144
165
  输出卡点分析 + 剩余问题清单
145
166
  round_budget: |
146
167
  每轮最多改 5 个文件
147
- 每轮必须让至少 1 个测试从 red/skip → green,否则视为无进展
168
+ 每轮必须让至少 1 个测试从 red/skip/hung → green,否则视为无进展
169
+ priority_order: |
170
+ Phase 1: 修 CRITICAL(编译错误)
171
+ Phase 2: 修 HIGH-INFRA(mock 基础设施,让 hung 测试能跑)
172
+ Phase 3: 修 HIGH-LOGIC(逻辑测试,让 red 变 green)
173
+ Phase 4: 修 MEDIUM(widget 测试,让 red 变 green)
174
+ 每个 phase 完成后才进入下一个
148
175
  ```
149
176
 
177
+ **为什么 HIGH-INFRA 优先于 HIGH-LOGIC?**
178
+
179
+ hung 的测试 = 行为没被验证 = 重写目标的盲区。如果跳过 mock 修复直接改逻辑,可能 20 个 widget 行为从来没被检验过。先让所有测试能跑(pass 或 fail),再让它们变绿。
180
+
150
181
  ### 完整 rescue workflow
151
182
 
152
183
  ```yaml