@forwardimpact/landmark
Advanced tools
+16
-3
@@ -35,5 +35,9 @@ #!/usr/bin/env node | ||
| const VERSION = JSON.parse( | ||
| readFileSync(join(__dirname, "..", "package.json"), "utf8"), | ||
| ).version; | ||
| // `bun build --compile` injects FIT_LANDMARK_VERSION via --define, eliminating | ||
| // the readFileSync branch in the compiled binary (which would ENOENT against | ||
| // the bunfs virtual mount). Source execution falls through to package.json. | ||
| const VERSION = | ||
| process.env.FIT_LANDMARK_VERSION || | ||
| JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf8")) | ||
| .version; | ||
@@ -121,2 +125,7 @@ const COMMANDS = { | ||
| manager: { type: "string", description: "Filter by manager email" }, | ||
| verbose: { | ||
| type: "boolean", | ||
| description: | ||
| "Show every per-driver field including all percentile anchors", | ||
| }, | ||
| }, | ||
@@ -249,2 +258,6 @@ }, | ||
| if (result.meta && command === "health") { | ||
| result.meta.verbose = values.verbose === true; | ||
| } | ||
| const output = formatResult(command, result); | ||
@@ -251,0 +264,0 @@ process.stdout.write(output); |
+2
-2
| { | ||
| "name": "@forwardimpact/landmark", | ||
| "version": "0.1.12", | ||
| "version": "0.1.14", | ||
| "description": "Surface engineering progress from activity evidence — outcomes visible without singling out individuals.", | ||
@@ -73,3 +73,3 @@ "keywords": [ | ||
| "@forwardimpact/summit": "^0.1.0", | ||
| "@supabase/supabase-js": "^2.105.1" | ||
| "@supabase/supabase-js": "^2.105.3" | ||
| }, | ||
@@ -76,0 +76,0 @@ "devDependencies": { |
+222
-37
@@ -5,3 +5,8 @@ /** | ||
| import { formatDelta, ordinalSuffix, renderHeader } from "./shared.js"; | ||
| import { | ||
| formatDelta, | ||
| ordinalSuffix, | ||
| padRight, | ||
| renderHeader, | ||
| } from "./shared.js"; | ||
@@ -28,11 +33,101 @@ // --------------------------------------------------------------------------- | ||
| function formatCandidates(rec) { | ||
| return rec.candidates | ||
| .slice(0, 2) | ||
| .map((c) => `${c.name ?? c.email} (${c.currentLevel})`) | ||
| .join(" or "); | ||
| function recordDedupedCandidate(byKey, driver, rec, candidate) { | ||
| const key = `${candidate.email}::${rec.skill}`; | ||
| const existing = byKey.get(key); | ||
| if (existing) { | ||
| if (!existing.driverNames.includes(driver.name)) { | ||
| existing.driverNames.push(driver.name); | ||
| } | ||
| return; | ||
| } | ||
| byKey.set(key, { | ||
| candidate, | ||
| skill: rec.skill, | ||
| impact: rec.impact, | ||
| driverNames: [driver.name], | ||
| }); | ||
| } | ||
| /** | ||
| * Walk drivers → recommendations → candidates and emit one DedupedRec per | ||
| * (candidate.email, rec.skill). Later occurrences extend driverNames; impact | ||
| * is taken from the first occurrence. | ||
| * | ||
| * @param {Array} drivers | ||
| * @returns {Array<{candidate: object, skill: string, impact: string, | ||
| * driverNames: string[]}>} | ||
| */ | ||
| function dedupeRecommendations(drivers) { | ||
| const byKey = new Map(); | ||
| for (const driver of drivers) { | ||
| for (const rec of driver.recommendations ?? []) { | ||
| for (const candidate of rec.candidates ?? []) { | ||
| recordDedupedCandidate(byKey, driver, rec, candidate); | ||
| } | ||
| } | ||
| } | ||
| return [...byKey.values()]; | ||
| } | ||
| /** | ||
| * Count non-null hidden anchors (vs_prev, vs_50th, vs_75th, vs_90th). | ||
| * vs_org is the displayed anchor and is not counted. | ||
| * | ||
| * @param {object} driver | ||
| * @returns {number} | ||
| */ | ||
| function countHiddenAnchors(driver) { | ||
| let n = 0; | ||
| for (const key of ["vs_prev", "vs_50th", "vs_75th", "vs_90th"]) { | ||
| if (driver[key] != null) n += 1; | ||
| } | ||
| return n; | ||
| } | ||
| /** | ||
| * Default-mode "Percentile" cell — ordinal only (e.g. "42nd"), without the | ||
| * "percentile" word. The column header already labels the dimension. | ||
| * | ||
| * @param {object} driver | ||
| * @returns {string} | ||
| */ | ||
| function formatPercentileCell(driver) { | ||
| return driver.score != null | ||
| ? `${driver.score}${ordinalSuffix(driver.score)}` | ||
| : "n/a"; | ||
| } | ||
| /** | ||
| * Score cells for a driver row. Default mode returns the table tuple; verbose | ||
| * mode returns a list of formatted anchor lines for the per-driver paragraph. | ||
| * | ||
| * @param {object} driver | ||
| * @param {boolean} verbose | ||
| * @returns {{percentile: string, vsOrg: string, more: string} | string[]} | ||
| */ | ||
| function renderScoreCells(driver, verbose) { | ||
| if (verbose) { | ||
| const lines = []; | ||
| if (driver.vs_prev != null) | ||
| lines.push(`vs_prev: ${formatDelta(driver.vs_prev)}`); | ||
| if (driver.vs_org != null) | ||
| lines.push(`vs_org: ${formatDelta(driver.vs_org)}`); | ||
| if (driver.vs_50th != null) | ||
| lines.push(`vs_50th: ${formatDelta(driver.vs_50th)}`); | ||
| if (driver.vs_75th != null) | ||
| lines.push(`vs_75th: ${formatDelta(driver.vs_75th)}`); | ||
| if (driver.vs_90th != null) | ||
| lines.push(`vs_90th: ${formatDelta(driver.vs_90th)}`); | ||
| return lines; | ||
| } | ||
| const hidden = countHiddenAnchors(driver); | ||
| return { | ||
| percentile: formatPercentileCell(driver), | ||
| vsOrg: driver.vs_org != null ? formatDelta(driver.vs_org) : "n/a", | ||
| more: hidden > 0 ? `+${hidden} anchors via --verbose` : "-", | ||
| }; | ||
| } | ||
| // --------------------------------------------------------------------------- | ||
| // Text: per-driver section renderers | ||
| // Text: per-driver section renderers (verbose mode) | ||
| // --------------------------------------------------------------------------- | ||
@@ -48,9 +143,10 @@ | ||
| function renderTextRecommendations(driver, lines) { | ||
| if (!driver.recommendations || driver.recommendations.length === 0) return; | ||
| for (const rec of driver.recommendations) { | ||
| function renderTextRecommendations(driver, lines, deduped) { | ||
| const mine = deduped.filter((d) => d.driverNames[0] === driver.name); | ||
| if (mine.length === 0) return; | ||
| for (const rec of mine) { | ||
| lines.push(""); | ||
| lines.push( | ||
| ` ⮕ Recommendation: ${formatCandidates(rec)} could develop ${rec.skill}.`, | ||
| ); | ||
| const candidate = rec.candidate; | ||
| const phrase = `${candidate.name ?? candidate.email} (${candidate.currentLevel})`; | ||
| lines.push(` ⮕ Recommendation: ${phrase} could develop ${rec.skill}.`); | ||
| lines.push(` (Summit growth alignment: ${rec.impact})`); | ||
@@ -60,10 +156,8 @@ } | ||
| function renderTextDriver(driver, lines) { | ||
| const orgPart = | ||
| driver.vs_org != null ? `vs_org: ${formatDelta(driver.vs_org)}` : ""; | ||
| const scorePart = formatScorePart(driver); | ||
| lines.push( | ||
| ` Driver: ${driver.name} (${scorePart}${orgPart ? ", " + orgPart : ""})`, | ||
| ); | ||
| function renderTextDriver(driver, lines, deduped) { | ||
| const anchorLines = renderScoreCells(driver, true); | ||
| lines.push(` Driver: ${driver.name} (${formatScorePart(driver)})`); | ||
| if (anchorLines.length > 0) { | ||
| lines.push(` Anchors: ${anchorLines.join(", ")}`); | ||
| } | ||
| lines.push(` Contributing skills: ${formatSkillNames(driver)}`); | ||
@@ -73,3 +167,3 @@ lines.push(` Evidence: ${formatEvidenceParts(driver)}`); | ||
| renderTextComments(driver, lines); | ||
| renderTextRecommendations(driver, lines); | ||
| renderTextRecommendations(driver, lines, deduped); | ||
@@ -80,3 +174,3 @@ lines.push(""); | ||
| // --------------------------------------------------------------------------- | ||
| // Markdown: per-driver section renderers | ||
| // Markdown: per-driver section renderers (verbose mode) | ||
| // --------------------------------------------------------------------------- | ||
@@ -93,8 +187,11 @@ | ||
| function renderMdRecommendations(driver, lines) { | ||
| if (!driver.recommendations || driver.recommendations.length === 0) return; | ||
| function renderMdRecommendations(driver, lines, deduped) { | ||
| const mine = deduped.filter((d) => d.driverNames[0] === driver.name); | ||
| if (mine.length === 0) return; | ||
| lines.push(""); | ||
| for (const rec of driver.recommendations) { | ||
| for (const rec of mine) { | ||
| const candidate = rec.candidate; | ||
| const phrase = `**${candidate.name ?? candidate.email}** (${candidate.currentLevel})`; | ||
| lines.push( | ||
| `> **Recommendation:** ${formatCandidates(rec)} could develop ${rec.skill}. (${rec.impact})`, | ||
| `> **Recommendation:** ${phrase} could develop \`${rec.skill}\`. (${rec.impact})`, | ||
| ); | ||
@@ -104,5 +201,10 @@ } | ||
| function renderMdDriver(driver, lines) { | ||
| function renderMdDriver(driver, lines, deduped) { | ||
| lines.push(`## Driver: ${driver.name} (${formatScorePart(driver)})`); | ||
| lines.push(""); | ||
| const anchorLines = renderScoreCells(driver, true); | ||
| if (anchorLines.length > 0) { | ||
| lines.push(`**Anchors:** ${anchorLines.join(", ")}`); | ||
| lines.push(""); | ||
| } | ||
@@ -113,3 +215,3 @@ lines.push(`**Contributing skills:** ${formatSkillNames(driver)}`); | ||
| renderMdComments(driver, lines); | ||
| renderMdRecommendations(driver, lines); | ||
| renderMdRecommendations(driver, lines, deduped); | ||
@@ -120,10 +222,86 @@ lines.push(""); | ||
| // --------------------------------------------------------------------------- | ||
| // Default mode: compact table + Recommendations trailer | ||
| // --------------------------------------------------------------------------- | ||
| const TEXT_COLS = { num: 3, driver: 16, percentile: 12, vsOrg: 9 }; | ||
| function renderTextDefault(view, deduped, lines) { | ||
| lines.push(` Drivers (${view.drivers.length})`); | ||
| lines.push(" " + "─".repeat(60)); | ||
| lines.push( | ||
| " " + | ||
| padRight("#", TEXT_COLS.num) + | ||
| padRight("Driver", TEXT_COLS.driver) + | ||
| padRight("Percentile", TEXT_COLS.percentile) + | ||
| padRight("vs_org", TEXT_COLS.vsOrg) + | ||
| "More", | ||
| ); | ||
| view.drivers.forEach((driver, i) => { | ||
| const cells = renderScoreCells(driver, false); | ||
| lines.push( | ||
| " " + | ||
| padRight(String(i + 1), TEXT_COLS.num) + | ||
| padRight(driver.name, TEXT_COLS.driver) + | ||
| padRight(cells.percentile, TEXT_COLS.percentile) + | ||
| padRight(cells.vsOrg, TEXT_COLS.vsOrg) + | ||
| cells.more, | ||
| ); | ||
| }); | ||
| if (deduped.length === 0) return; | ||
| lines.push(""); | ||
| lines.push(` Recommendations (${deduped.length} unique)`); | ||
| lines.push(" " + "─".repeat(60)); | ||
| for (const rec of deduped) { | ||
| const name = rec.candidate.name ?? rec.candidate.email; | ||
| const drivers = rec.driverNames.join(", "); | ||
| lines.push( | ||
| ` - ${name} (${rec.candidate.currentLevel}) could develop ${rec.skill}` + | ||
| ` — for ${drivers} (${rec.impact})`, | ||
| ); | ||
| } | ||
| } | ||
| function renderMdDefault(view, deduped, lines) { | ||
| lines.push(`## Drivers (${view.drivers.length})`); | ||
| lines.push(""); | ||
| lines.push("| # | Driver | Percentile | vs_org | More |"); | ||
| lines.push("| --- | --- | --- | --- | --- |"); | ||
| view.drivers.forEach((driver, i) => { | ||
| const cells = renderScoreCells(driver, false); | ||
| const more = | ||
| cells.more === "-" ? "-" : cells.more.replace("--verbose", "`--verbose`"); | ||
| lines.push( | ||
| `| ${i + 1} | ${driver.name} | ${cells.percentile} | ${cells.vsOrg} | ${more} |`, | ||
| ); | ||
| }); | ||
| if (deduped.length === 0) return; | ||
| lines.push(""); | ||
| lines.push(`## Recommendations (${deduped.length} unique)`); | ||
| lines.push(""); | ||
| for (const rec of deduped) { | ||
| const name = rec.candidate.name ?? rec.candidate.email; | ||
| const drivers = rec.driverNames.join(", "); | ||
| lines.push( | ||
| `- **${name}** (${rec.candidate.currentLevel}) could develop \`${rec.skill}\`` + | ||
| ` — for ${drivers} (${rec.impact})`, | ||
| ); | ||
| } | ||
| } | ||
| // --------------------------------------------------------------------------- | ||
| // Public API | ||
| // --------------------------------------------------------------------------- | ||
| /** Render the health view as indented plain text with drivers, evidence, comments, and recommendations. */ | ||
| export function toText(view) { | ||
| /** Render the health view as indented plain text. Default mode emits a compact | ||
| * table plus a deduped Recommendations trailer; verbose mode emits the | ||
| * per-driver paragraph layout with all anchors disclosed. */ | ||
| export function toText(view, meta) { | ||
| const lines = [renderHeader(`${view.teamLabel} — health view`), ""]; | ||
| for (const driver of view.drivers) { | ||
| renderTextDriver(driver, lines); | ||
| const deduped = dedupeRecommendations(view.drivers); | ||
| if (meta?.verbose) { | ||
| for (const driver of view.drivers) { | ||
| renderTextDriver(driver, lines, deduped); | ||
| } | ||
| } else { | ||
| renderTextDefault(view, deduped, lines); | ||
| } | ||
@@ -138,9 +316,16 @@ return lines.join("\n"); | ||
| /** Render the health view as markdown with driver sections, comments, initiatives, and recommendations. */ | ||
| export function toMarkdown(view) { | ||
| /** Render the health view as markdown. Default mode emits a compact driver | ||
| * table plus a deduped Recommendations trailer; verbose mode emits the | ||
| * per-driver section layout with all anchors disclosed. */ | ||
| export function toMarkdown(view, meta) { | ||
| const lines = [`# ${view.teamLabel} — health view`, ""]; | ||
| for (const driver of view.drivers) { | ||
| renderMdDriver(driver, lines); | ||
| const deduped = dedupeRecommendations(view.drivers); | ||
| if (meta?.verbose) { | ||
| for (const driver of view.drivers) { | ||
| renderMdDriver(driver, lines, deduped); | ||
| } | ||
| } else { | ||
| renderMdDefault(view, deduped, lines); | ||
| } | ||
| return lines.join("\n"); | ||
| } |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
110003
6.5%2923
6.95%4
33.33%