104 Commits

Author SHA1 Message Date
Deheng Huang f0a0930afa fix: address Copilot review comments
- 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>
2026-02-23 14:34:22 +08:00
Deheng Huang 8c48941498 feat: add multi-agent support for OpenClaw account isolation
- config.py: get_agent_id() (NBLM_AGENT_ID>OPENCLAW_AGENT>AGENT_NAME), get_agent_config_dir(), get_agent_active_account_file()
- account_manager.py: per-agent active account isolation (load/save/set/clear), agent-first get_active_account()
- auth_manager.py: accounts use/clear commands, status shows agent ID
- CLAUDE.md: English output iron rule
- SKILL.md: document use/clear commands and routing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 13:54:38 +08:00
Deheng Huang d47fbd3fd9 Revert "feat: add multi-agent support for OpenClaw account isolation"
This reverts commit f09d918818.
2026-02-23 13:48:09 +08:00
Deheng Huang f09d918818 feat: add multi-agent support for OpenClaw account isolation
- 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
2026-02-23 13:15:11 +08:00
copilot-swe-agent[bot] a40ba540a9 fix: use replace() instead of rename() for corrupted file backup
Co-authored-by: magicseek <446252+magicseek@users.noreply.github.com>
2026-01-30 14:01:43 +00:00
copilot-swe-agent[bot] db23c83fc1 style: move import to module level per PEP 8
Co-authored-by: magicseek <446252+magicseek@users.noreply.github.com>
2026-01-30 13:59:36 +00:00
copilot-swe-agent[bot] 6a8d08b7ec fix: address PR review feedback for Windows compatibility and path normalization
Co-authored-by: magicseek <446252+magicseek@users.noreply.github.com>
2026-01-30 13:57:24 +00:00
Deheng Huang 1199cc0cde feat(sync): add sync CLI command and fix rename sync
- nblm_cli: add sync command with --dry-run and --notebook-id options
- cmd_rename: sync local library after remote rename
2026-01-30 15:08:25 +08:00
Deheng Huang c079af3ea7 fix(sync): move tracking files to data/sync/ directory
- Tracking files stored in data/sync/ (not in synced folder)
- Uses hash-based filename: {md5_hash}.sync.json
- Prevents cluttering user's synced folder
2026-01-30 15:08:07 +08:00
Deheng Huang c5f398a08f feat(sync): add folder auto-routing and notebook auto-activation
- source_manager: auto-route folder uploads to sync command
- notebook_manager: add notebook_id parameter to add_notebook()
- Both: auto-activate newly created notebooks
2026-01-30 15:07:59 +08:00
Deheng Huang edcfa5d16e feat(sync): integrate sync command with CLI 2026-01-30 13:55:10 +08:00
Deheng Huang be2439257b feat(sync): add sync execution logic 2026-01-30 13:53:18 +08:00
Deheng Huang 80643ac68e feat(sync): add sync plan generation 2026-01-30 13:50:53 +08:00
Deheng Huang 53f8da7754 feat(sync): add folder scanning and file hashing 2026-01-30 13:49:41 +08:00
Deheng Huang 21014c5542 feat(sync): add state management (load_state, save_state) 2026-01-30 13:48:02 +08:00
Deheng Huang 7aa441969a feat(sync): create SyncManager class skeleton 2026-01-30 13:45:44 +08:00
Deheng Huang e999e6685d feat(auth): auto-reauth expired credentials on command execution
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>
2026-01-30 00:01:02 +08:00
Deheng Huang 772c702d0c fix(auth): enforce Patchright for all Google authentication
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>
2026-01-30 00:00:19 +08:00
Deheng Huang 109fb42a69 Update scripts/auth_manager.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-29 21:59:05 +08: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