js-index
Build the interprocedural callgraph + framework detection + tag table for an exploded source tree by calling the tlx MCP js_index_target tool. Run after rag-ingest when status.json.phases.index is mis
SKILL.md.claude/skills/js-index/SKILL.md
GitHubjs-index
Purpose
Run TLX's js_index_target against targets/<name>/sources/ and
persist the resulting graph artifacts inside the target dir so they're
versioned alongside the target's other state.
Inputs
targets/<name>/sources/**(output ofsourcemap-explode).
Steps
- Call the MCP tool:
js_index_target(target_folder="targets/<name>/sources/") - The tool persists the callgraph in TLX's own SQLite/Chroma at
~/.tlx/. We additionally export a copy into the target dir so each engagement is self-contained. - After success, mirror the artifacts into
targets/<name>/index/:index/nodes.jsonl—{qname, file, line, kind, framework_tag}index/edges.jsonl—{caller_qname, callee_qname, edge_kind}index/frameworks.json— detected frameworks + versionsindex/tags.jsonl— source/sink/sanitizer tags Usebin/export_index.pywith a--db <per-target.db>flag pointing at the snapshot produced bybin/db-isolate.py snapshot ...(perCLAUDE.md). Never let it default to the global~/.tlx/js_analyzer.db.
- jsluice tag layer (T1.4). Run:
Wraps the BishopFoxpython3 bin/run_jsluice.py targets/<name>jsluicebinary (install:go install github.com/BishopFox/jsluice/cmd/jsluice@latest). Extracts URL skeletons (withEXPRplaceholders flaggedseverity=medium, kindurl_skeleton) and secrets (severity per secret kind), maps each finding to the innermost containing node, inserts rows intonode_tagswithsource='jsluice', writes a raw audit trail toindex/jsluice.jsonl, and drafts a per-secret finding stub underfindings/jsluice_secret_<id>/draft.json(auto_submit: false,requires_user_review: true). Ifjsluiceis missing, the script writesstatus: skippedand exits 0 — does not fail the pipeline. - Build-manifest extractor (T2.3). Run:
Parses Next.js (python3 bin/build_manifest_extract.py targets/<name>_buildManifest.js,routes-manifest.json), Vite (manifest.json), Rspack (rspack.client.json), and CRA (asset-manifest.json) build manifests underraw/to enumerate SPA routes — including hidden admin paths the live crawl missed. Writesindex/routes.jsonl(one route per line). Hand the new routes back tojs-harvest(loop step 1 over each route as a navigation seed) to widen the JS asset surface. - Stamp
status.json.phases.indexwith counts.
Outputs
targets/<name>/index/{nodes,edges,tags}.jsonltargets/<name>/index/frameworks.jsontargets/<name>/index/jsluice.jsonl(Step 4)targets/<name>/findings/jsluice_secret_<id>/draft.json(Step 4)targets/<name>/index/routes.jsonl(Step 5, when implemented)
Failure modes
js_index_targetreturns zero nodes → almost always framework misdetection. Setsession_kv_set("target_<name>:framework_override", "<react|vue|...>")via the TLX UI or a one-off Python call (MCP exposes onlysession_kv_geton purpose); re-index.- AST parser chokes on a file → it's logged inside TLX; we surface
index/_skipped.jsonso the user knows the coverage gap. run_jsluice.pyreports manytags_orphanfindings → file paths emitted by jsluice don't matchnodes.fileconventions. Inspectresult.orphan_files_sampleto see what jsluice produced; usually fixed by re-running aftersourcemap-explodepopulatessources/.run_jsluice.pyexits 3 (per-target DB missing) → runbin/db-isolate.py snapshot targets/<name> <host>/first.
Result block
"phases": {
"index": { "status": "done", "ts": "<iso>",
"nodes": N, "edges": E, "tags": T, "frameworks": [...] },
"jsluice": { "status": "done|skipped", "ts": "<iso>",
"files_scanned": N, "urls_found": N, "url_skeletons": N,
"secrets_found": N, "tags_inserted": N, "tags_duplicate": N,
"tags_orphan": N, "secret_drafts_written": N,
"audit_file": "index/jsluice.jsonl" }
}