teams-transcripts 0.5.1__tar.gz → 0.5.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/.gitignore +1 -0
  2. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/.gitlab-ci.yml +20 -8
  3. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/PKG-INFO +41 -6
  4. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/README.md +40 -5
  5. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/pyproject.toml +8 -1
  6. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/scripts/verify_distribution.py +4 -0
  7. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_component_flags.py +9 -2
  8. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/uv.lock +1 -1
  9. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/bin/teams-transcripts +0 -0
  10. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/bin/teams-transcripts-mcp +0 -0
  11. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/lefthook.yml +0 -0
  12. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/legacy/__init__.py +0 -0
  13. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/legacy/transcript_download.py +0 -0
  14. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/pyrightconfig.json +0 -0
  15. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/__init__.py +0 -0
  16. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/__main__.py +0 -0
  17. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/adapters/__init__.py +0 -0
  18. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/adapters/cdp/__init__.py +0 -0
  19. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/adapters/cdp/browser.py +0 -0
  20. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/adapters/cdp/connection.py +0 -0
  21. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/adapters/cdp/helpers.py +0 -0
  22. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/adapters/cdp/teams.py +0 -0
  23. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/adapters/vertex.py +0 -0
  24. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/domain/__init__.py +0 -0
  25. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/domain/chat.py +0 -0
  26. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/domain/html.py +0 -0
  27. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/domain/mcps.py +0 -0
  28. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/domain/models.py +0 -0
  29. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/domain/participants.py +0 -0
  30. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/domain/scoring.py +0 -0
  31. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/domain/speakers.py +0 -0
  32. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/domain/summary.py +0 -0
  33. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/domain/timestamps.py +0 -0
  34. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/domain/vtt.py +0 -0
  35. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/infrastructure/__init__.py +0 -0
  36. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/infrastructure/config.py +0 -0
  37. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/infrastructure/errors.py +0 -0
  38. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/infrastructure/logging.py +0 -0
  39. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/infrastructure/signals.py +0 -0
  40. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/mcp_server.py +0 -0
  41. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/ports/__init__.py +0 -0
  42. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/ports/agent.py +0 -0
  43. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/ports/browser.py +0 -0
  44. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/services/__init__.py +0 -0
  45. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/services/downloader.py +0 -0
  46. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/services/extraction.py +0 -0
  47. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/services/listing.py +0 -0
  48. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/services/navigation.py +0 -0
  49. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/services/output.py +0 -0
  50. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/teams_transcripts/services/tenant.py +0 -0
  51. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/conftest.py +0 -0
  52. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/fakes/__init__.py +0 -0
  53. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/fakes/agent.py +0 -0
  54. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/fakes/browser.py +0 -0
  55. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_adapters_cdp_browser.py +0 -0
  56. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_adapters_cdp_connection.py +0 -0
  57. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_adapters_cdp_helpers.py +0 -0
  58. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_adapters_cdp_teams.py +0 -0
  59. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_adapters_vertex.py +0 -0
  60. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_append_chat.py +0 -0
  61. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_build_result_summary.py +0 -0
  62. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_cli_validation.py +0 -0
  63. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_domain_mcps.py +0 -0
  64. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_domain_models.py +0 -0
  65. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_domain_participants.py +0 -0
  66. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_env_vars.py +0 -0
  67. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_error_json.py +0 -0
  68. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_force_restart_cli.py +0 -0
  69. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_infrastructure_config.py +0 -0
  70. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_infrastructure_errors.py +0 -0
  71. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_infrastructure_logging.py +0 -0
  72. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_infrastructure_signals.py +0 -0
  73. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_log_and_exit.py +0 -0
  74. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_mcp_server.py +0 -0
  75. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_merge_vtt_parts.py +0 -0
  76. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_occurrence_matching.py +0 -0
  77. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_parse_meeting_times.py +0 -0
  78. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_parse_vtt_cues.py +0 -0
  79. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_prepend_vtt_metadata.py +0 -0
  80. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_regression_iframe_timing.py +0 -0
  81. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_resolve_chat_author.py +0 -0
  82. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_resolve_config.py +0 -0
  83. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_safe_teams_restart.py +0 -0
  84. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_search_scoring.py +0 -0
  85. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_services_downloader.py +0 -0
  86. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_services_extraction.py +0 -0
  87. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_services_listing.py +0 -0
  88. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_services_navigation.py +0 -0
  89. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_services_tenant.py +0 -0
  90. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_signal_handling.py +0 -0
  91. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_speaker_mapping.py +0 -0
  92. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_strip_html.py +0 -0
  93. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_tenant_config.py +0 -0
  94. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_timestamp_fill_and_discontinuity.py +0 -0
  95. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_timestamp_utils.py +0 -0
  96. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_verbose_dead_code.py +0 -0
  97. {teams_transcripts-0.5.1 → teams_transcripts-0.5.2}/tests/test_verify_output.py +0 -0
@@ -2,6 +2,7 @@ __pycache__
2
2
  .claude
3
3
  .git
4
4
  .ruff_cache
5
+ .uv-cache
5
6
  .venv
6
7
  .opencode
7
8
 
@@ -1,17 +1,14 @@
1
1
  stages:
2
2
  - verify
3
3
  - package
4
+ - publish
5
+
6
+ variables:
7
+ UV_CACHE_DIR: "/tmp/uv-cache"
4
8
 
5
9
  default:
6
10
  image: ghcr.io/astral-sh/uv:python3.13-bookworm-slim
7
- variables:
8
- UV_CACHE_DIR: "$CI_PROJECT_DIR/.uv-cache"
9
- cache:
10
- key:
11
- files:
12
- - uv.lock
13
- paths:
14
- - .uv-cache/
11
+
15
12
  verify:
16
13
  stage: verify
17
14
  parallel:
@@ -43,3 +40,18 @@ package:
43
40
  artifacts:
44
41
  paths:
45
42
  - dist/
43
+
44
+ publish:
45
+ stage: publish
46
+ dependencies:
47
+ - package
48
+ id_tokens:
49
+ PYPI_ID_TOKEN:
50
+ aud: pypi
51
+ environment:
52
+ name: pypi
53
+ resource_group: pypi
54
+ rules:
55
+ - if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+([a-zA-Z0-9.-]+)?$/'
56
+ script:
57
+ - uv publish --trusted-publishing always dist/*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: teams-transcripts
3
- Version: 0.5.1
3
+ Version: 0.5.2
4
4
  Summary: Download Microsoft Teams transcripts, chat, and meeting metadata from the macOS desktop app
5
5
  Project-URL: Homepage, https://gitlab.com/jamiemills-choreograph/teams-transcripts
6
6
  Project-URL: Repository, https://gitlab.com/jamiemills-choreograph/teams-transcripts
@@ -53,11 +53,11 @@ The MCP server has a different executable name from the PyPI package, so use
53
53
  `--from` to tell `uvx` which package provides it:
54
54
 
55
55
  ```sh
56
- uvx --from 'teams-transcripts==0.5.1' teams-transcripts-mcp
56
+ uvx --from 'teams-transcripts==0.5.2' teams-transcripts-mcp
57
57
  uvx --from teams-transcripts transcript-download --help
58
58
  ```
59
59
 
60
- Use `teams-transcripts==0.5.1` for a reproducible MCP configuration, or replace
60
+ Use `teams-transcripts==0.5.2` for a reproducible MCP configuration, or replace
61
61
  it with `teams-transcripts` to follow the latest release. Do not run
62
62
  `uvx teams-transcripts-mcp`: that asks PyPI for a package named
63
63
  `teams-transcripts-mcp`, rather than running the executable supplied by this
@@ -646,7 +646,7 @@ From PyPI, with no repository checkout or persistent installation:
646
646
 
647
647
  ```sh
648
648
  # Pinned release (recommended for MCP client configuration)
649
- uvx --from 'teams-transcripts==0.5.1' teams-transcripts-mcp
649
+ uvx --from 'teams-transcripts==0.5.2' teams-transcripts-mcp
650
650
 
651
651
  # Latest release
652
652
  uvx --from teams-transcripts teams-transcripts-mcp
@@ -754,7 +754,7 @@ configuration format, including Claude Desktop:
754
754
  "command": "uvx",
755
755
  "args": [
756
756
  "--from",
757
- "teams-transcripts==0.5.1",
757
+ "teams-transcripts==0.5.2",
758
758
  "teams-transcripts-mcp"
759
759
  ],
760
760
  "env": {
@@ -772,7 +772,7 @@ needs to the `env` object. The MCP process must run as the same macOS user as
772
772
  Teams so it can connect to the desktop app and use that user's credentials.
773
773
 
774
774
  To track the newest PyPI release instead of pinning one, change the package
775
- argument from `teams-transcripts==0.5.1` to `teams-transcripts`.
775
+ argument from `teams-transcripts==0.5.2` to `teams-transcripts`.
776
776
 
777
777
  ### Configuration from an installed checkout
778
778
 
@@ -1434,6 +1434,41 @@ uv add <package>
1434
1434
 
1435
1435
  This updates both `pyproject.toml` and `uv.lock`.
1436
1436
 
1437
+ ### Publishing a release
1438
+
1439
+ Version tags publish the verified wheel and source distribution to PyPI through
1440
+ GitLab CI/CD. The `publish` job runs only for tags such as `v0.6.0`, only after
1441
+ both verification jobs and the package job succeed, and uses PyPI Trusted
1442
+ Publishing with a short-lived GitLab OIDC token. No PyPI password or API token
1443
+ is stored in GitLab.
1444
+
1445
+ Before the first automated release, add a GitLab CI/CD trusted publisher under
1446
+ the PyPI project's **Manage > Publishing** settings with these values:
1447
+
1448
+ | Setting | Value |
1449
+ |---------|-------|
1450
+ | Namespace | `jamiemills-choreograph` |
1451
+ | Project | `teams-transcripts` |
1452
+ | Top-level pipeline file | `.gitlab-ci.yml` |
1453
+ | Environment | `pypi` |
1454
+
1455
+ To release a new version:
1456
+
1457
+ ```sh
1458
+ uv version 0.6.0 --no-sync
1459
+ git add pyproject.toml uv.lock
1460
+ git commit -m "Prepare 0.6.0 release"
1461
+ git push origin main
1462
+
1463
+ # After the main pipeline succeeds:
1464
+ git tag -a v0.6.0 -m "teams-transcripts 0.6.0"
1465
+ git push origin v0.6.0
1466
+ ```
1467
+
1468
+ The package job verifies that the tag exactly matches the built package version
1469
+ before publishing. PyPI releases are immutable, so never move or reuse a
1470
+ version tag; increment the project version and create a new tag instead.
1471
+
1437
1472
  ### Running tests
1438
1473
 
1439
1474
  ```sh
@@ -24,11 +24,11 @@ The MCP server has a different executable name from the PyPI package, so use
24
24
  `--from` to tell `uvx` which package provides it:
25
25
 
26
26
  ```sh
27
- uvx --from 'teams-transcripts==0.5.1' teams-transcripts-mcp
27
+ uvx --from 'teams-transcripts==0.5.2' teams-transcripts-mcp
28
28
  uvx --from teams-transcripts transcript-download --help
29
29
  ```
30
30
 
31
- Use `teams-transcripts==0.5.1` for a reproducible MCP configuration, or replace
31
+ Use `teams-transcripts==0.5.2` for a reproducible MCP configuration, or replace
32
32
  it with `teams-transcripts` to follow the latest release. Do not run
33
33
  `uvx teams-transcripts-mcp`: that asks PyPI for a package named
34
34
  `teams-transcripts-mcp`, rather than running the executable supplied by this
@@ -617,7 +617,7 @@ From PyPI, with no repository checkout or persistent installation:
617
617
 
618
618
  ```sh
619
619
  # Pinned release (recommended for MCP client configuration)
620
- uvx --from 'teams-transcripts==0.5.1' teams-transcripts-mcp
620
+ uvx --from 'teams-transcripts==0.5.2' teams-transcripts-mcp
621
621
 
622
622
  # Latest release
623
623
  uvx --from teams-transcripts teams-transcripts-mcp
@@ -725,7 +725,7 @@ configuration format, including Claude Desktop:
725
725
  "command": "uvx",
726
726
  "args": [
727
727
  "--from",
728
- "teams-transcripts==0.5.1",
728
+ "teams-transcripts==0.5.2",
729
729
  "teams-transcripts-mcp"
730
730
  ],
731
731
  "env": {
@@ -743,7 +743,7 @@ needs to the `env` object. The MCP process must run as the same macOS user as
743
743
  Teams so it can connect to the desktop app and use that user's credentials.
744
744
 
745
745
  To track the newest PyPI release instead of pinning one, change the package
746
- argument from `teams-transcripts==0.5.1` to `teams-transcripts`.
746
+ argument from `teams-transcripts==0.5.2` to `teams-transcripts`.
747
747
 
748
748
  ### Configuration from an installed checkout
749
749
 
@@ -1405,6 +1405,41 @@ uv add <package>
1405
1405
 
1406
1406
  This updates both `pyproject.toml` and `uv.lock`.
1407
1407
 
1408
+ ### Publishing a release
1409
+
1410
+ Version tags publish the verified wheel and source distribution to PyPI through
1411
+ GitLab CI/CD. The `publish` job runs only for tags such as `v0.6.0`, only after
1412
+ both verification jobs and the package job succeed, and uses PyPI Trusted
1413
+ Publishing with a short-lived GitLab OIDC token. No PyPI password or API token
1414
+ is stored in GitLab.
1415
+
1416
+ Before the first automated release, add a GitLab CI/CD trusted publisher under
1417
+ the PyPI project's **Manage > Publishing** settings with these values:
1418
+
1419
+ | Setting | Value |
1420
+ |---------|-------|
1421
+ | Namespace | `jamiemills-choreograph` |
1422
+ | Project | `teams-transcripts` |
1423
+ | Top-level pipeline file | `.gitlab-ci.yml` |
1424
+ | Environment | `pypi` |
1425
+
1426
+ To release a new version:
1427
+
1428
+ ```sh
1429
+ uv version 0.6.0 --no-sync
1430
+ git add pyproject.toml uv.lock
1431
+ git commit -m "Prepare 0.6.0 release"
1432
+ git push origin main
1433
+
1434
+ # After the main pipeline succeeds:
1435
+ git tag -a v0.6.0 -m "teams-transcripts 0.6.0"
1436
+ git push origin v0.6.0
1437
+ ```
1438
+
1439
+ The package job verifies that the tag exactly matches the built package version
1440
+ before publishing. PyPI releases are immutable, so never move or reuse a
1441
+ version tag; increment the project version and create a new tag instead.
1442
+
1408
1443
  ### Running tests
1409
1444
 
1410
1445
  ```sh
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "teams-transcripts"
3
- version = "0.5.1"
3
+ version = "0.5.2"
4
4
  description = "Download Microsoft Teams transcripts, chat, and meeting metadata from the macOS desktop app"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -34,6 +34,13 @@ Issues = "https://gitlab.com/jamiemills-choreograph/teams-transcripts/-/issues"
34
34
  requires = ["hatchling"]
35
35
  build-backend = "hatchling.build"
36
36
 
37
+ [tool.hatch.build]
38
+ exclude = [
39
+ "/.uv-cache",
40
+ "/.venv",
41
+ "/dist",
42
+ ]
43
+
37
44
  [tool.hatch.build.targets.wheel]
38
45
  packages = ["legacy", "teams_transcripts"]
39
46
 
@@ -10,6 +10,7 @@ import zipfile
10
10
  from email.parser import Parser
11
11
 
12
12
  EXPECTED_PACKAGES = ("legacy/", "teams_transcripts/")
13
+ EXCLUDED_SDIST_PATHS = ("/.uv-cache/", "/.venv/", "/dist/")
13
14
  EXPECTED_SCRIPTS = {
14
15
  "teams-transcripts = teams_transcripts.__main__:main",
15
16
  "teams-transcripts-mcp = teams_transcripts.mcp_server:main",
@@ -51,6 +52,9 @@ def _verify_sdist(path: pathlib.Path) -> None:
51
52
  for package in EXPECTED_PACKAGES:
52
53
  if not any(f"/{package}" in name for name in names):
53
54
  raise SystemExit(f"{path.name} does not contain {package}")
55
+ for excluded in EXCLUDED_SDIST_PATHS:
56
+ if any(excluded in f"/{name}/" for name in names):
57
+ raise SystemExit(f"{path.name} unexpectedly contains {excluded.strip('/')}")
54
58
 
55
59
 
56
60
  def main() -> None:
@@ -9,6 +9,7 @@ Covers:
9
9
  from __future__ import annotations
10
10
 
11
11
  import argparse
12
+ from datetime import datetime, timedelta
12
13
 
13
14
  import pytest
14
15
 
@@ -20,6 +21,7 @@ from teams_transcripts.domain.models import (
20
21
  TranscriptCue,
21
22
  )
22
23
  from teams_transcripts.domain.summary import build_result_summary
24
+ from teams_transcripts.domain.timestamps import parse_meeting_times
23
25
  from teams_transcripts.infrastructure.config import resolve_config
24
26
 
25
27
  # ---------------------------------------------------------------------------
@@ -331,11 +333,16 @@ class TestComposableJsonOutput:
331
333
 
332
334
  def test_chat_message_has_offset(self) -> None:
333
335
  """Chat messages in JSON include offset from meeting start."""
336
+ meeting_time_text = "22 April 2026 11:00 - 12:00"
337
+ meeting_start, _ = parse_meeting_times(meeting_time_text, "2026-04-22")
338
+ message_timestamp = (
339
+ datetime.fromisoformat(meeting_start) + timedelta(minutes=15)
340
+ ).isoformat()
334
341
  messages = [
335
- ChatMessage(timestamp="2026-04-22T11:15:00+01:00", author="Bob", text="Hi"),
342
+ ChatMessage(timestamp=message_timestamp, author="Bob", text="Hi"),
336
343
  ]
337
344
  result = build_result_summary(
338
- _base_config(meeting_time_text="22 April 2026 11:00 - 12:00"),
345
+ _base_config(meeting_time_text=meeting_time_text),
339
346
  chat_messages=messages,
340
347
  chat_count=1,
341
348
  include_transcript=False,
@@ -1156,7 +1156,7 @@ wheels = [
1156
1156
 
1157
1157
  [[package]]
1158
1158
  name = "teams-transcripts"
1159
- version = "0.5.1"
1159
+ version = "0.5.2"
1160
1160
  source = { editable = "." }
1161
1161
  dependencies = [
1162
1162
  { name = "anthropic", extra = ["vertex"] },