ai-workflow-kit
Advanced tools
+212
-32
@@ -6,8 +6,12 @@ #!/usr/bin/env node | ||
| * Usage: | ||
| * npx ai-workflow-kit → interactive selection menu | ||
| * npx ai-workflow-kit → interactive (asks IDE, scope, items) | ||
| * npx ai-workflow-kit --yes → install everything without prompting | ||
| * npx ai-workflow-kit --local → install into .claude/ of the current project | ||
| * npx ai-workflow-kit --local → install into .claude/ of current project | ||
| * npx ai-workflow-kit --global → install into ~/.claude/ (default) | ||
| * npx ai-workflow-kit --skills → all skills and agents only | ||
| * npx ai-workflow-kit --hooks → all hooks only | ||
| * npx ai-workflow-kit --claude → skip IDE prompt, use Claude Code | ||
| * npx ai-workflow-kit --cursor → skip IDE prompt, use Cursor | ||
| * npx ai-workflow-kit --copilot → skip IDE prompt, use GitHub Copilot | ||
| * npx ai-workflow-kit --antigravity → skip IDE prompt, use Antigravity | ||
| * npx ai-workflow-kit --skills → skills and agents only (Claude Code) | ||
| * npx ai-workflow-kit --hooks → hooks only (Claude Code) | ||
| * npx ai-workflow-kit --uninstall → remove what was installed | ||
@@ -41,10 +45,14 @@ * npx ai-workflow-kit --list → show what would be installed | ||
| // ─── Args ──────────────────────────────────────────────────────────────────── | ||
| const args = process.argv.slice(2) | ||
| const SKILLS_ONLY = args.includes('--skills') | ||
| const HOOKS_ONLY = args.includes('--hooks') | ||
| const YES = args.includes('--yes') || args.includes('-y') | ||
| const UNINSTALL = args.includes('--uninstall') | ||
| const LIST = args.includes('--list') | ||
| const FORCE_LOCAL = args.includes('--local') | ||
| const FORCE_GLOBAL = args.includes('--global') | ||
| const args = process.argv.slice(2) | ||
| const SKILLS_ONLY = args.includes('--skills') | ||
| const HOOKS_ONLY = args.includes('--hooks') | ||
| const YES = args.includes('--yes') || args.includes('-y') | ||
| const UNINSTALL = args.includes('--uninstall') | ||
| const LIST = args.includes('--list') | ||
| const FORCE_LOCAL = args.includes('--local') | ||
| const FORCE_GLOBAL = args.includes('--global') | ||
| const FORCE_CLAUDE = args.includes('--claude') | ||
| const FORCE_CURSOR = args.includes('--cursor') | ||
| const FORCE_COPILOT = args.includes('--copilot') | ||
| const FORCE_AG = args.includes('--antigravity') | ||
@@ -70,3 +78,2 @@ // ─── Paths ─────────────────────────────────────────────────────────────────── | ||
| // { src, name, isDir } — supports flat <name>.md and <name>/SKILL.md dirs | ||
| function listSkills(dir) { | ||
@@ -87,4 +94,2 @@ if (!fs.existsSync(dir)) return [] | ||
| // { src, name } — supports flat <name>.md and <name>/AGENT.md dirs | ||
| // Always installed as flat files to ~/.claude/agents/<name>.md | ||
| function listAgents(dir) { | ||
@@ -141,4 +146,35 @@ if (!fs.existsSync(dir)) return [] | ||
| // ─── Selection — step 1: categories ───────────────────────────────────────── | ||
| // ─── IDE Selection ─────────────────────────────────────────────────────────── | ||
| const IDES = [ | ||
| { key: 'claude', label: 'Claude Code', hint: '~/.claude/' }, | ||
| { key: 'cursor', label: 'Cursor', hint: '.cursorrules' }, | ||
| { key: 'copilot', label: 'GitHub Copilot', hint: '.github/copilot-instructions.md' }, | ||
| { key: 'antigravity', label: 'Antigravity', hint: 'GEMINI.md + skills' }, | ||
| ] | ||
| async function selectIDE() { | ||
| if (FORCE_CLAUDE) return 'claude' | ||
| if (FORCE_CURSOR) return 'cursor' | ||
| if (FORCE_COPILOT) return 'copilot' | ||
| if (FORCE_AG) return 'antigravity' | ||
| if (YES || SKILLS_ONLY || HOOKS_ONLY || UNINSTALL) return 'claude' | ||
| console.log(` ${c.bold}Which IDE are you using?${c.reset}\n`) | ||
| IDES.forEach((ide, i) => { | ||
| const n = String(i + 1).padStart(2) | ||
| console.log(` ${c.cyan}${n}${c.reset} ${ide.label.padEnd(20)} ${c.dim}${ide.hint}${c.reset}`) | ||
| }) | ||
| console.log() | ||
| const input = await prompt(` Enter number ${c.dim}[1-${IDES.length}]${c.reset}: `) | ||
| const n = parseInt(input, 10) | ||
| if (n >= 1 && n <= IDES.length) return IDES[n - 1].key | ||
| warn('Invalid selection, defaulting to Claude Code.') | ||
| return 'claude' | ||
| } | ||
| // ─── Selection — categories ────────────────────────────────────────────────── | ||
| async function selectCategories(allSkills, allAgents, allHooks) { | ||
@@ -172,3 +208,3 @@ const skillNames = allSkills.map(s => s.name).join(', ') | ||
| // ─── Selection — step 2: items within a category ──────────────────────────── | ||
| // ─── Selection — items ─────────────────────────────────────────────────────── | ||
@@ -233,2 +269,11 @@ async function selectItemsInCategory(items, getName) { | ||
| // ─── Antigravity — item selection ──────────────────────────────────────────── | ||
| async function selectAntigravitySkills(allSkills) { | ||
| console.log(`\n${c.bold} Which skills would you like to install?${c.reset}\n`) | ||
| console.log(` ${c.dim}Enter numbers separated by spaces, or Enter for all.${c.reset}`) | ||
| return selectItemsInCategory(allSkills, s => s.name) | ||
| } | ||
| // ─── Header ────────────────────────────────────────────────────────────────── | ||
@@ -242,14 +287,26 @@ console.log() | ||
| if (LIST) { | ||
| const skills = listSkills(path.join(REPO_ROOT, 'skills')) | ||
| const agents = listAgents(path.join(REPO_ROOT, 'agents')) | ||
| const hooks = listFiles(path.join(REPO_ROOT, 'hooks'), '.sh') | ||
| const skills = listSkills(path.join(REPO_ROOT, 'skills')) | ||
| const agents = listAgents(path.join(REPO_ROOT, 'agents')) | ||
| const hooks = listFiles(path.join(REPO_ROOT, 'hooks'), '.sh') | ||
| const agSkills = listSkills(path.join(REPO_ROOT, 'antigravity-skills')) | ||
| console.log(`${c.bold}Skills (${skills.length})${c.reset}`) | ||
| console.log(`${c.bold}Claude Code${c.reset}`) | ||
| console.log(` Skills (${skills.length}):`) | ||
| skills.forEach(s => dim(`/${s.name}`)) | ||
| console.log(`\n${c.bold}Agents (${agents.length})${c.reset}`) | ||
| console.log(` Agents (${agents.length}):`) | ||
| agents.forEach(a => dim(`/${a.name}`)) | ||
| console.log(` Hooks (${hooks.length}):`) | ||
| hooks.forEach(f => dim(path.basename(f))) | ||
| console.log(`\n${c.bold}Hooks (${hooks.length})${c.reset}`) | ||
| hooks.forEach(f => dim(path.basename(f))) | ||
| console.log(`\n${c.bold}Cursor${c.reset}`) | ||
| dim('.cursorrules') | ||
| console.log(`\n${c.bold}GitHub Copilot${c.reset}`) | ||
| dim('.github/copilot-instructions.md') | ||
| console.log(`\n${c.bold}Antigravity${c.reset}`) | ||
| console.log(` Skills (${agSkills.length}):`) | ||
| agSkills.forEach(s => dim(`@${s.name}`)) | ||
| dim('GEMINI.md') | ||
| console.log() | ||
@@ -259,4 +316,128 @@ process.exit(0) | ||
| // ─── Resolve scope (local vs global) ───────────────────────────────────────── | ||
| // ─── IDE Selection ──────────────────────────────────────────────────────────── | ||
| const ide = await selectIDE() | ||
| console.log() | ||
| // ─── Cursor ────────────────────────────────────────────────────────────────── | ||
| if (ide === 'cursor') { | ||
| const src = path.join(REPO_ROOT, '.cursorrules') | ||
| const dst = path.join(process.cwd(), '.cursorrules') | ||
| if (!fs.existsSync(src)) { | ||
| warn('.cursorrules file not found in the kit.') | ||
| process.exit(1) | ||
| } | ||
| if (fs.existsSync(dst) && !YES) { | ||
| const overwrite = await ask('.cursorrules already exists in this project. Overwrite?') | ||
| if (!overwrite) { info('Skipped.'); process.exit(0) } | ||
| } | ||
| copyFile(src, dst) | ||
| console.log() | ||
| console.log(`${c.bold} ─────────────────────────────${c.reset}`) | ||
| console.log(`${c.bold}${c.green} Installation complete${c.reset}`) | ||
| console.log(`${c.bold} ─────────────────────────────${c.reset}`) | ||
| console.log() | ||
| ok('.cursorrules → ' + dst) | ||
| console.log() | ||
| process.exit(0) | ||
| } | ||
| // ─── GitHub Copilot ─────────────────────────────────────────────────────────── | ||
| if (ide === 'copilot') { | ||
| const src = path.join(REPO_ROOT, '.github', 'copilot-instructions.md') | ||
| const dst = path.join(process.cwd(), '.github', 'copilot-instructions.md') | ||
| if (!fs.existsSync(src)) { | ||
| warn('copilot-instructions.md not found in the kit.') | ||
| process.exit(1) | ||
| } | ||
| if (fs.existsSync(dst) && !YES) { | ||
| const overwrite = await ask('copilot-instructions.md already exists. Overwrite?') | ||
| if (!overwrite) { info('Skipped.'); process.exit(0) } | ||
| } | ||
| copyFile(src, dst) | ||
| console.log() | ||
| console.log(`${c.bold} ─────────────────────────────${c.reset}`) | ||
| console.log(`${c.bold}${c.green} Installation complete${c.reset}`) | ||
| console.log(`${c.bold} ─────────────────────────────${c.reset}`) | ||
| console.log() | ||
| ok('.github/copilot-instructions.md → ' + dst) | ||
| console.log() | ||
| process.exit(0) | ||
| } | ||
| // ─── Antigravity ───────────────────────────────────────────────────────────── | ||
| if (ide === 'antigravity') { | ||
| const allAgSkills = listSkills(path.join(REPO_ROOT, 'antigravity-skills')) | ||
| const geminiSrc = path.join(REPO_ROOT, 'GEMINI.md') | ||
| const agentsMdSrc = path.join(REPO_ROOT, 'AGENTS.md') | ||
| let selectedSkills = allAgSkills | ||
| if (!YES) { | ||
| selectedSkills = await selectAntigravitySkills(allAgSkills) | ||
| if (selectedSkills.length === 0) { | ||
| info('Nothing selected. Exiting.') | ||
| console.log() | ||
| process.exit(0) | ||
| } | ||
| } | ||
| const agDst = path.join(process.cwd(), 'antigravity-skills') | ||
| let installedCount = 0 | ||
| step('Installing Antigravity skills...') | ||
| fs.mkdirSync(agDst, { recursive: true }) | ||
| for (const skill of selectedSkills) { | ||
| const dst = path.join(agDst, skill.name) | ||
| if (fs.existsSync(dst) && !YES) { | ||
| const overwrite = await ask(`@${skill.name} already exists. Overwrite?`) | ||
| if (!overwrite) { info(`Skipped: @${skill.name}`); continue } | ||
| } | ||
| copyDir(skill.src, dst) | ||
| ok(`skill: @${skill.name}`) | ||
| installedCount++ | ||
| } | ||
| if (fs.existsSync(geminiSrc)) { | ||
| const dst = path.join(process.cwd(), 'GEMINI.md') | ||
| if (!fs.existsSync(dst) || YES) { | ||
| copyFile(geminiSrc, dst) | ||
| ok('GEMINI.md') | ||
| installedCount++ | ||
| } else { | ||
| const overwrite = await ask('GEMINI.md already exists. Overwrite?') | ||
| if (overwrite) { copyFile(geminiSrc, dst); ok('GEMINI.md'); installedCount++ } | ||
| else info('Skipped: GEMINI.md') | ||
| } | ||
| } | ||
| if (fs.existsSync(agentsMdSrc)) { | ||
| const dst = path.join(process.cwd(), 'AGENTS.md') | ||
| if (!fs.existsSync(dst) || YES) { | ||
| copyFile(agentsMdSrc, dst) | ||
| ok('AGENTS.md') | ||
| installedCount++ | ||
| } | ||
| } | ||
| console.log() | ||
| console.log(`${c.bold} ─────────────────────────────${c.reset}`) | ||
| console.log(`${c.bold}${c.green} Installation complete${c.reset} (${installedCount} items)`) | ||
| console.log(`${c.bold} ─────────────────────────────${c.reset}`) | ||
| console.log() | ||
| console.log(` ${c.dim}Skills:${c.reset} ${selectedSkills.map(s => '@' + s.name).join(' ')}`) | ||
| console.log() | ||
| process.exit(0) | ||
| } | ||
| // ─── Claude Code: resolve scope ────────────────────────────────────────────── | ||
| let isLocal | ||
@@ -266,11 +447,10 @@ | ||
| isLocal = true | ||
| } else if (FORCE_GLOBAL) { | ||
| } else if (FORCE_GLOBAL || YES || SKILLS_ONLY || HOOKS_ONLY || UNINSTALL) { | ||
| isLocal = false | ||
| } else { | ||
| // Interactive scope question | ||
| console.log(` ${c.bold}Where do you want to install?${c.reset}`) | ||
| console.log(` ${c.bold}Where do you want to install?${c.reset}\n`) | ||
| console.log(` ${c.cyan}g${c.reset} Global ${c.dim}~/.claude/ — available in all projects${c.reset}`) | ||
| console.log(` ${c.cyan}l${c.reset} Local ${c.dim}.claude/ (here) — this project only${c.reset}`) | ||
| console.log() | ||
| const scopeAns = YES ? 'g' : await prompt(` ${c.dim}[g/l]${c.reset} `) | ||
| const scopeAns = await prompt(` ${c.dim}[g/l]${c.reset} `) | ||
| isLocal = scopeAns.toLowerCase() === 'l' | ||
@@ -316,3 +496,3 @@ console.log() | ||
| // ─── Resolve selection ──────────────────────────────────────────────────────── | ||
| // ─── Claude Code: check install ────────────────────────────────────────────── | ||
@@ -355,3 +535,3 @@ const claudeInstalled = spawnSync('claude', ['--version'], { shell: true }).status === 0 | ||
| // ─── Install ───────────────────────────────────────────────────────────────── | ||
| // ─── Install skills ─────────────────────────────────────────────────────────── | ||
@@ -358,0 +538,0 @@ let installedCount = 0 |
+24
-1
@@ -12,2 +12,24 @@ # Changelog | ||
| ## [2.2.0] - 2026-05-24 | ||
| ### Added | ||
| - **cli**: Flags `--claude`, `--cursor`, `--copilot`, `--antigravity` to skip IDE prompt | ||
| - **cli**: Local and global installation options (`--local`, `--global`) | ||
| - **cli**: Interactive selection menu with improved category and item handling | ||
| - Skills: `/commit`, `/debug`, `/memory`, `/plan`, `/pr`, `/review`, `/vibe-audit` | ||
| - Agents: `/api`, `/docs`, `/frontend`, `/refactor`, `/test` | ||
| - Memory management documentation and changelog guidelines | ||
| - Support for Google Antigravity alongside Claude Code, Cursor, and Copilot | ||
| ### Fixed | ||
| - Argument-hint YAML formatting in skill documentation | ||
| - CLI scope selection logic for non-interactive modes | ||
| - CLI uninstall option included in scope selection | ||
| ### Changed | ||
| - Enhanced CLI skill management with improved listing and copying functions | ||
| - Updated project architecture decisions and stack documentation | ||
| --- | ||
| ## [2.1.0] - 2026-04-11 | ||
@@ -55,3 +77,4 @@ | ||
| [Unreleased]: https://github.com/bezael/ai-workflow-kit/compare/v2.1.0...HEAD | ||
| [Unreleased]: https://github.com/bezael/ai-workflow-kit/compare/v2.2.0...HEAD | ||
| [2.2.0]: https://github.com/bezael/ai-workflow-kit/compare/v2.1.0...v2.2.0 | ||
| [2.1.0]: https://github.com/bezael/ai-workflow-kit/compare/v2.0.0...v2.1.0 |
+1
-1
| { | ||
| "name": "ai-workflow-kit", | ||
| "version": "2.2.0-beta.2", | ||
| "version": "2.2.0", | ||
| "description": "Skills, agents & hooks for Claude Code, Cursor, GitHub Copilot, and Google Antigravity", | ||
@@ -5,0 +5,0 @@ "type": "module", |
| --- | ||
| name: ak:memory | ||
| description: Manage persistent memory across sessions. Subcommands: save [topic] captures session learnings, recall [question] retrieves relevant context before acting, clean removes stale entries. | ||
| description: "Manage persistent memory across sessions. Subcommands: save [topic] captures session learnings, recall [question] retrieves relevant context before acting, clean removes stale entries." | ||
| argument-hint: <save|recall|clean> [topic or question] | ||
@@ -5,0 +5,0 @@ --- |
| --- | ||
| name: ak:review | ||
| description: Review code with real engineering criteria — logic bugs, security vulnerabilities, and technical debt. Use when user says /review @file or /review to review current PR changes. | ||
| argument-hint: [@file or leave empty for PR diff] | ||
| argument-hint: "[@file or leave empty for PR diff]" | ||
| context: fork | ||
@@ -6,0 +6,0 @@ agent: Explore |
@@ -5,3 +5,3 @@ --- | ||
| disable-model-invocation: true | ||
| argument-hint: [@folder or leave empty for current project] | ||
| argument-hint: "[@folder or leave empty for current project]" | ||
| context: fork | ||
@@ -8,0 +8,0 @@ agent: Explore |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
543534
1.57%1969
8.19%1
-50%