feat: productize decision center backend APIs
This commit is contained in:
+129
-28
@@ -3,14 +3,14 @@ import { resolve } from "node:path";
|
||||
import { type UniDeskConfig, repoRoot } from "./config";
|
||||
import { coreInternalFetch } from "./microservices";
|
||||
|
||||
type DecisionRecordType = "meeting" | "decision" | "goal" | "blocker" | "debt" | "experiment";
|
||||
type DecisionRecordType = "meeting" | "decision" | "goal" | "external_goal" | "internal_goal" | "blocker" | "debt" | "experiment";
|
||||
type RequirementRecordType = Exclude<DecisionRecordType, "meeting">;
|
||||
type DecisionRecordLevel = "G0" | "G1" | "G2" | "G3" | "P0" | "P1" | "P2" | "P3" | "none";
|
||||
type DecisionRecordStatus = "active" | "blocked" | "parked" | "done";
|
||||
|
||||
const serviceId = "decision-center";
|
||||
const typeValues = new Set<DecisionRecordType>(["meeting", "decision", "goal", "blocker", "debt", "experiment"]);
|
||||
const requirementTypeValues = new Set<RequirementRecordType>(["decision", "goal", "blocker", "debt", "experiment"]);
|
||||
const typeValues = new Set<DecisionRecordType>(["meeting", "decision", "goal", "external_goal", "internal_goal", "blocker", "debt", "experiment"]);
|
||||
const requirementTypeValues = new Set<RequirementRecordType>(["decision", "goal", "external_goal", "internal_goal", "blocker", "debt", "experiment"]);
|
||||
const levelValues = new Set<DecisionRecordLevel>(["G0", "G1", "G2", "G3", "P0", "P1", "P2", "P3", "none"]);
|
||||
const statusValues = new Set<DecisionRecordStatus>(["active", "blocked", "parked", "done"]);
|
||||
|
||||
@@ -129,12 +129,14 @@ function uploadMeeting(args: string[]): unknown {
|
||||
markdown,
|
||||
title: optionValue(args, ["--title"]),
|
||||
type,
|
||||
level: parseLevel(optionValue(args, ["--level"]), "none"),
|
||||
level: parseLevel(optionValue(args, ["--level", "--priority"]), "none"),
|
||||
status: parseStatus(optionValue(args, ["--status"]), "active"),
|
||||
linkedGoalId: optionValue(args, ["--linked-goal-id", "--linkedGoalId"]),
|
||||
tags: splitList(optionValues(args, ["--tag", "--tags"])),
|
||||
evidenceLinks: splitList(optionValues(args, ["--evidence", "--evidence-link", "--evidenceLinks"])),
|
||||
source: optionValue(args, ["--source"]),
|
||||
sourceSession: optionValue(args, ["--source-session", "--sourceSession"]),
|
||||
issueId: optionValue(args, ["--issue", "--issue-id", "--issueId", "--linked-issue", "--linked-task"]),
|
||||
taskId: optionValue(args, ["--task-id", "--taskId"]),
|
||||
commitId: optionValue(args, ["--commit-id", "--commitId"]),
|
||||
};
|
||||
@@ -152,12 +154,14 @@ async function uploadMeetingAsync(args: string[], fetcher: (path: string, init?:
|
||||
markdown,
|
||||
title: optionValue(args, ["--title"]),
|
||||
type,
|
||||
level: parseLevel(optionValue(args, ["--level"]), "none"),
|
||||
level: parseLevel(optionValue(args, ["--level", "--priority"]), "none"),
|
||||
status: parseStatus(optionValue(args, ["--status"]), "active"),
|
||||
linkedGoalId: optionValue(args, ["--linked-goal-id", "--linkedGoalId"]),
|
||||
tags: splitList(optionValues(args, ["--tag", "--tags"])),
|
||||
evidenceLinks: splitList(optionValues(args, ["--evidence", "--evidence-link", "--evidenceLinks"])),
|
||||
source: optionValue(args, ["--source"]),
|
||||
sourceSession: optionValue(args, ["--source-session", "--sourceSession"]),
|
||||
issueId: optionValue(args, ["--issue", "--issue-id", "--issueId", "--linked-issue", "--linked-task"]),
|
||||
taskId: optionValue(args, ["--task-id", "--taskId"]),
|
||||
commitId: optionValue(args, ["--commit-id", "--commitId"]),
|
||||
};
|
||||
@@ -238,8 +242,10 @@ function recordQuery(args: string[], options: { requirementOnly?: boolean } = {}
|
||||
const params = new URLSearchParams();
|
||||
const type = optionValue(args, ["--type"]);
|
||||
const status = optionValue(args, ["--status"]);
|
||||
const level = optionValue(args, ["--level"]);
|
||||
const level = optionValue(args, ["--level", "--priority"]);
|
||||
const linkedGoalId = optionValue(args, ["--linked-goal-id", "--linkedGoalId"]);
|
||||
const source = optionValue(args, ["--source"]);
|
||||
const issueId = optionValue(args, ["--issue", "--issue-id", "--issueId", "--linked-issue", "--linked-task"]);
|
||||
const tag = optionValue(args, ["--tag", "--tags"]);
|
||||
const queryText = optionValue(args, ["--query", "--q"]);
|
||||
const limit = optionValue(args, ["--limit"]);
|
||||
@@ -247,6 +253,8 @@ function recordQuery(args: string[], options: { requirementOnly?: boolean } = {}
|
||||
if (status !== undefined) params.set("status", parseStatus(status, "active"));
|
||||
if (level !== undefined) params.set("level", parseLevel(level, "none"));
|
||||
if (linkedGoalId !== undefined) params.set("linkedGoalId", linkedGoalId);
|
||||
if (source !== undefined) params.set("source", source);
|
||||
if (issueId !== undefined) params.set("issueId", issueId);
|
||||
if (tag !== undefined) params.set("tag", tag);
|
||||
if (queryText !== undefined) params.set("q", queryText);
|
||||
if (limit !== undefined) params.set("limit", limit);
|
||||
@@ -278,6 +286,14 @@ async function listDiaryAsync(args: string[], fetcher: (path: string, init?: { m
|
||||
return unwrapProxyResponse(await decisionProxyAsync(fetcher, `/api/diary/entries${diaryQuery(args)}`));
|
||||
}
|
||||
|
||||
function diaryHistory(args: string[]): unknown {
|
||||
return unwrapProxyResponse(decisionProxy(`/api/diary/history${diaryQuery(args)}`));
|
||||
}
|
||||
|
||||
async function diaryHistoryAsync(args: string[], fetcher: (path: string, init?: { method?: string; body?: unknown }) => Promise<unknown>): Promise<unknown> {
|
||||
return unwrapProxyResponse(await decisionProxyAsync(fetcher, `/api/diary/history${diaryQuery(args)}`));
|
||||
}
|
||||
|
||||
function listDiaryMonths(): unknown {
|
||||
return unwrapProxyResponse(decisionProxy("/api/diary/months"));
|
||||
}
|
||||
@@ -296,6 +312,14 @@ async function showDiaryAsync(key: string | undefined, fetcher: (path: string, i
|
||||
return unwrapProxyResponse(await decisionProxyAsync(fetcher, `/api/diary/entries/${encodeURIComponent(key)}`));
|
||||
}
|
||||
|
||||
function todayDiary(): unknown {
|
||||
return unwrapProxyResponse(decisionProxy("/api/diary/today"));
|
||||
}
|
||||
|
||||
async function todayDiaryAsync(fetcher: (path: string, init?: { method?: string; body?: unknown }) => Promise<unknown>): Promise<unknown> {
|
||||
return unwrapProxyResponse(await decisionProxyAsync(fetcher, "/api/diary/today"));
|
||||
}
|
||||
|
||||
function diaryEditPayload(args: string[], command: string): { key: string; payload: Record<string, unknown>; bodySource: Record<string, string> } {
|
||||
const key = positionalArgs(args)[0];
|
||||
if (!key) throw new Error(`${command} requires entry id or YYYY-MM-DD date`);
|
||||
@@ -320,6 +344,30 @@ async function editDiaryAsync(args: string[], fetcher: (path: string, init?: { m
|
||||
return { key, bodySource, result: unwrapProxyResponse(await decisionProxyAsync(fetcher, `/api/diary/entries/${encodeURIComponent(key)}`, { method: "PUT", body: payload })) };
|
||||
}
|
||||
|
||||
function editTodayDiary(args: string[]): unknown {
|
||||
const { body, bodySource } = bodyFromArgs(args, "decision diary today --edit");
|
||||
const payload: Record<string, unknown> = { body };
|
||||
const title = optionValue(args, ["--title"]);
|
||||
const sourceFile = optionValue(args, ["--source-file", "--source-path", "--source"]);
|
||||
if (title !== undefined) payload.title = title;
|
||||
if (sourceFile !== undefined) payload.sourceFile = sourceFile;
|
||||
const tags = splitList(optionValues(args, ["--tag", "--tags"]));
|
||||
if (tags.length > 0) payload.tags = tags;
|
||||
return { bodySource, result: unwrapProxyResponse(decisionProxy("/api/diary/today", { method: "PUT", body: payload })) };
|
||||
}
|
||||
|
||||
async function editTodayDiaryAsync(args: string[], fetcher: (path: string, init?: { method?: string; body?: unknown }) => Promise<unknown>): Promise<unknown> {
|
||||
const { body, bodySource } = bodyFromArgs(args, "decision diary today --edit");
|
||||
const payload: Record<string, unknown> = { body };
|
||||
const title = optionValue(args, ["--title"]);
|
||||
const sourceFile = optionValue(args, ["--source-file", "--source-path", "--source"]);
|
||||
if (title !== undefined) payload.title = title;
|
||||
if (sourceFile !== undefined) payload.sourceFile = sourceFile;
|
||||
const tags = splitList(optionValues(args, ["--tag", "--tags"]));
|
||||
if (tags.length > 0) payload.tags = tags;
|
||||
return { bodySource, result: unwrapProxyResponse(await decisionProxyAsync(fetcher, "/api/diary/today", { method: "PUT", body: payload })) };
|
||||
}
|
||||
|
||||
function showRecord(id: string | undefined): unknown {
|
||||
if (!id) throw new Error("decision show requires record id");
|
||||
return unwrapProxyResponse(decisionProxy(`/api/records/${encodeURIComponent(id)}`));
|
||||
@@ -330,26 +378,49 @@ async function showRecordAsync(id: string | undefined, fetcher: (path: string, i
|
||||
return unwrapProxyResponse(await decisionProxyAsync(fetcher, `/api/records/${encodeURIComponent(id)}`));
|
||||
}
|
||||
|
||||
function requirementPayload(args: string[], command: string): Record<string, unknown> {
|
||||
function requirementPayload(args: string[], command: string, options: { partial?: boolean; includeId?: boolean } = {}): Record<string, unknown> {
|
||||
const title = optionValue(args, ["--title"]);
|
||||
const bodyArg = optionValue(args, ["--body"]);
|
||||
const bodyFile = optionValue(args, ["--body-file", "--markdown-file", "--file"]);
|
||||
const body = bodyArg !== undefined ? bodyArg : bodyFile !== undefined ? readMarkdownFile(bodyFile).markdown : undefined;
|
||||
if (!title && body === undefined) throw new Error(`${command} requires --title or --body-file/--body`);
|
||||
return {
|
||||
id: optionValue(args, ["--id"]),
|
||||
title,
|
||||
body,
|
||||
type: parseRequirementType(optionValue(args, ["--type"]), "goal"),
|
||||
level: parseLevel(optionValue(args, ["--level"]), "none"),
|
||||
status: parseStatus(optionValue(args, ["--status"]), "active"),
|
||||
linkedGoalId: optionValue(args, ["--linked-goal-id", "--linkedGoalId"]),
|
||||
tags: splitList(optionValues(args, ["--tag", "--tags"])),
|
||||
evidenceLinks: splitList(optionValues(args, ["--evidence", "--evidence-link", "--evidenceLinks"])),
|
||||
sourceSession: optionValue(args, ["--source-session", "--sourceSession"]),
|
||||
taskId: optionValue(args, ["--task-id", "--taskId"]),
|
||||
commitId: optionValue(args, ["--commit-id", "--commitId"]),
|
||||
};
|
||||
const payload: Record<string, unknown> = {};
|
||||
const id = optionValue(args, ["--id"]);
|
||||
const type = optionValue(args, ["--type"]);
|
||||
const level = optionValue(args, ["--level", "--priority"]);
|
||||
const status = optionValue(args, ["--status"]);
|
||||
const linkedGoalId = optionValue(args, ["--linked-goal-id", "--linkedGoalId"]);
|
||||
const source = optionValue(args, ["--source"]);
|
||||
const sourceSession = optionValue(args, ["--source-session", "--sourceSession"]);
|
||||
const issueId = optionValue(args, ["--issue", "--issue-id", "--issueId", "--linked-issue", "--linked-task"]);
|
||||
const taskId = optionValue(args, ["--task-id", "--taskId"]);
|
||||
const commitId = optionValue(args, ["--commit-id", "--commitId"]);
|
||||
const tags = splitList(optionValues(args, ["--tag", "--tags"]));
|
||||
const evidenceLinks = splitList(optionValues(args, ["--evidence", "--evidence-link", "--evidenceLinks"]));
|
||||
if (options.includeId !== false && id !== undefined) payload.id = id;
|
||||
if (title !== undefined) payload.title = title;
|
||||
if (body !== undefined) payload.body = body;
|
||||
if (type !== undefined || options.partial !== true) payload.type = parseRequirementType(type, "external_goal");
|
||||
if (level !== undefined || options.partial !== true) payload.level = parseLevel(level, "none");
|
||||
if (status !== undefined || options.partial !== true) payload.status = parseStatus(status, "active");
|
||||
if (linkedGoalId !== undefined) payload.linkedGoalId = linkedGoalId;
|
||||
if (tags.length > 0 || options.partial !== true) payload.tags = tags;
|
||||
if (evidenceLinks.length > 0 || options.partial !== true) payload.evidenceLinks = evidenceLinks;
|
||||
if (source !== undefined) payload.source = source;
|
||||
if (sourceSession !== undefined) payload.sourceSession = sourceSession;
|
||||
if (issueId !== undefined) payload.issueId = issueId;
|
||||
if (taskId !== undefined) payload.taskId = taskId;
|
||||
if (commitId !== undefined) payload.commitId = commitId;
|
||||
if (Object.keys(payload).length === 0) throw new Error(`${command} requires at least one field to write`);
|
||||
if (options.partial !== true && title === undefined && body === undefined) throw new Error(`${command} requires --title or --body-file/--body`);
|
||||
return payload;
|
||||
}
|
||||
|
||||
function createRequirement(args: string[]): unknown {
|
||||
return unwrapProxyResponse(decisionProxy("/api/requirements", { method: "POST", body: requirementPayload(args, "decision requirement create") }));
|
||||
}
|
||||
|
||||
async function createRequirementAsync(args: string[], fetcher: (path: string, init?: { method?: string; body?: unknown }) => Promise<unknown>): Promise<unknown> {
|
||||
return unwrapProxyResponse(await decisionProxyAsync(fetcher, "/api/requirements", { method: "POST", body: requirementPayload(args, "decision requirement create") }));
|
||||
}
|
||||
|
||||
function upsertRequirement(args: string[]): unknown {
|
||||
@@ -360,25 +431,50 @@ async function upsertRequirementAsync(args: string[], fetcher: (path: string, in
|
||||
return unwrapProxyResponse(await decisionProxyAsync(fetcher, "/api/requirements", { method: "PUT", body: requirementPayload(args, "decision requirement upsert") }));
|
||||
}
|
||||
|
||||
function showRequirement(id: string | undefined): unknown {
|
||||
if (!id) throw new Error("decision requirement show requires record id");
|
||||
return unwrapProxyResponse(decisionProxy(`/api/requirements/${encodeURIComponent(id)}`));
|
||||
}
|
||||
|
||||
async function showRequirementAsync(id: string | undefined, fetcher: (path: string, init?: { method?: string; body?: unknown }) => Promise<unknown>): Promise<unknown> {
|
||||
if (!id) throw new Error("decision requirement show requires record id");
|
||||
return unwrapProxyResponse(await decisionProxyAsync(fetcher, `/api/requirements/${encodeURIComponent(id)}`));
|
||||
}
|
||||
|
||||
function updateRequirement(id: string | undefined, args: string[]): unknown {
|
||||
if (!id) throw new Error("decision requirement update requires record id");
|
||||
return unwrapProxyResponse(decisionProxy(`/api/requirements/${encodeURIComponent(id)}`, { method: "PUT", body: requirementPayload(args, "decision requirement update", { partial: true, includeId: false }) }));
|
||||
}
|
||||
|
||||
async function updateRequirementAsync(id: string | undefined, args: string[], fetcher: (path: string, init?: { method?: string; body?: unknown }) => Promise<unknown>): Promise<unknown> {
|
||||
if (!id) throw new Error("decision requirement update requires record id");
|
||||
return unwrapProxyResponse(await decisionProxyAsync(fetcher, `/api/requirements/${encodeURIComponent(id)}`, { method: "PUT", body: requirementPayload(args, "decision requirement update", { partial: true, includeId: false }) }));
|
||||
}
|
||||
|
||||
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 === "history") return diaryHistory(args.slice(2));
|
||||
if (diaryAction === "months") return listDiaryMonths();
|
||||
if (diaryAction === "today") return args.includes("--edit") ? editTodayDiary(args.slice(2).filter((arg) => arg !== "--edit")) : todayDiary();
|
||||
if (diaryAction === "show") return showDiary(diaryId);
|
||||
if (diaryAction === "edit" || diaryAction === "upsert") return editDiary(args.slice(2));
|
||||
throw new Error("decision diary command must be one of: import, list, months, show, edit, upsert");
|
||||
throw new Error("decision diary command must be one of: import, list, history, months, today, show, edit, upsert");
|
||||
}
|
||||
if (action === "requirement" || action === "requirements") {
|
||||
const [requirementAction = "list"] = args.slice(1);
|
||||
const [requirementAction = "list", requirementId] = args.slice(1);
|
||||
if (requirementAction === "list") {
|
||||
const query = recordQuery(args.slice(2), { requirementOnly: true });
|
||||
return unwrapProxyResponse(decisionProxy(`/api/requirements${query ? `?${query}` : ""}`));
|
||||
}
|
||||
if (requirementAction === "create") return createRequirement(args.slice(2));
|
||||
if (requirementAction === "upsert") return upsertRequirement(args.slice(2));
|
||||
throw new Error("decision requirement command must be one of: list, upsert");
|
||||
if (requirementAction === "show") return showRequirement(requirementId);
|
||||
if (requirementAction === "update") return updateRequirement(requirementId, args.slice(3));
|
||||
throw new Error("decision requirement command must be one of: list, create, show, update, upsert");
|
||||
}
|
||||
if (action === "upload") return uploadMeeting(args.slice(1));
|
||||
if (action === "list") return listRecords(args.slice(1));
|
||||
@@ -397,19 +493,24 @@ export async function runDecisionCenterCommandAsync(
|
||||
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 === "history") return diaryHistoryAsync(args.slice(2), fetcher);
|
||||
if (diaryAction === "months") return listDiaryMonthsAsync(fetcher);
|
||||
if (diaryAction === "today") return args.includes("--edit") ? editTodayDiaryAsync(args.slice(2).filter((arg) => arg !== "--edit"), fetcher) : todayDiaryAsync(fetcher);
|
||||
if (diaryAction === "show") return showDiaryAsync(diaryId, fetcher);
|
||||
if (diaryAction === "edit" || diaryAction === "upsert") return editDiaryAsync(args.slice(2), fetcher);
|
||||
throw new Error("decision diary command must be one of: import, list, months, show, edit, upsert");
|
||||
throw new Error("decision diary command must be one of: import, list, history, months, today, show, edit, upsert");
|
||||
}
|
||||
if (action === "requirement" || action === "requirements") {
|
||||
const [requirementAction = "list"] = args.slice(1);
|
||||
const [requirementAction = "list", requirementId] = args.slice(1);
|
||||
if (requirementAction === "list") {
|
||||
const query = recordQuery(args.slice(2), { requirementOnly: true });
|
||||
return unwrapProxyResponse(await decisionProxyAsync(fetcher, `/api/requirements${query ? `?${query}` : ""}`));
|
||||
}
|
||||
if (requirementAction === "create") return createRequirementAsync(args.slice(2), fetcher);
|
||||
if (requirementAction === "upsert") return upsertRequirementAsync(args.slice(2), fetcher);
|
||||
throw new Error("decision requirement command must be one of: list, upsert");
|
||||
if (requirementAction === "show") return showRequirementAsync(requirementId, fetcher);
|
||||
if (requirementAction === "update") return updateRequirementAsync(requirementId, args.slice(3), fetcher);
|
||||
throw new Error("decision requirement command must be one of: list, create, show, update, upsert");
|
||||
}
|
||||
if (action === "upload") return uploadMeetingAsync(args.slice(1), fetcher);
|
||||
if (action === "list") return listRecordsAsync(args.slice(1), fetcher);
|
||||
|
||||
+7
-5
@@ -27,14 +27,16 @@ export function rootHelp(): unknown {
|
||||
{ command: "microservice proxy <id> <path> [--method GET|POST|PUT|PATCH|DELETE] [--body-json JSON|--body-file path|--body-stdin] [--raw] [--max-body-bytes N]", description: "Access a private user-service backend path through the same frontend-only proxy used by WebUI; JSON request bodies are supported for controlled write/debug endpoints." },
|
||||
{ command: "microservice diagnostics <id>", description: "Split k3sctl-managed proxy health into provider-gateway, HTTP tunnel, adapter, Kubernetes API service proxy, and target Service checks." },
|
||||
{ command: "microservice tunnel-self-test <id>", description: "Trigger an expected provider HTTP tunnel failure and verify requestId/stage diagnostics are returned." },
|
||||
{ command: "decision upload <markdown-file> [--title text] [--type meeting|decision] [--level G0|G1|G2|G3|P0|P1|P2|P3|none] [--status active|blocked|parked|done] [--linked-goal-id id] [--evidence url]", description: "Upload a meeting note or decision record through backend-core -> decision-center user-service proxy." },
|
||||
{ command: "decision upload <markdown-file> [--title text] [--type meeting|decision|goal|external_goal|internal_goal|blocker|debt|experiment] [--level|--priority G0|G1|G2|G3|P0|P1|P2|P3|none] [--status active|blocked|parked|done] [--source text] [--issue id]", description: "Upload a meeting note or decision/requirement record through backend-core -> decision-center user-service proxy." },
|
||||
{ command: "decision diary import <markdown-file> [--source-file path] [--tag tag] [--include-entries]", description: "Import a dated work log Markdown into PostgreSQL diary entries split as YYYY-MM/YYYY-MM-DD.md." },
|
||||
{ command: "decision diary list [--month YYYY-MM] [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--limit N] [--include-body]", description: "List daily Markdown diary entries stored by Decision Center." },
|
||||
{ command: "decision diary history [--month YYYY-MM] [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--limit N] [--include-body]", description: "Read diary history through the productized history API alias." },
|
||||
{ command: "decision diary today [--edit --body-file path] [--title text] [--tag tag]", description: "Get or create today's diary entry using the service's real current date; --edit saves today's Markdown." },
|
||||
{ command: "decision diary months", description: "List available Decision Center diary months with day counts." },
|
||||
{ command: "decision diary show <YYYY-MM-DD|id>", description: "Show one daily diary Markdown entry." },
|
||||
{ command: "decision diary edit|upsert <YYYY-MM-DD|id> --body-file path [--title text] [--source-file path] [--tag tag]", description: "Create or edit one daily diary entry through PUT /api/diary/entries/:idOrDate via backend-core proxy." },
|
||||
{ command: "decision list [--type ...] [--status ...] [--level ...] [--linked-goal-id id] [--limit N]", description: "List Decision Center records through the user-service proxy." },
|
||||
{ command: "decision requirement list|upsert [--id id] [--title text] [--body-file path] [--type goal|decision|blocker|debt|experiment]", description: "Manage requirement records over the existing records model, excluding meeting records." },
|
||||
{ command: "decision list [--type ...] [--status ...] [--level|--priority ...] [--source text] [--issue id] [--linked-goal-id id] [--limit N]", description: "List Decision Center records through the user-service proxy." },
|
||||
{ command: "decision requirement list|create|show|update|upsert [id] [--title text] [--body-file path] [--type external_goal|internal_goal|goal|decision|blocker|debt|experiment] [--source text] [--issue id]", description: "Manage productized requirement records over the PostgreSQL records model, excluding meeting records." },
|
||||
{ command: "decision show <id>", description: "Show one Decision Center record." },
|
||||
{ command: "deploy check|plan|apply [--file deploy.json|--env dev|prod] [--service id] [--commit full-sha] [--dry-run] [--force]", description: "Reconcile services from a repo+commit manifest; --env reads origin/master:deploy.json environments and applies supported dev target-side rollouts or reviewed D601 registry artifact consumers. code-queue artifact consumption is dev-only." },
|
||||
{ command: "dev-env validate|prewarm-images", description: "Validate D601 unidesk-dev guardrails or prewarm dev foundation images into native k3s containerd through a bounded async job." },
|
||||
@@ -155,8 +157,8 @@ function decisionHelp(): unknown {
|
||||
"bun scripts/cli.ts decision list [--type ...] [--status ...] [--level ...] [--limit N]",
|
||||
"bun scripts/cli.ts decision show <id>",
|
||||
"bun scripts/cli.ts decision health",
|
||||
"bun scripts/cli.ts decision diary import|list|months|show|edit|upsert ...",
|
||||
"bun scripts/cli.ts decision requirement list|upsert ...",
|
||||
"bun scripts/cli.ts decision diary import|list|history|months|today|show|edit|upsert ...",
|
||||
"bun scripts/cli.ts decision requirement list|create|show|update|upsert ...",
|
||||
],
|
||||
description: "Operate Decision Center through the registered user-service proxy.",
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user