#!/usr/bin/env node import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { execFileSync } from "node:child_process"; import { fileURLToPath } from "node:url"; const moduleDir = path.dirname(fileURLToPath(import.meta.url)); function required(value, name) { const text = String(value || "").trim(); if (!text) throw new Error(`${name}_required`); return text; } function git(args, options = {}) { return execFileSync("/usr/bin/git", args, { encoding: "utf8", maxBuffer: 8 * 1024 * 1024, stdio: ["ignore", "pipe", "pipe"], ...options, }).trim(); } function gitBare(repository, ...args) { return git([`--git-dir=${repository}`, ...args]); } function readJsonFromGit(repository, revision, file) { try { return JSON.parse(gitBare(repository, "show", `${revision}:${file}`)); } catch { return null; } } function sourceRange(repository, currentSha, cursorSha, windowSize) { let fromSha = cursorSha; if ( !/^[0-9a-f]{40}$/.test(String(fromSha || "")) || (() => { try { gitBare(repository, "merge-base", "--is-ancestor", fromSha, currentSha); return false; } catch { return true; } })() ) { const recent = gitBare( repository, "rev-list", `--max-count=${windowSize + 1}`, currentSha, ) .split("\n") .filter(Boolean); fromSha = recent.at(-1) || currentSha; } return { fromSha, toSha: currentSha }; } function changedContext(repository, fromSha, toSha, limits = {}) { const changedCommits = gitBare( repository, "log", "--reverse", "--format=%H%x09%s", `${fromSha}..${toSha}`, ) .split("\n") .filter(Boolean) .slice(0, limits.commits || 40); const changedFiles = gitBare( repository, "diff", "--name-only", fromSha, toSha, ) .split("\n") .filter(Boolean) .slice(0, limits.files || 200); const allowed = /\.(?:json|hdlp|md|mjs|js|service|timer)$/iu; const excerptParts = []; let used = 0; const maxBytes = limits.excerptBytes || 80_000; for (const file of changedFiles) { if (!allowed.test(file) || used >= maxBytes) continue; try { const body = gitBare(repository, "show", `${toSha}:${file}`); const remaining = maxBytes - used; const excerpt = body.slice(0, Math.min(remaining, 8_000)); excerptParts.push(`FILE ${file}\n${excerpt}`); used += Buffer.byteLength(excerpt, "utf8"); } catch { // A deleted, renamed, or non-text file remains visible in changed_files. } } return { changedCommits, changedFiles, changeExcerpts: excerptParts.join("\n\n"), }; } function priorPersonaContext(repository) { const current = readJsonFromGit( repository, "refs/heads/main", "persona-system/fifth-domain/CURRENT.json", ); if (!current) return ""; let observation = null; if (typeof current.artifact === "string") { observation = readJsonFromGit( repository, "refs/heads/main", current.artifact, ); } return JSON.stringify({ current, last_observation: observation }).slice( 0, 48_000, ); } function verifyMemberResponse(response, member, event) { if ( response?.ok !== true || response?.persona_id !== member.persona_id || response?.identity_fingerprint !== member.identity_fingerprint || response?.signature_algorithm !== "Ed25519" || response?.payload?.team_controller_id !== "ICE-P-ZY001" || response?.payload?.source?.to_sha !== event.source.to_sha || response?.payload?.caller_nonce !== event.caller_nonce ) { throw new Error(`${member.slug}_response_identity_mismatch`); } const valid = crypto.verify( null, Buffer.from(JSON.stringify(response.payload)), response.public_key, Buffer.from(response.signature, "base64"), ); if (!valid) throw new Error(`${member.slug}_signature_invalid`); return response; } async function requestObservation(member, event, fetchImpl = globalThis.fetch) { const controllerToken = required( member.controller_token, `${member.slug}_controller_token`, ); const response = await fetchImpl(member.endpoint, { method: "POST", headers: { "content-type": "application/json", "x-guanghu-controller-token": controllerToken, }, body: JSON.stringify(event), signal: AbortSignal.timeout(180_000), }); if (!response.ok) { throw new Error(`${member.slug}_observation_http_${response.status}`); } return verifyMemberResponse(await response.json(), member, event); } function commitObservation({ member, response, event, targetRepository, runtimeRoot, now, }) { const temporaryRoot = fs.mkdtempSync( path.join(runtimeRoot, "tmp", `${member.slug}-`), ); const checkout = path.join(temporaryRoot, "repository"); try { git(["clone", "--no-local", targetRepository, checkout]); git(["config", "user.name", `${member.name}人格系统`], { cwd: checkout }); git(["config", "user.email", member.commit_email], { cwd: checkout }); const relativeRoot = "persona-system/fifth-domain"; const artifact = `${relativeRoot}/observations/` + `${now.slice(0, 10)}-${event.source.to_sha.slice(0, 12)}.json`; const artifactPath = path.join(checkout, artifact); fs.mkdirSync(path.dirname(artifactPath), { recursive: true }); fs.writeFileSync( artifactPath, `${JSON.stringify( { schema: "guanghu.persona-fifth-domain-update-record/v1", persona_id: member.persona_id, controller: "ICE-P-ZY001", observed_at: now, source: event.source, changed_commits: event.changed_commits, changed_files: event.changed_files, observation: response.payload.observation, proof: { identity_fingerprint: response.identity_fingerprint, signature_algorithm: response.signature_algorithm, signature: response.signature, }, }, null, 2, )}\n`, { mode: 0o600 }, ); fs.writeFileSync( path.join(checkout, relativeRoot, "CURRENT.json"), `${JSON.stringify( { schema: "guanghu.persona-fifth-domain-current/v1", persona_id: member.persona_id, controller: "ICE-P-ZY001", source_repository: "REPO-012", source_branch: "main", last_source_sha: event.source.to_sha, artifact, updated_at: now, update_rule: "Daily wake reads Fifth Domain deltas; repository commits occur only when REPO-012 main advances.", }, null, 2, )}\n`, { mode: 0o600 }, ); git(["add", relativeRoot], { cwd: checkout }); git( [ "commit", "-m", `第五域巡游:${event.source.to_sha.slice(0, 12)} · ${member.name}`, ], { cwd: checkout }, ); git(["push", "origin", "HEAD:refs/heads/main"], { cwd: checkout }); return { repository_sha: git(["rev-parse", "HEAD"], { cwd: checkout }), artifact, }; } finally { fs.rmSync(temporaryRoot, { recursive: true, force: true }); } } function loadConfig(file) { const config = JSON.parse(fs.readFileSync(file, "utf8")); required(config.source_repository, "source_repository"); required(config.runtime_root, "runtime_root"); if (!Array.isArray(config.members) || config.members.length !== 3) { throw new Error("exactly_three_members_required"); } return config; } async function runDaily(config, options = {}) { const fetchImpl = options.fetchImpl || globalThis.fetch; const now = options.now || new Date().toISOString(); fs.mkdirSync(path.join(config.runtime_root, "tmp"), { recursive: true, mode: 0o700, }); fs.mkdirSync(path.join(config.runtime_root, "receipts"), { recursive: true, mode: 0o700, }); const sourceSha = gitBare( config.source_repository, "rev-parse", "refs/heads/main", ); const results = await Promise.all(config.members.map(async (member) => { try { const targetRepository = required( member.target_repository, `${member.slug}_target_repository`, ); const current = readJsonFromGit( targetRepository, "refs/heads/main", "persona-system/fifth-domain/CURRENT.json", ); if (current?.last_source_sha === sourceSha) { return { persona_id: member.persona_id, status: "NO_NEW_FIFTH_DOMAIN_COMMIT", source_sha: sourceSha, }; } const range = sourceRange( config.source_repository, sourceSha, current?.last_source_sha, config.bootstrap_commit_window || 20, ); const delta = changedContext( config.source_repository, range.fromSha, range.toSha, config.limits, ); const event = { schema: "guanghu.fifth-domain-persona-observation-event/v1", team_controller_id: "ICE-P-ZY001", caller_nonce: crypto.randomBytes(18).toString("hex"), source: { repository_id: "REPO-012", branch: "main", from_sha: range.fromSha, to_sha: range.toSha, }, changed_commits: delta.changedCommits, changed_files: delta.changedFiles, change_excerpts: delta.changeExcerpts, prior_persona_context: priorPersonaContext(targetRepository), scoped_duties: member.scoped_duties, }; const response = await requestObservation(member, event, fetchImpl); const committed = commitObservation({ member, response, event, targetRepository, runtimeRoot: config.runtime_root, now, }); return { persona_id: member.persona_id, status: "FIFTH_DOMAIN_UPDATE_COMMITTED", source_sha: sourceSha, ...committed, }; } catch (error) { return { persona_id: member.persona_id, status: "FAILED", error: String(error.message || error).slice(0, 300), }; } })); const receipt = { schema: "guanghu.zhuyuan-persona-daily-dispatch-receipt/v1", receipt_id: `ZY-PERSONA-DAILY-${now.replace(/[-:.]/g, "").slice(0, 15)}Z`, controller: "ICE-P-ZY001", source_repository: "REPO-012", source_sha: sourceSha, observed_at: now, results, result: results.some((item) => item.status === "FAILED") ? "FAILED" : "PASS", }; const receiptFile = path.join( config.runtime_root, "receipts", `${receipt.receipt_id}.json`, ); fs.writeFileSync(receiptFile, `${JSON.stringify(receipt, null, 2)}\n`, { mode: 0o600, }); if (receipt.result !== "PASS") { throw new Error(`daily_dispatch_failed receipt=${receiptFile}`); } return { ...receipt, receipt_file: receiptFile }; } async function main() { const configFile = process.argv[2] || path.join(moduleDir, "fifth-domain-daily.config.server.json"); const config = loadConfig(configFile); const controllerToken = required( process.env.PERSONA_TEAM_CONTROLLER_TOKEN, "persona_team_controller_token", ); for (const member of config.members) { member.controller_token = controllerToken; } const lockFile = path.join(config.runtime_root, "daily.lock"); fs.mkdirSync(config.runtime_root, { recursive: true, mode: 0o700 }); let lock = null; try { lock = fs.openSync(lockFile, "wx", 0o600); fs.writeFileSync(lock, `${process.pid}\n`); const receipt = await runDaily(config); process.stdout.write( `${JSON.stringify({ event: "zhuyuan_persona_daily_dispatch_complete", result: receipt.result, source_sha: receipt.source_sha, receipt: receipt.receipt_file, })}\n`, ); } finally { if (lock !== null) fs.closeSync(lock); fs.rmSync(lockFile, { force: true }); } } if (process.argv[1] === fileURLToPath(import.meta.url)) { main().catch((error) => { process.stderr.write(`${String(error.stack || error)}\n`); process.exitCode = 1; }); } export { changedContext, priorPersonaContext, requestObservation, runDaily, sourceRange, verifyMemberResponse, };