@stonerzju/opencode 1.2.17 → 1.2.19

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 (261) hide show
  1. package/bin/opencode +29 -157
  2. package/package.json +29 -29
  3. package/src/acp/agent.ts +4 -4
  4. package/src/acp/session.ts +1 -1
  5. package/src/agent/agent.ts +3 -3
  6. package/src/bun/index.ts +2 -2
  7. package/src/cli/cmd/acp.ts +3 -3
  8. package/src/cli/cmd/debug/file.ts +1 -1
  9. package/src/cli/cmd/github.ts +2 -2
  10. package/src/cli/cmd/pr.ts +1 -1
  11. package/src/cli/cmd/tui/app.tsx +24 -24
  12. package/src/cli/cmd/tui/attach.ts +3 -3
  13. package/src/cli/cmd/tui/component/dialog-agent.tsx +3 -3
  14. package/src/cli/cmd/tui/component/dialog-command.tsx +3 -3
  15. package/src/cli/cmd/tui/component/dialog-mcp.tsx +5 -5
  16. package/src/cli/cmd/tui/component/dialog-model.tsx +4 -4
  17. package/src/cli/cmd/tui/component/dialog-provider.tsx +4 -4
  18. package/src/cli/cmd/tui/component/dialog-session-list.tsx +5 -5
  19. package/src/cli/cmd/tui/component/dialog-session-rename.tsx +3 -3
  20. package/src/cli/cmd/tui/component/dialog-skill.tsx +3 -3
  21. package/src/cli/cmd/tui/component/dialog-stash.tsx +3 -3
  22. package/src/cli/cmd/tui/component/dialog-status.tsx +2 -2
  23. package/src/cli/cmd/tui/component/dialog-tag.tsx +3 -3
  24. package/src/cli/cmd/tui/component/logo.tsx +2 -2
  25. package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +6 -6
  26. package/src/cli/cmd/tui/component/prompt/frecency.tsx +2 -2
  27. package/src/cli/cmd/tui/component/prompt/history.tsx +2 -2
  28. package/src/cli/cmd/tui/component/prompt/index.tsx +14 -14
  29. package/src/cli/cmd/tui/component/prompt/stash.tsx +2 -2
  30. package/src/cli/cmd/tui/component/textarea-keybindings.ts +1 -1
  31. package/src/cli/cmd/tui/component/tips.tsx +1 -1
  32. package/src/cli/cmd/tui/context/directory.ts +1 -1
  33. package/src/cli/cmd/tui/context/exit.tsx +1 -1
  34. package/src/cli/cmd/tui/context/keybind.tsx +2 -2
  35. package/src/cli/cmd/tui/context/kv.tsx +2 -2
  36. package/src/cli/cmd/tui/context/local.tsx +6 -6
  37. package/src/cli/cmd/tui/context/sync.tsx +4 -4
  38. package/src/cli/cmd/tui/context/theme/opencode.json +245 -0
  39. package/src/cli/cmd/tui/context/theme.tsx +2 -2
  40. package/src/cli/cmd/tui/context/tui-config.tsx +1 -1
  41. package/src/cli/cmd/tui/event.ts +2 -2
  42. package/src/cli/cmd/tui/routes/home.tsx +6 -6
  43. package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +6 -6
  44. package/src/cli/cmd/tui/routes/session/dialog-message.tsx +6 -6
  45. package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +2 -2
  46. package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +3 -3
  47. package/src/cli/cmd/tui/routes/session/header.tsx +5 -5
  48. package/src/cli/cmd/tui/routes/session/index.tsx +32 -32
  49. package/src/cli/cmd/tui/routes/session/permission.tsx +4 -4
  50. package/src/cli/cmd/tui/routes/session/sidebar.tsx +4 -4
  51. package/src/cli/cmd/tui/thread.ts +9 -9
  52. package/src/cli/cmd/tui/ui/dialog-confirm.tsx +1 -1
  53. package/src/cli/cmd/tui/ui/dialog-help.tsx +2 -2
  54. package/src/cli/cmd/tui/ui/dialog-select.tsx +5 -5
  55. package/src/cli/cmd/tui/ui/dialog.tsx +3 -3
  56. package/src/cli/cmd/tui/ui/toast.tsx +1 -1
  57. package/src/cli/cmd/tui/util/editor.ts +3 -3
  58. package/src/cli/cmd/tui/util/transcript.ts +1 -1
  59. package/src/cli/cmd/tui/worker.ts +10 -10
  60. package/src/cli/error.ts +1 -1
  61. package/src/cli/ui.ts +1 -1
  62. package/src/cli/upgrade.ts +4 -4
  63. package/src/command/index.ts +1 -1
  64. package/src/config/config.ts +10 -10
  65. package/src/config/markdown.ts +1 -1
  66. package/src/config/migrate-tui-config.ts +5 -5
  67. package/src/config/paths.ts +4 -4
  68. package/src/config/tui.ts +4 -4
  69. package/src/control/control.sql.ts +1 -1
  70. package/src/control/index.ts +1 -1
  71. package/src/control-plane/adaptors/worktree.ts +1 -1
  72. package/src/control-plane/session-proxy-middleware.ts +1 -1
  73. package/src/control-plane/workspace.sql.ts +1 -1
  74. package/src/control-plane/workspace.ts +7 -7
  75. package/src/file/index.ts +1 -1
  76. package/src/file/ripgrep.ts +2 -2
  77. package/src/file/watcher.ts +5 -5
  78. package/src/format/formatter.ts +1 -1
  79. package/src/ide/index.ts +3 -3
  80. package/src/index.ts +1 -1
  81. package/src/installation/index.ts +3 -3
  82. package/src/lsp/client.ts +3 -3
  83. package/src/lsp/index.ts +3 -3
  84. package/src/mcp/index.ts +4 -4
  85. package/src/permission/index.ts +2 -2
  86. package/src/permission/next.ts +10 -10
  87. package/src/plugin/codex.ts +1 -1
  88. package/src/plugin/copilot.ts +2 -2
  89. package/src/plugin/index.ts +1 -1
  90. package/src/project/bootstrap.ts +2 -2
  91. package/src/project/instance.ts +4 -4
  92. package/src/project/project.sql.ts +1 -1
  93. package/src/project/project.ts +5 -5
  94. package/src/project/state.ts +1 -1
  95. package/src/project/vcs.ts +4 -4
  96. package/src/provider/auth.ts +4 -4
  97. package/src/provider/error.ts +1 -1
  98. package/src/provider/models-snapshot.ts +2 -0
  99. package/src/provider/models.ts +1 -1
  100. package/src/provider/provider.ts +2 -2
  101. package/src/provider/transform.ts +2 -2
  102. package/src/pty/index.ts +5 -5
  103. package/src/question/index.ts +5 -5
  104. package/src/server/event.ts +1 -1
  105. package/src/server/mdns.ts +1 -1
  106. package/src/server/routes/global.ts +3 -3
  107. package/src/server/routes/permission.ts +1 -1
  108. package/src/server/routes/pty.ts +1 -1
  109. package/src/server/routes/session.ts +4 -4
  110. package/src/server/routes/tui.ts +1 -1
  111. package/src/server/server.ts +3 -3
  112. package/src/session/compaction.ts +7 -7
  113. package/src/session/index.ts +10 -10
  114. package/src/session/instruction.ts +1 -1
  115. package/src/session/llm.ts +11 -11
  116. package/src/session/message-v2.ts +10 -10
  117. package/src/session/message.ts +1 -1
  118. package/src/session/processor.ts +10 -10
  119. package/src/session/prompt.ts +8 -8
  120. package/src/session/retry.ts +2 -2
  121. package/src/session/revert.ts +1 -1
  122. package/src/session/session.sql.ts +3 -3
  123. package/src/session/status.ts +3 -3
  124. package/src/session/summary.ts +5 -5
  125. package/src/session/system.ts +1 -1
  126. package/src/session/todo.ts +2 -2
  127. package/src/share/share-next.ts +7 -7
  128. package/src/share/share.sql.ts +1 -1
  129. package/src/shell/shell.ts +3 -3
  130. package/src/skill/skill.ts +6 -6
  131. package/src/storage/db.ts +1 -1
  132. package/src/storage/storage.ts +1 -1
  133. package/src/tool/bash.ts +6 -6
  134. package/src/tool/edit.ts +1 -1
  135. package/src/tool/registry.ts +2 -2
  136. package/src/tool/skill.ts +1 -1
  137. package/src/tool/task.ts +3 -3
  138. package/src/util/array.ts +10 -0
  139. package/src/util/binary.ts +41 -0
  140. package/src/util/encode.ts +51 -0
  141. package/src/util/error.ts +54 -0
  142. package/src/util/identifier.ts +48 -0
  143. package/src/util/lazy.ts +4 -16
  144. package/src/util/path.ts +37 -0
  145. package/src/util/retry.ts +41 -0
  146. package/src/util/slug.ts +74 -0
  147. package/src/worktree/index.ts +3 -3
  148. package/AGENTS.md +0 -10
  149. package/BUN_SHELL_MIGRATION_PLAN.md +0 -136
  150. package/Dockerfile +0 -18
  151. package/README.md +0 -15
  152. package/bunfig.toml +0 -7
  153. package/drizzle.config.ts +0 -10
  154. package/script/build.ts +0 -224
  155. package/script/check-migrations.ts +0 -16
  156. package/script/postinstall.mjs +0 -131
  157. package/script/publish.ts +0 -181
  158. package/script/schema.ts +0 -63
  159. package/script/seed-e2e.ts +0 -50
  160. package/sst-env.d.ts +0 -10
  161. package/test/AGENTS.md +0 -81
  162. package/test/acp/agent-interface.test.ts +0 -51
  163. package/test/acp/event-subscription.test.ts +0 -683
  164. package/test/agent/agent.test.ts +0 -689
  165. package/test/bun.test.ts +0 -53
  166. package/test/cli/github-action.test.ts +0 -197
  167. package/test/cli/github-remote.test.ts +0 -80
  168. package/test/cli/import.test.ts +0 -38
  169. package/test/cli/plugin-auth-picker.test.ts +0 -120
  170. package/test/cli/tui/transcript.test.ts +0 -322
  171. package/test/config/agent-color.test.ts +0 -71
  172. package/test/config/config.test.ts +0 -1886
  173. package/test/config/fixtures/empty-frontmatter.md +0 -4
  174. package/test/config/fixtures/frontmatter.md +0 -28
  175. package/test/config/fixtures/markdown-header.md +0 -11
  176. package/test/config/fixtures/no-frontmatter.md +0 -1
  177. package/test/config/fixtures/weird-model-id.md +0 -13
  178. package/test/config/markdown.test.ts +0 -228
  179. package/test/config/tui.test.ts +0 -510
  180. package/test/control-plane/session-proxy-middleware.test.ts +0 -147
  181. package/test/control-plane/sse.test.ts +0 -56
  182. package/test/control-plane/workspace-server-sse.test.ts +0 -65
  183. package/test/control-plane/workspace-sync.test.ts +0 -97
  184. package/test/file/ignore.test.ts +0 -10
  185. package/test/file/index.test.ts +0 -394
  186. package/test/file/path-traversal.test.ts +0 -198
  187. package/test/file/ripgrep.test.ts +0 -39
  188. package/test/file/time.test.ts +0 -361
  189. package/test/fixture/db.ts +0 -11
  190. package/test/fixture/fixture.ts +0 -45
  191. package/test/fixture/lsp/fake-lsp-server.js +0 -77
  192. package/test/fixture/skills/agents-sdk/SKILL.md +0 -152
  193. package/test/fixture/skills/agents-sdk/references/callable.md +0 -92
  194. package/test/fixture/skills/cloudflare/SKILL.md +0 -211
  195. package/test/fixture/skills/index.json +0 -6
  196. package/test/ide/ide.test.ts +0 -82
  197. package/test/keybind.test.ts +0 -421
  198. package/test/lsp/client.test.ts +0 -95
  199. package/test/mcp/headers.test.ts +0 -153
  200. package/test/mcp/oauth-browser.test.ts +0 -249
  201. package/test/memory/abort-leak.test.ts +0 -136
  202. package/test/patch/patch.test.ts +0 -348
  203. package/test/permission/arity.test.ts +0 -33
  204. package/test/permission/next.test.ts +0 -689
  205. package/test/permission-task.test.ts +0 -319
  206. package/test/plugin/auth-override.test.ts +0 -44
  207. package/test/plugin/codex.test.ts +0 -123
  208. package/test/preload.ts +0 -80
  209. package/test/project/project.test.ts +0 -348
  210. package/test/project/worktree-remove.test.ts +0 -65
  211. package/test/provider/amazon-bedrock.test.ts +0 -446
  212. package/test/provider/copilot/convert-to-copilot-messages.test.ts +0 -523
  213. package/test/provider/copilot/copilot-chat-model.test.ts +0 -592
  214. package/test/provider/gitlab-duo.test.ts +0 -262
  215. package/test/provider/provider.test.ts +0 -2220
  216. package/test/provider/transform.test.ts +0 -2353
  217. package/test/pty/pty-output-isolation.test.ts +0 -140
  218. package/test/question/question.test.ts +0 -300
  219. package/test/scheduler.test.ts +0 -73
  220. package/test/server/global-session-list.test.ts +0 -89
  221. package/test/server/session-list.test.ts +0 -90
  222. package/test/server/session-select.test.ts +0 -78
  223. package/test/session/compaction.test.ts +0 -423
  224. package/test/session/instruction.test.ts +0 -170
  225. package/test/session/llm.test.ts +0 -667
  226. package/test/session/message-v2.test.ts +0 -924
  227. package/test/session/prompt.test.ts +0 -211
  228. package/test/session/retry.test.ts +0 -188
  229. package/test/session/revert-compact.test.ts +0 -285
  230. package/test/session/session.test.ts +0 -71
  231. package/test/session/structured-output-integration.test.ts +0 -233
  232. package/test/session/structured-output.test.ts +0 -385
  233. package/test/skill/discovery.test.ts +0 -110
  234. package/test/skill/skill.test.ts +0 -388
  235. package/test/snapshot/snapshot.test.ts +0 -1180
  236. package/test/storage/json-migration.test.ts +0 -846
  237. package/test/tool/__snapshots__/tool.test.ts.snap +0 -9
  238. package/test/tool/apply_patch.test.ts +0 -566
  239. package/test/tool/bash.test.ts +0 -402
  240. package/test/tool/edit.test.ts +0 -496
  241. package/test/tool/external-directory.test.ts +0 -127
  242. package/test/tool/fixtures/large-image.png +0 -0
  243. package/test/tool/fixtures/models-api.json +0 -38413
  244. package/test/tool/grep.test.ts +0 -110
  245. package/test/tool/question.test.ts +0 -107
  246. package/test/tool/read.test.ts +0 -504
  247. package/test/tool/registry.test.ts +0 -122
  248. package/test/tool/skill.test.ts +0 -112
  249. package/test/tool/truncation.test.ts +0 -160
  250. package/test/tool/webfetch.test.ts +0 -100
  251. package/test/tool/write.test.ts +0 -348
  252. package/test/util/filesystem.test.ts +0 -443
  253. package/test/util/format.test.ts +0 -59
  254. package/test/util/glob.test.ts +0 -164
  255. package/test/util/iife.test.ts +0 -36
  256. package/test/util/lazy.test.ts +0 -50
  257. package/test/util/lock.test.ts +0 -72
  258. package/test/util/process.test.ts +0 -59
  259. package/test/util/timeout.test.ts +0 -21
  260. package/test/util/wildcard.test.ts +0 -90
  261. package/tsconfig.json +0 -16
@@ -1,846 +0,0 @@
1
- import { describe, test, expect, beforeEach, afterEach } from "bun:test"
2
- import { Database } from "bun:sqlite"
3
- import { drizzle } from "drizzle-orm/bun-sqlite"
4
- import { migrate } from "drizzle-orm/bun-sqlite/migrator"
5
- import path from "path"
6
- import fs from "fs/promises"
7
- import { readFileSync, readdirSync } from "fs"
8
- import { JsonMigration } from "../../src/storage/json-migration"
9
- import { Global } from "../../src/global"
10
- import { ProjectTable } from "../../src/project/project.sql"
11
- import { SessionTable, MessageTable, PartTable, TodoTable, PermissionTable } from "../../src/session/session.sql"
12
- import { SessionShareTable } from "../../src/share/share.sql"
13
-
14
- // Test fixtures
15
- const fixtures = {
16
- project: {
17
- id: "proj_test123abc",
18
- name: "Test Project",
19
- worktree: "/test/path",
20
- vcs: "git" as const,
21
- sandboxes: [],
22
- },
23
- session: {
24
- id: "ses_test456def",
25
- projectID: "proj_test123abc",
26
- slug: "test-session",
27
- directory: "/test/path",
28
- title: "Test Session",
29
- version: "1.0.0",
30
- time: { created: 1700000000000, updated: 1700000001000 },
31
- },
32
- message: {
33
- id: "msg_test789ghi",
34
- sessionID: "ses_test456def",
35
- role: "user" as const,
36
- agent: "default",
37
- model: { providerID: "openai", modelID: "gpt-4" },
38
- time: { created: 1700000000000 },
39
- },
40
- part: {
41
- id: "prt_testabc123",
42
- messageID: "msg_test789ghi",
43
- sessionID: "ses_test456def",
44
- type: "text" as const,
45
- text: "Hello, world!",
46
- },
47
- }
48
-
49
- // Helper to create test storage directory structure
50
- async function setupStorageDir() {
51
- const storageDir = path.join(Global.Path.data, "storage")
52
- await fs.rm(storageDir, { recursive: true, force: true })
53
- await fs.mkdir(path.join(storageDir, "project"), { recursive: true })
54
- await fs.mkdir(path.join(storageDir, "session", "proj_test123abc"), { recursive: true })
55
- await fs.mkdir(path.join(storageDir, "message", "ses_test456def"), { recursive: true })
56
- await fs.mkdir(path.join(storageDir, "part", "msg_test789ghi"), { recursive: true })
57
- await fs.mkdir(path.join(storageDir, "session_diff"), { recursive: true })
58
- await fs.mkdir(path.join(storageDir, "todo"), { recursive: true })
59
- await fs.mkdir(path.join(storageDir, "permission"), { recursive: true })
60
- await fs.mkdir(path.join(storageDir, "session_share"), { recursive: true })
61
- // Create legacy marker to indicate JSON storage exists
62
- await Bun.write(path.join(storageDir, "migration"), "1")
63
- return storageDir
64
- }
65
-
66
- async function writeProject(storageDir: string, project: Record<string, unknown>) {
67
- await Bun.write(path.join(storageDir, "project", `${project.id}.json`), JSON.stringify(project))
68
- }
69
-
70
- async function writeSession(storageDir: string, projectID: string, session: Record<string, unknown>) {
71
- await Bun.write(path.join(storageDir, "session", projectID, `${session.id}.json`), JSON.stringify(session))
72
- }
73
-
74
- // Helper to create in-memory test database with schema
75
- function createTestDb() {
76
- const sqlite = new Database(":memory:")
77
- sqlite.exec("PRAGMA foreign_keys = ON")
78
-
79
- // Apply schema migrations using drizzle migrate
80
- const dir = path.join(import.meta.dirname, "../../migration")
81
- const entries = readdirSync(dir, { withFileTypes: true })
82
- const migrations = entries
83
- .filter((entry) => entry.isDirectory())
84
- .map((entry) => ({
85
- sql: readFileSync(path.join(dir, entry.name, "migration.sql"), "utf-8"),
86
- timestamp: Number(entry.name.split("_")[0]),
87
- }))
88
- .sort((a, b) => a.timestamp - b.timestamp)
89
- migrate(drizzle({ client: sqlite }), migrations)
90
-
91
- return sqlite
92
- }
93
-
94
- describe("JSON to SQLite migration", () => {
95
- let storageDir: string
96
- let sqlite: Database
97
-
98
- beforeEach(async () => {
99
- storageDir = await setupStorageDir()
100
- sqlite = createTestDb()
101
- })
102
-
103
- afterEach(async () => {
104
- sqlite.close()
105
- await fs.rm(storageDir, { recursive: true, force: true })
106
- })
107
-
108
- test("migrates project", async () => {
109
- await writeProject(storageDir, {
110
- id: "proj_test123abc",
111
- worktree: "/test/path",
112
- vcs: "git",
113
- name: "Test Project",
114
- time: { created: 1700000000000, updated: 1700000001000 },
115
- sandboxes: ["/test/sandbox"],
116
- })
117
-
118
- const stats = await JsonMigration.run(sqlite)
119
-
120
- expect(stats?.projects).toBe(1)
121
-
122
- const db = drizzle({ client: sqlite })
123
- const projects = db.select().from(ProjectTable).all()
124
- expect(projects.length).toBe(1)
125
- expect(projects[0].id).toBe("proj_test123abc")
126
- expect(projects[0].worktree).toBe("/test/path")
127
- expect(projects[0].name).toBe("Test Project")
128
- expect(projects[0].sandboxes).toEqual(["/test/sandbox"])
129
- })
130
-
131
- test("uses filename for project id when JSON has different value", async () => {
132
- await Bun.write(
133
- path.join(storageDir, "project", "proj_filename.json"),
134
- JSON.stringify({
135
- id: "proj_different_in_json", // Stale! Should be ignored
136
- worktree: "/test/path",
137
- vcs: "git",
138
- name: "Test Project",
139
- sandboxes: [],
140
- }),
141
- )
142
-
143
- const stats = await JsonMigration.run(sqlite)
144
-
145
- expect(stats?.projects).toBe(1)
146
-
147
- const db = drizzle({ client: sqlite })
148
- const projects = db.select().from(ProjectTable).all()
149
- expect(projects.length).toBe(1)
150
- expect(projects[0].id).toBe("proj_filename") // Uses filename, not JSON id
151
- })
152
-
153
- test("migrates project with commands", async () => {
154
- await writeProject(storageDir, {
155
- id: "proj_with_commands",
156
- worktree: "/test/path",
157
- vcs: "git",
158
- name: "Project With Commands",
159
- time: { created: 1700000000000, updated: 1700000001000 },
160
- sandboxes: ["/test/sandbox"],
161
- commands: { start: "npm run dev" },
162
- })
163
-
164
- const stats = await JsonMigration.run(sqlite)
165
-
166
- expect(stats?.projects).toBe(1)
167
-
168
- const db = drizzle({ client: sqlite })
169
- const projects = db.select().from(ProjectTable).all()
170
- expect(projects.length).toBe(1)
171
- expect(projects[0].id).toBe("proj_with_commands")
172
- expect(projects[0].commands).toEqual({ start: "npm run dev" })
173
- })
174
-
175
- test("migrates project without commands field", async () => {
176
- await writeProject(storageDir, {
177
- id: "proj_no_commands",
178
- worktree: "/test/path",
179
- vcs: "git",
180
- name: "Project Without Commands",
181
- time: { created: 1700000000000, updated: 1700000001000 },
182
- sandboxes: [],
183
- })
184
-
185
- const stats = await JsonMigration.run(sqlite)
186
-
187
- expect(stats?.projects).toBe(1)
188
-
189
- const db = drizzle({ client: sqlite })
190
- const projects = db.select().from(ProjectTable).all()
191
- expect(projects.length).toBe(1)
192
- expect(projects[0].id).toBe("proj_no_commands")
193
- expect(projects[0].commands).toBeNull()
194
- })
195
-
196
- test("migrates session with individual columns", async () => {
197
- await writeProject(storageDir, {
198
- id: "proj_test123abc",
199
- worktree: "/test/path",
200
- time: { created: Date.now(), updated: Date.now() },
201
- sandboxes: [],
202
- })
203
-
204
- await writeSession(storageDir, "proj_test123abc", {
205
- id: "ses_test456def",
206
- projectID: "proj_test123abc",
207
- slug: "test-session",
208
- directory: "/test/dir",
209
- title: "Test Session Title",
210
- version: "1.0.0",
211
- time: { created: 1700000000000, updated: 1700000001000 },
212
- summary: { additions: 10, deletions: 5, files: 3 },
213
- share: { url: "https://example.com/share" },
214
- })
215
-
216
- await JsonMigration.run(sqlite)
217
-
218
- const db = drizzle({ client: sqlite })
219
- const sessions = db.select().from(SessionTable).all()
220
- expect(sessions.length).toBe(1)
221
- expect(sessions[0].id).toBe("ses_test456def")
222
- expect(sessions[0].project_id).toBe("proj_test123abc")
223
- expect(sessions[0].slug).toBe("test-session")
224
- expect(sessions[0].title).toBe("Test Session Title")
225
- expect(sessions[0].summary_additions).toBe(10)
226
- expect(sessions[0].summary_deletions).toBe(5)
227
- expect(sessions[0].share_url).toBe("https://example.com/share")
228
- })
229
-
230
- test("migrates messages and parts", async () => {
231
- await writeProject(storageDir, {
232
- id: "proj_test123abc",
233
- worktree: "/",
234
- time: { created: Date.now(), updated: Date.now() },
235
- sandboxes: [],
236
- })
237
- await writeSession(storageDir, "proj_test123abc", { ...fixtures.session })
238
- await Bun.write(
239
- path.join(storageDir, "message", "ses_test456def", "msg_test789ghi.json"),
240
- JSON.stringify({ ...fixtures.message }),
241
- )
242
- await Bun.write(
243
- path.join(storageDir, "part", "msg_test789ghi", "prt_testabc123.json"),
244
- JSON.stringify({ ...fixtures.part }),
245
- )
246
-
247
- const stats = await JsonMigration.run(sqlite)
248
-
249
- expect(stats?.messages).toBe(1)
250
- expect(stats?.parts).toBe(1)
251
-
252
- const db = drizzle({ client: sqlite })
253
- const messages = db.select().from(MessageTable).all()
254
- expect(messages.length).toBe(1)
255
- expect(messages[0].id).toBe("msg_test789ghi")
256
-
257
- const parts = db.select().from(PartTable).all()
258
- expect(parts.length).toBe(1)
259
- expect(parts[0].id).toBe("prt_testabc123")
260
- })
261
-
262
- test("migrates legacy parts without ids in body", async () => {
263
- await writeProject(storageDir, {
264
- id: "proj_test123abc",
265
- worktree: "/",
266
- time: { created: Date.now(), updated: Date.now() },
267
- sandboxes: [],
268
- })
269
- await writeSession(storageDir, "proj_test123abc", { ...fixtures.session })
270
- await Bun.write(
271
- path.join(storageDir, "message", "ses_test456def", "msg_test789ghi.json"),
272
- JSON.stringify({
273
- role: "user",
274
- agent: "default",
275
- model: { providerID: "openai", modelID: "gpt-4" },
276
- time: { created: 1700000000000 },
277
- }),
278
- )
279
- await Bun.write(
280
- path.join(storageDir, "part", "msg_test789ghi", "prt_testabc123.json"),
281
- JSON.stringify({
282
- type: "text",
283
- text: "Hello, world!",
284
- }),
285
- )
286
-
287
- const stats = await JsonMigration.run(sqlite)
288
-
289
- expect(stats?.messages).toBe(1)
290
- expect(stats?.parts).toBe(1)
291
-
292
- const db = drizzle({ client: sqlite })
293
- const messages = db.select().from(MessageTable).all()
294
- expect(messages.length).toBe(1)
295
- expect(messages[0].id).toBe("msg_test789ghi")
296
- expect(messages[0].session_id).toBe("ses_test456def")
297
- expect(messages[0].data).not.toHaveProperty("id")
298
- expect(messages[0].data).not.toHaveProperty("sessionID")
299
-
300
- const parts = db.select().from(PartTable).all()
301
- expect(parts.length).toBe(1)
302
- expect(parts[0].id).toBe("prt_testabc123")
303
- expect(parts[0].message_id).toBe("msg_test789ghi")
304
- expect(parts[0].session_id).toBe("ses_test456def")
305
- expect(parts[0].data).not.toHaveProperty("id")
306
- expect(parts[0].data).not.toHaveProperty("messageID")
307
- expect(parts[0].data).not.toHaveProperty("sessionID")
308
- })
309
-
310
- test("uses filename for message id when JSON has different value", async () => {
311
- await writeProject(storageDir, {
312
- id: "proj_test123abc",
313
- worktree: "/",
314
- time: { created: Date.now(), updated: Date.now() },
315
- sandboxes: [],
316
- })
317
- await writeSession(storageDir, "proj_test123abc", { ...fixtures.session })
318
- await Bun.write(
319
- path.join(storageDir, "message", "ses_test456def", "msg_from_filename.json"),
320
- JSON.stringify({
321
- id: "msg_different_in_json", // Stale! Should be ignored
322
- sessionID: "ses_test456def",
323
- role: "user",
324
- agent: "default",
325
- time: { created: 1700000000000 },
326
- }),
327
- )
328
-
329
- const stats = await JsonMigration.run(sqlite)
330
-
331
- expect(stats?.messages).toBe(1)
332
-
333
- const db = drizzle({ client: sqlite })
334
- const messages = db.select().from(MessageTable).all()
335
- expect(messages.length).toBe(1)
336
- expect(messages[0].id).toBe("msg_from_filename") // Uses filename, not JSON id
337
- expect(messages[0].session_id).toBe("ses_test456def")
338
- })
339
-
340
- test("uses paths for part id and messageID when JSON has different values", async () => {
341
- await writeProject(storageDir, {
342
- id: "proj_test123abc",
343
- worktree: "/",
344
- time: { created: Date.now(), updated: Date.now() },
345
- sandboxes: [],
346
- })
347
- await writeSession(storageDir, "proj_test123abc", { ...fixtures.session })
348
- await Bun.write(
349
- path.join(storageDir, "message", "ses_test456def", "msg_realmsgid.json"),
350
- JSON.stringify({
351
- role: "user",
352
- agent: "default",
353
- time: { created: 1700000000000 },
354
- }),
355
- )
356
- await Bun.write(
357
- path.join(storageDir, "part", "msg_realmsgid", "prt_from_filename.json"),
358
- JSON.stringify({
359
- id: "prt_different_in_json", // Stale! Should be ignored
360
- messageID: "msg_different_in_json", // Stale! Should be ignored
361
- sessionID: "ses_test456def",
362
- type: "text",
363
- text: "Hello",
364
- }),
365
- )
366
-
367
- const stats = await JsonMigration.run(sqlite)
368
-
369
- expect(stats?.parts).toBe(1)
370
-
371
- const db = drizzle({ client: sqlite })
372
- const parts = db.select().from(PartTable).all()
373
- expect(parts.length).toBe(1)
374
- expect(parts[0].id).toBe("prt_from_filename") // Uses filename, not JSON id
375
- expect(parts[0].message_id).toBe("msg_realmsgid") // Uses parent dir, not JSON messageID
376
- })
377
-
378
- test("skips orphaned sessions (no parent project)", async () => {
379
- await Bun.write(
380
- path.join(storageDir, "session", "proj_test123abc", "ses_orphan.json"),
381
- JSON.stringify({
382
- id: "ses_orphan",
383
- projectID: "proj_nonexistent",
384
- slug: "orphan",
385
- directory: "/",
386
- title: "Orphan",
387
- version: "1.0.0",
388
- time: { created: Date.now(), updated: Date.now() },
389
- }),
390
- )
391
-
392
- const stats = await JsonMigration.run(sqlite)
393
-
394
- expect(stats?.sessions).toBe(0)
395
- })
396
-
397
- test("uses directory path for projectID when JSON has stale value", async () => {
398
- // Simulates the scenario where earlier migration moved sessions to new
399
- // git-based project directories but didn't update the projectID field
400
- const gitBasedProjectID = "abc123gitcommit"
401
- await writeProject(storageDir, {
402
- id: gitBasedProjectID,
403
- worktree: "/test/path",
404
- vcs: "git",
405
- time: { created: Date.now(), updated: Date.now() },
406
- sandboxes: [],
407
- })
408
-
409
- // Session is in the git-based directory but JSON still has old projectID
410
- await writeSession(storageDir, gitBasedProjectID, {
411
- id: "ses_migrated",
412
- projectID: "old-project-name", // Stale! Should be ignored
413
- slug: "migrated-session",
414
- directory: "/test/path",
415
- title: "Migrated Session",
416
- version: "1.0.0",
417
- time: { created: 1700000000000, updated: 1700000001000 },
418
- })
419
-
420
- const stats = await JsonMigration.run(sqlite)
421
-
422
- expect(stats?.sessions).toBe(1)
423
-
424
- const db = drizzle({ client: sqlite })
425
- const sessions = db.select().from(SessionTable).all()
426
- expect(sessions.length).toBe(1)
427
- expect(sessions[0].id).toBe("ses_migrated")
428
- expect(sessions[0].project_id).toBe(gitBasedProjectID) // Uses directory, not stale JSON
429
- })
430
-
431
- test("uses filename for session id when JSON has different value", async () => {
432
- await writeProject(storageDir, {
433
- id: "proj_test123abc",
434
- worktree: "/test/path",
435
- time: { created: Date.now(), updated: Date.now() },
436
- sandboxes: [],
437
- })
438
-
439
- await Bun.write(
440
- path.join(storageDir, "session", "proj_test123abc", "ses_from_filename.json"),
441
- JSON.stringify({
442
- id: "ses_different_in_json", // Stale! Should be ignored
443
- projectID: "proj_test123abc",
444
- slug: "test-session",
445
- directory: "/test/path",
446
- title: "Test Session",
447
- version: "1.0.0",
448
- time: { created: 1700000000000, updated: 1700000001000 },
449
- }),
450
- )
451
-
452
- const stats = await JsonMigration.run(sqlite)
453
-
454
- expect(stats?.sessions).toBe(1)
455
-
456
- const db = drizzle({ client: sqlite })
457
- const sessions = db.select().from(SessionTable).all()
458
- expect(sessions.length).toBe(1)
459
- expect(sessions[0].id).toBe("ses_from_filename") // Uses filename, not JSON id
460
- expect(sessions[0].project_id).toBe("proj_test123abc")
461
- })
462
-
463
- test("is idempotent (running twice doesn't duplicate)", async () => {
464
- await writeProject(storageDir, {
465
- id: "proj_test123abc",
466
- worktree: "/",
467
- time: { created: Date.now(), updated: Date.now() },
468
- sandboxes: [],
469
- })
470
-
471
- await JsonMigration.run(sqlite)
472
- await JsonMigration.run(sqlite)
473
-
474
- const db = drizzle({ client: sqlite })
475
- const projects = db.select().from(ProjectTable).all()
476
- expect(projects.length).toBe(1) // Still only 1 due to onConflictDoNothing
477
- })
478
-
479
- test("migrates todos", async () => {
480
- await writeProject(storageDir, {
481
- id: "proj_test123abc",
482
- worktree: "/",
483
- time: { created: Date.now(), updated: Date.now() },
484
- sandboxes: [],
485
- })
486
- await writeSession(storageDir, "proj_test123abc", { ...fixtures.session })
487
-
488
- // Create todo file (named by sessionID, contains array of todos)
489
- await Bun.write(
490
- path.join(storageDir, "todo", "ses_test456def.json"),
491
- JSON.stringify([
492
- {
493
- id: "todo_1",
494
- content: "First todo",
495
- status: "pending",
496
- priority: "high",
497
- },
498
- {
499
- id: "todo_2",
500
- content: "Second todo",
501
- status: "completed",
502
- priority: "medium",
503
- },
504
- ]),
505
- )
506
-
507
- const stats = await JsonMigration.run(sqlite)
508
-
509
- expect(stats?.todos).toBe(2)
510
-
511
- const db = drizzle({ client: sqlite })
512
- const todos = db.select().from(TodoTable).orderBy(TodoTable.position).all()
513
- expect(todos.length).toBe(2)
514
- expect(todos[0].content).toBe("First todo")
515
- expect(todos[0].status).toBe("pending")
516
- expect(todos[0].priority).toBe("high")
517
- expect(todos[0].position).toBe(0)
518
- expect(todos[1].content).toBe("Second todo")
519
- expect(todos[1].position).toBe(1)
520
- })
521
-
522
- test("todos are ordered by position", async () => {
523
- await writeProject(storageDir, {
524
- id: "proj_test123abc",
525
- worktree: "/",
526
- time: { created: Date.now(), updated: Date.now() },
527
- sandboxes: [],
528
- })
529
- await writeSession(storageDir, "proj_test123abc", { ...fixtures.session })
530
-
531
- await Bun.write(
532
- path.join(storageDir, "todo", "ses_test456def.json"),
533
- JSON.stringify([
534
- { content: "Third", status: "pending", priority: "low" },
535
- { content: "First", status: "pending", priority: "high" },
536
- { content: "Second", status: "in_progress", priority: "medium" },
537
- ]),
538
- )
539
-
540
- await JsonMigration.run(sqlite)
541
-
542
- const db = drizzle({ client: sqlite })
543
- const todos = db.select().from(TodoTable).orderBy(TodoTable.position).all()
544
-
545
- expect(todos.length).toBe(3)
546
- expect(todos[0].content).toBe("Third")
547
- expect(todos[0].position).toBe(0)
548
- expect(todos[1].content).toBe("First")
549
- expect(todos[1].position).toBe(1)
550
- expect(todos[2].content).toBe("Second")
551
- expect(todos[2].position).toBe(2)
552
- })
553
-
554
- test("migrates permissions", async () => {
555
- await writeProject(storageDir, {
556
- id: "proj_test123abc",
557
- worktree: "/",
558
- time: { created: Date.now(), updated: Date.now() },
559
- sandboxes: [],
560
- })
561
-
562
- // Create permission file (named by projectID, contains array of rules)
563
- const permissionData = [
564
- { permission: "file.read", pattern: "/test/file1.ts", action: "allow" as const },
565
- { permission: "file.write", pattern: "/test/file2.ts", action: "ask" as const },
566
- { permission: "command.run", pattern: "npm install", action: "deny" as const },
567
- ]
568
- await Bun.write(path.join(storageDir, "permission", "proj_test123abc.json"), JSON.stringify(permissionData))
569
-
570
- const stats = await JsonMigration.run(sqlite)
571
-
572
- expect(stats?.permissions).toBe(1)
573
-
574
- const db = drizzle({ client: sqlite })
575
- const permissions = db.select().from(PermissionTable).all()
576
- expect(permissions.length).toBe(1)
577
- expect(permissions[0].project_id).toBe("proj_test123abc")
578
- expect(permissions[0].data).toEqual(permissionData)
579
- })
580
-
581
- test("migrates session shares", async () => {
582
- await writeProject(storageDir, {
583
- id: "proj_test123abc",
584
- worktree: "/",
585
- time: { created: Date.now(), updated: Date.now() },
586
- sandboxes: [],
587
- })
588
- await writeSession(storageDir, "proj_test123abc", { ...fixtures.session })
589
-
590
- // Create session share file (named by sessionID)
591
- await Bun.write(
592
- path.join(storageDir, "session_share", "ses_test456def.json"),
593
- JSON.stringify({
594
- id: "share_123",
595
- secret: "supersecretkey",
596
- url: "https://share.example.com/ses_test456def",
597
- }),
598
- )
599
-
600
- const stats = await JsonMigration.run(sqlite)
601
-
602
- expect(stats?.shares).toBe(1)
603
-
604
- const db = drizzle({ client: sqlite })
605
- const shares = db.select().from(SessionShareTable).all()
606
- expect(shares.length).toBe(1)
607
- expect(shares[0].session_id).toBe("ses_test456def")
608
- expect(shares[0].id).toBe("share_123")
609
- expect(shares[0].secret).toBe("supersecretkey")
610
- expect(shares[0].url).toBe("https://share.example.com/ses_test456def")
611
- })
612
-
613
- test("returns empty stats when storage directory does not exist", async () => {
614
- await fs.rm(storageDir, { recursive: true, force: true })
615
-
616
- const stats = await JsonMigration.run(sqlite)
617
-
618
- expect(stats.projects).toBe(0)
619
- expect(stats.sessions).toBe(0)
620
- expect(stats.messages).toBe(0)
621
- expect(stats.parts).toBe(0)
622
- expect(stats.todos).toBe(0)
623
- expect(stats.permissions).toBe(0)
624
- expect(stats.shares).toBe(0)
625
- expect(stats.errors).toEqual([])
626
- })
627
-
628
- test("continues when a JSON file is unreadable and records an error", async () => {
629
- await writeProject(storageDir, {
630
- id: "proj_test123abc",
631
- worktree: "/",
632
- time: { created: Date.now(), updated: Date.now() },
633
- sandboxes: [],
634
- })
635
- await Bun.write(path.join(storageDir, "project", "broken.json"), "{ invalid json")
636
-
637
- const stats = await JsonMigration.run(sqlite)
638
-
639
- expect(stats.projects).toBe(1)
640
- expect(stats.errors.some((x) => x.includes("failed to read") && x.includes("broken.json"))).toBe(true)
641
-
642
- const db = drizzle({ client: sqlite })
643
- const projects = db.select().from(ProjectTable).all()
644
- expect(projects.length).toBe(1)
645
- expect(projects[0].id).toBe("proj_test123abc")
646
- })
647
-
648
- test("skips invalid todo entries while preserving source positions", async () => {
649
- await writeProject(storageDir, {
650
- id: "proj_test123abc",
651
- worktree: "/",
652
- time: { created: Date.now(), updated: Date.now() },
653
- sandboxes: [],
654
- })
655
- await writeSession(storageDir, "proj_test123abc", { ...fixtures.session })
656
-
657
- await Bun.write(
658
- path.join(storageDir, "todo", "ses_test456def.json"),
659
- JSON.stringify([
660
- { content: "keep-0", status: "pending", priority: "high" },
661
- { content: "drop-1", priority: "low" },
662
- { content: "keep-2", status: "completed", priority: "medium" },
663
- ]),
664
- )
665
-
666
- const stats = await JsonMigration.run(sqlite)
667
- expect(stats.todos).toBe(2)
668
-
669
- const db = drizzle({ client: sqlite })
670
- const todos = db.select().from(TodoTable).orderBy(TodoTable.position).all()
671
- expect(todos.length).toBe(2)
672
- expect(todos[0].content).toBe("keep-0")
673
- expect(todos[0].position).toBe(0)
674
- expect(todos[1].content).toBe("keep-2")
675
- expect(todos[1].position).toBe(2)
676
- })
677
-
678
- test("skips orphaned todos, permissions, and shares", async () => {
679
- await writeProject(storageDir, {
680
- id: "proj_test123abc",
681
- worktree: "/",
682
- time: { created: Date.now(), updated: Date.now() },
683
- sandboxes: [],
684
- })
685
- await writeSession(storageDir, "proj_test123abc", { ...fixtures.session })
686
-
687
- await Bun.write(
688
- path.join(storageDir, "todo", "ses_test456def.json"),
689
- JSON.stringify([{ content: "valid", status: "pending", priority: "high" }]),
690
- )
691
- await Bun.write(
692
- path.join(storageDir, "todo", "ses_missing.json"),
693
- JSON.stringify([{ content: "orphan", status: "pending", priority: "high" }]),
694
- )
695
-
696
- await Bun.write(
697
- path.join(storageDir, "permission", "proj_test123abc.json"),
698
- JSON.stringify([{ permission: "file.read" }]),
699
- )
700
- await Bun.write(
701
- path.join(storageDir, "permission", "proj_missing.json"),
702
- JSON.stringify([{ permission: "file.write" }]),
703
- )
704
-
705
- await Bun.write(
706
- path.join(storageDir, "session_share", "ses_test456def.json"),
707
- JSON.stringify({ id: "share_ok", secret: "secret", url: "https://ok.example.com" }),
708
- )
709
- await Bun.write(
710
- path.join(storageDir, "session_share", "ses_missing.json"),
711
- JSON.stringify({ id: "share_missing", secret: "secret", url: "https://missing.example.com" }),
712
- )
713
-
714
- const stats = await JsonMigration.run(sqlite)
715
-
716
- expect(stats.todos).toBe(1)
717
- expect(stats.permissions).toBe(1)
718
- expect(stats.shares).toBe(1)
719
-
720
- const db = drizzle({ client: sqlite })
721
- expect(db.select().from(TodoTable).all().length).toBe(1)
722
- expect(db.select().from(PermissionTable).all().length).toBe(1)
723
- expect(db.select().from(SessionShareTable).all().length).toBe(1)
724
- })
725
-
726
- test("handles mixed corruption and partial validity in one migration run", async () => {
727
- await writeProject(storageDir, {
728
- id: "proj_test123abc",
729
- worktree: "/ok",
730
- time: { created: 1700000000000, updated: 1700000001000 },
731
- sandboxes: [],
732
- })
733
- await Bun.write(
734
- path.join(storageDir, "project", "proj_missing_id.json"),
735
- JSON.stringify({ worktree: "/bad", sandboxes: [] }),
736
- )
737
- await Bun.write(path.join(storageDir, "project", "proj_broken.json"), "{ nope")
738
-
739
- await writeSession(storageDir, "proj_test123abc", {
740
- id: "ses_test456def",
741
- projectID: "proj_test123abc",
742
- slug: "ok",
743
- directory: "/ok",
744
- title: "Ok",
745
- version: "1",
746
- time: { created: 1700000000000, updated: 1700000001000 },
747
- })
748
- await Bun.write(
749
- path.join(storageDir, "session", "proj_test123abc", "ses_missing_project.json"),
750
- JSON.stringify({
751
- id: "ses_missing_project",
752
- slug: "bad",
753
- directory: "/bad",
754
- title: "Bad",
755
- version: "1",
756
- }),
757
- )
758
- await Bun.write(
759
- path.join(storageDir, "session", "proj_test123abc", "ses_orphan.json"),
760
- JSON.stringify({
761
- id: "ses_orphan",
762
- projectID: "proj_missing",
763
- slug: "orphan",
764
- directory: "/bad",
765
- title: "Orphan",
766
- version: "1",
767
- }),
768
- )
769
-
770
- await Bun.write(
771
- path.join(storageDir, "message", "ses_test456def", "msg_ok.json"),
772
- JSON.stringify({ role: "user", time: { created: 1700000000000 } }),
773
- )
774
- await Bun.write(path.join(storageDir, "message", "ses_test456def", "msg_broken.json"), "{ nope")
775
- await Bun.write(
776
- path.join(storageDir, "message", "ses_missing", "msg_orphan.json"),
777
- JSON.stringify({ role: "user", time: { created: 1700000000000 } }),
778
- )
779
-
780
- await Bun.write(
781
- path.join(storageDir, "part", "msg_ok", "part_ok.json"),
782
- JSON.stringify({ type: "text", text: "ok" }),
783
- )
784
- await Bun.write(
785
- path.join(storageDir, "part", "msg_missing", "part_missing_message.json"),
786
- JSON.stringify({ type: "text", text: "bad" }),
787
- )
788
- await Bun.write(path.join(storageDir, "part", "msg_ok", "part_broken.json"), "{ nope")
789
-
790
- await Bun.write(
791
- path.join(storageDir, "todo", "ses_test456def.json"),
792
- JSON.stringify([
793
- { content: "ok", status: "pending", priority: "high" },
794
- { content: "skip", status: "pending" },
795
- ]),
796
- )
797
- await Bun.write(
798
- path.join(storageDir, "todo", "ses_missing.json"),
799
- JSON.stringify([{ content: "orphan", status: "pending", priority: "high" }]),
800
- )
801
- await Bun.write(path.join(storageDir, "todo", "ses_broken.json"), "{ nope")
802
-
803
- await Bun.write(
804
- path.join(storageDir, "permission", "proj_test123abc.json"),
805
- JSON.stringify([{ permission: "file.read" }]),
806
- )
807
- await Bun.write(
808
- path.join(storageDir, "permission", "proj_missing.json"),
809
- JSON.stringify([{ permission: "file.write" }]),
810
- )
811
- await Bun.write(path.join(storageDir, "permission", "proj_broken.json"), "{ nope")
812
-
813
- await Bun.write(
814
- path.join(storageDir, "session_share", "ses_test456def.json"),
815
- JSON.stringify({ id: "share_ok", secret: "secret", url: "https://ok.example.com" }),
816
- )
817
- await Bun.write(
818
- path.join(storageDir, "session_share", "ses_missing.json"),
819
- JSON.stringify({ id: "share_orphan", secret: "secret", url: "https://missing.example.com" }),
820
- )
821
- await Bun.write(path.join(storageDir, "session_share", "ses_broken.json"), "{ nope")
822
-
823
- const stats = await JsonMigration.run(sqlite)
824
-
825
- // Projects: proj_test123abc (valid), proj_missing_id (now derives id from filename)
826
- // Sessions: ses_test456def (valid), ses_missing_project (now uses dir path),
827
- // ses_orphan (now uses dir path, ignores stale projectID)
828
- expect(stats.projects).toBe(2)
829
- expect(stats.sessions).toBe(3)
830
- expect(stats.messages).toBe(1)
831
- expect(stats.parts).toBe(1)
832
- expect(stats.todos).toBe(1)
833
- expect(stats.permissions).toBe(1)
834
- expect(stats.shares).toBe(1)
835
- expect(stats.errors.length).toBeGreaterThanOrEqual(6)
836
-
837
- const db = drizzle({ client: sqlite })
838
- expect(db.select().from(ProjectTable).all().length).toBe(2)
839
- expect(db.select().from(SessionTable).all().length).toBe(3)
840
- expect(db.select().from(MessageTable).all().length).toBe(1)
841
- expect(db.select().from(PartTable).all().length).toBe(1)
842
- expect(db.select().from(TodoTable).all().length).toBe(1)
843
- expect(db.select().from(PermissionTable).all().length).toBe(1)
844
- expect(db.select().from(SessionShareTable).all().length).toBe(1)
845
- })
846
- })