.{json,md}}.
diff --git a/package.json b/package.json
index a6a54e61..9b003848 100644
--- a/package.json
+++ b/package.json
@@ -4,6 +4,9 @@
"private": true,
"scripts": {
"docusaurus": "docusaurus",
+ "vendor-config": "rimraf .shared-config && git clone --depth 1 --branch main https://github.com/stackql/docusaurus-config.git .shared-config",
+ "prestart": "yarn vendor-config",
+ "prebuild": "yarn vendor-config",
"start": "docusaurus start",
"build": "docusaurus build",
"swizzle": "docusaurus swizzle",
@@ -22,7 +25,7 @@
"@mui/icons-material": "^5.2.0",
"@mui/material": "^5.2.5",
"@stackql/docusaurus-plugin-aeo": "^0.4.2",
- "@stackql/docusaurus-plugin-structured-data": "^1.5.1",
+ "@stackql/docusaurus-plugin-structured-data": "^1.6.0",
"clsx": "^1.1.1",
"prism-react-renderer": "^2.1.0",
"react": "^18.2.0",
@@ -39,5 +42,8 @@
"last 1 firefox version",
"last 1 safari version"
]
+ },
+ "devDependencies": {
+ "rimraf": "^6.0.1"
}
}
diff --git a/query-library/queries/github/activity/repo-stargazers.md b/query-library/queries/github/activity/repo-stargazers.md
new file mode 100644
index 00000000..a64e0a7d
--- /dev/null
+++ b/query-library/queries/github/activity/repo-stargazers.md
@@ -0,0 +1,74 @@
+---
+title: GitHub repository stargazers
+description: Lists the accounts that have starred a GitHub repository with login, profile URL and account type; the audience snapshot to take before a repository changes visibility or ownership.
+verb: select
+status: stable
+providers: [github]
+services: [activity]
+tags: [github, activity, community, stars]
+keywords: [stargazers, stars, who starred, star list, starred by, repository audience]
+intent_keywords:
+ - who starred this github repo
+ - list stargazers for a repository
+ - which users have starred my repo
+auth: [STACKQL_GITHUB_USERNAME, STACKQL_GITHUB_PASSWORD]
+params:
+ - name: owner
+ type: identifier
+ required: true
+ description: Repository owner (organization or user)
+ example: stackql
+ - name: repo
+ type: identifier
+ required: true
+ description: Repository name
+ example: stackql
+outputs:
+ - name: login
+ type: string
+ description: Stargazer login
+ - name: html_url
+ type: string
+ description: Profile URL of the stargazer
+ - name: type
+ type: string
+ description: Account type, User or Organization
+cost:
+ fan_out: none
+ expensive: false
+ notes: Paginated transparently
+related:
+ - github/repos/org-repos-list
+ - github/repos/contributor-analytics
+author: Jeffrey Aven
+author_company: StackQL Studios
+last_verified: "2026-10-05"
+---
+
+Lists every account that has starred a repository, one row per stargazer.
+Use it to capture a repository's audience before it changes visibility, moves
+to another owner or is archived: GitHub clears stars when a public repository
+is made private, and the `stargazers_count` on the repository record only
+says how many, not who.
+
+## Query
+
+```sql
+SELECT
+login,
+html_url,
+type
+FROM github.activity.repo_stargazers
+WHERE owner = '{{owner}}'
+AND repo = '{{repo}}';
+```
+
+## Notes
+
+The resource also exposes a starred_at column, but the provider requests the
+plain JSON media type rather than GitHub's star media type, so starred_at is
+always null. For the star count alone read stargazers_count from
+github.repos.repos instead of counting rows here. A 403 with the message
+"Resource not accessible by personal access token" comes from a fine-grained
+personal access token that does not cover the repository; use a classic token
+or extend the fine-grained token's repository access and Metadata permission.
diff --git a/query-library/scripts/build-artifacts.py b/query-library/scripts/build-artifacts.py
index 00949a02..63c0a580 100644
--- a/query-library/scripts/build-artifacts.py
+++ b/query-library/scripts/build-artifacts.py
@@ -31,7 +31,6 @@
import hashlib
import json
import re
-import shutil
import subprocess
import sys
from datetime import datetime, timezone
@@ -224,6 +223,24 @@ def build_index_md(entries, build_id: str) -> str:
return "\n".join(lines).rstrip() + "\n"
+def prune_stale_outputs(out_dir: Path, keep: set[Path]) -> None:
+ """Delete files under out_dir that this build did not write, then drop the
+ directories that are left empty, deepest first. A directory that cannot
+ be removed (a transient lock, seen on Windows) is left in place: git does
+ not track empty directories, so the committed tree is unaffected. A stale
+ file that cannot be deleted is an error - it would ship a removed entry.
+ """
+ for path in sorted(out_dir.rglob("*"), key=lambda p: len(p.parts), reverse=True):
+ if path.is_file():
+ if path not in keep:
+ path.unlink()
+ elif path.is_dir():
+ try:
+ path.rmdir() # succeeds only once empty
+ except OSError:
+ pass
+
+
def main() -> int:
if validate.main() != 0:
print("build-artifacts: validation failed, not emitting artifacts", file=sys.stderr)
@@ -235,34 +252,33 @@ def main() -> int:
build_id = compute_build_id(entries, docs, index_entries)
manifest = build_manifest(build_id, len(entries))
- if STATIC_OUT_DIR.exists():
- shutil.rmtree(STATIC_OUT_DIR)
- (STATIC_OUT_DIR / "queries").mkdir(parents=True)
+ # Write every output first, then remove whatever the previous build left
+ # that this one did not produce. The former rmtree-then-write was fragile
+ # on Windows: a transient handle on any subdirectory (editor file watcher,
+ # antivirus scanning the files just written) aborted the delete half-way
+ # and left the tree partially emptied under the pre-commit hook.
+ written: set[Path] = set()
+
+ def emit(path: Path, text: str) -> None:
+ path.parent.mkdir(parents=True, exist_ok=True)
+ path.write_text(text, encoding="utf-8", newline="\n")
+ written.add(path)
- (STATIC_OUT_DIR / "index.json").write_text(
+ emit(
+ STATIC_OUT_DIR / "index.json",
canonical_json({"build_id": build_id, "entries": index_entries}),
- encoding="utf-8",
- newline="\n",
- )
- (STATIC_OUT_DIR / "manifest.json").write_text(
- canonical_json(manifest), encoding="utf-8", newline="\n"
- )
- (STATIC_OUT_DIR / "index.md").write_text(
- build_index_md(entries, build_id), encoding="utf-8", newline="\n"
)
+ emit(STATIC_OUT_DIR / "manifest.json", canonical_json(manifest))
+ emit(STATIC_OUT_DIR / "index.md", build_index_md(entries, build_id))
# Site-facing extras: not part of the frozen machine contract and not
# hashed into build_id (presentation data only).
providers_summary = build_providers_summary(entries)
- (STATIC_OUT_DIR / "providers.json").write_text(
- canonical_json(providers_summary), encoding="utf-8", newline="\n"
- )
+ emit(STATIC_OUT_DIR / "providers.json", canonical_json(providers_summary))
write_provider_stubs(providers_summary)
for entry, doc in zip(entries, docs):
- out_json = STATIC_OUT_DIR / "queries" / f"{entry.id}.json"
- out_md = STATIC_OUT_DIR / "queries" / f"{entry.id}.md"
- out_json.parent.mkdir(parents=True, exist_ok=True)
- out_json.write_text(canonical_json(doc), encoding="utf-8", newline="\n")
- out_md.write_text(entry.raw, encoding="utf-8", newline="\n")
+ emit(STATIC_OUT_DIR / "queries" / f"{entry.id}.json", canonical_json(doc))
+ emit(STATIC_OUT_DIR / "queries" / f"{entry.id}.md", entry.raw)
+ prune_stale_outputs(STATIC_OUT_DIR, written)
print(
f"built {len(entries)} entries -> {STATIC_OUT_DIR.relative_to(REPO_ROOT)} "
diff --git a/query-library/scripts/precommit-artifacts.py b/query-library/scripts/precommit-artifacts.py
index 2f45a604..f84ec19a 100644
--- a/query-library/scripts/precommit-artifacts.py
+++ b/query-library/scripts/precommit-artifacts.py
@@ -4,15 +4,18 @@
Runs build-artifacts.py (which validates entries first), then checks git
status for the generated outputs: static/docs/query-library/ and the
-per-family .mdx stubs under query-library/. Any diff means the staged
-sources and the staged artifacts are out of sync - the same condition the
-CI freshness gate fails on. The rebuild is idempotent (build_id is a
-content hash; manifest timestamps only change when it does), so a clean
-tree passes with no side effects.
+per-family .mdx stubs under query-library/. Only the working-tree column of
+the porcelain status counts: a regenerated file that differs from the index
+(" M"), or an untracked one ("??"), means the staged sources and the staged
+artifacts are out of sync - the same condition the CI freshness gate fails
+on. Staged-only changes ("M ", "A ", "R ") are the artifact updates this
+commit legitimately carries and must pass. The rebuild is idempotent
+(build_id is a content hash; manifest timestamps only change when it does),
+so a clean tree passes with no side effects.
-pre-commit stashes unstaged changes before running hooks, so a diff here
-always means "regenerated artifacts were not staged", never "you have
-unrelated local edits".
+pre-commit stashes unstaged changes before running hooks, so a working-tree
+diff here always means "regenerated artifacts were not staged", never "you
+have unrelated local edits".
"""
from __future__ import annotations
@@ -41,10 +44,15 @@ def main() -> int:
print(status.stderr, file=sys.stderr)
return 1
+ # Porcelain v1 lines are "XY path": X is index-vs-HEAD, Y is
+ # worktree-vs-index. Stale means Y is set (modified/deleted in the
+ # worktree, or "??" untracked); a blank Y is a staged change and is fine.
stale = [
line
for line in status.stdout.splitlines()
- if line.strip() and line[3:].strip('"') not in HANDWRITTEN
+ if len(line) > 3
+ and line[1] != " "
+ and line[3:].strip('"') not in HANDWRITTEN
]
if stale:
print("Regenerated artifacts differ from what is staged:", file=sys.stderr)
diff --git a/sidebars-query-library.js b/sidebars-query-library.js
index 51ecd807..a7c23826 100644
--- a/sidebars-query-library.js
+++ b/sidebars-query-library.js
@@ -27,13 +27,13 @@ function labelFor(id) {
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
queryLibrarySidebar: [
- // Escape hatch back to the main stackql.io docs. '/docs' resolves under
- // baseUrl to the redirect stub at src/pages/docs/index.js, so the link
- // renders as internal (no external-link icon) and forwards to
- // stackql.io/docs.
+ // Escape hatch back to the main stackql.io docs. '/stackqldocs' is the
+ // shared chrome's redirect route for the main docs root (registered
+ // under baseUrl by the vendored redirects plugin), so the link renders
+ // as internal (no external-link icon) and forwards to stackql.io/.
{
type: 'link',
- href: '/docs',
+ href: '/stackqldocs',
label: 'Back to docs',
className: 'ql-sidebar-back-link',
},
diff --git a/src/components/ExternalRedirect/index.jsx b/src/components/ExternalRedirect/index.jsx
deleted file mode 100644
index 9a63f038..00000000
--- a/src/components/ExternalRedirect/index.jsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import React, {useEffect} from 'react';
-import Head from '@docusaurus/Head';
-
-// Body for the redirect stub pages under src/pages/. This site is proxied
-// under stackql.io/docs/query-library/, and its navbar/footer mirror the
-// main site's; the stubs give those main-site destinations real internal
-// routes (so links render without the external-link icon and satisfy the
-// broken-link checker) and immediately forward to the real page on
-// stackql.io. Stub routes are noindexed here and excluded from the sitemap
-// and structured-data emission in docusaurus.config.js.
-export default function ExternalRedirect({to}) {
- useEffect(() => {
- window.location.replace(to);
- }, [to]);
- return (
- <>
-
-
-
-
- Redirecting...
-
-
- Redirecting to {to}...
-
- >
- );
-}
diff --git a/src/pages/blog.js b/src/pages/blog.js
deleted file mode 100644
index 9f47c27f..00000000
--- a/src/pages/blog.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /blog an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/contact-us.js b/src/pages/contact-us.js
deleted file mode 100644
index eea5210e..00000000
--- a/src/pages/contact-us.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /contact-us an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/docs/command-line-usage/mcp.js b/src/pages/docs/command-line-usage/mcp.js
deleted file mode 100644
index 5de09c33..00000000
--- a/src/pages/docs/command-line-usage/mcp.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /docs/command-line-usage/mcp an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/docs/index.js b/src/pages/docs/index.js
deleted file mode 100644
index f7edaa34..00000000
--- a/src/pages/docs/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /docs an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/docs/mcp/embedded.js b/src/pages/docs/mcp/embedded.js
deleted file mode 100644
index a025b231..00000000
--- a/src/pages/docs/mcp/embedded.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /docs/mcp/embedded an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/docs/mcp/index.js b/src/pages/docs/mcp/index.js
deleted file mode 100644
index d71f7962..00000000
--- a/src/pages/docs/mcp/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /docs/mcp an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/install.js b/src/pages/install.js
deleted file mode 100644
index 7c4e0cbc..00000000
--- a/src/pages/install.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /install an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/providers/aws.js b/src/pages/providers/aws.js
deleted file mode 100644
index f77c71de..00000000
--- a/src/pages/providers/aws.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /providers/aws an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/providers/azure.js b/src/pages/providers/azure.js
deleted file mode 100644
index aa65f1f8..00000000
--- a/src/pages/providers/azure.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /providers/azure an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/providers/cloudflare.js b/src/pages/providers/cloudflare.js
deleted file mode 100644
index ca052aec..00000000
--- a/src/pages/providers/cloudflare.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /providers/cloudflare an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/providers/confluent.js b/src/pages/providers/confluent.js
deleted file mode 100644
index 85242fa2..00000000
--- a/src/pages/providers/confluent.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /providers/confluent an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/providers/databricks.js b/src/pages/providers/databricks.js
deleted file mode 100644
index 90d31317..00000000
--- a/src/pages/providers/databricks.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /providers/databricks an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/providers/github.js b/src/pages/providers/github.js
deleted file mode 100644
index 331e9311..00000000
--- a/src/pages/providers/github.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /providers/github an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/providers/google.js b/src/pages/providers/google.js
deleted file mode 100644
index f1c9b4ac..00000000
--- a/src/pages/providers/google.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /providers/google an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/providers/index.js b/src/pages/providers/index.js
deleted file mode 100644
index 614157ff..00000000
--- a/src/pages/providers/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /providers an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/providers/okta.js b/src/pages/providers/okta.js
deleted file mode 100644
index f971e837..00000000
--- a/src/pages/providers/okta.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /providers/okta an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/providers/openai.js b/src/pages/providers/openai.js
deleted file mode 100644
index c1856de6..00000000
--- a/src/pages/providers/openai.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /providers/openai an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/providers/snowflake.js b/src/pages/providers/snowflake.js
deleted file mode 100644
index 53dbde25..00000000
--- a/src/pages/providers/snowflake.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /providers/snowflake an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/stackql-deploy.js b/src/pages/stackql-deploy.js
deleted file mode 100644
index dfe68e04..00000000
--- a/src/pages/stackql-deploy.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /stackql-deploy an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/stackqldocs.js b/src/pages/stackqldocs.js
deleted file mode 100644
index 9377148f..00000000
--- a/src/pages/stackqldocs.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /stackqldocs an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/src/pages/tutorials.js b/src/pages/tutorials.js
deleted file mode 100644
index 81b46de8..00000000
--- a/src/pages/tutorials.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// GENERATED-STYLE stub: makes the main-site path /tutorials an internal
-// route on this site (no external-link icon in nav/footer) and forwards to
-// stackql.io. See src/components/ExternalRedirect.
-import React from 'react';
-import ExternalRedirect from '@site/src/components/ExternalRedirect';
-
-export default function RedirectPage() {
- return ;
-}
diff --git a/static/docs/query-library/index.json b/static/docs/query-library/index.json
index ece09ee4..82550b12 100644
--- a/static/docs/query-library/index.json
+++ b/static/docs/query-library/index.json
@@ -1,5 +1,5 @@
{
- "build_id": "ql-ea4d2cbf5ec44568",
+ "build_id": "ql-2e0083ba3d9afd03",
"entries": [
{
"id": "aws/cloud_control/resource-request-by-token",
@@ -1353,6 +1353,43 @@
"account_id"
]
},
+ {
+ "id": "github/activity/repo-stargazers",
+ "title": "GitHub repository stargazers",
+ "description": "Lists the accounts that have starred a GitHub repository with login, profile URL and account type; the audience snapshot to take before a repository changes visibility or ownership.",
+ "providers": [
+ "github"
+ ],
+ "services": [
+ "activity"
+ ],
+ "tags": [
+ "github",
+ "activity",
+ "community",
+ "stars"
+ ],
+ "keywords": [
+ "stargazers",
+ "stars",
+ "who starred",
+ "star list",
+ "starred by",
+ "repository audience"
+ ],
+ "intent_keywords": [
+ "who starred this github repo",
+ "list stargazers for a repository",
+ "which users have starred my repo"
+ ],
+ "mutation": false,
+ "verb": "select",
+ "status": "stable",
+ "required_params": [
+ "owner",
+ "repo"
+ ]
+ },
{
"id": "github/issues/issue-velocity",
"title": "GitHub issue creation velocity",
diff --git a/static/docs/query-library/index.md b/static/docs/query-library/index.md
index 65ede0d2..0aef5661 100644
--- a/static/docs/query-library/index.md
+++ b/static/docs/query-library/index.md
@@ -6,7 +6,7 @@
> (`.json`) consumed by the stackql MCP server's `query_library_search`
> and `query_library_get` tools.
-Build `ql-ea4d2cbf5ec44568` | 47 entries | machine catalogue:
+Build `ql-2e0083ba3d9afd03` | 48 entries | machine catalogue:
[index.json](https://stackql.io/docs/query-library/index.json) |
[manifest.json](https://stackql.io/docs/query-library/manifest.json)
@@ -62,6 +62,7 @@ Build `ql-ea4d2cbf5ec44568` | 47 entries | machine catalogue:
## github
+- [GitHub repository stargazers](https://stackql.io/docs/query-library/queries/github/activity/repo-stargazers) (select; params: owner, repo): Lists the accounts that have starred a GitHub repository with login, profile URL and account type; the audience snapshot to take before a repository changes visibility or ownership.
- [GitHub issue creation velocity](https://stackql.io/docs/query-library/queries/github/issues/issue-velocity) (select; draft; params: owner, repo): Sequences a repository's issues by creation date with a cumulative count and the gap since the previous issue; the intake rate and quiet-period view.
- [GitHub weekly commit activity trend](https://stackql.io/docs/query-library/queries/github/repos/commit-activity-trend) (select; params: owner, repo): Reports the last year of weekly commit counts with a four-week moving average and cumulative total; the project momentum view.
- [GitHub contributor ranking and concentration](https://stackql.io/docs/query-library/queries/github/repos/contributor-analytics) (select; params: owner, repo): Ranks a repository's contributors by commit count with running totals and share of the whole; the bus-factor and contribution concentration view.
diff --git a/static/docs/query-library/manifest.json b/static/docs/query-library/manifest.json
index 233532d6..07f7bace 100644
--- a/static/docs/query-library/manifest.json
+++ b/static/docs/query-library/manifest.json
@@ -1,6 +1,6 @@
{
- "build_id": "ql-ea4d2cbf5ec44568",
- "generated_at": "2026-07-31T21:03:45Z",
- "library_commit": "30430712",
- "entry_count": 47
+ "build_id": "ql-2e0083ba3d9afd03",
+ "generated_at": "2026-10-05T04:38:58Z",
+ "library_commit": "8d895876",
+ "entry_count": 48
}
diff --git a/static/docs/query-library/providers.json b/static/docs/query-library/providers.json
index 8aa3430a..ab348117 100644
--- a/static/docs/query-library/providers.json
+++ b/static/docs/query-library/providers.json
@@ -31,7 +31,7 @@
"id": "github",
"title": "GitHub",
"description": "Web-based version-control and collaboration.",
- "count": 5,
+ "count": 6,
"logo": "/img/providers/github/favicon.ico"
},
{
diff --git a/static/docs/query-library/queries/github/activity/repo-stargazers.json b/static/docs/query-library/queries/github/activity/repo-stargazers.json
new file mode 100644
index 00000000..42b5f817
--- /dev/null
+++ b/static/docs/query-library/queries/github/activity/repo-stargazers.json
@@ -0,0 +1,66 @@
+{
+ "id": "github/activity/repo-stargazers",
+ "title": "GitHub repository stargazers",
+ "description": "Lists the accounts that have starred a GitHub repository with login, profile URL and account type; the audience snapshot to take before a repository changes visibility or ownership.",
+ "mutation": false,
+ "verb": "select",
+ "status": "stable",
+ "providers": [
+ "github"
+ ],
+ "services": [
+ "activity"
+ ],
+ "auth": [
+ "STACKQL_GITHUB_USERNAME",
+ "STACKQL_GITHUB_PASSWORD"
+ ],
+ "params": [
+ {
+ "name": "owner",
+ "type": "identifier",
+ "required": true,
+ "description": "Repository owner (organization or user)",
+ "example": "stackql"
+ },
+ {
+ "name": "repo",
+ "type": "identifier",
+ "required": true,
+ "description": "Repository name",
+ "example": "stackql"
+ }
+ ],
+ "outputs": [
+ {
+ "name": "login",
+ "type": "string",
+ "description": "Stargazer login"
+ },
+ {
+ "name": "html_url",
+ "type": "string",
+ "description": "Profile URL of the stargazer"
+ },
+ {
+ "name": "type",
+ "type": "string",
+ "description": "Account type, User or Organization"
+ }
+ ],
+ "cost": {
+ "fan_out": "none",
+ "expensive": false,
+ "notes": "Paginated transparently"
+ },
+ "related": [
+ "github/repos/org-repos-list",
+ "github/repos/contributor-analytics"
+ ],
+ "template": "SELECT\nlogin,\nhtml_url,\ntype\nFROM github.activity.repo_stargazers\nWHERE owner = '{{owner}}'\nAND repo = '{{repo}}';",
+ "notes": "The resource also exposes a starred_at column, but the provider requests the plain JSON media type rather than GitHub's star media type, so starred_at is always null. For the star count alone read stargazers_count from github.repos.repos instead of counting rows here. A 403 with the message \"Resource not accessible by personal access token\" comes from a fine-grained personal access token that does not cover the repository; use a classic token or extend the fine-grained token's repository access and Metadata permission.",
+ "doc_url": "https://stackql.io/docs/query-library/queries/github/activity/repo-stargazers",
+ "last_verified": "2026-10-05",
+ "author": "Jeffrey Aven",
+ "author_company": "StackQL Studios"
+}
diff --git a/static/docs/query-library/queries/github/activity/repo-stargazers.md b/static/docs/query-library/queries/github/activity/repo-stargazers.md
new file mode 100644
index 00000000..a64e0a7d
--- /dev/null
+++ b/static/docs/query-library/queries/github/activity/repo-stargazers.md
@@ -0,0 +1,74 @@
+---
+title: GitHub repository stargazers
+description: Lists the accounts that have starred a GitHub repository with login, profile URL and account type; the audience snapshot to take before a repository changes visibility or ownership.
+verb: select
+status: stable
+providers: [github]
+services: [activity]
+tags: [github, activity, community, stars]
+keywords: [stargazers, stars, who starred, star list, starred by, repository audience]
+intent_keywords:
+ - who starred this github repo
+ - list stargazers for a repository
+ - which users have starred my repo
+auth: [STACKQL_GITHUB_USERNAME, STACKQL_GITHUB_PASSWORD]
+params:
+ - name: owner
+ type: identifier
+ required: true
+ description: Repository owner (organization or user)
+ example: stackql
+ - name: repo
+ type: identifier
+ required: true
+ description: Repository name
+ example: stackql
+outputs:
+ - name: login
+ type: string
+ description: Stargazer login
+ - name: html_url
+ type: string
+ description: Profile URL of the stargazer
+ - name: type
+ type: string
+ description: Account type, User or Organization
+cost:
+ fan_out: none
+ expensive: false
+ notes: Paginated transparently
+related:
+ - github/repos/org-repos-list
+ - github/repos/contributor-analytics
+author: Jeffrey Aven
+author_company: StackQL Studios
+last_verified: "2026-10-05"
+---
+
+Lists every account that has starred a repository, one row per stargazer.
+Use it to capture a repository's audience before it changes visibility, moves
+to another owner or is archived: GitHub clears stars when a public repository
+is made private, and the `stargazers_count` on the repository record only
+says how many, not who.
+
+## Query
+
+```sql
+SELECT
+login,
+html_url,
+type
+FROM github.activity.repo_stargazers
+WHERE owner = '{{owner}}'
+AND repo = '{{repo}}';
+```
+
+## Notes
+
+The resource also exposes a starred_at column, but the provider requests the
+plain JSON media type rather than GitHub's star media type, so starred_at is
+always null. For the star count alone read stargazers_count from
+github.repos.repos instead of counting rows here. A 403 with the message
+"Resource not accessible by personal access token" comes from a fine-grained
+personal access token that does not cover the repository; use a classic token
+or extend the fine-grained token's repository access and Metadata permission.
diff --git a/static/img/logo-original.svg b/static/img/logo-original.svg
deleted file mode 100644
index 1de09ec4..00000000
--- a/static/img/logo-original.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/static/img/logo-white.svg b/static/img/logo-white.svg
deleted file mode 100644
index 88c628e0..00000000
--- a/static/img/logo-white.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/yarn.lock b/yarn.lock
index 25ad474f..33405de1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2607,10 +2607,10 @@
dependencies:
gray-matter "^4.0.3"
-"@stackql/docusaurus-plugin-structured-data@^1.5.1":
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/@stackql/docusaurus-plugin-structured-data/-/docusaurus-plugin-structured-data-1.5.1.tgz#ab70476710cc01933994d6200c782865b697689b"
- integrity sha512-Q1RV9RxOwwDJyDfmQ0/ydTr2qAIkVIrlBIZ4JI2+cWJjPkaR6gSNBRYhk9b5z+2QsVXpDTxfdC/xyjXAPQbC0w==
+"@stackql/docusaurus-plugin-structured-data@^1.6.0":
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/@stackql/docusaurus-plugin-structured-data/-/docusaurus-plugin-structured-data-1.6.0.tgz#caffcf6bfede64679b4ee05132494605d9449c73"
+ integrity sha512-vRGJHITOP54bPNLas5iIBpMXDQidB2ILDBVOhdj/Et4O175ux+taj7ZEcvS5pGmLpaHhZUKGCYG8jIxkb/uu0A==
dependencies:
jsdom "^21.0.0"
@@ -3489,6 +3489,11 @@ balanced-match@^1.0.0:
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+balanced-match@^4.0.2:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-4.0.4.tgz#bfb10662feed8196a2c62e7c68e17720c274179a"
+ integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==
+
batch@0.6.1:
version "0.6.1"
resolved "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz"
@@ -3571,6 +3576,13 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0"
concat-map "0.0.1"
+brace-expansion@^5.0.8:
+ version "5.0.12"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.12.tgz#995fbb4750a77c4d16a7dc942ff2ca6ef8e675ec"
+ integrity sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==
+ dependencies:
+ balanced-match "^4.0.2"
+
braces@^3.0.3, braces@~3.0.2:
version "3.0.3"
resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz"
@@ -5118,6 +5130,15 @@ glob-to-regexp@^0.4.1:
resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz"
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
+glob@^13.0.3:
+ version "13.0.6"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-13.0.6.tgz#078666566a425147ccacfbd2e332deb66a2be71d"
+ integrity sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==
+ dependencies:
+ minimatch "^10.2.2"
+ minipass "^7.1.3"
+ path-scurry "^2.0.2"
+
global-dirs@^3.0.0:
version "3.0.1"
resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz"
@@ -6112,6 +6133,11 @@ lowercase-keys@^3.0.0:
resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz"
integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==
+lru-cache@^11.0.0:
+ version "11.5.3"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.5.3.tgz#a7767b4034e35269562d2b9da2b185b5df70c421"
+ integrity sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==
+
lru-cache@^5.1.1:
version "5.1.1"
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz"
@@ -6907,11 +6933,23 @@ minimatch@3.1.5:
dependencies:
brace-expansion "^1.1.7"
+minimatch@^10.2.2:
+ version "10.2.6"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.6.tgz#fd956bbe0b77241e9f15ac5dccb1c638060968ef"
+ integrity sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==
+ dependencies:
+ brace-expansion "^5.0.8"
+
minimist@^1.2.0:
version "1.2.8"
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
+minipass@^7.1.2, minipass@^7.1.3:
+ version "7.1.3"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.3.tgz#79389b4eb1bb2d003a9bba87d492f2bd37bdc65b"
+ integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==
+
mrmime@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz"
@@ -7155,6 +7193,11 @@ p-timeout@^3.2.0:
dependencies:
p-finally "^1.0.0"
+package-json-from-dist@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505"
+ integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==
+
package-json@^8.1.0:
version "8.1.1"
resolved "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz"
@@ -7256,6 +7299,14 @@ path-parse@^1.0.7:
resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+path-scurry@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.2.tgz#6be0d0ee02a10d9e0de7a98bae65e182c9061f85"
+ integrity sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==
+ dependencies:
+ lru-cache "^11.0.0"
+ minipass "^7.1.2"
+
path-to-regexp@3.3.0:
version "3.3.0"
resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz"
@@ -8425,6 +8476,14 @@ reusify@^1.0.4:
resolved "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz"
integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==
+rimraf@^6.0.1:
+ version "6.1.3"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-6.1.3.tgz#afbee236b3bd2be331d4e7ce4493bac1718981af"
+ integrity sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==
+ dependencies:
+ glob "^13.0.3"
+ package-json-from-dist "^1.0.1"
+
rrweb-cssom@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1"