@xiaotianxt/skills 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/EXCLUDED.md +42 -0
  2. package/LICENSE +21 -0
  3. package/README.md +165 -0
  4. package/SECURITY.md +23 -0
  5. package/SOURCES.md +45 -0
  6. package/bin/skills.mjs +241 -0
  7. package/package.json +38 -0
  8. package/skills/1password/SKILL.md +94 -0
  9. package/skills/1password/agents/openai.yaml +4 -0
  10. package/skills/1password/references/item-management.md +80 -0
  11. package/skills/1password/references/op-cli.md +107 -0
  12. package/skills/apple-calendar-event/SKILL.md +81 -0
  13. package/skills/apple-calendar-event/agents/openai.yaml +4 -0
  14. package/skills/apple-calendar-event/scripts/calendar_audit.py +201 -0
  15. package/skills/apple-calendar-event/scripts/calendar_event.py +164 -0
  16. package/skills/bro-browser/SKILL.md +118 -0
  17. package/skills/bro-browser/agents/openai.yaml +4 -0
  18. package/skills/bro-browser/references/tool-map.md +102 -0
  19. package/skills/bro-browser/references/workflows.md +146 -0
  20. package/skills/bro-browser/scripts/bro-call.mjs +189 -0
  21. package/skills/calendar/SKILL.md +182 -0
  22. package/skills/calendar/agents/openai.yaml +4 -0
  23. package/skills/calendar/references/operations.md +255 -0
  24. package/skills/calendar/scripts/calendar_list_review.py +157 -0
  25. package/skills/calendar/scripts/event_dedupe_preview.py +155 -0
  26. package/skills/canvas/SKILL.md +70 -0
  27. package/skills/canvas/agents/openai.yaml +4 -0
  28. package/skills/canvas/references/canvas-api.md +76 -0
  29. package/skills/course-exam-review-planner/SKILL.md +127 -0
  30. package/skills/cx/SKILL.md +25 -0
  31. package/skills/gh-fix-ci/LICENSE.txt +201 -0
  32. package/skills/gh-fix-ci/SKILL.md +81 -0
  33. package/skills/gh-fix-ci/agents/openai.yaml +6 -0
  34. package/skills/gh-fix-ci/assets/github-small.svg +3 -0
  35. package/skills/gh-fix-ci/assets/github.png +0 -0
  36. package/skills/gh-fix-ci/scripts/inspect_pr_checks.py +509 -0
  37. package/skills/gh-review-workflow/SKILL.md +61 -0
  38. package/skills/gh-review-workflow/agents/openai.yaml +4 -0
  39. package/skills/gh-review-workflow/references/workflow.md +48 -0
  40. package/skills/gh-review-workflow/scripts/fetch_review_state.py +222 -0
  41. package/skills/gh-review-workflow/scripts/resolve_review_threads.py +83 -0
  42. package/skills/github/SKILL.md +74 -0
  43. package/skills/github/agents/openai.yaml +6 -0
  44. package/skills/github/assets/github-small.svg +3 -0
  45. package/skills/github/assets/github.png +0 -0
  46. package/skills/gws-calendar/SKILL.md +126 -0
  47. package/skills/gws-calendar-agenda/SKILL.md +52 -0
  48. package/skills/gws-calendar-insert/SKILL.md +66 -0
  49. package/skills/gws-docs/SKILL.md +48 -0
  50. package/skills/gws-docs-write/SKILL.md +49 -0
  51. package/skills/gws-drive/SKILL.md +137 -0
  52. package/skills/gws-drive-upload/SKILL.md +52 -0
  53. package/skills/gws-gmail/SKILL.md +62 -0
  54. package/skills/gws-gmail-forward/SKILL.md +55 -0
  55. package/skills/gws-gmail-reply/SKILL.md +58 -0
  56. package/skills/gws-gmail-reply-all/SKILL.md +62 -0
  57. package/skills/gws-gmail-send/SKILL.md +57 -0
  58. package/skills/gws-gmail-triage/SKILL.md +50 -0
  59. package/skills/gws-gmail-watch/SKILL.md +58 -0
  60. package/skills/gws-shared/SKILL.md +27 -0
  61. package/skills/helium-browser-mcp/SKILL.md +137 -0
  62. package/skills/helium-browser-mcp/agents/openai.yaml +4 -0
  63. package/skills/helium-browser-mcp/scripts/obmcp.mjs +92 -0
  64. package/skills/helium-browser-mcp/scripts/openbrowsermcp-stdio-proxy.mjs +170 -0
  65. package/skills/learn/SKILL.md +122 -0
  66. package/skills/learn/agents/openai.yaml +7 -0
  67. package/skills/learn/assets/AGENTS.template.md +33 -0
  68. package/skills/learn/assets/errorlog.template.typ +61 -0
  69. package/skills/learn/assets/reading-sequence.template.md +23 -0
  70. package/skills/learn/assets/source-index.template.md +17 -0
  71. package/skills/learn/assets/tasklog.template.typ +57 -0
  72. package/skills/learn/assets/workbook.template.typ +60 -0
  73. package/skills/learn/references/learning-science.md +103 -0
  74. package/skills/learn/scripts/init_learning_workspace.py +70 -0
  75. package/skills/macos-messages/SKILL.md +258 -0
  76. package/skills/memory/SKILL.md +33 -0
  77. package/skills/memory/codex.md +186 -0
  78. package/skills/memory/opencode.md +164 -0
  79. package/skills/mimestreamctl/SKILL.md +170 -0
  80. package/skills/mimestreamctl/agents/openai.yaml +4 -0
  81. package/skills/mimestreamctl/scripts/mimestreamctl +33 -0
  82. package/skills/mon/SKILL.md +51 -0
  83. package/skills/mon/scripts/mon_spend_review.py +458 -0
  84. package/skills/ocr/SKILL.md +136 -0
  85. package/skills/ocr/agents/openai.yaml +4 -0
  86. package/skills/ocr/references/local-ocr-best-practices.md +297 -0
  87. package/skills/ocr/references/mineru-api.md +159 -0
  88. package/skills/ocr/scripts/ocr-router +22 -0
  89. package/skills/ocr/scripts/ocr_router.py +741 -0
  90. package/skills/panopto-mp4-bulk-download/SKILL.md +57 -0
  91. package/skills/panopto-mp4-bulk-download/agents/openai.yaml +4 -0
  92. package/skills/panopto-mp4-bulk-download/references/url-patterns.md +26 -0
  93. package/skills/panopto-mp4-bulk-download/scripts/panopto_bulk_mp4.sh +213 -0
  94. package/skills/rust-systems-style/SKILL.md +109 -0
  95. package/skills/rust-systems-style/agents/openai.yaml +4 -0
  96. package/skills/rust-systems-style/references/rust-review-checklist.md +77 -0
  97. package/skills/rust-systems-style/references/style-sources.md +68 -0
  98. package/skills/ship-ai-native-cli/SKILL.md +76 -0
  99. package/skills/ship-ai-native-cli/agents/openai.yaml +4 -0
  100. package/skills/ship-ai-native-cli/references/case-notes.md +83 -0
  101. package/skills/ship-ai-native-cli/references/product-method.md +82 -0
  102. package/skills/ship-ai-native-cli/references/release-checklist.md +147 -0
  103. package/skills/ship-ai-native-cli/references/rust-cli-shape.md +111 -0
  104. package/skills/telegram-mtproto-session/SKILL.md +125 -0
  105. package/skills/telegram-mtproto-session/agents/openai.yaml +4 -0
  106. package/skills/telegram-mtproto-session/scripts/telegram_session.py +687 -0
  107. package/skills/tg/SKILL.md +173 -0
  108. package/skills/things3-manager/SKILL.md +116 -0
  109. package/skills/things3-manager/scripts/things +42 -0
  110. package/skills/things3-manager/scripts/things_cli.py +514 -0
  111. package/skills/web-artifacts-builder/LICENSE.txt +202 -0
  112. package/skills/web-artifacts-builder/SKILL.md +74 -0
  113. package/skills/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
  114. package/skills/web-artifacts-builder/scripts/init-artifact.sh +379 -0
  115. package/skills/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  116. package/skills/yeet/LICENSE.txt +201 -0
  117. package/skills/yeet/SKILL.md +71 -0
  118. package/skills/yeet/agents/openai.yaml +6 -0
  119. package/skills/yeet/assets/yeet-small.svg +3 -0
  120. package/skills/yeet/assets/yeet.png +0 -0
@@ -0,0 +1,182 @@
1
+ ---
2
+ name: calendar
3
+ description: Govern and maintain the user's personal calendar system across Google Calendar, Apple Calendar.app, school/legacy accounts, and automation. Use when Codex needs to audit calendar state, choose the correct write target, create or verify calendar events, clean up cluttered calendar lists, rename or hide calendars, migrate away from school/Apple/iCloud/legacy sources, prevent non-authoritative accounts from owning personal events, or reason about Google Calendar vs macOS Calendar.app behavior.
4
+ ---
5
+
6
+ # Calendar
7
+
8
+ ## Purpose
9
+
10
+ Use this as the top-level calendar governance skill. It decides source of truth, write targets, audit depth, and safety level before delegating to lower-level skills such as `gws-calendar`, `gws-calendar-insert`, `gws-calendar-agenda`, and `apple-calendar-event`.
11
+
12
+ ## First Principles
13
+
14
+ - Treat calendars as data ownership boundaries, not folders. A separate calendar is justified only by a different owner, lifecycle, permission model, visibility need, reminder policy, or read-only source. Otherwise put context in the event title, description, location, guests, or reminders.
15
+ - Make `tianyupeiandy@gmail.com` in Google Calendar the durable source of truth for personal commitments. Default personal writes target calendar ID `tianyupeiandy@gmail.com`.
16
+ - Treat `yupeit@andrew.cmu.edu` and other school calendars as transition sources because the account may expire. Read and migrate from them; avoid new durable writes there unless the user explicitly requests school-owned placement.
17
+ - Treat Apple Calendar.app as a local view and legacy/transition layer. It can reveal defaults, duplicate names, and local sources, but it is not the default automation write path.
18
+ - Treat `1241811980i59@gmail.com`, `yupeigemini@gmail.com`, iCloud, Reminders, Siri Suggestions, subscribed calendars, and browser account defaults as non-authoritative for personal calendar ownership unless the user explicitly overrides this.
19
+ - Do not infer ownership from display names. Use authenticated account, calendar ID, `primary`, `accessRole`, real calendar metadata, and Apple store/account audit output.
20
+ - Prefer reversible changes first: `selected`, `hidden`, `summaryOverride`, and documented renames. Delete, unsubscribe, or bulk-copy only after explicit confirmation, backups, and rollback notes.
21
+ - Optimize for the user's real workflows: fast event capture, reliable agenda reads, low visual clutter, account-lifecycle resilience, and no surprise ownership drift.
22
+
23
+ ## Default Write Policy
24
+
25
+ For event creation when the user says "my calendar" or gives no target:
26
+
27
+ 1. Use `gws auth status`.
28
+ 2. Require `user == "tianyupeiandy@gmail.com"` and `token_valid == true`.
29
+ 3. Write to Google Calendar ID `tianyupeiandy@gmail.com`.
30
+ 4. State the active account, target calendar ID, title, and exact local start/end before writing.
31
+ 5. Use Apple Calendar only when the user explicitly asks for Apple Calendar or Calendar.app.
32
+
33
+ Do not rely on:
34
+
35
+ - Google Calendar web UI account switcher default labels.
36
+ - Calendar.app's default calendar.
37
+ - Display names alone when duplicate names exist.
38
+ - `primary` in multi-account or account-confusing contexts.
39
+
40
+ ## Scenario Router
41
+
42
+ ### Read or Agenda
43
+
44
+ Use `gws-calendar-agenda` or raw `gws calendar events list` against Google first. Include Apple Calendar.app only when the user asks about local Calendar.app state, missing events in Apple, duplicate display names, or default-calendar behavior.
45
+
46
+ ### Create or Edit Personal Events
47
+
48
+ Use `gws-calendar-insert` or raw `gws calendar +insert` with explicit `--calendar tianyupeiandy@gmail.com`. Before writing, state the active account, calendar ID, title, exact local start/end, time zone, and whether guests/conference/reminders will be created. If the auth account is not `tianyupeiandy@gmail.com`, stop and re-auth instead of writing through another account.
49
+
50
+ ### Diagnose "My Calendar Is Messy"
51
+
52
+ Inventory Google CalendarList and Apple Calendar.app first. Separate issues into ownership, visibility, naming, duplication, and lifecycle. Produce a proposed table before mutating anything: calendar ID, current label, likely owner/source, role, selected/hidden, recommended taxonomy bucket, proposed action, rollback.
53
+
54
+ ### Rename, Hide, or Reduce Visual Clutter
55
+
56
+ Prefer view-level changes: `selected`, `hidden`, then `summaryOverride`. Use real `calendars.patch {"summary": ...}` only when the user wants the actual Google Calendar `My calendars` name changed and the calendar is owned/controlled by the intended account. Confirm before renaming shared, external, read-only, school, holiday, birthday, task, or subscribed calendars.
57
+
58
+ ### Migrate Away From School, Apple, iCloud, or Legacy Accounts
59
+
60
+ Make an inventory first, usually future actionable events only. Compare against the primary calendar by `iCalUID`, normalized title, start time, and location. Treat dedupe previews as advisory: recurrence expansion, changed titles, changed locations, time zones, guests, Meet links, attachments, reminders, privacy, and organizer semantics need explicit review before copying. Keep the source visible but unselected during migration; do not delete or unsubscribe until the user confirms the migrated state.
61
+
62
+ ### Investigate Apple Calendar.app
63
+
64
+ Use `apple-calendar-event` for local audit and explicit Apple writes only. Run its audit before any Apple write when source or duplicate names matter. Never edit `Calendar.sqlitedb`; treat it as a read-only cache.
65
+
66
+ ### Delete or Unsubscribe
67
+
68
+ Default to "hide/archive" instead. Delete, unsubscribe, or remove shared calendars only after the user confirms the exact calendar ID/source and a backup exists. Built-ins such as Birthdays and Tasks are not ordinary owned cleanup targets.
69
+
70
+ ## Governance Workflow
71
+
72
+ ### 1. Classify Risk
73
+
74
+ - **Read-only**: agenda, inventory, audit, explain state. No backup required unless saving a report.
75
+ - **View mutation**: select/unselect, hide/unhide, `summaryOverride`. Backup CalendarList first.
76
+ - **Metadata mutation**: real calendar `summary`, description, time zone, reminders. Backup CalendarList and affected `calendars.get`.
77
+ - **Event mutation**: create, edit, copy, migrate, delete. Verify auth, target ID, exact timestamps, and event semantics.
78
+ - **Destructive mutation**: delete calendar, unsubscribe, bulk delete, remove source after migration. Require explicit confirmation and rollback/backup discussion.
79
+
80
+ ### 2. Build State From Source APIs
81
+
82
+ Use these checks before decisions that affect ownership or visibility:
83
+
84
+ ```bash
85
+ gws auth status
86
+ gws calendar calendarList list --params '{"showHidden":true,"maxResults":250}' > calendar-list-before.json
87
+ python3 /Users/yupeit/dev/skills/skills/calendar/scripts/calendar_list_review.py --calendar-list calendar-list-before.json --format tsv
88
+ cd /Users/yupeit/dev/skills/skills/apple-calendar-event && python3 scripts/calendar_audit.py --json
89
+ ```
90
+
91
+ Interpretation rules:
92
+
93
+ - CalendarList `dataOwner` is often absent. Infer ownership from `primary`, calendar ID, `accessRole`, real calendar metadata from `calendars.get`, and Apple audit store/account fields when reconciling with Calendar.app.
94
+ - Google `calendarList.summaryOverride` is a per-user list label. It may not consistently change `My calendars` display names in the web UI.
95
+ - Google `calendars.patch {"summary": ...}` changes the real calendar title and is the right operation when the user wants the left sidebar name itself changed.
96
+ - Real `summary` changes can affect how shared calendars appear to other users. Confirm intent before renaming shared or externally owned calendars.
97
+ - If both `summaryOverride` and real `summary` are present, explain to the user that Google UI may prefer real `summary` in `My calendars` and `summaryOverride` in shared/other list contexts. Use API output to verify the exact state.
98
+ - Google `calendarList.patch {"selected": ..., "hidden": ...}` changes sidebar visibility without deleting calendars or events.
99
+ - Google built-ins such as Birthdays and Tasks are not ordinary user calendars; do not treat them as owned cleanup targets.
100
+ - Apple `Calendar.sqlitedb` is useful for read-only source mapping, duplicate names, and default calendar diagnosis. Never edit it directly.
101
+
102
+ ### 3. Propose Before Mutating
103
+
104
+ For governance work, present the plan in concrete operations:
105
+
106
+ - `keep`: authoritative or intentionally visible.
107
+ - `hide`: remove visual clutter without deleting data.
108
+ - `label`: add/change `summaryOverride`.
109
+ - `rename`: change real `summary`.
110
+ - `migrate`: copy reviewed events to `tianyupeiandy@gmail.com`.
111
+ - `archive`: hide legacy source after migration.
112
+ - `delete/unsubscribe`: only after explicit confirmation.
113
+
114
+ Mention commands you would run and commands you would avoid when the request is a planning/governance request.
115
+
116
+ ### 4. Backup Before Mutations
117
+
118
+ Before any calendar governance mutation, create a timestamped backup under:
119
+
120
+ ```text
121
+ /Users/yupeit/Desktop/hertz/calendar-governance-backups/<timestamp>-<operation>/
122
+ ```
123
+
124
+ Save at least:
125
+
126
+ - `gws-auth-status.json`
127
+ - `calendar-list-before.json`
128
+ - affected `calendars.get` JSON files for real summary/metadata edits
129
+ - Apple audit JSON when Apple Calendar.app state is relevant
130
+ - a short `report.md` with scope, changes, and rollback values
131
+
132
+ ### 5. Apply The Least Powerful Change
133
+
134
+ Use this escalation order:
135
+
136
+ 1. Select/unselect calendars with `calendarList.patch selected`.
137
+ 2. Hide/unhide calendars with `calendarList.patch hidden`.
138
+ 3. Set `summaryOverride` for list labels where it is sufficient.
139
+ 4. Patch real `summary` when the user wants Google UI `My calendars` names to change.
140
+ 5. Copy/migrate events only after inventory and dedupe planning.
141
+ 6. Delete/unsubscribe only after explicit confirmation.
142
+
143
+ ### 6. Verify And Report
144
+
145
+ After any write, re-read the affected resource. Report the active account, exact calendar ID, changed fields, backup path, and rollback command. If verification fails, stop and diagnose before retrying.
146
+
147
+ ## Current Governance Model
148
+
149
+ The user's intended taxonomy is:
150
+
151
+ - `00 Core - Google 主号`: primary personal commitments; default automation write target.
152
+ - `10 Projects - ...`: active project calendars that need independent visibility.
153
+ - `20 Shared - ...`: other people's calendars or shared views.
154
+ - `30 School Transition - ...`: school-owned or school-lifecycle calendars to migrate away from.
155
+ - `80 Archive - ...`: hidden legacy or inactive calendars.
156
+ - `90 Reference - ...`: holidays and read-only reference calendars.
157
+
158
+ Current known source-of-truth assumptions:
159
+
160
+ - Primary Google account: `tianyupeiandy@gmail.com`.
161
+ - Preferred automation target calendar ID: `tianyupeiandy@gmail.com`.
162
+ - School transition source: `yupeit@andrew.cmu.edu`.
163
+ - Apple Calendar.app: view/legacy layer, not default write target.
164
+
165
+ ## Lower-Level Skills
166
+
167
+ - Use `gws-calendar` for Calendar API discovery, list, patch, event operations, and low-level Google Calendar resources.
168
+ - Use `gws-calendar-insert` for straightforward Google event creation.
169
+ - Use `gws-calendar-agenda` for upcoming event views.
170
+ - Use `apple-calendar-event` for local Apple Calendar.app audits and explicit Apple Calendar event writes.
171
+
172
+ ## OAuth Scope Expectations
173
+
174
+ - Read/audit operations may work with Calendar read scopes.
175
+ - CalendarList visibility and label changes require CalendarList write scope.
176
+ - Real calendar metadata edits require calendar metadata write scope.
177
+ - Event creation or migration requires calendar event write scope.
178
+ - If scope is missing, re-auth with the narrowest calendar service flow and avoid broad Workspace scopes unless the task needs them.
179
+
180
+ ## Detailed Recipes
181
+
182
+ For copy-pastable commands, migration dedupe preview, and rollback patterns, read `references/operations.md` only when performing governance mutations, migrations, or Apple/Google reconciliation.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Calendar"
3
+ short_description: "Govern Google-first calendars, Apple views, and school migrations."
4
+ default_prompt: "Use $calendar to audit, govern, migrate, and maintain my Google-first personal calendar system without accidental Apple, school, or secondary-account ownership."
@@ -0,0 +1,255 @@
1
+ # Calendar Operations
2
+
3
+ ## Contents
4
+
5
+ - Snapshot and backup
6
+ - Active account verification
7
+ - Read-only inventory and governance review
8
+ - Visibility, labels, and real names
9
+ - Event creation
10
+ - Apple Calendar audit
11
+ - School and legacy migration
12
+ - Commands to avoid
13
+ - Scope expectations and rollback
14
+
15
+ Use this file for copy-pastable commands. Do not run mutation commands during a planning-only request; show the command and explain the preconditions instead.
16
+
17
+ ## Snapshot
18
+
19
+ ```bash
20
+ backup_dir="/Users/yupeit/Desktop/hertz/calendar-governance-backups/$(date +%Y%m%d-%H%M%S)-calendar"
21
+ mkdir -p "$backup_dir"
22
+ gws auth status > "$backup_dir/gws-auth-status.json"
23
+ gws calendar calendarList list --params '{"showHidden":true,"maxResults":250}' > "$backup_dir/calendar-list-before.json"
24
+ python3 /Users/yupeit/dev/skills/skills/calendar/scripts/calendar_list_review.py \
25
+ --calendar-list "$backup_dir/calendar-list-before.json" \
26
+ --format tsv > "$backup_dir/calendar-list-review.tsv"
27
+ cd /Users/yupeit/dev/skills/skills/apple-calendar-event
28
+ python3 scripts/calendar_audit.py --json > "$backup_dir/apple-calendar-audit-before.json"
29
+ ```
30
+
31
+ ## Verify Active Account
32
+
33
+ ```bash
34
+ gws auth status | jq -e '.user == "tianyupeiandy@gmail.com" and .token_valid == true'
35
+ ```
36
+
37
+ If this fails, do not write events or patch calendar metadata. Re-auth with the narrowest needed scope, usually:
38
+
39
+ ```bash
40
+ gws auth login --services calendar
41
+ ```
42
+
43
+ ## Read-Only Inventory And Governance Review
44
+
45
+ Use this when the user says the calendar is messy, asks what to rename/hide/migrate, or asks why events are going to the wrong account. These commands do not mutate calendars.
46
+
47
+ ```bash
48
+ gws calendar calendarList list --params '{"showHidden":true,"maxResults":250}' \
49
+ > "$backup_dir/calendar-list-before.json"
50
+
51
+ gws calendar calendarList list --params '{"showHidden":true,"maxResults":250}' \
52
+ | jq -r '.items[] | [
53
+ .summary,
54
+ (.summaryOverride // ""),
55
+ .id,
56
+ (.primary // false),
57
+ .accessRole,
58
+ (.selected // false),
59
+ (.hidden // false)
60
+ ] | @tsv'
61
+
62
+ python3 /Users/yupeit/dev/skills/skills/calendar/scripts/calendar_list_review.py \
63
+ --calendar-list "$backup_dir/calendar-list-before.json" \
64
+ --format tsv
65
+ ```
66
+
67
+ When `dataOwner` is blank, do not assume the calendar has no owner. Use:
68
+
69
+ - `primary == true` and ID `tianyupeiandy@gmail.com` for the primary source.
70
+ - `accessRole` to understand the current account's effective control.
71
+ - `gws calendar calendars get --params '{"calendarId":"CALENDAR_ID"}'` for real metadata.
72
+ - Apple audit `store_name`, `store_owner`, and identity fields when reconciling Calendar.app display entries.
73
+
74
+ For calendars that might be renamed or migrated, capture real metadata before proposing a final write:
75
+
76
+ ```bash
77
+ gws calendar calendars get --params '{"calendarId":"CALENDAR_ID"}'
78
+ ```
79
+
80
+ ## Visibility Governance
81
+
82
+ Patch `selected` and `hidden` on the user's CalendarList entry. This affects the user's view and does not delete calendars or events.
83
+
84
+ ```bash
85
+ gws calendar calendarList patch \
86
+ --params '{"calendarId":"CALENDAR_ID"}' \
87
+ --json '{"selected":true,"hidden":false}'
88
+ ```
89
+
90
+ Hide archive calendars:
91
+
92
+ ```bash
93
+ gws calendar calendarList patch \
94
+ --params '{"calendarId":"CALENDAR_ID"}' \
95
+ --json '{"selected":false,"hidden":true}'
96
+ ```
97
+
98
+ ## Display Labels vs Real Names
99
+
100
+ `summaryOverride` is a per-user CalendarList label. It is reversible and low risk, but Google Calendar web UI may still display the real `summary` under `My calendars`.
101
+
102
+ ```bash
103
+ gws calendar calendarList patch \
104
+ --params '{"calendarId":"CALENDAR_ID"}' \
105
+ --json '{"summaryOverride":"80 Archive - Old Name"}'
106
+ ```
107
+
108
+ Use real `summary` when the user wants the actual Google Calendar sidebar name changed:
109
+
110
+ ```bash
111
+ gws calendar calendars patch \
112
+ --params '{"calendarId":"CALENDAR_ID"}' \
113
+ --json '{"summary":"00 Core - Google 主号"}'
114
+ ```
115
+
116
+ If `summaryOverride` and `summary` conflict, explain this directly: Google Calendar may show the real `summary` in `My calendars`, while API/list contexts can still expose `summaryOverride`. Verify with both `calendarList.list` and `calendars.get`.
117
+
118
+ Real `summary` edits may affect what shared users see. Confirm before renaming shared calendars or calendars whose owner is not clearly `tianyupeiandy@gmail.com`.
119
+
120
+ Before real summary edits, save:
121
+
122
+ ```bash
123
+ safe_id="$(printf '%s' 'CALENDAR_ID' | tr '/:@# ' '_____')"
124
+ gws calendar calendars get --params '{"calendarId":"CALENDAR_ID"}' > "$backup_dir/calendar-before-$safe_id.json"
125
+ ```
126
+
127
+ ## Default Event Creation
128
+
129
+ Preflight:
130
+
131
+ ```bash
132
+ gws auth status | jq -e '.user == "tianyupeiandy@gmail.com" and .token_valid == true'
133
+ ```
134
+
135
+ Then write only with an explicit target:
136
+
137
+ ```bash
138
+ gws calendar +insert \
139
+ --calendar 'tianyupeiandy@gmail.com' \
140
+ --summary 'TITLE' \
141
+ --start 'YYYY-MM-DDTHH:MM:SS-07:00' \
142
+ --end 'YYYY-MM-DDTHH:MM:SS-07:00' \
143
+ --location 'LOCATION_OR_URL' \
144
+ --description 'NOTES'
145
+ ```
146
+
147
+ Always use exact local timestamps. Do not rely on relative phrases after the planning step.
148
+
149
+ Avoid these for default personal writes:
150
+
151
+ ```bash
152
+ # Do not use the current browser account.
153
+ # Do not use Calendar.app's default calendar.
154
+ # Do not use --calendar primary in account-confusing contexts.
155
+ # Do not write to yupeit@andrew.cmu.edu, iCloud, or another Google account unless explicitly requested.
156
+ ```
157
+
158
+ ## Apple Calendar Audit
159
+
160
+ ```bash
161
+ cd /Users/yupeit/dev/skills/skills/apple-calendar-event
162
+ python3 scripts/calendar_audit.py
163
+ python3 scripts/calendar_audit.py --json
164
+ ```
165
+
166
+ Use this to detect:
167
+
168
+ - duplicate display names
169
+ - Calendar.app default policy and default UUID
170
+ - store/account ownership such as Google, iCloud, school CalDAV, subscribed calendars, Reminders, and system sources
171
+
172
+ Do not edit `Calendar.sqlitedb`.
173
+
174
+ ## School Migration Planning
175
+
176
+ Before copying school events into the primary Google calendar:
177
+
178
+ 1. Inventory future events from the school calendar with `events.list`.
179
+ 2. Compare against existing primary events by `iCalUID`, title, start time, and location.
180
+ 3. Keep the school calendar visible but unselected while migration is in progress.
181
+ 4. Prefer copying/importing only future actionable events.
182
+ 5. Do not delete the school source until the user confirms the migrated state.
183
+
184
+ Example inventory:
185
+
186
+ ```bash
187
+ gws calendar events list \
188
+ --params '{"calendarId":"yupeit@andrew.cmu.edu","timeMin":"YYYY-MM-DDT00:00:00-07:00","singleEvents":true,"showDeleted":false,"maxResults":2500,"orderBy":"startTime"}' \
189
+ > "$backup_dir/school-source-events.json"
190
+
191
+ gws calendar events list \
192
+ --params '{"calendarId":"tianyupeiandy@gmail.com","timeMin":"YYYY-MM-DDT00:00:00-07:00","singleEvents":true,"showDeleted":false,"maxResults":2500,"orderBy":"startTime"}' \
193
+ > "$backup_dir/primary-target-events.json"
194
+ ```
195
+
196
+ Preview source events that do not appear in the target by `iCalUID` or normalized `summary + start + location`:
197
+
198
+ ```bash
199
+ python3 /Users/yupeit/dev/skills/skills/calendar/scripts/event_dedupe_preview.py \
200
+ --source "$backup_dir/school-source-events.json" \
201
+ --target "$backup_dir/primary-target-events.json" \
202
+ --format tsv
203
+ ```
204
+
205
+ Treat the preview as advisory. Review ambiguous events before copying.
206
+
207
+ Before copying events, decide which fields to preserve and which to drop:
208
+
209
+ - Usually preserve: summary, start, end, location, description, and intentional reminders.
210
+ - Review carefully: recurrence rules, conferenceData/Meet links, attendees, organizer, attachments, visibility/transparency, and private fields.
211
+ - Avoid blindly recreating attendees or conference links unless the user wants invitations or meeting changes to propagate.
212
+
213
+ ## Commands To Avoid Unless Explicitly Requested
214
+
215
+ ```bash
216
+ # Avoid defaulting to Apple Calendar for personal event creation.
217
+ # Avoid using "primary" where multiple Google accounts may be authenticated or visible.
218
+ # Avoid deleting calendars, unsubscribing, or bulk-deleting events during cleanup planning.
219
+ # Avoid direct writes to ~/Library/Group Containers/group.com.apple.calendar/Calendar.sqlitedb.
220
+ # Avoid real summary changes for shared/read-only/school/system calendars without owner confirmation.
221
+ # Avoid copying attendees/conferenceData during migration unless the user wants invitations or meeting updates.
222
+ ```
223
+
224
+ ## Scope Expectations
225
+
226
+ Use the narrowest calendar authorization that satisfies the operation:
227
+
228
+ - Read/audit: Calendar read access is enough.
229
+ - CalendarList `selected`, `hidden`, `summaryOverride`: CalendarList write access.
230
+ - Real `summary`: calendar metadata write access.
231
+ - Event creation/migration: event write access.
232
+
233
+ When scope is insufficient, prefer:
234
+
235
+ ```bash
236
+ gws auth login --services calendar
237
+ ```
238
+
239
+ ## Rollback Pattern
240
+
241
+ Every mutation report should include exact rollback commands. For real `summary` edits:
242
+
243
+ ```bash
244
+ gws calendar calendars patch \
245
+ --params '{"calendarId":"CALENDAR_ID"}' \
246
+ --json '{"summary":"PREVIOUS_SUMMARY"}'
247
+ ```
248
+
249
+ For visibility edits:
250
+
251
+ ```bash
252
+ gws calendar calendarList patch \
253
+ --params '{"calendarId":"CALENDAR_ID"}' \
254
+ --json '{"selected":PREVIOUS_SELECTED,"hidden":PREVIOUS_HIDDEN}'
255
+ ```
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+
10
+ PRIMARY_ACCOUNT = "tianyupeiandy@gmail.com"
11
+ SCHOOL_ACCOUNT = "yupeit@andrew.cmu.edu"
12
+
13
+
14
+ def load_items(path: Path) -> list[dict[str, Any]]:
15
+ with path.open(encoding="utf-8") as handle:
16
+ payload = json.load(handle)
17
+ if isinstance(payload, dict):
18
+ items = payload.get("items", [])
19
+ elif isinstance(payload, list):
20
+ items = payload
21
+ else:
22
+ raise SystemExit(f"Unsupported JSON shape in {path}")
23
+ if not isinstance(items, list):
24
+ raise SystemExit(f"Expected items array in {path}")
25
+ return [item for item in items if isinstance(item, dict)]
26
+
27
+
28
+ def text_blob(item: dict[str, Any]) -> str:
29
+ values = [
30
+ item.get("id"),
31
+ item.get("summary"),
32
+ item.get("summaryOverride"),
33
+ item.get("description"),
34
+ ]
35
+ return " ".join(str(value or "") for value in values).casefold()
36
+
37
+
38
+ def classify(item: dict[str, Any]) -> dict[str, Any]:
39
+ calendar_id = str(item.get("id") or "")
40
+ summary = str(item.get("summary") or "")
41
+ role = str(item.get("accessRole") or "")
42
+ blob = text_blob(item)
43
+ primary = bool(item.get("primary")) or calendar_id == PRIMARY_ACCOUNT
44
+ selected = bool(item.get("selected"))
45
+ hidden = bool(item.get("hidden"))
46
+
47
+ if primary:
48
+ bucket = "00 Core - Google 主号"
49
+ action = "keep selected; use as default write target"
50
+ reason = "primary Google source of truth"
51
+ elif is_school_calendar(blob, summary):
52
+ bucket = "30 School Transition - review"
53
+ action = "inventory future events; migrate reviewed items; then hide"
54
+ reason = "school lifecycle risk"
55
+ elif is_reference_calendar(blob, summary):
56
+ bucket = "90 Reference - review"
57
+ action = "keep or hide; do not rename/delete as owned calendar"
58
+ reason = "system, holiday, task, birthday, or subscribed reference source"
59
+ elif role in {"reader", "freeBusyReader"}:
60
+ bucket = "20 Shared - review"
61
+ action = "keep visible only if useful; do not rename as owner"
62
+ reason = f"current account has {role} access"
63
+ elif hidden:
64
+ bucket = "80 Archive - review"
65
+ action = "keep hidden unless needed"
66
+ reason = "already hidden from CalendarList"
67
+ elif role in {"owner", "writer"}:
68
+ bucket = "10 Projects - review"
69
+ action = "confirm owner/lifecycle; label, hide, or keep"
70
+ reason = f"current account can modify calendar ({role})"
71
+ else:
72
+ bucket = "Review"
73
+ action = "inspect metadata before changing"
74
+ reason = "ownership and lifecycle are unclear"
75
+
76
+ return {
77
+ "bucket": bucket,
78
+ "action": action,
79
+ "reason": reason,
80
+ "id": calendar_id,
81
+ "summary": summary,
82
+ "summaryOverride": item.get("summaryOverride") or "",
83
+ "primary": primary,
84
+ "accessRole": role,
85
+ "selected": selected,
86
+ "hidden": hidden,
87
+ }
88
+
89
+
90
+ def is_reference_calendar(blob: str, summary: str) -> bool:
91
+ known_summary = summary.casefold() in {
92
+ "birthdays",
93
+ "tasks",
94
+ "reminders",
95
+ "siri suggestions",
96
+ }
97
+ return (
98
+ known_summary
99
+ or "holiday" in blob
100
+ or "#holiday@group.v.calendar.google.com" in blob
101
+ or "birthday" in blob
102
+ or "contacts" in blob
103
+ or "task" in blob
104
+ or "subscribed" in blob
105
+ )
106
+
107
+
108
+ def is_school_calendar(blob: str, summary: str) -> bool:
109
+ summary_tokens = {
110
+ token.strip(" -_:/()[]{}").casefold()
111
+ for token in summary.replace("|", " ").split()
112
+ }
113
+ return (
114
+ SCHOOL_ACCOUNT in blob
115
+ or "andrew.cmu.edu" in blob
116
+ or "carnegie mellon" in blob
117
+ or "cmu" in summary_tokens
118
+ )
119
+
120
+
121
+ def print_tsv(rows: list[dict[str, Any]]) -> None:
122
+ fields = [
123
+ "bucket",
124
+ "action",
125
+ "summary",
126
+ "summaryOverride",
127
+ "id",
128
+ "primary",
129
+ "accessRole",
130
+ "selected",
131
+ "hidden",
132
+ "reason",
133
+ ]
134
+ print("\t".join(fields))
135
+ for row in rows:
136
+ print("\t".join(str(row.get(field, "")) for field in fields))
137
+
138
+
139
+ def main() -> int:
140
+ parser = argparse.ArgumentParser(
141
+ description="Create an advisory governance review table from Google Calendar calendarList JSON."
142
+ )
143
+ parser.add_argument("--calendar-list", required=True, help="JSON from gws calendar calendarList list.")
144
+ parser.add_argument("--format", choices=["json", "tsv"], default="tsv")
145
+ args = parser.parse_args()
146
+
147
+ rows = [classify(item) for item in load_items(Path(args.calendar_list))]
148
+ if args.format == "json":
149
+ json.dump(rows, sys.stdout, ensure_ascii=False, indent=2)
150
+ print()
151
+ else:
152
+ print_tsv(rows)
153
+ return 0
154
+
155
+
156
+ if __name__ == "__main__":
157
+ sys.exit(main())