Files
OpenClaw-bot-review/app/api/idea-ledger/route.ts
T
Faisal C f59116866f feat: productionize self-improvement and R&D council workflows
- add canonical self-improvement/R&D Council data helpers, APIs, and tests

- persist council decisions, evidence telemetry, and work-order handoff

- harden operator UI states and require operator token by default

- ignore local R&D runtime artifacts
2026-04-30 21:43:45 -05:00

131 lines
2.9 KiB
TypeScript

import {
IDEA_LEDGER_PATH,
localOperatorDeniedPayload,
readJsonFile,
validateLocalOperatorRequest,
writeJsonFile,
} from "@/lib/self-improvement-data.mjs";
const LEDGER_TYPES = new Set(["proposed", "adopted", "rejected", "dormant"]);
function localOnly(request: Request) {
const validation = validateLocalOperatorRequest(request);
if (validation.ok) return null;
return Response.json(localOperatorDeniedPayload(validation.reason), { status: validation.status ?? 403 });
}
function defaultLedger() {
return {
proposed: [],
adopted: [],
rejected: [],
dormant: [],
};
}
export async function GET(request: Request) {
const denied = localOnly(request);
if (denied) return denied;
try {
const data = readJsonFile(IDEA_LEDGER_PATH, defaultLedger());
return Response.json({
success: true,
...data,
});
} catch (error) {
return Response.json(
{
success: false,
message: (error as Error).message,
},
{ status: 500 }
);
}
}
export async function POST(request: Request) {
const denied = localOnly(request);
if (denied) return denied;
try {
const body = await request.json();
const { type, idea } = body;
if (!LEDGER_TYPES.has(type)) {
return Response.json(
{
success: false,
message: `Invalid type: ${type}`,
},
{ status: 400 }
);
}
if (!idea || typeof idea !== "object") {
return Response.json(
{
success: false,
message: "idea object is required",
},
{ status: 400 }
);
}
const data = readJsonFile(IDEA_LEDGER_PATH, defaultLedger());
const ideaWithTimestamp = { ...idea, added_at: new Date().toISOString() };
data[type].push(ideaWithTimestamp);
writeJsonFile(IDEA_LEDGER_PATH, data);
return Response.json({
success: true,
message: `Idea added to ${type} list`,
idea: ideaWithTimestamp,
});
} catch (error) {
return Response.json(
{
success: false,
message: (error as Error).message,
},
{ status: 500 }
);
}
}
export async function DELETE(request: Request) {
const denied = localOnly(request);
if (denied) return denied;
try {
const body = await request.json();
const { type, id } = body;
if (!LEDGER_TYPES.has(type)) {
return Response.json(
{
success: false,
message: `Invalid type: ${type}`,
},
{ status: 400 }
);
}
const data = readJsonFile(IDEA_LEDGER_PATH, defaultLedger());
data[type] = data[type].filter((item: any) => item.id !== id);
writeJsonFile(IDEA_LEDGER_PATH, data);
return Response.json({
success: true,
message: `Idea removed from ${type} list`,
});
} catch (error) {
return Response.json(
{
success: false,
message: (error as Error).message,
},
{ status: 500 }
);
}
}