project-session-store.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
  2. import { join } from "node:path";
  3. import { InteractionSessionSchema, type InteractionSession, GlobalSessionSchema, type GlobalSession } from "./session.js";
  4. const SESSION_DIR = ".inkos";
  5. const SESSION_FILE = "session.json";
  6. export function resolveProjectSessionPath(projectRoot: string): string {
  7. return join(projectRoot, SESSION_DIR, SESSION_FILE);
  8. }
  9. export function createProjectSession(projectRoot: string): InteractionSession {
  10. return InteractionSessionSchema.parse({
  11. sessionId: `${Date.now()}`,
  12. projectRoot,
  13. automationMode: "semi",
  14. messages: [],
  15. });
  16. }
  17. export async function loadProjectSession(projectRoot: string): Promise<InteractionSession> {
  18. try {
  19. const raw = await readFile(resolveProjectSessionPath(projectRoot), "utf-8");
  20. return InteractionSessionSchema.parse(JSON.parse(raw));
  21. } catch {
  22. return createProjectSession(projectRoot);
  23. }
  24. }
  25. export async function persistProjectSession(
  26. projectRoot: string,
  27. session: InteractionSession,
  28. ): Promise<void> {
  29. const dir = join(projectRoot, SESSION_DIR);
  30. await mkdir(dir, { recursive: true });
  31. await writeFile(resolveProjectSessionPath(projectRoot), JSON.stringify(session, null, 2), "utf-8");
  32. }
  33. export async function loadGlobalSession(projectRoot: string): Promise<GlobalSession> {
  34. try {
  35. const raw = await readFile(join(projectRoot, SESSION_DIR, SESSION_FILE), "utf-8");
  36. const data = JSON.parse(raw);
  37. return GlobalSessionSchema.parse({
  38. activeBookId: data.activeBookId,
  39. automationMode: data.automationMode ?? "semi",
  40. });
  41. } catch {
  42. return { automationMode: "semi" };
  43. }
  44. }
  45. export async function persistGlobalSession(
  46. projectRoot: string,
  47. global: GlobalSession,
  48. ): Promise<void> {
  49. const dir = join(projectRoot, SESSION_DIR);
  50. await mkdir(dir, { recursive: true });
  51. await writeFile(join(dir, SESSION_FILE), JSON.stringify(global, null, 2));
  52. }
  53. export async function resolveSessionActiveBook(
  54. projectRoot: string,
  55. session: InteractionSession,
  56. ): Promise<string | undefined> {
  57. const booksDir = join(projectRoot, "books");
  58. const entries = await readdir(booksDir, { withFileTypes: true }).catch(() => []);
  59. const bookIds = entries
  60. .filter((entry) => entry.isDirectory())
  61. .map((entry) => entry.name)
  62. .sort();
  63. if (session.activeBookId && bookIds.includes(session.activeBookId)) {
  64. return session.activeBookId;
  65. }
  66. if (bookIds.length === 1) {
  67. return bookIds[0];
  68. }
  69. return undefined;
  70. }