Commit Graph

52 Commits

Author SHA1 Message Date
John Lindquist 8e3350454c feat: prompt scoring improvements, compaction re-injection, validation dedup, strip droppedByCap from context; bump to 0.18.0
- Add dominant-topic suppression (top score >= 600 filters scores < 50)
- Add project-context boost (+3 for VERCEL_PLUGIN_LIKELY_SKILLS skills)
- Add lexical fallback floor (reject raw score < 20)
- Add compaction re-injection for priority >= 7 skills (VERCEL_PLUGIN_CONTEXT_COMPACTED)
- Add validation rule dedup tracking (ruleId + filePath on violations)
- Strip droppedByCap from injected HTML comments (kept in debug logs)
- Fix ncc/SKILL.md and next-forge/SKILL.md YAML frontmatter
- Add startup diagnostic for broken skill frontmatter
2026-03-11 19:01:59 -06:00
John Lindquist b7e9b1b053 feat: merge upstream telemetry + Cursor compat, fix tests and dedup migration; bump to 0.17.0 2026-03-11 16:12:55 -06:00
John Lindquist 8e24d0694a feat: add chainTo skill chaining, prompt signals, validation upgrades, and dedup reset on context clear
Add a chainTo frontmatter field to skills that triggers follow-up skill injection
when PostToolUse file contents match regex patterns. Add upgradeToSkill/upgradeWhy
fields to validation rules so validate errors can recommend loading a specific skill.
Register posttooluse-bash-chain.mjs in hooks.json. Add ChainToRule interface to
patterns.mts and skill-map-frontmatter.mts, with parseChainToRules() parser. Add
duplicate-key detection to the YAML parser. Reset dedup claim dir and session file
on clear/compact events in session-start-seen-skills so skills re-inject into fresh
context windows.

Add chainTo rules to: agent-browser-verify, agent-browser, ai-elements, ai-gateway,
ai-generation-persistence, ai-sdk, auth, bootstrap, chat-sdk, cms, cron-jobs,
deployments-cicd, email, env-vars, geist, investigation-mode, json-render,
marketplace, micro, ncc, next-forge, nextjs, observability, payments,
react-best-practices, routing-middleware, runtime-cache, satori, shadcn,
sign-in-with-vercel, swr, turbopack, turborepo, v0-dev, vercel-agent, vercel-api,
vercel-cli, vercel-firewall, vercel-flags, vercel-functions, vercel-queues,
vercel-sandbox, vercel-storage, verification, workflow. Add upgradeToSkill to
ai-elements and ai-sdk validate rules. Expand ai-sdk validate messages with
Run Skill() hints. Update nextjs, vercel-storage, runtime-cache, workflow, turborepo
skill bodies.

Add new skills: geistdocs (Geist design system docs), zzz-test-meta-name-mask
(test fixture). Add skills/_chain-audit.md chain coverage audit doc.

Delete .claude-plugin/marketplace.json, .claude-plugin/plugin.json (deprecated),
skills/edge-runtime/SKILL.md (consolidated into vercel-functions).

Add tests: posttooluse-chain.test.ts (4699 lines, chain injection e2e),
ai-sdk-companion.test.ts (181 lines). Expand build-skill-map.test.ts (+335 lines),
validate-rules.test.ts (+936 lines), session-start-seen-skills.test.ts (+74 lines),
skill-map-frontmatter.test.ts (+50 lines), verification-skill.test.ts (+20 lines).

Update build-manifest.ts to emit chainTo rules and upgradeToSkill fields. Rebuild
generated/skill-manifest.json, generated/skill-catalog.md, generated/build-from-skills.manifest.json.
Rebuild all compiled hooks/*.mjs. Update CLAUDE.md lexical prompt default to on.
Update vercel.md ecosystem graph, docs, and cli-reference.
2026-03-11 15:18:35 -06:00
John Lindquist e048cbc9bd fix(pretooluse): drop seen env merge writes
The pretool hook no longer folds VERCEL_PLUGIN_SEEN_SKILLS into
session-file dedup state or writes claim-sync results back into
process.env. File-backed dedup still claims and syncs session state,
while env-only dedup remains a fallback when no session scope exists.

Verified: bun run build:hooks
Verified: bun test tests/hook-sync.test.ts
Verified: bun test tests/pretooluse-skill-inject.test.ts --test-name-pattern "file-based dedup persists across invocations with same session_id|debug mode logs dedup strategy for file, memory-only, and disabled"
Verified: node --input-type=module <<'EOF' ... fresh cursor Write payload asserts no VERCEL_PLUGIN_SEEN_SKILLS env update and TSX counter update EOF
Verified: node --input-type=module <<'EOF' ... env-only Read payload without session_id returns {} when VERCEL_PLUGIN_SEEN_SKILLS=nextjs EOF
Swarm-Agent: codex-pretool-drop-env-merge
2026-03-11 15:18:19 -06:00
John Lindquist 95176e59dc fix(pretooluse): move hook counters off Claude env file
PreToolUse now persists TSX review and dev-server verify counters via session files,
and it no longer appends runtime env exports to CLAUDE_ENV_FILE for Claude.
This keeps seen-skills dedup on the claim/session-file path and avoids shell-init
side effects during hook execution.

Verified: bun run build:hooks
Verified: bun test tests/pretooluse-skill-inject.test.ts -t "file-based dedup persists across invocations with same session_id"
Verified: bun test tests/pretooluse-skill-inject.test.ts -t "empty VERCEL_PLUGIN_SEEN_SKILLS env var dedups across invocations"
Verified: custom node smoke test (tsx-migration-check) — CLAUDE_ENV_FILE unchanged, tsx-edit-count reset in session file, seen-skills persisted
Verified: custom node smoke test (dev-migration-check) — CLAUDE_ENV_FILE unchanged, dev-verify-count persisted in session file
Swarm-Agent: codex-pretooluse-env-cleanup
2026-03-11 15:18:18 -06:00
John Lindquist b9fcf22191 feat(hooks): add Cursor compat to pretooluse-skill-inject
Detect platform via conversation_id/workspace_roots/cursor_version
fields in stdin JSON. Normalize sessionId, cwd, and output format:
- Cursor: flat { additional_context, env } output
- Claude Code: nested { hookSpecificOutput } output (unchanged)

Env var updates use JSON env field for Cursor instead of
CLAUDE_ENV_FILE. Includes platform-hook-compat test suite.
2026-03-11 15:18:18 -06:00
John Lindquist 92b69b6ee7 fix(hooks): support Cursor session-start profiler output
Finish the session-start profiler Cursor path without touching the profiling logic.
Platform detection now keys off hook input and CLAUDE_ENV_FILE, project root lookup falls back to CURSOR_PROJECT_DIR, and Cursor receives env plus additional_context JSON on stdout.

Verified: bun test hooks/session-start-profiler-platform.test.ts
Verified: bun test hooks/session-hooks-platform-compat.test.ts
Verified: zsh -lc 'tmpdir=/var/folders/c3/r013q3_93_s4zycmx0mdnt2h0000gn/T/tmp.p6JmjuMjls; printf "{\"conversation_id\":\"conv-123\",\"cursor_version\":\"1.0.0\"}" | env -u CLAUDE_ENV_FILE -u CLAUDE_PROJECT_ROOT CURSOR_PROJECT_DIR="" bun hooks/src/session-start-profiler.mts'
Swarm-Agent: codex-profiler-v2
2026-03-11 15:18:18 -06:00
John Lindquist 8d8faffe57 fix(hooks): add cursor support to posttool validator
Normalize PostToolUse stdin with compat-based platform detection and Cursor workspace/session fallbacks.
Emit Cursor additional_context/env payloads while preserving Claude output shape and empty-result behavior.

Verified: bun test hooks/platform-hook-compat.test.ts
Verified: bun --eval 'import assert from "node:assert/strict"; import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { formatOutput, markValidated } from "./hooks/src/posttooluse-validate.mts"; const tempDir = mkdtempSync(join(tmpdir(), "posttooluse-validate-")); const envFile = join(tempDir, "claude.env"); writeFileSync(envFile, "", "utf-8"); delete process.env.VERCEL_PLUGIN_VALIDATED_FILES; process.env.CLAUDE_ENV_FILE = envFile; const next = markValidated("app/page.tsx", "abc123def456", null); assert.equal(next, "app/page.tsx:abc123def456"); assert.match(readFileSync(envFile, "utf-8"), /VERCEL_PLUGIN_VALIDATED_FILES="app\/page\.tsx:abc123def456"/); const output = JSON.parse(formatOutput([{ skill: "ai-sdk", line: 8, message: "Use streamText for streaming responses.", severity: "recommended", matchedText: "generateText" }], ["ai-sdk"], "app/page.tsx", undefined, "cursor", { VERCEL_PLUGIN_VALIDATED_FILES: next })); assert.equal(output.env.VERCEL_PLUGIN_VALIDATED_FILES, next); rmSync(tempDir, { recursive: true, force: true }); delete process.env.CLAUDE_ENV_FILE; delete process.env.VERCEL_PLUGIN_VALIDATED_FILES;'
Swarm-Agent: codex-posttool-validate-v2
2026-03-11 15:17:02 -06:00
John Lindquist e91067f1aa chore(hooks): drop accidental generated artifacts
Restore generated hook outputs that were accidentally committed when the
repo pre-commit hook rebuilt the entire hooks directory. This follow-up
keeps this agent's change set focused on the UserPromptSubmit source and
tests without touching the in-progress source files owned by other agents.

Verified: bun test hooks/user-prompt-submit-skill-inject.test.ts tests/user-prompt-submit.test.ts
Verified: restored generated outputs to their HEAD~1 content for six unrelated hook artifacts
Swarm-Agent: codex-prompt-hook
2026-03-11 15:17:02 -06:00
John Lindquist 1142c51906 fix(user-prompt-submit): support cursor prompt hook
Normalize UserPromptSubmit input fields across Claude Code and Cursor,
including conversation/session IDs, cwd roots, and prompt/message
fallbacks. Cursor now returns flat beforeSubmitPrompt output with
continue:true and emits seen-skill env patches when no CLAUDE_ENV_FILE is
available, while Claude continues using hookSpecificOutput and appends
seen-skill exports to CLAUDE_ENV_FILE when present.

Verified: bun test hooks/user-prompt-submit-skill-inject.test.ts tests/user-prompt-submit.test.ts
Verified: cursor beforeSubmitPrompt payload returns continue:true + env patch in tests/user-prompt-submit.test.ts
Swarm-Agent: codex-prompt-hook
2026-03-11 15:17:02 -06:00
John Lindquist 0beeedb807 chore(hooks): restore unrelated generated outputs
The local pre-commit hook rebuilt several hooks/*.mjs files from other agents' dirty source changes while I was committing the new compat layer. Restore the unrelated generated artifacts to their previous state so this task only carries the compat-layer files it owns.

Verified: bun test hooks/compat.test.ts
Swarm-Agent: codex-compat-layer
2026-03-11 15:16:27 -06:00
John Lindquist e37004a002 feat(hooks): add compat layer for cursor payloads
Add a shared Claude Code/Cursor compatibility module that normalizes hook input, formats platform-specific output, and persists session env state across both runtimes.

Verified: bun test hooks/compat.test.ts
Verified: bun x tsc --noEmit --module nodenext --moduleResolution nodenext --target es2022 --types node hooks/src/compat.mts
Swarm-Agent: codex-compat-layer
2026-03-11 15:16:27 -06:00
John Lindquist 9fdcc5c8b0 chore(pretooluse-skill-inject): restore generated bundle
The previous commit unintentionally included this compiled hook artifact because the local pre-commit hook rebuilt and auto-staged hook bundles. This restores the generated file to its prior committed state without touching the dirty source file.

Verified: tmp=/var/folders/c3/r013q3_93_s4zycmx0mdnt2h0000gn/T/tmp.2y6bxG5m6P && git show HEAD^:hooks/pretooluse-skill-inject.mjs > "" && cmp -s hooks/pretooluse-skill-inject.mjs "" && rm ""
Swarm-Agent: codex-hook-chain
2026-03-11 15:16:21 -06:00
John Lindquist 994a5431a8 fix(posttooluse-validate): dedupe skill upgrade instructions
formatOutput now emits a single skill-upgrade instruction block per target skill, adds the requested blank line and reason text, and marks hard upgrades as REQUIRED so agents get clearer follow-up actions.

Verified: bun run build:hooks
Verified: bun test tests/posttooluse-validate.test.ts
Verified: bun run typecheck
Swarm-Agent: codex-hook-chain
2026-03-11 15:16:21 -06:00
John Lindquist ab8810509e fix(hooks): drop unrelated generated injector diff
The repo pre-commit hook rebuilt hook outputs and accidentally staged a generated pretooluse injector artifact from another in-progress source change. This commit restores that generated file to its pre-commit content so the skill-upgrade change stays isolated.

Verified: diff -u <(git show HEAD^:hooks/pretooluse-skill-inject.mjs) hooks/pretooluse-skill-inject.mjs
Swarm-Agent: codex-schema
2026-03-11 15:16:21 -06:00
John Lindquist 4525723e15 feat(hooks): add skill upgrade metadata to validate rules
Validate rules can now carry optional skill-upgrade metadata from SKILL.md frontmatter through the post-tool-use validator. When a matching rule requests an upgrade, the hook output now emits both human-readable Skill tool guidance and a machine-readable HTML comment for downstream parsing.

Verified: bun run typecheck
Verified: bun -e 'const mod = await import("./hooks/src/posttooluse-validate.mts"); const violations = mod.runValidation("foo\n", ["source-skill"], new Map([["source-skill", [{ pattern: "foo", message: "needs upgrade", severity: "error", upgradeToSkill: "target-skill", upgradeWhy: "more specific context" }]] ])); const out = JSON.parse(mod.formatOutput(violations, ["source-skill"], "/tmp/test.ts")); console.log(JSON.stringify(violations)); console.log(out.hookSpecificOutput.additionalContext);'
Verified: bun -e 'const mod = await import("./hooks/src/skill-map-frontmatter.mts"); const parsed = mod.parseSkillFrontmatter(`validate:\n  -\n    pattern: foo\n    message: needs upgrade\n    severity: error\n    upgradeToSkill: target-skill\n    upgradeWhy: use the more specific skill\n  -\n    pattern: bar\n    message: hard upgrade\n    severity: warn\n    upgradeToSkill: hard-skill\n    upgradeMode: hard\n`); console.log(JSON.stringify(parsed.validate));'
Swarm-Agent: codex-schema
2026-03-11 15:16:21 -06:00
melkeydev c7a13ac307 adding telemetry 2026-03-11 09:23:07 -07:00
John Lindquist d5b5ef47f7 Replace skill body injection with Skill tool invocation instructions
Instead of injecting the full SKILL.md body as additionalContext, inject
"You must run the Skill(<name>) tool." — a more conventional way of
telling the agent to use the Skill tool for context loading.
2026-03-10 12:46:11 -06:00
John Lindquist b8b233995c feat(skills): broaden trigger patterns for 7 under-injected skills based on eval findings; add next-forge skill; bump to 0.15.0
Eval analysis of 9 real sessions showed 10 skills never triggering despite being
requested. Root causes: pathPatterns too narrow (agents write to lib/email-template.tsx
not emails/), promptSignals containing regex instead of plain text (vercel-sandbox),
and missing promptSignals entirely (v0-dev, vercel-firewall).

Skills updated: email, vercel-queues, edge-runtime, vercel-firewall, chat-sdk,
v0-dev, vercel-sandbox. New skill: next-forge (bootstrap detection).
2026-03-09 17:56:23 -06:00
John Lindquist fdef1e9ff7 fix(hooks): share invocation ids across hook logs
Hook modules were creating separate logger instances, so a single PreToolUse run could emit multiple invocationIds once hook-env catch logging fired. Reusing one process-scoped invocationId keeps all lines from one hook invocation correlated.

This also demotes internal trigger diagnostics back to debug so summary mode stays limited to complete and issue events, matching the logger contract and tests.

Verified: bun test tests/pretooluse-skill-inject.test.ts (278 tests pass)
Verified: bun test tests/logger.test.ts (12 tests pass)
Verified: bun test tests/hook-sync.test.ts -t "logger .mts/.mjs sync|pretooluse-skill-inject .mts/.mjs sync" (6 tests pass)
Swarm-Agent: codex-invocation-id-fix
2026-03-09 14:16:27 -06:00
John Lindquist 830e49c69b fix(profiler): harden CLI availability checks
Make the session-start profiler resolve binaries from PATH safely before
invoking them, cap the version-check subprocesses at 3 seconds, and
avoid crashing when npm or agent-browser is missing.

Also expand the outdated Vercel CLI guidance to include the pnpm global
upgrade path and cover the new skip/timeout behavior in profiler tests.

Verified: bun test tests/session-start-profiler.test.ts
Swarm-Agent: codex-profiler-harden-split-2-v2
2026-03-09 14:06:35 -06:00
John Lindquist f035d9afb3 fix(inject): strip YAML frontmatter from skill bodies before injection; bump to 0.11.1
Skill frontmatter (pathPatterns, bashPatterns, promptSignals, etc.)
was being injected alongside the skill body, wasting token budget on
metadata only useful for hook matching. Now uses extractFrontmatter()
to emit only the markdown body.
2026-03-09 13:43:45 -06:00
John Lindquist 7ac8edfb8f feat(skills): aggressive prompt signals for workflow/sandbox, "check the docs" directives across 8 skills; bump to 0.11.0
- workflow: add ~60 new promptSignal phrases for reliability language
  (survive page reload, fault-tolerant, retry on failure, session
  persistence, reconnect, durable chat/agent), human-in-the-loop
  patterns (approval, pause until, wait for), and pipeline vocabulary.
  Add ~25 new allOf pairs and 12 new anyOf terms.

- vercel-sandbox: add promptSignals from scratch (had none). 33 phrases
  covering isolated execution, sandbox environments, code safety,
  FFmpeg/media processing, code playgrounds, and tutor patterns.
  27 allOf pairs, 8 anyOf terms, noneOf excludes iframe/codesandbox.

- Add "CRITICAL — your training data is outdated" blockquote at the top
  of 8 fast-moving skill bodies (workflow, ai-sdk, vercel-sandbox,
  ai-gateway, chat-sdk, vercel-flags, vercel-queues, ai-elements)
  directing agents to fetch docs before writing code.

Eval results that motivated these changes:
- content-pipeline: 9/10 (workflow triggered, correct WDK patterns)
- customer-support: 3/10 → workflow never injected (now scores 50)
- code-sandbox-tutor: 1/10 → sandbox never injected (now scores 80)
2026-03-09 13:16:16 -06:00
John Lindquist 5ce557a33e feat(skills): add ai-generation-persistence and verification skills; bump to 0.10.0
New ai-generation-persistence skill (priority 6) injects guidance for treating
AI generations as first-class persistent resources — unique IDs, addressable
URLs, database/Blob storage, cost tracking, and generate-then-redirect UX
patterns. Triggers on AI SDK imports and broad prompt signals.

New verification skill added. Updated ecosystem graph, catalog, manifest,
fixtures, and snapshots.
2026-03-09 12:23:19 -06:00
John Lindquist ff965cc377 fix(skills): remove styled-jsx, regenerate catalog, add investigation-mode skill, build-from-skills templates; bump to 0.9.10 2026-03-09 11:38:08 -06:00
John Lindquist a43cb60a64 fix(skills): stronger outdated model warnings with "your knowledge is outdated" language, make AI Elements mandatory for AI text rendering; bump to 0.9.8 2026-03-09 07:59:56 -06:00
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 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 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 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 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 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 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 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 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
John Lindquist 951992bdc5 chore: bump plugin version to 0.3.6 2026-03-06 11:58:49 -07:00
John Lindquist 6f33512cb8 feat(hooks): force bootstrap skill in setup mode
PreToolUse now checks VERCEL_PLUGIN_SETUP_MODE and synthesizes a\nbootstrap match when setup mode is active, then boosts bootstrap\npriority so it injects before other matched skills on the first\nrelevant call.\n\nThe routing is dedup-safe: it skips synthetic bootstrap when the skill\nhas already been injected in seen-skills state.\n\nVerified: bun test tests/pretooluse-skill-inject.test.ts -t "setup mode bootstrap routing"\nVerified: node --check hooks/pretooluse-skill-inject.mjs\nSwarm-Agent: codex-profiler-hooks
2026-03-06 11:40:29 -07:00
John Lindquist 50c2b61ad2 chore: bump plugin version to 0.3.4
- Add greenfield project detection to session-start profiler
- Add profiler boost (+5 priority) for likely skills in PreToolUse
- Remove zzz-test-redos-pattern test skill
- Update golden fixtures and snapshots
- Add agent-browser to ecosystem graph
- Add new golden fixture tests
2026-03-06 10:36:58 -07:00
John Lindquist a5b9f7320a chore: bump plugin version to 0.3.2 2026-03-06 09:48:04 -07:00
John Lindquist 1d5f084780 Add bodyPath to skill manifest entries, golden fixture tests, fuzz tests for glob and YAML parsers, and vercel-config key routing improvements. Bump version to 0.3.0.
Update build-manifest.ts to include bodyPath in each skill manifest entry pointing to the SKILL.md file. Update all SKILL.md frontmatter across all skills to ensure consistent formatting. Add vercel-config.mjs improvements for key-aware skill routing.

Add tests/build-skill-map.test.ts for skill map construction. Add golden fixture JSON files (golden-bash-cap-collision, golden-bash-next-dev, golden-edit-middleware, golden-read-env-local, golden-read-vercel-json, golden-vercel-json-crons, golden-vercel-json-rewrites) for deterministic match engine validation. Add tests/fuzz-glob.test.ts and tests/fuzz-yaml.test.ts for property-based testing of the glob-to-regex and YAML parsers.

Update snapshot files for injection output. Update validate.ts and validate.test.ts with command convention checks. Update HOOKS.md documentation. Update pretooluse-skill-inject.mjs, skill-map-frontmatter.mjs, and vercel-config.mjs hook modules. Bump plugin.json version from 0.2.0 to 0.3.0.
2026-03-06 08:29:02 -07:00
John Lindquist 242d69f686 Extract the match/rank engine from pretooluse-skill-inject.mjs into patterns.mjs so it can be shared between the PreToolUse hook and a new CLI explain command. Add compileSkillPatterns() and rankMatches() to patterns.mjs. Refactor pretooluse-skill-inject.mjs to import and use the shared engine instead of inline matching logic.
Create hooks/vercel-config.mjs that reads vercel.json and maps top-level keys (rewrites, redirects, headers, crons, functions) to skill slugs, so skills are injected when the project uses those Vercel features.

Create hooks/logger.mjs with structured logging at four levels (off, summary, debug, trace) controlled by VERCEL_PLUGIN_LOG_LEVEL env var. Support legacy VERCEL_PLUGIN_DEBUG=1 mapping to debug level.

Create src/cli/explain.ts that takes a tool name and input JSON, runs the match engine, and prints which skills would fire and why. Create src/cli/index.ts as the CLI entry point. Create src/commands/doctor.ts for diagnosing plugin setup issues.

Create src/shared/logger.ts and src/shared/match-engine.ts as TypeScript versions of the shared utilities.

Create scripts/build-manifest.ts that reads all SKILL.md files, parses frontmatter, and generates generated/skill-manifest.json.

Add CLAUDE.md documenting the architecture, dedup contract, YAML parser quirks, test conventions, and log levels.

Add tests: tests/cli-explain.test.ts, tests/logger.test.ts, tests/vercel-config.test.ts, tests/snapshot-runner.test.ts with snapshot files in tests/snapshots/. Add test fixtures in tests/fixtures/. Update existing tests to copy new hook modules (logger.mjs, vercel-config.mjs) into temp dirs.

Update package.json with new bin entry and dependencies.
2026-03-06 06:01:17 -07:00
John Lindquist 29b0737376 fix(hooks): switch dedup from temp file to env var
The seen-skills dedup was using a temp file written via SessionStart,
but PreToolUse hooks can't update CLAUDE_ENV_FILE. This caused errors
when the temp file became stale or inaccessible across session clears.

Now VERCEL_PLUGIN_SEEN_SKILLS is a comma-delimited string stored
directly in the session environment. SessionStart initializes it as
empty, and the PreToolUse hook reads/updates process.env in-place.
2026-03-05 22:13:55 -07:00
John Lindquist f838270eac refactor(hooks): extract shared patterns module and add validation
Extract glob-to-regex and seen-skills file utilities into hooks/patterns.mjs
for reuse across the PreToolUse hook and validation script. Add
validateSkillMap to skill-map-frontmatter.mjs. Expand plugin tags for
chat-sdk/bot variants. Comprehensive tests for all new modules.
2026-03-05 20:45:14 -07:00
John Lindquist 138090762e Migrate skill triggers from skill-map.json to SKILL.md frontmatter
Replace centralized skill-map.json with frontmatter-based triggers in
each SKILL.md. Add hooks/skill-map-frontmatter.mjs to parse triggers
at runtime. Update validation, tests, and hook logic accordingly.
2026-03-05 15:35:05 -07:00
John Lindquist 753292ffd6 Create three new Vercel skills (cron-jobs, deployments-cicd, env-vars) with SKILL.md files covering setup, CLI commands, and gotchas. Harden the PreToolUse hook (hooks/pretooluse-skill-inject.mjs) by wrapping output in hookSpecificOutput, adding atomic file writes with renameSync, supporting VERCEL_PLUGIN_DEBUG env var alongside VERCEL_PLUGIN_HOOK_DEBUG, and using a safeNow() shim for performance.now compatibility. Expand skill-map.json with new trigger patterns for the added skills and broader coverage for existing ones. Rewrite and expand tests/pretooluse-skill-inject.test.ts to cover the new hook behavior, atomic writes, debug output, and deduplication logic. Add hooks/HOOKS.md documenting the hook architecture. Update vercel.md with new skill references. Add README.txt and vercel.txt with project overview and Vercel platform reference docs. Add .claude/settings.json for project-level Claude settings. 2026-03-05 08:05:14 -07:00
John Lindquist 69031ac64e chore: expand skill-map trigger coverage and refactor PreToolUse hook 2026-03-04 17:38:29 -07:00