Compare commits
1 Commits
main
...
codex/add-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9b7efd256 |
@ -1,6 +1,6 @@
|
|||||||
export const CANVAS_SKILL_TAGS_SETTING_KEY = "canvas_skill_tags";
|
export const CANVAS_SKILL_TAGS_SETTING_KEY = "canvas_skill_tags";
|
||||||
export const CANVAS_SKILL_TAG_ORDER_SETTING_KEY_PREFIX = "canvas_skill_tag_order:";
|
export const CANVAS_SKILL_TAG_ORDER_SETTING_KEY_PREFIX = "canvas_skill_tag_order:";
|
||||||
export const CANVAS_SKILL_TAGS_CONFIG_VERSION = 5;
|
export const CANVAS_SKILL_TAGS_CONFIG_VERSION = 6;
|
||||||
export const DEFAULT_CANVAS_SKILL_TAGS_TITLE = "Claw 快捷技能";
|
export const DEFAULT_CANVAS_SKILL_TAGS_TITLE = "Claw 快捷技能";
|
||||||
|
|
||||||
export type CanvasSkillTagSettings = {
|
export type CanvasSkillTagSettings = {
|
||||||
@ -19,6 +19,27 @@ export type CanvasSkillTag = {
|
|||||||
iconUrl?: string;
|
iconUrl?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const CANVAS_SKILL_TAGS_V6_ADDITIONS: CanvasSkillTag[] = [
|
||||||
|
{
|
||||||
|
id: "product-lifecycle-overview",
|
||||||
|
name: "产品生命周期总览",
|
||||||
|
iconName: "layout-grid",
|
||||||
|
placeholder:
|
||||||
|
"查看公司产品生命周期总览,分析经营阶段、库存风险、SKU迭代和停产清退",
|
||||||
|
prompt:
|
||||||
|
"【前台技能:商品全生命周期】【技能路由:product-lifecycle-archive-db】【技能目录:product-lifecycle-archive】全生命周期产品分析。用途:查看公司内部产品从开款、经营到停产的全生命周期经营总览,包括产品规模、生命周期阶段、SKU 迭代、品类经营、库存周转、停产清退和负责人。进入后直接返回公司产品经营总览,并提供库存风险 TOP10、低效产品结构、品类经营表现、SKU 迭代效果、停产与清退、负责人看板和导出经营盘点表等下一步选择。不要解释成市场类目的引入期/成长期分析,也不要转到市场数据库。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "new-product-progress",
|
||||||
|
name: "新品进度",
|
||||||
|
iconName: "sparkles",
|
||||||
|
placeholder:
|
||||||
|
"输入 SPU、SKU、开款编号、商品ID或流程号,查询新品当前节点和审批时间线",
|
||||||
|
prompt:
|
||||||
|
"【前台技能:商品全生命周期】【技能路由:product-lifecycle-archive-db】【技能目录:product-lifecycle-archive】新品进度查询。用途:查询单个新品当前审批进度,或汇总全部进行中的新品项目。单品查询时先要求用户输入 SPU、SKU、开款编号、商品 ID 或流程号,返回当前节点、当前处理人、审批时间线和流程表单;用户明确要求全部新品时,返回所有未完结新品、超时节点、当前处理人和进行中明细,并提供查看当前卡点、负责人负载、品类进度等下一步选择。不要转到市场新品趋势或商品策划技能。",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const DEFAULT_CANVAS_SKILL_TAGS: CanvasSkillTag[] = [
|
export const DEFAULT_CANVAS_SKILL_TAGS: CanvasSkillTag[] = [
|
||||||
{
|
{
|
||||||
id: "video-gateway",
|
id: "video-gateway",
|
||||||
@ -52,6 +73,7 @@ export const DEFAULT_CANVAS_SKILL_TAGS: CanvasSkillTag[] = [
|
|||||||
prompt:
|
prompt:
|
||||||
"【技能路由:product-detail-planning-v2】用途:通过可恢复的分步对话完成商品详情页全案策划,覆盖产品事实、竞品、真实评价与问大家、内容策划、视觉策划、详情页提示词、五张主图、主图视频、AI 买家秀,以及最终 HTML 和 17 子表 Excel 交付。触发关键词:商品策划案、详情页策划、完整详情策划、新品详情策划、竞品详情分析、详情页改版、主图策划、SKU图策划、主图视频策划、AI买家秀策划、继续详情策划、新版商品策划案、商品策划案V2。通用“商品策划案”默认进入 V2,只有用户明确要求旧版/V1时才使用兼容流程。公司已有商品可提供 SKU/SPU;新品可以提供产品名、现有资料并上传产品图。每轮只处理当前节点,完整展示当前节点数据、系统最优推荐和可选动作,但不得替用户确认或跨节点推进;图片只证明可见结构,不得自动证明材质、参数、检测或服务承诺。全部必需节点完成后生成 HTML 策划案和固定 17 子表 Excel,并返回查看或下载入口。",
|
"【技能路由:product-detail-planning-v2】用途:通过可恢复的分步对话完成商品详情页全案策划,覆盖产品事实、竞品、真实评价与问大家、内容策划、视觉策划、详情页提示词、五张主图、主图视频、AI 买家秀,以及最终 HTML 和 17 子表 Excel 交付。触发关键词:商品策划案、详情页策划、完整详情策划、新品详情策划、竞品详情分析、详情页改版、主图策划、SKU图策划、主图视频策划、AI买家秀策划、继续详情策划、新版商品策划案、商品策划案V2。通用“商品策划案”默认进入 V2,只有用户明确要求旧版/V1时才使用兼容流程。公司已有商品可提供 SKU/SPU;新品可以提供产品名、现有资料并上传产品图。每轮只处理当前节点,完整展示当前节点数据、系统最优推荐和可选动作,但不得替用户确认或跨节点推进;图片只证明可见结构,不得自动证明材质、参数、检测或服务承诺。全部必需节点完成后生成 HTML 策划案和固定 17 子表 Excel,并返回查看或下载入口。",
|
||||||
},
|
},
|
||||||
|
...CANVAS_SKILL_TAGS_V6_ADDITIONS,
|
||||||
{
|
{
|
||||||
id: "install-media-db",
|
id: "install-media-db",
|
||||||
name: "安装资料",
|
name: "安装资料",
|
||||||
@ -195,6 +217,17 @@ function normalizeId(value: unknown, fallbackIndex: number) {
|
|||||||
return id || `tag-${fallbackIndex + 1}`;
|
return id || `tag-${fallbackIndex + 1}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function appendMissingCanvasSkillTags(
|
||||||
|
tags: CanvasSkillTag[],
|
||||||
|
additions: CanvasSkillTag[]
|
||||||
|
) {
|
||||||
|
const existingIds = new Set(tags.map((tag) => tag.id));
|
||||||
|
return [
|
||||||
|
...tags,
|
||||||
|
...additions.filter((tag) => !existingIds.has(tag.id)),
|
||||||
|
].slice(0, 30);
|
||||||
|
}
|
||||||
|
|
||||||
export function normalizeCanvasSkillTags(value: unknown): CanvasSkillTag[] {
|
export function normalizeCanvasSkillTags(value: unknown): CanvasSkillTag[] {
|
||||||
const source = Array.isArray(value) ? value : DEFAULT_CANVAS_SKILL_TAGS;
|
const source = Array.isArray(value) ? value : DEFAULT_CANVAS_SKILL_TAGS;
|
||||||
const usedIds = new Set<string>();
|
const usedIds = new Set<string>();
|
||||||
@ -236,10 +269,14 @@ export function normalizeCanvasSkillTagSettings(
|
|||||||
options: { requireCurrentVersion?: boolean } = {}
|
options: { requireCurrentVersion?: boolean } = {}
|
||||||
): CanvasSkillTagSettings {
|
): CanvasSkillTagSettings {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
|
const tags = appendMissingCanvasSkillTags(
|
||||||
|
normalizeCanvasSkillTags(value),
|
||||||
|
CANVAS_SKILL_TAGS_V6_ADDITIONS
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
title: DEFAULT_CANVAS_SKILL_TAGS_TITLE,
|
title: DEFAULT_CANVAS_SKILL_TAGS_TITLE,
|
||||||
tags: normalizeCanvasSkillTags(value),
|
tags,
|
||||||
version: CANVAS_SKILL_TAGS_CONFIG_VERSION,
|
version: CANVAS_SKILL_TAGS_CONFIG_VERSION,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -249,10 +286,14 @@ export function normalizeCanvasSkillTagSettings(
|
|||||||
const version = Number(row.version || 0);
|
const version = Number(row.version || 0);
|
||||||
if (options.requireCurrentVersion && version < CANVAS_SKILL_TAGS_CONFIG_VERSION) {
|
if (options.requireCurrentVersion && version < CANVAS_SKILL_TAGS_CONFIG_VERSION) {
|
||||||
const title = normalizeString(row.title) || DEFAULT_CANVAS_SKILL_TAGS_TITLE;
|
const title = normalizeString(row.title) || DEFAULT_CANVAS_SKILL_TAGS_TITLE;
|
||||||
|
const tags = appendMissingCanvasSkillTags(
|
||||||
|
normalizeCanvasSkillTags(row.tags),
|
||||||
|
CANVAS_SKILL_TAGS_V6_ADDITIONS
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
enabled: row.enabled !== false,
|
enabled: row.enabled !== false,
|
||||||
title,
|
title,
|
||||||
tags: normalizeCanvasSkillTags(row.tags),
|
tags,
|
||||||
version: CANVAS_SKILL_TAGS_CONFIG_VERSION,
|
version: CANVAS_SKILL_TAGS_CONFIG_VERSION,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { expect, test } from "@playwright/test";
|
import { expect, test } from "@playwright/test";
|
||||||
import {
|
import {
|
||||||
|
CANVAS_SKILL_TAGS_CONFIG_VERSION,
|
||||||
|
CANVAS_SKILL_TAGS_V6_ADDITIONS,
|
||||||
DEFAULT_CANVAS_SKILL_TAGS,
|
DEFAULT_CANVAS_SKILL_TAGS,
|
||||||
normalizeCanvasSkillTagSettings,
|
normalizeCanvasSkillTagSettings,
|
||||||
type CanvasSkillTag,
|
type CanvasSkillTag,
|
||||||
@ -161,7 +163,7 @@ test.describe.serial("/api/admin/settings", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("canvas skill tag upgrades preserve admin configured tags without restoring defaults", () => {
|
test("canvas skill tag upgrades preserve custom tags and append new managed skills", () => {
|
||||||
const customTags: CanvasSkillTag[] = [
|
const customTags: CanvasSkillTag[] = [
|
||||||
{
|
{
|
||||||
id: "custom-claw-skill",
|
id: "custom-claw-skill",
|
||||||
@ -183,17 +185,45 @@ test.describe.serial("/api/admin/settings", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(normalized.title).toBe("试试这些 Skills");
|
expect(normalized.title).toBe("试试这些 Skills");
|
||||||
expect(normalized.tags).toEqual(customTags);
|
expect(normalized.tags).toEqual([
|
||||||
|
...customTags,
|
||||||
|
...CANVAS_SKILL_TAGS_V6_ADDITIONS,
|
||||||
|
]);
|
||||||
expect(
|
expect(
|
||||||
normalized.tags.some((tag) => tag.id === "promotion-diagnosis-db")
|
normalized.tags.some((tag) => tag.id === "promotion-diagnosis-db")
|
||||||
).toBe(false);
|
).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("current canvas skill tag settings can intentionally remove managed skills", () => {
|
||||||
|
const customTags: CanvasSkillTag[] = [
|
||||||
|
{
|
||||||
|
id: "custom-claw-skill",
|
||||||
|
name: "自定义技能",
|
||||||
|
prompt: "只保留后台手动配置的技能。",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const normalized = normalizeCanvasSkillTagSettings(
|
||||||
|
{
|
||||||
|
enabled: true,
|
||||||
|
title: "Claw 快捷技能",
|
||||||
|
tags: customTags,
|
||||||
|
version: CANVAS_SKILL_TAGS_CONFIG_VERSION,
|
||||||
|
},
|
||||||
|
{ requireCurrentVersion: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(normalized.tags).toEqual(customTags);
|
||||||
|
});
|
||||||
|
|
||||||
test("canvas skill tags still use defaults when no stored setting exists", () => {
|
test("canvas skill tags still use defaults when no stored setting exists", () => {
|
||||||
const normalized = normalizeCanvasSkillTagSettings(null, {
|
const normalized = normalizeCanvasSkillTagSettings(null, {
|
||||||
requireCurrentVersion: true,
|
requireCurrentVersion: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(normalized.tags).toEqual(DEFAULT_CANVAS_SKILL_TAGS);
|
expect(normalized.tags).toEqual(DEFAULT_CANVAS_SKILL_TAGS);
|
||||||
|
expect(normalized.tags.map((tag) => tag.name)).toEqual(
|
||||||
|
expect.arrayContaining(["产品生命周期总览", "新品进度"])
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user