mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-06 13:45:35 +02:00
fix: gen-skill-docs resolver merge + preamble tier gate + plan file discovery
The local RESOLVERS record in gen-skill-docs.ts was shadowing the imported canonical resolvers, causing stale test coverage and preamble generators to be used instead of the authoritative versions in resolvers/. Changes: - Merge imported RESOLVERS with local overrides (spread + override pattern) - Fix preamble tier gate: tier 1 skills no longer get AskUserQuestion format - Make plan file discovery host-agnostic (search multiple plan dirs) - Add missing E2E tier entries for ship/review plan completion tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+13
-31
@@ -16,7 +16,7 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import type { Host, TemplateContext } from './resolvers/types';
|
||||
import { HOST_PATHS } from './resolvers/types';
|
||||
import { RESOLVERS } from './resolvers/index';
|
||||
import { RESOLVERS as IMPORTED_RESOLVERS } from './resolvers/index';
|
||||
import { codexSkillName, transformFrontmatter, extractHookSafetyProse, extractNameAndDescription, condenseOpenAIShortDescription, generateOpenAIYaml } from './resolvers/codex-helpers';
|
||||
import { generatePlanCompletionAuditShip, generatePlanCompletionAuditReview, generatePlanVerificationExec } from './resolvers/review';
|
||||
|
||||
@@ -473,7 +473,7 @@ Hey gstack team — ran into this while using /{skill-name}:
|
||||
|
||||
**What I was trying to do:** {what the user/agent was attempting}
|
||||
**What happened instead:** {what actually happened}
|
||||
**My rating:** {0-10} — {one sentence on why it wasn't a 10}
|
||||
**My Rating:** {0-10} — {one sentence on why it wasn't a 10}
|
||||
|
||||
## Steps to reproduce
|
||||
1. {step}
|
||||
@@ -584,15 +584,14 @@ plan's living status.`;
|
||||
}
|
||||
|
||||
function generatePreamble(ctx: TemplateContext): string {
|
||||
const tier = ctx.preambleTier ?? 4;
|
||||
return [
|
||||
generatePreambleBash(ctx),
|
||||
generateUpgradeCheck(ctx),
|
||||
generateLakeIntro(),
|
||||
generateTelemetryPrompt(ctx),
|
||||
generateAskUserFormat(ctx),
|
||||
generateCompletenessSection(),
|
||||
generateRepoModeSection(),
|
||||
generateSearchBeforeBuildingSection(ctx),
|
||||
...(tier >= 2 ? [generateAskUserFormat(ctx), generateCompletenessSection()] : []),
|
||||
...(tier >= 3 ? [generateRepoModeSection(), generateSearchBeforeBuildingSection(ctx)] : []),
|
||||
generateContributorMode(),
|
||||
generateCompletionStatus(),
|
||||
].join('\n\n');
|
||||
@@ -2801,37 +2800,20 @@ function generateSlugSetup(ctx: TemplateContext): string {
|
||||
return `eval "$(${ctx.paths.binDir}/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG`;
|
||||
}
|
||||
|
||||
// Use the canonical RESOLVERS from resolvers/index.ts, extended with local overrides.
|
||||
// Local overrides are kept for functions that have hardcoded ~/.claude/ paths in the
|
||||
// imported versions — the local versions are host-agnostic and safe for Codex output.
|
||||
const RESOLVERS: Record<string, (ctx: TemplateContext) => string> = {
|
||||
SLUG_EVAL: generateSlugEval,
|
||||
SLUG_SETUP: generateSlugSetup,
|
||||
COMMAND_REFERENCE: generateCommandReference,
|
||||
SNAPSHOT_FLAGS: generateSnapshotFlags,
|
||||
...IMPORTED_RESOLVERS,
|
||||
// Local override — preamble generator with tier-gated sections
|
||||
PREAMBLE: generatePreamble,
|
||||
BROWSE_SETUP: generateBrowseSetup,
|
||||
BASE_BRANCH_DETECT: generateBaseBranchDetect,
|
||||
QA_METHODOLOGY: generateQAMethodology,
|
||||
DESIGN_METHODOLOGY: generateDesignMethodology,
|
||||
DESIGN_HARD_RULES: generateDesignHardRules,
|
||||
DESIGN_OUTSIDE_VOICES: generateDesignOutsideVoices,
|
||||
DESIGN_REVIEW_LITE: generateDesignReviewLite,
|
||||
REVIEW_DASHBOARD: generateReviewDashboard,
|
||||
// Local overrides — these use host-agnostic paths (no ~/.claude/ hardcoding)
|
||||
PLAN_FILE_REVIEW_REPORT: generatePlanFileReviewReport,
|
||||
TEST_BOOTSTRAP: generateTestBootstrap,
|
||||
TEST_COVERAGE_AUDIT_PLAN: generateTestCoverageAuditPlan,
|
||||
TEST_COVERAGE_AUDIT_SHIP: generateTestCoverageAuditShip,
|
||||
TEST_COVERAGE_AUDIT_REVIEW: generateTestCoverageAuditReview,
|
||||
TEST_FAILURE_TRIAGE: generateTestFailureTriage,
|
||||
SPEC_REVIEW_LOOP: generateSpecReviewLoop,
|
||||
DESIGN_SKETCH: generateDesignSketch,
|
||||
BENEFITS_FROM: generateBenefitsFrom,
|
||||
CODEX_SECOND_OPINION: generateCodexSecondOpinion,
|
||||
CODEX_REVIEW_STEP: generateAdversarialStep,
|
||||
ADVERSARIAL_STEP: generateAdversarialStep,
|
||||
DEPLOY_BOOTSTRAP: generateDeployBootstrap,
|
||||
CODEX_PLAN_REVIEW: generateCodexPlanReview,
|
||||
PLAN_COMPLETION_AUDIT_SHIP: generatePlanCompletionAuditShip,
|
||||
PLAN_COMPLETION_AUDIT_REVIEW: generatePlanCompletionAuditReview,
|
||||
PLAN_VERIFICATION_EXEC: generatePlanVerificationExec,
|
||||
// Local-only entry not in resolvers/index.ts
|
||||
CODEX_REVIEW_STEP: generateAdversarialStep,
|
||||
};
|
||||
|
||||
// ─── Codex Helpers ───────────────────────────────────────────
|
||||
|
||||
@@ -598,19 +598,21 @@ SOURCE = "codex" if Codex ran, "claude" if subagent ran.
|
||||
function generatePlanFileDiscovery(): string {
|
||||
return `### Plan File Discovery
|
||||
|
||||
1. **Conversation context (primary):** Check if there is an active plan file in this conversation — Claude Code system messages include plan file paths when in plan mode. Look for references like \`~/.claude/plans/*.md\` in system messages. If found, use it directly — this is the most reliable signal.
|
||||
1. **Conversation context (primary):** Check if there is an active plan file in this conversation. The host agent's system messages include plan file paths when in plan mode. If found, use it directly — this is the most reliable signal.
|
||||
|
||||
2. **Content-based search (fallback):** If no plan file is referenced in conversation context, search by content:
|
||||
|
||||
\`\`\`bash
|
||||
BRANCH=$(git branch --show-current 2>/dev/null | tr '/' '-')
|
||||
REPO=$(basename "$(git rev-parse --show-toplevel 2>/dev/null)")
|
||||
# Try branch name match first (most specific)
|
||||
PLAN=$(ls -t ~/.claude/plans/*.md 2>/dev/null | xargs grep -l "$BRANCH" 2>/dev/null | head -1)
|
||||
# Fall back to repo name match
|
||||
[ -z "$PLAN" ] && PLAN=$(ls -t ~/.claude/plans/*.md 2>/dev/null | xargs grep -l "$REPO" 2>/dev/null | head -1)
|
||||
# Last resort: most recent plan modified in the last 24 hours
|
||||
[ -z "$PLAN" ] && PLAN=$(find ~/.claude/plans -name '*.md' -mmin -1440 -maxdepth 1 2>/dev/null | xargs ls -t 2>/dev/null | head -1)
|
||||
# Search common plan file locations
|
||||
for PLAN_DIR in "$HOME/.claude/plans" "$HOME/.codex/plans" ".gstack/plans"; do
|
||||
[ -d "$PLAN_DIR" ] || continue
|
||||
PLAN=$(ls -t "$PLAN_DIR"/*.md 2>/dev/null | xargs grep -l "$BRANCH" 2>/dev/null | head -1)
|
||||
[ -z "$PLAN" ] && PLAN=$(ls -t "$PLAN_DIR"/*.md 2>/dev/null | xargs grep -l "$REPO" 2>/dev/null | head -1)
|
||||
[ -z "$PLAN" ] && PLAN=$(find "$PLAN_DIR" -name '*.md' -mmin -1440 -maxdepth 1 2>/dev/null | xargs ls -t 2>/dev/null | head -1)
|
||||
[ -n "$PLAN" ] && break
|
||||
done
|
||||
[ -n "$PLAN" ] && echo "PLAN_FILE: $PLAN" || echo "NO_PLAN_FILE"
|
||||
\`\`\`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user