bradsansnow commited on
Commit
16ff884
·
1 Parent(s): 1759d72

feat: add blocked sync notification builder

Browse files
.claude/skills/sync-nowai-leaderboard/lib/blocked-notify.mjs ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const REASON_LABELS = {
2
+ 'dirty-worktree': 'Worktree has uncommitted files',
3
+ 'wrong-branch': 'Current branch is not main',
4
+ 'fetch-failed': 'git fetch origin main failed',
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
+ }
11
+
12
+ export function buildBlockedNotification({ reason, facts = [], now = new Date() }) {
13
+ const label = REASON_LABELS[reason];
14
+ if (!label) throw new Error(`Unknown blocked reason: ${reason}`);
15
+
16
+ return {
17
+ kind: 'warning',
18
+ title: '⚠️ Leaderboard sync blocked',
19
+ subtitle: blockedSubtitle(now),
20
+ facts: [['Reason', label], ...facts],
21
+ };
22
+ }
23
+
24
+ export function parseBlockedCliArgs(argv) {
25
+ const facts = [];
26
+ let reason;
27
+
28
+ for (let i = 0; i < argv.length; i++) {
29
+ const token = argv[i];
30
+
31
+ if (token === '--reason') {
32
+ reason = argv[++i];
33
+ continue;
34
+ }
35
+
36
+ if (token === '--fact') {
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
+
44
+ throw new Error(`Unknown argument: ${token}`);
45
+ }
46
+
47
+ if (!reason) throw new Error('Missing required --reason');
48
+
49
+ // Reuse payload validation so the CLI parser and notifier stay in lockstep.
50
+ buildBlockedNotification({ reason, facts, now: new Date(0) });
51
+
52
+ return { reason, facts };
53
+ }
.claude/skills/sync-nowai-leaderboard/test/blocked-notify.test.mjs ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {
4
+ buildBlockedNotification,
5
+ parseBlockedCliArgs,
6
+ } from '../lib/blocked-notify.mjs';
7
+
8
+ test('buildBlockedNotification maps dirty-worktree to a warning card payload', () => {
9
+ const out = buildBlockedNotification({
10
+ reason: 'dirty-worktree',
11
+ facts: [['Branch', 'main'], ['Files', '3']],
12
+ now: new Date('2026-07-01T21:00:00Z'),
13
+ });
14
+
15
+ assert.equal(out.kind, 'warning');
16
+ assert.equal(out.title, '⚠️ Leaderboard sync blocked');
17
+ assert.equal(out.subtitle, 'NowAI-Bench Sync · 2026-07-01 21:00 UTC');
18
+ assert.deepEqual(out.facts, [
19
+ ['Reason', 'Worktree has uncommitted files'],
20
+ ['Branch', 'main'],
21
+ ['Files', '3'],
22
+ ]);
23
+ });
24
+
25
+ test('parseBlockedCliArgs accepts repeated --fact pairs', () => {
26
+ const out = parseBlockedCliArgs([
27
+ '--reason', 'behind-or-diverged',
28
+ '--fact', 'Branch=main',
29
+ '--fact', 'RemoteAhead=2',
30
+ '--fact', 'LocalAhead=0',
31
+ ]);
32
+
33
+ assert.equal(out.reason, 'behind-or-diverged');
34
+ assert.deepEqual(out.facts, [
35
+ ['Branch', 'main'],
36
+ ['RemoteAhead', '2'],
37
+ ['LocalAhead', '0'],
38
+ ]);
39
+ });
40
+
41
+ test('parseBlockedCliArgs rejects unknown blocked reasons', () => {
42
+ assert.throws(
43
+ () => parseBlockedCliArgs(['--reason', 'mystery-reason']),
44
+ /Unknown blocked reason: mystery-reason/,
45
+ );
46
+ });
47
+
48
+ test('parseBlockedCliArgs rejects malformed fact entries', () => {
49
+ assert.throws(
50
+ () => parseBlockedCliArgs(['--reason', 'wrong-branch', '--fact', 'Branch']),
51
+ /Invalid --fact, expected key=value: Branch/,
52
+ );
53
+ });