chore: merge origin/main, resolve VERSION + CHANGELOG conflicts

Bump to v0.15.13.0 (above main's 0.15.12.0). Resolve preamble.ts
conflicts (keep both vendoring detection and spawned session check).
Regenerate all SKILL.md files from resolved sources.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-04-05 23:32:48 -07:00
72 changed files with 2754 additions and 149 deletions
+70 -3
View File
@@ -507,11 +507,16 @@ for (const currentHost of hostsToRun) {
let hasChanges = false;
const tokenBudget: Array<{ skill: string; lines: number; tokens: number }> = [];
const currentHostConfig = getHostConfig(currentHost);
for (const tmplPath of findTemplates()) {
// Skip skills listed in host config's generation.skipSkills
const currentHostConfig = getHostConfig(currentHost);
const dir = path.basename(path.dirname(tmplPath));
// includeSkills allowlist (union logic: include minus skip)
if (currentHostConfig.generation.includeSkills?.length) {
if (!currentHostConfig.generation.includeSkills.includes(dir)) continue;
}
// skipSkills denylist (subtracts from includeSkills or full set)
if (currentHostConfig.generation.skipSkills?.length) {
const dir = path.basename(path.dirname(tmplPath));
if (currentHostConfig.generation.skipSkills.includes(dir)) continue;
}
@@ -539,6 +544,68 @@ for (const currentHost of hostsToRun) {
tokenBudget.push({ skill: relOutput, lines, tokens });
}
// Generate gstack-lite and gstack-full for OpenClaw host
if (currentHost === 'openclaw' && !DRY_RUN) {
const openclawDir = path.join(ROOT, 'openclaw');
if (!fs.existsSync(openclawDir)) fs.mkdirSync(openclawDir, { recursive: true });
const gstackLite = `# gstack-lite Planning Discipline
Injected by the orchestrator into spawned Claude Code sessions. Append to existing CLAUDE.md.
## Planning Discipline
1. Read every file you will modify. Understand existing patterns first.
2. Before writing code, state your plan: what, why, which files, test case, risk.
3. When ambiguous, prefer: completeness over shortcuts, existing patterns over new ones,
reversible choices over irreversible ones, safe defaults over clever ones.
4. Self-review your changes before reporting done. Check for: missed files, broken
imports, untested paths, style inconsistencies.
5. Report when done: what shipped, what decisions you made, anything uncertain.
`;
fs.writeFileSync(path.join(openclawDir, 'gstack-lite-CLAUDE.md'), gstackLite);
console.log('GENERATED: openclaw/gstack-lite-CLAUDE.md');
const gstackFull = `# gstack-full Pipeline
Injected by the orchestrator for complete feature builds. Append to existing CLAUDE.md.
## Full Pipeline
1. Read CLAUDE.md and understand the project context.
2. Run /autoplan to review your approach (CEO + eng + design review pipeline).
3. Implement the approved plan. Follow the planning discipline above.
4. Run /ship to create a PR with tests, changelog, and version bump.
5. Report back: PR URL, what shipped, decisions made, anything uncertain.
Do not ask for human input until the PR is ready for review.
`;
fs.writeFileSync(path.join(openclawDir, 'gstack-full-CLAUDE.md'), gstackFull);
console.log('GENERATED: openclaw/gstack-full-CLAUDE.md');
const gstackPlan = `# gstack-plan: Full Review Gauntlet
Injected by the orchestrator when the user wants to plan a Claude Code project.
Append to existing CLAUDE.md.
## Planning Pipeline
1. Read CLAUDE.md and understand the project context.
2. Run /office-hours to produce a design doc (problem statement, premises, alternatives).
3. Run /autoplan to review the design (CEO + eng + design + DX reviews + codex adversarial).
4. Save the final reviewed plan to a file the orchestrator can reference later.
Write it to: plans/<project-slug>-plan-<date>.md in the current repo.
Include the design doc, all review decisions, and the implementation sequence.
5. Report back to the orchestrator:
- Plan file path
- One-paragraph summary of what was designed and the key decisions
- List of accepted scope expansions (if any)
- Recommended next step (usually: spawn a new session with gstack-full to implement)
Do not implement anything. This is planning only.
The orchestrator will persist the plan link to its own memory/knowledge store.
`;
fs.writeFileSync(path.join(openclawDir, 'gstack-plan-CLAUDE.md'), gstackPlan);
console.log('GENERATED: openclaw/gstack-plan-CLAUDE.md');
}
if (DRY_RUN && hasChanges) {
console.error(`\nGenerated SKILL.md files are stale (${currentHost} host). Run: bun run gen:skill-docs --host ${currentHost}`);
if (HOST_ARG_VAL !== 'all') process.exit(1);
+2
View File
@@ -62,6 +62,8 @@ export interface HostConfig {
metadataFormat?: string | null;
/** Skill directories to exclude from generation for this host. */
skipSkills?: string[];
/** Skill directories to include (allowlist). Union logic: include minus skip. */
includeSkills?: string[];
};
// --- Content Rewrites ---
+2 -1
View File
@@ -11,7 +11,7 @@ import { generateTestFailureTriage } from './preamble';
import { generateCommandReference, generateSnapshotFlags, generateBrowseSetup } from './browse';
import { generateDesignMethodology, generateDesignHardRules, generateDesignOutsideVoices, generateDesignReviewLite, generateDesignSketch, generateDesignSetup, generateDesignMockup, generateDesignShotgunLoop } from './design';
import { generateTestBootstrap, generateTestCoverageAuditPlan, generateTestCoverageAuditShip, generateTestCoverageAuditReview } from './testing';
import { generateReviewDashboard, generatePlanFileReviewReport, generateSpecReviewLoop, generateBenefitsFrom, generateCodexSecondOpinion, generateAdversarialStep, generateCodexPlanReview, generatePlanCompletionAuditShip, generatePlanCompletionAuditReview, generatePlanVerificationExec, generateScopeDrift } from './review';
import { generateReviewDashboard, generatePlanFileReviewReport, generateSpecReviewLoop, generateBenefitsFrom, generateCodexSecondOpinion, generateAdversarialStep, generateCodexPlanReview, generatePlanCompletionAuditShip, generatePlanCompletionAuditReview, generatePlanVerificationExec, generateScopeDrift, generateCrossReviewDedup } from './review';
import { generateSlugEval, generateSlugSetup, generateBaseBranchDetect, generateDeployBootstrap, generateQAMethodology, generateCoAuthorTrailer, generateChangelogWorkflow } from './utility';
import { generateLearningsSearch, generateLearningsLog } from './learnings';
import { generateConfidenceCalibration } from './confidence';
@@ -60,5 +60,6 @@ export const RESOLVERS: Record<string, ResolverFn> = {
INVOKE_SKILL: generateInvokeSkill,
CHANGELOG_WORKFLOW: generateChangelogWorkflow,
REVIEW_ARMY: generateReviewArmy,
CROSS_REVIEW_DEDUP: generateCrossReviewDedup,
DX_FRAMEWORK: generateDxFramework,
};
+12
View File
@@ -97,6 +97,8 @@ if [ -d ".claude/skills/gstack" ] && [ ! -L ".claude/skills/gstack" ]; then
fi
fi
echo "VENDORED_GSTACK: $_VENDORED"
# Detect spawned session (OpenClaw or other orchestrator)
[ -n "$OPENCLAW_SESSION" ] && echo "SPAWNED_SESSION: true" || true
\`\`\``;
}
@@ -268,6 +270,15 @@ touch ~/.gstack/.vendoring-warned-\${SLUG:-unknown}
This only happens once per project. If the marker file exists, skip entirely.`;
}
function generateSpawnedSessionCheck(): string {
return `If \`SPAWNED_SESSION\` is \`"true"\`, you are running inside a session spawned by an
AI orchestrator (e.g., OpenClaw). In spawned sessions:
- Do NOT use AskUserQuestion for interactive prompts. Auto-choose the recommended option.
- Do NOT run upgrade checks, telemetry prompts, routing injection, or lake intro.
- Focus on completing the task and reporting results via prose output.
- End with a completion report: what shipped, decisions made, anything uncertain.`;
}
function generateAskUserFormat(_ctx: TemplateContext): string {
return `## AskUserQuestion Format
@@ -718,6 +729,7 @@ export function generatePreamble(ctx: TemplateContext): string {
generateProactivePrompt(ctx),
generateRoutingInjection(ctx),
generateVendoringDeprecation(ctx),
generateSpawnedSessionCheck(),
generateVoiceDirective(tier),
...(tier >= 2 ? [generateContextRecovery(ctx), generateAskUserFormat(ctx), generateCompletenessSection()] : []),
...(tier >= 3 ? [generateRepoModeSection(), generateSearchBeforeBuildingSection(ctx)] : []),
+24 -9
View File
@@ -12,7 +12,11 @@
import type { TemplateContext } from './types';
function generateSpecialistSelection(ctx: TemplateContext): string {
return `## Step 4.5: Review Army — Specialist Dispatch
const isShip = ctx.skillName === 'ship';
const stepSel = isShip ? '3.55' : '4.5';
const stepMerge = isShip ? '3.56' : '4.6';
const nextStep = isShip ? 'the Fix-First flow (item 4)' : 'Step 5';
return `## Step ${stepSel}: Review Army — Specialist Dispatch
### Detect stack and scope
@@ -26,7 +30,9 @@ STACK=""
[ -f go.mod ] && STACK="\${STACK}go "
[ -f Cargo.toml ] && STACK="\${STACK}rust "
echo "STACK: \${STACK:-unknown}"
DIFF_LINES=$(git diff origin/<base> --stat | tail -1 | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo "0")
DIFF_INS=$(git diff origin/<base> --stat | tail -1 | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo "0")
DIFF_DEL=$(git diff origin/<base> --stat | tail -1 | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo "0")
DIFF_LINES=$((DIFF_INS + DIFF_DEL))
echo "DIFF_LINES: $DIFF_LINES"
# Detect test framework for specialist test stub generation
TEST_FW=""
@@ -52,7 +58,7 @@ Based on the scope signals above, select which specialists to dispatch.
1. **Testing** — read \`${ctx.paths.skillRoot}/review/specialists/testing.md\`
2. **Maintainability** — read \`${ctx.paths.skillRoot}/review/specialists/maintainability.md\`
**If DIFF_LINES < 50:** Skip all specialists. Print: "Small diff ($DIFF_LINES lines) — specialists skipped." Continue to Step 5.
**If DIFF_LINES < 50:** Skip all specialists. Print: "Small diff ($DIFF_LINES lines) — specialists skipped." Continue to ${nextStep}.
**Conditional (dispatch if the matching scope signal is true):**
3. **Security** — if SCOPE_AUTH=true, OR if SCOPE_BACKEND=true AND DIFF_LINES > 100. Read \`${ctx.paths.skillRoot}/review/specialists/security.md\`
@@ -126,8 +132,14 @@ CHECKLIST:
- If any specialist subagent fails or times out, log the failure and continue with results from successful specialists. Specialists are additive — partial results are better than no results.`;
}
function generateFindingsMerge(_ctx: TemplateContext): string {
return `### Step 4.6: Collect and merge findings
function generateFindingsMerge(ctx: TemplateContext): string {
const isShip = ctx.skillName === 'ship';
const stepMerge = isShip ? '3.56' : '4.6';
const stepSel = isShip ? '3.55' : '4.5';
const fixFirstRef = isShip ? 'the Fix-First flow (item 4)' : 'Step 5 Fix-First';
const critPassRef = isShip ? 'the checklist pass (Step 3.5)' : 'the CRITICAL pass findings from Step 4';
const persistRef = isShip ? 'the review-log persist' : 'the review-log entry in Step 5.8';
return `### Step ${stepMerge}: Collect and merge findings
After all specialist subagents complete, collect their outputs.
@@ -173,11 +185,11 @@ SPECIALIST REVIEW: N findings (X critical, Y informational) from Z specialists
PR Quality Score: X/10
\`\`\`
These findings flow into Step 5 Fix-First alongside the CRITICAL pass findings from Step 4.
These findings flow into ${fixFirstRef} alongside ${critPassRef}.
The Fix-First heuristic applies identically — specialist findings follow the same AUTO-FIX vs ASK classification.
**Compile per-specialist stats:**
After merging findings, compile a \`specialists\` object for the review-log entry in Step 5.8.
After merging findings, compile a \`specialists\` object for ${persistRef}.
For each specialist (testing, maintainability, security, performance, data-migration, api-contract, design, red-team):
- If dispatched: \`{"dispatched": true, "findings": N, "critical": N, "informational": N}\`
- If skipped by scope: \`{"dispatched": false, "reason": "scope"}\`
@@ -189,6 +201,9 @@ Remember these stats — you will need them for the review-log entry in Step 5.8
}
function generateRedTeam(ctx: TemplateContext): string {
const isShip = ctx.skillName === 'ship';
const stepMerge = isShip ? '3.56' : '4.6';
const fixFirstRef = isShip ? 'the Fix-First flow (item 4)' : 'Step 5 Fix-First';
return `### Red Team dispatch (conditional)
**Activation:** Only if DIFF_LINES > 200 OR any specialist produced a CRITICAL finding.
@@ -197,7 +212,7 @@ If activated, dispatch one more subagent via the Agent tool (foreground, not bac
The Red Team subagent receives:
1. The red-team checklist from \`${ctx.paths.skillRoot}/review/specialists/red-team.md\`
2. The merged specialist findings from Step 4.6 (so it knows what was already caught)
2. The merged specialist findings from Step ${stepMerge} (so it knows what was already caught)
3. The git diff command
Prompt: "You are a red team reviewer. The code has already been reviewed by N specialists
@@ -208,7 +223,7 @@ concerns, integration boundary issues, and failure modes that specialist checkli
don't cover."
If the Red Team finds additional issues, merge them into the findings list before
Step 5 Fix-First. Red Team findings are tagged with \`"specialist":"red-team"\`.
${fixFirstRef}. Red Team findings are tagged with \`"specialist":"red-team"\`.
If the Red Team returns NO FINDINGS, note: "Red Team review: no additional issues found."
If the Red Team subagent fails or times out, skip silently and continue.`;
+44
View File
@@ -975,3 +975,47 @@ Add a \`## Verification Results\` section to the PR body (Step 8):
- If verification ran: summary of results (N PASS, M FAIL, K SKIPPED)
- If skipped: reason for skipping (no plan, no server, no verification section)`;
}
// ─── Cross-Review Finding Dedup ──────────────────────────────────────
export function generateCrossReviewDedup(ctx: TemplateContext): string {
const isShip = ctx.skillName === 'ship';
const stepNum = isShip ? '3.57' : '5.0';
const findingsRef = isShip
? 'the checklist pass (Step 3.5) and specialist review (Step 3.55-3.56)'
: 'Step 4 critical pass and Step 4.5-4.6 specialists';
return `### Step ${stepNum}: Cross-review finding dedup
Before classifying findings, check if any were previously skipped by the user in a prior review on this branch.
\`\`\`bash
~/.claude/skills/gstack/bin/gstack-review-read
\`\`\`
Parse the output: only lines BEFORE \`---CONFIG---\` are JSONL entries (the output also contains \`---CONFIG---\` and \`---HEAD---\` footer sections that are not JSONL — ignore those).
For each JSONL entry that has a \`findings\` array:
1. Collect all fingerprints where \`action: "skipped"\`
2. Note the \`commit\` field from that entry
If skipped fingerprints exist, get the list of files changed since that review:
\`\`\`bash
git diff --name-only <prior-review-commit> HEAD
\`\`\`
For each current finding (from both ${findingsRef}), check:
- Does its fingerprint match a previously skipped finding?
- Is the finding's file path NOT in the changed-files set?
If both conditions are true: suppress the finding. It was intentionally skipped and the relevant code hasn't changed.
Print: "Suppressed N findings from prior reviews (previously skipped by user)"
**Only suppress \`skipped\` findings — never \`fixed\` or \`auto-fixed\`** (those might regress and should be re-checked).
If no prior reviews exist or none have a \`findings\` array, skip this step silently.
Output a summary header: \`Pre-Landing Review: N issues (X critical, Y informational)\``;
}