opencode-extended-sidebar 0.2.90

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 (105) hide show
  1. package/.oesignore +17 -0
  2. package/CHANGELOG.md +95 -0
  3. package/LICENSE +21 -0
  4. package/README.md +235 -0
  5. package/oes.json +11 -0
  6. package/package.json +100 -0
  7. package/scripts/install-git-hooks.mjs +29 -0
  8. package/src/pware.oc.core/constants/index.ts +18 -0
  9. package/src/pware.oc.core/constants/pware.oc.core.constants.eventKind.ts +29 -0
  10. package/src/pware.oc.core/constants/pware.oc.core.constants.eventName.ts +13 -0
  11. package/src/pware.oc.core/constants/pware.oc.core.constants.eventType.ts +241 -0
  12. package/src/pware.oc.core/constants/pware.oc.core.constants.myWork.ts +55 -0
  13. package/src/pware.oc.core/constants/pware.oc.core.constants.partType.ts +65 -0
  14. package/src/pware.oc.core/constants/pware.oc.core.constants.phase.ts +58 -0
  15. package/src/pware.oc.core/constants/pware.oc.core.constants.pulse.ts +63 -0
  16. package/src/pware.oc.core/constants/pware.oc.core.constants.rowKind.ts +34 -0
  17. package/src/pware.oc.core/constants/pware.oc.core.constants.status.ts +74 -0
  18. package/src/pware.oc.core/constants/pware.oc.core.constants.toolName.ts +69 -0
  19. package/src/pware.oc.core/git/index.ts +7 -0
  20. package/src/pware.oc.core/git/pware.oc.core.git.ts +237 -0
  21. package/src/pware.oc.core/git/pware.oc.core.gitignore.ts +87 -0
  22. package/src/pware.oc.core/index.ts +18 -0
  23. package/src/pware.oc.core/pware.oc.core.bus.ts +42 -0
  24. package/src/pware.oc.core/pware.oc.core.cache.ts +48 -0
  25. package/src/pware.oc.core/pware.oc.core.clipboard.ts +97 -0
  26. package/src/pware.oc.core/pware.oc.core.debug.ts +280 -0
  27. package/src/pware.oc.core/pware.oc.core.events.ts +79 -0
  28. package/src/pware.oc.core/pware.oc.core.glyph.ts +135 -0
  29. package/src/pware.oc.core/pware.oc.core.layout.ts +234 -0
  30. package/src/pware.oc.core/pware.oc.core.oes.ts +89 -0
  31. package/src/pware.oc.core/pware.oc.core.paths.ts +240 -0
  32. package/src/pware.oc.core/pware.oc.core.preview.ts +74 -0
  33. package/src/pware.oc.core/pware.oc.core.pulse.ts +726 -0
  34. package/src/pware.oc.core/pware.oc.core.sqlite.ts +175 -0
  35. package/src/pware.oc.core/pware.oc.core.status.ts +214 -0
  36. package/src/pware.oc.core/pware.oc.core.timing.ts +63 -0
  37. package/src/pware.oc.core/pware.oc.core.width.ts +215 -0
  38. package/src/pware.oc.omo/constants/index.ts +15 -0
  39. package/src/pware.oc.omo/constants/pware.oc.omo.constants.backgroundTask.ts +18 -0
  40. package/src/pware.oc.omo/constants/pware.oc.omo.constants.boulderStatus.ts +49 -0
  41. package/src/pware.oc.omo/constants/pware.oc.omo.constants.docKind.ts +29 -0
  42. package/src/pware.oc.omo/constants/pware.oc.omo.constants.eventName.ts +11 -0
  43. package/src/pware.oc.omo/constants/pware.oc.omo.constants.planStatus.ts +60 -0
  44. package/src/pware.oc.omo/constants/pware.oc.omo.constants.reviewStatus.ts +49 -0
  45. package/src/pware.oc.omo/constants/pware.oc.omo.constants.startWork.ts +25 -0
  46. package/src/pware.oc.omo/constants/pware.oc.omo.constants.verdict.ts +38 -0
  47. package/src/pware.oc.omo/index.ts +7 -0
  48. package/src/pware.oc.omo/resolver/index.ts +19 -0
  49. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.approval.ts +179 -0
  50. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.approvalGroup.ts +116 -0
  51. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.approvalState.ts +34 -0
  52. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.boulder.ts +503 -0
  53. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.config.ts +40 -0
  54. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.doc.ts +269 -0
  55. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.draftFile.ts +18 -0
  56. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.notepadsFile.ts +18 -0
  57. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.plan.ts +155 -0
  58. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.planFile.ts +361 -0
  59. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.proofFile.ts +18 -0
  60. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.rulesFile.ts +11 -0
  61. package/src/pware.oc.omo/resolver/pware.oc.omo.resolver.runContinuationFile.ts +14 -0
  62. package/src/pware.oc.opencode/constants/index.ts +10 -0
  63. package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.eventName.ts +15 -0
  64. package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.fileTouch.ts +18 -0
  65. package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.questionKind.ts +45 -0
  66. package/src/pware.oc.opencode/constants/pware.oc.opencode.constants.sessionStatus.ts +58 -0
  67. package/src/pware.oc.opencode/index.ts +8 -0
  68. package/src/pware.oc.opencode/pware.oc.opencode.events.ts +182 -0
  69. package/src/pware.oc.opencode/pware.oc.opencode.files.ts +399 -0
  70. package/src/pware.oc.opencode/resolver/index.ts +170 -0
  71. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.file.ts +162 -0
  72. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.question.ts +185 -0
  73. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.session.ts +211 -0
  74. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.todo.ts +26 -0
  75. package/src/pware.oc.opencode/resolver/pware.oc.opencode.resolver.tool.ts +236 -0
  76. package/src/pware.oc.perf/index.ts +14 -0
  77. package/src/pware.oc.perf/pware.oc.perf.asciichart.d.ts +15 -0
  78. package/src/pware.oc.perf/pware.oc.perf.charts.ts +284 -0
  79. package/src/pware.oc.perf/pware.oc.perf.reader.ts +927 -0
  80. package/src/pware.oc.perf/pware.oc.perf.realtime.ts +88 -0
  81. package/src/pware.oc.perf/pware.oc.perf.realtimeBlock.ts +118 -0
  82. package/src/pware.oc.perf/pware.oc.perf.realtimeCpuRam.ts +79 -0
  83. package/src/pware.oc.perf/pware.oc.perf.realtimeSampler.ts +71 -0
  84. package/src/pware.oc.perf/pware.oc.perf.realtimeTimeline.ts +214 -0
  85. package/src/pware.oc.perf/pware.oc.perf.self.ts +179 -0
  86. package/src/pware.oc.perf/pware.oc.perf.view.tsx +462 -0
  87. package/src/pware.oc.runtime/index.ts +13 -0
  88. package/src/pware.oc.runtime/pware.oc.runtime.monitor.ts +142 -0
  89. package/src/pware.oc.runtime/pware.oc.runtime.mywork-enrich.ts +79 -0
  90. package/src/pware.oc.runtime/pware.oc.runtime.mywork.ts +253 -0
  91. package/src/pware.oc.runtime/pware.oc.runtime.questions.ts +95 -0
  92. package/src/pware.oc.runtime/pware.oc.runtime.snapshotClient.ts +129 -0
  93. package/src/pware.oc.runtime/pware.oc.runtime.source.ts +105 -0
  94. package/src/pware.oc.runtime/pware.oc.runtime.worker.ts +43 -0
  95. package/src/pware.oc.runtime/resolver/index.ts +224 -0
  96. package/src/pware.oc.runtime/resolver/pware.oc.runtime.resolver.delegate.ts +146 -0
  97. package/src/pware.oc.ui/index.ts +12 -0
  98. package/src/pware.oc.ui/pware.oc.ui.chrome.tsx +339 -0
  99. package/src/pware.oc.ui/pware.oc.ui.glyphs.tsx +144 -0
  100. package/src/pware.oc.ui/pware.oc.ui.host.tsx +111 -0
  101. package/src/pware.oc.ui/pware.oc.ui.live.tsx +82 -0
  102. package/src/pware.oc.ui/pware.oc.ui.menudialogs.tsx +843 -0
  103. package/src/pware.oc.ui/pware.oc.ui.sections.tsx +526 -0
  104. package/src/pware.oc.ui/pware.oc.ui.sidebar.tsx +1629 -0
  105. package/src/pware.oc.ui.tsx +98 -0
@@ -0,0 +1,361 @@
1
+ /**
2
+ * pware.oc.omo.resolver.planFile
3
+ *
4
+ * Omo-file → writer-session index. Reads the OpenCode SQLite database through
5
+ * a raw `SqlDb` handle to map `.omo/` / `.sisyphus/` document files to the
6
+ * session that last wrote them. Lives in the omo layer because omo may read
7
+ * opencode data (one-way relaxation): the index needs the session/part rows,
8
+ * not any opencode-layer code.
9
+ *
10
+ * One generic engine (`omoFileIndex` / `sessionForOmoFile`) serves every
11
+ * document kind; the plan/draft index (`planSessionIndex` /
12
+ * `sessionForPlanFile`) is a legacy specialisation that folds plans and drafts
13
+ * into one map so a session's latest plan is preferred over its latest draft.
14
+ */
15
+ import { createStampCache } from "../../pware.oc.core/pware.oc.core.cache.js"
16
+ import { basenameOf, str } from "../../pware.oc.core/pware.oc.core.paths.js"
17
+ import type { SqlDb } from "../../pware.oc.core/pware.oc.core.sqlite.js"
18
+ import { DOC_KIND_PLAN, type DocKind } from "../constants/pware.oc.omo.constants.docKind.js"
19
+ import {
20
+ listOmoFiles,
21
+ type DocView,
22
+ type ListOmoFilesOptions,
23
+ } from "./pware.oc.omo.resolver.doc.js"
24
+
25
+ /** Every OMO on-disk document kind (the subdirectory under `.omo/` / `.sisyphus/`). */
26
+ export const OMO_FILE_KINDS = [
27
+ "plan",
28
+ "draft",
29
+ "notepad",
30
+ "proof",
31
+ "rule",
32
+ "run-continuation",
33
+ ] as const
34
+
35
+ /** An OMO on-disk document kind. */
36
+ export type OmoFileKind = (typeof OMO_FILE_KINDS)[number]
37
+
38
+ /** One case-insensitive regex per kind matching the omo/sisyphus subdir. */
39
+ const OMO_FILE_KIND_RE: Record<OmoFileKind, RegExp> = {
40
+ plan: /\.(omo|sisyphus)\/plans\//i,
41
+ draft: /\.(omo|sisyphus)\/drafts\//i,
42
+ notepad: /\.(omo|sisyphus)\/notepads\//i,
43
+ proof: /\.(omo|sisyphus)\/evidence\//i,
44
+ rule: /\.(omo|sisyphus)\/rules\//i,
45
+ "run-continuation": /\.(omo|sisyphus)\/run-continuation\//i,
46
+ }
47
+
48
+ export type PlanSessionIndex = {
49
+ fileWriter: Map<string, { sessionId: string; lastAt: number }>
50
+ sessionPlan: Map<string, { rel: string; lastAt: number; isPlan: boolean }>
51
+ }
52
+
53
+ export type OmoFileIndex = {
54
+ fileWriter: Map<string, { sessionId: string; lastAt: number }>
55
+ sessionFiles: Map<string, { rel: string; lastAt: number }>
56
+ }
57
+
58
+ const PLAN_FILE_RE = /\.(omo|sisyphus)\/(drafts|plans)\//i
59
+
60
+ /**
61
+ * Normalise `fp` to a project-relative posix path, match it against `regex`,
62
+ * and slice to the marker start. `projectRoot` strips the absolute prefix;
63
+ * without it the fp is used as-is and the marker may sit mid-path. Null when
64
+ * the path does not match `regex`.
65
+ */
66
+ function omoRelOf(
67
+ fp: string,
68
+ projectRoot: string | null | undefined,
69
+ regex: RegExp,
70
+ ): string | null {
71
+ let rel = fp.replace(/\\/g, "/").trim()
72
+ if (!rel) return null
73
+ if (projectRoot) {
74
+ const root = projectRoot.replace(/\\/g, "/").replace(/\/+$/, "")
75
+ if (rel.toLowerCase().startsWith(root.toLowerCase() + "/")) {
76
+ rel = rel.slice(root.length + 1)
77
+ } else if (rel.toLowerCase() === root.toLowerCase()) {
78
+ rel = ""
79
+ }
80
+ }
81
+ const m = rel.match(regex)
82
+ if (!m) return null
83
+ const start = m.index ?? 0
84
+ return start > 0 ? rel.slice(start) : rel
85
+ }
86
+
87
+ /**
88
+ * If `fp` is a plan/draft target under `.omo/` or `.sisyphus/`, return its
89
+ * project-relative path and whether it is under `plans/`. `projectRoot`
90
+ * strips the absolute prefix; without it the fp is used as-is and the marker
91
+ * may sit mid-path. Null for anything else (plain source files included).
92
+ */
93
+ function planFileOf(
94
+ fp: string,
95
+ projectRoot: string | null | undefined,
96
+ ): { rel: string; isPlan: boolean } | null {
97
+ const rel = omoRelOf(fp, projectRoot, PLAN_FILE_RE)
98
+ if (!rel) return null
99
+ const m = rel.match(PLAN_FILE_RE)
100
+ return { rel, isPlan: m?.[2]?.toLowerCase() === "plans" }
101
+ }
102
+
103
+ /** `MAX(part.time_updated)` over the part/session join, or null on error. */
104
+ function partsStampInfo(
105
+ db: SqlDb,
106
+ projectId: string | null | undefined,
107
+ ): { id: string; max: number } | null {
108
+ try {
109
+ const where = projectId ? "session.project_id = ?" : "1=1"
110
+ const args = projectId ? [projectId] : []
111
+ const p = db.get<{ m: number | null }>(
112
+ `SELECT MAX(part.time_updated) AS m
113
+ FROM part JOIN session ON session.id = part.session_id
114
+ WHERE ${where}`,
115
+ ...args,
116
+ )
117
+ return { id: projectId ?? "*", max: p?.m ?? 0 }
118
+ } catch {
119
+ return null
120
+ }
121
+ }
122
+
123
+ function planIndexStamp(db: SqlDb, projectId: string | null | undefined): string {
124
+ const info = partsStampInfo(db, projectId)
125
+ return info ? `${info.id}|${info.max}` : "x"
126
+ }
127
+
128
+ function omoFileStamp(db: SqlDb, projectId: string | null | undefined, kind: OmoFileKind): string {
129
+ const info = partsStampInfo(db, projectId)
130
+ return info ? `${info.id}|${kind}|${info.max}` : "x"
131
+ }
132
+
133
+ /** One write-ish part row: session, resolved filePath, latest write time, and
134
+ * whether the session ever `write`-created the file. */
135
+ type FilePartRow = {
136
+ session_id: string | null
137
+ fp: string | null
138
+ last: number | null
139
+ is_writer: number | null
140
+ }
141
+
142
+ function queryFileParts(db: SqlDb, projectId: string | null | undefined): FilePartRow[] {
143
+ const where = projectId ? "session.project_id = ? AND" : ""
144
+ const args = projectId ? [projectId] : []
145
+ return db.all<FilePartRow>(
146
+ `SELECT part.session_id,
147
+ COALESCE(
148
+ json_extract(part.data,'$.state.input.filePath'),
149
+ json_extract(part.data,'$.input.filePath'),
150
+ json_extract(part.data,'$.filePath')
151
+ ) AS fp,
152
+ MAX(part.time_updated) AS last,
153
+ MAX(CASE WHEN json_extract(part.data,'$.tool')='write' THEN 1 ELSE 0 END) AS is_writer
154
+ FROM part
155
+ JOIN session ON session.id = part.session_id
156
+ WHERE ${where} json_extract(part.data,'$.type')='tool'
157
+ AND json_extract(part.data,'$.tool') IN ('write','edit','multiedit','apply_edit','applyedit')
158
+ GROUP BY part.session_id, fp`,
159
+ ...args,
160
+ )
161
+ }
162
+
163
+ function buildPlanSessionIndex(
164
+ db: SqlDb,
165
+ projectId: string | null | undefined,
166
+ projectRoot: string | null | undefined,
167
+ ): PlanSessionIndex {
168
+ const fileWriter = new Map<string, { sessionId: string; lastAt: number }>()
169
+ const writerPref = new Map<string, number>() // basename → is_writer of the current entry
170
+ const sessionPlan = new Map<string, { rel: string; lastAt: number; isPlan: boolean }>()
171
+ try {
172
+ for (const row of queryFileParts(db, projectId)) {
173
+ const sessionId = str(row.session_id)
174
+ const fp = str(row.fp)
175
+ const last = typeof row.last === "number" && row.last > 0 ? row.last : 0
176
+ if (!sessionId || !fp) continue
177
+ const info = planFileOf(fp, projectRoot)
178
+ if (!info) continue
179
+ const base = basenameOf(info.rel)
180
+ const isWriter = row.is_writer === 1 ? 1 : 0
181
+ const writer = fileWriter.get(base)
182
+ if (!writer) {
183
+ fileWriter.set(base, { sessionId, lastAt: last })
184
+ writerPref.set(base, isWriter)
185
+ } else {
186
+ const cur = writerPref.get(base) ?? 0
187
+ // A `write` creator beats a session that only edited the file, even
188
+ // when the edit came later; equal preference falls back to the later
189
+ // timestamp.
190
+ if (isWriter > cur || (isWriter === cur && last > writer.lastAt)) {
191
+ fileWriter.set(base, { sessionId, lastAt: last })
192
+ writerPref.set(base, isWriter)
193
+ }
194
+ }
195
+ const plan = sessionPlan.get(sessionId)
196
+ if (!plan) {
197
+ sessionPlan.set(sessionId, { rel: info.rel, lastAt: last, isPlan: info.isPlan })
198
+ } else if (last > plan.lastAt) {
199
+ sessionPlan.set(sessionId, { rel: info.rel, lastAt: last, isPlan: info.isPlan })
200
+ } else if (last === plan.lastAt && info.isPlan && !plan.isPlan) {
201
+ sessionPlan.set(sessionId, { rel: info.rel, lastAt: last, isPlan: info.isPlan })
202
+ }
203
+ }
204
+ } catch {
205
+ // soft-fail → empty index
206
+ }
207
+ return { fileWriter, sessionPlan }
208
+ }
209
+
210
+ function buildOmoFileIndex(
211
+ db: SqlDb,
212
+ projectId: string | null | undefined,
213
+ projectRoot: string | null | undefined,
214
+ kind: OmoFileKind,
215
+ ): OmoFileIndex {
216
+ const fileWriter = new Map<string, { sessionId: string; lastAt: number }>()
217
+ const writerPref = new Map<string, number>() // basename → is_writer of the current entry
218
+ const sessionFiles = new Map<string, { rel: string; lastAt: number }>()
219
+ const regex = OMO_FILE_KIND_RE[kind]
220
+ try {
221
+ for (const row of queryFileParts(db, projectId)) {
222
+ const sessionId = str(row.session_id)
223
+ const fp = str(row.fp)
224
+ const last = typeof row.last === "number" && row.last > 0 ? row.last : 0
225
+ if (!sessionId || !fp) continue
226
+ const rel = omoRelOf(fp, projectRoot, regex)
227
+ if (!rel) continue
228
+ const base = basenameOf(rel)
229
+ const isWriter = row.is_writer === 1 ? 1 : 0
230
+ const writer = fileWriter.get(base)
231
+ if (!writer) {
232
+ fileWriter.set(base, { sessionId, lastAt: last })
233
+ writerPref.set(base, isWriter)
234
+ } else {
235
+ const cur = writerPref.get(base) ?? 0
236
+ // A `write` creator beats a session that only edited the file, even
237
+ // when the edit came later; equal preference falls back to the later
238
+ // timestamp.
239
+ if (isWriter > cur || (isWriter === cur && last > writer.lastAt)) {
240
+ fileWriter.set(base, { sessionId, lastAt: last })
241
+ writerPref.set(base, isWriter)
242
+ }
243
+ }
244
+ const curFile = sessionFiles.get(sessionId)
245
+ if (!curFile || last > curFile.lastAt) {
246
+ sessionFiles.set(sessionId, { rel, lastAt: last })
247
+ }
248
+ }
249
+ } catch {
250
+ // soft-fail → empty index
251
+ }
252
+ return { fileWriter, sessionFiles }
253
+ }
254
+
255
+ const planIndexCache = createStampCache<PlanSessionIndex>()
256
+ const omoIndexCache = createStampCache<OmoFileIndex>()
257
+
258
+ /**
259
+ * In-memory bidirectional plan-file index for one project, built from a single
260
+ * write-ish `part` join. `fileWriter` maps a plan/draft basename to its latest
261
+ * writer session; `sessionPlan` maps a session to its latest plan/draft file,
262
+ * preferring `plans/` over `drafts/` on an equal timestamp. Stamp-cached on the
263
+ * project's `MAX(part.time_updated)` so it rebuilds only when parts change.
264
+ */
265
+ export function planSessionIndex(
266
+ db: SqlDb,
267
+ projectId: string | null | undefined,
268
+ projectRoot: string | null | undefined,
269
+ ): PlanSessionIndex {
270
+ return planIndexCache.get(planIndexStamp(db, projectId), () =>
271
+ buildPlanSessionIndex(db, projectId, projectRoot),
272
+ )
273
+ }
274
+
275
+ /**
276
+ * The session that last wrote a `.omo/` plan/draft file, if any. Matches
277
+ * write-ish tool parts by the file's basename, so the planner session that
278
+ * created a pending approval is the one "Continue" should jump to.
279
+ */
280
+ export function sessionForPlanFile(db: SqlDb, relPath: string | null | undefined): string | null {
281
+ const base = basenameOf(relPath ?? "")
282
+ if (!base || base === "file") return null
283
+ return planSessionIndex(db, null, null).fileWriter.get(base)?.sessionId ?? null
284
+ }
285
+
286
+ /**
287
+ * In-memory bidirectional index for one OMO document kind, built from a single
288
+ * write-ish `part` join. `fileWriter` maps a file basename to its latest writer
289
+ * session; `sessionFiles` maps a session to its latest file of that kind.
290
+ * Stamp-cached on the project's `MAX(part.time_updated)` so it rebuilds only
291
+ * when parts change.
292
+ */
293
+ export function omoFileIndex(
294
+ db: SqlDb,
295
+ projectId: string | null | undefined,
296
+ projectRoot: string | null | undefined,
297
+ kind: OmoFileKind,
298
+ ): OmoFileIndex {
299
+ return omoIndexCache.get(omoFileStamp(db, projectId, kind), () =>
300
+ buildOmoFileIndex(db, projectId, projectRoot, kind),
301
+ )
302
+ }
303
+
304
+ /**
305
+ * The writer session for a rel path from an already-built index. The per-file
306
+ * half of `sessionForOmoFile`, split out so a caller can filter a whole list
307
+ * against one index build instead of one stamp lookup per file.
308
+ */
309
+ export function omoWriterSession(
310
+ index: OmoFileIndex,
311
+ relPath: string | null | undefined,
312
+ ): string | null {
313
+ const base = basenameOf(relPath ?? "")
314
+ if (!base || base === "file") return null
315
+ return index.fileWriter.get(base)?.sessionId ?? null
316
+ }
317
+
318
+ /**
319
+ * The session that last wrote a `.omo/` file of `kind`, if any. Matches
320
+ * write-ish tool parts by the file's basename.
321
+ */
322
+ export function sessionForOmoFile(
323
+ db: SqlDb,
324
+ relPath: string | null | undefined,
325
+ kind: OmoFileKind,
326
+ ): string | null {
327
+ return omoWriterSession(omoFileIndex(db, null, null, kind), relPath)
328
+ }
329
+
330
+ /** A per-kind omo-file resolver: the index builder + the writer-session lookup. */
331
+ export function makeOmoFileResolver(kind: OmoFileKind): {
332
+ sessionIndex: (
333
+ db: SqlDb,
334
+ projectId: string | null | undefined,
335
+ projectRoot: string | null | undefined,
336
+ ) => OmoFileIndex
337
+ sessionForFile: (db: SqlDb, relPath: string | null | undefined) => string | null
338
+ } {
339
+ return {
340
+ sessionIndex: (db, projectId, projectRoot) => omoFileIndex(db, projectId, projectRoot, kind),
341
+ sessionForFile: (db, relPath) => sessionForOmoFile(db, relPath, kind),
342
+ }
343
+ }
344
+
345
+ /** A per-doc-kind `.list` wrapper — the `XxxFile.list` shape. */
346
+ export function makeOmoFileList(docKind: DocKind): {
347
+ list: (
348
+ projectRoot: string | null | undefined,
349
+ sessionId?: string | null,
350
+ opts?: ListOmoFilesOptions,
351
+ ) => DocView[]
352
+ } {
353
+ return {
354
+ list(projectRoot, sessionId = null, opts = {}) {
355
+ return listOmoFiles(docKind, projectRoot, { ...opts, sessionId })
356
+ },
357
+ }
358
+ }
359
+
360
+ /** Plan files under `.omo/plans/`, optionally filtered by writer session. */
361
+ export const PlanFile = makeOmoFileList(DOC_KIND_PLAN)
@@ -0,0 +1,18 @@
1
+ /**
2
+ * pware.oc.omo.resolver.proofFile
3
+ *
4
+ * Evidence (proof) file → writer-session index. Thin re-export of the shared
5
+ * omo file engine (`planFile.ts`), pinned to the `.omo/evidence/` document kind.
6
+ */
7
+ import { DOC_KIND_PROOF } from "../constants/pware.oc.omo.constants.docKind.js"
8
+ import {
9
+ makeOmoFileList,
10
+ makeOmoFileResolver,
11
+ } from "./pware.oc.omo.resolver.planFile.js"
12
+
13
+ /** Bidirectional evidence-file index for one project (see `omoFileIndex`). */
14
+ export const { sessionIndex: proofSessionIndex, sessionForFile: sessionForProofFile } =
15
+ makeOmoFileResolver("proof")
16
+
17
+ /** Evidence files under `.omo/evidence/`, optionally filtered by writer session. */
18
+ export const ProofFile = makeOmoFileList(DOC_KIND_PROOF)
@@ -0,0 +1,11 @@
1
+ /**
2
+ * pware.oc.omo.resolver.rulesFile
3
+ *
4
+ * Rule-file → writer-session index. Thin re-export of the shared omo file
5
+ * engine (`planFile.ts`), pinned to the `.omo/rules/` document kind.
6
+ */
7
+ import { makeOmoFileResolver } from "./pware.oc.omo.resolver.planFile.js"
8
+
9
+ /** Bidirectional rule-file index for one project (see `omoFileIndex`). */
10
+ export const { sessionIndex: rulesSessionIndex, sessionForFile: sessionForRuleFile } =
11
+ makeOmoFileResolver("rule")
@@ -0,0 +1,14 @@
1
+ /**
2
+ * pware.oc.omo.resolver.runContinuationFile
3
+ *
4
+ * Run-continuation file → writer-session index. Thin re-export of the shared
5
+ * omo file engine (`planFile.ts`), pinned to the `.omo/run-continuation/`
6
+ * document kind.
7
+ */
8
+ import { makeOmoFileResolver } from "./pware.oc.omo.resolver.planFile.js"
9
+
10
+ /** Bidirectional run-continuation index for one project (see `omoFileIndex`). */
11
+ export const {
12
+ sessionIndex: runContinuationSessionIndex,
13
+ sessionForFile: sessionForRunContinuationFile,
14
+ } = makeOmoFileResolver("run-continuation")
@@ -0,0 +1,10 @@
1
+ /**
2
+ * pware.oc.opencode.constants
3
+ *
4
+ * Single source of truth for the OpenCode-domain string literals: session
5
+ * statuses and activity states, question-tool kinds, and file-touch kinds.
6
+ */
7
+ export * from "./pware.oc.opencode.constants.sessionStatus.js"
8
+ export * from "./pware.oc.opencode.constants.questionKind.js"
9
+ export * from "./pware.oc.opencode.constants.fileTouch.js"
10
+ export * from "./pware.oc.opencode.constants.eventName.js"
@@ -0,0 +1,15 @@
1
+ export const EV_OC_SESSION_ACTIVITY = "pware.oc.session.activity"
2
+ export const EV_OC_FLOW = "pware.oc.flow"
3
+ export const EV_OC_TOOL_HIT = "pware.oc.tool.hit"
4
+ export const EV_OC_FILES_TOUCHED = "pware.oc.files.touched"
5
+ export const EV_OC_TOKENS_DELTA = "pware.oc.tokens.delta"
6
+
7
+ export const OC_EVENT_NAMES = [
8
+ EV_OC_SESSION_ACTIVITY,
9
+ EV_OC_FLOW,
10
+ EV_OC_TOOL_HIT,
11
+ EV_OC_FILES_TOUCHED,
12
+ EV_OC_TOKENS_DELTA,
13
+ ] as const
14
+
15
+ export type OcEventName = (typeof OC_EVENT_NAMES)[number]
@@ -0,0 +1,18 @@
1
+ /**
2
+ * pware.oc.opencode.constants.filetouch
3
+ *
4
+ * OpenCode file-touch kinds: whether a tool call reads or writes a file.
5
+ * Classified in `pware.oc.opencode/pware.oc.opencode.files.ts`.
6
+ */
7
+
8
+ /** File touch: the tool read/viewed the file. */
9
+ export const FILE_TOUCH_READ = "read"
10
+
11
+ /** File touch: the tool wrote/deleted the file. */
12
+ export const FILE_TOUCH_WRITE = "write"
13
+
14
+ /** Every file-touch kind. */
15
+ export const FILE_TOUCHES = [FILE_TOUCH_READ, FILE_TOUCH_WRITE] as const
16
+
17
+ /** A file-touch kind. */
18
+ export type FileTouch = (typeof FILE_TOUCHES)[number]
@@ -0,0 +1,45 @@
1
+ /**
2
+ * pware.oc.opencode.constants.questionkind
3
+ *
4
+ * OpenCode `question` tool-part kinds: what an open question means for the
5
+ * "My work" queue. Classified in
6
+ * `pware.oc.opencode/resolver/pware.oc.opencode.resolver.question.ts`:
7
+ * - `question` — the agent is live and waiting for an answer (running/pending).
8
+ * - `interrupted` — the tool was aborted (`metadata.interrupted`), the answer
9
+ * never came, but the session moved on or died — still your call.
10
+ * - `error` — the tool genuinely failed (no answer, no interrupt marker).
11
+ */
12
+
13
+ /** Question kind: the agent is live and waiting for an answer. */
14
+ export const QUESTION_KIND_QUESTION = "question"
15
+
16
+ /** Question kind: the tool was aborted — the answer never came. */
17
+ export const QUESTION_KIND_INTERRUPTED = "interrupted"
18
+
19
+ /** Question kind: the tool genuinely failed. */
20
+ export const QUESTION_KIND_ERROR = "error"
21
+
22
+ /** Every open-question kind. */
23
+ export const QUESTION_KINDS = [
24
+ QUESTION_KIND_QUESTION,
25
+ QUESTION_KIND_INTERRUPTED,
26
+ QUESTION_KIND_ERROR,
27
+ ] as const
28
+
29
+ /** An open-question kind. */
30
+ export type OpenQuestionKind = (typeof QUESTION_KINDS)[number]
31
+
32
+ /** True when the open question is live and awaiting an answer. */
33
+ export function isWaitingForAnswer(kind: OpenQuestionKind | null): boolean {
34
+ return kind === QUESTION_KIND_QUESTION
35
+ }
36
+
37
+ /** True when the question was aborted and the answer never came. */
38
+ export function isInterrupted(kind: OpenQuestionKind | null): boolean {
39
+ return kind === QUESTION_KIND_INTERRUPTED
40
+ }
41
+
42
+ /** True when the question tool genuinely failed. */
43
+ export function isQuestionError(kind: OpenQuestionKind | null): boolean {
44
+ return kind === QUESTION_KIND_ERROR
45
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * pware.oc.opencode.constants.sessionstatus
3
+ *
4
+ * OpenCode session-domain string literals: the session status a `SessionView`
5
+ * carries, and the finer-grained activity state used for approval rows. Both
6
+ * derive from SQLite rows + host events in
7
+ * `pware.oc.opencode/resolver/pware.oc.opencode.resolver.session.ts`.
8
+ */
9
+
10
+ /** Session status: recently updated — the agent is likely still working. */
11
+ export const SESSION_STATUS_RUNNING = "running"
12
+
13
+ /** Session status: quiet — no recent updates. */
14
+ export const SESSION_STATUS_IDLE = "idle"
15
+
16
+ /** Session status: archived by the host. */
17
+ export const SESSION_STATUS_ARCHIVED = "archived"
18
+
19
+ /** Session status: no state could be determined. */
20
+ export const SESSION_STATUS_UNKNOWN = "unknown"
21
+
22
+ /** Every session status a `SessionView` can carry. */
23
+ export const SESSION_STATUSES = [
24
+ SESSION_STATUS_RUNNING,
25
+ SESSION_STATUS_IDLE,
26
+ SESSION_STATUS_ARCHIVED,
27
+ SESSION_STATUS_UNKNOWN,
28
+ ] as const
29
+
30
+ /** A session status value. */
31
+ export type AgentStatus = (typeof SESSION_STATUSES)[number]
32
+
33
+ /** Session activity state: a fresh `time_updated` — the session is streaming. */
34
+ export const SESSION_STATE_STREAMING = "streaming"
35
+
36
+ /** Session activity state: stale in SQLite but a background task is running. */
37
+ export const SESSION_STATE_AWAITING_BACKGROUND = "awaiting-background"
38
+
39
+ /** Session activity state: quiet. */
40
+ export const SESSION_STATE_IDLE = SESSION_STATUS_IDLE
41
+
42
+ /** Session activity state: archived. */
43
+ export const SESSION_STATE_ARCHIVED = SESSION_STATUS_ARCHIVED
44
+
45
+ /** Session activity state: unknown. */
46
+ export const SESSION_STATE_UNKNOWN = SESSION_STATUS_UNKNOWN
47
+
48
+ /** Every session activity state. */
49
+ export const SESSION_STATES = [
50
+ SESSION_STATE_STREAMING,
51
+ SESSION_STATE_AWAITING_BACKGROUND,
52
+ SESSION_STATE_IDLE,
53
+ SESSION_STATE_ARCHIVED,
54
+ SESSION_STATE_UNKNOWN,
55
+ ] as const
56
+
57
+ /** A session activity state. */
58
+ export type SessionState = (typeof SESSION_STATES)[number]
@@ -0,0 +1,8 @@
1
+ /**
2
+ * pware.oc.opencode
3
+ *
4
+ * OpenCode domain: SQLite + host-event file activity. Imports core only.
5
+ */
6
+ export * from "./pware.oc.opencode.files.js"
7
+ export * from "./pware.oc.opencode.events.js"
8
+ export * from "./resolver/index.js"