Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

ai-workflow-kit

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ai-workflow-kit - npm Package Compare versions

Comparing version
2.2.0-beta.1
to
2.2.0-beta.2
+117
-80
bin/cli.js

@@ -8,2 +8,4 @@ #!/usr/bin/env node

* 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 --global → install into ~/.claude/ (default)
* npx ai-workflow-kit --skills → all skills and agents only

@@ -38,11 +40,2 @@ * npx ai-workflow-kit --hooks → all hooks only

// ─── Paths ───────────────────────────────────────────────────────────────────
const __dir = path.dirname(fileURLToPath(import.meta.url))
const REPO_ROOT = path.resolve(__dir, '..')
const CLAUDE = path.join(os.homedir(), '.claude')
const SKILLS_DST = path.join(CLAUDE, 'skills')
const AGENTS_DST = path.join(CLAUDE, 'agents')
const HOOKS_DST = path.join(CLAUDE, 'hooks')
const SETTINGS = path.join(CLAUDE, 'settings.json')
// ─── Args ────────────────────────────────────────────────────────────────────

@@ -55,3 +48,22 @@ const args = process.argv.slice(2)

const LIST = args.includes('--list')
const FORCE_LOCAL = args.includes('--local')
const FORCE_GLOBAL = args.includes('--global')
// ─── Paths ───────────────────────────────────────────────────────────────────
const __dir = path.dirname(fileURLToPath(import.meta.url))
const REPO_ROOT = path.resolve(__dir, '..')
function resolvePaths(isLocal) {
const base = isLocal
? path.join(process.cwd(), '.claude')
: path.join(os.homedir(), '.claude')
return {
SKILLS_DST: path.join(base, 'skills'),
AGENTS_DST: path.join(base, 'agents'),
HOOKS_DST: path.join(base, 'hooks'),
SETTINGS: path.join(base, 'settings.json'),
base,
}
}
// ─── Discovery ───────────────────────────────────────────────────────────────

@@ -128,83 +140,90 @@

// ─── Selection menu ──────────────────────────────────────────────────────────
// ─── Selection — step 1: categories ─────────────────────────────────────────
function renderMenu(allSkills, allAgents, allHooks) {
const numWidth = String(allSkills.length + allAgents.length + allHooks.length).length
async function selectCategories(allSkills, allAgents, allHooks) {
const skillNames = allSkills.map(s => s.name).join(', ')
const agentNames = allAgents.map(a => a.name).join(', ')
const hookNames = allHooks.map(h => path.basename(h, '.sh')).join(', ')
function grid(items, startNum) {
const cols = 3
const colW = 14
for (let i = 0; i < items.length; i += cols) {
const row = items.slice(i, i + cols)
const line = row.map(({ num, name }) => {
const label = `${String(num).padStart(numWidth)} ${c.cyan}${name}${c.reset}`
// strip ANSI for length calculation
const rawLen = String(num).padStart(numWidth).length + 2 + name.length
return label + ' '.repeat(Math.max(1, colW - rawLen))
}).join(' ')
console.log(' ' + line)
}
console.log(`\n${c.bold} What would you like to install?${c.reset}\n`)
console.log(` ${c.cyan}s${c.reset} Skills ${c.dim}${skillNames}${c.reset}`)
console.log(` ${c.cyan}ag${c.reset} Agents ${c.dim}${agentNames}${c.reset}`)
console.log(` ${c.cyan}h${c.reset} Hooks ${c.dim}${hookNames}${c.reset}`)
console.log(` ${c.cyan}a${c.reset} All of the above`)
console.log()
const input = await prompt(` Enter categories ${c.dim}(e.g. "s h" or "a")${c.reset}: `)
const tokens = input.toLowerCase().split(/[\s,]+/).filter(Boolean)
if (!tokens.length) return { wantSkills: false, wantAgents: false, wantHooks: false }
if (tokens.includes('a') || tokens.includes('all')) {
return { wantSkills: true, wantAgents: true, wantHooks: true }
}
let n = 1
const skillItems = allSkills.map(s => ({ num: n++, name: s.name, item: s, type: 'skill' }))
const agentItems = allAgents.map(a => ({ num: n++, name: a.name, item: a, type: 'agent' }))
const hookItems = allHooks.map(h => ({ num: n++, name: path.basename(h, '.sh'), item: h, type: 'hook' }))
return {
wantSkills: tokens.includes('s') || tokens.includes('skills'),
wantAgents: tokens.includes('ag') || tokens.includes('agents'),
wantHooks: tokens.includes('h') || tokens.includes('hooks'),
}
}
console.log(`\n${c.bold} What would you like to install?${c.reset}\n`)
// ─── Selection — step 2: items within a category ────────────────────────────
console.log(` ${c.bold}SKILLS${c.reset}`)
grid(skillItems)
console.log()
async function selectItemsInCategory(items, getName) {
const numWidth = String(items.length).length
const cols = 3
const colW = 16
console.log(` ${c.bold}AGENTS${c.reset}`)
grid(agentItems)
console.log()
console.log(` ${c.bold}HOOKS${c.reset}`)
grid(hookItems)
for (let i = 0; i < items.length; i += cols) {
const row = items.slice(i, i + cols)
const line = row.map((item, j) => {
const n = i + j + 1
const name = getName(item)
const label = ` ${c.dim}${String(n).padStart(numWidth)}${c.reset} ${c.cyan}${name}${c.reset}`
const rawLen = 2 + String(n).padStart(numWidth).length + 2 + name.length
return label + ' '.repeat(Math.max(1, colW - rawLen))
}).join('')
console.log(line)
}
console.log()
console.log(` ${c.dim}Shortcuts: [a] all [s] all skills [ag] all agents [h] all hooks${c.reset}`)
console.log()
const input = await prompt(` Enter numbers or ${c.cyan}Enter${c.reset} for all: `)
return { skillItems, agentItems, hookItems }
if (!input.trim()) return items
const selected = new Set()
for (const token of input.split(/[\s,]+/).filter(Boolean)) {
const n = parseInt(token, 10)
if (n >= 1 && n <= items.length) selected.add(items[n - 1])
}
return [...selected]
}
async function selectItems(allSkills, allAgents, allHooks) {
const { skillItems, agentItems, hookItems } = renderMenu(allSkills, allAgents, allHooks)
const allItems = [...skillItems, ...agentItems, ...hookItems]
const { wantSkills, wantAgents, wantHooks } = await selectCategories(allSkills, allAgents, allHooks)
const input = await prompt(` Enter numbers or shortcuts ${c.dim}(e.g. "1 3 5" or "s h")${c.reset}: `)
if (!wantSkills && !wantAgents && !wantHooks) return { skills: [], agents: [], hooks: [] }
if (!input) return { skills: [], agents: [], hooks: [] }
let skills = []
let agents = []
let hooks = []
const tokens = input.toLowerCase().split(/[\s,]+/).filter(Boolean)
const skills = new Set()
const agents = new Set()
const hooks = new Set()
if (wantSkills && allSkills.length > 0) {
console.log(`\n ${c.bold}SKILLS${c.reset} — pick specific or Enter for all`)
skills = await selectItemsInCategory(allSkills, s => s.name)
}
for (const token of tokens) {
if (token === 'a' || token === 'all') {
return { skills: allSkills, agents: allAgents, hooks: allHooks }
}
if (token === 's' || token === 'skills') {
allSkills.forEach(s => skills.add(s)); continue
}
if (token === 'ag' || token === 'agents') {
allAgents.forEach(a => agents.add(a)); continue
}
if (token === 'h' || token === 'hooks') {
allHooks.forEach(h => hooks.add(h)); continue
}
const num = parseInt(token, 10)
const found = allItems.find(i => i.num === num)
if (found) {
if (found.type === 'skill') skills.add(found.item)
if (found.type === 'agent') agents.add(found.item)
if (found.type === 'hook') hooks.add(found.item)
}
if (wantAgents && allAgents.length > 0) {
console.log(`\n ${c.bold}AGENTS${c.reset} — pick specific or Enter for all`)
agents = await selectItemsInCategory(allAgents, a => a.name)
}
return { skills: [...skills], agents: [...agents], hooks: [...hooks] }
if (wantHooks && allHooks.length > 0) {
console.log(`\n ${c.bold}HOOKS${c.reset} — pick specific or Enter for all`)
hooks = await selectItemsInCategory(allHooks, h => path.basename(h, '.sh'))
}
return { skills, agents, hooks }
}

@@ -215,3 +234,3 @@

console.log(`${c.bold} AI Workflow Kit${c.reset} ${c.dim}v${JSON.parse(fs.readFileSync(path.join(REPO_ROOT, 'package.json'), 'utf8')).version}${c.reset}`)
console.log(` ${c.dim}Skills · Agents · Hooks for Claude Code, Cursor & Copilot${c.reset}`)
console.log(` ${c.dim}Skills · Agents · Hooks for Claude Code, Cursor, Antigravity & Copilot${c.reset}`)
console.log()

@@ -237,2 +256,27 @@

// ─── Resolve scope (local vs global) ─────────────────────────────────────────
let isLocal
if (FORCE_LOCAL) {
isLocal = true
} else if (FORCE_GLOBAL) {
isLocal = false
} else {
// Interactive scope question
console.log(` ${c.bold}Where do you want to install?${c.reset}`)
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} `)
isLocal = scopeAns.toLowerCase() === 'l'
console.log()
}
const { SKILLS_DST, AGENTS_DST, HOOKS_DST, SETTINGS, base: CLAUDE_BASE } = resolvePaths(isLocal)
const scopeLabel = isLocal
? `local ${c.dim}(.claude/)${c.reset}`
: `global ${c.dim}(~/.claude/)${c.reset}`
info(`Scope: ${scopeLabel}`)
// ─── Uninstall ───────────────────────────────────────────────────────────────

@@ -285,10 +329,7 @@ if (UNINSTALL) {

if (SKILLS_ONLY) {
// --skills wins over --yes: scope to skills + agents only
selectedSkills = allSkills
selectedAgents = allAgents
} else if (HOOKS_ONLY) {
// --hooks wins over --yes: scope to hooks only
selectedHooks = allHooks
} else if (YES) {
// --yes with no scope flag: install everything
selectedSkills = allSkills

@@ -298,3 +339,2 @@ selectedAgents = allAgents

} else {
// Interactive selection menu
const sel = await selectItems(allSkills, allAgents, allHooks)

@@ -316,3 +356,2 @@ selectedSkills = sel.skills

// Skills → ~/.claude/skills/
if (selectedSkills.length > 0) {

@@ -338,3 +377,2 @@ step('Installing skills...')

// Agents → ~/.claude/agents/ (flat .md files)
if (selectedAgents.length > 0) {

@@ -358,3 +396,2 @@ step('Installing agents...')

// Hooks → ~/.claude/hooks/ + configure settings.json
if (selectedHooks.length > 0) {

@@ -375,5 +412,5 @@ step('Installing hooks...')

if (!fs.existsSync(SETTINGS)) {
const template = fs.readFileSync(path.join(REPO_ROOT, 'hooks', 'settings.template.json'), 'utf8')
const template = fs.readFileSync(path.join(REPO_ROOT, 'hooks', 'settings.template.json'), 'utf8')
const hooksDstJson = HOOKS_DST.replace(/\\/g, '/')
const configured = template.replace(/~\/\.claude\/hooks/g, hooksDstJson)
const configured = template.replace(/~\/\.claude\/hooks/g, hooksDstJson)
try {

@@ -380,0 +417,0 @@ const cleaned = configured

{
"name": "ai-workflow-kit",
"version": "2.2.0-beta.1",
"version": "2.2.0-beta.2",
"description": "Skills, agents & hooks for Claude Code, Cursor, GitHub Copilot, and Google Antigravity",

@@ -5,0 +5,0 @@ "type": "module",

@@ -14,5 +14,14 @@ # AI Workflow Kit

Or pin a specific version as a dev dependency (it's a dev tool, not a runtime dependency):
```bash
npm i -D ai-workflow-kit@2.2.0-beta.1
npx ai-workflow-kit
```
Restart Claude Code. You'll have `/ak:commit`, `/ak:pr`, `/ak:plan`, `/ak:debug`, `/ak:review`, `/ak:vibe-audit`, `/ak:frontend`, `/ak:api`, `/ak:test`, `/ak:refactor`, and `/ak:docs` available — plus 5 automatic hooks.
```bash
npx ai-workflow-kit --global # install into ~/.claude/ — all projects (default)
npx ai-workflow-kit --local # install into .claude/ — this project only
npx ai-workflow-kit --skills # skills and agents only

@@ -19,0 +28,0 @@ npx ai-workflow-kit --hooks # hooks only