From 41b453c15703918db3403ec06b2e762444a6dc2e Mon Sep 17 00:00:00 2001 From: Enric Enrich Date: Wed, 28 Oct 2026 16:12:20 +0100 Subject: [PATCH 1/5] fix: send explicit Status field and effect removals --- src/commands/status/set.ts | 16 ++++++---------- src/commands/status/status.test.ts | 30 +++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/commands/status/set.ts b/src/commands/status/set.ts index 54d6e4d..a13d05a 100644 --- a/src/commands/status/set.ts +++ b/src/commands/status/set.ts @@ -88,16 +88,12 @@ export async function setStatus(message: string, options: SetStatusOptions): Pro const args: SetStatusArgs = { message: text, - ...(emoji ? { emoji } : {}), - ...(activeUntil ? { activeUntil } : {}), - ...(options.pauseNotifications || options.pauseActivity - ? { - effects: { - ...(options.pauseNotifications ? { pauseNotifications: {} } : {}), - ...(options.pauseActivity ? { pauseActivity: {} } : {}), - }, - } - : {}), + emoji: emoji ?? null, + activeUntil: activeUntil ?? null, + effects: { + pauseNotifications: options.pauseNotifications ? {} : null, + pauseActivity: options.pauseActivity ? {} : null, + }, } if (options.dryRun) { diff --git a/src/commands/status/status.test.ts b/src/commands/status/status.test.ts index 906d8f2..13d9eac 100644 --- a/src/commands/status/status.test.ts +++ b/src/commands/status/status.test.ts @@ -131,10 +131,15 @@ describe('tdc status', () => { }) describe('set', () => { - it('sends the message alone when nothing else is given', async () => { + it('explicitly removes omitted optional values and known effects', async () => { captureConsole('log') await run('set', 'Away') - expect(users.setStatus).toHaveBeenCalledWith({ message: 'Away' }) + expect(users.setStatus).toHaveBeenCalledWith({ + message: 'Away', + emoji: null, + activeUntil: null, + effects: { pauseNotifications: null, pauseActivity: null }, + }) }) it('sends emoji, an --until date and the pause effect', async () => { @@ -152,7 +157,7 @@ describe('tdc status', () => { message: 'Holiday', emoji: '🏝️', activeUntil: new Date('2026-10-20T09:00:00Z'), - effects: { pauseNotifications: {} }, + effects: { pauseNotifications: {}, pauseActivity: null }, }) }) @@ -160,8 +165,10 @@ describe('tdc status', () => { captureConsole('log') await run('set', 'Holiday', '--pause-activity') expect(users.setStatus).toHaveBeenCalledWith({ + emoji: null, + activeUntil: null, message: 'Holiday', - effects: { pauseActivity: {} }, + effects: { pauseNotifications: null, pauseActivity: {} }, }) }) @@ -169,6 +176,8 @@ describe('tdc status', () => { captureConsole('log') await run('set', 'Holiday', '--pause-notifications', '--pause-activity') expect(users.setStatus).toHaveBeenCalledWith({ + emoji: null, + activeUntil: null, message: 'Holiday', effects: { pauseNotifications: {}, pauseActivity: {} }, }) @@ -204,6 +213,8 @@ describe('tdc status', () => { captureConsole('log') await run('set', 'Focus', '--for', '1h30m') expect(users.setStatus).toHaveBeenCalledWith({ + emoji: null, + effects: { pauseNotifications: null, pauseActivity: null }, message: 'Focus', activeUntil: new Date('2026-10-14T13:30:00.000Z'), }) @@ -240,6 +251,8 @@ describe('tdc status', () => { captureConsole('log') await run('set', 'Holiday', '--until', '2026-10-20') expect(users.setStatus).toHaveBeenCalledWith({ + emoji: null, + effects: { pauseNotifications: null, pauseActivity: null }, message: 'Holiday', activeUntil: new Date(2026, 9, 20), }) @@ -357,7 +370,12 @@ describe('tdc status set input guards', () => { it('sends the trimmed message', async () => { captureConsole('log') await run('set', ' Away ') - expect(users.setStatus).toHaveBeenCalledWith({ message: 'Away' }) + expect(users.setStatus).toHaveBeenCalledWith({ + emoji: null, + activeUntil: null, + effects: { pauseNotifications: null, pauseActivity: null }, + message: 'Away', + }) }) it.each([80, 41])( @@ -373,6 +391,8 @@ describe('tdc status set input guards', () => { captureConsole('log') await run('set', 'ok', '--until', '2026-10-20T09:00+02:00') expect(users.setStatus).toHaveBeenCalledWith({ + emoji: null, + effects: { pauseNotifications: null, pauseActivity: null }, message: 'ok', activeUntil: new Date('2026-10-20T07:00:00Z'), }) From 60f85ae14024b0956bc4fdf856c9243b5eca3c27 Mon Sep 17 00:00:00 2001 From: Enric Enrich Date: Wed, 28 Oct 2026 16:12:39 +0100 Subject: [PATCH 2/5] docs: clarify Status set replacement behavior --- skills/comms-cli/SKILL.md | 4 +++- src/commands/status/index.ts | 3 ++- src/lib/skills/content.ts | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/skills/comms-cli/SKILL.md b/skills/comms-cli/SKILL.md index 2980e5c..84fb3dc 100644 --- a/skills/comms-cli/SKILL.md +++ b/skills/comms-cli/SKILL.md @@ -257,7 +257,7 @@ tdc users --include-removed # Include users removed from the workspace tdc users --ids-only # Output only user IDs tdc status # Show your status (default login is enough) tdc status --json # Show it as { status } JSON (null when unset; --full for the whole user) -tdc status set "Deep work" --emoji 🎯 --for 2h --pause-notifications # Set it (replaces any current status; needs --full-access) +tdc status set "Deep work" --emoji 🎯 --for 2h --pause-notifications # Set supported fields (needs --full-access) tdc status set "On holiday" --pause-activity # Pause Todoist Karma and streaks while it is active (independent of --pause-notifications) tdc status set "On holiday" --until 2026-10-20T09:00 # End at a date (YYYY-MM-DD, YYYY-MM-DDTHH:MM or a full ISO 8601 timestamp; local time unless it has Z or an offset) tdc status set "Away" --dry-run # Preview without setting @@ -323,6 +323,8 @@ All group *writes* (`groups create`, `rename`, `delete`, `add-user`, `remove-use `tdc status set` and `tdc status clear` need the `user:write` scope, which only `tdc auth login --full-access` grants. `tdc status` (show) works on a default login. +`tdc status set` replaces the fields this CLI supports: omitted emoji, expiration and pause flags clear those values, while other fields and effects are preserved. + Only pass `--pause-notifications` when the user asks for it. It holds back Comms notifications only for now: each app has to read the status and hold its own notifications back, and Todoist does not yet. Held notifications are not sent later. Only pass `--pause-activity` when the user asks for it. It pauses their Todoist Karma and streaks while the status is active. It is independent of `--pause-notifications`: it does not hold back notifications, and pausing notifications does not protect Karma. diff --git a/src/commands/status/index.ts b/src/commands/status/index.ts index 5e78ab5..d0e683f 100644 --- a/src/commands/status/index.ts +++ b/src/commands/status/index.ts @@ -22,7 +22,7 @@ Examples: status .command('set ') - .description('Set your status, replacing any current one') + .description('Set your status, replacing the fields this CLI supports') .option('--emoji ', 'Emoji to show next to the message') .option( '--until ', @@ -49,6 +49,7 @@ Setting or clearing it needs the user:write scope, so log in with tdc auth login its own notifications back, and Todoist does not yet. Held notifications are not sent later. --pause-activity protects your Todoist Karma and streaks. It does not hold back notifications, and --pause-notifications does not protect Karma, so pass both if you want both. +Omitting the emoji, expiration or a pause flag clears that value. Other fields and effects are preserved. Examples: tdc status set "On holiday" --emoji 🏝️ --until 2026-10-20T09:00 diff --git a/src/lib/skills/content.ts b/src/lib/skills/content.ts index 5af13af..0f9fb93 100644 --- a/src/lib/skills/content.ts +++ b/src/lib/skills/content.ts @@ -261,7 +261,7 @@ tdc users --include-removed # Include users removed from the workspace tdc users --ids-only # Output only user IDs tdc status # Show your status (default login is enough) tdc status --json # Show it as { status } JSON (null when unset; --full for the whole user) -tdc status set "Deep work" --emoji 🎯 --for 2h --pause-notifications # Set it (replaces any current status; needs --full-access) +tdc status set "Deep work" --emoji 🎯 --for 2h --pause-notifications # Set supported fields (needs --full-access) tdc status set "On holiday" --pause-activity # Pause Todoist Karma and streaks while it is active (independent of --pause-notifications) tdc status set "On holiday" --until 2026-10-20T09:00 # End at a date (YYYY-MM-DD, YYYY-MM-DDTHH:MM or a full ISO 8601 timestamp; local time unless it has Z or an offset) tdc status set "Away" --dry-run # Preview without setting @@ -327,6 +327,8 @@ All group *writes* (\`groups create\`, \`rename\`, \`delete\`, \`add-user\`, \`r \`tdc status set\` and \`tdc status clear\` need the \`user:write\` scope, which only \`tdc auth login --full-access\` grants. \`tdc status\` (show) works on a default login. +\`tdc status set\` replaces the fields this CLI supports: omitted emoji, expiration and pause flags clear those values, while other fields and effects are preserved. + Only pass \`--pause-notifications\` when the user asks for it. It holds back Comms notifications only for now: each app has to read the status and hold its own notifications back, and Todoist does not yet. Held notifications are not sent later. Only pass \`--pause-activity\` when the user asks for it. It pauses their Todoist Karma and streaks while the status is active. It is independent of \`--pause-notifications\`: it does not hold back notifications, and pausing notifications does not protect Karma. From a3e3657fccac1f06b2b0926f6f76b3e1faeacc0a Mon Sep 17 00:00:00 2001 From: Enric Enrich Date: Wed, 28 Oct 2026 18:30:22 +0100 Subject: [PATCH 3/5] fix: update Comms SDK to 3.9.1 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 97bbd49..400ba04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "license": "MIT", "dependencies": { "@doist/cli-core": "1.7.2", - "@doist/comms-sdk": "3.8.1", + "@doist/comms-sdk": "3.9.1", "@pnpm/tabtab": "0.5.4", "chalk": "5.6.2", "commander": "14.0.3", @@ -432,9 +432,9 @@ } }, "node_modules/@doist/comms-sdk": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@doist/comms-sdk/-/comms-sdk-3.8.1.tgz", - "integrity": "sha512-6lgdPNDd1u70pwCdCGcW5T2TBJHPkJ5fZubzwKjceCmL0j/OIhvmriOuLa+rFt2YuEmcGleIhJIMB2NBYFXj7Q==", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@doist/comms-sdk/-/comms-sdk-3.9.1.tgz", + "integrity": "sha512-l2J7l7x+jHGkE3C06ikpsfYFQu38B7mEpQPcZL9xot+QJuOFRTlFoQ6vk6/fTX0d/Tq5v2vvz1IE8psVauL1jg==", "license": "MIT", "dependencies": { "@doist/sdk-kmp": "0.2.3", diff --git a/package.json b/package.json index 603ccd3..287fb76 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ ], "dependencies": { "@doist/cli-core": "1.7.2", - "@doist/comms-sdk": "3.8.1", + "@doist/comms-sdk": "3.9.1", "@pnpm/tabtab": "0.5.4", "chalk": "5.6.2", "commander": "14.0.3", From fd0a36fd496e09e7156a4d448486390c816019d1 Mon Sep 17 00:00:00 2001 From: Enric Enrich Date: Wed, 28 Oct 2026 19:31:58 +0100 Subject: [PATCH 4/5] fix: show Status removals in dry-run preview --- src/commands/status/set.ts | 8 ++++---- src/commands/status/status.test.ts | 28 +++++++++++++++++----------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/commands/status/set.ts b/src/commands/status/set.ts index a13d05a..72508de 100644 --- a/src/commands/status/set.ts +++ b/src/commands/status/set.ts @@ -99,10 +99,10 @@ export async function setStatus(message: string, options: SetStatusOptions): Pro if (options.dryRun) { printDryRun('set status', { Message: text, - Emoji: emoji, - Until: activeUntil ? formatDateTime(activeUntil) : undefined, - 'Pause notifications': options.pauseNotifications ? 'yes' : undefined, - 'Pause activity': options.pauseActivity ? 'yes' : undefined, + Emoji: emoji ?? 'cleared', + Until: activeUntil ? formatDateTime(activeUntil) : 'cleared', + 'Pause notifications': options.pauseNotifications ? 'yes' : 'cleared', + 'Pause activity': options.pauseActivity ? 'yes' : 'cleared', }) return } diff --git a/src/commands/status/status.test.ts b/src/commands/status/status.test.ts index 13d9eac..cccae04 100644 --- a/src/commands/status/status.test.ts +++ b/src/commands/status/status.test.ts @@ -183,17 +183,23 @@ describe('tdc status', () => { }) }) - it('lists the activity pause in the --dry-run preview only when asked for', async () => { - const spy = captureConsole('log') - await run('set', 'Holiday', '--pause-activity', '--dry-run') - expect(logged(spy)).toContain('Pause activity') - expect(users.setStatus).not.toHaveBeenCalled() - - spy.mockClear() - await run('set', 'Holiday', '--dry-run') - expect(logged(spy)).toContain('Would set status') - expect(logged(spy)).not.toContain('Pause activity') - }) + it.each([ + { flags: [], pauseActivity: 'cleared' }, + { flags: ['--pause-activity'], pauseActivity: 'yes' }, + ])( + 'previews cleared values and Pause activity: $pauseActivity on --dry-run', + async ({ flags, pauseActivity }) => { + const spy = captureConsole('log') + await run('set', 'Holiday', ...flags, '--dry-run') + expect(users.setStatus).not.toHaveBeenCalled() + const out = logged(spy) + expect(out).toContain('Message: Holiday') + expect(out).toContain('Emoji: cleared') + expect(out).toContain('Until: cleared') + expect(out).toContain('Pause notifications: cleared') + expect(out).toContain(`Pause activity: ${pauseActivity}`) + }, + ) it('prints the activity pause in the text output', async () => { users.setStatus.mockResolvedValue({ From c052ae3f3e554c09a3be8c1f7249e37e0c6e0422 Mon Sep 17 00:00:00 2001 From: Enric Enrich Date: Wed, 28 Oct 2026 20:03:51 +0100 Subject: [PATCH 5/5] docs: clarify supported Status fields in command help --- src/commands/status/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/status/index.ts b/src/commands/status/index.ts index d0e683f..0d37fae 100644 --- a/src/commands/status/index.ts +++ b/src/commands/status/index.ts @@ -22,7 +22,7 @@ Examples: status .command('set ') - .description('Set your status, replacing the fields this CLI supports') + .description('Set your status, replacing its message, emoji, expiration, and pause effects') .option('--emoji ', 'Emoji to show next to the message') .option( '--until ', @@ -49,7 +49,7 @@ Setting or clearing it needs the user:write scope, so log in with tdc auth login its own notifications back, and Todoist does not yet. Held notifications are not sent later. --pause-activity protects your Todoist Karma and streaks. It does not hold back notifications, and --pause-notifications does not protect Karma, so pass both if you want both. -Omitting the emoji, expiration or a pause flag clears that value. Other fields and effects are preserved. +Omitted emoji, expiration, and pause flags clear those values. Other fields and effects are preserved. Examples: tdc status set "On holiday" --emoji 🏝️ --until 2026-10-20T09:00