@pmelab/gtd 24.0.0 → 24.2.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 (203) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +42 -13
  3. package/claude/hooks/access.ts +26 -1
  4. package/claude/hooks/assist.ts +135 -0
  5. package/claude/hooks/drive.ts +15 -7
  6. package/claude/hooks/judge.ts +27 -0
  7. package/claude/hooks/register.tsx +294 -135
  8. package/claude/hooks/tools.ts +121 -0
  9. package/claude/hooks/wording.ts +2 -35
  10. package/claude/types/index.d.ts +9 -0
  11. package/dist/chunks/Schema-Dh-mkwkq.mjs +25353 -0
  12. package/dist/chunks/reserved-ejn-LVYO.mjs +1388 -0
  13. package/dist/chunks/rolldown-runtime-8H4AJuhK.mjs +14 -0
  14. package/dist/chunks/steering-D-PvRC5W.mjs +16296 -0
  15. package/dist/chunks/wire-DA7q2ikx.mjs +473 -0
  16. package/dist/flows.mjs +525 -0
  17. package/dist/gtd.bundle.mjs +43339 -55575
  18. package/dist/steering.mjs +2 -0
  19. package/dist/testkit.mjs +13006 -0
  20. package/dist/wire.mjs +2 -0
  21. package/dist/workflow-kit.mjs +352 -0
  22. package/dist/workflows/feature.mjs +315 -0
  23. package/dist/workflows/fix.mjs +40 -0
  24. package/dist/workflows/review.mjs +25 -0
  25. package/dist/workflows.mjs +8 -6
  26. package/package.json +69 -8
  27. package/src/cli/Cli.test.ts +1329 -0
  28. package/src/cli/Cli.ts +1348 -0
  29. package/src/cli/Program.test.ts +2262 -0
  30. package/src/cli/Program.ts +1331 -0
  31. package/src/cli/ToolCommands.ts +43 -0
  32. package/src/cli/index.ts +14 -0
  33. package/src/edge/Edge.test.ts +1016 -0
  34. package/src/edge/Edge.ts +1225 -0
  35. package/src/edge/index.ts +16 -0
  36. package/src/emit/Emit.test.ts +425 -0
  37. package/src/emit/Emit.ts +139 -0
  38. package/src/emit/GitScript.test.ts +260 -0
  39. package/src/emit/GitScript.ts +131 -0
  40. package/src/emit/ModeContradiction.test.ts +120 -0
  41. package/src/emit/ModeContradiction.ts +66 -0
  42. package/src/emit/OutcomeScript.test.ts +238 -0
  43. package/src/emit/OutcomeScript.ts +73 -0
  44. package/src/emit/SteeringMode.test.ts +274 -0
  45. package/src/emit/SteeringMode.ts +256 -0
  46. package/src/emit/index.ts +40 -0
  47. package/src/install/ConfigScaffold.ts +19 -0
  48. package/src/install/Install.test.ts +426 -0
  49. package/src/install/Install.ts +634 -0
  50. package/src/install/Version.ts +27 -0
  51. package/src/install/index.ts +3 -0
  52. package/src/platform/CommandRunner.ts +74 -0
  53. package/src/platform/Commentary.test.ts +126 -0
  54. package/src/platform/Commentary.ts +92 -0
  55. package/src/platform/Git.test.ts +50 -0
  56. package/src/platform/Git.ts +552 -0
  57. package/src/platform/Host.ts +42 -0
  58. package/src/platform/RetainedHistory.test.ts +65 -0
  59. package/src/platform/RetainedHistory.ts +34 -0
  60. package/src/platform/Workspace.test.ts +669 -0
  61. package/src/platform/Workspace.ts +631 -0
  62. package/src/platform/WorktreeState.test.ts +162 -0
  63. package/src/platform/WorktreeState.ts +50 -0
  64. package/src/platform/index.ts +22 -0
  65. package/src/replay/Access.test.ts +53 -0
  66. package/src/replay/Access.ts +46 -0
  67. package/src/replay/Format.test.ts +20 -0
  68. package/src/replay/Format.ts +14 -0
  69. package/src/replay/Replay.test.ts +887 -0
  70. package/src/replay/Replay.ts +669 -0
  71. package/src/replay/Trailers.test.ts +117 -0
  72. package/src/replay/Trailers.ts +213 -0
  73. package/src/replay/Tree.test.ts +25 -0
  74. package/src/replay/Tree.ts +45 -0
  75. package/src/replay/index.ts +11 -0
  76. package/src/steering/Blocks.fixture.ts +6 -0
  77. package/src/steering/Blocks.test.ts +167 -0
  78. package/src/steering/Blocks.ts +321 -0
  79. package/src/steering/CodeThreads.test.ts +127 -0
  80. package/src/steering/CodeThreads.ts +197 -0
  81. package/src/steering/Edits.test.ts +19 -0
  82. package/src/steering/Edits.ts +20 -0
  83. package/src/steering/Eol.test.ts +16 -0
  84. package/src/steering/Eol.ts +2 -0
  85. package/src/steering/FORMATS.md +58 -0
  86. package/src/steering/Footnotes.test.ts +977 -0
  87. package/src/steering/Footnotes.ts +661 -0
  88. package/src/steering/Inline.fixture.ts +7 -0
  89. package/src/steering/Inline.test.ts +227 -0
  90. package/src/steering/Inline.ts +195 -0
  91. package/src/steering/MarkdownTree.test.ts +247 -0
  92. package/src/steering/MarkdownTree.ts +260 -0
  93. package/src/steering/Outline.ts +19 -0
  94. package/src/steering/SteeringFormat.test.ts +91 -0
  95. package/src/steering/SteeringFormat.ts +267 -0
  96. package/src/steering/SteeringFormats.test.ts +163 -0
  97. package/src/steering/Threads.ts +163 -0
  98. package/src/steering/contract.test.ts +264 -0
  99. package/src/steering/fixtures/code-threads/cache.stripped.ts.txt +6 -0
  100. package/src/steering/fixtures/code-threads/cache.ts.md +15 -0
  101. package/src/steering/fixtures/free-form/notes.md +12 -0
  102. package/src/steering/fixtures/free-form/notes.read.json +42 -0
  103. package/src/steering/fixtures/qa/answered.md +23 -0
  104. package/src/steering/fixtures/qa/answered.read.json +119 -0
  105. package/src/steering/fixtures/qa/requirements.md +160 -0
  106. package/src/steering/fixtures/qa/requirements.read.json +475 -0
  107. package/src/steering/fixtures/review/review.md +76 -0
  108. package/src/steering/fixtures/review/review.read.json +237 -0
  109. package/src/steering/fixtures/review/ticked.md +23 -0
  110. package/src/steering/fixtures/review/ticked.read.json +99 -0
  111. package/src/steering/fixtures/review-notes/baseline.md +14 -0
  112. package/src/steering/fixtures/review-notes/noted.md +19 -0
  113. package/src/steering/freeform.test.ts +311 -0
  114. package/src/steering/freeform.ts +148 -0
  115. package/src/steering/index.test.ts +62 -0
  116. package/src/steering/index.ts +140 -0
  117. package/src/steering/qa.test.ts +2160 -0
  118. package/src/steering/qa.ts +1104 -0
  119. package/src/steering/review.test.ts +1829 -0
  120. package/src/steering/review.ts +1180 -0
  121. package/src/step/LandStep.ts +31 -0
  122. package/src/step/RepoSnapshot.ts +29 -0
  123. package/src/step/accessRefusal.test.ts +58 -0
  124. package/src/step/accessRefusal.ts +26 -0
  125. package/src/step/index.ts +5 -0
  126. package/src/step/planStart.test.ts +202 -0
  127. package/src/step/planStart.ts +167 -0
  128. package/src/step/planStep.test.ts +104 -0
  129. package/src/step/planStep.ts +89 -0
  130. package/src/step/snapshot.fixture.ts +28 -0
  131. package/src/testkit/EmittedScriptRecognizer.test.ts +639 -0
  132. package/src/testkit/EmittedScriptRecognizer.ts +642 -0
  133. package/src/testkit/FakeGitOperations.ts +95 -0
  134. package/src/testkit/GitTiers.test.ts +11 -0
  135. package/src/testkit/GitTiers.ts +1052 -0
  136. package/src/testkit/InMemRepo.ts +467 -0
  137. package/src/testkit/Layers.test.ts +58 -0
  138. package/src/testkit/Layers.ts +241 -0
  139. package/src/testkit/StrictGitOperations.ts +31 -0
  140. package/src/testkit/TestRepo.test.ts +119 -0
  141. package/src/testkit/TestRepo.ts +274 -0
  142. package/src/testkit/cliIo.ts +36 -0
  143. package/src/testkit/index.ts +9 -0
  144. package/src/testkit/steps.ts +177 -0
  145. package/src/testkit/testkit.feature +65 -0
  146. package/src/wire/BeatDocument.test.ts +419 -0
  147. package/src/wire/BeatDocument.ts +114 -0
  148. package/src/wire/BeatPlain.test.ts +113 -0
  149. package/src/wire/BeatPlain.ts +127 -0
  150. package/src/wire/BeatStatus.test.ts +59 -0
  151. package/src/wire/BeatStatus.ts +81 -0
  152. package/src/wire/Demand.test.ts +142 -0
  153. package/src/wire/Demand.ts +108 -0
  154. package/src/wire/ExitCodes.test.ts +21 -0
  155. package/src/wire/ExitCodes.ts +16 -0
  156. package/src/wire/Glob.ts +29 -0
  157. package/src/wire/Judge.ts +22 -0
  158. package/src/wire/Land.test.ts +120 -0
  159. package/src/wire/Land.ts +75 -0
  160. package/src/wire/Select.test.ts +148 -0
  161. package/src/wire/Select.ts +78 -0
  162. package/src/wire/Sessions.test.ts +59 -0
  163. package/src/wire/Sessions.ts +39 -0
  164. package/src/wire/WireSchema.test.ts +162 -0
  165. package/src/wire/constants.ts +22 -0
  166. package/src/wire/golden/1/beat-capture.json +34 -0
  167. package/src/wire/golden/1/beat-message.json +34 -0
  168. package/src/wire/golden/1/beat-prompt.json +44 -0
  169. package/src/wire/golden/1/beat-script.json +34 -0
  170. package/src/wire/golden/1/beat-stalled.json +34 -0
  171. package/src/wire/golden/1/judge.json +14 -0
  172. package/src/wire/golden/1/land-noop.json +10 -0
  173. package/src/wire/golden/1/land.json +10 -0
  174. package/src/wire/index.ts +12 -0
  175. package/src/wire/types.ts +46 -0
  176. package/src/workflow/Diagnostic.test.ts +93 -0
  177. package/src/workflow/Diagnostic.ts +54 -0
  178. package/src/workflow/SteeringFormats.test.ts +27 -0
  179. package/src/workflow/SteeringFormats.ts +6 -0
  180. package/src/workflow/Workflow.ts +77 -0
  181. package/src/workflow/compile.test.ts +53 -0
  182. package/src/workflow/compile.ts +56 -0
  183. package/src/workflow/discovery.ts +122 -0
  184. package/src/workflow/fingerprint.test.ts +52 -0
  185. package/src/workflow/fingerprint.ts +53 -0
  186. package/src/workflow/index.ts +33 -0
  187. package/src/workflow/load.test.ts +1017 -0
  188. package/src/workflow/load.ts +836 -0
  189. package/src/workflow/skills.test.ts +109 -0
  190. package/src/workflow/skills.ts +90 -0
  191. package/src/workflow/vars.ts +33 -0
  192. package/src/workflows/feature/feature.test.ts +27 -33
  193. package/src/workflows/feature/index.ts +10 -0
  194. package/src/workflows/fix/fix.feature +80 -0
  195. package/src/workflows/fix/fix.test.ts +58 -78
  196. package/src/workflows/fix/index.ts +6 -0
  197. package/src/workflows/index.ts +2 -10
  198. package/src/workflows/review/index.ts +6 -0
  199. package/src/workflows/review/review.test.ts +85 -29
  200. package/src/workflows/review/review.ts +3 -1
  201. package/src/workflows/shared/config.fixture.ts +12 -0
  202. package/src/workflows/shared/reserved.ts +11 -0
  203. package/src/workflows/shared/workflows.steps.ts +7 -0
@@ -0,0 +1,121 @@
1
+ // The only way the main session's model moves gtd: tools the mod serves. Each
2
+ // checks the run before it acts, so a model cannot skip a rest or answer one
3
+ // gtd has already left.
4
+
5
+ import type { Run } from "../types"
6
+ import { humanVerdicts } from "./judge"
7
+ import type { Judgment } from "./judge"
8
+
9
+ export const TOOL = {
10
+ continue: "mcp__gtd__continue",
11
+ note: "mcp__gtd__note",
12
+ handoff: "mcp__gtd__handoff",
13
+ ship: "mcp__gtd__ship",
14
+ browser: "mcp__gtd__browser",
15
+ } as const
16
+
17
+ export const TOOLS = [
18
+ {
19
+ name: "continue",
20
+ description:
21
+ "Moves the gtd process on from the step it waits at. Call it ONLY after the person explicitly said to continue. `rest` is the rest id gtd gave you for this step. `verdicts` only at a step gtd's judge could not decide: each question id mapped to the person's chosen answer. Refused when gtd has moved on, while a step runs, or when the step's file does not validate; the result says why.",
22
+ inputSchema: {
23
+ type: "object",
24
+ properties: {
25
+ rest: { type: "string" },
26
+ verdicts: { type: "object", additionalProperties: { type: ["string", "number"] } },
27
+ },
28
+ required: ["rest"],
29
+ },
30
+ },
31
+ {
32
+ name: "note",
33
+ description:
34
+ "Records a request the person makes while gtd runs a step (a change, something to consider), for the next step that waits on them. Use it instead of editing files while gtd runs.",
35
+ inputSchema: {
36
+ type: "object",
37
+ properties: { text: { type: "string" } },
38
+ required: ["text"],
39
+ },
40
+ },
41
+ {
42
+ name: "handoff",
43
+ description:
44
+ "Hands the gtd process to someone else: pushes the branch and opens or refreshes a draft pull request assigned to them. Call it only when the person asks. `to`: their GitHub username; omit it to leave the process for anyone.",
45
+ inputSchema: { type: "object", properties: { to: { type: "string" } } },
46
+ },
47
+ {
48
+ name: "ship",
49
+ description:
50
+ "Combines the finished gtd process into one commit, pushes it and opens or updates its pull request. Call it only after the person agreed. `dryRun` previews without writing anything.",
51
+ inputSchema: { type: "object", properties: { dryRun: { type: "boolean" } } },
52
+ },
53
+ {
54
+ name: "browser",
55
+ description:
56
+ "Starts gtd's browser view of the step it waits at and returns its address. Call it only when the person wants it.",
57
+ inputSchema: { type: "object", properties: {} },
58
+ },
59
+ ]
60
+
61
+ // A rest is the state gtd waits at on a given HEAD: once either moves, an
62
+ // answer meant for it no longer applies. Survives a mod reload, unlike a counter.
63
+ export const restId = (head: string, state: string | undefined) =>
64
+ `${head.slice(0, 12)}:${state ?? "?"}`
65
+
66
+ export type Proceed = { refuse: string } | { refuse?: undefined; verdict?: string }
67
+
68
+ export type ContinueIo = {
69
+ // the rest gtd is at now; undefined when it cannot say
70
+ current(): Promise<string | undefined>
71
+ // the rest's own `gtd validate` script, run; ok when there is nothing to check
72
+ validate(): Promise<{ ok: boolean; out: string }>
73
+ judgment(): Promise<Judgment | undefined>
74
+ }
75
+
76
+ // What `continue` may do from here. `rest` undefined is the band's Continue,
77
+ // which always means the rest on screen.
78
+ export async function decideContinue(
79
+ run: Run,
80
+ rest: string | undefined,
81
+ verdicts: unknown,
82
+ io: ContinueIo,
83
+ ): Promise<Proceed> {
84
+ if (run.isRunning) return { refuse: "gtd is already running a step." }
85
+ const stop = run.stop
86
+ if (!stop) return { refuse: "Nothing is waiting: gtd has no rest open. /gtd drives it." }
87
+ if (stop.kind === "done") {
88
+ return { refuse: `The process is finished: ${TOOL.ship} opens its pull request.` }
89
+ }
90
+ if (rest !== undefined && rest !== run.rest) {
91
+ return {
92
+ refuse: "gtd has moved on from that step; it no longer waits there. Nothing was changed.",
93
+ }
94
+ }
95
+ // Another terminal or a branch switch can move gtd under a waiting answer.
96
+ const now = await io.current()
97
+ if (now !== undefined && now !== run.rest) {
98
+ return {
99
+ refuse:
100
+ "gtd is no longer at that step (it changed outside this session): /gtd shows where it is.",
101
+ }
102
+ }
103
+ if (stop.kind === "gate" && stop.isJudge) return judged(verdicts, io)
104
+ if (verdicts !== undefined) return { refuse: "This step takes no verdicts." }
105
+ if (stop.kind === "gate") {
106
+ const v = await io.validate()
107
+ if (!v.ok) return { refuse: `The step's file does not validate yet:\n${v.out}` }
108
+ }
109
+ return {}
110
+ }
111
+
112
+ // No verdicts lands the gate untouched: the cautious default.
113
+ async function judged(verdicts: unknown, io: ContinueIo): Promise<Proceed> {
114
+ if (verdicts === undefined) return {}
115
+ const j = await io.judgment()
116
+ if (!j) return { refuse: "gtd no longer has a judgment open here." }
117
+ const v = humanVerdicts(j, verdicts)
118
+ return typeof v === "string"
119
+ ? { refuse: `Those verdicts don't fit: ${v}` }
120
+ : { verdict: JSON.stringify(v) }
121
+ }
@@ -1,46 +1,13 @@
1
- // Everything the mod says to a person. Plain words: no gtd state ids, no tool
2
- // names, and options that say what choosing them does.
1
+ // Everything the mod itself shows a person. Plain words: no gtd state ids.
3
2
 
4
- import type { Run, Stop } from "../types"
3
+ import type { Stop } from "../types"
5
4
  import type { Beat } from "./drive"
6
5
 
7
- export const CONTINUE = "I'm done, continue"
8
- export const SAFE = "Continue with the safe choice"
9
- export const HANDOFF = "Hand off to someone else"
10
- export const LATER = "Not now"
11
- export const SHIP = "Yes, open the pull request"
12
- export const ANYONE = "Anyone on the team"
13
- export const CANCEL = "Cancel"
14
- export const CLOSE = "Close"
15
-
16
- export const gateOptions = (stop: Stop) => [stop.isJudge ? SAFE : CONTINUE, HANDOFF, LATER]
17
-
18
6
  const step = (s: { label?: string; state?: string }) => s.label ?? s.state ?? "the next step"
19
7
 
20
- export function question(r: Run) {
21
- const stop = r.stop as Stop
22
- if (stop.isJudge) {
23
- return `gtd can't decide this step on its own: ${step(stop)}. Continue with the safe choice, or hand it to someone who can decide?`
24
- }
25
- const how = r.url
26
- ? `Open it in your browser: ${r.url}`
27
- : `Make your changes in ${stop.file ?? "the files it names"}.`
28
- const again = r.isRepeat ? "You haven't changed anything yet, so gtd is still waiting. " : ""
29
- return `${again}gtd needs your input: ${step(stop)}. ${how} Ready to continue?`
30
- }
31
-
32
- export const STALE =
33
- "This question is out of date: gtd has already moved on. Choose Close to dismiss it."
34
-
35
8
  export const RELOAD_CUT_SCRIPT =
36
9
  "a reload cut a script off mid-run — check the working tree, then Continue to run it again"
37
10
 
38
- export const handoffQuestion =
39
- "Who should take over from here? Type their GitHub username, or let anyone on the team pick it up."
40
-
41
- export const shipQuestion = (branch: string) =>
42
- `gtd has finished the work on ${branch}. Combine it into a single commit and open (or update) its pull request for review?`
43
-
44
11
  export function headline(s: Stop) {
45
12
  const where = step(s)
46
13
  switch (s.kind) {
@@ -6,6 +6,8 @@ export type Stop = {
6
6
  isJudge?: boolean
7
7
  // the steering file the rest asks a person to edit
8
8
  file?: string
9
+ // the steering file's mode (`qa`, `review`), which bounds what may be written at the rest
10
+ mode?: string
9
11
  }
10
12
 
11
13
  export type Run = {
@@ -14,6 +16,13 @@ export type Run = {
14
16
  state?: string
15
17
  label?: string
16
18
  stop?: Stop
19
+ // the rest a person is helped at: HEAD and state, so an answer to an older one is refused
20
+ rest?: string
21
+ // a continue the model asked for, started once its turn ends (and only if
22
+ // gtd still rests at `rest`); kept here so a reload does not lose a verdict
23
+ pending?: { rest: string; isAnswered?: boolean; verdict?: string | undefined }
24
+ // requests a person made while a step ran, for the next rest's assistant
25
+ notes?: string[]
17
26
  // `gtd ui`'s address while it serves the current rest
18
27
  url?: string
19
28
  // why `gtd ui` is not serving it (refused, crashed)