xedoc-cli 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +8 -15
  2. package/bin/xedoc.mjs +13 -17
  3. package/build/client/assets/app-layout-d99dmiup.js +1 -0
  4. package/build/client/assets/app-shell-Dl69tJhv.js +1 -0
  5. package/build/client/assets/chat-B5FboIxH.js +1 -0
  6. package/build/client/assets/{connect-0oYrfAJT.js → connect-CHSFTXwk.js} +1 -1
  7. package/build/client/assets/{document-title-Dn4sU16M.js → document-title-B6Yxyaur.js} +1 -1
  8. package/build/client/assets/{entry.client-CM3vH2bv.js → entry.client-BlQXdBHx.js} +1 -1
  9. package/build/client/assets/home-Bahc85Gk.js +1 -0
  10. package/build/client/assets/{label-FUU4pCWu.js → label-C7i5Qt-O.js} +1 -1
  11. package/build/client/assets/manifest-fe1036ff.js +1 -0
  12. package/build/client/assets/{react-dom-KYDDPtOx.js → react-dom-CMuFyqmq.js} +1 -1
  13. package/build/client/assets/{root-DKEnPIjJ.js → root-feKzGV0p.js} +1 -1
  14. package/build/client/assets/{session-provider-FKGj36EG.js → session-provider-2Ozr-CuV.js} +1 -1
  15. package/build/server/index.js +1 -1
  16. package/package.json +2 -2
  17. package/prisma/schema.prisma +3 -19
  18. package/server/index.mjs +24 -2
  19. package/server/sqlite-setup.mjs +52 -47
  20. package/build/client/assets/api.workspaces.directories-B0tllRDq.js +0 -0
  21. package/build/client/assets/app-layout-C1QtSnIO.js +0 -1
  22. package/build/client/assets/app-shell-Bcxy4tS4.js +0 -1
  23. package/build/client/assets/chat-DrelwLpW.js +0 -1
  24. package/build/client/assets/home-DSWMwIrE.js +0 -1
  25. package/build/client/assets/manifest-9479dd15.js +0 -1
  26. /package/build/client/assets/{api.accounts-CHoT6sYP.js → api.accounts-x_2c5-qG.js} +0 -0
  27. /package/build/client/assets/{api.accounts._accountId-BixDYyx8.js → api.accounts._accountId-BksU0sQ7.js} +0 -0
  28. /package/build/client/assets/{api.accounts._accountId.authenticate-CLzgv3py.js → api.accounts._accountId.authenticate-Bp51NHGy.js} +0 -0
  29. /package/build/client/assets/{api.accounts._accountId.authenticate.callback-Bqhz8sDl.js → api.accounts._accountId.authenticate.callback-DLgNMRyd.js} +0 -0
  30. /package/build/client/assets/{api.accounts._accountId.models-VIVpVZrj.js → api.accounts._accountId.models-DGbCmT_9.js} +0 -0
  31. /package/build/client/assets/{api.accounts._accountId.rate-limits-C9iUvNFt.js → api.accounts._accountId.rate-limits-DZh4HPLO.js} +0 -0
  32. /package/build/client/assets/{api.accounts._accountId.runtime-settings-6XNKTx--.js → api.accounts._accountId.runtime-settings-ChGZGvfx.js} +0 -0
  33. /package/build/client/assets/{api.accounts.export-romutOT6.js → api.accounts.export-CwjXUcyG.js} +0 -0
  34. /package/build/client/assets/{api.accounts.import-BiWq2jPz.js → api.accounts.import-Km-76sRE.js} +0 -0
  35. /package/build/client/assets/{api.chats-C6-gVaXw.js → api.chats-DZ_6Q7rY.js} +0 -0
  36. /package/build/client/assets/{api.chats._chatId-DaXHa-ln.js → api.chats._chatId-BEX87qHo.js} +0 -0
  37. /package/build/client/assets/{api.chats._chatId.context-DlBgjpCD.js → api.chats._chatId.context-v4G0lNKq.js} +0 -0
  38. /package/build/client/assets/{api.chats._chatId.files-DVZKcoNV.js → api.chats._chatId.files-BrN7O-wM.js} +0 -0
  39. /package/build/client/assets/{api.chats._chatId.git._operation-8Xtyz4hF.js → api.chats._chatId.git._operation-CiUW8Knm.js} +0 -0
  40. /package/build/client/assets/{api.chats._chatId.interrupt-B71lrxkc.js → api.chats._chatId.interrupt-2DlVPDlX.js} +0 -0
  41. /package/build/client/assets/{api.chats._chatId.messages-iVzJcgvw.js → api.chats._chatId.messages-cDawTuvN.js} +0 -0
  42. /package/build/client/assets/{api.chats._chatId.server-requests._requestId.respond-BLhOUK8A.js → api.chats._chatId.server-requests._requestId.respond-CTlCffOk.js} +0 -0
  43. /package/build/client/assets/{api.users-BLvMDkJE.js → api.workspaces.directories-nVoleT74.js} +0 -0
  44. /package/build/client/assets/{jsx-runtime-B9QlDcuB.js → jsx-runtime-Dafdqr5g.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xedoc-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Local web UI for Codex account, chat, execution, and workspace management.",
5
5
  "author": "Edward Nguyen <monokaijs@gmail.com>",
6
6
  "type": "module",
@@ -36,7 +36,7 @@
36
36
  "clean:build": "node -e \"import('node:fs/promises').then(({ rm }) => rm('build', { recursive: true, force: true }))\"",
37
37
  "prepublishOnly": "pnpm typecheck",
38
38
  "prepack": "pnpm clean:build && pnpm build",
39
- "publish": "npm publish --access public",
39
+ "publish:npm": "npm publish --access public",
40
40
  "publish:dry-run": "npm publish --access public --dry-run",
41
41
  "prisma:generate": "prisma generate --schema prisma/schema.prisma",
42
42
  "db:setup": "node -e \"import('./server/sqlite-setup.mjs').then((m)=>m.setupSqliteDatabase())\""
@@ -4,7 +4,7 @@ generator client {
4
4
 
5
5
  datasource db {
6
6
  provider = "sqlite"
7
- url = env("DATABASE_URL")
7
+ url = "file:../.xedoc/xedoc.db"
8
8
  }
9
9
 
10
10
  enum AccountStatus {
@@ -54,16 +54,6 @@ enum RunStatus {
54
54
  CANCELLED
55
55
  }
56
56
 
57
- model User {
58
- id String @id @default(uuid())
59
- externalId String? @unique
60
- name String?
61
- createdAt DateTime @default(now())
62
- updatedAt DateTime @updatedAt
63
- accounts CodexAccount[]
64
- chats Chat[]
65
- }
66
-
67
57
  model ServerAuth {
68
58
  id String @id @default("server")
69
59
  passwordHash String
@@ -74,7 +64,6 @@ model ServerAuth {
74
64
 
75
65
  model CodexAccount {
76
66
  id String @id @default(uuid())
77
- userId String
78
67
  displayName String
79
68
  status AccountStatus @default(DISCONNECTED)
80
69
  command String @default("codex")
@@ -88,16 +77,12 @@ model CodexAccount {
88
77
  lastError String?
89
78
  createdAt DateTime @default(now())
90
79
  updatedAt DateTime @updatedAt
91
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
92
80
  chats Chat[]
93
81
  runs ChatRun[]
94
-
95
- @@index([userId])
96
82
  }
97
83
 
98
84
  model Chat {
99
85
  id String @id @default(uuid())
100
- userId String
101
86
  accountId String?
102
87
  title String
103
88
  workingDirectory String?
@@ -111,13 +96,12 @@ model Chat {
111
96
  lastActivityAt DateTime @default(now())
112
97
  createdAt DateTime @default(now())
113
98
  updatedAt DateTime @updatedAt
114
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
115
99
  account CodexAccount? @relation(fields: [accountId], references: [id], onDelete: SetNull)
116
100
  messages ChatMessage[]
117
101
  runs ChatRun[]
118
102
 
119
- @@index([userId, updatedAt])
120
- @@index([userId, lastActivityAt])
103
+ @@index([updatedAt])
104
+ @@index([lastActivityAt])
121
105
  @@index([accountId])
122
106
  }
123
107
 
package/server/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import "dotenv/config"
2
2
  import { createHmac, createHash, timingSafeEqual } from "node:crypto"
3
- import { createReadStream, statSync } from "node:fs"
3
+ import { createReadStream, mkdirSync, statSync } from "node:fs"
4
4
  import { createServer } from "node:http"
5
+ import { homedir } from "node:os"
5
6
  import { dirname, extname, join, normalize, resolve } from "node:path"
6
7
  import { fileURLToPath } from "node:url"
7
8
  import { PrismaClient } from "@prisma/client"
@@ -14,8 +15,15 @@ const DEFAULT_PORT = "6354"
14
15
  const SERVER_AUTH_ID = "server"
15
16
  const serverRoot = dirname(fileURLToPath(import.meta.url))
16
17
  const packageRoot = resolve(serverRoot, "..")
17
- const prisma = new PrismaClient()
18
18
  const options = parseArgs(process.argv.slice(2))
19
+ const workspaceRoot = resolveHomePath(process.env.CODEX_WORKSPACE_ROOT ?? homedir())
20
+ const databasePath = join(workspaceRoot, ".xedoc", "xedoc.db")
21
+ const databaseUrl = sqliteDatabaseUrl(databasePath)
22
+ process.env.DATABASE_URL = databaseUrl
23
+ mkdirSync(dirname(databasePath), { recursive: true, mode: 0o700 })
24
+ const prisma = new PrismaClient({
25
+ datasources: { db: { url: databaseUrl } },
26
+ })
19
27
  const build = await import(join(packageRoot, "build/server/index.js"))
20
28
  const clientRoot = join(packageRoot, "build/client")
21
29
  const requestListener = createRequestListener({
@@ -75,6 +83,20 @@ function fail(message) {
75
83
  process.exit(1)
76
84
  }
77
85
 
86
+ function resolveHomePath(path) {
87
+ if (path === "~") {
88
+ return homedir()
89
+ }
90
+ if (path.startsWith("~/")) {
91
+ return join(homedir(), path.slice(2))
92
+ }
93
+ return resolve(path)
94
+ }
95
+
96
+ function sqliteDatabaseUrl(path) {
97
+ return `file:${path}?connection_limit=1&pool_timeout=30`
98
+ }
99
+
78
100
  function installSocketServer(httpServer) {
79
101
  const io = new SocketServer(httpServer, {
80
102
  path: "/socket.io",
@@ -1,18 +1,21 @@
1
1
  import "dotenv/config"
2
2
  import { mkdir } from "node:fs/promises"
3
- import { dirname, isAbsolute, resolve } from "node:path"
4
- import { fileURLToPath } from "node:url"
5
-
6
- const schemaDirectory = dirname(
7
- fileURLToPath(new URL("../prisma/schema.prisma", import.meta.url)),
8
- )
3
+ import { homedir } from "node:os"
4
+ import { dirname, join, resolve } from "node:path"
9
5
 
10
6
  export async function setupSqliteDatabase() {
11
- await ensureSqliteDirectory()
7
+ const databasePath = workspaceDatabasePath()
8
+ const databaseUrl = sqliteDatabaseUrl(databasePath)
9
+ process.env.DATABASE_URL = databaseUrl
10
+ await mkdir(dirname(databasePath), { recursive: true, mode: 0o700 })
12
11
  const { PrismaClient } = await import("@prisma/client")
13
- const prisma = new PrismaClient()
12
+ const prisma = new PrismaClient({
13
+ datasources: { db: { url: databaseUrl } },
14
+ })
14
15
  try {
15
16
  await prisma.$executeRawUnsafe("PRAGMA foreign_keys = ON")
17
+ await prisma.$queryRawUnsafe("PRAGMA journal_mode = WAL")
18
+ await prisma.$queryRawUnsafe("PRAGMA busy_timeout = 30000")
16
19
  for (const statement of schemaStatements) {
17
20
  try {
18
21
  await prisma.$executeRawUnsafe(statement)
@@ -32,39 +35,31 @@ function isDuplicateColumnError(error) {
32
35
  return message.toLowerCase().includes("duplicate column name")
33
36
  }
34
37
 
35
- async function ensureSqliteDirectory() {
36
- const databaseUrl = process.env.DATABASE_URL
37
- if (!databaseUrl?.startsWith("file:")) {
38
- return
38
+ function workspaceDatabasePath() {
39
+ return join(
40
+ resolveHomePath(process.env.CODEX_WORKSPACE_ROOT?.trim() || homedir()),
41
+ ".xedoc",
42
+ "xedoc.db",
43
+ )
44
+ }
45
+
46
+ function resolveHomePath(path) {
47
+ if (path === "~") {
48
+ return homedir()
39
49
  }
40
- const filePath = databaseUrl.slice("file:".length)
41
- if (!filePath || filePath === ":memory:" || filePath.includes("?")) {
42
- return
50
+ if (path.startsWith("~/")) {
51
+ return join(homedir(), path.slice(2))
43
52
  }
44
- const resolvedPath = isAbsolute(filePath)
45
- ? filePath
46
- : resolve(schemaDirectory, filePath)
47
- await mkdir(dirname(resolvedPath), { recursive: true })
53
+ return resolve(path)
48
54
  }
49
55
 
50
- const schemaStatements = [
51
- `CREATE TABLE IF NOT EXISTS "User" (
52
- "id" TEXT NOT NULL PRIMARY KEY,
53
- "externalId" TEXT,
54
- "name" TEXT,
55
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
56
- "updatedAt" DATETIME NOT NULL
57
- )`,
58
- `CREATE TABLE IF NOT EXISTS "ServerAuth" (
59
- "id" TEXT NOT NULL PRIMARY KEY DEFAULT 'server',
60
- "passwordHash" TEXT NOT NULL,
61
- "tokenSecret" TEXT NOT NULL,
62
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
63
- "updatedAt" DATETIME NOT NULL
64
- )`,
65
- `CREATE TABLE IF NOT EXISTS "CodexAccount" (
56
+ function sqliteDatabaseUrl(path) {
57
+ return `file:${path}?connection_limit=1&pool_timeout=30`
58
+ }
59
+
60
+ function createCodexAccountTable(tableName) {
61
+ return `CREATE TABLE IF NOT EXISTS "${tableName}" (
66
62
  "id" TEXT NOT NULL PRIMARY KEY,
67
- "userId" TEXT NOT NULL,
68
63
  "displayName" TEXT NOT NULL,
69
64
  "status" TEXT NOT NULL DEFAULT 'DISCONNECTED',
70
65
  "command" TEXT NOT NULL DEFAULT 'codex',
@@ -77,12 +72,13 @@ const schemaStatements = [
77
72
  "lastAuthUrl" TEXT,
78
73
  "lastError" TEXT,
79
74
  "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
80
- "updatedAt" DATETIME NOT NULL,
81
- CONSTRAINT "CodexAccount_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
82
- )`,
83
- `CREATE TABLE IF NOT EXISTS "Chat" (
75
+ "updatedAt" DATETIME NOT NULL
76
+ )`
77
+ }
78
+
79
+ function createChatTable(tableName) {
80
+ return `CREATE TABLE IF NOT EXISTS "${tableName}" (
84
81
  "id" TEXT NOT NULL PRIMARY KEY,
85
- "userId" TEXT NOT NULL,
86
82
  "accountId" TEXT,
87
83
  "title" TEXT NOT NULL,
88
84
  "workingDirectory" TEXT,
@@ -96,9 +92,20 @@ const schemaStatements = [
96
92
  "lastActivityAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
97
93
  "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
98
94
  "updatedAt" DATETIME NOT NULL,
99
- CONSTRAINT "Chat_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
100
- CONSTRAINT "Chat_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "CodexAccount" ("id") ON DELETE SET NULL ON UPDATE CASCADE
95
+ CONSTRAINT "${tableName}_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "CodexAccount" ("id") ON DELETE SET NULL ON UPDATE CASCADE
96
+ )`
97
+ }
98
+
99
+ const schemaStatements = [
100
+ `CREATE TABLE IF NOT EXISTS "ServerAuth" (
101
+ "id" TEXT NOT NULL PRIMARY KEY DEFAULT 'server',
102
+ "passwordHash" TEXT NOT NULL,
103
+ "tokenSecret" TEXT NOT NULL,
104
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
105
+ "updatedAt" DATETIME NOT NULL
101
106
  )`,
107
+ createCodexAccountTable("CodexAccount"),
108
+ createChatTable("Chat"),
102
109
  `CREATE TABLE IF NOT EXISTS "ChatMessage" (
103
110
  "id" TEXT NOT NULL PRIMARY KEY,
104
111
  "chatId" TEXT NOT NULL,
@@ -134,14 +141,12 @@ const schemaStatements = [
134
141
  CONSTRAINT "ChatRun_chatId_fkey" FOREIGN KEY ("chatId") REFERENCES "Chat" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
135
142
  CONSTRAINT "ChatRun_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "CodexAccount" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
136
143
  )`,
137
- 'CREATE UNIQUE INDEX IF NOT EXISTS "User_externalId_key" ON "User"("externalId")',
138
144
  'ALTER TABLE "CodexAccount" ADD COLUMN "defaultModel" TEXT',
139
145
  'ALTER TABLE "CodexAccount" ADD COLUMN "defaultPermissionMode" TEXT',
140
146
  'ALTER TABLE "CodexAccount" ADD COLUMN "defaultReasoningEffort" TEXT',
141
147
  'ALTER TABLE "CodexAccount" ADD COLUMN "defaultServiceTier" TEXT',
142
- 'CREATE INDEX IF NOT EXISTS "CodexAccount_userId_idx" ON "CodexAccount"("userId")',
143
- 'CREATE INDEX IF NOT EXISTS "Chat_userId_updatedAt_idx" ON "Chat"("userId", "updatedAt")',
144
- 'CREATE INDEX IF NOT EXISTS "Chat_userId_lastActivityAt_idx" ON "Chat"("userId", "lastActivityAt")',
148
+ 'CREATE INDEX IF NOT EXISTS "Chat_updatedAt_idx" ON "Chat"("updatedAt")',
149
+ 'CREATE INDEX IF NOT EXISTS "Chat_lastActivityAt_idx" ON "Chat"("lastActivityAt")',
145
150
  'CREATE INDEX IF NOT EXISTS "Chat_accountId_idx" ON "Chat"("accountId")',
146
151
  'CREATE INDEX IF NOT EXISTS "ChatMessage_chatId_sequence_idx" ON "ChatMessage"("chatId", "sequence")',
147
152
  'CREATE INDEX IF NOT EXISTS "ChatMessage_chatId_turnId_idx" ON "ChatMessage"("chatId", "turnId")',
@@ -1 +0,0 @@
1
- import{j as r,t as s}from"./jsx-runtime-B9QlDcuB.js";import{t}from"./app-shell-Bcxy4tS4.js";var a=s(),o=r(function(){return(0,a.jsx)(t,{})});export{o as default};