Commit Graph

133 Commits

Author SHA1 Message Date
Trevin Chow c1ca1a4e9d feat(skill): replace narrative verdict row with evidence-triggered prose beat
Review showed the "Setting the narrative?" verdict compared across
abstraction levels: a homepage tagline is deliberately broad
("financial infrastructure" covers a chargebacks thread), so
tagline-vs-thread alignment verdicts are unfalsifiable and carry no
information. The signal now ships as PROSE in the entity's narrative
section, fires only when the month's evidence directly bears on the
pitch (supports a specific claim, cuts against one, or is squarely
about the pitched ground), and stays SILENT when the pulse is
orthogonal - omission over a manufactured connection. Claims are
tested at matched altitude (specific claim vs specific thread) and
stay windowed (no trend verbs one 30-day window can't support). The
positioning fetch step survives unchanged and now also grounds the
"What it is" row and brand-noise rejection. All scope gating (people
never, ownerless topics excluded, no pitch from memory) carries over.
2026-06-09 17:14:31 -07:00
Trevin Chow 57860aff1c feat(skill): scope narrative lens to first-party entities, gate on fetched positioning
The lens criterion is now explicit: an identifiable first party with a
fetchable public pitch - companies, products, services. People NEVER
qualify, even founders whose companies would (MrBeast the company can
get the lens; Jimmy Donaldson the person cannot; "Garry Tan vs Sam
Altman" gets N/A across the row). Ownerless topics (Bitcoin) fail the
same test - a foundation or fan site is not an authoritative first
party. Comparison-row verdicts are also artifact-gated to match the
single-entity beat: a verdict requires positioning fetched THIS run;
if item 6 couldn't run (no WebSearch), the cell is Unclear - the pitch
is never supplied from memory.
2026-06-09 16:33:29 -07:00
Trevin Chow 6a92f63a56 fix(rerank): ground entity-miss demotion on head token, not full phrase
The entity-grounding demotion required the full multi-word primary
entity as a contiguous substring, so on-entity items missing a trailing
search descriptor were buried: a 323-pt HN thread "Stripe is friendly
to 'friendly fraud'" scored 0 on a "Stripe payments" query. New
_entity_grounded helper keys on the brand head token; items that never
name the brand still miss it and stay demoted. reddit_keyless
_slot_priority, which had re-implemented the old check while claiming
to mirror rerank's signal, now calls the shared helper so the two
paths cannot diverge.
2026-06-09 16:24:16 -07:00
Trevin Chow fd0e47d99f feat(skill): add "Setting the narrative?" lens for company/product topics
Comparison tables gain a narrative axis judging whether each entity's
community conversation is about what the entity pitches or about
something else (pricing, rivals, an incident). Backed by a new
mandatory Step 0.55 research item that fetches each entity's CURRENT
first-party positioning (RESOLVED_POSITIONING) instead of relying on
memory, and a narrative-check synthesis beat for single-entity company
runs. The mismatch is the signal: companies usually don't control
their own conversation.
2026-06-09 16:24:07 -07:00
Matt Van Horn 122158415a chore(release): v3.3.2 (#485)
Security / Dependency audit (push) Has been cancelled
Security / Secret scan (push) Has been cancelled
Validate / tests (push) Has been cancelled
* chore(release): v3.3.2

* chore(release): sync uv.lock for 3.3.2

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
2026-06-06 09:58:05 -07:00
Matt Van Horn 1bdc14878c fix(reddit): relevance-aware comment-enrichment slot selection in keyless path (#484)
* fix(reddit): relevance-aware comment-enrichment slot selection in keyless path

* docs(changelog): record relevance-aware enrichment fix under Unreleased

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
2026-06-06 09:44:07 -07:00
Matt Van Horn 4aae93ee5d fix: remove duplicate /last30days command wrapper (#461) (#462)
* fix: remove duplicate command wrapper so plugin exposes only the skill (#461)

The plugin shipped both commands/last30days.md and the skill under the
same name, so /last30 surfaced two `last30days` entries with two
different descriptions. Remove the wrapper; the skill already carries
its own argument-hint, so the /last30days <topic> picker UX is unchanged.

Also corrects the README install note that claimed Claude Code dedupes
the slash command across install methods (it does not), and bumps
3.3.0 -> 3.3.1 across plugin.json, marketplace.json, gemini-extension.json,
and SKILL.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: bump pyproject.toml version to 3.3.1 (manifest contract)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: update uv.lock for 3.3.1 version bump

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 00:33:16 -05:00
Matt Van Horn 8d3a9e4368 fix(reddit): restore free path via keyless RSS + shreddit scrape (.json is dead) (#457)
* test(reddit): add live RSS + shreddit comment fixtures

Captured from reddit.com on 2026-05-29 (search.rss listing + the
/svc/shreddit/comments partial), trimmed to a representative subset plus
two synthetic edge cases (deleted author, negative score) for offline
parser tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(http): add keyless get_text helper

Browser-UA text fetch for RSS/HTML endpoints; returns None on any HTTP or
network failure so tiered callers fall through cleanly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(reddit): keyless RSS discovery (search.rss + listing feeds)

Replaces the now-403 search.json with keyless Atom feeds, normalized to the
existing reddit_public post shape. Scores are placeholder zeros, backfilled
during shreddit enrichment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(reddit): keyless shreddit comment scraper

Parses <shreddit-comment> elements from /svc/shreddit/comments/r/{sub}/t3_{id}
(score/author/created/permalink + thingId-anchored body) into top comments,
matching reddit_enrich output. Replaces the dead {thread}.json enrichment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(reddit): tiered keyless orchestrator

Tier 0 one-shot .json (residential bonus) -> Tier 1 RSS discovery ->
Tier 2 shreddit enrichment. Returns [] never raises, so the SC backup
still engages when every keyless tier is empty.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(reddit): route free path through keyless pipeline (.json is dead)

search_reddit_public is now a thin shim over reddit_keyless, so pipeline.py
and other callers need no change. Removes the dead .json enrichment helpers;
search/_parse_posts remain as the demoted Tier 0 attempt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(reddit): request sort=top so true top comments land on page 1

Guarantees the highest-scored comments are captured even on large threads,
independent of Reddit's default comment sort. Local score re-sort remains.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(reddit): recover post upvote scores via keyless listing partials

The shreddit community-more-posts partial server-renders each post's score
and comment count (works for normal users, not IP-gated), unlike RSS or the
comments endpoint. Use it as a scored discovery source and to backfill scores
onto RSS-discovered posts (subreddits derived from results when not provided).
Ranking now uses real upvote score.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(reddit): listings backfill scores only on bare queries, not discovery

Caught running the full pipeline on a bare topic: deriving subreddits from
noisy RSS results and merging their top/hot listings flooded results with
high-upvote off-topic posts. Now derived-subreddit listings are used only to
backfill scores onto keyword-matched RSS posts; listing cards are merged as
discovery only when the caller explicitly provides subreddits (on-topic).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 14:43:56 -05:00
Trevin Chow 1e03af19e0 Merge pull request #423 from hnshah/ren/preserve-requested-quick-sources 2026-05-22 08:14:46 -07:00
Ilia Alshanetsky c5c0239dc9 refactor(github): resolve token once at pipeline boundary; pad no-token envelope
Greptile review (PR #438) flagged two issues:

1. search_github and enrich_with_comments both call _resolve_token,
   so when GITHUB_TOKEN is absent from config and env the gh-CLI
   subprocess (with its 5s timeout) fires twice per query.

2. The no-token early-return envelope `{"items": [], "error": "no token"}`
   was missing the `context` key that every other failure path includes,
   making the envelope shape inconsistent between the no-token and
   fetch-failure cases.

Fix 1: add public github.resolve_token(token) wrapping the existing
_resolve_token. Pipeline calls it once before search and enrich, so
both downstream calls receive an already-resolved (or already-None)
token and skip the fallback chain.

Fix 2: thread core/from_date/to_date/count through the no-token
envelope's `context` key, matching the fetch-failure envelope shape.
parse_github_response was already tolerant of the missing key, but
diagnostics callers that read response["context"]["..."] now get a
consistent dict in both error paths.

Reviewer's suggested code patch for issue 1 was a no-op (it kept the
same _resolve_token(token) call inside enrich_with_comments); the
underlying intent — resolve at the boundary — is what this commit
implements.
2026-05-19 12:35:40 -04:00
Ilia Alshanetsky 269dda9f6c refactor(github): split search_github / parse_github_response / enrich_with_comments
search_github returned a normalized List[dict] directly while every
other adapter follows search_X -> dict envelope, parse_X_response ->
list[dict]. The github branch in pipeline._retrieve_stream was the
only one that called search_* and returned (result, {}) without a
parse step. This blocked fixture-driven testing: there was no parse
function to feed a synthetic envelope to.

Split into three:

  search_github(...) -> Dict[str, Any]
    HTTP fetch only. Returns {"items": [raw items], "context": {core,
    from_date, to_date, count}}.

  parse_github_response(response) -> List[Dict[str, Any]]
    Pure function. Normalizes, date-filters, sorts by relevance.

  enrich_with_comments(items, depth, token) -> List[Dict[str, Any]]
    Public extraction of the old private _enrich_top_items. Resolves
    the token via env / gh CLI fallback so callers don't have to.

Pipeline now does the standard 3-call dance:

  response = github.search_github(...)
  items = github.parse_github_response(response)
  items = github.enrich_with_comments(items, depth=depth, token=token)

Keeping enrich_with_comments in parse_github_response would make parse
impure and force every fixture-driven test to either mock HTTP or
skip enrichment. Splitting it out matches the YouTube adapter's
pattern.
2026-05-19 12:18:47 -04:00
Hiten Shah 444e07d141 fix: preserve requested sources in quick plans 2026-05-17 15:54:45 -07:00
Trevin Chow d53121f035 Merge pull request #420 from hnshah/ren/watchlist-delta 2026-05-17 10:35:41 -07:00
Trevin Chow daca71f89e chore(release): v3.3.0
Release / build-and-release (push) Has been cancelled
~75 PRs merged since v3.2.0 plus 7 community fixes salvaged via PR triage.

Highlights:
- Install everywhere: npx skills add is canonical for Claude Code, Codex,
  Cursor, Gemini CLI, Copilot, Windsurf, and 50+ Agent Skills hosts.
- New emit mode: --emit=html for shareable HTML briefs.
- New source: Digg (auto-enabled when digg-pp-cli on PATH).
- New env vars: EXCLUDE_SOURCES, LAST30DAYS_YOUTUBE_SSH_HOST.
- New credential source: macOS Keychain.
- Reliability sweep: Reddit (4xx + URL prefix + multi-key auth), xAI
  error surfacing, Windows compatibility, YouTube/HN unblock,
  HTTP retries, planner gating, render fixes.
- Multi-harness reframe: AGENTS.md becomes canonical, CLAUDE.md points
  at it. SKILL_ROOT → SKILL_DIR substitution.

Breaking:
- .codex-plugin/plugin.json removed. Codex installs via npx skills add.
2026-05-17 09:25:46 -07:00
Kaustav Mishra d51e91ea26 fix(xai): surface API errors instead of silently returning empty results
parse_x_response was returning an empty items list whenever xAI returned
a 200 OK with a malformed payload — empty output text, missing "items"
key, or invalid JSON. The pipeline saw "successful response with zero
items" and quietly handed the user a degraded report with no indication
the API had failed. Now raise http.HTTPError on each of those branches
so _retrieve_stream's caller catches it and surfaces the failure in
errors_by_source, giving the user a visible signal that X didn't work.

Closes #155.

Co-authored-by: Kaustav Mishra <km.git007@gmail.com>
2026-05-17 09:20:37 -07:00
Trevin Chow 170b570cbc fix(reddit): re-raise HTTP 402 so fallback chain triggers
The ScrapeCreators 402 (payment required / credits exhausted) status
was being swallowed by the broad except Exception handlers in
_global_search, _subreddit_search, and fetch_post_comments, returning
[] instead of propagating. That caused users with exhausted credits
to silently get zero Reddit results instead of falling through to
the OpenAI / public Reddit JSON fallback chain in _search_reddit_thread.
Add 402 to the existing 401/403 re-raise list across all three
ScrapeCreators call paths. Closes #170.

Co-authored-by: Jonathan Oppenheim <no-reply@postquantum.space>
2026-05-17 09:20:37 -07:00
Trevin Chow 4bae05e7fa fix(reddit): use browser-like headers to fix HTTP 403 from urllib
Reddit's public JSON endpoint returns 403 to requests carrying the
generic User-Agent and minimal header set urllib defaults to, while
matching curl requests succeed. Switch to a current-Chrome User-Agent
and add Accept-Language / Accept-Encoding / Connection headers so the
fingerprint matches a normal browser. Reddit now serves gzip when
Accept-Encoding includes it, so decompress the body before JSON parse.
Update the user-agent assertion in tests/test_reddit_public.py to match
the new browser-like string. Closes #199.

Co-authored-by: Franco Carballar <francocarballar@gmail.com>
2026-05-17 09:20:37 -07:00
Trevin Chow a4f1f94802 fix(env): restore multi-key rotation for SCRAPECREATORS_API_KEY
Originally added in #268 to spread load across free-tier accounts when
SCRAPECREATORS_API_KEY is set to a comma-separated list. The 7-line block
was inadvertently dropped during the v3.0.6 consolidation (d14814a) even
though the changelog still advertised the feature. Re-apply the same
random.choice rotation in get_config() so user-facing behavior matches
the documented contract. Closes #287.

Co-authored-by: Eric Oberhofer <eric@oberhofer.io>
2026-05-17 09:20:37 -07:00
Trevin Chow 16ce073d0c fix(cli): keep child cleanup working on Windows
_cleanup_children() called os.killpg unconditionally — Windows doesn't
have killpg as an attribute on os, so the call raised AttributeError
(not caught by the existing OSError-family handler) and aborted cleanup.
Guard with hasattr(os, "killpg") and fall back to os.kill(pid, SIGTERM)
on platforms without process-group APIs. Closes #226. Refs #110.

Co-authored-by: gujishh <baiaoshh@163.com>
2026-05-17 09:20:02 -07:00
Trevin Chow 5994b4f76a fix(reddit): use removeprefix("r/") for subreddit names, not lstrip("r/")
str.lstrip("r/") treats its argument as a character set, stripping
leading r and / repeatedly. Subreddits starting with 'r' (e.g. r/robotics,
r/ruby) were silently mangled to 'obotics' / 'uby'. Replace with
str.removeprefix("r/") at all four call sites. Python 3.9+ pattern is
safe here — project requires 3.12. Closes #288.

Co-authored-by: Alex Key <alexanderkey0508@gmail.com>
2026-05-17 09:20:02 -07:00
Trevin Chow bb5e6efbf9 fix(scripts): replace hardcoded developer paths in test-v1-vs-v2.sh
REPO_DIR now derives from the script's location (with env-var override)
and the Claude binary is looked up via PATH (with CLAUDE env-var override)
instead of hardcoded to /Users/mvanhorn/.local/bin/claude. Works on any
checkout. Closes #297.

Co-authored-by: Dave Morin <dave@morin.com>
2026-05-17 09:20:02 -07:00
Hiten Shah 2502a19d46 fix(watchlist): clarify delta URL identity 2026-05-17 09:09:33 -07:00
Hiten Shah 0f280245ac feat(watchlist): show deltas between topic runs 2026-05-17 09:01:09 -07:00
Trevin Chow 1a8ffd4847 fix(quality_nudge): also guard Instagram silent-failure on INCLUDE_SOURCES allowlist 2026-05-17 01:03:55 -07:00
Trevin Chow 1814bb1967 fix(quality_nudge,bluesky): gate Instagram nudge on EXCLUDE_SOURCES + anchor bluesky tests at resolver 2026-05-17 01:03:55 -07:00
Daniel Zivkovic 44971a6aae feat: configuration enablement — env-var defaults + source resilience
Six small additive changes that make the skill correctly understand its
configured sources, plus tests + docs.

User-visible benefits

- LAST30DAYS_STORE=1 in .env turns persistence default-on without
  remembering --store on every invocation. Mirrors LAST30DAYS_DEBUG /
  LAST30DAYS_SKIP_PREFLIGHT convention.
- SCRAPE_CREATORS_API_KEY (with underscore) accepted as alias for the
  canonical name. Matches the spelling used in the vendor's own example
  code (Adrian Horning's repo); saves the next user the same diagnostic
  rabbit hole.
- Bluesky search now hits api.bsky.app (canonical AppView) instead of
  public.api.bsky.app (BunnyCDN-blocked public mirror as of 2026-05-04).
  BSKY_SEARCH_HOST env var lets users self-rescue future host migrations
  without a code release. Pre-fix: silent 0 Bluesky posts on every run.
- App-password format validator emits a one-shot stderr warning when
  BSKY_APP_PASSWORD doesn't match xxxx-xxxx-xxxx-xxxx form. Detect-don't-
  gate: createSession still accepts main passwords; the warning helps
  users identify a hygiene issue without breaking existing setups.
- Instagram retry on multi-token 500. SC's v2 reels endpoint wraps
  Google Search and 500's frequently on multi-word queries; a hashtag-
  form retry runs once before bubbling up. Documented vendor instability.
- LAST30DAYS_TRANSCRIPT_TIMEOUT env var (default 30s, was hardcoded 15s).
  SC's transcript endpoint regularly takes >15s; the old default was
  clipping legitimate responses.
- Silent-failure visibility: new bonus_errored field in the quality
  nudge fires when SC is configured but Instagram returned 0 items.
  Users see "Bonus source silent: Instagram" instead of unexplained
  absence.
- YouTube degraded-ratio false-positive fixed. Captions-disabled videos
  can never produce a transcript regardless of yt-dlp version; they're
  now subtracted from the denominator so a single uploader-disabled
  video doesn't false-trigger the "stale yt-dlp" nudge.
- urllib retry path: status_code attribute typo fix. The Instagram
  500-retry was dead code on the urllib branch (getattr(e, 'status', ...)
  while http.HTTPError exposes status_code).

Docs

- README.md: added /plugin install last30days step after marketplace add
  in three places (the install was previously omitted in the docs).
- CONFIGURATION.md: documented LAST30DAYS_STORE env var, added
  BSKY_SEARCH_HOST + app-password format section, mentioned
  LAST30DAYS_TRANSCRIPT_TIMEOUT in the Instagram source row.

Test plan

- 43 new unit tests across test_bluesky.py, test_instagram_sc.py,
  test_quality_nudge.py, test_youtube_yt.py
- 141 total tests passing in target suite
- Verified end-to-end: /last30days "Toronto resale condo market" with
  all 11+ sources active stored 35 new + 5 updated findings, all builder-
  PR-style accounts absent (organic agent voice in Instagram + TikTok
  results)

Backward compatibility

All changes are strictly additive. Optional kwargs default to None.
New env vars are opt-in. Existing CLI flags untouched. Existing callers
of public functions unaffected.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 01:03:15 -07:00
Trevin Chow aef6f35460 docs(providers): note why OpenRouter slug includes -preview suffix 2026-05-17 00:59:31 -07:00
GAOJIAN-0106 77bd235f64 fix: correct invalid OPENROUTER_DEFAULT model ID
google/gemini-flash-2.0 is not a valid OpenRouter model ID (segments reversed).
Every rerank and FunJudge call fails with HTTP 400 when REASONING_PROVIDER=openrouter
and LAST30DAYS_RERANK_MODEL is not explicitly pinned, silently falling back to
local-score heuristics.

OpenRouter error body:
  {"message":"google/gemini-flash-2.0 is not a valid model ID","code":400}

Switching to google/gemini-3.1-flash-lite-preview, which matches the
GEMINI_FLASH_LITE constant already used by the native Gemini provider on
line 12 of the same file. This makes the Gemini and OpenRouter providers
consistent and avoids a future divergence.

Validated with /last30days 'Claude Opus 4.7' --quick:
- Rerank/FunJudge HTTP 400 errors: 1 per run -> 0
- 'Why: fallback-local-score' markers in output: every cluster -> 0
- LLM-generated 'Why:' reasoning lines: 0 -> 11
2026-05-17 00:59:11 -07:00
Trevin Chow 71b1e8a411 Merge pull request #302 from nidhi-singh02/fix/github-repo-canonicalization
fix: Canonicalize ambiguous GitHub repo resolution for product comparisons
2026-05-17 00:57:05 -07:00
Trevin Chow 618458eb7e Merge pull request #320 from kaushikgopal/feat/brave-cookie-extraction
Add Brave browser support for X/Twitter cookie extraction
2026-05-17 00:56:44 -07:00
Trevin Chow 8cccd3e982 Merge pull request #334 from iamitp/codex/last-run-config-state
Preserve clean mode for last run state
2026-05-17 00:56:28 -07:00
Trevin Chow 8ccd778366 fix(canonicalization): predicate-based call lookup + skip double-canon on auto-resolve
Two findings from Greptile review on PR #302:

1. tests/test_cli_v3.py:302 - The test asserted run_mock.call_args_list[0]
   was the main runner's invocation, but fanout.run_competitor_fanout
   submits main + competitors to a ThreadPoolExecutor and iterates with
   as_completed. With zero-latency mocks, thread scheduling determines
   which pipeline.run call lands first, so the competitor's call could
   take index [0] and flake CI. Replace [0] indexing with a predicate
   match on the canonicalized github_repos kwargs.

2. skills/last30days/scripts/last30days.py:662 - When auto_resolve returns
   github_repos, it has already run canonicalize_github_repos(cap=5) and
   ranked by relevance. The downstream block then re-canonicalized with
   cap=None, which can re-sort by topic-slug match and clobber the
   auto_resolve relevance order. Guard the second canonicalization with
   a repos_from_auto_resolve flag so it only fires for user-supplied
   --github-repo input.
2026-05-17 00:51:21 -07:00
nidhi-singh02 d0b990e211 Canonicalize GitHub repo resolution for ambiguous product repos 2026-05-17 00:50:05 -07:00
Trevin Chow 0f03a67166 Merge pull request #343 from Bortlesboat/codex/use-sandboxed-safari-cookie-path
fix: prefer sandboxed Safari cookie path
2026-05-17 00:47:32 -07:00
Trevin Chow b296a65515 fix(last-run): guard python3 absence + hoist datetime + use context manager 2026-05-17 00:44:30 -07:00
Trevin Chow 8f565ee241 fix(chrome_cookies): sort Brave profiles by mtime, not alphabetically 2026-05-17 00:40:10 -07:00
Amit Patnaik dd7e6a1562 Preserve clean mode for last run state 2026-05-17 00:39:44 -07:00
KG 65313ce542 feat(cookies): add Brave browser cookie extraction for macOS
Brave uses identical v10 AES-128-CBC encryption to Chrome; only the
DB path (BraveSoftware/Brave-Browser) and Keychain service name
("Brave Safe Storage") differ. Refactored chrome_cookies.py to share
a single _extract_chromium_cookies_macos helper rather than duplicating
the decryption logic.

Profile discovery tries Default/ first, then scans numbered Profile N/
directories so non-default Brave profiles are covered.
2026-05-17 00:39:30 -07:00
Trevin Chow e8f23b4205 Merge pull request #340 from dzivkovi/fix/youtube-transcript-observability
fix(youtube): surface transcript-fetch ratio + add degraded nudge for stale yt-dlp
2026-05-17 00:31:37 -07:00
Bortlesboat 0656b868e7 fix safari cookie path resolution 2026-05-17 00:30:25 -07:00
Trevin Chow 16a4fa9c39 Merge pull request #341 from flyingice/main
fix(grounding): align Parallel AI search with current API schema
2026-05-17 00:27:50 -07:00
Trevin Chow 3b75ff1537 Merge pull request #354 from dinakars777/fix/parallel-web-backend-source
fix: route parallel web backend through grounding
2026-05-17 00:26:50 -07:00
Trevin Chow 321975e144 Merge pull request #356 from dinakars777/fix/allow-threads-pinterest-search
fix: honor explicit optional source requests
2026-05-17 00:26:25 -07:00
Trevin Chow 5f9c637bbe Merge pull request #336 from davemorin/fix/319-xquik-source-capabilities
fix(planner): register xquik in SOURCE_CAPABILITIES (#319)
2026-05-17 00:26:08 -07:00
Trevin Chow 6a15afd8e8 Update skills/last30days/scripts/last30days.py
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-05-17 00:23:53 -07:00
Trevin Chow 0ab7051bc5 fix(planner): also register xquik in QUICK_SOURCE_PRIORITY 2026-05-17 00:22:04 -07:00
Dave Morin 87bf3debcc fix(planner): register xquik in SOURCE_CAPABILITIES (#319)
Without this entry, the planner's _default_sources_for_intent() drops
xquik from the candidate pool for how_to / comparison / news intents
because SOURCE_CAPABILITIES.get("xquik", set()) returns the empty set.
Users with XQUIK_API_KEY set get zero Xquik results even though the
engine recognizes the key.

Mirrors the capabilities for "x" since both are X/Twitter-shaped
discussion + social sources.

Fixes #319
2026-05-17 00:21:36 -07:00
Trevin Chow 261ea5895c refactor(pipeline): remove dead threads-explicit-request branch 2026-05-17 00:20:56 -07:00
Trevin Chow 10f35f82fe fix(grounding): guard parallel excerpts against None + cap at 500 chars 2026-05-17 00:20:27 -07:00
Dinakar Sarbada 5b29b8f427 fix: honor explicit perplexity source requests 2026-05-17 00:20:25 -07:00