mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-13 16:38:56 +02:00
Branch-name-to-filename had incompatible rules across writer and readers: gstack-review-log WRITES <branch>-reviews.jsonl with the gstack-slug canonical form (tr '/' '-' then tr -cd 'a-zA-Z0-9._-', bin/gstack-slug:178), but Context Recovery PROBED it with raw $_BRANCH from git branch --show-current — so for any branch containing a '/' the REVIEWS line never fired (#1851's reader half of #1127). The probe now uses ${BRANCH:-unknown}, the canonical value the gstack-slug eval on the block's first line already sets. review.ts's plan content-search BRANCH gains the missing tr -cd half so it matches the same canonical pipeline. Full audit of the 5 raw $_BRANCH interpolation sites in scripts/resolvers/ (E3): generate-context-recovery.ts:16 (reviews.jsonl path) -> canonical BRANCH; :19/:21 (timeline.jsonl content greps) KEEP raw $_BRANCH because the timeline writer (preamble's gstack-timeline-log call) stores the raw branch in the "branch" field — slugging the reader would break that pairing; generate-preamble-bash.ts:29 (display echo) and :97 (timeline data write) keep raw by design. The *-$BRANCH-design-*.md family (review.ts:313 + 3 plan-review templates) is a consistent tr '/' '-' writer/reader pair and is deliberately untouched. test/branch-slug-hygiene.test.ts pins the discipline: a rendered-output sweep forbids raw $_BRANCH adjacent to a path separator or as a filename prefix in ANY generated SKILL.md/section, and a live round-trip on a feat/slash branch proves gstack-review-log's write is found by the rendered probe (with the raw-form shape as a negative control). Reader-side fix folded from PR #1851. Contributed by @harjothkhara. Fixes #2550 Fixes #1127 Co-authored-by: harjothkhara <harjothkhara@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
45 lines
3.0 KiB
TypeScript
45 lines
3.0 KiB
TypeScript
import type { TemplateContext } from '../types';
|
|
|
|
export function generateContextRecovery(ctx: TemplateContext): string {
|
|
const binDir = ctx.paths.binDir; // env-var hosts already resolve to $GSTACK_BIN via types.ts
|
|
|
|
// Branch-form discipline (#2550/#1851): FILE-PATH positions use $BRANCH —
|
|
// the canonical slug form the gstack-slug eval on the first line sets
|
|
// (tr '/' '-' then tr -cd 'a-zA-Z0-9._-', matching what gstack-review-log
|
|
// WRITES). The timeline.jsonl greps keep raw $_BRANCH because the timeline
|
|
// writer (preamble's gstack-timeline-log call) stores the raw branch in the
|
|
// "branch" field — slugging the reader there would break matching.
|
|
return `## Context Recovery
|
|
|
|
At session start or after compaction, recover recent project context.
|
|
|
|
\`\`\`bash
|
|
eval "$(${binDir}/gstack-slug 2>/dev/null)"
|
|
_PROJ="\${GSTACK_HOME:-$HOME/.gstack}/projects/\${SLUG:-unknown}"
|
|
if [ -d "$_PROJ" ]; then
|
|
echo "--- RECENT ARTIFACTS ---"
|
|
find "$_PROJ/ceo-plans" "$_PROJ/checkpoints" -type f -name "*.md" 2>/dev/null | xargs -r ls -t 2>/dev/null | head -3
|
|
[ -f "$_PROJ/\${BRANCH:-unknown}-reviews.jsonl" ] && echo "REVIEWS: $(wc -l < "$_PROJ/\${BRANCH:-unknown}-reviews.jsonl" | tr -d ' ') entries"
|
|
[ -f "$_PROJ/timeline.jsonl" ] && tail -5 "$_PROJ/timeline.jsonl"
|
|
if [ -f "$_PROJ/timeline.jsonl" ]; then
|
|
_LAST=$(grep "\\"branch\\":\\"\${_BRANCH}\\"" "$_PROJ/timeline.jsonl" 2>/dev/null | grep '"event":"completed"' | tail -1)
|
|
[ -n "$_LAST" ] && echo "LAST_SESSION: $_LAST"
|
|
_RECENT_SKILLS=$(grep "\\"branch\\":\\"\${_BRANCH}\\"" "$_PROJ/timeline.jsonl" 2>/dev/null | grep '"event":"completed"' | tail -3 | grep -o '"skill":"[^"]*"' | sed 's/"skill":"//;s/"//' | tr '\\n' ',')
|
|
[ -n "$_RECENT_SKILLS" ] && echo "RECENT_PATTERN: $_RECENT_SKILLS"
|
|
fi
|
|
_LATEST_CP=$(find "$_PROJ/checkpoints" -name "*.md" -type f 2>/dev/null | xargs -r ls -t 2>/dev/null | head -1)
|
|
[ -n "$_LATEST_CP" ] && echo "LATEST_CHECKPOINT: $_LATEST_CP"
|
|
if [ -f "$_PROJ/decisions.active.json" ]; then
|
|
echo "--- ACTIVE DECISIONS (recent, scope-relevant) ---"
|
|
${binDir}/gstack-decision-search --recent 5 2>/dev/null
|
|
echo "--- END DECISIONS ---"
|
|
fi
|
|
echo "--- END ARTIFACTS ---"
|
|
fi
|
|
\`\`\`
|
|
|
|
If artifacts are listed, read the newest useful one. If \`LAST_SESSION\` or \`LATEST_CHECKPOINT\` appears, give a 2-sentence welcome back summary. If \`RECENT_PATTERN\` clearly implies a next skill, suggest it once.
|
|
|
|
**Cross-session decisions.** If \`ACTIVE DECISIONS\` are listed, treat them as prior settled calls with their rationale — do not silently re-litigate them; if you're about to reverse one, say so explicitly. Reach for \`${binDir}/gstack-decision-search\` whenever a question touches a past decision ("what did we decide / why / did we try"). When you or the user make a DURABLE decision (architecture, scope, tool/vendor choice, or a reversal) — NOT a turn-level or trivial choice — log it with \`${binDir}/gstack-decision-log\` (\`--supersede <id>\` for a reversal). Reliable and local; gbrain not required.`;
|
|
}
|