Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ updates:
schedule:
interval: weekly
open-pull-requests-limit: 5
ignore:
# Node 26 is a preview runtime; keep the current Node 24 type contract.
- dependency-name: '@types/node'
versions: ['26.x']
groups:
development:
dependency-type: development
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 (2026-09-13)
- uses: github/codeql-action/init@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
with:
languages: ${{ matrix.language }}
build-mode: none
- uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 (2026-09-13)
- uses: github/codeql-action/analyze@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
with:
category: /language:${{ matrix.language }}
2 changes: 1 addition & 1 deletion .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ jobs:
path: results.sarif
if-no-files-found: error
retention-days: 14
- uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 (2026-09-13)
- uses: github/codeql-action/upload-sarif@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
with:
sarif_file: results.sarif
8 changes: 8 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ Start from an issue labeled `good first issue`. Comment on the issue before open

For scoring-rule work, follow [docs/methodology.md](docs/methodology.md): every rule change needs an evidence class plus positive, negative, and false-positive fixtures. Pull requests that claim ranking, citation, or AI-visibility outcomes will not be merged.

### Adding a scoring rule

Before changing scoring behavior, read [docs/methodology.md](docs/methodology.md) and choose the applicable documented A–D evidence class. Record a current primary source for evidence-backed behavior or an explicit heuristic rationale for a content heuristic, including the rule's scope and known false positives. Class D experiments are informational only and earn no readiness points; do not add zero-weight Class D experiments to the scored fixture corpus.

Create a stable rule ID in [`src/core/rules.ts`](src/core/rules.ts), implement the rule there, and register it in the exported `allRules` array. In [`fixtures/v0.6/rule-corpus.ts`](fixtures/v0.6/rule-corpus.ts), add cases under the matching ID: `positive`, `negative`, and `boundary` for the false-positive boundary. Give each case a purpose and expected `score`, `issues`, and `suggestions`; the [release-contract tests](src/core/__tests__/release-contract.test.ts) cover every scored rule and enforce these expectations through the parser boundary.

Record expected JSON/output changes, score-contract compatibility, and any migration impact in the pull request. Keep claims within the documented scope and do not present a rule or score as evidence of ranking, citation, indexing, or adoption outcomes.

## Pull requests

Keep each pull request focused. Include:
Expand Down
5 changes: 4 additions & 1 deletion docs/action-pins.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
Resolved through official GitHub repositories on 2026-09-13. Annotated tag objects
were dereferenced to commits; tag-object SHAs are not used as Action pins.

CodeQL was updated to v4.38.0 on 2026-09-21 after checking its upstream tag
and [official release notes](https://github.com/github/codeql-action/releases/tag/v4.38.0).

| Action | Upstream tag | Full commit |
| --- | --- | --- |
| actions/checkout | v7.0.1 | 3d3c42e5aac5ba805825da76410c181273ba90b1 |
| actions/setup-node | v7.0.0 | 820762786026740c76f36085b0efc47a31fe5020 |
| actions/upload-artifact | v7.0.1 | 043fb46d1a93c77aae656e7c1c64a875d1fc6a0a |
| actions/download-artifact | v8.0.1 | 3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c |
| actions/dependency-review-action | v5.0.0 | a1d282b36b6f3519aa1f3fc636f609c47dddb294 |
| github/codeql-action | v4.37.9 | cdf488f595d80d6e07e03d4674febd5ab45fa938 |
| github/codeql-action | v4.38.0 | b96794f015dfd88f77b49b1c93e0fa7110f94c63 |
| ossf/scorecard-action | v2.4.4 | 2d1146689b8cda280b9bc96326124645441f03bc |
| actions/attest-build-provenance | v4.2.2 | 4d101475d8b20a2381f78447822ac1eab6504dd8 |

Expand Down
1 change: 1 addition & 0 deletions examples/github-action-sample/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ This directory is a copyable end-to-end sample for the v0.6 Action contract.
- `.github/workflows/geoptimize.yml` checks the static site on pull requests and manual runs.
- `site/index.html` is a deterministic public input.
- The Action is advisory by default. The sample does not block a pull request on an unreviewed score threshold.
- [VitePress workflow example](vitepress/README.md) adapts the check for an existing npm-based VitePress project.

The workflow pins `geoptimize@0.11.0` through the immutable `v0.11.0` Git tag.
Change this exact version only when deliberately adopting another release.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: VitePress content readiness

on:
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
readiness:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '24'
cache: npm
- run: npm ci
- run: npm run docs:build
- uses: cucuwang/geoptimize@v0.11.0
with:
path: docs/.vitepress/dist
fail-on-low-score: 'false'
16 changes: 16 additions & 0 deletions examples/github-action-sample/vitepress/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# VitePress GitHub Action sample

This is a copyable advisory-mode workflow for an existing npm-based VitePress project. It is not a standalone runnable site fixture.

Copy the [sample workflow](.github/workflows/geoptimize.yml) to `.github/workflows/geoptimize.yml` at the repository root of your project.

## Prerequisites

- `package.json` at the repository root and a committed `package-lock.json`.
- VitePress installed as a local dependency.
- A `docs:build` script that runs `vitepress build docs`.
- VitePress sources in `docs/`, with the default output at `docs/.vitepress/dist`.

The workflow runs `npm ci`, builds the site, and scans `docs/.vitepress/dist` with `cucuwang/geoptimize@v0.11.0`. Advisory mode lets a low score pass; installation, build, and scan errors still fail the job.

For another site root or a custom `outDir`, adjust the `docs:build` command and the Action `path` together so they point to the same build output. See the [official VitePress deployment guide](https://vitepress.dev/guide/deploy) for deployment details.
33 changes: 33 additions & 0 deletions src/cli/__tests__/resolve-target.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { describe, expect, it } from 'vitest';
import { resolveTarget } from '../interactive.js';

describe('resolveTarget', () => {
it('keeps HTTPS URLs unchanged', () => {
expect(resolveTarget('https://example.com')).toEqual({
type: 'url',
path: 'https://example.com',
});
});

it('normalizes a bare domain to HTTPS', () => {
expect(resolveTarget('example.com')).toEqual({
type: 'url',
path: 'https://example.com',
});
});

it('throws actionable guidance for relative paths without --dir', () => {
expect(() => resolveTarget('./dist')).toThrowError(/--dir/);
});

it('throws actionable guidance for absolute paths without --dir', () => {
expect(() => resolveTarget('/tmp/site')).toThrowError(/--dir/);
});

it('resolves paths as directory when --dir is set', () => {
expect(resolveTarget('./dist', true)).toEqual({
type: 'directory',
path: './dist',
});
});
});
Loading