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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions .github/workflows/check-schema.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Reusable ship gate: fail PRs when a help schema is empty or weak.
#
# Callers opt in. This does not run automatically in other repositories.
#
# jobs:
# prohelp:
# uses: dev-centr/prohelp/.github/workflows/check-schema.yml@main
# with:
# schema-path: help.sdl
# strict: true
#
name: Check help schema

on:
workflow_call:
inputs:
schema-path:
description: Schema file relative to the caller repository root
type: string
default: help.sdl
extra-paths:
description: Optional extra schema paths, one per line
type: string
default: ''
strict:
description: Treat completeness warnings as failures
type: boolean
default: true
prohelp-repository:
description: GitHub repo that provides the prohelp checker
type: string
default: dev-centr/prohelp
prohelp-ref:
description: Git ref of prohelp to build (tag or branch)
type: string
default: main
workflow_dispatch:
inputs:
schema-path:
description: Schema file relative to this repository
type: string
default: help.sdl
extra-paths:
description: Optional extra schema paths, one per line
type: string
default: ''
strict:
description: Treat completeness warnings as failures
type: boolean
default: true

jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout caller
uses: actions/checkout@v4

- name: Checkout prohelp
uses: actions/checkout@v4
with:
repository: ${{ inputs.prohelp-repository || 'dev-centr/prohelp' }}
ref: ${{ inputs.prohelp-ref || 'main' }}
path: .prohelp-tool

- name: Setup D compiler
uses: dlang-community/setup-dlang@v1
with:
compiler: ldc-latest

- name: Build prohelp CLI
run: dub build -c executable --build=release
working-directory: .prohelp-tool

- name: Check schema(s)
shell: bash
env:
SCHEMA_PATH: ${{ inputs.schema-path }}
EXTRA_PATHS: ${{ inputs.extra-paths }}
STRICT: ${{ inputs.strict }}
run: |
BIN=.prohelp-tool/prohelp
FLAGS=()
if [ "$STRICT" = "true" ]; then
FLAGS+=(--strict)
fi
status=0
"$BIN" check "$SCHEMA_PATH" "${FLAGS[@]}" || status=$?
if [ -n "$EXTRA_PATHS" ]; then
while IFS= read -r extra; do
extra="${extra//$'\r'/}"
[ -z "$extra" ] && continue
"$BIN" check "$extra" "${FLAGS[@]}" || status=$?
done <<< "$EXTRA_PATHS"
fi
exit "$status"
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,34 @@ jobs:
run: |
if [ -f prohelp.exe ]; then BIN=./prohelp.exe; else BIN=./prohelp; fi
"$BIN" --help || "$BIN" ?
"$BIN" check --help
"$BIN" init --help
"$BIN" fill --help

- name: Check schemas
shell: bash
run: |
if [ -f prohelp.exe ]; then BIN=./prohelp.exe; else BIN=./prohelp; fi
"$BIN" check help.sdl --strict
"$BIN" check examples/tar.sdl --strict
tmp=$(mktemp -d)
"$BIN" init "$tmp/help.sdl" --name smoke
"$BIN" check "$tmp/help.sdl"
if "$BIN" check "$tmp/help.sdl" --strict; then
echo "expected init template to fail --strict" >&2
exit 1
fi
if "$BIN" check examples/incomplete.sdl --strict; then
echo "expected incomplete.sdl to fail --strict" >&2
exit 1
fi
"$BIN" fill "$tmp/help.sdl" --no-prompt \
--set summary="Smoke test" \
--set description="Init/fill/check smoke" \
--set homepage="https://example.com" \
--set docs="https://example.com/docs" \
--set issues="https://example.com/issues"
"$BIN" check "$tmp/help.sdl" --strict

- name: Smoke help
shell: bash
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ This project maintains a structured release history with links to detailed relea

## Release History

* **2026-08-18** — [Init, fill, and check](changelog-details/2026-08-18%20-%20init-fill-check.md): `prohelp init` writes a shaped schema; `prohelp fill` is the questionnaire; `prohelp check [--strict]` reports completeness. Reusable workflow `.github/workflows/check-schema.yml` for downstream CI. Parser now keeps `example` tags and the preview renderer shows them.

* **2026-08-07** — Static box: frame glyphs always dim; section dividers share one width formula with content rows (display-column math, not UTF-8 byte length).
* **2026-08-06** — Build: avoid dub stringImportPaths: ["."] (dub 1.41 expands . as Invalid variable: null); embed help.sdl via embed/ + docs/.
* **2026-08-06** — Windows: set console UTF-8 + VT before printing; ASCII box/punctuation fallback when OutputCP is not UTF-8 (`PROHELP_ASCII` / `PROHELP_UNICODE`). Fixes CP437 mojibake (`Γöî` / `ΓÇö`) in PowerShell/conhost.
Expand Down
24 changes: 24 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,29 @@ prohelp examples/tar.sdl ? operations
prohelp -f myapp/help.sdl ?:de,i
----

=== Author a schema

[source,powershell]
----
prohelp init --name myapp # writes help.sdl immediately
prohelp fill # questionnaire (or init --fill)
prohelp check # report empty / weak fields
prohelp check --strict # fail for CI
prohelp help.sdl ?
----

Downstream repos opt into the ship gate:

[source,yaml]
----
jobs:
prohelp:
uses: dev-centr/prohelp/.github/workflows/check-schema.yml@main
with:
schema-path: help.sdl
strict: true
----

=== Shell `help` wrapper (recommended)

[source,shell]
Expand Down Expand Up @@ -125,6 +148,7 @@ void main(string[] args) {
* **Hierarchical Globbing (`*`)**: Subtree glob extraction for targeted documentation chunks.
* **Multilingual Localization**: Native OS locale auto-detection with explicit overrides.
* **Sliding-scale Line Budgets**: Enforces strict screen boundaries during development.
* **Authoring loop**: `prohelp init` writes a shaped `help.sdl`; `prohelp fill` is the questionnaire; `prohelp check --strict` is the CI ship gate (reusable workflow included).

See link:CHANGELOG.md[Changelog].

Expand Down
7 changes: 7 additions & 0 deletions changelog-details/2026-08-18 - init-fill-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Init, fill, and check (2026-08-18)

* `prohelp init` writes a blank-but-shaped `help.sdl` before any questions (`--fill` continues into the questionnaire).
* `prohelp fill` edits that file in a TTY, or via repeated `--set field=value`.
* `prohelp check` reports empty summaries, missing discovery URLs, empty sections, and line-budget slips. `--strict` fails the process so CI can block a ship.
* Downstream repos opt in with `uses: dev-centr/prohelp/.github/workflows/check-schema.yml`.
* SDL `example` tags are parsed and shown in Text Mode (they were previously ignored).
37 changes: 37 additions & 0 deletions docs/modules/ROOT/pages/authoring.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,40 @@ Each missing essential field gets a DuckDuckGo link seeded with the binary name/
When **no** prohelp schema is found at all, prohelp prints a separate notice nudging a feature request upstream (also with a filled search link), then falls back to info / man / `--help`.

Suppress notices with `PROHELP_QUIET=1`.

== Init, fill, and check

`prohelp init` writes a shaped `help.sdl` immediately (empty summaries and discovery URLs). It does not wait on a questionnaire.

[source,shell]
----
prohelp init --name myapp
prohelp init path/to/help.sdl --force
prohelp init --name myapp --fill # then the questionnaire
----

`prohelp fill` edits that file. In a TTY it asks for empty fields. In CI or pipes, pass `--set`:

[source,shell]
----
prohelp fill help.sdl --set summary="Does a thing" --set homepage=https://example.com
----

`prohelp check` prints completeness findings (empty summaries, missing `homepage`/`docs`/`issues`, empty sections, line budgets). Exit 0 while findings are warnings.

`--strict` promotes those warnings to failures. That is the ship gate. Prohelp cannot enable it in someone else's pipeline; they add a job that calls the reusable workflow:

[source,yaml]
----
name: Prohelp
on: [push, pull_request]
jobs:
check:
uses: dev-centr/prohelp/.github/workflows/check-schema.yml@main
with:
schema-path: help.sdl
strict: true
----

Pin `@vX.Y.Z` when you depend on a release tag instead of `main`.

24 changes: 24 additions & 0 deletions docs/modules/ROOT/pages/getting-started.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,27 @@ prohelp examples/help.adoc ?
----

See xref:authoring.adoc[Authoring schemas] for Markdown/AsciiDoc/CentrMark whole-document schemas and `content-ref` formats.

== Create, fill, and check

[source,powershell]
----
prohelp init --name myapp
prohelp fill
prohelp check
prohelp check --strict
----

`init` writes a shaped `help.sdl` before any questions. `fill` is the questionnaire (`init --fill` runs both). `check` reports empty fields; `--strict` fails the process so CI can block a ship.

Other GitHub repos can invoke the reusable workflow (they still have to add the job — Prohelp cannot reach into someone else's pipeline):

[source,yaml]
----
jobs:
prohelp:
uses: dev-centr/prohelp/.github/workflows/check-schema.yml@main
with:
schema-path: help.sdl
strict: true
----
2 changes: 2 additions & 0 deletions docs/modules/ROOT/pages/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ For building CLI tools, use a framework and wire Prohelp in:

The `prohelp` preview executable ships with built-in help and can interpret `help.sdl` as well as Markdown/AsciiDoc/CentrMark document schemas for authoring and testing. See xref:authoring.adoc[Authoring schemas].

Create a schema with `prohelp init`, fill fields with `prohelp fill`, and use `prohelp check --strict` (or the reusable GitHub workflow) as the ship gate so empty help cannot merge unnoticed.

Moved from Dev-Centr into OpenShellOrg as the reusable progressive-help library and global `help` entry point.
15 changes: 14 additions & 1 deletion embed/help.sdl
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ command "prohelp" {

section "usage" {
summary "Integration syntax and execution patterns"
content "prohelp [schema.sdl] [help|?][:[locale][,mode]] [path...] [*]\nprohelp wrapper status|install|uninstall [--shell=...]\nprohelp --as-help [command]"
content "prohelp [schema.sdl] [help|?][:[locale][,mode]] [path...] [*]\nprohelp init [path] [--name NAME] [--force] [--fill]\nprohelp fill [path] [--set field=value]\nprohelp check [path] [--strict]\nprohelp wrapper status|install|uninstall [--shell=...]\nprohelp --as-help [command]"

example "Built-in progressive help" "prohelp ?"
example "Write a starter schema" "prohelp init --name myapp"
example "Fill empty fields" "prohelp fill"
example "Report missing fields" "prohelp check"
example "Fail CI on weak schemas" "prohelp check --strict"
example "Shell-help setup section" "prohelp ? shell-help"
example "Install help() wrapper" "prohelp wrapper install"
example "Preview another command's help schema" "prohelp examples/tar.sdl ?"
Expand All @@ -39,6 +43,15 @@ command "prohelp" {
content "Registers a `help` function that keeps builtin help for builtins and routes PATH topics through prohelp. See: prohelp ? shell-help\nWeb: https://openshellorg.github.io/prohelp/shell-help.html"
}

section "authoring" {
summary "Create, fill, and check a help schema"
content "prohelp init writes a blank-but-shaped help.sdl immediately. prohelp fill is the questionnaire (also: init --fill). prohelp check reports empty fields; --strict is the CI ship gate. Other repos can call .github/workflows/check-schema.yml."

example "Scaffold then fill" "prohelp init --name myapp --fill"
example "Non-interactive field set" "prohelp fill --set summary=\"Does a thing\" --set homepage=https://example.com"
example "Strict completeness" "prohelp check help.sdl --strict"
}

section "preview" {
summary "Help schema interpreter mode"
content "Pass a help.sdl file to virtualize that command's context. Rendering, navigation, and examples use the schema's command name (for example tar) instead of prohelp."
Expand Down
8 changes: 8 additions & 0 deletions examples/incomplete.sdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
command "incomplete" {
title "incomplete"
summary ""
description ""
homepage ""
docs ""
issues ""
}
4 changes: 4 additions & 0 deletions examples/tar.sdl
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
command "tar" {
title "GNU tar"
summary "Tape archiver utility"
description "An archiver utility used to combine multiple files into a single archive file, often referred to as a 'tarball'."
homepage "https://www.gnu.org/software/tar/"
docs "https://www.gnu.org/software/tar/manual/"
issues "https://savannah.gnu.org/bugs/?group=tar"

// Multilingual support
locale "de" {
Expand Down
15 changes: 14 additions & 1 deletion help.sdl
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ command "prohelp" {

section "usage" {
summary "Integration syntax and execution patterns"
content "prohelp [schema.sdl] [help|?][:[locale][,mode]] [path...] [*]\nprohelp wrapper status|install|uninstall [--shell=...]\nprohelp --as-help [command]"
content "prohelp [schema.sdl] [help|?][:[locale][,mode]] [path...] [*]\nprohelp init [path] [--name NAME] [--force] [--fill]\nprohelp fill [path] [--set field=value]\nprohelp check [path] [--strict]\nprohelp wrapper status|install|uninstall [--shell=...]\nprohelp --as-help [command]"

example "Built-in progressive help" "prohelp ?"
example "Write a starter schema" "prohelp init --name myapp"
example "Fill empty fields" "prohelp fill"
example "Report missing fields" "prohelp check"
example "Fail CI on weak schemas" "prohelp check --strict"
example "Shell-help setup section" "prohelp ? shell-help"
example "Install help() wrapper" "prohelp wrapper install"
example "Preview another command's help schema" "prohelp examples/tar.sdl ?"
Expand All @@ -39,6 +43,15 @@ command "prohelp" {
content "Registers a `help` function that keeps builtin help for builtins and routes PATH topics through prohelp. See: prohelp ? shell-help\nWeb: https://openshellorg.github.io/prohelp/shell-help.html"
}

section "authoring" {
summary "Create, fill, and check a help schema"
content "prohelp init writes a blank-but-shaped help.sdl immediately. prohelp fill is the questionnaire (also: init --fill). prohelp check reports empty fields; --strict is the CI ship gate. Other repos can call .github/workflows/check-schema.yml."

example "Scaffold then fill" "prohelp init --name myapp --fill"
example "Non-interactive field set" "prohelp fill --set summary=\"Does a thing\" --set homepage=https://example.com"
example "Strict completeness" "prohelp check help.sdl --strict"
}

section "preview" {
summary "Help schema interpreter mode"
content "Pass a help.sdl file to virtualize that command's context. Rendering, navigation, and examples use the schema's command name (for example tar) instead of prohelp."
Expand Down
20 changes: 20 additions & 0 deletions source/app.d
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import std.array;
import std.algorithm;
import std.string;
import std.stdio;
import prohelp.check;
import prohelp.config;
import prohelp.dispatch;
import prohelp.intercept;
import prohelp.registration;
import prohelp.scaffold;
import prohelp.wrapper;

version (ProhelpExecutable) {
Expand Down Expand Up @@ -83,6 +85,21 @@ void main(string[] argv) {
exit(cast(ubyte) runAsHelp(tail[1 .. $]));
}

if (tail.length && tail[0] == "init") {
import core.stdc.stdlib : exit;
exit(cast(ubyte) runInitCommand(tail[1 .. $]));
}

if (tail.length && tail[0] == "fill") {
import core.stdc.stdlib : exit;
exit(cast(ubyte) runFillCommand(tail[1 .. $]));
}

if (tail.length && tail[0] == "check") {
import core.stdc.stdlib : exit;
exit(cast(ubyte) runCheckCommand(tail[1 .. $]));
}

InterceptConfig config = parseCliConfig(tail);

if (!config.isConfigured && tail.length > 0 && (tail[0] == "--schema" || tail[0] == "-f")) {
Expand All @@ -102,6 +119,9 @@ void main(string[] argv) {
} else {
stderr.writeln("prohelp error: Unrecognized arguments.");
stderr.writeln("Run 'prohelp ?' for built-in help, or:");
stderr.writeln(" prohelp init [--name myapp] [--fill]");
stderr.writeln(" prohelp fill [help.sdl]");
stderr.writeln(" prohelp check [help.sdl] [--strict]");
stderr.writeln(" prohelp wrapper install");
stderr.writeln(" prohelp --as-help <command>");
stderr.writeln(" prohelp path/to/help.sdl ?");
Expand Down
Loading
Loading