@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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +10 -8
- package/dist/chunks/{testkit-XQeYCNMn.mjs → testkit-CPzWnl3P.mjs} +56 -2
- package/dist/gtd.bundle.mjs +55 -0
- package/dist/gtd.core.mjs +76 -73
- package/dist/testkit/gherkin.mjs +1 -1
- package/dist/testkit.mjs +1 -1
- package/package.json +1 -1
- package/src/cli/Cli.test.ts +2 -0
- package/src/cli/Cli.ts +12 -0
- package/src/cli/Launch.ts +1 -0
- package/src/cli/Program.test.ts +3 -1
- package/src/cli/Program.ts +41 -0
- package/src/emit/GitScript.ts +7 -0
- package/src/emit/index.ts +1 -0
- package/src/twins/EmittedScriptRecognizer.ts +3 -2
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`,
|
|
628
|
-
`help`, `history list`, `history show`, `history metrics`,
|
|
629
|
-
`history fetch`, `strays`, the tools `ui`, `lsp`, `judge`
|
|
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
|
|
650
|
-
run live, and `gtd --live <command>` runs the live engine for any other,
|
|
651
|
-
risk of misreading the process.
|
|
652
|
-
|
|
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
|
}
|
package/dist/gtd.bundle.mjs
CHANGED
|
@@ -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",
|