From 4da4ceaf40aab7811d8427eb430dda6f380dd892 Mon Sep 17 00:00:00 2001 From: WuYongJie <549727955@qq.com> Date: Tue, 13 Oct 2026 14:47:22 +0800 Subject: [PATCH] feat: attach complete inventory check to progress sync --- scripts/kaifa-progress-sync.mjs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/scripts/kaifa-progress-sync.mjs b/scripts/kaifa-progress-sync.mjs index 2bdbde7..39454c7 100644 --- a/scripts/kaifa-progress-sync.mjs +++ b/scripts/kaifa-progress-sync.mjs @@ -26,6 +26,21 @@ export function validateOptions(options) { if (options.get('status') === 'done' && !options.get('completion-evidence')) throw new Error('done 必须提供 --completion-evidence') } +// 平台要求每次推送携带与线上目录逐项一致的完整功能清单(inventory_check)。 +// 文件由全量盘点脚本按 progress-sync GET 回读的最终状态生成,禁止手改占位。 +export async function readInventoryCheck(options) { + const path = options.get('inventory') + if (!path) return undefined + const parsed = JSON.parse(await readFile(resolve(path), 'utf8')) + if (!Array.isArray(parsed) || parsed.length === 0) throw new Error('--inventory 文件必须是包含全部功能的非空数组') + for (const item of parsed) { + for (const field of ['module_id', 'module_name', 'feature_id', 'feature_name', 'feature_description', 'status', 'progress_percent']) { + if (item[field] === undefined) throw new Error(`--inventory 条目缺少字段 ${field}`) + } + } + return parsed +} + export function buildIdempotencyKey(sha, status) { return `gongxiangp2-${sha}-${status}` } @@ -110,7 +125,7 @@ function readCommit(revision, target, config) { export async function main(argv = process.argv.slice(2)) { const options = parseArgs(argv) if (options.get('help')) { - console.log('用法: npm run progress:sync -- --module <模块> --feature <子功能> --status --summary <摘要> [--test-status passed] [--completion-evidence <证据>] [--resolve] [--apply]') + console.log('用法: npm run progress:sync -- --module <模块> --feature <子功能> --status --summary <摘要> [--test-status passed] [--completion-evidence <证据>] [--technical-summary <实现说明>] [--next-steps <下一步>] [--inventory <清单文件>] [--resolve] [--apply]') return } validateOptions(options) @@ -131,6 +146,8 @@ export async function main(argv = process.argv.slice(2)) { ...(options.get('next-steps') ? { next_steps: options.get('next-steps') } : {}), } const payload = { context: { department: config.DEPARTMENT, project: config.PROJECT, developer: config.DEVELOPER }, commits: [commit], updates: [update] } + const inventoryCheck = await readInventoryCheck(options) + if (inventoryCheck) payload.inventory_check = inventoryCheck if (!options.get('apply')) { console.log(JSON.stringify({ dryRun: true, sha: commit.sha, author: `${commit.author_name} <${commit.author_email}>`, module: options.get('module'), feature: options.get('feature'), status: options.get('status'), stats: commit.stats }, null, 2)) return