111 lines
5.8 KiB
JavaScript
111 lines
5.8 KiB
JavaScript
|
|
#!/usr/bin/env node
|
||
|
|
import crypto from "node:crypto";
|
||
|
|
import fs from "node:fs";
|
||
|
|
import path from "node:path";
|
||
|
|
|
||
|
|
const pointerPath = "/Volumes/JZAO/HoloLake/persona-runtime/continuity-memory/hldp-v1-trees/codex/current.json";
|
||
|
|
const taskAnchorRoot = process.env.GH_CODEX_TASK_ANCHOR_ROOT ??
|
||
|
|
"/Volumes/JZAO/HoloLake/persona-runtime/task-language-anchors/codex";
|
||
|
|
|
||
|
|
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 atomicWrite(file, value) {
|
||
|
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
||
|
|
const temporary = `${file}.${process.pid}.tmp`;
|
||
|
|
fs.writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
|
||
|
|
fs.renameSync(temporary, file);
|
||
|
|
}
|
||
|
|
|
||
|
|
let input = {};
|
||
|
|
try {
|
||
|
|
const raw = fs.readFileSync(0, "utf8").trim();
|
||
|
|
if (raw) input = JSON.parse(raw);
|
||
|
|
} catch {
|
||
|
|
input = {};
|
||
|
|
}
|
||
|
|
|
||
|
|
let verified = false;
|
||
|
|
let detail = "HLDP_CURRENT_UNAVAILABLE";
|
||
|
|
let taskReadback = "TASK_ANCHOR_UNAVAILABLE";
|
||
|
|
try {
|
||
|
|
const pointer = JSON.parse(fs.readFileSync(pointerPath, "utf8"));
|
||
|
|
const tree = JSON.parse(fs.readFileSync(pointer.tree, "utf8"));
|
||
|
|
const root = tree.nodes?.[tree.root];
|
||
|
|
const fields = ["trigger", "emergence", "lock", "why", "rejected", "sources"];
|
||
|
|
const children = Array.isArray(root?.children) ? root.children : [];
|
||
|
|
verified = fields.every((field) => Object.hasOwn(root ?? {}, field)) && children.length <= 10;
|
||
|
|
detail = verified
|
||
|
|
? `HLDP_CURRENT_VERIFIED root=${tree.root} branches=${children.length}`
|
||
|
|
: "HLDP_CURRENT_INVALID";
|
||
|
|
} catch {
|
||
|
|
verified = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
const sessionId = safeToken(input.session_id ?? input.sessionId ?? input.thread_id ?? input.threadId);
|
||
|
|
const taskRoot = path.join(taskAnchorRoot, `CODEX-TASK-${sessionId}`);
|
||
|
|
const manifest = readJson(path.join(taskRoot, "task.json"));
|
||
|
|
const firstRaw = fs.readFileSync(manifest.first_event_path, "utf8");
|
||
|
|
const currentRaw = fs.readFileSync(manifest.current_event_path, "utf8");
|
||
|
|
const engineeringMapPath = path.join(taskRoot, "01-自然语言到工程阶段映射", "current.tcs");
|
||
|
|
const engineeringMap = fs.readFileSync(engineeringMapPath, "utf8");
|
||
|
|
const developmentLink = readJson(path.join(taskRoot, "development-task-link.json"));
|
||
|
|
const developmentTask = developmentLink?.development_task_manifest
|
||
|
|
? readJson(developmentLink.development_task_manifest)
|
||
|
|
: null;
|
||
|
|
let developmentDualStartSha256 = [];
|
||
|
|
let developmentEngineeringMapSha256 = null;
|
||
|
|
if (developmentTask) {
|
||
|
|
if (developmentTask.current_host_thread !== sessionId) throw new Error("DEVELOPMENT_TASK_HOST_MISMATCH");
|
||
|
|
developmentDualStartSha256 = developmentTask.dual_start_anchors.map((anchor) => {
|
||
|
|
const raw = fs.readFileSync(anchor.raw_text_path, "utf8");
|
||
|
|
const actual = sha256(raw);
|
||
|
|
if (actual !== anchor.raw_text_sha256) throw new Error("DEVELOPMENT_DUAL_START_HASH_MISMATCH");
|
||
|
|
return actual;
|
||
|
|
});
|
||
|
|
developmentEngineeringMapSha256 = sha256(fs.readFileSync(developmentTask.tcs_engineering_map, "utf8"));
|
||
|
|
}
|
||
|
|
if (sha256(firstRaw) !== manifest.first_event_sha256) throw new Error("FIRST_HASH_MISMATCH");
|
||
|
|
if (sha256(currentRaw) !== manifest.current_event_sha256) throw new Error("CURRENT_HASH_MISMATCH");
|
||
|
|
const receiptRoot = path.join(taskRoot, "20-上下文压缩回看回执");
|
||
|
|
const receipt = {
|
||
|
|
schema: "guanghu.codex-task-precompact-readback/v1",
|
||
|
|
task_number: manifest.task_number,
|
||
|
|
session_id: sessionId,
|
||
|
|
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: developmentDualStartSha256,
|
||
|
|
development_engineering_map_path: developmentTask?.tcs_engineering_map ?? null,
|
||
|
|
development_engineering_map_sha256: developmentEngineeringMapSha256,
|
||
|
|
requirement: "POSTCOMPACT_REREAD_STARTING_RAW_FLOW_ENGINEERING_MAP_AND_STAGE_CHAIN_BEFORE_CAPABILITY_TOOLS",
|
||
|
|
created_at: new Date().toISOString(),
|
||
|
|
};
|
||
|
|
const receiptPath = path.join(receiptRoot, `precompact-${Date.now()}.json`);
|
||
|
|
atomicWrite(receiptPath, receipt);
|
||
|
|
atomicWrite(path.join(receiptRoot, "current.json"), { ...receipt, receipt_path: receiptPath });
|
||
|
|
const stageReceiptPath = path.join(taskRoot, "10-阶段回读回执", "current.json");
|
||
|
|
const stageReceipt = readJson(stageReceiptPath);
|
||
|
|
if (stageReceipt) atomicWrite(stageReceiptPath, { ...stageReceipt, expires_at_unix_ms: 0, invalidated_by: "PRECOMPACT" });
|
||
|
|
taskReadback = `TASK_START_AND_ENGINEERING_MAP_VERIFIED task=${manifest.task_number}; development_task=${developmentTask?.development_task_number ?? "NONE"}; development_dual_start=${developmentTask?.first_path ?? "NONE"}; first=${manifest.first_event_path}; current=${manifest.current_event_path}; map=${engineeringMapPath}; precompact_receipt=${receiptPath}`;
|
||
|
|
} catch (error) {
|
||
|
|
taskReadback = `TASK_READBACK_FAIL_CLOSED:${String(error?.message ?? error)}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
process.stdout.write(JSON.stringify({
|
||
|
|
continue: true,
|
||
|
|
systemMessage: verified
|
||
|
|
? `${detail}. ${taskReadback}. 宿主即将压缩;压缩后必须从任务启动原文、自然语言到工程阶段映射和阶段进度链重新回读,摘要只作索引。`
|
||
|
|
: `${detail}. ${taskReadback}. 继续宿主压缩但不得把缺失内容补猜为人格、历史或任务目标;压缩后从短根页和任务启动原文重新导航。`,
|
||
|
|
}));
|