@antoneeo/agentic-sdlc-skill 1.6.0 → 1.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 +22 -0
- package/gemini-extension.json +2 -2
- package/package.json +2 -4
- package/scripts/init.js +125 -176
- package/scripts/lib.js +138 -0
- package/scripts/postinstall.js +17 -113
- package/scripts/preuninstall.js +5 -14
- package/skills/agentic-sdlc-skill/ENFORCEMENT.md +56 -55
- package/skills/agentic-sdlc-skill/SKILL.md +244 -172
- package/skills/agentic-sdlc-skill/scripts/sdlc_check.py +713 -621
- package/skills/agentic-sdlc-skill/templates.md +212 -192
- package/references/analysis_template.md +0 -44
- package/references/architecture_template.md +0 -23
- package/references/existing_features_template.md +0 -8
- package/references/feature_vision_template.md +0 -21
- package/references/features_history_template.md +0 -5
- package/references/principles_template.md +0 -13
- package/references/project_vision_template.md +0 -26
- package/references/roadmap_template.md +0 -9
package/scripts/postinstall.js
CHANGED
|
@@ -1,132 +1,36 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const { execSync } = require('child_process');
|
|
4
3
|
const fs = require('fs');
|
|
5
|
-
const
|
|
6
|
-
const os = require('os');
|
|
4
|
+
const { SKILL_SOURCE, CLIENTS, clientDetected, skillTarget, copyRecursive } = require('./lib');
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
const SKILL_SOURCE = path.join(PACKAGE_ROOT, 'skills', 'agentic-sdlc-skill');
|
|
10
|
-
const CLAUDE_HOME = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude');
|
|
11
|
-
const CLAUDE_SKILLS_DIR = path.join(CLAUDE_HOME, 'skills');
|
|
12
|
-
const CLAUDE_SKILL_TARGET = path.join(CLAUDE_SKILLS_DIR, 'agentic-sdlc');
|
|
13
|
-
const CODEX_HOME = process.env.CODEX_HOME || path.join(os.homedir(), '.codex');
|
|
14
|
-
const CODEX_SKILLS_DIR = path.join(CODEX_HOME, 'skills');
|
|
15
|
-
const CODEX_SKILL_TARGET = path.join(CODEX_SKILLS_DIR, 'agentic-sdlc');
|
|
16
|
-
const GEMINI_HOME = process.env.GEMINI_HOME || path.join(os.homedir(), '.gemini');
|
|
17
|
-
const GEMINI_SKILLS_DIR = path.join(GEMINI_HOME, 'skills');
|
|
18
|
-
const GEMINI_SKILL_TARGET = path.join(GEMINI_SKILLS_DIR, 'agentic-sdlc');
|
|
19
|
-
|
|
20
|
-
function checkCommand(cmd) {
|
|
21
|
-
try {
|
|
22
|
-
execSync(`${cmd} --version`, { stdio: 'ignore' });
|
|
23
|
-
return true;
|
|
24
|
-
} catch (e) {
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function copyRecursive(src, dest) {
|
|
30
|
-
if (typeof fs.cpSync === 'function') {
|
|
31
|
-
fs.cpSync(src, dest, { recursive: true, force: true });
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
// Fallback for Node < 16.7
|
|
35
|
-
if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
|
|
36
|
-
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
37
|
-
const s = path.join(src, entry.name);
|
|
38
|
-
const d = path.join(dest, entry.name);
|
|
39
|
-
if (entry.isDirectory()) copyRecursive(s, d);
|
|
40
|
-
else fs.copyFileSync(s, d);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function installClaudeSkill() {
|
|
45
|
-
if (!fs.existsSync(SKILL_SOURCE)) {
|
|
46
|
-
console.log(`⚠️ Skill source not found at ${SKILL_SOURCE}; skipping Claude Code install.`);
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
try {
|
|
50
|
-
fs.mkdirSync(CLAUDE_SKILLS_DIR, { recursive: true });
|
|
51
|
-
copyRecursive(SKILL_SOURCE, CLAUDE_SKILL_TARGET);
|
|
52
|
-
console.log(`📦 Installed Claude Code skill at: ${CLAUDE_SKILL_TARGET}`);
|
|
53
|
-
console.log(' Restart Claude Code to load it. Invoke via Skill tool as "agentic-sdlc".');
|
|
54
|
-
return true;
|
|
55
|
-
} catch (err) {
|
|
56
|
-
console.log(`⚠️ Failed to install Claude Code skill: ${err.message}`);
|
|
57
|
-
console.log(` Manual install: copy "${SKILL_SOURCE}" to "${CLAUDE_SKILL_TARGET}".`);
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function installCodexSkill() {
|
|
6
|
+
function installSkill(client) {
|
|
63
7
|
if (!fs.existsSync(SKILL_SOURCE)) {
|
|
64
|
-
console.log(`⚠️ Skill source not found at ${SKILL_SOURCE}; skipping
|
|
8
|
+
console.log(`⚠️ Skill source not found at ${SKILL_SOURCE}; skipping ${client.label} install.`);
|
|
65
9
|
return false;
|
|
66
10
|
}
|
|
11
|
+
const target = skillTarget(client);
|
|
67
12
|
try {
|
|
68
|
-
fs.mkdirSync(
|
|
69
|
-
copyRecursive(SKILL_SOURCE,
|
|
70
|
-
console.log(`📦 Installed
|
|
71
|
-
console.log(
|
|
13
|
+
fs.mkdirSync(target, { recursive: true });
|
|
14
|
+
copyRecursive(SKILL_SOURCE, target);
|
|
15
|
+
console.log(`📦 Installed ${client.label} skill at: ${target}`);
|
|
16
|
+
console.log(` ${client.reload}`);
|
|
72
17
|
return true;
|
|
73
18
|
} catch (err) {
|
|
74
|
-
console.log(`⚠️ Failed to install
|
|
75
|
-
console.log(` Manual install: copy "${SKILL_SOURCE}" to "${
|
|
19
|
+
console.log(`⚠️ Failed to install ${client.label} skill: ${err.message}`);
|
|
20
|
+
console.log(` Manual install: copy "${SKILL_SOURCE}" to "${target}".`);
|
|
76
21
|
return false;
|
|
77
22
|
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function installGeminiSkill() {
|
|
81
|
-
if (!fs.existsSync(SKILL_SOURCE)) {
|
|
82
|
-
console.log(`⚠️ Skill source not found at ${SKILL_SOURCE}; skipping Gemini install.`);
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
try {
|
|
86
|
-
fs.mkdirSync(GEMINI_SKILLS_DIR, { recursive: true });
|
|
87
|
-
copyRecursive(SKILL_SOURCE, GEMINI_SKILL_TARGET);
|
|
88
|
-
console.log(`📦 Installed Gemini skill at: ${GEMINI_SKILL_TARGET}`);
|
|
89
|
-
console.log(' Run "gemini skills reload" or restart Gemini CLI to load it.');
|
|
90
|
-
return true;
|
|
91
|
-
} catch (err) {
|
|
92
|
-
console.log(`⚠️ Failed to install Gemini skill: ${err.message}`);
|
|
93
|
-
console.log(` Manual install: copy "${SKILL_SOURCE}" to "${GEMINI_SKILL_TARGET}".`);
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function hasCodexHome() {
|
|
99
|
-
return Boolean(process.env.CODEX_HOME) || fs.existsSync(CODEX_HOME);
|
|
100
23
|
}
|
|
101
24
|
|
|
102
|
-
function hasClaudeHome() {
|
|
103
|
-
return Boolean(process.env.CLAUDE_CONFIG_DIR) || fs.existsSync(CLAUDE_HOME);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function hasGeminiHome() {
|
|
107
|
-
return Boolean(process.env.GEMINI_HOME) || fs.existsSync(GEMINI_HOME);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
25
|
console.log('\n--- Agentic SDLC Skill Discovery ---');
|
|
111
26
|
|
|
112
27
|
let detected = false;
|
|
113
|
-
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (checkCommand('gemini') || hasGeminiHome()) {
|
|
121
|
-
console.log(`✅ Detected: Gemini CLI`);
|
|
122
|
-
detected = true;
|
|
123
|
-
installGeminiSkill();
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (checkCommand('codex') || hasCodexHome()) {
|
|
127
|
-
console.log(`✅ Detected: Codex AI`);
|
|
128
|
-
detected = true;
|
|
129
|
-
installCodexSkill();
|
|
28
|
+
for (const client of CLIENTS) {
|
|
29
|
+
if (clientDetected(client)) {
|
|
30
|
+
console.log(`✅ Detected: ${client.label}`);
|
|
31
|
+
detected = true;
|
|
32
|
+
installSkill(client);
|
|
33
|
+
}
|
|
130
34
|
}
|
|
131
35
|
|
|
132
36
|
if (!detected) {
|
package/scripts/preuninstall.js
CHANGED
|
@@ -1,26 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const
|
|
5
|
-
const os = require('os');
|
|
4
|
+
const { CLIENTS, skillTarget } = require('./lib');
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const CODEX_HOME = process.env.CODEX_HOME || path.join(os.homedir(), '.codex');
|
|
10
|
-
const CODEX_SKILL_TARGET = path.join(CODEX_HOME, 'skills', 'agentic-sdlc');
|
|
11
|
-
const GEMINI_HOME = process.env.GEMINI_HOME || path.join(os.homedir(), '.gemini');
|
|
12
|
-
const GEMINI_SKILL_TARGET = path.join(GEMINI_HOME, 'skills', 'agentic-sdlc');
|
|
13
|
-
|
|
14
|
-
function removeSkill(target, label) {
|
|
6
|
+
function removeSkill(client) {
|
|
7
|
+
const target = skillTarget(client);
|
|
15
8
|
if (!fs.existsSync(target)) return;
|
|
16
9
|
try {
|
|
17
10
|
fs.rmSync(target, { recursive: true, force: true });
|
|
18
|
-
console.log(`🧹 Removed ${label} skill at: ${target}`);
|
|
11
|
+
console.log(`🧹 Removed ${client.label} skill at: ${target}`);
|
|
19
12
|
} catch (err) {
|
|
20
13
|
console.log(`⚠️ Could not remove ${target}: ${err.message}`);
|
|
21
14
|
}
|
|
22
15
|
}
|
|
23
16
|
|
|
24
|
-
removeSkill
|
|
25
|
-
removeSkill(CODEX_SKILL_TARGET, 'Codex');
|
|
26
|
-
removeSkill(GEMINI_SKILL_TARGET, 'Gemini');
|
|
17
|
+
CLIENTS.forEach(removeSkill);
|
|
@@ -1,55 +1,56 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## 1.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
python "<
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
(`check` = validate + stale in
|
|
14
|
-
|
|
15
|
-
## 2. Check in CI (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
python tools/sdlc_check.py validate
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
## 3.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
```json
|
|
32
|
-
{
|
|
33
|
-
"hooks": {
|
|
34
|
-
"PreToolUse": [
|
|
35
|
-
{
|
|
36
|
-
"matcher": "Write|Edit",
|
|
37
|
-
"hooks": [
|
|
38
|
-
{
|
|
39
|
-
"type": "command",
|
|
40
|
-
"command": "python \"C:\\Users\\<
|
|
41
|
-
}
|
|
42
|
-
]
|
|
43
|
-
}
|
|
44
|
-
]
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
**
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
- `ai_docs/`, `tests/`
|
|
55
|
-
-
|
|
1
|
+
# Mechanical enforcement (optional, recommended for teams)
|
|
2
|
+
|
|
3
|
+
Prompt-level rules depend on the model's discipline and degrade with long contexts, compaction and competing instructions. Three levels of increasing guarantee:
|
|
4
|
+
|
|
5
|
+
## 1. Interactive validation (default, no setup)
|
|
6
|
+
|
|
7
|
+
The agent runs a single gate at closure (Phase 5):
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
python "<skill_dir>/scripts/sdlc_check.py" check
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
(`check` = validate + stale in one command.) Exit code ≠ 0 ⇒ the feature is not declared closed. This is the minimum level the skill expects.
|
|
14
|
+
|
|
15
|
+
## 2. Check in CI (recommended for teams)
|
|
16
|
+
|
|
17
|
+
Copy `scripts/sdlc_check.py` into the repository (e.g. `tools/sdlc_check.py`) and add to the pipeline:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
python tools/sdlc_check.py validate --strict
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Effect: an unregenerated index, invalid frontmatter, a missing security section or incoherent states **block the pipeline** instead of relying on the agent's memory. `--strict` also fails on warnings and on a missing `ai_docs/`, so a wrong working directory cannot produce a green pipeline. This works because documents travel in the same PR as the code (Phase 5 rule).
|
|
24
|
+
|
|
25
|
+
Note: the copy in the repo is the authoritative one for CI; update it when you update the skill.
|
|
26
|
+
|
|
27
|
+
## 3. PreToolUse hook (gate on writes)
|
|
28
|
+
|
|
29
|
+
Blocks Edit/Write on protected paths when no `ANALYSIS_*.md` is `IN_PROGRESS`. In the project's `.claude/settings.json`:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"hooks": {
|
|
34
|
+
"PreToolUse": [
|
|
35
|
+
{
|
|
36
|
+
"matcher": "Write|Edit",
|
|
37
|
+
"hooks": [
|
|
38
|
+
{
|
|
39
|
+
"type": "command",
|
|
40
|
+
"command": "python \"C:\\Users\\<user>\\.claude\\skills\\agentic-sdlc\\scripts\\sdlc_check.py\" gate --hook --protected \"src/auth;src/crypto\""
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Semantics: exit code 2 + message on stderr ⇒ the write is blocked and the message is shown to the agent, which must create the ANALYSIS (Phase 3) before retrying.
|
|
50
|
+
|
|
51
|
+
**Usage warnings:**
|
|
52
|
+
- The gate is deliberately coarse: applied to all of `src/` it would also block the legitimate L1/L2 tasks foreseen by the Triage. Use it **only on security-critical directories** (`--protected "src/auth;src/crypto"`), where "never without analysis" is the desired policy.
|
|
53
|
+
- The paths in `--protected` are prefixes relative to the project root, separated by `;`.
|
|
54
|
+
- `ai_docs/`, `tests/` and `test/` are always excluded from blocking.
|
|
55
|
+
- The hook assumes the working directory is the project root (standard behavior of Claude Code hooks).
|
|
56
|
+
- **Hybrid/devPNT projects**: add `--hybrid` to the gate command. Governed designs live in the devPNT DB, so the gate also unlocks when an approved E-TDD shadow (`ai_docs/solutions/SHADOW_*tdd*.md`, exported before implementation — see the SKILL.md shadow discipline) is present. Without the flag the gate would block legitimate governed work. The flag is deliberately explicit: never auto-detected.
|