Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,8 @@ Options:
- `--channel <channel-refs>` - Filter by channels (comma-separated IDs)
- `--author <user-refs>` - Filter by author (comma-separated IDs)
- `--mention-me` - Only results mentioning current user
- `--since <date>` - Content from date
- `--until <date>` - Content until date
- `--since <date>` - Content posted since date
- `--until <date>` - Content posted until date
- `--limit <n>` - Max results (default: 50)
- `--cursor <cursor>` - Pagination cursor
- `--json` / `--ndjson` - Machine-readable output
Expand Down
8 changes: 5 additions & 3 deletions skills/comms-cli/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ tdc thread view <ref> --comment <id> # View a specific comment
tdc thread view <url-with-/c/id> # Comment ID extracted from URL
tdc thread view <ref> --unread # Show only unread comments
tdc thread view <ref> --context 3 # Include 3 read comments before unread
tdc thread view <ref> --limit 20 # Limit number of comments
tdc thread view <ref> --limit 20 # Max comments to show (default: 50; the header says when it left some out)
tdc thread view <ref> --since <date> # Comments newer than date
tdc thread view <ref> --raw # Show raw markdown
tdc thread create <channel-ref> "Title" "content" # Create a new thread
Expand Down Expand Up @@ -235,14 +235,16 @@ tdc search "query" --to <ref> # Messages sent to user
tdc search "query" --title-only # Search thread titles only
tdc search "query" --mention-me # Results mentioning current user
tdc search "query" --conversation <refs> # Limit to conversations (comma-separated refs)
tdc search "query" --since <date> # Content from date
tdc search "query" --until <date> # Content until date
tdc search "query" --since <date> # Content posted since date
tdc search "query" --until <date> # Content posted until date
tdc search "query" --channel <refs> # Filter by channel refs (comma-separated)
tdc search "query" --limit <n> # Max results (default: 50)
tdc search "query" --cursor <cur> # Pagination cursor
tdc search "query" --all # Fetch all result pages
```

`--since` and `--until` filter by when the matching content was posted, not when a thread was last active, so a thread found by its title (`--title-only`) counts from when it was created.

## Users, Channels & Groups

```bash
Expand Down
68 changes: 68 additions & 0 deletions src/commands/thread/thread.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,74 @@ describe('thread view date filters', () => {
})
})

describe('thread view comment count header', () => {
beforeEach(() => {
clearWorkspaceUserCache()
vi.clearAllMocks()
configMocks.getConfig.mockResolvedValue({})
groupsMock.getWorkspaceGroups.mockResolvedValue([])
groupsMock.getWorkspaceUsers.mockResolvedValue([])
})

const users = { 1: { id: 1, fullName: 'Alice' }, 2: { id: 2, fullName: 'Bob' } }

async function viewOutput(client: ReturnType<typeof createClient>, args: string[]) {
apiMocks.getCommsClient.mockResolvedValue(client)
const program = createProgram()
const consoleSpy = captureConsole('log')
await program.parseAsync(['node', 'tdc', 'thread', 'view', '500', ...args])
return consoleSpy.mock.calls.map((c) => c[0]).join('\n')
}

it('shows the plain count when every comment came back', async () => {
const client = createClient({
comments: [createComment(1, 1), createComment(2, 2), createComment(3, 3)],
users,
})

const output = await viewOutput(client, [])

expect(output).toContain('--- 3 comments ---')
})

it('says how many comments the limit left out', async () => {
const client = createClient({
thread: { ...createThreadFixture(500), commentCount: 68 },
comments: [createComment(1, 1), createComment(2, 2)],
users,
})

const output = await viewOutput(client, ['--limit', '2'])

expect(output).toContain('--- 2 of 68 comments (use --limit for more) ---')
})

it('says when a date-filtered view reached the limit', async () => {
const client = createClient({
thread: { ...createThreadFixture(500), commentCount: 68 },
comments: [createComment(1, 1), createComment(2, 2)],
users,
})

const output = await viewOutput(client, ['--since', '2026-01-01', '--limit', '2'])

expect(output).toContain('--- 2 comments (limit reached, use --limit for more) ---')
expect(output).not.toContain('of 68')
})

it('shows the plain count for a date-filtered view under the limit', async () => {
const client = createClient({
thread: { ...createThreadFixture(500), commentCount: 68 },
comments: [createComment(1, 1), createComment(2, 2)],
users,
})

const output = await viewOutput(client, ['--since', '2026-01-01'])

expect(output).toContain('--- 2 comments ---')
})
})

describe('thread view error propagation', () => {
beforeEach(() => {
clearWorkspaceUserCache()
Expand Down
28 changes: 27 additions & 1 deletion src/commands/thread/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,24 @@ type ViewOptions = PaginatedViewOptions & {
context?: string
}

// getComments stops at the limit, so say when that left comments out. A date filter makes the
// thread's own count meaningless, so all that's left to report then is hitting the limit.
function formatCommentsHeader(
shown: number,
total: number,
limit: number,
isDateFiltered: boolean,
): string {
const label = `${shown} ${pluralize(shown, 'comment')}`
if (!isDateFiltered && total > shown) {
return `--- ${shown} of ${total} comments (use --limit for more) ---`
}
if (isDateFiltered && shown >= limit) {
return `--- ${label} (limit reached, use --limit for more) ---`
}
return `--- ${label} ---`
}

async function viewSingleComment(
client: CommsApi,
threadId: string,
Expand Down Expand Up @@ -200,8 +218,16 @@ export async function viewThread(ref: string, options: ViewOptions): Promise<voi
console.log('')

if (comments.length > 0) {
const isDateFiltered = options.since !== undefined || options.until !== undefined
console.log(
chalk.dim(`--- ${comments.length} ${pluralize(comments.length, 'comment')} ---`),
chalk.dim(
formatCommentsHeader(
comments.length,
thread.commentCount,
limit,
isDateFiltered,
),
),
)
console.log('')

Expand Down
4 changes: 2 additions & 2 deletions src/lib/search-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ export function addSharedSearchOptions<T extends Command>(

return command
.option('--conversation <refs>', 'Limit to conversations (comma-separated refs)')
.option('--since <date>', 'Content from date')
.option('--until <date>', 'Content until date')
.option('--since <date>', 'Content posted since date')
.option('--until <date>', 'Content posted until date')
.option('--limit <n>', limitDescription)
.option('--cursor <cursor>', 'Pagination cursor')
.option('--all', 'Fetch all pages of results')
Expand Down
8 changes: 5 additions & 3 deletions src/lib/skills/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ tdc thread view <ref> --comment <id> # View a specific comment
tdc thread view <url-with-/c/id> # Comment ID extracted from URL
tdc thread view <ref> --unread # Show only unread comments
tdc thread view <ref> --context 3 # Include 3 read comments before unread
tdc thread view <ref> --limit 20 # Limit number of comments
tdc thread view <ref> --limit 20 # Max comments to show (default: 50; the header says when it left some out)
tdc thread view <ref> --since <date> # Comments newer than date
tdc thread view <ref> --raw # Show raw markdown
tdc thread create <channel-ref> "Title" "content" # Create a new thread
Expand Down Expand Up @@ -239,14 +239,16 @@ tdc search "query" --to <ref> # Messages sent to user
tdc search "query" --title-only # Search thread titles only
tdc search "query" --mention-me # Results mentioning current user
tdc search "query" --conversation <refs> # Limit to conversations (comma-separated refs)
tdc search "query" --since <date> # Content from date
tdc search "query" --until <date> # Content until date
tdc search "query" --since <date> # Content posted since date
tdc search "query" --until <date> # Content posted until date
tdc search "query" --channel <refs> # Filter by channel refs (comma-separated)
tdc search "query" --limit <n> # Max results (default: 50)
tdc search "query" --cursor <cur> # Pagination cursor
tdc search "query" --all # Fetch all result pages
\`\`\`

\`--since\` and \`--until\` filter by when the matching content was posted, not when a thread was last active, so a thread found by its title (\`--title-only\`) counts from when it was created.

## Users, Channels & Groups

\`\`\`bash
Expand Down
Loading