@prism-d1/cli 1.0.84 → 1.0.85
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/assets/coding-agent/README.md +824 -0
- package/dist/assets/coding-agent/agent.py +381 -0
- package/dist/assets/coding-agent/config.py +338 -0
- package/dist/assets/coding-agent/deploy/Dockerfile +86 -0
- package/dist/assets/coding-agent/deploy/create_harness.py +144 -0
- package/dist/assets/coding-agent/deploy/deploy-harness.sh +201 -0
- package/dist/assets/coding-agent/deploy/prism-coding-agent.yml +399 -0
- package/dist/assets/coding-agent/eval/run_eval.py +430 -0
- package/dist/assets/coding-agent/eval/run_harness_eval.py +262 -0
- package/dist/assets/coding-agent/eval/stubs/001-tags-element-validation.json +11 -0
- package/dist/assets/coding-agent/eval/stubs/002-status-filter.json +11 -0
- package/dist/assets/coding-agent/eval/stubs/003-refuse-test-deletion.json +11 -0
- package/dist/assets/coding-agent/fixtures/001-tags-element-validation.json +12 -0
- package/dist/assets/coding-agent/fixtures/002-status-filter.json +12 -0
- package/dist/assets/coding-agent/fixtures/003-refuse-test-deletion.json +10 -0
- package/dist/assets/coding-agent/pyproject.toml +28 -0
- package/dist/assets/coding-agent/requirements.txt +8 -0
- package/dist/assets/coding-agent/system_prompt.py +290 -0
- package/dist/assets/coding-agent/tools/__init__.py +11 -0
- package/dist/assets/coding-agent/tools/create_pr.py +141 -0
- package/dist/assets/coding-agent/tools/git_ops.py +197 -0
- package/dist/assets/github-workflows/prism-agent-eval.yml +2 -1
- package/dist/assets/github-workflows/prism-ai-metrics.yml +12 -3
- package/dist/assets/github-workflows/prism-eval-gate-kiro.yml +4 -3
- package/dist/assets/github-workflows/prism-eval-gate.yml +3 -2
- package/dist/assets/gitlab-workflows/prism-agent-eval.yml +2 -1
- package/dist/assets/gitlab-workflows/prism-ai-metrics.yml +3 -2
- package/dist/assets/gitlab-workflows/prism-eval-gate.yml +2 -1
- package/dist/assets/infra/lib/constructs/otel-collector-construct.ts +134 -2
- package/dist/assets/infra/lib/dashboard-stack.ts +79 -95
- package/dist/assets/infra/lib/lambda/metrics-processor.ts +99 -1
- package/dist/assets/infra/lib/lambda/otel-receiver.ts +318 -29
- package/dist/assets/infra/lib/lambda/productivity-widget.ts +85 -4
- package/dist/assets/infra/lib/lambda/velocity-widget.ts +265 -0
- package/dist/assets/infra/lib/metrics-pipeline-stack.ts +5 -0
- package/dist/src/commands/bootstrapper/install-coding-agent.d.ts +61 -0
- package/dist/src/commands/bootstrapper/install-coding-agent.d.ts.map +1 -0
- package/dist/src/commands/bootstrapper/install-coding-agent.js +599 -0
- package/dist/src/commands/bootstrapper/install-coding-agent.js.map +1 -0
- package/dist/src/commands/bootstrapper/setup-github-oidc.d.ts.map +1 -1
- package/dist/src/commands/bootstrapper/setup-github-oidc.js +23 -0
- package/dist/src/commands/bootstrapper/setup-github-oidc.js.map +1 -1
- package/package.json +2 -2
|
@@ -1443,6 +1443,266 @@ async function renderCisoClasses(fromIso: string, toIso: string, p: Palette): Pr
|
|
|
1443
1443
|
+ footnote('compliance_mappings is a string array on each finding — it cannot be expressed as a CloudWatch dimension, so this view is only possible by reading events directly.', p);
|
|
1444
1444
|
}
|
|
1445
1445
|
|
|
1446
|
+
// ---- View: commits-trend (DDB-backed AI vs Human bar chart + merge rate) ----
|
|
1447
|
+
|
|
1448
|
+
/**
|
|
1449
|
+
* Replaces the CloudWatch native "Commits / Day (AI vs Human)" and "Merge
|
|
1450
|
+
* Ratio: AI vs Human" graphs. Reads the attribution store at render time,
|
|
1451
|
+
* which avoids the CloudWatch increment-only problem where CI-seeded human
|
|
1452
|
+
* items that later upgrade to AI would double-count in CloudWatch metrics.
|
|
1453
|
+
*
|
|
1454
|
+
* Renders two inline SVGs:
|
|
1455
|
+
* 1. Stacked bar chart: AI (accent) + Human (muted) commits per day/week
|
|
1456
|
+
* 2. Line chart: AI merge rate and Human merge rate as %
|
|
1457
|
+
*/
|
|
1458
|
+
async function renderCommitsTrend(fromIso: string, toIso: string, days: number, p: Palette): Promise<string> {
|
|
1459
|
+
let data: any;
|
|
1460
|
+
try {
|
|
1461
|
+
data = await invokeReceiver('/v1/commits-daily', `from=${fromIso.slice(0, 10)}&to=${toIso.slice(0, 10)}`);
|
|
1462
|
+
} catch (err) {
|
|
1463
|
+
return emptyState('commit trend', `Attribution store unreachable (${(err as Error).message}). Requires codeburn sync --attribution + CI workflow.`, p);
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
const dayBuckets: Array<{ date: string; ai: number; human: number; mergedAi: number; mergedHuman: number }> = data?.days ?? [];
|
|
1467
|
+
if (dayBuckets.length === 0) {
|
|
1468
|
+
return emptyState('commit trend', 'No COMMIT# items in the selected range. Run `codeburn sync push --attribution` or merge a PR with prism-ai-metrics.yml installed.', p);
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
// Weekly bucketing if range > 21 days
|
|
1472
|
+
const useWeekly = days > 21;
|
|
1473
|
+
type Bucket = { label: string; ai: number; human: number; mergedAi: number; mergedHuman: number };
|
|
1474
|
+
let buckets: Bucket[];
|
|
1475
|
+
|
|
1476
|
+
if (useWeekly) {
|
|
1477
|
+
const weeks = new Map<string, Bucket>();
|
|
1478
|
+
for (const d of dayBuckets) {
|
|
1479
|
+
const dt = new Date(d.date);
|
|
1480
|
+
const weekStart = new Date(dt);
|
|
1481
|
+
weekStart.setDate(dt.getDate() - dt.getDay()); // Sunday
|
|
1482
|
+
const key = weekStart.toISOString().slice(0, 10);
|
|
1483
|
+
let w = weeks.get(key);
|
|
1484
|
+
if (!w) { w = { label: key, ai: 0, human: 0, mergedAi: 0, mergedHuman: 0 }; weeks.set(key, w); }
|
|
1485
|
+
w.ai += d.ai; w.human += d.human; w.mergedAi += d.mergedAi; w.mergedHuman += d.mergedHuman;
|
|
1486
|
+
}
|
|
1487
|
+
buckets = [...weeks.values()].sort((a, b) => a.label.localeCompare(b.label));
|
|
1488
|
+
} else {
|
|
1489
|
+
buckets = dayBuckets.map(d => ({ label: d.date, ai: d.ai, human: d.human, mergedAi: d.mergedAi, mergedHuman: d.mergedHuman }));
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
// Summary stats
|
|
1493
|
+
const totalAi = buckets.reduce((s, b) => s + b.ai, 0);
|
|
1494
|
+
const totalHuman = buckets.reduce((s, b) => s + b.human, 0);
|
|
1495
|
+
const totalMergedAi = buckets.reduce((s, b) => s + b.mergedAi, 0);
|
|
1496
|
+
const totalMergedHuman = buckets.reduce((s, b) => s + b.mergedHuman, 0);
|
|
1497
|
+
|
|
1498
|
+
const aiPct = totalAi + totalHuman > 0 ? ((totalAi / (totalAi + totalHuman)) * 100).toFixed(0) : '—';
|
|
1499
|
+
const aiMergeRate = totalAi > 0 ? ((totalMergedAi / totalAi) * 100).toFixed(0) : '—';
|
|
1500
|
+
const humanMergeRate = totalHuman > 0 ? ((totalMergedHuman / totalHuman) * 100).toFixed(0) : '—';
|
|
1501
|
+
|
|
1502
|
+
return `
|
|
1503
|
+
<div style="display:flex;gap:12px;flex-wrap:wrap;margin-bottom:8px">
|
|
1504
|
+
<div style="flex:1;min-width:130px;border:1px solid ${p.bord};border-radius:6px;padding:8px 12px">
|
|
1505
|
+
<div style="color:${p.mut};font-size:10px">AI Commits</div>
|
|
1506
|
+
<div style="color:${p.accent};font-size:20px;font-weight:600">${totalAi}</div>
|
|
1507
|
+
</div>
|
|
1508
|
+
<div style="flex:1;min-width:130px;border:1px solid ${p.bord};border-radius:6px;padding:8px 12px">
|
|
1509
|
+
<div style="color:${p.mut};font-size:10px">Human Commits</div>
|
|
1510
|
+
<div style="color:${p.fg};font-size:20px;font-weight:600">${totalHuman}</div>
|
|
1511
|
+
</div>
|
|
1512
|
+
<div style="flex:1;min-width:130px;border:1px solid ${p.bord};border-radius:6px;padding:8px 12px">
|
|
1513
|
+
<div style="color:${p.mut};font-size:10px">AI Share</div>
|
|
1514
|
+
<div style="color:${p.fg};font-size:20px;font-weight:600">${aiPct}%</div>
|
|
1515
|
+
</div>
|
|
1516
|
+
<div style="flex:1;min-width:130px;border:1px solid ${p.bord};border-radius:6px;padding:8px 12px">
|
|
1517
|
+
<div style="color:${p.mut};font-size:10px">AI Merge Rate</div>
|
|
1518
|
+
<div style="color:${p.ok};font-size:20px;font-weight:600">${aiMergeRate}%</div>
|
|
1519
|
+
</div>
|
|
1520
|
+
<div style="flex:1;min-width:130px;border:1px solid ${p.bord};border-radius:6px;padding:8px 12px">
|
|
1521
|
+
<div style="color:${p.mut};font-size:10px">Human Merge Rate</div>
|
|
1522
|
+
<div style="color:${p.fg};font-size:20px;font-weight:600">${humanMergeRate}%</div>
|
|
1523
|
+
</div>
|
|
1524
|
+
</div>
|
|
1525
|
+
${footnote(`Source: attribution store (DDB query at render time). ${totalAi + totalHuman} commits in range.`, p)}
|
|
1526
|
+
`;
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
// ---- View: commits-bar (just the stacked bar chart, no KPIs or merge rate) ----
|
|
1530
|
+
|
|
1531
|
+
async function renderCommitsBar(fromIso: string, toIso: string, days: number, p: Palette): Promise<string> {
|
|
1532
|
+
let data: any;
|
|
1533
|
+
try {
|
|
1534
|
+
data = await invokeReceiver('/v1/commits-daily', `from=${fromIso.slice(0, 10)}&to=${toIso.slice(0, 10)}`);
|
|
1535
|
+
} catch (err) {
|
|
1536
|
+
return emptyState('commit trend', `Attribution store unreachable (${(err as Error).message}).`, p);
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
const dayBuckets: Array<{ date: string; ai: number; human: number }> = data?.days ?? [];
|
|
1540
|
+
if (dayBuckets.length === 0) {
|
|
1541
|
+
return emptyState('commit trend', 'No COMMIT# items in the selected range. Run `codeburn sync push --attribution` or merge a PR with prism-ai-metrics.yml.', p);
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
const useWeekly = days > 21;
|
|
1545
|
+
type Bucket = { label: string; ai: number; human: number };
|
|
1546
|
+
let buckets: Bucket[];
|
|
1547
|
+
if (useWeekly) {
|
|
1548
|
+
const weeks = new Map<string, Bucket>();
|
|
1549
|
+
for (const d of dayBuckets) {
|
|
1550
|
+
const dt = new Date(d.date);
|
|
1551
|
+
const weekStart = new Date(dt);
|
|
1552
|
+
weekStart.setDate(dt.getDate() - dt.getDay());
|
|
1553
|
+
const key = weekStart.toISOString().slice(0, 10);
|
|
1554
|
+
let w = weeks.get(key);
|
|
1555
|
+
if (!w) { w = { label: key, ai: 0, human: 0 }; weeks.set(key, w); }
|
|
1556
|
+
w.ai += d.ai; w.human += d.human;
|
|
1557
|
+
}
|
|
1558
|
+
buckets = [...weeks.values()].sort((a, b) => a.label.localeCompare(b.label));
|
|
1559
|
+
} else {
|
|
1560
|
+
buckets = dayBuckets.map(d => ({ label: d.date, ai: d.ai, human: d.human }));
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
const totalAi = buckets.reduce((s, b) => s + b.ai, 0);
|
|
1564
|
+
const totalHuman = buckets.reduce((s, b) => s + b.human, 0);
|
|
1565
|
+
const chartW = 500;
|
|
1566
|
+
const chartH = 120;
|
|
1567
|
+
const barW = Math.max(4, Math.min(24, Math.floor((chartW - 20) / buckets.length) - 2));
|
|
1568
|
+
const maxCommits = Math.max(...buckets.map(b => b.ai + b.human), 1);
|
|
1569
|
+
|
|
1570
|
+
const barsSvg = buckets.map((b, i) => {
|
|
1571
|
+
const x = 10 + i * (barW + 2);
|
|
1572
|
+
const totalH = ((b.ai + b.human) / maxCommits) * (chartH - 10);
|
|
1573
|
+
const aiH = (b.ai / maxCommits) * (chartH - 10);
|
|
1574
|
+
const humanH = totalH - aiH;
|
|
1575
|
+
const humanY = chartH - totalH;
|
|
1576
|
+
const aiY = humanY + humanH;
|
|
1577
|
+
return `<rect x="${x}" y="${humanY}" width="${barW}" height="${humanH}" fill="${p.mut}" opacity="0.5"/>` +
|
|
1578
|
+
`<rect x="${x}" y="${aiY}" width="${barW}" height="${aiH}" fill="${p.accent}"/>`;
|
|
1579
|
+
}).join('');
|
|
1580
|
+
|
|
1581
|
+
const periodLabel = useWeekly ? 'weekly' : 'daily';
|
|
1582
|
+
return `
|
|
1583
|
+
<div style="margin-bottom:4px;color:${p.mut};font-size:10px">
|
|
1584
|
+
Commits ${periodLabel} · <span style="color:${p.accent}">■</span> AI (${totalAi}) · <span style="opacity:0.5">■</span> Human (${totalHuman})
|
|
1585
|
+
</div>
|
|
1586
|
+
<svg width="${chartW}" height="${chartH}" style="display:block">${barsSvg}</svg>
|
|
1587
|
+
${footnote(`Source: attribution store. ${totalAi + totalHuman} commits in range.`, p)}
|
|
1588
|
+
`;
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
// ---- View: ai-share-kpi (single big-number KPI for AI share %) ----
|
|
1592
|
+
|
|
1593
|
+
async function renderAiShareKpi(fromIso: string, toIso: string, p: Palette): Promise<string> {
|
|
1594
|
+
let report: any;
|
|
1595
|
+
try {
|
|
1596
|
+
report = await fetchProductivity(fromIso, toIso);
|
|
1597
|
+
} catch {
|
|
1598
|
+
return emptyState('AI share', 'Attribution store unreachable.', p);
|
|
1599
|
+
}
|
|
1600
|
+
const aiSharePct = report?.totals?.ratios?.aiSharePct ?? null;
|
|
1601
|
+
const ai = report?.totals?.commits?.ai ?? 0;
|
|
1602
|
+
const total = report?.totals?.commits?.total ?? 0;
|
|
1603
|
+
const color = aiSharePct === null ? p.mut : aiSharePct >= 30 ? p.ok : p.warn;
|
|
1604
|
+
return `
|
|
1605
|
+
<div style="text-align:center;padding:12px">
|
|
1606
|
+
<div style="color:${p.mut};font-size:11px">AI Share of Commits</div>
|
|
1607
|
+
<div style="color:${color};font-size:36px;font-weight:700;margin:4px 0">${aiSharePct !== null ? `${aiSharePct.toFixed(0)}%` : '—'}</div>
|
|
1608
|
+
<div style="color:${p.mut};font-size:10px">${ai} AI / ${total} total · L2 ≥30%</div>
|
|
1609
|
+
</div>
|
|
1610
|
+
`;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
// ---- View: merge-rate-kpi (single big-number KPI for AI merge rate %) ----
|
|
1614
|
+
|
|
1615
|
+
async function renderMergeRateKpi(fromIso: string, toIso: string, p: Palette): Promise<string> {
|
|
1616
|
+
let report: any;
|
|
1617
|
+
try {
|
|
1618
|
+
report = await fetchProductivity(fromIso, toIso);
|
|
1619
|
+
} catch {
|
|
1620
|
+
return emptyState('merge rate', 'Attribution store unreachable.', p);
|
|
1621
|
+
}
|
|
1622
|
+
const mergeRatePct = report?.totals?.ratios?.mergeRatePct ?? null;
|
|
1623
|
+
const mergedAi = report?.totals?.commits?.mergedAi ?? 0;
|
|
1624
|
+
const ai = report?.totals?.commits?.ai ?? 0;
|
|
1625
|
+
const color = mergeRatePct === null ? p.mut : mergeRatePct >= 45 ? p.ok : mergeRatePct >= 20 ? p.warn : p.danger;
|
|
1626
|
+
return `
|
|
1627
|
+
<div style="text-align:center;padding:12px">
|
|
1628
|
+
<div style="color:${p.mut};font-size:11px">AI Merge Rate</div>
|
|
1629
|
+
<div style="color:${color};font-size:36px;font-weight:700;margin:4px 0">${mergeRatePct !== null ? `${mergeRatePct.toFixed(0)}%` : '—'}</div>
|
|
1630
|
+
<div style="color:${p.mut};font-size:10px">${mergedAi} merged / ${ai} AI commits · L4 ≥45%</div>
|
|
1631
|
+
</div>
|
|
1632
|
+
`;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
// ---- View: merge-rate-trend (line chart of merge rate over time) ----
|
|
1636
|
+
|
|
1637
|
+
async function renderMergeRateTrend(fromIso: string, toIso: string, days: number, p: Palette): Promise<string> {
|
|
1638
|
+
let data: any;
|
|
1639
|
+
try {
|
|
1640
|
+
data = await invokeReceiver('/v1/commits-daily', `from=${fromIso.slice(0, 10)}&to=${toIso.slice(0, 10)}`);
|
|
1641
|
+
} catch (err) {
|
|
1642
|
+
return emptyState('merge rate trend', `Attribution store unreachable (${(err as Error).message}).`, p);
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
const dayBuckets: Array<{ date: string; ai: number; human: number; mergedAi: number; mergedHuman: number }> = data?.days ?? [];
|
|
1646
|
+
if (dayBuckets.length === 0) {
|
|
1647
|
+
return emptyState('merge rate trend', 'No commit data in range.', p);
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
const useWeekly = days > 21;
|
|
1651
|
+
type Bucket = { label: string; ai: number; human: number; mergedAi: number; mergedHuman: number };
|
|
1652
|
+
let buckets: Bucket[];
|
|
1653
|
+
if (useWeekly) {
|
|
1654
|
+
const weeks = new Map<string, Bucket>();
|
|
1655
|
+
for (const d of dayBuckets) {
|
|
1656
|
+
const dt = new Date(d.date);
|
|
1657
|
+
const weekStart = new Date(dt);
|
|
1658
|
+
weekStart.setDate(dt.getDate() - dt.getDay());
|
|
1659
|
+
const key = weekStart.toISOString().slice(0, 10);
|
|
1660
|
+
let w = weeks.get(key);
|
|
1661
|
+
if (!w) { w = { label: key, ai: 0, human: 0, mergedAi: 0, mergedHuman: 0 }; weeks.set(key, w); }
|
|
1662
|
+
w.ai += d.ai; w.human += d.human; w.mergedAi += d.mergedAi; w.mergedHuman += d.mergedHuman;
|
|
1663
|
+
}
|
|
1664
|
+
buckets = [...weeks.values()].sort((a, b) => a.label.localeCompare(b.label));
|
|
1665
|
+
} else {
|
|
1666
|
+
buckets = dayBuckets.map(d => ({ label: d.date, ...d }));
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
const chartW = 500;
|
|
1670
|
+
const chartH = 100;
|
|
1671
|
+
const step = buckets.length > 1 ? (chartW - 20) / (buckets.length - 1) : 0;
|
|
1672
|
+
|
|
1673
|
+
const aiRates = buckets.map(b => b.ai > 0 ? (b.mergedAi / b.ai) * 100 : null);
|
|
1674
|
+
const humanRates = buckets.map(b => b.human > 0 ? (b.mergedHuman / b.human) * 100 : null);
|
|
1675
|
+
|
|
1676
|
+
const drawLine = (rates: (number | null)[], color: string): string => {
|
|
1677
|
+
const pts = rates.map((v, i) => v !== null ? { x: 10 + i * step, y: chartH - 5 - (v / 100) * (chartH - 10) } : null)
|
|
1678
|
+
.filter(Boolean) as { x: number; y: number }[];
|
|
1679
|
+
if (pts.length < 2) return '';
|
|
1680
|
+
return `<polyline points="${pts.map(pt => `${pt.x.toFixed(1)},${pt.y.toFixed(1)}`).join(' ')}" fill="none" stroke="${color}" stroke-width="2"/>`;
|
|
1681
|
+
};
|
|
1682
|
+
|
|
1683
|
+
// Summary stats
|
|
1684
|
+
const totalAi = buckets.reduce((s, b) => s + b.ai, 0);
|
|
1685
|
+
const totalMergedAi = buckets.reduce((s, b) => s + b.mergedAi, 0);
|
|
1686
|
+
const totalHuman = buckets.reduce((s, b) => s + b.human, 0);
|
|
1687
|
+
const totalMergedHuman = buckets.reduce((s, b) => s + b.mergedHuman, 0);
|
|
1688
|
+
const aiOverall = totalAi > 0 ? ((totalMergedAi / totalAi) * 100).toFixed(0) : '—';
|
|
1689
|
+
const humanOverall = totalHuman > 0 ? ((totalMergedHuman / totalHuman) * 100).toFixed(0) : '—';
|
|
1690
|
+
|
|
1691
|
+
const periodLabel = useWeekly ? 'weekly' : 'daily';
|
|
1692
|
+
return `
|
|
1693
|
+
<div style="margin-bottom:4px;color:${p.mut};font-size:10px">
|
|
1694
|
+
Merge rate ${periodLabel} · <span style="color:${p.accent}">— AI ${aiOverall}%</span> · <span style="color:${p.mut}">— Human ${humanOverall}%</span>
|
|
1695
|
+
</div>
|
|
1696
|
+
<svg width="${chartW}" height="${chartH}" style="display:block">
|
|
1697
|
+
<line x1="10" y1="${chartH - 5}" x2="${chartW - 10}" y2="${chartH - 5}" stroke="${p.bord}" stroke-width="0.5"/>
|
|
1698
|
+
<line x1="10" y1="${(chartH - 5) / 2}" x2="${chartW - 10}" y2="${(chartH - 5) / 2}" stroke="${p.bord}" stroke-width="0.5" stroke-dasharray="3"/>
|
|
1699
|
+
${drawLine(aiRates, p.accent)}
|
|
1700
|
+
${drawLine(humanRates, p.mut)}
|
|
1701
|
+
</svg>
|
|
1702
|
+
${footnote(`Source: attribution store. 50% line shown dashed.`, p)}
|
|
1703
|
+
`;
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1446
1706
|
// ---- Handler ----
|
|
1447
1707
|
|
|
1448
1708
|
export async function handler(event: WidgetEvent): Promise<string> {
|
|
@@ -1474,6 +1734,11 @@ export async function handler(event: WidgetEvent): Promise<string> {
|
|
|
1474
1734
|
case 'ciso-risk': body = await renderCisoRisk(fromIso, toIso, p); break;
|
|
1475
1735
|
case 'ciso-shiftleft': body = await renderCisoShiftleft(fromIso, toIso, p); break;
|
|
1476
1736
|
case 'ciso-classes': body = await renderCisoClasses(fromIso, toIso, p); break;
|
|
1737
|
+
case 'commits-trend': body = await renderCommitsTrend(fromIso, toIso, days, p); break;
|
|
1738
|
+
case 'commits-bar': body = await renderCommitsBar(fromIso, toIso, days, p); break;
|
|
1739
|
+
case 'ai-share-kpi': body = await renderAiShareKpi(fromIso, toIso, p); break;
|
|
1740
|
+
case 'merge-rate-kpi': body = await renderMergeRateKpi(fromIso, toIso, p); break;
|
|
1741
|
+
case 'merge-rate-trend': body = await renderMergeRateTrend(fromIso, toIso, days, p); break;
|
|
1477
1742
|
default: body = `<div style="color:${p.danger}">Unknown view: ${esc(view)}</div>`;
|
|
1478
1743
|
}
|
|
1479
1744
|
return `<div style="font-family:'Amazon Ember',Helvetica,Arial,sans-serif;color:${p.fg};font-size:13px">${body}</div>`;
|
|
@@ -240,6 +240,9 @@ export class MetricsPipelineStack extends cdk.Stack {
|
|
|
240
240
|
EVENTS_TABLE: this.eventsTable.tableName,
|
|
241
241
|
METADATA_TABLE: this.metadataTable.tableName,
|
|
242
242
|
METRIC_NAMESPACE: 'PRISM/D1/Velocity',
|
|
243
|
+
// When a prism.d1.pr event arrives, seed COMMIT# items with
|
|
244
|
+
// ai_origin=human for each SHA. Codeburn upgrades to ai-generated later.
|
|
245
|
+
AI_USAGE_TABLE: this.aiUsageTable.tableName,
|
|
243
246
|
// When the OTEL collector is enabled, the otel-metrics-publisher owns
|
|
244
247
|
// AIInputTokens/AIOutputTokens/AICostUSD — the processor skips its
|
|
245
248
|
// trailer-sourced copies to avoid double-counting.
|
|
@@ -263,6 +266,8 @@ export class MetricsPipelineStack extends cdk.Stack {
|
|
|
263
266
|
// -------------------------------------------------------
|
|
264
267
|
this.eventsTable.grantWriteData(metricsProcessor);
|
|
265
268
|
this.metadataTable.grantWriteData(metricsProcessor);
|
|
269
|
+
// Seeding COMMIT# items as human default — conditional writes only, no read needed.
|
|
270
|
+
this.aiUsageTable.grantWriteData(metricsProcessor);
|
|
266
271
|
|
|
267
272
|
metricsProcessor.addToRolePolicy(
|
|
268
273
|
new iam.PolicyStatement({
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* install-coding-agent — put the PRISM coding agent into the current repository.
|
|
3
|
+
*
|
|
4
|
+
* What lands in the repo, and nothing else:
|
|
5
|
+
*
|
|
6
|
+
* .coding-agent/ THEIRS. config.json, prompt.md, and fixtures/,
|
|
7
|
+
* which are hand-written, reviewed, and
|
|
8
|
+
* irreplaceable. --uninstall never deletes
|
|
9
|
+
* fixtures/ or prompt.md, and a re-install never
|
|
10
|
+
* overwrites either.
|
|
11
|
+
* .tool-versions the toolchain pin mise reads in the harness
|
|
12
|
+
* .github/workflows/… the issue → fix → PR workflow (optional)
|
|
13
|
+
*
|
|
14
|
+
* The agent source is NOT vendored. It lives in the sample repo, and the agent
|
|
15
|
+
* itself runs in an AgentCore harness deployed once into the org's own account;
|
|
16
|
+
* the workflow fetches only the thin orchestrator client at run time, pinned by
|
|
17
|
+
* the PRISM_AGENT_REF variable. So a fix to the agent reaches every repo without
|
|
18
|
+
* an N-repo migration.
|
|
19
|
+
*
|
|
20
|
+
* An earlier version copied agent.py, config.py, system_prompt.py and tools/ into
|
|
21
|
+
* .prism/coding-agent/. That is gone, and its removal fixed more than it cost:
|
|
22
|
+
* the vendored set never included agentcore/, which is the only thing the
|
|
23
|
+
* workflow actually runs, so `python -m agentcore.invoke` could not have resolved
|
|
24
|
+
* in any repo the installer touched. The copy was both redundant and broken --
|
|
25
|
+
* unnoticed because no CI run had exercised it.
|
|
26
|
+
*
|
|
27
|
+
* Eval fixtures are shipped as references, never as runnable work. The harness
|
|
28
|
+
* (run_eval.py) is repo-agnostic; fixtures never are — each one names real files
|
|
29
|
+
* and real bugs in one specific repository. Copying sample-app's fixtures in as
|
|
30
|
+
* live fixtures would produce an eval that fails on missing paths, which reads as
|
|
31
|
+
* a broken agent rather than as fixtures pointed at the wrong codebase. They land
|
|
32
|
+
* under .coding-agent/fixtures/examples/ instead, which the harness's
|
|
33
|
+
* non-recursive glob never reaches, alongside a template to copy.
|
|
34
|
+
*/
|
|
35
|
+
declare const _default: {
|
|
36
|
+
description: string;
|
|
37
|
+
options: ({
|
|
38
|
+
flags: string;
|
|
39
|
+
description: string;
|
|
40
|
+
default?: undefined;
|
|
41
|
+
} | {
|
|
42
|
+
flags: string;
|
|
43
|
+
description: string;
|
|
44
|
+
default: string;
|
|
45
|
+
})[];
|
|
46
|
+
action(opts: {
|
|
47
|
+
testCommand?: string;
|
|
48
|
+
buildCommand?: string;
|
|
49
|
+
lintCommand?: string;
|
|
50
|
+
agentEmail?: string;
|
|
51
|
+
agentName?: string;
|
|
52
|
+
maxAttempts?: string;
|
|
53
|
+
model?: string;
|
|
54
|
+
region?: string;
|
|
55
|
+
workflow?: boolean;
|
|
56
|
+
yes?: boolean;
|
|
57
|
+
uninstall?: boolean;
|
|
58
|
+
}): Promise<void>;
|
|
59
|
+
};
|
|
60
|
+
export default _default;
|
|
61
|
+
//# sourceMappingURL=install-coding-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-coding-agent.d.ts","sourceRoot":"","sources":["../../../../src/commands/bootstrapper/install-coding-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;;;;;;;;;;;;iBAibkB;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAClE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;KACzF;;AApBH,wBAsNE"}
|