Commit Graph
6 Commits
Author SHA1 Message Date
Chris CoutinhoandClaude Opus 4.7 271904c227 fix(deck): address review — notesPath key, scopes, modernize types
PR #781 review round 1:

- 🔴 Fix notesPath key: the Notes API returns the folder under camelCase
  ``notesPath`` (see models/notes.py:43), but `deck_attach_note` was
  looking up snake_case ``notes_path`` and silently falling back to
  ``"Notes"``. Users with a non-default notes folder would have produced
  shares pointing at non-existent files (404 on click in Deck UI).

- 🔴 Add wire-through unit test that would have caught the above:
  extract `_resolve_note_attach_path(client, note_id)` as a testable
  helper that encapsulates the camelCase-key lookup. Three new tests:
  custom notesPath honored, missing key falls back to default, null
  category handled.

- 🟡 Modernize new fields on `DeckAttachmentExtendedData` to PEP 604
  (`X | None`) per CLAUDE.md.

- 🟡 Drop unnecessary string forward reference on
  `ListAttachmentsResponse.results` — DeckAttachment is defined earlier
  in the same module.

- 🟢 Move `pytestmark = pytest.mark.unit` to module level in
  test_sharing_client.py to match the convention in test_deck_server.py.

Per user request: `deck_attach_file` is now scoped `deck.write` +
``files.read`` (was just `deck.write`) so the generic file-share
permission story is consistent — only `deck_attach_note` keeps
`notes.read` since it specifically reads from the Notes app. Docstring
updated to emphasise the tool is generic over the user's Files
(PDFs/images/etc., not just markdown).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 23:28:37 +02:00
Chris CoutinhoandClaude Opus 4.7 c0a974c498 feat(deck): add file/note attachment MCP tools
Adds four tools that expose Deck card attachments via the MCP surface:
deck_attach_file, deck_attach_note, deck_list_attachments, and
deck_delete_attachment. The attach* variants share an existing Files
entry (or Notes-app note) with the card via OCS shareType=12 — same
mechanism the Deck UI's "Share from Files" picker uses, no file copy.

This replaces the prior workaround of appending bulky activity content
as Deck card comments: per-PR/per-event narrative now lives in NC Notes
and surfaces on the tracking card as a clickable attachment that opens
the original note in place.

Implementation reuses existing client methods (SharingClient.create_share,
DeckClient.get/delete_attachment, NotesClient.get_settings/get_note);
no new client code. _SHARE_TYPE_DECK is centralised with a CI-guard test
to prevent silent drift, and SharingClient.create_share's wire format is
pinned to what the Deck Vue source sends.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 23:17:20 +02:00
Chris CoutinhoandClaude Opus 4.7 a995155bd4 fix(deck): address PR #759 round-3 review feedback
- Drop "(in-place)" from filter-helper docstrings; callers should
  consume the return value, mutation is an implementation detail.
- Document that deck_get_archived_stacks always returns cards (an
  archived stack without its cards has no audit value); point to
  description_max_length for size control.
- Document that deck_get_cards applies filtering client-side, so it
  is network-equivalent to deck_get_stack(include_cards=True).
- Pin the empty-list contract: a stack with all-archived cards and
  include_archived_cards=False yields cards == [] (loaded but empty),
  not cards is None (explicitly suppressed).
- Add explicit one-character-over-limit truncation test alongside the
  existing exact-boundary test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 01:09:54 +02:00
Chris CoutinhoandClaude Opus 4.7 b7805c2180 fix(deck): address PR #759 round-2 review feedback
- Move description_max_length validation to tool layer
  (_validate_description_max_length), matching the existing
  _validate_comment_message pattern; helper now trusts callers per
  CLAUDE.md ("validate at system boundaries only").
- Fix mutation/return inconsistency: deck_get_stacks now uses a list
  comprehension to capture _apply_stack_filters' return, matching
  deck_get_stack / deck_get_archived_stacks.
- Rename include_archived -> include_archived_cards on deck_get_cards
  and _apply_card_filters for consistency with deck_get_stacks.
- Route deck_get_archived_stacks through _apply_stack_filters so
  future filters apply uniformly to active + archived paths.
- Trim _truncate_card_descriptions docstring to one line; add inline
  comment in _apply_stack_filters explaining the breaking-change
  default (mirrors Deck UI archived-card filtering).
- Replace fragile call_args[0][1] with call_args.args[1] in the
  archived-stacks client test.
- Modernize Optional[X] -> X | None throughout deck.py (adjacent
  cleanup called out in the review).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 00:50:56 +02:00
Chris CoutinhoandClaude Opus 4.7 7d633a945d fix(deck): address PR #759 review feedback
- Validate description_max_length is positive (raises ValueError on 0
  or negative); the prior code would have wiped descriptions to a
  single ellipsis character on description_max_length=0.
- Extract filter logic into testable module-level helpers
  (_apply_board_filters, _apply_stack_filters, _apply_card_filters)
  and replace the dense `continue`-based loop in deck_get_stacks with
  the reviewer's elif form.
- Document the truncation length quirk in the helper docstring (result
  is description_max_length + 1 chars when truncation fires).
- Add 13 new unit tests covering the include/exclude flags on board,
  stacks, and flat card lists, plus the new validation paths and an
  explicit "description fits within limit, no ellipsis" case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 00:41:14 +02:00
Chris CoutinhoandClaude Opus 4.7 d8cd073e66 feat(deck): add response filters and archived stacks tool
Add filtering options to deck read tools to keep responses compact on
boards with accumulated cards/comments, and expose archived stacks so
agents can audit completed work that has been archived off the active
board.

- deck_get_board: include_acl, include_users, include_labels
- deck_get_stacks/deck_get_stack: include_cards, include_archived_cards,
  description_max_length
- deck_get_cards: include_archived, description_max_length
- New deck_get_archived_stacks tool wrapping the existing client method

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 00:00:09 +02:00