bps-kit 1.0.1 ā 1.0.2
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.
- package/package.json +1 -1
- package/templates/.agents/agents/backend-specialist.md +263 -0
- package/templates/.agents/agents/code-archaeologist.md +106 -0
- package/templates/.agents/agents/database-architect.md +226 -0
- package/templates/.agents/agents/debugger.md +225 -0
- package/templates/.agents/agents/devops-engineer.md +242 -0
- package/templates/.agents/agents/documentation-writer.md +104 -0
- package/templates/.agents/agents/explorer-agent.md +73 -0
- package/templates/.agents/agents/frontend-specialist.md +593 -0
- package/templates/.agents/agents/game-developer.md +162 -0
- package/templates/.agents/agents/mobile-developer.md +377 -0
- package/templates/.agents/agents/orchestrator.md +416 -0
- package/templates/.agents/agents/penetration-tester.md +188 -0
- package/templates/.agents/agents/performance-optimizer.md +187 -0
- package/templates/.agents/agents/product-manager.md +112 -0
- package/templates/.agents/agents/product-owner.md +95 -0
- package/templates/.agents/agents/project-planner.md +406 -0
- package/templates/.agents/agents/qa-automation-engineer.md +103 -0
- package/templates/.agents/agents/security-auditor.md +170 -0
- package/templates/.agents/agents/seo-specialist.md +111 -0
- package/templates/.agents/agents/test-engineer.md +158 -0
- package/templates/.agents/rules/GEMINI.md +219 -0
- package/templates/.agents/scripts/auto_preview.py +148 -0
- package/templates/.agents/scripts/checklist.py +217 -0
- package/templates/.agents/scripts/session_manager.py +120 -0
- package/templates/.agents/scripts/verify_all.py +327 -0
- package/templates/.agents/workflows/brainstorm.md +113 -0
- package/templates/.agents/workflows/create.md +59 -0
- package/templates/.agents/workflows/debug.md +103 -0
- package/templates/.agents/workflows/deploy.md +176 -0
- package/templates/.agents/workflows/enhance.md +63 -0
- package/templates/.agents/workflows/orchestrate.md +237 -0
- package/templates/.agents/workflows/plan.md +89 -0
- package/templates/.agents/workflows/preview.md +81 -0
- package/templates/.agents/workflows/setup-brain.md +39 -0
- package/templates/.agents/workflows/status.md +86 -0
- package/templates/.agents/workflows/test.md +144 -0
- package/templates/.agents/workflows/ui-ux-pro-max.md +296 -0
- package/templates/skills_normal/api-patterns/scripts/api_validator.py +211 -0
- package/templates/skills_normal/database-design/scripts/schema_validator.py +172 -0
- package/templates/skills_normal/frontend-design/scripts/accessibility_checker.py +183 -0
- package/templates/skills_normal/frontend-design/scripts/ux_audit.py +722 -0
- package/templates/skills_normal/git-pushing/scripts/smart_commit.sh +19 -0
- package/templates/skills_normal/lint-and-validate/scripts/lint_runner.py +184 -0
- package/templates/skills_normal/lint-and-validate/scripts/type_coverage.py +173 -0
- package/templates/skills_normal/performance-profiling/scripts/lighthouse_audit.py +76 -0
- package/templates/skills_normal/senior-fullstack/scripts/code_quality_analyzer.py +114 -0
- package/templates/skills_normal/senior-fullstack/scripts/fullstack_scaffolder.py +114 -0
- package/templates/skills_normal/senior-fullstack/scripts/project_scaffolder.py +114 -0
- package/templates/skills_normal/seo-fundamentals/scripts/seo_checker.py +219 -0
- package/templates/skills_normal/testing-patterns/scripts/test_runner.py +219 -0
- package/templates/skills_normal/vulnerability-scanner/scripts/security_scan.py +458 -0
- package/templates/vault/007/scripts/config.py +472 -0
- package/templates/vault/007/scripts/full_audit.py +1306 -0
- package/templates/vault/007/scripts/quick_scan.py +481 -0
- package/templates/vault/007/scripts/requirements.txt +26 -0
- package/templates/vault/007/scripts/scanners/__init__.py +0 -0
- package/templates/vault/007/scripts/scanners/dependency_scanner.py +1305 -0
- package/templates/vault/007/scripts/scanners/injection_scanner.py +1104 -0
- package/templates/vault/007/scripts/scanners/secrets_scanner.py +1008 -0
- package/templates/vault/007/scripts/score_calculator.py +693 -0
- package/templates/vault/agent-orchestrator/scripts/match_skills.py +329 -0
- package/templates/vault/agent-orchestrator/scripts/orchestrate.py +304 -0
- package/templates/vault/agent-orchestrator/scripts/requirements.txt +1 -0
- package/templates/vault/agent-orchestrator/scripts/scan_registry.py +508 -0
- package/templates/vault/ai-studio-image/scripts/config.py +613 -0
- package/templates/vault/ai-studio-image/scripts/generate.py +630 -0
- package/templates/vault/ai-studio-image/scripts/prompt_engine.py +424 -0
- package/templates/vault/ai-studio-image/scripts/requirements.txt +4 -0
- package/templates/vault/ai-studio-image/scripts/templates.py +349 -0
- package/templates/vault/android_ui_verification/scripts/verify_ui.sh +32 -0
- package/templates/vault/apify-audience-analysis/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-brand-reputation-monitoring/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-competitor-intelligence/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-content-analytics/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-ecommerce/reference/scripts/package.json +3 -0
- package/templates/vault/apify-ecommerce/reference/scripts/run_actor.js +369 -0
- package/templates/vault/apify-influencer-discovery/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-lead-generation/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-market-research/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-trend-analysis/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-ultimate-scraper/reference/scripts/run_actor.js +363 -0
- package/templates/vault/audio-transcriber/scripts/install-requirements.sh +190 -0
- package/templates/vault/audio-transcriber/scripts/transcribe.py +486 -0
- package/templates/vault/claude-monitor/scripts/api_bench.py +240 -0
- package/templates/vault/claude-monitor/scripts/config.py +69 -0
- package/templates/vault/claude-monitor/scripts/health_check.py +362 -0
- package/templates/vault/claude-monitor/scripts/monitor.py +296 -0
- package/templates/vault/content-creator/scripts/brand_voice_analyzer.py +185 -0
- package/templates/vault/content-creator/scripts/seo_optimizer.py +419 -0
- package/templates/vault/context-agent/scripts/active_context.py +227 -0
- package/templates/vault/context-agent/scripts/compressor.py +149 -0
- package/templates/vault/context-agent/scripts/config.py +69 -0
- package/templates/vault/context-agent/scripts/context_loader.py +155 -0
- package/templates/vault/context-agent/scripts/context_manager.py +302 -0
- package/templates/vault/context-agent/scripts/models.py +103 -0
- package/templates/vault/context-agent/scripts/project_registry.py +132 -0
- package/templates/vault/context-agent/scripts/requirements.txt +6 -0
- package/templates/vault/context-agent/scripts/search.py +115 -0
- package/templates/vault/context-agent/scripts/session_parser.py +206 -0
- package/templates/vault/context-agent/scripts/session_summary.py +319 -0
- package/templates/vault/context-guardian/scripts/context_snapshot.py +229 -0
- package/templates/vault/docx/ooxml/scripts/pack.py +159 -0
- package/templates/vault/docx/ooxml/scripts/unpack.py +29 -0
- package/templates/vault/docx/ooxml/scripts/validate.py +69 -0
- package/templates/vault/docx/ooxml/scripts/validation/__init__.py +15 -0
- package/templates/vault/docx/ooxml/scripts/validation/base.py +951 -0
- package/templates/vault/docx/ooxml/scripts/validation/docx.py +274 -0
- package/templates/vault/docx/ooxml/scripts/validation/pptx.py +315 -0
- package/templates/vault/docx/ooxml/scripts/validation/redlining.py +279 -0
- package/templates/vault/docx/scripts/__init__.py +1 -0
- package/templates/vault/docx/scripts/document.py +1276 -0
- package/templates/vault/docx/scripts/templates/comments.xml +3 -0
- package/templates/vault/docx/scripts/templates/commentsExtended.xml +3 -0
- package/templates/vault/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/templates/vault/docx/scripts/templates/commentsIds.xml +3 -0
- package/templates/vault/docx/scripts/templates/people.xml +3 -0
- package/templates/vault/docx/scripts/utilities.py +374 -0
- package/templates/vault/docx-official/ooxml/scripts/pack.py +159 -0
- package/templates/vault/docx-official/ooxml/scripts/unpack.py +29 -0
- package/templates/vault/docx-official/ooxml/scripts/validate.py +69 -0
- package/templates/vault/docx-official/ooxml/scripts/validation/__init__.py +15 -0
- package/templates/vault/docx-official/ooxml/scripts/validation/base.py +951 -0
- package/templates/vault/docx-official/ooxml/scripts/validation/docx.py +274 -0
- package/templates/vault/docx-official/ooxml/scripts/validation/pptx.py +315 -0
- package/templates/vault/docx-official/ooxml/scripts/validation/redlining.py +279 -0
- package/templates/vault/docx-official/scripts/__init__.py +1 -0
- package/templates/vault/docx-official/scripts/document.py +1276 -0
- package/templates/vault/docx-official/scripts/templates/comments.xml +3 -0
- package/templates/vault/docx-official/scripts/templates/commentsExtended.xml +3 -0
- package/templates/vault/docx-official/scripts/templates/commentsExtensible.xml +3 -0
- package/templates/vault/docx-official/scripts/templates/commentsIds.xml +3 -0
- package/templates/vault/docx-official/scripts/templates/people.xml +3 -0
- package/templates/vault/docx-official/scripts/utilities.py +374 -0
- package/templates/vault/geo-fundamentals/scripts/geo_checker.py +289 -0
- package/templates/vault/helm-chart-scaffolding/scripts/validate-chart.sh +244 -0
- package/templates/vault/i18n-localization/scripts/i18n_checker.py +241 -0
- package/templates/vault/instagram/scripts/account_setup.py +233 -0
- package/templates/vault/instagram/scripts/analyze.py +221 -0
- package/templates/vault/instagram/scripts/api_client.py +444 -0
- package/templates/vault/instagram/scripts/auth.py +411 -0
- package/templates/vault/instagram/scripts/comments.py +160 -0
- package/templates/vault/instagram/scripts/config.py +111 -0
- package/templates/vault/instagram/scripts/db.py +467 -0
- package/templates/vault/instagram/scripts/export.py +138 -0
- package/templates/vault/instagram/scripts/governance.py +233 -0
- package/templates/vault/instagram/scripts/hashtags.py +114 -0
- package/templates/vault/instagram/scripts/insights.py +170 -0
- package/templates/vault/instagram/scripts/media.py +65 -0
- package/templates/vault/instagram/scripts/messages.py +103 -0
- package/templates/vault/instagram/scripts/profile.py +58 -0
- package/templates/vault/instagram/scripts/publish.py +449 -0
- package/templates/vault/instagram/scripts/requirements.txt +5 -0
- package/templates/vault/instagram/scripts/run_all.py +189 -0
- package/templates/vault/instagram/scripts/schedule.py +189 -0
- package/templates/vault/instagram/scripts/serve_api.py +234 -0
- package/templates/vault/instagram/scripts/templates.py +155 -0
- package/templates/vault/junta-leiloeiros/scripts/db.py +216 -0
- package/templates/vault/junta-leiloeiros/scripts/export.py +137 -0
- package/templates/vault/junta-leiloeiros/scripts/requirements.txt +15 -0
- package/templates/vault/junta-leiloeiros/scripts/run_all.py +190 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/__init__.py +4 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/base_scraper.py +209 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/generic_scraper.py +110 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucap.py +110 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/juceac.py +72 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/juceal.py +72 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/juceb.py +68 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucec.py +63 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucema.py +211 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucemg.py +218 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucep.py +70 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucepa.py +74 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucepar.py +80 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucepe.py +78 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucepi.py +69 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucer.py +256 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucerja.py +170 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucern.py +71 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucesc.py +89 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucesp.py +233 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucetins.py +134 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucis_df.py +63 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucisrs.py +299 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/states.py +99 -0
- package/templates/vault/junta-leiloeiros/scripts/serve_api.py +164 -0
- package/templates/vault/junta-leiloeiros/scripts/web_scraper_fallback.py +233 -0
- package/templates/vault/last30days/scripts/last30days.py +521 -0
- package/templates/vault/last30days/scripts/lib/__init__.py +1 -0
- package/templates/vault/last30days/scripts/lib/cache.py +152 -0
- package/templates/vault/last30days/scripts/lib/dates.py +124 -0
- package/templates/vault/last30days/scripts/lib/dedupe.py +120 -0
- package/templates/vault/last30days/scripts/lib/env.py +149 -0
- package/templates/vault/last30days/scripts/lib/http.py +152 -0
- package/templates/vault/last30days/scripts/lib/models.py +175 -0
- package/templates/vault/last30days/scripts/lib/normalize.py +160 -0
- package/templates/vault/last30days/scripts/lib/openai_reddit.py +230 -0
- package/templates/vault/last30days/scripts/lib/reddit_enrich.py +232 -0
- package/templates/vault/last30days/scripts/lib/render.py +383 -0
- package/templates/vault/last30days/scripts/lib/schema.py +336 -0
- package/templates/vault/last30days/scripts/lib/score.py +311 -0
- package/templates/vault/last30days/scripts/lib/ui.py +324 -0
- package/templates/vault/last30days/scripts/lib/websearch.py +401 -0
- package/templates/vault/last30days/scripts/lib/xai_x.py +217 -0
- package/templates/vault/leiloeiro-avaliacao/scripts/governance.py +106 -0
- package/templates/vault/leiloeiro-avaliacao/scripts/requirements.txt +1 -0
- package/templates/vault/leiloeiro-edital/scripts/governance.py +106 -0
- package/templates/vault/leiloeiro-edital/scripts/requirements.txt +1 -0
- package/templates/vault/leiloeiro-ia/scripts/governance.py +106 -0
- package/templates/vault/leiloeiro-ia/scripts/requirements.txt +1 -0
- package/templates/vault/leiloeiro-juridico/scripts/governance.py +106 -0
- package/templates/vault/leiloeiro-juridico/scripts/requirements.txt +1 -0
- package/templates/vault/leiloeiro-mercado/scripts/governance.py +106 -0
- package/templates/vault/leiloeiro-mercado/scripts/requirements.txt +1 -0
- package/templates/vault/leiloeiro-risco/scripts/governance.py +106 -0
- package/templates/vault/leiloeiro-risco/scripts/requirements.txt +1 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/database.ts +24 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/db.ts +35 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/index.ts +2 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/migrations.ts +31 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/schema.sql +8 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/index.ts +44 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/routes/todos.ts +155 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/types/index.ts +35 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/App.css +384 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/App.tsx +81 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/api/todos.ts +57 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/ConfirmDialog.tsx +26 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/EmptyState.tsx +8 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/TodoForm.tsx +43 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/TodoItem.tsx +36 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/TodoList.tsx +27 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/hooks/useTodos.ts +81 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/index.css +48 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/main.tsx +10 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/vite-env.d.ts +1 -0
- package/templates/vault/loki-mode/scripts/export-to-vibe-kanban.sh +178 -0
- package/templates/vault/loki-mode/scripts/loki-wrapper.sh +281 -0
- package/templates/vault/loki-mode/scripts/take-screenshots.js +55 -0
- package/templates/vault/matematico-tao/scripts/complexity_analyzer.py +544 -0
- package/templates/vault/matematico-tao/scripts/dependency_graph.py +538 -0
- package/templates/vault/mcp-builder/scripts/connections.py +151 -0
- package/templates/vault/mcp-builder/scripts/evaluation.py +373 -0
- package/templates/vault/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/templates/vault/mcp-builder/scripts/requirements.txt +2 -0
- package/templates/vault/mobile-design/scripts/mobile_audit.py +670 -0
- package/templates/vault/notebooklm/scripts/__init__.py +81 -0
- package/templates/vault/notebooklm/scripts/ask_question.py +256 -0
- package/templates/vault/notebooklm/scripts/auth_manager.py +358 -0
- package/templates/vault/notebooklm/scripts/browser_session.py +255 -0
- package/templates/vault/notebooklm/scripts/browser_utils.py +107 -0
- package/templates/vault/notebooklm/scripts/cleanup_manager.py +302 -0
- package/templates/vault/notebooklm/scripts/config.py +44 -0
- package/templates/vault/notebooklm/scripts/notebook_manager.py +410 -0
- package/templates/vault/notebooklm/scripts/run.py +102 -0
- package/templates/vault/notebooklm/scripts/setup_environment.py +204 -0
- package/templates/vault/pdf/scripts/check_bounding_boxes.py +70 -0
- package/templates/vault/pdf/scripts/check_bounding_boxes_test.py +226 -0
- package/templates/vault/pdf/scripts/check_fillable_fields.py +12 -0
- package/templates/vault/pdf/scripts/convert_pdf_to_images.py +35 -0
- package/templates/vault/pdf/scripts/create_validation_image.py +41 -0
- package/templates/vault/pdf/scripts/extract_form_field_info.py +152 -0
- package/templates/vault/pdf/scripts/fill_fillable_fields.py +114 -0
- package/templates/vault/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
- package/templates/vault/pdf-official/scripts/check_bounding_boxes.py +70 -0
- package/templates/vault/pdf-official/scripts/check_bounding_boxes_test.py +226 -0
- package/templates/vault/pdf-official/scripts/check_fillable_fields.py +12 -0
- package/templates/vault/pdf-official/scripts/convert_pdf_to_images.py +35 -0
- package/templates/vault/pdf-official/scripts/create_validation_image.py +41 -0
- package/templates/vault/pdf-official/scripts/extract_form_field_info.py +152 -0
- package/templates/vault/pdf-official/scripts/fill_fillable_fields.py +114 -0
- package/templates/vault/pdf-official/scripts/fill_pdf_form_with_annotations.py +108 -0
- package/templates/vault/planning-with-files/scripts/check-complete.sh +44 -0
- package/templates/vault/planning-with-files/scripts/init-session.sh +120 -0
- package/templates/vault/pptx/ooxml/scripts/pack.py +159 -0
- package/templates/vault/pptx/ooxml/scripts/unpack.py +29 -0
- package/templates/vault/pptx/ooxml/scripts/validate.py +69 -0
- package/templates/vault/pptx/ooxml/scripts/validation/__init__.py +15 -0
- package/templates/vault/pptx/ooxml/scripts/validation/base.py +951 -0
- package/templates/vault/pptx/ooxml/scripts/validation/docx.py +274 -0
- package/templates/vault/pptx/ooxml/scripts/validation/pptx.py +315 -0
- package/templates/vault/pptx/ooxml/scripts/validation/redlining.py +279 -0
- package/templates/vault/pptx/scripts/html2pptx.js +979 -0
- package/templates/vault/pptx/scripts/inventory.py +1020 -0
- package/templates/vault/pptx/scripts/rearrange.py +231 -0
- package/templates/vault/pptx/scripts/replace.py +385 -0
- package/templates/vault/pptx/scripts/thumbnail.py +450 -0
- package/templates/vault/pptx-official/ooxml/scripts/pack.py +159 -0
- package/templates/vault/pptx-official/ooxml/scripts/unpack.py +29 -0
- package/templates/vault/pptx-official/ooxml/scripts/validate.py +69 -0
- package/templates/vault/pptx-official/ooxml/scripts/validation/__init__.py +15 -0
- package/templates/vault/pptx-official/ooxml/scripts/validation/base.py +951 -0
- package/templates/vault/pptx-official/ooxml/scripts/validation/docx.py +274 -0
- package/templates/vault/pptx-official/ooxml/scripts/validation/pptx.py +315 -0
- package/templates/vault/pptx-official/ooxml/scripts/validation/redlining.py +279 -0
- package/templates/vault/pptx-official/scripts/html2pptx.js +979 -0
- package/templates/vault/pptx-official/scripts/inventory.py +1020 -0
- package/templates/vault/pptx-official/scripts/rearrange.py +231 -0
- package/templates/vault/pptx-official/scripts/replace.py +385 -0
- package/templates/vault/pptx-official/scripts/thumbnail.py +450 -0
- package/templates/vault/product-manager-toolkit/scripts/customer_interview_analyzer.py +441 -0
- package/templates/vault/product-manager-toolkit/scripts/rice_prioritizer.py +296 -0
- package/templates/vault/prompt-engineering-patterns/scripts/optimize-prompt.py +279 -0
- package/templates/vault/scripts/.skill_cache.json +7538 -0
- package/templates/vault/scripts/skill_search.py +228 -0
- package/templates/vault/senior-architect/scripts/architecture_diagram_generator.py +114 -0
- package/templates/vault/senior-architect/scripts/dependency_analyzer.py +114 -0
- package/templates/vault/senior-architect/scripts/project_architect.py +114 -0
- package/templates/vault/shopify-development/scripts/requirements.txt +19 -0
- package/templates/vault/shopify-development/scripts/shopify_graphql.py +428 -0
- package/templates/vault/shopify-development/scripts/shopify_init.py +441 -0
- package/templates/vault/shopify-development/scripts/tests/test_shopify_init.py +379 -0
- package/templates/vault/skill-creator/scripts/init_skill.py +303 -0
- package/templates/vault/skill-creator/scripts/package_skill.py +110 -0
- package/templates/vault/skill-creator/scripts/quick_validate.py +95 -0
- package/templates/vault/skill-installer/scripts/detect_skills.py +318 -0
- package/templates/vault/skill-installer/scripts/install_skill.py +1708 -0
- package/templates/vault/skill-installer/scripts/package_skill.py +417 -0
- package/templates/vault/skill-installer/scripts/requirements.txt +1 -0
- package/templates/vault/skill-installer/scripts/validate_skill.py +430 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/__init__.py +13 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/code_quality.py +247 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/cross_skill.py +134 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/dependencies.py +121 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/documentation.py +189 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/governance_audit.py +153 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/performance.py +164 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/security.py +189 -0
- package/templates/vault/skill-sentinel/scripts/config.py +158 -0
- package/templates/vault/skill-sentinel/scripts/cost_optimizer.py +146 -0
- package/templates/vault/skill-sentinel/scripts/db.py +354 -0
- package/templates/vault/skill-sentinel/scripts/governance.py +58 -0
- package/templates/vault/skill-sentinel/scripts/recommender.py +228 -0
- package/templates/vault/skill-sentinel/scripts/report_generator.py +224 -0
- package/templates/vault/skill-sentinel/scripts/requirements.txt +1 -0
- package/templates/vault/skill-sentinel/scripts/run_audit.py +290 -0
- package/templates/vault/skill-sentinel/scripts/scanner.py +271 -0
- package/templates/vault/stability-ai/scripts/config.py +266 -0
- package/templates/vault/stability-ai/scripts/generate.py +687 -0
- package/templates/vault/stability-ai/scripts/requirements.txt +4 -0
- package/templates/vault/stability-ai/scripts/styles.py +174 -0
- package/templates/vault/telegram/assets/boilerplate/nodejs/src/bot-client.ts +86 -0
- package/templates/vault/telegram/assets/boilerplate/nodejs/src/handlers.ts +79 -0
- package/templates/vault/telegram/assets/boilerplate/nodejs/src/index.ts +32 -0
- package/templates/vault/telegram/scripts/send_message.py +143 -0
- package/templates/vault/telegram/scripts/setup_project.py +103 -0
- package/templates/vault/telegram/scripts/test_bot.py +144 -0
- package/templates/vault/typescript-expert/scripts/ts_diagnostic.py +203 -0
- package/templates/vault/ui-ux-pro-max/scripts/__pycache__/core.cpython-314.pyc +0 -0
- package/templates/vault/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
- package/templates/vault/ui-ux-pro-max/scripts/core.py +257 -0
- package/templates/vault/ui-ux-pro-max/scripts/design_system.py +487 -0
- package/templates/vault/ui-ux-pro-max/scripts/search.py +76 -0
- package/templates/vault/videodb/scripts/ws_listener.py +204 -0
- package/templates/vault/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
- package/templates/vault/web-artifacts-builder/scripts/init-artifact.sh +322 -0
- package/templates/vault/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
- package/templates/vault/webapp-testing/scripts/with_server.py +106 -0
- package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/index.ts +125 -0
- package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/template-manager.ts +67 -0
- package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/types.ts +216 -0
- package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/webhook-handler.ts +173 -0
- package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/whatsapp-client.ts +193 -0
- package/templates/vault/whatsapp-cloud-api/scripts/send_test_message.py +137 -0
- package/templates/vault/whatsapp-cloud-api/scripts/setup_project.py +118 -0
- package/templates/vault/whatsapp-cloud-api/scripts/validate_config.py +190 -0
- package/templates/vault/youtube-summarizer/scripts/extract-transcript.py +65 -0
- package/templates/vault/youtube-summarizer/scripts/install-dependencies.sh +28 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
NotebookLM Skill Scripts Package
|
|
4
|
+
Provides automatic environment management for all scripts
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
import subprocess
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def ensure_venv_and_run():
|
|
14
|
+
"""
|
|
15
|
+
Ensure virtual environment exists and run the requested script.
|
|
16
|
+
This is called when any script is imported or run directly.
|
|
17
|
+
"""
|
|
18
|
+
# Only do this if we're not already in the skill's venv
|
|
19
|
+
skill_dir = Path(__file__).parent.parent
|
|
20
|
+
venv_dir = skill_dir / ".venv"
|
|
21
|
+
|
|
22
|
+
# Check if we're in a venv
|
|
23
|
+
in_venv = hasattr(sys, 'real_prefix') or (
|
|
24
|
+
hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Check if it's OUR venv
|
|
28
|
+
if in_venv:
|
|
29
|
+
venv_path = Path(sys.prefix)
|
|
30
|
+
if venv_path == venv_dir:
|
|
31
|
+
# We're already in the correct venv
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
# We need to set up or switch to our venv
|
|
35
|
+
if not venv_dir.exists():
|
|
36
|
+
print("š§ First-time setup detected...")
|
|
37
|
+
print(" Creating isolated environment for NotebookLM skill...")
|
|
38
|
+
print(" This ensures clean dependency management...")
|
|
39
|
+
|
|
40
|
+
# Create venv
|
|
41
|
+
import venv
|
|
42
|
+
venv.create(venv_dir, with_pip=True)
|
|
43
|
+
|
|
44
|
+
# Install requirements
|
|
45
|
+
requirements_file = skill_dir / "requirements.txt"
|
|
46
|
+
if requirements_file.exists():
|
|
47
|
+
if os.name == 'nt': # Windows
|
|
48
|
+
pip_exe = venv_dir / "Scripts" / "pip.exe"
|
|
49
|
+
else:
|
|
50
|
+
pip_exe = venv_dir / "bin" / "pip"
|
|
51
|
+
|
|
52
|
+
print(" Installing dependencies in isolated environment...")
|
|
53
|
+
subprocess.run(
|
|
54
|
+
[str(pip_exe), "install", "-q", "-r", str(requirements_file)],
|
|
55
|
+
check=True
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Also install patchright's chromium
|
|
59
|
+
print(" Setting up browser automation...")
|
|
60
|
+
if os.name == 'nt':
|
|
61
|
+
python_exe = venv_dir / "Scripts" / "python.exe"
|
|
62
|
+
else:
|
|
63
|
+
python_exe = venv_dir / "bin" / "python"
|
|
64
|
+
|
|
65
|
+
subprocess.run(
|
|
66
|
+
[str(python_exe), "-m", "patchright", "install", "chromium"],
|
|
67
|
+
check=True,
|
|
68
|
+
capture_output=True
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
print("ā
Environment ready! All dependencies isolated in .venv/")
|
|
72
|
+
|
|
73
|
+
# If we're here and not in the venv, we should recommend using the venv
|
|
74
|
+
if not in_venv:
|
|
75
|
+
print("\nā ļø Running outside virtual environment")
|
|
76
|
+
print(" Recommended: Use scripts/run.py to ensure clean execution")
|
|
77
|
+
print(" Or activate: source .venv/bin/activate")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# Check environment when module is imported
|
|
81
|
+
ensure_venv_and_run()
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Simple NotebookLM Question Interface
|
|
4
|
+
Based on MCP server implementation - simplified without sessions
|
|
5
|
+
|
|
6
|
+
Implements hybrid auth approach:
|
|
7
|
+
- Persistent browser profile (user_data_dir) for fingerprint consistency
|
|
8
|
+
- Manual cookie injection from state.json for session cookies (Playwright bug workaround)
|
|
9
|
+
See: https://github.com/microsoft/playwright/issues/36139
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import sys
|
|
14
|
+
import time
|
|
15
|
+
import re
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
from patchright.sync_api import sync_playwright
|
|
19
|
+
|
|
20
|
+
# Add parent directory to path
|
|
21
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
22
|
+
|
|
23
|
+
from auth_manager import AuthManager
|
|
24
|
+
from notebook_manager import NotebookLibrary
|
|
25
|
+
from config import QUERY_INPUT_SELECTORS, RESPONSE_SELECTORS
|
|
26
|
+
from browser_utils import BrowserFactory, StealthUtils
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Follow-up reminder (adapted from MCP server for stateless operation)
|
|
30
|
+
# Since we don't have persistent sessions, we encourage comprehensive questions
|
|
31
|
+
FOLLOW_UP_REMINDER = (
|
|
32
|
+
"\n\nEXTREMELY IMPORTANT: Is that ALL you need to know? "
|
|
33
|
+
"You can always ask another question! Think about it carefully: "
|
|
34
|
+
"before you reply to the user, review their original request and this answer. "
|
|
35
|
+
"If anything is still unclear or missing, ask me another comprehensive question "
|
|
36
|
+
"that includes all necessary context (since each question opens a new browser session)."
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def ask_notebooklm(question: str, notebook_url: str, headless: bool = True) -> str:
|
|
41
|
+
"""
|
|
42
|
+
Ask a question to NotebookLM
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
question: Question to ask
|
|
46
|
+
notebook_url: NotebookLM notebook URL
|
|
47
|
+
headless: Run browser in headless mode
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Answer text from NotebookLM
|
|
51
|
+
"""
|
|
52
|
+
auth = AuthManager()
|
|
53
|
+
|
|
54
|
+
if not auth.is_authenticated():
|
|
55
|
+
print("ā ļø Not authenticated. Run: python auth_manager.py setup")
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
print(f"š¬ Asking: {question}")
|
|
59
|
+
print(f"š Notebook: {notebook_url}")
|
|
60
|
+
|
|
61
|
+
playwright = None
|
|
62
|
+
context = None
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
# Start playwright
|
|
66
|
+
playwright = sync_playwright().start()
|
|
67
|
+
|
|
68
|
+
# Launch persistent browser context using factory
|
|
69
|
+
context = BrowserFactory.launch_persistent_context(
|
|
70
|
+
playwright,
|
|
71
|
+
headless=headless
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Navigate to notebook
|
|
75
|
+
page = context.new_page()
|
|
76
|
+
print(" š Opening notebook...")
|
|
77
|
+
page.goto(notebook_url, wait_until="domcontentloaded")
|
|
78
|
+
|
|
79
|
+
# Wait for NotebookLM
|
|
80
|
+
page.wait_for_url(re.compile(r"^https://notebooklm\.google\.com/"), timeout=10000)
|
|
81
|
+
|
|
82
|
+
# Wait for query input (MCP approach)
|
|
83
|
+
print(" ā³ Waiting for query input...")
|
|
84
|
+
query_element = None
|
|
85
|
+
|
|
86
|
+
for selector in QUERY_INPUT_SELECTORS:
|
|
87
|
+
try:
|
|
88
|
+
query_element = page.wait_for_selector(
|
|
89
|
+
selector,
|
|
90
|
+
timeout=10000,
|
|
91
|
+
state="visible" # Only check visibility, not disabled!
|
|
92
|
+
)
|
|
93
|
+
if query_element:
|
|
94
|
+
print(f" ā Found input: {selector}")
|
|
95
|
+
break
|
|
96
|
+
except:
|
|
97
|
+
continue
|
|
98
|
+
|
|
99
|
+
if not query_element:
|
|
100
|
+
print(" ā Could not find query input")
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
# Type question (human-like, fast)
|
|
104
|
+
print(" ā³ Typing question...")
|
|
105
|
+
|
|
106
|
+
# Use primary selector for typing
|
|
107
|
+
input_selector = QUERY_INPUT_SELECTORS[0]
|
|
108
|
+
StealthUtils.human_type(page, input_selector, question)
|
|
109
|
+
|
|
110
|
+
# Submit
|
|
111
|
+
print(" š¤ Submitting...")
|
|
112
|
+
page.keyboard.press("Enter")
|
|
113
|
+
|
|
114
|
+
# Small pause
|
|
115
|
+
StealthUtils.random_delay(500, 1500)
|
|
116
|
+
|
|
117
|
+
# Wait for response (MCP approach: poll for stable text)
|
|
118
|
+
print(" ā³ Waiting for answer...")
|
|
119
|
+
|
|
120
|
+
answer = None
|
|
121
|
+
stable_count = 0
|
|
122
|
+
last_text = None
|
|
123
|
+
deadline = time.time() + 120 # 2 minutes timeout
|
|
124
|
+
|
|
125
|
+
while time.time() < deadline:
|
|
126
|
+
# Check if NotebookLM is still thinking (most reliable indicator)
|
|
127
|
+
try:
|
|
128
|
+
thinking_element = page.query_selector('div.thinking-message')
|
|
129
|
+
if thinking_element and thinking_element.is_visible():
|
|
130
|
+
time.sleep(1)
|
|
131
|
+
continue
|
|
132
|
+
except:
|
|
133
|
+
pass
|
|
134
|
+
|
|
135
|
+
# Try to find response with MCP selectors
|
|
136
|
+
for selector in RESPONSE_SELECTORS:
|
|
137
|
+
try:
|
|
138
|
+
elements = page.query_selector_all(selector)
|
|
139
|
+
if elements:
|
|
140
|
+
# Get last (newest) response
|
|
141
|
+
latest = elements[-1]
|
|
142
|
+
text = latest.inner_text().strip()
|
|
143
|
+
|
|
144
|
+
if text:
|
|
145
|
+
if text == last_text:
|
|
146
|
+
stable_count += 1
|
|
147
|
+
if stable_count >= 3: # Stable for 3 polls
|
|
148
|
+
answer = text
|
|
149
|
+
break
|
|
150
|
+
else:
|
|
151
|
+
stable_count = 0
|
|
152
|
+
last_text = text
|
|
153
|
+
except:
|
|
154
|
+
continue
|
|
155
|
+
|
|
156
|
+
if answer:
|
|
157
|
+
break
|
|
158
|
+
|
|
159
|
+
time.sleep(1)
|
|
160
|
+
|
|
161
|
+
if not answer:
|
|
162
|
+
print(" ā Timeout waiting for answer")
|
|
163
|
+
return None
|
|
164
|
+
|
|
165
|
+
print(" ā
Got answer!")
|
|
166
|
+
# Add follow-up reminder to encourage Claude to ask more questions
|
|
167
|
+
return answer + FOLLOW_UP_REMINDER
|
|
168
|
+
|
|
169
|
+
except Exception as e:
|
|
170
|
+
print(f" ā Error: {e}")
|
|
171
|
+
import traceback
|
|
172
|
+
traceback.print_exc()
|
|
173
|
+
return None
|
|
174
|
+
|
|
175
|
+
finally:
|
|
176
|
+
# Always clean up
|
|
177
|
+
if context:
|
|
178
|
+
try:
|
|
179
|
+
context.close()
|
|
180
|
+
except:
|
|
181
|
+
pass
|
|
182
|
+
|
|
183
|
+
if playwright:
|
|
184
|
+
try:
|
|
185
|
+
playwright.stop()
|
|
186
|
+
except:
|
|
187
|
+
pass
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def main():
|
|
191
|
+
parser = argparse.ArgumentParser(description='Ask NotebookLM a question')
|
|
192
|
+
|
|
193
|
+
parser.add_argument('--question', required=True, help='Question to ask')
|
|
194
|
+
parser.add_argument('--notebook-url', help='NotebookLM notebook URL')
|
|
195
|
+
parser.add_argument('--notebook-id', help='Notebook ID from library')
|
|
196
|
+
parser.add_argument('--show-browser', action='store_true', help='Show browser')
|
|
197
|
+
|
|
198
|
+
args = parser.parse_args()
|
|
199
|
+
|
|
200
|
+
# Resolve notebook URL
|
|
201
|
+
notebook_url = args.notebook_url
|
|
202
|
+
|
|
203
|
+
if not notebook_url and args.notebook_id:
|
|
204
|
+
library = NotebookLibrary()
|
|
205
|
+
notebook = library.get_notebook(args.notebook_id)
|
|
206
|
+
if notebook:
|
|
207
|
+
notebook_url = notebook['url']
|
|
208
|
+
else:
|
|
209
|
+
print(f"ā Notebook '{args.notebook_id}' not found")
|
|
210
|
+
return 1
|
|
211
|
+
|
|
212
|
+
if not notebook_url:
|
|
213
|
+
# Check for active notebook first
|
|
214
|
+
library = NotebookLibrary()
|
|
215
|
+
active = library.get_active_notebook()
|
|
216
|
+
if active:
|
|
217
|
+
notebook_url = active['url']
|
|
218
|
+
print(f"š Using active notebook: {active['name']}")
|
|
219
|
+
else:
|
|
220
|
+
# Show available notebooks
|
|
221
|
+
notebooks = library.list_notebooks()
|
|
222
|
+
if notebooks:
|
|
223
|
+
print("\nš Available notebooks:")
|
|
224
|
+
for nb in notebooks:
|
|
225
|
+
mark = " [ACTIVE]" if nb.get('id') == library.active_notebook_id else ""
|
|
226
|
+
print(f" {nb['id']}: {nb['name']}{mark}")
|
|
227
|
+
print("\nSpecify with --notebook-id or set active:")
|
|
228
|
+
print("python scripts/run.py notebook_manager.py activate --id ID")
|
|
229
|
+
else:
|
|
230
|
+
print("ā No notebooks in library. Add one first:")
|
|
231
|
+
print("python scripts/run.py notebook_manager.py add --url URL --name NAME --description DESC --topics TOPICS")
|
|
232
|
+
return 1
|
|
233
|
+
|
|
234
|
+
# Ask the question
|
|
235
|
+
answer = ask_notebooklm(
|
|
236
|
+
question=args.question,
|
|
237
|
+
notebook_url=notebook_url,
|
|
238
|
+
headless=not args.show_browser
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
if answer:
|
|
242
|
+
print("\n" + "=" * 60)
|
|
243
|
+
print(f"Question: {args.question}")
|
|
244
|
+
print("=" * 60)
|
|
245
|
+
print()
|
|
246
|
+
print(answer)
|
|
247
|
+
print()
|
|
248
|
+
print("=" * 60)
|
|
249
|
+
return 0
|
|
250
|
+
else:
|
|
251
|
+
print("\nā Failed to get answer")
|
|
252
|
+
return 1
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
if __name__ == "__main__":
|
|
256
|
+
sys.exit(main())
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Authentication Manager for NotebookLM
|
|
4
|
+
Handles Google login and browser state persistence
|
|
5
|
+
Based on the MCP server implementation
|
|
6
|
+
|
|
7
|
+
Implements hybrid auth approach:
|
|
8
|
+
- Persistent browser profile (user_data_dir) for fingerprint consistency
|
|
9
|
+
- Manual cookie injection from state.json for session cookies (Playwright bug workaround)
|
|
10
|
+
See: https://github.com/microsoft/playwright/issues/36139
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
import time
|
|
15
|
+
import argparse
|
|
16
|
+
import shutil
|
|
17
|
+
import re
|
|
18
|
+
import sys
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Optional, Dict, Any
|
|
21
|
+
|
|
22
|
+
from patchright.sync_api import sync_playwright, BrowserContext
|
|
23
|
+
|
|
24
|
+
# Add parent directory to path
|
|
25
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
26
|
+
|
|
27
|
+
from config import BROWSER_STATE_DIR, STATE_FILE, AUTH_INFO_FILE, DATA_DIR
|
|
28
|
+
from browser_utils import BrowserFactory
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class AuthManager:
|
|
32
|
+
"""
|
|
33
|
+
Manages authentication and browser state for NotebookLM
|
|
34
|
+
|
|
35
|
+
Features:
|
|
36
|
+
- Interactive Google login
|
|
37
|
+
- Browser state persistence
|
|
38
|
+
- Session restoration
|
|
39
|
+
- Account switching
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(self):
|
|
43
|
+
"""Initialize the authentication manager"""
|
|
44
|
+
# Ensure directories exist
|
|
45
|
+
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
46
|
+
BROWSER_STATE_DIR.mkdir(parents=True, exist_ok=True)
|
|
47
|
+
|
|
48
|
+
self.state_file = STATE_FILE
|
|
49
|
+
self.auth_info_file = AUTH_INFO_FILE
|
|
50
|
+
self.browser_state_dir = BROWSER_STATE_DIR
|
|
51
|
+
|
|
52
|
+
def is_authenticated(self) -> bool:
|
|
53
|
+
"""Check if valid authentication exists"""
|
|
54
|
+
if not self.state_file.exists():
|
|
55
|
+
return False
|
|
56
|
+
|
|
57
|
+
# Check if state file is not too old (7 days)
|
|
58
|
+
age_days = (time.time() - self.state_file.stat().st_mtime) / 86400
|
|
59
|
+
if age_days > 7:
|
|
60
|
+
print(f"ā ļø Browser state is {age_days:.1f} days old, may need re-authentication")
|
|
61
|
+
|
|
62
|
+
return True
|
|
63
|
+
|
|
64
|
+
def get_auth_info(self) -> Dict[str, Any]:
|
|
65
|
+
"""Get authentication information"""
|
|
66
|
+
info = {
|
|
67
|
+
'authenticated': self.is_authenticated(),
|
|
68
|
+
'state_file': str(self.state_file),
|
|
69
|
+
'state_exists': self.state_file.exists()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if self.auth_info_file.exists():
|
|
73
|
+
try:
|
|
74
|
+
with open(self.auth_info_file, 'r') as f:
|
|
75
|
+
saved_info = json.load(f)
|
|
76
|
+
info.update(saved_info)
|
|
77
|
+
except Exception:
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
if info['state_exists']:
|
|
81
|
+
age_hours = (time.time() - self.state_file.stat().st_mtime) / 3600
|
|
82
|
+
info['state_age_hours'] = age_hours
|
|
83
|
+
|
|
84
|
+
return info
|
|
85
|
+
|
|
86
|
+
def setup_auth(self, headless: bool = False, timeout_minutes: int = 10) -> bool:
|
|
87
|
+
"""
|
|
88
|
+
Perform interactive authentication setup
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
headless: Run browser in headless mode (False for login)
|
|
92
|
+
timeout_minutes: Maximum time to wait for login
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
True if authentication successful
|
|
96
|
+
"""
|
|
97
|
+
print("š Starting authentication setup...")
|
|
98
|
+
print(f" Timeout: {timeout_minutes} minutes")
|
|
99
|
+
|
|
100
|
+
playwright = None
|
|
101
|
+
context = None
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
playwright = sync_playwright().start()
|
|
105
|
+
|
|
106
|
+
# Launch using factory
|
|
107
|
+
context = BrowserFactory.launch_persistent_context(
|
|
108
|
+
playwright,
|
|
109
|
+
headless=headless
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Navigate to NotebookLM
|
|
113
|
+
page = context.new_page()
|
|
114
|
+
page.goto("https://notebooklm.google.com", wait_until="domcontentloaded")
|
|
115
|
+
|
|
116
|
+
# Check if already authenticated
|
|
117
|
+
if "notebooklm.google.com" in page.url and "accounts.google.com" not in page.url:
|
|
118
|
+
print(" ā
Already authenticated!")
|
|
119
|
+
self._save_browser_state(context)
|
|
120
|
+
return True
|
|
121
|
+
|
|
122
|
+
# Wait for manual login
|
|
123
|
+
print("\n ā³ Please log in to your Google account...")
|
|
124
|
+
print(f" ā±ļø Waiting up to {timeout_minutes} minutes for login...")
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
# Wait for URL to change to NotebookLM (regex ensures it's the actual domain, not a parameter)
|
|
128
|
+
timeout_ms = int(timeout_minutes * 60 * 1000)
|
|
129
|
+
page.wait_for_url(re.compile(r"^https://notebooklm\.google\.com/"), timeout=timeout_ms)
|
|
130
|
+
|
|
131
|
+
print(f" ā
Login successful!")
|
|
132
|
+
|
|
133
|
+
# Save authentication state
|
|
134
|
+
self._save_browser_state(context)
|
|
135
|
+
self._save_auth_info()
|
|
136
|
+
return True
|
|
137
|
+
|
|
138
|
+
except Exception as e:
|
|
139
|
+
print(f" ā Authentication timeout: {e}")
|
|
140
|
+
return False
|
|
141
|
+
|
|
142
|
+
except Exception as e:
|
|
143
|
+
print(f" ā Error: {e}")
|
|
144
|
+
return False
|
|
145
|
+
|
|
146
|
+
finally:
|
|
147
|
+
# Clean up browser resources
|
|
148
|
+
if context:
|
|
149
|
+
try:
|
|
150
|
+
context.close()
|
|
151
|
+
except Exception:
|
|
152
|
+
pass
|
|
153
|
+
|
|
154
|
+
if playwright:
|
|
155
|
+
try:
|
|
156
|
+
playwright.stop()
|
|
157
|
+
except Exception:
|
|
158
|
+
pass
|
|
159
|
+
|
|
160
|
+
def _save_browser_state(self, context: BrowserContext):
|
|
161
|
+
"""Save browser state to disk"""
|
|
162
|
+
try:
|
|
163
|
+
# Save storage state (cookies, localStorage)
|
|
164
|
+
context.storage_state(path=str(self.state_file))
|
|
165
|
+
print(f" š¾ Saved browser state to: {self.state_file}")
|
|
166
|
+
except Exception as e:
|
|
167
|
+
print(f" ā Failed to save browser state: {e}")
|
|
168
|
+
raise
|
|
169
|
+
|
|
170
|
+
def _save_auth_info(self):
|
|
171
|
+
"""Save authentication metadata"""
|
|
172
|
+
try:
|
|
173
|
+
info = {
|
|
174
|
+
'authenticated_at': time.time(),
|
|
175
|
+
'authenticated_at_iso': time.strftime('%Y-%m-%d %H:%M:%S')
|
|
176
|
+
}
|
|
177
|
+
with open(self.auth_info_file, 'w') as f:
|
|
178
|
+
json.dump(info, f, indent=2)
|
|
179
|
+
except Exception:
|
|
180
|
+
pass # Non-critical
|
|
181
|
+
|
|
182
|
+
def clear_auth(self) -> bool:
|
|
183
|
+
"""
|
|
184
|
+
Clear all authentication data
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
True if cleared successfully
|
|
188
|
+
"""
|
|
189
|
+
print("šļø Clearing authentication data...")
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
# Remove browser state
|
|
193
|
+
if self.state_file.exists():
|
|
194
|
+
self.state_file.unlink()
|
|
195
|
+
print(" ā
Removed browser state")
|
|
196
|
+
|
|
197
|
+
# Remove auth info
|
|
198
|
+
if self.auth_info_file.exists():
|
|
199
|
+
self.auth_info_file.unlink()
|
|
200
|
+
print(" ā
Removed auth info")
|
|
201
|
+
|
|
202
|
+
# Clear entire browser state directory
|
|
203
|
+
if self.browser_state_dir.exists():
|
|
204
|
+
shutil.rmtree(self.browser_state_dir)
|
|
205
|
+
self.browser_state_dir.mkdir(parents=True, exist_ok=True)
|
|
206
|
+
print(" ā
Cleared browser data")
|
|
207
|
+
|
|
208
|
+
return True
|
|
209
|
+
|
|
210
|
+
except Exception as e:
|
|
211
|
+
print(f" ā Error clearing auth: {e}")
|
|
212
|
+
return False
|
|
213
|
+
|
|
214
|
+
def re_auth(self, headless: bool = False, timeout_minutes: int = 10) -> bool:
|
|
215
|
+
"""
|
|
216
|
+
Perform re-authentication (clear and setup)
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
headless: Run browser in headless mode
|
|
220
|
+
timeout_minutes: Login timeout in minutes
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
True if successful
|
|
224
|
+
"""
|
|
225
|
+
print("š Starting re-authentication...")
|
|
226
|
+
|
|
227
|
+
# Clear existing auth
|
|
228
|
+
self.clear_auth()
|
|
229
|
+
|
|
230
|
+
# Setup new auth
|
|
231
|
+
return self.setup_auth(headless, timeout_minutes)
|
|
232
|
+
|
|
233
|
+
def validate_auth(self) -> bool:
|
|
234
|
+
"""
|
|
235
|
+
Validate that stored authentication works
|
|
236
|
+
Uses persistent context to match actual usage pattern
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
True if authentication is valid
|
|
240
|
+
"""
|
|
241
|
+
if not self.is_authenticated():
|
|
242
|
+
return False
|
|
243
|
+
|
|
244
|
+
print("š Validating authentication...")
|
|
245
|
+
|
|
246
|
+
playwright = None
|
|
247
|
+
context = None
|
|
248
|
+
|
|
249
|
+
try:
|
|
250
|
+
playwright = sync_playwright().start()
|
|
251
|
+
|
|
252
|
+
# Launch using factory
|
|
253
|
+
context = BrowserFactory.launch_persistent_context(
|
|
254
|
+
playwright,
|
|
255
|
+
headless=True
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
# Try to access NotebookLM
|
|
259
|
+
page = context.new_page()
|
|
260
|
+
page.goto("https://notebooklm.google.com", wait_until="domcontentloaded", timeout=30000)
|
|
261
|
+
|
|
262
|
+
# Check if we can access NotebookLM
|
|
263
|
+
if "notebooklm.google.com" in page.url and "accounts.google.com" not in page.url:
|
|
264
|
+
print(" ā
Authentication is valid")
|
|
265
|
+
return True
|
|
266
|
+
else:
|
|
267
|
+
print(" ā Authentication is invalid (redirected to login)")
|
|
268
|
+
return False
|
|
269
|
+
|
|
270
|
+
except Exception as e:
|
|
271
|
+
print(f" ā Validation failed: {e}")
|
|
272
|
+
return False
|
|
273
|
+
|
|
274
|
+
finally:
|
|
275
|
+
if context:
|
|
276
|
+
try:
|
|
277
|
+
context.close()
|
|
278
|
+
except Exception:
|
|
279
|
+
pass
|
|
280
|
+
if playwright:
|
|
281
|
+
try:
|
|
282
|
+
playwright.stop()
|
|
283
|
+
except Exception:
|
|
284
|
+
pass
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def main():
|
|
288
|
+
"""Command-line interface for authentication management"""
|
|
289
|
+
parser = argparse.ArgumentParser(description='Manage NotebookLM authentication')
|
|
290
|
+
|
|
291
|
+
subparsers = parser.add_subparsers(dest='command', help='Commands')
|
|
292
|
+
|
|
293
|
+
# Setup command
|
|
294
|
+
setup_parser = subparsers.add_parser('setup', help='Setup authentication')
|
|
295
|
+
setup_parser.add_argument('--headless', action='store_true', help='Run in headless mode')
|
|
296
|
+
setup_parser.add_argument('--timeout', type=float, default=10, help='Login timeout in minutes (default: 10)')
|
|
297
|
+
|
|
298
|
+
# Status command
|
|
299
|
+
subparsers.add_parser('status', help='Check authentication status')
|
|
300
|
+
|
|
301
|
+
# Validate command
|
|
302
|
+
subparsers.add_parser('validate', help='Validate authentication')
|
|
303
|
+
|
|
304
|
+
# Clear command
|
|
305
|
+
subparsers.add_parser('clear', help='Clear authentication')
|
|
306
|
+
|
|
307
|
+
# Re-auth command
|
|
308
|
+
reauth_parser = subparsers.add_parser('reauth', help='Re-authenticate (clear + setup)')
|
|
309
|
+
reauth_parser.add_argument('--timeout', type=float, default=10, help='Login timeout in minutes (default: 10)')
|
|
310
|
+
|
|
311
|
+
args = parser.parse_args()
|
|
312
|
+
|
|
313
|
+
# Initialize manager
|
|
314
|
+
auth = AuthManager()
|
|
315
|
+
|
|
316
|
+
# Execute command
|
|
317
|
+
if args.command == 'setup':
|
|
318
|
+
if auth.setup_auth(headless=args.headless, timeout_minutes=args.timeout):
|
|
319
|
+
print("\nā
Authentication setup complete!")
|
|
320
|
+
print("You can now use ask_question.py to query NotebookLM")
|
|
321
|
+
else:
|
|
322
|
+
print("\nā Authentication setup failed")
|
|
323
|
+
exit(1)
|
|
324
|
+
|
|
325
|
+
elif args.command == 'status':
|
|
326
|
+
info = auth.get_auth_info()
|
|
327
|
+
print("\nš Authentication Status:")
|
|
328
|
+
print(f" Authenticated: {'Yes' if info['authenticated'] else 'No'}")
|
|
329
|
+
if info.get('state_age_hours'):
|
|
330
|
+
print(f" State age: {info['state_age_hours']:.1f} hours")
|
|
331
|
+
if info.get('authenticated_at_iso'):
|
|
332
|
+
print(f" Last auth: {info['authenticated_at_iso']}")
|
|
333
|
+
print(f" State file: {info['state_file']}")
|
|
334
|
+
|
|
335
|
+
elif args.command == 'validate':
|
|
336
|
+
if auth.validate_auth():
|
|
337
|
+
print("Authentication is valid and working")
|
|
338
|
+
else:
|
|
339
|
+
print("Authentication is invalid or expired")
|
|
340
|
+
print("Run: auth_manager.py setup")
|
|
341
|
+
|
|
342
|
+
elif args.command == 'clear':
|
|
343
|
+
if auth.clear_auth():
|
|
344
|
+
print("Authentication cleared")
|
|
345
|
+
|
|
346
|
+
elif args.command == 'reauth':
|
|
347
|
+
if auth.re_auth(timeout_minutes=args.timeout):
|
|
348
|
+
print("\nā
Re-authentication complete!")
|
|
349
|
+
else:
|
|
350
|
+
print("\nā Re-authentication failed")
|
|
351
|
+
exit(1)
|
|
352
|
+
|
|
353
|
+
else:
|
|
354
|
+
parser.print_help()
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
if __name__ == "__main__":
|
|
358
|
+
main()
|