dsh-mcmp 2.3.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,50 +1,57 @@
1
- # dsh-mcmp · 数学建模论文自动化流水线(v2)
1
+ # dsh-mcmp · 数学建模竞赛自动化论文撰写系统(v3)
2
2
 
3
3
  [![npm](https://img.shields.io/badge/npm-dsh--mcmp-blue)](https://www.npmjs.com/package/dsh-mcmp)
4
4
 
5
5
  DeepSeek Harness **持久化 Cordis 插件**:面向全国大学生数学建模竞赛论文撰写的全自动流水线。
6
- 粘贴赛题 → 发送一条以 `/loopbegin` 开头的消息 → 插件按 8 大步骤、每步多次迭代自动完成论文撰写,
7
- 全程由专家子智能体「先质疑、再迭代」驱动,成果全部落盘保存,右下角浮动面板实时显示进度百分比。
8
- **无论流水线正常完成、出错还是被中止,最终都会生成一版完整、干净的 Markdown 论文(`论文定稿.md`)。**
6
+ 粘贴赛题 → 发送一条以 `/loopbegin` 开头的消息 → 插件按 **中控台 + 五阶段流水线**(阶段零初始化 →
7
+ 阶段一 EDA → 阶段二建模 → 阶段三撰写 → 阶段四排版,共 22 个子阶段)自动完成论文撰写,
8
+ 每个子阶段由专家子智能体执行,再经**中控台双重质疑**(扫描验证模块 + 评审决策模块)验证,
9
+ 问题按 P0-P3 评级处置(P0/P1/P2 阶段级回滚并持久化教训,P3 精确定点修改),
10
+ 成果全部落盘,右下角浮动面板实时显示阶段/子阶段/中控台/回滚进度。
11
+ **无论流水线正常完成、出错还是被中止,最终都会生成一版完整、干净的 Markdown 论文(`Final_Paper.md`)。**
12
+
13
+ > 完整设计见仓库内两份设计文档:
14
+ > **`架构.md`**(v3.17,流程架构设计书:中控台、五阶段、评级/回滚/教训机制)与
15
+ > **`提示词.md`**(v3.4,全部子智能体 Prompt 模板,主循环提示词由其逐段生成)。
9
16
 
10
17
  ## 功能特性
11
18
 
12
19
  - **消息触发**:输入文本以 `/loopbegin` 开头即自动运行(兼容斜杠命令路径)
13
- - **8 大步骤 × 多迭代**:每轮 19 次迭代,外循环轮数可配置(`--round=N`,默认 1 )
14
- - **质疑驱动**:每个子智能体必须先对上一版成果提出 ≥3 条质疑,再开始本轮工作
15
- - **图表视觉自检与修复**:S5 步骤自动探测识图插件——检测到识图服务/工具( vision_describe、read_image)即自动调用逐张检查定稿图;没有识图能力则让子智能体编写脚本做文本包围盒重叠/越界/乱码分析,发现问题必须**修复并复检**(A 级问题清零),而不是只写报告
16
- - **评审问题修复闭环**:S7 合并"合规检查 + 评审",建立《问题跟踪表》,每个 A/B 级问题必须在论文/图表/代码中**实际修复**并经复核验证,禁止"只写问题不修复"
17
- - **跨步骤缺陷回传(台账机制)**:后续步骤发现前序步骤的错误时,必须登记 `00_缺陷与裁决台账.md` 并**直接修复出错文件**(标注修正来源),下游以台账最新裁决为最高权威——错误在源头修掉,不打下游补丁
18
- - **论文兜底定稿**:S8 组装完整、可直接提交的 `论文定稿.md`;即使流水线提前出错或中止,也会追加一次兜底定稿
19
- - **成果全落盘**:每步迭代完整追加保存(含质疑清单),旧内容绝不覆盖;代码保留全部历史版本;全新运行时旧目录自动归档为 `数学建模流水线_历史归档_*`
20
- - **实时进度面板**:独立浮动窗口(可拖拽/最小化/关闭),显示百分比进度条、当前轮/步骤/迭代、8 步骤打点、日志、产出文件,支持一键中止、重置(全新开始)
21
- - **断点续跑与重置**:中断/关闭窗口不丢进度,再次 `/loopbegin` 自动续跑;`/loopreset` 或面板「重置(全新开始)」清空续跑记录,下次从头跑
22
- - **原生工作流卡片**:聊天区实时显示每个子智能体的运行状态(按阶段分组)
23
-
24
- ## 八大步骤(每轮 19 次迭代)
25
-
26
- | 步骤 | 内容 | 迭代次数 |
27
- |------|------|----------|
28
- | S1 | 赛题分析与建模方案 | 2 次(赛题精读与拆解→建模方案定稿) |
29
- | S2 | 模型建立与求解 | 3 次(模型建立→模型求解→模型验证设计) |
30
- | S3 | 编程实现与数值验证 | 3 次(核心代码→调试与数值验证→封装与自测) |
31
- | S4 | 图表与流程图生成 | 3 次(基础图表与结构图→美化统一→精选定稿) |
32
- | S5 | 图表视觉自检与修复 | 2 次(视觉自检与问题清单→修复与复检) |
33
- | S6 | 论文撰写 | 2 次(初稿→润色终稿) |
34
- | S7 | 评审与修复落实 | 3 次(合规检查与评审→修复落实→修复复核) |
35
- | S8 | 论文定稿与提交包 | 1 次(必产出完整 `论文定稿.md`) |
36
-
37
- > **跨步骤纠错机制**:每一步骤开工前必须先读 `00_缺陷与裁决台账.md`( S1 创建)。发现前序步骤的错误时:①登记台账(编号/证据/修复方案)→ ②直接编辑修复出错文件并标注「第R轮·Sx修正:D#编号」→ ③同步所有下游引用。任何文件与台账最新裁决冲突时,以台账为准。S8 终检台账,未闭环项列入「遗留缺陷清单」。
20
+ - **五阶段 × 22 子阶段**:阶段零(初始化 4)→ 阶段一(EDA 3)→ 阶段二(建模 5)→ 阶段三(撰写 7)→ 阶段四(排版 3),每遍 22 个子阶段,`--round=N` 控制外循环遍数(默认 1,上限 10)
21
+ - **中控台双重质疑**:执行Agent自检与中控台扫描验证执行**同一套六维度质疑标准**(逻辑自洽性/模型合理性/数据敏感性/视觉合理性/规范符合性/教训对照);扫描通过→索引 `VALIDATED`,发现问题→转交评审决策模块
22
+ - **唯一评级机构**:中控台评审决策模块按 **P0-P3** 评级——P0/P1/P2 经 DEPENDENCIES 链追溯根源阶段,阶段级回滚(物理移入 `deprecated/`、索引 `OBSOLETE`、写入教训文件、重跑);P3 精确定点修改(≤3 行代码/≤1 个句子/≤3 个参数,STAGING→VALIDATED)
23
+ - **教训持久化**:每次回滚(<10 次)写入 `ROLLBACK_LESSONS.yaml`(查重去重),所有执行Agent启动时必须完整读取(ACTIVE+RESOLVED)
24
+ - **防崩溃优先**:同一阶段回滚 ≥10 次强制 `FORCED_FINAL` 锁定、通知人工,问题降级为 P3 处理,保证必然产出
25
+ - **执行失败处理**:非质量问题重试 3 次指数退避(5s/10s/20s),全失败暂停人工介入(不计入回滚计数器),失败日志写入 `transactions.log`
26
+ - **索引导航**:`FILE_INDEX.yaml` 记录全部产出物的位置/状态(STAGING/VALIDATED/OBSOLETE/FORCED_FINAL)/依赖,上游状态跨阶段读取有权限校验
27
+ - **视觉模块集成**:涉及图表的子阶段(1.3/2.4/2.5/3.3/3.4/4.2/4.3)按两阶段流程调用视觉模块(详实描述→系统性质疑);不可用时标记"待人工确认"
28
+ - **论文兜底定稿**:4.3 产出 `Final_Paper.md`;即使流水线提前出错或中止,也会追加一次兜底定稿
29
+ - **实时进度面板**:浮动窗口显示总体进度、五阶段打点、当前子阶段、中控台模块、回滚计数与 P0-P3 评级、强制锁定提示、日志、产出文件,支持中止/重置
30
+ - **断点续跑与重置**:中断/关闭窗口不丢进度,再次 `/loopbegin` 自动续跑;`/loopreset` 或面板「重置(全新开始)」清空续跑记录
31
+ - **原生工作流卡片**:聊天区实时显示每个子智能体的运行状态(执行/扫描/评审/兜底)
32
+
33
+ ## 五阶段流水线(每遍 22 个子阶段)
34
+
35
+ | 阶段 | 子阶段 | 核心产出 |
36
+ |------|--------|----------|
37
+ | 阶段零 初始化 | 0.1 创建目录 · 0.2 加载数据 · 0.3 初始化索引 · 0.4 初始化教训文件 | `config/`、`raw_data/`、`FILE_INDEX.yaml`、`ROLLBACK_LESSONS.yaml` |
38
+ | 阶段一 EDA | 1.1 清洗 · 1.2 特征工程 · 1.3 EDA可视化 | 清洗/变换后数据、EDA 图表与报告 |
39
+ | 阶段二 建模 | 2.1 模型筛选 · 2.2 模型建立 · 2.3 模型求解 · 2.4 图表生成 · 2.5 检验与质疑 | 假设/公式、`code/` 求解代码、模型图表、检验质疑报告 |
40
+ | 阶段三 撰写 | 3.1 重述与背景 · 3.2 假设与符号 · 3.3 建模与求解章节 · 3.4 结果分析 · 3.5 摘要 · 3.6 参考文献 · 3.7 附录代码 | `stage_03_outputs/01~07` 各章节 |
41
+ | 阶段四 排版 | 4.1 合并 · 4.2 修正路径 · 4.3 最终产出 | `merged_draft.md`、`merged_with_figures.md`、**`Final_Paper.md`** |
42
+
43
+ > 每个子阶段完成后:执行Agent按 3.3 六维度自检并写入 `_report.yaml`(SUCCESS/HAS_ISSUES/NEEDS_REVIEW)→
44
+ > 中控台扫描验证(SUCCESS )或评审决策(HAS_ISSUES/NEEDS_REVIEW 时)→ 通过后推进下一子阶段。
38
45
 
39
46
  ## 使用方法
40
47
 
41
48
  1. **发送赛题**:把数学建模竞赛题目完整粘贴到对话框并发送;
42
49
  2. **触发插件**:发送一条以 `/loopbegin` 开头的消息:
43
- - `/loopbegin` —— 默认 1
44
- - `/loopbegin --round=3` —— 3 轮外循环(上限 10)
45
- - `/loopbegin --from 题目.txt` —— 从文件读取赛题(支持含空格/中文的文件名,如 `--from 2024 年高教社杯全国大学生数学建模竞赛题目.md`,也可用 `--from=文件` 形式)
46
- - `/loopbegin --model glm-vision/glm-4.7-Flash` —— 可选显式覆盖(也可用 `--provider 提供商 --model 模型` 分拆形式)。**默认不需要此参数**:流水线子任务的模型**强制跟随你在对话右下角选择的模型**(每次启动时读取当前选择);若无法读取(未安装默认模型服务),兜底使用 `deepseek-official/deepseek-v4-flash`(high 推理由 deepseek 提供商默认提供)
47
- 3. **查看进度**:右下角浮动面板(百分比、步骤打点、日志、文件)+ 聊天区工作流卡片。
50
+ - `/loopbegin` —— 默认 1 遍(22 个子阶段)
51
+ - `/loopbegin --round=3` —— 3 遍外循环(上限 10)
52
+ - `/loopbegin --from 题目.txt` —— 从文件读取赛题(支持含空格/中文的文件名,也可用 `--from=文件` 形式)
53
+ - `/loopbegin --model glm-vision/glm-4.7-Flash` —— 可选显式覆盖(也可用 `--provider 提供商 --model 模型` 分拆形式)。**默认不需要此参数**:流水线子任务的模型**强制跟随你在对话右下角选择的模型**(每次启动时读取当前选择);若无法读取,兜底使用 `deepseek-official/deepseek-v4-flash`
54
+ 3. **查看进度**:右下角浮动面板(阶段打点、中控台、回滚、日志、文件)+ 聊天区工作流卡片。
48
55
 
49
56
  辅助命令:`/loopstatus`(查看进度)、`/loopabort`(中止,已产出成果保留)、`/loopreset`(清空状态与断点续跑记录,下次 `/loopbegin` 从头全新开始;等价于面板「重置(全新开始)」按钮)。
50
57
 
@@ -67,9 +74,6 @@ DeepSeek Harness **持久化 Cordis 插件**:面向全国大学生数学建模
67
74
  ```powershell
68
75
  # 一条命令完成:安装包 + 自动注册(通过 bundle 机制)
69
76
  pnpm dsh plugin --profile web add dsh-mcmp
70
- # 等价调用形式:
71
- # dsh plugin --profile web add dsh-mcmp
72
- # npx @deepseek-ai/dsh plugin --profile web add dsh-mcmp
73
77
 
74
78
  # 然后重启:
75
79
  # 重启 pnpm dsh web → 刷新网页
@@ -92,19 +96,25 @@ pnpm dsh plugin --profile web remove dsh-mcmp
92
96
 
93
97
  ```
94
98
  数学建模流水线/
95
- ├── 00_赛题原文.md # 启动时自动保存的赛题
96
- ├── 00_缺陷与裁决台账.md # ★ 跨步骤缺陷台账:错误登记、裁决、向上修复的唯一权威
97
- ├── 01_赛题分析.md ~ 08_论文定稿.md # 八大步骤完整成果(逐迭代追加,含质疑清单/问题跟踪表)
98
- ├── 论文定稿.md # ★ 最终交付:完整、干净的 Markdown 论文(无论成败都会生成)
99
- ├── 代码/ # 全部验证与求解代码(_vN 后缀保留历史版本,绝不删除)
100
- │ └── results/ # 权威结构化结果(CSV/JSON + 结果索引)
101
- ├── 图表/ # 全部图表(定稿/ 为论文插图,归档/ 为冗余图)
102
- └── 数学建模流水线_历史归档_*/ # 全新运行时,上一次运行成果自动归档(改名,不删除)
99
+ ├── config/ # 项目配置(Project_Config.yaml 等)
100
+ ├── raw_data/ # 原始数据
101
+ ├── FILE_INDEX.yaml # 索引文件:全部产出物的位置/状态/依赖(STAGING/VALIDATED/OBSOLETE/FORCED_FINAL)
102
+ ├── ROLLBACK_LESSONS.yaml # ★ 教训文件:回滚教训持久化,执行Agent启动必读
103
+ ├── transactions.log # 事务日志:执行失败、强制锁定、DAG 阻断等
104
+ ├── stage_00_outputs/ # 阶段零产出( _report.yaml 上报文件)
105
+ ├── stage_01_outputs/ # 阶段一产出(清洗/特征/EDA 图表与报告)
106
+ ├── stage_02_outputs/ # 阶段二产出(建模文档、code 求解代码、figures 图表)
107
+ ├── stage_03_outputs/ # 阶段三产出(01~07 各章节 Markdown)
108
+ ├── stage_04_outputs/ # 阶段四产出(合并稿、修正稿)
109
+ ├── code/ # 建模求解核心代码(附录代码来源)
110
+ ├── figures/ # 全部图表
111
+ ├── deprecated/ # 回滚废弃文件(物理移入,不删除;建议每场比赛结束后人工清理)
112
+ └── Final_Paper.md # ★ 最终交付:完整、干净的 Markdown 论文(无论成败都会生成)
103
113
  ```
104
114
 
105
115
  ## 架构
106
116
 
107
- > 插件按职责拆分为三个模块:程序入口(lib/index.js)、论文写作主循环(lib/pipeline.js)、显示界面(lib/client.js)。
117
+ > 插件按职责拆分为三个模块,主循环按《架构.md》v3 实现。
108
118
 
109
119
  ```
110
120
  用户消息(/loopbegin 开头)
@@ -114,20 +124,20 @@ pnpm dsh plugin --profile web remove dsh-mcmp
114
124
  ├─ 输入框内检测:斜杠命令注册 + 消息触发监听 + systemPrompt 模型侧提示
115
125
  ├─ 模型选择:父对话当前选择 / --model 显式覆盖 / 兜底 DeepSeek V4 Flash
116
126
  ├─ 题目检测:提取赛题(对话文本或 --from 文件)
117
- ├─ 识图能力探测(宿主服务/工具注册表扫描;S5 子智能体再自检,以自检为准)
127
+ ├─ 识图能力探测(宿主服务/工具注册表扫描;子智能体以自身工具列表为准)
118
128
  └─ 启动解析与校验(--round/--fresh/--model/--from)→ 委托主循环模块启动
119
129
 
120
130
  论文写作主循环模块(lib/pipeline.js,createPipeline 实例)
121
- ├─ 断点续跑:扫描会话日志中 tool-workflow/* v2 记录,跳过已完成迭代
122
- ├─ 编排器:按 8 步骤 × 19 迭代 × N 轮逐个启动专家子智能体(subagents.spawn)
123
- │ 子智能体:读必读文件 质疑先行(质疑驱动)→ 完成任务 追加落盘 → 返回总结
124
- ├─ 兜底定稿:若 S8 未完成(出错/中止),追加一次子智能体组装完整 论文定稿.md
125
- ├─ 向会话追加 tool-workflow/* 事件 → 聊天区原生工作流卡片
126
- └─ 运行状态/进度快照/中止/重置:供入口命令与面板 API 调用
131
+ ├─ 五阶段 × 22 子阶段:每个子阶段启动执行Agent(提示词由 提示词.md 2.1/2.2 + 三 生成)
132
+ ├─ 中控台·扫描验证模块:执行Agent上报 SUCCESS 后按 3.3 六维度扫描(提示词.md 4.1)
133
+ ├─ 中控台·评审决策模块:P0-P3 评级、根源定位、回滚裁定与 P3 定点修改(提示词.md 5.1)
134
+ ├─ 代码逻辑:回滚计数器、阶段级删除调度、强制锁定(FORCED_FINAL)、重跑、断点续跑
135
+ ├─ 执行失败重试(3 次指数退避)+ 事务日志 transactions.log
136
+ └─ 兜底定稿:不论成败补一版 Final_Paper.md
127
137
 
128
138
  显示界面模块(lib/client.js,标准 __ModuleLoader__ bundle)
129
139
  ├─ shell.overlay 浮动面板,每 1.2s fetch('/mcmp-api/state') 轮询
130
- └─ 进度条/步骤打点/日志/文件/中止按钮(拖拽仅绑定标题文字)
140
+ └─ 五阶段打点/子阶段/中控台模块/回滚计数/P0-P3 评级/强制锁定提示/日志/文件/中止重置按钮
131
141
  (面板 API 路由 /mcmp-api/{state,abort,reset} 由程序入口模块注册并转发)
132
142
  ```
133
143
 
@@ -139,10 +149,12 @@ pnpm dsh plugin --profile web remove dsh-mcmp
139
149
  | --- | --- |
140
150
  | `package.json` | 插件包清单:`dsh.bundle` 补丁声明、`dsh.client` 声明、`exports` 入口(`.` → Host,`./client` → 面板 bundle) |
141
151
  | `cordis.patch.yml` | **bundle 补丁**:安装时自动注册插件行(`insert: mcmp`),无需手动编辑配置 |
142
- | `lib/index.js` | **程序入口模块**:输入框内检测(斜杠命令注册、消息触发监听、systemPrompt 模型侧提示)、模型选择(父对话当前选择 / --model 覆盖 / 兜底)、题目检测(对话文本提取 / --from 本地文件)、识图能力探测、启动参数解析与校验、`/mcmp-api` 面板路由注册 |
143
- | `lib/pipeline.js` | **论文写作主循环模块**:8 步骤元数据与提示词构造(含质疑驱动)、子智能体调度、主循环编排(断点续跑、失败熔断、中止处理、兜底定稿)、运行状态与进度快照、中止/重置 |
152
+ | `架构.md` | **流程架构设计书 v3.17**:中控台双模块、五阶段、评级/回滚/教训/索引机制与约束 |
153
+ | `提示词.md` | **Prompt 设计 v3.4**:执行Agent/扫描验证模块/评审决策模块的全部提示词模板(主循环按此生成) |
154
+ | `lib/index.js` | **程序入口模块**:输入框内检测、模型选择、题目检测、识图能力探测、启动参数解析与校验、`/mcmp-api` 面板路由注册 |
155
+ | `lib/pipeline.js` | **论文写作主循环模块**:五阶段元数据与提示词构造、中控台扫描/评审调度、回滚与锁定、断点续跑、运行状态与进度快照、中止/重置 |
144
156
  | `lib/client.js` | **显示界面模块**:浮动进度面板(标准 `__ModuleLoader__` bundle,`fetch` 轮询、显示与交互) |
145
- | `tests/smoke.mjs` | **冒烟测试**:伪造 Cordis ctx 驱动插件,验证启动/触发/断点续跑(含多轮)/中止/兜底/`--from`/识图探测等路径,`node tests/smoke.mjs`(不随 npm 包发布) |
157
+ | `tests/smoke.mjs` | **冒烟测试**:伪造 Cordis ctx 驱动插件,验证启动/扫描评审路由/回滚与强制锁定/P3 定点修改/失败重试/断点续跑/中止/兜底/`--from`/识图探测/`--model` 等路径,`node tests/smoke.mjs`(不随 npm 包发布) |
146
158
 
147
159
  ## License
148
160
 
package/lib/client.js CHANGED
@@ -2,6 +2,9 @@
2
2
  * dsh-mcmp · 显示界面模块(Client 半,标准 __ModuleLoader__ 客户端 bundle)
3
3
  * 小浮窗的显示与交互:每 1.2s 通过 fetch('/mcmp-api/state') 轮询 Host 状态,
4
4
  * 中止/重置通过 POST /mcmp-api/abort|reset。拖拽仅绑定标题文字。
5
+ * 按《架构.md》v3 目标架构渲染:五阶段(阶段零~四)子阶段进度、中控台模块、
6
+ * 回滚计数与强制锁定、P0-P3 问题评级;主循环重写前,快照无 stages 字段时
7
+ * 自动回退到旧 S1-S8 步骤渲染(见 index.js 中的 v3 快照契约)。
5
8
  * (程序入口模块见 lib/index.js,论文写作主循环模块见 lib/pipeline.js)
6
9
  */
7
10
  window.__ModuleLoader__.load({
@@ -45,6 +48,8 @@ window.__ModuleLoader__.load({
45
48
  '.mcmp-actions { display: flex; gap: 8px; justify-content: flex-end; }',
46
49
  '.mcmp-actions .mcmp-btn { border: 1px solid var(--dsw-alias-border-l1); padding: 4px 12px; font-size: 12px; }',
47
50
  '.mcmp-abort { color: var(--dsw-alias-state-error-primary, #dc2626); border-color: var(--dsw-alias-state-error-primary, #dc2626); }',
51
+ '.mcmp-super { color: var(--dsw-alias-brand-primary, #2563eb); font-weight: 600; }',
52
+ '.mcmp-lock { color: var(--dsw-alias-state-error-primary, #dc2626); font-weight: 600; }',
48
53
  ].join('\n')
49
54
 
50
55
  const h = react.createElement
@@ -77,6 +82,8 @@ window.__ModuleLoader__.load({
77
82
  if (!snap || snap.status === 'idle' || dismissedRun === snap.runId) return null
78
83
  const st = snap.status
79
84
  const pct = snap.pct
85
+ // v3 架构(架构.md):快照含 stages(五阶段)时走新渲染;当前主循环(旧 S1-S8)缺失该字段,回退旧渲染
86
+ const isV3 = Array.isArray(snap.stages) && snap.stages.length > 0
80
87
 
81
88
  // 拖拽只绑定在标题文字上,避免指针捕获吞掉同栏按钮的点击
82
89
  const onTitleDown = (e) => {
@@ -107,27 +114,42 @@ window.__ModuleLoader__.load({
107
114
  const ss = Math.floor((elapsed % 60000) / 1000)
108
115
  const elapsedText = mm > 0 ? mm + '分' + (ss < 10 ? '0' : '') + ss + '秒' : ss + '秒'
109
116
 
110
- const stepRows = (snap.steps || []).map((step) => {
111
- let dots = ''
112
- for (let k = 0; k < step.iterTotal; k++) {
113
- dots += k < step.done ? '●' : '○'
114
- }
115
- const name = h('span', { className: 'mname' }, step.key + ' ' + step.name)
116
- const dotEl = h('span', { className: 'mcmp-dots ' + (step.done > 0 ? 'mcmp-done-dot' : '') }, dots)
117
- const cnt = h('span', { className: 'mcmp-label' }, step.done + '/' + step.iterTotal)
118
- return h('div', { key: step.key, className: 'mcmp-step' + (step.active ? ' active' : '') }, name, dotEl, cnt)
119
- })
117
+ const stepRows = isV3
118
+ ? (snap.stages || []).map((stage) => {
119
+ let dots = ''
120
+ for (let k = 0; k < stage.subTotal; k++) {
121
+ dots += k < stage.done ? '●' : '○'
122
+ }
123
+ const name = h('span', { className: 'mname' }, stage.key + ' ' + stage.name)
124
+ const dotEl = h('span', { className: 'mcmp-dots ' + (stage.done > 0 ? 'mcmp-done-dot' : '') }, dots)
125
+ const cnt = h('span', { className: 'mcmp-label' }, stage.done + '/' + stage.subTotal)
126
+ return h('div', { key: stage.key, className: 'mcmp-step' + (stage.active ? ' active' : '') }, name, dotEl, cnt)
127
+ })
128
+ : (snap.steps || []).map((step) => {
129
+ let dots = ''
130
+ for (let k = 0; k < step.iterTotal; k++) {
131
+ dots += k < step.done ? '●' : '○'
132
+ }
133
+ const name = h('span', { className: 'mname' }, step.key + ' ' + step.name)
134
+ const dotEl = h('span', { className: 'mcmp-dots ' + (step.done > 0 ? 'mcmp-done-dot' : '') }, dots)
135
+ const cnt = h('span', { className: 'mcmp-label' }, step.done + '/' + step.iterTotal)
136
+ return h('div', { key: step.key, className: 'mcmp-step' + (step.active ? ' active' : '') }, name, dotEl, cnt)
137
+ })
120
138
 
121
139
  const logLines = (snap.logs || []).map((l, i) => l.t + ' ' + l.m).join('\n')
122
140
  const fileRows = (snap.files || []).map((f, i) => h('div', { key: 'f' + i, className: 'mcmp-file' }, (f.type === 'dir' ? '📁 ' : '📄 ') + f.name))
123
141
 
124
- const curLine = snap.cur
125
- ? snap.cur.stepKey + ' ' + snap.cur.stepName + ' · 迭代 ' + (snap.cur.iterIdx + 1) + '/' + snap.cur.iterTotal + ' 「' + snap.cur.iterName + '」'
126
- : st === 'completed' ? '🎉 全部迭代已完成' : '等待中…'
142
+ const curLine = isV3
143
+ ? (snap.cur
144
+ ? snap.cur.stageKey + ' ' + snap.cur.stageName + ' · 子阶段 ' + (snap.cur.subIdx + 1) + '/' + snap.cur.subTotal + ' 「' + snap.cur.subName + '」'
145
+ : st === 'completed' ? '🎉 全部子阶段已完成' : '等待中…')
146
+ : (snap.cur
147
+ ? snap.cur.stepKey + ' ' + snap.cur.stepName + ' · 迭代 ' + (snap.cur.iterIdx + 1) + '/' + snap.cur.iterTotal + ' 「' + snap.cur.iterName + '」'
148
+ : st === 'completed' ? '🎉 全部迭代已完成' : '等待中…')
127
149
 
128
150
  const children = []
129
151
  children.push(h('div', { key: 'head', className: 'mcmp-head' },
130
- h('span', { className: 'mcmp-title', title: '按住拖动面板', onPointerDown: onTitleDown }, '数学建模论文流水线'),
152
+ h('span', { className: 'mcmp-title', title: '按住拖动面板', onPointerDown: onTitleDown }, '数学建模论文撰写系统'),
131
153
  h('span', { className: 'mcmp-chip mcmp-chip-' + (STATUS_CLASS[st] || '') }, STATUS_TEXT[st] || st),
132
154
  h('button', { key: 'min', className: 'mcmp-btn', title: minimized ? '展开面板' : '最小化面板', onClick: () => setMinimized(!minimized) }, minimized ? '□' : '—'),
133
155
  h('button', { key: 'close', className: 'mcmp-btn', title: '关闭面板', onClick: () => setDismissedRun(snap.runId) }, '×'),
@@ -142,10 +164,32 @@ window.__ModuleLoader__.load({
142
164
  h('div', { className: 'mcmp-fill', style: { width: pct + '%' } }),
143
165
  ))
144
166
  body.push(h('div', { key: 'meta', className: 'mcmp-row' },
145
- h('span', { className: 'mcmp-label' }, '第 ' + snap.round + '/' + snap.rounds + ' 轮 · ' + snap.done + '/' + snap.total + ' 次迭代 · ' + elapsedText),
167
+ h('span', { className: 'mcmp-label' }, isV3
168
+ ? '已完成 ' + snap.done + '/' + snap.total + ' 个子阶段 · ' + elapsedText
169
+ : '第 ' + snap.round + '/' + snap.rounds + ' 轮 · ' + snap.done + '/' + snap.total + ' 次迭代 · ' + elapsedText),
146
170
  h('span', { className: 'mcmp-label' }, '已完成'),
147
171
  ))
148
172
  body.push(h('div', { key: 'cur', className: 'mcmp-cur' }, curLine))
173
+ if (isV3 && snap.supervisor) {
174
+ const sup = snap.supervisor
175
+ if (sup.module) {
176
+ body.push(h('div', { key: 'super', className: 'mcmp-row' },
177
+ h('span', { className: 'mcmp-label' }, '中控台'),
178
+ h('span', { className: 'mcmp-super' }, sup.module),
179
+ ))
180
+ }
181
+ const rb = '回滚 ' + (Number.isSafeInteger(sup.rollbackCount) ? sup.rollbackCount : 0)
182
+ + '/' + (Number.isSafeInteger(sup.rollbackLimit) ? sup.rollbackLimit : 10) + ' 次'
183
+ const q = sup.issues || {}
184
+ const iss = 'P0 ' + (q.P0 || 0) + ' · P1 ' + (q.P1 || 0) + ' · P2 ' + (q.P2 || 0) + ' · P3 ' + (q.P3 || 0)
185
+ body.push(h('div', { key: 'rb', className: 'mcmp-row' },
186
+ h('span', { className: 'mcmp-label' }, rb),
187
+ h('span', { className: 'mcmp-label' }, iss),
188
+ ))
189
+ if (sup.forcedFinal) {
190
+ body.push(h('div', { key: 'lock', className: 'mcmp-lock' }, '🔒 回滚已达上限,流水线已强制锁定(请人工介入)'))
191
+ }
192
+ }
149
193
  if (snap.agentLabel && st === 'running') {
150
194
  body.push(h('div', { key: 'agent', className: 'mcmp-label' }, '子任务: ' + snap.agentLabel))
151
195
  }
@@ -183,7 +227,7 @@ window.__ModuleLoader__.load({
183
227
  document.head.appendChild(tag)
184
228
  }
185
229
  ctx.slots.inject('shell.overlay', () => ctx.slots.register(
186
- { name: 'shell.overlay', id: 'mcmp-pipeline-panel', order: 50, label: '数学建模流水线进度面板' },
230
+ { name: 'shell.overlay', id: 'mcmp-pipeline-panel', order: 50, label: '数学建模论文撰写系统进度面板' },
187
231
  () => h(Panel),
188
232
  ))
189
233
  }
package/lib/index.js CHANGED
@@ -1,5 +1,11 @@
1
1
  /**
2
- * dsh-mcmp · 数学建模论文自动化流水线 —— 程序入口模块(Host 侧)
2
+ * dsh-mcmp · 数学建模竞赛自动化论文撰写系统 —— 程序入口模块(Host 侧)
3
+ *
4
+ * 按《架构.md》v3 目标架构对齐:中控台(扫描验证模块 + 评审决策模块)+ 五阶段流水线
5
+ * (阶段零初始化 → 阶段一EDA → 阶段二建模 → 阶段三撰写 → 阶段四排版)。
6
+ * 论文写作主循环模块(lib/pipeline.js)将在后续版本重写为该架构;本模块与显示界面
7
+ * 模块先行适配——命令文案、启动提示、模型侧提示、/loopstatus 与面板快照契约均按
8
+ * v3 架构编写,同时保留对当前主循环(旧 S1-S8 快照)的兼容回退。
3
9
  *
4
10
  * 职责(入口相关):
5
11
  * - 服务装配(apply)与三个模块的接线;
@@ -19,6 +25,40 @@
19
25
  */
20
26
  import { createPipeline, PER_ROUND } from './pipeline.js'
21
27
 
28
+ // ---------------------------------------------------------------------------
29
+ // 未来主循环模块(v3,参照《架构.md》)的快照契约(snapshot 输出):
30
+ // 显示界面模块与本模块的 /loopstatus 按此渲染。当前主循环(旧 S1-S8)不提供
31
+ // stages/supervisor 字段,面板与状态命令自动回退到旧渲染;主循环重写为 v3 后,
32
+ // 移除旧渲染回退即可。
33
+ // {
34
+ // status, runId, title, wsDir, problemPath, startedAt, endedAt, // 通用字段(不变)
35
+ // stages: [ // 五阶段(阶段零~阶段四),每阶段含子阶段清单与完成计数
36
+ // { key: '阶段零', name: '初始化', subTotal: 4, done: 4, active: false,
37
+ // subs: ['创建目录', '加载数据', '初始化索引', '初始化教训文件'] },
38
+ // { key: '阶段一', name: 'EDA', subTotal: 3, done: 2, active: true,
39
+ // subs: ['清洗', '特征工程', 'EDA可视化'] },
40
+ // { key: '阶段二', name: '建模', subTotal: 5, done: 0, active: false,
41
+ // subs: ['模型筛选', '建立', '求解', '图表生成', '检验与质疑'] },
42
+ // { key: '阶段三', name: '撰写', subTotal: 7, done: 0, active: false,
43
+ // subs: ['重述', '假设与符号', '建模与求解章节', '结果分析', '摘要', '参考文献', '附录代码'] },
44
+ // { key: '阶段四', name: '排版', subTotal: 3, done: 0, active: false,
45
+ // subs: ['合并', '修正路径', '最终产出'] },
46
+ // ],
47
+ // cur: { stageKey, stageIdx, stageName, subIdx, subName, subTotal }, // 当前子阶段
48
+ // supervisor: { // 中控台状态
49
+ // module: '扫描验证模块' | '评审决策模块' | null, // 当前值班模块
50
+ // rollbackCount: 0, rollbackLimit: 10, forcedFinal: false, // 回滚与强制锁定(R-021)
51
+ // issues: { P0: 0, P1: 0, P2: 0, P3: 0 }, // 累计问题评级(3.4)
52
+ // },
53
+ // total: 22, done: 7, pct: 31, // 子阶段总数进度(4+3+5+7+3=22)
54
+ // phase, agentLabel, logs, files, error, vision, visionLive, // 原有字段(不变)
55
+ // }
56
+ // 架构核心文件(FILE_INDEX.yaml / ROLLBACK_LESSONS.yaml / transactions.log /
57
+ // Final_Paper.md / stage_XX_outputs/ / deprecated/ / code/)由主循环写入工作区,
58
+ // 面板经 refreshFiles 列出的 files 字段展示,无需额外契约字段。
59
+ // ---------------------------------------------------------------------------
60
+
61
+
22
62
  export const name = 'mcmp'
23
63
  // 硬依赖:这些服务挂载后 Cordis 才会激活本插件(避免过早激活导致 ctx.get 全部为空)
24
64
  export const inject = ['commands', 'subagents', 'agents', 'webServer']
@@ -33,7 +73,10 @@ export function apply(ctx) {
33
73
  console.log('dsh-mcmp: services available -> commands=' + !!commands + ' fs=' + !!fs + ' agents=' + !!agents + ' subagents=' + !!subagents + ' systemPrompt=' + !!systemPrompt + ' webServer=' + !!webServer)
34
74
 
35
75
  // ---------- 论文写作主循环模块(主循环流程、运行状态、中止/重置、进度快照) ----------
36
- const pipeline = createPipeline({ fs, subagents, agents })
76
+ // mcmpRetryBackoffMs:可选服务钩子(仅测试/特殊部署用),覆盖执行失败重试的指数退避
77
+ let retryBackoffMs
78
+ try { retryBackoffMs = ctx.get('mcmpRetryBackoffMs') } catch (err) { /* 未提供则用默认 5s/10s/20s */ }
79
+ const pipeline = createPipeline({ fs, subagents, agents, retryBackoffMs })
37
80
 
38
81
  // 子任务模型路由解析:
39
82
  // 1) 显式 --model 覆盖(优先级最高)
@@ -94,7 +137,8 @@ export function apply(ctx) {
94
137
  function extractProblem(session) {
95
138
  if (!session || !Array.isArray(session.events)) return ''
96
139
  const parts = []
97
- const recent = session.events.slice(-80)
140
+ // v3 流水线每遍会产生 100+ 条工作流事件,窗口需足够大以覆盖赛题消息
141
+ const recent = session.events.slice(-600)
98
142
  for (const ev of recent) {
99
143
  if (ev.type !== 'user/message') continue
100
144
  const text = messageText(ev.data)
@@ -123,7 +167,7 @@ export function apply(ctx) {
123
167
  let rounds = 1
124
168
  if (mRound) rounds = parseInt(mRound[1], 10)
125
169
  if (!Number.isSafeInteger(rounds) || rounds < 1) rounds = 1
126
- if (rounds > 10) return { kind: 'error', text: '--round 最大为 10。每轮 19 次迭代、每次迭代启动一个专家子智能体,轮数过大会非常耗时。' }
170
+ if (rounds > 10) return { kind: 'error', text: '--round 最大为 10。每遍 22 个子阶段、每个子阶段由专家子智能体执行并经过中控台双重验证,遍数过大会非常耗时。' }
127
171
  const fresh = /(?:^|\s)--fresh\b/i.test(raw)
128
172
  // 子任务模型:默认强制跟随父对话当前选择的模型(右下角模型选择器);
129
173
  // 可选 --model 提供商/模型 显式覆盖;无法读取时兜底 DeepSeek V4 Flash。
@@ -171,14 +215,15 @@ export function apply(ctx) {
171
215
  // 断点续跑:扫描本会话落盘的 v2 工作流记录,跳过已完成的迭代
172
216
  const resumeCount = fresh ? 0 : pipeline.completedIterations(session)
173
217
  if (resumeCount >= rounds * PER_ROUND) {
174
- return { kind: 'error', text: '检测到本会话已完成 ' + resumeCount + ' 次迭代(≥ 本次请求的 ' + (rounds * PER_ROUND) + ' ),无需重复。\n- 如需继续优化,请增大轮数,例如 /loopbegin --round=' + Math.min(rounds + 1, 10) + '\n- 如需从头重跑,请使用 /loopbegin --fresh' }
218
+ return { kind: 'error', text: '检测到本会话已完成 ' + resumeCount + ' 个子阶段(≥ 本次请求的 ' + (rounds * PER_ROUND) + ' ),无需重复。\n- 如需继续优化,请增大遍数,例如 /loopbegin --round=' + Math.min(rounds + 1, 10) + '\n- 如需从头重跑,请使用 /loopbegin --fresh' }
175
219
  }
176
220
  pipeline.start({ session, agent, args, resumeCount, explicitModel: !!explicitAgentOptions })
177
221
  return {
178
222
  kind: 'success',
179
- text: '数学建模论文自动化流水线(v2)已启动:' + rounds + ' 轮 × 19 次迭代 = ' + (rounds * PER_ROUND) + ' 个子任务。\n输出目录: ' + wsDir
180
- + (resumeCount > 0 ? '\n断点续跑:已跳过此前完成的 ' + resumeCount + ' 次迭代,从第 ' + (resumeCount + 1) + ' 次继续。' : '\n全新运行(若输出目录有旧成果,第一步会自动归档为 数学建模流水线_历史归档_*)。')
181
- + '\n新流程:赛题分析 模型建立与求解 编程实现 图表与流程图 → 图表视觉自检与修复(有识图插件自动调用,无则脚本分析)→ 论文撰写 → 评审与修复落实(问题必须真正修复) 论文定稿。\n无论成败,最终都会生成完整论文 数学建模流水线/论文定稿.md。\n进度请在右下角浮动面板实时查看(含百分比),聊天区也会出现流水线运行卡片。\n提示:中断或关闭聊天窗口都不会丢进度,再次发送 /loopbegin 即从断点续跑;如要重头开始,点面板「重置(全新开始)」、运行 /loopreset 或加 --fresh。',
223
+ text: '数学建模竞赛自动化论文撰写系统(v3)已启动。\n输出目录: ' + wsDir
224
+ + (resumeCount > 0 ? '\n断点续跑:已跳过此前完成的 ' + resumeCount + ' 个子阶段,从第 ' + (resumeCount + 1) + ' 个继续。' : '\n全新运行(若输出目录有旧成果,流水线会先按架构规则归档)。')
225
+ + '\n流程:阶段零(初始化)阶段一(EDA)阶段二(建模)阶段三(撰写)→ 阶段四(排版)。每个子阶段完成后:执行智能体按统一质疑标准自检,再由中控台双重质疑(扫描验证模块 + 评审决策模块);问题按 P0-P3 评级——P0/P1/P2 触发阶段级回滚(根源阶段及之后全部产出移入 deprecated/,写入教训文件 ROLLBACK_LESSONS.yaml,同一阶段回滚≥10 次强制锁定并通知人工),P3 由中控台精确定点修改;全部产出登记到索引 FILE_INDEX.yaml。'
226
+ + '\n无论成败,最终都会生成完整论文 Final_Paper.md。\n进度请在右下角浮动面板实时查看(含阶段、中控台、回滚与评级),聊天区也会出现流水线运行卡片。\n提示:中断或关闭聊天窗口都不会丢进度,再次发送 /loopbegin 即从断点续跑;如要重头开始,点面板「重置(全新开始)」、运行 /loopreset 或加 --fresh。',
182
227
  }
183
228
  } catch (err) {
184
229
  return { kind: 'error', text: '启动失败: ' + String((err && err.message) || err) }
@@ -190,8 +235,8 @@ export function apply(ctx) {
190
235
  try {
191
236
  commands.register({
192
237
  name: 'loopbegin',
193
- description: '启动数学建模论文自动化流水线 v2(8 步骤:含图表视觉自检、评审修复闭环、论文定稿;每轮 19 次迭代、多轮外循环,成果全部落盘)',
194
- input: { hint: '--round=N 外循环轮数(默认 1);--model 提供商/模型 强制子任务模型(如 --model glm-vision/glm-4.7-Flash);可选 --from 题目文件 指定赛题文件;--fresh 从头重跑' },
238
+ description: '启动数学建模竞赛自动化论文撰写系统(中控台双重质疑 + 五阶段流水线:阶段零初始化/阶段一EDA/阶段二建模/阶段三撰写/阶段四排版;P0-P3 评级、阶段级回滚与教训持久化,成果全部落盘)',
239
+ input: { hint: '可选 --from 题目文件 指定赛题文件;--model 提供商/模型 强制子任务模型(如 --model glm-vision/glm-4.7-Flash);--round=N 外循环轮数(默认 1);--fresh 从头重跑' },
195
240
  handler: (invocation) => startPipeline(invocation.agent, invocation.rawInput),
196
241
  })
197
242
  } catch (err) { console.warn('dsh-mcmp: loopbegin 注册失败(可能被其他实例占用): ' + String((err && err.message) || err)) }
@@ -202,7 +247,7 @@ export function apply(ctx) {
202
247
  handler: () => {
203
248
  const r = pipeline.abort('用户通过 /loopabort 中止')
204
249
  if (!r.ok) return { kind: 'error', text: '当前没有运行中的流水线。' }
205
- return { kind: 'success', text: '已发送中止请求,流水线将在当前子任务结束后停止(已产出的成果全部保留,随后会自动兜底生成 论文定稿.md)。\n- 想从断点继续:直接再次发送 /loopbegin;\n- 想从头重新开始:先运行 /loopreset(或点面板「重置(全新开始)」),再发送 /loopbegin;也可直接 /loopbegin --fresh。' }
250
+ return { kind: 'success', text: '已发送中止请求,流水线将在当前子任务结束后停止(已产出的成果全部保留,随后会自动兜底生成 Final_Paper.md)。\n- 想从断点继续:直接再次发送 /loopbegin;\n- 想从头重新开始:先运行 /loopreset(或点面板「重置(全新开始)」),再发送 /loopbegin;也可直接 /loopbegin --fresh。' }
206
251
  },
207
252
  })
208
253
  } catch (err) { console.warn('dsh-mcmp: loopabort 注册失败: ' + String((err && err.message) || err)) }
@@ -213,7 +258,7 @@ export function apply(ctx) {
213
258
  handler: () => {
214
259
  const r = pipeline.reset()
215
260
  if (!r.ok) return { kind: 'error', text: r.reason }
216
- return { kind: 'success', text: '已清空流水线状态与断点续跑记录。下次发送 /loopbegin 将从第 1 个迭代全新开始(工作区旧成果不删除,首步会自动归档为 数学建模流水线_历史归档_*)。' }
261
+ return { kind: 'success', text: '已清空流水线状态与断点续跑记录。下次发送 /loopbegin 将从头全新开始(工作区旧成果保留,由流水线按架构规则归档处置)。' }
217
262
  },
218
263
  })
219
264
  } catch (err) { console.warn('dsh-mcmp: loopreset 注册失败: ' + String((err && err.message) || err)) }
@@ -224,9 +269,24 @@ export function apply(ctx) {
224
269
  handler: () => {
225
270
  const s = pipeline.snapshot()
226
271
  if (s.status === 'idle') return { kind: 'success', text: '流水线空闲。粘贴赛题后发送以 /loopbegin 开头的消息(可带 --round=N)即可启动。' }
272
+ // v3 架构快照(stages/supervisor 字段)优先;当前主循环(旧 S1-S8)缺失时回退旧渲染
273
+ const isV3 = Array.isArray(s.stages) && s.stages.length > 0
227
274
  let text = '状态: ' + ({ running: '运行中', completed: '已完成', error: '出错', cancelled: '已中止' }[s.status] || s.status)
228
- text += '\n进度: 第 ' + s.round + '/' + s.rounds + ' 轮,已完成 ' + s.done + '/' + s.total + ' 次迭代(' + s.pct + '%)'
229
- if (s.cur) text += '\n当前: ' + s.cur.stepKey + ' ' + s.cur.stepName + ' · 迭代 ' + (s.cur.iterIdx + 1) + '/' + s.cur.iterTotal + ' ' + s.cur.iterName
275
+ if (isV3) {
276
+ if (s.cur) text += '\n当前: ' + s.cur.stageKey + ' ' + s.cur.stageName + ' · 子阶段 ' + (s.cur.subIdx + 1) + '/' + s.cur.subTotal + ' ' + s.cur.subName
277
+ text += '\n进度: 已完成 ' + s.done + '/' + s.total + ' 个子阶段(' + s.pct + '%)'
278
+ if (s.supervisor && s.supervisor.module) text += '\n中控台: ' + s.supervisor.module
279
+ if (s.supervisor && Number.isSafeInteger(s.supervisor.rollbackCount)) {
280
+ text += '\n回滚: ' + s.supervisor.rollbackCount + '/' + (Number.isSafeInteger(s.supervisor.rollbackLimit) ? s.supervisor.rollbackLimit : 10) + ' 次' + (s.supervisor.forcedFinal ? '(已强制锁定,请人工介入)' : '')
281
+ }
282
+ if (s.supervisor && s.supervisor.issues) {
283
+ const q = s.supervisor.issues
284
+ text += '\n问题: P0 ' + (q.P0 || 0) + ' · P1 ' + (q.P1 || 0) + ' · P2 ' + (q.P2 || 0) + ' · P3 ' + (q.P3 || 0)
285
+ }
286
+ } else {
287
+ text += '\n进度: 第 ' + s.round + '/' + s.rounds + ' 轮,已完成 ' + s.done + '/' + s.total + ' 次迭代(' + s.pct + '%)'
288
+ if (s.cur) text += '\n当前: ' + s.cur.stepKey + ' ' + s.cur.stepName + ' · 迭代 ' + (s.cur.iterIdx + 1) + '/' + s.cur.iterTotal + ' ' + s.cur.iterName
289
+ }
230
290
  if (s.agentLabel) text += '\n子任务: ' + s.agentLabel
231
291
  text += '\n识图能力: ' + (s.visionLive === 'vision' ? '识图工具(视觉自检)' : s.visionLive === 'script' ? '脚本分析(无识图工具)' : s.vision ? '宿主侧已探测到' : '未探测到(由子智能体自检决定)')
232
292
  if (s.error) text += '\n错误: ' + s.error
@@ -260,7 +320,7 @@ export function apply(ctx) {
260
320
  systemPrompt.section({
261
321
  name: 'mcmp-pipeline',
262
322
  order: 130,
263
- text: '数学建模流水线说明:当用户消息以 /loopbegin 开头(可带 --round=N、--from 文件或 --fresh 参数)时,插件已自动在后台启动「数学建模论文自动化流水线」(8 步骤、每轮 19 次迭代,由工作流子智能体执行:赛题分析→模型建立与求解→编程实现→图表与流程图→图表视觉自检与修复→论文撰写→评审与修复落实→论文定稿)。此时你只需用一两句话确认已启动,并提示用户查看右下角进度面板与聊天区的工作流运行卡片;绝对不要自己去编写或执行该流水线的任何步骤,不要重复启动。流水线无论成败都会在 数学建模流水线/论文定稿.md 生成一版完整论文。若用户消息包含赛题但未以 /loopbegin 开头,说明尚未启动流水线,不要擅自运行。辅助命令 /loopstatus、/loopabort、/loopreset(清空续跑记录,下次从头开始)由系统处理,你无需执行。',
323
+ text: '数学建模流水线说明:当用户消息以 /loopbegin 开头(可带 --round=N、--from 文件或 --fresh 参数)时,插件已自动在后台启动「数学建模竞赛自动化论文撰写系统」(中控台 + 五阶段流水线:阶段零初始化→阶段一EDA→阶段二建模→阶段三撰写→阶段四排版,由工作流子智能体执行;每个子阶段完成后先由执行智能体按统一质疑标准自检,再由中控台扫描验证模块与评审决策模块双重质疑,问题按 P0-P3 评级:P0/P1/P2 触发阶段级回滚并写入教训文件 ROLLBACK_LESSONS.yaml,同一阶段回滚≥10 次强制锁定;P3 由中控台精确定点修改;全部产出登记到索引 FILE_INDEX.yaml)。此时你只需用一两句话确认已启动,并提示用户查看右下角进度面板与聊天区的工作流运行卡片;绝对不要自己去编写或执行该流水线的任何步骤,不要重复启动。系统无论成败都会产出完整论文 Final_Paper.md。若用户消息包含赛题但未以 /loopbegin 开头,说明尚未启动流水线,不要擅自运行。辅助命令 /loopstatus、/loopabort、/loopreset(清空续跑记录,下次从头开始)由系统处理,你无需执行。',
264
324
  })
265
325
  } catch (err) { console.warn('dsh-mcmp: systemPrompt 注册失败: ' + String((err && err.message) || err)) }
266
326
  }