devflow-kit 3.7.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 +359 -1
- package/README.md +11 -11
- package/dist/agents/code.md +2 -4
- package/dist/agents/design.md +1 -1
- package/dist/agents/fix.md +6 -7
- package/dist/agents/git.md +1 -1
- package/dist/agents/harden.md +1 -1
- package/dist/agents/refactor.md +2 -4
- package/dist/agents/review.md +4 -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 +34 -11
- package/dist/cli/commands/init-seed.js +11 -8
- package/dist/cli/commands/init.js +240 -54
- package/dist/cli/commands/memory.js +2 -2
- package/dist/cli/commands/prompt-io.js +37 -0
- package/dist/cli/commands/uninstall.js +81 -9
- package/dist/cli.js +2 -2
- package/dist/commands/bug-analysis.md +24 -35
- package/dist/commands/code-review.md +32 -36
- package/dist/commands/debug.md +4 -4
- package/dist/commands/dynamic-build.md +25 -24
- package/dist/commands/dynamic-plan.md +4 -4
- package/dist/commands/dynamic-profile.md +4 -4
- package/dist/commands/dynamic-tickets.md +4 -4
- package/dist/commands/explore.md +5 -5
- package/dist/commands/implement.md +52 -81
- package/dist/commands/plan.md +5 -5
- package/dist/commands/release.md +4 -4
- package/dist/commands/research.md +5 -5
- package/dist/commands/resolve.md +28 -30
- package/dist/commands/self-review.md +4 -12
- 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 +11 -5
- package/dist/core/evidence-policy.js +1 -1
- package/dist/core/feature-switch.js +95 -19
- package/dist/core/fs-atomic.js +1 -1
- package/dist/core/gate-level.js +10 -2
- 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 +58 -14
- package/dist/core/migrations.js +1 -13
- 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 +1 -1
- package/dist/{learning-off → curation-off}/agents/code.md +2 -4
- package/dist/{learning-off → curation-off}/agents/fix.md +6 -7
- package/dist/{learning-off → curation-off}/agents/refactor.md +2 -4
- package/dist/{learning-off → curation-off}/agents/review.md +3 -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 +29 -33
- package/dist/{learning-off → curation-off}/commands/debug.md +1 -1
- package/dist/{learning-off → curation-off}/commands/dynamic-build.md +22 -21
- package/dist/{learning-off → curation-off}/commands/explore.md +1 -1
- package/dist/{learning-off → curation-off}/commands/implement.md +49 -78
- package/dist/{learning-off → curation-off}/commands/plan.md +1 -1
- package/dist/{learning-off → curation-off}/commands/resolve.md +25 -27
- package/dist/{learning-off → curation-off}/commands/self-review.md +1 -9
- 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 +13 -5
- package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +13 -5
- package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +13 -5
- package/dist/targets/claude-code/{learning-install.js → curation-install.js} +85 -65
- 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 +11 -11
- package/src/assets/agents/code.mds +2 -2
- package/src/assets/agents/curate.md +8 -8
- 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 +43 -43
- package/src/assets/agents/skim.mds +11 -11
- 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 +2 -2
- package/src/assets/commands/_partials/_wave.mds +7 -7
- package/src/assets/commands/bug-analysis.mds +37 -48
- package/src/assets/commands/code-review.mds +46 -50
- package/src/assets/commands/debug.mds +14 -14
- package/src/assets/commands/dynamic-build.mds +38 -37
- 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 +77 -98
- package/src/assets/commands/plan.mds +27 -27
- 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 +10 -4
- package/src/assets/mds/git/_pr.mds +7 -4
- package/src/assets/rules/quality.md +1 -0
- package/src/assets/scripts/hooks/background-memory-update +2 -2
- 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 +134 -51
- package/src/assets/scripts/hooks/json-parse +1 -1
- 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-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 +143 -69
- package/src/assets/scripts/hooks/session-start-memory +3 -43
- package/src/assets/scripts/lib/project-config.cjs +12 -5
- package/src/assets/scripts/resolve-base.cjs +1043 -0
- package/src/assets/scripts/resolve-settings.cjs +42 -18
- package/src/assets/skills/agent-references/SKILL.md +5 -2
- 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/resolve-levels.md +24 -0
- 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,34 +42,34 @@
|
|
|
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
75
|
import { describeEchoedValue } from '../../core/echo-value.js';
|
|
@@ -77,7 +77,7 @@ import { writeFileAtomicExclusive } from '../../core/fs-atomic.js';
|
|
|
77
77
|
import { readManifest } from '../../core/manifest.js';
|
|
78
78
|
import { getPackageRoot } from '../../core/paths.js';
|
|
79
79
|
import { isProxyEnabled } from '../../core/proxy-state.js';
|
|
80
|
-
import { DEVFLOW_PLUGINS,
|
|
80
|
+
import { DEVFLOW_PLUGINS, CURATION_GATED_SKILLS, installedLanguageFocuses, prefixSkillName, skillsOf, } from '../../core/plugins.js';
|
|
81
81
|
import { copyDirectory, resolveSkillSource } from './installer.js';
|
|
82
82
|
import { LANGUAGE_STAMPED_COMMANDS, stampForConverge } from './language-stamp.js';
|
|
83
83
|
// ── Bounds ─────────────────────────────────────────────────────────────────
|
|
@@ -86,7 +86,7 @@ import { LANGUAGE_STAMPED_COMMANDS, stampForConverge } from './language-stamp.js
|
|
|
86
86
|
* 9 agents; the bound exists so a directory that grew without limit cannot turn the
|
|
87
87
|
* converge into an unbounded loop (every loop has an explicit bound).
|
|
88
88
|
*/
|
|
89
|
-
export const
|
|
89
|
+
export const MAX_CURATION_ROSTER = 256;
|
|
90
90
|
/** Deepest skill-directory descent the tree comparison takes. */
|
|
91
91
|
const MAX_SKILL_TREE_DEPTH = 4;
|
|
92
92
|
/** A roster entry is a flat, lowercase, hyphenated markdown basename. */
|
|
@@ -96,12 +96,12 @@ const KINDS = ['commands', 'agents'];
|
|
|
96
96
|
function installedFile(claudeDir, kind, fileName) {
|
|
97
97
|
return path.join(claudeDir, kind, 'devflow', fileName);
|
|
98
98
|
}
|
|
99
|
-
/** The
|
|
99
|
+
/** The curation-ON source directories for a kind, most-preferred first. */
|
|
100
100
|
function onSourceDirs(kind, root) {
|
|
101
101
|
return kind === 'commands' ? commandSourceDirs(true, root) : agentSourceDirs(root, true);
|
|
102
102
|
}
|
|
103
103
|
/**
|
|
104
|
-
* 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.
|
|
105
105
|
*
|
|
106
106
|
* `present` is false when the directory does not exist (the build has not run, or
|
|
107
107
|
* only `build:cli` did), so the caller can say so instead of reporting a converge
|
|
@@ -110,18 +110,18 @@ function onSourceDirs(kind, root) {
|
|
|
110
110
|
async function readRoster(kind, root, warn) {
|
|
111
111
|
let entries;
|
|
112
112
|
try {
|
|
113
|
-
entries = await fs.readdir(
|
|
113
|
+
entries = await fs.readdir(curationOffDir(kind, root));
|
|
114
114
|
}
|
|
115
115
|
catch (err) {
|
|
116
116
|
if (err.code === 'ENOENT')
|
|
117
117
|
return { names: [], present: false };
|
|
118
|
-
warn(`
|
|
118
|
+
warn(`curation variants: cannot read the ${kind} variants — ${String(err)}`);
|
|
119
119
|
return { names: [], present: false };
|
|
120
120
|
}
|
|
121
121
|
const names = entries.filter(entry => ROSTER_NAME_RE.test(entry)).sort();
|
|
122
|
-
if (names.length >
|
|
123
|
-
warn(`
|
|
124
|
-
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 };
|
|
125
125
|
}
|
|
126
126
|
return { names, present: true };
|
|
127
127
|
}
|
|
@@ -189,23 +189,23 @@ function withInstalledState(kind, fileName, source, installed, focuses) {
|
|
|
189
189
|
* file is still tried.
|
|
190
190
|
*/
|
|
191
191
|
async function convergeFile(kind, fileName, opts) {
|
|
192
|
-
const { claudeDir,
|
|
192
|
+
const { claudeDir, curation, warn, root, focuses } = opts;
|
|
193
193
|
const target = installedFile(claudeDir, kind, fileName);
|
|
194
194
|
const installed = await readIfPresent(target);
|
|
195
195
|
if (installed === 'absent')
|
|
196
196
|
return 'not-installed';
|
|
197
197
|
if (installed === 'unreadable') {
|
|
198
|
-
warn(`
|
|
198
|
+
warn(`curation variants: cannot read the installed ${kind}/${fileName} (${target}) — left as it is`);
|
|
199
199
|
return 'failed';
|
|
200
200
|
}
|
|
201
|
-
//
|
|
202
|
-
// source order, which is where the
|
|
203
|
-
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
|
|
204
204
|
? onSourceDirs(kind, root).map(dir => path.join(dir, fileName))
|
|
205
|
-
: [path.join(
|
|
205
|
+
: [path.join(curationOffDir(kind, root), fileName)];
|
|
206
206
|
const source = await firstReadable(candidates);
|
|
207
207
|
if (source === undefined) {
|
|
208
|
-
warn(`
|
|
208
|
+
warn(`curation variants: no source for ${kind}/${fileName} (searched: ${candidates.join(', ')}) — left as it is`);
|
|
209
209
|
return 'failed';
|
|
210
210
|
}
|
|
211
211
|
const wanted = withInstalledState(kind, fileName, source.bytes, installed, focuses);
|
|
@@ -219,7 +219,7 @@ async function convergeFile(kind, fileName, opts) {
|
|
|
219
219
|
await writeFileAtomicExclusive(target, wanted.toString('utf-8'));
|
|
220
220
|
}
|
|
221
221
|
catch (err) {
|
|
222
|
-
warn(`
|
|
222
|
+
warn(`curation variants: could not rewrite ${kind}/${fileName} (${target}) — ${String(err)}`);
|
|
223
223
|
return 'failed';
|
|
224
224
|
}
|
|
225
225
|
return 'rewritten';
|
|
@@ -288,7 +288,7 @@ async function pathExists(p) {
|
|
|
288
288
|
* crash leaves behind must not look like a second skill to Claude Code.
|
|
289
289
|
*/
|
|
290
290
|
async function swapInSkillDirectory(claudeDir, sourceDir, target) {
|
|
291
|
-
const staging = path.join(claudeDir, `.devflow-
|
|
291
|
+
const staging = path.join(claudeDir, `.devflow-curation-${process.pid}-${Date.now().toString(36)}.tmp`);
|
|
292
292
|
const backup = `${staging}.old`;
|
|
293
293
|
try {
|
|
294
294
|
await copyDirectory(sourceDir, staging);
|
|
@@ -310,16 +310,16 @@ async function swapInSkillDirectory(claudeDir, sourceDir, target) {
|
|
|
310
310
|
await fs.rm(backup, { recursive: true, force: true }).catch(() => undefined);
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
|
-
/** Converge the
|
|
313
|
+
/** Converge the curation-gated skill directories. Never throws. */
|
|
314
314
|
async function convergeSkills(opts) {
|
|
315
|
-
const { claudeDir, devflowDir,
|
|
315
|
+
const { claudeDir, devflowDir, curation, plugins, warn } = opts;
|
|
316
316
|
const selected = skillsOf(plugins);
|
|
317
317
|
let state = 'unchanged';
|
|
318
318
|
// Every gated skill is converged: a failure on one must not skip the next.
|
|
319
|
-
for (const skill of
|
|
319
|
+
for (const skill of CURATION_GATED_SKILLS) {
|
|
320
320
|
const target = path.join(claudeDir, 'skills', prefixSkillName(skill));
|
|
321
321
|
try {
|
|
322
|
-
if (!
|
|
322
|
+
if (!curation) {
|
|
323
323
|
if (!(await pathExists(target)))
|
|
324
324
|
continue;
|
|
325
325
|
await fs.rm(target, { recursive: true });
|
|
@@ -338,7 +338,7 @@ async function convergeSkills(opts) {
|
|
|
338
338
|
state = 'installed';
|
|
339
339
|
}
|
|
340
340
|
catch (err) {
|
|
341
|
-
warn(`
|
|
341
|
+
warn(`curation variants: could not converge the ${prefixSkillName(skill)} skill (${target}) — ${String(err)}`);
|
|
342
342
|
state = 'failed';
|
|
343
343
|
}
|
|
344
344
|
}
|
|
@@ -347,21 +347,21 @@ async function convergeSkills(opts) {
|
|
|
347
347
|
// ── Convergence ────────────────────────────────────────────────────────────
|
|
348
348
|
/**
|
|
349
349
|
* Make the installed commands, agents and apply-decisions skill match the
|
|
350
|
-
* machine's
|
|
350
|
+
* machine's curation switch.
|
|
351
351
|
*
|
|
352
352
|
* Never throws. A caller reads `converged`; it does not catch. A claudeDir that is
|
|
353
353
|
* not absolute is reported the same way rather than thrown, because an install
|
|
354
354
|
* must not die on it.
|
|
355
355
|
*/
|
|
356
|
-
export async function
|
|
357
|
-
const { claudeDir,
|
|
356
|
+
export async function convergeCurationVariants(opts) {
|
|
357
|
+
const { claudeDir, curation, warn } = opts;
|
|
358
358
|
const empty = {
|
|
359
359
|
converged: false, commandsRewritten: [], agentsRewritten: [], unchanged: 0, notInstalled: 0, skill: 'unchanged',
|
|
360
360
|
};
|
|
361
361
|
// Precondition, asserted in production code: a relative claudeDir would resolve
|
|
362
362
|
// the install targets somewhere unexpected.
|
|
363
363
|
if (!path.isAbsolute(claudeDir)) {
|
|
364
|
-
warn(`
|
|
364
|
+
warn(`curation variants: claudeDir is not an absolute path ("${claudeDir}") — skipping convergence`);
|
|
365
365
|
return empty;
|
|
366
366
|
}
|
|
367
367
|
const root = opts.packageRoot ?? getPackageRoot();
|
|
@@ -373,12 +373,12 @@ export async function convergeLearningVariants(opts) {
|
|
|
373
373
|
for (const kind of KINDS) {
|
|
374
374
|
const roster = await readRoster(kind, root, warn);
|
|
375
375
|
if (!roster.present) {
|
|
376
|
-
warn(`
|
|
376
|
+
warn(`curation variants: no ${kind} variants under ${curationOffDir(kind, root)} — run \`npm run build:mds\`; installed ${kind} left as they are`);
|
|
377
377
|
failed = true;
|
|
378
378
|
continue;
|
|
379
379
|
}
|
|
380
380
|
for (const fileName of roster.names) {
|
|
381
|
-
const outcome = await convergeFile(kind, fileName, { claudeDir,
|
|
381
|
+
const outcome = await convergeFile(kind, fileName, { claudeDir, curation, warn, root, focuses });
|
|
382
382
|
if (outcome === 'rewritten')
|
|
383
383
|
rewritten[kind].push(fileName);
|
|
384
384
|
else if (outcome === 'unchanged')
|
|
@@ -419,12 +419,12 @@ export async function readRunningVersion(packageRoot = getPackageRoot()) {
|
|
|
419
419
|
*
|
|
420
420
|
* The caller prints it only on a toggle: a run that moved nothing says nothing.
|
|
421
421
|
*/
|
|
422
|
-
export function
|
|
422
|
+
export function describeCurationConverge(result, curation) {
|
|
423
423
|
const parts = [];
|
|
424
424
|
const prompts = result.commandsRewritten.length + result.agentsRewritten.length;
|
|
425
425
|
if (prompts > 0) {
|
|
426
426
|
parts.push(`${result.commandsRewritten.length} command(s) and ${result.agentsRewritten.length} agent(s) ` +
|
|
427
|
-
`rewritten for the
|
|
427
|
+
`rewritten for the curation-${curation ? 'on' : 'off'} variant`);
|
|
428
428
|
}
|
|
429
429
|
if (result.skill === 'installed')
|
|
430
430
|
parts.push('the apply-decisions skill installed');
|
|
@@ -435,7 +435,7 @@ export function describeLearningConverge(result, learning) {
|
|
|
435
435
|
/**
|
|
436
436
|
* Whether the version the manifest records is the version of the running package.
|
|
437
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
|
|
438
|
+
* not known to be the ones this package would write. Both callers, the curation
|
|
439
439
|
* toggle and `init --hud-only`, ask this one question.
|
|
440
440
|
*/
|
|
441
441
|
export function installedVersionMatches(installedVersion, runningVersion) {
|
|
@@ -447,14 +447,34 @@ export function installedVersionMatches(installedVersion, runningVersion) {
|
|
|
447
447
|
* installed version is hand-editable file content, so it prints through
|
|
448
448
|
* `describeEchoedValue`.
|
|
449
449
|
*/
|
|
450
|
-
export function
|
|
450
|
+
export function curationToggleSkew(installedVersion, runningVersion, curation) {
|
|
451
451
|
if (installedVersionMatches(installedVersion, runningVersion))
|
|
452
452
|
return null;
|
|
453
453
|
return (`The installed prompts come from devflow ${describeEchoedValue(installedVersion)} and this CLI is ${runningVersion ?? 'of unknown version'}, ` +
|
|
454
|
-
`so the
|
|
454
|
+
`so the curation-${curation ? 'on' : 'off'} variants were not applied. Run \`devflow init\` to apply them.`);
|
|
455
455
|
}
|
|
456
456
|
/**
|
|
457
|
-
*
|
|
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`.
|
|
464
|
+
*/
|
|
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))
|
|
472
|
+
return null;
|
|
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.`);
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* What `devflow curation --enable/--disable` does after the switch is written:
|
|
458
478
|
* converge the installed tree onto the new value, then reapply the saved agent
|
|
459
479
|
* model and effort mapping.
|
|
460
480
|
*
|
|
@@ -467,24 +487,24 @@ export function learningToggleSkew(installedVersion, runningVersion, learning) {
|
|
|
467
487
|
*
|
|
468
488
|
* Never throws.
|
|
469
489
|
*/
|
|
470
|
-
export async function
|
|
471
|
-
const { claudeDir, devflowDir,
|
|
490
|
+
export async function applyCurationToggle(opts) {
|
|
491
|
+
const { claudeDir, devflowDir, curation, runningVersion, warn } = opts;
|
|
472
492
|
const manifest = await readManifest(devflowDir);
|
|
473
493
|
if (manifest === null) {
|
|
474
494
|
return {
|
|
475
495
|
kind: 'skipped',
|
|
476
496
|
reason: 'no-manifest',
|
|
477
|
-
message: 'No readable install manifest, so the
|
|
497
|
+
message: 'No readable install manifest, so the curation variants were not applied. Run `devflow init`.',
|
|
478
498
|
};
|
|
479
499
|
}
|
|
480
|
-
const skew =
|
|
500
|
+
const skew = curationToggleSkew(manifest.version, runningVersion, curation);
|
|
481
501
|
if (skew !== null)
|
|
482
502
|
return { kind: 'skipped', reason: 'version-skew', message: skew };
|
|
483
503
|
const selection = new Set(manifest.plugins);
|
|
484
|
-
const result = await
|
|
504
|
+
const result = await convergeCurationVariants({
|
|
485
505
|
claudeDir,
|
|
486
506
|
devflowDir,
|
|
487
|
-
|
|
507
|
+
curation,
|
|
488
508
|
plugins: DEVFLOW_PLUGINS.filter(plugin => selection.has(plugin.name)),
|
|
489
509
|
warn,
|
|
490
510
|
packageRoot: opts.packageRoot,
|
|
@@ -501,9 +521,9 @@ export async function applyLearningToggle(opts) {
|
|
|
501
521
|
agentMappingReapplied = true;
|
|
502
522
|
}
|
|
503
523
|
catch (err) {
|
|
504
|
-
warn(`
|
|
524
|
+
warn(`curation variants: could not reapply the agent model mapping — ${String(err)}`);
|
|
505
525
|
}
|
|
506
526
|
}
|
|
507
527
|
return { kind: 'converged', result, agentMappingReapplied };
|
|
508
528
|
}
|
|
509
|
-
//# 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
|
|
|
@@ -64,8 +66,6 @@ Run builds, typechecks, lints and tests in the foreground, each with an explicit
|
|
|
64
66
|
|
|
65
67
|
## Output
|
|
66
68
|
|
|
67
|
-
Return structured completion status:
|
|
68
|
-
|
|
69
69
|
```markdown
|
|
70
70
|
## Implementation Report: {TASK_ID}
|
|
71
71
|
|
|
@@ -19,9 +19,9 @@ skills:
|
|
|
19
19
|
- devflow:test-driven-development
|
|
20
20
|
- devflow:worktree-support
|
|
21
21
|
- devflow:apply-feature-knowledge
|
|
22
|
-
<!--
|
|
22
|
+
<!-- curation:on -->
|
|
23
23
|
- devflow:apply-decisions
|
|
24
|
-
<!--
|
|
24
|
+
<!-- curation:end -->
|
|
25
25
|
disallowedTools:
|
|
26
26
|
- Agent
|
|
27
27
|
- SendMessage
|