${escape(change.before)}
${escape(change.after)}
import { catalog as legacyCatalog } from './catalog.js';
import { files } from './files.js';
import { renderVoteWidget } from './vote.js';
// The Astro review-desk route serializes the typed content collection before
// this client module loads. Keeping the legacy fallback preserves the vanilla
// page until cutover removes it.
const catalog = window.__SKILLS_REVIEW_CATALOG || legacyCatalog;
const state = {
selected: catalog[0],
query: '',
preview: 'original',
file: null,
sourceByPath: new Map(),
lens: false,
rendered: false,
diff: false,
searching: false,
contentMatches: new Set(),
searchTimer: null,
searchRequest: 0,
};
const $ = (selector) => document.querySelector(selector);
const escape = (value) =>
value.replace(
/[&<>"']/g,
(character) =>
({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[character],
);
const redact = (value, entry) => {
const safe = value
.replace(/(NDO_PASS[^\n=]*[=:]\s*["']?)[^\n"']+/gi, '$1[REDACTED]')
.replace(/(password["']?\s*[:=]\s*["']?)[^\n"']+/gi, '$1[REDACTED]')
.replace(/\b[\w.+-]+@[\w.-]+\.[a-z]{2,}\b/gi, '[REDACTED SERVICE ACCOUNT]')
.replace(/\/home\/[A-Za-z0-9._-]+(?=\/)/g, '[REDACTED LOCAL USER]')
.replace(/display\/~[A-Za-z0-9._-]+/gi, 'display/~[REDACTED USER]');
return entry.id === 'ndo-repro'
? safe
.replace(/https?:\/\/[^\s)>]+/gi, '[REDACTED URL]')
.replace(/\b(?:[\w-]+\.)*netcracker\.[\w.-]+\b/gi, '[REDACTED HOST]')
.replace(/\bpedro[._ -]?aranha\b/gi, '[REDACTED CONTRIBUTOR]')
: safe;
};
const download = (name, content) => {
const url = URL.createObjectURL(new Blob([content], { type: 'text/markdown' }));
const a = document.createElement('a');
a.href = url;
a.download = name;
a.click();
URL.revokeObjectURL(url);
};
const copy = async (content) => {
if (navigator.clipboard?.writeText) return navigator.clipboard.writeText(content);
const textarea = document.createElement('textarea');
textarea.value = content;
textarea.setAttribute('readonly', '');
textarea.style.position = 'fixed';
textarea.style.opacity = '0';
document.body.append(textarea);
textarea.select();
document.execCommand('copy');
textarea.remove();
};
const packageFiles = (entry = state.selected) =>
files[entry.id] || [{ name: 'SKILL.md', path: entry.path, kind: 'skill' }];
const packageSearchText = (entry) =>
packageFiles(entry)
.map((file) => `${file.name} ${file.kind}`)
.join(' ');
function packageSummary(entry) {
const counts = packageFiles(entry).reduce((all, file) => {
all[file.kind] = (all[file.kind] || 0) + 1;
return all;
}, {});
const labels = {
skill: 'skill',
reference: 'ref',
script: 'script',
template: 'template',
data: 'data',
asset: 'asset',
};
return Object.entries(counts)
.map(([kind, count]) => `${count} ${labels[kind] || kind}${count === 1 ? '' : 's'}`)
.join(' · ');
}
const unchangedDraft = (file) =>
`# ${file.name}\n\n> Kept as-is in the improved package\n\nThis ${file.kind} file was not rewritten. Select **Change lens** to see why the improved draft concentrates its changes in the main skill contract.`;
const currentSource = () => state.sourceByPath.get(state.file.path);
const currentContent = () =>
state.preview === 'original'
? currentSource() || 'Loading original file…'
: state.file.improved ||
(state.file.name === 'SKILL.md'
? state.selected.improved
: currentSource()
? `# ${state.file.name}\n\n> Kept as-is in the improved package\n\n${currentSource()}`
: unchangedDraft(state.file));
const inlineMarkdown = (value) =>
escape(value)
.replace(/`([^`]+)`/g, '$1')
.replace(/\*\*([^*]+)\*\*/g, '$1')
.replace(/(?$1')
.replace(
/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g,
'$1 ↗',
);
const tableCells = (line) =>
line
.trim()
.replace(/^\||\|$/g, '')
.split('|')
.map((cell) => cell.trim());
const isTableDivider = (line) => /^\s*\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?\s*$/.test(line);
function markdownMarkup(markdown) {
const lines = markdown.replace(/\r/g, '').split('\n');
const headings = markdownHeadings(markdown);
let headingIndex = 0;
let index = 0;
const out = [];
if (lines[0] === '---') {
const end = lines.indexOf('---', 1);
if (end > 0) {
out.push(
`
${escape(code.join('\n'))}`,
);
continue;
}
if (line.includes('|') && isTableDivider(lines[index + 1] || '')) {
const headings = tableCells(line);
index += 2;
const rows = [];
while (index < lines.length && lines[index].includes('|') && lines[index].trim())
rows.push(tableCells(lines[index++]));
out.push(
`| ${inlineMarkdown(cell)} | `).join('')}
|---|
| ${inlineMarkdown(row[cell] || '')} | `).join('')}
${inlineMarkdown(quote.join(' '))}`); continue; } if (/^---+$/.test(line)) { out.push('
${inlineMarkdown(paragraph.join(' '))}
`); } return out.join(''); } function markdownHeadings(markdown) { const used = new Map(); let fenced = false; return markdown .replace(/\r/g, '') .split('\n') .flatMap((line) => { if (/^```/.test(line)) { fenced = !fenced; return []; } const match = !fenced && line.match(/^(#{1,6})\s+(.+)$/); if (!match) return []; const text = match[2].replace(/[`*_\[\]]/g, '').trim(); const base = text .toLowerCase() .replace(/[^\p{L}\p{N}]+/gu, '-') .replace(/(^-|-$)/g, '') || 'section'; const seen = used.get(base) || 0; used.set(base, seen + 1); return [{ level: match[1].length, text, id: seen ? `${base}-${seen + 1}` : base }]; }); } function markdownToc(markdown) { const headings = markdownHeadings(markdown); if (headings.length < 2) return ''; return ``; } const changeRows = (entry) => entry.improve.map((why, index) => ({ kind: ['SAFETY', 'SCOPE', 'EVIDENCE', 'STRUCTURE'][index] || 'CLARITY', before: index === 0 ? 'The submitted guidance leaves a material decision implicit.' : 'The submitted package carries detail without a clear boundary.', after: index === 0 ? 'The improved draft makes the operating rule explicit.' : 'The improved draft moves the decision into a smaller, reviewable contract.', why, })); function visible() { return catalog.filter( (item) => `${item.author} ${item.title} ${item.id} ${item.focus} ${packageSearchText(item)}` .toLowerCase() .includes(state.query) || state.contentMatches.has(item.id), ); } function syncUrl() { const url = new URL(window.location.href); url.searchParams.set('author', state.selected.author); url.searchParams.set('skill', state.selected.id); url.searchParams.set('view', state.preview); if (state.file && state.file.name !== 'SKILL.md') url.searchParams.set('file', state.file.name); else url.searchParams.delete('file'); if (state.preview === 'improved' && state.lens) url.searchParams.set('lens', 'changes'); else url.searchParams.delete('lens'); if (state.rendered) url.searchParams.set('render', 'preview'); else url.searchParams.delete('render'); if (state.diff) url.searchParams.set('compare', 'diff'); else url.searchParams.delete('compare'); history.pushState({}, '', url); } function selectFromUrl() { const params = new URLSearchParams(window.location.search); const author = params.get('author'); const id = params.get('skill'); const view = params.get('view'); const byAuthor = author && catalog.filter((item) => item.author.toLowerCase() === author.toLowerCase()); const byId = id && catalog.find((item) => item.id === id); state.selected = byId || byAuthor?.[0] || catalog[0]; state.query = byAuthor ? state.selected.author.toLowerCase() : ''; state.preview = view === 'improved' ? 'improved' : 'original'; state.lens = state.preview === 'improved' && params.get('lens') === 'changes'; state.rendered = params.get('render') === 'preview'; state.diff = params.get('compare') === 'diff'; state.file = packageFiles().find((item) => item.name === params.get('file')) || packageFiles()[0]; $('#skill-filter').value = byAuthor ? state.selected.author : ''; $('#submission-count').textContent = `${catalog.length} submissions`; } function renderList() { const items = visible(); $('#count').textContent = state.searching ? `Searching package files… ${items.length} of ${catalog.length}` : `${items.length} of ${catalog.length} reviewed`; $('#skill-list').innerHTML = items .map( (item) => ``, ) .join(''); $('#skill-list') .querySelectorAll('button') .forEach((button) => button.addEventListener('click', () => selectSkill(button.dataset.id))); } function selectSkill(id, focus = false) { state.selected = catalog.find((item) => item.id === id) || state.selected; state.file = packageFiles()[0]; state.preview = 'original'; state.lens = false; state.rendered = false; state.diff = false; syncUrl(); renderList(); renderDetail(); loadSelectedFile(); if (focus) $('#skill-list').querySelector(`[data-id="${state.selected.id}"]`)?.focus(); } async function fetchSource(entry, file) { if (state.sourceByPath.has(file.path)) return state.sourceByPath.get(file.path); try { state.sourceByPath.set(file.path, redact(await (await fetch(file.path)).text(), entry)); } catch { state.sourceByPath.set( file.path, '# Original preview unavailable\n\nServe this site from the repository root to load the submitted source.', ); } return state.sourceByPath.get(file.path); } async function loadSelectedFile() { const entry = state.selected; const file = state.file; await fetchSource(entry, file); if (state.selected.id === entry.id && state.file.path === file.path) renderDetail(); return state.sourceByPath.get(file.path); } function schedulePackageSearch() { clearTimeout(state.searchTimer); const query = state.query; const request = ++state.searchRequest; state.contentMatches.clear(); if (query.length < 3) { state.searching = false; renderList(); return; } state.searchTimer = setTimeout(async () => { state.searching = true; renderList(); await Promise.all( catalog.flatMap((entry) => packageFiles(entry).map((file) => fetchSource(entry, file))), ); if (request !== state.searchRequest) return; state.contentMatches = new Set( catalog .filter((entry) => packageFiles(entry).some((file) => state.sourceByPath.get(file.path)?.toLowerCase().includes(query), ), ) .map((entry) => entry.id), ); state.searching = false; renderList(); }, 180); } function lensMarkup(entry) { return `The improved draft keeps the job, but narrows the decisions an agent must make from memory.
${escape(change.before)}
${escape(change.after)}
${oldIndex + 1}${escape(oldLines[oldIndex] || '')}
`, ); oldIndex += 1; newIndex += 1; continue; } const oldAhead = oldLines.slice(oldIndex + 1, oldIndex + 9).indexOf(newLines[newIndex]); const newAhead = newLines.slice(newIndex + 1, newIndex + 9).indexOf(oldLines[oldIndex]); if ( newIndex < newLines.length && (oldIndex >= oldLines.length || (oldAhead === -1 && newAhead !== -1) || newAhead < oldAhead) ) { rows.push(`+${escape(newLines[newIndex++])}
`); continue; } if (oldIndex < oldLines.length) { rows.push(`−${escape(oldLines[oldIndex++])}
`); continue; } } return rows.join(''); } function diffMarkup(entry) { if (state.file.name !== 'SKILL.md') return `This review only rewrites the main skill contract. The selected ${escape(state.file.kind)} file remains available in its original form.
Green lines are additions; red lines are removals. Unmarked lines are shared context.
${escape(content)}`;
return `${escape(entry.focus)}