Skip to content

v2.2.0 — 接管已有的研究文件夹

Choose a tag to compare

@github-actions github-actions released this 02 Sep 07:04
· 27 commits to main since this release

一个已经堆了半年材料的文件夹怎么进 MAGI。magi migrate 管的是 Wikify 建过的
项目;这一版管的是从来没进过 MAGI、有文献有草稿有代码有数据、摆法不一定合我们
想象的那种目录。

magi init 本来就能在非空目录里跑(纯增量,已存在的文件一律跳过)。缺的是两件
事:判断目录里那堆东西是什么,以及搬动之后文件之间互指的路径还指得准
前者是判断,留给 skill;后者是路径算术,写成命令。

magi adopt

magi adopt survey .                    # 只读盘点
magi adopt apply plan.json --dry-run   # 看会搬什么、改哪些引用
magi adopt apply plan.json
magi adopt undo                        # 字和文件一起放回去

survey 除了列目录,把所有 markdown 里写着的 arXiv id 和 DOI 一并抓出来——一张
参考文献表往往就是这个项目已有的半数文献,抓出来是正则的事,判断每一篇值不值得
读才是要人读的事。整个目录只有一个子目录时自动往下钻一层并说明;否则一个
research/ 包着全部材料的仓库,盘点出来只有「112 个文件」一行,等于没说。

计划是一个 JSON,由 agent 写、人过目。apply 从不删除、从不覆盖、从不把东西搬
出项目目录、从不动 MAGI 自己的脚手架;计划里只要有一条不合法,一条都不执行——
搬了一半的文件夹比没搬的更难收拾。被搬空的目录它说出来,但不删。

不在链接会断的地方报错,而是改

研究文件夹是靠相对路径连起来的。按整目录搬恰好能保住它们,但一个乱到值得 adopt
的文件夹本来就不可能只靠整目录搬成 MAGI 的形状:迟早有一个文件要去它邻居不去的
地方。在那里报错等于把问题原样退回给人。

证明一条链接要断的那套算术,同时也算得出它该指向哪。 所以同一趟里改完,
包括写在反引号里的路径——没有任何东西渲染它们,也就没有任何别的东西会发现它们
失效了。每条改写记在导致它的那次搬动旁边,undo 因此能把字和文件一起放回去。

对着两个真实课题仓库做的

Algebra_Energy_Barrier:材料全压在 research/ 一层之下,112 个文件,109 个
arXiv id + 8 个 DOI。三棵子树整体搬进 drafts/,0 处需要改写,27 条链接全部解析。

KW Duality:扁平,18 个 md,37 个 arXiv id 一条命令全部入队。六次搬动(含三个
重命名),26 处引用被改对,26 处全是散文路径,markdown 链接 0 条——这个仓库
被任何不管散文路径的搬动处理,都会静默散架,而且没有任何东西会报错。改对的里面
包括自己没搬、但指的东西搬了的 log.mdREADME.md

两个仓库撤销后都与原件逐字节相同。

实测改出来的缺陷

全是跑真仓库才出来的,fixture 上一条都不会出现:

  • 一份叫 log.md 的工作日志被报成 magi 自己的家具(名字撞了而已,init 之前那
    个目录里没有一样东西是 magi 的)
  • 材料全在一层包装之下的仓库,盘点成一行「112 个文件」
  • 改一条链接却把整个文件的行尾从 LF 换成 CRLF——人回头 diff 自己的仓库,会看
    到整份文件都变了,也就看不出到底哪里变了
  • #anchor 被从匹配键上剪掉,于是带锚点的链接一条都改不动

也修了

magi next 对当天新建的命题说 open since 0001-01-01 回退值取的是纪元
下限,而一条还没有任何帖子的命题每次都落到那里——一个刚接管的项目对人说的第一句
话带着公元 1 年的日期。_oldest_open 的排序用的是同一个下限:两条都没帖子的命题
在那里并列,next 点名哪一条成了文件系统的列举顺序。

修这条时引入又修掉一个:YAML 把不带引号的 created: 2026-09-02 解析成 date
对象(我们的写入器加引号,人手改过的文件不加),交给给帖子时间戳用的 parse_at
.strip() 一个 date,整个面板挂掉。强度不放进 parse_at——为一个调用点放宽
它等于让所有调用点开始接受不知道什么东西。

两份指南都写着 magi migrate 没有 --dry-run,而 migrate.py 里就定义着
它,--help 那句话还建议先跑一遍。

一条不会咬的守卫

「一条没有帖子的命题被记成公元 1 年」那条变异用例,锚点指的是修 date 崩溃时被
重构掉的那一行。运行器报 ANCHOR? 而不是 caught——变异根本没被应用过
一条装不上的用例和一条咬得住的用例,在绿色的报告里长得一模一样。补丁脚本现在
写入前断言锚点在源码里恰好出现一次。

质量

2726 个测试通过 / 1 跳过。变异用例 adopt 9 条、state 3 条,全部会咬。三宿主冒烟
于 2026-09-02 通过:复核者驳回了一个故意过宽的命题,并逐行点名了命题本身、它
过度外推的那次单点测量、以及做出这一跳的推导,20.2 秒。

pipx upgrade --install magi-research

Browser buttonmagi-browser-extension-v1.2.2.zip below.
Unzip it, open chrome://extensions, turn on Developer Mode, and use Load unpacked on the unzipped folder. It sends the page you are reading to a local MAGI queue and nothing else; nothing enters a library until you approve the batch.