5-phase-workflow 3.0.0 → 3.1.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/README.md +31 -101
- package/bin/install.js +168 -176
- package/bin/sync-agents.js +59 -54
- package/docs/workflow-guide.md +35 -79
- package/package.json +2 -2
- package/src/agents/step-executor-agent.md +5 -4
- package/src/agents/step-orchestrator-agent.md +12 -12
- package/src/agents/verification-agent.md +7 -8
- package/src/codex-commands/plan.md +65 -0
- package/src/commands/5/address-review-findings.md +43 -52
- package/src/commands/5/analyze-feature.md +1 -1
- package/src/commands/5/configure.md +75 -179
- package/src/commands/5/eject.md +0 -1
- package/src/commands/5/implement.md +78 -68
- package/src/commands/5/lean-check.md +75 -0
- package/src/commands/5/reconfigure.md +48 -129
- package/src/commands/5/review.md +42 -14
- package/src/commands/5/synchronize-agents.md +1 -1
- package/src/commands/5/update.md +2 -2
- package/src/hooks/dependency-guard.js +150 -0
- package/src/hooks/statusline.js +5 -3
- package/src/references/configure-tables.md +0 -33
- package/src/settings.json +3 -4
- package/src/skills/baseline-conventions/SKILL.md +37 -0
- package/src/skills/cognitive-load/SKILL.md +52 -0
- package/src/skills/configure-agents-md/SKILL.md +72 -0
- package/src/skills/configure-rules/SKILL.md +146 -0
- package/src/skills/documentation-style/SKILL.md +32 -0
- package/src/skills/fowler-code-smells/SKILL.md +25 -0
- package/src/skills/review-style/SKILL.md +142 -0
- package/src/templates/AGENTS.md +31 -31
- package/src/templates/workflow/REVIEW-FINDINGS.md +2 -9
- package/src/workflows/5-implement.js +67 -92
- package/docs/findings.md +0 -361
- package/docs/progress.md +0 -102
- package/src/commands/5/apply-review-findings.md +0 -66
- package/src/commands/5/commit.md +0 -43
- package/src/commands/5/plan.md +0 -189
- package/src/commands/5/reply-pr-comments.md +0 -48
- package/src/commands/5/split.md +0 -86
- package/src/commands/5/triage-pr-comments.md +0 -70
- package/src/hooks/config-guard.js +0 -30
- package/src/skills/configure-docs-index/SKILL.md +0 -243
- package/src/skills/configure-skills/SKILL.md +0 -311
- package/src/skills/generate-readme/EXAMPLES.md +0 -168
- package/src/skills/generate-readme/SKILL.md +0 -122
- package/src/skills/generate-readme/TEMPLATE.md +0 -141
- package/src/skills/use-index/SKILL.md +0 -49
- package/src/templates/ARCHITECTURE.md +0 -33
- package/src/templates/CONCERNS.md +0 -33
- package/src/templates/CONVENTIONS.md +0 -74
- package/src/templates/TESTING.md +0 -24
- package/src/templates/workflow/FIX-PLAN.md +0 -55
- package/src/templates/workflow/PLAN-COMPACT.md +0 -42
- package/src/templates/workflow/PLAN.md +0 -76
- package/src/templates/workflow/REVIEW-SUMMARY.md +0 -53
package/src/commands/5/review.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: 5:review
|
|
3
|
-
description: Reviews code changes via the built-in code-review skill. Categorizes findings and saves them for /5:address-review-findings.
|
|
3
|
+
description: Reviews code changes for correctness via the built-in code-review skill, for security via security-review when the diff is security-sensitive, and for standards via review-style. Categorizes findings and saves them for /5:address-review-findings.
|
|
4
4
|
allowed-tools: Bash, Read, Glob, Grep, AskUserQuestion, Agent, Skill, mcp__jetbrains__*
|
|
5
|
-
argument-hint: [low|medium|high|max]
|
|
5
|
+
argument-hint: [low|medium|high|max] [since {fixed-point} files: {paths} feature: {name} dirty: {paths}]
|
|
6
6
|
user-invocable: true
|
|
7
7
|
model: sonnet
|
|
8
8
|
---
|
|
@@ -16,7 +16,9 @@ You do NOT apply fixes. Fix application is handled by /5:address-review-findings
|
|
|
16
16
|
|
|
17
17
|
## Step 1: Determine Scope
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
When the arguments say `since {fixed-point} files: {paths} feature: {name} dirty: {paths}` — `/5:implement` passes this — review exactly those files' changes since that commit and skip the question. `/5:implement` runs this before it commits, so the changes are in the working tree. The working tree can also hold changes the user had before the run: in this scope, **drop every finding whose file is not in `{paths}`**, from every reviewer, before saving.
|
|
20
|
+
|
|
21
|
+
Otherwise ask what to review:
|
|
20
22
|
|
|
21
23
|
1. Staged changes (`git diff --cached`)
|
|
22
24
|
2. Unstaged changes (`git diff`)
|
|
@@ -36,7 +38,23 @@ Never pass `--fix` or `--comment`. This command only records findings; applying
|
|
|
36
38
|
Skill(skill: "code-review", args: "{target} {effort}")
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
Derive `{target}` from the scope answer: options 1-3 review the current working-tree diff (no target argument needed); option 4 passes the branch. Use the findings it reports.
|
|
41
|
+
Derive `{target}` from the scope answer: options 1-3 and the `since … files:` scope review the current working-tree diff (no target argument needed); option 4 passes the branch. Use the findings it reports.
|
|
42
|
+
|
|
43
|
+
**Security review** — when the diff touches authentication, authorization, user input handling, secrets, cryptography, or SQL/shell/path construction, and the built-in `security-review` skill is available, invoke it on the same scope:
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
Skill(skill: "security-review")
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Use the vulnerabilities it reports. Skip it for diffs that touch none of these areas.
|
|
50
|
+
|
|
51
|
+
**Standards review** — then invoke `review-style` in report-only mode. It checks the same changes against the repository's own standards and the style skills it lists, and repository standards win:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
Skill(skill: "review-style", args: "{mode} report only")
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Derive `{mode}` from the scope answer: option 1 passes `staged`, option 2 `unstaged`, option 3 `uncommitted`, option 4 `{base-branch} committed only`, and the `since … files:` scope `{fixed-point} files: {paths}`.
|
|
40
58
|
|
|
41
59
|
**Fallback path** — on Codex, or when the `code-review` skill is unavailable, spawn one review agent instead:
|
|
42
60
|
|
|
@@ -61,9 +79,11 @@ Manual Review:
|
|
|
61
79
|
- file: {path}, line: {N}, description: {what}, severity: {level}
|
|
62
80
|
```
|
|
63
81
|
|
|
82
|
+
On Codex, or when the `review-style` skill cannot be invoked, read `.claude/skills/review-style/SKILL.md` and follow it with the same arguments.
|
|
83
|
+
|
|
64
84
|
## Step 3: Save Findings
|
|
65
85
|
|
|
66
|
-
|
|
86
|
+
Use the `feature:` argument when given. Otherwise use the feature of the most recently modified plan in `.5/planning/` — its `feature` frontmatter field, or its file name without `.md` — or ask the user.
|
|
67
87
|
|
|
68
88
|
Write `.5/features/{feature-name}/review-findings-{YYYYMMDD-HHmmss}.md` using `.claude/templates/workflow/REVIEW-FINDINGS.md`.
|
|
69
89
|
|
|
@@ -81,9 +101,22 @@ When the findings come from the `code-review` skill, map its reported fields ont
|
|
|
81
101
|
| the concrete fix, else `short_summary` | **Suggested Fix:** |
|
|
82
102
|
| `failure_scenario` | **Original Reviewer Message:** |
|
|
83
103
|
|
|
104
|
+
Findings from `security-review` map to **Category:** `Fixable` when the fix is local, otherwise `Manual`, always with **Severity:** `error`; its explanation of the exploit goes into **Original Reviewer Message:**.
|
|
105
|
+
|
|
84
106
|
Findings from the fallback path map directly: Fixable Issues, Questions, and Manual Review become their matching categories.
|
|
85
107
|
|
|
86
|
-
|
|
108
|
+
Findings from `review-style` map like this. Leave out its Suppressed findings; a repository standard overrides them.
|
|
109
|
+
|
|
110
|
+
| Reported finding | Template field |
|
|
111
|
+
|---|---|
|
|
112
|
+
| ⛔️ hard breach of a repository standard | **Category:** `Fixable`, **Severity:** `error` |
|
|
113
|
+
| ⚠️ judgement call | **Category:** `Fixable`, **Severity:** `suggestion` |
|
|
114
|
+
| `path:line` | **File:**, **Line:** |
|
|
115
|
+
| ID, title, and what is wrong | **Description:** |
|
|
116
|
+
| the `→` fix | **Suggested Fix:** |
|
|
117
|
+
| the cited standards and rules | **Original Reviewer Message:** |
|
|
118
|
+
|
|
119
|
+
Do not ask the user to edit action markers in the findings file. The findings file is the review record; `/5:address-review-findings` decides on the findings and records the decisions separately.
|
|
87
120
|
|
|
88
121
|
## Step 4: Report and Hand Off
|
|
89
122
|
|
|
@@ -101,12 +134,7 @@ Findings saved at `.5/features/{feature-name}/review-findings-{timestamp}.md`
|
|
|
101
134
|
|
|
102
135
|
If there are no findings, stop here.
|
|
103
136
|
|
|
104
|
-
Otherwise
|
|
105
|
-
|
|
106
|
-
- "Address these findings now?"
|
|
107
|
-
- Options:
|
|
108
|
-
1. "Yes, run `/5:address-review-findings {feature-name}`" — decide on each finding interactively, then apply approved fixes
|
|
109
|
-
2. "No, stop here" — findings stay on disk for later
|
|
137
|
+
Otherwise hand off to `/5:address-review-findings {feature-name}`. It fixes the clear findings on its own, asks the user one question at a time only about real decisions, and then runs build, test, and lint.
|
|
110
138
|
|
|
111
|
-
-
|
|
112
|
-
-
|
|
139
|
+
- **Called by `/5:implement`** (the `since … files:` scope): run `/5:address-review-findings {feature-name} dirty: {dirty-paths}` right away. The user approved the plan, and these are the run's own files — except the dirty ones, which also hold the user's earlier work.
|
|
140
|
+
- **Started on its own:** the reviewed code may come from someone else's branch, and the fixes are followed by the project's build and test commands. Ask once: "Fix the clear findings on my own and then run build, test, and lint?" On yes, run it. On no, stop and tell the user they can run `/5:address-review-findings {feature-name}` (or `--interactive`) later.
|
|
@@ -13,7 +13,7 @@ You do NOT modify files manually. After reporting, you are DONE.
|
|
|
13
13
|
|
|
14
14
|
# Synchronize Agent Runtimes
|
|
15
15
|
|
|
16
|
-
Synchronizes user-generated content (skills, commands, agents, rules) between the Claude Code (`.claude/`) and Codex (`.codex/`) runtimes.
|
|
16
|
+
Synchronizes user-generated content (skills, commands, agents, rules) between the Claude Code (`.claude/`) and Codex (`.codex/`) runtimes. Codex reads only `AGENTS.md`, so Claude rules and agent references go into the foifi block there.
|
|
17
17
|
|
|
18
18
|
## Step 1: Locate the Sync Script
|
|
19
19
|
|
package/src/commands/5/update.md
CHANGED
|
@@ -42,7 +42,7 @@ Read `.5/version.json` again. Compare the new `installedVersion` to the previous
|
|
|
42
42
|
|
|
43
43
|
Run `git status` to show the files modified by the upgrade. Summarize the changes for the user using the correct runtime paths:
|
|
44
44
|
- Claude Code installs typically update files in `.claude/commands/5/`, `.claude/skills/`, `.claude/hooks/`, `.claude/templates/`, `.claude/settings.json`, and `.5/version.json`
|
|
45
|
-
- Codex installs typically update files in `.codex/skills/`, `.codex/templates/`, `.codex/references/`,
|
|
45
|
+
- Codex installs typically update files in `.codex/skills/`, `.codex/templates/`, `.codex/references/`, and `.5/version.json`
|
|
46
46
|
|
|
47
47
|
## Step 5: Ask to Commit
|
|
48
48
|
|
|
@@ -67,7 +67,7 @@ Build the commit message by applying the pattern:
|
|
|
67
67
|
Stage **only** the workflow-managed files shown in `git status`.
|
|
68
68
|
|
|
69
69
|
- For Claude Code installs, this usually means files inside `.claude/commands/5/`, `.claude/skills/`, `.claude/hooks/`, `.claude/templates/`, `.claude/settings.json`, and `.5/version.json`
|
|
70
|
-
- For Codex installs, this usually means files inside `.codex/skills/`, `.codex/templates/`, `.codex/references/`,
|
|
70
|
+
- For Codex installs, this usually means files inside `.codex/skills/`, `.codex/templates/`, `.codex/references/`, and `.5/version.json`
|
|
71
71
|
|
|
72
72
|
Never use `git add .` or `git add -A`.
|
|
73
73
|
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Stop hook: when the uncommitted diff adds a dependency, make Claude justify it once
|
|
3
|
+
// before finishing. New dependencies are the most reliable, heuristic-free drift signal.
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { execFileSync } = require('child_process');
|
|
7
|
+
|
|
8
|
+
// Each extractor returns the dependency identities a manifest declares. The hook compares
|
|
9
|
+
// those sets with HEAD, so config edits and version bumps of existing packages never count.
|
|
10
|
+
const pep508Name = spec => (spec.trim().match(/^([A-Za-z0-9][A-Za-z0-9._-]*)/) || [])[1];
|
|
11
|
+
const normalizePy = name => name && name.toLowerCase().replace(/[_.]+/g, '-');
|
|
12
|
+
const jsonKeys = sections => text => { const json = JSON.parse(text); return sections.flatMap(s => Object.keys(json[s] || {})); };
|
|
13
|
+
const matchAll = (text, re, pick) => [...text.matchAll(re)].map(pick);
|
|
14
|
+
|
|
15
|
+
function requirementsDeps(text) {
|
|
16
|
+
return text.split('\n')
|
|
17
|
+
.map(l => l.replace(/#.*/, '').trim())
|
|
18
|
+
.filter(l => l && !l.startsWith('-'))
|
|
19
|
+
.map(l => normalizePy(pep508Name(l)))
|
|
20
|
+
.filter(Boolean);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Minimal TOML walk for Cargo.toml, Pipfile, and pyproject.toml (PEP 621, PEP 735, Poetry).
|
|
24
|
+
function tomlDeps(text) {
|
|
25
|
+
const deps = [];
|
|
26
|
+
let section = '';
|
|
27
|
+
let inArray = false;
|
|
28
|
+
// Collects quoted specs; returns true once the array closes (a `]` outside quotes, not in "pkg[extra]").
|
|
29
|
+
const arrayLine = line => {
|
|
30
|
+
matchAll(line, /"([^"]+)"|'([^']+)'/g, m => normalizePy(pep508Name(m[1] || m[2]))).forEach(d => d && deps.push(d));
|
|
31
|
+
return line.replace(/"[^"]*"|'[^']*'/g, '').includes(']');
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
for (const raw of text.split('\n')) {
|
|
35
|
+
const line = raw.replace(/\s#.*$/, '').trim();
|
|
36
|
+
if (inArray) { inArray = !arrayLine(line); continue; }
|
|
37
|
+
const header = line.match(/^\[\[?([^\]]+)\]\]?$/);
|
|
38
|
+
if (header) {
|
|
39
|
+
section = header[1].trim();
|
|
40
|
+
const dotted = section.match(/(?:^|\.)(?:dependencies|dev-dependencies|build-dependencies)\.([^.]+)$/);
|
|
41
|
+
if (dotted) deps.push(dotted[1]); // Cargo: [dependencies.serde]
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const key = (line.match(/^"?([A-Za-z0-9_.-]+)"?\s*=/) || [])[1];
|
|
45
|
+
if (!key) continue;
|
|
46
|
+
const arrayOfSpecs = (section === 'project' && key === 'dependencies') ||
|
|
47
|
+
section === 'project.optional-dependencies' || section === 'dependency-groups';
|
|
48
|
+
if (arrayOfSpecs && line.includes('[')) {
|
|
49
|
+
inArray = !arrayLine(line.slice(line.indexOf('[') + 1));
|
|
50
|
+
} else if (/(?:^|\.)(?:dependencies|dev-dependencies|build-dependencies|packages|dev-packages)$/.test(section) && key !== 'python') {
|
|
51
|
+
deps.push(key);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return deps;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function goModDeps(text) {
|
|
58
|
+
const deps = [];
|
|
59
|
+
let inBlock = false;
|
|
60
|
+
for (const raw of text.split('\n')) {
|
|
61
|
+
const line = raw.trim();
|
|
62
|
+
if (/^require\s*\($/.test(line)) { inBlock = true; continue; }
|
|
63
|
+
if (inBlock && line === ')') { inBlock = false; continue; }
|
|
64
|
+
if (line.includes('// indirect')) continue; // pulled in by tooling, not chosen
|
|
65
|
+
const spec = inBlock ? line : (line.match(/^require\s+(.+)$/) || [])[1];
|
|
66
|
+
const mod = spec && spec.split(/\s+/)[0];
|
|
67
|
+
if (mod && !mod.startsWith('//')) deps.push(mod);
|
|
68
|
+
}
|
|
69
|
+
return deps;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const EXTRACTORS = [
|
|
73
|
+
[/^package\.json$/, jsonKeys(['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'])],
|
|
74
|
+
[/^composer\.json$/, jsonKeys(['require', 'require-dev'])],
|
|
75
|
+
[/^requirements.*\.txt$/, requirementsDeps],
|
|
76
|
+
[/^(pyproject\.toml|Pipfile|Cargo\.toml)$/, tomlDeps],
|
|
77
|
+
[/^go\.mod$/, goModDeps],
|
|
78
|
+
[/^Gemfile$/, text => matchAll(text, /^\s*gem\s+['"]([^'"]+)['"]/gm, m => m[1])],
|
|
79
|
+
[/^pom\.xml$/, text => matchAll(text, /<dependency>([\s\S]*?)<\/dependency>/g, m =>
|
|
80
|
+
[/<groupId>([^<]+)</, /<artifactId>([^<]+)</].map(re => (m[1].match(re) || [])[1] || '?').join(':'))],
|
|
81
|
+
[/^build\.gradle(\.kts)?$/, text => matchAll(text,
|
|
82
|
+
/^\s*(?:implementation|api|compileOnly|runtimeOnly|testImplementation|testRuntimeOnly|annotationProcessor|kapt|ksp|classpath)\s*\(?\s*(?:['"]([^'":]+:[^'":]+)|(libs\.[\w.]+))/gm,
|
|
83
|
+
m => m[1] || m[2])],
|
|
84
|
+
[/\.csproj$/, text => matchAll(text, /<PackageReference\s+Include="([^"]+)"/gi, m => m[1])]
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
function git(cwd, args) {
|
|
88
|
+
return execFileSync('git', args, { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function headVersion(root, file) {
|
|
92
|
+
try { return git(root, ['show', `HEAD:${file}`]); } catch (e) { return null; }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function addedDependencies(root) {
|
|
96
|
+
const changed = git(root, ['diff', 'HEAD', '--name-only']).split('\n').filter(Boolean);
|
|
97
|
+
const untracked = git(root, ['ls-files', '--others', '--exclude-standard']).split('\n').filter(Boolean);
|
|
98
|
+
const found = [];
|
|
99
|
+
|
|
100
|
+
for (const file of new Set([...changed, ...untracked])) {
|
|
101
|
+
const extract = (EXTRACTORS.find(([re]) => re.test(path.basename(file))) || [])[1];
|
|
102
|
+
const abs = path.join(root, file);
|
|
103
|
+
if (!extract || !fs.existsSync(abs)) continue;
|
|
104
|
+
try {
|
|
105
|
+
const before = headVersion(root, file);
|
|
106
|
+
const old = new Set(before ? extract(before) : []);
|
|
107
|
+
extract(fs.readFileSync(abs, 'utf8'))
|
|
108
|
+
.filter(d => !old.has(d))
|
|
109
|
+
.forEach(d => found.push(`${d} (${file})`));
|
|
110
|
+
} catch (e) {
|
|
111
|
+
// Unparseable manifest (e.g. mid-edit JSON): skip this file, keep checking the others.
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return [...new Set(found)];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let input = '';
|
|
118
|
+
process.stdin.setEncoding('utf8');
|
|
119
|
+
process.stdin.on('data', chunk => input += chunk);
|
|
120
|
+
process.stdin.on('end', () => {
|
|
121
|
+
try {
|
|
122
|
+
const data = JSON.parse(input);
|
|
123
|
+
if (data.stop_hook_active) process.exit(0); // Claude is already continuing because of a Stop hook
|
|
124
|
+
|
|
125
|
+
const root = git(data.cwd || process.cwd(), ['rev-parse', '--show-toplevel']).trim(); // git paths are root-relative
|
|
126
|
+
const deps = addedDependencies(root);
|
|
127
|
+
if (!deps.length) process.exit(0);
|
|
128
|
+
|
|
129
|
+
// Ask once per session and dependency set, so an accepted dependency doesn't nag on every stop.
|
|
130
|
+
const stateFile = path.join(root, '.5', '.dependency-guard.json');
|
|
131
|
+
const signature = `${data.session_id || ''}:${deps.slice().sort().join('|')}`;
|
|
132
|
+
let seen = [];
|
|
133
|
+
try { seen = JSON.parse(fs.readFileSync(stateFile, 'utf8')).signatures || []; } catch (e) { /* first run */ }
|
|
134
|
+
if (seen.includes(signature)) process.exit(0);
|
|
135
|
+
if (fs.existsSync(path.dirname(stateFile))) {
|
|
136
|
+
fs.writeFileSync(stateFile, JSON.stringify({ signatures: [...seen, signature].slice(-20) })); // concurrent sessions
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
process.stdout.write(JSON.stringify({
|
|
140
|
+
decision: 'block',
|
|
141
|
+
reason: `Uncommitted changes add dependencies:\n${deps.map(d => `- ${d}`).join('\n')}\n\n` +
|
|
142
|
+
'For each one: if the user asked for it or added it themselves, keep it and name it in your reply. ' +
|
|
143
|
+
'Otherwise remove it with the package manager (never edit a lockfile by hand) and use existing code, ' +
|
|
144
|
+
'the standard library, a native platform feature, or an installed dependency instead.'
|
|
145
|
+
}));
|
|
146
|
+
process.exit(0);
|
|
147
|
+
} catch (e) {
|
|
148
|
+
process.exit(0); // Never block on errors (not a git repo, no HEAD, unparseable manifest)
|
|
149
|
+
}
|
|
150
|
+
});
|
package/src/hooks/statusline.js
CHANGED
|
@@ -103,9 +103,11 @@ process.stdin.on('end', () => {
|
|
|
103
103
|
parts.push(`\x1b[35m↻ /5:reconfigure\x1b[0m`);
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
// The installer writes .migration-v{major} after a major upgrade
|
|
107
|
+
const migrationFlag = fs.readdirSync(path.join(dir, '.5')).find(f => /^\.migration-v\d+$/.test(f));
|
|
108
|
+
if (migrationFlag) {
|
|
109
|
+
const major = migrationFlag.slice('.migration-'.length);
|
|
110
|
+
parts.push(`\x1b[31m⚠ ${major}: /5:reconfigure\x1b[0m`);
|
|
109
111
|
}
|
|
110
112
|
} catch (e) {}
|
|
111
113
|
|
|
@@ -37,33 +37,6 @@ Check files in this order (first match wins):
|
|
|
37
37
|
| rust | `cargo build` | `cargo test` |
|
|
38
38
|
| go | `go build ./...` | `go test ./...` |
|
|
39
39
|
|
|
40
|
-
## Codebase Pattern Categories to Scan
|
|
41
|
-
|
|
42
|
-
Use Glob to scan for architectural patterns. For each, check both suffix-based (`*{Pattern}.{ts,js,java,py,rb}`) and directory-based (`{patterns}/**`) globs.
|
|
43
|
-
|
|
44
|
-
- **Core:** Controllers, Services, Repositories, Models/Entities, Handlers
|
|
45
|
-
- **Data Transfer:** DTOs, Requests, Responses, Mappers, Validators, Schemas
|
|
46
|
-
- **Frontend:** Components, Hooks, Contexts, Stores, Pages, Layouts
|
|
47
|
-
- **API/Routes:** API Routes, Middleware, Guards, Interceptors, Filters
|
|
48
|
-
- **Testing:** Tests/Specs, Fixtures, Factories, Mocks
|
|
49
|
-
- **Utilities:** Utils, Helpers, Constants, Types/Interfaces, Config
|
|
50
|
-
- **Framework-Specific:** Modules, Pipes, Decorators, Blueprints, Views, Serializers
|
|
51
|
-
- **Background/Async:** Jobs, Workers, Events, Listeners, Commands
|
|
52
|
-
- **Database:** Migrations, Seeds
|
|
53
|
-
- **Error Handling:** Exceptions, Errors
|
|
54
|
-
|
|
55
|
-
For each pattern found: count matching files, identify primary location, sample 1 filename.
|
|
56
|
-
|
|
57
|
-
## Runnable Command Categories
|
|
58
|
-
|
|
59
|
-
Scan config files (`package.json` scripts, `Makefile` targets, `pyproject.toml` scripts, `Cargo.toml`, `build.gradle` tasks, `composer.json` scripts, `Rakefile` tasks) for commands in these categories:
|
|
60
|
-
|
|
61
|
-
Build, Test, Lint, Format, Type Check, Dev Server, Database (migrate/seed), Docker, Deploy, Clean, Generate
|
|
62
|
-
|
|
63
|
-
Skill naming: `run-{category}` (e.g., `run-build`, `run-tests`, `run-lint`).
|
|
64
|
-
|
|
65
|
-
For each command found: record exact syntax, note variants (e.g., `test:unit`, `test:e2e`), and environment requirements. Only include commands that are actually detected.
|
|
66
|
-
|
|
67
40
|
## Config Schema
|
|
68
41
|
|
|
69
42
|
```json
|
|
@@ -91,9 +64,6 @@ For each command found: record exact syntax, note variants (e.g., `test:unit`, `
|
|
|
91
64
|
},
|
|
92
65
|
"context7": {
|
|
93
66
|
"available": false
|
|
94
|
-
},
|
|
95
|
-
"skillCreator": {
|
|
96
|
-
"available": false
|
|
97
67
|
}
|
|
98
68
|
},
|
|
99
69
|
"git": {
|
|
@@ -107,9 +77,6 @@ For each command found: record exact syntax, note variants (e.g., `test:unit`, `
|
|
|
107
77
|
},
|
|
108
78
|
"rules": {
|
|
109
79
|
"generate": true
|
|
110
|
-
},
|
|
111
|
-
"conventions": {
|
|
112
|
-
"generate": true
|
|
113
80
|
}
|
|
114
81
|
}
|
|
115
82
|
```
|
package/src/settings.json
CHANGED
|
@@ -26,14 +26,13 @@
|
|
|
26
26
|
]
|
|
27
27
|
}
|
|
28
28
|
],
|
|
29
|
-
"
|
|
29
|
+
"Stop": [
|
|
30
30
|
{
|
|
31
|
-
"matcher": "Task|Agent",
|
|
32
31
|
"hooks": [
|
|
33
32
|
{
|
|
34
33
|
"type": "command",
|
|
35
|
-
"command": "node .claude/hooks/
|
|
36
|
-
"timeout":
|
|
34
|
+
"command": "node .claude/hooks/dependency-guard.js",
|
|
35
|
+
"timeout": 10
|
|
37
36
|
}
|
|
38
37
|
]
|
|
39
38
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: baseline-conventions
|
|
3
|
+
description: Baseline rules for errors, types, names and tests. They keep a codebase clean when the repository documents no rules of its own. Use when writing, refactoring or reviewing code.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Baseline conventions
|
|
7
|
+
|
|
8
|
+
These rules fill the gaps a repository leaves open. A repository standard always wins over them. Each rule reads
|
|
9
|
+
_what it is_ → _how to fix_:
|
|
10
|
+
|
|
11
|
+
## Errors
|
|
12
|
+
|
|
13
|
+
- **Swallowed error**: an empty catch, or a catch that ignores the error. → Log it, rethrow it, or turn it into a typed result.
|
|
14
|
+
- **Unhandled async failure**: a promise or future whose failure path nobody handles. → Handle the failure where it is awaited, or pass it on to the caller.
|
|
15
|
+
- **Bare error message**: an error that carries only a string. → Use a typed error that carries the context a reader needs.
|
|
16
|
+
- **Errors as control flow**: an exception thrown for an expected case. → Check the case up front, or return a result.
|
|
17
|
+
|
|
18
|
+
## Types and names
|
|
19
|
+
|
|
20
|
+
- **Untyped boundary**: a public function, exported type or data shape without an explicit type, where the language supports one. → Declare the type.
|
|
21
|
+
- **Escape hatch**: `any`, a non-null assertion or an unchecked cast. → Narrow the type. When it can't be avoided, say why in a comment.
|
|
22
|
+
- **Magic value**: a literal number or string whose meaning the reader must guess. → Give it a named constant.
|
|
23
|
+
- **Unclear boolean**: a boolean whose name doesn't read as a question. → Prefix it with `is`, `has`, `can` or `should`.
|
|
24
|
+
|
|
25
|
+
## Tests
|
|
26
|
+
|
|
27
|
+
- **Mixed test**: one test that checks several behaviours. → Split it, so each test checks one behaviour.
|
|
28
|
+
- **Method-named test**: a test named after the method it calls. → Name it after the behaviour, such as `returns 404 when the user is missing`.
|
|
29
|
+
- **Weak assertion**: an assertion that only checks a value exists, or that can't fail. → Assert the actual value or outcome.
|
|
30
|
+
- **Tangled test**: setup, action and checks are mixed together. → Order them as arrange, act, assert.
|
|
31
|
+
- **Internal mock**: a mock of an internal module or a pure function. → Mock only at system boundaries such as network, database, filesystem and clock. Test the rest directly.
|
|
32
|
+
- **Silent skip**: a disabled test with no reason. → Fix it, delete it, or link the issue that tracks it.
|
|
33
|
+
- **Unprotected bug fix**: a fix that no test guards. → Add a regression test that fails without the fix, when practical.
|
|
34
|
+
|
|
35
|
+
## Leftovers
|
|
36
|
+
|
|
37
|
+
- **Commented-out code**: code kept alive in a comment. → Delete it. Version control keeps the history.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cognitive-load
|
|
3
|
+
description: Rules for keeping the cognitive load of code low. Use when writing, refactoring or reviewing code.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cognitive load
|
|
7
|
+
|
|
8
|
+
Cognitive load is how much a reader must hold in mind to understand the code. Working memory holds about
|
|
9
|
+
**four chunks**: a variable's value, a branch taken, a call to chase, a mapping to remember. Past four, the
|
|
10
|
+
reader loses the thread.
|
|
11
|
+
|
|
12
|
+
_Intrinsic_ load comes from the problem itself and stays. _Extraneous_ load comes from how the code is
|
|
13
|
+
written. The rules below cut extraneous load.
|
|
14
|
+
|
|
15
|
+
## Rules
|
|
16
|
+
|
|
17
|
+
- **Named conditions.** Give the parts of a compound condition intermediate variables named after what they
|
|
18
|
+
mean. The `if` then reads as one chunk:
|
|
19
|
+
```java
|
|
20
|
+
var isFresh = price.timestamp().isAfter(cutoff);
|
|
21
|
+
var isKnownVendor = vendors.contains(price.vendor());
|
|
22
|
+
if (isFresh && isKnownVendor) { ... }
|
|
23
|
+
```
|
|
24
|
+
- **Early returns.** Handle invalid cases with guard clauses at the top. The happy path then runs
|
|
25
|
+
unindented. Nesting makes the reader carry every outer condition along.
|
|
26
|
+
- **Composition over inheritance.** Deep inheritance chains make the reader trace behaviour across levels.
|
|
27
|
+
A change in a parent can silently break a child.
|
|
28
|
+
- **Deep modules.** A module earns its place with a simple interface over substantial behaviour. Many
|
|
29
|
+
shallow modules whose interface is as complex as their body are tiring to navigate. Merge them.
|
|
30
|
+
- **Important logic can be large.** Keep the crux of a feature in one substantial function. Splitting it
|
|
31
|
+
into many tiny hops hides it.
|
|
32
|
+
- **One stakeholder per module.** A module answers to one user or one concern. "Does one thing" is too vague
|
|
33
|
+
to judge.
|
|
34
|
+
- **Plain language subset.** Use constructs any developer of the language reads fluently. A clever feature
|
|
35
|
+
makes the reader learn the feature before the code.
|
|
36
|
+
- **Self-describing values.** Prefer names, enums and descriptive strings over codes that need a lookup
|
|
37
|
+
table. Return `"jwt_has_expired"` rather than relying on HTTP status `401` vs `403`. Keep business meaning
|
|
38
|
+
out of transport details.
|
|
39
|
+
- **Plain terms.** Name things with the plainest accurate words, in the problem's own language. Reuse terms
|
|
40
|
+
already in the codebase.
|
|
41
|
+
- **Duplication over coupling.** A few copied lines beat a premature shared abstraction that couples
|
|
42
|
+
unrelated code. Every dependency is code the reader may have to debug.
|
|
43
|
+
- **Framework at the edge.** Core logic uses the framework like a library. It stays readable to someone who
|
|
44
|
+
doesn't know the framework's magic.
|
|
45
|
+
- **Layers only where they hide something.** Add an abstraction only at a real extension point. A layer that
|
|
46
|
+
only forwards calls is pure indirection.
|
|
47
|
+
- **Boring over clever.** Pick the straightforward solution. Debugging is twice as hard as writing the code.
|
|
48
|
+
- **Familiar is not simple.** Code feels simple to its author. Judge it as a newcomer would. If a newcomer
|
|
49
|
+
stays confused for about 40 minutes, the code needs work.
|
|
50
|
+
|
|
51
|
+
Source: Artem Zakirullin, [Cognitive load is what matters](https://github.com/zakirullin/cognitive-load),
|
|
52
|
+
CC BY 4.0. Condensed and adapted.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: configure-agents-md
|
|
3
|
+
description: Writes the workflow rules into AGENTS.md as one marked block, links the repository's own standards, and makes CLAUDE.md include AGENTS.md. Never changes content outside the block. Used during /5:implement CONFIGURE and /5:reconfigure.
|
|
4
|
+
allowed-tools: Read, Write, Edit, Bash, Glob, Grep
|
|
5
|
+
model: sonnet
|
|
6
|
+
user-invocable: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Configure AGENTS.md Skill
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
This skill writes the workflow rules into `AGENTS.md` as one block between `<!-- foifi:start` and `<!-- foifi:end -->`. Everything outside that block belongs to the repository. The skill never rewrites, moves, or deletes it, in `AGENTS.md` or in `CLAUDE.md`.
|
|
14
|
+
|
|
15
|
+
A step executor calls it for the CONFIGURE feature. `/5:reconfigure` calls it in refresh mode. Both modes run the same steps:
|
|
16
|
+
|
|
17
|
+
- **Full mode (default):** input is the plan at `.5/planning/CONFIGURE.md`.
|
|
18
|
+
- **Refresh mode:** the prompt includes "REFRESH MODE" and points at `.5/reconfigure-manifest.json`.
|
|
19
|
+
|
|
20
|
+
It generates no architecture, testing, concerns, or conventions docs and no codebase index. Agents explore the code themselves.
|
|
21
|
+
|
|
22
|
+
## 1. Collect Inputs
|
|
23
|
+
|
|
24
|
+
- **Build and run commands:** from `.5/config.json`, plus other detected scripts worth running. Skip commands that `AGENTS.md` or `CLAUDE.md` already document outside the block.
|
|
25
|
+
- **Commit message rule:** the repository's own commit convention when one is documented, such as in `CONTRIBUTING.md`. Then write `Follow the commit convention in {path}.` Otherwise use `git.commitMessage.pattern` from `.5/config.json` and write `Write commit messages as \`{pattern}\`. Take {ticket-id} from the branch name when it matches \`ticket.pattern\`; drop it otherwise.` Without a pattern, remove the `## Commit Messages` section.
|
|
26
|
+
- **Repository standards:** the files `.claude/skills/review-style/SKILL.md` step 2 counts as repository standards. Use the list in the CONFIGURE plan or the refresh manifest when it has one. Do not count workflow-generated files.
|
|
27
|
+
- **Existing project docs:** `.5/ARCHITECTURE.md`, `.5/TESTING.md`, `.5/CONCERNS.md`, and `.5/CONVENTIONS.md`, when they exist. Link them; never rewrite or delete them.
|
|
28
|
+
|
|
29
|
+
## 2. Fill the Template
|
|
30
|
+
|
|
31
|
+
Use `.claude/templates/AGENTS.md` as the block. Keep its marker comments and static sections exactly as written; `review-style` reads the markers to tell workflow rules apart from repository standards.
|
|
32
|
+
|
|
33
|
+
- `{BUILD_RUN_COMMANDS}` → the build, test, and other commands. Remove the section when there are none left.
|
|
34
|
+
- `{COMMIT_MESSAGE_RULE}` → the commit message rule.
|
|
35
|
+
- `{REPO_STANDARDS_LINKS}` → one bullet per repository standard, as `- [path](path)`. When there are none, write `- None documented yet. The style skills below set the baseline.`
|
|
36
|
+
- `{PROJECT_DOCUMENTATION_LINKS}` → one link per existing `.5/*.md` doc. When there are none, remove the whole `## Project Documentation` section.
|
|
37
|
+
|
|
38
|
+
## 3. Write AGENTS.md
|
|
39
|
+
|
|
40
|
+
- **No `AGENTS.md`:** create it with only the block.
|
|
41
|
+
- **`AGENTS.md` with a foifi block:** replace the text from the `<!-- foifi:start` line through the `<!-- foifi:end -->` line. Keep any `<!-- 5-sync:rules-start -->` … `<!-- 5-sync:rules-end -->` and `<!-- 5-sync:agents-start -->` … `<!-- 5-sync:agents-end -->` sections inside the old block unchanged, just before the new `<!-- foifi:end -->`: `configure-rules` and `/5:synchronize-agents` own them. Leave every other byte unchanged.
|
|
42
|
+
- **`AGENTS.md` without a block:** append a blank line and the block at the end. Leave the existing content unchanged.
|
|
43
|
+
- **Legacy file** (its first line starts with `<!-- Generated from the foifi AGENTS.md template`): an earlier version generated the whole file. Keep only what the user wrote: the content under its `## Custom Documentation` heading, unchanged. Write that content, then a blank line, then the block. Drop the rest; the block replaces it.
|
|
44
|
+
|
|
45
|
+
## 4. Include AGENTS.md from CLAUDE.md (Claude Code only)
|
|
46
|
+
|
|
47
|
+
Claude Code reads `CLAUDE.md`, and `@AGENTS.md` pulls in the full `AGENTS.md`.
|
|
48
|
+
|
|
49
|
+
- **No `CLAUDE.md`:** create it with only `@AGENTS.md`.
|
|
50
|
+
- **`CLAUDE.md` without an `@AGENTS.md` line:** append a blank line and `@AGENTS.md`. Leave the existing content unchanged.
|
|
51
|
+
- **`CLAUDE.md` with an `@AGENTS.md` line:** leave it as it is.
|
|
52
|
+
|
|
53
|
+
## Output Contract
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
Component A (AGENTS.md): SUCCESS - Wrote the foifi block in AGENTS.md
|
|
57
|
+
- AGENTS.md (block replaced | appended | created, 3 repository standards linked)
|
|
58
|
+
- CLAUDE.md (unchanged | @AGENTS.md appended | created)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Or on failure:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
Component A (AGENTS.md): FAILED - Unable to read the AGENTS.md template
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## DO NOT
|
|
68
|
+
|
|
69
|
+
- DO NOT change, move, or delete anything outside the foifi block, in `AGENTS.md` or `CLAUDE.md`.
|
|
70
|
+
- DO NOT generate architecture, testing, concerns, or conventions docs, index files, or rebuild scripts.
|
|
71
|
+
- DO NOT rewrite or delete existing `.5/*.md` docs.
|
|
72
|
+
- DO NOT restate repository standards in the block. Link them.
|