import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { readProductsFromProjectMd } from "../project/product-md"; export const COMMUNITY_PRODUCT_KEYS = ["enterprise", "cosmic", "xinghan", "flagship"] as const; export type CommunityProductKey = (typeof COMMUNITY_PRODUCT_KEYS)[number]; export interface CommunityProduct { key: CommunityProductKey; label: string; productId: number; productLineId: string; } export interface CommunityProductConfig { key: CommunityProductKey; label: string; productId: number; productLineId: string; source: "project-profile" | "user-selection"; } const SETTINGS_PATH = ".kcode/settings.json"; export const COMMUNITY_PRODUCTS: Record = { enterprise: { key: "enterprise", label: "金蝶AI星空企业版/标准版", productId: 1, productLineId: "35" }, cosmic: { key: "cosmic", label: "金蝶AI苍穹", productId: 87, productLineId: "35" }, xinghan: { key: "xinghan", label: "金蝶AI星瀚", productId: 3, productLineId: "35" }, flagship: { key: "flagship", label: "金蝶AI套件", productId: 93, productLineId: "35" }, }; export const COSMIC_COMMUNITY_OPTIONS = [ COMMUNITY_PRODUCTS.cosmic, COMMUNITY_PRODUCTS.xinghan, COMMUNITY_PRODUCTS.flagship, ]; function readSettings(cwd: string): Record { const settingsPath = resolve(cwd, SETTINGS_PATH); if (!existsSync(settingsPath)) return {}; try { const raw = JSON.parse(readFileSync(settingsPath, "utf8")); if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {}; return raw as Record; } catch { return {}; } } function writeSettings(cwd: string, data: Record): void { const settingsPath = resolve(cwd, SETTINGS_PATH); mkdirSync(dirname(settingsPath), { recursive: true }); writeFileSync(settingsPath, `${JSON.stringify(data, null, 2)}\n`, "utf8"); } function isCommunityProductKey(value: unknown): value is CommunityProductKey { return typeof value === "string" && COMMUNITY_PRODUCT_KEYS.includes(value as CommunityProductKey); } function readSavedConfig(cwd: string): CommunityProductConfig | undefined { const settings = readSettings(cwd); const kingdee = settings.kingdee; if (!kingdee || typeof kingdee !== "object" || Array.isArray(kingdee)) return undefined; const communityQa = (kingdee as Record).communityQa; if (!communityQa || typeof communityQa !== "object" || Array.isArray(communityQa)) return undefined; const key = (communityQa as Record).communityProduct; if (!isCommunityProductKey(key)) return undefined; const product = COMMUNITY_PRODUCTS[key]; return { ...product, source: "user-selection" }; } export function saveCommunityProductConfig(cwd: string, key: CommunityProductKey): CommunityProductConfig { const product = COMMUNITY_PRODUCTS[key]; const settings = readSettings(cwd); const kingdee = settings.kingdee && typeof settings.kingdee === "object" && !Array.isArray(settings.kingdee) ? (settings.kingdee as Record) : {}; kingdee.communityQa = { ...(kingdee.communityQa && typeof kingdee.communityQa === "object" && !Array.isArray(kingdee.communityQa) ? (kingdee.communityQa as Record) : {}), communityProduct: product.key, label: product.label, productId: product.productId, productLineId: product.productLineId, }; settings.kingdee = kingdee; writeSettings(cwd, settings); return { ...product, source: "user-selection" }; } export function resolveCommunityProduct( cwd: string, selectedKey?: CommunityProductKey, ): { ok: true; config: CommunityProductConfig; shouldPersist: boolean } | { ok: false; message: string } { if (selectedKey) { return { ok: true, config: saveCommunityProductConfig(cwd, selectedKey), shouldPersist: false }; } const saved = readSavedConfig(cwd); if (saved) return { ok: true, config: saved, shouldPersist: false }; const projectProducts = readProductsFromProjectMd(cwd); if (projectProducts.some(id => id.startsWith("enterprise-"))) { return { ok: true, config: { ...COMMUNITY_PRODUCTS.enterprise, source: "project-profile" }, shouldPersist: true }; } if (projectProducts.includes("cosmic-java")) { const options = COSMIC_COMMUNITY_OPTIONS.map(p => `${p.label}(communityProduct: "${p.key}")`).join(" / "); return { ok: false, message: [ "当前项目画像是 cosmic-java,但社区检索需要在 Cosmic 体系内选择具体产品目录。", `请先用 KCode question/选择交互询问用户:本次金蝶云社区检索使用哪个产品?选项只能显示中文产品名:金蝶AI苍穹 / 金蝶AI星瀚 / 金蝶AI套件。内部映射为:金蝶AI苍穹=cosmic,金蝶AI星瀚=xinghan,金蝶AI套件=flagship。当前可用映射:${options}。`, "用户选择后,重新调用 kd_cosmic_qa,并传入对应 communityProduct;不要向用户询问 productId。", ].join("\n"), }; } return { ok: false, message: [ "无法确定金蝶云社区产品目录。", "请先确认项目是否已运行 kcode init --cosmic 或 --enterprise。", "如果是 Cosmic 体系,请用 KCode question/选择交互询问用户:金蝶AI苍穹 / 金蝶AI星瀚 / 金蝶AI套件,并把选择作为 communityProduct 传入;不要询问 productId。", ].join("\n"), }; }