bradsansnow commited on
Commit
447d2ec
路
1 Parent(s): 16ff884

fix: normalize blocked facts and reuse subtitle helper

Browse files
.claude/skills/sync-nowai-leaderboard/lib/blocked-notify.mjs CHANGED
@@ -5,6 +5,16 @@ const REASON_LABELS = {
5
  'behind-or-diverged': 'Local main is behind or diverged from origin/main',
6
  };
7
 
 
 
 
 
 
 
 
 
 
 
8
  export function blockedSubtitle(now = new Date()) {
9
  return 'NowAI-Bench Sync 路 ' + now.toISOString().replace('T', ' ').slice(0, 16) + ' UTC';
10
  }
@@ -21,6 +31,12 @@ export function buildBlockedNotification({ reason, facts = [], now = new Date()
21
  };
22
  }
23
 
 
 
 
 
 
 
24
  export function parseBlockedCliArgs(argv) {
25
  const facts = [];
26
  let reason;
@@ -37,7 +53,7 @@ export function parseBlockedCliArgs(argv) {
37
  const raw = argv[++i] ?? '';
38
  const eq = raw.indexOf('=');
39
  if (eq <= 0) throw new Error(`Invalid --fact, expected key=value: ${raw}`);
40
- facts.push([raw.slice(0, eq), raw.slice(eq + 1)]);
41
  continue;
42
  }
43
 
 
5
  'behind-or-diverged': 'Local main is behind or diverged from origin/main',
6
  };
7
 
8
+ const FACT_LABELS = {
9
+ branch: 'Branch',
10
+ expected: 'Expected',
11
+ files: 'Files',
12
+ remote: 'Remote',
13
+ error: 'Error',
14
+ remoteahead: 'RemoteAhead',
15
+ localahead: 'LocalAhead',
16
+ };
17
+
18
  export function blockedSubtitle(now = new Date()) {
19
  return 'NowAI-Bench Sync 路 ' + now.toISOString().replace('T', ' ').slice(0, 16) + ' UTC';
20
  }
 
31
  };
32
  }
33
 
34
+ function normalizeFactKey(rawKey) {
35
+ const key = rawKey.trim();
36
+ const canonical = key.replace(/[\s_-]+/g, '').toLowerCase();
37
+ return FACT_LABELS[canonical] ?? key;
38
+ }
39
+
40
  export function parseBlockedCliArgs(argv) {
41
  const facts = [];
42
  let reason;
 
53
  const raw = argv[++i] ?? '';
54
  const eq = raw.indexOf('=');
55
  if (eq <= 0) throw new Error(`Invalid --fact, expected key=value: ${raw}`);
56
+ facts.push([normalizeFactKey(raw.slice(0, eq)), raw.slice(eq + 1)]);
57
  continue;
58
  }
59
 
.claude/skills/sync-nowai-leaderboard/sync.mjs CHANGED
@@ -6,6 +6,7 @@ import { createHash } from 'node:crypto';
6
  import { execFileSync } from 'node:child_process';
7
  import { join, dirname } from 'node:path';
8
  import { buildLeaderboard, hasChanges, diffBoards, validate } from './lib/transform.mjs';
 
9
  import { postTeams } from './lib/teams.mjs';
10
 
11
  const STAGING_URL = 'https://huggingface.co/spaces/ServiceNow-AI/NowAI-Bench-Staging';
@@ -39,11 +40,6 @@ async function fetchText(url, timeoutMs = FETCH_TIMEOUT_MS) {
39
  }
40
  }
41
 
42
- // Shared subtitle line for every Teams card: "NowAI-Bench Sync 路 2026-06-12 14:00 UTC".
43
- function subtitle() {
44
- return 'NowAI-Bench Sync 路 ' + new Date().toISOString().replace('T', ' ').slice(0, 16) + ' UTC';
45
- }
46
-
47
  // Convenience: an error/abort card with a consistent title.
48
  function notifyFailure(facts, kind = 'error') {
49
  return postTeams({
 
6
  import { execFileSync } from 'node:child_process';
7
  import { join, dirname } from 'node:path';
8
  import { buildLeaderboard, hasChanges, diffBoards, validate } from './lib/transform.mjs';
9
+ import { blockedSubtitle as subtitle } from './lib/blocked-notify.mjs';
10
  import { postTeams } from './lib/teams.mjs';
11
 
12
  const STAGING_URL = 'https://huggingface.co/spaces/ServiceNow-AI/NowAI-Bench-Staging';
 
40
  }
41
  }
42
 
 
 
 
 
 
43
  // Convenience: an error/abort card with a consistent title.
44
  function notifyFailure(facts, kind = 'error') {
45
  return postTeams({
.claude/skills/sync-nowai-leaderboard/test/blocked-notify.test.mjs CHANGED
@@ -38,6 +38,24 @@ test('parseBlockedCliArgs accepts repeated --fact pairs', () => {
38
  ]);
39
  });
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  test('parseBlockedCliArgs rejects unknown blocked reasons', () => {
42
  assert.throws(
43
  () => parseBlockedCliArgs(['--reason', 'mystery-reason']),
 
38
  ]);
39
  });
40
 
41
+ test('parseBlockedCliArgs normalizes lowercase fact keys for stable payload titles', () => {
42
+ const parsed = parseBlockedCliArgs([
43
+ '--reason', 'dirty-worktree',
44
+ '--fact', 'branch=main',
45
+ '--fact', 'files=3',
46
+ ]);
47
+ const out = buildBlockedNotification({
48
+ ...parsed,
49
+ now: new Date('2026-07-01T21:00:00Z'),
50
+ });
51
+
52
+ assert.deepEqual(out.facts, [
53
+ ['Reason', 'Worktree has uncommitted files'],
54
+ ['Branch', 'main'],
55
+ ['Files', '3'],
56
+ ]);
57
+ });
58
+
59
  test('parseBlockedCliArgs rejects unknown blocked reasons', () => {
60
  assert.throws(
61
  () => parseBlockedCliArgs(['--reason', 'mystery-reason']),