@pmelab/gtd 62.0.0 → 62.1.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": "62.0.0",
3
+ "version": "62.1.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
@@ -624,10 +624,10 @@ install for any of these but the testkit's: gtd resolves a `gtd.config.ts`'s
624
624
  `@pmelab/gtd/*` imports to its own copy.
625
625
 
626
626
  The `gtd` bin's commands — `next`, `land`, `start`, `abandon`, `restore`,
627
- `validate`, `check`, `uncheck`, `guide`, `bundle`, `summary`, `base`, `version`,
628
- `help`, `history list`, `history show`, `history metrics`, `history judges`,
629
- `history fetch`, `strays`, the tools `ui`, `lsp`, `judge` (`judge answer`,
630
- `judge run`) — are listed in the
627
+ `repin`, `validate`, `check`, `uncheck`, `guide`, `bundle`, `summary`, `base`,
628
+ `version`, `help`, `history list`, `history show`, `history metrics`,
629
+ `history judges`, `history fetch`, `strays`, the tools `ui`, `lsp`, `judge`
630
+ (`judge answer`, `judge run`) — are listed in the
631
631
  [CLI reference](https://github.com/pmelab/gtd/blob/main/docs/cli.md). Every
632
632
  command that prints a script takes `--json=script`, and `--` ends the options.
633
633
 
@@ -646,10 +646,12 @@ Histories with pin commits are history format 2, which an older gtd refuses.
646
646
  While a process is pinned, the `gtd` on your `PATH` hands every command over to
647
647
  the pin, so editing the workflow or upgrading gtd mid-process changes nothing;
648
648
  gtd notes on stderr when the live config differs from the pinned one. `ui`,
649
- `lsp`, `guide`, `bundle`, `help`, `version` and the `history` commands always
650
- run live, and `gtd --live <command>` runs the live engine for any other, at the
651
- risk of misreading the process. A pin in a format your gtd does not know is
652
- refused: upgrade gtd. See
649
+ `lsp`, `guide`, `bundle`, `repin`, `help`, `version` and the `history` commands
650
+ always run live, and `gtd --live <command>` runs the live engine for any other,
651
+ at the risk of misreading the process. To fix a workflow mid-process, edit it
652
+ and run `gtd repin`: its script commits a fresh pin from the live engine and
653
+ config, and the process continues on it. A pin in a format your gtd does not
654
+ know is refused: upgrade gtd. See
653
655
  [Pinned processes](https://github.com/pmelab/gtd/blob/main/docs/cli.md#pinned-processes).
654
656
 
655
657
  ## License
@@ -24610,6 +24610,12 @@ const pinScript = (path) => {
24610
24610
  const slash = path.lastIndexOf("/");
24611
24611
  return `${slash === -1 ? "" : `mkdir -p ${shellQuote(path.slice(0, slash))}\n`}gtd bundle >${p} || { rm -f -- ${p}; exit 1; }`;
24612
24612
  };
24613
+ /** `gtd repin`'s pin write: a failed `gtd bundle` leaves the committed pin in place. */
24614
+ const repinScript = (path) => {
24615
+ const p = shellQuote(path);
24616
+ const next = shellQuote(`${path}.new`);
24617
+ return `gtd bundle >${next} || { rm -f -- ${next}; exit 1; }\nmv -f -- ${next} ${p}`;
24618
+ };
24613
24619
  /** An unpin beat's script, and `gtd abandon`'s removal of the pin. */
24614
24620
  const unpinScript = (path) => `rm -f -- ${shellQuote(path)}`;
24615
24621
  /**
@@ -24850,6 +24856,12 @@ const FMT_ABANDONED = "abandoned the process resting at \"%s\" — HEAD is back
24850
24856
  const FMT_RESTORED = "restored the retained history — HEAD is back at %s (\"%s\"), resting at \"%s\". Resume with the loop, or `git reset` to any earlier turn to restart from there.\n";
24851
24857
  /** `no gtd process is underway (resting at "<initial>") — nothing to abandon` — `gtd abandon`'s no-op plain-text line. */
24852
24858
  const abandonNoopText = (initial) => renderFormat(FMT_ABANDON_NOOP, initial);
24859
+ /** A landed self-loop/target-change transition. */
24860
+ const transitionOutcome = (from, to) => printfLine("%s %s → %s\n", [
24861
+ "'->'",
24862
+ shellQuote(from),
24863
+ shellQuote(to)
24864
+ ]);
24853
24865
  /** One already-rendered plain line. */
24854
24866
  const noteOutcome = (text) => printfLine("%s\n", [shellQuote(text)]);
24855
24867
  /**
@@ -27328,6 +27340,36 @@ const runRestoreCommand = (json, out) => gen(function* () {
27328
27340
  yield* writeScript(json, out, combinedScript(required, ""));
27329
27341
  });
27330
27342
  /**
27343
+ * `gtd repin`: the pin beat's script and landing, on demand. It runs live,
27344
+ * so reading the rest first refuses a live workflow that cannot replay the
27345
+ * process before any pin is written.
27346
+ */
27347
+ const runRepinCommand = (json, out) => gen(function* () {
27348
+ const rest = yield* currentRest;
27349
+ const refusal = rest.pin === "add" ? "the next beat pins the process already — run it (`gtd next --json=content`), then land" : rest.pin === "remove" ? "the flow has ended — its unpin beat is next, so there is nothing to repin" : noProcessUnderway(rest) ? "no gtd process is underway — nothing to repin" : void 0;
27350
+ if (refusal !== void 0) return yield* fail$4(/* @__PURE__ */ new Error(`gtd repin: ${refusal}`));
27351
+ const message = formatCommitMessage({
27352
+ actor: "check",
27353
+ from: PIN_STATES.add,
27354
+ to: rest.step.name,
27355
+ pin: "add"
27356
+ });
27357
+ yield* writeScript(json, out, combinedScript(emitScripts([
27358
+ {
27359
+ kind: "gitWrite",
27360
+ command: repinScript(PIN_PATH)
27361
+ },
27362
+ {
27363
+ kind: "gitWrite",
27364
+ command: commitPath(PIN_PATH, message)
27365
+ },
27366
+ {
27367
+ kind: "outcome",
27368
+ command: transitionOutcome(PIN_STATES.add, rest.step.name)
27369
+ }
27370
+ ]).required, ""));
27371
+ });
27372
+ /**
27331
27373
  * The mode's own validate command for `file`: a declared `validate:` command
27332
27374
  * verbatim; a `"builtin"` validator or no mode at all names the leaf
27333
27375
  * `gtd check <mode>` invocation instead, so there's always something concrete
@@ -27594,6 +27636,7 @@ const dispatchVoidCommand = (command, json, out) => {
27594
27636
  case "start": return runStartCommand(command, json, out);
27595
27637
  case "abandon": return runAbandonCommand(json, out);
27596
27638
  case "restore": return runRestoreCommand(json, out);
27639
+ case "repin": return runRepinCommand(json, out);
27597
27640
  case "next": return runNextCommand(json, out);
27598
27641
  case "validate": return runValidateCommand(json, out);
27599
27642
  case "check":
@@ -27722,6 +27765,7 @@ const SCRIPT_KINDS = /* @__PURE__ */ new Set([
27722
27765
  "start",
27723
27766
  "abandon",
27724
27767
  "restore",
27768
+ "repin",
27725
27769
  "validate",
27726
27770
  "historyFetch"
27727
27771
  ]);
@@ -27989,6 +28033,16 @@ With no <name>, list every workflow and door it can start. An unknown <name>, th
27989
28033
  summary: "Bring back the last abandoned process",
27990
28034
  details: `Bring back the process the last \`gtd abandon\` stopped: the printed script resets HEAD to that process's last commit. Refuses on a dirty working tree, when nothing was abandoned, or when commits made since would be lost.`
27991
28035
  },
28036
+ {
28037
+ token: "repin",
28038
+ kind: "repin",
28039
+ arity: "none",
28040
+ group: "Start and stop",
28041
+ summary: "Pin the process to the live gtd and workflow",
28042
+ details: `Switch the process underway to the live engine and workflow, the way out when the workflow needs a fix mid-process: the printed script runs the pin beat again, writing \`gtd bundle\`'s output to .gtd/process.gtdpin and committing that file alone. Always runs on the gtd on PATH, never on the pin. Refuses when no process is underway, when the next beat is a pin or unpin beat already, or when the live workflow does not replay the process.
28043
+
28044
+ s=$(gtd repin --json=script) && sh -c "$s"`
28045
+ },
27992
28046
  {
27993
28047
  token: "summary",
27994
28048
  kind: "summary",
@@ -29892,9 +29946,9 @@ const recognizeGitBuilders = (repo, block) => {
29892
29946
  };
29893
29947
  /** What the in-memory `gtd bundle` prints: a pin header, and no engine behind it. */
29894
29948
  const IN_MEMORY_PIN = "gtdpin 1 gtd in-memory\n";
29895
- /** A pin or unpin beat's script. */
29949
+ /** A pin or unpin beat's script, or `gtd repin`'s. */
29896
29950
  const recognizePinScripts = (repo, block) => {
29897
- if (block === pinScript(".gtd/process.gtdpin")) {
29951
+ if (block === pinScript(".gtd/process.gtdpin") || block === repinScript(".gtd/process.gtdpin")) {
29898
29952
  repo.writeFile(PIN_PATH, IN_MEMORY_PIN);
29899
29953
  return { kind: "applied" };
29900
29954
  }
@@ -31335,6 +31335,12 @@ const pinScript = (path) => {
31335
31335
  const slash = path.lastIndexOf("/");
31336
31336
  return `${slash === -1 ? "" : `mkdir -p ${shellQuote$1(path.slice(0, slash))}\n`}gtd bundle >${p} || { rm -f -- ${p}; exit 1; }`;
31337
31337
  };
31338
+ /** `gtd repin`'s pin write: a failed `gtd bundle` leaves the committed pin in place. */
31339
+ const repinScript = (path) => {
31340
+ const p = shellQuote$1(path);
31341
+ const next = shellQuote$1(`${path}.new`);
31342
+ return `gtd bundle >${next} || { rm -f -- ${next}; exit 1; }\nmv -f -- ${next} ${p}`;
31343
+ };
31338
31344
  /** An unpin beat's script, and `gtd abandon`'s removal of the pin. */
31339
31345
  const unpinScript = (path) => `rm -f -- ${shellQuote$1(path)}`;
31340
31346
  /**
@@ -31563,6 +31569,12 @@ const FMT_ABANDONED = "abandoned the process resting at \"%s\" — HEAD is back
31563
31569
  const FMT_RESTORED = "restored the retained history — HEAD is back at %s (\"%s\"), resting at \"%s\". Resume with the loop, or `git reset` to any earlier turn to restart from there.\n";
31564
31570
  /** `no gtd process is underway (resting at "<initial>") — nothing to abandon` — `gtd abandon`'s no-op plain-text line. */
31565
31571
  const abandonNoopText = (initial) => renderFormat(FMT_ABANDON_NOOP, initial);
31572
+ /** A landed self-loop/target-change transition. */
31573
+ const transitionOutcome = (from, to) => printfLine("%s %s → %s\n", [
31574
+ "'->'",
31575
+ shellQuote$1(from),
31576
+ shellQuote$1(to)
31577
+ ]);
31566
31578
  /** One already-rendered plain line. */
31567
31579
  const noteOutcome = (text) => printfLine("%s\n", [shellQuote$1(text)]);
31568
31580
  /**
@@ -34055,6 +34067,36 @@ const runRestoreCommand = (json, out) => gen(function* () {
34055
34067
  yield* writeScript(json, out, combinedScript(required, ""));
34056
34068
  });
34057
34069
  /**
34070
+ * `gtd repin`: the pin beat's script and landing, on demand. It runs live,
34071
+ * so reading the rest first refuses a live workflow that cannot replay the
34072
+ * process before any pin is written.
34073
+ */
34074
+ const runRepinCommand = (json, out) => gen(function* () {
34075
+ const rest = yield* currentRest;
34076
+ const refusal = rest.pin === "add" ? "the next beat pins the process already — run it (`gtd next --json=content`), then land" : rest.pin === "remove" ? "the flow has ended — its unpin beat is next, so there is nothing to repin" : noProcessUnderway(rest) ? "no gtd process is underway — nothing to repin" : void 0;
34077
+ if (refusal !== void 0) return yield* fail$8(/* @__PURE__ */ new Error(`gtd repin: ${refusal}`));
34078
+ const message = formatCommitMessage({
34079
+ actor: "check",
34080
+ from: PIN_STATES.add,
34081
+ to: rest.step.name,
34082
+ pin: "add"
34083
+ });
34084
+ yield* writeScript(json, out, combinedScript(emitScripts([
34085
+ {
34086
+ kind: "gitWrite",
34087
+ command: repinScript(PIN_PATH)
34088
+ },
34089
+ {
34090
+ kind: "gitWrite",
34091
+ command: commitPath(PIN_PATH, message)
34092
+ },
34093
+ {
34094
+ kind: "outcome",
34095
+ command: transitionOutcome(PIN_STATES.add, rest.step.name)
34096
+ }
34097
+ ]).required, ""));
34098
+ });
34099
+ /**
34058
34100
  * The mode's own validate command for `file`: a declared `validate:` command
34059
34101
  * verbatim; a `"builtin"` validator or no mode at all names the leaf
34060
34102
  * `gtd check <mode>` invocation instead, so there's always something concrete
@@ -34321,6 +34363,7 @@ const dispatchVoidCommand = (command, json, out) => {
34321
34363
  case "start": return runStartCommand(command, json, out);
34322
34364
  case "abandon": return runAbandonCommand(json, out);
34323
34365
  case "restore": return runRestoreCommand(json, out);
34366
+ case "repin": return runRepinCommand(json, out);
34324
34367
  case "next": return runNextCommand(json, out);
34325
34368
  case "validate": return runValidateCommand(json, out);
34326
34369
  case "check":
@@ -34450,6 +34493,7 @@ const SCRIPT_KINDS = /* @__PURE__ */ new Set([
34450
34493
  "start",
34451
34494
  "abandon",
34452
34495
  "restore",
34496
+ "repin",
34453
34497
  "validate",
34454
34498
  "historyFetch"
34455
34499
  ]);
@@ -34717,6 +34761,16 @@ With no <name>, list every workflow and door it can start. An unknown <name>, th
34717
34761
  summary: "Bring back the last abandoned process",
34718
34762
  details: `Bring back the process the last \`gtd abandon\` stopped: the printed script resets HEAD to that process's last commit. Refuses on a dirty working tree, when nothing was abandoned, or when commits made since would be lost.`
34719
34763
  },
34764
+ {
34765
+ token: "repin",
34766
+ kind: "repin",
34767
+ arity: "none",
34768
+ group: "Start and stop",
34769
+ summary: "Pin the process to the live gtd and workflow",
34770
+ details: `Switch the process underway to the live engine and workflow, the way out when the workflow needs a fix mid-process: the printed script runs the pin beat again, writing \`gtd bundle\`'s output to .gtd/process.gtdpin and committing that file alone. Always runs on the gtd on PATH, never on the pin. Refuses when no process is underway, when the next beat is a pin or unpin beat already, or when the live workflow does not replay the process.
34771
+
34772
+ s=$(gtd repin --json=script) && sh -c "$s"`
34773
+ },
34720
34774
  {
34721
34775
  token: "summary",
34722
34776
  kind: "summary",
@@ -35418,6 +35472,7 @@ const LIVE_KINDS = /* @__PURE__ */ new Set([
35418
35472
  "lsp",
35419
35473
  "guide",
35420
35474
  "bundle",
35475
+ "repin",
35421
35476
  "historyList",
35422
35477
  "historyShow",
35423
35478
  "historyMetrics",