From fa2120f7a2a0ce35339e57201df6ff07dd1a8d9f Mon Sep 17 00:00:00 2001 From: Martin conur Date: Wed, 24 Jun 2026 11:33:43 -0400 Subject: [PATCH 1/2] task-work: recognize app.notion.com URLs in notion dispatchers (#158) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit is_notion_url() in claude-notion/bin/task-work and kiro-notion/bin/task-work only matched notion.so / notion.site, so app.notion.com URLs (now the default form Notion serves and the Notion MCP returns) fell through to the slug-only branch — NOTION_URL was dropped and the worker launched with no task. Add notion.com to the predicate in both files. Fixes the --plan/--planner path transitively (it gates URL forwarding on the same predicate). No task-reviewer or planner change needed. Adds regression tests covering both the and single- forms for an app.notion.com URL in each dispatcher. Co-Authored-By: WOZCODE --- claude-notion/bin/task-work | 2 +- kiro-notion/bin/task-work | 2 +- tests/claude_notion_task_work.bats | 14 ++++++++++++++ tests/kiro_task_work.bats | 14 ++++++++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/claude-notion/bin/task-work b/claude-notion/bin/task-work index 58756e2..72c155b 100755 --- a/claude-notion/bin/task-work +++ b/claude-notion/bin/task-work @@ -85,7 +85,7 @@ fi [[ ${#POSITIONAL[@]} -lt 1 ]] && usage is_notion_url() { - [[ "$1" == *"notion.so"* || "$1" == *"notion.site"* ]] + [[ "$1" == *"notion.so"* || "$1" == *"notion.site"* || "$1" == *"notion.com"* ]] } derive_slug_from_url() { diff --git a/kiro-notion/bin/task-work b/kiro-notion/bin/task-work index 921f006..a35c0bb 100755 --- a/kiro-notion/bin/task-work +++ b/kiro-notion/bin/task-work @@ -91,7 +91,7 @@ done [[ ${#POSITIONAL[@]} -lt 1 ]] && usage is_notion_url() { - [[ "$1" == *"notion.so"* || "$1" == *"notion.site"* ]] + [[ "$1" == *"notion.so"* || "$1" == *"notion.site"* || "$1" == *"notion.com"* ]] } derive_slug_from_url() { diff --git a/tests/claude_notion_task_work.bats b/tests/claude_notion_task_work.bats index 8d7eac9..f63ed5c 100644 --- a/tests/claude_notion_task_work.bats +++ b/tests/claude_notion_task_work.bats @@ -53,6 +53,20 @@ teardown() { assert [ -d "$WORKTREE_BASE/my-explicit-slug" ] } +@test "app.notion.com single-arg: derives slug from title segment (#158)" { + run "$CLAUDE_NOTION_TASK_WORK" "https://app.notion.com/My-Feature-abc123def456abc123def456abc123de" + assert_success + assert [ -d "$WORKTREE_BASE/my-feature" ] +} + +@test "app.notion.com : records NOTION_URL in .info (#158)" { + local url="https://app.notion.com/My-Feature-abc123def456abc123def456abc123de" + run "$CLAUDE_NOTION_TASK_WORK" my-feature "$url" + assert_success + source "$WORKTREE_BASE/.my-feature.info" + assert_equal "$NOTION_URL" "$url" +} + # --------------------------------------------------------------------------- # Worktree + branch creation # --------------------------------------------------------------------------- diff --git a/tests/kiro_task_work.bats b/tests/kiro_task_work.bats index e1217ca..5c1abba 100644 --- a/tests/kiro_task_work.bats +++ b/tests/kiro_task_work.bats @@ -53,6 +53,20 @@ teardown() { assert [ -d "$WORKTREE_BASE/my-explicit-slug" ] } +@test "app.notion.com single-arg: derives slug from title segment (#158)" { + run "$KIRO_TASK_WORK" "https://app.notion.com/My-Feature-abc123def456abc123def456abc123de" + assert_success + assert [ -d "$WORKTREE_BASE/my-feature" ] +} + +@test "app.notion.com : records NOTION_URL in .info (#158)" { + local url="https://app.notion.com/My-Feature-abc123def456abc123def456abc123de" + run "$KIRO_TASK_WORK" my-feature "$url" + assert_success + source "$WORKTREE_BASE/.my-feature.info" + assert_equal "$NOTION_URL" "$url" +} + # --------------------------------------------------------------------------- # Worktree + branch creation # --------------------------------------------------------------------------- From 2067e217a7b0f49e356f291a912680773c99aa49 Mon Sep 17 00:00:00 2001 From: Martin conur Date: Wed, 24 Jun 2026 11:50:16 -0400 Subject: [PATCH 2/2] task-work: harden is_notion_url against substring false-positive (#158) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per review: a bare *"notion.com"* substring test misclassifies a free-form slug that merely contains "notion.com" (e.g. "my-notion.com-feature") as a URL, so the third arg-resolution branch fires and NOTION_URL gets the slug instead of the real Notion URL. Replace the substring predicate with an anchored regex in both claude-notion/bin/task-work and kiro-notion/bin/task-work. Deviation from the reviewer's suggested form (www.|app.)?: that variant only allows www./app./no subdomain, which would silently drop the *.notion.site published-site subdomains the original substring predicate accepted. Used ([a-zA-Z0-9-]+\.)* instead so any subdomain (or none) is accepted — fixes the false-positive while preserving the original notion.site behavior. Tests: add the false-positive guard (slug containing "notion.com" + real URL → URL wins) and a notion.site-subdomain regression to both bats suites. Co-Authored-By: WOZCODE --- claude-notion/bin/task-work | 6 +++++- kiro-notion/bin/task-work | 6 +++++- tests/claude_notion_task_work.bats | 16 ++++++++++++++++ tests/kiro_task_work.bats | 16 ++++++++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/claude-notion/bin/task-work b/claude-notion/bin/task-work index 72c155b..fb32134 100755 --- a/claude-notion/bin/task-work +++ b/claude-notion/bin/task-work @@ -85,7 +85,11 @@ fi [[ ${#POSITIONAL[@]} -lt 1 ]] && usage is_notion_url() { - [[ "$1" == *"notion.so"* || "$1" == *"notion.site"* || "$1" == *"notion.com"* ]] + # Anchored to the URL host so a free-form slug that merely contains the text + # (e.g. "my-notion.com-feature") is not misclassified as a URL. Allows any + # subdomain (www., app., or a published-site workspace) so the original + # *.notion.site behavior is preserved. (#158) + [[ "$1" =~ ^https?://([a-zA-Z0-9-]+\.)*notion\.(so|site|com)/ ]] } derive_slug_from_url() { diff --git a/kiro-notion/bin/task-work b/kiro-notion/bin/task-work index a35c0bb..8a6f7fe 100755 --- a/kiro-notion/bin/task-work +++ b/kiro-notion/bin/task-work @@ -91,7 +91,11 @@ done [[ ${#POSITIONAL[@]} -lt 1 ]] && usage is_notion_url() { - [[ "$1" == *"notion.so"* || "$1" == *"notion.site"* || "$1" == *"notion.com"* ]] + # Anchored to the URL host so a free-form slug that merely contains the text + # (e.g. "my-notion.com-feature") is not misclassified as a URL. Allows any + # subdomain (www., app., or a published-site workspace) so the original + # *.notion.site behavior is preserved. (#158) + [[ "$1" =~ ^https?://([a-zA-Z0-9-]+\.)*notion\.(so|site|com)/ ]] } derive_slug_from_url() { diff --git a/tests/claude_notion_task_work.bats b/tests/claude_notion_task_work.bats index f63ed5c..432e2f3 100644 --- a/tests/claude_notion_task_work.bats +++ b/tests/claude_notion_task_work.bats @@ -67,6 +67,22 @@ teardown() { assert_equal "$NOTION_URL" "$url" } +@test "false-positive guard: slug containing 'notion.com' resolves URL, not slug (#158)" { + # A free-form slug that merely contains "notion.com" must NOT be treated as a + # URL — the real app.notion.com arg must win and land in NOTION_URL. + local url="https://app.notion.com/Real-Page-abc123def456abc123def456abc123de" + run "$CLAUDE_NOTION_TASK_WORK" "my-notion.com-feature" "$url" + assert_success + source "$WORKTREE_BASE/.my-notioncom-feature.info" + assert_equal "$NOTION_URL" "$url" +} + +@test "notion.site subdomain URL still recognized (#158)" { + run "$CLAUDE_NOTION_TASK_WORK" "https://myworkspace.notion.site/My-Feature-abc123def456abc123def456abc123de" + assert_success + assert [ -d "$WORKTREE_BASE/my-feature" ] +} + # --------------------------------------------------------------------------- # Worktree + branch creation # --------------------------------------------------------------------------- diff --git a/tests/kiro_task_work.bats b/tests/kiro_task_work.bats index 5c1abba..4058f29 100644 --- a/tests/kiro_task_work.bats +++ b/tests/kiro_task_work.bats @@ -67,6 +67,22 @@ teardown() { assert_equal "$NOTION_URL" "$url" } +@test "false-positive guard: slug containing 'notion.com' resolves URL, not slug (#158)" { + # A free-form slug that merely contains "notion.com" must NOT be treated as a + # URL — the real app.notion.com arg must win and land in NOTION_URL. + local url="https://app.notion.com/Real-Page-abc123def456abc123def456abc123de" + run "$KIRO_TASK_WORK" "my-notion.com-feature" "$url" + assert_success + source "$WORKTREE_BASE/.my-notioncom-feature.info" + assert_equal "$NOTION_URL" "$url" +} + +@test "notion.site subdomain URL still recognized (#158)" { + run "$KIRO_TASK_WORK" "https://myworkspace.notion.site/My-Feature-abc123def456abc123def456abc123de" + assert_success + assert [ -d "$WORKTREE_BASE/my-feature" ] +} + # --------------------------------------------------------------------------- # Worktree + branch creation # ---------------------------------------------------------------------------