claudeApi.ts
skills/bundled/claudeApi.ts
197
Lines
6323
Bytes
1
Exports
3
Imports
10
Keywords
What this is
This page documents one file from the repository and includes its full source so you can read it without leaving the docs site.
Beginner explanation
This file is one piece of the larger system. Its name, directory, imports, and exports show where it fits. Start by reading the exports and related files first.
How it is used
Start from the exports list and related files. Those are the easiest clues for where this file fits into the system.
Expert explanation
Architecturally, this file intersects with integrations. It contains 197 lines, 3 detected imports, and 1 detected exports.
Important relationships
Detected exports
registerClaudeApiSkill
Keywords
langcontentclaude-apireferpartspushreadmedetectedlanguagepathcleanprompt
Detected imports
fs/promises../../utils/cwd.js../bundledSkills.js
Source notes
This page embeds the full file contents. Small or leaf files are still indexed honestly instead of being over-explained.
Full source
import { readdir } from 'fs/promises'
import { getCwd } from '../../utils/cwd.js'
import { registerBundledSkill } from '../bundledSkills.js'
// claudeApiContent.js bundles 247KB of .md strings. Lazy-load inside
// getPromptForCommand so they only enter memory when /claude-api is invoked.
type SkillContent = typeof import('./claudeApiContent.js')
type DetectedLanguage =
| 'python'
| 'typescript'
| 'java'
| 'go'
| 'ruby'
| 'csharp'
| 'php'
| 'curl'
const LANGUAGE_INDICATORS: Record<DetectedLanguage, string[]> = {
python: ['.py', 'requirements.txt', 'pyproject.toml', 'setup.py', 'Pipfile'],
typescript: ['.ts', '.tsx', 'tsconfig.json', 'package.json'],
java: ['.java', 'pom.xml', 'build.gradle'],
go: ['.go', 'go.mod'],
ruby: ['.rb', 'Gemfile'],
csharp: ['.cs', '.csproj'],
php: ['.php', 'composer.json'],
curl: [],
}
async function detectLanguage(): Promise<DetectedLanguage | null> {
const cwd = getCwd()
let entries: string[]
try {
entries = await readdir(cwd)
} catch {
return null
}
for (const [lang, indicators] of Object.entries(LANGUAGE_INDICATORS) as [
DetectedLanguage,
string[],
][]) {
if (indicators.length === 0) continue
for (const indicator of indicators) {
if (indicator.startsWith('.')) {
if (entries.some(e => e.endsWith(indicator))) return lang
} else {
if (entries.includes(indicator)) return lang
}
}
}
return null
}
function getFilesForLanguage(
lang: DetectedLanguage,
content: SkillContent,
): string[] {
return Object.keys(content.SKILL_FILES).filter(
path => path.startsWith(`${lang}/`) || path.startsWith('shared/'),
)
}
function processContent(md: string, content: SkillContent): string {
// Strip HTML comments. Loop to handle nested comments.
let out = md
let prev
do {
prev = out
out = out.replace(/<!--[\s\S]*?-->\n?/g, '')
} while (out !== prev)
out = out.replace(
/\{\{(\w+)\}\}/g,
(match, key: string) =>
(content.SKILL_MODEL_VARS as Record<string, string>)[key] ?? match,
)
return out
}
function buildInlineReference(
filePaths: string[],
content: SkillContent,
): string {
const sections: string[] = []
for (const filePath of filePaths.sort()) {
const md = content.SKILL_FILES[filePath]
if (!md) continue
sections.push(
`<doc path="${filePath}">\n${processContent(md, content).trim()}\n</doc>`,
)
}
return sections.join('\n\n')
}
const INLINE_READING_GUIDE = `## Reference Documentation
The relevant documentation for your detected language is included below in \`<doc>\` tags. Each tag has a \`path\` attribute showing its original file path. Use this to find the right section:
### Quick Task Reference
**Single text classification/summarization/extraction/Q&A:**
→ Refer to \`{lang}/claude-api/README.md\`
**Chat UI or real-time response display:**
→ Refer to \`{lang}/claude-api/README.md\` + \`{lang}/claude-api/streaming.md\`
**Long-running conversations (may exceed context window):**
→ Refer to \`{lang}/claude-api/README.md\` — see Compaction section
**Prompt caching / optimize caching / "why is my cache hit rate low":**
→ Refer to \`shared/prompt-caching.md\` + \`{lang}/claude-api/README.md\` (Prompt Caching section)
**Function calling / tool use / agents:**
→ Refer to \`{lang}/claude-api/README.md\` + \`shared/tool-use-concepts.md\` + \`{lang}/claude-api/tool-use.md\`
**Batch processing (non-latency-sensitive):**
→ Refer to \`{lang}/claude-api/README.md\` + \`{lang}/claude-api/batches.md\`
**File uploads across multiple requests:**
→ Refer to \`{lang}/claude-api/README.md\` + \`{lang}/claude-api/files-api.md\`
**Agent with built-in tools (file/web/terminal) (Python & TypeScript only):**
→ Refer to \`{lang}/agent-sdk/README.md\` + \`{lang}/agent-sdk/patterns.md\`
**Error handling:**
→ Refer to \`shared/error-codes.md\`
**Latest docs via WebFetch:**
→ Refer to \`shared/live-sources.md\` for URLs`
function buildPrompt(
lang: DetectedLanguage | null,
args: string,
content: SkillContent,
): string {
// Take the SKILL.md content up to the "Reading Guide" section
const cleanPrompt = processContent(content.SKILL_PROMPT, content)
const readingGuideIdx = cleanPrompt.indexOf('## Reading Guide')
const basePrompt =
readingGuideIdx !== -1
? cleanPrompt.slice(0, readingGuideIdx).trimEnd()
: cleanPrompt
const parts: string[] = [basePrompt]
if (lang) {
const filePaths = getFilesForLanguage(lang, content)
const readingGuide = INLINE_READING_GUIDE.replace(/\{lang\}/g, lang)
parts.push(readingGuide)
parts.push(
'---\n\n## Included Documentation\n\n' +
buildInlineReference(filePaths, content),
)
} else {
// No language detected — include all docs and let the model ask
parts.push(INLINE_READING_GUIDE.replace(/\{lang\}/g, 'unknown'))
parts.push(
'No project language was auto-detected. Ask the user which language they are using, then refer to the matching docs below.',
)
parts.push(
'---\n\n## Included Documentation\n\n' +
buildInlineReference(Object.keys(content.SKILL_FILES), content),
)
}
// Preserve the "When to Use WebFetch" and "Common Pitfalls" sections
const webFetchIdx = cleanPrompt.indexOf('## When to Use WebFetch')
if (webFetchIdx !== -1) {
parts.push(cleanPrompt.slice(webFetchIdx).trimEnd())
}
if (args) {
parts.push(`## User Request\n\n${args}`)
}
return parts.join('\n\n')
}
export function registerClaudeApiSkill(): void {
registerBundledSkill({
name: 'claude-api',
description:
'Build apps with the Claude API or Anthropic SDK.\n' +
'TRIGGER when: code imports `anthropic`/`@anthropic-ai/sdk`/`claude_agent_sdk`, or user asks to use Claude API, Anthropic SDKs, or Agent SDK.\n' +
'DO NOT TRIGGER when: code imports `openai`/other AI SDK, general programming, or ML/data-science tasks.',
allowedTools: ['Read', 'Grep', 'Glob', 'WebFetch'],
userInvocable: true,
async getPromptForCommand(args) {
const content = await import('./claudeApiContent.js')
const lang = await detectLanguage()
const prompt = buildPrompt(lang, args, content)
return [{ type: 'text', text: prompt }]
},
})
}