devflow-kit 3.6.0 → 3.8.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.
Files changed (197) hide show
  1. package/CHANGELOG.md +438 -1
  2. package/README.md +15 -11
  3. package/dist/agents/code.md +9 -15
  4. package/dist/agents/design.md +1 -1
  5. package/dist/agents/fix.md +11 -13
  6. package/dist/agents/git.md +1 -1
  7. package/dist/agents/harden.md +1 -1
  8. package/dist/agents/refactor.md +7 -10
  9. package/dist/agents/review.md +6 -4
  10. package/dist/agents/skim.md +2 -2
  11. package/dist/agents/triage.md +2 -2
  12. package/dist/cli/commands/capture.js +1 -1
  13. package/dist/cli/commands/curation-move-io.js +102 -0
  14. package/dist/cli/commands/curation-move-step.js +374 -0
  15. package/dist/cli/commands/{learning.js → curation.js} +302 -99
  16. package/dist/cli/commands/gate-level-prompts.js +426 -0
  17. package/dist/cli/commands/gates.js +299 -0
  18. package/dist/cli/commands/init-seed.js +16 -5
  19. package/dist/cli/commands/init.js +263 -54
  20. package/dist/cli/commands/memory.js +20 -2
  21. package/dist/cli/commands/prompt-io.js +37 -0
  22. package/dist/cli/commands/uninstall.js +81 -9
  23. package/dist/cli.js +4 -2
  24. package/dist/commands/bug-analysis.md +25 -36
  25. package/dist/commands/code-review.md +77 -73
  26. package/dist/commands/debug.md +5 -5
  27. package/dist/commands/dynamic-build.md +76 -83
  28. package/dist/commands/dynamic-plan.md +5 -5
  29. package/dist/commands/dynamic-profile.md +5 -5
  30. package/dist/commands/dynamic-tickets.md +5 -5
  31. package/dist/commands/explore.md +6 -6
  32. package/dist/commands/implement.md +68 -102
  33. package/dist/commands/plan.md +19 -29
  34. package/dist/commands/release.md +5 -5
  35. package/dist/commands/research.md +6 -6
  36. package/dist/commands/resolve.md +29 -31
  37. package/dist/commands/self-review.md +5 -13
  38. package/dist/core/assets.js +20 -20
  39. package/dist/core/curate-tuning-config.js +5 -6
  40. package/dist/core/curation-move-notice.js +84 -0
  41. package/dist/core/curation-move-skip.js +36 -0
  42. package/dist/core/curation-move.js +35 -0
  43. package/dist/core/curation-queue-cleanup.js +134 -0
  44. package/dist/core/curation-store.js +98 -0
  45. package/dist/core/{learning-variants.js → curation-variants.js} +65 -41
  46. package/dist/core/echo-value.js +48 -0
  47. package/dist/core/evidence-policy.js +18 -6
  48. package/dist/core/feature-switch.js +95 -19
  49. package/dist/core/fs-atomic.js +1 -1
  50. package/dist/core/gate-level.js +221 -0
  51. package/dist/core/git.js +16 -14
  52. package/dist/core/ledger-root.js +82 -22
  53. package/dist/core/linked-path.js +4 -4
  54. package/dist/core/manifest-lock.js +238 -0
  55. package/dist/core/manifest.js +84 -24
  56. package/dist/core/migrations.js +1 -13
  57. package/dist/core/model-discovery.js +7 -1
  58. package/dist/core/observations.js +2 -2
  59. package/dist/core/plugins.js +15 -15
  60. package/dist/core/pool.js +26 -0
  61. package/dist/core/project-paths.js +103 -34
  62. package/dist/core/queue-drain.js +2 -2
  63. package/dist/core/tracked-areas.js +35 -0
  64. package/dist/core/tracker.js +6 -34
  65. package/dist/{learning-off → curation-off}/agents/code.md +9 -15
  66. package/dist/{learning-off → curation-off}/agents/fix.md +11 -13
  67. package/dist/{learning-off → curation-off}/agents/refactor.md +7 -10
  68. package/dist/{learning-off → curation-off}/agents/review.md +5 -3
  69. package/dist/{learning-off → curation-off}/agents/triage.md +1 -1
  70. package/dist/{learning-off → curation-off}/commands/bug-analysis.md +20 -31
  71. package/dist/{learning-off → curation-off}/commands/code-review.md +74 -70
  72. package/dist/{learning-off → curation-off}/commands/debug.md +2 -2
  73. package/dist/{learning-off → curation-off}/commands/dynamic-build.md +73 -80
  74. package/dist/{learning-off → curation-off}/commands/explore.md +2 -2
  75. package/dist/{learning-off → curation-off}/commands/implement.md +65 -99
  76. package/dist/{learning-off → curation-off}/commands/plan.md +15 -25
  77. package/dist/{learning-off → curation-off}/commands/resolve.md +26 -28
  78. package/dist/{learning-off → curation-off}/commands/self-review.md +2 -10
  79. package/dist/hud/components/{learning-counts.js → curation-counts.js} +36 -17
  80. package/dist/hud/config.js +1 -1
  81. package/dist/hud/index.js +6 -6
  82. package/dist/hud/render.js +3 -3
  83. package/dist/skills/git/references/pr/validate-branch.md +8 -5
  84. package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +20 -14
  85. package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +20 -20
  86. package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +20 -20
  87. package/dist/targets/claude-code/{learning-install.js → curation-install.js} +99 -67
  88. package/dist/targets/claude-code/installer.js +15 -15
  89. package/dist/targets/claude-code/language-stamp.js +5 -5
  90. package/dist/targets/claude-code/post-install.js +2 -2
  91. package/dist/targets/claude-code/tracker-servers.js +1 -1
  92. package/package.json +3 -2
  93. package/src/assets/agents/_partials/_code.mds +16 -17
  94. package/src/assets/agents/code.mds +4 -7
  95. package/src/assets/agents/curate.md +12 -14
  96. package/src/assets/agents/debug.mds +6 -6
  97. package/src/assets/agents/design.mds +18 -18
  98. package/src/assets/agents/fix.mds +6 -5
  99. package/src/assets/agents/git.mds +1 -1
  100. package/src/assets/agents/harden.mds +7 -7
  101. package/src/assets/agents/knowledge.mds +23 -23
  102. package/src/assets/agents/refactor.mds +2 -2
  103. package/src/assets/agents/research.mds +15 -15
  104. package/src/assets/agents/review.mds +45 -43
  105. package/src/assets/agents/skim.mds +11 -11
  106. package/src/assets/agents/synthesize.md +2 -2
  107. package/src/assets/agents/triage.mds +22 -22
  108. package/src/assets/agents/validate.md +13 -26
  109. package/src/assets/commands/_partials/_decisions.mds +13 -13
  110. package/src/assets/commands/_partials/_engine.mds +8 -8
  111. package/src/assets/commands/_partials/_knowledge.mds +29 -15
  112. package/src/assets/commands/_partials/_preamble.mds +4 -4
  113. package/src/assets/commands/_partials/_settings.mds +3 -3
  114. package/src/assets/commands/_partials/_wave.mds +17 -24
  115. package/src/assets/commands/bug-analysis.mds +37 -48
  116. package/src/assets/commands/code-review.mds +90 -86
  117. package/src/assets/commands/debug.mds +14 -14
  118. package/src/assets/commands/dynamic-build.mds +78 -78
  119. package/src/assets/commands/dynamic-plan.mds +22 -22
  120. package/src/assets/commands/dynamic-profile.mds +2 -2
  121. package/src/assets/commands/dynamic-tickets.mds +8 -8
  122. package/src/assets/commands/explore.mds +20 -20
  123. package/src/assets/commands/implement.mds +92 -118
  124. package/src/assets/commands/plan.mds +41 -51
  125. package/src/assets/commands/release.mds +12 -12
  126. package/src/assets/commands/research.mds +19 -19
  127. package/src/assets/commands/resolve.mds +56 -50
  128. package/src/assets/commands/self-review.mds +20 -20
  129. package/src/assets/mds/git/_ops.mds +3 -1
  130. package/src/assets/mds/git/_ops_pr.mds +1 -1
  131. package/src/assets/mds/git/_ops_steps.mds +13 -7
  132. package/src/assets/mds/git/_pr.mds +7 -4
  133. package/src/assets/mds/tracker/_common.mds +23 -12
  134. package/src/assets/mds/tracker/_github.mds +2 -9
  135. package/src/assets/mds/tracker/_jira.mds +2 -15
  136. package/src/assets/mds/tracker/_linear.mds +2 -15
  137. package/src/assets/rules/quality.md +1 -0
  138. package/src/assets/scripts/ci-wait.cjs +22 -4
  139. package/src/assets/scripts/claude-md-audit.cjs +66 -51
  140. package/src/assets/scripts/hooks/background-memory-update +406 -97
  141. package/src/assets/scripts/hooks/capture-prompt +12 -12
  142. package/src/assets/scripts/hooks/capture-question +11 -11
  143. package/src/assets/scripts/hooks/capture-turn +12 -12
  144. package/src/assets/scripts/hooks/{learning-lock → curation-lock} +2 -2
  145. package/src/assets/scripts/hooks/curation-move +293 -0
  146. package/src/assets/scripts/hooks/ensure-devflow-init +45 -13
  147. package/src/assets/scripts/hooks/ensure-proxy +4 -4
  148. package/src/assets/scripts/hooks/ensure-root-gitignore +4 -4
  149. package/src/assets/scripts/hooks/git-marker +81 -0
  150. package/src/assets/scripts/hooks/json-helper.cjs +145 -51
  151. package/src/assets/scripts/hooks/json-parse +19 -4
  152. package/src/assets/scripts/hooks/lib/curation-move.cjs +1582 -0
  153. package/src/assets/scripts/hooks/lib/{learning-store.cjs → curation-store.cjs} +242 -118
  154. package/src/assets/scripts/hooks/lib/decisions-format.cjs +3 -3
  155. package/src/assets/scripts/hooks/lib/mkdir-lock.cjs +24 -7
  156. package/src/assets/scripts/hooks/lib/project-paths.cjs +132 -39
  157. package/src/assets/scripts/hooks/lib/render-decisions.cjs +34 -22
  158. package/src/assets/scripts/hooks/lib/tracked-areas.cjs +259 -0
  159. package/src/assets/scripts/hooks/memory-permission +358 -0
  160. package/src/assets/scripts/hooks/memory-worker +1 -1
  161. package/src/assets/scripts/hooks/pre-compact-memory +6 -16
  162. package/src/assets/scripts/hooks/queue-append +228 -103
  163. package/src/assets/scripts/hooks/resolve-project-root +2 -2
  164. package/src/assets/scripts/hooks/session-start-context +145 -71
  165. package/src/assets/scripts/hooks/session-start-memory +27 -46
  166. package/src/assets/scripts/lib/project-config.cjs +31 -9
  167. package/src/assets/scripts/resolve-base.cjs +1043 -0
  168. package/src/assets/scripts/resolve-settings.cjs +238 -46
  169. package/src/assets/skills/agent-references/SKILL.md +9 -2
  170. package/src/assets/skills/agent-references/references/commands/code-review-levels.md +19 -0
  171. package/src/assets/skills/agent-references/references/commands/implement-levels.md +27 -0
  172. package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +6 -4
  173. package/src/assets/skills/agent-references/references/commands/plan-levels.md +40 -0
  174. package/src/assets/skills/agent-references/references/commands/resolve-levels.md +24 -0
  175. package/src/assets/skills/agent-references/references/synthesize/planning.md +9 -22
  176. package/src/assets/skills/agent-references/references/synthesize/review.md +11 -11
  177. package/src/assets/skills/apply-decisions/SKILL.md +1 -1
  178. package/src/assets/skills/docs-framework/SKILL.md +7 -7
  179. package/src/assets/skills/docs-framework/references/patterns.md +3 -4
  180. package/src/assets/skills/quality-gates/SKILL.md +1 -1
  181. package/src/assets/skills/worktree-support/references/roots.md +2 -2
  182. package/templates/lint-pack/.lint-pack.conf +86 -0
  183. package/templates/lint-pack/README.md +190 -0
  184. package/templates/lint-pack/lint-pack.sh +905 -0
  185. package/dist/core/learning-queue-cleanup.js +0 -27
  186. package/dist/core/learning-store.js +0 -61
  187. /package/dist/{learning-off → curation-off}/agents/debug.md +0 -0
  188. /package/dist/{learning-off → curation-off}/agents/design.md +0 -0
  189. /package/dist/{learning-off → curation-off}/agents/harden.md +0 -0
  190. /package/dist/{learning-off → curation-off}/agents/knowledge.md +0 -0
  191. /package/dist/{learning-off → curation-off}/agents/research.md +0 -0
  192. /package/dist/{learning-off → curation-off}/agents/skim.md +0 -0
  193. /package/dist/{learning-off → curation-off}/commands/dynamic-plan.md +0 -0
  194. /package/dist/{learning-off → curation-off}/commands/dynamic-profile.md +0 -0
  195. /package/dist/{learning-off → curation-off}/commands/dynamic-tickets.md +0 -0
  196. /package/dist/{learning-off → curation-off}/commands/release.md +0 -0
  197. /package/dist/{learning-off → curation-off}/commands/research.md +0 -0
@@ -47,13 +47,13 @@ and using its one-line output. If the command fails (outside a git repository),
47
47
  node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
48
48
  ```
49
49
 
50
- Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> LEARNING=<on|off> KNOWLEDGE=<on|off>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on LEARNING=on KNOWLEDGE=off` instead.
50
+ Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on CURATION=on KNOWLEDGE=off GATE_LEVEL=full` instead.
51
51
 
52
- The accepted line is the only source of these values: the script alone folds the committed `.devflow/project.json`, the personal `.devflow/config.json` and the machine manifest.
52
+ The accepted line is the only source of these values.
53
53
 
54
54
  ### Load DECISIONS_CONTEXT
55
55
 
56
- When the settings line says `LEARNING=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
56
+ When the settings line says `CURATION=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
57
57
 
58
58
  The decisions ledger belongs to the repository, not to one checkout: a linked worktree reads the main worktree's copy, a subdirectory session the repository root's. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
59
59
 
@@ -67,11 +67,11 @@ Line 1 is the checkout's toplevel, line 2 the common git directory. A git older
67
67
  2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
68
68
  3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
69
69
 
70
- This is the rule the learning hooks apply, so you read the index the Curate agent writes.
70
+ This is the rule the curation hooks apply, so you read the index the Curate agent writes.
71
71
 
72
72
  **Step 1 — Read the pre-rendered index:**
73
73
 
74
- Attempt to read `{ledger}/.devflow/learning/index.md`.
74
+ Attempt to read `{ledger}/.devflow/curation/index.md`.
75
75
 
76
76
  - If the file exists and contains non-empty content: use that content as `DECISIONS_CONTEXT`.
77
77
  - If the file is absent or empty: set `DECISIONS_CONTEXT` to `(none)`.
@@ -166,7 +166,7 @@ Analyze the research question to infer research types needed (min 2, max 5). For
166
166
 
167
167
  Only if `codebase` type is in RESEARCH_PLAN.
168
168
 
169
- Spawn `Agent(subagent_type="Skim")` with `LEARNING` from the settings line, targeting codebase areas relevant to the research question.
169
+ Spawn `Agent(subagent_type="Skim")` with `CURATION` from the settings line, targeting codebase areas relevant to the research question.
170
170
 
171
171
  Skip and set ORIENT_OUTPUT = "(none)" if `codebase` type is not in RESEARCH_PLAN.
172
172
 
@@ -86,7 +86,7 @@ Set `TARGET_DIR` to the selected review or bug-analysis directory path, and `TAR
86
86
 
87
87
  #### Step 0d: Load Project Decisions
88
88
 
89
- **Produces:** DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, FEATURE_KNOWLEDGE_RULES, EVIDENCE_POLICY, ISSUE_REQUIRED, APPLY_CONVENTIONS, REQUIRE_NON_AUTHOR_APPROVAL, REVIEW_PUBLICATION, RESOLUTION_TS
89
+ **Produces:** DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, FEATURE_KNOWLEDGE_RULES, EVIDENCE_POLICY, ISSUE_REQUIRED, APPLY_CONVENTIONS, REQUIRE_NON_AUTHOR_APPROVAL, REVIEW_PUBLICATION, RESOLUTION_TS, GATE_LEVEL
90
90
 
91
91
  **Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root when the run has one worktree:
92
92
 
@@ -94,13 +94,13 @@ Set `TARGET_DIR` to the selected review or bug-analysis directory path, and `TAR
94
94
  node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
95
95
  ```
96
96
 
97
- Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> LEARNING=<on|off> KNOWLEDGE=<on|off>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on LEARNING=on KNOWLEDGE=off` instead.
97
+ Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on CURATION=on KNOWLEDGE=off GATE_LEVEL=full` instead.
98
98
 
99
- The accepted line is the only source of these values: the script alone folds the committed `.devflow/project.json`, the personal `.devflow/config.json` and the machine manifest.
99
+ The accepted line is the only source of these values.
100
100
 
101
101
  ### Load DECISIONS_CONTEXT
102
102
 
103
- When the settings line says `LEARNING=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
103
+ When the settings line says `CURATION=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
104
104
 
105
105
  The decisions ledger belongs to the repository, not to one checkout: a linked worktree reads the main worktree's copy, a subdirectory session the repository root's. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
106
106
 
@@ -114,11 +114,11 @@ Line 1 is the checkout's toplevel, line 2 the common git directory. A git older
114
114
  2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
115
115
  3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
116
116
 
117
- This is the rule the learning hooks apply, so you read the index the Curate agent writes.
117
+ This is the rule the curation hooks apply, so you read the index the Curate agent writes.
118
118
 
119
119
  **Step 1 — Read the pre-rendered index:**
120
120
 
121
- Attempt to read `{ledger}/.devflow/learning/index.md`.
121
+ Attempt to read `{ledger}/.devflow/curation/index.md`.
122
122
 
123
123
  - If the file exists and contains non-empty content: use that content as `DECISIONS_CONTEXT`.
124
124
  - If the file is absent or empty: set `DECISIONS_CONTEXT` to `(none)`.
@@ -216,6 +216,12 @@ Resolve this per worktree — unlike the evidence policy above, the settings lin
216
216
 
217
217
  Set it per worktree, from that worktree's lens, and pass that worktree's `COMPLIANCE_DIRECTIVE` to each of its Code and Fix spawns, on a line of its own.
218
218
 
219
+ **Gate level.** Each worktree keeps its own `GATE_LEVEL`. When any is `standard` or `lean`, once per run, run `d="${CLAUDE_CONFIG_DIR:-}"; case "$d" in /*) ;; *) d="$HOME/.claude" ;; esac; printf '%s\n' "$d"` in Bash and Read `<that directory>/skills/devflow:agent-references/references/commands/resolve-levels.md` with the Read tool, and apply each row to the phase it names, as the reference says.
220
+
221
+ - No row or rule overrides the next two lines.
222
+ - If the Read fails, or the file has no `## Phases` heading with the `| Phase | standard | lean |` header, or a row breaks its grammar, apply no row in any worktree, keep every `GATE_LEVEL` and say `level reference unreadable: no level rows applied`.
223
+ - No level changes the Triage security gate or the ESCALATED route. The Verification Gate, the CI gate and the compliance directive run at every level.
224
+
219
225
  **Mint `RESOLUTION_TS` once per run:** `date -u +%Y-%m-%dT%H:%M:%SZ`. Every worktree reuses it — the resolution comment's dedup marker is searched per PR, so one run key keeps a retry of this run deduplicated while the next /resolve on the same PR posts. Phase 5 writes it as the summary's `**Date**:` and Phase 9b-2 passes it, so the local file and the posted marker agree.
220
226
 
221
227
  ### Phase 1: Parse Issues
@@ -309,10 +315,10 @@ Collect every decision and pitfall the Triage agent's Reasoning columns state, i
309
315
  **Produces:** BATCHES
310
316
  **Requires:** TRIAGE_RESULTS
311
317
 
312
- If FIX_NOW list is empty: skip to Phase 5 — write full summary (Phase 5), run manage-debt (Phase 9) if FIX_SEPARATE/TECH_DEBT exist, run thread resolution + resolution comment (Phase 9b), run merge readiness (Phase 9c), display results (Phase 10).
318
+ If FIX_NOW list is empty: skip to Phase 5, then run Phases 9, 9b, 9c and 10.
313
319
 
314
320
  Otherwise, batch FIX_NOW issues for Code agent execution. **DUPLICATE issues are never dispatched** — they inherit the primary's outcome:
315
- - **Same-file issues** → one batch (one Code agent per file, sequential for same-file pairs)
321
+ - **Same-file issues** → one batch (one Code agent per file)
316
322
  - **Distinct-file issues** → parallel Code agents
317
323
  - **Max 5 issues per batch** — chunk large sets
318
324
 
@@ -348,9 +354,9 @@ Collect from each Code agent:
348
354
  ### Phase 5: Write resolution-summary.md
349
355
 
350
356
  **Produces:** RESOLUTION_FILE (early write for compaction safety)
351
- **Requires:** TRIAGE_RESULTS, CODE_AGENT_RESULTS, TARGET_DIR, TARGET_DIR_REL, BRANCH_INFO, RESOLUTION_TS
357
+ **Requires:** TRIAGE_RESULTS, CODE_AGENT_RESULTS, TARGET_DIR, TARGET_DIR_REL, BRANCH_INFO, RESOLUTION_TS, GATE_LEVEL
352
358
 
353
- **Immediately write `resolution-summary.md`** to `{TARGET_DIR}` using the Write tool. Do this now — not in Phase 9 — while results are fresh in context. This ensures the record is persisted even if later phases (Polish, Verification Gate, CI gate, Tech Debt) trigger context compaction.
359
+ **Immediately write `resolution-summary.md`** to `{TARGET_DIR}` using the Write tool. Do this now — not in Phase 9 — while results are fresh in context.
354
360
 
355
361
  Set `Tracked` for FIX_SEPARATE and TECH_DEBT items to `(pending)` — to be backfilled after Phase 9 manage-debt (or `TRACEABILITY: DEGRADED ({reason})` if manage-debt degrades).
356
362
 
@@ -361,7 +367,7 @@ Use the template from the Output Artifact section below.
361
367
  ### Phase 6: Polish
362
368
 
363
369
  **Produces:** POLISH_RESULT
364
- **Requires:** CODE_AGENT_RESULTS
370
+ **Requires:** CODE_AGENT_RESULTS, GATE_LEVEL
365
371
 
366
372
  If any fixes were made, spawn Polish agent to refine the changed code:
367
373
 
@@ -423,7 +429,7 @@ git -C {worktree} push
423
429
 
424
430
  **If `fork_no_push` is set:** do not push. Record `Push: skipped — cannot push to fork` under `## Verification`, and skip Phase 8 — no pushed commit exists for CI to check.
425
431
 
426
- **Route after push:** VERIFICATION_STATUS = PASS → continue to Phase 8 (CI gate). VERIFICATION_STATUS = FAILED → skip Phase 8; proceed directly to Phase 9 (manage-debt), then Phase 9b (thread resolution + resolution comment), then Phase 9c (merge readiness), then Phase 10 (report). VERIFICATION_STATUS = SKIPPED → skip Phase 8 (no fixes applied); proceed to Phase 9 (manage-debt), then Phase 9b (thread resolution + resolution comment), then Phase 9c (merge readiness, when non-author approval is required), then Phase 10 (report).
432
+ **Route after push:** VERIFICATION_STATUS = PASS → continue to Phase 8 (CI gate). FAILED or SKIPPED → skip Phase 8 and continue with Phase 9 and the later phases in order.
427
433
 
428
434
  ### Phase 8: CI Status Gate (Conditional)
429
435
 
@@ -593,7 +599,7 @@ If the script prints a `TRACEABILITY: DEGRADED` line: warn, proceed to Phase 10.
593
599
 
594
600
  ### Phase 10: Report
595
601
 
596
- **Requires:** BRANCH_INFO, TARGET_DIR, PR_COMMENT, THREAD_RESOLUTION_RESULT
602
+ **Requires:** BRANCH_INFO, TARGET_DIR, PR_COMMENT, THREAD_RESOLUTION_RESULT, GATE_LEVEL
597
603
 
598
604
  The resolution summary was already written to `{TARGET_DIR}/resolution-summary.md` in Phase 5 (updated by Phase 7, Phase 9 and Phase 9b-1). Display results to the user:
599
605
 
@@ -603,6 +609,7 @@ The resolution summary was already written to `{TARGET_DIR}/resolution-summary.m
603
609
  **Branch**: {branch}
604
610
  **Reviews Processed**: {n} reports from {TARGET_DIR}
605
611
  **Total Issues**: {n}
612
+ **Gate level**: {GATE_LEVEL, with any level note}
606
613
 
607
614
  ### Results
608
615
  | Outcome | Count |
@@ -648,14 +655,6 @@ In multi-worktree mode, report results per worktree with aggregate summary.
648
655
 
649
656
  ### Feature Knowledge Write-Back (Conditional)
650
657
 
651
- Resolve `{worktree}` as the checkout's toplevel, because feature knowledge bases are committed with the branch (D-PROMPT-ROOT): from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`) — run
652
-
653
- ```bash
654
- git -C "{start}" rev-parse --show-toplevel
655
- ```
656
-
657
- and use its one-line output. If the command fails (outside a git repository), `{worktree}` is the start directory itself. All paths below are relative to `{worktree}`.
658
-
659
658
  **Step 1 — Check the opt-out gate, with `{root}` = `{worktree}`:** take the settings line resolved above for that root, resolving it with the settings block when this run has not yet.
660
659
 
661
660
  If the settings line says `KNOWLEDGE=off`, skip write-back entirely. The machine switch (`devflow knowledge --disable`), the repository and the personal settings can each turn knowledge off, and none can turn it back on (D-FEATURES-NARROW-ONLY). The fail-closed line says `KNOWLEDGE=off` too, so an unresolvable line skips write-back.
@@ -703,15 +702,15 @@ When the Knowledge agent reports `KB_COMMIT: skipped (detached HEAD)`, the files
703
702
  /resolve (orchestrator - spawns agents only)
704
703
  │
705
704
  ├─ Phase 0: Worktree Discovery & Pre-flight
706
- ├─ Phase 1: Parse issues from TARGET_DIR + extract confidence %
705
+ ├─ Phase 1: Parse issues from TARGET_DIR
707
706
  ├─ Phase 1b: Fetch external threads (evidence policy required)
708
707
  ├─ Phase 2: Global Triage [Triage agent, opus, single agent]
709
- ├─ Phase 3: Batch FIX_NOW issues (skip if empty; DUPLICATE issues never dispatched)
710
- ├─ Phase 4: Fix [Code agent × N, OPERATION: issue-fix, PUSH: false]
708
+ ├─ Phase 3: Batch FIX_NOW issues
709
+ ├─ Phase 4: Fix [Code agent × N]
711
710
  ├─ Phase 5: Write resolution-summary.md (compaction safety; Tracked = "(pending)" or "(pending — TRACEABILITY: DEGRADED)" if manage-debt degrades)
712
- ├─ Phase 6: Polish [Polish agent]
711
+ ├─ Phase 6: Polish
713
712
  ├─ Phase 7: Verification Gate [Validate agent, haiku] + push + Fix agent validation-fix loop ≤2
714
- ├─ Phase 8: CI Status Gate (conditional — skipped if no fixes or verification FAILED)
713
+ ├─ Phase 8: CI Status Gate (conditional)
715
714
  ├─ Phase 9: Git agent (manage-debt) — FIX_SEPARATE + TECH_DEBT → backfill Tracked={ISSUE_REF} (or TRACEABILITY: DEGRADED on failure)
716
715
  │
717
716
  ├─ Phase 9b: Thread resolution + resolution comment
@@ -730,10 +729,9 @@ When the Knowledge agent reports `KB_COMMIT: skipped (detached HEAD)`, the files
730
729
  | Case | Handling |
731
730
  |------|----------|
732
731
  | No reviews exist | Check bug-analysis fallback (Step 0c-5b); if also absent, error and suggest `/code-review` or `/bug-analysis` |
733
- | All false positives | Normal completion, report shows 0 fixes |
734
732
  | Fix attempt fails | Revert changes, mark BLOCKED, continue others |
735
733
  | Issue dependencies | Sequential chain, skip dependents if predecessor blocked |
736
- | No actionable issues | Report "No issues to resolve" |
734
+ | No issues parsed | Report "No issues to resolve" |
737
735
  | Latest review already resolved | Check bug-analysis fallback (Step 0c-5b); if also absent, skip worktree and suggest `/code-review` or `/bug-analysis` |
738
736
  | `--review {timestamp}` in multi-worktree mode | Not supported — use `--path` + `--review` to target specific worktree + review |
739
737
  | gh/GitHub absent | manage-debt degrades (`TRACEABILITY: DEGRADED ({reason})`); Tracked stays `(pending — TRACEABILITY: DEGRADED ({reason}))` — recorded, not dropped |
@@ -748,9 +746,8 @@ When the Knowledge agent reports `KB_COMMIT: skipped (detached HEAD)`, the files
748
746
  ## Principles
749
747
 
750
748
  1. **Orchestration only** - Command spawns agents, doesn't do git/resolve work itself
751
- 2. **No agent grades its own homework** - Triage agent validates, Code agents fix, Validate agent verifies
752
- 3. **Git agent for git work** - All git operations go through Git agent; the CI wait, the evidence refresh and the merge-readiness check are inline scripts (plumbing, no model work)
753
- 4. **Traceability-aware** - Policy-gated ops (thread fetch/resolve, merge readiness) are skipped cleanly when the evidence policy does not ask for them; resolution comment (Phase 9b-2) is always-on; test-plan evidence is re-verified (≤1 Test agent) and refreshed only when this run moved the head (Steps 9b-0, 9b-3)
749
+ 2. **Git agent for git work** - All git operations go through Git agent; the CI wait, the evidence refresh and the merge-readiness check are inline scripts (plumbing, no model work)
750
+ 3. **Traceability-aware** - Policy-gated ops (thread fetch/resolve, merge readiness) are skipped cleanly when the evidence policy does not ask for them; resolution comment (Phase 9b-2) is always-on; test-plan evidence is re-verified (≤1 Test agent) and refreshed only when this run moved the head (Steps 9b-0, 9b-3)
754
751
 
755
752
  ## Output Artifact
756
753
 
@@ -763,6 +760,7 @@ Written in Phase 5 (Collect Results) to `{TARGET_DIR}/resolution-summary.md`:
763
760
  **Date**: {RESOLUTION_TS}
764
761
  **Review**: {TARGET_DIR_REL}
765
762
  **Command**: /resolve
763
+ **Gate level**: {GATE_LEVEL}
766
764
 
767
765
  ## Decisions Citations
768
766
 
@@ -30,13 +30,13 @@ Detect changed files and build context:
30
30
  node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
31
31
  ```
32
32
 
33
- Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> LEARNING=<on|off> KNOWLEDGE=<on|off>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on LEARNING=on KNOWLEDGE=off` instead.
33
+ Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on CURATION=on KNOWLEDGE=off GATE_LEVEL=full` instead.
34
34
 
35
- The accepted line is the only source of these values: the script alone folds the committed `.devflow/project.json`, the personal `.devflow/config.json` and the machine manifest.
35
+ The accepted line is the only source of these values.
36
36
 
37
37
  ### Load DECISIONS_CONTEXT
38
38
 
39
- When the settings line says `LEARNING=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
39
+ When the settings line says `CURATION=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
40
40
 
41
41
  The decisions ledger belongs to the repository, not to one checkout: a linked worktree reads the main worktree's copy, a subdirectory session the repository root's. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
42
42
 
@@ -50,11 +50,11 @@ Line 1 is the checkout's toplevel, line 2 the common git directory. A git older
50
50
  2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
51
51
  3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
52
52
 
53
- This is the rule the learning hooks apply, so you read the index the Curate agent writes.
53
+ This is the rule the curation hooks apply, so you read the index the Curate agent writes.
54
54
 
55
55
  **Step 1 — Read the pre-rendered index:**
56
56
 
57
- Attempt to read `{ledger}/.devflow/learning/index.md`.
57
+ Attempt to read `{ledger}/.devflow/curation/index.md`.
58
58
 
59
59
  - If the file exists and contains non-empty content: use that content as `DECISIONS_CONTEXT`.
60
60
  - If the file is absent or empty: set `DECISIONS_CONTEXT` to `(none)`.
@@ -214,14 +214,6 @@ Display summary:
214
214
 
215
215
  ### Feature Knowledge Write-Back (Conditional)
216
216
 
217
- Resolve `{worktree}` as the checkout's toplevel, because feature knowledge bases are committed with the branch (D-PROMPT-ROOT): from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`) — run
218
-
219
- ```bash
220
- git -C "{start}" rev-parse --show-toplevel
221
- ```
222
-
223
- and use its one-line output. If the command fails (outside a git repository), `{worktree}` is the start directory itself. All paths below are relative to `{worktree}`.
224
-
225
217
  **Step 1 — Check the opt-out gate, with `{root}` = `{worktree}`:** take the settings line resolved above for that root, resolving it with the settings block when this run has not yet.
226
218
 
227
219
  If the settings line says `KNOWLEDGE=off`, skip write-back entirely. The machine switch (`devflow knowledge --disable`), the repository and the personal settings can each turn knowledge off, and none can turn it back on (D-FEATURES-NARROW-ONLY). The fail-closed line says `KNOWLEDGE=off` too, so an unresolvable line skips write-back.
@@ -1,13 +1,13 @@
1
1
  import { join } from 'path';
2
2
  import { getPackageRoot } from './paths.js';
3
3
  import { SKILL_REFS_OUTPUT_DIR } from './mds-variants.js';
4
- import { LEARNING_OFF_OUTPUT_DIR } from './learning-variants.js';
4
+ import { CURATION_OFF_OUTPUT_DIR } from './curation-variants.js';
5
5
  /**
6
6
  * Flat skills source directory: src/assets/skills/{name}/
7
7
  * All plugins' skills live here directly (no per-plugin subdirectory).
8
8
  *
9
9
  * @param root - Package root to resolve against. Injectable so a caller working
10
- * on a temp tree (the learning converge) reads the skill source from the same
10
+ * on a temp tree (the curation converge) reads the skill source from the same
11
11
  * root as the rest of its sources.
12
12
  */
13
13
  export function skillsDir(root = getPackageRoot()) {
@@ -41,42 +41,42 @@ export function scriptsDir() {
41
41
  /**
42
42
  * Compiled commands directory: dist/commands/
43
43
  * Single lookup directory for installed commands: one compiled file per `.mds`
44
- * command host in src/assets/commands/. A host that carries a learning arm also
45
- * has a learning-off variant (see learningOffDir).
44
+ * command host in src/assets/commands/. A host that carries a curation arm also
45
+ * has a curation-off variant (see curationOffDir).
46
46
  */
47
47
  export function commandsDir() {
48
48
  return join(getPackageRoot(), 'dist', 'commands');
49
49
  }
50
50
  /**
51
- * Learning-off variant directory: dist/learning-off/{commands,agents}/
51
+ * Curation-off variant directory: dist/curation-off/{commands,agents}/
52
52
  *
53
- * Holds the learning-off variant of each prompt that carries a learning arm
53
+ * Holds the curation-off variant of each prompt that carries a curation arm
54
54
  * (D-LEARNING-VARIANTS), and only those. Absent until the build has run, so every
55
55
  * reader tolerates its absence.
56
56
  *
57
- * The spelling comes from LEARNING_OFF_OUTPUT_DIR in learning-variants.ts, the
57
+ * The spelling comes from CURATION_OFF_OUTPUT_DIR in curation-variants.ts, the
58
58
  * build's own destination, rather than being retyped here.
59
59
  *
60
60
  * @param kind - Which prompt kind's variants.
61
61
  * @param root - Package root to resolve against (see agentsDir).
62
62
  */
63
- export function learningOffDir(kind, root = getPackageRoot()) {
64
- return join(root, ...LEARNING_OFF_OUTPUT_DIR.split('/'), kind);
63
+ export function curationOffDir(kind, root = getPackageRoot()) {
64
+ return join(root, ...CURATION_OFF_OUTPUT_DIR.split('/'), kind);
65
65
  }
66
66
  /**
67
67
  * Command source directories, MOST-PREFERRED FIRST.
68
68
  *
69
- * D-LEARNING-VARIANT-INSTALL: with learning off the learning-off variant comes
69
+ * D-LEARNING-VARIANT-INSTALL: with curation off the curation-off variant comes
70
70
  * first, so a host with an arm installs its off variant and a host with none falls
71
- * through to the one compiled file; with learning on the order is the normal
71
+ * through to the one compiled file; with curation on the order is the normal
72
72
  * single-directory lookup.
73
73
  *
74
- * @param learning - The machine's settled learning switch.
74
+ * @param curation - The machine's settled curation switch.
75
75
  * @param root - Package root to resolve against (see agentsDir).
76
76
  */
77
- export function commandSourceDirs(learning, root = getPackageRoot()) {
77
+ export function commandSourceDirs(curation, root = getPackageRoot()) {
78
78
  const normal = join(root, 'dist', 'commands');
79
- return learning ? [normal] : [learningOffDir('commands', root), normal];
79
+ return curation ? [normal] : [curationOffDir('commands', root), normal];
80
80
  }
81
81
  /**
82
82
  * Compiled agents directory: dist/agents/{name}.md
@@ -124,17 +124,17 @@ export function compiledSkillRefsDir(root = getPackageRoot()) {
124
124
  * The non-empty tuple makes an empty list a compile error at every call site:
125
125
  * an empty list would survive a `??` default and resolve to nothing.
126
126
  *
127
- * D-LEARNING-VARIANT-INSTALL: `learning: false` puts dist/learning-off/agents first,
128
- * for the installer and the converge only. The default (learning on) is the order
127
+ * D-LEARNING-VARIANT-INSTALL: `curation: false` puts dist/curation-off/agents first,
128
+ * for the installer and the converge only. The default (curation on) is the order
129
129
  * every other reader wants: the shipped defaults (model, effort) are the same in
130
130
  * both variants, so loadShippedAgentDefaults and the test harness keep reading the
131
- * learning-on tree.
131
+ * curation-on tree.
132
132
  *
133
133
  * @param root - Package root to resolve against (see agentsDir).
134
- * @param learning - The machine's settled learning switch; on by default.
134
+ * @param curation - The machine's settled curation switch; on by default.
135
135
  */
136
- export function agentSourceDirs(root = getPackageRoot(), learning = true) {
136
+ export function agentSourceDirs(root = getPackageRoot(), curation = true) {
137
137
  const normal = [compiledAgentsDir(root), agentsDir(root)];
138
- return learning ? normal : [learningOffDir('agents', root), ...normal];
138
+ return curation ? normal : [curationOffDir('agents', root), ...normal];
139
139
  }
140
140
  //# sourceMappingURL=assets.js.map
@@ -1,7 +1,6 @@
1
1
  import * as fs from 'fs';
2
- import * as path from 'path';
3
2
  import { getDevFlowDirectory } from '../targets/claude-code/claude-paths.js';
4
- import { getCurateTuningConfigPath } from './project-paths.js';
3
+ import { getCurateTuningConfigPath, getGlobalCurateTuningConfigPath } from './project-paths.js';
5
4
  const VALID_MODELS = new Set(['opus', 'sonnet', 'haiku']);
6
5
  function isValidModel(value) {
7
6
  return typeof value === 'string' && VALID_MODELS.has(value);
@@ -64,15 +63,15 @@ function readConfigFile(filePath) {
64
63
  *
65
64
  * Priority (highest wins): project config → global config → defaults.
66
65
  *
67
- * - Global: `~/.devflow/learning.json`
68
- * - Project: `<ledgerRoot>/.devflow/learning/learning.json` — pass the ledger root
69
- * (getLedgerRoot), where session-start-context reads it and `devflow learning
66
+ * - Global: `~/.devflow/curation.json`
67
+ * - Project: `<ledgerRoot>/.devflow/curation/curation.json` — pass the ledger root
68
+ * (getLedgerRoot), where session-start-context reads it and `devflow curation
70
69
  * --configure` writes it (D-LEDGER-MAIN-WORKTREE).
71
70
  *
72
71
  * Invalid JSON in either file is silently ignored and treated as absent.
73
72
  */
74
73
  export function loadCurateTuningConfig(ledgerRoot) {
75
- const globalConfigPath = path.join(getDevFlowDirectory(), 'learning.json');
74
+ const globalConfigPath = getGlobalCurateTuningConfigPath(getDevFlowDirectory());
76
75
  const projectConfigPath = getCurateTuningConfigPath(ledgerRoot);
77
76
  let config = { ...DEFAULTS };
78
77
  const globalJson = readConfigFile(globalConfigPath);
@@ -0,0 +1,84 @@
1
+ /**
2
+ * @file curation-move-notice.ts
3
+ *
4
+ * The notice for a project whose ledger still sits in the old folder: which line to
5
+ * show, the words of each, the fixed notice of a skipped move, and where the shell
6
+ * shim's markers for the project stand. The statusline (src/hud/components/curation-counts.ts)
7
+ * and `devflow curation` (src/cli/commands/curation.ts) both import it from here, so they
8
+ * say the same words and read the same markers, and neither imports the other.
9
+ *
10
+ * Reads the disk with one lstat per path, never follows a link and never opens the old
11
+ * ledger. The HUD runs it on every prompt, so it forks nothing and holds no state.
12
+ */
13
+ import * as fs from 'node:fs';
14
+ import * as path from 'node:path';
15
+ import { LEGACY_NAMES, curationMoveMarkerKey } from './project-paths.js';
16
+ import { MOVE_SKIP_NOTICE, isMoveSkipReason } from './curation-move-skip.js';
17
+ /** The file suffix of each marker kind, as the shim writes it. */
18
+ const MARKER_SUFFIX = {
19
+ refused: 'skip',
20
+ tracked: 'tracked',
21
+ unknown: 'unknown',
22
+ };
23
+ /**
24
+ * The marker the `curation-move` shim writes for the ledger root `root`:
25
+ * `<home>/.devflow/logs/curation-move.<key>.<suffix>`, the key being the root's
26
+ * {@link curationMoveMarkerKey}. Without `kind` it is the refusal marker (`refused`, the
27
+ * suffix `skip`). The shim builds the same paths in `_df_cm_markers`
28
+ * (src/assets/scripts/hooks/curation-move); tests/shell-hooks.test.ts runs that function
29
+ * and requires the two to agree for short, long and non-ASCII roots. Every marker stands
30
+ * outside the project, so a skipped move writes nothing into it.
31
+ */
32
+ export function getCurationMoveMarkerPath(home, root, kind = 'refused') {
33
+ return path.join(home, '.devflow', 'logs', `curation-move.${curationMoveMarkerKey(root)}.${MARKER_SUFFIX[kind]}`);
34
+ }
35
+ /** Whether anything, a link included, sits at `target`. One lstat, never followed. */
36
+ function exists(target) {
37
+ try {
38
+ fs.lstatSync(target);
39
+ return true;
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ /** The markers {@link gatherMoveNotice} looks for, in the order it prefers them, and the notice each one means. */
46
+ const MARKER_NOTICES = [
47
+ ['tracked', 'tracked'],
48
+ ['unknown', 'unknown'],
49
+ ['refused', 'refused'],
50
+ ];
51
+ /**
52
+ * The one extra question of a project with no counts to show: does it still have the old
53
+ * ledger folder? One existence test. If it does, one more for each of the shim's markers
54
+ * under the key of this same root ({@link getCurationMoveMarkerPath}) says which notice
55
+ * applies. Null when the old folder is gone. The old ledger itself is never opened or counted.
56
+ */
57
+ export function gatherMoveNotice(ledgerRoot, home) {
58
+ if (!exists(path.join(ledgerRoot, '.devflow', LEGACY_NAMES.folder)))
59
+ return null;
60
+ const found = MARKER_NOTICES.find(([kind]) => exists(getCurationMoveMarkerPath(home, ledgerRoot, kind)));
61
+ return found === undefined ? 'pointer' : found[1];
62
+ }
63
+ const MOVE_NOTICE_TEXT = {
64
+ pointer: 'run devflow init, or open Claude Code in this project after it',
65
+ refused: 'move refused, see the hook log',
66
+ tracked: 'move skipped, git tracks files in the .devflow data folders',
67
+ unknown: 'move skipped, git did not answer',
68
+ };
69
+ /**
70
+ * The one line the HUD prints for a notice. With `counts` (the entry counts, such as
71
+ * `2 decisions, 1 pitfall`) the notice follows them on the same line.
72
+ */
73
+ export function formatMoveNotice(notice, counts) {
74
+ return counts === undefined ? `Curation: ${MOVE_NOTICE_TEXT[notice]}` : `Curation: ${counts}; ${MOVE_NOTICE_TEXT[notice]}`;
75
+ }
76
+ /**
77
+ * The text `devflow curation --status`, `--list` and `--show` print for a notice: the HUD's
78
+ * line, except that a skipped move gets its whole fixed notice (MOVE_SKIP_NOTICE),
79
+ * because these commands have room to say what to do.
80
+ */
81
+ export function describeMoveNotice(notice) {
82
+ return isMoveSkipReason(notice) ? `Curation: ${MOVE_SKIP_NOTICE[notice]}` : formatMoveNotice(notice);
83
+ }
84
+ //# sourceMappingURL=curation-move-notice.js.map
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @file curation-move-skip.ts
3
+ *
4
+ * The fixed notice of a skipped move. The move leaves a project alone, and changes
5
+ * nothing, when git tracks files in a curation data folder (`tracked`) or when a
6
+ * `.git` entry stands and git did not answer (`unknown`). Pure: no fs, no os, no
7
+ * process state, so the init step (src/cli/commands/curation-move-step.ts) and the
8
+ * notice module (src/core/curation-move-notice.ts) can both import it.
9
+ *
10
+ * The words hold nothing from the repository. The session start hook
11
+ * (src/assets/scripts/hooks/session-start-context) holds the same words;
12
+ * tests/shell-hooks.test.ts requires the two to agree. The two commands the notice
13
+ * tells the user to run are listed in NOTICE_COMMAND_PHRASES in
14
+ * tests/guards/no-fsmonitor-index-read.test.ts, which holds both copies to them.
15
+ */
16
+ import { CURATION_DIR_NAME, LEGACY_NAMES } from './project-paths.js';
17
+ const MOVE_DESCRIPTION = `devflow did not move the curation data of this project from .devflow/${LEGACY_NAMES.folder}/ to .devflow/${CURATION_DIR_NAME}/, `;
18
+ /** The notice of each skip reason, as one paragraph of short sentences. */
19
+ export const MOVE_SKIP_NOTICE = {
20
+ tracked: `${MOVE_DESCRIPTION}because git tracks files in a curation data folder. `
21
+ + 'To find them, run `git ls-files .devflow`. '
22
+ + 'Untrack them with `git rm --cached <file>`, and delete them if you did not make them. '
23
+ + 'Run these commands in the checkout that holds these folders.',
24
+ unknown: `${MOVE_DESCRIPTION}because git did not answer. `
25
+ + 'The move runs again at the next session start or the next init. '
26
+ + 'If this notice stays, check that git runs in this project.',
27
+ };
28
+ /**
29
+ * Whether `value` is a {@link MoveSkipReason}: a reason that has a notice. The members
30
+ * come from the keys of {@link MOVE_SKIP_NOTICE}, which the compiler requires to list
31
+ * every reason, so this module needs no runtime import of the move seam.
32
+ */
33
+ export function isMoveSkipReason(value) {
34
+ return typeof value === 'string' && Object.hasOwn(MOVE_SKIP_NOTICE, value);
35
+ }
36
+ //# sourceMappingURL=curation-move-skip.js.map
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The CLI's view of the curation move — a typed seam onto the package's own
3
+ * `hooks/lib/curation-move.cjs`, never a second implementation of it.
4
+ *
5
+ * The one-time move of the old ledger folder to its new name lives in its own module,
6
+ * beside the store it builds on. `devflow init` and `devflow curation` reach it only
7
+ * through this seam: the module is loaded with the evidence-policy seam's `loadScript`
8
+ * from the package's own scripts directory and shape-checked against
9
+ * CURATION_MOVE_SURFACE; the interfaces below are TRANSCRIBED from the module's JSDoc
10
+ * and are this side's only shape authority (as for the store, see curation-store.ts).
11
+ */
12
+ import { join } from 'path';
13
+ import { scriptsDir } from './assets.js';
14
+ import { loadScript } from './evidence-policy.js';
15
+ /** The move module, relative to src/assets/scripts/ (and ~/.devflow/scripts/). */
16
+ export const CURATION_MOVE_SCRIPT_NAME = join('hooks', 'lib', 'curation-move.cjs');
17
+ /**
18
+ * Every key of CurationMoveModule and the runtime kind the loader requires of it.
19
+ * `satisfies` makes the compiler reject an interface key missing here.
20
+ */
21
+ export const CURATION_MOVE_SURFACE = Object.freeze({
22
+ moveLedger: 'function',
23
+ sweepLedgerBackups: 'function',
24
+ backupPendingRows: 'function',
25
+ backupQueueFiles: 'function',
26
+ });
27
+ /**
28
+ * Load the curation move module from `dir` (default: the package's own scripts
29
+ * directory) and shape-check its surface. Never throws: a missing file is
30
+ * `not-found`; a module that throws on load or lacks a surface key is `unusable`.
31
+ */
32
+ export function loadCurationMove(dir = scriptsDir()) {
33
+ return loadScript(join(dir, CURATION_MOVE_SCRIPT_NAME), CURATION_MOVE_SURFACE);
34
+ }
35
+ //# sourceMappingURL=curation-move.js.map