run() — dead-code-hunter Function Reference
Architecture documentation for the run() function in index.ts from the dead-code-hunter codebase.
Entity Profile
Dependency Diagram
graph TD 2707a308_9fa9_efa8_2fbd_febf984897e5["run()"] e9e74cdc_be9b_7bf4_8d35_36946c34cb62["createZipArchive()"] 2707a308_9fa9_efa8_2fbd_febf984897e5 -->|calls| e9e74cdc_be9b_7bf4_8d35_36946c34cb62 d58f9df4_f889_6148_ffb9_17e807228538["generateIdempotencyKey()"] 2707a308_9fa9_efa8_2fbd_febf984897e5 -->|calls| d58f9df4_f889_6148_ffb9_17e807228538 110ea7f3_8de2_f010_244b_fee04cd36588["pollForResult()"] 2707a308_9fa9_efa8_2fbd_febf984897e5 -->|calls| 110ea7f3_8de2_f010_244b_fee04cd36588 06636363_5986_b74f_155b_e1b4310ee84a["filterByIgnorePatterns()"] 2707a308_9fa9_efa8_2fbd_febf984897e5 -->|calls| 06636363_5986_b74f_155b_e1b4310ee84a 54526593_a8f4_ba9f_228e_754b8aa089c8["getChangedFiles()"] 2707a308_9fa9_efa8_2fbd_febf984897e5 -->|calls| 54526593_a8f4_ba9f_228e_754b8aa089c8 73125a5b_e60f_fe3f_510e_f54d8809eb51["filterByChangedFiles()"] 2707a308_9fa9_efa8_2fbd_febf984897e5 -->|calls| 73125a5b_e60f_fe3f_510e_f54d8809eb51 36781569_21cd_f406_4e3c_4e1ebae94da9["formatPrComment()"] 2707a308_9fa9_efa8_2fbd_febf984897e5 -->|calls| 36781569_21cd_f406_4e3c_4e1ebae94da9 d8391dca_c2e7_cb94_03ef_2b8ad084cde7["safeSerialize()"] 2707a308_9fa9_efa8_2fbd_febf984897e5 -->|calls| d8391dca_c2e7_cb94_03ef_2b8ad084cde7 e9f67350_005a_e85e_cb5a_a57d13ad57ef["redactSensitive()"] 2707a308_9fa9_efa8_2fbd_febf984897e5 -->|calls| e9f67350_005a_e85e_cb5a_a57d13ad57ef style 2707a308_9fa9_efa8_2fbd_febf984897e5 fill:#6366f1,stroke:#818cf8,color:#fff
Relationship Graph
Source Code
src/index.ts lines 191–367
async function run(): Promise<void> {
try {
const apiKey = core.getInput('supermodel-api-key', { required: true }).trim();
if (!apiKey.startsWith('smsk_')) {
core.warning('API key format looks incorrect. Get your key at https://dashboard.supermodeltools.com');
}
const commentOnPr = core.getBooleanInput('comment-on-pr');
const failOnDeadCode = core.getBooleanInput('fail-on-dead-code');
const ignorePatterns: string[] = JSON.parse(core.getInput('ignore-patterns') || '[]');
const workspacePath = process.env.GITHUB_WORKSPACE || process.cwd();
core.info('Dead Code Hunter starting...');
// Step 1: Create zip archive
const zipPath = await createZipArchive(workspacePath);
// Step 2: Generate idempotency key
const idempotencyKey = await generateIdempotencyKey(workspacePath);
// Step 3: Call Supermodel dead code analysis API
core.info('Analyzing codebase with Supermodel...');
const config = new Configuration({
basePath: process.env.SUPERMODEL_BASE_URL || 'https://api.supermodeltools.com',
apiKey: apiKey,
});
const api = new DefaultApi(config);
const zipBuffer = await fs.readFile(zipPath);
const zipBlob = new Blob([zipBuffer], { type: 'application/zip' });
const result = await pollForResult(api, idempotencyKey, zipBlob);
// Step 4: Apply client-side ignore patterns
let candidates = filterByIgnorePatterns(result.deadCodeCandidates, ignorePatterns);
// Step 5: Scope to PR diff when running on a pull request
const token = core.getInput('github-token') || process.env.GITHUB_TOKEN;
let changedFiles: Set<string> | null = null;
if (github.context.payload.pull_request && token) {
changedFiles = await getChangedFiles(token);
if (changedFiles) {
const totalBeforeScoping = candidates.length;
candidates = filterByChangedFiles(candidates, changedFiles);
core.info(`Scoped to PR: ${candidates.length} findings in changed files (${totalBeforeScoping} total across repo, ${changedFiles.size} files in PR)`);
}
}
core.info(`Found ${candidates.length} potentially unused code elements (${result.metadata.totalDeclarations} declarations analyzed)`);
core.info(`Analysis method: ${result.metadata.analysisMethod}`);
core.info(`Alive: ${result.metadata.aliveCode}, Entry points: ${result.entryPoints.length}, Root files: ${result.metadata.rootFilesCount ?? 'n/a'}`);
for (const dc of candidates) {
core.info(` [${dc.confidence}] ${dc.type} ${dc.name} @ ${dc.file}:${dc.line} — ${dc.reason}`);
}
// Step 6: Set outputs
core.setOutput('dead-code-count', candidates.length);
core.setOutput('dead-code-json', JSON.stringify(candidates));
// Step 7: Post PR comment if enabled
if (commentOnPr && github.context.payload.pull_request) {
if (token) {
const octokit = github.getOctokit(token);
const comment = formatPrComment(candidates, result.metadata);
await octokit.rest.issues.createComment({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
issue_number: github.context.payload.pull_request.number,
body: comment,
});
core.info('Posted findings to PR');
} else {
core.warning('GITHUB_TOKEN not available, skipping PR comment');
}
}
// Step 8: Clean up
await fs.unlink(zipPath);
// Step 9: Fail if configured and dead code found
if (candidates.length > 0 && failOnDeadCode) {
core.setFailed(`Found ${candidates.length} potentially unused code elements`);
}
} catch (error: any) {
core.info('--- Error Debug Info ---');
core.info(`Error type: ${error?.constructor?.name ?? 'unknown'}`);
core.info(`Error message: ${error?.message ?? 'no message'}`);
core.info(`Error name: ${error?.name ?? 'no name'}`);
try {
if (error?.response) {
core.info(`Response status: ${error.response.status ?? 'unknown'}`);
core.info(`Response statusText: ${error.response.statusText ?? 'unknown'}`);
core.info(`Response data: ${safeSerialize(error.response.data)}`);
core.debug(`Response headers: ${safeSerialize(redactSensitive(error.response.headers))}`);
}
if (error?.body) {
core.info(`Error body: ${safeSerialize(error.body)}`);
}
if (error?.status) {
core.info(`Error status: ${error.status}`);
}
if (error?.statusCode) {
core.info(`Error statusCode: ${error.statusCode}`);
}
if (error?.cause) {
core.debug(`Error cause: ${safeSerialize(error.cause)}`);
}
} catch {
core.debug('Failed to serialize some error properties');
}
core.info('--- End Debug Info ---');
let errorMessage = 'An unknown error occurred';
let helpText = '';
const status = error?.response?.status || error?.status || error?.statusCode;
let apiMessage = '';
try {
apiMessage =
error?.response?.data?.message ||
error?.response?.data?.error ||
error?.response?.data ||
error?.body?.message ||
error?.body?.error ||
error?.message ||
'';
if (typeof apiMessage !== 'string') {
apiMessage = safeSerialize(apiMessage, 500);
}
} catch {
apiMessage = '';
}
if (status === 401) {
errorMessage = 'Invalid API key';
helpText = 'Get your key at https://dashboard.supermodeltools.com';
} else if (status === 500) {
errorMessage = apiMessage || 'Internal server error';
if (apiMessage.includes('Nested archives')) {
helpText = 'Your repository contains nested archive files (.zip, .tar, etc.). ' +
'Add them to .gitattributes with "export-ignore" to exclude from analysis. ' +
'Example: tests/fixtures/*.zip export-ignore';
} else if (apiMessage.includes('exceeds maximum')) {
helpText = 'Your repository or a file within it exceeds size limits. ' +
'Consider excluding large files using .gitattributes with "export-ignore".';
}
} else if (status === 413) {
errorMessage = 'Repository archive too large';
helpText = 'Reduce archive size by excluding large files in .gitattributes';
} else if (status === 429) {
errorMessage = 'Rate limit exceeded';
helpText = 'Please wait before retrying';
} else if (status) {
errorMessage = apiMessage || `API error (${status})`;
} else {
errorMessage = apiMessage || error?.message || 'An unknown error occurred';
}
core.error(`Error: ${errorMessage}`);
if (helpText) {
core.error(`Help: ${helpText}`);
}
core.setFailed(errorMessage);
}
}
Domain
Subdomains
Calls
Source
Frequently Asked Questions
What does run() do?
run() is a function in the dead-code-hunter codebase.
What does run() call?
run() calls 9 function(s): createZipArchive, filterByChangedFiles, filterByIgnorePatterns, formatPrComment, generateIdempotencyKey, getChangedFiles, pollForResult, redactSensitive, and 1 more.
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free