diff --git a/hive-c0re/assets/app.js b/hive-c0re/assets/app.js index 18f9c4d..3364cee 100644 --- a/hive-c0re/assets/app.js +++ b/hive-c0re/assets/app.js @@ -48,13 +48,18 @@ // perspective (we'd need to know which agent the message is about // to translate it). Prefer `/agents//state/...` in agent // outputs and the link will resolve. - // Each branch insists the tail is at least one segment AND the - // last character is `[\w.-]` (not `/`), so trailing-slash paths - // — i.e. plain directories — don't linkify. The /api/state-file - // endpoint also refuses non-files; this is the front-end peer so - // the operator doesn't see a dead link they'll just get an error - // from on click. - const PATH_RE = /(\/var\/lib\/hyperhive\/agents\/[\w.-]+\/state\/(?:[\w.-]+\/)*[\w.-]+|\/var\/lib\/hyperhive\/shared\/(?:[\w.-]+\/)*[\w.-]+|\/agents\/[\w.-]+\/state\/(?:[\w.-]+\/)*[\w.-]+|\/shared\/(?:[\w.-]+\/)*[\w.-]+)/g; + // Each branch insists the final segment looks like a filename: + // at least one non-dot char, a literal dot, then an extension + // (`[\w-]+\.[\w.-]+`). That catches the common case (`notes.md`, + // `2026-01.log`, `foo.bar.baz`) while skipping bare directory + // names like `/agents/foo/state/notes` whether or not they carry + // a trailing slash. Misses extensionless files (`README`, + // `Makefile`) — accepted trade-off; the /api/state-file endpoint + // still serves them if the operator types the path manually. + // The endpoint also refuses non-files at the server level; this + // is the front-end peer so the operator doesn't see a dead link + // they'll just get an error from on click. + const PATH_RE = /(\/var\/lib\/hyperhive\/agents\/[\w.-]+\/state\/(?:[\w.-]+\/)*[\w-]+\.[\w.-]+|\/var\/lib\/hyperhive\/shared\/(?:[\w.-]+\/)*[\w-]+\.[\w.-]+|\/agents\/[\w.-]+\/state\/(?:[\w.-]+\/)*[\w-]+\.[\w.-]+|\/shared\/(?:[\w.-]+\/)*[\w-]+\.[\w.-]+)/g; async function fetchStateFile(path) { const resp = await fetch('/api/state-file?path=' + encodeURIComponent(path)); const text = await resp.text();