opencode-log 0.3.0__py3-none-any.whl

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 (35) hide show
  1. opencode_log/__init__.py +3 -0
  2. opencode_log/cache.py +240 -0
  3. opencode_log/cli.py +565 -0
  4. opencode_log/markdown.py +197 -0
  5. opencode_log/models.py +131 -0
  6. opencode_log/normalizer.py +146 -0
  7. opencode_log/render.py +360 -0
  8. opencode_log/storage.py +271 -0
  9. opencode_log/templates/combined.html +345 -0
  10. opencode_log/templates/components/base_styles.css +126 -0
  11. opencode_log/templates/components/edit_diff_styles.css +76 -0
  12. opencode_log/templates/components/filter_styles.css +168 -0
  13. opencode_log/templates/components/global_styles.css +237 -0
  14. opencode_log/templates/components/message_styles.css +1057 -0
  15. opencode_log/templates/components/page_nav_styles.css +79 -0
  16. opencode_log/templates/components/project_card_styles.css +138 -0
  17. opencode_log/templates/components/pygments_styles.css +218 -0
  18. opencode_log/templates/components/search.html +774 -0
  19. opencode_log/templates/components/search_inline.html +29 -0
  20. opencode_log/templates/components/search_inline_script.html +3 -0
  21. opencode_log/templates/components/search_results_panel.html +10 -0
  22. opencode_log/templates/components/search_styles.css +371 -0
  23. opencode_log/templates/components/session_nav.html +39 -0
  24. opencode_log/templates/components/session_nav_styles.css +106 -0
  25. opencode_log/templates/components/timeline.html +493 -0
  26. opencode_log/templates/components/timeline_styles.css +151 -0
  27. opencode_log/templates/components/timezone_converter.js +115 -0
  28. opencode_log/templates/components/todo_styles.css +186 -0
  29. opencode_log/templates/index.html +308 -0
  30. opencode_log/templates/transcript.html +372 -0
  31. opencode_log-0.3.0.dist-info/METADATA +519 -0
  32. opencode_log-0.3.0.dist-info/RECORD +35 -0
  33. opencode_log-0.3.0.dist-info/WHEEL +4 -0
  34. opencode_log-0.3.0.dist-info/entry_points.txt +2 -0
  35. opencode_log-0.3.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,29 @@
1
+ <!-- Inline Search Component for Filter Toolbar -->
2
+ <div id="searchContainer" class="search-inline search-container">
3
+ <div class="search-input-wrapper">
4
+ <input type="text"
5
+ id="searchInput"
6
+ class="search-input"
7
+ placeholder="Search conversations... (Ctrl+F)"
8
+ autocomplete="off">
9
+ <button id="searchClear" class="search-clear" title="Clear search">✕</button>
10
+ </div>
11
+
12
+ <div id="searchResultsInfo" class="search-results-info">
13
+ <div class="search-navigation">
14
+ <span id="searchResultCount">No results</span>
15
+ <button id="searchPrev" class="search-nav-btn" disabled title="Previous match (Shift+F3)">↑</button>
16
+ <button id="searchNext" class="search-nav-btn" disabled title="Next match (F3)">↓</button>
17
+ </div>
18
+ <div class="search-options-inline">
19
+ <label class="search-option-inline">
20
+ <input type="checkbox" id="searchRegex">
21
+ <span>Regex</span>
22
+ </label>
23
+ <label class="search-option-inline">
24
+ <input type="checkbox" id="searchInFiltered" checked>
25
+ <span>Visible only</span>
26
+ </label>
27
+ </div>
28
+ </div>
29
+ </div>
@@ -0,0 +1,3 @@
1
+ <script>
2
+ {% include 'components/search.html' %}
3
+ </script>
@@ -0,0 +1,10 @@
1
+ <!-- Search Results Panel (for index page) -->
2
+ <div id="searchResultsPanel" class="search-results-panel">
3
+ <div class="search-results-header">
4
+ <span class="search-results-title">Search Results</span>
5
+ <button id="searchResultsClose" class="search-close-btn" title="Close">✕</button>
6
+ </div>
7
+ <div id="searchResultsContent">
8
+ <!-- Results will be dynamically inserted here -->
9
+ </div>
10
+ </div>
@@ -0,0 +1,371 @@
1
+ /* Search Bar Styles */
2
+ .search-container {
3
+ position: relative;
4
+ width: 100%;
5
+ }
6
+
7
+ /* Keyboard shortcut hint */
8
+ .search-hint {
9
+ position: absolute;
10
+ right: 45px;
11
+ top: 50%;
12
+ transform: translateY(-50%);
13
+ color: var(--text-muted);
14
+ font-size: 0.75em;
15
+ pointer-events: none;
16
+ transition: opacity 0.2s;
17
+ }
18
+
19
+ .search-hint.hidden {
20
+ opacity: 0;
21
+ visibility: hidden;
22
+ }
23
+
24
+ /* Inline Search for Filter Toolbar */
25
+ .search-inline {
26
+ width: 100%;
27
+ margin-bottom: 12px;
28
+ }
29
+
30
+ /* In filter toolbar mode, search is always visible when toolbar is visible */
31
+ .filter-toolbar:not(.visible) .search-container {
32
+ display: none;
33
+ }
34
+
35
+ .search-input-wrapper {
36
+ position: relative;
37
+ display: flex;
38
+ align-items: center;
39
+ gap: 10px;
40
+ }
41
+
42
+ .search-input {
43
+ width: 100%;
44
+ padding: 8px 40px 8px 12px;
45
+ background: #ffffff88;
46
+ border: 1px solid #dee2e6;
47
+ border-radius: 20px;
48
+ color: var(--text-secondary);
49
+ font-size: 0.85em;
50
+ font-family: inherit;
51
+ transition: all 0.2s;
52
+ }
53
+
54
+ .search-input:focus {
55
+ outline: none;
56
+ border-color: var(--system-warning-color);
57
+ background: #ffffff99;
58
+ box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.2);
59
+ }
60
+
61
+ .search-input::placeholder {
62
+ color: var(--text-muted);
63
+ }
64
+
65
+ .search-clear {
66
+ position: absolute;
67
+ right: 15px;
68
+ background: none;
69
+ border: none;
70
+ color: var(--text-muted);
71
+ cursor: pointer;
72
+ font-size: 18px;
73
+ padding: 5px;
74
+ display: none;
75
+ border-radius: 50%;
76
+ transition: all 0.2s;
77
+ }
78
+
79
+ .search-clear:hover {
80
+ color: var(--text-primary);
81
+ background: var(--white-dimmed);
82
+ }
83
+
84
+ .search-clear.visible {
85
+ display: block;
86
+ }
87
+
88
+ /* Search Results Counter */
89
+ .search-results-info {
90
+ margin-top: 8px;
91
+ font-size: 12px;
92
+ color: var(--text-muted);
93
+ display: none;
94
+ }
95
+
96
+ .search-results-info.visible {
97
+ display: flex;
98
+ justify-content: space-between;
99
+ align-items: center;
100
+ gap: 12px;
101
+ }
102
+
103
+ .search-navigation {
104
+ display: flex;
105
+ gap: 5px;
106
+ align-items: center;
107
+ }
108
+
109
+ .search-options-inline {
110
+ display: flex;
111
+ gap: 12px;
112
+ font-size: 0.75em;
113
+ }
114
+
115
+ .search-option-inline {
116
+ display: flex;
117
+ align-items: center;
118
+ gap: 4px;
119
+ cursor: pointer;
120
+ color: var(--text-muted);
121
+ }
122
+
123
+ .search-option-inline:hover {
124
+ color: var(--text-primary);
125
+ }
126
+
127
+ .search-option-inline input[type="checkbox"] {
128
+ cursor: pointer;
129
+ margin: 0;
130
+ }
131
+
132
+ .search-nav-btn {
133
+ background: #ffffff88;
134
+ border: 1px solid #dee2e6;
135
+ border-radius: 4px;
136
+ color: var(--text-primary);
137
+ padding: 4px 8px;
138
+ cursor: pointer;
139
+ font-size: 12px;
140
+ transition: all 0.2s;
141
+ }
142
+
143
+ .search-nav-btn:hover:not(:disabled) {
144
+ background: #ffffff99;
145
+ border-color: var(--system-warning-color);
146
+ transform: translateY(-1px);
147
+ }
148
+
149
+ .search-nav-btn:disabled {
150
+ opacity: 0.5;
151
+ cursor: not-allowed;
152
+ }
153
+
154
+ /* Search Match Highlighting */
155
+ .search-highlight {
156
+ background-color: #ffeb3b;
157
+ color: #000;
158
+ padding: 0 2px;
159
+ border-radius: 2px;
160
+ }
161
+
162
+ .search-highlight.current {
163
+ background-color: #ff9800;
164
+ color: #000;
165
+ }
166
+
167
+ /* Search Options */
168
+ .search-options {
169
+ margin-top: 8px;
170
+ display: flex;
171
+ gap: 12px;
172
+ font-size: 0.75em;
173
+ }
174
+
175
+ .search-option {
176
+ display: flex;
177
+ align-items: center;
178
+ gap: 5px;
179
+ color: var(--text-muted);
180
+ transition: color 0.2s;
181
+ }
182
+
183
+ .search-option input[type="checkbox"] {
184
+ cursor: pointer;
185
+ accent-color: #2196f3;
186
+ }
187
+
188
+ .search-option label {
189
+ cursor: pointer;
190
+ user-select: none;
191
+ }
192
+
193
+ .search-option:hover {
194
+ color: var(--text-primary);
195
+ }
196
+
197
+ /* Index Page Search Results */
198
+ .search-results-panel {
199
+ margin: 20px 0;
200
+ padding: 20px;
201
+ background-color: var(--white-dimmed);
202
+ border-radius: 8px;
203
+ box-shadow: -7px -7px 10px #eeeeee44, 7px 7px 10px #00000011;
204
+ border-left: var(--white-dimmed) 1px solid;
205
+ border-top: var(--white-dimmed) 1px solid;
206
+ border-bottom: #00000017 1px solid;
207
+ border-right: #00000017 1px solid;
208
+ display: none;
209
+ }
210
+
211
+ .search-results-panel.visible {
212
+ display: block;
213
+ }
214
+
215
+ .search-results-header {
216
+ display: flex;
217
+ justify-content: space-between;
218
+ align-items: center;
219
+ margin-bottom: 15px;
220
+ padding-bottom: 10px;
221
+ border-bottom: 1px solid #dee2e6;
222
+ }
223
+
224
+ .search-results-title {
225
+ font-size: 16px;
226
+ font-weight: 600;
227
+ color: #2c3e50;
228
+ }
229
+
230
+ .search-close-btn {
231
+ background: none;
232
+ border: none;
233
+ color: var(--text-muted);
234
+ cursor: pointer;
235
+ font-size: 20px;
236
+ padding: 5px;
237
+ border-radius: 50%;
238
+ transition: all 0.2s;
239
+ }
240
+
241
+ .search-close-btn:hover {
242
+ color: var(--text-primary);
243
+ background: var(--white-dimmed);
244
+ }
245
+
246
+ .search-result-group {
247
+ margin-bottom: 20px;
248
+ }
249
+
250
+ .search-result-group-title {
251
+ font-size: 14px;
252
+ font-weight: 600;
253
+ color: #2196f3;
254
+ margin-bottom: 10px;
255
+ display: flex;
256
+ align-items: center;
257
+ gap: 8px;
258
+ }
259
+
260
+ .search-result-count {
261
+ background: #ffffff88;
262
+ color: var(--text-muted);
263
+ padding: 2px 8px;
264
+ border-radius: 12px;
265
+ font-size: 11px;
266
+ font-weight: normal;
267
+ border: 1px solid #dee2e6;
268
+ }
269
+
270
+ .search-result-item {
271
+ padding: 12px;
272
+ margin-bottom: 8px;
273
+ background-color: #ffffff88;
274
+ border-radius: 6px;
275
+ cursor: pointer;
276
+ transition: all 0.2s;
277
+ box-shadow: -3px -3px 5px #eeeeee22, 3px 3px 5px #00000008;
278
+ border-left: #ffffff44 1px solid;
279
+ border-top: #ffffff44 1px solid;
280
+ border-bottom: #00000012 1px solid;
281
+ border-right: #00000012 1px solid;
282
+ }
283
+
284
+ .search-result-item:hover {
285
+ background-color: #ffffff99;
286
+ transform: translateY(-1px);
287
+ box-shadow: -5px -5px 8px #eeeeee33, 5px 5px 8px #00000012;
288
+ }
289
+
290
+ .search-result-item a {
291
+ text-decoration: none;
292
+ color: inherit;
293
+ display: block;
294
+ }
295
+
296
+ .search-result-session {
297
+ font-size: 12px;
298
+ color: var(--text-muted);
299
+ margin-bottom: 5px;
300
+ font-weight: 500;
301
+ }
302
+
303
+ .search-result-excerpt {
304
+ font-size: 13px;
305
+ color: var(--text-secondary);
306
+ line-height: 1.4;
307
+ }
308
+
309
+ .search-result-excerpt .search-highlight {
310
+ font-weight: 600;
311
+ background-color: #ffeb3b;
312
+ color: #000;
313
+ padding: 0 2px;
314
+ border-radius: 2px;
315
+ }
316
+
317
+ .search-result-meta {
318
+ margin-top: 8px;
319
+ font-size: 11px;
320
+ color: var(--text-muted);
321
+ display: flex;
322
+ gap: 15px;
323
+ padding-top: 5px;
324
+ border-top: 1px solid #dee2e611;
325
+ }
326
+
327
+ /* Removed floating search button - now integrated in filter toolbar */
328
+
329
+ /* No results message */
330
+ .search-no-results {
331
+ text-align: center;
332
+ padding: 30px;
333
+ color: var(--text-muted);
334
+ font-size: 14px;
335
+ background-color: #ffffff44;
336
+ border-radius: 6px;
337
+ margin: 10px 0;
338
+ }
339
+
340
+ /* Loading indicator */
341
+ .search-loading {
342
+ text-align: center;
343
+ padding: 20px;
344
+ color: var(--text-muted);
345
+ background-color: #ffffff44;
346
+ border-radius: 6px;
347
+ }
348
+
349
+ .search-loading::after {
350
+ content: '...';
351
+ animation: dots 1.5s infinite;
352
+ }
353
+
354
+ @keyframes dots {
355
+ 0%, 20% { content: '.'; }
356
+ 40% { content: '..'; }
357
+ 60%, 100% { content: '...'; }
358
+ }
359
+
360
+ /* Keyboard shortcut hint */
361
+
362
+ /* Responsive adjustments */
363
+ @media (max-width: 768px) {
364
+ .search-input {
365
+ font-size: 0.8em;
366
+ }
367
+
368
+ .search-options {
369
+ font-size: 0.7em;
370
+ }
371
+ }
@@ -0,0 +1,39 @@
1
+ {# Session navigation component - can be used for ToC or expandable navigation #}
2
+ {% macro render_session_nav(sessions, mode="toc", link_prefix="") %}
3
+ {% if sessions and sessions|length > 0 %}
4
+ <div class='navigation'>
5
+ {% if mode == "toc" %}
6
+ <h2>Sessions</h2>
7
+ <span class='nav-hint'>↓ Click a box below to scroll down to the corresponding session</span>
8
+ {% elif mode == "expandable" %}
9
+ <h2>Session Navigation</h2>
10
+ <span class='nav-hint'>↓ Click any to open individual session page</span>
11
+ {% endif %}
12
+
13
+ <div class='session-nav'>
14
+ {% for session in sessions %}
15
+ <a href='{{ link_prefix }}{% if mode == "expandable" %}session-{{ session.id }}.html{% else %}#msg-d-{{ session.message_index }}{% endif %}'
16
+ class='session-link'>
17
+ <div class='session-link-title'>
18
+ {% if session.summary %}
19
+ {{ session.summary }} •
20
+ {% endif %}
21
+ {{ session.id[:8] }}
22
+ </div>
23
+ <div class='session-link-meta'>
24
+ <span class="timestamp"{% if session.first_timestamp %} data-timestamp="{{ session.first_timestamp }}"{% endif %}{% if session.last_timestamp and session.last_timestamp != session.first_timestamp %} data-timestamp-end="{{ session.last_timestamp }}"{% endif %}>{{ session.timestamp_range }}</span> • {{ session.message_count }} messages
25
+ {% if session.token_summary %}
26
+ <br>{{ session.token_summary }}
27
+ {% endif %}
28
+ </div>
29
+ {% if session.first_user_message %}
30
+ <pre class='session-preview'>
31
+ {{- session.first_user_message|e -}}
32
+ </pre>
33
+ {% endif %}
34
+ </a>
35
+ {% endfor %}
36
+ </div>
37
+ </div>
38
+ {% endif %}
39
+ {% endmacro %}
@@ -0,0 +1,106 @@
1
+ /* Session navigation styles */
2
+ .navigation {
3
+ background-color: var(--bg-neutral);
4
+ border-radius: 8px;
5
+ padding: 16px;
6
+ margin-bottom: 24px;
7
+ box-shadow: -7px -7px 10px #eeeeee44, 7px 7px 10px #00000011;
8
+ border-left: var(--white-dimmed) 1px solid;
9
+ border-top: var(--white-dimmed) 1px solid;
10
+ border-bottom: #00000017 1px solid;
11
+ border-right: #00000017 1px solid;
12
+ }
13
+
14
+ .navigation h2 {
15
+ margin: 0 0 12px 0;
16
+ font-size: 1.2em;
17
+ color: var(--text-secondary);
18
+ }
19
+
20
+ .session-nav {
21
+ margin-top: 1em;
22
+ display: grid;
23
+ gap: 8px;
24
+ }
25
+
26
+ .session-link {
27
+ padding: 8px 12px;
28
+ background-color: var(--white-dimmed);
29
+ border: 1px solid #dee2e6;
30
+ border-radius: 4px;
31
+ text-decoration: none;
32
+ color: var(--text-secondary);
33
+ transition: background-color 0.2s;
34
+ }
35
+
36
+ .session-link:hover {
37
+ background-color: #ffffff99;
38
+ }
39
+
40
+ .session-link-title {
41
+ font-weight: 600;
42
+ font-size: 0.9em;
43
+ }
44
+
45
+ .session-link-meta {
46
+ font-size: 0.8em;
47
+ color: #6c757d;
48
+ margin-top: 2px;
49
+ }
50
+
51
+ /* Project-specific session navigation */
52
+ .project-sessions {
53
+ margin-top: 15px;
54
+ border-top: 1px solid #dee2e6;
55
+ padding-top: 15px;
56
+ }
57
+
58
+ .project-sessions h4 {
59
+ margin: 0 0 10px 0;
60
+ font-size: 0.9em;
61
+ color: var(--text-secondary);
62
+ font-weight: 600;
63
+ }
64
+
65
+ .project-sessions .session-link {
66
+ padding: 6px 8px;
67
+ font-size: 0.8em;
68
+ margin-bottom: 4px;
69
+ }
70
+
71
+ .project-sessions .session-link-title {
72
+ font-size: 0.85em;
73
+ }
74
+
75
+ .project-sessions .session-link-meta {
76
+ font-size: 0.75em;
77
+ }
78
+
79
+ /* Combined transcript link */
80
+ .combined-transcript-link {
81
+ display: inline-block;
82
+ padding: 8px 12px;
83
+ background-color: var(--white-dimmed);
84
+ border: 1px solid #dee2e6;
85
+ border-radius: 4px;
86
+ text-decoration: none;
87
+ color: var(--text-secondary);
88
+ font-weight: 500;
89
+ transition: background-color 0.2s;
90
+ }
91
+
92
+ .combined-transcript-link:hover {
93
+ background-color: #ffffff99;
94
+ text-decoration: none;
95
+ }
96
+
97
+ /* Navigation hints */
98
+ .nav-hint {
99
+ font-size: 0.75em;
100
+ }
101
+
102
+ /* Session preview styling */
103
+ .session-preview {
104
+ font-size: 0.75em;
105
+ line-height: 1.3;
106
+ }