Skip to content

Commit 49cc4ff

Browse files
garrytanToraDadymvanhornclaudejbetala7
authored
v1.31.1.0 fix wave: 3 community PRs (careful BSD sed, codex Step 0 rename, make-pdf setup ordering) (#1413)
* fix(careful): BSD sed compatibility for safe exception detection on macOS The sed regex in check-careful.sh uses \s+, which is a GNU sed extension not supported by BSD sed (macOS default). On macOS, this causes the RM_ARGS strip to fail silently, making rm -rf of safe exceptions (node_modules, .next, dist, etc.) trigger the destructive warning instead of being permitted as designed. Fix: replace \s+ with POSIX [[:space:]]+, which works on both GNU sed (Linux) and BSD sed (macOS). The existing test/hook-scripts.test.ts already documented this limitation via a detectSafeRmWorks() helper and a platform-conditional assertion ("if GNU sed: expect undefined, else: expect ask"). Now that the regex works on both platforms, this dead path is removed and the safe-exception tests assert the same expectation on every OS. Note: the grep regex in the same file also uses \s+, but BSD grep -E on macOS does support \s (verified via bash -x trace), so only the sed expression needs the fix. Discovered while translating the careful skill for a Japanese derivative project (uzustack). Reference: uzumaki-inc/uzustack@bc67c8d * docs(codex): rename Step 0 to avoid collision with platform-detect prelude The codex skill template had its own '## Step 0: Check codex binary' heading (line 42), which after gen-skill-docs collided with the platform-detection prelude '## Step 0: Detect platform and base branch' (injected by scripts/resolvers/utility.ts). The generated codex/SKILL.md ended up with two H2 headings labeled Step 0, which is ambiguous to an agent reading the skill in order. Renamed the local heading to Step 0.4, slotting it between the prelude (Step 0) and the existing Step 0.5 / Step 0.6 sections. No renumbering of downstream steps needed. Closes #1388 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(codex): regenerate SKILL.md after Step 0 rename Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(make-pdf): move setup before preamble footer * chore: bump version and changelog (v1.31.1.0) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: ToraDady <tac201k@gmail.com> Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Jayesh Betala <jayesh.betala7@gmail.com>
1 parent 5d4fe7d commit 49cc4ff

11 files changed

Lines changed: 81 additions & 64 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Changelog
22

3+
## [1.31.1.0] - 2026-05-10
4+
5+
## **Three small community fixes land cleanly.**
6+
## **`/careful` works on macOS again, Codex Step 0 stops colliding, `/make-pdf` setup runs in the right place.**
7+
8+
A short patch wave from three contributors. macOS users who ran `/careful` with `rm -rf node_modules` were silently hitting the warning gate instead of the safe exception path because BSD sed doesn't understand `\s`. The Codex skill's `## Step 0: Check codex binary` header was colliding with the platform-detect prelude that also runs first. `/make-pdf`'s SETUP block was rendered after the Telemetry footer instead of immediately after the Preamble Bash, so `$P` could be referenced before it was set. Each fix is tightly scoped and ships with a regression test (or template ordering invariant) that catches the original failure shape.
9+
10+
This release came out of a contributor-wave triage pass that closed ~75 stale PRs, dropped 11 candidates that needed focused review with specific feedback to each contributor, and lined the survivors through `/plan-eng-review` + Codex outside-voice review before merge. One additional security PR (token-registry timing-safe comparison) was rejected at the codex-review gate after Codex caught a subtle multi-byte UTF-8 buffer-mismatch bug that would have thrown on the auth path instead of returning false; that finding now lives as feedback on the original PR.
11+
12+
### Fixed
13+
14+
- **#1242** `careful/bin/check-careful.sh` uses `[[:space:]]` instead of `\s` in the safe-rm exception regex. macOS sed -E does not support `\s`, which silently broke the exception detection — `rm -rf node_modules` now correctly skips the warning gate on macOS, matching Linux behavior. Removes the `detectSafeRmWorks()` platform-conditional from `test/hook-scripts.test.ts` so both platforms are tested at the same bar. Contributed by @ToraDady.
15+
- **#1394** Codex skill `## Step 0: Check codex binary` renamed to `## Step 0.4: Check codex binary` so the header no longer collides with the new platform-detect prelude (also numbered Step 0). Affects both `codex/SKILL.md.tmpl` and the regenerated `codex/SKILL.md`. Contributed by @mvanhorn.
16+
- **#1393** `/make-pdf` MAKE-PDF SETUP block moves from after the Telemetry footer to right after the Preamble Bash, so `$P` is set before any subsequent step references it. The implementation switches from the `{{MAKE_PDF_SETUP}}` placeholder pattern to programmatic insertion via `generateMakePdfSetup` in `scripts/resolvers/preamble.ts`, gated on `ctx.skillName === 'make-pdf'`. New `make-pdf setup ordering` test in `test/gen-skill-docs.test.ts` asserts the SETUP block sits after the Preamble heading and before Plan Mode / Telemetry / workflow headings. Contributed by @jbetala7.
17+
318
## [1.31.0.0] - 2026-05-09
419

520
## **AskUserQuestion stops getting silently buried in plan files.**

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.31.0.0
1+
1.31.1.0

careful/bin/check-careful.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ CMD_LOWER=$(printf '%s' "$CMD" | tr '[:upper:]' '[:lower:]')
2828
# --- Check for safe exceptions (rm -rf of build artifacts) ---
2929
if printf '%s' "$CMD" | grep -qE 'rm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+|--recursive\s+)' 2>/dev/null; then
3030
SAFE_ONLY=true
31-
RM_ARGS=$(printf '%s' "$CMD" | sed -E 's/.*rm\s+(-[a-zA-Z]+\s+)*//;s/--recursive\s*//')
31+
RM_ARGS=$(printf '%s' "$CMD" | sed -E 's/.*rm[[:space:]]+(-[a-zA-Z]+[[:space:]]+)*//;s/--recursive[[:space:]]*//')
3232
for target in $RM_ARGS; do
3333
case "$target" in
3434
*/node_modules|node_modules|*/\.next|\.next|*/dist|dist|*/__pycache__|__pycache__|*/\.cache|\.cache|*/build|build|*/\.turbo|\.turbo|*/coverage|coverage)

codex/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ assumptions, catches things you might miss. Present its output faithfully, not s
792792

793793
---
794794

795-
## Step 0: Check codex binary
795+
## Step 0.4: Check codex binary
796796

797797
```bash
798798
CODEX_BIN=$(which codex 2>/dev/null || echo "")

codex/SKILL.md.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ assumptions, catches things you might miss. Present its output faithfully, not s
3939

4040
---
4141

42-
## Step 0: Check codex binary
42+
## Step 0.4: Check codex binary
4343

4444
```bash
4545
CODEX_BIN=$(which codex 2>/dev/null || echo "")

make-pdf/SKILL.md

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,42 @@ echo "CHECKPOINT_PUSH: $_CHECKPOINT_PUSH"
102102
[ -n "$OPENCLAW_SESSION" ] && echo "SPAWNED_SESSION: true" || true
103103
```
104104

105+
## MAKE-PDF SETUP (run this check BEFORE any make-pdf command)
106+
107+
```bash
108+
_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
109+
P=""
110+
[ -n "$MAKE_PDF_BIN" ] && [ -x "$MAKE_PDF_BIN" ] && P="$MAKE_PDF_BIN"
111+
[ -z "$P" ] && [ -n "$_ROOT" ] && [ -x "$_ROOT/.claude/skills/gstack/make-pdf/dist/pdf" ] && P="$_ROOT/.claude/skills/gstack/make-pdf/dist/pdf"
112+
[ -z "$P" ] && P="$HOME/.claude/skills/gstack/make-pdf/dist/pdf"
113+
if [ -x "$P" ]; then
114+
echo "MAKE_PDF_READY: $P"
115+
alias _p_="$P" # shellcheck alias helper (not exported)
116+
export P # available as $P in subsequent blocks within the same skill invocation
117+
else
118+
echo "MAKE_PDF_NOT_AVAILABLE (run './setup' in the gstack repo to build it)"
119+
fi
120+
```
121+
122+
If `MAKE_PDF_NOT_AVAILABLE` is printed: tell the user the binary is not
123+
built. Have them run `./setup` from the gstack repo, then retry.
124+
125+
If `MAKE_PDF_READY` is printed: `$P` is the binary path for the rest of
126+
the skill. Use `$P` (not an explicit path) so the skill body stays portable.
127+
128+
Core commands:
129+
- `$P generate <input.md> [output.pdf]` — render markdown to PDF (80% use case)
130+
- `$P generate --cover --toc essay.md out.pdf` — full publication layout
131+
- `$P generate --watermark DRAFT memo.md draft.pdf` — diagonal DRAFT watermark
132+
- `$P preview <input.md>` — render HTML and open in browser (fast iteration)
133+
- `$P setup` — verify browse + Chromium + pdftotext and run a smoke test
134+
- `$P --help` — full flag reference
135+
136+
Output contract:
137+
- `stdout`: ONLY the output path on success. One line.
138+
- `stderr`: progress (`Rendering HTML... Generating PDF...`) unless `--quiet`.
139+
- Exit 0 success / 1 bad args / 2 render error / 3 Paged.js timeout / 4 browse unavailable.
140+
105141
## Plan Mode Safe Operations
106142

107143
In plan mode, allowed because they inform the plan: `$B`, `$D`, `codex exec`/`codex review`, writes to `~/.gstack/`, writes to the plan file, and `open` for generated artifacts.
@@ -489,42 +525,6 @@ On Linux, install `fonts-liberation` for correct rendering — Helvetica and Ari
489525
aren't present by default, and Liberation Sans is the standard metric-compatible
490526
fallback. CI and Docker builds install it automatically via Dockerfile.ci.
491527

492-
## MAKE-PDF SETUP (run this check BEFORE any make-pdf command)
493-
494-
```bash
495-
_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
496-
P=""
497-
[ -n "$MAKE_PDF_BIN" ] && [ -x "$MAKE_PDF_BIN" ] && P="$MAKE_PDF_BIN"
498-
[ -z "$P" ] && [ -n "$_ROOT" ] && [ -x "$_ROOT/.claude/skills/gstack/make-pdf/dist/pdf" ] && P="$_ROOT/.claude/skills/gstack/make-pdf/dist/pdf"
499-
[ -z "$P" ] && P="$HOME/.claude/skills/gstack/make-pdf/dist/pdf"
500-
if [ -x "$P" ]; then
501-
echo "MAKE_PDF_READY: $P"
502-
alias _p_="$P" # shellcheck alias helper (not exported)
503-
export P # available as $P in subsequent blocks within the same skill invocation
504-
else
505-
echo "MAKE_PDF_NOT_AVAILABLE (run './setup' in the gstack repo to build it)"
506-
fi
507-
```
508-
509-
If `MAKE_PDF_NOT_AVAILABLE` is printed: tell the user the binary is not
510-
built. Have them run `./setup` from the gstack repo, then retry.
511-
512-
If `MAKE_PDF_READY` is printed: `$P` is the binary path for the rest of
513-
the skill. Use `$P` (not an explicit path) so the skill body stays portable.
514-
515-
Core commands:
516-
- `$P generate <input.md> [output.pdf]` — render markdown to PDF (80% use case)
517-
- `$P generate --cover --toc essay.md out.pdf` — full publication layout
518-
- `$P generate --watermark DRAFT memo.md draft.pdf` — diagonal DRAFT watermark
519-
- `$P preview <input.md>` — render HTML and open in browser (fast iteration)
520-
- `$P setup` — verify browse + Chromium + pdftotext and run a smoke test
521-
- `$P --help` — full flag reference
522-
523-
Output contract:
524-
- `stdout`: ONLY the output path on success. One line.
525-
- `stderr`: progress (`Rendering HTML... Generating PDF...`) unless `--quiet`.
526-
- Exit 0 success / 1 bad args / 2 render error / 3 Paged.js timeout / 4 browse unavailable.
527-
528528
## Core patterns
529529

530530
### 80% case — memo/letter

make-pdf/SKILL.md.tmpl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ On Linux, install `fonts-liberation` for correct rendering — Helvetica and Ari
4141
aren't present by default, and Liberation Sans is the standard metric-compatible
4242
fallback. CI and Docker builds install it automatically via Dockerfile.ci.
4343

44-
{{MAKE_PDF_SETUP}}
45-
4644
## Core patterns
4745

4846
### 80% case — memo/letter

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "gstack",
3-
"version": "1.31.0.0",
3+
"version": "1.31.1.0",
44
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
55
"license": "MIT",
66
"type": "module",

scripts/resolvers/preamble.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import { generateContextHealth } from './preamble/generate-context-health';
5858
// Tier 3+ repo mode + search
5959
import { generateRepoModeSection } from './preamble/generate-repo-mode-section';
6060
import { generateSearchBeforeBuildingSection } from './preamble/generate-search-before-building';
61+
import { generateMakePdfSetup } from './make-pdf';
6162

6263
// Standalone export used directly by the resolver registry
6364
export { generateTestFailureTriage } from './preamble/generate-test-failure-triage';
@@ -81,7 +82,8 @@ export function generatePreamble(ctx: TemplateContext): string {
8182
}
8283
const sections = [
8384
generatePreambleBash(ctx),
84-
// Plan-mode-skill semantics at position 1: after bash (so _SESSION_ID /
85+
...(ctx.skillName === 'make-pdf' ? [generateMakePdfSetup(ctx)] : []),
86+
// Plan-mode-skill semantics stays near the top: after bash (so _SESSION_ID /
8587
// _BRANCH / _TEL env vars are live) and before all onboarding gates so
8688
// models read the authoritative "AskUserQuestion satisfies plan mode's
8789
// end-of-turn" rule before any other instruction. Renders for all skills

test/gen-skill-docs.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,26 @@ describe('Plan status footer in preamble', () => {
10981098
});
10991099
});
11001100

1101+
// --- make-pdf setup ordering ---
1102+
1103+
describe('make-pdf setup ordering', () => {
1104+
test('MAKE-PDF SETUP appears before generic preamble footer sections', () => {
1105+
const content = fs.readFileSync(path.join(ROOT, 'make-pdf', 'SKILL.md'), 'utf-8');
1106+
const preambleIdx = content.indexOf('## Preamble (run first)');
1107+
const setupIdx = content.indexOf('## MAKE-PDF SETUP');
1108+
const planModeIdx = content.indexOf('## Plan Mode Safe Operations');
1109+
const telemetryIdx = content.indexOf('## Telemetry (run last)');
1110+
const workflowIdx = content.indexOf('# make-pdf: publication-quality PDFs from markdown');
1111+
1112+
expect(preambleIdx).toBeGreaterThanOrEqual(0);
1113+
expect(setupIdx).toBeGreaterThan(preambleIdx);
1114+
expect(setupIdx).toBeLessThan(planModeIdx);
1115+
expect(setupIdx).toBeLessThan(telemetryIdx);
1116+
expect(setupIdx).toBeLessThan(workflowIdx);
1117+
expect(content.match(/^## MAKE-PDF SETUP/gm)?.length ?? 0).toBe(1);
1118+
});
1119+
});
1120+
11011121
// --- Skill invocation during plan mode in preamble ---
11021122

11031123
describe('Skill invocation during plan mode in preamble', () => {

0 commit comments

Comments
 (0)