@calcit/procs 0.12.53 → 0.12.55
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/.yarn/install-state.gz +0 -0
- package/README.md +12 -12
- package/RFCs/04-13-type-slot-mechanism-rfc.md +519 -115
- package/RFCs/04-16-wasm-data-structures.md +1 -1
- package/RFCs/07-26-agent-docs-and-evaluation-rfc.md +33 -0
- package/RFCs/07-26-agent-machine-protocol-rfc.md +102 -0
- package/RFCs/07-26-safe-structured-editing-rfc.md +66 -0
- package/RFCs/07-26-static-semantic-analysis-rfc.md +105 -0
- package/RFCs/07-28-git-module-store-rfc.md +59 -0
- package/RFCs/07-28-persistent-tree-cursor-rfc.md +287 -0
- package/RFCs/README.md +9 -3
- package/build.rs +89 -7
- package/editing-history/2026-07-28-1346-edit-transaction.md +27 -0
- package/editing-history/2026-07-28-1454-persistent-tree-cursor.md +30 -0
- package/editing-history/2026-07-28-1651-cursor-focus-stack-clipboard.md +30 -0
- package/editing-history/2026-07-28-1719-cursor-navigation-search-selection.md +21 -0
- package/editing-history/2026-07-28-1958-agent-rfc-split.md +14 -0
- package/editing-history/2026-07-28-2004-cursor-editing-docs.md +14 -0
- package/editing-history/2026-07-28-2132-cursor-recoverable-clipboard.md +18 -0
- package/editing-history/2026-07-28-2151-cursor-native-structural-editing.md +20 -0
- package/editing-history/2026-07-28-2158-document-cursor-native-workflows.md +13 -0
- package/editing-history/2026-07-29-0022-add-cursor-cli-options.md +7 -0
- package/editing-history/2026-07-29-0022-audit-cursor-development-scenarios.md +6 -0
- package/editing-history/2026-07-29-0022-complete-cursor-structural-edits.md +8 -0
- package/editing-history/2026-07-29-0022-document-cursor-edit-recipes.md +8 -0
- package/editing-history/2026-07-29-0022-echo-cursor-commands.md +6 -0
- package/editing-history/2026-07-29-0022-edit-target-cursor-alias.md +6 -0
- package/editing-history/2026-07-29-0022-guide-agents-through-cursor-workflows.md +7 -0
- package/editing-history/2026-07-29-0022-query-from-active-cursor.md +8 -0
- package/editing-history/2026-07-29-0022-tree-target-cursor-alias.md +5 -0
- package/editing-history/2026-07-29-1242-agent-guide-cold-start-validation.md +15 -0
- package/editing-history/2026-07-29-1242-cirru-quote-input-errors.md +13 -0
- package/editing-history/2026-07-29-1242-internal-wasm-doc-boundary.md +13 -0
- package/editing-history/2026-07-30-1130-pr-281-review-fixes.md +5 -0
- package/editing-history/20260729-1421-consolidate-local-state-and-cursor-tools.md +22 -0
- package/editing-history/20260729-1422-document-calcit-local-state.md +15 -0
- package/editing-history/20260729-1952-strengthen-polymorphism-diagnostics.md +21 -0
- package/editing-history/202607301429-entry-type-slots.md +29 -0
- package/editing-history/202607301435-release-0.12.54.md +22 -0
- package/editing-history/202607301620-program-diff-type-slots.md +6 -0
- package/editing-history/202607301959-unify-snapshot-entries.md +7 -0
- package/editing-history/202607310027-entry-description.md +7 -0
- package/editing-history/202607310032-initialize-entry-descriptions.md +6 -0
- package/editing-history/202607310041-entry-functions-as-symbols.md +7 -0
- package/editing-history/202607310052-release-0.12.55.md +5 -0
- package/lib/package.json +1 -1
- package/package.json +1 -1
- package/RFCs/07-26-agent-semantic-interface-roadmap-rfc.md +0 -793
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# RFC: 可持续迁移的树形 Cursor
|
|
2
|
+
|
|
3
|
+
状态:Draft
|
|
4
|
+
日期:2026-07-28
|
|
5
|
+
关联:`07-06-semantic-tree-navigation-rfc.md`、`07-26-safe-structured-editing-rfc.md`、`03-18-query-def-tree-show-chunked-display-plan.md`
|
|
6
|
+
|
|
7
|
+
## 1. 目标
|
|
8
|
+
|
|
9
|
+
Calcit 源码以 EDN tree 保存,数字 path 只是某个 snapshot revision 下的瞬时坐标。复杂表达式需要连续执行 show、insert、wrap、replace、delete 等操作时,Agent 即使第一次选对节点,也可能因为前方兄弟节点增删而继续使用已经漂移的 path。
|
|
10
|
+
|
|
11
|
+
引入项目本地 `.calcit/cursor.cirru` 与 `cr cursor`,保存当前选择的 namespace、definition 和 tree path。Cursor 不是新的源码身份,也不写进 snapshot;它是 CLI 在多次调用之间维护的结构化选择状态。`.calcit/` 同时作为 error、snippets 与后续模块链接等小型项目本地工件的统一目录,避免继续增加顶层隐藏文件。
|
|
12
|
+
|
|
13
|
+
核心要求:一旦 cursor 已存在,任何作用于同一 definition 的 tree mutation 都必须尝试迁移 cursor。能够确定新位置时更新坐标并提示;不能确定时明确标为 stale 或移动到可证明安全的父节点,不允许静默指向另一个节点。
|
|
14
|
+
|
|
15
|
+
## 2. 文件格式
|
|
16
|
+
|
|
17
|
+
当前只有一个 active cursor;named marks 只是有限位置书签,不是并发 cursor。schema v2 在 v1 的 selection 上增加历史、显式栈和结构化 clipboard;schema v3 移除每个位置中重复保存的完整 subtree preview;schema v4 增加单一 region anchor、最多 16 个 marks 和不保存结果集的 last query。读取器接受 v1-v3,旧 `.calcit-cursor.cirru` 在首次读取时一次性移动到新目录:
|
|
18
|
+
|
|
19
|
+
```cirru
|
|
20
|
+
{}
|
|
21
|
+
:schema-version 4
|
|
22
|
+
:active :main
|
|
23
|
+
:cursors $ {}
|
|
24
|
+
:main $ {}
|
|
25
|
+
:snapshot |calcit.cirru
|
|
26
|
+
:target |app.main/render!
|
|
27
|
+
:section :code
|
|
28
|
+
:path $ [] 3 2 1
|
|
29
|
+
:definition-revision |md5:...
|
|
30
|
+
:fingerprint |md5:...
|
|
31
|
+
:history $ []
|
|
32
|
+
{}
|
|
33
|
+
:snapshot |calcit.cirru
|
|
34
|
+
:target |app.main/render!
|
|
35
|
+
:section :code
|
|
36
|
+
:path $ [] 3 2
|
|
37
|
+
:definition-revision |md5:...
|
|
38
|
+
:fingerprint |md5:...
|
|
39
|
+
:stack $ []
|
|
40
|
+
:anchor $ {}
|
|
41
|
+
:snapshot |calcit.cirru
|
|
42
|
+
:target |app.main/render!
|
|
43
|
+
:section :code
|
|
44
|
+
:path $ [] 3 2 0
|
|
45
|
+
:definition-revision |md5:...
|
|
46
|
+
:fingerprint |md5:...
|
|
47
|
+
:marks $ {}
|
|
48
|
+
:render-start $ {}
|
|
49
|
+
:snapshot |calcit.cirru
|
|
50
|
+
:target |app.main/render!
|
|
51
|
+
:section :code
|
|
52
|
+
:path $ [] 3 2
|
|
53
|
+
:definition-revision |md5:...
|
|
54
|
+
:fingerprint |md5:...
|
|
55
|
+
:last-query $ {}
|
|
56
|
+
:command |search
|
|
57
|
+
:pattern |render-item
|
|
58
|
+
:filter |app.main/render!
|
|
59
|
+
:exact true
|
|
60
|
+
:regex false
|
|
61
|
+
:max-depth 0
|
|
62
|
+
:start-path nil
|
|
63
|
+
:entry nil
|
|
64
|
+
:pattern-is-json false
|
|
65
|
+
:selected-index 2
|
|
66
|
+
:snapshot-revision |md5:...
|
|
67
|
+
:clipboard $ {}
|
|
68
|
+
:mode |cut
|
|
69
|
+
:source-target |app.main/render!
|
|
70
|
+
:source-path $ [] 3 2 1
|
|
71
|
+
:fingerprint |md5:...
|
|
72
|
+
:tree $ quote
|
|
73
|
+
map items $ fn (item)
|
|
74
|
+
render-item item
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- `:path` 是快速坐标,不是跨 revision 的身份;
|
|
78
|
+
- `:fingerprint` 校验 path 处仍是预期 subtree;
|
|
79
|
+
- `:definition-revision` 用于发现外部修改;
|
|
80
|
+
- `:section` 第一版只接受 `:code`,为 schema、example 与结构化 docs 预留空间。
|
|
81
|
+
- `:history` 由 `set` 和导航命令维护,最多保存 32 个位置,供 `back` 使用;
|
|
82
|
+
- `:stack` 只由 `push` / `pop` 控制,最多保存 16 个位置,不与普通导航历史混用;
|
|
83
|
+
- `:anchor` 与 active cursor 必须是同一 parent 下的 sibling 才形成 region;不保存复制的 subtree;
|
|
84
|
+
- `:marks` 最多 16 个,每个只保存位置、revision 和 fingerprint;
|
|
85
|
+
- `:last-query` 只保存查询参数、当前 index 和 revision,`query next/prev` 每次重新解析并计算结果,不持久化结果列表;
|
|
86
|
+
- `:clipboard` 保存真实 Cirru subtree,不保存经过 formatter 的文本;`copy` 和 `cut` 都可写入,`paste` 后仍保留以支持重复粘贴。
|
|
87
|
+
|
|
88
|
+
cursor 文件位于 snapshot 同目录的 `.calcit/`,使用目标文件所在目录的临时文件加 rename 更新。`.calcit/` 应作为本地状态加入 `.gitignore`,不参与模块发布或项目语义。首次 `cursor set` 若未检测到相应 ignore 规则,CLI 在 stderr 给出提示但不自动修改项目文件。文件硬上限为 64 KiB;history、stack、marks 都有固定条目上限,只有 clipboard 允许保存源码 subtree,超过上限时先拒绝写入而不截断数据。
|
|
89
|
+
|
|
90
|
+
## 3. CLI 契约
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
cr cursor set app.main/render! --path @3.2.1
|
|
94
|
+
cr cursor show
|
|
95
|
+
cr cursor parent
|
|
96
|
+
cr cursor child # first child
|
|
97
|
+
cr cursor child 2
|
|
98
|
+
cr cursor child --last # last child
|
|
99
|
+
cr cursor next --count 3
|
|
100
|
+
cr cursor prev --count 2
|
|
101
|
+
cr cursor forward --count 8
|
|
102
|
+
cr cursor backward --count 5
|
|
103
|
+
cr cursor back --count 4
|
|
104
|
+
cr cursor push
|
|
105
|
+
cr cursor pop
|
|
106
|
+
cr cursor anchor
|
|
107
|
+
cr cursor region
|
|
108
|
+
cr cursor clear-anchor
|
|
109
|
+
cr cursor mark render-start
|
|
110
|
+
cr cursor goto render-start
|
|
111
|
+
cr cursor marks
|
|
112
|
+
cr cursor rm-mark render-start
|
|
113
|
+
cr cursor apply swap-next
|
|
114
|
+
cr cursor apply wrap --code 'quote $ when visible? self'
|
|
115
|
+
cr cursor slurp-next
|
|
116
|
+
cr cursor slurp-prev
|
|
117
|
+
cr cursor barf-last
|
|
118
|
+
cr cursor barf-first
|
|
119
|
+
cr cursor duplicate --at after
|
|
120
|
+
cr cursor copy
|
|
121
|
+
cr cursor cut
|
|
122
|
+
cr cursor paste --at after
|
|
123
|
+
cr cursor clipboard
|
|
124
|
+
cr cursor clear-clipboard
|
|
125
|
+
cr cursor clear
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
definition-oriented query/tree/edit 命令的 target 与 tree path 都可用 `@cursor` 引用 active cursor:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
cr query context @cursor --format json
|
|
132
|
+
cr query type-at @cursor --path @cursor --format json
|
|
133
|
+
cr tree show @cursor --path @cursor
|
|
134
|
+
cr tree replace @cursor --path @cursor --code 'quote $ render-list items'
|
|
135
|
+
cr tree wrap @cursor --path @cursor --code 'quote $ when visible? self'
|
|
136
|
+
cr edit split-def @cursor --path @cursor --name render-items
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
对连续编辑中最常用的操作,`cursor apply <operation>` 进一步省略重复的 target 和 path,但内部仍构造并调用既有 tree 命令,不另外实现 mutation 语义。支持 `delete`、`swap-next`、`swap-prev`、`unwrap`、`raise`、`replace`、`wrap`、`insert-before`、`insert-after`、`insert-child` 与 `append-child`。其中 `unwrap` 的语义是把选中 list 的所有 child 展开到 parent,不承诺与包含额外语法节点的 wrap 模板严格互逆。
|
|
140
|
+
|
|
141
|
+
`cursor slurp-next/slurp-prev` 与 `cursor barf-last/barf-first` 构成双向 Paredit 风格复合命令:slurp 把相邻 sibling 移入选中 list 对应一端,barf 把首/末 child 移到 list 外对应一侧。能够安全表达为通用 node move 的操作复用 `edit mv`;跨 parent 删除会使 destination 暂时失效的 `barf-first` 使用一次内存树变换。`cursor duplicate --at before|after` 直接复制当前表达式并选中新副本,不污染 clipboard。复合 Snapshot/sidecar 改动都先 stage 两个文件,再按 Snapshot→cursor 顺序提交并报告 partial success。
|
|
142
|
+
|
|
143
|
+
对双 target 命令,`@cursor` 表示 source;destination 必须显式给出。显式 target/path 与 cursor 的 `namespace/definition` 不一致时拒绝执行。transaction operation 文件必须保持自包含,使用 concrete target/path,不解析依赖外部可变状态的 cursor alias。后续可增加 `@cursor:<name>`,当前不承诺该语法。
|
|
144
|
+
|
|
145
|
+
`cursor show` 默认调用 Cirru Parser 0.2.15 的 `focus_cirru_preview_with_options`,通过 `CirruFocusOptions` 在 definition 级展示副本中折叠无关分支、保留 definition 的 head/name/参数,并直接使用 `CURSOR` marker。Calcit 不再遍历重写 `'FOCUSED` 或手工拼接 definition header;该依赖使用精确版本约束,防止全局安装忽略 lockfile 时出现未经验证的展示语义漂移。目标表达式只在展示副本中渲染为:
|
|
146
|
+
|
|
147
|
+
```cirru
|
|
148
|
+
CURSOR
|
|
149
|
+
map items $ fn (item)
|
|
150
|
+
render-item item
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`CURSOR` 只存在于 presentation AST。真实 path、fingerprint、JSON tree 和任何 mutation 都基于未包裹的源码树。`cursor show --view node|focus|full` 可切换只看节点、结构聚焦或完整 definition;机器输出分别提供真实 `tree` 与带展示标记的 `preview_tree`,不要求调用方从展示代码反推 path。
|
|
154
|
+
|
|
155
|
+
编辑后的 cursor 回显由顶层参数控制:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
cr --cursor-after none calcit.cirru tree replace app.main/render! --path @cursor --code 'quote nil'
|
|
159
|
+
cr --cursor-after summary calcit.cirru edit cp app.main/render! --from @3 --path @cursor
|
|
160
|
+
cr --cursor-after focus calcit.cirru tree wrap app.main/render! --path @cursor --code 'quote $ when ok? self'
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`summary` 是默认值,只向 stderr 输出 target、更新后 path 与迁移原因;`focus` 额外输出结构聚焦预览;`none` 关闭自动回显。三种模式都不改变 cursor 的实际维护。
|
|
164
|
+
|
|
165
|
+
导航命令按当前 snapshot 的真实树验证边界:`child` 省略 index 时进入首子节点,`child --last` 按当前 child count 进入末子节点;`next` / `prev` 的 `--count N` 一次跨越 N 个 sibling;`forward` / `backward` 按 definition 的深度优先结构顺序跨 list 边界移动;`back --count N` 一次回退 N 条普通导航历史。所有多步移动只写一条 history。`--count 0`、越界和同时传 child index 与 `--last` 都拒绝执行,且不改变 cursor。顶层 `--cursor-after focus` 用于 set、search 选中和导航时,会紧接成功提示展示新的 focus,不要求 Agent 再调用一次 `cursor show`。
|
|
166
|
+
|
|
167
|
+
`back` 只回退 cursor 位置,不撤销 Snapshot mutation。源码恢复仍应使用版本控制或显式的反向结构编辑,避免把导航历史误当成 source undo。
|
|
168
|
+
|
|
169
|
+
搜索结果可直接成为 cursor,不需要 Agent 从展示文本复制 target/path:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
cr query search render-item --filter app.main/render! --exact --set-cursor 0
|
|
173
|
+
cr query search-expr 'map items' --filter app.main/render! --set-cursor 1
|
|
174
|
+
cr query search state --start-path @cursor --set-cursor 0
|
|
175
|
+
cr query search-expr 'div $ {}' --start-path @cursor
|
|
176
|
+
cr query next
|
|
177
|
+
cr query prev
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
`query search` 与 `query search-expr` 在 human 输出为每个 match 显示稳定的全局 `[#N]`,JSON match 增加 `cursor_index`。`--filter @cursor` 限定当前 definition;`--start-path @cursor` 同时推导 definition filter 并把搜索根限制到当前 subtree,冲突 filter 直接报错。显式 `--set-cursor N` 采用同一排序后的结果,在返回查询结果前更新 sidecar;成功提示写 stderr,因此 `--format json` 的 stdout 仍是单个 JSON。越界或 dependency-only match 无法映射到当前可编辑 snapshot 时拒绝设置,并提示用 `--filter <project-namespace>` 缩小范围。`query next/prev` 从 last query 计算相邻 index、重新执行搜索并只回显新 cursor;若 snapshot revision 已变化则拒绝复用旧 index,要求重新执行原搜索选中结果,避免结果重排后跳错节点。
|
|
181
|
+
|
|
182
|
+
## 3.1 高频开发场景覆盖
|
|
183
|
+
|
|
184
|
+
- **定位后连续小改**:search `--set-cursor` 后用 `cursor apply`,无需复制容易漂移的数字路径。
|
|
185
|
+
- **组件/分支样板扩展**:`cursor duplicate` 后继续 replace/wrap;clipboard 保留给跨位置搬运。
|
|
186
|
+
- **调整调用或属性层级**:双向 slurp/barf、swap、wrap/unwrap/raise 覆盖 Lisp 编辑器最常见的结构操作。
|
|
187
|
+
- **在大表达式内二次查找**:`search/search-expr --start-path @cursor` 只遍历选中 subtree,并可把结果再次设为 cursor。
|
|
188
|
+
- **连续浏览搜索命中**:首次 `--set-cursor` 后使用 `query next/prev`,不再重复长查询参数或保存完整结果集。
|
|
189
|
+
- **连续 sibling 范围确认**:在起点 `cursor anchor`,移动到终点后用 `cursor region` 验证结构化范围;region 第一版不隐式改变单表达式 copy/cut 语义。
|
|
190
|
+
- **跨 definition 往返**:用最多 16 个 `cursor mark/goto` 保存高频位置,普通短期返回仍用 push/pop。
|
|
191
|
+
- **编辑后语义确认**:`query type-at @cursor --path @cursor`、`query context @cursor` 复用当前 definition/selection。
|
|
192
|
+
- **抽取与跨位置重构**:`edit split-def @cursor --path @cursor`,或 push/cut/search/pop/paste 组合保留起点和结构化代码。
|
|
193
|
+
- **definition 元数据维护**:schema、examples、doc、tags 等 edit target 接受 `@cursor`,definition rename/move 后 cursor 跟随。
|
|
194
|
+
|
|
195
|
+
workspace/module 解析、全项目分析、namespace 批量更新与可复现 transaction 输入不依赖 cursor;这些操作使用显式目标更清晰,也避免把本地临时状态引入项目语义。
|
|
196
|
+
|
|
197
|
+
## 4. Cursor 迁移规则
|
|
198
|
+
|
|
199
|
+
一次 mutation 记为作用于 path `M`,当前 cursor path 为 `C`。所有规则在旧树坐标上计算,保存 snapshot 成功后再持久化新 cursor。
|
|
200
|
+
|
|
201
|
+
### 4.1 不改变层级的操作
|
|
202
|
+
|
|
203
|
+
- `replace` / `rewrite` / `search-replace`:`C == M` 时 cursor 保持 `M` 并刷新 fingerprint;若 `M` 是 `C` 的祖先,任意 replacement 无法证明内部节点对应关系,cursor 降级到 `M` 并提示;其他位置不变。
|
|
204
|
+
- `replace-leaf`:不改变路径;若恰好替换 cursor 节点,刷新 fingerprint。
|
|
205
|
+
- `append-child`:已有节点路径不变。
|
|
206
|
+
|
|
207
|
+
### 4.2 插入
|
|
208
|
+
|
|
209
|
+
- `insert-before M`:与 `M` 同父且 index 大于等于插入点的 cursor,index 加一;cursor 位于这些兄弟节点的 subtree 内时同样迁移。
|
|
210
|
+
- `insert-after M`:同父且 index 大于 `M` 的 cursor,index 加一。
|
|
211
|
+
- `insert-child M`:cursor 是 `M` 的严格后代时,紧随 `M` 后的第一段 index 加一;cursor 正好在 `M` 时不变。
|
|
212
|
+
|
|
213
|
+
### 4.3 删除与重排
|
|
214
|
+
|
|
215
|
+
- `delete M`:位于 `M` 之后的同级 cursor index 减一;`C == M` 或 `C` 位于其内部时,cursor 移到 `M` 的 parent 并返回 `target-deleted` 提示。
|
|
216
|
+
- `batch-delete`:按实际从后向前的删除顺序逐条应用同一规则。
|
|
217
|
+
- `swap-next M` / `swap-prev M`:cursor 位于两个交换 sibling 任一 subtree 时,交换对应 path 段。
|
|
218
|
+
- `unwrap M`:cursor 在 wrapper 内时移除 `M` 对应的 wrapper path 段,并叠加 child index;cursor 在其后的 sibling 时按展开 child 数调整。
|
|
219
|
+
- `raise M`:cursor 位于被提升 child 内时删除 parent 到 child 的 path 段;位于被丢弃 sibling 内时降级到被替换的 parent。
|
|
220
|
+
- `wrap M`:`C == M` 时选择 wrapper;若 cursor 位于原 subtree 内,只有能从模板中的唯一 `self` 映射证明新路径时才跟随,否则降级到 wrapper。
|
|
221
|
+
|
|
222
|
+
所有迁移完成后必须用新 snapshot 重新读取 cursor path,刷新 fingerprint 和 definition revision。preview 每次从当前 Snapshot 构造,不持久化到 cursor history。新 path 无法读取时不写一个看似有效的 cursor。
|
|
223
|
+
|
|
224
|
+
## 5. 外部变化与 stale 恢复
|
|
225
|
+
|
|
226
|
+
`cr cursor show` 和 `--path @cursor` 每次都重新解析 snapshot:
|
|
227
|
+
|
|
228
|
+
1. revision 与 fingerprint 均匹配时状态为 `exact`;
|
|
229
|
+
2. revision 变化但 path fingerprint 仍匹配时刷新 revision,状态为 `verified-at-path`;
|
|
230
|
+
3. path 不匹配时,全 definition 搜索旧 fingerprint;唯一命中则重定位并提示 `relocated`;
|
|
231
|
+
4. 零命中或多命中时拒绝作为 mutation target,报告命中数量并要求重新 set。
|
|
232
|
+
|
|
233
|
+
自动恢复必须宁可失败,也不能在重复结构中猜测。
|
|
234
|
+
|
|
235
|
+
## 6. Edit 命令、Transaction 与并发
|
|
236
|
+
|
|
237
|
+
`edit cp/mv/split-def` 的 path 参数接受 `@cursor`。`edit def --overwrite` 把 cursor 安全降级到 definition root;`rename` / `mv-def` 更新 target;`split-def` 在 cursor 位于被抽取 subtree 内时把 target 切换到新 definition,并保留相对 path。`cp` 使用与 tree insertion 相同的确定性坐标迁移;`mv` 完成后按 fingerprint 验证或唯一重定位。
|
|
238
|
+
|
|
239
|
+
定义被 `rm-def` 删除时不删除整个 sidecar,因为 history、stack 和 clipboard 仍可能用于恢复。active cursor 被明确标为 stale,并提示使用 `cursor back` 或重新 `set`。
|
|
240
|
+
|
|
241
|
+
transaction 的 staged 子命令不得直接更新真实 cursor 文件。完整目标是 transaction 开始时读取 cursor 到内存,按 operation 顺序迁移 staged cursor;只有 snapshot 原子提交成功后才写 cursor,dry-run 返回 `cursor_before` / `cursor_after` 但不更新文件。
|
|
242
|
+
|
|
243
|
+
当前实现先满足较保守的兼容路径:staged 子命令禁用 cursor sidecar 写入;transaction 提交后重新解析最终 snapshot,并用 same-path fingerprint 或全 definition 唯一 fingerprint 验证 active cursor。无法唯一恢复时只提示 cursor 需要处理,不把已经成功提交的 transaction 误报成回滚。逐 operation 的 staged cursor 迁移以及 dry-run 的 `cursor_before` / `cursor_after` 仍是后续增强。
|
|
244
|
+
|
|
245
|
+
`cursor cut` 与 `cursor paste` 同时影响 Snapshot 和 sidecar,两个文件不能由普通 rename 构成单一原子事务。实现必须先把两边都写入同目录 staged 文件,再按可恢复顺序提交:cut 先提交含完整 clipboard 的 sidecar,再提交删除后的 Snapshot,保证后一步失败时表达式仍可恢复;paste 先提交 Snapshot,再提交新 cursor,并在第二步失败时明确报告“源码已修改”,禁止把它伪装成可安全重试的普通失败。
|
|
246
|
+
|
|
247
|
+
snapshot 与 cursor 是两个文件,无法依靠单次 rename 同时提交。若 snapshot 已成功而 cursor 写入失败,后续调用会通过 revision/fingerprint 检出 stale;错误必须明确报告“源码已提交、cursor 未更新”,不能声称整体回滚。
|
|
248
|
+
|
|
249
|
+
当前状态只有一个 active cursor。原子 rename 保证文件完整性,但不提供多个进程共享同一 Snapshot 时的语义并发控制;并行 Agent 应使用独立 worktree/Snapshot,或改用带 precondition 的 transaction 与显式路径。marks 只能隔离导航位置,不能解决并发源码写入,因此不作为并发安全方案。
|
|
250
|
+
|
|
251
|
+
## 7. 第一阶段实现范围
|
|
252
|
+
|
|
253
|
+
1. Cirru EDN cursor 状态的读取、v1-v3→v4 兼容、旧路径一次性迁移、校验、64 KiB 上限和原子写入;
|
|
254
|
+
2. `cr cursor set/show/clear/parent/child/next/prev/forward/backward/back/push/pop`,含末子节点、同级多步与跨 list 的深度优先导航;
|
|
255
|
+
3. 结构化 `copy/cut/paste/clipboard`,clipboard 不经过文本序列化;
|
|
256
|
+
4. definition-oriented query/tree/edit 接受 `@cursor` target;tree/type-at/edit 的 path 可同时引用 `@cursor`;
|
|
257
|
+
5. `edit cp/mv/split-def` 接受 `@cursor`,definition replace/rename/move/delete 与 cursor 协作;
|
|
258
|
+
6. 所有直接 tree mutation 对 active cursor 执行确定性 path 迁移,并按 `--cursor-after` 控制回显;
|
|
259
|
+
7. 外部 revision 变化下的 same-path 校验与唯一 fingerprint 重定位;
|
|
260
|
+
8. 单元测试覆盖前方插入、前方删除、swap、目标删除、状态扩展字段、clipboard round-trip 和 focus 展示不影响真实 path。
|
|
261
|
+
9. `query search` / `query search-expr` 为结果提供全局 cursor index,并可显式设置 active cursor。
|
|
262
|
+
10. `cursor apply` 复用 tree mutation;双向 slurp/barf 与 duplicate 保持 active selection;
|
|
263
|
+
11. leaf/expression search 都支持 `--filter @cursor` 与 `--start-path @cursor`,并继续支持 `--set-cursor`。
|
|
264
|
+
12. 单一 sibling region anchor、最多 16 个 named marks,以及只保存参数的 last query / `query next/prev`。
|
|
265
|
+
|
|
266
|
+
transaction 内逐 operation 的 cursor preview、多 active cursor、region 批量 mutation,以及跨 definition 的 clipboard 引用策略在后续阶段接入;未接入的 mutation 必须让 cursor/anchor/marks 在下次使用时经过 stale 校验,不能绕过 fingerprint。
|
|
267
|
+
|
|
268
|
+
## 8. 验收
|
|
269
|
+
|
|
270
|
+
- cursor 位于 `@3.4` 时在同父 `@3.2` 前插入,自动变为 `@3.5`;
|
|
271
|
+
- cursor 之前的 sibling 被删除时自动减一;
|
|
272
|
+
- 对 cursor 之前的 subtree 做内部修改,不改变 cursor;
|
|
273
|
+
- cursor 自身被删除时移动到 parent 并给出提示;
|
|
274
|
+
- cursor 展示 wrapper 不改变真实 path 或 JSON tree;
|
|
275
|
+
- focus 展示保留 definition 签名,并对无关分支使用结构化 folded marker;
|
|
276
|
+
- `back` 与 `push/pop` 语义独立,clipboard 的 cut/paste 保持 Cirru subtree;
|
|
277
|
+
- `child --last`、`next/prev/forward/backward/back --count N` 在成功时只产生一条 history 记录,越界时不修改 cursor;
|
|
278
|
+
- `cursor apply` 与对应 tree 命令的 mutation、校验和 preview 一致;
|
|
279
|
+
- 双向 slurp/barf 跨 parent 边界移动表达式后 cursor 仍选择原 list;duplicate 选中新副本且不修改 clipboard;
|
|
280
|
+
- query/tree/edit 的 `@cursor` target、type-at path 与 subtree search scope 解析到同一 active selection,target 冲突时拒绝执行;
|
|
281
|
+
- search human/JSON 中的 cursor index 一致,`--set-cursor N` 不污染 JSON stdout;
|
|
282
|
+
- `query next/prev` 不保存结果列表,每次重新计算;snapshot 改变后拒绝复用旧 index;
|
|
283
|
+
- region 只接受同 parent 的连续 siblings;marks 不超过 16 个,并随可证明的 tree path 变换迁移;
|
|
284
|
+
- `--cursor-after none|summary|focus` 只改变 stderr 反馈,不改变 mutation 结果;
|
|
285
|
+
- snapshot 被外部修改后,重复 subtree 不会被猜测性选中;
|
|
286
|
+
- `.calcit/cursor.cirru` 始终是可由 `cirru_edn::parse` 读取、且不超过 64 KiB 的单个 EDN value;
|
|
287
|
+
- cut 的 Snapshot 提交失败时 clipboard 已可恢复;paste 的 cursor 提交失败时必须明确报告 Snapshot 已修改。
|
package/RFCs/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# RFC 整理索引
|
|
2
2
|
|
|
3
|
-
更新时间:2026-07-
|
|
3
|
+
更新时间:2026-07-30
|
|
4
4
|
|
|
5
5
|
## 目录原则
|
|
6
6
|
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
| `03-16-runtime-boundary-refactor-plan.md` | Review-needed | 运行时边界重构方案。 |
|
|
22
22
|
| `03-18-query-def-tree-show-chunked-display-plan.md` | Review-needed | query/tree show 分块展示方案。 |
|
|
23
23
|
| `04-13-call-arg-literal-rewrite-rfc.md` | Active | 调用参数字面量重写优化提案。 |
|
|
24
|
-
| `04-13-type-slot-mechanism-rfc.md` |
|
|
24
|
+
| `04-13-type-slot-mechanism-rfc.md` | Partial | Revision 3:已落地无条件擦除与 entry `:type-slots`;环境指纹和 namespaced identity 暂缓。 |
|
|
25
25
|
| `04-15-match-syntax-rfc.md` | Active | match 语法改进提案。 |
|
|
26
26
|
| `04-15-type-directed-optimization-catalog.md` | Active | 基于 `&record:nth` 经验,系统梳理 Record/Tuple/Scope 等类型导向优化机会。 |
|
|
27
27
|
| `04-15-wasm-compilation-feasibility.md` | Active | WASM 编译三条路径(解释器→WASM / AOT 子集 / WASM GC)的可行性评估。 |
|
|
@@ -32,7 +32,13 @@
|
|
|
32
32
|
| `07-06-semantic-tree-navigation-rfc.md` | Draft | 语义化树形导航与编辑:路径标注、多候选交互、锚点搜索替换、结构化查询语言。 |
|
|
33
33
|
| `07-19-doc-knowledge-index-rfc.md` | Draft | Markdown/Calcit snapshot 的知识节点、关系索引与用户级增量缓存方案。 |
|
|
34
34
|
| `07-19-type-introspection-consistency-rfc.md` | Implemented | 类型自省一致性改进:`&methods-of` 支持裸类型定义、`Enum` Display 补 variants、`to-pairs`/`keys` 类型签名修正(第 4 项可选新增 proc 延后)。 |
|
|
35
|
-
| `07-26-agent-
|
|
35
|
+
| `07-26-agent-machine-protocol-rfc.md` | Draft | Agent typed result、JSON 协议、definition descriptor 与按需重新解析/可选 daemon 的边界。 |
|
|
36
|
+
| `07-26-static-semantic-analysis-rfc.md` | Draft | 静态类型发现、类型证据、动态边界分类与统一结构化诊断。 |
|
|
37
|
+
| `07-26-safe-structured-editing-rfc.md` | Draft | revision/fingerprint 前置条件、事务编辑、语义 diff 与受影响范围验证。 |
|
|
38
|
+
| `07-26-agent-docs-and-evaluation-rfc.md` | Draft | 结构化文档上下文、默认检索范围和 Agent 接口基准。 |
|
|
39
|
+
| `07-28-git-module-store-rfc.md` | Draft | 保持 `deps.cirru` 与 Git 模块路径,以 tag 为最佳实践并使用 pnpm 式全局目录存储;不引入 registry、lockfile、workspace 或多版本。 |
|
|
40
|
+
| `07-28-project-tooling-contract-rfc.md` | Draft | 在既有 `cr` 子命令上补强单项目工具契约,保持 EDN 树形事实来源。 |
|
|
41
|
+
| `07-28-persistent-tree-cursor-rfc.md` | Draft | `.calcit/` 本地状态、虚拟 cursor、region/marks/last-query、结构化 clipboard 与 path 迁移。 |
|
|
36
42
|
|
|
37
43
|
## 已执行的清理
|
|
38
44
|
|
package/build.rs
CHANGED
|
@@ -6,16 +6,71 @@ use std::env;
|
|
|
6
6
|
use std::fs;
|
|
7
7
|
use std::path::Path;
|
|
8
8
|
|
|
9
|
+
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
|
|
10
|
+
#[serde(rename_all = "lowercase")]
|
|
11
|
+
pub enum SnapshotRunMode {
|
|
12
|
+
#[default]
|
|
13
|
+
Native,
|
|
14
|
+
Js,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fn deserialize_run_mode<'de, D>(deserializer: D) -> Result<SnapshotRunMode, D::Error>
|
|
18
|
+
where
|
|
19
|
+
D: serde::Deserializer<'de>,
|
|
20
|
+
{
|
|
21
|
+
let value = Edn::deserialize(deserializer)?;
|
|
22
|
+
let mode = match value {
|
|
23
|
+
Edn::Tag(tag) => tag.ref_str().to_owned(),
|
|
24
|
+
Edn::Str(text) | Edn::Symbol(text) => text.trim_start_matches(':').to_owned(),
|
|
25
|
+
other => return Err(serde::de::Error::custom(format!("expected :native or :js, got {other:?}"))),
|
|
26
|
+
};
|
|
27
|
+
match mode.as_str() {
|
|
28
|
+
"native" => Ok(SnapshotRunMode::Native),
|
|
29
|
+
"js" => Ok(SnapshotRunMode::Js),
|
|
30
|
+
_ => Err(serde::de::Error::custom(format!("expected :native or :js, got {mode}"))),
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
fn deserialize_ns_def<'de, D>(deserializer: D) -> Result<String, D::Error>
|
|
35
|
+
where
|
|
36
|
+
D: serde::Deserializer<'de>,
|
|
37
|
+
{
|
|
38
|
+
match Edn::deserialize(deserializer)? {
|
|
39
|
+
Edn::Str(text) | Edn::Symbol(text) => Ok(text.to_string()),
|
|
40
|
+
other => Err(serde::de::Error::custom(format!(
|
|
41
|
+
"expected namespace/definition string or symbol, got {other:?}"
|
|
42
|
+
))),
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
9
46
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
10
|
-
pub struct
|
|
11
|
-
#[serde(
|
|
47
|
+
pub struct SnapshotEntry {
|
|
48
|
+
#[serde(default, deserialize_with = "deserialize_run_mode")]
|
|
49
|
+
pub mode: SnapshotRunMode,
|
|
50
|
+
#[serde(rename = "init-fn", deserialize_with = "deserialize_ns_def")]
|
|
12
51
|
pub init_fn: String,
|
|
13
|
-
#[serde(rename = "reload-fn")]
|
|
52
|
+
#[serde(rename = "reload-fn", deserialize_with = "deserialize_ns_def")]
|
|
53
|
+
pub reload_fn: String,
|
|
54
|
+
#[serde(default)]
|
|
55
|
+
pub description: String,
|
|
56
|
+
#[serde(default)]
|
|
57
|
+
pub modules: Vec<String>,
|
|
58
|
+
#[serde(default, rename = "type-slots")]
|
|
59
|
+
pub type_slots: HashMap<String, String>,
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
63
|
+
pub struct LegacySnapshotConfigs {
|
|
64
|
+
#[serde(rename = "init-fn", deserialize_with = "deserialize_ns_def")]
|
|
65
|
+
pub init_fn: String,
|
|
66
|
+
#[serde(rename = "reload-fn", deserialize_with = "deserialize_ns_def")]
|
|
14
67
|
pub reload_fn: String,
|
|
15
68
|
#[serde(default)]
|
|
16
69
|
pub modules: Vec<String>,
|
|
17
70
|
#[serde(default)]
|
|
18
71
|
pub version: String,
|
|
72
|
+
#[serde(default, rename = "type-slots")]
|
|
73
|
+
pub type_slots: HashMap<String, String>,
|
|
19
74
|
}
|
|
20
75
|
|
|
21
76
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
@@ -46,8 +101,9 @@ pub struct FileInSnapShot {
|
|
|
46
101
|
pub struct Snapshot {
|
|
47
102
|
pub package: String,
|
|
48
103
|
pub about: Option<String>,
|
|
49
|
-
|
|
50
|
-
pub
|
|
104
|
+
#[serde(default)]
|
|
105
|
+
pub version: String,
|
|
106
|
+
pub entries: HashMap<String, SnapshotEntry>,
|
|
51
107
|
pub files: HashMap<String, FileInSnapShot>,
|
|
52
108
|
}
|
|
53
109
|
|
|
@@ -417,11 +473,37 @@ fn main() {
|
|
|
417
473
|
|
|
418
474
|
let files = parse_files(data.get_or_nil("files")).unwrap_or_else(|e| panic!("failed to parse calcit-core `:files`: {e}"));
|
|
419
475
|
|
|
476
|
+
let legacy_configs = match data.get_or_nil("configs") {
|
|
477
|
+
Edn::Nil => None,
|
|
478
|
+
value => {
|
|
479
|
+
Some(from_edn::<LegacySnapshotConfigs>(value).unwrap_or_else(|e| panic!("failed to parse calcit-core legacy `:configs`: {e}")))
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
let mut entries: HashMap<String, SnapshotEntry> =
|
|
483
|
+
from_edn(data.get_or_nil("entries")).unwrap_or_else(|e| panic!("failed to parse calcit-core `:entries`: {e}"));
|
|
484
|
+
if let Some(configs) = &legacy_configs {
|
|
485
|
+
entries.insert(
|
|
486
|
+
"default".to_owned(),
|
|
487
|
+
SnapshotEntry {
|
|
488
|
+
mode: SnapshotRunMode::Native,
|
|
489
|
+
init_fn: configs.init_fn.clone(),
|
|
490
|
+
reload_fn: configs.reload_fn.clone(),
|
|
491
|
+
description: String::new(),
|
|
492
|
+
modules: configs.modules.clone(),
|
|
493
|
+
type_slots: configs.type_slots.clone(),
|
|
494
|
+
},
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
let version = match data.get_or_nil("version") {
|
|
498
|
+
Edn::Nil => legacy_configs.map(|configs| configs.version).unwrap_or_default(),
|
|
499
|
+
value => from_edn(value).unwrap_or_else(|e| panic!("failed to parse calcit-core `:version`: {e}")),
|
|
500
|
+
};
|
|
501
|
+
|
|
420
502
|
let snapshot = Snapshot {
|
|
421
503
|
package: pkg,
|
|
422
504
|
about,
|
|
423
|
-
|
|
424
|
-
entries
|
|
505
|
+
version,
|
|
506
|
+
entries,
|
|
425
507
|
files,
|
|
426
508
|
};
|
|
427
509
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# `cr edit transaction` 第一版
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
- 在既有 `cr edit` 命令组中增加 `transaction`,输入复用现有 `edit`、`tree`、`config` 参数序列。
|
|
6
|
+
- 以 Cirru EDN argument lists 为主输入,并允许在 `--code` 后直接嵌入 quoted AST;JSON 作为兼容格式保留。支持 `--dry-run`、`--expect-revision` 和 human/JSON 输出。
|
|
7
|
+
- 所有 operation 只修改同目录 staged snapshot;全部成功、snapshot 可重新加载/序列化且原文件 revision 未变化后,才通过 rename 一次提交。
|
|
8
|
+
- staged 文件保留原 snapshot 权限;失败、stale revision 与 dry-run 都由 guard 清理,不修改原文件。
|
|
9
|
+
- transaction 会捕获每个子命令的 stdout/stderr,保证成功时 JSON stdout 仍是单个可解析值。
|
|
10
|
+
|
|
11
|
+
## 关键取舍
|
|
12
|
+
|
|
13
|
+
- 没有立即把全部 handler 重构成新的内存 mutation API,因为这会同时改变大量稳定的 `edit/tree/config` 路径。
|
|
14
|
+
- 第一版通过 staged snapshot 调用当前 `cr` 子命令,直接复用参数解析、namespace 边界、tree path、schema 和保存校验。
|
|
15
|
+
- transaction 仅允许 `edit`、`tree`、`config`,拒绝嵌套 transaction 和只读/执行类命令。
|
|
16
|
+
- snapshot revision 当前是原文件内容的 MD5 opaque ID;执行前和最终 rename 前都会检查,避免 stale write。
|
|
17
|
+
|
|
18
|
+
## 验证
|
|
19
|
+
|
|
20
|
+
- 新增 JSON/Cirru 解析、Cirru EDN 内嵌 quoted code、非法 command、nested transaction、stale revision、dry-run、operation failure rollback、成功提交测试。
|
|
21
|
+
- 真实临时 snapshot 验证了 `config version`、`edit doc` 与 `tree replace` 的组合提交及失败回滚。
|
|
22
|
+
- `cargo fmt --all`
|
|
23
|
+
- `cargo clippy -- -D warnings`
|
|
24
|
+
- `cargo test`
|
|
25
|
+
- `yarn compile`
|
|
26
|
+
- `yarn check-agent-interface`(新增 staged transaction 场景,12/12)
|
|
27
|
+
- `yarn check-all`
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# 可持续迁移的 tree cursor
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
- 新增 `07-28-persistent-tree-cursor-rfc.md`,将 cursor 定义为 CLI 跨调用维护的树形选择状态,而不是 snapshot 中的源码身份。
|
|
6
|
+
- 新增 `cr cursor set/show/clear/parent/child/next/prev`,状态以 Cirru EDN 保存到 snapshot 同目录的 `.calcit-cursor.cirru`。
|
|
7
|
+
- path-based tree 命令可通过 `--path @cursor` 引用 active cursor,显式 definition target 必须匹配。
|
|
8
|
+
- `cursor show` 在展示副本中用 `CURSOR` 包裹目标;JSON 输出仍返回真实 subtree 与独立 cursor 元数据。
|
|
9
|
+
- 直接 tree mutation 成功后会刷新 cursor fingerprint、preview 与 definition revision,并对插入、删除、swap、unwrap、raise、wrap、replace 等操作执行确定性 path 迁移。
|
|
10
|
+
|
|
11
|
+
## 安全边界
|
|
12
|
+
|
|
13
|
+
- cursor 文件是本地状态,已加入 `.gitignore`,不会写进 snapshot 或模块内容。
|
|
14
|
+
- 外部修改导致 path fingerprint 不匹配时,只允许通过唯一 fingerprint 命中自动重定位;零命中或多命中拒绝猜测。
|
|
15
|
+
- snapshot 已保存但 cursor 写入失败时,错误会明确说明源码 mutation 已成功,避免误认为整体回滚。
|
|
16
|
+
- transaction staged 子命令暂时禁用真实 cursor 写入;transaction 内 cursor 演化留到下一阶段实现。
|
|
17
|
+
|
|
18
|
+
## 验证
|
|
19
|
+
|
|
20
|
+
- cursor path transform 单元测试覆盖前方插入、前方删除、删除目标、swap 与 unwrap。
|
|
21
|
+
- Cursor Cirru EDN 文件 round-trip 测试。
|
|
22
|
+
- 临时 snapshot 集成测试覆盖源码插入后持久化 cursor 从 `@48.1` 迁移到 `@48.2`,且 preview 仍为原来的 `true` 节点。
|
|
23
|
+
- 手工 CLI smoke 覆盖 `cursor set/show --format json`、`tree show --path @cursor` 和 `tree insert-before --path @cursor`。
|
|
24
|
+
- `cargo fmt --all`
|
|
25
|
+
- `cargo clippy -- -D warnings`
|
|
26
|
+
- `cargo test`(256 lib + 147 cr)
|
|
27
|
+
- `yarn compile`
|
|
28
|
+
- `yarn check-agent-interface`(12/12)
|
|
29
|
+
- `yarn check-all`
|
|
30
|
+
- `cr docs check-md` 验证 `docs/run/edit-tree.md` 与 `docs/CalcitAgent.md`
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Cursor focus、导航栈与结构化 clipboard
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
- `cursor show` 基于 Cirru Parser 0.2.15 `focus_cirru_preview_with_options` 展示 definition 上下文,由 parser 直接保留 definition 签名并生成展示态 `CURSOR`。
|
|
6
|
+
- 精确锁定 `cirru_parser = 0.2.15`。原因是 `cargo install --path` 不保证沿用仓库 lockfile;若只使用兼容版本范围,本地测试与全局安装可能获得不同的 focus marker 语义。
|
|
7
|
+
- `.calcit-cursor.cirru` 升级到 schema v2,继续兼容读取 v1;新增普通导航 history、显式 `push/pop` stack 与保存 Cirru tree 的 clipboard。
|
|
8
|
+
- 新增 `cursor back/push/pop/copy/cut/paste/clipboard/clear-clipboard`。cut 后选择 parent,paste 后选择新节点,clipboard 保留以支持重复粘贴。
|
|
9
|
+
- 顶层 `--cursor-after none|summary|focus` 控制 mutation 后的 stderr 回显;默认 summary,不影响实际 cursor 维护。
|
|
10
|
+
- `edit cp/mv/split-def` 支持 `@cursor`;definition overwrite/rename/move/delete、namespace delete 与 transaction 提交后验证会更新或明确提示 cursor 状态。
|
|
11
|
+
|
|
12
|
+
## 准确性要点
|
|
13
|
+
|
|
14
|
+
- `edit mv` 按插入路径、源删除后的 index 漂移和 cursor 在源 subtree 内的相对路径做确定性迁移,不依赖可能多命中的 fingerprint 搜索。
|
|
15
|
+
- focus、full 和 node 都只构造 presentation tree;真实 snapshot、path、fingerprint 与 JSON `tree` 不包含 `CURSOR`。
|
|
16
|
+
- JSON `cursor.show` 分开返回真实 `tree` 和展示用 `preview_tree`,并报告 `exact`、`verified-at-path` 或 `relocated`。
|
|
17
|
+
- sidecar 不在 `.gitignore` 时只提示建议,不自动修改用户项目。
|
|
18
|
+
|
|
19
|
+
## 验证
|
|
20
|
+
|
|
21
|
+
- cursor 单元测试覆盖 v1→v2 兼容、history/stack/clipboard round-trip、focus 签名与 marker、cut/paste、前方增删、swap/unwrap,以及重复 fingerprint 下的确定性 move。
|
|
22
|
+
- 临时 Calcit snapshot 手工验证 `cursor show --view focus`、`--cursor-after focus`、back/push/pop、copy/cut/paste 和 `edit cp/mv/split-def/rename/mv-def`。
|
|
23
|
+
- 全局安装后的 `cr` 在 `respo-calcit-workflow` 临时副本中完成深层 cursor focus、cut/paste 原位恢复、`tree replace --path @cursor` 与 `cr js` 编译。
|
|
24
|
+
- `cargo fmt`
|
|
25
|
+
- `cargo clippy -- -D warnings`
|
|
26
|
+
- `cargo test`
|
|
27
|
+
- `yarn compile`
|
|
28
|
+
- `yarn check-agent-interface`(12/12)
|
|
29
|
+
- `yarn check-all`
|
|
30
|
+
- `cr docs check-md` 验证 `docs/run/edit-tree.md` 与 `docs/CalcitAgent.md`
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Cursor 多步导航与搜索选取
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
- `cursor child` 省略 index 时进入首子节点,`cursor child --last` 按当前树进入末子节点。
|
|
6
|
+
- `cursor next`、`cursor prev` 与 `cursor back` 支持 `--count N`;多步移动只产生一次 history transition,参数为零或越界时不写 cursor。
|
|
7
|
+
- `query search` 与 `query search-expr` 的每个结果获得稳定的全局 cursor index:human 输出为 `[#N]`,JSON 字段为 `cursor_index`。
|
|
8
|
+
- 搜索命令新增 `--set-cursor N`,直接将对应结果写入项目 cursor。确认信息走 stderr,保持 JSON stdout 为单个可解析对象。
|
|
9
|
+
- dependency-only 搜索结果不能映射到当前可编辑 snapshot 时明确报错,不将 cursor 猜测性落到同名定义。
|
|
10
|
+
|
|
11
|
+
## 验证关注点
|
|
12
|
+
|
|
13
|
+
- `child --last` 必须读取当前 node 的 child count,不能把 `-1` 或陈旧 index 写入 sidecar。
|
|
14
|
+
- sibling skip 和 multi-back 必须预先验证完整步数;失败后 active cursor 与 history 均保持不变。
|
|
15
|
+
- human 与 JSON 的结果编号必须共享同一排序和扁平化顺序。
|
|
16
|
+
|
|
17
|
+
## 验证结果
|
|
18
|
+
|
|
19
|
+
- `cargo fmt`、`cargo clippy --all-targets -- -D warnings`、`cargo test`、`yarn compile` 与 `yarn check-all` 通过。
|
|
20
|
+
- Agent interface smoke 12/12,`docs/run/edit-tree.md` 与 `docs/CalcitAgent.md` 的可执行代码块检查通过。
|
|
21
|
+
- 全局安装 `cr 0.12.53` 后,在 `respo-calcit-workflow` 临时副本以 `query search --set-cursor 0` 定位 `comp-runs`,随后验证 `child --last`、`prev --count 1`、`back --count 2`、focus 展示,并完成 `cr calcit.cirru js` 编译。
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Agent 工具链 RFC 拆分
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
- 移除体量过大的 `07-26-agent-semantic-interface-roadmap-rfc.md`,按紧密关联的功能边界拆分为文档与评估、机器协议、安全结构化编辑、静态语义分析等 RFC。
|
|
6
|
+
- 补充单项目工具契约、Git 模块存储与持久树形 cursor RFC,明确 Calcit 继续以 EDN/Cirru 树形源码、结构化文档和既有 `cr` 子命令为中心。
|
|
7
|
+
- Git 模块仍以 tag 为最佳实践、允许分支名,不引入 registry、workspace 或 lockfile;依赖冲突采用最高版本并输出 warning。
|
|
8
|
+
- LSP 延后到一次性解析接口足够稳定且维护成本可接受之后,不把行号作为源码或诊断的核心身份。
|
|
9
|
+
|
|
10
|
+
## 文档边界
|
|
11
|
+
|
|
12
|
+
- 新 RFC 各自描述一块可独立评审和实施的能力,避免实现状态、长期设想和不适用于 Calcit 的 Cargo 风格命令混在同一文件中。
|
|
13
|
+
- `RFCs/README.md` 更新索引,后续实现和验收可直接引用对应 RFC。
|
|
14
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Cursor 与 transaction 使用文档
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
- 在 Agent 指南中补充通过搜索结果设置 cursor、用 `@cursor` 进行连续树形编辑、导航栈与结构化 clipboard 的推荐流程。
|
|
6
|
+
- 在结构化编辑参考中完整记录 cursor sidecar、focus/node/full 展示、mutation 后坐标维护与 `--cursor-after` 回显控制。
|
|
7
|
+
- 记录 Cirru EDN transaction 的主要输入形式、quoted code、dry-run、revision 检查与 JSON 兼容边界。
|
|
8
|
+
- 将新增命令加入 Agent 能力地图和文档 frontmatter,便于结构化文档查询定位。
|
|
9
|
+
|
|
10
|
+
## 一致性
|
|
11
|
+
|
|
12
|
+
- 文档示例沿用既有 `cr` 子命令风格,不引入 Cargo 风格命令。
|
|
13
|
+
- 所有路径仍指向 Snapshot 中的 Cirru tree,展示用 `CURSOR` 不改变真实源码与 path。
|
|
14
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Cursor clipboard 可恢复提交与精简状态
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
- `.calcit-cursor.cirru` 升级到 schema v3,继续读取 v1/v2;active、history 与 stack 不再重复保存完整 subtree preview,展示时从当前 Snapshot 重建。
|
|
6
|
+
- `cursor cut` 和 `cursor paste` 在修改任何目标文件前先生成 Snapshot 与 sidecar staged 文件,避免序列化或临时文件失败造成半成品。
|
|
7
|
+
- cut 按 sidecar→Snapshot 顺序提交,确保 Snapshot 提交失败时完整表达式已经存在于结构化 clipboard。
|
|
8
|
+
- paste 按 Snapshot→sidecar 顺序提交;若第二步失败,错误明确说明源码已经修改并禁止盲目重试。
|
|
9
|
+
- `cursor show` 构造真实节点和 focus preview 时复用同一次 Snapshot 读取,减少重复解析。
|
|
10
|
+
|
|
11
|
+
## 验证
|
|
12
|
+
|
|
13
|
+
- 新增 cut 第二阶段失败时 clipboard 已持久化的故障注入测试。
|
|
14
|
+
- 新增 paste cursor 提交失败时 Snapshot 已提交且错误包含 partial-success 指引的测试。
|
|
15
|
+
- sidecar round-trip 断言 schema v3 且不包含 `:preview`。
|
|
16
|
+
- `cargo test --bin cr cursor`
|
|
17
|
+
- `cargo clippy --bin cr -- -D warnings`
|
|
18
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Cursor 原生结构编辑与跨层导航
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
- 新增 `cursor apply <operation>`,由 active cursor 推导 definition target 与 tree path,再复用既有 tree handler,避免 Agent 在连续操作中重复传递坐标。
|
|
6
|
+
- 新增 `cursor slurp-next` 与 `cursor barf-last`,通过已有 `edit mv` 完成跨 parent 的 Paredit 风格节点移动,cursor 始终跟随原先选中的 list。
|
|
7
|
+
- 新增 `cursor forward/backward --count N`,按 definition 的深度优先结构顺序跨 list 边界移动,并把整次多步移动记录为一条 history。
|
|
8
|
+
- 当顶层使用 `--cursor-after focus` 时,set、search 选中、普通导航与 history/stack 恢复会立即输出 focus preview。
|
|
9
|
+
- 非法 root、leaf、空 list、缺少 sibling、零步和越界操作均在写 Snapshot 前失败。
|
|
10
|
+
|
|
11
|
+
## 验证
|
|
12
|
+
|
|
13
|
+
- `cargo fmt`
|
|
14
|
+
- `cargo clippy -- -D warnings`
|
|
15
|
+
- `cargo test`
|
|
16
|
+
- `yarn compile`
|
|
17
|
+
- `yarn check-agent-interface`
|
|
18
|
+
- `yarn check-all`
|
|
19
|
+
- `cr docs check-md` 检查 Agent 指南和 tree editing 文档。
|
|
20
|
+
- 全局安装当前 `cr` 后,在 Respo workflow 临时副本往返执行 depth-first navigation、swap、slurp/barf;Snapshot 与原文件逐字节一致,`cr js` 成功。
|