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.
- {memorytalk-5.0.1 → memorytalk-5.0.2}/PKG-INFO +1 -1
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v5/README.md +1 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v5/collections.md +14 -3
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/collections-layer.md +9 -9
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/collections.md +2 -2
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/manager.md +1 -1
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v5/collections.md +4 -4
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v5/filesystem.md +1 -2
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/README.md +2 -2
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/controllers/collections.py +5 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/layers/__init__.py +2 -2
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/layers/_user.py +13 -2
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/collections/__init__.py +30 -18
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/collections/repo.py +29 -8
- {memorytalk-5.0.1 → memorytalk-5.0.2}/pyproject.toml +1 -1
- memorytalk-5.0.2/tests/README.md +19 -0
- memorytalk-5.0.2/tests/_util.py +2 -0
- memorytalk-5.0.2/tests/adapters/claude_code/README.md +12 -0
- memorytalk-5.0.2/tests/adapters/claude_code/test.py +65 -0
- memorytalk-5.0.2/tests/adapters/codex/README.md +8 -0
- memorytalk-5.0.2/tests/adapters/codex/test.py +34 -0
- memorytalk-5.0.2/tests/adapters/kimi/README.md +8 -0
- memorytalk-5.0.2/tests/adapters/kimi/test.py +36 -0
- memorytalk-5.0.2/tests/cli/end_to_end/README.md +13 -0
- {memorytalk-5.0.1/tests/cli → memorytalk-5.0.2/tests/cli/end_to_end}/test.py +1 -1
- memorytalk-5.0.2/tests/collections/config/README.md +12 -0
- memorytalk-5.0.2/tests/collections/config/test.py +42 -0
- memorytalk-5.0.2/tests/collections/decide_and_discuss/README.md +8 -0
- memorytalk-5.0.2/tests/collections/decide_and_discuss/test.py +44 -0
- memorytalk-5.0.2/tests/collections/history/README.md +8 -0
- memorytalk-5.0.2/tests/collections/history/test.py +21 -0
- memorytalk-5.0.2/tests/collections/inbox_delivery/README.md +8 -0
- memorytalk-5.0.2/tests/collections/inbox_delivery/test.py +40 -0
- memorytalk-5.0.2/tests/collections/issue_behaviors/README.md +11 -0
- memorytalk-5.0.2/tests/collections/issue_behaviors/test.py +56 -0
- memorytalk-5.0.2/tests/collections/layer_guard/README.md +8 -0
- memorytalk-5.0.2/tests/collections/layer_guard/test.py +27 -0
- memorytalk-5.0.2/tests/collections/layers/README.md +11 -0
- memorytalk-5.0.2/tests/collections/layers/test.py +23 -0
- memorytalk-5.0.2/tests/collections/manager/README.md +11 -0
- memorytalk-5.0.2/tests/collections/manager/test.py +51 -0
- memorytalk-5.0.2/tests/collections/objects/README.md +9 -0
- memorytalk-5.0.2/tests/collections/objects/test.py +50 -0
- memorytalk-5.0.2/tests/collections/tree_and_search/README.md +9 -0
- memorytalk-5.0.2/tests/collections/tree_and_search/test.py +35 -0
- memorytalk-5.0.2/tests/collections/user_layer/README.md +8 -0
- memorytalk-5.0.2/tests/collections/user_layer/test.py +42 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/tests/conftest.py +32 -5
- memorytalk-5.0.2/tests/providers/local_fs/README.md +12 -0
- memorytalk-5.0.2/tests/providers/local_fs/test.py +63 -0
- memorytalk-5.0.2/tests/providers/sqlite_builder/README.md +13 -0
- memorytalk-5.0.2/tests/providers/sqlite_builder/test.py +69 -0
- memorytalk-5.0.2/tests/users/activity/README.md +11 -0
- memorytalk-5.0.2/tests/users/activity/test.py +54 -0
- memorytalk-5.0.2/tests/users/commit_author/README.md +11 -0
- memorytalk-5.0.2/tests/users/commit_author/test.py +25 -0
- memorytalk-5.0.2/tests/users/identity_header/README.md +12 -0
- memorytalk-5.0.2/tests/users/identity_header/test.py +18 -0
- memorytalk-5.0.2/tests/users/register/README.md +12 -0
- memorytalk-5.0.2/tests/users/register/test.py +32 -0
- memorytalk-5.0.2/tests/users/work_ownership/README.md +11 -0
- memorytalk-5.0.2/tests/users/work_ownership/test.py +29 -0
- memorytalk-5.0.2/tests/work_servers/bash_session/README.md +11 -0
- memorytalk-5.0.2/tests/work_servers/bash_session/test.py +59 -0
- memorytalk-5.0.2/tests/work_servers/default_session/README.md +8 -0
- memorytalk-5.0.2/tests/work_servers/default_session/test.py +23 -0
- memorytalk-5.0.2/tests/work_servers/freeze/README.md +7 -0
- memorytalk-5.0.2/tests/work_servers/freeze/test.py +13 -0
- memorytalk-5.0.2/tests/work_servers/http_session/README.md +11 -0
- memorytalk-5.0.2/tests/work_servers/http_session/test.py +20 -0
- memorytalk-5.0.2/tests/work_servers/registry/README.md +11 -0
- memorytalk-5.0.2/tests/work_servers/registry/test.py +20 -0
- memorytalk-5.0.2/tests/works/canvas/README.md +11 -0
- memorytalk-5.0.2/tests/works/canvas/test.py +32 -0
- memorytalk-5.0.2/tests/works/events_and_inbox/README.md +11 -0
- memorytalk-5.0.2/tests/works/events_and_inbox/test.py +38 -0
- memorytalk-5.0.2/tests/works/recall/README.md +11 -0
- memorytalk-5.0.2/tests/works/recall/test.py +17 -0
- memorytalk-5.0.2/tests/works/status/README.md +11 -0
- memorytalk-5.0.2/tests/works/status/test.py +33 -0
- memorytalk-5.0.2/tests/works/tree/README.md +12 -0
- memorytalk-5.0.2/tests/works/tree/test.py +33 -0
- memorytalk-5.0.1/tests/README.md +0 -7
- memorytalk-5.0.1/tests/adapters/test.py +0 -99
- memorytalk-5.0.1/tests/collections/test.py +0 -166
- memorytalk-5.0.1/tests/users/test.py +0 -69
- memorytalk-5.0.1/tests/work_server_attach/test.py +0 -76
- memorytalk-5.0.1/tests/work_tree/test.py +0 -52
- {memorytalk-5.0.1 → memorytalk-5.0.2}/.github/workflows/test.yml +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/.gitignore +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/LICENSE +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v1/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v1/cards.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v1/links.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v1/recall.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v1/sessions.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v1/status.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/cards.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/links.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/log.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/rebuild.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/search.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/sessions.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/status.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/tags.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v2/view.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/cards.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/embedding.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/explore.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/read.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/recall.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/reviews.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/search.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/sessions.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/status.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v3/sync.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/card-links.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/card-sessions.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/cards.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/read.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/recall.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/reviews.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v4/search.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v5/system.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v5/users.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/api/v5/works.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/card.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/link.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/rebuild.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/recall.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/search.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/server.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/session.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v1/sync.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/card.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/explore.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/filter.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/link.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/log.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/rebuild.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/recall.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/review.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/search.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/server.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/setup.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/sync.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/tag.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v2/view.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/card.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/explore.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/read.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/recall.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/review.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/search.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/session.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/setup.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/sync.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v3/upgrade.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v4/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v4/card.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v4/insight.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v4/read.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v4/recall.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v4/search.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v5/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v5/collection.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v5/server.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v5/user.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/cli/v5/work.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/card-creation-flow.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/card-deletion-flow.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/codex-trust-flow.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/dsl.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/explore-cwd-suppression.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/explore.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/file-canonical-pattern.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/forum-dynamics.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/hook-installation.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/index-backfill.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/migration.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/read-side-effects.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/recall-pipeline.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/review-impact.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/search-ranking.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/searchbase-extraction.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/session-namespace.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/session-rounds-write.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v3/sync-pipeline.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v4/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v4/card.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v4/insight-migration.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v4/session-annotation.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/card.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/collections-store.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/issue.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/origin.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/provider.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/session.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/user.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/work-server.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/designs/v5/work.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/report/2026-05-21-search-noisy-or-aggregation-bug.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/report/2026-05-23-claude-code-adapter-role-misclassification.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/report/2026-05-23-search-linear-combination-regression.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/report/2026-05-23-search-vector-index-batch-gap.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v1/link.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v1/session.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v1/settings.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v1/talk-card.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v2/link.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v2/search-result.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v2/session.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v2/settings.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v2/tag.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v2/talk-card.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/filesystem.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/recall.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/review.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/search-result.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/session.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/settings.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v3/talk-card.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v4/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v4/card-link.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v4/card-session.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v4/card.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v4/filesystem.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v4/recall.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v4/review.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v5/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v5/work-server.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/structure/v5/work.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/superpowers/plans/2026-06-19-v4-data-foundation.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/superpowers/plans/2026-06-19-v4-insight-rename.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/docs/superpowers/specs/2026-05-19-sync-as-settings-design.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/__init__.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/__main__.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/__init__.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/config.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/controllers/__init__.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/controllers/auth.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/controllers/system.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/controllers/users.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/controllers/works.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/envelope.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/gateway.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/layers/_spec.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/layers/card.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/layers/issue.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/layers/origin.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/main.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/models/__init__.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/models/collections.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/models/users.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/models/work.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/models/work_server.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/providers/__init__.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/providers/db.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/providers/fs.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/__init__.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/collections/catalog.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/collections/manager.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/store/__init__.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/users/__init__.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/users/repo.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/__init__.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/canvas.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/events.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/inbox.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/repo.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/rounds.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/sessions.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/tree.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work/users.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/__init__.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/adapters/__init__.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/adapters/base.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/adapters/claude_code.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/adapters/codex.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/adapters/kimi.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/agent.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/registry.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/terminal.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/services/work_servers/uri.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/work_servers/__init__.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/work_servers/bash.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/work_servers/claude.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/work_servers/codex.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/work_servers/default.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/work_servers/http.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/backend/work_servers/kimi.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/cli/__init__.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/cli/_common.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/cli/collection.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/cli/server.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/cli/user.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/cli/work.py +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/.gitignore +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/README.md +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/apps/browser.html +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/apps/cards.html +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/apps/files.html +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/apps/issues.html +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/apps/settings.html +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/index.html +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/package.json +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/postcss.config.js +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/public/login.html +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/browser/main.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/cards/CardHistory.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/cards/CardView.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/cards/Catalog.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/cards/main.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/badge.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/button.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/card.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/dialog.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/dropdown-menu.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/input.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/label.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/sonner.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/components/ui/tooltip.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/files/main.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/index.css +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/issues/IssueGraph.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/issues/IssueView.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/issues/main.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/lib/api.ts +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/lib/grid.ts +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/lib/queries.ts +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/lib/query.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/lib/store.ts +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/lib/uri.ts +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/lib/utils.ts +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/settings/main.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/shell/Dividers.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/shell/PanelView.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/shell/Shell.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/shell/TaskHeader.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/shell/TaskTree.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/shell/UrlBar.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/src/shell/main.tsx +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/tailwind.config.js +0 -0
- {memorytalk-5.0.1 → memorytalk-5.0.2}/memorytalk/frontend/tsconfig.json +0 -0
- {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.
|
|
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。副作用:`
|
|
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` / `
|
|
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`
|
|
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`
|
|
19
|
+
| **叫什么** | 层名:`collections.json` 的 `layers[]` 里一项、分支 `layer/<名>`、提交前缀 `[名]` |
|
|
20
20
|
| **住哪** | 路径:这个层的文件都在哪个目录下(和别的层不相交) |
|
|
21
21
|
| **长什么样** | schema:一个对象是一个什么格式的文件、有哪些字段、哪个是标题、哪些是引用 |
|
|
22
|
-
| **排在哪** | 层序:它在 `layers` 里的位置——比谁更接近记录、比谁更接近结论 |
|
|
22
|
+
| **排在哪** | 层序:它在 `collections.json` 的 `layers[]` 里的位置——比谁更接近记录、比谁更接近结论 |
|
|
23
23
|
|
|
24
|
-
|
|
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
|
-
#
|
|
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
|
|
143
|
-
- **加层**:`
|
|
144
|
-
- **删层**:collectbase 说层是可以停的(分支留着不动);memory.talk 侧把它从 `
|
|
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
|
-
-
|
|
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
|
|
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
|
|
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` 是**机制文件**(同
|
|
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
|
-
- **机制文件**:`
|
|
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
|
-
`
|
|
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
|
-
│ ├──
|
|
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:层的装载(内置 +
|
|
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
|
|
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
|
|
16
|
+
def schema_from_yaml(text: str) -> dict:
|
|
17
17
|
doc = yaml.safe_load(text) or {}
|
|
18
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
87
|
-
if
|
|
88
|
-
raise CollectionsError("bad_layer", f"schema 里的 layer 是 {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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 ==
|
|
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 ==
|
|
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
|
|
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 ==
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
"""
|
|
149
|
+
"""无则建拓扑;有则把缺的内置层补上(新层分支从始祖出发,collections.json 在最底层更新)。"""
|
|
140
150
|
cur = self.layers()
|
|
141
151
|
if cur is None:
|
|
142
|
-
|
|
143
|
-
tree = self.write_tree({ANCHOR: Entry("100644", self.hash_object(
|
|
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
|
-
|
|
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: (
|
|
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.
|
|
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,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 记录根)。
|