New POST /api/rescan re-runs the boot item setup (ensureItemDirs + ensureToolLoader) and returns live item counts; the header button calls it and invalidates the item query caches so the UI refetches from disk. Also fix ensure-tool-loader to write into OFFICER_ITEMS_DIR/extensions (the runtime read path) instead of the now-unread DATA_PATH/extensions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
40 lines
1.3 KiB
TypeScript
40 lines
1.3 KiB
TypeScript
import { readdirSync, existsSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { createRouter } from '../../create-router';
|
|
import { ITEM_TYPES, itemsDir, ensureItemDirs, type ItemType } from '../../data-path';
|
|
import { ensureToolLoader } from '../../ensure-tool-loader';
|
|
|
|
// Re-applies the boot-time item setup so changes under OFFICER_ITEMS_DIR take effect without a
|
|
// server restart. Item lists are already read fresh from disk on every request; this ensures the
|
|
// type dirs exist and the tool-loader extension is current, and reports the live item counts so the
|
|
// UI can refetch.
|
|
|
|
const CANONICAL: Record<ItemType, string> = {
|
|
skills: 'SKILL.md',
|
|
tools: 'TOOL.md',
|
|
tasks: 'TASK.md',
|
|
processes: 'PROCESS.md',
|
|
extensions: 'index.ts',
|
|
};
|
|
|
|
function countItems(type: ItemType): number {
|
|
const dir = itemsDir(type);
|
|
if (!existsSync(dir)) return 0;
|
|
let count = 0;
|
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
if (entry.isDirectory() && existsSync(join(dir, entry.name, CANONICAL[type]))) count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
export const rescanRouter = createRouter();
|
|
|
|
rescanRouter.post('/', async (ctx) => {
|
|
ensureItemDirs();
|
|
ensureToolLoader();
|
|
|
|
const counts = Object.fromEntries(ITEM_TYPES.map((type) => [type, countItems(type)])) as Record<ItemType, number>;
|
|
|
|
return ctx.json({ ok: true, counts });
|
|
});
|