- config.py: add _sanitize_agent_id() to strip path traversal chars and
limit length; use it in get_agent_config_dir()
- account_manager.py: set_agent_active_account() validates account exists
before saving, raises ValueError if not found
- account_manager.py: switch_account() also persists to agent-specific
file when running under an agent ID
- auth_manager.py: status() shows 'Active Account (agent-specific):',
'Active Account (global):', or 'Active Account:' based on context
- SKILL.md: add 'accounts remove <id>' to commands table
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- config.py: add get_agent_id(), get_agent_config_dir(), get_agent_active_account_file()
- account_manager.py: per-agent active account with fallback to global default
- auth_manager.py: add 'accounts use' and 'accounts clear' commands
- CLAUDE.md: add English output iron rule
- SKILL.md: document new multi-agent commands
When Google credentials expire (>10 days old), automatically trigger
re-authentication instead of requiring manual reauth command.
Changes:
- Add _prompt_auth_reauth() for automatic credential refresh
- Modify ensure_google_auth() to call reauth on expiry, not setup
- Reauth uses existing account, setup adds new account
This makes credential expiry transparent to users - they just see
a browser window and continue working after login.
Co-Authored-By: Claude (gemini-claude-opus-4-5-thinking) <noreply@anthropic.com>
Remove agent-browser fallback for Google auth to prevent "browser not
secure" blocking. Google detects Chrome for Testing as automation.
Changes:
- Remove 3 fallback paths to _setup_with_agent_browser("google")
- Add helpful error messages with installation instructions
- Add service = service or "google" to handle None case
- Update clear() message to not mention reauth command
BREAKING: Google auth now requires Patchright. Install with:
pip install patchright && patchright install chromium
Co-Authored-By: Claude (gemini-claude-opus-4-5-thinking) <noreply@anthropic.com>
AuthManager improvements for multi-account support:
1. Fresh profile support:
- Add use_fresh_profile parameter to setup() and _setup_google_with_patchright()
- Pass through to patchright for new account authentication
- _accounts_add() uses fresh profile to force account selection
2. Symlink management:
- Add quiet parameter to _ensure_storage_state_symlink()
- Call symlink update in __init__ after migration (silent)
- Update symlink on account switch for notebooklm-py compatibility
3. Better integration:
- Symlink now always points to active account's auth file
- Ensures notebooklm-py uses correct credentials after switch
Co-Authored-By: Claude <noreply@anthropic.com>
Major improvements for adding new Google accounts:
1. Temporary profile for new accounts:
- Create isolated temp directory with tempfile.mkdtemp()
- Avoids Chrome profile switching when signing into different account
- Auto-cleanup after authentication completes
2. CDP-based cross-window detection:
- Use Chrome DevTools Protocol to detect NotebookLM pages
- Works even when Chrome opens new windows during login
- Target.getTargets finds pages across all Chrome windows
3. Multi-tab monitoring:
- Check all pages in context, not just the first one
- Handle Google's multi-tab login flow correctly
4. Session capture from other windows:
- Navigate controlled page to NotebookLM after CDP detection
- Extract cookies (session shared across windows)
Co-Authored-By: Claude <noreply@anthropic.com>
Update ensure_google_auth() to check new multi-account structure:
- Check google/index.json first for multi-account mode
- Find active account's auth file from index
- Fall back to legacy google.json for backward compatibility
- Fix argument order in auth setup subprocess call
This prevents unnecessary auth prompts when multi-account is configured.
Co-Authored-By: Claude <noreply@anthropic.com>
When migrating from legacy google.json to multi-account structure,
abort migration if email cannot be extracted from credentials instead
of creating an "unknown@google.com" placeholder account.
- Keep legacy google.json active until proper re-authentication
- Guide user to run 'accounts add' to migrate with proper email
- Prevents orphan accounts with invalid email addresses
Co-Authored-By: Claude <noreply@anthropic.com>
Display active Google account email and index at the top
of the status output.
Co-Authored-By: Claude (gemini-claude-opus-4-5-thinking) <noreply@anthropic.com>
- Detect notebook's associated account from library
- Use correct account credentials for cross-account queries
- Log when using a different account than active
Co-Authored-By: Claude <noreply@anthropic.com>
- Add account_index and account_email fields on add
- list_notebooks_for_account() filters by account
- list_all_notebooks_grouped() groups by account
- CLI: --all-accounts flag for list command
Co-Authored-By: Claude <noreply@anthropic.com>
NotebookLMWrapper can now be initialized with a specific
account_index to use that account's credentials instead
of the active account.
Co-Authored-By: Claude <noreply@anthropic.com>
During migration from single-account to multi-account structure,
existing notebooks in library.json are updated to include
account_index and account_email fields.
Co-Authored-By: Claude <noreply@anthropic.com>
- Delegate Google auth file resolution to AccountManager
- Handle add/update account flow in setup
- Maintain backward compatibility with existing API
Co-Authored-By: Claude <noreply@anthropic.com>
- add_account() with credential storage
- remove_account() with cleanup
- update_account_credentials() for reauth
- get_account_credentials() for loading
Co-Authored-By: Claude <noreply@anthropic.com>
- switch_account() by index or email
- get_account_by_index() and get_account_by_email()
- account_exists() for duplicate detection
Co-Authored-By: Claude <noreply@anthropic.com>
- AccountInfo dataclass for account metadata
- AccountManager class with index loading/saving
- Email sanitization for safe filenames
- Migration detection from legacy google.json
Co-Authored-By: Claude <noreply@anthropic.com>
Add GOOGLE_AUTH_DIR, GOOGLE_AUTH_INDEX for new multi-account structure.
Keep GOOGLE_AUTH_FILE_LEGACY for migration detection.
Co-Authored-By: Claude <noreply@anthropic.com>
When requirements.txt changes trigger pip install, automatically
install the Patchright Chromium browser if patchright package exists.
- Add _ensure_patchright_browser() function
- Use marker file to track installation status
- 5-minute timeout for browser download
- Graceful fallback on failure
Co-Authored-By: Claude <noreply@anthropic.com>
Google blocks personal Gmail sign-in with Playwright's bundled Chromium,
showing "This browser or app may not be secure" error. This commit:
- Add patchright_auth.py module using anti-detection Playwright fork
- Route Google auth through Patchright in auth_manager.py
- Add patchright>=1.50.0 to requirements.txt
- Fall back to agent-browser if Patchright unavailable
Key anti-detection techniques:
- ignore_default_args=["--enable-automation"]
- --disable-blink-features=AutomationControlled
- Uses real Chrome via executable_path
- Persistent context for session management
Co-Authored-By: Claude <noreply@anthropic.com>
Problem: AI agents run scripts non-interactively, so input() gets EOF.
Solution: Add explicit CLI flags for notebook selection:
- --use-active: Upload to currently active notebook
- --create-new: Create new notebook named after the file
- --notebook-id: Upload to specific notebook (existing)
The AI agent should ask the user BEFORE running the script, then
pass the appropriate flag. Script now exits with clear error
message if no target is specified.
Updated SKILL.md to instruct agents to ask user first.
Co-Authored-By: Claude <noreply@anthropic.com>
- Changed all prints from stderr to stdout for consistent buffering
- Added sys.stdout.flush() before input() to ensure proper ordering
- Fixes issue where input prompt appeared before options were displayed
Co-Authored-By: Claude <noreply@anthropic.com>
- Use npm.cmd instead of npm on Windows (os.name == 'nt')
- Add Windows shell names to IGNORED_PROCESS_NAMES (cmd, powershell, pwsh)
- Add Windows executable extensions (.exe, .cmd) to ignored list
- Apply fix to both run.py and setup_environment.py
Co-Authored-By: Claude <noreply@anthropic.com>
When no --notebook-id is specified, prompt user to choose:
- Upload to active notebook (if one exists)
- Create a new notebook
- Select from existing notebooks (if no active)
Adds interactive parameter to disable prompting for programmatic use.
Co-Authored-By: Claude <noreply@anthropic.com>
Compare SHA256 hash of requirements.txt against stored hash in
.venv/.requirements.hash. Automatically runs pip install when
requirements change or hash file is missing.
Co-Authored-By: Claude <noreply@anthropic.com>
Move pre-flight checks from SKILL.md instructions into run.py itself,
providing automatic dependency and authentication validation on every
command. Auth is checked for freshness (10-day TTL) and auto-prompts
browser login when missing or expired.
Co-Authored-By: Claude <noreply@anthropic.com>