cowork-dash 0.2.0__py3-none-any.whl → 0.2.2__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.
@@ -156,6 +156,15 @@ code, pre, .mono {
156
156
  line-height: 1.6;
157
157
  }
158
158
 
159
+ /* Tighter spacing for consecutive AI text blocks */
160
+ #chat-messages .ai-text-block p {
161
+ margin: 0;
162
+ }
163
+
164
+ #chat-messages .ai-text-block p:last-child {
165
+ margin-bottom: 0;
166
+ }
167
+
159
168
  #chat-messages ul, #chat-messages ol {
160
169
  margin: 6px 0;
161
170
  padding-left: 20px;
@@ -1158,3 +1167,14 @@ details.display-inline-container[open] > .display-inline-summary::before {
1158
1167
  text-overflow: ellipsis;
1159
1168
  white-space: nowrap;
1160
1169
  }
1170
+
1171
+ /* Fullscreen button for HTML/PDF preview */
1172
+ .fullscreen-btn {
1173
+ opacity: 0.7;
1174
+ transition: opacity 0.15s ease, background-color 0.15s ease;
1175
+ }
1176
+
1177
+ .fullscreen-btn:hover {
1178
+ opacity: 1;
1179
+ background-color: rgba(255,255,255,1) !important;
1180
+ }
cowork_dash/components.py CHANGED
@@ -82,20 +82,110 @@ def format_loading(colors: Dict):
82
82
 
83
83
 
84
84
  def format_thinking(thinking_text: str, colors: Dict):
85
- """Format thinking as an inline subordinate message."""
85
+ """Format thinking as an inline subordinate message (non-collapsible)."""
86
86
  if not thinking_text:
87
87
  return None
88
88
 
89
- return html.Details([
90
- html.Summary("Thinking", className="details-summary details-summary-thinking"),
91
- html.Div(thinking_text, className="details-content details-content-thinking", style={
89
+ return html.Div([
90
+ html.Div("Thinking", style={
91
+ "fontSize": "12px",
92
+ "fontWeight": "500",
93
+ "color": colors.get("thinking", colors.get("text_muted", "#888")),
94
+ "marginBottom": "2px",
95
+ }),
96
+ html.Div(thinking_text, style={
92
97
  "whiteSpace": "pre-wrap",
98
+ "fontSize": "13px",
99
+ "color": colors.get("text_muted", "#666"),
100
+ "paddingLeft": "8px",
101
+ "borderLeft": f"2px solid {colors.get('thinking', '#7c4dff')}",
93
102
  })
94
- ], open=True, className="chat-details", style={
103
+ ], style={
95
104
  "marginBottom": "4px",
96
105
  })
97
106
 
98
107
 
108
+ def format_ai_text(text: str, colors: Dict, is_new: bool = False):
109
+ """Format AI text response (without the full message wrapper).
110
+
111
+ This is used when rendering ordered content items where thinking
112
+ and text are interleaved.
113
+ """
114
+ if not text:
115
+ return None
116
+
117
+ return dcc.Markdown(
118
+ text,
119
+ className="ai-text-block",
120
+ style={
121
+ "fontSize": "15px",
122
+ "lineHeight": "1.5",
123
+ "margin": "0",
124
+ "padding": "0",
125
+ }
126
+ )
127
+
128
+
129
+ def render_ordered_content_items(content_items: List[Dict], colors: Dict, styles: Dict = None, response_time: float = None) -> List:
130
+ """Render content items in their original emission order.
131
+
132
+ Args:
133
+ content_items: List of {"type": "text"|"thinking"|"display_inline", "content": ...}
134
+ colors: Color scheme dict
135
+ styles: Optional styles dict
136
+ response_time: Optional response time to show after the last text item
137
+
138
+ Returns:
139
+ List of rendered Dash components in order
140
+ """
141
+ if not content_items:
142
+ return []
143
+
144
+ rendered = []
145
+ last_text_index = None
146
+
147
+ # Find the last text item index for response time display
148
+ for i, item in enumerate(content_items):
149
+ if item.get("type") == "text":
150
+ last_text_index = i
151
+
152
+ for i, item in enumerate(content_items):
153
+ item_type = item.get("type")
154
+ content = item.get("content", "")
155
+
156
+ if not content:
157
+ continue
158
+
159
+ if item_type == "thinking":
160
+ block = format_thinking(content, colors)
161
+ if block:
162
+ rendered.append(block)
163
+ elif item_type == "text":
164
+ # For the last text item, we might want to show response time
165
+ is_last_text = (i == last_text_index)
166
+ block = format_ai_text(content, colors)
167
+ if block:
168
+ rendered.append(block)
169
+ # Add response time after the last text block
170
+ if is_last_text and response_time is not None:
171
+ time_display = f"{response_time:.1f}s" if response_time >= 1 else f"{response_time*1000:.0f}ms"
172
+ rendered.append(html.Span(
173
+ time_display,
174
+ style={
175
+ "fontSize": "11px",
176
+ "color": colors.get("text_muted", "#888"),
177
+ "marginLeft": "4px",
178
+ }
179
+ ))
180
+ elif item_type == "display_inline":
181
+ # content is the full display_inline item dict
182
+ block = render_display_inline_result(content, colors)
183
+ if block:
184
+ rendered.append(block)
185
+
186
+ return rendered
187
+
188
+
99
189
  def format_todos(todos, colors: Dict):
100
190
  """Format todo list. Handles both list format [{"content": ..., "status": ...}] and dict format {task_name: status}."""
101
191
  if not todos:
@@ -201,13 +291,23 @@ def format_tool_call(tool_call: Dict, colors: Dict, is_completed: bool = False):
201
291
 
202
292
  # Format args for display (truncate if too long)
203
293
  args_display = ""
294
+ args_preview = "" # Short preview for header
204
295
  if tool_args:
205
296
  try:
297
+ # Compact JSON for preview (no indentation)
298
+ args_compact = json.dumps(tool_args, separators=(',', ':'))
299
+ if len(args_compact) > 100:
300
+ args_preview = args_compact[:100] + "..."
301
+ else:
302
+ args_preview = args_compact
303
+
304
+ # Full JSON for expanded view
206
305
  args_str = json.dumps(tool_args, indent=2)
207
306
  if len(args_str) > 500:
208
307
  args_str = args_str[:500] + "..."
209
308
  args_display = args_str
210
309
  except:
310
+ args_preview = str(tool_args)[:100]
211
311
  args_display = str(tool_args)[:500]
212
312
 
213
313
  # Build inner content (shown when expanded)
@@ -235,11 +335,14 @@ def format_tool_call(tool_call: Dict, colors: Dict, is_completed: bool = False):
235
335
  html.Pre(result_display, className="tool-call-result")
236
336
  ]))
237
337
 
338
+ # Build header text: tool_name(args_preview)
339
+ header_text = f"{tool_name}({args_preview})" if args_preview else tool_name
340
+
238
341
  # Wrap entire tool call in a details element
239
342
  return html.Details([
240
343
  html.Summary([
241
344
  html.Span(className="tool-call-status-dot"),
242
- html.Span(tool_name, className="tool-call-name"),
345
+ html.Span(header_text, className="tool-call-name"),
243
346
  ], className="tool-call-header"),
244
347
  html.Div(inner_children, className="tool-call-body") if inner_children else None
245
348
  ], className=f"tool-call {status_class}")
@@ -349,24 +452,53 @@ def render_display_inline_result(result: Dict, colors: Dict) -> html.Div:
349
452
  ])
350
453
 
351
454
  elif display_type == "html":
352
- # Show preview thumbnail with expand button
353
- preview_content = preview or data
354
- if len(str(preview_content)) > 500:
355
- preview_content = str(preview_content)[:500] + "..."
356
-
357
- content_element = html.Details([
358
- html.Summary("HTML Content", className="tool-call-summary"),
359
- html.Iframe(
360
- srcDoc=data,
455
+ # Show HTML preview directly in iframe (like PDF)
456
+ if not data:
457
+ content_element = html.Div(
458
+ "Error: HTML content is empty or missing",
459
+ style={"color": "red", "padding": "10px"}
460
+ )
461
+ else:
462
+ # Create fullscreen button
463
+ fullscreen_btn = html.Button(
464
+ DashIconify(icon="mdi:fullscreen", width=18),
465
+ id={"type": "fullscreen-btn", "index": item_id},
466
+ className="fullscreen-btn",
467
+ title="View fullscreen",
361
468
  style={
362
- "width": "100%",
363
- "height": "300px",
469
+ "position": "absolute",
470
+ "top": "8px",
471
+ "right": "8px",
472
+ "background": "rgba(255,255,255,0.9)",
364
473
  "border": "1px solid #ddd",
365
- "borderRadius": "5px",
366
- "backgroundColor": "white",
474
+ "borderRadius": "4px",
475
+ "cursor": "pointer",
476
+ "padding": "4px 6px",
477
+ "display": "flex",
478
+ "alignItems": "center",
479
+ "justifyContent": "center",
480
+ "zIndex": "10",
367
481
  }
368
482
  )
369
- ], className="display-inline-html")
483
+ # Store data for fullscreen modal
484
+ fullscreen_store = dcc.Store(
485
+ id={"type": "fullscreen-data", "index": item_id},
486
+ data={"type": "html", "content": data, "title": title or "HTML Preview"}
487
+ )
488
+ content_element = html.Div([
489
+ fullscreen_btn,
490
+ html.Iframe(
491
+ srcDoc=data,
492
+ style={
493
+ "width": "100%",
494
+ "height": "400px",
495
+ "border": "none",
496
+ "borderRadius": "5px",
497
+ "backgroundColor": "white",
498
+ }
499
+ ),
500
+ fullscreen_store,
501
+ ], style={"position": "relative"})
370
502
 
371
503
  elif display_type == "pdf":
372
504
  mime_type = result.get("mime_type", "application/pdf")
@@ -378,16 +510,46 @@ def render_display_inline_result(result: Dict, colors: Dict) -> html.Div:
378
510
  )
379
511
  else:
380
512
  data_url = f"data:{mime_type};base64,{data}"
381
- # Use iframe instead of embed for better browser compatibility
382
- content_element = html.Iframe(
383
- src=data_url,
513
+ # Create fullscreen button
514
+ fullscreen_btn = html.Button(
515
+ DashIconify(icon="mdi:fullscreen", width=18),
516
+ id={"type": "fullscreen-btn", "index": item_id},
517
+ className="fullscreen-btn",
518
+ title="View fullscreen",
384
519
  style={
385
- "width": "100%",
386
- "height": "400px",
387
- "border": "none",
388
- "borderRadius": "5px",
520
+ "position": "absolute",
521
+ "top": "8px",
522
+ "right": "8px",
523
+ "background": "rgba(255,255,255,0.9)",
524
+ "border": "1px solid #ddd",
525
+ "borderRadius": "4px",
526
+ "cursor": "pointer",
527
+ "padding": "4px 6px",
528
+ "display": "flex",
529
+ "alignItems": "center",
530
+ "justifyContent": "center",
531
+ "zIndex": "10",
389
532
  }
390
533
  )
534
+ # Store data for fullscreen modal
535
+ fullscreen_store = dcc.Store(
536
+ id={"type": "fullscreen-data", "index": item_id},
537
+ data={"type": "pdf", "content": data_url, "title": title or "PDF Preview"}
538
+ )
539
+ # Use iframe instead of embed for better browser compatibility
540
+ content_element = html.Div([
541
+ fullscreen_btn,
542
+ html.Iframe(
543
+ src=data_url,
544
+ style={
545
+ "width": "100%",
546
+ "height": "400px",
547
+ "border": "none",
548
+ "borderRadius": "5px",
549
+ }
550
+ ),
551
+ fullscreen_store,
552
+ ], style={"position": "relative"})
391
553
 
392
554
  elif display_type == "json":
393
555
  json_str = json.dumps(data, indent=2) if isinstance(data, (dict, list)) else str(data)
@@ -477,16 +639,38 @@ def render_display_inline_result(result: Dict, colors: Dict) -> html.Div:
477
639
  }
478
640
  )
479
641
 
642
+ # Create download button
643
+ download_btn = html.Button(
644
+ DashIconify(icon="mdi:download", width=16),
645
+ id={"type": "download-display-btn", "index": item_id},
646
+ className="download-display-btn",
647
+ title="Download",
648
+ style={
649
+ "background": "transparent",
650
+ "border": "none",
651
+ "cursor": "pointer",
652
+ "padding": "4px",
653
+ "borderRadius": "4px",
654
+ "display": "flex",
655
+ "alignItems": "center",
656
+ "justifyContent": "center",
657
+ "marginLeft": "4px",
658
+ }
659
+ )
660
+
480
661
  # Store the result data in a hidden div for the callback to retrieve
481
662
  result_store = dcc.Store(
482
663
  id={"type": "display-inline-data", "index": item_id},
483
664
  data=result
484
665
  )
485
666
 
486
- # Build summary with text and button
667
+ # Build summary with text and buttons
487
668
  summary_content = html.Div([
488
669
  html.Span(summary_text, className="display-inline-summary-text"),
489
- add_to_canvas_btn,
670
+ html.Div([
671
+ add_to_canvas_btn,
672
+ download_btn,
673
+ ], style={"display": "flex", "alignItems": "center"}),
490
674
  ], className="display-inline-summary-row", style={
491
675
  "display": "flex",
492
676
  "alignItems": "center",
cowork_dash/layout.py CHANGED
@@ -53,6 +53,7 @@ def create_layout(workspace_root, app_title, app_subtitle, colors, styles, agent
53
53
  dcc.Store(id="theme-store", data="light", storage_type="local"),
54
54
  dcc.Store(id="current-workspace-path", data=""), # Relative path from original workspace root
55
55
  dcc.Store(id="collapsed-canvas-items", data=[]), # Track which canvas items are collapsed
56
+ dcc.Store(id="sidebar-collapsed", data=False), # Track if sidebar is collapsed
56
57
  dcc.Download(id="file-download"),
57
58
 
58
59
  # Interval for polling agent updates (disabled by default)
@@ -134,6 +135,22 @@ def create_layout(workspace_root, app_title, app_subtitle, colors, styles, agent
134
135
  opened=False,
135
136
  ),
136
137
 
138
+ # Fullscreen preview modal for HTML/PDF
139
+ dmc.Modal(
140
+ id="fullscreen-preview-modal",
141
+ title="Preview",
142
+ size="100%",
143
+ children=[
144
+ html.Div(id="fullscreen-preview-content", style={"height": "calc(100vh - 120px)"})
145
+ ],
146
+ opened=False,
147
+ styles={
148
+ "content": {"height": "95vh", "maxHeight": "95vh"},
149
+ "body": {"height": "calc(100% - 60px)", "padding": "0"},
150
+ },
151
+ ),
152
+ dcc.Store(id="fullscreen-preview-data", data=None),
153
+
137
154
  html.Div([
138
155
  # Compact Header
139
156
  html.Header([
@@ -264,6 +281,13 @@ def create_layout(workspace_root, app_title, app_subtitle, colors, styles, agent
264
281
  variant="default",
265
282
  size="md",
266
283
  ),
284
+ dmc.ActionIcon(
285
+ DashIconify(icon="mdi:chevron-right", width=18),
286
+ id="collapse-sidebar-btn",
287
+ variant="subtle",
288
+ size="md",
289
+ **{"aria-label": "Collapse sidebar"},
290
+ ),
267
291
  ], id="files-actions", gap=5)
268
292
  ], id="sidebar-header", style={
269
293
  "display": "flex", "justifyContent": "space-between",
@@ -346,6 +370,25 @@ def create_layout(workspace_root, app_title, app_subtitle, colors, styles, agent
346
370
  "background": "var(--mantine-color-body)",
347
371
  "borderLeft": "1px solid var(--mantine-color-default-border)",
348
372
  }),
373
+
374
+ # Expand button (shown when sidebar is collapsed)
375
+ html.Div([
376
+ dmc.ActionIcon(
377
+ DashIconify(icon="mdi:chevron-left", width=18),
378
+ id="expand-sidebar-btn",
379
+ variant="subtle",
380
+ size="md",
381
+ **{"aria-label": "Expand sidebar"},
382
+ ),
383
+ ], id="sidebar-expand-btn", style={
384
+ "display": "none",
385
+ "alignItems": "flex-start",
386
+ "paddingTop": "8px",
387
+ "paddingLeft": "2px",
388
+ "paddingRight": "2px",
389
+ "borderLeft": "1px solid var(--mantine-color-default-border)",
390
+ "background": "var(--mantine-color-body)",
391
+ }),
349
392
  ], id="main-container", style={"display": "flex", "flex": "1", "overflow": "hidden"}),
350
393
  ], id="app-container", style={"display": "flex", "flexDirection": "column", "height": "100vh"})
351
394
  ])
cowork_dash/tools.py CHANGED
@@ -230,37 +230,6 @@ except (ImportError, AttributeError):
230
230
  if VIRTUAL_FS:
231
231
  self._inject_virtual_fs_helpers()
232
232
 
233
- # Inject add_to_canvas function that captures items
234
- def _add_to_canvas_wrapper(content: Any) -> Dict[str, Any]:
235
- """Add content to the canvas for visualization.
236
-
237
- Supports: DataFrames, matplotlib figures, plotly figures,
238
- PIL images, and markdown strings.
239
- """
240
- try:
241
- # Use session's VirtualFilesystem in virtual FS mode, otherwise physical path
242
- if VIRTUAL_FS and self._session_id:
243
- from .virtual_fs import get_session_manager
244
- workspace_root = get_session_manager().get_filesystem(self._session_id)
245
- if workspace_root is None:
246
- raise RuntimeError(f"Session {self._session_id} not found")
247
- else:
248
- workspace_root = WORKSPACE_ROOT
249
-
250
- parsed = parse_canvas_object(content, workspace_root=workspace_root)
251
- self._canvas_items.append(parsed)
252
- return parsed
253
- except Exception as e:
254
- error_result = {
255
- "type": "error",
256
- "data": f"Failed to add to canvas: {str(e)}",
257
- "error": str(e)
258
- }
259
- self._canvas_items.append(error_result)
260
- return error_result
261
-
262
- self._namespace["add_to_canvas"] = _add_to_canvas_wrapper
263
-
264
233
  def _inject_virtual_fs_helpers(self):
265
234
  """Inject virtual filesystem helper functions into the namespace."""
266
235
  from .virtual_fs import get_session_manager
@@ -1089,6 +1058,9 @@ def _display_inline_impl(
1089
1058
  # Handle explicit display_type for strings
1090
1059
  if isinstance(content, str) and display_type:
1091
1060
  if display_type == "html":
1061
+ # Check if it's a file path first
1062
+ if _is_file_path(content, workspace_root):
1063
+ return _process_file_for_display(content, workspace_root, title, "html")
1092
1064
  result["display_type"] = "html"
1093
1065
  result["data"] = content
1094
1066
  result["preview"] = content[:500] + "..." if len(content) > 500 else content
@@ -1098,6 +1070,9 @@ def _display_inline_impl(
1098
1070
  result["data"] = content
1099
1071
  return result
1100
1072
  elif display_type in ("csv", "dataframe"):
1073
+ # Check if it's a file path first
1074
+ if _is_file_path(content, workspace_root):
1075
+ return _process_file_for_display(content, workspace_root, title, "csv")
1101
1076
  # Parse CSV string
1102
1077
  try:
1103
1078
  import pandas as pd
@@ -1109,6 +1084,9 @@ def _display_inline_impl(
1109
1084
  result["error"] = f"Could not parse as CSV: {e}"
1110
1085
  return result
1111
1086
  elif display_type == "json":
1087
+ # Check if it's a file path first
1088
+ if _is_file_path(content, workspace_root):
1089
+ return _process_file_for_display(content, workspace_root, title, "json")
1112
1090
  result["display_type"] = "json"
1113
1091
  try:
1114
1092
  result["data"] = json.loads(content) if isinstance(content, str) else content
@@ -1123,6 +1101,9 @@ def _display_inline_impl(
1123
1101
  result["data"] = content # Assume base64
1124
1102
  return result
1125
1103
  elif display_type == "plotly":
1104
+ # Check if it's a file path first
1105
+ if _is_file_path(content, workspace_root):
1106
+ return _process_file_for_display(content, workspace_root, title, "plotly")
1126
1107
  result["display_type"] = "plotly"
1127
1108
  if isinstance(content, str):
1128
1109
  result["data"] = json.loads(content)
@@ -1406,14 +1387,18 @@ def _process_file_for_display(
1406
1387
  result["error"] = f"Could not parse as CSV: {e}"
1407
1388
  return result
1408
1389
 
1409
- # JSON files (check for Plotly)
1410
- if ext == '.json' or display_type == "json":
1390
+ # JSON files (check for Plotly) or explicit plotly display_type
1391
+ if ext == '.json' or display_type in ("json", "plotly"):
1411
1392
  content, is_text, error = read_file_content(workspace_root, file_path)
1412
1393
  if content:
1413
1394
  try:
1414
1395
  data = json.loads(content)
1415
- # Check if it's Plotly JSON
1416
- if isinstance(data, dict) and 'data' in data and isinstance(data.get('data'), list):
1396
+ # Force plotly if display_type is explicitly set, otherwise auto-detect
1397
+ if display_type == "plotly":
1398
+ result["display_type"] = "plotly"
1399
+ result["data"] = data
1400
+ # Check if it's Plotly JSON (auto-detect)
1401
+ elif isinstance(data, dict) and 'data' in data and isinstance(data.get('data'), list):
1417
1402
  result["display_type"] = "plotly"
1418
1403
  result["data"] = data
1419
1404
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cowork-dash
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: AI Agent Web Interface with Filesystem and Canvas Visualization
5
5
  Project-URL: Homepage, https://github.com/dkedar7/cowork-dash
6
6
  Project-URL: Documentation, https://github.com/dkedar7/cowork-dash/blob/main/README.md
@@ -1,23 +1,23 @@
1
1
  cowork_dash/__init__.py,sha256=37qBKl7g12Zos8GFukXLXligCdpD32e2qe9F8cd8Qdk,896
2
2
  cowork_dash/__main__.py,sha256=CCM9VIkWuwh7hwVGNBBgCCbeVAcHj1soyBVXUaPgABk,131
3
- cowork_dash/agent.py,sha256=ZtpgRAft29OaD_GdJidfmZJ7_gzhP4ezQz136tUCByM,6853
4
- cowork_dash/app.py,sha256=jKpaHlsZ1GH17OVB3PXb2xMoqLjl_XI7u1mdcNEMtvA,148643
3
+ cowork_dash/agent.py,sha256=ebbqie02mbk7iemnQ3EFUap6Ywfc9iGfuJJjEYTJF8A,6497
4
+ cowork_dash/app.py,sha256=1xgY3HfXtEZE4D8yrcHGWTlza5-JNpHeVzemnyFhUOg,163453
5
5
  cowork_dash/backends.py,sha256=YQE8f65o2qGxIIfvBITAS6krCLjl8D9UixW-pgbdgZk,15050
6
6
  cowork_dash/canvas.py,sha256=sYOQ5WBLm29UazA5KO7j8jvIeQpx55LToz1o44o2U-k,17261
7
7
  cowork_dash/cli.py,sha256=HRxu_k_AphxD8JuLOVTIb6a1lmSdX7ziGCxnEBrW2gA,7561
8
- cowork_dash/components.py,sha256=fbqxTgFVILiWdxlJFBQVBc7klM3SaSvhjnwWlOl0V0s,36289
8
+ cowork_dash/components.py,sha256=DtJn7vQH5AKvbRQ4xCa5jfd3XeSLFe07wNJp5r8y-vc,43029
9
9
  cowork_dash/config.py,sha256=vVyDiX9Cdjk1wiZ_ktC3I2aiFC-GndNvLXWGW4aXUOM,5094
10
10
  cowork_dash/file_utils.py,sha256=qIpTycCNRIQWhdGcO8OIAKmehrxwkMMumgqw-5MjbSg,15431
11
- cowork_dash/layout.py,sha256=eDMingJVkcG5NeYuCFREaH21LNMBa6Ut5MSw9MV5eO0,16662
11
+ cowork_dash/layout.py,sha256=x38qpNmk7Ry69-YjnQwyiusrJtVsBech3Q7RvegEHSc,18610
12
12
  cowork_dash/sandbox.py,sha256=T0TMnZefPJj4OV1D1GNaYrircSG4MhXHk0IPizHXqME,11766
13
- cowork_dash/tools.py,sha256=MP-OX-OEeROtgcqJVQERAx91IP0th13O95L4EMP_dY8,58448
13
+ cowork_dash/tools.py,sha256=JXpYcE7AjBXki1HxZjDrSzMzyHBk0qdscbIEOl1AIZw,58150
14
14
  cowork_dash/virtual_fs.py,sha256=PAAdRiMkxgJ4xPpGUyAUd69KbH-nFlt-FjldfB1FrQ4,16296
15
15
  cowork_dash/assets/app.js,sha256=Rln4MQPxfyOcyH4lkSbT4RAP-fqF1lT_Qw25cHHUFS8,10157
16
16
  cowork_dash/assets/favicon.ico,sha256=IiP0rVr0m-TBGGmCY88SyFC14drNwDhLRqb0n2ZufKk,54252
17
17
  cowork_dash/assets/favicon.svg,sha256=MdT50APCvIlWh3HSwW5SNXYWB3q_wKfuLP-JV53SnKg,1065
18
- cowork_dash/assets/styles.css,sha256=9XoUoDB6s5xX3o3nifwiY6WFgrb_2y2JXP4OYlCs-Lc,28914
19
- cowork_dash-0.2.0.dist-info/METADATA,sha256=NAS-bflWJMhTrYQmMhwJ-HCp7PX6kCVqW4IPOuYHosg,6719
20
- cowork_dash-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
21
- cowork_dash-0.2.0.dist-info/entry_points.txt,sha256=lL_9XJINiky3nh13tLqWd61LitKbbyh085ROATH9fck,53
22
- cowork_dash-0.2.0.dist-info/licenses/LICENSE,sha256=2SFXFfIa_c_g_uwY0JApQDXI1mWqEfJeG87Pn4ehLMQ,1072
23
- cowork_dash-0.2.0.dist-info/RECORD,,
18
+ cowork_dash/assets/styles.css,sha256=hUmw_dYhZJJQQ20iuz7sosrOiGouNE1tkWuyEdBMvaI,29335
19
+ cowork_dash-0.2.2.dist-info/METADATA,sha256=fe67fO8mfql-IIaxV6gCoOejPg0K3Xg5ojiWWj6CwF4,6719
20
+ cowork_dash-0.2.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
21
+ cowork_dash-0.2.2.dist-info/entry_points.txt,sha256=lL_9XJINiky3nh13tLqWd61LitKbbyh085ROATH9fck,53
22
+ cowork_dash-0.2.2.dist-info/licenses/LICENSE,sha256=2SFXFfIa_c_g_uwY0JApQDXI1mWqEfJeG87Pn4ehLMQ,1072
23
+ cowork_dash-0.2.2.dist-info/RECORD,,