memorytalk 5.0.1__tar.gz → 5.0.2__tar.gz

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.
Files changed (355) hide show
  1. {memorytalk-5.0.1 → memorytalk-5.0.2}/PKG-INFO +1 -1
  2. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v5/README.md +1 -0
  3. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v5/collections.md +14 -3
  4. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/collections-layer.md +9 -9
  5. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/collections.md +2 -2
  6. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/manager.md +1 -1
  7. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v5/collections.md +4 -4
  8. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v5/filesystem.md +1 -2
  9. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/README.md +2 -2
  10. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/controllers/collections.py +5 -0
  11. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/layers/__init__.py +2 -2
  12. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/layers/_user.py +13 -2
  13. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/collections/__init__.py +30 -18
  14. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/collections/repo.py +29 -8
  15. {memorytalk-5.0.1 → memorytalk-5.0.2}/pyproject.toml +1 -1
  16. memorytalk-5.0.2/tests/README.md +19 -0
  17. memorytalk-5.0.2/tests/_util.py +2 -0
  18. memorytalk-5.0.2/tests/adapters/claude_code/README.md +12 -0
  19. memorytalk-5.0.2/tests/adapters/claude_code/test.py +65 -0
  20. memorytalk-5.0.2/tests/adapters/codex/README.md +8 -0
  21. memorytalk-5.0.2/tests/adapters/codex/test.py +34 -0
  22. memorytalk-5.0.2/tests/adapters/kimi/README.md +8 -0
  23. memorytalk-5.0.2/tests/adapters/kimi/test.py +36 -0
  24. memorytalk-5.0.2/tests/cli/end_to_end/README.md +13 -0
  25. {memorytalk-5.0.1/tests/cli → memorytalk-5.0.2/tests/cli/end_to_end}/test.py +1 -1
  26. memorytalk-5.0.2/tests/collections/config/README.md +12 -0
  27. memorytalk-5.0.2/tests/collections/config/test.py +42 -0
  28. memorytalk-5.0.2/tests/collections/decide_and_discuss/README.md +8 -0
  29. memorytalk-5.0.2/tests/collections/decide_and_discuss/test.py +44 -0
  30. memorytalk-5.0.2/tests/collections/history/README.md +8 -0
  31. memorytalk-5.0.2/tests/collections/history/test.py +21 -0
  32. memorytalk-5.0.2/tests/collections/inbox_delivery/README.md +8 -0
  33. memorytalk-5.0.2/tests/collections/inbox_delivery/test.py +40 -0
  34. memorytalk-5.0.2/tests/collections/issue_behaviors/README.md +11 -0
  35. memorytalk-5.0.2/tests/collections/issue_behaviors/test.py +56 -0
  36. memorytalk-5.0.2/tests/collections/layer_guard/README.md +8 -0
  37. memorytalk-5.0.2/tests/collections/layer_guard/test.py +27 -0
  38. memorytalk-5.0.2/tests/collections/layers/README.md +11 -0
  39. memorytalk-5.0.2/tests/collections/layers/test.py +23 -0
  40. memorytalk-5.0.2/tests/collections/manager/README.md +11 -0
  41. memorytalk-5.0.2/tests/collections/manager/test.py +51 -0
  42. memorytalk-5.0.2/tests/collections/objects/README.md +9 -0
  43. memorytalk-5.0.2/tests/collections/objects/test.py +50 -0
  44. memorytalk-5.0.2/tests/collections/tree_and_search/README.md +9 -0
  45. memorytalk-5.0.2/tests/collections/tree_and_search/test.py +35 -0
  46. memorytalk-5.0.2/tests/collections/user_layer/README.md +8 -0
  47. memorytalk-5.0.2/tests/collections/user_layer/test.py +42 -0
  48. {memorytalk-5.0.1 → memorytalk-5.0.2}/tests/conftest.py +32 -5
  49. memorytalk-5.0.2/tests/providers/local_fs/README.md +12 -0
  50. memorytalk-5.0.2/tests/providers/local_fs/test.py +63 -0
  51. memorytalk-5.0.2/tests/providers/sqlite_builder/README.md +13 -0
  52. memorytalk-5.0.2/tests/providers/sqlite_builder/test.py +69 -0
  53. memorytalk-5.0.2/tests/users/activity/README.md +11 -0
  54. memorytalk-5.0.2/tests/users/activity/test.py +54 -0
  55. memorytalk-5.0.2/tests/users/commit_author/README.md +11 -0
  56. memorytalk-5.0.2/tests/users/commit_author/test.py +25 -0
  57. memorytalk-5.0.2/tests/users/identity_header/README.md +12 -0
  58. memorytalk-5.0.2/tests/users/identity_header/test.py +18 -0
  59. memorytalk-5.0.2/tests/users/register/README.md +12 -0
  60. memorytalk-5.0.2/tests/users/register/test.py +32 -0
  61. memorytalk-5.0.2/tests/users/work_ownership/README.md +11 -0
  62. memorytalk-5.0.2/tests/users/work_ownership/test.py +29 -0
  63. memorytalk-5.0.2/tests/work_servers/bash_session/README.md +11 -0
  64. memorytalk-5.0.2/tests/work_servers/bash_session/test.py +59 -0
  65. memorytalk-5.0.2/tests/work_servers/default_session/README.md +8 -0
  66. memorytalk-5.0.2/tests/work_servers/default_session/test.py +23 -0
  67. memorytalk-5.0.2/tests/work_servers/freeze/README.md +7 -0
  68. memorytalk-5.0.2/tests/work_servers/freeze/test.py +13 -0
  69. memorytalk-5.0.2/tests/work_servers/http_session/README.md +11 -0
  70. memorytalk-5.0.2/tests/work_servers/http_session/test.py +20 -0
  71. memorytalk-5.0.2/tests/work_servers/registry/README.md +11 -0
  72. memorytalk-5.0.2/tests/work_servers/registry/test.py +20 -0
  73. memorytalk-5.0.2/tests/works/canvas/README.md +11 -0
  74. memorytalk-5.0.2/tests/works/canvas/test.py +32 -0
  75. memorytalk-5.0.2/tests/works/events_and_inbox/README.md +11 -0
  76. memorytalk-5.0.2/tests/works/events_and_inbox/test.py +38 -0
  77. memorytalk-5.0.2/tests/works/recall/README.md +11 -0
  78. memorytalk-5.0.2/tests/works/recall/test.py +17 -0
  79. memorytalk-5.0.2/tests/works/status/README.md +11 -0
  80. memorytalk-5.0.2/tests/works/status/test.py +33 -0
  81. memorytalk-5.0.2/tests/works/tree/README.md +12 -0
  82. memorytalk-5.0.2/tests/works/tree/test.py +33 -0
  83. memorytalk-5.0.1/tests/README.md +0 -7
  84. memorytalk-5.0.1/tests/adapters/test.py +0 -99
  85. memorytalk-5.0.1/tests/collections/test.py +0 -166
  86. memorytalk-5.0.1/tests/users/test.py +0 -69
  87. memorytalk-5.0.1/tests/work_server_attach/test.py +0 -76
  88. memorytalk-5.0.1/tests/work_tree/test.py +0 -52
  89. {memorytalk-5.0.1 → memorytalk-5.0.2}/.github/workflows/test.yml +0 -0
  90. {memorytalk-5.0.1 → memorytalk-5.0.2}/.gitignore +0 -0
  91. {memorytalk-5.0.1 → memorytalk-5.0.2}/LICENSE +0 -0
  92. {memorytalk-5.0.1 → memorytalk-5.0.2}/README.md +0 -0
  93. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v1/README.md +0 -0
  94. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v1/cards.md +0 -0
  95. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v1/links.md +0 -0
  96. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v1/recall.md +0 -0
  97. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v1/sessions.md +0 -0
  98. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v1/status.md +0 -0
  99. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/README.md +0 -0
  100. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/cards.md +0 -0
  101. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/links.md +0 -0
  102. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/log.md +0 -0
  103. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/rebuild.md +0 -0
  104. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/search.md +0 -0
  105. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/sessions.md +0 -0
  106. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/status.md +0 -0
  107. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/tags.md +0 -0
  108. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/view.md +0 -0
  109. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/README.md +0 -0
  110. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/cards.md +0 -0
  111. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/embedding.md +0 -0
  112. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/explore.md +0 -0
  113. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/read.md +0 -0
  114. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/recall.md +0 -0
  115. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/reviews.md +0 -0
  116. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/search.md +0 -0
  117. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/sessions.md +0 -0
  118. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/status.md +0 -0
  119. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/sync.md +0 -0
  120. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/README.md +0 -0
  121. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/card-links.md +0 -0
  122. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/card-sessions.md +0 -0
  123. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/cards.md +0 -0
  124. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/read.md +0 -0
  125. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/recall.md +0 -0
  126. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/reviews.md +0 -0
  127. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/search.md +0 -0
  128. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v5/system.md +0 -0
  129. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v5/users.md +0 -0
  130. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v5/works.md +0 -0
  131. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/README.md +0 -0
  132. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/card.md +0 -0
  133. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/link.md +0 -0
  134. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/rebuild.md +0 -0
  135. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/recall.md +0 -0
  136. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/search.md +0 -0
  137. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/server.md +0 -0
  138. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/session.md +0 -0
  139. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/sync.md +0 -0
  140. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/README.md +0 -0
  141. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/card.md +0 -0
  142. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/explore.md +0 -0
  143. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/filter.md +0 -0
  144. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/link.md +0 -0
  145. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/log.md +0 -0
  146. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/rebuild.md +0 -0
  147. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/recall.md +0 -0
  148. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/review.md +0 -0
  149. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/search.md +0 -0
  150. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/server.md +0 -0
  151. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/setup.md +0 -0
  152. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/sync.md +0 -0
  153. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/tag.md +0 -0
  154. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/view.md +0 -0
  155. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/README.md +0 -0
  156. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/card.md +0 -0
  157. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/explore.md +0 -0
  158. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/read.md +0 -0
  159. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/recall.md +0 -0
  160. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/review.md +0 -0
  161. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/search.md +0 -0
  162. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/session.md +0 -0
  163. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/setup.md +0 -0
  164. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/sync.md +0 -0
  165. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/upgrade.md +0 -0
  166. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v4/README.md +0 -0
  167. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v4/card.md +0 -0
  168. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v4/insight.md +0 -0
  169. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v4/read.md +0 -0
  170. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v4/recall.md +0 -0
  171. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v4/search.md +0 -0
  172. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v5/README.md +0 -0
  173. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v5/collection.md +0 -0
  174. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v5/server.md +0 -0
  175. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v5/user.md +0 -0
  176. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v5/work.md +0 -0
  177. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/README.md +0 -0
  178. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/card-creation-flow.md +0 -0
  179. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/card-deletion-flow.md +0 -0
  180. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/codex-trust-flow.md +0 -0
  181. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/dsl.md +0 -0
  182. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/explore-cwd-suppression.md +0 -0
  183. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/explore.md +0 -0
  184. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/file-canonical-pattern.md +0 -0
  185. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/forum-dynamics.md +0 -0
  186. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/hook-installation.md +0 -0
  187. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/index-backfill.md +0 -0
  188. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/migration.md +0 -0
  189. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/read-side-effects.md +0 -0
  190. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/recall-pipeline.md +0 -0
  191. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/review-impact.md +0 -0
  192. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/search-ranking.md +0 -0
  193. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/searchbase-extraction.md +0 -0
  194. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/session-namespace.md +0 -0
  195. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/session-rounds-write.md +0 -0
  196. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/sync-pipeline.md +0 -0
  197. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v4/README.md +0 -0
  198. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v4/card.md +0 -0
  199. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v4/insight-migration.md +0 -0
  200. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v4/session-annotation.md +0 -0
  201. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/README.md +0 -0
  202. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/card.md +0 -0
  203. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/collections-store.md +0 -0
  204. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/issue.md +0 -0
  205. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/origin.md +0 -0
  206. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/provider.md +0 -0
  207. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/session.md +0 -0
  208. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/user.md +0 -0
  209. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/work-server.md +0 -0
  210. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/work.md +0 -0
  211. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/report/2026-05-21-search-noisy-or-aggregation-bug.md +0 -0
  212. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/report/2026-05-23-claude-code-adapter-role-misclassification.md +0 -0
  213. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/report/2026-05-23-search-linear-combination-regression.md +0 -0
  214. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/report/2026-05-23-search-vector-index-batch-gap.md +0 -0
  215. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v1/link.md +0 -0
  216. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v1/session.md +0 -0
  217. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v1/settings.md +0 -0
  218. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v1/talk-card.md +0 -0
  219. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v2/link.md +0 -0
  220. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v2/search-result.md +0 -0
  221. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v2/session.md +0 -0
  222. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v2/settings.md +0 -0
  223. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v2/tag.md +0 -0
  224. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v2/talk-card.md +0 -0
  225. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/README.md +0 -0
  226. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/filesystem.md +0 -0
  227. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/recall.md +0 -0
  228. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/review.md +0 -0
  229. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/search-result.md +0 -0
  230. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/session.md +0 -0
  231. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/settings.md +0 -0
  232. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/talk-card.md +0 -0
  233. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v4/README.md +0 -0
  234. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v4/card-link.md +0 -0
  235. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v4/card-session.md +0 -0
  236. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v4/card.md +0 -0
  237. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v4/filesystem.md +0 -0
  238. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v4/recall.md +0 -0
  239. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v4/review.md +0 -0
  240. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v5/README.md +0 -0
  241. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v5/work-server.md +0 -0
  242. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v5/work.md +0 -0
  243. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/superpowers/plans/2026-06-19-v4-data-foundation.md +0 -0
  244. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/superpowers/plans/2026-06-19-v4-insight-rename.md +0 -0
  245. {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/superpowers/specs/2026-05-19-sync-as-settings-design.md +0 -0
  246. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/__init__.py +0 -0
  247. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/__main__.py +0 -0
  248. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/__init__.py +0 -0
  249. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/config.py +0 -0
  250. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/controllers/__init__.py +0 -0
  251. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/controllers/auth.py +0 -0
  252. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/controllers/system.py +0 -0
  253. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/controllers/users.py +0 -0
  254. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/controllers/works.py +0 -0
  255. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/envelope.py +0 -0
  256. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/gateway.py +0 -0
  257. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/layers/_spec.py +0 -0
  258. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/layers/card.py +0 -0
  259. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/layers/issue.py +0 -0
  260. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/layers/origin.py +0 -0
  261. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/main.py +0 -0
  262. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/models/__init__.py +0 -0
  263. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/models/collections.py +0 -0
  264. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/models/users.py +0 -0
  265. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/models/work.py +0 -0
  266. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/models/work_server.py +0 -0
  267. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/providers/__init__.py +0 -0
  268. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/providers/db.py +0 -0
  269. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/providers/fs.py +0 -0
  270. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/__init__.py +0 -0
  271. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/collections/catalog.py +0 -0
  272. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/collections/manager.py +0 -0
  273. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/store/__init__.py +0 -0
  274. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/users/__init__.py +0 -0
  275. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/users/repo.py +0 -0
  276. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/__init__.py +0 -0
  277. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/canvas.py +0 -0
  278. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/events.py +0 -0
  279. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/inbox.py +0 -0
  280. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/repo.py +0 -0
  281. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/rounds.py +0 -0
  282. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/sessions.py +0 -0
  283. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/tree.py +0 -0
  284. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/users.py +0 -0
  285. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/__init__.py +0 -0
  286. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/adapters/__init__.py +0 -0
  287. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/adapters/base.py +0 -0
  288. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/adapters/claude_code.py +0 -0
  289. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/adapters/codex.py +0 -0
  290. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/adapters/kimi.py +0 -0
  291. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/agent.py +0 -0
  292. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/registry.py +0 -0
  293. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/terminal.py +0 -0
  294. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/uri.py +0 -0
  295. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/work_servers/__init__.py +0 -0
  296. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/work_servers/bash.py +0 -0
  297. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/work_servers/claude.py +0 -0
  298. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/work_servers/codex.py +0 -0
  299. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/work_servers/default.py +0 -0
  300. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/work_servers/http.py +0 -0
  301. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/work_servers/kimi.py +0 -0
  302. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/cli/__init__.py +0 -0
  303. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/cli/_common.py +0 -0
  304. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/cli/collection.py +0 -0
  305. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/cli/server.py +0 -0
  306. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/cli/user.py +0 -0
  307. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/cli/work.py +0 -0
  308. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/.gitignore +0 -0
  309. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/README.md +0 -0
  310. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/apps/browser.html +0 -0
  311. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/apps/cards.html +0 -0
  312. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/apps/files.html +0 -0
  313. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/apps/issues.html +0 -0
  314. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/apps/settings.html +0 -0
  315. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/index.html +0 -0
  316. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/package.json +0 -0
  317. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/postcss.config.js +0 -0
  318. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/public/login.html +0 -0
  319. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/browser/main.tsx +0 -0
  320. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/cards/CardHistory.tsx +0 -0
  321. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/cards/CardView.tsx +0 -0
  322. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/cards/Catalog.tsx +0 -0
  323. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/cards/main.tsx +0 -0
  324. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/badge.tsx +0 -0
  325. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/button.tsx +0 -0
  326. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/card.tsx +0 -0
  327. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/dialog.tsx +0 -0
  328. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/dropdown-menu.tsx +0 -0
  329. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/input.tsx +0 -0
  330. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/label.tsx +0 -0
  331. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/sonner.tsx +0 -0
  332. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/tooltip.tsx +0 -0
  333. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/files/main.tsx +0 -0
  334. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/index.css +0 -0
  335. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/issues/IssueGraph.tsx +0 -0
  336. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/issues/IssueView.tsx +0 -0
  337. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/issues/main.tsx +0 -0
  338. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/lib/api.ts +0 -0
  339. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/lib/grid.ts +0 -0
  340. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/lib/queries.ts +0 -0
  341. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/lib/query.tsx +0 -0
  342. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/lib/store.ts +0 -0
  343. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/lib/uri.ts +0 -0
  344. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/lib/utils.ts +0 -0
  345. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/settings/main.tsx +0 -0
  346. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/shell/Dividers.tsx +0 -0
  347. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/shell/PanelView.tsx +0 -0
  348. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/shell/Shell.tsx +0 -0
  349. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/shell/TaskHeader.tsx +0 -0
  350. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/shell/TaskTree.tsx +0 -0
  351. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/shell/UrlBar.tsx +0 -0
  352. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/shell/main.tsx +0 -0
  353. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/tailwind.config.js +0 -0
  354. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/tsconfig.json +0 -0
  355. {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/vite.config.ts +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: memorytalk
3
- Version: 5.0.1
3
+ Version: 5.0.2
4
4
  Summary: memory.talk v5 — work / collections / user 三个顶层对象的工作台:跑 code agent 的 work 树,git 分层的认知层,注册的团队成员
5
5
  Project-URL: Homepage, https://github.com/memory-co/memory.talk
6
6
  Project-URL: Repository, https://github.com/memory-co/memory.talk
@@ -34,6 +34,7 @@
34
34
  | `GET` | `/api/users/me` | 我是谁:X-Memory-Talk-User 对应的 user 档案(没带 → null) |
35
35
  | `GET` | `/api/users/{name}` | 一个 user 的档案 + 建的 / 动过的 work、最近的提交 |
36
36
  | `PUT` | `/api/users/{name}` | 改档案(display_name / email) |
37
+ | `GET` | `/api/collections/config` | collections.json 本体 + 它的 git 历史(层的变化史) |
37
38
  | `GET` | `/api/collections/layers` | 有哪些层(最底在前)、各自的 schema 与行为 |
38
39
  | `POST` | `/api/collections/layers` | 加一个用户层:一份 schema YAML |
39
40
  | `GET` | `/api/collections/managed` | 某个 work 管的所有对象;不传 work = 没人管的对象 |
@@ -2,7 +2,7 @@
2
2
 
3
3
  认知层。层由 schema 定义(内置 origin / issue / card,可加用户层);对象 = 带后缀的目录 `<path>.<层>/`,放在树的任何位置;origin = 不带后缀的文件。每个写动作一个 `[层名]` 提交,落在 `layer/<层>` 上再 merge 进 `stack`;碰了别的层的路径被守卫拒绝(409 `guard`)。机制见 [designs collections.md](../../designs/v5/collections.md) / [collections-layer.md](../../designs/v5/collections-layer.md) / [manager.md](../../designs/v5/manager.md)。
4
4
 
5
- `{path:path}` 直接放在 URL 里(可含 `/` 和中文)。固定子路径(`layers` `tree` `search` `manager` `managed` `history` `act`)先于 `{layer}`。
5
+ `{path:path}` 直接放在 URL 里(可含 `/` 和中文)。固定子路径(`layers` `config` `tree` `search` `manager` `managed` `history` `act`)先于 `{layer}`。
6
6
 
7
7
  ---
8
8
 
@@ -28,15 +28,26 @@
28
28
  {"name": "decision", "schema_yaml": "layer: decision\nformat: markdown+frontmatter\ntitle: title\nfields:\n title: {type: string, required: true}\n issue: {type: ref, layer: issue}\n", "reason": ""}
29
29
  ```
30
30
 
31
- **201** 返回 LayerInfo。副作用:`schemas/decision.yaml` 进最底层(一个 `[origin]` 提交)、根上的 `layers` 文件加一行、新分支 `layer/decision` 从始祖出发。重启后仍在。已存在 → 409。类型只有 `string` `int` `bool` `"list[string]"` `ref` `"list[ref]"`(带 `[` 的要加引号)。
31
+ **201** 返回 LayerInfo。副作用:`collections.json` 的 `layers[]` 多一项(schema 内嵌、`added_at`),一个 `[origin]` 提交;新分支 `layer/decision` 从始祖出发。重启后仍在。已存在 → 409。类型只有 `string` `int` `bool` `"list[string]"` `ref` `"list[ref]"`(带 `[` 的要加引号)。
32
32
 
33
33
  ---
34
34
 
35
35
  ## 树、检索、目录
36
36
 
37
+ ### GET /api/collections/config
38
+
39
+ `collections.json` 本体 + 它的提交历史(层的变化史):
40
+
41
+ ```json
42
+ {"config": {"version": 1, "layers": [{"name": "origin", "builtin": true}, {"name": "issue", "builtin": true}, {"name": "card", "builtin": true},
43
+ {"name": "decision", "schema": {"format": "…", "fields": {…}}, "added_at": "…"}]},
44
+ "history": [{"sha": "…", "author": "alice", "date": "…", "subject": "[origin] collections: add layer decision", "body": "Reason: …"},
45
+ {"sha": "…", "subject": "[origin] collections: init", …}]}
46
+ ```
47
+
37
48
  ### GET /api/collections/tree?path=
38
49
 
39
- 浏览一个目录:对象折成一项(`kind: object`,`path` 不含后缀)、普通目录、origin 文件。`manager.json` / `layers` / `schemas/` 不列。
50
+ 浏览一个目录:对象折成一项(`kind: object`,`path` 不含后缀)、普通目录、origin 文件。`manager.json` / `collections.json` 不列。
40
51
 
41
52
  ```json
42
53
  [{"name": "配置", "path": "memory.talk/配置", "kind": "dir", "layer": null},
@@ -6,7 +6,7 @@
6
6
  - v5 collections(层即 collectbase 的 layer;Collections 是认知层的容器): [collections.md](collections.md)
7
7
  - v5 manager(任何层的任何目录都可以放 `manager.json`): [manager.md](manager.md)
8
8
  - v5 issue / card(两个内置层,照着看就是范例): [issue.md](issue.md) / [card.md](card.md)
9
- - collectbase `layers` 文件与 `cb init`(层的清单和顺序在这里): [cli.md](https://github.com/memory-co/collectbase/blob/main/docs/v2/works/cli.md)
9
+ - collectbase 的 `layers` 锚定文件(memory.talk 对应的是仓库根的 `collections.json`): [cli.md](https://github.com/memory-co/collectbase/blob/main/docs/v2/works/cli.md)
10
10
 
11
11
  ---
12
12
 
@@ -16,12 +16,12 @@
16
16
 
17
17
  | 问题 | 答案落在哪 |
18
18
  |---|---|
19
- | **叫什么** | 层名:`layers` 文件里一行、分支 `layer/<名>`、提交前缀 `[名]` |
19
+ | **叫什么** | 层名:`collections.json` 的 `layers[]` 里一项、分支 `layer/<名>`、提交前缀 `[名]` |
20
20
  | **住哪** | 路径:这个层的文件都在哪个目录下(和别的层不相交) |
21
21
  | **长什么样** | schema:一个对象是一个什么格式的文件、有哪些字段、哪个是标题、哪些是引用 |
22
- | **排在哪** | 层序:它在 `layers` 里的位置——比谁更接近记录、比谁更接近结论 |
22
+ | **排在哪** | 层序:它在 `collections.json` 的 `layers[]` 里的位置——比谁更接近记录、比谁更接近结论 |
23
23
 
24
- 落下来就是两个文件:**`layers` 里加一行**(collectbase 的事),**`schemas/<名>.yaml` 写一份**(memory.talk 的事)。不写代码。
24
+ 落下来就是**仓库根 `collections.json` 的 `layers[]` 里多一项**——名字、schema 内嵌、什么时候加的;一次最底层的提交,`git log collections.json` 就是层的变化史。不写代码。你手里写的还是一份 YAML 字段表(`memory.talk collection layers add <名> --schema <file>`),系统把它嵌进 `collections.json`。
25
25
 
26
26
  ---
27
27
 
@@ -42,7 +42,7 @@
42
42
  schema 说清一个对象是什么样的文件。最小的一份:
43
43
 
44
44
  ```yaml
45
- # schemas/decision.yaml
45
+ # 写成 YAML 交给 `collection layers add`;落进 collections.json 时就是这份的 JSON
46
46
  layer: decision
47
47
  object: <名>.decision/decision.md # 对象 = 带后缀的目录,本体文件叫 decision.md;<名> 由人起,放哪都行
48
48
  format: markdown+frontmatter # 或 json
@@ -139,15 +139,15 @@ schema: title / hypothesis / setup / result / verdict(supports | refutes |
139
139
 
140
140
  ## 6. 改层、删层
141
141
 
142
- - **改 schema**:加字段随时加(老对象没有那个字段就是空);删字段、改类型要先把老对象迁过来——那是一次 `[名]` 提交,历史里看得见。schema 文件本身也在 Collections 里(最底层,和 `layers` 一起),改它也是提交。
143
- - **加层**:`layers` 加一行 + 一份 schema;collectbase 从当前 HEAD 开分支,从此这一层的历史开始。之前的历史不受影响。
144
- - **删层**:collectbase 说层是可以停的(分支留着不动);memory.talk 侧把它从 `layers` 拿掉,通用端点就不再暴露它,文件和历史都在。**不删对象**——删了也在 git 里,但没必要。
142
+ - **改 schema**:加字段随时加(老对象没有那个字段就是空);删字段、改类型要先把老对象迁过来——那是一次 `[名]` 提交,历史里看得见。schema 就在 `collections.json` 里(最底层),改它也是提交。
143
+ - **加层**:`collections.json` 的 `layers[]` 加一项(带 schema);新分支从始祖出发,从此这一层的历史开始。之前的历史不受影响。
144
+ - **删层**:collectbase 说层是可以停的(分支留着不动);memory.talk 侧把它从 `collections.json` 拿掉,通用端点就不再暴露它,文件和历史都在。**不删对象**——删了也在 git 里,但没必要。
145
145
 
146
146
  ---
147
147
 
148
148
  ## 7. 这篇有意不定的事
149
149
 
150
- - **schema 文件放哪、归哪层**:本篇按「Collections 最底层,和 `layers` 并列」写(它是机制不是内容)。要不要单独一个 `schemas/` 目录,还是每层目录里一份 `schema.yaml`——后者「层和它的定义在一起」更好看,但底层改不动上层目录里的文件,得想清楚归属。
150
+ - ~~schema 文件放哪、归哪层~~:已定——没有单独的 schema 文件,schema 内嵌在 `collections.json` 的 `layers[]` 里,整份文件归最底层。
151
151
  - **schema 语言**:上面用的是 YAML 字段表。要不要直接用 JSON Schema(表达力强、工具多,但对人不友好)——倾向 YAML 字段表 + 少数约定,真不够再说。
152
152
  - **引用要不要校验存在**:`decision.issue` 指向一个不存在的 issue,写的时候拒绝还是放行。倾向写时校验存在、删时不级联(同 [collections.md §7](collections.md))。
153
153
  - **通用端点的形状**:`/api/collections/<层>/<id>` 一套,内置层的 `/api/issues/…` `/api/cards/…` 是不是它上面的别名。
@@ -68,7 +68,7 @@ issue 和 card **只是两个内置的 layer**。它们的对象模型([issue.md
68
68
 
69
69
  - **每个 layer 自己一条历史。** `git log layer/card` 只有卡的变化,`git log layer/issue` 只有辩论序列;`git log --first-parent stack` 是全部认知的时间线,每一行自带 `[issue]` / `[card]` 标注。裸 git 里这些要靠路径过滤去拼,而且分支上什么都混在一起。
70
70
  - **layer 与 layer 之间路径不相交,由 hook 守着。** 一个声明 `[card]` 的提交碰了某个 `.issue/` 目录里的文件,当场拒绝——包括 `--no-verify`、`reset`、`cherry-pick` 都绕不过。这就是 collectbase 说的「认知卫生」在 memory.talk 里的形态:**不会有一次提交把「争的过程」和「争完的结论」搅在一起**。
71
- - **layer 是可加的,不用改代码。** collectbase 的 `layers` 文件就是 layer 的清单;加一层 = 加一个名字。memory.talk 在这上面只多要一样东西:**schema**——这个 layer 的文件长什么样。于是「我想记一种新东西」(决策记录、实验日志、人物档案……)变成写一份 schema,而不是往 backend 里加一个包。
71
+ - **layer 是可加的,不用改代码。** collectbase 用根上的 `layers` 文件当锚定;memory.talk 对应的是根上的 **`collections.json`**——整个 collections 的配置 + `layers[]` 清单(最底在前),用户层的 schema 内嵌在自己那一项里。它被 git 追踪、归最底层,`git log collections.json` 就是层的变化史;加一层 = 这份文件多一项。于是「我想记一种新东西」(决策记录、实验日志、人物档案……)变成写一份 schema,而不是往 backend 里加一个包。
72
72
 
73
73
  一句话:**collectbase 管「层怎么在 git 里成立」,memory.talk 管「每一层里的文件是什么」。**
74
74
 
@@ -146,7 +146,7 @@ git log --first-parent stack
146
146
  | 提交信息 | `card: write …` / `issue: argue …` | `[card] write …` / `[issue] argue …`(动词不变,层名前置) |
147
147
  | 跨对象的决定 | 一个 commit | 两个相邻提交 + 同一个 `Decision:` trailer(§6) |
148
148
  | 历史 | `git log -- <path>` | 同,外加 `git log layer/<名>` 看整层 |
149
- | 加一种新对象 | 改代码 | 写一份 schema + `layers` 里加一行 |
149
+ | 加一种新对象 | 改代码 | 写一份 schema,嵌进 `collections.json` 的 `layers[]` |
150
150
  | 谁改不动谁 | 靠代码纪律 | hook 守着:上层改不动下层,跨层提交被拒 |
151
151
 
152
152
  collections-store.md 的两条原则不变:**认知层进 git,现场层用裸文件**。Collections 只是把「进 git」这一半做成了有层语义的。
@@ -107,7 +107,7 @@ manager 机制不规定动作。但把它接到 v5 已有的几条线上,会自
107
107
  | issue.md §4 派出论证 work | `positions[].spawned_works` | 不变——派出是 issue 的领域动作,不是 manager 机制的事;派出的 work 默认挂在 manager work 下 |
108
108
  | work 树的父子 | 只表达「事怎么拆」 | 同时是**隐式的 manager 链**:子的变动默认打到父 |
109
109
  | issue / card 的存储形态 | `issues/<id>.json`、`cards/**/<slug>.md`,按层分目录 | 都变成**带后缀的目录**,放哪都行:`<名>.issue/issue.json`、`<名>.card/card.md`,自己目录里可放 `manager.json`([collections.md §1](collections.md)) |
110
- | collectbase 分层 | `[issue]` / `[card]` 各自路径 | `manager.json` 是**机制文件**(同 collectbase 的 `layers`),不是证据:在 `.issue/` 里随 `[issue]` 提交,在 `.card/` 里随 `[card]` 提交,在普通文件夹里归最底层但**不受 444 保护**——memory.talk 把它登记为机制例外 |
110
+ | collectbase 分层 | `[issue]` / `[card]` 各自路径 | `manager.json` 是**机制文件**(同 `collections.json`),不是证据:在 `.issue/` 里随 `[issue]` 提交,在 `.card/` 里随 `[card]` 提交,在普通文件夹里归最底层但**不受 444 保护**——memory.talk 把它登记为机制例外 |
111
111
 
112
112
  ---
113
113
 
@@ -16,10 +16,10 @@
16
16
  HEAD → stack;工作树跟着 stack(只为了人能 ls / cat,服务从不读它)
17
17
  ```
18
18
 
19
- - **始祖** = 第一个提交,只有根上的 `layers` 文件(一行一层,最底在前)。所有分支从它出发。
19
+ - **始祖** = 第一个提交,只有根上的 `collections.json`:`{"version": 1, "layers": [{"name": "origin", "builtin": true}, …]}`,最底在前;用户层的项内嵌 `schema` 和 `added_at`。所有分支从它出发;`git log collections.json` = 层的变化史。
20
20
  - **一个动作一个提交**,信息以 `[层名]` 开头;跨层的决定是两个相邻提交 + 同一个 trailer。`git log --first-parent stack` 是全部认知的时间线;`git log layer/<层>` 是那一层的。
21
21
  - **守卫**(写时,plumbing 内):① 后缀 / 机制规则说这个路径该归哪层,和声明的层不符 → 拒;② 路径已在别的层的树里 → 拒。所以 `[card]` 提交碰不到 `.issue/` 里的东西。
22
- - **机制文件**:`layers`、`schemas/<层>.yaml` 归最底层;`manager.json` 归它所在目录按后缀规则算出的层。它们的变动不投递。
22
+ - **机制文件**:`collections.json` 归最底层;`manager.json` 归它所在目录按后缀规则算出的层。它们的变动不投递,也不出现在 tree / 目录里。
23
23
  - 全部 plumbing(hash-object / update-index / write-tree / commit-tree / update-ref),不需要工作树、不装 hook——服务进程是唯一写者。
24
24
 
25
25
  ## 对象:带后缀的目录
@@ -30,7 +30,7 @@
30
30
  | id | 文件路径 | `path`(不含后缀) | `path` | `path` |
31
31
  | 格式 | 原文 | JSON | markdown + frontmatter | schema 定 |
32
32
  | 标题 | 文件名 | `question` | `title` | schema 的 `title` |
33
- | 层序 | 0(最底) | 1 | 2 | 之上,按 `layers` 顺序 |
33
+ | 层序 | 0(最底) | 1 | 2 | 之上,按 `collections.json` 的 `layers[]` 顺序 |
34
34
 
35
35
  对象目录里还可以放 `manager.json`(谁管它)和附件。目录树按主题组织,原文、`.issue/`、`.card/` 并排。
36
36
 
@@ -122,7 +122,7 @@ frontmatter 只有 `key: value` 行;`links` 逗号分隔;空值不写。读出
122
122
 
123
123
  ### 用户层的 schema
124
124
 
125
- `schemas/<名>.yaml`,在仓库最底层:
125
+ 写成 YAML 交给 `POST /api/collections/layers`,系统把它嵌进 `collections.json` 的 `layers[]`:
126
126
 
127
127
  ```yaml
128
128
  layer: decision
@@ -6,8 +6,7 @@
6
6
  ~/.memory.talk/ ← MEMORY_TALK_HOME
7
7
  ├── collections/ ← 分层 git 仓库(认知层),见 collections.md
8
8
  │ ├── .git/ ← refs/heads/layer/{origin,issue,card,…}、refs/heads/stack;HEAD → stack
9
- │ ├── layers ← 层清单,一行一层,最底在前(始祖提交里就有)
10
- │ ├── schemas/<层>.yaml ← 用户层的 schema(最底层)
9
+ │ ├── collections.json ← 锚定:整个 collections 的配置 + layers[](最底在前,用户层内嵌 schema);始祖提交只有它;git 历史 = 层的变化史
11
10
  │ ├── manager.json ← 根:管一切(可选)
12
11
  │ └── <按主题组织的目录树>/ ← 原文、.issue/、.card/、.<用户层>/ 并排
13
12
  │ ├── manager.json ← 这一片归谁管(可选,任何目录)
@@ -39,7 +39,7 @@ memorytalk/backend/ # 服务本体;memorytalk/cli.py 是它的命令
39
39
  │ │ ├── repo.py # 分层 git(自己实现):layer/<名> 权威分支 + stack merge 视图 + 路径归属守卫;纯 plumbing
40
40
  │ │ ├── manager.py # manager.json:最近祖先解析
41
41
  │ │ ├── catalog.py # 一层的目录(按目录树列标题)+ 召回文本
42
- │ │ └── __init__.py # CollectionsService:层的装载(内置 + schemas/*.yaml)、对象 CRUD、历史、检索、树、行为、manager、投递到收件箱
42
+ │ │ └── __init__.py # CollectionsService:层的装载(内置 + collections.json 里内嵌 schema 的用户层)、对象 CRUD、历史、检索、树、行为、manager、投递到收件箱
43
43
  │ └── store/ # 装配 —— docs/designs/v5/provider.md
44
44
  │ └── __init__.py # StoreService:按 MEMORY_TALK_STORE 选 provider,按族建 work 仓储
45
45
  │
@@ -47,7 +47,7 @@ memorytalk/backend/ # 服务本体;memorytalk/cli.py 是它的命令
47
47
  │ ├── fs.py # FileSystemProvider(read/write/append/list/…,能力 local_path)+ LocalFS
48
48
  │ └── db.py # DatabaseProvider(表定义 + 链式 select/insert/update/delete,方言在内)+ SQLite
49
49
  │
50
- ├── layers/ # 每个内置 layer 一个文件;用户层来自仓库里的 schemas/<name>.yaml
50
+ ├── layers/ # 每个内置 layer 一个文件;用户层来自仓库根 collections.json 里内嵌的 schema
51
51
  │ ├── _spec.py # LayerSpec:名字 + 形态(后缀 / 本体文件 / 格式)+ schema + 行为
52
52
  │ ├── _user.py # YAML 字段表 → LayerSpec(用户层,无行为)
53
53
  │ ├── origin.py # 最底层:不带后缀的一切,原文
@@ -35,6 +35,11 @@ def add_layer(req: LayerCreate, svc: CollectionsService = Depends(collections),
35
35
  return svc.add_layer(req.name, req.schema_yaml, req.reason, c)
36
36
 
37
37
 
38
+ @router.get("/config", summary="collections.json 本体 + 它的 git 历史(层的变化史)")
39
+ def config(svc: CollectionsService = Depends(collections)) -> dict:
40
+ return {"config": svc.anchor(), "history": [r.model_dump() for r in svc.anchor_history()]}
41
+
42
+
38
43
  @router.get("/tree", response_model=list[TreeItem], summary="浏览目录树:对象(带后缀的目录折成一项)、目录、origin 文件")
39
44
  def tree(path: str = "", svc: CollectionsService = Depends(collections)):
40
45
  return svc.tree(path)
@@ -3,11 +3,11 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from ._spec import LayerSpec
6
- from ._user import from_yaml
6
+ from ._user import from_dict, from_yaml, schema_from_yaml
7
7
  from .card import LAYER as CARD
8
8
  from .issue import LAYER as ISSUE
9
9
  from .origin import LAYER as ORIGIN
10
10
 
11
11
  BUILTIN: list[LayerSpec] = [ORIGIN, ISSUE, CARD]
12
12
 
13
- __all__ = ["LayerSpec", "BUILTIN", "from_yaml"]
13
+ __all__ = ["LayerSpec", "BUILTIN", "from_yaml", "from_dict", "schema_from_yaml"]
@@ -13,9 +13,20 @@ _TYPES: dict[str, Any] = {"string": str, "int": int, "bool": bool, "ref": str,
13
13
  "list[string]": list[str], "list[ref]": list[str]}
14
14
 
15
15
 
16
- def from_yaml(text: str) -> LayerSpec:
16
+ def schema_from_yaml(text: str) -> dict:
17
17
  doc = yaml.safe_load(text) or {}
18
- name = doc["layer"]
18
+ if "layer" not in doc:
19
+ raise ValueError("schema 里要有 layer: <名字>")
20
+ return doc
21
+
22
+
23
+ def from_yaml(text: str) -> LayerSpec:
24
+ doc = schema_from_yaml(text)
25
+ return from_dict(doc["layer"], doc)
26
+
27
+
28
+ def from_dict(name: str, doc: dict) -> LayerSpec:
29
+ """collections.json 里内嵌的 schema → LayerSpec。"""
19
30
  fmt = "markdown" if str(doc.get("format", "markdown+frontmatter")).startswith("markdown") else "json"
20
31
  fields: dict[str, FieldSpec] = {}
21
32
  refs: dict[str, str] = {}
@@ -19,7 +19,7 @@ from .manager import FILE as MANAGER_FILE
19
19
  from .manager import ManagerIndex, manager_path
20
20
  from .repo import GuardError, Repo
21
21
 
22
- SCHEMAS_DIR = "schemas"
22
+ CONFIG_FILE = "collections.json"
23
23
 
24
24
 
25
25
  class CollectionsError(RuntimeError):
@@ -60,16 +60,25 @@ class CollectionsService:
60
60
  if b.name not in names:
61
61
  names.append(b.name)
62
62
  self.repo.ensure_layers(names)
63
+ cfg = self.repo.config()
63
64
  specs: dict[str, LayerSpec] = {}
64
- for name in names:
65
+ for entry in cfg["layers"]:
66
+ name = entry["name"]
65
67
  if name in builtin:
66
68
  specs[name] = builtin[name]
69
+ elif "schema" in entry:
70
+ specs[name] = layer_pkg.from_dict(name, entry["schema"])
67
71
  else:
68
- text = self.repo.read(f"{SCHEMAS_DIR}/{name}.yaml")
69
- if text is None:
70
- raise CollectionsError("bad_layer", f"层 {name} 在 layers 里,但没有 {SCHEMAS_DIR}/{name}.yaml", 500)
71
- specs[name] = layer_pkg.from_yaml(text.decode())
72
- self.layers, self.order = specs, names
72
+ raise CollectionsError("bad_layer", f"collections.json 里的层 {name} 既不是内置的,也没有 schema", 500)
73
+ self.layers, self.order = specs, [e["name"] for e in cfg["layers"]]
74
+
75
+ def anchor(self) -> dict:
76
+ """collections.json 本体。"""
77
+ return self.repo.config()
78
+
79
+ def anchor_history(self):
80
+ """collections.json 的提交历史 = 层的变化史(在最底层分支上)。"""
81
+ return self.repo.log(self.repo.layer_ref(self.order[0]), CONFIG_FILE)
73
82
 
74
83
  def layer(self, name: str) -> LayerSpec:
75
84
  try:
@@ -83,19 +92,22 @@ class CollectionsService:
83
92
  def add_layer(self, name: str, schema_yaml: str, reason: str, ctx: Ctx) -> LayerInfo:
84
93
  if name in self.layers:
85
94
  raise CollectionsError("exists", f"层已存在:{name}", 409)
86
- spec = layer_pkg.from_yaml(schema_yaml)
87
- if spec.name != name:
88
- raise CollectionsError("bad_layer", f"schema 里的 layer 是 {spec.name!r},不是 {name!r}")
89
- # schema 文件归最底层(机制,不是证据);然后重跑 init 把新层加在最上
90
- self.repo.commit(self.order[0], f"[{self.order[0]}] layer: add {name}\n\n{('Reason: ' + reason) if reason else ''}".strip(),
91
- {f"{SCHEMAS_DIR}/{name}.yaml": schema_yaml.encode()}, [], layer_of=self.layer_of_path)
92
- self.repo.ensure_layers([*self.order, name])
95
+ schema = layer_pkg.schema_from_yaml(schema_yaml)
96
+ if schema.get("layer", name) != name:
97
+ raise CollectionsError("bad_layer", f"schema 里的 layer 是 {schema.get('layer')!r},不是 {name!r}")
98
+ layer_pkg.from_dict(name, schema) # 先校验能不能解析
99
+ entry = {"name": name, "schema": {k: v for k, v in schema.items() if k != "layer"}, "added_at": _now()}
100
+ msg = f"[{self.order[0]}] collections: add layer {name}" + (f"\n\nReason: {reason}" if reason else "")
101
+ try:
102
+ self.repo.add_layer(entry, msg, author=self.author_of(ctx.user))
103
+ except GuardError as e:
104
+ raise CollectionsError("guard", str(e), e.status) from None
93
105
  self._load_layers()
94
106
  return self.layers[name].info(self.order.index(name))
95
107
 
96
108
  def layer_of_path(self, repo_path: str) -> str:
97
109
  """一个仓库路径归哪层:第一个带 `.<层>` 后缀的目录段说了算;都没有 → 最底层。"""
98
- if repo_path == "layers" or repo_path.startswith(SCHEMAS_DIR + "/"):
110
+ if repo_path == CONFIG_FILE:
99
111
  return self.order[0] # 机制文件归最底层
100
112
  for seg in repo_path.split("/"):
101
113
  for name, spec in self.layers.items():
@@ -124,7 +136,7 @@ class CollectionsService:
124
136
  spec = self.layer(layer)
125
137
  out = []
126
138
  for repo_path in self.repo.tree(prefix):
127
- if repo_path == "layers" or repo_path.startswith(SCHEMAS_DIR + "/") or repo_path.endswith(MANAGER_FILE):
139
+ if repo_path == CONFIG_FILE or repo_path.endswith(MANAGER_FILE):
128
140
  continue
129
141
  if spec.format == "raw" and self.layer_of_path(repo_path) != spec.name:
130
142
  continue
@@ -164,7 +176,7 @@ class CollectionsService:
164
176
  seen: dict[str, TreeItem] = {}
165
177
  for repo_path in self.repo.tree(prefix):
166
178
  rest = repo_path[len(prefix):].lstrip("/") if prefix else repo_path
167
- if not rest or rest in ("layers",) or rest.startswith(SCHEMAS_DIR):
179
+ if not rest or rest == CONFIG_FILE:
168
180
  continue
169
181
  head = rest.split("/", 1)[0]
170
182
  full = f"{prefix}/{head}" if prefix else head
@@ -306,7 +318,7 @@ class CollectionsService:
306
318
  """变动打到 manager work 的收件箱;没人管 → home/unmanaged.jsonl;自己造成的不投给自己。"""
307
319
  seen = set()
308
320
  for f in files:
309
- if f == MANAGER_FILE or f.endswith("/" + MANAGER_FILE) or f == "layers" or f.startswith(SCHEMAS_DIR + "/"):
321
+ if f == MANAGER_FILE or f.endswith("/" + MANAGER_FILE) or f == CONFIG_FILE:
310
322
  continue # 机制文件的变动不投递
311
323
  m = self.managers.resolve(f)
312
324
  spec = self.layers[layer]
@@ -12,6 +12,7 @@
12
12
  """
13
13
  from __future__ import annotations
14
14
 
15
+ import json
15
16
  import os
16
17
  import subprocess
17
18
  import tempfile
@@ -21,7 +22,11 @@ from pathlib import Path
21
22
 
22
23
  from memorytalk.backend.models.collections import Revision
23
24
 
24
- ANCHOR = "layers" # 根上的层清单:一行一个,最底在前
25
+
26
+ def _dump(cfg: dict) -> bytes:
27
+ return (json.dumps(cfg, ensure_ascii=False, indent=2) + "\n").encode()
28
+
29
+ ANCHOR = "collections.json" # 根上的配置:整个 collections 的配置 + 层清单(最底在前);git 历史 = 层的变化史
25
30
 
26
31
 
27
32
  class GuardError(RuntimeError):
@@ -129,18 +134,23 @@ class Repo:
129
134
  sha = self._git("rev-list", "--max-parents=0", self.stack, check=False).split()
130
135
  return sha[0] if sha else None
131
136
 
132
- def layers(self) -> list[str] | None:
137
+ def config(self) -> dict | None:
138
+ """collections.json(从 stack 树里读,不读工作区)。"""
133
139
  if self.resolve(self.stack) is None:
134
140
  return None
135
141
  data = self.read(ANCHOR)
136
- return [l.strip() for l in data.decode().splitlines() if l.strip()] if data else None
142
+ return json.loads(data) if data else None
143
+
144
+ def layers(self) -> list[str] | None:
145
+ cfg = self.config()
146
+ return [l["name"] for l in cfg["layers"]] if cfg else None
137
147
 
138
148
  def ensure_layers(self, names: list[str]) -> None:
139
- """无则建拓扑;有则把缺的层补上(新层分支从始祖出发,layers 文件在最底层更新)。"""
149
+ """无则建拓扑;有则把缺的内置层补上(新层分支从始祖出发,collections.json 在最底层更新)。"""
140
150
  cur = self.layers()
141
151
  if cur is None:
142
- text = "\n".join(names) + "\n"
143
- tree = self.write_tree({ANCHOR: Entry("100644", self.hash_object(text.encode()), ANCHOR)})
152
+ cfg = {"version": 1, "layers": [{"name": n, "builtin": True} for n in names]}
153
+ tree = self.write_tree({ANCHOR: Entry("100644", self.hash_object(_dump(cfg)), ANCHOR)})
144
154
  start = self.commit_tree(tree, [], f"[{names[0]}] collections: init\n\nlayers: {', '.join(names)}")
145
155
  for n in names:
146
156
  self.update_ref(self.layer_ref(n), start)
@@ -155,9 +165,20 @@ class Repo:
155
165
  for n in missing:
156
166
  if self.resolve(self.layer_ref(n)) is None:
157
167
  self.update_ref(self.layer_ref(n), start)
158
- new = [*cur, *missing]
168
+ cfg = self.config()
169
+ cfg["layers"] += [{"name": n, "builtin": True} for n in missing]
159
170
  self.commit(cur[0], f"[{cur[0]}] collections: add layers {', '.join(missing)}",
160
- {ANCHOR: ("\n".join(new) + "\n").encode()}, [], layer_of=lambda p: cur[0])
171
+ {ANCHOR: _dump(cfg)}, [], layer_of=lambda p: cur[0])
172
+
173
+ def add_layer(self, entry: dict, message: str, author=None) -> None:
174
+ """在 collections.json 的 layers[] 末尾加一层(最上),并从始祖开一条分支。"""
175
+ cfg = self.config()
176
+ cfg["layers"].append(entry)
177
+ start = self.anchor()
178
+ if self.resolve(self.layer_ref(entry["name"])) is None:
179
+ self.update_ref(self.layer_ref(entry["name"]), start)
180
+ bottom = cfg["layers"][0]["name"]
181
+ self.commit(bottom, message, {ANCHOR: _dump(cfg)}, [], layer_of=lambda p: bottom, author=author)
161
182
 
162
183
  # ------------------------------------------------------------ 归属
163
184
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "memorytalk"
7
- version = "5.0.1"
7
+ version = "5.0.2"
8
8
  description = "memory.talk v5 — work / collections / user 三个顶层对象的工作台:跑 code agent 的 work 树,git 分层的认知层,注册的团队成员"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -0,0 +1,19 @@
1
+ # tests
2
+
3
+ **场景化**:每个目录一个场景,自带 `README.md`(在测什么 / 不在这测什么 / fixture 来源)和 `test.py`;test.py 里每个函数只断言一件事,函数名就是结论。目录按层分:`providers/` `collections/` `works/` `work_servers/` `adapters/` `users/` `cli/`。
4
+
5
+ ```
6
+ pip install -e ".[dev]" && pytest # 全部
7
+ pytest tests/collections/layer_guard # 单个场景
8
+ ```
9
+
10
+ ## 公共 fixture(`conftest.py`)
11
+
12
+ | fixture | 给什么 |
13
+ |---|---|
14
+ | `home` | 临时 `MEMORY_TALK_HOME` / workspace / 各平台会话记录根 / 独立 tmux socket;**按 `fs` 和 `sqlite` 两种 store 各跑一遍**(参数化) |
15
+ | `client` | 直连 ASGI 的 `TestClient`;已注册 `alice` / `bob` / `carol`;`.json()` 解掉响应信封(成功给 `data`,出错给整个信封) |
16
+ | `svc` | `client.app.state`:`collections` / `works` / `users` / `work_servers` / `store`,给要直接碰服务层的场景 |
17
+ | `H(user)` | 返回带 `X-Memory-Talk-User` 的 headers 的小函数 |
18
+
19
+ 需要 tmux 的场景标了 `needs_tmux`,机器上没有就跳过。
@@ -0,0 +1,2 @@
1
+ """场景共用的小工具(conftest 里的函数导出一份,避免 import conftest)。"""
2
+ from tests.conftest import git_authors, git_log # noqa: F401
@@ -0,0 +1,12 @@
1
+ # adapters / claude_code — agent 把手读 Claude Code 的会话记录
2
+
3
+ ## 这个场景在测什么
4
+ `claude://<cwd>` 的会话是终端 + 把手多一项 `rounds`:按 cwd 编码定位 `~/.claude/projects/<cwd>/*.jsonl`,
5
+ 只认成员创建之后出现的记录;user / assistant 消息解析成 round(tool_result → tool,isMeta → system,sidechain 跳过);
6
+ `GET …/rounds` 先同步再读,append-only、按 uuid 去重、增量追加。
7
+
8
+ ## 不在这测什么
9
+ - Codex / Kimi 的格式 → 各自场景
10
+
11
+ ## fixture 来源
12
+ `client`、`home`;PATH 里放一个假 `claude`(只要 tmux 能起);`needs_tmux`。
@@ -0,0 +1,65 @@
1
+ """adapters/claude_code -- rounds from ~/.claude/projects. See README.md."""
2
+ import json
3
+ import os
4
+ import time
5
+
6
+ import pytest
7
+
8
+ from tests.conftest import needs_tmux
9
+
10
+ pytestmark = needs_tmux
11
+
12
+
13
+ @pytest.fixture
14
+ def agent(client, home, monkeypatch):
15
+ bindir = home / "bin"; bindir.mkdir()
16
+ fake = bindir / "claude"; fake.write_text("#!/bin/sh\nsleep 60\n"); fake.chmod(0o755)
17
+ monkeypatch.setenv("PATH", f"{bindir}:{os.environ['PATH']}")
18
+ w = client.post("/api/works", json={"goal": "让 agent 干活"}).json()
19
+ proj = home / "ws" / "proj"; proj.mkdir(parents=True)
20
+ s = client.post(f"/api/works/{w['id']}/sessions", json={"uri": f"claude://{proj}"}).json()
21
+ time.sleep(0.05)
22
+ d = home / "claude" / str(proj).replace("/", "-"); d.mkdir(parents=True)
23
+ return w, s, proj, d / "sess.jsonl"
24
+
25
+
26
+ ROWS = [
27
+ {"type": "user", "uuid": "u1", "timestamp": "2026-09-05T10:00:00Z", "message": {"content": [{"type": "text", "text": "把配置改成环境变量"}]}},
28
+ {"type": "assistant", "uuid": "a1", "message": {"content": [{"type": "text", "text": "好"}, {"type": "tool_use", "name": "Edit", "input": {"f": "config.py"}}]}},
29
+ {"type": "user", "uuid": "u2", "toolUseResult": {}, "message": {"content": [{"type": "tool_result", "content": "ok"}]}},
30
+ {"type": "user", "uuid": "u3", "isMeta": True, "message": {"content": "caveat"}},
31
+ {"type": "user", "uuid": "u4", "isSidechain": True, "message": {"content": "旁支"}},
32
+ ]
33
+
34
+
35
+ def _write(path, rows, mode="w"):
36
+ with open(path, mode) as f:
37
+ f.write("".join(json.dumps(r) + "\n" for r in rows))
38
+
39
+
40
+ def test_agent_session_has_rounds_capability(agent):
41
+ _, s, _, _ = agent
42
+ assert s["scheme"] == "claude" and "rounds" in s["handle"]["capabilities"]
43
+
44
+
45
+ def test_no_transcript_yet_means_no_rounds(client, agent):
46
+ w, s, _, _ = agent
47
+ assert client.get(f"/api/works/{w['id']}/sessions/{s['id']}/rounds").json() == []
48
+
49
+
50
+ def test_roles_are_classified_and_sidechain_skipped(client, agent):
51
+ w, s, _, path = agent
52
+ _write(path, ROWS)
53
+ rounds = client.get(f"/api/works/{w['id']}/sessions/{s['id']}/rounds").json()
54
+ assert [(r["id"], r["role"]) for r in rounds] == [("u1", "human"), ("a1", "assistant"), ("u2", "tool"), ("u3", "system")]
55
+ assert "[Edit]" in rounds[1]["text"]
56
+
57
+
58
+ def test_rounds_are_deduplicated_and_appended(client, agent, svc):
59
+ w, s, _, path = agent
60
+ _write(path, ROWS)
61
+ client.get(f"/api/works/{w['id']}/sessions/{s['id']}/rounds")
62
+ assert len(client.get(f"/api/works/{w['id']}/sessions/{s['id']}/rounds").json()) == 4 # 再读不重复
63
+ _write(path, [{"type": "assistant", "uuid": "a2", "message": {"content": [{"type": "text", "text": "改完了"}]}}], "a")
64
+ assert client.get(f"/api/works/{w['id']}/sessions/{s['id']}/rounds").json()[-1]["id"] == "a2"
65
+ assert len(svc.works.repo.read(w["id"], "rounds", sub=s["id"])) == 5 # append-only 的流
@@ -0,0 +1,8 @@
1
+ # adapters / codex — 读 Codex 的 rollout 记录
2
+
3
+ ## 这个场景在测什么
4
+ `CodexAdapter`:按 `session_meta.cwd` 匹配工作目录找到 `rollout-*.jsonl`;`user_message` / `agent_message` / `function_call` /
5
+ `function_call_output` 解析成 round,`task_started` 之类的控制事件跳过。纯解析,不起 tmux。
6
+
7
+ ## fixture 来源
8
+ `home`(临时的 codex 记录根)。
@@ -0,0 +1,34 @@
1
+ """adapters/codex -- rollout parsing. See README.md."""
2
+ import json
3
+ from pathlib import Path
4
+
5
+ from memorytalk.backend.services.work_servers.adapters import CodexAdapter
6
+
7
+ ROWS = [
8
+ {"type": "session_meta", "payload": {"cwd": "/w/p"}},
9
+ {"type": "event_msg", "timestamp": "t1", "payload": {"type": "user_message", "message": "hi"}},
10
+ {"type": "event_msg", "timestamp": "t2", "payload": {"type": "task_started"}},
11
+ {"type": "response_item", "timestamp": "t3", "payload": {"type": "function_call", "name": "shell", "arguments": "ls"}},
12
+ {"type": "response_item", "timestamp": "t4", "payload": {"type": "function_call_output", "output": "a b"}},
13
+ {"type": "event_msg", "timestamp": "t5", "payload": {"type": "agent_message", "message": "done"}},
14
+ ]
15
+
16
+
17
+ def _rollout(home):
18
+ root = home / "codex" / "2026" / "09" / "05"; root.mkdir(parents=True)
19
+ p = root / "rollout-2026-09-05T10-00-00-abc.jsonl"
20
+ p.write_text("".join(json.dumps(r) + "\n" for r in ROWS))
21
+ return p
22
+
23
+
24
+ def test_find_matches_by_cwd(home):
25
+ p = _rollout(home)
26
+ ad = CodexAdapter(home / "codex")
27
+ assert ad.find(Path("/w/p"), 0) == p
28
+ assert ad.find(Path("/other"), 0) is None
29
+
30
+
31
+ def test_rounds_keep_conversation_and_tools_skip_control_events(home):
32
+ p = _rollout(home)
33
+ assert [(r.role, r.text) for r in CodexAdapter(home / "codex").rounds(p)] == [
34
+ ("human", "hi"), ("assistant", "[shell] ls"), ("tool", "[result] a b"), ("assistant", "done")]
@@ -0,0 +1,8 @@
1
+ # adapters / kimi — 读 Kimi Code 的 wire 记录
2
+
3
+ ## 这个场景在测什么
4
+ `KimiAdapter`:`~/.kimi-code/sessions/wd_*/session_*/state.json` 的 `workDir` 匹配工作目录,记录在 `agents/main/wire.jsonl`;
5
+ `turn.prompt` → human,loop event 里 `content.part`(text / think)→ assistant,`tool.call` / `tool.result` → 工具调用与结果。
6
+
7
+ ## fixture 来源
8
+ `home`(临时的 kimi 记录根)。