Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/on-before-mergeable-no-branch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@gemstack/framework": patch
---

The on-before-mergeable follow-up no longer strands its output on a branch nothing merges. It was spawned as a plain `framework prompt` run, so it inherited the #326 system prompt's `### Session name` step and committed + created + checked out a fresh `the-framework/<name>` branch before writing anything. Its output (the queued quality TODO entries and the business-knowledge docs, `DECISIONS.md` / `KNOWLEDGE-BASE.md`) landed on that branch, which nothing merges, so the next run branched from main and could not see it. The follow-up is a follow-up to a session, not a session of its own, so it now runs `--vanilla` (no built-in prompt, hence no session-name step) and stays on the session's current branch, where its output rides to review and merge with the work.
9 changes: 9 additions & 0 deletions packages/framework/src/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ test('promptRunArgs runs a headless prompt and carries NO --on-before-mergeable
assert.equal(args.includes('--on-before-mergeable'), false)
// maxCost is optional.
assert.equal(promptRunArgs('x', '/w', '/bin/f').includes('--max-cost'), false)
// Not vanilla by default: a normal direct/quality run keeps the built-in #326 prompt.
assert.equal(args.includes('--vanilla'), false)
})

test('promptRunArgs adds --vanilla so the on-before-mergeable follow-up skips the session-name branch step (#560)', () => {
// The follow-up is not a session; --vanilla drops the #326 prompt (and its `### Session
// name` step), so the run stays on the session branch instead of stranding its output.
const args = promptRunArgs('queue follow-ups', '/work/app', '/bin/framework', 3, true)
assert.ok(args.includes('--vanilla'))
})

test('runOnBeforeMergeable queues the follow-ups in ONE run instead of running the presets (#326/#556)', async () => {
Expand Down
16 changes: 12 additions & 4 deletions packages/framework/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1388,17 +1388,24 @@ function spawnMaintenanceRun(review: RepoReview, binPath: string, maxCost?: numb
* note it carries **no** `--on-before-mergeable`, which is the on-before-mergeable recursion guard (a quality
* pass must not trigger its own suite).
*/
export function promptRunArgs(prompt: string, cwd: string, binPath: string, maxCost?: number): string[] {
export function promptRunArgs(prompt: string, cwd: string, binPath: string, maxCost?: number, vanilla = false): string[] {
const args = [binPath, 'prompt', prompt, '--no-dashboard', '--cwd', cwd]
if (maxCost !== undefined) args.push('--max-cost', String(maxCost))
// The on-before-mergeable follow-up runs `--vanilla` so it skips the #326 prompt's
// `### Session name` step: it is a follow-up to a session, not a session of its own,
// so it must not commit + branch + checkout a new `the-framework/<name>` branch. That
// stranded its output (the #556 TODO entries and #537 knowledge docs) on a branch
// nothing merges (#560). Vanilla keeps it on the session's current branch, where its
// output rides to review and merge with the work. The follow-up prompt is self-contained.
if (vanilla) args.push('--vanilla')
return args
}

function spawnPromptRun(prompt: string, cwd: string, binPath: string, maxCost?: number): Promise<boolean> {
function spawnPromptRun(prompt: string, cwd: string, binPath: string, maxCost?: number, vanilla = false): Promise<boolean> {
if (process.env.NODE_TEST_CONTEXT || /\.test\.[cm]?[jt]s$/.test(binPath)) {
return Promise.resolve(false) // refuse to spawn from a test entry
}
const args = promptRunArgs(prompt, cwd, binPath, maxCost)
const args = promptRunArgs(prompt, cwd, binPath, maxCost, vanilla)
return new Promise<boolean>(resolvePromise => {
const child = spawn(process.execPath, args, { stdio: 'inherit' })
child.once('error', () => resolvePromise(false))
Expand Down Expand Up @@ -1426,7 +1433,8 @@ export async function runOnBeforeMergeable(
tf: OnBeforeMergeableContext,
maxCost?: number,
eco?: EcoOptions,
run: PromptRunner = spawnPromptRun,
// Vanilla by default: the follow-up must not run the session-name step and branch (#560).
run: PromptRunner = (prompt, cwd, binPath, maxCost) => spawnPromptRun(prompt, cwd, binPath, maxCost, true),
fs: StoreFs = nodeStoreFs(),
): Promise<void> {
// Ensure the presets exist so the queued entries' filePaths resolve, even in a repo
Expand Down
Loading