claude/skills/javascript/SKILL.md
Node.js and JavaScript development patterns, gotchas, and library compatibility notes. Use when working with Node.js projects, TypeScript, React, antd, Zustand, Playwright, Bun, or Vitest.
npx skillsauth add lanej/dotfiles javascriptInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
package.json first to understand available scripts before running anythingnpm install before attempting to execute Node.js scripts in a new project@lobehub/ui and antd-style bundle Zustand 3.x internally. Mixing them with Zustand 5 crashes every state update with:
TypeError: h.use is not a function
Fix: NEVER import @lobehub/ui or antd-style in projects using Zustand 5. Use antd + theme.useToken() instead.
Check before adding LobeHub deps:
find node_modules -path '*antd-style*zustand*'
page.fill() does NOT trigger React onChange on antd TextArea components.
Fix: Use page.type() instead:
// ❌ Broken with antd TextArea
await page.fill('textarea', 'my text');
// ✅ Works
await page.type('textarea', 'my text');
bun:sqlite is a Bun built-in unavailable in Node.js/Vitest. Tests using it must run via bun test.
Fix: Exclude from Vitest:
// vitest.config.ts
export default {
test: {
exclude: ['**/sqlite-session-store.test.ts']
}
}
When implementing Claude SSE streaming in a frontend:
Set isStreaming: false as the FIRST operation in the done handler — before appending the assembled message — so the UI re-enables input even if message assembly throws:
// ✅ Correct order
eventSource.addEventListener('done', () => {
set({ isStreaming: false }); // ← FIRST: re-enable UI
appendMessage(assembleMessage()); // ← then handle message
});
Safety net: After the read loop exits, add a fallback in case the done branch was skipped:
if (get().isStreaming) set({ isStreaming: false });
Claude SSE output is interleaved, not strictly sequential:
thinking block (once) → [text chunks ↔ tool_use/tool_result cycles]
Store a segments: MessageSegment[] array and flush the text buffer on each tool_use event to preserve interleave order in the rendered UI.
When building a Node.js client that connects to stdio MCP servers (pkm, memory):
Use StdioClientTransport from @modelcontextprotocol/sdk/client/stdio.js and create the transport once at app startup, not per-request:
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
// ✅ Create once at startup
const transport = new StdioClientTransport({ command: 'pkm', args: ['mcp'] });
const client = new Client({ name: 'my-app', version: '1.0' }, { capabilities: {} });
await client.connect(transport);
transport.onclose = () => sessions.delete(name);
// Re-create on next access — don't pre-spawn
Always spread process.env first so the child inherits PATH and critical env vars:
new StdioClientTransport({
command: 'pkm',
args: ['mcp'],
env: { ...process.env, ...server.env } // ← process.env FIRST
});
data-ai
Delegate research and context-gathering tasks to a sub-agent to protect the primary context window. Use when the user asks to "research X", "look into X", "find out about X", "gather context on X", or any investigative framing where answering requires 2+ searches or multiple sources. Also use proactively before starting substantive work when prior context is unknown. Never run research inline — always delegate.
documentation
--- name: qmd-math description: Math notation conventions for Quarto/EPQ documents rendered via lualatex. Use when: writing or adding a formula, equation, or mathematical expression to a .qmd file; asked about display math, inline math, or LaTeX notation in a QMD/Quarto context; defining a where-clause or variable definitions for an equation; converting prose variable descriptions into structured math notation; fixing math that renders badly in a PDF; using \lvert, \begin{aligned}, \tfrac, \text
development
Trim a prose document (README, design doc, blog post, notes) for readability by cutting redundancy, filler, and dead weight in the author's own words. Invoke with /trim [file path], or /trim alone to be prompted for a file. Not for source code, data files, or summarization.
business
Query and analyze Josh Lane's org headcount from the staffing DuckDB at ~/workspace/areas/staffing/staffing.duckdb. Use when asked about headcount counts, org structure, direct reports, team breakdown, hiring/attrition trends, international employees, salary/pay grade distribution, offboarding lag, or any question about people in Josh's org. Triggers on questions about how many people, who reports to whom, headcount by team/country/level, who joined or left, org size, staffing, headcount trend.