Conversation
ctld is writable (plugin scenes populate ctld.i18n at load); the design-time gate spec spies on CTLDObjectRegistry; the vendored dcs_stubs.lua defines the DCS globals. Configure luacheck accordingly so CI passes.
…sion points plugins/_template is a heavily-commented reference scene to copy when authoring a plugin. It exercises the full extension surface: i18n (4 languages), ObjectRegistry declarations, a scene model with polar + func steps, a crate injected into Request Equipment, and an F10 radio submenu wired via deferMenuSection — plus requiresCtld and (empty) modTypes metadata. The radio submenu is the point Metal FARP alone did not cover: loaded after CTLD init, its deferMenuSection routes straight to registerMenuSection (CTLD's load-position-independent fix), so the submenu still attaches. A busted smoke test asserts registration, crate, metadata and the wired menu section; the asset gate now validates the template's types too. CI runs busted over tests/ and plugins/ so per-plugin tests are discovered. Catalogue: an authoring "Template" page (EN/FR). SCENE-PLUGINS ticket 09.
feat(template): _template reference plugin + luacheck CI fix
CTLD SCENE-PLUGINS ticket 05 removed Metal FARP from the core deliverable; refresh the vendored test runtime so the metal-farp plugin registers cleanly (no duplicate) and the gate runs against the real baseline.
chore(vendor): refresh CTLD.lua baseline (Metal FARP removed from core)
…ion) The asset gate read desc.units[].type and so silently skipped GROUND groups, whose unit types come from unitType(coalitionId). It now resolves both coalitions (mirrors CTLD's CTLDTypeCollector.typesOfDescriptor). metal-farp's Fuel_Truck / repare_Truck GROUND types are now validated (all in the datamine set). ASSET-VALIDATION-REVAMP ticket 01 (plugins side).
fix(gate): validate GROUND descriptor unit types
Add CONTEXT.md glossary and two ADRs: - 0001: plugin README as single doc source of truth - 0002: mike-versioned docs (latest/dev on one site) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e pages Closes #5 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Provides front-matter structure (modUrls) and French prose sections as a model for new plugin READMEs. Closes #6 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- plugins/metal-farp/README.md: authored prose + modUrls front-matter
- CTLD_metalFarpScene.lua: rename Farp_FG_Petit_Helipad -> FG_small_Helipad
- docs/plugins/metal-farp.{md,fr.md}: regenerated via generate-plugin-doc skill
- .claude/skills/generate-plugin-doc: skill definition for doc generation
Closes #7
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- tools/ci/validate_docs.py: checks front-matter, modUrls structure,
and presence of docs/plugins/{name}.{fr.}md for every plugin
- .github/workflows/ci.yml: new validate-docs job (pip pyyaml + script)
- README.md: document the CI gate and plugin authoring steps
Closes #8
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- docs.yml: triggers on master+develop, mike deploy instead of gh-deploy master -> version 'master' aliased 'latest' (set as default) develop -> version 'develop' aliased 'dev' - Inject GITHUB_REF_NAME into /master/ download URLs before build so dev docs link to develop-branch sources - mkdocs.yml: add version selector (mike provider, default: latest) Closes #9 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- docs/index.md, index.fr.md: Farp_FG_Petit_Helipad -> FG_small_Helipad - validate_docs.py: distinguish absent front-matter (None) from malformed structure (Exception) for a clearer error message Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat: catalogue download buttons, mod links, generated docs, CI gate
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CI: copy plugin .lua files to docs/downloads/ before MkDocs build so they are served same-origin, making the download attribute effective in all browsers (closes #12) - Docs: switch .lua buttons to relative downloads/ path + download attr; add target="ext-{mod}" rel="noopener" on mod buttons; add target="_blank" rel="noopener" on external prose links (closes #13) - Domain: update CONTEXT.md (Bouton download, Mod button, External prose link entries); add ADR-0003 for docs/downloads/ serving decision (closes #14) - Skill: update generate-plugin-doc template with new button/link rules (closes #15) - Migrate CONTEXT.md and ADR 0001-0003 from French to English Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add hooks.py: MkDocs hook that adds target="ext-{id}" rel="noopener"
to all external links at build time (attr_list does not reliably apply
target to inline links in Python-Markdown)
- Register hook in mkdocs.yml
- Switch download attribute to download="{name}.lua" to force correct
filename instead of browser defaulting to "download"
- Remove target/rel from attr_list in doc files and skill (hook owns this)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reviewer's GuideDocs CI and site are updated to serve plugin Lua downloads from same-origin paths with versioned docs via mike, external links get consistent target/rel attributes, the Metal FARP plugin is switched to the FG_small_Helipad mod with a new template plugin and documentation validation tooling, and CONTEXT/ADRs/doc authoring guidance are migrated and added in English/French. Sequence diagram for MkDocs external link processing hooksequenceDiagram
participant MkDocs as MkDocs
participant Hook as hooks.on_page_content
participant Util as _url_target
MkDocs->>Hook: on_page_content(html, page, config)
Hook->>Hook: site = config.get(site_url)
Hook->>Hook: re.sub("<a ([^>]+)>", process, html)
loop for each <a ...> match
Hook->>Hook: Extract attrs and href
alt href is non-http or same site or has target
Hook-->>MkDocs: Return original <a> tag
else external link without target
Hook->>Util: _url_target(href)
Util-->>Hook: target name ext-{id}
Hook-->>MkDocs: Return <a ... target="ext-{id}" rel="noopener">
end
end
MkDocs-->>MkDocs: Use transformed HTML for page output
Flow diagram for validate-docs CI gateflowchart TD
A[Start validate_docs.py] --> B[Scan plugins/ excluding _template]
B --> C{Any plugins?}
C -- No --> D[Print 'nothing to validate'] --> Z[Exit 0]
C -- Yes --> E[For each plugin]
E --> F[Check plugins/<name>/README.md]
F --> G{README.md exists?}
G -- No --> H[Add WARNING: README absent]
G -- Yes --> I[parse_frontmatter]
I --> J{Front-matter result}
J -- None --> K[Add ERROR: no YAML front-matter]
J -- Exception --> L[Add ERROR: malformed front-matter]
J -- Dict --> M[Get modUrls]
M --> N{modUrls is not None?}
N -- Yes --> O[validate_mod_urls]
O --> P{Valid?}
P -- No --> Q[Add ERROR: modUrls invalid]
P -- Yes --> R[Continue]
N -- No --> R
R --> S[Check docs/plugins/<name>.md and .fr.md exist]
S --> T[Add ERROR for each missing doc]
T --> U[After all plugins]
H --> U
K --> U
L --> U
Q --> U
U --> V[Print warnings]
V --> W[Print errors]
W --> X{Any errors?}
X -- Yes --> Y[Print summary, Exit 1]
X -- No --> Z[Print OK summary, Exit 0]
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- The MkDocs hook in hooks.py treats any HTTP link as external unless it starts with config.site_url, but site_url is not set in mkdocs.yml, so internal links will get target="ext-*" and rel="noopener"; consider using a more robust check (e.g. comparing netloc against the docs host or leaving relative URLs untouched) or setting site_url explicitly.
- validate_docs.py imports PyYAML inside parse_frontmatter and treats a README with leading "---" but no closing "---" as a hard error; if you expect authors to sometimes omit front-matter, it may be worth relaxing this to a warning unless modUrls or other metadata is required.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The MkDocs hook in hooks.py treats any HTTP link as external unless it starts with config.site_url, but site_url is not set in mkdocs.yml, so internal links will get target="ext-*" and rel="noopener"; consider using a more robust check (e.g. comparing netloc against the docs host or leaving relative URLs untouched) or setting site_url explicitly.
- validate_docs.py imports PyYAML inside parse_frontmatter and treats a README with leading "---" but no closing "---" as a hard error; if you expect authors to sometimes omit front-matter, it may be worth relaxing this to a warning unless modUrls or other metadata is required.
## Individual Comments
### Comment 1
<location path=".github/workflows/docs.yml" line_range="29-32" />
<code_context>
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ - name: Copy plugin .lua files to docs/downloads/
+ run: |
+ mkdir -p docs/downloads
+ cp plugins/*/src/*.lua docs/downloads/
+ - name: Inject branch into download URLs
+ # Replace /master/ with the actual branch in raw download links,
</code_context>
<issue_to_address>
**issue:** Copy step will fail if no plugin src trees or no .lua files exist
This `cp plugins/*/src/*.lua docs/downloads/` pattern will fail if any plugin lacks a `src` directory or if there are no `.lua` files (e.g. new plugin skeletons, partial checkouts), causing the docs job to error unnecessarily. Please make this step resilient, e.g. by using `find` to locate `.lua` files or by tolerating a non-zero `cp` exit:
```bash
mkdir -p docs/downloads
find plugins -mindepth 2 -maxdepth 2 -type d -name src -exec find {} -name '*.lua' -exec cp {} docs/downloads/ \;
# or
cp plugins/*/src/*.lua docs/downloads/ 2>/dev/null || true
```
</issue_to_address>
### Comment 2
<location path="docs/index.fr.md" line_range="21" />
<code_context>
-| [Metal FARP](plugins/metal-farp.md) | Un FARP à hélisurface métallique | Mod DCS `Farp_FG_Petit_Helipad` |
+| Plugin | Ce qu'il construit | Requiert | Télécharger |
+|--------|--------------------|----------|-------------|
+| [Metal FARP](plugins/metal-farp.md) | Un FARP à hélisurface métallique | Mod DCS `FG_small_Helipad` | [⬇ metal-farp.lua](downloads/CTLD_metalFarpScene.lua){ download .md-button } |
</code_context>
<issue_to_address>
**suggestion (bug_risk):** The download button attribute syntax looks inconsistent with other examples and may not be parsed as intended.
This link uses `{ download .md-button }`, while other examples use `download="metal-farp.lua" .md-button .md-button--primary`. For consistent behavior and reliable parsing, consider adding an explicit `download="metal-farp.lua"` attribute and matching the class list to the existing button examples.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| - name: Copy plugin .lua files to docs/downloads/ | ||
| run: | | ||
| mkdir -p docs/downloads | ||
| cp plugins/*/src/*.lua docs/downloads/ |
There was a problem hiding this comment.
issue: Copy step will fail if no plugin src trees or no .lua files exist
This cp plugins/*/src/*.lua docs/downloads/ pattern will fail if any plugin lacks a src directory or if there are no .lua files (e.g. new plugin skeletons, partial checkouts), causing the docs job to error unnecessarily. Please make this step resilient, e.g. by using find to locate .lua files or by tolerating a non-zero cp exit:
mkdir -p docs/downloads
find plugins -mindepth 2 -maxdepth 2 -type d -name src -exec find {} -name '*.lua' -exec cp {} docs/downloads/ \;
# or
cp plugins/*/src/*.lua docs/downloads/ 2>/dev/null || true| | [Metal FARP](plugins/metal-farp.md) | Un FARP à hélisurface métallique | Mod DCS `Farp_FG_Petit_Helipad` | | ||
| | Plugin | Ce qu'il construit | Requiert | Télécharger | | ||
| |--------|--------------------|----------|-------------| | ||
| | [Metal FARP](plugins/metal-farp.md) | Un FARP à hélisurface métallique | Mod DCS `FG_small_Helipad` | [⬇ metal-farp.lua](downloads/CTLD_metalFarpScene.lua){ download .md-button } | |
There was a problem hiding this comment.
suggestion (bug_risk): The download button attribute syntax looks inconsistent with other examples and may not be parsed as intended.
This link uses { download .md-button }, while other examples use download="metal-farp.lua" .md-button .md-button--primary. For consistent behavior and reliable parsing, consider adding an explicit download="metal-farp.lua" attribute and matching the class list to the existing button examples.
Closes #11
Summary
.luafiles todocs/downloads/for same-origin downloaddownload="plugin-name.lua"for correct filenamehooks.py) addstarget="ext-{id}" rel="noopener"to all external linksTest plan
.luadownload triggers file save with correct filenameSummary by Sourcery
Update Metal FARP plugin and docs to use the FG_small_Helipad mod, introduce a plugin authoring template with supporting docs and tests, and revamp documentation build, validation, and download handling.
New Features:
Enhancements:
Build:
CI:
Documentation:
Tests: