memorytalk 5.0.2__tar.gz → 5.0.4__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 (353) hide show
  1. {memorytalk-5.0.2 → memorytalk-5.0.4}/PKG-INFO +1 -1
  2. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v5/README.md +1 -1
  3. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v5/README.md +1 -0
  4. memorytalk-5.0.4/memorytalk/__init__.py +21 -0
  5. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/README.md +1 -1
  6. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/controllers/collections.py +31 -28
  7. memorytalk-5.0.4/memorytalk/backend/controllers/system.py +18 -0
  8. memorytalk-5.0.4/memorytalk/backend/controllers/users.py +39 -0
  9. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/controllers/works.py +38 -36
  10. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/main.py +4 -5
  11. memorytalk-5.0.4/memorytalk/backend/models/result.py +30 -0
  12. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/cli/__init__.py +5 -0
  13. {memorytalk-5.0.2 → memorytalk-5.0.4}/pyproject.toml +1 -1
  14. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/conftest.py +1 -1
  15. memorytalk-5.0.2/memorytalk/backend/controllers/system.py +0 -17
  16. memorytalk-5.0.2/memorytalk/backend/controllers/users.py +0 -38
  17. memorytalk-5.0.2/memorytalk/backend/envelope.py +0 -44
  18. memorytalk-5.0.2/memorytalk/backend/services/__init__.py +0 -0
  19. {memorytalk-5.0.2 → memorytalk-5.0.4}/.github/workflows/test.yml +0 -0
  20. {memorytalk-5.0.2 → memorytalk-5.0.4}/.gitignore +0 -0
  21. {memorytalk-5.0.2 → memorytalk-5.0.4}/LICENSE +0 -0
  22. {memorytalk-5.0.2 → memorytalk-5.0.4}/README.md +0 -0
  23. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v1/README.md +0 -0
  24. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v1/cards.md +0 -0
  25. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v1/links.md +0 -0
  26. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v1/recall.md +0 -0
  27. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v1/sessions.md +0 -0
  28. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v1/status.md +0 -0
  29. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/README.md +0 -0
  30. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/cards.md +0 -0
  31. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/links.md +0 -0
  32. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/log.md +0 -0
  33. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/rebuild.md +0 -0
  34. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/search.md +0 -0
  35. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/sessions.md +0 -0
  36. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/status.md +0 -0
  37. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/tags.md +0 -0
  38. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/view.md +0 -0
  39. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/README.md +0 -0
  40. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/cards.md +0 -0
  41. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/embedding.md +0 -0
  42. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/explore.md +0 -0
  43. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/read.md +0 -0
  44. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/recall.md +0 -0
  45. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/reviews.md +0 -0
  46. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/search.md +0 -0
  47. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/sessions.md +0 -0
  48. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/status.md +0 -0
  49. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/sync.md +0 -0
  50. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/README.md +0 -0
  51. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/card-links.md +0 -0
  52. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/card-sessions.md +0 -0
  53. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/cards.md +0 -0
  54. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/read.md +0 -0
  55. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/recall.md +0 -0
  56. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/reviews.md +0 -0
  57. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/search.md +0 -0
  58. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v5/collections.md +0 -0
  59. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v5/system.md +0 -0
  60. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v5/users.md +0 -0
  61. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v5/works.md +0 -0
  62. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/README.md +0 -0
  63. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/card.md +0 -0
  64. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/link.md +0 -0
  65. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/rebuild.md +0 -0
  66. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/recall.md +0 -0
  67. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/search.md +0 -0
  68. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/server.md +0 -0
  69. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/session.md +0 -0
  70. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/sync.md +0 -0
  71. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/README.md +0 -0
  72. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/card.md +0 -0
  73. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/explore.md +0 -0
  74. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/filter.md +0 -0
  75. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/link.md +0 -0
  76. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/log.md +0 -0
  77. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/rebuild.md +0 -0
  78. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/recall.md +0 -0
  79. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/review.md +0 -0
  80. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/search.md +0 -0
  81. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/server.md +0 -0
  82. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/setup.md +0 -0
  83. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/sync.md +0 -0
  84. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/tag.md +0 -0
  85. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/view.md +0 -0
  86. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/README.md +0 -0
  87. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/card.md +0 -0
  88. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/explore.md +0 -0
  89. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/read.md +0 -0
  90. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/recall.md +0 -0
  91. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/review.md +0 -0
  92. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/search.md +0 -0
  93. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/session.md +0 -0
  94. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/setup.md +0 -0
  95. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/sync.md +0 -0
  96. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/upgrade.md +0 -0
  97. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v4/README.md +0 -0
  98. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v4/card.md +0 -0
  99. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v4/insight.md +0 -0
  100. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v4/read.md +0 -0
  101. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v4/recall.md +0 -0
  102. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v4/search.md +0 -0
  103. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v5/collection.md +0 -0
  104. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v5/server.md +0 -0
  105. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v5/user.md +0 -0
  106. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v5/work.md +0 -0
  107. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/README.md +0 -0
  108. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/card-creation-flow.md +0 -0
  109. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/card-deletion-flow.md +0 -0
  110. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/codex-trust-flow.md +0 -0
  111. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/dsl.md +0 -0
  112. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/explore-cwd-suppression.md +0 -0
  113. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/explore.md +0 -0
  114. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/file-canonical-pattern.md +0 -0
  115. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/forum-dynamics.md +0 -0
  116. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/hook-installation.md +0 -0
  117. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/index-backfill.md +0 -0
  118. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/migration.md +0 -0
  119. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/read-side-effects.md +0 -0
  120. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/recall-pipeline.md +0 -0
  121. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/review-impact.md +0 -0
  122. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/search-ranking.md +0 -0
  123. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/searchbase-extraction.md +0 -0
  124. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/session-namespace.md +0 -0
  125. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/session-rounds-write.md +0 -0
  126. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/sync-pipeline.md +0 -0
  127. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v4/README.md +0 -0
  128. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v4/card.md +0 -0
  129. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v4/insight-migration.md +0 -0
  130. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v4/session-annotation.md +0 -0
  131. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/README.md +0 -0
  132. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/card.md +0 -0
  133. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/collections-layer.md +0 -0
  134. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/collections-store.md +0 -0
  135. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/collections.md +0 -0
  136. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/issue.md +0 -0
  137. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/manager.md +0 -0
  138. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/origin.md +0 -0
  139. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/provider.md +0 -0
  140. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/session.md +0 -0
  141. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/user.md +0 -0
  142. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/work-server.md +0 -0
  143. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/work.md +0 -0
  144. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/report/2026-05-21-search-noisy-or-aggregation-bug.md +0 -0
  145. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/report/2026-05-23-claude-code-adapter-role-misclassification.md +0 -0
  146. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/report/2026-05-23-search-linear-combination-regression.md +0 -0
  147. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/report/2026-05-23-search-vector-index-batch-gap.md +0 -0
  148. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v1/link.md +0 -0
  149. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v1/session.md +0 -0
  150. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v1/settings.md +0 -0
  151. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v1/talk-card.md +0 -0
  152. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v2/link.md +0 -0
  153. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v2/search-result.md +0 -0
  154. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v2/session.md +0 -0
  155. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v2/settings.md +0 -0
  156. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v2/tag.md +0 -0
  157. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v2/talk-card.md +0 -0
  158. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/README.md +0 -0
  159. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/filesystem.md +0 -0
  160. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/recall.md +0 -0
  161. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/review.md +0 -0
  162. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/search-result.md +0 -0
  163. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/session.md +0 -0
  164. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/settings.md +0 -0
  165. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/talk-card.md +0 -0
  166. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v4/README.md +0 -0
  167. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v4/card-link.md +0 -0
  168. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v4/card-session.md +0 -0
  169. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v4/card.md +0 -0
  170. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v4/filesystem.md +0 -0
  171. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v4/recall.md +0 -0
  172. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v4/review.md +0 -0
  173. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v5/README.md +0 -0
  174. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v5/collections.md +0 -0
  175. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v5/filesystem.md +0 -0
  176. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v5/work-server.md +0 -0
  177. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v5/work.md +0 -0
  178. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/superpowers/plans/2026-06-19-v4-data-foundation.md +0 -0
  179. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/superpowers/plans/2026-06-19-v4-insight-rename.md +0 -0
  180. {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/superpowers/specs/2026-05-19-sync-as-settings-design.md +0 -0
  181. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/__main__.py +0 -0
  182. {memorytalk-5.0.2/memorytalk → memorytalk-5.0.4/memorytalk/backend}/__init__.py +0 -0
  183. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/config.py +0 -0
  184. {memorytalk-5.0.2/memorytalk/backend → memorytalk-5.0.4/memorytalk/backend/controllers}/__init__.py +0 -0
  185. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/controllers/auth.py +0 -0
  186. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/gateway.py +0 -0
  187. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/layers/__init__.py +0 -0
  188. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/layers/_spec.py +0 -0
  189. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/layers/_user.py +0 -0
  190. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/layers/card.py +0 -0
  191. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/layers/issue.py +0 -0
  192. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/layers/origin.py +0 -0
  193. {memorytalk-5.0.2/memorytalk/backend/controllers → memorytalk-5.0.4/memorytalk/backend/models}/__init__.py +0 -0
  194. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/models/collections.py +0 -0
  195. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/models/users.py +0 -0
  196. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/models/work.py +0 -0
  197. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/models/work_server.py +0 -0
  198. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/providers/__init__.py +0 -0
  199. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/providers/db.py +0 -0
  200. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/providers/fs.py +0 -0
  201. {memorytalk-5.0.2/memorytalk/backend/models → memorytalk-5.0.4/memorytalk/backend/services}/__init__.py +0 -0
  202. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/collections/__init__.py +0 -0
  203. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/collections/catalog.py +0 -0
  204. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/collections/manager.py +0 -0
  205. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/collections/repo.py +0 -0
  206. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/store/__init__.py +0 -0
  207. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/users/__init__.py +0 -0
  208. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/users/repo.py +0 -0
  209. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/__init__.py +0 -0
  210. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/canvas.py +0 -0
  211. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/events.py +0 -0
  212. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/inbox.py +0 -0
  213. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/repo.py +0 -0
  214. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/rounds.py +0 -0
  215. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/sessions.py +0 -0
  216. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/tree.py +0 -0
  217. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/users.py +0 -0
  218. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/__init__.py +0 -0
  219. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/adapters/__init__.py +0 -0
  220. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/adapters/base.py +0 -0
  221. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/adapters/claude_code.py +0 -0
  222. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/adapters/codex.py +0 -0
  223. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/adapters/kimi.py +0 -0
  224. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/agent.py +0 -0
  225. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/registry.py +0 -0
  226. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/terminal.py +0 -0
  227. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/uri.py +0 -0
  228. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/work_servers/__init__.py +0 -0
  229. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/work_servers/bash.py +0 -0
  230. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/work_servers/claude.py +0 -0
  231. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/work_servers/codex.py +0 -0
  232. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/work_servers/default.py +0 -0
  233. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/work_servers/http.py +0 -0
  234. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/work_servers/kimi.py +0 -0
  235. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/cli/_common.py +0 -0
  236. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/cli/collection.py +0 -0
  237. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/cli/server.py +0 -0
  238. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/cli/user.py +0 -0
  239. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/cli/work.py +0 -0
  240. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/.gitignore +0 -0
  241. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/README.md +0 -0
  242. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/apps/browser.html +0 -0
  243. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/apps/cards.html +0 -0
  244. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/apps/files.html +0 -0
  245. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/apps/issues.html +0 -0
  246. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/apps/settings.html +0 -0
  247. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/index.html +0 -0
  248. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/package.json +0 -0
  249. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/postcss.config.js +0 -0
  250. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/public/login.html +0 -0
  251. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/browser/main.tsx +0 -0
  252. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/cards/CardHistory.tsx +0 -0
  253. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/cards/CardView.tsx +0 -0
  254. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/cards/Catalog.tsx +0 -0
  255. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/cards/main.tsx +0 -0
  256. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/badge.tsx +0 -0
  257. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/button.tsx +0 -0
  258. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/card.tsx +0 -0
  259. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/dialog.tsx +0 -0
  260. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/dropdown-menu.tsx +0 -0
  261. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/input.tsx +0 -0
  262. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/label.tsx +0 -0
  263. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/sonner.tsx +0 -0
  264. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/tooltip.tsx +0 -0
  265. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/files/main.tsx +0 -0
  266. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/index.css +0 -0
  267. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/issues/IssueGraph.tsx +0 -0
  268. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/issues/IssueView.tsx +0 -0
  269. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/issues/main.tsx +0 -0
  270. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/lib/api.ts +0 -0
  271. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/lib/grid.ts +0 -0
  272. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/lib/queries.ts +0 -0
  273. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/lib/query.tsx +0 -0
  274. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/lib/store.ts +0 -0
  275. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/lib/uri.ts +0 -0
  276. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/lib/utils.ts +0 -0
  277. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/settings/main.tsx +0 -0
  278. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/shell/Dividers.tsx +0 -0
  279. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/shell/PanelView.tsx +0 -0
  280. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/shell/Shell.tsx +0 -0
  281. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/shell/TaskHeader.tsx +0 -0
  282. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/shell/TaskTree.tsx +0 -0
  283. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/shell/UrlBar.tsx +0 -0
  284. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/shell/main.tsx +0 -0
  285. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/tailwind.config.js +0 -0
  286. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/tsconfig.json +0 -0
  287. {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/vite.config.ts +0 -0
  288. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/README.md +0 -0
  289. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/_util.py +0 -0
  290. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/adapters/claude_code/README.md +0 -0
  291. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/adapters/claude_code/test.py +0 -0
  292. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/adapters/codex/README.md +0 -0
  293. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/adapters/codex/test.py +0 -0
  294. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/adapters/kimi/README.md +0 -0
  295. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/adapters/kimi/test.py +0 -0
  296. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/cli/end_to_end/README.md +0 -0
  297. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/cli/end_to_end/test.py +0 -0
  298. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/config/README.md +0 -0
  299. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/config/test.py +0 -0
  300. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/decide_and_discuss/README.md +0 -0
  301. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/decide_and_discuss/test.py +0 -0
  302. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/history/README.md +0 -0
  303. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/history/test.py +0 -0
  304. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/inbox_delivery/README.md +0 -0
  305. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/inbox_delivery/test.py +0 -0
  306. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/issue_behaviors/README.md +0 -0
  307. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/issue_behaviors/test.py +0 -0
  308. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/layer_guard/README.md +0 -0
  309. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/layer_guard/test.py +0 -0
  310. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/layers/README.md +0 -0
  311. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/layers/test.py +0 -0
  312. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/manager/README.md +0 -0
  313. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/manager/test.py +0 -0
  314. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/objects/README.md +0 -0
  315. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/objects/test.py +0 -0
  316. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/tree_and_search/README.md +0 -0
  317. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/tree_and_search/test.py +0 -0
  318. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/user_layer/README.md +0 -0
  319. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/user_layer/test.py +0 -0
  320. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/providers/local_fs/README.md +0 -0
  321. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/providers/local_fs/test.py +0 -0
  322. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/providers/sqlite_builder/README.md +0 -0
  323. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/providers/sqlite_builder/test.py +0 -0
  324. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/activity/README.md +0 -0
  325. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/activity/test.py +0 -0
  326. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/commit_author/README.md +0 -0
  327. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/commit_author/test.py +0 -0
  328. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/identity_header/README.md +0 -0
  329. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/identity_header/test.py +0 -0
  330. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/register/README.md +0 -0
  331. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/register/test.py +0 -0
  332. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/work_ownership/README.md +0 -0
  333. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/work_ownership/test.py +0 -0
  334. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/bash_session/README.md +0 -0
  335. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/bash_session/test.py +0 -0
  336. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/default_session/README.md +0 -0
  337. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/default_session/test.py +0 -0
  338. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/freeze/README.md +0 -0
  339. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/freeze/test.py +0 -0
  340. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/http_session/README.md +0 -0
  341. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/http_session/test.py +0 -0
  342. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/registry/README.md +0 -0
  343. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/registry/test.py +0 -0
  344. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/canvas/README.md +0 -0
  345. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/canvas/test.py +0 -0
  346. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/events_and_inbox/README.md +0 -0
  347. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/events_and_inbox/test.py +0 -0
  348. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/recall/README.md +0 -0
  349. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/recall/test.py +0 -0
  350. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/status/README.md +0 -0
  351. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/status/test.py +0 -0
  352. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/tree/README.md +0 -0
  353. {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/tree/test.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: memorytalk
3
- Version: 5.0.2
3
+ Version: 5.0.4
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
@@ -56,7 +56,7 @@
56
56
 
57
57
  ## 通用约定
58
58
 
59
- - **响应信封**:所有 `/api/*` 的响应都是 **`{"data": …, "message": "ok"}`**——分页面里写的响应体是 `data` 那一半。纯文本端点(recall / capture)的 `data` 是那段字符串;删除类端点返回 `200`,`data` 为 `null`(不再有 204)。
59
+ - **响应信封**:所有 `/api/*` 端点的 `response_model` 都是 **`Result[T]`** = **`{"data": T, "message": "ok"}`**(OpenAPI 里能看到 `Result_User_` 这类 schema)——分页面里写的响应体是 `data` 那一半。纯文本端点(recall / capture)的 `data` 是那段字符串;删除类端点返回 `200`,`data` 为 `null`(不再有 204)。
60
60
  - **错误体**:`{"data": null, "error": "<机器码>", "message": "<人读>"}`。
61
61
 
62
62
  | 状态 | `error` | 何时 |
@@ -8,6 +8,7 @@
8
8
 
9
9
  ```
10
10
  memory.talk
11
+ ├── version # 版本号(也可 -V / --version)
11
12
  ├── server start | stop | restart | status # 本地 API 服务(后台守护)
12
13
  ├── work create | list | show | set # work 树
13
14
  │ attach | sessions | detach | capture | rounds # 会话(现场)
@@ -0,0 +1,21 @@
1
+ """memory.talk —— 跑 code agent 的工作台,记忆是它的副产物。"""
2
+ from importlib.metadata import PackageNotFoundError, version as _version
3
+ from pathlib import Path
4
+
5
+
6
+ def _from_pyproject() -> str:
7
+ """没安装、直接从源码跑时,读仓库根 pyproject.toml 的 version。"""
8
+ try:
9
+ import tomllib
10
+ with open(Path(__file__).resolve().parents[1] / "pyproject.toml", "rb") as f:
11
+ return tomllib.load(f)["project"]["version"] + "+src"
12
+ except Exception:
13
+ return "0.0.0+src"
14
+
15
+
16
+ try:
17
+ __version__ = _version("memorytalk")
18
+ except PackageNotFoundError:
19
+ __version__ = _from_pyproject()
20
+
21
+ __all__ = ["__version__"]
@@ -7,9 +7,9 @@ memorytalk/backend/ # 服务本体;memorytalk/cli.py 是它的命令
7
7
  ├── main.py # FastAPI 实例、路由挂载、启动钩子
8
8
  ├── config.py # 环境变量与路径(~/.memory.talk/{memory,works})
9
9
  ├── gateway.py # AuthGate + 静态托管 + 反代(/tty、/proxy/<port>)
10
- ├── envelope.py # 响应信封中间件:所有 /api/* → {"data", "message"[, "error"]}
11
10
  │
12
11
  ├── models/ # 数据模型(纯结构,不含 IO)
12
+ │ ├── result.py # Result[T]:统一响应信封 {data, message[, error]},每个端点的 response_model
13
13
  │ ├── users.py # User(档案,存)/ UserView / UserProfile(带派生统计)
14
14
  │ ├── work.py # Work 节点(目标、created_by、状态、父子)、Canvas、Session、WorkUser、Round、Event
15
15
  │ ├── collections.py # LayerInfo / Obj / Revision / SearchHit / Catalog / Tree / Manager / InboxItem
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
 
4
4
  from typing import Any
5
5
 
6
+ from memorytalk.backend.models.result import Result, ok
6
7
  from fastapi import APIRouter, Depends, Header, Query, Request
7
8
 
8
9
  from memorytalk.backend.models.collections import (CatalogDir, InboxItem, LayerCreate, LayerInfo, Manager, ManagerPut, Obj,
@@ -25,91 +26,93 @@ def ctx(request: Request, x_memory_talk_user: str | None = Header(None, alias="X
25
26
 
26
27
  # ---- 固定路径先于 /{layer} ----
27
28
 
28
- @router.get("/layers", response_model=list[LayerInfo], summary="有哪些层(最底在前)、各自的 schema 与行为")
29
+ @router.get("/layers", response_model=Result[list[LayerInfo]], summary="有哪些层(最底在前)、各自的 schema 与行为")
29
30
  def layers(svc: CollectionsService = Depends(collections)):
30
- return svc.layer_infos()
31
+ return ok(svc.layer_infos())
31
32
 
32
33
 
33
- @router.post("/layers", response_model=LayerInfo, status_code=201, summary="加一个用户层:一份 schema YAML")
34
+ @router.post("/layers", response_model=Result[LayerInfo], status_code=201, summary="加一个用户层:一份 schema YAML")
34
35
  def add_layer(req: LayerCreate, svc: CollectionsService = Depends(collections), c: Ctx = Depends(ctx)):
35
- return svc.add_layer(req.name, req.schema_yaml, req.reason, c)
36
+ return ok(svc.add_layer(req.name, req.schema_yaml, req.reason, c))
36
37
 
37
38
 
38
- @router.get("/config", summary="collections.json 本体 + 它的 git 历史(层的变化史)")
39
+ @router.get("/config", summary="collections.json 本体 + 它的 git 历史(层的变化史)", response_model=Result[dict])
39
40
  def config(svc: CollectionsService = Depends(collections)) -> dict:
40
- return {"config": svc.anchor(), "history": [r.model_dump() for r in svc.anchor_history()]}
41
+ return ok({"config": svc.anchor(), "history": [r.model_dump() for r in svc.anchor_history()]})
41
42
 
42
43
 
43
- @router.get("/tree", response_model=list[TreeItem], summary="浏览目录树:对象(带后缀的目录折成一项)、目录、origin 文件")
44
+ @router.get("/tree", response_model=Result[list[TreeItem]], summary="浏览目录树:对象(带后缀的目录折成一项)、目录、origin 文件")
44
45
  def tree(path: str = "", svc: CollectionsService = Depends(collections)):
45
- return svc.tree(path)
46
+ return ok(svc.tree(path))
46
47
 
47
48
 
48
- @router.get("/search", response_model=list[SearchHit], summary="git grep 整个 Collections(可限定层)")
49
+ @router.get("/search", response_model=Result[list[SearchHit]], summary="git grep 整个 Collections(可限定层)")
49
50
  def search(q: str, layer: str | None = None, svc: CollectionsService = Depends(collections)):
50
- return svc.search(q, layer)
51
+ return ok(svc.search(q, layer))
51
52
 
52
53
 
53
- @router.get("/manager", response_model=Manager | None, summary="这个路径归谁管(最近的 manager.json)")
54
+ @router.get("/manager", response_model=Result[Manager | None], summary="这个路径归谁管(最近的 manager.json)")
54
55
  def get_manager(path: str = "", svc: CollectionsService = Depends(collections)):
55
- return svc.manager(path)
56
+ return ok(svc.manager(path))
56
57
 
57
58
 
58
- @router.put("/manager", response_model=Manager, summary="在这个目录(或对象)下放 manager.json,绑到一个 work")
59
+ @router.put("/manager", response_model=Result[Manager], summary="在这个目录(或对象)下放 manager.json,绑到一个 work")
59
60
  def put_manager(req: ManagerPut, path: str = "", svc: CollectionsService = Depends(collections), c: Ctx = Depends(ctx)):
60
- return svc.set_manager(path, req.work, req.reason, c)
61
+ return ok(svc.set_manager(path, req.work, req.reason, c))
61
62
 
62
63
 
63
64
  @router.delete("/manager", summary="解绑:删这个目录的 manager.json")
64
65
  def delete_manager(path: str = "", reason: str = "", svc: CollectionsService = Depends(collections), c: Ctx = Depends(ctx)):
65
66
  svc.unset_manager(path, reason, c)
67
+ return ok()
66
68
 
67
69
 
68
- @router.get("/managed", response_model=list[TreeItem], summary="某个 work 管的所有对象;不传 work = 没人管的对象")
70
+ @router.get("/managed", response_model=Result[list[TreeItem]], summary="某个 work 管的所有对象;不传 work = 没人管的对象")
69
71
  def managed(work: str | None = None, svc: CollectionsService = Depends(collections)):
70
- return svc.managed_by(work) if work else svc.unmanaged()
72
+ return ok(svc.managed_by(work) if work else svc.unmanaged())
71
73
 
72
74
 
73
- @router.get("/history/{layer}/{path:path}", response_model=list[Revision], summary="一个对象的 git log(这一层的分支上)")
75
+ @router.get("/history/{layer}/{path:path}", response_model=Result[list[Revision]], summary="一个对象的 git log(这一层的分支上)")
74
76
  def history(layer: str, path: str, svc: CollectionsService = Depends(collections)):
75
- return svc.history(layer, path)
77
+ return ok(svc.history(layer, path))
76
78
 
77
79
 
78
80
  @router.post("/act/{layer}/{action}/{path:path}", summary="行为:schema 之上的领域动作(issue: position / argue / link / spawn / decide;card: discuss)")
79
81
  def act(layer: str, action: str, path: str, payload: dict[str, Any], svc: CollectionsService = Depends(collections),
80
82
  c: Ctx = Depends(ctx)) -> Any:
81
- return svc.act(layer, action, path, payload, c)
83
+ return ok(svc.act(layer, action, path, payload, c))
82
84
 
83
85
 
84
86
  # ---- 层级 / 对象 ----
85
87
 
86
- @router.get("/{layer}", response_model=CatalogDir, summary="一层的目录(按目录树列标题)")
88
+ @router.get("/{layer}", response_model=Result[CatalogDir], summary="一层的目录(按目录树列标题)")
87
89
  def catalog(layer: str, dir: str = "", svc: CollectionsService = Depends(collections)):
88
- return svc.catalog(layer, dir)
90
+ return ok(svc.catalog(layer, dir))
89
91
 
90
92
 
91
93
  @router.get("/{layer}/recall", summary="目录渲染成可注入 agent 的文本")
92
94
  def recall(layer: str, dir: str = "", svc: CollectionsService = Depends(collections)):
93
- return svc.recall_text(layer, dir)
95
+ return ok(svc.recall_text(layer, dir))
94
96
 
95
97
 
96
- @router.post("/{layer}/{path:path}", response_model=Obj, status_code=201, summary="建一个对象(一个 [layer] 提交)")
98
+ @router.post("/{layer}/{path:path}", response_model=Result[Obj], status_code=201, summary="建一个对象(一个 [layer] 提交)")
97
99
  def create(layer: str, path: str, req: ObjCreate, svc: CollectionsService = Depends(collections), c: Ctx = Depends(ctx)):
98
100
  data = req.content if svc.layer(layer).format == "raw" else (req.data or {})
99
- return svc.create(layer, path, data, req.reason, c)
101
+ return ok(svc.create(layer, path, data, req.reason, c))
100
102
 
101
103
 
102
- @router.get("/{layer}/{path:path}", response_model=Obj, summary="读一个对象(rev= 读历史版本)")
104
+ @router.get("/{layer}/{path:path}", response_model=Result[Obj], summary="读一个对象(rev= 读历史版本)")
103
105
  def get(layer: str, path: str, rev: str | None = Query(None), svc: CollectionsService = Depends(collections)):
104
- return svc.get(layer, path, rev)
106
+ return ok(svc.get(layer, path, rev))
105
107
 
106
108
 
107
- @router.put("/{layer}/{path:path}", response_model=Obj, summary="改一个对象(字段合并;origin 整体替换)")
109
+ @router.put("/{layer}/{path:path}", response_model=Result[Obj], summary="改一个对象(字段合并;origin 整体替换)")
108
110
  def update(layer: str, path: str, req: ObjUpdate, svc: CollectionsService = Depends(collections), c: Ctx = Depends(ctx)):
109
111
  patch = req.content if svc.layer(layer).format == "raw" else (req.data or {})
110
- return svc.update(layer, path, patch, req.reason, c)
112
+ return ok(svc.update(layer, path, patch, req.reason, c))
111
113
 
112
114
 
113
115
  @router.delete("/{layer}/{path:path}", summary="删一个对象(历史在 git)")
114
116
  def delete(layer: str, path: str, reason: str = "", svc: CollectionsService = Depends(collections), c: Ctx = Depends(ctx)):
115
117
  svc.delete(layer, path, reason, c)
118
+ return ok()
@@ -0,0 +1,18 @@
1
+ from memorytalk.backend.models.result import Result, ok
2
+ from fastapi import APIRouter, Request
3
+
4
+ router = APIRouter(prefix="/api/system", tags=["system"])
5
+
6
+
7
+ @router.get("/health", summary="健康检查", response_model=Result[dict])
8
+ def health():
9
+ return ok({"ok": True})
10
+
11
+
12
+ @router.get("/info", summary="运行信息:路径、存储 provider、tmux socket、有没有窗", response_model=Result[dict])
13
+ def info(request: Request):
14
+ cfg, rt = request.app.state.config, request.app.state.runtime
15
+ store = request.app.state.store.provider
16
+ return ok({"home": str(cfg.home), "collections": str(cfg.collections_dir),
17
+ "store": {"family": store.family, "backend": type(store).__name__},
18
+ "workspace": str(rt.workspace), "tmux_socket": rt.tmux_socket, "ttyd_url": rt.ttyd_url})
@@ -0,0 +1,39 @@
1
+ """/api/users —— user 是注册的顶层对象:注册、档案、清单、我是谁。不做权限。"""
2
+ from __future__ import annotations
3
+
4
+ from memorytalk.backend.models.result import Result, ok
5
+ from fastapi import APIRouter, Depends, Header, Request
6
+
7
+ from memorytalk.backend.models.users import User, UserCreate, UserProfile, UserUpdate, UserView
8
+ from memorytalk.backend.services.users import UserService
9
+
10
+ router = APIRouter(prefix="/api/users", tags=["users"])
11
+
12
+
13
+ def users(request: Request) -> UserService:
14
+ return request.app.state.users
15
+
16
+
17
+ @router.get("", response_model=Result[list[UserView]], summary="所有注册的 user,带活动统计,按最近活动倒序")
18
+ def list_users(svc: UserService = Depends(users)):
19
+ return ok(svc.list())
20
+
21
+
22
+ @router.post("", response_model=Result[User], status_code=201, summary="注册一个 user(name 唯一;之后请求头 X-Memory-Talk-User 用它)")
23
+ def register(req: UserCreate, svc: UserService = Depends(users)):
24
+ return ok(svc.register(req))
25
+
26
+
27
+ @router.get("/me", response_model=Result[UserProfile | None], summary="我是谁:X-Memory-Talk-User 对应的 user 档案(没带 → null)")
28
+ def me(svc: UserService = Depends(users), x_memory_talk_user: str | None = Header(None, alias="X-Memory-Talk-User")):
29
+ return ok(svc.profile(x_memory_talk_user) if x_memory_talk_user else None)
30
+
31
+
32
+ @router.get("/{name}", response_model=Result[UserProfile], summary="一个 user 的档案 + 建的 / 动过的 work、最近的提交")
33
+ def get_user(name: str, svc: UserService = Depends(users)):
34
+ return ok(svc.profile(name))
35
+
36
+
37
+ @router.put("/{name}", response_model=Result[User], summary="改档案(display_name / email)")
38
+ def update_user(name: str, req: UserUpdate, svc: UserService = Depends(users)):
39
+ return ok(svc.update(name, req))
@@ -1,6 +1,7 @@
1
1
  """/api/works —— 树、画布、会话(attach = 经 server 建现场)、痕迹、事件、召回。"""
2
2
  from __future__ import annotations
3
3
 
4
+ from memorytalk.backend.models.result import Result, ok
4
5
  from fastapi import APIRouter, Depends, Header, Query, Request
5
6
 
6
7
  from memorytalk.backend.models.collections import InboxItem
@@ -28,38 +29,38 @@ def user(request: Request, x_memory_talk_user: str | None = Header(None, alias="
28
29
  return x_memory_talk_user
29
30
 
30
31
 
31
- @router.get("", response_model=list[WorkNode], summary="work 树(森林;root= 只看一棵;created_by= 只看某人建的)")
32
+ @router.get("", response_model=Result[list[WorkNode]], summary="work 树(森林;root= 只看一棵;created_by= 只看某人建的)")
32
33
  def forest(root: str | None = None, created_by: str | None = None, svc: WorkService = Depends(works)):
33
- return svc.forest(root, created_by)
34
+ return ok(svc.forest(root, created_by))
34
35
 
35
36
 
36
- @router.get("/servers", response_model=list[WorkServerInfo],
37
+ @router.get("/servers", response_model=Result[list[WorkServerInfo]],
37
38
  summary="有哪些 work server(bash / claude / codex / kimi / http / default)及各自响应的协议;attach 时按协议去找它们")
38
39
  def servers(request: Request):
39
- return request.app.state.work_servers.list()
40
+ return ok(request.app.state.work_servers.list())
40
41
 
41
42
 
42
- @router.post("", response_model=Work, status_code=201, summary="开工:建一个 work(parent= 挂到树上)")
43
+ @router.post("", response_model=Result[Work], status_code=201, summary="开工:建一个 work(parent= 挂到树上)")
43
44
  def create(req: WorkCreate, svc: WorkService = Depends(works), who: str | None = Depends(user)):
44
- return svc.create(req, created_by=who)
45
+ return ok(svc.create(req, created_by=who))
45
46
 
46
47
 
47
- @router.get("/{work_id}", response_model=Work, summary="读一个 work(带身份 = 打开它,记一笔在操作)")
48
+ @router.get("/{work_id}", response_model=Result[Work], summary="读一个 work(带身份 = 打开它,记一笔在操作)")
48
49
  def get(work_id: str, svc: WorkService = Depends(works), who: str | None = Depends(user)):
49
50
  svc.touch(work_id, who)
50
- return svc.get(work_id)
51
+ return ok(svc.get(work_id))
51
52
 
52
53
 
53
- @router.patch("/{work_id}", response_model=Work,
54
+ @router.patch("/{work_id}", response_model=Result[Work],
54
55
  summary="改目标 / 状态;done 要求子 work 全完;结束后会话冻结")
55
56
  def update(work_id: str, req: WorkUpdate, svc: WorkService = Depends(works), who: str | None = Depends(user)):
56
57
  svc.touch(work_id, who)
57
- return svc.update(work_id, req)
58
+ return ok(svc.update(work_id, req))
58
59
 
59
60
 
60
- @router.get("/{work_id}/events", response_model=list[Event], summary="work 自己的时间线")
61
+ @router.get("/{work_id}/events", response_model=Result[list[Event]], summary="work 自己的时间线")
61
62
  def events(work_id: str, svc: WorkService = Depends(works)):
62
- return svc.history(work_id)
63
+ return ok(svc.history(work_id))
63
64
 
64
65
 
65
66
  @router.get("/{work_id}/recall",
@@ -67,81 +68,82 @@ def events(work_id: str, svc: WorkService = Depends(works)):
67
68
  def recall(work_id: str, dir: str = "", layer: str = "card", svc: WorkService = Depends(works),
68
69
  c: CollectionsService = Depends(collections)):
69
70
  svc.get(work_id)
70
- return c.recall_text(layer, dir)
71
+ return ok(c.recall_text(layer, dir))
71
72
 
72
73
 
73
- @router.get("/{work_id}/inbox", response_model=list[InboxItem],
74
+ @router.get("/{work_id}/inbox", response_model=Result[list[InboxItem]],
74
75
  summary="收件箱:被 manager.json 路由过来的变动(Collections 的对象、子 work 的状态)")
75
76
  def inbox(work_id: str, svc: WorkService = Depends(works)):
76
- return svc.read_inbox(work_id)
77
+ return ok(svc.read_inbox(work_id))
77
78
 
78
79
 
79
- @router.get("/{work_id}/manager", summary="这个 work 的变动打给谁:manager.json,没有则父 work")
80
+ @router.get("/{work_id}/manager", summary="这个 work 的变动打给谁:manager.json,没有则父 work", response_model=Result[dict])
80
81
  def get_manager(work_id: str, svc: WorkService = Depends(works)) -> dict:
81
- return {"work": svc.manager_of(work_id)}
82
+ return ok({"work": svc.manager_of(work_id)})
82
83
 
83
84
 
84
- @router.put("/{work_id}/manager", summary="改写默认:这棵子树的变动打给指定 work(null = 删掉,回到父)")
85
+ @router.put("/{work_id}/manager", summary="改写默认:这棵子树的变动打给指定 work(null = 删掉,回到父)", response_model=Result[dict])
85
86
  def put_manager(work_id: str, req: dict, svc: WorkService = Depends(works)) -> dict:
86
- return {"work": svc.set_manager(work_id, req.get("work"))}
87
+ return ok({"work": svc.set_manager(work_id, req.get("work"))})
87
88
 
88
89
 
89
- @router.get("/{work_id}/users", response_model=WorkUsers,
90
+ @router.get("/{work_id}/users", response_model=Result[WorkUsers],
90
91
  summary="user:谁当前正在操作(current)、谁历史操作过(history)。只做可见性,不做权限")
91
92
  def users(work_id: str, svc: WorkService = Depends(works)):
92
- return svc.list_users(work_id)
93
+ return ok(svc.list_users(work_id))
93
94
 
94
95
 
95
- @router.post("/{work_id}/users/touch", response_model=WorkUsers, summary="我在操作这个 work(心跳;身份来自 X-Memory-Talk-User)")
96
+ @router.post("/{work_id}/users/touch", response_model=Result[WorkUsers], summary="我在操作这个 work(心跳;身份来自 X-Memory-Talk-User)")
96
97
  def touch(work_id: str, svc: WorkService = Depends(works), who: str | None = Depends(user)):
97
98
  svc.touch(work_id, who)
98
- return svc.list_users(work_id)
99
+ return ok(svc.list_users(work_id))
99
100
 
100
101
 
101
- @router.get("/{work_id}/canvas", response_model=Canvas, summary="画布(视图,随时可重排)")
102
+ @router.get("/{work_id}/canvas", response_model=Result[Canvas], summary="画布(视图,随时可重排)")
102
103
  def get_canvas(work_id: str, svc: WorkService = Depends(works)):
103
- return svc.get_canvas(work_id)
104
+ return ok(svc.get_canvas(work_id))
104
105
 
105
106
 
106
- @router.put("/{work_id}/canvas", response_model=Canvas, summary="全量写画布(version 乐观锁)")
107
+ @router.put("/{work_id}/canvas", response_model=Result[Canvas], summary="全量写画布(version 乐观锁)")
107
108
  def put_canvas(work_id: str, req: CanvasPut, svc: WorkService = Depends(works), who: str | None = Depends(user)):
108
109
  svc.touch(work_id, who)
109
- return svc.put_canvas(work_id, req)
110
+ return ok(svc.put_canvas(work_id, req))
110
111
 
111
112
 
112
- @router.get("/{work_id}/sessions", response_model=list[SessionView], summary="会话清单(含活没活着)")
113
+ @router.get("/{work_id}/sessions", response_model=Result[list[SessionView]], summary="会话清单(含活没活着)")
113
114
  def sessions(work_id: str, svc: WorkService = Depends(works)):
114
- return svc.list_sessions(work_id)
115
+ return ok(svc.list_sessions(work_id))
115
116
 
116
117
 
117
- @router.post("/{work_id}/sessions", response_model=SessionView, status_code=201,
118
+ @router.post("/{work_id}/sessions", response_model=Result[SessionView], status_code=201,
118
119
  summary="在 work 里打开一个块:协议 → server 建现场,登记会话,交回窗 + 把手")
119
120
  def attach(work_id: str, req: SessionCreate, svc: WorkService = Depends(works), who: str | None = Depends(user)):
120
121
  svc.touch(work_id, who)
121
- return svc.attach(work_id, req.uri)
122
+ return ok(svc.attach(work_id, req.uri))
122
123
 
123
124
 
124
- @router.post("/{work_id}/sessions/{session_id}/attach", response_model=SessionView,
125
+ @router.post("/{work_id}/sessions/{session_id}/attach", response_model=Result[SessionView],
125
126
  summary="重入:幂等取回同一个现场")
126
127
  def reattach(work_id: str, session_id: str, svc: WorkService = Depends(works), who: str | None = Depends(user)):
127
128
  svc.touch(work_id, who)
128
- return svc.reattach(work_id, session_id)
129
+ return ok(svc.reattach(work_id, session_id))
129
130
 
130
131
 
131
132
  @router.delete("/{work_id}/sessions/{session_id}", summary="关闭即回收:销毁现场 + 删登记")
132
133
  def detach(work_id: str, session_id: str, svc: WorkService = Depends(works), who: str | None = Depends(user)):
133
134
  svc.touch(work_id, who)
134
135
  svc.detach(work_id, session_id)
136
+ return ok()
135
137
 
136
138
 
137
139
  @router.get("/{work_id}/sessions/{session_id}/capture",
138
140
  summary="观测:抓终端屏幕(把手 capture)")
139
141
  def capture(work_id: str, session_id: str, lines: int = Query(200, ge=1, le=5000),
140
142
  svc: WorkService = Depends(works)):
141
- return svc.capture(work_id, session_id, lines)
143
+ return ok(svc.capture(work_id, session_id, lines))
142
144
 
143
145
 
144
- @router.get("/{work_id}/sessions/{session_id}/rounds", response_model=list[Round],
146
+ @router.get("/{work_id}/sessions/{session_id}/rounds", response_model=Result[list[Round]],
145
147
  summary="痕迹:agent 会话的 round(先从把手同步新 round,再读 rounds.jsonl)")
146
148
  def rounds(work_id: str, session_id: str, svc: WorkService = Depends(works)):
147
- return svc.rounds(work_id, session_id)
149
+ return ok(svc.rounds(work_id, session_id))
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
  from fastapi import FastAPI, Request
5
5
  from fastapi.responses import JSONResponse
6
6
 
7
- from memorytalk.backend.envelope import EnvelopeMiddleware, envelope
7
+ from memorytalk.backend.models.result import fail
8
8
 
9
9
  from memorytalk.backend.config import Config, RuntimeConfig, load_config, load_runtime_config
10
10
  from memorytalk.backend.controllers import collections, system, users, works
@@ -35,11 +35,10 @@ def create_app(config: Config | None = None, runtime: RuntimeConfig | None = Non
35
35
 
36
36
  for r in (system.router, works.router, users.router, collections.router):
37
37
  app.include_router(r)
38
- app.add_middleware(EnvelopeMiddleware) # 所有 /api/* 响应包成 {"data", "message"[, "error"]}
39
38
 
40
39
  def _err(status: int, code: str):
41
40
  async def handler(_: Request, exc: Exception):
42
- return JSONResponse(envelope(None, str(exc), code), status_code=status)
41
+ return JSONResponse(fail(code, str(exc)), status_code=status)
43
42
  return handler
44
43
 
45
44
  for exc_type in (WorkNotFound, SessionNotFound, UserNotFound):
@@ -49,11 +48,11 @@ def create_app(config: Config | None = None, runtime: RuntimeConfig | None = Non
49
48
 
50
49
  @app.exception_handler(CollectionsError)
51
50
  async def _collect(_: Request, exc: CollectionsError):
52
- return JSONResponse(envelope(None, str(exc), exc.code), status_code=exc.status)
51
+ return JSONResponse(fail(exc.code, str(exc)), status_code=exc.status)
53
52
 
54
53
  @app.exception_handler(WorkServerError)
55
54
  async def _server(_: Request, exc: WorkServerError):
56
55
  status = {"bad_uri": 400, "cmd_not_found": 400, "no_server": 400, "platform": 502}.get(exc.code, 500)
57
- return JSONResponse(envelope(None, str(exc), exc.code), status_code=status)
56
+ return JSONResponse(fail(exc.code, str(exc)), status_code=status)
58
57
 
59
58
  return app
@@ -0,0 +1,30 @@
1
+ """统一响应信封:所有 /api/* 端点返回 Result[T] = {"data": T, "message": "ok"};出错时 data 为 null、多一个 error 机器码。
2
+ 显式写在每个端点的 response_model 上,OpenAPI 文档和实际响应一致。"""
3
+ from __future__ import annotations
4
+
5
+ from typing import Generic, TypeVar
6
+
7
+ from pydantic import BaseModel, Field, model_serializer
8
+
9
+ T = TypeVar("T")
10
+
11
+
12
+ class Result(BaseModel, Generic[T]):
13
+ data: T | None = None
14
+ message: str = "ok"
15
+ error: str | None = Field(None, description="出错时的机器码;成功时没有")
16
+
17
+ @model_serializer(mode="wrap")
18
+ def _drop_empty_error(self, handler):
19
+ out = handler(self)
20
+ if out.get("error") is None:
21
+ out.pop("error", None) # 成功时就是 {"data", "message"},没有 error 键
22
+ return out
23
+
24
+
25
+ def ok(data=None, message: str = "ok") -> dict:
26
+ return {"data": data, "message": message}
27
+
28
+
29
+ def fail(error: str, message: str) -> dict:
30
+ return {"data": None, "message": message, "error": error}
@@ -1,5 +1,6 @@
1
1
  """memory.talk 命令行:本地 API 的客户端,不含业务逻辑(docs/cli/v5)。
2
2
 
3
+ memory.talk version → 版本号
3
4
  memory.talk server start | stop | restart | status | daemon → cli/server.py
4
5
  memory.talk work create | list | show | set | attach | … → cli/work.py
5
6
  memory.talk user add | list | show | set | whoami → cli/user.py
@@ -12,6 +13,8 @@ from __future__ import annotations
12
13
  import argparse
13
14
  import os
14
15
 
16
+ from memorytalk import __version__
17
+
15
18
  from . import collection, server, user, work
16
19
  from ._common import DEFAULT_SERVER, Api
17
20
 
@@ -22,7 +25,9 @@ def build_parser() -> argparse.ArgumentParser:
22
25
  ap.add_argument("--user", default=os.environ.get("MEMORY_TALK_USER"), help="我是谁(须注册过)")
23
26
  ap.add_argument("--work", default=os.environ.get("MEMORY_TALK_WORK"), help="在哪个 work 里操作")
24
27
  ap.add_argument("--json", action="store_true", help="结构化输出")
28
+ ap.add_argument("-V", "--version", action="version", version=f"memory.talk {__version__}")
25
29
  top = ap.add_subparsers(dest="cmd", required=True)
30
+ top.add_parser("version", help="版本号").set_defaults(local=lambda a: print(f"memory.talk {__version__}"))
26
31
  for group in (server, work, user, collection):
27
32
  group.register(top)
28
33
  return ap
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "memorytalk"
7
- version = "5.0.2"
7
+ version = "5.0.4"
8
8
  description = "memory.talk v5 — work / collections / user 三个顶层对象的工作台:跑 code agent 的 work 树,git 分层的认知层,注册的团队成员"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -18,7 +18,7 @@ _orig_json = httpx.Response.json
18
18
  def _unwrap(self, **kw):
19
19
  """API 响应是 {data, message[, error]} 信封:成功时 .json() 直接给 data,出错时给整个信封(测试看 error 码)。"""
20
20
  body = _orig_json(self, **kw)
21
- if isinstance(body, dict) and "data" in body and "message" in body and "error" not in body:
21
+ if isinstance(body, dict) and "data" in body and "message" in body and not body.get("error"):
22
22
  return body["data"]
23
23
  return body
24
24
 
@@ -1,17 +0,0 @@
1
- from fastapi import APIRouter, Request
2
-
3
- router = APIRouter(prefix="/api/system", tags=["system"])
4
-
5
-
6
- @router.get("/health", summary="健康检查")
7
- def health():
8
- return {"ok": True}
9
-
10
-
11
- @router.get("/info", summary="运行信息:路径、存储 provider、tmux socket、有没有窗")
12
- def info(request: Request):
13
- cfg, rt = request.app.state.config, request.app.state.runtime
14
- store = request.app.state.store.provider
15
- return {"home": str(cfg.home), "collections": str(cfg.collections_dir),
16
- "store": {"family": store.family, "backend": type(store).__name__},
17
- "workspace": str(rt.workspace), "tmux_socket": rt.tmux_socket, "ttyd_url": rt.ttyd_url}
@@ -1,38 +0,0 @@
1
- """/api/users —— user 是注册的顶层对象:注册、档案、清单、我是谁。不做权限。"""
2
- from __future__ import annotations
3
-
4
- from fastapi import APIRouter, Depends, Header, Request
5
-
6
- from memorytalk.backend.models.users import User, UserCreate, UserProfile, UserUpdate, UserView
7
- from memorytalk.backend.services.users import UserService
8
-
9
- router = APIRouter(prefix="/api/users", tags=["users"])
10
-
11
-
12
- def users(request: Request) -> UserService:
13
- return request.app.state.users
14
-
15
-
16
- @router.get("", response_model=list[UserView], summary="所有注册的 user,带活动统计,按最近活动倒序")
17
- def list_users(svc: UserService = Depends(users)):
18
- return svc.list()
19
-
20
-
21
- @router.post("", response_model=User, status_code=201, summary="注册一个 user(name 唯一;之后请求头 X-Memory-Talk-User 用它)")
22
- def register(req: UserCreate, svc: UserService = Depends(users)):
23
- return svc.register(req)
24
-
25
-
26
- @router.get("/me", response_model=UserProfile | None, summary="我是谁:X-Memory-Talk-User 对应的 user 档案(没带 → null)")
27
- def me(svc: UserService = Depends(users), x_memory_talk_user: str | None = Header(None, alias="X-Memory-Talk-User")):
28
- return svc.profile(x_memory_talk_user) if x_memory_talk_user else None
29
-
30
-
31
- @router.get("/{name}", response_model=UserProfile, summary="一个 user 的档案 + 建的 / 动过的 work、最近的提交")
32
- def get_user(name: str, svc: UserService = Depends(users)):
33
- return svc.profile(name)
34
-
35
-
36
- @router.put("/{name}", response_model=User, summary="改档案(display_name / email)")
37
- def update_user(name: str, req: UserUpdate, svc: UserService = Depends(users)):
38
- return svc.update(name, req)
@@ -1,44 +0,0 @@
1
- """统一响应信封:所有 /api/* 的响应都是 {"data": …, "message": …};出错时多一个 "error"(机器码)。
2
-
3
- - JSON 响应 → data = 原来的 body;
4
- - 纯文本响应(recall / capture)→ data = 那段文本;
5
- - 204 → 200,data = null;
6
- - 已经是信封的(错误处理器直接产出的)原样放行;/docs /openapi.json 不碰。
7
- """
8
- from __future__ import annotations
9
-
10
- import json
11
-
12
- from starlette.middleware.base import BaseHTTPMiddleware
13
- from starlette.requests import Request
14
- from starlette.responses import JSONResponse, Response
15
-
16
-
17
- def envelope(data, message: str = "ok", error: str | None = None) -> dict:
18
- body = {"data": data, "message": message}
19
- if error:
20
- body["error"] = error
21
- return body
22
-
23
-
24
- def is_envelope(obj) -> bool:
25
- return isinstance(obj, dict) and "data" in obj and "message" in obj and set(obj) <= {"data", "message", "error"}
26
-
27
-
28
- class EnvelopeMiddleware(BaseHTTPMiddleware):
29
- async def dispatch(self, request: Request, call_next) -> Response:
30
- response = await call_next(request)
31
- if not request.url.path.startswith("/api/"):
32
- return response
33
- raw = b"".join([chunk async for chunk in response.body_iterator])
34
- ctype = response.headers.get("content-type", "")
35
- status = 200 if response.status_code == 204 else response.status_code
36
- if status == 204 or not raw:
37
- payload = envelope(None)
38
- elif ctype.startswith("application/json"):
39
- obj = json.loads(raw)
40
- payload = obj if is_envelope(obj) else envelope(obj)
41
- else:
42
- payload = envelope(raw.decode("utf-8", "replace"))
43
- headers = {k: v for k, v in response.headers.items() if k.lower() not in ("content-length", "content-type")}
44
- return JSONResponse(payload, status_code=status, headers=headers)
File without changes