devflow-kit 1.3.3 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +2 -1
- package/dist/commands/init.js +29 -0
- package/dist/commands/list.d.ts +21 -0
- package/dist/commands/list.js +71 -3
- package/dist/plugins.js +1 -1
- package/dist/utils/manifest.d.ts +45 -0
- package/dist/utils/manifest.js +100 -0
- package/package.json +1 -1
- package/plugins/devflow-accessibility/.claude-plugin/plugin.json +2 -3
- package/plugins/devflow-ambient/.claude-plugin/plugin.json +4 -1
- package/plugins/devflow-ambient/skills/ambient-router/SKILL.md +1 -1
- package/plugins/devflow-ambient/skills/ambient-router/references/skill-catalog.md +1 -0
- package/plugins/devflow-audit-claude/.claude-plugin/plugin.json +4 -1
- package/plugins/devflow-code-review/.claude-plugin/plugin.json +2 -3
- package/plugins/devflow-code-review/agents/git.md +13 -8
- package/plugins/devflow-code-review/agents/reviewer.md +42 -5
- package/plugins/devflow-code-review/agents/synthesizer.md +12 -5
- package/plugins/devflow-code-review/commands/code-review-teams.md +4 -4
- package/plugins/devflow-code-review/commands/code-review.md +8 -5
- package/plugins/devflow-core-skills/.claude-plugin/plugin.json +3 -3
- package/plugins/devflow-core-skills/skills/search-first/SKILL.md +133 -0
- package/plugins/devflow-core-skills/skills/search-first/references/evaluation-criteria.md +101 -0
- package/plugins/devflow-debug/.claude-plugin/plugin.json +2 -3
- package/plugins/devflow-debug/agents/git.md +13 -8
- package/plugins/devflow-frontend-design/.claude-plugin/plugin.json +2 -3
- package/plugins/devflow-go/.claude-plugin/plugin.json +2 -3
- package/plugins/devflow-implement/.claude-plugin/plugin.json +2 -3
- package/plugins/devflow-implement/agents/coder.md +16 -13
- package/plugins/devflow-implement/agents/git.md +13 -8
- package/plugins/devflow-implement/agents/synthesizer.md +12 -5
- package/plugins/devflow-implement/commands/implement-teams.md +6 -11
- package/plugins/devflow-implement/commands/implement.md +6 -11
- package/plugins/devflow-java/.claude-plugin/plugin.json +2 -3
- package/plugins/devflow-python/.claude-plugin/plugin.json +2 -3
- package/plugins/devflow-react/.claude-plugin/plugin.json +2 -3
- package/plugins/devflow-resolve/.claude-plugin/plugin.json +2 -3
- package/plugins/devflow-resolve/agents/git.md +13 -8
- package/plugins/devflow-rust/.claude-plugin/plugin.json +2 -3
- package/plugins/devflow-self-review/.claude-plugin/plugin.json +4 -1
- package/plugins/devflow-specify/.claude-plugin/plugin.json +2 -3
- package/plugins/devflow-specify/agents/synthesizer.md +12 -5
- package/plugins/devflow-typescript/.claude-plugin/plugin.json +2 -3
- package/shared/agents/coder.md +16 -13
- package/shared/agents/git.md +13 -8
- package/shared/agents/reviewer.md +42 -5
- package/shared/agents/synthesizer.md +12 -5
- package/shared/skills/ambient-router/SKILL.md +1 -1
- package/shared/skills/ambient-router/references/skill-catalog.md +1 -0
- package/shared/skills/search-first/SKILL.md +133 -0
- package/shared/skills/search-first/references/evaluation-criteria.md +101 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,31 @@ All notable changes to DevFlow will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.5.0] - 2026-03-13
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Search-first skill** (#111) — New skill enforcing research before building custom utility code. 4-phase loop: Need Analysis → Search (via Explore subagent) → Evaluate → Decide (Adopt/Extend/Compose/Build)
|
|
12
|
+
- **Reviewer confidence thresholds** (#113) — Each review finding now includes a visible confidence score (0-100%). Only ≥80% findings appear in main sections; lower-confidence items go to a capped Suggestions section. Adds consolidation rules to group similar issues and skip stylistic preferences
|
|
13
|
+
- **Version manifest** (#91) — Tracks installed version, plugins, and features in `manifest.json`. Enables upgrade detection during `devflow init` and shows install status in `devflow list`
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **Synthesizer review glob** — Fixed `${REVIEW_BASE_DIR}/*-report.*.md` glob that matched zero reviewer files; now uses `${REVIEW_BASE_DIR}/*.md` with self-exclusion
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## [1.4.0] - 2026-03-09
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- **Smart branch naming** — `/implement #42` auto-derives branch names from issue labels and title (e.g., `feature/42-add-jwt-auth`); free-text tasks infer type from keywords (e.g., `/implement fix login bug` → `fix/login-bug`)
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- **Code review file detection** — Corrected file detection and skill check logic in `/code-review`
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
- **Author standardization** — Unified author name to Dean0x across marketplace and plugin manifests
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
8
33
|
## [1.3.3] - 2026-03-09
|
|
9
34
|
|
|
10
35
|
### Changed
|
|
@@ -840,6 +865,9 @@ devflow init
|
|
|
840
865
|
|
|
841
866
|
---
|
|
842
867
|
|
|
868
|
+
[Unreleased]: https://github.com/dean0x/devflow/compare/v1.4.0...HEAD
|
|
869
|
+
[1.5.0]: https://github.com/dean0x/devflow/compare/v1.4.0...v1.5.0
|
|
870
|
+
[1.4.0]: https://github.com/dean0x/devflow/compare/v1.3.3...v1.4.0
|
|
843
871
|
[1.3.3]: https://github.com/dean0x/devflow/compare/v1.3.2...v1.3.3
|
|
844
872
|
[1.3.2]: https://github.com/dean0x/devflow/compare/v1.3.1...v1.3.2
|
|
845
873
|
[1.3.1]: https://github.com/dean0x/devflow/compare/v1.3.0...v1.3.1
|
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ DevFlow adds structured commands that handle the full lifecycle: specify feature
|
|
|
24
24
|
- **Full-lifecycle implementation** — spec, explore, plan, code, validate, refine in one command
|
|
25
25
|
- **Automatic session memory** — survives restarts, `/clear`, and context compaction
|
|
26
26
|
- **Parallel debugging** — competing hypotheses investigated simultaneously
|
|
27
|
-
- **
|
|
27
|
+
- **31 quality skills** — 9 auto-activating core, 8 optional language/ecosystem, plus specialized review and agent skills
|
|
28
28
|
|
|
29
29
|
## Quick Start
|
|
30
30
|
|
|
@@ -120,6 +120,7 @@ The `devflow-core-skills` plugin provides quality enforcement skills that activa
|
|
|
120
120
|
| `test-driven-development` | Implementing new features (RED-GREEN-REFACTOR) |
|
|
121
121
|
| `test-patterns` | Writing or modifying tests |
|
|
122
122
|
| `input-validation` | Creating API endpoints |
|
|
123
|
+
| `search-first` | Adding utilities, helpers, or infrastructure code |
|
|
123
124
|
|
|
124
125
|
## Language & Ecosystem Plugins
|
|
125
126
|
|
package/dist/commands/init.js
CHANGED
|
@@ -15,6 +15,7 @@ import { detectPlatform, detectShell, getProfilePath, getSafeDeleteInfo, hasSafe
|
|
|
15
15
|
import { generateSafeDeleteBlock, installToProfile, removeFromProfile, getInstalledVersion, SAFE_DELETE_BLOCK_VERSION } from '../utils/safe-delete-install.js';
|
|
16
16
|
import { addAmbientHook } from './ambient.js';
|
|
17
17
|
import { addMemoryHooks, removeMemoryHooks } from './memory.js';
|
|
18
|
+
import { readManifest, writeManifest, resolvePluginList, detectUpgrade } from '../utils/manifest.js';
|
|
18
19
|
// Re-export pure functions for tests (canonical source is post-install.ts)
|
|
19
20
|
export { substituteSettingsTemplate, computeGitignoreAppend, applyTeamsConfig, stripTeamsConfig, mergeDenyList } from '../utils/post-install.js';
|
|
20
21
|
export { addAmbientHook, removeAmbientHook, hasAmbientHook } from './ambient.js';
|
|
@@ -238,6 +239,17 @@ export const initCommand = new Command('init')
|
|
|
238
239
|
p.log.error(`Path configuration error: ${error instanceof Error ? error.message : error}`);
|
|
239
240
|
process.exit(1);
|
|
240
241
|
}
|
|
242
|
+
// Check existing manifest for upgrade detection
|
|
243
|
+
const existingManifest = await readManifest(devflowDir);
|
|
244
|
+
if (existingManifest) {
|
|
245
|
+
const upgrade = detectUpgrade(version, existingManifest.version);
|
|
246
|
+
if (upgrade.isUpgrade) {
|
|
247
|
+
s.message(`Upgrading from v${upgrade.previousVersion} to v${version}`);
|
|
248
|
+
}
|
|
249
|
+
else if (upgrade.isSameVersion) {
|
|
250
|
+
s.message('Reinstalling same version');
|
|
251
|
+
}
|
|
252
|
+
}
|
|
241
253
|
// Validate target directory
|
|
242
254
|
s.message('Validating target directory');
|
|
243
255
|
if (scope === 'local') {
|
|
@@ -519,6 +531,23 @@ export const initCommand = new Command('init')
|
|
|
519
531
|
p.log.info(`Deduplication: ${skillsMap.size} unique skills (from ${totalSkillDeclarations} declarations)`);
|
|
520
532
|
p.log.info(`Deduplication: ${agentsMap.size} unique agents (from ${totalAgentDeclarations} declarations)`);
|
|
521
533
|
}
|
|
534
|
+
// Write installation manifest for upgrade tracking (non-fatal — install already succeeded)
|
|
535
|
+
const installedPluginNames = pluginsToInstall.map(pl => pl.name);
|
|
536
|
+
const now = new Date().toISOString();
|
|
537
|
+
const manifestData = {
|
|
538
|
+
version,
|
|
539
|
+
plugins: resolvePluginList(installedPluginNames, existingManifest, !!options.plugin),
|
|
540
|
+
scope,
|
|
541
|
+
features: { teams: teamsEnabled, ambient: ambientEnabled, memory: memoryEnabled },
|
|
542
|
+
installedAt: existingManifest?.installedAt ?? now,
|
|
543
|
+
updatedAt: now,
|
|
544
|
+
};
|
|
545
|
+
try {
|
|
546
|
+
await writeManifest(devflowDir, manifestData);
|
|
547
|
+
}
|
|
548
|
+
catch (error) {
|
|
549
|
+
p.log.warn(`Failed to write installation manifest (install succeeded): ${error instanceof Error ? error.message : error}`);
|
|
550
|
+
}
|
|
522
551
|
p.outro(color.green('Ready! Run any command in Claude Code to get started.'));
|
|
523
552
|
});
|
|
524
553
|
//# sourceMappingURL=init.js.map
|
package/dist/commands/list.d.ts
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
+
import { type ManifestData } from '../utils/manifest.js';
|
|
3
|
+
/**
|
|
4
|
+
* Format manifest feature flags into a human-readable comma-separated string.
|
|
5
|
+
* Returns 'none' when no features are enabled.
|
|
6
|
+
*/
|
|
7
|
+
export declare function formatFeatures(features: ManifestData['features']): string;
|
|
8
|
+
/**
|
|
9
|
+
* Determine effective installation scope based on which manifest was found.
|
|
10
|
+
* Local scope takes precedence when a local manifest exists.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveScope(localManifest: ManifestData | null): 'user' | 'local';
|
|
13
|
+
/**
|
|
14
|
+
* Compute the install status indicator for a plugin.
|
|
15
|
+
* Returns 'installed', 'not_installed', or 'unknown' (when no manifest exists).
|
|
16
|
+
*/
|
|
17
|
+
export declare function getPluginInstallStatus(pluginName: string, installedPlugins: ReadonlySet<string>, hasManifest: boolean): 'installed' | 'not_installed' | 'unknown';
|
|
18
|
+
/**
|
|
19
|
+
* Format the commands portion of a plugin entry.
|
|
20
|
+
* Returns the comma-separated command list or '(skills only)' for skill-only plugins.
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatPluginCommands(commands: string[]): string;
|
|
2
23
|
export declare const listCommand: Command;
|
|
3
24
|
//# sourceMappingURL=list.d.ts.map
|
package/dist/commands/list.js
CHANGED
|
@@ -2,19 +2,87 @@ import { Command } from 'commander';
|
|
|
2
2
|
import * as p from '@clack/prompts';
|
|
3
3
|
import color from 'picocolors';
|
|
4
4
|
import { DEVFLOW_PLUGINS } from '../plugins.js';
|
|
5
|
+
import { getDevFlowDirectory } from '../utils/paths.js';
|
|
6
|
+
import { getGitRoot } from '../utils/git.js';
|
|
7
|
+
import { readManifest } from '../utils/manifest.js';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
/**
|
|
10
|
+
* Format manifest feature flags into a human-readable comma-separated string.
|
|
11
|
+
* Returns 'none' when no features are enabled.
|
|
12
|
+
*/
|
|
13
|
+
export function formatFeatures(features) {
|
|
14
|
+
return [
|
|
15
|
+
features.teams ? 'teams' : null,
|
|
16
|
+
features.ambient ? 'ambient' : null,
|
|
17
|
+
features.memory ? 'memory' : null,
|
|
18
|
+
].filter(Boolean).join(', ') || 'none';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Determine effective installation scope based on which manifest was found.
|
|
22
|
+
* Local scope takes precedence when a local manifest exists.
|
|
23
|
+
*/
|
|
24
|
+
export function resolveScope(localManifest) {
|
|
25
|
+
return localManifest ? 'local' : 'user';
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Compute the install status indicator for a plugin.
|
|
29
|
+
* Returns 'installed', 'not_installed', or 'unknown' (when no manifest exists).
|
|
30
|
+
*/
|
|
31
|
+
export function getPluginInstallStatus(pluginName, installedPlugins, hasManifest) {
|
|
32
|
+
if (!hasManifest)
|
|
33
|
+
return 'unknown';
|
|
34
|
+
return installedPlugins.has(pluginName) ? 'installed' : 'not_installed';
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Format the commands portion of a plugin entry.
|
|
38
|
+
* Returns the comma-separated command list or '(skills only)' for skill-only plugins.
|
|
39
|
+
*/
|
|
40
|
+
export function formatPluginCommands(commands) {
|
|
41
|
+
return commands.length > 0 ? commands.join(', ') : '(skills only)';
|
|
42
|
+
}
|
|
5
43
|
export const listCommand = new Command('list')
|
|
6
44
|
.description('List available DevFlow plugins')
|
|
7
|
-
.action(() => {
|
|
45
|
+
.action(async () => {
|
|
8
46
|
p.intro(color.bgCyan(color.black(' DevFlow Plugins ')));
|
|
47
|
+
// Resolve user manifest and git root in parallel (independent I/O)
|
|
48
|
+
const userDevflowDir = getDevFlowDirectory();
|
|
49
|
+
const [gitRoot, userManifest] = await Promise.all([
|
|
50
|
+
getGitRoot(),
|
|
51
|
+
readManifest(userDevflowDir),
|
|
52
|
+
]);
|
|
53
|
+
const localDevflowDir = gitRoot ? path.join(gitRoot, '.devflow') : null;
|
|
54
|
+
const localManifest = localDevflowDir ? await readManifest(localDevflowDir) : null;
|
|
55
|
+
const manifest = localManifest ?? userManifest;
|
|
56
|
+
// Show install status if manifest exists
|
|
57
|
+
if (manifest) {
|
|
58
|
+
const installedAt = new Date(manifest.installedAt).toLocaleDateString();
|
|
59
|
+
const updatedAt = new Date(manifest.updatedAt).toLocaleDateString();
|
|
60
|
+
const scope = resolveScope(localManifest);
|
|
61
|
+
const features = formatFeatures(manifest.features);
|
|
62
|
+
p.note(`${color.dim('Version:')} ${color.cyan(`v${manifest.version}`)}\n` +
|
|
63
|
+
`${color.dim('Scope:')} ${scope}\n` +
|
|
64
|
+
`${color.dim('Features:')} ${features}\n` +
|
|
65
|
+
`${color.dim('Installed:')} ${installedAt}` +
|
|
66
|
+
(installedAt !== updatedAt ? ` ${color.dim('Updated:')} ${updatedAt}` : ''), 'Installation');
|
|
67
|
+
}
|
|
68
|
+
const installedPlugins = new Set(manifest?.plugins ?? []);
|
|
69
|
+
const hasManifest = manifest !== null;
|
|
9
70
|
const maxNameLen = Math.max(...DEVFLOW_PLUGINS.map(p => p.name.length));
|
|
10
71
|
const pluginList = DEVFLOW_PLUGINS
|
|
11
72
|
.map(plugin => {
|
|
12
|
-
const cmds = plugin.commands
|
|
73
|
+
const cmds = formatPluginCommands(plugin.commands);
|
|
13
74
|
const optionalTag = plugin.optional ? color.dim(' (optional)') : '';
|
|
14
|
-
|
|
75
|
+
const status = getPluginInstallStatus(plugin.name, installedPlugins, hasManifest);
|
|
76
|
+
const installedTag = status === 'installed' ? color.green(' ✓')
|
|
77
|
+
: status === 'not_installed' ? color.dim(' ✗')
|
|
78
|
+
: '';
|
|
79
|
+
return `${color.cyan(plugin.name.padEnd(maxNameLen + 2))}${color.dim(plugin.description)}${optionalTag}${installedTag}\n${' '.repeat(maxNameLen + 2)}${color.yellow(cmds)}`;
|
|
15
80
|
})
|
|
16
81
|
.join('\n\n');
|
|
17
82
|
p.note(pluginList, 'Available plugins');
|
|
83
|
+
if (!manifest) {
|
|
84
|
+
p.log.info(color.dim('Run `devflow init` for install tracking'));
|
|
85
|
+
}
|
|
18
86
|
p.outro(color.dim('Install with: npx devflow-kit init --plugin=<name>'));
|
|
19
87
|
});
|
|
20
88
|
//# sourceMappingURL=list.js.map
|
package/dist/plugins.js
CHANGED
|
@@ -10,7 +10,7 @@ export const DEVFLOW_PLUGINS = [
|
|
|
10
10
|
description: 'Auto-activating quality enforcement (foundation layer)',
|
|
11
11
|
commands: [],
|
|
12
12
|
agents: [],
|
|
13
|
-
skills: ['core-patterns', 'docs-framework', 'git-safety', 'git-workflow', 'github-patterns', 'input-validation', 'test-driven-development', 'test-patterns'],
|
|
13
|
+
skills: ['core-patterns', 'docs-framework', 'git-safety', 'git-workflow', 'github-patterns', 'input-validation', 'search-first', 'test-driven-development', 'test-patterns'],
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
name: 'devflow-specify',
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manifest data tracked for each DevFlow installation.
|
|
3
|
+
*/
|
|
4
|
+
export interface ManifestData {
|
|
5
|
+
version: string;
|
|
6
|
+
plugins: string[];
|
|
7
|
+
scope: 'user' | 'local';
|
|
8
|
+
features: {
|
|
9
|
+
teams: boolean;
|
|
10
|
+
ambient: boolean;
|
|
11
|
+
memory: boolean;
|
|
12
|
+
};
|
|
13
|
+
installedAt: string;
|
|
14
|
+
updatedAt: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Read and parse the manifest file. Returns null if missing or corrupt.
|
|
18
|
+
*/
|
|
19
|
+
export declare function readManifest(devflowDir: string): Promise<ManifestData | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Write manifest to disk. Creates parent directory if needed.
|
|
22
|
+
*/
|
|
23
|
+
export declare function writeManifest(devflowDir: string, data: ManifestData): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Merge new plugins into existing plugin list (union, no duplicates).
|
|
26
|
+
* Preserves order: existing plugins first, then new ones appended.
|
|
27
|
+
*/
|
|
28
|
+
export declare function mergeManifestPlugins(existing: string[], newPlugins: string[]): string[];
|
|
29
|
+
/**
|
|
30
|
+
* Detect upgrade/downgrade/same version status.
|
|
31
|
+
*/
|
|
32
|
+
export interface UpgradeInfo {
|
|
33
|
+
isUpgrade: boolean;
|
|
34
|
+
isDowngrade: boolean;
|
|
35
|
+
isSameVersion: boolean;
|
|
36
|
+
previousVersion: string | null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolve the final plugin list for a manifest write.
|
|
40
|
+
* On partial installs (--plugin flag), merge newly installed plugins into
|
|
41
|
+
* the existing manifest's plugin list. On full installs, replace entirely.
|
|
42
|
+
*/
|
|
43
|
+
export declare function resolvePluginList(installedPluginNames: string[], existingManifest: ManifestData | null, isPartialInstall: boolean): string[];
|
|
44
|
+
export declare function detectUpgrade(currentVersion: string, installedVersion: string | null): UpgradeInfo;
|
|
45
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Read and parse the manifest file. Returns null if missing or corrupt.
|
|
5
|
+
*/
|
|
6
|
+
export async function readManifest(devflowDir) {
|
|
7
|
+
const manifestPath = path.join(devflowDir, 'manifest.json');
|
|
8
|
+
try {
|
|
9
|
+
const content = await fs.readFile(manifestPath, 'utf-8');
|
|
10
|
+
const data = JSON.parse(content);
|
|
11
|
+
if (!data.version ||
|
|
12
|
+
!Array.isArray(data.plugins) ||
|
|
13
|
+
!data.scope ||
|
|
14
|
+
typeof data.features !== 'object' ||
|
|
15
|
+
data.features === null ||
|
|
16
|
+
typeof data.features.teams !== 'boolean' ||
|
|
17
|
+
typeof data.features.ambient !== 'boolean' ||
|
|
18
|
+
typeof data.features.memory !== 'boolean' ||
|
|
19
|
+
typeof data.installedAt !== 'string' ||
|
|
20
|
+
typeof data.updatedAt !== 'string') {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return data;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Write manifest to disk. Creates parent directory if needed.
|
|
31
|
+
*/
|
|
32
|
+
export async function writeManifest(devflowDir, data) {
|
|
33
|
+
await fs.mkdir(devflowDir, { recursive: true });
|
|
34
|
+
const manifestPath = path.join(devflowDir, 'manifest.json');
|
|
35
|
+
await fs.writeFile(manifestPath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Merge new plugins into existing plugin list (union, no duplicates).
|
|
39
|
+
* Preserves order: existing plugins first, then new ones appended.
|
|
40
|
+
*/
|
|
41
|
+
export function mergeManifestPlugins(existing, newPlugins) {
|
|
42
|
+
const merged = [...existing];
|
|
43
|
+
for (const plugin of newPlugins) {
|
|
44
|
+
if (!merged.includes(plugin)) {
|
|
45
|
+
merged.push(plugin);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return merged;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Compare two semver strings. Returns -1, 0, or 1.
|
|
52
|
+
* Handles simple x.y.z versions; returns null for unparseable input.
|
|
53
|
+
*
|
|
54
|
+
* Note: Pre-release suffixes (e.g., `-beta.1`, `-rc.2`) are silently ignored.
|
|
55
|
+
* `1.0.0-beta.1` and `1.0.0` compare as equal. Build metadata is also ignored.
|
|
56
|
+
*/
|
|
57
|
+
function compareSemver(a, b) {
|
|
58
|
+
const parse = (v) => {
|
|
59
|
+
const match = v.match(/^v?(\d+)\.(\d+)\.(\d+)/);
|
|
60
|
+
return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : [];
|
|
61
|
+
};
|
|
62
|
+
const pa = parse(a);
|
|
63
|
+
const pb = parse(b);
|
|
64
|
+
if (pa.length === 0 || pb.length === 0)
|
|
65
|
+
return null;
|
|
66
|
+
for (let i = 0; i < 3; i++) {
|
|
67
|
+
if (pa[i] > pb[i])
|
|
68
|
+
return 1;
|
|
69
|
+
if (pa[i] < pb[i])
|
|
70
|
+
return -1;
|
|
71
|
+
}
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Resolve the final plugin list for a manifest write.
|
|
76
|
+
* On partial installs (--plugin flag), merge newly installed plugins into
|
|
77
|
+
* the existing manifest's plugin list. On full installs, replace entirely.
|
|
78
|
+
*/
|
|
79
|
+
export function resolvePluginList(installedPluginNames, existingManifest, isPartialInstall) {
|
|
80
|
+
if (existingManifest && isPartialInstall) {
|
|
81
|
+
return mergeManifestPlugins(existingManifest.plugins, installedPluginNames);
|
|
82
|
+
}
|
|
83
|
+
return installedPluginNames;
|
|
84
|
+
}
|
|
85
|
+
export function detectUpgrade(currentVersion, installedVersion) {
|
|
86
|
+
if (!installedVersion) {
|
|
87
|
+
return { isUpgrade: false, isDowngrade: false, isSameVersion: false, previousVersion: null };
|
|
88
|
+
}
|
|
89
|
+
const cmp = compareSemver(currentVersion, installedVersion);
|
|
90
|
+
if (cmp === null) {
|
|
91
|
+
return { isUpgrade: false, isDowngrade: false, isSameVersion: false, previousVersion: installedVersion };
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
isUpgrade: cmp > 0,
|
|
95
|
+
isDowngrade: cmp < 0,
|
|
96
|
+
isSameVersion: cmp === 0,
|
|
97
|
+
previousVersion: installedVersion,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=manifest.js.map
|
package/package.json
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
"name": "devflow-accessibility",
|
|
3
3
|
"description": "Web accessibility patterns - WCAG compliance, ARIA roles, keyboard navigation, focus management",
|
|
4
4
|
"author": {
|
|
5
|
-
"name": "
|
|
6
|
-
"email": "dean@keren.dev"
|
|
5
|
+
"name": "Dean0x"
|
|
7
6
|
},
|
|
8
|
-
"version": "1.
|
|
7
|
+
"version": "1.5.0",
|
|
9
8
|
"homepage": "https://github.com/dean0x/devflow",
|
|
10
9
|
"repository": "https://github.com/dean0x/devflow",
|
|
11
10
|
"license": "MIT",
|
|
@@ -54,7 +54,7 @@ Based on classified intent, read the following skills to inform your response.
|
|
|
54
54
|
|
|
55
55
|
| Intent | Primary Skills | Secondary (if file type matches) |
|
|
56
56
|
|--------|---------------|----------------------------------|
|
|
57
|
-
| **BUILD** | test-driven-development, implementation-patterns | typescript (.ts), react (.tsx/.jsx), go (.go), java (.java), python (.py), rust (.rs), frontend-design (CSS/UI), input-validation (forms/API), security-patterns (auth/crypto) |
|
|
57
|
+
| **BUILD** | test-driven-development, implementation-patterns, search-first | typescript (.ts), react (.tsx/.jsx), go (.go), java (.java), python (.py), rust (.rs), frontend-design (CSS/UI), input-validation (forms/API), security-patterns (auth/crypto) |
|
|
58
58
|
| **DEBUG** | test-patterns, core-patterns | git-safety (if git operations involved) |
|
|
59
59
|
| **REVIEW** | self-review, core-patterns | test-patterns |
|
|
60
60
|
| **PLAN** | implementation-patterns | core-patterns |
|
|
@@ -12,6 +12,7 @@ These skills may be loaded during GUIDED-depth ambient routing.
|
|
|
12
12
|
|-------|-------------|---------------|
|
|
13
13
|
| test-driven-development | Always for BUILD | `*.ts`, `*.tsx`, `*.js`, `*.jsx`, `*.py` |
|
|
14
14
|
| implementation-patterns | Always for BUILD | Any code file |
|
|
15
|
+
| search-first | Always for BUILD | Any code file |
|
|
15
16
|
| typescript | TypeScript files in scope | `*.ts`, `*.tsx` |
|
|
16
17
|
| react | React components in scope | `*.tsx`, `*.jsx` |
|
|
17
18
|
| frontend-design | UI/styling work | `*.css`, `*.scss`, `*.tsx` with styling keywords |
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
"name": "devflow-code-review",
|
|
3
3
|
"description": "Comprehensive code review with parallel specialized agents covering security, architecture, performance, and more",
|
|
4
4
|
"author": {
|
|
5
|
-
"name": "
|
|
6
|
-
"email": "dean@keren.dev"
|
|
5
|
+
"name": "Dean0x"
|
|
7
6
|
},
|
|
8
|
-
"version": "1.
|
|
7
|
+
"version": "1.5.0",
|
|
9
8
|
"homepage": "https://github.com/dean0x/devflow",
|
|
10
9
|
"repository": "https://github.com/dean0x/devflow",
|
|
11
10
|
"license": "MIT",
|
|
@@ -21,7 +21,7 @@ The orchestrator provides:
|
|
|
21
21
|
|-----------|---------|----------------|
|
|
22
22
|
| `ensure-pr-ready` | Pre-flight for /review: commit, push, create PR | - |
|
|
23
23
|
| `validate-branch` | Pre-flight for /resolve: check branch state | - |
|
|
24
|
-
| `setup-task` | Create feature branch and fetch issue | `
|
|
24
|
+
| `setup-task` | Create feature branch and fetch issue | `BASE_BRANCH`, `ISSUE_INPUT` (optional), `TASK_DESCRIPTION` (optional) |
|
|
25
25
|
| `fetch-issue` | Fetch GitHub issue for implementation | `ISSUE_INPUT` (number or search term) |
|
|
26
26
|
| `comment-pr` | Create PR inline comments for review findings | `PR_NUMBER`, `REVIEW_BASE_DIR`, `TIMESTAMP` |
|
|
27
27
|
| `manage-debt` | Update tech debt backlog with pre-existing issues | `REVIEW_DIR`, `TIMESTAMP` |
|
|
@@ -101,25 +101,30 @@ Pre-flight validation for `/resolve`. Checks branch state without modifications.
|
|
|
101
101
|
|
|
102
102
|
## Operation: setup-task
|
|
103
103
|
|
|
104
|
-
Set up task environment: create feature branch and optionally fetch issue.
|
|
104
|
+
Set up task environment: derive branch name, create feature branch, and optionally fetch issue.
|
|
105
105
|
|
|
106
106
|
**Input:**
|
|
107
|
-
- `TASK_ID`: Unique task identifier (becomes branch name)
|
|
108
107
|
- `BASE_BRANCH`: Branch to create from (track this for PR target)
|
|
109
108
|
- `ISSUE_INPUT` (optional): Issue number to fetch
|
|
109
|
+
- `TASK_DESCRIPTION` (optional): Free-text task description (when no issue)
|
|
110
110
|
|
|
111
111
|
**Process:**
|
|
112
112
|
1. Record current branch as BASE_BRANCH for later PR targeting
|
|
113
|
-
2.
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
2. **Derive branch name:**
|
|
114
|
+
- If `ISSUE_INPUT` provided: fetch issue via GitHub API first, then derive branch name as `{type}/{number}-{slug}` where:
|
|
115
|
+
- `type` is inferred from issue labels: `bug` → `fix`, `documentation` or `docs` → `docs`, `refactor` → `refactor`, `chore` or `maintenance` → `chore`, default → `feature`
|
|
116
|
+
- `slug` is the issue title: lowercased, non-alphanumeric replaced with hyphens, consecutive hyphens collapsed, trimmed, max 40 characters
|
|
117
|
+
- If `TASK_DESCRIPTION` provided (no issue): infer type from description keywords (e.g., "fix login bug" → `fix`, "refactor auth" → `refactor`, "add JWT" → `feature`, "update docs" → `docs`, "chore: cleanup" → `chore`), then slugify description as `{type}/{slug}` (max 40 chars)
|
|
118
|
+
- If neither: fallback to `task-{YYYY-MM-DD_HHMM}`
|
|
119
|
+
3. Create and checkout feature branch: `git checkout -b {derived-branch-name}`
|
|
120
|
+
4. Return setup summary with branch name and BASE_BRANCH recorded
|
|
116
121
|
|
|
117
122
|
**Output:**
|
|
118
123
|
```markdown
|
|
119
|
-
## Task Setup: {
|
|
124
|
+
## Task Setup: {branch-name}
|
|
120
125
|
|
|
121
126
|
### Branch
|
|
122
|
-
- **
|
|
127
|
+
- **Branch name**: {derived-branch-name}
|
|
123
128
|
- **Base branch**: {BASE_BRANCH} (PR target)
|
|
124
129
|
|
|
125
130
|
### Issue (if fetched)
|
|
@@ -46,8 +46,33 @@ The orchestrator provides:
|
|
|
46
46
|
3. **Apply 3-category classification** - Sort issues by where they occur
|
|
47
47
|
4. **Apply focus-specific analysis** - Use pattern skill detection rules from the loaded skill file
|
|
48
48
|
5. **Assign severity** - CRITICAL, HIGH, MEDIUM, LOW based on impact
|
|
49
|
-
6. **
|
|
50
|
-
7. **
|
|
49
|
+
6. **Assess confidence** - Assign 0-100% confidence to each finding (see Confidence Scale below)
|
|
50
|
+
7. **Filter by confidence** - Only report findings ≥80% in main sections; lower-confidence items go to Suggestions
|
|
51
|
+
8. **Consolidate similar issues** - Group related findings to reduce noise (see Consolidation Rules)
|
|
52
|
+
9. **Generate report** - File:line references with suggested fixes
|
|
53
|
+
10. **Determine merge recommendation** - Based on blocking issues
|
|
54
|
+
|
|
55
|
+
## Confidence Scale
|
|
56
|
+
|
|
57
|
+
Assess how certain you are that each finding is a real issue (not a false positive):
|
|
58
|
+
|
|
59
|
+
| Range | Label | Meaning |
|
|
60
|
+
|-------|-------|---------|
|
|
61
|
+
| 90-100% | Certain | Clearly a bug, vulnerability, or violation — no ambiguity |
|
|
62
|
+
| 80-89% | High | Very likely an issue, but minor chance of false positive |
|
|
63
|
+
| 60-79% | Medium | Plausible issue, but depends on context you may not fully see |
|
|
64
|
+
| < 60% | Low | Possible concern, but likely a matter of style or interpretation |
|
|
65
|
+
|
|
66
|
+
<!-- Confidence threshold also in: shared/agents/synthesizer.md, plugins/devflow-code-review/commands/code-review.md -->
|
|
67
|
+
**Threshold**: Only report findings with ≥80% confidence in Blocking, Should-Fix, and Pre-existing sections. Findings with 60-79% confidence go to the Suggestions section. Findings < 60% are dropped entirely.
|
|
68
|
+
|
|
69
|
+
## Consolidation Rules
|
|
70
|
+
|
|
71
|
+
Before writing your report, apply these noise reduction rules:
|
|
72
|
+
|
|
73
|
+
1. **Group similar issues** — If 3+ instances of the same pattern appear (e.g., "missing error handling" in multiple functions), consolidate into 1 finding listing all locations rather than N separate findings
|
|
74
|
+
2. **Skip stylistic preferences** — Do not flag formatting, naming style, or code organization choices unless they violate explicit project conventions found in CLAUDE.md, .editorconfig, or linter configs
|
|
75
|
+
3. **Skip issues in unchanged code** — Pre-existing issues in lines you did NOT change should only be reported if CRITICAL severity (security vulnerabilities, data loss risks)
|
|
51
76
|
|
|
52
77
|
## Issue Categories (from review-methodology)
|
|
53
78
|
|
|
@@ -76,17 +101,29 @@ Report format for `{output_path}`:
|
|
|
76
101
|
|
|
77
102
|
### CRITICAL
|
|
78
103
|
**{Issue}** - `file.ts:123`
|
|
104
|
+
**Confidence**: {n}%
|
|
79
105
|
- Problem: {description}
|
|
80
106
|
- Fix: {suggestion with code}
|
|
81
107
|
|
|
108
|
+
**{Issue Title} ({N} occurrences)** — Confidence: {n}%
|
|
109
|
+
- `file1.ts:12`, `file2.ts:45`, `file3.ts:89`
|
|
110
|
+
- Problem: {description of the shared pattern}
|
|
111
|
+
- Fix: {suggestion that applies to all occurrences}
|
|
112
|
+
|
|
82
113
|
### HIGH
|
|
83
|
-
{issues...}
|
|
114
|
+
{issues with **Confidence**: {n}% each...}
|
|
84
115
|
|
|
85
116
|
## Issues in Code You Touched (Should Fix)
|
|
86
|
-
{issues with file:line...}
|
|
117
|
+
{issues with file:line and **Confidence**: {n}% each...}
|
|
87
118
|
|
|
88
119
|
## Pre-existing Issues (Not Blocking)
|
|
89
|
-
{informational issues...}
|
|
120
|
+
{informational issues with **Confidence**: {n}% each...}
|
|
121
|
+
|
|
122
|
+
## Suggestions (Lower Confidence)
|
|
123
|
+
|
|
124
|
+
{Max 3 items with 60-79% confidence. Brief description only — no code fixes.}
|
|
125
|
+
|
|
126
|
+
- **{Issue}** - `file.ts:456` (Confidence: {n}%) — {brief description}
|
|
90
127
|
|
|
91
128
|
## Summary
|
|
92
129
|
| Category | CRITICAL | HIGH | MEDIUM | LOW |
|
|
@@ -128,10 +128,14 @@ Analyze 3 axes to determine strategy:
|
|
|
128
128
|
Synthesize outputs from multiple Reviewer agents. Apply strict merge rules.
|
|
129
129
|
|
|
130
130
|
**Process:**
|
|
131
|
-
1. Read all review reports from `${REVIEW_BASE_DIR}
|
|
132
|
-
2.
|
|
133
|
-
3.
|
|
134
|
-
|
|
131
|
+
1. Read all review reports from `${REVIEW_BASE_DIR}/*.md` (exclude your own output `review-summary.*.md`)
|
|
132
|
+
2. Extract confidence percentages from each finding
|
|
133
|
+
3. Apply confidence-aware aggregation: when multiple reviewers flag the same file:line, boost confidence by 10% per additional reviewer (cap at 100%)
|
|
134
|
+
<!-- Confidence threshold also in: shared/agents/reviewer.md, plugins/devflow-code-review/commands/code-review.md -->
|
|
135
|
+
4. Maintain ≥80% confidence threshold in final output
|
|
136
|
+
5. Categorize issues into 3 buckets (from review-methodology)
|
|
137
|
+
6. Count by severity (CRITICAL, HIGH, MEDIUM, LOW)
|
|
138
|
+
7. Determine merge recommendation based on blocking issues
|
|
135
139
|
|
|
136
140
|
**Issue Categories:**
|
|
137
141
|
- **Blocking** (Category 1): Issues in YOUR changes - CRITICAL/HIGH must block
|
|
@@ -172,7 +176,10 @@ Report format:
|
|
|
172
176
|
| Pre-existing | - | - | {n} | {n} | {n} |
|
|
173
177
|
|
|
174
178
|
## Blocking Issues
|
|
175
|
-
{List with file:line and suggested fix}
|
|
179
|
+
{List with file:line, confidence %, and suggested fix}
|
|
180
|
+
|
|
181
|
+
## Suggestions (Lower Confidence)
|
|
182
|
+
{Max 5 items across all reviewers with 60-79% confidence. Brief descriptions only.}
|
|
176
183
|
|
|
177
184
|
## Action Plan
|
|
178
185
|
1. {Priority fix}
|
|
@@ -38,9 +38,9 @@ Detect file types in diff to determine conditional reviews:
|
|
|
38
38
|
|
|
39
39
|
| Condition | Adds Perspective |
|
|
40
40
|
|-----------|-----------------|
|
|
41
|
-
| .ts
|
|
42
|
-
| .tsx
|
|
43
|
-
| .tsx
|
|
41
|
+
| Any .ts or .tsx files | typescript |
|
|
42
|
+
| .tsx or .jsx files (React components) | react |
|
|
43
|
+
| .tsx or .jsx files (React components) | accessibility |
|
|
44
44
|
| .tsx/.jsx/.css/.scss files | frontend-design |
|
|
45
45
|
| .go files | go |
|
|
46
46
|
| .java files | java |
|
|
@@ -50,7 +50,7 @@ Detect file types in diff to determine conditional reviews:
|
|
|
50
50
|
| Dependency files changed | dependencies |
|
|
51
51
|
| Docs or significant code | documentation |
|
|
52
52
|
|
|
53
|
-
**Skill availability check**: Language/ecosystem reviews (typescript, react, accessibility, frontend-design, go, java, python, rust) require their optional skill plugin to be installed. Before adding a conditional perspective, check if `~/.claude/skills/{focus}/SKILL.md` exists
|
|
53
|
+
**Skill availability check**: Language/ecosystem reviews (typescript, react, accessibility, frontend-design, go, java, python, rust) require their optional skill plugin to be installed. Before adding a conditional perspective, use Read to check if `~/.claude/skills/{focus}/SKILL.md` exists. If Read returns an error (file not found), **skip that perspective** — the language plugin isn't installed. Non-language reviews (database, dependencies, documentation) use skills bundled with this plugin and are always available.
|
|
54
54
|
|
|
55
55
|
### Phase 2: Spawn Review Team
|
|
56
56
|
|