@antoneeo/mkt-agentic-sdlc-skill 0.2.1 → 0.3.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 +68 -22
- package/README.md +67 -57
- package/gemini-extension.json +6 -6
- package/package.json +50 -45
- package/scripts/init.js +214 -147
- package/scripts/lib.js +183 -170
- package/scripts/postinstall.js +42 -42
- package/scripts/preuninstall.js +17 -17
- package/skills/mkt-agentic-sdlc/ENFORCEMENT.md +116 -82
- package/skills/mkt-agentic-sdlc/SKILL.md +236 -201
- package/skills/mkt-agentic-sdlc/dispatch.md +87 -0
- package/skills/mkt-agentic-sdlc/elicitation.md +147 -89
- package/skills/mkt-agentic-sdlc/frameworks.md +105 -105
- package/skills/mkt-agentic-sdlc/guides.md +287 -0
- package/skills/mkt-agentic-sdlc/research.md +104 -104
- package/skills/mkt-agentic-sdlc/review.md +168 -73
- package/skills/mkt-agentic-sdlc/routing.md +100 -0
- package/skills/mkt-agentic-sdlc/scripts/mkt_check.py +677 -567
- package/skills/mkt-agentic-sdlc/scripts/sdlc_core.py +1996 -0
- package/skills/mkt-agentic-sdlc/templates.md +616 -444
- package/skills/mkt-agentic-sdlc/vision.md +245 -0
package/scripts/lib.js
CHANGED
|
@@ -1,170 +1,183 @@
|
|
|
1
|
-
// Shared helpers for the Marketing Agentic SDLC npm scripts (init / postinstall / preuninstall).
|
|
2
|
-
// Single source for client detection and skill-target paths: init and postinstall
|
|
3
|
-
// must never disagree on what "Claude Code is installed" means.
|
|
4
|
-
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const os = require('os');
|
|
8
|
-
const { execSync } = require('child_process');
|
|
9
|
-
|
|
10
|
-
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
11
|
-
const SKILL_SOURCE = path.join(PACKAGE_ROOT, 'skills', 'mkt-agentic-sdlc');
|
|
12
|
-
const TEMPLATES_PATH = path.join(SKILL_SOURCE, 'templates.md');
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
fs.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
1
|
+
// Shared helpers for the Marketing Agentic SDLC npm scripts (init / postinstall / preuninstall).
|
|
2
|
+
// Single source for client detection and skill-target paths: init and postinstall
|
|
3
|
+
// must never disagree on what "Claude Code is installed" means.
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
const { execSync } = require('child_process');
|
|
9
|
+
|
|
10
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
11
|
+
const SKILL_SOURCE = path.join(PACKAGE_ROOT, 'skills', 'mkt-agentic-sdlc');
|
|
12
|
+
const TEMPLATES_PATH = path.join(SKILL_SOURCE, 'templates.md');
|
|
13
|
+
// Kept for backward compatibility with this package's own scripts; the
|
|
14
|
+
// authoritative value is INSTALLED_SKILL_NAME, derived from SKILL.md below.
|
|
15
|
+
// The directory name each client loads the skill from. Derived from the manifest,
|
|
16
|
+
// never hard-coded by a consumer: three distributions share these scripts, and a
|
|
17
|
+
// literal here is how a copy-fork starts installing under its sibling's name.
|
|
18
|
+
const INSTALLED_SKILL_NAME = (() => {
|
|
19
|
+
const m = fs.readFileSync(path.join(SKILL_SOURCE, 'SKILL.md'), 'utf8').match(/^name:\s*(\S+)/m);
|
|
20
|
+
if (!m) throw new Error(`SKILL.md carries no 'name:' field: ${SKILL_SOURCE}`);
|
|
21
|
+
return m[1];
|
|
22
|
+
})();
|
|
23
|
+
|
|
24
|
+
// One entry per supported AI client. `home` may be overridden by an env var
|
|
25
|
+
// (Claude Desktop / portable installs); presence of the home dir counts as
|
|
26
|
+
// detection even when the CLI is not on PATH.
|
|
27
|
+
|
|
28
|
+
// One entry per supported AI client. `home` may be overridden by an env var
|
|
29
|
+
// (Claude Desktop / portable installs); presence of the home dir counts as
|
|
30
|
+
// detection even when the CLI is not on PATH.
|
|
31
|
+
const CLIENTS = [
|
|
32
|
+
{
|
|
33
|
+
key: 'claude',
|
|
34
|
+
label: 'Claude Code',
|
|
35
|
+
cmd: 'claude',
|
|
36
|
+
home: process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude'),
|
|
37
|
+
envVar: 'CLAUDE_CONFIG_DIR',
|
|
38
|
+
reload: 'Restart Claude Code to load it. Invoke via Skill tool as "mkt-agentic-sdlc".',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
key: 'gemini',
|
|
42
|
+
label: 'Gemini CLI',
|
|
43
|
+
cmd: 'gemini',
|
|
44
|
+
home: process.env.GEMINI_HOME || path.join(os.homedir(), '.gemini'),
|
|
45
|
+
envVar: 'GEMINI_HOME',
|
|
46
|
+
reload: 'Run "gemini skills reload" or restart Gemini CLI to load it.',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
key: 'codex',
|
|
50
|
+
label: 'Codex AI',
|
|
51
|
+
cmd: 'codex',
|
|
52
|
+
home: process.env.CODEX_HOME || path.join(os.homedir(), '.codex'),
|
|
53
|
+
envVar: 'CODEX_HOME',
|
|
54
|
+
reload: 'Restart Codex to load it. Invoke it as "$mkt-agentic-sdlc" or by asking for the Marketing SDLC skill.',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
// Google Antigravity 2.0 discovers global agent skills under
|
|
58
|
+
// ~/.gemini/config/skills/ -- the SAME home the legacy Gemini CLI claims.
|
|
59
|
+
// To avoid a shared-home double-install, this entry sets:
|
|
60
|
+
// - skillsSubdir 'config/skills': distinct target from gemini's ~/.gemini/skills
|
|
61
|
+
// - homeMarker on ~/.gemini/config/skills: detection never fires on bare
|
|
62
|
+
// ~/.gemini (which every Antigravity user has); only the Antigravity skills
|
|
63
|
+
// dir, the `agy` CLI, or ANTIGRAVITY_HOME count as "Antigravity installed".
|
|
64
|
+
key: 'antigravity',
|
|
65
|
+
label: 'Google Antigravity',
|
|
66
|
+
cmd: 'agy',
|
|
67
|
+
home: process.env.ANTIGRAVITY_HOME || path.join(os.homedir(), '.gemini'),
|
|
68
|
+
envVar: 'ANTIGRAVITY_HOME',
|
|
69
|
+
skillsSubdir: 'config/skills',
|
|
70
|
+
homeMarker: path.join(
|
|
71
|
+
process.env.ANTIGRAVITY_HOME || path.join(os.homedir(), '.gemini'),
|
|
72
|
+
'config',
|
|
73
|
+
'skills',
|
|
74
|
+
),
|
|
75
|
+
reload: 'Restart Antigravity, or run "agy skills reload", to load it. Invoke by asking for the Marketing SDLC skill.',
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
function commandExists(cmd) {
|
|
80
|
+
try {
|
|
81
|
+
execSync(`${cmd} --version`, { stdio: 'ignore' });
|
|
82
|
+
return true;
|
|
83
|
+
} catch (e) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function clientDetected(client) {
|
|
89
|
+
// An entry may override the fs-existence probe with a `homeMarker` (a more
|
|
90
|
+
// specific path than the bare home) so two clients sharing a home dir do not
|
|
91
|
+
// both fire on its mere existence. Entries without a marker check `home`
|
|
92
|
+
// exactly as before (backward-compatible).
|
|
93
|
+
const homePathToCheck = client.homeMarker || client.home;
|
|
94
|
+
return commandExists(client.cmd)
|
|
95
|
+
|| Boolean(process.env[client.envVar])
|
|
96
|
+
|| fs.existsSync(homePathToCheck);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function skillTarget(client) {
|
|
100
|
+
// An entry may override the default `skills` sub-path with `skillsSubdir`
|
|
101
|
+
// (split on '/' to keep cross-platform path.join correctness). Entries
|
|
102
|
+
// without it resolve to <home>/skills/mkt-agentic-sdlc exactly as before.
|
|
103
|
+
const subdir = client.skillsSubdir ? client.skillsSubdir.split('/') : ['skills'];
|
|
104
|
+
return path.join(client.home, ...subdir, INSTALLED_SKILL_NAME);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function copyRecursive(src, dest) {
|
|
108
|
+
if (typeof fs.cpSync === 'function') {
|
|
109
|
+
fs.cpSync(src, dest, { recursive: true, force: true });
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
// Fallback for Node < 16.7
|
|
113
|
+
if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
|
|
114
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
115
|
+
const s = path.join(src, entry.name);
|
|
116
|
+
const d = path.join(dest, entry.name);
|
|
117
|
+
if (entry.isDirectory()) copyRecursive(s, d);
|
|
118
|
+
else fs.copyFileSync(s, d);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Parse templates.md into { headingText: [fencedBlock, ...] }.
|
|
124
|
+
* Templates are single-sourced there: the init script must extract them
|
|
125
|
+
* instead of carrying its own inline copies (which historically drifted).
|
|
126
|
+
*/
|
|
127
|
+
function loadTemplates() {
|
|
128
|
+
const text = fs.readFileSync(TEMPLATES_PATH, 'utf8');
|
|
129
|
+
const lines = text.split(/\r?\n/);
|
|
130
|
+
const sections = {};
|
|
131
|
+
let heading = null;
|
|
132
|
+
let block = null;
|
|
133
|
+
for (const line of lines) {
|
|
134
|
+
const h = line.match(/^##\s+(.*)$/);
|
|
135
|
+
if (h && block === null) {
|
|
136
|
+
heading = h[1].trim();
|
|
137
|
+
sections[heading] = sections[heading] || [];
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (/^```/.test(line)) {
|
|
141
|
+
if (block === null) {
|
|
142
|
+
block = [];
|
|
143
|
+
} else {
|
|
144
|
+
if (heading) sections[heading].push(block.join('\n') + '\n');
|
|
145
|
+
block = null;
|
|
146
|
+
}
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (block !== null) block.push(line);
|
|
150
|
+
}
|
|
151
|
+
return sections;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Return the Nth fenced block of the section whose heading contains `needle`.
|
|
156
|
+
* Throws with a clear message when missing: writing a wrong or empty
|
|
157
|
+
* boilerplate silently would be worse than failing the init.
|
|
158
|
+
*/
|
|
159
|
+
function templateFor(sections, needle, index = 0) {
|
|
160
|
+
const heading = Object.keys(sections).find((h) => h.includes(needle));
|
|
161
|
+
const blocks = heading ? sections[heading] : undefined;
|
|
162
|
+
if (!blocks || !blocks[index]) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
`Template section containing "${needle}" (block ${index}) not found in ${TEMPLATES_PATH}. ` +
|
|
165
|
+
'The package is corrupted or templates.md was restructured: fix templates.md, do not improvise content.'
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
return blocks[index];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
module.exports = {
|
|
172
|
+
INSTALLED_SKILL_NAME,
|
|
173
|
+
PACKAGE_ROOT,
|
|
174
|
+
SKILL_SOURCE,
|
|
175
|
+
TEMPLATES_PATH,
|
|
176
|
+
CLIENTS,
|
|
177
|
+
commandExists,
|
|
178
|
+
clientDetected,
|
|
179
|
+
skillTarget,
|
|
180
|
+
copyRecursive,
|
|
181
|
+
loadTemplates,
|
|
182
|
+
templateFor,
|
|
183
|
+
};
|
package/scripts/postinstall.js
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const { SKILL_SOURCE, CLIENTS, clientDetected, skillTarget, copyRecursive } = require('./lib');
|
|
5
|
-
|
|
6
|
-
function installSkill(client) {
|
|
7
|
-
if (!fs.existsSync(SKILL_SOURCE)) {
|
|
8
|
-
console.log(`⚠️ Skill source not found at ${SKILL_SOURCE}; skipping ${client.label} install.`);
|
|
9
|
-
return false;
|
|
10
|
-
}
|
|
11
|
-
const target = skillTarget(client);
|
|
12
|
-
try {
|
|
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}`);
|
|
17
|
-
return true;
|
|
18
|
-
} catch (err) {
|
|
19
|
-
console.log(`⚠️ Failed to install ${client.label} skill: ${err.message}`);
|
|
20
|
-
console.log(` Manual install: copy "${SKILL_SOURCE}" to "${target}".`);
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
console.log('\n--- Marketing Agentic SDLC Skill Discovery ---');
|
|
26
|
-
|
|
27
|
-
let detected = false;
|
|
28
|
-
for (const client of CLIENTS) {
|
|
29
|
-
if (clientDetected(client)) {
|
|
30
|
-
console.log(`✅ Detected: ${client.label}`);
|
|
31
|
-
detected = true;
|
|
32
|
-
installSkill(client);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (!detected) {
|
|
37
|
-
console.log('ℹ️ No specific AI CLI detected globally, but you can still use the skill.');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
console.log('\nTo initialize a project with the marketing protocol, run:');
|
|
41
|
-
console.log('👉 npx mkt-sdlc-init');
|
|
42
|
-
console.log('------------------------------------\n');
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const { SKILL_SOURCE, CLIENTS, clientDetected, skillTarget, copyRecursive } = require('./lib');
|
|
5
|
+
|
|
6
|
+
function installSkill(client) {
|
|
7
|
+
if (!fs.existsSync(SKILL_SOURCE)) {
|
|
8
|
+
console.log(`⚠️ Skill source not found at ${SKILL_SOURCE}; skipping ${client.label} install.`);
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
const target = skillTarget(client);
|
|
12
|
+
try {
|
|
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}`);
|
|
17
|
+
return true;
|
|
18
|
+
} catch (err) {
|
|
19
|
+
console.log(`⚠️ Failed to install ${client.label} skill: ${err.message}`);
|
|
20
|
+
console.log(` Manual install: copy "${SKILL_SOURCE}" to "${target}".`);
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
console.log('\n--- Marketing Agentic SDLC Skill Discovery ---');
|
|
26
|
+
|
|
27
|
+
let detected = false;
|
|
28
|
+
for (const client of CLIENTS) {
|
|
29
|
+
if (clientDetected(client)) {
|
|
30
|
+
console.log(`✅ Detected: ${client.label}`);
|
|
31
|
+
detected = true;
|
|
32
|
+
installSkill(client);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!detected) {
|
|
37
|
+
console.log('ℹ️ No specific AI CLI detected globally, but you can still use the skill.');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
console.log('\nTo initialize a project with the marketing protocol, run:');
|
|
41
|
+
console.log('👉 npx mkt-sdlc-init');
|
|
42
|
+
console.log('------------------------------------\n');
|
package/scripts/preuninstall.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const { CLIENTS, skillTarget } = require('./lib');
|
|
5
|
-
|
|
6
|
-
function removeSkill(client) {
|
|
7
|
-
const target = skillTarget(client);
|
|
8
|
-
if (!fs.existsSync(target)) return;
|
|
9
|
-
try {
|
|
10
|
-
fs.rmSync(target, { recursive: true, force: true });
|
|
11
|
-
console.log(`🧹 Removed ${client.label} skill at: ${target}`);
|
|
12
|
-
} catch (err) {
|
|
13
|
-
console.log(`⚠️ Could not remove ${target}: ${err.message}`);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
CLIENTS.forEach(removeSkill);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const { CLIENTS, skillTarget } = require('./lib');
|
|
5
|
+
|
|
6
|
+
function removeSkill(client) {
|
|
7
|
+
const target = skillTarget(client);
|
|
8
|
+
if (!fs.existsSync(target)) return;
|
|
9
|
+
try {
|
|
10
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
11
|
+
console.log(`🧹 Removed ${client.label} skill at: ${target}`);
|
|
12
|
+
} catch (err) {
|
|
13
|
+
console.log(`⚠️ Could not remove ${target}: ${err.message}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
CLIENTS.forEach(removeSkill);
|