From cf15682d1cbe510228c6ed3e9bc45abf9699a60c Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Sun, 23 Aug 2026 22:38:12 -0400 Subject: [PATCH] enhance(#3028): responsive Markdown separators instead of fixed-width rules (#3789) * feat(#3028): responsive Markdown separators instead of fixed-width rules Stage banners, checkpoints, completion and error panels used fixed-width runs of box-drawing characters -- a 53-column heavy rule and a 62-column double-line box. Those runs are ordinary text to a Markdown-rendering host, so in a narrower pane they wrap and the border comes apart from the heading it framed. Shipped content now emits an ATX heading for a titled section and a blank-line-delimited --- for a break between sections, both of which adapt to the available width. The same convention is applied to the three code sites that built these strings at runtime: the UAT checkpoint renderer, the milestone-close audit report, and the TDD review checkpoint table. Removing the box also removes its only reason to exist -- the east-asian-width padding helpers that kept its right border aligned (checkpointBoxLine, displayWidth, isWideCodePoint, ZERO_WIDTH_MARK_RE, CHECKPOINT_BOX_WIDTH). RTL directional isolation is unchanged. The convention is specified in gsd-core/references/ui-brand.md and enforced across all shipped content by tests/responsive-separators.test.cjs. Refs #3028 * test(#3028): pin the heading form in checkpoint and audit-report assertions These suites asserted the exact box borders and the 62-column padded banner interior. With the box gone they assert the ### heading form, the --- break and the bolded instruction line, and each now carries a positive assertion that no box character remains -- which is what pins the fix rather than merely tolerating it. Language coverage is converted, not dropped: Japanese, Chinese, Korean, Hindi and Arabic all still assert their rendered banner, and the Arabic case still asserts the RTL directional isolates the box removal must not disturb. Adds a case for a banner longer than the old inner width, which previously produced a ragged border and now has none. Refs #3028 * chore(#3028): acknowledge execute-plan.md growth from the checkpoint display spec The checkpoint_protocol display spec described the drawn box; it now describes the heading, the --- break and the bolded action prompt, which costs 22 bytes (40111 -> 40133, 827 under the cap). Appended to the existing #3370 fragment rather than filed as a new one: a growth ack keys on the bare filename and #3370 already declares execute-plan.md, so a second source naming it would be a hard duplicate-key error. Same supersede-by-append route #3370 took for the spent #2652 fragment. Refs #3028 * docs(#3028): state the load-bearing half of the separator rule, and amend the zh-CN reference Review found three things. The rule as first written demanded a blank line above AND below every ---. Only the one above is load-bearing: it is what stops CommonMark reading the rule as a setext underline for the line above. The one below is cosmetic, because a thematic break is a leaf block. The rule now says that, with the reason, instead of asserting a stricter form the content does not keep. The zh-CN reference had received the mechanical box-to-heading swap but none of the prose behind it: it still claimed a 62-character checkpoint width and still listed --- among forbidden mixed banner styles, so it contradicted the convention it was translating. It now carries the separator section, the setext reasoning, the unconditional-vs-per-runtime rationale and a corrected anti-pattern list, in Chinese. The user guide asserted that a heading is not a degradation anywhere. That is an assertion, not a demonstration. It now says what was actually traded away in a plain terminal, points at the recorded rationale, and invites the report that would justify the capability flag instead. Refs #3028 * chore(#3028): backfill changeset PR number Refs #3028 --------- Co-authored-by: sim --- .changeset/clever-eagles-jump.md | 5 + agents/gsd-framework-selector.md | 4 +- commands/gsd/quick.md | 12 +- docs/USER-GUIDE.md | 61 ++++ docs/how-to/update-gsd.md | 7 +- docs/ja-JP/how-to/update-gsd.md | 7 +- docs/ko-KR/how-to/update-gsd.md | 7 +- docs/pt-BR/how-to/update-gsd.md | 7 +- docs/tutorials/your-first-project.md | 10 +- docs/zh-CN/how-to/update-gsd.md | 7 +- docs/zh-CN/references/checkpoints.md | 20 +- docs/zh-CN/references/ui-brand.md | 75 +++-- gsd-core/references/checkpoints.md | 30 +- gsd-core/references/execute-mvp-tdd.md | 4 +- gsd-core/references/gate-prompts.md | 2 +- gsd-core/references/offer-next.md | 8 +- gsd-core/references/tdd.md | 4 +- gsd-core/references/ui-brand.md | 86 +++-- gsd-core/workflows/add-tests.md | 9 +- gsd-core/workflows/ai-integration-phase.md | 9 +- gsd-core/workflows/audit-milestone.md | 14 +- gsd-core/workflows/autonomous.md | 32 +- gsd-core/workflows/code-review.md | 11 +- gsd-core/workflows/debug.md | 6 +- gsd-core/workflows/diagnose-issues.md | 4 +- .../steps/auto-advance-dispatch.md | 4 +- .../workflows/discuss-phase/modes/chain.md | 8 +- gsd-core/workflows/do.md | 5 +- gsd-core/workflows/eval-review.md | 9 +- gsd-core/workflows/execute-plan.md | 2 +- gsd-core/workflows/health.md | 5 +- gsd-core/workflows/import.md | 12 +- gsd-core/workflows/inbox.md | 5 +- gsd-core/workflows/ingest-docs.md | 8 +- gsd-core/workflows/list-seeds.md | 6 +- gsd-core/workflows/manager.md | 31 +- gsd-core/workflows/new-milestone.md | 24 +- gsd-core/workflows/new-project.md | 36 +-- gsd-core/workflows/plan-phase.md | 45 +-- .../plan-phase/steps/prd-express-path.md | 4 +- gsd-core/workflows/plan-review-convergence.md | 8 +- gsd-core/workflows/pr-branch.md | 4 +- gsd-core/workflows/profile-user.md | 10 +- gsd-core/workflows/quick.md | 28 +- .../workflows/quick/steps/discussion-phase.md | 4 +- .../quick/steps/plan-checker-loop.md | 4 +- .../quick/steps/quick-verification.md | 4 +- .../workflows/quick/steps/research-phase.md | 4 +- gsd-core/workflows/resume-project.md | 18 +- gsd-core/workflows/review.md | 8 +- gsd-core/workflows/settings-advanced.md | 4 +- gsd-core/workflows/settings-integrations.md | 4 +- gsd-core/workflows/settings.md | 4 +- gsd-core/workflows/ship.md | 4 +- gsd-core/workflows/sketch-wrap-up.md | 24 +- gsd-core/workflows/sketch.md | 24 +- gsd-core/workflows/smart-entry.md | 4 +- gsd-core/workflows/spike-wrap-up.md | 14 +- gsd-core/workflows/spike.md | 45 +-- gsd-core/workflows/thread.md | 12 +- gsd-core/workflows/ui-phase.md | 16 +- gsd-core/workflows/ui-review.md | 12 +- gsd-core/workflows/ultraplan-phase.md | 16 +- gsd-core/workflows/undo.md | 20 +- gsd-core/workflows/update.md | 12 +- gsd-core/workflows/verify-work.md | 23 +- skills/gsd-quick/SKILL.md | 12 +- src/audit.cts | 19 +- src/check-command-router.cts | 5 +- src/uat.cts | 63 +--- tests/audit-command-cutover.test.cjs | 16 +- .../3370-execute-phase-gate-conflation.json | 2 +- tests/responsive-separators.test.cjs | 297 ++++++++++++++++++ tests/uat.test.cjs | 159 +++++----- 74 files changed, 849 insertions(+), 699 deletions(-) create mode 100644 .changeset/clever-eagles-jump.md create mode 100644 tests/responsive-separators.test.cjs diff --git a/.changeset/clever-eagles-jump.md b/.changeset/clever-eagles-jump.md new file mode 100644 index 000000000..3ebbb7211 --- /dev/null +++ b/.changeset/clever-eagles-jump.md @@ -0,0 +1,5 @@ +--- +type: Changed +pr: 3789 +--- +**Section separators now render responsively instead of wrapping** — stage banners, checkpoints, completion and error panels used fixed-width runs of box-drawing characters (a 53-column `━` rule, a 62-column `╔═╗` box). In a narrower pane those runs wrap and the border comes apart from the heading it framed. GSD now emits Markdown headings and `---` thematic breaks, which adapt to the available width in every runtime. (#3028) diff --git a/agents/gsd-framework-selector.md b/agents/gsd-framework-selector.md index b9c9d5d99..830cafcdf 100644 --- a/agents/gsd-framework-selector.md +++ b/agents/gsd-framework-selector.md @@ -134,9 +134,7 @@ FRAMEWORK_RECOMMENDATION: Display to user: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - FRAMEWORK RECOMMENDATION -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### FRAMEWORK RECOMMENDATION ◆ Primary Pick: {framework} {rationale} diff --git a/commands/gsd/quick.md b/commands/gsd/quick.md index 35b89b57d..e4597bb87 100644 --- a/commands/gsd/quick.md +++ b/commands/gsd/quick.md @@ -86,12 +86,14 @@ For each directory found: Display format: ``` Quick Tasks -──────────────────────────────────────────────────────────── + +--- slug date status backup-s3-policy 2026-04-10 in-progress auth-token-refresh-fix 2026-04-09 complete ✓ update-node-deps 2026-04-08 abandoned? (>7 days, no summary) -──────────────────────────────────────────────────────────── + +--- 3 tasks (1 complete, 2 incomplete/in-progress) ``` @@ -113,12 +115,14 @@ If no directory found, print `No quick task found with slug: {SLUG}` and stop. Read PLAN.md and SUMMARY.md (if exists) for the given slug. Display: ``` Quick Task: {slug} -───────────────────────────────────── + +--- Plan file: .planning/quick/{dir}/PLAN.md Status: {status from SUMMARY.md frontmatter, or "no summary yet"} Description: {first non-empty line from PLAN.md after frontmatter} Last action: {last meaningful line of SUMMARY.md, or "none"} -───────────────────────────────────── + +--- Resume with: /gsd:quick resume {slug} ``` diff --git a/docs/USER-GUIDE.md b/docs/USER-GUIDE.md index 5e4da0dc9..b919b26e0 100644 --- a/docs/USER-GUIDE.md +++ b/docs/USER-GUIDE.md @@ -11,6 +11,7 @@ A narrative companion guide to GSD Core — orient yourself here, then follow th - [Slash-command forms](#slash-command-forms-hyphen-vs-colon) - [Namespace routing primer](#namespace-routing-primer-gsd-ns--v140) +- [Reading GSD's output](#reading-gsds-output) - [Project lifecycle overview](#project-lifecycle-overview) - [Workflow Diagrams](#workflow-diagrams) - [UI Design Contract](#ui-design-contract) @@ -73,6 +74,66 @@ On the seven nesting runtimes listed above, upgrading to v1.40 changes skill inv --- +## Reading GSD's output + +GSD marks its sections with Markdown, not with drawn borders. There are exactly +three forms, and every workflow, checkpoint and report uses them: + +| You see | It means | +|---|---| +| `### GSD ► {STAGE NAME}` | A major workflow transition — planning, executing a wave, verifying, completing | +| `### CHECKPOINT: {Type}` | GSD is waiting on you. The bolded `**→ …**` line at the bottom tells you what to type | +| `---` | A break between two sections — most often before the **▶ Next Up** block at the end of a completion | + +Panels that used to be drawn with box characters are now a heading followed by +their rows as ordinary lines. A checkpoint reads: + +``` +### CHECKPOINT: Verification Required + +Progress: 5/8 tasks complete +Task: Responsive dashboard layout + +How to verify: + 1. Visit: http://localhost:3000/dashboard + +--- + +**→ YOUR ACTION: Type "approved" or describe issues** +``` + +### Why there are no drawn borders + +Earlier releases framed stage banners between two 53-character runs +of `━`, and checkpoints were a 62-column box drawn with `╔`, `║` and `╚`. Those +runs are ordinary text to whatever renders GSD's output. In a pane narrower than +the run, the rule wraps and the leftover glyphs land on a second line — so the +border comes apart from the heading it was framing, and the output looks broken +rather than merely narrow. Reported against the Codex desktop interface in +[#3028](https://github.com/open-gsd/gsd-core/issues/3028). + +A Markdown heading and a thematic break carry the same structure without +committing to a width, so they read correctly in a narrow pane and a wide one. + +This is unconditional: every runtime gets the same output. The alternative — a +capability flag that kept line-art for terminal-oriented runtimes — was weighed +and rejected, because it leaves two output conventions to keep in sync forever +for a gain that is aesthetic rather than structural. What a terminal loses is the +drawn frame; what it keeps is the title, the hierarchy and the break, none of +which depended on the frame. The reasoning is recorded in +`gsd-core/references/ui-brand.md § Why this is unconditional, not per-runtime`. +If you run GSD in a host where the heading form reads worse than the old boxes +did, that is worth reporting — it is the evidence that would justify the flag. + +Single-cell tokens are unaffected and unchanged: the status symbols +(`✓ ✗ ◆ ○ ⚠`), the `GSD ►` prefix, and the ten-cell progress gauge +(`Progress: ████████░░ 80%`) are not runs and do not wrap. + +The convention is specified in `gsd-core/references/ui-brand.md` and enforced +against all shipped content by `tests/responsive-separators.test.cjs`. + +--- + ## Project lifecycle overview The core GSD loop is: **discuss → plan → execute → verify → ship**, repeated per phase. The full step-by-step walkthrough — including example outputs, what files get created, and all the flags in play — is in the dedicated tutorial. diff --git a/docs/how-to/update-gsd.md b/docs/how-to/update-gsd.md index 218b03485..188fa79be 100644 --- a/docs/how-to/update-gsd.md +++ b/docs/how-to/update-gsd.md @@ -75,9 +75,12 @@ Installed: 1.39.0 Latest: 1.41.0 ### What's New -──────────────────────────────────────────────────────────── + +--- + [changelog entries for 1.40.0 and 1.41.0] -──────────────────────────────────────────────────────────── + +--- Proceed with update? [Yes, update now / No, cancel] ``` diff --git a/docs/ja-JP/how-to/update-gsd.md b/docs/ja-JP/how-to/update-gsd.md index f3bf1c5b6..7354f9821 100644 --- a/docs/ja-JP/how-to/update-gsd.md +++ b/docs/ja-JP/how-to/update-gsd.md @@ -54,9 +54,12 @@ Installed: 1.39.0 Latest: 1.41.0 ### What's New -──────────────────────────────────────────────────────────── + +--- + [changelog entries for 1.40.0 and 1.41.0] -──────────────────────────────────────────────────────────── + +--- Proceed with update? [Yes, update now / No, cancel] ``` diff --git a/docs/ko-KR/how-to/update-gsd.md b/docs/ko-KR/how-to/update-gsd.md index a15924c22..a0a25ccf5 100644 --- a/docs/ko-KR/how-to/update-gsd.md +++ b/docs/ko-KR/how-to/update-gsd.md @@ -54,9 +54,12 @@ Installed: 1.39.0 Latest: 1.41.0 ### What's New -──────────────────────────────────────────────────────────── + +--- + [changelog entries for 1.40.0 and 1.41.0] -──────────────────────────────────────────────────────────── + +--- Proceed with update? [Yes, update now / No, cancel] ``` diff --git a/docs/pt-BR/how-to/update-gsd.md b/docs/pt-BR/how-to/update-gsd.md index 128261fd4..3efcd324a 100644 --- a/docs/pt-BR/how-to/update-gsd.md +++ b/docs/pt-BR/how-to/update-gsd.md @@ -54,9 +54,12 @@ Installed: 1.39.0 Latest: 1.41.0 ### What's New -──────────────────────────────────────────────────────────── + +--- + [changelog entries for 1.40.0 and 1.41.0] -──────────────────────────────────────────────────────────── + +--- Proceed with update? [Yes, update now / No, cancel] ``` diff --git a/docs/tutorials/your-first-project.md b/docs/tutorials/your-first-project.md index 9198c5895..c2e267a1c 100644 --- a/docs/tutorials/your-first-project.md +++ b/docs/tutorials/your-first-project.md @@ -441,17 +441,15 @@ deliverables into checkpoints. It presents one checkpoint at a time; the first one looks like this (the test wording depends on what was built): ```text -╔══════════════════════════════════════════════════════════════╗ -║ CHECKPOINT: Verification Required ║ -╚══════════════════════════════════════════════════════════════╝ +### CHECKPOINT: Verification Required **Test 1: Add a to-do** Running `node todo.js add "buy milk"` creates a pending item without errors. -────────────────────────────────────────────────────────────── -Type `pass` or describe what's wrong. -────────────────────────────────────────────────────────────── +--- + +**Type `pass` or describe what's wrong.** ``` Type `pass` when reality matches, or describe what differs. GSD records the diff --git a/docs/zh-CN/how-to/update-gsd.md b/docs/zh-CN/how-to/update-gsd.md index 3dc3c740c..7a4aaf804 100644 --- a/docs/zh-CN/how-to/update-gsd.md +++ b/docs/zh-CN/how-to/update-gsd.md @@ -54,9 +54,12 @@ Installed: 1.39.0 Latest: 1.41.0 ### What's New -──────────────────────────────────────────────────────────── + +--- + [changelog entries for 1.40.0 and 1.41.0] -──────────────────────────────────────────────────────────── + +--- Proceed with update? [Yes, update now / No, cancel] ``` diff --git a/docs/zh-CN/references/checkpoints.md b/docs/zh-CN/references/checkpoints.md index 9be3db209..9e0fdda78 100644 --- a/docs/zh-CN/references/checkpoints.md +++ b/docs/zh-CN/references/checkpoints.md @@ -202,9 +202,7 @@ **对于 checkpoint:human-verify:** ``` -╔═══════════════════════════════════════════════════════╗ -║ CHECKPOINT: 需要验证 ║ -╚═══════════════════════════════════════════════════════╝ +### CHECKPOINT: 需要验证 进度: 5/8 任务完成 任务: 响应式仪表板布局 @@ -217,16 +215,14 @@ 3. 平板端 (768px): 侧边栏折叠为图标 4. 移动端 (375px): 侧边栏隐藏,出现汉堡菜单 -──────────────────────────────────────────────────────── -→ 你的操作: 输入 "approved" 或描述问题 -──────────────────────────────────────────────────────── +--- + +**→ 你的操作: 输入 "approved" 或描述问题** ``` **对于 checkpoint:decision:** ``` -╔═══════════════════════════════════════════════════════╗ -║ CHECKPOINT: 需要决策 ║ -╚═══════════════════════════════════════════════════════╝ +### CHECKPOINT: 需要决策 进度: 2/6 任务完成 任务: 选择认证提供商 @@ -248,9 +244,9 @@ 优点: 免费,无供应商锁定,广泛采用 缺点: 更多设置工作,自行 DIY 安全更新 -──────────────────────────────────────────────────────── -→ 你的操作: 选择 supabase、clerk 或 nextauth -──────────────────────────────────────────────────────── +--- + +**→ 你的操作: 选择 supabase、clerk 或 nextauth** ``` ## 认证门控 diff --git a/docs/zh-CN/references/ui-brand.md b/docs/zh-CN/references/ui-brand.md index 08b7840bd..a45f44036 100644 --- a/docs/zh-CN/references/ui-brand.md +++ b/docs/zh-CN/references/ui-brand.md @@ -2,14 +2,43 @@ 面向用户的 GSD 输出的视觉模式。编排器通过 @ 引用此文件。 +## 分隔符与横幅 + +**绝不要输出固定宽度的制表符(box-drawing)长串。** 由 `━`、`─`、`═` 组成的长串,对渲染 +输出的宿主而言只是普通文本。当窗格比该长串更窄时,它会折行,多余的字符落到第二行,于是边框 +与它本应框住的标题就散开了。Markdown 会自适应可用宽度,53 个字符的横线不会。 + +只有三种形式,没有其他: + +| 需求 | 输出 | +|---|---| +| 带标题的区块 —— 阶段、检查点、完成、错误 | `### {标题}`(ATX 标题) | +| 两个区块之间的分隔 | 单独一行的 `---`,**其上方必须有一个空行** | +| 带边框的信息面板 | `### {标题}`,随后各行以普通文本列出 | + +**`---` 上方的空行是关键,不是排版讲究。** 紧跟在一行文本下方的 `---` 会被解析为该行的 +setext 标题下划线,而不是分隔线 —— 那条横线会把上面那行"吞掉"。空行才使它成为分隔线。 +(`---` *下方*的空行是可选的:分隔线是叶子块,后面的内容无论如何都会另起一块。) + +**阶段横幅只用标题,不要在其上方加 `---`。** ATX 标题本身就是分隔,而且不会像裸的 `---` +那样被误解析。 + +### 为什么是统一形式,而非按运行时区分 + +曾考虑过引入 `rendersMarkdown` 能力键:终端类运行时保留线条图形,Markdown 宿主使用 +Markdown。该方案被否决 —— 它需要在每个运行时描述符及解析器中新增一个键,并且会留下两套必须 +永远保持同步的输出约定,正是本仓库已记录的"分叉"缺陷类别。在纯终端里,标题与分隔线所承载的 +结构与原来的横线对并无二致,却不必锁定宽度,因此第二套约定并无收益。若将来确实出现需要线条 +图形的运行时,届时再依据该证据添加此键。 + +--- + ## 阶段横幅 用于主要工作流过渡。 ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► {阶段名称} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► {阶段名称} ``` **阶段名称(大写):** @@ -25,20 +54,18 @@ --- -## 检查点框 +## 检查点面板 -需要用户操作。62 字符宽度。 +需要用户操作。 ``` -╔══════════════════════════════════════════════════════════════╗ -║ CHECKPOINT: {类型} ║ -╚══════════════════════════════════════════════════════════════╝ +### CHECKPOINT: {类型} {内容} -────────────────────────────────────────────────────────────── -→ {操作提示} -────────────────────────────────────────────────────────────── +--- + +**→ {操作提示}** ``` **类型:** @@ -102,7 +129,7 @@ 始终在主要完成后。 ``` -─────────────────────────────────────────────────────────────── +--- ## ▶ 下一步 @@ -112,22 +139,20 @@ `/clear` 优先 → 全新上下文窗口 -─────────────────────────────────────────────────────────────── +--- **也可选:** - (根据工作流选填可选命令,例如 `/gsd-progress --next`) -─────────────────────────────────────────────────────────────── +--- ``` --- -## 错误框 +## 错误面板 ``` -╔══════════════════════════════════════════════════════════════╗ -║ ERROR ║ -╚══════════════════════════════════════════════════════════════╝ +### ERROR {错误描述} @@ -150,8 +175,16 @@ ## 反模式 -- 变化的框/横幅宽度 -- 混合横幅样式(`===`、`---`、`***`) +- 用 `━`、`─`、`═` 的固定宽度长串作分隔符 —— 在窄窗格中会折行 +- 用双线制表符(U+2554、U+2557、U+255A、U+255D、U+2551、U+2560、U+2563)画的边框面板 —— + 边框会独立于内容折行。此处以码位命名而非直接展示,因为守卫检查会拒绝这些字符出现在任何 + 随包分发的内容中。 +- 紧跟在一行文本下方、中间没有空行的 `---` —— 那是 setext 标题下划线而非分隔线,会把上面 + 那行吞掉 +- 把标题夹在两条横线之间 —— 标题本身就是分隔 +- 混合横幅样式(`===`、`***`) - 横幅中缺少 `GSD ►` 前缀 - 随机 emoji(`🚀`、`✨`、`💫`) -- 完成后缺少下一步区块 \ No newline at end of file +- 完成后缺少下一步区块 + +由 `tests/responsive-separators.test.cjs` 强制执行。 \ No newline at end of file diff --git a/gsd-core/references/checkpoints.md b/gsd-core/references/checkpoints.md index 25d616ec8..ab52164f0 100644 --- a/gsd-core/references/checkpoints.md +++ b/gsd-core/references/checkpoints.md @@ -323,9 +323,7 @@ When Claude encounters `type="checkpoint:*"`: **For checkpoint:human-verify:** ``` -╔═══════════════════════════════════════════════════════╗ -║ CHECKPOINT: Verification Required ║ -╚═══════════════════════════════════════════════════════╝ +### CHECKPOINT: Verification Required Progress: 5/8 tasks complete Task: Responsive dashboard layout @@ -338,16 +336,14 @@ How to verify: 3. Tablet (768px): Sidebar collapses to icons 4. Mobile (375px): Sidebar hidden, hamburger menu appears -──────────────────────────────────────────────────────── -→ YOUR ACTION: Type "approved" or describe issues -──────────────────────────────────────────────────────── +--- + +**→ YOUR ACTION: Type "approved" or describe issues** ``` **For checkpoint:decision:** ``` -╔═══════════════════════════════════════════════════════╗ -║ CHECKPOINT: Decision Required ║ -╚═══════════════════════════════════════════════════════╝ +### CHECKPOINT: Decision Required Progress: 2/6 tasks complete Task: Select authentication provider @@ -369,16 +365,14 @@ Options: Pros: Free, no vendor lock-in, widely adopted Cons: More setup work, DIY security updates -──────────────────────────────────────────────────────── -→ YOUR ACTION: Select supabase, clerk, or nextauth -──────────────────────────────────────────────────────── +--- + +**→ YOUR ACTION: Select supabase, clerk, or nextauth** ``` **For checkpoint:human-action:** ``` -╔═══════════════════════════════════════════════════════╗ -║ CHECKPOINT: Action Required ║ -╚═══════════════════════════════════════════════════════╝ +### CHECKPOINT: Action Required Progress: 3/8 tasks complete Task: Deploy to Vercel @@ -393,9 +387,9 @@ What you need to do: I'll verify: vercel whoami returns your account -──────────────────────────────────────────────────────── -→ YOUR ACTION: Type "done" when authenticated -──────────────────────────────────────────────────────── +--- + +**→ YOUR ACTION: Type "done" when authenticated** ``` diff --git a/gsd-core/references/execute-mvp-tdd.md b/gsd-core/references/execute-mvp-tdd.md index bba22c9c3..0beb9fc81 100644 --- a/gsd-core/references/execute-mvp-tdd.md +++ b/gsd-core/references/execute-mvp-tdd.md @@ -40,9 +40,7 @@ The executor MUST: 2. Emit a structured halt report: ``` - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - MVP+TDD GATE TRIPPED — Plan {plan_id}, Task {task_id} - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### MVP+TDD GATE TRIPPED — Plan {plan_id}, Task {task_id} Reason: {missing_red_commit | red_commit_not_failing | feat_before_test} diff --git a/gsd-core/references/gate-prompts.md b/gsd-core/references/gate-prompts.md index feecace8b..94b68548c 100644 --- a/gsd-core/references/gate-prompts.md +++ b/gsd-core/references/gate-prompts.md @@ -2,7 +2,7 @@ Reusable prompt patterns for structured gate checks in workflows and agents. -**For checkpoint box format details, see `gsd-core/references/ui-brand.md`** -- checkpoint boxes use double-line border drawing with 62-character inner width. +**For checkpoint format details, see `gsd-core/references/ui-brand.md`** -- a checkpoint is a `### CHECKPOINT: {Type}` heading followed by its content, then a `---` break and the bolded action prompt. Never a fixed-width drawn border: it wraps in a narrow pane. ## Rules diff --git a/gsd-core/references/offer-next.md b/gsd-core/references/offer-next.md index b808e4d02..003124238 100644 --- a/gsd-core/references/offer-next.md +++ b/gsd-core/references/offer-next.md @@ -4,7 +4,6 @@ extraction restores byte-budget headroom the frozen ceiling exists to provide. --> - **Exception:** If `gaps_found`, the `verify_phase_goal` step already presents the gap-closure path (`/gsd:plan-phase {X} --gaps`). No additional routing needed — skip auto-advance. **No-transition check (spawned by auto-advance chain):** @@ -41,10 +40,9 @@ STOP. Do not proceed to auto-advance or transition. **If `--auto` flag present OR `AUTO_MODE` is true (AND verification passed with no gaps):** ``` -╔══════════════════════════════════════════╗ -║ AUTO-ADVANCING → TRANSITION ║ -║ Phase {X} verified, continuing chain ║ -╚══════════════════════════════════════════╝ +### AUTO-ADVANCING → TRANSITION + +Phase {X} verified, continuing chain ``` Execute the transition workflow inline (do NOT use Agent — orchestrator context is ~10-15%, transition needs phase completion data already in context): diff --git a/gsd-core/references/tdd.md b/gsd-core/references/tdd.md index 92a367240..2e2de42f6 100644 --- a/gsd-core/references/tdd.md +++ b/gsd-core/references/tdd.md @@ -289,9 +289,7 @@ When `workflow.tdd_mode` is enabled, the execute-phase orchestrator inserts a co ### Review Checkpoint Format ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - TDD REVIEW — Phase {X} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### TDD REVIEW — Phase {X} TDD Plans: {count} | Gate violations: {count} diff --git a/gsd-core/references/ui-brand.md b/gsd-core/references/ui-brand.md index 9a9676b78..8a70a0e56 100644 --- a/gsd-core/references/ui-brand.md +++ b/gsd-core/references/ui-brand.md @@ -2,14 +2,51 @@ Visual patterns for user-facing GSD output. Orchestrators @-reference this file. +## Separators and Banners + +**Never emit a fixed-width run of box-drawing characters.** A run of `━`, `─` or +`═` is ordinary text to the host that renders your output. In a narrower pane it +wraps, leaving orphan glyphs on a second line and coming apart from the heading it +was meant to frame. Markdown adapts to the available width; a 53-character rule +does not. + +Three forms, and nothing else: + +| Need | Emit | +|---|---| +| A titled section — stage, phase, checkpoint, completion, error | `### {TITLE}` (ATX heading) | +| A break between two sections | `---` on its own line, **with a blank line above it** | +| A framed panel of rows | `### {TITLE}` followed by the rows as plain lines | + +**The blank line above `---` is load-bearing, not cosmetic.** A `---` placed +directly under a line of text is parsed as a setext heading underline for that +line, not as a thematic break — the rule silently swallows the line above it. A +blank line is what makes it a thematic break. (A blank line *after* `---` is +optional: a thematic break is a leaf block, so whatever follows starts a new +block either way. Add one where it reads better.) + +**A stage banner is a heading alone — do not put a `---` above it.** An ATX +heading already separates, and it cannot be misparsed the way a bare `---` can. + +### Why this is unconditional, not per-runtime + +The alternative considered was a `rendersMarkdown` capability key, keeping +line-art for terminal-oriented runtimes and Markdown for Markdown hosts. It was +rejected: it needs a new descriptor key across every runtime plus the resolver, +and it leaves two output conventions to keep in sync forever — the divergence +class this repo already has a defect entry for. A heading and a thematic break +carry the same structure in a plain terminal that a rule pair did, without +committing to a width, so the second convention buys nothing. If a runtime ever +turns up that genuinely needs line-art, add the key then, against that evidence. + +--- + ## Stage Banners Use for major workflow transitions. ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► {STAGE NAME} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► {STAGE NAME} ``` **Stage names (uppercase):** @@ -25,20 +62,18 @@ Use for major workflow transitions. --- -## Checkpoint Boxes +## Checkpoint Panels -User action required. 62-character width. +User action required. ``` -╔══════════════════════════════════════════════════════════════╗ -║ CHECKPOINT: {Type} ║ -╚══════════════════════════════════════════════════════════════╝ +### CHECKPOINT: {Type} {Content} -────────────────────────────────────────────────────────────── -→ {ACTION PROMPT} -────────────────────────────────────────────────────────────── +--- + +**→ {ACTION PROMPT}** ``` **Types:** @@ -60,6 +95,9 @@ User action required. 62-character width. 🎉 Milestone complete (only in banner) ``` +Status symbols are single characters, not runs — they do not wrap and are +unaffected by the separator rule above. + --- ## Progress Display @@ -79,6 +117,9 @@ Tasks: 2/4 complete Plans: 3/5 complete ``` +The bar itself is a fixed 10-cell gauge, not a separator; it is intentionally +fixed-width and stays as it is. + --- ## Spawning Indicators @@ -104,7 +145,7 @@ Plans: 3/5 complete Always at end of major completions. ``` -─────────────────────────────────────────────────────────────── +--- ## ▶ Next Up @@ -114,23 +155,19 @@ Always at end of major completions. `{copy-paste command}` -─────────────────────────────────────────────────────────────── +--- **Also available:** - `/gsd-alternative-1` — description - `/gsd-alternative-2` — description - -─────────────────────────────────────────────────────────────── ``` --- -## Error Box +## Error Panel ``` -╔══════════════════════════════════════════════════════════════╗ -║ ERROR ║ -╚══════════════════════════════════════════════════════════════╝ +### ERROR {Error description} @@ -149,14 +186,21 @@ Always at end of major completions. | 3 | ○ | 0/2 | 0% | ``` +Table rules use ASCII `-`, never box-drawing characters. + --- ## Anti-Patterns -- Varying box/banner widths -- Mixing banner styles (`===`, `---`, `***`) +- Fixed-width runs of `━`, `─` or `═` as separators — they wrap in a narrow pane +- Box panels drawn with double-line box characters (U+2554, U+2557, U+255A, U+255D, U+2551, U+2560, U+2563) — the borders wrap independently of their contents. They are named here by code point rather than shown, because the guard below rejects the characters themselves anywhere in shipped content. +- A `---` directly under a line of text with no blank line between — that is a setext heading underline, not a break, and it swallows the line above +- Boxing a heading between two rules — the heading is the separator +- Mixing banner styles (`===`, `***`) - Skipping `GSD ►` prefix in banners - Random emoji (`🚀`, `✨`, `💫`) - Missing Next Up block after completions +Enforced by `tests/responsive-separators.test.cjs`. + diff --git a/gsd-core/workflows/add-tests.md b/gsd-core/workflows/add-tests.md index 88803ca23..04b5797d2 100644 --- a/gsd-core/workflows/add-tests.md +++ b/gsd-core/workflows/add-tests.md @@ -63,9 +63,7 @@ Exit. Present banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► ADD TESTS — Phase ${phase_number}: ${phase_name} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► ADD TESTS — Phase ${phase_number}: ${phase_name} ``` @@ -111,7 +109,6 @@ Read each file to verify classification. Don't classify based on filename alone. Present the classification to the user for confirmation before proceeding: - **Text mode (`workflow.text_mode: true` in config or `--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available. ``` @@ -280,9 +277,7 @@ For each approved E2E test: Create a test coverage report and present to user: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► TEST GENERATION COMPLETE -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► TEST GENERATION COMPLETE ## Results diff --git a/gsd-core/workflows/ai-integration-phase.md b/gsd-core/workflows/ai-integration-phase.md index 5e24cfbcf..e4b2b5eec 100644 --- a/gsd-core/workflows/ai-integration-phase.md +++ b/gsd-core/workflows/ai-integration-phase.md @@ -78,7 +78,6 @@ Continue (non-blocking). AI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-AI-SPEC.md 2>/dev/null | head -1) ``` - **Text mode (`workflow.text_mode: true` in config or `--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available. **If exists:** Use AskUserQuestion: - header: "Existing AI-SPEC" @@ -96,9 +95,7 @@ If "Update": continue to step 5. Display: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► AI DESIGN CONTRACT — PHASE {N}: {name} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► AI DESIGN CONTRACT — PHASE {N}: {name} ◆ Step 1/4 — Framework Selection... ``` @@ -265,9 +262,7 @@ gsd_run query commit "docs({phase_slug}): generate AI-SPEC.md — {primary_frame ## 12. Display Completion ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► AI-SPEC COMPLETE — PHASE {N}: {name} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► AI-SPEC COMPLETE — PHASE {N}: {name} ◆ Framework: {primary_framework} ◆ System Type: {system_type} diff --git a/gsd-core/workflows/audit-milestone.md b/gsd-core/workflows/audit-milestone.md index 4b919ee8c..9f5008d67 100644 --- a/gsd-core/workflows/audit-milestone.md +++ b/gsd-core/workflows/audit-milestone.md @@ -244,7 +244,7 @@ Output this markdown directly (not as a code block). Route based on status: All requirements covered. Cross-phase integration verified. E2E flows complete. -─────────────────────────────────────────────────────────────── +--- ## ▶ Next Up — [${PROJECT_CODE}] ${PROJECT_TITLE} @@ -254,7 +254,7 @@ All requirements covered. Cross-phase integration verified. E2E flows complete. /gsd:complete-milestone {version} -─────────────────────────────────────────────────────────────── +--- --- @@ -289,7 +289,7 @@ All requirements covered. Cross-phase integration verified. E2E flows complete. Phases needing validation: run `/gsd:validate-phase {N}` for each flagged phase. -─────────────────────────────────────────────────────────────── +--- ## ▶ Next Up — [${PROJECT_CODE}] ${PROJECT_TITLE} @@ -310,13 +310,13 @@ For Nyquist-coverage gaps flagged in the table above, prefer running ` if SECURITY.md was flagged) before inserting a new closure phase — they may close the gap retroactively without a new phase. -─────────────────────────────────────────────────────────────── +--- **Also available:** - cat .planning/v{version}-MILESTONE-AUDIT.md — see full report - /gsd:complete-milestone {version} — proceed anyway (accept tech debt) -─────────────────────────────────────────────────────────────── +--- --- @@ -338,7 +338,7 @@ All requirements met. No critical blockers. Accumulated tech debt needs review. ### Total: {N} items across {M} phases -─────────────────────────────────────────────────────────────── +--- ## ▶ Options @@ -356,7 +356,7 @@ Insert a closure phase using the standard chain: /gsd:plan-phase /gsd:execute-phase -─────────────────────────────────────────────────────────────── +--- diff --git a/gsd-core/workflows/autonomous.md b/gsd-core/workflows/autonomous.md index bc546a3e5..6ad629558 100644 --- a/gsd-core/workflows/autonomous.md +++ b/gsd-core/workflows/autonomous.md @@ -106,9 +106,7 @@ Parse JSON for: `milestone_version`, `milestone_name`, `phase_count`, `completed Display startup banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► AUTONOMOUS -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► AUTONOMOUS Milestone: {milestone_version} — {milestone_name} Phases: {phase_count} total, {completed_phases} complete @@ -175,9 +173,7 @@ Exit cleanly. **If no incomplete phases remain:** ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► AUTONOMOUS ▸ COMPLETE 🎉 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► AUTONOMOUS ▸ COMPLETE 🎉 All phases complete! Nothing left to do. ``` @@ -216,9 +212,7 @@ Extract `phase_name`, `goal`, `success_criteria` from each. Store for use in exe For the current phase, display the progress banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► AUTONOMOUS ▸ Phase {N}/{T}: {Name} [████░░░░] {P}% -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► AUTONOMOUS ▸ Phase {N}/{T}: {Name} [████░░░░] {P}% ``` Where N is the ROADMAP phase number, T is the milestone `phase_count`, and P = completed milestone phases / T × 100. Use `phase_count`, not remaining phases: phase 63 in a 7-phase milestone is `Phase 63/7`, not `Phase 63/3`. If N > T, render `Phase {N} ({position}/{T})`. Use an 8-character bar with █ and ░. @@ -594,9 +588,7 @@ Read and execute: `$HOME/.claude/gsd-core/references/autonomous-smart-discuss.md **If `TO_PHASE` is set and current phase number >= `TO_PHASE`:** The target phase has been reached. Do not iterate further. Display: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► AUTONOMOUS ▸ --to ${TO_PHASE} REACHED -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► AUTONOMOUS ▸ --to ${TO_PHASE} REACHED Completed through phase ${TO_PHASE} as requested. Remaining phases were not executed. @@ -646,9 +638,7 @@ If all phases complete, proceed to lifecycle step. **If `ONLY_PHASE` is set:** Skip lifecycle. A single phase does not trigger audit/complete/cleanup. Display: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► AUTONOMOUS ▸ PHASE ${ONLY_PHASE} COMPLETE ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► AUTONOMOUS ▸ PHASE ${ONLY_PHASE} COMPLETE ✓ Phase ${ONLY_PHASE}: ${PHASE_NAME} — Done Mode: Single phase (--only) @@ -664,9 +654,7 @@ Exit cleanly. Display lifecycle transition banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► AUTONOMOUS ▸ LIFECYCLE -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► AUTONOMOUS ▸ LIFECYCLE All phases complete → Starting lifecycle: audit → complete → cleanup Milestone: {milestone_version} — {milestone_name} @@ -755,9 +743,7 @@ Cleanup shows its own dry-run and asks user for approval internally — this is Display final completion banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► AUTONOMOUS ▸ COMPLETE 🎉 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► AUTONOMOUS ▸ COMPLETE 🎉 Milestone: {milestone_version} — {milestone_name} Status: Complete ✅ @@ -788,9 +774,7 @@ When any phase operation fails or a blocker is detected, present 3 options via A **On "Stop autonomous mode":** Display progress summary: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► AUTONOMOUS ▸ STOPPED -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► AUTONOMOUS ▸ STOPPED Completed: {list of completed phases} Skipped: {list of skipped phases} diff --git a/gsd-core/workflows/code-review.md b/gsd-core/workflows/code-review.md index b86ae66ea..cfe439243 100644 --- a/gsd-core/workflows/code-review.md +++ b/gsd-core/workflows/code-review.md @@ -690,11 +690,11 @@ TOTAL=$(echo "$FRONTMATTER" | grep "total:" | head -1 | cut -d: -f2 | xargs) Display inline summary to user: ``` -═══════════════════════════════════════════════════════════════ +--- Code Review Complete: Phase ${PHASE_NUMBER} (${PHASE_NAME}) -─────────────────────────────────────────────────────────────── +--- Depth: ${REVIEW_DEPTH} (${DEPTH_PROVENANCE}) Files Reviewed: ${FILES_REVIEWED} @@ -703,10 +703,11 @@ Display inline summary to user: Critical: ${CRITICAL} Warning: ${WARNING} Info: ${INFO} - ────────── + +--- Total: ${TOTAL} -─────────────────────────────────────────────────────────────── +--- ``` If status is "clean": @@ -735,7 +736,7 @@ grep -A 3 "^### CR-\|^### BL-\|^### WR-" "${REVIEW_PATH}" | head -n 12 **Note on tests:** Automated tests for this command and workflow are planned for Phase 4 (Pipeline Integration & Testing, requirement INFR-03). Phase 2 focuses on correct implementation; Phase 4 adds regression coverage across platforms. -═══════════════════════════════════════════════════════════════ +--- diff --git a/gsd-core/workflows/debug.md b/gsd-core/workflows/debug.md index 58e86ee65..ca85849f6 100644 --- a/gsd-core/workflows/debug.md +++ b/gsd-core/workflows/debug.md @@ -44,7 +44,8 @@ For each file found, parse frontmatter fields (`status`, `trigger`, `updated`) a ``` Active Debug Sessions -───────────────────────────────────────────── + +--- # Slug Status Updated 1 auth-token-null investigating 2026-04-12 hypothesis: JWT decode fails when token contains nested claims @@ -53,7 +54,8 @@ Active Debug Sessions 2 form-submit-500 fixing 2026-04-11 hypothesis: Missing null check on req.body.user next: Verify fix passes regression test -───────────────────────────────────────────── + +--- Run `/gsd:debug continue ` to resume a session. No sessions? `/gsd:debug ` to start. ``` diff --git a/gsd-core/workflows/diagnose-issues.md b/gsd-core/workflows/diagnose-issues.md index 3e1c525e0..ab6ee9afb 100644 --- a/gsd-core/workflows/diagnose-issues.md +++ b/gsd-core/workflows/diagnose-issues.md @@ -258,9 +258,7 @@ gsd_run query commit "docs({phase_num}): add root causes from diagnosis" --files Display: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► DIAGNOSIS COMPLETE -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► DIAGNOSIS COMPLETE | Gap (Truth) | Root Cause | Files | |-------------|------------|-------| diff --git a/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md b/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md index 07d0596b6..07018d4aa 100644 --- a/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +++ b/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md @@ -2,9 +2,7 @@ Display banner: ```text -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► AUTO-ADVANCING TO PLAN -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► AUTO-ADVANCING TO PLAN Context captured (assumptions mode). Launching plan-phase... ``` diff --git a/gsd-core/workflows/discuss-phase/modes/chain.md b/gsd-core/workflows/discuss-phase/modes/chain.md index 4463a4fa4..11afd986d 100644 --- a/gsd-core/workflows/discuss-phase/modes/chain.md +++ b/gsd-core/workflows/discuss-phase/modes/chain.md @@ -48,9 +48,7 @@ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-pars Banner: ``` - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► AUTO-ADVANCING TO PLAN - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► AUTO-ADVANCING TO PLAN Context captured. Launching plan-phase... ``` @@ -69,9 +67,7 @@ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-pars - **PHASE COMPLETE** → Full chain succeeded. Display: ``` - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► PHASE ${PHASE} COMPLETE - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► PHASE ${PHASE} COMPLETE Auto-advance pipeline finished: discuss → plan → execute diff --git a/gsd-core/workflows/do.md b/gsd-core/workflows/do.md index 8b49d6856..3e250f5f8 100644 --- a/gsd-core/workflows/do.md +++ b/gsd-core/workflows/do.md @@ -18,7 +18,6 @@ RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --default "" 2>/d **Check for input.** - **Text mode (`workflow.text_mode: true` in config or `--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available. If `$ARGUMENTS` is empty, ask via AskUserQuestion: @@ -85,9 +84,7 @@ Which approach fits better? **Show the routing decision.** ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► ROUTING -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► ROUTING **Input:** {first 80 chars of $ARGUMENTS} **Routing to:** {chosen command} diff --git a/gsd-core/workflows/eval-review.md b/gsd-core/workflows/eval-review.md index 8b121c6e5..2ea0c6026 100644 --- a/gsd-core/workflows/eval-review.md +++ b/gsd-core/workflows/eval-review.md @@ -30,9 +30,7 @@ AGENT_SKILLS_AUDITOR=$(gsd_run query agent-skills gsd-eval-auditor) Display banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► EVAL AUDIT — PHASE {N}: {name} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► EVAL AUDIT — PHASE {N}: {name} ``` ## 1. Detect Input State @@ -47,7 +45,6 @@ EVAL_REVIEW_FILE=$(ls "${PHASE_DIR}"/*-EVAL-REVIEW.md 2>/dev/null | head -1) **State B** — SUMMARY.md exists, no AI-SPEC.md: Audit against general best practices **State C** — No SUMMARY.md: Exit — "Phase {N} not executed. Run /gsd:execute-phase {N} first." - **Text mode (`workflow.text_mode: true` in config or `--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available. **If `EVAL_REVIEW_FILE` non-empty:** Use AskUserQuestion: - header: "Existing Eval Review" @@ -121,9 +118,7 @@ Read the written EVAL-REVIEW.md. Extract: ## 5. Display Summary ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► EVAL AUDIT COMPLETE — PHASE {N}: {name} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► EVAL AUDIT COMPLETE — PHASE {N}: {name} ◆ Score: {overall_score}/100 ◆ Verdict: {verdict} diff --git a/gsd-core/workflows/execute-plan.md b/gsd-core/workflows/execute-plan.md index 62eb3789b..cda873c02 100644 --- a/gsd-core/workflows/execute-plan.md +++ b/gsd-core/workflows/execute-plan.md @@ -333,7 +333,7 @@ Canonical per-task commit rules live in **`agents/gsd-executor.md`** (` On `type="checkpoint:*"`: automate everything possible first. Checkpoints are for verification/decisions only. -Display: `CHECKPOINT: [Type]` box → Progress {X}/{Y} → Task name → type-specific content → `YOUR ACTION: [signal]` +Display: `### CHECKPOINT: [Type]` heading → Progress {X}/{Y} → Task name → type-specific content → `---` → `**YOUR ACTION: [signal]**` | Type | Content | Resume signal | |------|---------|---------------| diff --git a/gsd-core/workflows/health.md b/gsd-core/workflows/health.md index c2b63b0cb..b4362a180 100644 --- a/gsd-core/workflows/health.md +++ b/gsd-core/workflows/health.md @@ -14,7 +14,6 @@ RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --default "" 2>/d **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated. - **Parse arguments:** @@ -136,9 +135,7 @@ If the check prints, append it to the Warnings section of the report as `[W025]` **Format and display results:** ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD Health Check -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD Health Check Status: HEALTHY | DEGRADED | BROKEN Errors: N | Warnings: N | Info: N diff --git a/gsd-core/workflows/import.md b/gsd-core/workflows/import.md index f2bfa463e..df27f5c7a 100644 --- a/gsd-core/workflows/import.md +++ b/gsd-core/workflows/import.md @@ -19,9 +19,7 @@ RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --default "" 2>/d **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated. ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► IMPORT -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► IMPORT ``` @@ -57,9 +55,7 @@ test -f "{FILEPATH}" || echo "FILE_NOT_FOUND" If FILE_NOT_FOUND: display error and exit: ``` -╔══════════════════════════════════════════════════════════════╗ -║ ERROR ║ -╚══════════════════════════════════════════════════════════════╝ +### ERROR File not found: {FILEPATH} @@ -251,9 +247,7 @@ gsd_run query commit "docs({phase}): import plan from {basename FILEPATH}" --fil Display completion: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► IMPORT COMPLETE -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► IMPORT COMPLETE ``` Show: plan filename written, phase directory, validation result, next steps. diff --git a/gsd-core/workflows/inbox.md b/gsd-core/workflows/inbox.md index 79f1a78df..45ea84d7c 100644 --- a/gsd-core/workflows/inbox.md +++ b/gsd-core/workflows/inbox.md @@ -24,7 +24,6 @@ RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --default "" 2>/d **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated. - Verify prerequisites: @@ -351,7 +350,7 @@ AskUserQuestion: ``` -─────────────────────────────────────────────────────────────── +--- ## Inbox Triage Complete @@ -368,7 +367,7 @@ Next steps: - Merge ready PRs - Triage unclassified issues -─────────────────────────────────────────────────────────────── +--- ``` diff --git a/gsd-core/workflows/ingest-docs.md b/gsd-core/workflows/ingest-docs.md index 1c54899a3..32f933b65 100644 --- a/gsd-core/workflows/ingest-docs.md +++ b/gsd-core/workflows/ingest-docs.md @@ -14,9 +14,7 @@ Scan a repo for mixed planning documents (ADR, PRD, SPEC, DOC), synthesize them Display the stage banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► INGEST DOCS -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► INGEST DOCS ``` @@ -332,9 +330,7 @@ gsd_run commit \ Display completion: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► INGEST DOCS COMPLETE -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► INGEST DOCS COMPLETE ``` Show: diff --git a/gsd-core/workflows/list-seeds.md b/gsd-core/workflows/list-seeds.md index f28d39971..5af83021c 100644 --- a/gsd-core/workflows/list-seeds.md +++ b/gsd-core/workflows/list-seeds.md @@ -37,11 +37,13 @@ Render the seeds as a table, sorted by `seed_id` (already sorted by the tool). T ``` Seeds -───────────────────────────────────────────────────────────────────── + +--- ID Status Scope Trigger Title SEED-001 dormant large when websockets land Real-time collaboration SEED-006 triggered medium MILE-04 planning Remove legacy auth crates -───────────────────────────────────────────────────────────────────── + +--- seeds () ``` diff --git a/gsd-core/workflows/manager.md b/gsd-core/workflows/manager.md index 22cf96820..c4c46e026 100644 --- a/gsd-core/workflows/manager.md +++ b/gsd-core/workflows/manager.md @@ -40,16 +40,15 @@ These are empty strings by default. Set via: `gsd-tools.cjs query config-set man Display startup banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► MANAGER -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► MANAGER {milestone_version} — {milestone_name} {phase_count} phases · {completed_count} complete ✓ Discuss → inline ◆ Plan/Execute → inline (background when FLATTEN=false) Dashboard auto-refreshes when background work is active. -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +--- ``` Proceed to dashboard step. @@ -92,9 +91,7 @@ Use `deps_display` from init JSON for the Deps column — shows which phases thi Example output: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► DASHBOARD -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► DASHBOARD ████████████░░░░░░░░ 60% (3/5 phases) ◆ Background: Planning Phase 4 | # | Phase | Deps | D | P | E | Status | @@ -116,9 +113,7 @@ Use `queued_milestone_version` and `queued_milestone_name` for the header. Phase Example: ``` - ─────────────────────────────────────────────────────────────── - ◆ Queued — {queued_milestone_version} {queued_milestone_name} ({queued_phases.length} phases) - ─────────────────────────────────────────────────────────────── +### ◆ Queued — {queued_milestone_version} {queued_milestone_name} ({queued_phases.length} phases) | # | Phase | Deps | Status | |---|----------------------|------|--------------| | 31| Email Logs | — | · Queued | @@ -134,16 +129,13 @@ Queued phases are NOT eligible for the Continue action menu — they live in a f If `all_complete` is true: ``` -╔══════════════════════════════════════════════════════════════╗ -║ MILESTONE COMPLETE ║ -╚══════════════════════════════════════════════════════════════╝ +### MILESTONE COMPLETE All {phase_count} phases verified complete. Ready for final steps: → /gsd:verify-work — run acceptance testing → /gsd:complete-milestone — archive and wrap up ``` - **Text mode (`workflow.text_mode: true` in config or `--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available. Ask user via AskUserQuestion: - **question:** "All phases complete. What next?" @@ -188,9 +180,7 @@ Handle responses: Display recommendations compactly: ``` -─────────────────────────────────────────────────────────────── -▶ Next Steps -─────────────────────────────────────────────────────────────── +### ▶ Next Steps Continue: → Execute Phase 32 (background) @@ -411,15 +401,14 @@ Classify the error: Display final status with progress bar: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► SESSION END -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► SESSION END {milestone_version} — {milestone_name} {PROGRESS_BAR} {progress_pct}% ({completed_count}/{phase_count} phases) Resume anytime: /gsd:manager -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +--- ``` **Note:** Any background agents still running will continue to completion. Their results will be visible on next `/gsd:manager` or `/gsd:progress` invocation. diff --git a/gsd-core/workflows/new-milestone.md b/gsd-core/workflows/new-milestone.md index 6d5583c8b..22a661c57 100644 --- a/gsd-core/workflows/new-milestone.md +++ b/gsd-core/workflows/new-milestone.md @@ -131,9 +131,7 @@ AskUserQuestion( Before writing any files, present a summary of what was gathered and ask for confirmation. ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► MILESTONE SUMMARY -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► MILESTONE SUMMARY **Milestone v[X.Y]: [Name]** @@ -325,9 +323,7 @@ AskUserQuestion: "Research the domain ecosystem for new features before defining **If user chose "Research first":** ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► RESEARCHING -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► RESEARCHING ◆ Spawning 4 researchers in parallel... (each runs in a subagent — no output until they return, ~1–5 min; expected, not a freeze) → Stack, Features, Architecture, Pitfalls @@ -422,9 +418,7 @@ This guarantees `gsd-roadmapper` (which lists SUMMARY.md as required reading) ne Display key findings from SUMMARY.md: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► RESEARCH COMPLETE ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► RESEARCH COMPLETE ✓ **Stack additions:** [from SUMMARY.md] **Feature table stakes:** [from SUMMARY.md] @@ -436,9 +430,7 @@ Display key findings from SUMMARY.md: ## 9. Define Requirements ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► DEFINING REQUIREMENTS -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► DEFINING REQUIREMENTS ``` Read PROJECT.md: core value, current milestone goals, validated requirements (what exists). @@ -509,9 +501,7 @@ gsd_run query commit "docs: define milestone v[X.Y] requirements" --files .plann ## 10. Create Roadmap ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► CREATING ROADMAP -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► CREATING ROADMAP ◆ Spawning roadmapper... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze) ``` @@ -645,9 +635,7 @@ Print a summary: ## 11. Done ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► MILESTONE INITIALIZED ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► MILESTONE INITIALIZED ✓ **Milestone v[X.Y]: [Name]** diff --git a/gsd-core/workflows/new-project.md b/gsd-core/workflows/new-project.md index 142c89b93..8eafd1d19 100644 --- a/gsd-core/workflows/new-project.md +++ b/gsd-core/workflows/new-project.md @@ -151,9 +151,7 @@ If spike/sketch findings skills exist, read their SKILL.md files to inform the q **Display stage banner:** ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► QUESTIONING -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► QUESTIONING ``` **Open the conversation:** @@ -700,9 +698,7 @@ Use AskUserQuestion: Display stage banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► RESEARCHING -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► RESEARCHING Researching [domain] ecosystem... ``` @@ -942,9 +938,7 @@ This guarantees `gsd-roadmapper` (which lists SUMMARY.md as required reading) ne Display research complete banner and key findings: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► RESEARCH COMPLETE ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► RESEARCH COMPLETE ✓ ## Key Findings @@ -962,9 +956,7 @@ Files: `.planning/research/` Display stage banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► DEFINING REQUIREMENTS -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► DEFINING REQUIREMENTS ``` **Load context:** @@ -1131,9 +1123,7 @@ When `TEXT_MODE=true` (per the workflow's existing TEXT_MODE handling for non-Cl Display stage banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► CREATING ROADMAP -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► CREATING ROADMAP ◆ Spawning roadmapper... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze) ``` @@ -1300,9 +1290,7 @@ gsd_run query commit "docs: create roadmap ([N] phases)" --files .planning/ROADM Present completion summary: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► PROJECT INITIALIZED ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► PROJECT INITIALIZED ✓ **[Project Name]** @@ -1321,9 +1309,7 @@ Present completion summary: **If auto mode:** ``` -╔══════════════════════════════════════════╗ -║ AUTO-ADVANCING → DISCUSS PHASE 1 ║ -╚══════════════════════════════════════════╝ +### AUTO-ADVANCING → DISCUSS PHASE 1 ``` Exit skill and invoke SlashCommand("/gsd:discuss-phase 1 --auto") @@ -1340,7 +1326,7 @@ PHASE1_HAS_UI=$(echo "$PHASE1_SECTION" | grep -qi "UI hint.*yes" && echo "true" **If Phase 1 has UI (`PHASE1_HAS_UI` is `true`):** ``` -─────────────────────────────────────────────────────────────── +--- ## ▶ Next Up — [${PROJECT_CODE}] ${PROJECT_TITLE} @@ -1356,13 +1342,13 @@ PHASE1_HAS_UI=$(echo "$PHASE1_SECTION" | grep -qi "UI hint.*yes" && echo "true" - /gsd:ui-phase 1 — generate UI design contract (recommended for frontend phases) - /gsd:plan-phase 1 — skip discussion, plan directly -─────────────────────────────────────────────────────────────── +--- ``` **If Phase 1 has no UI:** ``` -─────────────────────────────────────────────────────────────── +--- ## ▶ Next Up — [${PROJECT_CODE}] ${PROJECT_TITLE} @@ -1377,7 +1363,7 @@ PHASE1_HAS_UI=$(echo "$PHASE1_SECTION" | grep -qi "UI hint.*yes" && echo "true" **Also available:** - /gsd:plan-phase 1 — skip discussion, plan directly -─────────────────────────────────────────────────────────────── +--- ``` diff --git a/gsd-core/workflows/plan-phase.md b/gsd-core/workflows/plan-phase.md index 63035b208..f3416856b 100644 --- a/gsd-core/workflows/plan-phase.md +++ b/gsd-core/workflows/plan-phase.md @@ -337,9 +337,7 @@ If user selects "Skip research": skip to step 6. Display banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► RESEARCHING PHASE {X} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► RESEARCHING PHASE {X} ◆ Spawning researcher... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze) ``` @@ -434,9 +432,7 @@ Resolve active contribution hooks from `PLAN_PRE_HOOKS_JSON` where `kind == "con Display banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► SECURITY THREAT MODEL REQUIRED (ASVS L{SECURITY_ASVS}) -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► SECURITY THREAT MODEL REQUIRED (ASVS L{SECURITY_ASVS}) Each PLAN.md must include a block. Block on: {SECURITY_BLOCK} severity threats. @@ -522,7 +518,8 @@ Output this markdown directly (not as a code block): ## ⚠ UI-SPEC.md missing for Phase {N} ▶ Recommended next step: `/gsd:ui-phase {N} ${GSD_WS}` — generate UI design contract before planning -─────────────────────────────────────────────── + +--- Also available: - `/gsd:plan-phase {N} --skip-ui ${GSD_WS}` — plan without UI-SPEC (not recommended for frontend phases) ``` @@ -618,9 +615,7 @@ Pattern mapper activation is owned by the `pattern-mapper` capability's `plan:pr Display banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► PATTERN MAPPING PHASE {X} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► PATTERN MAPPING PHASE {X} ◆ Spawning pattern mapper... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze) ``` @@ -690,9 +685,7 @@ independent of the teams-status guard above, AC2). Display banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► PLANNING PHASE {X} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► PLANNING PHASE {X} ◆ Spawning planner... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze) ``` @@ -993,9 +986,7 @@ Use AskUserQuestion for each gap (or batch if multiple gaps). Display banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► VERIFYING PLANS -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► VERIFYING PLANS ◆ Spawning plan checker... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze) ``` @@ -1222,9 +1213,7 @@ BOUNCE_SCRIPT=$(gsd_run query config-get workflow.plan_bounce_script --raw 2>/de Display banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► BOUNCING PLANS (External Refinement) -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► BOUNCING PLANS (External Refinement) Script: ${BOUNCE_SCRIPT} Max passes: ${BOUNCE_PASSES} @@ -1498,9 +1487,7 @@ fi Display banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► AUTO-ADVANCING TO EXECUTE -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► AUTO-ADVANCING TO EXECUTE Plans ready. Launching execute-phase... ``` @@ -1515,9 +1502,7 @@ The `--no-transition` flag tells execute-phase to return status after verificati **Handle execute-phase return:** - **PHASE COMPLETE** → Display final summary: ``` - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► PHASE ${PHASE} COMPLETE ✓ - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► PHASE ${PHASE} COMPLETE ✓ Auto-advance pipeline finished. @@ -1541,9 +1526,7 @@ Output this markdown directly (not as a code block): `${GAPS_EXEC_FLAG}` projects the just-completed planning mode onto the follow-up execute command (#3297): it expands to `--gaps-only` for a `--gaps` planning run (so the handoff points at execute-phase's gap-closure scope — only the newly created `gap_closure: true` plans — not the whole phase) and to empty for a standard or `--reviews` run (whole-phase scope, unchanged). Substitute it verbatim; when empty, collapse the extra space. -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► PHASE {X} PLANNED ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► PHASE {X} PLANNED ✓ **Phase {X}: {Name}** — {N} plan(s) in {M} wave(s) @@ -1555,7 +1538,7 @@ Output this markdown directly (not as a code block): Research: {Completed | Used existing | Skipped} Verification: {Passed | Passed with override | Skipped} -─────────────────────────────────────────────────────────────── +--- ## ▶ Next Up — [${PROJECT_CODE}] ${PROJECT_TITLE} @@ -1565,7 +1548,7 @@ Verification: {Passed | Passed with override | Skipped} /gsd:execute-phase {X} ${GAPS_EXEC_FLAG} ${GSD_WS} -─────────────────────────────────────────────────────────────── +--- **Also available:** - cat .planning/phases/{phase-dir}/*-PLAN.md — review plans @@ -1573,7 +1556,7 @@ Verification: {Passed | Passed with override | Skipped} - /gsd:review --phase {X} --all — peer review plans with external AIs - /gsd:plan-phase {X} --reviews — replan incorporating review feedback -─────────────────────────────────────────────────────────────── +--- diff --git a/gsd-core/workflows/plan-phase/steps/prd-express-path.md b/gsd-core/workflows/plan-phase/steps/prd-express-path.md index e05c988fa..47e85dd6e 100644 --- a/gsd-core/workflows/plan-phase/steps/prd-express-path.md +++ b/gsd-core/workflows/plan-phase/steps/prd-express-path.md @@ -13,9 +13,7 @@ fi 2. Display banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► PRD EXPRESS PATH -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► PRD EXPRESS PATH Using PRD: {PRD_FILE} Generating CONTEXT.md from requirements... diff --git a/gsd-core/workflows/plan-review-convergence.md b/gsd-core/workflows/plan-review-convergence.md index e5f6690f6..59a271cc9 100644 --- a/gsd-core/workflows/plan-review-convergence.md +++ b/gsd-core/workflows/plan-review-convergence.md @@ -134,9 +134,7 @@ PHASE_INFO=$(gsd_run roadmap get-phase "${PHASE}") Display startup banner: ```text -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► PLAN CONVERGENCE — Phase {phase_number} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► PLAN CONVERGENCE — Phase {phase_number} Reviewers: {REVIEWER_DISPLAY} Max cycles: {MAX_CYCLES} @@ -400,9 +398,7 @@ gsd_run state planned-phase --phase "${PHASE}" --name "${phase_name}" --plans "$ Display: ```text -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► CONVERGENCE COMPLETE ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► CONVERGENCE COMPLETE ✓ Phase {phase_number} converged in {cycle} cycle(s). No HIGH concerns remaining. diff --git a/gsd-core/workflows/pr-branch.md b/gsd-core/workflows/pr-branch.md index bc5163114..013f6c9e9 100644 --- a/gsd-core/workflows/pr-branch.md +++ b/gsd-core/workflows/pr-branch.md @@ -63,9 +63,7 @@ if [ "$PR_STRICT" = "true" ]; then PR_MODE="strict"; else PR_MODE="default"; PR_ Display: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► PR BRANCH -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► PR BRANCH Branch: {CURRENT_BRANCH} Target: {TARGET} diff --git a/gsd-core/workflows/profile-user.md b/gsd-core/workflows/profile-user.md index 88addea26..8458756d8 100644 --- a/gsd-core/workflows/profile-user.md +++ b/gsd-core/workflows/profile-user.md @@ -21,7 +21,6 @@ RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --default "" 2>/d **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated. - ## 1. Initialize Parse flags from $ARGUMENTS: @@ -37,7 +36,6 @@ PROFILE_PATH="$HOME/.claude/gsd-core/USER-PROFILE.md" **If profile exists AND --refresh NOT set AND --questionnaire NOT set:** - **Text mode (`workflow.text_mode: true` in config or `--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available. Use AskUserQuestion: - header: "Existing Profile" @@ -72,9 +70,7 @@ Continue to step 2. Display consent screen: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD > PROFILE YOUR CODING STYLE -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD > PROFILE YOUR CODING STYLE Claude starts every conversation generic. A profile teaches Claude how YOU actually work -- not how you think you work. @@ -421,9 +417,7 @@ If nothing changed: Display "No changes detected -- your profile is already up t **Display final summary:** ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD > PROFILE COMPLETE ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD > PROFILE COMPLETE ✓ Your profile: $HOME/.claude/gsd-core/USER-PROFILE.md ``` diff --git a/gsd-core/workflows/quick.md b/gsd-core/workflows/quick.md index a7c8924f8..a85683b1b 100644 --- a/gsd-core/workflows/quick.md +++ b/gsd-core/workflows/quick.md @@ -65,63 +65,49 @@ Display banner based on active flags: If `$FULL_MODE` (all phases enabled — `--full` or all granular flags): ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► QUICK TASK (FULL) -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► QUICK TASK (FULL) ◆ Discussion + research + plan checking + verification enabled ``` If `$DISCUSS_MODE` and `$VALIDATE_MODE` (no research): ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► QUICK TASK (DISCUSS + VALIDATE) -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► QUICK TASK (DISCUSS + VALIDATE) ◆ Discussion + plan checking + verification enabled ``` If `$DISCUSS_MODE` and `$RESEARCH_MODE` (no validate): ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► QUICK TASK (DISCUSS + RESEARCH) -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► QUICK TASK (DISCUSS + RESEARCH) ◆ Discussion + research enabled ``` If `$RESEARCH_MODE` and `$VALIDATE_MODE` (no discuss): ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► QUICK TASK (RESEARCH + VALIDATE) -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► QUICK TASK (RESEARCH + VALIDATE) ◆ Research + plan checking + verification enabled ``` If `$DISCUSS_MODE` only: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► QUICK TASK (DISCUSS) -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► QUICK TASK (DISCUSS) ◆ Discussion phase enabled — surfacing gray areas before planning ``` If `$RESEARCH_MODE` only: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► QUICK TASK (RESEARCH) -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► QUICK TASK (RESEARCH) ◆ Research phase enabled — investigating approaches before planning ``` If `$VALIDATE_MODE` only: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► QUICK TASK (VALIDATE) -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► QUICK TASK (VALIDATE) ◆ Plan checking + verification enabled ``` diff --git a/gsd-core/workflows/quick/steps/discussion-phase.md b/gsd-core/workflows/quick/steps/discussion-phase.md index 6bc92fc26..8b1e32d40 100644 --- a/gsd-core/workflows/quick/steps/discussion-phase.md +++ b/gsd-core/workflows/quick/steps/discussion-phase.md @@ -4,9 +4,7 @@ Skip this step entirely if NOT `$DISCUSS_MODE`. Display banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► DISCUSSING QUICK TASK -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► DISCUSSING QUICK TASK ◆ Surfacing gray areas for: ${DESCRIPTION} ``` diff --git a/gsd-core/workflows/quick/steps/plan-checker-loop.md b/gsd-core/workflows/quick/steps/plan-checker-loop.md index 1685062a9..3df2d259c 100644 --- a/gsd-core/workflows/quick/steps/plan-checker-loop.md +++ b/gsd-core/workflows/quick/steps/plan-checker-loop.md @@ -4,9 +4,7 @@ Skip this step entirely if NOT `$VALIDATE_MODE`. Display banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► CHECKING PLAN -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► CHECKING PLAN ◆ Spawning plan checker... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze) ``` diff --git a/gsd-core/workflows/quick/steps/quick-verification.md b/gsd-core/workflows/quick/steps/quick-verification.md index 41b1314d6..3f1488f97 100644 --- a/gsd-core/workflows/quick/steps/quick-verification.md +++ b/gsd-core/workflows/quick/steps/quick-verification.md @@ -4,9 +4,7 @@ Skip this step entirely if NOT `$VALIDATE_MODE`. Display banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► VERIFYING RESULTS -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► VERIFYING RESULTS ◆ Spawning verifier... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze) ``` diff --git a/gsd-core/workflows/quick/steps/research-phase.md b/gsd-core/workflows/quick/steps/research-phase.md index ddf164487..ecbfb652d 100644 --- a/gsd-core/workflows/quick/steps/research-phase.md +++ b/gsd-core/workflows/quick/steps/research-phase.md @@ -4,9 +4,7 @@ Skip this step entirely if NOT `$RESEARCH_MODE`. Display banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► RESEARCHING QUICK TASK -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► RESEARCHING QUICK TASK ◆ Investigating approaches for: ${DESCRIPTION} (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze) ``` diff --git a/gsd-core/workflows/resume-project.md b/gsd-core/workflows/resume-project.md index d00719c46..38d48146a 100644 --- a/gsd-core/workflows/resume-project.md +++ b/gsd-core/workflows/resume-project.md @@ -133,17 +133,13 @@ fi Present complete project status to user: ``` -╔══════════════════════════════════════════════════════════════╗ -║ PROJECT STATUS ║ -╠══════════════════════════════════════════════════════════════╣ -║ Building: [one-liner from PROJECT.md "What This Is"] ║ -║ ║ -║ Phase: [X] of [Y] - [Phase name] ║ -║ Plan: [A] of [B] - [Status] ║ -║ Progress: [██████░░░░] XX% ║ -║ ║ -║ Last activity: [date] - [what happened] ║ -╚══════════════════════════════════════════════════════════════╝ +### PROJECT STATUS + +Building: [one-liner from PROJECT.md "What This Is"] +Phase: [X] of [Y] - [Phase name] +Plan: [A] of [B] - [Status] +Progress: [██████░░░░] XX% +Last activity: [date] - [what happened] [If incomplete work found:] ⚠️ Incomplete work detected: diff --git a/gsd-core/workflows/review.md b/gsd-core/workflows/review.md index 20d0576fb..19ed9e458 100644 --- a/gsd-core/workflows/review.md +++ b/gsd-core/workflows/review.md @@ -404,9 +404,7 @@ blocked, not silently redirected** (ADR-2782 D5). Display progress: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► CROSS-AI REVIEW — Phase {N} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► CROSS-AI REVIEW — Phase {N} ◆ Reviewing with {CLI}... done ✓ ◆ Reviewing with {CLI}... done ✓ @@ -507,9 +505,7 @@ gsd_run query commit "docs: cross-AI review for phase {N}" --files {phase_dir}/{ Display summary: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► REVIEW COMPLETE -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► REVIEW COMPLETE Phase {N} reviewed by {count} AI systems. diff --git a/gsd-core/workflows/settings-advanced.md b/gsd-core/workflows/settings-advanced.md index 3c97f5272..c6b98de89 100644 --- a/gsd-core/workflows/settings-advanced.md +++ b/gsd-core/workflows/settings-advanced.md @@ -747,9 +747,7 @@ Never write a tier the user explicitly chose to keep; the existing value must su Display: ```text -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► ADVANCED SETTINGS UPDATED -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► ADVANCED SETTINGS UPDATED | Setting | Value | |--------------------------------------------|-------| diff --git a/gsd-core/workflows/settings-integrations.md b/gsd-core/workflows/settings-integrations.md index a1315e7d1..21e29402b 100644 --- a/gsd-core/workflows/settings-integrations.md +++ b/gsd-core/workflows/settings-integrations.md @@ -302,9 +302,7 @@ Display the masked confirmation table. **No plaintext API keys appear in this output under any circumstance.** ```text -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► INTEGRATIONS UPDATED -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► INTEGRATIONS UPDATED Search Integrations | Field | Value | diff --git a/gsd-core/workflows/settings.md b/gsd-core/workflows/settings.md index 6aa4d00b1..7f406d631 100644 --- a/gsd-core/workflows/settings.md +++ b/gsd-core/workflows/settings.md @@ -606,9 +606,7 @@ Write `~/.gsd/defaults.json` with: Display: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► SETTINGS UPDATED -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► SETTINGS UPDATED | Setting | Value | |----------------------|-------| diff --git a/gsd-core/workflows/ship.md b/gsd-core/workflows/ship.md index b0105d195..055ed18f5 100644 --- a/gsd-core/workflows/ship.md +++ b/gsd-core/workflows/ship.md @@ -571,7 +571,7 @@ Each dispatch is best-effort: if it errors, record a warning and continue — ne ``` -─────────────────────────────────────────────────────────────── +--- ## ✓ Phase {X}: {Name} — Shipped @@ -587,7 +587,7 @@ Next steps: - /gsd:complete-milestone (if last phase in milestone) - /gsd:progress (to see what's next) -─────────────────────────────────────────────────────────────── +--- ``` diff --git a/gsd-core/workflows/sketch-wrap-up.md b/gsd-core/workflows/sketch-wrap-up.md index 3312fc3e1..0b6fa7840 100644 --- a/gsd-core/workflows/sketch-wrap-up.md +++ b/gsd-core/workflows/sketch-wrap-up.md @@ -13,9 +13,7 @@ Read all files referenced by the invoking prompt's execution_context before star ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► SKETCH WRAP-UP -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► SKETCH WRAP-UP ``` @@ -55,17 +53,15 @@ Present each unprocessed sketch in ascending order. For each sketch, show: Then ask the user: -╔══════════════════════════════════════════════════════════════╗ -║ CHECKPOINT: Decision Required ║ -╚══════════════════════════════════════════════════════════════╝ +### CHECKPOINT: Decision Required Sketch {NNN}: {name} — Winner: Variant {X} {key design decisions summary} -────────────────────────────────────────────────────────────── -→ Include / Exclude / Partial / Let me look at it -────────────────────────────────────────────────────────────── +--- + +**→ Include / Exclude / Partial / Let me look at it** **If "Let me look at it":** 1. Provide: `open .planning/sketches/NNN-name/index.html` @@ -239,9 +235,7 @@ gsd_run query commit "docs(sketch-wrap-up): package [N] sketch findings into pro ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► SKETCH WRAP-UP COMPLETE ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► SKETCH WRAP-UP COMPLETE ✓ **Curated:** {N} sketches ({included} included, {excluded} excluded) **Design areas:** {list} @@ -252,7 +246,7 @@ gsd_run query commit "docs(sketch-wrap-up): package [N] sketch findings into pro The sketch-findings skill will auto-load when building the UI. ``` -─────────────────────────────────────────────────────────────── +--- ## ▶ Next Up @@ -260,7 +254,7 @@ The sketch-findings skill will auto-load when building the UI. `/gsd:sketch` (run with no argument — its frontier mode analyzes the sketch landscape and proposes consistency and frontier sketches) -─────────────────────────────────────────────────────────────── +--- **Also available:** - `/gsd:plan-phase` — start building the real UI @@ -268,7 +262,7 @@ The sketch-findings skill will auto-load when building the UI. - `/gsd:sketch [idea]` — sketch a specific new design area - `/gsd:explore` — continue exploring -─────────────────────────────────────────────────────────────── +--- diff --git a/gsd-core/workflows/sketch.md b/gsd-core/workflows/sketch.md index 82623aab7..799d6bc85 100644 --- a/gsd-core/workflows/sketch.md +++ b/gsd-core/workflows/sketch.md @@ -21,9 +21,7 @@ Read all files referenced by the invoking prompt's execution_context before star ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► SKETCHING -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► SKETCHING ``` Parse `$ARGUMENTS` for: @@ -272,9 +270,7 @@ open .planning/sketches/NNN-descriptive-name/index.html **e.** Present to the user with a checkpoint: -╔══════════════════════════════════════════════════════════════╗ -║ CHECKPOINT: Verification Required ║ -╚══════════════════════════════════════════════════════════════╝ +### CHECKPOINT: Verification Required **Sketch {NNN}: {name}** @@ -282,9 +278,9 @@ Open: `open .planning/sketches/NNN-name/index.html` Compare: {what to look for between variants} -────────────────────────────────────────────────────────────── -→ Which variant feels right? Or cherry-pick elements across variants. -────────────────────────────────────────────────────────────── +--- + +**→ Which variant feels right? Or cherry-pick elements across variants.** **f.** Handle feedback: - **Pick a direction:** mark winner, move to next sketch @@ -315,9 +311,7 @@ gsd_run query commit "docs(sketch-NNN): [winning direction] — [key visual insi After all sketches complete: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► SKETCH COMPLETE ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► SKETCH COMPLETE ✓ ## Design Direction {what we landed on overall} @@ -329,7 +323,7 @@ After all sketches complete: {anything unresolved or worth revisiting} ``` -─────────────────────────────────────────────────────────────── +--- ## ▶ Next Up @@ -337,14 +331,14 @@ After all sketches complete: `/gsd:sketch --wrap-up` -─────────────────────────────────────────────────────────────── +--- **Also available:** - `/gsd:sketch` — sketch more (or run with no argument for frontier mode) - `/gsd:plan-phase` — start building the real UI - `/gsd:spike` — spike technical feasibility of a design pattern -─────────────────────────────────────────────────────────────── +--- diff --git a/gsd-core/workflows/smart-entry.md b/gsd-core/workflows/smart-entry.md index 9d00ddd94..1ce6e9cc8 100644 --- a/gsd-core/workflows/smart-entry.md +++ b/gsd-core/workflows/smart-entry.md @@ -93,9 +93,7 @@ Wait for the user's response before continuing. Map the chosen number to the cor **Show the routing decision.** ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► SMART ENTRY -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► SMART ENTRY **Situation:** {situation} **Routing to:** {chosen command} diff --git a/gsd-core/workflows/spike-wrap-up.md b/gsd-core/workflows/spike-wrap-up.md index bdccecaf7..82c59b3ec 100644 --- a/gsd-core/workflows/spike-wrap-up.md +++ b/gsd-core/workflows/spike-wrap-up.md @@ -13,9 +13,7 @@ Read all files referenced by the invoking prompt's execution_context before star ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► SPIKE WRAP-UP -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► SPIKE WRAP-UP ``` @@ -267,9 +265,7 @@ gsd_run query commit "docs(spike-wrap-up): package [N] spike findings into proje ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► SPIKE WRAP-UP COMPLETE ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► SPIKE WRAP-UP COMPLETE ✓ **Processed:** {N} spikes **Feature areas:** {list} @@ -287,7 +283,7 @@ The spike-findings skill will auto-load in future build conversations. After the summary, present next-step options: -─────────────────────────────────────────────────────────────── +--- ## ▶ Next Up @@ -295,7 +291,7 @@ After the summary, present next-step options: `/gsd:spike` (run with no argument — its frontier mode analyzes the spike landscape and proposes integration and frontier spikes) -─────────────────────────────────────────────────────────────── +--- **Also available:** - `/gsd:plan-phase` — start planning the real implementation @@ -303,7 +299,7 @@ After the summary, present next-step options: - `/gsd:explore` — continue exploring - Other -─────────────────────────────────────────────────────────────── +--- diff --git a/gsd-core/workflows/spike.md b/gsd-core/workflows/spike.md index db1def70a..8241d648b 100644 --- a/gsd-core/workflows/spike.md +++ b/gsd-core/workflows/spike.md @@ -20,12 +20,9 @@ RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --default "" 2>/d **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated. - ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► SPIKING -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► SPIKING ``` Parse `$ARGUMENTS` for: @@ -175,15 +172,13 @@ Order by risk — most likely to kill the idea runs first. **If `QUICK_MODE` is true:** Skip. -╔══════════════════════════════════════════════════════════════╗ -║ CHECKPOINT: Decision Required ║ -╚══════════════════════════════════════════════════════════════╝ +### CHECKPOINT: Decision Required {spike table from decompose step} -────────────────────────────────────────────────────────────── -→ Build all in this order, or adjust the list? -────────────────────────────────────────────────────────────── +--- + +**→ Build all in this order, or adjust the list?** @@ -358,17 +353,15 @@ tags: [tag1, tag2] - Self-verifiable: run, iterate if findings warrant deeper investigation, update verdict - Needs human judgment: present checkpoint box: -╔══════════════════════════════════════════════════════════════╗ -║ CHECKPOINT: Verification Required ║ -╚══════════════════════════════════════════════════════════════╝ +### CHECKPOINT: Verification Required **Spike {NNN}: {name}** **How to run:** {command} **What to expect:** {concrete outcomes} -────────────────────────────────────────────────────────────── -→ Does this match what you expected? Describe what you see. -────────────────────────────────────────────────────────────── +--- + +**→ Does this match what you expected? Describe what you see.** **h.** Update `.planning/spikes/MANIFEST.md` with the spike's row, setting the Idea column to this spike's idea key. @@ -390,16 +383,14 @@ Do not rush to a verdict. A spike that says "VALIDATED — it works" with no nua **k.** If core assumption invalidated: -╔══════════════════════════════════════════════════════════════╗ -║ CHECKPOINT: Decision Required ║ -╚══════════════════════════════════════════════════════════════╝ +### CHECKPOINT: Decision Required Core assumption invalidated by Spike {NNN}. {what was invalidated and why} -────────────────────────────────────────────────────────────── -→ Continue with remaining spikes / Pivot approach / Abandon -────────────────────────────────────────────────────────────── +--- + +**→ Continue with remaining spikes / Pivot approach / Abandon** @@ -435,9 +426,7 @@ gsd_run query commit "docs(spikes): update conventions" --files .planning/spikes ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► SPIKE COMPLETE ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► SPIKE COMPLETE ✓ ## Verdicts @@ -456,7 +445,7 @@ gsd_run query commit "docs(spikes): update conventions" --files .planning/spikes {what to use, avoid, watch out for} ``` -─────────────────────────────────────────────────────────────── +--- ## ▶ Next Up @@ -464,14 +453,14 @@ gsd_run query commit "docs(spikes): update conventions" --files .planning/spikes `/gsd:spike --wrap-up` -─────────────────────────────────────────────────────────────── +--- **Also available:** - `/gsd:spike` — spike more ideas (or run with no argument for frontier mode) - `/gsd:plan-phase` — start planning the real implementation - `/gsd:explore` — continue exploring the idea -─────────────────────────────────────────────────────────────── +--- diff --git a/gsd-core/workflows/thread.md b/gsd-core/workflows/thread.md index deeed8c20..6fce00545 100644 --- a/gsd-core/workflows/thread.md +++ b/gsd-core/workflows/thread.md @@ -42,12 +42,14 @@ Apply filter for LIST-OPEN (show only status=open or status=in_progress) or LIST Display: ``` Context Threads -───────────────────────────────────────────────────────── + +--- slug status updated title auth-decision open 2026-04-09 OAuth vs Session tokens db-schema-v2 in_progress 2026-04-07 Connection pool sizing frontend-build-tools resolved 2026-04-01 Vite vs webpack -───────────────────────────────────────────────────────── + +--- 3 threads (2 open/in_progress, 1 resolved) ``` @@ -96,7 +98,8 @@ When SUBCMD=status and SLUG is set (already sanitized): 2. Read the file and display a summary: ``` Thread: {SLUG} - ───────────────────────────────────── + +--- Title: {title from frontmatter or # heading} Status: {status from frontmatter or ## Status heading} Updated: {updated from frontmatter} @@ -107,7 +110,8 @@ When SUBCMD=status and SLUG is set (already sanitized): Next Steps: {content of ## Next Steps section} - ───────────────────────────────────── + +--- Resume with: /gsd:thread {SLUG} Close with: /gsd:thread close {SLUG} ``` diff --git a/gsd-core/workflows/ui-phase.md b/gsd-core/workflows/ui-phase.md index 9fd8df446..2cd4e8e17 100644 --- a/gsd-core/workflows/ui-phase.md +++ b/gsd-core/workflows/ui-phase.md @@ -115,9 +115,7 @@ If "Update": continue to step 5. Display: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► UI DESIGN CONTRACT — PHASE {N} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► UI DESIGN CONTRACT — PHASE {N} ◆ Spawning UI researcher... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze) ``` @@ -188,9 +186,7 @@ Display blocker details and options. Exit workflow. Display: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► VERIFYING UI-SPEC -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► VERIFYING UI-SPEC ◆ Spawning UI checker... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze) ``` @@ -423,16 +419,14 @@ STATE coverage and REFERENCES those rows rather than restating the copy (de-dup) Display: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► UI-SPEC READY ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► UI-SPEC READY ✓ **Phase {N}: {Name}** — UI design contract approved Dimensions: 7/7 passed {If any FLAGs: "Recommendations: {N} (non-blocking)"} -─────────────────────────────────────────────────────────────── +--- ## ▶ Next Up — [${PROJECT_CODE}] ${PROJECT_TITLE} @@ -448,7 +442,7 @@ Dimensions: 7/7 passed (or `/gsd:plan-phase {N}` to skip discussion) -─────────────────────────────────────────────────────────────── +--- ``` ## 11. Commit (if configured) diff --git a/gsd-core/workflows/ui-review.md b/gsd-core/workflows/ui-review.md index c0c376f36..b3bf810d7 100644 --- a/gsd-core/workflows/ui-review.md +++ b/gsd-core/workflows/ui-review.md @@ -33,9 +33,7 @@ UI_AUDITOR_MODEL=$(gsd_run query resolve-model gsd-ui-auditor --raw) Display banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► UI AUDIT — PHASE {N}: {name} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► UI AUDIT — PHASE {N}: {name} ``` ## 1. Detect Input State @@ -127,9 +125,7 @@ Agent( Display score summary: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► UI AUDIT COMPLETE ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► UI AUDIT COMPLETE ✓ **Phase {N}: {Name}** — Overall: {score}/24 @@ -149,7 +145,7 @@ Top fixes: Full review: {path to UI-REVIEW.md} -─────────────────────────────────────────────────────────────── +--- ## ▶ Next @@ -157,7 +153,7 @@ Full review: {path to UI-REVIEW.md} - `/gsd:verify-work {N}` — UAT testing before phase completion -─────────────────────────────────────────────────────────────── +--- ``` ## Automated UI Verification (when Playwright-MCP is available) diff --git a/gsd-core/workflows/ultraplan-phase.md b/gsd-core/workflows/ultraplan-phase.md index 8960fd8e2..835e64795 100644 --- a/gsd-core/workflows/ultraplan-phase.md +++ b/gsd-core/workflows/ultraplan-phase.md @@ -13,9 +13,7 @@ affect the core planning pipeline. Display the stage banner: ```text -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► ULTRAPLAN PHASE ⚠ BETA -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► ULTRAPLAN PHASE ⚠ BETA Ultraplan is in research preview (Claude Code v2.1.91+). Use /gsd:plan-phase for stable local planning. ``` @@ -44,9 +42,7 @@ fi If the output is empty or unset, display the following error and exit: ```text -╔══════════════════════════════════════════════════════════════╗ -║ RUNTIME ERROR ║ -╚══════════════════════════════════════════════════════════════╝ +### RUNTIME ERROR /gsd:ultraplan-phase requires Claude Code. ultraplan is not available in this runtime. @@ -159,9 +155,7 @@ Display the return-path instructions **before** triggering ultraplan so they are in the terminal scroll-back after ultraplan launches: ```text -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - WHEN THE PLAN IS READY — WHAT TO DO -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### WHEN THE PLAN IS READY — WHAT TO DO When ◆ ultraplan ready appears in your terminal: @@ -176,9 +170,7 @@ When ◆ ultraplan ready appears in your terminal: /gsd:import will run conflict detection, convert to GSD format, validate via plan-checker, update ROADMAP.md, and commit. -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -Launching ultraplan for Phase {N}: {phase_name}... -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### Launching ultraplan for Phase {N}: {phase_name}... ``` diff --git a/gsd-core/workflows/undo.md b/gsd-core/workflows/undo.md index 14d5f7541..ad4717b31 100644 --- a/gsd-core/workflows/undo.md +++ b/gsd-core/workflows/undo.md @@ -15,14 +15,11 @@ RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --default "" 2>/d **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated. - Display the stage banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► UNDO -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► UNDO ``` @@ -70,7 +67,6 @@ Recent GSD commits: 3. ghi9012 fix(02-03): correct validation logic ``` - **Text mode (`workflow.text_mode: true` in config or `--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available. Use AskUserQuestion to ask: - question: "Which commits to revert? Enter numbers (e.g., 1,3) or 'all'" @@ -237,9 +233,7 @@ If any revert fails (merge conflict or error): ``` 3. Display: ``` - ╔══════════════════════════════════════════════════════════════╗ - ║ ERROR ║ - ╚══════════════════════════════════════════════════════════════╝ +### ERROR Revert failed on commit ${HASH}. Likely cause: merge conflict with subsequent changes. @@ -271,9 +265,7 @@ git commit -m "revert: undo ${N} selected commits — ${REVERT_REASON}" Display the completion banner: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► UNDO COMPLETE ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► UNDO COMPLETE ✓ ``` Show summary: @@ -284,7 +276,7 @@ Show summary: Show next steps: ``` -─────────────────────────────────────────────────────────────── +--- ## ▶ Next Up — [${PROJECT_CODE}] ${PROJECT_TITLE} @@ -294,13 +286,13 @@ Show next steps: /gsd:progress -─────────────────────────────────────────────────────────────── +--- **Also available:** - `/gsd:execute-phase ${PHASE}` — re-execute if needed - `/gsd:undo --last 1` — undo the revert itself if something went wrong -─────────────────────────────────────────────────────────────── +--- ``` diff --git a/gsd-core/workflows/update.md b/gsd-core/workflows/update.md index 7b1c44e09..76805bede 100644 --- a/gsd-core/workflows/update.md +++ b/gsd-core/workflows/update.md @@ -9,7 +9,6 @@ Read all files referenced by the invoking prompt's execution_context before star **If `response_language` is configured:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in that language. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated. - Detect the installed GSD version, scope, runtime, and config dir. @@ -253,11 +252,12 @@ rm -f "$CHANGELOG_TMP" **Latest:** {LATEST_VERSION} ### What's New -──────────────────────────────────────────────────────────── + +--- {CHANGELOG_PREVIEW} -──────────────────────────────────────────────────────────── +--- ⚠️ **Note:** The installer performs a clean install of GSD folders: - `commands/gsd/` will be wiped and replaced @@ -277,7 +277,6 @@ Your custom files in other locations are preserved: If you've modified any GSD files directly, they'll be automatically backed up to `gsd-local-patches/` and can be reapplied with `/gsd:update --reapply` after the update. ``` - **Text mode (`workflow.text_mode: true` in config or `--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available. Use AskUserQuestion: - Question: "Proceed with update?" @@ -480,9 +479,7 @@ The SessionStart hook (`gsd-check-update.js`) writes to the detected runtime's c Format completion message (changelog was already shown in confirmation step): ``` -╔═══════════════════════════════════════════════════════════╗ -║ GSD Updated: v1.5.10 → v1.5.15 ║ -╚═══════════════════════════════════════════════════════════╝ +### GSD Updated: v1.5.10 → v1.5.15 ⚠️ Restart your runtime to pick up the new commands. @@ -490,7 +487,6 @@ Format completion message (changelog was already shown in confirmation step): ``` - `backup_custom_files` copied user-added files into `gsd-user-files-backup/` before the wipe. Offer to put them back — now, against the release that was diff --git a/gsd-core/workflows/verify-work.md b/gsd-core/workflows/verify-work.md index eeae64bed..13656de97 100644 --- a/gsd-core/workflows/verify-work.md +++ b/gsd-core/workflows/verify-work.md @@ -649,9 +649,12 @@ Parse the JSON output. For the CURRENT PHASE ONLY, surface: If any are found, display: ``` Phase {N} Artifact Check -───────────────────────────────────────────────── + +--- + {list each item with status and file path} -───────────────────────────────────────────────── + +--- These items are open. Proceed anyway? [Y/n] ``` @@ -687,9 +690,7 @@ Diagnosis runs automatically - no user prompt. Parallel agents investigate simul Display: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► PLANNING FIXES -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► PLANNING FIXES ◆ Spawning planner for gap closure... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze) ``` @@ -754,9 +755,7 @@ On return: Display: ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► VERIFYING FIX PLANS -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► VERIFYING FIX PLANS ◆ Spawning plan checker... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze) ``` @@ -860,9 +859,7 @@ Wait for user response. **Present completion and next steps:** ``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - GSD ► FIXES READY ✓ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +### GSD ► FIXES READY ✓ **Phase {X}: {Name}** — {N} gap(s) diagnosed, {M} fix plan(s) created @@ -873,7 +870,7 @@ Wait for user response. Plans verified and ready for execution. -─────────────────────────────────────────────────────────────── +--- ## ▶ Next Up — [${PROJECT_CODE}] ${PROJECT_TITLE} @@ -881,7 +878,7 @@ Plans verified and ready for execution. `/clear` then `/gsd:execute-phase {phase} --gaps-only` -─────────────────────────────────────────────────────────────── +--- ``` diff --git a/skills/gsd-quick/SKILL.md b/skills/gsd-quick/SKILL.md index 157f9dc0d..e1194f703 100644 --- a/skills/gsd-quick/SKILL.md +++ b/skills/gsd-quick/SKILL.md @@ -86,12 +86,14 @@ For each directory found: Display format: ``` Quick Tasks -──────────────────────────────────────────────────────────── + +--- slug date status backup-s3-policy 2026-04-10 in-progress auth-token-refresh-fix 2026-04-09 complete ✓ update-node-deps 2026-04-08 abandoned? (>7 days, no summary) -──────────────────────────────────────────────────────────── + +--- 3 tasks (1 complete, 2 incomplete/in-progress) ``` @@ -113,12 +115,14 @@ If no directory found, print `No quick task found with slug: {SLUG}` and stop. Read PLAN.md and SUMMARY.md (if exists) for the given slug. Display: ``` Quick Task: {slug} -───────────────────────────────────── + +--- Plan file: .planning/quick/{dir}/PLAN.md Status: {status from SUMMARY.md frontmatter, or "no summary yet"} Description: {first non-empty line from PLAN.md after frontmatter} Last action: {last meaningful line of SUMMARY.md, or "none"} -───────────────────────────────────── + +--- Resume with: /gsd-quick resume {slug} ``` diff --git a/src/audit.cts b/src/audit.cts index 71dcfdf56..71b08ea89 100644 --- a/src/audit.cts +++ b/src/audit.cts @@ -1330,11 +1330,8 @@ function auditOpenArtifacts(cwd: string): AuditResult { function formatAuditReport(auditResult: AuditResult): string { const { counts, items, has_open_items, acknowledged } = auditResult; const lines: string[] = []; - const hr = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'; - lines.push(hr); - lines.push(' Milestone Close: Open Artifact Audit'); - lines.push(hr); + lines.push('### Milestone Close: Open Artifact Audit'); // WARNING 3 (#3458 follow-up review): the acknowledged tally previously // existed only in `--json` output — the human report could not tell @@ -1343,12 +1340,12 @@ function formatAuditReport(auditResult: AuditResult): string { if (!has_open_items) { lines.push(''); if (acknowledged.total > 0) { - lines.push(` All artifact types clear (${acknowledged.total} previously acknowledged item${acknowledged.total !== 1 ? 's' : ''} still suppressed).`); + lines.push(`All artifact types clear (${acknowledged.total} previously acknowledged item${acknowledged.total !== 1 ? 's' : ''} still suppressed).`); } else { - lines.push(' All artifact types clear. Safe to proceed.'); + lines.push('All artifact types clear. Safe to proceed.'); } lines.push(''); - lines.push(hr); + lines.push('---'); return lines.join('\n'); } @@ -1459,12 +1456,12 @@ function formatAuditReport(auditResult: AuditResult): string { } lines.push(''); - lines.push(hr); - lines.push(` ${counts.total} item${counts.total !== 1 ? 's' : ''} require decisions before close.`); + lines.push('---'); + lines.push(''); + lines.push(`**${counts.total} item${counts.total !== 1 ? 's' : ''} require decisions before close.**`); if (acknowledged.total > 0) { - lines.push(` ${acknowledged.total} previously acknowledged item${acknowledged.total !== 1 ? 's' : ''} also suppressed above the ${counts.total} open item${counts.total !== 1 ? 's' : ''}.`); + lines.push(`${acknowledged.total} previously acknowledged item${acknowledged.total !== 1 ? 's' : ''} also suppressed above the ${counts.total} open item${counts.total !== 1 ? 's' : ''}.`); } - lines.push(hr); return lines.join('\n'); } diff --git a/src/check-command-router.cts b/src/check-command-router.cts index 47db5aa06..e6f5e2227 100644 --- a/src/check-command-router.cts +++ b/src/check-command-router.cts @@ -890,7 +890,6 @@ function cmdTddReviewCheckpoint(projectDir: string, args: string[], raw: boolean const violations = rows.filter(r => r.status === 'FAIL').length; // Build review table - const sep = '━'.repeat(53); const tableHeader = '| Plan | RED | GREEN | REFACTOR | Status |'; const tableDivider = '|------|-----|-------|----------|--------|'; const tableRows = rows.map(r => @@ -898,9 +897,7 @@ function cmdTddReviewCheckpoint(projectDir: string, args: string[], raw: boolean ); let table = [ - sep, - ` TDD REVIEW — Phase ${phase}`, - sep, + `### TDD REVIEW — Phase ${phase}`, '', `TDD Plans: ${tddPlanFiles.length} | Gate violations: ${violations}`, '', diff --git a/src/uat.cts b/src/uat.cts index 1c9f6c977..5f3d73922 100644 --- a/src/uat.cts +++ b/src/uat.cts @@ -421,8 +421,6 @@ interface CheckpointFrame { direction?: 'rtl'; } -const CHECKPOINT_BOX_WIDTH = 64; // total column width of the ╔══...╗ border, borders stay byte-identical - const CHECKPOINT_FRAMES: Record = { english: { banner: 'CHECKPOINT: Verification Required', @@ -529,56 +527,6 @@ function resolveCheckpointFrame(responseLanguage: string | undefined): Checkpoin return (key && CHECKPOINT_FRAMES[key]) || CHECKPOINT_FRAMES.english; } -// Approximate terminal-cell width. East Asian Width W/F code points occupy two -// cells, while Unicode combining marks occupy no additional cell beyond their -// base character. Counting only W/F ranges is insufficient for scripts such as -// Devanagari: Hindi vowel signs and viramas are combining marks, and treating -// each as a full cell visibly shifts the checkpoint box's right border. -function isWideCodePoint(codePoint: number): boolean { - return ( - (codePoint >= 0x1100 && codePoint <= 0x115f) || // Hangul Jamo - codePoint === 0x2329 || codePoint === 0x232a || - (codePoint >= 0x2e80 && codePoint <= 0x303e) || // CJK Radicals .. CJK Symbols and Punctuation - (codePoint >= 0x3041 && codePoint <= 0x33ff) || // Hiragana .. CJK Compatibility - (codePoint >= 0x3400 && codePoint <= 0x4dbf) || // CJK Unified Ideographs Extension A - (codePoint >= 0x4e00 && codePoint <= 0x9fff) || // CJK Unified Ideographs - (codePoint >= 0xa000 && codePoint <= 0xa4cf) || // Yi Syllables - (codePoint >= 0xac00 && codePoint <= 0xd7a3) || // Hangul Syllables - (codePoint >= 0xf900 && codePoint <= 0xfaff) || // CJK Compatibility Ideographs - (codePoint >= 0xfe30 && codePoint <= 0xfe4f) || // CJK Compatibility Forms - (codePoint >= 0xff00 && codePoint <= 0xff60) || // Fullwidth Forms - (codePoint >= 0xffe0 && codePoint <= 0xffe6) || - (codePoint >= 0x20000 && codePoint <= 0x3fffd) // CJK Unified Ideographs Extension B+ / supplementary - ); -} - -// Non-spacing/enclosing marks and format controls occupy zero terminal cells. -// Spacing combining marks (General_Category=Mc), such as Devanagari vowel -// signs, still advance the cursor and must contribute one column. -const ZERO_WIDTH_MARK_RE = /\p{gc=Mn}|\p{gc=Me}|\p{gc=Cf}/u; - -// Iterates by Unicode code point (not UTF-16 code unit) so astral characters -// are measured once, not as two surrogate units. -function displayWidth(text: string): number { - let width = 0; - for (const ch of text) { - if (ZERO_WIDTH_MARK_RE.test(ch)) continue; - width += isWideCodePoint(ch.codePointAt(0) as number) ? 2 : 1; - } - return width; -} - -// Pads `text` into a `║ text… ║` line matching CHECKPOINT_BOX_WIDTH. Content -// that overflows the box (a longer translated string) is left unpadded rather -// than truncated — a slightly ragged border beats losing text. -function checkpointBoxLine(text: string): string { - const innerWidth = CHECKPOINT_BOX_WIDTH - 2; - const content = ` ${text}`; - const padLength = innerWidth - displayWidth(content); - const padded = padLength > 0 ? content + ' '.repeat(padLength) : content; - return `║${padded}║`; -} - const RTL_ISOLATE = '\u2067'; const POP_DIRECTIONAL_ISOLATE = '\u2069'; @@ -593,17 +541,15 @@ function buildCheckpoint(currentTest: { number: number; name: string; expected: const banner = isolateCheckpointFrameText(frame.banner, frame); const instruction = isolateCheckpointFrameText(frame.instruction, frame); return [ - '╔══════════════════════════════════════════════════════════════╗', - checkpointBoxLine(banner), - '╚══════════════════════════════════════════════════════════════╝', + `### ${banner}`, '', `**Test ${currentTest.number}: ${currentTest.name}**`, '', currentTest.expected, '', - '──────────────────────────────────────────────────────────────', - instruction, - '──────────────────────────────────────────────────────────────', + '---', + '', + `**${instruction}**`, ].join('\n'); } @@ -1676,7 +1622,6 @@ export = { CHECKPOINT_FRAMES, CHECKPOINT_LANGUAGE_ALIASES, resolveCheckpointFrame, - checkpointBoxLine, parseDeferredItems, parseDeferredItemsWithStatus, acknowledgeDeferredItem, diff --git a/tests/audit-command-cutover.test.cjs b/tests/audit-command-cutover.test.cjs index 92c6cc37c..c560e4795 100644 --- a/tests/audit-command-cutover.test.cjs +++ b/tests/audit-command-cutover.test.cjs @@ -238,8 +238,8 @@ describe('audit cutover: output shape equivalence', () => { `audit-open must succeed. stderr: ${result.error}`); const lines = result.output.split('\n').map(l => l.trim()).filter(Boolean); assert.ok( - lines.includes('Milestone Close: Open Artifact Audit'), - `report title must appear as a standalone line; got: ${JSON.stringify(lines.slice(0, 5))}`, + lines.includes('### Milestone Close: Open Artifact Audit'), + `report title must appear as a standalone Markdown heading line; got: ${JSON.stringify(lines.slice(0, 5))}`, ); }); @@ -481,7 +481,7 @@ describe('audit-open — does not crash with ReferenceError (#2659)', () => { * 2. Even after switching to `core.output(formatted, raw)`, the human-readable * branch JSON-stringifies the formatted string because `core.output` only * bypasses JSON encoding when called as `core.output(null, true, rawValue)`. - * Result: stdout contains `"━━━…\n Milestone Close: …\n…"` (a JSON string + * Result: stdout contains `"### Milestone Close: …\n…"` (a JSON string * literal) instead of the rendered report. * * The shape assertions below catch both regressions structurally — never via @@ -640,10 +640,10 @@ describe('audit-open — output shape (#2911)', () => { const lines = result.output.split('\n').map(l => l.trim()).filter(Boolean); - // The first non-empty line must be the divider character row, *not* a - // JSON-encoded string starting with a quote. If core.output JSON-stringified + // The first non-empty line must be the rendered Markdown heading row, *not* + // a JSON-encoded string starting with a quote. If core.output JSON-stringified // the formatted report, the entire payload sits on one line wrapped in - // double quotes ("━━━…\n…"). + // double quotes ("### Milestone Close: …\n…"). assert.ok( !result.output.startsWith('"'), 'text-mode stdout must not begin with a JSON quote (would mean the report was JSON.stringified)' @@ -655,8 +655,8 @@ describe('audit-open — output shape (#2911)', () => { // Section headers from formatAuditReport that must appear as standalone lines. assert.ok( - lines.includes('Milestone Close: Open Artifact Audit'), - `expected report title as a standalone line; got lines: ${JSON.stringify(lines.slice(0, 5))}` + lines.includes('### Milestone Close: Open Artifact Audit'), + `expected report title as a standalone Markdown heading line; got lines: ${JSON.stringify(lines.slice(0, 5))}` ); assert.ok( lines.includes('All artifact types clear. Safe to proceed.'), diff --git a/tests/emitted-drift-acks/3370-execute-phase-gate-conflation.json b/tests/emitted-drift-acks/3370-execute-phase-gate-conflation.json index 7d404c976..2a3c7122e 100644 --- a/tests/emitted-drift-acks/3370-execute-phase-gate-conflation.json +++ b/tests/emitted-drift-acks/3370-execute-phase-gate-conflation.json @@ -1,6 +1,6 @@ { "version": 1, "paths": { - "execute-plan.md": "#3370: the Pattern A dispatch prompt spec gained the gate-semantics clause (gate=\"blocking\" (the default) is auto-approvable in auto-mode per the executor's own checkpoint protocol, gate=\"blocking-human\" always surfaces to a human; add no instruction overriding that protocol), closing the identically-shaped dispatch-time gap on the single-plan path named in the issue. Growth ~248 bytes (38913 -> 39161, still under the DEFAULT 40 KiB ceiling). Supersedes the spent #2652 fragment (merged into next), which also named execute-plan.md and would otherwise double-ack the same path. #3659 appends --mode \"$ISOLATION\" to the #2649 pre-dispatch base-check and corrects the baseRef restore-advice to the orchestrator/harness split (+154B; the harness does not read baseRef, #48). Deliberate growth. — #3299 append: the tracer feedback gate's interactive branch, which read `Interactive: STOP -> return a checkpoint:human-verify` and keyed on auto-mode alone, now branches on HUMAN_VERIFY_MODE — under the documented `end-of-phase` default an automated-only tracer `` is re-run and continues to expansion with no checkpoint. Growth is 796 bytes (39315 -> 40111, still under the DEFAULT_CAP of 40960 LF bytes, 849 bytes of headroom; the earlier 39161 -> 39957 / 1003 figures were measured before the 2026-08-22 merge of next and are superseded): that branch plus a `HUMAN_VERIFY_MODE=` read alongside the existing RUNTIME/USE_WORKTREES reads in parse_segments. The read carries an explicit `--default end-of-phase` because `workflow.human_verify_mode` is absent from SCHEMA_DEFAULTS (src/config.cts): a bare config-get exits non-zero with `Key not found` on any project whose config.json predates #3309, which is every pre-existing project and the reporter's exact config. The three carve-outs (``, `gate=\"blocking-human\"`, `mid-flight`) are stated inline here rather than delegated to gsd-core/references/dispatch-isolation-gate.md, because this file is the inline dispatch path used for step-by-step / non-Claude-Code execution, where agents/gsd-executor.md is never loaded. This entry carries #3370's own reason forward verbatim above rather than replacing it — that growth is in the base and still needs its account. The blocking-human STOP is evaluated BEFORE the auto-mode branch here, matching golden rule 6 in checkpoints.md — the earlier ordering let an autonomous run continue past a blocking-human tracer." + "execute-plan.md": "#3370: the Pattern A dispatch prompt spec gained the gate-semantics clause (gate=\"blocking\" (the default) is auto-approvable in auto-mode per the executor's own checkpoint protocol, gate=\"blocking-human\" always surfaces to a human; add no instruction overriding that protocol), closing the identically-shaped dispatch-time gap on the single-plan path named in the issue. Growth ~248 bytes (38913 -> 39161, still under the DEFAULT 40 KiB ceiling). Supersedes the spent #2652 fragment (merged into next), which also named execute-plan.md and would otherwise double-ack the same path. #3659 appends --mode \"$ISOLATION\" to the #2649 pre-dispatch base-check and corrects the baseRef restore-advice to the orchestrator/harness split (+154B; the harness does not read baseRef, #48). Deliberate growth. — #3299 append: the tracer feedback gate's interactive branch, which read `Interactive: STOP -> return a checkpoint:human-verify` and keyed on auto-mode alone, now branches on HUMAN_VERIFY_MODE — under the documented `end-of-phase` default an automated-only tracer `` is re-run and continues to expansion with no checkpoint. Growth is 796 bytes (39315 -> 40111, still under the DEFAULT_CAP of 40960 LF bytes, 849 bytes of headroom; the earlier 39161 -> 39957 / 1003 figures were measured before the 2026-08-22 merge of next and are superseded): that branch plus a `HUMAN_VERIFY_MODE=` read alongside the existing RUNTIME/USE_WORKTREES reads in parse_segments. The read carries an explicit `--default end-of-phase` because `workflow.human_verify_mode` is absent from SCHEMA_DEFAULTS (src/config.cts): a bare config-get exits non-zero with `Key not found` on any project whose config.json predates #3309, which is every pre-existing project and the reporter's exact config. The three carve-outs (``, `gate=\"blocking-human\"`, `mid-flight`) are stated inline here rather than delegated to gsd-core/references/dispatch-isolation-gate.md, because this file is the inline dispatch path used for step-by-step / non-Claude-Code execution, where agents/gsd-executor.md is never loaded. This entry carries #3370's own reason forward verbatim above rather than replacing it — that growth is in the base and still needs its account. The blocking-human STOP is evaluated BEFORE the auto-mode branch here, matching golden rule 6 in checkpoints.md — the earlier ordering let an autonomous run continue past a blocking-human tracer. — #3028 append: the checkpoint_protocol step's one-line display spec described the old drawn box (`CHECKPOINT: [Type]` box … `YOUR ACTION: [signal]`). Under #3028 a checkpoint is a `### CHECKPOINT: [Type]` heading, a `---` break and a bolded action prompt, so the spec now reads `### CHECKPOINT: [Type]` heading → Progress {X}/{Y} → Task name → type-specific content → `---` → `**YOUR ACTION: [signal]**`. Growth is 22 bytes (40111 -> 40133, still under the DEFAULT_CAP of 40960 LF bytes, 827 bytes of headroom) — the naming of the two new Markdown tokens and the heading marker. Appended here rather than filed as a new fragment because a growth ack keys on the BARE FILENAME and #3370 already declares `execute-plan.md`; two sources naming one path is a hard duplicate-key error, so this follows the same supersede-by-append route #3370 itself took for the spent #2652 fragment. Every other file this change touches SHRANK, which needs no acknowledgment." } } diff --git a/tests/responsive-separators.test.cjs b/tests/responsive-separators.test.cjs new file mode 100644 index 000000000..be9867c5b --- /dev/null +++ b/tests/responsive-separators.test.cjs @@ -0,0 +1,297 @@ +// Guards the responsive-separator convention defined in +// gsd-core/references/ui-brand.md § "Separators and Banners". +// +// Shipped content (gsd-core/, agents/, commands/) is runtime-loaded text: an +// agent reads it and emits the banners it describes. A fixed-width run of +// box-drawing characters is ordinary text to a Markdown-rendering host, so in a +// narrower pane it wraps and leaves orphan glyphs on a second line, coming apart +// from the heading it was meant to frame. Markdown headings and thematic breaks +// adapt to the available width instead. +// +// Enhancement for https://github.com/open-gsd/gsd-core/issues/3028. +// +// SCOPE - deliberately narrow, see the negative-space cases below: +// * A "rule line" is a line whose trimmed content is composed ENTIRELY of +// U+2500, U+2501 or U+2550, three or more of them. Tree glyphs, boxed-table +// rows, progress bars and inline art all carry other characters and are +// never flagged. +// * A "panel character" is one of U+2554 U+2557 U+255A U+255D U+2551 anywhere +// on a line. +// * docs/ is NOT scanned: a documentation page may legitimately quote the old +// form while explaining the change. src/ is not scanned either - its +// section-divider comments are read in an editor, never emitted. + +const { describe, test, afterEach } = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('fs'); +const path = require('path'); +const fc = require('fast-check'); +const { createTempDir, cleanup } = require('./helpers.cjs'); + +const REPO_ROOT = path.join(__dirname, '..'); + +// Runtime-loaded text: an agent reads these and emits what they describe. +const SHIPPED_ROOTS = ['gsd-core', 'agents', 'commands']; + +// A shorter run than MIN_RULE_RUN is a glyph fragment, not a rule. +const MIN_RULE_RUN = 3; +const RULE_LINE_RE = /^[─━═]{3,}$/; + +// Double-line box vocabulary only. Single-line characters (└ ├ │ ...) are +// deliberately absent: they are legitimate tree glyphs, not panel borders. +const PANEL_CHAR_RE = /[╔╗╚╝║╠╣╦╩╬]/; + +const HEAVY = '━'; +const LIGHT = '─'; +const DOUBLE = '═'; + +// `trim()` also strips a trailing \r, so CRLF files are handled without a +// separate newline split dialect. +function isFixedWidthRuleLine(line) { + return RULE_LINE_RE.test(line.trim()); +} + +function hasPanelCharacter(line) { + return PANEL_CHAR_RE.test(line); +} + +function findMarkdownFiles(dir) { + const out = []; + let entries; + try { + entries = fs.readdirSync(dir, { withFileTypes: true }); + } catch (err) { + if (err.code === 'ENOENT') return out; + throw err; + } + for (const entry of entries) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) { + out.push(...findMarkdownFiles(full)); + } else if (entry.isFile() && entry.name.endsWith('.md')) { + out.push(full); + } + } + return out; +} + +function shippedMarkdownFiles() { + const files = []; + for (const root of SHIPPED_ROOTS) { + files.push(...findMarkdownFiles(path.join(REPO_ROOT, root))); + } + return files; +} + +function scan(files, predicate) { + const violations = []; + for (const filePath of files) { + const content = fs.readFileSync(filePath, 'utf-8'); + const lines = content.split(/\r?\n/); + for (let i = 0; i < lines.length; i++) { + if (predicate(lines[i])) { + violations.push( + `${path.relative(REPO_ROOT, filePath)}:${i + 1}: ${lines[i].trim().slice(0, 40)}` + ); + } + } + } + return violations; +} + +const REMEDY = + '\n\nPer gsd-core/references/ui-brand.md "Separators and Banners":\n' + + ' - a stage banner is an ATX heading with no rule lines;\n' + + ' - a panel becomes a heading followed by its rows as plain lines;\n' + + ' - a divider between sections is --- with a blank line above and below.\n' + + 'A fixed-width run wraps in a narrow pane and comes apart from its heading.\n' + + 'See https://github.com/open-gsd/gsd-core/issues/3028'; + +describe('responsive-separators', () => { + const tmpDirs = []; + afterEach(() => { + while (tmpDirs.length) cleanup(tmpDirs.pop()); + }); + + function tempFile(name, content) { + const dir = createTempDir('responsive-separators'); + tmpDirs.push(dir); + const filePath = path.join(dir, name); + fs.writeFileSync(filePath, content, 'utf-8'); + return filePath; + } + + test('the shipped-content walk actually finds files', () => { + const files = shippedMarkdownFiles(); + // Without this the two repo-wide scans below would pass vacuously if the + // roots were ever renamed out from under them. + assert.ok( + files.length > 100, + `expected the shipped roots (${SHIPPED_ROOTS.join(', ')}) to hold markdown, found ${files.length}` + ); + for (const root of SHIPPED_ROOTS) { + assert.ok( + files.some((f) => f.startsWith(path.join(REPO_ROOT, root) + path.sep)), + `no markdown found under shipped root "${root}"` + ); + } + }); + + test('no shipped content emits a fixed-width rule line', () => { + const violations = scan(shippedMarkdownFiles(), isFixedWidthRuleLine); + assert.deepStrictEqual( + violations, + [], + 'Fixed-width box-drawing rule lines found in shipped content:\n' + + violations.map((v) => ` - ${v}`).join('\n') + + REMEDY + ); + }); + + test('no shipped content emits box-panel characters', () => { + const violations = scan(shippedMarkdownFiles(), hasPanelCharacter); + assert.deepStrictEqual( + violations, + [], + 'Box-panel characters found in shipped content:\n' + + violations.map((v) => ` - ${v}`).join('\n') + + REMEDY + ); + }); + + test(`run of ${MIN_RULE_RUN - 1} is not a rule (limit-1)`, () => { + assert.equal(isFixedWidthRuleLine(HEAVY.repeat(MIN_RULE_RUN - 1)), false); + assert.equal(isFixedWidthRuleLine(LIGHT.repeat(MIN_RULE_RUN - 1)), false); + assert.equal(isFixedWidthRuleLine(DOUBLE.repeat(MIN_RULE_RUN - 1)), false); + }); + + test(`run of ${MIN_RULE_RUN} is a rule (limit)`, () => { + assert.equal(isFixedWidthRuleLine(HEAVY.repeat(MIN_RULE_RUN)), true); + assert.equal(isFixedWidthRuleLine(LIGHT.repeat(MIN_RULE_RUN)), true); + assert.equal(isFixedWidthRuleLine(DOUBLE.repeat(MIN_RULE_RUN)), true); + }); + + test(`run of ${MIN_RULE_RUN + 1} is a rule (limit+1)`, () => { + assert.equal(isFixedWidthRuleLine(HEAVY.repeat(MIN_RULE_RUN + 1)), true); + }); + + test('run of 1 is not a rule', () => { + assert.equal(isFixedWidthRuleLine(HEAVY), false); + }); + + test('lines that merely contain box-drawing glyphs are not rules', () => { + const notRules = [ + '└── file.md', + '├── dir/', + '├────┼────┤', + 'Progress: ████░░ 80%', + '| --- | --- |', + '---', + '### GSD ► EXECUTING WAVE 8', + '', + ' \t ', + `a${HEAVY.repeat(3)}`, + `${HEAVY.repeat(3)}a`, + ]; + for (const line of notRules) { + assert.equal( + isFixedWidthRuleLine(line), + false, + `should not be a rule: ${JSON.stringify(line)}` + ); + } + }); + + test('an indented rule line is still a rule', () => { + assert.equal(isFixedWidthRuleLine(` ${HEAVY.repeat(4)} `), true); + assert.equal(isFixedWidthRuleLine(`\t${LIGHT.repeat(3)}\t`), true); + }); + + test('mixed rule characters still count as a rule', () => { + assert.equal(isFixedWidthRuleLine(`${LIGHT}${LIGHT}${LIGHT}${HEAVY}${HEAVY}${DOUBLE}`), true); + }); + + test('panel characters are detected anywhere on the line', () => { + assert.equal(hasPanelCharacter('╔══╗'), true); + assert.equal(hasPanelCharacter('║ CHECKPOINT: Verification Required ║'), true); + assert.equal(hasPanelCharacter('╚══╝'), true); + assert.equal(hasPanelCharacter('╠══╣'), true); + assert.equal(hasPanelCharacter('├──┤'), false); + assert.equal(hasPanelCharacter('│ tree'), false); + assert.equal(hasPanelCharacter('### CHECKPOINT: Verification Required'), false); + assert.equal(hasPanelCharacter('└── file.md'), false); + }); + + test('the scan flags a heavy fixed-width rule line, with path and line number', () => { + const filePath = tempFile( + 'banner.md', + ['Display banner:', '', HEAVY.repeat(53), ' GSD ► PLANNING', ''].join('\n') + ); + const violations = scan([filePath], isFixedWidthRuleLine); + assert.equal(violations.length, 1); + assert.match(violations[0], /banner\.md:3: /); + }); + + test('the scan flags box-panel characters', () => { + const filePath = tempFile( + 'panel.md', + ['╔══╗', '║ ERROR ║', '╚══╝'].join('\n') + ); + const violations = scan([filePath], hasPanelCharacter); + assert.equal(violations.length, 3); + }); + + test('CRLF files are scanned identically to LF files', () => { + const crlf = tempFile( + 'crlf.md', + ['Display:', HEAVY.repeat(53), '└── file.md', ''].join('\r\n') + ); + const violations = scan([crlf], isFixedWidthRuleLine); + assert.equal(violations.length, 1, 'the \\r must not defeat the rule-line trim'); + assert.match(violations[0], /crlf\.md:2: /); + }); + + test('a file with no separators produces no violations', () => { + const filePath = tempFile( + 'clean.md', + ['# Title', '', '### GSD ► PLANNING', '', '---', '', 'Body.'].join('\n') + ); + assert.deepStrictEqual(scan([filePath], isFixedWidthRuleLine), []); + assert.deepStrictEqual(scan([filePath], hasPanelCharacter), []); + }); + + test('an empty shipped file produces no violations', () => { + const filePath = tempFile('empty.md', ''); + assert.deepStrictEqual(scan([filePath], isFixedWidthRuleLine), []); + assert.deepStrictEqual(scan([filePath], hasPanelCharacter), []); + }); + + const RULE_CHAR = fc.constantFrom(LIGHT, HEAVY, DOUBLE); + + test(`property: any pure run of ${MIN_RULE_RUN}+ rule characters is flagged`, () => { + fc.assert( + fc.property( + fc.array(RULE_CHAR, { minLength: MIN_RULE_RUN, maxLength: 120 }), + fc.constantFrom('', ' ', ' ', '\t', ' \t '), + fc.constantFrom('', ' ', ' ', '\t', '\r'), + (chars, lead, trail) => isFixedWidthRuleLine(`${lead}${chars.join('')}${trail}`) + ), + { seed: 3028, numRuns: 300 } + ); + }); + + test('property: a line carrying any non-rule, non-whitespace character is never flagged', () => { + fc.assert( + fc.property( + fc.array(RULE_CHAR, { minLength: 0, maxLength: 60 }), + fc + .string({ minLength: 1, maxLength: 12 }) + .filter((s) => /\S/.test(s) && !/^[─━═\s]*$/.test(s)), + fc.array(RULE_CHAR, { minLength: 0, maxLength: 60 }), + (before, intruder, after) => + isFixedWidthRuleLine(`${before.join('')}${intruder}${after.join('')}`) === false + ), + { seed: 3028, numRuns: 300 } + ); + }); +}); diff --git a/tests/uat.test.cjs b/tests/uat.test.cjs index 051a8f56b..b44a6d61a 100644 --- a/tests/uat.test.cjs +++ b/tests/uat.test.cjs @@ -15,7 +15,6 @@ const { CHECKPOINT_FRAMES, CHECKPOINT_LANGUAGE_ALIASES, resolveCheckpointFrame, - checkpointBoxLine, parseDeferredItems, } = require('../gsd-core/bin/lib/uat.cjs'); @@ -932,12 +931,12 @@ describe('uat render-checkpoint', () => { assert.ok(japanese.includes('チェックポイント')); assert.ok(japanese.includes('`pass`')); - // Structural lines (borders, separators, Test N heading, expected content) are untouched. - assert.ok(japanese.includes('╔══════════════════════════════════════════════════════════════╗')); - assert.ok(japanese.includes('╚══════════════════════════════════════════════════════════════╝')); - assert.ok(japanese.includes('──────────────────────────────────────────────────────────────')); + // Structural lines (heading marker, separator, Test N heading, expected content) are untouched. + assert.ok(japanese.includes('### チェックポイント: 検証が必要です')); + assert.ok(japanese.includes('---')); assert.ok(japanese.includes('**Test 1: Sample**')); assert.ok(japanese.includes('Something happens.')); + assert.ok(!/[╔╗╚╝║]/.test(japanese), 'the box border must be gone (#3028)'); assert.notStrictEqual(japanese, english); }); @@ -1116,91 +1115,73 @@ describe('uat render-checkpoint', () => { ); }); - // Regression: #2402 review medium finding — checkpointBoxLine() padded using - // JS string `.length` (UTF-16 code units), not display width. The property - // below supplies an independent, category-labelled cell-width oracle rather - // than copying the implementation's Unicode range logic. - describe('checkpoint banner padding uses terminal display width (#2402, #2530)', () => { - test('property: category-labelled strings are padded to a 62-cell interior', () => { - const oneCell = fc.constantFrom( - { text: 'a', width: 1 }, - { text: '7', width: 1 }, - { text: ' ', width: 1 }, - { text: '\u093e', width: 1 }, // Mc: DEVANAGARI VOWEL SIGN AA - { text: '\u093f', width: 1 }, // Mc: DEVANAGARI VOWEL SIGN I - { text: '\u0949', width: 1 }, // Mc: DEVANAGARI VOWEL SIGN CANDRA O - ); - const zeroCell = fc.constantFrom( - { text: '\u0301', width: 0 }, // Mn: COMBINING ACUTE ACCENT - { text: '\u093c', width: 0 }, // Mn: DEVANAGARI SIGN NUKTA - { text: '\u20dd', width: 0 }, // Me: COMBINING ENCLOSING CIRCLE - { text: '\u200d', width: 0 }, // Cf: ZERO WIDTH JOINER - { text: '\u2066', width: 0 }, // Cf: LEFT-TO-RIGHT ISOLATE - { text: '\u2069', width: 0 }, // Cf: POP DIRECTIONAL ISOLATE - ); - const twoCell = fc.constantFrom( - { text: '界', width: 2 }, - { text: '語', width: 2 }, - { text: '한', width: 2 }, - ); + // Regression: #3028 — the checkpoint renderer no longer draws a 64-column + // double-line box (checkpointBoxLine/displayWidth/isWideCodePoint/ + // ZERO_WIDTH_MARK_RE/CHECKPOINT_BOX_WIDTH were removed from src/uat.cts). + // These cases now pin the heading form (`### {banner}`) directly instead of + // a padded box interior; the localized-language coverage that used to prove + // display-width-correct padding now proves the banner text is emitted + // intact, unpadded, and box-free. + describe('checkpoint banner renders as a heading, not a box (#2402, #2530, #3028)', () => { + test('exact rendered banner heading for Japanese/Chinese/Korean (regression pin)', () => { + const currentTest = { number: 1, name: 'Sample', expected: 'Something happens.' }; + const japanese = buildCheckpoint(currentTest, 'Japanese'); + const chinese = buildCheckpoint(currentTest, 'Chinese'); + const korean = buildCheckpoint(currentTest, 'Korean'); - fc.assert(fc.property( - fc.array(fc.oneof(oneCell, zeroCell, twoCell), { maxLength: 35 }), - (cells) => { - const text = cells.map((cell) => cell.text).join(''); - const textWidth = cells.reduce((sum, cell) => sum + cell.width, 0); - const padding = ' '.repeat(Math.max(0, 60 - textWidth)); - assert.strictEqual( - checkpointBoxLine(text), - `║ ${text}${padding}║`, - ); - }, - )); - }); + assert.strictEqual(japanese.split('\n')[0], '### チェックポイント: 検証が必要です'); + assert.strictEqual(chinese.split('\n')[0], '### 检查点:需要验证'); + assert.strictEqual(korean.split('\n')[0], '### 체크포인트: 검증 필요'); - test('padding boundary: width limit-1, limit, and limit+1', () => { - for (const width of [59, 60, 61]) { - const text = 'a'.repeat(width); - assert.strictEqual( - checkpointBoxLine(text), - `║ ${text}${' '.repeat(Math.max(0, 60 - width))}║`, - `unexpected rendering at text width ${width}`, - ); + for (const output of [japanese, chinese, korean]) { + assert.ok(!/[╔╗╚╝║]/.test(output), 'the box border must be gone (#3028)'); } }); - test('exact rendered banner lines for Japanese/Chinese/Korean (regression pin)', () => { + test('exact rendered Hindi banner heading ignores combining-mark cell width (regression pin)', () => { const currentTest = { number: 1, name: 'Sample', expected: 'Something happens.' }; - assert.strictEqual( - buildCheckpoint(currentTest, 'Japanese').split('\n')[1], - '║ チェックポイント: 検証が必要です ║', - ); - assert.strictEqual( - buildCheckpoint(currentTest, 'Chinese').split('\n')[1], - '║ 检查点:需要验证 ║', - ); - assert.strictEqual( - buildCheckpoint(currentTest, 'Korean').split('\n')[1], - '║ 체크포인트: 검증 필요 ║', - ); - }); - - test('exact rendered Hindi banner line ignores combining-mark cell width (regression pin)', () => { - const currentTest = { number: 1, name: 'Sample', expected: 'Something happens.' }; - assert.strictEqual( - buildCheckpoint(currentTest, 'Hindi').split('\n')[1], - `║ चेकपॉइंट: सत्यापन आवश्यक${' '.repeat(40)}║`, - ); + const hindi = buildCheckpoint(currentTest, 'Hindi'); + assert.strictEqual(hindi.split('\n')[0], '### चेकपॉइंट: सत्यापन आवश्यक'); + assert.ok(!/[╔╗╚╝║]/.test(hindi), 'the box border must be gone (#3028)'); }); test('exact rendered Arabic frame is isolated inside the LTR checkpoint layout', () => { const currentTest = { number: 1, name: 'Sample', expected: 'Something happens.' }; const arabic = buildCheckpoint(currentTest, 'Arabic'); + // The one behavior the box removal must not disturb: the RTL banner and + // instruction text stay wrapped in directional isolates. assert.strictEqual( - arabic.split('\n')[1], - `║ \u2067نقطة تحقق: المراجعة مطلوبة\u2069${' '.repeat(34)}║`, + arabic.split('\n')[0], + `### ⁧نقطة تحقق: المراجعة مطلوبة⁩`, ); - assert.ok(arabic.includes('\u2067اكتب `pass` أو صف المشكلة.\u2069')); + assert.ok(arabic.includes('⁧اكتب `pass` أو صف المشكلة.⁩')); + assert.ok(!/[╔╗╚╝║]/.test(arabic), 'the box border must be gone (#3028)'); + }); + + test('emits an over-long banner intact (no box to overflow)', (t) => { + // Previously a banner exceeding the 64-column inner width produced a + // ragged, unpadded border. Now there is no border to overflow — the + // full heading text is emitted intact regardless of length. None of the + // shipped frames are long enough to exercise this, so a synthetic frame + // is registered on the exported (mutable) lookup tables for the + // duration of the test. + const longBanner = `${'X'.repeat(80)}: Verification required well beyond the old 64-column box width`; + const frameKey = '__test_overlong_frame__3028__'; + const aliasKey = '__test_overlong_alias__3028__'; + CHECKPOINT_FRAMES[frameKey] = { + banner: longBanner, + instruction: 'Type `pass` or describe what\'s wrong.', + }; + CHECKPOINT_LANGUAGE_ALIASES[aliasKey] = frameKey; + t.after(() => { + delete CHECKPOINT_FRAMES[frameKey]; + delete CHECKPOINT_LANGUAGE_ALIASES[aliasKey]; + }); + const currentTest = { number: 1, name: 'Sample', expected: 'Something happens.' }; + const output = buildCheckpoint(currentTest, aliasKey); + assert.strictEqual(output.split('\n')[0], `### ${longBanner}`, + 'an over-long banner must be emitted in full, not truncated or wrapped'); + assert.ok(!/[╔╗╚╝║]/.test(output), 'no box characters should appear regardless of banner length'); }); }); @@ -1224,7 +1205,9 @@ awaiting: user response assert.strictEqual(result.success, true, `render-checkpoint failed: ${result.error}`); assert.ok(result.output.includes('**Test 2: Submit form validation**')); assert.ok(result.output.includes('Empty submit keeps controls visible.')); - assert.ok(result.output.includes("Type `pass` or describe what's wrong.")); + // The instruction line renders as a bold line preceded by a `---` thematic + // break, not inside a box border (#3028). + assert.ok(result.output.includes("---\n\n**Type `pass` or describe what's wrong.**")); }); test('strips protocol leak lines from current test copy', () => { @@ -1440,14 +1423,14 @@ awaiting: user response assert.ok(result.output.includes('Verificación requerida'), 'banner should be in Spanish'); assert.ok(result.output.includes('Escribe `pass`'), 'instruction line should be in Spanish'); - // Structure/IDs stay untranslated: box borders, the Test N: name line, and the - // expected content are preserved verbatim. - assert.ok(result.output.includes('╔══════════════════════════════════════════════════════════════╗')); - assert.ok(result.output.includes('╚══════════════════════════════════════════════════════════════╝')); - assert.ok(result.output.includes('──────────────────────────────────────────────────────────────')); + // Structure/IDs stay untranslated: the heading marker, the `---` separator, + // the Test N: name line, and the expected content are preserved verbatim. + assert.ok(result.output.includes('### PUNTO DE CONTROL: Verificación requerida')); + assert.ok(result.output.includes('---')); assert.ok(result.output.includes('**Test 2: Submit form validation**')); assert.ok(result.output.includes('Empty submit keeps controls visible.')); assert.ok(result.output.includes('Validation error copy is shown.')); + assert.ok(!/[╔╗╚╝║]/.test(result.output), 'the box border must be gone (#3028)'); }); // Regression guard for the "unset ⇒ byte-identical English" acceptance criterion. @@ -1471,17 +1454,15 @@ awaiting: user response assert.strictEqual(result.success, true, `render-checkpoint failed: ${result.error}`); const expected = [ - '╔══════════════════════════════════════════════════════════════╗', - '║ CHECKPOINT: Verification Required ║', - '╚══════════════════════════════════════════════════════════════╝', + '### CHECKPOINT: Verification Required', '', '**Test 2: Submit form validation**', '', 'Empty submit keeps controls visible.\nValidation error copy is shown.', '', - '──────────────────────────────────────────────────────────────', - 'Type `pass` or describe what\'s wrong.', - '──────────────────────────────────────────────────────────────', + '---', + '', + '**Type `pass` or describe what\'s wrong.**', ].join('\n'); assert.strictEqual(result.output, expected);