@pmelab/gtd 12.5.0 → 14.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.
- package/README.md +49 -38
- package/dist/gtd.bundle.mjs +3572 -11508
- package/package.json +8 -3
- package/schema.json +5 -287
- package/src/flows/helpers.ts +93 -0
- package/src/flows/index.ts +3 -0
- package/src/flows/runtime.ts +295 -0
- package/src/flows/scripts.ts +116 -0
- package/src/workflows/health.ts +126 -0
- package/src/workflows/index.ts +1 -0
- package/src/workflows/packages.ts +93 -0
- package/src/workflows/planning.ts +99 -0
- package/src/workflows/prose.ts +200 -0
- package/src/workflows/review.ts +169 -0
- package/src/workflows/steps.ts +200 -0
- package/src/workflows/text.fixture.ts +38 -0
- package/src/workflows/text.test.ts +37 -0
- package/src/workflows/text.ts +682 -0
- package/src/workflows/unified.ts +128 -0
- package/src/workflows/vars.ts +23 -0
|
@@ -0,0 +1,682 @@
|
|
|
1
|
+
import { head, start, vars, type SummaryContext } from "../flows/index.js"
|
|
2
|
+
import {
|
|
3
|
+
skillsPreamble,
|
|
4
|
+
styleBlock,
|
|
5
|
+
styleFormatContract,
|
|
6
|
+
agentConduct,
|
|
7
|
+
designPersona,
|
|
8
|
+
architectPersona,
|
|
9
|
+
reviewerPersona,
|
|
10
|
+
specReviewerPersona,
|
|
11
|
+
builderPersona,
|
|
12
|
+
finisherPersona,
|
|
13
|
+
escalationPersona,
|
|
14
|
+
stateFileRules,
|
|
15
|
+
questionBar,
|
|
16
|
+
questionBarReturn,
|
|
17
|
+
fixFeedbackPrompt,
|
|
18
|
+
footnoteRules,
|
|
19
|
+
footnoteFoldIn,
|
|
20
|
+
} from "./prose.js"
|
|
21
|
+
|
|
22
|
+
// The bundled workflow's prompts, messages and scripts. Each is evaluated
|
|
23
|
+
// when its step is reached, against the commit replay stands on.
|
|
24
|
+
|
|
25
|
+
/** `prompt` behind the skills preamble naming `skills`; blank skills leave it bare. */
|
|
26
|
+
export const withSkills = (skills: string | undefined, prompt: string): string => {
|
|
27
|
+
if (skills === undefined || skills.trim() === "") return prompt
|
|
28
|
+
return `${skillsPreamble.replaceAll("{skills}", skills)}\n\n${prompt}`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const unwindFailure = (commit: string): string =>
|
|
32
|
+
`gtd could not unwind ${commit} out of your working tree.`
|
|
33
|
+
|
|
34
|
+
export const idleMessage = (): string =>
|
|
35
|
+
`No active gtd process.
|
|
36
|
+
|
|
37
|
+
To start one, make ANY change — a hand-edit to real code, a scratch
|
|
38
|
+
note, anything at all. .gtd/TODO.md is a good default
|
|
39
|
+
place to start sketching. gtd treats it as a SKETCH, not finished
|
|
40
|
+
work: the very next beat unwinds it out of your working tree (its
|
|
41
|
+
intent survives in history, for the triage phase to read), then
|
|
42
|
+
checks the test baseline is green, then triages the reverted diff
|
|
43
|
+
into ordered, classified concerns: product questions, then
|
|
44
|
+
technical questions, then one package per concern, built and
|
|
45
|
+
reviewed in parallel.
|
|
46
|
+
|
|
47
|
+
What each change does next (then run \`gtd land\`):
|
|
48
|
+
- **Start** — make any change — gtd unwinds it out of your working tree (its intent survives in history) before checking the test baseline is green, then triages the reverted diff into ordered, classified concerns and resolves product questions, then technical ones, before building each concern's package (**unwind** -> **start-gate.check**).
|
|
49
|
+
`
|
|
50
|
+
|
|
51
|
+
export const unwindFailedMessage = (): string =>
|
|
52
|
+
`gtd could not revert your sketch out of the working tree.
|
|
53
|
+
\`.gtd/FEEDBACK.md\` holds the error.
|
|
54
|
+
|
|
55
|
+
Undo the sketch by hand (its intent survives in history either
|
|
56
|
+
way), then continue — gtd will not start work on a tree that still
|
|
57
|
+
carries it.
|
|
58
|
+
|
|
59
|
+
What each change does next (then run \`gtd land\`):
|
|
60
|
+
- **Continue** — having undone the sketch by hand, check the test baseline is green and start triage (**start-gate.check**).
|
|
61
|
+
`
|
|
62
|
+
|
|
63
|
+
export const architecturePreMessage = (): string =>
|
|
64
|
+
`Judging whether \`.gtd/REQUIREMENTS.md\`'s settled concerns need a
|
|
65
|
+
dedicated architecture pass — real structural decisions, multiple
|
|
66
|
+
integration points, or a non-obvious tradeoff — before packages
|
|
67
|
+
are written. Run \`gtd judge answer\` and pipe a verdict for
|
|
68
|
+
\`architectureWarranted\` — or land untouched to run the full pass
|
|
69
|
+
(the conservative default; a skipped judgment never suppresses
|
|
70
|
+
it).
|
|
71
|
+
`
|
|
72
|
+
|
|
73
|
+
export const startGateBlockedMessage = (): string =>
|
|
74
|
+
`The test baseline is red — gtd will not start new work on a broken suite.
|
|
75
|
+
\`.gtd/FEEDBACK.md\` holds the failing output.
|
|
76
|
+
|
|
77
|
+
What each change does next (then run \`gtd land\`):
|
|
78
|
+
- **Retry check** — edit the code and/or \`.gtd/FEEDBACK.md\` to fix the failing tests (**start-gate.check**). To repair the baseline as its own separate reviewed commit instead, abandon this start and run \`gtd --entry fix-precheck\` from a clean \`idle\`.
|
|
79
|
+
`
|
|
80
|
+
|
|
81
|
+
export const reviewGateBlockedMessage = (): string =>
|
|
82
|
+
`The test baseline is red — gtd will not start a review on a broken suite.
|
|
83
|
+
\`.gtd/FEEDBACK.md\` holds the failing output.
|
|
84
|
+
|
|
85
|
+
What each change does next (then run \`gtd land\`):
|
|
86
|
+
- **Retry check** — edit the code and/or \`.gtd/FEEDBACK.md\` to fix the failing tests (**review-gate.check**).
|
|
87
|
+
`
|
|
88
|
+
|
|
89
|
+
export const designTriagePrompt = (base: string): string =>
|
|
90
|
+
`${styleBlock}
|
|
91
|
+
|
|
92
|
+
${styleFormatContract}
|
|
93
|
+
|
|
94
|
+
${stateFileRules}
|
|
95
|
+
${footnoteFoldIn}
|
|
96
|
+
- The only state file this turn touches is \`.gtd/REQUIREMENTS.md\`
|
|
97
|
+
— no other files for notes or output
|
|
98
|
+
- \`.gtd/TODO.md\` is the likely home of the sketch that started
|
|
99
|
+
this process — the human's input, folded into the concerns
|
|
100
|
+
below like any other part of the start diff; never a state
|
|
101
|
+
file to preserve, never gtd bookkeeping to ignore
|
|
102
|
+
- This process started at commit \`${start()}\`,
|
|
103
|
+
reverted out of the tree by \`unwind\` right after landing, so
|
|
104
|
+
\`git diff ${start()}\` is now empty — its content
|
|
105
|
+
survives only in history. Find the entry commit yourself:
|
|
106
|
+
\`git rev-list --ancestry-path ${start()}..HEAD | tail -1\`
|
|
107
|
+
(the process's first turn, before any baseline-repair
|
|
108
|
+
commits), then \`git show\` it — a hand-edit, a scratch note,
|
|
109
|
+
or both
|
|
110
|
+
- Whichever lap this is, leave \`.gtd/REQUIREMENTS.md\`
|
|
111
|
+
uncommitted and finish once it reflects this lap's own work
|
|
112
|
+
|
|
113
|
+
## First lap
|
|
114
|
+
|
|
115
|
+
\`.gtd/REQUIREMENTS.md\` does not exist yet (or holds whatever the
|
|
116
|
+
human's change left there). Build it from that start diff into an
|
|
117
|
+
ordered list of concerns, each classified below.
|
|
118
|
+
|
|
119
|
+
### Classify each concern
|
|
120
|
+
|
|
121
|
+
Classify each as PRODUCT (user-facing/requirements) or TECHNICAL
|
|
122
|
+
(implementation).
|
|
123
|
+
|
|
124
|
+
${questionBar}
|
|
125
|
+
|
|
126
|
+
Raise questions only for product concerns here — technical ones
|
|
127
|
+
wait for the next phase. When every concern is TECHNICAL, write
|
|
128
|
+
no \`## Open Questions\` section. STRICT: answer it yourself only
|
|
129
|
+
when the product default is unmistakable; a wrong intent costs a
|
|
130
|
+
whole rebuild lap.
|
|
131
|
+
|
|
132
|
+
### Fold in the sketch
|
|
133
|
+
|
|
134
|
+
- Fold everything the entry commit added under the concern it
|
|
135
|
+
belongs to — a scratch note and a real code edit are both
|
|
136
|
+
just a sketch to finish, never work to preserve; \`unwind\`
|
|
137
|
+
already reverted both, so there is nothing left to delete
|
|
138
|
+
|
|
139
|
+
## Return lap
|
|
140
|
+
|
|
141
|
+
${questionBarReturn}
|
|
142
|
+
## Review loop-back
|
|
143
|
+
|
|
144
|
+
- \`.gtd/REQUIREMENTS.md\` already holds concerns with no
|
|
145
|
+
ticked-but-unfolded answer waiting — a completed REVIEW round
|
|
146
|
+
put this here, not a question you asked. Develop those
|
|
147
|
+
concerns further with whatever the round raised; never
|
|
148
|
+
rediscover or regroup them cold, the way the first lap does
|
|
149
|
+
- The human's review-round edit was reverted the same way the
|
|
150
|
+
entry commit was — read it from history:
|
|
151
|
+
\`git show ${base}\`. (On the first lap that hash
|
|
152
|
+
is the process's own diff base, \`${start()}\` — this
|
|
153
|
+
branch doesn't apply)
|
|
154
|
+
- Every decision under \`## Answered Questions\` stays settled —
|
|
155
|
+
never re-open one. A genuinely open PRODUCT point may still
|
|
156
|
+
raise a fresh \`## Open Questions\` entry: the product gate sits
|
|
157
|
+
on this path exactly as on the first lap
|
|
158
|
+
- Before grouping anything, run \`${vars.testCommand}\`
|
|
159
|
+
yourself — a loop-back runs no green-baseline gate, so the
|
|
160
|
+
tree may already be red (reverting the edit can undo a fix it
|
|
161
|
+
made). If red, make that breakage the first concern, ahead of
|
|
162
|
+
everything else — every later concern's green-on-its-own
|
|
163
|
+
property assumes the suite started green
|
|
164
|
+
`
|
|
165
|
+
|
|
166
|
+
export const designSystem = (): string =>
|
|
167
|
+
`${designPersona}
|
|
168
|
+
|
|
169
|
+
${agentConduct}`
|
|
170
|
+
|
|
171
|
+
export const designGateAnswerMessage = (): string =>
|
|
172
|
+
`Answering here closes a gap between what you want the product to
|
|
173
|
+
do and what gets built; changing nothing and re-running says that
|
|
174
|
+
gap is already closed.
|
|
175
|
+
|
|
176
|
+
\`.gtd/REQUIREMENTS.md\` holds the concerns under
|
|
177
|
+
development. Each open question under \`## Open Questions\` offers
|
|
178
|
+
a few options plus a \`- [ ] _your answer_\` slot. Answer EVERY
|
|
179
|
+
question by ticking exactly one box (\`- [x]\`); for your own
|
|
180
|
+
answer, replace \`_your answer_\` with your text and tick that
|
|
181
|
+
line. Stepping is refused while any question is unanswered — with one
|
|
182
|
+
escape: change nothing and re-run to advance with the questions
|
|
183
|
+
unanswered.
|
|
184
|
+
|
|
185
|
+
You can also leave a footnote alongside an answer — it never
|
|
186
|
+
substitutes for ticking a box, which is still required before
|
|
187
|
+
stepping is allowed:
|
|
188
|
+
|
|
189
|
+
${footnoteRules}
|
|
190
|
+
What each change does next (then run \`gtd land\`):
|
|
191
|
+
- **Accept as-is** — change nothing and re-run to advance with the questions unanswered — the plan stands as written.
|
|
192
|
+
- **Revise answers** — tick exactly one option per open question (replace \`_your answer_\` for your own) to send it back for the agent to fold your answers in, or delete a question to skip it. To accept the plan as-is instead, revert everything and re-run — a clean tree is the only accept gesture.
|
|
193
|
+
`
|
|
194
|
+
|
|
195
|
+
export const architectureAuthorPrompt = (): string =>
|
|
196
|
+
`${styleBlock}
|
|
197
|
+
|
|
198
|
+
${styleFormatContract}
|
|
199
|
+
|
|
200
|
+
${stateFileRules}
|
|
201
|
+
${footnoteFoldIn}
|
|
202
|
+
- The only state files this turn touches are
|
|
203
|
+
\`.gtd/ARCHITECTURE.md\` (write it) and \`.gtd/REQUIREMENTS.md\`
|
|
204
|
+
(delete once folded in) — no other files for notes or output
|
|
205
|
+
- You do not resume the design conversation — a separate
|
|
206
|
+
machine, its own memory, a cold read every time. Read
|
|
207
|
+
\`.gtd/REQUIREMENTS.md\` (the settled, ordered, classified
|
|
208
|
+
concerns) in full; treat every decision there, PRODUCT or
|
|
209
|
+
TECHNICAL alike, as settled — never re-open it
|
|
210
|
+
- Cold means no memory of triage's own back-and-forth, not no
|
|
211
|
+
git access. This process started at commit
|
|
212
|
+
\`${start()}\`. Find the first turn yourself: run
|
|
213
|
+
\`git rev-list --ancestry-path ${start()}..HEAD | tail -1\`
|
|
214
|
+
then \`git show\` it to see what started this process — a
|
|
215
|
+
hand-edit, a scratch note, or both
|
|
216
|
+
- Once \`.gtd/ARCHITECTURE.md\` is written, delete
|
|
217
|
+
\`.gtd/REQUIREMENTS.md\` — folded in, it must not linger. Leave
|
|
218
|
+
everything uncommitted and finish
|
|
219
|
+
|
|
220
|
+
## First lap
|
|
221
|
+
|
|
222
|
+
- Develop \`.gtd/ARCHITECTURE.md\` from those concerns: for each,
|
|
223
|
+
in order, work out the *how*, building on the settled *what*
|
|
224
|
+
- You now know the *how*, so you know each concern's file footprint
|
|
225
|
+
— list each concern's primary paths. Merge concerns whose
|
|
226
|
+
footprints center on the same files into one, unless the later
|
|
227
|
+
one only consumes an interface the earlier one creates (keeps a
|
|
228
|
+
build-on-top sequence from collapsing into one blob). This
|
|
229
|
+
authority is to merge only, never to split — the whole problem
|
|
230
|
+
is over-granularity
|
|
231
|
+
- Record every merge under \`## Merged Concerns\`,
|
|
232
|
+
carrying both merged requirements verbatim so spec review
|
|
233
|
+
still covers each independently
|
|
234
|
+
- A merge raises no open question and stops for no
|
|
235
|
+
human — do not route it to \`architecture.gate\` for a veto; the
|
|
236
|
+
human sees it when reviewing the plan, and spec review is the
|
|
237
|
+
real safety net
|
|
238
|
+
- Prefer fewer, larger packages — the smallest independently
|
|
239
|
+
valuable change, not the smallest change that compiles
|
|
240
|
+
- Every open point here is TECHNICAL — triage already resolved
|
|
241
|
+
the product ones, one phase earlier. PERMISSIVE: answer it
|
|
242
|
+
yourself unless you genuinely cannot defend a default; a wrong
|
|
243
|
+
technical call is still caught at spec review
|
|
244
|
+
|
|
245
|
+
${questionBar}
|
|
246
|
+
## Return lap
|
|
247
|
+
|
|
248
|
+
${questionBarReturn}`
|
|
249
|
+
|
|
250
|
+
export const architectSystem = (): string =>
|
|
251
|
+
`${architectPersona}
|
|
252
|
+
|
|
253
|
+
${agentConduct}`
|
|
254
|
+
|
|
255
|
+
export const architectureDecomposePrompt = (): string =>
|
|
256
|
+
`${styleBlock}
|
|
257
|
+
|
|
258
|
+
${stateFileRules}
|
|
259
|
+
- The only state files this turn touches are the package files
|
|
260
|
+
under \`.gtd/packages/\` and \`.gtd/ARCHITECTURE.md\` (deleted) —
|
|
261
|
+
no other files for notes or output
|
|
262
|
+
- Work from \`.gtd/ARCHITECTURE.md\` if you wrote it earlier this
|
|
263
|
+
conversation, otherwise read it (the converged technical
|
|
264
|
+
plan). It already lists an ordered set of concerns with every
|
|
265
|
+
merge/split judgement made — this turn is a mechanical
|
|
266
|
+
write-out, not a planning one. A \`## Merged Concerns\` heading
|
|
267
|
+
there records those merges, never a concern of its own: write
|
|
268
|
+
no package file for it
|
|
269
|
+
- Write one package file per concern, in the settled order,
|
|
270
|
+
under \`.gtd/packages/\` (e.g. \`.gtd/packages/01-name.md\`,
|
|
271
|
+
\`02-name.md\`, ...), each carrying that concern's
|
|
272
|
+
requirement(s) — both, independently, if merged — its
|
|
273
|
+
independent tasks, and each task's acceptance criteria as
|
|
274
|
+
\`- [ ]\` checkboxes and relevant paths
|
|
275
|
+
- Do not merge or split concerns here — that judgement already
|
|
276
|
+
happened; carry the settled grouping over verbatim. No
|
|
277
|
+
package file may reference any other \`.gtd/\` file
|
|
278
|
+
- Once written, delete \`.gtd/ARCHITECTURE.md\`. Leave everything
|
|
279
|
+
uncommitted and finish
|
|
280
|
+
`
|
|
281
|
+
|
|
282
|
+
export const architectureGateAnswerMessage = (): string =>
|
|
283
|
+
`Answering here closes a gap between what you want built and how
|
|
284
|
+
it actually gets built; changing nothing and re-running says
|
|
285
|
+
that gap is already closed.
|
|
286
|
+
|
|
287
|
+
\`.gtd/ARCHITECTURE.md\` holds the technical plan under
|
|
288
|
+
development. Each open question under \`## Open Questions\` offers
|
|
289
|
+
a few options plus a \`- [ ] _your answer_\` slot. Answer EVERY
|
|
290
|
+
question by ticking exactly one box (\`- [x]\`); for your own
|
|
291
|
+
answer, replace \`_your answer_\` with your text and tick that
|
|
292
|
+
line. Stepping is refused while any question is unanswered — with one
|
|
293
|
+
escape: change nothing and re-run to advance with the questions
|
|
294
|
+
unanswered.
|
|
295
|
+
|
|
296
|
+
You can also leave a footnote alongside an answer — it never
|
|
297
|
+
substitutes for ticking a box, which is still required before
|
|
298
|
+
stepping is allowed:
|
|
299
|
+
|
|
300
|
+
${footnoteRules}
|
|
301
|
+
What each change does next (then run \`gtd land\`):
|
|
302
|
+
- **Accept as-is** — change nothing and re-run to advance with the questions unanswered — the plan stands as written.
|
|
303
|
+
- **Revise answers** — tick exactly one option per open question (replace \`_your answer_\` for your own) to send it back for the agent to fold your answers in, or delete a question to skip it. To accept the plan as-is instead, revert everything and re-run — a clean tree is the only accept gesture.
|
|
304
|
+
`
|
|
305
|
+
|
|
306
|
+
export const packagesItemBuildingPrompt = (pkg: string): string =>
|
|
307
|
+
`${stateFileRules}
|
|
308
|
+
- The only state file this turn may write is \`.gtd/SATISFIED.md\`;
|
|
309
|
+
never delete the package file (the spec-review gate reads it
|
|
310
|
+
after you)
|
|
311
|
+
- The package to implement is \`${pkg}\`
|
|
312
|
+
- First check its acceptance criteria against the current tree —
|
|
313
|
+
an earlier fix turn may already satisfy them. If **every**
|
|
314
|
+
criterion is met, implement nothing: write \`.gtd/SATISFIED.md\`
|
|
315
|
+
with each criterion's concrete evidence (commit, file, or
|
|
316
|
+
symbol), change nothing else, and finish. Otherwise implement
|
|
317
|
+
normally and skip that file
|
|
318
|
+
- Implement every task the package describes, no more, no less,
|
|
319
|
+
fanning independent ones out to parallel subagents where your
|
|
320
|
+
harness supports it; leave other package files untouched
|
|
321
|
+
- Leave the package file in place, everything uncommitted, then
|
|
322
|
+
finish your turn
|
|
323
|
+
`
|
|
324
|
+
|
|
325
|
+
export const builderSystem = (): string =>
|
|
326
|
+
`${builderPersona}
|
|
327
|
+
|
|
328
|
+
${agentConduct}`
|
|
329
|
+
|
|
330
|
+
export const packagesItemFixSuitePrompt = (): string =>
|
|
331
|
+
`${stateFileRules}
|
|
332
|
+
${fixFeedbackPrompt}
|
|
333
|
+
- If the only way to green the suite is another package's work,
|
|
334
|
+
make the smallest change that gets there — that package can
|
|
335
|
+
then legitimately report itself already satisfied later
|
|
336
|
+
- Leave everything uncommitted and finish your turn — do not commit
|
|
337
|
+
`
|
|
338
|
+
|
|
339
|
+
export const packagesItemFixSpecPrompt = (pkg: string): string =>
|
|
340
|
+
`${stateFileRules}
|
|
341
|
+
- The only state file this turn touches is
|
|
342
|
+
\`.gtd/SPEC_FEEDBACK.md\` — address it, then delete it
|
|
343
|
+
- Read it (the reviewer's concerns) and the package spec
|
|
344
|
+
(\`${pkg}\`), then fix the code to
|
|
345
|
+
resolve every concern
|
|
346
|
+
- Delete \`.gtd/SPEC_FEEDBACK.md\` once resolved; leave everything
|
|
347
|
+
else uncommitted and finish your turn
|
|
348
|
+
`
|
|
349
|
+
|
|
350
|
+
export const healthJudgeMessage = (): string =>
|
|
351
|
+
`The check is still red, and this isn't the first round —
|
|
352
|
+
\`.gtd/FEEDBACK.md\` holds this round's output, and the previous round's
|
|
353
|
+
is in history. Run \`gtd judge answer\` and pipe a
|
|
354
|
+
verdict — identical, new-failure, or progress — or land (with or
|
|
355
|
+
without an edit of your own) to accept the conservative default
|
|
356
|
+
(retry the fix) with no verdict recorded.
|
|
357
|
+
`
|
|
358
|
+
|
|
359
|
+
export const healthDescribePrompt = (): string =>
|
|
360
|
+
`${stateFileRules}
|
|
361
|
+
- The only state file this turn writes is \`.gtd/ESCALATION.md\`
|
|
362
|
+
- Read \`.gtd/FEEDBACK.md\` (this round's failing check output),
|
|
363
|
+
earlier rounds' from history (\`git log -p -- .gtd/FEEDBACK.md\` —
|
|
364
|
+
this may be the first round, with no prior round to compare), and
|
|
365
|
+
the code your own earlier attempts touched
|
|
366
|
+
- Write \`.gtd/ESCALATION.md\`: what is failing, why the previous
|
|
367
|
+
attempts did not resolve it, and concrete suggested approaches to
|
|
368
|
+
solve it
|
|
369
|
+
- Never fix the code yourself — this turn only writes the document
|
|
370
|
+
`
|
|
371
|
+
|
|
372
|
+
export const escalationSystem = (): string =>
|
|
373
|
+
`${escalationPersona}
|
|
374
|
+
|
|
375
|
+
${agentConduct}`
|
|
376
|
+
|
|
377
|
+
export const healthStopMessage = (): string =>
|
|
378
|
+
`The agent could not get the check to pass after repeated attempts,
|
|
379
|
+
and has written \`.gtd/ESCALATION.md\`: what is failing, why the
|
|
380
|
+
previous attempts didn't resolve it, and suggested approaches.
|
|
381
|
+
|
|
382
|
+
Edit it — narrow it, redirect it, add what you know — or land it
|
|
383
|
+
untouched to hand it to the next fix turn as-is.
|
|
384
|
+
`
|
|
385
|
+
|
|
386
|
+
export const healthExhaustedMessage = (): string =>
|
|
387
|
+
`Escalation attempts are exhausted — this is the second round, and
|
|
388
|
+
the check is still red. \`.gtd/ESCALATION.md\` holds the last
|
|
389
|
+
unresolved analysis, and \`.gtd/FEEDBACK.md\` the last failing
|
|
390
|
+
output.
|
|
391
|
+
|
|
392
|
+
Edit \`.gtd/ESCALATION.md\` with fresh instructions for the next fix
|
|
393
|
+
turn, or land untouched to give it one more attempt at the same
|
|
394
|
+
analysis.
|
|
395
|
+
`
|
|
396
|
+
|
|
397
|
+
export const packagesItemSpecPreMessage = (): string =>
|
|
398
|
+
`Judging whether the code already satisfies each requirement in the
|
|
399
|
+
package spec, before spending a full review turn. Run \`gtd judge
|
|
400
|
+
answer\` and pipe a verdict per section — or land untouched to run
|
|
401
|
+
the full review (the conservative default; a skipped judgment
|
|
402
|
+
never suppresses anything).
|
|
403
|
+
`
|
|
404
|
+
|
|
405
|
+
/** The sections a pre-judge could not clear, when it cleared the rest. */
|
|
406
|
+
const specScope = (failing: readonly string[]): string =>
|
|
407
|
+
failing.length > 0
|
|
408
|
+
? `- A pre-judge already found the other sections satisfied. Confine
|
|
409
|
+
your review to only these sections:
|
|
410
|
+
${failing.map((title) => ` - ${title}\n`).join("")}`
|
|
411
|
+
: ""
|
|
412
|
+
|
|
413
|
+
export const packagesItemSpecReviewPrompt = (
|
|
414
|
+
pkg: string,
|
|
415
|
+
failing: readonly string[] = [],
|
|
416
|
+
): string =>
|
|
417
|
+
`${styleBlock}
|
|
418
|
+
|
|
419
|
+
You are reviewing a freshly-built work package against its own
|
|
420
|
+
spec.
|
|
421
|
+
|
|
422
|
+
${stateFileRules}
|
|
423
|
+
- The only state file this turn touches is
|
|
424
|
+
\`.gtd/SPEC_FEEDBACK.md\` — write it only when you find problems
|
|
425
|
+
- The package spec is \`${pkg}\`
|
|
426
|
+
${specScope(failing)}- Verify the implementation against it: tasks done, criteria
|
|
427
|
+
met, code sound and consistent with the codebase. No diff is
|
|
428
|
+
given — read the range yourself, from \`${start()}\`
|
|
429
|
+
to the working tree, process-wide (it can span earlier
|
|
430
|
+
packages)
|
|
431
|
+
- You own that bar; nothing downstream re-weighs your findings
|
|
432
|
+
- Write nothing when the package fully satisfies its spec —
|
|
433
|
+
silence is your approval. Otherwise write
|
|
434
|
+
\`.gtd/SPEC_FEEDBACK.md\` listing what would violate the spec if
|
|
435
|
+
it shipped unaddressed, specific enough to act on, each as its
|
|
436
|
+
own \`## \` heading
|
|
437
|
+
- Never fix anything yourself and never delete the package
|
|
438
|
+
file — a later step owns that
|
|
439
|
+
`
|
|
440
|
+
|
|
441
|
+
export const specReviewerSystem = (): string =>
|
|
442
|
+
`${specReviewerPersona}
|
|
443
|
+
|
|
444
|
+
${agentConduct}`
|
|
445
|
+
|
|
446
|
+
export const buildFixPrompt = (): string =>
|
|
447
|
+
`${stateFileRules}
|
|
448
|
+
${fixFeedbackPrompt}
|
|
449
|
+
- Leave everything uncommitted — do not commit
|
|
450
|
+
`
|
|
451
|
+
|
|
452
|
+
export const finisherSystem = (): string =>
|
|
453
|
+
`${finisherPersona}
|
|
454
|
+
|
|
455
|
+
${agentConduct}`
|
|
456
|
+
|
|
457
|
+
export const buildFixQualityPrompt = (): string =>
|
|
458
|
+
`${stateFileRules}
|
|
459
|
+
- Read \`.gtd/QUALITY.md\` — one \`## \` chunk per quality dimension
|
|
460
|
+
that found something blocking. Merge duplicate findings across
|
|
461
|
+
dimensions FIRST, then fix every chunk
|
|
462
|
+
- Delete \`.gtd/QUALITY.md\` once every finding is resolved
|
|
463
|
+
- Leave everything else uncommitted and finish your turn
|
|
464
|
+
`
|
|
465
|
+
|
|
466
|
+
export const buildQualityReviewingPrompt = (lens: string): string =>
|
|
467
|
+
`${stateFileRules}
|
|
468
|
+
- The only state file this turn writes is \`.gtd/QUALITY.md\` — no
|
|
469
|
+
other files for notes or output
|
|
470
|
+
- Review the whole assembled change, from \`${start()}\`
|
|
471
|
+
to the working tree, through this ONE quality lens only —
|
|
472
|
+
\`${lens}\`, already loaded as this turn's own skill
|
|
473
|
+
- Where you find something blocking, APPEND a \`## \` chunk to
|
|
474
|
+
\`.gtd/QUALITY.md\` describing it — never overwrite what an
|
|
475
|
+
earlier dimension already wrote there
|
|
476
|
+
- Write nothing when nothing is blocking under this lens — a
|
|
477
|
+
clean turn IS this dimension's approval
|
|
478
|
+
- Touch no other state file, and leave everything uncommitted
|
|
479
|
+
`
|
|
480
|
+
|
|
481
|
+
export const reviewerSystem = (): string =>
|
|
482
|
+
`${reviewerPersona}
|
|
483
|
+
|
|
484
|
+
${agentConduct}`
|
|
485
|
+
|
|
486
|
+
export const buildReviewAwaitReviewMessage = (base: string): string =>
|
|
487
|
+
`\`.gtd/REVIEW.md\` holds the review record for the process — one
|
|
488
|
+
\`- [ ]\` checkbox per reviewable item, grouped into chunks. Tick a box
|
|
489
|
+
(\`- [x]\`) as you review each hunk; ticking only records that you've read
|
|
490
|
+
it, it is not sign-off. Ticks are read-progress only: landing clears
|
|
491
|
+
every box back to \`- [ ]\` on disk and nothing records which hunks
|
|
492
|
+
you read — there is no persisted trail of it.
|
|
493
|
+
|
|
494
|
+
Review the diff yourself, with whatever tool you like — gtd checks
|
|
495
|
+
nothing out and touches no ref; \`gtd base\` prints this same hash any
|
|
496
|
+
time you need it again. The range runs from the review base to the
|
|
497
|
+
working tree:
|
|
498
|
+
|
|
499
|
+
git diff ${base}
|
|
500
|
+
When you've been through the whole diff, run \`gtd land\`:
|
|
501
|
+
|
|
502
|
+
- **Sign off** — leave no comment — no note in
|
|
503
|
+
\`.gtd/REVIEW.md\`, no code edit — to close the process,
|
|
504
|
+
whatever the boxes say. Every turn commit stays on the
|
|
505
|
+
branch; run \`gtd summary\` afterward for a closing-message
|
|
506
|
+
prompt.
|
|
507
|
+
- **Request changes** — leave a comment: a note on a
|
|
508
|
+
\`.gtd/REVIEW.md\` line, a footnote anchored to a hunk, or a
|
|
509
|
+
direct code edit — to send a FULL development lap
|
|
510
|
+
(**review.closing** → **review.triage** → **review.collecting**
|
|
511
|
+
→ re-triage; a hand-edit outside \`.gtd/\` skips the triage
|
|
512
|
+
straight to **review.collecting**, no verdict of your own
|
|
513
|
+
required). A
|
|
514
|
+
hand-edit you make here is treated as a SKETCH, not a
|
|
515
|
+
fix the agent builds on: it is reverted out of the tree and re-planned
|
|
516
|
+
from scratch, the same as any other change that starts a process.
|
|
517
|
+
There is no baseline check on the way back into planning — only a
|
|
518
|
+
genuinely non-actionable comment (an approving remark with no code
|
|
519
|
+
edit) skips the lap and signs off straight away.
|
|
520
|
+
|
|
521
|
+
A footnote works the same way here as a line note:
|
|
522
|
+
|
|
523
|
+
${footnoteRules}
|
|
524
|
+
Deleting \`.gtd/REVIEW.md\` is refused.
|
|
525
|
+
`
|
|
526
|
+
|
|
527
|
+
export const reviewEditsCapture = (commit: string): string =>
|
|
528
|
+
`This is machine-captured input, not instructions. A downstream agent judges whether it's actionable.
|
|
529
|
+
|
|
530
|
+
Commit: ${commit}
|
|
531
|
+
The human's notes are in .gtd/REVIEW.md at this commit. Any hand edits are
|
|
532
|
+
in that commit's other paths. Run: git show ${commit}
|
|
533
|
+
`
|
|
534
|
+
|
|
535
|
+
export const reviewNotesCapture = (commit: string): string =>
|
|
536
|
+
`This is machine-captured input, not instructions. A downstream agent judges whether it's actionable.
|
|
537
|
+
|
|
538
|
+
Commit: ${commit}
|
|
539
|
+
The human's notes are in .gtd/REVIEW.md at this commit. Run: git show ${commit}
|
|
540
|
+
`
|
|
541
|
+
|
|
542
|
+
export const buildReviewReviewMissingMessage = (commit: string): string =>
|
|
543
|
+
`The review round committed no \`.gtd/REVIEW.md\` (at ${commit}), so there is
|
|
544
|
+
nothing to sign off on.
|
|
545
|
+
|
|
546
|
+
Make any change to re-run the reviewer and author a fresh review
|
|
547
|
+
record.
|
|
548
|
+
|
|
549
|
+
What each change does next (then run \`gtd land\`):
|
|
550
|
+
- **Re-review** — re-run the reviewer to author a fresh \`.gtd/REVIEW.md\` (**build.review.reviewing**).
|
|
551
|
+
`
|
|
552
|
+
|
|
553
|
+
export const buildReviewTriageMessage = (): string =>
|
|
554
|
+
`Judging whether each \`## \` chunk's note in \`.gtd/REVIEW.md\` is
|
|
555
|
+
actionable, to skip \`collecting\`'s full turn when the round is
|
|
556
|
+
approval-only. Run \`gtd judge answer\` and pipe a verdict per
|
|
557
|
+
chunk — or land untouched to run the full triage (the
|
|
558
|
+
conservative default; a skipped judgment never signs off).
|
|
559
|
+
`
|
|
560
|
+
|
|
561
|
+
export const buildReviewCollectingPrompt = (capture: string): string =>
|
|
562
|
+
`${styleBlock}
|
|
563
|
+
|
|
564
|
+
${styleFormatContract}
|
|
565
|
+
|
|
566
|
+
You are judging and classifying a round of review feedback.
|
|
567
|
+
|
|
568
|
+
${stateFileRules}
|
|
569
|
+
${footnoteFoldIn}
|
|
570
|
+
- The only state file this turn touches is \`.gtd/REQUIREMENTS.md\` —
|
|
571
|
+
you classify, you do not build
|
|
572
|
+
|
|
573
|
+
The raw review material is:
|
|
574
|
+
|
|
575
|
+
${capture}
|
|
576
|
+
It names a commit. Work from what you already reviewed if you
|
|
577
|
+
wrote today's review earlier this conversation; otherwise read
|
|
578
|
+
that commit's diff yourself first.
|
|
579
|
+
|
|
580
|
+
The round is actionable if any of these hold:
|
|
581
|
+
|
|
582
|
+
- The human left a note on \`.gtd/REVIEW.md\`. A note is a mandatory
|
|
583
|
+
concern below
|
|
584
|
+
- The human added a code comment this round, even a plain-prose
|
|
585
|
+
one — describe it as a concern, and note the comment line
|
|
586
|
+
itself is transient: it must not survive the lap that
|
|
587
|
+
satisfies it
|
|
588
|
+
- The human hand-edited non-comment code this round — no longer
|
|
589
|
+
a committed intent to build on, but a sketch like the entry
|
|
590
|
+
commit's own diff. Describe what it was reaching for; expect
|
|
591
|
+
the next lap to re-derive it from scratch, never call it final
|
|
592
|
+
|
|
593
|
+
Not actionable only when none of the above holds — nothing but an
|
|
594
|
+
approving remark, no code edit, no substantive note. Never invent
|
|
595
|
+
actionability, and never dismiss a real note or edit as approval.
|
|
596
|
+
|
|
597
|
+
- If actionable: write \`.gtd/REQUIREMENTS.md\` with an ordered
|
|
598
|
+
list of concerns, each PRODUCT or TECHNICAL — the shape
|
|
599
|
+
\`design.triage\` builds, one \`## <heading>\` per concern in
|
|
600
|
+
build order. Fold every note, comment, and hand-edit in under
|
|
601
|
+
its concern. Raise no open questions here — \`design.triage\`
|
|
602
|
+
owns that later. Then finish
|
|
603
|
+
- If not: finish without writing anything — changing nothing is
|
|
604
|
+
the sign-off
|
|
605
|
+
`
|
|
606
|
+
|
|
607
|
+
export const buildReviewReviewingPrompt = (base: string): string =>
|
|
608
|
+
`${styleBlock}
|
|
609
|
+
|
|
610
|
+
${styleFormatContract}
|
|
611
|
+
|
|
612
|
+
${stateFileRules}
|
|
613
|
+
- The only state file this turn touches is \`.gtd/REVIEW.md\` —
|
|
614
|
+
no other files for notes or output
|
|
615
|
+
|
|
616
|
+
Write \`.gtd/REVIEW.md\` in this exact format, to help a human
|
|
617
|
+
review the changes:
|
|
618
|
+
|
|
619
|
+
- First non-blank line: \`# Review: ${head().slice(0, 7)}\`
|
|
620
|
+
- Somewhere in the document: \`<!-- base: ${base} -->\`
|
|
621
|
+
- At least one \`## <Chunk Title>\` heading grouping hunks
|
|
622
|
+
semantically (same feature/refactor/fix, across files), each
|
|
623
|
+
with a short explanation of what changed and why, then one
|
|
624
|
+
pointer per hunk (\`./\`-relative path, optional \`#line\`;
|
|
625
|
+
checkboxes are for the human, not you). Put the note's
|
|
626
|
+
opening line right on the pointer's line:
|
|
627
|
+
|
|
628
|
+
- [ ] ./path/to/file.ts#42 — what this hunk does
|
|
629
|
+
|
|
630
|
+
Continue a longer note below the pointer, indented exactly two spaces
|
|
631
|
+
— never four or more, which reads as a code block and never
|
|
632
|
+
reflows:
|
|
633
|
+
|
|
634
|
+
- [ ] ./path/to/file.ts#42 — what this hunk does
|
|
635
|
+
and here is more detail, continued below it
|
|
636
|
+
|
|
637
|
+
A note sitting entirely on the line(s) beneath the pointer is
|
|
638
|
+
also valid. Either way, the note must never start with a bare \`./path\` token
|
|
639
|
+
— that parses as a second pointer, not a note
|
|
640
|
+
No diff is given — read the changes yourself. The range runs
|
|
641
|
+
from \`${base}\` to the working tree (committed turns
|
|
642
|
+
plus anything pending); on a feedback round that's the previous
|
|
643
|
+
review's boundary, so it covers only what's new.
|
|
644
|
+
|
|
645
|
+
Leave \`.gtd/REVIEW.md\` uncommitted and finish.
|
|
646
|
+
`
|
|
647
|
+
|
|
648
|
+
/** `gtd summary`'s prompt: printed cold, no session identity, no diff inlined. */
|
|
649
|
+
export const summaryPrompt = (it: SummaryContext): string => {
|
|
650
|
+
const human =
|
|
651
|
+
it.humanCommits.length > 0
|
|
652
|
+
? `The human contributed at these commits,
|
|
653
|
+
oldest to newest:
|
|
654
|
+
${it.humanCommits.map((c) => `- \`${c.hash}\` (entering \`${c.state}\`)\n`).join("")}
|
|
655
|
+
`
|
|
656
|
+
: `The human left no comment or edit this process —
|
|
657
|
+
every commit is machine-authored.
|
|
658
|
+
`
|
|
659
|
+
return `${styleBlock}
|
|
660
|
+
|
|
661
|
+
- Write the closing message for the process HEAD closes or sits inside —
|
|
662
|
+
for a squash, an amend, or a PR body. Starting cold: read every
|
|
663
|
+
decision out of the commits below, not assumed context
|
|
664
|
+
- Cover the motivation, the decisions, the trade-offs, and the
|
|
665
|
+
high-level architectural changes — never which files changed; \`git
|
|
666
|
+
diff --stat\` is for that, not this message
|
|
667
|
+
- If the range removes or renames a documented config key, CLI flag, or
|
|
668
|
+
workflow state — a public surface, not an internal one — add a literal
|
|
669
|
+
\`BREAKING CHANGE:\` footer naming what disappears. A \`!\` on the type
|
|
670
|
+
prefix alone (\`feat!:\`/\`refactor!:\`) is NOT enough: this repo's own
|
|
671
|
+
commit-analyzer has missed that marker before, cutting no release
|
|
672
|
+
until a follow-up commit carried the literal footer instead
|
|
673
|
+
|
|
674
|
+
The process's entry commit is \`${it.entryCommit}\`. ${human}Inspect the range: \`git log ${it.processBase}..${it.processTip}\`
|
|
675
|
+
and \`git diff ${it.processBase} ${it.processTip}\` — exactly what
|
|
676
|
+
a squash or PR body should describe.
|
|
677
|
+
|
|
678
|
+
Token cost: ${it.processCost}
|
|
679
|
+
${it.processCostByModel.map((m) => `- ${m.model}: ${m.cost}\n`).join("")}
|
|
680
|
+
Print the closing message and stop — this writes nothing itself.
|
|
681
|
+
`
|
|
682
|
+
}
|