devflow-kit 3.3.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/README.md +8 -4
- package/dist/agents/code-edit.md +133 -0
- package/dist/agents/code-fix.md +165 -0
- package/dist/agents/code.md +187 -0
- package/{src/assets → dist}/agents/design.md +1 -2
- package/{src/assets → dist}/agents/diagnose.md +1 -2
- package/dist/agents/git.md +33 -722
- package/{src/assets → dist}/agents/knowledge.md +12 -5
- package/{src/assets → dist}/agents/research.md +8 -2
- package/{src/assets → dist}/agents/review.md +8 -11
- package/{src/assets → dist}/agents/scrutinize.md +4 -1
- package/dist/agents/skim.md +152 -0
- package/{src/assets → dist}/agents/triage.md +9 -2
- package/dist/cli/commands/behavior-prompts.js +77 -0
- package/dist/cli/commands/behavior.js +123 -0
- package/dist/cli/commands/flags.js +8 -2
- package/dist/cli/commands/init-seed.js +7 -3
- package/dist/cli/commands/init.js +134 -5
- package/dist/cli/commands/learning.js +38 -3
- package/dist/cli/commands/rules.js +16 -0
- package/dist/cli/commands/tracker.js +112 -15
- package/dist/cli/commands/uninstall.js +42 -1
- package/dist/cli.js +2 -0
- package/dist/commands/bug-analysis.md +35 -13
- package/dist/commands/code-review.md +155 -69
- package/dist/commands/debug.md +39 -16
- package/dist/commands/dynamic-build.md +61 -72
- package/dist/commands/dynamic-plan.md +39 -25
- package/dist/commands/dynamic-profile.md +28 -14
- package/dist/commands/dynamic-tickets.md +38 -22
- package/dist/commands/explore.md +18 -16
- package/dist/commands/implement.md +121 -150
- package/dist/commands/plan.md +51 -31
- package/dist/commands/release.md +72 -6
- package/dist/commands/research.md +49 -20
- package/dist/commands/resolve.md +54 -46
- package/dist/commands/self-review.md +38 -25
- package/dist/core/agent-frontmatter.js +101 -0
- package/dist/core/agent-models.js +43 -0
- package/dist/core/assets.js +55 -10
- package/dist/core/claude-md-audit.js +190 -0
- package/dist/core/compliance-compose.js +6 -4
- package/dist/core/feature-switch.js +41 -1
- package/dist/core/flags.js +139 -0
- package/dist/core/fs-atomic.js +8 -3
- package/dist/core/learning-variants.js +213 -0
- package/dist/core/manifest.js +73 -3
- package/dist/core/mds-variants.js +98 -19
- package/dist/core/plugins.js +111 -72
- package/dist/core/project-paths.js +0 -4
- package/dist/core/proxy-log.js +1 -1
- package/dist/core/proxy-state.js +1 -1
- package/dist/core/tracker.js +120 -2
- package/dist/learning-off/agents/code-edit.md +129 -0
- package/dist/learning-off/agents/code-fix.md +161 -0
- package/dist/learning-off/agents/code.md +183 -0
- package/dist/learning-off/agents/design.md +118 -0
- package/dist/learning-off/agents/diagnose.md +210 -0
- package/dist/learning-off/agents/knowledge.md +96 -0
- package/dist/learning-off/agents/research.md +155 -0
- package/dist/learning-off/agents/review.md +224 -0
- package/dist/learning-off/agents/scrutinize.md +120 -0
- package/{src/assets → dist/learning-off}/agents/skim.md +5 -8
- package/dist/learning-off/agents/triage.md +170 -0
- package/dist/learning-off/commands/bug-analysis.md +420 -0
- package/dist/learning-off/commands/code-review.md +530 -0
- package/dist/learning-off/commands/debug.md +314 -0
- package/dist/learning-off/commands/dynamic-build.md +1245 -0
- package/dist/learning-off/commands/dynamic-plan.md +426 -0
- package/dist/learning-off/commands/dynamic-profile.md +214 -0
- package/dist/learning-off/commands/dynamic-tickets.md +634 -0
- package/dist/learning-off/commands/explore.md +210 -0
- package/dist/learning-off/commands/implement.md +774 -0
- package/dist/learning-off/commands/plan.md +671 -0
- package/dist/learning-off/commands/release.md +311 -0
- package/dist/learning-off/commands/research.md +229 -0
- package/dist/learning-off/commands/resolve.md +842 -0
- package/dist/learning-off/commands/self-review.md +266 -0
- package/dist/skills/git/references/learn-conventions.md +27 -3
- package/dist/skills/git/references/pr/check-ci-status.md +19 -0
- package/dist/skills/git/references/pr/check-merge-readiness.md +19 -0
- package/dist/skills/git/references/pr/fetch-review-threads.md +30 -0
- package/dist/skills/git/references/pr/post-resolution-summary.md +18 -0
- package/dist/skills/git/references/pr/post-review-summary.md +20 -0
- package/dist/skills/git/references/pr/resolve-review-threads.md +28 -4
- package/dist/skills/git/references/pr/update-pr-evidence.md +13 -0
- package/dist/skills/git/references/pr/validate-branch.md +26 -0
- package/dist/skills/git/references/tracker/_contract.md +33 -0
- package/dist/skills/git/references/tracker/github/associate-release.md +24 -0
- package/dist/skills/git/references/tracker/github/backlink-shipped-issues.md +31 -1
- package/dist/skills/git/references/tracker/github/create-release.md +30 -1
- package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +89 -2
- package/dist/skills/git/references/tracker/github/ensure-traceable-issue.md +16 -1
- package/dist/skills/git/references/tracker/github/fetch-issue.md +38 -1
- package/dist/skills/git/references/tracker/github/fetch-issues-batch.md +49 -1
- package/dist/skills/git/references/tracker/github/gather-release-evidence.md +29 -0
- package/dist/skills/git/references/tracker/github/manage-debt.md +21 -1
- package/dist/skills/git/references/tracker/github/post-wave-report.md +17 -1
- package/dist/skills/git/references/tracker/github/setup-task.md +53 -1
- package/dist/skills/git/references/tracker/jira/associate-release.md +25 -1
- package/dist/skills/git/references/tracker/jira/backlink-shipped-issues.md +31 -1
- package/dist/skills/git/references/tracker/jira/create-release.md +30 -1
- package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +89 -2
- package/dist/skills/git/references/tracker/jira/ensure-traceable-issue.md +16 -1
- package/dist/skills/git/references/tracker/jira/fetch-issue.md +38 -1
- package/dist/skills/git/references/tracker/jira/fetch-issues-batch.md +49 -1
- package/dist/skills/git/references/tracker/jira/gather-release-evidence.md +29 -0
- package/dist/skills/git/references/tracker/jira/manage-debt.md +21 -1
- package/dist/skills/git/references/tracker/jira/post-wave-report.md +17 -1
- package/dist/skills/git/references/tracker/jira/setup-task.md +55 -3
- package/dist/skills/git/references/tracker/linear/associate-release.md +25 -1
- package/dist/skills/git/references/tracker/linear/backlink-shipped-issues.md +31 -1
- package/dist/skills/git/references/tracker/linear/create-release.md +30 -1
- package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +89 -2
- package/dist/skills/git/references/tracker/linear/ensure-traceable-issue.md +16 -1
- package/dist/skills/git/references/tracker/linear/fetch-issue.md +38 -1
- package/dist/skills/git/references/tracker/linear/fetch-issues-batch.md +49 -1
- package/dist/skills/git/references/tracker/linear/gather-release-evidence.md +29 -0
- package/dist/skills/git/references/tracker/linear/manage-debt.md +21 -1
- package/dist/skills/git/references/tracker/linear/post-wave-report.md +17 -1
- package/dist/skills/git/references/tracker/linear/setup-task.md +55 -3
- package/dist/targets/claude-code/agent-type-owner.js +164 -0
- package/dist/targets/claude-code/behavior-install.js +111 -0
- package/dist/targets/claude-code/installer.js +140 -37
- package/dist/targets/claude-code/language-stamp.js +185 -0
- package/dist/targets/claude-code/learning-install.js +497 -0
- package/dist/targets/claude-code/tracker-install.js +33 -16
- package/dist/targets/claude-code/tracker-servers.js +107 -0
- package/package.json +4 -3
- package/src/assets/agents/_partials/_code.mds +109 -0
- package/src/assets/agents/code-edit.mds +81 -0
- package/src/assets/agents/code-fix.mds +113 -0
- package/src/assets/agents/code.mds +135 -0
- package/src/assets/agents/design.mds +148 -0
- package/src/assets/agents/diagnose.mds +225 -0
- package/src/assets/agents/evaluate.md +8 -4
- package/src/assets/agents/explore.md +58 -0
- package/src/assets/agents/git.mds +33 -722
- package/src/assets/agents/knowledge.mds +131 -0
- package/src/assets/agents/learning.md +19 -69
- package/src/assets/agents/research.mds +182 -0
- package/src/assets/agents/review.mds +282 -0
- package/src/assets/agents/scrutinize.mds +135 -0
- package/src/assets/agents/simplify.md +3 -0
- package/src/assets/agents/skim.mds +165 -0
- package/src/assets/agents/synthesize.md +26 -352
- package/src/assets/agents/test.md +8 -0
- package/src/assets/agents/tracker.md +20 -7
- package/src/assets/agents/triage.mds +201 -0
- package/src/assets/agents/validate.md +13 -6
- package/src/assets/commands/_partials/_compliance.mds +41 -4
- package/src/assets/commands/_partials/_decisions.mds +33 -2
- package/src/assets/commands/_partials/_engine.mds +14 -6
- package/src/assets/commands/_partials/_knowledge.mds +25 -12
- package/src/assets/commands/_partials/_preamble.mds +34 -10
- package/src/assets/commands/_partials/_publication.mds +5 -4
- package/src/assets/commands/_partials/_roster.mds +4 -3
- package/src/assets/commands/_partials/_settings.mds +13 -5
- package/src/assets/commands/_partials/_wave.mds +9 -1
- package/src/assets/commands/bug-analysis.mds +27 -5
- package/src/assets/commands/code-review.mds +158 -52
- package/src/assets/commands/debug.mds +41 -3
- package/src/assets/commands/dynamic-build.mds +47 -27
- package/src/assets/commands/dynamic-plan.mds +40 -9
- package/src/assets/commands/dynamic-profile.mds +9 -1
- package/src/assets/commands/dynamic-tickets.mds +21 -6
- package/src/assets/commands/explore.mds +28 -2
- package/src/assets/commands/implement.mds +126 -129
- package/src/assets/commands/plan.mds +58 -14
- package/src/assets/commands/{release.md → release.mds} +30 -26
- package/src/assets/commands/research.mds +42 -11
- package/src/assets/commands/resolve.mds +59 -15
- package/src/assets/commands/self-review.mds +30 -5
- package/src/assets/mds/.mdsroot +4 -0
- package/src/assets/mds/git/_ops.mds +383 -0
- package/src/assets/mds/git/_ops_pr.mds +201 -0
- package/src/assets/mds/git/_ops_steps.mds +147 -0
- package/src/assets/mds/git/_pr.mds +39 -44
- package/src/assets/mds/git/_references.mds +6 -3
- package/src/assets/mds/tracker/_common.mds +5 -5
- package/src/assets/mds/tracker/_contract.mds +73 -0
- package/src/assets/mds/tracker/_github.mds +73 -16
- package/src/assets/mds/tracker/_jira.mds +77 -19
- package/src/assets/mds/tracker/_linear.mds +77 -19
- package/src/assets/mds/tracker/_mcp.mds +2 -2
- package/src/assets/mds/tracker/_steps.mds +98 -0
- package/src/assets/rules/behavior.md +6 -0
- package/src/assets/rules/context-economy.md +10 -0
- package/src/assets/rules/go.md +1 -0
- package/src/assets/rules/java.md +1 -0
- package/src/assets/rules/python.md +1 -0
- package/src/assets/rules/rust.md +1 -0
- package/src/assets/rules/typescript.md +1 -0
- package/src/assets/scripts/claude-md-audit.cjs +611 -0
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +3 -3
- package/src/assets/scripts/hooks/json-helper.cjs +13 -5
- package/src/assets/scripts/hooks/json-parse +34 -10
- package/src/assets/scripts/hooks/lib/project-paths.cjs +0 -6
- package/src/assets/scripts/hooks/session-start-context +315 -7
- package/src/assets/skills/agent-references/SKILL.md +33 -0
- package/src/assets/skills/agent-references/references/learning/maintain.md +71 -0
- package/src/assets/skills/agent-references/references/synthesize/bug-analysis.md +71 -0
- package/src/assets/skills/agent-references/references/synthesize/design.md +36 -0
- package/src/assets/skills/agent-references/references/synthesize/exploration.md +38 -0
- package/src/assets/skills/agent-references/references/synthesize/planning.md +60 -0
- package/src/assets/skills/agent-references/references/synthesize/research.md +61 -0
- package/src/assets/skills/agent-references/references/synthesize/review.md +76 -0
- package/src/assets/skills/apply-decisions/SKILL.md +1 -1
- package/src/assets/skills/apply-feature-knowledge/SKILL.md +5 -5
- package/src/assets/skills/compliance/SKILL.md +1 -1
- package/src/assets/skills/docs-framework/SKILL.md +80 -83
- package/src/assets/skills/docs-framework/references/patterns.md +14 -25
- package/src/assets/skills/docs-framework/references/violations.md +7 -7
- package/src/assets/skills/feature-knowledge/SKILL.md +43 -12
- package/src/assets/skills/gap-analysis/SKILL.md +0 -16
- package/src/assets/skills/gap-analysis/references/compliance.md +19 -0
- package/src/assets/skills/quality-gates/SKILL.md +1 -1
- package/dist/skills/git/references/pr/ensure-pr-ready.md +0 -24
- package/src/assets/agents/code.md +0 -330
package/dist/commands/resolve.md
CHANGED
|
@@ -22,9 +22,10 @@ Process issues from code review reports: triage every issue through the blast-ra
|
|
|
22
22
|
|
|
23
23
|
**Produces:** WORKTREES
|
|
24
24
|
|
|
25
|
-
1. **Discover resolvable worktrees
|
|
26
|
-
- Run `git worktree list --porcelain`
|
|
27
|
-
- Invoke the `devflow:worktree-support` skill, then Read its `references/discovery.md` from the skill's base directory for the full 7-step algorithm; the canonical protected branch list stays in the skill
|
|
25
|
+
1. **Discover resolvable worktrees**:
|
|
26
|
+
- Run `git worktree list --porcelain` and count the worktrees it lists
|
|
27
|
+
- **More than one listed:** Invoke the `devflow:worktree-support` skill, then Read its `references/discovery.md` from the skill's base directory for the full 7-step algorithm; the canonical protected branch list stays in the skill. Parse the list, filter (skip protected/detached/mid-rebase), dedup by branch, sort by recent commit
|
|
28
|
+
- **Exactly one listed:** load neither the skill nor the reference — that worktree is the only candidate, and Step 0b's Git agent validates its branch
|
|
28
29
|
- Additional filter: must have unresolved reviews (latest review directory has no `resolution-summary.md`)
|
|
29
30
|
2. **If `--path` flag provided:** use only that worktree, skip discovery
|
|
30
31
|
**`--path` validation**: Before proceeding, verify the path exists as a directory and appears in `git worktree list` output. If not: report error and stop.
|
|
@@ -85,10 +86,22 @@ Set `TARGET_DIR` to the selected review or bug-analysis directory path, and `TAR
|
|
|
85
86
|
|
|
86
87
|
#### Step 0d: Load Project Decisions
|
|
87
88
|
|
|
88
|
-
**Produces:** DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, 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
|
|
90
|
+
|
|
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
|
+
|
|
93
|
+
```bash
|
|
94
|
+
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
95
|
+
```
|
|
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.
|
|
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.
|
|
89
100
|
|
|
90
101
|
### Load DECISIONS_CONTEXT
|
|
91
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.
|
|
104
|
+
|
|
92
105
|
The decisions ledger belongs to the repository, not to one checkout: in a linked worktree it lives in the main worktree, and a session started in a subdirectory reads the copy at the repository root. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
|
|
93
106
|
|
|
94
107
|
```bash
|
|
@@ -112,9 +125,9 @@ Attempt to read `{ledger}/.devflow/learning/index.md`.
|
|
|
112
125
|
|
|
113
126
|
The index is one direct file read, written at render time by `render-decisions.cjs` alongside `decisions.md`/`pitfalls.md` — no `.cjs` script runs here, and the index's own footer names the files that hold each entry's full body.
|
|
114
127
|
|
|
115
|
-
**Step 2 —
|
|
128
|
+
**Step 2 — Agents apply the decisions:**
|
|
116
129
|
|
|
117
|
-
When `DECISIONS_CONTEXT` is not `(none)`, follow `devflow:apply-decisions
|
|
130
|
+
When `DECISIONS_CONTEXT` is not `(none)`, hand it only to the agents whose contract declares it. They follow `devflow:apply-decisions`: scan the index, identify plausibly-relevant entries, Read full entry bodies on demand, and cite verbatim IDs in their reasoning. A host that uses the index in its own thread says so in its own step.
|
|
118
131
|
|
|
119
132
|
This produces a compact index of active ADR/PF entries written at render time — Deprecated/Superseded entries are already stripped. Pass `DECISIONS_CONTEXT` to the Triage agent in Phase 2 and to Code agents in Phase 4.
|
|
120
133
|
|
|
@@ -146,22 +159,32 @@ Glob `{worktree}/.devflow/features/*/KNOWLEDGE.md`. For each file found, read on
|
|
|
146
159
|
|
|
147
160
|
Match the current task area and description against each index line (or frontmatter `description` + `directories` on fallback). Select entries whose documented area overlaps the current task. This is a relevance judgment — prefer specificity over breadth.
|
|
148
161
|
|
|
149
|
-
**Step 4 — Read selected
|
|
162
|
+
**Step 4 — Read each selected KB's Rules:**
|
|
163
|
+
|
|
164
|
+
For each selected entry, `{kb}` is `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md`:
|
|
150
165
|
|
|
151
|
-
|
|
166
|
+
1. List its `##` headings with line numbers through Bash: `command grep -n '^## ' "{kb}"`. This only locates sections; the text of a KB comes from the Read view alone.
|
|
167
|
+
2. Read the `## Rules` range (its line to the next heading) with the Read tool, using `offset` and `limit`, and choose the one to three bullets most relevant to the current task. The choice is yours, made per KB.
|
|
168
|
+
3. If the KB has no `## Rules` section, choose one to three entries from its `## Anti-Patterns` or `## Gotchas` range the same way, and label them by that section's name instead of an ID.
|
|
152
169
|
|
|
153
|
-
**
|
|
170
|
+
When a KB contradicts the code you observe, **trust the code** — the code is the freshness mechanism; the KB may lag behind. A missing Rules section, a missing heading list and `(none)` are legitimate states, not errors.
|
|
154
171
|
|
|
155
|
-
|
|
172
|
+
**Step 5 — Set FEATURE_KNOWLEDGE and FEATURE_KNOWLEDGE_RULES:**
|
|
173
|
+
|
|
174
|
+
Write one block per selected KB. Paste each bullet verbatim from the Read view, never from a shell view. The path is relative to the checkout root; an agent resolves it under `WORKTREE_PATH` when one is provided.
|
|
156
175
|
|
|
157
176
|
```
|
|
158
177
|
--- Feature knowledge: {slug} ---
|
|
159
|
-
{
|
|
178
|
+
KB: .devflow/features/{slug}/KNOWLEDGE.md
|
|
179
|
+
Rules:
|
|
180
|
+
- **KB-AP-2** {bullet text, verbatim}
|
|
181
|
+
- **KB-INV-1** {bullet text, verbatim}
|
|
182
|
+
Headings: L5 Rules · L40 Overview · L62 Anti-Patterns · L118 Key Files
|
|
160
183
|
```
|
|
161
184
|
|
|
162
|
-
If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set
|
|
185
|
+
A KB with no Rules section labels its entries `Rules ({section name}):` and gives them no ID. `FEATURE_KNOWLEDGE` is these blocks; `FEATURE_KNOWLEDGE_RULES` is the same blocks without the `Headings:` line. Both come from this one selection, and each spawn names the variable its recipient takes. If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set both to `(none)`.
|
|
163
186
|
|
|
164
|
-
**One git call, then direct
|
|
187
|
+
**One git call, then direct reads — no `.cjs` script.** After resolving `{worktree}`, this step is 1 index read (or N frontmatter reads on fallback), plus one heading listing and one Rules read per selected KB, bounded by KB count.
|
|
165
188
|
|
|
166
189
|
Pass `FEATURE_KNOWLEDGE` to the Triage agent in Phase 2.
|
|
167
190
|
|
|
@@ -176,23 +199,19 @@ Accept the output only when it is exactly two lines: `exit=0` last and, before i
|
|
|
176
199
|
Set `EVIDENCE_POLICY`, `ISSUE_REQUIRED`, `APPLY_CONVENTIONS` and `REQUIRE_NON_AUTHOR_APPROVAL` from the accepted line. Pass agents only the three mechanism inputs, never `EVIDENCE_POLICY`. Report `Evidence policy: {EVIDENCE_POLICY} (source: {SOURCE})`, plus any `WARN` tokens as advisory, once in the final report.
|
|
177
200
|
Reuse this result for every worktree.
|
|
178
201
|
|
|
179
|
-
**Resolve
|
|
180
|
-
|
|
181
|
-
```bash
|
|
182
|
-
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
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.
|
|
186
|
-
|
|
187
|
-
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.
|
|
188
|
-
|
|
189
|
-
**Resolve `REVIEW_PUBLICATION` per worktree:** take `REVIEW_PUBLICATION` from that worktree's settings line, with `{root}` the worktree's root — multi-worktree repos may resolve different values per worktree. The line already caps the personal choice at the team's (D-PUBLICATION-CEILING), so it is `off`, `auto` or `full`, and `off` when the line was unresolvable.
|
|
202
|
+
**Resolve `REVIEW_PUBLICATION` per worktree:** take `REVIEW_PUBLICATION` from that worktree's settings line — the line resolved above for `{root}`, the worktree's root, by the settings block when this run has not yet resolved that root; multi-worktree repos may resolve different values per worktree. The line already caps the personal choice at the team's (D-PUBLICATION-CEILING), so it is `off`, `auto` or `full`, and `off` when the line was unresolvable.
|
|
190
203
|
|
|
191
204
|
**Evidence stub:** only when `EVIDENCE_POLICY` is `required`, a resolved `off` becomes `stub`, so a counts-only record still reaches the PR. `stub` is never a config value: the settings line never carries it.
|
|
192
205
|
|
|
193
206
|
Note: `auto` is NOT fail-open — under `auto`, the Git agent probes the repository visibility and treats any error or unrecognised value as PUBLIC (mode STUB). What each value does is decided by the Git agent's publication gate (`references/publication-gate.md` step 2); this partial only resolves the value.
|
|
194
207
|
Resolve this per worktree — unlike the evidence policy above, the settings line is per worktree root. From the same line: `COMPLIANCE_FRAMEWORKS` is the settings line's `COMPLIANCE` with `generic` written `none`: `off`, `none`, or the framework ids the machine and this repository declare.
|
|
195
208
|
|
|
209
|
+
**Set the compliance directive** from `COMPLIANCE_FRAMEWORKS`. `COMPLIANCE_DIRECTIVE` is empty when `COMPLIANCE_FRAMEWORKS` is `off`: a spawn line that holds only `{COMPLIANCE_DIRECTIVE}` is then left out, so a lens-off spawn carries nothing about compliance. Otherwise `COMPLIANCE_DIRECTIVE` is this one line, with `<ids>` replaced by the value of `COMPLIANCE_FRAMEWORKS`:
|
|
210
|
+
|
|
211
|
+
> When the task touches regulated surface (data models, auth flows, logging/observability, payments, IaC, retention), invoke Skill(skill="devflow:compliance") and load references/{id}.md only for the ids in <ids> (none: generic controls only); never fabricate guidance for a framework you were not given.
|
|
212
|
+
|
|
213
|
+
Set it per worktree, from that worktree's lens, and pass that worktree's `COMPLIANCE_DIRECTIVE` to each of its Code and Code-fix spawns, on a line of its own.
|
|
214
|
+
|
|
196
215
|
**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.
|
|
197
216
|
|
|
198
217
|
### Phase 1: Parse Issues
|
|
@@ -307,11 +326,10 @@ TASK_ID: resolve-{batch-id}
|
|
|
307
326
|
ISSUES: {fix_now_issues_in_batch}
|
|
308
327
|
SCOPE: {risk_tier_per_issue}
|
|
309
328
|
PUSH: false
|
|
310
|
-
CREATE_PR: false
|
|
311
329
|
WORKTREE_PATH: {worktree_path} (omit if cwd)
|
|
312
330
|
DECISIONS_CONTEXT: {decisions_context}
|
|
313
331
|
FEATURE_KNOWLEDGE: {feature_knowledge}
|
|
314
|
-
|
|
332
|
+
{COMPLIANCE_DIRECTIVE}
|
|
315
333
|
Fix only the listed pre-classified FIX_NOW issues. Do not re-litigate dispositions.
|
|
316
334
|
Same-file issues → one commit. Include ## Verification block in report.
|
|
317
335
|
Regression fix without failing-then-passing regression test → BLOCKED."
|
|
@@ -374,17 +392,17 @@ Run build, typecheck, lint, test. Report pass/fail with failure details."
|
|
|
374
392
|
1. Extract failure details from Validate agent output
|
|
375
393
|
2. Increment `validation_retry_count`
|
|
376
394
|
3. If `validation_retry_count <= 2`:
|
|
377
|
-
- Spawn Code agent with fix context:
|
|
395
|
+
- Spawn Code-fix agent with fix context:
|
|
378
396
|
```
|
|
379
|
-
Agent(subagent_type="Code"):
|
|
397
|
+
Agent(subagent_type="Code-fix"):
|
|
380
398
|
"OPERATION: validation-fix
|
|
381
399
|
TASK_ID: resolve-{batch-id}-valfix-{count}
|
|
382
400
|
VALIDATION_FAILURES: {parsed failures from Validate agent}
|
|
383
401
|
SCOPE: Fix only the listed failures, no other changes
|
|
384
402
|
PUSH: false
|
|
385
|
-
CREATE_PR: false
|
|
386
403
|
WORKTREE_PATH: {worktree_path} (omit if cwd)
|
|
387
|
-
|
|
404
|
+
DECISIONS_CONTEXT: {decisions_context}
|
|
405
|
+
{COMPLIANCE_DIRECTIVE}"
|
|
388
406
|
```
|
|
389
407
|
- Loop back to re-validate
|
|
390
408
|
4. If `validation_retry_count > 2`: set VERIFICATION_STATUS = FAILED and exit the validation loop — record a blocking callout in the `## Verification` section (never a silent pass).
|
|
@@ -394,7 +412,7 @@ Run build, typecheck, lint, test. Report pass/fail with failure details."
|
|
|
394
412
|
Record `## Verification` outcome in resolution-summary.md (runs unconditionally after the validation loop exits):
|
|
395
413
|
- Rewrite the `## Verification` section with | Command | Result | table + `Final gate: PASS | FAILED after N attempts`
|
|
396
414
|
|
|
397
|
-
Push all commits to remote once (Code
|
|
415
|
+
Push all commits to remote once (Code and Code-fix agents ran with PUSH: false — runs whether the gate PASSED or FAILED, so the branch is always visible before Phase 9 or CI runs):
|
|
398
416
|
```bash
|
|
399
417
|
git -C {worktree} push
|
|
400
418
|
```
|
|
@@ -432,7 +450,7 @@ Phase 7 has pushed already, so this is a no-op unless the head moved since. `exi
|
|
|
432
450
|
3. **If NO_PR or NO_CI** → skip: "No PR/CI configured, skipping CI validation." Proceed to next phase.
|
|
433
451
|
4. **If PENDING** and fewer than 3 waits have run → wait again (step 1). After the third wait → report "CI still running — verify manually before merging" and proceed.
|
|
434
452
|
5. **If INDETERMINATE** and fewer than 3 waits have run → wait again (step 1). After the third wait → report "CI status unknown — verify manually before merging" and proceed.
|
|
435
|
-
6. **If FAILING** and fewer than 2 fixes have run → report the failing checks from the line. Spawn `Agent(subagent_type="Code")` whose prompt opens with `OPERATION: ci-fix`, with `
|
|
453
|
+
6. **If FAILING** and fewer than 2 fixes have run → report the failing checks from the line. Spawn `Agent(subagent_type="Code-fix")` whose prompt opens with `OPERATION: ci-fix`, with `COMPLIANCE_DIRECTIVE` (when it is not empty), `CI_FAILURES`, `DECISIONS_CONTEXT` and `PUSH: false`; `CI_FAILURES` holds the failing-check names from the line and nothing else, because the Code-fix agent fetches the full names and reads the logs itself and this command reads none. After a fix, push with the command above and, if a wait remains, wait again (step 1); a failed push records `TRACEABILITY: DEGRADED (ci push failed)`, reports "CI status unknown — verify manually before merging" and stops waiting. After the second fix still FAILING → report the failing checks and proceed.
|
|
436
454
|
7. **Budget**: at most 3 waits and 2 fixes in all, per worktree. When one is spent, report the current status and proceed.
|
|
437
455
|
<!-- /PATTERN: ci-status-gate -->
|
|
438
456
|
|
|
@@ -642,17 +660,7 @@ git -C "{start}" rev-parse --show-toplevel
|
|
|
642
660
|
|
|
643
661
|
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}`.
|
|
644
662
|
|
|
645
|
-
**Step 1 — Check the opt-out gate, with `{root}` = `{worktree}`:**
|
|
646
|
-
|
|
647
|
-
**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:
|
|
648
|
-
|
|
649
|
-
```bash
|
|
650
|
-
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
651
|
-
```
|
|
652
|
-
|
|
653
|
-
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.
|
|
654
|
-
|
|
655
|
-
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.
|
|
663
|
+
**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.
|
|
656
664
|
|
|
657
665
|
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.
|
|
658
666
|
|
|
@@ -682,7 +690,7 @@ Write the knowledge base to:
|
|
|
682
690
|
Then update the index cache by performing a read-modify-write on:
|
|
683
691
|
{worktree}/.devflow/features/index.md
|
|
684
692
|
|
|
685
|
-
Index line format: `- **{slug}** — {areas} — {Use-when description}`
|
|
693
|
+
Index line format: `- **{slug}** — {areas} — {Use-when description}` — at most 300 characters, the description at most 220; reword a longer one, never cut it.
|
|
686
694
|
|
|
687
695
|
If the line for this slug already exists in index.md, replace it. If it does not exist, append it. If index.md does not exist, create it with just this line.
|
|
688
696
|
|
|
@@ -726,10 +734,10 @@ When the Knowledge agent reports `KB_COMMIT: skipped (detached HEAD)`, the files
|
|
|
726
734
|
│
|
|
727
735
|
├─ Phase 6: Simplify [Simplify agent]
|
|
728
736
|
│
|
|
729
|
-
├─ Phase 7: Verification Gate [Validate agent, haiku] + push + Code agent validation-fix loop ≤2
|
|
737
|
+
├─ Phase 7: Verification Gate [Validate agent, haiku] + push + Code-fix agent validation-fix loop ≤2
|
|
730
738
|
│
|
|
731
739
|
├─ Phase 8: CI Status Gate (conditional — skipped if no fixes or verification FAILED)
|
|
732
|
-
│ └─ push, then ci-wait.cjs (inline, one wait ≤ 570 s) → Code agent on FAILING (3 waits + 2 fixes per worktree)
|
|
740
|
+
│ └─ push, then ci-wait.cjs (inline, one wait ≤ 570 s) → Code-fix agent on FAILING (3 waits + 2 fixes per worktree)
|
|
733
741
|
│
|
|
734
742
|
├─ Phase 9: Git agent (manage-debt) — FIX_SEPARATE + TECH_DEBT → backfill Tracked={ISSUE_REF} (or TRACEABILITY: DEGRADED on failure)
|
|
735
743
|
│ SEQUENTIAL across worktrees
|
|
@@ -14,7 +14,7 @@ Run Simplify agent and Scrutinize agent sequentially on changed files for post-i
|
|
|
14
14
|
|
|
15
15
|
### Phase 0: Context Gathering
|
|
16
16
|
|
|
17
|
-
**Produces:** FILES_CHANGED, TASK_DESCRIPTION, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, HEAD_BEFORE
|
|
17
|
+
**Produces:** FILES_CHANGED, TASK_DESCRIPTION, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, FEATURE_KNOWLEDGE_RULES, HEAD_BEFORE
|
|
18
18
|
|
|
19
19
|
Detect changed files and build context:
|
|
20
20
|
|
|
@@ -23,8 +23,21 @@ Detect changed files and build context:
|
|
|
23
23
|
3. If no changes found, report "No changes to review" and exit
|
|
24
24
|
4. Build TASK_DESCRIPTION from recent commit messages or branch name
|
|
25
25
|
5. Record `HEAD_BEFORE` (`git rev-parse HEAD`) now, before Simplify runs — Phase 3 compares against it
|
|
26
|
+
|
|
27
|
+
**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:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
31
|
+
```
|
|
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.
|
|
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.
|
|
36
|
+
|
|
26
37
|
### Load DECISIONS_CONTEXT
|
|
27
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.
|
|
40
|
+
|
|
28
41
|
The decisions ledger belongs to the repository, not to one checkout: in a linked worktree it lives in the main worktree, and a session started in a subdirectory reads the copy at the repository root. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
|
|
29
42
|
|
|
30
43
|
```bash
|
|
@@ -48,9 +61,9 @@ Attempt to read `{ledger}/.devflow/learning/index.md`.
|
|
|
48
61
|
|
|
49
62
|
The index is one direct file read, written at render time by `render-decisions.cjs` alongside `decisions.md`/`pitfalls.md` — no `.cjs` script runs here, and the index's own footer names the files that hold each entry's full body.
|
|
50
63
|
|
|
51
|
-
**Step 2 —
|
|
64
|
+
**Step 2 — Agents apply the decisions:**
|
|
52
65
|
|
|
53
|
-
When `DECISIONS_CONTEXT` is not `(none)`, follow `devflow:apply-decisions
|
|
66
|
+
When `DECISIONS_CONTEXT` is not `(none)`, hand it only to the agents whose contract declares it. They follow `devflow:apply-decisions`: scan the index, identify plausibly-relevant entries, Read full entry bodies on demand, and cite verbatim IDs in their reasoning. A host that uses the index in its own thread says so in its own step.
|
|
54
67
|
|
|
55
68
|
Pass `DECISIONS_CONTEXT` to Scrutinize agent — the compact index lists active ADR/PF entries; Scrutinize agent uses `devflow:apply-decisions` to Read full entry bodies on demand. Known pitfalls help identify reintroduced issues, prior decisions help validate architectural consistency. (Simplify agent does not consume decisions — it operates at code-shape level and Scrutinize agent runs after to catch any architectural drift.)
|
|
56
69
|
|
|
@@ -82,26 +95,36 @@ Glob `{worktree}/.devflow/features/*/KNOWLEDGE.md`. For each file found, read on
|
|
|
82
95
|
|
|
83
96
|
Match the current task area and description against each index line (or frontmatter `description` + `directories` on fallback). Select entries whose documented area overlaps the current task. This is a relevance judgment — prefer specificity over breadth.
|
|
84
97
|
|
|
85
|
-
**Step 4 — Read selected
|
|
98
|
+
**Step 4 — Read each selected KB's Rules:**
|
|
86
99
|
|
|
87
|
-
For each selected entry,
|
|
100
|
+
For each selected entry, `{kb}` is `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md`:
|
|
88
101
|
|
|
89
|
-
|
|
102
|
+
1. List its `##` headings with line numbers through Bash: `command grep -n '^## ' "{kb}"`. This only locates sections; the text of a KB comes from the Read view alone.
|
|
103
|
+
2. Read the `## Rules` range (its line to the next heading) with the Read tool, using `offset` and `limit`, and choose the one to three bullets most relevant to the current task. The choice is yours, made per KB.
|
|
104
|
+
3. If the KB has no `## Rules` section, choose one to three entries from its `## Anti-Patterns` or `## Gotchas` range the same way, and label them by that section's name instead of an ID.
|
|
90
105
|
|
|
91
|
-
|
|
106
|
+
When a KB contradicts the code you observe, **trust the code** — the code is the freshness mechanism; the KB may lag behind. A missing Rules section, a missing heading list and `(none)` are legitimate states, not errors.
|
|
107
|
+
|
|
108
|
+
**Step 5 — Set FEATURE_KNOWLEDGE and FEATURE_KNOWLEDGE_RULES:**
|
|
109
|
+
|
|
110
|
+
Write one block per selected KB. Paste each bullet verbatim from the Read view, never from a shell view. The path is relative to the checkout root; an agent resolves it under `WORKTREE_PATH` when one is provided.
|
|
92
111
|
|
|
93
112
|
```
|
|
94
113
|
--- Feature knowledge: {slug} ---
|
|
95
|
-
{
|
|
114
|
+
KB: .devflow/features/{slug}/KNOWLEDGE.md
|
|
115
|
+
Rules:
|
|
116
|
+
- **KB-AP-2** {bullet text, verbatim}
|
|
117
|
+
- **KB-INV-1** {bullet text, verbatim}
|
|
118
|
+
Headings: L5 Rules · L40 Overview · L62 Anti-Patterns · L118 Key Files
|
|
96
119
|
```
|
|
97
120
|
|
|
98
|
-
If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set
|
|
121
|
+
A KB with no Rules section labels its entries `Rules ({section name}):` and gives them no ID. `FEATURE_KNOWLEDGE` is these blocks; `FEATURE_KNOWLEDGE_RULES` is the same blocks without the `Headings:` line. Both come from this one selection, and each spawn names the variable its recipient takes. If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set both to `(none)`.
|
|
99
122
|
|
|
100
|
-
**One git call, then direct
|
|
123
|
+
**One git call, then direct reads — no `.cjs` script.** After resolving `{worktree}`, this step is 1 index read (or N frontmatter reads on fallback), plus one heading listing and one Rules read per selected KB, bounded by KB count.
|
|
101
124
|
|
|
102
|
-
Pass `
|
|
125
|
+
Pass `FEATURE_KNOWLEDGE_RULES` to Scrutinize agent.
|
|
103
126
|
|
|
104
|
-
**Extract:** FILES_CHANGED (list), TASK_DESCRIPTION (string), DECISIONS_CONTEXT (string, optional), FEATURE_KNOWLEDGE (string, optional), HEAD_BEFORE (40-hex SHA)
|
|
127
|
+
**Extract:** FILES_CHANGED (list), TASK_DESCRIPTION (string), DECISIONS_CONTEXT (string, optional), FEATURE_KNOWLEDGE (string, optional), FEATURE_KNOWLEDGE_RULES (string, optional), HEAD_BEFORE (40-hex SHA)
|
|
105
128
|
|
|
106
129
|
### Phase 1: Simplify agent (Code Refinement)
|
|
107
130
|
|
|
@@ -129,7 +152,7 @@ Agent(subagent_type="Scrutinize", run_in_background=false):
|
|
|
129
152
|
"TASK_DESCRIPTION: {task_description}
|
|
130
153
|
FILES_CHANGED: {files_changed}
|
|
131
154
|
DECISIONS_CONTEXT: {decisions_context}
|
|
132
|
-
FEATURE_KNOWLEDGE: {
|
|
155
|
+
FEATURE_KNOWLEDGE: {feature_knowledge_rules}
|
|
133
156
|
Evaluate against 9-pillar framework. Fix P0/P1 issues. Return structured report.
|
|
134
157
|
Follow devflow:apply-decisions to scan DECISIONS_CONTEXT and Read full ADR/PF bodies on demand. Skip if (none).
|
|
135
158
|
Follow devflow:apply-feature-knowledge for FEATURE_KNOWLEDGE. Skip if (none)."
|
|
@@ -195,17 +218,7 @@ git -C "{start}" rev-parse --show-toplevel
|
|
|
195
218
|
|
|
196
219
|
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}`.
|
|
197
220
|
|
|
198
|
-
**Step 1 — Check the opt-out gate, with `{root}` = `{worktree}`:**
|
|
199
|
-
|
|
200
|
-
**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:
|
|
201
|
-
|
|
202
|
-
```bash
|
|
203
|
-
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
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.
|
|
207
|
-
|
|
208
|
-
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.
|
|
221
|
+
**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.
|
|
209
222
|
|
|
210
223
|
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.
|
|
211
224
|
|
|
@@ -235,7 +248,7 @@ Write the knowledge base to:
|
|
|
235
248
|
Then update the index cache by performing a read-modify-write on:
|
|
236
249
|
{worktree}/.devflow/features/index.md
|
|
237
250
|
|
|
238
|
-
Index line format: `- **{slug}** — {areas} — {Use-when description}`
|
|
251
|
+
Index line format: `- **{slug}** — {areas} — {Use-when description}` — at most 300 characters, the description at most 220; reword a longer one, never cut it.
|
|
239
252
|
|
|
240
253
|
If the line for this slug already exists in index.md, replace it. If it does not exist, append it. If index.md does not exist, create it with just this line.
|
|
241
254
|
|
|
@@ -231,4 +231,105 @@ export function rewriteAgentFrontmatter(content, opts) {
|
|
|
231
231
|
const changed = newContent !== content;
|
|
232
232
|
return Ok({ content: newContent, changed });
|
|
233
233
|
}
|
|
234
|
+
const WHOLE_SERVER_PREFIX = 'mcp__';
|
|
235
|
+
/** A server name as it appears in a whole-server entry: the charset Claude Code keeps, no `__`. */
|
|
236
|
+
const WHOLE_SERVER_NAME_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
237
|
+
/**
|
|
238
|
+
* True when `tool` is a whole-server allowlist entry: `mcp__` and a server name of
|
|
239
|
+
* 1-64 characters from `[A-Za-z0-9_-]` with no `__` (D-WHOLE-SERVER-ENTRY).
|
|
240
|
+
*/
|
|
241
|
+
export function isWholeServerTool(tool) {
|
|
242
|
+
if (!tool.startsWith(WHOLE_SERVER_PREFIX))
|
|
243
|
+
return false;
|
|
244
|
+
const name = tool.slice(WHOLE_SERVER_PREFIX.length);
|
|
245
|
+
return WHOLE_SERVER_NAME_RE.test(name) && !name.includes('__');
|
|
246
|
+
}
|
|
247
|
+
/** The single-line inline form `tools: ["A", "B"]`, within a frontmatter body. */
|
|
248
|
+
const INLINE_TOOLS_RE = /^tools:[ \t]*\[([^\r\n]*)\][ \t]*(?=\r?$)/m;
|
|
249
|
+
function toolItems(inner) {
|
|
250
|
+
return inner.split(',').filter(item => item.trim() !== '');
|
|
251
|
+
}
|
|
252
|
+
function unquoteTool(item) {
|
|
253
|
+
return item.trim().replace(/^(["'])(.*)\1$/, '$2');
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Replace the whole-server entries of the first frontmatter block's inline `tools:` line
|
|
257
|
+
* with `extraTools`, and touch nothing else.
|
|
258
|
+
*
|
|
259
|
+
* Idempotent: stamping the same list twice yields the same bytes, and stamping a new list
|
|
260
|
+
* replaces the previous one rather than adding to it. Every other entry of the line keeps
|
|
261
|
+
* its original text, and every other byte of the file (other keys, the body, CRLF or LF)
|
|
262
|
+
* is untouched. An empty `extraTools` removes the stamp.
|
|
263
|
+
*
|
|
264
|
+
* Rejects, rather than repairs: an entry that is not a whole-server entry (`invalid-tool`;
|
|
265
|
+
* it would otherwise reach the frontmatter as free text), a file with no inline
|
|
266
|
+
* `tools: [...]` line (`no-tools-line`; a block-list `tools:` is not edited) and a file
|
|
267
|
+
* with no well-formed frontmatter.
|
|
268
|
+
*
|
|
269
|
+
* Pure function — no I/O.
|
|
270
|
+
*/
|
|
271
|
+
export function stampAgentTools(content, extraTools) {
|
|
272
|
+
for (const tool of extraTools) {
|
|
273
|
+
if (!isWholeServerTool(tool))
|
|
274
|
+
return Err('invalid-tool');
|
|
275
|
+
}
|
|
276
|
+
const parts = parseFrontmatter(content);
|
|
277
|
+
if (!parts.ok)
|
|
278
|
+
return Err(parts.error);
|
|
279
|
+
const { fmBody, openDelim, closeDelim, afterClose, eol } = parts.value;
|
|
280
|
+
const match = INLINE_TOOLS_RE.exec(fmBody);
|
|
281
|
+
if (!match)
|
|
282
|
+
return Err('no-tools-line');
|
|
283
|
+
const rawItems = toolItems(match[1]);
|
|
284
|
+
const kept = rawItems.filter(item => !isWholeServerTool(unquoteTool(item)));
|
|
285
|
+
const stamped = [...new Set(extraTools)].map(tool => `"${tool}"`);
|
|
286
|
+
// Nothing to remove and nothing to add: the line, whatever its spacing, is already right.
|
|
287
|
+
if (kept.length === rawItems.length && stamped.length === 0)
|
|
288
|
+
return Ok({ content, changed: false });
|
|
289
|
+
// The kept entries keep their own text; only the edges lose the padding that no longer
|
|
290
|
+
// borders a neighbour, so the appended entries land after `, ` and the line stays one shape.
|
|
291
|
+
const keptText = kept
|
|
292
|
+
.map((item, i) => {
|
|
293
|
+
const lead = i === 0 ? item.trimStart() : item;
|
|
294
|
+
return i === kept.length - 1 ? lead.trimEnd() : lead;
|
|
295
|
+
})
|
|
296
|
+
.join(',');
|
|
297
|
+
const inner = [keptText, stamped.join(', ')].filter(text => text !== '').join(', ');
|
|
298
|
+
const line = `tools: [${inner}]`;
|
|
299
|
+
const newBody = fmBody.slice(0, match.index) + line + fmBody.slice(match.index + match[0].length);
|
|
300
|
+
const newContent = openDelim + newBody + eol + closeDelim + afterClose;
|
|
301
|
+
return Ok({ content: newContent, changed: newContent !== content });
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* The whole-server entries of the first frontmatter block's inline `tools:` line, in
|
|
305
|
+
* order. Ok([]) when the line carries none; an error when there is no line to read.
|
|
306
|
+
* Pure function — no I/O.
|
|
307
|
+
*/
|
|
308
|
+
export function readStampedTools(content) {
|
|
309
|
+
const parts = parseFrontmatter(content);
|
|
310
|
+
if (!parts.ok)
|
|
311
|
+
return Err(parts.error);
|
|
312
|
+
const match = INLINE_TOOLS_RE.exec(parts.value.fmBody);
|
|
313
|
+
if (!match)
|
|
314
|
+
return Err('no-tools-line');
|
|
315
|
+
return Ok(toolItems(match[1]).map(unquoteTool).filter(isWholeServerTool));
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* The text a converge installs for an agent: the variant `source` wearing the whole-server
|
|
319
|
+
* entries the installed copy carries. The stamp is applied at install and by
|
|
320
|
+
* `devflow tracker --servers`, never by a converge, so a converge only CARRIES it. Without
|
|
321
|
+
* the carry, switching an agent between prompt variants would drop its stamp and compare
|
|
322
|
+
* unequal to the installed copy on every run.
|
|
323
|
+
*
|
|
324
|
+
* `source` is returned unchanged when there is nothing safe to carry: either side has no
|
|
325
|
+
* well-formed inline `tools:` line, or the installed copy carries no entries.
|
|
326
|
+
* Pure function — no I/O.
|
|
327
|
+
*/
|
|
328
|
+
export function carryStampedTools(source, installed) {
|
|
329
|
+
const carried = readStampedTools(installed);
|
|
330
|
+
if (!carried.ok || carried.value.length === 0)
|
|
331
|
+
return source;
|
|
332
|
+
const stamped = stampAgentTools(source, carried.value);
|
|
333
|
+
return stamped.ok ? stamped.value.content : source;
|
|
334
|
+
}
|
|
234
335
|
//# sourceMappingURL=agent-frontmatter.js.map
|
|
@@ -599,6 +599,49 @@ export async function loadShippedAgentDefaults(dirs = agentSourceDirs(), opts) {
|
|
|
599
599
|
}
|
|
600
600
|
return defaults;
|
|
601
601
|
}
|
|
602
|
+
// ---------------------------------------------------------------------------
|
|
603
|
+
// carryAgentOverrides — the frontmatter a converge keeps
|
|
604
|
+
// ---------------------------------------------------------------------------
|
|
605
|
+
/**
|
|
606
|
+
* D-AGENT-OVERRIDE-CARRY: the text a prompt converge installs for an agent is the
|
|
607
|
+
* variant `source` wearing the installed copy's `model:` and `effort:`.
|
|
608
|
+
*
|
|
609
|
+
* Those two lines are the only frontmatter keys reapplyAgentMapping manages, and
|
|
610
|
+
* `devflow agents` and the proxy put their values there. A converge that installed
|
|
611
|
+
* the bare variant would write every overridden agent back to its shipped model
|
|
612
|
+
* and effort and leave reapplyAgentMapping to restore it: a window with default
|
|
613
|
+
* models, and a no-op converge that rewrites everything. Carrying the two lines
|
|
614
|
+
* keeps that window shut, so a copy already holding the right variant and its
|
|
615
|
+
* overrides compares byte-equal and is not touched.
|
|
616
|
+
*
|
|
617
|
+
* The carry is an optimisation, never the authority: reapplyAgentMapping reads
|
|
618
|
+
* agent-models.json and decides what the installed frontmatter must say. It
|
|
619
|
+
* agrees with the carry whenever the installed copy was last written by it, and
|
|
620
|
+
* where they disagree the later reapply wins. Both go through
|
|
621
|
+
* rewriteAgentFrontmatter, so the model-name charset guard, the first-block scope
|
|
622
|
+
* and the EOL handling are the ones the reapply uses.
|
|
623
|
+
*
|
|
624
|
+
* `source` is returned unchanged when there is nothing safe to carry: either side
|
|
625
|
+
* has no well-formed frontmatter, the installed copy has no model, its model
|
|
626
|
+
* fails the model-name charset or its effort is not an EFFORT_LEVELS member. An
|
|
627
|
+
* installed copy with no `effort:` line carries no effort (a mapping effort of
|
|
628
|
+
* `inherit` yields exactly that).
|
|
629
|
+
*
|
|
630
|
+
* Pure function — no I/O.
|
|
631
|
+
*/
|
|
632
|
+
export function carryAgentOverrides(source, installed) {
|
|
633
|
+
const model = readFrontmatterModel(installed);
|
|
634
|
+
const effort = readFrontmatterEffort(installed);
|
|
635
|
+
if (!model.ok || !effort.ok || model.value === '')
|
|
636
|
+
return source;
|
|
637
|
+
if (effort.value !== '' && !isEffortLevel(effort.value))
|
|
638
|
+
return source;
|
|
639
|
+
const carried = rewriteAgentFrontmatter(source, {
|
|
640
|
+
model: model.value,
|
|
641
|
+
effort: effort.value === '' ? null : effort.value,
|
|
642
|
+
});
|
|
643
|
+
return carried.ok ? carried.value.content : source;
|
|
644
|
+
}
|
|
602
645
|
/**
|
|
603
646
|
* Idempotent convergence function: walk every installed agent file and
|
|
604
647
|
* rewrite frontmatter model/effort to match the effective mapping.
|
package/dist/core/assets.js
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
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
5
|
/**
|
|
5
6
|
* Flat skills source directory: src/assets/skills/{name}/
|
|
6
7
|
* All plugins' skills live here directly (no per-plugin subdirectory).
|
|
8
|
+
*
|
|
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
|
|
11
|
+
* root as the rest of its sources.
|
|
7
12
|
*/
|
|
8
|
-
export function skillsDir() {
|
|
9
|
-
return join(
|
|
13
|
+
export function skillsDir(root = getPackageRoot()) {
|
|
14
|
+
return join(root, 'src', 'assets', 'skills');
|
|
10
15
|
}
|
|
11
16
|
/**
|
|
12
|
-
* Flat agents source directory: src/assets/agents/{name}.md
|
|
13
|
-
* All plugins' agents live here directly.
|
|
17
|
+
* Flat agents source directory: src/assets/agents/{name}.md, or {name}.mds for a
|
|
18
|
+
* generator host. All plugins' agents live here directly.
|
|
14
19
|
*
|
|
15
20
|
* @param root - Package root to resolve against. Injectable so a caller working
|
|
16
21
|
* on a temp tree (the test harness) reads the layout from here rather than
|
|
@@ -35,17 +40,49 @@ export function scriptsDir() {
|
|
|
35
40
|
}
|
|
36
41
|
/**
|
|
37
42
|
* Compiled commands directory: dist/commands/
|
|
38
|
-
* Single lookup directory for installed commands
|
|
39
|
-
*
|
|
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).
|
|
40
46
|
*/
|
|
41
47
|
export function commandsDir() {
|
|
42
48
|
return join(getPackageRoot(), 'dist', 'commands');
|
|
43
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Learning-off variant directory: dist/learning-off/{commands,agents}/
|
|
52
|
+
*
|
|
53
|
+
* Holds the learning-off variant of each prompt that carries a learning arm
|
|
54
|
+
* (D-LEARNING-VARIANTS), and only those. Absent until the build has run, so every
|
|
55
|
+
* reader tolerates its absence.
|
|
56
|
+
*
|
|
57
|
+
* The spelling comes from LEARNING_OFF_OUTPUT_DIR in learning-variants.ts, the
|
|
58
|
+
* build's own destination, rather than being retyped here.
|
|
59
|
+
*
|
|
60
|
+
* @param kind - Which prompt kind's variants.
|
|
61
|
+
* @param root - Package root to resolve against (see agentsDir).
|
|
62
|
+
*/
|
|
63
|
+
export function learningOffDir(kind, root = getPackageRoot()) {
|
|
64
|
+
return join(root, ...LEARNING_OFF_OUTPUT_DIR.split('/'), kind);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Command source directories, MOST-PREFERRED FIRST.
|
|
68
|
+
*
|
|
69
|
+
* D-LEARNING-VARIANT-INSTALL: with learning off the learning-off variant comes
|
|
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
|
|
72
|
+
* single-directory lookup.
|
|
73
|
+
*
|
|
74
|
+
* @param learning - The machine's settled learning switch.
|
|
75
|
+
* @param root - Package root to resolve against (see agentsDir).
|
|
76
|
+
*/
|
|
77
|
+
export function commandSourceDirs(learning, root = getPackageRoot()) {
|
|
78
|
+
const normal = join(root, 'dist', 'commands');
|
|
79
|
+
return learning ? [normal] : [learningOffDir('commands', root), normal];
|
|
80
|
+
}
|
|
44
81
|
/**
|
|
45
82
|
* Compiled agents directory: dist/agents/{name}.md
|
|
46
83
|
*
|
|
47
|
-
* Output of the .mds generator hosts. The directory is absent until
|
|
48
|
-
*
|
|
84
|
+
* Output of the .mds generator hosts. The directory is absent until the build has
|
|
85
|
+
* run, so every reader must tolerate its absence.
|
|
49
86
|
*
|
|
50
87
|
* @param root - Package root to resolve against (see agentsDir).
|
|
51
88
|
*/
|
|
@@ -87,9 +124,17 @@ export function compiledSkillRefsDir(root = getPackageRoot()) {
|
|
|
87
124
|
* The non-empty tuple makes an empty list a compile error at every call site:
|
|
88
125
|
* an empty list would survive a `??` default and resolve to nothing.
|
|
89
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
|
|
129
|
+
* every other reader wants: the shipped defaults (model, effort) are the same in
|
|
130
|
+
* both variants, so loadShippedAgentDefaults and the test harness keep reading the
|
|
131
|
+
* learning-on tree.
|
|
132
|
+
*
|
|
90
133
|
* @param root - Package root to resolve against (see agentsDir).
|
|
134
|
+
* @param learning - The machine's settled learning switch; on by default.
|
|
91
135
|
*/
|
|
92
|
-
export function agentSourceDirs(root = getPackageRoot()) {
|
|
93
|
-
|
|
136
|
+
export function agentSourceDirs(root = getPackageRoot(), learning = true) {
|
|
137
|
+
const normal = [compiledAgentsDir(root), agentsDir(root)];
|
|
138
|
+
return learning ? normal : [learningOffDir('agents', root), ...normal];
|
|
94
139
|
}
|
|
95
140
|
//# sourceMappingURL=assets.js.map
|