@pmelab/gtd 31.0.0 → 32.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtd",
3
- "version": "31.0.0",
3
+ "version": "32.0.0",
4
4
  "description": "Drive the gtd loop inside Claude Code: agent turns run as subagents, gtd decides every beat",
5
5
  "author": {
6
6
  "name": "Philipp Melab"
package/README.md CHANGED
@@ -339,28 +339,29 @@ asks, and moves the process on only when you say so; a review you leave
339
339
  untouched signs off. While a step runs you can keep asking; requests for changes
340
340
  wait for the next rest. When the process finishes, Claude offers to squash it
341
341
  and open its pull request(s) (or run `/gtd ship`; `GTD_SHIP_MODE` picks one
342
- stacked pull request per slice or one commit per slice, see the
343
- [driver doc](docs/driver.md)); a process started for an issue ships with
344
- `Closes #N` on its top pull request; a later process on an already-stacked
345
- branch, such as review fixes, lands one commit per slice on the top pull request
346
- and keeps the stack; a closed pull request whose branch was deleted from origin
347
- is left behind and a new one opens; re-running `/gtd ship` after a lower stacked
348
- pull request merged restacks the rest (it refuses, with nothing changed, when
349
- that pull request merged anywhere but the default branch (unless into a lower
350
- slice branch before that one merged into it), a slice branch is checked out in
351
- another worktree, an unrelated local branch sits inside the rebased commits, or
352
- a slice's change is already upstream; a failed rebase is rolled back; to tear a
353
- stack down from its worktree, delete the top branch with
354
- `git push origin --delete`, since `gh pr close --delete-branch` cannot). A
355
- process can change hands at any gate: ask Claude to hand it off (or run
356
- `/gtd throw @dev`) and it opens a draft pull request assigned to them, and
357
- `/gtd catch <pr>` picks it up exactly where it waits, so whoever wrote the
358
- requirements can hand the build to someone else. Ship, hand-off and throw answer
359
- at once and run in the background, with progress on the status line; they report
360
- by waking Claude, a toast, a transcript line and a push notification, and a
361
- failed push or `gh` call reports as a failure. While a ship or hand-off runs or
362
- is queued, `/gtd catch`, the doors, `/gtd <requirements>` and bare `/gtd` wait
363
- for its report. See
342
+ commit per slice under one pull request (the default) or, set to `stack`, one
343
+ stacked pull request per slice, see the [driver doc](docs/driver.md)); a process
344
+ started for an issue ships with `Closes #N` on its top pull request; a closed
345
+ pull request whose branch was deleted from origin is left behind and a new one
346
+ opens; on a branch an earlier ship in this clone stacked (unless
347
+ `GTD_SHIP_MODE=commits`), a later process, such as review fixes, lands one
348
+ commit per slice on the top pull request and keeps the stack, and re-running
349
+ `/gtd ship` after a lower stacked pull request merged restacks the rest (it
350
+ refuses, with nothing changed, when that pull request merged anywhere but the
351
+ default branch (unless into a lower slice branch before that one merged into
352
+ it), a slice branch is checked out in another worktree, an unrelated local
353
+ branch sits inside the rebased commits, or a slice's change is already upstream;
354
+ a failed rebase is rolled back; to tear a stack down from its worktree, delete
355
+ the top branch with `git push origin --delete`, since
356
+ `gh pr close --delete-branch` cannot). A process can change hands at any gate:
357
+ ask Claude to hand it off (or run `/gtd throw @dev`) and it opens a draft pull
358
+ request assigned to them, and `/gtd catch <pr>` picks it up exactly where it
359
+ waits, so whoever wrote the requirements can hand the build to someone else.
360
+ Ship, hand-off and throw answer at once and run in the background, with progress
361
+ on the status line; they report by waking Claude, a toast, a transcript line and
362
+ a push notification, and a failed push or `gh` call reports as a failure. While
363
+ a ship or hand-off runs or is queued, `/gtd catch`, the doors,
364
+ `/gtd <requirements>` and bare `/gtd` wait for its report. See
364
365
  [Inside Claude Code](https://github.com/pmelab/gtd/blob/main/docs/driver.md#inside-claude-code-the-gtd-mod).
365
366
 
366
367
  ### Then let an agent build your own
@@ -49,7 +49,7 @@ export function costTrailers(log: string) {
49
49
  export type ShipMode = "stack" | "commits"
50
50
 
51
51
  export function shipMode(raw: string | undefined): ShipMode | { refusal: string } {
52
- if (!raw) return "stack"
52
+ if (!raw) return "commits"
53
53
  if (raw === "stack" || raw === "commits") return raw
54
54
  return { refusal: `GTD_SHIP_MODE must be 'stack' or 'commits', not '${raw}'.` }
55
55
  }
@@ -209,8 +209,8 @@ async function preflight(git: Git, ok: Ok) {
209
209
  }
210
210
 
211
211
  export async function ship(io: ShipIo, isDry: boolean, rawMode?: string): Promise<Shipped> {
212
- const mode = shipMode(rawMode)
213
- if (typeof mode === "object") return fail(mode.refusal)
212
+ const valid = shipMode(rawMode)
213
+ if (typeof valid === "object") return fail(valid.refusal)
214
214
  const git = async (...args: string[]) => (await io.run(["git", ...args])).out.trim()
215
215
  const ok = async (...args: string[]) => (await io.run(["git", ...args])).code === 0
216
216
 
@@ -223,6 +223,10 @@ export async function ship(io: ShipIo, isDry: boolean, rawMode?: string): Promis
223
223
  const live = names(await git("config", "--local", "--get", STACK_KEY(branch)))
224
224
  const retired = names(await git("config", "--local", "--get", RETIRED_KEY(branch)))
225
225
  const recorded = [...live, ...retired]
226
+ // Unset keeps a live stack stacking: commits mode would retarget its top PR
227
+ // and strand the lower ones. A dead record ships as commits.
228
+ const stacked = !rawMode && live.length > 0 && (await chainsToHead(git, ok, branch, live))
229
+ const mode: ShipMode = stacked ? "stack" : valid
226
230
  const squashed = await squash(io, git, ok, branch, baseBranch, isDry, mode)
227
231
  if (!squashed.ok) return squashed
228
232
  // Until the PR step succeeds the record only moves aside: a retry must not
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pmelab/gtd",
3
- "version": "31.0.0",
3
+ "version": "32.0.0",
4
4
  "private": false,
5
5
  "description": "Git-aware CLI that emits the next prompt for an autonomous coding agent based on the current repository state",
6
6
  "bin": {