xtrm-tools 0.7.3 → 0.7.7
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/.xtrm/config/hooks.json +3 -0
- package/.xtrm/config/pi/extensions/xtrm-ui/format.ts +189 -0
- package/.xtrm/config/pi/extensions/xtrm-ui/index.ts +76 -17
- package/.xtrm/config/pi/extensions/xtrm-ui/package.json +16 -5
- package/.xtrm/ext-src/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.combined.log +7 -0
- package/.xtrm/ext-src/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.stderr.log +0 -0
- package/.xtrm/ext-src/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.stdout.log +7 -0
- package/.xtrm/ext-src/xtrm-ui/format.ts +282 -0
- package/.xtrm/{extensions → ext-src}/xtrm-ui/index.ts +76 -17
- package/.xtrm/ext-src/xtrm-ui/package.json +21 -0
- package/.xtrm/hooks/specialists/specialists-complete.mjs +70 -0
- package/.xtrm/hooks/specialists/specialists-session-start.mjs +105 -0
- package/.xtrm/registry.json +397 -409
- package/.xtrm/skills/default/README.txt +31 -0
- package/.xtrm/skills/default/clean-code/SKILL.md +201 -0
- package/.xtrm/skills/default/creating-service-skills/SKILL.md +433 -0
- package/.xtrm/skills/default/creating-service-skills/references/script_quality_standards.md +425 -0
- package/.xtrm/skills/default/creating-service-skills/references/service_skill_system_guide.md +278 -0
- package/.xtrm/skills/default/creating-service-skills/scripts/bootstrap.py +326 -0
- package/.xtrm/skills/default/creating-service-skills/scripts/deep_dive.py +304 -0
- package/.xtrm/skills/default/creating-service-skills/scripts/scaffolder.py +482 -0
- package/.xtrm/skills/default/deepwiki/SKILL.md +50 -0
- package/.xtrm/skills/default/delegating/SKILL.md +196 -0
- package/.xtrm/skills/default/delegating/config.yaml +210 -0
- package/.xtrm/skills/default/delegating/references/orchestration-protocols.md +41 -0
- package/.xtrm/skills/default/documenting/CHANGELOG.md +23 -0
- package/.xtrm/skills/default/documenting/README.md +148 -0
- package/.xtrm/skills/default/documenting/SKILL.md +113 -0
- package/.xtrm/skills/default/documenting/examples/example_pattern.md +70 -0
- package/.xtrm/skills/default/documenting/examples/example_reference.md +70 -0
- package/.xtrm/skills/default/documenting/examples/example_ssot_analytics.md +64 -0
- package/.xtrm/skills/default/documenting/examples/example_workflow.md +141 -0
- package/.xtrm/skills/default/documenting/references/changelog-format.md +97 -0
- package/.xtrm/skills/default/documenting/references/metadata-schema.md +136 -0
- package/.xtrm/skills/default/documenting/references/taxonomy.md +81 -0
- package/.xtrm/skills/default/documenting/references/versioning-rules.md +78 -0
- package/.xtrm/skills/default/documenting/scripts/bump_version.sh +60 -0
- package/.xtrm/skills/default/documenting/scripts/changelog/__init__.py +0 -0
- package/.xtrm/skills/default/documenting/scripts/changelog/add_entry.py +216 -0
- package/.xtrm/skills/default/documenting/scripts/changelog/bump_release.py +117 -0
- package/.xtrm/skills/default/documenting/scripts/changelog/init_changelog.py +54 -0
- package/.xtrm/skills/default/documenting/scripts/changelog/validate_changelog.py +128 -0
- package/.xtrm/skills/default/documenting/scripts/drift_detector.py +266 -0
- package/.xtrm/skills/default/documenting/scripts/generate_template.py +311 -0
- package/.xtrm/skills/default/documenting/scripts/list_by_category.sh +84 -0
- package/.xtrm/skills/default/documenting/scripts/orchestrator.py +255 -0
- package/.xtrm/skills/default/documenting/scripts/validate_metadata.py +242 -0
- package/.xtrm/skills/default/documenting/templates/CHANGELOG.md.template +13 -0
- package/.xtrm/skills/default/find-docs/SKILL.md +175 -0
- package/.xtrm/skills/default/find-skills/SKILL.md +133 -0
- package/.xtrm/skills/default/github-search/SKILL.md +49 -0
- package/.xtrm/skills/default/gitnexus-debugging/SKILL.md +89 -0
- package/.xtrm/skills/default/gitnexus-impact-analysis/SKILL.md +97 -0
- package/.xtrm/skills/default/gitnexus-pr-review/SKILL.md +163 -0
- package/.xtrm/skills/default/gitnexus-refactoring/SKILL.md +121 -0
- package/.xtrm/skills/default/hook-development/SKILL.md +797 -0
- package/.xtrm/skills/default/hook-development/examples/load-context.sh +55 -0
- package/.xtrm/skills/default/hook-development/examples/quality-check.js +1168 -0
- package/.xtrm/skills/default/hook-development/examples/validate-bash.sh +43 -0
- package/.xtrm/skills/default/hook-development/examples/validate-write.sh +38 -0
- package/.xtrm/skills/default/hook-development/references/advanced.md +527 -0
- package/.xtrm/skills/default/hook-development/references/migration.md +369 -0
- package/.xtrm/skills/default/hook-development/references/patterns.md +412 -0
- package/.xtrm/skills/default/hook-development/scripts/README.md +164 -0
- package/.xtrm/skills/default/hook-development/scripts/hook-linter.sh +153 -0
- package/.xtrm/skills/default/hook-development/scripts/test-hook.sh +252 -0
- package/.xtrm/skills/default/hook-development/scripts/validate-hook-schema.sh +159 -0
- package/.xtrm/skills/default/init-session/SKILL.md +69 -0
- package/.xtrm/skills/default/last30days/SKILL.md +881 -0
- package/.xtrm/skills/default/last30days/scripts/briefing.py +260 -0
- package/.xtrm/skills/default/last30days/scripts/evaluate-synthesis.py +120 -0
- package/.xtrm/skills/default/last30days/scripts/evaluate_search_quality.py +641 -0
- package/.xtrm/skills/default/last30days/scripts/generate-synthesis-inputs.py +53 -0
- package/.xtrm/skills/default/last30days/scripts/last30days.py +2137 -0
- package/.xtrm/skills/default/last30days/scripts/lib/__init__.py +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/bird_x.py +458 -0
- package/.xtrm/skills/default/last30days/scripts/lib/bluesky.py +225 -0
- package/.xtrm/skills/default/last30days/scripts/lib/brave_search.py +329 -0
- package/.xtrm/skills/default/last30days/scripts/lib/cache.py +165 -0
- package/.xtrm/skills/default/last30days/scripts/lib/chrome_cookies.py +265 -0
- package/.xtrm/skills/default/last30days/scripts/lib/cookie_extract.py +295 -0
- package/.xtrm/skills/default/last30days/scripts/lib/dates.py +124 -0
- package/.xtrm/skills/default/last30days/scripts/lib/dedupe.py +290 -0
- package/.xtrm/skills/default/last30days/scripts/lib/entity_extract.py +127 -0
- package/.xtrm/skills/default/last30days/scripts/lib/env.py +807 -0
- package/.xtrm/skills/default/last30days/scripts/lib/exa_search.py +176 -0
- package/.xtrm/skills/default/last30days/scripts/lib/hackernews.py +266 -0
- package/.xtrm/skills/default/last30days/scripts/lib/http.py +174 -0
- package/.xtrm/skills/default/last30days/scripts/lib/instagram.py +365 -0
- package/.xtrm/skills/default/last30days/scripts/lib/models.py +221 -0
- package/.xtrm/skills/default/last30days/scripts/lib/normalize.py +489 -0
- package/.xtrm/skills/default/last30days/scripts/lib/openai_reddit.py +631 -0
- package/.xtrm/skills/default/last30days/scripts/lib/openrouter_search.py +216 -0
- package/.xtrm/skills/default/last30days/scripts/lib/parallel_search.py +139 -0
- package/.xtrm/skills/default/last30days/scripts/lib/polymarket.py +580 -0
- package/.xtrm/skills/default/last30days/scripts/lib/quality_nudge.py +201 -0
- package/.xtrm/skills/default/last30days/scripts/lib/query.py +117 -0
- package/.xtrm/skills/default/last30days/scripts/lib/query_type.py +111 -0
- package/.xtrm/skills/default/last30days/scripts/lib/reddit.py +617 -0
- package/.xtrm/skills/default/last30days/scripts/lib/reddit_enrich.py +325 -0
- package/.xtrm/skills/default/last30days/scripts/lib/reddit_public.py +259 -0
- package/.xtrm/skills/default/last30days/scripts/lib/relevance.py +148 -0
- package/.xtrm/skills/default/last30days/scripts/lib/render.py +1018 -0
- package/.xtrm/skills/default/last30days/scripts/lib/safari_cookies.py +182 -0
- package/.xtrm/skills/default/last30days/scripts/lib/schema.py +843 -0
- package/.xtrm/skills/default/last30days/scripts/lib/score.py +775 -0
- package/.xtrm/skills/default/last30days/scripts/lib/scrapecreators_x.py +182 -0
- package/.xtrm/skills/default/last30days/scripts/lib/setup_wizard.py +186 -0
- package/.xtrm/skills/default/last30days/scripts/lib/tiktok.py +349 -0
- package/.xtrm/skills/default/last30days/scripts/lib/truthsocial.py +183 -0
- package/.xtrm/skills/default/last30days/scripts/lib/ui.py +620 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/LICENSE +21 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/bird-search.mjs +134 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/lib/cookies.js +191 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/lib/features.json +17 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/lib/paginate-cursor.js +37 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/lib/query-ids.json +20 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/lib/runtime-features.js +151 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/lib/runtime-query-ids.js +264 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-base.js +129 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-constants.js +50 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-features.js +347 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-search.js +157 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-types.js +2 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-utils.js +511 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/LICENSE +22 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/README.md +29 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/index.d.ts +3 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/index.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/index.js +2 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/index.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chrome.d.ts +8 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chrome.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chrome.js +27 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chrome.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/crypto.d.ts +11 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/crypto.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/crypto.js +100 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/crypto.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/linuxKeyring.d.ts +25 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/linuxKeyring.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/linuxKeyring.js +104 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/linuxKeyring.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/shared.d.ts +10 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/shared.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/shared.js +293 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/shared.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/windowsDpapi.d.ts +10 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/windowsDpapi.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/windowsDpapi.js +26 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqlite/windowsDpapi.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqliteLinux.d.ts +7 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqliteLinux.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqliteLinux.js +51 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqliteLinux.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqliteMac.d.ts +7 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqliteMac.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqliteMac.js +60 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqliteMac.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqliteWindows.d.ts +7 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqliteWindows.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqliteWindows.js +38 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromeSqliteWindows.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/linuxPaths.d.ts +5 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/linuxPaths.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/linuxPaths.js +33 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/linuxPaths.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/macosKeychain.d.ts +24 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/macosKeychain.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/macosKeychain.js +30 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/macosKeychain.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/paths.d.ts +11 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/paths.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/paths.js +43 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/paths.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/windowsMasterKey.d.ts +8 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/windowsMasterKey.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/windowsMasterKey.js +41 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/windowsMasterKey.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/windowsPaths.d.ts +8 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/windowsPaths.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/windowsPaths.js +53 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/chromium/windowsPaths.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edge.d.ts +8 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edge.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edge.js +27 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edge.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edgeSqliteLinux.d.ts +7 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edgeSqliteLinux.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edgeSqliteLinux.js +53 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edgeSqliteLinux.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edgeSqliteMac.d.ts +8 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edgeSqliteMac.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edgeSqliteMac.js +60 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edgeSqliteMac.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edgeSqliteWindows.d.ts +7 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edgeSqliteWindows.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edgeSqliteWindows.js +38 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/edgeSqliteWindows.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/firefoxSqlite.d.ts +6 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/firefoxSqlite.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/firefoxSqlite.js +257 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/firefoxSqlite.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/inline.d.ts +8 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/inline.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/inline.js +71 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/inline.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/safariBinaryCookies.d.ts +6 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/safariBinaryCookies.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/safariBinaryCookies.js +173 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/providers/safariBinaryCookies.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/public.d.ts +26 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/public.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/public.js +195 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/public.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/types.d.ts +121 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/types.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/types.js +2 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/types.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/base64.d.ts +2 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/base64.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/base64.js +18 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/base64.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/exec.d.ts +8 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/exec.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/exec.js +110 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/exec.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/expire.d.ts +2 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/expire.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/expire.js +32 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/expire.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/fs.d.ts +2 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/fs.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/fs.js +13 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/fs.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/hostMatch.d.ts +2 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/hostMatch.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/hostMatch.js +7 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/hostMatch.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/nodeSqlite.d.ts +5 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/nodeSqlite.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/nodeSqlite.js +58 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/nodeSqlite.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/origins.d.ts +2 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/origins.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/origins.js +27 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/origins.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/runtime.d.ts +2 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/runtime.d.ts.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/runtime.js +8 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/dist/util/runtime.js.map +1 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/node_modules/@steipete/sweet-cookie/package.json +40 -0
- package/.xtrm/skills/default/last30days/scripts/lib/vendor/bird-search/package.json +13 -0
- package/.xtrm/skills/default/last30days/scripts/lib/websearch.py +401 -0
- package/.xtrm/skills/default/last30days/scripts/lib/xai_x.py +217 -0
- package/.xtrm/skills/default/last30days/scripts/lib/xiaohongshu_api.py +162 -0
- package/.xtrm/skills/default/last30days/scripts/lib/youtube_yt.py +538 -0
- package/.xtrm/skills/default/last30days/scripts/store.py +654 -0
- package/.xtrm/skills/default/last30days/scripts/sync.sh +50 -0
- package/.xtrm/skills/default/last30days/scripts/test-v1-vs-v2.sh +219 -0
- package/.xtrm/skills/default/last30days/scripts/watchlist.py +329 -0
- package/.xtrm/skills/default/planning/SKILL.md +405 -0
- package/.xtrm/skills/default/planning/evals/evals.json +19 -0
- package/.xtrm/skills/default/prompt-improving/README.md +162 -0
- package/.xtrm/skills/default/prompt-improving/SKILL.md +74 -0
- package/.xtrm/skills/default/prompt-improving/references/analysis_commands.md +24 -0
- package/.xtrm/skills/default/prompt-improving/references/chain_of_thought.md +24 -0
- package/.xtrm/skills/default/prompt-improving/references/mcp_definitions.md +20 -0
- package/.xtrm/skills/default/prompt-improving/references/multishot.md +23 -0
- package/.xtrm/skills/default/prompt-improving/references/xml_core.md +60 -0
- package/.xtrm/skills/default/quality-gates/.claude/hooks/hook-config.json +66 -0
- package/.xtrm/skills/default/quality-gates/.claude/hooks/quality-check.cjs +1286 -0
- package/.xtrm/skills/default/quality-gates/.claude/hooks/quality-check.py +334 -0
- package/.xtrm/skills/default/quality-gates/.claude/settings.json +3 -0
- package/.xtrm/skills/default/quality-gates/.claude/skills/using-quality-gates/SKILL.md +254 -0
- package/.xtrm/skills/default/quality-gates/README.md +109 -0
- package/.xtrm/skills/default/quality-gates/evals/evals.json +181 -0
- package/.xtrm/skills/default/quality-gates/workspace/iteration-1/FINAL-EVAL-SUMMARY.md +75 -0
- package/.xtrm/skills/default/quality-gates/workspace/iteration-1/edge-case-auto-fix-verification/with_skill/outputs/response.md +59 -0
- package/.xtrm/skills/default/quality-gates/workspace/iteration-1/edge-case-mixed-language-project/with_skill/outputs/response.md +60 -0
- package/.xtrm/skills/default/quality-gates/workspace/iteration-1/eval-summary.md +105 -0
- package/.xtrm/skills/default/quality-gates/workspace/iteration-1/partial-install-python-only/with_skill/outputs/response.md +93 -0
- package/.xtrm/skills/default/quality-gates/workspace/iteration-1/python-refactor-request/with_skill/outputs/response.md +104 -0
- package/.xtrm/skills/default/quality-gates/workspace/iteration-1/quality-gate-error-fix/with_skill/outputs/response.md +74 -0
- package/.xtrm/skills/default/quality-gates/workspace/iteration-1/should-not-trigger-general-chat/with_skill/outputs/response.md +18 -0
- package/.xtrm/skills/default/quality-gates/workspace/iteration-1/should-not-trigger-math-question/with_skill/outputs/response.md +18 -0
- package/.xtrm/skills/default/quality-gates/workspace/iteration-1/should-not-trigger-unrelated-coding/with_skill/outputs/response.md +56 -0
- package/.xtrm/skills/default/quality-gates/workspace/iteration-1/tdd-guard-blocking-confusion/with_skill/outputs/response.md +67 -0
- package/.xtrm/skills/default/quality-gates/workspace/iteration-1/typescript-feature-with-tests/with_skill/outputs/response.md +97 -0
- package/.xtrm/skills/default/scoping-service-skills/SKILL.md +231 -0
- package/.xtrm/skills/default/scoping-service-skills/scripts/scope.py +74 -0
- package/.xtrm/skills/default/service-skills-set/README.md +93 -0
- package/.xtrm/skills/default/service-skills-set/git-hooks/doc_reminder.py +67 -0
- package/.xtrm/skills/default/service-skills-set/git-hooks/skill_staleness.py +194 -0
- package/.xtrm/skills/default/service-skills-set/install-service-skills.py +193 -0
- package/.xtrm/skills/default/service-skills-set/service-registry.json +4 -0
- package/.xtrm/skills/default/service-skills-set/service-skills-readme.md +236 -0
- package/.xtrm/skills/default/service-skills-set/settings.json +37 -0
- package/.xtrm/skills/default/session-close-report/SKILL.md +131 -0
- package/.xtrm/skills/default/skill-creator/LICENSE.txt +202 -0
- package/.xtrm/skills/default/skill-creator/SKILL.md +479 -0
- package/.xtrm/skills/default/skill-creator/agents/analyzer.md +274 -0
- package/.xtrm/skills/default/skill-creator/agents/comparator.md +202 -0
- package/.xtrm/skills/default/skill-creator/agents/grader.md +223 -0
- package/.xtrm/skills/default/skill-creator/assets/eval_review.html +146 -0
- package/.xtrm/skills/default/skill-creator/eval-viewer/generate_review.py +471 -0
- package/.xtrm/skills/default/skill-creator/eval-viewer/viewer.html +1325 -0
- package/.xtrm/skills/default/skill-creator/references/schemas.md +430 -0
- package/.xtrm/skills/default/skill-creator/scripts/__init__.py +0 -0
- package/.xtrm/skills/default/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/.xtrm/skills/default/skill-creator/scripts/generate_report.py +326 -0
- package/.xtrm/skills/default/skill-creator/scripts/improve_description.py +248 -0
- package/.xtrm/skills/default/skill-creator/scripts/package_skill.py +136 -0
- package/.xtrm/skills/default/skill-creator/scripts/quick_validate.py +103 -0
- package/.xtrm/skills/default/skill-creator/scripts/run_eval.py +310 -0
- package/.xtrm/skills/default/skill-creator/scripts/run_loop.py +332 -0
- package/.xtrm/skills/default/skill-creator/scripts/utils.py +47 -0
- package/.xtrm/skills/default/specialists-creator/SKILL.md +705 -0
- package/.xtrm/skills/default/specialists-creator/scripts/validate-specialist.ts +41 -0
- package/.xtrm/skills/default/sync-docs/SKILL.md +262 -0
- package/.xtrm/skills/default/sync-docs/evals/evals.json +89 -0
- package/.xtrm/skills/default/sync-docs/references/doc-structure.md +99 -0
- package/.xtrm/skills/default/sync-docs/references/schema.md +103 -0
- package/.xtrm/skills/default/sync-docs/scripts/changelog/add_entry.py +216 -0
- package/.xtrm/skills/default/sync-docs/scripts/context_gatherer.py +405 -0
- package/.xtrm/skills/default/sync-docs/scripts/doc_structure_analyzer.py +495 -0
- package/.xtrm/skills/default/sync-docs/scripts/drift_detector.py +563 -0
- package/.xtrm/skills/default/sync-docs/scripts/validate_doc.py +365 -0
- package/.xtrm/skills/default/sync-docs/scripts/validate_metadata.py +185 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/benchmark.json +293 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/benchmark.md +13 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-doc-audit/eval_metadata.json +27 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/outputs/result.md +210 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/grading.json +28 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/timing.json +1 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/outputs/result.md +101 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/grading.json +28 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/timing.json +5 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/timing.json +5 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-fix-mode/eval_metadata.json +27 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/outputs/result.md +198 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/grading.json +28 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/timing.json +1 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/outputs/result.md +94 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/grading.json +28 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/timing.json +1 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-sprint-closeout/eval_metadata.json +27 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/outputs/result.md +237 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/grading.json +28 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/outputs/result.md +134 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/grading.json +28 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/timing.json +1 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/benchmark.json +297 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/benchmark.md +13 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-doc-audit/eval_metadata.json +27 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/outputs/result.md +137 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/grading.json +92 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/timing.json +1 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/outputs/result.md +134 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/grading.json +86 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/timing.json +1 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-fix-mode/eval_metadata.json +27 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/outputs/result.md +193 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/grading.json +72 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/timing.json +1 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/outputs/result.md +211 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/grading.json +91 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/timing.json +5 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-sprint-closeout/eval_metadata.json +27 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/outputs/result.md +182 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/outputs/result.md +222 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/grading.json +88 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/benchmark.json +298 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/benchmark.md +13 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-doc-audit/eval_metadata.json +27 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/outputs/result.md +125 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/grading.json +97 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/timing.json +5 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/outputs/result.md +144 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/grading.json +78 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/timing.json +5 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-fix-mode/eval_metadata.json +27 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/outputs/result.md +104 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/grading.json +91 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/timing.json +5 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/outputs/result.md +79 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/grading.json +82 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/timing.json +5 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-sprint-closeout/eval_metadata.json +27 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase1_context.json +302 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase2_drift.txt +33 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase3_analysis.json +114 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase4_fix.txt +118 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase5_validate.txt +38 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/result.md +158 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/timing.json +5 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/outputs/result.md +71 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/grading.json +90 -0
- package/.xtrm/skills/default/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
- package/.xtrm/skills/default/test-planning/SKILL.md +465 -0
- package/.xtrm/skills/default/test-planning/evals/evals.json +23 -0
- package/.xtrm/skills/default/updating-service-skills/SKILL.md +136 -0
- package/.xtrm/skills/default/updating-service-skills/scripts/drift_detector.py +222 -0
- package/.xtrm/skills/default/using-nodes/SKILL.md +333 -0
- package/.xtrm/skills/default/using-quality-gates/SKILL.md +254 -0
- package/.xtrm/skills/default/using-service-skills/SKILL.md +108 -0
- package/.xtrm/skills/default/using-service-skills/scripts/cataloger.py +74 -0
- package/.xtrm/skills/default/using-service-skills/scripts/skill_activator.py +152 -0
- package/.xtrm/skills/default/using-specialists/SKILL.md +848 -0
- package/.xtrm/skills/default/using-specialists/evals/evals.json +68 -0
- package/.xtrm/skills/default/using-tdd/SKILL.md +410 -0
- package/.xtrm/skills/default/using-xtrm/SKILL.md +127 -0
- package/.xtrm/skills/default/xt-debugging/SKILL.md +149 -0
- package/.xtrm/skills/default/xt-end/SKILL.md +297 -0
- package/.xtrm/skills/default/xt-merge/SKILL.md +326 -0
- package/.xtrm/skills/optional/README.txt +2 -0
- package/.xtrm/skills/optional/architecture-design/PACK.json +11 -0
- package/.xtrm/skills/optional/architecture-design/architecture-patterns/SKILL.md +494 -0
- package/.xtrm/skills/optional/architecture-design/architecture-patterns/references/advanced-patterns.md +391 -0
- package/.xtrm/skills/optional/architecture-design/prompt-engineering-patterns/SKILL.md +473 -0
- package/.xtrm/skills/optional/architecture-design/prompt-engineering-patterns/assets/few-shot-examples.json +106 -0
- package/.xtrm/skills/optional/architecture-design/prompt-engineering-patterns/assets/prompt-template-library.md +264 -0
- package/.xtrm/skills/optional/architecture-design/prompt-engineering-patterns/references/chain-of-thought.md +412 -0
- package/.xtrm/skills/optional/architecture-design/prompt-engineering-patterns/references/few-shot-learning.md +386 -0
- package/.xtrm/skills/optional/architecture-design/prompt-engineering-patterns/references/prompt-optimization.md +428 -0
- package/.xtrm/skills/optional/architecture-design/prompt-engineering-patterns/references/prompt-templates.md +484 -0
- package/.xtrm/skills/optional/architecture-design/prompt-engineering-patterns/references/system-prompts.md +195 -0
- package/.xtrm/skills/optional/architecture-design/prompt-engineering-patterns/scripts/optimize-prompt.py +279 -0
- package/.xtrm/skills/optional/architecture-design/subagent-driven-development/SKILL.md +277 -0
- package/.xtrm/skills/optional/architecture-design/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
- package/.xtrm/skills/optional/architecture-design/subagent-driven-development/implementer-prompt.md +113 -0
- package/.xtrm/skills/optional/architecture-design/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/.xtrm/skills/optional/code-quality/PACK.json +12 -0
- package/.xtrm/skills/optional/code-quality/code-review-excellence/SKILL.md +529 -0
- package/.xtrm/skills/optional/code-quality/multi-reviewer-patterns/SKILL.md +127 -0
- package/.xtrm/skills/optional/code-quality/systematic-debugging/SKILL.md +296 -0
- package/.xtrm/skills/optional/code-quality/verification-before-completion/SKILL.md +139 -0
- package/.xtrm/skills/optional/data-engineering/PACK.json +9 -0
- package/.xtrm/skills/optional/data-engineering/data-analyst/SKILL.md +57 -0
- package/.xtrm/skills/optional/research-methods/PACK.json +12 -0
- package/.xtrm/skills/optional/research-methods/academic-researcher/SKILL.md +269 -0
- package/.xtrm/skills/optional/research-methods/brainstorming/SKILL.md +164 -0
- package/.xtrm/skills/optional/research-methods/brainstorming/scripts/frame-template.html +214 -0
- package/.xtrm/skills/optional/research-methods/brainstorming/scripts/helper.js +88 -0
- package/.xtrm/skills/optional/research-methods/brainstorming/scripts/server.cjs +354 -0
- package/.xtrm/skills/optional/research-methods/brainstorming/scripts/start-server.sh +148 -0
- package/.xtrm/skills/optional/research-methods/brainstorming/scripts/stop-server.sh +56 -0
- package/.xtrm/skills/optional/research-methods/brainstorming/spec-document-reviewer-prompt.md +49 -0
- package/.xtrm/skills/optional/research-methods/brainstorming/visual-companion.md +287 -0
- package/.xtrm/skills/optional/research-methods/deep-research/SKILL.md +192 -0
- package/.xtrm/skills/optional/research-methods/fact-checker/SKILL.md +182 -0
- package/.xtrm/skills/optional/security-ops/PACK.json +9 -0
- package/.xtrm/skills/optional/security-ops/security-auditor/SKILL.md +165 -0
- package/.xtrm/skills/optional/xt-optional/PACK.json +16 -0
- package/.xtrm/skills/optional/xt-optional/docker-expert/SKILL.md +409 -0
- package/.xtrm/skills/optional/xt-optional/obsidian-cli/SKILL.md +106 -0
- package/.xtrm/skills/optional/xt-optional/python-testing/SKILL.md +815 -0
- package/.xtrm/skills/optional/xt-optional/senior-backend/SKILL.md +209 -0
- package/.xtrm/skills/optional/xt-optional/senior-backend/references/api_design_patterns.md +103 -0
- package/.xtrm/skills/optional/xt-optional/senior-backend/references/backend_security_practices.md +103 -0
- package/.xtrm/skills/optional/xt-optional/senior-backend/references/database_optimization_guide.md +103 -0
- package/.xtrm/skills/optional/xt-optional/senior-backend/scripts/api_load_tester.py +114 -0
- package/.xtrm/skills/optional/xt-optional/senior-backend/scripts/api_scaffolder.py +114 -0
- package/.xtrm/skills/optional/xt-optional/senior-backend/scripts/database_migration_tool.py +114 -0
- package/.xtrm/skills/optional/xt-optional/senior-data-scientist/SKILL.md +226 -0
- package/.xtrm/skills/optional/xt-optional/senior-data-scientist/references/experiment_design_frameworks.md +80 -0
- package/.xtrm/skills/optional/xt-optional/senior-data-scientist/references/feature_engineering_patterns.md +80 -0
- package/.xtrm/skills/optional/xt-optional/senior-data-scientist/references/statistical_methods_advanced.md +80 -0
- package/.xtrm/skills/optional/xt-optional/senior-data-scientist/scripts/experiment_designer.py +100 -0
- package/.xtrm/skills/optional/xt-optional/senior-data-scientist/scripts/feature_engineering_pipeline.py +100 -0
- package/.xtrm/skills/optional/xt-optional/senior-data-scientist/scripts/model_evaluation_suite.py +100 -0
- package/.xtrm/skills/optional/xt-optional/senior-devops/SKILL.md +209 -0
- package/.xtrm/skills/optional/xt-optional/senior-devops/references/cicd_pipeline_guide.md +103 -0
- package/.xtrm/skills/optional/xt-optional/senior-devops/references/deployment_strategies.md +103 -0
- package/.xtrm/skills/optional/xt-optional/senior-devops/references/infrastructure_as_code.md +103 -0
- package/.xtrm/skills/optional/xt-optional/senior-devops/scripts/deployment_manager.py +114 -0
- package/.xtrm/skills/optional/xt-optional/senior-devops/scripts/pipeline_generator.py +114 -0
- package/.xtrm/skills/optional/xt-optional/senior-devops/scripts/terraform_scaffolder.py +114 -0
- package/.xtrm/skills/optional/xt-optional/senior-security/SKILL.md +209 -0
- package/.xtrm/skills/optional/xt-optional/senior-security/references/cryptography_implementation.md +103 -0
- package/.xtrm/skills/optional/xt-optional/senior-security/references/penetration_testing_guide.md +103 -0
- package/.xtrm/skills/optional/xt-optional/senior-security/references/security_architecture_patterns.md +103 -0
- package/.xtrm/skills/optional/xt-optional/senior-security/scripts/pentest_automator.py +114 -0
- package/.xtrm/skills/optional/xt-optional/senior-security/scripts/security_auditor.py +114 -0
- package/.xtrm/skills/optional/xt-optional/senior-security/scripts/threat_modeler.py +114 -0
- package/CHANGELOG.md +16 -0
- package/README.md +5 -0
- package/cli/dist/index.cjs +862 -614
- package/cli/dist/index.cjs.map +1 -1
- package/cli/package.json +1 -1
- package/package.json +4 -1
- package/.xtrm/extensions/xtrm-ui/format.ts +0 -93
- package/.xtrm/extensions/xtrm-ui/package.json +0 -10
- /package/.xtrm/{extensions → ext-src}/auto-session-name/index.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/auto-session-name/package.json +0 -0
- /package/.xtrm/{extensions → ext-src}/auto-update/index.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/auto-update/package.json +0 -0
- /package/.xtrm/{extensions → ext-src}/beads/index.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/beads/package.json +0 -0
- /package/.xtrm/{extensions → ext-src}/compact-header/index.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/compact-header/package.json +0 -0
- /package/.xtrm/{extensions → ext-src}/core/adapter.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/core/guard-rules.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/core/lib.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/core/logger.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/core/package.json +0 -0
- /package/.xtrm/{extensions → ext-src}/core/runner.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/core/session-state.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/custom-footer/index.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/custom-footer/package.json +0 -0
- /package/.xtrm/{extensions → ext-src}/custom-provider-qwen-cli/index.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/custom-provider-qwen-cli/package.json +0 -0
- /package/.xtrm/{extensions → ext-src}/git-checkpoint/index.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/git-checkpoint/package.json +0 -0
- /package/.xtrm/{extensions → ext-src}/lsp-bootstrap/index.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/lsp-bootstrap/package.json +0 -0
- /package/.xtrm/{extensions → ext-src}/pi-serena-compact/index.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/pi-serena-compact/package.json +0 -0
- /package/.xtrm/{extensions → ext-src}/quality-gates/index.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/quality-gates/package.json +0 -0
- /package/.xtrm/{extensions → ext-src}/service-skills/index.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/service-skills/package.json +0 -0
- /package/.xtrm/{extensions → ext-src}/session-flow/index.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/session-flow/package.json +0 -0
- /package/.xtrm/{extensions → ext-src}/xtrm-loader/index.ts +0 -0
- /package/.xtrm/{extensions → ext-src}/xtrm-loader/package.json +0 -0
- /package/.xtrm/{extensions → ext-src}/xtrm-ui/themes/pidex-dark.json +0 -0
- /package/.xtrm/{extensions → ext-src}/xtrm-ui/themes/pidex-light.json +0 -0
|
@@ -0,0 +1,807 @@
|
|
|
1
|
+
"""Environment and API key management for last30days skill."""
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
import os
|
|
7
|
+
import time
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Optional, Dict, Any, List, Literal
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
# Cookie domain registry: maps source names to browser cookie extraction params.
|
|
16
|
+
# Each entry: (domain, cookie_names, config_key_mapping)
|
|
17
|
+
# config_key_mapping: {cookie_name: config_key} so we know which config key
|
|
18
|
+
# each extracted cookie should populate.
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
COOKIE_DOMAINS: Dict[str, Dict[str, Any]] = {
|
|
21
|
+
"x": {
|
|
22
|
+
"domain": ".x.com",
|
|
23
|
+
"cookies": ["auth_token", "ct0"],
|
|
24
|
+
"mapping": {
|
|
25
|
+
"auth_token": "AUTH_TOKEN",
|
|
26
|
+
"ct0": "CT0",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
"truthsocial": {
|
|
30
|
+
"domain": ".truthsocial.com",
|
|
31
|
+
"cookies": ["_session_id"],
|
|
32
|
+
"mapping": {
|
|
33
|
+
"_session_id": "TRUTHSOCIAL_TOKEN",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Allow override via environment variable for testing
|
|
39
|
+
# Set LAST30DAYS_CONFIG_DIR="" for clean/no-config mode
|
|
40
|
+
# Set LAST30DAYS_CONFIG_DIR="/path/to/dir" for custom config location
|
|
41
|
+
_config_override = os.environ.get('LAST30DAYS_CONFIG_DIR')
|
|
42
|
+
if _config_override == "":
|
|
43
|
+
# Empty string = no config file (clean mode)
|
|
44
|
+
CONFIG_DIR = None
|
|
45
|
+
CONFIG_FILE = None
|
|
46
|
+
elif _config_override:
|
|
47
|
+
CONFIG_DIR = Path(_config_override)
|
|
48
|
+
CONFIG_FILE = CONFIG_DIR / ".env"
|
|
49
|
+
else:
|
|
50
|
+
CONFIG_DIR = Path.home() / ".config" / "last30days"
|
|
51
|
+
CONFIG_FILE = CONFIG_DIR / ".env"
|
|
52
|
+
|
|
53
|
+
CODEX_AUTH_FILE = Path(os.environ.get("CODEX_AUTH_FILE", str(Path.home() / ".codex" / "auth.json")))
|
|
54
|
+
|
|
55
|
+
AuthSource = Literal["api_key", "codex", "none"]
|
|
56
|
+
AuthStatus = Literal["ok", "missing", "expired", "missing_account_id"]
|
|
57
|
+
|
|
58
|
+
AUTH_SOURCE_API_KEY: AuthSource = "api_key"
|
|
59
|
+
AUTH_SOURCE_CODEX: AuthSource = "codex"
|
|
60
|
+
AUTH_SOURCE_NONE: AuthSource = "none"
|
|
61
|
+
|
|
62
|
+
AUTH_STATUS_OK: AuthStatus = "ok"
|
|
63
|
+
AUTH_STATUS_MISSING: AuthStatus = "missing"
|
|
64
|
+
AUTH_STATUS_EXPIRED: AuthStatus = "expired"
|
|
65
|
+
AUTH_STATUS_MISSING_ACCOUNT_ID: AuthStatus = "missing_account_id"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass(frozen=True)
|
|
69
|
+
class OpenAIAuth:
|
|
70
|
+
token: Optional[str]
|
|
71
|
+
source: AuthSource
|
|
72
|
+
status: AuthStatus
|
|
73
|
+
account_id: Optional[str]
|
|
74
|
+
codex_auth_file: str
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _check_file_permissions(path: Path) -> None:
|
|
78
|
+
"""Warn to stderr if a secrets file has overly permissive permissions."""
|
|
79
|
+
try:
|
|
80
|
+
mode = path.stat().st_mode
|
|
81
|
+
# Check if group or other can read (bits 0o044)
|
|
82
|
+
if mode & 0o044:
|
|
83
|
+
import sys
|
|
84
|
+
sys.stderr.write(
|
|
85
|
+
f"[last30days] WARNING: {path} is readable by other users. "
|
|
86
|
+
f"Run: chmod 600 {path}\n"
|
|
87
|
+
)
|
|
88
|
+
sys.stderr.flush()
|
|
89
|
+
except OSError:
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def load_env_file(path: Path) -> Dict[str, str]:
|
|
94
|
+
"""Load environment variables from a file."""
|
|
95
|
+
env = {}
|
|
96
|
+
if not path or not path.exists():
|
|
97
|
+
return env
|
|
98
|
+
_check_file_permissions(path)
|
|
99
|
+
|
|
100
|
+
with open(path, 'r') as f:
|
|
101
|
+
for line in f:
|
|
102
|
+
line = line.strip()
|
|
103
|
+
if not line or line.startswith('#'):
|
|
104
|
+
continue
|
|
105
|
+
if '=' in line:
|
|
106
|
+
key, _, value = line.partition('=')
|
|
107
|
+
key = key.strip()
|
|
108
|
+
value = value.strip()
|
|
109
|
+
# Remove quotes if present
|
|
110
|
+
if value and value[0] in ('"', "'") and value[-1] == value[0]:
|
|
111
|
+
value = value[1:-1]
|
|
112
|
+
if key and value:
|
|
113
|
+
env[key] = value
|
|
114
|
+
return env
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _decode_jwt_payload(token: str) -> Optional[Dict[str, Any]]:
|
|
118
|
+
"""Decode JWT payload without verification."""
|
|
119
|
+
try:
|
|
120
|
+
parts = token.split(".")
|
|
121
|
+
if len(parts) < 2:
|
|
122
|
+
return None
|
|
123
|
+
payload_b64 = parts[1]
|
|
124
|
+
pad = "=" * (-len(payload_b64) % 4)
|
|
125
|
+
decoded = base64.urlsafe_b64decode(payload_b64 + pad)
|
|
126
|
+
return json.loads(decoded.decode("utf-8"))
|
|
127
|
+
except Exception:
|
|
128
|
+
return None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _token_expired(token: str, leeway_seconds: int = 60) -> bool:
|
|
132
|
+
"""Check if JWT token is expired."""
|
|
133
|
+
payload = _decode_jwt_payload(token)
|
|
134
|
+
if not payload:
|
|
135
|
+
return False
|
|
136
|
+
exp = payload.get("exp")
|
|
137
|
+
if not exp:
|
|
138
|
+
return False
|
|
139
|
+
return exp <= (time.time() + leeway_seconds)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def extract_chatgpt_account_id(access_token: str) -> Optional[str]:
|
|
143
|
+
"""Extract chatgpt_account_id from JWT token."""
|
|
144
|
+
payload = _decode_jwt_payload(access_token)
|
|
145
|
+
if not payload:
|
|
146
|
+
return None
|
|
147
|
+
auth_claim = payload.get("https://api.openai.com/auth", {})
|
|
148
|
+
if isinstance(auth_claim, dict):
|
|
149
|
+
return auth_claim.get("chatgpt_account_id")
|
|
150
|
+
return None
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def load_codex_auth(path: Path = CODEX_AUTH_FILE) -> Dict[str, Any]:
|
|
154
|
+
"""Load Codex auth JSON."""
|
|
155
|
+
if not path.exists():
|
|
156
|
+
return {}
|
|
157
|
+
try:
|
|
158
|
+
with open(path, "r") as f:
|
|
159
|
+
return json.load(f)
|
|
160
|
+
except Exception:
|
|
161
|
+
return {}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def get_codex_access_token() -> tuple[Optional[str], str]:
|
|
165
|
+
"""Get Codex access token from auth.json.
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
(token, status) where status is 'ok', 'missing', or 'expired'
|
|
169
|
+
"""
|
|
170
|
+
auth = load_codex_auth()
|
|
171
|
+
token = None
|
|
172
|
+
if isinstance(auth, dict):
|
|
173
|
+
tokens = auth.get("tokens") or {}
|
|
174
|
+
if isinstance(tokens, dict):
|
|
175
|
+
token = tokens.get("access_token")
|
|
176
|
+
if not token:
|
|
177
|
+
token = auth.get("access_token")
|
|
178
|
+
if not token:
|
|
179
|
+
return None, AUTH_STATUS_MISSING
|
|
180
|
+
if _token_expired(token):
|
|
181
|
+
return None, AUTH_STATUS_EXPIRED
|
|
182
|
+
return token, AUTH_STATUS_OK
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def get_openai_auth(file_env: Dict[str, str]) -> OpenAIAuth:
|
|
186
|
+
"""Resolve OpenAI auth from API key or Codex login."""
|
|
187
|
+
api_key = os.environ.get('OPENAI_API_KEY') or file_env.get('OPENAI_API_KEY')
|
|
188
|
+
if api_key:
|
|
189
|
+
return OpenAIAuth(
|
|
190
|
+
token=api_key,
|
|
191
|
+
source=AUTH_SOURCE_API_KEY,
|
|
192
|
+
status=AUTH_STATUS_OK,
|
|
193
|
+
account_id=None,
|
|
194
|
+
codex_auth_file=str(CODEX_AUTH_FILE),
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
codex_token, codex_status = get_codex_access_token()
|
|
198
|
+
if codex_token:
|
|
199
|
+
account_id = extract_chatgpt_account_id(codex_token)
|
|
200
|
+
if account_id:
|
|
201
|
+
return OpenAIAuth(
|
|
202
|
+
token=codex_token,
|
|
203
|
+
source=AUTH_SOURCE_CODEX,
|
|
204
|
+
status=AUTH_STATUS_OK,
|
|
205
|
+
account_id=account_id,
|
|
206
|
+
codex_auth_file=str(CODEX_AUTH_FILE),
|
|
207
|
+
)
|
|
208
|
+
return OpenAIAuth(
|
|
209
|
+
token=None,
|
|
210
|
+
source=AUTH_SOURCE_CODEX,
|
|
211
|
+
status=AUTH_STATUS_MISSING_ACCOUNT_ID,
|
|
212
|
+
account_id=None,
|
|
213
|
+
codex_auth_file=str(CODEX_AUTH_FILE),
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
return OpenAIAuth(
|
|
217
|
+
token=None,
|
|
218
|
+
source=AUTH_SOURCE_NONE,
|
|
219
|
+
status=codex_status,
|
|
220
|
+
account_id=None,
|
|
221
|
+
codex_auth_file=str(CODEX_AUTH_FILE),
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _find_project_env() -> Optional[Path]:
|
|
226
|
+
"""Find per-project .env by walking up from cwd.
|
|
227
|
+
|
|
228
|
+
Searches for .claude/last30days.env in each parent directory,
|
|
229
|
+
stopping at the user's home directory or filesystem root.
|
|
230
|
+
"""
|
|
231
|
+
cwd = Path.cwd()
|
|
232
|
+
for parent in [cwd, *cwd.parents]:
|
|
233
|
+
candidate = parent / '.claude' / 'last30days.env'
|
|
234
|
+
if candidate.exists():
|
|
235
|
+
return candidate
|
|
236
|
+
# Stop at filesystem root or home
|
|
237
|
+
if parent == Path.home() or parent == parent.parent:
|
|
238
|
+
break
|
|
239
|
+
return None
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def extract_browser_credentials(config: Dict[str, Any]) -> Dict[str, str]:
|
|
243
|
+
"""Extract credentials from browser cookies for sources that need them.
|
|
244
|
+
|
|
245
|
+
Checks the FROM_BROWSER config key to decide whether/how to extract:
|
|
246
|
+
- 'auto': try browsers in platform order
|
|
247
|
+
- 'firefox', 'chrome', 'safari': try only that browser
|
|
248
|
+
- 'off': skip extraction entirely
|
|
249
|
+
|
|
250
|
+
If SETUP_COMPLETE is not set AND FROM_BROWSER is not explicitly set,
|
|
251
|
+
defaults to 'off' (wizard hasn't run yet — no extraction without consent).
|
|
252
|
+
If SETUP_COMPLETE is set and FROM_BROWSER is not set, defaults to 'auto'.
|
|
253
|
+
|
|
254
|
+
Explicit env var/config values always take priority over extracted cookies.
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
Dict of {config_key: value} for credentials discovered from cookies.
|
|
258
|
+
"""
|
|
259
|
+
setup_complete = config.get("SETUP_COMPLETE")
|
|
260
|
+
from_browser = config.get("FROM_BROWSER")
|
|
261
|
+
|
|
262
|
+
# Determine effective browser setting
|
|
263
|
+
if from_browser is None:
|
|
264
|
+
if setup_complete:
|
|
265
|
+
from_browser = "auto"
|
|
266
|
+
else:
|
|
267
|
+
from_browser = "off"
|
|
268
|
+
|
|
269
|
+
from_browser = from_browser.lower().strip() if isinstance(from_browser, str) else "off"
|
|
270
|
+
|
|
271
|
+
if from_browser == "off":
|
|
272
|
+
return {}
|
|
273
|
+
|
|
274
|
+
# Lazy import to avoid loading cookie_extract at module level
|
|
275
|
+
try:
|
|
276
|
+
from . import cookie_extract
|
|
277
|
+
except Exception:
|
|
278
|
+
logger.debug("cookie_extract module not available")
|
|
279
|
+
return {}
|
|
280
|
+
|
|
281
|
+
credentials: Dict[str, str] = {}
|
|
282
|
+
|
|
283
|
+
for source_name, spec in COOKIE_DOMAINS.items():
|
|
284
|
+
domain = spec["domain"]
|
|
285
|
+
cookie_names: List[str] = spec["cookies"]
|
|
286
|
+
mapping: Dict[str, str] = spec["mapping"]
|
|
287
|
+
|
|
288
|
+
# Skip if ALL mapped config keys already have values
|
|
289
|
+
all_present = all(config.get(config_key) for config_key in mapping.values())
|
|
290
|
+
if all_present:
|
|
291
|
+
logger.debug(
|
|
292
|
+
"Skipping cookie extraction for %s: credentials already set",
|
|
293
|
+
source_name,
|
|
294
|
+
)
|
|
295
|
+
continue
|
|
296
|
+
|
|
297
|
+
try:
|
|
298
|
+
result = cookie_extract.extract_cookies_with_source(from_browser, domain, cookie_names)
|
|
299
|
+
except Exception as exc:
|
|
300
|
+
logger.debug(
|
|
301
|
+
"Cookie extraction failed for %s: %s", source_name, exc
|
|
302
|
+
)
|
|
303
|
+
continue
|
|
304
|
+
|
|
305
|
+
if result is None:
|
|
306
|
+
continue
|
|
307
|
+
|
|
308
|
+
cookies, browser_name = result
|
|
309
|
+
filled_any = False
|
|
310
|
+
for cookie_name, config_key in mapping.items():
|
|
311
|
+
# Only fill in keys not already present
|
|
312
|
+
if not config.get(config_key) and cookie_name in cookies:
|
|
313
|
+
credentials[config_key] = cookies[cookie_name]
|
|
314
|
+
filled_any = True
|
|
315
|
+
|
|
316
|
+
# Track which browser provided the credentials for this source
|
|
317
|
+
if filled_any:
|
|
318
|
+
credentials[f"__{source_name.upper()}_BROWSER"] = browser_name
|
|
319
|
+
|
|
320
|
+
return credentials
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def get_config() -> Dict[str, Any]:
|
|
324
|
+
"""Load configuration from multiple sources.
|
|
325
|
+
|
|
326
|
+
Priority (highest wins):
|
|
327
|
+
1. Environment variables (os.environ)
|
|
328
|
+
2. .claude/last30days.env (per-project config)
|
|
329
|
+
3. ~/.config/last30days/.env (global config)
|
|
330
|
+
4. Browser cookies (only fills in missing keys)
|
|
331
|
+
"""
|
|
332
|
+
# Load from global config file
|
|
333
|
+
file_env = load_env_file(CONFIG_FILE) if CONFIG_FILE else {}
|
|
334
|
+
|
|
335
|
+
# Load from per-project config (overrides global)
|
|
336
|
+
project_env_path = _find_project_env()
|
|
337
|
+
project_env = load_env_file(project_env_path) if project_env_path else {}
|
|
338
|
+
|
|
339
|
+
# Merge: project overrides global
|
|
340
|
+
merged_env = {**file_env, **project_env}
|
|
341
|
+
|
|
342
|
+
openai_auth = get_openai_auth(merged_env)
|
|
343
|
+
|
|
344
|
+
# Build config: Codex/OpenAI auth + process.env > project .env > global .env
|
|
345
|
+
config = {
|
|
346
|
+
'OPENAI_API_KEY': openai_auth.token,
|
|
347
|
+
'OPENAI_AUTH_SOURCE': openai_auth.source,
|
|
348
|
+
'OPENAI_AUTH_STATUS': openai_auth.status,
|
|
349
|
+
'OPENAI_CHATGPT_ACCOUNT_ID': openai_auth.account_id,
|
|
350
|
+
'CODEX_AUTH_FILE': openai_auth.codex_auth_file,
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
keys = [
|
|
354
|
+
('XAI_API_KEY', None),
|
|
355
|
+
('GOOGLE_API_KEY', None),
|
|
356
|
+
('GEMINI_API_KEY', None),
|
|
357
|
+
('GOOGLE_GENAI_API_KEY', None),
|
|
358
|
+
('OPENROUTER_API_KEY', None),
|
|
359
|
+
('PARALLEL_API_KEY', None),
|
|
360
|
+
('BRAVE_API_KEY', None),
|
|
361
|
+
('EXA_API_KEY', None),
|
|
362
|
+
('XIAOHONGSHU_API_BASE', None),
|
|
363
|
+
('GEMINI_MODEL', None),
|
|
364
|
+
('OPENAI_MODEL_POLICY', 'auto'),
|
|
365
|
+
('OPENAI_MODEL_PIN', None),
|
|
366
|
+
('XAI_MODEL_POLICY', 'latest'),
|
|
367
|
+
('XAI_MODEL_PIN', None),
|
|
368
|
+
('SCRAPECREATORS_API_KEY', None),
|
|
369
|
+
('APIFY_API_TOKEN', None),
|
|
370
|
+
('AUTH_TOKEN', None),
|
|
371
|
+
('CT0', None),
|
|
372
|
+
('BSKY_HANDLE', None),
|
|
373
|
+
('BSKY_APP_PASSWORD', None),
|
|
374
|
+
('TRUTHSOCIAL_TOKEN', None),
|
|
375
|
+
('FROM_BROWSER', None),
|
|
376
|
+
('SETUP_COMPLETE', None),
|
|
377
|
+
('INCLUDE_SOURCES', None),
|
|
378
|
+
]
|
|
379
|
+
|
|
380
|
+
for key, default in keys:
|
|
381
|
+
config[key] = os.environ.get(key) or merged_env.get(key, default)
|
|
382
|
+
|
|
383
|
+
# Inject browser cookies for any credentials not already set
|
|
384
|
+
browser_creds = extract_browser_credentials(config)
|
|
385
|
+
for key, value in browser_creds.items():
|
|
386
|
+
if not config.get(key):
|
|
387
|
+
config[key] = value
|
|
388
|
+
|
|
389
|
+
# Track AUTH_TOKEN source for status reporting
|
|
390
|
+
if config.get('AUTH_TOKEN'):
|
|
391
|
+
if os.environ.get('AUTH_TOKEN') or merged_env.get('AUTH_TOKEN'):
|
|
392
|
+
config['_AUTH_TOKEN_SOURCE'] = 'env'
|
|
393
|
+
elif browser_creds.get('AUTH_TOKEN'):
|
|
394
|
+
browser_name = browser_creds.get('__X_BROWSER', 'unknown')
|
|
395
|
+
config['_AUTH_TOKEN_SOURCE'] = f'browser-{browser_name}'
|
|
396
|
+
else:
|
|
397
|
+
config['_AUTH_TOKEN_SOURCE'] = 'env' # fallback
|
|
398
|
+
else:
|
|
399
|
+
config['_AUTH_TOKEN_SOURCE'] = None
|
|
400
|
+
|
|
401
|
+
# Track which config source was used
|
|
402
|
+
if project_env_path:
|
|
403
|
+
config['_CONFIG_SOURCE'] = f'project:{project_env_path}'
|
|
404
|
+
elif CONFIG_FILE and CONFIG_FILE.exists():
|
|
405
|
+
config['_CONFIG_SOURCE'] = f'global:{CONFIG_FILE}'
|
|
406
|
+
else:
|
|
407
|
+
config['_CONFIG_SOURCE'] = 'env_only'
|
|
408
|
+
|
|
409
|
+
return config
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def config_exists() -> bool:
|
|
413
|
+
"""Check if any configuration source exists."""
|
|
414
|
+
if _find_project_env():
|
|
415
|
+
return True
|
|
416
|
+
if CONFIG_FILE:
|
|
417
|
+
return CONFIG_FILE.exists()
|
|
418
|
+
return False
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def is_reddit_available(config: Dict[str, Any]) -> bool:
|
|
422
|
+
"""Check if Reddit search is available.
|
|
423
|
+
|
|
424
|
+
Reddit can use either ScrapeCreators (preferred) or OpenAI.
|
|
425
|
+
"""
|
|
426
|
+
has_sc = bool(config.get('SCRAPECREATORS_API_KEY'))
|
|
427
|
+
has_openai = bool(config.get('OPENAI_API_KEY')) and config.get('OPENAI_AUTH_STATUS') == AUTH_STATUS_OK
|
|
428
|
+
return has_sc or has_openai
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def get_reddit_source(config: Dict[str, Any]) -> Optional[str]:
|
|
432
|
+
"""Determine which Reddit backend to use.
|
|
433
|
+
|
|
434
|
+
Priority: ScrapeCreators (cheaper, faster) > OpenAI (legacy)
|
|
435
|
+
|
|
436
|
+
Returns: 'scrapecreators', 'openai', or None
|
|
437
|
+
"""
|
|
438
|
+
if config.get('SCRAPECREATORS_API_KEY'):
|
|
439
|
+
return 'scrapecreators'
|
|
440
|
+
if config.get('OPENAI_API_KEY') and config.get('OPENAI_AUTH_STATUS') == AUTH_STATUS_OK:
|
|
441
|
+
return 'openai'
|
|
442
|
+
return None
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def get_available_sources(config: Dict[str, Any]) -> str:
|
|
446
|
+
"""Determine which sources are available.
|
|
447
|
+
|
|
448
|
+
X is available if ANY auth method works: AUTH_TOKEN/CT0 (env or cookies),
|
|
449
|
+
XAI_API_KEY, or Bird installed+authenticated.
|
|
450
|
+
Reddit is always available (public JSON fallback).
|
|
451
|
+
HN and Polymarket are always available.
|
|
452
|
+
YouTube available if yt-dlp installed.
|
|
453
|
+
|
|
454
|
+
Returns: 'all', 'both', 'reddit', 'reddit-web', 'x', 'x-web', 'web', or 'none'
|
|
455
|
+
"""
|
|
456
|
+
has_reddit = True
|
|
457
|
+
has_x = get_x_source(config) is not None
|
|
458
|
+
has_web = has_web_search_keys(config)
|
|
459
|
+
|
|
460
|
+
if has_reddit and has_x:
|
|
461
|
+
return 'all' if has_web else 'both'
|
|
462
|
+
elif has_reddit:
|
|
463
|
+
return 'reddit-web' if has_web else 'reddit'
|
|
464
|
+
return 'web' if has_web else 'none'
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
def has_web_search_keys(config: Dict[str, Any]) -> bool:
|
|
468
|
+
"""Check if any web search API keys are configured."""
|
|
469
|
+
return bool(config.get('EXA_API_KEY') or config.get('OPENROUTER_API_KEY') or config.get('PARALLEL_API_KEY') or config.get('BRAVE_API_KEY'))
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
def get_web_search_source(config: Dict[str, Any]) -> Optional[str]:
|
|
473
|
+
"""Determine the best available web search backend.
|
|
474
|
+
|
|
475
|
+
Priority: Exa (free) > Parallel AI > Brave > OpenRouter/Sonar Pro
|
|
476
|
+
|
|
477
|
+
Returns: 'exa', 'parallel', 'brave', 'openrouter', or None
|
|
478
|
+
"""
|
|
479
|
+
if config.get('EXA_API_KEY'):
|
|
480
|
+
return 'exa'
|
|
481
|
+
if config.get('PARALLEL_API_KEY'):
|
|
482
|
+
return 'parallel'
|
|
483
|
+
if config.get('BRAVE_API_KEY'):
|
|
484
|
+
return 'brave'
|
|
485
|
+
if config.get('OPENROUTER_API_KEY'):
|
|
486
|
+
return 'openrouter'
|
|
487
|
+
return None
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def get_missing_keys(config: Dict[str, Any]) -> str:
|
|
491
|
+
"""Determine which sources are missing (accounting for Bird).
|
|
492
|
+
|
|
493
|
+
Returns: 'all', 'both', 'reddit', 'x', 'web', or 'none'
|
|
494
|
+
"""
|
|
495
|
+
has_reddit = True
|
|
496
|
+
has_xai = bool(config.get('XAI_API_KEY'))
|
|
497
|
+
has_web = has_web_search_keys(config)
|
|
498
|
+
|
|
499
|
+
# Check if Bird provides X access (import here to avoid circular dependency)
|
|
500
|
+
from . import bird_x
|
|
501
|
+
has_bird = bird_x.is_bird_installed() and bird_x.is_bird_authenticated()
|
|
502
|
+
|
|
503
|
+
has_x = has_xai or has_bird
|
|
504
|
+
|
|
505
|
+
if has_reddit and has_x and has_web:
|
|
506
|
+
return 'none'
|
|
507
|
+
elif has_reddit and has_x:
|
|
508
|
+
return 'web' # Missing web search keys
|
|
509
|
+
elif has_reddit and has_web:
|
|
510
|
+
return 'x' # Missing X source
|
|
511
|
+
elif has_reddit:
|
|
512
|
+
return 'x' # Missing X source (and possibly web)
|
|
513
|
+
return 'all'
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
def validate_sources(requested: str, available: str, include_web: bool = False) -> tuple[str, Optional[str]]:
|
|
517
|
+
"""Validate requested sources against available keys.
|
|
518
|
+
|
|
519
|
+
Args:
|
|
520
|
+
requested: 'auto', 'reddit', 'x', 'both', or 'web'
|
|
521
|
+
available: Result from get_available_sources()
|
|
522
|
+
include_web: If True, add WebSearch to available sources
|
|
523
|
+
|
|
524
|
+
Returns:
|
|
525
|
+
Tuple of (effective_sources, error_message)
|
|
526
|
+
"""
|
|
527
|
+
has_reddit = available in ('reddit', 'both', 'reddit-web', 'all')
|
|
528
|
+
has_x = available in ('x', 'both', 'x-web', 'all')
|
|
529
|
+
has_web = available in ('web', 'reddit-web', 'x-web', 'all')
|
|
530
|
+
|
|
531
|
+
if requested == 'auto':
|
|
532
|
+
if has_reddit and has_x:
|
|
533
|
+
base = 'both'
|
|
534
|
+
elif has_reddit:
|
|
535
|
+
base = 'reddit'
|
|
536
|
+
elif has_x:
|
|
537
|
+
base = 'x'
|
|
538
|
+
elif has_web:
|
|
539
|
+
base = 'web'
|
|
540
|
+
else:
|
|
541
|
+
return 'none', "No sources are available."
|
|
542
|
+
|
|
543
|
+
if include_web:
|
|
544
|
+
if base == 'both':
|
|
545
|
+
return 'all', None
|
|
546
|
+
if base == 'reddit':
|
|
547
|
+
return 'reddit-web', None
|
|
548
|
+
if base == 'x':
|
|
549
|
+
return 'x-web', None
|
|
550
|
+
return base, None
|
|
551
|
+
|
|
552
|
+
if requested == 'web':
|
|
553
|
+
return 'web', None
|
|
554
|
+
|
|
555
|
+
if requested == 'both':
|
|
556
|
+
if not (has_reddit and has_x):
|
|
557
|
+
return 'none', "Requested both sources but X source is missing."
|
|
558
|
+
if include_web:
|
|
559
|
+
return 'all', None
|
|
560
|
+
return 'both', None
|
|
561
|
+
|
|
562
|
+
if requested == 'reddit':
|
|
563
|
+
if not has_reddit:
|
|
564
|
+
return 'none', "Requested Reddit but only xAI key is available."
|
|
565
|
+
if include_web:
|
|
566
|
+
return 'reddit-web', None
|
|
567
|
+
return 'reddit', None
|
|
568
|
+
|
|
569
|
+
if requested == 'x':
|
|
570
|
+
if not has_x:
|
|
571
|
+
return 'none', "Requested X but no X source is available (need Bird auth or XAI_API_KEY)."
|
|
572
|
+
if include_web:
|
|
573
|
+
return 'x-web', None
|
|
574
|
+
return 'x', None
|
|
575
|
+
|
|
576
|
+
return requested, None
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def get_x_source(config: Dict[str, Any]) -> Optional[str]:
|
|
580
|
+
"""Determine the best available X/Twitter source.
|
|
581
|
+
|
|
582
|
+
Priority chain:
|
|
583
|
+
1. AUTH_TOKEN/CT0 from env var or .env file → Bird with method "env"
|
|
584
|
+
2. AUTH_TOKEN/CT0 from browser cookie extraction → Bird with method "browser-{browser}"
|
|
585
|
+
3. XAI_API_KEY → xAI with method "api"
|
|
586
|
+
4. None
|
|
587
|
+
|
|
588
|
+
Use get_x_source_with_method() to also get the method string.
|
|
589
|
+
|
|
590
|
+
Args:
|
|
591
|
+
config: Configuration dict from get_config()
|
|
592
|
+
|
|
593
|
+
Returns:
|
|
594
|
+
'bird' if Bird is installed and authenticated,
|
|
595
|
+
'xai' if XAI_API_KEY is configured,
|
|
596
|
+
None if no X source available.
|
|
597
|
+
"""
|
|
598
|
+
source, _method = get_x_source_with_method(config)
|
|
599
|
+
return source
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
def get_x_source_with_method(config: Dict[str, Any]) -> tuple[Optional[str], Optional[str]]:
|
|
603
|
+
"""Determine the best available X/Twitter source and auth method.
|
|
604
|
+
|
|
605
|
+
Priority chain:
|
|
606
|
+
1. AUTH_TOKEN/CT0 (env var or .env) → Bird with method "env"
|
|
607
|
+
2. AUTH_TOKEN/CT0 (browser cookies) → Bird with method "browser-{browser}"
|
|
608
|
+
3. XAI_API_KEY → xAI with method "api"
|
|
609
|
+
4. None
|
|
610
|
+
|
|
611
|
+
Args:
|
|
612
|
+
config: Configuration dict from get_config()
|
|
613
|
+
|
|
614
|
+
Returns:
|
|
615
|
+
Tuple of (source, method) where source is 'bird', 'xai', or None
|
|
616
|
+
and method is 'env', 'browser-chrome', 'browser-firefox', 'browser-safari', 'api', or None.
|
|
617
|
+
"""
|
|
618
|
+
from . import bird_x
|
|
619
|
+
|
|
620
|
+
setup_complete = config.get('SETUP_COMPLETE')
|
|
621
|
+
|
|
622
|
+
# Check Bird first (free option — uses AUTH_TOKEN/CT0 from any source)
|
|
623
|
+
if bird_x.is_bird_installed():
|
|
624
|
+
auth_source = config.get('_AUTH_TOKEN_SOURCE')
|
|
625
|
+
|
|
626
|
+
# If SETUP_COMPLETE is not set, only allow explicit env var credentials.
|
|
627
|
+
# Do NOT call is_bird_authenticated() for browser-cookie probing —
|
|
628
|
+
# that requires user consent via the setup wizard.
|
|
629
|
+
if not setup_complete:
|
|
630
|
+
# Explicit AUTH_TOKEN from env var / .env file is always allowed
|
|
631
|
+
if auth_source == 'env' and config.get('AUTH_TOKEN'):
|
|
632
|
+
username = bird_x.is_bird_authenticated()
|
|
633
|
+
if username:
|
|
634
|
+
return 'bird', 'env'
|
|
635
|
+
else:
|
|
636
|
+
# SETUP_COMPLETE is set — normal flow, probe cookies if needed
|
|
637
|
+
username = bird_x.is_bird_authenticated()
|
|
638
|
+
if username:
|
|
639
|
+
if auth_source and auth_source.startswith('browser-'):
|
|
640
|
+
method = auth_source # e.g. "browser-firefox"
|
|
641
|
+
else:
|
|
642
|
+
method = 'env'
|
|
643
|
+
return 'bird', method
|
|
644
|
+
|
|
645
|
+
# Fall back to xAI if key exists
|
|
646
|
+
if config.get('XAI_API_KEY'):
|
|
647
|
+
return 'xai', 'api'
|
|
648
|
+
|
|
649
|
+
return None, None
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
def is_ytdlp_available() -> bool:
|
|
653
|
+
"""Check if yt-dlp is installed for YouTube search."""
|
|
654
|
+
from . import youtube_yt
|
|
655
|
+
return youtube_yt.is_ytdlp_installed()
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def is_hackernews_available() -> bool:
|
|
659
|
+
"""Check if Hacker News source is available.
|
|
660
|
+
|
|
661
|
+
Always returns True - HN uses free Algolia API, no key needed.
|
|
662
|
+
"""
|
|
663
|
+
return True
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
def is_bluesky_available(config: Dict[str, Any]) -> bool:
|
|
667
|
+
"""Check if Bluesky source is available.
|
|
668
|
+
|
|
669
|
+
Requires BSKY_HANDLE and BSKY_APP_PASSWORD (app password from bsky.app/settings).
|
|
670
|
+
"""
|
|
671
|
+
return bool(config.get('BSKY_HANDLE') and config.get('BSKY_APP_PASSWORD'))
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
def is_truthsocial_available(config: Dict[str, Any]) -> bool:
|
|
675
|
+
"""Check if Truth Social source is available.
|
|
676
|
+
|
|
677
|
+
Requires TRUTHSOCIAL_TOKEN (bearer token from browser dev tools).
|
|
678
|
+
"""
|
|
679
|
+
return bool(config.get('TRUTHSOCIAL_TOKEN'))
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
def is_polymarket_available() -> bool:
|
|
683
|
+
"""Check if Polymarket source is available.
|
|
684
|
+
|
|
685
|
+
Always returns True - Gamma API is free, no key needed.
|
|
686
|
+
"""
|
|
687
|
+
return True
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
def is_tiktok_available(config: Dict[str, Any]) -> bool:
|
|
691
|
+
"""Check if TikTok source is available (ScrapeCreators or legacy Apify).
|
|
692
|
+
|
|
693
|
+
Returns True if SCRAPECREATORS_API_KEY or APIFY_API_TOKEN is set.
|
|
694
|
+
"""
|
|
695
|
+
return bool(config.get('SCRAPECREATORS_API_KEY') or config.get('APIFY_API_TOKEN'))
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
def get_tiktok_token(config: Dict[str, Any]) -> str:
|
|
699
|
+
"""Get TikTok API token, preferring ScrapeCreators over legacy Apify."""
|
|
700
|
+
return config.get('SCRAPECREATORS_API_KEY') or config.get('APIFY_API_TOKEN') or ''
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
def is_instagram_available(config: Dict[str, Any]) -> bool:
|
|
704
|
+
"""Check if Instagram source is available (ScrapeCreators).
|
|
705
|
+
|
|
706
|
+
Returns True if SCRAPECREATORS_API_KEY is set.
|
|
707
|
+
Instagram uses the same key as TikTok.
|
|
708
|
+
"""
|
|
709
|
+
return bool(config.get('SCRAPECREATORS_API_KEY'))
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
def get_instagram_token(config: Dict[str, Any]) -> str:
|
|
713
|
+
"""Get Instagram API token (same ScrapeCreators key as TikTok)."""
|
|
714
|
+
return config.get('SCRAPECREATORS_API_KEY') or ''
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
def get_xiaohongshu_api_base(config: Dict[str, Any]) -> str:
|
|
718
|
+
"""Get Xiaohongshu HTTP API base URL.
|
|
719
|
+
|
|
720
|
+
Defaults to host.docker.internal so OpenClaw Docker can reach host service.
|
|
721
|
+
"""
|
|
722
|
+
return (config.get('XIAOHONGSHU_API_BASE') or "http://host.docker.internal:18060").rstrip("/")
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
def is_xiaohongshu_available(config: Dict[str, Any]) -> bool:
|
|
726
|
+
"""Check whether Xiaohongshu HTTP API is reachable and logged in."""
|
|
727
|
+
# Import here to avoid heavy imports at module load.
|
|
728
|
+
from . import http
|
|
729
|
+
|
|
730
|
+
base = get_xiaohongshu_api_base(config)
|
|
731
|
+
try:
|
|
732
|
+
# Keep health probe snappy, but allow one retry for transient hiccups.
|
|
733
|
+
health = http.get(f"{base}/health", timeout=3, retries=2)
|
|
734
|
+
if not isinstance(health, dict):
|
|
735
|
+
return False
|
|
736
|
+
if not health.get("success"):
|
|
737
|
+
return False
|
|
738
|
+
|
|
739
|
+
# Login probe can be slower on some deployments (browser/session checks),
|
|
740
|
+
# so use a slightly longer timeout to avoid false negatives.
|
|
741
|
+
login = http.get(f"{base}/api/v1/login/status", timeout=8, retries=2)
|
|
742
|
+
is_logged_in = (
|
|
743
|
+
login.get("data", {}).get("is_logged_in")
|
|
744
|
+
if isinstance(login, dict) else False
|
|
745
|
+
)
|
|
746
|
+
return bool(is_logged_in)
|
|
747
|
+
except Exception:
|
|
748
|
+
return False
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
# Backward compat alias
|
|
752
|
+
is_apify_available = is_tiktok_available
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
def get_x_source_status(config: Dict[str, Any]) -> Dict[str, Any]:
|
|
756
|
+
"""Get detailed X source status for UI decisions.
|
|
757
|
+
|
|
758
|
+
Returns:
|
|
759
|
+
Dict with keys: source, method, bird_installed, bird_authenticated,
|
|
760
|
+
bird_username, xai_available, can_install_bird
|
|
761
|
+
|
|
762
|
+
The ``method`` field indicates HOW the active source is authenticated:
|
|
763
|
+
- "env" — AUTH_TOKEN came from an env var or .env file
|
|
764
|
+
- "browser-chrome", "browser-firefox", "browser-safari" — from cookie extraction
|
|
765
|
+
- "api" — using xAI API key
|
|
766
|
+
- None — no X source available
|
|
767
|
+
"""
|
|
768
|
+
from . import bird_x
|
|
769
|
+
|
|
770
|
+
setup_complete = config.get('SETUP_COMPLETE')
|
|
771
|
+
xai_available = bool(config.get('XAI_API_KEY'))
|
|
772
|
+
|
|
773
|
+
if not setup_complete:
|
|
774
|
+
# Before consent: do NOT call get_bird_status() which probes cookies.
|
|
775
|
+
# Only check if Bird is installed (no cookie probing) and use the
|
|
776
|
+
# gated get_x_source_with_method() which blocks cookie detection.
|
|
777
|
+
bird_installed = bird_x.is_bird_installed()
|
|
778
|
+
source, method = get_x_source_with_method(config)
|
|
779
|
+
|
|
780
|
+
# Bird "authenticated" only if get_x_source_with_method found explicit creds
|
|
781
|
+
bird_authenticated = (source == 'bird')
|
|
782
|
+
|
|
783
|
+
return {
|
|
784
|
+
"source": source,
|
|
785
|
+
"method": method,
|
|
786
|
+
"bird_installed": bird_installed,
|
|
787
|
+
"bird_authenticated": bird_authenticated,
|
|
788
|
+
"bird_username": None if not bird_authenticated else "env AUTH_TOKEN",
|
|
789
|
+
"xai_available": xai_available,
|
|
790
|
+
"can_install_bird": True,
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
# SETUP_COMPLETE is set — normal flow
|
|
794
|
+
bird_status = bird_x.get_bird_status()
|
|
795
|
+
|
|
796
|
+
# Use the unified resolution function for source + method
|
|
797
|
+
source, method = get_x_source_with_method(config)
|
|
798
|
+
|
|
799
|
+
return {
|
|
800
|
+
"source": source,
|
|
801
|
+
"method": method,
|
|
802
|
+
"bird_installed": bird_status["installed"],
|
|
803
|
+
"bird_authenticated": bird_status["authenticated"],
|
|
804
|
+
"bird_username": bird_status["username"],
|
|
805
|
+
"xai_available": xai_available,
|
|
806
|
+
"can_install_bird": bird_status["can_install"],
|
|
807
|
+
}
|