feat(voyage): implement screenshots-spor convention (window.__hooks + docs/screenshots/)

This commit is contained in:
Kjell Tore Guttormsen 2026-05-10 17:58:56 +02:00
commit e839ba2a7a
3 changed files with 179 additions and 0 deletions

View file

@ -2840,6 +2840,65 @@ playground first-run shows a complete round-trip-able artifact.
});
}
// ---- v4.3 Step 23 — screenshots-spor convention -------------------
// Expose a minimal automation surface for headless screenshot scripts
// (Wave 7 axe-spec + manual screenshot tooling). Mirrors the
// llm-security-playground.html `window.__navigate` /
// `window.__scheduleRender` pattern but namespaced under
// `window.__voyage` to avoid global pollution. All three methods are
// intentionally read-only from the outside — they wrap existing
// functions; we never expose state-mutating internals directly.
//
// Methods:
// navigate(surface) — surface ∈ ['dashboard', 'detail', 'render', 'a11y']
// scheduleRender(state) — state.markdown → mountRender; state.artifacts → renderDashboard
// getProjectArtifacts() — returns the last-loaded ProjectArtifacts object (or null)
//
// See docs/screenshots/README.md for the screenshot mappestruktur.
window.__voyage = {
navigate: function (surface) {
var s = String(surface || '').toLowerCase();
if (s === 'dashboard') {
if (__voyageCurrentArtifacts && typeof renderDashboard === 'function') {
renderDashboard(__voyageCurrentArtifacts);
}
return s;
}
if (s === 'detail') {
// No-op without an artifact-key; renderArtifactDetail requires
// a key (brief|plan|review|progress|research:N|architecture:overview).
return s;
}
if (s === 'render') {
var ta = document.getElementById('voyage-paste-input');
if (ta && typeof mountRender === 'function') mountRender(ta.value || '');
return s;
}
if (s === 'a11y') {
var panel = document.getElementById('voyage-a11y-panel');
if (panel) panel.hidden = false;
return s;
}
return null;
},
scheduleRender: function (state) {
if (!state || typeof state !== 'object') return false;
if (typeof state.markdown === 'string' && typeof mountRender === 'function') {
var ta = document.getElementById('voyage-paste-input');
if (ta) ta.value = state.markdown;
mountRender(state.markdown);
}
if (state.artifacts && typeof renderDashboard === 'function') {
__voyageCurrentArtifacts = state.artifacts;
renderDashboard(state.artifacts);
}
return true;
},
getProjectArtifacts: function () {
return __voyageCurrentArtifacts || null;
},
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {