diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json new file mode 100644 index 0000000..858bfc6 --- /dev/null +++ b/.agents/plugins/marketplace.json @@ -0,0 +1,20 @@ +{ + "name": "last30days-skill", + "interface": { + "displayName": "Last 30 Days" + }, + "plugins": [ + { + "name": "last30days", + "source": { + "source": "local", + "path": "./" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Research" + } + ] +} diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index c544849..f51866e 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,7 +10,7 @@ { "name": "last30days", "description": "Research any topic across Reddit, X, YouTube, TikTok, Instagram, HN, Polymarket, GitHub, and 5+ more sources.", - "version": "3.0.9", + "version": "3.0.10", "author": { "name": "Matt Van Horn", "url": "https://github.com/mvanhorn" diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index c9d60bf..8399d76 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,3 +1,43 @@ { - "name": "last30days" + "name": "last30days", + "version": "3.0.10", + "description": "Research any topic across Reddit, X, YouTube, TikTok, Instagram, Hacker News, Polymarket, GitHub, and more sources.", + "author": { + "name": "Matt Van Horn", + "email": "mvanhorn@gmail.com", + "url": "https://github.com/mvanhorn" + }, + "homepage": "https://github.com/mvanhorn/last30days-skill", + "repository": "https://github.com/mvanhorn/last30days-skill", + "license": "MIT", + "keywords": [ + "research", + "reddit", + "twitter", + "youtube", + "tiktok", + "instagram", + "trends", + "polymarket", + "github", + "hacker-news" + ], + "skills": "./skills/", + "interface": { + "displayName": "Last 30 Days", + "shortDescription": "Research recent discussion across social and web sources", + "longDescription": "Use Last 30 Days to research what people are saying, upvoting, sharing, and betting on across Reddit, X, YouTube, TikTok, Instagram, Hacker News, Polymarket, GitHub, and web sources.", + "developerName": "Matt Van Horn", + "category": "Research", + "capabilities": [ + "Interactive", + "Read", + "Write" + ], + "websiteURL": "https://github.com/mvanhorn/last30days-skill", + "privacyPolicyURL": "https://docs.github.com/en/site-policy/privacy-policies/github-general-privacy-statement", + "termsOfServiceURL": "https://docs.github.com/en/site-policy/github-terms/github-terms-of-service", + "defaultPrompt": "Use Last 30 Days to research this topic from the last 30 days across Reddit, X, YouTube, and web.", + "brandColor": "#FF6B35" + } } diff --git a/.gitattributes b/.gitattributes index 06fa5fc..5b0fff7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,6 @@ # Exclude non-runtime files from `git archive` output. -# Used by scripts/build-skill.sh to produce a claude.ai-upload-ready .skill file. +# Used by skills/last30days/scripts/build-skill.sh to produce a +# claude.ai-upload-ready .skill file from the canonical skills/last30days tree. # See docs/plans/2026-04-14-001-fix-skill-upload-200-file-limit-plan.md. # Anthropic canonical skill-packaging excludes @@ -32,9 +33,8 @@ release-notes.md export-ignore CHANGELOG.md export-ignore uv.lock export-ignore -# Platform adapters - skill-upload path is platform-agnostic -.agents/ export-ignore -.codex-plugin/ export-ignore +# Platform adapters are kept in git archives because Claude Code and Codex +# plugin installs use the same repository archive as their source payload. .hermes-plugin/ export-ignore # CI workflows - repo-only, not needed at skill runtime diff --git a/CHANGELOG.md b/CHANGELOG.md index dbe1735..fe0ec3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,6 +78,7 @@ Individual changelog entries for 3.0.10 through 3.0.14 below document the increm ### Fixed - **TikTok author preference.** `_fetch_post_comments` in `scripts/lib/tiktok.py` preferred `user.nickname` over `user.unique_id`, so the engine captured display names ("Moosa Noormahomed") instead of @handles ("moosanoormahomed"). Flipped to prefer `unique_id`. Nickname still wins as a fallback when `unique_id` is missing. Display names can contain emoji, spaces, and non-Latin characters that do not round-trip to a profile URL; the @handle is the stable identifier. +- **Single plugin payload layout.** The canonical runtime moved to `skills/last30days/` for both Claude Code and Codex plugin loading. Root-level `SKILL.md`, `scripts/`, `agents/`, and `assets/` are no longer maintained as duplicate copies. ### Behavior fallback diff --git a/CLAUDE.md b/CLAUDE.md index 42427aa..410e382 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,20 +4,20 @@ Claude Code skill for researching any topic across Reddit, X, YouTube, and web. Python scripts with multi-source search aggregation. ## Structure -- `scripts/last30days.py` — main research engine -- `scripts/lib/` — search, enrichment, rendering modules -- `scripts/lib/vendor/bird-search/` — vendored X search client -- `SKILL.md` — skill definition (deployed to ~/.claude/skills/last30days/) +- `skills/last30days/SKILL.md` — canonical skill definition +- `skills/last30days/scripts/last30days.py` — main research engine +- `skills/last30days/scripts/lib/` — search, enrichment, rendering modules +- `skills/last30days/scripts/lib/vendor/bird-search/` — vendored X search client ## Commands ```bash -python3 scripts/last30days.py "test query" --emit=compact # Run research -bash scripts/sync.sh # Deploy to ~/.claude, ~/.agents, ~/.codex +python3 skills/last30days/scripts/last30days.py "test query" --emit=compact +bash skills/last30days/scripts/sync.sh ``` ## Rules - `lib/__init__.py` must be bare package marker (comment only, NO eager imports) -- After edits: run `bash scripts/sync.sh` to deploy +- After edits: run `bash skills/last30days/scripts/sync.sh` to deploy - Git remote: origin = public (`mvanhorn/last30days-skill`) ## Beta channel diff --git a/HERMES_SETUP.md b/HERMES_SETUP.md index 0e0e503..ce0d36b 100644 --- a/HERMES_SETUP.md +++ b/HERMES_SETUP.md @@ -18,7 +18,7 @@ git clone https://github.com/mvanhorn/last30days-skill.git cd last30days-skill # Run the sync script -bash scripts/sync.sh +bash skills/last30days/scripts/sync.sh ``` This will auto-detect Hermes and deploy to `~/.hermes/skills/research/last30days/` @@ -30,8 +30,8 @@ This will auto-detect Hermes and deploy to `~/.hermes/skills/research/last30days mkdir -p ~/.hermes/skills/research/last30days # Copy files -cp -r scripts ~/.hermes/skills/research/last30days/ -cp .hermes-plugin/SKILL.md ~/.hermes/skills/research/last30days/ +cp skills/last30days/SKILL.md ~/.hermes/skills/research/last30days/ +cp -r skills/last30days/scripts ~/.hermes/skills/research/last30days/ ``` ## Usage @@ -111,7 +111,7 @@ To update to the latest version: ```bash cd last30days-skill git pull -bash scripts/sync.sh +bash skills/last30days/scripts/sync.sh ``` ## Support diff --git a/README.md b/README.md index a77251d..dc45cd9 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,7 @@ gemini extensions install ./last30days-skill git clone https://github.com/mvanhorn/last30days-skill.git ~/.claude/skills/last30days ``` -Or build the claude.ai `.skill` file from source: `bash scripts/build-skill.sh` produces `dist/last30days.skill`. +Or build the claude.ai `.skill` file from source: `bash skills/last30days/scripts/build-skill.sh` produces `dist/last30days.skill`. Reddit (with comments), Hacker News, Polymarket, and GitHub work immediately. Zero configuration. Run `/last30days` once and the setup wizard unlocks more sources in 30 seconds. diff --git a/pyproject.toml b/pyproject.toml index 05abd37..0b2548f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "last30days-skill" -version = "3.0.0" +version = "3.0.10" description = "Multi-source last-30-days research skill" readme = "README.md" requires-python = ">=3.12" @@ -24,9 +24,9 @@ addopts = [ [tool.coverage.run] branch = true -source = ["scripts", "tests"] +source = ["skills/last30days/scripts", "tests"] omit = [ - "scripts/lib/vendor/*", + "skills/last30days/scripts/lib/vendor/*", "dist/*", ] @@ -34,7 +34,6 @@ omit = [ skip_empty = true show_missing = true omit = [ - "scripts/lib/vendor/*", + "skills/last30days/scripts/lib/vendor/*", "dist/*", ] - diff --git a/release-notes.md b/release-notes.md index b0fb510..1492d68 100644 --- a/release-notes.md +++ b/release-notes.md @@ -58,7 +58,7 @@ OpenClaw: clawhub install last30days-official ``` -OpenAI Codex CLI: run `codex` from a checkout of this repo and v3's skill at `.agents/skills/last30days/SKILL.md` will be discovered automatically. Or copy `SKILL.md` to `~/.agents/skills/last30days/SKILL.md` for a global install. +OpenAI Codex CLI: install the repo as a local Codex marketplace/plugin. The plugin manifest lives at `.codex-plugin/plugin.json`, and the canonical skill payload is `skills/last30days/SKILL.md`. Zero config. Reddit, Hacker News, Polymarket, and GitHub work immediately. Run it once and the setup wizard unlocks X, YouTube, TikTok, and more in 30 seconds. diff --git a/SKILL.md b/skills/last30days/SKILL.md similarity index 98% rename from SKILL.md rename to skills/last30days/SKILL.md index b645e4e..89c007a 100644 --- a/SKILL.md +++ b/skills/last30days/SKILL.md @@ -1,6 +1,6 @@ --- name: last30days -version: "3.0.1" +version: "3.0.10" description: "Research what people actually say about any topic in the last 30 days. Pulls posts and engagement from Reddit, X, YouTube, TikTok, Hacker News, Polymarket, GitHub, and the web." argument-hint: 'last30days nvidia earnings reaction | last30days AI video tools | last30days what users want in react' allowed-tools: Bash, Read, Write, AskUserQuestion, WebSearch @@ -104,7 +104,7 @@ These anchors used to live at line 1094 of this file. Three independent Opus 4.7 🌐 last30days v{VERSION} · synced {YYYY-MM-DD} ``` -Replace `{VERSION}` with the installed plugin version (`jq -r '.version' "$SKILL_ROOT/.claude-plugin/plugin.json"`) and `{YYYY-MM-DD}` with today's date. No other text on this line. One blank line after, then the synthesis begins. +Replace `{VERSION}` with the installed plugin version (`jq -r '.version' "$SKILL_ROOT/../../.codex-plugin/plugin.json" 2>/dev/null || jq -r '.version' "$SKILL_ROOT/.claude-plugin/plugin.json"`) and `{YYYY-MM-DD}` with today's date. No other text on this line. One blank line after, then the synthesis begins. **Why the badge is MANDATORY:** it is the structural anchor for the canonical output shape. Without it the model drifts into blog-post narrative format with `##` section headers and invented titles, violating LAW 2 and LAW 4. The 2026-04-18 public v3.0.6 0/8 regression produced outputs with section headers like "The headline", "Why he is everywhere", "1. gstack dominates", "The 'Homecoming' peak". Direct cause: this anchor was absent. Do NOT skip the badge. Do NOT describe it. Do NOT paraphrase it. Emit it verbatim as line 1. @@ -233,7 +233,7 @@ If your Bash call to `last30days.py` does NOT include the FULL pre-flight checkl --- -# last30days v3.0.1: Research Any Topic from the Last 30 Days +# last30days v3.0.10: Research Any Topic from the Last 30 Days > **Permissions overview:** Reads public web/platform data and optionally saves research briefings to `LAST30DAYS_MEMORY_DIR` (defaults to `~/Documents/Last30Days`). X/Twitter search uses optional user-provided tokens (AUTH_TOKEN/CT0 env vars). Bluesky search uses optional app password (BSKY_HANDLE/BSKY_APP_PASSWORD env vars - create at bsky.app/settings/app-passwords). All credential usage and data writes are documented in the [Security & Permissions](#security--permissions) section. @@ -867,26 +867,30 @@ Store your plan as `QUERY_PLAN_JSON` - you'll pass it to the script in the next **IMPORTANT: Include `--x-handle={RESOLVED_HANDLE}` in the command. For comparison mode: Pass `--x-handle={TOPIC_A_HANDLE}` to the first pass, `--x-handle={TOPIC_B_HANDLE}` to the second pass, and both to the head-to-head pass. Also include `--subreddits={RESOLVED_SUBREDDITS}`, `--tiktok-hashtags={RESOLVED_HASHTAGS}`, `--tiktok-creators={RESOLVED_TIKTOK_CREATORS}`, and `--ig-creators={RESOLVED_IG_CREATORS}` from Step 0.55. Omit any flag where the value was not resolved (empty).** ```bash -# PIN SKILL_ROOT to the public plugin cache (highest-version dir wins on upgrade). -# DO NOT write your own path-discovery loop. The 2026-04-18 Peter Steinberger run 1 -# regression was caused by a custom discovery loop landing on ~/.openclaw/skills/last30days/ -# (a stale copy from a private-repo sync pattern). That path contains a pre-plan-007 -# engine and produces non-canonical output. This pinned resolution ignores every stale -# copy (~/.openclaw/, ~/.agents/, ~/.codex/) and picks the plugin cache exclusively. -SKILL_ROOT="$(ls -d "$HOME/.claude/plugins/cache/last30days-skill/last30days/"*/ 2>/dev/null | sort -V | tail -1)" +# PIN SKILL_ROOT to an installed plugin cache first (highest-version dir wins on upgrade). +# Prefer Codex's skill package path when installed as a Codex plugin. Keep the Claude +# plugin-root fallback for other hosts, then fall back to a repo checkout. +SKILL_ROOT="$(ls -d "$HOME/.codex/plugins/cache/"*/last30days/*/skills/last30days/ 2>/dev/null | sort -V | tail -1)" SKILL_ROOT="${SKILL_ROOT%/}" -# Fallback for repo checkout / Gemini / Codex hosts where the plugin cache does not exist. -# Only runs if the public plugin cache is missing entirely. +# Fallback for Claude plugin cache. if [ -z "$SKILL_ROOT" ] || [ ! -f "$SKILL_ROOT/scripts/last30days.py" ]; then - for dir in "." "${CLAUDE_PLUGIN_ROOT:-}" "${GEMINI_EXTENSION_DIR:-}"; do + CLAUDE_PLUGIN_ROOT="$(ls -d "$HOME/.claude/plugins/cache/last30days-skill/last30days/"*/ 2>/dev/null | sort -V | tail -1)" + CLAUDE_PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT%/}" + [ -n "$CLAUDE_PLUGIN_ROOT" ] && [ -f "$CLAUDE_PLUGIN_ROOT/scripts/last30days.py" ] && SKILL_ROOT="$CLAUDE_PLUGIN_ROOT" +fi + +# Fallback for repo checkout / Gemini / local development hosts where the plugin cache does not exist. +if [ -z "$SKILL_ROOT" ] || [ ! -f "$SKILL_ROOT/scripts/last30days.py" ]; then + for dir in "." "./skills/last30days" "${CLAUDE_PLUGIN_ROOT:-}" "${GEMINI_EXTENSION_DIR:-}"; do [ -n "$dir" ] && [ -f "$dir/scripts/last30days.py" ] && SKILL_ROOT="$dir" && break done fi if [ -z "${SKILL_ROOT:-}" ] || [ ! -f "$SKILL_ROOT/scripts/last30days.py" ]; then - echo "ERROR: Could not find scripts/last30days.py in public plugin cache or repo checkout" >&2 - echo "Expected: $HOME/.claude/plugins/cache/last30days-skill/last30days/{VERSION}/scripts/last30days.py" >&2 + echo "ERROR: Could not find scripts/last30days.py in Codex/Claude plugin cache or repo checkout" >&2 + echo "Expected Codex: $HOME/.codex/plugins/cache/{MARKETPLACE}/last30days/{VERSION}/skills/last30days/scripts/last30days.py" >&2 + echo "Expected Claude: $HOME/.claude/plugins/cache/last30days-skill/last30days/{VERSION}/scripts/last30days.py" >&2 exit 1 fi diff --git a/agents/openai.yaml b/skills/last30days/agents/openai.yaml similarity index 100% rename from agents/openai.yaml rename to skills/last30days/agents/openai.yaml diff --git a/assets/aging-portrait.jpeg b/skills/last30days/assets/aging-portrait.jpeg similarity index 100% rename from assets/aging-portrait.jpeg rename to skills/last30days/assets/aging-portrait.jpeg diff --git a/assets/claude-code-rap.mp3 b/skills/last30days/assets/claude-code-rap.mp3 similarity index 100% rename from assets/claude-code-rap.mp3 rename to skills/last30days/assets/claude-code-rap.mp3 diff --git a/assets/dog-as-human.png b/skills/last30days/assets/dog-as-human.png similarity index 100% rename from assets/dog-as-human.png rename to skills/last30days/assets/dog-as-human.png diff --git a/assets/dog-original.jpeg b/skills/last30days/assets/dog-original.jpeg similarity index 100% rename from assets/dog-original.jpeg rename to skills/last30days/assets/dog-original.jpeg diff --git a/assets/swimmom-mockup.jpeg b/skills/last30days/assets/swimmom-mockup.jpeg similarity index 100% rename from assets/swimmom-mockup.jpeg rename to skills/last30days/assets/swimmom-mockup.jpeg diff --git a/scripts/briefing.py b/skills/last30days/scripts/briefing.py similarity index 100% rename from scripts/briefing.py rename to skills/last30days/scripts/briefing.py diff --git a/scripts/build-skill.sh b/skills/last30days/scripts/build-skill.sh similarity index 65% rename from scripts/build-skill.sh rename to skills/last30days/scripts/build-skill.sh index 51d9139..bc3acfe 100755 --- a/scripts/build-skill.sh +++ b/skills/last30days/scripts/build-skill.sh @@ -1,13 +1,14 @@ #!/usr/bin/env bash # build-skill.sh - package this repo as a claude.ai-upload-ready .skill file -# Usage: bash scripts/build-skill.sh (run from repo root) +# Usage: bash skills/last30days/scripts/build-skill.sh (run from repo root) # # Produces dist/last30days.skill, a zip with a single top-level `last30days/` -# directory containing SKILL.md and the scripts/ runtime. See +# directory containing SKILL.md and the scripts/ runtime from skills/last30days. +# See # docs/plans/2026-04-14-001-fix-skill-upload-200-file-limit-plan.md. set -euo pipefail -REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +REPO_ROOT="$(cd "$(dirname "$0")/../../.." && pwd)" cd "$REPO_ROOT" if ! git diff --quiet || ! git diff --cached --quiet; then @@ -17,14 +18,7 @@ fi mkdir -p dist OUT="dist/last30days.skill" -git archive --format=zip --prefix=last30days/ --output="$OUT" HEAD - -# claude.ai's .skill bundle only needs the root SKILL.md + scripts/ runtime. -# Claude Code needs skills/ and .claude-plugin/ in the git archive -# (that's why they're NOT in .gitattributes export-ignore), but the .skill -# bundle must strip them to keep a single canonical SKILL.md and stay under -# the 200-file cap. -zip -d "$OUT" "last30days/skills/*" "last30days/.claude-plugin/*" > /dev/null 2>&1 || true +git archive --format=zip --prefix=last30days/ --output="$OUT" HEAD:skills/last30days COUNT=$(unzip -l "$OUT" | tail -1 | awk '{print $2}') SIZE=$(du -h "$OUT" | cut -f1) diff --git a/scripts/compare.sh b/skills/last30days/scripts/compare.sh similarity index 91% rename from scripts/compare.sh rename to skills/last30days/scripts/compare.sh index 359dd8a..880b509 100755 --- a/scripts/compare.sh +++ b/skills/last30days/scripts/compare.sh @@ -1,6 +1,6 @@ #!/bin/bash # A/B test runner: public release vs private beta -# Usage: bash scripts/compare.sh "Kanye West" +# Usage: bash skills/last30days/scripts/compare.sh "Kanye West" # # Runs /last30days (public release) and /last30days-beta (private beta) # sequentially with a 30s gap, saves raw results with distinct suffixes, @@ -9,8 +9,8 @@ set -e if [ $# -eq 0 ]; then - echo "Usage: bash scripts/compare.sh " - echo " Example: bash scripts/compare.sh Kevin Rose" + echo "Usage: bash skills/last30days/scripts/compare.sh " + echo " Example: bash skills/last30days/scripts/compare.sh Kevin Rose" exit 1 fi TOPIC="$*" diff --git a/scripts/evaluate_search_quality.py b/skills/last30days/scripts/evaluate_search_quality.py similarity index 98% rename from scripts/evaluate_search_quality.py rename to skills/last30days/scripts/evaluate_search_quality.py index a16dc3a..55d62f6 100644 --- a/scripts/evaluate_search_quality.py +++ b/skills/last30days/scripts/evaluate_search_quality.py @@ -22,7 +22,8 @@ from lib import env as envlib from lib import schema -REPO_ROOT = Path(__file__).resolve().parent.parent +SKILL_ROOT = Path(__file__).resolve().parents[1] +REPO_ROOT = Path(__file__).resolve().parents[3] EVAL_TOPICS_FILE = REPO_ROOT / "fixtures" / "eval_topics.json" @@ -307,7 +308,10 @@ def create_eval_env() -> dict[str, str]: def run_last30days(repo_dir: Path, topic: str, *, search: str, timeout_seconds: int, quick: bool, mock: bool, env: dict[str, str]) -> dict[str, Any]: - cmd = [sys.executable, "scripts/last30days.py", topic, "--emit=json"] + engine = repo_dir / "skills" / "last30days" / "scripts" / "last30days.py" + if not engine.exists(): + engine = repo_dir / "scripts" / "last30days.py" + cmd = [sys.executable, str(engine), topic, "--emit=json"] if search: cmd.extend(["--search", search]) if quick: diff --git a/scripts/last30days.py b/skills/last30days/scripts/last30days.py similarity index 100% rename from scripts/last30days.py rename to skills/last30days/scripts/last30days.py diff --git a/scripts/lib/__init__.py b/skills/last30days/scripts/lib/__init__.py similarity index 100% rename from scripts/lib/__init__.py rename to skills/last30days/scripts/lib/__init__.py diff --git a/scripts/lib/bird_x.py b/skills/last30days/scripts/lib/bird_x.py similarity index 100% rename from scripts/lib/bird_x.py rename to skills/last30days/scripts/lib/bird_x.py diff --git a/scripts/lib/bluesky.py b/skills/last30days/scripts/lib/bluesky.py similarity index 100% rename from scripts/lib/bluesky.py rename to skills/last30days/scripts/lib/bluesky.py diff --git a/scripts/lib/categories.py b/skills/last30days/scripts/lib/categories.py similarity index 100% rename from scripts/lib/categories.py rename to skills/last30days/scripts/lib/categories.py diff --git a/scripts/lib/chrome_cookies.py b/skills/last30days/scripts/lib/chrome_cookies.py similarity index 100% rename from scripts/lib/chrome_cookies.py rename to skills/last30days/scripts/lib/chrome_cookies.py diff --git a/scripts/lib/cluster.py b/skills/last30days/scripts/lib/cluster.py similarity index 100% rename from scripts/lib/cluster.py rename to skills/last30days/scripts/lib/cluster.py diff --git a/scripts/lib/competitors.py b/skills/last30days/scripts/lib/competitors.py similarity index 100% rename from scripts/lib/competitors.py rename to skills/last30days/scripts/lib/competitors.py diff --git a/scripts/lib/cookie_extract.py b/skills/last30days/scripts/lib/cookie_extract.py similarity index 100% rename from scripts/lib/cookie_extract.py rename to skills/last30days/scripts/lib/cookie_extract.py diff --git a/scripts/lib/dates.py b/skills/last30days/scripts/lib/dates.py similarity index 100% rename from scripts/lib/dates.py rename to skills/last30days/scripts/lib/dates.py diff --git a/scripts/lib/dedupe.py b/skills/last30days/scripts/lib/dedupe.py similarity index 100% rename from scripts/lib/dedupe.py rename to skills/last30days/scripts/lib/dedupe.py diff --git a/scripts/lib/entity_extract.py b/skills/last30days/scripts/lib/entity_extract.py similarity index 100% rename from scripts/lib/entity_extract.py rename to skills/last30days/scripts/lib/entity_extract.py diff --git a/scripts/lib/env.py b/skills/last30days/scripts/lib/env.py similarity index 100% rename from scripts/lib/env.py rename to skills/last30days/scripts/lib/env.py diff --git a/scripts/lib/fanout.py b/skills/last30days/scripts/lib/fanout.py similarity index 100% rename from scripts/lib/fanout.py rename to skills/last30days/scripts/lib/fanout.py diff --git a/scripts/lib/fusion.py b/skills/last30days/scripts/lib/fusion.py similarity index 100% rename from scripts/lib/fusion.py rename to skills/last30days/scripts/lib/fusion.py diff --git a/scripts/lib/github.py b/skills/last30days/scripts/lib/github.py similarity index 100% rename from scripts/lib/github.py rename to skills/last30days/scripts/lib/github.py diff --git a/scripts/lib/grounding.py b/skills/last30days/scripts/lib/grounding.py similarity index 100% rename from scripts/lib/grounding.py rename to skills/last30days/scripts/lib/grounding.py diff --git a/scripts/lib/hackernews.py b/skills/last30days/scripts/lib/hackernews.py similarity index 100% rename from scripts/lib/hackernews.py rename to skills/last30days/scripts/lib/hackernews.py diff --git a/scripts/lib/http.py b/skills/last30days/scripts/lib/http.py similarity index 100% rename from scripts/lib/http.py rename to skills/last30days/scripts/lib/http.py diff --git a/scripts/lib/instagram.py b/skills/last30days/scripts/lib/instagram.py similarity index 100% rename from scripts/lib/instagram.py rename to skills/last30days/scripts/lib/instagram.py diff --git a/scripts/lib/log.py b/skills/last30days/scripts/lib/log.py similarity index 100% rename from scripts/lib/log.py rename to skills/last30days/scripts/lib/log.py diff --git a/scripts/lib/normalize.py b/skills/last30days/scripts/lib/normalize.py similarity index 100% rename from scripts/lib/normalize.py rename to skills/last30days/scripts/lib/normalize.py diff --git a/scripts/lib/perplexity.py b/skills/last30days/scripts/lib/perplexity.py similarity index 100% rename from scripts/lib/perplexity.py rename to skills/last30days/scripts/lib/perplexity.py diff --git a/scripts/lib/pinterest.py b/skills/last30days/scripts/lib/pinterest.py similarity index 100% rename from scripts/lib/pinterest.py rename to skills/last30days/scripts/lib/pinterest.py diff --git a/scripts/lib/pipeline.py b/skills/last30days/scripts/lib/pipeline.py similarity index 100% rename from scripts/lib/pipeline.py rename to skills/last30days/scripts/lib/pipeline.py diff --git a/scripts/lib/planner.py b/skills/last30days/scripts/lib/planner.py similarity index 100% rename from scripts/lib/planner.py rename to skills/last30days/scripts/lib/planner.py diff --git a/scripts/lib/polymarket.py b/skills/last30days/scripts/lib/polymarket.py similarity index 100% rename from scripts/lib/polymarket.py rename to skills/last30days/scripts/lib/polymarket.py diff --git a/scripts/lib/preflight.py b/skills/last30days/scripts/lib/preflight.py similarity index 100% rename from scripts/lib/preflight.py rename to skills/last30days/scripts/lib/preflight.py diff --git a/scripts/lib/providers.py b/skills/last30days/scripts/lib/providers.py similarity index 100% rename from scripts/lib/providers.py rename to skills/last30days/scripts/lib/providers.py diff --git a/scripts/lib/quality_nudge.py b/skills/last30days/scripts/lib/quality_nudge.py similarity index 100% rename from scripts/lib/quality_nudge.py rename to skills/last30days/scripts/lib/quality_nudge.py diff --git a/scripts/lib/query.py b/skills/last30days/scripts/lib/query.py similarity index 100% rename from scripts/lib/query.py rename to skills/last30days/scripts/lib/query.py diff --git a/scripts/lib/reddit.py b/skills/last30days/scripts/lib/reddit.py similarity index 100% rename from scripts/lib/reddit.py rename to skills/last30days/scripts/lib/reddit.py diff --git a/scripts/lib/reddit_enrich.py b/skills/last30days/scripts/lib/reddit_enrich.py similarity index 100% rename from scripts/lib/reddit_enrich.py rename to skills/last30days/scripts/lib/reddit_enrich.py diff --git a/scripts/lib/reddit_public.py b/skills/last30days/scripts/lib/reddit_public.py similarity index 100% rename from scripts/lib/reddit_public.py rename to skills/last30days/scripts/lib/reddit_public.py diff --git a/scripts/lib/relevance.py b/skills/last30days/scripts/lib/relevance.py similarity index 100% rename from scripts/lib/relevance.py rename to skills/last30days/scripts/lib/relevance.py diff --git a/scripts/lib/render.py b/skills/last30days/scripts/lib/render.py similarity index 99% rename from scripts/lib/render.py rename to skills/last30days/scripts/lib/render.py index 98c9119..c2f336c 100644 --- a/scripts/lib/render.py +++ b/skills/last30days/scripts/lib/render.py @@ -12,7 +12,7 @@ from . import dates, schema def _skill_version() -> str: - """Read plugin version from .claude-plugin/plugin.json if available. + """Read plugin version from a plugin manifest if available. Tries nearest plugin.json by walking up from render.py's own location. Falls back to "?" if not found. This keeps the badge emission from @@ -20,12 +20,13 @@ def _skill_version() -> str: """ here = pathlib.Path(__file__).resolve() for parent in [here.parent, *here.parents]: - candidate = parent / ".claude-plugin" / "plugin.json" - if candidate.is_file(): - try: - return json.loads(candidate.read_text()).get("version", "?") - except (json.JSONDecodeError, OSError): - return "?" + for manifest_dir in (".codex-plugin", ".claude-plugin"): + candidate = parent / manifest_dir / "plugin.json" + if candidate.is_file(): + try: + return json.loads(candidate.read_text()).get("version", "?") + except (json.JSONDecodeError, OSError): + return "?" return "?" diff --git a/scripts/lib/rerank.py b/skills/last30days/scripts/lib/rerank.py similarity index 100% rename from scripts/lib/rerank.py rename to skills/last30days/scripts/lib/rerank.py diff --git a/scripts/lib/resolve.py b/skills/last30days/scripts/lib/resolve.py similarity index 100% rename from scripts/lib/resolve.py rename to skills/last30days/scripts/lib/resolve.py diff --git a/scripts/lib/safari_cookies.py b/skills/last30days/scripts/lib/safari_cookies.py similarity index 100% rename from scripts/lib/safari_cookies.py rename to skills/last30days/scripts/lib/safari_cookies.py diff --git a/scripts/lib/schema.py b/skills/last30days/scripts/lib/schema.py similarity index 100% rename from scripts/lib/schema.py rename to skills/last30days/scripts/lib/schema.py diff --git a/scripts/lib/setup_wizard.py b/skills/last30days/scripts/lib/setup_wizard.py similarity index 100% rename from scripts/lib/setup_wizard.py rename to skills/last30days/scripts/lib/setup_wizard.py diff --git a/scripts/lib/signals.py b/skills/last30days/scripts/lib/signals.py similarity index 100% rename from scripts/lib/signals.py rename to skills/last30days/scripts/lib/signals.py diff --git a/scripts/lib/snippet.py b/skills/last30days/scripts/lib/snippet.py similarity index 100% rename from scripts/lib/snippet.py rename to skills/last30days/scripts/lib/snippet.py diff --git a/scripts/lib/threads.py b/skills/last30days/scripts/lib/threads.py similarity index 100% rename from scripts/lib/threads.py rename to skills/last30days/scripts/lib/threads.py diff --git a/scripts/lib/tiktok.py b/skills/last30days/scripts/lib/tiktok.py similarity index 100% rename from scripts/lib/tiktok.py rename to skills/last30days/scripts/lib/tiktok.py diff --git a/scripts/lib/truthsocial.py b/skills/last30days/scripts/lib/truthsocial.py similarity index 100% rename from scripts/lib/truthsocial.py rename to skills/last30days/scripts/lib/truthsocial.py diff --git a/scripts/lib/ui.py b/skills/last30days/scripts/lib/ui.py similarity index 100% rename from scripts/lib/ui.py rename to skills/last30days/scripts/lib/ui.py diff --git a/scripts/lib/vendor/bird-search/LICENSE b/skills/last30days/scripts/lib/vendor/bird-search/LICENSE similarity index 100% rename from scripts/lib/vendor/bird-search/LICENSE rename to skills/last30days/scripts/lib/vendor/bird-search/LICENSE diff --git a/scripts/lib/vendor/bird-search/bird-search.mjs b/skills/last30days/scripts/lib/vendor/bird-search/bird-search.mjs similarity index 100% rename from scripts/lib/vendor/bird-search/bird-search.mjs rename to skills/last30days/scripts/lib/vendor/bird-search/bird-search.mjs diff --git a/scripts/lib/vendor/bird-search/lib/cookies.js b/skills/last30days/scripts/lib/vendor/bird-search/lib/cookies.js similarity index 100% rename from scripts/lib/vendor/bird-search/lib/cookies.js rename to skills/last30days/scripts/lib/vendor/bird-search/lib/cookies.js diff --git a/scripts/lib/vendor/bird-search/lib/features.json b/skills/last30days/scripts/lib/vendor/bird-search/lib/features.json similarity index 100% rename from scripts/lib/vendor/bird-search/lib/features.json rename to skills/last30days/scripts/lib/vendor/bird-search/lib/features.json diff --git a/scripts/lib/vendor/bird-search/lib/paginate-cursor.js b/skills/last30days/scripts/lib/vendor/bird-search/lib/paginate-cursor.js similarity index 100% rename from scripts/lib/vendor/bird-search/lib/paginate-cursor.js rename to skills/last30days/scripts/lib/vendor/bird-search/lib/paginate-cursor.js diff --git a/scripts/lib/vendor/bird-search/lib/query-ids.json b/skills/last30days/scripts/lib/vendor/bird-search/lib/query-ids.json similarity index 100% rename from scripts/lib/vendor/bird-search/lib/query-ids.json rename to skills/last30days/scripts/lib/vendor/bird-search/lib/query-ids.json diff --git a/scripts/lib/vendor/bird-search/lib/runtime-features.js b/skills/last30days/scripts/lib/vendor/bird-search/lib/runtime-features.js similarity index 100% rename from scripts/lib/vendor/bird-search/lib/runtime-features.js rename to skills/last30days/scripts/lib/vendor/bird-search/lib/runtime-features.js diff --git a/scripts/lib/vendor/bird-search/lib/runtime-query-ids.js b/skills/last30days/scripts/lib/vendor/bird-search/lib/runtime-query-ids.js similarity index 100% rename from scripts/lib/vendor/bird-search/lib/runtime-query-ids.js rename to skills/last30days/scripts/lib/vendor/bird-search/lib/runtime-query-ids.js diff --git a/scripts/lib/vendor/bird-search/lib/twitter-client-base.js b/skills/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-base.js similarity index 100% rename from scripts/lib/vendor/bird-search/lib/twitter-client-base.js rename to skills/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-base.js diff --git a/scripts/lib/vendor/bird-search/lib/twitter-client-constants.js b/skills/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-constants.js similarity index 100% rename from scripts/lib/vendor/bird-search/lib/twitter-client-constants.js rename to skills/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-constants.js diff --git a/scripts/lib/vendor/bird-search/lib/twitter-client-features.js b/skills/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-features.js similarity index 100% rename from scripts/lib/vendor/bird-search/lib/twitter-client-features.js rename to skills/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-features.js diff --git a/scripts/lib/vendor/bird-search/lib/twitter-client-search.js b/skills/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-search.js similarity index 100% rename from scripts/lib/vendor/bird-search/lib/twitter-client-search.js rename to skills/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-search.js diff --git a/scripts/lib/vendor/bird-search/lib/twitter-client-types.js b/skills/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-types.js similarity index 100% rename from scripts/lib/vendor/bird-search/lib/twitter-client-types.js rename to skills/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-types.js diff --git a/scripts/lib/vendor/bird-search/lib/twitter-client-utils.js b/skills/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-utils.js similarity index 100% rename from scripts/lib/vendor/bird-search/lib/twitter-client-utils.js rename to skills/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-utils.js diff --git a/scripts/lib/vendor/bird-search/package.json b/skills/last30days/scripts/lib/vendor/bird-search/package.json similarity index 100% rename from scripts/lib/vendor/bird-search/package.json rename to skills/last30days/scripts/lib/vendor/bird-search/package.json diff --git a/scripts/lib/xai_x.py b/skills/last30days/scripts/lib/xai_x.py similarity index 100% rename from scripts/lib/xai_x.py rename to skills/last30days/scripts/lib/xai_x.py diff --git a/scripts/lib/xiaohongshu_api.py b/skills/last30days/scripts/lib/xiaohongshu_api.py similarity index 100% rename from scripts/lib/xiaohongshu_api.py rename to skills/last30days/scripts/lib/xiaohongshu_api.py diff --git a/scripts/lib/xquik.py b/skills/last30days/scripts/lib/xquik.py similarity index 100% rename from scripts/lib/xquik.py rename to skills/last30days/scripts/lib/xquik.py diff --git a/scripts/lib/xurl_x.py b/skills/last30days/scripts/lib/xurl_x.py similarity index 100% rename from scripts/lib/xurl_x.py rename to skills/last30days/scripts/lib/xurl_x.py diff --git a/scripts/lib/youtube_yt.py b/skills/last30days/scripts/lib/youtube_yt.py similarity index 100% rename from scripts/lib/youtube_yt.py rename to skills/last30days/scripts/lib/youtube_yt.py diff --git a/scripts/store.py b/skills/last30days/scripts/store.py similarity index 100% rename from scripts/store.py rename to skills/last30days/scripts/store.py diff --git a/scripts/sync.sh b/skills/last30days/scripts/sync.sh similarity index 97% rename from scripts/sync.sh rename to skills/last30days/scripts/sync.sh index 09b696f..cbc7247 100755 --- a/scripts/sync.sh +++ b/skills/last30days/scripts/sync.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # sync.sh - Deploy last30days skill to all host locations -# Usage: bash scripts/sync.sh (run from repo root) +# Usage: bash skills/last30days/scripts/sync.sh (run from repo root) set -euo pipefail SRC="$(cd "$(dirname "$0")/.." && pwd)" @@ -11,7 +11,7 @@ COMMON_TARGETS=( # but local development needs the cache kept in sync with the repo. # Do NOT add ~/.claude/skills/last30days - it creates a duplicate # /last30days-3 in the slash command menu alongside the plugin version. - "$HOME/.claude/plugins/cache/last30days-skill-private/last30days-3/3.0.1" + "$HOME/.claude/plugins/cache/last30days-skill-private/last30days-3/3.0.10" "$HOME/.claude/plugins/cache/last30days-skill-private/last30days-3-nogem/3.0.0-nogem" "$HOME/.agents/skills/last30days" "$HOME/.codex/skills/last30days" diff --git a/scripts/test-v1-vs-v2.sh b/skills/last30days/scripts/test-v1-vs-v2.sh similarity index 100% rename from scripts/test-v1-vs-v2.sh rename to skills/last30days/scripts/test-v1-vs-v2.sh diff --git a/scripts/test_device_auth.py b/skills/last30days/scripts/test_device_auth.py similarity index 100% rename from scripts/test_device_auth.py rename to skills/last30days/scripts/test_device_auth.py diff --git a/scripts/verify_v3.py b/skills/last30days/scripts/verify_v3.py similarity index 87% rename from scripts/verify_v3.py rename to skills/last30days/scripts/verify_v3.py index 7cbc193..73319c7 100644 --- a/scripts/verify_v3.py +++ b/skills/last30days/scripts/verify_v3.py @@ -13,8 +13,11 @@ import time from pathlib import Path -REPO_ROOT = Path(__file__).resolve().parent.parent +SKILL_ROOT = Path(__file__).resolve().parents[1] +REPO_ROOT = Path(__file__).resolve().parents[3] PYTHON = sys.executable +ENGINE = SKILL_ROOT / "scripts" / "last30days.py" +EVALUATOR = SKILL_ROOT / "scripts" / "evaluate_search_quality.py" SMOKE_TOPIC = "openclaw skills" SMOKE_CASES = [ @@ -56,7 +59,16 @@ def verify_unit() -> dict[str, str]: "-m", "py_compile", *subprocess.run( - ["rg", "--files", "scripts", "tests", "-g", "*.py", "-g", "!scripts/lib/vendor/**"], + [ + "rg", + "--files", + "skills/last30days/scripts", + "tests", + "-g", + "*.py", + "-g", + "!skills/last30days/scripts/lib/vendor/**", + ], cwd=REPO_ROOT, text=True, capture_output=True, @@ -69,7 +81,7 @@ def verify_unit() -> dict[str, str]: def verify_diagnose() -> dict[str, object]: - result = run_command([PYTHON, "scripts/last30days.py", "--diagnose"], timeout=120) + result = run_command([PYTHON, str(ENGINE), "--diagnose"], timeout=120) return json.loads(result.stdout) @@ -80,7 +92,7 @@ def verify_smoke() -> list[dict[str, object]]: env["LAST30DAYS_REASONING_PROVIDER"] = provider start = time.time() result = run_command( - [PYTHON, "scripts/last30days.py", SMOKE_TOPIC, "--emit=json", *extra], + [PYTHON, str(ENGINE), SMOKE_TOPIC, "--emit=json", *extra], env=env, timeout=240, ) @@ -106,7 +118,7 @@ def verify_latency() -> dict[str, dict[str, object]]: for topic in LATENCY_TOPICS: start = time.time() run_command( - [PYTHON, "scripts/last30days.py", topic, "--emit=json", *extra], + [PYTHON, str(ENGINE), topic, "--emit=json", *extra], timeout=300, ) timings.append(time.time() - start) @@ -129,7 +141,7 @@ def verify_eval( ) -> dict[str, object]: cmd = [ PYTHON, - "scripts/evaluate_search_quality.py", + str(EVALUATOR), f"--baseline={baseline}", f"--candidate={candidate}", f"--output-dir={output_dir}", diff --git a/scripts/watchlist.py b/skills/last30days/scripts/watchlist.py similarity index 100% rename from scripts/watchlist.py rename to skills/last30days/scripts/watchlist.py diff --git a/tests/test_adversarial_v3.py b/tests/test_adversarial_v3.py index 1d5a9c1..0631c0d 100644 --- a/tests/test_adversarial_v3.py +++ b/tests/test_adversarial_v3.py @@ -9,7 +9,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import planner diff --git a/tests/test_bird_x.py b/tests/test_bird_x.py index c436908..92bb202 100644 --- a/tests/test_bird_x.py +++ b/tests/test_bird_x.py @@ -7,13 +7,13 @@ import textwrap import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib.bird_x import parse_bird_response REPO_ROOT = Path(__file__).resolve().parents[1] -VENDORED_BIRD = REPO_ROOT / "scripts" / "lib" / "vendor" / "bird-search" / "bird-search.mjs" +VENDORED_BIRD = REPO_ROOT / "skills" / "last30days" / "scripts" / "lib" / "vendor" / "bird-search" / "bird-search.mjs" class TestBirdXEngagementZero(unittest.TestCase): @@ -77,6 +77,8 @@ class TestVendoredBirdRuntime(unittest.TestCase): def test_browser_cookie_helpers_lazy_load_sweet_cookie(self): sweet_cookie_dir = ( REPO_ROOT + / "skills" + / "last30days" / "scripts" / "lib" / "vendor" @@ -130,7 +132,7 @@ class TestVendoredBirdRuntime(unittest.TestCase): extractCookiesFromSafari, extractCookiesFromChrome, extractCookiesFromFirefox, - } from "./scripts/lib/vendor/bird-search/lib/cookies.js"; + } from "./skills/last30days/scripts/lib/vendor/bird-search/lib/cookies.js"; const payload = await Promise.all([ extractCookiesFromSafari(), diff --git a/tests/test_bluesky.py b/tests/test_bluesky.py index 59bb096..cb3cd33 100644 --- a/tests/test_bluesky.py +++ b/tests/test_bluesky.py @@ -5,7 +5,7 @@ import unittest from pathlib import Path from unittest.mock import patch, MagicMock -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) from lib import bluesky diff --git a/tests/test_briefing_v3.py b/tests/test_briefing_v3.py index 2d4f4f4..ad77933 100644 --- a/tests/test_briefing_v3.py +++ b/tests/test_briefing_v3.py @@ -4,7 +4,7 @@ import unittest from pathlib import Path from unittest import mock -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) import briefing import store diff --git a/tests/test_categories.py b/tests/test_categories.py index 848abaa..45d6822 100644 --- a/tests/test_categories.py +++ b/tests/test_categories.py @@ -11,7 +11,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import categories from lib.categories import CATEGORY_PEERS, detect_category, peer_subs_for diff --git a/tests/test_category_integration.py b/tests/test_category_integration.py index 513c193..15bd8dc 100644 --- a/tests/test_category_integration.py +++ b/tests/test_category_integration.py @@ -19,7 +19,7 @@ from contextlib import redirect_stderr from pathlib import Path from unittest.mock import patch -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import resolve diff --git a/tests/test_cli_v3.py b/tests/test_cli_v3.py index b649715..f7120d5 100644 --- a/tests/test_cli_v3.py +++ b/tests/test_cli_v3.py @@ -12,7 +12,7 @@ from unittest import mock REPO_ROOT = Path(__file__).resolve().parents[1] -sys.path.insert(0, str(REPO_ROOT / "scripts")) +sys.path.insert(0, str(REPO_ROOT / "skills" / "last30days" / "scripts")) import last30days as cli from lib import schema @@ -53,7 +53,7 @@ class CliV3Tests(unittest.TestCase): def test_mock_json_cli(self): result = subprocess.run( - [sys.executable, "scripts/last30days.py", "test topic", "--mock", "--emit=json"], + [sys.executable, "skills/last30days/scripts/last30days.py", "test topic", "--mock", "--emit=json"], cwd=REPO_ROOT, capture_output=True, text=True, diff --git a/tests/test_cluster_v3.py b/tests/test_cluster_v3.py index 86b7583..2e9ac4e 100644 --- a/tests/test_cluster_v3.py +++ b/tests/test_cluster_v3.py @@ -2,7 +2,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import cluster, schema diff --git a/tests/test_dates.py b/tests/test_dates.py index 6d932ec..819ed26 100644 --- a/tests/test_dates.py +++ b/tests/test_dates.py @@ -6,7 +6,7 @@ from datetime import datetime, timedelta, timezone from pathlib import Path # Add lib to path -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) from lib import dates diff --git a/tests/test_dates_v3.py b/tests/test_dates_v3.py index 6d445ef..5331b31 100644 --- a/tests/test_dates_v3.py +++ b/tests/test_dates_v3.py @@ -3,7 +3,7 @@ import unittest from datetime import datetime, timedelta, timezone from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import dates diff --git a/tests/test_dedupe_v3.py b/tests/test_dedupe_v3.py index 3cb235f..e3852a1 100644 --- a/tests/test_dedupe_v3.py +++ b/tests/test_dedupe_v3.py @@ -4,7 +4,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import dedupe from lib.schema import SourceItem diff --git a/tests/test_entity_extract.py b/tests/test_entity_extract.py index 0114724..d960589 100644 --- a/tests/test_entity_extract.py +++ b/tests/test_entity_extract.py @@ -5,7 +5,7 @@ import unittest from pathlib import Path # Add lib to path -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) from lib import entity_extract diff --git a/tests/test_entity_extract_v3.py b/tests/test_entity_extract_v3.py index b779d2e..ed063c2 100644 --- a/tests/test_entity_extract_v3.py +++ b/tests/test_entity_extract_v3.py @@ -2,7 +2,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import entity_extract diff --git a/tests/test_env_cookies.py b/tests/test_env_cookies.py index 4be7d69..17a74b7 100644 --- a/tests/test_env_cookies.py +++ b/tests/test_env_cookies.py @@ -7,7 +7,7 @@ from unittest.mock import patch import pytest -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib.env import extract_browser_credentials, COOKIE_DOMAINS diff --git a/tests/test_env_v3.py b/tests/test_env_v3.py index ab8a70c..c5a5b86 100644 --- a/tests/test_env_v3.py +++ b/tests/test_env_v3.py @@ -4,7 +4,7 @@ import unittest from pathlib import Path from unittest import mock -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import bird_x, env diff --git a/tests/test_evaluator_v3.py b/tests/test_evaluator_v3.py index 69e03a5..5e8eb62 100644 --- a/tests/test_evaluator_v3.py +++ b/tests/test_evaluator_v3.py @@ -6,7 +6,7 @@ import unittest from pathlib import Path from unittest import mock -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) import evaluate_search_quality as evaluator diff --git a/tests/test_fusion_v3.py b/tests/test_fusion_v3.py index 618caf9..a0c745e 100644 --- a/tests/test_fusion_v3.py +++ b/tests/test_fusion_v3.py @@ -2,7 +2,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import fusion, schema diff --git a/tests/test_generate_synthesis_inputs_v3.py b/tests/test_generate_synthesis_inputs_v3.py index b7b2f20..cf179d0 100644 --- a/tests/test_generate_synthesis_inputs_v3.py +++ b/tests/test_generate_synthesis_inputs_v3.py @@ -5,12 +5,12 @@ import tempfile import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import schema -SCRIPT_PATH = Path(__file__).resolve().parents[1] / "scripts" / "generate-synthesis-inputs.py" +SCRIPT_PATH = Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts" / "generate-synthesis-inputs.py" def load_module(): diff --git a/tests/test_github.py b/tests/test_github.py index c943fda..b13d435 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -6,7 +6,7 @@ import unittest from pathlib import Path from unittest.mock import patch, MagicMock -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) from lib import github diff --git a/tests/test_grounding_v3.py b/tests/test_grounding_v3.py index e428c39..b9867d6 100644 --- a/tests/test_grounding_v3.py +++ b/tests/test_grounding_v3.py @@ -3,7 +3,7 @@ import unittest from pathlib import Path from unittest.mock import patch -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import grounding diff --git a/tests/test_hackernews.py b/tests/test_hackernews.py index 0b0132f..c8d1579 100644 --- a/tests/test_hackernews.py +++ b/tests/test_hackernews.py @@ -8,7 +8,7 @@ from unittest.mock import Mock, patch import pytest -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) from lib import hackernews diff --git a/tests/test_http_v3.py b/tests/test_http_v3.py index dd495e7..a50a61a 100644 --- a/tests/test_http_v3.py +++ b/tests/test_http_v3.py @@ -4,7 +4,7 @@ import unittest from pathlib import Path from unittest.mock import patch, MagicMock -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import http diff --git a/tests/test_instagram.py b/tests/test_instagram.py index 23c96b2..2fbdfbb 100644 --- a/tests/test_instagram.py +++ b/tests/test_instagram.py @@ -2,7 +2,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib.instagram import _parse_items diff --git a/tests/test_instagram_sc.py b/tests/test_instagram_sc.py index 6ca2b14..88ebf7f 100644 --- a/tests/test_instagram_sc.py +++ b/tests/test_instagram_sc.py @@ -5,7 +5,7 @@ import unittest from pathlib import Path # Add lib to path -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) from lib import instagram from lib.relevance import tokenize as _tokenize diff --git a/tests/test_internals_v3.py b/tests/test_internals_v3.py index 4bdd285..b05628d 100644 --- a/tests/test_internals_v3.py +++ b/tests/test_internals_v3.py @@ -9,7 +9,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import planner, rerank, render, signals, schema diff --git a/tests/test_normalize_v3.py b/tests/test_normalize_v3.py index 7c397a8..aa88d78 100644 --- a/tests/test_normalize_v3.py +++ b/tests/test_normalize_v3.py @@ -2,7 +2,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import normalize diff --git a/tests/test_pipeline_v3.py b/tests/test_pipeline_v3.py index cc16f35..08b6109 100644 --- a/tests/test_pipeline_v3.py +++ b/tests/test_pipeline_v3.py @@ -4,7 +4,7 @@ import unittest from pathlib import Path from unittest.mock import patch -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import pipeline from lib import http diff --git a/tests/test_planner_v3.py b/tests/test_planner_v3.py index fee2484..fffdd68 100644 --- a/tests/test_planner_v3.py +++ b/tests/test_planner_v3.py @@ -2,7 +2,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import planner diff --git a/tests/test_polymarket.py b/tests/test_polymarket.py index f29f99b..1105e17 100644 --- a/tests/test_polymarket.py +++ b/tests/test_polymarket.py @@ -7,7 +7,7 @@ from unittest.mock import Mock, patch import pytest -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) from lib import polymarket diff --git a/tests/test_preflight.py b/tests/test_preflight.py index 9cfe531..916cf8f 100644 --- a/tests/test_preflight.py +++ b/tests/test_preflight.py @@ -10,7 +10,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import preflight diff --git a/tests/test_providers_v3.py b/tests/test_providers_v3.py index c4d61a5..f5aaadf 100644 --- a/tests/test_providers_v3.py +++ b/tests/test_providers_v3.py @@ -3,7 +3,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import providers diff --git a/tests/test_query.py b/tests/test_query.py index 55c759c..60c1fc7 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -4,7 +4,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) from lib.query import NOISE_WORDS, extract_compound_terms, extract_core_subject diff --git a/tests/test_query_v3.py b/tests/test_query_v3.py index 1950272..79fcda6 100644 --- a/tests/test_query_v3.py +++ b/tests/test_query_v3.py @@ -2,7 +2,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import query diff --git a/tests/test_reddit.py b/tests/test_reddit.py index fcecc19..def066d 100644 --- a/tests/test_reddit.py +++ b/tests/test_reddit.py @@ -2,7 +2,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib.reddit import ( _extract_date, diff --git a/tests/test_reddit_enrich.py b/tests/test_reddit_enrich.py index c093f82..c9b2040 100644 --- a/tests/test_reddit_enrich.py +++ b/tests/test_reddit_enrich.py @@ -6,7 +6,7 @@ import unittest from pathlib import Path # Add lib to path -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) from lib import reddit_enrich diff --git a/tests/test_reddit_public.py b/tests/test_reddit_public.py index 5f55b36..af2005c 100644 --- a/tests/test_reddit_public.py +++ b/tests/test_reddit_public.py @@ -9,7 +9,7 @@ import sys import os # Ensure lib is importable -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "scripts")) +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "skills", "last30days", "scripts")) from lib import reddit_public diff --git a/tests/test_reddit_sc.py b/tests/test_reddit_sc.py index 9d38943..4578b65 100644 --- a/tests/test_reddit_sc.py +++ b/tests/test_reddit_sc.py @@ -5,7 +5,7 @@ import unittest from pathlib import Path # Add lib to path -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) from lib import reddit diff --git a/tests/test_regression.py b/tests/test_regression.py index b598be0..b5f379b 100644 --- a/tests/test_regression.py +++ b/tests/test_regression.py @@ -10,7 +10,7 @@ REPO_ROOT = Path(__file__).resolve().parents[1] def run_mock_json(topic: str) -> dict: result = subprocess.run( - [sys.executable, "scripts/last30days.py", topic, "--mock", "--emit=json"], + [sys.executable, "skills/last30days/scripts/last30days.py", topic, "--mock", "--emit=json"], cwd=REPO_ROOT, capture_output=True, text=True, diff --git a/tests/test_relevance.py b/tests/test_relevance.py index 368b1d1..39765af 100644 --- a/tests/test_relevance.py +++ b/tests/test_relevance.py @@ -7,7 +7,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) from lib.relevance import STOPWORDS, SYNONYMS, token_overlap_relevance, tokenize diff --git a/tests/test_relevance_core_v3.py b/tests/test_relevance_core_v3.py index edba3a6..7bef858 100644 --- a/tests/test_relevance_core_v3.py +++ b/tests/test_relevance_core_v3.py @@ -2,7 +2,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import relevance diff --git a/tests/test_render_v3.py b/tests/test_render_v3.py index 0e040c2..0184812 100644 --- a/tests/test_render_v3.py +++ b/tests/test_render_v3.py @@ -2,7 +2,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import render, schema diff --git a/tests/test_rerank_fun.py b/tests/test_rerank_fun.py index b43a917..72a010b 100644 --- a/tests/test_rerank_fun.py +++ b/tests/test_rerank_fun.py @@ -5,7 +5,7 @@ from pathlib import Path import pytest -SCRIPTS_DIR = Path(__file__).parent.parent / "scripts" +SCRIPTS_DIR = Path(__file__).parent.parent / "skills" / "last30days" / "scripts" sys.path.insert(0, str(SCRIPTS_DIR)) from lib import schema diff --git a/tests/test_rerank_v3.py b/tests/test_rerank_v3.py index 852c262..a3ccb96 100644 --- a/tests/test_rerank_v3.py +++ b/tests/test_rerank_v3.py @@ -2,7 +2,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import rerank, schema diff --git a/tests/test_resolve.py b/tests/test_resolve.py index f497fde..742f657 100644 --- a/tests/test_resolve.py +++ b/tests/test_resolve.py @@ -5,7 +5,7 @@ from contextlib import redirect_stderr from pathlib import Path from unittest.mock import patch -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import resolve from lib.resolve import MAX_SUBS, _merge_category_peers diff --git a/tests/test_schema_v3.py b/tests/test_schema_v3.py index e394ba6..9997905 100644 --- a/tests/test_schema_v3.py +++ b/tests/test_schema_v3.py @@ -2,7 +2,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import schema diff --git a/tests/test_setup_openclaw.py b/tests/test_setup_openclaw.py index 4f1a2cb..250cc1d 100644 --- a/tests/test_setup_openclaw.py +++ b/tests/test_setup_openclaw.py @@ -9,7 +9,7 @@ from unittest.mock import patch, MagicMock, call import pytest # Add scripts dir to path -SCRIPTS_DIR = Path(__file__).parent.parent / "scripts" +SCRIPTS_DIR = Path(__file__).parent.parent / "skills" / "last30days" / "scripts" sys.path.insert(0, str(SCRIPTS_DIR)) from lib import setup_wizard diff --git a/tests/test_setup_wizard.py b/tests/test_setup_wizard.py index 086ce21..252e257 100644 --- a/tests/test_setup_wizard.py +++ b/tests/test_setup_wizard.py @@ -9,7 +9,7 @@ from unittest.mock import patch, MagicMock import pytest # Add scripts dir to path -SCRIPTS_DIR = Path(__file__).parent.parent / "scripts" +SCRIPTS_DIR = Path(__file__).parent.parent / "skills" / "last30days" / "scripts" sys.path.insert(0, str(SCRIPTS_DIR)) from lib import setup_wizard diff --git a/tests/test_signals_v3.py b/tests/test_signals_v3.py index 4535111..b3ea5bc 100644 --- a/tests/test_signals_v3.py +++ b/tests/test_signals_v3.py @@ -3,7 +3,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import schema, signals from lib.hackernews import parse_hackernews_response diff --git a/tests/test_snippet_v3.py b/tests/test_snippet_v3.py index 9bb4439..1de607d 100644 --- a/tests/test_snippet_v3.py +++ b/tests/test_snippet_v3.py @@ -2,7 +2,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import schema, snippet diff --git a/tests/test_store.py b/tests/test_store.py index 7b93c37..66a0f93 100644 --- a/tests/test_store.py +++ b/tests/test_store.py @@ -10,7 +10,7 @@ import pytest # Import the module under test import sys -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) import store from lib import schema diff --git a/tests/test_tiktok.py b/tests/test_tiktok.py index ea9095d..8b1ce4c 100644 --- a/tests/test_tiktok.py +++ b/tests/test_tiktok.py @@ -2,7 +2,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib.tiktok import _parse_items diff --git a/tests/test_truthsocial.py b/tests/test_truthsocial.py index e827eab..0843f40 100644 --- a/tests/test_truthsocial.py +++ b/tests/test_truthsocial.py @@ -4,7 +4,7 @@ import unittest from pathlib import Path from unittest.mock import patch, MagicMock -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) from lib import truthsocial diff --git a/tests/test_ui_v3.py b/tests/test_ui_v3.py index 125e7dd..3797ae0 100644 --- a/tests/test_ui_v3.py +++ b/tests/test_ui_v3.py @@ -6,7 +6,7 @@ from contextlib import redirect_stderr from pathlib import Path from unittest import mock -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib import ui diff --git a/tests/test_verify_v3.py b/tests/test_verify_v3.py index f985ea2..e019f1d 100644 --- a/tests/test_verify_v3.py +++ b/tests/test_verify_v3.py @@ -4,7 +4,7 @@ from pathlib import Path def load_verify_module(): - path = Path(__file__).resolve().parents[1] / "scripts" / "verify_v3.py" + path = Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts" / "verify_v3.py" spec = importlib.util.spec_from_file_location("verify_v3_module", path) module = importlib.util.module_from_spec(spec) assert spec and spec.loader diff --git a/tests/test_version_consistency.py b/tests/test_version_consistency.py index dfa446b..b4ec79d 100644 --- a/tests/test_version_consistency.py +++ b/tests/test_version_consistency.py @@ -4,10 +4,11 @@ from pathlib import Path ROOT = Path(__file__).resolve().parents[1] +SKILL_ROOT = ROOT / "skills" / "last30days" def _skill_version() -> str: - text = (ROOT / "SKILL.md").read_text(encoding="utf-8") + text = (SKILL_ROOT / "SKILL.md").read_text(encoding="utf-8") match = re.search(r'^version:\s*"([^"]+)"\s*$', text, re.MULTILINE) if not match: raise AssertionError("SKILL.md version frontmatter not found") @@ -16,18 +17,18 @@ def _skill_version() -> str: class TestVersionConsistency(unittest.TestCase): def test_root_skill_header_matches_frontmatter_version(self) -> None: - text = (ROOT / "SKILL.md").read_text(encoding="utf-8") + text = (SKILL_ROOT / "SKILL.md").read_text(encoding="utf-8") version = _skill_version() self.assertIn(f"# last30days v{version}:", text) def test_sync_cache_path_uses_skill_version(self) -> None: - sync_text = (ROOT / "scripts" / "sync.sh").read_text(encoding="utf-8") + sync_text = (SKILL_ROOT / "scripts" / "sync.sh").read_text(encoding="utf-8") version = _skill_version() self.assertIn(f'last30days-3/{version}"', sync_text) def test_memory_save_dir_uses_single_env_variable(self) -> None: - skill_text = (ROOT / "SKILL.md").read_text(encoding="utf-8") - compare_text = (ROOT / "scripts" / "compare.sh").read_text(encoding="utf-8") + skill_text = (SKILL_ROOT / "SKILL.md").read_text(encoding="utf-8") + compare_text = (SKILL_ROOT / "scripts" / "compare.sh").read_text(encoding="utf-8") default_assignment = 'LAST30DAYS_MEMORY_DIR="${LAST30DAYS_MEMORY_DIR:-$HOME/Documents/Last30Days}"' self.assertIn(default_assignment, skill_text) diff --git a/tests/test_watchlist_commands.py b/tests/test_watchlist_commands.py index a162e11..b86a5ee 100644 --- a/tests/test_watchlist_commands.py +++ b/tests/test_watchlist_commands.py @@ -10,7 +10,7 @@ from unittest.mock import Mock, patch import pytest -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) import store import watchlist diff --git a/tests/test_watchlist_delivery.py b/tests/test_watchlist_delivery.py index 7cf7486..a316b24 100644 --- a/tests/test_watchlist_delivery.py +++ b/tests/test_watchlist_delivery.py @@ -6,7 +6,7 @@ from unittest.mock import Mock, patch import pytest -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) import watchlist diff --git a/tests/test_xai_x.py b/tests/test_xai_x.py index eaa5ca0..ab0c90b 100644 --- a/tests/test_xai_x.py +++ b/tests/test_xai_x.py @@ -3,7 +3,7 @@ import sys import unittest from pathlib import Path -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib.xai_x import parse_x_response diff --git a/tests/test_xquik.py b/tests/test_xquik.py index b54d097..27439ed 100644 --- a/tests/test_xquik.py +++ b/tests/test_xquik.py @@ -3,7 +3,7 @@ import unittest from pathlib import Path from unittest.mock import patch -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "skills" / "last30days" / "scripts")) from lib.xquik import ( DEPTH_CONFIG, diff --git a/tests/test_youtube_relevance.py b/tests/test_youtube_relevance.py index 51e2ceb..183314b 100644 --- a/tests/test_youtube_relevance.py +++ b/tests/test_youtube_relevance.py @@ -5,7 +5,7 @@ import unittest from pathlib import Path # Add lib to path -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) from lib.relevance import token_overlap_relevance as _compute_relevance, tokenize as _tokenize diff --git a/tests/test_youtube_yt.py b/tests/test_youtube_yt.py index 504ef9a..a68ab86 100644 --- a/tests/test_youtube_yt.py +++ b/tests/test_youtube_yt.py @@ -8,7 +8,7 @@ import urllib.error from pathlib import Path from unittest import mock -sys.path.insert(0, str(Path(__file__).parent.parent / "scripts")) +sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts")) from lib import youtube_yt diff --git a/uv.lock b/uv.lock index 1280b15..f8f7825 100644 --- a/uv.lock +++ b/uv.lock @@ -197,7 +197,7 @@ wheels = [ [[package]] name = "last30days-skill" -version = "3.0.0" +version = "3.0.10" source = { virtual = "." } dependencies = [ { name = "requests" },