CoDEVX / lib /chat-request-context.ts
CodexMacTiger
feat: live package-scoped chat and thinking logs
837e3ac
import type {
ChatProvider,
ParsedCommand,
ResolvedChatContext,
WorkPackage,
} from "./work-package-types";
const SLASH_COMMAND = /^\/(ask|plan|change|execute)\b\s*/i;
export function resolveChatRequestContext(args: {
parsed: ParsedCommand;
detailOpen: boolean;
selectedWorkPackage?: Pick<WorkPackage, "id" | "title" | "shortName">;
}) {
const { parsed, detailOpen, selectedWorkPackage } = args;
const hasExplicitCommand =
Boolean(parsed.mode) || Boolean(parsed.referencedPackageName);
if (hasExplicitCommand) {
return {
parsedCommand: parsed,
shouldAutomateBoard: false,
source: "explicit-command" as const,
};
}
const slashMatch = parsed.instruction.match(SLASH_COMMAND);
if (slashMatch && selectedWorkPackage) {
return {
parsedCommand: {
referencedPackageName: selectedWorkPackage.title,
mode: slashMatch[1].toLowerCase() as "ask" | "plan" | "change" | "execute",
instruction: parsed.instruction.replace(SLASH_COMMAND, "").trim(),
},
shouldAutomateBoard: false,
source: "slash-command" as const,
};
}
if (detailOpen && selectedWorkPackage && parsed.instruction.trim()) {
return {
parsedCommand: {
referencedPackageName: selectedWorkPackage.title,
mode: "ask" as const,
instruction: parsed.instruction,
},
shouldAutomateBoard: false,
source: "selected-package-context" as const,
};
}
return {
parsedCommand: parsed,
shouldAutomateBoard: true,
source: "board-automation" as const,
};
}
export function buildResolvedContext(args: {
parsedCommand?: ParsedCommand;
shouldAutomateBoard?: boolean;
selectedWorkPackage?: Pick<WorkPackage, "id" | "title" | "shortName"> | null;
provider: ChatProvider;
}): ResolvedChatContext {
const { parsedCommand, shouldAutomateBoard, selectedWorkPackage, provider } = args;
if (shouldAutomateBoard || !parsedCommand?.mode) {
return {
scope: "global",
workPackageId: null,
workPackageTitle: null,
mode: "board_automation",
provider,
boardMutationPolicy: "replace_all",
};
}
return {
scope: "package",
workPackageId: selectedWorkPackage?.id ?? null,
workPackageTitle:
selectedWorkPackage?.title ?? parsedCommand.referencedPackageName ?? null,
mode: parsedCommand.mode,
provider,
boardMutationPolicy:
parsedCommand.mode === "ask" ? "none" : "selected_package_only",
};
}
export function buildThinkingSummary(args: {
context: ResolvedChatContext;
model?: string;
note?: string;
}) {
const { context, model, note } = args;
const lines: string[] = [];
if (context.scope === "package" && context.workPackageTitle) {
lines.push(`Resolved scope to ${context.workPackageTitle}.`);
} else {
lines.push("Resolved scope to board-wide planning.");
}
if (context.mode === "board_automation") {
lines.push("Mode: board_automation. Board hydration is allowed.");
} else if (context.boardMutationPolicy === "none") {
lines.push(`Mode: ${context.mode}. Board changes are disabled for this request.`);
} else {
lines.push(
`Mode: ${context.mode}. Board changes are limited to the selected work package.`,
);
}
lines.push(
context.provider === "live"
? `Using live model ${model ?? "configured model"}.`
: "Using mock mode.",
);
if (note) {
lines.push(note);
}
return lines;
}