返回 Skill 列表
extension
分类: 开发与工程无需 API Key

calendar-sync

当用户要求“同步到Google日历”、“将活动导入日历”、“将GitHub/Linear事件添加到日历”或“将活动报告转换为日历”时,应使用此技能。它会将结构化的活动数据转换成gcalcli命令,以便导入Google日历。

person作者: jakexiaohubgithub

Calendar Sync

Convert structured activity data from GitHub, Linear, and other sources into executable gcalcli commands for Google Calendar import.

Workflow

1. Collect Configuration

Use AskUserQuestion to gather required information interactively:

Calendar selection:

# List available calendars
calendars=$(gcalcli list)

Prompt user with AskUserQuestion:

  • Question: "Which calendar should events be added to?"
  • Options: List from gcalcli list output (primary calendar, work calendar, etc.)
  • Header: "Calendar"

Timezone detection (optional):

# Auto-detect system timezone
TZ_ABBR=$(date +%Z)  # e.g., "KST", "PST"

If user request specifies different timezone or auto-detection fails, use AskUserQuestion to confirm.

Duplicate check preference:

  • Question: "Check for duplicate events before importing?"
  • Options: "Yes (recommended)" | "No (faster import)"
  • Header: "Duplicates"
  • Default: Yes

2. Parse Input

Accept input in three formats:

Markdown table (from github-activity skill):

| Time  | Activity |
|-------|----------|
| 09:00 | 🔨 **Commits**: 3 commits in `org/repo` |
| 17:00 | 🔀 **PR Created**: [#234](url) "title" in `org/repo` |

JSON file (GitHub/Linear activity output):

{
  "activities": [
    {
      "type": "commit|pr_created|pr_merged|issue_comment|...",
      "timestamp": "2025-11-01T10:30:00Z",
      "title": "PR #234: Add user auth",
      "url": "https://github.com/org/repo/pull/234"
    }
  ]
}

Structured data: Direct activity objects from other skills.

Extract from markdown using regex:

  • Time: \d{2}:\d{2}
  • Icon: 🔨|🔀|✅|🔍|💬|🆕
  • Title: Text in quotes or after colon
  • URL: Markdown links [#\d+](url)

Convert timestamps to local timezone using config.

3. Calculate Time Blocks (Backdate Algorithm)

Key insight: Activity timestamps represent completion time, not start time.

  • Commit timestamp = when pushed (work already done)
  • PR timestamp = when created (coding already finished)

Backdate calculation: start_time = timestamp - duration

| Activity Type | Duration | Example: timestamp 09:00 | |---------------|----------|--------------------------| | Commits | 30 min | → 08:30-09:00 | | PR Created | 60 min | → 08:00-09:00 | | PR Review | 45 min | → 08:15-09:00 | | Issue Comment | 15 min | → 08:45-09:00 |

For detailed duration rules: references/duration-guide.md

Time snapping (15-minute grid for calendar readability):

08:37 start → snap to 08:30
08:52 start → snap to 08:45

4. Build Work Sessions

Group related activities into coherent work sessions for clean calendar visualization.

Session formation rules:

  1. Sort activities by timestamp (completion time)
  2. Backdate each activity to get time range
  3. Merge overlapping/adjacent activities (gap ≤ 30min) into sessions
  4. Same repository activities prefer single session

Example transformation:

Raw activity data:

09:00 🔨 Commit A (30min work)
09:30 🔨 Commit B (30min work)
10:00 🔀 PR #234 created (60min work)

Before (forward projection - wrong):

09:00-09:30 🔨 Commit A
09:30-10:00 🔨 Commit B
10:00-11:00 🔀 PR #234     ← extends into future!

After (backdate + session merge - correct):

08:30-10:00 🔨🔀 Work session: 2 commits + PR #234 in org/repo
  • Session start: earliest backdate (09:00 - 30min = 08:30)
  • Session end: latest timestamp (10:00, when PR completed)

Overlap resolution (when backdated blocks collide):

Input:
  09:00 🔨 Commit (30min) → 08:30-09:00
  09:15 💬 Comment (15min) → 09:00-09:15

Resolution: Merge into 08:30-09:15 session

Session output format:

  • Title: {icons} {summary} in {repo}
  • Start: Earliest backdated start (snapped to 15min)
  • End: Latest activity timestamp
  • Description: Timeline of activities
    Work session timeline:
    08:30 → 🔨 Started coding
    09:00 → 🔨 Commit A pushed
    09:30 → 🔨 Commit B pushed
    10:00 → 🔀 PR #234 created
    
    https://github.com/org/repo/pull/234
    

User override: "without grouping" or "separate events" to disable session merge.

5. Check for Duplicates (Optional)

Query existing events using gcalcli:

gcalcli --calendar "email" agenda "start_time" "end_time"

Compare by:

  • Time window (±30 minutes)
  • Icon matching
  • PR/Issue number matching
  • Text similarity (60% threshold)

Prompt user for duplicate handling: y (add anyway), n (skip), s (skip all duplicates).

Default: Duplicate check enabled. Disable with explicit user request: "without duplicate check".

6. Generate gcalcli Commands

Output executable bash script with backdated sessions:

#!/bin/bash
set +e  # Continue on error

SUCCESS=0
FAILED=0
FAILED_COMMANDS=()

# Session: backdated from 09:30 (last commit) by 30min
echo -n "[1] 2025-11-01 09:00-09:30 🔨 Work session... "
if gcalcli add --calendar "email" \
  --title "🔨 3 commits in org/repo" \
  --when "2025-11-01 09:00" \
  --duration 30 \
  --description "Session: 09:00-09:30
09:10 → Commit: Setup auth
09:20 → Commit: Add tests
09:30 → Commit: Update docs
https://github.com/org/repo" \
  --where "GitHub" > /dev/null 2>&1; then
  echo "✓"
  ((SUCCESS++))
else
  echo "✗"
  ((FAILED++))
  FAILED_COMMANDS+=("gcalcli add ...")
fi

# Summary
echo "Import Summary: $SUCCESS/$TOTAL succeeded"
[ $FAILED -gt 0 ] && {
  printf '%s\n' "${FAILED_COMMANDS[@]}" > "$FAILED_LOG"
  echo "Failed commands: $FAILED_LOG"
  exit 1
}

Log location: ~/.claude/tmp/calendar-sync/logs/failed_imports_YYYYMMDD_HHMMSS.log

Activity Type Mapping

| Type | Icon | Title Prefix | Duration | Where | |------|------|--------------|----------|-------| | commit | 🔨 | "Commits" | 30 min | GitHub | | pr_created | 🔀 | "PR Created" | 60 min | GitHub | | pr_merged | ✅ | "PR Merged" | 15 min | GitHub | | pr_review | 🔍 | "PR Review" | 45 min | GitHub | | issue_comment | 💬 | "Issue Comment" | 15 min | GitHub | | issue_created | 🆕 | "Issue Created" | 30 min | GitHub | | linear_issue_created | 🎫 | "Linear Issue" | 30 min | Linear | | linear_status_change | 🔄 | "Status Change" | 15 min | Linear |

References

Usage Examples

  • "Sync GitHub report to calendar" → Parse markdown, group overlapping activities, generate gcalcli commands
  • "Import yesterday's activities" → Process activity JSON, add to calendar with grouping
  • "Convert markdown to calendar events" → Auto-detect format, create events
  • "Sync ~/reports/github-2025-11-01.json without duplicate check" → Fast import with grouping
  • "Sync activities without grouping" → Create separate calendar events for each activity

Troubleshooting

No Calendars Available

Error: gcalcli list returns empty or fails.

Solution:

  1. Run gcalcli --help to trigger OAuth authentication
  2. Follow browser prompts to grant calendar access
  3. Verify calendars exist in Google Calendar web interface

Authorization Error

Error: gcalcli OAuth token expired.

Solution: Run gcalcli --help to trigger OAuth re-authentication flow. Follow browser prompts to grant access.

Invalid Date Format

Error: gcalcli rejects timestamp.

Solution: Ensure timestamps are YYYY-MM-DD HH:MM format. Check timezone conversion is applied correctly from config.

Duplicate Events

Cause: Events already exist in calendar for specified time range.

Solution:

  • Enable duplicate detection (default)
  • Review existing events with gcalcli agenda start_date end_date
  • Manually delete duplicates or skip during import

Failed Command Retry

Cause: Some gcalcli commands failed during batch import.

Solution: Check failed command log at ~/.claude/tmp/calendar-sync/logs/failed_imports_*.log. Resolve issues (auth, format, network) and run log file as bash script to retry.