arcane-cli 1.8.1 → 1.9.0
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.js +54 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7735,6 +7735,33 @@ function renderShowReport(model, templateHtml) {
|
|
|
7735
7735
|
});
|
|
7736
7736
|
}
|
|
7737
7737
|
|
|
7738
|
+
// src/modules/show-report/theme.ts
|
|
7739
|
+
var REPORT_THEMES = ["auto", "light", "dark"];
|
|
7740
|
+
function radioTagPattern(id) {
|
|
7741
|
+
return new RegExp(`<input\\b[^>]*\\bid="arcane-report-theme-${id}"[^>]*?/?>`);
|
|
7742
|
+
}
|
|
7743
|
+
function withoutChecked(tag) {
|
|
7744
|
+
return tag.replace(/\s+checked(?:="[^"]*")?/, "");
|
|
7745
|
+
}
|
|
7746
|
+
function withChecked(tag) {
|
|
7747
|
+
return /\bchecked\b/.test(tag) ? tag : tag.replace(/(\/?>)$/, " checked$1");
|
|
7748
|
+
}
|
|
7749
|
+
function applyReportTheme(html, theme) {
|
|
7750
|
+
if (theme === "auto") return { html, applied: true };
|
|
7751
|
+
if (!radioTagPattern(theme).test(html)) return { html, applied: false };
|
|
7752
|
+
let result = html;
|
|
7753
|
+
for (const id of REPORT_THEMES) {
|
|
7754
|
+
const match = radioTagPattern(id).exec(result);
|
|
7755
|
+
if (!match) continue;
|
|
7756
|
+
const original = match[0];
|
|
7757
|
+
const replaced = id === theme ? withChecked(original) : withoutChecked(original);
|
|
7758
|
+
if (replaced !== original) {
|
|
7759
|
+
result = result.slice(0, match.index) + replaced + result.slice(match.index + original.length);
|
|
7760
|
+
}
|
|
7761
|
+
}
|
|
7762
|
+
return { html: result, applied: true };
|
|
7763
|
+
}
|
|
7764
|
+
|
|
7738
7765
|
// src/modules/show-report/generate.ts
|
|
7739
7766
|
var TEMPLATE_VERSION = "v0-interim";
|
|
7740
7767
|
var NO_EPICS_REASON = "no parseable `- [x] **ID \u2014 Title.**` epic bullets";
|
|
@@ -7801,7 +7828,7 @@ async function readOptionalFile(path4) {
|
|
|
7801
7828
|
throw error;
|
|
7802
7829
|
}
|
|
7803
7830
|
}
|
|
7804
|
-
async function generateReport(rootDir, program2, templateHtml) {
|
|
7831
|
+
async function generateReport(rootDir, program2, templateHtml, theme = "auto") {
|
|
7805
7832
|
const planContent = await readFile15(join18(rootDir, program2.planRelPath), "utf8");
|
|
7806
7833
|
const frontmatter = parseFrontmatter(planContent);
|
|
7807
7834
|
const model = await buildShowReportModel({
|
|
@@ -7813,19 +7840,24 @@ async function generateReport(rootDir, program2, templateHtml) {
|
|
|
7813
7840
|
compiledAt: deterministicCompiledAt(frontmatter),
|
|
7814
7841
|
templateVersion: TEMPLATE_VERSION
|
|
7815
7842
|
});
|
|
7843
|
+
const themed = applyReportTheme(renderShowReport(model, templateHtml), theme);
|
|
7816
7844
|
return {
|
|
7817
7845
|
json: `${JSON.stringify(model, null, 2)}
|
|
7818
7846
|
`,
|
|
7819
|
-
html:
|
|
7847
|
+
html: themed.html,
|
|
7848
|
+
themeApplied: themed.applied
|
|
7820
7849
|
};
|
|
7821
7850
|
}
|
|
7822
7851
|
async function runReportGeneration(options) {
|
|
7823
7852
|
const templateHtml = await readFile15(options.templatePath, "utf8");
|
|
7853
|
+
const theme = options.theme ?? "auto";
|
|
7824
7854
|
const drifted = [];
|
|
7825
7855
|
const repaired = [];
|
|
7826
7856
|
const unwritten = [];
|
|
7857
|
+
const themeSkipped = [];
|
|
7827
7858
|
for (const program2 of options.programs) {
|
|
7828
|
-
const generated = await generateReport(options.rootDir, program2, templateHtml);
|
|
7859
|
+
const generated = await generateReport(options.rootDir, program2, templateHtml, theme);
|
|
7860
|
+
if (!generated.themeApplied) themeSkipped.push(program2.slug);
|
|
7829
7861
|
const missing = JSON.parse(generated.json).sections.flatMap((section) => section.rows).filter((row) => row.descriptionState === "unwritten").map((row) => row.id);
|
|
7830
7862
|
if (missing.length > 0) unwritten.push({ slug: program2.slug, ids: missing });
|
|
7831
7863
|
const outAbs = options.outDir ? isAbsolute(options.outDir) ? options.outDir : resolve4(options.rootDir, options.outDir) : resolve4(options.rootDir, dirname10(program2.planRelPath));
|
|
@@ -7846,7 +7878,7 @@ async function runReportGeneration(options) {
|
|
|
7846
7878
|
}
|
|
7847
7879
|
}
|
|
7848
7880
|
}
|
|
7849
|
-
return { drifted, repaired, unwritten };
|
|
7881
|
+
return { drifted, repaired, unwritten, themeSkipped };
|
|
7850
7882
|
}
|
|
7851
7883
|
|
|
7852
7884
|
// src/commands/report.ts
|
|
@@ -7866,6 +7898,14 @@ async function runReport(targetDir, options = {}, assetsDir) {
|
|
|
7866
7898
|
"--refresh: external-data snapshotting (gh PR titles/merge dates) is not implemented yet; regenerating from local sources."
|
|
7867
7899
|
);
|
|
7868
7900
|
}
|
|
7901
|
+
const theme = options.theme ?? "auto";
|
|
7902
|
+
if (!REPORT_THEMES.includes(theme)) {
|
|
7903
|
+
console.error(
|
|
7904
|
+
`\u2716 arcane: --theme must be one of ${REPORT_THEMES.join(" | ")}, got "${options.theme}".`
|
|
7905
|
+
);
|
|
7906
|
+
process.exitCode = 1;
|
|
7907
|
+
return;
|
|
7908
|
+
}
|
|
7869
7909
|
if (await isShallowRepository(targetDir)) {
|
|
7870
7910
|
console.warn(
|
|
7871
7911
|
"\u26A0 arcane: shallow clone -- the report's version span and cast are derived from git history and will be omitted. Run `git fetch --unshallow` for a complete report."
|
|
@@ -7895,13 +7935,19 @@ async function runReport(targetDir, options = {}, assetsDir) {
|
|
|
7895
7935
|
templatePath,
|
|
7896
7936
|
mode: "write",
|
|
7897
7937
|
programs,
|
|
7898
|
-
outDir: options.out
|
|
7938
|
+
outDir: options.out,
|
|
7939
|
+
theme
|
|
7899
7940
|
});
|
|
7900
7941
|
for (const u of result.unwritten) {
|
|
7901
7942
|
console.warn(
|
|
7902
7943
|
`\u26A0 arcane: ${u.slug} has ${u.ids.length} epic(s) with no \`**Report:**\` line in PLAN.md -- they render as "unwritten": ${u.ids.join(", ")}.`
|
|
7903
7944
|
);
|
|
7904
7945
|
}
|
|
7946
|
+
for (const slug of result.themeSkipped) {
|
|
7947
|
+
console.warn(
|
|
7948
|
+
`\u26A0 arcane: ${slug} -- --theme ${theme} requested, but this template has no theme toggle to set (older vendored template?); left unchanged.`
|
|
7949
|
+
);
|
|
7950
|
+
}
|
|
7905
7951
|
if (result.repaired.length === 0) {
|
|
7906
7952
|
console.log(`Show report: ${programs.length} program(s) already up to date.`);
|
|
7907
7953
|
return;
|
|
@@ -8054,6 +8100,9 @@ program.command("report").description(
|
|
|
8054
8100
|
).option("--plan <path>", "Report on one PLAN.md instead of auto-discovering docs/plans/*/PLAN.md").option("--out <dir>", "Write show-report.{json,html} into this directory instead of next to the plan").option(
|
|
8055
8101
|
"--refresh",
|
|
8056
8102
|
"Accepted for forward compatibility; external-data snapshotting is not implemented yet, so this regenerates from local sources"
|
|
8103
|
+
).option(
|
|
8104
|
+
"--theme <mode>",
|
|
8105
|
+
"Force the in-page toggle's initial state: auto | light | dark (default auto, byte-for-byte unchanged). Pair with --out for a one-off themed copy so it doesn't overwrite the tracked show-report.html"
|
|
8057
8106
|
).action(async (opts) => {
|
|
8058
8107
|
await runReport(process.cwd(), opts, ASSETS_DIR);
|
|
8059
8108
|
});
|