@aida-dev/cli 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +20 -18
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -109,10 +109,10 @@ function createCollectCommand() {
|
|
|
109
109
|
const outputPath = join(config.outDir, "commit-stream.json");
|
|
110
110
|
await writeJSON(outputPath, commitStream);
|
|
111
111
|
logger.info(`Collected ${commitStream.commits.length} commits`);
|
|
112
|
-
const counts = { ai: 0, human: 0, unknown: 0 };
|
|
112
|
+
const counts = { ai: 0, human: 0, automated: 0, unknown: 0 };
|
|
113
113
|
for (const c of commitStream.commits) counts[c.tags.attribution]++;
|
|
114
114
|
logger.info(
|
|
115
|
-
`Attribution: ai ${counts.ai} \xB7 human ${counts.human} \xB7 unknown ${counts.unknown}`
|
|
115
|
+
`Attribution: ai ${counts.ai} \xB7 human ${counts.human} \xB7 automated ${counts.automated} \xB7 unknown ${counts.unknown}`
|
|
116
116
|
);
|
|
117
117
|
logger.info(`Output written to: ${outputPath}`);
|
|
118
118
|
} catch (error) {
|
|
@@ -171,14 +171,13 @@ function createAnalyzeCommand() {
|
|
|
171
171
|
await writeJSON2(outputPath, metrics);
|
|
172
172
|
const a = metrics.attribution;
|
|
173
173
|
logger.info(
|
|
174
|
-
`Attribution coverage: ${(a.coverage * 100).toFixed(1)}% (ai: ${a.ai}, human: ${a.human}, unknown: ${a.unknown})`
|
|
174
|
+
`Attribution coverage: ${(a.coverage * 100).toFixed(1)}% (ai: ${a.ai}, human: ${a.human}, automated: ${a.automated}, unknown: ${a.unknown})`
|
|
175
175
|
);
|
|
176
176
|
if (a.belowThreshold) {
|
|
177
177
|
logger.warn(
|
|
178
178
|
`Coverage is below ${(a.coverageThreshold * 100).toFixed(0)}%: metrics are low-confidence. Tag AI commits or set defaultAttribution.`
|
|
179
179
|
);
|
|
180
180
|
}
|
|
181
|
-
logger.info(`Merge ratio: ${(metrics.mergeRatio.mergeRatio * 100).toFixed(1)}%`);
|
|
182
181
|
logger.info(`Average persistence: ${metrics.persistence.avgDays} days`);
|
|
183
182
|
if (!metrics.baseline) {
|
|
184
183
|
logger.warn("No baseline cohort: no commits attributed as human (see caveats).");
|
|
@@ -202,14 +201,13 @@ function formatDelta(value, suffix) {
|
|
|
202
201
|
return `${sign}${value}${suffix}`;
|
|
203
202
|
}
|
|
204
203
|
function generateMarkdownReport(metrics) {
|
|
205
|
-
const mergeRatioPct = (metrics.mergeRatio.mergeRatio * 100).toFixed(1);
|
|
206
204
|
const a = metrics.attribution;
|
|
207
205
|
const coveragePct = (a.coverage * 100).toFixed(1);
|
|
208
206
|
const unknownPct = a.commitsTotal > 0 ? (a.unknown / a.commitsTotal * 100).toFixed(1) : "0.0";
|
|
209
207
|
const coverageWarning = a.belowThreshold ? `
|
|
210
208
|
> \u26A0\uFE0F **Coverage is below ${(a.coverageThreshold * 100).toFixed(0)}%.** Most of this history has unknown provenance: every metric below is low-confidence. Tag AI commits (trailers, \`[AI]\`) or set \`defaultAttribution\` in \`.aida.json\`.
|
|
211
209
|
` : "";
|
|
212
|
-
const priorNote = a.defaultAttribution !== "unknown" ? `
|
|
210
|
+
const priorNote = a.defaultAttribution !== "unknown" && a.unknown > 0 ? `
|
|
213
211
|
Unattributed commits are **assumed \`${a.defaultAttribution}\`** via \`defaultAttribution\` \u2014 this is a prior, not observed data.
|
|
214
212
|
` : "";
|
|
215
213
|
const baselineLabel = metrics.baseline?.assumed ? "Human baseline (assumed)" : "Human baseline";
|
|
@@ -217,8 +215,7 @@ Unattributed commits are **assumed \`${a.defaultAttribution}\`** via \`defaultAt
|
|
|
217
215
|
|
|
218
216
|
| Metric | AI commits | ${baselineLabel} | Delta |
|
|
219
217
|
|---|---:|---:|---:|
|
|
220
|
-
| Commits | ${metrics.
|
|
221
|
-
| Merge ratio | ${mergeRatioPct}% | ${(metrics.baseline.mergeRatio.mergeRatio * 100).toFixed(1)}% | ${formatDelta(Math.round(metrics.delta.mergeRatio * 1e3) / 10, " pp")} |
|
|
218
|
+
| Commits | ${metrics.persistence.commitsConsidered} | ${metrics.baseline.persistence.commitsConsidered} | \u2014 |
|
|
222
219
|
| Avg persistence (days) | ${metrics.persistence.avgDays} | ${metrics.baseline.persistence.avgDays} | ${formatDelta(metrics.delta.avgPersistenceDays, "")} |
|
|
223
220
|
| Median persistence (days) | ${metrics.persistence.medianDays} | ${metrics.baseline.persistence.medianDays} | ${formatDelta(metrics.delta.medianPersistenceDays, "")} |
|
|
224
221
|
` : `## AI vs Baseline
|
|
@@ -244,10 +241,20 @@ Persistence comparisons are only meaningful between cohorts of similar **age** a
|
|
|
244
241
|
| Median age (days) | ${aiCtx.age?.medianAgeDays ?? "\u2014"} | ${baseCtx.age?.medianAgeDays ?? "\u2014"} |
|
|
245
242
|
${categories.map((cat) => `| Files: ${cat} | ${mixCell(aiCtx.taskMix, cat)} | ${mixCell(baseCtx.taskMix, cat)} |`).join("\n")}
|
|
246
243
|
`;
|
|
244
|
+
const modeOrder = ["agent", "assisted", "autocomplete", "none", "unknown"];
|
|
245
|
+
const modeRows = modeOrder.map((mode) => ({ mode, stats: metrics.byMode[mode] })).filter((row) => row.stats !== null).map(
|
|
246
|
+
({ mode, stats }) => `| ${mode} | ${stats.commits} | ${stats.persistence.avgDays} | ${stats.persistence.medianDays} | ${stats.persistence.censored} |`
|
|
247
|
+
);
|
|
248
|
+
const byModeSection = modeRows.length > 0 ? `## By Autonomy Level
|
|
249
|
+
|
|
250
|
+
The comparison that stays meaningful when everything is AI-assisted: how code holds up per autonomy level (automated commits excluded).
|
|
251
|
+
|
|
252
|
+
| Mode | Commits | Avg persistence (d) | Median (d) | Surviving |
|
|
253
|
+
|---|---:|---:|---:|---:|
|
|
254
|
+
${modeRows.join("\n")}
|
|
255
|
+
|
|
256
|
+
` : "";
|
|
247
257
|
const baselineDetail = metrics.baseline ? `## ${baselineLabel}
|
|
248
|
-
- Commits (total): ${metrics.baseline.mergeRatio.commitsTotal}
|
|
249
|
-
- Commits merged: ${metrics.baseline.mergeRatio.commitsMerged}
|
|
250
|
-
- **Merge Ratio:** ${(metrics.baseline.mergeRatio.mergeRatio * 100).toFixed(1)}%
|
|
251
258
|
- Persistence \u2014 commits considered: ${metrics.baseline.persistence.commitsConsidered}, avg: ${metrics.baseline.persistence.avgDays}d, median: ${metrics.baseline.persistence.medianDays}d
|
|
252
259
|
|
|
253
260
|
` : "";
|
|
@@ -260,17 +267,12 @@ ${categories.map((cat) => `| Files: ${cat} | ${mixCell(aiCtx.taskMix, cat)} | ${
|
|
|
260
267
|
|
|
261
268
|
## Attribution Coverage
|
|
262
269
|
|
|
263
|
-
**${coveragePct}% of commits have known provenance** \u2014 ai: ${a.ai} \xB7 human: ${a.human} \xB7 unknown: ${a.unknown} (${unknownPct}%)
|
|
270
|
+
**${coveragePct}% of commits have known provenance** \u2014 ai: ${a.ai} \xB7 human: ${a.human} \xB7 automated: ${a.automated} \xB7 unknown: ${a.unknown} (${unknownPct}%)
|
|
264
271
|
|
|
265
272
|
**Autonomy:** agent ${a.modes.agent} \xB7 assisted ${a.modes.assisted} \xB7 autocomplete ${a.modes.autocomplete} \xB7 none ${a.modes.none} \xB7 unknown ${a.modes.unknown} \u2014 evidence: declared ${a.modeEvidence.declared} / inferred ${a.modeEvidence.inferred} / none ${a.modeEvidence.none}
|
|
266
273
|
${coverageWarning}${priorNote}
|
|
267
274
|
${comparisonSection}
|
|
268
|
-
${fairnessSection}
|
|
269
|
-
## Merge Ratio
|
|
270
|
-
- AI-tagged commits (total): ${metrics.mergeRatio.aiCommitsTotal}
|
|
271
|
-
- AI-tagged commits merged: ${metrics.mergeRatio.aiCommitsMerged}
|
|
272
|
-
- **Merge Ratio:** ${mergeRatioPct}%
|
|
273
|
-
|
|
275
|
+
${byModeSection}${fairnessSection}
|
|
274
276
|
## Persistence (file-level survival)
|
|
275
277
|
- Commits considered: ${metrics.persistence.commitsConsidered}
|
|
276
278
|
- Files measured: ${metrics.persistence.filesConsidered} (${metrics.persistence.censored} still surviving at collection time; ${metrics.persistence.filesExcluded} excluded: migrations/generated)
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/collect.ts","../src/schema/config.ts","../src/providers/pr-base.ts","../src/commands/analyze.ts","../src/commands/report.ts","../src/commands/comment.ts","../src/providers/github.ts","../src/providers/detect.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { createCollectCommand } from './commands/collect.js';\nimport { createAnalyzeCommand } from './commands/analyze.js';\nimport { createReportCommand } from './commands/report.js';\nimport { createCommentCommand } from './commands/comment.js';\n\nconst program = new Command();\n\nprogram\n .name('aida')\n .description('AIDA (AI Development Accounting) - Metrics for AI-assisted development')\n .version('0.0.0');\n\n// Add commands\nprogram.addCommand(createCollectCommand());\nprogram.addCommand(createAnalyzeCommand());\nprogram.addCommand(createReportCommand());\nprogram.addCommand(createCommentCommand());\n\nprogram.parse();\n","import { Command } from 'commander';\nimport { collectCommits, writeJSON, createLogger, AidaConfig } from '@aida-dev/core';\nimport { join } from 'path';\nimport { readFile } from 'fs/promises';\nimport { CLIConfig } from '../schema/config.js';\nimport { detectPRBaseRef } from '../providers/pr-base.js';\n\nasync function loadAidaConfig(repoPath: string): Promise<Partial<AidaConfig>> {\n try {\n const raw = await readFile(join(repoPath, '.aida.json'), 'utf-8');\n return AidaConfig.parse(JSON.parse(raw));\n } catch {\n return {};\n }\n}\n\nfunction collectRepeatable(value: string, previous: string[]): string[] {\n return previous ? [...previous, value] : [value];\n}\n\nexport function createCollectCommand(): Command {\n return new Command('collect')\n .description('Collect commits and generate commit-stream.json')\n .option('--repo <path>', 'Repository path', process.cwd())\n .option('--since <date>', 'Start date (ISO or relative like 90d)')\n .option('--until <date>', 'End date (ISO or relative)')\n .option('--pr', 'PR-scoped analysis (auto-detect base ref from CI env vars)')\n .option('--diff-base <ref>', 'Explicit base ref for PR-scoped analysis (e.g., origin/main)')\n .option('--ai-pattern <pattern>', 'AI detection regex (repeatable)', collectRepeatable, [])\n .option('--ai-tool <name>', 'Additional AI tool name (repeatable)', collectRepeatable, [])\n .option('--ai-trailer-domain <domain>', 'Additional Co-authored-by domain (repeatable)', collectRepeatable, [])\n .option('--ai-bot-blocklist <name>', 'Non-AI bot to exclude from trailer matching (repeatable)', collectRepeatable, [])\n .option('--default-branch <name>', 'Default branch name')\n .option('--out-dir <path>', 'Output directory', './aida-output')\n .option('--verbose', 'Verbose logging', false)\n .action(async (options) => {\n // Commander uses singular camelCase (--ai-tool → aiTool), schema uses plural\n const mapped = {\n ...options,\n aiPatterns: options.aiPattern || [],\n aiTools: options.aiTool || [],\n aiTrailerDomains: options.aiTrailerDomain || [],\n aiBotBlocklist: options.aiBotBlocklist || [],\n };\n const config = CLIConfig.parse(mapped);\n const logger = createLogger(config.verbose);\n\n try {\n // Load .aida.json config (merge with CLI flags)\n const fileConfig = await loadAidaConfig(config.repo);\n const aiPatterns = [...(fileConfig.patterns || []), ...config.aiPatterns];\n const aiTools = [...(fileConfig.tools || []), ...config.aiTools];\n const aiTrailerDomains = [...(fileConfig.trailerDomains || []), ...config.aiTrailerDomains];\n const aiBotBlocklist = [...(fileConfig.botBlocklist || []), ...config.aiBotBlocklist];\n\n if (aiTools.length > 0) logger.info(`Custom AI tools: ${aiTools.join(', ')}`);\n if (aiTrailerDomains.length > 0) logger.info(`Custom trailer domains: ${aiTrailerDomains.join(', ')}`);\n if (aiBotBlocklist.length > 0) logger.info(`Custom bot blocklist: ${aiBotBlocklist.join(', ')}`);\n\n // Determine diffBase for PR-scoped analysis\n let diffBase: string | undefined = options.diffBase;\n if (options.pr && !diffBase) {\n diffBase = detectPRBaseRef() ?? undefined;\n if (diffBase) {\n logger.info(`PR mode: detected base ref ${diffBase}`);\n } else {\n logger.warn('--pr flag used but no PR context detected. Falling back to --since mode.');\n }\n }\n\n logger.info('Starting commit collection...');\n\n const commitStream = await collectCommits({\n repoPath: config.repo,\n since: diffBase ? undefined : config.since,\n until: diffBase ? undefined : config.until,\n diffBase,\n aiPatterns,\n aiTools,\n aiTrailerDomains,\n aiBotBlocklist,\n defaultBranch: config.defaultBranch,\n logger,\n });\n\n const outputPath = join(config.outDir, 'commit-stream.json');\n await writeJSON(outputPath, commitStream);\n\n logger.info(`Collected ${commitStream.commits.length} commits`);\n const counts = { ai: 0, human: 0, unknown: 0 };\n for (const c of commitStream.commits) counts[c.tags.attribution]++;\n logger.info(\n `Attribution: ai ${counts.ai} · human ${counts.human} · unknown ${counts.unknown}`\n );\n logger.info(`Output written to: ${outputPath}`);\n } catch (error) {\n logger.error(\n `Collection failed: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n });\n}\n","import { z } from 'zod';\n\nexport const CLIConfig = z.object({\n repo: z.string().default(process.cwd()),\n since: z.string().optional(),\n until: z.string().optional(),\n aiPatterns: z.array(z.string()).default([]),\n aiTools: z.array(z.string()).default([]),\n aiTrailerDomains: z.array(z.string()).default([]),\n aiBotBlocklist: z.array(z.string()).default([]),\n defaultBranch: z.string().optional(),\n outDir: z.string().default('./aida-output'),\n verbose: z.boolean().default(false),\n});\n\nexport type CLIConfig = z.infer<typeof CLIConfig>;\n","/**\n * Detect the PR base ref from CI environment variables.\n * Returns the base branch/ref that the PR is targeting, or null if not in a PR context.\n */\nexport function detectPRBaseRef(): string | null {\n // GitHub Actions\n // GITHUB_BASE_REF is set on pull_request events\n if (process.env.GITHUB_ACTIONS === 'true' && process.env.GITHUB_BASE_REF) {\n return `origin/${process.env.GITHUB_BASE_REF}`;\n }\n\n // GitLab CI\n // CI_MERGE_REQUEST_DIFF_BASE_SHA is the commit SHA of the base branch\n // CI_MERGE_REQUEST_TARGET_BRANCH_NAME is the branch name\n if (process.env.GITLAB_CI === 'true') {\n if (process.env.CI_MERGE_REQUEST_DIFF_BASE_SHA) {\n return process.env.CI_MERGE_REQUEST_DIFF_BASE_SHA;\n }\n if (process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME) {\n return `origin/${process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME}`;\n }\n }\n\n // Bitbucket Pipelines\n if (process.env.BITBUCKET_PIPELINE_UUID) {\n if (process.env.BITBUCKET_PR_DESTINATION_BRANCH) {\n return `origin/${process.env.BITBUCKET_PR_DESTINATION_BRANCH}`;\n }\n }\n\n // Azure DevOps\n if (process.env.TF_BUILD === 'True') {\n // SYSTEM_PULLREQUEST_TARGETBRANCH contains refs/heads/main format\n const targetBranch = process.env.SYSTEM_PULLREQUEST_TARGETBRANCH;\n if (targetBranch) {\n const branchName = targetBranch.replace('refs/heads/', '');\n return `origin/${branchName}`;\n }\n }\n\n return null;\n}\n","import { Command } from 'commander';\nimport { readJSON, writeJSON, createLogger, CommitStream, AidaConfig } from '@aida-dev/core';\nimport { calculateMetrics } from '@aida-dev/metrics';\nimport { join } from 'path';\nimport { readFile } from 'fs/promises';\nimport { CLIConfig } from '../schema/config.js';\n\nasync function loadAidaConfig(repoPath: string): Promise<Partial<AidaConfig>> {\n try {\n const raw = await readFile(join(repoPath, '.aida.json'), 'utf-8');\n return AidaConfig.parse(JSON.parse(raw));\n } catch {\n return {};\n }\n}\n\nexport function createAnalyzeCommand(): Command {\n return new Command('analyze')\n .description('Analyze commit stream and generate metrics.json')\n .option('--out-dir <path>', 'Output directory', './aida-output')\n .option(\n '--default-attribution <value>',\n 'Prior for unattributed commits: ai | human | unknown (default: unknown, or .aida.json)'\n )\n .option(\n '--coverage-threshold <fraction>',\n 'Coverage below this flags metrics as low-confidence (default: 0.7, or .aida.json)'\n )\n .option('--verbose', 'Verbose logging', false)\n .action(async (options) => {\n const config = CLIConfig.parse(options);\n const logger = createLogger(config.verbose);\n\n try {\n logger.info('Starting metrics analysis...');\n\n const inputPath = join(config.outDir, 'commit-stream.json');\n const commitStream = await readJSON(inputPath, CommitStream);\n\n logger.info(`Analyzing ${commitStream.commits.length} commits`);\n\n // CLI flags override .aida.json (read from the collected repo's root)\n const fileConfig = await loadAidaConfig(commitStream.repoPath);\n const defaultAttribution =\n options.defaultAttribution ?? fileConfig.defaultAttribution ?? 'unknown';\n if (!['ai', 'human', 'unknown'].includes(defaultAttribution)) {\n throw new Error(\n `Invalid --default-attribution \"${defaultAttribution}\": expected ai, human, or unknown`\n );\n }\n const coverageThreshold = options.coverageThreshold\n ? Number(options.coverageThreshold)\n : (fileConfig.coverageThreshold ?? 0.7);\n if (Number.isNaN(coverageThreshold) || coverageThreshold < 0 || coverageThreshold > 1) {\n throw new Error(\n `Invalid --coverage-threshold \"${options.coverageThreshold}\": expected a fraction between 0 and 1`\n );\n }\n\n const metrics = calculateMetrics(commitStream, { defaultAttribution, coverageThreshold });\n\n const outputPath = join(config.outDir, 'metrics.json');\n await writeJSON(outputPath, metrics);\n\n const a = metrics.attribution;\n logger.info(\n `Attribution coverage: ${(a.coverage * 100).toFixed(1)}% (ai: ${a.ai}, human: ${a.human}, unknown: ${a.unknown})`\n );\n if (a.belowThreshold) {\n logger.warn(\n `Coverage is below ${(a.coverageThreshold * 100).toFixed(0)}%: metrics are low-confidence. Tag AI commits or set defaultAttribution.`\n );\n }\n logger.info(`Merge ratio: ${(metrics.mergeRatio.mergeRatio * 100).toFixed(1)}%`);\n logger.info(`Average persistence: ${metrics.persistence.avgDays} days`);\n if (!metrics.baseline) {\n logger.warn('No baseline cohort: no commits attributed as human (see caveats).');\n }\n logger.info(`Output written to: ${outputPath}`);\n } catch (error) {\n logger.error(`Analysis failed: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n}\n","import { Command } from 'commander';\nimport { readJSON, createLogger } from '@aida-dev/core';\nimport { Metrics } from '@aida-dev/metrics';\nimport { join } from 'path';\nimport { promises as fs } from 'fs';\nimport { CLIConfig } from '../schema/config.js';\n\nfunction formatDelta(value: number, suffix: string): string {\n const sign = value > 0 ? '+' : '';\n return `${sign}${value}${suffix}`;\n}\n\nfunction generateMarkdownReport(metrics: Metrics): string {\n const mergeRatioPct = (metrics.mergeRatio.mergeRatio * 100).toFixed(1);\n const a = metrics.attribution;\n const coveragePct = (a.coverage * 100).toFixed(1);\n const unknownPct = a.commitsTotal > 0 ? ((a.unknown / a.commitsTotal) * 100).toFixed(1) : '0.0';\n\n const coverageWarning = a.belowThreshold\n ? `\\n> ⚠️ **Coverage is below ${(a.coverageThreshold * 100).toFixed(0)}%.** Most of this history has unknown provenance: every metric below is low-confidence. Tag AI commits (trailers, \\`[AI]\\`) or set \\`defaultAttribution\\` in \\`.aida.json\\`.\\n`\n : '';\n\n const priorNote =\n a.defaultAttribution !== 'unknown'\n ? `\\nUnattributed commits are **assumed \\`${a.defaultAttribution}\\`** via \\`defaultAttribution\\` — this is a prior, not observed data.\\n`\n : '';\n\n const baselineLabel = metrics.baseline?.assumed\n ? 'Human baseline (assumed)'\n : 'Human baseline';\n\n const comparisonSection = metrics.baseline && metrics.delta\n ? `## AI vs Baseline\n\n| Metric | AI commits | ${baselineLabel} | Delta |\n|---|---:|---:|---:|\n| Commits | ${metrics.mergeRatio.aiCommitsTotal} | ${metrics.baseline.mergeRatio.commitsTotal} | — |\n| Merge ratio | ${mergeRatioPct}% | ${(metrics.baseline.mergeRatio.mergeRatio * 100).toFixed(1)}% | ${formatDelta(Math.round(metrics.delta.mergeRatio * 1000) / 10, ' pp')} |\n| Avg persistence (days) | ${metrics.persistence.avgDays} | ${metrics.baseline.persistence.avgDays} | ${formatDelta(metrics.delta.avgPersistenceDays, '')} |\n| Median persistence (days) | ${metrics.persistence.medianDays} | ${metrics.baseline.persistence.medianDays} | ${formatDelta(metrics.delta.medianPersistenceDays, '')} |\n`\n : `## AI vs Baseline\n\n**No baseline available** — no commits are attributed as human, so there is nothing honest to compare against. If unattributed commits in this repo are human-authored, set \\`\"defaultAttribution\": \"human\"\\` in \\`.aida.json\\`.\n`;\n\n const categories = ['source', 'tests', 'migrations', 'config', 'docs', 'generated'] as const;\n\n function mixCell(mix: Metrics['cohorts']['ai']['taskMix'], cat: (typeof categories)[number]) {\n if (!mix) return '—';\n const total = categories.reduce((sum, c) => sum + mix[c], 0);\n return total > 0 ? `${mix[cat]} (${((mix[cat] / total) * 100).toFixed(0)}%)` : '0';\n }\n\n const aiCtx = metrics.cohorts.ai;\n const baseCtx = metrics.cohorts.baseline;\n const fairnessSection = `## Cohort Fairness\n\nPersistence comparisons are only meaningful between cohorts of similar **age** and **task mix**.\n\n| | AI cohort | Baseline cohort |\n|---|---:|---:|\n| Commits | ${aiCtx.age?.commits ?? 0} | ${baseCtx.age?.commits ?? 0} |\n| Avg age (days) | ${aiCtx.age?.avgAgeDays ?? '—'} | ${baseCtx.age?.avgAgeDays ?? '—'} |\n| Median age (days) | ${aiCtx.age?.medianAgeDays ?? '—'} | ${baseCtx.age?.medianAgeDays ?? '—'} |\n${categories.map((cat) => `| Files: ${cat} | ${mixCell(aiCtx.taskMix, cat)} | ${mixCell(baseCtx.taskMix, cat)} |`).join('\\n')}\n`;\n\n const baselineDetail = metrics.baseline\n ? `## ${baselineLabel}\n- Commits (total): ${metrics.baseline.mergeRatio.commitsTotal}\n- Commits merged: ${metrics.baseline.mergeRatio.commitsMerged}\n- **Merge Ratio:** ${(metrics.baseline.mergeRatio.mergeRatio * 100).toFixed(1)}%\n- Persistence — commits considered: ${metrics.baseline.persistence.commitsConsidered}, avg: ${metrics.baseline.persistence.avgDays}d, median: ${metrics.baseline.persistence.medianDays}d\n\n`\n : '';\n\n return `# AIDA Report\n\n**Repo:** ${metrics.repoPath} \n**Default branch:** ${metrics.defaultBranch} \n**Window:** ${metrics.window.since || 'beginning'} → ${metrics.window.until || 'now'} \n**Generated:** ${metrics.generatedAt}\n\n## Attribution Coverage\n\n**${coveragePct}% of commits have known provenance** — ai: ${a.ai} · human: ${a.human} · unknown: ${a.unknown} (${unknownPct}%)\n\n**Autonomy:** agent ${a.modes.agent} · assisted ${a.modes.assisted} · autocomplete ${a.modes.autocomplete} · none ${a.modes.none} · unknown ${a.modes.unknown} — evidence: declared ${a.modeEvidence.declared} / inferred ${a.modeEvidence.inferred} / none ${a.modeEvidence.none}\n${coverageWarning}${priorNote}\n${comparisonSection}\n${fairnessSection}\n## Merge Ratio\n- AI-tagged commits (total): ${metrics.mergeRatio.aiCommitsTotal}\n- AI-tagged commits merged: ${metrics.mergeRatio.aiCommitsMerged}\n- **Merge Ratio:** ${mergeRatioPct}%\n\n## Persistence (file-level survival)\n- Commits considered: ${metrics.persistence.commitsConsidered}\n- Files measured: ${metrics.persistence.filesConsidered} (${metrics.persistence.censored} still surviving at collection time; ${metrics.persistence.filesExcluded} excluded: migrations/generated)\n- Average days: ${metrics.persistence.avgDays}\n- Median days: ${metrics.persistence.medianDays}\n\n| 0–1d | 2–7d | 8–30d | 31–90d | 90d+ |\n|---:|---:|---:|---:|---:|\n| ${metrics.persistence.buckets.d0_1} | ${metrics.persistence.buckets.d2_7} | ${metrics.persistence.buckets.d8_30} | ${metrics.persistence.buckets.d31_90} | ${metrics.persistence.buckets.d90_plus} |\n\n${baselineDetail}### Caveats\n${metrics.caveats.map((caveat) => `- ${caveat}`).join('\\n')}\n`;\n}\n\nexport function createReportCommand(): Command {\n return new Command('report')\n .description('Generate report from metrics.json')\n .option('--out-dir <path>', 'Output directory', './aida-output')\n .option('--verbose', 'Verbose logging', false)\n .action(async (options) => {\n const config = CLIConfig.parse(options);\n const logger = createLogger(config.verbose);\n\n try {\n logger.info('Generating report...');\n\n const inputPath = join(config.outDir, 'metrics.json');\n const metrics = await readJSON(inputPath, Metrics);\n\n const markdown = generateMarkdownReport(metrics);\n const mdPath = join(config.outDir, 'report.md');\n await fs.writeFile(mdPath, markdown, 'utf-8');\n logger.info(`Markdown report written to: ${mdPath}`);\n\n logger.info('Report generation completed');\n } catch (error) {\n logger.error(\n `Report generation failed: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n });\n}\n","import { Command } from 'commander';\nimport { createLogger } from '@aida-dev/core';\nimport { join } from 'path';\nimport { promises as fs } from 'fs';\nimport { CLIConfig } from '../schema/config.js';\nimport { detectProvider } from '../providers/detect.js';\n\nexport function createCommentCommand(): Command {\n return new Command('comment')\n .description('Post AIDA report as a PR/MR comment (auto-detects CI provider)')\n .option('--out-dir <path>', 'Output directory', './aida-output')\n .option('--verbose', 'Verbose logging', false)\n .option('--dry-run', 'Print comment to stdout instead of posting', false)\n .action(async (options) => {\n const config = CLIConfig.parse(options);\n const logger = createLogger(config.verbose);\n\n try {\n const reportPath = join(config.outDir, 'report.md');\n let content: string;\n\n try {\n content = await fs.readFile(reportPath, 'utf-8');\n } catch {\n logger.error(`Report not found at ${reportPath}. Run 'aida report' first.`);\n process.exit(1);\n }\n\n // Dry run — just print to stdout\n if (options.dryRun) {\n logger.info('Dry run — printing report to stdout:');\n console.log(content);\n return;\n }\n\n // Detect CI provider\n const provider = detectProvider();\n if (!provider) {\n logger.error(\n 'Could not detect CI provider. Supported: GitHub Actions.\\n' +\n 'Use --dry-run to print the report to stdout instead.'\n );\n process.exit(1);\n }\n\n logger.info(`Detected CI provider: ${provider.name}`);\n\n const pr = provider.getPRIdentifier();\n if (!pr) {\n logger.error(\n 'Could not determine PR/MR number. Is this running on a pull_request event?'\n );\n process.exit(1);\n }\n\n logger.info(`Posting comment to ${provider.name} PR #${pr.prNumber}...`);\n await provider.postComment(content);\n logger.info('AIDA report posted as PR comment');\n } catch (error) {\n logger.error(\n `Comment failed: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n });\n}\n","import type { CIProvider, PRIdentifier } from './types.js';\nimport { readFileSync } from 'fs';\n\nconst MARKER = '<!-- aida-metrics-report -->';\n\nfunction sanitizeErrorBody(text: string, maxLength = 200): string {\n // Strip potential tokens, auth headers, and URLs with credentials\n let sanitized = text\n .replace(/ghp_[A-Za-z0-9_]+/g, '[REDACTED]')\n .replace(/gho_[A-Za-z0-9_]+/g, '[REDACTED]')\n .replace(/github_pat_[A-Za-z0-9_]+/g, '[REDACTED]')\n .replace(/Bearer\\s+[A-Za-z0-9._-]+/gi, 'Bearer [REDACTED]')\n .replace(/token\\s+[A-Za-z0-9._-]+/gi, 'token [REDACTED]');\n if (sanitized.length > maxLength) {\n sanitized = sanitized.slice(0, maxLength) + '...(truncated)';\n }\n return sanitized;\n}\n\ninterface GitHubEvent {\n pull_request?: {\n number: number;\n };\n number?: number;\n}\n\nexport class GitHubProvider implements CIProvider {\n name = 'github';\n\n private get token(): string {\n const token = process.env.GITHUB_TOKEN;\n if (!token) {\n throw new Error('GITHUB_TOKEN is required for GitHub PR comments. Pass it via env.');\n }\n return token;\n }\n\n private get repo(): string {\n const repo = process.env.GITHUB_REPOSITORY;\n if (!repo) {\n throw new Error('GITHUB_REPOSITORY env var not found. Are you running in GitHub Actions?');\n }\n return repo;\n }\n\n private get apiUrl(): string {\n return process.env.GITHUB_API_URL || 'https://api.github.com';\n }\n\n getPRIdentifier(): PRIdentifier | null {\n const eventPath = process.env.GITHUB_EVENT_PATH;\n if (!eventPath) return null;\n\n try {\n const event: GitHubEvent = JSON.parse(readFileSync(eventPath, 'utf-8'));\n const prNumber = event.pull_request?.number || event.number;\n if (!prNumber) return null;\n\n return {\n provider: 'github',\n prNumber: String(prNumber),\n repo: this.repo,\n };\n } catch {\n return null;\n }\n }\n\n async postComment(content: string, marker: string = MARKER): Promise<void> {\n const pr = this.getPRIdentifier();\n if (!pr) {\n throw new Error('Could not determine PR number. Is this running on a pull_request event?');\n }\n\n const markedContent = `${marker}\\n${content}`;\n\n // Try to find and update existing comment\n const existingId = await this.findExistingComment(pr, marker);\n\n if (existingId) {\n await this.updateComment(existingId, markedContent);\n } else {\n await this.createComment(pr, markedContent);\n }\n }\n\n private async findExistingComment(pr: PRIdentifier, marker: string): Promise<number | null> {\n const url = `${this.apiUrl}/repos/${pr.repo}/issues/${pr.prNumber}/comments?per_page=100`;\n\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${this.token}`,\n Accept: 'application/vnd.github.v3+json',\n },\n });\n\n if (!response.ok) return null;\n\n const comments = (await response.json()) as Array<{ id: number; body: string }>;\n const existing = comments.find((c) => c.body.startsWith(marker));\n return existing?.id || null;\n }\n\n private async createComment(pr: PRIdentifier, body: string): Promise<void> {\n const url = `${this.apiUrl}/repos/${pr.repo}/issues/${pr.prNumber}/comments`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.token}`,\n Accept: 'application/vnd.github.v3+json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ body }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to create GitHub comment: ${response.status} ${sanitizeErrorBody(error)}`);\n }\n }\n\n private async updateComment(commentId: number, body: string): Promise<void> {\n const url = `${this.apiUrl}/repos/${this.repo}/issues/comments/${commentId}`;\n\n const response = await fetch(url, {\n method: 'PATCH',\n headers: {\n Authorization: `Bearer ${this.token}`,\n Accept: 'application/vnd.github.v3+json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ body }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to update GitHub comment: ${response.status} ${sanitizeErrorBody(error)}`);\n }\n }\n}\n","import type { CIProvider } from './types.js';\nimport { GitHubProvider } from './github.js';\n\nexport function detectProvider(): CIProvider | null {\n // GitHub Actions\n if (process.env.GITHUB_ACTIONS === 'true') {\n return new GitHubProvider();\n }\n\n // GitLab CI — not yet implemented\n // if (process.env.GITLAB_CI === 'true') { ... }\n\n // Bitbucket Pipelines — not yet implemented\n // if (process.env.BITBUCKET_PIPELINE_UUID) { ... }\n\n // Azure DevOps — not yet implemented\n // if (process.env.TF_BUILD === 'True') { ... }\n\n return null;\n}\n"],"mappings":"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","names":["Command","Command","writeJSON","createLogger","AidaConfig","join","readFile","loadAidaConfig","readFile","join","AidaConfig","Command","createLogger","writeJSON","Command","readJSON","createLogger","join","Command","createLogger","join","readJSON","Command","createLogger","join","fs","Command","createLogger","join","fs","Command"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/collect.ts","../src/schema/config.ts","../src/providers/pr-base.ts","../src/commands/analyze.ts","../src/commands/report.ts","../src/commands/comment.ts","../src/providers/github.ts","../src/providers/detect.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { createCollectCommand } from './commands/collect.js';\nimport { createAnalyzeCommand } from './commands/analyze.js';\nimport { createReportCommand } from './commands/report.js';\nimport { createCommentCommand } from './commands/comment.js';\n\nconst program = new Command();\n\nprogram\n .name('aida')\n .description('AIDA (AI Development Accounting) - Metrics for AI-assisted development')\n .version('0.0.0');\n\n// Add commands\nprogram.addCommand(createCollectCommand());\nprogram.addCommand(createAnalyzeCommand());\nprogram.addCommand(createReportCommand());\nprogram.addCommand(createCommentCommand());\n\nprogram.parse();\n","import { Command } from 'commander';\nimport { collectCommits, writeJSON, createLogger, AidaConfig } from '@aida-dev/core';\nimport { join } from 'path';\nimport { readFile } from 'fs/promises';\nimport { CLIConfig } from '../schema/config.js';\nimport { detectPRBaseRef } from '../providers/pr-base.js';\n\nasync function loadAidaConfig(repoPath: string): Promise<Partial<AidaConfig>> {\n try {\n const raw = await readFile(join(repoPath, '.aida.json'), 'utf-8');\n return AidaConfig.parse(JSON.parse(raw));\n } catch {\n return {};\n }\n}\n\nfunction collectRepeatable(value: string, previous: string[]): string[] {\n return previous ? [...previous, value] : [value];\n}\n\nexport function createCollectCommand(): Command {\n return new Command('collect')\n .description('Collect commits and generate commit-stream.json')\n .option('--repo <path>', 'Repository path', process.cwd())\n .option('--since <date>', 'Start date (ISO or relative like 90d)')\n .option('--until <date>', 'End date (ISO or relative)')\n .option('--pr', 'PR-scoped analysis (auto-detect base ref from CI env vars)')\n .option('--diff-base <ref>', 'Explicit base ref for PR-scoped analysis (e.g., origin/main)')\n .option('--ai-pattern <pattern>', 'AI detection regex (repeatable)', collectRepeatable, [])\n .option('--ai-tool <name>', 'Additional AI tool name (repeatable)', collectRepeatable, [])\n .option('--ai-trailer-domain <domain>', 'Additional Co-authored-by domain (repeatable)', collectRepeatable, [])\n .option('--ai-bot-blocklist <name>', 'Non-AI bot to exclude from trailer matching (repeatable)', collectRepeatable, [])\n .option('--default-branch <name>', 'Default branch name')\n .option('--out-dir <path>', 'Output directory', './aida-output')\n .option('--verbose', 'Verbose logging', false)\n .action(async (options) => {\n // Commander uses singular camelCase (--ai-tool → aiTool), schema uses plural\n const mapped = {\n ...options,\n aiPatterns: options.aiPattern || [],\n aiTools: options.aiTool || [],\n aiTrailerDomains: options.aiTrailerDomain || [],\n aiBotBlocklist: options.aiBotBlocklist || [],\n };\n const config = CLIConfig.parse(mapped);\n const logger = createLogger(config.verbose);\n\n try {\n // Load .aida.json config (merge with CLI flags)\n const fileConfig = await loadAidaConfig(config.repo);\n const aiPatterns = [...(fileConfig.patterns || []), ...config.aiPatterns];\n const aiTools = [...(fileConfig.tools || []), ...config.aiTools];\n const aiTrailerDomains = [...(fileConfig.trailerDomains || []), ...config.aiTrailerDomains];\n const aiBotBlocklist = [...(fileConfig.botBlocklist || []), ...config.aiBotBlocklist];\n\n if (aiTools.length > 0) logger.info(`Custom AI tools: ${aiTools.join(', ')}`);\n if (aiTrailerDomains.length > 0) logger.info(`Custom trailer domains: ${aiTrailerDomains.join(', ')}`);\n if (aiBotBlocklist.length > 0) logger.info(`Custom bot blocklist: ${aiBotBlocklist.join(', ')}`);\n\n // Determine diffBase for PR-scoped analysis\n let diffBase: string | undefined = options.diffBase;\n if (options.pr && !diffBase) {\n diffBase = detectPRBaseRef() ?? undefined;\n if (diffBase) {\n logger.info(`PR mode: detected base ref ${diffBase}`);\n } else {\n logger.warn('--pr flag used but no PR context detected. Falling back to --since mode.');\n }\n }\n\n logger.info('Starting commit collection...');\n\n const commitStream = await collectCommits({\n repoPath: config.repo,\n since: diffBase ? undefined : config.since,\n until: diffBase ? undefined : config.until,\n diffBase,\n aiPatterns,\n aiTools,\n aiTrailerDomains,\n aiBotBlocklist,\n defaultBranch: config.defaultBranch,\n logger,\n });\n\n const outputPath = join(config.outDir, 'commit-stream.json');\n await writeJSON(outputPath, commitStream);\n\n logger.info(`Collected ${commitStream.commits.length} commits`);\n const counts = { ai: 0, human: 0, automated: 0, unknown: 0 };\n for (const c of commitStream.commits) counts[c.tags.attribution]++;\n logger.info(\n `Attribution: ai ${counts.ai} · human ${counts.human} · automated ${counts.automated} · unknown ${counts.unknown}`\n );\n logger.info(`Output written to: ${outputPath}`);\n } catch (error) {\n logger.error(\n `Collection failed: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n });\n}\n","import { z } from 'zod';\n\nexport const CLIConfig = z.object({\n repo: z.string().default(process.cwd()),\n since: z.string().optional(),\n until: z.string().optional(),\n aiPatterns: z.array(z.string()).default([]),\n aiTools: z.array(z.string()).default([]),\n aiTrailerDomains: z.array(z.string()).default([]),\n aiBotBlocklist: z.array(z.string()).default([]),\n defaultBranch: z.string().optional(),\n outDir: z.string().default('./aida-output'),\n verbose: z.boolean().default(false),\n});\n\nexport type CLIConfig = z.infer<typeof CLIConfig>;\n","/**\n * Detect the PR base ref from CI environment variables.\n * Returns the base branch/ref that the PR is targeting, or null if not in a PR context.\n */\nexport function detectPRBaseRef(): string | null {\n // GitHub Actions\n // GITHUB_BASE_REF is set on pull_request events\n if (process.env.GITHUB_ACTIONS === 'true' && process.env.GITHUB_BASE_REF) {\n return `origin/${process.env.GITHUB_BASE_REF}`;\n }\n\n // GitLab CI\n // CI_MERGE_REQUEST_DIFF_BASE_SHA is the commit SHA of the base branch\n // CI_MERGE_REQUEST_TARGET_BRANCH_NAME is the branch name\n if (process.env.GITLAB_CI === 'true') {\n if (process.env.CI_MERGE_REQUEST_DIFF_BASE_SHA) {\n return process.env.CI_MERGE_REQUEST_DIFF_BASE_SHA;\n }\n if (process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME) {\n return `origin/${process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME}`;\n }\n }\n\n // Bitbucket Pipelines\n if (process.env.BITBUCKET_PIPELINE_UUID) {\n if (process.env.BITBUCKET_PR_DESTINATION_BRANCH) {\n return `origin/${process.env.BITBUCKET_PR_DESTINATION_BRANCH}`;\n }\n }\n\n // Azure DevOps\n if (process.env.TF_BUILD === 'True') {\n // SYSTEM_PULLREQUEST_TARGETBRANCH contains refs/heads/main format\n const targetBranch = process.env.SYSTEM_PULLREQUEST_TARGETBRANCH;\n if (targetBranch) {\n const branchName = targetBranch.replace('refs/heads/', '');\n return `origin/${branchName}`;\n }\n }\n\n return null;\n}\n","import { Command } from 'commander';\nimport { readJSON, writeJSON, createLogger, CommitStream, AidaConfig } from '@aida-dev/core';\nimport { calculateMetrics } from '@aida-dev/metrics';\nimport { join } from 'path';\nimport { readFile } from 'fs/promises';\nimport { CLIConfig } from '../schema/config.js';\n\nasync function loadAidaConfig(repoPath: string): Promise<Partial<AidaConfig>> {\n try {\n const raw = await readFile(join(repoPath, '.aida.json'), 'utf-8');\n return AidaConfig.parse(JSON.parse(raw));\n } catch {\n return {};\n }\n}\n\nexport function createAnalyzeCommand(): Command {\n return new Command('analyze')\n .description('Analyze commit stream and generate metrics.json')\n .option('--out-dir <path>', 'Output directory', './aida-output')\n .option(\n '--default-attribution <value>',\n 'Prior for unattributed commits: ai | human | unknown (default: unknown, or .aida.json)'\n )\n .option(\n '--coverage-threshold <fraction>',\n 'Coverage below this flags metrics as low-confidence (default: 0.7, or .aida.json)'\n )\n .option('--verbose', 'Verbose logging', false)\n .action(async (options) => {\n const config = CLIConfig.parse(options);\n const logger = createLogger(config.verbose);\n\n try {\n logger.info('Starting metrics analysis...');\n\n const inputPath = join(config.outDir, 'commit-stream.json');\n const commitStream = await readJSON(inputPath, CommitStream);\n\n logger.info(`Analyzing ${commitStream.commits.length} commits`);\n\n // CLI flags override .aida.json (read from the collected repo's root)\n const fileConfig = await loadAidaConfig(commitStream.repoPath);\n const defaultAttribution =\n options.defaultAttribution ?? fileConfig.defaultAttribution ?? 'unknown';\n if (!['ai', 'human', 'unknown'].includes(defaultAttribution)) {\n throw new Error(\n `Invalid --default-attribution \"${defaultAttribution}\": expected ai, human, or unknown`\n );\n }\n const coverageThreshold = options.coverageThreshold\n ? Number(options.coverageThreshold)\n : (fileConfig.coverageThreshold ?? 0.7);\n if (Number.isNaN(coverageThreshold) || coverageThreshold < 0 || coverageThreshold > 1) {\n throw new Error(\n `Invalid --coverage-threshold \"${options.coverageThreshold}\": expected a fraction between 0 and 1`\n );\n }\n\n const metrics = calculateMetrics(commitStream, { defaultAttribution, coverageThreshold });\n\n const outputPath = join(config.outDir, 'metrics.json');\n await writeJSON(outputPath, metrics);\n\n const a = metrics.attribution;\n logger.info(\n `Attribution coverage: ${(a.coverage * 100).toFixed(1)}% (ai: ${a.ai}, human: ${a.human}, automated: ${a.automated}, unknown: ${a.unknown})`\n );\n if (a.belowThreshold) {\n logger.warn(\n `Coverage is below ${(a.coverageThreshold * 100).toFixed(0)}%: metrics are low-confidence. Tag AI commits or set defaultAttribution.`\n );\n }\n logger.info(`Average persistence: ${metrics.persistence.avgDays} days`);\n if (!metrics.baseline) {\n logger.warn('No baseline cohort: no commits attributed as human (see caveats).');\n }\n logger.info(`Output written to: ${outputPath}`);\n } catch (error) {\n logger.error(`Analysis failed: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n}\n","import { Command } from 'commander';\nimport { readJSON, createLogger } from '@aida-dev/core';\nimport { Metrics } from '@aida-dev/metrics';\nimport { join } from 'path';\nimport { promises as fs } from 'fs';\nimport { CLIConfig } from '../schema/config.js';\n\nfunction formatDelta(value: number, suffix: string): string {\n const sign = value > 0 ? '+' : '';\n return `${sign}${value}${suffix}`;\n}\n\nfunction generateMarkdownReport(metrics: Metrics): string {\n const a = metrics.attribution;\n const coveragePct = (a.coverage * 100).toFixed(1);\n const unknownPct = a.commitsTotal > 0 ? ((a.unknown / a.commitsTotal) * 100).toFixed(1) : '0.0';\n\n const coverageWarning = a.belowThreshold\n ? `\\n> ⚠️ **Coverage is below ${(a.coverageThreshold * 100).toFixed(0)}%.** Most of this history has unknown provenance: every metric below is low-confidence. Tag AI commits (trailers, \\`[AI]\\`) or set \\`defaultAttribution\\` in \\`.aida.json\\`.\\n`\n : '';\n\n const priorNote =\n a.defaultAttribution !== 'unknown' && a.unknown > 0\n ? `\\nUnattributed commits are **assumed \\`${a.defaultAttribution}\\`** via \\`defaultAttribution\\` — this is a prior, not observed data.\\n`\n : '';\n\n const baselineLabel = metrics.baseline?.assumed\n ? 'Human baseline (assumed)'\n : 'Human baseline';\n\n const comparisonSection = metrics.baseline && metrics.delta\n ? `## AI vs Baseline\n\n| Metric | AI commits | ${baselineLabel} | Delta |\n|---|---:|---:|---:|\n| Commits | ${metrics.persistence.commitsConsidered} | ${metrics.baseline.persistence.commitsConsidered} | — |\n| Avg persistence (days) | ${metrics.persistence.avgDays} | ${metrics.baseline.persistence.avgDays} | ${formatDelta(metrics.delta.avgPersistenceDays, '')} |\n| Median persistence (days) | ${metrics.persistence.medianDays} | ${metrics.baseline.persistence.medianDays} | ${formatDelta(metrics.delta.medianPersistenceDays, '')} |\n`\n : `## AI vs Baseline\n\n**No baseline available** — no commits are attributed as human, so there is nothing honest to compare against. If unattributed commits in this repo are human-authored, set \\`\"defaultAttribution\": \"human\"\\` in \\`.aida.json\\`.\n`;\n\n const categories = ['source', 'tests', 'migrations', 'config', 'docs', 'generated'] as const;\n\n function mixCell(mix: Metrics['cohorts']['ai']['taskMix'], cat: (typeof categories)[number]) {\n if (!mix) return '—';\n const total = categories.reduce((sum, c) => sum + mix[c], 0);\n return total > 0 ? `${mix[cat]} (${((mix[cat] / total) * 100).toFixed(0)}%)` : '0';\n }\n\n const aiCtx = metrics.cohorts.ai;\n const baseCtx = metrics.cohorts.baseline;\n const fairnessSection = `## Cohort Fairness\n\nPersistence comparisons are only meaningful between cohorts of similar **age** and **task mix**.\n\n| | AI cohort | Baseline cohort |\n|---|---:|---:|\n| Commits | ${aiCtx.age?.commits ?? 0} | ${baseCtx.age?.commits ?? 0} |\n| Avg age (days) | ${aiCtx.age?.avgAgeDays ?? '—'} | ${baseCtx.age?.avgAgeDays ?? '—'} |\n| Median age (days) | ${aiCtx.age?.medianAgeDays ?? '—'} | ${baseCtx.age?.medianAgeDays ?? '—'} |\n${categories.map((cat) => `| Files: ${cat} | ${mixCell(aiCtx.taskMix, cat)} | ${mixCell(baseCtx.taskMix, cat)} |`).join('\\n')}\n`;\n\n const modeOrder = ['agent', 'assisted', 'autocomplete', 'none', 'unknown'] as const;\n const modeRows = modeOrder\n .map((mode) => ({ mode, stats: metrics.byMode[mode] }))\n .filter((row) => row.stats !== null)\n .map(\n ({ mode, stats }) =>\n `| ${mode} | ${stats!.commits} | ${stats!.persistence.avgDays} | ${stats!.persistence.medianDays} | ${stats!.persistence.censored} |`\n );\n const byModeSection =\n modeRows.length > 0\n ? `## By Autonomy Level\n\nThe comparison that stays meaningful when everything is AI-assisted: how code holds up per autonomy level (automated commits excluded).\n\n| Mode | Commits | Avg persistence (d) | Median (d) | Surviving |\n|---|---:|---:|---:|---:|\n${modeRows.join('\\n')}\n\n`\n : '';\n\n const baselineDetail = metrics.baseline\n ? `## ${baselineLabel}\n- Persistence — commits considered: ${metrics.baseline.persistence.commitsConsidered}, avg: ${metrics.baseline.persistence.avgDays}d, median: ${metrics.baseline.persistence.medianDays}d\n\n`\n : '';\n\n return `# AIDA Report\n\n**Repo:** ${metrics.repoPath} \n**Default branch:** ${metrics.defaultBranch} \n**Window:** ${metrics.window.since || 'beginning'} → ${metrics.window.until || 'now'} \n**Generated:** ${metrics.generatedAt}\n\n## Attribution Coverage\n\n**${coveragePct}% of commits have known provenance** — ai: ${a.ai} · human: ${a.human} · automated: ${a.automated} · unknown: ${a.unknown} (${unknownPct}%)\n\n**Autonomy:** agent ${a.modes.agent} · assisted ${a.modes.assisted} · autocomplete ${a.modes.autocomplete} · none ${a.modes.none} · unknown ${a.modes.unknown} — evidence: declared ${a.modeEvidence.declared} / inferred ${a.modeEvidence.inferred} / none ${a.modeEvidence.none}\n${coverageWarning}${priorNote}\n${comparisonSection}\n${byModeSection}${fairnessSection}\n## Persistence (file-level survival)\n- Commits considered: ${metrics.persistence.commitsConsidered}\n- Files measured: ${metrics.persistence.filesConsidered} (${metrics.persistence.censored} still surviving at collection time; ${metrics.persistence.filesExcluded} excluded: migrations/generated)\n- Average days: ${metrics.persistence.avgDays}\n- Median days: ${metrics.persistence.medianDays}\n\n| 0–1d | 2–7d | 8–30d | 31–90d | 90d+ |\n|---:|---:|---:|---:|---:|\n| ${metrics.persistence.buckets.d0_1} | ${metrics.persistence.buckets.d2_7} | ${metrics.persistence.buckets.d8_30} | ${metrics.persistence.buckets.d31_90} | ${metrics.persistence.buckets.d90_plus} |\n\n${baselineDetail}### Caveats\n${metrics.caveats.map((caveat) => `- ${caveat}`).join('\\n')}\n`;\n}\n\nexport function createReportCommand(): Command {\n return new Command('report')\n .description('Generate report from metrics.json')\n .option('--out-dir <path>', 'Output directory', './aida-output')\n .option('--verbose', 'Verbose logging', false)\n .action(async (options) => {\n const config = CLIConfig.parse(options);\n const logger = createLogger(config.verbose);\n\n try {\n logger.info('Generating report...');\n\n const inputPath = join(config.outDir, 'metrics.json');\n const metrics = await readJSON(inputPath, Metrics);\n\n const markdown = generateMarkdownReport(metrics);\n const mdPath = join(config.outDir, 'report.md');\n await fs.writeFile(mdPath, markdown, 'utf-8');\n logger.info(`Markdown report written to: ${mdPath}`);\n\n logger.info('Report generation completed');\n } catch (error) {\n logger.error(\n `Report generation failed: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n });\n}\n","import { Command } from 'commander';\nimport { createLogger } from '@aida-dev/core';\nimport { join } from 'path';\nimport { promises as fs } from 'fs';\nimport { CLIConfig } from '../schema/config.js';\nimport { detectProvider } from '../providers/detect.js';\n\nexport function createCommentCommand(): Command {\n return new Command('comment')\n .description('Post AIDA report as a PR/MR comment (auto-detects CI provider)')\n .option('--out-dir <path>', 'Output directory', './aida-output')\n .option('--verbose', 'Verbose logging', false)\n .option('--dry-run', 'Print comment to stdout instead of posting', false)\n .action(async (options) => {\n const config = CLIConfig.parse(options);\n const logger = createLogger(config.verbose);\n\n try {\n const reportPath = join(config.outDir, 'report.md');\n let content: string;\n\n try {\n content = await fs.readFile(reportPath, 'utf-8');\n } catch {\n logger.error(`Report not found at ${reportPath}. Run 'aida report' first.`);\n process.exit(1);\n }\n\n // Dry run — just print to stdout\n if (options.dryRun) {\n logger.info('Dry run — printing report to stdout:');\n console.log(content);\n return;\n }\n\n // Detect CI provider\n const provider = detectProvider();\n if (!provider) {\n logger.error(\n 'Could not detect CI provider. Supported: GitHub Actions.\\n' +\n 'Use --dry-run to print the report to stdout instead.'\n );\n process.exit(1);\n }\n\n logger.info(`Detected CI provider: ${provider.name}`);\n\n const pr = provider.getPRIdentifier();\n if (!pr) {\n logger.error(\n 'Could not determine PR/MR number. Is this running on a pull_request event?'\n );\n process.exit(1);\n }\n\n logger.info(`Posting comment to ${provider.name} PR #${pr.prNumber}...`);\n await provider.postComment(content);\n logger.info('AIDA report posted as PR comment');\n } catch (error) {\n logger.error(\n `Comment failed: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n });\n}\n","import type { CIProvider, PRIdentifier } from './types.js';\nimport { readFileSync } from 'fs';\n\nconst MARKER = '<!-- aida-metrics-report -->';\n\nfunction sanitizeErrorBody(text: string, maxLength = 200): string {\n // Strip potential tokens, auth headers, and URLs with credentials\n let sanitized = text\n .replace(/ghp_[A-Za-z0-9_]+/g, '[REDACTED]')\n .replace(/gho_[A-Za-z0-9_]+/g, '[REDACTED]')\n .replace(/github_pat_[A-Za-z0-9_]+/g, '[REDACTED]')\n .replace(/Bearer\\s+[A-Za-z0-9._-]+/gi, 'Bearer [REDACTED]')\n .replace(/token\\s+[A-Za-z0-9._-]+/gi, 'token [REDACTED]');\n if (sanitized.length > maxLength) {\n sanitized = sanitized.slice(0, maxLength) + '...(truncated)';\n }\n return sanitized;\n}\n\ninterface GitHubEvent {\n pull_request?: {\n number: number;\n };\n number?: number;\n}\n\nexport class GitHubProvider implements CIProvider {\n name = 'github';\n\n private get token(): string {\n const token = process.env.GITHUB_TOKEN;\n if (!token) {\n throw new Error('GITHUB_TOKEN is required for GitHub PR comments. Pass it via env.');\n }\n return token;\n }\n\n private get repo(): string {\n const repo = process.env.GITHUB_REPOSITORY;\n if (!repo) {\n throw new Error('GITHUB_REPOSITORY env var not found. Are you running in GitHub Actions?');\n }\n return repo;\n }\n\n private get apiUrl(): string {\n return process.env.GITHUB_API_URL || 'https://api.github.com';\n }\n\n getPRIdentifier(): PRIdentifier | null {\n const eventPath = process.env.GITHUB_EVENT_PATH;\n if (!eventPath) return null;\n\n try {\n const event: GitHubEvent = JSON.parse(readFileSync(eventPath, 'utf-8'));\n const prNumber = event.pull_request?.number || event.number;\n if (!prNumber) return null;\n\n return {\n provider: 'github',\n prNumber: String(prNumber),\n repo: this.repo,\n };\n } catch {\n return null;\n }\n }\n\n async postComment(content: string, marker: string = MARKER): Promise<void> {\n const pr = this.getPRIdentifier();\n if (!pr) {\n throw new Error('Could not determine PR number. Is this running on a pull_request event?');\n }\n\n const markedContent = `${marker}\\n${content}`;\n\n // Try to find and update existing comment\n const existingId = await this.findExistingComment(pr, marker);\n\n if (existingId) {\n await this.updateComment(existingId, markedContent);\n } else {\n await this.createComment(pr, markedContent);\n }\n }\n\n private async findExistingComment(pr: PRIdentifier, marker: string): Promise<number | null> {\n const url = `${this.apiUrl}/repos/${pr.repo}/issues/${pr.prNumber}/comments?per_page=100`;\n\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${this.token}`,\n Accept: 'application/vnd.github.v3+json',\n },\n });\n\n if (!response.ok) return null;\n\n const comments = (await response.json()) as Array<{ id: number; body: string }>;\n const existing = comments.find((c) => c.body.startsWith(marker));\n return existing?.id || null;\n }\n\n private async createComment(pr: PRIdentifier, body: string): Promise<void> {\n const url = `${this.apiUrl}/repos/${pr.repo}/issues/${pr.prNumber}/comments`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.token}`,\n Accept: 'application/vnd.github.v3+json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ body }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to create GitHub comment: ${response.status} ${sanitizeErrorBody(error)}`);\n }\n }\n\n private async updateComment(commentId: number, body: string): Promise<void> {\n const url = `${this.apiUrl}/repos/${this.repo}/issues/comments/${commentId}`;\n\n const response = await fetch(url, {\n method: 'PATCH',\n headers: {\n Authorization: `Bearer ${this.token}`,\n Accept: 'application/vnd.github.v3+json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ body }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to update GitHub comment: ${response.status} ${sanitizeErrorBody(error)}`);\n }\n }\n}\n","import type { CIProvider } from './types.js';\nimport { GitHubProvider } from './github.js';\n\nexport function detectProvider(): CIProvider | null {\n // GitHub Actions\n if (process.env.GITHUB_ACTIONS === 'true') {\n return new GitHubProvider();\n }\n\n // GitLab CI — not yet implemented\n // if (process.env.GITLAB_CI === 'true') { ... }\n\n // Bitbucket Pipelines — not yet implemented\n // if (process.env.BITBUCKET_PIPELINE_UUID) { ... }\n\n // Azure DevOps — not yet implemented\n // if (process.env.TF_BUILD === 'True') { ... }\n\n return null;\n}\n"],"mappings":"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","names":["Command","Command","writeJSON","createLogger","AidaConfig","join","readFile","loadAidaConfig","readFile","join","AidaConfig","Command","createLogger","writeJSON","Command","readJSON","createLogger","join","Command","createLogger","join","readJSON","Command","createLogger","join","fs","Command","createLogger","join","fs","Command"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aida-dev/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "CLI for AIDA (AI Development Accounting) - Track and measure AI-assisted development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"commander": "^11.1.0",
|
|
44
44
|
"zod": "^3.22.4",
|
|
45
|
-
"@aida-dev/core": "0.
|
|
46
|
-
"@aida-dev/metrics": "0.
|
|
45
|
+
"@aida-dev/core": "0.11.0",
|
|
46
|
+
"@aida-dev/metrics": "0.8.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"tsup": "^8.0.0",
|