mustflow 2.85.4 → 2.99.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.
Files changed (78) hide show
  1. package/dist/cli/commands/script-pack.js +10 -0
  2. package/dist/cli/i18n/en.js +183 -0
  3. package/dist/cli/i18n/es.js +183 -0
  4. package/dist/cli/i18n/fr.js +183 -0
  5. package/dist/cli/i18n/hi.js +183 -0
  6. package/dist/cli/i18n/ko.js +183 -0
  7. package/dist/cli/i18n/zh.js +183 -0
  8. package/dist/cli/lib/script-pack-registry.js +284 -1
  9. package/dist/cli/script-packs/code-change-impact.js +6 -0
  10. package/dist/cli/script-packs/code-import-cycle.js +193 -0
  11. package/dist/cli/script-packs/docs-link-integrity.js +145 -0
  12. package/dist/cli/script-packs/repo-approval-gate.js +100 -0
  13. package/dist/cli/script-packs/repo-git-ignore-audit.js +119 -0
  14. package/dist/cli/script-packs/repo-manifest-lock-drift.js +122 -0
  15. package/dist/cli/script-packs/repo-merge-conflict-scan.js +123 -0
  16. package/dist/cli/script-packs/repo-skill-route-audit.js +86 -0
  17. package/dist/cli/script-packs/repo-version-source.js +92 -0
  18. package/dist/cli/script-packs/test-performance-report.js +247 -0
  19. package/dist/cli/script-packs/test-regression-selector.js +167 -0
  20. package/dist/core/change-impact.js +23 -51
  21. package/dist/core/change-surface-classification.js +198 -0
  22. package/dist/core/docs-link-integrity.js +443 -0
  23. package/dist/core/import-cycle.js +152 -0
  24. package/dist/core/public-json-contracts.js +116 -0
  25. package/dist/core/repo-approval-gate.js +116 -0
  26. package/dist/core/repo-git-ignore-audit.js +302 -0
  27. package/dist/core/repo-manifest-lock-drift.js +321 -0
  28. package/dist/core/repo-merge-conflict-scan.js +335 -0
  29. package/dist/core/repo-version-source.js +82 -0
  30. package/dist/core/script-pack-suggestions.js +77 -1
  31. package/dist/core/skill-route-audit.js +354 -0
  32. package/dist/core/test-performance-report.js +697 -0
  33. package/dist/core/test-regression-selector.js +335 -0
  34. package/package.json +1 -1
  35. package/schemas/README.md +40 -2
  36. package/schemas/change-impact-report.schema.json +35 -1
  37. package/schemas/import-cycle-report.schema.json +157 -0
  38. package/schemas/link-integrity-report.schema.json +176 -0
  39. package/schemas/repo-approval-gate-report.schema.json +115 -0
  40. package/schemas/repo-git-ignore-audit-report.schema.json +201 -0
  41. package/schemas/repo-manifest-lock-drift-report.schema.json +202 -0
  42. package/schemas/repo-merge-conflict-scan-report.schema.json +169 -0
  43. package/schemas/repo-version-source-report.schema.json +127 -0
  44. package/schemas/skill-route-audit-report.schema.json +144 -0
  45. package/schemas/test-performance-report.schema.json +319 -0
  46. package/schemas/test-regression-selector-report.schema.json +187 -0
  47. package/templates/default/i18n.toml +66 -18
  48. package/templates/default/locales/en/.mustflow/skills/INDEX.md +45 -8
  49. package/templates/default/locales/en/.mustflow/skills/api-access-control-review/SKILL.md +48 -27
  50. package/templates/default/locales/en/.mustflow/skills/api-failure-triage/SKILL.md +270 -0
  51. package/templates/default/locales/en/.mustflow/skills/auth-flow-triage/SKILL.md +192 -0
  52. package/templates/default/locales/en/.mustflow/skills/auth-permission-change/SKILL.md +59 -13
  53. package/templates/default/locales/en/.mustflow/skills/backend-log-evidence-review/SKILL.md +14 -5
  54. package/templates/default/locales/en/.mustflow/skills/cache-integrity-review/SKILL.md +30 -15
  55. package/templates/default/locales/en/.mustflow/skills/change-blast-radius-review/SKILL.md +45 -32
  56. package/templates/default/locales/en/.mustflow/skills/ci-pipeline-triage/SKILL.md +200 -0
  57. package/templates/default/locales/en/.mustflow/skills/clarifying-question-gate/SKILL.md +87 -13
  58. package/templates/default/locales/en/.mustflow/skills/docker-runtime-triage/SKILL.md +191 -0
  59. package/templates/default/locales/en/.mustflow/skills/go-code-change/SKILL.md +18 -13
  60. package/templates/default/locales/en/.mustflow/skills/line-ending-hygiene/SKILL.md +18 -10
  61. package/templates/default/locales/en/.mustflow/skills/llm-hallucination-control-review/SKILL.md +4 -1
  62. package/templates/default/locales/en/.mustflow/skills/motion-system-contract-review/SKILL.md +155 -0
  63. package/templates/default/locales/en/.mustflow/skills/next-action-menu/SKILL.md +177 -0
  64. package/templates/default/locales/en/.mustflow/skills/observability-debuggability-review/SKILL.md +15 -7
  65. package/templates/default/locales/en/.mustflow/skills/payment-integrity-review/SKILL.md +59 -35
  66. package/templates/default/locales/en/.mustflow/skills/powershell-code-change/SKILL.md +16 -6
  67. package/templates/default/locales/en/.mustflow/skills/prompt-contract-quality-review/SKILL.md +4 -1
  68. package/templates/default/locales/en/.mustflow/skills/python-code-change/SKILL.md +19 -10
  69. package/templates/default/locales/en/.mustflow/skills/rag-pipeline-triage/SKILL.md +206 -0
  70. package/templates/default/locales/en/.mustflow/skills/routes.toml +54 -0
  71. package/templates/default/locales/en/.mustflow/skills/rust-code-change/SKILL.md +10 -4
  72. package/templates/default/locales/en/.mustflow/skills/search-index-integrity-review/SKILL.md +181 -0
  73. package/templates/default/locales/en/.mustflow/skills/service-boundary-architecture/SKILL.md +37 -23
  74. package/templates/default/locales/en/.mustflow/skills/test-suite-performance-review/SKILL.md +9 -0
  75. package/templates/default/locales/en/.mustflow/skills/typescript-code-change/SKILL.md +14 -9
  76. package/templates/default/locales/en/.mustflow/skills/vector-search-integrity-review/SKILL.md +209 -0
  77. package/templates/default/locales/en/.mustflow/skills/version-freshness-check/SKILL.md +16 -14
  78. package/templates/default/manifest.toml +64 -1
@@ -0,0 +1,152 @@
1
+ import { createHash } from 'node:crypto';
2
+ import path from 'node:path';
3
+ import { DEPENDENCY_GRAPH_SCRIPT_REF, inspectDependencyGraph, } from './dependency-graph.js';
4
+ export const IMPORT_CYCLE_PACK_ID = 'code';
5
+ export const IMPORT_CYCLE_SCRIPT_ID = 'import-cycle';
6
+ export const IMPORT_CYCLE_SCRIPT_REF = `${IMPORT_CYCLE_PACK_ID}/${IMPORT_CYCLE_SCRIPT_ID}`;
7
+ const DEFAULT_MAX_DEPTH = 20;
8
+ const DEFAULT_MAX_CYCLES = 50;
9
+ const MAX_ISSUES = 50;
10
+ function sha256Tagged(value) {
11
+ return `sha256:${createHash('sha256').update(value).digest('hex')}`;
12
+ }
13
+ function cycleId(paths) {
14
+ return `cycle:${createHash('sha256').update(paths.join('\0')).digest('hex').slice(0, 12)}`;
15
+ }
16
+ function edgeKey(sourcePath, targetPath) {
17
+ return `${sourcePath}\0${targetPath}`;
18
+ }
19
+ function buildEdgeIndex(edges) {
20
+ const index = new Map();
21
+ for (const edge of edges) {
22
+ const key = edgeKey(edge.source_path, edge.target_path);
23
+ const existing = index.get(key) ?? [];
24
+ existing.push(edge);
25
+ index.set(key, existing);
26
+ }
27
+ for (const indexedEdges of index.values()) {
28
+ indexedEdges.sort((left, right) => left.line - right.line ||
29
+ left.kind.localeCompare(right.kind) ||
30
+ left.specifier.localeCompare(right.specifier));
31
+ }
32
+ return index;
33
+ }
34
+ function importCycleEdges(cyclePaths, edgeIndex) {
35
+ const edges = [];
36
+ let index = 0;
37
+ while (index < cyclePaths.length - 1) {
38
+ const sourcePath = cyclePaths[index];
39
+ const targetPath = cyclePaths[index + 1];
40
+ if (!sourcePath || !targetPath) {
41
+ index += 1;
42
+ continue;
43
+ }
44
+ const [edge] = edgeIndex.get(edgeKey(sourcePath, targetPath)) ?? [];
45
+ if (edge) {
46
+ edges.push({
47
+ source_path: edge.source_path,
48
+ target_path: edge.target_path,
49
+ specifier: edge.specifier,
50
+ line: edge.line,
51
+ kind: edge.kind,
52
+ });
53
+ }
54
+ index += 1;
55
+ }
56
+ return edges;
57
+ }
58
+ function makeFinding(code, severity, pathValue, message, cycle_id) {
59
+ return cycle_id
60
+ ? { code, severity, path: pathValue, message, cycle_id }
61
+ : { code, severity, path: pathValue, message };
62
+ }
63
+ function normalizeGraphFinding(finding) {
64
+ return {
65
+ code: finding.code,
66
+ severity: finding.severity,
67
+ path: finding.path,
68
+ message: finding.message,
69
+ };
70
+ }
71
+ function pushIssue(issues, issue) {
72
+ if (issues.length < MAX_ISSUES) {
73
+ issues.push(issue);
74
+ }
75
+ }
76
+ function importCycleStatus(graphStatus, cycles, findings) {
77
+ if (graphStatus === 'error') {
78
+ return 'error';
79
+ }
80
+ return cycles.length > 0 || findings.length > 0 ? 'failed' : 'passed';
81
+ }
82
+ function createInputHash(policy, graph, cycles, findings, issues) {
83
+ return sha256Tagged(JSON.stringify({
84
+ policy,
85
+ graph_input_hash: graph.input_hash,
86
+ targets: graph.targets,
87
+ cycles: cycles.map((cycle) => ({ cycle_id: cycle.cycle_id, paths: cycle.paths })),
88
+ findings: findings.map((finding) => ({ code: finding.code, path: finding.path, cycle_id: finding.cycle_id })),
89
+ issues,
90
+ }));
91
+ }
92
+ export function inspectImportCycles(projectRoot, options) {
93
+ const root = path.resolve(projectRoot);
94
+ const graph = inspectDependencyGraph(root, {
95
+ paths: options.paths,
96
+ maxFiles: options.maxFiles,
97
+ maxFileBytes: options.maxFileBytes,
98
+ maxDepth: options.maxDepth ?? DEFAULT_MAX_DEPTH,
99
+ maxNodes: options.maxNodes,
100
+ maxEdges: options.maxEdges,
101
+ });
102
+ const policy = {
103
+ ...graph.policy,
104
+ max_cycles: options.maxCycles ?? DEFAULT_MAX_CYCLES,
105
+ };
106
+ const edgeIndex = buildEdgeIndex(graph.edges);
107
+ const cycles = graph.cycles.slice(0, policy.max_cycles).map((cyclePaths) => ({
108
+ cycle_id: cycleId(cyclePaths),
109
+ path_count: Math.max(0, cyclePaths.length - 1),
110
+ paths: cyclePaths,
111
+ edges: importCycleEdges(cyclePaths, edgeIndex),
112
+ }));
113
+ const issues = [...graph.issues];
114
+ const findings = graph.findings.map(normalizeGraphFinding);
115
+ for (const cycle of cycles) {
116
+ const [firstPath] = cycle.paths;
117
+ findings.push(makeFinding('import_cycle_detected', 'high', firstPath ?? '.', `Import cycle detected: ${cycle.paths.join(' -> ')}`, cycle.cycle_id));
118
+ }
119
+ if (graph.cycles.length > cycles.length) {
120
+ const message = `Import cycle scan found more than ${policy.max_cycles} cycles; remaining cycles were skipped.`;
121
+ pushIssue(issues, message);
122
+ findings.push(makeFinding('import_cycle_max_cycles_exceeded', 'medium', '.', message));
123
+ }
124
+ const status = importCycleStatus(graph.status, cycles, findings);
125
+ const truncated = graph.truncated || graph.cycles.length > cycles.length;
126
+ return {
127
+ schema_version: '1',
128
+ command: 'script-pack',
129
+ pack_id: IMPORT_CYCLE_PACK_ID,
130
+ script_id: IMPORT_CYCLE_SCRIPT_ID,
131
+ script_ref: IMPORT_CYCLE_SCRIPT_REF,
132
+ action: 'check',
133
+ status,
134
+ ok: status === 'passed',
135
+ mustflow_root: root,
136
+ policy,
137
+ input_hash: createInputHash(policy, graph, cycles, findings, issues),
138
+ targets: graph.targets,
139
+ graph: {
140
+ script_ref: DEPENDENCY_GRAPH_SCRIPT_REF,
141
+ status: graph.status,
142
+ node_count: graph.nodes.length,
143
+ edge_count: graph.edges.length,
144
+ cycle_hint_count: graph.cycles.length,
145
+ truncated: graph.truncated,
146
+ },
147
+ cycles,
148
+ truncated,
149
+ findings,
150
+ issues,
151
+ };
152
+ }
@@ -264,6 +264,23 @@ const PUBLIC_JSON_SCHEMA_CONTRACTS = [
264
264
  '--json',
265
265
  ],
266
266
  },
267
+ {
268
+ id: 'import-cycle-report',
269
+ schemaFile: 'import-cycle-report.schema.json',
270
+ producer: 'mf script-pack run code/import-cycle check <path...> --json',
271
+ packaged: true,
272
+ documented: true,
273
+ installedCommand: [
274
+ 'mf',
275
+ 'script-pack',
276
+ 'run',
277
+ 'code/import-cycle',
278
+ 'check',
279
+ 'node_modules/mustflow/dist/cli/index.js',
280
+ '--json',
281
+ ],
282
+ expectedExitCodes: [0, 1],
283
+ },
267
284
  {
268
285
  id: 'change-impact-report',
269
286
  schemaFile: 'change-impact-report.schema.json',
@@ -342,6 +359,42 @@ const PUBLIC_JSON_SCHEMA_CONTRACTS = [
342
359
  ],
343
360
  expectedExitCodes: [0, 1],
344
361
  },
362
+ {
363
+ id: 'link-integrity-report',
364
+ schemaFile: 'link-integrity-report.schema.json',
365
+ producer: 'mf script-pack run docs/link-integrity check [path...] --json',
366
+ packaged: true,
367
+ documented: true,
368
+ installedCommand: [
369
+ 'mf',
370
+ 'script-pack',
371
+ 'run',
372
+ 'docs/link-integrity',
373
+ 'check',
374
+ 'node_modules/mustflow/README.md',
375
+ 'node_modules/mustflow/schemas/README.md',
376
+ '--json',
377
+ ],
378
+ expectedExitCodes: [0, 1],
379
+ },
380
+ {
381
+ id: 'test-performance-report',
382
+ schemaFile: 'test-performance-report.schema.json',
383
+ producer: 'mf script-pack run test/performance-report summarize --json',
384
+ packaged: true,
385
+ documented: true,
386
+ installedCommand: ['mf', 'script-pack', 'run', 'test/performance-report', 'summarize', '--json'],
387
+ expectedExitCodes: [0, 1],
388
+ },
389
+ {
390
+ id: 'test-regression-selector-report',
391
+ schemaFile: 'test-regression-selector-report.schema.json',
392
+ producer: 'mf script-pack run test/regression-selector select --json',
393
+ packaged: true,
394
+ documented: true,
395
+ installedCommand: ['mf', 'script-pack', 'run', 'test/regression-selector', 'select', '--json'],
396
+ expectedExitCodes: [0, 1],
397
+ },
345
398
  {
346
399
  id: 'text-budget-report',
347
400
  schemaFile: 'text-budget-report.schema.json',
@@ -379,6 +432,69 @@ const PUBLIC_JSON_SCHEMA_CONTRACTS = [
379
432
  ],
380
433
  expectedExitCodes: [0, 1],
381
434
  },
435
+ {
436
+ id: 'repo-merge-conflict-scan-report',
437
+ schemaFile: 'repo-merge-conflict-scan-report.schema.json',
438
+ producer: 'mf script-pack run repo/merge-conflict-scan check [path...] --json',
439
+ packaged: true,
440
+ documented: true,
441
+ installedCommand: ['mf', 'script-pack', 'run', 'repo/merge-conflict-scan', 'check', '--json'],
442
+ expectedExitCodes: [0, 1],
443
+ },
444
+ {
445
+ id: 'repo-git-ignore-audit-report',
446
+ schemaFile: 'repo-git-ignore-audit-report.schema.json',
447
+ producer: 'mf script-pack run repo/git-ignore-audit audit [path...] --json',
448
+ packaged: true,
449
+ documented: true,
450
+ installedCommand: ['mf', 'script-pack', 'run', 'repo/git-ignore-audit', 'audit', 'AGENTS.md', '--json'],
451
+ expectedExitCodes: [0, 1],
452
+ },
453
+ {
454
+ id: 'repo-manifest-lock-drift-report',
455
+ schemaFile: 'repo-manifest-lock-drift-report.schema.json',
456
+ producer: 'mf script-pack run repo/manifest-lock-drift check [path...] --json',
457
+ packaged: true,
458
+ documented: true,
459
+ installedCommand: ['mf', 'script-pack', 'run', 'repo/manifest-lock-drift', 'check', 'AGENTS.md', '--json'],
460
+ expectedExitCodes: [0, 1],
461
+ },
462
+ {
463
+ id: 'skill-route-audit-report',
464
+ schemaFile: 'skill-route-audit-report.schema.json',
465
+ producer: 'mf script-pack run repo/skill-route-audit audit --json',
466
+ packaged: true,
467
+ documented: true,
468
+ installedCommand: ['mf', 'script-pack', 'run', 'repo/skill-route-audit', 'audit', '--json'],
469
+ expectedExitCodes: [0, 1],
470
+ },
471
+ {
472
+ id: 'repo-version-source-report',
473
+ schemaFile: 'repo-version-source-report.schema.json',
474
+ producer: 'mf script-pack run repo/version-source inspect --json',
475
+ packaged: true,
476
+ documented: true,
477
+ installedCommand: ['mf', 'script-pack', 'run', 'repo/version-source', 'inspect', '--json'],
478
+ expectedExitCodes: [0, 1],
479
+ },
480
+ {
481
+ id: 'repo-approval-gate-report',
482
+ schemaFile: 'repo-approval-gate-report.schema.json',
483
+ producer: 'mf script-pack run repo/approval-gate check --action <type> --json',
484
+ packaged: true,
485
+ documented: true,
486
+ installedCommand: [
487
+ 'mf',
488
+ 'script-pack',
489
+ 'run',
490
+ 'repo/approval-gate',
491
+ 'check',
492
+ '--action',
493
+ 'git_commit',
494
+ '--json',
495
+ ],
496
+ expectedExitCodes: [0, 1],
497
+ },
382
498
  {
383
499
  id: 'config-chain-report',
384
500
  schemaFile: 'config-chain-report.schema.json',
@@ -0,0 +1,116 @@
1
+ import { createHash } from 'node:crypto';
2
+ import path from 'node:path';
3
+ import { isRecord, MUSTFLOW_CONFIG_RELATIVE_PATH, readMustflowConfigIfExists, readStringArray, } from './config-loading.js';
4
+ export const REPO_APPROVAL_GATE_PACK_ID = 'repo';
5
+ export const REPO_APPROVAL_GATE_SCRIPT_ID = 'approval-gate';
6
+ export const REPO_APPROVAL_GATE_SCRIPT_REF = `${REPO_APPROVAL_GATE_PACK_ID}/${REPO_APPROVAL_GATE_SCRIPT_ID}`;
7
+ export const REPO_APPROVAL_GATE_POLICY_PATH = MUSTFLOW_CONFIG_RELATIVE_PATH;
8
+ function sha256(value) {
9
+ return `sha256:${createHash('sha256').update(value).digest('hex')}`;
10
+ }
11
+ function uniqueActions(actions) {
12
+ const normalized = [];
13
+ const seen = new Set();
14
+ for (const action of actions) {
15
+ const trimmed = action.trim();
16
+ if (trimmed.length === 0 || seen.has(trimmed)) {
17
+ continue;
18
+ }
19
+ seen.add(trimmed);
20
+ normalized.push(trimmed);
21
+ }
22
+ return normalized;
23
+ }
24
+ function readApprovalPolicy(projectRoot, issues) {
25
+ let config;
26
+ try {
27
+ config = readMustflowConfigIfExists(projectRoot);
28
+ }
29
+ catch (error) {
30
+ const message = error instanceof Error ? error.message : String(error);
31
+ issues.push(`Could not read ${REPO_APPROVAL_GATE_POLICY_PATH}: ${message}`);
32
+ }
33
+ if (!config) {
34
+ issues.push(`${REPO_APPROVAL_GATE_POLICY_PATH} is missing.`);
35
+ return { required_for: [], on_required: null };
36
+ }
37
+ if (!isRecord(config.approval)) {
38
+ issues.push(`[approval] in ${REPO_APPROVAL_GATE_POLICY_PATH} must be a TOML table.`);
39
+ return { required_for: [], on_required: null };
40
+ }
41
+ const approval = config.approval;
42
+ const requiredFor = readStringArray(approval, 'required_for');
43
+ if (!requiredFor) {
44
+ issues.push(`[approval].required_for in ${REPO_APPROVAL_GATE_POLICY_PATH} must be a string array.`);
45
+ }
46
+ const onRequired = approval.on_required;
47
+ if (onRequired !== undefined && typeof onRequired !== 'string') {
48
+ issues.push(`[approval].on_required in ${REPO_APPROVAL_GATE_POLICY_PATH} must be a string.`);
49
+ }
50
+ return {
51
+ required_for: requiredFor ?? [],
52
+ on_required: typeof onRequired === 'string' ? onRequired : null,
53
+ };
54
+ }
55
+ function createDecisions(actionTypes, policy) {
56
+ const required = new Set(policy.required_for);
57
+ return actionTypes.map((actionType) => {
58
+ const approvalRequired = required.has(actionType);
59
+ return {
60
+ action_type: actionType,
61
+ approval_required: approvalRequired,
62
+ policy_source: approvalRequired ? `${REPO_APPROVAL_GATE_POLICY_PATH}#[approval].required_for` : null,
63
+ reason: approvalRequired
64
+ ? `Action "${actionType}" is listed in [approval].required_for.`
65
+ : `Action "${actionType}" is not listed in [approval].required_for.`,
66
+ };
67
+ });
68
+ }
69
+ function createFindings(decisions) {
70
+ return decisions
71
+ .filter((decision) => decision.approval_required)
72
+ .map((decision) => ({
73
+ code: 'approval_required_for_action',
74
+ severity: 'high',
75
+ path: REPO_APPROVAL_GATE_POLICY_PATH,
76
+ message: `Action "${decision.action_type}" requires explicit approval before proceeding.`,
77
+ json_pointer: '/approval/required_for',
78
+ metric: null,
79
+ actual: null,
80
+ expected: null,
81
+ }));
82
+ }
83
+ function createInputHash(reportInput) {
84
+ return sha256(JSON.stringify(reportInput));
85
+ }
86
+ export function checkRepoApprovalGate(projectRoot, actionTypes) {
87
+ const root = path.resolve(projectRoot);
88
+ const actions = uniqueActions(actionTypes);
89
+ const issues = [];
90
+ const policy = readApprovalPolicy(root, issues);
91
+ const decisions = issues.length > 0 ? [] : createDecisions(actions, policy);
92
+ const findings = createFindings(decisions);
93
+ const approvalRequired = findings.length > 0;
94
+ const status = issues.length > 0 ? 'error' : approvalRequired ? 'failed' : 'passed';
95
+ return {
96
+ schema_version: '1',
97
+ command: 'script-pack',
98
+ pack_id: REPO_APPROVAL_GATE_PACK_ID,
99
+ script_id: REPO_APPROVAL_GATE_SCRIPT_ID,
100
+ script_ref: REPO_APPROVAL_GATE_SCRIPT_REF,
101
+ action: 'check',
102
+ status,
103
+ ok: status === 'passed',
104
+ mustflow_root: root,
105
+ input: {
106
+ action_types: actions,
107
+ policy_path: REPO_APPROVAL_GATE_POLICY_PATH,
108
+ },
109
+ input_hash: createInputHash({ actionTypes: actions, policy, decisions, findings, issues }),
110
+ approval_required: approvalRequired,
111
+ policy,
112
+ decisions,
113
+ findings,
114
+ issues,
115
+ };
116
+ }