devflow-kit 3.6.0 → 3.7.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 +80 -1
- package/README.md +6 -2
- package/dist/agents/code.md +7 -11
- package/dist/agents/fix.md +5 -6
- package/dist/agents/refactor.md +5 -6
- package/dist/agents/review.md +2 -0
- package/dist/cli/commands/gates.js +276 -0
- package/dist/cli/commands/init-seed.js +9 -1
- package/dist/cli/commands/init.js +31 -8
- package/dist/cli/commands/memory.js +18 -0
- package/dist/cli.js +2 -0
- package/dist/commands/bug-analysis.md +2 -2
- package/dist/commands/code-review.md +52 -44
- package/dist/commands/debug.md +2 -2
- package/dist/commands/dynamic-build.md +53 -61
- package/dist/commands/dynamic-plan.md +2 -2
- package/dist/commands/dynamic-profile.md +2 -2
- package/dist/commands/dynamic-tickets.md +2 -2
- package/dist/commands/explore.md +2 -2
- package/dist/commands/implement.md +26 -31
- package/dist/commands/plan.md +15 -25
- package/dist/commands/release.md +2 -2
- package/dist/commands/research.md +2 -2
- package/dist/commands/resolve.md +2 -2
- package/dist/commands/self-review.md +2 -2
- package/dist/core/echo-value.js +42 -0
- package/dist/core/evidence-policy.js +17 -5
- package/dist/core/gate-level.js +213 -0
- package/dist/core/manifest.js +26 -10
- package/dist/core/model-discovery.js +7 -1
- package/dist/core/tracker.js +5 -33
- package/dist/learning-off/agents/code.md +7 -11
- package/dist/learning-off/agents/fix.md +5 -6
- package/dist/learning-off/agents/refactor.md +5 -6
- package/dist/learning-off/agents/review.md +2 -0
- package/dist/learning-off/commands/code-review.md +52 -44
- package/dist/learning-off/commands/debug.md +2 -2
- package/dist/learning-off/commands/dynamic-build.md +53 -61
- package/dist/learning-off/commands/explore.md +2 -2
- package/dist/learning-off/commands/implement.md +26 -31
- package/dist/learning-off/commands/plan.md +15 -25
- package/dist/learning-off/commands/resolve.md +2 -2
- package/dist/learning-off/commands/self-review.md +2 -2
- package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +7 -9
- package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +7 -15
- package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +7 -15
- package/dist/targets/claude-code/learning-install.js +15 -3
- package/package.json +1 -1
- package/src/assets/agents/_partials/_code.mds +5 -6
- package/src/assets/agents/code.mds +2 -5
- package/src/assets/agents/curate.md +4 -6
- package/src/assets/agents/review.mds +2 -0
- package/src/assets/agents/synthesize.md +2 -2
- package/src/assets/commands/_partials/_settings.mds +2 -2
- package/src/assets/commands/_partials/_wave.mds +10 -17
- package/src/assets/commands/code-review.mds +50 -42
- package/src/assets/commands/dynamic-build.mds +41 -42
- package/src/assets/commands/implement.mds +24 -29
- package/src/assets/commands/plan.mds +14 -24
- package/src/assets/mds/git/_ops_steps.mds +3 -3
- 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/scripts/ci-wait.cjs +22 -4
- package/src/assets/scripts/claude-md-audit.cjs +66 -51
- package/src/assets/scripts/hooks/background-memory-update +404 -95
- package/src/assets/scripts/hooks/json-helper.cjs +11 -0
- package/src/assets/scripts/hooks/json-parse +18 -3
- package/src/assets/scripts/hooks/memory-permission +358 -0
- package/src/assets/scripts/hooks/session-start-context +2 -2
- package/src/assets/scripts/hooks/session-start-memory +26 -5
- package/src/assets/scripts/lib/project-config.cjs +19 -4
- package/src/assets/scripts/resolve-settings.cjs +200 -32
- package/src/assets/skills/agent-references/SKILL.md +6 -2
- package/src/assets/skills/agent-references/references/commands/code-review-levels.md +19 -0
- package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +2 -2
- package/src/assets/skills/agent-references/references/commands/plan-levels.md +40 -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
|
@@ -9,6 +9,7 @@ import { getGitRoot } from '../../core/git.js';
|
|
|
9
9
|
import { isSameLocation, withoutHomeRoots } from '../../core/same-location.js';
|
|
10
10
|
import { pruneHookLogDirs, MAX_HOOK_LOG_DIRS } from '../../core/hook-log-dirs.js';
|
|
11
11
|
import { getLedgerRoot } from '../../core/ledger-root.js';
|
|
12
|
+
import { describeEchoedValue } from '../../core/echo-value.js';
|
|
12
13
|
import { installViaFileCopy, composeScripts } from '../../targets/claude-code/installer.js';
|
|
13
14
|
import { formatOverlaySummary, formatSkillScopeSummary, formatTrackerAssetSummary, isPluginListUnchanged } from './install-report.js';
|
|
14
15
|
import { convergeTrackerArtifacts } from '../../targets/claude-code/tracker-install.js';
|
|
@@ -18,7 +19,7 @@ import { LEGACY_SKILL_NAMES } from '../../targets/claude-code/legacy.js';
|
|
|
18
19
|
import { detectPlatform, detectShell, getProfilePath, getSafeDeleteInfo, hasSafeDelete } from '../../core/safe-delete.js';
|
|
19
20
|
import { generateSafeDeleteBlock, installToProfile, removeFromProfile, getInstalledVersion, SAFE_DELETE_BLOCK_VERSION } from '../../core/safe-delete-install.js';
|
|
20
21
|
import { convergeAmbientHooks } from './ambient.js';
|
|
21
|
-
import { convergeMemoryHooks, drainMemoryQueue } from './memory.js';
|
|
22
|
+
import { convergeMemoryHooks, drainMemoryQueue, workingMemoryNote } from './memory.js';
|
|
22
23
|
import { addCaptureHooks, removeCaptureHooks } from './capture.js';
|
|
23
24
|
import { removeDreamHook } from './legacy-hooks.js';
|
|
24
25
|
import { addProxyHooks, removeProxyHooks, applyProxyEnv, stripProxyEnv, runProxyPreflight, buildRealPreflightDeps } from './proxy.js';
|
|
@@ -45,7 +46,7 @@ import { applyTrackerSentinel, effectiveTrackerServers, parseTrackerId, rearmTra
|
|
|
45
46
|
import { formatTrackerSummary, shouldRunTrackerStep, runTrackerStep, buildClackTrackerPrompts, } from './tracker-prompts.js';
|
|
46
47
|
import { shouldRunAttributionStep, runAttributionStep, buildClackAttributionPrompts, applyAttributionAnswer, attributionSeedFrom, } from './attribution-prompts.js';
|
|
47
48
|
import { convergeFromManifest } from '../../targets/claude-code/compliance-install.js';
|
|
48
|
-
import { convergeLearningVariants } from '../../targets/claude-code/learning-install.js';
|
|
49
|
+
import { convergeLearningVariants, installedVersionMatches, readRunningVersion } from '../../targets/claude-code/learning-install.js';
|
|
49
50
|
import { auditAndRecordClaudeMd, formatClaudeMdAuditNote, formatClaudeMdAuditUnavailable, } from '../../core/claude-md-audit.js';
|
|
50
51
|
import * as os from 'os';
|
|
51
52
|
// Re-export pure functions for tests (canonical source is post-install.ts)
|
|
@@ -507,6 +508,23 @@ export function buildHudOnlyManifest(existing, version, now) {
|
|
|
507
508
|
updatedAt: now,
|
|
508
509
|
};
|
|
509
510
|
}
|
|
511
|
+
/**
|
|
512
|
+
* The line `init --hud-only` prints when the version the manifest records is not the
|
|
513
|
+
* running version, or null when there is nothing to say. Pure.
|
|
514
|
+
*
|
|
515
|
+
* `--hud-only` refreshes the scripts under ~/.devflow and leaves the installed
|
|
516
|
+
* commands and agents alone, so after an upgrade or a downgrade the prompts and the
|
|
517
|
+
* scripts they call can disagree until a full init. The window is accepted; this
|
|
518
|
+
* line names it, in either direction, and ends with the remedy. A machine with no
|
|
519
|
+
* readable manifest records no version, so there is nothing to compare. The recorded
|
|
520
|
+
* version is hand-editable file content, so it prints through `describeEchoedValue`.
|
|
521
|
+
*/
|
|
522
|
+
export function formatHudOnlySkew(recordedVersion, runningVersion) {
|
|
523
|
+
if (recordedVersion === null || installedVersionMatches(recordedVersion, runningVersion))
|
|
524
|
+
return null;
|
|
525
|
+
return `The installed prompts come from devflow ${describeEchoedValue(recordedVersion)} and this CLI is ${runningVersion ?? 'of unknown version'}. ` +
|
|
526
|
+
'--hud-only refreshed only the scripts, so run `devflow init` to update the prompts.';
|
|
527
|
+
}
|
|
510
528
|
/**
|
|
511
529
|
* Decide what `init --scope <value>` does now that there is one install scope.
|
|
512
530
|
* Pure — the action performs the exit.
|
|
@@ -686,6 +704,9 @@ export const initCommand = new Command('init')
|
|
|
686
704
|
await writeManifest(devflowDir, buildHudOnlyManifest(existingHudManifest, version, new Date().toISOString()));
|
|
687
705
|
}
|
|
688
706
|
catch { /* non-fatal */ }
|
|
707
|
+
const hudOnlySkew = formatHudOnlySkew(existingHudManifest?.version ?? null, await readRunningVersion());
|
|
708
|
+
if (hudOnlySkew !== null)
|
|
709
|
+
p.log.warn(hudOnlySkew);
|
|
689
710
|
p.log.success('HUD installed');
|
|
690
711
|
p.log.info(`Configure later: ${color.cyan('devflow hud --status')}`);
|
|
691
712
|
p.outro(color.green('HUD-only install complete.'));
|
|
@@ -935,6 +956,11 @@ export const initCommand = new Command('init')
|
|
|
935
956
|
// alone, so init carries the prior value through untouched: it stamps the installed agents
|
|
936
957
|
// with it and writes it back to the manifest. Absent stays absent (the default list).
|
|
937
958
|
const trackerServers = seed.features.tracker.servers;
|
|
959
|
+
// The machine gate level (features.gateLevel) is set by `devflow gates --set` alone, so init
|
|
960
|
+
// carries the prior value through raw: no default, no narrowing, a stored `null` kept. The
|
|
961
|
+
// seed holds `undefined` only for an absent key or a --reset seed, and the full manifest
|
|
962
|
+
// write below then leaves the key out.
|
|
963
|
+
const gateLevel = seed.features.gateLevel;
|
|
938
964
|
let enabledFlags = { ...seed.flags };
|
|
939
965
|
// viewModeExplicit: true when --reset is passed; signals resolveFinalViewMode to let the
|
|
940
966
|
// seed-time view-mode win over an externally-set value in settings.json.
|
|
@@ -1145,12 +1171,7 @@ export const initCommand = new Command('init')
|
|
|
1145
1171
|
memoryEnabled = options.memory;
|
|
1146
1172
|
}
|
|
1147
1173
|
else {
|
|
1148
|
-
p.note(
|
|
1149
|
-
'compaction. Clear your session at any point and resume right\n' +
|
|
1150
|
-
'where you left off.\n\n' +
|
|
1151
|
-
'Runs a background agent on session stop that consumes additional\n' +
|
|
1152
|
-
'tokens. Consider skipping if token usage is a concern.\n' +
|
|
1153
|
-
'Applies to every project.', 'Working Memory');
|
|
1174
|
+
p.note(workingMemoryNote(), 'Working Memory');
|
|
1154
1175
|
const memoryChoice = await p.confirm({
|
|
1155
1176
|
message: 'Enable working memory? (Recommended)',
|
|
1156
1177
|
initialValue: seed.features.memory,
|
|
@@ -2324,6 +2345,8 @@ export const initCommand = new Command('init')
|
|
|
2324
2345
|
// through parseTrackerId (CLI), the typed wizard select, or the seed, which
|
|
2325
2346
|
// itself came through normalizeTrackerFeature on read.
|
|
2326
2347
|
tracker: { provider: trackerProvider, ...(trackerServers !== undefined ? { servers: trackerServers } : {}) },
|
|
2348
|
+
// The prior machine gate level, raw (see where `gateLevel` is read above).
|
|
2349
|
+
...(gateLevel !== undefined ? { gateLevel } : {}),
|
|
2327
2350
|
},
|
|
2328
2351
|
installedAt: existingManifest?.installedAt ?? now,
|
|
2329
2352
|
updatedAt: now,
|
|
@@ -56,6 +56,24 @@ const LEGACY_HOOK_SUFFIXES = {
|
|
|
56
56
|
'sidecar-evaluate', 'dream-evaluate',
|
|
57
57
|
].map(runHookSuffix),
|
|
58
58
|
};
|
|
59
|
+
/**
|
|
60
|
+
* The lowest Claude Code the memory worker runs on: the lowest version on which the
|
|
61
|
+
* worker's write was measured to be limited to its staged file (2026-10-15,
|
|
62
|
+
* docs/reference/platform-assumptions.md). Below it the worker does not run and logs one
|
|
63
|
+
* line. `background-memory-update` holds the same value as MEMORY_MIN_PERMISSION_VERSION;
|
|
64
|
+
* a test holds the two equal.
|
|
65
|
+
*/
|
|
66
|
+
export const MEMORY_MIN_PERMISSION_VERSION = '2.1.269';
|
|
67
|
+
/** The note `devflow init` shows at its working-memory step. */
|
|
68
|
+
export function workingMemoryNote() {
|
|
69
|
+
return ('Preserves session context across /clear, restarts, and context\n' +
|
|
70
|
+
'compaction. Clear your session at any point and resume right\n' +
|
|
71
|
+
'where you left off.\n\n' +
|
|
72
|
+
'Runs a background agent on session stop that consumes additional\n' +
|
|
73
|
+
'tokens. Consider skipping if token usage is a concern.\n' +
|
|
74
|
+
`Needs Claude Code ${MEMORY_MIN_PERMISSION_VERSION} or newer.\n` +
|
|
75
|
+
'Applies to every project.');
|
|
76
|
+
}
|
|
59
77
|
/** D-EXACT-HOOK-OWNER: the current memory hook for `marker` (hooks.ts). */
|
|
60
78
|
function isMemoryHook(marker) {
|
|
61
79
|
return devflowHookOwner([marker]);
|
package/dist/cli.js
CHANGED
|
@@ -21,6 +21,7 @@ import { agentsCommand } from './cli/commands/agents.js';
|
|
|
21
21
|
import { complianceCommand } from './cli/commands/compliance.js';
|
|
22
22
|
import { behaviorCommand } from './cli/commands/behavior.js';
|
|
23
23
|
import { trackerCommand } from './cli/commands/tracker.js';
|
|
24
|
+
import { gatesCommand } from './cli/commands/gates.js';
|
|
24
25
|
const __filename = fileURLToPath(import.meta.url);
|
|
25
26
|
const __dirname = dirname(__filename);
|
|
26
27
|
// Read version from package.json
|
|
@@ -51,6 +52,7 @@ program.addCommand(agentsCommand);
|
|
|
51
52
|
program.addCommand(complianceCommand);
|
|
52
53
|
program.addCommand(behaviorCommand);
|
|
53
54
|
program.addCommand(trackerCommand);
|
|
55
|
+
program.addCommand(gatesCommand);
|
|
54
56
|
// Handle no command (bare `devflow`) or unknown subcommand.
|
|
55
57
|
// When Commander sees an unrecognised first argument it does not route to any
|
|
56
58
|
// registered subcommand; instead the root action fires with that argument
|
|
@@ -187,9 +187,9 @@ If no tool produced findings: set `STATIC_FINDINGS` to `(none)`.
|
|
|
187
187
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> LEARNING=<on|off> KNOWLEDGE=<on|off>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on LEARNING=on KNOWLEDGE=off` instead.
|
|
190
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> LEARNING=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on LEARNING=on KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
191
191
|
|
|
192
|
-
The accepted line is the only source of these values
|
|
192
|
+
The accepted line is the only source of these values.
|
|
193
193
|
|
|
194
194
|
### Load DECISIONS_CONTEXT
|
|
195
195
|
|
|
@@ -28,12 +28,12 @@ Run a comprehensive code review of the current branch by spawning parallel revie
|
|
|
28
28
|
- **Exactly one listed:** load neither the skill nor the reference — that worktree is the only candidate, and Step 0c's Git agent validates its branch
|
|
29
29
|
2. **If `--path` flag provided:** use only that worktree, skip discovery
|
|
30
30
|
**`--path` validation**: Before proceeding, verify the path exists as a directory and appears in `git worktree list` output. If not: report error and stop.
|
|
31
|
-
3. **If only 1 reviewable worktree
|
|
31
|
+
3. **If only 1 reviewable worktree**: proceed as single-worktree flow — zero behavior change
|
|
32
32
|
4. **If multiple reviewable worktrees:** report "Found N worktrees with reviewable branches: {list with paths and branches}" and proceed with multi-worktree flow
|
|
33
33
|
|
|
34
|
-
#### Step 0b: Resolve the compliance lens
|
|
34
|
+
#### Step 0b: Resolve the compliance lens and gate level
|
|
35
35
|
|
|
36
|
-
**Produces:** COMPLIANCE_ACTIVE, COMPLIANCE_FRAMEWORKS
|
|
36
|
+
**Produces:** COMPLIANCE_ACTIVE, COMPLIANCE_FRAMEWORKS, GATE_LEVEL
|
|
37
37
|
|
|
38
38
|
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root when the run has one worktree:
|
|
39
39
|
|
|
@@ -41,16 +41,16 @@ Run a comprehensive code review of the current branch by spawning parallel revie
|
|
|
41
41
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> LEARNING=<on|off> KNOWLEDGE=<on|off>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on LEARNING=on KNOWLEDGE=off` instead.
|
|
44
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> LEARNING=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on LEARNING=on KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
45
45
|
|
|
46
|
-
The accepted line is the only source of these values
|
|
46
|
+
The accepted line is the only source of these values.
|
|
47
47
|
|
|
48
48
|
**Resolve the compliance lens** for each worktree root, from its settings line — the line resolved above for that root, by the settings block when this run has not yet resolved it (every framework reference is installed on every machine, so no file check decides it).
|
|
49
49
|
|
|
50
50
|
**Set the compliance lens** from that line: `COMPLIANCE_FRAMEWORKS` is the settings line's `COMPLIANCE` with `generic` written `none`: `off`, `none`, or the framework ids the machine and this repository declare.
|
|
51
51
|
|
|
52
52
|
`COMPLIANCE_ACTIVE` is `true` unless `COMPLIANCE_FRAMEWORKS` is `off`.
|
|
53
|
-
Keep each worktree's values for every downstream phase
|
|
53
|
+
Keep each worktree's values for every downstream phase.
|
|
54
54
|
|
|
55
55
|
#### Step 0b-ii: Resolve the evidence policy
|
|
56
56
|
|
|
@@ -100,7 +100,7 @@ Validate branch, commit if needed, push, create PR if needed.
|
|
|
100
100
|
Return: branch, base_branch, branch-slug, PR#"
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
In multi-worktree mode, spawn all pre-flight agents **in a single message
|
|
103
|
+
In multi-worktree mode, spawn all pre-flight agents **in a single message**.
|
|
104
104
|
|
|
105
105
|
**If BLOCKED:** In single-worktree mode, stop and report. In multi-worktree mode, report the failure but continue with other worktrees.
|
|
106
106
|
|
|
@@ -140,7 +140,7 @@ For each worktree, perform a single pass over timestamped directories:
|
|
|
140
140
|
2. Iterate once: accumulate CYCLE_NUMBER count for each directory containing `resolution-summary.md`; capture the first (most-recent) such directory as PRIOR_DIR.
|
|
141
141
|
3. If CYCLE_NUMBER = 0: set PRIOR_RESOLUTIONS=(none), CYCLE_NUMBER=1, proceed.
|
|
142
142
|
4. Otherwise: set CYCLE_NUMBER = count + 1. Read `{PRIOR_DIR}/resolution-summary.md` as PRIOR_RESOLUTIONS.
|
|
143
|
-
5. If `--full`: still load PRIOR_RESOLUTIONS
|
|
143
|
+
5. If `--full`: still load PRIOR_RESOLUTIONS.
|
|
144
144
|
|
|
145
145
|
#### Step 0e-ii: Convergence Assessment
|
|
146
146
|
|
|
@@ -186,7 +186,7 @@ Note: `auto` is NOT fail-open — under `auto`, the Git agent probes the reposit
|
|
|
186
186
|
### Phase 1: Analyze Changed Files
|
|
187
187
|
|
|
188
188
|
**Produces:** REVIEW_FOCUS_LIST, DIFF_CLASS, DIFF_FILES
|
|
189
|
-
**Requires:** DIFF_RANGE, REVIEW_DIR, COMPLIANCE_ACTIVE (from Step 0b)
|
|
189
|
+
**Requires:** DIFF_RANGE, REVIEW_DIR, COMPLIANCE_ACTIVE, GATE_LEVEL (from Step 0b)
|
|
190
190
|
|
|
191
191
|
Per worktree, in order. Each `git` command here writes to a file and prints nothing.
|
|
192
192
|
|
|
@@ -202,7 +202,7 @@ git -C "{WORKTREE_PATH}" diff --name-only --no-renames {DIFF_RANGE} > "{REVIEW_D
|
|
|
202
202
|
wc -l < "{REVIEW_DIR}/paths.txt"
|
|
203
203
|
```
|
|
204
204
|
|
|
205
|
-
Read `paths.txt` once when the count is about 40 or fewer, and in ranges of about 40 lines (Read with offset and limit) when it is more.
|
|
205
|
+
Read `paths.txt` once when the count is about 40 or fewer, and in ranges of about 40 lines (Read with offset and limit) when it is more.
|
|
206
206
|
|
|
207
207
|
Set `DIFF_CLASS` by these rules, in order; the first that decides wins:
|
|
208
208
|
|
|
@@ -219,7 +219,7 @@ Each reduced class runs only its focus set, every member reading `diff.patch`:
|
|
|
219
219
|
- `tests-only`: testing, reliability, consistency, security
|
|
220
220
|
- `lockfile-only`: dependencies, security
|
|
221
221
|
|
|
222
|
-
A mixed non-code diff runs the union of the sets of the classes it holds. Language and conditional triggers inside a reduced class are suppressed
|
|
222
|
+
A mixed non-code diff runs the union of the sets of the classes it holds. Language and conditional triggers inside a reduced class are suppressed.
|
|
223
223
|
|
|
224
224
|
#### Step 1.2: Choose the focuses
|
|
225
225
|
|
|
@@ -243,13 +243,27 @@ When `DIFF_CLASS` is `code`, read the file types from the paths in `paths.txt` t
|
|
|
243
243
|
| Docs or significant code | documentation |
|
|
244
244
|
| COMPLIANCE_ACTIVE AND diff touches regulated surface | compliance |
|
|
245
245
|
|
|
246
|
-
If `COMPLIANCE_ACTIVE` AND the diff touches regulated surface (data models, auth flows, logging/observability, payments, IaC, retention):
|
|
246
|
+
If `COMPLIANCE_ACTIVE` AND the diff touches regulated surface (data models, auth flows, logging/observability, payments, IaC, retention): on a `code` diff, add `compliance`.
|
|
247
247
|
|
|
248
248
|
**Language focus stamp.** The eight language focuses — `typescript`, `react`, `accessibility`, `ui-design`, `go`, `java`, `python`, `rust` — ship with optional plugins, and the installer stamps the ones installed on this machine onto this line, rewriting it on every install and on `uninstall --plugin`:
|
|
249
249
|
|
|
250
250
|
Installed language focuses: (none)
|
|
251
251
|
|
|
252
|
-
A language focus is spawned only when its file-type condition above fires AND its name appears in that stamped line. A focus missing from the line is never spawned, even when its trigger fires.
|
|
252
|
+
A language focus is spawned only when its file-type condition above fires AND its name appears in that stamped line. A focus missing from the line is never spawned, even when its trigger fires. On a `code` diff, REVIEW_FOCUS_LIST starts with the eight core focuses. Step 1.2b may narrow them; they are never stamp-gated.
|
|
253
|
+
|
|
254
|
+
#### Step 1.2b: Narrow by gate level
|
|
255
|
+
|
|
256
|
+
**Produces:** REVIEW_FOCUS_LIST, GATE_LEVEL
|
|
257
|
+
**Requires:** REVIEW_FOCUS_LIST, DIFF_CLASS, CHANGED_PATHS, GATE_LEVEL
|
|
258
|
+
|
|
259
|
+
**Gate level.** Narrow REVIEW_FOCUS_LIST, for every class, by this worktree's `GATE_LEVEL`. `full` keeps it and reads nothing.
|
|
260
|
+
|
|
261
|
+
At `standard` or `lean`, once per run, run `d="${CLAUDE_CONFIG_DIR:-}"; case "$d" in /*) ;; *) d="$HOME/.claude" ;; esac; printf '%s\n' "$d"` in Bash and Read `<that directory>/skills/devflow:agent-references/references/commands/code-review-levels.md` with the Read tool.
|
|
262
|
+
|
|
263
|
+
- Apply each class's row to that class's own set, then take the union of the results. A row only removes focuses.
|
|
264
|
+
- If the Read fails, or a row is missing or malformed, set `GATE_LEVEL` to `full` for every worktree of this run and say `level reference unreadable: full sets applied`.
|
|
265
|
+
- Security runs at every level and in every class.
|
|
266
|
+
- Compliance keeps the trigger above at every level.
|
|
253
267
|
|
|
254
268
|
#### Step 1.3: Write the diff files
|
|
255
269
|
|
|
@@ -383,9 +397,9 @@ Pass `FEATURE_KNOWLEDGE` to all Review agents alongside `DECISIONS_CONTEXT`.
|
|
|
383
397
|
**Produces:** REVIEW_FOCUS_OUTPUTS
|
|
384
398
|
**Requires:** DIFF_RANGE, REVIEW_DIR, TIMESTAMP, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, PR_DESCRIPTION, PRIOR_RESOLUTIONS, REVIEW_FOCUS_LIST, DIFF_CLASS, DIFF_FILES
|
|
385
399
|
|
|
386
|
-
Spawn Review agents **in a single message**,
|
|
400
|
+
Spawn Review agents **in a single message**, one per focus in REVIEW_FOCUS_LIST (max 20 per worktree):
|
|
387
401
|
|
|
388
|
-
- `code`: the 8 core reviews on the full `diff.patch
|
|
402
|
+
- `code`: the 8 core reviews on the full `diff.patch` (lean keeps 3), plus the language and conditional focuses Phase 1 added.
|
|
389
403
|
- `docs-only`, `tests-only`, `lockfile-only`: only the reduced set Phase 1 names, each reading `diff.patch`; a mixed non-code diff runs the union. No language or conditional focus is spawned, whatever its trigger.
|
|
390
404
|
|
|
391
405
|
| Focus | Runs | Pattern Skill | DIFF_FILE |
|
|
@@ -411,7 +425,7 @@ Spawn Review agents **in a single message**, for the focus set `DIFF_CLASS` sele
|
|
|
411
425
|
| documentation | conditional | devflow:documentation | diff.patch |
|
|
412
426
|
| compliance | diff-driven | devflow:compliance | diff.patch |
|
|
413
427
|
|
|
414
|
-
Review agent count: `code` runs 8 core
|
|
428
|
+
Review agent count: at `full`, `code` runs 8 core +1-12; `standard` runs up to 2 fewer; lean `code` runs 3-4; a reduced class or a mix runs 2-6.
|
|
415
429
|
|
|
416
430
|
**Set the compliance focus directive** from `COMPLIANCE_FRAMEWORKS`. `COMPLIANCE_FOCUS_DIRECTIVE` is this one line, with `<ids>` replaced by the value of `COMPLIANCE_FRAMEWORKS`; only the compliance focus's spawn carries it:
|
|
417
431
|
|
|
@@ -437,16 +451,16 @@ Follow devflow:apply-feature-knowledge for FEATURE_KNOWLEDGE — feature-specifi
|
|
|
437
451
|
IMPORTANT: Write report to {worktree_path}/.devflow/docs/reviews/{branch-slug}/{timestamp}/{focus}.md using Write tool"
|
|
438
452
|
```
|
|
439
453
|
|
|
440
|
-
In multi-worktree mode, process worktrees **sequentially
|
|
454
|
+
In multi-worktree mode, process worktrees **sequentially**: complete Phases 1-4 for one worktree before starting the next, so Review spawns never pile up.
|
|
441
455
|
|
|
442
456
|
### Phase 3: Synthesis → Review Comment (Sequential)
|
|
443
457
|
|
|
444
458
|
**Produces:** REVIEW_SUMMARY, PR_COMMENT
|
|
445
|
-
**Requires:** REVIEW_FOCUS_OUTPUTS, REVIEW_DIR, PR_INFO
|
|
459
|
+
**Requires:** REVIEW_FOCUS_OUTPUTS, REVIEW_DIR, PR_INFO, GATE_LEVEL, REVIEW_FOCUS_LIST
|
|
446
460
|
|
|
447
461
|
**WAIT** for Phase 2. For each worktree, run steps 3a and 3b in sequence:
|
|
448
462
|
|
|
449
|
-
**Step 3a — Synthesize agent** per worktree
|
|
463
|
+
**Step 3a — Synthesize agent** per worktree:
|
|
450
464
|
```
|
|
451
465
|
Agent(subagent_type="Synthesize", run_in_background=false):
|
|
452
466
|
"Mode: review
|
|
@@ -454,6 +468,8 @@ WORKTREE_PATH: {worktree_path} (omit if cwd)
|
|
|
454
468
|
REVIEW_BASE_DIR: {worktree_path}/.devflow/docs/reviews/{branch-slug}/{timestamp}
|
|
455
469
|
TIMESTAMP: {timestamp}
|
|
456
470
|
CYCLE_NUMBER: {cycle_number}
|
|
471
|
+
GATE_LEVEL: {GATE_LEVEL}
|
|
472
|
+
FOCUSES: {REVIEW_FOCUS_LIST}
|
|
457
473
|
PRIOR_RESOLUTIONS: <prior-resolution-summary>{prior_resolutions}</prior-resolution-summary>
|
|
458
474
|
Include Convergence Status section in review-summary.md.
|
|
459
475
|
Aggregate findings, determine merge recommendation.
|
|
@@ -486,8 +502,6 @@ Per worktree, after successful completion:
|
|
|
486
502
|
- Publication status: FULL (private repo) | FULL (config override) | STUB (public repository) | OFF (publication disabled by config) | STUB (visibility undeterminable) | STUB (evidence policy) (from Git agent)
|
|
487
503
|
- Artifact paths
|
|
488
504
|
|
|
489
|
-
In multi-worktree mode, report results per worktree.
|
|
490
|
-
|
|
491
505
|
## Architecture
|
|
492
506
|
|
|
493
507
|
```
|
|
@@ -495,29 +509,27 @@ In multi-worktree mode, report results per worktree.
|
|
|
495
509
|
│
|
|
496
510
|
├─ Phase 0: Worktree Discovery & Pre-flight
|
|
497
511
|
│ ├─ Step 0a: git worktree list → filter reviewable
|
|
498
|
-
│ ├─ Step 0b: Resolve the compliance lens
|
|
512
|
+
│ ├─ Step 0b: Resolve the compliance lens and gate level
|
|
499
513
|
│ ├─ Step 0c: Git agent (ensure-pr-ready) per worktree [parallel]
|
|
500
514
|
│ ├─ Step 0d: Incremental detection + timestamp setup per worktree
|
|
501
515
|
│ ├─ Step 0e-i: Load prior resolution-summary.md
|
|
502
|
-
│ ├─ Step 0e-ii: Convergence assessment (warn
|
|
516
|
+
│ ├─ Step 0e-ii: Convergence assessment (warn only)
|
|
503
517
|
│ └─ Step 0f: Resolve REVIEW_PUBLICATION per worktree (publication gate)
|
|
504
518
|
│
|
|
505
519
|
├─ Per worktree (SEQUENTIAL — one worktree at a time):
|
|
506
520
|
│ │
|
|
507
521
|
│ ├─ Phase 1: Analyze changed files
|
|
508
522
|
│ │ ├─ Classify the diff (paths.txt → DIFF_CLASS)
|
|
509
|
-
│ │ ├─ Choose the focuses (code
|
|
523
|
+
│ │ ├─ Choose the focuses (code: file types + the language stamp; all: the gate level)
|
|
510
524
|
│ │ └─ Write diff.patch and diff-{focus}.patch, by redirect
|
|
511
525
|
│ │
|
|
512
|
-
│ ├─ Phase 2: Reviews (PARALLEL within worktree)
|
|
513
|
-
│ │ ├─ code:
|
|
514
|
-
│ │ │ consistency, regression, testing, reliability (diff.patch)
|
|
515
|
-
│ │ ├─ code: + language (diff-{focus}.patch) and conditional Review agents
|
|
526
|
+
│ ├─ Phase 2: Reviews (PARALLEL within worktree), one per REVIEW_FOCUS_LIST focus
|
|
527
|
+
│ │ ├─ code: core (diff.patch), language (diff-{focus}.patch), conditional
|
|
516
528
|
│ │ └─ docs-only / tests-only / lockfile-only: the reduced set (diff.patch)
|
|
517
529
|
│ │
|
|
518
530
|
│ ├─ Phase 3: Synthesis → Review Comment (SEQUENTIAL within worktree)
|
|
519
531
|
│ │ ├─ Step 3a: Synthesize agent (mode: review, writes review-summary.md)
|
|
520
|
-
│ │ └─ Step 3b: Git agent (post-review-summary
|
|
532
|
+
│ │ └─ Step 3b: Git agent (post-review-summary)
|
|
521
533
|
│ │
|
|
522
534
|
│ └─ Phase 4: Write .last-review-head + display results
|
|
523
535
|
```
|
|
@@ -526,31 +538,27 @@ In multi-worktree mode, report results per worktree.
|
|
|
526
538
|
|
|
527
539
|
| Case | Handling |
|
|
528
540
|
|------|----------|
|
|
529
|
-
| `--full` in multi-worktree mode | Applies to all worktrees (global modifier) |
|
|
541
|
+
| `--full` in multi-worktree mode | Applies to all worktrees (global modifier). It sets the diff range, never the gate level |
|
|
530
542
|
| Review comment already posted | Git agent matches its own marker on the `{cycle, timestamp}` pair → skip silently (D7); a re-review in the same cycle (different timestamp) posts its own comment. The marker's format belongs to the operation; this caller passes the pair and never restates the literal |
|
|
531
|
-
|
|
|
532
|
-
|
|
|
533
|
-
|
|
|
534
|
-
|
|
|
535
|
-
|
|
|
536
|
-
| A
|
|
537
|
-
|
|
|
538
|
-
| Path listing above about 40 lines | The count is printed; `paths.txt` is read in ranges of about 40 lines |
|
|
543
|
+
| Docs-only diff | Its Step 1.1 set, narrowed by level |
|
|
544
|
+
| Tests-only diff | Its Step 1.1 set, narrowed by level |
|
|
545
|
+
| Lockfile-only diff | Its Step 1.1 set, narrowed by level |
|
|
546
|
+
| Mixed non-code diff | The union of the matching sets |
|
|
547
|
+
| A path matching no class pattern, or an empty path list | `code` (fail-safe) |
|
|
548
|
+
| A file moved across classes | `--no-renames` lists both paths, so a code path makes the diff `code` |
|
|
549
|
+
| Path listing above about 40 lines | Read in ranges (Step 1.1) |
|
|
539
550
|
| Language files changed, plugin not installed | The focus is absent from the stamped line: not spawned |
|
|
540
551
|
| Public repo (`auto` mode) | Git agent probes visibility, posts counts-only STUB comment; full report stays local |
|
|
541
552
|
| `reviewPublication: off` | Git agent skips posting the review comment (OFF) — except that, only when `EVIDENCE_POLICY` is `required`, Step 0f passes `stub` and a counts-only STUB comment posts |
|
|
542
553
|
|
|
543
554
|
## Backwards Compatibility
|
|
544
555
|
|
|
545
|
-
- **
|
|
546
|
-
- **Legacy flat layout**: If `{worktree}/.devflow/docs/reviews/{branch-slug}/` contains flat `*.md` files (no timestamped subdirectories), new runs create timestamped subdirectories. Old flat files remain untouched.
|
|
556
|
+
- **Gate level**: `full` runs the sets named here; the default `standard` and `lean` narrow them. `devflow gates --set full` keeps them.
|
|
547
557
|
|
|
548
558
|
## Principles
|
|
549
559
|
|
|
550
560
|
1. **Orchestration only** - Command spawns agents, doesn't do git/review work itself. The exceptions are the read-only Phase 0 probes (`git worktree list`, `git -C ... branch --show-current`, `git -C ... cat-file -t`), the bounded Phase 1 path listing (a redirect into `paths.txt`, a `wc -l` count and ranged reads) and the redirect-only patch writes (`diff.patch`, `diff-{focus}.patch`). Redirect-only writes print nothing, so no diff content reaches this thread
|
|
551
561
|
2. **Parallel, not background** - Multiple agents in one message, but `run_in_background=false` so phases complete before proceeding
|
|
552
562
|
3. **Git agent for git work** - All git operations go through Git agent, except the exceptions named in Principle 1; redirect-only writes print nothing
|
|
553
|
-
4. **
|
|
554
|
-
5. **
|
|
555
|
-
6. **Incremental by default** - Only review new changes unless `--full` specified
|
|
556
|
-
7. **Auto-discover worktrees** - One command handles all reviewable branches
|
|
563
|
+
4. **Honest reporting** - Display agent outputs directly
|
|
564
|
+
5. **Incremental by default** - Only review new changes unless `--full` specified
|
package/dist/commands/debug.md
CHANGED
|
@@ -38,9 +38,9 @@ $ARGUMENTS
|
|
|
38
38
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> LEARNING=<on|off> KNOWLEDGE=<on|off>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on LEARNING=on KNOWLEDGE=off` instead.
|
|
41
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> LEARNING=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on LEARNING=on KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
42
42
|
|
|
43
|
-
The accepted line is the only source of these values
|
|
43
|
+
The accepted line is the only source of these values.
|
|
44
44
|
|
|
45
45
|
From the same line: `COMPLIANCE_FRAMEWORKS` is the settings line's `COMPLIANCE` with `generic` written `none`: `off`, `none`, or the framework ids the machine and this repository declare.
|
|
46
46
|
|