heyiam 0.2.29 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/README.md +45 -0
  2. package/dist/auth.js +29 -3
  3. package/dist/config.js +10 -1
  4. package/dist/db.js +0 -1
  5. package/dist/export.js +124 -27
  6. package/dist/format-utils.js +5 -0
  7. package/dist/github.js +381 -0
  8. package/dist/index.js +168 -0
  9. package/dist/mount.js +300 -102
  10. package/dist/parsers/claude.js +2 -28
  11. package/dist/parsers/codex.js +2 -26
  12. package/dist/parsers/cursor.js +2 -26
  13. package/dist/parsers/duration.js +35 -0
  14. package/dist/parsers/gemini.js +2 -20
  15. package/dist/parsers/index.js +22 -3
  16. package/dist/parsers/types.js +0 -1
  17. package/dist/public/assets/index-Coilyhtr.css +1 -0
  18. package/dist/public/assets/index-D0noVMFu.js +44 -0
  19. package/dist/public/index.html +2 -2
  20. package/dist/redact.js +4 -104
  21. package/dist/render/build-render-data.js +9 -2
  22. package/dist/render/index.js +32 -5
  23. package/dist/render/liquid.js +147 -7
  24. package/dist/render/mock-data.js +303 -0
  25. package/dist/render/templates/aurora/portfolio.liquid +192 -0
  26. package/dist/render/templates/aurora/project.liquid +260 -0
  27. package/dist/render/templates/aurora/session.liquid +223 -0
  28. package/dist/render/templates/aurora/styles.css +1184 -0
  29. package/dist/render/templates/bauhaus/portfolio.liquid +169 -0
  30. package/dist/render/templates/bauhaus/project.liquid +300 -0
  31. package/dist/render/templates/bauhaus/session.liquid +333 -0
  32. package/dist/render/templates/bauhaus/styles.css +1645 -0
  33. package/dist/render/templates/blueprint/portfolio.liquid +153 -0
  34. package/dist/render/templates/blueprint/project.liquid +286 -0
  35. package/dist/render/templates/blueprint/session.liquid +248 -0
  36. package/dist/render/templates/blueprint/styles.css +1289 -0
  37. package/dist/render/templates/canvas/portfolio.liquid +203 -0
  38. package/dist/render/templates/canvas/project.liquid +235 -0
  39. package/dist/render/templates/canvas/session.liquid +223 -0
  40. package/dist/render/templates/canvas/styles.css +1440 -0
  41. package/dist/render/templates/carbon/portfolio.liquid +160 -0
  42. package/dist/render/templates/carbon/project.liquid +249 -0
  43. package/dist/render/templates/carbon/session.liquid +190 -0
  44. package/dist/render/templates/carbon/styles.css +1097 -0
  45. package/dist/render/templates/chalk/portfolio.liquid +189 -0
  46. package/dist/render/templates/chalk/project.liquid +245 -0
  47. package/dist/render/templates/chalk/session.liquid +215 -0
  48. package/dist/render/templates/chalk/styles.css +1161 -0
  49. package/dist/render/templates/circuit/portfolio.liquid +152 -0
  50. package/dist/render/templates/circuit/project.liquid +247 -0
  51. package/dist/render/templates/circuit/session.liquid +205 -0
  52. package/dist/render/templates/circuit/styles.css +1409 -0
  53. package/dist/render/templates/cosmos/portfolio.liquid +222 -0
  54. package/dist/render/templates/cosmos/project.liquid +327 -0
  55. package/dist/render/templates/cosmos/session.liquid +239 -0
  56. package/dist/render/templates/cosmos/styles.css +1157 -0
  57. package/dist/render/templates/daylight/portfolio.liquid +207 -0
  58. package/dist/render/templates/daylight/project.liquid +229 -0
  59. package/dist/render/templates/daylight/session.liquid +219 -0
  60. package/dist/render/templates/daylight/styles.css +1315 -0
  61. package/dist/render/templates/editorial/portfolio.liquid +110 -0
  62. package/dist/render/templates/editorial/project.liquid +202 -0
  63. package/dist/render/templates/editorial/session.liquid +171 -0
  64. package/dist/render/templates/editorial/styles.css +826 -0
  65. package/dist/render/templates/ember/portfolio.liquid +306 -0
  66. package/dist/render/templates/ember/project.liquid +232 -0
  67. package/dist/render/templates/ember/session.liquid +202 -0
  68. package/dist/render/templates/ember/styles.css +1289 -0
  69. package/dist/render/templates/glacier/portfolio.liquid +261 -0
  70. package/dist/render/templates/glacier/project.liquid +288 -0
  71. package/dist/render/templates/glacier/session.liquid +217 -0
  72. package/dist/render/templates/glacier/styles.css +1204 -0
  73. package/dist/render/templates/grid/portfolio.liquid +255 -0
  74. package/dist/render/templates/grid/project.liquid +306 -0
  75. package/dist/render/templates/grid/session.liquid +260 -0
  76. package/dist/render/templates/grid/styles.css +1445 -0
  77. package/dist/render/templates/kinetic/portfolio.liquid +158 -0
  78. package/dist/render/templates/kinetic/project.liquid +242 -0
  79. package/dist/render/templates/kinetic/session.liquid +228 -0
  80. package/dist/render/templates/kinetic/styles.css +948 -0
  81. package/dist/render/templates/meridian/portfolio.liquid +243 -0
  82. package/dist/render/templates/meridian/project.liquid +376 -0
  83. package/dist/render/templates/meridian/session.liquid +298 -0
  84. package/dist/render/templates/meridian/styles.css +1375 -0
  85. package/dist/render/templates/minimal/portfolio.liquid +71 -0
  86. package/dist/render/templates/minimal/project.liquid +154 -0
  87. package/dist/render/templates/minimal/session.liquid +140 -0
  88. package/dist/render/templates/minimal/styles.css +529 -0
  89. package/dist/render/templates/mono/portfolio.liquid +281 -0
  90. package/dist/render/templates/mono/project.liquid +275 -0
  91. package/dist/render/templates/mono/session.liquid +276 -0
  92. package/dist/render/templates/mono/styles.css +1022 -0
  93. package/dist/render/templates/neon/portfolio.liquid +207 -0
  94. package/dist/render/templates/neon/project.liquid +225 -0
  95. package/dist/render/templates/neon/session.liquid +195 -0
  96. package/dist/render/templates/neon/styles.css +1271 -0
  97. package/dist/render/templates/noir/portfolio.liquid +137 -0
  98. package/dist/render/templates/noir/project.liquid +220 -0
  99. package/dist/render/templates/noir/session.liquid +241 -0
  100. package/dist/render/templates/noir/styles.css +1229 -0
  101. package/dist/render/templates/obsidian/portfolio.liquid +247 -0
  102. package/dist/render/templates/obsidian/project.liquid +280 -0
  103. package/dist/render/templates/obsidian/session.liquid +241 -0
  104. package/dist/render/templates/obsidian/styles.css +1407 -0
  105. package/dist/render/templates/paper/portfolio.liquid +257 -0
  106. package/dist/render/templates/paper/project.liquid +235 -0
  107. package/dist/render/templates/paper/session.liquid +271 -0
  108. package/dist/render/templates/paper/styles.css +1513 -0
  109. package/dist/render/templates/parallax/portfolio.liquid +295 -0
  110. package/dist/render/templates/parallax/project.liquid +275 -0
  111. package/dist/render/templates/parallax/session.liquid +295 -0
  112. package/dist/render/templates/parallax/styles.css +1880 -0
  113. package/dist/render/templates/parchment/portfolio.liquid +280 -0
  114. package/dist/render/templates/parchment/project.liquid +289 -0
  115. package/dist/render/templates/parchment/session.liquid +346 -0
  116. package/dist/render/templates/parchment/styles.css +1401 -0
  117. package/dist/render/templates/partials/_beats.liquid +16 -0
  118. package/dist/render/templates/partials/_breadcrumb.liquid +9 -0
  119. package/dist/render/templates/partials/_footer.liquid +7 -0
  120. package/dist/render/templates/partials/_growth-chart.liquid +7 -0
  121. package/dist/render/templates/partials/_key-decisions.liquid +20 -0
  122. package/dist/render/templates/partials/_links.liquid +16 -0
  123. package/dist/render/templates/partials/_narrative.liquid +8 -0
  124. package/dist/render/templates/partials/_phases.liquid +20 -0
  125. package/dist/render/templates/partials/_portfolio-header.liquid +20 -0
  126. package/dist/render/templates/partials/_portfolio-projects.liquid +16 -0
  127. package/dist/render/templates/partials/_portfolio-stats.liquid +19 -0
  128. package/dist/render/templates/partials/_qa.liquid +13 -0
  129. package/dist/render/templates/partials/_screenshot.liquid +15 -0
  130. package/dist/render/templates/partials/_session-cards.liquid +30 -0
  131. package/dist/render/templates/partials/_session-header.liquid +39 -0
  132. package/dist/render/templates/partials/_session-sidebar.liquid +30 -0
  133. package/dist/render/templates/partials/_skills.liquid +12 -0
  134. package/dist/render/templates/partials/_source-breakdown.liquid +22 -0
  135. package/dist/render/templates/partials/_stats.liquid +38 -0
  136. package/dist/render/templates/partials/_work-timeline.liquid +7 -0
  137. package/dist/render/templates/project.liquid +7 -4
  138. package/dist/render/templates/radar/portfolio.liquid +223 -0
  139. package/dist/render/templates/radar/project.liquid +278 -0
  140. package/dist/render/templates/radar/session.liquid +300 -0
  141. package/dist/render/templates/radar/styles.css +1055 -0
  142. package/dist/render/templates/showcase/portfolio.liquid +221 -0
  143. package/dist/render/templates/showcase/project.liquid +237 -0
  144. package/dist/render/templates/showcase/session.liquid +210 -0
  145. package/dist/render/templates/showcase/styles.css +1284 -0
  146. package/dist/render/templates/signal/portfolio.liquid +217 -0
  147. package/dist/render/templates/signal/project.liquid +278 -0
  148. package/dist/render/templates/signal/session.liquid +282 -0
  149. package/dist/render/templates/signal/styles.css +1401 -0
  150. package/dist/render/templates/strata/portfolio.liquid +180 -0
  151. package/dist/render/templates/strata/project.liquid +282 -0
  152. package/dist/render/templates/strata/session.liquid +261 -0
  153. package/dist/render/templates/strata/styles.css +1354 -0
  154. package/dist/render/templates/styles.css +1190 -0
  155. package/dist/render/templates/terminal/portfolio.liquid +102 -0
  156. package/dist/render/templates/terminal/project.liquid +161 -0
  157. package/dist/render/templates/terminal/session.liquid +145 -0
  158. package/dist/render/templates/terminal/styles.css +497 -0
  159. package/dist/render/templates/verdant/portfolio.liquid +321 -0
  160. package/dist/render/templates/verdant/project.liquid +309 -0
  161. package/dist/render/templates/verdant/session.liquid +237 -0
  162. package/dist/render/templates/verdant/styles.css +1261 -0
  163. package/dist/render/templates/zen/portfolio.liquid +124 -0
  164. package/dist/render/templates/zen/project.liquid +187 -0
  165. package/dist/render/templates/zen/session.liquid +203 -0
  166. package/dist/render/templates/zen/styles.css +1211 -0
  167. package/dist/render/templates.js +90 -0
  168. package/dist/routes/auth.js +7 -3
  169. package/dist/routes/context.js +17 -10
  170. package/dist/routes/delete.js +195 -0
  171. package/dist/routes/enhance.js +57 -40
  172. package/dist/routes/export.js +14 -4
  173. package/dist/routes/github.js +254 -0
  174. package/dist/routes/index.js +2 -0
  175. package/dist/routes/portfolio-render-data.js +160 -0
  176. package/dist/routes/preview.js +555 -108
  177. package/dist/routes/projects.js +61 -24
  178. package/dist/routes/publish.js +320 -31
  179. package/dist/routes/settings.js +194 -1
  180. package/dist/routes/sse.js +9 -0
  181. package/dist/search.js +6 -0
  182. package/dist/server.js +11 -3
  183. package/dist/settings.js +112 -9
  184. package/package.json +3 -4
  185. package/dist/public/assets/index-CC9G8EF1.js +0 -21
  186. package/dist/public/assets/index-Dalqz2mC.css +0 -1
@@ -0,0 +1,124 @@
1
+ <div class="zen-portfolio" data-render-version="2" data-template="zen" data-username="{{ user.username }}">
2
+
3
+ <main class="zen-container">
4
+
5
+ {% if hasProfile %}
6
+ <!-- Section 1: Profile Header -->
7
+ <section class="zen-section zen-fade" aria-label="Profile">
8
+ <div class="zen-header-profile">
9
+ {% if user.photoUrl %}
10
+ <img src="{{ user.photoUrl }}" alt="{{ user.displayName }}" class="zen-header-photo" data-portfolio-field="photoBase64"{% unless user.photoUrl %} data-portfolio-empty="true"{% endunless %}>
11
+ {% endif %}
12
+ <div class="zen-header-info">
13
+ {% if user.displayName != blank %}
14
+ <h1 class="zen-display zen-header-name" data-portfolio-field="displayName">{{ user.displayName }}</h1>
15
+ {% endif %}
16
+ {% if user.bio != blank %}
17
+ <p class="zen-header-bio" data-portfolio-field="bio">{{ user.bio }}</p>
18
+ {% endif %}
19
+ {% if user.location != blank %}
20
+ <p class="zen-header-location" data-portfolio-field="location">{{ user.location }}</p>
21
+ {% endif %}
22
+ {% if user.email != blank or user.linkedinUrl != blank or user.githubUrl != blank or user.twitterHandle != blank or user.websiteUrl != blank %}
23
+ <ul class="zen-header-contact" aria-label="Contact and social links">
24
+ <li data-portfolio-field="email"{% unless user.email %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.email %}mailto:{{ user.email }}{% endif %}"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m2 4 10 8 10-8"/></svg>{{ user.email }}</a></li>
25
+ <li data-portfolio-field="phone"{% unless user.phone %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.phone %}tel:{{ user.phone }}{% endif %}"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 22 16.92z"/></svg>{{ user.phone }}</a></li>
26
+ <li data-portfolio-field="linkedinUrl"{% unless user.linkedinUrl %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.linkedinUrl %}{{ user.linkedinUrl }}{% endif %}"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M20.5 2h-17A1.5 1.5 0 002 3.5v17A1.5 1.5 0 003.5 22h17a1.5 1.5 0 001.5-1.5v-17A1.5 1.5 0 0020.5 2zM8 19H5v-9h3zM6.5 8.25A1.75 1.75 0 118.3 6.5a1.78 1.78 0 01-1.8 1.75zM19 19h-3v-4.74c0-1.42-.6-1.93-1.38-1.93A1.74 1.74 0 0013 14.19V19h-3v-9h2.9v1.3a3.11 3.11 0 012.7-1.4c1.55 0 3.36.86 3.36 3.66z"/></svg>LinkedIn</a></li>
27
+ <li data-portfolio-field="githubUrl"{% unless user.githubUrl %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.githubUrl %}{{ user.githubUrl }}{% endif %}"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>GitHub</a></li>
28
+ <li data-portfolio-field="twitterHandle"{% unless user.twitterHandle %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.twitterHandle %}https://x.com/{{ user.twitterHandle }}{% endif %}"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>@{{ user.twitterHandle }}</a></li>
29
+ <li data-portfolio-field="websiteUrl"{% unless user.websiteUrl %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.websiteUrl %}{{ user.websiteUrl }}{% endif %}"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>{{ user.websiteUrl | stripProtocol }}</a></li>
30
+ </ul>
31
+ {% endif %}
32
+ {% if user.resumeUrl != blank %}
33
+ <a href="{{ user.resumeUrl }}" class="zen-header-resume"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="12" y1="18" x2="12" y2="12"/><polyline points="9 15 12 18 15 15"/></svg>Download Resume</a>
34
+ {% endif %}
35
+ </div>
36
+ </div>
37
+ </section>
38
+ {% endif %}
39
+
40
+ <hr class="zen-rule zen-fade" aria-hidden="true">
41
+
42
+ <!-- Section 2: Aggregate Stats -->
43
+ <section class="zen-section zen-fade" aria-label="Portfolio statistics">
44
+ <h2 class="zen-heading">Overview</h2>
45
+ <p class="zen-stats">
46
+ <span class="zen-stat-value">{{ projects.size }}</span> projects across
47
+ <span class="zen-stat-value">{{ totalSessions | localeNumber }}</span> sessions.
48
+ <span class="zen-stat-value">{{ totalLoc | localeNumber }}</span> lines changed.
49
+ {% if efficiencyMultiplier %}
50
+ I spent <span class="zen-stat-value">{{ totalDurationMinutes | formatDuration }}</span> directing
51
+ <span class="zen-stat-value" style="font-weight:500">{{ totalAgentDurationMinutes | formatDuration }}</span> of agent work &mdash;
52
+ a <span class="zen-stat-value" style="font-size:1.375rem;font-weight:600">{{ efficiencyMultiplier }}&times;</span> multiplier.
53
+ {% else %}
54
+ <span class="zen-stat-value">{{ totalDurationMinutes | formatDuration }}</span> of work.
55
+ {% endif %}
56
+ </p>
57
+ </section>
58
+
59
+ <hr class="zen-rule zen-fade" aria-hidden="true">
60
+
61
+ <!-- Section 3: Projects -->
62
+ {% if projects.size > 0 %}
63
+ <section class="zen-section zen-fade" aria-label="Projects">
64
+ <h2 class="zen-heading">Projects</h2>
65
+
66
+ {% for p in projects %}
67
+ {% if forloop.index > 1 %}
68
+ <hr class="zen-project-divider" aria-hidden="true">
69
+ {% endif %}
70
+ <article class="zen-project zen-fade" aria-label="{{ p.title }} project">
71
+ <h3 class="zen-project-title">
72
+ <a href="/{{ user.username }}/{{ p.slug }}">{{ p.title }}</a>
73
+ </h3>
74
+ {% if p.narrative != blank %}
75
+ <p class="zen-project-narrative">{{ p.narrative }}</p>
76
+ {% endif %}
77
+ <p class="zen-project-meta">
78
+ {{ p.totalSessions }} sessions &middot; {{ p.totalDurationMinutes | formatDuration }} &middot; {{ p.totalLoc | localeNumber }} lines changed
79
+ </p>
80
+ {% if p.skills.size > 0 %}
81
+ <p class="zen-project-skills">
82
+ {{ p.skills | join: ", " }}
83
+ </p>
84
+ {% endif %}
85
+ {% if p.sourceCounts.size > 0 %}
86
+ <p class="zen-project-source">
87
+ {% for sc in p.sourceCounts %}{% assign pct = sc.count | times: 100 | divided_by: p.totalSessions %}{{ sc.tool }} {{ pct }}%{% unless forloop.last %}, {% endunless %}{% endfor %}
88
+ </p>
89
+ {% endif %}
90
+ </article>
91
+ {% endfor %}
92
+ </section>
93
+
94
+ <hr class="zen-rule zen-fade" aria-hidden="true">
95
+ {% endif %}
96
+
97
+ <!-- Source Summary -->
98
+ {% if sourceCounts.size > 0 %}
99
+ <section class="zen-section zen-fade" aria-label="Source breakdown">
100
+ <h2 class="zen-heading">Source Tools</h2>
101
+ <div class="zen-source-summary">
102
+ {% for sc in sourceCounts %}
103
+ {% assign pct = sc.count | times: 100 | divided_by: totalSourceSessions %}
104
+ <div class="zen-source-row">
105
+ <span class="zen-source-label">{{ sc.tool }}</span>
106
+ <span class="zen-source-value">{{ pct }}% ({{ sc.count }} sessions)</span>
107
+ </div>
108
+ {% endfor %}
109
+ </div>
110
+ </section>
111
+
112
+ <hr class="zen-rule zen-fade" aria-hidden="true">
113
+ {% endif %}
114
+
115
+ <!-- Footer -->
116
+ <footer class="zen-footer zen-fade" role="contentinfo">
117
+ <div class="zen-footer-inner">
118
+ <p class="zen-footer-text">heyi.am</p>
119
+ </div>
120
+ </footer>
121
+
122
+ </main>
123
+
124
+ </div>
@@ -0,0 +1,187 @@
1
+ <div class="zen-project-page" data-render-version="2" data-template="zen"{% if sessionBaseUrl %} data-session-base-url="{{ sessionBaseUrl }}"{% endif %} data-username="{{ user.username }}" data-project-slug="{{ project.slug }}">
2
+
3
+ <main class="zen-container">
4
+
5
+ <!-- Section 1: Project Header -->
6
+ <section class="zen-section zen-fade" aria-label="Project header">
7
+ <h1 class="zen-display">{{ project.title }}</h1>
8
+ {% if project.repoUrl != blank or project.projectUrl != blank %}
9
+ <div class="zen-project-links">
10
+ {% if project.repoUrl != blank %}
11
+ <a href="{{ project.repoUrl }}">{{ project.repoUrl | stripProtocol }}</a>
12
+ {% endif %}
13
+ {% if project.projectUrl != blank %}
14
+ <a href="{{ project.projectUrl }}">{{ project.projectUrl | stripProtocol }}</a>
15
+ {% endif %}
16
+ </div>
17
+ {% endif %}
18
+
19
+ {% if project.screenshotUrl != blank %}
20
+ <div class="zen-screenshot" role="img" aria-label="{{ project.title }} application screenshot">
21
+ <div class="zen-screenshot-chrome">
22
+ <span class="zen-screenshot-dot"></span>
23
+ <span class="zen-screenshot-dot"></span>
24
+ <span class="zen-screenshot-dot"></span>
25
+ {% if project.projectUrl != blank %}
26
+ <span class="zen-screenshot-url">{{ project.projectUrl | stripProtocol }}</span>
27
+ {% endif %}
28
+ </div>
29
+ <img src="{{ project.screenshotUrl }}" alt="{{ project.title }} screenshot" style="width:100%;display:block;">
30
+ </div>
31
+ {% endif %}
32
+ </section>
33
+
34
+ <hr class="zen-rule zen-fade" aria-hidden="true">
35
+
36
+ <!-- Section 2: Narrative -->
37
+ {% if project.narrative != blank %}
38
+ <section class="zen-section zen-fade" aria-label="Project narrative">
39
+ <h2 class="zen-heading">Narrative</h2>
40
+ <div class="zen-narrative">
41
+ <p>{{ project.narrative }}</p>
42
+ </div>
43
+ </section>
44
+
45
+ <hr class="zen-rule zen-fade" aria-hidden="true">
46
+ {% endif %}
47
+
48
+ <!-- Section 3: Stats -->
49
+ <section class="zen-section zen-fade" aria-label="Project statistics">
50
+ <h2 class="zen-heading">Numbers</h2>
51
+ <p class="zen-stats">
52
+ <span class="zen-stat-value">{{ project.totalSessions }}</span> sessions.
53
+ <span class="zen-stat-value">{{ project.totalLoc | localeNumber }}</span> lines changed.
54
+ {% if efficiencyMultiplier %}
55
+ I spent <span class="zen-stat-value">{{ project.totalDurationMinutes | formatDuration }}</span> directing
56
+ <span class="zen-stat-value" style="font-weight:500">{{ project.totalAgentDurationMinutes | formatDuration }}</span> of agent work &mdash;
57
+ a <span class="zen-stat-value" style="font-size:1.375rem;font-weight:600">{{ efficiencyMultiplier }}&times;</span> multiplier.
58
+ {% else %}
59
+ <span class="zen-stat-value">{{ project.totalDurationMinutes | formatDuration }}</span> of work.
60
+ {% endif %}
61
+ </p>
62
+ </section>
63
+
64
+ <hr class="zen-rule zen-fade" aria-hidden="true">
65
+
66
+ <!-- Section 4: Work Timeline (CSS-only bars) -->
67
+ {% if featuredSessions.size > 0 %}
68
+ {% assign maxDuration = 1 %}
69
+ {% for s in featuredSessions %}
70
+ {% if s.durationMinutes > maxDuration %}
71
+ {% assign maxDuration = s.durationMinutes %}
72
+ {% endif %}
73
+ {% endfor %}
74
+ <section class="zen-section zen-fade" aria-label="Work timeline">
75
+ <h2 class="zen-heading">Work Timeline</h2>
76
+ <div class="zen-chart" role="img" aria-label="Session duration chart">
77
+ {% for s in featuredSessions %}
78
+ {% assign barWidth = s.durationMinutes | times: 100.0 | divided_by: maxDuration | round: 1 %}
79
+ <div class="zen-chart-row">
80
+ <span class="zen-chart-label">{{ s.recordedAt | formatDateShort }}</span>
81
+ <span class="zen-chart-bar-track">
82
+ <span class="zen-chart-bar" style="width: {{ barWidth }}%"></span>
83
+ </span>
84
+ <span class="zen-chart-value">{{ s.durationMinutes }}m</span>
85
+ </div>
86
+ {% endfor %}
87
+ </div>
88
+ </section>
89
+
90
+ <hr class="zen-rule zen-fade" aria-hidden="true">
91
+ {% endif %}
92
+
93
+ <!-- Section 5: Phases -->
94
+ {% if arc.size > 0 %}
95
+ <section class="zen-section zen-fade" aria-label="Project phases">
96
+ <h2 class="zen-heading">Phases</h2>
97
+ <div class="zen-timeline" role="list" aria-label="Project phase timeline">
98
+ {% for phase in arc %}
99
+ <div class="zen-timeline-item" role="listitem">
100
+ {% if phase.dates != blank %}
101
+ <p class="zen-timeline-date">{{ phase.dates }}</p>
102
+ {% endif %}
103
+ <p class="zen-timeline-title">{{ phase.title }}</p>
104
+ {% if phase.description != blank %}
105
+ <p class="zen-timeline-desc">{{ phase.description }}</p>
106
+ {% endif %}
107
+ </div>
108
+ {% endfor %}
109
+ </div>
110
+ </section>
111
+
112
+ <hr class="zen-rule zen-fade" aria-hidden="true">
113
+ {% endif %}
114
+
115
+ <!-- Section 6: Skills -->
116
+ {% if project.skills.size > 0 %}
117
+ <section class="zen-section zen-fade" aria-label="Skills used">
118
+ <h2 class="zen-heading">Skills</h2>
119
+ <p class="zen-skills-text">
120
+ {{ project.skills | join: ", " }}
121
+ </p>
122
+ </section>
123
+
124
+ <hr class="zen-rule zen-fade" aria-hidden="true">
125
+ {% endif %}
126
+
127
+ <!-- Section 7: Key Decisions -->
128
+ {% if arc.size > 0 %}
129
+ <section class="zen-section zen-fade" aria-label="Key decisions">
130
+ <h2 class="zen-heading">Key Decisions</h2>
131
+ <ul class="zen-decisions" role="list">
132
+ {% for phase in arc %}
133
+ {% if phase.description != blank %}
134
+ <li class="zen-decision-item">
135
+ <p class="zen-decision-text">{{ phase.description }}</p>
136
+ </li>
137
+ {% endif %}
138
+ {% endfor %}
139
+ </ul>
140
+ </section>
141
+
142
+ <hr class="zen-rule zen-fade" aria-hidden="true">
143
+ {% endif %}
144
+
145
+ <!-- Section 8: Source Breakdown -->
146
+ {% if sourceCounts.size > 0 %}
147
+ <section class="zen-section zen-fade" aria-label="Source breakdown">
148
+ <h2 class="zen-heading">Source</h2>
149
+ <p class="zen-source">
150
+ {% for sc in sourceCounts %}{% if forloop.index > 1 %} &middot; {% endif %}{{ sc.tool }} {{ sc.count | times: 100.0 | divided_by: project.totalSessions | round }}% ({{ sc.count }} sessions){% endfor %}
151
+ </p>
152
+ </section>
153
+
154
+ <hr class="zen-rule zen-fade" aria-hidden="true">
155
+ {% endif %}
156
+
157
+ <!-- Section 9: Featured Sessions -->
158
+ {% if featuredSessions.size > 0 %}
159
+ <section class="zen-section zen-fade" aria-label="Featured sessions">
160
+ <h2 class="zen-heading">Sessions</h2>
161
+
162
+ {% for s in featuredSessions %}
163
+ {% if forloop.index > 1 %}
164
+ <hr class="zen-session-divider" aria-hidden="true">
165
+ {% endif %}
166
+ <div class="zen-session-item zen-fade">
167
+ <p class="zen-session-title">
168
+ <a href="{{ sessionBaseUrl }}/{{ s.slug }}{{ sessionSuffix }}">{{ s.title }}</a>
169
+ </p>
170
+ <p class="zen-session-meta">
171
+ {{ s.recordedAt | formatDateShort }} &middot; {{ s.durationMinutes | formatDuration }} &middot; {{ s.locChanged | localeNumber }} LOC{% if s.skills.size > 0 %} &middot; {{ s.skills | join: ", " }}{% endif %}
172
+ </p>
173
+ </div>
174
+ {% endfor %}
175
+ </section>
176
+ {% endif %}
177
+
178
+ <!-- Footer -->
179
+ <footer class="zen-footer zen-fade" role="contentinfo">
180
+ <div class="zen-footer-inner">
181
+ <p class="zen-footer-text">heyi.am</p>
182
+ </div>
183
+ </footer>
184
+
185
+ </main>
186
+
187
+ </div>
@@ -0,0 +1,203 @@
1
+ <div class="zen-session-page" data-render-version="2" data-template="zen">
2
+
3
+ <main class="zen-container">
4
+
5
+ <!-- Breadcrumb -->
6
+ {% if user.username != blank %}
7
+ <nav class="zen-breadcrumb zen-fade" aria-label="Breadcrumb">
8
+ <a href="/{{ user.username }}">{{ user.username }}</a>
9
+ {% if projectSlug != blank %}
10
+ <span class="zen-breadcrumb-sep" aria-hidden="true">/</span>
11
+ <a href="/{{ user.username }}/{{ projectSlug }}">{{ projectSlug }}</a>
12
+ {% endif %}
13
+ <span class="zen-breadcrumb-sep" aria-hidden="true">/</span>
14
+ <span aria-current="page">{{ session.title }}</span>
15
+ </nav>
16
+ {% endif %}
17
+
18
+ <!-- Section 1: Session Header -->
19
+ <section class="zen-section zen-fade" aria-label="Session header">
20
+ <h1 class="zen-display">{{ session.title }}</h1>
21
+ <div class="zen-session-header-meta">
22
+ <span class="zen-session-meta-row">{{ session.recordedAt | formatDate }}</span>
23
+ {% if session.sourceTool != blank %}
24
+ <span class="zen-session-meta-row"> &middot; {{ session.sourceTool }}</span>
25
+ {% endif %}
26
+ <span class="zen-session-meta-row"> &middot; {{ session.durationMinutes | formatDuration }}</span>
27
+ {% if session.wallClockMinutes %}
28
+ <span class="zen-session-meta-row"> ({{ session.wallClockMinutes | formatDuration }} wall clock)</span>
29
+ {% endif %}
30
+ <br>
31
+ <span class="zen-session-meta-row">{{ session.turns }} turns</span>
32
+ <span class="zen-session-meta-row"> &middot; {{ session.locChanged | localeNumber }} LOC</span>
33
+ <span class="zen-session-meta-row"> &middot; {{ session.filesChanged }} files changed</span>
34
+ </div>
35
+ </section>
36
+
37
+ <hr class="zen-rule zen-fade" aria-hidden="true">
38
+
39
+ <!-- Section 2: Dev Take -->
40
+ {% if session.devTake != blank %}
41
+ <section class="zen-section zen-fade" aria-label="Developer commentary">
42
+ <h2 class="zen-heading">Dev Take</h2>
43
+ <p class="zen-dev-take">
44
+ &ldquo;{{ session.devTake }}&rdquo;
45
+ </p>
46
+ </section>
47
+
48
+ <hr class="zen-rule zen-fade" aria-hidden="true">
49
+ {% endif %}
50
+
51
+ <!-- Context -->
52
+ {% if session.context != blank %}
53
+ <section class="zen-section zen-fade" aria-label="Session context">
54
+ <h2 class="zen-heading">Context</h2>
55
+ <p class="zen-body">{{ session.context }}</p>
56
+ </section>
57
+
58
+ <hr class="zen-rule zen-fade" aria-hidden="true">
59
+ {% endif %}
60
+
61
+ <!-- Narrative -->
62
+ {% if session.narrative != blank %}
63
+ <section class="zen-section zen-fade" aria-label="Session narrative">
64
+ <h2 class="zen-heading">Narrative</h2>
65
+ <p class="zen-body">{{ session.narrative }}</p>
66
+ </section>
67
+
68
+ <hr class="zen-rule zen-fade" aria-hidden="true">
69
+ {% endif %}
70
+
71
+ <!-- Highlights -->
72
+ {% if session.highlights.size > 0 %}
73
+ <section class="zen-section zen-fade" aria-label="Highlights">
74
+ <h2 class="zen-heading">Highlights</h2>
75
+ <ul class="zen-decisions" role="list">
76
+ {% for h in session.highlights %}
77
+ <li class="zen-decision-item">
78
+ <p class="zen-decision-text">{{ h }}</p>
79
+ </li>
80
+ {% endfor %}
81
+ </ul>
82
+ </section>
83
+
84
+ <hr class="zen-rule zen-fade" aria-hidden="true">
85
+ {% endif %}
86
+
87
+ <!-- Section 3: Execution Path / Beats -->
88
+ {% if session.beats.size > 0 %}
89
+ <section class="zen-section zen-fade" aria-label="Execution path">
90
+ <h2 class="zen-heading">Execution Path</h2>
91
+
92
+ {% for beat in session.beats %}
93
+ {% if forloop.index > 1 %}
94
+ <hr class="zen-beat-divider" aria-hidden="true">
95
+ {% endif %}
96
+ <div class="zen-beat zen-fade">
97
+ <p class="zen-beat-number">{% if forloop.index < 10 %}0{% endif %}{{ forloop.index }}</p>
98
+ <p class="zen-beat-title">{{ beat.title }}</p>
99
+ {% if beat.body != blank %}
100
+ <p class="zen-beat-desc">{{ beat.body }}</p>
101
+ {% endif %}
102
+ </div>
103
+ {% endfor %}
104
+ </section>
105
+
106
+ <hr class="zen-rule zen-fade" aria-hidden="true">
107
+ {% endif %}
108
+
109
+ <!-- Section 4: Q&A -->
110
+ {% if session.qaPairs.size > 0 %}
111
+ <section class="zen-section zen-fade" aria-label="Questions and answers">
112
+ <h2 class="zen-heading">Questions</h2>
113
+
114
+ {% for qa in session.qaPairs %}
115
+ {% if forloop.index > 1 %}
116
+ <hr class="zen-qa-divider" aria-hidden="true">
117
+ {% endif %}
118
+ <div class="zen-qa-item zen-fade">
119
+ <p class="zen-question">{{ qa.question }}</p>
120
+ <p class="zen-answer">{{ qa.answer }}</p>
121
+ </div>
122
+ {% endfor %}
123
+ </section>
124
+
125
+ <hr class="zen-rule zen-fade" aria-hidden="true">
126
+ {% endif %}
127
+
128
+ <!-- Section 5: Details -->
129
+ <section class="zen-section zen-fade" aria-label="Session details">
130
+ <h2 class="zen-heading">Details</h2>
131
+
132
+ <!-- Tools Used -->
133
+ {% if session.toolBreakdown.size > 0 %}
134
+ <div class="zen-details-group">
135
+ <p class="zen-details-label" id="tools-heading">Tools Used</p>
136
+ <div class="zen-tools" role="list" aria-labelledby="tools-heading">
137
+ {% for tool in session.toolBreakdown %}
138
+ <div class="zen-tool-row" role="listitem">
139
+ <span class="zen-tool-name">{{ tool.tool }}</span>
140
+ <span class="zen-tool-count">{{ tool.count }}</span>
141
+ </div>
142
+ {% endfor %}
143
+ </div>
144
+ </div>
145
+ {% endif %}
146
+
147
+ <!-- Files Changed -->
148
+ {% if session.topFiles.size > 0 %}
149
+ <div class="zen-details-group">
150
+ <p class="zen-details-label" id="files-heading">Files Changed</p>
151
+ <ul class="zen-files" role="list" aria-labelledby="files-heading">
152
+ {% for f in session.topFiles %}
153
+ <li class="zen-file-item">
154
+ <span class="zen-file-path">{{ f.path }}</span>
155
+ <span class="zen-file-diff">+{{ f.additions }}</span>
156
+ </li>
157
+ {% endfor %}
158
+ </ul>
159
+ </div>
160
+ {% endif %}
161
+
162
+ <!-- Skills -->
163
+ {% if session.skills.size > 0 %}
164
+ <div class="zen-details-group">
165
+ <p class="zen-details-label">Skills</p>
166
+ <p class="zen-skills-text">{{ session.skills | join: ", " }}</p>
167
+ </div>
168
+ {% endif %}
169
+ </section>
170
+
171
+ {% if session.agentSummary %}
172
+ <hr class="zen-rule zen-fade" aria-hidden="true">
173
+
174
+ <!-- Section 6: Agent Summary -->
175
+ <section class="zen-section zen-fade" aria-label="Agent summary">
176
+ <h2 class="zen-heading">Agents</h2>
177
+ {% if session.agentSummary.totalSubSessions %}
178
+ <p class="zen-agents-count">{{ session.agentSummary.totalSubSessions }} sub-sessions</p>
179
+ {% endif %}
180
+
181
+ {% if session.agentSummary.agents.size > 0 %}
182
+ <div role="list" aria-label="Agent roles and contributions">
183
+ {% for agent in session.agentSummary.agents %}
184
+ <div class="zen-agent-row" role="listitem">
185
+ <span class="zen-agent-role">{{ agent.role }}</span>
186
+ <span class="zen-agent-meta">{{ agent.duration_minutes | formatDuration }} &middot; {{ agent.loc_changed | localeNumber }} LOC</span>
187
+ </div>
188
+ {% endfor %}
189
+ </div>
190
+ {% endif %}
191
+ </section>
192
+ {% endif %}
193
+
194
+ <!-- Footer -->
195
+ <footer class="zen-footer zen-fade" role="contentinfo">
196
+ <div class="zen-footer-inner">
197
+ <p class="zen-footer-text">heyi.am</p>
198
+ </div>
199
+ </footer>
200
+
201
+ </main>
202
+
203
+ </div>