heyiam 0.3.4 → 0.3.7
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.
- package/dist/export.js +19 -5
- package/dist/llm/project-enhance.js +11 -5
- package/dist/mount.js +9 -7
- package/dist/public/assets/{index-Cq04whgG.js → index-BDh4ne9u.js} +3 -3
- package/dist/public/assets/index-ByoBtx7P.css +1 -0
- package/dist/public/index.html +2 -2
- package/dist/render/build-render-data.js +1 -0
- package/dist/render/liquid.js +12 -2
- package/dist/render/mock-data.js +6 -0
- package/dist/render/select-profile-skills.js +54 -0
- package/dist/render/templates/aurora/portfolio.liquid +4 -4
- package/dist/render/templates/aurora/project.liquid +1 -1
- package/dist/render/templates/aurora/styles.css +6 -6
- package/dist/render/templates/bauhaus/portfolio.liquid +4 -4
- package/dist/render/templates/bauhaus/project.liquid +1 -1
- package/dist/render/templates/bauhaus/styles.css +1 -1
- package/dist/render/templates/blueprint/portfolio.liquid +4 -4
- package/dist/render/templates/blueprint/project.liquid +1 -1
- package/dist/render/templates/blueprint/styles.css +1 -1
- package/dist/render/templates/canvas/portfolio.liquid +4 -4
- package/dist/render/templates/canvas/project.liquid +1 -1
- package/dist/render/templates/canvas/styles.css +2 -2
- package/dist/render/templates/carbon/portfolio.liquid +4 -4
- package/dist/render/templates/carbon/project.liquid +1 -1
- package/dist/render/templates/carbon/styles.css +7 -7
- package/dist/render/templates/chalk/portfolio.liquid +4 -4
- package/dist/render/templates/chalk/project.liquid +1 -1
- package/dist/render/templates/chalk/styles.css +44 -2
- package/dist/render/templates/circuit/portfolio.liquid +4 -4
- package/dist/render/templates/circuit/project.liquid +1 -1
- package/dist/render/templates/cosmos/portfolio.liquid +4 -4
- package/dist/render/templates/cosmos/project.liquid +1 -1
- package/dist/render/templates/cosmos/styles.css +4 -4
- package/dist/render/templates/daylight/portfolio.liquid +4 -4
- package/dist/render/templates/daylight/project.liquid +1 -1
- package/dist/render/templates/editorial/portfolio.liquid +4 -4
- package/dist/render/templates/editorial/project.liquid +1 -1
- package/dist/render/templates/editorial/styles.css +6 -1
- package/dist/render/templates/ember/portfolio.liquid +4 -4
- package/dist/render/templates/ember/project.liquid +1 -1
- package/dist/render/templates/ember/styles.css +2 -2
- package/dist/render/templates/glacier/portfolio.liquid +4 -4
- package/dist/render/templates/glacier/project.liquid +1 -1
- package/dist/render/templates/glacier/styles.css +2 -2
- package/dist/render/templates/grid/portfolio.liquid +4 -4
- package/dist/render/templates/grid/project.liquid +1 -1
- package/dist/render/templates/grid/styles.css +2 -2
- package/dist/render/templates/kinetic/portfolio.liquid +5 -5
- package/dist/render/templates/kinetic/project.liquid +1 -1
- package/dist/render/templates/kinetic/styles.css +20 -14
- package/dist/render/templates/meridian/portfolio.liquid +4 -4
- package/dist/render/templates/meridian/project.liquid +1 -1
- package/dist/render/templates/meridian/styles.css +1 -1
- package/dist/render/templates/minimal/portfolio.liquid +3 -3
- package/dist/render/templates/minimal/project.liquid +1 -1
- package/dist/render/templates/mono/portfolio.liquid +4 -4
- package/dist/render/templates/mono/project.liquid +1 -1
- package/dist/render/templates/mono/styles.css +15 -1
- package/dist/render/templates/neon/portfolio.liquid +4 -4
- package/dist/render/templates/neon/project.liquid +1 -1
- package/dist/render/templates/neon/styles.css +11 -20
- package/dist/render/templates/noir/portfolio.liquid +4 -4
- package/dist/render/templates/noir/project.liquid +1 -1
- package/dist/render/templates/noir/styles.css +5 -5
- package/dist/render/templates/obsidian/portfolio.liquid +4 -4
- package/dist/render/templates/obsidian/project.liquid +1 -1
- package/dist/render/templates/obsidian/styles.css +2 -2
- package/dist/render/templates/paper/portfolio.liquid +4 -4
- package/dist/render/templates/paper/project.liquid +1 -1
- package/dist/render/templates/paper/styles.css +60 -1
- package/dist/render/templates/parallax/portfolio.liquid +4 -4
- package/dist/render/templates/parallax/project.liquid +1 -1
- package/dist/render/templates/parallax/styles.css +1 -1
- package/dist/render/templates/parchment/portfolio.liquid +4 -4
- package/dist/render/templates/parchment/project.liquid +1 -1
- package/dist/render/templates/parchment/styles.css +3 -3
- package/dist/render/templates/project.liquid +1 -1
- package/dist/render/templates/radar/portfolio.liquid +4 -4
- package/dist/render/templates/radar/project.liquid +1 -1
- package/dist/render/templates/radar/styles.css +4 -4
- package/dist/render/templates/showcase/portfolio.liquid +4 -4
- package/dist/render/templates/showcase/project.liquid +1 -1
- package/dist/render/templates/showcase/styles.css +7 -7
- package/dist/render/templates/signal/portfolio.liquid +4 -4
- package/dist/render/templates/signal/project.liquid +1 -1
- package/dist/render/templates/signal/styles.css +5 -5
- package/dist/render/templates/strata/portfolio.liquid +4 -4
- package/dist/render/templates/strata/project.liquid +1 -1
- package/dist/render/templates/strata/styles.css +3 -3
- package/dist/render/templates/styles.css +39 -28
- package/dist/render/templates/terminal/portfolio.liquid +2 -2
- package/dist/render/templates/terminal/project.liquid +1 -1
- package/dist/render/templates/verdant/portfolio.liquid +4 -4
- package/dist/render/templates/verdant/project.liquid +1 -1
- package/dist/render/templates/verdant/styles.css +17 -2
- package/dist/render/templates/zen/portfolio.liquid +4 -4
- package/dist/render/templates/zen/project.liquid +1 -1
- package/dist/render/templates/zen/styles.css +8 -8
- package/dist/routes/export.js +1 -0
- package/dist/routes/github.js +1 -1
- package/dist/routes/portfolio-render-data.js +17 -3
- package/dist/routes/preview.js +33 -3
- package/dist/routes/project-session-upload.js +4 -3
- package/dist/routes/publish.js +120 -17
- package/dist/settings.js +14 -1
- package/package.json +1 -1
- package/dist/public/assets/index-CMyamplX.css +0 -1
package/dist/export.js
CHANGED
|
@@ -42,8 +42,10 @@ function resolveScreenshotDataUri(dirName, cache) {
|
|
|
42
42
|
return b64;
|
|
43
43
|
return `data:image/png;base64,${b64}`;
|
|
44
44
|
}
|
|
45
|
-
// Try local screenshot file
|
|
46
|
-
|
|
45
|
+
// Try local screenshot file. Screenshots are keyed by the clean slug that
|
|
46
|
+
// the publish flow uses (toSlug(displayNameFromDir(dirName))), not the raw
|
|
47
|
+
// encoded path.
|
|
48
|
+
const slug = toSlug(displayNameFromDir(dirName));
|
|
47
49
|
const screenshotPath = join(SCREENSHOTS_DIR, `${slug}.png`);
|
|
48
50
|
if (existsSync(screenshotPath)) {
|
|
49
51
|
const buf = readFileSync(screenshotPath);
|
|
@@ -207,8 +209,12 @@ export async function exportHtml(dirName, cache, sessions, outputPath, username
|
|
|
207
209
|
let totalBytes = 0;
|
|
208
210
|
mkdirSync(outputPath, { recursive: true });
|
|
209
211
|
const { result } = cache;
|
|
210
|
-
|
|
212
|
+
// dirName is Claude Code's encoded full path (e.g. `-Users-ben-Dev-agent-sync`).
|
|
213
|
+
// The Phoenix-side slug comes from `toSlug(displayNameFromDir(dirName))`, so
|
|
214
|
+
// match that here — otherwise anchor hrefs and zip folder names keep the
|
|
215
|
+
// entire encoded path.
|
|
211
216
|
const title = opts?.title ?? cache.title ?? displayNameFromDir(dirName);
|
|
217
|
+
const slug = slugify(displayNameFromDir(dirName));
|
|
212
218
|
// Use ALL sessions (same as dashboard), build cards for each
|
|
213
219
|
const sessionCards = sessions.map((session) => {
|
|
214
220
|
return buildSessionCard({
|
|
@@ -259,6 +265,7 @@ export async function exportHtml(dirName, cache, sessions, outputPath, username
|
|
|
259
265
|
totalTokens,
|
|
260
266
|
sessionCards,
|
|
261
267
|
sessionBaseUrl: './sessions',
|
|
268
|
+
sessionSuffix: '.html',
|
|
262
269
|
});
|
|
263
270
|
const templateName = resolveTemplate(undefined, getDefaultTemplate());
|
|
264
271
|
const projectBody = renderProjectHtml(projectRenderData, {
|
|
@@ -311,8 +318,12 @@ function getInlineCss() {
|
|
|
311
318
|
// ── Shared render helpers ─────────────────────────────────────
|
|
312
319
|
function buildProjectRenderInputs(dirName, cache, sessions, username, opts) {
|
|
313
320
|
const { result } = cache;
|
|
314
|
-
|
|
321
|
+
// dirName is Claude Code's encoded full path (e.g. `-Users-ben-Dev-agent-sync`).
|
|
322
|
+
// The Phoenix-side slug comes from `toSlug(displayNameFromDir(dirName))`, so
|
|
323
|
+
// match that here — otherwise anchor hrefs and zip folder names keep the
|
|
324
|
+
// entire encoded path.
|
|
315
325
|
const title = opts?.title ?? cache.title ?? displayNameFromDir(dirName);
|
|
326
|
+
const slug = slugify(displayNameFromDir(dirName));
|
|
316
327
|
const sessionCards = sessions.map((session) => buildSessionCard({
|
|
317
328
|
sessionId: session.id,
|
|
318
329
|
session,
|
|
@@ -356,6 +367,8 @@ export function generateProjectHtmlFragment(dirName, cache, sessions, username =
|
|
|
356
367
|
totalSessions: sessions.length,
|
|
357
368
|
totalLoc, totalDurationMinutes, totalAgentDurationMinutes, totalFilesChanged, totalTokens,
|
|
358
369
|
sessionCards,
|
|
370
|
+
sessionBaseUrl: `/${username}/${slug}`,
|
|
371
|
+
sessionSuffix: '',
|
|
359
372
|
});
|
|
360
373
|
const templateName = resolveTemplate(undefined, getDefaultTemplate());
|
|
361
374
|
return renderProjectHtml(renderData, {
|
|
@@ -380,6 +393,7 @@ export function generateHtmlFiles(dirName, cache, sessions, username = 'local',
|
|
|
380
393
|
totalLoc, totalDurationMinutes, totalAgentDurationMinutes, totalFilesChanged, totalTokens,
|
|
381
394
|
sessionCards,
|
|
382
395
|
sessionBaseUrl: './sessions',
|
|
396
|
+
sessionSuffix: '.html',
|
|
383
397
|
});
|
|
384
398
|
const projectBody = renderProjectHtml(projectRenderData, {
|
|
385
399
|
arc: result.arc,
|
|
@@ -633,7 +647,7 @@ export async function generatePortfolioSite(portfolioData, projects, outputDir,
|
|
|
633
647
|
const projectsRoot = join(outputDir, 'projects');
|
|
634
648
|
mkdirSync(projectsRoot, { recursive: true });
|
|
635
649
|
for (const p of projects) {
|
|
636
|
-
const projectSlug = slugify(p.dirName);
|
|
650
|
+
const projectSlug = slugify(displayNameFromDir(p.dirName));
|
|
637
651
|
const projectDir = join(projectsRoot, projectSlug);
|
|
638
652
|
const result = await exportHtml(p.dirName, p.cache, p.sessions, projectDir, username, p.opts);
|
|
639
653
|
files.push(...result.files);
|
|
@@ -4,11 +4,12 @@ import { getAnthropicApiKey } from '../settings.js';
|
|
|
4
4
|
const PROJECT_ENHANCE_SYSTEM = `You are building a project narrative from multiple coding sessions for a developer portfolio on heyi.am.
|
|
5
5
|
|
|
6
6
|
Your job:
|
|
7
|
-
1.
|
|
8
|
-
2.
|
|
9
|
-
3.
|
|
10
|
-
4.
|
|
11
|
-
5.
|
|
7
|
+
1. Write a tagline: 1-2 sentences, first-person, starting with "I built". State what the thing IS and the one thing that makes it interesting. Example voice: "I built a better NVR system that's simple and intuitive." / "I built a proof of work for the AI space." Not a pitch, not marketing — how a developer describes what they made when asked at a bar. No fluff words (leverage, robust, comprehensive, cutting-edge, seamless, innovative). If you can't name what it IS in concrete terms, the tagline is wrong.
|
|
8
|
+
2. Synthesize a 2-3 sentence project description that captures what was built and why it matters. Write in third person about the project, not the developer. No fluff — every word earns its place.
|
|
9
|
+
3. Identify 4-7 project phases (the "arc") that show how the project evolved. Each phase should have a short title and one-sentence description.
|
|
10
|
+
4. Deduplicate and rank skills across all sessions.
|
|
11
|
+
5. Group sessions into timeline periods (e.g., "Week 1", "Days 1-3") with labels describing what happened in each period. Mark featured sessions (the most interesting ones) vs background sessions.
|
|
12
|
+
6. Generate 2-3 context-aware questions based on patterns you detect in the sessions (see instructions below).
|
|
12
13
|
|
|
13
14
|
For questions, look for these signals and generate questions that reference specific data:
|
|
14
15
|
- High correction counts → ask about override strategy, referencing the count
|
|
@@ -24,6 +25,7 @@ Each question must have:
|
|
|
24
25
|
|
|
25
26
|
Return valid JSON matching this exact structure:
|
|
26
27
|
{
|
|
28
|
+
"tagline": "I built a ... — 1-2 sentences, first-person, concrete, no fluff",
|
|
27
29
|
"narrative": "2-3 sentence project description",
|
|
28
30
|
"arc": [{ "phase": 1, "title": "...", "description": "..." }],
|
|
29
31
|
"skills": ["skill1", "skill2"],
|
|
@@ -183,6 +185,10 @@ export async function enhanceProject(sessions, skippedSessions, onProgress) {
|
|
|
183
185
|
if (!result.narrative || !Array.isArray(result.arc) || !Array.isArray(result.skills)) {
|
|
184
186
|
throw new Error('LLM returned incomplete project enhance result');
|
|
185
187
|
}
|
|
188
|
+
// Tagline is new; tolerate legacy cache entries by defaulting to empty string.
|
|
189
|
+
if (typeof result.tagline !== 'string') {
|
|
190
|
+
result.tagline = '';
|
|
191
|
+
}
|
|
186
192
|
// Ensure questions have IDs
|
|
187
193
|
if (result.questions) {
|
|
188
194
|
result.questions = result.questions.map((q, i) => ({
|
package/dist/mount.js
CHANGED
|
@@ -21961,7 +21961,7 @@
|
|
|
21961
21961
|
count
|
|
21962
21962
|
}));
|
|
21963
21963
|
}
|
|
21964
|
-
function buildLegendEntries(
|
|
21964
|
+
function buildLegendEntries(sessionRanges) {
|
|
21965
21965
|
return sessionRanges.map((r) => {
|
|
21966
21966
|
const kids = getChildren(r.session);
|
|
21967
21967
|
return {
|
|
@@ -22297,7 +22297,7 @@
|
|
|
22297
22297
|
const concurrentLimit = expanded ? 999 : DEFAULT_MAX_CONCURRENT;
|
|
22298
22298
|
const themeColors = (0, import_react.useMemo)(() => ({ main: mainColor, muted: textMuted }), [mainColor, textMuted]);
|
|
22299
22299
|
const L = (0, import_react.useMemo)(() => layoutSegments(segments, concurrentLimit, themeColors), [segments, concurrentLimit, themeColors]);
|
|
22300
|
-
const legendEntries = (0, import_react.useMemo)(() => buildLegendEntries(
|
|
22300
|
+
const legendEntries = (0, import_react.useMemo)(() => buildLegendEntries(L.sessionRanges), [L.sessionRanges]);
|
|
22301
22301
|
const scrollRef = (0, import_react.useRef)(null);
|
|
22302
22302
|
const [hovered, setHovered] = (0, import_react.useState)(null);
|
|
22303
22303
|
const [focusedEntry, setFocusedEntry] = (0, import_react.useState)(null);
|
|
@@ -23135,22 +23135,24 @@
|
|
|
23135
23135
|
}
|
|
23136
23136
|
var allSessions = /* @__PURE__ */ new Map();
|
|
23137
23137
|
var showOverlay = null;
|
|
23138
|
-
function OverlayRoot(
|
|
23138
|
+
function OverlayRoot() {
|
|
23139
23139
|
const [active, setActive] = (0, import_react3.useState)(null);
|
|
23140
23140
|
showOverlay = (session) => setActive(session);
|
|
23141
23141
|
if (!active) return null;
|
|
23142
23142
|
const projectEl = document.querySelector(".heyiam-project");
|
|
23143
23143
|
const baseUrl = projectEl?.getAttribute("data-session-base-url");
|
|
23144
|
+
const suffix = projectEl?.getAttribute("data-session-suffix") ?? "";
|
|
23144
23145
|
let sessionPageUrl;
|
|
23145
23146
|
if (baseUrl) {
|
|
23146
|
-
const
|
|
23147
|
-
|
|
23147
|
+
const fromTitle = active.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 80) || "untitled";
|
|
23148
|
+
const sessionSlug = active.slug ?? fromTitle;
|
|
23149
|
+
sessionPageUrl = `${baseUrl}/${sessionSlug}${suffix}`;
|
|
23148
23150
|
} else {
|
|
23149
23151
|
const username = projectEl?.getAttribute("data-username");
|
|
23150
23152
|
const projectSlug = projectEl?.getAttribute("data-project-slug");
|
|
23151
23153
|
const sessionSlug = active.slug;
|
|
23152
23154
|
if (username && projectSlug && sessionSlug) {
|
|
23153
|
-
sessionPageUrl =
|
|
23155
|
+
sessionPageUrl = `/${username}/${projectSlug}/${sessionSlug}`;
|
|
23154
23156
|
}
|
|
23155
23157
|
}
|
|
23156
23158
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -23219,7 +23221,7 @@
|
|
|
23219
23221
|
overlayEl.id = "heyiam-overlay-root";
|
|
23220
23222
|
document.body.appendChild(overlayEl);
|
|
23221
23223
|
(0, import_client.createRoot)(overlayEl).render(
|
|
23222
|
-
import_react3.default.createElement(OverlayRoot
|
|
23224
|
+
import_react3.default.createElement(OverlayRoot)
|
|
23223
23225
|
);
|
|
23224
23226
|
}
|
|
23225
23227
|
}
|