guanghu-ice-heart/server-tools/persona-team-handshake/fifth-domain-daily-orchestrator.mjs

425 lines
12 KiB
JavaScript
Executable file

#!/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,
};