def load(p):
    raw = open(p, encoding='utf-8', newline='').read()
    return raw.replace('\r\n', '\n'), '\r\n' in raw

def save(p, s, crlf):
    open(p, 'w', encoding='utf-8', newline='').write(s.replace('\n', '\r\n') if crlf else s)

def once(s, old, new):
    assert s.count(old) == 1, (old[:80], s.count(old))
    return s.replace(old, new)

p = 'crates/spt-runtime/src/surfaces.rs'
s, c = load(p)
s = once(s, '''/// Everything an adapter page says, already read by the caller.''', '''/// [`installed_at`] on this machine's local clock.
pub fn installed_at_local(at_ms: u64) -> Option<String> {
    installed_at(at_ms, &chrono::Local)
}

/// Everything an adapter page says, already read by the caller.''')
save(p, s, c)

p = 'crates/spt-daemon/src/webserve.rs'
s, c = load(p)
s = once(s, '''fn adapter(
    home: &Path,
    registry: &ServingRegistry,
    remainder: &str,''', '''fn adapter(
    home: &Path,
    local_node: &str,
    registry: &ServingRegistry,
    remainder: &str,''')
s = once(s, '''            Ok(registry) => adapter(home, &registry, remainder, uri_path, query, head_only),''',
         '''            Ok(registry) => adapter(home, local_node, &registry, remainder, uri_path, query, head_only),''')
s = once(s, '''    if raw_segment == "changelog" && docs_subpath.is_empty() {
        return adapter_changelog(home, &name, head_only);
    }
''', '''    if raw_segment == "changelog" && docs_subpath.is_empty() {
        return adapter_changelog(home, &name, head_only);
    }
    // `about` is core's too: every installed adapter's page (releases#332).
    // [impl->REQ-DOCS-ADAPTER-PAGE]
    if raw_segment == "about" && docs_subpath.is_empty() {
        return Resolved::Ready(adapter_about(home, local_node, &name, head_only));
    }
''')
anchor = '/// The adapter changelog page:'
s = once(s, anchor, '''/// The adapter page: `/<node>/a/<adapter>/about`, a template over records
/// read per request — the registry record, the manifest, the retained-archive
/// sidecar and the install-time changelog page — so an adapter installed
/// before this page existed, or shipped built in, has one with no migration.
/// Nothing here renders markdown. An adapter that is not installed and
/// active answers one 404 naming the facet.
// [impl->REQ-DOCS-ADAPTER-PAGE]
fn adapter_about(home: &Path, local_node: &str, adapter: &str, head_only: bool) -> Response<Full<Bytes>> {
    use spt_runtime::surfaces::{self, AboutFacts, AdapterSource};
    let adapters = home.join("adapters");
    let record = match spt_runtime::registry::load_record(&adapters, adapter) {
        Ok(record) if record.active => record,
        _ => return text(StatusCode::NOT_FOUND, format!("NOT_FOUND: facet a adapter {adapter} about\\n"), head_only),
    };
    let manifest = spt_runtime::registry::load_manifest(&adapters, &record).ok();
    let group = match &manifest {
        Some(m) => surfaces::adapter_group(m.adapter.kind, &m.adapter.hostable_types),
        None => surfaces::adapter_group(record.kind, &[]),
    };
    let source = crate::ReleaseCache::open(&home.join("releases"))
        .retained_adapter(adapter)
        .and_then(|sidecar| sidecar.current_source)
        .and_then(|word| AdapterSource::parse(&word));
    let facts = AboutFacts {
        node: local_node.to_owned(),
        name: record.name.clone(),
        group: Some(group),
        version: manifest.as_ref().map(|m| m.adapter.version.clone()),
        installed: surfaces::installed_at_local(record.registered_at_ms),
        source,
        summary: manifest.as_ref().and_then(|m| m.adapter.summary.clone()),
        docs: manifest.as_ref().is_some_and(|m| m.adapter.docs_dir.is_some()),
        changelog_page: std::fs::read_to_string(spt_store::serving::adapter_changelog_page_in(home, adapter)).ok(),
    };
    let mut page = response(StatusCode::OK, "text/html; charset=utf-8", surfaces::about_page(&facts).into_bytes(), head_only);
    // The same wall as the changelog page it embeds: no script, frame, font
    // or remote fetch on the node's own origin.
    page.headers_mut().insert(
        "content-security-policy",
        hyper::header::HeaderValue::from_static("default-src 'none'; style-src 'unsafe-inline'"),
    );
    page
}

''' + anchor)
save(p, s, c)
print('ok')
