First Release of Claw3D (#11)

Co-authored-by: iamlukethedev <iamlukethedev@users.noreply.github.com>
This commit is contained in:
Luke The Dev
2026-03-19 23:14:04 -05:00
committed by GitHub
parent 5ea96b2650
commit 4fa4f13558
431 changed files with 105438 additions and 14 deletions
+89
View File
@@ -0,0 +1,89 @@
import fs from "node:fs";
import path from "node:path";
import { resolveStateDir } from "@/lib/clawdbot/paths";
import type { StandupMeeting, StandupMeetingStore } from "@/lib/office/standup/types";
const STORE_DIR = "claw3d";
const STORE_FILE = "standup-store.json";
const ensureDirectory = (dirPath: string) => {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
};
const resolveStorePath = () => {
const dir = path.join(resolveStateDir(), STORE_DIR);
ensureDirectory(dir);
return path.join(dir, STORE_FILE);
};
const defaultStore = (): StandupMeetingStore => ({
activeMeeting: null,
lastMeeting: null,
});
const isRecord = (value: unknown): value is Record<string, unknown> =>
Boolean(value && typeof value === "object" && !Array.isArray(value));
const normalizeMeeting = (value: unknown): StandupMeeting | null => {
if (!isRecord(value)) return null;
if (typeof value.id !== "string") return null;
if (!Array.isArray(value.cards) || !Array.isArray(value.participantOrder)) return null;
if (!Array.isArray(value.arrivedAgentIds)) return null;
if (typeof value.startedAt !== "string" || typeof value.updatedAt !== "string") return null;
return value as StandupMeeting;
};
const readStore = (): StandupMeetingStore => {
const storePath = resolveStorePath();
if (!fs.existsSync(storePath)) {
return defaultStore();
}
const raw = fs.readFileSync(storePath, "utf8");
const parsed = JSON.parse(raw) as unknown;
if (!isRecord(parsed)) return defaultStore();
return {
activeMeeting: normalizeMeeting(parsed.activeMeeting),
lastMeeting: normalizeMeeting(parsed.lastMeeting),
};
};
const writeStore = (store: StandupMeetingStore) => {
const storePath = resolveStorePath();
fs.writeFileSync(storePath, JSON.stringify(store, null, 2), "utf8");
};
export const loadStandupMeetingStore = (): StandupMeetingStore => readStore();
export const loadActiveStandupMeeting = (): StandupMeeting | null => readStore().activeMeeting;
export const saveStandupMeeting = (meeting: StandupMeeting | null): StandupMeetingStore => {
const current = readStore();
const next: StandupMeetingStore = {
activeMeeting: meeting,
lastMeeting: meeting ?? current.lastMeeting,
};
if (meeting?.phase === "complete") {
next.lastMeeting = meeting;
}
writeStore(next);
return next;
};
export const updateStandupMeeting = (
updater: (meeting: StandupMeeting | null) => StandupMeeting | null
): StandupMeetingStore => {
const current = readStore();
const nextMeeting = updater(current.activeMeeting);
const nextStore: StandupMeetingStore = {
activeMeeting: nextMeeting,
lastMeeting:
nextMeeting?.phase === "complete"
? nextMeeting
: current.lastMeeting,
};
writeStore(nextStore);
return nextStore;
};