Add the AI tab — grounded chat over the documentation index

Token and poll rather than SSE, so the api layer keeps one response
convention and reuses the pattern manual_sync already proved. History is
capped at three turns because the model is only fully offloaded at 16384
context and unbounded history would cross that silently. The tab exists
only while AI_ENABLED is true, rejected server-side and not merely hidden.
This commit is contained in:
Gmer4Lfe
2026-08-02 17:32:17 -04:00
parent a537ae4217
commit 264ba57cbb
6 changed files with 1053 additions and 5 deletions
+11 -4
View File
@@ -31,9 +31,16 @@
// implied by the character class.
//
// The extension allowlist is the real access boundary.
// Only .sh and .md can be named at all, which is what keeps Configurations/*.conf —
// the files holding every credential in the system — outside this endpoint's reach. Any
// future extension added here has to be checked against that first.
// Only .sh, .md, .php and .template can be named at all, which is what keeps
// Configurations/*.conf — the files holding every credential in the system — outside
// this endpoint's reach. Any future extension added here has to be checked against that
// first.
//
// .php and .template were added for the AI tab's source viewer, whose retrieval results
// span every tracked file type. They are safe by the same argument that makes the AI
// index safe: only git-tracked content is involved, the conf files were never tracked,
// and the repository is pushed to a remote — anything reachable here is already
// published. .conf is deliberately still absent, and must stay that way.
//
// A missing file is reported, not opened.
// file_exists() precedes file_get_contents(), so a bad id returns a named error rather
@@ -62,7 +69,7 @@ require_once dirname(__DIR__) . '/include/config.php';
$id = trim($_GET['id'] ?? '');
// Must be relative path within SCRIPTS_DIR, no traversal, must end in .sh or .md
if (!$id || str_contains($id, '..') || !preg_match('/^[A-Za-z0-9_.\-\/]+\.(sh|md)$/', $id)) {
if (!$id || str_contains($id, '..') || !preg_match('/^[A-Za-z0-9_.\-\/]+\.(sh|md|php|template)$/', $id)) {
echo json_encode(['ok' => false, 'error' => 'Invalid id']);
exit;
}