project-agent 0.2.2__tar.gz → 0.2.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.
- {project_agent-0.2.2 → project_agent-0.2.4}/PKG-INFO +1 -1
- {project_agent-0.2.2 → project_agent-0.2.4}/pyproject.toml +1 -1
- project_agent-0.2.4/src/project_agent/application/context/add_project_member.py +50 -0
- project_agent-0.2.4/src/project_agent/application/context/get_project_context.py +128 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/context/project_summary.py +18 -2
- project_agent-0.2.4/src/project_agent/application/context/set_project_owner.py +59 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/doc/render.py +99 -17
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/doc/sync.py +9 -2
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/doc/writeback.py +5 -2
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/doc_hub/manage.py +4 -2
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/doc_hub/read.py +1 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/mind/create_version.py +2 -2
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/mind/finalize_version_closure.py +9 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/mind/propose_change.py +6 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/mind/read.py +18 -83
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/mind/signoff_proposal.py +2 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/mind/update_version.py +3 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/report/build.py +173 -76
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/scheduled/run.py +252 -36
- project_agent-0.2.4/src/project_agent/application/shared/project_participants.py +123 -0
- project_agent-0.2.4/src/project_agent/application/shared/user_refs.py +105 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/doc/models.py +6 -3
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/mind/models.py +7 -13
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/monitoring/models.py +26 -17
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/project_context/models.py +38 -1
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/report/models.py +21 -4
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/scheduled/models.py +10 -1
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/shared/documents.py +2 -1
- project_agent-0.2.4/src/project_agent/domain/shared/project_participants.py +14 -0
- project_agent-0.2.4/src/project_agent/domain/shared/user_refs.py +31 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/infrastructure/clock/workday_clock.py +15 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/infrastructure/db/repositories.py +58 -8
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/infrastructure/db/schema.py +93 -28
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/infrastructure/db/tables.py +5 -2
- project_agent-0.2.4/src/project_agent/infrastructure/feature_flags.py +18 -0
- project_agent-0.2.4/src/project_agent/interface/cli/commands/_monitoring_support.py +6 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/context.py +291 -8
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/doc.py +55 -5
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/doc_hub.py +16 -8
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/mind.py +73 -1
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/monitoring.py +3 -4
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/report.py +4 -3
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/scheduled.py +15 -2
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/task_event_notify.py +1 -1
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/helptext.py +2 -2
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent.egg-info/PKG-INFO +1 -1
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent.egg-info/SOURCES.txt +12 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_bootstrap_checkpoint.py +3 -1
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_cli_help.py +39 -2
- project_agent-0.2.4/tests/test_context_add_project_member.py +217 -0
- project_agent-0.2.4/tests/test_context_get_project.py +241 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_context_get_project_pending_states.py +4 -19
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_context_list_projects.py +75 -11
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_context_list_tasks.py +9 -9
- project_agent-0.2.4/tests/test_context_project_binding.py +154 -0
- project_agent-0.2.4/tests/test_context_project_summary.py +837 -0
- project_agent-0.2.4/tests/test_context_set_project_owner.py +174 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_db_migration.py +67 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_db_schema.py +13 -7
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_db_session.py +31 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_doc_hub.py +5 -1
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_doc_render_planned_versions.py +3 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_finalize_version_closure.py +77 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_mind_governance.py +59 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_mind_proposal_extensions.py +9 -4
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_mind_read.py +185 -6
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_monitoring_run.py +85 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_project_group_boundary_guard.py +110 -1
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_project_group_routing_contracts.py +48 -25
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_report_build.py +179 -14
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_runtime_bundles.py +18 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_runtime_output_hygiene_contracts.py +1 -16
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_scheduled_run.py +498 -56
- project_agent-0.2.2/src/project_agent/application/context/get_project_context.py +0 -59
- project_agent-0.2.2/tests/test_context_project_summary.py +0 -322
- {project_agent-0.2.2 → project_agent-0.2.4}/README.md +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/setup.cfg +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/bootstrap/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/bootstrap/checkpoint.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/bootstrap/init.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/bootstrap/loop_state.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/context/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/context/binding_normalization.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/context/get_project_owner.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/context/get_task.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/context/get_user_context.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/context/list_projects.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/context/list_tasks.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/context/resolve_binding.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/context/resolve_group.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/context/resolve_user.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/context/search_user.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/context/upsert_user_identity.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/doc/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/doc_hub/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/loop/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/loop/enqueue.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/loop/run.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/mind/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/mind/delete_task.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/mind/milestones.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/mind/planned_versions.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/mind/set_tracking.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/mind/snooze_task_reminder.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/mind/switch_version.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/mind/write_task_update.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/monitoring/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/monitoring/evaluate_followups.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/monitoring/plan.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/monitoring/run.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/report/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/scheduled/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/version_closure/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/version_closure/evaluate.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/bootstrap/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/bootstrap/models.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/doc/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/doc_hub/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/doc_hub/models.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/loop/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/loop/models.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/mind/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/monitoring/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/monitoring/evaluator.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/project_context/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/report/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/scheduled/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/shared/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/shared/models.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/shared/project_mind_derived.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/shared/project_mind_readiness.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/shared/statuses.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/user/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/user/models.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/version_closure/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/version_closure/evaluator.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/domain/version_closure/models.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/infrastructure/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/infrastructure/clock/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/infrastructure/db/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/infrastructure/db/migration.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/infrastructure/db/session.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/app.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/__init__.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/bootstrap.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/db.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/loop.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/project_boundary.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/upgrade.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/interface/cli/commands/version_closure.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent.egg-info/dependency_links.txt +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent.egg-info/entry_points.txt +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent.egg-info/requires.txt +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent.egg-info/top_level.txt +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_cli_version.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_context_get_project_owner.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_context_resolve_binding.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_context_search_user.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_context_upsert_user_identity.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_loop_jobs.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_mind_proposal_signoff.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_monitoring_plan.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_overview_sync_hints.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_pending_state_idempotency.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_release_versioning.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_report_persistence.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_version_closure_trigger.py +0 -0
- {project_agent-0.2.2 → project_agent-0.2.4}/tests/test_version_status_auto_sync.py +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from typing import Any, Protocol
|
|
2
|
+
|
|
3
|
+
from project_agent.domain.project_context.models import AddProjectMemberResult, ProjectParticipantSummary
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ProjectStore(Protocol):
|
|
7
|
+
def find_by_id(self, project_id: str) -> Any: ...
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class UserStore(Protocol):
|
|
11
|
+
def find_by_id(self, user_id: str) -> Any: ...
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ParticipantWriteStore(Protocol):
|
|
15
|
+
def upsert_participant(self, payload: dict) -> dict: ...
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def add_project_member(
|
|
19
|
+
*,
|
|
20
|
+
project_id: str,
|
|
21
|
+
user_id: str,
|
|
22
|
+
project_store: ProjectStore,
|
|
23
|
+
user_store: UserStore,
|
|
24
|
+
participant_store: ParticipantWriteStore,
|
|
25
|
+
) -> AddProjectMemberResult:
|
|
26
|
+
if not project_store.find_by_id(project_id):
|
|
27
|
+
raise ValueError(f"project not found: {project_id}")
|
|
28
|
+
if not user_store.find_by_id(user_id):
|
|
29
|
+
raise ValueError(f"user not found: {user_id}")
|
|
30
|
+
|
|
31
|
+
participant = participant_store.upsert_participant(
|
|
32
|
+
{
|
|
33
|
+
"project_id": project_id,
|
|
34
|
+
"user_id": user_id,
|
|
35
|
+
"role": "member",
|
|
36
|
+
"status": "active",
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
return AddProjectMemberResult(
|
|
40
|
+
status="ok",
|
|
41
|
+
participant=ProjectParticipantSummary(
|
|
42
|
+
participant_id=participant["participant_id"],
|
|
43
|
+
project_id=participant["project_id"],
|
|
44
|
+
user_id=participant["user_id"],
|
|
45
|
+
role=participant["role"],
|
|
46
|
+
status=participant["status"],
|
|
47
|
+
created_at=participant.get("created_at"),
|
|
48
|
+
updated_at=participant.get("updated_at"),
|
|
49
|
+
),
|
|
50
|
+
)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from typing import Any, Protocol
|
|
2
|
+
|
|
3
|
+
from project_agent.application.shared.project_participants import build_project_participant_summaries
|
|
4
|
+
from project_agent.application.shared.user_refs import build_structured_user_ref
|
|
5
|
+
from project_agent.domain.project_context.models import ProjectContext
|
|
6
|
+
from project_agent.domain.shared.project_mind_derived import build_project_intro, collect_participants
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ProjectStore(Protocol):
|
|
10
|
+
def find_by_id(self, project_id: str) -> Any: ...
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BindingStore(Protocol):
|
|
14
|
+
def list_by_project_id(self, project_id: str) -> list[Any]: ...
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class PendingStateStore(Protocol):
|
|
18
|
+
def list_open_by_project_id(self, project_id: str) -> list[Any]: ...
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DocumentStore(Protocol):
|
|
22
|
+
def list_by_project_id(self, project_id: str) -> list[Any]: ...
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ParticipantStore(Protocol):
|
|
26
|
+
def list_by_project_id(self, project_id: str) -> list[Any]: ...
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class VersionStore(Protocol):
|
|
30
|
+
def list_by_project_id(self, project_id: str) -> list[Any]: ...
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class TaskStore(Protocol):
|
|
34
|
+
def list_by_project_id(self, project_id: str, task_id: str | None = None) -> list[Any]: ...
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class UserStore(Protocol):
|
|
38
|
+
def find_by_id(self, user_id: str) -> Any: ...
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class UserIdentityStore(Protocol):
|
|
42
|
+
def list_by_user_id(self, user_id: str) -> list[Any]: ...
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def get_project_context(
|
|
46
|
+
*,
|
|
47
|
+
project_id: str,
|
|
48
|
+
channel: str | None = None,
|
|
49
|
+
project_store: ProjectStore,
|
|
50
|
+
binding_store: BindingStore | None = None,
|
|
51
|
+
pending_state_store: PendingStateStore | None = None,
|
|
52
|
+
document_store: DocumentStore | None = None,
|
|
53
|
+
participant_store: ParticipantStore | None = None,
|
|
54
|
+
version_store: VersionStore | None = None,
|
|
55
|
+
task_store: TaskStore | None = None,
|
|
56
|
+
user_store: UserStore | None = None,
|
|
57
|
+
identity_store: UserIdentityStore | None = None,
|
|
58
|
+
) -> ProjectContext | None:
|
|
59
|
+
project = project_store.find_by_id(project_id)
|
|
60
|
+
|
|
61
|
+
if not project:
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
bindings = []
|
|
65
|
+
if binding_store is not None:
|
|
66
|
+
bindings = binding_store.list_by_project_id(project_id)
|
|
67
|
+
|
|
68
|
+
pending_states = []
|
|
69
|
+
if pending_state_store is not None:
|
|
70
|
+
pending_states = pending_state_store.list_open_by_project_id(project_id)
|
|
71
|
+
|
|
72
|
+
documents = []
|
|
73
|
+
if document_store is not None:
|
|
74
|
+
documents = document_store.list_by_project_id(project_id)
|
|
75
|
+
|
|
76
|
+
participant_rows = []
|
|
77
|
+
if participant_store is not None:
|
|
78
|
+
participant_rows = participant_store.list_by_project_id(project_id)
|
|
79
|
+
|
|
80
|
+
versions = []
|
|
81
|
+
if version_store is not None:
|
|
82
|
+
versions = version_store.list_by_project_id(project_id)
|
|
83
|
+
|
|
84
|
+
tasks = []
|
|
85
|
+
if task_store is not None:
|
|
86
|
+
tasks = task_store.list_by_project_id(project_id)
|
|
87
|
+
|
|
88
|
+
owner_user = build_structured_user_ref(
|
|
89
|
+
user_id=project.get("owner_user_id"),
|
|
90
|
+
user_store=user_store,
|
|
91
|
+
user_identity_store=identity_store,
|
|
92
|
+
identity_cache={},
|
|
93
|
+
user_cache={},
|
|
94
|
+
)
|
|
95
|
+
user_cache: dict[str, dict | None] = {}
|
|
96
|
+
identity_cache: dict[str, list[dict]] = {}
|
|
97
|
+
participant_summaries = build_project_participant_summaries(
|
|
98
|
+
participant_user_ids=collect_participants(
|
|
99
|
+
versions=versions,
|
|
100
|
+
tasks=tasks,
|
|
101
|
+
participants=participant_rows,
|
|
102
|
+
),
|
|
103
|
+
participant_rows=participant_rows,
|
|
104
|
+
owner_user_id=project.get("owner_user_id"),
|
|
105
|
+
user_store=user_store,
|
|
106
|
+
user_identity_store=identity_store,
|
|
107
|
+
channel=channel,
|
|
108
|
+
user_cache=user_cache,
|
|
109
|
+
identity_cache=identity_cache,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
return ProjectContext(
|
|
113
|
+
project_id=project_id,
|
|
114
|
+
owner_user=owner_user,
|
|
115
|
+
primary_goal=project.get("primary_goal"),
|
|
116
|
+
project_intro=build_project_intro(project=project, versions=versions, tasks=tasks),
|
|
117
|
+
lifecycle_status=project["lifecycle_status"],
|
|
118
|
+
mind_stage=project["mind_stage"],
|
|
119
|
+
current_revision_id=project.get("current_revision_id"),
|
|
120
|
+
current_version_id=project.get("current_version_id"),
|
|
121
|
+
tracking_mode=project.get("tracking_mode") or "active",
|
|
122
|
+
tracking_paused_reason=project.get("tracking_paused_reason"),
|
|
123
|
+
tracking_paused_at=project.get("tracking_paused_at"),
|
|
124
|
+
bindings=bindings,
|
|
125
|
+
participants=participant_summaries,
|
|
126
|
+
pending_states=pending_states,
|
|
127
|
+
documents=documents,
|
|
128
|
+
)
|
{project_agent-0.2.2 → project_agent-0.2.4}/src/project_agent/application/context/project_summary.py
RENAMED
|
@@ -45,7 +45,7 @@ def build_project_summary(
|
|
|
45
45
|
project_name=project["project_name"],
|
|
46
46
|
team_task=_build_team_task_summary(tasks, today=today, tz=tz),
|
|
47
47
|
personal=_build_personal_task_summary(tasks, user_id=user_id, today=today, tz=tz),
|
|
48
|
-
updated_at=project.get("last_updated_at"),
|
|
48
|
+
updated_at=_utc_millis(project.get("last_updated_at")),
|
|
49
49
|
)
|
|
50
50
|
|
|
51
51
|
|
|
@@ -62,9 +62,18 @@ def _build_team_task_summary(
|
|
|
62
62
|
today: date,
|
|
63
63
|
tz: ZoneInfo,
|
|
64
64
|
) -> TeamTaskSummary:
|
|
65
|
+
new_assigned_today_tasks = [
|
|
66
|
+
task for task in tasks if _is_today(_task_value(task, "created_at"), today, tz)
|
|
67
|
+
]
|
|
68
|
+
new_assigned_today = len(new_assigned_today_tasks)
|
|
69
|
+
if new_assigned_today_tasks and all(
|
|
70
|
+
is_done_status(_task_value(task, "task_status")) for task in new_assigned_today_tasks
|
|
71
|
+
):
|
|
72
|
+
new_assigned_today = 0
|
|
73
|
+
|
|
65
74
|
return TeamTaskSummary(
|
|
66
75
|
status="HAS_TASK" if tasks else "NO_TASK",
|
|
67
|
-
new_assigned_today=
|
|
76
|
+
new_assigned_today=new_assigned_today,
|
|
68
77
|
completed_today=sum(
|
|
69
78
|
1
|
|
70
79
|
for task in tasks
|
|
@@ -142,3 +151,10 @@ def _parse_datetime(value: Any, *, tz: ZoneInfo) -> datetime | None:
|
|
|
142
151
|
if parsed.tzinfo is None:
|
|
143
152
|
parsed = parsed.replace(tzinfo=UTC)
|
|
144
153
|
return parsed.astimezone(tz)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _utc_millis(value: Any) -> int | None:
|
|
157
|
+
parsed = _parse_datetime(value, tz=ZoneInfo("UTC"))
|
|
158
|
+
if parsed is None:
|
|
159
|
+
return None
|
|
160
|
+
return int(parsed.timestamp() * 1000)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from typing import Any, Protocol
|
|
2
|
+
|
|
3
|
+
from project_agent.domain.project_context.models import SetProjectOwnerResult
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ProjectStore(Protocol):
|
|
7
|
+
def find_by_id(self, project_id: str) -> Any: ...
|
|
8
|
+
|
|
9
|
+
def update_owner_user_id(self, *, project_id: str, owner_user_id: str) -> dict: ...
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class UserStore(Protocol):
|
|
13
|
+
def find_by_id(self, user_id: str) -> Any: ...
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ParticipantWriteStore(Protocol):
|
|
17
|
+
def upsert_participant(self, payload: dict) -> dict: ...
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def set_project_owner(
|
|
21
|
+
*,
|
|
22
|
+
project_id: str,
|
|
23
|
+
user_id: str,
|
|
24
|
+
project_store: ProjectStore,
|
|
25
|
+
user_store: UserStore,
|
|
26
|
+
participant_store: ParticipantWriteStore,
|
|
27
|
+
) -> SetProjectOwnerResult:
|
|
28
|
+
project = project_store.find_by_id(project_id)
|
|
29
|
+
if not project:
|
|
30
|
+
raise ValueError(f"project not found: {project_id}")
|
|
31
|
+
if not user_store.find_by_id(user_id):
|
|
32
|
+
raise ValueError(f"user not found: {user_id}")
|
|
33
|
+
|
|
34
|
+
previous_owner_user_id = project.get("owner_user_id")
|
|
35
|
+
project_store.update_owner_user_id(project_id=project_id, owner_user_id=user_id)
|
|
36
|
+
participant_store.upsert_participant(
|
|
37
|
+
{
|
|
38
|
+
"project_id": project_id,
|
|
39
|
+
"user_id": user_id,
|
|
40
|
+
"role": "owner",
|
|
41
|
+
"status": "active",
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
if previous_owner_user_id and previous_owner_user_id != user_id:
|
|
45
|
+
participant_store.upsert_participant(
|
|
46
|
+
{
|
|
47
|
+
"project_id": project_id,
|
|
48
|
+
"user_id": previous_owner_user_id,
|
|
49
|
+
"role": "member",
|
|
50
|
+
"status": "active",
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return SetProjectOwnerResult(
|
|
55
|
+
status="ok",
|
|
56
|
+
project_id=project_id,
|
|
57
|
+
owner_user_id=user_id,
|
|
58
|
+
previous_owner_user_id=previous_owner_user_id,
|
|
59
|
+
)
|
|
@@ -34,6 +34,10 @@ class ParticipantStore(Protocol):
|
|
|
34
34
|
def list_by_project_id(self, project_id: str) -> list[Any]: ...
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
class UserStore(Protocol):
|
|
38
|
+
def find_by_id(self, user_id: str) -> Any: ...
|
|
39
|
+
|
|
40
|
+
|
|
37
41
|
class DocumentStore(Protocol):
|
|
38
42
|
def list_by_project_id(self, project_id: str) -> list[Any]: ...
|
|
39
43
|
|
|
@@ -74,9 +78,12 @@ def render_project_document(
|
|
|
74
78
|
document_store: DocumentStore | None = None,
|
|
75
79
|
doc_hub_entry_store: DocHubEntryStore | None = None,
|
|
76
80
|
channel: str | None = None,
|
|
81
|
+
provider: str | None = None,
|
|
82
|
+
user_store: UserStore | None = None,
|
|
77
83
|
user_identity_store: Any | None = None,
|
|
78
84
|
) -> DocRenderResult | None:
|
|
79
85
|
del template_ref
|
|
86
|
+
provider = provider or channel
|
|
80
87
|
|
|
81
88
|
project = project_store.find_by_id(project_id)
|
|
82
89
|
if not project:
|
|
@@ -97,7 +104,9 @@ def render_project_document(
|
|
|
97
104
|
tasks=tasks,
|
|
98
105
|
version_id=version_id,
|
|
99
106
|
)
|
|
100
|
-
|
|
107
|
+
_enrich_sections_with_user_display_values(sections, user_store)
|
|
108
|
+
if provider == "feishu":
|
|
109
|
+
_enrich_sections_with_channel_identities(sections, "feishu", user_identity_store)
|
|
101
110
|
return _with_render_hash(DocRenderResult(
|
|
102
111
|
project_id=project_id,
|
|
103
112
|
doc_kind=doc_kind,
|
|
@@ -190,7 +199,9 @@ def render_project_document(
|
|
|
190
199
|
),
|
|
191
200
|
]
|
|
192
201
|
title = project["project_name"]
|
|
193
|
-
|
|
202
|
+
_enrich_sections_with_user_display_values(sections, user_store)
|
|
203
|
+
if provider == "feishu":
|
|
204
|
+
_enrich_sections_with_channel_identities(sections, "feishu", user_identity_store)
|
|
194
205
|
return _with_render_hash(DocRenderResult(
|
|
195
206
|
project_id=project_id,
|
|
196
207
|
doc_kind=doc_kind,
|
|
@@ -204,7 +215,7 @@ def render_project_document(
|
|
|
204
215
|
project_id=project_id,
|
|
205
216
|
doc_hub_entry_store=doc_hub_entry_store,
|
|
206
217
|
)
|
|
207
|
-
sections = _build_docs_index_sections(entries=entries, relations=relations,
|
|
218
|
+
sections = _build_docs_index_sections(entries=entries, relations=relations, provider=provider)
|
|
208
219
|
title = f"{project['project_name']} Docs Index"
|
|
209
220
|
return _with_render_hash(DocRenderResult(
|
|
210
221
|
project_id=project_id,
|
|
@@ -222,11 +233,11 @@ def render_project_document(
|
|
|
222
233
|
planned_versions = _planned_versions(versions=versions, current_version_id=current_version_id)
|
|
223
234
|
past_versions = _past_versions(versions=versions)
|
|
224
235
|
documents = document_store.list_by_project_id(project_id) if document_store is not None else []
|
|
225
|
-
snapshot_links = _version_snapshot_links(documents=documents,
|
|
236
|
+
snapshot_links = _version_snapshot_links(documents=documents, provider=provider)
|
|
226
237
|
docs_index_url = _single_document_link(
|
|
227
238
|
documents=documents,
|
|
228
239
|
doc_kind="docs_index",
|
|
229
|
-
|
|
240
|
+
provider=provider,
|
|
230
241
|
)
|
|
231
242
|
sections = _build_overview_sections(
|
|
232
243
|
project=project,
|
|
@@ -241,7 +252,9 @@ def render_project_document(
|
|
|
241
252
|
docs_index_url=docs_index_url,
|
|
242
253
|
)
|
|
243
254
|
title = f"{project['project_name']} Overview"
|
|
244
|
-
|
|
255
|
+
_enrich_sections_with_user_display_values(sections, user_store)
|
|
256
|
+
if provider == "feishu":
|
|
257
|
+
_enrich_sections_with_channel_identities(sections, "feishu", user_identity_store)
|
|
245
258
|
return _with_render_hash(DocRenderResult(
|
|
246
259
|
project_id=project_id,
|
|
247
260
|
doc_kind=doc_kind,
|
|
@@ -265,18 +278,38 @@ def _load_doc_hub_index_inputs(
|
|
|
265
278
|
|
|
266
279
|
|
|
267
280
|
def _with_render_hash(result: DocRenderResult) -> DocRenderResult:
|
|
268
|
-
payload =
|
|
281
|
+
payload = _strip_render_hash_ignored_hints(
|
|
282
|
+
result.model_dump(mode="json", by_alias=True, exclude={"render_hash", "status"})
|
|
283
|
+
)
|
|
269
284
|
encoded = json.dumps(payload, ensure_ascii=True, sort_keys=True, separators=(",", ":"))
|
|
270
285
|
return result.model_copy(update={"render_hash": hashlib.sha256(encoded.encode("utf-8")).hexdigest()})
|
|
271
286
|
|
|
272
287
|
|
|
288
|
+
def _strip_render_hash_ignored_hints(value: Any) -> Any:
|
|
289
|
+
if isinstance(value, dict):
|
|
290
|
+
return {
|
|
291
|
+
key: _strip_render_hash_ignored_hints(item)
|
|
292
|
+
for key, item in value.items()
|
|
293
|
+
if key
|
|
294
|
+
not in {
|
|
295
|
+
"displayValue",
|
|
296
|
+
"userDisplayNames",
|
|
297
|
+
"task_owner_display_value",
|
|
298
|
+
"planned_version_owner_display_value",
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if isinstance(value, list):
|
|
302
|
+
return [_strip_render_hash_ignored_hints(item) for item in value]
|
|
303
|
+
return value
|
|
304
|
+
|
|
305
|
+
|
|
273
306
|
def _build_docs_index_sections(
|
|
274
307
|
*,
|
|
275
308
|
entries: list[Any],
|
|
276
309
|
relations: list[Any],
|
|
277
|
-
|
|
310
|
+
provider: str | None,
|
|
278
311
|
) -> list[DocSection]:
|
|
279
|
-
index_payload = _build_docs_index_payload(entries=entries, relations=relations,
|
|
312
|
+
index_payload = _build_docs_index_payload(entries=entries, relations=relations, provider=provider)
|
|
280
313
|
sections = [
|
|
281
314
|
DocSection(
|
|
282
315
|
heading="Registered Documents",
|
|
@@ -297,13 +330,13 @@ def _build_docs_index_payload(
|
|
|
297
330
|
*,
|
|
298
331
|
entries: list[Any],
|
|
299
332
|
relations: list[Any],
|
|
300
|
-
|
|
333
|
+
provider: str | None,
|
|
301
334
|
) -> dict[str, list[dict]]:
|
|
302
335
|
rows = []
|
|
303
336
|
filtered_entry_ids: set[str] = set()
|
|
304
337
|
entry_titles_by_id: dict[str, str] = {}
|
|
305
338
|
for entry in entries:
|
|
306
|
-
if
|
|
339
|
+
if provider is not None and entry.get("provider") != provider:
|
|
307
340
|
continue
|
|
308
341
|
entry_id = entry.get("entry_id")
|
|
309
342
|
filtered_entry_ids.add(entry_id)
|
|
@@ -341,6 +374,45 @@ def _build_docs_index_payload(
|
|
|
341
374
|
return {"documents": rows, "relations": relation_rows}
|
|
342
375
|
|
|
343
376
|
|
|
377
|
+
def _enrich_sections_with_user_display_values(
|
|
378
|
+
sections: list[DocSection],
|
|
379
|
+
user_store: UserStore | None,
|
|
380
|
+
) -> None:
|
|
381
|
+
if user_store is None:
|
|
382
|
+
return
|
|
383
|
+
|
|
384
|
+
user_ids: set[str] = set()
|
|
385
|
+
_collect_user_ids(sections, user_ids)
|
|
386
|
+
if not user_ids:
|
|
387
|
+
return
|
|
388
|
+
|
|
389
|
+
display_names: dict[str, str] = {}
|
|
390
|
+
for uid in user_ids:
|
|
391
|
+
user = user_store.find_by_id(uid)
|
|
392
|
+
display_names[uid] = (user or {}).get("display_name") or uid
|
|
393
|
+
|
|
394
|
+
for section in sections:
|
|
395
|
+
for field in section.payload.get("fields", []):
|
|
396
|
+
value = field.get("value", "")
|
|
397
|
+
if not isinstance(value, str):
|
|
398
|
+
continue
|
|
399
|
+
uids = [token for token in value.split(", ") if token.startswith("usr_")]
|
|
400
|
+
if not uids:
|
|
401
|
+
continue
|
|
402
|
+
names = [display_names.get(uid, uid) for uid in uids]
|
|
403
|
+
field["displayValue"] = ", ".join(names)
|
|
404
|
+
if len(names) > 1:
|
|
405
|
+
field["userDisplayNames"] = names
|
|
406
|
+
for item in section.payload.get("tasks", []):
|
|
407
|
+
owner = item.get("task_owner", "")
|
|
408
|
+
if isinstance(owner, str) and owner.startswith("usr_"):
|
|
409
|
+
item["task_owner_display_value"] = display_names.get(owner, owner)
|
|
410
|
+
for item in section.payload.get("versions", []):
|
|
411
|
+
owner = item.get("planned_version_owner", "")
|
|
412
|
+
if isinstance(owner, str) and owner.startswith("usr_"):
|
|
413
|
+
item["planned_version_owner_display_value"] = display_names.get(owner, owner)
|
|
414
|
+
|
|
415
|
+
|
|
344
416
|
def _enrich_sections_with_channel_identities(
|
|
345
417
|
sections: list[DocSection],
|
|
346
418
|
channel: str | None,
|
|
@@ -535,6 +607,11 @@ def _build_overview_sections(
|
|
|
535
607
|
"label": "Goal",
|
|
536
608
|
"value": (current_version or {}).get("version_goal") or "TBD",
|
|
537
609
|
},
|
|
610
|
+
{
|
|
611
|
+
"name": "version_summary",
|
|
612
|
+
"label": "Version Summary",
|
|
613
|
+
"value": (current_version or {}).get("version_summary") or "TBD",
|
|
614
|
+
},
|
|
538
615
|
{
|
|
539
616
|
"name": "version_owner",
|
|
540
617
|
"label": "Owner",
|
|
@@ -693,6 +770,7 @@ def _build_planned_versions_payload(*, planned_versions: list[dict], current_ver
|
|
|
693
770
|
"planned_version_name": "TBD",
|
|
694
771
|
"planned_version_milestone": "TBD",
|
|
695
772
|
"planned_version_goal": "TBD",
|
|
773
|
+
"planned_version_summary": "TBD",
|
|
696
774
|
"planned_version_owner": "TBD",
|
|
697
775
|
"planned_version_target_start_date": "TBD",
|
|
698
776
|
"planned_version_target_start_date_note": "(待补充)",
|
|
@@ -710,6 +788,7 @@ def _build_planned_versions_payload(*, planned_versions: list[dict], current_ver
|
|
|
710
788
|
"planned_version_name": version.get("version_name") or "TBD",
|
|
711
789
|
"planned_version_milestone": _display_milestone(version),
|
|
712
790
|
"planned_version_goal": version.get("version_goal") or "TBD",
|
|
791
|
+
"planned_version_summary": version.get("version_summary") or "TBD",
|
|
713
792
|
"planned_version_owner": version.get("owner_user_id") or "TBD",
|
|
714
793
|
"planned_version_target_start_date": version.get("start_date") or "TBD",
|
|
715
794
|
"planned_version_target_start_date_note": _planned_start_note(
|
|
@@ -765,6 +844,7 @@ def _build_version_snapshot(
|
|
|
765
844
|
"fields": [
|
|
766
845
|
{"name": "version_name", "label": "Version Name", "value": version.get("version_name") or "TBD"},
|
|
767
846
|
{"name": "version_goal", "label": "Goal", "value": version.get("version_goal") or "TBD"},
|
|
847
|
+
{"name": "version_summary", "label": "Version Summary", "value": version.get("version_summary") or "TBD"},
|
|
768
848
|
{"name": "version_owner", "label": "Owner", "value": version.get("owner_user_id") or "TBD"},
|
|
769
849
|
{"name": "start_date", "label": "Start Date", "value": version.get("start_date") or "TBD"},
|
|
770
850
|
{
|
|
@@ -875,18 +955,19 @@ def _build_past_version_snapshots_payload(past_versions: list[dict], *, snapshot
|
|
|
875
955
|
}
|
|
876
956
|
|
|
877
957
|
|
|
878
|
-
def _version_snapshot_links(*, documents: list[dict],
|
|
958
|
+
def _version_snapshot_links(*, documents: list[dict], provider: str | None) -> dict[str, str]:
|
|
879
959
|
links: dict[str, str] = {}
|
|
880
960
|
for document in sorted(
|
|
881
961
|
documents,
|
|
882
962
|
key=lambda item: (
|
|
883
|
-
item.get("channel") or "",
|
|
963
|
+
item.get("provider") or item.get("channel") or "",
|
|
884
964
|
item.get("document_id") or "",
|
|
885
965
|
),
|
|
886
966
|
):
|
|
887
967
|
if document.get("doc_kind") != "version_snapshot":
|
|
888
968
|
continue
|
|
889
|
-
|
|
969
|
+
document_provider = document.get("provider") or document.get("channel")
|
|
970
|
+
if provider is not None and document_provider != provider:
|
|
890
971
|
continue
|
|
891
972
|
version_id = document.get("version_id")
|
|
892
973
|
if not version_id or version_id in links:
|
|
@@ -897,17 +978,18 @@ def _version_snapshot_links(*, documents: list[dict], channel: str | None) -> di
|
|
|
897
978
|
return links
|
|
898
979
|
|
|
899
980
|
|
|
900
|
-
def _single_document_link(*, documents: list[dict], doc_kind: str,
|
|
981
|
+
def _single_document_link(*, documents: list[dict], doc_kind: str, provider: str | None) -> str:
|
|
901
982
|
for document in sorted(
|
|
902
983
|
documents,
|
|
903
984
|
key=lambda item: (
|
|
904
|
-
item.get("channel") or "",
|
|
985
|
+
item.get("provider") or item.get("channel") or "",
|
|
905
986
|
item.get("document_id") or "",
|
|
906
987
|
),
|
|
907
988
|
):
|
|
908
989
|
if document.get("doc_kind") != doc_kind:
|
|
909
990
|
continue
|
|
910
|
-
|
|
991
|
+
document_provider = document.get("provider") or document.get("channel")
|
|
992
|
+
if provider is not None and document_provider != provider:
|
|
911
993
|
continue
|
|
912
994
|
url = document.get("url")
|
|
913
995
|
if url and document.get("last_verified_render_hash"):
|
|
@@ -40,7 +40,8 @@ def sync_project_document(
|
|
|
40
40
|
project_id: str,
|
|
41
41
|
doc_kind: str,
|
|
42
42
|
version_id: str | None,
|
|
43
|
-
|
|
43
|
+
provider: str,
|
|
44
|
+
channel: str | None,
|
|
44
45
|
trigger_kind: str,
|
|
45
46
|
template_ref: str | None,
|
|
46
47
|
force: bool,
|
|
@@ -50,6 +51,7 @@ def sync_project_document(
|
|
|
50
51
|
document_store: DocumentStore,
|
|
51
52
|
doc_hub_entry_store: DocHubEntryStore | None = None,
|
|
52
53
|
participant_store: ParticipantStore | None = None,
|
|
54
|
+
user_store: Any | None = None,
|
|
53
55
|
user_identity_store: Any | None = None,
|
|
54
56
|
) -> DocSyncResult | None:
|
|
55
57
|
del trigger_kind
|
|
@@ -63,7 +65,7 @@ def sync_project_document(
|
|
|
63
65
|
for document in document_store.list_by_project_id(project_id):
|
|
64
66
|
if (
|
|
65
67
|
document["doc_kind"] == doc_kind
|
|
66
|
-
and document
|
|
68
|
+
and (document.get("provider") or document.get("channel")) == provider
|
|
67
69
|
and document.get("version_id") == version_id
|
|
68
70
|
):
|
|
69
71
|
existing_document = document
|
|
@@ -85,6 +87,8 @@ def sync_project_document(
|
|
|
85
87
|
document_store=document_store,
|
|
86
88
|
doc_hub_entry_store=doc_hub_entry_store,
|
|
87
89
|
channel=channel,
|
|
90
|
+
provider=provider,
|
|
91
|
+
user_store=user_store,
|
|
88
92
|
user_identity_store=user_identity_store,
|
|
89
93
|
)
|
|
90
94
|
|
|
@@ -100,6 +104,7 @@ def sync_project_document(
|
|
|
100
104
|
project_id=project_id,
|
|
101
105
|
doc_kind=doc_kind,
|
|
102
106
|
version_id=version_id,
|
|
107
|
+
provider=provider,
|
|
103
108
|
channel=channel,
|
|
104
109
|
source_revision_id=source_revision_id,
|
|
105
110
|
last_synced_revision_id=last_synced_revision_id,
|
|
@@ -116,6 +121,7 @@ def sync_project_document(
|
|
|
116
121
|
project_id=project_id,
|
|
117
122
|
doc_kind=doc_kind,
|
|
118
123
|
version_id=version_id,
|
|
124
|
+
provider=provider,
|
|
119
125
|
channel=channel,
|
|
120
126
|
source_revision_id=source_revision_id,
|
|
121
127
|
last_synced_revision_id=last_synced_revision_id,
|
|
@@ -126,6 +132,7 @@ def sync_project_document(
|
|
|
126
132
|
project_id=project_id,
|
|
127
133
|
doc_kind=doc_kind,
|
|
128
134
|
version_id=version_id,
|
|
135
|
+
provider=provider,
|
|
129
136
|
channel=channel,
|
|
130
137
|
last_synced_revision_id=source_revision_id,
|
|
131
138
|
render_hash=render.render_hash if render is not None else None,
|
|
@@ -21,7 +21,8 @@ def writeback_document(
|
|
|
21
21
|
project_id: str,
|
|
22
22
|
doc_kind: str,
|
|
23
23
|
version_id: str | None,
|
|
24
|
-
|
|
24
|
+
provider: str,
|
|
25
|
+
channel: str | None,
|
|
25
26
|
external_doc_id: str | None,
|
|
26
27
|
url: str | None,
|
|
27
28
|
last_synced_revision_id: str | None,
|
|
@@ -48,6 +49,7 @@ def writeback_document(
|
|
|
48
49
|
"project_id": project_id,
|
|
49
50
|
"doc_kind": doc_kind,
|
|
50
51
|
"version_id": version_id,
|
|
52
|
+
"provider": provider,
|
|
51
53
|
"channel": channel,
|
|
52
54
|
"external_doc_id": external_doc_id,
|
|
53
55
|
"url": url,
|
|
@@ -60,7 +62,8 @@ def writeback_document(
|
|
|
60
62
|
document_id=document["document_id"],
|
|
61
63
|
doc_kind=document["doc_kind"],
|
|
62
64
|
version_id=document.get("version_id"),
|
|
63
|
-
|
|
65
|
+
provider=document["provider"],
|
|
66
|
+
channel=document.get("channel"),
|
|
64
67
|
external_doc_id=document.get("external_doc_id"),
|
|
65
68
|
url=document.get("url"),
|
|
66
69
|
last_synced_revision_id=document.get("last_synced_revision_id"),
|
|
@@ -248,7 +248,7 @@ def ensure_system_documents(
|
|
|
248
248
|
document_rows_by_kind = {
|
|
249
249
|
(document["doc_kind"], document.get("version_id")): document
|
|
250
250
|
for document in existing_documents
|
|
251
|
-
if document.get("channel") == provider
|
|
251
|
+
if (document.get("provider") or document.get("channel")) == provider
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
entries: list[DocHubEntry] = []
|
|
@@ -270,7 +270,9 @@ def ensure_system_documents(
|
|
|
270
270
|
entries.append(_doc_hub_entry(entry))
|
|
271
271
|
|
|
272
272
|
for document in existing_documents:
|
|
273
|
-
if document["doc_kind"] != "version_snapshot"
|
|
273
|
+
if document["doc_kind"] != "version_snapshot":
|
|
274
|
+
continue
|
|
275
|
+
if (document.get("provider") or document.get("channel")) != provider:
|
|
274
276
|
continue
|
|
275
277
|
version_id = document.get("version_id")
|
|
276
278
|
title = _system_doc_title(
|
|
@@ -248,6 +248,7 @@ def _proposal_kwargs(fact: CandidateFact) -> dict[str, Any]:
|
|
|
248
248
|
"task_dependencies": _optional_list_payload_value(payload, "task_dependencies"),
|
|
249
249
|
"version_name": _payload_value(payload, "version_name"),
|
|
250
250
|
"version_goal": _payload_value(payload, "version_goal"),
|
|
251
|
+
"version_summary": _payload_value(payload, "version_summary"),
|
|
251
252
|
"version_start_date": _payload_value(payload, "version_start_date"),
|
|
252
253
|
"target_end_date": _payload_value(payload, "target_end_date"),
|
|
253
254
|
"version_deliverables": _list_payload_value(payload, "version_deliverables"),
|