@thanhvn14/csvibe 0.1.4 → 0.1.5
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/.github/agents/schemas/base-output.schema.json +88 -0
- package/.github/agents/schemas/brainstorm-output.schema.json +88 -0
- package/.github/agents/schemas/scout-output.schema.json +60 -0
- package/.github/agents/scripts/fetch-copilot-tools.js +245 -0
- package/.github/agents/scripts/lib/parse-agent-file.js +275 -0
- package/.github/agents/scripts/package-lock.json +78 -0
- package/.github/agents/scripts/package.json +22 -0
- package/.github/agents/scripts/schemas/agent-frontmatter.schema.json +83 -0
- package/.github/agents/scripts/validate-agent-all.js +157 -0
- package/.github/agents/scripts/validate-agent-frontmatter.js +96 -0
- package/.github/agents/scripts/validate-agent-handoffs.js +169 -0
- package/.github/agents/scripts/validate-agent-output.js +157 -0
- package/.github/agents/scripts/validate-agent-tools.js +278 -0
- package/.github/skills/.env.example +100 -0
- package/.github/skills/.install-state.json +23 -0
- package/.github/skills/README.md +149 -0
- package/.github/skills/ai-multimodal/.env.example +204 -0
- package/.github/skills/ai-multimodal/scripts/.coverage +0 -0
- package/.github/skills/ai-multimodal/scripts/check_setup.py +305 -0
- package/.github/skills/ai-multimodal/scripts/document_converter.py +395 -0
- package/.github/skills/ai-multimodal/scripts/gemini_batch_process.py +1184 -0
- package/.github/skills/ai-multimodal/scripts/media_optimizer.py +506 -0
- package/.github/skills/ai-multimodal/scripts/requirements.txt +26 -0
- package/.github/skills/better-auth/scripts/.coverage +0 -0
- package/.github/skills/better-auth/scripts/better_auth_init.py +521 -0
- package/.github/skills/better-auth/scripts/requirements.txt +15 -0
- package/.github/skills/chrome-devtools/scripts/README.md +272 -0
- package/.github/skills/chrome-devtools/scripts/__tests__/selector.test.js +210 -0
- package/.github/skills/chrome-devtools/scripts/aria-snapshot.js +362 -0
- package/.github/skills/chrome-devtools/scripts/click.js +83 -0
- package/.github/skills/chrome-devtools/scripts/console.js +79 -0
- package/.github/skills/chrome-devtools/scripts/evaluate.js +53 -0
- package/.github/skills/chrome-devtools/scripts/fill.js +76 -0
- package/.github/skills/chrome-devtools/scripts/inject-auth.js +229 -0
- package/.github/skills/chrome-devtools/scripts/install-deps.sh +181 -0
- package/.github/skills/chrome-devtools/scripts/install.sh +83 -0
- package/.github/skills/chrome-devtools/scripts/lib/browser.js +318 -0
- package/.github/skills/chrome-devtools/scripts/lib/selector.js +178 -0
- package/.github/skills/chrome-devtools/scripts/navigate.js +54 -0
- package/.github/skills/chrome-devtools/scripts/network.js +106 -0
- package/.github/skills/chrome-devtools/scripts/package-lock.json +1589 -0
- package/.github/skills/chrome-devtools/scripts/package.json +16 -0
- package/.github/skills/chrome-devtools/scripts/performance.js +149 -0
- package/.github/skills/chrome-devtools/scripts/screenshot.js +198 -0
- package/.github/skills/chrome-devtools/scripts/select-ref.js +131 -0
- package/.github/skills/chrome-devtools/scripts/snapshot.js +135 -0
- package/.github/skills/common/README.md +120 -0
- package/.github/skills/common/api_key_helper.py +411 -0
- package/.github/skills/common/api_key_rotator.py +248 -0
- package/.github/skills/databases/scripts/.coverage +0 -0
- package/.github/skills/databases/scripts/db_backup.py +502 -0
- package/.github/skills/databases/scripts/db_migrate.py +425 -0
- package/.github/skills/databases/scripts/db_performance_check.py +456 -0
- package/.github/skills/databases/scripts/requirements.txt +20 -0
- package/.github/skills/debugging/scripts/find-polluter.sh +63 -0
- package/.github/skills/devops/.env.example +76 -0
- package/.github/skills/devops/scripts/cloudflare_deploy.py +269 -0
- package/.github/skills/devops/scripts/docker_optimize.py +331 -0
- package/.github/skills/devops/scripts/requirements.txt +20 -0
- package/.github/skills/docs-seeker/.env.example +15 -0
- package/.github/skills/docs-seeker/package.json +25 -0
- package/.github/skills/docs-seeker/scripts/analyze-llms-txt.js +211 -0
- package/.github/skills/docs-seeker/scripts/detect-topic.js +172 -0
- package/.github/skills/docs-seeker/scripts/fetch-docs.js +213 -0
- package/.github/skills/docs-seeker/scripts/utils/env-loader.js +94 -0
- package/.github/skills/document-skills/docx/LICENSE.txt +30 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/mce/mc.xsd +75 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/.github/skills/document-skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/.github/skills/document-skills/docx/ooxml/scripts/pack.py +159 -0
- package/.github/skills/document-skills/docx/ooxml/scripts/unpack.py +29 -0
- package/.github/skills/document-skills/docx/ooxml/scripts/validate.py +69 -0
- package/.github/skills/document-skills/docx/ooxml/scripts/validation/__init__.py +15 -0
- package/.github/skills/document-skills/docx/ooxml/scripts/validation/base.py +951 -0
- package/.github/skills/document-skills/docx/ooxml/scripts/validation/docx.py +274 -0
- package/.github/skills/document-skills/docx/ooxml/scripts/validation/pptx.py +315 -0
- package/.github/skills/document-skills/docx/ooxml/scripts/validation/redlining.py +279 -0
- package/.github/skills/document-skills/docx/scripts/__init__.py +1 -0
- package/.github/skills/document-skills/docx/scripts/document.py +1276 -0
- package/.github/skills/document-skills/docx/scripts/templates/comments.xml +3 -0
- package/.github/skills/document-skills/docx/scripts/templates/commentsExtended.xml +3 -0
- package/.github/skills/document-skills/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/.github/skills/document-skills/docx/scripts/templates/commentsIds.xml +3 -0
- package/.github/skills/document-skills/docx/scripts/templates/people.xml +3 -0
- package/.github/skills/document-skills/docx/scripts/utilities.py +374 -0
- package/.github/skills/document-skills/pdf/LICENSE.txt +30 -0
- package/.github/skills/document-skills/pdf/scripts/check_bounding_boxes.py +70 -0
- package/.github/skills/document-skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
- package/.github/skills/document-skills/pdf/scripts/check_fillable_fields.py +12 -0
- package/.github/skills/document-skills/pdf/scripts/convert_pdf_to_images.py +35 -0
- package/.github/skills/document-skills/pdf/scripts/create_validation_image.py +41 -0
- package/.github/skills/document-skills/pdf/scripts/extract_form_field_info.py +152 -0
- package/.github/skills/document-skills/pdf/scripts/fill_fillable_fields.py +114 -0
- package/.github/skills/document-skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
- package/.github/skills/document-skills/pptx/LICENSE.txt +30 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/mce/mc.xsd +75 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/.github/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/.github/skills/document-skills/pptx/ooxml/scripts/pack.py +159 -0
- package/.github/skills/document-skills/pptx/ooxml/scripts/unpack.py +29 -0
- package/.github/skills/document-skills/pptx/ooxml/scripts/validate.py +69 -0
- package/.github/skills/document-skills/pptx/ooxml/scripts/validation/__init__.py +15 -0
- package/.github/skills/document-skills/pptx/ooxml/scripts/validation/base.py +951 -0
- package/.github/skills/document-skills/pptx/ooxml/scripts/validation/docx.py +274 -0
- package/.github/skills/document-skills/pptx/ooxml/scripts/validation/pptx.py +315 -0
- package/.github/skills/document-skills/pptx/ooxml/scripts/validation/redlining.py +279 -0
- package/.github/skills/document-skills/pptx/scripts/html2pptx.js +979 -0
- package/.github/skills/document-skills/pptx/scripts/inventory.py +1020 -0
- package/.github/skills/document-skills/pptx/scripts/rearrange.py +231 -0
- package/.github/skills/document-skills/pptx/scripts/replace.py +385 -0
- package/.github/skills/document-skills/pptx/scripts/thumbnail.py +450 -0
- package/.github/skills/document-skills/xlsx/LICENSE.txt +30 -0
- package/.github/skills/document-skills/xlsx/recalc.py +190 -0
- package/.github/skills/install.ps1 +1220 -0
- package/.github/skills/install.sh +1032 -0
- package/.github/skills/markdown-novel-viewer/assets/directory-browser.css +215 -0
- package/.github/skills/markdown-novel-viewer/assets/favicon.png +0 -0
- package/.github/skills/markdown-novel-viewer/assets/novel-theme.css +818 -0
- package/.github/skills/markdown-novel-viewer/assets/reader.js +262 -0
- package/.github/skills/markdown-novel-viewer/assets/template.html +80 -0
- package/.github/skills/markdown-novel-viewer/package-lock.json +146 -0
- package/.github/skills/markdown-novel-viewer/package.json +15 -0
- package/.github/skills/markdown-novel-viewer/scripts/lib/http-server.cjs +434 -0
- package/.github/skills/markdown-novel-viewer/scripts/lib/markdown-renderer.cjs +272 -0
- package/.github/skills/markdown-novel-viewer/scripts/lib/plan-navigator.cjs +509 -0
- package/.github/skills/markdown-novel-viewer/scripts/lib/port-finder.cjs +48 -0
- package/.github/skills/markdown-novel-viewer/scripts/lib/process-mgr.cjs +150 -0
- package/.github/skills/markdown-novel-viewer/scripts/server.cjs +411 -0
- package/.github/skills/mcp-builder/LICENSE.txt +202 -0
- package/.github/skills/mcp-builder/scripts/connections.py +151 -0
- package/.github/skills/mcp-builder/scripts/evaluation.py +373 -0
- package/.github/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/.github/skills/mcp-builder/scripts/requirements.txt +2 -0
- package/.github/skills/mcp-management/README.md +219 -0
- package/.github/skills/mcp-management/assets/tools.json +3146 -0
- package/.github/skills/mcp-management/package-lock.json +6 -0
- package/.github/skills/mcp-management/scripts/.env.example +10 -0
- package/.github/skills/mcp-management/scripts/cli.ts +195 -0
- package/.github/skills/mcp-management/scripts/dist/analyze-tools.js +70 -0
- package/.github/skills/mcp-management/scripts/dist/cli.js +160 -0
- package/.github/skills/mcp-management/scripts/dist/mcp-client.js +183 -0
- package/.github/skills/mcp-management/scripts/mcp-client.ts +230 -0
- package/.github/skills/mcp-management/scripts/package.json +20 -0
- package/.github/skills/media-processing/scripts/README.md +111 -0
- package/.github/skills/media-processing/scripts/batch-remove-background.sh +124 -0
- package/.github/skills/media-processing/scripts/batch_resize.py +342 -0
- package/.github/skills/media-processing/scripts/media_convert.py +311 -0
- package/.github/skills/media-processing/scripts/remove-background.sh +96 -0
- package/.github/skills/media-processing/scripts/remove-bg-node.js +158 -0
- package/.github/skills/media-processing/scripts/requirements.txt +24 -0
- package/.github/skills/media-processing/scripts/video_optimize.py +414 -0
- package/.github/skills/payment-integration/README.md +185 -0
- package/.github/skills/payment-integration/scripts/.env.example +20 -0
- package/.github/skills/payment-integration/scripts/checkout-helper.js +244 -0
- package/.github/skills/payment-integration/scripts/package.json +17 -0
- package/.github/skills/payment-integration/scripts/polar-webhook-verify.js +202 -0
- package/.github/skills/payment-integration/scripts/sepay-webhook-verify.js +193 -0
- package/.github/skills/payment-integration/scripts/test-scripts.js +237 -0
- package/.github/skills/plans-kanban/assets/dashboard-template.html +119 -0
- package/.github/skills/plans-kanban/assets/dashboard.css +1594 -0
- package/.github/skills/plans-kanban/assets/dashboard.js +596 -0
- package/.github/skills/plans-kanban/assets/favicon.png +0 -0
- package/.github/skills/plans-kanban/package-lock.json +123 -0
- package/.github/skills/plans-kanban/package.json +13 -0
- package/.github/skills/plans-kanban/scripts/lib/dashboard-renderer.cjs +884 -0
- package/.github/skills/plans-kanban/scripts/lib/http-server.cjs +310 -0
- package/.github/skills/plans-kanban/scripts/lib/plan-metadata-extractor.cjs +489 -0
- package/.github/skills/plans-kanban/scripts/lib/plan-parser.cjs +175 -0
- package/.github/skills/plans-kanban/scripts/lib/plan-scanner.cjs +272 -0
- package/.github/skills/plans-kanban/scripts/lib/port-finder.cjs +48 -0
- package/.github/skills/plans-kanban/scripts/lib/process-mgr.cjs +128 -0
- package/.github/skills/plans-kanban/scripts/server.cjs +260 -0
- package/.github/skills/repomix/scripts/.coverage +0 -0
- package/.github/skills/repomix/scripts/README.md +179 -0
- package/.github/skills/repomix/scripts/repomix_batch.py +455 -0
- package/.github/skills/repomix/scripts/repos.example.json +15 -0
- package/.github/skills/repomix/scripts/requirements.txt +15 -0
- package/.github/skills/scout-validation/scripts/lib/broad-pattern-detector.cjs +124 -0
- package/.github/skills/scout-validation/scripts/lib/path-checker.cjs +66 -0
- package/.github/skills/scout-validation/scripts/lib/schema-validator.cjs +45 -0
- package/.github/skills/scout-validation/scripts/package.json +11 -0
- package/.github/skills/scout-validation/scripts/validate-scout-output.cjs +219 -0
- package/.github/skills/scout-validation/test/broad-pattern-output.json +18 -0
- package/.github/skills/scout-validation/test/invalid-path-output.json +18 -0
- package/.github/skills/scout-validation/test/valid-scout-output.json +26 -0
- package/.github/skills/sequential-thinking/.env.example +8 -0
- package/.github/skills/sequential-thinking/README.md +183 -0
- package/.github/skills/sequential-thinking/package.json +31 -0
- package/.github/skills/sequential-thinking/scripts/format-thought.js +159 -0
- package/.github/skills/sequential-thinking/scripts/process-thought.js +236 -0
- package/.github/skills/shopify/README.md +66 -0
- package/.github/skills/shopify/scripts/.coverage +0 -0
- package/.github/skills/shopify/scripts/requirements.txt +19 -0
- package/.github/skills/shopify/scripts/shopify_init.py +423 -0
- package/.github/skills/skill-creator/LICENSE.txt +202 -0
- package/.github/skills/skill-creator/scripts/init_skill.py +303 -0
- package/.github/skills/skill-creator/scripts/package_skill.py +110 -0
- package/.github/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/.github/skills/ui-styling/LICENSE.txt +202 -0
- package/.github/skills/ui-styling/canvas-fonts/ArsenalSC-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/BigShoulders-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/Boldonse-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/CrimsonPro-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/DMMono-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/EricaOne-OFL.txt +94 -0
- package/.github/skills/ui-styling/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/GeistMono-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/Gloock-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/InstrumentSans-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/Italiana-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/Jura-Light.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/Jura-Medium.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/Jura-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/Lora-Bold.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/Lora-Italic.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/Lora-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/Lora-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/NationalPark-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/Outfit-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/PixelifySans-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/PoiretOne-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/RedHatMono-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/Silkscreen-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/SmoochSans-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/Tektur-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/WorkSans-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/.github/skills/ui-styling/canvas-fonts/YoungSerif-OFL.txt +93 -0
- package/.github/skills/ui-styling/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- package/.github/skills/ui-styling/scripts/.coverage +0 -0
- package/.github/skills/ui-styling/scripts/requirements.txt +17 -0
- package/.github/skills/ui-styling/scripts/shadcn_add.py +292 -0
- package/.github/skills/ui-styling/scripts/tailwind_config_gen.py +456 -0
- package/.github/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/.github/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/.github/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/.github/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/.github/skills/ui-ux-pro-max/data/prompts.csv +24 -0
- package/.github/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.github/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +51 -0
- package/.github/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.github/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.github/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.github/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.github/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.github/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.github/skills/ui-ux-pro-max/data/styles.csv +59 -0
- package/.github/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/.github/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.github/skills/ui-ux-pro-max/scripts/core.py +236 -0
- package/.github/skills/ui-ux-pro-max/scripts/search.py +76 -0
- package/.github/skills/web-frameworks/scripts/.coverage +0 -0
- package/.github/skills/web-frameworks/scripts/__init__.py +0 -0
- package/.github/skills/web-frameworks/scripts/nextjs_init.py +547 -0
- package/.github/skills/web-frameworks/scripts/requirements.txt +16 -0
- package/.github/skills/web-frameworks/scripts/turborepo_migrate.py +394 -0
- package/dist/config/constants.d.ts +2 -0
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/config/constants.js +4 -1
- package/dist/config/constants.js.map +1 -1
- package/dist/domains/github/github-client.d.ts +5 -0
- package/dist/domains/github/github-client.d.ts.map +1 -1
- package/dist/domains/github/github-client.js +44 -0
- package/dist/domains/github/github-client.js.map +1 -1
- package/dist/utils/downloader.d.ts +3 -1
- package/dist/utils/downloader.d.ts.map +1 -1
- package/dist/utils/downloader.js +48 -11
- package/dist/utils/downloader.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared browser utilities for Chrome DevTools scripts
|
|
3
|
+
* Supports persistent browser sessions via WebSocket endpoint file
|
|
4
|
+
*/
|
|
5
|
+
import puppeteer from 'puppeteer';
|
|
6
|
+
import debug from 'debug';
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
|
|
11
|
+
const log = debug('chrome-devtools:browser');
|
|
12
|
+
|
|
13
|
+
// Session file stores WebSocket endpoint for browser reuse across processes
|
|
14
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const SESSION_FILE = path.join(__dirname, '..', '.browser-session.json');
|
|
16
|
+
const AUTH_SESSION_FILE = path.join(__dirname, '..', '.auth-session.json');
|
|
17
|
+
|
|
18
|
+
let browserInstance = null;
|
|
19
|
+
let pageInstance = null;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Read session info from file
|
|
23
|
+
*/
|
|
24
|
+
function readSession() {
|
|
25
|
+
try {
|
|
26
|
+
if (fs.existsSync(SESSION_FILE)) {
|
|
27
|
+
const data = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf8'));
|
|
28
|
+
// Check if session is not too old (max 1 hour)
|
|
29
|
+
if (Date.now() - data.timestamp < 3600000) {
|
|
30
|
+
return data;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
} catch (e) {
|
|
34
|
+
log('Failed to read session:', e.message);
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Write session info to file
|
|
41
|
+
*/
|
|
42
|
+
function writeSession(wsEndpoint) {
|
|
43
|
+
try {
|
|
44
|
+
fs.writeFileSync(SESSION_FILE, JSON.stringify({
|
|
45
|
+
wsEndpoint,
|
|
46
|
+
timestamp: Date.now()
|
|
47
|
+
}));
|
|
48
|
+
} catch (e) {
|
|
49
|
+
log('Failed to write session:', e.message);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Clear session file
|
|
55
|
+
*/
|
|
56
|
+
function clearSession() {
|
|
57
|
+
try {
|
|
58
|
+
if (fs.existsSync(SESSION_FILE)) {
|
|
59
|
+
fs.unlinkSync(SESSION_FILE);
|
|
60
|
+
}
|
|
61
|
+
} catch (e) {
|
|
62
|
+
log('Failed to clear session:', e.message);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Save auth session (cookies, storage) for persistence
|
|
68
|
+
* @param {Object} authData - Auth data to save
|
|
69
|
+
*/
|
|
70
|
+
export function saveAuthSession(authData) {
|
|
71
|
+
try {
|
|
72
|
+
const existing = readAuthSession() || {};
|
|
73
|
+
const merged = { ...existing, ...authData, timestamp: Date.now() };
|
|
74
|
+
fs.writeFileSync(AUTH_SESSION_FILE, JSON.stringify(merged, null, 2));
|
|
75
|
+
log('Auth session saved');
|
|
76
|
+
} catch (e) {
|
|
77
|
+
log('Failed to save auth session:', e.message);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Read auth session from file
|
|
83
|
+
* @returns {Object|null} - Auth session data or null
|
|
84
|
+
*/
|
|
85
|
+
export function readAuthSession() {
|
|
86
|
+
try {
|
|
87
|
+
if (fs.existsSync(AUTH_SESSION_FILE)) {
|
|
88
|
+
const data = JSON.parse(fs.readFileSync(AUTH_SESSION_FILE, 'utf8'));
|
|
89
|
+
// Auth sessions valid for 24 hours
|
|
90
|
+
if (Date.now() - data.timestamp < 86400000) {
|
|
91
|
+
return data;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
} catch (e) {
|
|
95
|
+
log('Failed to read auth session:', e.message);
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Clear auth session file
|
|
102
|
+
*/
|
|
103
|
+
export function clearAuthSession() {
|
|
104
|
+
try {
|
|
105
|
+
if (fs.existsSync(AUTH_SESSION_FILE)) {
|
|
106
|
+
fs.unlinkSync(AUTH_SESSION_FILE);
|
|
107
|
+
log('Auth session cleared');
|
|
108
|
+
}
|
|
109
|
+
} catch (e) {
|
|
110
|
+
log('Failed to clear auth session:', e.message);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Apply saved auth session to page
|
|
116
|
+
* @param {Object} page - Puppeteer page instance
|
|
117
|
+
* @param {string} url - Target URL for domain context
|
|
118
|
+
*/
|
|
119
|
+
export async function applyAuthSession(page, url) {
|
|
120
|
+
const authData = readAuthSession();
|
|
121
|
+
if (!authData) {
|
|
122
|
+
log('No auth session found');
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
// Apply cookies
|
|
128
|
+
if (authData.cookies && authData.cookies.length > 0) {
|
|
129
|
+
await page.setCookie(...authData.cookies);
|
|
130
|
+
log(`Applied ${authData.cookies.length} cookies`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Apply localStorage (requires navigation first)
|
|
134
|
+
if (authData.localStorage && Object.keys(authData.localStorage).length > 0) {
|
|
135
|
+
await page.evaluate((data) => {
|
|
136
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
137
|
+
localStorage.setItem(key, typeof value === 'string' ? value : JSON.stringify(value));
|
|
138
|
+
});
|
|
139
|
+
}, authData.localStorage);
|
|
140
|
+
log('Applied localStorage data');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Apply sessionStorage
|
|
144
|
+
if (authData.sessionStorage && Object.keys(authData.sessionStorage).length > 0) {
|
|
145
|
+
await page.evaluate((data) => {
|
|
146
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
147
|
+
sessionStorage.setItem(key, typeof value === 'string' ? value : JSON.stringify(value));
|
|
148
|
+
});
|
|
149
|
+
}, authData.sessionStorage);
|
|
150
|
+
log('Applied sessionStorage data');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Apply extra headers
|
|
154
|
+
if (authData.headers) {
|
|
155
|
+
await page.setExtraHTTPHeaders(authData.headers);
|
|
156
|
+
log('Applied HTTP headers');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return true;
|
|
160
|
+
} catch (e) {
|
|
161
|
+
log('Failed to apply auth session:', e.message);
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Launch or connect to browser
|
|
168
|
+
* If a session file exists with valid wsEndpoint, connects to existing browser
|
|
169
|
+
* Otherwise launches new browser and saves wsEndpoint for future connections
|
|
170
|
+
*/
|
|
171
|
+
export async function getBrowser(options = {}) {
|
|
172
|
+
// If we already have a connected browser in this process, reuse it
|
|
173
|
+
if (browserInstance && browserInstance.isConnected()) {
|
|
174
|
+
log('Reusing existing browser instance from process');
|
|
175
|
+
return browserInstance;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Try to connect to existing browser from session file
|
|
179
|
+
const session = readSession();
|
|
180
|
+
if (session && session.wsEndpoint) {
|
|
181
|
+
try {
|
|
182
|
+
log('Attempting to connect to existing browser session');
|
|
183
|
+
browserInstance = await puppeteer.connect({
|
|
184
|
+
browserWSEndpoint: session.wsEndpoint
|
|
185
|
+
});
|
|
186
|
+
log('Connected to existing browser');
|
|
187
|
+
return browserInstance;
|
|
188
|
+
} catch (e) {
|
|
189
|
+
log('Failed to connect to existing browser:', e.message);
|
|
190
|
+
clearSession();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Connect via provided wsEndpoint or browserUrl
|
|
195
|
+
if (options.wsEndpoint || options.browserUrl) {
|
|
196
|
+
log('Connecting to browser via provided endpoint');
|
|
197
|
+
browserInstance = await puppeteer.connect({
|
|
198
|
+
browserWSEndpoint: options.wsEndpoint,
|
|
199
|
+
browserURL: options.browserUrl
|
|
200
|
+
});
|
|
201
|
+
return browserInstance;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Launch new browser
|
|
205
|
+
const launchOptions = {
|
|
206
|
+
headless: options.headless !== false,
|
|
207
|
+
args: [
|
|
208
|
+
'--no-sandbox',
|
|
209
|
+
'--disable-setuid-sandbox',
|
|
210
|
+
'--disable-dev-shm-usage',
|
|
211
|
+
...(options.args || [])
|
|
212
|
+
],
|
|
213
|
+
defaultViewport: options.viewport || {
|
|
214
|
+
width: 1920,
|
|
215
|
+
height: 1080
|
|
216
|
+
},
|
|
217
|
+
...options
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
log('Launching new browser');
|
|
221
|
+
browserInstance = await puppeteer.launch(launchOptions);
|
|
222
|
+
|
|
223
|
+
// Save wsEndpoint for future connections
|
|
224
|
+
const wsEndpoint = browserInstance.wsEndpoint();
|
|
225
|
+
writeSession(wsEndpoint);
|
|
226
|
+
log('Browser launched, session saved');
|
|
227
|
+
|
|
228
|
+
return browserInstance;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Get current page or create new one
|
|
233
|
+
*/
|
|
234
|
+
export async function getPage(browser) {
|
|
235
|
+
if (pageInstance && !pageInstance.isClosed()) {
|
|
236
|
+
log('Reusing existing page');
|
|
237
|
+
return pageInstance;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const pages = await browser.pages();
|
|
241
|
+
if (pages.length > 0) {
|
|
242
|
+
pageInstance = pages[0];
|
|
243
|
+
} else {
|
|
244
|
+
pageInstance = await browser.newPage();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return pageInstance;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Close browser and clear session
|
|
252
|
+
*/
|
|
253
|
+
export async function closeBrowser() {
|
|
254
|
+
if (browserInstance) {
|
|
255
|
+
await browserInstance.close();
|
|
256
|
+
browserInstance = null;
|
|
257
|
+
pageInstance = null;
|
|
258
|
+
clearSession();
|
|
259
|
+
log('Browser closed, session cleared');
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Disconnect from browser without closing it
|
|
265
|
+
* Use this to keep browser running for future script executions
|
|
266
|
+
*/
|
|
267
|
+
export async function disconnectBrowser() {
|
|
268
|
+
if (browserInstance) {
|
|
269
|
+
browserInstance.disconnect();
|
|
270
|
+
browserInstance = null;
|
|
271
|
+
pageInstance = null;
|
|
272
|
+
log('Disconnected from browser (browser still running)');
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Parse command line arguments
|
|
278
|
+
*/
|
|
279
|
+
export function parseArgs(argv, options = {}) {
|
|
280
|
+
const args = {};
|
|
281
|
+
|
|
282
|
+
for (let i = 0; i < argv.length; i++) {
|
|
283
|
+
const arg = argv[i];
|
|
284
|
+
|
|
285
|
+
if (arg.startsWith('--')) {
|
|
286
|
+
const key = arg.slice(2);
|
|
287
|
+
const nextArg = argv[i + 1];
|
|
288
|
+
|
|
289
|
+
if (nextArg && !nextArg.startsWith('--')) {
|
|
290
|
+
args[key] = nextArg;
|
|
291
|
+
i++;
|
|
292
|
+
} else {
|
|
293
|
+
args[key] = true;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return args;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Output JSON result
|
|
303
|
+
*/
|
|
304
|
+
export function outputJSON(data) {
|
|
305
|
+
console.log(JSON.stringify(data, null, 2));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Output error
|
|
310
|
+
*/
|
|
311
|
+
export function outputError(error) {
|
|
312
|
+
console.error(JSON.stringify({
|
|
313
|
+
success: false,
|
|
314
|
+
error: error.message,
|
|
315
|
+
stack: error.stack
|
|
316
|
+
}, null, 2));
|
|
317
|
+
process.exit(1);
|
|
318
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared selector parsing and validation library
|
|
3
|
+
* Supports CSS and XPath selectors with security validation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Parse and validate selector
|
|
8
|
+
* @param {string} selector - CSS or XPath selector
|
|
9
|
+
* @returns {{type: 'css'|'xpath', selector: string}}
|
|
10
|
+
* @throws {Error} If XPath contains injection patterns
|
|
11
|
+
*/
|
|
12
|
+
export function parseSelector(selector) {
|
|
13
|
+
if (!selector || typeof selector !== 'string') {
|
|
14
|
+
throw new Error('Selector must be a non-empty string');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Detect XPath selectors
|
|
18
|
+
if (selector.startsWith('/') || selector.startsWith('(//')) {
|
|
19
|
+
// XPath injection prevention
|
|
20
|
+
validateXPath(selector);
|
|
21
|
+
return { type: 'xpath', selector };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// CSS selector
|
|
25
|
+
return { type: 'css', selector };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Validate XPath selector for security
|
|
30
|
+
* @param {string} xpath - XPath expression to validate
|
|
31
|
+
* @throws {Error} If XPath contains dangerous patterns
|
|
32
|
+
*/
|
|
33
|
+
function validateXPath(xpath) {
|
|
34
|
+
const dangerous = [
|
|
35
|
+
'javascript:',
|
|
36
|
+
'<script',
|
|
37
|
+
'onerror=',
|
|
38
|
+
'onload=',
|
|
39
|
+
'onclick=',
|
|
40
|
+
'onmouseover=',
|
|
41
|
+
'eval(',
|
|
42
|
+
'Function(',
|
|
43
|
+
'constructor(',
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const lower = xpath.toLowerCase();
|
|
47
|
+
for (const pattern of dangerous) {
|
|
48
|
+
if (lower.includes(pattern.toLowerCase())) {
|
|
49
|
+
throw new Error(`Potential XPath injection detected: ${pattern}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Additional validation: check for extremely long selectors (potential DoS)
|
|
54
|
+
if (xpath.length > 1000) {
|
|
55
|
+
throw new Error('XPath selector too long (max 1000 characters)');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Wait for element based on selector type
|
|
61
|
+
* @param {Object} page - Puppeteer page instance
|
|
62
|
+
* @param {{type: string, selector: string}} parsed - Parsed selector
|
|
63
|
+
* @param {Object} options - Wait options (visible, timeout)
|
|
64
|
+
* @returns {Promise<void>}
|
|
65
|
+
*/
|
|
66
|
+
export async function waitForElement(page, parsed, options = {}) {
|
|
67
|
+
const defaultOptions = {
|
|
68
|
+
visible: true,
|
|
69
|
+
timeout: 5000,
|
|
70
|
+
...options
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
if (parsed.type === 'xpath') {
|
|
74
|
+
// Use locator API for XPath (Puppeteer v24+)
|
|
75
|
+
const locator = page.locator(`::-p-xpath(${parsed.selector})`);
|
|
76
|
+
// setVisibility and setTimeout are the locator options
|
|
77
|
+
await locator
|
|
78
|
+
.setVisibility(defaultOptions.visible ? 'visible' : null)
|
|
79
|
+
.setTimeout(defaultOptions.timeout)
|
|
80
|
+
.wait();
|
|
81
|
+
} else {
|
|
82
|
+
await page.waitForSelector(parsed.selector, defaultOptions);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Click element based on selector type
|
|
88
|
+
* @param {Object} page - Puppeteer page instance
|
|
89
|
+
* @param {{type: string, selector: string}} parsed - Parsed selector
|
|
90
|
+
* @returns {Promise<void>}
|
|
91
|
+
*/
|
|
92
|
+
export async function clickElement(page, parsed) {
|
|
93
|
+
if (parsed.type === 'xpath') {
|
|
94
|
+
// Use locator API for XPath (Puppeteer v24+)
|
|
95
|
+
const locator = page.locator(`::-p-xpath(${parsed.selector})`);
|
|
96
|
+
await locator.click();
|
|
97
|
+
} else {
|
|
98
|
+
await page.click(parsed.selector);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Type into element based on selector type
|
|
104
|
+
* @param {Object} page - Puppeteer page instance
|
|
105
|
+
* @param {{type: string, selector: string}} parsed - Parsed selector
|
|
106
|
+
* @param {string} value - Text to type
|
|
107
|
+
* @param {Object} options - Type options (delay, clear)
|
|
108
|
+
* @returns {Promise<void>}
|
|
109
|
+
*/
|
|
110
|
+
export async function typeIntoElement(page, parsed, value, options = {}) {
|
|
111
|
+
if (parsed.type === 'xpath') {
|
|
112
|
+
// Use locator API for XPath (Puppeteer v24+)
|
|
113
|
+
const locator = page.locator(`::-p-xpath(${parsed.selector})`);
|
|
114
|
+
|
|
115
|
+
// Clear if requested
|
|
116
|
+
if (options.clear) {
|
|
117
|
+
await locator.fill('');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
await locator.fill(value);
|
|
121
|
+
} else {
|
|
122
|
+
// CSS selector
|
|
123
|
+
if (options.clear) {
|
|
124
|
+
await page.$eval(parsed.selector, el => el.value = '');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
await page.type(parsed.selector, value, { delay: options.delay || 0 });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get element handle based on selector type
|
|
133
|
+
* @param {Object} page - Puppeteer page instance
|
|
134
|
+
* @param {{type: string, selector: string}} parsed - Parsed selector
|
|
135
|
+
* @returns {Promise<ElementHandle|null>}
|
|
136
|
+
*/
|
|
137
|
+
export async function getElement(page, parsed) {
|
|
138
|
+
if (parsed.type === 'xpath') {
|
|
139
|
+
// For XPath, use page.evaluate with XPath evaluation
|
|
140
|
+
// This returns the first matching element
|
|
141
|
+
const element = await page.evaluateHandle((xpath) => {
|
|
142
|
+
const result = document.evaluate(
|
|
143
|
+
xpath,
|
|
144
|
+
document,
|
|
145
|
+
null,
|
|
146
|
+
XPathResult.FIRST_ORDERED_NODE_TYPE,
|
|
147
|
+
null
|
|
148
|
+
);
|
|
149
|
+
return result.singleNodeValue;
|
|
150
|
+
}, parsed.selector);
|
|
151
|
+
|
|
152
|
+
// Convert JSHandle to ElementHandle
|
|
153
|
+
const elementHandle = element.asElement();
|
|
154
|
+
return elementHandle;
|
|
155
|
+
} else {
|
|
156
|
+
return await page.$(parsed.selector);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get enhanced error message for selector failures
|
|
162
|
+
* @param {Error} error - Original error
|
|
163
|
+
* @param {string} selector - Selector that failed
|
|
164
|
+
* @returns {Error} Enhanced error with troubleshooting tips
|
|
165
|
+
*/
|
|
166
|
+
export function enhanceError(error, selector) {
|
|
167
|
+
if (error.message.includes('waiting for selector') ||
|
|
168
|
+
error.message.includes('waiting for XPath') ||
|
|
169
|
+
error.message.includes('No node found')) {
|
|
170
|
+
error.message += '\n\nTroubleshooting:\n' +
|
|
171
|
+
'1. Use snapshot.js to find correct selector: node snapshot.js --url <url>\n' +
|
|
172
|
+
'2. Try XPath selector: //button[text()="Click"] or //button[contains(text(),"Click")]\n' +
|
|
173
|
+
'3. Check element is visible on page (not display:none or hidden)\n' +
|
|
174
|
+
'4. Increase --timeout value: --timeout 10000\n' +
|
|
175
|
+
'5. Change wait strategy: --wait-until load or --wait-until domcontentloaded';
|
|
176
|
+
}
|
|
177
|
+
return error;
|
|
178
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Navigate to a URL
|
|
4
|
+
* Usage: node navigate.js --url https://example.com [--wait-until networkidle2] [--timeout 30000]
|
|
5
|
+
*
|
|
6
|
+
* Session behavior:
|
|
7
|
+
* --close false : Keep browser running, disconnect from it (default for chaining)
|
|
8
|
+
* --close true : Close browser completely and clear session
|
|
9
|
+
*/
|
|
10
|
+
import { getBrowser, getPage, closeBrowser, disconnectBrowser, parseArgs, outputJSON, outputError } from './lib/browser.js';
|
|
11
|
+
|
|
12
|
+
async function navigate() {
|
|
13
|
+
const args = parseArgs(process.argv.slice(2));
|
|
14
|
+
|
|
15
|
+
if (!args.url) {
|
|
16
|
+
outputError(new Error('--url is required'));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const browser = await getBrowser({
|
|
22
|
+
headless: args.headless !== 'false'
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const page = await getPage(browser);
|
|
26
|
+
|
|
27
|
+
const options = {
|
|
28
|
+
waitUntil: args['wait-until'] || 'networkidle2',
|
|
29
|
+
timeout: parseInt(args.timeout || '30000')
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
await page.goto(args.url, options);
|
|
33
|
+
|
|
34
|
+
const result = {
|
|
35
|
+
success: true,
|
|
36
|
+
url: page.url(),
|
|
37
|
+
title: await page.title()
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
outputJSON(result);
|
|
41
|
+
|
|
42
|
+
// Default: disconnect to keep browser running for session persistence
|
|
43
|
+
// Use --close true to fully close browser
|
|
44
|
+
if (args.close === 'true') {
|
|
45
|
+
await closeBrowser();
|
|
46
|
+
} else {
|
|
47
|
+
await disconnectBrowser();
|
|
48
|
+
}
|
|
49
|
+
} catch (error) {
|
|
50
|
+
outputError(error);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
navigate();
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Monitor network requests
|
|
4
|
+
* Usage: node network.js --url https://example.com [--types xhr,fetch] [--output requests.json]
|
|
5
|
+
*/
|
|
6
|
+
import { getBrowser, getPage, closeBrowser, disconnectBrowser, parseArgs, outputJSON, outputError } from './lib/browser.js';
|
|
7
|
+
import fs from 'fs/promises';
|
|
8
|
+
|
|
9
|
+
async function monitorNetwork() {
|
|
10
|
+
const args = parseArgs(process.argv.slice(2));
|
|
11
|
+
|
|
12
|
+
if (!args.url) {
|
|
13
|
+
outputError(new Error('--url is required'));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const browser = await getBrowser({
|
|
19
|
+
headless: args.headless !== 'false'
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const page = await getPage(browser);
|
|
23
|
+
|
|
24
|
+
const requests = [];
|
|
25
|
+
const filterTypes = args.types ? args.types.split(',').map(t => t.toLowerCase()) : null;
|
|
26
|
+
|
|
27
|
+
// Monitor requests
|
|
28
|
+
page.on('request', (request) => {
|
|
29
|
+
const resourceType = request.resourceType().toLowerCase();
|
|
30
|
+
|
|
31
|
+
if (!filterTypes || filterTypes.includes(resourceType)) {
|
|
32
|
+
requests.push({
|
|
33
|
+
id: request._requestId || requests.length,
|
|
34
|
+
url: request.url(),
|
|
35
|
+
method: request.method(),
|
|
36
|
+
resourceType: resourceType,
|
|
37
|
+
headers: request.headers(),
|
|
38
|
+
postData: request.postData(),
|
|
39
|
+
timestamp: Date.now()
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Monitor responses
|
|
45
|
+
const responses = new Map();
|
|
46
|
+
page.on('response', async (response) => {
|
|
47
|
+
const request = response.request();
|
|
48
|
+
const resourceType = request.resourceType().toLowerCase();
|
|
49
|
+
|
|
50
|
+
if (!filterTypes || filterTypes.includes(resourceType)) {
|
|
51
|
+
try {
|
|
52
|
+
responses.set(request._requestId || request.url(), {
|
|
53
|
+
status: response.status(),
|
|
54
|
+
statusText: response.statusText(),
|
|
55
|
+
headers: response.headers(),
|
|
56
|
+
fromCache: response.fromCache(),
|
|
57
|
+
timing: response.timing()
|
|
58
|
+
});
|
|
59
|
+
} catch (e) {
|
|
60
|
+
// Ignore errors for some response types
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Navigate
|
|
66
|
+
await page.goto(args.url, {
|
|
67
|
+
waitUntil: args['wait-until'] || 'networkidle2'
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Merge requests with responses
|
|
71
|
+
const combined = requests.map(req => ({
|
|
72
|
+
...req,
|
|
73
|
+
response: responses.get(req.id) || responses.get(req.url) || null
|
|
74
|
+
}));
|
|
75
|
+
|
|
76
|
+
const result = {
|
|
77
|
+
success: true,
|
|
78
|
+
url: page.url(),
|
|
79
|
+
requestCount: combined.length,
|
|
80
|
+
requests: combined
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
if (args.output) {
|
|
84
|
+
await fs.writeFile(args.output, JSON.stringify(result, null, 2));
|
|
85
|
+
outputJSON({
|
|
86
|
+
success: true,
|
|
87
|
+
output: args.output,
|
|
88
|
+
requestCount: combined.length
|
|
89
|
+
});
|
|
90
|
+
} else {
|
|
91
|
+
outputJSON(result);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Default: disconnect to keep browser running for session persistence
|
|
95
|
+
// Use --close true to fully close browser
|
|
96
|
+
if (args.close === 'true') {
|
|
97
|
+
await closeBrowser();
|
|
98
|
+
} else {
|
|
99
|
+
await disconnectBrowser();
|
|
100
|
+
}
|
|
101
|
+
} catch (error) {
|
|
102
|
+
outputError(error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
monitorNetwork();
|