Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion scripts/export-client-delivery-cockpit.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { localIsoDate } from "./date-utils.mjs";
import { codeRoot, serviceRoot } from "./lib/runtime-roots.mjs";
import { resolveRepoPath } from "./lib/service-contract.mjs";
import { loadValidatedServiceClient } from "./lib/validated-service-client.mjs";
import { handleHelp, resolveOutputPath } from "./lib/operator-cli.mjs";

const args = process.argv.slice(2);
handleHelp(args, `Usage: npm run client:cockpit -- clients/client-slug [--output=clients/client-slug/delivery-cockpit.html]`);
const clientPath = args[0];
const outputArg = args.find((arg) => arg.startsWith("--output="));
const repoRoot = serviceRoot;
Expand All @@ -30,7 +32,7 @@ if (!existsSync(resolvedClientPath)) {
process.exit(1);
}

const outputPath = outputArg ? resolveRepoPath(repoRoot, outputArg.split("=")[1]) : join(resolvedClientPath, "delivery-cockpit.html");
const outputPath = outputArg ? resolveOutputPath(outputArg.split("=")[1]) : join(resolvedClientPath, "delivery-cockpit.html");

function read(relativePath) {
const path = resolveRepoPath(repoRoot, join(resolvedClientPath, relativePath));
Expand Down
10 changes: 6 additions & 4 deletions scripts/export-daily-money-mission.mjs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
#!/usr/bin/env node
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { dirname, join } from "node:path";
import { execFileSync } from "node:child_process";
import { localIsoDate } from "./date-utils.mjs";
import { isValidLoomUrl } from "./lib/loom-url.mjs";
import { sendChannelGuidance } from "./lib/send-channel-guidance.mjs";
import { routedContactPlan } from "./lib/contact-route.mjs";
import { canonicalProspectAsk } from "./lib/canonical-service-copy.mjs";
import { NO_GUARANTEE_CLIENT_SENTENCE } from "./lib/service-contract.mjs";
import { handleHelp, resolveOutputPath } from "./lib/operator-cli.mjs";

handleHelp(process.argv.slice(2), `Usage: npm run growth:mission -- [--limit=N] [--output=runs/daily-money-mission.md] [--html=runs/daily-money-mission.html]`);
const limitArg = process.argv.find((arg) => arg.startsWith("--limit="));
const limit = limitArg ? Number(limitArg.split("=")[1]) : 5;
const outputArg = process.argv.find((arg) => arg.startsWith("--output="));
const outputPath = outputArg ? outputArg.split("=")[1] : "runs/daily-money-mission.md";
const outputPath = resolveOutputPath(outputArg?.split("=")[1], { fallback: "runs/daily-money-mission.md" });
const htmlArg = process.argv.find((arg) => arg.startsWith("--html="));
const htmlPath = htmlArg ? htmlArg.split("=")[1] : "runs/daily-money-mission.html";
const htmlPath = resolveOutputPath(htmlArg?.split("=")[1], { flag: "--html", fallback: "runs/daily-money-mission.html" });
const today = localIsoDate();

function runJson(args) {
Expand Down Expand Up @@ -160,7 +162,7 @@ function missionFromMetrics(counts) {
}

function write(path, content) {
const dir = path.split("/").slice(0, -1).join("/");
const dir = dirname(path);
if (dir) mkdirSync(dir, { recursive: true });
writeFileSync(path, `${String(content).replace(/[ \t]+$/gm, "").trimEnd()}\n`);
}
Expand Down
8 changes: 5 additions & 3 deletions scripts/export-followup-cockpit.mjs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
#!/usr/bin/env node
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { dirname, join } from "node:path";
import { listOutboundProspectFolders } from "./lib/outbound-prospects.mjs";
import { execFileSync } from "node:child_process";
import { localIsoDate } from "./date-utils.mjs";
import { sendChannelGuidance } from "./lib/send-channel-guidance.mjs";
import { handleHelp, resolveOutputPath } from "./lib/operator-cli.mjs";

handleHelp(process.argv.slice(2), `Usage: npm run prospect:followups -- [--limit=N] [--date=YYYY-MM-DD] [--output=prospects/followup-cockpit.html]`);
const limitArg = process.argv.find((arg) => arg.startsWith("--limit="));
const limit = limitArg ? Number(limitArg.split("=")[1]) : 10;
const outputArg = process.argv.find((arg) => arg.startsWith("--output="));
const outputPath = outputArg ? outputArg.split("=")[1] : "prospects/followup-cockpit.html";
const outputPath = resolveOutputPath(outputArg?.split("=")[1], { fallback: "prospects/followup-cockpit.html" });
const dateArg = process.argv.find((arg) => arg.startsWith("--date="));
const today = dateArg ? dateArg.split("=")[1] : localIsoDate();

Expand Down Expand Up @@ -403,7 +405,7 @@ const html = `<!doctype html>
</html>
`;

const outputDir = outputPath.split("/").slice(0, -1).join("/");
const outputDir = dirname(outputPath);
if (outputDir) mkdirSync(outputDir, { recursive: true });
writeFileSync(outputPath, html);

Expand Down
10 changes: 7 additions & 3 deletions scripts/export-growth-cockpit.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
#!/usr/bin/env node
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname } from "node:path";
import { execFileSync } from "node:child_process";
import { localIsoDate } from "./date-utils.mjs";
import { handleHelp, resolveOutputPath } from "./lib/operator-cli.mjs";

const outputArg = process.argv.find((arg) => arg.startsWith("--output="));
const outputPath = outputArg ? outputArg.split("=")[1] : "runs/growth-cockpit.html";
const args = process.argv.slice(2);
handleHelp(args, `Usage: npm run growth:cockpit -- [--output=runs/growth-cockpit.html]`);
const outputArg = args.find((arg) => arg.startsWith("--output="));
const outputPath = resolveOutputPath(outputArg?.split("=")[1], { fallback: "runs/growth-cockpit.html" });
const today = localIsoDate();

function runJson(args) {
Expand Down Expand Up @@ -241,7 +245,7 @@ const html = `<!doctype html>
</html>
`;

const outputDir = outputPath.split("/").slice(0, -1).join("/");
const outputDir = dirname(outputPath);
if (outputDir) mkdirSync(outputDir, { recursive: true });
writeFileSync(outputPath, `${html.replace(/[ \t]+$/gm, "").trimEnd()}\n`);

Expand Down
8 changes: 5 additions & 3 deletions scripts/export-growth-doctor.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
#!/usr/bin/env node
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { dirname, join } from "node:path";
import { localIsoDate } from "./date-utils.mjs";
import { checkProspectReadiness, prospectWarningWeight } from "./lib/prospect-readiness.mjs";
import { listOutboundProspectFolders } from "./lib/outbound-prospects.mjs";
import { runRepoJson as runJson } from "./lib/runtime-roots.mjs";
import { handleHelp, resolveOutputPath } from "./lib/operator-cli.mjs";

handleHelp(process.argv.slice(2), `Usage: npm run growth:doctor -- [--no-checks] [--plain] [--output=runs/growth-doctor.md]`);
const outputArg = process.argv.find((arg) => arg.startsWith("--output="));
const outputPath = outputArg ? outputArg.split("=")[1] : "runs/growth-doctor.md";
const outputPath = resolveOutputPath(outputArg?.split("=")[1], { fallback: "runs/growth-doctor.md" });
const skipChecks = process.argv.includes("--no-checks");
const plain = process.argv.includes("--plain");
const today = localIsoDate();
Expand Down Expand Up @@ -233,7 +235,7 @@ ${focusRows || "- No active focus items."}
Do not build more system surface until the current bottleneck is worked.
`;

const outputDir = outputPath.split("/").slice(0, -1).join("/");
const outputDir = dirname(outputPath);
if (outputDir) mkdirSync(outputDir, { recursive: true });
writeFileSync(outputPath, markdown);

Expand Down
8 changes: 5 additions & 3 deletions scripts/export-growth-metrics.mjs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
#!/usr/bin/env node
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { dirname, join } from "node:path";
import { localIsoDate } from "./date-utils.mjs";
import { checkProspectReadiness } from "./lib/prospect-readiness.mjs";
import { isValidLoomUrl } from "./lib/loom-url.mjs";
import { loadValidatedServiceClients } from "./lib/validated-service-client.mjs";
import { listOutboundProspectFolders } from "./lib/outbound-prospects.mjs";
import { runRepoJson } from "./lib/runtime-roots.mjs";
import { handleHelp, resolveOutputPath } from "./lib/operator-cli.mjs";

handleHelp(process.argv.slice(2), `Usage: npm run growth:metrics -- [--plain] [--output=growth-brain/ops/live-metrics.md]`);
const outputArg = process.argv.find((arg) => arg.startsWith("--output="));
const outputPath = outputArg ? outputArg.split("=")[1] : "growth-brain/ops/live-metrics.md";
const outputPath = resolveOutputPath(outputArg?.split("=")[1], { fallback: "growth-brain/ops/live-metrics.md" });
const plain = process.argv.includes("--plain");
const today = localIsoDate();
const repoRoot = process.env.SERVICE_REPO_ROOT || process.cwd();
Expand Down Expand Up @@ -182,7 +184,7 @@ ${Object.entries(stageCounts).sort(([a], [b]) => a.localeCompare(b)).map(([stage
- If calls are high and closed is low, improve scope, price, or proof.
`;

const outputDir = outputPath.split("/").slice(0, -1).join("/");
const outputDir = dirname(outputPath);
if (outputDir) mkdirSync(outputDir, { recursive: true });
writeFileSync(outputPath, markdown);

Expand Down
24 changes: 16 additions & 8 deletions scripts/export-internal-dashboard.mjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
#!/usr/bin/env node
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join, resolve } from "node:path";
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { localIsoDate } from "./date-utils.mjs";
import { sendChannelGuidance } from "./lib/send-channel-guidance.mjs";
import { listOutboundProspectFolders } from "./lib/outbound-prospects.mjs";
import { codeRoot, runRepoJson as runJson, serviceRoot } from "./lib/runtime-roots.mjs";
import { handleHelp, resolveOutputPath } from "./lib/operator-cli.mjs";

handleHelp(process.argv.slice(2), `Usage: npm run growth:dashboard -- [--plain] [--output=runs/internal-dashboard.md] [--html=runs/internal-dashboard.html]`);
const outputArg = process.argv.find((arg) => arg.startsWith("--output="));
const htmlArg = process.argv.find((arg) => arg.startsWith("--html="));
const plain = process.argv.includes("--plain");
const today = localIsoDate();
const outputPath = outputArg ? outputArg.split("=")[1] : "runs/internal-dashboard.md";
const htmlPath = htmlArg ? htmlArg.split("=")[1] : "runs/internal-dashboard.html";
const outputPath = resolveOutputPath(outputArg?.split("=")[1], { fallback: "runs/internal-dashboard.md" });
const htmlPath = resolveOutputPath(htmlArg?.split("=")[1], { flag: "--html", fallback: "runs/internal-dashboard.html" });

function htmlEscape(value) {
return String(value ?? "")
Expand All @@ -32,7 +34,7 @@ function pill(status) {
}

function write(path, content) {
const dir = path.split("/").slice(0, -1).join("/");
const dir = dirname(path);
if (dir) mkdirSync(dir, { recursive: true });
writeFileSync(path, content);
}
Expand All @@ -54,7 +56,13 @@ catch (error) {
const output = String(error.stderr || error.message || "");
serviceQueue = { items: [], counts: { blocked: 1 }, error: output.match(/service:queue failed:[^\n]*/)?.[0] || "service queue validation failed" };
}
const parity = runJson(["scripts/check-market-parity-readiness.mjs", "--skip-kit", "--output=/tmp/tinystudio-internal-dashboard-parity.md"]);
const parityScratchPath = `runs/.internal-dashboard-parity-${process.pid}.md`;
let parity;
try {
parity = runJson(["scripts/check-market-parity-readiness.mjs", "--skip-kit", `--output=${parityScratchPath}`]);
} finally {
rmSync(join(serviceRoot, parityScratchPath), { force: true });
}
const todayView = runJson(["scripts/show-growth-command-center.mjs", "--limit=12"]);
const marketProof = existsSync(join(serviceRoot, "prospects/loom-links.txt"))
? runJson(["scripts/export-market-proof-cockpit.mjs"])
Expand Down Expand Up @@ -482,8 +490,8 @@ const html = `<!doctype html>
</html>
`;

write(resolve(serviceRoot, outputPath), markdown);
write(resolve(serviceRoot, htmlPath), html);
write(outputPath, markdown);
write(htmlPath, html);

const result = {
status: doctor.status === "blocked" || parity.status === "not-11-10-yet" || serviceQueueBlocked > 0 || clientIntegrityBlocked > 0 ? "attention-needed" : "ready",
Expand Down
8 changes: 5 additions & 3 deletions scripts/export-lead-scoring-cockpit.mjs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#!/usr/bin/env node
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { dirname, join } from "node:path";
import { listOutboundProspectFolders } from "./lib/outbound-prospects.mjs";
import { handleHelp, resolveOutputPath } from "./lib/operator-cli.mjs";

handleHelp(process.argv.slice(2), `Usage: npm run prospect:score-cockpit -- [--limit=N] [--output=prospects/lead-scoring-cockpit.html]`);
const limitArg = process.argv.find((arg) => arg.startsWith("--limit="));
const limit = limitArg ? Number(limitArg.split("=")[1]) : 10;
const outputArg = process.argv.find((arg) => arg.startsWith("--output="));
const outputPath = outputArg ? outputArg.split("=")[1] : "prospects/lead-scoring-cockpit.html";
const outputPath = resolveOutputPath(outputArg?.split("=")[1], { fallback: "prospects/lead-scoring-cockpit.html" });

function listFolders(root) {
return listOutboundProspectFolders(root);
Expand Down Expand Up @@ -295,7 +297,7 @@ const html = `<!doctype html>
</html>
`;

const outputDir = outputPath.split("/").slice(0, -1).join("/");
const outputDir = dirname(outputPath);
if (outputDir) mkdirSync(outputDir, { recursive: true });
writeFileSync(outputPath, html);

Expand Down
2 changes: 2 additions & 0 deletions scripts/export-managed-it-one-pager.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/usr/bin/env node
import { readFileSync, writeFileSync } from "node:fs";
import { handleHelp } from "./lib/operator-cli.mjs";

handleHelp(process.argv.slice(2), `Usage: npm run sales:one-pager -- (writes growth-brain/sales/managed-it-one-page-offer.html)`);
const inputPath = "growth-brain/sales/managed-it-one-page-offer.md";
const outputPath = "growth-brain/sales/managed-it-one-page-offer.html";

Expand Down
20 changes: 13 additions & 7 deletions scripts/export-market-benchmark.mjs
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
#!/usr/bin/env node
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname } from "node:path";
import { localIsoDate } from "./date-utils.mjs";
import { NO_GUARANTEE_CLIENT_SENTENCE } from "./lib/service-contract.mjs";
import { runRepoJson as runJson } from "./lib/runtime-roots.mjs";
import { handleHelp, resolveOutputPath } from "./lib/operator-cli.mjs";

const args = process.argv.slice(2);
handleHelp(args, `Usage: npm run market:benchmark -- [--output=docs/strategy/market-parity-benchmark-2026.md] [--ops=growth-brain/ops/competitive-proof-matrix.md] [--html=growth-brain/ops/competitive-proof-matrix.html]`);
const outputArg = args.find((arg) => arg.startsWith("--output="));
const opsArg = args.find((arg) => arg.startsWith("--ops="));
const htmlArg = args.find((arg) => arg.startsWith("--html="));
const outputPath = outputArg ? outputArg.split("=").slice(1).join("=") : "docs/strategy/market-parity-benchmark-2026.md";
const opsPath = opsArg ? opsArg.split("=").slice(1).join("=") : "growth-brain/ops/competitive-proof-matrix.md";
const htmlPath = htmlArg ? htmlArg.split("=").slice(1).join("=") : "growth-brain/ops/competitive-proof-matrix.html";
const rawOutputPath = outputArg?.split("=").slice(1).join("=") || "docs/strategy/market-parity-benchmark-2026.md";
const rawOpsPath = opsArg?.split("=").slice(1).join("=") || "growth-brain/ops/competitive-proof-matrix.md";
const rawHtmlPath = htmlArg?.split("=").slice(1).join("=") || "growth-brain/ops/competitive-proof-matrix.html";
const outputPath = resolveOutputPath(rawOutputPath);
const opsPath = resolveOutputPath(rawOpsPath, { flag: "--ops" });
const htmlPath = resolveOutputPath(rawHtmlPath, { flag: "--html" });
const today = localIsoDate();
const MARKET_ANCHORS_LAST_CHECKED = "2026-05-29";
function write(path, content) {
const dir = path.split("/").slice(0, -1).join("/");
const dir = dirname(path);
if (dir) mkdirSync(dir, { recursive: true });
writeFileSync(path, content);
}
Expand Down Expand Up @@ -355,9 +361,9 @@ const status = proofBars.some((item) => item.status === "fail")

console.log(JSON.stringify({
status,
path: outputPath,
opsPath,
htmlPath,
path: rawOutputPath,
opsPath: rawOpsPath,
htmlPath: rawHtmlPath,
alternatives: alternatives.length,
proofBars,
sources: alternatives.map((item) => item.sourceUrl)
Expand Down
10 changes: 6 additions & 4 deletions scripts/export-market-learning-review.mjs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
#!/usr/bin/env node
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { dirname, join } from "node:path";
import { localIsoDate } from "./date-utils.mjs";
import { listOutboundProspectFolders } from "./lib/outbound-prospects.mjs";
import { runRepoJson as runJson } from "./lib/runtime-roots.mjs";
import { handleHelp, resolveOutputPath } from "./lib/operator-cli.mjs";

handleHelp(process.argv.slice(2), `Usage: npm run market:learn -- [--limit=N] [--output=runs/market-learning-review.md] [--html=runs/market-learning-review.html]`);
const outputArg = process.argv.find((arg) => arg.startsWith("--output="));
const htmlArg = process.argv.find((arg) => arg.startsWith("--html="));
const limitArg = process.argv.find((arg) => arg.startsWith("--limit="));
const outputPath = outputArg ? outputArg.split("=").slice(1).join("=") : "runs/market-learning-review.md";
const htmlPath = htmlArg ? htmlArg.split("=").slice(1).join("=") : "runs/market-learning-review.html";
const outputPath = resolveOutputPath(outputArg?.split("=").slice(1).join("="), { fallback: "runs/market-learning-review.md" });
const htmlPath = resolveOutputPath(htmlArg?.split("=").slice(1).join("="), { flag: "--html", fallback: "runs/market-learning-review.html" });
const limit = limitArg ? Number(limitArg.split("=").slice(1).join("=")) : 10;
const today = localIsoDate();

Expand All @@ -26,7 +28,7 @@ function json(path) {
}

function write(path, content) {
const dir = path.split("/").slice(0, -1).join("/");
const dir = dirname(path);
if (dir) mkdirSync(dir, { recursive: true });
writeFileSync(path, content);
}
Expand Down
13 changes: 8 additions & 5 deletions scripts/export-market-proof-cockpit.mjs
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
#!/usr/bin/env node
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { dirname, join } from "node:path";
import { localIsoDate } from "./date-utils.mjs";
import { isValidLoomUrl, loomUrlError } from "./lib/loom-url.mjs";
import { sendChannelGuidance } from "./lib/send-channel-guidance.mjs";
import { routedContactPlan } from "./lib/contact-route.mjs";
import { classifyOutboundProspect } from "./lib/outbound-prospects.mjs";
import { runRepoJson as runJson } from "./lib/runtime-roots.mjs";
import { handleHelp, resolveOutputPath } from "./lib/operator-cli.mjs";

const args = process.argv.slice(2);
handleHelp(args, `Usage: npm run market:proof-cockpit -- [prospects/loom-links.txt] [--limit=N] [--plain] [--output=runs/market-proof-cockpit.md] [--html=runs/market-proof-cockpit.html]`);
const inputPath = args.find((arg) => !arg.startsWith("--")) || "prospects/loom-links.txt";
const outputArg = args.find((arg) => arg.startsWith("--output="));
const htmlArg = args.find((arg) => arg.startsWith("--html="));
const limitArg = args.find((arg) => arg.startsWith("--limit="));
const plain = args.includes("--plain");
const outputPath = outputArg ? outputArg.split("=").slice(1).join("=") : "runs/market-proof-cockpit.md";
const htmlPath = htmlArg ? htmlArg.split("=").slice(1).join("=") : "runs/market-proof-cockpit.html";
const rawOutputPath = outputArg ? outputArg.split("=").slice(1).join("=") : "runs/market-proof-cockpit.md";
const outputPath = resolveOutputPath(rawOutputPath);
const htmlPath = resolveOutputPath(htmlArg?.split("=").slice(1).join("="), { flag: "--html", fallback: "runs/market-proof-cockpit.html" });
const limit = limitArg ? Number(limitArg.split("=").slice(1).join("=")) : 5;
const today = localIsoDate();

Expand All @@ -28,7 +31,7 @@ function json(path) {
}

function write(path, content) {
const dir = path.split("/").slice(0, -1).join("/");
const dir = dirname(path);
if (dir) mkdirSync(dir, { recursive: true });
writeFileSync(path, content);
}
Expand Down Expand Up @@ -207,7 +210,7 @@ if (!existsSync(inputPath)) {
process.exit(1);
}

const checkOutputPath = outputPath.startsWith("prospects/kit-")
const checkOutputPath = rawOutputPath.startsWith("prospects/kit-")
? "prospects/kit-market-proof-run-check.md"
: "runs/market-proof-run-check.md";
const check = runJson(["scripts/check-market-proof-run.mjs", inputPath, `--output=${checkOutputPath}`, `--limit=${limit}`]);
Expand Down
Loading