analyze-cc-feature — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited analyze-cc-feature (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Reverse engineer a specific feature in Claude Code's source code.
Terminology note: Claude Code's cli.js is minified (whitespace removed, identifiers shortened for size), NOT obfuscated (intentionally made hard to read with control flow flattening, string encryption, etc.). webcrack's --no-deobfuscate flag is used because there is no obfuscation to reverse. The output file is called deobfuscated.js by webcrack convention, but it is more accurately "unminified" source.
IMPORTANT: Use the task list (TaskCreate/TaskUpdate) to track progress through the pipeline. Create all tasks upfront, then work through them sequentially, marking each in_progress when starting and completed when done.
Create these tasks at the start:
If the user says to skip steps (e.g., "unminified source already exists at X, skip steps 1-2"), create those tasks as completed immediately.
Run scripts/extract-cli.sh to extract cli.js from the installed native binary. The script caches by version.
bash ~/.claude/skills/analyze-cc-feature/scripts/extract-cli.shImportant — the source is no longer in the npm package. Since v2.1.113 the npm package (@anthropic-ai/claude-code) is a ~170 KB thin installer; the real CLI ships as a per-platform native Bun standalone executable (~250 MB) with the JavaScript embedded in its module graph. extract-cli.sh locates the installed binary (~/.local/share/claude/versions/<version> or $(which claude)) and runs scripts/extract-bun-cli.py to pull cli.js out of the binary's module graph. It also drops the sibling modules (a precompiled Bun bytecode blob and two Rust NAPI addons — image-processor.node, audio-capture.node) into /tmp/claude-code-npm/bun-modules/.
This produces /tmp/claude-code-npm/package/cli.js (~18 MB). See REFERENCE.md for the binary format details if you need to adapt the extractor to a new layout.
Run scripts/unminify.sh to produce readable source. The script caches the output.
bash ~/.claude/skills/analyze-cc-feature/scripts/unminify.shThis produces webcrack-output/deobfuscated.js (~965K lines for 2.1.201, well-formatted). Despite the filename, this is unminified code — see terminology note above.
The script runs webcrack with `--no-jsx`. On today's ~18 MB bundle the JSX-decompile pass takes ~50 min, needs 4 GB+ RAM, and currently emits output Prettier can't reparse. Skipping it costs only verbose createElement(...) + React memo-cache boilerplate (mechanical to read — see the React/Ink section). If you specifically need decompiled JSX for a UI feature, run the JSX pass separately on the extracted module (a few thousand lines) rather than the whole bundle.
Search the unminified source for the feature keyword the user specified. Use multiple anchor strings:
"insights", "compact")querySource: values that tag API calls"tengu_compact", "tengu_input_command")Use Grep to find all occurrences and identify the line range where the feature's code is concentrated. Search for at least 3-4 different anchor strings to triangulate.
Read the identified line range from the unminified file. Read in large chunks (500+ lines) to see full boundaries. Also search for any helper functions called from within the range that are defined elsewhere (API call wrappers, model selectors, data loaders, prompt builders).
Save an annotated file as {feature}-annotated.js (or {feature}-raw.js + {feature}-clean.js if producing both raw and renamed versions) that contains:
deobfuscated.js (e.g., // deobfuscated.js:554320)Renaming technique:
.filter() is likely an item)new Map() and used with .get()/.set() with session IDs is a session map)Rules:
/* uncertain */ comments$ or _ in functions with template literals (conflicts with ${...})Scoping strategy: Find the v(() => { ... }) lazy initializer that sets up the feature's module. All functions between this initializer and the next one belong to the same module. For local-jsx commands, also trace the load: → module → call export chain to find the entry-point component, then include all components it renders.
Read the annotated code and document:
Produce a markdown report with:
deobfuscated.js:NNNNN)After completing the analysis, evaluate the skill itself (this file + REFERENCE.md):
If improvements are warranted, propose specific edits to this SKILL.md or REFERENCE.md and ask the user if they'd like to apply them. Not every analysis will produce skill updates — only suggest changes when they'd concretely help future analyses.
Commands have different type values that affect how to analyze them:
getPromptForCommand. These are pipeline-style features (like /insights) with procedural logic.{ call: entryFunction } which is invoked directly. The return value determines what happens (e.g., type: "compact" replaces the entire conversation). Examples: /compact, /clear, /copy.load: which returns a module with a call export. These are UI-heavy features (like /usage) built as component trees.For local-jsx commands, the extraction strategy differs — see the React/Ink section below.
The dispatch function (mangled name changes per version) matches on command.type:
"local" — Calls (await command.load()).call(args, toolUseContext) and handles the return type ("compact", "skip", or plain value)"local-jsx" — Same load pattern, but the result is rendered as JSX"prompt" — Calls command.getPromptForCommand(args, context) and injects the result as messagesNew field to expect (2.1.201): `thinClientDispatch`. Command objects now carry a thinClientDispatch tag ("post-text", "control-request", …) that routes the command when the session is being driven by a thin client / remote control instead of the local TUI. "control-request" commands (e.g. /context, /usage) can be answered by the remote side via a control request rather than local execution. Many former built-in commands are now skills loaded from SKILL.md files (e.g. /code-review, /simplify), so if you can't find a command in the built-in registry, check the bundled/loaded skills.
Many features render UI using React (via Ink for terminal). Key patterns:
createElement calls, props, children).v(() => { ... }) lazy initializers. All functions between two initializers typically belong to the same module.f is Ink's <Text> component. I is Ink's <Box> (layout container).See the Mangled identifier reference table in REFERENCE.md for the full list of known infrastructure functions (telemetry, settings, token counting, hooks, etc.) with their call signatures and stable evidence patterns for re-identification across versions.
querySource field in API call options tags which feature is making the call.v(() => { ... }) pattern is a lazy initializer — code inside runs once on first access.type: "prompt", name, description, getPromptForCommand, or type: "local-jsx" / type: "local" with load:.local-jsx commands, trace the load: function to find the module, then find its call export to locate the entry point.deobfuscated.js:NNNNN for traceability.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.