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/core/plugins.js
CHANGED
|
@@ -49,7 +49,14 @@ export const DEVFLOW_PLUGINS = [
|
|
|
49
49
|
* dist/commands/, and a hook-spawned agent appears in none of them.
|
|
50
50
|
*/
|
|
51
51
|
agents: ['learning', 'tracker'],
|
|
52
|
-
|
|
52
|
+
/**
|
|
53
|
+
* D-AGENT-REFS: `agent-references` is a reference-only skill. It holds the Synthesize mode
|
|
54
|
+
* templates and the Learning maintain step, which those two agents read by explicit path, so
|
|
55
|
+
* it sits here (core-skills is always installed) and no other plugin lists or requires it.
|
|
56
|
+
* It is never preloaded: tests/guards/agent-references.test.ts holds that, and the one
|
|
57
|
+
* exception to the repo-wide ban on `disable-model-invocation` names this skill alone.
|
|
58
|
+
*/
|
|
59
|
+
skills: ['apply-decisions', 'apply-feature-knowledge', 'software-design', 'docs-framework', 'git', 'boundary-validation', 'test-driven-development', 'testing', 'dependency-research', 'agent-references'],
|
|
53
60
|
requires: [
|
|
54
61
|
'architecture',
|
|
55
62
|
'complexity',
|
|
@@ -64,34 +71,30 @@ export const DEVFLOW_PLUGINS = [
|
|
|
64
71
|
'security',
|
|
65
72
|
'worktree-support',
|
|
66
73
|
],
|
|
67
|
-
|
|
74
|
+
// D-CONTEXT-ECONOMY-RULE: reading discipline is a core rule, not a skill, because it
|
|
75
|
+
// must reach every session and every spawned agent without an activation step. It
|
|
76
|
+
// tells the model to list a large file's headings and read ranges, and to count
|
|
77
|
+
// search matches before printing them. Its body stays near 400 characters (ceiling
|
|
78
|
+
// 450) and names no search binary, since the rule is loaded into every session;
|
|
79
|
+
// tests/rules.test.ts enforces the length, the directives and this registration.
|
|
80
|
+
rules: ['security', 'engineering', 'quality', 'reliability', 'context-economy'],
|
|
68
81
|
},
|
|
69
82
|
{
|
|
70
83
|
name: 'devflow-plan',
|
|
71
84
|
description: 'Unified design planning with gap analysis and design review',
|
|
72
85
|
commands: ['/plan'],
|
|
73
|
-
agents: ['git', 'skim', 'synthesize', 'design'],
|
|
86
|
+
agents: ['git', 'skim', 'synthesize', 'design', 'explore'],
|
|
74
87
|
skills: ['gap-analysis', 'design-review', 'patterns', 'worktree-support', 'feature-knowledge', 'apply-feature-knowledge'],
|
|
75
88
|
// D-CHARTER-BOUNDED-INLINE: /plan's main thread orchestrates and loads no
|
|
76
89
|
// companion skills, so `requires:` lists only skills this plugin's command,
|
|
77
90
|
// agents and skills reference. `software-design` and `test-driven-development`
|
|
78
91
|
// have no reader here; the closure guard's reverse arm rejects an unread entry.
|
|
92
|
+
// `docs-framework` is read: Phase 14 loads it at the step that names the
|
|
93
|
+
// design document (D-DOCS-NAMES-AUTHORITY).
|
|
79
94
|
requires: [
|
|
80
95
|
'apply-decisions',
|
|
81
|
-
'architecture',
|
|
82
|
-
'complexity',
|
|
83
|
-
'consistency',
|
|
84
|
-
'database',
|
|
85
|
-
'dependencies',
|
|
86
96
|
'docs-framework',
|
|
87
|
-
'documentation',
|
|
88
97
|
'git',
|
|
89
|
-
'performance',
|
|
90
|
-
'regression',
|
|
91
|
-
'reliability',
|
|
92
|
-
'review-methodology',
|
|
93
|
-
'security',
|
|
94
|
-
'testing',
|
|
95
98
|
],
|
|
96
99
|
rules: [],
|
|
97
100
|
},
|
|
@@ -99,17 +102,15 @@ export const DEVFLOW_PLUGINS = [
|
|
|
99
102
|
name: 'devflow-implement',
|
|
100
103
|
description: 'Complete task implementation workflow - accepts plan documents, issues, or task descriptions',
|
|
101
104
|
commands: ['/implement'],
|
|
102
|
-
agents: ['git', 'code', 'simplify', 'scrutinize', 'evaluate', 'test', 'validate', 'knowledge'],
|
|
105
|
+
agents: ['git', 'code', 'code-fix', 'simplify', 'scrutinize', 'evaluate', 'test', 'validate', 'knowledge'],
|
|
103
106
|
skills: ['patterns', 'qa', 'quality-gates', 'worktree-support', 'feature-knowledge', 'apply-feature-knowledge'],
|
|
104
107
|
requires: [
|
|
105
108
|
'apply-decisions',
|
|
106
109
|
'architecture',
|
|
107
|
-
'boundary-validation',
|
|
108
110
|
'complexity',
|
|
109
111
|
'consistency',
|
|
110
112
|
'database',
|
|
111
113
|
'dependencies',
|
|
112
|
-
'dependency-research',
|
|
113
114
|
'documentation',
|
|
114
115
|
'git',
|
|
115
116
|
'performance',
|
|
@@ -133,23 +134,21 @@ export const DEVFLOW_PLUGINS = [
|
|
|
133
134
|
// no companion skills, so `requires:` lists only skills this plugin's command,
|
|
134
135
|
// agents and skills reference. `quality-gates` and `software-design` have no
|
|
135
136
|
// reader here; the closure guard's reverse arm rejects an unread entry.
|
|
136
|
-
requires: ['apply-decisions', '
|
|
137
|
+
requires: ['apply-decisions', 'git'],
|
|
137
138
|
rules: [],
|
|
138
139
|
},
|
|
139
140
|
{
|
|
140
141
|
name: 'devflow-resolve',
|
|
141
142
|
description: 'Process and fix code review issues with blast-radius triage, Code agent fixes, and Validate agent verification',
|
|
142
143
|
commands: ['/resolve'],
|
|
143
|
-
agents: ['git', 'triage', 'code', 'simplify', 'validate', 'test', 'knowledge'],
|
|
144
|
-
skills: ['patterns', '
|
|
144
|
+
agents: ['git', 'triage', 'code', 'code-fix', 'simplify', 'validate', 'test', 'knowledge'],
|
|
145
|
+
skills: ['patterns', 'worktree-support', 'feature-knowledge', 'apply-feature-knowledge', 'apply-decisions'],
|
|
145
146
|
requires: [
|
|
146
147
|
'architecture',
|
|
147
|
-
'boundary-validation',
|
|
148
148
|
'complexity',
|
|
149
149
|
'consistency',
|
|
150
150
|
'database',
|
|
151
151
|
'dependencies',
|
|
152
|
-
'dependency-research',
|
|
153
152
|
'documentation',
|
|
154
153
|
'git',
|
|
155
154
|
'performance',
|
|
@@ -157,6 +156,7 @@ export const DEVFLOW_PLUGINS = [
|
|
|
157
156
|
'regression',
|
|
158
157
|
'reliability',
|
|
159
158
|
'review-methodology',
|
|
159
|
+
'security',
|
|
160
160
|
'software-design',
|
|
161
161
|
'test-driven-development',
|
|
162
162
|
'testing',
|
|
@@ -167,8 +167,11 @@ export const DEVFLOW_PLUGINS = [
|
|
|
167
167
|
name: 'devflow-debug',
|
|
168
168
|
description: 'Debugging workflows with competing hypothesis investigation via parallel subagents',
|
|
169
169
|
commands: ['/debug'],
|
|
170
|
-
agents: ['git', 'synthesize', 'simplify', 'knowledge'],
|
|
170
|
+
agents: ['git', 'synthesize', 'simplify', 'knowledge', 'explore', 'code'],
|
|
171
171
|
skills: ['git', 'worktree-support', 'feature-knowledge', 'apply-feature-knowledge'],
|
|
172
|
+
// D-DEBUG-FIX-VIA-CODE: the fix is a Code spawn. Code loads no skill by language or mode
|
|
173
|
+
// (D-NO-RUNTIME-SKILLS), so `requires:` lists only the skills this command, its agents and the
|
|
174
|
+
// skills they preload reference; the closure guard rejects an entry nothing reads.
|
|
172
175
|
requires: [
|
|
173
176
|
'apply-decisions',
|
|
174
177
|
'architecture',
|
|
@@ -176,9 +179,7 @@ export const DEVFLOW_PLUGINS = [
|
|
|
176
179
|
'consistency',
|
|
177
180
|
'database',
|
|
178
181
|
'dependencies',
|
|
179
|
-
'docs-framework',
|
|
180
182
|
'documentation',
|
|
181
|
-
'patterns',
|
|
182
183
|
'performance',
|
|
183
184
|
'regression',
|
|
184
185
|
'reliability',
|
|
@@ -194,23 +195,12 @@ export const DEVFLOW_PLUGINS = [
|
|
|
194
195
|
name: 'devflow-explore',
|
|
195
196
|
description: 'Codebase exploration with structured analysis and optional knowledge base creation',
|
|
196
197
|
commands: ['/explore'],
|
|
197
|
-
|
|
198
|
+
// 'explore' is devflow's override of Claude Code's built-in Explore agent, spawned by
|
|
199
|
+
// type name (D-EXPLORE-OVERRIDE and D-EXPLORE-NO-CLOBBER, targets/claude-code/agent-type-owner.ts).
|
|
200
|
+
agents: ['skim', 'synthesize', 'knowledge', 'explore'],
|
|
198
201
|
skills: ['worktree-support', 'apply-feature-knowledge', 'feature-knowledge'],
|
|
199
202
|
requires: [
|
|
200
203
|
'apply-decisions',
|
|
201
|
-
'architecture',
|
|
202
|
-
'complexity',
|
|
203
|
-
'consistency',
|
|
204
|
-
'database',
|
|
205
|
-
'dependencies',
|
|
206
|
-
'docs-framework',
|
|
207
|
-
'documentation',
|
|
208
|
-
'performance',
|
|
209
|
-
'regression',
|
|
210
|
-
'reliability',
|
|
211
|
-
'review-methodology',
|
|
212
|
-
'security',
|
|
213
|
-
'testing',
|
|
214
204
|
],
|
|
215
205
|
rules: [],
|
|
216
206
|
},
|
|
@@ -220,21 +210,11 @@ export const DEVFLOW_PLUGINS = [
|
|
|
220
210
|
commands: ['/research'],
|
|
221
211
|
agents: ['research', 'skim', 'synthesize', 'knowledge'],
|
|
222
212
|
skills: ['worktree-support', 'apply-feature-knowledge', 'feature-knowledge', 'research-codebase', 'research-external', 'research-market', 'research-competitor', 'research-technology'],
|
|
213
|
+
// `docs-framework` is read: Phase 2 loads it at the step that names the
|
|
214
|
+
// research directory (D-DOCS-NAMES-AUTHORITY).
|
|
223
215
|
requires: [
|
|
224
216
|
'apply-decisions',
|
|
225
|
-
'architecture',
|
|
226
|
-
'complexity',
|
|
227
|
-
'consistency',
|
|
228
|
-
'database',
|
|
229
|
-
'dependencies',
|
|
230
217
|
'docs-framework',
|
|
231
|
-
'documentation',
|
|
232
|
-
'performance',
|
|
233
|
-
'regression',
|
|
234
|
-
'reliability',
|
|
235
|
-
'review-methodology',
|
|
236
|
-
'security',
|
|
237
|
-
'testing',
|
|
238
218
|
],
|
|
239
219
|
rules: [],
|
|
240
220
|
},
|
|
@@ -280,7 +260,6 @@ export const DEVFLOW_PLUGINS = [
|
|
|
280
260
|
'architecture',
|
|
281
261
|
'database',
|
|
282
262
|
'dependencies',
|
|
283
|
-
'docs-framework',
|
|
284
263
|
'documentation',
|
|
285
264
|
'git',
|
|
286
265
|
'performance',
|
|
@@ -293,7 +272,7 @@ export const DEVFLOW_PLUGINS = [
|
|
|
293
272
|
name: 'devflow-ambient',
|
|
294
273
|
description: 'Orchestrator ambient mode — session charter, per-prompt reminder, plan handoff',
|
|
295
274
|
commands: [],
|
|
296
|
-
agents: ['code', 'validate', 'simplify', 'scrutinize', 'evaluate', 'test', 'skim', 'review', 'git', 'synthesize', 'triage', 'design', 'knowledge', 'research', 'learning'],
|
|
275
|
+
agents: ['code', 'code-edit', 'validate', 'simplify', 'scrutinize', 'evaluate', 'test', 'skim', 'review', 'git', 'synthesize', 'triage', 'design', 'knowledge', 'research', 'learning', 'explore'],
|
|
297
276
|
skills: [
|
|
298
277
|
'review-methodology',
|
|
299
278
|
'security',
|
|
@@ -317,9 +296,6 @@ export const DEVFLOW_PLUGINS = [
|
|
|
317
296
|
],
|
|
318
297
|
requires: [
|
|
319
298
|
'apply-decisions',
|
|
320
|
-
'boundary-validation',
|
|
321
|
-
'dependency-research',
|
|
322
|
-
'docs-framework',
|
|
323
299
|
'git',
|
|
324
300
|
'quality-gates',
|
|
325
301
|
'research-codebase',
|
|
@@ -337,22 +313,19 @@ export const DEVFLOW_PLUGINS = [
|
|
|
337
313
|
description: 'Dynamic workflow recipes - dependency-aware tickets→plan→build delivery pipeline',
|
|
338
314
|
// Commands compiled from commands/*.mds at build time (build:mds).
|
|
339
315
|
commands: ['/dynamic-tickets', '/dynamic-plan', '/dynamic-build', '/dynamic-profile'],
|
|
340
|
-
agents: ['code', 'validate', 'simplify', 'scrutinize', 'evaluate', 'test', 'review', 'git', 'synthesize', 'knowledge', 'design'],
|
|
316
|
+
agents: ['code', 'code-fix', 'validate', 'simplify', 'scrutinize', 'evaluate', 'test', 'review', 'git', 'synthesize', 'knowledge', 'design'],
|
|
341
317
|
skills: ['apply-decisions', 'apply-feature-knowledge', 'worktree-support', 'docs-framework'],
|
|
342
318
|
requires: [
|
|
343
319
|
'architecture',
|
|
344
|
-
'boundary-validation',
|
|
345
320
|
'complexity',
|
|
346
321
|
'consistency',
|
|
347
322
|
'database',
|
|
348
323
|
'dependencies',
|
|
349
|
-
'dependency-research',
|
|
350
324
|
'design-review',
|
|
351
325
|
'documentation',
|
|
352
326
|
'feature-knowledge',
|
|
353
327
|
'gap-analysis',
|
|
354
328
|
'git',
|
|
355
|
-
'patterns',
|
|
356
329
|
'performance',
|
|
357
330
|
'qa',
|
|
358
331
|
'quality-gates',
|
|
@@ -485,29 +458,72 @@ export const FEATURE_OWNED_SKILLS = ['compliance'];
|
|
|
485
458
|
/**
|
|
486
459
|
* Rules owned by the feature system — not any plugin in DEVFLOW_PLUGINS.
|
|
487
460
|
* The compliance rule (src/assets/rules/compliance.md) is stamped and installed
|
|
488
|
-
* by convergeComplianceArtifacts, not by the plugin installer.
|
|
461
|
+
* by convergeComplianceArtifacts, not by the plugin installer. The behavior rule
|
|
462
|
+
* (src/assets/rules/behavior.md) is installed and removed by convergeBehaviorRule.
|
|
463
|
+
*
|
|
464
|
+
* D-BEHAVIOR-OPT-IN: the behavior rule is OPT-IN and default off. How agents reply and
|
|
465
|
+
* act is a taste, so no install carries it until the user asks: `features.behavior` in
|
|
466
|
+
* the machine manifest (`devflow init --behavior`, `devflow behavior --enable`). That is
|
|
467
|
+
* why it sits here and in no plugin's `rules` array: a plugin's rules install for every
|
|
468
|
+
* install that selects the plugin, with no switch, and the core plugin is always
|
|
469
|
+
* selected. The rule is one bullet per behavior and stays small, because every session
|
|
470
|
+
* and every subagent that loads the rules pays for it; tests/rules.test.ts pins the
|
|
471
|
+
* shape, the length and this registration.
|
|
489
472
|
*
|
|
490
473
|
* Used by:
|
|
491
474
|
* - rules.ts: union into allRules for shadow/unshadow/list
|
|
492
|
-
* - tests: independent literal ['compliance'] (avoids EXCLUDED-as-oracle trap)
|
|
475
|
+
* - tests: independent literal ['compliance', 'behavior'] (avoids EXCLUDED-as-oracle trap)
|
|
493
476
|
*
|
|
494
477
|
* D-FO-2: FEATURE_OWNED_RULES must be disjoint from getAllRuleNames()
|
|
495
478
|
* (guarded by plugins.test.ts FEATURE_OWNED constants describe block).
|
|
496
479
|
*/
|
|
497
|
-
export const FEATURE_OWNED_RULES = ['compliance'];
|
|
480
|
+
export const FEATURE_OWNED_RULES = ['compliance', 'behavior'];
|
|
481
|
+
/**
|
|
482
|
+
* Skills a learning-off machine does not install.
|
|
483
|
+
*
|
|
484
|
+
* D-LEARNING-VARIANT-INSTALL: the learning-off variants of the commands and
|
|
485
|
+
* agents (D-LEARNING-VARIANTS) carry no decisions text and preload no
|
|
486
|
+
* apply-decisions, so the skill has no reader on a machine with learning off. It
|
|
487
|
+
* stays OWNED and REQUIRED by its plugins in the registry — the closure guard
|
|
488
|
+
* reasons over the learning-on variant, the superset — and the install drops it
|
|
489
|
+
* on top of the selection: `installViaFileCopy` skips it when `learning` is false
|
|
490
|
+
* and `convergeLearningVariants` installs or removes it when the switch flips.
|
|
491
|
+
*
|
|
492
|
+
* This is a machine-switch condition, not a deselection: the plan
|
|
493
|
+
* ({@link resolveSkillInstallPlan}) is untouched, so a learning-off machine never
|
|
494
|
+
* reports the skill as "removed because no selected plugin requires it" nor its
|
|
495
|
+
* shadow as inactive for a plugin that is not selected.
|
|
496
|
+
*
|
|
497
|
+
* Used by:
|
|
498
|
+
* - installer.ts installViaFileCopy: omits these from the install loop when learning is off
|
|
499
|
+
* - learning-install.ts convergeLearningVariants: installs or removes the directory
|
|
500
|
+
* - tests: independent literal ['apply-decisions'] (avoids the EXCLUDED-as-oracle trap)
|
|
501
|
+
*/
|
|
502
|
+
export const LEARNING_GATED_SKILLS = ['apply-decisions'];
|
|
503
|
+
/**
|
|
504
|
+
* A skills map with the learning-gated skills left out when learning is off.
|
|
505
|
+
*
|
|
506
|
+
* Pure: the same map instance comes back when learning is on, a copy otherwise.
|
|
507
|
+
*/
|
|
508
|
+
export function omitLearningGatedSkills(skillsMap, learning) {
|
|
509
|
+
if (learning)
|
|
510
|
+
return skillsMap;
|
|
511
|
+
const gated = LEARNING_GATED_SKILLS;
|
|
512
|
+
return new Map([...skillsMap].filter(([skill]) => !gated.includes(skill)));
|
|
513
|
+
}
|
|
498
514
|
// ── Skill-closure boundaries ──────────────────────────────────────────────────
|
|
499
515
|
/**
|
|
500
516
|
* Skills that are REFERENCED but never REQUIRED — the presence-gated set.
|
|
501
517
|
*
|
|
502
518
|
* D-PRESENCE-GATED: every language/ecosystem skill ships with an optional,
|
|
503
519
|
* command-less plugin, so a reference to one is a reference to something the
|
|
504
|
-
* user may deliberately not have. The referencing prompts are written to
|
|
505
|
-
*
|
|
506
|
-
*
|
|
507
|
-
*
|
|
508
|
-
*
|
|
509
|
-
*
|
|
510
|
-
*
|
|
520
|
+
* user may deliberately not have. The referencing prompts are written to
|
|
521
|
+
* proceed without it: `/code-review` spawns a language focus only when the
|
|
522
|
+
* installer stamped it into the command (D-LANGUAGE-FOCUS-STAMP,
|
|
523
|
+
* {@link installedLanguageFocuses}), and the Review agent continues when the
|
|
524
|
+
* Skill invocation fails. Putting them in a `requires` would reinstate
|
|
525
|
+
* the universal install for exactly the eight skills the selection prompt
|
|
526
|
+
* exists to let a user decline (AC-25).
|
|
511
527
|
*
|
|
512
528
|
* DERIVED from the registry rather than hand-listed: a ninth language plugin is
|
|
513
529
|
* presence-gated by being declared, with no second roster to remember. Guarded
|
|
@@ -545,7 +561,7 @@ export const TEMPLATE_SKILL_REFS = [
|
|
|
545
561
|
},
|
|
546
562
|
{
|
|
547
563
|
literal: 'devflow:{FOCUS}',
|
|
548
|
-
site: 'src/assets/agents/review.
|
|
564
|
+
site: 'src/assets/agents/review.mds (the Review agent loading its own focus skill)',
|
|
549
565
|
why: 'receiving half of the same substitution — the agent is told which focus it is, not which skill exists',
|
|
550
566
|
},
|
|
551
567
|
];
|
|
@@ -733,6 +749,29 @@ export function buildScopedSkillsMap(plugins) {
|
|
|
733
749
|
}
|
|
734
750
|
return skillsMap;
|
|
735
751
|
}
|
|
752
|
+
/**
|
|
753
|
+
* The language focuses an install selection makes available — the list the
|
|
754
|
+
* installer stamps into the installed /code-review command.
|
|
755
|
+
*
|
|
756
|
+
* D-LANGUAGE-FOCUS-STAMP: the language gate moved from a run-time `test -f`
|
|
757
|
+
* probe of Claude Code's directory to this list, computed once at install time.
|
|
758
|
+
* Pure plumbing and nothing more: the registry's {@link PRESENCE_GATED_SKILLS}
|
|
759
|
+
* filtered to the skills the selection's closure installs
|
|
760
|
+
* ({@link buildScopedSkillsMap}), in registry order. Which focuses a diff gets
|
|
761
|
+
* stays a prompt rule that the orchestrator executes; no code here, or anywhere
|
|
762
|
+
* in the installer, classifies a diff or chooses a focus.
|
|
763
|
+
*
|
|
764
|
+
* The selection is the EFFECTIVE one (`FileCopyOptions.effectivePlugins`), never
|
|
765
|
+
* the plugins one run copies: `--plugin=X` installs X alone while the machine's
|
|
766
|
+
* selection is the manifest's plugins plus X, and the stamp has to describe what
|
|
767
|
+
* is on disk. Selective uninstall passes the plugins that remain.
|
|
768
|
+
*
|
|
769
|
+
* @param effectivePlugins - The plugins whose skill closure is, or stays, installed.
|
|
770
|
+
*/
|
|
771
|
+
export function installedLanguageFocuses(effectivePlugins) {
|
|
772
|
+
const installed = buildScopedSkillsMap(effectivePlugins);
|
|
773
|
+
return PRESENCE_GATED_SKILLS.filter(skill => installed.has(skill));
|
|
774
|
+
}
|
|
736
775
|
/**
|
|
737
776
|
* Build a skills map over the WHOLE registry.
|
|
738
777
|
*
|
|
@@ -131,8 +131,4 @@ export function getDesignDir(projectRoot) {
|
|
|
131
131
|
export function getResearchDir(projectRoot) {
|
|
132
132
|
return path.join(projectRoot, '.devflow', 'docs', 'research');
|
|
133
133
|
}
|
|
134
|
-
/** .devflow/docs/handoff-{branchSlug}.md — Code agent phase handoff artifact */
|
|
135
|
-
export function getHandoffPath(projectRoot, branchSlug) {
|
|
136
|
-
return path.join(projectRoot, '.devflow', 'docs', `handoff-${branchSlug}.md`);
|
|
137
|
-
}
|
|
138
134
|
//# sourceMappingURL=project-paths.js.map
|
package/dist/core/proxy-log.js
CHANGED
|
@@ -34,7 +34,7 @@ export const PROXY_LOG_TAIL_BYTES = 1_048_576;
|
|
|
34
34
|
* XDG_CONFIG_HOME (user-config lookup, reached only on an implicit config load —
|
|
35
35
|
* see D-EFR-6 in model-discovery.ts). CI is read only by `init`; CODEX_HOME and
|
|
36
36
|
* CLAUDE_CONFIG_DIR only by the Codex ingress, `init` and the Codex doctor, none of
|
|
37
|
-
* which devflow enables or invokes. Verified by whole-dist grep of the 0.
|
|
37
|
+
* which devflow enables or invokes. Verified by whole-dist grep of the 0.6.0
|
|
38
38
|
* package. An allowlist is the correct shape: 61 inherited vars → 6.
|
|
39
39
|
*
|
|
40
40
|
* HOME is retained: the runtime's loadConfig resolves ~ paths via homedir().
|
package/dist/core/proxy-state.js
CHANGED
|
@@ -91,7 +91,7 @@ export async function writeProxyState(devflowDir, state) {
|
|
|
91
91
|
* Top-level keys devflow carries into the routing config. Unknown top-level keys
|
|
92
92
|
* cause a hard relay startup error — never emit them.
|
|
93
93
|
*
|
|
94
|
-
* @D-EFR-4 Subswitch 0.
|
|
94
|
+
* @D-EFR-4 Subswitch 0.6.0 routing config contract:
|
|
95
95
|
* FileConfigSchema is a z.strictObject with exactly 6 accepted top-level keys:
|
|
96
96
|
* port, logLevel, anthropic, providers, limits, codexIngress. Unknown keys cause a
|
|
97
97
|
* hard startup error — the relay refuses to start. anthropic and limits are
|
package/dist/core/tracker.js
CHANGED
|
@@ -60,6 +60,44 @@ export const TRACKER_PROVIDER_IDS = TRACKER_PROVIDERS.map(p => p.id);
|
|
|
60
60
|
*/
|
|
61
61
|
export const DEFAULT_TRACKER_PROVIDER = 'github';
|
|
62
62
|
// ---------------------------------------------------------------------------
|
|
63
|
+
// Tracker tool servers — the allowlist half of the Git and Tracker agents
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
/**
|
|
66
|
+
* D-TRACKER-SERVER-ALLOWLIST: the Git and Tracker agents hold a tool ALLOWLIST, and the
|
|
67
|
+
* tracker tool servers a user has connected differ per machine, so the shipped allowlist
|
|
68
|
+
* names no server (the agent sources stay vendor-neutral). The installer stamps one
|
|
69
|
+
* whole-server entry per name below onto the INSTALLED `tools:` line of those two agents
|
|
70
|
+
* (`stampAgentTools`, src/core/agent-frontmatter.ts), after the file is copied. Claude Code
|
|
71
|
+
* has no pattern form for an allowlist entry, so a server is granted by its name; a name
|
|
72
|
+
* that matches no connected server is inert (it grants nothing and blocks nothing).
|
|
73
|
+
*
|
|
74
|
+
* The default is one FLAT list, stamped whatever the provider: every install carries every
|
|
75
|
+
* provider, and a repository may select a provider other than the machine's, so a list
|
|
76
|
+
* keyed on the machine's provider would strand that repository. A server the user runs
|
|
77
|
+
* under another name is added with `devflow tracker --servers`. A wrong or missing name
|
|
78
|
+
* does not fail silently: the agent finds no tool for the capability it needs and reports
|
|
79
|
+
* `TRACEABILITY: DEGRADED (no tracker tool for {capability})`.
|
|
80
|
+
*
|
|
81
|
+
* The default leaves `github` out. Under the github provider the Git agent uses `gh` and
|
|
82
|
+
* never reads `_mcp.md`, so a stamped `github` server is never used by a tracker operation;
|
|
83
|
+
* under jira or linear, a connected GitHub server that also advertises issue creation would
|
|
84
|
+
* make the `_mcp.md` capability selection ambiguous, which is a degraded run. A user who
|
|
85
|
+
* wants it adds it with `devflow tracker --servers`.
|
|
86
|
+
*/
|
|
87
|
+
export const TRACKER_MCP_SERVERS_DEFAULT = Object.freeze([
|
|
88
|
+
'atlassian',
|
|
89
|
+
'jira',
|
|
90
|
+
'claude_ai_Atlassian',
|
|
91
|
+
'linear',
|
|
92
|
+
'claude_ai_Linear',
|
|
93
|
+
]);
|
|
94
|
+
/** A server name as a user may configure it. Byte-exact, like a provider token. */
|
|
95
|
+
export const TRACKER_SERVER_NAME_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
96
|
+
/** The most servers one list may hold; every entry lands in a prompt-adjacent frontmatter line. */
|
|
97
|
+
export const TRACKER_SERVERS_MAX = 32;
|
|
98
|
+
/** The reserved word that returns the setting to {@link TRACKER_MCP_SERVERS_DEFAULT}. */
|
|
99
|
+
export const TRACKER_SERVERS_DEFAULT_WORD = 'default';
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
63
101
|
// Artifact basenames — one spelling for every TypeScript reader
|
|
64
102
|
//
|
|
65
103
|
// NOT the only spelling in the repository, and a rename that assumes it is will
|
|
@@ -238,6 +276,72 @@ export function parseTrackerId(input) {
|
|
|
238
276
|
}
|
|
239
277
|
return { ok: true, value: input };
|
|
240
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* Validate a list of tracker server names. The one rule set behind both the CLI argument
|
|
281
|
+
* and the manifest field.
|
|
282
|
+
*
|
|
283
|
+
* REJECT, NEVER REPAIR (as {@link parseTrackerId}): a name is accepted byte-exact against
|
|
284
|
+
* {@link TRACKER_SERVER_NAME_RE} and must not hold `__`, which is what separates a server
|
|
285
|
+
* from its tool in an entry such as `mcp__server__tool`. No trim, no case folding, no
|
|
286
|
+
* alias. Exact duplicates collapse to the first occurrence and the order is kept. The list
|
|
287
|
+
* is non-empty and holds at most {@link TRACKER_SERVERS_MAX} distinct names.
|
|
288
|
+
*/
|
|
289
|
+
export function validateTrackerServers(raw) {
|
|
290
|
+
if (raw.length === 0) {
|
|
291
|
+
return { ok: false, error: 'No tracker servers given. Pass one or more server names, or "default".' };
|
|
292
|
+
}
|
|
293
|
+
const seen = new Set();
|
|
294
|
+
for (const entry of raw) {
|
|
295
|
+
if (typeof entry !== 'string' || !TRACKER_SERVER_NAME_RE.test(entry)) {
|
|
296
|
+
return {
|
|
297
|
+
ok: false,
|
|
298
|
+
error: `Invalid tracker server name: "${describeTrackerValue(entry)}". ` +
|
|
299
|
+
'Names are 1-64 characters from A-Z, a-z, 0-9, "_" and "-".',
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
if (entry.includes('__')) {
|
|
303
|
+
return {
|
|
304
|
+
ok: false,
|
|
305
|
+
error: `Invalid tracker server name: "${describeTrackerValue(entry)}". ` +
|
|
306
|
+
'A name must not contain "__" (it separates a server from its tool).',
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
seen.add(entry);
|
|
310
|
+
}
|
|
311
|
+
if (seen.size > TRACKER_SERVERS_MAX) {
|
|
312
|
+
return { ok: false, error: `Too many tracker servers: ${seen.size} (at most ${TRACKER_SERVERS_MAX}).` };
|
|
313
|
+
}
|
|
314
|
+
return { ok: true, value: [...seen] };
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Strict boundary parser for `devflow tracker --servers <list>`.
|
|
318
|
+
*
|
|
319
|
+
* `default` alone selects {@link TRACKER_MCP_SERVERS_DEFAULT}; anything else is a
|
|
320
|
+
* comma-separated list of names handed to {@link validateTrackerServers} unchanged. An
|
|
321
|
+
* empty argument, an empty item (`a,,b`, a trailing comma) and the reserved word inside a
|
|
322
|
+
* list are errors, never silently dropped.
|
|
323
|
+
*/
|
|
324
|
+
export function parseTrackerServers(input) {
|
|
325
|
+
if (input === '') {
|
|
326
|
+
return { ok: false, error: 'Missing tracker servers. Pass a comma-separated list of names, or "default".' };
|
|
327
|
+
}
|
|
328
|
+
if (input === TRACKER_SERVERS_DEFAULT_WORD)
|
|
329
|
+
return { ok: true, value: { kind: 'default' } };
|
|
330
|
+
const items = input.split(',');
|
|
331
|
+
if (items.includes(TRACKER_SERVERS_DEFAULT_WORD)) {
|
|
332
|
+
return { ok: false, error: `"${TRACKER_SERVERS_DEFAULT_WORD}" is reserved: pass it alone, not inside a list.` };
|
|
333
|
+
}
|
|
334
|
+
const validated = validateTrackerServers(items);
|
|
335
|
+
return validated.ok ? { ok: true, value: { kind: 'list', servers: validated.value } } : validated;
|
|
336
|
+
}
|
|
337
|
+
/** The servers in force for `state`: its own list, else the default. */
|
|
338
|
+
export function effectiveTrackerServers(state) {
|
|
339
|
+
return state.servers ?? TRACKER_MCP_SERVERS_DEFAULT;
|
|
340
|
+
}
|
|
341
|
+
/** The whole-server allowlist entries for `servers`, in order: `github` becomes `mcp__github`. */
|
|
342
|
+
export function trackerServerTools(servers) {
|
|
343
|
+
return servers.map(name => `mcp__${name}`);
|
|
344
|
+
}
|
|
241
345
|
/**
|
|
242
346
|
* Tolerant sink normaliser for a raw `manifest.features.tracker` value.
|
|
243
347
|
*
|
|
@@ -249,9 +353,11 @@ export function parseTrackerId(input) {
|
|
|
249
353
|
* D-TRACKER-SELF-HEAL [DR-26]: self-healing here is SILENT and emits no
|
|
250
354
|
* DEGRADED — that is the correct self-heal behaviour, and it is a different
|
|
251
355
|
* condition from a per-repo config value outside the domain (which does emit
|
|
252
|
-
* `unknown tracker provider`). The two must not be conflated.
|
|
356
|
+
* `unknown tracker provider`). The two must not be conflated. The one exception is
|
|
357
|
+
* `servers` (see the body): a present but invalid list heals to the default AND reaches
|
|
358
|
+
* `onWarning` when a caller supplies one, because the user wrote that list on purpose.
|
|
253
359
|
*/
|
|
254
|
-
export function normalizeTrackerFeature(raw) {
|
|
360
|
+
export function normalizeTrackerFeature(raw, onWarning) {
|
|
255
361
|
const DEFAULT = { provider: DEFAULT_TRACKER_PROVIDER };
|
|
256
362
|
if (raw === null || raw === undefined || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
257
363
|
return DEFAULT;
|
|
@@ -259,6 +365,18 @@ export function normalizeTrackerFeature(raw) {
|
|
|
259
365
|
const obj = raw;
|
|
260
366
|
if (!isTrackerProvider(obj.provider))
|
|
261
367
|
return DEFAULT;
|
|
368
|
+
// `servers`: absent is the default, silently. A present value that is not a valid list is
|
|
369
|
+
// dropped WHOLE (never trimmed to its valid names) and reported through `onWarning`, which a
|
|
370
|
+
// caller with a terminal passes; the reader itself has no output channel. The state then
|
|
371
|
+
// reads as the default list, and the next `devflow tracker --servers` or `devflow init`
|
|
372
|
+
// writes the manifest without the bad value.
|
|
373
|
+
if (obj.servers === undefined)
|
|
374
|
+
return { provider: obj.provider };
|
|
375
|
+
const servers = Array.isArray(obj.servers) ? validateTrackerServers(obj.servers) : undefined;
|
|
376
|
+
if (servers?.ok === true)
|
|
377
|
+
return { provider: obj.provider, servers: servers.value };
|
|
378
|
+
onWarning?.(`The manifest's tracker servers setting is not a valid list (${servers?.ok === false ? servers.error : 'not a list'}); ` +
|
|
379
|
+
'using the default. Run `devflow tracker --servers <names>` to set it, or `devflow tracker --servers default`.');
|
|
262
380
|
return { provider: obj.provider };
|
|
263
381
|
}
|
|
264
382
|
// ---------------------------------------------------------------------------
|