tandem-cli 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 (113) hide show
  1. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/PKG-INFO +9 -1
  2. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/README.md +8 -0
  3. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/formats.md +10 -0
  4. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/plugin/.claude-plugin/plugin.json +1 -1
  5. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/pyproject.toml +1 -1
  6. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/harness/claude_code.py +17 -4
  7. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_parse.py +7 -1
  8. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_sync.py +8 -3
  9. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_toolmap.py +13 -0
  10. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/uv.lock +1 -1
  11. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/.claude-plugin/marketplace.json +0 -0
  12. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/.github/workflows/ci.yml +0 -0
  13. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/.gitignore +0 -0
  14. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/LICENSE +0 -0
  15. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/configuration.md +0 -0
  16. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/development.md +0 -0
  17. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/how-it-works.md +0 -0
  18. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/plans/2026-07-29-native-tool-call-translation.md +0 -0
  19. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/plans/2026-07-31-codex-subagents.md +0 -0
  20. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/plans/2026-08-01-plugin-marketplace-install.md +0 -0
  21. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/plans/2026-08-01-sandbox-consent-and-manual-routing.md +0 -0
  22. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/plans/2026-08-02-plugin-auto-install.md +0 -0
  23. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/plans/2026-08-03-manual-default-model-passthrough.md +0 -0
  24. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/plans/2026-08-06-harness-startup-args.md +0 -0
  25. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/plans/2026-08-09-meta-harness-frame.md +0 -0
  26. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/plans/2026-08-09-readme-restructure.md +0 -0
  27. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/plans/2026-08-10-idle-flip-status-probe.md +0 -0
  28. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/plans/2026-08-10-retire-interstitial-prompt.md +0 -0
  29. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/plans/2026-08-13-pr1-nharness-core.md +0 -0
  30. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/plans/2026-08-13-pr2-opencode-adapter.md +0 -0
  31. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/specs/2026-07-29-native-tool-call-translation-design.md +0 -0
  32. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/specs/2026-07-31-codex-subagents-design.md +0 -0
  33. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/specs/2026-08-02-plugin-auto-install-design.md +0 -0
  34. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/specs/2026-08-03-manual-default-model-passthrough-design.md +0 -0
  35. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/specs/2026-08-06-harness-startup-args-design.md +0 -0
  36. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/specs/2026-08-09-meta-harness-frame-design.md +0 -0
  37. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/specs/2026-08-09-model-pin-recovery-design.md +0 -0
  38. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/specs/2026-08-09-readme-restructure-design.md +0 -0
  39. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/specs/2026-08-10-remove-interstitial-prompt-design.md +0 -0
  40. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/specs/2026-08-13-opencode-harness-design.md +0 -0
  41. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/subagents.md +0 -0
  42. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/superpowers/plans/2026-07-29-tandem-shell.md +0 -0
  43. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/superpowers/plans/2026-08-11-process-warmup-live-validation.md +0 -0
  44. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/superpowers/plans/2026-08-11-process-warmup.md +0 -0
  45. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/superpowers/plans/2026-08-12-process-warmup-pipelined.md +0 -0
  46. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/superpowers/specs/2026-07-29-tandem-shell-design.md +0 -0
  47. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/superpowers/specs/2026-08-10-idle-flip-status-probe.md +0 -0
  48. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/superpowers/specs/2026-08-11-process-warmup-design.md +0 -0
  49. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/superpowers/specs/2026-08-12-process-warmup-pipelined-design.md +0 -0
  50. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/docs/why.md +0 -0
  51. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/plugin/README.md +0 -0
  52. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/plugin/agents/codex-worker.md +0 -0
  53. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/plugin/agents/gpt.md +0 -0
  54. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/plugin/hooks/hooks.json +0 -0
  55. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/__init__.py +0 -0
  56. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/cli.py +0 -0
  57. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/compat.py +0 -0
  58. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/config.py +0 -0
  59. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/constants.py +0 -0
  60. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/converter.py +0 -0
  61. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/doctor.py +0 -0
  62. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/events.py +0 -0
  63. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/flip.py +0 -0
  64. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/frame.py +0 -0
  65. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/harness/__init__.py +0 -0
  66. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/harness/base.py +0 -0
  67. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/harness/codex.py +0 -0
  68. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/harness/opencode.py +0 -0
  69. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/hookroute.py +0 -0
  70. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/memory_sync.py +0 -0
  71. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/modelcat.py +0 -0
  72. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/ops.py +0 -0
  73. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/paths.py +0 -0
  74. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/pinstash.py +0 -0
  75. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/plugin_setup.py +0 -0
  76. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/ptyrun.py +0 -0
  77. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/ratelimit.py +0 -0
  78. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/runner.py +0 -0
  79. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/state.py +0 -0
  80. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/summarize.py +0 -0
  81. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/sync.py +0 -0
  82. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/tailer.py +0 -0
  83. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/toolmap.py +0 -0
  84. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/util.py +0 -0
  85. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/src/tandem/warm.py +0 -0
  86. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/conftest.py +0 -0
  87. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/golden/claude-probe.jsonl +0 -0
  88. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/golden/codex-probe.jsonl +0 -0
  89. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_cli.py +0 -0
  90. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_config.py +0 -0
  91. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_converter.py +0 -0
  92. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_current_formats.py +0 -0
  93. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_flip.py +0 -0
  94. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_frame.py +0 -0
  95. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_hookroute.py +0 -0
  96. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_memory_doctor.py +0 -0
  97. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_modelcat.py +0 -0
  98. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_opencode.py +0 -0
  99. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_opencode_oracle.py +0 -0
  100. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_ops.py +0 -0
  101. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_participants.py +0 -0
  102. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_paths_compat.py +0 -0
  103. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_pinstash.py +0 -0
  104. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_plugin.py +0 -0
  105. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_plugin_setup.py +0 -0
  106. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_ptyrun.py +0 -0
  107. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_ratelimit.py +0 -0
  108. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_runner.py +0 -0
  109. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_state.py +0 -0
  110. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_sub.py +0 -0
  111. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_tail.py +0 -0
  112. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_usage.py +0 -0
  113. {tandem_cli-0.5.1 → tandem_cli-0.5.2}/tests/test_warm.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tandem-cli
3
- Version: 0.5.1
3
+ Version: 0.5.2
4
4
  Summary: Run Claude Code, Codex CLI, and opencode in one shared coding session with live trace sync.
5
5
  Project-URL: Homepage, https://github.com/Bhavya6187/tandem
6
6
  Project-URL: Repository, https://github.com/Bhavya6187/tandem
@@ -102,6 +102,14 @@ at each start, and could lose a claude → codex flip to `already has an
102
102
  active writer`. All three are fixed, and codex's list-shaped tool outputs
103
103
  now reach the other side as text with their exit codes intact.
104
104
 
105
+ **0.5.2 stops claude complaining about synced turns.** claude 2.1.261
106
+ restores a session's model on resume from its last assistant entry, and a
107
+ claude session that had never run a turn of its own (claude → codex →
108
+ opencode → claude) opened with `Session model <synced> could not be
109
+ restored … using fable instead`. Synced entries now carry claude's own
110
+ `<synthetic>` tag until claude has run, which its resume skips; the synced
111
+ turns still render and still reach the model.
112
+
105
113
  ## Why tandem?
106
114
 
107
115
  - **Keep going when a model hits its limit.** The tab bar shows each
@@ -76,6 +76,14 @@ at each start, and could lose a claude → codex flip to `already has an
76
76
  active writer`. All three are fixed, and codex's list-shaped tool outputs
77
77
  now reach the other side as text with their exit codes intact.
78
78
 
79
+ **0.5.2 stops claude complaining about synced turns.** claude 2.1.261
80
+ restores a session's model on resume from its last assistant entry, and a
81
+ claude session that had never run a turn of its own (claude → codex →
82
+ opencode → claude) opened with `Session model <synced> could not be
83
+ restored … using fable instead`. Synced entries now carry claude's own
84
+ `<synthetic>` tag until claude has run, which its resume skips; the synced
85
+ turns still render and still reach the model.
86
+
79
87
  ## Why tandem?
80
88
 
81
89
  - **Keep going when a model hits its limit.** The tab bar shows each
@@ -60,6 +60,16 @@ validation rather than being silently declared compatible.
60
60
  tandem drops it like any other non-text assistant block.
61
61
  - Resume: `claude --resume <sessionId>` (from the same cwd). A new session
62
62
  can be pinned to a chosen id with `claude --session-id <uuid>`.
63
+ - 2.1.261 restores the session model on resume from the last assistant
64
+ entry whose `message.model` is a string other than `"<synthetic>"`
65
+ (claude's own tag on model-less stubs such as API-error messages) and
66
+ warns `Session model X could not be restored (not a model this version
67
+ of Claude Code recognizes) — using <default> instead` when that value is
68
+ not a model it knows. Tandem-rendered assistant entries therefore copy
69
+ the model claude last used in that transcript, and carry `"<synthetic>"`
70
+ until claude has run at all (a zero-turn claude flipped back into). The
71
+ `"<synced>"` placeholder tandem ≤0.5.1 wrote there drew the warning;
72
+ entries carrying it are still skipped when tandem derives the model.
63
73
  - Turn boundary: a `user` entry with string content starts a turn; an
64
74
  `assistant` line with `stop_reason: "end_turn"` ends it. The `Stop` hook
65
75
  (injectable per-invocation via `--settings '<json>'`) fires at turn end.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tandem",
3
3
  "description": "Route Claude Code subagent dispatches to cheap codex models via tandem.",
4
- "version": "0.5.1",
4
+ "version": "0.5.2",
5
5
  "author": {"name": "tandem"}
6
6
  }
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tandem-cli"
3
- version = "0.5.1"
3
+ version = "0.5.2"
4
4
  description = "Run Claude Code, Codex CLI, and opencode in one shared coding session with live trace sync."
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -127,6 +127,18 @@ _CLAUDE_ENTRY_TYPES = {
127
127
  }
128
128
 
129
129
 
130
+ # claude's own tag for an assistant entry no model produced (its API-error
131
+ # stubs carry it). `claude --resume` (2.1.261) restores the session model from
132
+ # the last assistant entry and warns "Session model X could not be restored"
133
+ # for anything it does not recognise; "<synthetic>" is the one value that scan
134
+ # skips, so rendered entries carry it until claude itself has run and a real
135
+ # model can be copied instead (live-verified 2026-09-05: no warning, synced
136
+ # turns still render and reach the model).
137
+ SYNTHETIC_MODEL = "<synthetic>"
138
+ # what tandem <= 0.5.1 wrote in that slot; still skipped when deriving
139
+ LEGACY_SYNCED_MODEL = "<synced>"
140
+
141
+
130
142
  class ClaudeCodeAdapter(HarnessAdapter):
131
143
  id = "claude"
132
144
  display_name = "Claude Code"
@@ -434,7 +446,7 @@ class ClaudeCodeAdapter(HarnessAdapter):
434
446
  st["run_msg_id"] = f"msg_tandem_{entry['uuid'][:8]}"
435
447
  return {
436
448
  "role": "assistant",
437
- "model": st.get("model") or "<synced>",
449
+ "model": st.get("model") or SYNTHETIC_MODEL,
438
450
  "id": st["run_msg_id"],
439
451
  "type": "message",
440
452
  "content": content,
@@ -487,14 +499,15 @@ class ClaudeCodeAdapter(HarnessAdapter):
487
499
 
488
500
  def derive_last_model(self, transcript: Path) -> str | None:
489
501
  """Model of the last main-thread assistant entry with a real model
490
- name. Skips the "<synced>" placeholder (pre-fix tandem appends) and
491
- sidechain entries (subagents may run on a different model)."""
502
+ name. Skips tandem's own tags (SYNTHETIC_MODEL now, the older
503
+ "<synced>"), claude's synthetic stubs, and sidechain entries
504
+ (subagents may run on a different model)."""
492
505
  model = None
493
506
  for obj in self._tail_objects(transcript):
494
507
  if obj.get("type") != "assistant" or obj.get("isSidechain"):
495
508
  continue
496
509
  m = (obj.get("message") or {}).get("model")
497
- if m and m != "<synced>":
510
+ if m and m not in (SYNTHETIC_MODEL, LEGACY_SYNCED_MODEL):
498
511
  model = m
499
512
  return model
500
513
 
@@ -140,7 +140,10 @@ class TestDeriveLastModel:
140
140
  ])
141
141
  assert get_adapter("claude").derive_last_model(p) == "claude-fable-5"
142
142
 
143
- def test_synced_and_sidechain_models_skipped(self, tmp_path):
143
+ def test_placeholder_and_sidechain_models_skipped(self, tmp_path):
144
+ # "<synced>" is the placeholder older tandem wrote; "<synthetic>" is
145
+ # claude's own tag for model-less assistant entries (its API-error
146
+ # stubs) and what tandem writes now — neither is a model claude ran
144
147
  p = self.write(tmp_path, [
145
148
  {"type": "assistant", "uuid": "a1",
146
149
  "message": {"role": "assistant", "model": "claude-fable-5",
@@ -151,6 +154,9 @@ class TestDeriveLastModel:
151
154
  {"type": "assistant", "uuid": "a2",
152
155
  "message": {"role": "assistant", "model": "<synced>",
153
156
  "content": []}},
157
+ {"type": "assistant", "uuid": "a3",
158
+ "message": {"role": "assistant", "model": "<synthetic>",
159
+ "content": []}},
154
160
  ])
155
161
  assert get_adapter("claude").derive_last_model(p) == "claude-fable-5"
156
162
 
@@ -159,8 +159,12 @@ class TestSyncCodexToClaude:
159
159
  assert synced
160
160
  assert all(e["message"]["model"] == "claude-fable-5" for e in synced)
161
161
 
162
- def test_synced_model_placeholder_when_claude_never_ran(self, env_factory):
163
- # regression guard for the fresh-shadow case: no real model to copy
162
+ def test_synthetic_model_tag_when_claude_never_ran(self, env_factory):
163
+ """Fresh-shadow case: no real model to copy. Entries carry claude's
164
+ own "<synthetic>" tag, which its --resume model-restore scan skips
165
+ (live-verified on 2.1.261); the old "<synced>" placeholder drew
166
+ "Session model <synced> could not be restored" on every zero-turn
167
+ claude session flipped back into."""
164
168
  env = env_factory(active="codex")
165
169
  for obj in self.codex_lines():
166
170
  write_line(env.source_file, obj)
@@ -168,7 +172,8 @@ class TestSyncCodexToClaude:
168
172
  loop.drain()
169
173
  synced = [e for e in read_jsonl(env.claude_shadow)
170
174
  if e.get("type") == "assistant"]
171
- assert all(e["message"]["model"] == "<synced>" for e in synced)
175
+ assert synced
176
+ assert all(e["message"]["model"] == "<synthetic>" for e in synced)
172
177
 
173
178
  def test_leaf_rederived_from_file(self, env_factory):
174
179
  """If claude itself appended entries (it was active earlier), new
@@ -464,6 +464,19 @@ class TestClaudeToolRendering:
464
464
  ], ctx)
465
465
  assert all(e["message"]["model"] == "claude-fable-5" for e in entries)
466
466
 
467
+ def test_render_uses_claudes_synthetic_tag_when_no_model_is_known(self):
468
+ # claude --resume (2.1.261) restores the session model from the last
469
+ # assistant entry and warns "Session model X could not be restored"
470
+ # for anything it does not recognise; "<synthetic>" is claude's own
471
+ # tag for model-less assistant entries and the one value its scan
472
+ # skips, so it is what a shadow with no claude turn yet must carry
473
+ ctx = _ctx("codex->claude")
474
+ entries = get_adapter("claude").render_events([
475
+ AssistantMessage(source="codex", text="hi"),
476
+ call("Bash", {"command": "ls"}, source="codex", call_id="c9"),
477
+ ], ctx)
478
+ assert all(e["message"]["model"] == "<synthetic>" for e in entries)
479
+
467
480
  def test_is_error_flag_rides(self):
468
481
  ctx = _ctx("codex->claude")
469
482
  entries = get_adapter("claude").render_events([
@@ -224,7 +224,7 @@ wheels = [
224
224
 
225
225
  [[package]]
226
226
  name = "tandem-cli"
227
- version = "0.5.1"
227
+ version = "0.5.2"
228
228
  source = { editable = "." }
229
229
  dependencies = [
230
230
  { name = "click" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes