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.
- {memorytalk-5.0.2 → memorytalk-5.0.4}/PKG-INFO +1 -1
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v5/README.md +1 -1
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v5/README.md +1 -0
- memorytalk-5.0.4/memorytalk/__init__.py +21 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/README.md +1 -1
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/controllers/collections.py +31 -28
- memorytalk-5.0.4/memorytalk/backend/controllers/system.py +18 -0
- memorytalk-5.0.4/memorytalk/backend/controllers/users.py +39 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/controllers/works.py +38 -36
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/main.py +4 -5
- memorytalk-5.0.4/memorytalk/backend/models/result.py +30 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/cli/__init__.py +5 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/pyproject.toml +1 -1
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/conftest.py +1 -1
- memorytalk-5.0.2/memorytalk/backend/controllers/system.py +0 -17
- memorytalk-5.0.2/memorytalk/backend/controllers/users.py +0 -38
- memorytalk-5.0.2/memorytalk/backend/envelope.py +0 -44
- memorytalk-5.0.2/memorytalk/backend/services/__init__.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/.github/workflows/test.yml +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/.gitignore +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/LICENSE +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v1/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v1/cards.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v1/links.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v1/recall.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v1/sessions.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v1/status.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/cards.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/links.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/log.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/rebuild.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/search.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/sessions.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/status.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/tags.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v2/view.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/cards.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/embedding.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/explore.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/read.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/recall.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/reviews.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/search.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/sessions.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/status.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v3/sync.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/card-links.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/card-sessions.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/cards.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/read.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/recall.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/reviews.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v4/search.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v5/collections.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v5/system.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v5/users.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/api/v5/works.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/card.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/link.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/rebuild.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/recall.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/search.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/server.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/session.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v1/sync.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/card.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/explore.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/filter.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/link.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/log.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/rebuild.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/recall.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/review.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/search.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/server.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/setup.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/sync.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/tag.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v2/view.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/card.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/explore.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/read.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/recall.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/review.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/search.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/session.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/setup.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/sync.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v3/upgrade.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v4/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v4/card.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v4/insight.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v4/read.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v4/recall.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v4/search.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v5/collection.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v5/server.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v5/user.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/cli/v5/work.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/card-creation-flow.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/card-deletion-flow.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/codex-trust-flow.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/dsl.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/explore-cwd-suppression.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/explore.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/file-canonical-pattern.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/forum-dynamics.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/hook-installation.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/index-backfill.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/migration.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/read-side-effects.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/recall-pipeline.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/review-impact.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/search-ranking.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/searchbase-extraction.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/session-namespace.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/session-rounds-write.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v3/sync-pipeline.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v4/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v4/card.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v4/insight-migration.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v4/session-annotation.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/card.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/collections-layer.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/collections-store.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/collections.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/issue.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/manager.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/origin.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/provider.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/session.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/user.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/work-server.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/designs/v5/work.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/report/2026-05-21-search-noisy-or-aggregation-bug.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/report/2026-05-23-claude-code-adapter-role-misclassification.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/report/2026-05-23-search-linear-combination-regression.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/report/2026-05-23-search-vector-index-batch-gap.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v1/link.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v1/session.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v1/settings.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v1/talk-card.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v2/link.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v2/search-result.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v2/session.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v2/settings.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v2/tag.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v2/talk-card.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/filesystem.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/recall.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/review.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/search-result.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/session.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/settings.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v3/talk-card.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v4/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v4/card-link.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v4/card-session.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v4/card.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v4/filesystem.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v4/recall.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v4/review.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v5/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v5/collections.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v5/filesystem.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v5/work-server.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/structure/v5/work.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/superpowers/plans/2026-06-19-v4-data-foundation.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/superpowers/plans/2026-06-19-v4-insight-rename.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/docs/superpowers/specs/2026-05-19-sync-as-settings-design.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/__main__.py +0 -0
- {memorytalk-5.0.2/memorytalk → memorytalk-5.0.4/memorytalk/backend}/__init__.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/config.py +0 -0
- {memorytalk-5.0.2/memorytalk/backend → memorytalk-5.0.4/memorytalk/backend/controllers}/__init__.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/controllers/auth.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/gateway.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/layers/__init__.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/layers/_spec.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/layers/_user.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/layers/card.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/layers/issue.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/layers/origin.py +0 -0
- {memorytalk-5.0.2/memorytalk/backend/controllers → memorytalk-5.0.4/memorytalk/backend/models}/__init__.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/models/collections.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/models/users.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/models/work.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/models/work_server.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/providers/__init__.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/providers/db.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/providers/fs.py +0 -0
- {memorytalk-5.0.2/memorytalk/backend/models → memorytalk-5.0.4/memorytalk/backend/services}/__init__.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/collections/__init__.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/collections/catalog.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/collections/manager.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/collections/repo.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/store/__init__.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/users/__init__.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/users/repo.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/__init__.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/canvas.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/events.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/inbox.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/repo.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/rounds.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/sessions.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/tree.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work/users.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/__init__.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/adapters/__init__.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/adapters/base.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/adapters/claude_code.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/adapters/codex.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/adapters/kimi.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/agent.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/registry.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/terminal.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/services/work_servers/uri.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/work_servers/__init__.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/work_servers/bash.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/work_servers/claude.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/work_servers/codex.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/work_servers/default.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/work_servers/http.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/backend/work_servers/kimi.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/cli/_common.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/cli/collection.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/cli/server.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/cli/user.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/cli/work.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/.gitignore +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/apps/browser.html +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/apps/cards.html +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/apps/files.html +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/apps/issues.html +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/apps/settings.html +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/index.html +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/package.json +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/postcss.config.js +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/public/login.html +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/browser/main.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/cards/CardHistory.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/cards/CardView.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/cards/Catalog.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/cards/main.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/badge.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/button.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/card.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/dialog.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/dropdown-menu.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/input.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/label.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/sonner.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/components/ui/tooltip.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/files/main.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/index.css +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/issues/IssueGraph.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/issues/IssueView.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/issues/main.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/lib/api.ts +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/lib/grid.ts +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/lib/queries.ts +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/lib/query.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/lib/store.ts +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/lib/uri.ts +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/lib/utils.ts +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/settings/main.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/shell/Dividers.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/shell/PanelView.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/shell/Shell.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/shell/TaskHeader.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/shell/TaskTree.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/shell/UrlBar.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/src/shell/main.tsx +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/tailwind.config.js +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/tsconfig.json +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/memorytalk/frontend/vite.config.ts +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/_util.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/adapters/claude_code/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/adapters/claude_code/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/adapters/codex/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/adapters/codex/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/adapters/kimi/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/adapters/kimi/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/cli/end_to_end/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/cli/end_to_end/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/config/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/config/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/decide_and_discuss/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/decide_and_discuss/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/history/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/history/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/inbox_delivery/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/inbox_delivery/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/issue_behaviors/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/issue_behaviors/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/layer_guard/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/layer_guard/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/layers/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/layers/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/manager/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/manager/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/objects/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/objects/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/tree_and_search/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/tree_and_search/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/user_layer/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/collections/user_layer/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/providers/local_fs/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/providers/local_fs/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/providers/sqlite_builder/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/providers/sqlite_builder/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/activity/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/activity/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/commit_author/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/commit_author/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/identity_header/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/identity_header/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/register/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/register/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/work_ownership/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/users/work_ownership/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/bash_session/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/bash_session/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/default_session/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/default_session/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/freeze/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/freeze/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/http_session/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/http_session/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/registry/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/work_servers/registry/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/canvas/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/canvas/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/events_and_inbox/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/events_and_inbox/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/recall/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/recall/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/status/README.md +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/status/test.py +0 -0
- {memorytalk-5.0.2 → memorytalk-5.0.4}/tests/works/tree/README.md +0 -0
- {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.
|
|
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/*`
|
|
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` | 何时 |
|
|
@@ -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.
|
|
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(
|
|
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(
|
|
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(
|
|
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.
|
|
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"
|
|
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
|