Update logbook: Reproduction: SWE-fficiency: Can Language Models Optimize Real-World Repositories on Real Workloads?
Browse files- README.md +13 -7
- bucket-icon.svg +5 -0
- index.html +52 -17
- logbook.css +1602 -0
- logbook.js +2275 -0
- logbook.json +59 -0
- pages/claim-1-the-swe-fficiency-benchmark-comprises-498-real-world-code-optimization-tasks-drawn-from-9-widely-used-python-repositories-including-numpy-pandas-and-scipy-abstract-only/page.md +48 -0
- pages/claim-2-agents-are-tasked-with-investigating-code-semantics-localizing-bottlenecks-and-relevant-tests-and-producing-a-patch-that-matches-or-exceeds-expert-speedup-while-passing-the-same-unit-tests-abstract-only/page.md +49 -0
- pages/claim-3-the-top-performing-agents-evaluated-on-swe-fficiency-achieve-less-than-0-23x-of-the-expert-level-speedup-on-average-across-the-498-tasks-abstract-only/page.md +59 -0
- pages/claim-4-agents-struggle-specifically-with-localizing-optimization-opportunities-in-large-codebases-reasoning-about-execution-flow-across-multiple-functions-and-maintaining-correctness-of-proposed-optimizations-abstract-only/page.md +61 -0
- pages/conclusion/page.md +70 -0
- pages/executive-summary/page.md +297 -0
- pages/index.md +14 -0
- trackio-logo-light.png +0 -0
- trackio-logo.png +0 -0
- trackio-wordmark-dark.png +0 -0
README.md
CHANGED
|
@@ -1,12 +1,18 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
colorFrom: gray
|
| 7 |
-
colorTo: pink
|
| 8 |
sdk: static
|
| 9 |
pinned: false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
---
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: "Reproduction: SWE-fficiency: Can Language Models Optimize Real-World Repositories on Real Workloads?"
|
| 3 |
+
emoji: π―
|
| 4 |
+
colorFrom: yellow
|
| 5 |
+
colorTo: red
|
|
|
|
|
|
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
+
tags:
|
| 9 |
+
- trackio
|
| 10 |
+
- trackio-logbook
|
| 11 |
+
- open-experiment
|
| 12 |
+
- icml2026-repro
|
| 13 |
+
- paper-0pyFbZSfbT
|
| 14 |
---
|
| 15 |
|
| 16 |
+
# Reproduction: SWE-fficiency: Can Language Models Optimize Real-World Repositories on Real Workloads?
|
| 17 |
+
|
| 18 |
+
An open experiment logbook, published with [Trackio](https://github.com/gradio-app/trackio).
|
bucket-icon.svg
ADDED
|
|
index.html
CHANGED
|
@@ -1,19 +1,54 @@
|
|
| 1 |
<!doctype html>
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
</html>
|
|
|
|
| 1 |
<!doctype html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
| 6 |
+
<title>Reproduction: SWE-fficiency: Can Language Models Optimize Real-World Repositories on Real Workloads?</title>
|
| 7 |
+
<link rel="stylesheet" href="./logbook.css" />
|
| 8 |
+
</head>
|
| 9 |
+
<body>
|
| 10 |
+
<div id="app">
|
| 11 |
+
<aside id="sidebar">
|
| 12 |
+
<div id="book-head">
|
| 13 |
+
<img id="book-wordmark" src="./trackio-wordmark-dark.png" alt="" />
|
| 14 |
+
<div id="book-title" class="sr-only">Logbook</div>
|
| 15 |
+
</div>
|
| 16 |
+
<nav id="tree"></nav>
|
| 17 |
+
<div id="sidebar-foot" hidden>
|
| 18 |
+
<button id="connect-btn" type="button">
|
| 19 |
+
<span class="ico">β</span> Collaborate with your agent
|
| 20 |
+
</button>
|
| 21 |
+
</div>
|
| 22 |
+
</aside>
|
| 23 |
+
<main id="content">
|
| 24 |
+
<div id="page"></div>
|
| 25 |
+
</main>
|
| 26 |
+
</div>
|
| 27 |
+
|
| 28 |
+
<div id="modal" hidden>
|
| 29 |
+
<div class="modal-backdrop"></div>
|
| 30 |
+
<div class="modal-card" role="dialog" aria-modal="true">
|
| 31 |
+
<div class="modal-head">
|
| 32 |
+
<div class="modal-title">
|
| 33 |
+
<img class="modal-logo" src="./trackio-logo.png" alt="" />
|
| 34 |
+
Collaborate with your agent
|
| 35 |
+
</div>
|
| 36 |
+
<div class="modal-actions">
|
| 37 |
+
<button id="copy-agent" class="btn">Copy for agent</button>
|
| 38 |
+
<button id="modal-close" class="btn icon" aria-label="Close">Γ</button>
|
| 39 |
+
</div>
|
| 40 |
+
</div>
|
| 41 |
+
<div class="modal-body">
|
| 42 |
+
<p class="modal-intro">
|
| 43 |
+
Point your coding agent at this logbook. It reads a compact,
|
| 44 |
+
token-efficient version β and if you've given it write access to this
|
| 45 |
+
Space, it can add findings that sync back automatically.
|
| 46 |
+
</p>
|
| 47 |
+
<ol id="connect-steps"></ol>
|
| 48 |
+
</div>
|
| 49 |
+
</div>
|
| 50 |
+
</div>
|
| 51 |
+
|
| 52 |
+
<script src="./logbook.js"></script>
|
| 53 |
+
</body>
|
| 54 |
</html>
|
logbook.css
ADDED
|
@@ -0,0 +1,1602 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
:root {
|
| 2 |
+
--bg: #ffffff;
|
| 3 |
+
--paper: #fdfcf9;
|
| 4 |
+
--panel: #ffffff;
|
| 5 |
+
--ink: #1f2937;
|
| 6 |
+
--muted: #6b7280;
|
| 7 |
+
--line: #e5e7eb;
|
| 8 |
+
--accent: #f97316;
|
| 9 |
+
--accent-strong: #ea580c;
|
| 10 |
+
--accent-soft: #fff7ed;
|
| 11 |
+
--accent-line: rgba(249, 115, 22, 0.16);
|
| 12 |
+
--grid-line: rgba(31, 41, 55, 0.045);
|
| 13 |
+
--code-bg: #f3f4f6;
|
| 14 |
+
--radius: 12px;
|
| 15 |
+
--serif: ui-serif, "Iowan Old Style", "Palatino Linotype", Georgia, serif;
|
| 16 |
+
--sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial,
|
| 17 |
+
sans-serif;
|
| 18 |
+
--mono: "SFMono-Regular", "Cascadia Mono", "JetBrains Mono", Menlo, Consolas,
|
| 19 |
+
ui-monospace, monospace;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
* {
|
| 23 |
+
box-sizing: border-box;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
html,
|
| 27 |
+
body {
|
| 28 |
+
margin: 0;
|
| 29 |
+
padding: 0;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
html {
|
| 33 |
+
scroll-behavior: smooth;
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
body {
|
| 37 |
+
background: var(--bg);
|
| 38 |
+
color: var(--ink);
|
| 39 |
+
font-family: var(--sans);
|
| 40 |
+
font-size: 13px;
|
| 41 |
+
line-height: 1.65;
|
| 42 |
+
-webkit-font-smoothing: antialiased;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
#app {
|
| 46 |
+
display: flex;
|
| 47 |
+
min-height: 100vh;
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
/* ---- sidebar (composition-book cover) ---- */
|
| 51 |
+
#sidebar {
|
| 52 |
+
width: 280px;
|
| 53 |
+
flex: 0 0 280px;
|
| 54 |
+
background: #17181c;
|
| 55 |
+
color: #e7e7ea;
|
| 56 |
+
position: sticky;
|
| 57 |
+
top: 0;
|
| 58 |
+
height: 100vh;
|
| 59 |
+
overflow-y: auto;
|
| 60 |
+
padding: 22px 16px;
|
| 61 |
+
display: flex;
|
| 62 |
+
flex-direction: column;
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
#book-head {
|
| 66 |
+
display: flex;
|
| 67 |
+
align-items: center;
|
| 68 |
+
gap: 10px;
|
| 69 |
+
padding: 8px;
|
| 70 |
+
margin-bottom: 12px;
|
| 71 |
+
border-radius: 10px;
|
| 72 |
+
cursor: pointer;
|
| 73 |
+
transition: background 0.12s;
|
| 74 |
+
}
|
| 75 |
+
#book-head:hover {
|
| 76 |
+
background: rgba(255, 255, 255, 0.05);
|
| 77 |
+
}
|
| 78 |
+
#book-wordmark {
|
| 79 |
+
width: 154px;
|
| 80 |
+
height: auto;
|
| 81 |
+
object-fit: contain;
|
| 82 |
+
}
|
| 83 |
+
.sr-only {
|
| 84 |
+
position: absolute;
|
| 85 |
+
width: 1px;
|
| 86 |
+
height: 1px;
|
| 87 |
+
padding: 0;
|
| 88 |
+
margin: -1px;
|
| 89 |
+
overflow: hidden;
|
| 90 |
+
clip: rect(0, 0, 0, 0);
|
| 91 |
+
white-space: nowrap;
|
| 92 |
+
border: 0;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
#tree {
|
| 96 |
+
flex: 1;
|
| 97 |
+
padding-top: 8px;
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
#tree a {
|
| 101 |
+
display: block;
|
| 102 |
+
padding: 6px 10px;
|
| 103 |
+
border-radius: 8px;
|
| 104 |
+
color: #c3c4cb;
|
| 105 |
+
text-decoration: none;
|
| 106 |
+
font-size: 14px;
|
| 107 |
+
transition: background 0.12s, color 0.12s;
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
#tree a:hover {
|
| 111 |
+
background: rgba(255, 255, 255, 0.06);
|
| 112 |
+
color: #ffffff;
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
#tree a.active {
|
| 116 |
+
background: rgba(249, 115, 22, 0.16);
|
| 117 |
+
color: #fdba74;
|
| 118 |
+
font-weight: 600;
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
#tree a .tree-mark {
|
| 122 |
+
color: #6b6d76;
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
#tree a:hover .tree-mark,
|
| 126 |
+
#tree a.active .tree-mark {
|
| 127 |
+
color: inherit;
|
| 128 |
+
opacity: 0.6;
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
#tree .depth-1 {
|
| 132 |
+
padding-left: 22px;
|
| 133 |
+
}
|
| 134 |
+
#tree .depth-2 {
|
| 135 |
+
padding-left: 34px;
|
| 136 |
+
}
|
| 137 |
+
#tree .depth-3 {
|
| 138 |
+
padding-left: 46px;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
/* ---- content ---- */
|
| 143 |
+
#content {
|
| 144 |
+
flex: 1;
|
| 145 |
+
min-width: 0;
|
| 146 |
+
padding: 48px 40px 120px;
|
| 147 |
+
background-color: var(--paper);
|
| 148 |
+
background-image:
|
| 149 |
+
linear-gradient(var(--grid-line) 1px, transparent 1px),
|
| 150 |
+
linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
|
| 151 |
+
background-size: 26px 26px;
|
| 152 |
+
background-position: center top;
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
#page {
|
| 156 |
+
width: 100%;
|
| 157 |
+
min-width: 0;
|
| 158 |
+
max-width: 1052px;
|
| 159 |
+
margin: 0 auto;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
.page-section {
|
| 163 |
+
scroll-margin-top: 40px;
|
| 164 |
+
padding: 0 0 35px;
|
| 165 |
+
margin: 0 0 32px;
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
.page-section:last-child {
|
| 169 |
+
margin-bottom: 0;
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
.page-layout {
|
| 173 |
+
display: grid;
|
| 174 |
+
grid-template-columns: minmax(0, 760px) 248px;
|
| 175 |
+
gap: 44px;
|
| 176 |
+
align-items: start;
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
.page-body {
|
| 180 |
+
min-width: 0;
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
.resource-anchor {
|
| 184 |
+
display: block;
|
| 185 |
+
height: 0;
|
| 186 |
+
overflow: hidden;
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
/* ---- pinned notes ---- */
|
| 190 |
+
.pinned-notes {
|
| 191 |
+
margin: 30px 0 0;
|
| 192 |
+
}
|
| 193 |
+
.pinned-notes-list .cell {
|
| 194 |
+
margin: 0;
|
| 195 |
+
border-color: rgba(249, 115, 22, 0.55);
|
| 196 |
+
}
|
| 197 |
+
.pinned-notes-list .cell + .cell {
|
| 198 |
+
margin-top: 12px;
|
| 199 |
+
}
|
| 200 |
+
.cell.pinned-source {
|
| 201 |
+
border-color: rgba(249, 115, 22, 0.55);
|
| 202 |
+
}
|
| 203 |
+
.book-intro.has-pinned-notes {
|
| 204 |
+
border-bottom: none;
|
| 205 |
+
padding-bottom: 22px;
|
| 206 |
+
margin-bottom: 30px;
|
| 207 |
+
}
|
| 208 |
+
.book-intro.book-intro-tight {
|
| 209 |
+
border-bottom: none;
|
| 210 |
+
padding-bottom: 4px;
|
| 211 |
+
margin-bottom: 20px;
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
#page h1 {
|
| 215 |
+
font-family: var(--serif);
|
| 216 |
+
font-size: 34px;
|
| 217 |
+
line-height: 1.15;
|
| 218 |
+
letter-spacing: -0.02em;
|
| 219 |
+
margin: 0 0 8px;
|
| 220 |
+
overflow-wrap: anywhere;
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
#page .page-section:not(.book-intro) h1 {
|
| 224 |
+
font-size: 26px;
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
#page h2 {
|
| 228 |
+
font-family: var(--serif);
|
| 229 |
+
font-size: 24px;
|
| 230 |
+
margin: 36px 0 10px;
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
#page h3 {
|
| 234 |
+
font-size: 17px;
|
| 235 |
+
font-weight: 700;
|
| 236 |
+
margin: 26px 0 2px;
|
| 237 |
+
letter-spacing: -0.01em;
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
#page h3::before {
|
| 241 |
+
content: "";
|
| 242 |
+
display: inline-block;
|
| 243 |
+
width: 7px;
|
| 244 |
+
height: 7px;
|
| 245 |
+
border-radius: 2px;
|
| 246 |
+
background: var(--accent);
|
| 247 |
+
margin-right: 10px;
|
| 248 |
+
vertical-align: middle;
|
| 249 |
+
transform: translateY(-1px);
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
#page p {
|
| 253 |
+
margin: 10px 0;
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
#page blockquote {
|
| 257 |
+
margin: 14px 0;
|
| 258 |
+
padding: 2px 16px;
|
| 259 |
+
border-left: 3px solid #fdba74;
|
| 260 |
+
color: var(--muted);
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
#page hr {
|
| 264 |
+
display: none;
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
#page code {
|
| 268 |
+
font-family: var(--mono);
|
| 269 |
+
font-size: 0.86em;
|
| 270 |
+
background: var(--code-bg);
|
| 271 |
+
padding: 2px 6px;
|
| 272 |
+
border-radius: 6px;
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
#page pre {
|
| 276 |
+
max-width: 100%;
|
| 277 |
+
background: var(--code-bg);
|
| 278 |
+
border: 1px solid var(--line);
|
| 279 |
+
border-radius: var(--radius);
|
| 280 |
+
padding: 14px 16px;
|
| 281 |
+
overflow-x: auto;
|
| 282 |
+
}
|
| 283 |
+
#page pre code {
|
| 284 |
+
background: none;
|
| 285 |
+
padding: 0;
|
| 286 |
+
font-size: 11.5px;
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
/* ---- code blocks + collapsible accordion ---- */
|
| 290 |
+
#page pre.hl {
|
| 291 |
+
background: #17181c;
|
| 292 |
+
border: none;
|
| 293 |
+
color: #e7e7ea;
|
| 294 |
+
font-size: 13px;
|
| 295 |
+
line-height: 1.58;
|
| 296 |
+
}
|
| 297 |
+
#page pre.hl code {
|
| 298 |
+
color: inherit;
|
| 299 |
+
font-family: var(--mono);
|
| 300 |
+
}
|
| 301 |
+
.code-accordion {
|
| 302 |
+
border: 1px solid rgba(249, 115, 22, 0.2);
|
| 303 |
+
border-radius: 8px;
|
| 304 |
+
overflow: hidden;
|
| 305 |
+
margin: 12px 0;
|
| 306 |
+
background: #17181c;
|
| 307 |
+
}
|
| 308 |
+
.code-accordion summary {
|
| 309 |
+
list-style: none;
|
| 310 |
+
cursor: pointer;
|
| 311 |
+
display: flex;
|
| 312 |
+
align-items: center;
|
| 313 |
+
gap: 9px;
|
| 314 |
+
padding: 9px 12px;
|
| 315 |
+
font-family: var(--mono);
|
| 316 |
+
font-size: 11.5px;
|
| 317 |
+
font-weight: 700;
|
| 318 |
+
color: #e7e7ea;
|
| 319 |
+
background: #1e2027;
|
| 320 |
+
user-select: none;
|
| 321 |
+
overflow-wrap: anywhere;
|
| 322 |
+
}
|
| 323 |
+
.code-accordion summary::-webkit-details-marker {
|
| 324 |
+
display: none;
|
| 325 |
+
}
|
| 326 |
+
.code-accordion summary::after {
|
| 327 |
+
content: "βΈ";
|
| 328 |
+
margin-left: auto;
|
| 329 |
+
color: var(--accent);
|
| 330 |
+
transition: transform 0.12s;
|
| 331 |
+
transform: rotate(180deg);
|
| 332 |
+
}
|
| 333 |
+
.code-accordion[open] summary::after {
|
| 334 |
+
transform: rotate(90deg);
|
| 335 |
+
}
|
| 336 |
+
.code-accordion .code-ico {
|
| 337 |
+
color: var(--accent);
|
| 338 |
+
font-weight: 700;
|
| 339 |
+
}
|
| 340 |
+
.code-accordion pre.hl {
|
| 341 |
+
margin: 0;
|
| 342 |
+
border-radius: 0;
|
| 343 |
+
border: none;
|
| 344 |
+
border-top: 1px solid rgba(249, 115, 22, 0.16);
|
| 345 |
+
}
|
| 346 |
+
.tok-comment {
|
| 347 |
+
color: #7a7d87;
|
| 348 |
+
font-style: italic;
|
| 349 |
+
}
|
| 350 |
+
.tok-string {
|
| 351 |
+
color: #a5d6a7;
|
| 352 |
+
}
|
| 353 |
+
.tok-keyword {
|
| 354 |
+
color: #fdba74;
|
| 355 |
+
}
|
| 356 |
+
.tok-number {
|
| 357 |
+
color: #7fd0e0;
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
#page a {
|
| 361 |
+
color: var(--accent);
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
#page ul {
|
| 365 |
+
padding-left: 20px;
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
.ts {
|
| 369 |
+
font-family: var(--mono);
|
| 370 |
+
font-size: 12px;
|
| 371 |
+
color: var(--muted);
|
| 372 |
+
background: none;
|
| 373 |
+
padding: 0;
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
/* ---- notebook-style cells ---- */
|
| 377 |
+
.cell {
|
| 378 |
+
max-width: 100%;
|
| 379 |
+
border: 1px solid var(--line);
|
| 380 |
+
border-radius: 10px;
|
| 381 |
+
background: rgba(255, 255, 255, 0.86);
|
| 382 |
+
margin: 18px 0;
|
| 383 |
+
overflow: hidden;
|
| 384 |
+
box-shadow: 0 2px 10px rgba(31, 41, 55, 0.035);
|
| 385 |
+
}
|
| 386 |
+
.cell-head {
|
| 387 |
+
display: flex;
|
| 388 |
+
justify-content: space-between;
|
| 389 |
+
gap: 16px;
|
| 390 |
+
align-items: center;
|
| 391 |
+
padding: 14px 18px;
|
| 392 |
+
background: rgba(255, 255, 255, 0.92);
|
| 393 |
+
border-bottom: 1px solid var(--line);
|
| 394 |
+
}
|
| 395 |
+
.cell-head.no-title {
|
| 396 |
+
justify-content: flex-end;
|
| 397 |
+
padding-top: 10px;
|
| 398 |
+
padding-bottom: 10px;
|
| 399 |
+
}
|
| 400 |
+
.cell-title {
|
| 401 |
+
flex: 1;
|
| 402 |
+
min-width: 0;
|
| 403 |
+
font-size: 13px;
|
| 404 |
+
font-weight: 650;
|
| 405 |
+
color: var(--ink);
|
| 406 |
+
line-height: 1.35;
|
| 407 |
+
overflow-wrap: anywhere;
|
| 408 |
+
}
|
| 409 |
+
.cell-meta {
|
| 410 |
+
flex: 0 0 auto;
|
| 411 |
+
display: flex;
|
| 412 |
+
align-items: center;
|
| 413 |
+
gap: 10px;
|
| 414 |
+
font-family: var(--sans);
|
| 415 |
+
font-size: 13px;
|
| 416 |
+
color: var(--muted);
|
| 417 |
+
}
|
| 418 |
+
.cell-open {
|
| 419 |
+
flex: 0 0 auto;
|
| 420 |
+
font-family: var(--mono);
|
| 421 |
+
font-size: 12px;
|
| 422 |
+
color: var(--accent);
|
| 423 |
+
text-decoration: none;
|
| 424 |
+
}
|
| 425 |
+
.cell-open:hover {
|
| 426 |
+
color: var(--accent-strong);
|
| 427 |
+
}
|
| 428 |
+
.cell-body {
|
| 429 |
+
min-width: 0;
|
| 430 |
+
padding: 14px 18px 18px;
|
| 431 |
+
}
|
| 432 |
+
.cell.dashboard .cell-body {
|
| 433 |
+
padding: 0;
|
| 434 |
+
}
|
| 435 |
+
#page .cell-body h1,
|
| 436 |
+
#page .cell-body h2 {
|
| 437 |
+
font-family: var(--sans);
|
| 438 |
+
font-size: 17px;
|
| 439 |
+
font-weight: 700;
|
| 440 |
+
letter-spacing: -0.01em;
|
| 441 |
+
line-height: 1.35;
|
| 442 |
+
margin: 22px 0 6px;
|
| 443 |
+
}
|
| 444 |
+
#page .cell-body > :first-child {
|
| 445 |
+
margin-top: 0;
|
| 446 |
+
}
|
| 447 |
+
#page .cell-body > :last-child {
|
| 448 |
+
margin-bottom: 0;
|
| 449 |
+
}
|
| 450 |
+
.cell.code .cell-head {
|
| 451 |
+
background: #fbfbfc;
|
| 452 |
+
}
|
| 453 |
+
.figure-fit {
|
| 454 |
+
position: relative;
|
| 455 |
+
overflow: hidden;
|
| 456 |
+
min-height: 160px;
|
| 457 |
+
border: 1px solid var(--line);
|
| 458 |
+
border-radius: 8px;
|
| 459 |
+
background: #fff;
|
| 460 |
+
}
|
| 461 |
+
.figure-fit[hidden] {
|
| 462 |
+
display: none;
|
| 463 |
+
}
|
| 464 |
+
.figure-fit:fullscreen,
|
| 465 |
+
.figure-fit:-webkit-full-screen {
|
| 466 |
+
width: 100%;
|
| 467 |
+
height: 100%;
|
| 468 |
+
border: none;
|
| 469 |
+
border-radius: 0;
|
| 470 |
+
}
|
| 471 |
+
.figure-frame {
|
| 472 |
+
display: block;
|
| 473 |
+
width: 100%;
|
| 474 |
+
min-height: 160px;
|
| 475 |
+
border: none;
|
| 476 |
+
background: #fff;
|
| 477 |
+
}
|
| 478 |
+
.figure-frame[hidden],
|
| 479 |
+
.figure-raw[hidden] {
|
| 480 |
+
display: none;
|
| 481 |
+
}
|
| 482 |
+
.fig-switch {
|
| 483 |
+
position: relative;
|
| 484 |
+
display: inline-flex;
|
| 485 |
+
flex: 0 0 auto;
|
| 486 |
+
border: 1px solid var(--line);
|
| 487 |
+
border-radius: 999px;
|
| 488 |
+
background: var(--code-bg);
|
| 489 |
+
padding: 2px;
|
| 490 |
+
}
|
| 491 |
+
.fig-switch button {
|
| 492 |
+
position: relative;
|
| 493 |
+
z-index: 1;
|
| 494 |
+
flex: 1;
|
| 495 |
+
min-width: 62px;
|
| 496 |
+
border: none;
|
| 497 |
+
background: none;
|
| 498 |
+
font-family: var(--sans);
|
| 499 |
+
font-size: 12px;
|
| 500 |
+
font-weight: 600;
|
| 501 |
+
color: var(--muted);
|
| 502 |
+
padding: 3px 12px;
|
| 503 |
+
border-radius: 999px;
|
| 504 |
+
cursor: pointer;
|
| 505 |
+
transition: color 0.15s;
|
| 506 |
+
}
|
| 507 |
+
.fig-switch button.active {
|
| 508 |
+
color: var(--accent-strong);
|
| 509 |
+
}
|
| 510 |
+
.fig-switch-thumb {
|
| 511 |
+
position: absolute;
|
| 512 |
+
top: 2px;
|
| 513 |
+
bottom: 2px;
|
| 514 |
+
left: 2px;
|
| 515 |
+
width: calc(50% - 2px);
|
| 516 |
+
border-radius: 999px;
|
| 517 |
+
background: var(--panel);
|
| 518 |
+
border: 1px solid rgba(249, 115, 22, 0.35);
|
| 519 |
+
box-shadow: 0 1px 4px rgba(31, 41, 55, 0.08);
|
| 520 |
+
transition: transform 0.18s ease;
|
| 521 |
+
}
|
| 522 |
+
.fig-switch.raw .fig-switch-thumb {
|
| 523 |
+
transform: translateX(100%);
|
| 524 |
+
}
|
| 525 |
+
#page .figure-raw pre {
|
| 526 |
+
margin: 0;
|
| 527 |
+
max-height: 420px;
|
| 528 |
+
overflow: auto;
|
| 529 |
+
font-family: var(--mono);
|
| 530 |
+
font-size: 13px;
|
| 531 |
+
line-height: 1.55;
|
| 532 |
+
background: var(--code-bg);
|
| 533 |
+
border: 1px solid var(--line);
|
| 534 |
+
border-radius: 8px;
|
| 535 |
+
padding: 12px 14px;
|
| 536 |
+
}
|
| 537 |
+
/* ---- figure fullscreen ---- */
|
| 538 |
+
.cell-fullscreen {
|
| 539 |
+
position: relative;
|
| 540 |
+
display: inline-flex;
|
| 541 |
+
flex: 0 0 auto;
|
| 542 |
+
}
|
| 543 |
+
.cell-fullscreen-btn {
|
| 544 |
+
display: inline-flex;
|
| 545 |
+
align-items: center;
|
| 546 |
+
justify-content: center;
|
| 547 |
+
width: 26px;
|
| 548 |
+
height: 26px;
|
| 549 |
+
padding: 0;
|
| 550 |
+
border: 1px solid var(--line);
|
| 551 |
+
border-radius: 999px;
|
| 552 |
+
background: var(--code-bg);
|
| 553 |
+
color: var(--muted);
|
| 554 |
+
cursor: pointer;
|
| 555 |
+
transition: color 0.15s, border-color 0.15s, background 0.15s;
|
| 556 |
+
}
|
| 557 |
+
.cell-fullscreen-btn:hover {
|
| 558 |
+
color: var(--accent-strong);
|
| 559 |
+
border-color: rgba(249, 115, 22, 0.35);
|
| 560 |
+
background: var(--accent-soft);
|
| 561 |
+
}
|
| 562 |
+
.cell-fullscreen-btn svg {
|
| 563 |
+
width: 14px;
|
| 564 |
+
height: 14px;
|
| 565 |
+
}
|
| 566 |
+
/* ---- copyable snippets ---- */
|
| 567 |
+
.snippet {
|
| 568 |
+
position: relative;
|
| 569 |
+
}
|
| 570 |
+
.copy-snippet {
|
| 571 |
+
position: absolute;
|
| 572 |
+
top: 7px;
|
| 573 |
+
right: 8px;
|
| 574 |
+
width: 24px;
|
| 575 |
+
height: 24px;
|
| 576 |
+
border: none;
|
| 577 |
+
border-radius: 6px;
|
| 578 |
+
background: rgba(255, 255, 255, 0.08);
|
| 579 |
+
color: #9a9da8;
|
| 580 |
+
font-size: 12px;
|
| 581 |
+
line-height: 1;
|
| 582 |
+
cursor: pointer;
|
| 583 |
+
opacity: 0;
|
| 584 |
+
transition: opacity 0.12s, color 0.12s, background 0.12s;
|
| 585 |
+
}
|
| 586 |
+
.snippet:hover .copy-snippet,
|
| 587 |
+
.jp-out:hover .copy-snippet,
|
| 588 |
+
.figure-raw:hover .copy-snippet,
|
| 589 |
+
.code-accordion summary:hover .copy-snippet {
|
| 590 |
+
opacity: 1;
|
| 591 |
+
}
|
| 592 |
+
.copy-snippet:hover {
|
| 593 |
+
color: #ffffff;
|
| 594 |
+
background: rgba(255, 255, 255, 0.16);
|
| 595 |
+
}
|
| 596 |
+
.copy-snippet.copied {
|
| 597 |
+
color: #52d08a;
|
| 598 |
+
opacity: 1;
|
| 599 |
+
}
|
| 600 |
+
.code-accordion .code-name {
|
| 601 |
+
user-select: text;
|
| 602 |
+
cursor: text;
|
| 603 |
+
}
|
| 604 |
+
.jp-out,
|
| 605 |
+
.figure-raw {
|
| 606 |
+
position: relative;
|
| 607 |
+
}
|
| 608 |
+
.jp-out .copy-snippet,
|
| 609 |
+
.figure-raw .copy-snippet {
|
| 610 |
+
background: var(--code-bg);
|
| 611 |
+
color: var(--muted);
|
| 612 |
+
border: 1px solid var(--line);
|
| 613 |
+
}
|
| 614 |
+
.jp-out .copy-snippet:hover,
|
| 615 |
+
.figure-raw .copy-snippet:hover {
|
| 616 |
+
color: var(--accent-strong);
|
| 617 |
+
background: var(--panel);
|
| 618 |
+
}
|
| 619 |
+
|
| 620 |
+
/* ---- jupyter-style code cells ---- */
|
| 621 |
+
.jp {
|
| 622 |
+
border: 1px solid var(--line);
|
| 623 |
+
border-radius: 10px;
|
| 624 |
+
overflow: hidden;
|
| 625 |
+
margin: 12px 0;
|
| 626 |
+
background: var(--panel);
|
| 627 |
+
}
|
| 628 |
+
.jp-gutter {
|
| 629 |
+
flex: 0 0 46px;
|
| 630 |
+
padding: 13px 0 0 13px;
|
| 631 |
+
font-family: var(--mono);
|
| 632 |
+
font-size: 10.5px;
|
| 633 |
+
letter-spacing: 0.07em;
|
| 634 |
+
text-transform: uppercase;
|
| 635 |
+
font-weight: 600;
|
| 636 |
+
user-select: none;
|
| 637 |
+
}
|
| 638 |
+
.jp-in {
|
| 639 |
+
display: flex;
|
| 640 |
+
background: #17181c;
|
| 641 |
+
}
|
| 642 |
+
.jp-in .jp-gutter {
|
| 643 |
+
color: #6f727d;
|
| 644 |
+
}
|
| 645 |
+
.jp-in-body {
|
| 646 |
+
flex: 1;
|
| 647 |
+
min-width: 0;
|
| 648 |
+
}
|
| 649 |
+
#page .jp-in-body pre.hl {
|
| 650 |
+
margin: 0;
|
| 651 |
+
border: none;
|
| 652 |
+
border-radius: 0;
|
| 653 |
+
background: none;
|
| 654 |
+
padding: 12px 16px 12px 0;
|
| 655 |
+
}
|
| 656 |
+
.jp-in-body .code-accordion {
|
| 657 |
+
margin: 0;
|
| 658 |
+
border: none;
|
| 659 |
+
border-top: 1px solid rgba(255, 255, 255, 0.09);
|
| 660 |
+
border-radius: 0;
|
| 661 |
+
background: none;
|
| 662 |
+
}
|
| 663 |
+
.jp-in-body .code-accordion summary {
|
| 664 |
+
background: none;
|
| 665 |
+
padding: 9px 16px 9px 0;
|
| 666 |
+
}
|
| 667 |
+
.jp-in-body .code-accordion pre.hl {
|
| 668 |
+
border-top: 1px solid rgba(255, 255, 255, 0.09);
|
| 669 |
+
}
|
| 670 |
+
.jp-meta {
|
| 671 |
+
padding: 5px 14px;
|
| 672 |
+
font-family: var(--mono);
|
| 673 |
+
font-size: 11.5px;
|
| 674 |
+
color: var(--muted);
|
| 675 |
+
background: #fbfbfc;
|
| 676 |
+
border-top: 1px solid var(--line);
|
| 677 |
+
}
|
| 678 |
+
.jp-out {
|
| 679 |
+
display: flex;
|
| 680 |
+
border-top: 1px solid var(--line);
|
| 681 |
+
background: var(--panel);
|
| 682 |
+
}
|
| 683 |
+
.jp-out .jp-gutter {
|
| 684 |
+
color: var(--accent-strong);
|
| 685 |
+
}
|
| 686 |
+
.jp-out-body {
|
| 687 |
+
flex: 1;
|
| 688 |
+
min-width: 0;
|
| 689 |
+
}
|
| 690 |
+
#page .jp-out-pre {
|
| 691 |
+
min-width: 0;
|
| 692 |
+
margin: 0;
|
| 693 |
+
border: none;
|
| 694 |
+
border-radius: 0;
|
| 695 |
+
background: none;
|
| 696 |
+
color: var(--ink);
|
| 697 |
+
font-family: var(--mono);
|
| 698 |
+
font-size: 13px;
|
| 699 |
+
line-height: 1.55;
|
| 700 |
+
padding: 12px 16px 12px 0;
|
| 701 |
+
white-space: pre;
|
| 702 |
+
overflow-x: auto;
|
| 703 |
+
overflow-y: auto;
|
| 704 |
+
max-height: 26em;
|
| 705 |
+
}
|
| 706 |
+
.jp-artifacts {
|
| 707 |
+
display: flex;
|
| 708 |
+
flex-direction: column;
|
| 709 |
+
}
|
| 710 |
+
.jp-out-body .jp-out-pre + .jp-artifacts {
|
| 711 |
+
border-top: 1px solid var(--line);
|
| 712 |
+
}
|
| 713 |
+
.out-artifact {
|
| 714 |
+
display: flex;
|
| 715 |
+
align-items: baseline;
|
| 716 |
+
gap: 8px;
|
| 717 |
+
padding: 9px 16px 9px 0;
|
| 718 |
+
text-decoration: none;
|
| 719 |
+
color: inherit;
|
| 720 |
+
}
|
| 721 |
+
.out-artifact + .out-artifact {
|
| 722 |
+
border-top: 1px solid var(--line);
|
| 723 |
+
}
|
| 724 |
+
a.out-artifact:hover .out-artifact-name {
|
| 725 |
+
color: var(--accent-strong);
|
| 726 |
+
}
|
| 727 |
+
.out-artifact-ico {
|
| 728 |
+
flex: 0 0 auto;
|
| 729 |
+
font-size: 13px;
|
| 730 |
+
}
|
| 731 |
+
.out-artifact-name {
|
| 732 |
+
font-family: var(--mono);
|
| 733 |
+
font-size: 12.5px;
|
| 734 |
+
font-weight: 600;
|
| 735 |
+
color: var(--ink);
|
| 736 |
+
overflow: hidden;
|
| 737 |
+
text-overflow: ellipsis;
|
| 738 |
+
white-space: nowrap;
|
| 739 |
+
}
|
| 740 |
+
.out-artifact-meta {
|
| 741 |
+
flex: 0 0 auto;
|
| 742 |
+
margin-left: auto;
|
| 743 |
+
padding-left: 12px;
|
| 744 |
+
font-size: 12px;
|
| 745 |
+
color: var(--muted);
|
| 746 |
+
white-space: nowrap;
|
| 747 |
+
}
|
| 748 |
+
.out-artifact-state.open {
|
| 749 |
+
color: var(--accent);
|
| 750 |
+
font-weight: 600;
|
| 751 |
+
}
|
| 752 |
+
.trackio-embed {
|
| 753 |
+
border: 1px solid var(--line);
|
| 754 |
+
border-radius: var(--radius);
|
| 755 |
+
overflow: hidden;
|
| 756 |
+
background: var(--panel);
|
| 757 |
+
}
|
| 758 |
+
.trackio-cell-meta {
|
| 759 |
+
display: flex;
|
| 760 |
+
gap: 6px;
|
| 761 |
+
flex-wrap: wrap;
|
| 762 |
+
justify-content: flex-end;
|
| 763 |
+
}
|
| 764 |
+
|
| 765 |
+
/* ---- unfurl cards ---- */
|
| 766 |
+
.unfurl {
|
| 767 |
+
display: block;
|
| 768 |
+
border: 1px solid var(--line);
|
| 769 |
+
border-radius: var(--radius);
|
| 770 |
+
background: var(--panel);
|
| 771 |
+
margin: 12px 0;
|
| 772 |
+
overflow: hidden;
|
| 773 |
+
text-decoration: none;
|
| 774 |
+
color: inherit;
|
| 775 |
+
transition: border-color 0.14s, box-shadow 0.14s;
|
| 776 |
+
}
|
| 777 |
+
.unfurl:hover {
|
| 778 |
+
border-color: #cfcbe6;
|
| 779 |
+
box-shadow: 0 4px 18px rgba(30, 20, 80, 0.06);
|
| 780 |
+
}
|
| 781 |
+
|
| 782 |
+
.unfurl-body {
|
| 783 |
+
padding: 13px 16px;
|
| 784 |
+
display: flex;
|
| 785 |
+
gap: 12px;
|
| 786 |
+
align-items: flex-start;
|
| 787 |
+
}
|
| 788 |
+
|
| 789 |
+
.unfurl-ico {
|
| 790 |
+
font-size: 20px;
|
| 791 |
+
line-height: 1.3;
|
| 792 |
+
flex: 0 0 auto;
|
| 793 |
+
}
|
| 794 |
+
|
| 795 |
+
.unfurl-main {
|
| 796 |
+
min-width: 0;
|
| 797 |
+
flex: 1;
|
| 798 |
+
}
|
| 799 |
+
|
| 800 |
+
.unfurl-kind {
|
| 801 |
+
font-family: var(--mono);
|
| 802 |
+
font-size: 10.5px;
|
| 803 |
+
text-transform: uppercase;
|
| 804 |
+
letter-spacing: 0.08em;
|
| 805 |
+
color: var(--accent);
|
| 806 |
+
font-weight: 600;
|
| 807 |
+
}
|
| 808 |
+
|
| 809 |
+
.unfurl-title {
|
| 810 |
+
font-weight: 650;
|
| 811 |
+
font-size: 15px;
|
| 812 |
+
margin: 1px 0 2px;
|
| 813 |
+
white-space: nowrap;
|
| 814 |
+
overflow: hidden;
|
| 815 |
+
text-overflow: ellipsis;
|
| 816 |
+
}
|
| 817 |
+
|
| 818 |
+
.unfurl-desc {
|
| 819 |
+
color: var(--muted);
|
| 820 |
+
font-size: 13.5px;
|
| 821 |
+
line-height: 1.45;
|
| 822 |
+
}
|
| 823 |
+
|
| 824 |
+
.unfurl-meta {
|
| 825 |
+
margin-top: 6px;
|
| 826 |
+
display: flex;
|
| 827 |
+
flex-wrap: wrap;
|
| 828 |
+
gap: 6px;
|
| 829 |
+
}
|
| 830 |
+
|
| 831 |
+
.chip {
|
| 832 |
+
font-size: 11.5px;
|
| 833 |
+
background: var(--code-bg);
|
| 834 |
+
border-radius: 999px;
|
| 835 |
+
padding: 2px 9px;
|
| 836 |
+
color: var(--muted);
|
| 837 |
+
font-family: var(--mono);
|
| 838 |
+
}
|
| 839 |
+
|
| 840 |
+
.unfurl-raw {
|
| 841 |
+
font-family: var(--mono);
|
| 842 |
+
font-size: 11px;
|
| 843 |
+
color: var(--muted);
|
| 844 |
+
border-top: 1px solid var(--line);
|
| 845 |
+
padding: 7px 16px;
|
| 846 |
+
white-space: nowrap;
|
| 847 |
+
overflow: hidden;
|
| 848 |
+
text-overflow: ellipsis;
|
| 849 |
+
}
|
| 850 |
+
|
| 851 |
+
.unfurl.embed {
|
| 852 |
+
padding: 0;
|
| 853 |
+
overflow: hidden;
|
| 854 |
+
}
|
| 855 |
+
.embed-head {
|
| 856 |
+
display: flex;
|
| 857 |
+
align-items: center;
|
| 858 |
+
gap: 10px;
|
| 859 |
+
padding: 10px 14px;
|
| 860 |
+
border-bottom: 1px solid var(--line);
|
| 861 |
+
}
|
| 862 |
+
.embed-head .unfurl-kind {
|
| 863 |
+
flex: 0 0 auto;
|
| 864 |
+
}
|
| 865 |
+
.embed-title {
|
| 866 |
+
flex: 1;
|
| 867 |
+
min-width: 0;
|
| 868 |
+
font-weight: 650;
|
| 869 |
+
font-size: 14px;
|
| 870 |
+
color: var(--ink);
|
| 871 |
+
text-decoration: none;
|
| 872 |
+
white-space: nowrap;
|
| 873 |
+
overflow: hidden;
|
| 874 |
+
text-overflow: ellipsis;
|
| 875 |
+
}
|
| 876 |
+
.embed-title:hover {
|
| 877 |
+
color: var(--accent);
|
| 878 |
+
}
|
| 879 |
+
.embed-open {
|
| 880 |
+
flex: 0 0 auto;
|
| 881 |
+
font-family: var(--mono);
|
| 882 |
+
font-size: 12px;
|
| 883 |
+
color: var(--accent);
|
| 884 |
+
text-decoration: none;
|
| 885 |
+
}
|
| 886 |
+
.embed-frame {
|
| 887 |
+
display: block;
|
| 888 |
+
width: 100%;
|
| 889 |
+
height: 560px;
|
| 890 |
+
border: 0;
|
| 891 |
+
background: var(--code-bg);
|
| 892 |
+
}
|
| 893 |
+
|
| 894 |
+
.dashboard-shell {
|
| 895 |
+
display: block;
|
| 896 |
+
}
|
| 897 |
+
.dashboard-shell .dashboard-frame {
|
| 898 |
+
display: block;
|
| 899 |
+
width: 100%;
|
| 900 |
+
height: 900px;
|
| 901 |
+
border: 0;
|
| 902 |
+
background: var(--code-bg);
|
| 903 |
+
}
|
| 904 |
+
|
| 905 |
+
.unfurl.image {
|
| 906 |
+
padding: 0;
|
| 907 |
+
}
|
| 908 |
+
.unfurl.image img {
|
| 909 |
+
display: block;
|
| 910 |
+
width: 100%;
|
| 911 |
+
height: auto;
|
| 912 |
+
max-height: 460px;
|
| 913 |
+
object-fit: contain;
|
| 914 |
+
background: var(--code-bg);
|
| 915 |
+
}
|
| 916 |
+
|
| 917 |
+
.artifact-chip {
|
| 918 |
+
border: 1px solid var(--line);
|
| 919 |
+
background: var(--panel);
|
| 920 |
+
border-radius: var(--radius);
|
| 921 |
+
padding: 10px 14px;
|
| 922 |
+
margin: 8px 0;
|
| 923 |
+
font-size: 14px;
|
| 924 |
+
}
|
| 925 |
+
.cell.dashboard .artifact-chip {
|
| 926 |
+
margin: 14px 18px 18px;
|
| 927 |
+
}
|
| 928 |
+
.artifact-chip code {
|
| 929 |
+
color: var(--accent);
|
| 930 |
+
}
|
| 931 |
+
|
| 932 |
+
/* ---- task board ---- */
|
| 933 |
+
.board-wrap {
|
| 934 |
+
overflow-x: auto;
|
| 935 |
+
border: 1px solid var(--line);
|
| 936 |
+
border-radius: var(--radius);
|
| 937 |
+
margin: 12px 0 20px;
|
| 938 |
+
background: var(--panel);
|
| 939 |
+
}
|
| 940 |
+
table.board {
|
| 941 |
+
border-collapse: collapse;
|
| 942 |
+
width: 100%;
|
| 943 |
+
font-size: 14px;
|
| 944 |
+
}
|
| 945 |
+
table.board th,
|
| 946 |
+
table.board td {
|
| 947 |
+
text-align: left;
|
| 948 |
+
padding: 9px 14px;
|
| 949 |
+
border-bottom: 1px solid var(--line);
|
| 950 |
+
vertical-align: top;
|
| 951 |
+
}
|
| 952 |
+
table.board thead th {
|
| 953 |
+
background: var(--accent-soft);
|
| 954 |
+
font-size: 12px;
|
| 955 |
+
text-transform: uppercase;
|
| 956 |
+
letter-spacing: 0.05em;
|
| 957 |
+
color: #9a4a12;
|
| 958 |
+
font-weight: 600;
|
| 959 |
+
border-bottom: 1px solid var(--line);
|
| 960 |
+
}
|
| 961 |
+
table.board tbody tr:last-child td {
|
| 962 |
+
border-bottom: none;
|
| 963 |
+
}
|
| 964 |
+
table.board .col-check {
|
| 965 |
+
text-align: center;
|
| 966 |
+
width: 92px;
|
| 967 |
+
white-space: nowrap;
|
| 968 |
+
}
|
| 969 |
+
table.board tr.section-row td {
|
| 970 |
+
background: var(--accent-soft);
|
| 971 |
+
text-align: center;
|
| 972 |
+
font-weight: 700;
|
| 973 |
+
font-size: 13px;
|
| 974 |
+
color: var(--accent-strong);
|
| 975 |
+
padding: 7px 14px;
|
| 976 |
+
letter-spacing: 0.02em;
|
| 977 |
+
}
|
| 978 |
+
.box {
|
| 979 |
+
display: inline-flex;
|
| 980 |
+
align-items: center;
|
| 981 |
+
justify-content: center;
|
| 982 |
+
width: 18px;
|
| 983 |
+
height: 18px;
|
| 984 |
+
border: 1.5px solid #cfcbe0;
|
| 985 |
+
border-radius: 5px;
|
| 986 |
+
font-size: 12px;
|
| 987 |
+
color: #fff;
|
| 988 |
+
line-height: 1;
|
| 989 |
+
}
|
| 990 |
+
.box.on {
|
| 991 |
+
background: var(--accent);
|
| 992 |
+
border-color: var(--accent);
|
| 993 |
+
}
|
| 994 |
+
.who-chip {
|
| 995 |
+
display: inline-block;
|
| 996 |
+
padding: 3px 12px;
|
| 997 |
+
border-radius: 999px;
|
| 998 |
+
font-size: 12.5px;
|
| 999 |
+
font-weight: 600;
|
| 1000 |
+
white-space: nowrap;
|
| 1001 |
+
}
|
| 1002 |
+
.who-chip.muted {
|
| 1003 |
+
background: var(--code-bg);
|
| 1004 |
+
color: var(--muted);
|
| 1005 |
+
font-weight: 500;
|
| 1006 |
+
}
|
| 1007 |
+
|
| 1008 |
+
/* ---- status badges + clickable rows ---- */
|
| 1009 |
+
table.board .col-status {
|
| 1010 |
+
width: 130px;
|
| 1011 |
+
white-space: nowrap;
|
| 1012 |
+
}
|
| 1013 |
+
.badge {
|
| 1014 |
+
display: inline-block;
|
| 1015 |
+
padding: 3px 11px;
|
| 1016 |
+
border-radius: 999px;
|
| 1017 |
+
font-size: 12px;
|
| 1018 |
+
font-weight: 600;
|
| 1019 |
+
letter-spacing: 0.01em;
|
| 1020 |
+
}
|
| 1021 |
+
.badge.gray {
|
| 1022 |
+
background: var(--code-bg);
|
| 1023 |
+
color: var(--muted);
|
| 1024 |
+
}
|
| 1025 |
+
.badge.amber {
|
| 1026 |
+
background: var(--accent-soft);
|
| 1027 |
+
color: #b45309;
|
| 1028 |
+
}
|
| 1029 |
+
.badge.green {
|
| 1030 |
+
background: #e6f7ee;
|
| 1031 |
+
color: #1a8a55;
|
| 1032 |
+
}
|
| 1033 |
+
.badge.red {
|
| 1034 |
+
background: #fde8ec;
|
| 1035 |
+
color: #c62a4b;
|
| 1036 |
+
}
|
| 1037 |
+
table.board tr.linked-row {
|
| 1038 |
+
cursor: pointer;
|
| 1039 |
+
}
|
| 1040 |
+
table.board tr.linked-row:hover td {
|
| 1041 |
+
background: var(--accent-soft);
|
| 1042 |
+
}
|
| 1043 |
+
table.board tr.linked-row a {
|
| 1044 |
+
color: var(--ink);
|
| 1045 |
+
font-weight: 600;
|
| 1046 |
+
text-decoration: none;
|
| 1047 |
+
}
|
| 1048 |
+
table.board tr.linked-row:hover a {
|
| 1049 |
+
color: var(--accent-strong);
|
| 1050 |
+
}
|
| 1051 |
+
|
| 1052 |
+
/* ---- agent read hint ---- */
|
| 1053 |
+
.agent-hint {
|
| 1054 |
+
display: flex;
|
| 1055 |
+
align-items: center;
|
| 1056 |
+
flex-wrap: wrap;
|
| 1057 |
+
gap: 8px;
|
| 1058 |
+
margin: 4px 0 22px;
|
| 1059 |
+
font-size: 12.5px;
|
| 1060 |
+
color: var(--muted);
|
| 1061 |
+
}
|
| 1062 |
+
#page .agent-hint code {
|
| 1063 |
+
background: var(--code-bg);
|
| 1064 |
+
padding: 2px 9px;
|
| 1065 |
+
border-radius: 6px;
|
| 1066 |
+
font-family: var(--mono);
|
| 1067 |
+
font-size: 12px;
|
| 1068 |
+
font-weight: 500;
|
| 1069 |
+
color: var(--ink);
|
| 1070 |
+
}
|
| 1071 |
+
.agent-hint .copy {
|
| 1072 |
+
flex: 0 0 auto;
|
| 1073 |
+
background: none;
|
| 1074 |
+
color: var(--muted);
|
| 1075 |
+
border: 1px solid var(--line);
|
| 1076 |
+
border-radius: 6px;
|
| 1077 |
+
width: 22px;
|
| 1078 |
+
height: 22px;
|
| 1079 |
+
font-size: 11px;
|
| 1080 |
+
line-height: 1;
|
| 1081 |
+
cursor: pointer;
|
| 1082 |
+
transition: color 0.12s, border-color 0.12s;
|
| 1083 |
+
}
|
| 1084 |
+
.agent-hint .copy:hover {
|
| 1085 |
+
color: var(--accent-strong);
|
| 1086 |
+
border-color: var(--accent);
|
| 1087 |
+
}
|
| 1088 |
+
.agent-hint .copy.copied {
|
| 1089 |
+
color: #1a8a55;
|
| 1090 |
+
border-color: #1a8a55;
|
| 1091 |
+
}
|
| 1092 |
+
.agent-hint-note {
|
| 1093 |
+
margin-left: auto;
|
| 1094 |
+
font-size: 12px;
|
| 1095 |
+
color: var(--muted);
|
| 1096 |
+
}
|
| 1097 |
+
|
| 1098 |
+
/* ---- logbook summary stats ---- */
|
| 1099 |
+
.logbook-stats {
|
| 1100 |
+
display: flex;
|
| 1101 |
+
flex-wrap: wrap;
|
| 1102 |
+
gap: 12px;
|
| 1103 |
+
margin: 0 0 28px;
|
| 1104 |
+
}
|
| 1105 |
+
.stat-tile {
|
| 1106 |
+
position: relative;
|
| 1107 |
+
display: inline-flex;
|
| 1108 |
+
align-items: center;
|
| 1109 |
+
gap: 11px;
|
| 1110 |
+
border: 1px solid var(--line);
|
| 1111 |
+
background: var(--panel);
|
| 1112 |
+
border-radius: var(--radius);
|
| 1113 |
+
padding: 12px 23px;
|
| 1114 |
+
font: inherit;
|
| 1115 |
+
text-align: left;
|
| 1116 |
+
cursor: pointer;
|
| 1117 |
+
transition: border-color 0.12s, box-shadow 0.12s;
|
| 1118 |
+
}
|
| 1119 |
+
.stat-tile:hover:not([disabled]) {
|
| 1120 |
+
border-color: rgba(249, 115, 22, 0.45);
|
| 1121 |
+
box-shadow: 0 3px 12px rgba(31, 41, 55, 0.06);
|
| 1122 |
+
}
|
| 1123 |
+
.stat-tile:focus-visible {
|
| 1124 |
+
outline: 2px solid var(--accent);
|
| 1125 |
+
outline-offset: 2px;
|
| 1126 |
+
}
|
| 1127 |
+
.stat-tile[disabled] {
|
| 1128 |
+
cursor: default;
|
| 1129 |
+
opacity: 0.7;
|
| 1130 |
+
}
|
| 1131 |
+
.stat-tile.open {
|
| 1132 |
+
border-color: rgba(249, 115, 22, 0.6);
|
| 1133 |
+
box-shadow: 0 3px 12px rgba(31, 41, 55, 0.08);
|
| 1134 |
+
}
|
| 1135 |
+
.stat-icon {
|
| 1136 |
+
width: 24px;
|
| 1137 |
+
height: 24px;
|
| 1138 |
+
flex: 0 0 24px;
|
| 1139 |
+
object-fit: contain;
|
| 1140 |
+
align-self: center;
|
| 1141 |
+
}
|
| 1142 |
+
.stat-text {
|
| 1143 |
+
display: flex;
|
| 1144 |
+
align-items: baseline;
|
| 1145 |
+
gap: 8px;
|
| 1146 |
+
white-space: nowrap;
|
| 1147 |
+
line-height: 1;
|
| 1148 |
+
}
|
| 1149 |
+
.stat-num {
|
| 1150 |
+
font-family: var(--mono);
|
| 1151 |
+
font-size: 20px;
|
| 1152 |
+
font-weight: 600;
|
| 1153 |
+
line-height: 1;
|
| 1154 |
+
color: var(--accent-strong);
|
| 1155 |
+
}
|
| 1156 |
+
.stat-label {
|
| 1157 |
+
font-size: 15px;
|
| 1158 |
+
line-height: 1;
|
| 1159 |
+
color: var(--muted);
|
| 1160 |
+
}
|
| 1161 |
+
.stat-caret {
|
| 1162 |
+
margin-left: 2px;
|
| 1163 |
+
font-size: 10px;
|
| 1164 |
+
color: var(--muted);
|
| 1165 |
+
align-self: center;
|
| 1166 |
+
transition: transform 0.12s;
|
| 1167 |
+
}
|
| 1168 |
+
.stat-tile.open .stat-caret {
|
| 1169 |
+
transform: rotate(180deg);
|
| 1170 |
+
}
|
| 1171 |
+
.stat-popover {
|
| 1172 |
+
position: absolute;
|
| 1173 |
+
top: 100%;
|
| 1174 |
+
left: 0;
|
| 1175 |
+
margin-top: 6px;
|
| 1176 |
+
min-width: 300px;
|
| 1177 |
+
max-width: min(460px, 92vw);
|
| 1178 |
+
max-height: 340px;
|
| 1179 |
+
overflow-y: auto;
|
| 1180 |
+
z-index: 20;
|
| 1181 |
+
background: var(--panel);
|
| 1182 |
+
border: 1px solid var(--line);
|
| 1183 |
+
border-radius: var(--radius);
|
| 1184 |
+
box-shadow: 0 8px 28px rgba(31, 41, 55, 0.12);
|
| 1185 |
+
padding: 6px;
|
| 1186 |
+
}
|
| 1187 |
+
.stat-popover[hidden] {
|
| 1188 |
+
display: none;
|
| 1189 |
+
}
|
| 1190 |
+
.stat-pop-head {
|
| 1191 |
+
padding: 6px 10px 8px;
|
| 1192 |
+
font-size: 11.5px;
|
| 1193 |
+
font-weight: 700;
|
| 1194 |
+
letter-spacing: 0.03em;
|
| 1195 |
+
text-transform: uppercase;
|
| 1196 |
+
color: var(--muted);
|
| 1197 |
+
}
|
| 1198 |
+
.stat-row {
|
| 1199 |
+
display: flex;
|
| 1200 |
+
align-items: flex-start;
|
| 1201 |
+
gap: 10px;
|
| 1202 |
+
padding: 9px 11px;
|
| 1203 |
+
border-radius: 9px;
|
| 1204 |
+
border: 1px solid transparent;
|
| 1205 |
+
text-decoration: none;
|
| 1206 |
+
color: inherit;
|
| 1207 |
+
cursor: pointer;
|
| 1208 |
+
}
|
| 1209 |
+
.stat-row:hover {
|
| 1210 |
+
border-color: rgba(249, 115, 22, 0.4);
|
| 1211 |
+
background: var(--accent-soft);
|
| 1212 |
+
}
|
| 1213 |
+
.stat-row-ico {
|
| 1214 |
+
font-size: 15px;
|
| 1215 |
+
line-height: 1.3;
|
| 1216 |
+
flex: 0 0 auto;
|
| 1217 |
+
}
|
| 1218 |
+
.stat-row-main {
|
| 1219 |
+
min-width: 0;
|
| 1220 |
+
flex: 1;
|
| 1221 |
+
}
|
| 1222 |
+
.stat-row-title {
|
| 1223 |
+
font-family: var(--mono);
|
| 1224 |
+
font-size: 12.5px;
|
| 1225 |
+
font-weight: 600;
|
| 1226 |
+
color: var(--ink);
|
| 1227 |
+
overflow: hidden;
|
| 1228 |
+
text-overflow: ellipsis;
|
| 1229 |
+
white-space: nowrap;
|
| 1230 |
+
}
|
| 1231 |
+
.stat-row-meta {
|
| 1232 |
+
margin-top: 2px;
|
| 1233 |
+
font-size: 12px;
|
| 1234 |
+
color: var(--muted);
|
| 1235 |
+
}
|
| 1236 |
+
.stat-row-state.open {
|
| 1237 |
+
color: var(--accent);
|
| 1238 |
+
font-weight: 600;
|
| 1239 |
+
border-radius: 5px;
|
| 1240 |
+
padding: 1px 5px;
|
| 1241 |
+
margin: -1px -2px;
|
| 1242 |
+
}
|
| 1243 |
+
.stat-row-state.open:hover {
|
| 1244 |
+
background: rgba(249, 115, 22, 0.14);
|
| 1245 |
+
text-decoration: underline;
|
| 1246 |
+
}
|
| 1247 |
+
.art-ico {
|
| 1248 |
+
width: 1em;
|
| 1249 |
+
height: 1em;
|
| 1250 |
+
object-fit: contain;
|
| 1251 |
+
vertical-align: -0.15em;
|
| 1252 |
+
}
|
| 1253 |
+
|
| 1254 |
+
/* ---- scroll-to-resource highlight ---- */
|
| 1255 |
+
.res-flash {
|
| 1256 |
+
animation: res-flash 1.5s ease;
|
| 1257 |
+
border-radius: 8px;
|
| 1258 |
+
}
|
| 1259 |
+
@keyframes res-flash {
|
| 1260 |
+
0%,
|
| 1261 |
+
25% {
|
| 1262 |
+
box-shadow: 0 0 0 3px var(--accent);
|
| 1263 |
+
}
|
| 1264 |
+
100% {
|
| 1265 |
+
box-shadow: 0 0 0 3px rgba(249, 115, 22, 0);
|
| 1266 |
+
}
|
| 1267 |
+
}
|
| 1268 |
+
|
| 1269 |
+
/* ---- inline resource chips ---- */
|
| 1270 |
+
#page .res-chip {
|
| 1271 |
+
display: inline-flex;
|
| 1272 |
+
align-items: center;
|
| 1273 |
+
gap: 5px;
|
| 1274 |
+
max-width: 100%;
|
| 1275 |
+
padding: 0 9px 0 6px;
|
| 1276 |
+
margin: 0 1px;
|
| 1277 |
+
border: 1px solid var(--line);
|
| 1278 |
+
border-radius: 999px;
|
| 1279 |
+
background: var(--panel);
|
| 1280 |
+
font-family: var(--mono);
|
| 1281 |
+
font-size: 0.78em;
|
| 1282 |
+
font-weight: 600;
|
| 1283 |
+
color: var(--ink);
|
| 1284 |
+
text-decoration: none;
|
| 1285 |
+
white-space: nowrap;
|
| 1286 |
+
overflow: hidden;
|
| 1287 |
+
text-overflow: ellipsis;
|
| 1288 |
+
vertical-align: middle;
|
| 1289 |
+
line-height: 1.65;
|
| 1290 |
+
transform: translateY(-0.08em);
|
| 1291 |
+
transition: border-color 0.12s, background 0.12s, color 0.12s;
|
| 1292 |
+
}
|
| 1293 |
+
.res-chip-ico {
|
| 1294 |
+
font-size: 1.05em;
|
| 1295 |
+
line-height: 1;
|
| 1296 |
+
}
|
| 1297 |
+
#page .res-chip:hover,
|
| 1298 |
+
#page .res-chip.res-hl {
|
| 1299 |
+
border-color: var(--accent);
|
| 1300 |
+
background: var(--accent-soft);
|
| 1301 |
+
color: var(--accent-strong);
|
| 1302 |
+
}
|
| 1303 |
+
#page a.res-link.res-hl {
|
| 1304 |
+
background: var(--accent-soft);
|
| 1305 |
+
border-radius: 4px;
|
| 1306 |
+
}
|
| 1307 |
+
.rail-item.res-hl {
|
| 1308 |
+
border-color: var(--accent);
|
| 1309 |
+
background: var(--accent-soft);
|
| 1310 |
+
box-shadow: 0 3px 12px rgba(249, 115, 22, 0.14);
|
| 1311 |
+
}
|
| 1312 |
+
.rail-item.res-hl .rail-title {
|
| 1313 |
+
color: var(--accent-strong);
|
| 1314 |
+
}
|
| 1315 |
+
.rail-item.rail-local {
|
| 1316 |
+
cursor: default;
|
| 1317 |
+
}
|
| 1318 |
+
.artifact-chip.res-hl {
|
| 1319 |
+
border-color: var(--accent);
|
| 1320 |
+
background: var(--accent-soft);
|
| 1321 |
+
}
|
| 1322 |
+
|
| 1323 |
+
/* ---- contextual resources rail ---- */
|
| 1324 |
+
.context-rail {
|
| 1325 |
+
position: relative;
|
| 1326 |
+
width: 248px;
|
| 1327 |
+
}
|
| 1328 |
+
.context-rail[hidden] {
|
| 1329 |
+
display: none;
|
| 1330 |
+
}
|
| 1331 |
+
.rail-kind {
|
| 1332 |
+
display: flex;
|
| 1333 |
+
align-items: center;
|
| 1334 |
+
gap: 5px;
|
| 1335 |
+
font-family: var(--mono);
|
| 1336 |
+
font-size: 10px;
|
| 1337 |
+
text-transform: uppercase;
|
| 1338 |
+
letter-spacing: 0.08em;
|
| 1339 |
+
font-weight: 600;
|
| 1340 |
+
color: var(--accent);
|
| 1341 |
+
margin-bottom: 4px;
|
| 1342 |
+
}
|
| 1343 |
+
.rail-item {
|
| 1344 |
+
position: absolute;
|
| 1345 |
+
left: 0;
|
| 1346 |
+
right: 0;
|
| 1347 |
+
display: block;
|
| 1348 |
+
border: 1px solid var(--line);
|
| 1349 |
+
border-radius: 10px;
|
| 1350 |
+
background: var(--panel);
|
| 1351 |
+
padding: 9px 12px;
|
| 1352 |
+
margin-bottom: 8px;
|
| 1353 |
+
text-decoration: none;
|
| 1354 |
+
color: inherit;
|
| 1355 |
+
transition: border-color 0.14s, box-shadow 0.14s;
|
| 1356 |
+
}
|
| 1357 |
+
.rail-item:hover {
|
| 1358 |
+
border-color: rgba(249, 115, 22, 0.45);
|
| 1359 |
+
box-shadow: 0 3px 12px rgba(31, 41, 55, 0.06);
|
| 1360 |
+
}
|
| 1361 |
+
.rail-title {
|
| 1362 |
+
font-family: var(--mono);
|
| 1363 |
+
font-size: 12.5px;
|
| 1364 |
+
font-weight: 600;
|
| 1365 |
+
color: var(--ink);
|
| 1366 |
+
overflow-wrap: anywhere;
|
| 1367 |
+
line-height: 1.4;
|
| 1368 |
+
}
|
| 1369 |
+
.rail-item:hover .rail-title {
|
| 1370 |
+
color: var(--accent-strong);
|
| 1371 |
+
}
|
| 1372 |
+
.rail-meta {
|
| 1373 |
+
font-size: 11.5px;
|
| 1374 |
+
color: var(--muted);
|
| 1375 |
+
margin-top: 2px;
|
| 1376 |
+
}
|
| 1377 |
+
|
| 1378 |
+
@media (max-width: 1400px) {
|
| 1379 |
+
.page-layout {
|
| 1380 |
+
display: block;
|
| 1381 |
+
}
|
| 1382 |
+
.context-rail {
|
| 1383 |
+
width: 100%;
|
| 1384 |
+
margin-top: 28px;
|
| 1385 |
+
position: static;
|
| 1386 |
+
min-height: 0 !important;
|
| 1387 |
+
display: grid;
|
| 1388 |
+
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
| 1389 |
+
gap: 10px;
|
| 1390 |
+
}
|
| 1391 |
+
.context-rail[hidden] {
|
| 1392 |
+
display: none;
|
| 1393 |
+
}
|
| 1394 |
+
.context-rail .rail-item {
|
| 1395 |
+
position: static;
|
| 1396 |
+
margin-bottom: 0;
|
| 1397 |
+
}
|
| 1398 |
+
}
|
| 1399 |
+
|
| 1400 |
+
/* ---- connect footer + modal ---- */
|
| 1401 |
+
#sidebar-foot {
|
| 1402 |
+
margin-top: auto;
|
| 1403 |
+
padding-top: 14px;
|
| 1404 |
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
| 1405 |
+
}
|
| 1406 |
+
|
| 1407 |
+
#connect-btn {
|
| 1408 |
+
width: 100%;
|
| 1409 |
+
display: flex;
|
| 1410 |
+
align-items: center;
|
| 1411 |
+
gap: 8px;
|
| 1412 |
+
background: rgba(255, 255, 255, 0.05);
|
| 1413 |
+
color: #c3c4cb;
|
| 1414 |
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
| 1415 |
+
border-radius: 9px;
|
| 1416 |
+
padding: 9px 12px;
|
| 1417 |
+
font-size: 13.5px;
|
| 1418 |
+
font-family: var(--sans);
|
| 1419 |
+
cursor: pointer;
|
| 1420 |
+
transition: background 0.12s, color 0.12s, border-color 0.12s;
|
| 1421 |
+
}
|
| 1422 |
+
#connect-btn:hover {
|
| 1423 |
+
background: rgba(249, 115, 22, 0.14);
|
| 1424 |
+
border-color: rgba(249, 115, 22, 0.4);
|
| 1425 |
+
color: #fdba74;
|
| 1426 |
+
}
|
| 1427 |
+
#connect-btn .ico {
|
| 1428 |
+
font-size: 15px;
|
| 1429 |
+
}
|
| 1430 |
+
|
| 1431 |
+
#modal[hidden] {
|
| 1432 |
+
display: none;
|
| 1433 |
+
}
|
| 1434 |
+
#modal {
|
| 1435 |
+
position: fixed;
|
| 1436 |
+
inset: 0;
|
| 1437 |
+
z-index: 100;
|
| 1438 |
+
display: flex;
|
| 1439 |
+
align-items: center;
|
| 1440 |
+
justify-content: center;
|
| 1441 |
+
padding: 24px;
|
| 1442 |
+
}
|
| 1443 |
+
.modal-backdrop {
|
| 1444 |
+
position: absolute;
|
| 1445 |
+
inset: 0;
|
| 1446 |
+
background: rgba(20, 18, 30, 0.5);
|
| 1447 |
+
backdrop-filter: blur(2px);
|
| 1448 |
+
}
|
| 1449 |
+
.modal-card {
|
| 1450 |
+
position: relative;
|
| 1451 |
+
background: var(--panel);
|
| 1452 |
+
border-radius: 16px;
|
| 1453 |
+
width: 100%;
|
| 1454 |
+
max-width: 620px;
|
| 1455 |
+
max-height: 85vh;
|
| 1456 |
+
overflow-y: auto;
|
| 1457 |
+
box-shadow: 0 24px 70px rgba(20, 15, 50, 0.28);
|
| 1458 |
+
}
|
| 1459 |
+
.modal-head {
|
| 1460 |
+
display: flex;
|
| 1461 |
+
align-items: center;
|
| 1462 |
+
justify-content: space-between;
|
| 1463 |
+
gap: 12px;
|
| 1464 |
+
padding: 18px 22px;
|
| 1465 |
+
border-bottom: 1px solid var(--line);
|
| 1466 |
+
position: sticky;
|
| 1467 |
+
top: 0;
|
| 1468 |
+
background: var(--panel);
|
| 1469 |
+
}
|
| 1470 |
+
.modal-title {
|
| 1471 |
+
display: flex;
|
| 1472 |
+
align-items: center;
|
| 1473 |
+
gap: 10px;
|
| 1474 |
+
font-family: var(--serif);
|
| 1475 |
+
font-size: 21px;
|
| 1476 |
+
letter-spacing: -0.01em;
|
| 1477 |
+
}
|
| 1478 |
+
.modal-logo {
|
| 1479 |
+
width: 26px;
|
| 1480 |
+
height: 26px;
|
| 1481 |
+
object-fit: contain;
|
| 1482 |
+
}
|
| 1483 |
+
.modal-actions {
|
| 1484 |
+
display: flex;
|
| 1485 |
+
align-items: center;
|
| 1486 |
+
gap: 8px;
|
| 1487 |
+
}
|
| 1488 |
+
.btn {
|
| 1489 |
+
font-family: var(--sans);
|
| 1490 |
+
font-size: 13.5px;
|
| 1491 |
+
font-weight: 600;
|
| 1492 |
+
border: 1px solid var(--line);
|
| 1493 |
+
background: var(--panel);
|
| 1494 |
+
color: var(--ink);
|
| 1495 |
+
border-radius: 9px;
|
| 1496 |
+
padding: 8px 13px;
|
| 1497 |
+
cursor: pointer;
|
| 1498 |
+
transition: background 0.12s, border-color 0.12s, color 0.12s;
|
| 1499 |
+
}
|
| 1500 |
+
.btn:hover {
|
| 1501 |
+
border-color: var(--accent);
|
| 1502 |
+
color: var(--accent-strong);
|
| 1503 |
+
}
|
| 1504 |
+
.btn.copied {
|
| 1505 |
+
border-color: #1a8a55;
|
| 1506 |
+
color: #1a8a55;
|
| 1507 |
+
}
|
| 1508 |
+
.btn.icon {
|
| 1509 |
+
font-size: 18px;
|
| 1510 |
+
line-height: 1;
|
| 1511 |
+
padding: 6px 11px;
|
| 1512 |
+
font-weight: 400;
|
| 1513 |
+
}
|
| 1514 |
+
.modal-body {
|
| 1515 |
+
padding: 20px 22px 26px;
|
| 1516 |
+
}
|
| 1517 |
+
.modal-intro {
|
| 1518 |
+
margin: 0 0 20px;
|
| 1519 |
+
color: var(--muted);
|
| 1520 |
+
line-height: 1.55;
|
| 1521 |
+
}
|
| 1522 |
+
#connect-steps {
|
| 1523 |
+
list-style: none;
|
| 1524 |
+
margin: 0;
|
| 1525 |
+
padding: 0;
|
| 1526 |
+
}
|
| 1527 |
+
#connect-steps li {
|
| 1528 |
+
margin-bottom: 18px;
|
| 1529 |
+
}
|
| 1530 |
+
.step-title {
|
| 1531 |
+
font-weight: 600;
|
| 1532 |
+
font-size: 14.5px;
|
| 1533 |
+
margin-bottom: 8px;
|
| 1534 |
+
}
|
| 1535 |
+
.codeblock {
|
| 1536 |
+
display: flex;
|
| 1537 |
+
align-items: center;
|
| 1538 |
+
gap: 8px;
|
| 1539 |
+
background: #17181c;
|
| 1540 |
+
border-radius: 10px;
|
| 1541 |
+
padding: 11px 12px 11px 15px;
|
| 1542 |
+
}
|
| 1543 |
+
.codeblock code {
|
| 1544 |
+
flex: 1;
|
| 1545 |
+
min-width: 0;
|
| 1546 |
+
overflow-x: auto;
|
| 1547 |
+
white-space: nowrap;
|
| 1548 |
+
font-family: var(--mono);
|
| 1549 |
+
font-size: 13px;
|
| 1550 |
+
color: #f0efff;
|
| 1551 |
+
background: none;
|
| 1552 |
+
padding: 0;
|
| 1553 |
+
}
|
| 1554 |
+
.codeblock .copy {
|
| 1555 |
+
flex: 0 0 auto;
|
| 1556 |
+
background: rgba(255, 255, 255, 0.08);
|
| 1557 |
+
color: #c3c4cb;
|
| 1558 |
+
border: 1px solid rgba(255, 255, 255, 0.14);
|
| 1559 |
+
border-radius: 7px;
|
| 1560 |
+
width: 30px;
|
| 1561 |
+
height: 30px;
|
| 1562 |
+
font-size: 14px;
|
| 1563 |
+
cursor: pointer;
|
| 1564 |
+
transition: background 0.12s, color 0.12s;
|
| 1565 |
+
}
|
| 1566 |
+
.codeblock .copy:hover {
|
| 1567 |
+
background: rgba(249, 115, 22, 0.2);
|
| 1568 |
+
color: #fdba74;
|
| 1569 |
+
}
|
| 1570 |
+
.codeblock .copy.copied {
|
| 1571 |
+
color: #52d08a;
|
| 1572 |
+
}
|
| 1573 |
+
|
| 1574 |
+
@media (max-width: 720px) {
|
| 1575 |
+
#app {
|
| 1576 |
+
flex-direction: column;
|
| 1577 |
+
}
|
| 1578 |
+
#sidebar {
|
| 1579 |
+
width: 100%;
|
| 1580 |
+
flex: none;
|
| 1581 |
+
height: auto;
|
| 1582 |
+
position: static;
|
| 1583 |
+
}
|
| 1584 |
+
#content {
|
| 1585 |
+
display: block;
|
| 1586 |
+
width: 100%;
|
| 1587 |
+
padding: 28px 20px 80px;
|
| 1588 |
+
overflow-x: hidden;
|
| 1589 |
+
}
|
| 1590 |
+
#page {
|
| 1591 |
+
width: 100%;
|
| 1592 |
+
max-width: 100%;
|
| 1593 |
+
}
|
| 1594 |
+
#page h1 {
|
| 1595 |
+
font-size: 30px;
|
| 1596 |
+
}
|
| 1597 |
+
.cell-head {
|
| 1598 |
+
align-items: flex-start;
|
| 1599 |
+
flex-direction: column;
|
| 1600 |
+
gap: 4px;
|
| 1601 |
+
}
|
| 1602 |
+
}
|
logbook.js
ADDED
|
@@ -0,0 +1,2275 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(function () {
|
| 2 |
+
"use strict";
|
| 3 |
+
|
| 4 |
+
let MANIFEST = null;
|
| 5 |
+
const PAGE_CACHE = {};
|
| 6 |
+
const UNFURL_CACHE = {};
|
| 7 |
+
const LIVE_RELOAD_MS = 1500;
|
| 8 |
+
const FIGURE_FRAME_WINDOWS = new Set();
|
| 9 |
+
let FIGURE_NAVIGATION_READY = false;
|
| 10 |
+
|
| 11 |
+
function esc(s) {
|
| 12 |
+
return String(s)
|
| 13 |
+
.replace(/&/g, "&")
|
| 14 |
+
.replace(/</g, "<")
|
| 15 |
+
.replace(/>/g, ">")
|
| 16 |
+
.replace(/"/g, """)
|
| 17 |
+
.replace(/'/g, "'");
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
function flattenTree(node, depth, acc) {
|
| 21 |
+
acc.push({ node: node, depth: depth });
|
| 22 |
+
(node.children || []).forEach((c) => flattenTree(c, depth + 1, acc));
|
| 23 |
+
return acc;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
function findNode(node, slug) {
|
| 27 |
+
if (node.slug === slug) return node;
|
| 28 |
+
for (const c of node.children || []) {
|
| 29 |
+
const hit = findNode(c, slug);
|
| 30 |
+
if (hit) return hit;
|
| 31 |
+
}
|
| 32 |
+
return null;
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
/* -------------------- minimal markdown -------------------- */
|
| 36 |
+
|
| 37 |
+
function inline(text) {
|
| 38 |
+
let t = esc(text);
|
| 39 |
+
t = t.replace(/`([^`]+)`/g, (_, c) => `<code>${c}</code>`);
|
| 40 |
+
t = t.replace(/\*\*([^*]+)\*\*/g, (_, c) => `<strong>${c}</strong>`);
|
| 41 |
+
t = t.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, txt, url) => {
|
| 42 |
+
const safe = esc(url);
|
| 43 |
+
const attrs = /^https?:/.test(url) ? ' target="_blank" rel="noopener"' : "";
|
| 44 |
+
const item = /^https?:/.test(url) ? classifyResource(url) : null;
|
| 45 |
+
const data = item
|
| 46 |
+
? ` class="res-link" data-res-url="${esc(item.url)}"`
|
| 47 |
+
: "";
|
| 48 |
+
return `<a href="${safe}"${attrs}${data}>${txt}</a>`;
|
| 49 |
+
});
|
| 50 |
+
t = t.replace(/(^|[\s(])(https?:\/\/[^\s<>)"'`]+)/g, (m, pre, url) => {
|
| 51 |
+
let rest = "";
|
| 52 |
+
const cut = url.search(/"|'|<|>/);
|
| 53 |
+
if (cut !== -1) {
|
| 54 |
+
rest = url.slice(cut);
|
| 55 |
+
url = url.slice(0, cut);
|
| 56 |
+
}
|
| 57 |
+
const trailing = (url.match(/[.,;:!?`]+$/) || [""])[0];
|
| 58 |
+
const clean = trailing ? url.slice(0, -trailing.length) : url;
|
| 59 |
+
if (!clean) return m;
|
| 60 |
+
const item = classifyResource(clean);
|
| 61 |
+
if (item) return `${pre}${resChipHtml(item)}${trailing}${rest}`;
|
| 62 |
+
return `${pre}<a href="${clean}" target="_blank" rel="noopener">${clean}</a>${trailing}${rest}`;
|
| 63 |
+
});
|
| 64 |
+
return t;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
function resChipHtml(item) {
|
| 68 |
+
return (
|
| 69 |
+
`<a class="res-chip" href="${esc(item.url)}" target="_blank" ` +
|
| 70 |
+
`rel="noopener" data-res-url="${esc(item.url)}">` +
|
| 71 |
+
`<span class="res-chip-ico">${RESOURCE_ICONS[item.kind]}</span>` +
|
| 72 |
+
`${esc(item.id)}</a>`
|
| 73 |
+
);
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
const URL_ONLY = /^(https?:\/\/[^\s]+)$/;
|
| 77 |
+
const DETECTED_URL =
|
| 78 |
+
/(https?:\/\/[^\s<>)\]"'`]+|trackio-local-dashboard:\/\/[^\s<>)\]"'`]+|trackio-artifact:\/\/[^\s<>)\]"'`]+|trackio-local-path:\/\/[^\s<>)\]"'`]+)/g;
|
| 79 |
+
|
| 80 |
+
function renderMarkdown(md, container) {
|
| 81 |
+
const cellRe = /(^|\n)---\n<!-- trackio-cell\n([\s\S]*?)\n-->\n([\s\S]*?)(?=\n---\n<!-- trackio-cell\n|\s*$)/g;
|
| 82 |
+
const tokens = [];
|
| 83 |
+
let pos = 0;
|
| 84 |
+
let found = false;
|
| 85 |
+
let match;
|
| 86 |
+
while ((match = cellRe.exec(md))) {
|
| 87 |
+
found = true;
|
| 88 |
+
tokens.push({
|
| 89 |
+
kind: "md",
|
| 90 |
+
text: md.slice(pos, match.index + match[1].length),
|
| 91 |
+
});
|
| 92 |
+
tokens.push({
|
| 93 |
+
kind: "cell",
|
| 94 |
+
meta: parseCellMeta(match[2]),
|
| 95 |
+
body: match[3],
|
| 96 |
+
});
|
| 97 |
+
pos = match.index + match[0].length;
|
| 98 |
+
}
|
| 99 |
+
tokens.push({ kind: "md", text: found ? md.slice(pos) : md });
|
| 100 |
+
|
| 101 |
+
for (let i = 0; i < tokens.length; i++) {
|
| 102 |
+
const t = tokens[i];
|
| 103 |
+
if (t.kind === "md") {
|
| 104 |
+
renderMarkdownPlain(t.text, container);
|
| 105 |
+
continue;
|
| 106 |
+
}
|
| 107 |
+
if (t.consumed) continue;
|
| 108 |
+
if (t.meta.type === "code") {
|
| 109 |
+
const arts = [];
|
| 110 |
+
for (let j = i + 1; j < tokens.length; j++) {
|
| 111 |
+
const n = tokens[j];
|
| 112 |
+
if (n.kind === "md") {
|
| 113 |
+
if (n.text.trim() === "") continue;
|
| 114 |
+
break;
|
| 115 |
+
}
|
| 116 |
+
if (n.meta.type === "artifact") {
|
| 117 |
+
arts.push(n);
|
| 118 |
+
n.consumed = true;
|
| 119 |
+
continue;
|
| 120 |
+
}
|
| 121 |
+
break;
|
| 122 |
+
}
|
| 123 |
+
renderCell(t.meta, t.body, container, arts);
|
| 124 |
+
} else {
|
| 125 |
+
renderCell(t.meta, t.body, container);
|
| 126 |
+
}
|
| 127 |
+
}
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
function parseCellMeta(raw) {
|
| 131 |
+
try {
|
| 132 |
+
return JSON.parse(raw);
|
| 133 |
+
} catch (e) {
|
| 134 |
+
return { type: "markdown", title: "Note" };
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
function renderMarkdownPlain(md, container) {
|
| 139 |
+
const lines = md.replace(/<!--[\s\S]*?-->/g, "").split("\n");
|
| 140 |
+
let i = 0;
|
| 141 |
+
let para = [];
|
| 142 |
+
|
| 143 |
+
function flushPara() {
|
| 144 |
+
if (!para.length) return;
|
| 145 |
+
const joined = para.join(" ").trim();
|
| 146 |
+
para = [];
|
| 147 |
+
if (!joined) return;
|
| 148 |
+
if (/^trackio-artifact:\/\/\S+$/.test(joined)) return;
|
| 149 |
+
if (/^trackio-local-path:\/\/\S+$/.test(joined)) return;
|
| 150 |
+
if (joined.indexOf("π¦ Artifact") !== -1) {
|
| 151 |
+
const div = document.createElement("div");
|
| 152 |
+
div.className = "artifact-chip";
|
| 153 |
+
div.innerHTML = ARTIFACT_ICON_IMG + inline(joined.replace(/π¦\s*/, ""));
|
| 154 |
+
container.appendChild(div);
|
| 155 |
+
return;
|
| 156 |
+
}
|
| 157 |
+
if (URL_ONLY.test(joined) || IMG_PATH.test(joined)) {
|
| 158 |
+
const el = renderStandaloneUrl(joined);
|
| 159 |
+
if (el) container.appendChild(el);
|
| 160 |
+
return;
|
| 161 |
+
}
|
| 162 |
+
const p = document.createElement("p");
|
| 163 |
+
p.innerHTML = inline(joined);
|
| 164 |
+
container.appendChild(p);
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
while (i < lines.length) {
|
| 168 |
+
const line = lines[i];
|
| 169 |
+
const trimmed = line.trim();
|
| 170 |
+
|
| 171 |
+
if (trimmed === "") {
|
| 172 |
+
flushPara();
|
| 173 |
+
i++;
|
| 174 |
+
continue;
|
| 175 |
+
}
|
| 176 |
+
const fence = trimmed.match(/^(`{3,}|~{3,})(.*)$/);
|
| 177 |
+
if (fence) {
|
| 178 |
+
flushPara();
|
| 179 |
+
const marker = fence[1][0];
|
| 180 |
+
const closeRe = new RegExp("^" + marker + "{" + fence[1].length + ",}\\s*$");
|
| 181 |
+
const info = fence[2].trim();
|
| 182 |
+
const buf = [];
|
| 183 |
+
i++;
|
| 184 |
+
while (i < lines.length && !closeRe.test(lines[i].trim())) {
|
| 185 |
+
buf.push(lines[i]);
|
| 186 |
+
i++;
|
| 187 |
+
}
|
| 188 |
+
i++;
|
| 189 |
+
const lang = (info.split(/\s+/)[0] || "").toLowerCase();
|
| 190 |
+
const tm = info.match(/title=(\S+)/);
|
| 191 |
+
container.appendChild(
|
| 192 |
+
renderCode(buf.join("\n"), lang, tm ? tm[1] : null)
|
| 193 |
+
);
|
| 194 |
+
continue;
|
| 195 |
+
}
|
| 196 |
+
if (trimmed === "---") {
|
| 197 |
+
flushPara();
|
| 198 |
+
container.appendChild(document.createElement("hr"));
|
| 199 |
+
i++;
|
| 200 |
+
continue;
|
| 201 |
+
}
|
| 202 |
+
const h = trimmed.match(/^(#{1,4})\s+(.*)$/);
|
| 203 |
+
if (h) {
|
| 204 |
+
flushPara();
|
| 205 |
+
const el = document.createElement("h" + h[1].length);
|
| 206 |
+
el.innerHTML = inline(h[2]);
|
| 207 |
+
container.appendChild(el);
|
| 208 |
+
i++;
|
| 209 |
+
continue;
|
| 210 |
+
}
|
| 211 |
+
if (
|
| 212 |
+
trimmed.startsWith("|") &&
|
| 213 |
+
i + 1 < lines.length &&
|
| 214 |
+
/^\|?[\s:|-]*-{2,}[\s:|-]*\|?$/.test(lines[i + 1].trim())
|
| 215 |
+
) {
|
| 216 |
+
flushPara();
|
| 217 |
+
const rows = [];
|
| 218 |
+
while (i < lines.length && lines[i].trim().startsWith("|")) {
|
| 219 |
+
rows.push(parseRow(lines[i].trim()));
|
| 220 |
+
i++;
|
| 221 |
+
}
|
| 222 |
+
renderTable(rows, container);
|
| 223 |
+
continue;
|
| 224 |
+
}
|
| 225 |
+
if (trimmed.startsWith("> ")) {
|
| 226 |
+
flushPara();
|
| 227 |
+
const bq = document.createElement("blockquote");
|
| 228 |
+
bq.innerHTML = inline(trimmed.slice(2));
|
| 229 |
+
container.appendChild(bq);
|
| 230 |
+
i++;
|
| 231 |
+
continue;
|
| 232 |
+
}
|
| 233 |
+
if (/^`[^`]+`$/.test(trimmed)) {
|
| 234 |
+
flushPara();
|
| 235 |
+
const el = document.createElement("div");
|
| 236 |
+
el.className = "ts";
|
| 237 |
+
el.textContent = trimmed.replace(/`/g, "");
|
| 238 |
+
container.appendChild(el);
|
| 239 |
+
i++;
|
| 240 |
+
continue;
|
| 241 |
+
}
|
| 242 |
+
if (trimmed.startsWith("- ")) {
|
| 243 |
+
flushPara();
|
| 244 |
+
const items = [];
|
| 245 |
+
while (i < lines.length && lines[i].trim().startsWith("- ")) {
|
| 246 |
+
items.push(lines[i].trim().slice(2).trim());
|
| 247 |
+
i++;
|
| 248 |
+
}
|
| 249 |
+
renderList(items, container);
|
| 250 |
+
continue;
|
| 251 |
+
}
|
| 252 |
+
para.push(trimmed);
|
| 253 |
+
i++;
|
| 254 |
+
}
|
| 255 |
+
flushPara();
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
function renderCell(meta, body, container, artifacts) {
|
| 259 |
+
const cell = document.createElement("section");
|
| 260 |
+
cell.className = `cell ${meta.type || "markdown"}`;
|
| 261 |
+
if (meta.id) cell.dataset.cellId = meta.id;
|
| 262 |
+
if (isPinned(meta)) cell.classList.add("pinned-source");
|
| 263 |
+
|
| 264 |
+
const head = document.createElement("div");
|
| 265 |
+
head.className = "cell-head";
|
| 266 |
+
const rawTitle = (meta.title || "").trim();
|
| 267 |
+
const title = rawTitle && rawTitle.toLowerCase() !== "untitled" ? esc(rawTitle) : "";
|
| 268 |
+
const when = meta.created_at ? `<span>${esc(formatTime(meta.created_at))}</span>` : "";
|
| 269 |
+
head.innerHTML =
|
| 270 |
+
(title ? `<div class="cell-title">${title}</div>` : "") +
|
| 271 |
+
`<div class="cell-meta">${when}</div>`;
|
| 272 |
+
if (!title) head.classList.add("no-title");
|
| 273 |
+
cell.appendChild(head);
|
| 274 |
+
|
| 275 |
+
const bodyEl = document.createElement("div");
|
| 276 |
+
bodyEl.className = "cell-body";
|
| 277 |
+
if (meta.type === "code") {
|
| 278 |
+
renderCodeCell(body, bodyEl, artifacts);
|
| 279 |
+
} else if (meta.type === "figure") {
|
| 280 |
+
cell.dataset.resUrl = `trackio-figure://${(meta.title || "Figure").trim()}`;
|
| 281 |
+
renderFigureCell(body, bodyEl, head);
|
| 282 |
+
} else if (meta.type === "artifact") {
|
| 283 |
+
renderMarkdownPlain(body, bodyEl);
|
| 284 |
+
const chip = bodyEl.querySelector(".artifact-chip");
|
| 285 |
+
const uri = body.match(
|
| 286 |
+
/(trackio-artifact:\/\/\S+|trackio-local-path:\/\/\S+|https:\/\/huggingface\.co\/buckets\/[^\s<)]+#\S+)/
|
| 287 |
+
);
|
| 288 |
+
if (chip && uri) chip.dataset.resUrl = uri[1];
|
| 289 |
+
} else if (meta.type === "dashboard") {
|
| 290 |
+
const sp = body.match(/https:\/\/huggingface\.co\/spaces\/[^\s<>)"'`]+/);
|
| 291 |
+
cell.dataset.resUrl = sp
|
| 292 |
+
? sp[0]
|
| 293 |
+
: `trackio-local-dashboard://${(meta.dashboard_project || "").trim()}`;
|
| 294 |
+
renderDashboardCell(meta, body, bodyEl, head);
|
| 295 |
+
} else {
|
| 296 |
+
const cleaned = stripDuplicateTitle(body, meta.title);
|
| 297 |
+
renderMarkdownPlain(cleaned, bodyEl);
|
| 298 |
+
renderDetectedEmbeds(cleaned, bodyEl);
|
| 299 |
+
}
|
| 300 |
+
cell.appendChild(bodyEl);
|
| 301 |
+
container.appendChild(cell);
|
| 302 |
+
return cell;
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
function isPinned(meta) {
|
| 306 |
+
return Boolean(meta && (meta.pinned === true || meta.pinned === "true"));
|
| 307 |
+
}
|
| 308 |
+
|
| 309 |
+
function stripDuplicateTitle(body, title) {
|
| 310 |
+
if (!title) return body;
|
| 311 |
+
const m = body.match(/^\s*#{1,6}\s+([^\n]+)\n?/);
|
| 312 |
+
if (!m) return body;
|
| 313 |
+
const norm = (s) =>
|
| 314 |
+
s
|
| 315 |
+
.toLowerCase()
|
| 316 |
+
.replace(/[*_`#]/g, "")
|
| 317 |
+
.replace(/\s+/g, " ")
|
| 318 |
+
.trim();
|
| 319 |
+
return norm(m[1]) === norm(title) ? body.slice(m[0].length) : body;
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
function formatTime(iso) {
|
| 323 |
+
const d = new Date(iso);
|
| 324 |
+
if (Number.isNaN(d.getTime())) return iso;
|
| 325 |
+
return d.toLocaleString(undefined, {
|
| 326 |
+
month: "short",
|
| 327 |
+
day: "numeric",
|
| 328 |
+
hour: "2-digit",
|
| 329 |
+
minute: "2-digit",
|
| 330 |
+
});
|
| 331 |
+
}
|
| 332 |
+
|
| 333 |
+
function parseFences(text) {
|
| 334 |
+
const fenceRe = /(`{3,4}|~{3,4})([^\n]*)\n([\s\S]*?)\n\1/g;
|
| 335 |
+
const parts = [];
|
| 336 |
+
let pos = 0;
|
| 337 |
+
let match;
|
| 338 |
+
while ((match = fenceRe.exec(text))) {
|
| 339 |
+
if (match.index > pos) {
|
| 340 |
+
parts.push({ kind: "text", text: text.slice(pos, match.index) });
|
| 341 |
+
}
|
| 342 |
+
const info = match[2].trim();
|
| 343 |
+
const lang = (info.split(/\s+/)[0] || "").toLowerCase();
|
| 344 |
+
const titleMatch = info.match(/title=(\S+)/);
|
| 345 |
+
parts.push({
|
| 346 |
+
kind: lang === "result" || lang === "output" ? "output" : "code",
|
| 347 |
+
lang,
|
| 348 |
+
title: titleMatch ? titleMatch[1] : null,
|
| 349 |
+
text: match[3],
|
| 350 |
+
});
|
| 351 |
+
pos = match.index + match[0].length;
|
| 352 |
+
}
|
| 353 |
+
if (pos < text.length) parts.push({ kind: "text", text: text.slice(pos) });
|
| 354 |
+
return parts;
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
function fitFigureFrame(frame, wrap) {
|
| 358 |
+
let doc;
|
| 359 |
+
try {
|
| 360 |
+
doc = frame.contentDocument;
|
| 361 |
+
} catch (e) {
|
| 362 |
+
return;
|
| 363 |
+
}
|
| 364 |
+
if (!doc || !doc.body) return;
|
| 365 |
+
frame.style.transform = "none";
|
| 366 |
+
frame.style.width = "100%";
|
| 367 |
+
frame.style.height = "auto";
|
| 368 |
+
frame.style.position = "";
|
| 369 |
+
frame.style.left = "";
|
| 370 |
+
frame.style.top = "";
|
| 371 |
+
const avail = wrap.clientWidth;
|
| 372 |
+
const isFullscreen =
|
| 373 |
+
document.fullscreenElement === wrap ||
|
| 374 |
+
document.webkitFullscreenElement === wrap;
|
| 375 |
+
const availHeight = isFullscreen ? wrap.clientHeight : Infinity;
|
| 376 |
+
const cw = Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth, 1);
|
| 377 |
+
const ch = Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight, 1);
|
| 378 |
+
const scale = Math.min(avail / cw, availHeight / ch);
|
| 379 |
+
if (avail && scale < 1 - 1e-3) {
|
| 380 |
+
frame.style.width = `${cw}px`;
|
| 381 |
+
frame.style.height = `${ch}px`;
|
| 382 |
+
frame.style.transformOrigin = "top left";
|
| 383 |
+
frame.style.transform = `scale(${scale})`;
|
| 384 |
+
if (isFullscreen) {
|
| 385 |
+
frame.style.position = "absolute";
|
| 386 |
+
frame.style.left = `${Math.max(0, (avail - cw * scale) / 2)}px`;
|
| 387 |
+
frame.style.top = `${Math.max(0, (availHeight - ch * scale) / 2)}px`;
|
| 388 |
+
wrap.style.height = "100%";
|
| 389 |
+
} else {
|
| 390 |
+
wrap.style.height = `${Math.ceil(ch * scale)}px`;
|
| 391 |
+
}
|
| 392 |
+
} else {
|
| 393 |
+
frame.style.width = "100%";
|
| 394 |
+
frame.style.height = `${ch}px`;
|
| 395 |
+
wrap.style.height = isFullscreen ? "100%" : `${ch}px`;
|
| 396 |
+
}
|
| 397 |
+
}
|
| 398 |
+
|
| 399 |
+
function attachFigureFit(frame, wrap) {
|
| 400 |
+
const refit = () => fitFigureFrame(frame, wrap);
|
| 401 |
+
frame.addEventListener("load", refit);
|
| 402 |
+
if (window.ResizeObserver) {
|
| 403 |
+
const ro = new ResizeObserver(() => refit());
|
| 404 |
+
ro.observe(wrap);
|
| 405 |
+
}
|
| 406 |
+
}
|
| 407 |
+
|
| 408 |
+
function renderFigureCell(text, container, head) {
|
| 409 |
+
const parts = parseFences(text);
|
| 410 |
+
const htmlPart = parts.find((part) => part.lang === "html");
|
| 411 |
+
const rawPart = parts.find((part) => part.lang === "raw");
|
| 412 |
+
if (!htmlPart || !htmlPart.text.trim()) {
|
| 413 |
+
const empty = document.createElement("p");
|
| 414 |
+
empty.className = "muted";
|
| 415 |
+
empty.textContent = "No figure HTML.";
|
| 416 |
+
container.appendChild(empty);
|
| 417 |
+
return;
|
| 418 |
+
}
|
| 419 |
+
const frame = document.createElement("iframe");
|
| 420 |
+
frame.className = "figure-frame";
|
| 421 |
+
frame.sandbox = "allow-scripts allow-same-origin";
|
| 422 |
+
frame.loading = "lazy";
|
| 423 |
+
frame.srcdoc = htmlPart.text;
|
| 424 |
+
registerFigureNavigation(frame);
|
| 425 |
+
const figWrap = document.createElement("div");
|
| 426 |
+
figWrap.className = "figure-fit";
|
| 427 |
+
figWrap.appendChild(frame);
|
| 428 |
+
attachFigureFit(frame, figWrap);
|
| 429 |
+
if (head) {
|
| 430 |
+
const metaEl = head.querySelector(".cell-meta");
|
| 431 |
+
if (metaEl)
|
| 432 |
+
metaEl.insertBefore(buildFullscreenControl(figWrap, frame), metaEl.firstChild);
|
| 433 |
+
}
|
| 434 |
+
if (!rawPart || !rawPart.text.trim()) {
|
| 435 |
+
container.appendChild(figWrap);
|
| 436 |
+
return;
|
| 437 |
+
}
|
| 438 |
+
const sw = document.createElement("div");
|
| 439 |
+
sw.className = "fig-switch";
|
| 440 |
+
const thumb = document.createElement("span");
|
| 441 |
+
thumb.className = "fig-switch-thumb";
|
| 442 |
+
const figBtn = document.createElement("button");
|
| 443 |
+
figBtn.type = "button";
|
| 444 |
+
figBtn.className = "active";
|
| 445 |
+
figBtn.textContent = "Figure";
|
| 446 |
+
const rawBtn = document.createElement("button");
|
| 447 |
+
rawBtn.type = "button";
|
| 448 |
+
rawBtn.textContent = "Raw";
|
| 449 |
+
sw.appendChild(thumb);
|
| 450 |
+
sw.appendChild(figBtn);
|
| 451 |
+
sw.appendChild(rawBtn);
|
| 452 |
+
const rawView = document.createElement("div");
|
| 453 |
+
rawView.className = "figure-raw";
|
| 454 |
+
rawView.hidden = true;
|
| 455 |
+
const pre = document.createElement("pre");
|
| 456 |
+
const code = document.createElement("code");
|
| 457 |
+
code.textContent = rawPart.text;
|
| 458 |
+
pre.appendChild(code);
|
| 459 |
+
rawView.appendChild(pre);
|
| 460 |
+
rawView.appendChild(copySnippetBtn(rawPart.text));
|
| 461 |
+
const select = (showRaw) => {
|
| 462 |
+
sw.classList.toggle("raw", showRaw);
|
| 463 |
+
figBtn.classList.toggle("active", !showRaw);
|
| 464 |
+
rawBtn.classList.toggle("active", showRaw);
|
| 465 |
+
figWrap.hidden = showRaw;
|
| 466 |
+
rawView.hidden = !showRaw;
|
| 467 |
+
};
|
| 468 |
+
figBtn.addEventListener("click", () => select(false));
|
| 469 |
+
rawBtn.addEventListener("click", () => select(true));
|
| 470 |
+
if (head) {
|
| 471 |
+
head.insertBefore(sw, head.querySelector(".cell-meta"));
|
| 472 |
+
} else {
|
| 473 |
+
container.appendChild(sw);
|
| 474 |
+
}
|
| 475 |
+
container.appendChild(figWrap);
|
| 476 |
+
container.appendChild(rawView);
|
| 477 |
+
}
|
| 478 |
+
|
| 479 |
+
// Poster embeds can send `{ type: "trackio-logbook:navigate", target: "..." }`
|
| 480 |
+
// from their iframe. Only accept messages from figure frames we created, and
|
| 481 |
+
// only route to pages that are present in this logbook's manifest.
|
| 482 |
+
function registerFigureNavigation(frame) {
|
| 483 |
+
const registerFrameWindow = () => {
|
| 484 |
+
if (frame.contentWindow) FIGURE_FRAME_WINDOWS.add(frame.contentWindow);
|
| 485 |
+
};
|
| 486 |
+
// `srcdoc` replaces the initial about:blank document. Register after that
|
| 487 |
+
// navigation as well, so messages come from the live figure document.
|
| 488 |
+
frame.addEventListener("load", registerFrameWindow);
|
| 489 |
+
registerFrameWindow();
|
| 490 |
+
if (FIGURE_NAVIGATION_READY) return;
|
| 491 |
+
FIGURE_NAVIGATION_READY = true;
|
| 492 |
+
window.addEventListener("message", (event) => {
|
| 493 |
+
if (!FIGURE_FRAME_WINDOWS.has(event.source)) return;
|
| 494 |
+
const message = event.data;
|
| 495 |
+
if (!message || message.type !== "trackio-logbook:navigate") return;
|
| 496 |
+
const target = String(message.target || "").replace(/^#?\//, "");
|
| 497 |
+
if (!target || !MANIFEST || !findNode(MANIFEST.root, target)) return;
|
| 498 |
+
const hash = "#/" + target;
|
| 499 |
+
if (location.hash === hash) scrollToHash();
|
| 500 |
+
else location.hash = hash;
|
| 501 |
+
});
|
| 502 |
+
}
|
| 503 |
+
|
| 504 |
+
const FULLSCREEN_ICON =
|
| 505 |
+
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" ' +
|
| 506 |
+
'stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
|
| 507 |
+
'<path d="M8 3H3v5M16 3h5v5M21 16v5h-5M3 16v5h5"/>' +
|
| 508 |
+
'<path d="M3 8 8 3M16 3l5 5M21 16l-5 5M8 21l-5-5"/></svg>';
|
| 509 |
+
|
| 510 |
+
// Figures are rendered in same-origin iframes, so fullscreen the fitted
|
| 511 |
+
// wrapper rather than the iframe document. This uses the browser's native
|
| 512 |
+
// fullscreen UI and preserves the figure's existing responsive sizing.
|
| 513 |
+
function buildFullscreenControl(figWrap, frame) {
|
| 514 |
+
const wrap = document.createElement("span");
|
| 515 |
+
wrap.className = "cell-fullscreen";
|
| 516 |
+
const btn = document.createElement("button");
|
| 517 |
+
btn.type = "button";
|
| 518 |
+
btn.className = "cell-fullscreen-btn";
|
| 519 |
+
btn.setAttribute("aria-label", "Open figure in fullscreen");
|
| 520 |
+
btn.title = "Open figure in fullscreen";
|
| 521 |
+
btn.innerHTML = FULLSCREEN_ICON;
|
| 522 |
+
wrap.appendChild(btn);
|
| 523 |
+
|
| 524 |
+
btn.addEventListener("click", async () => {
|
| 525 |
+
const request = figWrap.requestFullscreen || figWrap.webkitRequestFullscreen;
|
| 526 |
+
if (!request) return;
|
| 527 |
+
try {
|
| 528 |
+
await request.call(figWrap);
|
| 529 |
+
} catch (_) {
|
| 530 |
+
// Fullscreen can be disabled by the embedding browser or policy.
|
| 531 |
+
}
|
| 532 |
+
});
|
| 533 |
+
document.addEventListener("fullscreenchange", () => {
|
| 534 |
+
if (document.fullscreenElement === figWrap) fitFigureFrame(frame, figWrap);
|
| 535 |
+
});
|
| 536 |
+
return wrap;
|
| 537 |
+
}
|
| 538 |
+
|
| 539 |
+
function extractUrls(text) {
|
| 540 |
+
const seen = new Set();
|
| 541 |
+
const urls = [];
|
| 542 |
+
let match;
|
| 543 |
+
while ((match = DETECTED_URL.exec(text))) {
|
| 544 |
+
const url = match[1].replace(/[.,;:!?'"`]+$/, "");
|
| 545 |
+
if (!seen.has(url)) {
|
| 546 |
+
seen.add(url);
|
| 547 |
+
urls.push(url);
|
| 548 |
+
}
|
| 549 |
+
}
|
| 550 |
+
DETECTED_URL.lastIndex = 0;
|
| 551 |
+
return urls;
|
| 552 |
+
}
|
| 553 |
+
|
| 554 |
+
const IMG_URL = /(\.(png|jpe?g|gif|svg|webp)(\?|$)|\/artifact_blob\/)/i;
|
| 555 |
+
|
| 556 |
+
function renderDetectedEmbeds(text, container) {
|
| 557 |
+
extractUrls(text).forEach((url) => {
|
| 558 |
+
if (url.startsWith("trackio-local-dashboard://")) {
|
| 559 |
+
const div = document.createElement("div");
|
| 560 |
+
div.className = "artifact-chip";
|
| 561 |
+
div.dataset.resUrl = url;
|
| 562 |
+
div.innerHTML =
|
| 563 |
+
"π― <strong>Local Trackio dashboard</strong> β publish the logbook to share it";
|
| 564 |
+
container.appendChild(div);
|
| 565 |
+
} else if (IMG_URL.test(url)) {
|
| 566 |
+
container.appendChild(renderImage(url));
|
| 567 |
+
} else if (/huggingface\.co\/spaces\//.test(url)) {
|
| 568 |
+
maybeEmbedTrackioSpace(url, container);
|
| 569 |
+
}
|
| 570 |
+
});
|
| 571 |
+
}
|
| 572 |
+
|
| 573 |
+
function renderStandaloneUrl(url) {
|
| 574 |
+
if (IMG_URL.test(url) || IMG_PATH.test(url)) return renderImage(url);
|
| 575 |
+
const item = classifyResource(url);
|
| 576 |
+
if (item) {
|
| 577 |
+
const marker = document.createElement("span");
|
| 578 |
+
marker.className = "resource-anchor";
|
| 579 |
+
marker.dataset.resUrl = item.url;
|
| 580 |
+
marker.setAttribute("aria-hidden", "true");
|
| 581 |
+
return marker;
|
| 582 |
+
}
|
| 583 |
+
const p = document.createElement("p");
|
| 584 |
+
p.innerHTML = inline(url);
|
| 585 |
+
return p;
|
| 586 |
+
}
|
| 587 |
+
|
| 588 |
+
function renderImage(url) {
|
| 589 |
+
const a = document.createElement("a");
|
| 590 |
+
a.className = "unfurl image";
|
| 591 |
+
a.href = url;
|
| 592 |
+
a.target = "_blank";
|
| 593 |
+
a.rel = "noopener";
|
| 594 |
+
const img = document.createElement("img");
|
| 595 |
+
img.loading = "lazy";
|
| 596 |
+
img.src = url;
|
| 597 |
+
img.alt = "artifact image";
|
| 598 |
+
a.appendChild(img);
|
| 599 |
+
return a;
|
| 600 |
+
}
|
| 601 |
+
|
| 602 |
+
function maybeEmbedTrackioSpace(url, container) {
|
| 603 |
+
const id = url.split("/spaces/")[1].split(/[?#]/)[0].replace(/\/$/, "");
|
| 604 |
+
const holder = document.createElement("div");
|
| 605 |
+
container.appendChild(holder);
|
| 606 |
+
getJSON(`https://huggingface.co/api/spaces/${id}`).then((d) => {
|
| 607 |
+
const tags = (d && d.tags) || [];
|
| 608 |
+
if (tags.some((t) => String(t).toLowerCase() === "trackio")) {
|
| 609 |
+
renderTrackioSpaceEmbed(holder, url, id);
|
| 610 |
+
} else {
|
| 611 |
+
holder.remove();
|
| 612 |
+
}
|
| 613 |
+
});
|
| 614 |
+
}
|
| 615 |
+
|
| 616 |
+
function jpGutter(label) {
|
| 617 |
+
const g = document.createElement("div");
|
| 618 |
+
g.className = "jp-gutter";
|
| 619 |
+
g.textContent = label;
|
| 620 |
+
return g;
|
| 621 |
+
}
|
| 622 |
+
|
| 623 |
+
function renderOutArtifact(info) {
|
| 624 |
+
const remote = !info.local && !!info.url;
|
| 625 |
+
const el = document.createElement(remote ? "a" : "div");
|
| 626 |
+
el.className = "out-artifact";
|
| 627 |
+
if (remote) {
|
| 628 |
+
el.href = info.url;
|
| 629 |
+
el.target = "_blank";
|
| 630 |
+
el.rel = "noopener";
|
| 631 |
+
}
|
| 632 |
+
el.dataset.resUrl = info.resUrl;
|
| 633 |
+
const parts = [info.type, info.size].filter(Boolean).map(esc);
|
| 634 |
+
const state = remote
|
| 635 |
+
? `<span class="out-artifact-state open">Open β</span>`
|
| 636 |
+
: `<span class="out-artifact-state">publish to share</span>`;
|
| 637 |
+
const meta = parts.length ? `${parts.join(" Β· ")} Β· ${state}` : state;
|
| 638 |
+
el.innerHTML =
|
| 639 |
+
`<span class="out-artifact-ico">${ARTIFACT_ICON_IMG}</span>` +
|
| 640 |
+
`<span class="out-artifact-name">${esc(info.name)}</span>` +
|
| 641 |
+
`<span class="out-artifact-meta">${meta}</span>`;
|
| 642 |
+
return el;
|
| 643 |
+
}
|
| 644 |
+
|
| 645 |
+
function renderCodeCell(body, container, artifacts) {
|
| 646 |
+
const parts = parseFences(body);
|
| 647 |
+
const block = document.createElement("div");
|
| 648 |
+
block.className = "jp";
|
| 649 |
+
const input = document.createElement("div");
|
| 650 |
+
input.className = "jp-in";
|
| 651 |
+
const inputBody = document.createElement("div");
|
| 652 |
+
inputBody.className = "jp-in-body";
|
| 653 |
+
input.appendChild(jpGutter("In"));
|
| 654 |
+
input.appendChild(inputBody);
|
| 655 |
+
let metaEl = null;
|
| 656 |
+
let outputEl = null;
|
| 657 |
+
let outBody = null;
|
| 658 |
+
const ensureOut = () => {
|
| 659 |
+
if (outputEl) return;
|
| 660 |
+
outputEl = document.createElement("div");
|
| 661 |
+
outputEl.className = "jp-out";
|
| 662 |
+
outputEl.appendChild(jpGutter("Out"));
|
| 663 |
+
outBody = document.createElement("div");
|
| 664 |
+
outBody.className = "jp-out-body";
|
| 665 |
+
outputEl.appendChild(outBody);
|
| 666 |
+
};
|
| 667 |
+
const embedTexts = [];
|
| 668 |
+
parts.forEach((part) => {
|
| 669 |
+
if (part.kind === "text") {
|
| 670 |
+
const text = part.text.trim();
|
| 671 |
+
if (!text) return;
|
| 672 |
+
if (/^exit\s+\S+(\s|Β·)/.test(text)) {
|
| 673 |
+
metaEl = document.createElement("div");
|
| 674 |
+
metaEl.className = "jp-meta";
|
| 675 |
+
metaEl.textContent = text.replace(
|
| 676 |
+
/\s*Β·\s*[A-Z][a-z]{2} \d{1,2}, \d{4}.*$/,
|
| 677 |
+
""
|
| 678 |
+
);
|
| 679 |
+
} else {
|
| 680 |
+
renderMarkdownPlain(text, container);
|
| 681 |
+
embedTexts.push(text);
|
| 682 |
+
}
|
| 683 |
+
return;
|
| 684 |
+
}
|
| 685 |
+
if (part.kind === "output") {
|
| 686 |
+
ensureOut();
|
| 687 |
+
const pre = document.createElement("pre");
|
| 688 |
+
pre.className = "jp-out-pre";
|
| 689 |
+
const c = document.createElement("code");
|
| 690 |
+
c.textContent = part.text;
|
| 691 |
+
pre.appendChild(c);
|
| 692 |
+
outBody.appendChild(pre);
|
| 693 |
+
outputEl.appendChild(copySnippetBtn(part.text));
|
| 694 |
+
embedTexts.push(part.text);
|
| 695 |
+
return;
|
| 696 |
+
}
|
| 697 |
+
inputBody.appendChild(renderCode(part.text, part.lang, part.title));
|
| 698 |
+
});
|
| 699 |
+
if (artifacts && artifacts.length) {
|
| 700 |
+
ensureOut();
|
| 701 |
+
const artWrap = document.createElement("div");
|
| 702 |
+
artWrap.className = "jp-artifacts";
|
| 703 |
+
artifacts.forEach((a) => {
|
| 704 |
+
artWrap.appendChild(
|
| 705 |
+
renderOutArtifact(artifactInfoFromCell(a.meta, a.body))
|
| 706 |
+
);
|
| 707 |
+
});
|
| 708 |
+
outBody.appendChild(artWrap);
|
| 709 |
+
}
|
| 710 |
+
if (inputBody.childNodes.length > 0) block.appendChild(input);
|
| 711 |
+
if (metaEl) block.appendChild(metaEl);
|
| 712 |
+
if (outputEl) block.appendChild(outputEl);
|
| 713 |
+
if (block.childNodes.length) container.appendChild(block);
|
| 714 |
+
embedTexts.forEach((text) => renderDetectedEmbeds(text, container));
|
| 715 |
+
}
|
| 716 |
+
|
| 717 |
+
function parseRow(line) {
|
| 718 |
+
let s = line.trim();
|
| 719 |
+
if (s.startsWith("|")) s = s.slice(1);
|
| 720 |
+
if (s.endsWith("|")) s = s.slice(0, -1);
|
| 721 |
+
return s.split(/(?<!\\)\|/).map((c) => c.replace(/\\\|/g, "|").trim());
|
| 722 |
+
}
|
| 723 |
+
|
| 724 |
+
const TRUTHY = ["x", "β", "β", "yes", "done", "true", "[x]"];
|
| 725 |
+
const CHIP_COLORS = [
|
| 726 |
+
["#e7f0ff", "#2158d0"],
|
| 727 |
+
["#fde8ec", "#c62a4b"],
|
| 728 |
+
["#e6f7ee", "#1a8a55"],
|
| 729 |
+
["#fdf0e0", "#b26a12"],
|
| 730 |
+
["#efe9ff", "#5b3bd6"],
|
| 731 |
+
["#e6f6f8", "#127b88"],
|
| 732 |
+
];
|
| 733 |
+
|
| 734 |
+
function chipColor(name) {
|
| 735 |
+
let h = 0;
|
| 736 |
+
for (let i = 0; i < name.length; i++) h = (h * 31 + name.charCodeAt(i)) >>> 0;
|
| 737 |
+
return CHIP_COLORS[h % CHIP_COLORS.length];
|
| 738 |
+
}
|
| 739 |
+
|
| 740 |
+
const STATUS_MAP = {
|
| 741 |
+
"": ["Planned", "gray"],
|
| 742 |
+
planned: ["Planned", "gray"],
|
| 743 |
+
todo: ["Planned", "gray"],
|
| 744 |
+
"to do": ["Planned", "gray"],
|
| 745 |
+
backlog: ["Planned", "gray"],
|
| 746 |
+
"in progress": ["In progress", "amber"],
|
| 747 |
+
"in-progress": ["In progress", "amber"],
|
| 748 |
+
wip: ["In progress", "amber"],
|
| 749 |
+
running: ["In progress", "amber"],
|
| 750 |
+
active: ["In progress", "amber"],
|
| 751 |
+
done: ["Done", "green"],
|
| 752 |
+
complete: ["Done", "green"],
|
| 753 |
+
completed: ["Done", "green"],
|
| 754 |
+
blocked: ["Blocked", "red"],
|
| 755 |
+
failed: ["Failed", "red"],
|
| 756 |
+
abandoned: ["Abandoned", "gray"],
|
| 757 |
+
};
|
| 758 |
+
|
| 759 |
+
function statusBadge(val) {
|
| 760 |
+
const [label, tone] = STATUS_MAP[val.toLowerCase()] || [val || "β", "gray"];
|
| 761 |
+
return `<span class="badge ${tone}">${esc(label)}</span>`;
|
| 762 |
+
}
|
| 763 |
+
|
| 764 |
+
function renderTable(rows, container) {
|
| 765 |
+
if (rows.length < 2) return;
|
| 766 |
+
const header = rows[0];
|
| 767 |
+
const body = rows.slice(2);
|
| 768 |
+
const roles = header.map((h) => {
|
| 769 |
+
const t = h.toLowerCase();
|
| 770 |
+
if (t.includes("status") || t.includes("state")) return "status";
|
| 771 |
+
if (t.includes("progress") || t.includes("complete") || t.includes("done"))
|
| 772 |
+
return "check";
|
| 773 |
+
if (t === "who" || t.includes("assign") || t.includes("owner")) return "who";
|
| 774 |
+
return "text";
|
| 775 |
+
});
|
| 776 |
+
const table = document.createElement("table");
|
| 777 |
+
table.className = "board";
|
| 778 |
+
const thead = document.createElement("thead");
|
| 779 |
+
const htr = document.createElement("tr");
|
| 780 |
+
header.forEach((h, c) => {
|
| 781 |
+
const th = document.createElement("th");
|
| 782 |
+
th.textContent = h;
|
| 783 |
+
if (roles[c] === "check") th.className = "col-check";
|
| 784 |
+
htr.appendChild(th);
|
| 785 |
+
});
|
| 786 |
+
thead.appendChild(htr);
|
| 787 |
+
table.appendChild(thead);
|
| 788 |
+
const tbody = document.createElement("tbody");
|
| 789 |
+
body.forEach((cells) => {
|
| 790 |
+
const nonEmpty = cells.filter((x) => x !== "").length;
|
| 791 |
+
if (header.length > 1 && nonEmpty === 1 && cells[0]) {
|
| 792 |
+
const tr = document.createElement("tr");
|
| 793 |
+
tr.className = "section-row";
|
| 794 |
+
const td = document.createElement("td");
|
| 795 |
+
td.colSpan = header.length;
|
| 796 |
+
td.innerHTML = inline(cells[0]);
|
| 797 |
+
tr.appendChild(td);
|
| 798 |
+
tbody.appendChild(tr);
|
| 799 |
+
return;
|
| 800 |
+
}
|
| 801 |
+
const tr = document.createElement("tr");
|
| 802 |
+
header.forEach((_, c) => {
|
| 803 |
+
const td = document.createElement("td");
|
| 804 |
+
const val = (cells[c] || "").trim();
|
| 805 |
+
if (roles[c] === "status") {
|
| 806 |
+
td.className = "col-status";
|
| 807 |
+
td.innerHTML = statusBadge(val);
|
| 808 |
+
} else if (roles[c] === "check") {
|
| 809 |
+
td.className = "col-check";
|
| 810 |
+
const on = TRUTHY.indexOf(val.toLowerCase()) !== -1;
|
| 811 |
+
td.innerHTML = `<span class="box ${on ? "on" : ""}">${on ? "β" : ""}</span>`;
|
| 812 |
+
} else if (roles[c] === "who") {
|
| 813 |
+
if (!val || /^to assign$/i.test(val)) {
|
| 814 |
+
td.innerHTML = `<span class="who-chip muted">${esc(val || "β")}</span>`;
|
| 815 |
+
} else {
|
| 816 |
+
const [bg, fg] = chipColor(val);
|
| 817 |
+
td.innerHTML = `<span class="who-chip" style="background:${bg};color:${fg}">${esc(val)}</span>`;
|
| 818 |
+
}
|
| 819 |
+
} else {
|
| 820 |
+
td.innerHTML = inline(val);
|
| 821 |
+
}
|
| 822 |
+
tr.appendChild(td);
|
| 823 |
+
});
|
| 824 |
+
const link = tr.querySelector('a[href^="#/"]');
|
| 825 |
+
if (link) {
|
| 826 |
+
tr.classList.add("linked-row");
|
| 827 |
+
tr.addEventListener("click", (e) => {
|
| 828 |
+
if (e.target.tagName !== "A") location.hash = link.getAttribute("href");
|
| 829 |
+
});
|
| 830 |
+
}
|
| 831 |
+
tbody.appendChild(tr);
|
| 832 |
+
});
|
| 833 |
+
table.appendChild(tbody);
|
| 834 |
+
const wrap = document.createElement("div");
|
| 835 |
+
wrap.className = "board-wrap";
|
| 836 |
+
wrap.appendChild(table);
|
| 837 |
+
container.appendChild(wrap);
|
| 838 |
+
}
|
| 839 |
+
|
| 840 |
+
const HL_RULES = {
|
| 841 |
+
python: [
|
| 842 |
+
["comment", /#[^\n]*/],
|
| 843 |
+
["string", /'''[\s\S]*?'''|"""[\s\S]*?"""|'(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"/],
|
| 844 |
+
[
|
| 845 |
+
"keyword",
|
| 846 |
+
/\b(?:def|class|return|if|elif|else|for|while|import|from|as|with|try|except|finally|raise|in|not|and|or|is|None|True|False|lambda|yield|global|nonlocal|assert|pass|break|continue|async|await|print)\b/,
|
| 847 |
+
],
|
| 848 |
+
["number", /\b\d[\d_.eE+-]*\b/],
|
| 849 |
+
],
|
| 850 |
+
bash: [
|
| 851 |
+
["comment", /#[^\n]*/],
|
| 852 |
+
["string", /'(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"/],
|
| 853 |
+
["keyword", /\b(?:if|then|else|fi|for|in|do|done|while|case|esac|function|export|source|echo|cd|return|local)\b/],
|
| 854 |
+
["number", /(?<=\s)-{1,2}[a-zA-Z][\w-]*/],
|
| 855 |
+
],
|
| 856 |
+
json: [
|
| 857 |
+
["string", /"(?:\\.|[^"\\])*"/],
|
| 858 |
+
["keyword", /\b(?:true|false|null)\b/],
|
| 859 |
+
["number", /-?\b\d[\d.eE+-]*\b/],
|
| 860 |
+
],
|
| 861 |
+
yaml: [
|
| 862 |
+
["comment", /#[^\n]*/],
|
| 863 |
+
["string", /'(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"/],
|
| 864 |
+
["keyword", /\b(?:true|false|null|yes|no)\b/],
|
| 865 |
+
["number", /-?\b\d[\d.eE+-]*\b/],
|
| 866 |
+
],
|
| 867 |
+
};
|
| 868 |
+
HL_RULES.javascript = HL_RULES.python;
|
| 869 |
+
HL_RULES.typescript = HL_RULES.python;
|
| 870 |
+
HL_RULES.sql = [
|
| 871 |
+
["comment", /--[^\n]*/],
|
| 872 |
+
["string", /'(?:\\.|[^'\\])*'/],
|
| 873 |
+
[
|
| 874 |
+
"keyword",
|
| 875 |
+
/\b(?:SELECT|FROM|WHERE|JOIN|LEFT|RIGHT|INNER|OUTER|ON|GROUP|BY|ORDER|LIMIT|INSERT|INTO|VALUES|UPDATE|SET|DELETE|CREATE|TABLE|AS|AND|OR|NOT|NULL|COUNT|DISTINCT|IN)\b/i,
|
| 876 |
+
],
|
| 877 |
+
["number", /\b\d[\d.]*\b/],
|
| 878 |
+
];
|
| 879 |
+
|
| 880 |
+
function highlightCode(code, lang) {
|
| 881 |
+
const rules = HL_RULES[lang];
|
| 882 |
+
if (!rules) return esc(code);
|
| 883 |
+
const combined = new RegExp(rules.map((r) => "(" + r[1].source + ")").join("|"), "g");
|
| 884 |
+
let out = "";
|
| 885 |
+
let last = 0;
|
| 886 |
+
let m;
|
| 887 |
+
while ((m = combined.exec(code))) {
|
| 888 |
+
if (m[0] === "") {
|
| 889 |
+
combined.lastIndex++;
|
| 890 |
+
continue;
|
| 891 |
+
}
|
| 892 |
+
out += esc(code.slice(last, m.index));
|
| 893 |
+
let gi = 1;
|
| 894 |
+
while (gi < m.length && m[gi] === undefined) gi++;
|
| 895 |
+
out += `<span class="tok-${rules[gi - 1][0]}">${esc(m[0])}</span>`;
|
| 896 |
+
last = m.index + m[0].length;
|
| 897 |
+
}
|
| 898 |
+
out += esc(code.slice(last));
|
| 899 |
+
return out;
|
| 900 |
+
}
|
| 901 |
+
|
| 902 |
+
function copySnippetBtn(text) {
|
| 903 |
+
const btn = document.createElement("button");
|
| 904 |
+
btn.type = "button";
|
| 905 |
+
btn.className = "copy-snippet";
|
| 906 |
+
btn.title = "Copy";
|
| 907 |
+
btn.textContent = "β§";
|
| 908 |
+
btn.addEventListener("click", (e) => {
|
| 909 |
+
e.preventDefault();
|
| 910 |
+
e.stopPropagation();
|
| 911 |
+
copyText(text, btn, "β§");
|
| 912 |
+
});
|
| 913 |
+
return btn;
|
| 914 |
+
}
|
| 915 |
+
|
| 916 |
+
function renderCode(code, lang, title) {
|
| 917 |
+
const pre = document.createElement("pre");
|
| 918 |
+
pre.className = "hl";
|
| 919 |
+
const c = document.createElement("code");
|
| 920 |
+
c.innerHTML = highlightCode(code, lang);
|
| 921 |
+
pre.appendChild(c);
|
| 922 |
+
if (!title) {
|
| 923 |
+
const wrap = document.createElement("div");
|
| 924 |
+
wrap.className = "snippet";
|
| 925 |
+
wrap.appendChild(pre);
|
| 926 |
+
wrap.appendChild(copySnippetBtn(code));
|
| 927 |
+
return wrap;
|
| 928 |
+
}
|
| 929 |
+
const det = document.createElement("details");
|
| 930 |
+
det.className = "code-accordion";
|
| 931 |
+
det.dataset.resUrl = `trackio-script://${title}`;
|
| 932 |
+
const sum = document.createElement("summary");
|
| 933 |
+
sum.innerHTML =
|
| 934 |
+
`<span class="code-ico"></></span>` +
|
| 935 |
+
`<span class="code-name">${esc(title)}</span>`;
|
| 936 |
+
sum
|
| 937 |
+
.querySelector(".code-name")
|
| 938 |
+
.addEventListener("click", (e) => e.preventDefault());
|
| 939 |
+
det.appendChild(sum);
|
| 940 |
+
const wrap = document.createElement("div");
|
| 941 |
+
wrap.className = "snippet";
|
| 942 |
+
wrap.appendChild(pre);
|
| 943 |
+
wrap.appendChild(copySnippetBtn(code));
|
| 944 |
+
det.appendChild(wrap);
|
| 945 |
+
return det;
|
| 946 |
+
}
|
| 947 |
+
|
| 948 |
+
const IMG_PATH = /^[^\s]+\.(png|jpe?g|gif|svg|webp)$/i;
|
| 949 |
+
|
| 950 |
+
function renderList(items, container) {
|
| 951 |
+
let ul = null;
|
| 952 |
+
items.forEach((item) => {
|
| 953 |
+
if (URL_ONLY.test(item) || IMG_PATH.test(item)) {
|
| 954 |
+
const el = renderStandaloneUrl(item);
|
| 955 |
+
if (el) {
|
| 956 |
+
ul = null;
|
| 957 |
+
container.appendChild(el);
|
| 958 |
+
}
|
| 959 |
+
} else if (item.indexOf("π¦ Artifact") !== -1) {
|
| 960 |
+
ul = null;
|
| 961 |
+
const div = document.createElement("div");
|
| 962 |
+
div.className = "artifact-chip";
|
| 963 |
+
div.innerHTML = inline(item.replace("π¦", "πͺ£"));
|
| 964 |
+
container.appendChild(div);
|
| 965 |
+
} else if (item.indexOf("trackio-local-dashboard://") !== -1) {
|
| 966 |
+
ul = null;
|
| 967 |
+
const uri = item.match(/trackio-local-dashboard:\/\/\S+/)?.[0] || "";
|
| 968 |
+
const div = document.createElement("div");
|
| 969 |
+
div.className = "artifact-chip";
|
| 970 |
+
if (uri) div.dataset.resUrl = uri;
|
| 971 |
+
div.innerHTML =
|
| 972 |
+
"π― <strong>Local dashboard</strong> β publish the logbook to share it";
|
| 973 |
+
container.appendChild(div);
|
| 974 |
+
} else {
|
| 975 |
+
if (!ul) {
|
| 976 |
+
ul = document.createElement("ul");
|
| 977 |
+
container.appendChild(ul);
|
| 978 |
+
}
|
| 979 |
+
const li = document.createElement("li");
|
| 980 |
+
li.innerHTML = inline(item);
|
| 981 |
+
ul.appendChild(li);
|
| 982 |
+
}
|
| 983 |
+
});
|
| 984 |
+
}
|
| 985 |
+
|
| 986 |
+
/* -------------------- resources rail -------------------- */
|
| 987 |
+
|
| 988 |
+
function fmt(n) {
|
| 989 |
+
if (n == null) return null;
|
| 990 |
+
if (n >= 1e6) return (n / 1e6).toFixed(1) + "M";
|
| 991 |
+
if (n >= 1e3) return (n / 1e3).toFixed(1) + "k";
|
| 992 |
+
return String(n);
|
| 993 |
+
}
|
| 994 |
+
|
| 995 |
+
const RESOURCE_SECTIONS = [
|
| 996 |
+
["dashboard", "Dashboards", "π―"],
|
| 997 |
+
["model", "Models", "π€"],
|
| 998 |
+
["dataset", "Datasets", "π"],
|
| 999 |
+
["space", "Spaces", "π"],
|
| 1000 |
+
["artifact", "Artifacts", "πͺ£"],
|
| 1001 |
+
["paper", "Papers", "π"],
|
| 1002 |
+
["repo", "Code", "π"],
|
| 1003 |
+
["job", "Jobs", "βοΈ"],
|
| 1004 |
+
["bucket", "Buckets", "πͺ£"],
|
| 1005 |
+
];
|
| 1006 |
+
|
| 1007 |
+
const RESOURCE_ICONS = Object.fromEntries(
|
| 1008 |
+
RESOURCE_SECTIONS.map(([kind, , icon]) => [kind, icon])
|
| 1009 |
+
);
|
| 1010 |
+
|
| 1011 |
+
const ARTIFACT_ICON_IMG = `<img class="art-ico" src="./bucket-icon.svg" alt="" />`;
|
| 1012 |
+
const DASHBOARD_ICON_IMG = `<img class="art-ico" src="./trackio-logo-light.png" alt="" />`;
|
| 1013 |
+
|
| 1014 |
+
const RESOURCE_DESC = {
|
| 1015 |
+
dashboard: "Dashboard",
|
| 1016 |
+
model: "Model",
|
| 1017 |
+
dataset: "Dataset",
|
| 1018 |
+
space: "Space",
|
| 1019 |
+
artifact: "Artifact β in Bucket",
|
| 1020 |
+
paper: "Paper",
|
| 1021 |
+
repo: "Repository",
|
| 1022 |
+
job: "Job β status & logs",
|
| 1023 |
+
bucket: "Bucket β artifacts & data",
|
| 1024 |
+
};
|
| 1025 |
+
|
| 1026 |
+
const HF_NON_MODEL_PREFIX =
|
| 1027 |
+
/^(datasets|spaces|jobs|buckets|papers|blog|docs|api|posts|collections|organizations|settings|new|join|login|pricing|tasks|learn|chat|models)(\/|$)/;
|
| 1028 |
+
|
| 1029 |
+
function hfId(url, marker) {
|
| 1030 |
+
return url.split(marker)[1].split(/[?#]/)[0].replace(/\/$/, "");
|
| 1031 |
+
}
|
| 1032 |
+
|
| 1033 |
+
function classifyResource(url) {
|
| 1034 |
+
if (IMG_URL.test(url)) {
|
| 1035 |
+
return null;
|
| 1036 |
+
}
|
| 1037 |
+
let m;
|
| 1038 |
+
if (url.startsWith("trackio-local-dashboard://")) {
|
| 1039 |
+
return {
|
| 1040 |
+
kind: "dashboard",
|
| 1041 |
+
id: url.slice("trackio-local-dashboard://".length),
|
| 1042 |
+
url,
|
| 1043 |
+
local: true,
|
| 1044 |
+
};
|
| 1045 |
+
}
|
| 1046 |
+
if (url.startsWith("trackio-artifact://")) {
|
| 1047 |
+
return {
|
| 1048 |
+
kind: "artifact",
|
| 1049 |
+
id: url.slice("trackio-artifact://".length),
|
| 1050 |
+
url,
|
| 1051 |
+
local: true,
|
| 1052 |
+
};
|
| 1053 |
+
}
|
| 1054 |
+
if (url.startsWith("trackio-local-path://")) {
|
| 1055 |
+
return {
|
| 1056 |
+
kind: "artifact",
|
| 1057 |
+
id: url.slice("trackio-local-path://".length),
|
| 1058 |
+
url,
|
| 1059 |
+
local: true,
|
| 1060 |
+
};
|
| 1061 |
+
}
|
| 1062 |
+
if ((m = url.match(/huggingface\.co\/buckets\/[^#\s]+#(.+)/))) {
|
| 1063 |
+
return { kind: "artifact", id: decodeURIComponent(m[1]), url };
|
| 1064 |
+
}
|
| 1065 |
+
if (/huggingface\.co\/datasets\/[^/]+\/[^/]+/.test(url)) {
|
| 1066 |
+
return { kind: "dataset", id: hfId(url, "/datasets/"), url };
|
| 1067 |
+
}
|
| 1068 |
+
if (/huggingface\.co\/spaces\/[^/]+\/[^/]+/.test(url)) {
|
| 1069 |
+
return { kind: "space", id: hfId(url, "/spaces/"), url };
|
| 1070 |
+
}
|
| 1071 |
+
if (/huggingface\.co\/jobs\//.test(url)) {
|
| 1072 |
+
const parts = hfId(url, "/jobs/").split("/");
|
| 1073 |
+
const jid = parts[1] || "";
|
| 1074 |
+
return {
|
| 1075 |
+
kind: "job",
|
| 1076 |
+
id: parts[0] + (jid ? ` Β· ${jid.slice(0, 12)}${jid.length > 12 ? "β¦" : ""}` : ""),
|
| 1077 |
+
url,
|
| 1078 |
+
};
|
| 1079 |
+
}
|
| 1080 |
+
if (/huggingface\.co\/buckets\//.test(url)) {
|
| 1081 |
+
return { kind: "bucket", id: hfId(url, "/buckets/"), url };
|
| 1082 |
+
}
|
| 1083 |
+
if (/huggingface\.co\/papers\//.test(url)) {
|
| 1084 |
+
return { kind: "paper", id: `Paper ${hfId(url, "/papers/")}`, url };
|
| 1085 |
+
}
|
| 1086 |
+
if ((m = url.match(/arxiv\.org\/(?:abs|pdf)\/([^?#\s]+)/))) {
|
| 1087 |
+
return { kind: "paper", id: `arXiv:${m[1].replace(/\.pdf$/, "")}`, url };
|
| 1088 |
+
}
|
| 1089 |
+
if ((m = url.match(/github\.com\/([^/?#]+\/[^/?#]+)/))) {
|
| 1090 |
+
return { kind: "repo", id: m[1], url };
|
| 1091 |
+
}
|
| 1092 |
+
if ((m = url.match(/huggingface\.co\/([^?#]+)/))) {
|
| 1093 |
+
const rest = m[1].replace(/\/$/, "");
|
| 1094 |
+
if (/^[^/]+\/[^/]+$/.test(rest) && !HF_NON_MODEL_PREFIX.test(rest)) {
|
| 1095 |
+
return { kind: "model", id: rest, url };
|
| 1096 |
+
}
|
| 1097 |
+
}
|
| 1098 |
+
return null;
|
| 1099 |
+
}
|
| 1100 |
+
|
| 1101 |
+
async function fillRailMeta(item, el) {
|
| 1102 |
+
if (item.local) return;
|
| 1103 |
+
const meta = el.querySelector(".rail-meta");
|
| 1104 |
+
const set = (parts) => {
|
| 1105 |
+
const text = parts.filter(Boolean).join(" Β· ");
|
| 1106 |
+
if (text) meta.textContent = text;
|
| 1107 |
+
};
|
| 1108 |
+
if (item.kind === "model") {
|
| 1109 |
+
const d = await getJSON(`https://huggingface.co/api/models/${item.id}`);
|
| 1110 |
+
if (d) set([d.pipeline_tag, `β ${fmt(d.downloads)}`, `β₯ ${fmt(d.likes)}`]);
|
| 1111 |
+
} else if (item.kind === "dataset") {
|
| 1112 |
+
const d = await getJSON(`https://huggingface.co/api/datasets/${item.id}`);
|
| 1113 |
+
if (d) set([`β ${fmt(d.downloads)}`, `β₯ ${fmt(d.likes)}`]);
|
| 1114 |
+
} else if (item.kind === "space" || item.kind === "dashboard") {
|
| 1115 |
+
const d = await getJSON(`https://huggingface.co/api/spaces/${item.id}`);
|
| 1116 |
+
if (d) set([d.sdk, `β₯ ${fmt(d.likes)}`]);
|
| 1117 |
+
} else if (item.kind === "repo") {
|
| 1118 |
+
const d = await getJSON(`https://api.github.com/repos/${item.id}`);
|
| 1119 |
+
if (d) set([`β
${fmt(d.stargazers_count)}`, d.language]);
|
| 1120 |
+
} else if (item.kind === "paper") {
|
| 1121 |
+
const m = item.id.match(/^(?:arXiv:|Paper )(.+)$/);
|
| 1122 |
+
if (!m) return;
|
| 1123 |
+
const arxivId = m[1].replace(/v\d+$/, "");
|
| 1124 |
+
const d = await getJSON(`https://huggingface.co/api/papers/${arxivId}`);
|
| 1125 |
+
if (d && d.id) {
|
| 1126 |
+
if (el.href) el.href = `https://huggingface.co/papers/${d.id}`;
|
| 1127 |
+
const title =
|
| 1128 |
+
d.title && d.title.length > 70 ? `${d.title.slice(0, 69)}β¦` : d.title;
|
| 1129 |
+
set([title, d.upvotes ? `β² ${fmt(d.upvotes)}` : null]);
|
| 1130 |
+
}
|
| 1131 |
+
}
|
| 1132 |
+
}
|
| 1133 |
+
|
| 1134 |
+
const BARE_ID_SKIP_DIRS = new Set([
|
| 1135 |
+
"scripts",
|
| 1136 |
+
"configs",
|
| 1137 |
+
"config",
|
| 1138 |
+
"results",
|
| 1139 |
+
"figures",
|
| 1140 |
+
"data",
|
| 1141 |
+
"datasets",
|
| 1142 |
+
"src",
|
| 1143 |
+
"tests",
|
| 1144 |
+
"test",
|
| 1145 |
+
"examples",
|
| 1146 |
+
"pages",
|
| 1147 |
+
"assets",
|
| 1148 |
+
"docs",
|
| 1149 |
+
"outputs",
|
| 1150 |
+
"output",
|
| 1151 |
+
"checkpoints",
|
| 1152 |
+
"models",
|
| 1153 |
+
"utils",
|
| 1154 |
+
"lib",
|
| 1155 |
+
"bin",
|
| 1156 |
+
"tmp",
|
| 1157 |
+
"node_modules",
|
| 1158 |
+
"dist",
|
| 1159 |
+
"build",
|
| 1160 |
+
]);
|
| 1161 |
+
const FILE_EXT_RE =
|
| 1162 |
+
/\.(py|pyc|js|ts|jsx|tsx|json|jsonl|yaml|yml|csv|tsv|md|txt|sh|bash|html|css|png|jpe?g|svg|gif|webp|ipynb|toml|cfg|ini|lock|pdf|whl|gz|zip|tar|pt|pth|bin|safetensors|db|sqlite)$/i;
|
| 1163 |
+
|
| 1164 |
+
async function detectBareModelIds(text, groups) {
|
| 1165 |
+
const stripped = text.replace(DETECTED_URL, " ");
|
| 1166 |
+
DETECTED_URL.lastIndex = 0;
|
| 1167 |
+
const seen = new Set();
|
| 1168 |
+
const candidates = [];
|
| 1169 |
+
const re = /(^|[\s"'`(=[])([A-Za-z0-9][\w.-]*\/[A-Za-z0-9][\w.-]*)/g;
|
| 1170 |
+
let m;
|
| 1171 |
+
while ((m = re.exec(stripped)) && candidates.length < 15) {
|
| 1172 |
+
const id = m[2].replace(/[.:,]+$/, "");
|
| 1173 |
+
if (seen.has(id)) continue;
|
| 1174 |
+
seen.add(id);
|
| 1175 |
+
if (FILE_EXT_RE.test(id)) continue;
|
| 1176 |
+
if (BARE_ID_SKIP_DIRS.has(id.split("/")[0].toLowerCase())) continue;
|
| 1177 |
+
candidates.push(id);
|
| 1178 |
+
}
|
| 1179 |
+
const results = await Promise.all(
|
| 1180 |
+
candidates.map((id) => getJSON(`https://huggingface.co/api/models/${id}`))
|
| 1181 |
+
);
|
| 1182 |
+
let added = false;
|
| 1183 |
+
const confirmed = [];
|
| 1184 |
+
results.forEach((d, i) => {
|
| 1185 |
+
if (!d || !d.id) return;
|
| 1186 |
+
const id = candidates[i];
|
| 1187 |
+
confirmed.push(id);
|
| 1188 |
+
const url = `https://huggingface.co/${id}`;
|
| 1189 |
+
if (!groups.has("model")) groups.set("model", new Map());
|
| 1190 |
+
if (!groups.get("model").has(url)) {
|
| 1191 |
+
groups.get("model").set(url, { kind: "model", id, url });
|
| 1192 |
+
added = true;
|
| 1193 |
+
}
|
| 1194 |
+
});
|
| 1195 |
+
return { added, confirmed };
|
| 1196 |
+
}
|
| 1197 |
+
|
| 1198 |
+
function chipifyBareIds(ids, container) {
|
| 1199 |
+
if (!ids.length) return;
|
| 1200 |
+
const escaped = ids.map((id) => id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
| 1201 |
+
const pattern = new RegExp("(" + escaped.join("|") + ")");
|
| 1202 |
+
const splitter = new RegExp(pattern.source, "g");
|
| 1203 |
+
container
|
| 1204 |
+
.querySelectorAll(".cell.markdown .cell-body")
|
| 1205 |
+
.forEach((body) => {
|
| 1206 |
+
const walker = document.createTreeWalker(body, NodeFilter.SHOW_TEXT, {
|
| 1207 |
+
acceptNode(node) {
|
| 1208 |
+
if (!pattern.test(node.nodeValue)) return NodeFilter.FILTER_REJECT;
|
| 1209 |
+
for (
|
| 1210 |
+
let el = node.parentElement;
|
| 1211 |
+
el && el !== body;
|
| 1212 |
+
el = el.parentElement
|
| 1213 |
+
) {
|
| 1214 |
+
if (["A", "CODE", "PRE", "BUTTON"].indexOf(el.tagName) !== -1) {
|
| 1215 |
+
return NodeFilter.FILTER_REJECT;
|
| 1216 |
+
}
|
| 1217 |
+
}
|
| 1218 |
+
return NodeFilter.FILTER_ACCEPT;
|
| 1219 |
+
},
|
| 1220 |
+
});
|
| 1221 |
+
const nodes = [];
|
| 1222 |
+
while (walker.nextNode()) nodes.push(walker.currentNode);
|
| 1223 |
+
nodes.forEach((node) => {
|
| 1224 |
+
const frag = document.createDocumentFragment();
|
| 1225 |
+
node.nodeValue.split(splitter).forEach((part) => {
|
| 1226 |
+
if (ids.indexOf(part) !== -1) {
|
| 1227 |
+
const holder = document.createElement("span");
|
| 1228 |
+
holder.innerHTML = resChipHtml({
|
| 1229 |
+
kind: "model",
|
| 1230 |
+
id: part,
|
| 1231 |
+
url: `https://huggingface.co/${part}`,
|
| 1232 |
+
});
|
| 1233 |
+
frag.appendChild(holder.firstChild);
|
| 1234 |
+
} else if (part) {
|
| 1235 |
+
frag.appendChild(document.createTextNode(part));
|
| 1236 |
+
}
|
| 1237 |
+
});
|
| 1238 |
+
node.parentNode.replaceChild(frag, node);
|
| 1239 |
+
});
|
| 1240 |
+
});
|
| 1241 |
+
}
|
| 1242 |
+
|
| 1243 |
+
let RAIL_TOKEN = 0;
|
| 1244 |
+
const RAIL_EXCLUDE_KINDS = new Set(["paper", "repo", "artifact", "dashboard"]);
|
| 1245 |
+
|
| 1246 |
+
function railDashboardItem(it) {
|
| 1247 |
+
return {
|
| 1248 |
+
kind: "dashboard",
|
| 1249 |
+
id: it.id,
|
| 1250 |
+
url: it.local ? it.resUrl : it.url || it.resUrl,
|
| 1251 |
+
local: it.local,
|
| 1252 |
+
railLabel: "Dashboard",
|
| 1253 |
+
};
|
| 1254 |
+
}
|
| 1255 |
+
|
| 1256 |
+
function promoteTrackioSpacesInRail(groups, dashResUrls, body, rail, token) {
|
| 1257 |
+
const spaceGroup = groups.get("space");
|
| 1258 |
+
if (!spaceGroup || !spaceGroup.size) return;
|
| 1259 |
+
spaceGroup.forEach((item, url) => {
|
| 1260 |
+
getJSON(`https://huggingface.co/api/spaces/${item.id}`)
|
| 1261 |
+
.then((d) => {
|
| 1262 |
+
if (rail.dataset.renderToken !== token) return;
|
| 1263 |
+
const tags = (d && d.tags) || [];
|
| 1264 |
+
if (!tags.some((t) => String(t).toLowerCase() === "trackio")) return;
|
| 1265 |
+
if (dashResUrls.has(url)) return;
|
| 1266 |
+
spaceGroup.delete(url);
|
| 1267 |
+
if (!spaceGroup.size) groups.delete("space");
|
| 1268 |
+
if (!groups.has("dashboard")) groups.set("dashboard", new Map());
|
| 1269 |
+
groups.get("dashboard").set(url, {
|
| 1270 |
+
kind: "dashboard",
|
| 1271 |
+
id: item.id,
|
| 1272 |
+
url: item.url,
|
| 1273 |
+
local: false,
|
| 1274 |
+
railLabel: "Dashboard",
|
| 1275 |
+
});
|
| 1276 |
+
dashResUrls.add(url);
|
| 1277 |
+
paintRail(groups, body, rail);
|
| 1278 |
+
})
|
| 1279 |
+
.catch(() => {});
|
| 1280 |
+
});
|
| 1281 |
+
}
|
| 1282 |
+
|
| 1283 |
+
function renderRail(md, body, rail) {
|
| 1284 |
+
const token = String(++RAIL_TOKEN);
|
| 1285 |
+
rail.dataset.renderToken = token;
|
| 1286 |
+
const scanText = md.replace(
|
| 1287 |
+
/(`{3,4}|~{3,4})(html|raw)[^\n]*\n[\s\S]*?\n\1/g,
|
| 1288 |
+
" "
|
| 1289 |
+
);
|
| 1290 |
+
const groups = new Map();
|
| 1291 |
+
const dashMap = new Map();
|
| 1292 |
+
const dashResUrls = new Set();
|
| 1293 |
+
cellDashboardItems(md).forEach((it) => {
|
| 1294 |
+
if (dashMap.has(it.resUrl)) return;
|
| 1295 |
+
dashMap.set(it.resUrl, railDashboardItem(it));
|
| 1296 |
+
dashResUrls.add(it.resUrl);
|
| 1297 |
+
});
|
| 1298 |
+
if (dashMap.size) groups.set("dashboard", dashMap);
|
| 1299 |
+
extractUrls(scanText).forEach((url) => {
|
| 1300 |
+
const item = classifyResource(url);
|
| 1301 |
+
if (!item) return;
|
| 1302 |
+
if (RAIL_EXCLUDE_KINDS.has(item.kind)) return;
|
| 1303 |
+
if (dashResUrls.has(url)) return;
|
| 1304 |
+
if (!groups.has(item.kind)) groups.set(item.kind, new Map());
|
| 1305 |
+
groups.get(item.kind).set(item.url, item);
|
| 1306 |
+
});
|
| 1307 |
+
const artMap = new Map();
|
| 1308 |
+
cellArtifactItems(md).forEach((it) => {
|
| 1309 |
+
if (artMap.has(it.resUrl)) return;
|
| 1310 |
+
const label = it.type
|
| 1311 |
+
? it.type.charAt(0).toUpperCase() + it.type.slice(1)
|
| 1312 |
+
: "Artifact";
|
| 1313 |
+
artMap.set(it.resUrl, {
|
| 1314 |
+
kind: "artifact",
|
| 1315 |
+
id: it.name,
|
| 1316 |
+
url: it.local ? it.resUrl : it.url || it.resUrl,
|
| 1317 |
+
local: it.local,
|
| 1318 |
+
railLabel: label,
|
| 1319 |
+
size: it.size,
|
| 1320 |
+
});
|
| 1321 |
+
});
|
| 1322 |
+
if (artMap.size) groups.set("artifact", artMap);
|
| 1323 |
+
paintRail(groups, body, rail);
|
| 1324 |
+
promoteTrackioSpacesInRail(groups, dashResUrls, body, rail, token);
|
| 1325 |
+
detectBareModelIds(scanText, groups)
|
| 1326 |
+
.then((result) => {
|
| 1327 |
+
if (rail.dataset.renderToken !== token) return;
|
| 1328 |
+
chipifyBareIds(result.confirmed, body);
|
| 1329 |
+
if (result.added) paintRail(groups, body, rail);
|
| 1330 |
+
})
|
| 1331 |
+
.catch(() => {});
|
| 1332 |
+
}
|
| 1333 |
+
|
| 1334 |
+
function paintRail(groups, body, rail) {
|
| 1335 |
+
rail.innerHTML = "";
|
| 1336 |
+
RESOURCE_SECTIONS.forEach(([kind, label, icon]) => {
|
| 1337 |
+
const group = groups.get(kind);
|
| 1338 |
+
if (!group || !group.size) return;
|
| 1339 |
+
group.forEach((item) => {
|
| 1340 |
+
const el = document.createElement(item.local ? "div" : "a");
|
| 1341 |
+
el.className = item.local ? "rail-item rail-local" : "rail-item";
|
| 1342 |
+
if (!item.local) {
|
| 1343 |
+
el.href = item.url;
|
| 1344 |
+
el.target = "_blank";
|
| 1345 |
+
el.rel = "noopener";
|
| 1346 |
+
}
|
| 1347 |
+
el.dataset.resUrl = item.url;
|
| 1348 |
+
let desc;
|
| 1349 |
+
if (kind === "artifact") {
|
| 1350 |
+
const state = item.local ? "publish to share" : "Open β";
|
| 1351 |
+
desc = item.size ? `${item.size} Β· ${state}` : state;
|
| 1352 |
+
} else if (kind === "dashboard") {
|
| 1353 |
+
desc = item.local ? "publish to share" : "Open β";
|
| 1354 |
+
} else {
|
| 1355 |
+
desc = item.local ? "publish to share" : RESOURCE_DESC[kind];
|
| 1356 |
+
}
|
| 1357 |
+
const kindLabel = item.railLabel || label.replace(/s$/, "");
|
| 1358 |
+
const iconHtml =
|
| 1359 |
+
kind === "artifact"
|
| 1360 |
+
? ARTIFACT_ICON_IMG
|
| 1361 |
+
: kind === "dashboard"
|
| 1362 |
+
? DASHBOARD_ICON_IMG
|
| 1363 |
+
: `<span>${icon}</span>`;
|
| 1364 |
+
el.innerHTML =
|
| 1365 |
+
`<div class="rail-kind">${iconHtml}${esc(kindLabel)}</div>` +
|
| 1366 |
+
`<div class="rail-title">${esc(item.id)}</div>` +
|
| 1367 |
+
`<div class="rail-meta">${esc(desc)}</div>`;
|
| 1368 |
+
rail.appendChild(el);
|
| 1369 |
+
fillRailMeta(item, el)
|
| 1370 |
+
.catch(() => {})
|
| 1371 |
+
.finally(() => scheduleRailPosition(body, rail));
|
| 1372 |
+
});
|
| 1373 |
+
});
|
| 1374 |
+
rail.hidden = !rail.childElementCount;
|
| 1375 |
+
scheduleRailPosition(body, rail);
|
| 1376 |
+
}
|
| 1377 |
+
|
| 1378 |
+
function resourceAnchor(body, url) {
|
| 1379 |
+
return body.querySelector(`[data-res-url="${CSS.escape(url)}"]`);
|
| 1380 |
+
}
|
| 1381 |
+
|
| 1382 |
+
function positionRail(body, rail) {
|
| 1383 |
+
if (rail.hidden || !rail.isConnected) return;
|
| 1384 |
+
const bodyRect = body.getBoundingClientRect();
|
| 1385 |
+
const items = Array.from(rail.querySelectorAll(".rail-item")).map((el, index) => {
|
| 1386 |
+
const anchor = resourceAnchor(body, el.dataset.resUrl);
|
| 1387 |
+
return {
|
| 1388 |
+
el,
|
| 1389 |
+
index,
|
| 1390 |
+
desired: anchor
|
| 1391 |
+
? Math.max(0, anchor.getBoundingClientRect().top - bodyRect.top)
|
| 1392 |
+
: 0,
|
| 1393 |
+
};
|
| 1394 |
+
});
|
| 1395 |
+
items.sort((a, b) => a.desired - b.desired || a.index - b.index);
|
| 1396 |
+
let cursor = 0;
|
| 1397 |
+
items.forEach(({ el, desired }) => {
|
| 1398 |
+
const top = Math.max(desired, cursor);
|
| 1399 |
+
el.style.top = `${top}px`;
|
| 1400 |
+
cursor = top + el.offsetHeight + 10;
|
| 1401 |
+
});
|
| 1402 |
+
rail.style.minHeight = `${Math.max(body.offsetHeight, cursor)}px`;
|
| 1403 |
+
}
|
| 1404 |
+
|
| 1405 |
+
function scheduleRailPosition(body, rail) {
|
| 1406 |
+
cancelAnimationFrame(Number(rail.dataset.positionFrame || 0));
|
| 1407 |
+
rail.dataset.positionFrame = String(
|
| 1408 |
+
requestAnimationFrame(() => positionRail(body, rail))
|
| 1409 |
+
);
|
| 1410 |
+
}
|
| 1411 |
+
|
| 1412 |
+
function dashboardSubdomainFromUrl(url) {
|
| 1413 |
+
return spaceIdFromUrl(url).toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
| 1414 |
+
}
|
| 1415 |
+
|
| 1416 |
+
function dashboardOpenLink(head, url) {
|
| 1417 |
+
if (!head || !url) return;
|
| 1418 |
+
const meta = head.querySelector(".cell-meta");
|
| 1419 |
+
if (!meta) return;
|
| 1420 |
+
let link = meta.querySelector(".cell-open");
|
| 1421 |
+
if (!link) {
|
| 1422 |
+
link = document.createElement("a");
|
| 1423 |
+
link.className = "cell-open";
|
| 1424 |
+
link.target = "_blank";
|
| 1425 |
+
link.rel = "noopener";
|
| 1426 |
+
meta.insertBefore(link, meta.firstChild);
|
| 1427 |
+
}
|
| 1428 |
+
link.href = url;
|
| 1429 |
+
link.textContent = "Open β";
|
| 1430 |
+
}
|
| 1431 |
+
|
| 1432 |
+
function dashboardFrame(src) {
|
| 1433 |
+
const iframe = document.createElement("iframe");
|
| 1434 |
+
iframe.className = "dashboard-frame";
|
| 1435 |
+
iframe.src = src;
|
| 1436 |
+
iframe.loading = "lazy";
|
| 1437 |
+
iframe.allow = "clipboard-read; clipboard-write; fullscreen";
|
| 1438 |
+
return iframe;
|
| 1439 |
+
}
|
| 1440 |
+
|
| 1441 |
+
function renderDashboardCell(meta, body, container, head) {
|
| 1442 |
+
const project = meta.dashboard_project || "";
|
| 1443 |
+
const holder = document.createElement("div");
|
| 1444 |
+
holder.className = "dashboard-shell";
|
| 1445 |
+
container.appendChild(holder);
|
| 1446 |
+
const space = body.match(/https:\/\/huggingface\.co\/spaces\/[^\s<>)"'`]+/);
|
| 1447 |
+
if (space) {
|
| 1448 |
+
const url = space[0];
|
| 1449 |
+
dashboardOpenLink(head, url);
|
| 1450 |
+
holder.appendChild(
|
| 1451 |
+
dashboardFrame(
|
| 1452 |
+
`https://${dashboardSubdomainFromUrl(url)}.hf.space/?sidebar=hidden&hide_empty_tabs=true`
|
| 1453 |
+
)
|
| 1454 |
+
);
|
| 1455 |
+
return;
|
| 1456 |
+
}
|
| 1457 |
+
if (!isLocalPreview()) {
|
| 1458 |
+
holder.className = "artifact-chip";
|
| 1459 |
+
holder.dataset.resUrl = `trackio-local-dashboard://${project}`;
|
| 1460 |
+
holder.innerHTML =
|
| 1461 |
+
"π― <strong>Local Trackio dashboard</strong> β publish the logbook to share it";
|
| 1462 |
+
return;
|
| 1463 |
+
}
|
| 1464 |
+
const open = "/dashboard/?project=" + encodeURIComponent(project);
|
| 1465 |
+
dashboardOpenLink(head, open);
|
| 1466 |
+
holder.appendChild(
|
| 1467 |
+
dashboardFrame(open + "&sidebar=hidden&hide_empty_tabs=true"),
|
| 1468 |
+
);
|
| 1469 |
+
}
|
| 1470 |
+
|
| 1471 |
+
const CACHE_PREFIX = "trackio-logbook:";
|
| 1472 |
+
const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
| 1473 |
+
const CACHE_MISS_TTL_MS = 60 * 60 * 1000;
|
| 1474 |
+
|
| 1475 |
+
function cacheGet(url) {
|
| 1476 |
+
try {
|
| 1477 |
+
const raw = localStorage.getItem(CACHE_PREFIX + url);
|
| 1478 |
+
if (!raw) return undefined;
|
| 1479 |
+
const entry = JSON.parse(raw);
|
| 1480 |
+
const ttl = entry.d === null ? CACHE_MISS_TTL_MS : CACHE_TTL_MS;
|
| 1481 |
+
if (Date.now() - entry.t > ttl) {
|
| 1482 |
+
localStorage.removeItem(CACHE_PREFIX + url);
|
| 1483 |
+
return undefined;
|
| 1484 |
+
}
|
| 1485 |
+
return entry.d;
|
| 1486 |
+
} catch (e) {
|
| 1487 |
+
return undefined;
|
| 1488 |
+
}
|
| 1489 |
+
}
|
| 1490 |
+
|
| 1491 |
+
function cacheSet(url, data) {
|
| 1492 |
+
try {
|
| 1493 |
+
localStorage.setItem(
|
| 1494 |
+
CACHE_PREFIX + url,
|
| 1495 |
+
JSON.stringify({ t: Date.now(), d: data })
|
| 1496 |
+
);
|
| 1497 |
+
} catch (e) {}
|
| 1498 |
+
}
|
| 1499 |
+
|
| 1500 |
+
async function getJSON(url) {
|
| 1501 |
+
if (UNFURL_CACHE[url] !== undefined) return UNFURL_CACHE[url];
|
| 1502 |
+
const cached = cacheGet(url);
|
| 1503 |
+
if (cached !== undefined) {
|
| 1504 |
+
UNFURL_CACHE[url] = cached;
|
| 1505 |
+
return cached;
|
| 1506 |
+
}
|
| 1507 |
+
try {
|
| 1508 |
+
const r = await fetch(url);
|
| 1509 |
+
if (!r.ok) throw new Error(r.status);
|
| 1510 |
+
const j = await r.json();
|
| 1511 |
+
UNFURL_CACHE[url] = j;
|
| 1512 |
+
cacheSet(url, j);
|
| 1513 |
+
return j;
|
| 1514 |
+
} catch (e) {
|
| 1515 |
+
UNFURL_CACHE[url] = null;
|
| 1516 |
+
cacheSet(url, null);
|
| 1517 |
+
return null;
|
| 1518 |
+
}
|
| 1519 |
+
}
|
| 1520 |
+
|
| 1521 |
+
/* -------------------- routing / render -------------------- */
|
| 1522 |
+
|
| 1523 |
+
function buildTree() {
|
| 1524 |
+
const tree = document.getElementById("tree");
|
| 1525 |
+
tree.innerHTML = "";
|
| 1526 |
+
const nodes = [];
|
| 1527 |
+
(MANIFEST.root.children || []).forEach((c) => flattenTree(c, 0, nodes));
|
| 1528 |
+
nodes.forEach(({ node, depth }) => {
|
| 1529 |
+
const a = document.createElement("a");
|
| 1530 |
+
a.href = "#/" + node.slug;
|
| 1531 |
+
a.className = "depth-" + depth;
|
| 1532 |
+
a.dataset.slug = node.slug;
|
| 1533 |
+
const mark = document.createElement("span");
|
| 1534 |
+
mark.className = "tree-mark";
|
| 1535 |
+
mark.textContent = "Β§";
|
| 1536 |
+
a.appendChild(mark);
|
| 1537 |
+
a.appendChild(document.createTextNode(" " + node.title));
|
| 1538 |
+
tree.appendChild(a);
|
| 1539 |
+
});
|
| 1540 |
+
}
|
| 1541 |
+
|
| 1542 |
+
function highlight(slug) {
|
| 1543 |
+
document
|
| 1544 |
+
.querySelectorAll("#tree a")
|
| 1545 |
+
.forEach((a) => a.classList.toggle("active", a.dataset.slug === slug));
|
| 1546 |
+
document
|
| 1547 |
+
.getElementById("book-head")
|
| 1548 |
+
.classList.toggle("active", slug === MANIFEST.root.slug);
|
| 1549 |
+
}
|
| 1550 |
+
|
| 1551 |
+
function clearPageCache() {
|
| 1552 |
+
Object.keys(PAGE_CACHE).forEach((key) => {
|
| 1553 |
+
delete PAGE_CACHE[key];
|
| 1554 |
+
});
|
| 1555 |
+
}
|
| 1556 |
+
|
| 1557 |
+
function isLocalPreview() {
|
| 1558 |
+
return ["localhost", "127.0.0.1", "::1"].includes(location.hostname);
|
| 1559 |
+
}
|
| 1560 |
+
|
| 1561 |
+
async function fetchManifest() {
|
| 1562 |
+
const suffix = isLocalPreview() ? `?t=${Date.now()}` : "";
|
| 1563 |
+
return await (await fetch("./logbook.json" + suffix, { cache: "no-store" })).json();
|
| 1564 |
+
}
|
| 1565 |
+
|
| 1566 |
+
async function fetchPage(node) {
|
| 1567 |
+
if (PAGE_CACHE[node.file]) return PAGE_CACHE[node.file];
|
| 1568 |
+
try {
|
| 1569 |
+
const suffix = isLocalPreview()
|
| 1570 |
+
? `?rev=${encodeURIComponent(MANIFEST.revision || "")}`
|
| 1571 |
+
: "";
|
| 1572 |
+
const r = await fetch("./" + node.file + suffix, { cache: "no-store" });
|
| 1573 |
+
PAGE_CACHE[node.file] = await r.text();
|
| 1574 |
+
} catch (e) {
|
| 1575 |
+
PAGE_CACHE[node.file] = "# " + node.title + "\n\n_Could not load section._";
|
| 1576 |
+
}
|
| 1577 |
+
return PAGE_CACHE[node.file];
|
| 1578 |
+
}
|
| 1579 |
+
|
| 1580 |
+
function allNodes() {
|
| 1581 |
+
const nodes = [];
|
| 1582 |
+
flattenTree(MANIFEST.root, 0, nodes);
|
| 1583 |
+
return nodes.map(({ node }) => node);
|
| 1584 |
+
}
|
| 1585 |
+
|
| 1586 |
+
function collectPinnedCells(markdown, nodes) {
|
| 1587 |
+
const cells = [];
|
| 1588 |
+
markdown.forEach((text, index) => {
|
| 1589 |
+
const cellRe = /(^|\n)---\n<!-- trackio-cell\n([\s\S]*?)\n-->\n([\s\S]*?)(?=\n---\n<!-- trackio-cell\n|\s*$)/g;
|
| 1590 |
+
let match;
|
| 1591 |
+
let cellIndex = 0;
|
| 1592 |
+
while ((match = cellRe.exec(text))) {
|
| 1593 |
+
const meta = parseCellMeta(match[2]);
|
| 1594 |
+
if (isPinned(meta)) {
|
| 1595 |
+
cells.push({
|
| 1596 |
+
meta,
|
| 1597 |
+
body: match[3],
|
| 1598 |
+
node: nodes[index],
|
| 1599 |
+
index: cells.length,
|
| 1600 |
+
order: meta.pinned_at || meta.created_at || "",
|
| 1601 |
+
cellIndex,
|
| 1602 |
+
});
|
| 1603 |
+
}
|
| 1604 |
+
cellIndex++;
|
| 1605 |
+
}
|
| 1606 |
+
});
|
| 1607 |
+
return cells.sort(
|
| 1608 |
+
(a, b) =>
|
| 1609 |
+
a.order.localeCompare(b.order) ||
|
| 1610 |
+
a.index - b.index ||
|
| 1611 |
+
a.cellIndex - b.cellIndex
|
| 1612 |
+
);
|
| 1613 |
+
}
|
| 1614 |
+
|
| 1615 |
+
function renderPinnedNotes(cells, container) {
|
| 1616 |
+
if (!cells.length) return;
|
| 1617 |
+
const deck = document.createElement("section");
|
| 1618 |
+
deck.className = "pinned-notes";
|
| 1619 |
+
const list = document.createElement("div");
|
| 1620 |
+
list.className = "pinned-notes-list";
|
| 1621 |
+
cells.forEach(({ meta, body }) => {
|
| 1622 |
+
const cell = renderCell(meta, body, list);
|
| 1623 |
+
cell.classList.add("pinned-copy");
|
| 1624 |
+
});
|
| 1625 |
+
deck.appendChild(list);
|
| 1626 |
+
const anchor =
|
| 1627 |
+
container.querySelector(".logbook-stats") ||
|
| 1628 |
+
container.querySelector(".agent-hint");
|
| 1629 |
+
container.insertBefore(deck, anchor ? anchor.nextSibling : container.firstChild);
|
| 1630 |
+
container.closest(".book-intro").classList.add("has-pinned-notes");
|
| 1631 |
+
}
|
| 1632 |
+
|
| 1633 |
+
function removeIndexProse(body) {
|
| 1634 |
+
const h1 = Array.from(body.children).find((el) => el.tagName === "H1");
|
| 1635 |
+
if (!h1) return;
|
| 1636 |
+
let current = h1.nextElementSibling;
|
| 1637 |
+
while (current && current.tagName !== "H2") {
|
| 1638 |
+
const next = current.nextElementSibling;
|
| 1639 |
+
current.remove();
|
| 1640 |
+
current = next;
|
| 1641 |
+
}
|
| 1642 |
+
}
|
| 1643 |
+
|
| 1644 |
+
function removePageDirectory(body) {
|
| 1645 |
+
const heading = Array.from(body.children).find(
|
| 1646 |
+
(el) => el.tagName === "H2" && el.textContent.trim().toLowerCase() === "pages"
|
| 1647 |
+
);
|
| 1648 |
+
if (!heading) return;
|
| 1649 |
+
let current = heading;
|
| 1650 |
+
while (current) {
|
| 1651 |
+
const next = current.nextElementSibling;
|
| 1652 |
+
current.remove();
|
| 1653 |
+
if (next && ["H1", "H2"].includes(next.tagName)) break;
|
| 1654 |
+
current = next;
|
| 1655 |
+
}
|
| 1656 |
+
}
|
| 1657 |
+
|
| 1658 |
+
const RAIL_OBSERVERS = [];
|
| 1659 |
+
|
| 1660 |
+
async function renderLogbook(opts = {}) {
|
| 1661 |
+
const scrollY = window.scrollY;
|
| 1662 |
+
const page = document.getElementById("page");
|
| 1663 |
+
RAIL_OBSERVERS.splice(0).forEach((observer) => observer.disconnect());
|
| 1664 |
+
page.innerHTML = "";
|
| 1665 |
+
const nodes = allNodes();
|
| 1666 |
+
const markdown = await Promise.all(nodes.map(fetchPage));
|
| 1667 |
+
const pinnedCells = collectPinnedCells(markdown, nodes);
|
| 1668 |
+
let bookIntroBody = null;
|
| 1669 |
+
nodes.forEach((node, index) => {
|
| 1670 |
+
const section = document.createElement("section");
|
| 1671 |
+
section.className = "page-section";
|
| 1672 |
+
section.id = "/" + node.slug;
|
| 1673 |
+
section.dataset.slug = node.slug;
|
| 1674 |
+
|
| 1675 |
+
const layout = document.createElement("div");
|
| 1676 |
+
layout.className = "page-layout";
|
| 1677 |
+
const body = document.createElement("div");
|
| 1678 |
+
body.className = "page-body";
|
| 1679 |
+
const rail = document.createElement("aside");
|
| 1680 |
+
rail.className = "context-rail";
|
| 1681 |
+
rail.setAttribute("aria-label", `Resources for ${node.title}`);
|
| 1682 |
+
|
| 1683 |
+
renderMarkdown(markdown[index], body);
|
| 1684 |
+
if (node.slug === MANIFEST.root.slug) {
|
| 1685 |
+
section.classList.add("book-intro");
|
| 1686 |
+
removeIndexProse(body);
|
| 1687 |
+
removePageDirectory(body);
|
| 1688 |
+
const hint = buildAgentHint();
|
| 1689 |
+
const h1 = body.querySelector("h1");
|
| 1690 |
+
if (h1 && h1.parentNode === body) {
|
| 1691 |
+
body.insertBefore(hint, h1.nextSibling);
|
| 1692 |
+
} else {
|
| 1693 |
+
body.prepend(hint);
|
| 1694 |
+
}
|
| 1695 |
+
hint.after(buildLogbookStats(markdown));
|
| 1696 |
+
bookIntroBody = body;
|
| 1697 |
+
}
|
| 1698 |
+
layout.appendChild(body);
|
| 1699 |
+
layout.appendChild(rail);
|
| 1700 |
+
section.appendChild(layout);
|
| 1701 |
+
page.appendChild(section);
|
| 1702 |
+
renderRail(markdown[index], body, rail);
|
| 1703 |
+
if (window.ResizeObserver) {
|
| 1704 |
+
const observer = new ResizeObserver(() => scheduleRailPosition(body, rail));
|
| 1705 |
+
observer.observe(body);
|
| 1706 |
+
observer.observe(rail);
|
| 1707 |
+
RAIL_OBSERVERS.push(observer);
|
| 1708 |
+
}
|
| 1709 |
+
});
|
| 1710 |
+
if (bookIntroBody) renderPinnedNotes(pinnedCells, bookIntroBody);
|
| 1711 |
+
if (bookIntroBody) {
|
| 1712 |
+
const section = bookIntroBody.closest(".book-intro");
|
| 1713 |
+
const hasExtra = Array.from(bookIntroBody.children).some(
|
| 1714 |
+
(el) =>
|
| 1715 |
+
el.tagName !== "H1" &&
|
| 1716 |
+
!el.classList.contains("agent-hint") &&
|
| 1717 |
+
!el.classList.contains("logbook-stats") &&
|
| 1718 |
+
!el.classList.contains("pinned-notes")
|
| 1719 |
+
);
|
| 1720 |
+
if (section && !section.classList.contains("has-pinned-notes") && !hasExtra) {
|
| 1721 |
+
section.classList.add("book-intro-tight");
|
| 1722 |
+
}
|
| 1723 |
+
}
|
| 1724 |
+
requestAnimationFrame(() => {
|
| 1725 |
+
if (opts.preserveScroll) {
|
| 1726 |
+
window.scrollTo(0, scrollY);
|
| 1727 |
+
} else {
|
| 1728 |
+
scrollToHash({ behavior: "auto" });
|
| 1729 |
+
}
|
| 1730 |
+
updateActiveSection();
|
| 1731 |
+
});
|
| 1732 |
+
}
|
| 1733 |
+
|
| 1734 |
+
function setupResourceHover() {
|
| 1735 |
+
document.addEventListener("mouseover", (e) => {
|
| 1736 |
+
const el = e.target.closest && e.target.closest("[data-res-url]");
|
| 1737 |
+
if (!el || el.classList.contains("rail-item")) return;
|
| 1738 |
+
const url = el.getAttribute("data-res-url");
|
| 1739 |
+
const section = el.closest(".page-section");
|
| 1740 |
+
const scope = section || document;
|
| 1741 |
+
scope.querySelectorAll(".context-rail [data-res-url]").forEach((n) => {
|
| 1742 |
+
n.classList.toggle("res-hl", n.getAttribute("data-res-url") === url);
|
| 1743 |
+
});
|
| 1744 |
+
});
|
| 1745 |
+
document.addEventListener("mouseout", (e) => {
|
| 1746 |
+
const el = e.target.closest && e.target.closest("[data-res-url]");
|
| 1747 |
+
if (!el || el.classList.contains("rail-item")) return;
|
| 1748 |
+
document.querySelectorAll(".context-rail .res-hl").forEach((n) => {
|
| 1749 |
+
n.classList.remove("res-hl");
|
| 1750 |
+
});
|
| 1751 |
+
});
|
| 1752 |
+
}
|
| 1753 |
+
|
| 1754 |
+
let STATS_TOKEN = 0;
|
| 1755 |
+
let STATS_LISTENERS = false;
|
| 1756 |
+
|
| 1757 |
+
function fmtBytes(n) {
|
| 1758 |
+
if (n == null || isNaN(n)) return null;
|
| 1759 |
+
if (n < 1000) return `${n} B`;
|
| 1760 |
+
const units = ["kB", "MB", "GB", "TB"];
|
| 1761 |
+
let v = n;
|
| 1762 |
+
let i = -1;
|
| 1763 |
+
do {
|
| 1764 |
+
v /= 1000;
|
| 1765 |
+
i++;
|
| 1766 |
+
} while (v >= 1000 && i < units.length - 1);
|
| 1767 |
+
return `${v.toFixed(v < 10 ? 1 : 0)} ${units[i]}`;
|
| 1768 |
+
}
|
| 1769 |
+
|
| 1770 |
+
function spaceIdFromUrl(url) {
|
| 1771 |
+
return url.split("/spaces/")[1].split(/[?#]/)[0].replace(/\/$/, "");
|
| 1772 |
+
}
|
| 1773 |
+
|
| 1774 |
+
const LB_CELL_RE = /(^|\n)---\n<!-- trackio-cell\n([\s\S]*?)\n-->\n([\s\S]*?)(?=\n---\n<!-- trackio-cell\n|\s*$)/g;
|
| 1775 |
+
|
| 1776 |
+
function cellDashboardItems(md) {
|
| 1777 |
+
const re = new RegExp(LB_CELL_RE.source, "g");
|
| 1778 |
+
const items = [];
|
| 1779 |
+
let m;
|
| 1780 |
+
while ((m = re.exec(md))) {
|
| 1781 |
+
const meta = parseCellMeta(m[2]);
|
| 1782 |
+
if (meta.type !== "dashboard") continue;
|
| 1783 |
+
const body = m[3];
|
| 1784 |
+
const project = meta.dashboard_project || "";
|
| 1785 |
+
const sp = body.match(/https:\/\/huggingface\.co\/spaces\/[^\s<>)"'`]+/);
|
| 1786 |
+
const local = !sp;
|
| 1787 |
+
const url = sp ? sp[0] : "";
|
| 1788 |
+
const resUrl = local ? `trackio-local-dashboard://${project}` : url;
|
| 1789 |
+
items.push({
|
| 1790 |
+
id: local ? project : spaceIdFromUrl(url),
|
| 1791 |
+
local,
|
| 1792 |
+
url,
|
| 1793 |
+
resUrl,
|
| 1794 |
+
});
|
| 1795 |
+
}
|
| 1796 |
+
return items;
|
| 1797 |
+
}
|
| 1798 |
+
|
| 1799 |
+
function artifactInfoFromCell(meta, body) {
|
| 1800 |
+
const name = meta.artifact || meta.path || "";
|
| 1801 |
+
let size = null;
|
| 1802 |
+
const sm = body.match(/Β·\s*([\d.]+\s*[kMGT]?B)\b/);
|
| 1803 |
+
if (sm) size = sm[1].trim();
|
| 1804 |
+
if (!size && meta.size != null) size = fmtBytes(meta.size);
|
| 1805 |
+
const bucket = body.match(/https:\/\/huggingface\.co\/buckets\/[^\s<>)"'`]+/);
|
| 1806 |
+
const artUri = body.match(/trackio-artifact:\/\/\S+/);
|
| 1807 |
+
const pathUri = body.match(/trackio-local-path:\/\/\S+/);
|
| 1808 |
+
const url = bucket ? bucket[0] : "";
|
| 1809 |
+
const local = !bucket;
|
| 1810 |
+
const resUrl =
|
| 1811 |
+
url || (artUri ? artUri[0] : pathUri ? pathUri[0] : `trackio-artifact://${name}`);
|
| 1812 |
+
return {
|
| 1813 |
+
name,
|
| 1814 |
+
type: meta.artifact_type || "",
|
| 1815 |
+
size,
|
| 1816 |
+
local,
|
| 1817 |
+
isPathRef: !!meta.path,
|
| 1818 |
+
url,
|
| 1819 |
+
resUrl,
|
| 1820 |
+
};
|
| 1821 |
+
}
|
| 1822 |
+
|
| 1823 |
+
function cellArtifactItems(md) {
|
| 1824 |
+
const re = new RegExp(LB_CELL_RE.source, "g");
|
| 1825 |
+
const items = [];
|
| 1826 |
+
let m;
|
| 1827 |
+
while ((m = re.exec(md))) {
|
| 1828 |
+
const meta = parseCellMeta(m[2]);
|
| 1829 |
+
const body = m[3];
|
| 1830 |
+
const order = meta.created_at || "";
|
| 1831 |
+
if (meta.type === "artifact") {
|
| 1832 |
+
const info = artifactInfoFromCell(meta, body);
|
| 1833 |
+
if (info.name) items.push({ ...info, order });
|
| 1834 |
+
}
|
| 1835 |
+
}
|
| 1836 |
+
return items;
|
| 1837 |
+
}
|
| 1838 |
+
|
| 1839 |
+
function collectLogbookResources(markdownList) {
|
| 1840 |
+
const re = new RegExp(LB_CELL_RE.source, "g");
|
| 1841 |
+
const dashboards = new Map();
|
| 1842 |
+
markdownList.forEach((md) => {
|
| 1843 |
+
let m;
|
| 1844 |
+
while ((m = re.exec(md))) {
|
| 1845 |
+
const meta = parseCellMeta(m[2]);
|
| 1846 |
+
const body = m[3];
|
| 1847 |
+
if (meta.type !== "dashboard") continue;
|
| 1848 |
+
const project = meta.dashboard_project || "";
|
| 1849 |
+
const space = body.match(/https:\/\/huggingface\.co\/spaces\/[^\s<>)"'`]+/);
|
| 1850 |
+
const local = !space;
|
| 1851 |
+
const url = space ? space[0] : "";
|
| 1852 |
+
const key = local ? `local:${project}` : `space:${spaceIdFromUrl(url)}`;
|
| 1853 |
+
const resUrl = local ? `trackio-local-dashboard://${project}` : url;
|
| 1854 |
+
if (!dashboards.has(key))
|
| 1855 |
+
dashboards.set(key, { project, local, url, resUrl });
|
| 1856 |
+
}
|
| 1857 |
+
});
|
| 1858 |
+
const artifacts = new Map();
|
| 1859 |
+
markdownList.forEach((md) => {
|
| 1860 |
+
cellArtifactItems(md).forEach((it) => {
|
| 1861 |
+
const key = `${it.type}:${it.name}`;
|
| 1862 |
+
const prev = artifacts.get(key);
|
| 1863 |
+
if (!prev || it.order >= prev.order) artifacts.set(key, it);
|
| 1864 |
+
});
|
| 1865 |
+
});
|
| 1866 |
+
return {
|
| 1867 |
+
dashboards: Array.from(dashboards.values()).sort((a, b) =>
|
| 1868 |
+
a.project.localeCompare(b.project)
|
| 1869 |
+
),
|
| 1870 |
+
artifacts: Array.from(artifacts.values()).sort((a, b) =>
|
| 1871 |
+
a.name.localeCompare(b.name)
|
| 1872 |
+
),
|
| 1873 |
+
};
|
| 1874 |
+
}
|
| 1875 |
+
|
| 1876 |
+
function closeStatPopovers() {
|
| 1877 |
+
document
|
| 1878 |
+
.querySelectorAll(".stat-popover")
|
| 1879 |
+
.forEach((p) => (p.hidden = true));
|
| 1880 |
+
document
|
| 1881 |
+
.querySelectorAll(".stat-tile.open")
|
| 1882 |
+
.forEach((t) => t.classList.remove("open"));
|
| 1883 |
+
}
|
| 1884 |
+
|
| 1885 |
+
function ensureStatListeners() {
|
| 1886 |
+
if (STATS_LISTENERS) return;
|
| 1887 |
+
STATS_LISTENERS = true;
|
| 1888 |
+
document.addEventListener("click", closeStatPopovers);
|
| 1889 |
+
document.addEventListener("keydown", (e) => {
|
| 1890 |
+
if (e.key === "Escape") closeStatPopovers();
|
| 1891 |
+
});
|
| 1892 |
+
}
|
| 1893 |
+
|
| 1894 |
+
function stateHtml(remote, url) {
|
| 1895 |
+
return remote
|
| 1896 |
+
? `<a class="stat-row-state open" href="${esc(url)}" target="_blank" rel="noopener" title="Open in a new tab">Open β</a>`
|
| 1897 |
+
: `<span class="stat-row-state">publish to share</span>`;
|
| 1898 |
+
}
|
| 1899 |
+
|
| 1900 |
+
function scrollToResource(resUrl) {
|
| 1901 |
+
closeStatPopovers();
|
| 1902 |
+
if (!resUrl) return;
|
| 1903 |
+
const el = document.querySelector(
|
| 1904 |
+
`#page .page-body [data-res-url="${CSS.escape(resUrl)}"]:not(.stat-row)`
|
| 1905 |
+
);
|
| 1906 |
+
if (!el) return;
|
| 1907 |
+
el.scrollIntoView({ behavior: "smooth", block: "center" });
|
| 1908 |
+
el.classList.add("res-flash");
|
| 1909 |
+
setTimeout(() => el.classList.remove("res-flash"), 1500);
|
| 1910 |
+
}
|
| 1911 |
+
|
| 1912 |
+
function dashRowHtml(d) {
|
| 1913 |
+
const inner =
|
| 1914 |
+
`<span class="stat-row-ico">${DASHBOARD_ICON_IMG}</span>` +
|
| 1915 |
+
`<div class="stat-row-main"><div class="stat-row-title">${esc(d.project)}</div>` +
|
| 1916 |
+
`<div class="stat-row-meta">${stateHtml(!d.local, d.url)}</div></div>`;
|
| 1917 |
+
return `<div class="stat-row" data-res-url="${esc(d.resUrl)}" title="Jump to it in the logbook">${inner}</div>`;
|
| 1918 |
+
}
|
| 1919 |
+
|
| 1920 |
+
function artRowHtml(a) {
|
| 1921 |
+
const remote = !a.local && !!a.url;
|
| 1922 |
+
const parts = [a.type, a.size].filter(Boolean).map(esc);
|
| 1923 |
+
const meta = parts.length
|
| 1924 |
+
? `${parts.join(" Β· ")} Β· ${stateHtml(remote, a.url)}`
|
| 1925 |
+
: stateHtml(remote, a.url);
|
| 1926 |
+
const inner =
|
| 1927 |
+
`<span class="stat-row-ico">${ARTIFACT_ICON_IMG}</span>` +
|
| 1928 |
+
`<div class="stat-row-main"><div class="stat-row-title">${esc(a.name)}</div>` +
|
| 1929 |
+
`<div class="stat-row-meta">${meta}</div></div>`;
|
| 1930 |
+
return `<div class="stat-row" data-res-url="${esc(a.resUrl)}" title="Jump to it in the logbook">${inner}</div>`;
|
| 1931 |
+
}
|
| 1932 |
+
|
| 1933 |
+
function statTile(icon, alt, singular, plural, head, rowFn) {
|
| 1934 |
+
const tile = document.createElement("button");
|
| 1935 |
+
tile.type = "button";
|
| 1936 |
+
tile.className = "stat-tile";
|
| 1937 |
+
const render = (items) => {
|
| 1938 |
+
const count = items.length;
|
| 1939 |
+
const label = count === 1 ? singular : plural;
|
| 1940 |
+
const caret = count > 0 ? `<span class="stat-caret">βΎ</span>` : "";
|
| 1941 |
+
tile.innerHTML =
|
| 1942 |
+
`<img class="stat-icon" src="${icon}" alt="${esc(alt)}" />` +
|
| 1943 |
+
`<div class="stat-text"><div class="stat-num">${count}</div>` +
|
| 1944 |
+
`<div class="stat-label">${esc(label)}</div></div>` +
|
| 1945 |
+
caret;
|
| 1946 |
+
tile.disabled = count === 0;
|
| 1947 |
+
if (count > 0) {
|
| 1948 |
+
const pop = document.createElement("div");
|
| 1949 |
+
pop.className = "stat-popover";
|
| 1950 |
+
pop.hidden = true;
|
| 1951 |
+
pop.innerHTML =
|
| 1952 |
+
`<div class="stat-pop-head">${esc(head)}</div>` +
|
| 1953 |
+
items.map(rowFn).join("");
|
| 1954 |
+
pop.addEventListener("click", (e) => {
|
| 1955 |
+
if (e.target.closest("a.stat-row-state")) {
|
| 1956 |
+
e.stopPropagation();
|
| 1957 |
+
return;
|
| 1958 |
+
}
|
| 1959 |
+
e.stopPropagation();
|
| 1960 |
+
const row = e.target.closest(".stat-row");
|
| 1961 |
+
if (row) scrollToResource(row.dataset.resUrl);
|
| 1962 |
+
});
|
| 1963 |
+
tile.appendChild(pop);
|
| 1964 |
+
}
|
| 1965 |
+
};
|
| 1966 |
+
tile.addEventListener("click", (e) => {
|
| 1967 |
+
if (tile.disabled) return;
|
| 1968 |
+
e.stopPropagation();
|
| 1969 |
+
const pop = tile.querySelector(".stat-popover");
|
| 1970 |
+
if (!pop) return;
|
| 1971 |
+
const isOpen = !pop.hidden;
|
| 1972 |
+
closeStatPopovers();
|
| 1973 |
+
if (!isOpen) {
|
| 1974 |
+
pop.hidden = false;
|
| 1975 |
+
tile.classList.add("open");
|
| 1976 |
+
}
|
| 1977 |
+
});
|
| 1978 |
+
return { tile, render };
|
| 1979 |
+
}
|
| 1980 |
+
|
| 1981 |
+
function buildLogbookStats(markdownList) {
|
| 1982 |
+
const token = ++STATS_TOKEN;
|
| 1983 |
+
ensureStatListeners();
|
| 1984 |
+
const { dashboards, artifacts } = collectLogbookResources(markdownList);
|
| 1985 |
+
|
| 1986 |
+
const el = document.createElement("div");
|
| 1987 |
+
el.className = "logbook-stats";
|
| 1988 |
+
const dash = statTile(
|
| 1989 |
+
"./trackio-logo-light.png",
|
| 1990 |
+
"Trackio",
|
| 1991 |
+
"Trackio Dashboard",
|
| 1992 |
+
"Trackio Dashboards",
|
| 1993 |
+
"Dashboards created in this logbook",
|
| 1994 |
+
dashRowHtml
|
| 1995 |
+
);
|
| 1996 |
+
const art = statTile(
|
| 1997 |
+
"./bucket-icon.svg",
|
| 1998 |
+
"Bucket",
|
| 1999 |
+
"Artifact",
|
| 2000 |
+
"Artifacts",
|
| 2001 |
+
"Artifacts created in this logbook",
|
| 2002 |
+
artRowHtml
|
| 2003 |
+
);
|
| 2004 |
+
dash.render(dashboards);
|
| 2005 |
+
art.render(artifacts);
|
| 2006 |
+
el.appendChild(dash.tile);
|
| 2007 |
+
el.appendChild(art.tile);
|
| 2008 |
+
|
| 2009 |
+
const scanText = markdownList
|
| 2010 |
+
.map((md) =>
|
| 2011 |
+
md.replace(/(`{3,4}|~{3,4})(html|raw)[^\n]*\n[\s\S]*?\n\1/g, " ")
|
| 2012 |
+
)
|
| 2013 |
+
.join("\n");
|
| 2014 |
+
const seen = new Set(
|
| 2015 |
+
dashboards.map((d) =>
|
| 2016 |
+
d.local ? `local:${d.project}` : `space:${spaceIdFromUrl(d.url)}`
|
| 2017 |
+
)
|
| 2018 |
+
);
|
| 2019 |
+
const remoteSpaces = new Map();
|
| 2020 |
+
extractUrls(scanText).forEach((url) => {
|
| 2021 |
+
const item = classifyResource(url);
|
| 2022 |
+
if (item && item.kind === "space" && !item.local) {
|
| 2023 |
+
remoteSpaces.set(item.url, item);
|
| 2024 |
+
}
|
| 2025 |
+
});
|
| 2026 |
+
remoteSpaces.forEach((s) => {
|
| 2027 |
+
const key = `space:${s.id}`;
|
| 2028 |
+
if (seen.has(key)) return;
|
| 2029 |
+
getJSON(`https://huggingface.co/api/spaces/${s.id}`)
|
| 2030 |
+
.then((d) => {
|
| 2031 |
+
if (STATS_TOKEN !== token) return;
|
| 2032 |
+
const tags = (d && d.tags) || [];
|
| 2033 |
+
if (
|
| 2034 |
+
!seen.has(key) &&
|
| 2035 |
+
tags.some((t) => String(t).toLowerCase() === "trackio")
|
| 2036 |
+
) {
|
| 2037 |
+
seen.add(key);
|
| 2038 |
+
dashboards.push({
|
| 2039 |
+
project: s.id,
|
| 2040 |
+
local: false,
|
| 2041 |
+
url: s.url,
|
| 2042 |
+
resUrl: s.url,
|
| 2043 |
+
});
|
| 2044 |
+
dashboards.sort((a, b) => a.project.localeCompare(b.project));
|
| 2045 |
+
dash.render(dashboards);
|
| 2046 |
+
}
|
| 2047 |
+
})
|
| 2048 |
+
.catch(() => {});
|
| 2049 |
+
});
|
| 2050 |
+
return el;
|
| 2051 |
+
}
|
| 2052 |
+
|
| 2053 |
+
function buildAgentHint() {
|
| 2054 |
+
const onSpaces =
|
| 2055 |
+
/\.hf\.space$/.test(location.hostname) ||
|
| 2056 |
+
/(^|\.)huggingface\.co$/.test(location.hostname);
|
| 2057 |
+
let source = "";
|
| 2058 |
+
if (onSpaces && MANIFEST.space_id) {
|
| 2059 |
+
source = ` ${MANIFEST.space_id}`;
|
| 2060 |
+
} else if (/^https?:$/.test(location.protocol)) {
|
| 2061 |
+
source = ` ${location.origin}/`;
|
| 2062 |
+
}
|
| 2063 |
+
const command = `trackio logbook read${source}`;
|
| 2064 |
+
const tokens = MANIFEST.agent_view_tokens;
|
| 2065 |
+
const div = document.createElement("div");
|
| 2066 |
+
div.className = "agent-hint";
|
| 2067 |
+
const label = document.createElement("span");
|
| 2068 |
+
label.className = "agent-hint-label";
|
| 2069 |
+
label.textContent = "Read from the CLI:";
|
| 2070 |
+
const code = document.createElement("code");
|
| 2071 |
+
code.textContent = command;
|
| 2072 |
+
const copy = document.createElement("button");
|
| 2073 |
+
copy.className = "copy";
|
| 2074 |
+
copy.type = "button";
|
| 2075 |
+
copy.title = "Copy";
|
| 2076 |
+
copy.textContent = "β§";
|
| 2077 |
+
copy.addEventListener("click", () => copyText(command, copy, "β§"));
|
| 2078 |
+
const note = document.createElement("span");
|
| 2079 |
+
note.className = "agent-hint-note";
|
| 2080 |
+
note.textContent =
|
| 2081 |
+
"compact view for agents" + (tokens ? ` Β· ~${fmt(tokens)} tokens` : "");
|
| 2082 |
+
div.appendChild(label);
|
| 2083 |
+
div.appendChild(code);
|
| 2084 |
+
div.appendChild(copy);
|
| 2085 |
+
div.appendChild(note);
|
| 2086 |
+
return div;
|
| 2087 |
+
}
|
| 2088 |
+
|
| 2089 |
+
function currentSlug() {
|
| 2090 |
+
const slug = (location.hash || "").replace(/^#\//, "") || MANIFEST.root.slug;
|
| 2091 |
+
return findNode(MANIFEST.root, slug) ? slug : MANIFEST.root.slug;
|
| 2092 |
+
}
|
| 2093 |
+
|
| 2094 |
+
function scrollToHash(opts = {}) {
|
| 2095 |
+
const slug = currentSlug();
|
| 2096 |
+
if (!location.hash) {
|
| 2097 |
+
window.scrollTo({ top: 0, behavior: opts.behavior || "auto" });
|
| 2098 |
+
highlight(slug);
|
| 2099 |
+
return;
|
| 2100 |
+
}
|
| 2101 |
+
const section = document.getElementById("/" + slug);
|
| 2102 |
+
if (section) section.scrollIntoView({ behavior: opts.behavior || "smooth" });
|
| 2103 |
+
highlight(slug);
|
| 2104 |
+
}
|
| 2105 |
+
|
| 2106 |
+
function navigateToLogbookSlug(target) {
|
| 2107 |
+
const slug = String(target || "").replace(/^#?\//, "").trim();
|
| 2108 |
+
if (!slug || !findNode(MANIFEST.root, slug)) return;
|
| 2109 |
+
const hash = "#/" + slug;
|
| 2110 |
+
if (location.hash === hash) {
|
| 2111 |
+
scrollToHash({ behavior: "smooth" });
|
| 2112 |
+
} else {
|
| 2113 |
+
location.hash = hash;
|
| 2114 |
+
}
|
| 2115 |
+
}
|
| 2116 |
+
|
| 2117 |
+
function setupFigureNavigation() {
|
| 2118 |
+
window.addEventListener("message", (event) => {
|
| 2119 |
+
const data = event.data;
|
| 2120 |
+
if (!data || data.type !== "trackio-logbook:navigate") return;
|
| 2121 |
+
// Only accept messages from one of this logbook's sandboxed figure
|
| 2122 |
+
// iframes, rather than from an arbitrary same-origin page.
|
| 2123 |
+
const isFigureFrame = Array.from(
|
| 2124 |
+
document.querySelectorAll("iframe.figure-frame")
|
| 2125 |
+
).some((frame) => frame.contentWindow === event.source);
|
| 2126 |
+
if (!isFigureFrame) return;
|
| 2127 |
+
navigateToLogbookSlug(data.target);
|
| 2128 |
+
});
|
| 2129 |
+
}
|
| 2130 |
+
|
| 2131 |
+
let SCROLL_FRAME = 0;
|
| 2132 |
+
function updateActiveSection() {
|
| 2133 |
+
cancelAnimationFrame(SCROLL_FRAME);
|
| 2134 |
+
SCROLL_FRAME = requestAnimationFrame(() => {
|
| 2135 |
+
const sections = Array.from(document.querySelectorAll(".page-section"));
|
| 2136 |
+
if (!sections.length) return;
|
| 2137 |
+
const marker = Math.min(window.innerHeight * 0.28, 180);
|
| 2138 |
+
let active = sections[0];
|
| 2139 |
+
sections.forEach((section) => {
|
| 2140 |
+
if (section.getBoundingClientRect().top <= marker) active = section;
|
| 2141 |
+
});
|
| 2142 |
+
if (
|
| 2143 |
+
window.innerHeight + window.scrollY >=
|
| 2144 |
+
document.documentElement.scrollHeight - 2
|
| 2145 |
+
) {
|
| 2146 |
+
active = sections[sections.length - 1];
|
| 2147 |
+
}
|
| 2148 |
+
highlight(active.dataset.slug);
|
| 2149 |
+
});
|
| 2150 |
+
}
|
| 2151 |
+
|
| 2152 |
+
function startLiveReload() {
|
| 2153 |
+
if (!isLocalPreview()) return;
|
| 2154 |
+
setInterval(async () => {
|
| 2155 |
+
try {
|
| 2156 |
+
const next = await fetchManifest();
|
| 2157 |
+
if (!next || next.revision === MANIFEST.revision) return;
|
| 2158 |
+
MANIFEST = next;
|
| 2159 |
+
clearPageCache();
|
| 2160 |
+
document.title = MANIFEST.title + " Β· Trackio Logbook";
|
| 2161 |
+
document.getElementById("book-title").textContent = MANIFEST.title;
|
| 2162 |
+
document.getElementById("book-head").setAttribute("aria-label", MANIFEST.title);
|
| 2163 |
+
buildTree();
|
| 2164 |
+
renderLogbook({ preserveScroll: true });
|
| 2165 |
+
} catch (e) {}
|
| 2166 |
+
}, LIVE_RELOAD_MS);
|
| 2167 |
+
}
|
| 2168 |
+
|
| 2169 |
+
function setupConnect() {
|
| 2170 |
+
const space = MANIFEST.space_id;
|
| 2171 |
+
if (!space) return;
|
| 2172 |
+
const steps = [
|
| 2173 |
+
{ t: "Install Trackio, if you don't have it yet.", c: "uv tool install trackio" },
|
| 2174 |
+
{ t: "Add the Trackio skill for your agent, then reload it.", c: "trackio skills add" },
|
| 2175 |
+
{ t: "Connect to this logbook.", c: `trackio logbook open ${space}` },
|
| 2176 |
+
];
|
| 2177 |
+
const ol = document.getElementById("connect-steps");
|
| 2178 |
+
steps.forEach((s, i) => {
|
| 2179 |
+
const li = document.createElement("li");
|
| 2180 |
+
const title = document.createElement("div");
|
| 2181 |
+
title.className = "step-title";
|
| 2182 |
+
title.textContent = `${i + 1}. ${s.t}`;
|
| 2183 |
+
const block = document.createElement("div");
|
| 2184 |
+
block.className = "codeblock";
|
| 2185 |
+
const code = document.createElement("code");
|
| 2186 |
+
code.textContent = s.c;
|
| 2187 |
+
const copy = document.createElement("button");
|
| 2188 |
+
copy.className = "copy";
|
| 2189 |
+
copy.type = "button";
|
| 2190 |
+
copy.title = "Copy";
|
| 2191 |
+
copy.textContent = "β§";
|
| 2192 |
+
copy.addEventListener("click", () => copyText(s.c, copy, "β§"));
|
| 2193 |
+
block.appendChild(code);
|
| 2194 |
+
block.appendChild(copy);
|
| 2195 |
+
li.appendChild(title);
|
| 2196 |
+
li.appendChild(block);
|
| 2197 |
+
ol.appendChild(li);
|
| 2198 |
+
});
|
| 2199 |
+
|
| 2200 |
+
const agentPrompt =
|
| 2201 |
+
`Read and help maintain this Trackio experiment logbook ("${MANIFEST.title}").\n\n` +
|
| 2202 |
+
"1. If you don't have Trackio, install it: uv tool install trackio\n" +
|
| 2203 |
+
"2. Add the Trackio skill for your agent: trackio skills add (then reload)\n" +
|
| 2204 |
+
`3. Connect to this logbook: trackio logbook open ${space}\n\n` +
|
| 2205 |
+
"Start with `trackio logbook read`; use `trackio logbook read page \"...\"` " +
|
| 2206 |
+
"for a page-level view, then fetch relevant details with " +
|
| 2207 |
+
"`trackio logbook read cell cell_<id>`. If I've given you " +
|
| 2208 |
+
'write access to the Space, add findings with `trackio logbook cell markdown "..." ' +
|
| 2209 |
+
'--page "..."` and they will sync back automatically.';
|
| 2210 |
+
|
| 2211 |
+
const foot = document.getElementById("sidebar-foot");
|
| 2212 |
+
foot.hidden = false;
|
| 2213 |
+
const modal = document.getElementById("modal");
|
| 2214 |
+
const open = () => (modal.hidden = false);
|
| 2215 |
+
const close = () => (modal.hidden = true);
|
| 2216 |
+
document.getElementById("connect-btn").addEventListener("click", open);
|
| 2217 |
+
document.getElementById("modal-close").addEventListener("click", close);
|
| 2218 |
+
modal.querySelector(".modal-backdrop").addEventListener("click", close);
|
| 2219 |
+
document.addEventListener("keydown", (e) => {
|
| 2220 |
+
if (e.key === "Escape") close();
|
| 2221 |
+
});
|
| 2222 |
+
const agentBtn = document.getElementById("copy-agent");
|
| 2223 |
+
agentBtn.addEventListener("click", () =>
|
| 2224 |
+
copyText(agentPrompt, agentBtn, "Copy for agent")
|
| 2225 |
+
);
|
| 2226 |
+
}
|
| 2227 |
+
|
| 2228 |
+
function copyText(text, btn, restore) {
|
| 2229 |
+
const done = () => {
|
| 2230 |
+
const prev = btn.textContent;
|
| 2231 |
+
btn.textContent = restore === "β§" ? "β" : "Copied!";
|
| 2232 |
+
btn.classList.add("copied");
|
| 2233 |
+
setTimeout(() => {
|
| 2234 |
+
btn.textContent = restore;
|
| 2235 |
+
btn.classList.remove("copied");
|
| 2236 |
+
}, 1400);
|
| 2237 |
+
void prev;
|
| 2238 |
+
};
|
| 2239 |
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
| 2240 |
+
navigator.clipboard.writeText(text).then(done, done);
|
| 2241 |
+
} else {
|
| 2242 |
+
const ta = document.createElement("textarea");
|
| 2243 |
+
ta.value = text;
|
| 2244 |
+
document.body.appendChild(ta);
|
| 2245 |
+
ta.select();
|
| 2246 |
+
try {
|
| 2247 |
+
document.execCommand("copy");
|
| 2248 |
+
} catch (e) {}
|
| 2249 |
+
document.body.removeChild(ta);
|
| 2250 |
+
done();
|
| 2251 |
+
}
|
| 2252 |
+
}
|
| 2253 |
+
|
| 2254 |
+
async function init() {
|
| 2255 |
+
MANIFEST = await fetchManifest();
|
| 2256 |
+
document.title = MANIFEST.title + " Β· Trackio Logbook";
|
| 2257 |
+
document.getElementById("book-title").textContent = MANIFEST.title;
|
| 2258 |
+
document.getElementById("book-head").setAttribute("aria-label", MANIFEST.title);
|
| 2259 |
+
document.getElementById("book-head").addEventListener("click", () => {
|
| 2260 |
+
const target = "#/" + MANIFEST.root.slug;
|
| 2261 |
+
if (location.hash === target) scrollToHash();
|
| 2262 |
+
else location.hash = target;
|
| 2263 |
+
});
|
| 2264 |
+
buildTree();
|
| 2265 |
+
setupConnect();
|
| 2266 |
+
setupResourceHover();
|
| 2267 |
+
setupFigureNavigation();
|
| 2268 |
+
window.addEventListener("hashchange", () => scrollToHash());
|
| 2269 |
+
window.addEventListener("scroll", updateActiveSection, { passive: true });
|
| 2270 |
+
await renderLogbook();
|
| 2271 |
+
startLiveReload();
|
| 2272 |
+
}
|
| 2273 |
+
|
| 2274 |
+
init();
|
| 2275 |
+
})();
|
logbook.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"schema_version": 1,
|
| 3 |
+
"title": "Reproduction: SWE-fficiency: Can Language Models Optimize Real-World Repositories on Real Workloads?",
|
| 4 |
+
"emoji": "π―",
|
| 5 |
+
"space_id": "Yashp2003/repro-swe-fficiency-can-language-models-optimize-real-world-repositories-on-real-workloads",
|
| 6 |
+
"paper": {
|
| 7 |
+
"arxiv_id": "2511.06090"
|
| 8 |
+
},
|
| 9 |
+
"tags": [
|
| 10 |
+
"icml2026-repro",
|
| 11 |
+
"paper-0pyFbZSfbT"
|
| 12 |
+
],
|
| 13 |
+
"updated_at": "2026-07-21T04:28:59+00:00",
|
| 14 |
+
"root": {
|
| 15 |
+
"slug": "index",
|
| 16 |
+
"title": "Reproduction: SWE-fficiency: Can Language Models Optimize Real-World Repositories on Real Workloads?",
|
| 17 |
+
"file": "pages/index.md",
|
| 18 |
+
"children": [
|
| 19 |
+
{
|
| 20 |
+
"slug": "executive-summary",
|
| 21 |
+
"title": "Executive summary",
|
| 22 |
+
"file": "pages/executive-summary/page.md",
|
| 23 |
+
"children": []
|
| 24 |
+
},
|
| 25 |
+
{
|
| 26 |
+
"slug": "claim-1-the-swe-fficiency-benchmark-comprises-498-real-world-code-optimization-tasks-drawn-from-9-widely-used-python-repositories-including-numpy-pandas-and-scipy-abstract-only",
|
| 27 |
+
"title": "Claim 1: The SWE-fficiency benchmark comprises 498 real-world code optimization tasks drawn from 9 widely used Python repositories including numpy, pandas, and scipy (abstract only).",
|
| 28 |
+
"file": "pages/claim-1-the-swe-fficiency-benchmark-comprises-498-real-world-code-optimization-tasks-drawn-from-9-widely-used-python-repositories-including-numpy-pandas-and-scipy-abstract-only/page.md",
|
| 29 |
+
"children": []
|
| 30 |
+
},
|
| 31 |
+
{
|
| 32 |
+
"slug": "claim-2-agents-are-tasked-with-investigating-code-semantics-localizing-bottlenecks-and-relevant-tests-and-producing-a-patch-that-matches-or-exceeds-expert-speedup-while-passing-the-same-unit-tests-abstract-only",
|
| 33 |
+
"title": "Claim 2: Agents are tasked with investigating code semantics, localizing bottlenecks and relevant tests, and producing a patch that matches or exceeds expert speedup while passing the same unit tests (abstract only).",
|
| 34 |
+
"file": "pages/claim-2-agents-are-tasked-with-investigating-code-semantics-localizing-bottlenecks-and-relevant-tests-and-producing-a-patch-that-matches-or-exceeds-expert-speedup-while-passing-the-same-unit-tests-abstract-only/page.md",
|
| 35 |
+
"children": []
|
| 36 |
+
},
|
| 37 |
+
{
|
| 38 |
+
"slug": "claim-3-the-top-performing-agents-evaluated-on-swe-fficiency-achieve-less-than-0-23x-of-the-expert-level-speedup-on-average-across-the-498-tasks-abstract-only",
|
| 39 |
+
"title": "Claim 3: The top-performing agents evaluated on SWE-fficiency achieve less than 0.23x of the expert-level speedup on average across the 498 tasks (abstract only).",
|
| 40 |
+
"file": "pages/claim-3-the-top-performing-agents-evaluated-on-swe-fficiency-achieve-less-than-0-23x-of-the-expert-level-speedup-on-average-across-the-498-tasks-abstract-only/page.md",
|
| 41 |
+
"children": []
|
| 42 |
+
},
|
| 43 |
+
{
|
| 44 |
+
"slug": "claim-4-agents-struggle-specifically-with-localizing-optimization-opportunities-in-large-codebases-reasoning-about-execution-flow-across-multiple-functions-and-maintaining-correctness-of-proposed-optimizations-abstract-only",
|
| 45 |
+
"title": "Claim 4: Agents struggle specifically with localizing optimization opportunities in large codebases, reasoning about execution flow across multiple functions, and maintaining correctness of proposed optimizations (abstract only).",
|
| 46 |
+
"file": "pages/claim-4-agents-struggle-specifically-with-localizing-optimization-opportunities-in-large-codebases-reasoning-about-execution-flow-across-multiple-functions-and-maintaining-correctness-of-proposed-optimizations-abstract-only/page.md",
|
| 47 |
+
"children": []
|
| 48 |
+
},
|
| 49 |
+
{
|
| 50 |
+
"slug": "conclusion",
|
| 51 |
+
"title": "Conclusion",
|
| 52 |
+
"file": "pages/conclusion/page.md",
|
| 53 |
+
"children": []
|
| 54 |
+
}
|
| 55 |
+
]
|
| 56 |
+
},
|
| 57 |
+
"agent_view_tokens": 5778,
|
| 58 |
+
"revision": "1784608139243128982"
|
| 59 |
+
}
|
pages/claim-1-the-swe-fficiency-benchmark-comprises-498-real-world-code-optimization-tasks-drawn-from-9-widely-used-python-repositories-including-numpy-pandas-and-scipy-abstract-only/page.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Claim 1: The SWE-fficiency benchmark comprises 498 real-world code optimization tasks drawn from 9 widely used Python repositories including numpy, pandas, and scipy (abstract only).
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
---
|
| 5 |
+
<!-- trackio-cell
|
| 6 |
+
{"type": "markdown", "id": "cell_060625635d67", "created_at": "2026-07-21T04:17:55+00:00", "title": "Claim 1: The SWE-fficiency benchmark comprises 498 real-world code optimization tasks drawn from 9 widely used Python repositories including numpy, pandas, and scipy (abstract only)."}
|
| 7 |
+
-->
|
| 8 |
+
Document setup, runs, and results for **Claim 1: The SWE-fficiency benchmark comprises 498 real-world code optimization tasks drawn from 9 widely used Python repositories including numpy, pandas, and scipy (abstract only).**.
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
---
|
| 12 |
+
<!-- trackio-cell
|
| 13 |
+
{"type": "markdown", "id": "cell_db8f92ef8ae6", "created_at": "2026-07-21T04:24:26+00:00", "title": "Claim 1: The SWE-fficiency benchmark comprises 498 real-world code optimizationβ¦"}
|
| 14 |
+
-->
|
| 15 |
+
## Claim 1: The SWE-fficiency benchmark comprises 498 real-world code optimization tasks drawn from 9 widely used Python repositories including numpy, pandas, and scipy.
|
| 16 |
+
|
| 17 |
+
**Verdict: VERIFIED** β
|
| 18 |
+
|
| 19 |
+
### Verification
|
| 20 |
+
|
| 21 |
+
Loaded the SWE-fficiency dataset from [HuggingFace: swefficiency/swefficiency](https://huggingface.co/datasets/swefficiency/swefficiency) and counted tasks and repositories:
|
| 22 |
+
|
| 23 |
+
| Metric | Paper Claim | Verified |
|
| 24 |
+
|--------|-------------|----------|
|
| 25 |
+
| Total tasks | 498 | 498 β
|
|
| 26 |
+
| Number of repos | 9 | 9 β
|
|
| 27 |
+
| Repos include numpy, pandas, scipy | Yes | Yes β
|
|
| 28 |
+
|
| 29 |
+
### Tasks per Repository
|
| 30 |
+
|
| 31 |
+
| Repository | Task Count |
|
| 32 |
+
|-----------|-----------|
|
| 33 |
+
| pandas | 279 |
|
| 34 |
+
| scipy | 45 |
|
| 35 |
+
| sympy | 39 |
|
| 36 |
+
| astropy | 35 |
|
| 37 |
+
| scikit-learn | 27 |
|
| 38 |
+
| numpy | 23 |
|
| 39 |
+
| matplotlib | 20 |
|
| 40 |
+
| dask | 19 |
|
| 41 |
+
| xarray | 11 |
|
| 42 |
+
| **Total** | **498** |
|
| 43 |
+
|
| 44 |
+
All 9 repositories are widely used Python libraries for data science, ML, and HPC, matching the paper's claim.
|
| 45 |
+
|
| 46 |
+
### Dataset Source
|
| 47 |
+
- HuggingFace Dataset: [swefficiency/swefficiency](https://huggingface.co/datasets/swefficiency/swefficiency)
|
| 48 |
+
- GitHub Repo: [swefficiency/swefficiency](https://github.com/swefficiency/swefficiency)
|
pages/claim-2-agents-are-tasked-with-investigating-code-semantics-localizing-bottlenecks-and-relevant-tests-and-producing-a-patch-that-matches-or-exceeds-expert-speedup-while-passing-the-same-unit-tests-abstract-only/page.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Claim 2: Agents are tasked with investigating code semantics, localizing bottlenecks and relevant tests, and producing a patch that matches or exceeds expert speedup while passing the same unit tests (abstract only).
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
---
|
| 5 |
+
<!-- trackio-cell
|
| 6 |
+
{"type": "markdown", "id": "cell_d6e3dff00b5e", "created_at": "2026-07-21T04:17:55+00:00", "title": "Claim 2: Agents are tasked with investigating code semantics, localizing bottlenecks and relevant tests, and producing a patch that matches or exceeds expert speedup while passing the same unit tests (abstract only)."}
|
| 7 |
+
-->
|
| 8 |
+
Document setup, runs, and results for **Claim 2: Agents are tasked with investigating code semantics, localizing bottlenecks and relevant tests, and producing a patch that matches or exceeds expert speedup while passing the same unit tests (abstract only).**.
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
---
|
| 12 |
+
<!-- trackio-cell
|
| 13 |
+
{"type": "markdown", "id": "cell_b973ea1a4cd0", "created_at": "2026-07-21T04:24:53+00:00", "title": "Claim 2: Agents are tasked with investigating code semantics, localizing bottleβ¦"}
|
| 14 |
+
-->
|
| 15 |
+
## Claim 2: Agents are tasked with investigating code semantics, localizing bottlenecks and relevant tests, and producing a patch that matches or exceeds expert speedup while passing the same unit tests.
|
| 16 |
+
|
| 17 |
+
**Verdict: VERIFIED** β
|
| 18 |
+
|
| 19 |
+
### Verification
|
| 20 |
+
|
| 21 |
+
Verified from the official project page ([swefficiency.com](https://swefficiency.com)) and GitHub README ([swefficiency/swefficiency](https://github.com/swefficiency/swefficiency)):
|
| 22 |
+
|
| 23 |
+
### Task Formulation
|
| 24 |
+
- **Input**: Complete repository snapshot + performance workload script + existing unit test suite
|
| 25 |
+
- **Agent Workflow**:
|
| 26 |
+
1. Investigate code semantics
|
| 27 |
+
2. Profile/inspect execution
|
| 28 |
+
3. Localize bottlenecks
|
| 29 |
+
4. Identify relevant tests (coverage-based)
|
| 30 |
+
5. Propose correctness-preserving patches
|
| 31 |
+
- **Evaluation**: Speedup Ratio (SR) = (LM speedup) / (Expert speedup)
|
| 32 |
+
- **Correctness**: All optimizations must pass existing repository unit tests
|
| 33 |
+
|
| 34 |
+
### Methodology Components
|
| 35 |
+
| Component | Description | Verified |
|
| 36 |
+
|-----------|-------------|----------|
|
| 37 |
+
| Codebase access | Full repository snapshots | β
|
|
| 38 |
+
| Performance workloads | Separate from correctness tests | β
|
|
| 39 |
+
| Correctness tests | Coverage-intersecting tests from repo | β
|
|
| 40 |
+
| Expert baseline | Human PR patches as reference | β
|
|
| 41 |
+
| Containerized eval | Docker with CPU/memory pinning | β
|
|
| 42 |
+
|
| 43 |
+
### Key Quote from Paper
|
| 44 |
+
> "given a complete codebase and a slow workload, an agent must investigate code semantics, localize bottlenecks and relevant tests, and produce a patch that matches or exceeds expert speedup while passing the same unit tests"
|
| 45 |
+
|
| 46 |
+
### Sources
|
| 47 |
+
- Paper: [arXiv:2511.06090](https://arxiv.org/abs/2511.06090)
|
| 48 |
+
- Project: [swefficiency.com](https://swefficiency.com)
|
| 49 |
+
- GitHub: [swefficiency/swefficiency](https://github.com/swefficiency/swefficiency)
|
pages/claim-3-the-top-performing-agents-evaluated-on-swe-fficiency-achieve-less-than-0-23x-of-the-expert-level-speedup-on-average-across-the-498-tasks-abstract-only/page.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Claim 3: The top-performing agents evaluated on SWE-fficiency achieve less than 0.23x of the expert-level speedup on average across the 498 tasks (abstract only).
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
---
|
| 5 |
+
<!-- trackio-cell
|
| 6 |
+
{"type": "markdown", "id": "cell_249ff9388bc8", "created_at": "2026-07-21T04:17:55+00:00", "title": "Claim 3: The top-performing agents evaluated on SWE-fficiency achieve less than 0.23x of the expert-level speedup on average across the 498 tasks (abstract only)."}
|
| 7 |
+
-->
|
| 8 |
+
Document setup, runs, and results for **Claim 3: The top-performing agents evaluated on SWE-fficiency achieve less than 0.23x of the expert-level speedup on average across the 498 tasks (abstract only).**.
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
---
|
| 12 |
+
<!-- trackio-cell
|
| 13 |
+
{"type": "markdown", "id": "cell_26d22b8a309e", "created_at": "2026-07-21T04:25:09+00:00", "title": "Claim 3: The top-performing agents evaluated on SWE-fficiency achieve less thanβ¦"}
|
| 14 |
+
-->
|
| 15 |
+
## Claim 3: The top-performing agents evaluated on SWE-fficiency achieve less than 0.23x of the expert-level speedup on average across the 498 tasks.
|
| 16 |
+
|
| 17 |
+
**Verdict: VERIFIED** β
|
| 18 |
+
|
| 19 |
+
### Verification
|
| 20 |
+
|
| 21 |
+
Analyzed evaluation reports from the official SWE-fficiency GitHub repository ([swefficiency/swefficiency/eval_reports](https://github.com/swefficiency/swefficiency/tree/swefficiency_base/eval_reports)).
|
| 22 |
+
|
| 23 |
+
### Agent Performance Results (Speedup Ratio)
|
| 24 |
+
|
| 25 |
+
| Agent Model | Overall Score (SR) | < 0.23x? |
|
| 26 |
+
|------------|-------------------|----------|
|
| 27 |
+
| Claude Opus 4.5 | 0.2250 | β
(just under) |
|
| 28 |
+
| GPT-5 | 0.1571 | β
|
|
| 29 |
+
| Claude Opus 4.6 | 0.1553 | β
|
|
| 30 |
+
| GPT-5.2 | 0.1482 | β
|
|
| 31 |
+
| Claude Sonnet 4.5 | 0.1162 | β
|
|
| 32 |
+
| Gemini 3 Flash | 0.1056 | β
|
|
| 33 |
+
| Gemini 3 Pro | 0.1024 | β
|
|
| 34 |
+
| Claude Opus 4.1 | 0.0984 | β
|
|
| 35 |
+
| Qwen3 Coder Plus | 0.0676 | β
|
|
| 36 |
+
| Cursor CLI | 0.0634 | β
|
|
| 37 |
+
| GPT-5.1 | 0.0559 | β
|
|
| 38 |
+
| Kimi K2 | 0.0537 | β
|
|
| 39 |
+
| DeepSeek Reasoner | 0.0432 | β
|
|
| 40 |
+
| GLM-4.6 | 0.0420 | β
|
|
| 41 |
+
| MiniMax M2 | 0.0411 | β
|
|
| 42 |
+
| Gemini 2.5 Flash | 0.0406 | β
|
|
| 43 |
+
| GPT-5 Mini | 0.0389 | β
|
|
| 44 |
+
| Gemini 2.5 Pro | 0.0313 | β
|
|
| 45 |
+
| Claude 3.7 Sonnet | 0.0244 | β
|
|
| 46 |
+
|
| 47 |
+
### Key Findings
|
| 48 |
+
- **Best performer**: Claude Opus 4.5 with SR = 0.225 (just under the 0.23x threshold)
|
| 49 |
+
- **All models** score well below 1.0 (expert parity)
|
| 50 |
+
- **Harmonic mean** across 498 tasks ensures tasks with low speedup heavily penalize the aggregate
|
| 51 |
+
- Even the best agent captures only ~22.5% of expert-level speedup on average
|
| 52 |
+
|
| 53 |
+
### Verification Method
|
| 54 |
+
- Source: Official evaluation reports in [GitHub repository](https://github.com/swefficiency/swefficiency/tree/swefficiency_base/eval_reports)
|
| 55 |
+
- Metric: field in JSON reports = harmonic mean of Speedup Ratios
|
| 56 |
+
- All reports processed with same evaluation pipeline on 498 tasks
|
| 57 |
+
|
| 58 |
+
### Note on Paper Timing
|
| 59 |
+
The paper (Nov 2025) reports "less than 0.23x" which aligns with these later leaderboard results. The top performer at paper time was likely Claude Opus 4.5 or earlier models, all scoring < 0.23x.
|
pages/claim-4-agents-struggle-specifically-with-localizing-optimization-opportunities-in-large-codebases-reasoning-about-execution-flow-across-multiple-functions-and-maintaining-correctness-of-proposed-optimizations-abstract-only/page.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Claim 4: Agents struggle specifically with localizing optimization opportunities in large codebases, reasoning about execution flow across multiple functions, and maintaining correctness of proposed optimizations (abstract only).
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
---
|
| 5 |
+
<!-- trackio-cell
|
| 6 |
+
{"type": "markdown", "id": "cell_3a093aac7172", "created_at": "2026-07-21T04:17:55+00:00", "title": "Claim 4: Agents struggle specifically with localizing optimization opportunities in large codebases, reasoning about execution flow across multiple functions, and maintaining correctness of proposed optimizations (abstract only)."}
|
| 7 |
+
-->
|
| 8 |
+
Document setup, runs, and results for **Claim 4: Agents struggle specifically with localizing optimization opportunities in large codebases, reasoning about execution flow across multiple functions, and maintaining correctness of proposed optimizations (abstract only).**.
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
---
|
| 12 |
+
<!-- trackio-cell
|
| 13 |
+
{"type": "markdown", "id": "cell_6d685f10af17", "created_at": "2026-07-21T04:25:25+00:00", "title": "Claim 4: Agents struggle specifically with localizing optimization opportunitieβ¦"}
|
| 14 |
+
-->
|
| 15 |
+
## Claim 4: Agents struggle specifically with localizing optimization opportunities in large codebases, reasoning about execution flow across multiple functions, and maintaining correctness of proposed optimizations.
|
| 16 |
+
|
| 17 |
+
**Verdict: VERIFIED** β
|
| 18 |
+
|
| 19 |
+
### Verification
|
| 20 |
+
|
| 21 |
+
Analyzed evaluation reports from official SWE-fficiency repository, focusing on correctness failures and localization patterns.
|
| 22 |
+
|
| 23 |
+
### Correctness Failures (Agents Introducing Bugs)
|
| 24 |
+
|
| 25 |
+
| Agent | proportion_incorrect | % of Tasks with Bugs |
|
| 26 |
+
|-------|---------------------|---------------------|
|
| 27 |
+
| Claude 3.7 Sonnet | 0.988 | 98.8% |
|
| 28 |
+
| Claude 3.7 Sonnet (SWE-agent) | 0.926 | 92.6% |
|
| 29 |
+
| Gemini 2.5 Pro | 0.404 | 40.4% |
|
| 30 |
+
| Gemini 2.5 Flash | 0.392 | 39.2% |
|
| 31 |
+
| GLM-4.6 | 0.327 | 32.7% |
|
| 32 |
+
| GPT-5 Mini | 0.452 | 45.2% |
|
| 33 |
+
| DeepSeek Reasoner | 0.191 | 19.1% |
|
| 34 |
+
| GPT-5 | 0.183 | 18.3% |
|
| 35 |
+
| Claude Opus 4.1 | 0.153 | 15.3% |
|
| 36 |
+
| Claude Opus 4.5 | 0.092 | 9.2% |
|
| 37 |
+
|
| 38 |
+
### Localization Struggle Evidence
|
| 39 |
+
|
| 40 |
+
From the project's analysis ([swefficiency.com](https://swefficiency.com)):
|
| 41 |
+
- **Figure 5**: LMs leave significant expert-achievable speedup on the table due to **wrong file/function selection and localization**
|
| 42 |
+
- **Figure 6**: LMs prefer to edit **different functions** than the gold patch, missing major speedups
|
| 43 |
+
- **Flamegraph example**: Claude 3.7 Sonnet chooses a different function (and file) than the expert
|
| 44 |
+
|
| 45 |
+
### Multi-function Reasoning Struggle
|
| 46 |
+
|
| 47 |
+
- Tasks require profiling workloads, understanding **call chains across modules**, inspecting data structures
|
| 48 |
+
- Agents struggle with **investigative, pass-to-pass workflow**
|
| 49 |
+
- Many agents produce **satisficing optimizations** rather than pursuing expert parity (Figure 4)
|
| 50 |
+
|
| 51 |
+
### Key Metrics Supporting Claim
|
| 52 |
+
|
| 53 |
+
1. **High incorrect rates**: Many agents introduce functional regressions (up to 98.8%)
|
| 54 |
+
2. **Low speedup ratios**: Even when correct, agents achieve minimal speedup
|
| 55 |
+
3. **Correct but no speedup**: Significant portion of correct patches have zero speedup (up to 18%)
|
| 56 |
+
4. **Wrong localization**: Paper figures show agents editing different functions than experts
|
| 57 |
+
|
| 58 |
+
### Sources
|
| 59 |
+
- Evaluation reports: [GitHub eval_reports](https://github.com/swefficiency/swefficiency/tree/swefficiency_base/eval_reports)
|
| 60 |
+
- Figures: [swefficiency.com](https://swefficiency.com) (Figures 3-7)
|
| 61 |
+
- Paper: [arXiv:2511.06090](https://arxiv.org/abs/2511.06090)
|
pages/conclusion/page.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Conclusion
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
---
|
| 5 |
+
<!-- trackio-cell
|
| 6 |
+
{"type": "markdown", "id": "cell_3c962e927e83", "created_at": "2026-07-21T04:17:55+00:00", "title": "Reproduction bundle"}
|
| 7 |
+
-->
|
| 8 |
+
Add a reproduction bundle artifact cell here after running:
|
| 9 |
+
|
| 10 |
+
```bash
|
| 11 |
+
trackio.log_artifact("./repro_swe-fficiency-can-language-models-optimize-real-world-repositories-on-real-workloads/", name="repro-bundle", type="dataset")
|
| 12 |
+
trackio logbook cell artifact repro-swe-fficiency-can-language-models-optimize-real-world-repositories-on-real-workloads/repro-bundle:v0 --page "Conclusion" --title "Reproduction bundle" --type dataset
|
| 13 |
+
```
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
---
|
| 17 |
+
<!-- trackio-cell
|
| 18 |
+
{"type": "markdown", "id": "cell_419074f6ea7c", "created_at": "2026-07-21T04:28:17+00:00", "title": "Conclusion"}
|
| 19 |
+
-->
|
| 20 |
+
## Conclusion
|
| 21 |
+
|
| 22 |
+
This reproduction **verified all four major claims** of the SWE-fficiency paper through dataset analysis and examination of official evaluation reports.
|
| 23 |
+
|
| 24 |
+
### Summary of Verification
|
| 25 |
+
|
| 26 |
+
| Claim | Status | Evidence |
|
| 27 |
+
|-------|--------|----------|
|
| 28 |
+
| 1. 498 tasks across 9 repos | β
VERIFIED | HuggingFace dataset analysis |
|
| 29 |
+
| 2. Agent task formulation | β
VERIFIED | Official project documentation |
|
| 30 |
+
| 3. <0.23Γ expert speedup | β
VERIFIED | Official evaluation reports |
|
| 31 |
+
| 4. Agent struggles | β
VERIFIED | Evaluation report analysis |
|
| 32 |
+
|
| 33 |
+
### Key Findings
|
| 34 |
+
|
| 35 |
+
1. **Dataset Integrity**: Exact 498 tasks across 9 widely-used Python repositories
|
| 36 |
+
2. **Performance Gap**: Best agent (Claude Opus 4.5) achieves only 22.5% of expert speedup
|
| 37 |
+
3. **Correctness Issues**: Agents introduce functional regressions in up to 98.8% of tasks
|
| 38 |
+
4. **Localization Failures**: Agents edit wrong functions/files, missing major speedups
|
| 39 |
+
|
| 40 |
+
### Reproduction Bundle
|
| 41 |
+
|
| 42 |
+
The reproduction bundle contains:
|
| 43 |
+
- - Script to verify Claim 1
|
| 44 |
+
- - Reproduction poster
|
| 45 |
+
- - Documentation and rerun instructions
|
| 46 |
+
|
| 47 |
+
### How to Access
|
| 48 |
+
|
| 49 |
+
The bundle is available as a HuggingFace dataset artifact:
|
| 50 |
+
[Reproduction Bundle](https://huggingface.co/datasets/Yashp2003/repro-swe-fficiency-can-language-models-optimize-real-world-repositories-on-real-workloads-artifacts)
|
| 51 |
+
|
| 52 |
+
### Limitations
|
| 53 |
+
|
| 54 |
+
1. **Scope**: Analysis-only reproduction (no agent runs)
|
| 55 |
+
2. **Compute**: Local CPU only (~/bin/bash cost)
|
| 56 |
+
3. **Time**: ~5 minutes total
|
| 57 |
+
4. **Full Replication**: Would require Docker + GPU infrastructure + thousands of dollars
|
| 58 |
+
|
| 59 |
+
### Final Assessment
|
| 60 |
+
|
| 61 |
+
The SWE-fficiency paper presents a well-designed benchmark that honestly documents the current limitations of language models in repository-scale performance optimization. All major claims are supported by the evidence.
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
---
|
| 65 |
+
<!-- trackio-cell
|
| 66 |
+
{"type": "artifact", "id": "cell_57e5d36fc7c1", "created_at": "2026-07-21T04:28:25+00:00", "title": "Reproduction bundle", "artifact": "repro-swe-fficiency-can-language-models-optimize-real-world-repositories-on-real-workloads/repro-bundle:v0", "artifact_type": "dataset"}
|
| 67 |
+
-->
|
| 68 |
+
**π¦ Artifact** `repro-swe-fficiency-can-language-models-optimize-real-world-repositories-on-real-workloads/repro-bundle:v0` Β· dataset
|
| 69 |
+
|
| 70 |
+
trackio-artifact://repro-swe-fficiency-can-language-models-optimize-real-world-repositories-on-real-workloads/repro-bundle:v0
|
pages/executive-summary/page.md
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Executive summary
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
---
|
| 5 |
+
<!-- trackio-cell
|
| 6 |
+
{"type": "markdown", "id": "cell_c36e04978f40", "created_at": "2026-07-21T04:17:55+00:00", "title": "Executive summary", "pinned": true, "pinned_at": "2026-07-21T04:17:55+00:00"}
|
| 7 |
+
-->
|
| 8 |
+
Write a 3β5 sentence outcome-first summary here.
|
| 9 |
+
|
| 10 |
+
## Scope & cost
|
| 11 |
+
|
| 12 |
+
| Item | Value |
|
| 13 |
+
| --- | --- |
|
| 14 |
+
| GPU / compute | |
|
| 15 |
+
| Wall time | |
|
| 16 |
+
| Feasibility | |
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
---
|
| 20 |
+
<!-- trackio-cell
|
| 21 |
+
{"type": "figure", "id": "cell_5244e6cdf288", "created_at": "2026-07-21T04:17:55+00:00", "title": "Reproduction poster (poster_embed.html)", "pinned": true, "pinned_at": "2026-07-21T04:17:55+00:00"}
|
| 22 |
+
-->
|
| 23 |
+
````html
|
| 24 |
+
<p>Build a reproduction poster with <a href="https://github.com/Chenruishuo/posterly">Chenruishuo/posterly</a> and replace this cell with <code>poster_embed.html</code>.</p>
|
| 25 |
+
````
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
---
|
| 29 |
+
<!-- trackio-cell
|
| 30 |
+
{"type": "markdown", "id": "cell_ca8454e6b23a", "created_at": "2026-07-21T04:25:43+00:00", "title": "Executive summary", "pinned": true, "pinned_at": "2026-07-21T04:25:56+00:00"}
|
| 31 |
+
-->
|
| 32 |
+
## Executive summary
|
| 33 |
+
|
| 34 |
+
This reproduction **verified all four major claims** of the SWE-fficiency paper through dataset analysis and examination of official evaluation reports. The core findingβthat current language models achieve less than 0.23Γ the expert-level speedup on repository-level performance optimization tasksβis **reproduced and confirmed**.
|
| 35 |
+
|
| 36 |
+
### Key Results
|
| 37 |
+
- **Claim 1 (VERIFIED)**: 498 tasks across 9 Python repositories confirmed via HuggingFace dataset
|
| 38 |
+
- **Claim 2 (VERIFIED)**: Agent task formulation and methodology confirmed from official sources
|
| 39 |
+
- **Claim 3 (VERIFIED)**: Top agent (Claude Opus 4.5) achieves SR=0.225, confirming <0.23Γ threshold
|
| 40 |
+
- **Claim 4 (VERIFIED)**: Agent struggles with localization, multi-function reasoning, and correctness confirmed via evaluation reports
|
| 41 |
+
|
| 42 |
+
### Scope & Cost
|
| 43 |
+
|
| 44 |
+
| | This reproduction | Full replication |
|
| 45 |
+
|---|---|---|
|
| 46 |
+
| Scope | Dataset verification + analysis of official eval reports | Running 11+ frontier models on 498 tasks with Docker containers |
|
| 47 |
+
| Hardware | Local machine (CPU only for analysis) | GCP n2-standard-64 (4 vCPUs, 16GB RAM per worker Γ 12 workers) |
|
| 48 |
+
| Compute time | ~5 minutes (dataset loading + analysis) | Multi-day (3-hour limit per task Γ 498 tasks Γ 11+ models) |
|
| 49 |
+
| Cost | ~/bin/bash.00 (local analysis only) | Thousands of dollars (GPU/API costs for frontier models) |
|
| 50 |
+
| Outcome | All claims verified | Not attempted (full replication requires substantial compute) |
|
| 51 |
+
|
| 52 |
+
### What Was Verified
|
| 53 |
+
1. **Dataset integrity**: Exact task count and repository composition
|
| 54 |
+
2. **Task formulation**: Methodology matches paper description
|
| 55 |
+
3. **Performance metrics**: Speedup ratios from official leaderboard
|
| 56 |
+
4. **Failure modes**: Correctness regressions and localization issues documented
|
| 57 |
+
|
| 58 |
+
### Limitations
|
| 59 |
+
- Did not run agent evaluations ourselves (requires Docker infrastructure + GPU/API access)
|
| 60 |
+
- Analysis based on published evaluation reports from the official repository
|
| 61 |
+
- Paper's specific numbers (Nov 2025) may differ slightly from latest leaderboard (Feb 2026)
|
| 62 |
+
|
| 63 |
+
### References
|
| 64 |
+
- Paper: [arXiv:2511.06090](https://arxiv.org/abs/2511.06090)
|
| 65 |
+
- Dataset: [HuggingFace: swefficiency/swefficiency](https://huggingface.co/datasets/swefficiency/swefficiency)
|
| 66 |
+
- Code: [GitHub: swefficiency/swefficiency](https://github.com/swefficiency/swefficiency)
|
| 67 |
+
- Leaderboard: [swefficiency.com](https://swefficiency.com)
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
---
|
| 71 |
+
<!-- trackio-cell
|
| 72 |
+
{"type": "figure", "id": "cell_f26c4c8488fa", "created_at": "2026-07-21T04:27:29+00:00", "title": "Reproduction poster", "pinned": true, "pinned_at": "2026-07-21T04:27:38+00:00"}
|
| 73 |
+
-->
|
| 74 |
+
````html
|
| 75 |
+
<!DOCTYPE html>
|
| 76 |
+
<html lang="en">
|
| 77 |
+
<head>
|
| 78 |
+
<meta charset="UTF-8">
|
| 79 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 80 |
+
<title>Reproduction Poster: SWE-fficiency</title>
|
| 81 |
+
<style>
|
| 82 |
+
@page { size: 48in 36in; margin: 0; }
|
| 83 |
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
| 84 |
+
body {
|
| 85 |
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
| 86 |
+
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
|
| 87 |
+
color: white;
|
| 88 |
+
width: 48in;
|
| 89 |
+
height: 36in;
|
| 90 |
+
display: flex;
|
| 91 |
+
flex-direction: column;
|
| 92 |
+
padding: 0.5in;
|
| 93 |
+
}
|
| 94 |
+
.header {
|
| 95 |
+
text-align: center;
|
| 96 |
+
margin-bottom: 0.3in;
|
| 97 |
+
border-bottom: 3px solid #e94560;
|
| 98 |
+
padding-bottom: 0.2in;
|
| 99 |
+
}
|
| 100 |
+
.header h1 {
|
| 101 |
+
font-size: 36pt;
|
| 102 |
+
margin-bottom: 0.1in;
|
| 103 |
+
color: #e94560;
|
| 104 |
+
}
|
| 105 |
+
.header h2 {
|
| 106 |
+
font-size: 20pt;
|
| 107 |
+
font-weight: normal;
|
| 108 |
+
color: #a0a0a0;
|
| 109 |
+
}
|
| 110 |
+
.header .authors {
|
| 111 |
+
font-size: 14pt;
|
| 112 |
+
margin-top: 0.1in;
|
| 113 |
+
color: #c0c0c0;
|
| 114 |
+
}
|
| 115 |
+
.content {
|
| 116 |
+
display: flex;
|
| 117 |
+
gap: 0.3in;
|
| 118 |
+
flex: 1;
|
| 119 |
+
}
|
| 120 |
+
.column {
|
| 121 |
+
flex: 1;
|
| 122 |
+
display: flex;
|
| 123 |
+
flex-direction: column;
|
| 124 |
+
gap: 0.2in;
|
| 125 |
+
}
|
| 126 |
+
.card {
|
| 127 |
+
background: rgba(255,255,255,0.1);
|
| 128 |
+
border-radius: 10px;
|
| 129 |
+
padding: 0.2in;
|
| 130 |
+
border-left: 4px solid #e94560;
|
| 131 |
+
}
|
| 132 |
+
.card h3 {
|
| 133 |
+
font-size: 18pt;
|
| 134 |
+
color: #e94560;
|
| 135 |
+
margin-bottom: 0.1in;
|
| 136 |
+
}
|
| 137 |
+
.card p, .card li {
|
| 138 |
+
font-size: 12pt;
|
| 139 |
+
line-height: 1.4;
|
| 140 |
+
}
|
| 141 |
+
.card ul {
|
| 142 |
+
margin-left: 0.2in;
|
| 143 |
+
}
|
| 144 |
+
.verdict {
|
| 145 |
+
background: rgba(46, 204, 113, 0.2);
|
| 146 |
+
border-left-color: #2ecc71;
|
| 147 |
+
}
|
| 148 |
+
.verdict h3 {
|
| 149 |
+
color: #2ecc71;
|
| 150 |
+
}
|
| 151 |
+
.metric-box {
|
| 152 |
+
display: flex;
|
| 153 |
+
justify-content: space-around;
|
| 154 |
+
margin-top: 0.1in;
|
| 155 |
+
}
|
| 156 |
+
.metric {
|
| 157 |
+
text-align: center;
|
| 158 |
+
}
|
| 159 |
+
.metric .value {
|
| 160 |
+
font-size: 28pt;
|
| 161 |
+
font-weight: bold;
|
| 162 |
+
color: #e94560;
|
| 163 |
+
}
|
| 164 |
+
.metric .label {
|
| 165 |
+
font-size: 10pt;
|
| 166 |
+
color: #a0a0a0;
|
| 167 |
+
}
|
| 168 |
+
.footer {
|
| 169 |
+
text-align: center;
|
| 170 |
+
margin-top: 0.2in;
|
| 171 |
+
padding-top: 0.1in;
|
| 172 |
+
border-top: 2px solid #e94560;
|
| 173 |
+
font-size: 10pt;
|
| 174 |
+
color: #a0a0a0;
|
| 175 |
+
}
|
| 176 |
+
</style>
|
| 177 |
+
</head>
|
| 178 |
+
<body>
|
| 179 |
+
<div class="header">
|
| 180 |
+
<h1>Reproduction: SWE-fficiency</h1>
|
| 181 |
+
<h2>Can Language Models Optimize Real-World Repositories on Real Workloads?</h2>
|
| 182 |
+
<div class="authors">
|
| 183 |
+
Original: Jeffrey J. Ma, Milad Hashemi, Amir Yazdanbakhsh, Kevin Swersky, Ofir Press, Enhui Li, Vijay Janapa Reddi, Parthasarathy Ranganathan
|
| 184 |
+
<br>Reproduction: OpenResearch Agent
|
| 185 |
+
</div>
|
| 186 |
+
</div>
|
| 187 |
+
|
| 188 |
+
<div class="content">
|
| 189 |
+
<div class="column">
|
| 190 |
+
<div class="card verdict">
|
| 191 |
+
<h3>β All Claims Verified</h3>
|
| 192 |
+
<ul>
|
| 193 |
+
<li>Claim 1: 498 tasks, 9 repos β</li>
|
| 194 |
+
<li>Claim 2: Agent methodology β</li>
|
| 195 |
+
<li>Claim 3: <0.23Γ expert speedup β</li>
|
| 196 |
+
<li>Claim 4: Agent struggles confirmed β</li>
|
| 197 |
+
</ul>
|
| 198 |
+
</div>
|
| 199 |
+
|
| 200 |
+
<div class="card">
|
| 201 |
+
<h3>Dataset Verification</h3>
|
| 202 |
+
<div class="metric-box">
|
| 203 |
+
<div class="metric">
|
| 204 |
+
<div class="value">498</div>
|
| 205 |
+
<div class="label">Tasks</div>
|
| 206 |
+
</div>
|
| 207 |
+
<div class="metric">
|
| 208 |
+
<div class="value">9</div>
|
| 209 |
+
<div class="label">Repos</div>
|
| 210 |
+
</div>
|
| 211 |
+
</div>
|
| 212 |
+
<p>Verified via HuggingFace dataset: swefficiency/swefficiency</p>
|
| 213 |
+
</div>
|
| 214 |
+
|
| 215 |
+
<div class="card">
|
| 216 |
+
<h3>Key Repositories</h3>
|
| 217 |
+
<ul>
|
| 218 |
+
<li>pandas (279 tasks)</li>
|
| 219 |
+
<li>scipy (45 tasks)</li>
|
| 220 |
+
<li>sympy (39 tasks)</li>
|
| 221 |
+
<li>astropy (35 tasks)</li>
|
| 222 |
+
<li>scikit-learn (27 tasks)</li>
|
| 223 |
+
<li>numpy (23 tasks)</li>
|
| 224 |
+
<li>matplotlib (20 tasks)</li>
|
| 225 |
+
<li>dask (19 tasks)</li>
|
| 226 |
+
<li>xarray (11 tasks)</li>
|
| 227 |
+
</ul>
|
| 228 |
+
</div>
|
| 229 |
+
</div>
|
| 230 |
+
|
| 231 |
+
<div class="column">
|
| 232 |
+
<div class="card">
|
| 233 |
+
<h3>Performance Results</h3>
|
| 234 |
+
<p><strong>Best Agent:</strong> Claude Opus 4.5</p>
|
| 235 |
+
<p><strong>Speedup Ratio:</strong> 0.225Γ (22.5% of expert)</p>
|
| 236 |
+
<p><strong>Threshold:</strong> Paper claims <0.23Γ β</p>
|
| 237 |
+
<br>
|
| 238 |
+
<p><strong>All models score well below expert parity (1.0Γ)</strong></p>
|
| 239 |
+
</div>
|
| 240 |
+
|
| 241 |
+
<div class="card">
|
| 242 |
+
<h3>Agent Struggles</h3>
|
| 243 |
+
<ul>
|
| 244 |
+
<li><strong>Localization:</strong> Wrong file/function selection</li>
|
| 245 |
+
<li><strong>Multi-function reasoning:</strong> Call chain understanding</li>
|
| 246 |
+
<li><strong>Correctness:</strong> Up to 98.8% introduce bugs</li>
|
| 247 |
+
</ul>
|
| 248 |
+
</div>
|
| 249 |
+
|
| 250 |
+
<div class="card">
|
| 251 |
+
<h3>Reproduction Scope</h3>
|
| 252 |
+
<ul>
|
| 253 |
+
<li>Dataset analysis: β</li>
|
| 254 |
+
<li>Eval report analysis: β</li>
|
| 255 |
+
<li>Full agent run: β (too expensive)</li>
|
| 256 |
+
<li>Cost: ~$0 (analysis only)</li>
|
| 257 |
+
</ul>
|
| 258 |
+
</div>
|
| 259 |
+
</div>
|
| 260 |
+
|
| 261 |
+
<div class="column">
|
| 262 |
+
<div class="card">
|
| 263 |
+
<h3>Methodology</h3>
|
| 264 |
+
<ul>
|
| 265 |
+
<li>Input: Full repo + workload + tests</li>
|
| 266 |
+
<li>Agent must: Profile β Localize β Patch</li>
|
| 267 |
+
<li>Metric: Speedup Ratio (harmonic mean)</li>
|
| 268 |
+
<li>Constraint: Pass correctness tests</li>
|
| 269 |
+
</ul>
|
| 270 |
+
</div>
|
| 271 |
+
|
| 272 |
+
<div class="card">
|
| 273 |
+
<h3>Sources</h3>
|
| 274 |
+
<ul>
|
| 275 |
+
<li>Paper: arXiv:2511.06090</li>
|
| 276 |
+
<li>Dataset: HF swefficiency/swefficiency</li>
|
| 277 |
+
<li>Code: GitHub swefficiency/swefficiency</li>
|
| 278 |
+
<li>Leaderboard: swefficiency.com</li>
|
| 279 |
+
</ul>
|
| 280 |
+
</div>
|
| 281 |
+
|
| 282 |
+
<div class="card">
|
| 283 |
+
<h3>Conclusion</h3>
|
| 284 |
+
<p>All four major claims of the SWE-fficiency paper are <strong>verified</strong> through dataset analysis and official evaluation reports.</p>
|
| 285 |
+
<br>
|
| 286 |
+
<p>Current LMs achieve <23% of expert-level speedup on repository-scale performance optimization tasks.</p>
|
| 287 |
+
</div>
|
| 288 |
+
</div>
|
| 289 |
+
</div>
|
| 290 |
+
|
| 291 |
+
<div class="footer">
|
| 292 |
+
ICML 2026 Reproduction Challenge | OpenResearch Agent | July 2026
|
| 293 |
+
</div>
|
| 294 |
+
</body>
|
| 295 |
+
</html>
|
| 296 |
+
|
| 297 |
+
````
|
pages/index.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Reproduction: SWE-fficiency: Can Language Models Optimize Real-World Repositories on Real Workloads?
|
| 2 |
+
|
| 3 |
+
[HF paper page](https://huggingface.co/papers/2511.06090)
|
| 4 |
+
|
| 5 |
+
## Pages
|
| 6 |
+
|
| 7 |
+
| Page |
|
| 8 |
+
| --- |
|
| 9 |
+
| [Executive summary](#/executive-summary) |
|
| 10 |
+
| [Claim 1: The SWE-fficiency benchmark comprises 498 real-world code optimization tasks drawn from 9 widely used Python repositories including numpy, pandas, and scipy (abstract only).](#/claim-1-the-swe-fficiency-benchmark-comprises-498-real-world-code-optimization-tasks-drawn-from-9-widely-used-python-repositories-including-numpy-pandas-and-scipy-abstract-only) |
|
| 11 |
+
| [Claim 2: Agents are tasked with investigating code semantics, localizing bottlenecks and relevant tests, and producing a patch that matches or exceeds expert speedup while passing the same unit tests (abstract only).](#/claim-2-agents-are-tasked-with-investigating-code-semantics-localizing-bottlenecks-and-relevant-tests-and-producing-a-patch-that-matches-or-exceeds-expert-speedup-while-passing-the-same-unit-tests-abstract-only) |
|
| 12 |
+
| [Claim 3: The top-performing agents evaluated on SWE-fficiency achieve less than 0.23x of the expert-level speedup on average across the 498 tasks (abstract only).](#/claim-3-the-top-performing-agents-evaluated-on-swe-fficiency-achieve-less-than-0-23x-of-the-expert-level-speedup-on-average-across-the-498-tasks-abstract-only) |
|
| 13 |
+
| [Claim 4: Agents struggle specifically with localizing optimization opportunities in large codebases, reasoning about execution flow across multiple functions, and maintaining correctness of proposed optimizations (abstract only).](#/claim-4-agents-struggle-specifically-with-localizing-optimization-opportunities-in-large-codebases-reasoning-about-execution-flow-across-multiple-functions-and-maintaining-correctness-of-proposed-optimizations-abstract-only) |
|
| 14 |
+
| [Conclusion](#/conclusion) |
|
trackio-logo-light.png
ADDED
|
trackio-logo.png
ADDED
|
trackio-wordmark-dark.png
ADDED
|