← Files VeraARCHIVED FILE
modules/client-file-preparation/scripts/review_mcp_server.cjs
106 KB · Oct 5, 2026 · 18:29 UTC
"use strict";
const fs = require("node:fs");
const { spawnSync } = require("node:child_process");
const crypto = require("node:crypto");
const os = require("node:os");
const path = require("node:path");
const readline = require("node:readline");
const SERVER_NAME = "client-file-preparation-widgets";
const PLUGIN_ROOT = path.resolve(__dirname, "..");
const PLUGIN_MANIFEST = JSON.parse(
fs.readFileSync(path.join(PLUGIN_ROOT, ".codex-plugin", "plugin.json"), "utf8"),
);
const SERVER_VERSION = PLUGIN_MANIFEST.version || "0.1.0";
const WIDGET_URI = "ui://widget/client-file-preparation-review.html";
const WIDGET_MIME_TYPE = "text/html;profile=mcp-app";
const MAX_ITEMS = 2500;
const MAX_PAYLOAD_BYTES = 1_500_000;
const TOOL_NAMES = {
validateReview: "validate_client_file_preparation_review",
renderReview: "render_client_file_preparation_review",
saveDecisions: "save_client_file_preparation_decisions",
applyDecisions: "apply_client_file_preparation_decisions",
};
const ALLOWED_ACTIONS = new Set([
"accept",
"reject",
"edit",
"mark_unclear",
"request_more_documents",
"skip",
]);
const ACTION_STATUSES = {
accept: "accepted",
reject: "rejected",
edit: "edited",
mark_unclear: "needs_evidence",
request_more_documents: "needs_evidence",
skip: "skipped",
};
const MAX_DECISION_TEXT_LENGTH = 10_000;
const MAX_LOCAL_JSON_BYTES = 25_000_000;
const MAX_PERSISTENCE_CONTEXTS = 128;
const PERSISTENCE_CONTEXT_TTL_MS = 4 * 60 * 60 * 1000;
const PERSISTENCE_TOKEN_RE = /^[A-Za-z0-9_-]{43}$/;
const PERSISTENCE_CONTEXTS = new Map();
const PACKAGE_HASH_BASIS = "sorted_outputs_path_size_sha256_canonical_json_v1";
const MAX_REVIEWER_REFERENCE_LENGTH = 160;
const REVIEWER_REFERENCE_SECRET_RE =
/(?:password|passwd|api[_ -]?key|access[_ -]?token|refresh[_ -]?token|session[_ -]?(?:token|cookie)|authorization)\s*[:=]/i;
const REVIEWER_REFERENCE_CREDENTIAL_VALUE_RE =
/^(?:sk-[A-Za-z0-9_-]{16,}|eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.)/;
const PROTECTED_RUN_FILES = new Set([
"final_artifacts.json",
"review_payload.json",
"run_intake.json",
"ui_decisions.json",
"applied_decisions.json",
"model_handoff.json",
]);
const ITEM_TYPES = new Set([
"document_inventory",
"uncertain_file",
"missing_document_request",
"extracted_fiscal_field",
"duplicate_warning",
"formal_xml_anomaly",
"draft_memo_section",
"draft_client_email",
]);
function isProtectedRunFile(targetKey) {
return PROTECTED_RUN_FILES.has(targetKey) || targetKey.startsWith("model_handoff_pages/");
}
function isPlainObject(value) {
return value != null && typeof value === "object" && !Array.isArray(value);
}
function pythonExecutable() {
const virtualEnvironmentPython = process.env.VIRTUAL_ENV
? path.join(
process.env.VIRTUAL_ENV,
process.platform === "win32" ? "Scripts/python.exe" : "bin/python",
)
: "";
const repositoryPython = path.resolve(
PLUGIN_ROOT,
"..",
"..",
".venv",
process.platform === "win32" ? "Scripts/python.exe" : "bin/python",
);
const candidates = [
process.env.VERA_CLIENT_WORKFLOW_PYTHON,
process.env.PYTHON,
virtualEnvironmentPython,
repositoryPython,
"python3",
"python",
].filter(Boolean);
for (const candidate of candidates) {
if (path.isAbsolute(candidate) && !fs.existsSync(candidate)) continue;
return candidate;
}
return "python3";
}
const CLIENT_WORKFLOW_PREFLIGHT = String.raw`
import json
import sys
from pathlib import Path
plugin_root = Path(sys.argv[1]).resolve()
output_dir = Path(sys.argv[2])
workflow_id = sys.argv[3]
candidates = (
plugin_root.parent / "_shared" / "vendor" / "modules",
plugin_root / "vendor" / "modules",
plugin_root.parent.parent / "vendor" / "modules",
)
for candidate in candidates:
if (candidate / "vera_assurance").is_dir():
sys.path.insert(0, str(candidate))
break
else:
raise RuntimeError("The required vera_assurance module is not available.")
from vera_assurance import load_client_workflow_context_for_output
context = load_client_workflow_context_for_output(
output_dir,
expected_workflow_id=workflow_id,
)
print(json.dumps({
"ok": True,
"schema_version": context["schema_version"],
"workflow_id": context["workflow_id"],
"run_id": context["run_id"],
}, separators=(",", ":")))
`;
function preflightClientWorkflowRun(outputDir, expectedRunId) {
if (!outputDir) return null;
// Run ownership and lifecycle state are exact audit properties, so every
// persistence boundary reuses the shared v2 validator immediately before write.
const completed = spawnSync(
pythonExecutable(),
[
"-I",
"-B",
"-c",
CLIENT_WORKFLOW_PREFLIGHT,
PLUGIN_ROOT,
outputDir,
"client-file-preparation",
],
{ cwd: PLUGIN_ROOT, encoding: "utf8", maxBuffer: 64 * 1024 },
);
if (completed.error || completed.status !== 0) {
throw new Error(
"Client File Preparation persistence requires a running v2 customer-folder workflow run",
);
}
let result;
try {
result = JSON.parse(completed.stdout.trim());
} catch {
throw new Error("Client File Preparation customer-run preflight returned an invalid result");
}
if (
!isPlainObject(result)
|| result.ok !== true
|| result.schema_version !== "vera.client_workflow_context.v2"
|| result.workflow_id !== "client-file-preparation"
|| result.run_id !== expectedRunId
) {
throw new Error("Client File Preparation customer-run preflight returned an invalid result");
}
return result;
}
function refreshModelHandoff(outputDir) {
if (!outputDir) return [];
const scriptPath = path.join(PLUGIN_ROOT, "scripts", "model_handoff.py");
const completed = spawnSync(
pythonExecutable(),
["-I", "-B", scriptPath, "--output-dir", outputDir],
{ cwd: PLUGIN_ROOT, encoding: "utf8", maxBuffer: 4 * 1024 * 1024 },
);
if (completed.error || completed.status !== 0) {
throw new Error("Client File Preparation could not refresh model_handoff.json");
}
let result;
try {
result = JSON.parse(completed.stdout.trim());
} catch {
throw new Error("Client File Preparation model handoff returned an invalid result");
}
if (!isPlainObject(result) || result.ok !== true || !Array.isArray(result.outputs)) {
throw new Error("Client File Preparation model handoff returned an invalid result");
}
const seen = new Set();
return result.outputs.map((output, index) => {
if (!isPlainObject(output)) {
throw new Error(`model handoff output ${index} must be an object`);
}
const outputPath = artifactPathKey(output.path);
const isRoot = outputPath === "model_handoff.json";
const isPage = /^model_handoff_pages\/page-[0-9]{4}\.json$/.test(outputPath);
if ((!isRoot && !isPage) || seen.has(outputPath)) {
throw new Error(`model handoff output path is invalid: ${outputPath}`);
}
seen.add(outputPath);
const resolved = resolveSafeRunOutputPath(outputDir, outputPath, { mustExist: true });
const stat = fs.lstatSync(resolved.absolutePath);
if (!stat.isFile() || stat.isSymbolicLink()) {
throw new Error(`model handoff output is missing or unsafe: ${outputPath}`);
}
const actualHash = sha256File(resolved.absolutePath);
if (stat.size !== output.size_bytes || actualHash !== output.sha256) {
throw new Error(`model handoff output integrity mismatch: ${outputPath}`);
}
return {
path: outputPath,
kind: "json",
status: "written_reviewed",
size_bytes: stat.size,
sha256: actualHash,
};
});
}
function assetDataUrl(fileName, mimeType) {
const assetBytes = fs.readFileSync(path.join(PLUGIN_ROOT, "assets", fileName));
return `data:${mimeType};base64,${assetBytes.toString("base64")}`;
}
function icon() {
return {
src: assetDataUrl("icon.svg", "image/svg+xml"),
mimeType: "image/svg+xml",
sizes: ["24x24"],
};
}
function objectSchema(properties, required = [], additionalProperties = true) {
return { type: "object", properties, required, additionalProperties };
}
function toolUiMeta(resourceUri, toolName = null) {
const meta = {
ui: { resourceUri, visibility: ["model"] },
"ui/resourceUri": resourceUri,
"openai/outputTemplate": resourceUri,
"openai/widgetAccessible": true,
};
if (toolName === TOOL_NAMES.renderReview) {
meta["openai/toolInvocation/invoking"] = "Rendering client file preparation review";
meta["openai/toolInvocation/invoked"] = "Rendered client file preparation review";
}
return meta;
}
function widgetResourceMeta(uri) {
return {
ui: { resourceUri: uri },
"openai/widgetDescription":
"Interactive New Client · File Preparation review surface for document inventory, missing documents, fiscal fields, memo, and client email draft.",
"openai/widgetPrefersBorder": false,
"openai/widgetCSP": { connect_domains: [], resource_domains: [] },
"openai/widgetDomain": "https://chatgpt.com",
};
}
function toolDefinitions() {
const reviewPayload = objectSchema(
{
schema_version: { type: "string" },
plugin: { type: "string" },
workflow: { type: "string" },
run_id: { type: "string" },
review_type: { type: "string" },
items: { type: "array", items: { type: "object" } },
item_count: { type: "number" },
status: { type: "string" },
},
["schema_version", "plugin", "workflow", "run_id", "items", "item_count"],
);
const inputSchema = objectSchema(
{
client_engagement: { type: "string" },
run_intake: { type: "object", description: "Optional run_intake.json object." },
review_payload: reviewPayload,
ui_decisions: { type: "object", description: "Optional ui_decisions.json object." },
final_artifacts: { type: "object", description: "Optional final_artifacts.json object." },
},
[],
);
const decisionSchema = objectSchema(
{
item_id: { type: "string", description: "Review item id from review_payload.items[].id." },
action: { type: "string", enum: Array.from(ALLOWED_ACTIONS) },
reviewer_note: { type: "string", description: "Optional reviewer note." },
edit_value: { type: "string", description: "Required replacement text or value when action is edit." },
requested_documents: {
type: "array",
items: { type: "string" },
description: "Optional document requests when action is request_more_documents.",
},
},
["item_id", "action"],
);
const decisionInputSchema = objectSchema(
{
client_engagement: { type: "string" },
run_intake: { type: "object", description: "Optional run_intake.json object with output_dir for persistence." },
persistence_token: {
type: "string",
pattern: "^[A-Za-z0-9_-]{43}$",
description: "Opaque token returned by the render tool for path-private persistence.",
},
review_payload: reviewPayload,
ui_decisions: { type: "object", description: "Optional current ui_decisions.json object." },
decisions: { type: "array", items: decisionSchema },
decision_source: { type: "string", description: "Decision source label. Defaults to mcp_widget." },
reviewer: {
type: "string",
minLength: 1,
maxLength: MAX_REVIEWER_REFERENCE_LENGTH,
description:
"Stable professional or account reference. A real professional name is allowed. Required before a complete review can become final_ready; do not enter credentials, session material, or raw local paths.",
},
},
["decisions"],
);
return [
{
name: TOOL_NAMES.validateReview,
title: "Validate New Client · File Preparation review payload",
description:
"Validate the New Client · File Preparation review-session payload before rendering. Call this first, then render_client_file_preparation_review.",
inputSchema,
annotations: {
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: false,
},
},
{
name: TOOL_NAMES.renderReview,
title: "Render New Client · File Preparation review",
description:
"Render a New Client · File Preparation review-session payload as an MCP HTML widget for document inventory, exceptions, fields, memo, and email review.",
inputSchema,
_meta: toolUiMeta(WIDGET_URI, TOOL_NAMES.renderReview),
annotations: {
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: false,
},
},
{
name: TOOL_NAMES.saveDecisions,
title: "Save New Client · File Preparation review decisions",
description:
"Validate New Client · File Preparation review decisions and persist them to ui_decisions.json when run_intake.output_dir is available.",
inputSchema: decisionInputSchema,
annotations: {
readOnlyHint: false,
destructiveHint: true,
idempotentHint: false,
openWorldHint: false,
},
},
{
name: TOOL_NAMES.applyDecisions,
title: "Apply New Client · File Preparation review decisions",
description:
"Validate New Client · File Preparation review decisions, write applied_decisions.json, and update final_artifacts.json status when run_intake.output_dir is available.",
inputSchema: decisionInputSchema,
annotations: {
readOnlyHint: false,
destructiveHint: true,
idempotentHint: false,
openWorldHint: false,
},
},
];
}
function resources() {
return [
{
uri: WIDGET_URI,
name: "client_file_preparation_review_widget",
title: "New Client · File Preparation review widget",
description:
"Renders New Client · File Preparation review-session payloads with searchable review items and source previews.",
mimeType: WIDGET_MIME_TYPE,
_meta: widgetResourceMeta(WIDGET_URI),
},
];
}
function resourceText(uri) {
if (uri !== WIDGET_URI) throw new Error(`unknown New Client · File Preparation widget resource: ${uri}`);
return fs.readFileSync(
path.join(PLUGIN_ROOT, "assets", "client-file-preparation-review-widget.html"),
"utf8",
);
}
function payloadBytes(payload) {
return Buffer.byteLength(JSON.stringify(payload), "utf8");
}
function requireString(value, fieldPath) {
if (typeof value !== "string" || value.trim() === "") {
throw new Error(`${fieldPath} must be a non-empty string`);
}
}
function boundedOptionalString(value, fieldPath) {
if (value == null) return "";
if (typeof value !== "string") {
throw new Error(`${fieldPath} must be a string when provided`);
}
if (value.length > MAX_DECISION_TEXT_LENGTH) {
throw new Error(`${fieldPath} exceeds ${MAX_DECISION_TEXT_LENGTH} characters`);
}
return value.trim();
}
function canonicalValue(value) {
if (Array.isArray(value)) return value.map(canonicalValue);
if (!isPlainObject(value)) return value;
return Object.fromEntries(
Object.keys(value)
.sort()
.map((key) => [key, canonicalValue(value[key])]),
);
}
function canonicalJson(value) {
return JSON.stringify(canonicalValue(value));
}
function canonicalSha256(value) {
return crypto.createHash("sha256").update(canonicalJson(value), "utf8").digest("hex");
}
function normalizeReviewerReference(value, fieldPath = "reviewer") {
const reference = boundedOptionalString(value, fieldPath);
if (!reference) return "";
const containsControlCharacter = /[\u0000-\u001f\u007f]/.test(reference);
const containsRawPath = reference.includes("/") || reference.includes("\\");
if (
reference.length > MAX_REVIEWER_REFERENCE_LENGTH
|| containsControlCharacter
|| containsRawPath
|| REVIEWER_REFERENCE_SECRET_RE.test(reference)
|| REVIEWER_REFERENCE_CREDENTIAL_VALUE_RE.test(reference)
) {
throw new Error(
`${fieldPath} must be a stable professional or account reference of at most ${MAX_REVIEWER_REFERENCE_LENGTH} characters and must not contain credentials, session material, or raw local paths`,
);
}
return reference;
}
function validateItem(item, index) {
if (!isPlainObject(item)) throw new Error(`review_payload.items[${index}] must be an object`);
requireString(item.id, `review_payload.items[${index}].id`);
requireString(item.item_type, `review_payload.items[${index}].item_type`);
requireString(item.title, `review_payload.items[${index}].title`);
if (!ITEM_TYPES.has(item.item_type)) {
throw new Error(`review_payload.items[${index}].item_type is not supported: ${item.item_type}`);
}
if (!Array.isArray(item.allowed_actions) || item.allowed_actions.length === 0) {
throw new Error(`review_payload.items[${index}].allowed_actions must be a non-empty array`);
}
for (const action of item.allowed_actions) {
if (!ALLOWED_ACTIONS.has(action)) {
throw new Error(`review_payload.items[${index}].allowed_actions contains unsupported action: ${action}`);
}
}
if (item.recommended_action != null && !ALLOWED_ACTIONS.has(item.recommended_action)) {
throw new Error(`review_payload.items[${index}].recommended_action is not supported`);
}
}
function sanitizedRunIntakeForReview(value) {
if (!isPlainObject(value)) return null;
const sanitized = { ...value, input_paths: [] };
delete sanitized.output_dir;
delete sanitized.source_snapshot;
if (isPlainObject(value.data_posture)) {
const localFiles = Array.isArray(value.data_posture.local_files_read)
? value.data_posture.local_files_read
: [];
sanitized.data_posture = {
...value.data_posture,
local_files_read: [],
local_files_read_count: localFiles.length,
};
}
if (Array.isArray(value.execution_trace)) {
sanitized.execution_trace = value.execution_trace.map((entry) => {
if (!isPlainObject(entry)) return entry;
const redactPath = (candidate) => {
const text = shortString(candidate);
if (!text) return text;
return path.isAbsolute(text) || /^[A-Za-z]:[\\/]/.test(text)
? "<local-path>"
: text;
};
return {
...entry,
command: Array.isArray(entry.command) ? entry.command.map(redactPath) : entry.command,
inputs: Array.isArray(entry.inputs) ? entry.inputs.map(redactPath) : [],
};
});
}
return sanitized;
}
function sanitizedFinalArtifactsForReview(value) {
if (!isPlainObject(value)) return null;
const sanitized = JSON.parse(JSON.stringify(value));
if (Array.isArray(sanitized.outputs)) {
sanitized.outputs = sanitized.outputs.map((output) => {
if (!isPlainObject(output)) return output;
if (
typeof output.path === "string"
&& (path.isAbsolute(output.path) || /^[A-Za-z]:[\\/]/.test(output.path))
) {
return { ...output, path: "<local-path>" };
}
return output;
});
}
return sanitized;
}
function validateReviewPayload(inputArgs) {
if (!isPlainObject(inputArgs)) throw new Error("tool arguments must be an object");
const reviewPayload = inputArgs.review_payload;
if (!isPlainObject(reviewPayload)) throw new Error("review_payload must be an object");
requireString(reviewPayload.schema_version, "review_payload.schema_version");
if (reviewPayload.plugin !== "client-file-preparation") {
throw new Error('review_payload.plugin must be "client-file-preparation"');
}
requireString(reviewPayload.workflow, "review_payload.workflow");
requireString(reviewPayload.run_id, "review_payload.run_id");
if (!Array.isArray(reviewPayload.items)) {
throw new Error("review_payload.items must be an array");
}
if (reviewPayload.items.length > MAX_ITEMS) {
throw new Error(`review_payload.items exceeds ${MAX_ITEMS} items`);
}
if (reviewPayload.item_count !== reviewPayload.items.length) {
throw new Error("review_payload.item_count must equal review_payload.items.length");
}
reviewPayload.items.forEach((item, index) => validateItem(item, index));
const payload = {
widget_type: "client_file_preparation_review",
run_intake: sanitizedRunIntakeForReview(inputArgs.run_intake),
review_payload: reviewPayload,
ui_decisions: isPlainObject(inputArgs.ui_decisions) ? inputArgs.ui_decisions : null,
final_artifacts: isPlainObject(inputArgs.final_artifacts) ? inputArgs.final_artifacts : null,
decision_policy: {
save_tool: TOOL_NAMES.saveDecisions,
apply_tool: TOOL_NAMES.applyDecisions,
can_persist: Boolean(resolveDecisionOutputPath(inputArgs)),
fallback: "copy_json",
},
};
if (payloadBytes(payload) > MAX_PAYLOAD_BYTES) {
throw new Error(`client file preparation widget payload exceeds ${MAX_PAYLOAD_BYTES} bytes`);
}
return payload;
}
function reviewPayloadForWidget(inputArgs) {
const payload = validateReviewPayload(inputArgs);
let persistenceToken = null;
try {
persistenceToken = issuePersistenceToken(inputArgs, payload.review_payload);
payload.decision_policy.can_persist = Boolean(persistenceToken);
if (persistenceToken) {
payload.decision_policy.persistence_token = persistenceToken;
}
payload.final_artifacts = sanitizedFinalArtifactsForReview(inputArgs.final_artifacts);
if (payloadBytes(payload) > MAX_PAYLOAD_BYTES) {
throw new Error(
`client file preparation widget payload exceeds ${MAX_PAYLOAD_BYTES} bytes`,
);
}
return payload;
} catch (error) {
if (persistenceToken) PERSISTENCE_CONTEXTS.delete(persistenceToken);
throw error;
}
}
function resolveDecisionOutputPath(inputArgs) {
try {
const outputDir = resolveRunOutputDir(inputArgs);
return outputDir ? path.join(outputDir, "ui_decisions.json") : null;
} catch {
return null;
}
}
function normalizeRequestedDocuments(value, fieldPath) {
if (value == null) return [];
if (!Array.isArray(value)) throw new Error(`${fieldPath} must be an array when provided`);
return value.map((entry, index) => {
const documentName = boundedOptionalString(entry, `${fieldPath}[${index}]`);
if (!documentName) throw new Error(`${fieldPath}[${index}] must be a non-empty string`);
return documentName;
});
}
function normalizeDecision(decision, itemById, seenIds, decidedAt, index) {
// Decision persistence is an audit contract: ids, actions, and edit payloads are mechanically verifiable.
if (!isPlainObject(decision)) throw new Error(`decisions[${index}] must be an object`);
const itemId = boundedOptionalString(decision.item_id ?? decision.id, `decisions[${index}].item_id`);
if (!itemId) throw new Error(`decisions[${index}].item_id must be a non-empty string`);
if (seenIds.has(itemId)) throw new Error(`decisions contains duplicate item_id: ${itemId}`);
seenIds.add(itemId);
const item = itemById.get(itemId);
if (!item) throw new Error(`decisions[${index}].item_id is not in review_payload.items: ${itemId}`);
const action = boundedOptionalString(decision.action, `decisions[${index}].action`);
if (!ALLOWED_ACTIONS.has(action)) throw new Error(`decisions[${index}].action is not supported: ${action}`);
if (!item.allowed_actions.includes(action)) {
throw new Error(`decisions[${index}].action is not allowed for item ${itemId}: ${action}`);
}
const reviewerNote = boundedOptionalString(
decision.reviewer_note ?? decision.note,
`decisions[${index}].reviewer_note`,
);
const editValue = boundedOptionalString(
decision.edit_value ?? decision.user_text,
`decisions[${index}].edit_value`,
);
if (action === "edit" && !editValue) {
throw new Error(`decisions[${index}].edit_value is required when action is edit`);
}
const explicitRequestedDocuments = normalizeRequestedDocuments(
decision.requested_documents,
`decisions[${index}].requested_documents`,
);
// Missing-document requests copy only explicit review metadata; no semantic evidence inference happens here.
const requestedDocuments = requestedDocumentsFromReviewContext(
{ action, requested_documents: explicitRequestedDocuments },
item,
isPlainObject(item.data) ? item.data : {},
);
// Follow-up context copies only explicit item/evidence metadata to make blocker queues actionable.
const followupContext = followupContextFromReviewContext(
{ action },
item,
isPlainObject(item.data) ? item.data : {},
);
const normalized = {
item_id: itemId,
item_type: item.item_type,
title: item.title,
action,
status: ACTION_STATUSES[action],
decided_at: decidedAt,
};
if (reviewerNote) normalized.reviewer_note = reviewerNote;
if (editValue) normalized.edit_value = editValue;
if (requestedDocuments.length) normalized.requested_documents = requestedDocuments;
if (Object.keys(followupContext).length) normalized.followup_context = followupContext;
return normalized;
}
function buildUiDecisions(inputArgs) {
const payload = validateReviewPayload(inputArgs);
const reviewPayload = payload.review_payload;
const runIntake = payload.run_intake;
if (runIntake?.run_id != null && runIntake.run_id !== reviewPayload.run_id) {
throw new Error("run_intake.run_id must match review_payload.run_id");
}
if (!Array.isArray(inputArgs.decisions)) throw new Error("decisions must be an array");
if (inputArgs.decisions.length > reviewPayload.items.length) {
throw new Error("decisions cannot exceed review_payload.items.length");
}
const decidedAt = new Date().toISOString();
const itemById = new Map(reviewPayload.items.map((item) => [item.id, item]));
const seenIds = new Set();
const decisions = inputArgs.decisions.map((decision, index) =>
normalizeDecision(decision, itemById, seenIds, decidedAt, index),
);
const decisionSource =
boundedOptionalString(inputArgs.decision_source, "decision_source") || "mcp_widget";
const reviewer = normalizeReviewerReference(inputArgs.reviewer, "reviewer");
const currentUiDecisions = isPlainObject(inputArgs.ui_decisions) ? inputArgs.ui_decisions : null;
const reviewPayloadPath =
typeof currentUiDecisions?.review_payload_path === "string"
? path.basename(currentUiDecisions.review_payload_path)
: "review_payload.json";
const status =
decisions.length === 0
? "pending_review"
: decisions.length === reviewPayload.items.length
&& decisions.every((decision) => decision.action !== "skip")
? "reviewed"
: "partial_review";
const uiDecisions = {
schema_version: reviewPayload.schema_version,
plugin: reviewPayload.plugin,
workflow: reviewPayload.workflow,
run_id: reviewPayload.run_id,
decided_at: decisions.length ? decidedAt : null,
decision_source: decisionSource,
review_payload_path: reviewPayloadPath,
decisions,
decision_count: decisions.length,
item_count: reviewPayload.items.length,
status,
};
if (reviewer) uiDecisions.reviewer = reviewer;
return {
uiDecisions,
decisionOutputPath: resolveDecisionOutputPath(inputArgs),
};
}
function saveDecisionPayload(inputArgs) {
inputArgs = inputArgsWithReviewReference(inputArgs);
const { uiDecisions } = buildUiDecisions(inputArgs);
const reviewPayload = validateReviewPayload(inputArgs).review_payload;
const persistentInputArgs = inputArgsWithPersistentOutput(inputArgs, reviewPayload);
const persistence = validatePersistentState(persistentInputArgs, reviewPayload);
const decisionOutputPath = persistence
? path.join(persistence.outputDir, "ui_decisions.json")
: null;
if (persistence) {
stabilizeReviewer(uiDecisions, persistence.currentUiDecisions);
uiDecisions.review_payload_sha256 = persistence.reviewBytesHash;
uiDecisions.review_payload_canonical_sha256 = persistence.reviewCanonicalHash;
}
let persisted = false;
if (persistence && decisionOutputPath) {
preflightClientWorkflowRun(persistence.outputDir, reviewPayload.run_id);
withStagedRunDirectory(persistence.outputDir, (stagedDir) => {
const stagedDecisionPath = path.join(stagedDir, "ui_decisions.json");
const stagedFinalPath = path.join(stagedDir, "final_artifacts.json");
fs.writeFileSync(stagedDecisionPath, `${JSON.stringify(uiDecisions, null, 2)}\n`, "utf8");
const stagedFinal = readJsonFileIfPresent(stagedFinalPath);
const refreshed = refreshFinalArtifactsIntegrity(stagedDir, stagedFinal);
refreshed.review_payload_sha256 = persistence.reviewBytesHash;
refreshed.review_payload_canonical_sha256 = persistence.reviewCanonicalHash;
fs.writeFileSync(stagedFinalPath, `${JSON.stringify(refreshed, null, 2)}\n`, "utf8");
});
persisted = true;
}
return {
ok: true,
validation_type: "client_file_preparation_decisions",
run_id: uiDecisions.run_id,
decision_count: uiDecisions.decision_count,
item_count: uiDecisions.item_count,
status: uiDecisions.status,
persisted,
ui_decisions_path: persisted ? "ui_decisions.json" : null,
message: persisted
? `Saved ${uiDecisions.decision_count} New Client · File Preparation decisions.`
: "Validated decisions. No run_intake.output_dir was provided, so nothing was written.",
ui_decisions: uiDecisions,
};
}
function resolveRunOutputDir(inputArgs) {
const runIntake = isPlainObject(inputArgs.run_intake) ? inputArgs.run_intake : null;
const outputDir = typeof runIntake?.output_dir === "string" ? runIntake.output_dir.trim() : "";
if (!outputDir) return null;
let requested;
if (path.isAbsolute(outputDir)) {
requested = path.resolve(outputDir);
} else {
if (runIntake?.path_reference !== "run_root_relative") {
throw new Error("relative run output requires path_reference=run_root_relative");
}
const contextValue =
typeof inputArgs.client_engagement === "string"
? inputArgs.client_engagement.trim()
: "";
if (!contextValue || !path.isAbsolute(contextValue)) {
throw new Error(
"client_engagement is required to resolve the portable run output",
);
}
const contextPath = path.resolve(contextValue);
const contextStat = fs.lstatSync(contextPath);
if (!contextStat.isFile() || contextStat.isSymbolicLink()) {
throw new Error("client_engagement must identify a regular context file");
}
if (fs.realpathSync(contextPath) !== contextPath) {
throw new Error("client_engagement may not traverse symlinks");
}
const runRoot = path.dirname(contextPath);
requested = path.resolve(runRoot, outputDir);
if (requested === runRoot || !isInsideOrEqual(requested, runRoot)) {
throw new Error("run output reference leaves the customer run");
}
}
if (!fs.existsSync(requested)) {
throw new Error("run_intake.output_dir must identify an existing directory");
}
const stat = fs.lstatSync(requested);
if (!stat.isDirectory() || stat.isSymbolicLink()) {
throw new Error("run_intake.output_dir must be a regular directory without symlinks");
}
const resolved = fs.realpathSync(requested);
if (resolved !== requested) {
throw new Error("run_intake.output_dir may not traverse symlinks");
}
const protectedRoot = protectedOutputRoots().find((root) => isInsideOrEqual(resolved, root));
if (protectedRoot) {
throw new Error(
"run_intake.output_dir must be outside the plugin package and source repository",
);
}
const broadRoots = new Set([
path.parse(resolved).root,
path.resolve(os.homedir()),
path.resolve(os.tmpdir()),
]);
if (broadRoots.has(resolved)) {
throw new Error("run_intake.output_dir must be a dedicated run directory");
}
if (process.platform !== "win32") {
if ((stat.mode & 0o077) !== 0) {
throw new Error("run_intake.output_dir must be owner-only (mode 0700)");
}
if (typeof process.getuid === "function" && stat.uid !== process.getuid()) {
throw new Error("run_intake.output_dir must be owned by the current user");
}
}
return resolved;
}
function resolveAppliedDecisionOutputPath(inputArgs) {
const outputDir = resolveRunOutputDir(inputArgs);
return outputDir ? path.join(outputDir, "applied_decisions.json") : null;
}
function resolveFinalArtifactsOutputPath(inputArgs) {
const outputDir = resolveRunOutputDir(inputArgs);
return outputDir ? path.join(outputDir, "final_artifacts.json") : null;
}
function shortString(value) {
return typeof value === "string" ? value.trim() : "";
}
const REVISION_TEXT_EXTENSIONS = new Set([
".htm",
".html",
".md",
".sql",
".txt",
".xml",
".yaml",
".yml",
]);
const DIRECT_TEXT_UPDATE_EXTENSIONS = new Set([
".htm",
".html",
".md",
".sql",
".txt",
".xml",
".yaml",
".yml",
]);
const STRUCTURED_UPDATE_EXTENSIONS = new Set([".csv", ".json", ".jsonl"]);
const NATIVE_REGENERATION_EXTENSIONS = new Set([
".docx",
".pdf",
".pptx",
".xls",
".xlsm",
".xlsx",
]);
const DERIVED_NATIVE_REGENERATION_TARGETS = new Map([
["check_results.csv", ["check_results.xlsx"]],
["codex_run_review.md", ["concordato_review_summary.docx"]],
["reconciliation_matches.csv", ["journal_bank_reconciliation.xlsx"]],
]);
function safePathSegment(value, fallback) {
const cleaned = shortString(value)
.replace(/[^a-zA-Z0-9._-]+/g, "-")
.replace(/^-+|-+$/g, "")
.slice(0, 80);
return cleaned || fallback;
}
function revisionExtension(targetArtifact) {
const extension = path.extname(shortString(targetArtifact)).toLowerCase();
return REVISION_TEXT_EXTENSIONS.has(extension) ? extension : ".txt";
}
function revisionRelativePath(effect) {
const extension = revisionExtension(effect.target_artifact);
const targetArtifact = shortString(effect.target_artifact);
const targetExtension = path.extname(targetArtifact) || extension;
const sourceBase = path.basename(targetArtifact || "review-item", targetExtension);
const base = safePathSegment(sourceBase, "review-item");
const itemId = safePathSegment(effect.item_id, "item");
return path.join("revisions", `${base}__${itemId}${extension}`).split(path.sep).join("/");
}
function normalizeRelativePath(filePath) {
return filePath.split(path.sep).join("/");
}
function artifactPathKey(value) {
return normalizeRelativePath(shortString(value)).replace(/\\/g, "/").replace(/^\.\//, "");
}
function findRepositoryRoot(start) {
let current = path.resolve(start);
while (true) {
if (fs.existsSync(path.join(current, ".git"))) return current;
const parent = path.dirname(current);
if (parent === current) return null;
current = parent;
}
}
function protectedOutputRoots() {
const roots = new Set([PLUGIN_ROOT]);
const repositoryRoot = findRepositoryRoot(PLUGIN_ROOT);
if (repositoryRoot) roots.add(repositoryRoot);
return [...roots].map((entry) => fs.realpathSync(entry));
}
function isInsideOrEqual(candidate, parent) {
const relative = path.relative(parent, candidate);
return (
relative === ""
|| (!relative.startsWith(`..${path.sep}`) && relative !== ".." && !path.isAbsolute(relative))
);
}
function validateRunRelativePath(value, fieldPath = "run output path") {
const rawPath = shortString(value);
if (!rawPath) throw new Error(`${fieldPath} is required`);
if (path.isAbsolute(rawPath) || rawPath.includes("\\")) {
throw new Error(`${fieldPath} must be a run-local POSIX relative path`);
}
const parsed = rawPath.split("/");
if (parsed.some((segment) => !segment || segment === "." || segment === "..")) {
throw new Error(`${fieldPath} must not contain empty, dot, or parent segments`);
}
const normalized = path.posix.normalize(rawPath);
if (normalized !== rawPath) {
throw new Error(`${fieldPath} must be normalized`);
}
return rawPath;
}
function assertOwnerOnlyStat(stat, fieldPath, expectedDirectory) {
if (process.platform === "win32") return;
const expectedMode = expectedDirectory ? "0700" : "0600";
if ((stat.mode & 0o077) !== 0) {
throw new Error(`${fieldPath} must be owner-only (mode ${expectedMode})`);
}
if (typeof process.getuid === "function" && stat.uid !== process.getuid()) {
throw new Error(`${fieldPath} must be owned by the current user`);
}
}
function resolveSafeRunOutputPath(outputDir, value, { mustExist = false } = {}) {
if (!outputDir) return null;
const rawPath = validateRunRelativePath(value);
const absolutePath = path.resolve(outputDir, ...rawPath.split("/"));
const relativePath = path.relative(outputDir, absolutePath);
if (!relativePath || !isInsideOrEqual(absolutePath, outputDir)) return null;
let current = outputDir;
for (const segment of rawPath.split("/")) {
current = path.join(current, segment);
if (!fs.existsSync(current)) {
if (mustExist) throw new Error(`run output is missing: ${rawPath}`);
break;
}
const stat = fs.lstatSync(current);
if (stat.isSymbolicLink()) {
throw new Error(`run output may not traverse symbolic links: ${rawPath}`);
}
if (current !== absolutePath && !stat.isDirectory()) {
throw new Error(`run output parent is not a directory: ${rawPath}`);
}
}
if (fs.existsSync(absolutePath)) {
const resolved = fs.realpathSync(absolutePath);
if (!isInsideOrEqual(resolved, outputDir)) {
throw new Error(`run output resolves outside the run directory: ${rawPath}`);
}
}
return {
absolutePath,
relativePath: normalizeRelativePath(relativePath),
};
}
function canDirectlyUpdateTextArtifact(targetArtifact) {
const extension = path.extname(shortString(targetArtifact)).toLowerCase();
return DIRECT_TEXT_UPDATE_EXTENSIONS.has(extension);
}
function canUpdateStructuredArtifact(targetArtifact) {
const extension = path.extname(shortString(targetArtifact)).toLowerCase();
return STRUCTURED_UPDATE_EXTENSIONS.has(extension);
}
function needsNativeRegeneration(targetArtifact) {
const extension = path.extname(shortString(targetArtifact)).toLowerCase();
return NATIVE_REGENERATION_EXTENSIONS.has(extension);
}
function currentFinalArtifactsForApplication(inputArgs, finalArtifactsPath) {
return (
readJsonFileIfPresent(finalArtifactsPath) ||
(isPlainObject(inputArgs.final_artifacts) ? inputArgs.final_artifacts : null) ||
{}
);
}
function sha256File(filePath) {
return crypto.createHash("sha256").update(fs.readFileSync(filePath)).digest("hex");
}
function canonicalPackageEntries(outputs) {
return outputs
.map((output) => ({
path: artifactPathKey(output?.path),
sha256: shortString(output?.sha256).toLowerCase(),
size_bytes: Number(output?.size_bytes),
}))
.sort((left, right) => Buffer.compare(Buffer.from(left.path, "utf8"), Buffer.from(right.path, "utf8")));
}
function packageHash(outputs) {
return crypto
.createHash("sha256")
.update(JSON.stringify(canonicalPackageEntries(outputs)), "utf8")
.digest("hex");
}
function validateManifestIntegrity(outputDir, finalArtifacts) {
if (!outputDir || !isPlainObject(finalArtifacts)) {
throw new Error("run_intake.output_dir must contain final_artifacts.json");
}
if (
finalArtifacts.plugin !== "client-file-preparation"
|| finalArtifacts.workflow !== "client-file-preparation"
) {
throw new Error("final_artifacts identity must be client-file-preparation");
}
requireString(finalArtifacts.run_id, "final_artifacts.run_id");
const integrity = isPlainObject(finalArtifacts.integrity) ? finalArtifacts.integrity : null;
if (!integrity) throw new Error("final_artifacts.integrity is required");
if (integrity.algorithm !== "sha256") {
throw new Error("final_artifacts.integrity.algorithm must be sha256");
}
if (integrity.package_hash_basis !== PACKAGE_HASH_BASIS) {
throw new Error(`unsupported final_artifacts package_hash_basis: ${integrity.package_hash_basis}`);
}
if (!Array.isArray(finalArtifacts.outputs) || finalArtifacts.outputs.length === 0) {
throw new Error("final_artifacts.outputs must be a non-empty array");
}
const outputs = finalArtifacts.outputs;
const seenPaths = new Set();
const outputRecords = new Map();
for (const [index, output] of outputs.entries()) {
const outputPath = validateRunRelativePath(
output?.path,
`final_artifacts.outputs[${index}].path`,
);
if (outputPath === "final_artifacts.json") {
throw new Error("final_artifacts.json may not include itself in outputs");
}
if (seenPaths.has(outputPath)) throw new Error(`duplicate final artifact path: ${outputPath}`);
seenPaths.add(outputPath);
if (!/^[a-f0-9]{64}$/.test(shortString(output?.sha256))) {
throw new Error(`final_artifacts.outputs[${index}].sha256 is invalid`);
}
if (!Number.isSafeInteger(output?.size_bytes) || output.size_bytes < 0) {
throw new Error(`final_artifacts.outputs[${index}].size_bytes is invalid`);
}
const resolved = resolveSafeRunOutputPath(outputDir, outputPath, { mustExist: true });
const outputStat = fs.lstatSync(resolved.absolutePath);
if (!outputStat.isFile() || outputStat.isSymbolicLink()) {
throw new Error(`final artifact is missing or unsafe: ${outputPath}`);
}
assertOwnerOnlyStat(outputStat, `final artifact ${outputPath}`, false);
const actualSize = outputStat.size;
if (actualSize !== output.size_bytes) {
throw new Error(`final artifact size mismatch: ${outputPath}`);
}
const actualHash = sha256File(resolved.absolutePath);
if (actualHash !== output.sha256) {
throw new Error(`final artifact sha256 mismatch: ${outputPath}`);
}
outputRecords.set(outputPath, output);
}
const expectedPackageHash = packageHash(outputs);
if (!/^[a-f0-9]{64}$/.test(shortString(integrity.package_hash))) {
throw new Error("final_artifacts.integrity.package_hash is invalid");
}
if (integrity.package_hash !== expectedPackageHash) {
throw new Error("final_artifacts package_hash mismatch");
}
return {
verified: true,
package_hash: expectedPackageHash,
output_records: outputRecords,
};
}
function refreshFinalArtifactsIntegrity(outputDir, finalArtifacts) {
if (!outputDir || !isPlainObject(finalArtifacts)) return finalArtifacts;
const outputs = Array.isArray(finalArtifacts.outputs) ? finalArtifacts.outputs : [];
const refreshedOutputs = outputs.map((output) => {
const outputPath = artifactPathKey(output?.path);
const resolved = resolveSafeRunOutputPath(outputDir, outputPath);
if (!resolved || !fs.existsSync(resolved.absolutePath) || !fs.statSync(resolved.absolutePath).isFile()) {
throw new Error(`cannot seal missing final artifact: ${outputPath || "(empty path)"}`);
}
return {
...output,
path: outputPath,
size_bytes: fs.statSync(resolved.absolutePath).size,
sha256: sha256File(resolved.absolutePath),
};
});
return {
...finalArtifacts,
outputs: refreshedOutputs,
integrity: {
algorithm: "sha256",
package_hash_basis: PACKAGE_HASH_BASIS,
package_hash: packageHash(refreshedOutputs),
},
};
}
function finalArtifactsOutputPaths(currentFinalArtifacts) {
const outputs = Array.isArray(currentFinalArtifacts?.outputs)
? currentFinalArtifacts.outputs
: [];
return new Set(
outputs
.map((output) => artifactPathKey(output?.path))
.filter(Boolean),
);
}
function existingDerivedNativeTargets(outputDir, currentFinalArtifacts, sourceArtifact) {
const sourceKey = artifactPathKey(sourceArtifact);
const candidates = DERIVED_NATIVE_REGENERATION_TARGETS.get(sourceKey) || [];
if (!candidates.length) return [];
const declaredOutputPaths = finalArtifactsOutputPaths(currentFinalArtifacts);
return candidates.filter((candidate) => {
const candidateKey = artifactPathKey(candidate);
if (declaredOutputPaths.has(candidateKey)) return true;
const target = resolveSafeRunOutputPath(outputDir, candidateKey);
return Boolean(target && fs.existsSync(target.absolutePath));
});
}
function csvEscape(value) {
const text = String(value ?? "");
if (!/[",\r\n]/.test(text)) return text;
return `"${text.replace(/"/g, '""')}"`;
}
function parseCsv(text) {
const rows = [];
let row = [];
let field = "";
let inQuotes = false;
for (let index = 0; index < text.length; index += 1) {
const char = text[index];
if (inQuotes) {
if (char === '"' && text[index + 1] === '"') {
field += '"';
index += 1;
} else if (char === '"') {
inQuotes = false;
} else {
field += char;
}
continue;
}
if (char === '"') {
inQuotes = true;
} else if (char === ",") {
row.push(field);
field = "";
} else if (char === "\n") {
row.push(field);
rows.push(row);
row = [];
field = "";
} else if (char === "\r") {
if (text[index + 1] === "\n") index += 1;
row.push(field);
rows.push(row);
row = [];
field = "";
} else {
field += char;
}
}
if (inQuotes) throw new Error("CSV parse failed: unclosed quoted field");
if (field !== "" || row.length || !text.endsWith("\n")) {
row.push(field);
rows.push(row);
}
return rows;
}
function serializeCsv(rows) {
return `${rows.map((row) => row.map(csvEscape).join(",")).join("\n")}\n`;
}
function structuredUpdateSpec(effect) {
// Native table/object edits are deterministic only when the review payload names the exact row and field.
if (!effect.target_artifact || !effect.target_id_field || !effect.target_record_id || !effect.target_field) {
return null;
}
return {
idField: effect.target_id_field,
recordId: effect.target_record_id,
targetField: effect.target_field,
recordsKey: effect.target_records_key || null,
};
}
function updateMatchingRecord(records, spec, editValue) {
if (!Array.isArray(records)) throw new Error("structured artifact records must be an array");
let updated = 0;
for (const record of records) {
if (!isPlainObject(record)) continue;
if (String(record[spec.idField] ?? "") !== spec.recordId) continue;
record[spec.targetField] = editValue;
updated += 1;
}
if (updated !== 1) {
throw new Error(
`structured edit expected exactly one record for ${spec.idField}=${spec.recordId}, found ${updated}`,
);
}
return updated;
}
function updateCsvArtifact(filePath, effect, spec) {
const rows = parseCsv(fs.readFileSync(filePath, "utf8"));
if (!rows.length) throw new Error("CSV structured edit requires a header row");
const header = rows[0];
const idIndex = header.indexOf(spec.idField);
const fieldIndex = header.indexOf(spec.targetField);
if (idIndex < 0) throw new Error(`CSV structured edit missing id column ${spec.idField}`);
if (fieldIndex < 0) throw new Error(`CSV structured edit missing target column ${spec.targetField}`);
let updated = 0;
for (const row of rows.slice(1)) {
if (String(row[idIndex] ?? "") !== spec.recordId) continue;
while (row.length < header.length) row.push("");
row[fieldIndex] = effect.edit_value;
updated += 1;
}
if (updated !== 1) {
throw new Error(
`CSV structured edit expected exactly one row for ${spec.idField}=${spec.recordId}, found ${updated}`,
);
}
fs.writeFileSync(filePath, serializeCsv(rows), "utf8");
return { updatedRows: updated, rowCount: Math.max(rows.length - 1, 0) };
}
function updateJsonArtifact(filePath, effect, spec) {
const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
if (Array.isArray(parsed)) {
const updatedRows = updateMatchingRecord(parsed, spec, effect.edit_value);
fs.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
return { updatedRows, rowCount: parsed.length };
}
if (isPlainObject(parsed) && spec.recordsKey && Array.isArray(parsed[spec.recordsKey])) {
const records = parsed[spec.recordsKey];
const updatedRows = updateMatchingRecord(records, spec, effect.edit_value);
fs.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
return { updatedRows, rowCount: records.length };
}
if (isPlainObject(parsed) && String(parsed[spec.idField] ?? "") === spec.recordId) {
parsed[spec.targetField] = effect.edit_value;
fs.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
return { updatedRows: 1, rowCount: 1 };
}
throw new Error("JSON structured edit requires an object, array, or explicit records_key array");
}
function updateJsonlArtifact(filePath, effect, spec) {
const text = fs.readFileSync(filePath, "utf8");
const records = text
.split(/\r?\n/)
.filter((line) => line.trim())
.map((line) => JSON.parse(line));
const updatedRows = updateMatchingRecord(records, spec, effect.edit_value);
fs.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}\n`, "utf8");
return { updatedRows, rowCount: records.length };
}
function originalBackupRelativePath(effect, targetRelativePath) {
const extension = path.extname(targetRelativePath).toLowerCase() || ".txt";
const sourceBase = path.basename(targetRelativePath, extension);
const base = safePathSegment(sourceBase, "artifact");
const itemId = safePathSegment(effect.item_id, "item");
return normalizeRelativePath(path.join("revisions", "originals", `${base}__${itemId}${extension}`));
}
function readJsonFileIfPresent(filePath) {
if (!filePath || !fs.existsSync(filePath)) return null;
try {
const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
return isPlainObject(parsed) ? parsed : null;
} catch {
return null;
}
}
function readRunJsonFile(filePath, { required = true } = {}) {
if (!fs.existsSync(filePath)) {
if (!required) return null;
throw new Error(`${path.basename(filePath)} is required in the run directory`);
}
const stat = fs.lstatSync(filePath);
if (!stat.isFile() || stat.isSymbolicLink()) {
throw new Error(`${path.basename(filePath)} must be a regular JSON file without symlinks`);
}
assertOwnerOnlyStat(stat, path.basename(filePath), false);
if (stat.size > MAX_LOCAL_JSON_BYTES) {
throw new Error(`${path.basename(filePath)} exceeds ${MAX_LOCAL_JSON_BYTES} bytes`);
}
let value;
try {
value = JSON.parse(fs.readFileSync(filePath, "utf8"));
} catch {
throw new Error(`${path.basename(filePath)} must contain valid JSON`);
}
if (!isPlainObject(value)) {
throw new Error(`${path.basename(filePath)} must contain a JSON object`);
}
return value;
}
function validateRunTreeNoSymlinks(outputDir) {
const pending = [outputDir];
while (pending.length) {
const current = pending.pop();
const stat = fs.lstatSync(current);
if (stat.isSymbolicLink()) {
throw new Error("run output tree may not contain symbolic links");
}
if (stat.isDirectory()) {
assertOwnerOnlyStat(stat, path.relative(outputDir, current) || "run output directory", true);
for (const entry of fs.readdirSync(current)) pending.push(path.join(current, entry));
} else if (stat.isFile()) {
assertOwnerOnlyStat(stat, path.relative(outputDir, current), false);
} else {
throw new Error(`run output tree contains a non-regular entry: ${path.relative(outputDir, current)}`);
}
}
}
function validatePersistentState(inputArgs, reviewPayload) {
const outputDir = resolveRunOutputDir(inputArgs);
if (!outputDir) return null;
validateRunTreeNoSymlinks(outputDir);
const finalArtifactsPath = path.join(outputDir, "final_artifacts.json");
const finalArtifacts = readRunJsonFile(finalArtifactsPath);
const integrity = validateManifestIntegrity(outputDir, finalArtifacts);
const runIntake = readRunJsonFile(path.join(outputDir, "run_intake.json"));
const storedOutputMatches = resolveRunOutputDir({
...inputArgs,
run_intake: runIntake,
}) === outputDir;
if (
runIntake.plugin !== reviewPayload.plugin
|| runIntake.workflow !== reviewPayload.workflow
|| runIntake.run_id !== reviewPayload.run_id
|| !storedOutputMatches
) {
throw new Error("stored run_intake.json does not bind this review to the output directory");
}
if (
finalArtifacts.run_id !== reviewPayload.run_id
|| finalArtifacts.plugin !== reviewPayload.plugin
|| finalArtifacts.workflow !== reviewPayload.workflow
) {
throw new Error("final_artifacts identity does not match review_payload");
}
for (const requiredPath of [
"run_intake.json",
"review_payload.json",
"ui_decisions.json",
"review_handoff.md",
"model_handoff.json",
]) {
if (!integrity.output_records.has(requiredPath)) {
throw new Error(`final_artifacts.outputs is missing required binding: ${requiredPath}`);
}
}
const storedReviewPath = path.join(outputDir, "review_payload.json");
const storedReview = readRunJsonFile(storedReviewPath);
const reviewCanonicalHash = canonicalSha256(reviewPayload);
const storedCanonicalHash = canonicalSha256(storedReview);
if (storedCanonicalHash !== reviewCanonicalHash || canonicalJson(storedReview) !== canonicalJson(reviewPayload)) {
throw new Error("stored review_payload.json does not match the reviewed payload canonical hash");
}
const reviewBytesHash = sha256File(storedReviewPath);
if (integrity.output_records.get("review_payload.json").sha256 !== reviewBytesHash) {
throw new Error("stored review_payload.json byte hash does not match the sealed manifest");
}
if (isPlainObject(inputArgs.final_artifacts) && canonicalJson(inputArgs.final_artifacts) !== canonicalJson(finalArtifacts)) {
throw new Error("final_artifacts argument is stale or does not match the sealed run manifest");
}
const currentUiDecisions = readRunJsonFile(
path.join(outputDir, "ui_decisions.json"),
{ required: false },
);
return {
outputDir,
finalArtifacts,
currentUiDecisions,
reviewBytesHash,
reviewCanonicalHash,
};
}
function pruneExpiredPersistenceContexts(now = Date.now()) {
for (const [token, context] of PERSISTENCE_CONTEXTS.entries()) {
if (context.expiresAt <= now) PERSISTENCE_CONTEXTS.delete(token);
}
}
function reservePersistenceContextSlot() {
pruneExpiredPersistenceContexts();
while (PERSISTENCE_CONTEXTS.size >= MAX_PERSISTENCE_CONTEXTS) {
const oldest = PERSISTENCE_CONTEXTS.keys().next().value;
if (oldest == null) break;
PERSISTENCE_CONTEXTS.delete(oldest);
}
}
function issuePersistenceToken(inputArgs, reviewPayload) {
const persistence = validatePersistentState(inputArgs, reviewPayload);
if (!persistence) return null;
reservePersistenceContextSlot();
const token = crypto.randomBytes(32).toString("base64url");
PERSISTENCE_CONTEXTS.set(token, {
outputDir: persistence.outputDir,
clientEngagement: inputArgs.client_engagement,
outputReference: inputArgs.run_intake.output_dir,
pathReference: inputArgs.run_intake.path_reference,
runId: reviewPayload.run_id,
reviewHash: persistence.reviewCanonicalHash,
expiresAt: Date.now() + PERSISTENCE_CONTEXT_TTL_MS,
});
return token;
}
function inputArgsWithReviewReference(inputArgs) {
if (isPlainObject(inputArgs?.review_payload)) return inputArgs;
const token = inputArgs?.persistence_token;
if (typeof token !== "string" || !PERSISTENCE_TOKEN_RE.test(token)) {
throw new Error("review_payload or a valid persistence_token is required");
}
pruneExpiredPersistenceContexts();
const context = PERSISTENCE_CONTEXTS.get(token);
if (!context || context.expiresAt <= Date.now()) {
throw new Error("persistence_token is unknown or expired; validate the review again");
}
const reviewPayload = readJsonFileIfPresent(path.join(context.outputDir, "review_payload.json"));
if (!isPlainObject(reviewPayload)
|| reviewPayload.run_id !== context.runId
|| canonicalSha256(reviewPayload) !== context.reviewHash) {
throw new Error("persistence_token review binding no longer matches the stored package");
}
return {
...inputArgs,
client_engagement: context.clientEngagement,
review_payload: reviewPayload,
ui_decisions: readJsonFileIfPresent(path.join(context.outputDir, "ui_decisions.json")),
final_artifacts: readJsonFileIfPresent(path.join(context.outputDir, "final_artifacts.json")),
run_intake: {
...(isPlainObject(inputArgs.run_intake) ? inputArgs.run_intake : {}),
output_dir: context.outputDir,
path_reference: context.pathReference,
},
};
}
function inputArgsWithPersistentOutput(inputArgs, reviewPayload) {
const rawToken = inputArgs.persistence_token;
if (rawToken == null || rawToken === "") return inputArgs;
if (typeof rawToken !== "string" || !PERSISTENCE_TOKEN_RE.test(rawToken)) {
throw new Error("persistence_token has an invalid format");
}
const directOutputDir = resolveRunOutputDir(inputArgs);
pruneExpiredPersistenceContexts();
const context = PERSISTENCE_CONTEXTS.get(rawToken);
if (!context || context.expiresAt <= Date.now()) {
// The local loopback workbench intentionally invokes a fresh Node process
// per tool call and supplies its server-held output directory each time.
// Its render-process token cannot survive, so the already-supported direct
// binding remains authoritative when that private path is present.
if (directOutputDir) return inputArgs;
throw new Error("persistence_token is unknown or expired; render the review again");
}
if (
context.runId !== reviewPayload.run_id
|| context.reviewHash !== canonicalSha256(reviewPayload)
) {
throw new Error("persistence_token does not match this review run");
}
const boundOutputDir = resolveRunOutputDir({
...inputArgs,
run_intake: {
output_dir: context.outputReference,
path_reference: context.pathReference,
},
});
if (directOutputDir && directOutputDir !== boundOutputDir) {
throw new Error("persistence_token and run_intake.output_dir do not match");
}
return {
...inputArgs,
run_intake: {
...(isPlainObject(inputArgs.run_intake) ? inputArgs.run_intake : {}),
output_dir: boundOutputDir,
},
};
}
function stabilizeReviewer(uiDecisions, currentUiDecisions) {
const currentReviewer = normalizeReviewerReference(currentUiDecisions?.reviewer, "ui_decisions.reviewer");
const submittedReviewer = normalizeReviewerReference(uiDecisions.reviewer, "reviewer");
if (currentReviewer && submittedReviewer && currentReviewer !== submittedReviewer) {
throw new Error("reviewer reference must remain stable for the run");
}
const reviewer = currentReviewer || submittedReviewer;
if (reviewer) uiDecisions.reviewer = reviewer;
else delete uiDecisions.reviewer;
return reviewer;
}
function hardenOwnerOnlyTree(outputDir) {
const pending = [outputDir];
while (pending.length) {
const current = pending.pop();
const stat = fs.lstatSync(current);
if (stat.isSymbolicLink()) throw new Error("transaction output may not contain symbolic links");
if (stat.isDirectory()) {
if (process.platform !== "win32") fs.chmodSync(current, 0o700);
for (const entry of fs.readdirSync(current)) pending.push(path.join(current, entry));
} else if (stat.isFile()) {
if (process.platform !== "win32") fs.chmodSync(current, 0o600);
} else {
throw new Error("transaction output may contain only regular files and directories");
}
}
}
function withStagedRunDirectory(outputDir, callback) {
const parent = path.dirname(outputDir);
const base = path.basename(outputDir);
const transactionId = crypto.randomUUID();
const stagedDir = path.join(parent, `.${base}.${transactionId}.tmp`);
const backupDir = path.join(parent, `.${base}.${transactionId}.bak`);
let backedUp = false;
let installed = false;
try {
fs.cpSync(outputDir, stagedDir, {
recursive: true,
dereference: false,
errorOnExist: true,
force: false,
preserveTimestamps: true,
});
hardenOwnerOnlyTree(stagedDir);
const result = callback(stagedDir);
hardenOwnerOnlyTree(stagedDir);
validateRunTreeNoSymlinks(stagedDir);
const stagedFinal = readRunJsonFile(path.join(stagedDir, "final_artifacts.json"));
validateManifestIntegrity(stagedDir, stagedFinal);
fs.renameSync(outputDir, backupDir);
backedUp = true;
fs.renameSync(stagedDir, outputDir);
installed = true;
fs.rmSync(backupDir, { recursive: true, force: true });
backedUp = false;
return result;
} catch (error) {
if (installed && fs.existsSync(outputDir)) {
fs.rmSync(outputDir, { recursive: true, force: true });
installed = false;
}
if (backedUp && fs.existsSync(backupDir)) {
fs.renameSync(backupDir, outputDir);
backedUp = false;
}
throw error;
} finally {
if (fs.existsSync(stagedDir)) fs.rmSync(stagedDir, { recursive: true, force: true });
if (fs.existsSync(backupDir) && !backedUp) {
fs.rmSync(backupDir, { recursive: true, force: true });
}
}
}
function uniqueStrings(values) {
return Array.from(
new Set(
values
.map((value) => shortString(value))
.filter(Boolean),
),
);
}
function collectReviewApplicationPaths(appliedDecisions, finalArtifacts) {
const paths = ["ui_decisions.json", "applied_decisions.json", "final_artifacts.json"];
const finalOutputs = Array.isArray(finalArtifacts?.outputs) ? finalArtifacts.outputs : [];
if (
finalOutputs.some(
(output) => isPlainObject(output) && output.path === "review_handoff.md",
)
) {
paths.push("review_handoff.md");
}
const reviewApplication = isPlainObject(finalArtifacts?.review_application)
? finalArtifacts.review_application
: {};
for (const fieldName of [
"applied_decisions_path",
"revision_paths",
"target_update_paths",
"structured_update_paths",
"native_regeneration_paths",
"native_regenerated_paths",
"downstream_regenerated_paths",
"original_backup_paths",
]) {
const value = reviewApplication[fieldName] ?? appliedDecisions?.[fieldName];
if (Array.isArray(value)) paths.push(...value);
else paths.push(value);
}
return uniqueStrings(paths);
}
function appendReviewApplicationExecutionTrace(
inputArgs,
outputDir,
appliedDecisions,
finalArtifacts,
) {
if (!outputDir) return null;
const runIntakePath = path.join(outputDir, "run_intake.json");
const current = readJsonFileIfPresent(runIntakePath) ||
(isPlainObject(inputArgs.run_intake) ? { ...inputArgs.run_intake } : null);
if (!current) return null;
const trace = Array.isArray(current.execution_trace) ? [...current.execution_trace] : [];
const appliedAt = shortString(appliedDecisions?.applied_at) || new Date().toISOString();
const stepIdSuffix = appliedAt.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
trace.push({
step_id: `${shortString(appliedDecisions?.workflow) || "client_file_preparation"}_review_apply_${stepIdSuffix || Date.now()}`,
kind: "deterministic_review_apply",
status: "passed",
execution_location: "local_codex_workspace",
command: [SERVER_NAME, TOOL_NAMES.applyDecisions],
inputs: uniqueStrings([
appliedDecisions?.review_payload?.path || "review_payload.json",
"ui_decisions.json",
"final_artifacts.json",
]),
outputs: collectReviewApplicationPaths(appliedDecisions, finalArtifacts),
});
const updated = { ...current, execution_trace: trace };
fs.mkdirSync(path.dirname(runIntakePath), { recursive: true });
fs.writeFileSync(runIntakePath, `${JSON.stringify(updated, null, 2)}\n`, "utf8");
return runIntakePath;
}
function requestedDocumentsFromReviewContext(decision, item, data) {
if (Array.isArray(decision.requested_documents) && decision.requested_documents.length) {
return decision.requested_documents;
}
if (decision.action !== "request_more_documents") return [];
const candidates = [];
function add(value) {
if (Array.isArray(value)) {
for (const entry of value) add(entry);
return;
}
const text = shortString(value);
if (text) candidates.push(text);
}
for (const key of [
"requested_document",
"requested_documents",
"missing_document",
"missing_documents",
"required_document",
"required_documents",
"support_document",
"support_documents",
]) {
add(data[key]);
}
const evidence = Array.isArray(item.evidence) ? item.evidence : [];
for (const record of evidence) {
if (!isPlainObject(record)) continue;
for (const key of [
"requested_document",
"requested_documents",
"missing_document",
"missing_documents",
"required_document",
"required_documents",
"support_document",
"support_documents",
]) {
add(record[key]);
}
}
return Array.from(new Set(candidates));
}
function compactContextValue(value) {
if (value == null || value === "") return "";
if (typeof value === "string") return value.trim();
if (typeof value === "number" && Number.isFinite(value)) return String(value);
if (typeof value === "boolean") return String(value);
return "";
}
function followupContextFromReviewContext(decision, item, data) {
if (isPlainObject(decision.followup_context) && Object.keys(decision.followup_context).length) {
return decision.followup_context;
}
if (!["reject", "mark_unclear", "request_more_documents"].includes(decision.action)) return {};
const records = [
data,
...(Array.isArray(item.evidence) ? item.evidence.filter(isPlainObject) : []),
];
const fields = [
["owner", ["owner", "responsible_party", "assignee", "contact", "client_contact"]],
["source_system", ["source_system", "system", "source_system_name"]],
["source_file", ["source_file", "filename", "file_name", "source_workbook"]],
["source_table", ["source_table", "sheet", "worksheet", "table"]],
["due_date", ["due_date", "deadline", "response_due_date"]],
["period", ["period", "tax_period", "fiscal_year", "year"]],
["entity", ["entity", "client", "company", "account", "counterparty", "beneficiary"]],
["record_id", ["record_id", "source_row", "movement_number", "bank_transaction_id", "journal_entry_id", "claim_index"]],
["amount", ["amount", "amount_abs", "amount_value"]],
["reason", ["reason", "missing_reason", "blocking_reason", "mismatches"]],
["priority", ["priority", "severity"]],
];
const context = {};
for (const [targetKey, sourceKeys] of fields) {
for (const record of records) {
for (const sourceKey of sourceKeys) {
const value = compactContextValue(record[sourceKey]);
if (!value) continue;
context[targetKey] = value;
break;
}
if (context[targetKey]) break;
}
}
return context;
}
function buildApplicationEffect(decision, item, appliedAt) {
const data = isPlainObject(item.data) ? item.data : {};
const targetArtifact =
shortString(data.target_artifact) ||
shortString(item.output_path) ||
shortString(data.path);
const targetPath =
shortString(data.target_path) ||
shortString(data.field_path) ||
shortString(data.field);
const targetIdField =
shortString(data.target_id_field) ||
shortString(data.record_id_field);
const targetRecordId =
shortString(data.target_record_id) ||
shortString(data.record_id);
const targetField =
shortString(data.target_field) ||
shortString(data.edit_field);
const targetRecordsKey =
shortString(data.target_records_key) ||
shortString(data.records_key);
const requiresFollowup = new Set(["reject", "mark_unclear", "request_more_documents", "skip"]).has(
decision.action,
);
const requestedDocuments = requestedDocumentsFromReviewContext(decision, item, data);
const followupContext = followupContextFromReviewContext(decision, item, data);
const effect = {
item_id: decision.item_id,
item_type: decision.item_type,
title: decision.title,
action: decision.action,
status: decision.status,
applied_at: appliedAt,
applied: true,
requires_followup: requiresFollowup,
target_artifact: targetArtifact || null,
target_path: targetPath || null,
target_id_field: targetIdField || null,
target_record_id: targetRecordId || null,
target_field: targetField || null,
target_records_key: targetRecordsKey || null,
source_path: shortString(item.source_path) || null,
artifact_update:
decision.action === "edit"
? "revision_artifact_pending"
: targetArtifact
? "decision_manifest_only"
: "review_record_only",
};
if (decision.reviewer_note) effect.reviewer_note = decision.reviewer_note;
if (decision.edit_value) effect.edit_value = decision.edit_value;
if (requestedDocuments.length) {
effect.requested_documents = requestedDocuments;
}
if (Object.keys(followupContext).length) {
effect.followup_context = followupContext;
}
return effect;
}
function writeRevisionArtifacts(outputDir, effects) {
if (!outputDir) return [];
const revisionOutputs = [];
for (const effect of effects) {
if (effect.action !== "edit" || !effect.edit_value) continue;
const relativePath = revisionRelativePath(effect);
const absolutePath = path.join(outputDir, relativePath);
fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
fs.writeFileSync(absolutePath, effect.edit_value, "utf8");
effect.revision_artifact = relativePath;
effect.artifact_update = "revision_artifact_written";
revisionOutputs.push({
path: relativePath,
kind: revisionExtension(effect.target_artifact).replace(/^\./, "") || "txt",
status: "written_revision",
source_artifact: effect.target_artifact,
item_id: effect.item_id,
});
}
return revisionOutputs;
}
function writeDirectTextArtifactUpdates(outputDir, effects, currentFinalArtifacts) {
if (!outputDir) return { targetOutputs: [], backupOutputs: [] };
const targetOutputs = [];
const backupOutputs = [];
const updatedTargets = new Set();
const declaredPaths = finalArtifactsOutputPaths(currentFinalArtifacts);
for (const effect of effects) {
if (effect.action !== "edit" || !effect.edit_value) continue;
if (!canDirectlyUpdateTextArtifact(effect.target_artifact)) continue;
const targetKey = validateRunRelativePath(effect.target_artifact, `effect ${effect.item_id} target_artifact`);
if (isProtectedRunFile(targetKey)) {
throw new Error(`effect ${effect.item_id} may not edit protected run artifact ${targetKey}`);
}
if (!declaredPaths.has(targetKey)) {
throw new Error(`effect ${effect.item_id} target_artifact is not a sealed output: ${targetKey}`);
}
if (updatedTargets.has(targetKey)) {
throw new Error(`multiple whole-artifact edits target ${targetKey}; combine them into one reviewed edit`);
}
updatedTargets.add(targetKey);
const target = resolveSafeRunOutputPath(outputDir, targetKey, { mustExist: true });
const stat = fs.lstatSync(target.absolutePath);
if (!stat.isFile() || stat.isSymbolicLink()) {
throw new Error(`effect ${effect.item_id} target_artifact is not a regular file`);
}
const backupRelativePath = originalBackupRelativePath(effect, target.relativePath);
const backupAbsolutePath = path.join(outputDir, backupRelativePath);
fs.mkdirSync(path.dirname(backupAbsolutePath), { recursive: true });
if (!fs.existsSync(backupAbsolutePath)) {
fs.writeFileSync(backupAbsolutePath, fs.readFileSync(target.absolutePath, "utf8"), "utf8");
}
fs.writeFileSync(target.absolutePath, effect.edit_value, "utf8");
effect.target_artifact = target.relativePath;
effect.original_artifact_backup = backupRelativePath;
effect.artifact_update = "target_artifact_updated";
targetOutputs.push({
path: target.relativePath,
kind: path.extname(target.relativePath).replace(/^\./, "") || "txt",
status: "updated_from_review",
item_id: effect.item_id,
...((target.relativePath === "04_bozza_email_cliente.md"
&& effect.item_type === "draft_client_email")
|| (["06_memo_istruttoria.md", "07_scheda_codex_per_studio.md"].includes(target.relativePath)
&& effect.item_type === "draft_memo_section")
? {
// A complete reviewed replacement supersedes the starter draft's
// literal wording. Keep exact reviewed-text and nonempty checks;
// the ordinary package hashes still bind the resulting bytes.
qa_checks: ["nonempty_text", "required_text"],
required_text: [effect.edit_value],
}
: {}),
});
backupOutputs.push({
path: backupRelativePath,
kind: path.extname(backupRelativePath).replace(/^\./, "") || "txt",
status: "backup_original",
source_artifact: target.relativePath,
item_id: effect.item_id,
});
}
return { targetOutputs, backupOutputs };
}
function writeStructuredArtifactUpdates(outputDir, effects, currentFinalArtifacts) {
if (!outputDir) return { targetOutputs: [], backupOutputs: [] };
const targetOutputs = [];
const backupOutputs = [];
const updatedRecords = new Set();
const declaredPaths = finalArtifactsOutputPaths(currentFinalArtifacts);
for (const effect of effects) {
if (effect.action !== "edit" || !effect.edit_value) continue;
const spec = structuredUpdateSpec(effect);
if (!spec) continue;
if (!canUpdateStructuredArtifact(effect.target_artifact)) continue;
const targetKey = validateRunRelativePath(effect.target_artifact, `effect ${effect.item_id} target_artifact`);
if (isProtectedRunFile(targetKey)) {
throw new Error(`effect ${effect.item_id} may not edit protected run artifact ${targetKey}`);
}
if (!declaredPaths.has(targetKey)) {
throw new Error(`effect ${effect.item_id} target_artifact is not a sealed output: ${targetKey}`);
}
const updateKey = [targetKey, spec.recordsKey || "", spec.idField, spec.recordId, spec.targetField].join("\u0000");
if (updatedRecords.has(updateKey)) {
throw new Error(`multiple structured edits target the same field in ${targetKey}`);
}
updatedRecords.add(updateKey);
const target = resolveSafeRunOutputPath(outputDir, targetKey, { mustExist: true });
const stat = fs.lstatSync(target.absolutePath);
if (!stat.isFile() || stat.isSymbolicLink()) {
throw new Error(`effect ${effect.item_id} target_artifact is not a regular file`);
}
const backupRelativePath = originalBackupRelativePath(effect, target.relativePath);
const backupAbsolutePath = path.join(outputDir, backupRelativePath);
fs.mkdirSync(path.dirname(backupAbsolutePath), { recursive: true });
if (!fs.existsSync(backupAbsolutePath)) {
fs.copyFileSync(target.absolutePath, backupAbsolutePath);
}
const extension = path.extname(target.relativePath).toLowerCase();
const result =
extension === ".csv"
? updateCsvArtifact(target.absolutePath, effect, spec)
: extension === ".jsonl"
? updateJsonlArtifact(target.absolutePath, effect, spec)
: updateJsonArtifact(target.absolutePath, effect, spec);
effect.target_artifact = target.relativePath;
effect.original_artifact_backup = backupRelativePath;
effect.artifact_update = "structured_artifact_updated";
effect.structured_update = {
id_field: spec.idField,
record_id: spec.recordId,
target_field: spec.targetField,
records_key: spec.recordsKey,
updated_rows: result.updatedRows,
};
targetOutputs.push({
path: target.relativePath,
kind: extension.replace(/^\./, "") || "file",
status: "updated_from_review",
item_id: effect.item_id,
row_count: result.rowCount,
required_columns: [spec.idField, spec.targetField],
});
backupOutputs.push({
path: backupRelativePath,
kind: path.extname(backupRelativePath).replace(/^\./, "") || "file",
status: "backup_original",
source_artifact: target.relativePath,
item_id: effect.item_id,
});
}
return { targetOutputs, backupOutputs };
}
function markNativeRegenerationPending(effects) {
const nativeOutputs = [];
for (const effect of effects) {
if (effect.action !== "edit" || !effect.edit_value) continue;
if (effect.artifact_update !== "revision_artifact_written") continue;
if (!needsNativeRegeneration(effect.target_artifact)) continue;
effect.requires_native_regeneration = true;
effect.native_regeneration_status = "pending";
effect.artifact_update = "native_regeneration_pending";
nativeOutputs.push({
path: effect.target_artifact,
kind: path.extname(effect.target_artifact || "").replace(/^\./, "") || "file",
status: "native_regeneration_pending",
item_id: effect.item_id,
revision_artifact: effect.revision_artifact || null,
});
}
return nativeOutputs;
}
function markDerivedNativeRegenerationPending(outputDir, effects, currentFinalArtifacts) {
const nativeOutputs = [];
for (const effect of effects) {
if (effect.action !== "edit" || !effect.edit_value) continue;
if (!["revision_artifact_written", "structured_artifact_updated"].includes(effect.artifact_update)) continue;
const derivedTargets = existingDerivedNativeTargets(
outputDir,
currentFinalArtifacts,
effect.target_artifact,
);
if (!derivedTargets.length) continue;
effect.requires_native_regeneration = true;
effect.native_regeneration_status = "pending";
effect.derived_native_regeneration_paths = derivedTargets;
for (const targetPath of derivedTargets) {
nativeOutputs.push({
path: targetPath,
kind: path.extname(targetPath).replace(/^\./, "") || "file",
status: "native_regeneration_pending",
item_id: effect.item_id,
source_artifact: effect.target_artifact,
});
}
}
return nativeOutputs;
}
function nativeRegenerationPathsForEffect(effect) {
const derivedPaths = Array.isArray(effect.derived_native_regeneration_paths)
? effect.derived_native_regeneration_paths
: [];
const paths = derivedPaths.length
? derivedPaths
: effect.requires_native_regeneration
? [effect.target_artifact]
: [];
return Array.from(new Set(paths.map(artifactPathKey).filter(Boolean)));
}
function statusFromEffects(effects, itemCount) {
if (!effects.length) return "pending_review";
if (effects.some((effect) => effect.requires_followup)) return "blocked";
if (effects.some((effect) => effect.requires_native_regeneration)) return "partial_review_applied";
if (effects.some((effect) => effect.artifact_update === "revision_artifact_written")) {
return "partial_review_applied";
}
if (effects.length < itemCount) return "partial_review_applied";
return "final_ready";
}
function validateDeclaredTextQa(outputDir, finalArtifacts) {
if (!outputDir || !isPlainObject(finalArtifacts)) return;
const outputs = Array.isArray(finalArtifacts.outputs) ? finalArtifacts.outputs : [];
for (const output of outputs) {
if (!isPlainObject(output) || !Array.isArray(output.qa_checks)) continue;
if (!output.qa_checks.includes("nonempty_text") && !output.qa_checks.includes("required_text")) {
continue;
}
const target = resolveSafeRunOutputPath(
outputDir,
validateRunRelativePath(output.path, "final_artifacts.outputs[].path"),
{ mustExist: true },
);
const stat = fs.lstatSync(target.absolutePath);
if (!stat.isFile() || stat.isSymbolicLink()) {
throw new Error(`artifact QA target is not a regular file: ${target.relativePath}`);
}
const text = fs.readFileSync(target.absolutePath, "utf8");
if (output.qa_checks.includes("nonempty_text") && !text.trim()) {
throw new Error(`artifact QA failed nonempty_text: ${target.relativePath}`);
}
if (output.qa_checks.includes("required_text")) {
const required = Array.isArray(output.required_text) ? output.required_text : [];
if (!required.length) {
throw new Error(`artifact QA metadata has no required_text: ${target.relativePath}`);
}
const missing = required.filter(
(fragment) => typeof fragment !== "string" || !fragment || !text.includes(fragment),
);
if (missing.length) {
throw new Error(`artifact QA failed required_text for ${target.relativePath}`);
}
}
}
}
const REVIEW_HANDOFF_PLUGINS = new Set([
"check-entries",
"client-file-preparation",
"journal-sampling",
"journal-bank-reconciliation",
"deep-research-validator",
"prompt-optimizer",
"report-builder",
"concordato-plan-review",
]);
function reviewHandoffOutputRecord() {
return {
path: "review_handoff.md",
kind: "md",
status: "written",
required_text: [
"Review Handoff",
"review_payload.json",
"ui_decisions.json",
"applied_decisions.json",
"final_artifacts.json",
"model_handoff.json",
],
qa_checks: ["nonempty_text", "required_text"],
};
}
function ensureReviewHandoffCard(inputArgs, outputDir) {
const reviewPayload = isPlainObject(inputArgs.review_payload) ? inputArgs.review_payload : {};
const pluginName = shortString(reviewPayload.plugin);
if (!REVIEW_HANDOFF_PLUGINS.has(pluginName) || !outputDir) return null;
const handoffPath = path.join(outputDir, "review_handoff.md");
fs.mkdirSync(outputDir, { recursive: true });
if (!fs.existsSync(handoffPath)) {
const language = shortString(reviewPayload.language) || "en";
const handoffCopy = {
it: {
product: "Preparazione del fascicolo cliente",
title: "Passaggio alla revisione",
payload: "Payload di revisione",
intake: "Dati di esecuzione",
pending: "Decisioni in attesa",
applied: "Decisioni applicate",
artifacts: "Artefatti finali",
model: "Contesto predefinito del modello",
heading: "Revisione in Codex",
validate: "Validare il payload con",
render: "Aprire l’area di revisione con",
save: "Salvare le decisioni con",
apply: "Applicare le decisioni con",
},
en: {
product: "Client file preparation",
title: "Review handoff",
payload: "Review payload",
intake: "Run intake",
pending: "Pending decisions",
applied: "Applied decisions",
artifacts: "Final artifacts",
model: "Default model context",
heading: "Review in Codex",
validate: "Validate the payload with",
render: "Open the review workbench with",
save: "Save reviewer actions with",
apply: "Apply reviewer actions with",
},
fr: {
product: "Préparation du dossier client",
title: "Passage à la revue",
payload: "Données de revue",
intake: "Paramètres d’exécution",
pending: "Décisions en attente",
applied: "Décisions appliquées",
artifacts: "Livrables finaux",
model: "Contexte par défaut du modèle",
heading: "Revue dans Codex",
validate: "Valider les données avec",
render: "Ouvrir l’espace de revue avec",
save: "Enregistrer les décisions avec",
apply: "Appliquer les décisions avec",
},
de: {
product: "Vorbereitung der Mandantenakte",
title: "Übergabe zur Prüfung",
payload: "Prüfdaten",
intake: "Laufdaten",
pending: "Ausstehende Entscheidungen",
applied: "Angewandte Entscheidungen",
artifacts: "Endartefakte",
model: "Standardkontext des Modells",
heading: "Prüfung in Codex",
validate: "Prüfdaten validieren mit",
render: "Prüfansicht öffnen mit",
save: "Entscheidungen speichern mit",
apply: "Entscheidungen anwenden mit",
},
es: {
product: "Preparación del expediente de cliente",
title: "Entrega para revisión",
payload: "Datos de revisión",
intake: "Datos de ejecución",
pending: "Decisiones pendientes",
applied: "Decisiones aplicadas",
artifacts: "Artefactos finales",
model: "Contexto predeterminado del modelo",
heading: "Revisión en Codex",
validate: "Validar los datos con",
render: "Abrir el área de revisión con",
save: "Guardar las decisiones con",
apply: "Aplicar las decisiones con",
},
}[language] || {
product: "Client file preparation",
title: "Review handoff",
payload: "Review payload",
intake: "Run intake",
pending: "Pending decisions",
applied: "Applied decisions",
artifacts: "Final artifacts",
model: "Default model context",
heading: "Review in Codex",
validate: "Validate the payload with",
render: "Open the review workbench with",
save: "Save reviewer actions with",
apply: "Apply reviewer actions with",
};
const text = [
`# ${handoffCopy.product} · ${handoffCopy.title}`,
"<!-- review-contract: Review Handoff -->",
"",
`- ${handoffCopy.payload}: \`review_payload.json\``,
`- ${handoffCopy.intake}: \`run_intake.json\``,
`- ${handoffCopy.pending}: \`ui_decisions.json\``,
`- ${handoffCopy.applied}: \`applied_decisions.json\``,
`- ${handoffCopy.artifacts}: \`final_artifacts.json\``,
`- ${handoffCopy.model}: \`model_handoff.json\``,
"",
`## ${handoffCopy.heading}`,
`1. ${handoffCopy.validate} \`${TOOL_NAMES.validateReview}\`.`,
`2. ${handoffCopy.render} \`${TOOL_NAMES.renderReview}\`.`,
`3. ${handoffCopy.save} \`${TOOL_NAMES.saveDecisions}\`.`,
`4. ${handoffCopy.apply} \`${TOOL_NAMES.applyDecisions}\`.`,
].join("\n");
fs.writeFileSync(handoffPath, `${text}\n`, "utf8");
}
return reviewHandoffOutputRecord();
}
function finalArtifactsWithApplication(
inputArgs,
appliedDecisions,
finalArtifactsPath,
revisionOutputs = [],
targetOutputs = [],
backupOutputs = [],
nativeRegenerationOutputs = [],
modelHandoffOutputs = [],
) {
const reviewPayload = appliedDecisions.review_payload;
const current = currentFinalArtifactsForApplication(inputArgs, finalArtifactsPath);
const outputDir = resolveRunOutputDir(inputArgs);
const outputs = Array.isArray(current.outputs)
? current.outputs.filter((output) => {
if (!modelHandoffOutputs.length) return true;
const outputPath = artifactPathKey(output?.path);
return outputPath !== "model_handoff.json"
&& !outputPath.startsWith("model_handoff_pages/");
})
: [];
function upsertOutput(record) {
const existingIndex = outputs.findIndex((output) => output?.path === record.path);
if (existingIndex >= 0) outputs[existingIndex] = { ...outputs[existingIndex], ...record };
else outputs.push(record);
}
const handoffOutput = ensureReviewHandoffCard(inputArgs, outputDir);
if (handoffOutput) upsertOutput(handoffOutput);
upsertOutput({ path: "ui_decisions.json", kind: "json", status: "written_reviewed" });
upsertOutput({
path: "applied_decisions.json",
kind: "json",
status: appliedDecisions.application_status,
});
for (const output of revisionOutputs) upsertOutput(output);
for (const output of targetOutputs) upsertOutput(output);
for (const output of backupOutputs) upsertOutput(output);
for (const output of nativeRegenerationOutputs) upsertOutput(output);
for (const output of modelHandoffOutputs) upsertOutput(output);
const blockers = effectsToBlockers(appliedDecisions.effects);
return {
schema_version: current.schema_version || reviewPayload.schema_version || "1.0",
plugin: current.plugin || reviewPayload.plugin,
workflow: current.workflow || reviewPayload.workflow,
run_id: current.run_id || reviewPayload.run_id,
outputs,
caveats: Array.isArray(current.caveats) ? current.caveats : [],
blockers,
next_actions: nextActionsWithReviewApplication(
current.next_actions,
appliedDecisions,
blockers,
inputArgs.review_payload?.language || reviewPayload.language,
),
status: appliedDecisions.application_status,
review_status: appliedDecisions.application_status,
review_application: {
applied_at: appliedDecisions.applied_at,
application_status: appliedDecisions.application_status,
decision_count: appliedDecisions.decision_count,
item_count: appliedDecisions.item_count,
blocker_count: appliedDecisions.blocker_count,
revision_count: revisionOutputs.length,
revision_paths: revisionOutputs.map((output) => output.path),
target_update_count: targetOutputs.length,
target_update_paths: targetOutputs.map((output) => output.path),
structured_update_count: appliedDecisions.structured_update_count || 0,
structured_update_paths: appliedDecisions.structured_update_paths || [],
native_regeneration_count: appliedDecisions.native_regeneration_count || 0,
native_regeneration_paths: appliedDecisions.native_regeneration_paths || [],
original_backup_paths: backupOutputs.map((output) => output.path),
model_handoff_paths: modelHandoffOutputs.map((output) => output.path),
applied_decisions_path: "applied_decisions.json",
},
};
}
function effectsToBlockers(effects) {
return effects
.filter((effect) => effect.requires_followup)
.map((effect) => {
const blocker = {
item_id: effect.item_id,
item_type: effect.item_type,
title: effect.title,
action: effect.action,
status: effect.status,
reviewer_note: effect.reviewer_note || null,
requested_documents: Array.isArray(effect.requested_documents)
? effect.requested_documents
: [],
};
if (isPlainObject(effect.followup_context) && Object.keys(effect.followup_context).length) {
blocker.followup_context = effect.followup_context;
}
return blocker;
});
}
function nextActionsWithReviewApplication(currentNextActions, appliedDecisions, blockers, language) {
const nextActions = Array.isArray(currentNextActions) ? [...currentNextActions] : [];
const copy = {
it: {
blockers: "Risolvere le decisioni di review bloccanti prima di considerare pronti gli artefatti finali.",
regenerate: "Rigenerare gli output nativi DOCX/XLSX/PDF prima della consegna finale.",
ready: "Usare final_artifacts.json come galleria verificata degli artefatti per la consegna.",
partial: "Completare le decisioni di review mancanti prima della consegna finale.",
},
en: {
blockers: "Resolve blocked review decisions before treating final artifacts as ready.",
regenerate: "Regenerate native DOCX/XLSX/PDF outputs before final handoff.",
ready: "Use final_artifacts.json as the reviewed artifact gallery for handoff.",
partial: "Complete remaining review decisions before final handoff.",
},
fr: {
blockers: "Résoudre les décisions de revue bloquantes avant de considérer les livrables finaux comme prêts.",
regenerate: "Régénérer les livrables natifs DOCX/XLSX/PDF avant la remise finale.",
ready: "Utiliser final_artifacts.json comme galerie vérifiée des livrables à remettre.",
partial: "Terminer les décisions de revue restantes avant la remise finale.",
},
de: {
blockers: "Blockierende Prüfentscheidungen klären, bevor die Endartefakte als fertig gelten.",
regenerate: "Native DOCX/XLSX/PDF-Ausgaben vor der endgültigen Übergabe neu erzeugen.",
ready: "final_artifacts.json als geprüfte Artefaktübersicht für die Übergabe verwenden.",
partial: "Verbleibende Prüfentscheidungen vor der endgültigen Übergabe abschließen.",
},
es: {
blockers: "Resolver las decisiones de revisión bloqueadas antes de considerar listos los artefactos finales.",
regenerate: "Volver a generar las salidas nativas DOCX/XLSX/PDF antes de la entrega final.",
ready: "Usar final_artifacts.json como galería revisada de artefactos para la entrega.",
partial: "Completar las decisiones de revisión pendientes antes de la entrega final.",
},
}[language] || {
blockers: "Resolve blocked review decisions before treating final artifacts as ready.",
regenerate: "Regenerate native DOCX/XLSX/PDF outputs before final handoff.",
ready: "Use final_artifacts.json as the reviewed artifact gallery for handoff.",
partial: "Complete remaining review decisions before final handoff.",
};
if (blockers.length) {
nextActions.push(copy.blockers);
} else if (appliedDecisions.native_regeneration_count) {
nextActions.push(copy.regenerate);
} else if (appliedDecisions.application_status === "final_ready") {
nextActions.push(copy.ready);
} else if (appliedDecisions.application_status === "partial_review_applied") {
nextActions.push(copy.partial);
}
return Array.from(new Set(nextActions));
}
function applyDecisionPayload(inputArgs) {
inputArgs = inputArgsWithReviewReference(inputArgs);
const { uiDecisions } = buildUiDecisions(inputArgs);
const validationPayload = validateReviewPayload(inputArgs);
const reviewPayload = validationPayload.review_payload;
const persistentInputArgs = inputArgsWithPersistentOutput(inputArgs, reviewPayload);
const persistence = validatePersistentState(persistentInputArgs, reviewPayload);
const reviewer = persistence
? stabilizeReviewer(uiDecisions, persistence.currentUiDecisions)
: normalizeReviewerReference(uiDecisions.reviewer, "reviewer");
if (persistence) {
uiDecisions.review_payload_sha256 = persistence.reviewBytesHash;
uiDecisions.review_payload_canonical_sha256 = persistence.reviewCanonicalHash;
}
const itemById = new Map(reviewPayload.items.map((item) => [item.id, item]));
const appliedAt = new Date().toISOString();
function executeApplication(workingDir, workingInputArgs, currentFinalArtifacts) {
const effects = uiDecisions.decisions.map((decision) =>
buildApplicationEffect(decision, itemById.get(decision.item_id), appliedAt),
);
const workingDecisionPath = workingDir ? path.join(workingDir, "ui_decisions.json") : null;
const workingAppliedPath = workingDir ? path.join(workingDir, "applied_decisions.json") : null;
const workingFinalPath = workingDir ? path.join(workingDir, "final_artifacts.json") : null;
const revisionOutputs = writeRevisionArtifacts(workingDir, effects);
const textUpdates = writeDirectTextArtifactUpdates(
workingDir,
effects,
currentFinalArtifacts,
);
const structuredUpdates = writeStructuredArtifactUpdates(
workingDir,
effects,
currentFinalArtifacts,
);
const nativeRegenerationOutputs = [
...markNativeRegenerationPending(effects),
...markDerivedNativeRegenerationPending(workingDir, effects, currentFinalArtifacts),
];
const targetOutputs = [...textUpdates.targetOutputs, ...structuredUpdates.targetOutputs];
const backupOutputs = [...textUpdates.backupOutputs, ...structuredUpdates.backupOutputs];
const structuredUpdatePaths = effects
.filter((effect) => effect.artifact_update === "structured_artifact_updated")
.map((effect) => effect.target_artifact);
const nativeRegenerationPaths = Array.from(
new Set(effects.flatMap((effect) => nativeRegenerationPathsForEffect(effect))),
);
const blockerCount = effects.filter((effect) => effect.requires_followup).length;
const applicationStatus = statusFromEffects(effects, reviewPayload.items.length);
if (applicationStatus === "final_ready" && !reviewer) {
throw new Error(
"reviewer is required as a stable professional or account reference before phase-one review can become final_ready",
);
}
const appliedDecisions = {
schema_version: reviewPayload.schema_version,
plugin: reviewPayload.plugin,
workflow: reviewPayload.workflow,
run_id: reviewPayload.run_id,
applied_at: appliedAt,
decision_source: uiDecisions.decision_source || "mcp_widget",
review_payload: {
path: uiDecisions.review_payload_path || "review_payload.json",
item_count: reviewPayload.items.length,
review_type: reviewPayload.review_type || null,
...(persistence
? {
sha256: persistence.reviewBytesHash,
canonical_sha256: persistence.reviewCanonicalHash,
}
: {}),
},
decisions: uiDecisions.decisions,
effects,
decision_count: uiDecisions.decision_count,
item_count: reviewPayload.items.length,
blocker_count: blockerCount,
revision_count: revisionOutputs.length,
revision_paths: revisionOutputs.map((output) => output.path),
target_update_count: targetOutputs.length,
target_update_paths: targetOutputs.map((output) => output.path),
structured_update_count: structuredUpdatePaths.length,
structured_update_paths: structuredUpdatePaths,
native_regeneration_count: nativeRegenerationPaths.length,
native_regeneration_paths: nativeRegenerationPaths,
original_backup_paths: backupOutputs.map((output) => output.path),
application_status: applicationStatus,
};
if (reviewer) appliedDecisions.reviewer = reviewer;
if (workingDecisionPath) {
fs.writeFileSync(
workingDecisionPath,
`${JSON.stringify(uiDecisions, null, 2)}\n`,
"utf8",
);
}
const modelHandoffOutputs = workingDir ? refreshModelHandoff(workingDir) : [];
appliedDecisions.model_handoff_paths = modelHandoffOutputs.map(
(output) => output.path,
);
let responseFinalArtifacts = finalArtifactsWithApplication(
workingInputArgs,
appliedDecisions,
workingFinalPath,
revisionOutputs,
targetOutputs,
backupOutputs,
nativeRegenerationOutputs,
modelHandoffOutputs,
);
validateDeclaredTextQa(workingDir, responseFinalArtifacts);
responseFinalArtifacts.review_payload_sha256 = persistence?.reviewBytesHash || null;
responseFinalArtifacts.review_payload_canonical_sha256 =
persistence?.reviewCanonicalHash || null;
if (workingDecisionPath) {
fs.writeFileSync(workingDecisionPath, `${JSON.stringify(uiDecisions, null, 2)}\n`, "utf8");
}
if (workingAppliedPath) {
fs.writeFileSync(workingAppliedPath, `${JSON.stringify(appliedDecisions, null, 2)}\n`, "utf8");
}
if (workingFinalPath) {
fs.writeFileSync(workingFinalPath, `${JSON.stringify(responseFinalArtifacts, null, 2)}\n`, "utf8");
}
const workflowSpecificResult = applyWorkflowSpecificReviewApplication(
workingDir,
workingAppliedPath,
workingFinalPath,
);
const responseAppliedDecisions =
(isPlainObject(workflowSpecificResult?.applied_decisions)
? workflowSpecificResult.applied_decisions
: null)
|| readJsonFileIfPresent(workingAppliedPath)
|| appliedDecisions;
responseFinalArtifacts =
(isPlainObject(workflowSpecificResult?.final_artifacts)
? workflowSpecificResult.final_artifacts
: null)
|| readJsonFileIfPresent(workingFinalPath)
|| responseFinalArtifacts;
const runIntakePath = appendReviewApplicationExecutionTrace(
workingInputArgs,
workingDir,
responseAppliedDecisions,
responseFinalArtifacts,
);
if (workingDir && workingFinalPath) {
responseFinalArtifacts = refreshFinalArtifactsIntegrity(workingDir, responseFinalArtifacts);
fs.writeFileSync(
workingFinalPath,
`${JSON.stringify(responseFinalArtifacts, null, 2)}\n`,
"utf8",
);
}
return {
responseAppliedDecisions,
responseFinalArtifacts,
runIntakePath,
revisionOutputs,
targetOutputs,
structuredUpdatePaths,
applicationStatus,
};
}
let result;
if (persistence) {
preflightClientWorkflowRun(persistence.outputDir, reviewPayload.run_id);
result = withStagedRunDirectory(persistence.outputDir, (stagedDir) => {
const stagedInputArgs = {
...persistentInputArgs,
run_intake: { ...persistentInputArgs.run_intake, output_dir: stagedDir },
final_artifacts: readJsonFileIfPresent(path.join(stagedDir, "final_artifacts.json")),
};
return executeApplication(
stagedDir,
stagedInputArgs,
stagedInputArgs.final_artifacts,
);
});
} else {
result = executeApplication(
null,
inputArgs,
isPlainObject(inputArgs.final_artifacts) ? inputArgs.final_artifacts : {},
);
}
const {
responseAppliedDecisions,
responseFinalArtifacts,
revisionOutputs,
targetOutputs,
structuredUpdatePaths,
applicationStatus,
} = result;
const outputDir = persistence?.outputDir || null;
const persisted = Boolean(outputDir);
return {
ok: true,
validation_type: "client_file_preparation_application",
run_id: responseAppliedDecisions.run_id,
decision_count: responseAppliedDecisions.decision_count,
item_count: responseAppliedDecisions.item_count,
blocker_count: responseAppliedDecisions.blocker_count,
revision_count: responseAppliedDecisions.revision_count || revisionOutputs.length,
target_update_count: responseAppliedDecisions.target_update_count || targetOutputs.length,
structured_update_count: responseAppliedDecisions.structured_update_count || structuredUpdatePaths.length,
native_regeneration_count: responseAppliedDecisions.native_regeneration_count || 0,
native_regenerated_count: responseAppliedDecisions.native_regenerated_count || 0,
application_status: responseAppliedDecisions.application_status || applicationStatus,
persisted,
ui_decisions_path: persisted ? "ui_decisions.json" : null,
applied_decisions_path: persisted ? "applied_decisions.json" : null,
final_artifacts_path: persisted ? "final_artifacts.json" : null,
run_intake_path: persisted ? "run_intake.json" : null,
message: persisted
? `Applied ${responseAppliedDecisions.decision_count} New Client · File Preparation decisions.`
: "Validated applied decisions. No run_intake.output_dir was provided, so nothing was written.",
applied_decisions: responseAppliedDecisions,
final_artifacts: sanitizedFinalArtifactsForReview(responseFinalArtifacts),
};
}
function applyWorkflowSpecificReviewApplication(
_outputDir,
_appliedOutputPath,
_finalArtifactsPath,
) {
return null;
}
function callTool(name, args = {}) {
if (name === TOOL_NAMES.validateReview) {
const payload = validateReviewPayload(args);
let persistenceToken = null;
try {
persistenceToken = issuePersistenceToken(args, payload.review_payload);
} catch (_error) {
// Validation remains read-only and usable for non-persistent previews.
// Render/save/apply still fail closed when persistence was requested.
}
return {
ok: true,
validation_type: "client_file_preparation_review",
run_id: payload.review_payload.run_id,
item_count: payload.review_payload.item_count,
review_type: payload.review_payload.review_type || null,
message: "New Client · File Preparation review payload is valid. It is safe to call render_client_file_preparation_review once.",
review_reference: persistenceToken ? {
persistence_token: persistenceToken,
run_id: payload.review_payload.run_id,
review_payload_sha256: canonicalSha256(payload.review_payload),
expires_in_seconds: Math.floor(PERSISTENCE_CONTEXT_TTL_MS / 1000),
} : null,
};
}
if (name === TOOL_NAMES.renderReview) {
return reviewPayloadForWidget(inputArgsWithReviewReference(args));
}
if (name === TOOL_NAMES.saveDecisions) {
return saveDecisionPayload(args);
}
if (name === TOOL_NAMES.applyDecisions) {
return applyDecisionPayload(args);
}
throw new Error(`unknown New Client · File Preparation widget tool: ${name}`);
}
function toolResult(payload, toolName) {
const summary = {
ok: payload?.ok !== false,
run_id: payload?.run_id || payload?.review_payload?.run_id || null,
item_count: payload?.item_count ?? payload?.review_payload?.item_count ?? null,
status: payload?.status || payload?.application_status || payload?.review_payload?.status || null,
message: payload?.message || null,
};
const result = {
content: [{ type: "text", text: JSON.stringify(summary) }],
structuredContent: payload,
isError: false,
};
if (toolName === TOOL_NAMES.renderReview) result._meta = toolUiMeta(WIDGET_URI, toolName);
return result;
}
function toolError(message) {
const payload = { ok: false, error: message };
return {
content: [{ type: "text", text: JSON.stringify(payload) }],
structuredContent: payload,
isError: true,
};
}
function rpcResponse(id, result) {
return { jsonrpc: "2.0", id, result };
}
function rpcError(id, code, message) {
return { jsonrpc: "2.0", id, error: { code, message } };
}
function handleRpc(message) {
const messageId = message.id ?? null;
const method = message.method;
const params = isPlainObject(message.params) ? message.params : {};
try {
if (method === "initialize") {
return rpcResponse(messageId, {
protocolVersion: params.protocolVersion || "2024-11-05",
serverInfo: { name: SERVER_NAME, version: SERVER_VERSION },
capabilities: {
tools: {},
resources: {},
prompts: {},
},
instructions:
"Use validate_client_file_preparation_review before render_client_file_preparation_review. Prefer the MCP widget for New Client · File Preparation review handoff; use save_client_file_preparation_decisions to persist reviewer actions to ui_decisions.json and apply_client_file_preparation_decisions to write applied_decisions.json plus final_artifacts.json status when decisions are collected; fall back to Markdown/static review only when MCP is unavailable.",
});
}
if (method === "notifications/initialized") return null;
if (method === "tools/list") return rpcResponse(messageId, { tools: toolDefinitions() });
if (method === "tools/call") {
const { name, arguments: args } = params;
if (typeof name !== "string") return rpcError(messageId, -32602, "tools/call requires a tool name");
if (!isPlainObject(args)) return rpcError(messageId, -32602, "tools/call arguments must be an object");
try {
return rpcResponse(messageId, toolResult(callTool(name, args), name));
} catch (error) {
return rpcResponse(messageId, toolError(error instanceof Error ? error.message : String(error)));
}
}
if (method === "resources/list") return rpcResponse(messageId, { resources: resources() });
if (method === "resources/read") {
const { uri } = params;
if (typeof uri !== "string") return rpcError(messageId, -32602, "resources/read requires a resource uri");
const text = resourceText(uri);
return rpcResponse(messageId, {
contents: [
{
uri,
mimeType: WIDGET_MIME_TYPE,
text,
_meta: widgetResourceMeta(uri),
},
],
});
}
if (method === "resources/templates/list") return rpcResponse(messageId, { resourceTemplates: [] });
if (method === "prompts/list") return rpcResponse(messageId, { prompts: [] });
return rpcError(messageId, -32601, `method not found: ${method}`);
} catch (error) {
return rpcError(messageId, -32000, error instanceof Error ? error.message : String(error));
}
}
function send(payload) {
process.stdout.write(`${JSON.stringify(payload)}\n`);
}
function main() {
const rl = readline.createInterface({ input: process.stdin, crlfDelay: Infinity });
rl.on("line", (line) => {
if (!line.trim()) return;
let message;
try {
message = JSON.parse(line);
} catch (error) {
send(rpcError(null, -32700, "parse error"));
return;
}
const response = handleRpc(message);
if (response != null && message.id != null) send(response);
});
}
main();
SHA-256: abbfd875fb797603d41e6af3819d54b3e63d38cce6093cae8a3895f343531a35