opencode-extended-sidebar 0.2.90 → 0.2.91

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 (108) hide show
  1. package/.oesignore +17 -17
  2. package/CHANGELOG.md +96 -95
  3. package/LICENSE +21 -21
  4. package/README.md +150 -235
  5. package/oes.json +13 -11
  6. package/package.json +100 -100
  7. package/scripts/install-git-hooks.mjs +29 -29
  8. package/src/pware.oc.core/constants/index.ts +18 -18
  9. package/src/pware.oc.core/constants/pware.oc.core.constants.eventKind.ts +29 -29
  10. package/src/pware.oc.core/constants/pware.oc.core.constants.eventName.ts +15 -13
  11. package/src/pware.oc.core/constants/pware.oc.core.constants.eventType.ts +241 -241
  12. package/src/pware.oc.core/constants/pware.oc.core.constants.myWork.ts +55 -55
  13. package/src/pware.oc.core/constants/pware.oc.core.constants.partType.ts +65 -65
  14. package/src/pware.oc.core/constants/pware.oc.core.constants.phase.ts +58 -58
  15. package/src/pware.oc.core/constants/pware.oc.core.constants.pulse.ts +63 -63
  16. package/src/pware.oc.core/constants/pware.oc.core.constants.rowKind.ts +34 -34
  17. package/src/pware.oc.core/constants/pware.oc.core.constants.status.ts +74 -74
  18. package/src/pware.oc.core/constants/pware.oc.core.constants.toolName.ts +69 -69
  19. package/src/pware.oc.core/git/index.ts +7 -7
  20. package/src/pware.oc.core/git/pware.oc.core.git.ts +237 -237
  21. package/src/pware.oc.core/git/pware.oc.core.gitignore.ts +87 -87
  22. package/src/pware.oc.core/index.ts +19 -18
  23. package/src/pware.oc.core/pware.oc.core.bus.ts +42 -42
  24. package/src/pware.oc.core/pware.oc.core.cache.ts +48 -48
  25. package/src/pware.oc.core/pware.oc.core.clipboard.ts +97 -97
  26. package/src/pware.oc.core/pware.oc.core.debug.ts +280 -280
  27. package/src/pware.oc.core/pware.oc.core.events.ts +79 -79
  28. package/src/pware.oc.core/pware.oc.core.glyph.ts +135 -135
  29. package/src/pware.oc.core/pware.oc.core.layout.ts +234 -234
  30. package/src/pware.oc.core/pware.oc.core.oes.ts +99 -89
  31. package/src/pware.oc.core/pware.oc.core.paths.ts +240 -240
  32. package/src/pware.oc.core/pware.oc.core.preview.ts +74 -74
  33. package/src/pware.oc.core/pware.oc.core.pulse.ts +726 -726
  34. package/src/pware.oc.core/pware.oc.core.runtimeConfig.ts +41 -0
  35. package/src/pware.oc.core/pware.oc.core.sqlite.ts +164 -175
  36. package/src/pware.oc.core/pware.oc.core.sqliteGateway.ts +89 -0
  37. package/src/pware.oc.core/pware.oc.core.status.ts +214 -214
  38. package/src/pware.oc.core/pware.oc.core.timing.ts +63 -63
  39. package/src/pware.oc.core/pware.oc.core.width.ts +215 -215
  40. package/src/pware.oc.omo/constants/index.ts +15 -15
  41. package/src/pware.oc.omo/constants/pware.oc.omo.constants.backgroundTask.ts +18 -18
  42. package/src/pware.oc.omo/constants/pware.oc.omo.constants.boulderStatus.ts +49 -49
  43. package/src/pware.oc.omo/constants/pware.oc.omo.constants.docKind.ts +29 -29
  44. package/src/pware.oc.omo/constants/pware.oc.omo.constants.eventName.ts +11 -11
  45. package/src/pware.oc.omo/constants/pware.oc.omo.constants.planStatus.ts +60 -60
  46. package/src/pware.oc.omo/constants/pware.oc.omo.constants.reviewStatus.ts +49 -49
  47. package/src/pware.oc.omo/constants/pware.oc.omo.constants.startWork.ts +25 -25
  48. package/src/pware.oc.omo/constants/pware.oc.omo.constants.verdict.ts +38 -38
  49. package/src/pware.oc.omo/index.ts +7 -7
  50. package/src/pware.oc.omo/resolver/index.ts +19 -19
  51. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.approval.ts +179 -179
  52. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.approvalGroup.ts +116 -116
  53. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.approvalState.ts +34 -34
  54. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.boulder.ts +503 -503
  55. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.config.ts +40 -40
  56. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.doc.ts +269 -269
  57. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.draftFile.ts +18 -18
  58. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.notepadsFile.ts +18 -18
  59. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.plan.ts +155 -155
  60. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.planFile.ts +363 -361
  61. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.proofFile.ts +18 -18
  62. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.rulesFile.ts +11 -11
  63. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.runContinuationFile.ts +14 -14
  64. package/src/pware.oc.opencode/constants/index.ts +10 -10
  65. package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.eventName.ts +15 -15
  66. package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.fileTouch.ts +18 -18
  67. package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.questionKind.ts +45 -45
  68. package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.sessionStatus.ts +58 -58
  69. package/src/pware.oc.opencode/index.ts +8 -8
  70. package/src/pware.oc.opencode/pware.oc.opencode.events.ts +182 -182
  71. package/src/pware.oc.opencode/pware.oc.opencode.files.ts +399 -399
  72. package/src/pware.oc.opencode/resolver/index.ts +223 -170
  73. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.file.ts +150 -162
  74. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.question.ts +149 -185
  75. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.session.ts +248 -211
  76. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.todo.ts +22 -26
  77. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.tool.ts +224 -236
  78. package/src/pware.oc.perf/index.ts +14 -14
  79. package/src/pware.oc.perf/pware.oc.perf.asciichart.d.ts +15 -15
  80. package/src/pware.oc.perf/pware.oc.perf.charts.ts +284 -284
  81. package/src/pware.oc.perf/pware.oc.perf.reader.ts +962 -927
  82. package/src/pware.oc.perf/pware.oc.perf.realtime.ts +88 -88
  83. package/src/pware.oc.perf/pware.oc.perf.realtimeBlock.ts +118 -118
  84. package/src/pware.oc.perf/pware.oc.perf.realtimeCpuRam.ts +79 -79
  85. package/src/pware.oc.perf/pware.oc.perf.realtimeSampler.ts +71 -71
  86. package/src/pware.oc.perf/pware.oc.perf.realtimeTimeline.ts +214 -214
  87. package/src/pware.oc.perf/pware.oc.perf.self.ts +179 -179
  88. package/src/pware.oc.perf/pware.oc.perf.view.tsx +463 -462
  89. package/src/pware.oc.runtime/index.ts +13 -13
  90. package/src/pware.oc.runtime/pware.oc.runtime.monitor.ts +142 -142
  91. package/src/pware.oc.runtime/pware.oc.runtime.mywork-enrich.ts +87 -79
  92. package/src/pware.oc.runtime/pware.oc.runtime.mywork.ts +282 -253
  93. package/src/pware.oc.runtime/pware.oc.runtime.omoRead.ts +37 -0
  94. package/src/pware.oc.runtime/pware.oc.runtime.questions.ts +83 -95
  95. package/src/pware.oc.runtime/pware.oc.runtime.snapshotClient.ts +130 -129
  96. package/src/pware.oc.runtime/pware.oc.runtime.source.ts +105 -105
  97. package/src/pware.oc.runtime/pware.oc.runtime.worker.ts +44 -43
  98. package/src/pware.oc.runtime/resolver/index.ts +268 -224
  99. package/src/pware.oc.runtime/resolver/pware.oc.runtime.resolver.delegate.ts +146 -146
  100. package/src/pware.oc.ui/index.ts +12 -12
  101. package/src/pware.oc.ui/pware.oc.ui.chrome.tsx +381 -339
  102. package/src/pware.oc.ui/pware.oc.ui.glyphs.tsx +144 -144
  103. package/src/pware.oc.ui/pware.oc.ui.host.tsx +111 -111
  104. package/src/pware.oc.ui/pware.oc.ui.live.tsx +82 -82
  105. package/src/pware.oc.ui/pware.oc.ui.menudialogs.tsx +843 -843
  106. package/src/pware.oc.ui/pware.oc.ui.sections.tsx +552 -526
  107. package/src/pware.oc.ui/pware.oc.ui.sidebar.tsx +1718 -1629
  108. package/src/pware.oc.ui.tsx +98 -98
@@ -1,170 +1,223 @@
1
- /**
2
- * pware.oc.core.opencode.resolver
3
- *
4
- * Aggregate of the opencode SQLite resolvers: readDbSnapshot composes the
5
- * session graph + tools + files for the panel; readProjectFeed rolls the
6
- * Sessions-tab feed across a set of sessions. Re-exports the entity resolvers.
7
- */
8
- import fs from "node:fs"
9
- import type { FileFilter, FileView } from "../pware.oc.opencode.files.js"
10
- import { profile } from "../../pware.oc.core/pware.oc.core.debug.js"
11
- import { getOes } from "../../pware.oc.core/pware.oc.core.oes.js"
12
- import { openReadonlyDb, withDbRead } from "../../pware.oc.core/pware.oc.core.sqlite.js"
13
- import {
14
- getSessionById,
15
- getSessionsByIds,
16
- listChildSessions,
17
- listRecentMainSessions,
18
- toSessionView,
19
- type SessionView,
20
- } from "./pware.oc.opencode.resolver.session.js"
21
- import { listRecentToolEvents, listToolEvents, type ToolView } from "./pware.oc.opencode.resolver.tool.js"
22
- import { listSessionFiles, listRecentSessionFiles } from "./pware.oc.opencode.resolver.file.js"
23
- import type { TodoRow } from "./pware.oc.opencode.resolver.todo.js"
24
-
25
- export * from "./pware.oc.opencode.resolver.session.js"
26
- export * from "./pware.oc.opencode.resolver.todo.js"
27
- export * from "./pware.oc.opencode.resolver.tool.js"
28
- export * from "./pware.oc.opencode.resolver.file.js"
29
- export * from "./pware.oc.opencode.resolver.question.js"
30
-
31
- export type DbSnapshot = {
32
- present: boolean
33
- dbPath: string
34
- /** Project of the current session — scopes project-wide reads (questions). */
35
- projectId: string | null
36
- current: SessionView | null
37
- /** Orchestrator: parent if current is a child, otherwise current. */
38
- main: SessionView | null
39
- parent: SessionView | null
40
- children: SessionView[]
41
- siblings: SessionView[]
42
- /** Sessions keyed by id — current, main, and any looked-up delegates. */
43
- byId: Record<string, SessionView>
44
- /** Recent main (parent_id null) sessions in this project — the `sessionFetch` window. */
45
- recent: SessionView[]
46
- todos: TodoRow[]
47
- /** Current session tool parts — name + status only, no args/outputs. */
48
- tools: ToolView[]
49
- /** Basenames + optional +/- from edit/write parts. No paths, no bodies. */
50
- files: FileView[]
51
- error: string | null
52
- }
53
-
54
- export function emptyDb(dbPath: string, error: string | null = null): DbSnapshot {
55
- return {
56
- present: false,
57
- dbPath,
58
- projectId: null,
59
- current: null,
60
- main: null,
61
- parent: null,
62
- children: [],
63
- siblings: [],
64
- byId: {},
65
- recent: [],
66
- todos: [],
67
- tools: [],
68
- files: [],
69
- error,
70
- }
71
- }
72
-
73
- export function readDbSnapshot(opts: {
74
- dbPath: string
75
- sessionId: string
76
- extraIds?: string[]
77
- projectRoot?: string | null
78
- }): DbSnapshot {
79
- if (!opts.dbPath || !fs.existsSync(opts.dbPath)) {
80
- return emptyDb(opts.dbPath, "db missing")
81
- }
82
-
83
- const run = (): DbSnapshot => {
84
- const db = openReadonlyDb(opts.dbPath)
85
- if (!db) return emptyDb(opts.dbPath, "sqlite unavailable")
86
-
87
- const now = Date.now()
88
- const row = getSessionById(db, opts.sessionId)
89
- if (!row) {
90
- return { ...emptyDb(opts.dbPath, "session not in db yet"), present: true }
91
- }
92
- const current = toSessionView(row, now)
93
- let parent: SessionView | null = null
94
- const children = listChildSessions(db, row.id).map((r) => toSessionView(r, now))
95
- if (row.parent_id) {
96
- const p = getSessionById(db, row.parent_id)
97
- if (p) parent = toSessionView(p, now)
98
- }
99
-
100
- const main = parent ?? current
101
- const extra = getSessionsByIds(db, opts.extraIds ?? []).map((r) =>
102
- toSessionView(r, now),
103
- )
104
- const byId: Record<string, SessionView> = {}
105
- const oes = getOes(opts.projectRoot)
106
- const recent = listRecentMainSessions(db, {
107
- projectId: row.project_id,
108
- limit: oes.sessionFetch,
109
- }).map((r) => toSessionView(r, now))
110
- for (const v of [current, parent, main, ...children, ...extra, ...recent]) {
111
- if (v) byId[v.id] = v
112
- }
113
-
114
- return {
115
- present: true,
116
- dbPath: opts.dbPath,
117
- projectId: row.project_id,
118
- current,
119
- main,
120
- parent,
121
- children,
122
- siblings: [],
123
- byId,
124
- recent,
125
- todos: [],
126
- tools: listToolEvents(db, row.id, oes.toolFetch),
127
- files: listSessionFiles(db, row.id, {
128
- skipGitignore: oes.skipGitignore,
129
- projectRoot: opts.projectRoot,
130
- }),
131
- error: null,
132
- }
133
- }
134
-
135
- return profile("db.snapshot", () =>
136
- withDbRead(run, (e) =>
137
- emptyDb(opts.dbPath, e instanceof Error ? e.message : "db read failed"),
138
- ),
139
- )
140
- }
141
-
142
- export type ProjectFeed = {
143
- tools: ToolView[]
144
- files: FileView[]
145
- }
146
-
147
- export function emptyProjectFeed(): ProjectFeed {
148
- return { tools: [], files: [] }
149
- }
150
-
151
- /** Lazy read callers gate on the Sessions tab so the queries never run elsewhere. */
152
- export function readProjectFeed(opts: {
153
- dbPath: string
154
- sessionIds: string[]
155
- toolLimit: number
156
- filter?: FileFilter
157
- }): ProjectFeed {
158
- const empty = emptyProjectFeed()
159
- if (!opts.dbPath || opts.sessionIds.length === 0 || !fs.existsSync(opts.dbPath)) return empty
160
- return profile("db.feed", () =>
161
- withDbRead(() => {
162
- const db = openReadonlyDb(opts.dbPath)
163
- if (!db) return empty
164
- return {
165
- tools: listRecentToolEvents(db, opts.sessionIds, opts.toolLimit),
166
- files: listRecentSessionFiles(db, opts.sessionIds, opts.filter),
167
- }
168
- }, () => empty),
169
- )
170
- }
1
+ /**
2
+ * pware.oc.core.opencode.resolver
3
+ *
4
+ * Aggregate of the opencode SQLite resolvers: readDbSnapshot composes the
5
+ * session graph + tools + files for the panel; readProjectFeed rolls the
6
+ * Sessions-tab feed across a set of sessions. Re-exports the entity resolvers.
7
+ */
8
+ import type { FileFilter, FileView } from "../pware.oc.opencode.files.js"
9
+ import { getOes } from "../../pware.oc.core/pware.oc.core.oes.js"
10
+ import { profileAsync } from "../../pware.oc.core/pware.oc.core.debug.js"
11
+ import { readonlyReadGateway } from "../../pware.oc.core/pware.oc.core.sqliteGateway.js"
12
+ import type { SqlDb } from "../../pware.oc.core/pware.oc.core.sqlite.js"
13
+ import {
14
+ getSessionById,
15
+ getSessionsByIds,
16
+ listChildSessions,
17
+ listRecentMainSessions,
18
+ HOUR_MS,
19
+ sessionAgeTier,
20
+ toSessionView,
21
+ type SessionView,
22
+ } from "./pware.oc.opencode.resolver.session.js"
23
+ import { SESSION_STATUS_RUNNING } from "../constants/pware.oc.opencode.constants.sessionStatus.js"
24
+ import { listRecentToolEvents, listToolEvents, type ToolView } from "./pware.oc.opencode.resolver.tool.js"
25
+ import { listSessionFiles, listRecentSessionFiles } from "./pware.oc.opencode.resolver.file.js"
26
+
27
+ export * from "./pware.oc.opencode.resolver.session.js"
28
+ export * from "./pware.oc.opencode.resolver.todo.js"
29
+ export * from "./pware.oc.opencode.resolver.tool.js"
30
+ export * from "./pware.oc.opencode.resolver.file.js"
31
+ export * from "./pware.oc.opencode.resolver.question.js"
32
+
33
+ export type DbSnapshot = {
34
+ present: boolean
35
+ dbPath: string
36
+ /** Project of the current session scopes project-wide reads (questions). */
37
+ projectId: string | null
38
+ current: SessionView | null
39
+ /** Orchestrator: parent if current is a child, otherwise current. */
40
+ main: SessionView | null
41
+ parent: SessionView | null
42
+ children: SessionView[]
43
+ /** Sessions keyed by id — current, main, and any looked-up delegates. */
44
+ byId: Record<string, SessionView>
45
+ /** Recent main (parent_id null) sessions in this project — the `sessionFetch` window. */
46
+ recent: SessionView[]
47
+ /** Current session tool parts — name + status only, no args/outputs. */
48
+ tools: ToolView[]
49
+ /** Basenames + optional +/- from edit/write parts. No paths, no bodies. */
50
+ files: FileView[]
51
+ error: string | null
52
+ }
53
+
54
+ export function emptyDb(dbPath: string, error: string | null = null): DbSnapshot {
55
+ return {
56
+ present: false,
57
+ dbPath,
58
+ projectId: null,
59
+ current: null,
60
+ main: null,
61
+ parent: null,
62
+ children: [],
63
+ byId: {},
64
+ recent: [],
65
+ tools: [],
66
+ files: [],
67
+ error,
68
+ }
69
+ }
70
+
71
+ export type DbSnapshotReadOptions = {
72
+ readonly dbPath: string
73
+ readonly sessionId: string
74
+ readonly extraIds?: readonly string[]
75
+ readonly projectRoot?: string | null
76
+ }
77
+
78
+ export type DbReadPlan<T> = {
79
+ readonly initial: () => T
80
+ readonly stages: readonly ((db: SqlDb, state: T) => T)[]
81
+ }
82
+
83
+ export function createDbSnapshotRead(opts: DbSnapshotReadOptions): DbReadPlan<DbSnapshot> {
84
+ const now = Date.now()
85
+ const oes = getOes(opts.projectRoot)
86
+ const loadCurrent = (db: SqlDb, state: DbSnapshot): DbSnapshot => {
87
+ const row = getSessionById(db, opts.sessionId)
88
+ if (!row) {
89
+ return { ...emptyDb(opts.dbPath, "session not in db yet"), present: true }
90
+ }
91
+ const current = toSessionView(row, now)
92
+ return {
93
+ ...state,
94
+ present: true,
95
+ projectId: row.project_id,
96
+ current,
97
+ main: current,
98
+ byId: { [current.id]: current },
99
+ error: null,
100
+ }
101
+ }
102
+
103
+ const loadGraph = (db: SqlDb, state: DbSnapshot): DbSnapshot => {
104
+ const current = state.current
105
+ const projectId = state.projectId
106
+ if (!current || !projectId) return state
107
+ let parent: SessionView | null = null
108
+ const children = listChildSessions(db, current.id).map((r) => toSessionView(r, now))
109
+ if (current.parentId) {
110
+ const p = getSessionById(db, current.parentId)
111
+ if (p) parent = toSessionView(p, now)
112
+ }
113
+ const main = parent ?? current
114
+ const extra = getSessionsByIds(db, [...(opts.extraIds ?? [])]).map((r) =>
115
+ toSessionView(r, now),
116
+ )
117
+ const visibleMs = oes.sessionVisibleHours * HOUR_MS
118
+ const dimMs = oes.sessionDimHours * HOUR_MS
119
+ const recent = listRecentMainSessions(db, {
120
+ projectId,
121
+ limit: oes.sessionFetch,
122
+ })
123
+ .map((r) => toSessionView(r, now))
124
+ .filter((v) => {
125
+ const keep =
126
+ v.id === current.id || v.id === main.id || v.status === SESSION_STATUS_RUNNING
127
+ return sessionAgeTier(v.ageMs, dimMs, visibleMs, keep) !== "hidden"
128
+ })
129
+ const byId: Record<string, SessionView> = {}
130
+ for (const v of [current, parent, main, ...children, ...extra, ...recent]) {
131
+ if (v) byId[v.id] = v
132
+ }
133
+ return {
134
+ ...state,
135
+ main,
136
+ parent,
137
+ children,
138
+ byId,
139
+ recent,
140
+ }
141
+ }
142
+
143
+ const loadTools = (db: SqlDb, state: DbSnapshot): DbSnapshot => {
144
+ if (!state.current) return state
145
+ return {
146
+ ...state,
147
+ tools: listToolEvents(db, state.current.id, oes.toolFetch),
148
+ }
149
+ }
150
+
151
+ const loadFiles = (db: SqlDb, state: DbSnapshot): DbSnapshot => {
152
+ if (!state.current) return state
153
+ return {
154
+ ...state,
155
+ files: listSessionFiles(db, state.current.id, {
156
+ skipGitignore: oes.skipGitignore,
157
+ projectRoot: opts.projectRoot,
158
+ }),
159
+ }
160
+ }
161
+
162
+ return {
163
+ initial: () => emptyDb(opts.dbPath),
164
+ stages: [loadCurrent, loadGraph, loadTools, loadFiles],
165
+ }
166
+ }
167
+
168
+ export function readDbSnapshot(db: SqlDb, opts: DbSnapshotReadOptions): DbSnapshot {
169
+ const plan = createDbSnapshotRead(opts)
170
+ return plan.stages.reduce((state, stage) => stage(db, state), plan.initial())
171
+ }
172
+
173
+ export type ProjectFeed = {
174
+ tools: ToolView[]
175
+ files: FileView[]
176
+ }
177
+
178
+ export function emptyProjectFeed(): ProjectFeed {
179
+ return { tools: [], files: [] }
180
+ }
181
+
182
+ /** Lazy read — callers gate on the Sessions tab so the queries never run elsewhere. */
183
+ export type ProjectFeedReadOptions = {
184
+ readonly dbPath: string
185
+ readonly sessionIds: readonly string[]
186
+ readonly toolLimit: number
187
+ readonly filter?: FileFilter
188
+ }
189
+
190
+ export function createProjectFeedRead(opts: ProjectFeedReadOptions): DbReadPlan<ProjectFeed> {
191
+ return {
192
+ initial: emptyProjectFeed,
193
+ stages: [
194
+ (db, state) => ({
195
+ ...state,
196
+ tools: listRecentToolEvents(db, [...opts.sessionIds], opts.toolLimit),
197
+ }),
198
+ (db, state) => ({
199
+ ...state,
200
+ files: listRecentSessionFiles(db, [...opts.sessionIds], opts.filter),
201
+ }),
202
+ ],
203
+ }
204
+ }
205
+
206
+ export function readProjectFeed(db: SqlDb, opts: ProjectFeedReadOptions): ProjectFeed {
207
+ if (opts.sessionIds.length === 0) return emptyProjectFeed()
208
+ const plan = createProjectFeedRead(opts)
209
+ return plan.stages.reduce((state, stage) => stage(db, state), plan.initial())
210
+ }
211
+
212
+ export function readProjectFeedAsync(opts: ProjectFeedReadOptions): Promise<ProjectFeed> {
213
+ if (!opts.dbPath || opts.sessionIds.length === 0) return Promise.resolve(emptyProjectFeed())
214
+ const plan = createProjectFeedRead(opts)
215
+ return profileAsync("db.feed", () =>
216
+ readonlyReadGateway.run({
217
+ dbPath: opts.dbPath,
218
+ initial: plan.initial,
219
+ stages: plan.stages,
220
+ fallback: emptyProjectFeed,
221
+ }),
222
+ )
223
+ }