Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ ParamsPanel(frontend/src/schema.ts:TOOL_REGISTRY 的 JSON Schema 生成表单
| 目录 | 用途 |
|---|---|
| `src/model/` `src/engine/` `src/commons/` | Python 领域资产:数据类(`Artifact`/`Project`)、e2m2e 接缝(`facade_bridge`/`catalog_service`/`exceptions`)、单位/常量/路径/内核 |
| `src-tauri/src/` | Rust 壳:`cmd.rs`(22 个 Tauri command)、`sidecar/`(帧协议客户端)、`assistant/`(pi RPC 适配)、`state.rs`、`update.rs` |
| `src-tauri/src/` | Rust 壳:23 个 Tauri command(`cmd.rs` 11 个、`assistant_cmd.rs` 9 个、`update.rs` 3 个)、`sidecar/`(帧协议客户端)、`assistant/`(pi RPC 适配)、`state.rs`、`update.rs` |
| `frontend/src/` | React 界面;组件 `PascalCase.tsx`,逻辑模块 `camelCase.ts` |
| `tests/` `src-tauri/tests/` `frontend/src/*.test.tsx` | 三套测试,与实现同树 |
| `packaging/` | PyInstaller sidecar spec、release 配置、`scripts/validate-release.sh` |
Expand Down Expand Up @@ -84,9 +84,9 @@ uv run python scripts/smoke_mcp_serve.py # sidecar 打包冒烟(releas
- **依赖注入 / 状态**:Tauri managed state(`SidecarState` / `ProjectState` / `AssistantState`)+ `State<'_>`;Python 构造器注入(`FacadeBridge(kernel_dir, catalog_dir)`、`CatalogService(bridge)`);前端无 store 库,`App.tsx` 单组件 `useState` 集中 + `localStorage`(`tod-*` 键)。
- **硬契约**(违反即坏,改动必守):
1. **`import e2m2e` 之前**把内核目录写入 `SPICE_KERNEL_DIR`(见 `src-tauri/src/lib.rs` setup、`tests/conftest.py`);
2. 单位换算唯一来源 `src/commons/units.py`(`DU_KM=384400`、`TU_SECONDS≈375676.97`),禁止另立换算常量;前端 TU 有两种口径,见 `frontend/src/paramOverlay/index.ts` 注释;
2. 单位换算唯一来源 `src/commons/units.py`(`DU_KM=384400`、`TU_SECONDS≈375190.26`,由 e2m2e 模板常量导出),禁止另立换算常量;前端 TU 有两种口径,见 `frontend/src/paramOverlay/index.ts` 注释;
3. 时间唯一绝对基准是 et 秒(J2000 TDB),`frontend/src/timeBasis.ts` 是换算唯一出口(ADR 0021);
4. 质心归一(画布)与地心归一(算法层)的换算点是 `centroid_normalized_states`(减 μ);理想化会合系到惯性系旋转在 `viz_adapter` / `trajectoryParsing` / `cr3bp` 三处必须同口径(#477);
4. 质心归一(画布)与地心归一(算法层)的换算点是 `centroid_normalized_states`(减 μ);理想化会合系到惯性系旋转在 `viz_adapter` / `trajectoryParsing` 两处必须同口径(#477、#521,`cr3bp` 已不含旋转实现);
5. `serde_json` 的 `preserve_order` 不能关(帧序契约,见 `src-tauri/Cargo.toml` 注释)。
- **领域术语以 `CONTEXT.md` 为正典**(单条轨道、轨道族、参考历元、工具注册……),写代码与文档前先对齐术语表;注释内联 issue/ADR 编号(`#452`、`ADR 0013`)是全仓惯例。

Expand Down
4 changes: 2 additions & 2 deletions frontend/src/AboutModal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ beforeEach(() => {
vi.mocked(getVersion).mockClear();
});

describe("AboutModal component", () => {
describe("AboutModal 组件(#403)", () => {
it("缺省显示 Tauri 运行时真实版本(不再硬编码)", async () => {
render(
<AboutModal open={true} onClose={vi.fn()} onUpdateAvailable={vi.fn()} />
Expand All @@ -37,7 +37,7 @@ describe("AboutModal component", () => {
expect(screen.getByText(/CODE - 地月转移轨道设计系统/)).toBeDefined();
});

it("checks for updates when user clicks check button", async () => {
it("点击检查按钮时检查更新,上抛更新信息并关闭弹窗", async () => {
const mockUpdateInfo: updaterModule.UpdateInfo = {
version: "4.2.0",
currentVersion: "4.1.2",
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ describe("App 布局收缩契约(#462 折叠回归)", () => {
});
});

describe("transferTimelineEvents 转移时间轴事件(5.9.7 maneuver_events)", () => {
describe("transferTimelineEvents 转移时间轴事件(5.9.7 maneuver_events,#504)", () => {
// t 直通词典:被测的是 kind → 词典键的映射,不是文案本身
// t passes keys through: the kind → dictionary-key mapping is under test, not the wording.
const t = (key: string) => key;
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/CanvasOrbitList.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { buildOrbitListItems } from "./orbitListItems";

const CYCLE = ["#4c72b0", "#dd8452", "#55a868", "#c44e52", "#8172b3"];

describe("buildOrbitListItems", () => {
describe("buildOrbitListItems(#469)", () => {
it("无标签项不进清单;色样按色环循环取色", () => {
const items = buildOrbitListItems({
count: 3,
Expand Down Expand Up @@ -80,7 +80,7 @@ describe("buildOrbitListItems", () => {
});
});

describe("CanvasOrbitList", () => {
describe("CanvasOrbitList(#469)", () => {
const items = buildOrbitListItems({
count: 2,
labels: ["甲轨道", "乙轨道"],
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/CanvasToolbar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function setup(overrides: Partial<typeof baseProps> = {}) {
return props;
}

describe("CanvasToolbar component", () => {
describe("CanvasToolbar 组件(#410)", () => {
it("渲染全部投影与中心选项及操作按钮", () => {
setup();
for (const name of ["3D", "XY", "XZ", "YZ"]) {
Expand Down Expand Up @@ -122,7 +122,7 @@ describe("CanvasToolbar 绘制内容切换", () => {
// —— 视图系切换(#428)——
// The view-frame switch (#428).

describe("CanvasToolbar 视图系切换", () => {
describe("CanvasToolbar 视图系切换(#428)", () => {
it("默认渲染会合系/惯性选项,缺省选中会合系", () => {
setup();
expect(screen.getByRole("radio", { name: "会合系" })).toBeDefined();
Expand Down
12 changes: 6 additions & 6 deletions frontend/src/OrbitCanvas.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ afterEach(() => {
vi.restoreAllMocks();
});

describe("OrbitCanvas 轨迹渲染", () => {
describe("OrbitCanvas 轨迹渲染(#405)", () => {
it("渲染后场景中存在与 trajectories 等量的轨迹线", () => {
renderCanvas();
flushFrames();
Expand Down Expand Up @@ -253,7 +253,7 @@ describe("OrbitCanvas 轨迹渲染", () => {
});
});

describe("时刻标记(每条轨迹一个)", () => {
describe("时刻标记(每条轨迹一个,#419)", () => {
// 两条不同时刻区间的轨迹:marker 各自沿自己的 times 插值,区间外隐藏
// Two trajectories with disjoint time spans: each marker interpolates over its own times, hidden outside.
const MULTI_TRAJ: number[][][] = [
Expand Down Expand Up @@ -381,7 +381,7 @@ describe("时刻标记(每条轨迹一个)", () => {
});
});

describe("中心点居中几何", () => {
describe("中心点居中几何(#405)", () => {
// 选定中心后,该天体/平动点的世界坐标应为原点(相机 target 默认 0,0,0)
// After a center is selected, that body/libration point's world coordinate should be the origin (camera target defaults to 0,0,0).
const CASES: { name: string; center: CenterMode; bodyLocalX: number }[] = [
Expand Down Expand Up @@ -419,7 +419,7 @@ describe("中心点居中几何", () => {
});
});

describe("中心切换的相机注视点", () => {
describe("中心切换的相机注视点(#405)", () => {
// 用户场景:L2 轨道族 + 适配(注视点在轨道盒中心)→ 手动切“质心居中”,
// 期望质心(世界原点)成为画面中心,而不是重新适配又盯回轨道盒。
// User scenario: an L2 orbit family + fit (gaze at the orbit-box center), then manually switching to
Expand Down Expand Up @@ -485,7 +485,7 @@ describe("中心切换的相机注视点", () => {
});
});

describe("坐标轴图层", () => {
describe("坐标轴图层(#405)", () => {
it("默认显示:三轴箭头 + X/Y/Z 标注 + 轨道面网格", () => {
render(
<OrbitCanvas
Expand Down Expand Up @@ -600,7 +600,7 @@ const REGIONS: RegionElement[] = [
{ kind: "point", label: "L3", centerDU: [-1.198, 0, 0] },
];

describe("OrbitCanvas regions layer", () => {
describe("OrbitCanvas 分区图层(#432)", () => {
it("传入 regions 时渲染 regions 组:圆族折线 + 点标记 + 标注 sprite", () => {
render(
<OrbitCanvas
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/OrbitInfoPanel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ beforeAll(() => {

const t = (key: string) => translations[key] ?? key;

describe("buildOrbitInfo", () => {
describe("buildOrbitInfo(#476)", () => {
it("族成员段:类型/数据系/Jacobi/点数/跨度/来源齐全", () => {
const info = buildOrbitInfo({
item: { label: "DRO 成员", frame: "会合系无量纲" },
Expand Down Expand Up @@ -83,7 +83,7 @@ describe("buildOrbitInfo", () => {
});
});

describe("OrbitInfoPanel", () => {
describe("OrbitInfoPanel(#476)", () => {
it("空态显示操作指引", () => {
render(<OrbitInfoPanel info={null} />);
expect(screen.getByTestId("orbit-info-panel").textContent).toContain(
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/ProjectTree.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ afterEach(() => {
vi.unstubAllGlobals();
});

describe("ProjectTree 勾选多选", () => {
describe("ProjectTree 勾选多选(#419)", () => {
it("勾选 ≥2 叶子出现“绘制所选”,点击回传勾选集合", async () => {
const { props } = setup();
// 只勾 1 条不出现入口
Expand All @@ -91,7 +91,7 @@ describe("ProjectTree 勾选多选", () => {
});
});

describe("ProjectTree 星标切换", () => {
describe("ProjectTree 星标切换(#419)", () => {
it("行缺 tags 时先查详情再追加 ★(catalog_tag 整体替换,note 不动)", async () => {
const { props } = setup();
fireEvent.click(screen.getAllByRole("button", { name: "星标" })[1]); // NRHO B
Expand All @@ -112,7 +112,7 @@ describe("ProjectTree 星标切换", () => {
});
});

describe("ProjectTree 备注", () => {
describe("ProjectTree 备注(#419)", () => {
it("悬停显示备注摘要(超长截断到 80 字符)", async () => {
setup();
fireEvent.mouseEnter(screen.getByText("Halo A"));
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/RecordDetailPanel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ describe("RecordDetailPanel hooks 规则(#437)", () => {
});
});

describe("RecordDetailPanel 族维度(e2m2e 5.9.3 一轨一记录)", () => {
describe("RecordDetailPanel 族维度(e2m2e 5.9.3 一轨一记录,#486)", () => {
it("族成员记录展示族内序号与所属族批次,不再渲染提升区", () => {
render(<RecordDetailPanel record={RECORD_B} />);
expect(screen.getByText("#2")).toBeDefined();
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/RecordDetailPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export function RecordDetailPanel({ record, transferCandidates, selectedLabel, o
{transferCandidates && transferCandidates.length > 0 && (
<CandidateComparisonCard candidates={transferCandidates} />
)}
<Card size="small" title={detailTitle} style={{ marginTop: 8 }} bodyStyle={{ padding: "8px 12px" }}>
<Card size="small" title={detailTitle} style={{ marginTop: 8 }} styles={{ body: { padding: "8px 12px" } }}>
<Descriptions size="small" column={1} bordered={false}>
<Descriptions.Item label="ID">
<Text copyable style={{ fontSize: 11 }}>{record.record_id}</Text>
Expand Down Expand Up @@ -181,7 +181,7 @@ export function RecordDetailPanel({ record, transferCandidates, selectedLabel, o
function CandidateComparisonCard({ candidates }: { candidates: TransferCandidateView[] }) {
const { t } = useTranslation();
return (
<Card size="small" title={t("panel.candidates_title")} bodyStyle={{ padding: "4px 12px" }}>
<Card size="small" title={t("panel.candidates_title")} styles={{ body: { padding: "4px 12px" } }}>
{candidates.map((c) => (
<div
key={c.key}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/StationKeepingModal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ beforeEach(() => {
vi.mocked(invoke).mockResolvedValue({ status: "ok" });
});

describe("ephemerisSpanDays(纯函数)", () => {
describe("ephemerisSpanDays(纯函数,#416)", () => {
it("优先用 eph/times_jd_tdb 帧取极差(天)", () => {
expect(ephemerisSpanDays(resultWithJdSpan(30))).toBeCloseTo(30, 9);
});
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/TimelineBar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ describe("TimelineBar 播放(#429 播放配置)", () => {
});
});

describe("TimelineBar 基础交互回归", () => {
describe("TimelineBar 基础交互回归(#429)", () => {
it("事件芯片点击跳转到事件时刻", () => {
const props = setup({
events: [{ et: 42, label: "出发脉冲", dv: "3.10 km/s" }],
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/UpdateModal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { UpdateModal } from "./UpdateModal";
import * as updaterModule from "./updater";
import type { UpdateInfo } from "./updater";

describe("UpdateModal component", () => {
describe("UpdateModal 组件(#403)", () => {
const mockUpdateInfo: UpdateInfo = {
version: "4.2.0",
currentVersion: "4.1.2",
Expand All @@ -16,7 +16,7 @@ describe("UpdateModal component", () => {
} as any,
};

it("renders modal when open is true", () => {
it("open 为 true 时渲染弹窗,版本号与更新说明可见", () => {
render(
<UpdateModal
open={true}
Expand All @@ -28,7 +28,7 @@ describe("UpdateModal component", () => {
expect(screen.getByText("New features added")).toBeDefined();
});

it("triggers download when clicking download button", async () => {
it("点击下载按钮后调用下载安装,完成后显示立即重启", async () => {
const downloadAndInstall = vi.fn().mockImplementation(async (cb) => {
cb({ event: "Started", data: { contentLength: 100 } });
cb({ event: "Progress", data: { chunkLength: 100 } });
Expand Down Expand Up @@ -60,7 +60,7 @@ describe("UpdateModal component", () => {
});
});

it("shows downloaded size and percent during download", async () => {
it("下载过程中显示已下载大小与总量进度", async () => {
const downloadAndInstall = vi.fn().mockImplementation(async (cb) => {
cb({ event: "Started", data: { contentLength: 100 } });
cb({ event: "Progress", data: { chunkLength: 40 } });
Expand Down Expand Up @@ -91,7 +91,7 @@ describe("UpdateModal component", () => {
});
});

it("falls back to received-only stats when contentLength is missing", async () => {
it("缺少总量时只显示已下载大小,不出现 x / y 形式", async () => {
const downloadAndInstall = vi.fn().mockImplementation(async (cb) => {
cb({ event: "Started", data: {} });
cb({ event: "Progress", data: { chunkLength: 40 } });
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/assistant/AssistantConfigStrip.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const configOptions = [
},
];

describe("AssistantConfigStrip", () => {
describe("AssistantConfigStrip 配置面(#493)", () => {
it("渲染模型/思考两个控件,未知配置项不渲染(pi 切换后无模式项)", () => {
render(
<AssistantConfigStrip configOptions={configOptions} disabled={false} onChange={vi.fn()} />,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/assistant/SessionSwitcher.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function setup(overrides: Partial<Parameters<typeof SessionSwitcher>[0]> = {}) {
return props;
}

describe("SessionSwitcher", () => {
describe("SessionSwitcher 会话切换(#493)", () => {
it("下拉行显示标题与「消息数 · 相对时间」,无标题显示未命名会话", () => {
setup();
fireEvent.mouseDown(screen.getByRole("combobox"));
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/assistant/chatModel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function toolCard(item: ChatItem): ToolCardData {
return item.card;
}

describe("reset / user_message", () => {
describe("reset / user_message 事件折叠(#492)", () => {
it("reset 清空序列(回放开头)", () => {
const seeded = foldEvent([], { kind: "user_message", text: "旧问题" });
const out = foldEvent(seeded, { kind: "reset" });
Expand All @@ -35,7 +35,7 @@ describe("reset / user_message", () => {
});
});

describe("foldEvent 流式折叠", () => {
describe("foldEvent 流式折叠(#492)", () => {
it("delta 增量归并进同一助手气泡", () => {
let items = foldEvent([], { kind: "delta", text: "你" });
items = foldEvent(items, { kind: "delta", text: "好" });
Expand Down Expand Up @@ -104,7 +104,7 @@ describe("foldEvent 流式折叠", () => {
});
});

describe("回放序列(reset + 逐条重建)", () => {
describe("回放序列(reset + 逐条重建,#492)", () => {
it("foldAll 重建完整时间线:用户/正文/思考/工具卡片", () => {
const replay: AssistantEventPayload[] = [
{ kind: "reset" },
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/cr3bp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const SEED = {
] as [number, number, number, number, number, number],
};

describe("deriv", () => {
describe("deriv(#397)", () => {
it("在初值处与 e2m2e equations_of_motion 一致(含科里奥利项)", () => {
// e2m2e CR3BP_Dynamics.equations_of_motion(0, SEED) 的参考输出
// Reference output of e2m2e CR3BP_Dynamics.equations_of_motion(0, SEED).
Expand All @@ -27,7 +27,7 @@ describe("deriv", () => {
});
});

describe("propagate", () => {
describe("propagate(#397)", () => {
it("传播一个周期后回到起点(闭合误差 < 1e-8)", () => {
const pts = propagate(MU, SEED, 4000);
const s = pts[pts.length - 1];
Expand All @@ -36,7 +36,7 @@ describe("propagate", () => {
});
});

describe("librationPoint", () => {
describe("librationPoint(#397)", () => {
it("地月 L1/L2 与已知值一致", () => {
expect(librationPoint(MU, 1)).toBeCloseTo(0.836915, 5);
expect(librationPoint(MU, 2)).toBeCloseTo(1.155682, 5);
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/i18n.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { describe, it, expect, beforeEach } from "vitest";
import { render, screen } from "@testing-library/react";
import { I18nProvider, useTranslation, translations } from "./i18n";

describe("i18n 词典(固定中文)", () => {
describe("i18n 词典(固定中文,#447)", () => {
it("每个词条非空字符串且键非空", () => {
for (const [key, value] of Object.entries(translations)) {
expect(typeof value).toBe("string");
Expand All @@ -29,7 +29,7 @@ beforeEach(() => {
document.documentElement.lang = "";
});

describe("i18n 中文共享状态", () => {
describe("i18n 中文共享状态(#447)", () => {
it("同一 Provider 下两个组件渲染同一中文文案", () => {
render(
<I18nProvider>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/jacobiColormap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { describe, expect, it } from "vitest";
import { COOLWARM_STOPS, jacobiColor, jacobiNorm } from "./jacobiColormap";

describe("jacobiNorm 归一化范围(matplotlib _get_jacobi_norm 口径)", () => {
describe("jacobiNorm 归一化范围(matplotlib _get_jacobi_norm 口径,#435)", () => {
it("空列表 → (0, 1, 1)", () => {
expect(jacobiNorm([])).toEqual([0, 1, 1]);
});
Expand Down Expand Up @@ -36,7 +36,7 @@ describe("jacobiNorm 归一化范围(matplotlib _get_jacobi_norm 口径)", (
});
});

describe("jacobiColor coolwarm 采样插值", () => {
describe("jacobiColor coolwarm 采样插值(#435)", () => {
it("采样表是 coolwarm 蓝端到红端的 9 档", () => {
expect(COOLWARM_STOPS).toHaveLength(9);
expect(COOLWARM_STOPS[0]).toBe("#3b4cc0");
Expand Down
Loading