Skip to content

Conversation

@mkyutani
Copy link
Collaborator

@mkyutani mkyutani commented Nov 3, 2025

Summary

This PR implements two major thread-related features for the ssky tool:

  1. Thread Retrieval (Add thread-based retrieval functionality for get and search commands #47): Retrieve posts with their complete conversation threads
  2. Thread Splitting (feat: Auto-split long posts into threads with facet preservation #51): Auto-split long posts into threads with facet preservation

Changes

New Files

  • src/ssky/thread_data.py: Represents a single thread with flattened post structure
  • src/ssky/thread_data_list.py: Holds multiple ThreadData objects
  • tests/test_thread.py: Comprehensive test suite with 9 test cases

Modified Files

  • src/ssky/get.py: Added --thread support with thread retrieval logic
  • src/ssky/post.py: Added automatic thread splitting for long posts (>300 chars)
  • src/ssky/main.py: Added --thread, --thread-depth, --thread-parent-height, --no-split options
  • src/ssky/result.py: Added InvalidOptionCombinationError and TooLongForThreadError
  • tests/test_get.py: Fixed parameter names (param=target=)
  • README.md: Added thread retrieval and splitting documentation
  • CLAUDE.md: Updated architecture documentation

Feature 1: Thread Retrieval (#47)

Command Line Options

--thread                      # Retrieve full thread for each post
--thread-depth NUM            # Maximum depth of replies (default: 10)
--thread-parent-height NUM    # Number of parent posts (default: 0)

Supported Targets

The --thread option works with ALL target types:

  • Timeline: ssky get --thread
  • Author feeds: ssky get user.bsky.social --thread
  • DIDs: ssky get did:plc:xxx --thread
  • Single posts: ssky get at://... --thread

Output Formatting

  • Short/ID format (-S, -I): Reply lines prefixed with "| "
  • Long/Text format (-L, -T): Posts within thread separated by "|", independent threads by "----------------"
  • JSON/simple_json: Raises InvalidOptionCombinationError (cannot be used with --thread)

Usage Examples

# Get timeline with threads
ssky get --thread

# Get specific post's thread
ssky get at://did:plc:.../app.bsky.feed.post/... --thread

# Get user's posts as threads with custom depth
ssky get user.bsky.social --thread --thread-depth 5 --thread-parent-height 2

Feature 2: Thread Splitting (#51)

Automatic Thread Splitting

Posts exceeding 300 characters are automatically split into threads:

ssky post "Very long text that exceeds 300 characters..."
# Output:
# (1/3) Very long text that exceeds...
# (2/3) ...continuation with preserved @mentions...
# (3/3) ...and #hashtags https://links.com

Facet Preservation

  • Links, mentions, and hashtags are preserved across splits
  • Split boundaries never break facets
  • Byte positions recalculated for each part
  • URL shortening remains compatible

Opt-out Option

# Disable splitting (will fail if > 300 chars)
ssky post "long text" --no-split

Limits

  • Maximum 99 posts per thread
  • Raises TooLongForThreadError if message would require 100+ posts
  • Character budget: 285 chars per part (accounting for continuation marks)

Testing

All tests pass (130 total):

  • 9 new thread retrieval tests in tests/test_thread.py
  • Tests cover initialization, retrieval, formatting, and error handling
  • Thread splitting tests verify facet preservation and continuation marks
  • Backward compatibility maintained for existing commands

Implementation Details

Thread Retrieval

  1. ThreadData class: Flattens recursive thread structure into list of (post, depth) tuples
  2. ThreadDataList class: Holds multiple threads with proper separator logic
  3. get() function: Retrieves threads for each post when --thread is specified
  4. Validation: Prevents invalid option combinations

Thread Splitting

  1. Character counting: Uses grapheme cluster counting (300 limit)
  2. Facet preservation: Recalculates byte positions after adding continuation marks
  3. Smart splitting: Prefers sentence > paragraph > word boundaries
  4. Thread structure: First post as root, subsequent posts as replies

Commits

  • cc78daa: feat: add automatic thread splitting for long posts
  • a488057: feat: add thread retrieval for get command
  • ab12b95: fix: reject --thread with --json/--simple-json
  • dbf4c73: docs: add thread retrieval documentation

Related Issues

Closes #47
Closes #51

@mkyutani mkyutani changed the title feat: add thread retrieval functionality to get command feat: add thread retrieval and automatic thread splitting Nov 3, 2025
@mkyutani mkyutani merged commit a0b1228 into simpleskyclient:main Nov 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Auto-split long posts into threads with facet preservation Add thread-based retrieval functionality for get and search commands

1 participant