Commit Graph

88 Commits

Author SHA1 Message Date
Deheng Huang b9f1d921b4 Update scripts/auth_manager.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-29 22:09:21 +08:00
copilot-swe-agent[bot] 3371ea385e refactor: address code review feedback - DRY validation, shared instances
Co-authored-by: magicseek <446252+magicseek@users.noreply.github.com>
2026-01-29 14:06:13 +00:00
copilot-swe-agent[bot] c446c56d77 fix: address code review feedback - error handling, validation, and compatibility
Co-authored-by: magicseek <446252+magicseek@users.noreply.github.com>
2026-01-29 14:02:48 +00:00
Deheng Huang 88e5fc09b9 feat(auth): fresh profile and symlink improvements
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>
2026-01-29 13:48:09 +08:00
Deheng Huang 189253e0df feat(patchright): temp profile and CDP cross-window detection
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>
2026-01-29 13:47:30 +08:00
Deheng Huang a9c4fbc418 fix(run): support multi-account auth check in wrapper
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>
2026-01-29 13:46:58 +08:00
Deheng Huang a8a317c8da fix(migration): prevent placeholder account creation
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>
2026-01-29 13:46:25 +08:00
Deheng Huang 4dfba9c512 fix(symlink): update storage_state symlink for multi-account
Symlink now points to active account's credential file
in the google/ subdirectory.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-28 23:18:46 +08:00
Deheng Huang fb22193f8a feat(status): show active account in auth status
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>
2026-01-28 23:16:41 +08:00
Deheng Huang d59e75b20c feat(query): account-aware notebook queries
- 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>
2026-01-28 23:15:00 +08:00
Deheng Huang 13fec86ea1 feat(notebooks): associate notebooks with accounts
- 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>
2026-01-28 23:07:02 +08:00
Deheng Huang 494a362128 feat(wrapper): add account_index parameter
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>
2026-01-28 23:04:59 +08:00
Deheng Huang 3631ae22cf feat(migration): update existing notebooks with account association
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>
2026-01-28 23:04:51 +08:00
Deheng Huang 03d3f0f9b2 feat(cli): add accounts subcommand to auth_manager
Commands:
- accounts list: show all accounts
- accounts add: add new account via auth
- accounts switch <id>: switch active account
- accounts remove <id>: remove account
- accounts reauth <id>: re-authenticate existing account

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-28 23:02:00 +08:00
Deheng Huang bf24e2d45e feat(auth): integrate AccountManager into AuthManager
- 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>
2026-01-28 22:57:10 +08:00
Deheng Huang 5cf9eeea91 feat(auth): return email and storage_state from patchright auth
- authenticate_with_patchright now returns (success, email, storage_state)
- Add _extract_email_from_page helper
- Caller responsible for saving credentials

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-28 22:53:49 +08:00
Deheng Huang 8fe4952a86 feat(accounts): add/remove account methods
- 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>
2026-01-28 22:50:40 +08:00
Deheng Huang ce488fdb88 feat(accounts): add switch and lookup methods
- 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>
2026-01-28 22:48:54 +08:00
Deheng Huang f20a0004e4 feat(accounts): create AccountManager with core data structures
- 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>
2026-01-28 22:46:41 +08:00
Deheng Huang 71acf76aeb feat(config): add multi-account path constants
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>
2026-01-28 22:44:28 +08:00
Deheng Huang ccff425bdc refactor(browser): clean up agent_browser_client launch method
Minor cleanup: improve docstring and simplify parameter handling.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-27 10:22:38 +08:00
Deheng Huang 624ca7bfd4 fix(library): normalize Unicode smart quotes in notebook IDs
Notebook names containing smart quotes (', ', ", ") from NotebookLM
could not be activated/removed when user typed ASCII equivalents.

- Add _normalize_id() helper for Unicode normalization
- Apply normalization in add_notebook, select_notebook, remove_notebook
- Handle: smart quotes, en/em dashes, ellipsis
- Backward compatible: stored IDs unchanged, input normalized for matching

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-27 10:22:26 +08:00
Deheng Huang 407cb3ac5a feat(deps): auto-install Patchright browser for existing users
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>
2026-01-27 10:22:11 +08:00
Deheng Huang 6f0d08deae feat(auth): use Patchright for Google authentication
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>
2026-01-27 10:21:53 +08:00
Deheng Huang 2d5d47673e feat(upload): replace interactive prompt with CLI flags
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>
2026-01-26 18:51:22 +08:00
Deheng Huang eb5ed2869e fix(source): fix prompt buffering issue for notebook choice
- 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>
2026-01-26 17:30:08 +08:00
Deheng Huang c77966425d feat(init): create symlinks in home directory for all platforms
- Added symlink_path config for each platform (e.g., .cursor/skills/nblm)
- Creates ~/.{agent}/skills/nblm -> ~/.nblm symlink on Unix
- Skips symlink creation on Windows (requires admin privileges)
- Handles existing symlinks: skip if correct, warn if different
- Supports --force to overwrite existing symlinks

Symlink paths:
- Claude: ~/.claude/skills/nblm
- Cursor: ~/.cursor/skills/nblm
- Codex: ~/.codex/skills/nblm
- Antigravity: ~/.agent/skills/nblm
- Windsurf: ~/.windsurf/skills/nblm
- Copilot: ~/.github/skills/nblm

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-26 17:05:37 +08:00
Deheng Huang 7b8611a6e1 fix: add Windows compatibility for npm commands
- 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>
2026-01-26 15:09:34 +08:00
Deheng Huang 81d5bbe0bd feat(init): add platform initializer for AI coding assistants
Create init_platform.py to generate platform-specific skill files:
- Claude Code: .claude/skills/nblm/SKILL.md
- Cursor: .cursor/commands/nblm.md
- Codex: .codex/skills/nblm/SKILL.md
- Antigravity: .agent/skills/nblm/SKILL.md
- Windsurf: .windsurf/workflows/nblm.md
- GitHub Copilot: .github/copilot-instructions/nblm.md

Usage: python scripts/run.py init --ai cursor
       python scripts/run.py init --ai all

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-26 14:35:42 +08:00
Deheng Huang ef16e6f2e7 feat(source): prompt for notebook choice on upload
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>
2026-01-26 10:27:26 +08:00
Deheng Huang 4ad4e9597b chore(run): increase install timeouts to 10 minutes
Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-26 08:57:01 +08:00
Deheng Huang e552c79ab3 feat(run): add timeouts for long-running operations
Add subprocess timeouts to prevent hanging:
- Venv setup: 5 minutes
- pip install: 5 minutes
- npm install: 5 minutes
- Auth setup: 10 minutes (user interaction)

Provides clear error messages when timeouts occur.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-26 08:55:28 +08:00
Deheng Huang 93387a52bd feat(run): add pip dependency hash check for auto-install
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>
2026-01-26 08:45:58 +08:00
Deheng Huang 1f6fa65ed7 feat(run): auto-check Google auth before script execution
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>
2026-01-26 08:35:03 +08:00
Deheng Huang d9ca72ee08 feat(artifacts): add slide deck and infographic generation
- Add generate_slide_deck() and generate_infographic() to notebooklm_wrapper.py
- Add download_slide_deck() and download_infographic() methods
- Add generate-slides and generate-infographic CLI commands to artifact_manager.py
- Update SKILL.md with correct command routing and new options documentation
- Support slide formats: DETAILED_DECK, PRESENTER_SLIDES
- Support infographic orientations: LANDSCAPE, PORTRAIT, SQUARE
- Support detail levels: CONCISE, STANDARD, DETAILED

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-25 22:50:01 +08:00
Deheng Huang 6c1a8b9888 fix(auth): create storage_state.json symlink for notebooklm-py compatibility
The notebooklm-py library's download methods use Playwright internally and
look for storage at NOTEBOOKLM_HOME/storage_state.json. This fix:

- Adds _ensure_storage_state_symlink() to create symlink after Google auth
- Symlink points storage_state.json -> google.json in auth directory
- Falls back to file copy on Windows if symlink creation fails
- NOTEBOOKLM_HOME env var already set in config.py to data/auth

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-25 21:21:52 +08:00
Deheng Huang 87ea9e09dd docs: rebrand to nblm with multi-agent support
- Complete README rewrite with new nblm identity
- Add npx add-skill installation via vercel-labs/add-skill
- Position as multi-agent skill (Claude Code, Cursor, OpenCode)
- Add tiered command docs (Quick Start + collapsible reference)
- Add acknowledgments for upstream projects
- Update package.json name to nblm
- Replace all "NotebookLM Skill" references across codebase
- Update .gitignore for .claude-plugin/ and docs/plans/

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-25 21:12:53 +08:00
Deheng Huang 048b9b9f46 feat(notebook): intelligent URL vs notebook ID detection
The --url argument now auto-detects input type:
- Full URL (https://...): Used as-is
- Partial URL (notebooklm.google.com/...): Adds https://
- Notebook ID (abc123...): Converts to full URL

Users can now simply pass either format to --url without thinking.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-25 20:16:16 +08:00
Deheng Huang bced4209d6 feat(notebook): support both URL and notebook ID for add command
Update /nblm add to accept either:
- --url: Full NotebookLM URL
- --notebook-id: Just the notebook ID (auto-converts to URL)

Updated files:
- scripts/notebook_manager.py: Add --notebook-id argument, auto-generate URL
- SKILL.md: Update command documentation
- CLAUDE.md: Update command examples

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-25 20:16:16 +08:00
Deheng Huang 2a5979c49a feat(artifacts): add artifact manager for audio/podcast generation
Add comprehensive artifact management capabilities:
- New artifact_manager.py CLI with list, get, delete, generate, status, download commands
- Extend notebooklm_wrapper.py with artifact APIs (list_artifacts, get_artifact, delete_artifact, get_audio_status, download_artifact)
- Configure NOTEBOOKLM_HOME in config.py to use data/auth/ for notebooklm-py storage
- Update CLAUDE.md and api_reference.md with artifact command documentation

Supported audio formats: DEEP_DIVE, BRIEF, CRITIQUE, DEBATE
Supported lengths: SHORT, DEFAULT, LONG

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-25 20:16:16 +08:00
Deheng Huang 2fa9f68136 feat(skill): add pre-flight checks for dependencies and authentication on first use 2026-01-25 20:16:16 +08:00
Deheng Huang 87ebd6dcdc fix(browser): use load wait state with 3s delay for stable storage restoration 2026-01-25 20:16:16 +08:00
Deheng Huang 15ed577f20 fix(browser): add wait after navigation in set_storage_state to prevent context destruction 2026-01-25 20:16:16 +08:00
Deheng Huang 875d097059 fix(chat): set DETAILED mode and use response.answer attribute 2026-01-25 20:16:16 +08:00
Deheng Huang 1bdfeec1a4 fix(chat): use client.chat.ask() instead of client.chat(), add browser fallback 2026-01-25 20:16:16 +08:00
Deheng Huang 0af7909ad1 feat: add unified nblm_cli.py for all NotebookLM commands 2026-01-25 20:16:16 +08:00
Deheng Huang 935873b92b feat(wrapper): add notebook rename/summary/description, source rename/refresh/fulltext/guide, and audio generation APIs 2026-01-25 20:16:16 +08:00
Deheng Huang 4ee1db69f8 fix: use NotebookLMClient.from_storage() instead of manual AuthTokens
Root cause: Manual AuthTokens creation doesn't work with notebooklm-py.
The library expects from_storage() which handles token extraction internally.

- Remove AuthTokens import and _create_auth_tokens method
- Use from_storage(auth_file) in __aenter__ and _refresh_tokens
- All API calls (list, create, upload) now work correctly

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-25 20:16:16 +08:00
Deheng Huang 0acfec7333 feat: add browser fallback for notebook creation
- Add _fallback_create_notebook() method
- API failures now fall back to browser for both create_notebook and add_file
- Extract notebook ID from URL after browser creation

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-25 20:16:16 +08:00
Deheng Huang cd3bf5faa6 fix: extract API tokens during login and improve browser fallback upload
- Add _extract_and_save_tokens() helper that navigates to NotebookLM before extraction
- Token extraction now happens reliably after successful login (no re-auth needed)
- Fix browser fallback upload to use refs instead of CSS selectors
- Add _find_file_input_ref() to locate upload input in snapshot
- Improve upload flow with better error messages and progress logging

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-25 20:16:16 +08:00