main
27 次代码提交
| 作者 | SHA1 | 备注 | 提交日期 | |
|---|---|---|---|---|
|
|
3fba1c6fc3 |
Give messaging clear exact subtree semantics (#1072)
## Problem Messaging `/clear` did not follow the selected platform message boundary. Reply clears preserved the selected user prompt, while standalone clears preserved user-authored messages and could reset FCC state outside the invoking chat. ## Changes | Before | After | | --- | --- | | Reply `/clear` removed a logical conversation branch but retained the selected message. | Reply `/clear` deletes the selected message and its literal reply subtree, including the clear command. | | Standalone `/clear` retained user prompts and voice notes while resetting global messaging state. | Standalone `/clear` deletes every tracked message and resets FCC state only in the invoking platform and chat. | | Trees recorded only logical execution parentage. | Trees separately persist logical execution ancestry and exact prompt/status reply ownership. | | Clear coordination used one global admission boundary. | Per-chat clear generations coordinate admission, voice cancellation, persistence, and best-effort platform deletion. | | Persistence tracked only FCC-authored clearable output. | Persistence tracks managed inbound and outbound messages and migrates legacy entries. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR gives messaging `/clear` exact per-chat and reply-subtree behavior. The main changes are: - Per-chat clear generations for admission and startup-notice cleanup. - Managed inbound and outbound message tracking for deletion. - Exact prompt/status reply ownership in message trees. - Scoped voice cancellation and clear persistence updates. - Updated docs, smoke coverage, and messaging tests. </details> <h3>Confidence Score: 4/5</h3> The clear flow is mostly well-contained, with one upgrade-path issue in legacy tree restoration. Newly created prompt/status subtrees use the new exact reference fields consistently, and legacy snapshots can map old status replies to prompt references. However, reply `/clear` on an upgraded status can miss descendants and leave stale state/messages. src/free_claude_code/messaging/trees/snapshot.py <details><summary><h3><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="20" align="absmiddle"></a> T-Rex Logs</h3></summary> **What T-Rex did** - T-Rex attempted to prepare and run a focused legacy snapshot reproduction harness for legacy status replies detach, but tool access was blocked before execution. - A messaging clear smoke test harness was executed and reported a passing result: 20 items collected and 20 passed in 1.69 seconds, with traces for test\_reply\_clear\_uses\_literal and related paths shown in the log. <a href="https://app.greptile.com/trex/runs/14131337/artifacts"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img alt="View all artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a> <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> </details> <details open><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | src/free_claude_code/messaging/workflow.py | Adds per-chat clear generations, managed inbound recording, scoped clears, and startup-notice invalidation. | | src/free_claude_code/messaging/trees/graph.py | Adds exact prompt/status reference resolution and literal reply-subtree traversal. | | src/free_claude_code/messaging/trees/runtime.py | Adds exact message-subtree removal and status-only clearing behavior. | | src/free_claude_code/messaging/trees/snapshot.py | Adds parent_reference_id persistence and legacy fallback; the fallback can miss legacy status-reply descendants. | | src/free_claude_code/messaging/session/managed_message_log.py | Replaces the clearable output log with managed inbound and outbound message tracking. | | src/free_claude_code/messaging/commands.py | Routes reply and standalone `/clear` through the new exact deletion ID flows. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD A[Incoming message] --> B{Standalone /clear?} B -- yes --> C[Clear invoking chat] C --> D[Cancel scoped voice work] C --> E[Collect managed and tree message IDs] C --> F[Advance chat clear generation] F --> G[Detach scoped trees] G --> H[Clear scoped session store] H --> I[Best-effort platform deletes] B -- no --> J[Record managed inbound message] J --> K[Admit with stop and clear token] K --> L{Reply /clear?} L -- yes --> M[Resolve exact prompt or status reference] M --> N[Remove literal reference subtree] N --> I L -- no --> O[Queue or run tree node] ``` </a> <a href="#gh-dark-mode-only"> ```mermaid %%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD A[Incoming message] --> B{Standalone /clear?} B -- yes --> C[Clear invoking chat] C --> D[Cancel scoped voice work] C --> E[Collect managed and tree message IDs] C --> F[Advance chat clear generation] F --> G[Detach scoped trees] G --> H[Clear scoped session store] H --> I[Best-effort platform deletes] B -- no --> J[Record managed inbound message] J --> K[Admit with stop and clear token] K --> L{Reply /clear?} L -- yes --> M[Resolve exact prompt or status reference] M --> N[Remove literal reference subtree] N --> I L -- no --> O[Queue or run tree node] ``` </a> </details> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fclear-message-subtree%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fclear-message-subtree%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fmessaging%2Ftrees%2Fsnapshot.py%3A192-193%0A**Legacy%20Status%20Replies%20Detach**%0A%0AWhen%20an%20upgraded%20legacy%20snapshot%20contains%20a%20child%20that%20originally%20replied%20to%20its%20parent%20status%2C%20this%20fallback%20rewrites%20the%20missing%20exact%20reference%20to%20the%20parent%20prompt.%20A%20later%20reply%20%60%2Fclear%60%20on%20that%20status%20traverses%20from%20the%20status%20ID%2C%20finds%20no%20migrated%20child%20edge%2C%20and%20leaves%20the%20old%20status-reply%20descendants%20and%20their%20managed%20messages%20behind.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1072&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a> <sub>Reviews (1): Last reviewed commit: ["Give messaging clear exact subtree seman..."](https://github.com/alishahryar1/free-claude-code/commit/0a3baecf9470da4bb866c864c1d1f01abd517085) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43593126)</sub> > Greptile also left **1 inline comment** on this PR. <!-- /greptile_comment --> |
||
|
|
e37b504636 |
Preserve user messages during messaging clear (#1068)
## Problem Messaging `/clear` used one untyped collection for both internal reply references and platform deletion targets. Clearing a branch or cancelling a voice task could therefore delete the customer's prompt or voice note along with FCC's own status and reply messages. ## Changes | Before | After | | --- | --- | | Tree transitions exposed one message-ID set for repository unindexing and platform deletion. | Tree transitions now separate internal `reference_ids` from FCC-owned `clearable_message_ids`. | | Reply and global clear deleted user prompts and voice notes with FCC output. | Clear removes FCC statuses, replies, notices, and the explicit `/clear` command while preserving user-authored messages. | | The persisted message log accepted ordinary inbound content. | The clearable-message log accepts only FCC output and explicit clear commands, and drops legacy user-content entries when loading. | | Tests treated user-message deletion as successful cleanup. | Deterministic and live messaging coverage enforce preservation across branch, global, and voice clear paths. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR narrows messaging clear behavior so user-authored messages are preserved. The main changes are: - Clearable platform IDs are separated from internal tree reference IDs. - The session message log now tracks FCC-owned output and explicit clear commands. - Branch, global, and voice clear paths now avoid deleting user prompts and voice notes. - Tests, smoke coverage, docs, and the package version were updated. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge after a small migration cleanup. The clear paths now preserve user-authored messages, and current clearable-log writers use the new shape consistently. src/free_claude_code/messaging/session/clearable_message_log.py needs a migration cleanup for old retained clear-command IDs during session reload. <details><summary><h3><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="20" align="absmiddle"></a> T-Rex Logs</h3></summary> **What T-Rex did** - Validated the messaging-clear-preservation contract by reviewing the foreground pytest run log, which captured the exact command, working directory, full test output, and exit code, and by examining the artifact note and its capture log that summarize the command, test count, exit code, and scope. <a href="https://app.greptile.com/trex/runs/14123111/artifacts"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img alt="View all artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a> <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> </details> <details open><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | src/free_claude_code/messaging/session/clearable_message_log.py | Replaces the broad message log with a clearable-message log, but the migration filter can drop old retained clear-command IDs. | | src/free_claude_code/messaging/session/store.py | Renames the session-store API around clearable message IDs while keeping the same persisted `message_log` key. | | src/free_claude_code/messaging/trees/runtime.py | Returns internal reference IDs separately from FCC-owned deletion IDs during branch removal and chat-wide enumeration. | | src/free_claude_code/messaging/trees/manager.py | Uses reference IDs for repository cleanup and returns clearable IDs for platform deletion. | | src/free_claude_code/messaging/turn_intake.py | Stops recording ordinary inbound content and records clear commands only when needed for cleanup. | | src/free_claude_code/messaging/commands.py | Deletes clearable IDs plus the invoking clear command instead of deleting all branch reference IDs. | | src/free_claude_code/messaging/workflow.py | Aggregates clearable IDs from tree state, the session log, and voice cancellation results. | | src/free_claude_code/messaging/voice.py | Changes voice cancellation deletion ownership so only FCC-authored status messages are clearable. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD A[Incoming message] --> B{Clear command?} B -- No --> C[Handle normal turn] C --> D[Record FCC outbound status] B -- Reply clear --> E[Record clear command] E --> F[Clear branch or voice task] F --> G[Delete FCC-owned IDs plus clear command] B -- Global clear --> H[Collect clearable IDs] H --> I[Reset conversation state] I --> J[Delete FCC-owned IDs plus clear command] D --> K[Clearable-message log] K --> H ``` </a> <a href="#gh-dark-mode-only"> ```mermaid %%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD A[Incoming message] --> B{Clear command?} B -- No --> C[Handle normal turn] C --> D[Record FCC outbound status] B -- Reply clear --> E[Record clear command] E --> F[Clear branch or voice task] F --> G[Delete FCC-owned IDs plus clear command] B -- Global clear --> H[Collect clearable IDs] H --> I[Reset conversation state] I --> J[Delete FCC-owned IDs plus clear command] D --> K[Clearable-message log] K --> H ``` </a> </details> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fpreserve-user-messages-on-clear%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fpreserve-user-messages-on-clear%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fmessaging%2Fsession%2Fclearable_message_log.py%3A36-37%0A**Legacy%20Clear%20Commands%20Are%20Dropped**%0A%0AWhen%20an%20existing%20session%20file%20contains%20a%20previously%20retained%20clear%20command%20from%20the%20old%20log%2C%20it%20is%20stored%20as%20%60direction%3D%22in%22%60%20and%20%60kind%3D%22command%22%60.%20This%20new%20load%20filter%20drops%20that%20entry%20because%20it%20only%20keeps%20%60kind%3D%22clear_command%22%60%2C%20so%20a%20failed%20or%20cancelled%20%60%2Fclear%60%20command%20recorded%20before%20the%20upgrade%20is%20no%20longer%20retried%20by%20the%20next%20clear%20and%20remains%20on%20the%20platform.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1068&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a> <sub>Reviews (1): Last reviewed commit: ["Preserve user messages during clear"](https://github.com/alishahryar1/free-claude-code/commit/af7a910facaa29a5ca8f7fb95ec2faae28798e62) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43576921)</sub> > Greptile also left **1 inline comment** on this PR. **Context used:** - Context used - CLAUDE.md ([source](https://app.greptile.com/alishahryar1/github/Alishahryar1/free-claude-code/-/custom-context?memory=d2fd24d8-0dec-4faf-8ee4-e085e215a2f8)) <!-- /greptile_comment --> |
||
|
|
ef76bddd58 |
Make Telegram startup notices clearable (#1066)
## Problem Telegram's online notice was sent directly by the SDK runtime and its message ID was discarded, so `/clear` could not delete it. Moving delivery into the workflow also needs to keep slow sends from blocking commands and prevent acknowledged notices from losing clear ownership. ## Changes | Before | After | | --- | --- | | The Telegram runtime sent a transport-specific startup side effect. | The platform declares a semantic notice intent that the application gives to the workflow after transport readiness. | | Startup delivery bypassed the persisted message log. | The workflow renders and records each acknowledged notice in the same bounded log used by `/clear`. | | Serializing send and record held workflow state across platform I/O. | A dedicated clear generation reserves publication, delivery runs outside the state lock, and a short receipt finalizer commits or compensates. | | Concurrent clear, cancellation, or record failure could leave a delivered notice unowned. | Clear or cancellation deletes a late receipt; record failure deletes it; failed deletion restores tracking for a later `/clear`. | | A standalone `/clear` command could evict an older target at the log cap. | Successful standalone clear owns its command ID directly, while failed or cancelled clear records it for the next attempt. | | Startup ownership races were implicit. | Deterministic race, failure, cap, restart, and product-smoke coverage enforce the final state machine in version 3.5.10. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes Telegram startup notices clearable through the messaging workflow. The main changes are: - Moves the Telegram online notice out of the SDK runtime and into workflow-owned publication. - Adds a startup-notice intent to platform composition and publishes it after runtime start and restored-status repair. - Records delivered startup notice IDs for later `/clear` ownership, with delete compensation on interrupted ownership transfer. - Defers standalone `/clear` command ID recording so it cannot evict older deletion targets at the log cap. - Adds tests and smoke coverage for startup notice clearing, cancellation, failures, cap pressure, persistence, and startup ordering. - Bumps the package version and lockfile to 3.5.10. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues were found in the changed code. No files need attention. <details><summary><h3><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="20" align="absmiddle"></a> T-Rex Logs</h3></summary> **What T-Rex did** - A focused proof run for the telegram startup tests completed, showing 121 tests passed in 2.94 seconds with EXIT\_CODE 0. - A smoke proof run for the same flow completed, showing 18 tests skipped in 0.97 seconds with EXIT\_CODE 0. - The shell wrapper issue was addressed by re-running with bash -lc, producing a clean result with EXIT\_CODE 0 in the final artifact. <a href="https://app.greptile.com/trex/runs/14118230/artifacts"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img alt="View all artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a> <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> </details> <details open><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | src/free_claude_code/messaging/workflow.py | Adds workflow-owned startup notice sending, tracking, compensation, and clear-generation ordering. | | src/free_claude_code/messaging/turn_intake.py | Defers standalone `/clear` command ID recording until failure or cancellation paths need it. | | src/free_claude_code/runtime/application.py | Publishes optional startup notices after messaging runtime start and restored-status repair. | | src/free_claude_code/messaging/platforms/factory.py | Creates a Telegram startup-notice intent when an allowed Telegram user is configured. | | src/free_claude_code/messaging/platforms/telegram.py | Removes the direct Telegram runtime startup-message side effect. | </details> <sub>Reviews (2): Last reviewed commit: ["Make Telegram startup notices clearable"](https://github.com/alishahryar1/free-claude-code/commit/6e779006e0cdaf1df24c27a8d04784e2d7220a66) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43565904)</sub> <!-- /greptile_comment --> |
||
|
|
eda8ea3060 |
Use task status as the sole stop confirmation (#1065)
## Problem Messaging `/stop` edited each affected task status to `Stopped` and also posted a second success message. The duplicate confirmation added noise even though the existing status already represented the terminal result. ## Changes | Before | After | | --- | --- | | Successful active, queued, global, and bound-voice stops posted a second confirmation. | Successful stops use the affected task status as their sole success UI. | | Stop commands returned an ambiguous integer or `None`. | A typed `StopOutcome` carries the cancelled count and terminal status ownership. | | Statusless voice cancellation could become silent if confirmations were removed unconditionally. | Statusless voice cancellation receives one fallback confirmation. | | A global stop could under-report work when any affected status was in another chat. | The invoking chat receives one summary whenever any affected status is outside its scope. | | Zero-work global stops reported that zero requests were cancelled. | No-op global and reply stops report that there was nothing to stop. | | Runtime and product coverage encoded the duplicate message. | Runtime mapping and Discord/Telegram product smokes cover active, queued, voice, no-op, and fallback behavior. | | The package version was 3.5.8. | The package version is 3.5.9 with an updated lockfile. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR changes `/stop` so task statuses become the main success feedback. The main changes are: - Added a typed stop outcome for cancelled counts and status feedback ownership. - Suppressed duplicate stop confirmations when the invoking chat already has complete status feedback. - Kept explicit fallback messages for no-op stops, statusless voice cancellations, and cross-chat stop results. - Updated runtime mapping, docs, product smokes, tests, and the package version. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. None. <details><summary><h3><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="20" align="absmiddle"></a> T-Rex Logs</h3></summary> **What T-Rex did** - Ran the live messaging product smoke test with FCC\_LIVE\_SMOKE=1 and FCC\_SMOKE\_TARGETS=messaging, executing the command uv run pytest under /home/user/repo; the run exited with code 0 and 17 tests passed in 1.34s. - Reviewed the test run log to verify proper shutdown behavior, noting Discord and Telegram stop statuses, a queued trace, and cancellation messages indicating shutdown tasks were being canceled. - Linked the stop-product-smoke-20260711.log artifact for review of the run's stop behavior. <a href="https://app.greptile.com/trex/runs/14115543/artifacts"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img alt="View all artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a> <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> </details> <details open><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | src/free_claude_code/messaging/command_context.py | Adds `StopOutcome` and updates stop command context signatures. | | src/free_claude_code/messaging/commands.py | Routes stop confirmations through the new outcome and fallback rules. | | src/free_claude_code/messaging/workflow.py | Builds stop outcomes from voice cancellations and tree cancellation effects. | | src/free_claude_code/runtime/application.py | Maps the messaging stop outcome back to the runtime stop result count. | | tests/messaging/test_handler.py | Covers same-chat status feedback, cross-chat fallback, no-op stops, and voice fallback behavior. | | smoke/product/test_messaging_product_live.py | Updates product smokes for status-only stop success feedback. | </details> <sub>Reviews (2): Last reviewed commit: ["Use task status as the sole stop confirm..."](https://github.com/alishahryar1/free-claude-code/commit/98f0acb01b3405c2afd918539eff49b9410bf487) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43560341)</sub> <!-- /greptile_comment --> |
||
|
|
78377253d6 |
Keep voice ownership continuous through admission (#1063)
## Problem Pending voice ownership ended before workflow admission completed. A concurrent reply or global stop/clear could miss the handoff and return while transcribed work was still able to enter the tree. ## Changes | Before | After | | --- | --- | | The registry released voice and status aliases before the workflow callback finished. | The registry retains both aliases and an owned child through callback completion or explicit cancellation and join. | | Caller and nested cancellation could interrupt cleanup or form recursive joins. | Completion-driven cleanup preserves cancellation state and excludes current or actively cancelling claims. | | Commands coordinated voice-registry and message-tree primitives. | The workflow exposes typed reply and global stop/clear use cases that own voice-to-tree synchronization. | | Admission could be interrupted between tree mutation, processor publication, and persistence. | One workflow-owned transaction validates the epoch, admits work, publishes processing, and persists its exact snapshot. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR keeps voice-message ownership active until admission, stop, or clear work finishes. The main changes are: - Adds registry-managed voice handoff tasks and bulk cancellation. - Moves reply `/stop` and `/clear` into workflow-owned voice/tree operations. - Wraps admission, stop, and clear work so state changes finish before caller cancellation is restored. - Updates platform ports, adapters, tests, smoke fixtures, docs, and package metadata. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. None. <details><summary><h3><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="20" align="absmiddle"></a> T-Rex Logs</h3></summary> **What T-Rex did** - Ran the primary test suite for messaging and platform voice flow; 64 tests passed with exit code 0. - Ran the live smoke tests for messaging product; 15 tests passed with exit code 0. - Captured and organized logs documenting the test commands, working directory, pytest outputs, and exit codes for both runs. <a href="https://app.greptile.com/trex/runs/14110540/artifacts"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img alt="View all artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a> <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> </details> <details open><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | src/free_claude_code/messaging/voice.py | Adds continuous pending-voice ownership, handoff task tracking, alias cleanup, and guarded bulk cancellation. | | src/free_claude_code/messaging/platforms/voice_flow.py | Routes transcription handoff and cleanup through the registry-owned lifecycle. | | src/free_claude_code/messaging/workflow.py | Coordinates voice cancellation with tree admission, reply stop, reply clear, and global stop/clear operations. | | src/free_claude_code/messaging/commands.py | Delegates reply-scoped stop and clear behavior to typed workflow operations. | </details> <sub>Reviews (3): Last reviewed commit: ["Keep voice ownership continuous through ..."](https://github.com/alishahryar1/free-claude-code/commit/14acdfad8c38c1410620ac461fa05988aa417913) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43549792)</sub> <!-- /greptile_comment --> |
||
|
|
3081a72f41 |
Make application shutdown completion-driven (#1056)
## Problem\n\nShutdown could report success after bounded messaging cleanup, hidden persistence failures, or failed managed-process stops. An Admin restart could then construct a replacement while the old runtime still owned work.\n\n## Changes\n\n| Before | After |\n| --- | --- |\n| Runtime reused bounded interactive stop semantics for terminal messaging cleanup. | Workflow close cancels work, stops managed sessions, awaits every claim and recovery task, then flushes persistence. |\n| Explicit persistence failures were logged and treated as successful writes. | Explicit flushes and authoritative writes propagate failure and stay dirty for retry; timer writes remain best effort. |\n| Managed sessions and aliases were removed before subprocess termination was confirmed. | Manager and session terminal states prevent reuse, retain failed owners and PIDs, reject ID collisions, and retry exact sessions. |\n| Admin restart followed the restart request even after incomplete shutdown. | Supervisor restarts only when the prior runtime reports its entire ownership graph closed. |\n| Partial messaging startup cleanup could fail while application startup continued. | Incomplete partial cleanup fails startup and retains the exact graph for a later close attempt. |\n| Messaging task failures read process-global settings. | Runtime injects diagnostic policy and the messaging package depends only on core. |\n| Lifecycle edge cases were verified only in isolated components. | Deterministic and live product coverage proves composed retry, drain, privacy, and customer command behavior. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes application shutdown wait for owned work to finish before restart or exit. The main changes are: - Runtime close now waits for messaging work, managed sessions, and persistence flushes. - Admin restart now requires the previous runtime to report full closure. - Managed Claude sessions now keep aliases and PIDs until stop is confirmed. - Session persistence now propagates explicit write failures and keeps dirty state for retry. - Messaging no longer reads global config from task-failure callbacks. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. No files need attention. <details><summary><h3><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="20" align="absmiddle"></a> T-Rex Logs</h3></summary> **What T-Rex did** - I reviewed the general contract validation proof and confirmed that the lifecycle\_session pytest run completed with 73 passed in 2.68s (EXIT\_CODE: 0) and the messaging pytest run completed with 95 passed in 1.96s (EXIT\_CODE: 0). <a href="https://app.greptile.com/trex/runs/14094038/artifacts"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img alt="View all artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a> <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> </details> <details open><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | src/free_claude_code/messaging/trees/processor.py | Completion callback failures now release task ownership and surface through the idle waiter. | | src/free_claude_code/messaging/workflow.py | Terminal workflow close now cancels tasks, waits for processor cleanup, and flushes persistence. | | src/free_claude_code/runtime/application.py | Runtime shutdown now keeps incomplete ownership cleanup retryable and exposes closure state. | | src/free_claude_code/cli/entrypoints.py | The supervisor now restarts only after the old runtime reports full closure. | | src/free_claude_code/cli/managed/manager.py | Managed session shutdown now blocks reuse and retains failed owners for retry. | | src/free_claude_code/cli/managed/session.py | Managed sessions now mark terminal state under a lifecycle lock and retain PID ownership until exit. | </details> <!-- greptile_failed_comments --> <h3>Comments Outside Diff (1)</h3> 1. `src/free_claude_code/messaging/trees/processor.py`, line 194-202 ([link](https://github.com/alishahryar1/free-claude-code/blob/b736bad1aacb66784e7b4d1e09d27a32b2a380c7/src/free_claude_code/messaging/trees/processor.py#L194-L202)) <a href="#"><img alt="P1" src="https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=9" align="top"></a> **Idle Event Stays Cleared** When `_claim_finished_callback` raises a non-cancellation exception, `_finish_and_continue` exits before `slot.transitioned` is set, before the slot is removed from `_tasks`, and before `_idle` is set. `MessagingWorkflow.close()` now waits on `wait_idle()`, so a finish-path error can leave shutdown waiting forever instead of returning a failed close. <details><summary><strong>Artifacts</strong></summary><br /> **[Repro: standalone async harness that drives TreeQueueManager and forces a finish callback RuntimeError](https://app.greptile.com/trex/artifacts/da413ba3-7f69-459d-b8c8-3141c2bb6c41)** - Contains supporting evidence from the run (text/x-python; charset=utf-8). **[Repro: uv run output showing finish callback RuntimeError, retained task\_count, cleared idle event, and wait\_idle timeout](https://app.greptile.com/trex/artifacts/35b2beaa-ec52-47bd-b36b-2735b3ebc62c)** - Keeps the command output available without making the summary code-heavy. <a href="https://app.greptile.com/trex/runs/14093236/artifacts?artifact=da413ba3-7f69-459d-b8c8-3141c2bb6c41"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifactsDark.svg?v=4"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifacts.svg?v=4"><img alt="View artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifacts.svg?v=4"></picture></a> </details> <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fcompletion-driven-shutdown%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fcompletion-driven-shutdown%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20src%2Ffree_claude_code%2Fmessaging%2Ftrees%2Fprocessor.py%0ALine%3A%20194-202%0A%0AComment%3A%0A**Idle%20Event%20Stays%20Cleared**%0A%0AWhen%20%60_claim_finished_callback%60%20raises%20a%20non-cancellation%20exception%2C%20%60_finish_and_continue%60%20exits%20before%20%60slot.transitioned%60%20is%20set%2C%20before%20the%20slot%20is%20removed%20from%20%60_tasks%60%2C%20and%20before%20%60_idle%60%20is%20set.%20%60MessagingWorkflow.close%28%29%60%20now%20waits%20on%20%60wait_idle%28%29%60%2C%20so%20a%20finish-path%20error%20can%20leave%20shutdown%20waiting%20forever%20instead%20of%20returning%20a%20failed%20close.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=alishahryar1%2Ffree-claude-code&pr=1056&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"><img alt="Fix in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"></picture></a> <!-- /greptile_failed_comments --> <sub>Reviews (2): Last reviewed commit: ["Surface messaging completion failures"](https://github.com/alishahryar1/free-claude-code/commit/39a874c8f0e0614847d80321dd51c9654707a7ff) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43514893)</sub> <!-- /greptile_comment --> |
||
|
|
795a83a826 |
Make pending voice cancellation atomic (#1054)
## Problem Reply-scoped `/clear` could miss a voice note during status delivery or race its final handoff. It could report cancellation while the transcription still executed or later emitted a contradictory error. ## Changes | Before | After | | --- | --- | | Pending state appeared only after status delivery. | The flow reserves an opaque claim before any status I/O. | | Pending checks and removal were separate transitions. | One registry-locked handoff claim is exclusive with cancellation. | | Cancellation always assumed a status message existed. | Cancellation returns the voice ID with an optional bound status ID. | | Stale flows could mutate reused IDs or report late failures. | Exact claim IDs reject ABA updates and make late canceled work cleanup-only. | | Race coverage exercised only ordinary transcription cancellation. | Deterministic tests cover pre-bind cancel, handoff races, stale claims, and late failures. | | The architecture documented registration but not ownership transfer. | The architecture defines reservation, status binding, cancellation, and handoff ownership. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes voice-note cancellation claim-based and race-safe. The main changes are: - Pending voice work now reserves an opaque claim before status delivery. - Status binding, cancellation, discard, and handoff now run through the shared registry. - Reply-scoped `/clear` now handles cancellations with or without a bound status message. - Platform runtimes, smoke fakes, and tests now use the new cancellation result shape. - Architecture notes and package metadata were updated for the patch release. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues were found in the changed code. The registry uses locked claim checks for cancellation, discard, status binding, and handoff, and the updated callers handle cancellation results with and without a status message. No files need attention. <details><summary><h3><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="20" align="absmiddle"></a> T-Rex Logs</h3></summary> **What T-Rex did** - Validated the focused voice cancellation pytest run completed successfully with 58 tests passing (EXIT\_CODE: 0) according to the focused log. - Validated the broader voice cancellation regression pytest run completed successfully with 120 tests passing (EXIT\_CODE: 0) according to the broader log. <a href="https://app.greptile.com/trex/runs/14089714/artifacts"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img alt="View all artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a> <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> </details> <details open><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | src/free_claude_code/messaging/voice.py | Adds claim-based pending voice reservation, status binding, cancellation, discard, and handoff. | | src/free_claude_code/messaging/platforms/voice_flow.py | Reorders voice handling around early claim reservation and exclusive final handoff. | | src/free_claude_code/messaging/commands.py | Updates `/clear` to delete the voice message and optional status message from a cancellation result. | | src/free_claude_code/messaging/platforms/ports.py | Updates the cancellation protocol to return `VoiceCancellationResult | None`. | | src/free_claude_code/messaging/platforms/discord.py | Updates the Discord cancellation signature to match the shared protocol. | | src/free_claude_code/messaging/platforms/telegram.py | Updates the Telegram cancellation signature to match the shared protocol. | | tests/messaging/test_platform_voice_flow.py | Adds race-focused coverage for pre-bind cancellation, late failures, and handoff cancellation. | | tests/messaging/test_voice_services.py | Adds registry coverage for stale claims, duplicate reservations, and cancellation/handoff exclusivity. | | tests/messaging/test_handler.py | Covers `/clear` deletion behavior for bound and unbound voice cancellation results. | | smoke/lib/e2e.py | Updates the fake platform cancellation helper to return the new result object. | | smoke/product/test_messaging_product_live.py | Updates the smoke test setup to use the renamed pending voice seeding helper. | | ARCHITECTURE.md | Documents pending voice reservation, binding, cancellation, and handoff ownership. | | pyproject.toml | Bumps the package version for the production change. | | uv.lock | Synchronizes the lockfile package version. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD A[Voice note received] --> B[Reserve pending claim] B -->|duplicate voice id| Z[Return handled] B --> C[Send status message] C --> D[Bind status id] D -->|canceled or stale claim| E[Delete late status and stop] D --> F[Download and transcribe] F --> G[Claim for handoff] G -->|cancel won| E G -->|handoff won| H[Remove registry entry] H --> I[Invoke message workflow] J[/Reply-scoped clear/] --> K[Cancel registry entry] K --> L[Return voice id and optional status id] L --> M[Delete clear command, voice, and bound status] ``` </a> <a href="#gh-dark-mode-only"> ```mermaid %%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD A[Voice note received] --> B[Reserve pending claim] B -->|duplicate voice id| Z[Return handled] B --> C[Send status message] C --> D[Bind status id] D -->|canceled or stale claim| E[Delete late status and stop] D --> F[Download and transcribe] F --> G[Claim for handoff] G -->|cancel won| E G -->|handoff won| H[Remove registry entry] H --> I[Invoke message workflow] J[/Reply-scoped clear/] --> K[Cancel registry entry] K --> L[Return voice id and optional status id] L --> M[Delete clear command, voice, and bound status] ``` </a> </details> <sub>Reviews (1): Last reviewed commit: ["Make pending voice cancellation atomic"](https://github.com/alishahryar1/free-claude-code/commit/6680c794247d66aa631e78001488492ae8128045) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43507813)</sub> <!-- /greptile_comment --> |
||
|
|
2bcaf3ac74 |
Make messaging trees atomic ownership boundaries (#1048)
## Problem Messaging tree state, queue coordination, task ownership, and persistence were jointly mutated across several classes. Raw message IDs were treated as globally unique, allowing cross-chat collisions and unsafe cancellation or clear ordering. ## Changes | Before | After | | --- | --- | | Managers and processors coordinated partial tree mutations through exposed locks and mutable nodes. | MessageTree owns atomic transitions and returns detached effects to task, UI, and persistence owners. | | Raw message IDs and task identities could collide across chats or detached generations. | Scoped tree identities and opaque claim IDs isolate chats and reject stale task writes. | | Session snapshots duplicated graph links and retained ingress payloads. | Lean scoped snapshots rebuild validated indexes and continue reading existing session files. | | Stop, clear, and runner persistence could interleave across commit boundaries. | Admission epochs, cancellation-safe detach, and authoritative writes make committed cleanup durable. | | Tree implementation classes leaked through messaging package exports. | Adapter-facing values and ports remain supported while tree internals stay internal. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes messaging trees own their state transitions and scoped identities. The main changes are: - Scoped tree and voice ownership by platform and chat. - Opaque claim IDs for queued task execution. - Manager-owned atomic cancellation, clear, and successor task launch paths. - Lean scoped snapshots with legacy session restore support. - Messaging tree internals removed from the public package surface. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. <details><summary><h3><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="20" align="absmiddle"></a> T-Rex Logs</h3></summary> **What T-Rex did** - Executed the messaging and contract-boundary test suite with pytest across all specified test modules. - Observed the run completed with 96 tests passing in 4.10 seconds and an exit code of 0. - The exact pytest command used for the run is documented in the proof to enable reproducibility of the test scope. - The run log is available as an artifact for reviewers to inspect test output and details. <a href="https://app.greptile.com/trex/runs/14083891/artifacts"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img alt="View all artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a> <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> </details> <details open><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | src/free_claude_code/messaging/trees/runtime.py | Adds claim-scoped state transitions and cancellation tombstones for late runner writes. | | src/free_claude_code/messaging/trees/manager.py | Centralizes aggregate publication, branch removal, global clear, and successor task launch decisions. | | src/free_claude_code/messaging/trees/processor.py | Runs tasks by opaque claim ID and routes cleanup through manager-owned finish handling. | | src/free_claude_code/messaging/trees/snapshot.py | Serializes scoped tree snapshots and restores supported legacy tree shapes. | | src/free_claude_code/messaging/voice.py | Scopes pending voice registrations by message scope and message ID. | </details> <!-- greptile_failed_comments --> <h3>Comments Outside Diff (1)</h3> 1. `src/free_claude_code/messaging/commands.py`, line 161-164 ([link](https://github.com/alishahryar1/free-claude-code/blob/a4e49f082a9d3ffc1f6cdf3ab6a065b0f22a759d/src/free_claude_code/messaging/commands.py#L161-L164)) <a href="#"><img alt="P1" src="https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=9" align="top"></a> **Voice Cancellation Is Unscoped** The tree reply path is now scoped by `incoming.scope`, but the voice fallback still cancels by only `chat_id` and `reply_id`. If Discord and Telegram both have the same raw chat/message IDs, a reply `/clear` from one platform can cancel a pending voice note from the other platform, crossing the ownership boundary this PR adds for message trees. <details><summary><strong>Artifacts</strong></summary><br /> **[Repro: focused pytest harness that models cross-platform raw ID collision for voice cancellation](https://app.greptile.com/trex/artifacts/0ad480a9-4e20-4b4e-970e-63aebc4577b3)** - Contains supporting evidence from the run (text/x-python; charset=utf-8). **[Repro: verbose pytest output showing unscoped cancel\_pending\_voice call and Discord-owned voice cancellation from Telegram /clear](https://app.greptile.com/trex/artifacts/ead824f3-2f41-4028-a8e3-8359c5f6d3a9)** - Keeps the command output available without making the summary code-heavy. <a href="https://app.greptile.com/trex/runs/14082218/artifacts?artifact=0ad480a9-4e20-4b4e-970e-63aebc4577b3"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifactsDark.svg?v=4"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifacts.svg?v=4"><img alt="View artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifacts.svg?v=4"></picture></a> </details> <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22architecture%2Fmessage-tree-ownership%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22architecture%2Fmessage-tree-ownership%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20src%2Ffree_claude_code%2Fmessaging%2Fcommands.py%0ALine%3A%20161-164%0A%0AComment%3A%0A**Voice%20Cancellation%20Is%20Unscoped**%0A%0AThe%20tree%20reply%20path%20is%20now%20scoped%20by%20%60incoming.scope%60%2C%20but%20the%20voice%20fallback%20still%20cancels%20by%20only%20%60chat_id%60%20and%20%60reply_id%60.%20If%20Discord%20and%20Telegram%20both%20have%20the%20same%20raw%20chat%2Fmessage%20IDs%2C%20a%20reply%20%60%2Fclear%60%20from%20one%20platform%20can%20cancel%20a%20pending%20voice%20note%20from%20the%20other%20platform%2C%20crossing%20the%20ownership%20boundary%20this%20PR%20adds%20for%20message%20trees.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=alishahryar1%2Ffree-claude-code&pr=1048&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"><img alt="Fix in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"></picture></a> <!-- /greptile_failed_comments --> <sub>Reviews (4): Last reviewed commit: ["Serialize successor task publication wit..."](https://github.com/alishahryar1/free-claude-code/commit/ec8744a8882c1ebc38d5dc7e87aaf2e31b08f653) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43492190)</sub> <!-- /greptile_comment --> |
||
|
|
71a78a0c5a |
Move runtime packages under src namespace (#1029)
## Problem Runtime modules were published as generic top-level packages like `api`, `cli`, and `providers`. That shape is fragile for PyPI packaging and weakens explicit ownership boundaries. ## Changes | Before | After | | --- | --- | | Runtime code lived in root-level packages. | Runtime code lives under `src/free_claude_code/`. | | Console scripts targeted top-level modules. | Console scripts target namespaced modules. | | Tests and smoke helpers imported old package roots. | Tests and smoke helpers import `free_claude_code.*`. | | Packaging listed six root packages. | Packaging builds the single namespaced package. | | Contracts allowed old root package directories. | Contracts require the src namespace and reject old root imports. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR moves the runtime packages into the `src/free_claude_code` namespace. The main changes are: - Console scripts now point to `free_claude_code.*` entrypoints. - Runtime imports, tests, and smoke helpers now use the namespaced package. - Packaging now builds the single `src/free_claude_code` package. - Contract tests now reject old top-level runtime package roots and imports. </details> <h3>Confidence Score: 5/5</h3> This PR is safe to merge with minimal risk. The changes are a broad but mostly mechanical namespace and package-layout migration with updated packaging, tests, and contract coverage. No files require special attention. <details><summary><h3><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="20" align="absmiddle"></a> T-Rex Logs</h3></summary> **What T-Rex did** - Reviewed the primary contract validation by examining the namespace validation log, which documents the exact commands executed, the working directory, exit codes, pytest output, wheel build output, install output, and import/entrypoint resolution. - Verified the wheel listing by inspecting the wheel listing artifact, confirming the available wheel filenames for the namespace validation. - Ran and inspected the isolated import/entrypoint validation harness saved as package-installed-import-check.py to validate import resolution and entrypoint exposure. - Captured and noted the wheel filename record in package-wheel-filename.txt to enable traceability of the observed artifact. <a href="https://app.greptile.com/trex/runs/13810533/artifacts"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img alt="View all artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a> <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> </details> <details open><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | pyproject.toml | Updates packaging to build the single `src/free_claude_code` package and retargets console scripts to namespaced modules. | | src/free_claude_code/config/env_template.py | Loads `.env.example` from packaged resources with a source-checkout fallback after the runtime package move. | | src/free_claude_code/cli/entrypoints.py | Updates CLI entrypoint imports to `free_claude_code.*` and continues to use the shared env template loader. | | src/free_claude_code/api/routes.py | Retargets API route dependencies and handlers to the namespaced package without changing route behavior. | | src/free_claude_code/api/app.py | Updates app factory imports to the namespaced package while preserving middleware, routers, and exception handling. | | src/free_claude_code/providers/runtime/factory.py | Updates lazy provider factory imports to `free_claude_code.providers.*` under the new package layout. | | tests/contracts/test_import_boundaries.py | Adds contract coverage requiring runtime packages to live under `src/free_claude_code` and rejecting old top-level imports. | | smoke/lib/child_process.py | Updates smoke child-process helpers to import CLI entrypoints from the namespaced package. | | README.md | Updates the project layout and extension guidance to refer to `src/free_claude_code` and importable `free_claude_code.*` modules. | | uv.lock | Reflects the package version bump associated with the runtime packaging move. | </details> <details open><summary><h3>Sequence Diagram</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% sequenceDiagram participant User as User / CLI participant Script as Console script participant Pkg as free_claude_code package participant API as free_claude_code.api participant Runtime as free_claude_code.providers.runtime participant Provider as Provider adapter User->>Script: run fcc-server / free-claude-code Script->>Pkg: load free_claude_code.cli.entrypoints:serve Pkg->>API: create FastAPI app and routes API->>Runtime: resolve configured provider Runtime->>Provider: instantiate namespaced adapter Provider-->>Runtime: stream/model responses Runtime-->>API: provider result API-->>User: Anthropic/OpenAI-compatible response ``` </a> <a href="#gh-dark-mode-only"> ```mermaid %%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant User as User / CLI participant Script as Console script participant Pkg as free_claude_code package participant API as free_claude_code.api participant Runtime as free_claude_code.providers.runtime participant Provider as Provider adapter User->>Script: run fcc-server / free-claude-code Script->>Pkg: load free_claude_code.cli.entrypoints:serve Pkg->>API: create FastAPI app and routes API->>Runtime: resolve configured provider Runtime->>Provider: instantiate namespaced adapter Provider-->>Runtime: stream/model responses Runtime-->>API: provider result API-->>User: Anthropic/OpenAI-compatible response ``` </a> </details> <sub>Reviews (2): Last reviewed commit: ["Fix documented package import paths"](https://github.com/alishahryar1/free-claude-code/commit/bfa9f2704c45f3684da39657d5e13f3814e5d450) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=42950471)</sub> <!-- /greptile_comment --> |
||
|
|
d7c54c6dc5 | Preserve messaging transcript on stop | ||
|
|
755a3851f7 |
Use batch delete boundary for messaging (#996)
## Problem Messaging cleanup had two public queued delete paths. Command code could loop single-message deletes and bypass Telegram batch deletion. ## Changes | Before | After | | --- | --- | | Workflow code could call `queue_delete_message` or `queue_delete_messages`. | Workflow code calls only `queue_delete_messages`. | | Telegram `/clear` cleanup used one API request per message. | Telegram `/clear` cleanup uses `deleteMessages` in chunks of 100. | | The outbox dedupe key used Python process hashing. | The outbox dedupe key uses a stable SHA-based digest. | | Voice and smoke cleanup depended on the single-delete queue API. | Voice and smoke cleanup pass one-item delete lists. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR moves messaging cleanup to a list-based delete boundary. The main changes are: - `/clear` now sends collected message IDs through `queue_delete_messages`. - Telegram deletion uses `deleteMessages` in 100-message chunks with per-message fallback. - Discord keeps per-message deletion behind the list-based outbound API. - Delete-batch dedupe keys now use a stable SHA digest instead of Python process hashing. - Voice cleanup, smoke fakes, protocol tests, and messaging tests were updated for the new delete boundary. </details> <h3>Confidence Score: 5/5</h3> Safe to merge with minimal risk. The change is well-scoped to the messaging delete boundary, keeps platform-specific best-effort behavior, addresses the batch-fallback concern, updates protocol consumers and tests, and includes the required version and lockfile bump. No files require special attention. <details><summary><h3><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="20" align="absmiddle"></a> T-Rex Logs</h3></summary> **What T-Rex did** - No execution evidence is available for this session; no harness was created, no tests were run, and no artifacts were produced. <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> </details> <details open><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | messaging/commands.py | Routes `/clear` cleanup through `queue_delete_messages` once per collected message set while preserving best-effort state cleanup. | | messaging/platforms/outbox.py | Removes single-delete queueing, snapshots delete batches, and uses a stable SHA digest for delete dedupe keys. | | messaging/platforms/telegram_io.py | Adds Telegram `deleteMessages` batching with 100-message chunks and per-message fallback when batch deletion fails. | | messaging/platforms/discord_io.py | Removes the public single queued-delete wrapper and backs queued deletion with the list-based outbox API. | | messaging/platforms/voice_flow.py | Changes shared voice cleanup call sites to submit one-item lists to the delete queue. | | messaging/platforms/ports.py | Narrows the outbound protocol to the list-based delete queue method. | | tests/messaging/test_telegram.py | Adds Telegram batch delete, chunking, and fallback coverage. | | tests/messaging/test_platform_outbox.py | Covers stable delete-batch dedupe keys and snapshotting mutable message ID lists before queueing. | | pyproject.toml | Bumps the package patch version for the production messaging changes. | | uv.lock | Updates the editable package version in the lockfile to match `pyproject.toml`. | </details> <details open><summary><h3>Sequence Diagram</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Command as /clear or voice cleanup participant Outbound as OutboundMessenger.queue_delete_messages participant Outbox as PlatformOutbox participant Telegram as TelegramMessenger participant Discord as DiscordMessenger participant API as Platform API Command->>Outbound: queue_delete_messages(chat_id, message_ids) Outbound->>Outbox: snapshot IDs and dedupe batch alt Telegram Outbox->>Telegram: delete_messages(chat_id, ids) loop chunks of 100 Telegram->>API: deleteMessages(chat_id, chunk) alt batch fails Telegram->>API: deleteMessage(chat_id, each id) end end else Discord Outbox->>Discord: delete_messages(chat_id, ids) loop each id Discord->>API: fetch_message + delete end end ``` </a> <a href="#gh-dark-mode-only"> ```mermaid %%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant Command as /clear or voice cleanup participant Outbound as OutboundMessenger.queue_delete_messages participant Outbox as PlatformOutbox participant Telegram as TelegramMessenger participant Discord as DiscordMessenger participant API as Platform API Command->>Outbound: queue_delete_messages(chat_id, message_ids) Outbound->>Outbox: snapshot IDs and dedupe batch alt Telegram Outbox->>Telegram: delete_messages(chat_id, ids) loop chunks of 100 Telegram->>API: deleteMessages(chat_id, chunk) alt batch fails Telegram->>API: deleteMessage(chat_id, each id) end end else Discord Outbox->>Discord: delete_messages(chat_id, ids) loop each id Discord->>API: fetch_message + delete end end ``` </a> </details> <sub>Reviews (2): Last reviewed commit: ["Preserve Telegram batch delete fallback"](https://github.com/alishahryar1/free-claude-code/commit/87090edcd95c4014cae37c2f540d9bfa4eba8962) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=41993526)</sub> <!-- /greptile_comment --> |
||
|
|
28e8996121 |
Make messaging cancellation terminal (#995)
## Problem Messaging `/clear` and `/stop` could return before cancelled node tasks finished cleanup. Late cleanup could save stale conversation state after `/clear` reset FCC state. ## Changes | Before | After | | --- | --- | | Tree cancellation called `task.cancel()` and returned immediately. | Tree cancellation awaits cancelled task cleanup outside tree locks with a bounded timeout. | | Node runners saved snapshots even after their tree was removed or replaced. | Node runners save only when their node still belongs to the active tree queue. | | `/clear` deletion stopped at a batch failure and left tracking vague. | `/clear` attempts each tracked delete independently and clears FCC-owned tracking state. | | Architecture docs did not state terminal cancellation ownership. | Architecture docs assign terminal cancellation to `messaging/trees` and guarded cleanup persistence to node runners. | | Package metadata stayed at `3.4.0`. | Package metadata and lockfile move to `3.4.1`. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes messaging cancellation wait for node cleanup before command cleanup continues. The main changes are: - Drains cancelled tree tasks with a bounded timeout outside tree locks. - Guards node-runner snapshot saves so removed or replaced trees are not restored by late cleanup. - Changes `/clear` deletion to try each tracked platform message independently. - Removes cleared branch message IDs from FCC-owned tracking state. - Adds cancellation, stale-save, and clear-delete regression tests. - Bumps package metadata and lockfile version to `3.4.1`. </details> <h3>Confidence Score: 5/5</h3> Safe to merge with minimal risk. The cancellation paths now drain outside tree locks with a bounded wait, stale snapshot persistence is guarded, and `/clear` continues through individual delete failures. Tests cover the key cancellation cleanup, timeout, stale-save, and clear-delete cases. No blocking correctness or security issues were found in the changed files. No files require special attention. <details><summary><h3><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="20" align="absmiddle"></a> T-Rex Logs</h3></summary> **What T-Rex did** - Ran the messaging cancellation test suite with verbose output to capture the command, current working directory, timestamps, and verbose test names. - Verified the targeted cancellation tests passed, including test\_cancel\_tree\_waits\_for\_current\_task\_cleanup, test\_cancel\_node\_waits\_for\_current\_task\_cleanup, test\_cancel\_branch\_waits\_for\_current\_task\_cleanup, test\_cancel\_all\_waits\_for\_current\_task\_cleanup\_across\_trees, and test\_cancel\_task\_drain\_timeout\_is\_bounded. - Verified that the coverage tests for /clear handling and stale persistence guard also passed, including test\_handle\_message\_clear\_command\_stops\_deletes\_and\_wipes\_state and test\_cancelled\_node\_runner\_does\_not\_save\_after\_clear\_replaces\_queue. <a href="https://app.greptile.com/trex/runs/13359514/artifacts"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img alt="View all artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a> <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> </details> <details open><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | messaging/trees/manager.py | Makes tree, node, branch, and all-tree cancellation await cancelled task cleanup outside tree locks with a bounded drain helper. | | messaging/node_runner.py | Guards runner-owned snapshot saves by confirming the node still belongs to the active tree queue. | | messaging/commands.py | Updates `/clear` deletion to attempt message deletes individually and forget branch-owned message IDs after branch clears. | | messaging/session/message_log.py | Adds targeted removal of tracked message IDs while keeping the per-chat ID cache synchronized. | | tests/messaging/test_tree_queue.py | Adds cancellation-drain tests for tree, node, branch, all-tree, and timeout-bounded cleanup paths. | | tests/messaging/test_handler.py | Adds coverage for resilient clear deletion, branch message-log cleanup, and stale cancellation persistence prevention. | </details> <details open><summary><h3>Sequence Diagram</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% sequenceDiagram participant User participant Commands as messaging/commands.py participant Manager as TreeQueueManager participant Tree as MessageTree participant Runner as MessagingNodeRunner participant Store as SessionStore participant Outbound as OutboundMessenger User->>Commands: /clear or /stop Commands->>Manager: cancel_tree/cancel_branch/cancel_all Manager->>Tree: cancel_current_task() Tree-->>Manager: cancelled asyncio.Task Manager->>Tree: mark queued/current nodes ERROR Manager->>Runner: task cancellation propagates Manager->>Manager: await _drain_cancelled_tasks(timeout) Runner->>Runner: cancellation cleanup/update UI Runner->>Manager: check active tree for node alt node still belongs to active queue Runner->>Store: save_tree_snapshot(snapshot) else tree removed or queue replaced Runner-->>Store: skip stale save end Commands->>Outbound: delete tracked messages individually Commands->>Store: clear_all or forget_message_ids ``` </a> <a href="#gh-dark-mode-only"> ```mermaid %%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant User participant Commands as messaging/commands.py participant Manager as TreeQueueManager participant Tree as MessageTree participant Runner as MessagingNodeRunner participant Store as SessionStore participant Outbound as OutboundMessenger User->>Commands: /clear or /stop Commands->>Manager: cancel_tree/cancel_branch/cancel_all Manager->>Tree: cancel_current_task() Tree-->>Manager: cancelled asyncio.Task Manager->>Tree: mark queued/current nodes ERROR Manager->>Runner: task cancellation propagates Manager->>Manager: await _drain_cancelled_tasks(timeout) Runner->>Runner: cancellation cleanup/update UI Runner->>Manager: check active tree for node alt node still belongs to active queue Runner->>Store: save_tree_snapshot(snapshot) else tree removed or queue replaced Runner-->>Store: skip stale save end Commands->>Outbound: delete tracked messages individually Commands->>Store: clear_all or forget_message_ids ``` </a> </details> <sub>Reviews (2): Last reviewed commit: ["Bound messaging cancellation drain"](https://github.com/alishahryar1/free-claude-code/commit/d63b5b43f5fce98469741a530154961a0a535c9d) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=41990665)</sub> <!-- /greptile_comment --> |
||
|
|
002012dfcd | Refactor messaging conversation state (#931) | ||
|
|
d281d52ced | Refactor messaging around explicit ports (#878) | ||
|
|
a97bf7f8b3 | Refactor messaging workflow architecture (#852) | ||
|
|
29e7714337 |
feat(logging): structured TRACE events and end-to-end request correlation
Add core/trace.py with trace_event, traced_async_stream, and payload snapshots. Merge TRACE fields into JSON logs; promote claude_session_id, http path/method. Instrument API, messaging/CLI, and OpenAI-compat/native provider paths. Harden log sink with enqueue and stdlib intercept re-entrancy guard. Document behavior in .env.example and README; extend tests. |
||
|
|
0cca5699cb |
fix(messaging): reuse parent CLI session for Telegram reply continuation (#233)
Pass parent_session_id into get_or_create_session so reply nodes align with the fork/resume path instead of always allocating a fresh pending session. Add unit coverage and update integration expectations. |
||
|
|
f3a7528d49 |
Major refactor: API, providers, messaging, and Anthropic protocol
Consolidates the incremental refactor work into a single change set: modular web tools (api/web_tools), native Anthropic request building and SSE block policy, OpenAI conversion and error handling, provider transports and rate limiting, messaging handler and tree queue, safe logging, smoke tests, and broad test coverage. |
||
|
|
fae8a2a044 |
Remove over-engineering: drop tree_queue setter, _set_connected(), fi… (#63)
…x cancel_all() TOCTOU - Remove tree_queue property setter (backward-compat hack; all callers already migrated to replace_tree_queue()); keep property getter only - Update 2 remaining tests that still used direct assignment to use replace_tree_queue() - Remove _set_connected() 1-line wrapper on DiscordPlatform; assign _connected directly - Fix cancel_all() TOCTOU: hold self._lock for the full loop so newly created trees cannot slip through between the snapshot and cancellation --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
35a2760f6e | Fixed encapsulation violations | ||
|
|
aee9f0ad93 | Add code review fix plan covering 11 issues across modularity, encapsulation, performance, and dead code (#62) | ||
|
|
0c8d59e33e | Removed deprecated modules and updated imports | ||
|
|
99f99fce90 |
Remove max_cli_sessions — CLI session pool is now unbounded
The max_sessions cap in CLISessionManager was the only thing enforcing a limit on concurrent CLI processes. Now that provider concurrency is controlled at the streaming layer (PROVIDER_MAX_CONCURRENCY semaphore), the CLI session pool cap is redundant and removed entirely. Changes: - cli/manager.py: remove max_sessions param, cap check, _cleanup_idle_sessions_unlocked, max_sessions from get_stats() - config/settings.py: remove max_cli_sessions field - api/app.py: remove max_sessions=settings.max_cli_sessions from CLISessionManager constructor - messaging/handler.py: remove "Waiting for slot" status check; stats display no longer shows Max CLI - .env.example: remove MAX_CLI_SESSIONS line - tests/cli/test_cli.py: remove max_sessions args and assertion from manager tests - tests/cli/test_cli_manager_edge_cases.py: remove two tests for cap/cleanup behavior - tests/api/test_app_lifespan_and_errors.py: remove max_cli_sessions from all SimpleNamespace settings - tests/config/test_config.py: remove max_cli_sessions isinstance assertion - tests/conftest.py: remove max_sessions from mock stats - tests/messaging/test_handler.py: merge slot/capacity tests into single new-conversation test; remove Max CLI assertion from stats test - tests/messaging/test_handler_markdown_and_status_edges.py: remove "Waiting for slot" assertion; drop max_sessions from all stats mocks https://claude.ai/code/session_014mrF1WMNgmNjtPBuoQHsbg |
||
|
|
16fa9d90cd |
Add message_thread_id support across messaging components
- Introduced message_thread_id to the IncomingMessage model for handling forum topic IDs in Telegram. - Updated messaging platforms (Discord and Telegram) to accept and process message_thread_id in send_message methods. - Modified message handlers to utilize message_thread_id when sending messages. - Enhanced test cases to validate the integration of message_thread_id in message handling. This change improves support for forum supergroups in Telegram and enhances message management across platforms. |
||
|
|
2220880671 |
Add voice note cancellation feature during transcription
- Implemented functionality to cancel pending voice transcriptions when a user replies with the /clear command. - Updated the Telegram and Discord platform classes to manage pending voice messages, including registration and cancellation logic. - Enhanced the message handler to delete associated messages and notify users when a voice note is cancelled. - Added tests to ensure the cancellation feature works as expected during transcription. |
||
|
|
b05d0d2703 | new linter rules and fixes | ||
|
|
4b4f87515d |
Phase 7: Directory restructuring (messaging/ and tests/)
- Create messaging/platforms/ (base, discord, telegram, factory) - Create messaging/rendering/ (discord_markdown, telegram_markdown) - Create messaging/trees/ (data, repository, processor, queue_manager) - Organize tests/ into api/, providers/, messaging/, cli/, config/ - Add backward-compatible re-exports at old locations - Update handler.py and test_messaging_factory.py imports - Fix Telegram type hints for TELEGRAM_AVAILABLE=False case - Fix Python 3 except syntax in discord_markdown Co-authored-by: Ali Khokhar <alishahryar2@gmail.com> |