p = 'crates/spt-daemon/src/webserve.rs'
raw = open(p, encoding='utf-8', newline='').read()
crlf = '\r\n' in raw
s = raw.replace('\r\n', '\n')
old = '''                return ready(redirect_directory(uri_path, query));
            }
            planned(docs_root, remainder, head_only)
        }'''
assert s.count(old) == 1
new = '''                return ready(redirect_directory(uri_path, query));
            }
            // [impl->REQ-DOCS-NODE-TOC]
            if spt_runtime::surfaces::is_sidebar_script(remainder) {
                return ready(sidebar(home, docs_root, local_node, remainder, head_only));
            }
            planned(docs_root, remainder, head_only)
        }'''
s = s.replace(old, new)
anchor = '''/// The adapter changelog page:'''
assert s.count(anchor) == 1
fn = '''/// The docs sidebar script (`toc.js` or mdBook's fingerprinted `toc-<hex>.js`)
/// with this node's `Installed on <node>` part spliced in. The bytes change
/// whenever the roster does while the fingerprinted NAME does not, so this one
/// response is `no-store`; every other bundle byte is served verbatim. A static
/// script the generator does not recognise is served verbatim too.
// [impl->REQ-DOCS-NODE-TOC]
fn sidebar(home: &Path, docs_root: &Path, local_node: &str, name: &str, head_only: bool) -> Response<Full<Bytes>> {
    let (path, content_type) = match locate_path(docs_root, name, head_only) {
        Ok(found) => found,
        Err(refusal) => return *refusal,
    };
    let bytes = match std::fs::read(&path) {
        Ok(bytes) => bytes,
        Err(error) => {
            return text(StatusCode::INTERNAL_SERVER_ERROR, format!("DOCS_READ_FAIL: {name}: {error}\\n"), head_only)
        }
    };
    let roster = spt_runtime::surfaces::installed_roster(&home.join("adapters"));
    let body = std::str::from_utf8(&bytes)
        .ok()
        .and_then(|script| spt_runtime::surfaces::node_toc(script, local_node, &roster))
        .map(String::into_bytes)
        .unwrap_or(bytes);
    let mut page = response(StatusCode::OK, content_type, body, head_only);
    page.headers_mut().insert("cache-control", hyper::header::HeaderValue::from_static("no-store"));
    page
}

'''
s = s.replace(anchor, fn + anchor)
open(p, 'w', encoding='utf-8', newline='').write(s.replace('\n', '\r\n') if crlf else s)
print('ok crlf=', crlf)
