@calcit/procs 0.13.12 → 0.13.14

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.
Binary file
package/README.md CHANGED
@@ -130,9 +130,22 @@ Related examples and workflows:
130
130
  :dependencies $ {}
131
131
  |calcit-lang/memof |0.0.11
132
132
  |calcit-lang/lilac |main
133
+ :dev-dependencies $ {}
134
+ |calcit-lang/calcit-test |0.1.0
133
135
  ```
134
136
 
135
- Run `caps` to download. Sources are downloaded into `~/.config/calcit/modules/`. If a module contains `build.sh`, it will be executed mostly for compiling Rust dylibs.
137
+ Run `caps` to resolve the recursive dependency graph and install it. Immutable revisions are stored under
138
+ `~/.config/calcit/modules/.store/`, while the current project receives links under `.calcit/modules/`.
139
+ Different projects can therefore use different revisions without switching a shared checkout. Existing
140
+ `~/.config/calcit/modules/<repo>/` checkouts remain a runtime fallback during migration.
141
+
142
+ Published SemVer tags are preferred. Branch refs remain supported for development, but `caps` warns with
143
+ the resolved commit. When a graph requests several SemVer tags for one repository, the highest requested
144
+ version is selected and reported.
145
+
146
+ Root projects install both `:dependencies` and `:dev-dependencies`. Recursive resolution only follows
147
+ `:dependencies`, so test and maintenance modules declared by a dependency do not leak into consumers.
148
+ Use `caps add --dev <org/repo>@<ref>` and `caps remove --dev <org/repo>` to manage the development group.
136
149
 
137
150
  `:calcit-version` helps with version checks and provides hints in [CI](https://github.com/calcit-lang/setup-cr).
138
151
 
@@ -144,11 +157,20 @@ To load modules, use `:modules` configuration and the runtime snapshot file `cal
144
157
  :modules $ [] |memof/calcit.cirru |lilac/
145
158
  ```
146
159
 
147
- Paths defined in `:modules` field are just loaded as files from `~/.config/calcit/modules/`,
148
- i.e. `~/.config/calcit/modules/memof/calcit.cirru`.
160
+ Paths defined in `:modules` first load from the snapshot directory's `.calcit/modules/`, then fall back to
161
+ `~/.config/calcit/modules/`, i.e. `.calcit/modules/memof/calcit.cirru` or the legacy global path.
149
162
 
150
163
  Modules ending with `/` are automatically suffixed with `calcit.cirru`, and still fall back to `compact.cirru` for compatibility.
151
164
 
165
+ Inspect and verify the resolved graph with:
166
+
167
+ ```bash
168
+ caps tree
169
+ caps why calcit-lang/memof
170
+ caps status
171
+ caps verify
172
+ ```
173
+
152
174
  ### Development
153
175
 
154
176
  Local validation commands:
@@ -1,59 +1,474 @@
1
- # RFC: Git 模块解析与本地内容寻址存储
1
+ # RFC: Git 模块依赖图与项目级模块视图
2
2
 
3
3
  状态:Draft
4
4
  日期:2026-07-28
5
+ 更新:2026-08-12
5
6
  关联:`docs/run/load-deps.md`
6
7
 
7
- ## 1. 决策
8
+ ## 1. 决策摘要
8
9
 
9
- Calcit 暂不提供 registry,也不引入 workspace。模块的发布、获取与版本身份继续以 Git repository + ref/commit 为基础;模块仍以目录形态提供 `calcit.cirru`、文档与可选 Rust 动态库构建输入。
10
+ Calcit 继续使用 GitHub repository + Git ref 管理模块,不建设 registry,
11
+ 也暂不引入 workspace、依赖别名和同一项目内的多版本 namespace 隔离。
10
12
 
11
- 依赖声明应优先使用发布 tag;tag 是可复现安装、兼容性沟通与 CI 的最佳实践。允许使用分支名以支持开发中的模块,但分支是可变引用:每次安装或更新都应显示其解析到的具体 commit,不能把“当前分支头”当作稳定版本身份。
13
+ 这次演进增加四层能力:
12
14
 
13
- 依赖图中同一模块只能选择一个版本:解析多个约束时统一选择最高版本,并对不同声明或无法严格满足的约束输出 warning,说明最终选中的 ref/commit 与受影响依赖。由于 namespace 是全局语义空间,不支持同项目多版本并存或 Cargo 式依赖重命名隔离。
15
+ 1. 全局目录可以同时保存同一模块的多个 revision;
16
+ 2. 每个项目通过 `.calcit/modules/` 中的链接获得自己的模块视图;
17
+ 3. `caps` 递归读取各模块的 `deps.cirru`,解析单版本依赖图并提供
18
+ `tree`、`why`、`status` 和 `verify`;
19
+ 4. native 模块的构建产物按平台和 ABI 隔离,并生成可检查的构建回执。
14
20
 
15
- ## 2. 问题
21
+ 依赖应优先声明为发布 tag。允许分支用于开发,但每次解析都必须 warning,
22
+ 并显示最终 commit。多个可比较的版本 tag 冲突时统一选择最高版本,并显示
23
+ 声明来源;不可比较的 branch、commit 或非版本 tag 不猜测“更高版本”。
16
24
 
17
- 直接把每个项目依赖完整 clone 到全局 modules 目录会造成重复体积;但单纯的 archive cache 不适合需要文档浏览、Git 状态检查、`build.sh` 和 Rust dylib 的模块。目标是在保留目录体验和 Git 路径的前提下,获得类似 pnpm 的去重。
25
+ 整个迁移保持现有 `calcit.cirru` `:modules` 内容可用。旧项目仍可从
26
+ `~/.config/calcit/modules/<repo>/` 加载,新项目则优先从自身
27
+ `.calcit/modules/<repo>/` 加载。
18
28
 
19
- ## 3. 两层本地布局
29
+ ## 2. 目标与非目标
20
30
 
21
- 建议将实现分为不可变 store 与项目可见链接:
31
+ ### 2.1 目标
32
+
33
+ - 两个项目可以使用同一模块的不同版本,互不切换对方的 checkout;
34
+ - 相同 repository + commit + native build key 在本机只安装一份;
35
+ - `caps deps.cirru` 在没有 `calcit.cirru` 的目录中也能完成递归下载;
36
+ - 依赖选择结果确定、可解释,冲突能追溯到每条父依赖;
37
+ - 项目链接只在完整解析、下载和构建成功后切换;
38
+ - native 产物不会在不同 target、Calcit ABI 或 `cirru_edn` ABI 间误用;
39
+ - 当前 `caps`、`caps outdated`、`caps upgrade`、`caps status` 和
40
+ `caps reset` 在迁移期继续可用。
41
+
42
+ ### 2.2 非目标
43
+
44
+ - 不建设中心 registry、账号或发布服务;
45
+ - 第一阶段不支持 `^1.2`、`~1.2` 等版本范围,依赖值仍是准确 Git ref;
46
+ - 不允许同一项目同时加载同一模块的两个版本;
47
+ - 不用模块别名解决 namespace 冲突;
48
+ - 不要求所有历史模块立刻增加 native manifest;
49
+ - 不在第一阶段自动删除 legacy clone 或未引用的 store 内容。
50
+
51
+ ## 3. 目录模型
52
+
53
+ 当前正式路径是 `~/.config/calcit/modules/`。新 store 放在它下面,避免再引入
54
+ 一套顶级目录;路径解析应集中到一个 helper,后续再考虑 XDG 或其他平台差异。
55
+
56
+ ```text
57
+ ~/.config/calcit/modules/
58
+ .store/git/<owner>/<repo>/<commit>/source/
59
+ .store/git/<owner>/<repo>/<commit>/realizations/<build-key>/
60
+ <repo>/ # legacy clone,迁移期保留
61
+
62
+ <project>/
63
+ deps.cirru
64
+ .calcit/
65
+ caps-state.cirru
66
+ modules/
67
+ <repo> -> ~/.config/calcit/modules/.store/.../source/
68
+ <native-repo> -> .../realizations/<build-key>/
69
+ tmp/
70
+ ```
71
+
72
+ Git tag 或 branch 只负责解析 commit;store 的 source 身份始终是 canonical Git
73
+ URL + resolved commit。这样同一 commit 被两个 tag 指向时不会重复保存。
74
+
75
+ `.calcit/caps-state.cirru` 是本次安装的诊断记录,不是 lockfile,也不参与下一次版本
76
+ 选择。它至少记录:
77
+
78
+ - canonical repository URL;
79
+ - 所有请求来源及声明的 ref;
80
+ - 选中的 ref、ref 类型和 resolved commit;
81
+ - 项目链接目标;
82
+ - branch warning 和版本冲突 warning;
83
+ - native build key、回执路径与验证状态。
84
+
85
+ 项目侧由 `caps` 生成或维护的内容统一放在 `.calcit/` 内,包括模块链接、状态、
86
+ 临时文件、构建日志以及未来的本机 override sidecar,避免在项目根目录或模块链接
87
+ 目录散落工具文件。项目根目录只保留用户维护、需要纳入版本控制的 `deps.cirru`。
88
+ `.calcit/` 整体默认应加入 `.gitignore`;其中内容是本机安装状态,不能作为跨机器
89
+ 依赖身份。
90
+
91
+ ### 3.1 模块目录名冲突
92
+
93
+ 现有 `:modules` 使用 repository basename,例如 `memof/`。因此第一阶段继续用
94
+ basename 建立项目链接。如果依赖图里出现 `owner-a/utils` 与 `owner-b/utils`,
95
+ `caps` 必须报错并列出两者,不能静默覆盖。依赖别名需要同时解决 namespace
96
+ 身份,不在本 RFC 范围内。
97
+
98
+ ### 3.2 原子切换
99
+
100
+ `caps` 按以下顺序修改本机状态:
101
+
102
+ 1. 在 store 的 `.store/tmp/` 下创建临时目录,解析 ref、下载 source(与 store 同文件系统,保证 rename 原子);项目侧临时 project view 写入 `.calcit/tmp/`;
103
+ 2. 完成递归依赖图和版本选择;
104
+ 3. 完成需要的 native realization 与验证;
105
+ 4. 写入临时 project view;
106
+ 5. 原子替换 `.calcit/modules/` 中的项目链接和 `.calcit/caps-state.cirru`。
107
+
108
+ 任何一步失败都保留项目原来的链接。下载完成但未被链接的 store 内容可以留给
109
+ 后续安装复用,由未来的 `caps clean` 回收。
110
+
111
+ Windows 上优先使用 directory junction;不支持链接时允许显式 copy fallback,
112
+ 并在 `caps status` 中标记为非共享副本,不能假装已经去重。
113
+
114
+ ## 4. `deps.cirru` 协议
115
+
116
+ 保持当前字符串 map 兼容,先不引入复杂 constraint 对象:
117
+
118
+ ```cirru
119
+ {}
120
+ :version |0.16.67
121
+ :calcit-version |0.13.10
122
+ :dependencies $ {}
123
+ |Respo/respo-ui.calcit |0.7.2
124
+ |calcit-lang/calcit.std |0.2.15
125
+ ```
126
+
127
+ 字段职责:
128
+
129
+ - `:version`:当前项目或模块自身的发布版本,由 `caps version` 管理;
130
+ - `:calcit-version`:期望使用的 Calcit 工具链版本;
131
+ - `:dependencies`:repository 到准确 Git tag、branch 或 commit 的映射。
132
+
133
+ 依赖 key 继续要求 canonical `owner/repo`。GitHub URL 仅作为 `caps add` 输入,
134
+ 写回文件前必须规范化。
135
+
136
+ ### 4.1 项目版本迁移
137
+
138
+ 当前项目版本在 `calcit.cirru :version`。迁移时不能立即删除该字段:
139
+
140
+ 1. `deps.cirru :version` 存在时,它是发布工具的权威值;
141
+ 2. 只有 `calcit.cirru :version` 时,`caps version get` 读取旧值并提示迁移;
142
+ 3. `caps version set/bump` 只写入 `deps.cirru`,不隐式改写机器生成的 snapshot;
143
+ 迁移期 snapshot `:version` 继续作为旧版 `cr` 的兼容字段,允许暂时不同;
144
+ 4. `cr config set version` 先保留,但提示改用 `caps version set`;
145
+ 5. 等生态完成迁移后,再让 snapshot 的 `:version` 变为可选并停止写入镜像。
146
+
147
+ 建议命令:
148
+
149
+ ```bash
150
+ caps version get
151
+ caps version set 0.16.68
152
+ caps version bump patch
153
+ ```
154
+
155
+ `caps version` 必须验证 SemVer。安装 tag 时,如果模块的 `deps.cirru :version`
156
+ 与 tag(允许 tag 带一个 `v` 前缀)不一致,`caps verify` 报错。branch 模块只做
157
+ warning,因为 branch 没有稳定发布版本身份。
158
+
159
+ ### 4.2 standalone `deps.cirru`
160
+
161
+ 位置参数继续是依赖文件:
162
+
163
+ ```bash
164
+ caps ./fixtures/demo/deps.cirru
165
+ caps /tmp/download-only/deps.cirru tree
166
+ ```
167
+
168
+ 项目根目录始终取该文件的父目录,项目视图写到同目录的 `.calcit/modules/`。
169
+ 这个流程不得要求同目录存在 `calcit.cirru`、`package.json` 或 Git repository。
170
+ 如果只想预览,`caps <file> tree --resolve` 可以解析远端但不创建项目链接。
171
+
172
+ ## 5. ref 分类和 warning
173
+
174
+ 不能只根据字符串长相判断 branch 或 tag。`caps` 获取远端 refs 后按以下顺序
175
+ 分类:
176
+
177
+ 1. 精确匹配 `refs/tags/<ref>`:tag;
178
+ 2. 精确匹配 `refs/heads/<ref>`:branch;
179
+ 3. 完整 commit hash:commit;
180
+ 4. 都不匹配:错误。
181
+
182
+ 如果远端同时存在同名 tag 和 branch,拒绝并要求用户明确修改命名;Git 自己的
183
+ 模糊 ref 选择不能成为包管理语义。
184
+
185
+ warning 分级:
186
+
187
+ - SemVer tag:正常推荐路径;
188
+ - 非 SemVer tag:可复现,但无法参与“选择最高版本”,给提示;
189
+ - branch:每次安装 warning,并显示 branch -> commit;
190
+ - commit:可复现,但缺少发布版本语义,给提示。
191
+
192
+ `--ci` 不隐藏 warning。未来可增加 `--deny-branch`,让发布 CI 把 branch 依赖
193
+ 升级为错误。
194
+
195
+ ## 6. 递归解析与单版本选择
196
+
197
+ ### 6.1 解析过程
198
+
199
+ `caps` 维护带 provenance 的请求集合:
22
200
 
23
201
  ```text
24
- ~/.config/calcit/store/git/<content-id>/ # 完整模块目录,按 resolved commit 内容去重
25
- <project>/.calcit/modules/<module-name>/ # 指向 store 的符号链接或平台等价链接
202
+ Request {
203
+ repository,
204
+ requested_ref,
205
+ requested_by, # root 或 owner/repo@resolved-ref
206
+ }
26
207
  ```
27
208
 
28
- `content-id` 至少由 canonical repository URL、resolved commit、submodule 状态与必要构建输入版本组成。tag 或分支名只用于解析;store 身份始终以其解析后的 commit 为准。链接目标是完整目录,因此 snapshot、docs、native source、已构建产物与诊断文件仍能按现有路径读取。
209
+ 解析采用 fixpoint,而不是“下载时顺手递归”:
210
+
211
+ 1. 读取 root `deps.cirru`,产生第一批 requests;
212
+ 2. 为每个 repository 解析 refs 并选择当前 revision;
213
+ 3. 读取选中 revision 的 `deps.cirru`,加入它的 requests;
214
+ 4. 如果新请求改变了某模块的选择,撤销旧 revision 贡献的传递请求,再展开新
215
+ revision;
216
+ 5. 重复直到选择和边集合都不再变化;
217
+ 6. 检测 dependency cycle,`tree` 展示 cycle 标记但安装不重复展开;
218
+ 7. graph 完整后才进入 native build 和项目链接阶段。
219
+
220
+ 模块没有 `deps.cirru` 时按空依赖处理并给兼容性提示。文件存在但无法解析,或
221
+ `:dependencies` 类型错误时必须失败,不能静默当作空依赖。
222
+
223
+ ### 6.2 冲突规则
224
+
225
+ 同一 repository 在项目内只能有一个选择:
226
+
227
+ - 所有请求都是可解析 SemVer 的 tag:选择最高 SemVer;
228
+ - 多个请求指向同一 commit:合并为一个选择;
229
+ - 相同 branch 名:选择该 branch 当前远端 commit,并 warning;
230
+ - tag 与 branch 混合时,仍在所有请求中选择最高 SemVer tag 并给强 warning;
231
+ 发布 tag 比可变 branch 更适合作为现有项目的兼容裁决,根项目的较低 tag 也
232
+ 不压过传递依赖明确请求的较高 tag;
233
+ - 不同 branch、commit 与其他 ref、或多个不可比较 tag:不能定义“更高”。如果
234
+ root 有直接声明,使用 root 声明并给强 warning;没有 root 直接声明则报错,
235
+ 要求 root 在 `deps.cirru` 中显式裁决。
29
236
 
30
- 项目 snapshot `:modules` 可继续使用模块目录路径。链接层只解决本地寻址和项目隔离,不改变模块的目录接口。
237
+ 选择较高 SemVer tag 时,即使能自动继续,也必须打印类似:
31
238
 
32
- ## 4. 解析与 native 模块
239
+ ```text
240
+ warning: selected Respo/respo.calcit@0.16.67
241
+ requested 0.16.65 by Cumulo/cumulo-reel.calcit@0.6.7
242
+ requested 0.16.67 by root
243
+ ```
33
244
 
34
- 当前不引入 `calcit.lock`。`deps.cirru` 是唯一的依赖声明与解析来源;`caps` 每次按其 tag/branch 解析依赖图并选择统一最高版本。命令结果应记录 canonical Git URL、声明的 tag/branch、实际 resolved commit、版本选择 warning 和完整性信息,方便 CI 日志与问题排查。对于 branch 依赖,更新应明确提示其从哪个 commit 前进到哪个 commit。
245
+ `caps --strict` 可把所有版本提升和不可复现 ref warning 变为错误,适合对依赖
246
+ 漂移敏感的 CI。第一阶段不自动寻找远端“最新版本”;最高版本只在依赖图实际
247
+ 请求的版本集合中选择。
35
248
 
36
- Rust dylib 不是 store 的例外:其 source 与 `build.sh` 仍在模块目录中。产物必须按 target triple、Calcit ABI/version、Rust toolchain 或 build-input hash 分桶,不能跨不兼容环境复用。构建前展示将执行的脚本、来源与 hash;失败信息关联到具体 module revision。
249
+ ### 6.3 确定性
37
250
 
38
- ## 5. caps 命令演进
251
+ - repository、边、warning tree 子节点统一排序后输出;
252
+ - SemVer 比较使用标准 precedence,不用发布时间;
253
+ - build metadata 不参与 SemVer precedence,相同 precedence 但不同 tag 指向不同
254
+ commit 时视为不可裁决冲突;
255
+ - 解析结果中的每个 ref 都保存 resolved commit;
256
+ - 网络并发只能改变耗时,不能改变选择或输出顺序。
39
257
 
40
- 在保留 `caps`、`outdated`、`status`、`reset` 的基础上,逐步增加:
258
+ ## 7. `caps tree` 与命令演进
259
+
260
+ 在保留已有命令的基础上增加:
41
261
 
42
262
  ```bash
43
- caps add <git-url-or-org/repo>@<constraint>
44
- caps remove <module>
45
- caps tree
46
- caps why <module>
47
- caps update [module]
48
- caps verify
263
+ caps [deps.cirru] # resolve + install + link
264
+ caps [deps.cirru] add owner/repo@0.1.2
265
+ caps [deps.cirru] remove owner/repo
266
+ caps [deps.cirru] tree
267
+ caps [deps.cirru] why owner/repo
268
+ caps [deps.cirru] update [owner/repo]
269
+ caps [deps.cirru] verify
270
+ caps [deps.cirru] status
271
+ ```
272
+
273
+ 兼容规则:
274
+
275
+ - 现有 `caps add owner/repo --version 0.1.2` 继续工作;
276
+ - 现有 `upgrade` 先作为 `update` 的别名,不立即删除;
277
+ - 现有 `download owner/repo@ref` 可以内部构造临时 root graph,默认也递归;
278
+ - `reset` 只处理 legacy clone 或显式 path/checkout override。不可变 store 不做
279
+ `git reset --hard`,项目链接损坏时由 `caps` 重建。
280
+
281
+ `caps tree` 默认展示实际选择和来源,而不只是 root 声明:
282
+
283
+ ```text
284
+ root
285
+ ├─ Respo/reel.calcit@0.6.7
286
+ │ └─ Respo/respo.calcit@0.16.67 ↑ requested 0.16.65
287
+ └─ Respo/respo.calcit@0.16.67
288
+ ```
289
+
290
+ 建议同时支持:
291
+
292
+ - `--depth <n>`:限制展示深度;
293
+ - `--all`:重复展示共享子图,否则使用 `(*)` 引用;
294
+ - `--format json`:供 Agent 和 CI 读取,stdout 必须是单个 JSON;
295
+ - `--offline`:只使用已经解析进 store 的 refs;
296
+ - `--resolve`:没有安装时允许访问远端完成预览。
297
+
298
+ `caps why <module>` 为每个 root dependency 输出到该模块的一条最短路径,并
299
+ 列出全部直接版本请求和最终选择理由。稠密依赖图不枚举所有简单路径,避免输出
300
+ 组合爆炸。
301
+
302
+ ## 8. `cr` 的模块查找兼容层
303
+
304
+ 目前多个命令各自拼接 `~/.config/calcit/modules/`。实现项目视图前先把它们
305
+ 收敛到共享 resolver,至少覆盖运行、query、config、call-graph、docs 和 wasm
306
+ 内部验证路径。
307
+
308
+ 对于 snapshot 中的非相对模块路径,例如 `memof/`,查找顺序是:
309
+
310
+ 1. `<snapshot-dir>/.calcit/modules/memof/`;
311
+ 2. `~/.config/calcit/modules/memof/`(legacy fallback)。
312
+
313
+ `./util.cirru` 这类明确相对路径仍只相对 snapshot,不进入模块 store。项目视图
314
+ 存在但单个模块链接缺失时仍允许逐项 fallback,并在 verbose/status 中提示,
315
+ 这样迁移不要求一次切换所有模块。
316
+
317
+ 模块源码中的 `calcit-dirname` 应解析到项目链接最终指向的完整 module view。
318
+ 这保证现有 `get-dylib-path` 拼接 `dylibs/lib...` 的代码无需修改。
319
+
320
+ ## 9. native 模块
321
+
322
+ ### 9.1 为什么不能直接在 source store 运行 `build.sh`
323
+
324
+ 现有脚本会删除并重建 `dylibs/`。如果直接在按 commit 共享的 source 中执行,
325
+ 不同平台、Rust toolchain 或 Calcit ABI 的项目会相互覆盖,source 也不再不可变。
326
+
327
+ 因此 native 模块分为:
328
+
329
+ - `source/`:按 commit 保存,不运行构建脚本;
330
+ - `realizations/<build-key>/`:从 source 创建的独立构建视图,项目链接指向这里。
331
+
332
+ realization 可以先使用完整工作树保证简单可靠;以后再用 reflink、hardlink 或
333
+ 只读 source + artifact view 优化体积,不应在第一版提前增加复杂度。
334
+
335
+ ### 9.2 build key
336
+
337
+ build key 至少包含:
338
+
339
+ - canonical repository URL 和 resolved commit;
340
+ - target triple 与 OS/architecture;
341
+ - Calcit FFI ABI version;
342
+ - `cirru_edn` version;
343
+ - Calcit version(第一阶段保守隔离);
344
+ - `rustc -vV` 的 toolchain identity;
345
+ - build command 和显式 build environment 的 hash。
346
+
347
+ 同一 build key 的 realization 构建成功后可跨项目复用。失败或未完成的临时目录
348
+ 不能被项目链接引用。
349
+
350
+ ### 9.3 可选 native manifest
351
+
352
+ 已有 `build.sh` 继续识别。新模块建议在自己的 `deps.cirru` 增加:
353
+
354
+ ```cirru
355
+ :native $ {}
356
+ :build $ [] |sh |build.sh
357
+ :libraries $ [] |dylibs/libcalcit_std
358
+ :timeout-seconds 600
49
359
  ```
50
360
 
51
- `caps status` 区分 store 完整性、项目链接、当前 `deps.cirru` 解析结果、版本选择 warning、native 产物兼容性和用户手工修改。不可变 store 不接受直接编辑;开发依赖使用明确的 path/checkout override,而不是污染共享内容。
361
+ `:libraries` 使用不带平台扩展名的路径,`caps` 根据 target `.so`、`.dylib`
362
+ 或 `.dll`。manifest 存在时,未产生声明产物是构建失败。只有 `build.sh` 而没有
363
+ manifest 的旧模块仍构建,但给迁移提示,并至少验证 `dylibs/` 下存在当前平台
364
+ 动态库。
365
+
366
+ 构建脚本是来自依赖的代码执行。`caps` 执行前必须显示 module、ref、commit、
367
+ 脚本路径和 hash;CI 日志也不能隐藏。后续可增加 allow-list,但第一阶段不突然
368
+ 改变现有默认构建行为。
369
+
370
+ ### 9.4 构建回执与验证
371
+
372
+ 成功后在 realization 中写 `.calcit-native.cirru`,记录:
373
+
374
+ - build key 的全部输入;
375
+ - 开始/结束时间和 command;
376
+ - 每个产物的相对路径、大小和内容 hash;
377
+ - ABI version、`cirru_edn` version 和验证结果。
378
+
379
+ `caps verify` 检查:
380
+
381
+ 1. project link 指向 state 声明的 source/realization;
382
+ 2. source commit 与 store identity 一致,且没有用户修改;
383
+ 3. native receipt 的 build key 与当前环境一致;
384
+ 4. 声明产物存在、未通过 symlink 逃出 realization、hash 匹配;
385
+ 5. 能加载动态库,存在 ABI 查询符号,且 ABI/EDN version 匹配;
386
+ 6. manifest 声明的业务符号(若未来增加)存在。
387
+
388
+ 动态库加载验证应放在短生命周期子进程中。错误库崩溃时只让 verifier 子进程
389
+ 失败,`caps` 仍能报告 module、commit、产物路径和退出状态。
390
+
391
+ 运行时继续执行 ABI 检查,不能因为 `caps verify` 已通过就跳过。加载错误应尝试
392
+ 附带相邻 build receipt 的 module revision、target 和 rebuild 提示。dylib cache
393
+ 应使用 canonical path 作为 key;项目链接在 watcher 运行期间切换后,提示重启
394
+ 进程,不尝试卸载已加载 library。
395
+
396
+ ## 10. 状态、override 与人工修改
397
+
398
+ 共享 store 视为不可变。开发某个依赖时不要在 store 中直接编辑,后续使用显式
399
+ override,例如 `.calcit/overrides.cirru` 本机 sidecar 或 CLI 参数指向 path checkout。
400
+ override 的正式语法另开小 RFC,不阻塞 store 和递归解析。
401
+
402
+ 在 override 落地前,`caps status` 至少区分:
403
+
404
+ - dependency graph 是否仍能解析;
405
+ - store source 是否完整、commit 是否匹配;
406
+ - project link 是否缺失或指错;
407
+ - 是否使用 legacy global clone;
408
+ - branch 与版本选择 warning;
409
+ - native realization 是否适配当前环境;
410
+ - source 或 realization 是否被手工修改。
411
+
412
+ 发现 store 被修改时不自动 reset。重新安装到新的临时目录并原子替换,旧的损坏
413
+ 目录留待显式 clean,可以减少误删用户内容的风险。
414
+
415
+ ## 11. 渐进实现顺序
416
+
417
+ ### Phase A:共享路径解析和元数据
418
+
419
+ - 集中 `cr`/docs/query 的 module resolver;
420
+ - 项目 `.calcit/modules` 优先、legacy global fallback;
421
+ - `PackageDeps` 支持 `:version` 与可选 `:native`;
422
+ - 增加 `caps version`,只管理 `deps.cirru`;
423
+ - 远端 ref 分类,branch/non-SemVer warning;
424
+ - 保持当前单层下载行为作为兼容基线。
425
+
426
+ ### Phase B:多版本 store 与项目链接
427
+
428
+ - source 以 canonical repo + commit 入 store;
429
+ - 安装完成后原子创建项目链接和 state;
430
+ - 从干净 legacy clone 导入/复用 commit,不删除旧目录;
431
+ - `caps status` 同时理解 legacy 与 project view。
432
+
433
+ ### Phase C:递归依赖图
434
+
435
+ - 带 provenance 的 fixpoint resolver;
436
+ - SemVer tag 最高版本选择和不可比较冲突规则;
437
+ - `caps tree`、`caps why`、JSON 输出;
438
+ - cycle、缺失 `deps.cirru`、损坏子依赖文件的测试。
439
+
440
+ ### Phase D:native realization
441
+
442
+ - build key、隔离构建目录和 receipt;
443
+ - legacy `build.sh` 兼容与可选 native manifest;
444
+ - `caps verify` 子进程加载检查;
445
+ - runtime 错误关联 receipt。
446
+
447
+ 每个 phase 都可以单独发布,不能要求一次性修改所有模块。Phase A/B 稳定后再让
448
+ 默认 `caps` 开启递归解析;此前可用实验 flag 在真实 Respo 依赖链验证。
449
+
450
+ ## 12. 测试与验收
52
451
 
53
- ## 6. 非目标与验收
452
+ 除仓库常规 `cargo fmt`、`cargo clippy -- -D warnings`、`cargo test`、
453
+ `yarn compile`、`yarn check-all` 和 `yarn check-agent-interface` 外,依赖管理需覆盖:
54
454
 
55
- - 不建设中心 registry、账号、发布服务、lockfile 或语义版本多版本安装;
56
- - 不支持 workspace,也不让多个版本进入同一 namespace 空间;
57
- - 不把模块压缩成失去 docs/native source 的 blob。
455
+ - 两项目请求同模块不同 tag,链接到不同 commit;
456
+ - 两项目请求相同 commit,store 只保存一份 source;
457
+ - 菱形依赖选择最高 SemVer,并输出全部 provenance warning;
458
+ - branch 依赖显示 resolved commit,`--strict` 失败;
459
+ - branch/tag 混合时优先 SemVer tag 并强 warning;全是不可比较 ref 且没有 root
460
+ 裁决时失败;
461
+ - 依赖环不会无限递归,`tree` 输出稳定;
462
+ - 子模块 `deps.cirru` 损坏时安装失败且旧项目链接不变;
463
+ - standalone `deps.cirru` 在空目录完成安装;
464
+ - basename 冲突不会覆盖链接;
465
+ - native build key 在 target/ABI/toolchain 改变后失效;
466
+ - native 构建中断不会留下可复用的“成功”目录;
467
+ - 产物缺失、hash 改变、错误架构、ABI 不匹配和系统依赖缺失均能定位到具体
468
+ module revision;
469
+ - legacy `~/.config/calcit/modules/<repo>` 项目仍可运行;
470
+ - Respo 等真实项目的 compile、类型查询与 examples 回归通过。
58
471
 
59
- 验收:两项目共享同一 resolved revision 只保存一份内容;项目链接可独立重建;版本不一致时选择最高版本并输出可读 warning;不同 native ABI/target 不会错误复用产物;原有目录模块加载与文档命令保持兼容。
472
+ 最终验收标准:项目之间不再通过切换全局 checkout 相互影响;依赖图的每个选择
473
+ 都可用 `tree/why` 解释;失败安装不破坏现有项目;native 产物不会跨不兼容环境
474
+ 复用,并能在运行前通过 `caps verify` 发现主要错误。
@@ -0,0 +1,81 @@
1
+ # caps project module store and recursive dependency graph
2
+
3
+ ## Summary
4
+
5
+ - Added a commit-addressed global module store under
6
+ `~/.config/calcit/modules/.store/` and a per-project module view under
7
+ `.calcit/modules/`.
8
+ - Made runtime module loading prefer the project view while retaining the
9
+ legacy global module directory as a fallback.
10
+ - Added recursive `deps.cirru` resolution with deterministic highest-SemVer
11
+ selection, branch warnings, request provenance, and basename collision
12
+ rejection.
13
+ - Added `caps tree`, `caps why`, `caps verify`, strict warning handling, and
14
+ `caps version get/set/bump`.
15
+ - Isolated native `build.sh` execution in keyed realizations so shared source
16
+ revisions stay clean and incompatible build outputs are not reused.
17
+ - Kept generated project state, links, temporary files, and local ignore rules
18
+ inside `.calcit/`.
19
+
20
+ ## Compatibility findings
21
+
22
+ - Older module metadata may omit `:dependencies`; it is treated as an empty
23
+ graph. A present but malformed `:dependencies` still fails the install.
24
+ - Existing projects frequently mix published tags with transitive `main`
25
+ dependencies. Published SemVer tags take precedence over mutable refs and
26
+ produce an explicit warning. Completely incomparable mutable refs still
27
+ require a direct root decision.
28
+ - Dense graphs make exhaustive `why` path enumeration impractical. The command
29
+ reports one shortest path per root dependency and all direct version
30
+ requests instead.
31
+ - Review changed `caps reset` to rebuild project links instead of applying
32
+ `git reset --hard` to shared state. Existing store hits now reject the wrong
33
+ commit or local changes before they are linked.
34
+ - Remote discovery prefers non-interactive HTTPS, falls back to SSH outside CI,
35
+ prints per-module progress, and resolves up to six repositories concurrently.
36
+ Temporary clone names include the repository so equal refs such as `main`
37
+ cannot collide.
38
+ - `cr config modules` now uses the same project-first candidate search as the
39
+ runtime and continues from an invalid `calcit.cirru` to a valid legacy
40
+ `compact.cirru` candidate.
41
+ - Follow-up review fixes use `Path::is_absolute` for module paths, disable
42
+ Git credential prompts in `caps outdated`, and create Windows directory
43
+ junctions before falling back to directory symlinks.
44
+ - The follow-up pass gives isolated commit hashes their own fetch-and-detached
45
+ checkout path, namespaces staging directories with an identity hash, and
46
+ keeps all network Git operations non-interactive with HTTPS-to-SSH fallback
47
+ where supported.
48
+ - Native receipts now record every `dylibs/` artifact's relative path, size,
49
+ and MD5. Reuse and `caps verify` reject malformed receipts, path escapes,
50
+ symlinks, unlisted files, and changed contents. Native staging lives beside
51
+ the destination realization so its final rename stays on one filesystem.
52
+ - On Windows a failed junction and symlink attempt uses a copy fallback. The
53
+ generated state records `:view-mode`, while `caps status` reports a
54
+ non-shared copy rather than treating it as a deduplicated store link.
55
+
56
+ ## Real-project verification
57
+
58
+ - Fast-forwarded clean local checkouts of `lilac`, `calcit.std`, `calcit-http`,
59
+ and `guidebook` before validation. `calcit.std` advanced to remote main;
60
+ the other three were already current.
61
+ - Installed and checked standalone dependency files for `lilac`, `calcit.std`,
62
+ `calcit-http`, and the ten-module transitive `guidebook` graph in temporary
63
+ project roots sharing a temporary store.
64
+ - Confirmed project-view loading with a copied `memof` snapshot and
65
+ `cr query ns lilac.core`.
66
+ - Built `calcit.std@0.2.15` as a native realization, reused the cached build on
67
+ the second install, passed `caps verify`, then confirmed a changed ABI build
68
+ key is rejected until a normal `caps` install switches the project link.
69
+ - Installed the release `cr` and `caps` binaries into `~/.cargo/bin`, then
70
+ installed modules directly inside updated `lilac` and `guidebook` checkouts.
71
+ `guidebook` resolved ten modules, reported all conflicts/branch refs, and
72
+ passed `status`, `verify`, and `cr query ns respo.core` using project links.
73
+
74
+ ## Repository verification
75
+
76
+ - `cargo fmt -- --check`
77
+ - `cargo clippy -- -D warnings`
78
+ - `cargo test`
79
+ - `yarn compile`
80
+ - `yarn check-all`
81
+ - `yarn check-agent-interface`
@@ -0,0 +1,9 @@
1
+ # release 0.13.13 from caps module-store branch
2
+
3
+ ## Summary
4
+
5
+ - Released version `0.13.13` directly from `codex/caps-project-module-store`
6
+ while keeping the feature branch unmerged, as requested.
7
+ - Kept the Rust crate, npm package, and workspace lockfile versions aligned.
8
+ - The branch had already passed PR CI; the release update was additionally
9
+ checked with formatting and the `caps` test suite.
@@ -0,0 +1,36 @@
1
+ # Scope development dependencies in recursive resolution
2
+
3
+ ## Knowledge points
4
+
5
+ - `deps.cirru` now distinguishes consumer-facing `:dependencies` from root-only
6
+ `:dev-dependencies`.
7
+ - A root project resolves and installs both groups. A materialized dependency module exposes only
8
+ its `:dependencies` to the recursive graph, preventing its tests, examples, documentation tools,
9
+ and maintenance modules from leaking into consumers.
10
+ - The same repository may appear in both root groups only when both declarations use the same ref;
11
+ conflicting refs fail before installation or before `caps add` writes the file.
12
+ - `caps add --dev` and `caps remove --dev` manage development dependencies. `caps outdated` and
13
+ `caps upgrade --all` inspect both root groups and update the declaration in its original group.
14
+ - Upgrade guidance should ask projects to audit dependency intent, move project-only tooling into
15
+ `:dev-dependencies`, and confirm the resulting boundary with `caps tree`.
16
+ - A legacy-project upgrade must be staged: record the old behavior, update `cr`/`caps`, migrate the
17
+ dependency graph and Snapshot, then run every entry through strict preprocessing before tightening
18
+ dynamic dispatch and static debt baselines.
19
+ - `--check-only` is a blocking preprocessing gate, including warnings, but it covers the selected
20
+ entry's reachable path rather than every public definition. `check-types`, `weak-types`, and
21
+ `deprecated` are report commands whose JSON summaries require explicit CI comparison.
22
+ - Type-debt baselines should compare separate categories instead of one total. For coverage, track
23
+ `none` and `none + partial` so progress from none to partial is accepted; track dynamic, nil,
24
+ Optional compatibility, and deprecated calls independently.
25
+
26
+ ## Validation
27
+
28
+ - `cargo fmt`
29
+ - `cargo clippy -- -D warnings`
30
+ - `yarn compile`
31
+ - `cargo test`
32
+ - `yarn check-agent-interface`
33
+ - `yarn check-all`
34
+ - `cr docs format-md docs/run/upgrade.md --check`
35
+ - `cr docs check-md docs/run/upgrade.md --entry calcit/test.cirru --failures-only`
36
+ - `cr docs graph check` (with a temporary writable HOME/cache)
@@ -0,0 +1,23 @@
1
+ # Audit the legacy project upgrade playbook
2
+
3
+ ## Findings
4
+
5
+ - An old project cannot safely treat dependency upgrade success as completion. The workflow must
6
+ preserve an old-toolchain behavior baseline and separate tool, dependency, Snapshot, type, and
7
+ behavior changes into reviewable stages.
8
+ - New CLI validation has distinct failure semantics. `--check-only`, examples, Markdown checks, and
9
+ tests are blocking gates; static type/deprecation analysis emits reports that require explicit
10
+ JSON summary comparison in CI.
11
+ - Strict preprocessing must run for every named entry, then run again with `--warn-dyn-method`.
12
+ Entry reachability does not replace tests/examples for public library definitions.
13
+ - Gradual typing needs category-aware baselines for none/not-full coverage, dynamic locations,
14
+ nil/Optional debt, and deprecated calls. A single aggregate can hide category regressions.
15
+ - Snapshot migration must verify which legacy file is authoritative and must not claim that Calcit
16
+ no longer depends on a Snapshot.
17
+
18
+ ## Documentation validation
19
+
20
+ - `cr docs format-md docs/run/upgrade.md --check`
21
+ - `cr docs check-md docs/run/upgrade.md --entry calcit/test.cirru --failures-only`
22
+ - `cr docs graph check` with a temporary writable HOME/cache: 22 nodes, 51 edges
23
+ - `git diff --check`
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calcit/procs",
3
- "version": "0.13.12",
3
+ "version": "0.13.14",
4
4
  "main": "./lib/calcit.procs.mjs",
5
5
  "devDependencies": {
6
6
  "@types/node": "^25.7.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calcit/procs",
3
- "version": "0.13.12",
3
+ "version": "0.13.14",
4
4
  "main": "./lib/calcit.procs.mjs",
5
5
  "devDependencies": {
6
6
  "@types/node": "^25.7.0",