devflow-kit 3.6.0 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +438 -1
- package/README.md +15 -11
- package/dist/agents/code.md +9 -15
- package/dist/agents/design.md +1 -1
- package/dist/agents/fix.md +11 -13
- package/dist/agents/git.md +1 -1
- package/dist/agents/harden.md +1 -1
- package/dist/agents/refactor.md +7 -10
- package/dist/agents/review.md +6 -4
- package/dist/agents/skim.md +2 -2
- package/dist/agents/triage.md +2 -2
- package/dist/cli/commands/capture.js +1 -1
- package/dist/cli/commands/curation-move-io.js +102 -0
- package/dist/cli/commands/curation-move-step.js +374 -0
- package/dist/cli/commands/{learning.js → curation.js} +302 -99
- package/dist/cli/commands/gate-level-prompts.js +426 -0
- package/dist/cli/commands/gates.js +299 -0
- package/dist/cli/commands/init-seed.js +16 -5
- package/dist/cli/commands/init.js +263 -54
- package/dist/cli/commands/memory.js +20 -2
- package/dist/cli/commands/prompt-io.js +37 -0
- package/dist/cli/commands/uninstall.js +81 -9
- package/dist/cli.js +4 -2
- package/dist/commands/bug-analysis.md +25 -36
- package/dist/commands/code-review.md +77 -73
- package/dist/commands/debug.md +5 -5
- package/dist/commands/dynamic-build.md +76 -83
- package/dist/commands/dynamic-plan.md +5 -5
- package/dist/commands/dynamic-profile.md +5 -5
- package/dist/commands/dynamic-tickets.md +5 -5
- package/dist/commands/explore.md +6 -6
- package/dist/commands/implement.md +68 -102
- package/dist/commands/plan.md +19 -29
- package/dist/commands/release.md +5 -5
- package/dist/commands/research.md +6 -6
- package/dist/commands/resolve.md +29 -31
- package/dist/commands/self-review.md +5 -13
- package/dist/core/assets.js +20 -20
- package/dist/core/curate-tuning-config.js +5 -6
- package/dist/core/curation-move-notice.js +84 -0
- package/dist/core/curation-move-skip.js +36 -0
- package/dist/core/curation-move.js +35 -0
- package/dist/core/curation-queue-cleanup.js +134 -0
- package/dist/core/curation-store.js +98 -0
- package/dist/core/{learning-variants.js → curation-variants.js} +65 -41
- package/dist/core/echo-value.js +48 -0
- package/dist/core/evidence-policy.js +18 -6
- package/dist/core/feature-switch.js +95 -19
- package/dist/core/fs-atomic.js +1 -1
- package/dist/core/gate-level.js +221 -0
- package/dist/core/git.js +16 -14
- package/dist/core/ledger-root.js +82 -22
- package/dist/core/linked-path.js +4 -4
- package/dist/core/manifest-lock.js +238 -0
- package/dist/core/manifest.js +84 -24
- package/dist/core/migrations.js +1 -13
- package/dist/core/model-discovery.js +7 -1
- package/dist/core/observations.js +2 -2
- package/dist/core/plugins.js +15 -15
- package/dist/core/pool.js +26 -0
- package/dist/core/project-paths.js +103 -34
- package/dist/core/queue-drain.js +2 -2
- package/dist/core/tracked-areas.js +35 -0
- package/dist/core/tracker.js +6 -34
- package/dist/{learning-off → curation-off}/agents/code.md +9 -15
- package/dist/{learning-off → curation-off}/agents/fix.md +11 -13
- package/dist/{learning-off → curation-off}/agents/refactor.md +7 -10
- package/dist/{learning-off → curation-off}/agents/review.md +5 -3
- package/dist/{learning-off → curation-off}/agents/triage.md +1 -1
- package/dist/{learning-off → curation-off}/commands/bug-analysis.md +20 -31
- package/dist/{learning-off → curation-off}/commands/code-review.md +74 -70
- package/dist/{learning-off → curation-off}/commands/debug.md +2 -2
- package/dist/{learning-off → curation-off}/commands/dynamic-build.md +73 -80
- package/dist/{learning-off → curation-off}/commands/explore.md +2 -2
- package/dist/{learning-off → curation-off}/commands/implement.md +65 -99
- package/dist/{learning-off → curation-off}/commands/plan.md +15 -25
- package/dist/{learning-off → curation-off}/commands/resolve.md +26 -28
- package/dist/{learning-off → curation-off}/commands/self-review.md +2 -10
- package/dist/hud/components/{learning-counts.js → curation-counts.js} +36 -17
- package/dist/hud/config.js +1 -1
- package/dist/hud/index.js +6 -6
- package/dist/hud/render.js +3 -3
- package/dist/skills/git/references/pr/validate-branch.md +8 -5
- package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +20 -14
- package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +20 -20
- package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +20 -20
- package/dist/targets/claude-code/{learning-install.js → curation-install.js} +99 -67
- package/dist/targets/claude-code/installer.js +15 -15
- package/dist/targets/claude-code/language-stamp.js +5 -5
- package/dist/targets/claude-code/post-install.js +2 -2
- package/dist/targets/claude-code/tracker-servers.js +1 -1
- package/package.json +3 -2
- package/src/assets/agents/_partials/_code.mds +16 -17
- package/src/assets/agents/code.mds +4 -7
- package/src/assets/agents/curate.md +12 -14
- package/src/assets/agents/debug.mds +6 -6
- package/src/assets/agents/design.mds +18 -18
- package/src/assets/agents/fix.mds +6 -5
- package/src/assets/agents/git.mds +1 -1
- package/src/assets/agents/harden.mds +7 -7
- package/src/assets/agents/knowledge.mds +23 -23
- package/src/assets/agents/refactor.mds +2 -2
- package/src/assets/agents/research.mds +15 -15
- package/src/assets/agents/review.mds +45 -43
- package/src/assets/agents/skim.mds +11 -11
- package/src/assets/agents/synthesize.md +2 -2
- package/src/assets/agents/triage.mds +22 -22
- package/src/assets/agents/validate.md +13 -26
- package/src/assets/commands/_partials/_decisions.mds +13 -13
- package/src/assets/commands/_partials/_engine.mds +8 -8
- package/src/assets/commands/_partials/_knowledge.mds +29 -15
- package/src/assets/commands/_partials/_preamble.mds +4 -4
- package/src/assets/commands/_partials/_settings.mds +3 -3
- package/src/assets/commands/_partials/_wave.mds +17 -24
- package/src/assets/commands/bug-analysis.mds +37 -48
- package/src/assets/commands/code-review.mds +90 -86
- package/src/assets/commands/debug.mds +14 -14
- package/src/assets/commands/dynamic-build.mds +78 -78
- package/src/assets/commands/dynamic-plan.mds +22 -22
- package/src/assets/commands/dynamic-profile.mds +2 -2
- package/src/assets/commands/dynamic-tickets.mds +8 -8
- package/src/assets/commands/explore.mds +20 -20
- package/src/assets/commands/implement.mds +92 -118
- package/src/assets/commands/plan.mds +41 -51
- package/src/assets/commands/release.mds +12 -12
- package/src/assets/commands/research.mds +19 -19
- package/src/assets/commands/resolve.mds +56 -50
- package/src/assets/commands/self-review.mds +20 -20
- package/src/assets/mds/git/_ops.mds +3 -1
- package/src/assets/mds/git/_ops_pr.mds +1 -1
- package/src/assets/mds/git/_ops_steps.mds +13 -7
- package/src/assets/mds/git/_pr.mds +7 -4
- package/src/assets/mds/tracker/_common.mds +23 -12
- package/src/assets/mds/tracker/_github.mds +2 -9
- package/src/assets/mds/tracker/_jira.mds +2 -15
- package/src/assets/mds/tracker/_linear.mds +2 -15
- package/src/assets/rules/quality.md +1 -0
- package/src/assets/scripts/ci-wait.cjs +22 -4
- package/src/assets/scripts/claude-md-audit.cjs +66 -51
- package/src/assets/scripts/hooks/background-memory-update +406 -97
- package/src/assets/scripts/hooks/capture-prompt +12 -12
- package/src/assets/scripts/hooks/capture-question +11 -11
- package/src/assets/scripts/hooks/capture-turn +12 -12
- package/src/assets/scripts/hooks/{learning-lock → curation-lock} +2 -2
- package/src/assets/scripts/hooks/curation-move +293 -0
- package/src/assets/scripts/hooks/ensure-devflow-init +45 -13
- package/src/assets/scripts/hooks/ensure-proxy +4 -4
- package/src/assets/scripts/hooks/ensure-root-gitignore +4 -4
- package/src/assets/scripts/hooks/git-marker +81 -0
- package/src/assets/scripts/hooks/json-helper.cjs +145 -51
- package/src/assets/scripts/hooks/json-parse +19 -4
- package/src/assets/scripts/hooks/lib/curation-move.cjs +1582 -0
- package/src/assets/scripts/hooks/lib/{learning-store.cjs → curation-store.cjs} +242 -118
- package/src/assets/scripts/hooks/lib/decisions-format.cjs +3 -3
- package/src/assets/scripts/hooks/lib/mkdir-lock.cjs +24 -7
- package/src/assets/scripts/hooks/lib/project-paths.cjs +132 -39
- package/src/assets/scripts/hooks/lib/render-decisions.cjs +34 -22
- package/src/assets/scripts/hooks/lib/tracked-areas.cjs +259 -0
- package/src/assets/scripts/hooks/memory-permission +358 -0
- package/src/assets/scripts/hooks/memory-worker +1 -1
- package/src/assets/scripts/hooks/pre-compact-memory +6 -16
- package/src/assets/scripts/hooks/queue-append +228 -103
- package/src/assets/scripts/hooks/resolve-project-root +2 -2
- package/src/assets/scripts/hooks/session-start-context +145 -71
- package/src/assets/scripts/hooks/session-start-memory +27 -46
- package/src/assets/scripts/lib/project-config.cjs +31 -9
- package/src/assets/scripts/resolve-base.cjs +1043 -0
- package/src/assets/scripts/resolve-settings.cjs +238 -46
- package/src/assets/skills/agent-references/SKILL.md +9 -2
- package/src/assets/skills/agent-references/references/commands/code-review-levels.md +19 -0
- package/src/assets/skills/agent-references/references/commands/implement-levels.md +27 -0
- package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +6 -4
- package/src/assets/skills/agent-references/references/commands/plan-levels.md +40 -0
- package/src/assets/skills/agent-references/references/commands/resolve-levels.md +24 -0
- package/src/assets/skills/agent-references/references/synthesize/planning.md +9 -22
- package/src/assets/skills/agent-references/references/synthesize/review.md +11 -11
- package/src/assets/skills/apply-decisions/SKILL.md +1 -1
- package/src/assets/skills/docs-framework/SKILL.md +7 -7
- package/src/assets/skills/docs-framework/references/patterns.md +3 -4
- package/src/assets/skills/quality-gates/SKILL.md +1 -1
- package/src/assets/skills/worktree-support/references/roots.md +2 -2
- package/templates/lint-pack/.lint-pack.conf +86 -0
- package/templates/lint-pack/README.md +190 -0
- package/templates/lint-pack/lint-pack.sh +905 -0
- package/dist/core/learning-queue-cleanup.js +0 -27
- package/dist/core/learning-store.js +0 -61
- /package/dist/{learning-off → curation-off}/agents/debug.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/design.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/harden.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/knowledge.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/research.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/skim.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/dynamic-plan.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/dynamic-profile.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/dynamic-tickets.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/release.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/research.md +0 -0
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Curation-variant installer for the Claude Code target.
|
|
3
3
|
*
|
|
4
|
-
* D-LEARNING-VARIANT-INSTALL: the install follows the machine's
|
|
5
|
-
* (`features.
|
|
6
|
-
* switch is off, every command and agent that has a
|
|
7
|
-
* (dist/
|
|
4
|
+
* D-LEARNING-VARIANT-INSTALL: the install follows the machine's curation switch
|
|
5
|
+
* (`features.curation` in ~/.devflow/manifest.json) and nothing else. When the
|
|
6
|
+
* switch is off, every command and agent that has a curation-off variant
|
|
7
|
+
* (dist/curation-off/{commands,agents}, built by D-LEARNING-VARIANTS) is installed
|
|
8
8
|
* from it, and the apply-decisions skill is not installed, so the decisions text
|
|
9
9
|
* reaches no prompt and the skill has no reader. When the switch is on, the
|
|
10
|
-
*
|
|
10
|
+
* curation-on files and the skill are installed. Three pieces carry it:
|
|
11
11
|
*
|
|
12
12
|
* - the source order (src/core/assets.ts commandSourceDirs / agentSourceDirs):
|
|
13
|
-
* with
|
|
13
|
+
* with curation off the curation-off directory is consulted first, then the
|
|
14
14
|
* normal order, so a host with no arm installs its one file as before;
|
|
15
|
-
* - the skill condition (
|
|
16
|
-
* installViaFileCopy leaves the skill out when
|
|
17
|
-
* - {@link
|
|
15
|
+
* - the skill condition (CURATION_GATED_SKILLS in src/core/plugins.ts):
|
|
16
|
+
* installViaFileCopy leaves the skill out when curation is off;
|
|
17
|
+
* - {@link convergeCurationVariants}, below: the converge that makes an
|
|
18
18
|
* ALREADY-installed tree match the switch, run by `devflow init` after the
|
|
19
|
-
* file copy and by `devflow
|
|
20
|
-
* written ({@link
|
|
19
|
+
* file copy and by `devflow curation --enable/--disable` after the switch is
|
|
20
|
+
* written ({@link applyCurationToggle}).
|
|
21
21
|
*
|
|
22
22
|
* The converge, decided in turn:
|
|
23
|
-
* - Its roster is the files that exist under dist/
|
|
23
|
+
* - Its roster is the files that exist under dist/curation-off, not a list typed
|
|
24
24
|
* here: the build owns which hosts have an arm, so a new arm is converged with
|
|
25
25
|
* no edit to this file.
|
|
26
26
|
* - It rewrites only files that are ALREADY installed. A `--plugin` install
|
|
@@ -42,41 +42,42 @@
|
|
|
42
42
|
* the skill is resolved through the installer's own resolveSkillSource. Only
|
|
43
43
|
* skills and rules have shadows; commands and agents have none, so there is
|
|
44
44
|
* nothing for an off variant to collide with. A shadow of apply-decisions
|
|
45
|
-
* under
|
|
45
|
+
* under curation off is DORMANT in the same sense as one for a deselected
|
|
46
46
|
* skill: kept in ~/.devflow/skills, never installed, never deleted, and
|
|
47
|
-
* applied again the moment
|
|
47
|
+
* applied again the moment curation comes back on.
|
|
48
48
|
* - Version skew: the variants in this package were built with this version.
|
|
49
49
|
* When the manifest records another version, the installed files are not the
|
|
50
|
-
* ones this package would rewrite, so {@link
|
|
50
|
+
* ones this package would rewrite, so {@link applyCurationToggle} skips the
|
|
51
51
|
* converge and says to run `devflow init`.
|
|
52
52
|
* - An agent's installed `model:` and `effort:` are carried into the variant before
|
|
53
53
|
* the byte comparison (D-AGENT-OVERRIDE-CARRY, see {@link withInstalledState}),
|
|
54
54
|
* so the overrides `devflow agents` and the proxy put there are never written
|
|
55
55
|
* back to the shipped values and a no-op converge writes no agent.
|
|
56
|
-
* {@link
|
|
56
|
+
* {@link applyCurationToggle} still runs reapplyAgentMapping straight after a
|
|
57
57
|
* converge that rewrote an agent: it reads agent-models.json and is the authority.
|
|
58
58
|
*
|
|
59
59
|
* D-LEARNING-PRELOAD-MACHINE-ONLY (amended): the apply-decisions preload follows
|
|
60
60
|
* the machine switch only, never a repository's narrowing, because a repository
|
|
61
|
-
* can narrow
|
|
62
|
-
* machine-wide. Met by the variant: the
|
|
63
|
-
* the skill (no install-time frontmatter rewrite exists), and the
|
|
61
|
+
* can narrow curation off on a machine where it is on and the installed agents are
|
|
62
|
+
* machine-wide. Met by the variant: the curation-off agent files do not preload
|
|
63
|
+
* the skill (no install-time frontmatter rewrite exists), and the curation-on files
|
|
64
64
|
* keep the preload and their run-time gate for a narrowed repository. A repo
|
|
65
|
-
* `project.json` with `
|
|
65
|
+
* `project.json` with `curation: false` on a curation-on machine therefore changes
|
|
66
66
|
* nothing installed.
|
|
67
67
|
*
|
|
68
68
|
* I/O orchestration in src/targets/; the pure selection rules stay in src/core/.
|
|
69
69
|
*/
|
|
70
70
|
import { promises as fs } from 'fs';
|
|
71
71
|
import * as path from 'path';
|
|
72
|
-
import { agentSourceDirs, commandSourceDirs,
|
|
72
|
+
import { agentSourceDirs, commandSourceDirs, curationOffDir, } from '../../core/assets.js';
|
|
73
73
|
import { carryStampedTools } from '../../core/agent-frontmatter.js';
|
|
74
74
|
import { carryAgentOverrides, reapplyAgentMapping } from '../../core/agent-models.js';
|
|
75
|
+
import { describeEchoedValue } from '../../core/echo-value.js';
|
|
75
76
|
import { writeFileAtomicExclusive } from '../../core/fs-atomic.js';
|
|
76
77
|
import { readManifest } from '../../core/manifest.js';
|
|
77
78
|
import { getPackageRoot } from '../../core/paths.js';
|
|
78
79
|
import { isProxyEnabled } from '../../core/proxy-state.js';
|
|
79
|
-
import { DEVFLOW_PLUGINS,
|
|
80
|
+
import { DEVFLOW_PLUGINS, CURATION_GATED_SKILLS, installedLanguageFocuses, prefixSkillName, skillsOf, } from '../../core/plugins.js';
|
|
80
81
|
import { copyDirectory, resolveSkillSource } from './installer.js';
|
|
81
82
|
import { LANGUAGE_STAMPED_COMMANDS, stampForConverge } from './language-stamp.js';
|
|
82
83
|
// ── Bounds ─────────────────────────────────────────────────────────────────
|
|
@@ -85,7 +86,7 @@ import { LANGUAGE_STAMPED_COMMANDS, stampForConverge } from './language-stamp.js
|
|
|
85
86
|
* 9 agents; the bound exists so a directory that grew without limit cannot turn the
|
|
86
87
|
* converge into an unbounded loop (every loop has an explicit bound).
|
|
87
88
|
*/
|
|
88
|
-
export const
|
|
89
|
+
export const MAX_CURATION_ROSTER = 256;
|
|
89
90
|
/** Deepest skill-directory descent the tree comparison takes. */
|
|
90
91
|
const MAX_SKILL_TREE_DEPTH = 4;
|
|
91
92
|
/** A roster entry is a flat, lowercase, hyphenated markdown basename. */
|
|
@@ -95,12 +96,12 @@ const KINDS = ['commands', 'agents'];
|
|
|
95
96
|
function installedFile(claudeDir, kind, fileName) {
|
|
96
97
|
return path.join(claudeDir, kind, 'devflow', fileName);
|
|
97
98
|
}
|
|
98
|
-
/** The
|
|
99
|
+
/** The curation-ON source directories for a kind, most-preferred first. */
|
|
99
100
|
function onSourceDirs(kind, root) {
|
|
100
101
|
return kind === 'commands' ? commandSourceDirs(true, root) : agentSourceDirs(root, true);
|
|
101
102
|
}
|
|
102
103
|
/**
|
|
103
|
-
* The roster of one kind: the `.md` files under dist/
|
|
104
|
+
* The roster of one kind: the `.md` files under dist/curation-off/<kind>, sorted.
|
|
104
105
|
*
|
|
105
106
|
* `present` is false when the directory does not exist (the build has not run, or
|
|
106
107
|
* only `build:cli` did), so the caller can say so instead of reporting a converge
|
|
@@ -109,18 +110,18 @@ function onSourceDirs(kind, root) {
|
|
|
109
110
|
async function readRoster(kind, root, warn) {
|
|
110
111
|
let entries;
|
|
111
112
|
try {
|
|
112
|
-
entries = await fs.readdir(
|
|
113
|
+
entries = await fs.readdir(curationOffDir(kind, root));
|
|
113
114
|
}
|
|
114
115
|
catch (err) {
|
|
115
116
|
if (err.code === 'ENOENT')
|
|
116
117
|
return { names: [], present: false };
|
|
117
|
-
warn(`
|
|
118
|
+
warn(`curation variants: cannot read the ${kind} variants — ${String(err)}`);
|
|
118
119
|
return { names: [], present: false };
|
|
119
120
|
}
|
|
120
121
|
const names = entries.filter(entry => ROSTER_NAME_RE.test(entry)).sort();
|
|
121
|
-
if (names.length >
|
|
122
|
-
warn(`
|
|
123
|
-
return { names: names.slice(0,
|
|
122
|
+
if (names.length > MAX_CURATION_ROSTER) {
|
|
123
|
+
warn(`curation variants: ${names.length} ${kind} variants exceed the bound of ${MAX_CURATION_ROSTER}; converging the first ${MAX_CURATION_ROSTER}`);
|
|
124
|
+
return { names: names.slice(0, MAX_CURATION_ROSTER), present: true };
|
|
124
125
|
}
|
|
125
126
|
return { names, present: true };
|
|
126
127
|
}
|
|
@@ -188,23 +189,23 @@ function withInstalledState(kind, fileName, source, installed, focuses) {
|
|
|
188
189
|
* file is still tried.
|
|
189
190
|
*/
|
|
190
191
|
async function convergeFile(kind, fileName, opts) {
|
|
191
|
-
const { claudeDir,
|
|
192
|
+
const { claudeDir, curation, warn, root, focuses } = opts;
|
|
192
193
|
const target = installedFile(claudeDir, kind, fileName);
|
|
193
194
|
const installed = await readIfPresent(target);
|
|
194
195
|
if (installed === 'absent')
|
|
195
196
|
return 'not-installed';
|
|
196
197
|
if (installed === 'unreadable') {
|
|
197
|
-
warn(`
|
|
198
|
+
warn(`curation variants: cannot read the installed ${kind}/${fileName} (${target}) — left as it is`);
|
|
198
199
|
return 'failed';
|
|
199
200
|
}
|
|
200
|
-
//
|
|
201
|
-
// source order, which is where the
|
|
202
|
-
const candidates =
|
|
201
|
+
// Curation off: the variant is the roster file itself. Curation on: the normal
|
|
202
|
+
// source order, which is where the curation-on file of that host lives.
|
|
203
|
+
const candidates = curation
|
|
203
204
|
? onSourceDirs(kind, root).map(dir => path.join(dir, fileName))
|
|
204
|
-
: [path.join(
|
|
205
|
+
: [path.join(curationOffDir(kind, root), fileName)];
|
|
205
206
|
const source = await firstReadable(candidates);
|
|
206
207
|
if (source === undefined) {
|
|
207
|
-
warn(`
|
|
208
|
+
warn(`curation variants: no source for ${kind}/${fileName} (searched: ${candidates.join(', ')}) — left as it is`);
|
|
208
209
|
return 'failed';
|
|
209
210
|
}
|
|
210
211
|
const wanted = withInstalledState(kind, fileName, source.bytes, installed, focuses);
|
|
@@ -218,7 +219,7 @@ async function convergeFile(kind, fileName, opts) {
|
|
|
218
219
|
await writeFileAtomicExclusive(target, wanted.toString('utf-8'));
|
|
219
220
|
}
|
|
220
221
|
catch (err) {
|
|
221
|
-
warn(`
|
|
222
|
+
warn(`curation variants: could not rewrite ${kind}/${fileName} (${target}) — ${String(err)}`);
|
|
222
223
|
return 'failed';
|
|
223
224
|
}
|
|
224
225
|
return 'rewritten';
|
|
@@ -287,7 +288,7 @@ async function pathExists(p) {
|
|
|
287
288
|
* crash leaves behind must not look like a second skill to Claude Code.
|
|
288
289
|
*/
|
|
289
290
|
async function swapInSkillDirectory(claudeDir, sourceDir, target) {
|
|
290
|
-
const staging = path.join(claudeDir, `.devflow-
|
|
291
|
+
const staging = path.join(claudeDir, `.devflow-curation-${process.pid}-${Date.now().toString(36)}.tmp`);
|
|
291
292
|
const backup = `${staging}.old`;
|
|
292
293
|
try {
|
|
293
294
|
await copyDirectory(sourceDir, staging);
|
|
@@ -309,16 +310,16 @@ async function swapInSkillDirectory(claudeDir, sourceDir, target) {
|
|
|
309
310
|
await fs.rm(backup, { recursive: true, force: true }).catch(() => undefined);
|
|
310
311
|
}
|
|
311
312
|
}
|
|
312
|
-
/** Converge the
|
|
313
|
+
/** Converge the curation-gated skill directories. Never throws. */
|
|
313
314
|
async function convergeSkills(opts) {
|
|
314
|
-
const { claudeDir, devflowDir,
|
|
315
|
+
const { claudeDir, devflowDir, curation, plugins, warn } = opts;
|
|
315
316
|
const selected = skillsOf(plugins);
|
|
316
317
|
let state = 'unchanged';
|
|
317
318
|
// Every gated skill is converged: a failure on one must not skip the next.
|
|
318
|
-
for (const skill of
|
|
319
|
+
for (const skill of CURATION_GATED_SKILLS) {
|
|
319
320
|
const target = path.join(claudeDir, 'skills', prefixSkillName(skill));
|
|
320
321
|
try {
|
|
321
|
-
if (!
|
|
322
|
+
if (!curation) {
|
|
322
323
|
if (!(await pathExists(target)))
|
|
323
324
|
continue;
|
|
324
325
|
await fs.rm(target, { recursive: true });
|
|
@@ -337,7 +338,7 @@ async function convergeSkills(opts) {
|
|
|
337
338
|
state = 'installed';
|
|
338
339
|
}
|
|
339
340
|
catch (err) {
|
|
340
|
-
warn(`
|
|
341
|
+
warn(`curation variants: could not converge the ${prefixSkillName(skill)} skill (${target}) — ${String(err)}`);
|
|
341
342
|
state = 'failed';
|
|
342
343
|
}
|
|
343
344
|
}
|
|
@@ -346,21 +347,21 @@ async function convergeSkills(opts) {
|
|
|
346
347
|
// ── Convergence ────────────────────────────────────────────────────────────
|
|
347
348
|
/**
|
|
348
349
|
* Make the installed commands, agents and apply-decisions skill match the
|
|
349
|
-
* machine's
|
|
350
|
+
* machine's curation switch.
|
|
350
351
|
*
|
|
351
352
|
* Never throws. A caller reads `converged`; it does not catch. A claudeDir that is
|
|
352
353
|
* not absolute is reported the same way rather than thrown, because an install
|
|
353
354
|
* must not die on it.
|
|
354
355
|
*/
|
|
355
|
-
export async function
|
|
356
|
-
const { claudeDir,
|
|
356
|
+
export async function convergeCurationVariants(opts) {
|
|
357
|
+
const { claudeDir, curation, warn } = opts;
|
|
357
358
|
const empty = {
|
|
358
359
|
converged: false, commandsRewritten: [], agentsRewritten: [], unchanged: 0, notInstalled: 0, skill: 'unchanged',
|
|
359
360
|
};
|
|
360
361
|
// Precondition, asserted in production code: a relative claudeDir would resolve
|
|
361
362
|
// the install targets somewhere unexpected.
|
|
362
363
|
if (!path.isAbsolute(claudeDir)) {
|
|
363
|
-
warn(`
|
|
364
|
+
warn(`curation variants: claudeDir is not an absolute path ("${claudeDir}") — skipping convergence`);
|
|
364
365
|
return empty;
|
|
365
366
|
}
|
|
366
367
|
const root = opts.packageRoot ?? getPackageRoot();
|
|
@@ -372,12 +373,12 @@ export async function convergeLearningVariants(opts) {
|
|
|
372
373
|
for (const kind of KINDS) {
|
|
373
374
|
const roster = await readRoster(kind, root, warn);
|
|
374
375
|
if (!roster.present) {
|
|
375
|
-
warn(`
|
|
376
|
+
warn(`curation variants: no ${kind} variants under ${curationOffDir(kind, root)} — run \`npm run build:mds\`; installed ${kind} left as they are`);
|
|
376
377
|
failed = true;
|
|
377
378
|
continue;
|
|
378
379
|
}
|
|
379
380
|
for (const fileName of roster.names) {
|
|
380
|
-
const outcome = await convergeFile(kind, fileName, { claudeDir,
|
|
381
|
+
const outcome = await convergeFile(kind, fileName, { claudeDir, curation, warn, root, focuses });
|
|
381
382
|
if (outcome === 'rewritten')
|
|
382
383
|
rewritten[kind].push(fileName);
|
|
383
384
|
else if (outcome === 'unchanged')
|
|
@@ -418,12 +419,12 @@ export async function readRunningVersion(packageRoot = getPackageRoot()) {
|
|
|
418
419
|
*
|
|
419
420
|
* The caller prints it only on a toggle: a run that moved nothing says nothing.
|
|
420
421
|
*/
|
|
421
|
-
export function
|
|
422
|
+
export function describeCurationConverge(result, curation) {
|
|
422
423
|
const parts = [];
|
|
423
424
|
const prompts = result.commandsRewritten.length + result.agentsRewritten.length;
|
|
424
425
|
if (prompts > 0) {
|
|
425
426
|
parts.push(`${result.commandsRewritten.length} command(s) and ${result.agentsRewritten.length} agent(s) ` +
|
|
426
|
-
`rewritten for the
|
|
427
|
+
`rewritten for the curation-${curation ? 'on' : 'off'} variant`);
|
|
427
428
|
}
|
|
428
429
|
if (result.skill === 'installed')
|
|
429
430
|
parts.push('the apply-decisions skill installed');
|
|
@@ -431,18 +432,49 @@ export function describeLearningConverge(result, learning) {
|
|
|
431
432
|
parts.push('the apply-decisions skill removed');
|
|
432
433
|
return parts.length === 0 ? null : parts.join('; ');
|
|
433
434
|
}
|
|
435
|
+
/**
|
|
436
|
+
* Whether the version the manifest records is the version of the running package.
|
|
437
|
+
* Pure. An unknown running version (null) never matches: the installed files are then
|
|
438
|
+
* not known to be the ones this package would write. Both callers, the curation
|
|
439
|
+
* toggle and `init --hud-only`, ask this one question.
|
|
440
|
+
*/
|
|
441
|
+
export function installedVersionMatches(installedVersion, runningVersion) {
|
|
442
|
+
return runningVersion !== null && installedVersion === runningVersion;
|
|
443
|
+
}
|
|
434
444
|
/**
|
|
435
445
|
* The version-skew check, apart from the I/O so it is provable by itself: null when
|
|
436
|
-
* the installed prompts and this package agree, else the message to print.
|
|
446
|
+
* the installed prompts and this package agree, else the message to print. The
|
|
447
|
+
* installed version is hand-editable file content, so it prints through
|
|
448
|
+
* `describeEchoedValue`.
|
|
449
|
+
*/
|
|
450
|
+
export function curationToggleSkew(installedVersion, runningVersion, curation) {
|
|
451
|
+
if (installedVersionMatches(installedVersion, runningVersion))
|
|
452
|
+
return null;
|
|
453
|
+
return (`The installed prompts come from devflow ${describeEchoedValue(installedVersion)} and this CLI is ${runningVersion ?? 'of unknown version'}, ` +
|
|
454
|
+
`so the curation-${curation ? 'on' : 'off'} variants were not applied. Run \`devflow init\` to apply them.`);
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* The version-skew line for a command that writes curation data, or null when the
|
|
458
|
+
* installed scripts are the ones this CLI would write. A hook of another version
|
|
459
|
+
* reads and creates a different ledger folder, so such a command writes nothing until
|
|
460
|
+
* `devflow init` has run. Apart from the toggle's own check (`curationToggleSkew`,
|
|
461
|
+
* which also names the prompt variants): this line is for configure and the other
|
|
462
|
+
* mutating subcommands. The installed version is hand-editable file content, so it
|
|
463
|
+
* prints through `describeEchoedValue`.
|
|
437
464
|
*/
|
|
438
|
-
export function
|
|
439
|
-
|
|
465
|
+
export async function installedScriptsSkew(devflowDir, packageRoot) {
|
|
466
|
+
const manifest = await readManifest(devflowDir);
|
|
467
|
+
if (manifest === null) {
|
|
468
|
+
return 'No readable install manifest, so the installed scripts are not known. Run `devflow init` first. Nothing was written.';
|
|
469
|
+
}
|
|
470
|
+
const running = await readRunningVersion(packageRoot);
|
|
471
|
+
if (installedVersionMatches(manifest.version, running))
|
|
440
472
|
return null;
|
|
441
|
-
return (`The installed
|
|
442
|
-
|
|
473
|
+
return (`The installed scripts come from devflow ${describeEchoedValue(manifest.version)} and this CLI is ` +
|
|
474
|
+
`${running ?? 'of unknown version'}. Run \`devflow init\` first. Nothing was written.`);
|
|
443
475
|
}
|
|
444
476
|
/**
|
|
445
|
-
* What `devflow
|
|
477
|
+
* What `devflow curation --enable/--disable` does after the switch is written:
|
|
446
478
|
* converge the installed tree onto the new value, then reapply the saved agent
|
|
447
479
|
* model and effort mapping.
|
|
448
480
|
*
|
|
@@ -455,24 +487,24 @@ export function learningToggleSkew(installedVersion, runningVersion, learning) {
|
|
|
455
487
|
*
|
|
456
488
|
* Never throws.
|
|
457
489
|
*/
|
|
458
|
-
export async function
|
|
459
|
-
const { claudeDir, devflowDir,
|
|
490
|
+
export async function applyCurationToggle(opts) {
|
|
491
|
+
const { claudeDir, devflowDir, curation, runningVersion, warn } = opts;
|
|
460
492
|
const manifest = await readManifest(devflowDir);
|
|
461
493
|
if (manifest === null) {
|
|
462
494
|
return {
|
|
463
495
|
kind: 'skipped',
|
|
464
496
|
reason: 'no-manifest',
|
|
465
|
-
message: 'No readable install manifest, so the
|
|
497
|
+
message: 'No readable install manifest, so the curation variants were not applied. Run `devflow init`.',
|
|
466
498
|
};
|
|
467
499
|
}
|
|
468
|
-
const skew =
|
|
500
|
+
const skew = curationToggleSkew(manifest.version, runningVersion, curation);
|
|
469
501
|
if (skew !== null)
|
|
470
502
|
return { kind: 'skipped', reason: 'version-skew', message: skew };
|
|
471
503
|
const selection = new Set(manifest.plugins);
|
|
472
|
-
const result = await
|
|
504
|
+
const result = await convergeCurationVariants({
|
|
473
505
|
claudeDir,
|
|
474
506
|
devflowDir,
|
|
475
|
-
|
|
507
|
+
curation,
|
|
476
508
|
plugins: DEVFLOW_PLUGINS.filter(plugin => selection.has(plugin.name)),
|
|
477
509
|
warn,
|
|
478
510
|
packageRoot: opts.packageRoot,
|
|
@@ -489,9 +521,9 @@ export async function applyLearningToggle(opts) {
|
|
|
489
521
|
agentMappingReapplied = true;
|
|
490
522
|
}
|
|
491
523
|
catch (err) {
|
|
492
|
-
warn(`
|
|
524
|
+
warn(`curation variants: could not reapply the agent model mapping — ${String(err)}`);
|
|
493
525
|
}
|
|
494
526
|
}
|
|
495
527
|
return { kind: 'converged', result, agentMappingReapplied };
|
|
496
528
|
}
|
|
497
|
-
//# sourceMappingURL=
|
|
529
|
+
//# sourceMappingURL=curation-install.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { promises as fs } from 'fs';
|
|
2
2
|
import { existsSync } from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
|
-
import { SKILL_NAMESPACE, buildAssetMaps, prefixSkillName, unprefixSkillName, getAllSkillNames, getAllAgentNames, getAllCommandNames, FEATURE_OWNED_SKILLS, resolveSkillInstallPlan,
|
|
4
|
+
import { SKILL_NAMESPACE, buildAssetMaps, prefixSkillName, unprefixSkillName, getAllSkillNames, getAllAgentNames, getAllCommandNames, FEATURE_OWNED_SKILLS, resolveSkillInstallPlan, omitCurationGatedSkills } from '../../core/plugins.js';
|
|
5
5
|
import { skillsDir, agentSourceDirs, rulesDir, commandSourceDirs, scriptsDir, compiledSkillRefsDir } from '../../core/assets.js';
|
|
6
6
|
import { getPackageRoot, isContainedIn } from '../../core/paths.js';
|
|
7
7
|
import { sweepOrphanedAssets, mdFileName, mdEntryName } from '../../core/orphan-sweep.js';
|
|
@@ -1344,7 +1344,7 @@ async function firstExisting(candidates) {
|
|
|
1344
1344
|
* installed in its place).
|
|
1345
1345
|
*
|
|
1346
1346
|
* The ONE spelling of that decision: the install loop and
|
|
1347
|
-
*
|
|
1347
|
+
* convergeCurationVariants both call it, so a skill the curation toggle installs
|
|
1348
1348
|
* later is shadowed exactly as one the install installed.
|
|
1349
1349
|
*
|
|
1350
1350
|
* The shipped source is stat-checked FIRST, even under a valid shadow, so an
|
|
@@ -1438,8 +1438,8 @@ async function removeDeselectedSkills(skillsDir, names) {
|
|
|
1438
1438
|
* the selective uninstall, which rewrites the files of the plugins that stay installed
|
|
1439
1439
|
* after it removed a retired agent.
|
|
1440
1440
|
*
|
|
1441
|
-
* Commands come from dist/commands/{name}.md, or — with
|
|
1442
|
-
* variant dist/
|
|
1441
|
+
* Commands come from dist/commands/{name}.md, or — with curation off — the curation-off
|
|
1442
|
+
* variant dist/curation-off/commands/{name}.md when the host has one
|
|
1443
1443
|
* (D-LEARNING-VARIANT-INSTALL; commandSourceDirs owns the order). A declared command
|
|
1444
1444
|
* with no compiled source file is a hard error, not a skip.
|
|
1445
1445
|
*
|
|
@@ -1458,9 +1458,9 @@ async function removeDeselectedSkills(skillsDir, names) {
|
|
|
1458
1458
|
* known and leaves it alone.
|
|
1459
1459
|
*/
|
|
1460
1460
|
export async function installCommandsAndAgents(opts) {
|
|
1461
|
-
const { plugins, agentsMap, claudeDir,
|
|
1461
|
+
const { plugins, agentsMap, claudeDir, curation, trackerServers, warn } = opts;
|
|
1462
1462
|
const commandsTarget = path.join(claudeDir, 'commands', 'devflow');
|
|
1463
|
-
const commandDirs = commandSourceDirs(
|
|
1463
|
+
const commandDirs = commandSourceDirs(curation);
|
|
1464
1464
|
const commandsSourceNames = new Set();
|
|
1465
1465
|
for (const plugin of plugins) {
|
|
1466
1466
|
for (const cmd of plugin.commands) {
|
|
@@ -1473,8 +1473,8 @@ export async function installCommandsAndAgents(opts) {
|
|
|
1473
1473
|
for (const name of commandsSourceNames) {
|
|
1474
1474
|
const srcFile = await firstExisting(commandDirs.map(dir => path.join(dir, mdFileName(name))));
|
|
1475
1475
|
if (srcFile === undefined) {
|
|
1476
|
-
// The error names the
|
|
1477
|
-
// command, while a
|
|
1476
|
+
// The error names the curation-ON path: that file exists for every declared
|
|
1477
|
+
// command, while a curation-off file exists only for a host with an arm.
|
|
1478
1478
|
throw new Error(`Command source not found for declared command "${name}": ${path.join(commandSourceDirs(true)[0], mdFileName(name))}. ` +
|
|
1479
1479
|
`Ensure build:mds ran successfully before install.`);
|
|
1480
1480
|
}
|
|
@@ -1482,8 +1482,8 @@ export async function installCommandsAndAgents(opts) {
|
|
|
1482
1482
|
}
|
|
1483
1483
|
}
|
|
1484
1484
|
const agentsTarget = path.join(claudeDir, 'agents', 'devflow');
|
|
1485
|
-
//
|
|
1486
|
-
const agentDirs = opts.agentSourceDirs ?? agentSourceDirs(undefined,
|
|
1485
|
+
// Curation-aware (D-LEARNING-VARIANT-INSTALL). An injected list wins as given.
|
|
1486
|
+
const agentDirs = opts.agentSourceDirs ?? agentSourceDirs(undefined, curation);
|
|
1487
1487
|
const allAgentNames = new Set();
|
|
1488
1488
|
for (const plugin of plugins) {
|
|
1489
1489
|
for (const agent of plugin.agents) {
|
|
@@ -1524,7 +1524,7 @@ export async function installCommandsAndAgents(opts) {
|
|
|
1524
1524
|
* Returns an InstallReport describing which shadows were applied and which were skipped.
|
|
1525
1525
|
*/
|
|
1526
1526
|
export async function installViaFileCopy(options) {
|
|
1527
|
-
const { plugins, claudeDir, devflowDir, skillsMap, agentsMap, rulesMap = new Map(), isPartialInstall, spinner,
|
|
1527
|
+
const { plugins, claudeDir, devflowDir, skillsMap, agentsMap, rulesMap = new Map(), isPartialInstall, spinner, curation, trackerServers = TRACKER_MCP_SERVERS_DEFAULT, warn = () => { }, } = options;
|
|
1528
1528
|
const report = {
|
|
1529
1529
|
shadowedSkills: [],
|
|
1530
1530
|
shadowedRules: [],
|
|
@@ -1687,7 +1687,7 @@ export async function installViaFileCopy(options) {
|
|
|
1687
1687
|
plugins: commandAgentPlugins,
|
|
1688
1688
|
agentsMap: commandAgentMap,
|
|
1689
1689
|
claudeDir,
|
|
1690
|
-
|
|
1690
|
+
curation,
|
|
1691
1691
|
trackerServers,
|
|
1692
1692
|
agentSourceDirs: options.agentSourceDirs,
|
|
1693
1693
|
warn,
|
|
@@ -1713,12 +1713,12 @@ export async function installViaFileCopy(options) {
|
|
|
1713
1713
|
// A declared skill whose source directory is absent is a build/packaging failure
|
|
1714
1714
|
// and throws rather than silently skipping (matches command pattern).
|
|
1715
1715
|
//
|
|
1716
|
-
// D-LEARNING-VARIANT-INSTALL: a
|
|
1716
|
+
// D-LEARNING-VARIANT-INSTALL: a curation-off machine skips the curation-gated
|
|
1717
1717
|
// skills here. The pre-clean above walked the UNFILTERED map, so on a full
|
|
1718
1718
|
// install a leftover copy is already gone; a partial install leaves removal to
|
|
1719
|
-
//
|
|
1719
|
+
// convergeCurationVariants, which init runs straight after this call.
|
|
1720
1720
|
spinner.message('Installing skills...');
|
|
1721
|
-
for (const [skillName] of
|
|
1721
|
+
for (const [skillName] of omitCurationGatedSkills(skillsMap, curation)) {
|
|
1722
1722
|
const resolved = await resolveSkillSource(skillName, devflowDir);
|
|
1723
1723
|
const skillTarget = path.join(claudeDir, 'skills', prefixSkillName(skillName));
|
|
1724
1724
|
await copyDirectory(resolved.dir, skillTarget);
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - The carrier is one line, `Installed language focuses: <list>`, shipped as `(none)` in
|
|
11
11
|
* src/assets/commands/code-review.mds and found again by an anchored match, so a later run can
|
|
12
12
|
* re-stamp a copy an earlier run stamped. It carries no MDS interpolation braces, and it sits outside
|
|
13
|
-
* every
|
|
13
|
+
* every curation arm, so both variants carry it. A separate stamped file would add a file to the
|
|
14
14
|
* install walk and the install goldens, which an in-place rewrite leaves unchanged.
|
|
15
15
|
* - Only code-review.md carries it. /dynamic-build spawns every review focus and drops none (plan
|
|
16
16
|
* decision 1), so it has no stamp, no reduced classes and no DIFF_FILE.
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
* - `devflow uninstall --plugin` removes a language plugin's skill but no command, so its name would
|
|
23
23
|
* stay in the stamped copy; the selective phase re-stamps from the plugins that remain, through
|
|
24
24
|
* {@link restampInstalledCommands} like the install.
|
|
25
|
-
* - Composition with the
|
|
26
|
-
* installed command files from dist or dist/
|
|
25
|
+
* - Composition with the curation converge (D-LEARNING-VARIANT-INSTALL), pinned: the converge rewrites
|
|
26
|
+
* installed command files from dist or dist/curation-off, and those files carry the shipped `(none)`
|
|
27
27
|
* line. It therefore applies {@link carryLanguageStamp} inside its own write path, putting the stamp
|
|
28
28
|
* it finds on the installed copy into the variant it writes ({@link stampForConverge}); a copy with no
|
|
29
29
|
* list to carry, one installed before the stamp existed, is stamped from the converge's selection
|
|
@@ -83,7 +83,7 @@ export function applyLanguageStamp(content, focuses) {
|
|
|
83
83
|
/**
|
|
84
84
|
* `source` with its stamp line replaced by the one on `installed`.
|
|
85
85
|
*
|
|
86
|
-
* The
|
|
86
|
+
* The curation converge's write path (see the header): the variant it installs keeps the list the
|
|
87
87
|
* install stamped. Returns `source` unchanged unless both sides hold exactly one stamp line and the
|
|
88
88
|
* installed one is a well-formed list, so a damaged or hostile line is never copied into a fresh file.
|
|
89
89
|
*/
|
|
@@ -103,7 +103,7 @@ function carriableStampLine(installed) {
|
|
|
103
103
|
return STAMP_VALUE_RE.test(from[0][0].slice(LANGUAGE_STAMP_PREFIX.length)) ? from[0][0] : null;
|
|
104
104
|
}
|
|
105
105
|
/**
|
|
106
|
-
* The text the
|
|
106
|
+
* The text the curation converge installs for a stamped command: `source` carrying the installed copy's
|
|
107
107
|
* list ({@link carryLanguageStamp}) when the copy holds one, else `source` stamped with `focuses`, the
|
|
108
108
|
* effective selection's list, exactly as the install stamps it.
|
|
109
109
|
*
|
|
@@ -56,7 +56,7 @@ const DEVFLOW_POLICY_LINE = '!.devflow/policy.json';
|
|
|
56
56
|
const DEVFLOW_PROJECT_LINE = '!.devflow/project.json';
|
|
57
57
|
/**
|
|
58
58
|
* The shared .devflow/ gitignore block. Everything under .devflow/ is local
|
|
59
|
-
* (memory,
|
|
59
|
+
* (memory, curation, docs, locks) EXCEPT:
|
|
60
60
|
* - Feature knowledge bases: index.md and every {slug}/KNOWLEDGE.md are tracked
|
|
61
61
|
* + committed (the Knowledge agent commits them at workflow end).
|
|
62
62
|
* - conventions.md: naming-convention authority written by the Git learn-conventions
|
|
@@ -78,7 +78,7 @@ const DEVFLOW_PROJECT_LINE = '!.devflow/project.json';
|
|
|
78
78
|
* so the init-time path and the always-on hook path produce the same file.
|
|
79
79
|
*/
|
|
80
80
|
const DEVFLOW_GITIGNORE_BLOCK_LINES = [
|
|
81
|
-
'# Devflow runtime data — local by default (memory,
|
|
81
|
+
'# Devflow runtime data — local by default (memory, curation, docs, locks).',
|
|
82
82
|
'# Shared via git: feature knowledge bases under .devflow/features/ (index.md and',
|
|
83
83
|
'# every {slug}/KNOWLEDGE.md), .devflow/conventions.md (naming authority),',
|
|
84
84
|
'# .devflow/policy.json (retired; presence only) and .devflow/project.json (team settings).',
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* a `--plugin` run that does not install Git leaves the installed, stamped copy alone.
|
|
18
18
|
* 2. `convergeTrackerArtifacts` stamps Tracker as it writes it, and compares the STAMPED text
|
|
19
19
|
* with the installed file, so a steady-state run reports `unchanged`.
|
|
20
|
-
* 3. `
|
|
20
|
+
* 3. `convergeCurationVariants` (init, `devflow curation --enable/--disable`) carries the
|
|
21
21
|
* installed stamp onto the variant it writes (`carryStampedTools`), the way it carries
|
|
22
22
|
* `model:` and `effort:`, so a variant switch keeps the list and a repeat run is byte-equal.
|
|
23
23
|
* 4. `devflow tracker --servers` re-stamps the installed copies at once ({@link restampTrackerAgents}).
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devflow-kit",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "A meta-harness for Claude Code — turns a single coding agent into an engineering team: orchestration, parallel review, persistent memory,
|
|
3
|
+
"version": "3.8.0",
|
|
4
|
+
"description": "A meta-harness for Claude Code — turns a single coding agent into an engineering team: orchestration, parallel review, persistent memory, curated decisions, and graph workflows",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"devflow": "dist/cli.js"
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"!dist/**/*.d.ts",
|
|
13
13
|
"src/assets/",
|
|
14
14
|
"src/targets/claude-code/templates/",
|
|
15
|
+
"templates/lint-pack/",
|
|
15
16
|
"README.md",
|
|
16
17
|
"LICENSE",
|
|
17
18
|
"CHANGELOG.md"
|
|
@@ -6,8 +6,10 @@ so the build skips it and it reaches an artifact only through the hosts that imp
|
|
|
6
6
|
D-CODE-VARIANTS: a spawn runs exactly one mode, so one agent for every mode would pay for every
|
|
7
7
|
mode's text and skills on every spawn. Each host carries its own mode sections, its own `OPERATION:`
|
|
8
8
|
line and its own preload (D-CODE-PRELOADS); what every mode needs is written once here. The
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
Commit and push line lives in `commit_push()`. It ends with one check of the staged diff of every
|
|
10
|
+
committed file for secrets or tokens in debug output, and the security-scan block follows it, so
|
|
11
|
+
every variant keeps both. The Running commands block lives in `tail()`, so the three carry one
|
|
12
|
+
byte-identical copy.
|
|
11
13
|
|
|
12
14
|
D-NO-RUNTIME-SKILLS: no variant carries a mode-skill table, a `DOMAIN` input or an instruction
|
|
13
15
|
to load a skill by language.
|
|
@@ -16,27 +18,27 @@ D-COMPLIANCE-INJECT: no variant names the compliance skill or takes a compliance
|
|
|
16
18
|
injects the compliance directive into a spawn prompt only when the resolved lens is on, so a
|
|
17
19
|
lens-off spawn pays nothing for it (the directive's home is `commands/_partials/_compliance.mds`).
|
|
18
20
|
|
|
19
|
-
The hosts import this partial as an alias (`as code`) and call each define once. A
|
|
21
|
+
The hosts import this partial as an alias (`as code`) and call each define once. A curation arm
|
|
20
22
|
inside a define is split by the build like an arm in a host: the markers sit on lines of their own.
|
|
21
23
|
|
|
22
24
|
@define input_core():
|
|
23
|
-
- **TASK_ID**: Unique identifier
|
|
25
|
+
- **TASK_ID**: Unique identifier
|
|
24
26
|
- **TASK_DESCRIPTION**: What to do
|
|
25
27
|
- **PUSH** (optional): `true` (default) | `false` — when false, commit only; orchestrator owns push/CI gate
|
|
26
|
-
<!--
|
|
28
|
+
<!-- curation:on -->
|
|
27
29
|
- **DECISIONS_CONTEXT** (optional): Compact index of active ADR/PF entries.
|
|
28
30
|
When provided, use `devflow:apply-decisions` to Read full bodies on demand.
|
|
29
|
-
<!--
|
|
31
|
+
<!-- curation:end -->
|
|
30
32
|
@end
|
|
31
33
|
|
|
32
34
|
@define decisions_orient():
|
|
33
|
-
<!--
|
|
35
|
+
<!-- curation:on -->
|
|
34
36
|
- If `DECISIONS_CONTEXT` is provided, follow `devflow:apply-decisions` on it. An absent key or `(none)` means no decisions context. State every decision or pitfall you apply in words in code, comments, tests and commit messages, never by its ID.
|
|
35
|
-
<!--
|
|
37
|
+
<!-- curation:end -->
|
|
36
38
|
@end
|
|
37
39
|
|
|
38
40
|
@define commit_push():
|
|
39
|
-
**Commit and push**: Create atomic commits with clear messages. Reference TASK_ID. Push to remote UNLESS `PUSH: false
|
|
41
|
+
**Commit and push**: Create atomic commits with clear messages. Reference TASK_ID. Push to remote UNLESS `PUSH: false`. Before you commit, check the staged diff of every file you commit: no secrets or tokens in logs or debug output.
|
|
40
42
|
**Security scan (conditional):** Only when this session offers a code-scanning tool. Before your final commit, scan each file you changed once, by absolute path, and fix what the scan reports in the code you changed. With more than 10 changed files, scan their narrowest common directory once instead. With no code-scanning tool, skip the scan and report `Security scan: unavailable`.
|
|
41
43
|
@end
|
|
42
44
|
|
|
@@ -56,15 +58,13 @@ Run builds, typechecks, lints and tests in the foreground, each with an explicit
|
|
|
56
58
|
|
|
57
59
|
## Principles
|
|
58
60
|
|
|
59
|
-
1. **
|
|
60
|
-
2. **
|
|
61
|
-
3. **
|
|
62
|
-
4. **Small, focused changes** - Don't scope creep beyond the plan
|
|
63
|
-
5. **Fail honestly** - If blocked, report clearly with what was completed
|
|
61
|
+
1. **Read once** - Never re-read an unchanged file. For a file over 400 lines, or a second look, `grep -n` first, then Read only that range (`offset`, `limit`)
|
|
62
|
+
2. **Small, focused changes** - Don't scope creep beyond the plan
|
|
63
|
+
3. **Fail honestly** - If blocked, report clearly with what was completed
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
- Never print a large file whole; page it with offset and limit, and cap any output you print. Before printing search matches, list or count them.
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
## Output
|
|
68
68
|
|
|
69
69
|
```markdown
|
|
70
70
|
## Implementation Report: {TASK_ID}
|
|
@@ -100,7 +100,6 @@ Report cap: final message at most about 1,500 tokens; longer material goes to a
|
|
|
100
100
|
- Switch branches during implementation
|
|
101
101
|
- Push to branches other than your feature branch
|
|
102
102
|
- Merge PRs (orchestrator handles this)
|
|
103
|
-
- Trust handoff summaries without reading actual code
|
|
104
103
|
@end
|
|
105
104
|
|
|
106
105
|
@export input_core
|