@pmelab/gtd 59.0.0 → 60.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.
Files changed (90) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +42 -38
  3. package/claude/hooks/doors.ts +8 -4
  4. package/dist/chunks/flows-DENt0uWV.mjs +707 -0
  5. package/dist/chunks/{steering-CCNvngSH.mjs → steering-DF_BMadH.mjs} +292 -289
  6. package/dist/chunks/{testkit-CMBAAyRK.mjs → testkit-BvecVjQ0.mjs} +937 -772
  7. package/dist/chunks/{wire-C12dahrH.mjs → wire-DZ8R1RU9.mjs} +9 -2
  8. package/dist/flows.mjs +2 -676
  9. package/dist/gtd.bundle.mjs +1101 -1025
  10. package/dist/steering.mjs +2 -2
  11. package/dist/testkit/gherkin.mjs +371 -82
  12. package/dist/testkit.mjs +3 -2
  13. package/dist/web/main.js +234 -232
  14. package/dist/wire.mjs +2 -2
  15. package/dist/workflow-kit.mjs +3 -3
  16. package/package.json +1 -1
  17. package/skills/authoring/SKILL.md +68 -61
  18. package/src/cli/Cli.test.ts +311 -229
  19. package/src/cli/Cli.ts +486 -585
  20. package/src/cli/Help.test.ts +47 -0
  21. package/src/cli/Help.ts +70 -0
  22. package/src/cli/History.ts +9 -4
  23. package/src/cli/Judges.ts +1 -1
  24. package/src/cli/Output.test.ts +35 -0
  25. package/src/cli/Output.ts +31 -1
  26. package/src/cli/Program.test.ts +131 -82
  27. package/src/cli/Program.ts +197 -111
  28. package/src/edge/Edge.test.ts +64 -56
  29. package/src/edge/Edge.ts +4 -4
  30. package/src/emit/Emit.test.ts +1 -1
  31. package/src/emit/Emit.ts +1 -1
  32. package/src/flows/factory.test.ts +14 -0
  33. package/src/flows/factory.ts +25 -6
  34. package/src/flows/helpers.test.ts +35 -0
  35. package/src/flows/helpers.ts +19 -10
  36. package/src/flows/index.test.ts +66 -0
  37. package/src/flows/index.ts +109 -5
  38. package/src/flows/internal.ts +7 -0
  39. package/src/flows/runtime.test.ts +192 -1
  40. package/src/flows/runtime.ts +188 -54
  41. package/src/gherkin/git-control.feature +6 -6
  42. package/src/gherkin/index.test.ts +127 -0
  43. package/src/gherkin/index.ts +481 -98
  44. package/src/gherkin/messages.test.ts +124 -0
  45. package/src/gherkin/messages.ts +101 -0
  46. package/src/gherkin/more-steps.feature +170 -0
  47. package/src/gherkin/scenario-end.feature +101 -0
  48. package/src/gherkin/testkit.feature +83 -7
  49. package/src/install/Install.test.ts +7 -7
  50. package/src/install/Install.ts +8 -8
  51. package/src/replay/Replay.test.ts +13 -2
  52. package/src/replay/Replay.ts +19 -30
  53. package/src/replay/judgeDiffShape.test.ts +1 -1
  54. package/src/steering/Footnotes.test.ts +1 -1
  55. package/src/steering/SteeringFormats.test.ts +1 -1
  56. package/src/steering/freeform.test.ts +1 -1
  57. package/src/steering/index.test.ts +27 -1
  58. package/src/steering/index.ts +6 -104
  59. package/src/steering/internal.ts +11 -0
  60. package/src/steering/qa.test.ts +7 -2
  61. package/src/steering/reads.test.ts +42 -0
  62. package/src/steering/reads.ts +43 -0
  63. package/src/steering/registry.ts +93 -0
  64. package/src/steering/review.test.ts +2 -2
  65. package/src/step/planStart.test.ts +18 -16
  66. package/src/step/planStart.ts +9 -9
  67. package/src/testkit/TestRepo.test.ts +289 -6
  68. package/src/testkit/TestRepo.ts +317 -41
  69. package/src/testkit/imports.test.ts +58 -0
  70. package/src/testkit/imports.ts +102 -0
  71. package/src/testkit/index.test.ts +28 -0
  72. package/src/testkit/index.ts +14 -2
  73. package/src/twins/EmittedScriptRecognizer.ts +7 -14
  74. package/src/twins/EmittedScripts.test.ts +4 -2
  75. package/src/twins/InMemRepo.ts +1 -0
  76. package/src/wire/Land.ts +1 -1
  77. package/src/wire/Script.ts +11 -0
  78. package/src/wire/WireSchema.test.ts +3 -0
  79. package/src/wire/golden/1/script.json +4 -0
  80. package/src/wire/index.ts +1 -0
  81. package/src/workflow/SteeringFormats.test.ts +1 -1
  82. package/src/workflow/compile.ts +2 -2
  83. package/src/workflow/discovery.test.ts +3 -3
  84. package/src/workflow/load.test.ts +256 -116
  85. package/src/workflow/load.ts +175 -152
  86. package/src/workflow/skills.test.ts +5 -5
  87. package/src/workflow/skills.ts +1 -1
  88. package/src/workflow-kit/index.test.ts +25 -0
  89. package/src/workflow-kit/index.ts +37 -4
  90. package/src/workflow-kit/review.ts +2 -2
@@ -0,0 +1,127 @@
1
+ import { describe, expect, it } from "vitest"
2
+ import type { TestContext } from "vitest"
3
+ import { applyHooks, type InfoConstructor } from "quickpickle"
4
+ import { agent, human } from "../flows/index.js"
5
+ import { TestkitWorld } from "./index.js"
6
+
7
+ const flow = async (): Promise<void> => {
8
+ await agent("plan", "Write PLAN.md.")
9
+ await human("sign-off")
10
+ await agent("ship", "Ship it.")
11
+ await human("done")
12
+ }
13
+
14
+ type Common = TestkitWorld["common"]
15
+
16
+ const feature = (): Common => ({ info: { feature: "Feature: shipping", tags: [] } })
17
+
18
+ // `ship` scripted by a Background step (quickpickle numbers those negatively) or by the scenario.
19
+ const world = (
20
+ shipFrom: "Background" | "scenario" = "scenario",
21
+ common = feature(),
22
+ ): TestkitWorld => {
23
+ const info = { feature: "", scenario: "", tags: [], steps: [], common, config: {} }
24
+ const created = new TestkitWorld({} as TestContext, info as unknown as InfoConstructor)
25
+ created.common = common
26
+ created.configure({ default: flow })
27
+ created.act("plan", (_, repo) => repo.write("PLAN.md", "p\n"))
28
+ created.info.stepIdx = shipFrom === "Background" ? -1 : 1
29
+ created.act("ship", (_, repo) => repo.write("SHIPPED.md", "s\n"))
30
+ created.info.stepIdx = 2
31
+ created.repo().write("go", "\n")
32
+ return created
33
+ }
34
+
35
+ describe("TestkitWorld's scenario-end check", () => {
36
+ it("passes a step a later drive reaches, though an earlier one rested before it", async () => {
37
+ const scenario = world()
38
+ await scenario.drive()
39
+ scenario.act("sign-off", (_, repo) => repo.write("SIGNED.md", "x\n"))
40
+ await scenario.drive()
41
+ await expect(scenario.assertReached()).resolves.toBeUndefined()
42
+ })
43
+
44
+ it("fails on a step no drive reached, naming it", async () => {
45
+ const scenario = world()
46
+ await scenario.drive()
47
+ await expect(scenario.assertReached()).rejects.toThrow(
48
+ 'at scenario end, no drive reached the steps scripted for "ship" (scenario)',
49
+ )
50
+ })
51
+
52
+ it("fails on a step no drive reached though every drive was lenient", async () => {
53
+ const scenario = world()
54
+ await scenario.drive({ strict: false })
55
+ await expect(scenario.assertReached()).rejects.toThrow('"ship" (scenario)')
56
+ })
57
+
58
+ it("leaves a step only a Background scripted to the feature's end", async () => {
59
+ const scenario = world("Background")
60
+ await scenario.drive()
61
+ await expect(scenario.assertReached()).resolves.toBeUndefined()
62
+ })
63
+
64
+ it("checks a step the Background scripted and the scenario scripts again", async () => {
65
+ const scenario = world("Background")
66
+ scenario.act("ship", () => undefined)
67
+ await scenario.drive()
68
+ await expect(scenario.assertReached()).rejects.toThrow('"ship" (scenario)')
69
+ })
70
+
71
+ it("excuses the steps a refused drive was handed, not those scripted after it", async () => {
72
+ const scenario = world()
73
+ scenario.act("sign-off", () => undefined)
74
+ await expect(scenario.drive()).rejects.toThrow("changed nothing")
75
+ await expect(scenario.assertReached()).resolves.toBeUndefined()
76
+ scenario.act("done", (_, repo) => repo.write("DONE.md", "d\n"))
77
+ await expect(scenario.assertReached()).rejects.toThrow('"done" (scenario)')
78
+ })
79
+ })
80
+
81
+ describe("the feature-end check of Background steps", () => {
82
+ const scenarioEnd = async (scenario: TestkitWorld): Promise<void> => {
83
+ await applyHooks("after", scenario)
84
+ }
85
+
86
+ it("fails on a Background step no scenario of the feature reached, naming it", async () => {
87
+ const common = feature()
88
+ const scenario = world("Background", common)
89
+ await scenario.drive()
90
+ await scenarioEnd(scenario)
91
+ await expect(applyHooks("afterAll", common)).rejects.toThrow(
92
+ 'Feature: shipping: no scenario reached the steps scripted for "ship" (Background)',
93
+ )
94
+ })
95
+
96
+ it("passes a Background step one scenario of the feature reached", async () => {
97
+ const common = feature()
98
+ const resting = world("Background", common)
99
+ await resting.drive()
100
+ await scenarioEnd(resting)
101
+ const shipping = world("Background", common)
102
+ await shipping.drive()
103
+ shipping.act("sign-off", (_, repo) => repo.write("SIGNED.md", "x\n"))
104
+ await shipping.drive()
105
+ await scenarioEnd(shipping)
106
+ await expect(applyHooks("afterAll", common)).resolves.toBe(common)
107
+ })
108
+
109
+ it("counts a failed scenario as reaching its Background steps", async () => {
110
+ const common = feature()
111
+ const scenario = world("Background", common)
112
+ await scenario.drive()
113
+ scenario.info.errors.push(new Error("a step failed"))
114
+ await scenarioEnd(scenario)
115
+ await expect(applyHooks("afterAll", common)).resolves.toBe(common)
116
+ })
117
+
118
+ it("is left out when a scenario of the file did not run", async () => {
119
+ const common = feature()
120
+ const scenario = world("Background", common)
121
+ const tasks = [{ mode: "run", result: { state: "pass" } }, { tasks: [{ mode: "skip" }] }]
122
+ Object.assign(scenario, { context: { task: { file: { tasks } } } })
123
+ await scenario.drive()
124
+ await scenarioEnd(scenario)
125
+ await expect(applyHooks("afterAll", common)).resolves.toBe(common)
126
+ })
127
+ })