feat: add decision center diary imports
This commit is contained in:
@@ -74,7 +74,7 @@ function readMarkdownFile(path: string): { absolutePath: string; markdown: strin
|
||||
const absolutePath = resolve(repoRoot, path);
|
||||
const markdown = readFileSync(absolutePath, "utf8");
|
||||
if (markdown.trim().length === 0) throw new Error(`markdown file is empty: ${absolutePath}`);
|
||||
if (markdown.length > 1_000_000) throw new Error(`markdown file is too large: ${absolutePath}`);
|
||||
if (markdown.length > 4_500_000) throw new Error(`markdown file is too large: ${absolutePath}`);
|
||||
return { absolutePath, markdown };
|
||||
}
|
||||
|
||||
@@ -143,6 +143,64 @@ async function uploadMeetingAsync(args: string[], fetcher: (path: string, init?:
|
||||
return { file: absolutePath, result: unwrapProxyResponse(await decisionProxyAsync(fetcher, endpoint, { method: "POST", body })) };
|
||||
}
|
||||
|
||||
function summarizeDiaryImportResult(result: unknown, includeEntries: boolean): unknown {
|
||||
const body = typeof result === "object" && result !== null && !Array.isArray(result) ? result as Record<string, unknown> : {};
|
||||
const entries = Array.isArray(body.entries) ? body.entries : [];
|
||||
const summaryEntries = entries.map((item) => {
|
||||
const record = typeof item === "object" && item !== null && !Array.isArray(item) ? item as Record<string, unknown> : {};
|
||||
return {
|
||||
id: record.id,
|
||||
date: record.date,
|
||||
month: record.month,
|
||||
title: record.title,
|
||||
markdownPath: record.markdownPath,
|
||||
summary: record.summary,
|
||||
sourceFile: record.sourceFile,
|
||||
updatedAt: record.updatedAt,
|
||||
};
|
||||
});
|
||||
return {
|
||||
...body,
|
||||
entries: includeEntries ? summaryEntries : summaryEntries.slice(0, 20),
|
||||
entriesOmitted: includeEntries ? 0 : Math.max(0, summaryEntries.length - 20),
|
||||
outputPolicy: includeEntries
|
||||
? { bounded: false, entries: summaryEntries.length }
|
||||
: { bounded: true, entriesShown: Math.min(summaryEntries.length, 20), fullCommand: "Re-run with --include-entries to show every imported day summary." },
|
||||
};
|
||||
}
|
||||
|
||||
function diaryImportPayload(args: string[]): { absolutePath: string; payload: Record<string, unknown> } {
|
||||
const file = positionalArgs(args)[0];
|
||||
if (!file) throw new Error("decision diary import requires markdown file");
|
||||
const { absolutePath, markdown } = readMarkdownFile(file);
|
||||
return {
|
||||
absolutePath,
|
||||
payload: {
|
||||
markdown,
|
||||
sourceFile: optionValue(args, ["--source-file", "--source-path", "--source"]) ?? absolutePath,
|
||||
tags: splitList(optionValues(args, ["--tag", "--tags"])),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function importDiary(args: string[]): unknown {
|
||||
const { absolutePath, payload } = diaryImportPayload(args);
|
||||
const result = unwrapProxyResponse(decisionProxy("/api/diary/import", { method: "POST", body: payload }));
|
||||
const body = typeof result === "object" && result !== null && !Array.isArray(result) && "body" in result
|
||||
? (result as { body?: unknown }).body
|
||||
: result;
|
||||
return { file: absolutePath, result: { ...(typeof result === "object" && result !== null && !Array.isArray(result) && "upstream" in result ? { upstream: (result as { upstream?: unknown }).upstream } : {}), body: summarizeDiaryImportResult(body, args.includes("--include-entries")) } };
|
||||
}
|
||||
|
||||
async function importDiaryAsync(args: string[], fetcher: (path: string, init?: { method?: string; body?: unknown }) => Promise<unknown>): Promise<unknown> {
|
||||
const { absolutePath, payload } = diaryImportPayload(args);
|
||||
const result = unwrapProxyResponse(await decisionProxyAsync(fetcher, "/api/diary/import", { method: "POST", body: payload }));
|
||||
const body = typeof result === "object" && result !== null && !Array.isArray(result) && "body" in result
|
||||
? (result as { body?: unknown }).body
|
||||
: result;
|
||||
return { file: absolutePath, result: { ...(typeof result === "object" && result !== null && !Array.isArray(result) && "upstream" in result ? { upstream: (result as { upstream?: unknown }).upstream } : {}), body: summarizeDiaryImportResult(body, args.includes("--include-entries")) } };
|
||||
}
|
||||
|
||||
function listRecords(args: string[]): unknown {
|
||||
const params = new URLSearchParams();
|
||||
const type = optionValue(args, ["--type"]);
|
||||
@@ -175,6 +233,49 @@ async function listRecordsAsync(args: string[], fetcher: (path: string, init?: {
|
||||
return unwrapProxyResponse(await decisionProxyAsync(fetcher, `/api/records${query ? `?${query}` : ""}`));
|
||||
}
|
||||
|
||||
function diaryQuery(args: string[]): string {
|
||||
const params = new URLSearchParams();
|
||||
const month = optionValue(args, ["--month"]);
|
||||
const from = optionValue(args, ["--from"]);
|
||||
const to = optionValue(args, ["--to"]);
|
||||
const sourceFile = optionValue(args, ["--source-file", "--source-path", "--source"]);
|
||||
const limit = optionValue(args, ["--limit"]);
|
||||
if (month !== undefined) params.set("month", month);
|
||||
if (from !== undefined) params.set("from", from);
|
||||
if (to !== undefined) params.set("to", to);
|
||||
if (sourceFile !== undefined) params.set("sourceFile", sourceFile);
|
||||
if (limit !== undefined) params.set("limit", limit);
|
||||
if (args.includes("--include-body")) params.set("includeBody", "true");
|
||||
const query = params.toString();
|
||||
return query ? `?${query}` : "";
|
||||
}
|
||||
|
||||
function listDiary(args: string[]): unknown {
|
||||
return unwrapProxyResponse(decisionProxy(`/api/diary/entries${diaryQuery(args)}`));
|
||||
}
|
||||
|
||||
async function listDiaryAsync(args: string[], fetcher: (path: string, init?: { method?: string; body?: unknown }) => Promise<unknown>): Promise<unknown> {
|
||||
return unwrapProxyResponse(await decisionProxyAsync(fetcher, `/api/diary/entries${diaryQuery(args)}`));
|
||||
}
|
||||
|
||||
function listDiaryMonths(): unknown {
|
||||
return unwrapProxyResponse(decisionProxy("/api/diary/months"));
|
||||
}
|
||||
|
||||
async function listDiaryMonthsAsync(fetcher: (path: string, init?: { method?: string; body?: unknown }) => Promise<unknown>): Promise<unknown> {
|
||||
return unwrapProxyResponse(await decisionProxyAsync(fetcher, "/api/diary/months"));
|
||||
}
|
||||
|
||||
function showDiary(key: string | undefined): unknown {
|
||||
if (!key) throw new Error("decision diary show requires entry id or YYYY-MM-DD date");
|
||||
return unwrapProxyResponse(decisionProxy(`/api/diary/entries/${encodeURIComponent(key)}`));
|
||||
}
|
||||
|
||||
async function showDiaryAsync(key: string | undefined, fetcher: (path: string, init?: { method?: string; body?: unknown }) => Promise<unknown>): Promise<unknown> {
|
||||
if (!key) throw new Error("decision diary show requires entry id or YYYY-MM-DD date");
|
||||
return unwrapProxyResponse(await decisionProxyAsync(fetcher, `/api/diary/entries/${encodeURIComponent(key)}`));
|
||||
}
|
||||
|
||||
function showRecord(id: string | undefined): unknown {
|
||||
if (!id) throw new Error("decision show requires record id");
|
||||
return unwrapProxyResponse(decisionProxy(`/api/records/${encodeURIComponent(id)}`));
|
||||
@@ -187,6 +288,14 @@ async function showRecordAsync(id: string | undefined, fetcher: (path: string, i
|
||||
|
||||
export async function runDecisionCenterCommand(_config: UniDeskConfig, args: string[]): Promise<unknown> {
|
||||
const [action = "list", id] = args;
|
||||
if (action === "diary") {
|
||||
const [diaryAction = "list", diaryId] = args.slice(1);
|
||||
if (diaryAction === "import") return importDiary(args.slice(2));
|
||||
if (diaryAction === "list") return listDiary(args.slice(2));
|
||||
if (diaryAction === "months") return listDiaryMonths();
|
||||
if (diaryAction === "show") return showDiary(diaryId);
|
||||
throw new Error("decision diary command must be one of: import, list, months, show");
|
||||
}
|
||||
if (action === "upload") return uploadMeeting(args.slice(1));
|
||||
if (action === "list") return listRecords(args.slice(1));
|
||||
if (action === "show") return showRecord(id);
|
||||
@@ -200,6 +309,14 @@ export async function runDecisionCenterCommandAsync(
|
||||
fetcher: (path: string, init?: { method?: string; body?: unknown }) => Promise<unknown>,
|
||||
): Promise<unknown> {
|
||||
const [action = "list", id] = args;
|
||||
if (action === "diary") {
|
||||
const [diaryAction = "list", diaryId] = args.slice(1);
|
||||
if (diaryAction === "import") return importDiaryAsync(args.slice(2), fetcher);
|
||||
if (diaryAction === "list") return listDiaryAsync(args.slice(2), fetcher);
|
||||
if (diaryAction === "months") return listDiaryMonthsAsync(fetcher);
|
||||
if (diaryAction === "show") return showDiaryAsync(diaryId, fetcher);
|
||||
throw new Error("decision diary command must be one of: import, list, months, show");
|
||||
}
|
||||
if (action === "upload") return uploadMeetingAsync(args.slice(1), fetcher);
|
||||
if (action === "list") return listRecordsAsync(args.slice(1), fetcher);
|
||||
if (action === "show") return showRecordAsync(id, fetcher);
|
||||
|
||||
Reference in New Issue
Block a user