Files
max-sixty__worktrunk/dev/wt.example.toml
Worktrunk Bot 2203c414f5 fix(docs): convert a config-example link whose text holds a bracketed span (#3731)
`wt config create --project` writes a comment into the user's
`.config/wt.toml` — and `wt config create --help` prints the same text —
carrying a raw, unresolvable Zola link:

```
# When many repositories share one self-hosted host, name it once in user config with a [pattern-keyed `[projects]` entry](@/config.md#user-project-specific-settings) instead of repeating this block in each repo.
```

Every other cross-reference in that file is a plain URL (`… see \`wt
hook\` (https://worktrunk.dev/hook/) …`), because
`transform_config_source_to_toml` converts the `after_long_help`
markdown to plain text on the way into `dev/wt.example.toml`. This one
link isn't converted: `convert_markdown_links_for_config` matched link
text with `[^\]]+`, which stops at the first `]` — here the one closing
the nested `` `[projects]` `` span — so the regex failed to match and
the markdown survived verbatim. The line arrived with #3701; it's the
only link in either generated example file with a bracketed span in its
text.

## The fix

**One rule for `]` in link text.** `ZOLA_LINK_PATTERN`, earlier in the
same file, already solves this problem for the skill mirrors — it
alternates a backticked code span with any non-`]`-non-backtick char,
which is why `skills/worktrunk/reference/config.md` renders this very
sentence with a resolved URL while the TOML example didn't.
`convert_markdown_links_for_config` now uses that same class rather than
a second, weaker one. Brackets in these link texts always sit inside a
code span, so the class fits the shape exactly, and it covers `[[…]]`
array-of-tables names as well — these sections already document
`[[projects."…".post-start]]` pipelines, so a link naming one is the
next form to arrive. Regenerating produces the intended form:

```
# When many repositories share one self-hosted host, name it once in user config with a pattern-keyed `[projects]` entry (https://worktrunk.dev/config/#user-project-specific-settings) instead of repeating this block in each repo.
```

**A shape the regex declines now fails loudly.** Widening the class
fixes the shapes we know about; it can't fix the next one.
`finalize_skill_content` already handled that risk with a guardrail —
after the rewrite it scans for a stray `](@/…md` and panics with the
offending line, precisely because "the regex declined on an unexpected
character in the link text" is the expected failure mode.
`transform_config_source_to_toml` had no equivalent, which is why this
one reached `dev/wt.example.toml` and the `--help` output. That check is
now extracted into `assert_no_untransformed_zola_links` and called from
both surfaces, so the next unsupported shape is a test failure naming
the line rather than a raw `@/config.md` target in a user's config file.

## Why nothing caught it

`test_project_config_source_generates_example_toml` compares
`dev/wt.example.toml` against the output of this same transform, so an
unconverted link is "in sync" by construction — the sync test can't see
the difference between a link that converted and one the regex declined
to match. Two tests close that gap:

- `test_config_markdown_links_convert_to_plain_text` asserts the
transform's output directly. It fails on `main`'s regex with exactly the
reported symptom, and pins the forms already working (Zola page, Zola
page + anchor, absolute URL, two links on one line, the `[[…]]`
array-of-tables name) plus the case that must *not* convert — a bare ``
`[forge]` `` span is not a link and has to survive verbatim.
- `test_untransformed_zola_link_fails_the_config_transform` covers the
backstop itself: an unbalanced backtick in link text makes the rewrite
decline, and the assertion turns that into a panic naming the line.

## Files

- `tests/integration_tests/readme_sync.rs` — the shared link-text class,
the guardrail extraction and its second call site, and both tests.
- `dev/wt.example.toml` — regenerated by the sync test (one line).
- `tests/snapshots/…help_config_create.snap` — the same line, as `wt
config create --help` renders it.

Ran locally on the final state: `readme_sync::` (15), `test_help` (47),
`cargo clippy --tests --all-features`, and `cargo fmt --check`. All
green; the generated files are byte-identical under the new class, so
the sync tests pass without regenerating. The full gate runs in CI.

---------

Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
2026-08-05 10:15:55 -07:00

62 lines
3.1 KiB
TOML

# # Project Configuration
#
# Project configuration lets teams share repository-specific settings — hooks, dev server URLs, and other defaults. The file lives in `.config/wt.toml` and is typically checked into version control.
#
# To create a starter file with commented-out examples, run `wt config create --project`.
#
# ## Hooks
#
# Project hooks apply to this repository only. See `wt hook` (https://worktrunk.dev/hook/) for hook types, execution order, and examples.
#
# pre-start = "npm ci"
# post-start = "npm run dev"
# pre-merge = "npm test"
#
# ## Dev server URL
#
# URL column in `wt list` (dimmed when port not listening):
#
# [list]
# url = "http://localhost:{{ branch | hash_port }}"
#
# ## Forge platform
#
# The forge is read from the remote's hostname: any host carrying `github`, `gitlab`, or `gitea` anywhere in it, plus the Azure DevOps service domains. Name the forge explicitly for a host carrying none of those, such as a Forgejo instance at `forge.example.com`:
#
# [forge]
# platform = "github" # or "gitlab", "gitea" (experimental), "azure-devops" (experimental)
# hostname = "github.example.com" # Example: API host (GHE / self-hosted GitLab)
#
# When many repositories share one self-hosted host, name it once in user config with a pattern-keyed `[projects]` entry (https://worktrunk.dev/config/#user-project-specific-settings) instead of repeating this block in each repo. A repository's own `[forge]` still wins, field by field.
#
# ## Commit-message append [experimental]
#
# `template-append` adds project-wide conventions to the LLM commit and squash prompts, shared so every teammate's LLM sees the same style guide:
#
# [commit.generation]
# template-append = """
# - Use conventional commits (feat:, fix:, docs:, …)
# - Reference the relevant issue ID in the body
# """
#
# The first time the fragment is used (and whenever it changes), `wt` prompts the user to approve it — the same one-shot gate as project-defined hooks. Only `template-append` is honored from the project file; the LLM command and the main prompt template stay in user config (https://worktrunk.dev/config/), since they describe per-developer environment (which CLI is installed, which agent the developer prefers). How the fragment renders: the LLM commits guide (https://worktrunk.dev/llm-commits/#appending-to-the-prompt).
#
# ## Copy-ignored excludes
#
# Additional excludes for `wt step copy-ignored`:
#
# [step.copy-ignored]
# exclude = [".cache/", ".turbo/"]
#
# Built-in excludes (VCS metadata and tool-state directories) always apply; the `wt step copy-ignored` docs (https://worktrunk.dev/step/#wt-step-copy-ignored) list them. User config and project config exclusions are combined.
#
# ## Aliases
#
# Command templates that run as `wt <name>`. See the Extending Worktrunk guide (https://worktrunk.dev/extending/#aliases) for usage and flags.
#
# [aliases]
# deploy = "make deploy BRANCH={{ branch }}"
# url = "echo http://localhost:{{ branch | hash_port }}"
#
# Aliases defined here are shared with teammates. For personal aliases, use the user config (https://worktrunk.dev/config/#aliases) `[aliases]` section instead.