← GPT-AI-VIDEO
CODE · 3.0 KB

tools/index-source-assets.mjs

Workspace snapshot · 09/04 14:52

import { promises as fs } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";

const workspace = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const registryPath = path.join(workspace, "config", "source-registry.json");
const outputPath = path.join(workspace, "knowledge", "source-inventory.json");
const summaryPath = path.join(workspace, "knowledge", "source-inventory.md");
const ignored = new Set(["node_modules", ".git", "dist", "build", "vendor", "logs", "output"]);

async function scanLocalSource(source) {
  const extensions = new Set(source.extensions || []);
  const stack = [source.location];
  let files = 0;
  let bytes = 0;
  let oldest = null;
  let newest = null;

  while (stack.length) {
    const current = stack.pop();
    let entries;
    try {
      entries = await fs.readdir(current, { withFileTypes: true });
    } catch {
      continue;
    }
    for (const entry of entries) {
      if (ignored.has(entry.name)) continue;
      const fullPath = path.join(current, entry.name);
      if (entry.isDirectory()) {
        stack.push(fullPath);
        continue;
      }
      if (!entry.isFile() || (extensions.size && !extensions.has(path.extname(entry.name).toLowerCase()))) continue;
      try {
        const stat = await fs.stat(fullPath);
        const modified = stat.mtime.toISOString();
        files += 1;
        bytes += stat.size;
        if (!oldest || modified < oldest) oldest = modified;
        if (!newest || modified > newest) newest = modified;
      } catch {
        // A disconnected Drive item must not abort the whole inventory.
      }
    }
  }
  return { ...source, status: files ? "INDEXED" : "EMPTY_OR_UNAVAILABLE", files, bytes, oldest, newest };
}

const registry = JSON.parse(await fs.readFile(registryPath, "utf8"));
const results = [];
for (const source of registry.sources) {
  if (["session", "local-project-assets"].includes(source.kind)) results.push(await scanLocalSource(source));
  else results.push({ ...source, status: "REGISTERED_EXTERNAL" });
}

const inventory = { generatedAt: new Date().toISOString(), version: registry.version, sources: results };
await fs.mkdir(path.dirname(outputPath), { recursive: true });
await fs.writeFile(outputPath, `${JSON.stringify(inventory, null, 2)}\n`, "utf8");

const rows = results.map((item) => `| ${item.id} | ${item.kind} | ${item.classification} | ${item.files ?? item.observedMinimumCount ?? "—"} | ${item.status} |`);
const markdown = [
  "# Source Inventory",
  "",
  `Generated: ${inventory.generatedAt}`,
  "",
  "| Source | Kind | Classification | Files / observed minimum | Status |",
  "|---|---|---|---:|---|",
  ...rows,
  "",
  "This inventory stores counts and source locations only. It does not copy session, meeting, chat, or client content.",
  ""
].join("\n");
await fs.writeFile(summaryPath, markdown, "utf8");
console.log(JSON.stringify({ outputPath, summaryPath, sources: results.map(({ id, files, status }) => ({ id, files, status })) }, null, 2));