summaryrefslogtreecommitdiff
path: root/src/cli/localState.ts
blob: 73a1060af612d9d96aae2dac6751800f730ec3de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// Manages per-clone state stored in <dir>/.lattex-cli.json
// and the global auth credential at ~/.config/lattex/auth.json

import { join } from 'path'
import { readFile, writeFile, mkdir, chmod } from 'fs/promises'
import { existsSync } from 'fs'
import { homedir } from 'os'

const CONFIG_DIR = join(homedir(), '.config', 'lattex')
const AUTH_PATH = join(CONFIG_DIR, 'auth.json')
const STATE_FILE = '.lattex-cli.json'

// ── Global auth ──

export async function saveCookie(cookie: string): Promise<void> {
  await mkdir(CONFIG_DIR, { recursive: true })
  await writeFile(AUTH_PATH, JSON.stringify({ cookie }), { mode: 0o600 })
  // Ensure directory and file are user-only
  await chmod(CONFIG_DIR, 0o700).catch(() => {})
  await chmod(AUTH_PATH, 0o600).catch(() => {})
}

export async function loadCookie(): Promise<string | null> {
  try {
    const data = JSON.parse(await readFile(AUTH_PATH, 'utf-8'))
    return data.cookie || null
  } catch {
    return null
  }
}

// ── Per-clone state ──

export interface CloneState {
  projectId: string
  projectName: string
  /** docId → relPath */
  docPathMap: Record<string, string>
  /** relPath → docId */
  pathDocMap: Record<string, string>
  /** fileRefId → relPath */
  fileRefPathMap: Record<string, string>
  /** relPath → fileRefId */
  pathFileRefMap: Record<string, string>
  /** folderId → relDirPath */
  folderMap: Record<string, string>
  /** relDirPath → folderId */
  pathFolderMap: Record<string, string>
  rootFolderId: string
  rootDocId: string
  /** ISO timestamp of last pull */
  lastPull: string
  /** sha256 hash of each file at last pull (relPath → hash) */
  fileHashes: Record<string, string>
}

export function statePath(dir: string): string {
  return join(dir, STATE_FILE)
}

export async function loadState(dir: string): Promise<CloneState | null> {
  const p = statePath(dir)
  try {
    return JSON.parse(await readFile(p, 'utf-8'))
  } catch {
    return null
  }
}

export async function saveState(dir: string, state: CloneState): Promise<void> {
  await writeFile(statePath(dir), JSON.stringify(state, null, 2))
}

export function hasState(dir: string): boolean {
  return existsSync(statePath(dir))
}