codymaster 4.4.4 → 4.5.1
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/CHANGELOG.md +33 -0
- package/README.md +29 -14
- package/commands/demo.md +1 -1
- package/dist/context-bus.js +70 -0
- package/dist/context-db.js +265 -0
- package/dist/continuity.js +12 -0
- package/dist/file-watcher.js +79 -0
- package/dist/index.js +152 -1
- package/dist/l0-indexer.js +158 -0
- package/dist/mcp-context-server.js +400 -0
- package/dist/migrate-json-to-sqlite.js +126 -0
- package/dist/skill-chain.js +19 -3
- package/dist/token-budget.js +108 -0
- package/dist/uri-resolver.js +203 -0
- package/package.json +7 -1
- package/skills/_shared/helpers.md +50 -14
- package/skills/cm-autopilot/SKILL.md +29 -0
- package/skills/cm-autopilot/scripts/autopilot.py +190 -0
- package/skills/cm-continuity/SKILL.md +90 -28
- package/skills/cm-quality-gate/SKILL.md +11 -1
- package/skills/cm-safe-deploy/SKILL.md +38 -2
- package/skills/cm-security-gate/SKILL.md +158 -34
- package/skills/cm-skill-chain/SKILL.md +47 -1
- package/skills/cm-start/SKILL.md +11 -2
- package/skills/cm-test-gate/SKILL.md +3 -0
- package/skills/boxme-git-config/SKILL.md +0 -56
- package/skills/boxme-local-dev/SKILL.md +0 -66
- package/skills/jobs-to-be-done/SKILL.md +0 -266
- package/skills/jobs-to-be-done/references/case-studies.md +0 -154
- package/skills/jobs-to-be-done/references/competitive-strategy.md +0 -280
- package/skills/jobs-to-be-done/references/diagnostics.md +0 -158
- package/skills/jobs-to-be-done/references/innovation-process.md +0 -392
- package/skills/jobs-to-be-done/references/organizational-change.md +0 -328
- package/skills/marketplace-report-crawler/SKILL.md +0 -176
- package/skills/marketplace-report-crawler/config/accounts.json +0 -41
- package/skills/marketplace-report-crawler/config/report-types.json +0 -422
- package/skills/marketplace-report-crawler/config/sessions.json +0 -3
- package/skills/marketplace-report-crawler/scripts/ab-wrapper.sh +0 -102
- package/skills/marketplace-report-crawler/scripts/browser-actions/lazada/lazada-actions.js +0 -114
- package/skills/marketplace-report-crawler/scripts/browser-actions/shopee/shopee-actions.js +0 -94
- package/skills/marketplace-report-crawler/scripts/browser-actions/tiktok/tiktok-actions.js +0 -272
- package/skills/marketplace-report-crawler/scripts/crawl-runner.js +0 -281
- package/skills/marketplace-report-crawler/scripts/session-check.sh +0 -72
- package/skills/marketplace-report-crawler/scripts/session-manager.sh +0 -349
- package/skills/marketplace-report-crawler/scripts/setup-folders.sh +0 -83
- package/skills/medical-research/SKILL.md +0 -194
- package/skills/medical-research/scripts/evidence_checker.py +0 -288
- package/skills/mom-test/SKILL.md +0 -267
- package/skills/mom-test/references/avoiding-bad-data.md +0 -221
- package/skills/mom-test/references/case-studies.md +0 -306
- package/skills/mom-test/references/commitment-advancement.md +0 -219
- package/skills/mom-test/references/finding-conversations.md +0 -251
- package/skills/mom-test/references/processing-learning.md +0 -256
- package/skills/mom-test/references/question-patterns.md +0 -198
- package/skills/pandasai-analytics/SKILL.md +0 -251
- package/skills/release-it/SKILL.md +0 -235
- package/skills/release-it/references/anti-patterns.md +0 -279
- package/skills/release-it/references/capacity-planning.md +0 -285
- package/skills/release-it/references/chaos-engineering.md +0 -325
- package/skills/release-it/references/deployment-strategies.md +0 -331
- package/skills/release-it/references/observability.md +0 -301
- package/skills/release-it/references/stability-patterns.md +0 -355
- package/skills/skill-creator-ultra/.agents/workflows/skill-audit.md +0 -37
- package/skills/skill-creator-ultra/.agents/workflows/skill-compare.md +0 -34
- package/skills/skill-creator-ultra/.agents/workflows/skill-export.md +0 -51
- package/skills/skill-creator-ultra/.agents/workflows/skill-generate.md +0 -39
- package/skills/skill-creator-ultra/.agents/workflows/skill-scaffold.md +0 -52
- package/skills/skill-creator-ultra/.agents/workflows/skill-simulate.md +0 -25
- package/skills/skill-creator-ultra/.agents/workflows/skill-stats.md +0 -31
- package/skills/skill-creator-ultra/.agents/workflows/skill-validate.md +0 -25
- package/skills/skill-creator-ultra/README.md +0 -1242
- package/skills/skill-creator-ultra/SKILL.md +0 -388
- package/skills/skill-creator-ultra/agents/analyzer.md +0 -274
- package/skills/skill-creator-ultra/agents/comparator.md +0 -202
- package/skills/skill-creator-ultra/agents/grader.md +0 -223
- package/skills/skill-creator-ultra/assets/eval_review.html +0 -146
- package/skills/skill-creator-ultra/eval-viewer/generate_review.py +0 -471
- package/skills/skill-creator-ultra/eval-viewer/viewer.html +0 -1325
- package/skills/skill-creator-ultra/examples/example_anthropic_frontend.md +0 -109
- package/skills/skill-creator-ultra/examples/example_anthropic_pdf.md +0 -116
- package/skills/skill-creator-ultra/examples/example_api_docs.md +0 -189
- package/skills/skill-creator-ultra/examples/example_db_migration.md +0 -253
- package/skills/skill-creator-ultra/examples/example_git_commit.md +0 -111
- package/skills/skill-creator-ultra/install.ps1 +0 -289
- package/skills/skill-creator-ultra/install.sh +0 -313
- package/skills/skill-creator-ultra/phases/phase1_interview.md +0 -202
- package/skills/skill-creator-ultra/phases/phase2_extract.md +0 -55
- package/skills/skill-creator-ultra/phases/phase3_detect.md +0 -57
- package/skills/skill-creator-ultra/phases/phase4_generate.md +0 -543
- package/skills/skill-creator-ultra/phases/phase5_test.md +0 -319
- package/skills/skill-creator-ultra/phases/phase6_eval.md +0 -301
- package/skills/skill-creator-ultra/phases/phase7_iterate.md +0 -103
- package/skills/skill-creator-ultra/phases/phase8_optimize.md +0 -113
- package/skills/skill-creator-ultra/resources/advanced_patterns.md +0 -499
- package/skills/skill-creator-ultra/resources/anti_patterns.md +0 -376
- package/skills/skill-creator-ultra/resources/blueprints.md +0 -498
- package/skills/skill-creator-ultra/resources/checklist.md +0 -243
- package/skills/skill-creator-ultra/resources/composition_cookbook.md +0 -291
- package/skills/skill-creator-ultra/resources/description_optimization.md +0 -90
- package/skills/skill-creator-ultra/resources/eval_guide.md +0 -133
- package/skills/skill-creator-ultra/resources/industry_questions.md +0 -189
- package/skills/skill-creator-ultra/resources/interview_questions.md +0 -200
- package/skills/skill-creator-ultra/resources/pattern_detection.md +0 -200
- package/skills/skill-creator-ultra/resources/prompt_engineering.md +0 -531
- package/skills/skill-creator-ultra/resources/schemas.md +0 -430
- package/skills/skill-creator-ultra/resources/script_integration.md +0 -593
- package/skills/skill-creator-ultra/resources/scripts_guide.md +0 -339
- package/skills/skill-creator-ultra/resources/skill_template.md +0 -124
- package/skills/skill-creator-ultra/resources/skill_writing_guide.md +0 -634
- package/skills/skill-creator-ultra/resources/versioning_guide.md +0 -193
- package/skills/skill-creator-ultra/scripts/ci_eval.py +0 -200
- package/skills/skill-creator-ultra/scripts/package_skill.py +0 -165
- package/skills/skill-creator-ultra/scripts/simulate_skill.py +0 -398
- package/skills/skill-creator-ultra/scripts/skill_audit.py +0 -611
- package/skills/skill-creator-ultra/scripts/skill_compare.py +0 -265
- package/skills/skill-creator-ultra/scripts/skill_export.py +0 -334
- package/skills/skill-creator-ultra/scripts/skill_scaffold.py +0 -403
- package/skills/skill-creator-ultra/scripts/skill_stats.py +0 -339
- package/skills/skill-creator-ultra/scripts/validate_skill.py +0 -411
- package/skills/tailwind-mastery/SKILL.md +0 -229
- package/skills/vercel-react-best-practices/AGENTS.md +0 -3373
- package/skills/vercel-react-best-practices/README.md +0 -123
- package/skills/vercel-react-best-practices/SKILL.md +0 -143
- package/skills/vercel-react-best-practices/rules/_sections.md +0 -46
- package/skills/vercel-react-best-practices/rules/_template.md +0 -28
- package/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
- package/skills/vercel-react-best-practices/rules/advanced-init-once.md +0 -42
- package/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -39
- package/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -38
- package/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -80
- package/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -51
- package/skills/vercel-react-best-practices/rules/async-parallel.md +0 -28
- package/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
- package/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -59
- package/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
- package/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
- package/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
- package/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -50
- package/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
- package/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
- package/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
- package/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
- package/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -107
- package/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
- package/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
- package/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
- package/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
- package/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -50
- package/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +0 -60
- package/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
- package/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -37
- package/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
- package/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
- package/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
- package/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
- package/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -26
- package/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
- package/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
- package/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
- package/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
- package/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
- package/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +0 -30
- package/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +0 -85
- package/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +0 -68
- package/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
- package/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +0 -75
- package/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
- package/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
- package/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +0 -40
- package/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
- package/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
- package/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
- package/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +0 -38
- package/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -44
- package/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +0 -45
- package/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +0 -82
- package/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -35
- package/skills/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +0 -64
- package/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
- package/skills/vercel-react-best-practices/rules/rerender-use-deferred-value.md +0 -59
- package/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +0 -73
- package/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
- package/skills/vercel-react-best-practices/rules/server-auth-actions.md +0 -96
- package/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
- package/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -76
- package/skills/vercel-react-best-practices/rules/server-dedup-props.md +0 -65
- package/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +0 -142
- package/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
- package/skills/vercel-react-best-practices/rules/server-serialization.md +0 -38
- package/skills/web-design-guidelines/SKILL.md +0 -39
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# =============================================================================
|
|
3
|
-
# ab-wrapper.sh — agent-browser thin wrapper
|
|
4
|
-
# =============================================================================
|
|
5
|
-
# Provides shorthand commands for marketplace report crawling.
|
|
6
|
-
# Cross-agent compatible: any AI agent can call these commands.
|
|
7
|
-
#
|
|
8
|
-
# Usage:
|
|
9
|
-
# ./ab-wrapper.sh login <platform> <brand-id> # Guided login
|
|
10
|
-
# ./ab-wrapper.sh check <platform> <brand-id> # Check session
|
|
11
|
-
# ./ab-wrapper.sh crawl <platform> <brand-id> <YYYYMM> # Crawl reports
|
|
12
|
-
# ./ab-wrapper.sh open <platform> <brand-id> <url> # Open URL with session
|
|
13
|
-
# ./ab-wrapper.sh snapshot <platform> <brand-id> # Get page snapshot
|
|
14
|
-
# ./ab-wrapper.sh close <platform> <brand-id> # Close browser
|
|
15
|
-
# =============================================================================
|
|
16
|
-
|
|
17
|
-
set -euo pipefail
|
|
18
|
-
|
|
19
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
20
|
-
PROFILE_ROOT="${MARKETPLACE_PROFILE_ROOT:-$HOME/.marketplace-crawler/profiles}"
|
|
21
|
-
AB_CMD="${AGENT_BROWSER_CMD:-npx -y agent-browser}"
|
|
22
|
-
|
|
23
|
-
get_profile_dir() {
|
|
24
|
-
echo "$PROFILE_ROOT/${1}-${2}"
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
ensure_ab() {
|
|
28
|
-
if ! command -v agent-browser &>/dev/null && ! npx -y agent-browser --version &>/dev/null 2>&1; then
|
|
29
|
-
echo "❌ agent-browser not found. Installing..."
|
|
30
|
-
npm install -g agent-browser 2>/dev/null || {
|
|
31
|
-
echo "⚠️ Global install failed. Using npx (slower first run)."
|
|
32
|
-
}
|
|
33
|
-
fi
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
# --- Commands ---
|
|
37
|
-
|
|
38
|
-
case "${1:-help}" in
|
|
39
|
-
login)
|
|
40
|
-
"$SCRIPT_DIR/session-manager.sh" login "$2" "$3"
|
|
41
|
-
;;
|
|
42
|
-
check)
|
|
43
|
-
"$SCRIPT_DIR/session-manager.sh" check "$2" "$3"
|
|
44
|
-
;;
|
|
45
|
-
crawl)
|
|
46
|
-
platform="$2"
|
|
47
|
-
brand_id="$3"
|
|
48
|
-
period="${4:-$(date -v-1m +%Y%m 2>/dev/null || date -d '-1 month' +%Y%m)}"
|
|
49
|
-
echo "🕷️ Starting crawl: $platform / $brand_id / $period"
|
|
50
|
-
node "$SCRIPT_DIR/crawl-runner.js" --plan --platform "$platform" --brand-id "$brand_id" --period "$period"
|
|
51
|
-
;;
|
|
52
|
-
open)
|
|
53
|
-
profile_dir=$(get_profile_dir "$2" "$3")
|
|
54
|
-
mkdir -p "$profile_dir"
|
|
55
|
-
$AB_CMD --profile "$profile_dir" open "$4"
|
|
56
|
-
;;
|
|
57
|
-
snapshot)
|
|
58
|
-
profile_dir=$(get_profile_dir "$2" "$3")
|
|
59
|
-
$AB_CMD --profile "$profile_dir" snapshot -i --json
|
|
60
|
-
;;
|
|
61
|
-
screenshot)
|
|
62
|
-
profile_dir=$(get_profile_dir "$2" "$3")
|
|
63
|
-
output="${4:-/tmp/marketplace-screenshot-$(date +%s).png}"
|
|
64
|
-
$AB_CMD --profile "$profile_dir" screenshot "$output"
|
|
65
|
-
echo "📸 Screenshot saved: $output"
|
|
66
|
-
;;
|
|
67
|
-
close)
|
|
68
|
-
profile_dir=$(get_profile_dir "$2" "$3")
|
|
69
|
-
$AB_CMD --profile "$profile_dir" close 2>/dev/null || true
|
|
70
|
-
echo "🔒 Browser closed for $2/$3"
|
|
71
|
-
;;
|
|
72
|
-
exec)
|
|
73
|
-
# Pass any agent-browser command with the correct profile
|
|
74
|
-
profile_dir=$(get_profile_dir "$2" "$3")
|
|
75
|
-
shift 3
|
|
76
|
-
$AB_CMD --profile "$profile_dir" "$@"
|
|
77
|
-
;;
|
|
78
|
-
help|*)
|
|
79
|
-
echo ""
|
|
80
|
-
echo "🕷️ ab-wrapper — Marketplace Browser Automation"
|
|
81
|
-
echo "════════════════════════════════════════════════"
|
|
82
|
-
echo ""
|
|
83
|
-
echo "Session Management:"
|
|
84
|
-
echo " login <platform> <brand-id> Guided login (headed browser)"
|
|
85
|
-
echo " check <platform> <brand-id> Check session validity"
|
|
86
|
-
echo ""
|
|
87
|
-
echo "Crawling:"
|
|
88
|
-
echo " crawl <platform> <brand-id> [YYYYMM] Generate & show crawl plan"
|
|
89
|
-
echo ""
|
|
90
|
-
echo "Browser Control:"
|
|
91
|
-
echo " open <platform> <brand-id> <url> Open URL with saved session"
|
|
92
|
-
echo " snapshot <platform> <brand-id> Get accessibility tree (JSON)"
|
|
93
|
-
echo " screenshot <platform> <brand-id> [path] Take screenshot"
|
|
94
|
-
echo " close <platform> <brand-id> Close browser"
|
|
95
|
-
echo " exec <platform> <brand-id> <ab-args...> Run any agent-browser command"
|
|
96
|
-
echo ""
|
|
97
|
-
echo "Environment:"
|
|
98
|
-
echo " MARKETPLACE_PROFILE_ROOT Default: ~/.marketplace-crawler/profiles"
|
|
99
|
-
echo " AGENT_BROWSER_CMD Default: npx -y agent-browser"
|
|
100
|
-
echo ""
|
|
101
|
-
;;
|
|
102
|
-
esac
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Lazada Browser Actions
|
|
3
|
-
* ==================================================
|
|
4
|
-
* JavaScript snippets to inject into Lazada Seller Center pages.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Open calendar and go to the target month using next/prev buttons
|
|
9
|
-
* Used for platform_income, platform_wallet
|
|
10
|
-
*/
|
|
11
|
-
function lazadaCalendar_selectMonthRange(yearMonth) {
|
|
12
|
-
// Try to find the date picker input
|
|
13
|
-
const dateInputs = document.querySelectorAll('.next-date-picker-input input, input[placeholder*="YYYY"]');
|
|
14
|
-
if (dateInputs.length > 0) {
|
|
15
|
-
dateInputs[0].click(); // Open picker
|
|
16
|
-
|
|
17
|
-
setTimeout(() => {
|
|
18
|
-
// Find the 'Last Month' preset if it exists
|
|
19
|
-
const presets = document.querySelectorAll('.next-date-picker-quick span');
|
|
20
|
-
for (const preset of presets) {
|
|
21
|
-
if (preset.textContent.trim() === 'Tháng trước' || preset.textContent.trim() === 'Last month') {
|
|
22
|
-
preset.click();
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Otherwise find the 'OK' button and click it to accept default (usually last 30 days)
|
|
28
|
-
const okBtn = document.querySelector('.next-btn-primary');
|
|
29
|
-
if (okBtn) okBtn.click();
|
|
30
|
-
}, 500);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Lazada Paid Ads uses a specific date input format
|
|
36
|
-
* Used for paid_ads_onsite_report, paid_ads_product
|
|
37
|
-
*/
|
|
38
|
-
function lazadaAds_setDateRange(startDateStr, endDateStr) {
|
|
39
|
-
// Check the 'Product' checkbox if needed for paid_ads_product
|
|
40
|
-
const productCheckbox = document.querySelector('input[type="checkbox"][value="product"]');
|
|
41
|
-
if (productCheckbox && !productCheckbox.checked) {
|
|
42
|
-
productCheckbox.click();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Find date inputs (DD/MM/YYYY format usually)
|
|
46
|
-
const inputs = document.querySelectorAll('.next-input input');
|
|
47
|
-
if (inputs.length >= 2) {
|
|
48
|
-
// Start Date
|
|
49
|
-
inputs[0].value = startDateStr;
|
|
50
|
-
inputs[0].dispatchEvent(new Event('input', { bubbles: true }));
|
|
51
|
-
inputs[0].dispatchEvent(new Event('change', { bubbles: true }));
|
|
52
|
-
|
|
53
|
-
// End Date
|
|
54
|
-
inputs[1].value = endDateStr;
|
|
55
|
-
inputs[1].dispatchEvent(new Event('input', { bubbles: true }));
|
|
56
|
-
inputs[1].dispatchEvent(new Event('change', { bubbles: true }));
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Select from Lazada dropdown list
|
|
62
|
-
* Used for shipping_fee_details
|
|
63
|
-
*/
|
|
64
|
-
function lazadaMultiSelect_selectDates(targetYYYYMM) {
|
|
65
|
-
// Find the dropdown button
|
|
66
|
-
const dropdownTrigger = document.querySelector('.next-select-trigger');
|
|
67
|
-
if (dropdownTrigger) {
|
|
68
|
-
dropdownTrigger.click();
|
|
69
|
-
|
|
70
|
-
setTimeout(() => {
|
|
71
|
-
// Select logic
|
|
72
|
-
const items = document.querySelectorAll('.next-menu-item');
|
|
73
|
-
for(const item of items) {
|
|
74
|
-
if(item.textContent.trim().includes(targetYYYYMM)) {
|
|
75
|
-
item.click();
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}, 500);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Click export button on Lazada
|
|
84
|
-
*/
|
|
85
|
-
function lazadaClickExport() {
|
|
86
|
-
const buttons = document.querySelectorAll('button');
|
|
87
|
-
for (const btn of buttons) {
|
|
88
|
-
const text = btn.textContent.trim().toLowerCase();
|
|
89
|
-
if (text.includes('tải xuống') || text.includes('xuất dữ liệu') || text.includes('export') || text.includes('download')) {
|
|
90
|
-
btn.click();
|
|
91
|
-
|
|
92
|
-
// Some export buttons open a dropdown. If so, look for Excel/PDF option.
|
|
93
|
-
setTimeout(() => {
|
|
94
|
-
const menuItems = document.querySelectorAll('.next-menu-item');
|
|
95
|
-
for (const item of menuItems) {
|
|
96
|
-
if (item.textContent.toLowerCase().includes('excel') || item.textContent.toLowerCase().includes('pdf')) {
|
|
97
|
-
item.click();
|
|
98
|
-
return true;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}, 500);
|
|
102
|
-
|
|
103
|
-
return true;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return false;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
module.exports = {
|
|
110
|
-
lazadaCalendar_selectMonthRange,
|
|
111
|
-
lazadaAds_setDateRange,
|
|
112
|
-
lazadaMultiSelect_selectDates,
|
|
113
|
-
lazadaClickExport
|
|
114
|
-
};
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shopee Browser Actions
|
|
3
|
-
* ==================================================
|
|
4
|
-
* JavaScript snippets to inject into Shopee Seller pages.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Select month range on Shopee's typical calendar-range picker
|
|
9
|
-
* Used for platform_income, platform_wallet, ads_wallet_historical
|
|
10
|
-
*/
|
|
11
|
-
function shopeeCalendar_selectMonthRange(yearMonth) {
|
|
12
|
-
// Shopee usually has a date range input that opens a popper with two calendars.
|
|
13
|
-
const dateRangeInputs = document.querySelectorAll('.shopee-date-range-picker input');
|
|
14
|
-
if (dateRangeInputs.length > 0) {
|
|
15
|
-
dateRangeInputs[0].click(); // Open picker
|
|
16
|
-
|
|
17
|
-
setTimeout(() => {
|
|
18
|
-
// Very naive approach: try to find 'THIS_MONTH' or 'LAST_MONTH' button
|
|
19
|
-
// Or try to select the 1st and last day. Shopee's calendar is highly custom.
|
|
20
|
-
const lastMonthBtn = Array.from(document.querySelectorAll('.shopee-popover span, .shopee-popover div')).find(el => el.textContent.trim() === 'Tháng trước' || el.textContent.trim() === 'Last Month');
|
|
21
|
-
if (lastMonthBtn) {
|
|
22
|
-
lastMonthBtn.click();
|
|
23
|
-
}
|
|
24
|
-
}, 500);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Select a specific month in a month-picker
|
|
30
|
-
* Used for platform_report (PDF)
|
|
31
|
-
*/
|
|
32
|
-
function shopeeMonthPicker_selectMonth(yearMonth) {
|
|
33
|
-
const monthInput = document.querySelector('.shopeesc-month-picker, .month-picker-input');
|
|
34
|
-
if (monthInput) {
|
|
35
|
-
monthInput.click();
|
|
36
|
-
setTimeout(() => {
|
|
37
|
-
// Find the specific month cell
|
|
38
|
-
const monthStr = parseInt(yearMonth.substring(4, 6), 10).toString();
|
|
39
|
-
const cells = document.querySelectorAll('.month-cell, .shopee-month-table td');
|
|
40
|
-
for (const cell of cells) {
|
|
41
|
-
if (cell.textContent.trim() === monthStr || cell.textContent.trim().includes(`Tháng ${monthStr}`)) {
|
|
42
|
-
cell.click();
|
|
43
|
-
break;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}, 500);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Input Start and End date directly into text inputs
|
|
52
|
-
* Used for paid_ads_onsite_report (date_input)
|
|
53
|
-
*/
|
|
54
|
-
function shopeeDateInput_setDate(startDateStr, endDateStr) {
|
|
55
|
-
// Usually there are two inputs: start date and end date
|
|
56
|
-
const inputs = document.querySelectorAll('.shopee-input__input[placeholder*="YYYY"], input[placeholder*="Ngày"]');
|
|
57
|
-
if (inputs.length >= 2) {
|
|
58
|
-
// Start date
|
|
59
|
-
const startInput = inputs[0];
|
|
60
|
-
startInput.value = startDateStr;
|
|
61
|
-
startInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
62
|
-
startInput.dispatchEvent(new Event('change', { bubbles: true }));
|
|
63
|
-
|
|
64
|
-
// End date
|
|
65
|
-
const endInput = inputs[1];
|
|
66
|
-
endInput.value = endDateStr;
|
|
67
|
-
endInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
68
|
-
endInput.dispatchEvent(new Event('change', { bubbles: true }));
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Click export button
|
|
74
|
-
*/
|
|
75
|
-
function shopeeClickExport() {
|
|
76
|
-
// Tries to find common export buttons
|
|
77
|
-
const exportBtn = Array.from(document.querySelectorAll('button')).find(btn => {
|
|
78
|
-
const text = btn.textContent.trim().toLowerCase();
|
|
79
|
-
return text.includes('xuất') || text.includes('export') || text.includes('tải');
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
if (exportBtn) {
|
|
83
|
-
exportBtn.click();
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
module.exports = {
|
|
90
|
-
shopeeCalendar_selectMonthRange,
|
|
91
|
-
shopeeMonthPicker_selectMonth,
|
|
92
|
-
shopeeDateInput_setDate,
|
|
93
|
-
shopeeClickExport
|
|
94
|
-
};
|
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TikTok Browser Actions — Date Selection & Export
|
|
3
|
-
* ==================================================
|
|
4
|
-
* JavaScript snippets to inject into TikTok Seller Center pages.
|
|
5
|
-
*
|
|
6
|
-
* Extracted from Power Automate Desktop flow: "20260209 GBS Tiktok"
|
|
7
|
-
*
|
|
8
|
-
* TikTok uses:
|
|
9
|
-
* 1. core-picker (TikTok Design System) — for Income, Wallet pages
|
|
10
|
-
* 2. pulse-select — for pagination on Invoice page
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
// ============================================================================
|
|
14
|
-
// TIKTOK INCOME / WALLET — core-picker date range
|
|
15
|
-
// URL: https://seller-vn.tiktok.com/finance/transactions?shop_region=VN&tab=settled_tab
|
|
16
|
-
// URL: https://seller-vn.tiktok.com/finance/withdraw-new
|
|
17
|
-
// ============================================================================
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Select first and last day of target month in TikTok core-picker
|
|
21
|
-
* Used for TikTok Income and Wallet pages
|
|
22
|
-
*
|
|
23
|
-
* @param {string} yearMonth - Format: "YYYYMM" (e.g., "202602")
|
|
24
|
-
*/
|
|
25
|
-
function tiktokCorePicker_selectMonthRange(yearMonth) {
|
|
26
|
-
const lastDay = new Date(yearMonth.slice(0, 4), yearMonth.slice(4, 6), 0)
|
|
27
|
-
.getDate().toString().padStart(2, '0');
|
|
28
|
-
|
|
29
|
-
const cells = [...document.querySelectorAll('.core-picker-cell-in-view .core-picker-date-value')];
|
|
30
|
-
const first = cells.find(c => c.textContent.trim() === '01');
|
|
31
|
-
const last = cells.find(c => c.textContent.trim() === lastDay);
|
|
32
|
-
|
|
33
|
-
first?.click();
|
|
34
|
-
setTimeout(() => last?.click(), 100);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// ============================================================================
|
|
38
|
-
// TIKTOK AFFILIATE INVOICE — Month picker + Table scraping
|
|
39
|
-
// URL: https://seller-vn.tiktok.com/finance/invoice?shop_region=VN
|
|
40
|
-
// ============================================================================
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Select target month in TikTok month picker (Jan-Dec display)
|
|
44
|
-
* Used for TikTok Affiliate Invoice page
|
|
45
|
-
*
|
|
46
|
-
* @param {string} yearMonth - Format: "YYYYMM" (e.g., "202602")
|
|
47
|
-
*/
|
|
48
|
-
function tiktokMonthPicker_selectMonth(yearMonth) {
|
|
49
|
-
const month = parseInt(yearMonth.substring(4, 6), 10);
|
|
50
|
-
const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
|
51
|
-
'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'];
|
|
52
|
-
const monthName = monthNames[month - 1];
|
|
53
|
-
|
|
54
|
-
const cells = document.querySelectorAll('.core-picker-date-value');
|
|
55
|
-
let targetCell = null;
|
|
56
|
-
|
|
57
|
-
for (let i = 0; i < cells.length; i++) {
|
|
58
|
-
if (cells[i].textContent.trim() === monthName) {
|
|
59
|
-
targetCell = cells[i];
|
|
60
|
-
break;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (targetCell) {
|
|
65
|
-
targetCell.click();
|
|
66
|
-
setTimeout(function() {
|
|
67
|
-
targetCell.click(); // Double-click to confirm
|
|
68
|
-
}, 300);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Set pagination to 50 items per page
|
|
74
|
-
* Used on TikTok Affiliate Invoice page for large datasets
|
|
75
|
-
*/
|
|
76
|
-
function tiktokPagination_set50PerPage() {
|
|
77
|
-
const options = document.querySelectorAll('.pulse-select-option');
|
|
78
|
-
|
|
79
|
-
for (let option of options) {
|
|
80
|
-
const label = option.querySelector('.pulse-select-option-label-single');
|
|
81
|
-
if (label && label.textContent.trim() === '50/Page') {
|
|
82
|
-
option.click();
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Get max page number from TikTok pagination
|
|
91
|
-
* @returns {number|null} Max page number
|
|
92
|
-
*/
|
|
93
|
-
function tiktokPagination_getMaxPage() {
|
|
94
|
-
const paginationElement = document.querySelector('.core-pagination-list');
|
|
95
|
-
if (!paginationElement) return null;
|
|
96
|
-
|
|
97
|
-
const pageItems = paginationElement.querySelectorAll('.core-pagination-item');
|
|
98
|
-
let maxPage = 0;
|
|
99
|
-
|
|
100
|
-
pageItems.forEach(item => {
|
|
101
|
-
const text = item.textContent.trim();
|
|
102
|
-
if (/^\d+$/.test(text)) {
|
|
103
|
-
const pageNumber = parseInt(text, 10);
|
|
104
|
-
if (pageNumber > maxPage) {
|
|
105
|
-
maxPage = pageNumber;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
return maxPage || null;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Click next page button in TikTok pagination
|
|
115
|
-
*/
|
|
116
|
-
function tiktokPagination_clickNext() {
|
|
117
|
-
const element = document.querySelector('.core-pagination-item-next');
|
|
118
|
-
if (!element) return;
|
|
119
|
-
|
|
120
|
-
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
121
|
-
|
|
122
|
-
const rect = element.getBoundingClientRect();
|
|
123
|
-
const x = rect.left + rect.width / 2;
|
|
124
|
-
const y = rect.top + rect.height / 2;
|
|
125
|
-
|
|
126
|
-
element.dispatchEvent(new MouseEvent('mousemove', {
|
|
127
|
-
view: window, bubbles: true, cancelable: true, clientX: x, clientY: y
|
|
128
|
-
}));
|
|
129
|
-
|
|
130
|
-
element.dispatchEvent(new MouseEvent('click', {
|
|
131
|
-
view: window, bubbles: true, cancelable: true, button: 0
|
|
132
|
-
}));
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// ============================================================================
|
|
136
|
-
// HELPER — Scroll to bottom
|
|
137
|
-
// ============================================================================
|
|
138
|
-
|
|
139
|
-
function scrollToBottom() {
|
|
140
|
-
window.scrollTo({
|
|
141
|
-
top: document.body.scrollHeight,
|
|
142
|
-
behavior: "smooth"
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// ============================================================================
|
|
147
|
-
// BROWSER AGENT INSTRUCTIONS — TIKTOK COMPLETE FLOWS
|
|
148
|
-
// ============================================================================
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* === TIKTOK PLATFORM INCOME ===
|
|
152
|
-
* 1. Navigate to: https://seller-vn.tiktok.com/finance/transactions?shop_region=VN&tab=settled_tab
|
|
153
|
-
* 2. Wait for text "Lịch sử xuất dữ liệu" to appear (up to 200s)
|
|
154
|
-
* 3. Wait 1s
|
|
155
|
-
* 4. Click "Xuất" button
|
|
156
|
-
* 5. Wait 1s → Click SVG calendar icon to open date picker
|
|
157
|
-
* 6. Wait 1s → Click another SVG to clear existing date
|
|
158
|
-
* 7. Execute tiktokCorePicker_selectMonthRange(yearMonth)
|
|
159
|
-
* 8. Wait 1s → Click "OK" button
|
|
160
|
-
* 9. Wait 2s → Click "Xuất" (the export Span inside popup)
|
|
161
|
-
* 10. Wait for "Đang xuất" text to disappear (up to 600s!)
|
|
162
|
-
* 11. Wait 1s → Click "Tải xuống" button
|
|
163
|
-
* 12. Save file as: {yearMonth}_{brand}_platform_income.xlsx
|
|
164
|
-
*
|
|
165
|
-
* === TIKTOK WALLET ===
|
|
166
|
-
* 1. Navigate to: https://seller-vn.tiktok.com/finance/withdraw-new?is_new_connect=0&shop_region=VN
|
|
167
|
-
* 2. Wait for "Lịch sử xuất dữ liệu" (up to 200s)
|
|
168
|
-
* 3. Scroll down 500px
|
|
169
|
-
* 4. Click "Xuất"
|
|
170
|
-
* 5. Click SVG → clear → select date range (same as Income)
|
|
171
|
-
* 6. Click OK → Click "Xuất" button
|
|
172
|
-
* 7. Wait for "Đang xuất" to disappear (up to 600s)
|
|
173
|
-
* 8. Click "Tải xuống"
|
|
174
|
-
* 9. Save as: {yearMonth}_{brand}_platform_wallet.xlsx
|
|
175
|
-
*
|
|
176
|
-
* === TIKTOK AFFILIATE INVOICE ===
|
|
177
|
-
* 1. Navigate to: https://seller-vn.tiktok.com/finance/invoice?shop_region=VN
|
|
178
|
-
* 2. Wait for page load
|
|
179
|
-
* 3. Click "Biên nhận hoa hồng liên kết"
|
|
180
|
-
* 4. Wait 2s → Click SVG to open month picker
|
|
181
|
-
* 5. Execute tiktokMonthPicker_selectMonth(yearMonth)
|
|
182
|
-
* 6. Wait 3s → Click "OK"
|
|
183
|
-
* 7. Check if "Nothing here at the moment" exists
|
|
184
|
-
* - If yes: skip (no data)
|
|
185
|
-
* - If no: continue below
|
|
186
|
-
* 8. Scroll to bottom
|
|
187
|
-
* 9. Click pagination dropdown → Execute tiktokPagination_set50PerPage()
|
|
188
|
-
* 10. Get max page: tiktokPagination_getMaxPage()
|
|
189
|
-
* 11. If single page: extract table → save as .xlsx
|
|
190
|
-
* 12. If multiple pages: loop through pages:
|
|
191
|
-
* a. Extract table data from current page
|
|
192
|
-
* b. Save as: {yearMonth}_{brand}_affiliate_invoice_report_part_{pageNum}.xlsx
|
|
193
|
-
* c. Click next: tiktokPagination_clickNext()
|
|
194
|
-
* d. Wait 2s → repeat
|
|
195
|
-
*
|
|
196
|
-
* TABLE EXTRACTION CSS SELECTOR:
|
|
197
|
-
* Rows: html > body > div:eq(0) > div:eq(1) > main > div:eq(0) >
|
|
198
|
-
* div:eq(0) > div:eq(0) > div:eq(1) > div:eq(0) > div:eq(0) >
|
|
199
|
-
* div:eq(0) > div:eq(0) > div:eq(2) > div:eq(0) > div:eq(0) >
|
|
200
|
-
* div:eq(0) > div:eq(0) > div:eq(0) > table > tbody > tr
|
|
201
|
-
*
|
|
202
|
-
* Columns:
|
|
203
|
-
* - td:eq(0) > div > span > div > div (Column 1)
|
|
204
|
-
* - td:eq(1) > div > span (Column 2)
|
|
205
|
-
* - td:eq(2) > div > span (Column 3)
|
|
206
|
-
* - td:eq(3) > div > span (Column 4)
|
|
207
|
-
* - td:eq(4) > div > span (Column 5)
|
|
208
|
-
*/
|
|
209
|
-
|
|
210
|
-
// ============================================================================
|
|
211
|
-
// TIKTOK ADS AND AFFILIATE ORDERS
|
|
212
|
-
// ============================================================================
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Handle TikTok Business Center (Ads) date picker
|
|
216
|
-
* Used for ads_cost, ads_revenue
|
|
217
|
-
*/
|
|
218
|
-
function tiktokAds_setDateRange(startDateStr, endDateStr) {
|
|
219
|
-
// Usually involves clicking the date picker button
|
|
220
|
-
const pickerBtn = document.querySelector('.byted-date-picker, .date-picker-trigger');
|
|
221
|
-
if (pickerBtn) {
|
|
222
|
-
pickerBtn.click();
|
|
223
|
-
setTimeout(() => {
|
|
224
|
-
// Very naive: find inputs or presets inside the popup
|
|
225
|
-
// TikTok Business Center uses a complex React date picker
|
|
226
|
-
const presets = document.querySelectorAll('.byted-picker-preset-item');
|
|
227
|
-
for (const preset of presets) {
|
|
228
|
-
if (preset.textContent.trim().includes('Last Month') || preset.textContent.trim().includes('Tháng trước')) {
|
|
229
|
-
preset.click();
|
|
230
|
-
break;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}, 500);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Click typical TikTok export buttons
|
|
239
|
-
*/
|
|
240
|
-
function tiktokClickExport() {
|
|
241
|
-
const exportBtns = document.querySelectorAll('button');
|
|
242
|
-
for (const btn of exportBtns) {
|
|
243
|
-
const text = btn.textContent.trim().toLowerCase();
|
|
244
|
-
if (text.includes('export') || text.includes('xuất') || text.includes('tải')) {
|
|
245
|
-
btn.click();
|
|
246
|
-
return true;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Also check divs/spans that act as buttons (TikTok uses these heavily)
|
|
251
|
-
const allElements = document.querySelectorAll('div, span');
|
|
252
|
-
for (const el of allElements) {
|
|
253
|
-
const text = el.textContent.trim().toLowerCase();
|
|
254
|
-
if ((text === 'export' || text === 'xuất' || text === 'tải xuống') && el.children.length === 0) {
|
|
255
|
-
el.click();
|
|
256
|
-
return true;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return false;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
module.exports = {
|
|
264
|
-
tiktokCorePicker_selectMonthRange,
|
|
265
|
-
tiktokMonthPicker_selectMonth,
|
|
266
|
-
tiktokPagination_set50PerPage,
|
|
267
|
-
tiktokPagination_getMaxPage,
|
|
268
|
-
tiktokPagination_clickNext,
|
|
269
|
-
scrollToBottom,
|
|
270
|
-
tiktokAds_setDateRange,
|
|
271
|
-
tiktokClickExport
|
|
272
|
-
};
|