fix(create-readme): allow empty quick_start with steps-only Quick Start (#149)
* fix(create-readme): allow empty quick_start with steps-only Quick Start * docs(handoff): add handoff + ADR for empty-quick-start * docs(handoff): set PR number * docs(project-map): update create-readme.ts role for PR#149 --------- Co-authored-by: opencode-agent <agent@opencode.local>
This commit is contained in:
parent
8308de0981
commit
4bb504a604
4 changed files with 102 additions and 8 deletions
|
|
@ -13,7 +13,7 @@ type CreateArgs = {
|
|||
what_en: string
|
||||
why_ru: string
|
||||
what_ru: string
|
||||
quick_start: string
|
||||
quick_start?: string
|
||||
features_en: Feature[]
|
||||
features_ru: Feature[]
|
||||
access_url?: string
|
||||
|
|
@ -67,12 +67,13 @@ function generateReadme(args: CreateArgs): string {
|
|||
const cloneLine = args.include_clone !== false
|
||||
? `git clone https://github.com/slaid098/${args.repo_name}.git\n`
|
||||
: ""
|
||||
const hasBashBlock = args.include_clone !== false || args.quick_start !== ""
|
||||
const hasBashBlock = args.include_clone !== false || (args.quick_start ?? "") !== ""
|
||||
const qs = args.quick_start ?? ""
|
||||
const bashBlockEn = hasBashBlock
|
||||
? `\`\`\`bash\n${cloneLine}${args.quick_start}\n\`\`\``
|
||||
? `\`\`\`bash\n${cloneLine}${qs}\n\`\`\``
|
||||
: ""
|
||||
const bashBlockRu = hasBashBlock
|
||||
? `\`\`\`bash\n${cloneLine}${args.quick_start}\n\`\`\``
|
||||
? `\`\`\`bash\n${cloneLine}${qs}\n\`\`\``
|
||||
: ""
|
||||
const stepsEn = renderSteps(args.quick_start_steps_en)
|
||||
const stepsRu = renderSteps(args.quick_start_steps_ru)
|
||||
|
|
@ -210,7 +211,7 @@ export default tool({
|
|||
quick_start: tool.schema
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Install/setup command (e.g. 'pip install -r requirements.txt'). Required for create mode."),
|
||||
.describe("Install/setup command (e.g. 'pip install -r requirements.txt'). Optional — omit or pass '' when setup is steps-only (use quick_start_steps_*); bash block omitted when empty AND include_clone is false."),
|
||||
quick_start_steps_en: tool.schema
|
||||
.array(tool.schema.string())
|
||||
.optional()
|
||||
|
|
@ -294,7 +295,6 @@ export default tool({
|
|||
what_en: args.what_en,
|
||||
why_ru: args.why_ru,
|
||||
what_ru: args.what_ru,
|
||||
quick_start: args.quick_start,
|
||||
}
|
||||
for (const [k, v] of Object.entries(required)) {
|
||||
if (!v) return `❌ ${k} is required for create mode`
|
||||
|
|
@ -304,6 +304,14 @@ export default tool({
|
|||
if (!args.features_ru || args.features_ru.length === 0)
|
||||
return `❌ features_ru is required for create mode`
|
||||
|
||||
const hasBash = args.include_clone !== false || (args.quick_start ?? "") !== ""
|
||||
const hasStepsEn = !!args.quick_start_steps_en && args.quick_start_steps_en.length > 0
|
||||
const hasStepsRu = !!args.quick_start_steps_ru && args.quick_start_steps_ru.length > 0
|
||||
if (!hasBash && !hasStepsEn)
|
||||
return `❌ quick_start or quick_start_steps_en required (Quick Start EN would be empty)`
|
||||
if (!hasBash && !hasStepsRu)
|
||||
return `❌ quick_start or quick_start_steps_ru required (Quick Start RU would be empty)`
|
||||
|
||||
const content = generateReadme({
|
||||
repo_name: args.repo_name!,
|
||||
tagline: args.tagline!,
|
||||
|
|
@ -311,7 +319,7 @@ export default tool({
|
|||
what_en: args.what_en!,
|
||||
why_ru: args.why_ru!,
|
||||
what_ru: args.what_ru!,
|
||||
quick_start: args.quick_start!,
|
||||
quick_start: args.quick_start,
|
||||
features_en: args.features_en!,
|
||||
features_ru: args.features_ru!,
|
||||
access_url: args.access_url,
|
||||
|
|
|
|||
66
docs/decisions/063-pr-149-empty-quick-start.md
Normal file
66
docs/decisions/063-pr-149-empty-quick-start.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# ADR-063: Allow empty quick_start with steps-only Quick Start (PR-149)
|
||||
|
||||
## Статус
|
||||
Accepted (2026-07-30)
|
||||
|
||||
## Контекст
|
||||
ADR-062 (PR-146) добавил параметры `quick_start_steps_en/ru` и условный
|
||||
`hasBashBlock` (`include_clone !== false || quick_start !== ""`), чтобы
|
||||
поддержать userscript-README с кликабельными шагами вместо bash-команды. Однако
|
||||
валидация в `execute()` (mode `create`) по-прежнему требовала непустой
|
||||
`quick_start` через falsy-чек `!v` в required-Record — пустая строка `""`
|
||||
считалась отсутствующей, тулза возвращала `quick_start is required for create
|
||||
mode`. Скилл `repo-readme` (раздел 8 «Кейс: userscript / web-app / npm-package»)
|
||||
документирует комбинацию `include_clone: false` + `quick_start: ""` +
|
||||
`quick_start_steps_*` как supported — но тулза её отвергала. Дополнительно:
|
||||
`hasBashBlock` использовал `args.quick_start !== ""`, что для `undefined`
|
||||
давало `true` (undefined !== ""), и bash-блок рендерил literal `undefined`
|
||||
в теле code-fence. ADR-062 явно отметил в «Альтернативах», что ослабление
|
||||
required-чек — отдельное решение вне scope того PR.
|
||||
|
||||
## Решение
|
||||
1. **`CreateArgs.quick_start`** — сделан optional (`quick_start?: string`),
|
||||
чтобы отражать реальную опциональность параметра.
|
||||
2. **Required-валидация в `execute()`** — `quick_start` убран из required-Record.
|
||||
Вместо него добавлен guard после общих required-чеков:
|
||||
- `hasBash = include_clone !== false || (quick_start ?? "") !== ""`
|
||||
- `hasStepsEn = !!quick_start_steps_en && length > 0`
|
||||
- `hasStepsRu = !!quick_start_steps_ru && length > 0`
|
||||
- Если `!hasBash && !hasStepsEn` → ошибка `quick_start or
|
||||
quick_start_steps_en required (Quick Start EN would be empty)`
|
||||
- Если `!hasBash && !hasStepsRu` → аналогичная ошибка для RU.
|
||||
Guard гарантирует, что Quick Start секция не пуста в ОБОИХ языках. Если
|
||||
bash-блок рендерится — steps опциональны (backward compat).
|
||||
3. **`hasBashBlock` и тела bash-блоков** — `args.quick_start ?? ""` вместо
|
||||
`args.quick_start`: обрабатывает `undefined` (когда параметр не передан
|
||||
вообще), иначе `undefined !== ""` даёт `true` и bash-блок рендерит literal
|
||||
`undefined`. Локальная переменная `qs = args.quick_start ?? ""` переиспользуется
|
||||
в обоих bash-блоках (EN/RU).
|
||||
4. **Schema `.describe()`** — убрано "Required for create mode.", добавлено
|
||||
пояснение: параметр optional, пустая строка/absent допустимы когда есть
|
||||
`quick_start_steps_*`, bash-блок опускается при пустом AND `include_clone=false`.
|
||||
5. **`validateReadme`** — без изменений: проверяет наличие строк "Quick Start" /
|
||||
"Быстрый старт" в заголовках (`### ⚡ Quick Start` / `### ⚡ Быстрый старт`),
|
||||
которые рендерятся всегда. README без bash-блока (только steps) проходит
|
||||
валидацию. Подтверждено smoke-тестом (сценарий 1).
|
||||
6. **Backward compatibility** — все существующие вызовы с непустым `quick_start`
|
||||
и без steps работают идентично (сценарий 2 smoke-теста: git clone + pip
|
||||
install, без шагов, без `undefined`).
|
||||
|
||||
## Альтернативы
|
||||
- **Сделать `quick_start` required только когда нет steps** — отвергнуто:
|
||||
сложная условная required-логика в одном Record, тяжело читать. Cleaner —
|
||||
убрать из required и добавить явный guard с понятными сообщениями ошибок
|
||||
для каждого языка отдельно.
|
||||
- **Один общий guard «есть bash ИЛИ (steps EN И steps RU)»** — отвергнуто:
|
||||
это допустило бы пустую RU-секцию когда есть bash + steps EN (но это
|
||||
backward-compat кейс, где bash рендерится в обеих секциях). Текущий guard
|
||||
(`!hasBash && !hasStepsX`) срабатывает ТОЛЬКО когда bash-блока нет —
|
||||
тогда steps нужны в обоих языках. Когда bash есть — steps опциональны.
|
||||
- **Валидировать steps в `validateReadme`** — отвергнуто: validate проверяет
|
||||
структуру delimiter-пар и наличие секций, не содержимое Quick Start.
|
||||
Заголовки рендерятся всегда; проверять пустоту секции — responsibility
|
||||
`execute()`, не `validateReadme`.
|
||||
- **Не вводить `qs` локальную переменную** — отвергнуто: повторение
|
||||
`args.quick_start ?? ""` в трёх местах (hasBashBlock + 2 bash-блока) хуже
|
||||
для читаемости, чем одна переменная.
|
||||
20
docs/handoff/pr-149-empty-quick-start.md
Normal file
20
docs/handoff/pr-149-empty-quick-start.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
pr: 149
|
||||
title: fix(create-readme): allow empty quick_start with steps-only Quick Start
|
||||
---
|
||||
|
||||
## Что сделано
|
||||
|
||||
Ослаблена валидация `quick_start` в `.opencode/tools/create-readme.ts` (mode `create`): параметр убран из required-Record (раньше falsy-чек `!v` отвергал `""`), вместо него добавлен guard — Quick Start секция не должна быть пустой (bash-блок ИЛИ steps в ОБОИХ языках EN/RU). `CreateArgs.quick_start` сделан optional (`?: string`). `hasBashBlock` и тела bash-блоков обрабатывают `undefined` через `?? ""` (раньше `undefined !== ""` давало `true` → bash-блок рендерил literal `undefined`). `.describe()` в schema обновлён (убрано "Required for create mode."). Smoke-тест: 5 сценариев, 24 assertion'а, все PASS (userscript-only-steps, backward-compat bash, guard EN, guard RU, bash+steps-en-no-steps-ru).
|
||||
|
||||
## Почему
|
||||
|
||||
Issue #147: тулза блокировала userscript-README без bash-команды (`quick_start: ""` + `include_clone: false`), хотя скилл `repo-readme` (раздел 8) документирует именно эту комбинацию. PR #146 (ADR-062) добавил `quick_start_steps_*` и условный `hasBashBlock`, но явно отметил в «Альтернативах», что ослабление required-валидации `quick_start` — вне scope того PR. PR #147 закрывает этот пробел: guard гарантирует, что Quick Start не пуст, при этом пустой `quick_start` (или его отсутствие) теперь допустим, если есть steps.
|
||||
|
||||
## Pending
|
||||
|
||||
—
|
||||
|
||||
## Watch out
|
||||
|
||||
Guard проверяет steps отдельно для EN и RU: если bash-блок не рендерится (`include_clone=false` + пустой `quick_start`), нужно `quick_start_steps_en` И `quick_start_steps_ru` — иначе одна из секций будет пустой. Если у репо один bash-блок (non-empty `quick_start` или `include_clone=true`) — steps опциональны в обоих языках (backward compat). `validateReadme` не менялся: он проверяет наличие строк "Quick Start"/"Быстрый старт" в заголовках, которые рендерятся всегда. ADR-063 отменяет альтернативу «Ослабить required-чек quick_start» из ADR-062.
|
||||
|
|
@ -45,7 +45,7 @@ opencode-config/
|
|||
│ │ ├── commit.ts # commit tool wrapper (1 arg message, validates format+staged) — PR#38
|
||||
│ │ ├── create-issue.ts # create-issue tool wrapper (3 args, validates format+labels; optional repo?: string) — PR#38, PR#65
|
||||
│ │ ├── create-pr.ts # create-pr tool wrapper (3 args, validates format+Closes #N; optional repo?: string) — PR#38, PR#65
|
||||
│ │ ├── create-readme.ts # create-readme tool (TS plugin, modes: create/validate; standardized bilingual README with features table, include_clone/development_en/ru/quick_start_steps_en/ru optional params, clickable access_url [url](url), conditional bash block via hasBashBlock, RU heading 'Русский' + anchor checks, 4 delimiter pairs for slaid098.dev; local fs + remote gh api) — PR#112, PR#116, PR#118, PR#130, PR#146
|
||||
│ │ ├── create-readme.ts # create-readme tool (TS plugin, modes: create/validate; standardized bilingual README with features table, include_clone/development_en/ru/quick_start_steps_en/ru optional params, clickable access_url [url](url), conditional bash block via hasBashBlock, RU heading 'Русский' + anchor checks, 4 delimiter pairs for slaid098.dev; local fs + remote gh api) — PR#112, PR#116, PR#118, PR#130, PR#146, PR#149 (quick_start optional + guard: Quick Start non-empty per-lang via hasBash/hasStepsEn/hasStepsRu; hasBashBlock handles undefined via ?? "")
|
||||
│ │ ├── draw-image.ts # draw-image tool wrapper (opencode plugin, 5 args: template/title/subtitle?/slots?/out?; spawnSync node cli.ts render → sharp PNG) — PR#133
|
||||
│ │ ├── merge-pr.ts # merge-pr tool wrapper (orchestrator-safe gh pr merge; optional repo?: string) — PR#30, PR#65
|
||||
│ │ ├── memory-access.ts # memory-access tool (bump frontmatter last_accessed/access_count, regex replace, atomic write tmp+rename) — PR#101
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue