@hackerrank/astra-cli 0.1.14 → 0.1.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hackerrank/astra-cli",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "Minimal zero-dependency AI coding agent for the HackerRank AI Gateway.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/report.html CHANGED
@@ -56,6 +56,11 @@
56
56
  .criterion-cell.pass { background:rgba(57,174,118,.10); }
57
57
  .criterion-cell.fail { background:rgba(216,86,104,.10); }
58
58
  .criterion-cell.na { color:var(--muted); }
59
+ .criterion-group th { background:var(--wash); color:var(--ink); cursor:default; font-size:12px; letter-spacing:0; text-transform:none; padding:10px 8px; }
60
+ .result-badge { display:inline-block; min-width:64px; padding:3px 8px; border-radius:999px; font-size:11px; font-weight:700; text-align:center; }
61
+ .result-badge.passed { background:rgba(57,174,118,.14); color:#16734a; }
62
+ .result-badge.failed { background:rgba(216,86,104,.14); color:#ad3042; }
63
+ .result-badge.unscored { background:var(--wash); color:var(--muted); }
59
64
  footer { color: var(--muted); font-size: 11.5px; margin-top: 40px; text-align: center; }
60
65
  svg text { fill: var(--muted); font-size: 10.5px; }
61
66
  .axis line, .axis path { stroke: var(--line); }
@@ -318,14 +323,35 @@
318
323
  var selected = matrix.models.find(function (model) {
319
324
  return matrix.criteria.some(function (criterion) { return criterion.cells[model]; });
320
325
  }) || matrix.models[0] || "";
326
+ var GROUP_TITLES = {
327
+ "scim.discovery-auth": "Discovery & authentication",
328
+ "scim.read-existing": "Reading existing resources",
329
+ "scim.create-user": "User creation",
330
+ "scim.user-lifecycle": "User lifecycle",
331
+ "scim.group-lifecycle": "Group lifecycle",
332
+ "scim.membership": "Group membership",
333
+ "scim.errors-atomicity": "Errors & atomicity"
334
+ };
335
+ function groupTitle(parentId) {
336
+ return GROUP_TITLES[parentId] || "Other checks";
337
+ }
321
338
  function draw() {
322
- container.innerHTML = '<thead><tr><th>Test case</th><th>Available</th><th>Earned</th><th>Result</th></tr></thead><tbody>' + matrix.criteria.map(function (criterion) {
323
- var cell = criterion.cells[selected];
324
- if (!cell) return '<tr><td>' + esc(criterion.title || criterion.id) + '</td><td class="n-a">NA</td><td class="n-a">NA</td><td class="n-a">Unscored</td></tr>';
325
- var max = cell.maxPoints || 0, earned = cell.earnedPoints || 0;
326
- var status = cell.passed === cell.total ? 'Passed' : (cell.error ? 'Errored' : cell.blocked ? 'Blocked' : 'Failed');
327
- return '<tr><td>' + esc(criterion.title || criterion.id) + '</td><td>' + fmt1(max) + '</td><td>' + fmt1(earned) + '</td><td>' + esc(status) + '</td></tr>';
328
- }).join('') + '</tbody>';
339
+ var groups = {};
340
+ matrix.criteria.forEach(function (criterion) {
341
+ var parentId = criterion.parentId || criterion.id;
342
+ (groups[parentId] || (groups[parentId] = [])).push(criterion);
343
+ });
344
+ var bodies = Object.keys(groups).sort().map(function (parentId) {
345
+ var rows = groups[parentId].map(function (criterion) {
346
+ var cell = criterion.cells[selected];
347
+ if (!cell) return '<tr><td>' + esc(criterion.title || criterion.id) + '</td><td class="n-a">NA</td><td><span class="result-badge unscored">Unscored</span></td></tr>';
348
+ var max = cell.maxPoints || 0, earned = cell.earnedPoints || 0;
349
+ var passed = cell.passed === cell.total;
350
+ return '<tr><td>' + esc(criterion.title || criterion.id) + '</td><td>' + fmt1(earned) + ' / ' + fmt1(max) + '</td><td><span class="result-badge ' + (passed ? 'passed' : 'failed') + '">' + (passed ? 'Passed' : 'Failed') + '</span></td></tr>';
351
+ }).join('');
352
+ return '<tbody><tr class="criterion-group"><th colspan="3">' + esc(groupTitle(parentId)) + '</th></tr>' + rows + '</tbody>';
353
+ }).join('');
354
+ container.innerHTML = '<thead><tr><th>Test case</th><th>Points</th><th>Result</th></tr></thead>' + bodies;
329
355
  }
330
356
  matrix.models.forEach(function (model) {
331
357
  var option = el("option", { value: model }, esc(model));
package/src/report.js CHANGED
@@ -507,11 +507,13 @@ function flattenCriteria(criteria) {
507
507
  if (!Array.isArray(criterion?.checks) || criterion.checks.length === 0) {
508
508
  return [criterion];
509
509
  }
510
+ const leafWeight = Math.max(0, Number(criterion.weight) || 0) / criterion.checks.length;
510
511
  return criterion.checks.map((check, index) => ({
511
512
  id: `${criterion.id}.${check.name || `check-${index + 1}`}`,
512
513
  title: check.description || check.name || criterion.title || criterion.id,
513
514
  status: check.passed === true ? "passed" : check.status === "blocked" ? "blocked" : check.status === "error" ? "error" : "failed",
514
515
  parentId: criterion.id,
516
+ weight: leafWeight,
515
517
  }));
516
518
  });
517
519
  }
@@ -540,7 +542,11 @@ function buildVerifierMatrix(runs) {
540
542
  const byCriterion = new Map();
541
543
  for (const run of runs) {
542
544
  for (const criterion of run.criteria || []) {
543
- if (!byCriterion.has(criterion.id)) byCriterion.set(criterion.id, { title: criterion.title || criterion.id, byModel: new Map() });
545
+ if (!byCriterion.has(criterion.id)) byCriterion.set(criterion.id, {
546
+ title: criterion.title || criterion.id,
547
+ parentId: criterion.parentId || criterion.id,
548
+ byModel: new Map(),
549
+ });
544
550
  const entry = byCriterion.get(criterion.id);
545
551
  const byModel = entry.byModel;
546
552
  if (!byModel.has(run.slug)) byModel.set(run.slug, { passed: 0, failed: 0, blocked: 0, error: 0, total: 0, maxPoints: 0, earnedPoints: 0 });
@@ -560,6 +566,7 @@ function buildVerifierMatrix(runs) {
560
566
  criteria: [...byCriterion.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([id, entry]) => ({
561
567
  id,
562
568
  title: entry.title,
569
+ parentId: entry.parentId,
563
570
  cells: Object.fromEntries(models.map((model) => [model, entry.byModel.get(model) || null])),
564
571
  })),
565
572
  };