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,236 +1,224 @@
1
- /**
2
- * pware.oc.core.opencode.resolver.tool
3
- *
4
- * Tool-call parts → ToolView (name, status, timings). Metadata only — never
5
- * args or outputs. Feeds the Current and Sessions tabs.
6
- */
7
- import { preferToolLabel, shortToolLabel, toEpochMs, type ToolHit } from "../../pware.oc.core/pware.oc.core.pulse.js"
8
- import { str } from "../../pware.oc.core/pware.oc.core.paths.js"
9
- import { uniqueIds, type SqlDb } from "../../pware.oc.core/pware.oc.core.sqlite.js"
10
- import { toToolStatus, type ToolStatus } from "../../pware.oc.core/pware.oc.core.status.js"
11
- import {
12
- TOOL_STATUS_COMPLETED,
13
- TOOL_STATUS_ERROR,
14
- TOOL_STATUS_PENDING,
15
- TOOL_STATUS_RUNNING,
16
- } from "../../pware.oc.core/constants/pware.oc.core.constants.status.js"
17
- import { PART_TYPE_TOOL } from "../../pware.oc.core/constants/pware.oc.core.constants.partType.js"
18
-
19
- export type { ToolStatus }
20
-
21
- export { toToolStatus as normalizeToolStatus }
22
-
23
- export type ToolView = {
24
- id: string
25
- callId?: string | null
26
- /** Display label: command / file / task description, not just "bash" or "task". */
27
- name: string
28
- tool: string
29
- status: ToolStatus
30
- startedAt: number | null
31
- endedAt: number | null
32
- durationMs: number | null
33
- }
34
-
35
- const TOOL_SCAN = 80
36
- const TOOL_ROWS = 8
37
-
38
- /** Metadata only — json_extract, never the part blob. */
39
- type ToolEventRow = {
40
- id: string
41
- time_created: number
42
- time_updated: number
43
- tool: string | null
44
- callID: string | null
45
- status: string | null
46
- tstart: number | null
47
- tend: number | null
48
- title: string | null
49
- command: string | null
50
- command2: string | null
51
- filePath: string | null
52
- filePath2: string | null
53
- pattern: string | null
54
- pattern2: string | null
55
- description: string | null
56
- description2: string | null
57
- subagent: string | null
58
- category: string | null
59
- }
60
-
61
- /** Shared tool-part column list — all columns from `part.data` via json_extract. */
62
- function toolColumns(): string {
63
- return [
64
- `id`,
65
- `time_created`,
66
- `time_updated`,
67
- `json_extract(data,'$.tool') AS tool`,
68
- `json_extract(data,'$.callID') AS callID`,
69
- `json_extract(data,'$.state.status') AS status`,
70
- `json_extract(data,'$.state.time.start') AS tstart`,
71
- `json_extract(data,'$.state.time.end') AS tend`,
72
- `json_extract(data,'$.state.title') AS title`,
73
- `json_extract(data,'$.state.input.command') AS command`,
74
- `json_extract(data,'$.input.command') AS command2`,
75
- `json_extract(data,'$.state.input.filePath') AS filePath`,
76
- `json_extract(data,'$.input.filePath') AS filePath2`,
77
- `json_extract(data,'$.state.input.pattern') AS pattern`,
78
- `json_extract(data,'$.input.pattern') AS pattern2`,
79
- `json_extract(data,'$.state.input.description') AS description`,
80
- `json_extract(data,'$.input.description') AS description2`,
81
- `json_extract(data,'$.state.input.subagent_type') AS subagent`,
82
- `json_extract(data,'$.state.input.category') AS category`,
83
- ].join(",\n ")
84
- }
85
-
86
- function toolViewsFromRows(rows: readonly ToolEventRow[], limit: number): ToolView[] {
87
- const out: ToolView[] = []
88
- for (const row of rows) {
89
- const tool = str(row.tool) || "tool"
90
- const start = toEpochMs(row.tstart)
91
- const end = toEpochMs(row.tend)
92
- const status = toToolStatus(
93
- str(row.status) || (end != null ? TOOL_STATUS_COMPLETED : start != null ? TOOL_STATUS_RUNNING : null),
94
- )
95
- const startedAt = start ?? toEpochMs(row.time_created)
96
- const endedAt =
97
- end ??
98
- (status === TOOL_STATUS_COMPLETED || status === TOOL_STATUS_ERROR ? toEpochMs(row.time_updated) : null)
99
- const durationMs =
100
- startedAt != null && endedAt != null && endedAt >= startedAt ? endedAt - startedAt : null
101
- out.push({
102
- id: String(row.id),
103
- callId: str(row.callID),
104
- tool,
105
- name: shortToolLabel({
106
- tool,
107
- title: str(row.title),
108
- command: str(row.command) || str(row.command2),
109
- filePath: str(row.filePath) || str(row.filePath2),
110
- pattern: str(row.pattern) || str(row.pattern2),
111
- description: str(row.description) || str(row.description2),
112
- subagent: str(row.subagent) || str(row.category),
113
- }),
114
- status,
115
- startedAt,
116
- endedAt,
117
- durationMs,
118
- })
119
- if (out.length >= limit) break
120
- }
121
- return out
122
- }
123
-
124
- function listToolRows(db: SqlDb, where: string, params: string[], limit: number): ToolEventRow[] {
125
- const candidateRows = db.all<{ id: string }>(
126
- `SELECT id
127
- FROM part
128
- WHERE ${where}
129
- ORDER BY time_created DESC
130
- LIMIT ${TOOL_SCAN}`,
131
- ...params,
132
- )
133
- const ids = candidateRows.map((r) => String(r.id))
134
- if (ids.length === 0) return []
135
- const saturated = ids.length === TOOL_SCAN
136
-
137
- const placeholders = ids.map(() => "?").join(",")
138
- const rows = db.all<ToolEventRow>(
139
- `SELECT ${toolColumns()}
140
- FROM part
141
- WHERE id IN (${placeholders})
142
- AND json_extract(data,'$.type') = '${PART_TYPE_TOOL}'
143
- ORDER BY time_created DESC
144
- LIMIT ${limit}`,
145
- ...ids,
146
- )
147
-
148
- if (saturated && rows.length < limit) {
149
- return db.all<ToolEventRow>(
150
- `SELECT ${toolColumns()}
151
- FROM part
152
- WHERE ${where}
153
- AND json_extract(data,'$.type') = '${PART_TYPE_TOOL}'
154
- ORDER BY time_created DESC
155
- LIMIT ${TOOL_SCAN}`,
156
- ...params,
157
- )
158
- }
159
- return rows
160
- }
161
-
162
- /** Newest tool parts of one session — the Current tab feed. */
163
- export function listToolEvents(db: SqlDb, sessionId: string, limit = TOOL_ROWS): ToolView[] {
164
- let rows: ToolEventRow[] = []
165
- try {
166
- rows = listToolRows(db, "session_id = ?", [sessionId], limit)
167
- } catch {
168
- return []
169
- }
170
- return toolViewsFromRows(rows, limit)
171
- }
172
-
173
- /** Newest tool parts across the given sessions — the Sessions tab feed. */
174
- export function listRecentToolEvents(db: SqlDb, sessionIds: string[], limit = TOOL_ROWS): ToolView[] {
175
- const clean = uniqueIds(sessionIds)
176
- if (clean.length === 0) return []
177
- const placeholders = clean.map(() => "?").join(",")
178
- let rows: ToolEventRow[] = []
179
- try {
180
- rows = listToolRows(db, `session_id IN (${placeholders})`, clean, limit)
181
- } catch {
182
- return []
183
- }
184
- return toolViewsFromRows(rows, limit)
185
- }
186
-
187
- export function mergeTools(
188
- dbTools: ToolView[],
189
- live: Record<string, ToolHit>,
190
- now: number,
191
- limit: number,
192
- ): ToolView[] {
193
- // DB rows are keyed by the part id (`prt_…`) but carry the callID (`call_…`);
194
- // live events reference only the callID. Key both sides by callID so a live
195
- // hit lands on the same slot as its DB row, or the same call renders twice.
196
- // A live hit fills in a running start it saw first, but once the DB row has
197
- // the real endedAt/duration, the live event must not clobber them the panel
198
- // sorts finished calls by endedAt, and `now` would keep reordering them.
199
- const byId = new Map<string, ToolView>()
200
- const byCall = new Map<string, string>()
201
- for (const t of dbTools) {
202
- const key = t.callId || t.id
203
- byId.set(key, t)
204
- if (t.callId && t.callId !== t.id) byCall.set(t.id, key)
205
- }
206
- for (const hit of Object.values(live)) {
207
- const key = byCall.get(hit.id) ?? hit.id
208
- const prev = byId.get(key)
209
- if (prev && (prev.status === TOOL_STATUS_COMPLETED || prev.status === TOOL_STATUS_ERROR) && hit.status === TOOL_STATUS_RUNNING) {
210
- continue
211
- }
212
- byId.set(key, {
213
- id: prev?.id ?? hit.id,
214
- callId: prev?.callId ?? null,
215
- name: preferToolLabel(hit.name, prev?.name),
216
- tool: prev?.tool || "tool",
217
- status: hit.status,
218
- startedAt: prev?.startedAt ?? now,
219
- endedAt: hit.status === TOOL_STATUS_RUNNING ? null : (prev?.endedAt ?? now),
220
- durationMs:
221
- hit.status === TOOL_STATUS_RUNNING
222
- ? null
223
- : prev?.durationMs ?? (prev?.startedAt != null ? Math.max(0, now - prev.startedAt) : null),
224
- })
225
- }
226
- return [...byId.values()]
227
- .sort((a, b) => {
228
- const ar = a.status === TOOL_STATUS_RUNNING || a.status === TOOL_STATUS_PENDING ? 0 : 1
229
- const br = b.status === TOOL_STATUS_RUNNING || b.status === TOOL_STATUS_PENDING ? 0 : 1
230
- if (ar !== br) return ar - br
231
- const at = ar === 0 ? (a.startedAt ?? 0) : (a.endedAt ?? a.startedAt ?? 0)
232
- const bt = br === 0 ? (b.startedAt ?? 0) : (b.endedAt ?? b.startedAt ?? 0)
233
- return bt - at
234
- })
235
- .slice(0, limit)
236
- }
1
+ /**
2
+ * pware.oc.core.opencode.resolver.tool
3
+ *
4
+ * Tool-call parts → ToolView (name, status, timings). Metadata only — never
5
+ * args or outputs. Feeds the Current and Sessions tabs.
6
+ */
7
+ import { preferToolLabel, shortToolLabel, toEpochMs, type ToolHit } from "../../pware.oc.core/pware.oc.core.pulse.js"
8
+ import { str } from "../../pware.oc.core/pware.oc.core.paths.js"
9
+ import { uniqueIds, type SqlDb } from "../../pware.oc.core/pware.oc.core.sqlite.js"
10
+ import { toToolStatus, type ToolStatus } from "../../pware.oc.core/pware.oc.core.status.js"
11
+ import {
12
+ TOOL_STATUS_COMPLETED,
13
+ TOOL_STATUS_ERROR,
14
+ TOOL_STATUS_PENDING,
15
+ TOOL_STATUS_RUNNING,
16
+ } from "../../pware.oc.core/constants/pware.oc.core.constants.status.js"
17
+ import { PART_TYPE_TOOL } from "../../pware.oc.core/constants/pware.oc.core.constants.partType.js"
18
+
19
+ export type { ToolStatus }
20
+
21
+ export { toToolStatus as normalizeToolStatus }
22
+
23
+ export type ToolView = {
24
+ id: string
25
+ callId?: string | null
26
+ /** Display label: command / file / task description, not just "bash" or "task". */
27
+ name: string
28
+ tool: string
29
+ status: ToolStatus
30
+ startedAt: number | null
31
+ endedAt: number | null
32
+ durationMs: number | null
33
+ }
34
+
35
+ const TOOL_SCAN = 80
36
+ const TOOL_ROWS = 8
37
+
38
+ /** Metadata only — json_extract, never the part blob. */
39
+ type ToolEventRow = {
40
+ id: string
41
+ time_created: number
42
+ time_updated: number
43
+ tool: string | null
44
+ callID: string | null
45
+ status: string | null
46
+ tstart: number | null
47
+ tend: number | null
48
+ title: string | null
49
+ command: string | null
50
+ command2: string | null
51
+ filePath: string | null
52
+ filePath2: string | null
53
+ pattern: string | null
54
+ pattern2: string | null
55
+ description: string | null
56
+ description2: string | null
57
+ subagent: string | null
58
+ category: string | null
59
+ }
60
+
61
+ /** Shared tool-part column list — all columns from `part.data` via json_extract. */
62
+ function toolColumns(): string {
63
+ return [
64
+ `id`,
65
+ `time_created`,
66
+ `time_updated`,
67
+ `json_extract(data,'$.tool') AS tool`,
68
+ `json_extract(data,'$.callID') AS callID`,
69
+ `json_extract(data,'$.state.status') AS status`,
70
+ `json_extract(data,'$.state.time.start') AS tstart`,
71
+ `json_extract(data,'$.state.time.end') AS tend`,
72
+ `json_extract(data,'$.state.title') AS title`,
73
+ `json_extract(data,'$.state.input.command') AS command`,
74
+ `json_extract(data,'$.input.command') AS command2`,
75
+ `json_extract(data,'$.state.input.filePath') AS filePath`,
76
+ `json_extract(data,'$.input.filePath') AS filePath2`,
77
+ `json_extract(data,'$.state.input.pattern') AS pattern`,
78
+ `json_extract(data,'$.input.pattern') AS pattern2`,
79
+ `json_extract(data,'$.state.input.description') AS description`,
80
+ `json_extract(data,'$.input.description') AS description2`,
81
+ `json_extract(data,'$.state.input.subagent_type') AS subagent`,
82
+ `json_extract(data,'$.state.input.category') AS category`,
83
+ ].join(",\n ")
84
+ }
85
+
86
+ function toolViewsFromRows(rows: readonly ToolEventRow[], limit: number): ToolView[] {
87
+ const out: ToolView[] = []
88
+ for (const row of rows) {
89
+ const tool = str(row.tool) || "tool"
90
+ const start = toEpochMs(row.tstart)
91
+ const end = toEpochMs(row.tend)
92
+ const status = toToolStatus(
93
+ str(row.status) || (end != null ? TOOL_STATUS_COMPLETED : start != null ? TOOL_STATUS_RUNNING : null),
94
+ )
95
+ const startedAt = start ?? toEpochMs(row.time_created)
96
+ const endedAt =
97
+ end ??
98
+ (status === TOOL_STATUS_COMPLETED || status === TOOL_STATUS_ERROR ? toEpochMs(row.time_updated) : null)
99
+ const durationMs =
100
+ startedAt != null && endedAt != null && endedAt >= startedAt ? endedAt - startedAt : null
101
+ out.push({
102
+ id: String(row.id),
103
+ callId: str(row.callID),
104
+ tool,
105
+ name: shortToolLabel({
106
+ tool,
107
+ title: str(row.title),
108
+ command: str(row.command) || str(row.command2),
109
+ filePath: str(row.filePath) || str(row.filePath2),
110
+ pattern: str(row.pattern) || str(row.pattern2),
111
+ description: str(row.description) || str(row.description2),
112
+ subagent: str(row.subagent) || str(row.category),
113
+ }),
114
+ status,
115
+ startedAt,
116
+ endedAt,
117
+ durationMs,
118
+ })
119
+ if (out.length >= limit) break
120
+ }
121
+ return out
122
+ }
123
+
124
+ function listToolRows(db: SqlDb, where: string, params: string[], limit: number): ToolEventRow[] {
125
+ const candidateRows = db.all<{ id: string }>(
126
+ `SELECT id
127
+ FROM part
128
+ WHERE ${where}
129
+ ORDER BY time_created DESC
130
+ LIMIT ${TOOL_SCAN}`,
131
+ ...params,
132
+ )
133
+ const ids = candidateRows.map((r) => String(r.id))
134
+ if (ids.length === 0) return []
135
+ const saturated = ids.length === TOOL_SCAN
136
+
137
+ const placeholders = ids.map(() => "?").join(",")
138
+ const rows = db.all<ToolEventRow>(
139
+ `SELECT ${toolColumns()}
140
+ FROM part
141
+ WHERE id IN (${placeholders})
142
+ AND json_extract(data,'$.type') = '${PART_TYPE_TOOL}'
143
+ ORDER BY time_created DESC
144
+ LIMIT ${limit}`,
145
+ ...ids,
146
+ )
147
+
148
+ if (saturated && rows.length < limit) {
149
+ return db.all<ToolEventRow>(
150
+ `SELECT ${toolColumns()}
151
+ FROM part
152
+ WHERE ${where}
153
+ AND json_extract(data,'$.type') = '${PART_TYPE_TOOL}'
154
+ ORDER BY time_created DESC
155
+ LIMIT ${TOOL_SCAN}`,
156
+ ...params,
157
+ )
158
+ }
159
+ return rows
160
+ }
161
+
162
+ /** Newest tool parts of one session — the Current tab feed. */
163
+ export function listToolEvents(db: SqlDb, sessionId: string, limit = TOOL_ROWS): ToolView[] {
164
+ return toolViewsFromRows(listToolRows(db, "session_id = ?", [sessionId], limit), limit)
165
+ }
166
+
167
+ /** Newest tool parts across the given sessions — the Sessions tab feed. */
168
+ export function listRecentToolEvents(db: SqlDb, sessionIds: string[], limit = TOOL_ROWS): ToolView[] {
169
+ const clean = uniqueIds(sessionIds)
170
+ if (clean.length === 0) return []
171
+ const placeholders = clean.map(() => "?").join(",")
172
+ return toolViewsFromRows(listToolRows(db, `session_id IN (${placeholders})`, clean, limit), limit)
173
+ }
174
+
175
+ export function mergeTools(
176
+ dbTools: ToolView[],
177
+ live: Record<string, ToolHit>,
178
+ now: number,
179
+ limit: number,
180
+ ): ToolView[] {
181
+ // DB rows are keyed by the part id (`prt_…`) but carry the callID (`call_…`);
182
+ // live events reference only the callID. Key both sides by callID so a live
183
+ // hit lands on the same slot as its DB row, or the same call renders twice.
184
+ // A live hit fills in a running start it saw first, but once the DB row has
185
+ // the real endedAt/duration, the live event must not clobber them — the panel
186
+ // sorts finished calls by endedAt, and `now` would keep reordering them.
187
+ const byId = new Map<string, ToolView>()
188
+ const byCall = new Map<string, string>()
189
+ for (const t of dbTools) {
190
+ const key = t.callId || t.id
191
+ byId.set(key, t)
192
+ if (t.callId && t.callId !== t.id) byCall.set(t.id, key)
193
+ }
194
+ for (const hit of Object.values(live)) {
195
+ const key = byCall.get(hit.id) ?? hit.id
196
+ const prev = byId.get(key)
197
+ if (prev && (prev.status === TOOL_STATUS_COMPLETED || prev.status === TOOL_STATUS_ERROR) && hit.status === TOOL_STATUS_RUNNING) {
198
+ continue
199
+ }
200
+ byId.set(key, {
201
+ id: prev?.id ?? hit.id,
202
+ callId: prev?.callId ?? null,
203
+ name: preferToolLabel(hit.name, prev?.name),
204
+ tool: prev?.tool || "tool",
205
+ status: hit.status,
206
+ startedAt: prev?.startedAt ?? now,
207
+ endedAt: hit.status === TOOL_STATUS_RUNNING ? null : (prev?.endedAt ?? now),
208
+ durationMs:
209
+ hit.status === TOOL_STATUS_RUNNING
210
+ ? null
211
+ : prev?.durationMs ?? (prev?.startedAt != null ? Math.max(0, now - prev.startedAt) : null),
212
+ })
213
+ }
214
+ return [...byId.values()]
215
+ .sort((a, b) => {
216
+ const ar = a.status === TOOL_STATUS_RUNNING || a.status === TOOL_STATUS_PENDING ? 0 : 1
217
+ const br = b.status === TOOL_STATUS_RUNNING || b.status === TOOL_STATUS_PENDING ? 0 : 1
218
+ if (ar !== br) return ar - br
219
+ const at = ar === 0 ? (a.startedAt ?? 0) : (a.endedAt ?? a.startedAt ?? 0)
220
+ const bt = br === 0 ? (b.startedAt ?? 0) : (b.endedAt ?? b.startedAt ?? 0)
221
+ return bt - at
222
+ })
223
+ .slice(0, limit)
224
+ }
@@ -1,14 +1,14 @@
1
- /**
2
- * pware.oc.perf
3
- *
4
- * Turn-timing analysis: reader + TUI view.
5
- */
6
- export * from "./pware.oc.perf.reader.js"
7
- export * from "./pware.oc.perf.self.js"
8
- export * from "./pware.oc.perf.charts.js"
9
- export * from "./pware.oc.perf.realtime.js"
10
- export * from "./pware.oc.perf.realtimeBlock.js"
11
- export * from "./pware.oc.perf.realtimeTimeline.js"
12
- export * from "./pware.oc.perf.realtimeSampler.js"
13
- export * from "./pware.oc.perf.realtimeCpuRam.js"
14
- export * from "./pware.oc.perf.view.js"
1
+ /**
2
+ * pware.oc.perf
3
+ *
4
+ * Turn-timing analysis: reader + TUI view.
5
+ */
6
+ export * from "./pware.oc.perf.reader.js"
7
+ export * from "./pware.oc.perf.self.js"
8
+ export * from "./pware.oc.perf.charts.js"
9
+ export * from "./pware.oc.perf.realtime.js"
10
+ export * from "./pware.oc.perf.realtimeBlock.js"
11
+ export * from "./pware.oc.perf.realtimeTimeline.js"
12
+ export * from "./pware.oc.perf.realtimeSampler.js"
13
+ export * from "./pware.oc.perf.realtimeCpuRam.js"
14
+ export * from "./pware.oc.perf.view.js"
@@ -1,15 +1,15 @@
1
- declare module "asciichart" {
2
- export function plot(
3
- series: number[] | number[][],
4
- config?: {
5
- min?: number
6
- max?: number
7
- offset?: number
8
- padding?: string
9
- height?: number
10
- colors?: string[]
11
- symbols?: string[]
12
- format?: (x: number, i: number) => string
13
- },
14
- ): string
15
- }
1
+ declare module "asciichart" {
2
+ export function plot(
3
+ series: number[] | number[][],
4
+ config?: {
5
+ min?: number
6
+ max?: number
7
+ offset?: number
8
+ padding?: string
9
+ height?: number
10
+ colors?: string[]
11
+ symbols?: string[]
12
+ format?: (x: number, i: number) => string
13
+ },
14
+ ): string
15
+ }