@antoneeo/mkt-agentic-sdlc-skill 0.4.7 → 0.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 +54 -0
- package/gemini-extension.json +6 -6
- package/package.json +50 -50
- package/scripts/init.js +123 -6
- package/scripts/lib.js +440 -233
- package/skills/mkt-agentic-sdlc/ENFORCEMENT.md +33 -2
- package/skills/mkt-agentic-sdlc/SKILL.md +240 -240
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,59 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.0] - 2026-08-25
|
|
4
|
+
|
|
5
|
+
F-036 — the orientation hook installs itself.
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **`ENFORCEMENT.md` 4 said "wire it on every project" and nothing ever did.** The
|
|
9
|
+
SessionStart orientation hook was real, tested and fail-open, but installing it was a
|
|
10
|
+
manual step, so it was skipped — and a session that never enters Phase 1 explicitly
|
|
11
|
+
then never meets the guide router at all. Field result: an agent worked a governed
|
|
12
|
+
project without invoking the process. `init` now wires the hook itself.
|
|
13
|
+
- **The invariant that looked like it guarded this guarded only prose** — it asserted
|
|
14
|
+
the documentation section exists (`assertIn("## 4. SessionStart hook", t)`) and that
|
|
15
|
+
`orient` runs. It gains a companion asserting the shipped installer actually CALLS the
|
|
16
|
+
writer. Mutation-tested: the first draft asserted the bare symbol and passed on a file
|
|
17
|
+
that imports the writer without invoking it, which is exactly the disabled-installer
|
|
18
|
+
case it exists to catch.
|
|
19
|
+
|
|
20
|
+
### Fixed (also)
|
|
21
|
+
- **ENFORCEMENT 4/2's own worked hook examples named a skill directory that two of
|
|
22
|
+
the three lenses do not install.** kb and mkt both printed
|
|
23
|
+
`.claude/skills/agentic-sdlc/scripts/...`; kb installs under `kb-agentic` and mkt
|
|
24
|
+
under `mkt-agentic-sdlc`, so anyone who copied the snippet got a hook that runs,
|
|
25
|
+
prints `can't open file`, and emits nothing — the wired-and-dead defect this release
|
|
26
|
+
detects, sitting in the instructions that produce it. Four paths corrected, and a new
|
|
27
|
+
invariant derives the expected directory and validator from what the distribution
|
|
28
|
+
actually ships and fails if an example names anything else. Mutation-tested.
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- **A portability rule the doctrine did not have.** The hook command names a validator,
|
|
32
|
+
and where that validator lives decides which settings file may carry it: a repo that
|
|
33
|
+
vendors the validator gets a repo-relative command in the shared, committed
|
|
34
|
+
`.claude/settings.json`; a normal project gets an absolute path, which goes to the
|
|
35
|
+
git-ignored `.claude/settings.local.json` instead — committing it would hand every
|
|
36
|
+
teammate a hook naming a directory they do not have. `init` picks the file and adds
|
|
37
|
+
the local one to `.gitignore`. ENFORCEMENT 4's own worked example showed an absolute
|
|
38
|
+
path and did not mention the distinction; it now does.
|
|
39
|
+
- **A wired-but-dead hook is detected and reported instead of counted as done.** Found
|
|
40
|
+
in the field: a repository whose hook named a sibling lens's path, so it ran every
|
|
41
|
+
session, printed `can't open file`, and emitted nothing. A bare "is a hook present?"
|
|
42
|
+
check answers "already wired" to that and makes the silence permanent, so the existing
|
|
43
|
+
command's validator path is checked on disk. Never rewritten — it may be hand-tuned —
|
|
44
|
+
but never passed off as working either.
|
|
45
|
+
|
|
46
|
+
### Notes
|
|
47
|
+
- `init` declines rather than guessing: no Python, skill not installed, a settings file
|
|
48
|
+
that is not valid JSON (never rewritten — a merge would discard what is in it), or a
|
|
49
|
+
skill path containing a double quote. Each case prints the snippet to paste.
|
|
50
|
+
- Only Claude Code's hook shape is wired. Codex and Gemini keep the manual snippet: this
|
|
51
|
+
repository has no fixture pinning their schema, and writing a hook file in a shape
|
|
52
|
+
nobody has verified is how the wired-but-dead defect above was born.
|
|
53
|
+
- A blocking `PreToolUse` gate would be real enforcement rather than a nudge, and it is
|
|
54
|
+
refused by the Vision's no-ceremony-ratchet Non-Goal. Recorded in the analysis so the
|
|
55
|
+
next person to have the idea finds the ruling instead of re-deriving it.
|
|
56
|
+
|
|
3
57
|
## [0.4.7] - 2026-08-06
|
|
4
58
|
|
|
5
59
|
### Fixed
|
package/gemini-extension.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "mkt-agentic-sdlc",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Evidence-First marketing planning protocol with engagement triage, SOSTAC workflow, evidence ledger and optional devPNT integration.",
|
|
5
|
-
"author": "Antonio Pinto (https://github.com/Antoneeo)"
|
|
6
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "mkt-agentic-sdlc",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Evidence-First marketing planning protocol with engagement triage, SOSTAC workflow, evidence ledger and optional devPNT integration.",
|
|
5
|
+
"author": "Antonio Pinto (https://github.com/Antoneeo)"
|
|
6
|
+
}
|
package/package.json
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@antoneeo/mkt-agentic-sdlc-skill",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Evidence-First marketing planning protocol for Claude Code, Gemini CLI, Google Antigravity and Codex: engagement triage, SOSTAC workflow, evidence ledger, mechanical validator and optional devPNT integration.",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"claude-code",
|
|
7
|
-
"claude-skill",
|
|
8
|
-
"gemini-cli",
|
|
9
|
-
"skill",
|
|
10
|
-
"marketing",
|
|
11
|
-
"marketing-plan",
|
|
12
|
-
"sostac",
|
|
13
|
-
"ai-agent"
|
|
14
|
-
],
|
|
15
|
-
"author": "Antonio Pinto (https://github.com/Antoneeo)",
|
|
16
|
-
"license": "MIT",
|
|
17
|
-
"publishConfig": {
|
|
18
|
-
"access": "public"
|
|
19
|
-
},
|
|
20
|
-
"bin": {
|
|
21
|
-
"mkt-sdlc-init": "scripts/init.js",
|
|
22
|
-
"mkt-sdlc-install-skill": "scripts/postinstall.js"
|
|
23
|
-
},
|
|
24
|
-
"scripts": {
|
|
25
|
-
"postinstall": "node scripts/postinstall.js",
|
|
26
|
-
"preuninstall": "node scripts/preuninstall.js"
|
|
27
|
-
},
|
|
28
|
-
"files": [
|
|
29
|
-
"skills/mkt-agentic-sdlc/SKILL.md",
|
|
30
|
-
"skills/mkt-agentic-sdlc/frameworks.md",
|
|
31
|
-
"skills/mkt-agentic-sdlc/elicitation.md",
|
|
32
|
-
"skills/mkt-agentic-sdlc/research.md",
|
|
33
|
-
"skills/mkt-agentic-sdlc/templates.md",
|
|
34
|
-
"skills/mkt-agentic-sdlc/review.md",
|
|
35
|
-
"skills/mkt-agentic-sdlc/scripts/sdlc_core.py",
|
|
36
|
-
"skills/mkt-agentic-sdlc/routing.md",
|
|
37
|
-
"skills/mkt-agentic-sdlc/guides.md",
|
|
38
|
-
"skills/mkt-agentic-sdlc/vision.md",
|
|
39
|
-
"skills/mkt-agentic-sdlc/dispatch.md",
|
|
40
|
-
"skills/mkt-agentic-sdlc/ENFORCEMENT.md",
|
|
41
|
-
"skills/mkt-agentic-sdlc/scripts/mkt_check.py",
|
|
42
|
-
"gemini-extension.json",
|
|
43
|
-
"README.md",
|
|
44
|
-
"CHANGELOG.md",
|
|
45
|
-
"scripts/lib.js",
|
|
46
|
-
"scripts/init.js",
|
|
47
|
-
"scripts/postinstall.js",
|
|
48
|
-
"scripts/preuninstall.js"
|
|
49
|
-
]
|
|
50
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@antoneeo/mkt-agentic-sdlc-skill",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Evidence-First marketing planning protocol for Claude Code, Gemini CLI, Google Antigravity and Codex: engagement triage, SOSTAC workflow, evidence ledger, mechanical validator and optional devPNT integration.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"claude-code",
|
|
7
|
+
"claude-skill",
|
|
8
|
+
"gemini-cli",
|
|
9
|
+
"skill",
|
|
10
|
+
"marketing",
|
|
11
|
+
"marketing-plan",
|
|
12
|
+
"sostac",
|
|
13
|
+
"ai-agent"
|
|
14
|
+
],
|
|
15
|
+
"author": "Antonio Pinto (https://github.com/Antoneeo)",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"bin": {
|
|
21
|
+
"mkt-sdlc-init": "scripts/init.js",
|
|
22
|
+
"mkt-sdlc-install-skill": "scripts/postinstall.js"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"postinstall": "node scripts/postinstall.js",
|
|
26
|
+
"preuninstall": "node scripts/preuninstall.js"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"skills/mkt-agentic-sdlc/SKILL.md",
|
|
30
|
+
"skills/mkt-agentic-sdlc/frameworks.md",
|
|
31
|
+
"skills/mkt-agentic-sdlc/elicitation.md",
|
|
32
|
+
"skills/mkt-agentic-sdlc/research.md",
|
|
33
|
+
"skills/mkt-agentic-sdlc/templates.md",
|
|
34
|
+
"skills/mkt-agentic-sdlc/review.md",
|
|
35
|
+
"skills/mkt-agentic-sdlc/scripts/sdlc_core.py",
|
|
36
|
+
"skills/mkt-agentic-sdlc/routing.md",
|
|
37
|
+
"skills/mkt-agentic-sdlc/guides.md",
|
|
38
|
+
"skills/mkt-agentic-sdlc/vision.md",
|
|
39
|
+
"skills/mkt-agentic-sdlc/dispatch.md",
|
|
40
|
+
"skills/mkt-agentic-sdlc/ENFORCEMENT.md",
|
|
41
|
+
"skills/mkt-agentic-sdlc/scripts/mkt_check.py",
|
|
42
|
+
"gemini-extension.json",
|
|
43
|
+
"README.md",
|
|
44
|
+
"CHANGELOG.md",
|
|
45
|
+
"scripts/lib.js",
|
|
46
|
+
"scripts/init.js",
|
|
47
|
+
"scripts/postinstall.js",
|
|
48
|
+
"scripts/preuninstall.js"
|
|
49
|
+
]
|
|
50
|
+
}
|
package/scripts/init.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const { execSync } = require('child_process');
|
|
6
|
-
const { SKILL_SOURCE, INSTALLED_SKILL_NAME, SELF_LENS, SIBLING_LENSES, CLIENTS, clientDetected, skillTarget, loadTemplates, templateFor } = require('./lib');
|
|
6
|
+
const { SKILL_SOURCE, INSTALLED_SKILL_NAME, SELF_LENS, SIBLING_LENSES, CLIENTS, clientDetected, skillTarget, wireOrientHook, loadTemplates, templateFor } = require('./lib');
|
|
7
7
|
|
|
8
8
|
const cwd = process.cwd();
|
|
9
9
|
|
|
@@ -147,8 +147,22 @@ const protocolFiles = {
|
|
|
147
147
|
// written aside and merged by hand.
|
|
148
148
|
let protocolPreexisting = false;
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
// Probed ONCE and reused by section 6c: re-filtering CLIENTS there would
|
|
151
|
+
// run every client's detection a second time.
|
|
152
|
+
const detectedClients = CLIENTS.filter(clientDetected);
|
|
153
|
+
const PYTHON_CANDIDATES = ['python', 'python3', 'py'];
|
|
154
|
+
const detectedPython = (() => {
|
|
155
|
+
for (const py of PYTHON_CANDIDATES) {
|
|
156
|
+
try {
|
|
157
|
+
execSync(`${py} --version`, { stdio: 'ignore' });
|
|
158
|
+
return py;
|
|
159
|
+
} catch (e) { /* try the next interpreter */ }
|
|
160
|
+
}
|
|
161
|
+
return null;
|
|
162
|
+
})();
|
|
163
|
+
|
|
164
|
+
for (const client of detectedClients) {
|
|
165
|
+
{
|
|
152
166
|
console.log(`✅ ${client.label} detected.`);
|
|
153
167
|
const created = writeIfNotExists(protocolFiles[client.key], protocolContent, `${client.label} protocol pointer`);
|
|
154
168
|
if (!created) protocolPreexisting = true;
|
|
@@ -211,16 +225,119 @@ Delete it once the merge is done.
|
|
|
211
225
|
}
|
|
212
226
|
}
|
|
213
227
|
|
|
228
|
+
|
|
229
|
+
// 6c. SessionStart orientation hook (F-036).
|
|
230
|
+
// ENFORCEMENT.md §4 asks for this on every project with a docs root and Python.
|
|
231
|
+
// It was a manual step until now, so it was skipped -- and a session that never
|
|
232
|
+
// enters Phase 1 explicitly then never meets the guide router at all.
|
|
233
|
+
|
|
234
|
+
// devPNT projects want `--hybrid`: without it the hook reports audit-plan
|
|
235
|
+
// staleness that devPNT/KL owns, and noise at every session start is how a
|
|
236
|
+
// session-start message stops being read.
|
|
237
|
+
const hybridProject = fs.existsSync(path.join(cwd, '.devpnt'));
|
|
238
|
+
|
|
239
|
+
// Only touch .gitignore when the wiring landed in the machine-specific file:
|
|
240
|
+
// if that file is not ignored, the absolute path reaches teammates anyway and
|
|
241
|
+
// the whole reason for choosing it is undone. Append-only and marker-guarded,
|
|
242
|
+
// exactly like gitattributes() above. Wrapped, because the installer has already
|
|
243
|
+
// written the seed files and must not die here.
|
|
244
|
+
const ignoreLocalSettings = () => {
|
|
245
|
+
const marker = '.claude/settings.local.json';
|
|
246
|
+
if (!fs.existsSync(path.join(cwd, '.git'))) return;
|
|
247
|
+
const filePath = path.join(cwd, '.gitignore');
|
|
248
|
+
try {
|
|
249
|
+
const current = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : '';
|
|
250
|
+
// Line-wise, not substring: a `!.claude/settings.local.json` un-ignore would
|
|
251
|
+
// satisfy `includes()` and leave the machine-specific path committed.
|
|
252
|
+
if (current.split(/\r?\n/).some((l) => l.trim() === marker)) return;
|
|
253
|
+
fs.writeFileSync(filePath, current + [
|
|
254
|
+
'',
|
|
255
|
+
'# agentic-sdlc: the orientation hook here names a path on THIS machine.',
|
|
256
|
+
marker,
|
|
257
|
+
'',
|
|
258
|
+
].join(EOL), 'utf8');
|
|
259
|
+
console.log(`OK .gitignore: ${marker} ignored (it names a machine-specific path).`);
|
|
260
|
+
console.log(' If it is already tracked, run: git rm --cached ' + marker);
|
|
261
|
+
} catch (e) {
|
|
262
|
+
console.log(`⚠️ Could not update .gitignore (${e.message}). Add "${marker}" by hand.`);
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const claudeClient = detectedClients.find((c) => c.key === 'claude');
|
|
267
|
+
const otherClients = detectedClients.filter((c) => c.key !== 'claude');
|
|
268
|
+
if (!claudeClient) {
|
|
269
|
+
console.log('ℹ️ Claude Code not detected: SessionStart orientation hook not wired.');
|
|
270
|
+
} else {
|
|
271
|
+
const r = wireOrientHook({
|
|
272
|
+
cwd, client: claudeClient, python: detectedPython,
|
|
273
|
+
hybrid: hybridProject, docsLabel: 'mkt_docs',
|
|
274
|
+
});
|
|
275
|
+
switch (r.code) {
|
|
276
|
+
case 'wired':
|
|
277
|
+
console.log(`🪝 Wired the SessionStart orientation hook in .claude/${r.file}.`);
|
|
278
|
+
if (r.local) {
|
|
279
|
+
console.log(' It names a path on THIS machine, so it went to the git-ignored');
|
|
280
|
+
console.log(' file: each teammate runs init once to get their own.');
|
|
281
|
+
ignoreLocalSettings();
|
|
282
|
+
}
|
|
283
|
+
break;
|
|
284
|
+
case 'already':
|
|
285
|
+
console.log(`⏭️ SessionStart orientation hook already wired (.claude/${r.file}).`);
|
|
286
|
+
if (r.file === 'settings.local.json') ignoreLocalSettings();
|
|
287
|
+
break;
|
|
288
|
+
case 'broken':
|
|
289
|
+
console.log(`⚠️ The SessionStart orientation hook in .claude/${r.file} is BROKEN —`);
|
|
290
|
+
console.log(' its validator does not resolve, so it has been emitting nothing:');
|
|
291
|
+
console.log(` ${r.existing}`);
|
|
292
|
+
console.log(' Not overwritten (it may be hand-tuned). Correct it to:');
|
|
293
|
+
console.log(` ${r.command}`);
|
|
294
|
+
break;
|
|
295
|
+
case 'unverifiable':
|
|
296
|
+
console.log(`ℹ️ A SessionStart orientation hook exists in .claude/${r.file} but names`);
|
|
297
|
+
console.log(' no validator this installer recognises, so it was left alone:');
|
|
298
|
+
console.log(` ${r.existing}`);
|
|
299
|
+
break;
|
|
300
|
+
case 'malformed':
|
|
301
|
+
console.log(`⚠️ .claude/${r.file} has a shape this installer will not rewrite`);
|
|
302
|
+
console.log(` (${r.why}): left untouched. Add the hook by hand — command:`);
|
|
303
|
+
console.log(` ${JSON.stringify(r.command)}`);
|
|
304
|
+
break;
|
|
305
|
+
case 'write-failed':
|
|
306
|
+
console.log(`⚠️ Could not write .claude/${r.file} (${r.error}). Add by hand:`);
|
|
307
|
+
console.log(` ${JSON.stringify(r.command)}`);
|
|
308
|
+
break;
|
|
309
|
+
case 'no-python':
|
|
310
|
+
console.log('ℹ️ Python not found: SessionStart orientation hook not wired.');
|
|
311
|
+
break;
|
|
312
|
+
case 'no-validator':
|
|
313
|
+
console.log('ℹ️ Skill not installed yet: orientation hook not wired. Install it');
|
|
314
|
+
console.log(' (below), then re-run init.');
|
|
315
|
+
break;
|
|
316
|
+
case 'unsafe-path':
|
|
317
|
+
console.log('⚠️ The validator path contains a character that cannot be placed in a');
|
|
318
|
+
console.log(` hook command safely: ${r.validator}`);
|
|
319
|
+
console.log(' Refusing to build one. Wire it by hand (ENFORCEMENT.md §4).');
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
for (const c of otherClients) {
|
|
324
|
+
// Said out loud rather than skipped in silence: ENFORCEMENT.md §4's manual
|
|
325
|
+
// snippet is these clients' only route, and a silent skip is what let the
|
|
326
|
+
// "documented default nobody installs" defect live in the first place.
|
|
327
|
+
console.log(`ℹ️ ${c.label}: hook not wired (only Claude Code's shape is verified) —`);
|
|
328
|
+
console.log(' wire it by hand from ENFORCEMENT.md §4 if that client supports it.');
|
|
329
|
+
}
|
|
330
|
+
|
|
214
331
|
// 7. Generate mkt_docs/INDEX.md so the very first `validate` is already clean.
|
|
215
332
|
// The manifest is generated, never seeded: delegate to the validator if Python is available.
|
|
216
333
|
const validator = path.join(SKILL_SOURCE, 'scripts', 'mkt_check.py');
|
|
217
334
|
let indexed = false;
|
|
218
|
-
|
|
335
|
+
// detectedPython is probed once, above: one answer for the hook and for this.
|
|
336
|
+
if (detectedPython) {
|
|
219
337
|
try {
|
|
220
|
-
execSync(`${
|
|
338
|
+
execSync(`${detectedPython} "${validator}" index --root "${cwd}"`, { stdio: 'ignore' });
|
|
221
339
|
console.log('📇 Generated mkt_docs/INDEX.md (document manifest).');
|
|
222
340
|
indexed = true;
|
|
223
|
-
break;
|
|
224
341
|
} catch (e) { /* try the next interpreter */ }
|
|
225
342
|
}
|
|
226
343
|
if (!indexed) {
|