Commit Graph

264 Commits

Author SHA1 Message Date
John Lindquist 62f6718d31 feat(skills): remove streamdown skill, expand ai-elements, update profiler and pretool hook, update tests; bump to 0.9.0 2026-03-08 19:50:24 -06:00
John Lindquist 43fec91f36 fix(workflow): document canonical project structure for src/ vs no-src, fix @/workflows import path guidance; bump to 0.8.3 2026-03-08 19:46:35 -06:00
John Lindquist c8e1da3760 fix(ai-sdk): refine markdown rendering guidance to focus on AI Elements Message component; bump to 0.8.2 2026-03-08 18:33:30 -06:00
John Lindquist 6e9a0640d3 fix(skills): strengthen skills from eval feedback — markdown rendering warning in ai-sdk, sandbox/withWorkflow/peer-deps in workflow, mandatory browser verify language; bump to 0.8.1 2026-03-08 18:04:42 -06:00
John Lindquist 2d53cbe2bf feat(hooks): bump skill cap from 3 to 5, add shadcn create-next-app nudge; bump to 0.8.0 2026-03-08 17:26:11 -06:00
John Lindquist 5110bb6529 fix(skills): add flags importPatterns, model slug callout in ai-sdk; bump to 0.7.3 2026-03-08 14:17:05 -06:00
John Lindquist a449bd36c2 fix(skills): rewrite workflow SKILL.md with real WDK API, tighten shadcn patterns; bump to 0.7.2 2026-03-08 14:08:39 -06:00
John Lindquist a9c3119ef1 docs(skills): add design cross-reference guidance
Add short UI/design cross-reference sections to six skill guides.
Each insertion is anchored to the requested existing section so the rest
of the guidance remains unchanged.

Verified: git diff --check -- skills/nextjs/SKILL.md skills/v0-dev/SKILL.md skills/ai-elements/SKILL.md skills/chat-sdk/SKILL.md skills/bootstrap/SKILL.md skills/react-best-practices/SKILL.md
Verified: node <<'NODE' ... anchor-order assertions for all 6 files ... NODE
Swarm-Agent: codex-crossrefs
2026-03-08 11:42:22 -06:00
John Lindquist 4978c36f69 docs(geist): expand skill metadata and typography guidance
Broaden the geist skill trigger metadata so layout, globals, styles, and install commands
map to the skill more reliably in monorepos and app-router projects.
Add explicit typography direction so the skill guides Vercel-style hierarchy,
family usage, and common anti-patterns instead of acting like a bare font import.

Verified: node --input-type=module <<'EOF'
import { readFile } from 'node:fs/promises';
import { extractFrontmatter, parseSkillFrontmatter } from './hooks/skill-map-frontmatter.mjs';

const content = await readFile('skills/geist/SKILL.md', 'utf8');
const { yaml, body } = extractFrontmatter(content);
const parsed = parseSkillFrontmatter(yaml);

const expectedPaths = [
  'app/layout.*',
  'src/app/layout.*',
  'app/globals.css',
  'src/app/globals.css',
  'styles/**',
  'tailwind.config.*',
  'apps/*/app/layout.*',
  'apps/*/src/app/layout.*',
  'apps/*/app/globals.css',
  'apps/*/src/app/globals.css',
];
const expectedImports = ['geist', 'geist/font', 'geist/font/*'];

function assert(condition, message) {
  if (!condition) throw new Error(message);
}

assert(parsed.description.includes('typography system'), 'description should mention typography system');
assert(parsed.description.includes('aesthetic guidance'), 'description should mention aesthetic guidance');
assert(parsed.metadata.priority === 4, 'priority should be 4');
assert(JSON.stringify(parsed.metadata.pathPatterns) === JSON.stringify(expectedPaths), 'pathPatterns should match requested list');
assert(JSON.stringify(parsed.metadata.importPatterns) === JSON.stringify(expectedImports), 'importPatterns should match requested list');
assert(Array.isArray(parsed.metadata.bashPatterns) && parsed.metadata.bashPatterns.length === 4, 'bashPatterns should include npm/pnpm/bun/yarn install patterns');

const fontWeightsIndex = body.indexOf('## Font Weights');
const typographyIndex = body.indexOf('## Typography Direction for Geist');
const subsetIndex = body.indexOf('## Subset Configuration');
assert(fontWeightsIndex !== -1, 'Font Weights heading should exist');
assert(typographyIndex > fontWeightsIndex, 'Typography Direction section should come after Font Weights');
assert(subsetIndex === -1 || typographyIndex < subsetIndex, 'Typography Direction section should come before Subset Configuration');
assert(body.includes('### What good looks like'), 'Typography section should include What good looks like');
assert(body.includes('### Default type recipes'), 'Typography section should include default type recipes');
assert(body.includes('### Where to use each family'), 'Typography section should include family guidance');
assert(body.includes('### Anti-patterns'), 'Typography section should include anti-patterns');
assert(body.includes('text-lg tracking-tight'), 'Typography recipes should include text-lg section heading');
assert(body.includes('text-xl tracking-tight'), 'Typography recipes should include text-xl section heading');

console.log('frontmatter and section structure verified');
EOF
Verified: node --input-type=module <<'EOF'
import { readFile } from 'node:fs/promises';
import { extractFrontmatter, parseSkillFrontmatter } from './hooks/skill-map-frontmatter.mjs';
import { compileSkillPatterns, matchBashWithReason, matchImportWithReason, matchPathWithReason } from './hooks/patterns.mjs';

const content = await readFile('skills/geist/SKILL.md', 'utf8');
const { yaml } = extractFrontmatter(content);
const parsed = parseSkillFrontmatter(yaml);
const [compiled] = compileSkillPatterns({ geist: parsed.metadata });

function assert(condition, message) {
  if (!condition) throw new Error(message);
}

for (const filePath of [
  'app/layout.tsx',
  'src/app/layout.tsx',
  'app/globals.css',
  'apps/web/app/layout.tsx',
  'apps/web/src/app/globals.css',
  'styles/tokens.css',
  'tailwind.config.ts',
]) {
  assert(matchPathWithReason(filePath, compiled.compiledPaths), );
}

for (const command of [
  'npm install geist',
  'pnpm add geist',
  'bun install geist',
  'yarn add geist',
]) {
  assert(matchBashWithReason(command, compiled.compiledBash), );
}

for (const source of [
  "import { GeistSans } from 'geist/font/sans'",
  "const mono = require('geist/font/mono')",
  "await import('geist')",
]) {
  assert(matchImportWithReason(source, compiled.compiledImports), );
}

console.log('path, bash, and import pattern matching verified');
EOF
Swarm-Agent: codex-geist
2026-03-08 11:38:07 -06:00
John Lindquist 86a57328ec docs(vercel): add UI design defaults
Add a new UI Design Defaults subsection under Conventions so the repo guidance
states the default design system, mode, token, typography, and composition
choices for application UI.

Verified: node -e "const fs=require('fs'); const text=fs.readFileSync('vercel.md','utf8'); const marker='### UI Design Defaults\n\n- For application UI, default to **shadcn/ui + Geist**.'; if(!text.includes(marker)) throw new Error('missing UI Design Defaults section'); const ui=text.indexOf('### UI Design Defaults'); const next=text.indexOf('### Next.js 16'); if(ui===-1||next===-1||ui>next) throw new Error('section not before Next.js 16'); console.log('verified vercel.md UI Design Defaults ordering');"\nHow to test: open vercel.md and confirm the new subsection appears directly before `### Next.js 16`.\nSwarm-Agent: codex-vercel-md
2026-03-08 11:37:44 -06:00
John Lindquist 181eb1bc28 docs(shadcn): broaden skill triggers and design guidance
Broaden the shadcn skill frontmatter so it triggers on page, layout, and
component files across app, src, apps/*, and packages/* layouts.
Add explicit Vercel product UI composition and design direction guidance
after the common components table.

Verified: bun run - <<'EOF'
import { readFileSync } from 'node:fs';
import { extractFrontmatter, parseSkillFrontmatter } from './hooks/skill-map-frontmatter.mjs';
import { compileSkillPatterns, matchPathWithReason } from './hooks/patterns.mjs';
const content = readFileSync('skills/shadcn/SKILL.md', 'utf8');
const { yaml } = extractFrontmatter(content);
const parsed = parseSkillFrontmatter(yaml);
if (parsed.metadata.priority !== 6) throw new Error('priority');
if (!parsed.description.includes('composition patterns') || !parsed.description.includes('high-quality interface design')) throw new Error('description');
const compiled = compileSkillPatterns({ shadcn: { priority: parsed.metadata.priority, pathPatterns: parsed.metadata.pathPatterns, bashPatterns: parsed.metadata.bashPatterns } })[0];
for (const sample of ['components.json','app/dashboard/page.tsx','app/marketing/layout.jsx','src/app/docs/page.jsx','components/settings-panel.tsx','src/components/filters.jsx','apps/web/app/admin/page.tsx','apps/web/src/app/admin/layout.jsx','apps/web/components/command-bar.tsx','packages/ui/src/components/chart.jsx','packages/ui/components/ui/button.tsx']) {
  if (!matchPathWithReason(sample, compiled.compiledPaths)) throw new Error(sample);
}
console.log('shadcn skill frontmatter and path patterns validated');
EOF
Verified: git diff --check -- skills/shadcn/SKILL.md
Swarm-Agent: codex-shadcn
2026-03-08 11:35:16 -06:00
John Lindquist 77f3f2c4eb fix(workflow): update golden snapshots for broadened workflow patterns; bump to 0.7.1 2026-03-08 10:38:58 -06:00
John Lindquist 2809b81206 fix(workflow): broaden skill injection triggers
Workflow skill frontmatter now covers workflow-named paths, @vercel/workflow and related package installs/imports, and prompt signals for durable execution or step-based route work. The priority was also raised so Workflow-specific contexts inject the specialized skill before generic route guidance exhausts the budget.

Verified: bun test hooks/skill-map-frontmatter.test.ts
Verified: node -e "const { spawnSync } = require('node:child_process'); const payload = JSON.stringify({ prompt: 'Add Vercel Workflow durable execution to this API route using use workflow and step functions', session_id: 'workflow-prompt-2', cwd: process.cwd(), hook_event_name: 'UserPromptSubmit' }); const res = spawnSync('node', ['hooks/user-prompt-submit-skill-inject.mjs'], { input: payload, encoding: 'utf8', env: { ...process.env, VERCEL_PLUGIN_SEEN_SKILLS: '' } }); if (res.status !== 0) process.exit(res.status ?? 1); const out = JSON.parse(res.stdout || '{}'); const ctx = out.hookSpecificOutput?.additionalContext || ''; if (!ctx.includes('skill:workflow')) process.exit(1);"
Verified: node -e "const { spawnSync } = require('node:child_process'); const payload = JSON.stringify({ tool_name: 'Read', tool_input: { file_path: '/Users/me/project/app/api/workflows/process-order/route.ts' }, session_id: 'workflow-read-2', cwd: process.cwd() }); const res = spawnSync('node', ['hooks/pretooluse-skill-inject.mjs'], { input: payload, encoding: 'utf8', env: { ...process.env, VERCEL_PLUGIN_SEEN_SKILLS: '' } }); if (res.status !== 0) process.exit(res.status ?? 1); const out = JSON.parse(res.stdout || '{}'); const ctx = out.hookSpecificOutput?.additionalContext || ''; if (!ctx.includes('skill:workflow')) process.exit(1);"
Verified: node -e "const { spawnSync } = require('node:child_process'); const payload = JSON.stringify({ tool_name: 'Bash', tool_input: { command: 'pnpm add @vercel/workflow' }, session_id: 'workflow-bash-2', cwd: process.cwd() }); const res = spawnSync('node', ['hooks/pretooluse-skill-inject.mjs'], { input: payload, encoding: 'utf8', env: { ...process.env, VERCEL_PLUGIN_SEEN_SKILLS: '' } }); if (res.status !== 0) process.exit(res.status ?? 1); const out = JSON.parse(res.stdout || '{}'); const ctx = out.hookSpecificOutput?.additionalContext || ''; if (!ctx.includes('skill:workflow')) process.exit(1);"
Verified: node -e "const { spawnSync } = require('node:child_process'); const payload = JSON.stringify({ tool_name: 'Write', tool_input: { file_path: '/Users/me/project/app/api/orders/route.ts', content: "import { workflow } from '@vercel/workflow';\nexport const POST = async () => { return Response.json({ ok: true }); };" }, session_id: 'workflow-write-2', cwd: process.cwd() }); const res = spawnSync('node', ['hooks/pretooluse-skill-inject.mjs'], { input: payload, encoding: 'utf8', env: { ...process.env, VERCEL_PLUGIN_SEEN_SKILLS: '' } }); if (res.status !== 0) process.exit(res.status ?? 1); const out = JSON.parse(res.stdout || '{}'); const ctx = out.hookSpecificOutput?.additionalContext || ''; if (!ctx.includes('skill:workflow')) process.exit(1);"
Swarm-Agent: codex-workflow-patterns
2026-03-08 10:18:08 -06:00
John Lindquist a95d55d911 test(workflow): add trigger regression coverage
Add workflow trigger regression tests for pretool path and bash matching, plus prompt-signal and frontmatter coverage for durable workflow phrasing.
These cases mirror the workflow demo repo patterns such as workflows/*.ts routes, createWebhook-based async request/reply flows, and crash-safe step orchestration.

Verified: bun test tests/pretooluse-skill-inject.test.ts tests/user-prompt-submit.test.ts tests/skill-map-frontmatter.test.ts
Swarm-Agent: codex-workflow-test
2026-03-08 10:16:50 -06:00
John Lindquist 004137663e feat(skills): update 29 skill docs, add eval skill, update validate tests; bump to 0.7.0
Refine SKILL.md content across 29 skills based on live eval findings from 16
benchmark sessions. Add .claude/skills/vercel-plugin-eval/ for running real-world
plugin eval sessions with debug log monitoring. Update posttooluse-validate and
validate-rules tests to match refined skill content.
2026-03-08 09:30:36 -06:00
John Lindquist 08ee18d51d feat(hooks): atomic per-skill claim dedup, fix race condition and UserPromptSubmit sharing; bump to 0.6.0
Parallel PreToolUse hooks were racing on the same seen-skills file, causing 2-6x
duplicate injections. UserPromptSubmit hook didn't share dedup state at all.

Fix by implementing atomic per-skill claim files (Oracle session: fix-dedup-race-condition-plan):

1. In hooks/src/hook-env.mts, add tryClaimSessionKey(sessionId, kind, key) using
   openSync(path, 'wx') for atomic exclusive create. Add listSessionKeys() to read
   claim dir, syncSessionFileFromClaims() to derive the txt snapshot, and
   removeSessionClaimDir() for cleanup. Claim files live in
   <tmpdir>/vercel-plugin-<sessionId>-seen-skills.d/<skill-name>.

2. In hooks/src/patterns.mts, add mergeSeenSkillStates(...values) to union env var,
   session file, and claim dir state. Add serializeSeenSkills(set) helper.

3. In hooks/src/pretooluse-skill-inject.mts, load merged state from env+file+claims.
   Before injecting each skill, call tryClaimSessionKey — first process wins, others
   get EEXIST and skip. Use same claim path for once-only keys (agent-browser warning,
   vercel-env-help). Pass sessionId through InjectOptions.

4. In hooks/src/user-prompt-submit-skill-inject.mts, preserve sessionId from parsed
   input, load merged seen state, pass sessionId to injection flow so it uses the
   shared claim backend. Skills injected via promptSignals now visible to PreToolUse.

5. In hooks/src/session-end-cleanup.mts, add rmSync deletion of claim directories.

6. Update CLAUDE.md dedup contract to document atomic claim mechanism.
7. Bump .plugin/plugin.json to 0.6.0, rebuild.
2026-03-07 17:19:25 -07:00
John Lindquist aad9e11dbe fix(user-prompt-hook): share seen-skill dedup state with session claims
UserPromptSubmit previously deduped only against VERCEL_PLUGIN_SEEN_SKILLS,
so prompt-signal injections were invisible to PreToolUse when session-file/claim
state diverged. This caused duplicate skill injection across hooks.

This change merges seen-skill state from env + session file + atomic claim keys,
passes sessionId through injectSkills, and syncs injected skills back into claim
state after injection so both hooks observe one dedup source of truth.

Verified: bun test hooks/user-prompt-submit-skill-inject.test.ts (2 pass)
Verified: bun run build:hooks (pass)
Swarm-Agent: codex-userprompt-dedup
2026-03-07 17:17:53 -07:00
John Lindquist 62f1fb2d7c fix(hooks): use atomic seen-skill claims in pretool hook
PreToolUse dedup now merges env, legacy file, and per-key claim state so
parallel hooks converge on one seen-skills view.

Skill injection now performs per-skill atomic claims before appending content,
skipping skills already claimed by concurrent hooks and syncing env/file from
claim keys. Once-only warning/help keys now use the same claim path when a
session id is available, with previous in-process append fallback preserved
when no session id exists.

Verified: bun run build:hooks
Verified: bun test tests/pretooluse-skill-inject.test.ts
Swarm-Agent: codex-pretool-claims
2026-03-07 17:14:29 -07:00
John Lindquist 847f368f6b fix(hooks): clean claim directories on session end
SessionEnd cleanup previously removed only the legacy temp files.
This adds best-effort removal of the atomic claim directories for seen-skills and validated-files to avoid stale per-session artifacts.

Verified: bun run build:hooks
How to test: invoke hooks/src/session-end-cleanup.mts with a session_id and confirm *.txt and *.d temp artifacts are removed from tmpdir.
Swarm-Agent: codex-cleanup-claims
2026-03-07 17:09:21 -07:00
John Lindquist 23e6a56461 feat(hooks): add SessionEnd cleanup hook, update docs and version; bump to 0.5.6
Add session-end-cleanup.mts that deletes temp dedup files when session ends:
1. Create hooks/src/session-end-cleanup.mts — reads session_id from stdin JSON,
   deletes tmpdir/vercel-plugin-<sessionId>-seen-skills.txt and validated-files.txt
2. Register SessionEnd hook in hooks/hooks.json
3. Add entry point to hooks/tsup.config.ts
4. Update CLAUDE.md dedup contract to document file-based persistence + cleanup
5. Bump .plugin/plugin.json to 0.5.6, rebuild manifest
2026-03-07 14:59:22 -07:00
John Lindquist 73d03a96ab test(dedup): align session dedup tests with file strategy
Update dedup-related tests to reflect session_id-backed file persistence and
subagent session separation.

Verified: bun test tests/pretooluse-skill-inject.test.ts tests/subagent-fresh-env.test.ts tests/session-timeline-subagent.test.ts
Swarm-Agent: codex-dedup-tests
2026-03-07 14:58:01 -07:00
John Lindquist c45856f4f7 fix(hooks): persist session dedup state via temp files
PreToolUse and PostToolUse dedup state was previously process-local, which broke across hook subprocess invocations.\nThis change adds session-scoped temp-file persistence and threads session_id through the relevant flows.\n\nPreToolUse now falls back to per-session seen-skills file state and writes back on every appendSeenSkill update.\nPostToolUse now checks persisted validated-files state and writes updates after marking files validated.\n\nVerified: bun run build:hooks\nVerified: bun test tests/pretooluse-skill-inject.test.ts tests/posttooluse-validate.test.ts\nSwarm-Agent: codex-dedup-core
2026-03-07 14:57:23 -07:00
John Lindquist cbf4ed8a3e revert(hooks): remove temp file dedup, restore pure env-var dedup via CLAUDE_ENV_FILE; bump to 0.5.5
The 0.5.4 release added session-scoped temp files for dedup persistence, but this
was wrong — CLAUDE_ENV_FILE env vars ARE propagated to hook subprocesses by Claude
Code. The temp file approach littered tmpdir with hundreds of small files.

Revert to the original env-var-only mechanism:

1. Remove readSessionFile/writeSessionFile/dedupFilePath from hooks/src/hook-env.mts
2. Remove all writeSessionFile calls from pretooluse-skill-inject.mts — revert to
   pure process.env.VERCEL_PLUGIN_SEEN_SKILLS = appendSeenSkill(...) pattern
3. Remove sessionId from InjectOptions and the injectSkills call site
4. Remove sessionId from posttooluse-validate.mts ParsedInput — revert
   isAlreadyValidated/markValidated to pure env-var signatures
5. Revert all test expectations back to "env-var" and "memory-only" strategies
6. Restore CLAUDE.md dedup contract to env-var-only documentation
2026-03-07 14:39:08 -07:00
John Lindquist c107aec73d fix(hooks): persist skill dedup across hook invocations via session-scoped temp files; bump to 0.5.4
Skill dedup is completely broken because CLAUDE_ENV_FILE vars are only available to Bash
tool commands, not hook subprocesses. Each PreToolUse invocation starts a fresh Node.js
process that never sees VERCEL_PLUGIN_SEEN_SKILLS.

To fix this:

1. In hooks/src/hook-env.mts, add readSessionFile(sessionId, kind) and
   writeSessionFile(sessionId, kind, value) helpers that read/write
   /tmp/vercel-plugin-<sessionId>-<kind>.txt for persistent dedup state.

2. In hooks/src/pretooluse-skill-inject.mts, read seen skills from the session file
   at startup using readSessionFile(sessionId, "seen-skills"). Add a persistSeen()
   closure inside injectSkills() that calls both appendSeenSkill and writeSessionFile.
   Replace all process.env.VERCEL_PLUGIN_SEEN_SKILLS = appendSeenSkill(...) calls with
   persistSeen() or inline writeSessionFile calls. Add "file" as the primary dedup
   strategy when session_id is present, falling back to "env-var" then "memory-only".
   Pass sessionId through InjectOptions to injectSkills().

3. In hooks/src/posttooluse-validate.mts, add sessionId to ParsedInput and extract it
   from input.session_id in parseInput(). Pass sessionId to isAlreadyValidated() and
   markValidated(), which should read/write via readSessionFile/writeSessionFile for
   the "validated-files" kind.

4. Update tests: pretooluse-skill-inject.test.ts — rename "no env var" test to expect
   file-based dedup persistence, update strategy assertions from "env-var" to "file",
   use omitSessionId for memory-only test. subagent-fresh-env.test.ts — use a fresh
   session ID for subagent calls, update strategy expectations to "file".
   session-timeline-subagent.test.ts — add sessionId option to runHookEnv, use a
   different session ID for the subagent call.

5. Update CLAUDE.md dedup contract section to document file-based mechanism.

6. Bump .plugin/plugin.json version to 0.5.4, run bun run build.
2026-03-07 14:23:09 -07:00
John Lindquist c860d07cb2 fix(nextjs): remove broken .claude dir backup/restore scaffolding pattern; bump to 0.5.3 2026-03-07 13:48:10 -07:00
John Lindquist 365a710e67 feat(hooks): add prompt analysis, enhance validate/frontmatter hooks, expand test coverage; bump to 0.5.2 2026-03-07 13:09:28 -07:00
John Lindquist ff251ab018 refactor(hooks): move audit log to ~/.claude/projects dir; add validate hooks, prompt patterns, benchmark suite; bump to 0.5.1 2026-03-07 12:31:10 -07:00
John Lindquist 86dcaa8600 fix(tests): align fuzz and validate tests with skill-map validate field; bump to 0.5.0 2026-03-07 11:18:54 -07:00
John Lindquist d92df12306 feat(benchmark): align analyzer and runner with agent slugs
Switch benchmark runner project definitions to the 12 benchmark-agent scenario slugs and refresh expected skill targets.

Analyzer now discovers benchmark-agent projects from ~/.claude/projects when results subdirectories are absent, and falls back to hook_progress parsing from session JSONL when skill-injections.jsonl is missing.

Report skill hint mappings were expanded for the new scenario skill set so recommendations stay specific.

Verified: bun test tests/benchmark-analyze.test.ts tests/benchmark-pipeline.test.ts (43 pass)
Verified: bun run scripts/benchmark-analyze.ts (discovers 12 benchmark-agent projects)
Swarm-Agent: codex-p0-analyzer-slugs
2026-03-07 10:56:35 -07:00
John Lindquist 9d4080802d fix(hooks): resolve audit log path from stdin cwd fallback
When hooks run as child processes, process.cwd() can point at the plugin root\ninstead of the user project.\n\nThis change threads cwd from PreToolUse stdin JSON through parseInput()\ninto appendAuditLog(), and uses it as fallback when CLAUDE_PROJECT_ROOT\nis not set.\n\nVerified: bun run build:hooks\nVerified: bun test tests/pretooluse-skill-inject.test.ts\nSwarm-Agent: codex-p0-audit-path
2026-03-07 10:48:57 -07:00
John Lindquist 953496f115 docs(chat-sdk): correct Field and Thread API guidance
Adds a Packages section with explicit chat SDK and adapter version ranges,\nupdates install commands to include ranges, and documents three critical\nAPI corrections: Field options shape, Thread/Channel generic constraints,\nand lazy adapter initialization when signingSecret validation runs early.\n\nVerified: bun test tests/slack-clone-patterns.test.ts -t "slack-clone lib/bot/slack.ts injects chat-sdk" (1 pass)\nVerified: bun test tests/skill-map-frontmatter.test.ts -t "skill count matches number of SKILL.md directories" (1 pass)\nSwarm-Agent: codex-p4p5p6p7-new-skills
2026-03-07 10:37:40 -07:00
John Lindquist fd0c9d9553 docs(ai-gateway): add model slug and package guidance
Adds explicit model slug rules, default model recommendations, and a\nlookup step via gateway.getAvailableModels() before hardcoding IDs.\nAlso adds a Packages section with current AI SDK package ranges and\nupdates examples from gpt-5.2 to gpt-5.4.\n\nVerified: bun test tests/pretooluse-skill-inject.test.ts -t "vercel env pull" (3 pass)\nVerified: bun test tests/skill-map-frontmatter.test.ts -t "skill count matches number of SKILL.md directories" (1 pass)\nSwarm-Agent: codex-p4p5p6p7-new-skills
2026-03-07 10:37:34 -07:00
John Lindquist eee2fb15ab docs(nextjs): add critical init and lazy-load patterns
The Next.js skill needed explicit guardrails for two recurring failures:\n1) create-next-app in repos containing .claude/\n2) build-time crashes from module-scope SDK initialization without env vars.\n\nAdded two prominent sections near the top of skills/nextjs/SKILL.md with concrete commands and a reusable lazy singleton example.\n\nVerified: node -e "const fs=require('fs');const s=fs.readFileSync('skills/nextjs/SKILL.md','utf8');const required=['## Critical Pattern: Safe Project Init in Existing Repos','## Critical Pattern: Lazy Initialization for Build-Safe Modules','mv .claude /tmp/_claude_backup && npx create-next-app@latest . && mv /tmp/_claude_backup .claude','let _db: ReturnType<typeof drizzle> | null = null'];for(const r of required){if(!s.includes(r)){process.exit(1);}}const safeIdx=s.indexOf(required[0]);const lazyIdx=s.indexOf(required[1]);const scaffoldIdx=s.indexOf('## Scaffolding');if(!(safeIdx>=0&&lazyIdx>=0&&scaffoldIdx>=0&&safeIdx<scaffoldIdx&&lazyIdx<scaffoldIdx)){process.exit(1);}"\nVerified: command exits 0 and confirms both critical sections are present before Scaffolding.\nSwarm-Agent: codex-p2p3-nextjs-skill
2026-03-07 10:33:27 -07:00
John Lindquist 591478db60 docs(ai-sdk): add v6 migration pitfalls and API corrections
Add a prominent v6 pitfall section near the top of the AI SDK skill and correct stale migration guidance that was causing repeated implementation mistakes in generated code.\n\nThis captures critical package version mapping (ai/react/gateway), stream writer API usage, useChat transport migration, tool part naming, typed tool result fields, Agent class naming, and gateway limits for embeddings/image models.\n\nVerified: bun -e 'import { readFileSync } from "node:fs"; import { extractFrontmatter, parseSkillFrontmatter } from "./hooks/skill-map-frontmatter.mjs"; const content = readFileSync("skills/ai-sdk/SKILL.md", "utf8"); const fm = extractFrontmatter(content); if (!fm.yaml) throw new Error("missing frontmatter"); parseSkillFrontmatter(fm.yaml); console.log("frontmatter-ok");'\nVerified: bun -e 'import { readFileSync } from "node:fs"; const c = readFileSync("skills/ai-sdk/SKILL.md", "utf8"); const required = ["## v6 Migration Pitfalls (Read First)","ai@^6.0.0","@ai-sdk/react^3.0.x","@ai-sdk/gateway^3.x","stream.writer.write(...)"," or ","tool-<toolName>","DynamicToolCall","TypedToolResult","class name is ","does not support embeddings or image generation"]; for (const needle of required) { if (!c.includes(needle)) throw new Error(); } console.log("content-check-ok");'\nSwarm-Agent: codex-p1-ai-sdk-skill
2026-03-07 10:30:47 -07:00
John Lindquist 16c9ae25fd fix(hooks): inject one-shot vercel env quick reference
Add a Bash-triggered one-shot help block for vercel env add/update/pull.
This prevents repeated reminders under dedup while still allowing explicit repeats when dedup is off.

Verified: bun run build:hooks
Verified: bun test tests/subagent-fresh-env.test.ts
Swarm-Agent: codex-vercel-env-help
2026-03-07 07:51:05 -07:00
John Lindquist c2f07bd36b feat(hooks): add skill injection audit logging
Skill injections now append JSONL audit records for post-run debugging and traceability.
Audit path resolves from VERCEL_PLUGIN_AUDIT_LOG_FILE with an opt-out mode and a project-local default.

Verified: bun run build:hooks
Verified: bun test tests/subagent-fresh-env.test.ts
Swarm-Agent: codex-audit-log
2026-03-07 00:50:15 -07:00
John Lindquist 65c287f3df docs(ai-sdk-skill): clarify streaming response helpers
Add explicit guidance on when to return UI message streams versus text streams so client/server protocol choices are unambiguous. Also add a text-only server route example and update key pattern and migration bullets to reflect the correct helper for each client type.

Verified: npx --yes prettier@3 --check skills/ai-sdk/SKILL.md

How to test: run npx --yes prettier@3 --check skills/ai-sdk/SKILL.md

Swarm-Agent: codex-ai-sdk-streaming
2026-03-07 00:48:04 -07:00
John Lindquist 4c842ee4c1 feat(hooks): add greenfield execution nudge to claude inject
Injecting a greenfield-specific section steers fresh directories away from planning-only behavior and toward immediate execution with tool calls.\n\nVerified: bun run build:hooks\nVerified: output now joins vercel.md plus optional greenfield block with double newlines\nSwarm-Agent: codex-greenfield-nudge
2026-03-07 00:45:40 -07:00
John Lindquist 88469a2474 fix(profiler): seed greenfield defaults and keep env writes
Greenfield projects were exiting before writing likely skills and setup mode, which caused cold-start misses for subagents.\n\nThis change removes the early exit, applies explicit greenfield defaults, preserves the greenfield env marker, and writes likely skills/setup mode through the shared env-write path.\n\nVerified: bun run build:hooks\nVerified: bun test tests/subagent-fresh-env.test.ts\nSwarm-Agent: codex-greenfield-profiler
2026-03-07 00:44:57 -07:00
John Lindquist 7cf4462cea Add new skills, tests, and fixtures; bump to 0.4.3 2026-03-06 23:01:38 -07:00
John Lindquist cd5f369dcb Add new skills, typecheck gate, remove arg/ms/serve skills, bump to 0.4.2
- Add 8 new skills: edge-runtime, geist, micro, ncc, satori, streamdown, styled-jsx, swr
- Remove arg, ms, serve skills (standalone utilities, not relevant to shipping apps on Vercel)
- Add typecheck script and wire into `bun run test` and pre-commit hook
- Fix StdioOptions type error in session-start-profiler
- Add hook-env module and posttooluse-shadcn-font-fix hook
- Refactor skill-map-frontmatter, patterns, pretooluse-skill-inject
- Update generated catalog and manifest (42 skills)
- Add .gitignore with .DS_Store
2026-03-06 19:04:25 -07:00
John Lindquist ef6a6160e0 docs: add "How Do I Use This?" section to README 2026-03-06 16:14:15 -07:00
John Lindquist 3f3059a281 Add installation instructions to README 2026-03-06 15:22:33 -07:00
John Lindquist e449377742 docs: update README and CLAUDE.md for 34 skills, new hooks, and 20 test files
Reflect additions since last docs update: 13 new skills (agent-browser,
ai-elements, auth, bootstrap, chat-sdk, cms, cron-jobs, deployments-cicd,
email, env-vars, json-render, payments, shadcn), bootstrap command,
session-start-profiler and inject-claude-md hooks, and expanded test suite.
2026-03-06 15:22:03 -07:00
John Lindquist c082f8112e Add auth, cms, email, and payments skills. Update skill catalog and manifest with new entries. Expand observability and vercel-storage SKILL.md content. Update tests (snapshots, patterns, build-skill-map, vercel-config, subagent-fresh-env, redaction) and fixtures (consolidated-payloads, golden-edit/write-middleware, pattern-fixtures). Improve scripts/validate.ts and scripts/explain.ts with enhanced validation and CLI explain logic. Remove deprecated README.txt and remove Inngest skill references from marketplace SKILL.md, vercel.md, skill-catalog.md, and skill-manifest.json — Vercel now uses Workflow DevKit instead. 2026-03-06 13:49:46 -07:00
John Lindquist f2b67166eb chore: bump plugin version to 0.4.1 2026-03-06 13:19:27 -07:00
John Lindquist b725f5308e refactor(hooks): switch to tsup, remove compiled/ intermediate dir
- Replace tsc+cp+rm pipeline with tsup (7ms builds, no intermediate dir)
- tsup compiles hooks/src/*.mts directly to hooks/*.mjs
- tsconfig.json retained for type-checking only (noEmit)
- Remove all .sh references from tests, docs, and hooks.json
- Fix glob pattern test to handle tsup's output format
2026-03-06 13:08:58 -07:00
John Lindquist d679ac227f chore: remove legacy shell hook scripts 2026-03-06 13:00:28 -07:00
John Lindquist ba2aec03bb refactor(hooks): convert shell scripts to TypeScript
Convert inject-claude-md.sh and session-start-seen-skills.sh to .mts
source with compiled .mjs output. All hooks are now TypeScript.
Update hooks.json to invoke with node instead of bash.
2026-03-06 12:59:48 -07:00
John Lindquist 5a0591c292 feat(hooks): convert hooks to TypeScript with SDK type-checking
Hook source now lives in hooks/src/*.mts and compiles to hooks/*.mjs via tsc.
The formatOutput() return type is checked against SyncHookJSONOutput from
@anthropic-ai/claude-agent-sdk, preventing unknown fields in hookSpecificOutput
that Claude Code's strict Zod validation would silently reject.

Root cause: skillInjection metadata was a sibling key in hookSpecificOutput,
which Claude Code rejected as "Hook JSON output validation failed: Invalid input".
All skill injections were silently discarded. Now skillInjection metadata is
embedded as an HTML comment inside additionalContext.

- Add hooks/src/*.mts (TypeScript source for all 6 hook modules)
- Add hooks/tsconfig.json (strict, NodeNext, compiles .mts → .mjs)
- Add build:hooks script and pre-commit hook for auto-compilation
- Install @anthropic-ai/claude-agent-sdk as devDependency for types
- Bump plugin version to 0.4.0
2026-03-06 12:48:39 -07:00