#!/usr/bin/env node const fs = require('fs'); const path = require('path'); const ROOT = path.resolve(__dirname, '..'); const DEFAULT_OUTPUT = path.join(ROOT, 'outputs', 'business-execution-index-latest'); function main() { const args = parseArgs(process.argv.slice(2)); const outputsDir = path.resolve(args.outputs || path.join(ROOT, 'outputs')); const outputDir = path.resolve(args.output || DEFAULT_OUTPUT); const summary = buildBusinessExecutionIndex({ root: ROOT, outputsDir }); fs.mkdirSync(outputDir, { recursive: true }); const jsonPath = path.join(outputDir, 'business-execution-index-summary.json'); const reportPath = path.join(outputDir, 'business-execution-index.md'); const csvPath = path.join(outputDir, 'business-execution-index.csv'); fs.writeFileSync(jsonPath, JSON.stringify(summary, null, 2), 'utf8'); fs.writeFileSync(reportPath, withBom(renderReport(summary)), 'utf8'); fs.writeFileSync(csvPath, withBom(renderCsv(summary.rows)), 'utf8'); console.log(JSON.stringify({ outputDir, json: jsonPath, report: reportPath, csv: csvPath, passed: summary.passed, rowCount: summary.rowCount, proofOpenCount: summary.proofOpenCount }, null, 2)); if (args.strict && !summary.passed) process.exitCode = 1; } function buildBusinessExecutionIndex({ root, outputsDir }) { const nextActionsDir = pickDir(outputsDir, 'business-proof-next-actions-latest', /^business-proof-next-actions-/); const latestFormDir = pickDir(outputsDir, 'latest-form-index-latest', /^latest-form-index-/); const proofFormDir = pickDir(outputsDir, 'tihao-proof-gap-software-form-latest', /^tihao-proof-gap-software-form-/); const proofClosureDir = pickDir(outputsDir, 'proof-gap-closure-latest', /^proof-gap-closure-/); const evidenceDir = pickDir(outputsDir, 'evidence-index-latest', /^evidence-index-/); const fieldChecklistDir = pickDir(outputsDir, 'intake-field-checklist-latest', /^intake-field-checklist-/); const longRunReadinessDir = pickDir(outputsDir, 'long-run-readiness-latest', /^long-run-readiness-/); const optimizationCompletionDir = pickDir(outputsDir, 'optimization-completion-latest', /^optimization-completion-/); const proofGapOperatorPackDir = pickDir(outputsDir, 'proof-gap-operator-pack-latest', /^proof-gap-operator-pack-/); const nextActions = readJson(path.join(nextActionsDir, 'business-proof-next-actions-summary.json')); const latestForm = readJson(path.join(latestFormDir, 'latest-form-index-summary.json')); const proofForm = readJson(path.join(proofFormDir, 'tihao-proof-gap-software-form-summary.json')); const closure = readJson(path.join(proofClosureDir, 'proof-gap-closure-summary.json')); const evidence = readJson(path.join(evidenceDir, 'evidence-index-summary.json')); const fieldChecklist = readJson(path.join(fieldChecklistDir, 'intake-field-checklist-summary.json')); const longRunReadiness = readJson(path.join(longRunReadinessDir, 'long-run-readiness-summary.json')); const optimizationCompletion = readJson(path.join(optimizationCompletionDir, 'optimization-completion-summary.json')); const proofGapOperatorPack = readJson(path.join(proofGapOperatorPackDir, 'proof-gap-operator-pack-summary.json')); const operatorPackOwnerArtifacts = normalizeProofGapOperatorOwnerArtifacts(root, proofGapOperatorPackDir, proofGapOperatorPack); const rows = [ ...buildOwnerActionRows(root, nextActionsDir, nextActions), ...buildRepairRows(root, nextActionsDir, nextActions), ...buildProofGapOperatorOwnerRows(operatorPackOwnerArtifacts), ...buildFieldChecklistOwnerRows(root, fieldChecklistDir, fieldChecklist), ...buildFieldChecklistRecheckRows(root, fieldChecklistDir, fieldChecklist), ...buildPrimaryFileRows(root, latestFormDir, latestForm, proofForm, fieldChecklistDir, fieldChecklist, longRunReadinessDir, longRunReadiness, optimizationCompletionDir, optimizationCompletion) ].map(row => ({ ...row, boundary: normalizeProofBoundary(row.boundary) })); const proofOpenCount = Number(nextActions?.sourceState?.proofGapOpenCount ?? closure?.openCount ?? latestForm?.nextActions?.proofOpenCount ?? 0); const passed = rows.length > 0 && rows.every(row => row.owner && row.title && row.acceptance && row.boundary); return { generatedAt: new Date().toISOString(), root, outputsDir, passed, rowCount: rows.length, actionRowCount: rows.filter(row => row.type === '负责人行动').length, repairRowCount: rows.filter(row => row.type === '修复清单').length, operatorPackOwnerArtifactRowCount: rows.filter(row => row.type === '操作包负责人附件').length, operatorPackOwnerArtifactCount: operatorPackOwnerArtifacts.length, operatorPackOwnerArtifacts, fieldOwnerRowCount: rows.filter(row => row.type === '字段补齐负责人').length, recheckCommandRowCount: rows.filter(row => row.type === '补齐后复验命令').length, fileRowCount: rows.filter(row => row.type === '关键文件').length, proofOpenCount, closureComplete: Boolean(closure?.complete), status: proofOpenCount === 0 && closure?.complete ? 'ready_for_claim_audit' : 'actions_open', evidenceCounts: evidence?.counts || {}, proofLevel: 'smoke_or_local', directCustomerProof: false, files: { report: 'outputs/business-execution-index-latest/business-execution-index.md', csv: 'outputs/business-execution-index-latest/business-execution-index.csv', summary: 'outputs/business-execution-index-latest/business-execution-index-summary.json' }, sourceFiles: { nextActions: rel(root, path.join(nextActionsDir, 'business-proof-next-actions-summary.json')), latestFormIndex: rel(root, path.join(latestFormDir, 'latest-form-index-summary.json')), proofGapSoftwareForm: rel(root, path.join(proofFormDir, 'tihao-proof-gap-software-form-summary.json')), proofGapClosure: rel(root, path.join(proofClosureDir, 'proof-gap-closure-summary.json')), intakeFieldChecklist: rel(root, path.join(fieldChecklistDir, 'intake-field-checklist-summary.json')), longRunReadiness: rel(root, path.join(longRunReadinessDir, 'long-run-readiness-summary.json')), optimizationCompletion: rel(root, path.join(optimizationCompletionDir, 'optimization-completion-summary.json')), proofGapOperatorPack: rel(root, path.join(proofGapOperatorPackDir, 'proof-gap-operator-pack-summary.json')), evidenceIndex: rel(root, path.join(evidenceDir, 'evidence-index-summary.json')) }, guardrails: [ '本表只用于商务补证执行分派,不证明客户效果或命中率提升。', 'sample、smoke、模板、provider fallback、接口 200 都不能作为业务证明。', '只有 proof-gap-closure openCount=0 且 customer-effect/video/live 真实审计通过后,才能进入效果宣称。', 'optimization-completion readyForClaim=false 时,本表不证明客户效果,不得宣称提号率提升、客户效果达标或人工补号量下降。', '本表不得包含 sessionToken、Authorization、模型 token 或 npm token。' ], rows }; } function buildOwnerActionRows(root, nextActionsDir, nextActions) { const actions = Array.isArray(nextActions?.actions) ? nextActions.actions : []; return actions.map(action => { const ownerArtifact = findOwnerArtifact(nextActions, action.owner); return { owner: action.owner || '未分配', type: '负责人行动', title: action.title || '', priority: Number(action.priority || action.order || 0), status: action.status || 'open', mainFile: ownerArtifact?.markdown ? rel(root, path.join(nextActionsDir, ownerArtifact.markdown)) : rel(root, path.join(nextActionsDir, 'business-proof-next-actions-report.md')), csv: ownerArtifact?.csv ? rel(root, path.join(nextActionsDir, ownerArtifact.csv)) : rel(root, path.join(nextActionsDir, 'business-proof-next-actions.csv')), repairFile: '', actionCount: 1, command: action.command || '', expectedArtifact: action.expectedArtifact || '', acceptance: appendMissingProofRequirements(action.acceptance || '', action.missingProofRequirements), boundary: '补证任务,不证明业务效果' }; }); } function buildRepairRows(root, nextActionsDir, nextActions) { const ownerArtifacts = Array.isArray(nextActions?.ownerArtifacts) ? nextActions.ownerArtifacts : []; return ownerArtifacts.flatMap(owner => { const repairs = Array.isArray(owner.repairArtifacts) ? owner.repairArtifacts : []; const ownerMarkdown = owner.markdown ? rel(root, path.join(nextActionsDir, owner.markdown)) : ''; const ownerCsv = owner.csv ? rel(root, path.join(nextActionsDir, owner.csv)) : ''; return repairs.map(repair => ({ owner: owner.owner || repair.owner || '未分配', type: '修复清单', title: repair.title || '修复清单', priority: Number(repair.topPriority || 0), status: Number(repair.actionCount || 0) > 0 ? 'actions_open' : 'empty', mainFile: ownerMarkdown, csv: ownerCsv, repairFile: repair.csv || '', actionCount: Number(repair.actionCount || 0), command: '按修复清单补齐字段后重新运行 round:refresh', expectedArtifact: repair.csv || '', acceptance: Number(repair.actionCount || 0) > 0 ? `修复动作数=${Number(repair.actionCount || 0)},补齐后对应 readiness failureCount=0` : '无修复动作', boundary: '修复清单是补证执行材料,不证明客户效果' })); }); } function buildProofGapOperatorOwnerRows(ownerArtifacts) { return ownerArtifacts.map(item => ({ owner: item.owner || '未分配', type: '操作包负责人附件', title: 'proof-gap 操作包负责人附件', priority: Number(item.topPriority || 0), status: Number(item.actionCount || 0) > 0 ? 'actions_open' : 'empty', mainFile: item.markdown || '', csv: item.csv || '', repairFile: item.csv || '', actionCount: Number(item.actionCount || 0), command: '打开负责人附件,按 gapId 补齐当前证据和下一步动作后重新运行 proof-gap:operator-pack 与 round:refresh', expectedArtifact: [item.markdown, item.csv].filter(Boolean).join(';'), acceptance: [ `actionCount=${Number(item.actionCount || 0)}`, `evidenceRowCount=${Number(item.evidenceRowCount || 0)}`, `nextActionCount=${Number(item.nextActionCount || 0)}`, `gapIds=${(item.gapIds || []).join(';') || 'none'}` ].join(';'), boundary: '负责人附件只用于补证派工,不证明客户效果' })); } function buildFieldChecklistOwnerRows(root, fieldChecklistDir, fieldChecklist) { const groups = Array.isArray(fieldChecklist?.ownerGroups) ? fieldChecklist.ownerGroups : []; return groups.map((group, index) => ({ owner: group.owner || '未分配', type: '字段补齐负责人', title: `${sectionLabel(group.section)}字段补齐`, priority: index + 1, status: Number(group.missingRequiredCount || 0) > 0 || Number(group.placeholderCount || 0) > 0 ? 'actions_open' : 'ready', mainFile: rel(root, path.join(fieldChecklistDir, 'intake-field-checklist.md')), csv: rel(root, path.join(fieldChecklistDir, 'intake-field-checklist.csv')), repairFile: Array.isArray(group.files) ? group.files.join(';') : '', actionCount: Number(group.itemCount || 0), command: group.nextAction || '按字段核对表补齐真实材料', expectedArtifact: Array.isArray(group.files) ? group.files.join(';') : rel(root, path.join(fieldChecklistDir, 'intake-field-checklist-summary.json')), acceptance: [ `字段项=${Number(group.itemCount || 0)}`, `缺必填=${Number(group.missingRequiredCount || 0)}`, `占位=${Number(group.placeholderCount || 0)}`, group.acceptance || '' ].filter(Boolean).join(';'), boundary: group.boundary || '补齐材料,不证明客户效果' })); } function buildFieldChecklistRecheckRows(root, fieldChecklistDir, fieldChecklist) { const commands = Array.isArray(fieldChecklist?.recheckCommands) ? fieldChecklist.recheckCommands : []; return commands.map((item, index) => ({ owner: item.owner || '技术/AI', type: '补齐后复验命令', title: item.stage || `复验命令 ${index + 1}`, priority: index + 1, status: 'pending_after_fill', mainFile: rel(root, path.join(fieldChecklistDir, 'intake-field-checklist.md')), csv: rel(root, path.join(fieldChecklistDir, 'intake-field-checklist.csv')), repairFile: '', actionCount: 1, command: item.command || '', expectedArtifact: rel(root, path.join(fieldChecklistDir, 'intake-field-checklist-summary.json')), acceptance: item.acceptance || '复验命令通过', boundary: item.boundary || '复验通过不证明客户效果' })); } function buildPrimaryFileRows(root, latestFormDir, latestForm, proofForm, fieldChecklistDir, fieldChecklist, longRunReadinessDir, longRunReadiness, optimizationCompletionDir, optimizationCompletion) { const rows = []; if (latestForm?.primaryForm?.csv || proofForm) { rows.push({ owner: '商务', type: '关键文件', title: '最新提号补证表单', priority: 0, status: proofForm?.passed ? 'pass' : 'not_ready', mainFile: latestForm?.primaryForm?.csv || 'outputs/tihao-proof-gap-software-form-latest/tihao-proof-gap-software-form.csv', csv: latestForm?.primaryForm?.csv || '', repairFile: '', actionCount: Number(proofForm?.rowCount || 0), command: '打开 CSV 分派补证任务', expectedArtifact: latestForm?.primaryForm?.summary || '', acceptance: `rowCount=${Number(proofForm?.rowCount || 0)},duplicateId=${Number(proofForm?.duplicateIdCount || 0)}`, boundary: '补证表单不证明客户效果' }); } if (latestForm?.clientList?.csv) { rows.push({ owner: '商务', type: '关键文件', title: '最新软件端候选名单', priority: 0, status: latestForm.clientList.exists === false ? 'missing' : 'ready', mainFile: latestForm.clientList.csv, csv: latestForm.clientList.csv, repairFile: '', actionCount: Number(latestForm.clientList.rowCount || 0), command: '用于商务复核候选博主', expectedArtifact: latestForm.clientList.summary || '', acceptance: `候选行数=${Number(latestForm.clientList.rowCount || 0)},仍需人工复核和客户反馈`, boundary: '候选名单不证明命中率提升' }); } if (fieldChecklist?.passed) { rows.push({ owner: '商务', type: '关键文件', title: '真实材料字段级补齐核对表', priority: 0, status: Number(fieldChecklist.itemCount || 0) > 0 ? 'actions_open' : 'empty', mainFile: rel(root, path.join(fieldChecklistDir, 'intake-field-checklist.md')), csv: rel(root, path.join(fieldChecklistDir, 'intake-field-checklist.csv')), repairFile: rel(root, path.join(fieldChecklistDir, 'intake-field-checklist.csv')), actionCount: Number(fieldChecklist.itemCount || 0), command: '按字段级核对表逐格补齐真实材料后重新运行 round:refresh', expectedArtifact: rel(root, path.join(fieldChecklistDir, 'intake-field-checklist-summary.json')), acceptance: `itemCount=${Number(fieldChecklist.itemCount || 0)},placeholder=${Number(fieldChecklist.placeholderCount || 0)},missingRequired=${Number(fieldChecklist.missingRequiredCount || 0)}`, boundary: '字段级核对表只指导补齐材料,不证明客户效果' }); } if (longRunReadiness || fs.existsSync(path.join(longRunReadinessDir, 'long-run-readiness-report.md'))) { const failCount = Number(longRunReadiness?.counts?.fail ?? longRunReadiness?.failCount ?? 0); rows.push({ owner: '技术/AI', type: '关键文件', title: '长跑前置门禁报告', priority: 0, status: longRunReadiness?.ready ? 'ready' : 'blocked', mainFile: rel(root, path.join(longRunReadinessDir, 'long-run-readiness-report.md')), csv: '', repairFile: '', actionCount: failCount, command: '补齐真实材料后运行 longrun:readiness,再判断是否允许启动 full-matrix/live 长跑', expectedArtifact: rel(root, path.join(longRunReadinessDir, 'long-run-readiness-summary.json')), acceptance: `ready=${Boolean(longRunReadiness?.ready)},failCount=${failCount};ready=true 且 failCount=0 后才允许进入真实 live/provider 长跑启动判断。`, boundary: '长跑前置门禁只判断启动条件,不证明客户效果;ready=false 时不能启动或宣称 full-matrix/live 长跑完成。' }); } if (optimizationCompletion || fs.existsSync(path.join(optimizationCompletionDir, 'optimization-completion-report.md'))) { const blockingReasonCount = Number(optimizationCompletion?.blockingReasonCount ?? (Array.isArray(optimizationCompletion?.blockingReasons) ? optimizationCompletion.blockingReasons.length : 0)); const missingProofRequirementCount = Number(optimizationCompletion?.missingProofRequirementCount ?? uniqueMissingProofRequirementCount(optimizationCompletion?.blockingReasons)); const proofGapOpenCount = Number(optimizationCompletion?.proofGapOpenCount || 0); const videoAbPreflightReadyForVideoAb = Boolean(optimizationCompletion?.videoAbPreflightReadyForVideoAb); const videoAbPreflightFailureCount = Number.isFinite(Number(optimizationCompletion?.videoAbPreflightFailureCount)) ? Number(optimizationCompletion.videoAbPreflightFailureCount) : null; rows.push({ owner: '技术/AI', type: '关键文件', title: '优化完成度审计报告', priority: 0, status: optimizationCompletion?.readyForClaim ? 'ready_for_claim' : 'blocked', mainFile: rel(root, path.join(optimizationCompletionDir, 'optimization-completion-report.md')), csv: '', repairFile: '', actionCount: blockingReasonCount, command: '补齐真实材料和证明缺口后运行 optimization:completion,再判断是否允许声明长期目标完成', expectedArtifact: rel(root, path.join(optimizationCompletionDir, 'optimization-completion-summary.json')), acceptance: `complete=${Boolean(optimizationCompletion?.complete)},readyForClaim=${Boolean(optimizationCompletion?.readyForClaim)},proofGapOpenCount=${proofGapOpenCount},blockingReasons=${blockingReasonCount},missingProofRequirementCount=${missingProofRequirementCount},videoAbPreflightReadyForVideoAb=${videoAbPreflightReadyForVideoAb},videoAbPreflightFailureCount=${videoAbPreflightFailureCount ?? 'unknown'}`, boundary: '优化完成度审计只判断能否进入完成声明,不证明客户效果;readyForClaim=false 时不得宣称提号率提升、客户效果达标或人工补号量下降。' }); } if (latestForm?.handoff?.report) { rows.push({ owner: '技术/AI', type: '关键文件', title: '下一轮交接摘要', priority: 0, status: latestForm.handoff.complete ? 'complete_reported' : 'incomplete_reported', mainFile: latestForm.handoff.report, csv: '', repairFile: '', actionCount: 1, command: '下一轮 AI 先读 handoff 和本执行总表', expectedArtifact: latestForm.handoff.summary || '', acceptance: `handoff.complete=${Boolean(latestForm.handoff.complete)}`, boundary: '交接摘要不证明客户效果' }); } else if (fs.existsSync(path.join(latestFormDir, 'latest-form-index.md'))) { rows.push({ owner: '技术/AI', type: '关键文件', title: '最新表单索引', priority: 0, status: latestForm?.passed ? 'pass' : 'not_ready', mainFile: rel(root, path.join(latestFormDir, 'latest-form-index.md')), csv: '', repairFile: '', actionCount: 1, command: '定位最新补证表单、候选名单和负责人文件', expectedArtifact: rel(root, path.join(latestFormDir, 'latest-form-index-summary.json')), acceptance: `latestFormIndex.passed=${Boolean(latestForm?.passed)}`, boundary: '索引不证明客户效果' }); } return rows; } function renderReport(summary) { const lines = [ '# 商务补证执行总表', '', `- 生成时间:${summary.generatedAt}`, `- 是否通过:${summary.passed ? '是' : '否'}`, `- 当前状态:${summary.status}`, `- 未关闭证明缺口:${summary.proofOpenCount}`, `- 行数:${summary.rowCount}`, '', '## 执行总表', '', '| 负责人 | 类型 | 标题 | 优先级 | 状态 | 主文件 | 修复清单 | 动作数 | 验收标准 | 边界 |', '| --- | --- | --- | ---: | --- | --- | --- | ---: | --- | --- |', ...summary.rows.map(row => tableRow([ row.owner, row.type, row.title, row.priority, row.status, row.mainFile || row.csv || '', row.repairFile || '', row.actionCount, row.acceptance, row.boundary ])), '', '## 来源', '', ...Object.entries(summary.sourceFiles).map(([key, value]) => `- ${key}:${value || '缺失'}`), '', '## 防误用边界', '', ...summary.guardrails.map(item => `- ${item}`) ]; return lines.join('\n'); } function renderCsv(rows) { const headers = ['负责人', '类型', '标题', '优先级', '状态', '主文件', '负责人CSV', '修复清单', '动作数', '命令/动作', '预期产物', '验收标准', '边界']; return [ headers.join(','), ...rows.map(row => [ row.owner, row.type, row.title, row.priority, row.status, row.mainFile, row.csv, row.repairFile, row.actionCount, row.command, row.expectedArtifact, row.acceptance, row.boundary ].map(csvCell).join(',')) ].join('\n'); } function appendMissingProofRequirements(acceptance, missingProofRequirements) { const items = Array.isArray(missingProofRequirements) ? missingProofRequirements.filter(Boolean) : []; if (!items.length) return acceptance; return `${acceptance}${acceptance ? ';' : ''}缺失证明:${items.join(';')}`; } function normalizeProofBoundary(boundary) { const text = String(boundary || '').trim(); const fallback = '不证明客户效果'; if (!text) return fallback; if (text.includes('不证明') || text.includes('不能证明')) return text; if (text.includes('不得宣称') || text.includes('不得宣布') || text.includes('只证明')) { return `${text};${fallback}`; } return `${text};${fallback}`; } function uniqueMissingProofRequirementCount(rows) { if (!Array.isArray(rows)) return 0; const values = new Set(); for (const row of rows) { const requirements = Array.isArray(row.missingProofRequirements) ? row.missingProofRequirements : []; for (const requirement of requirements) { if (requirement) values.add(String(requirement)); } } return values.size; } function sectionLabel(section) { const value = String(section || ''); if (value === 'history') return '历史 Brief'; if (value === 'video') return '视频资源'; if (value === 'review') return '商务复核'; return value || '真实材料'; } function findOwnerArtifact(summary, owner) { return (summary?.ownerArtifacts || []).find(item => item.owner === owner); } function normalizeProofGapOperatorOwnerArtifacts(root, dir, summary) { const artifacts = Array.isArray(summary?.ownerArtifacts) ? summary.ownerArtifacts : []; return artifacts.map(item => ({ owner: item.owner || '', actionCount: Number(item.actionCount || 0), topPriority: Number(item.topPriority || 0), markdown: artifactRef(root, dir, item.markdown || ''), csv: artifactRef(root, dir, item.csv || ''), gapIds: Array.isArray(item.gapIds) ? item.gapIds.filter(Boolean) : [], evidenceRowCount: Number(item.evidenceRowCount || 0), nextActionCount: Number(item.nextActionCount || 0) })); } function artifactRef(root, dir, file) { const value = String(file || '').replace(/\\/g, '/'); if (!value) return ''; if (path.isAbsolute(file)) return rel(root, file); if (value.startsWith('outputs/')) return value; return rel(root, path.join(dir, file)); } function pickDir(outputsDir, latestName, pattern) { const latest = path.join(outputsDir, latestName); if (fs.existsSync(latest)) return latest; if (!fs.existsSync(outputsDir)) return latest; const dirs = fs.readdirSync(outputsDir, { withFileTypes: true }) .filter(entry => entry.isDirectory() && pattern.test(entry.name)) .map(entry => path.join(outputsDir, entry.name)) .sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs); return dirs[0] || latest; } function readJson(file) { if (!fs.existsSync(file)) return null; return JSON.parse(fs.readFileSync(file, 'utf8').replace(/^\uFEFF/, '')); } function rel(root, file) { return file ? path.relative(root, file).replace(/\\/g, '/') : ''; } function tableRow(cells) { return `| ${cells.map(escapeCell).join(' | ')} |`; } function escapeCell(value) { return String(value ?? '').replace(/\|/g, '/').replace(/\r?\n/g, ' '); } function csvCell(value) { const text = String(value ?? ''); return /[",\r\n]/.test(text) ? `"${text.replace(/"/g, '""')}"` : text; } function parseArgs(argv) { const result = {}; for (let index = 0; index < argv.length; index += 1) { const arg = argv[index]; if (!arg.startsWith('--')) continue; const key = arg.slice(2).replace(/-([a-z])/g, (_, char) => char.toUpperCase()); const next = argv[index + 1]; if (!next || next.startsWith('--')) result[key] = true; else { result[key] = next; index += 1; } } return result; } function withBom(text) { return `\uFEFF${text}`; } if (require.main === module) main(); module.exports = { buildBusinessExecutionIndex };