通用执行路径驱动全部生成器("加生成器=加一份声明"):
- @llm: ww_agents +7 输出 schema + 7 spec(book-title/blurb/name/golden-finger/
glossary/opening/fine-outline,只声明 tier)+ build_outline_chapter_context
- @backend: ww_skills GeneratorTool 描述符 + TOOLBOX(11) + get_tool;3 通用端点
GET /skills/toolbox · POST .../skills/{tool_key}/generate(预览不写库,仅记账) ·
POST .../ingest(复用 continuity 409 + partition_writes 白名单);纯 context 派发
- @frontend: 工具箱落地页 RSC + 声明驱动 GeneratorRunner + lib/toolbox 纯函数
+ LeftNav「工具箱」+ ⌘K nav-toolbox/action-gen-*;legacy 3 跳现页
- @qa: tests/test_t6_toolbox_e2e.py 5 用例真 pg + mock 网关零 token,无端点 bug
- P2 收尾: 限流→decisions.md 记延后(单用户原型);noopener/Committable 早已修
守不变量 #2(只声明 tier)/#3(预览不写库,入库经验收 gate)/#9(缓存前缀)。无 DB 迁移。
门禁绿: 后端 ruff/format/mypy 195/alembic 无漂移/pytest 583;前端 lint/tsc/vitest 279/build。
spec 回写 PRODUCT_SPEC §7 + ARCHITECTURE §7.2 端点表。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
76 lines
1.9 KiB
TypeScript
76 lines
1.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
GLOBAL_NAV_ITEMS,
|
|
isNavItemActive,
|
|
projectNavItems,
|
|
type NavItem,
|
|
} from "./items";
|
|
|
|
const PID = "p1";
|
|
|
|
describe("projectNavItems", () => {
|
|
it("builds the nine project entries scoped to the project id", () => {
|
|
const items = projectNavItems(PID);
|
|
|
|
expect(items).toHaveLength(9);
|
|
expect(items.map((i) => i.key)).toEqual([
|
|
"write",
|
|
"outline",
|
|
"foreshadow",
|
|
"review",
|
|
"style",
|
|
"codex",
|
|
"toolbox",
|
|
"rules",
|
|
"skills",
|
|
]);
|
|
expect(items.every((i) => i.href.startsWith(`/projects/${PID}/`))).toBe(
|
|
true,
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("isNavItemActive", () => {
|
|
const write: NavItem = {
|
|
href: `/projects/${PID}/write`,
|
|
label: "写作",
|
|
key: "write",
|
|
};
|
|
|
|
it("matches a project item by its activeNav key regardless of pathname", () => {
|
|
expect(
|
|
isNavItemActive(write, { pathname: "/anything", activeNav: "write" }),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("matches a project item by exact pathname when no activeNav given", () => {
|
|
expect(isNavItemActive(write, { pathname: `/projects/${PID}/write` })).toBe(
|
|
true,
|
|
);
|
|
});
|
|
|
|
it("does not match a project item when neither key nor path align", () => {
|
|
expect(isNavItemActive(write, { pathname: "/", activeNav: "outline" })).toBe(
|
|
false,
|
|
);
|
|
});
|
|
|
|
it("matches a global item by exact pathname only", () => {
|
|
const works = GLOBAL_NAV_ITEMS[0];
|
|
if (!works) throw new Error("expected GLOBAL_NAV_ITEMS[0]");
|
|
expect(isNavItemActive(works, { pathname: "/" })).toBe(true);
|
|
expect(isNavItemActive(works, { pathname: "/projects/p1/write" })).toBe(
|
|
false,
|
|
);
|
|
});
|
|
|
|
it("ignores activeNav for global items (no key)", () => {
|
|
const settings = GLOBAL_NAV_ITEMS[1];
|
|
if (!settings) throw new Error("expected GLOBAL_NAV_ITEMS[1]");
|
|
expect(
|
|
isNavItemActive(settings, { pathname: "/", activeNav: "write" }),
|
|
).toBe(false);
|
|
});
|
|
});
|