@shoalrun/cli 0.1.0-beta.1 → 1.0.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/CHANGELOG.md +17 -0
- package/CODE-REFERENCES.md +137 -0
- package/README.md +8 -5
- package/adapters/python/requirements.txt +1 -0
- package/adapters/python/shoalrun_reference.py +234 -0
- package/agent-docs/.well-known/shoalrun/navigation/project-updates-50f26fe22670.txt +4 -2
- package/agent-docs/SNAPSHOT.json +5 -5
- package/agent-docs/about.md +3 -3
- package/agent-docs/api-docs/code-reference-settings.md +160 -0
- package/agent-docs/api-docs/code-reference-settings.sections/catalog-settings.md +50 -0
- package/agent-docs/api-docs/code-reference-settings.sections/complete-reference-page.md +46 -0
- package/agent-docs/api-docs/code-reference-settings.sections/converter-snapshot.md +58 -0
- package/agent-docs/api-docs/code-reference-settings.sections/descriptions-type-links-and-source-links.md +40 -0
- package/agent-docs/api-docs/code-reference-settings.sections/html-markdown-and-agents.md +38 -0
- package/agent-docs/api-docs/code-reference-settings.sections/metadata-and-selection.md +38 -0
- package/agent-docs/api-docs/code-reference-settings.sections/publication-sources.md +54 -0
- package/agent-docs/api-docs/code-reference-settings.sections/python-adapter-limits.md +38 -0
- package/agent-docs/api-docs/code-reference-settings.sections/related-reading.md +32 -0
- package/agent-docs/api-docs/code-reference-settings.sections/symbol-fields.md +56 -0
- package/agent-docs/api-docs/code-references.md +143 -0
- package/agent-docs/author/agent-overview.md +2 -2
- package/agent-docs/changelog/code-api-references.md +44 -0
- package/agent-docs/changelog.md +9 -1
- package/agent-docs/cli.md +11 -1
- package/agent-docs/cli.sections/audit-a-project-and-api-sources.md +1 -1
- package/agent-docs/cli.sections/author-pages.md +1 -1
- package/agent-docs/cli.sections/build-and-serve.md +1 -1
- package/agent-docs/cli.sections/inspect-config-and-operations.md +1 -1
- package/agent-docs/cli.sections/npm-scripts-in-this-repository.md +1 -1
- package/agent-docs/cli.sections/related-reading.md +1 -1
- package/agent-docs/cli.sections/search-and-chat.md +1 -1
- package/agent-docs/cli.sections/start-a-project.md +1 -1
- package/agent-docs/cli.sections/validate-code-reference-snapshots.md +41 -0
- package/agent-docs/cli.sections/working-tree-authoring-tools.md +1 -1
- package/agent-docs/config/apis.md +5 -1
- package/agent-docs/config/examples.md +3 -3
- package/agent-docs/config/examples.sections/feature-showcase.md +3 -3
- package/agent-docs/config/examples.sections/minimal-site.md +2 -2
- package/agent-docs/config/examples.sections/multilingual-help-center.md +2 -2
- package/agent-docs/config/examples.sections/parcel-api-documentation.md +2 -2
- package/agent-docs/config/examples.sections/related-reading.md +2 -2
- package/agent-docs/config/examples.sections/shared-company-preset.md +2 -2
- package/agent-docs/config.md +2 -2
- package/agent-docs/configuration.md +2 -2
- package/agent-docs/configuration.sections/build-several-sites-from-shared-content.md +1 -1
- package/agent-docs/configuration.sections/change-inherited-lists-deliberately.md +1 -1
- package/agent-docs/configuration.sections/extract-a-section-with-include.md +1 -1
- package/agent-docs/configuration.sections/inspect-and-validate-changes.md +1 -1
- package/agent-docs/configuration.sections/related-reading.md +1 -1
- package/agent-docs/configuration.sections/separate-config-inheritance-from-page-metadata.md +1 -1
- package/agent-docs/configuration.sections/share-defaults-through-extends.md +1 -1
- package/agent-docs/configuration.sections/start-with-one-working-file.md +2 -2
- package/agent-docs/configuration.sections/understand-the-three-stages.md +1 -1
- package/agent-docs/configuration.sections/understand-where-paths-point.md +1 -1
- package/agent-docs/documents.json +609 -215
- package/agent-docs/features.md +3 -2
- package/agent-docs/provenance.json +6 -6
- package/agent-docs/publish/api-references.md +3 -1
- package/agent-docs/publish/api-references.sections/author-the-reference-page.md +3 -1
- package/agent-docs/publish/api-references.sections/build-and-verify-the-output.md +3 -1
- package/agent-docs/publish/api-references.sections/inspect-the-machine-readable-contract.md +3 -1
- package/agent-docs/publish/api-references.sections/next-steps.md +3 -1
- package/agent-docs/publish/api-references.sections/preview-a-small-api-reference.md +3 -1
- package/agent-docs/publish/api-references.sections/put-the-spec-in-your-project.md +3 -1
- package/agent-docs/publish/api-references.sections/register-the-operation.md +3 -1
- package/agent-docs/publish/api-references.sections/related-reading.md +3 -1
- package/agent-docs/publish/api-references.sections/review-imported-content-before-publishing.md +3 -1
- package/agent-docs/publish/api-references.sections/what-readers-get.md +3 -1
- package/agent-docs/search-index.json +1 -1
- package/agent-docs/start.md +3 -3
- package/agent-docs/start.sections/add-the-page-to-navigation.md +2 -2
- package/agent-docs/start.sections/build-and-check-both-outputs.md +2 -2
- package/agent-docs/start.sections/build-this-site.md +2 -2
- package/agent-docs/start.sections/check-writing-style.md +2 -2
- package/agent-docs/start.sections/create-a-page.md +2 -2
- package/agent-docs/start.sections/make-it-yours.md +2 -2
- package/agent-docs/start.sections/migrating-from-github-packages.md +2 -2
- package/agent-docs/start.sections/prerequisites.md +2 -2
- package/agent-docs/start.sections/related-reading.md +2 -2
- package/agent-docs/start.sections/start-your-own-project.md +3 -3
- package/agent-docs/status.md +6 -4
- package/agent-docs/styling/themes.md +7 -3
- package/agent-docs/what-is-shoalrun.md +2 -2
- package/dist/artifact-bundle.d.ts +1 -0
- package/dist/artifact-bundle.js +11 -3
- package/dist/cli-discovery.d.ts +1 -1
- package/dist/cli-discovery.js +1 -0
- package/dist/cli.js +7 -0
- package/dist/code-reference-model.d.ts +85 -0
- package/dist/code-reference-model.js +73 -0
- package/dist/code-references.d.ts +23 -0
- package/dist/code-references.js +371 -0
- package/dist/compiler-config.d.ts +1 -0
- package/dist/compiler.js +4 -3
- package/dist/config.js +1 -1
- package/dist/content-source.d.ts +1 -0
- package/dist/content-workspace.d.ts +1 -0
- package/dist/content-workspace.js +2 -0
- package/dist/fonts.d.ts +9 -0
- package/dist/fonts.js +58 -3
- package/dist/page-materialization.js +3 -2
- package/dist/page-renderer.d.ts +1 -0
- package/dist/page-renderer.js +3 -1
- package/dist/publication-render.d.ts +2 -1
- package/dist/publication-render.js +2 -2
- package/dist/representation-tree.js +4 -0
- package/examples/code-references/content/start.md +53 -0
- package/examples/code-references/docs.config.yaml +262 -0
- package/examples/code-references/python/orchard/__init__.py +11 -0
- package/examples/code-references/python/orchard/client.py +212 -0
- package/examples/code-references/python/orchard/errors.py +31 -0
- package/examples/code-references/python/orchard/models.py +69 -0
- package/examples/code-references/python/orchard/pagination.py +39 -0
- package/examples/code-references/reference.json +1244 -0
- package/package.json +8 -1
- package/schemas/code-reference.schema.json +306 -0
- package/skills/shoalrun-author/SKILL.md +4 -0
- package/skills/shoalrun-author/references/code-api-references.md +15 -0
- package/styles/site.css +61 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.0 — 2026-11-06
|
|
4
|
+
|
|
5
|
+
- Generate [code API references](https://www.shoalrun.com/api-docs/code-references)
|
|
6
|
+
from Python source and docstrings, or bring a converter using the shared JSON
|
|
7
|
+
snapshot format. Choose symbol, class, module, or optional complete-page
|
|
8
|
+
references with linked types, field defaults, and native content delivery.
|
|
9
|
+
- Preload local custom body and heading fonts, cache custom assets by content,
|
|
10
|
+
and revalidate bundled fonts. Match the preset's font style and CSS weight
|
|
11
|
+
selection, including overlapping face registrations.
|
|
12
|
+
- Tighten shared page-header spacing around metadata and page actions.
|
|
13
|
+
- Correct npm distribution tagging and verify it separately from upload.
|
|
14
|
+
Stable releases use `latest`; later prereleases preserve that stable channel.
|
|
15
|
+
|
|
16
|
+
Upgrade to CLI `1.0.0` and rebuild. Python extraction is optional and runs
|
|
17
|
+
explicitly; normal site builds consume the saved snapshot without Python.
|
|
18
|
+
|
|
19
|
+
|
|
3
20
|
## 0.1.0-beta.1 — 2026-11-05
|
|
4
21
|
|
|
5
22
|
- Add custom code-fence highlighting with local TextMate JSON grammars and aliases.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Code API references
|
|
2
|
+
|
|
3
|
+
Code API references describe a library's classes, functions, methods, fields, parameters, return values, and exceptions. OpenAPI references describe HTTP endpoints. Guides explain how to accomplish tasks; code references explain the interfaces used to accomplish them.
|
|
4
|
+
|
|
5
|
+
Shoalrun consumes a versioned JSON snapshot and generates native reference pages. The pages participate in navigation, search, publication selection, reader filters, customer-profile pruning, Markdown output, content exports, and PDF exports. They use the site's theme and a compact code-reference layout with signatures and member tables.
|
|
6
|
+
|
|
7
|
+
## Generate Python references
|
|
8
|
+
|
|
9
|
+
The optional Python adapter reads local source with Griffe. It doesn't import the documented package or enable runtime inspection, extensions, or external alias resolution. It requires Python 3.11 or newer and the pinned `griffelib` dependency. Normal Shoalrun builds consume the JSON snapshot and don't require Python.
|
|
10
|
+
|
|
11
|
+
From a checkout of this package:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
python3.11 -m venv .venv-reference
|
|
15
|
+
.venv-reference/bin/python -m pip install --require-hashes -r adapters/python/requirements.txt
|
|
16
|
+
.venv-reference/bin/python adapters/python/shoalrun_reference.py \
|
|
17
|
+
--root examples/code-references/python --module orchard \
|
|
18
|
+
--out examples/code-references/reference.json
|
|
19
|
+
shoalrun references check examples/code-references/reference.json
|
|
20
|
+
shoalrun build examples/code-references/docs.config.yaml site-dist
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Use `--style google`, `--style numpy`, or `--style sphinx` for the docstring convention. Review the generated snapshot before publishing it. Public source declarations and their docstrings can contain sensitive information even when extraction doesn't execute code.
|
|
24
|
+
|
|
25
|
+
The adapter emits locally defined symbols, skips aliases and underscore-prefixed members except constructors, and rejects symlinks in its declared source root. It doesn't expand inherited members, execute decorators, resolve external re-exports, or infer undocumented behavior. Its example SDK stores records in memory and doesn't contact a live service.
|
|
26
|
+
|
|
27
|
+
## Configure a catalog
|
|
28
|
+
|
|
29
|
+
```yaml
|
|
30
|
+
codeReferences:
|
|
31
|
+
sdk:
|
|
32
|
+
source: { kind: file, path: ./reference.json }
|
|
33
|
+
pathPrefix: /reference/code
|
|
34
|
+
symbols:
|
|
35
|
+
orchard.client.Client:
|
|
36
|
+
documentId: reference.client
|
|
37
|
+
slug: /reference/client
|
|
38
|
+
navigation:
|
|
39
|
+
- { id: client, doc: reference.client }
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Paths resolve relative to the file that declares them and must stay inside the project root. Generated pages use `type: code-reference`. The `programmingLanguage` in a snapshot is distinct from a publication's language, such as `en`.
|
|
43
|
+
|
|
44
|
+
Set `symbols.<symbol-id>.documentId` and `slug` to keep deliberate public identities and URLs. Without these settings, Shoalrun generates deterministic IDs and routes from the catalog and symbol IDs. Moving or renaming a symbol changes those defaults.
|
|
45
|
+
|
|
46
|
+
Use `include` and `exclude` lists of exact symbol IDs to select public symbols. Private symbols and descendants of private symbols aren't published. `metadata` supplies ordinary page metadata; `symbols.<id>.metadata` overrides it for one symbol. A symbol's explicit `shared` or `requires` classification replaces the catalog's classification. Each symbol's feature requirements are evaluated separately; classification isn't inherited from its parent symbol. Project frontmatter defaults and enforced settings still apply.
|
|
47
|
+
|
|
48
|
+
For independent product versions, replace `source` with explicit source bindings:
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
codeReferences:
|
|
52
|
+
sdk:
|
|
53
|
+
publications:
|
|
54
|
+
- product: sdk
|
|
55
|
+
channel: production
|
|
56
|
+
version: v1
|
|
57
|
+
language: en
|
|
58
|
+
source: { kind: file, path: ./reference-v1.json }
|
|
59
|
+
- product: sdk
|
|
60
|
+
channel: production
|
|
61
|
+
version: v2
|
|
62
|
+
language: en
|
|
63
|
+
source: { kind: file, path: ./reference-v2.json }
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Declare those products and versions in `publications` as usual. Each binding uses its own snapshot. Links and member tables include only eligible pages in the same catalog and publication.
|
|
67
|
+
|
|
68
|
+
## Bring another converter
|
|
69
|
+
|
|
70
|
+
A converter for Kotlin or another language can emit the same snapshot format. Shoalrun doesn't need to load that converter during compilation. Run it explicitly in your own build workflow, validate its output, and point a catalog at the resulting file.
|
|
71
|
+
|
|
72
|
+
The contract is [schemas/code-reference.schema.json](schemas/code-reference.schema.json). A minimal snapshot looks like this:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"schemaVersion": 1,
|
|
77
|
+
"kind": "shoalrun-code-reference",
|
|
78
|
+
"programmingLanguage": "kotlin",
|
|
79
|
+
"producer": { "name": "example-converter", "version": "1.0.0" },
|
|
80
|
+
"symbols": [{
|
|
81
|
+
"id": "example.greet",
|
|
82
|
+
"name": "greet",
|
|
83
|
+
"kind": "function",
|
|
84
|
+
"summary": "Create a greeting.",
|
|
85
|
+
"signatures": ["fun greet(name: String): String"],
|
|
86
|
+
"parameters": [{ "name": "name", "type": "String", "description": "Reader name." }],
|
|
87
|
+
"returns": { "type": "String", "description": "The greeting." }
|
|
88
|
+
}]
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
This illustrates the converter contract; it isn't a bundled Kotlin extractor. Supported symbol kinds are module, namespace, class, interface, enum, type, function, method, constructor, property, attribute, and constant. Optional fields include `parent`, `description`, `raises`, `yields`, `examples`, `seeAlso`, relative source provenance, and a source digest. Symbol IDs must be unique, referenced IDs must exist, and parent ownership must be acyclic. `shoalrun references check` performs these semantic checks as well as schema validation. JavaScript tools can import `validateCodeReference` from `@shoalrun/cli/references`.
|
|
93
|
+
|
|
94
|
+
Descriptions use inert Markdown, with raw HTML stripped. They don't run MDX or expand project directives. Use `[Record](symbol:orchard.models.Record)` to link a symbol in the same catalog and publication. External links support HTTPS and mailto; relative links and images aren't supported. Use code examples for runnable-looking snippets; extraction doesn't execute or verify those examples.
|
|
95
|
+
|
|
96
|
+
## Types, fields, and source links
|
|
97
|
+
|
|
98
|
+
Converters can supply `typeReferences`, mapping the exact type text to a symbol ID in the same snapshot. Shoalrun links those types in parameter, return, yield, base-class, exception, and field descriptions only when the target is published in the same catalog and publication. Excluded targets stay plain text. Signatures retain copyable code. Shoalrun doesn't guess targets from short names.
|
|
99
|
+
|
|
100
|
+
Field symbols can supply `annotation`, `required`, and `default`. A nullable field can still be required; `required` describes whether a value must be supplied, not whether the type admits null. Unknown requirements stay unmarked. Defaults are source expressions, not evaluated values.
|
|
101
|
+
|
|
102
|
+
Class symbols can supply `bases` and `constructorSignature`. The Python adapter extracts local constructors and synthesizes simple local dataclass constructors; it leaves unsupported cases unspecified. Dataclass factory defaults appear as `<factory>` in the constructor signature and retain their source expression in the field details.
|
|
103
|
+
|
|
104
|
+
To show **View source**, configure a catalog's `sourceLink.baseUrl` with an HTTPS repository URL ending at the directory that contains the snapshot's relative source paths. Include the desired immutable commit or release in that URL. For example, a base URL ending in `/blob/<commit>/src` and a source path of `sdk/models.py` produce `/blob/<commit>/src/sdk/models.py#L12` for line 12. Query strings, fragments, and embedded credentials aren't accepted in the base URL. Shoalrun doesn't download source or publish source files automatically. Source links are omitted when no base URL is configured.
|
|
105
|
+
|
|
106
|
+
## Choose separate or grouped pages
|
|
107
|
+
|
|
108
|
+
Configure each catalog independently:
|
|
109
|
+
|
|
110
|
+
```yaml
|
|
111
|
+
codeReferences:
|
|
112
|
+
sdk:
|
|
113
|
+
source: { kind: file, path: ./reference.json }
|
|
114
|
+
layout: classes
|
|
115
|
+
singlePage:
|
|
116
|
+
documentId: reference.sdk.complete
|
|
117
|
+
slug: /reference/sdk/all
|
|
118
|
+
title: Complete SDK reference
|
|
119
|
+
navigation:
|
|
120
|
+
- { id: complete-reference, doc: reference.sdk.complete }
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`layout` accepts:
|
|
124
|
+
|
|
125
|
+
| Value | Reading experience |
|
|
126
|
+
| --- | --- |
|
|
127
|
+
| `symbols` | Separate symbol pages with linked member tables. This is the default. |
|
|
128
|
+
| `classes` | Class pages include member details inline. Module pages include their direct functions and class overviews. |
|
|
129
|
+
| `modules` | Module pages include details for the classes, functions, and fields in that module. Submodules have their own grouping. |
|
|
130
|
+
|
|
131
|
+
Individual symbol pages and URLs remain available in every layout. Choose class or module pages for the main navigation when you want fewer navigation entries. Grouping controls the reading experience; it doesn't remove the underlying symbol pages or change their content-delivery identities.
|
|
132
|
+
|
|
133
|
+
`singlePage` independently adds a complete reference for the catalog, containing every eligible symbol in the selected publication. It works with any layout. Omit it or set `singlePage: false` to disable it. Within a grouped or complete page, links to symbols included on that page jump to their sections. Links to other symbols retain their individual URLs. Generated heading anchors distinguish repeated headings, such as Parameters and Returns.
|
|
134
|
+
|
|
135
|
+
The complete page defaults to document ID `reference.<catalog>.complete` and slug `<pathPrefix>/all`. You can configure its `documentId`, `slug`, `title`, `summary`, and `metadata`. Its metadata inherits the catalog's settings; an explicit `shared` or `requires` classification replaces the catalog classification. Strictly classified projects must classify the complete page as well as the symbols.
|
|
136
|
+
|
|
137
|
+
Each combined page contains only symbols already allowed by its publication, profile grants, visibility, and build audience selection. Enabling a complete page doesn't grant access to excluded content. If no symbols are eligible, no empty complete page is emitted. Complete and grouped pages support the same HTML, Markdown, content export, and PDF workflows as other reference pages. Their default outline depth is two; explicit frontmatter settings can override it.
|
package/README.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Shoalrun builds a documentation website, Markdown pages, and application content from the same Markdown and MDX source. People can browse the site; applications and agents can read stable documents, sections, and snippet instances. Native components keep essential instructions and API details readable in both HTML and Markdown.
|
|
4
4
|
|
|
5
|
-
This package provides the `shoalrun` CLI, starter projects, agent skills, and offline documentation. It requires Node.js 22.12 or newer.
|
|
5
|
+
This package provides the `shoalrun` CLI, starter projects, agent skills, and offline documentation. It requires Node.js 22.12 or newer. The package is distributed through the public npm registry. Installation requires no npm account or package token.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
9
|
From the project where you want to keep your documentation:
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
|
-
npm install --save-dev --save-exact @shoalrun/cli@
|
|
12
|
+
npm install --save-dev --save-exact @shoalrun/cli@1.0.0
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Create and preview a site
|
|
@@ -38,7 +38,8 @@ The [features overview](https://www.shoalrun.com/features) describes the complet
|
|
|
38
38
|
| --- | --- |
|
|
39
39
|
| A documentation site | Pages, navigation, local preview, themes, palettes, fonts, and project CSS. |
|
|
40
40
|
| Reusable procedures | Recipes, shared ingredients, and cookbooks that help readers choose a complete task. |
|
|
41
|
-
| API
|
|
41
|
+
| HTTP API references | OpenAPI operation pages, code examples, focused contracts, and an explicit source-review gate. |
|
|
42
|
+
| Code API references | [Python docstrings and converter-supplied symbols](CODE-REFERENCES.md), rendered as native reference pages. |
|
|
42
43
|
| Several product releases | Independent product versions and defaults, publication routes, and a header publication selector. |
|
|
43
44
|
| Customer editions | External profiles, SKU revisions, feature grants, and conditional pages or sections. |
|
|
44
45
|
| Application help | HTML and Markdown exports, stable page/section/snippet references, static and REST clients, and instance-safe mounting. |
|
|
@@ -51,6 +52,8 @@ Local builds and keyword search need no provider credentials. Semantic retrieval
|
|
|
51
52
|
|
|
52
53
|
Use `site.logo`, `site.favicon`, and header settings for site identity. Choose a theme preset and configure `theme.palette`, `theme.mode`, and `theme.fonts`. Use `site.customCss` for changes beyond those settings. Customer profiles can supply deployment-owned branding without storing customer records in the shared source.
|
|
53
54
|
|
|
55
|
+
Local body and heading fonts registered through `theme.fonts` preload automatically. Custom font URLs include a content digest so browsers can cache them and fetch fresh files after font edits. Preloading starts the download earlier; first-visit layout movement still depends on the font metrics and connection.
|
|
56
|
+
|
|
54
57
|
Check controls and interactive states as well as article text: a dark header can contain light inputs, menus, and search results. Palette validation doesn't check arbitrary project CSS. See [themes and fonts](https://www.shoalrun.com/styling/themes), the [CSS reference](https://www.shoalrun.com/author/css), and [deployment profiles](DEPLOYMENT-PROFILES.md).
|
|
55
58
|
|
|
56
59
|
## Export styled PDFs
|
|
@@ -346,14 +349,14 @@ with a Hero replaces the standard page header and does not display its dates.
|
|
|
346
349
|
If you previously used the private GitHub Packages alpha, check `npm config get @shoalrun:registry`. Remove or replace any `@shoalrun:registry=https://npm.pkg.github.com` entry in your project or user `.npmrc`. You can explicitly select the public registry for the upgrade:
|
|
347
350
|
|
|
348
351
|
```sh
|
|
349
|
-
npm install --save-dev --save-exact @shoalrun/cli@
|
|
352
|
+
npm install --save-dev --save-exact @shoalrun/cli@1.0.0 --@shoalrun:registry=https://registry.npmjs.org
|
|
350
353
|
```
|
|
351
354
|
|
|
352
355
|
Commit the updated package manifest and lockfile together. Check that the lockfile resolves `@shoalrun/cli` from `registry.npmjs.org`. Keep any credentials needed by other private dependencies; Shoalrun itself no longer needs a package token.
|
|
353
356
|
|
|
354
357
|
## Status and development
|
|
355
358
|
|
|
356
|
-
|
|
359
|
+
Shoalrun 1.0 is the stable release line. Pin exact versions and review release notes for configuration or output-contract changes. Older release lines aren't maintained. Creating and previewing a basic site does not require a model provider or Chrome. Optional provider-backed features require their own configuration.
|
|
357
360
|
|
|
358
361
|
Shoalrun is maintainer-led and does not accept unsolicited pull requests at this time. The [repository development instructions](https://github.com/shoalrun/shoalrun#develop-the-framework) explain how to build and test your own checkout or fork.
|
|
359
362
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
griffelib==2.4.1 --hash=sha256:76bc562f936ad1ce198d2cf6d0731bd5c92a7d934b69ef828ef22ee0ffdb62ce
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Convert local Python source to Shoalrun code-reference JSON without importing it."""
|
|
3
|
+
import argparse
|
|
4
|
+
import ast
|
|
5
|
+
import hashlib
|
|
6
|
+
import importlib.metadata
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import re
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
VERSION = "1.0.0"
|
|
14
|
+
EXTRACTOR_VERSION = "2.4.1"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def convert(root, module, style):
|
|
18
|
+
if importlib.metadata.version("griffelib") != EXTRACTOR_VERSION:
|
|
19
|
+
raise ValueError(f"This adapter requires griffelib=={EXTRACTOR_VERSION}")
|
|
20
|
+
import griffe
|
|
21
|
+
|
|
22
|
+
root = root.resolve(strict=True)
|
|
23
|
+
if not root.is_dir() or not re.fullmatch(r"[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*", module):
|
|
24
|
+
raise ValueError("Provide a local source directory and a dotted Python module name")
|
|
25
|
+
# Reject symlinks before the extractor can follow any source outside this root.
|
|
26
|
+
digest = hashlib.sha256()
|
|
27
|
+
count = size = 0
|
|
28
|
+
for directory, dirs, files in os.walk(root, followlinks=False):
|
|
29
|
+
for name in dirs + files:
|
|
30
|
+
if (Path(directory) / name).is_symlink():
|
|
31
|
+
raise ValueError("Python source roots must not contain symlinks")
|
|
32
|
+
for name in sorted(files):
|
|
33
|
+
file = Path(directory) / name
|
|
34
|
+
if file.suffix not in (".py", ".pyi"):
|
|
35
|
+
continue
|
|
36
|
+
data = file.read_bytes()
|
|
37
|
+
size += len(data)
|
|
38
|
+
count += 1
|
|
39
|
+
if count > 10000 or size > 32 * 1024 * 1024:
|
|
40
|
+
raise ValueError("Python source root exceeds 10,000 files or 32 MiB")
|
|
41
|
+
relative = file.relative_to(root).as_posix().encode()
|
|
42
|
+
digest.update(len(relative).to_bytes(4, "big") + relative + len(data).to_bytes(8, "big") + data)
|
|
43
|
+
dirs.sort()
|
|
44
|
+
target = root.joinpath(*module.split("."))
|
|
45
|
+
if not target.with_suffix(".py").is_file() and not (target / "__init__.py").is_file():
|
|
46
|
+
raise ValueError("Requested module must exist as Python source under --root")
|
|
47
|
+
loaded = griffe.load(module, search_paths=[root], try_relative_path=False,
|
|
48
|
+
extensions=griffe.Extensions(), allow_inspection=False,
|
|
49
|
+
force_inspection=False, resolve_aliases=False,
|
|
50
|
+
resolve_external=False, find_stubs_package=False,
|
|
51
|
+
docstring_parser=style)
|
|
52
|
+
symbols = []
|
|
53
|
+
|
|
54
|
+
def field_info(obj):
|
|
55
|
+
info = {}
|
|
56
|
+
if obj.annotation is not None:
|
|
57
|
+
info["annotation"] = str(obj.annotation)
|
|
58
|
+
if obj.value is not None:
|
|
59
|
+
info["default"] = str(obj.value)
|
|
60
|
+
parent = obj.parent
|
|
61
|
+
if parent and parent.is_class and "dataclass" in parent.labels and "instance-attribute" in obj.labels:
|
|
62
|
+
if obj.value is None:
|
|
63
|
+
info["required"] = True
|
|
64
|
+
elif str(obj.value).startswith("field("):
|
|
65
|
+
call = ast.parse(str(obj.value), mode="eval").body
|
|
66
|
+
options = {keyword.arg: keyword.value for keyword in call.keywords}
|
|
67
|
+
if "init" not in options:
|
|
68
|
+
info["required"] = not ("default" in options or "default_factory" in options)
|
|
69
|
+
elif isinstance(options["init"], ast.Constant) and options["init"].value is False:
|
|
70
|
+
info["required"] = False
|
|
71
|
+
else:
|
|
72
|
+
info["required"] = False
|
|
73
|
+
elif parent and parent.is_class and any(str(base) in ("TypedDict", "typing.TypedDict", "typing_extensions.TypedDict") for base in parent.bases):
|
|
74
|
+
annotation = str(obj.annotation).split("[", 1)[0].rsplit(".", 1)[-1]
|
|
75
|
+
info["required"] = annotation != "NotRequired" and (annotation == "Required" or str(parent.keywords.get("total", "True")) != "False")
|
|
76
|
+
return info
|
|
77
|
+
|
|
78
|
+
def type_references(obj, expressions):
|
|
79
|
+
references = {}
|
|
80
|
+
for expression in expressions:
|
|
81
|
+
if expression is None:
|
|
82
|
+
continue
|
|
83
|
+
if isinstance(expression, str):
|
|
84
|
+
for token in re.findall(r"[A-Za-z_]\w*(?:\.\w+)*", expression):
|
|
85
|
+
try:
|
|
86
|
+
references[token] = obj.resolve(token)
|
|
87
|
+
except griffe.NameResolutionError:
|
|
88
|
+
pass
|
|
89
|
+
else:
|
|
90
|
+
for part in [expression, *expression.iterate()]:
|
|
91
|
+
if isinstance(part, griffe.Expr) and part.reference_path:
|
|
92
|
+
references[str(part)] = part.reference_path
|
|
93
|
+
return references
|
|
94
|
+
|
|
95
|
+
def visit(obj, parent=None):
|
|
96
|
+
if obj.is_alias or (obj.name.startswith("_") and obj.name != "__init__"):
|
|
97
|
+
return
|
|
98
|
+
kind = obj.kind.value
|
|
99
|
+
if kind == "function" and parent is not None and obj.parent.is_class:
|
|
100
|
+
kind = "constructor" if obj.name == "__init__" else "method"
|
|
101
|
+
if obj.is_class and any(str(base) in ("Enum", "IntEnum", "StrEnum", "enum.Enum", "enum.IntEnum", "enum.StrEnum") for base in obj.bases):
|
|
102
|
+
kind = "enum"
|
|
103
|
+
if kind == "type alias":
|
|
104
|
+
kind = "type"
|
|
105
|
+
symbol = {"id": obj.path, "name": obj.name, "kind": kind, "visibility": "public"}
|
|
106
|
+
if parent:
|
|
107
|
+
symbol["parent"] = parent
|
|
108
|
+
file = obj.filepath.resolve(strict=True)
|
|
109
|
+
relative = file.relative_to(root).as_posix()
|
|
110
|
+
symbol["source"] = {"path": relative}
|
|
111
|
+
if obj.lineno:
|
|
112
|
+
symbol["source"]["line"] = obj.lineno
|
|
113
|
+
sections = obj.docstring.parsed if obj.docstring else []
|
|
114
|
+
prose = []
|
|
115
|
+
parameter_docs = {}
|
|
116
|
+
for section in sections:
|
|
117
|
+
section_kind = section.kind.value
|
|
118
|
+
if section_kind == "text":
|
|
119
|
+
prose.append(section.value)
|
|
120
|
+
elif section_kind == "parameters":
|
|
121
|
+
parameter_docs.update({p.name: p for p in section.value})
|
|
122
|
+
elif section_kind == "raises":
|
|
123
|
+
symbol["raises"] = [{"name": str(p.annotation or p.name or "Exception"), "description": p.description} for p in section.value]
|
|
124
|
+
elif section_kind in ("returns", "yields") and len(section.value) == 1:
|
|
125
|
+
item = section.value[0]
|
|
126
|
+
symbol[section_kind] = {"description": item.description}
|
|
127
|
+
if item.annotation is not None:
|
|
128
|
+
symbol[section_kind]["type"] = str(item.annotation)
|
|
129
|
+
elif section_kind == "examples":
|
|
130
|
+
examples = []
|
|
131
|
+
for example_kind, value in section.value:
|
|
132
|
+
if example_kind.value == "text":
|
|
133
|
+
prose.append(value)
|
|
134
|
+
else:
|
|
135
|
+
examples.append({"code": value})
|
|
136
|
+
if examples:
|
|
137
|
+
symbol["examples"] = examples
|
|
138
|
+
else:
|
|
139
|
+
# Preserve less-common sections rather than silently losing their prose.
|
|
140
|
+
if obj.docstring:
|
|
141
|
+
prose = [obj.docstring.value]
|
|
142
|
+
symbol.pop("returns", None)
|
|
143
|
+
symbol.pop("yields", None)
|
|
144
|
+
symbol.pop("raises", None)
|
|
145
|
+
symbol.pop("examples", None)
|
|
146
|
+
break
|
|
147
|
+
if prose:
|
|
148
|
+
symbol["description"] = "\n\n".join(prose)
|
|
149
|
+
symbol["summary"] = prose[0].split("\n", 1)[0][:1000]
|
|
150
|
+
annotations = []
|
|
151
|
+
if obj.is_function:
|
|
152
|
+
annotations.extend([obj.returns, *(p.annotation for p in obj.parameters)])
|
|
153
|
+
prefix = "async def " if "async" in obj.labels else "def "
|
|
154
|
+
signatures = obj.overloads or [obj]
|
|
155
|
+
symbol["signatures"] = [prefix + entry.signature() for entry in signatures]
|
|
156
|
+
params = []
|
|
157
|
+
for parameter in obj.parameters:
|
|
158
|
+
if parameter.name in ("self", "cls") and obj.parent.is_class:
|
|
159
|
+
continue
|
|
160
|
+
detail = {"name": parameter.name}
|
|
161
|
+
if parameter.annotation is not None:
|
|
162
|
+
detail["type"] = str(parameter.annotation)
|
|
163
|
+
if parameter.default is not None:
|
|
164
|
+
detail["default"] = str(parameter.default)
|
|
165
|
+
if parameter.name in parameter_docs:
|
|
166
|
+
detail["description"] = parameter_docs[parameter.name].description
|
|
167
|
+
params.append(detail)
|
|
168
|
+
if params:
|
|
169
|
+
symbol["parameters"] = params
|
|
170
|
+
if obj.returns is not None:
|
|
171
|
+
symbol.setdefault("returns", {})["type"] = str(obj.returns)
|
|
172
|
+
elif obj.is_class:
|
|
173
|
+
annotations.extend(obj.bases)
|
|
174
|
+
if obj.bases:
|
|
175
|
+
symbol["bases"] = [str(base) for base in obj.bases]
|
|
176
|
+
constructor = obj.members.get("__init__")
|
|
177
|
+
if constructor is not None and not constructor.is_alias and constructor.is_function:
|
|
178
|
+
symbol["constructorSignature"] = constructor.signature(name=obj.name, return_type=False)
|
|
179
|
+
annotations.extend(p.annotation for p in constructor.parameters)
|
|
180
|
+
elif "dataclass" in obj.labels and not obj.bases and not any("init=" in str(decorator.value) or "kw_only=" in str(decorator.value) for decorator in obj.decorators):
|
|
181
|
+
# Synthesize only the simple local dataclass case; never execute decorators.
|
|
182
|
+
fields = [member for member in obj.attributes.values() if "instance-attribute" in member.labels]
|
|
183
|
+
if all(field_info(member).get("required") is not None and (not str(member.value).startswith("field(") or str(member.value).startswith("field(default_factory=")) for member in fields):
|
|
184
|
+
declarations = []
|
|
185
|
+
for member in fields:
|
|
186
|
+
info = field_info(member)
|
|
187
|
+
default = "<factory>" if str(member.value).startswith("field(default_factory=") else info.get("default")
|
|
188
|
+
declarations.append(member.name + (": " + info["annotation"] if "annotation" in info else "") + (" = " + default if default is not None else ""))
|
|
189
|
+
annotations.append(member.annotation)
|
|
190
|
+
symbol["constructorSignature"] = obj.name + "(" + ", ".join(declarations) + ")"
|
|
191
|
+
symbol["signatures"] = ["class " + obj.name + ("(" + ", ".join(map(str, obj.bases)) + ")" if obj.bases else "")]
|
|
192
|
+
elif obj.is_attribute:
|
|
193
|
+
annotations.append(obj.annotation)
|
|
194
|
+
symbol.update(field_info(obj))
|
|
195
|
+
annotation = ": " + str(obj.annotation) if obj.annotation is not None else ""
|
|
196
|
+
symbol["signatures"] = [obj.name + annotation]
|
|
197
|
+
annotations.extend(item["name"] for item in symbol.get("raises", []))
|
|
198
|
+
references = type_references(obj, annotations)
|
|
199
|
+
if references:
|
|
200
|
+
symbol["typeReferences"] = references
|
|
201
|
+
symbols.append(symbol)
|
|
202
|
+
for child in sorted(getattr(obj, "members", {}).values(), key=lambda item: item.name):
|
|
203
|
+
visit(child, obj.path)
|
|
204
|
+
|
|
205
|
+
visit(loaded)
|
|
206
|
+
known = {symbol["id"] for symbol in symbols}
|
|
207
|
+
for symbol in symbols:
|
|
208
|
+
if "typeReferences" in symbol:
|
|
209
|
+
symbol["typeReferences"] = {name: target for name, target in symbol["typeReferences"].items() if target in known}
|
|
210
|
+
if not symbol["typeReferences"]:
|
|
211
|
+
del symbol["typeReferences"]
|
|
212
|
+
return {"schemaVersion": 1, "kind": "shoalrun-code-reference", "programmingLanguage": "python",
|
|
213
|
+
"producer": {"name": "shoalrun-python", "version": VERSION, "extractorVersion": EXTRACTOR_VERSION},
|
|
214
|
+
"sourceDigest": digest.hexdigest(), "symbols": symbols}
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def main():
|
|
218
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
219
|
+
parser.add_argument("--root", type=Path, required=True)
|
|
220
|
+
parser.add_argument("--module", required=True)
|
|
221
|
+
parser.add_argument("--style", choices=("google", "numpy", "sphinx"), default="google")
|
|
222
|
+
parser.add_argument("--out", type=Path, required=True)
|
|
223
|
+
args = parser.parse_args()
|
|
224
|
+
try:
|
|
225
|
+
data = convert(args.root, args.module, args.style)
|
|
226
|
+
args.out.write_text(json.dumps(data, indent=2, ensure_ascii=False) + "\n", encoding="utf8")
|
|
227
|
+
except (ImportError, importlib.metadata.PackageNotFoundError):
|
|
228
|
+
parser.exit(1, "Install the adapter's pinned requirements in Python 3.11+ before running it.\n")
|
|
229
|
+
except (ValueError, OSError) as error:
|
|
230
|
+
parser.exit(1, f"{error}\n")
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
if __name__ == "__main__":
|
|
234
|
+
main()
|
|
@@ -28,13 +28,15 @@ Full-page token counts use cl100k_base. Navigation section ID: project-updates.
|
|
|
28
28
|
|
|
29
29
|
- [Styled PDFs and custom code languages](https://www.shoalrun.com/changelog/pdf-custom-languages.md) — ID: change.pdf-custom-languages. changelog-entry; 487 tokens. Print branded pages, export a complete PDF manual, and highlight your own code language.
|
|
30
30
|
|
|
31
|
+
- [Shoalrun 1.0 — SDK references and smoother font loading](https://www.shoalrun.com/changelog/code-api-references.md) — ID: change.code-api-references. changelog-entry; 538 tokens. Generate code API references from source and docstrings, choose how readers browse them, and load custom fonts earlier.
|
|
32
|
+
|
|
31
33
|
- [Authoring snapshot previews and review reports](https://www.shoalrun.com/changelog/authoring-preview.md) — ID: change.authoring-preview. changelog-entry; 554 tokens. Snapshot previews with coverage and freshness reports.
|
|
32
34
|
|
|
33
35
|
- [Agent authoring, search, and documentation answers](https://www.shoalrun.com/changelog/authoring-search.md) — ID: change.authoring-search. changelog-entry; 468 tokens. Reviewed agent drafts, search improvements, and answer context.
|
|
34
36
|
|
|
35
37
|
- [Working-tree authoring tools](https://www.shoalrun.com/changelog/authoring-tools.md) — ID: change.authoring-tools. changelog-entry; 384 tokens. Project discovery and captured working-tree validation.
|
|
36
38
|
|
|
37
|
-
- [Changelog](https://www.shoalrun.com/changelog.md) — ID: reference.changelog. reference;
|
|
39
|
+
- [Changelog](https://www.shoalrun.com/changelog.md) — ID: reference.changelog. reference; 1547 tokens. Compiler, CLI, and reader changes.
|
|
38
40
|
|
|
39
41
|
- [MCP hosting, analytics, and component improvements](https://www.shoalrun.com/changelog/2026-10-17-mcp-hosting.md) — ID: change.mcp-hosting. changelog-entry; 1147 tokens. MCP hosting, analytics, and shared component content.
|
|
40
42
|
|
|
@@ -48,4 +50,4 @@ Full-page token counts use cl100k_base. Navigation section ID: project-updates.
|
|
|
48
50
|
|
|
49
51
|
- [Non-goals](https://www.shoalrun.com/non-goals.md) — ID: guide.non-goals. explanation; 821 tokens. Scope limits for skill generation, agent orchestration, and reader-view authorization.
|
|
50
52
|
|
|
51
|
-
- [Project status](https://www.shoalrun.com/status.md) — ID: guide.status. reference;
|
|
53
|
+
- [Project status](https://www.shoalrun.com/status.md) — ID: guide.status. reference; 1990 tokens. Current capabilities, planned features, and known limits.
|
package/agent-docs/SNAPSHOT.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"sourceRepository": "https://github.com/shoalrun/docs",
|
|
4
|
-
"sourceCommit": "
|
|
5
|
-
"siteBuildId": "
|
|
6
|
-
"manifestDigest": "
|
|
7
|
-
"indexDigest": "
|
|
8
|
-
"packageIntegrity": "sha512-
|
|
4
|
+
"sourceCommit": "0af50d753fc59c1e332d5e710999e3219c3e2443",
|
|
5
|
+
"siteBuildId": "6b51e1bac3826424f2ec68156866ec40c1761f7765901fc6dfc2f2d4f24a8596",
|
|
6
|
+
"manifestDigest": "2cb3bc1d411d08d4156fb139c6257dd4e56ea79ea1aed38c85eb32986b2a1743",
|
|
7
|
+
"indexDigest": "a6c8b514805bfd808949c3d22a01deee1ae9c35b4c6e54009ae3866b21df2c6e",
|
|
8
|
+
"packageIntegrity": "sha512-TVNgFm5dtSyO7c+njfPC2fta5IWnIVALrTD0CYktEUeuFbKv0pdKg8C7ihBiQ3svOhXNnyjZSDF96N23lVl/Tw=="
|
|
9
9
|
}
|
package/agent-docs/about.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: guide.about
|
|
3
3
|
title: About Shoalrun
|
|
4
|
-
summary: Learn what Shoalrun
|
|
4
|
+
summary: Learn what Shoalrun does and where the project is heading.
|
|
5
5
|
type: overview
|
|
6
6
|
area: project
|
|
7
7
|
subarea: project-overview
|
|
@@ -12,7 +12,7 @@ canonical: /about
|
|
|
12
12
|
|
|
13
13
|
> Documentation index: [llms.min.txt](https://www.shoalrun.com/llms.min.txt) · Document manifest: [documents.json](https://www.shoalrun.com/documents.json)
|
|
14
14
|
|
|
15
|
-
**Updated: 2026-11-
|
|
15
|
+
**Updated: 2026-11-07.**
|
|
16
16
|
|
|
17
17
|
I'm CT Smith, and I'm building Shoalrun cause there's no such thing as a perfect doc tool. I have opinions, undirected rage, and curiosity about doc-building tools. I built my first documentation generator back in 2015. It was based on Jekyll and relied heavily (probably too heavily) on general templating and... you guessed it... *page metadata*.
|
|
18
18
|
|
|
@@ -42,7 +42,7 @@ API content follows the same approach. Local OpenAPI files can supply reference
|
|
|
42
42
|
|
|
43
43
|
I'm building Shoalrun for tinkerers like me, who will never be fully satisfied with a mass market docs tool. Docs are never one-size-fits-all, on any level.
|
|
44
44
|
|
|
45
|
-
You can try the
|
|
45
|
+
You can try the CLI from npm: [Getting started](https://www.shoalrun.com/start.md) walks through installation and your first page. The [project status](https://www.shoalrun.com/status.md) describes what works and what still needs work.
|
|
46
46
|
|
|
47
47
|
yee haw forever,
|
|
48
48
|
|