@nerviq/cli 1.8.9 → 1.10.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.
@@ -1,214 +1,214 @@
1
- /**
2
- * Cursor Freshness Operationalization
3
- *
4
- * Release gates, recurring probes, propagation checklists,
5
- * and staleness blocking for Cursor surfaces.
6
- *
7
- * P0 sources from docs.cursor.com, propagation for rule format changes.
8
- */
9
-
10
- const { version } = require('../../package.json');
11
-
12
- /**
13
- * P0 sources that must be fresh before any Cursor release claim.
14
- */
15
- const P0_SOURCES = [
16
- {
17
- key: 'cursor-rules-docs',
18
- label: 'Cursor Rules Documentation',
19
- url: 'https://docs.cursor.com/context/rules-for-ai',
20
- stalenessThresholdDays: 30,
21
- verifiedAt: null,
22
- },
23
- {
24
- key: 'cursor-mdc-format',
25
- label: 'MDC Format Documentation',
26
- url: 'https://docs.cursor.com/context/rules-for-ai#rule-types',
27
- stalenessThresholdDays: 30,
28
- verifiedAt: null,
29
- },
30
- {
31
- key: 'cursor-mcp-docs',
32
- label: 'Cursor MCP Documentation',
33
- url: 'https://docs.cursor.com/context/model-context-protocol',
34
- stalenessThresholdDays: 30,
35
- verifiedAt: null,
36
- },
37
- {
38
- key: 'cursor-background-agents',
39
- label: 'Background Agents Documentation',
40
- url: 'https://docs.cursor.com/background-agent',
41
- stalenessThresholdDays: 14,
42
- verifiedAt: null,
43
- },
44
- {
45
- key: 'cursor-automations',
46
- label: 'Automations Documentation',
47
- url: 'https://docs.cursor.com/automations',
48
- stalenessThresholdDays: 14,
49
- verifiedAt: null,
50
- },
51
- {
52
- key: 'cursor-bugbot',
53
- label: 'BugBot Documentation',
54
- url: 'https://docs.cursor.com/bugbot',
55
- stalenessThresholdDays: 30,
56
- verifiedAt: null,
57
- },
58
- {
59
- key: 'cursor-privacy-mode',
60
- label: 'Cursor Privacy Mode Documentation',
61
- url: 'https://docs.cursor.com/account/privacy',
62
- stalenessThresholdDays: 30,
63
- verifiedAt: null,
64
- },
65
- {
66
- key: 'cursor-changelog',
67
- label: 'Cursor Changelog',
68
- url: 'https://changelog.cursor.com',
69
- stalenessThresholdDays: 14,
70
- verifiedAt: null,
71
- },
72
- {
73
- key: 'cursor-security',
74
- label: 'Cursor Security Documentation',
75
- url: 'https://docs.cursor.com/account/security',
76
- stalenessThresholdDays: 30,
77
- verifiedAt: null,
78
- },
79
- ];
80
-
81
- /**
82
- * Propagation checklist: when a Cursor source changes, these must update.
83
- */
84
- const PROPAGATION_CHECKLIST = [
85
- {
86
- trigger: 'MDC rule format change (new frontmatter fields, type behavior change)',
87
- targets: [
88
- 'src/cursor/config-parser.js — update VALID_MDC_FIELDS, detectRuleType, parseSimpleYaml',
89
- 'src/cursor/techniques.js — update rule validation checks (CU-A01..CU-A09)',
90
- 'src/cursor/context.js — update cursorRules() parsing and type detection',
91
- 'src/cursor/setup.js — update rule template generation',
92
- ],
93
- },
94
- {
95
- trigger: 'Background agent behavior change (environment.json format, VM config)',
96
- targets: [
97
- 'src/cursor/techniques.js — update background agent checks (CU-G01..CU-G05)',
98
- 'src/cursor/setup.js — update environment.json template',
99
- 'src/cursor/governance.js — update background-agent permission profile',
100
- ],
101
- },
102
- {
103
- trigger: 'Automation trigger format or behavior change',
104
- targets: [
105
- 'src/cursor/techniques.js — update automation checks (CU-H01..CU-H05)',
106
- 'src/cursor/context.js — update automationsConfig() parsing',
107
- 'src/cursor/governance.js — update automation permission profile and caveats',
108
- ],
109
- },
110
- {
111
- trigger: 'MCP configuration format change in .cursor/mcp.json',
112
- targets: [
113
- 'src/cursor/mcp-packs.js — update pack JSON projections and merge logic',
114
- 'src/cursor/techniques.js — update MCP checks (CU-E01..CU-E05)',
115
- 'src/cursor/context.js — update mcpConfig() parsing',
116
- 'src/cursor/config-parser.js — update validateMcpEnvVars',
117
- ],
118
- },
119
- {
120
- trigger: 'MCP tool limit change (currently ~40)',
121
- targets: [
122
- 'src/cursor/techniques.js — update CU-B02 threshold',
123
- 'src/cursor/governance.js — update mcp-tool-limit caveat',
124
- 'src/cursor/mcp-packs.js — update recommendation logic',
125
- ],
126
- },
127
- {
128
- trigger: 'BugBot feature update or autofix behavior change',
129
- targets: [
130
- 'src/cursor/techniques.js — update BugBot checks (CU-J01..CU-J04)',
131
- 'src/cursor/setup.js — update BugBot guide template',
132
- 'src/cursor/governance.js — update bugbot-review hook',
133
- ],
134
- },
135
- {
136
- trigger: 'Privacy Mode or security model change',
137
- targets: [
138
- 'src/cursor/techniques.js — update trust checks (CU-C01..CU-C09)',
139
- 'src/cursor/governance.js — update caveats and permission profiles',
140
- 'src/cursor/deep-review.js — update trust class detection',
141
- ],
142
- },
143
- {
144
- trigger: 'Design Mode feature update',
145
- targets: [
146
- 'src/cursor/setup.js — update Design Mode guide template',
147
- 'src/cursor/techniques.js — update CU-L01 modern features check',
148
- ],
149
- },
150
- ];
151
-
152
- /**
153
- * Release gate: check if all P0 sources are within staleness threshold.
154
- */
155
- function checkReleaseGate(sourceVerifications = {}) {
156
- const now = new Date();
157
- const results = P0_SOURCES.map(source => {
158
- const verifiedAt = sourceVerifications[source.key]
159
- ? new Date(sourceVerifications[source.key])
160
- : source.verifiedAt ? new Date(source.verifiedAt) : null;
161
-
162
- if (!verifiedAt) {
163
- return { ...source, status: 'unverified', daysStale: null };
164
- }
165
-
166
- const daysSince = Math.floor((now - verifiedAt) / (1000 * 60 * 60 * 24));
167
- const isStale = daysSince > source.stalenessThresholdDays;
168
-
169
- return { ...source, verifiedAt: verifiedAt.toISOString(), daysStale: daysSince, status: isStale ? 'stale' : 'fresh' };
170
- });
171
-
172
- return {
173
- ready: results.every(r => r.status === 'fresh'),
174
- stale: results.filter(r => r.status === 'stale' || r.status === 'unverified'),
175
- fresh: results.filter(r => r.status === 'fresh'),
176
- results,
177
- };
178
- }
179
-
180
- function formatReleaseGate(gateResult) {
181
- const lines = [
182
- `Cursor Freshness Gate (nerviq v${version})`,
183
- '═══════════════════════════════════════',
184
- '',
185
- `Status: ${gateResult.ready ? 'READY' : 'BLOCKED'}`,
186
- `Fresh: ${gateResult.fresh.length}/${gateResult.results.length}`,
187
- '',
188
- ];
189
-
190
- for (const result of gateResult.results) {
191
- const icon = result.status === 'fresh' ? '✓' : result.status === 'stale' ? '✗' : '?';
192
- const age = result.daysStale !== null ? ` (${result.daysStale}d ago)` : ' (unverified)';
193
- lines.push(` ${icon} ${result.label}${age} — threshold: ${result.stalenessThresholdDays}d`);
194
- }
195
-
196
- if (!gateResult.ready) {
197
- lines.push('', 'Action required: verify stale/unverified sources before claiming release freshness.');
198
- }
199
-
200
- return lines.join('\n');
201
- }
202
-
203
- function getPropagationTargets(triggerKeyword) {
204
- const keyword = triggerKeyword.toLowerCase();
205
- return PROPAGATION_CHECKLIST.filter(item => item.trigger.toLowerCase().includes(keyword));
206
- }
207
-
208
- module.exports = {
209
- P0_SOURCES,
210
- PROPAGATION_CHECKLIST,
211
- checkReleaseGate,
212
- formatReleaseGate,
213
- getPropagationTargets,
214
- };
1
+ /**
2
+ * Cursor Freshness Operationalization
3
+ *
4
+ * Release gates, recurring probes, propagation checklists,
5
+ * and staleness blocking for Cursor surfaces.
6
+ *
7
+ * P0 sources from docs.cursor.com, propagation for rule format changes.
8
+ */
9
+
10
+ const { version } = require('../../package.json');
11
+
12
+ /**
13
+ * P0 sources that must be fresh before any Cursor release claim.
14
+ */
15
+ const P0_SOURCES = [
16
+ {
17
+ key: 'cursor-rules-docs',
18
+ label: 'Cursor Rules Documentation',
19
+ url: 'https://cursor.com/docs/rules',
20
+ stalenessThresholdDays: 30,
21
+ verifiedAt: '2026-04-07',
22
+ },
23
+ {
24
+ key: 'cursor-mdc-format',
25
+ label: 'MDC Format Documentation',
26
+ url: 'https://cursor.com/docs/rules',
27
+ stalenessThresholdDays: 30,
28
+ verifiedAt: '2026-04-07',
29
+ },
30
+ {
31
+ key: 'cursor-mcp-docs',
32
+ label: 'Cursor MCP Documentation',
33
+ url: 'https://cursor.com/docs/context/mcp',
34
+ stalenessThresholdDays: 30,
35
+ verifiedAt: '2026-04-07',
36
+ },
37
+ {
38
+ key: 'cursor-background-agents',
39
+ label: 'Cloud Agents Documentation',
40
+ url: 'https://cursor.com/docs/cloud-agent',
41
+ stalenessThresholdDays: 14,
42
+ verifiedAt: '2026-04-07',
43
+ },
44
+ {
45
+ key: 'cursor-automations',
46
+ label: 'Automations Documentation',
47
+ url: 'https://cursor.com/docs/cloud-agent/automations',
48
+ stalenessThresholdDays: 14,
49
+ verifiedAt: '2026-04-07',
50
+ },
51
+ {
52
+ key: 'cursor-bugbot',
53
+ label: 'BugBot Documentation',
54
+ url: 'https://cursor.com/docs/bugbot',
55
+ stalenessThresholdDays: 30,
56
+ verifiedAt: '2026-04-07',
57
+ },
58
+ {
59
+ key: 'cursor-privacy-mode',
60
+ label: 'Cursor Privacy & Data Governance',
61
+ url: 'https://cursor.com/docs/enterprise/privacy-and-data-governance',
62
+ stalenessThresholdDays: 30,
63
+ verifiedAt: '2026-04-07',
64
+ },
65
+ {
66
+ key: 'cursor-changelog',
67
+ label: 'Cursor Changelog',
68
+ url: 'https://cursor.com/changelog',
69
+ stalenessThresholdDays: 14,
70
+ verifiedAt: '2026-04-07',
71
+ },
72
+ {
73
+ key: 'cursor-security',
74
+ label: 'Cursor Agent Security',
75
+ url: 'https://cursor.com/docs/agent/security',
76
+ stalenessThresholdDays: 30,
77
+ verifiedAt: '2026-04-07',
78
+ },
79
+ ];
80
+
81
+ /**
82
+ * Propagation checklist: when a Cursor source changes, these must update.
83
+ */
84
+ const PROPAGATION_CHECKLIST = [
85
+ {
86
+ trigger: 'MDC rule format change (new frontmatter fields, type behavior change)',
87
+ targets: [
88
+ 'src/cursor/config-parser.js — update VALID_MDC_FIELDS, detectRuleType, parseSimpleYaml',
89
+ 'src/cursor/techniques.js — update rule validation checks (CU-A01..CU-A09)',
90
+ 'src/cursor/context.js — update cursorRules() parsing and type detection',
91
+ 'src/cursor/setup.js — update rule template generation',
92
+ ],
93
+ },
94
+ {
95
+ trigger: 'Background agent behavior change (environment.json format, VM config)',
96
+ targets: [
97
+ 'src/cursor/techniques.js — update background agent checks (CU-G01..CU-G05)',
98
+ 'src/cursor/setup.js — update environment.json template',
99
+ 'src/cursor/governance.js — update background-agent permission profile',
100
+ ],
101
+ },
102
+ {
103
+ trigger: 'Automation trigger format or behavior change',
104
+ targets: [
105
+ 'src/cursor/techniques.js — update automation checks (CU-H01..CU-H05)',
106
+ 'src/cursor/context.js — update automationsConfig() parsing',
107
+ 'src/cursor/governance.js — update automation permission profile and caveats',
108
+ ],
109
+ },
110
+ {
111
+ trigger: 'MCP configuration format change in .cursor/mcp.json',
112
+ targets: [
113
+ 'src/cursor/mcp-packs.js — update pack JSON projections and merge logic',
114
+ 'src/cursor/techniques.js — update MCP checks (CU-E01..CU-E05)',
115
+ 'src/cursor/context.js — update mcpConfig() parsing',
116
+ 'src/cursor/config-parser.js — update validateMcpEnvVars',
117
+ ],
118
+ },
119
+ {
120
+ trigger: 'MCP tool limit change (currently ~40)',
121
+ targets: [
122
+ 'src/cursor/techniques.js — update CU-B02 threshold',
123
+ 'src/cursor/governance.js — update mcp-tool-limit caveat',
124
+ 'src/cursor/mcp-packs.js — update recommendation logic',
125
+ ],
126
+ },
127
+ {
128
+ trigger: 'BugBot feature update or autofix behavior change',
129
+ targets: [
130
+ 'src/cursor/techniques.js — update BugBot checks (CU-J01..CU-J04)',
131
+ 'src/cursor/setup.js — update BugBot guide template',
132
+ 'src/cursor/governance.js — update bugbot-review hook',
133
+ ],
134
+ },
135
+ {
136
+ trigger: 'Privacy Mode or security model change',
137
+ targets: [
138
+ 'src/cursor/techniques.js — update trust checks (CU-C01..CU-C09)',
139
+ 'src/cursor/governance.js — update caveats and permission profiles',
140
+ 'src/cursor/deep-review.js — update trust class detection',
141
+ ],
142
+ },
143
+ {
144
+ trigger: 'Design Mode feature update',
145
+ targets: [
146
+ 'src/cursor/setup.js — update Design Mode guide template',
147
+ 'src/cursor/techniques.js — update CU-L01 modern features check',
148
+ ],
149
+ },
150
+ ];
151
+
152
+ /**
153
+ * Release gate: check if all P0 sources are within staleness threshold.
154
+ */
155
+ function checkReleaseGate(sourceVerifications = {}) {
156
+ const now = new Date();
157
+ const results = P0_SOURCES.map(source => {
158
+ const verifiedAt = sourceVerifications[source.key]
159
+ ? new Date(sourceVerifications[source.key])
160
+ : source.verifiedAt ? new Date(source.verifiedAt) : null;
161
+
162
+ if (!verifiedAt) {
163
+ return { ...source, status: 'unverified', daysStale: null };
164
+ }
165
+
166
+ const daysSince = Math.floor((now - verifiedAt) / (1000 * 60 * 60 * 24));
167
+ const isStale = daysSince > source.stalenessThresholdDays;
168
+
169
+ return { ...source, verifiedAt: verifiedAt.toISOString(), daysStale: daysSince, status: isStale ? 'stale' : 'fresh' };
170
+ });
171
+
172
+ return {
173
+ ready: results.every(r => r.status === 'fresh'),
174
+ stale: results.filter(r => r.status === 'stale' || r.status === 'unverified'),
175
+ fresh: results.filter(r => r.status === 'fresh'),
176
+ results,
177
+ };
178
+ }
179
+
180
+ function formatReleaseGate(gateResult) {
181
+ const lines = [
182
+ `Cursor Freshness Gate (nerviq v${version})`,
183
+ '═══════════════════════════════════════',
184
+ '',
185
+ `Status: ${gateResult.ready ? 'READY' : 'BLOCKED'}`,
186
+ `Fresh: ${gateResult.fresh.length}/${gateResult.results.length}`,
187
+ '',
188
+ ];
189
+
190
+ for (const result of gateResult.results) {
191
+ const icon = result.status === 'fresh' ? '✓' : result.status === 'stale' ? '✗' : '?';
192
+ const age = result.daysStale !== null ? ` (${result.daysStale}d ago)` : ' (unverified)';
193
+ lines.push(` ${icon} ${result.label}${age} — threshold: ${result.stalenessThresholdDays}d`);
194
+ }
195
+
196
+ if (!gateResult.ready) {
197
+ lines.push('', 'Action required: verify stale/unverified sources before claiming release freshness.');
198
+ }
199
+
200
+ return lines.join('\n');
201
+ }
202
+
203
+ function getPropagationTargets(triggerKeyword) {
204
+ const keyword = triggerKeyword.toLowerCase();
205
+ return PROPAGATION_CHECKLIST.filter(item => item.trigger.toLowerCase().includes(keyword));
206
+ }
207
+
208
+ module.exports = {
209
+ P0_SOURCES,
210
+ PROPAGATION_CHECKLIST,
211
+ checkReleaseGate,
212
+ formatReleaseGate,
213
+ getPropagationTargets,
214
+ };
package/src/dashboard.js CHANGED
@@ -68,7 +68,7 @@ function buildScoreOverTimeSvg(history) {
68
68
 
69
69
  return `
70
70
  <div class="card">
71
- <h2>Score Over Time</h2>
71
+ <h2>Audit Snapshot Score Over Time</h2>
72
72
  <svg viewBox="0 0 ${w} ${h}" width="100%" style="max-width:${w}px">
73
73
  ${yLabels}
74
74
  <polyline points="${polyline}" fill="none" stroke="${COLORS.blue}" stroke-width="2"/>
@@ -119,11 +119,28 @@ function buildCategoryBreakdownSvg(results) {
119
119
  </div>`;
120
120
  }
121
121
 
122
+ function getDashboardScoreMeta(history) {
123
+ if (history && history.length > 0) {
124
+ return {
125
+ label: 'Latest audit snapshot score',
126
+ note: 'Dashboard is anchored to the most recent saved audit snapshot. Trend and drift sections use audit snapshots only.',
127
+ consoleSource: 'latest audit snapshot',
128
+ };
129
+ }
130
+
131
+ return {
132
+ label: 'Live audit score',
133
+ note: 'No saved audit snapshots found, so this dashboard ran a live audit of the current repo. Run `nerviq audit --snapshot` to build history.',
134
+ consoleSource: 'live audit (no snapshots yet)',
135
+ };
136
+ }
137
+
122
138
  function buildHtml(projectName, auditPayload, history) {
123
139
  const score = auditPayload.score ?? 0;
124
140
  const platform = auditPayload.platform || 'unknown';
125
141
  const results = auditPayload.results || [];
126
142
  const timestamp = new Date().toISOString();
143
+ const scoreMeta = getDashboardScoreMeta(history);
127
144
 
128
145
  // Top 5 failed checks sorted by impact severity
129
146
  const impactOrder = { critical: 0, high: 1, medium: 2, low: 3 };
@@ -184,7 +201,8 @@ function buildHtml(projectName, auditPayload, history) {
184
201
 
185
202
  <div class="card score-card">
186
203
  <div class="score-number" style="color:${scoreColor(score)}">${score}</div>
187
- <div class="score-label">out of 100</div>
204
+ <div class="score-label">${escapeHtml(scoreMeta.label)}</div>
205
+ <div style="color:${COLORS.textDim};font-size:.85rem;margin-top:.75rem;max-width:520px;margin-left:auto;margin-right:auto">${escapeHtml(scoreMeta.note)}</div>
188
206
  </div>
189
207
 
190
208
  <div class="card">
@@ -238,6 +256,7 @@ async function generateDashboard(dir, flags = {}) {
238
256
  auditPayload = await audit({ dir, silent: true, platform: flags.platform || 'claude' });
239
257
  }
240
258
 
259
+ const scoreMeta = getDashboardScoreMeta(history);
241
260
  const html = buildHtml(projectName, auditPayload, history);
242
261
  fs.mkdirSync(path.dirname(outputPath), { recursive: true });
243
262
  fs.writeFileSync(outputPath, html, 'utf8');
@@ -247,8 +266,9 @@ async function generateDashboard(dir, flags = {}) {
247
266
  console.log('');
248
267
  console.log(' nerviq dashboard');
249
268
  console.log(' \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550');
250
- console.log(` Score: ${auditPayload.score ?? '?'}/100`);
251
- console.log(` Snapshots: ${history.length}`);
269
+ console.log(` Dashboard score: ${auditPayload.score ?? '?'}/100`);
270
+ console.log(` Score source: ${scoreMeta.consoleSource}`);
271
+ console.log(` Audit snapshots: ${history.length}`);
252
272
  console.log(` Output: ${relPath}`);
253
273
  console.log('');
254
274
  }
@@ -261,7 +281,7 @@ async function generateDashboard(dir, flags = {}) {
261
281
  exec(cmd);
262
282
  }
263
283
 
264
- return { outputPath, relativePath: relPath, score: auditPayload.score };
284
+ return { outputPath, relativePath: relPath, score: auditPayload.score, scoreSource: scoreMeta.consoleSource };
265
285
  }
266
286
 
267
287
  /**
@@ -274,13 +294,15 @@ function detectDrifts(history, threshold = 5) {
274
294
  for (let i = 0; i < history.length - 1; i++) {
275
295
  const current = history[i];
276
296
  const previous = history[i + 1];
277
- if (current.score != null && previous.score != null) {
278
- const delta = current.score - previous.score;
297
+ const currentScore = current.summary?.score;
298
+ const previousScore = previous.summary?.score;
299
+ if (currentScore != null && previousScore != null) {
300
+ const delta = currentScore - previousScore;
279
301
  if (Math.abs(delta) >= threshold) {
280
302
  drifts.push({
281
- date: current.date || current.timestamp,
282
- from: previous.score,
283
- to: current.score,
303
+ date: current.createdAt || current.date || current.timestamp,
304
+ from: previousScore,
305
+ to: currentScore,
284
306
  delta,
285
307
  });
286
308
  }
@@ -307,8 +329,8 @@ function buildDriftAlertsHtml(drifts) {
307
329
 
308
330
  return `
309
331
  <div style="margin-top:32px">
310
- <h2 style="color:${COLORS.text};font-size:18px;margin-bottom:12px">⚠ Score Drift Alerts</h2>
311
- <p style="color:${COLORS.textDim};font-size:13px;margin-bottom:12px">Changes of 5+ points between consecutive snapshots</p>
332
+ <h2 style="color:${COLORS.text};font-size:18px;margin-bottom:12px">⚠ Audit Snapshot Drift Alerts</h2>
333
+ <p style="color:${COLORS.textDim};font-size:13px;margin-bottom:12px">Changes of 5+ points between consecutive audit snapshots</p>
312
334
  <table style="width:100%;border-collapse:collapse;background:${COLORS.surface};border-radius:8px;overflow:hidden">
313
335
  <thead><tr style="background:${COLORS.border}">
314
336
  <th style="padding:8px 12px;text-align:left;color:${COLORS.textDim};font-size:12px">Date</th>
@@ -375,7 +397,7 @@ function buildPortfolioHtml(repoResults) {
375
397
 
376
398
  <div class="card score-card">
377
399
  <div class="score-number" style="color:${scoreColor(avgScore)}">${avgScore}</div>
378
- <div class="score-label">average score across ${repoResults.length} repos</div>
400
+ <div class="score-label">average live audit score across ${repoResults.length} repos</div>
379
401
  </div>
380
402
 
381
403
  <div class="highlights">
@@ -452,7 +474,7 @@ async function generatePortfolioDashboard(repoPaths, flags = {}) {
452
474
  console.log(' nerviq portfolio dashboard');
453
475
  console.log(' \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550');
454
476
  console.log(` Repos: ${repoResults.length}`);
455
- console.log(` Average score: ${avgScore}/100`);
477
+ console.log(` Average live audit score: ${avgScore}/100`);
456
478
  console.log(` Output: ${outputPath}`);
457
479
  console.log('');
458
480
  }
package/src/freshness.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Release gates, recurring probes, propagation checklists,
5
5
  * and staleness blocking for Claude Code surfaces.
6
6
  *
7
- * P0 sources from docs.anthropic.com, propagation for CLAUDE.md format changes.
7
+ * P0 sources from code.claude.com/docs, propagation for CLAUDE.md format changes.
8
8
  */
9
9
 
10
10
  const { version } = require('../package.json');
@@ -16,58 +16,58 @@ const P0_SOURCES = [
16
16
  {
17
17
  key: 'claude-code-docs',
18
18
  label: 'Claude Code Official Docs',
19
- url: 'https://docs.anthropic.com/claude-code',
19
+ url: 'https://code.claude.com/docs',
20
20
  stalenessThresholdDays: 30,
21
- verifiedAt: null,
21
+ verifiedAt: '2026-04-07',
22
22
  },
23
23
  {
24
24
  key: 'claude-md-format',
25
- label: 'CLAUDE.md Format Documentation',
26
- url: 'https://docs.anthropic.com/claude-code/claude-md',
25
+ label: 'CLAUDE.md / Memory Documentation',
26
+ url: 'https://code.claude.com/docs/en/memory',
27
27
  stalenessThresholdDays: 30,
28
- verifiedAt: null,
28
+ verifiedAt: '2026-04-07',
29
29
  },
30
30
  {
31
31
  key: 'claude-mcp-docs',
32
32
  label: 'Claude Code MCP Documentation',
33
- url: 'https://docs.anthropic.com/claude-code/mcp',
33
+ url: 'https://code.claude.com/docs/en/mcp',
34
34
  stalenessThresholdDays: 30,
35
- verifiedAt: null,
35
+ verifiedAt: '2026-04-07',
36
36
  },
37
37
  {
38
38
  key: 'claude-hooks-docs',
39
39
  label: 'Claude Code Hooks Documentation',
40
- url: 'https://docs.anthropic.com/claude-code/hooks',
40
+ url: 'https://code.claude.com/docs/en/hooks',
41
41
  stalenessThresholdDays: 14,
42
- verifiedAt: null,
42
+ verifiedAt: '2026-04-07',
43
43
  },
44
44
  {
45
45
  key: 'claude-security-docs',
46
46
  label: 'Claude Code Security Documentation',
47
- url: 'https://docs.anthropic.com/claude-code/security',
47
+ url: 'https://code.claude.com/docs/en/security',
48
48
  stalenessThresholdDays: 30,
49
- verifiedAt: null,
49
+ verifiedAt: '2026-04-07',
50
50
  },
51
51
  {
52
52
  key: 'claude-permissions-docs',
53
53
  label: 'Claude Code Permissions Documentation',
54
- url: 'https://docs.anthropic.com/claude-code/permissions',
54
+ url: 'https://code.claude.com/docs/en/permissions',
55
55
  stalenessThresholdDays: 14,
56
- verifiedAt: null,
56
+ verifiedAt: '2026-04-07',
57
57
  },
58
58
  {
59
59
  key: 'claude-settings-docs',
60
60
  label: 'Claude Code Settings Documentation',
61
- url: 'https://docs.anthropic.com/claude-code/settings',
61
+ url: 'https://code.claude.com/docs/en/settings',
62
62
  stalenessThresholdDays: 30,
63
- verifiedAt: null,
63
+ verifiedAt: '2026-04-07',
64
64
  },
65
65
  {
66
66
  key: 'anthropic-changelog',
67
- label: 'Anthropic Changelog',
68
- url: 'https://docs.anthropic.com/changelog',
67
+ label: 'Claude Code Changelog',
68
+ url: 'https://code.claude.com/docs/en/changelog',
69
69
  stalenessThresholdDays: 14,
70
- verifiedAt: null,
70
+ verifiedAt: '2026-04-07',
71
71
  },
72
72
  ];
73
73