Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2d7a76f
test(navigation) Ignore pending badge images
tony Nov 8, 2026
547ee12
test(browser) Isolate checks from external requests
tony Nov 8, 2026
83ea953
docs(feat[perl]) Integrate native Perl API and source distributions
tony Nov 8, 2026
f14e97e
docs(ci[perl]) Check native contracts and shared types before artifac…
tony Nov 8, 2026
27da172
docs(fix[checks]) Restore reader exports and destination fixture imports
tony Nov 8, 2026
fdf4a4e
docs(fix[perl]) Add the workspace API index
tony Nov 8, 2026
64aaaa8
docs(fix[status]) Describe unpublished ports as source previews
tony Nov 8, 2026
18c797b
perl(docs[reference]) Complete native glossary and source-only worksp…
tony Nov 8, 2026
52bb66d
ci(fix[perl]) Check out integrated guide sources
tony Nov 8, 2026
aa9d60e
registry(fix) Preserve source-only package status
tony Nov 8, 2026
eb9ad77
docs(fix[checks]) Align source destination evidence
tony Nov 8, 2026
1e0321b
docs(fix[checks]) Verify integrated source mappings
tony Nov 8, 2026
442f385
docs(fix[perl]) Resolve guide references
tony Nov 8, 2026
20143e5
docs(fix[perl]) Refresh dependent source caches
tony Nov 8, 2026
00e5f5f
docs(fix[navigation]) Respect product exclusions at roots
tony Nov 8, 2026
fd2d88f
docs(test[products]) Verify native product pages
tony Nov 8, 2026
a359838
docs(fix) Record the Perl cross-reference floor
tony Nov 8, 2026
ba1ba32
docs(test) Derive product checks from metadata
tony Nov 8, 2026
6fc6a41
test(perl) Retain excluded product coverage
tony Nov 8, 2026
1c525a1
fix(api-model) Resolve shared Perl POD sections
tony Nov 8, 2026
120c9bc
docs(perl) Integrate qualified native contracts
tony Nov 8, 2026
b095dc4
docs(perl) Clarify async installation requirements
tony Nov 8, 2026
e8397f4
docs(perl) Verify additional POD destinations
tony Nov 8, 2026
9ae81a6
docs(perl) Bind reference to signal-safe source
tony Nov 8, 2026
42424ce
fix(perl) Preserve native POD section links
tony Nov 8, 2026
4bff1d8
docs(perl) Clarify loop and CLI prerequisites
tony Nov 8, 2026
ec43e21
fix(perl) Link member summaries in Markdown
tony Nov 8, 2026
cb4848a
docs(perl) Bind endpoint qualification source
tony Nov 8, 2026
e66920e
docs(perl) Preserve the full tmux support range
tony Nov 8, 2026
818fa2e
docs(perl) Record the type-link ceiling
tony Nov 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
57 changes: 48 additions & 9 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ $ pnpm test
The outer loop includes the `*.outer.test.ts` integration suites, which seed
the full API catalog, run native compiler comparisons, or exercise subprocess
shutdown. Elixir exporter fixtures and live clang-format comparisons run here;
the medium loop keeps the pinned formatter fixtures. It also adds type
the medium loop keeps the pinned formatter fixtures. Adversarial example,
workspace-showcase, and product-copy CLI checks also run in outer because
they spawn subprocesses and temporary Git repositories. It also adds type
checks and starts its own Astro development server
from current source. Browser checks cover prose, an MCP table, row permalinks,
API equivalents, and phone dropdown placement at 1440, 768, and 390 pixels. The
Expand All @@ -115,14 +117,25 @@ medium, and outer respectively; measure the complete pnpm command when
changing a loop. `test:fast` aliases medium. The runner stops an over-budget
loop and fails.

The medium and outer loops first stage the integrated Ruby and Lua guides
from local Git objects. Each revision comes from `site/src/data/api/<port>.json`;
the checkout's current branch and uncommitted files do not affect these guides.
Keep those repositories at their standard `checkout` paths in `ports.ts`, or
set `LIBTMUX_DOCS_CHECKOUT_RUBY` and `LIBTMUX_DOCS_CHECKOUT_LUA` to local clones
containing the required commits. Missing repositories or commits fail with
the required revision and environment variable. The gate does not fetch;
a fresh docs clone needs these source checkouts before `pnpm test`.
`scripts/test-tiers.json` assigns existing compiler/rendering, subprocess/Git,
and full-catalog integration suites to outer, with a reason for each group.
Publication retains exhaustive link rendering and destination/literal catalog audits.
Medium and outer exclude publication suites; the unfiltered package tests in
`test:publication` run every suite, including both manifest tiers and suffix
tiers. Native shell tree/search fixtures stay in inner; owned Git collection
fixtures run in outer. No tier changes a test's assertions.

The medium and outer loops stage every port in `SOURCE_GUIDE_PORTS` in
[`port-documentation.ts`](../site/src/lib/port-documentation.ts), including Perl.
Native guides come from local Git objects at each integrated
`site/src/data/api/<port>.json` revision; the checkout's current branch and
uncommitted files do not affect them. Wrapper guides use the committed guide cache.
Keep native repositories at their `checkout` paths in
[`ports.ts`](../site/src/lib/ports.ts), or set `LIBTMUX_DOCS_CHECKOUT_<UPPERCASE_PORT>`
to a clone containing the required commit, such as `LIBTMUX_DOCS_CHECKOUT_PERL`.
Missing repositories or commits report the exact revision and override.
The gate never fetches. Provision every catalogued native checkout before
running these loops in a fresh docs clone; unchanged staged guides retain their timestamps.

Browser checks use Playwright's installed Chromium by default. To use local
Chrome:
Expand Down Expand Up @@ -667,3 +680,29 @@ cleanup in separate work.

Follow [WRITING.md](../WRITING.md#commits) for commit messages and
[AGENTS.md](../AGENTS.md#repository-boundaries) for push and deployment limits.

### Perl source-bound documentation checks

The reusable port builder checks the selected Perl artifact after rendering.
It runs the native model/POD/source/inventory suites and the shared Node type
checks before uploading an artifact. These checks use the selected source
revision and the builder workflow's own committed docs revision. They do not
replace the development-loop timing gates or the full publication audit.

```console
$ node site/node_modules/vitest/vitest.mjs run \
--root packages/api-model \
test/perl.test.ts
```

```console
$ node site/node_modules/vitest/vitest.mjs run \
--root site \
test/perl-pod-links.test.ts \
test/perl-source-usage.test.ts \
test/source-only-inventory.test.ts
```

```console
$ pnpm run --recursive type-check
```
67 changes: 57 additions & 10 deletions .github/workflows/port-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,15 @@ jobs:
echo "::error::GitHub Cloud job.workflow_repository/job.workflow_sha are required" >&2
exit 1
}
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ job.workflow_repository }}
ref: ${{ job.workflow_sha }}
sparse-checkout: |
scripts
site/src/lib
persist-credentials: false
- uses: actions/setup-node@v7
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7
with:
node-version: '26'
- id: identity
Expand Down Expand Up @@ -160,7 +160,7 @@ jobs:
echo "::error::GitHub Cloud job.workflow_repository/job.workflow_sha are required" >&2
exit 1
}
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.identity.outputs.source-ref }}
fetch-depth: 0
Expand All @@ -183,7 +183,7 @@ jobs:
}
echo "sha=$sha" >> "$GITHUB_OUTPUT"

- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ job.workflow_repository }}
ref: ${{ job.workflow_sha }}
Expand All @@ -194,7 +194,7 @@ jobs:
# Record both checkouts before either native exporter produces files.
- name: Check out native documentation tooling
if: matrix.port == 'powershell' || matrix.port == 'julia'
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.sha }}
path: docs-generator
Expand Down Expand Up @@ -234,14 +234,14 @@ jobs:
echo "$product=$ref" >> "$GITHUB_OUTPUT"
done
- if: inputs.port == 'py'
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: tmux-python/tmuxp
ref: ${{ steps.python-products.outputs.workspace }}
path: python-workspace
persist-credentials: false
- if: inputs.port == 'py'
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: tmux-python/libtmux-mcp
ref: ${{ steps.python-products.outputs.mcp }}
Expand All @@ -251,10 +251,10 @@ jobs:
# No dependency cache: this job checks out whichever ref it was asked
# to publish, and a cache it saved could be restored by a later
# default-branch run.
- uses: pnpm/action-setup@v6
- uses: pnpm/action-setup@73e46992e05b19abd31f2f3c20e0e7370d762115 # v6
with:
package_json_file: docs/package.json
- uses: actions/setup-node@v7
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7
with:
node-version: '26'
- run: pnpm install --frozen-lockfile
Expand Down Expand Up @@ -497,6 +497,38 @@ jobs:
mix deps.get --only prod
mix run --no-start "$EXPORTER" _build/docs/api.json

- name: Read the selected Perl documentation runtime
if: matrix.port == 'perl'
id: perl-runtime
working-directory: port
run: |
python3 - <<'PYCODE'
import os, pathlib, re
rows = [line.split() for line in pathlib.Path('.tool-versions').read_text().splitlines()]
versions = [row[1] for row in rows if len(row) == 2 and row[0] == 'perl']
if len(versions) != 1 or not re.fullmatch(r'[0-9]+\.[0-9]+\.[0-9]+', versions[0]):
raise ValueError('Perl documentation requires an exact native runtime pin')
with open(os.environ['GITHUB_OUTPUT'], 'a') as output:
output.write(f'version={versions[0]}\n')
PYCODE
- name: Install the selected Perl and documentation dependencies
if: matrix.port == 'perl'
uses: shogo82148/actions-setup-perl@eebc5c886de14ebbfcd2493d49a12007d2c30477 # v1.44.5
with:
perl-version: ${{ steps.perl-runtime.outputs.version }}
working-directory: port
install-modules-with: cpm
install-modules-args: --top-level-phase configure,runtime,develop
enable-modules-cache: false
- name: Export the selected Perl declarations and native POD
if: matrix.port == 'perl'
working-directory: port
env:
SOURCE_SHA: ${{ steps.source.outputs.sha }}
run: |
perl scripts/export-api.pl --revision "$SOURCE_SHA" \
--exporter-revision "$SOURCE_SHA" --output docs/_build/api.json

- if: matrix.port == 'ruby'
uses: ruby/setup-ruby@14594264cd68ce8a2345dd349bc3d138a4ef85c8 # v1.327.0
with:
Expand All @@ -510,7 +542,7 @@ jobs:
run: bundle install

- if: inputs.port == 'py'
uses: astral-sh/setup-uv@v10.2.0
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
with:
enable-cache: false
python-version: '3.14'
Expand Down Expand Up @@ -610,6 +642,21 @@ jobs:
test -s "_site/en/py/$LIBTMUX_DOCS_VERSION/api/api/index.html"
fi

- name: Check Perl native model and authored POD links
if: matrix.port == 'perl'
working-directory: docs
env:
LIBTMUX_DOCS_TEST_SOURCE_ONLY: '1'
run: |
time node site/node_modules/vitest/vitest.mjs run --root packages/api-model test/perl.test.ts
time node site/node_modules/vitest/vitest.mjs run --root site \
test/perl-pod-links.test.ts test/perl-source-usage.test.ts test/source-only-inventory.test.ts

- name: Check shared TypeScript and Astro types for Perl
if: matrix.port == 'perl'
working-directory: docs
run: time pnpm run --recursive type-check

# The version directory itself: its contents become
# <locale>/<port>/<version>.
- id: content
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/reusable-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ jobs:
echo "::error::path-prefix '$p' must be an unrooted path using letters, digits, '.', '_', '-' and '/', without '..'" >&2
exit 1
fi
reserved=(py ruby lua powershell julia elixir ts rs go java kotlin scala csharp fsharp cxx swift manifest _shell)
reserved=(py ruby lua powershell julia elixir ts rs go java kotlin scala csharp fsharp cxx swift perl manifest _shell)
for r in "${reserved[@]}"; do
if [[ "$p" == "$r" ]]; then
echo "::error::path-prefix '$p' is a bare reserved top-level name — qualify it, e.g. '$r/latest'" >&2
Expand All @@ -153,7 +153,7 @@ jobs:
done
if [[ -n "${PORT_IN:-}" ]]; then
case "$PORT_IN" in
py|ruby|lua|powershell|julia|elixir|ts|rs|go|java|kotlin|scala|csharp|fsharp|cxx|swift) ;;
py|ruby|lua|powershell|julia|elixir|perl|ts|rs|go|java|kotlin|scala|csharp|fsharp|cxx|swift) ;;
*) echo "::error::unknown port '$PORT_IN'" >&2; exit 1 ;;
esac
if [[ ! "$VERSION_IN" =~ ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ || "$VERSION_IN" == *..* ]]; then
Expand Down
24 changes: 17 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,14 @@ jobs:
- name: Resolve integrated guide sources
id: integrated-sources
run: |
echo "ruby=$(jq -r .revision site/src/data/api/ruby.json)" >> "$GITHUB_OUTPUT"
echo "lua=$(jq -r .revision site/src/data/api/lua.json)" >> "$GITHUB_OUTPUT"
echo "powershell=$(jq -r .revision site/src/data/api/powershell.json)" >> "$GITHUB_OUTPUT"
echo "julia=$(jq -r .revision site/src/data/api/julia.json)" >> "$GITHUB_OUTPUT"
echo "elixir=$(jq -r .revision site/src/data/api/elixir.json)" >> "$GITHUB_OUTPUT"
{
echo "ruby=$(jq -r .revision site/src/data/api/ruby.json)"
echo "lua=$(jq -r .revision site/src/data/api/lua.json)"
echo "powershell=$(jq -r .revision site/src/data/api/powershell.json)"
echo "julia=$(jq -r .revision site/src/data/api/julia.json)"
echo "elixir=$(jq -r .revision site/src/data/api/elixir.json)"
echo "perl=$(jq -r .revision site/src/data/api/perl.json)"
} >> "$GITHUB_OUTPUT"

- uses: actions/checkout@v7
with:
Expand Down Expand Up @@ -89,6 +92,12 @@ jobs:
ref: ${{ steps.integrated-sources.outputs.elixir }}
path: .port-sources/elixir
persist-credentials: false
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
repository: libtmux/libtmux-perl
ref: ${{ steps.integrated-sources.outputs.perl }}
path: .port-sources/perl
persist-credentials: false

# The exporter tests compile a fixture with the package's own toolchain:
# the exact pair the integrated Elixir source pins, read as port-docs.yml
Expand All @@ -112,6 +121,7 @@ jobs:
LIBTMUX_DOCS_CHECKOUT_POWERSHELL: ${{ github.workspace }}/.port-sources/powershell
LIBTMUX_DOCS_CHECKOUT_JULIA: ${{ github.workspace }}/.port-sources/julia
LIBTMUX_DOCS_CHECKOUT_ELIXIR: ${{ github.workspace }}/.port-sources/elixir
LIBTMUX_DOCS_CHECKOUT_PERL: ${{ github.workspace }}/.port-sources/perl
run: |
node scripts/stage-port-docs.mjs --from-source
node scripts/stage-port-docs.mjs --cached --check
Expand All @@ -131,12 +141,12 @@ jobs:
PREVIEW_PREFIX: pr-${{ github.event.pull_request.number }}
LIBTMUX_DOCS_CHECKOUT_RUBY: ${{ github.workspace }}/.port-sources/ruby
LIBTMUX_DOCS_CHECKOUT_LUA: ${{ github.workspace }}/.port-sources/lua
# PowerShell, Julia and Elixir paths stay scoped to guide staging
# PowerShell, Julia, Elixir and Perl paths stay scoped to guide staging
# above, which checks the cache used by ordinary builds. Native API
# and MCP export freshness remain owning-port checks, not claims of
# this root audit. Elixir's exporter tests run in the unit step; its
# committed model is derived again by port-docs.yml at publication.
LIBTMUX_DOCS_SKIP_NATIVE_MODEL_PORTS: ruby,lua,powershell,julia,elixir
LIBTMUX_DOCS_SKIP_NATIVE_MODEL_PORTS: ruby,lua,powershell,julia,elixir,perl

- name: Upload audited preview
if: github.event_name == 'pull_request'
Expand Down
6 changes: 4 additions & 2 deletions notes/adding-a-port.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ products. Leave out private workspaces and development tools.
Name a package page or API reference only where the host really serves one.
A port installed from Git, or from its own registry, names no host page. Set
an entry `planned` or `configured-unpublished` until its host serves it: only
`published` entries produce links. List a page an ecosystem suggests and its
`published` entries produce registry/API links. Set `sourceAvailable: true`
only for a verified public source directory or file; that source can be linked
while the distribution remains `configured-unpublished`. List a page an ecosystem suggests and its
host does not serve as `unavailable`.

Give a package that ships inside another distribution (a Go package, a
Expand Down Expand Up @@ -85,7 +87,7 @@ $ node scripts/verify-destinations.mjs
```

The verifier refuses to run, with or without `--check`, if a port in `ports.ts`
has no inventory entry with a published library: the header builds its links
has no library with a published distribution or explicitly available source: the header builds its links
from that entry, so a port without one would offer nothing. A host the
inventory has not named before needs an identity rule in
`scripts/lib/destination-verification.mjs` and its cases in
Expand Down
6 changes: 5 additions & 1 deletion packages/api-model/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
"type": "module",
"description": "A shared API model for language ports, extracted from native documentation artifacts and source.",
"exports": {
".": "./src/index.ts"
".": "./src/index.ts",
"./products": "./src/products.ts",
"./modules": "./src/modules.ts",
"./link": "./src/link.ts",
"./reference": "./src/reference.ts"
},
"scripts": {
"test": "vitest run",
Expand Down
Loading
Loading