@jakkrichm/create-nexus-devflow 2.14.0 → 2.15.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.
Files changed (40) hide show
  1. package/dist/lib/branch-context.d.ts +1 -0
  2. package/dist/lib/branch-context.js +8 -3
  3. package/dist/lib/branch-context.js.map +1 -1
  4. package/dist/lib/dashboard-page.d.ts +5 -2
  5. package/dist/lib/dashboard-page.js +7 -388
  6. package/dist/lib/dashboard-page.js.map +1 -1
  7. package/dist/lib/dashboard-snapshot.d.ts +22 -3
  8. package/dist/lib/dashboard-snapshot.js +154 -3
  9. package/dist/lib/dashboard-snapshot.js.map +1 -1
  10. package/dist/lib/delivery-lifecycle-engine.d.ts +1 -1
  11. package/dist/lib/delivery-lifecycle-engine.js +1 -1
  12. package/dist/lib/delivery-lifecycle-engine.js.map +1 -1
  13. package/dist/lib/mcp-server-engine.d.ts +57 -0
  14. package/dist/lib/mcp-server-engine.js +678 -0
  15. package/dist/lib/mcp-server-engine.js.map +1 -0
  16. package/dist/lib/mcp.d.ts +15 -27
  17. package/dist/lib/mcp.js +20 -646
  18. package/dist/lib/mcp.js.map +1 -1
  19. package/dist/lib/project-status-engine.d.ts +110 -0
  20. package/dist/lib/project-status-engine.js +493 -0
  21. package/dist/lib/project-status-engine.js.map +1 -0
  22. package/dist/lib/skill-manager.d.ts +2 -82
  23. package/dist/lib/skill-manager.js +15 -1168
  24. package/dist/lib/skill-manager.js.map +1 -1
  25. package/dist/lib/skill-registry-engine.d.ts +121 -0
  26. package/dist/lib/skill-registry-engine.js +824 -0
  27. package/dist/lib/skill-registry-engine.js.map +1 -0
  28. package/dist/lib/status.d.ts +1 -90
  29. package/dist/lib/status.js +7 -467
  30. package/dist/lib/status.js.map +1 -1
  31. package/dist/lib/studio-view-renderer.d.ts +17 -1
  32. package/dist/lib/studio-view-renderer.js +855 -3
  33. package/dist/lib/studio-view-renderer.js.map +1 -1
  34. package/package.json +1 -1
  35. package/template/.agents/skills/complete/SKILL.md +14 -13
  36. package/template/.agents/skills/implement/SKILL.md +36 -2
  37. package/template/.claude/skills/complete/SKILL.md +14 -13
  38. package/template/.claude/skills/implement/SKILL.md +36 -2
  39. package/template/devflow/build-plan.md +5 -4
  40. package/template/devflow/context/ai-interaction.md +4 -2
@@ -1,1186 +1,33 @@
1
- import { execFile } from "node:child_process";
2
- import fs from "node:fs/promises";
3
- import fsSync from "node:fs";
4
- import os from "node:os";
5
- import path from "node:path";
6
- import { promisify } from "node:util";
7
- import { loadCoreSkillInventory } from "./core-skill-inventory.js";
8
- const execFileAsync = promisify(execFile);
9
- export const DEV_ROLE_SKILLS = Object.freeze([
10
- "adopt", "audit", "autopilot", "brainstorm", "brief", "browser-tests",
11
- "bughunter", "check", "ci", "complete", "continuous", "convert-any-to-md",
12
- "debug", "devflow", "discovery", "doctor", "feature", "fix", "grill",
13
- "idea", "implement", "onboard", "overview", "prototype", "release",
14
- "report-html", "rollback", "setup-tests", "status", "test", "try"
15
- ]);
16
- export const SA_ROLE_SKILLS = Object.freeze([
17
- "analyze", "audit", "brainstorm", "brief", "bughunter", "convert-any-to-md",
18
- "devflow", "discovery", "doctor", "grill", "idea", "overview", "prototype",
19
- "report-html", "status"
20
- ]);
21
- export const FULL_ROLE_SKILLS = Object.freeze([
22
- "adopt", "analyze", "audit", "autopilot", "brainstorm", "brief", "browser-tests",
23
- "bughunter", "check", "ci", "complete", "continuous", "convert-any-to-md",
24
- "debug", "devflow", "discovery", "doctor", "feature", "fix", "grill",
25
- "idea", "implement", "onboard", "overview", "prototype", "release",
26
- "report-html", "rollback", "setup-tests", "status", "test", "try"
27
- ]);
28
- export function getSkillsForRole(role, allCoreSkills) {
29
- switch (role) {
30
- case "sa":
31
- return SA_ROLE_SKILLS;
32
- case "full":
33
- return allCoreSkills || FULL_ROLE_SKILLS;
34
- case "dev":
35
- default:
36
- return DEV_ROLE_SKILLS;
37
- }
38
- }
39
- export const KNOWN_SKILL_ALIASES = {
40
- archify: {
41
- source: "https://github.com/tt-a1i/archify",
42
- description: "Interactive technical system architecture, dataflow, and sequence trace diagrams"
43
- },
44
- "diagram-design": {
45
- source: "https://github.com/cathrynlavery/diagram-design",
46
- description: "39 editorial visual diagram templates (Business, Quadrants, Timelines, Mindmaps, Radar)"
47
- },
48
- "9arm-skills": {
49
- source: "https://github.com/thananon/9arm-skills",
50
- all: true,
51
- description: "6 specialized skills (debug-mantra, post-mortem, qwen-agent, scrutinize, management-talk, qwenchance)"
52
- },
53
- "9arm": {
54
- source: "https://github.com/thananon/9arm-skills",
55
- all: true,
56
- description: "4 specialized skills (debug-mantra, post-mortem, scrutinize, management-talk)"
57
- },
58
- bughunter: {
59
- source: "https://github.com/elementalsouls/Claude-BugHunter",
60
- type: "compound-knowledge",
61
- referencePath: "devflow/.vendor/bughunter",
62
- description: "[devflow] Offensive security orchestrator & bug hunting guide"
63
- },
64
- "matt-pocock": {
65
- source: "https://github.com/mattpocock/skills",
66
- name: "matt-pocock",
67
- type: "compound-knowledge",
68
- referencePath: "devflow/.vendor/matt-pocock",
69
- description: "Master Matt Pocock's 6 AI-engineering flows (Getting Started, Main Flow, Shaping, Upkeep, Productivity, Reference)"
70
- },
71
- mattpocock: {
72
- source: "https://github.com/mattpocock/skills",
73
- name: "matt-pocock",
74
- type: "compound-knowledge",
75
- referencePath: "devflow/.vendor/matt-pocock",
76
- description: "Master Matt Pocock's 6 AI-engineering flows (Getting Started, Main Flow, Shaping, Upkeep, Productivity, Reference)"
77
- }
78
- };
79
- export const RECOMMENDED_THIRD_PARTY_SKILLS = Object.freeze([
80
- {
81
- source: "https://github.com/tt-a1i/archify",
82
- description: "Interactive technical system architecture, dataflow, and sequence trace diagrams"
83
- },
84
- {
85
- source: "https://github.com/cathrynlavery/diagram-design",
86
- description: "39 editorial visual diagram templates (Business, Quadrants, Timelines, Mindmaps, Radar)"
87
- },
88
- {
89
- source: "https://github.com/thananon/9arm-skills",
90
- all: true,
91
- description: "4 specialized skills (debug-mantra, post-mortem, scrutinize, management-talk)"
92
- }
93
- ]);
94
- const SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
95
- const MANIFEST_PATH = path.join(".nexus", "nexus-devflow.json");
96
- const AGENT_MANIFEST_PATH = "agent-bundle.manifest.json";
97
- export function parseSkillFrontmatter(content) {
98
- if (!content.startsWith("---"))
99
- return {};
100
- const parts = content.split("---");
101
- if (parts.length < 3)
102
- return {};
103
- const lines = parts[1].split("\n");
104
- let name;
105
- let description;
106
- let version;
107
- for (const line of lines) {
108
- const trimmed = line.trim();
109
- if (trimmed.startsWith("name:")) {
110
- name = trimmed.replace("name:", "").trim().replace(/^["']|["']$/g, "");
111
- }
112
- else if (trimmed.startsWith("description:")) {
113
- description = trimmed.replace("description:", "").trim().replace(/^["']|["']$/g, "");
114
- }
115
- else if (trimmed.startsWith("version:")) {
116
- version = trimmed.replace("version:", "").trim().replace(/^["']|["']$/g, "");
117
- }
118
- }
119
- // Also check metadata: version block
120
- const metaMatch = parts[1].match(/version:\s*["']?([^"'\r\n]+)["']?/);
121
- if (!version && metaMatch) {
122
- version = metaMatch[1].trim();
123
- }
124
- return { name, description, version };
1
+ import { SkillRegistryEngine, DefaultGitRepositoryAdapter, DEV_ROLE_SKILLS, SA_ROLE_SKILLS, FULL_ROLE_SKILLS, getSkillsForRole, KNOWN_SKILL_ALIASES, RECOMMENDED_THIRD_PARTY_SKILLS, parseSkillFrontmatter, discoverSkillsInDirectory, findSkillSourceDirectory } from "./skill-registry-engine.js";
2
+ export { SkillRegistryEngine, DefaultGitRepositoryAdapter, DEV_ROLE_SKILLS, SA_ROLE_SKILLS, FULL_ROLE_SKILLS, getSkillsForRole, KNOWN_SKILL_ALIASES, RECOMMENDED_THIRD_PARTY_SKILLS, parseSkillFrontmatter, discoverSkillsInDirectory, findSkillSourceDirectory };
3
+ function getEngine(projectRoot) {
4
+ return new SkillRegistryEngine(projectRoot);
125
5
  }
126
6
  export async function readDevflowManifest(projectRoot) {
127
- const fullPath = path.join(projectRoot, MANIFEST_PATH);
128
- try {
129
- const raw = await fs.readFile(fullPath, "utf8");
130
- return JSON.parse(raw);
131
- }
132
- catch (err) {
133
- if (err.code === "ENOENT") {
134
- return null;
135
- }
136
- throw err;
137
- }
7
+ return getEngine(projectRoot).readManifest();
138
8
  }
139
9
  export async function writeDevflowManifest(projectRoot, manifest) {
140
- const fullPath = path.join(projectRoot, MANIFEST_PATH);
141
- await fs.mkdir(path.dirname(fullPath), { recursive: true });
142
- await fs.writeFile(fullPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
10
+ return getEngine(projectRoot).writeManifest(manifest);
143
11
  }
144
12
  export async function listInstalledSkills(projectRoot) {
145
- let coreNameSet = new Set();
146
- try {
147
- const inventory = await loadCoreSkillInventory(path.join(projectRoot, AGENT_MANIFEST_PATH));
148
- coreNameSet = inventory.nameSet;
149
- }
150
- catch {
151
- // fallback if manifest not found
152
- }
153
- const manifest = await readDevflowManifest(projectRoot);
154
- const recordedThirdParty = Array.isArray(manifest?.thirdPartySkills)
155
- ? manifest.thirdPartySkills
156
- : [];
157
- const thirdPartyMap = new Map();
158
- for (const record of recordedThirdParty) {
159
- if (record?.name) {
160
- thirdPartyMap.set(record.name, record);
161
- }
162
- }
163
- const agentsDir = path.join(projectRoot, ".agents", "skills");
164
- const claudeDir = path.join(projectRoot, ".claude", "skills");
165
- const agentsSkills = new Set();
166
- const claudeSkills = new Set();
167
- try {
168
- const entries = await fs.readdir(agentsDir, { withFileTypes: true });
169
- for (const e of entries) {
170
- if (e.isDirectory())
171
- agentsSkills.add(e.name);
172
- }
173
- }
174
- catch {
175
- // ignore missing dir
176
- }
177
- try {
178
- const entries = await fs.readdir(claudeDir, { withFileTypes: true });
179
- for (const e of entries) {
180
- if (e.isDirectory())
181
- claudeSkills.add(e.name);
182
- }
183
- }
184
- catch {
185
- // ignore missing dir
186
- }
187
- const allNames = new Set([...agentsSkills, ...claudeSkills, ...thirdPartyMap.keys()]);
188
- const coreSkills = [];
189
- const thirdPartySkills = [];
190
- for (const name of [...allNames].sort()) {
191
- const inAgents = agentsSkills.has(name);
192
- const inClaude = claudeSkills.has(name);
193
- const adapters = [];
194
- if (inAgents)
195
- adapters.push(".agents");
196
- if (inClaude)
197
- adapters.push(".claude");
198
- const skillFilePath = inAgents
199
- ? path.join(agentsDir, name, "SKILL.md")
200
- : path.join(claudeDir, name, "SKILL.md");
201
- let description = "";
202
- let version = "";
203
- try {
204
- const content = await fs.readFile(skillFilePath, "utf8");
205
- const meta = parseSkillFrontmatter(content);
206
- description = meta.description || "";
207
- version = meta.version || "";
208
- }
209
- catch {
210
- // no readable SKILL.md
211
- }
212
- const recorded = thirdPartyMap.get(name);
213
- const isCore = coreNameSet.has(name);
214
- let category = "local-extension";
215
- if (isCore) {
216
- category = "core";
217
- }
218
- else if (recorded) {
219
- category = "third-party";
220
- }
221
- const detail = {
222
- name,
223
- category,
224
- description: description || recorded?.description || "",
225
- version: version || recorded?.version,
226
- source: recorded?.source,
227
- adapters,
228
- synced: inAgents && inClaude,
229
- path: inAgents ? `.agents/skills/${name}` : `.claude/skills/${name}`
230
- };
231
- if (isCore) {
232
- coreSkills.push(detail);
233
- }
234
- else {
235
- thirdPartySkills.push(detail);
236
- }
237
- }
238
- return {
239
- coreSkills,
240
- thirdPartySkills,
241
- totalCount: coreSkills.length + thirdPartySkills.length
242
- };
243
- }
244
- export async function discoverSkillsInDirectory(rootDir, maxDepth = 5, currentDepth = 0) {
245
- const results = [];
246
- if (currentDepth > maxDepth)
247
- return results;
248
- const skillMdPath = path.join(rootDir, "SKILL.md");
249
- if (fsSync.existsSync(skillMdPath)) {
250
- try {
251
- const content = await fs.readFile(skillMdPath, "utf8");
252
- const meta = parseSkillFrontmatter(content);
253
- const skillName = meta.name || path.basename(rootDir);
254
- results.push({
255
- sourceSkillPath: rootDir,
256
- skillName,
257
- meta
258
- });
259
- return results;
260
- }
261
- catch {
262
- // ignore read error
263
- }
264
- }
265
- let entries;
266
- try {
267
- entries = await fs.readdir(rootDir, { withFileTypes: true });
268
- }
269
- catch {
270
- return results;
271
- }
272
- const IGNORED_DIRS = new Set([".git", "node_modules", "dist", ".nexus", "build", "coverage", ".turbo"]);
273
- for (const entry of entries) {
274
- if (entry.isDirectory() && !IGNORED_DIRS.has(entry.name)) {
275
- const subDir = path.join(rootDir, entry.name);
276
- const subResults = await discoverSkillsInDirectory(subDir, maxDepth, currentDepth + 1);
277
- results.push(...subResults);
278
- }
279
- }
280
- return results;
281
- }
282
- export async function findSkillSourceDirectory(sourceDir, requestedName) {
283
- const discovered = await discoverSkillsInDirectory(sourceDir);
284
- if (discovered.length === 0) {
285
- throw new Error(`Could not find any valid skill with SKILL.md in source: ${sourceDir}`);
286
- }
287
- if (requestedName) {
288
- const match = discovered.find((s) => s.skillName === requestedName || path.basename(s.sourceSkillPath) === requestedName);
289
- if (match) {
290
- return {
291
- sourceSkillPath: match.sourceSkillPath,
292
- skillName: requestedName,
293
- meta: match.meta
294
- };
295
- }
296
- const available = discovered.map((s) => s.skillName).join(", ");
297
- throw new Error(`Skill "${requestedName}" not found in source. Available skills (${discovered.length}): ${available}`);
298
- }
299
- if (discovered.length === 1) {
300
- return {
301
- sourceSkillPath: discovered[0].sourceSkillPath,
302
- skillName: discovered[0].skillName,
303
- meta: discovered[0].meta
304
- };
305
- }
306
- // Check if one matches the sourceDir basename
307
- const baseName = path.basename(sourceDir);
308
- const baseMatch = discovered.find((s) => s.skillName === baseName || path.basename(s.sourceSkillPath) === baseName);
309
- if (baseMatch) {
310
- return {
311
- sourceSkillPath: baseMatch.sourceSkillPath,
312
- skillName: baseMatch.skillName,
313
- meta: baseMatch.meta
314
- };
315
- }
316
- const available = discovered.map((s) => s.skillName).join(", ");
317
- throw new Error(`Multiple skills found in source (${discovered.length} skills: ${available}). Please specify --name <skill-name> or use --all to install all skills.`);
13
+ return getEngine(projectRoot).list();
318
14
  }
319
15
  export async function installThirdPartySkill(projectRoot, source, options) {
320
- const alias = KNOWN_SKILL_ALIASES[source.toLowerCase()];
321
- let effectiveSource = source;
322
- let isCompound = false;
323
- let compoundName = "bughunter";
324
- let compoundRefPath = "devflow/.vendor/bughunter";
325
- if (alias) {
326
- effectiveSource = alias.source;
327
- if (alias.type === "compound-knowledge") {
328
- isCompound = true;
329
- compoundName = alias.name || source.toLowerCase();
330
- compoundRefPath = alias.referencePath || path.join("devflow", ".vendor", compoundName);
331
- }
332
- if (alias.all && options?.all === undefined) {
333
- options = { ...options, all: true };
334
- }
335
- if (alias.name && !options?.name) {
336
- options = { ...options, name: alias.name };
337
- }
338
- }
339
- else if (source.includes("Claude-BugHunter")) {
340
- isCompound = true;
341
- compoundName = "bughunter";
342
- compoundRefPath = "devflow/.vendor/bughunter";
343
- }
344
- else if (source.includes("mattpocock/skills") || source.includes("matt-pocock")) {
345
- isCompound = true;
346
- compoundName = "matt-pocock";
347
- compoundRefPath = "devflow/.vendor/matt-pocock";
348
- }
349
- const isGitUrl = /^https?:\/\/|^git@|^ssh:\/\/|\.git$/.test(effectiveSource);
350
- let tempCloneDir = null;
351
- let sourceDirectory = effectiveSource;
352
- let coreNameSet = new Set();
353
- try {
354
- const inventory = await loadCoreSkillInventory(path.join(projectRoot, AGENT_MANIFEST_PATH));
355
- coreNameSet = inventory.nameSet;
356
- }
357
- catch {
358
- // ignore
359
- }
360
- try {
361
- if (isGitUrl) {
362
- tempCloneDir = await fs.mkdtemp(path.join(os.tmpdir(), "nexus-skill-"));
363
- await execFileAsync("git", ["clone", "--depth", "1", effectiveSource, tempCloneDir]);
364
- sourceDirectory = tempCloneDir;
365
- }
366
- else {
367
- sourceDirectory = path.isAbsolute(effectiveSource) ? effectiveSource : path.resolve(projectRoot, effectiveSource);
368
- if (!fsSync.existsSync(sourceDirectory)) {
369
- throw new Error(`Source directory does not exist: ${effectiveSource}`);
370
- }
371
- }
372
- const recordedSource = options?.overrideSource || effectiveSource;
373
- const recordedType = isCompound ? "compound-knowledge" : isGitUrl || options?.overrideSource ? "git" : "local";
374
- if (isCompound) {
375
- const targetRefDir = path.join(projectRoot, compoundRefPath);
376
- await fs.mkdir(targetRefDir, { recursive: true });
377
- const srcSkills = path.join(sourceDirectory, "skills");
378
- if (fsSync.existsSync(srcSkills)) {
379
- await fs.cp(srcSkills, path.join(targetRefDir, "skills"), { recursive: true });
380
- }
381
- const srcCommands = path.join(sourceDirectory, "commands");
382
- if (fsSync.existsSync(srcCommands)) {
383
- await fs.cp(srcCommands, path.join(targetRefDir, "commands"), { recursive: true });
384
- }
385
- const srcReports = path.join(sourceDirectory, "docs", "disclosed-reports");
386
- if (fsSync.existsSync(srcReports)) {
387
- await fs.cp(srcReports, path.join(targetRefDir, "disclosed-reports"), { recursive: true });
388
- }
389
- const srcDocs = path.join(sourceDirectory, "docs");
390
- if (fsSync.existsSync(srcDocs)) {
391
- await fs.cp(srcDocs, path.join(targetRefDir, "docs"), { recursive: true });
392
- }
393
- for (const guideFile of [
394
- "ENGAGEMENTS.md",
395
- "USAGE.md",
396
- "README.md",
397
- "INSTALL.md",
398
- "CONTEXT.md",
399
- "AGENTS.md",
400
- "CLAUDE.md"
401
- ]) {
402
- const srcFile = path.join(sourceDirectory, guideFile);
403
- if (fsSync.existsSync(srcFile)) {
404
- await fs.copyFile(srcFile, path.join(targetRefDir, guideFile));
405
- }
406
- }
407
- const isMatt = compoundName === "matt-pocock";
408
- const compoundDesc = isMatt
409
- ? "Master Matt Pocock's 6 AI-engineering flows (Getting Started, Main Flow, Shaping, Upkeep, Productivity, Reference)"
410
- : "Offensive security orchestrator & bug hunting guide";
411
- const compoundVer = isMatt ? "1.0.0" : "2.0.0";
412
- // Ensure Master Skill is written in .agents and .claude
413
- const masterContent = isMatt
414
- ? `---
415
- name: ${compoundName}
416
- description: "[devflow] Master Matt Pocock's 6 AI-engineering flows (Getting Started, Main Flow, Shaping, Upkeep, Productivity, Reference) for developing software according to real-world situations, while interactively mentoring the developer. References JIT skills in ${compoundRefPath}/. Use when running /matt-pocock, learning AI workflows, or orchestrating spec-driven development."
417
- argument-hint: "[{flow, topic, or question}]"
418
- ---
419
-
420
- # 🧠 ${compoundName} — The 6 Canonical Matt Pocock Flows & Interactive Coaching
421
-
422
- $ARGUMENTS
423
-
424
- \`${compoundName}\` brings the full AI-engineering workflow pioneered by **Matt Pocock** (from [aihero.dev](https://www.aihero.dev)) into Nexus-DevFlow.
425
-
426
- This skill serves two complementary purposes:
427
- 1. **Interactive Coach & Mentor**: Teaches the engineering discipline and mindset behind each flow based on real-world engineering situations.
428
- 2. **Execution & Routing Orchestrator**: Directs, prepares, and dispatches the actual skills located in \`${compoundRefPath}/\`.
429
-
430
- ---
431
-
432
- ## ⚠️ Pre-Flight Check (Knowledge Base Availability)
433
-
434
- Before executing any Matt Pocock flow, advice, or skill guidance:
435
- 1. **Check if \`${compoundRefPath}/\` exists in this project using your file inspection tool (\`view_file\` or \`list_dir\`)**.
436
- 2. **If \`${compoundRefPath}/\` is MISSING / NOT INSTALLED**:
437
- - **DO NOT hallucinate skill instructions or invent fake flows**.
438
- - Inform the user in their configured communication language (defaulting to Thai per \`devflow/config.json\` and \`AGENTS.md\`):
439
- - State clearly that the Matt Pocock skill suite (\`${compoundRefPath}/\`) is not yet installed in this project.
440
- - Provide the exact installation command:
441
- \`\`\`bash
442
- npx @jakkrichm/create-nexus-devflow skill add ${compoundName}
443
- \`\`\`
444
- - Offer to run the installation command on their behalf.
445
- - Stop and wait for installation before proceeding.
446
- 3. **If \`${compoundRefPath}/\` is PRESENT**:
447
- - Proceed with the 6 Canonical Flows, JIT skill references, and interactive coaching below.
448
-
449
- ---
450
-
451
- ## 🧭 The Golden Rule: "Decisions are Yours, Facts are the Agent's"
452
-
453
- Matt Pocock's workflow is built upon a strict division of responsibility:
454
- - **Agent's Role**: Gather codebase facts, inspect primary sources, surface constraints, write deterministic tests, propose candidate options, and draft code.
455
- - **Developer's Role**: Make architectural decisions, approve testing seams, define domain boundaries, and evaluate business trade-offs.
456
-
457
- ---
458
-
459
- ## 🗺️ The 6 Canonical Flows & Real-World Situations
460
-
461
- \`\`\`text
462
- ┌─────────────────────────────────────────────────────────────────────────────┐
463
- │ 01. Getting Started : Setup repo once & Router (/setup-matt-pocock-skills, /ask-matt) │
464
- └──────┬──────────────────────────────────────────────────────────────────────┘
465
- │
466
- ├─────────────────────────────────────────────────────────────┐
467
- ▼ ▼
468
- ┌──────────────────────────────┐ ┌──────────────────────────────┐
469
- │ 03. Shaping │ │ 04. Upkeep │
470
- │ Open questions & fuzzy ideas │ │ Maintenance & bug diagnosis │
471
- │ • /wayfinder (Decision map) │ │ • /diagnosing-bugs (Red loop)│
472
- │ • /prototype (Throwaway code)│ │ • /improve-codebase-arch │
473
- │ • /research (Primary docs) │ │ • /resolving-merge-conflicts │
474
- └──────┬───────────────────────┘ │ • /triage /wizard │
475
- │ (Clarity reached) └──────────────┬───────────────┘
476
- │ │ (Split into issues)
477
- ▼ ▼
478
- ┌─────────────────────────────────────────────────────────────────────────────┐
479
- │ 02. The Main Flow (Idea ➔ Ship Spine) │
480
- │ 1. /grill-with-docs ➔ 2. /to-spec ➔ 3. /to-tickets ➔ [CLEAR] ➔ 4. /implement ➔ 5. /code-review │
481
- └─────────────────────────────────────────────────────────────────────────────┘
482
- ▲ ▲
483
- │ │
484
- ┌──────┴───────────────────────┐ ┌──────────────────────┴───────┐
485
- │ 05. Productivity (Human Collab) │ 06. Reference (Foundations) │
486
- │ • /grill-me (Repo-less idea) │ │ • /codebase-design (Seams) │
487
- │ • /handoff (Session transfer)│ │ • /domain-modeling (Glossary)│
488
- │ • /to-questionnaire /teach │ │ • /grilling (Interview core) │
489
- │ • /wait-what /writing-for-agents │ • /tdd (Red-Green-Refactor) │
490
- └──────────────────────────────┘ └──────────────────────────────┘
491
- \`\`\`
492
-
493
- ---
494
-
495
- ## 01. Getting Started Flow (Initial Configuration & Routing)
496
-
497
- > **Real-World Situation:**
498
- > - A freshly cloned or initialized repository where the AI does not yet know the issue tracker, triage labels, or domain context layout.
499
- > - You have 37 skills available and need an immediate GPS to pick the right flow.
500
-
501
- ### Key Skills:
502
- 1. **\`/setup-matt-pocock-skills\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/setup-matt-pocock-skills/SKILL.md)
503
- - **Action**: Run once per repo to explore the codebase and populate \`docs/agents/\` (configuring Issue Tracker location like \`.scratch/\`, triage labels, and \`CONTEXT.md\` layout).
504
- - **Command**: \`/${compoundName} setup\` or \`/setup-matt-pocock-skills\`
505
- 2. **\`/ask-matt\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/ask-matt/SKILL.md)
506
- - **Action**: Acts as an interactive router. Evaluates your current situation and directs you to the optimal flow.
507
- - **Command**: \`/${compoundName} ask "<your current situation...>"\`
508
-
509
- > 💡 **Matt's Tip:** Never begin coding until the agent understands the project's environment. Running setup once establishes unified project awareness for every tool in the repository.
510
-
511
- ---
512
-
513
- ## 02. The Main Flow (The Spine: Idea ➔ Ship)
514
-
515
- > **Real-World Situation:**
516
- > A feature or requirement is reasonably understood and needs to be taken from raw idea all the way to tested, verified, and shipped code.
517
-
518
- ### The 5 Progressive Steps:
519
- 1. **\`/grill-with-docs\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/grill-with-docs/SKILL.md)
520
- - Conduct 2–3 rounds of Socratic grilling to unearth boundaries, assumptions, and edge cases. Retain domain terms in \`CONTEXT.md\` and record hard-to-reverse decisions in \`docs/adr/\`.
521
- 2. **\`/to-spec\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/to-spec/SKILL.md)
522
- - Synthesize interview results into a Living Spec. Explicitly identify the **Testing Seam** (the highest level of integration to test against) and outline comprehensive User Stories.
523
- 3. **\`/to-tickets\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/to-tickets/SKILL.md)
524
- - Decompose the spec into thin, end-to-end **Tracer-bullet tickets** with explicit \`Blocked by:\` dependencies (saved under \`.scratch/<feature>/issues/<NN>-<slug>.md\` or an issue tracker).
525
- 4. ⚠️ **Phase Boundary (Context Hygiene)**:
526
- - **Clear Context (\`/clear\` or fresh session)** before coding! Because each ticket is self-contained with its own acceptance criteria, resetting the window brings the agent into the **Smart Zone (~150k tokens)** where code generation is sharpest.
527
- 5. **\`/implement\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/implement/SKILL.md)
528
- - Execute tickets sequentially, driven by **\`/tdd\`** (Red ➔ Green ➔ Refactor).
529
- 6. **\`/code-review\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/code-review/SKILL.md)
530
- - Perform independent two-axis review of the diff: **Spec Axis** (did we build what was asked?) and **Standards Axis** (clean code, deep modules, regression safety) prior to committing.
531
-
532
- > 💡 **Matt's Tip:** Steps 1–3 must stay in a single unbroken context window so the grilling, spec, and tickets share continuous reasoning. But once tickets exist, *immediately clear context* before implementing.
533
-
534
- ---
535
-
536
- ## 03. Shaping Flow (Open Questions & Fog of War)
537
-
538
- > **Real-World Situation:**
539
- > - A massive greenfield initiative or high-uncertainty feature with heavy Fog of War.
540
- > - UI/UX or state-machine dilemmas that cannot be resolved in conversation alone.
541
- > - Deep research into official docs or third-party source code needed before committing to a plan.
542
-
543
- ### Key Skills:
544
- 1. **\`/wayfinder\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/wayfinder/SKILL.md)
545
- - Constructs a **Decision Map** for sprawling projects, resolving fog node by node until an actionable path emerges to hand off to \`/to-spec\`.
546
- 2. **\`/prototype\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/prototype/SKILL.md)
547
- - Creates throwaway, minimal prototype code (e.g. single HTML file or standalone script) to provide tactile validation of UI or complex state logic. Commit onto a separate prototype branch and discard.
548
- 3. **\`/research\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/research/SKILL.md)
549
- - Dispatches a background subagent to inspect **Primary Sources** (official documentation, vendor source code) and generates cited summaries for \`/grill-with-docs\`.
550
-
551
- > 💡 **Matt's Tip:** Prototypes are NOT production code! No unit tests, no real database. Their singular purpose is to answer nagging design questions as quickly as possible.
552
-
553
- ---
554
-
555
- ## 04. Upkeep Flow (Code Health & Maintenance)
556
-
557
- > **Real-World Situation:**
558
- > - Complex, intermittent, or hard-to-pinpoint bugs.
559
- > - Modules that feel bloated, shallow, or tightly coupled.
560
- > - Git merge conflicts during branch integration.
561
- > - Incoming raw bug reports and feature requests needing categorization.
562
-
563
- ### Key Skills:
564
- 1. **\`/diagnosing-bugs\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/diagnosing-bugs/SKILL.md)
565
- - Enforces a **Tight Red Loop**: refuse to propose fixes or theorize until an exact, failing reproduction command is captured. Fix the defect and keep the test as a regression lock.
566
- 2. **\`/improve-codebase-architecture\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/improve-codebase-architecture/SKILL.md)
567
- - Analyzes codebase boundaries to identify shallow modules or tangled dependencies, outputting a prioritized refactoring plan.
568
- 3. **\`/resolving-merge-conflicts\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/resolving-merge-conflicts/SKILL.md)
569
- - Resolves conflicts hunk-by-hunk by discovering the underlying **engineering intent** of both branches rather than picking arbitrary lines.
570
- 4. **\`/triage\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/triage/SKILL.md)
571
- - Triages raw external requests and bugs, applying standard labels (\`needs-info\`, \`ready-for-agent\`, \`wontfix\`).
572
- 5. **\`/wizard\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/wizard/SKILL.md)
573
- - Generates interactive CLI scripts guiding developers through manual out-of-band setups (cloud provisioning, OAuth tokens, secrets).
574
-
575
- ---
576
-
577
- ## 05. Productivity Skills (Human Collaboration & Communication)
578
-
579
- > **Real-World Situation:**
580
- > - Exploring an idea before any repository or directory exists.
581
- > - Context window nearing saturation, requiring seamless handover to a fresh session.
582
- > - Missing information is locked inside a teammate's or stakeholder's head.
583
- > - Explaining complex technical concepts cleanly.
584
-
585
- ### Key Skills:
586
- 1. **\`/grill-me\`** — [SKILL.md](file:///${compoundRefPath}/skills/productivity/grill-me/SKILL.md)
587
- - Stateless ideation interview without file writes or repo modifications. Ideal for early brainstorming.
588
- 2. **\`/handoff\`** — [SKILL.md](file:///${compoundRefPath}/skills/productivity/handoff/SKILL.md)
589
- - Exports the current session state and open threads into a standalone Markdown file in the OS temporary directory for instant agent pickup.
590
- 3. **\`/to-questionnaire\`** — [SKILL.md](file:///${compoundRefPath}/skills/productivity/to-questionnaire/SKILL.md)
591
- - Formulates targeted questionnaires to send to external stakeholders when domain knowledge is missing from code.
592
- 4. **\`/wait-what\`** — [SKILL.md](file:///${compoundRefPath}/skills/productivity/wait-what/SKILL.md)
593
- - Instant interruption command when the agent uses jargon or confusing explanations; forces plain-language re-explanation using \`CONTEXT.md\`.
594
- 5. **\`/teach\`** — [SKILL.md](file:///${compoundRefPath}/skills/productivity/teach/SKILL.md)
595
- - Teaches programming or architecture concepts interactively using the workspace as a live chalkboard.
596
- 6. **\`/writing-for-agents\`** — [SKILL.md](file:///${compoundRefPath}/skills/productivity/writing-for-agents/SKILL.md)
597
- - Guidelines for authoring markdown documentation optimized for AI agent readability and retrieval.
598
-
599
- ---
600
-
601
- ## 06. Reference Skills (Architecture Foundations & Mental Models)
602
-
603
- > **Real-World Situation:**
604
- > Establishing foundational engineering standards, domain taxonomies, and testing discipline across the engineering team.
605
-
606
- ### Key Skills:
607
- 1. **\`/codebase-design\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/codebase-design/SKILL.md)
608
- - Principles of **Deep Modules & Clean Seams**: encapsulating complexity behind concise, stable interfaces.
609
- 2. **\`/domain-modeling\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/domain-modeling/SKILL.md)
610
- - Refining domain vocabulary, synchronizing \`CONTEXT.md\`, and documenting immutable decisions in Architecture Decision Records (ADRs).
611
- 3. **\`/grilling\`** — [SKILL.md](file:///${compoundRefPath}/skills/productivity/grilling/SKILL.md)
612
- - Core interview methodology leveraged by \`grill-with-docs\`, \`triage\`, and \`wayfinder\`.
613
- 4. **\`/tdd\`** — [SKILL.md](file:///${compoundRefPath}/skills/engineering/tdd/SKILL.md)
614
- - The ironclad Red ➔ Green ➔ Refactor discipline with deterministic assertions.
615
-
616
- ---
617
-
618
- ## 🗂️ Just-In-Time (JIT) Reference Knowledge Map
619
-
620
- Before running any flow, inspect the exact primary skill document in \`${compoundRefPath}/\` using your file reading tool:
621
-
622
- | Flow Category | Skill Name | Path in \`${compoundRefPath}/\` |
623
- | :--- | :--- | :--- |
624
- | **01. Getting Started** | \`setup-matt-pocock-skills\` | \`skills/engineering/setup-matt-pocock-skills/SKILL.md\` |
625
- | | \`ask-matt\` | \`skills/engineering/ask-matt/SKILL.md\` |
626
- | **02. The Main Flow** | \`grill-with-docs\` | \`skills/engineering/grill-with-docs/SKILL.md\` |
627
- | | \`to-spec\` | \`skills/engineering/to-spec/SKILL.md\` |
628
- | | \`to-tickets\` | \`skills/engineering/to-tickets/SKILL.md\` |
629
- | | \`implement\` | \`skills/engineering/implement/SKILL.md\` |
630
- | | \`code-review\` | \`skills/engineering/code-review/SKILL.md\` |
631
- | **03. Shaping** | \`wayfinder\` | \`skills/engineering/wayfinder/SKILL.md\` |
632
- | | \`prototype\` | \`skills/engineering/prototype/SKILL.md\` |
633
- | | \`research\` | \`skills/engineering/research/SKILL.md\` |
634
- | **04. Upkeep** | \`diagnosing-bugs\` | \`skills/engineering/diagnosing-bugs/SKILL.md\` |
635
- | | \`improve-codebase-architecture\` | \`skills/engineering/improve-codebase-architecture/SKILL.md\` |
636
- | | \`resolving-merge-conflicts\` | \`skills/engineering/resolving-merge-conflicts/SKILL.md\` |
637
- | | \`triage\` | \`skills/engineering/triage/SKILL.md\` |
638
- | | \`wizard\` | \`skills/engineering/wizard/SKILL.md\` |
639
- | **05. Productivity** | \`grill-me\` | \`skills/productivity/grill-me/SKILL.md\` |
640
- | | \`handoff\` | \`skills/productivity/handoff/SKILL.md\` |
641
- | | \`to-questionnaire\` | \`skills/productivity/to-questionnaire/SKILL.md\` |
642
- | | \`wait-what\` | \`skills/productivity/wait-what/SKILL.md\` |
643
- | | \`teach\` | \`skills/productivity/teach/SKILL.md\` |
644
- | | \`writing-for-agents\` | \`skills/productivity/writing-for-agents/SKILL.md\` |
645
- | **06. Reference** | \`codebase-design\` | \`skills/engineering/codebase-design/SKILL.md\` |
646
- | | \`domain-modeling\` | \`skills/engineering/domain-modeling/SKILL.md\` |
647
- | | \`grilling\` | \`skills/productivity/grilling/SKILL.md\` |
648
- | | \`tdd\` | \`skills/engineering/tdd/SKILL.md\` |
649
-
650
- ---
651
-
652
- ## 🕹️ CLI & Command Dispatcher
653
-
654
- Invoke \`${compoundName}\` according to your specific task or question:
655
-
656
- \`\`\`bash
657
- # 01 Getting Started
658
- /${compoundName} setup # Run one-time repo setup in docs/agents/
659
- /${compoundName} ask "Encountering a bug..." # Consult Matt for flow selection
660
-
661
- # 02 The Main Flow (Idea -> Ship)
662
- /${compoundName} grill "Export PDF feature" # Socratic grilling of the requirement
663
- /${compoundName} spec # Establish Seam and generate Living Spec
664
- /${compoundName} tickets # Split spec into tracer-bullet tickets
665
- /${compoundName} run-ticket 01 # TDD implementation of ticket 01
666
- /${compoundName} review # Two-axis review before git commit
667
-
668
- # 03 Shaping
669
- /${compoundName} wayfinder "Massive project" # Resolve high-fog architecture
670
- /${compoundName} prototype "Test UI state" # Fast throwaway tactile validation
671
- /${compoundName} research "Library internals"# Deep-dive reading of official docs
672
-
673
- # 04 Upkeep
674
- /${compoundName} bug "check command failing" # Tight red loop root-cause diagnosis
675
- /${compoundName} architecture # Identify shallow modules for refactoring
676
- /${compoundName} conflict # Semantic merge conflict resolution
677
-
678
- # 05 Productivity & Learning
679
- /${compoundName} learn "Explain Smart Zone" # In-depth conceptual coaching
680
- /${compoundName} handoff "Switching session" # Generate Markdown handoff note
681
- \`\`\`
682
-
683
- ---
684
-
685
- ## 🌐 Artifact & Communication Language
686
-
687
- All user-facing communication, guidance, coaching responses, and stage artifacts MUST default to **Thai (\`th\`)** (per \`devflow/config.json\` and \`AGENTS.md\` directive #5 / \`ai-interaction.md\`), while code snippets, CLI commands, file paths, and technical identifiers remain in English.
688
- `
689
- : `---
690
- name: ${compoundName}
691
- description: "[devflow] Offensive security orchestrator & bug hunting guide. Indexes 83 vulnerability classes, 5-phase methodology (Think, Hunt, Perimeter, Ship), 681 disclosed HackerOne patterns, and JIT reference guides in ${compoundRefPath}/. Use when running /bughunter, performing security reviews, verifying auth/injection risks in /check or /audit, or testing API endpoints for vulnerabilities."
692
- argument-hint: "[{target, vuln-class, or topic}]"
693
- ---
694
-
695
- # 🛡️ ${compoundName} - Offensive Security & Vulnerability Assessment Orchestrator
696
-
697
- $ARGUMENTS
698
-
699
- \`${compoundName}\` is the master security testing orchestrator in Nexus-DevFlow, bringing the complete power of **Claude-BugHunter** into your development lifecycle with **Zero Token Bloat**.
700
-
701
- ---
702
-
703
- ## ⚠️ Pre-Flight Check (Knowledge Base Availability)
704
-
705
- Before executing any BugHunter analysis or security test:
706
- 1. **Check if \`${compoundRefPath}/\` exists in this project using your file inspection tool**.
707
- 2. **If \`${compoundRefPath}/\` is MISSING / NOT INSTALLED**:
708
- - **DO NOT hallucinate payloads or fake security reports**.
709
- - Inform the user in their configured communication language (per \`devflow/config.json\` and \`AGENTS.md\`):
710
- - State clearly that the BugHunter knowledge base (83 Vulnerability Classes, Payloads & 681 Disclosed Reports) is not yet downloaded in this project.
711
- - Provide the exact installation command:
712
- \`\`\`bash
713
- npx @jakkrichm/create-nexus-devflow skill add ${compoundName}
714
- \`\`\`
715
- - Offer to run the installation command on their behalf.
716
- - Stop and wait for installation before proceeding.
717
- 3. **If \`${compoundRefPath}/\` is PRESENT**:
718
- - Proceed with the JIT Knowledge Map and 5-phase testing methodology below.
719
-
720
- ---
721
-
722
- ### 📦 Full Upstream Arsenal in \`${compoundRefPath}/\`:
723
- - **83 Full Skills** (\`${compoundRefPath}/skills/<skill-name>/SKILL.md\`): Detailed detection patterns, bypass tables, and payloads for all 83 classes.
724
- - **15 Slash Commands** (\`${compoundRefPath}/commands/<command>.md\`): \`hunt\`, \`recon\`, \`triage\`, \`validate\`, \`chain\`, \`report\`, \`scope\`, \`token-scan\`, \`surface\`, \`autopilot\`, etc.
725
- - **681 Disclosed HackerOne Reports** (\`${compoundRefPath}/disclosed-reports/<class>.md\`): Real-world vulnerability citations across 24 core classes.
726
- - **Engagement Scaffolding** (\`${compoundRefPath}/ENGAGEMENTS.md\`): Comprehensive directory and methodology scaffolding for security assessments.
727
-
728
- ---
729
-
730
- ## 🧭 The 4-Layer Architecture & 5-Phase Methodology
731
-
732
- \`\`\`text
733
- ┌────────────────────────────────────────────────────────────────────────┐
734
- │ 1. THINK │ bb-methodology, redteam-mindset, 5-phase workflow │
735
- ├───────────────┼────────────────────────────────────────────────────────┤
736
- │ 2. HUNT │ 58 web app vulnerability classes (IDOR, SSRF, SQLi) │
737
- ├───────────────┼────────────────────────────────────────────────────────┤
738
- │ 3. PERIMETER │ M365/Entra, Okta, vCenter, Cloud IAM, SSL-VPN │
739
- ├───────────────┼────────────────────────────────────────────────────────┤
740
- │ 4. SHIP │ 7-Question Gate, VRT-aware triage, H1/Bugcrowd reports │
741
- └────────────────────────────────────────────────────────────────────────┘
742
- \`\`\`
743
-
744
- ### The 5-Phase Workflow:
745
- 1. **Recon & Scope**: Fingerprint tech stack, enumerate subdomains/endpoints, define in-scope vs. out-of-scope boundaries (\`skills/web2-recon/\`, \`skills/recon-scope-triage/\`).
746
- 2. **Map & Surface Ranking**: Identify high-value targets (Auth, Payment, GraphQL mutations, File uploads, Webhook receivers) (\`commands/surface.md\`).
747
- 3. **Hunt & Test**: Apply vulnerability-specific bypass tables, edge-case payloads, and condition variations (\`skills/hunt-*/SKILL.md\`).
748
- 4. **Validate**: Apply the **7-Question Gate** (Impact, Pre-conditions, Repro steps, Root cause, Severity score) (\`skills/triage-validation/\`).
749
- 5. **Report / Remediate**: Produce actionable vulnerability proof, remediation advice, or bug bounty reports (\`commands/report.md\`, \`skills/report-writing/\`).
750
-
751
- ---
752
-
753
- ## 🗂️ Just-in-Time (JIT) Reference Knowledge Map
754
-
755
- Before analyzing or probing any security concern, **ALWAYS read the relevant reference document in \`${compoundRefPath}/\` using your file reading tool (\`view_file\` / \`grep_search\`)**:
756
-
757
- | Target Category | Specific Skill Path in \`${compoundRefPath}/\` | Disclosed Reports Path |
758
- | :--- | :--- | :--- |
759
- | **Index & Overview** | \`${compoundRefPath}/INDEX.md\` | - |
760
- | **IDOR / BOLA** | \`skills/hunt-idor/SKILL.md\` | \`disclosed-reports/hunt-idor.md\` |
761
- | **OAuth 2.0 / SSO** | \`skills/hunt-oauth/SKILL.md\` | \`disclosed-reports/hunt-oauth.md\` |
762
- | **JWT Flaws & Crypto** | \`skills/hunt-jwt-crypto/SKILL.md\` | \`disclosed-reports/hunt-jwt-crypto.md\` |
763
- | **SSRF (Cloud IMDS)** | \`skills/hunt-ssrf/SKILL.md\` | \`disclosed-reports/hunt-ssrf.md\` |
764
- | **SQL & NoSQL Injection** | \`skills/hunt-sqli/SKILL.md\`, \`skills/hunt-nosqli/SKILL.md\` | \`disclosed-reports/hunt-sqli.md\` |
765
- | **XSS & DOM Injection** | \`skills/hunt-xss/SKILL.md\`, \`skills/hunt-dom/SKILL.md\` | \`disclosed-reports/hunt-xss.md\` |
766
- | **GraphQL & APIs** | \`skills/hunt-graphql/SKILL.md\`, \`skills/hunt-fintech-graphql/\` | \`disclosed-reports/hunt-graphql.md\` |
767
- | **Next.js / Node.js** | \`skills/hunt-nextjs/SKILL.md\`, \`skills/hunt-nodejs/SKILL.md\` | - |
768
- | **Cloud IAM & Perimeter** | \`skills/hunt-cloud-misconfig/\`, \`skills/m365-entra-attack/\` | \`disclosed-reports/hunt-cloud-misconfig.md\` |
769
- | **CI/CD & Kubernetes** | \`skills/hunt-cicd/SKILL.md\`, \`skills/hunt-k8s/SKILL.md\` | - |
770
- | **LLM & AI Security** | \`skills/hunt-llm-ai/SKILL.md\`, \`skills/hunt-rag-vector/SKILL.md\` | - |
771
-
772
- ---
773
-
774
- ## 🔗 Integration with Nexus-DevFlow Core Lifecycle
775
-
776
- 1. **During \`/check\` (Security & QA Verification)**:
777
- - When verifying a feature dealing with Auth, Multi-tenancy, or Data Exports, run a BugHunter self-assessment:
778
- *Read \`${compoundRefPath}/skills/hunt-idor/SKILL.md\` to test for IDOR and token tampering vulnerabilities on the affected endpoint.*
779
- 2. **During \`/audit\` (Code Audit)**:
780
- - Review code against Fowler smells AND offensive attack vectors simultaneously, logging findings into \`devflow/context/{xxx-slug}/findings.md\`.
781
- 3. **During \`/debug\` (Security Incident Investigation)**:
782
- - Trace vulnerability root causes using the 681 disclosed report patterns in \`disclosed-reports/\`.
783
-
784
- ---
785
-
786
- ## 🌐 Artifact & Communication Language
787
-
788
- All generated reports, findings recorded in \`devflow/context/{xxx-slug}/findings.md\`, and user communication MUST follow the project's central configuration in \`devflow/config.json\` (and \`AGENTS.md\` directive #5 / \`ai-interaction.md\`, defaulting to Thai \`th\`), while code snippets, CVE IDs, HTTP payloads, and technical identifiers remain in English.
789
-
790
- ---
791
-
792
- ## 🔄 Updating Knowledge Base
793
-
794
- To update all 83 skills, 15 commands, and report patterns to the latest upstream version:
795
- \`\`\`bash
796
- npx @jakkrichm/create-nexus-devflow skill update ${compoundName}
797
- \`\`\`
798
- `;
799
- const agentTarget = path.join(projectRoot, ".agents", "skills", compoundName, "SKILL.md");
800
- const claudeTarget = path.join(projectRoot, ".claude", "skills", compoundName, "SKILL.md");
801
- await fs.mkdir(path.dirname(agentTarget), { recursive: true });
802
- await fs.mkdir(path.dirname(claudeTarget), { recursive: true });
803
- if (!fsSync.existsSync(agentTarget) || options?.force) {
804
- await fs.writeFile(agentTarget, masterContent, "utf8");
805
- }
806
- if (!fsSync.existsSync(claudeTarget) || options?.force) {
807
- await fs.writeFile(claudeTarget, masterContent, "utf8");
808
- }
809
- // Update manifest
810
- const manifest = (await readDevflowManifest(projectRoot)) || {
811
- schemaVersion: 1,
812
- name: "nexus-devflow",
813
- package: "@jakkrichm/create-nexus-devflow",
814
- version: "2.9.5"
815
- };
816
- const existingThirdParty = Array.isArray(manifest.thirdPartySkills)
817
- ? manifest.thirdPartySkills
818
- : [];
819
- const filtered = existingThirdParty.filter((s) => s.name !== compoundName);
820
- filtered.push({
821
- name: compoundName,
822
- source: recordedSource,
823
- version: compoundVer,
824
- description: compoundDesc,
825
- installedAt: new Date().toISOString(),
826
- type: "compound-knowledge",
827
- referencePath: compoundRefPath
828
- });
829
- manifest.thirdPartySkills = filtered;
830
- await writeDevflowManifest(projectRoot, manifest);
831
- return {
832
- name: compoundName,
833
- category: "third-party",
834
- description: compoundDesc,
835
- version: compoundVer,
836
- source: recordedSource,
837
- adapters: [".agents", ".claude"],
838
- synced: true,
839
- path: `.agents/skills/${compoundName}`
840
- };
841
- }
842
- if (options?.all) {
843
- const discovered = await discoverSkillsInDirectory(sourceDirectory);
844
- if (discovered.length === 0) {
845
- throw new Error(`Could not find any valid skill with SKILL.md in source: ${source}`);
846
- }
847
- const installedList = [];
848
- const manifest = (await readDevflowManifest(projectRoot)) || {
849
- schemaVersion: 1,
850
- name: "nexus-devflow",
851
- package: "@jakkrichm/create-nexus-devflow",
852
- version: "2.9.3"
853
- };
854
- const existingThirdParty = Array.isArray(manifest.thirdPartySkills)
855
- ? manifest.thirdPartySkills
856
- : [];
857
- let updatedThirdParty = [...existingThirdParty];
858
- for (const skill of discovered) {
859
- const skillName = skill.skillName;
860
- if (!SKILL_NAME_PATTERN.test(skillName)) {
861
- continue; // skip invalid names in batch mode
862
- }
863
- if (coreNameSet.has(skillName) && !options?.force) {
864
- continue; // skip core collisions in batch mode
865
- }
866
- const targetAgentsSkillDir = path.join(projectRoot, ".agents", "skills", skillName);
867
- const targetClaudeSkillDir = path.join(projectRoot, ".claude", "skills", skillName);
868
- await fs.rm(targetAgentsSkillDir, { recursive: true, force: true });
869
- await fs.rm(targetClaudeSkillDir, { recursive: true, force: true });
870
- await fs.mkdir(path.dirname(targetAgentsSkillDir), { recursive: true });
871
- await fs.mkdir(path.dirname(targetClaudeSkillDir), { recursive: true });
872
- await fs.cp(skill.sourceSkillPath, targetAgentsSkillDir, { recursive: true });
873
- await fs.cp(skill.sourceSkillPath, targetClaudeSkillDir, { recursive: true });
874
- updatedThirdParty = updatedThirdParty.filter((s) => s.name !== skillName);
875
- updatedThirdParty.push({
876
- name: skillName,
877
- source: recordedSource,
878
- version: skill.meta.version || "1.0.0",
879
- description: skill.meta.description || "",
880
- installedAt: new Date().toISOString(),
881
- type: recordedType
882
- });
883
- installedList.push({
884
- name: skillName,
885
- category: "third-party",
886
- description: skill.meta.description || "",
887
- version: skill.meta.version || "1.0.0",
888
- source: recordedSource,
889
- adapters: [".agents", ".claude"],
890
- synced: true,
891
- path: `.agents/skills/${skillName}`
892
- });
893
- }
894
- manifest.thirdPartySkills = updatedThirdParty;
895
- await writeDevflowManifest(projectRoot, manifest);
896
- return installedList;
897
- }
898
- const { sourceSkillPath, skillName, meta } = await findSkillSourceDirectory(sourceDirectory, options?.name);
899
- if (!SKILL_NAME_PATTERN.test(skillName)) {
900
- throw new Error(`Invalid skill name: "${skillName}". Must use kebab-case (e.g. "diagram-design").`);
901
- }
902
- if (coreNameSet.has(skillName) && !options?.force) {
903
- throw new Error(`Cannot install skill with name "${skillName}" as it conflicts with a Core DevFlow Skill.`);
904
- }
905
- const targetAgentsSkillDir = path.join(projectRoot, ".agents", "skills", skillName);
906
- const targetClaudeSkillDir = path.join(projectRoot, ".claude", "skills", skillName);
907
- await fs.rm(targetAgentsSkillDir, { recursive: true, force: true });
908
- await fs.rm(targetClaudeSkillDir, { recursive: true, force: true });
909
- await fs.mkdir(path.dirname(targetAgentsSkillDir), { recursive: true });
910
- await fs.mkdir(path.dirname(targetClaudeSkillDir), { recursive: true });
911
- // Copy verbatim to .agents/skills/<name>
912
- await fs.cp(sourceSkillPath, targetAgentsSkillDir, { recursive: true });
913
- // Copy verbatim to .claude/skills/<name>
914
- await fs.cp(sourceSkillPath, targetClaudeSkillDir, { recursive: true });
915
- // Update .nexus/nexus-devflow.json
916
- const manifest = (await readDevflowManifest(projectRoot)) || {
917
- schemaVersion: 1,
918
- name: "nexus-devflow",
919
- package: "@jakkrichm/create-nexus-devflow",
920
- version: "2.9.3"
921
- };
922
- const existingThirdParty = Array.isArray(manifest.thirdPartySkills)
923
- ? manifest.thirdPartySkills
924
- : [];
925
- const existingRecord = existingThirdParty.find((s) => s.name === skillName);
926
- const filtered = existingThirdParty.filter((s) => s.name !== skillName);
927
- filtered.push({
928
- name: skillName,
929
- source: recordedSource,
930
- version: meta.version || existingRecord?.version || "1.0.0",
931
- description: meta.description || existingRecord?.description || "",
932
- installedAt: new Date().toISOString(),
933
- type: existingRecord?.type || recordedType,
934
- referencePath: existingRecord?.referencePath
935
- });
936
- manifest.thirdPartySkills = filtered;
937
- await writeDevflowManifest(projectRoot, manifest);
938
- return {
939
- name: skillName,
940
- category: "third-party",
941
- description: meta.description || existingRecord?.description || "",
942
- version: meta.version || existingRecord?.version || "1.0.0",
943
- source: recordedSource,
944
- adapters: [".agents", ".claude"],
945
- synced: true,
946
- path: `.agents/skills/${skillName}`
947
- };
948
- }
949
- finally {
950
- if (tempCloneDir) {
951
- try {
952
- await fs.rm(tempCloneDir, { recursive: true, force: true });
953
- }
954
- catch {
955
- // ignore cleanup error
956
- }
957
- }
16
+ const result = await getEngine(projectRoot).install(source, options);
17
+ if (result.details.length === 1 && !options?.all) {
18
+ return result.details[0];
958
19
  }
20
+ return result.details;
959
21
  }
960
22
  export async function removeThirdPartySkill(projectRoot, name) {
961
- let coreNameSet = new Set();
962
- try {
963
- const inventory = await loadCoreSkillInventory(path.join(projectRoot, AGENT_MANIFEST_PATH));
964
- coreNameSet = inventory.nameSet;
965
- }
966
- catch {
967
- // ignore
968
- }
969
- if (coreNameSet.has(name)) {
970
- throw new Error(`Cannot remove Core Skill: "${name}". Core skills are managed by Nexus-DevFlow.`);
971
- }
972
- const targetAgentsSkillDir = path.join(projectRoot, ".agents", "skills", name);
973
- const targetClaudeSkillDir = path.join(projectRoot, ".claude", "skills", name);
974
- let removedAny = false;
975
- if (fsSync.existsSync(targetAgentsSkillDir)) {
976
- await fs.rm(targetAgentsSkillDir, { recursive: true, force: true });
977
- removedAny = true;
978
- }
979
- if (fsSync.existsSync(targetClaudeSkillDir)) {
980
- await fs.rm(targetClaudeSkillDir, { recursive: true, force: true });
981
- removedAny = true;
982
- }
983
- const manifest = await readDevflowManifest(projectRoot);
984
- if (manifest && Array.isArray(manifest.thirdPartySkills)) {
985
- const prevList = manifest.thirdPartySkills;
986
- const nextList = prevList.filter((s) => s.name !== name);
987
- if (nextList.length !== prevList.length) {
988
- manifest.thirdPartySkills = nextList;
989
- await writeDevflowManifest(projectRoot, manifest);
990
- removedAny = true;
991
- }
992
- }
993
- return removedAny;
23
+ const res = await getEngine(projectRoot).remove(name);
24
+ return res.removed;
994
25
  }
995
26
  export async function syncSkills(projectRoot) {
996
- const agentsDir = path.join(projectRoot, ".agents", "skills");
997
- const claudeDir = path.join(projectRoot, ".claude", "skills");
998
- if (!fsSync.existsSync(agentsDir)) {
999
- return { syncedCount: 0, skills: [] };
1000
- }
1001
- await fs.rm(claudeDir, { recursive: true, force: true });
1002
- await fs.mkdir(claudeDir, { recursive: true });
1003
- const entries = await fs.readdir(agentsDir, { withFileTypes: true });
1004
- const syncedSkills = [];
1005
- for (const entry of entries) {
1006
- if (entry.isDirectory()) {
1007
- const src = path.join(agentsDir, entry.name);
1008
- const dst = path.join(claudeDir, entry.name);
1009
- await fs.cp(src, dst, { recursive: true });
1010
- syncedSkills.push(entry.name);
1011
- }
1012
- }
1013
- return {
1014
- syncedCount: syncedSkills.length,
1015
- skills: syncedSkills
1016
- };
27
+ return getEngine(projectRoot).sync();
1017
28
  }
1018
29
  export async function updateThirdPartySkills(projectRoot, targetSkillName, options) {
1019
- const manifest = await readDevflowManifest(projectRoot);
1020
- const existingThirdParty = Array.isArray(manifest?.thirdPartySkills)
1021
- ? manifest.thirdPartySkills
1022
- : [];
1023
- if (existingThirdParty.length === 0) {
1024
- return { updatedSkills: [], failedSkills: [], totalUpdated: 0 };
1025
- }
1026
- let skillsToUpdate = existingThirdParty;
1027
- if (targetSkillName && targetSkillName !== "--all") {
1028
- skillsToUpdate = existingThirdParty.filter((s) => s.name === targetSkillName);
1029
- if (skillsToUpdate.length === 0) {
1030
- throw new Error(`Skill "${targetSkillName}" is not installed as a third-party skill.`);
1031
- }
1032
- }
1033
- // Group by source to avoid duplicate cloning
1034
- const sourceToSkillsMap = new Map();
1035
- for (const skill of skillsToUpdate) {
1036
- const list = sourceToSkillsMap.get(skill.source) || [];
1037
- list.push(skill);
1038
- sourceToSkillsMap.set(skill.source, list);
1039
- }
1040
- const updatedSkills = [];
1041
- const failedSkills = [];
1042
- for (const [source, skills] of sourceToSkillsMap) {
1043
- const isGit = /^https?:\/\/|^git@|^ssh:\/\/|\.git$/.test(source);
1044
- let tempCloneDir = null;
1045
- try {
1046
- let sourceDir = source;
1047
- if (isGit) {
1048
- tempCloneDir = await fs.mkdtemp(path.join(os.tmpdir(), "nexus-skill-update-"));
1049
- await execFileAsync("git", ["clone", "--depth", "1", source, tempCloneDir]);
1050
- sourceDir = tempCloneDir;
1051
- }
1052
- for (const skill of skills) {
1053
- try {
1054
- if (skill.type === "compound-knowledge") {
1055
- let directSkillFound = false;
1056
- try {
1057
- const detail = (await installThirdPartySkill(projectRoot, sourceDir, {
1058
- name: skill.name,
1059
- force: true,
1060
- overrideSource: isGit ? source : undefined
1061
- }));
1062
- updatedSkills.push(detail);
1063
- directSkillFound = true;
1064
- }
1065
- catch {
1066
- directSkillFound = false;
1067
- }
1068
- if (!directSkillFound) {
1069
- const refRelPath = skill.referencePath || path.join("devflow", ".vendor", skill.name);
1070
- const targetRefDir = path.join(projectRoot, refRelPath);
1071
- await fs.mkdir(targetRefDir, { recursive: true });
1072
- // 1. Sync source skills directory to reference/skills
1073
- const srcSkills = path.join(sourceDir, "skills");
1074
- if (fsSync.existsSync(srcSkills)) {
1075
- await fs.cp(srcSkills, path.join(targetRefDir, "skills"), { recursive: true });
1076
- }
1077
- // 2. Sync source commands directory to reference/commands
1078
- const srcCommands = path.join(sourceDir, "commands");
1079
- if (fsSync.existsSync(srcCommands)) {
1080
- await fs.cp(srcCommands, path.join(targetRefDir, "commands"), { recursive: true });
1081
- }
1082
- // 3. Sync source disclosed-reports directory
1083
- const srcReports = path.join(sourceDir, "docs", "disclosed-reports");
1084
- if (fsSync.existsSync(srcReports)) {
1085
- await fs.cp(srcReports, path.join(targetRefDir, "disclosed-reports"), { recursive: true });
1086
- }
1087
- // 4. Sync source docs directory
1088
- const srcDocs = path.join(sourceDir, "docs");
1089
- if (fsSync.existsSync(srcDocs)) {
1090
- await fs.cp(srcDocs, path.join(targetRefDir, "docs"), { recursive: true });
1091
- }
1092
- // 5. Copy notable guide files
1093
- for (const guideFile of ["ENGAGEMENTS.md", "USAGE.md", "README.md", "INSTALL.md"]) {
1094
- const srcFile = path.join(sourceDir, guideFile);
1095
- if (fsSync.existsSync(srcFile)) {
1096
- await fs.copyFile(srcFile, path.join(targetRefDir, guideFile));
1097
- }
1098
- }
1099
- let newVersion = skill.version || "1.0.0";
1100
- try {
1101
- const pkgPath = path.join(sourceDir, "package.json");
1102
- if (fsSync.existsSync(pkgPath)) {
1103
- const pkgRaw = await fs.readFile(pkgPath, "utf8");
1104
- const pkg = JSON.parse(pkgRaw);
1105
- if (pkg.version)
1106
- newVersion = pkg.version;
1107
- }
1108
- }
1109
- catch {
1110
- // ignore
1111
- }
1112
- // Update manifest
1113
- const currentManifest = (await readDevflowManifest(projectRoot)) || {};
1114
- const existingList = Array.isArray(currentManifest.thirdPartySkills)
1115
- ? currentManifest.thirdPartySkills
1116
- : [];
1117
- const updatedList = existingList.map((s) => {
1118
- if (s.name === skill.name) {
1119
- return {
1120
- ...s,
1121
- version: newVersion,
1122
- installedAt: new Date().toISOString(),
1123
- type: "compound-knowledge",
1124
- referencePath: refRelPath
1125
- };
1126
- }
1127
- return s;
1128
- });
1129
- currentManifest.thirdPartySkills = updatedList;
1130
- await writeDevflowManifest(projectRoot, currentManifest);
1131
- updatedSkills.push({
1132
- name: skill.name,
1133
- category: "third-party",
1134
- description: skill.description || "Compound Knowledge Skill",
1135
- version: newVersion,
1136
- source: skill.source,
1137
- adapters: [".agents", ".claude"],
1138
- synced: true,
1139
- path: `.agents/skills/${skill.name}`
1140
- });
1141
- }
1142
- }
1143
- else {
1144
- const detail = (await installThirdPartySkill(projectRoot, sourceDir, {
1145
- name: skill.name,
1146
- force: true,
1147
- overrideSource: isGit ? source : undefined
1148
- }));
1149
- updatedSkills.push(detail);
1150
- }
1151
- }
1152
- catch (err) {
1153
- failedSkills.push({
1154
- name: skill.name,
1155
- reason: err instanceof Error ? err.message : String(err)
1156
- });
1157
- }
1158
- }
1159
- }
1160
- catch (err) {
1161
- for (const skill of skills) {
1162
- failedSkills.push({
1163
- name: skill.name,
1164
- reason: err instanceof Error ? err.message : String(err)
1165
- });
1166
- }
1167
- }
1168
- finally {
1169
- if (tempCloneDir) {
1170
- try {
1171
- await fs.rm(tempCloneDir, { recursive: true, force: true });
1172
- }
1173
- catch {
1174
- // ignore
1175
- }
1176
- }
1177
- }
1178
- }
1179
- return {
1180
- updatedSkills,
1181
- failedSkills,
1182
- totalUpdated: updatedSkills.length
1183
- };
30
+ return getEngine(projectRoot).update(targetSkillName, options);
1184
31
  }
1185
32
  export async function installRecommendedSkills(projectRoot, options) {
1186
33
  const presets = options?.presets || RECOMMENDED_THIRD_PARTY_SKILLS;