File size: 2,253 Bytes
06671aa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import { readFileSync } from "node:fs";
import { createHash } from "node:crypto";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = dirname(fileURLToPath(import.meta.url));
const REPO_ROOT = join(__dirname, "../../..");
const FRONTEND_SOURCE = join(
    REPO_ROOT,
    "frontend/src/app/components/workflows/builtinWorkflows.ts",
);

/** @typedef {import("../../../frontend/src/app/components/shared/types").MikeWorkflow} MikeWorkflow */

/**
 * Parse the pre-cutover frontend builtin workflow registry by evaluating its
 * literal array definition. No template interpolation is used in the source file.
 * @returns {MikeWorkflow[]}
 */
export function parseFrontendBuiltinWorkflows(sourcePath = FRONTEND_SOURCE) {
    const src = readFileSync(sourcePath, "utf8");
    const trimmed = src
        .replace(/^import.*\n/m, "")
        .replace(/export const BUILT_IN_IDS[\s\S]*$/, "")
        .replace(
            /export const BUILT_IN_WORKFLOWS:\s*MikeWorkflow\[\]\s*=/,
            "const BUILT_IN_WORKFLOWS =",
        );
    const fn = new Function(`${trimmed}; return BUILT_IN_WORKFLOWS;`);
    return fn();
}

/** @param {MikeWorkflow[]} workflows */
export function workflowInventory(workflows) {
    const orderedIds = workflows.map((wf) => wf.id);
    const perWorkflowColumnCount = Object.fromEntries(
        workflows.map((wf) => [wf.id, wf.columns_config?.length ?? 0]),
    );
    const normalized = stableStringify(workflows);
    return {
        orderedIds,
        totalWorkflowCount: workflows.length,
        perWorkflowColumnCount,
        totalColumnPromptCount: workflows.reduce(
            (sum, wf) =>
                sum +
                (wf.columns_config?.filter((col) => typeof col.prompt === "string")
                    .length ?? 0),
            0,
        ),
        sha256: createHash("sha256").update(normalized).digest("hex"),
        workflows,
    };
}

/** @param {unknown} value */
export function stableStringify(value) {
    return `${JSON.stringify(value, null, 2)}\n`;
}

export function parseFrontendInventory(sourcePath = FRONTEND_SOURCE) {
    const workflows = parseFrontendBuiltinWorkflows(sourcePath);
    return workflowInventory(workflows);
}