google-workspace-cli 0.1.0__tar.gz

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 (50) hide show
  1. google_workspace_cli-0.1.0/.claude/commands/quality.md +21 -0
  2. google_workspace_cli-0.1.0/.claude/commands/release.md +77 -0
  3. google_workspace_cli-0.1.0/.claude/commands/self-review.md +48 -0
  4. google_workspace_cli-0.1.0/.claude/commands/test.md +8 -0
  5. google_workspace_cli-0.1.0/.claude/rules/development-workflow.md +31 -0
  6. google_workspace_cli-0.1.0/.claude/rules/python.md +41 -0
  7. google_workspace_cli-0.1.0/.claude/rules/versioning.md +62 -0
  8. google_workspace_cli-0.1.0/.claude/settings.json +26 -0
  9. google_workspace_cli-0.1.0/.claude-plugin/marketplace.json +17 -0
  10. google_workspace_cli-0.1.0/.claude-plugin/plugin.json +22 -0
  11. google_workspace_cli-0.1.0/.github/FUNDING.yml +3 -0
  12. google_workspace_cli-0.1.0/.github/workflows/ci.yml +53 -0
  13. google_workspace_cli-0.1.0/.github/workflows/publish.yml +97 -0
  14. google_workspace_cli-0.1.0/.gitignore +20 -0
  15. google_workspace_cli-0.1.0/CHANGELOG.md +25 -0
  16. google_workspace_cli-0.1.0/CLAUDE.md +54 -0
  17. google_workspace_cli-0.1.0/CONTRIBUTING.md +78 -0
  18. google_workspace_cli-0.1.0/LICENSE +21 -0
  19. google_workspace_cli-0.1.0/PKG-INFO +270 -0
  20. google_workspace_cli-0.1.0/README.md +241 -0
  21. google_workspace_cli-0.1.0/SECURITY.md +44 -0
  22. google_workspace_cli-0.1.0/commands/gw-auth.md +23 -0
  23. google_workspace_cli-0.1.0/commands/gw-calendar.md +25 -0
  24. google_workspace_cli-0.1.0/commands/gw-drive.md +23 -0
  25. google_workspace_cli-0.1.0/commands/gw-loop.md +92 -0
  26. google_workspace_cli-0.1.0/commands/gw-mail.md +30 -0
  27. google_workspace_cli-0.1.0/commands/gw-setup.md +107 -0
  28. google_workspace_cli-0.1.0/commands/gw-workflow.md +33 -0
  29. google_workspace_cli-0.1.0/pyproject.toml +71 -0
  30. google_workspace_cli-0.1.0/src/gw/__init__.py +1 -0
  31. google_workspace_cli-0.1.0/src/gw/auth.py +199 -0
  32. google_workspace_cli-0.1.0/src/gw/calendar.py +239 -0
  33. google_workspace_cli-0.1.0/src/gw/cli.py +119 -0
  34. google_workspace_cli-0.1.0/src/gw/config.py +110 -0
  35. google_workspace_cli-0.1.0/src/gw/drive.py +189 -0
  36. google_workspace_cli-0.1.0/src/gw/gmail.py +366 -0
  37. google_workspace_cli-0.1.0/src/gw/output.py +35 -0
  38. google_workspace_cli-0.1.0/tests/conftest.py +53 -0
  39. google_workspace_cli-0.1.0/tests/test_auth.py +145 -0
  40. google_workspace_cli-0.1.0/tests/test_auth_service.py +38 -0
  41. google_workspace_cli-0.1.0/tests/test_bugfixes.py +322 -0
  42. google_workspace_cli-0.1.0/tests/test_calendar.py +180 -0
  43. google_workspace_cli-0.1.0/tests/test_cli.py +65 -0
  44. google_workspace_cli-0.1.0/tests/test_cli_config.py +32 -0
  45. google_workspace_cli-0.1.0/tests/test_config.py +94 -0
  46. google_workspace_cli-0.1.0/tests/test_coverage.py +388 -0
  47. google_workspace_cli-0.1.0/tests/test_drive.py +121 -0
  48. google_workspace_cli-0.1.0/tests/test_gmail.py +179 -0
  49. google_workspace_cli-0.1.0/tests/test_output.py +43 -0
  50. google_workspace_cli-0.1.0/uv.lock +895 -0
@@ -0,0 +1,21 @@
1
+ Run all quality checks.
2
+
3
+ Steps:
4
+ 1. Lint:
5
+ ```
6
+ uv run ruff check src/ tests/
7
+ ```
8
+ 2. Format check:
9
+ ```
10
+ uv run ruff format --check src/ tests/
11
+ ```
12
+ 3. Type check:
13
+ ```
14
+ uv run pyright src/
15
+ ```
16
+ 4. Tests:
17
+ ```
18
+ uv run pytest tests/ -v
19
+ ```
20
+
21
+ Report any issues found. If fixable, ask to auto-fix (`ruff check --fix`, `ruff format`).
@@ -0,0 +1,77 @@
1
+ ---
2
+ description: Bump version, commit, tag, and push a release
3
+ arguments:
4
+ - name: level
5
+ description: "patch, minor, or major"
6
+ required: true
7
+ ---
8
+
9
+ Release gw-cli with a version bump.
10
+
11
+ ## Prerequisites
12
+
13
+ Before releasing, ensure:
14
+ 1. `/quality` has been run and passes
15
+ 2. Current branch is `master`
16
+
17
+ ## Steps
18
+
19
+ ### 1. Validate preconditions
20
+
21
+ - Argument: `$ARGUMENTS` (must be `patch`, `minor`, or `major`)
22
+ - Verify current branch is `master` (`git branch --show-current`). Abort if not.
23
+
24
+ ### 2. Read current version
25
+
26
+ Read `src/gw/__init__.py` and extract `__version__`.
27
+
28
+ ### 3. Calculate new version
29
+
30
+ Apply SemVer bump:
31
+ - `patch`: 0.1.0 → 0.1.1
32
+ - `minor`: 0.1.0 → 0.2.0
33
+ - `major`: 0.1.0 → 1.0.0
34
+
35
+ (While MAJOR is 0, treat breaking changes as `minor`.)
36
+
37
+ ### 4. Update version in all three locations
38
+
39
+ Keep these in lockstep (see `.claude/rules/versioning.md`):
40
+ 1. `src/gw/__init__.py` → `__version__`
41
+ 2. `.claude-plugin/plugin.json` → `version`
42
+ 3. `.claude-plugin/marketplace.json` → `plugins[0].version`
43
+
44
+ ### 5. Lock and build
45
+
46
+ ```bash
47
+ uv lock
48
+ uv build
49
+ ```
50
+
51
+ Verify the build produces `dist/google_workspace_cli-X.Y.Z-*.whl` and `dist/google_workspace_cli-X.Y.Z.tar.gz`.
52
+
53
+ ### 6. Commit and tag
54
+
55
+ ```bash
56
+ git add src/gw/__init__.py .claude-plugin/plugin.json .claude-plugin/marketplace.json uv.lock
57
+ git commit -m "chore(release): vX.Y.Z"
58
+ git tag vX.Y.Z
59
+ ```
60
+
61
+ ### 7. Push
62
+
63
+ ```bash
64
+ git push && git push --tags
65
+ ```
66
+
67
+ This triggers the `Publish to PyPI` workflow → publishes `google-workspace-cli` to PyPI and creates a GitHub Release.
68
+
69
+ ### 8. Update CHANGELOG and write release notes
70
+
71
+ 1. `git log --oneline vPREVIOUS..vX.Y.Z` to review commits in this release.
72
+ 2. Add a new section to the top of `CHANGELOG.md` for `vX.Y.Z`.
73
+ 3. Write release notes grouped as **New features** / **Improvements** / **Bug fixes** (omit empty sections), referencing issue/PR numbers with `#N`. Add a `## Migration` section if any commit is a breaking change.
74
+
75
+ ### 9. Report
76
+
77
+ Print the new version, the GitHub Release link, and the Actions run URL.
@@ -0,0 +1,48 @@
1
+ Perform a pre-PR self-review of all changes.
2
+
3
+ ## Role
4
+
5
+ You are an AI code reviewer. Review only the modified code in the diff. Prioritize high-signal feedback over quantity.
6
+
7
+ ## Review the diff
8
+
9
+ ```bash
10
+ git diff master...HEAD
11
+ ```
12
+
13
+ If no diff, review `git diff HEAD~1`.
14
+
15
+ ## Review for (in priority order)
16
+
17
+ 1. **Correctness** — bugs, edge cases, broken logic, unreachable code
18
+ 2. **Security** — credential/token leaks, secrets in logs, unsafe defaults, committing `credentials.json`/tokens
19
+ 3. **Error handling** — exceptions swallowed, auth errors not surfacing a recovery hint, missing input validation (`click.BadParameter`)
20
+ 4. **Test coverage** — every changed/added code path must have a test. Check: new branches, error paths, edge cases
21
+ 5. **CLI behavior** — `--json` / `--account` honored, output routed through `format_output`, help text accurate
22
+ 6. **Consistency** — patterns used differently across files, naming inconsistencies with existing code
23
+
24
+ ## Rules
25
+
26
+ - Only comment on lines that were changed in the diff
27
+ - Be specific and actionable — suggest concrete fixes
28
+ - Do not nitpick formatting (ruff handles it)
29
+
30
+ ## Severity
31
+
32
+ | Marker | Meaning | Action |
33
+ |--------|---------|--------|
34
+ | `[C]` | Bug, security hole, data loss | Must fix before merge |
35
+ | `[W]` | Risk, missing guard, edge case | Should fix |
36
+ | `[I]` | Readability, minor improvement | Fix or justify |
37
+
38
+ ## Output
39
+
40
+ ```markdown
41
+ ## Self-review: X files changed
42
+
43
+ `[C]` file:line — Description. **Fix:** concrete suggestion.
44
+
45
+ ### Verdict: Ready / Needs fixes
46
+ ```
47
+
48
+ If no significant issues: state "Changes look good" with a brief summary.
@@ -0,0 +1,8 @@
1
+ Run the test suite.
2
+
3
+ Steps:
4
+ 1. Run all tests:
5
+ ```
6
+ uv run pytest tests/ -v --maxfail=5
7
+ ```
8
+ 2. Report results: passed/failed/skipped counts and failing test names.
@@ -0,0 +1,31 @@
1
+ ---
2
+ paths:
3
+ - "**"
4
+ ---
5
+
6
+ # Development Workflow
7
+
8
+ ## Flow
9
+
10
+ 1. **Start**: `gh issue view <number>` → understand the task
11
+ 2. **Branch**: `git checkout -b {issue-number}-{type}/{description} master`
12
+ 3. **Implement**: Write code keeping self-review criteria in mind from the start
13
+ 4. **Quality**: Run `/quality` (lint, format, type-check, tests)
14
+ 5. **Self-review**: Run `/self-review` — fix all `[C]` and `[W]` findings
15
+ 6. **PR**: Create PR linking the issue. Only when the user explicitly asks.
16
+ 7. **Merge**: Only after user approval. Never auto-merge.
17
+
18
+ ## Commit Discipline
19
+
20
+ - Commit frequently with meaningful messages
21
+ - Follow Conventional Commits: `<type>(<scope>): <subject>`
22
+ - Each commit should be atomic — one logical change per commit
23
+ - Types: `feat`, `fix`, `refactor`, `test`, `docs`, `chore`, `ci`
24
+
25
+ ## PR Rules
26
+
27
+ - Run `/quality` → `/self-review` before every PR
28
+ - PR title: Under 70 characters, Conventional Commits format
29
+ - Squash merge to `master`
30
+ - Delete branch after merge
31
+ - Never skip self-review before merge
@@ -0,0 +1,41 @@
1
+ ---
2
+ paths:
3
+ - "src/**"
4
+ - "tests/**"
5
+ ---
6
+
7
+ # Python Coding Rules
8
+
9
+ ## Style
10
+ - snake_case for functions/variables, PascalCase for classes
11
+ - Type hints required on all function signatures
12
+ - `from __future__ import annotations` at the top of modules using new-style unions on 3.10
13
+ - Google-style docstrings on public functions and Click commands (the docstring is the `--help` text)
14
+ - Target Python 3.10+; keep syntax compatible with 3.10/3.11/3.12
15
+
16
+ ## CLI (Click)
17
+ - Every command is a `@click.command` / `@click.group` with explicit `@click.option` / `@click.argument`
18
+ - User-facing output goes through `click.echo`, formatted via `gw.output.format_output` — never bare `print()`
19
+ - Respect the global `--json` / `--account` flags from `ctx.obj`; pass them into `format_output`
20
+ - Validate user input with `click.BadParameter`, not bare exceptions
21
+
22
+ ## Error Handling
23
+ - Raise `RuntimeError` (or `click.BadParameter` for bad input) with an actionable message; the top-level CLI maps these to friendly errors
24
+ - Never swallow exceptions silently — re-raise or surface a clear message
25
+ - Auth/credential failures must tell the user how to recover (e.g. "Run 'gw auth login'")
26
+
27
+ ## Google API
28
+ - Build services lazily; reuse credentials from the token store
29
+ - Never assume a field exists in an API response — use `.get(...)` with sensible defaults
30
+ - Request only the scopes a command needs
31
+
32
+ ## Security
33
+ - Never commit `credentials.json`, tokens, or `.env` (see `.gitignore`)
34
+ - Never log access/refresh tokens or full credential payloads
35
+ - Store tokens under the config dir with restrictive permissions; never write secrets to `os.environ`
36
+
37
+ ## Testing
38
+ - `pytest`; mock the Google API client (no live network calls in unit tests)
39
+ - Use Click's `CliRunner` for command tests; pass `--config-dir` to isolate state
40
+ - Test error paths (missing account, bad input, API failure), not just the happy path
41
+ - Every changed/added code path needs a test
@@ -0,0 +1,62 @@
1
+ ---
2
+ paths:
3
+ - "src/gw/__init__.py"
4
+ - "pyproject.toml"
5
+ - ".claude-plugin/plugin.json"
6
+ - ".claude-plugin/marketplace.json"
7
+ ---
8
+
9
+ # Version Management
10
+
11
+ ## Single Source of Truth
12
+
13
+ - The canonical version is `__version__` in `src/gw/__init__.py`
14
+ - `pyproject.toml` uses `dynamic = ["version"]` with `[tool.hatch.version]` to read it — never set `version = "..."` in `pyproject.toml`
15
+ - The two Claude Code plugin manifests carry their own `version` and must be kept in sync:
16
+ - `.claude-plugin/plugin.json` → `version`
17
+ - `.claude-plugin/marketplace.json` → `plugins[0].version`
18
+ - `/release` bumps all three in lockstep
19
+
20
+ ## SemVer Rules
21
+
22
+ Format: `MAJOR.MINOR.PATCH` (e.g. `0.2.3`)
23
+
24
+ | Change type | Bump | Example |
25
+ |-------------|------|---------|
26
+ | Breaking change | MAJOR | Removing/renaming a CLI command or flag |
27
+ | New feature (backward compatible) | MINOR | Adding a new `gw` subcommand |
28
+ | Bug fix, docs, refactor | PATCH | Fixing an error message |
29
+
30
+ While `MAJOR` is `0`, breaking changes bump MINOR instead.
31
+
32
+ ## Conventional Commits → Version
33
+
34
+ | Commit prefix | Version bump |
35
+ |---------------|-------------|
36
+ | `feat` | MINOR (or PATCH if 0.x) |
37
+ | `fix`, `perf` | PATCH |
38
+ | `BREAKING CHANGE` footer or `!` suffix | MAJOR (or MINOR if 0.x) |
39
+ | `docs`, `chore`, `refactor`, `test`, `ci` | No bump |
40
+
41
+ ## Release Flow
42
+
43
+ Use `/release patch|minor|major` to:
44
+ 1. Bump `__version__` in `src/gw/__init__.py`
45
+ 2. Sync `version` in `.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json`
46
+ 3. `uv lock` and `uv build` (verify)
47
+ 4. Commit: `chore(release): vX.Y.Z`
48
+ 5. Tag: `vX.Y.Z`
49
+ 6. Push commit + tag → the `Publish to PyPI` workflow publishes to PyPI
50
+
51
+ ### Test release
52
+
53
+ Manual trigger via GitHub Actions → `Publish to PyPI` → Run workflow → `testpypi`
54
+
55
+ ## Release Infrastructure (Trusted Publishing)
56
+
57
+ Publishing uses PyPI's OIDC Trusted Publisher — **no API tokens**. Configure once:
58
+
59
+ - **PyPI project**: `google-workspace-cli`
60
+ - **Owner / repo**: `JFK/gw-cli`
61
+ - **Workflow**: `publish.yml`
62
+ - **Environments**: `pypi` (production) and `testpypi` — create both as GitHub Environments and register each as a Trusted Publisher on PyPI / TestPyPI
@@ -0,0 +1,26 @@
1
+ {
2
+ "hooks": {
3
+ "PostToolUse": [
4
+ {
5
+ "matcher": "Write|Edit",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "file_path=$(cat | jq -r '.tool_input.file_path // empty'); [ -z \"$file_path\" ] && exit 0; case \"$file_path\" in *.py) uv run ruff format --quiet \"$file_path\" 2>/dev/null;; esac; exit 0"
10
+ }
11
+ ]
12
+ }
13
+ ],
14
+ "PreToolUse": [
15
+ {
16
+ "matcher": "Bash",
17
+ "hooks": [
18
+ {
19
+ "type": "command",
20
+ "command": "INPUT=$(cat); CMD=$(echo \"$INPUT\" | jq -r '.tool_input.command // empty'); if echo \"$CMD\" | grep -qE 'gh pr (merge|create)'; then echo 'Reminder: Before PR, ensure /quality and /self-review have been run.' >&2; fi; if echo \"$CMD\" | grep -qE 'git tag v'; then echo 'Reminder: Bump the version in src/gw/__init__.py and the .claude-plugin manifests before tagging (use /release).' >&2; fi; exit 0"
21
+ }
22
+ ]
23
+ }
24
+ ]
25
+ }
26
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
3
+ "name": "gw-cli",
4
+ "description": "Google Workspace CLI for Claude Code — manage Calendar, Gmail, Drive with multi-account support",
5
+ "owner": {
6
+ "name": "Fumikazu Kiyota",
7
+ "email": "fumikazu.kiyota@gmail.com"
8
+ },
9
+ "plugins": [
10
+ {
11
+ "name": "gw-cli",
12
+ "source": "./",
13
+ "version": "0.1.0",
14
+ "category": "productivity"
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "gw-cli",
3
+ "version": "0.1.0",
4
+ "description": "Google Workspace CLI for Claude Code — Calendar, Gmail, Drive with multi-account support",
5
+ "author": {
6
+ "name": "Fumikazu Kiyota",
7
+ "url": "https://github.com/JFK"
8
+ },
9
+ "repository": "https://github.com/JFK/gw-cli",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "google-workspace",
13
+ "calendar",
14
+ "gmail",
15
+ "drive",
16
+ "multi-account",
17
+ "oauth",
18
+ "cli",
19
+ "productivity"
20
+ ],
21
+ "commands": ["./commands/"]
22
+ }
@@ -0,0 +1,3 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: JFK
@@ -0,0 +1,53 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ lint:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - uses: astral-sh/setup-uv@v6
16
+ with:
17
+ enable-cache: true
18
+
19
+ - name: Set up Python
20
+ run: uv python install 3.10
21
+
22
+ - name: Install dependencies
23
+ run: uv sync --dev
24
+
25
+ - name: Lint
26
+ run: uv run ruff check src/ tests/
27
+
28
+ - name: Format check
29
+ run: uv run ruff format --check src/ tests/
30
+
31
+ - name: Type check
32
+ run: uv run pyright src/
33
+
34
+ test:
35
+ runs-on: ubuntu-latest
36
+ strategy:
37
+ matrix:
38
+ python-version: ["3.10", "3.11", "3.12"]
39
+ steps:
40
+ - uses: actions/checkout@v4
41
+
42
+ - uses: astral-sh/setup-uv@v6
43
+ with:
44
+ enable-cache: true
45
+
46
+ - name: Set up Python ${{ matrix.python-version }}
47
+ run: uv python install ${{ matrix.python-version }}
48
+
49
+ - name: Install dependencies
50
+ run: uv sync --dev --python ${{ matrix.python-version }}
51
+
52
+ - name: Test with coverage
53
+ run: uv run pytest tests/ -v --cov=src/gw --cov-report=xml --cov-report=term
@@ -0,0 +1,97 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ target:
10
+ description: "Publish target"
11
+ required: true
12
+ default: "testpypi"
13
+ type: choice
14
+ options:
15
+ - testpypi
16
+
17
+ jobs:
18
+ build:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - uses: astral-sh/setup-uv@v6
24
+ with:
25
+ enable-cache: true
26
+
27
+ - name: Build
28
+ run: uv build
29
+
30
+ - uses: actions/upload-artifact@v4
31
+ with:
32
+ name: dist
33
+ path: dist/
34
+
35
+ publish-testpypi:
36
+ if: github.event_name == 'workflow_dispatch'
37
+ needs: build
38
+ runs-on: ubuntu-latest
39
+ environment: testpypi
40
+ permissions:
41
+ id-token: write
42
+ steps:
43
+ - uses: actions/download-artifact@v4
44
+ with:
45
+ name: dist
46
+ path: dist/
47
+
48
+ - name: Publish to TestPyPI
49
+ uses: pypa/gh-action-pypi-publish@release/v1
50
+ with:
51
+ repository-url: https://test.pypi.org/legacy/
52
+
53
+ publish-pypi:
54
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
55
+ needs: build
56
+ runs-on: ubuntu-latest
57
+ environment: pypi
58
+ permissions:
59
+ id-token: write
60
+ steps:
61
+ - uses: actions/download-artifact@v4
62
+ with:
63
+ name: dist
64
+ path: dist/
65
+
66
+ - name: Publish to PyPI
67
+ uses: pypa/gh-action-pypi-publish@release/v1
68
+
69
+ github-release:
70
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
71
+ needs: publish-pypi
72
+ runs-on: ubuntu-latest
73
+ permissions:
74
+ contents: write
75
+ steps:
76
+ - uses: actions/checkout@v4
77
+
78
+ - name: Create GitHub Release
79
+ # Idempotent + race-safe: the /release skill may also create the release
80
+ # (with hand-written notes) right after pushing the tag, so a plain
81
+ # check-then-create here can lose the race and 422 with
82
+ # "Release.tag_name already exists". Re-check after a failed create and
83
+ # treat "already exists" as success.
84
+ run: |
85
+ if gh release view "$REF" >/dev/null 2>&1; then
86
+ echo "Release $REF already exists, skipping."
87
+ elif gh release create "$REF" --generate-notes; then
88
+ echo "Created release $REF."
89
+ elif gh release view "$REF" >/dev/null 2>&1; then
90
+ echo "Release $REF was created concurrently; treating as success."
91
+ else
92
+ echo "Failed to create release $REF." >&2
93
+ exit 1
94
+ fi
95
+ env:
96
+ GH_TOKEN: ${{ github.token }}
97
+ REF: ${{ github.ref_name }}
@@ -0,0 +1,20 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .venv/
7
+ credentials/
8
+ tokens/
9
+ .env
10
+ .env.*
11
+ *.json
12
+ !.claude-plugin/*.json
13
+ !.claude/settings.json
14
+ !pyproject.toml
15
+ .pytest_cache/
16
+ .ruff_cache/
17
+ .coverage
18
+
19
+ # local OAuth client secret (never commit)
20
+ credentials.json
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to
5
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Added
10
+ - PyPI packaging: published as `google-workspace-cli` via hatchling with the version sourced from
11
+ `src/gw/__init__.py`.
12
+ - GitHub Actions: `ci.yml` (lint + type check + test on Python 3.10/3.11/3.12) and
13
+ `publish.yml` (OIDC Trusted Publishing to PyPI/TestPyPI + GitHub Release).
14
+ - Claude Code dev config: `CLAUDE.md`, `.claude/rules/`, and `.claude/commands/`
15
+ (`/quality`, `/test`, `/self-review`, `/release`).
16
+ - `CONTRIBUTING.md`.
17
+
18
+ ## [0.1.0]
19
+
20
+ ### Added
21
+ - Initial release: multi-account Google Workspace CLI (`gw`) for Calendar, Gmail, and Drive
22
+ with OAuth, plus a Claude Code plugin with 7 skills.
23
+
24
+ [Unreleased]: https://github.com/JFK/gw-cli/compare/v0.1.0...HEAD
25
+ [0.1.0]: https://github.com/JFK/gw-cli/releases/tag/v0.1.0
@@ -0,0 +1,54 @@
1
+ # gw-cli — Development Guide
2
+
3
+ ## Overview
4
+
5
+ Google Workspace CLI for Claude Code. A Click-based, synchronous CLI (`gw`) over the Google
6
+ Calendar, Gmail, and Drive APIs with multi-account OAuth. Also ships as a Claude Code plugin.
7
+
8
+ - **PyPI package**: `google-workspace-cli` (the `gw-cli` name was taken) — import package and command are both `gw`
9
+ - **Plugin**: `.claude-plugin/` + `commands/gw-*.md` (7 skills)
10
+
11
+ Modules (`src/gw/`):
12
+ - `cli.py` — Click root group, global `--json` / `--account` flags
13
+ - `auth.py` — OAuth login/switch/list/remove, token store
14
+ - `calendar.py`, `gmail.py`, `drive.py` — per-service command groups
15
+ - `config.py` — config dir + account state
16
+ - `output.py` — `format_output` (text/JSON rendering)
17
+
18
+ ## Development Workflow
19
+
20
+ See `.claude/rules/development-workflow.md` for the full flow (auto-loaded).
21
+
22
+ **Key sequence**: Issue → Branch → Implement → `/quality` → `/self-review` → PR → Merge
23
+
24
+ ## Commands
25
+
26
+ ```bash
27
+ uv sync --dev # Install deps (incl. dev)
28
+ uv run pytest tests/ -v # Tests
29
+ uv run ruff check src/ tests/ # Lint
30
+ uv run ruff format src/ tests/ # Format
31
+ uv run pyright src/ # Type check
32
+ ```
33
+
34
+ **Slash commands**: `/quality`, `/test`, `/self-review`, `/release patch|minor|major`
35
+
36
+ ## Conventions
37
+
38
+ - Click commands; user output via `click.echo(format_output(...))`, never bare `print()`
39
+ - Honor global `--json` / `--account` from `ctx.obj`
40
+ - Errors: `RuntimeError` / `click.BadParameter` with an actionable recovery hint
41
+ - Never commit `credentials.json`, tokens, or `.env`; never log tokens
42
+ - Full rules: `.claude/rules/python.md` (auto-loaded)
43
+
44
+ ## Versioning & Release
45
+
46
+ Version lives in `src/gw/__init__.py` (`pyproject.toml` reads it via `dynamic`). The two
47
+ `.claude-plugin/*.json` manifests carry their own `version` and must stay in sync.
48
+ `/release` bumps all three, tags `vX.Y.Z`, and the `Publish to PyPI` workflow publishes `google-workspace-cli`
49
+ via OIDC Trusted Publishing. See `.claude/rules/versioning.md`.
50
+
51
+ ## Branch Strategy
52
+
53
+ - Branch from `master` for every issue: `{issue-number}-{type}/{description}`
54
+ - Conventional Commits; squash merge to `master`