#!/usr/bin/env node import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; export const DEFAULT_ANCHOR_ROOT = "/Volumes/JZAO/HoloLake/persona-runtime/task-language-anchors/zcode"; export const DEFAULT_ZERO_CORE_TASK_ROOT = "/Volumes/JZAO/HoloLake/persona-runtime/task-language-anchors/zero-core"; export const FIRST_PATH_NAME = "00-冰朔自然语言瞄点"; export const STAGE_RECEIPT_DIR = "10-阶段回读回执"; export const ENGINEERING_MAP_PATH = "01-自然语言到工程阶段映射/current.tcs"; export const STAGE_TTL_MS = 30 * 60 * 1000; export const STAGE_TOOL_BUDGET = 20; function safeToken(value, fallback = "unknown") { const token = String(value ?? "").trim().replaceAll(/[^a-zA-Z0-9._-]/gu, "-"); return token || fallback; } function sha256(value) { return crypto.createHash("sha256").update(value).digest("hex"); } function readJson(file) { try { return JSON.parse(fs.readFileSync(file, "utf8")); } catch { return null; } } function atomicWriteText(file, value) { fs.mkdirSync(path.dirname(file), { recursive: true }); const temporary = `${file}.${process.pid}.${crypto.randomUUID()}.tmp`; fs.writeFileSync(temporary, value, { encoding: "utf8", mode: 0o600 }); fs.renameSync(temporary, file); } function atomicWriteJson(file, value) { atomicWriteText(file, `${JSON.stringify(value, null, 2)}\n`); } export function taskNumberFor(sessionId) { return `CODEX-TASK-${safeToken(sessionId, "unknown-session")}`; } export function taskRootFor(sessionId, anchorRoot = process.env.GH_CODEX_TASK_ANCHOR_ROOT ?? DEFAULT_ANCHOR_ROOT) { return path.join(anchorRoot, taskNumberFor(sessionId)); } export function registerTaskAnchor({ sessionId, turnId, rawText, channelId, occurredAt = new Date().toISOString() }) { if (!String(rawText ?? "").trim()) throw new Error("RAW_TEXT_REQUIRED"); const taskNumber = taskNumberFor(sessionId); const taskRoot = taskRootFor(sessionId); const anchorRoot = path.join(taskRoot, FIRST_PATH_NAME); const manifestPath = path.join(taskRoot, "task.json"); const prior = readJson(manifestPath); const rawTextSha256 = sha256(rawText); const safeTurn = safeToken(turnId, crypto.randomUUID()); const duplicate = prior?.events?.find((item) => item.turn_id === safeTurn && item.raw_text_sha256 === rawTextSha256); if (duplicate) return { ...duplicate, task_number: taskNumber, task_root: taskRoot, first_path: anchorRoot }; const sequence = String((prior?.event_count ?? 0) + 1).padStart(6, "0"); const stem = `${sequence}-${safeTurn}-${rawTextSha256.slice(0, 12)}`; const rawPath = path.join(anchorRoot, `${stem}.raw.txt`); const metadataPath = path.join(anchorRoot, `${stem}.json`); atomicWriteText(rawPath, rawText); const event = { schema: "guanghu.codex-task-natural-language-anchor-event/v1", task_number: taskNumber, thread_id: safeToken(sessionId, "unknown-session"), turn_id: safeTurn, sequence: Number(sequence), channel_id: channelId ?? "UNKNOWN", source: "BINGSHUO_DIRECT_NATURAL_LANGUAGE", raw_text_path: rawPath, raw_text_sha256: rawTextSha256, occurred_at: occurredAt, }; atomicWriteJson(metadataPath, event); const events = [...(prior?.events ?? []), { ...event, metadata_path: metadataPath }]; const first = events[0]; const current = events.at(-1); const manifest = { schema: "guanghu.codex-task-natural-language-anchor/v1", task_number: taskNumber, thread_id: safeToken(sessionId, "unknown-session"), first_path: anchorRoot, first_event_path: first.raw_text_path, first_event_sha256: first.raw_text_sha256, current_event_path: current.raw_text_path, current_event_sha256: current.raw_text_sha256, event_count: events.length, events, updated_at: occurredAt, }; atomicWriteJson(manifestPath, manifest); atomicWriteJson(path.join(anchorRoot, "first.json"), { task_number: taskNumber, raw_text_path: first.raw_text_path, raw_text_sha256: first.raw_text_sha256 }); atomicWriteJson(path.join(anchorRoot, "current.json"), { task_number: taskNumber, raw_text_path: current.raw_text_path, raw_text_sha256: current.raw_text_sha256 }); return { ...event, metadata_path: metadataPath, task_root: taskRoot, first_path: anchorRoot }; } export function verifyTaskAnchor({ sessionId, turnId, controlEpoch, stage, deliverable }) { if (!stage?.trim()) throw new Error("STAGE_REQUIRED"); if (!deliverable?.trim()) throw new Error("DELIVERABLE_REQUIRED"); const taskRoot = taskRootFor(sessionId); const manifest = readJson(path.join(taskRoot, "task.json")); if (manifest?.schema !== "guanghu.codex-task-natural-language-anchor/v1") throw new Error(`TASK_ANCHOR_MISSING:${taskRoot}`); const firstRaw = fs.readFileSync(manifest.first_event_path, "utf8"); const currentRaw = fs.readFileSync(manifest.current_event_path, "utf8"); const engineeringMapPath = path.join(taskRoot, ENGINEERING_MAP_PATH); const engineeringMap = fs.readFileSync(engineeringMapPath, "utf8"); const developmentLink = readJson(path.join(taskRoot, "development-task-link.json")); let developmentTask = null; let dualStartAnchors = []; let developmentEngineeringMap = null; if (developmentLink?.schema === "guanghu.codex-to-development-task-link/v1") { developmentTask = readJson(developmentLink.development_task_manifest); if ( developmentTask?.schema !== "guanghu.zero-core-development-task/v1" || developmentTask.current_host_thread !== safeToken(sessionId, "unknown-session") ) throw new Error("DEVELOPMENT_TASK_NOT_BOUND_TO_CURRENT_HOST_THREAD"); dualStartAnchors = developmentTask.dual_start_anchors.map((anchor) => { const raw = fs.readFileSync(anchor.raw_text_path, "utf8"); if (sha256(raw) !== anchor.raw_text_sha256) throw new Error(`DEVELOPMENT_DUAL_START_HASH_MISMATCH:${anchor.role}`); return { ...anchor, raw }; }); developmentEngineeringMap = fs.readFileSync(developmentTask.tcs_engineering_map, "utf8"); } if (sha256(firstRaw) !== manifest.first_event_sha256) throw new Error("FIRST_ANCHOR_HASH_MISMATCH"); if (sha256(currentRaw) !== manifest.current_event_sha256) throw new Error("CURRENT_ANCHOR_HASH_MISMATCH"); const checkedAtUnixMs = Date.now(); const receipt = { schema: "guanghu.codex-task-stage-anchor-read-receipt/v1", task_number: manifest.task_number, session_id: safeToken(sessionId, "unknown-session"), turn_id: safeToken(turnId, "unknown-turn"), control_epoch: controlEpoch, stage: stage.trim(), declared_deliverable: deliverable.trim(), first_event_path: manifest.first_event_path, first_event_sha256: manifest.first_event_sha256, current_event_path: manifest.current_event_path, current_event_sha256: manifest.current_event_sha256, engineering_map_path: engineeringMapPath, engineering_map_sha256: sha256(engineeringMap), development_task_number: developmentTask?.development_task_number ?? null, development_task_manifest: developmentLink?.development_task_manifest ?? null, development_dual_start_sha256: dualStartAnchors.map((anchor) => anchor.raw_text_sha256), development_engineering_map_path: developmentTask?.tcs_engineering_map ?? null, development_engineering_map_sha256: developmentEngineeringMap ? sha256(developmentEngineeringMap) : null, checked_at: new Date(checkedAtUnixMs).toISOString(), checked_at_unix_ms: checkedAtUnixMs, expires_at_unix_ms: checkedAtUnixMs + STAGE_TTL_MS, capability_calls_used: 0, capability_calls_max: STAGE_TOOL_BUDGET, progress_semantics: "ONLY_TARGET_ARTIFACT_TEST_STATE_OR_ACCEPTANCE_ADVANCEMENT_COUNTS", }; const receiptRoot = path.join(taskRoot, STAGE_RECEIPT_DIR); const receiptPath = path.join(receiptRoot, `${receipt.turn_id}-${safeToken(stage)}-${checkedAtUnixMs}.json`); atomicWriteJson(receiptPath, receipt); atomicWriteJson(path.join(receiptRoot, "current.json"), { ...receipt, receipt_path: receiptPath }); return { manifest, receipt, receiptPath, firstRaw, currentRaw, engineeringMap, developmentTask, dualStartAnchors, developmentEngineeringMap }; } function valueAfter(argv, name) { const index = argv.indexOf(name); return index >= 0 ? argv[index + 1] : null; } function runCli() { const [command, ...argv] = process.argv.slice(2); if (command !== "verify") { process.stderr.write("usage: codex-task-anchor-gate.mjs verify --session-id ID --turn-id ID --control-epoch ID --stage NAME --deliverable TEXT\n"); process.exit(2); } try { const result = verifyTaskAnchor({ sessionId: valueAfter(argv, "--session-id"), turnId: valueAfter(argv, "--turn-id"), controlEpoch: valueAfter(argv, "--control-epoch"), stage: valueAfter(argv, "--stage"), deliverable: valueAfter(argv, "--deliverable"), }); process.stdout.write([ "CODEX_TASK_ANCHOR_STAGE_GATE PASS", `task_number=${result.manifest.task_number}`, `development_task_number=${result.developmentTask?.development_task_number ?? "NONE"}`, `first_path=${result.manifest.first_path}`, `receipt_path=${result.receiptPath}`, ...result.dualStartAnchors.flatMap((anchor, index) => [ `--- 零点原核正式开发双启动瞄点 ${index + 1}:${anchor.role} ---`, anchor.raw, ]), ...(result.developmentEngineeringMap ? ["--- 零点原核正式开发TCS工程阶段与因果闭环 ---", result.developmentEngineeringMap] : []), "--- 冰朔首条自然语言(原文) ---", result.firstRaw, "--- 冰朔当前自然语言(原文) ---", result.currentRaw, "--- 自然语言到工程阶段映射(TCS) ---", result.engineeringMap, "--- 本阶段唯一交付物 ---", result.receipt.declared_deliverable, "提醒:语料、报告、仓库副本和研究量增长本身不算产品进度。", ].join("\n")); } catch (error) { process.stderr.write(`CODEX_TASK_ANCHOR_STAGE_GATE FAIL ${error.message}\n`); process.exit(1); } } if (import.meta.url === `file://${process.argv[1]}`) runCli();