@majeanson/lac 3.4.0 → 3.4.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.
- package/dist/index.mjs +41 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -10431,8 +10431,20 @@ body { background: var(--bg); color: var(--text); font-family: var(--sans); font
|
|
|
10431
10431
|
font-family: var(--mono);
|
|
10432
10432
|
font-size: 11px;
|
|
10433
10433
|
color: var(--text-soft);
|
|
10434
|
-
margin-bottom:
|
|
10434
|
+
margin-bottom: 12px;
|
|
10435
|
+
}
|
|
10436
|
+
.guide-link {
|
|
10437
|
+
display: inline-block;
|
|
10438
|
+
margin-bottom: 28px;
|
|
10439
|
+
font-family: var(--mono);
|
|
10440
|
+
font-size: 11px;
|
|
10441
|
+
color: var(--accent);
|
|
10442
|
+
text-decoration: none;
|
|
10443
|
+
border: 1px solid rgba(196,162,85,0.3);
|
|
10444
|
+
border-radius: 4px;
|
|
10445
|
+
padding: 3px 10px;
|
|
10435
10446
|
}
|
|
10447
|
+
.guide-link:hover { background: rgba(196,162,85,0.08); }
|
|
10436
10448
|
.completeness-bar {
|
|
10437
10449
|
display: inline-block;
|
|
10438
10450
|
width: 80px;
|
|
@@ -10891,7 +10903,8 @@ function renderFeature(key) {
|
|
|
10891
10903
|
\${f.domain ? \`<span class="badge badge-domain">\${esc(f.domain)}</span>\` : ''}
|
|
10892
10904
|
</div>\` : ''}
|
|
10893
10905
|
<div class="feature-title">\${esc(f.title)}</div>
|
|
10894
|
-
\${VIEW !== 'user' ? \`<div class="feature-completeness">\${barFill}\${pct}% complete</div>\` : ''}
|
|
10906
|
+
\${VIEW !== 'user' ? \`<div class="feature-completeness">\${barFill}\${pct}% complete</div>\` : ''}
|
|
10907
|
+
\${f.userGuide ? \`<a class="guide-link" href="./lac-guide.html#\${esc(f.featureKey)}" target="_self">📖 View User Guide →</a>\` : ''}\`;
|
|
10895
10908
|
|
|
10896
10909
|
// Problem
|
|
10897
10910
|
html += section(VIEW === 'user' ? 'About this feature' : 'Problem', f.problem ? \`<div class="section-body">\${md(f.problem)}</div>\` : '<span class="empty">Not documented.</span>');
|
|
@@ -21234,7 +21247,7 @@ body {
|
|
|
21234
21247
|
|
|
21235
21248
|
/* Feature pages */
|
|
21236
21249
|
.feature-page { max-width: 760px; margin: 0 auto; padding: 48px 40px 80px; }
|
|
21237
|
-
.feature-page.hidden { display: none; }
|
|
21250
|
+
.feature-page.hidden, .home-page.hidden { display: none; }
|
|
21238
21251
|
.feature-domain-eyebrow { font-family: var(--mono); font-size: 9px; letter-spacing: 0.18em; text-transform: uppercase; margin-bottom: 10px; }
|
|
21239
21252
|
.feature-title { font-size: 28px; font-weight: 800; color: var(--text); letter-spacing: -0.015em; line-height: 1.2; margin-bottom: 12px; }
|
|
21240
21253
|
.feature-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 28px; }
|
|
@@ -21355,9 +21368,21 @@ function showPage(id) {
|
|
|
21355
21368
|
const page = document.getElementById('page-' + id);
|
|
21356
21369
|
if (page) { page.classList.remove('hidden'); document.getElementById('content').scrollTop = 0; }
|
|
21357
21370
|
document.querySelectorAll('.nav-item').forEach(el => el.classList.toggle('active', el.dataset.id === id));
|
|
21371
|
+
var hash = '#' + id;
|
|
21372
|
+
if (window.location.hash !== hash) { history.replaceState(null, '', hash); }
|
|
21358
21373
|
}
|
|
21359
21374
|
// init
|
|
21360
21375
|
document.querySelectorAll('.feature-page').forEach(p => p.classList.add('hidden'));
|
|
21376
|
+
// Hash routing: navigate to feature on load if hash is present
|
|
21377
|
+
(function() {
|
|
21378
|
+
var hash = window.location.hash.slice(1);
|
|
21379
|
+
if (hash) { showPage(hash); }
|
|
21380
|
+
})();
|
|
21381
|
+
// Hash routing: respond to browser back/forward navigation
|
|
21382
|
+
window.addEventListener('hashchange', function() {
|
|
21383
|
+
var hash = window.location.hash.slice(1);
|
|
21384
|
+
showPage(hash || 'home');
|
|
21385
|
+
});
|
|
21361
21386
|
|
|
21362
21387
|
const gsearch = document.getElementById('gsearch');
|
|
21363
21388
|
const sresults = document.getElementById('sresults');
|
|
@@ -21479,10 +21504,14 @@ const ALL_HUB_ENTRIES = [
|
|
|
21479
21504
|
primary: false
|
|
21480
21505
|
}
|
|
21481
21506
|
];
|
|
21482
|
-
function generateHub(projectName, stats, entries, generatedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
21507
|
+
function generateHub(projectName, stats, entries, generatedAt = (/* @__PURE__ */ new Date()).toISOString(), prefix) {
|
|
21483
21508
|
function esc(s) {
|
|
21484
21509
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
21485
21510
|
}
|
|
21511
|
+
const urlPrefix = prefix ? "/" + (/[A-Za-z]:[/\\]/.test(prefix) ? prefix.split(/[/\\]/).filter(Boolean).pop() ?? "" : prefix.replace(/^\/+/, "").replace(/\/+$/, "")) : "";
|
|
21512
|
+
function href(file) {
|
|
21513
|
+
return urlPrefix ? `${urlPrefix}/${file}` : `./${file}`;
|
|
21514
|
+
}
|
|
21486
21515
|
const primaryEntries = entries.filter((e) => e.primary);
|
|
21487
21516
|
const secondaryEntries = entries.filter((e) => !e.primary);
|
|
21488
21517
|
const date = new Date(generatedAt).toLocaleDateString("en-US", {
|
|
@@ -21492,7 +21521,7 @@ function generateHub(projectName, stats, entries, generatedAt = (/* @__PURE__ */
|
|
|
21492
21521
|
});
|
|
21493
21522
|
function primaryCard(e) {
|
|
21494
21523
|
return `
|
|
21495
|
-
<a href="
|
|
21524
|
+
<a href="${esc(href(e.file))}" class="primary-card">
|
|
21496
21525
|
<div class="primary-card-icon">${e.icon}</div>
|
|
21497
21526
|
<div class="primary-card-body">
|
|
21498
21527
|
<div class="primary-card-label">${esc(e.label)}</div>
|
|
@@ -21503,7 +21532,7 @@ function generateHub(projectName, stats, entries, generatedAt = (/* @__PURE__ */
|
|
|
21503
21532
|
}
|
|
21504
21533
|
function secondaryCard(e) {
|
|
21505
21534
|
return `
|
|
21506
|
-
<a href="
|
|
21535
|
+
<a href="${esc(href(e.file))}" class="secondary-card">
|
|
21507
21536
|
<div class="secondary-card-icon">${e.icon}</div>
|
|
21508
21537
|
<div class="secondary-card-label">${esc(e.label)}</div>
|
|
21509
21538
|
<div class="secondary-card-desc">${esc(e.description)}</div>
|
|
@@ -21603,6 +21632,9 @@ body { background: var(--bg); color: var(--text); font-family: var(--sans); font
|
|
|
21603
21632
|
.footer-sep { font-family: var(--mono); font-size: 10px; color: var(--border); }
|
|
21604
21633
|
.footer-note { font-size: 11px; color: var(--text-soft); }
|
|
21605
21634
|
</style>
|
|
21635
|
+
${urlPrefix ? "" : `<script>
|
|
21636
|
+
function lacGo(file){location.href=location.href.replace(/[^\\/]*$/,'')+file}
|
|
21637
|
+
<\/script>`}
|
|
21606
21638
|
</head>
|
|
21607
21639
|
<body>
|
|
21608
21640
|
|
|
@@ -22034,7 +22066,7 @@ function buildReconstructionPrompt(features, projectName, promptDir) {
|
|
|
22034
22066
|
lines.push("");
|
|
22035
22067
|
return lines.join("\n");
|
|
22036
22068
|
}
|
|
22037
|
-
const exportCommand = new Command("export").description("Export feature.json as JSON, Markdown, or generate a static HTML view").option("--out <path>", "Output file or directory path").option("--html [dir]", "Scan <dir> (default: cwd) and emit a single self-contained HTML wiki").option("--raw [dir]", "Raw field-by-field HTML dump with sidebar navigation").option("--print [dir]", "Print-ready HTML document (A4, all features, @media print CSS)").option("--postcard", "Beautiful single-feature shareable card (nearest feature.json)").option("--resume [dir]", "Portfolio page from all frozen features").option("--slide [dir]", "Full-screen HTML slideshow, one slide per feature").option("--graph [dir]", "Interactive force-directed feature lineage graph").option("--heatmap [dir]", "Completeness heatmap — fields × features grid").option("--quiz [dir]", "Flashcard-style quiz to test knowledge of your feature set").option("--story [dir]", "Long-form narrative document — product case study from feature data").option("--treemap [dir]", "Rectangular treemap — features sized by decisions × completeness, grouped by domain").option("--kanban [dir]", "Kanban board — Active / Frozen / Draft columns with sortable, filterable cards").option("--health [dir]", "Project health scorecard — completeness, coverage, tech debt, and health score").option("--embed [dir]", "Compact embeddable stats widget (iframe-ready)").option("--decisions [dir]", "Consolidated ADR — all decisions from all features, searchable by domain").option("--guide [dir]", "User guide — one page per feature that has a non-empty userGuide field").option("--hub [dir]", "Hub landing page linking to all generated views → lac-hub.html").option("--all [dir]", "Generate all HTML views + hub index.html → --out dir (default: ./lac-output)").option("--diff <dir-b>", "Compare cwd workspace against <dir-b> and show added/removed/changed").option("--site <dir>", "Generate a multi-page static site → --out dir (default: ./lac-site)").option("--prompt [dir]", "AI reconstruction prompt for all features (stdout or --out file)").option("--markdown", "Single feature as Markdown (nearest feature.json)").option("--tags <tags>", "Comma-separated tags to filter by (OR logic) — applies to all multi-feature modes").option("--sort <mode>", "Sort order for multi-feature modes: key (default) | build-order (parents before children)").option("--view <name>", `Audience view — filters and shapes exported fields. One of: ${VIEW_NAMES.join(", ")}`).addHelpText("after", `
|
|
22069
|
+
const exportCommand = new Command("export").description("Export feature.json as JSON, Markdown, or generate a static HTML view").option("--out <path>", "Output file or directory path").option("--html [dir]", "Scan <dir> (default: cwd) and emit a single self-contained HTML wiki").option("--raw [dir]", "Raw field-by-field HTML dump with sidebar navigation").option("--print [dir]", "Print-ready HTML document (A4, all features, @media print CSS)").option("--postcard", "Beautiful single-feature shareable card (nearest feature.json)").option("--resume [dir]", "Portfolio page from all frozen features").option("--slide [dir]", "Full-screen HTML slideshow, one slide per feature").option("--graph [dir]", "Interactive force-directed feature lineage graph").option("--heatmap [dir]", "Completeness heatmap — fields × features grid").option("--quiz [dir]", "Flashcard-style quiz to test knowledge of your feature set").option("--story [dir]", "Long-form narrative document — product case study from feature data").option("--treemap [dir]", "Rectangular treemap — features sized by decisions × completeness, grouped by domain").option("--kanban [dir]", "Kanban board — Active / Frozen / Draft columns with sortable, filterable cards").option("--health [dir]", "Project health scorecard — completeness, coverage, tech debt, and health score").option("--embed [dir]", "Compact embeddable stats widget (iframe-ready)").option("--decisions [dir]", "Consolidated ADR — all decisions from all features, searchable by domain").option("--guide [dir]", "User guide — one page per feature that has a non-empty userGuide field").option("--hub [dir]", "Hub landing page linking to all generated views → lac-hub.html").option("--all [dir]", "Generate all HTML views + hub index.html → --out dir (default: ./lac-output)").option("--prefix <prefix>", "URL prefix for hub links (no leading slash), e.g. lac → hrefs become /lac/lac-guide.html").option("--diff <dir-b>", "Compare cwd workspace against <dir-b> and show added/removed/changed").option("--site <dir>", "Generate a multi-page static site → --out dir (default: ./lac-site)").option("--prompt [dir]", "AI reconstruction prompt for all features (stdout or --out file)").option("--markdown", "Single feature as Markdown (nearest feature.json)").option("--tags <tags>", "Comma-separated tags to filter by (OR logic) — applies to all multi-feature modes").option("--sort <mode>", "Sort order for multi-feature modes: key (default) | build-order (parents before children)").option("--view <name>", `Audience view — filters and shapes exported fields. One of: ${VIEW_NAMES.join(", ")}`).addHelpText("after", `
|
|
22038
22070
|
Examples:
|
|
22039
22071
|
lac export --html HTML wiki (cwd) → lac-wiki.html
|
|
22040
22072
|
lac export --raw Raw field dump → lac-raw.html
|
|
@@ -22445,7 +22477,7 @@ Views (--view):
|
|
|
22445
22477
|
deprecated: fs.filter((f) => f.status === "deprecated").length,
|
|
22446
22478
|
domains: [...new Set(fs.map((f) => f.domain).filter((d) => Boolean(d)))]
|
|
22447
22479
|
};
|
|
22448
|
-
const html = generateHub(basename(dir), stats, ALL_HUB_ENTRIES);
|
|
22480
|
+
const html = generateHub(basename(dir), stats, ALL_HUB_ENTRIES, (/* @__PURE__ */ new Date()).toISOString(), options.prefix);
|
|
22449
22481
|
const outFile = options.out ? resolve(options.out) : resolve(process$1.cwd(), "lac-hub.html");
|
|
22450
22482
|
try {
|
|
22451
22483
|
await writeFile(outFile, html, "utf-8");
|
|
@@ -22499,7 +22531,7 @@ Views (--view):
|
|
|
22499
22531
|
draft: fs.filter((f) => f.status === "draft").length,
|
|
22500
22532
|
deprecated: fs.filter((f) => f.status === "deprecated").length,
|
|
22501
22533
|
domains: [...new Set(fs.map((f) => f.domain).filter((d) => Boolean(d)))]
|
|
22502
|
-
}, ALL_HUB_ENTRIES));
|
|
22534
|
+
}, ALL_HUB_ENTRIES, (/* @__PURE__ */ new Date()).toISOString(), options.prefix));
|
|
22503
22535
|
process$1.stdout.write(`Done — ${features.length} features, 11 files written to ${outDir}\n`);
|
|
22504
22536
|
return;
|
|
22505
22537
|
}
|