pagegraph 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +325 -66
- package/dist/anthropic-messages-TqKpKmfW.js +1067 -0
- package/dist/anthropic-messages-TqKpKmfW.js.map +1 -0
- package/dist/audit.d.ts +4 -2
- package/dist/audit.js +5 -5
- package/dist/audit.js.map +1 -1
- package/dist/azure-openai-responses-DJjBLwoI.js +231 -0
- package/dist/azure-openai-responses-DJjBLwoI.js.map +1 -0
- package/dist/build-only/audit.js +1 -1
- package/dist/build-only/claims.d.ts +1 -0
- package/dist/build-only/claims.js +6 -0
- package/dist/build-only/claims.js.map +1 -0
- package/dist/build-only/config.js +1 -1
- package/dist/build-only/oxlint.d.ts +1 -0
- package/dist/build-only/oxlint.js +6 -0
- package/dist/build-only/oxlint.js.map +1 -0
- package/dist/build-only/tanstack-start.js +1 -1
- package/dist/build-only/vite.js +1 -1
- package/dist/{checks-uZk5Em9A.js → checks-BS-aDXB_.js} +2 -2
- package/dist/checks-BS-aDXB_.js.map +1 -0
- package/dist/claims-Bch7Lxlo.d.ts +92 -0
- package/dist/claims-Bv7voeEV.js +431 -0
- package/dist/claims-Bv7voeEV.js.map +1 -0
- package/dist/claims.d.ts +94 -0
- package/dist/claims.js +2 -0
- package/dist/cli.js +17607 -43387
- package/dist/cli.js.map +1 -1
- package/dist/cloudflare-workers-ai-system-one-f3ZrvNYZ.js +41 -0
- package/dist/cloudflare-workers-ai-system-one-f3ZrvNYZ.js.map +1 -0
- package/dist/config.d.ts +9 -29
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/{content-kcEnQdfi.js → content-CHd0X4s6.js} +2 -2
- package/dist/{content-kcEnQdfi.js.map → content-CHd0X4s6.js.map} +1 -1
- package/dist/{content-B1cPtL8b.d.ts → content-DgNr7apS.d.ts} +4 -5
- package/dist/declare-D5o7hwmv.js.map +1 -1
- package/dist/diagnostics-Wt5faNDM.js +108 -0
- package/dist/diagnostics-Wt5faNDM.js.map +1 -0
- package/dist/dist-B6zg_Z3Z.js +4794 -0
- package/dist/dist-B6zg_Z3Z.js.map +1 -0
- package/dist/document-CztEu3Vd.d.ts +109 -0
- package/dist/document-Dvemcv7V.js +379 -0
- package/dist/document-Dvemcv7V.js.map +1 -0
- package/dist/env-api-keys-C-OA0yM-.js +124 -0
- package/dist/env-api-keys-C-OA0yM-.js.map +1 -0
- package/dist/error-body-CyiejW4b.js +103 -0
- package/dist/error-body-CyiejW4b.js.map +1 -0
- package/dist/facts-1OKclPOk.js +115 -0
- package/dist/facts-1OKclPOk.js.map +1 -0
- package/dist/github-copilot-headers-CEpMOpQF.js +24 -0
- package/dist/github-copilot-headers-CEpMOpQF.js.map +1 -0
- package/dist/google-generative-ai-BxABKIKO.js +330 -0
- package/dist/google-generative-ai-BxABKIKO.js.map +1 -0
- package/dist/google-shared-0gpM2jFi.js +19471 -0
- package/dist/google-shared-0gpM2jFi.js.map +1 -0
- package/dist/google-vertex-D8Eb5cbu.js +376 -0
- package/dist/google-vertex-D8Eb5cbu.js.map +1 -0
- package/dist/{declare-DVgdEdOL.d.ts → graph-D1PIndsC.d.ts} +117 -6
- package/dist/{graph-Bcsourlv.js → graph-DMNOLXLu.js} +23 -13
- package/dist/graph-DMNOLXLu.js.map +1 -0
- package/dist/hash-Dp7EzZUo.js +18 -0
- package/dist/hash-Dp7EzZUo.js.map +1 -0
- package/dist/headers-BRNMVpzu.js +19 -0
- package/dist/headers-BRNMVpzu.js.map +1 -0
- package/dist/index-C5w9ripz.d.ts +204 -0
- package/dist/index.d.ts +6 -160
- package/dist/index.js +37 -5
- package/dist/index.js.map +1 -1
- package/dist/inline-BbS93GAT.js +682 -0
- package/dist/inline-BbS93GAT.js.map +1 -0
- package/dist/json-parse-C10znB7l.js +383 -0
- package/dist/json-parse-C10znB7l.js.map +1 -0
- package/dist/llms-Dhr_5u2O.js +19 -0
- package/dist/llms-Dhr_5u2O.js.map +1 -0
- package/dist/markdown-C6dRE9zD.js +168 -0
- package/dist/markdown-C6dRE9zD.js.map +1 -0
- package/dist/markdown-path-lJB9BAVZ.js +6 -0
- package/dist/markdown-path-lJB9BAVZ.js.map +1 -0
- package/dist/{message-DT_CjUdt.js → message-CuBjgZ74.js} +2 -2
- package/dist/{message-DT_CjUdt.js.map → message-CuBjgZ74.js.map} +1 -1
- package/dist/mistral-conversations-CvaqBWjR.js +690 -0
- package/dist/mistral-conversations-CvaqBWjR.js.map +1 -0
- package/dist/models-DcT5qOEL.js +1203 -0
- package/dist/models-DcT5qOEL.js.map +1 -0
- package/dist/node-Ccvru9GE.js +26 -0
- package/dist/node-Ccvru9GE.js.map +1 -0
- package/dist/node-MEosBOF2.js +2403 -0
- package/dist/node-MEosBOF2.js.map +1 -0
- package/dist/openai-BCBEd2eO.js +17350 -0
- package/dist/openai-BCBEd2eO.js.map +1 -0
- package/dist/openai-codex-responses-vJqxeeRC.js +1268 -0
- package/dist/openai-codex-responses-vJqxeeRC.js.map +1 -0
- package/dist/openai-completions-Cb_fRAbI.js +989 -0
- package/dist/openai-completions-Cb_fRAbI.js.map +1 -0
- package/dist/openai-prompt-cache-Bc6qNWt0.js +10 -0
- package/dist/openai-prompt-cache-Bc6qNWt0.js.map +1 -0
- package/dist/openai-responses-sDuh82G5.js +268 -0
- package/dist/openai-responses-sDuh82G5.js.map +1 -0
- package/dist/openai-responses-shared-mhuo1Jov.js +599 -0
- package/dist/openai-responses-shared-mhuo1Jov.js.map +1 -0
- package/dist/openrouter-images-CRmBkzpX.js +127 -0
- package/dist/openrouter-images-CRmBkzpX.js.map +1 -0
- package/dist/oxlint.d.ts +58 -0
- package/dist/oxlint.js +202 -0
- package/dist/oxlint.js.map +1 -0
- package/dist/page-heads-BfjWQvau.d.ts +108 -0
- package/dist/{page-heads-6y-CARRQ.js → page-heads-BgbaIjj9.js} +3 -3
- package/dist/page-heads-BgbaIjj9.js.map +1 -0
- package/dist/pi-Bvw6J0gh.js +56795 -0
- package/dist/pi-Bvw6J0gh.js.map +1 -0
- package/dist/pi-messages-CejiVYvO.js +308 -0
- package/dist/pi-messages-CejiVYvO.js.map +1 -0
- package/dist/{projections-DeEFe7XT.d.ts → projections-Bk-qOOsR.d.ts} +2 -2
- package/dist/provider-env-t38GK5FF.js +39 -0
- package/dist/provider-env-t38GK5FF.js.map +1 -0
- package/dist/provider-retry-DzKoh1X7.js +80 -0
- package/dist/provider-retry-DzKoh1X7.js.map +1 -0
- package/dist/react.d.ts +3 -2
- package/dist/react.js +2 -1
- package/dist/react.js.map +1 -1
- package/dist/rolldown-runtime-B-lAHAz2.js +37 -0
- package/dist/sanitize-unicode-Ds14l9Om.js +28 -0
- package/dist/sanitize-unicode-Ds14l9Om.js.map +1 -0
- package/dist/sdk-C9_wiO6w.js +12503 -0
- package/dist/sdk-C9_wiO6w.js.map +1 -0
- package/dist/state-BuJP_3Lr.js +28102 -0
- package/dist/state-BuJP_3Lr.js.map +1 -0
- package/dist/system-one-shared-Dl10ZF7Z.js +167 -0
- package/dist/system-one-shared-Dl10ZF7Z.js.map +1 -0
- package/dist/tanstack-start/index.d.ts +29 -13
- package/dist/tanstack-start/index.js +391 -42
- package/dist/tanstack-start/index.js.map +1 -1
- package/dist/tanstack-start/markdown.d.ts +12 -0
- package/dist/tanstack-start/markdown.js +149 -0
- package/dist/tanstack-start/markdown.js.map +1 -0
- package/dist/tanstack-start/prerender-worker.d.ts +2 -0
- package/dist/tanstack-start/prerender-worker.js +7 -0
- package/dist/tanstack-start/prerender-worker.js.map +1 -0
- package/dist/tanstack-start/react.d.ts +7 -0
- package/dist/tanstack-start/react.js +12 -0
- package/dist/tanstack-start/react.js.map +1 -0
- package/dist/tanstack-start/server.d.ts +9 -3
- package/dist/tanstack-start/server.js +26 -2
- package/dist/tanstack-start/server.js.map +1 -1
- package/dist/transform-messages-BLJ8EfK6.js +468 -0
- package/dist/transform-messages-BLJ8EfK6.js.map +1 -0
- package/dist/typesafe-system-one-CwEWMV8P.js +25 -0
- package/dist/typesafe-system-one-CwEWMV8P.js.map +1 -0
- package/dist/{vite-graph-loader-01p1WxEq.js → vite-graph-loader-CsGiYNWE.js} +6 -5
- package/dist/vite-graph-loader-CsGiYNWE.js.map +1 -0
- package/dist/vite-graph-loader-DZCwejuJ.d.ts +133 -0
- package/package.json +47 -10
- package/dist/checks-uZk5Em9A.js.map +0 -1
- package/dist/graph-Bcsourlv.js.map +0 -1
- package/dist/graph-BxCY90vq.d.ts +0 -104
- package/dist/graph-CBIY71w6.d.ts +0 -57
- package/dist/page-heads-6y-CARRQ.js.map +0 -1
- package/dist/page-heads-DNkjMUEN.d.ts +0 -21
- package/dist/vite-graph-loader-01p1WxEq.js.map +0 -1
- package/dist/vite-graph-loader-Btgjz5RH.d.ts +0 -56
package/README.md
CHANGED
|
@@ -26,20 +26,194 @@ bun add pagegraph
|
|
|
26
26
|
bun add -D lighthouse # only for `pagegraph audit` performance evidence
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
## Authored pages
|
|
30
|
+
|
|
31
|
+
Keep authored text beside its React layout. `DocumentProvider` records only its page body when
|
|
32
|
+
supplied a collector; ordinary rendering preserves the layout. `Title` assigns a heading to the
|
|
33
|
+
nearest section or item, `Fact` resolves shared values, and `Visual` describes content for the
|
|
34
|
+
markdown document without rendering its children during capture.
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
38
|
+
import { defineFacts, fact, documentMarkdown } from "pagegraph";
|
|
39
|
+
import {
|
|
40
|
+
DocumentProvider, T, Title, Section, Fact, createCollector, finishDocument,
|
|
41
|
+
} from "pagegraph/react";
|
|
42
|
+
|
|
43
|
+
const facts = defineFacts({ attempts: fact.number(8) });
|
|
44
|
+
declare module "pagegraph" {
|
|
45
|
+
interface Register { facts: typeof facts }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const collector = createCollector({ path: "/email", site: "https://example.com", facts });
|
|
49
|
+
const page = (
|
|
50
|
+
<DocumentProvider collector={collector}>
|
|
51
|
+
<Section kind="prose" id="intro">
|
|
52
|
+
<h1><Title>Email delivery</Title></h1>
|
|
53
|
+
<p><T>Retry up to <Fact id="attempts" /> times.</T></p>
|
|
54
|
+
</Section>
|
|
55
|
+
</DocumentProvider>
|
|
56
|
+
);
|
|
57
|
+
// Your SSR renderer supplies completed HTML, whose markers determine document order.
|
|
58
|
+
const html = renderToStaticMarkup(page);
|
|
59
|
+
const document = finishDocument(collector, {
|
|
60
|
+
title: "Email delivery", description: "Reliable delivery with retries.",
|
|
61
|
+
}, html);
|
|
62
|
+
const markdown = documentMarkdown(document, "https://example.com");
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Use `defineSectionKind` for custom formatting; its markdown writer provides `text`, `heading`,
|
|
66
|
+
and `table`:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { defineSectionKind } from "pagegraph";
|
|
70
|
+
const comparison = defineSectionKind({
|
|
71
|
+
kind: "comparison",
|
|
72
|
+
markdown: (section, md) => md.heading(2, section.title)
|
|
73
|
+
+ md.table(section.items.map((item) => item.cells)),
|
|
74
|
+
}); // pass kind={comparison} to Section
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`Section.Item.Link` records a card's destination, while `CaptureAnchor` is the
|
|
78
|
+
public anchor boundary for router `createLink` integrations. `ForAgents` and `ForHumans` mark
|
|
79
|
+
audience-specific text; markdown excludes human-only content. `messageText` extracts text or
|
|
80
|
+
inline markdown for head metadata. The root entry also provides `hashDocument`,
|
|
81
|
+
`createMarkdownLock`, and pure `llmsMarkdown`/`llmsSection` string builders.
|
|
82
|
+
|
|
83
|
+
## Rendered markdown with TanStack Start
|
|
84
|
+
|
|
85
|
+
Declare rendered pages on the route that owns `DocumentProvider`. Collection instances inherit
|
|
86
|
+
these fields from their parameter route; the parameter template itself is never captured.
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
90
|
+
import { DocumentProvider, Section, T, Title } from "pagegraph/react";
|
|
91
|
+
import { Link } from "pagegraph/tanstack-start/react";
|
|
92
|
+
|
|
93
|
+
export const Route = createFileRoute("/pricing")({
|
|
94
|
+
staticData: {
|
|
95
|
+
seo: { kind: "page", head: { title: "Pricing", description: "Plans for your team." } },
|
|
96
|
+
markdown: "rendered",
|
|
97
|
+
llms: "Product",
|
|
98
|
+
},
|
|
99
|
+
head: () => ({ meta: [{ title: "Pricing" }, { name: "description", content: "Plans for your team." }] }),
|
|
100
|
+
component: () => (
|
|
101
|
+
<DocumentProvider>
|
|
102
|
+
<Section kind="prose" id="plans">
|
|
103
|
+
<h1><Title>Plans for your team</Title></h1>
|
|
104
|
+
<Link to="/"><T>Back home</T></Link>
|
|
105
|
+
</Section>
|
|
106
|
+
</DocumentProvider>
|
|
107
|
+
),
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`markdown: "source"` identifies pages whose Markdown is supplied by the application; pagegraph
|
|
112
|
+
captures only `"rendered"` pages. `llms` sets an optional llms.txt group. Use the capture-aware
|
|
113
|
+
`Link` for authored links: it uses TanStack's ordinary Link outside a capture and records resolved
|
|
114
|
+
anchor destinations during capture. The plugin adds `source=` locations to authored JSX imported
|
|
115
|
+
from `pagegraph/react`. In development, `DocumentProvider` rejects a current route lacking
|
|
116
|
+
`staticData.markdown: "rendered"`.
|
|
117
|
+
|
|
118
|
+
Configure the plugin and pass its fixed capture page to Start:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { pagegraph } from "pagegraph/tanstack-start";
|
|
122
|
+
|
|
123
|
+
const graph = pagegraph({
|
|
124
|
+
origin: "https://preview.example.com", // this deployment's SEO origin
|
|
125
|
+
collections: "src/collections.ts",
|
|
126
|
+
markdown: {
|
|
127
|
+
origin: "https://example.com", // canonical document and twin links
|
|
128
|
+
serverEntry: "dist/server/index.js", // default; relative to the Vite root
|
|
129
|
+
},
|
|
130
|
+
facts: "src/facts.ts", // exports `facts`; evaluated in the pagegraph environment
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// In your Vite plugins:
|
|
134
|
+
// tanstackStart({
|
|
135
|
+
// prerender: { enabled: true, autoStaticPathsDiscovery: false, crawlLinks: false, failOnError: true },
|
|
136
|
+
// pages: [...graph.prerenderPages],
|
|
137
|
+
// }), graph
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
For Cloudflare, wire the non-deployed prerender Worker to the compiled Start server. Add this to
|
|
141
|
+
`cloudflare()` alongside the production Worker's configuration:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
experimental: {
|
|
145
|
+
prerenderWorker: {
|
|
146
|
+
config: {
|
|
147
|
+
name: "app-markdown-prerender",
|
|
148
|
+
main: "pagegraph/tanstack-start/prerender-worker",
|
|
149
|
+
compatibility_date: "2026-09-20",
|
|
150
|
+
compatibility_flags: ["nodejs_compat"],
|
|
151
|
+
vars: { TSS_PRERENDERING: "true" },
|
|
152
|
+
assets: { binding: "ASSETS", run_worker_first: true },
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Call the capture adapter before your normal Start handler, forwarding the same request options:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
import handler from "@tanstack/react-start/server-entry";
|
|
162
|
+
import { markdownRequest } from "pagegraph/tanstack-start/markdown";
|
|
163
|
+
|
|
164
|
+
export default {
|
|
165
|
+
async fetch(request: Request) {
|
|
166
|
+
return await markdownRequest(request) ?? handler.fetch(request);
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Only dev and the prerender Worker capture documents. `GET` and `HEAD` on
|
|
172
|
+
`/__pagegraph/markdown.json` capture all rendered pages; `/pricing.md` and
|
|
173
|
+
`/pricing.document.json` capture one page in dev. Ordinary requests return `null`. In production,
|
|
174
|
+
private capture paths return 404 and Markdown twins fall through to your static asset server.
|
|
175
|
+
`markdownPagePaths()` exposes the concrete rendered page paths.
|
|
176
|
+
|
|
177
|
+
After prerender, the plugin writes `dist/client/pricing.md` (`/` becomes `index.md`),
|
|
178
|
+
`.pagegraph/documents/pricing.json`, and `.pagegraph/heads.json`, and removes the emitted private
|
|
179
|
+
capture response. Stale valid documents at their derived paths are pruned; unrelated files are
|
|
180
|
+
preserved. Ignore the private generated documents and heads in Git. Claims replay is reserved for
|
|
181
|
+
a separate integration.
|
|
182
|
+
|
|
183
|
+
Serve graph-derived llms.txt without rendering pages:
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
187
|
+
import { llmsTxt } from "pagegraph/tanstack-start/server";
|
|
188
|
+
|
|
189
|
+
export const Route = createFileRoute("/llms.txt")({
|
|
190
|
+
server: { handlers: { GET: llmsTxt({ sections: ["## Docs\n\nRead our documentation."] }) } },
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
`llmsSection()` returns the generated section for custom composition. It includes rendered twins
|
|
195
|
+
and explicitly grouped pages, using graph titles and descriptions and `markdown.origin`.
|
|
196
|
+
|
|
29
197
|
## What runs where
|
|
30
198
|
|
|
31
|
-
Every entry belongs to one place. Runtime entries
|
|
32
|
-
|
|
199
|
+
Every entry belongs to one place. Runtime entries use portable graph and document code with
|
|
200
|
+
the framework peers listed below; the capture adapter runs on a Start server. Build entries
|
|
201
|
+
load your app through Vite, parse routes natively, or drive Node I/O.
|
|
33
202
|
|
|
34
203
|
| Entry | Runs in | Exports | Peers |
|
|
35
204
|
| ------------------ | ----------------------------- | --------------------------------------------------------------------------------------------------------- | --------------------------------- |
|
|
36
|
-
| `pagegraph` | runtime (Worker, SSR, browser) | `buildSeoGraph`, `contentCollection`, `renderSitemap`, `renderRobots`, `pageHeads`, `graphToJson`/`graphFromJson`, checks, `inspectHtml
|
|
37
|
-
| `pagegraph/react` | runtime | `createSeo` → `seo.head`, `seoHead`, `Breadcrumbs`, JSON-LD generators | `react`, `@tanstack/react-router` |
|
|
38
|
-
| `pagegraph/tanstack-start/server` | runtime (Start server routes) | `robotsTxt`, `sitemapXml`, `seoGraph`, `seoSite` | the `pagegraph()` plugin |
|
|
39
|
-
| `pagegraph/tanstack-start` |
|
|
205
|
+
| `pagegraph` | runtime (Worker, SSR, browser) | `buildSeoGraph`, `contentCollection`, `renderSitemap`, `renderRobots`, `pageHeads`, `graphToJson`/`graphFromJson`, checks, `inspectHtml`, document types, facts, markdown and locks | — |
|
|
206
|
+
| `pagegraph/react` | runtime | `createSeo` → `seo.head`, `seoHead`, `Breadcrumbs`, JSON-LD generators, authored page primitives | `react`, `@tanstack/react-router` |
|
|
207
|
+
| `pagegraph/tanstack-start/server` | runtime (Start server routes) | `robotsTxt`, `sitemapXml`, `llmsTxt`, `llmsSection`, `seoGraph`, `seoSite` | the `pagegraph()` plugin |
|
|
208
|
+
| `pagegraph/tanstack-start/markdown` | runtime (Start server) | `markdownRequest`, `markdownPagePaths` | `react`, `react-dom`, `@tanstack/react-start`, `@tanstack/react-router` |
|
|
209
|
+
| `pagegraph/tanstack-start/react` | runtime | capture-aware `Link` | `react`, `@tanstack/react-router` |
|
|
210
|
+
| `pagegraph/tanstack-start/prerender-worker` | non-deployed prerender Worker | compiled Start server | the `pagegraph()` plugin |
|
|
211
|
+
| `pagegraph/tanstack-start` | build (`vite.config.ts`, `pagegraph.config.ts`) | `pagegraph()` Vite plugin, `tanstackStartGraph`, `evaluateAppGraph` | `vite`, `@tanstack/router-generator`, `effect` |
|
|
40
212
|
| `pagegraph/vite` | build (`vite.config.ts`) | `seoRouteConfig` coverage gate | `vite`, `@tanstack/router-generator` |
|
|
41
|
-
| `pagegraph/config` | build (`
|
|
213
|
+
| `pagegraph/config` | build (`pagegraph.config.ts`, CLI) | `defineSeoConfig`, `viteGraphLoader`, `loadPageHeads` | `vite` |
|
|
214
|
+
| `pagegraph/claims` | build / CLI (Node or Bun) | `claimsInput`, `claimsFamily`, document resolution, committed claims checks | `effect` |
|
|
42
215
|
| `pagegraph/audit` | build / CLI (Node or Bun) | Audit services, scanner protocol, rules, and report schemas | `effect` |
|
|
216
|
+
| `pagegraph/oxlint` | build (oxlint) | `pagegraph` plugin: `no-bare-text`, `t-children` | — |
|
|
43
217
|
| `pagegraph` bin | CLI (Bun) | CLI over the same graph | bundled |
|
|
44
218
|
|
|
45
219
|
Build entries resolve to a stub under the `workerd`, `worker`, and `browser` export conditions.
|
|
@@ -48,21 +222,14 @@ instead of crashing on a native binding when a request first runs the code. The
|
|
|
48
222
|
have **zero runtime dependencies** beyond their listed peers; a test pins each entry's import
|
|
49
223
|
graph.
|
|
50
224
|
|
|
51
|
-
The CLI **bundles PageGraph's Effect
|
|
52
|
-
app's Effect version; it runs on [Bun](https://bun.sh) (`bunx pagegraph`).
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
undeclared error bodies are capped at 16 KiB.
|
|
60
|
-
Discovery-only research gets one continuation to complete provider evidence. Every workflow failure
|
|
61
|
-
after run creation writes `failure.json` in the run directory, with the stage, session ID when available,
|
|
62
|
-
transcript, and cause chain. `vite` stays a peer — graph commands
|
|
63
|
-
load your app through Vite at runtime — and `lighthouse` is only needed by `pagegraph audit`.
|
|
64
|
-
Importing `pagegraph/audit` programmatically needs `effect@^4.0.0`. The Effect and TypeSafe
|
|
65
|
-
peers remain optional for other library entry points and the bundled CLI.
|
|
225
|
+
The CLI **bundles PageGraph's Effect, TypeSafe provider runtime, and Pi agent runtime**, so it does
|
|
226
|
+
not depend on the app's Effect version; it runs on [Bun](https://bun.sh) (`bunx pagegraph`). Every
|
|
227
|
+
workflow runs in-process on Pi 1.0.0. Improve workflows use guarded repository edit tools;
|
|
228
|
+
research and dry-run actions expose only read tools. Every workflow failure after run creation
|
|
229
|
+
writes `failure.json` with its stage, agent messages, and cause chain. `vite` stays a peer — graph commands load your app through Vite at
|
|
230
|
+
runtime — and `lighthouse` is only needed by `pagegraph audit`. Importing `pagegraph/audit`
|
|
231
|
+
programmatically needs `effect@^4.0.0`. The Effect and TypeSafe peers remain optional for other
|
|
232
|
+
library entry points and the bundled CLI.
|
|
66
233
|
|
|
67
234
|
### Agent skill
|
|
68
235
|
|
|
@@ -195,15 +362,14 @@ import { robotsTxt } from "pagegraph/tanstack-start/server";
|
|
|
195
362
|
export const Route = createFileRoute("/robots.txt")({ server: { handlers: { GET: robotsTxt } } });
|
|
196
363
|
```
|
|
197
364
|
|
|
198
|
-
**5. Gate CI.** The CLI reads the same graph through `
|
|
365
|
+
**5. Gate CI.** The CLI reads the same graph through `pagegraph.config.ts`:
|
|
199
366
|
|
|
200
367
|
```ts
|
|
201
|
-
//
|
|
368
|
+
// pagegraph.config.ts
|
|
202
369
|
import { defineSeoConfig } from "pagegraph/config";
|
|
203
370
|
import { tanstackStartGraph } from "pagegraph/tanstack-start";
|
|
204
371
|
|
|
205
372
|
export default defineSeoConfig({
|
|
206
|
-
origin: "https://example.com",
|
|
207
373
|
loadGraph: tanstackStartGraph({ root: import.meta.dirname }),
|
|
208
374
|
});
|
|
209
375
|
```
|
|
@@ -217,7 +383,7 @@ pagegraph check
|
|
|
217
383
|
`buildSeoGraph({ routeTree, collections })` builds the same graph from any TanStack
|
|
218
384
|
Router tree; render it with `renderSitemap(graph, { origin, indexable })` and
|
|
219
385
|
`renderRobots(graph, { origin, indexable, disallow, contentSignal })`, and point
|
|
220
|
-
`
|
|
386
|
+
`pagegraph.config.ts` at it with `viteGraphLoader` (see [CLI](#cli)).
|
|
221
387
|
|
|
222
388
|
`renderRobots` does not invent a Content-Signal. Pass `contentSignal` for
|
|
223
389
|
the value (the plugin prefixes `Content-Signal: `), `directives` for extra
|
|
@@ -227,28 +393,37 @@ Preview hosts (`indexable: false`) drop `contentSignal` and `directives`;
|
|
|
227
393
|
|
|
228
394
|
## Agentic workflows
|
|
229
395
|
|
|
230
|
-
PageGraph
|
|
231
|
-
|
|
396
|
+
PageGraph combines the deterministic route graph with project-owned agent instructions, live
|
|
397
|
+
Executor tools, and Jev decisions. Every workflow uses Pi in-process. Scaffold the shared preset once:
|
|
232
398
|
|
|
233
399
|
```bash
|
|
234
400
|
pagegraph init
|
|
235
401
|
```
|
|
236
402
|
|
|
237
|
-
The generated `.pagegraph/
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
403
|
+
The generated `.pagegraph/agent` directory contains the `seo` agent instructions, `AGENTS.md`,
|
|
404
|
+
and customizable workflow skills with Executor recipes. Pi composes these files into its system
|
|
405
|
+
prompt and fails if a required file is missing. Pi uses its provider-specific environment variables
|
|
406
|
+
for model authentication, such as `ANTHROPIC_API_KEY` or `OPENAI_API_KEY`.
|
|
241
407
|
|
|
242
|
-
|
|
408
|
+
Research connects to [Executor](https://github.com/RhysSullivan/executor) through
|
|
409
|
+
`@pi-ext/executor`. Set `EXECUTOR_BASE_URL` to the server, plus `EXECUTOR_CLIENT_ID[_FILE]` and
|
|
410
|
+
`EXECUTOR_CLIENT_SECRET[_FILE]` when Cloudflare Access fronts it (both or neither). Every workflow
|
|
411
|
+
declines Executor approval requests, and only provider calls that succeeded count as evidence.
|
|
412
|
+
Use `executor_search` to discover tools and their TypeScript shapes, then `executor_execute` with
|
|
413
|
+
a TypeScript snippet calling `tools.<namespace>.<tool>(input)` and a top-level `return`.
|
|
414
|
+
Repository tools are `read_file`, `list_files`, and `search_text`; structured results go through
|
|
415
|
+
`submit_result`. Improve action turns expose `edit_file` and `write_file` in write mode.
|
|
416
|
+
|
|
417
|
+
Enable workflows in `pagegraph.config.ts`:
|
|
243
418
|
|
|
244
419
|
```ts
|
|
245
420
|
export default defineSeoConfig({
|
|
246
421
|
// origin, disallow, and loadGraph as above
|
|
247
422
|
workflows: {
|
|
248
|
-
|
|
249
|
-
|
|
423
|
+
agent: {
|
|
424
|
+
presetDirectory: ".pagegraph/agent",
|
|
250
425
|
defaultModel: "openrouter/example/model",
|
|
251
|
-
// Optional per-
|
|
426
|
+
// Optional per-turn budget in milliseconds; default 180000.
|
|
252
427
|
timeoutMs: 360_000,
|
|
253
428
|
models: {
|
|
254
429
|
"research.keywords": "openrouter/example/research-model",
|
|
@@ -279,9 +454,9 @@ Executor's live catalog and inspect the discovered tools' argument schemas, then
|
|
|
279
454
|
structured observations with Jev. Tool paths are discovered at runtime; the generated skills contain
|
|
280
455
|
editable starter recipes, not a fixed integration list.
|
|
281
456
|
|
|
282
|
-
`workflows.
|
|
283
|
-
|
|
284
|
-
|
|
457
|
+
`workflows.agent.timeoutMs` sets the positive integer deadline in milliseconds for each Pi research or action turn
|
|
458
|
+
(maximum `2147483647`, default `180000`). Research and action share the same agent conversation,
|
|
459
|
+
so action turns retain the research context.
|
|
285
460
|
|
|
286
461
|
Selecting pages preserves their incoming and outgoing relationships to non-selected pages in
|
|
287
462
|
`evidence.neighborhood`. Those neighbors supply architecture context without becoming workflow
|
|
@@ -289,12 +464,13 @@ targets or consuming `--limit`. The agent receives the limit before research, an
|
|
|
289
464
|
the decoded result before decisions.
|
|
290
465
|
|
|
291
466
|
After research is validated, the run directory contains `research.json`: an incomplete checkpoint
|
|
292
|
-
with the collected evidence, decision inputs, and
|
|
293
|
-
its path so the evidence remains available for diagnosis. Only a completed workflow writes
|
|
467
|
+
with the collected evidence, decision inputs, and agent messages. A downstream failure
|
|
468
|
+
reports its path so the evidence remains available for diagnosis. Only a completed workflow writes
|
|
294
469
|
`run.json` and `summary.md`; a research checkpoint is not a final recommendation.
|
|
295
|
-
Model
|
|
296
|
-
|
|
297
|
-
|
|
470
|
+
Model results drop null properties and array elements before validation. Pi receives decode issues
|
|
471
|
+
and missing Executor evidence through `submit_result`, so it can correct the result in the same
|
|
472
|
+
agent loop; repeated rejected submissions fail the run. Every error after run creation writes
|
|
473
|
+
`failure.json` with the workflow, stage, agent messages, and full cause
|
|
298
474
|
chain. The error reports the artifact path and a next step; a failed artifact write preserves the
|
|
299
475
|
original error with a note.
|
|
300
476
|
|
|
@@ -313,20 +489,24 @@ original error with a note.
|
|
|
313
489
|
| `improve links` | Contextual internal-link edits from graph and page evidence |
|
|
314
490
|
|
|
315
491
|
The common selectors are repeatable `--page`, `--query`, and `--kind`, plus `--limit`, `--market`,
|
|
316
|
-
`--language`, `--refresh`, `--model`, `--
|
|
317
|
-
accept `--competitor`, `--domain`, or `--device desktop|mobile`.
|
|
318
|
-
|
|
492
|
+
`--language`, `--refresh`, `--model`, `--preset-directory`, and `--out`. Relevant workflows also
|
|
493
|
+
accept `--competitor`, `--domain`, or `--device desktop|mobile`. Workflow prompts direct the agent
|
|
494
|
+
to proceed without questions or forms and fail clearly when required input is missing.
|
|
319
495
|
|
|
320
496
|
The four `improve` workflows write source files by default and require a clean Git tree. Use
|
|
321
|
-
`--dry-run` to
|
|
497
|
+
`--dry-run` to expose only read tools, or `--allow-dirty` when you explicitly
|
|
322
498
|
want the agent to edit alongside existing changes. PageGraph leaves every diff uncommitted and
|
|
323
|
-
records modified, added, and deleted files after the workflow finishes.
|
|
499
|
+
records modified, added, and deleted files after the workflow finishes. Write tools reject paths
|
|
500
|
+
outside the repository, including symlink escapes, and paths under `.git`, `node_modules`,
|
|
501
|
+
the runs directory, and the preset directory. There is no shell tool. For `improve links`,
|
|
502
|
+
`fetch_page` reads extracted sentences from served pages on suggestion-report origins, respecting
|
|
503
|
+
robots rules and the response size limit.
|
|
324
504
|
|
|
325
505
|
Each run writes `.pagegraph/runs/<run-id>/run.json` and `summary.md`. The JSON retains the
|
|
326
|
-
deterministic graph, context,
|
|
327
|
-
|
|
328
|
-
ignored: provider output can be large or account-specific. Workflows fail when the configured model,
|
|
329
|
-
|
|
506
|
+
deterministic graph, context, Executor tool evidence, Jev question definitions and answers, Git
|
|
507
|
+
provenance, changed files, and model provenance. Schema-version-2 artifacts record `agent.runtime`
|
|
508
|
+
as the literal `pi`, with messages and usage. Keep this directory ignored: provider output can be large or account-specific. Workflows fail when the configured model,
|
|
509
|
+
Executor toolset, catalog search plus completed tool call, or `TYPESAFE_API_KEY` for Jev is
|
|
330
510
|
unavailable.
|
|
331
511
|
|
|
332
512
|
## Typed paths
|
|
@@ -406,27 +586,106 @@ It also derives a small config module from the route tree: `robotsExclusions`
|
|
|
406
586
|
(the plugin adds them to robots.txt; a Router-only app feeds them to `renderRobots`) and
|
|
407
587
|
`reservedSegments` (top-level segments an app must not hand out as tenant/org slugs).
|
|
408
588
|
|
|
589
|
+
## Claims gate
|
|
590
|
+
|
|
591
|
+
Declare probability rules against `claimsInput` from the build-only `pagegraph/claims` entry.
|
|
592
|
+
Each rule asks whether the section violates your policy:
|
|
593
|
+
|
|
594
|
+
```ts
|
|
595
|
+
import { Decision } from "effect/ai";
|
|
596
|
+
import { claimsInput } from "pagegraph/claims";
|
|
597
|
+
import { pagegraph } from "pagegraph/tanstack-start";
|
|
598
|
+
|
|
599
|
+
const rules = Decision.make({
|
|
600
|
+
input: claimsInput,
|
|
601
|
+
decisions: {
|
|
602
|
+
unsupportedPromise: Decision.probability({
|
|
603
|
+
instructions: "Does this section promise a capability unsupported by its facts or evidence?",
|
|
604
|
+
}),
|
|
605
|
+
},
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
const graph = pagegraph({
|
|
609
|
+
origin: "https://example.com",
|
|
610
|
+
markdown: { origin: "https://example.com" },
|
|
611
|
+
facts: "src/facts.ts",
|
|
612
|
+
claims: { rules, model: "typesafe/jev", cutoff: 0.8 },
|
|
613
|
+
});
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
Pass `graph.prerenderPages` to Start as shown in the rendered Markdown setup. The build persists
|
|
617
|
+
captured documents and graph heads, then replays committed answers without a model or credentials.
|
|
618
|
+
Missing answers and violations fail the build and name the page, section, and rule.
|
|
619
|
+
|
|
620
|
+
Run `pagegraph claims check` after changing prose, facts, context, or rules, then review and commit
|
|
621
|
+
`.pagegraph/decisions/claims/`. The cache key includes the rule definition fingerprint, model, and
|
|
622
|
+
input hash. Cached answers are reused; `--refresh` asks again and replaces them. The command reports
|
|
623
|
+
cached and asked counts and exits nonzero on violations. Set `TYPESAFE_API_KEY` when answers need
|
|
624
|
+
asking. `pagegraph check` also replays configured claims without model calls.
|
|
625
|
+
|
|
626
|
+
```sh
|
|
627
|
+
pagegraph claims check
|
|
628
|
+
pagegraph claims check --refresh
|
|
629
|
+
pagegraph claims check --dev http://localhost:3000
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
`claims.context` supplies policy text to every input. Inputs include the section's authored
|
|
633
|
+
Markdown, messages, all code-owned facts, and other sections marked as evidence. Page metadata is
|
|
634
|
+
judged as a `head` section, including graph pages outside rendered capture. `excludeHeads` accepts
|
|
635
|
+
path globs to omit metadata while keeping captured sections in the gate. The default cutoff is
|
|
636
|
+
`0.8` only when omitted; any probability at or above the configured cutoff is a violation, and
|
|
637
|
+
values below it pass. Changing the cutoff reuses answers and recalculates verdicts.
|
|
638
|
+
|
|
639
|
+
## Markdown CLI
|
|
640
|
+
|
|
641
|
+
Inspect captured documents, search page metadata and sections, and maintain a reviewable lock:
|
|
642
|
+
|
|
643
|
+
```sh
|
|
644
|
+
pagegraph markdown show /pricing
|
|
645
|
+
pagegraph markdown find email
|
|
646
|
+
pagegraph markdown lock
|
|
647
|
+
pagegraph markdown lock --check
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
`show` prints the page's Markdown twin. `find` reports matching pages and sections.
|
|
651
|
+
`lock` writes `.pagegraph/markdown.lock.json` from document and message hashes, including
|
|
652
|
+
head-only pages; `--check` exits nonzero if the lock is missing or differs. These commands use
|
|
653
|
+
`.pagegraph/documents/` and `.pagegraph/heads.json` from the build. Use `--dev <origin>` to inspect
|
|
654
|
+
the development bundle instead. `--json` emits structured output using the CLI's usual conventions.
|
|
655
|
+
Markdown and claims settings come from `pagegraph()` in Vite, including the canonical Markdown
|
|
656
|
+
origin and facts module. Built-mode commands read Vite with `command: "build"` and
|
|
657
|
+
`mode: "production"`; `--dev` reads `command: "serve"` and `mode: "development"`.
|
|
658
|
+
Put CLI policies and the graph loader in `pagegraph.config.ts`.
|
|
659
|
+
|
|
409
660
|
## CLI
|
|
410
661
|
|
|
411
|
-
The graph commands acquire your graph through `
|
|
662
|
+
The graph commands acquire your graph through `pagegraph.config.ts` at the app root.
|
|
663
|
+
Rename an existing `seo.config.ts`, `.js`, or `.mjs` to its `pagegraph.config.*` equivalent.
|
|
664
|
+
The file holds CLI policies and `loadGraph`; site identity and robots policy come from the
|
|
665
|
+
loader result, and Markdown and claims settings come from the Vite plugin. A
|
|
412
666
|
TanStack Start app uses `tanstackStartGraph` (above), which also supplies the robots
|
|
413
|
-
policy
|
|
414
|
-
|
|
667
|
+
policy and site identity from `pagegraph()`, using build settings in production mode by default.
|
|
668
|
+
Pass `command: "serve", mode: "development"` to inspect a development configuration instead.
|
|
669
|
+
Otherwise `viteGraphLoader` evaluates your graph
|
|
670
|
+
module inside a headless Vite server, so path aliases, content plugins, and virtual modules all resolve:
|
|
415
671
|
|
|
416
672
|
```ts
|
|
417
|
-
//
|
|
673
|
+
// pagegraph.config.ts
|
|
418
674
|
import { defineSeoConfig, viteGraphLoader } from "pagegraph/config";
|
|
675
|
+
import { routeConfig } from "./src/lib/route-config";
|
|
419
676
|
|
|
420
677
|
export default defineSeoConfig({
|
|
421
|
-
origin: "https://example.com",
|
|
422
|
-
disallow: routeConfig.robotsExclusions,
|
|
423
|
-
contentSignal: "search=yes, ai-input=yes, ai-train=yes",
|
|
424
678
|
// Fail `check` unless each named money page has enough contextual links.
|
|
425
679
|
coverage: [{ path: "/pricing", minInbound: 2 }, { path: "/features/*", minInbound: 1 }],
|
|
426
680
|
loadGraph: viteGraphLoader({
|
|
427
681
|
root: import.meta.dirname,
|
|
428
682
|
entry: "/lib/seo/graph.ts",
|
|
429
683
|
exportName: "loadSeoGraph",
|
|
684
|
+
site: {
|
|
685
|
+
origin: "https://example.com",
|
|
686
|
+
indexable: true,
|
|
687
|
+
robots: { disallow: routeConfig.robotsExclusions, contentSignal: "search=yes, ai-input=yes, ai-train=yes" },
|
|
688
|
+
},
|
|
430
689
|
}),
|
|
431
690
|
});
|
|
432
691
|
```
|
|
@@ -461,7 +720,7 @@ pagegraph graph # the graph as a tree · --format mermaid | json
|
|
|
461
720
|
pagegraph inspect /pricing # one node: policy, sitemap status, in/out edges
|
|
462
721
|
pagegraph inspect <url> --live # fetch a deployed page, validate its rendered <head>
|
|
463
722
|
pagegraph links verify <url> # crawl served HTML: depth, orphans, declared-vs-rendered
|
|
464
|
-
pagegraph links verify <url> --assert-coverage # also assert
|
|
723
|
+
pagegraph links verify <url> --assert-coverage # also assert pagegraph.config.ts coverage on served anchors
|
|
465
724
|
pagegraph links verify <url> --emit-rendered <file> # save the rendered edge set
|
|
466
725
|
pagegraph links candidates # propose contextual links from the declared graph
|
|
467
726
|
pagegraph research keywords --query "email api" # combine graph, Executor, and Jev evidence
|
|
@@ -477,7 +736,7 @@ Stdout is data, stderr is status — `pagegraph check --json | jq` just works.
|
|
|
477
736
|
`pagegraph links verify` crawls a site's served HTML — through the same DNS-pinned,
|
|
478
737
|
private-IP-blocked HTTP path as `pagegraph audit` — and reports what a crawler
|
|
479
738
|
actually receives: the real homepage depth, the pages with no incoming internal
|
|
480
|
-
edge (rendered orphans), and, when the app has a `
|
|
739
|
+
edge (rendered orphans), and, when the app has a `pagegraph.config.ts`, the
|
|
481
740
|
declared-vs-rendered link diff. It is bounded with `--limit` and needs no
|
|
482
741
|
framework or config. Discovery reads same-origin `robots.txt` and bounded
|
|
483
742
|
sitemaps before following page anchors, so a sitemap-only page can appear as an
|
|
@@ -532,7 +791,7 @@ It is also a drop-in input for `pagegraph links candidates --rendered`.
|
|
|
532
791
|
|
|
533
792
|
### Assert coverage on the rendered graph
|
|
534
793
|
|
|
535
|
-
`pagegraph check` evaluates the `
|
|
794
|
+
`pagegraph check` evaluates the `pagegraph.config.ts` `coverage` rules against the
|
|
536
795
|
**declared** graph; `pagegraph links verify --assert-coverage` evaluates the same
|
|
537
796
|
rules against the anchors a crawler **actually receives**. Only same-origin
|
|
538
797
|
body-region anchors count — nav, header, and footer links are chrome — which is
|
|
@@ -549,7 +808,7 @@ non-zero) rather than reporting a false pass when the crawl outran `--limit`, a
|
|
|
549
808
|
page failed to fetch (its anchors are missing), a body hit `--max-body-bytes`, the
|
|
550
809
|
robots or sitemap discovery is incomplete, the
|
|
551
810
|
config declares no `coverage`, or the artifact's origin differs from
|
|
552
|
-
`
|
|
811
|
+
`pagegraph.config.ts`. Under `--assert-coverage` the report gains a `coverage` block
|
|
553
812
|
(`{ rules, ok, violations }`); the default `--json` summary is unchanged.
|
|
554
813
|
|
|
555
814
|
### Propose contextual links
|
|
@@ -615,7 +874,7 @@ both `links candidates --site` and `improve links --suggestions`.
|
|
|
615
874
|
|
|
616
875
|
### Contextual-link coverage
|
|
617
876
|
|
|
618
|
-
Declare a contextual-link coverage policy in `
|
|
877
|
+
Declare a contextual-link coverage policy in `pagegraph.config.ts` (a `coverage` array
|
|
619
878
|
of `{ path, minInbound }`), or pass repeatable `--require-inbound "<path-glob>=<n>"`
|
|
620
879
|
flags to override it for one run. `pagegraph check` then fails (exit 1) unless
|
|
621
880
|
every sitemap-eligible page matching the glob has at least `minInbound` incoming
|
|
@@ -709,7 +968,7 @@ undated rather than stale; give content its `modifiedAt` (or a route its
|
|
|
709
968
|
|
|
710
969
|
### Audit any website
|
|
711
970
|
|
|
712
|
-
`pagegraph audit` is framework-independent and does not need `
|
|
971
|
+
`pagegraph audit` is framework-independent and does not need `pagegraph.config.ts`. It
|
|
713
972
|
validates target URLs before making requests, follows redirects through the same
|
|
714
973
|
validation boundary, inspects the rendered document and discovery files, and
|
|
715
974
|
can collect Lighthouse evidence through a validating proxy.
|