@pmelab/gtd 52.0.0 → 52.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 +5 -2
- package/dist/chunks/{reserved-D0MKVFFa.mjs → reserved-DxB5CROj.mjs} +46 -5
- package/dist/chunks/{review-ZzUQH1KZ.mjs → review-CKMSdvgW.mjs} +2 -2
- package/dist/chunks/{tail-I1-vVq0P.mjs → tail-QZc7Uz2U.mjs} +1 -1
- package/dist/workflows/cleanup.mjs +2 -2
- package/dist/workflows/feature.mjs +51 -4
- package/dist/workflows/fix.mjs +2 -2
- package/dist/workflows/review.mjs +3 -3
- package/dist/workflows/rollout.mjs +1 -1
- package/dist/workflows.mjs +93 -5
- package/package.json +5 -4
- package/src/testkit/steps.ts +13 -0
- package/src/workflows/feature/acceptance-criteria.feature +159 -3
- package/src/workflows/feature/continuation-cap.feature +4 -0
- package/src/workflows/feature/continuation-rebuild.feature +4 -0
- package/src/workflows/feature/continuation-slices.feature +4 -0
- package/src/workflows/feature/continuation.feature +4 -0
- package/src/workflows/feature/criteria.test.ts +22 -1
- package/src/workflows/feature/criteria.ts +66 -1
- package/src/workflows/feature/fast-path.feature +4 -0
- package/src/workflows/feature/feature.test.ts +6 -5
- package/src/workflows/feature/flag-mode.feature +4 -0
- package/src/workflows/feature/hands-on-skip.feature +40 -0
- package/src/workflows/feature/lens-models.feature +4 -0
- package/src/workflows/feature/lens-review.feature +4 -0
- package/src/workflows/feature/naive-acceptance.feature +4 -0
- package/src/workflows/feature/one-step-land.feature +4 -0
- package/src/workflows/feature/planning.ts +2 -1
- package/src/workflows/feature/prototype-rounds.feature +4 -0
- package/src/workflows/feature/prototype.feature +8 -0
- package/src/workflows/feature/refactor-absorbs.feature +4 -0
- package/src/workflows/feature/refactor-first.feature +4 -0
- package/src/workflows/feature/refactor-lens-models.feature +4 -0
- package/src/workflows/feature/refactor-rebuild.feature +4 -0
- package/src/workflows/feature/refactor-review.feature +20 -0
- package/src/workflows/feature/review-answers.feature +4 -0
- package/src/workflows/feature/review-gate.feature +12 -0
- package/src/workflows/feature/reviewer-walkthrough.feature +4 -0
- package/src/workflows/feature/risk-tier.feature +32 -0
- package/src/workflows/feature/seam-rejection.feature +8 -0
- package/src/workflows/feature/seam.feature +8 -0
- package/src/workflows/feature/seam.test.ts +4 -2
- package/src/workflows/feature/severity-budget.feature +4 -0
- package/src/workflows/feature/severity-sorted-review.feature +4 -0
- package/src/workflows/feature/slice-findings.feature +4 -0
- package/src/workflows/feature/slicing.feature +32 -0
- package/src/workflows/feature/standards.feature +4 -0
- package/src/workflows/feature/tier-pin.feature +4 -0
- package/src/workflows/shared/text.test.ts +40 -0
- package/src/workflows/shared/text.ts +50 -4
package/README.md
CHANGED
|
@@ -441,9 +441,12 @@ noted in steps 3 and 4 below.
|
|
|
441
441
|
entry is the agent's, moving on is refused. Leave the file untouched and
|
|
442
442
|
start the loop to accept the plan as-is, unanswered questions and all. The
|
|
443
443
|
file lists numbered acceptance criteria (`AC-1`, `AC-2`, …) that bind the
|
|
444
|
-
build
|
|
444
|
+
build, and an `## Impact` section mapping the units and public surfaces the
|
|
445
|
+
change touches — correct it here and the next lap re-explores from your edit.
|
|
446
|
+
Sketch your own criteria under an `Acceptance criteria` heading and, when a
|
|
445
447
|
judge finds every one clear and checkable, they are recorded as they are and
|
|
446
|
-
this moment is skipped
|
|
448
|
+
this moment is skipped: a `design.impact` agent turn writes Impact instead,
|
|
449
|
+
unreviewed. One vague criterion brings the moment back. See
|
|
447
450
|
[Acceptance criteria](docs/configuration.md#acceptance-criteria).
|
|
448
451
|
|
|
449
452
|
3. **You wait.** The agent first implements the requirements the quickest way
|
|
@@ -774,6 +774,19 @@ writing \`(no hands-on)\` between its ID and the colon:
|
|
|
774
774
|
Leave the tag off whatever a person can see by running the change. A
|
|
775
775
|
tag the human added or removed at the gate stays as they left it.
|
|
776
776
|
`;
|
|
777
|
+
const impactBlock = `
|
|
778
|
+
## Impact
|
|
779
|
+
|
|
780
|
+
\`.gtd/REQUIREMENTS.md\` carries a \`## Impact\` section: explore the
|
|
781
|
+
codebase (not just the start diff) and name the units and boundaries
|
|
782
|
+
this change touches, the public surfaces it affects (CLI commands and
|
|
783
|
+
flags, config keys, driver protocol, exported API), and anything
|
|
784
|
+
surprising. Name the project's own declared units first —
|
|
785
|
+
dependency-cruiser rules, workspace packages, module boundaries named
|
|
786
|
+
in its docs or agent instructions (\`AGENTS.md\`, \`CLAUDE.md\`). When
|
|
787
|
+
none is declared, fall back to directories and packages. Landing is
|
|
788
|
+
refused while the section is missing.
|
|
789
|
+
`;
|
|
777
790
|
const riskTierBlock = `
|
|
778
791
|
## Risk tier and production signals
|
|
779
792
|
|
|
@@ -813,7 +826,14 @@ ${footnoteFoldIn}${codeThreadReplies()}
|
|
|
813
826
|
or both
|
|
814
827
|
- Whichever lap this is, leave \`.gtd/REQUIREMENTS.md\`
|
|
815
828
|
uncommitted and finish once it reflects this lap's own work
|
|
816
|
-
${acceptanceCriteriaBlock}
|
|
829
|
+
${acceptanceCriteriaBlock}${impactBlock}
|
|
830
|
+
Every lap re-explores and leaves \`## Impact\` present. On a return
|
|
831
|
+
lap or review loop-back the human may have edited \`## Impact\` (or
|
|
832
|
+
footnoted it): read that edit from history (\`git log -1 -p --
|
|
833
|
+
.gtd/REQUIREMENTS.md\`), keep the human's correction, and
|
|
834
|
+
re-explore from it. A surprise the human must settle becomes an
|
|
835
|
+
entry under \`## Open Questions\`.
|
|
836
|
+
|
|
817
837
|
## First lap
|
|
818
838
|
|
|
819
839
|
\`.gtd/REQUIREMENTS.md\` does not exist yet (or holds whatever the
|
|
@@ -868,6 +888,21 @@ ${questionBarReturn}
|
|
|
868
888
|
made). If red, make that breakage the first concern, ahead of
|
|
869
889
|
everything else — the build assumes the suite started green
|
|
870
890
|
${riskTier ? riskTierBlock : ""}`;
|
|
891
|
+
const designImpactPrompt = () => `${styleBlock}
|
|
892
|
+
|
|
893
|
+
${styleFormatContract}
|
|
894
|
+
|
|
895
|
+
${stateFileRules}
|
|
896
|
+
- The only state file this turn touches is \`.gtd/REQUIREMENTS.md\`
|
|
897
|
+
— no other files for notes or output
|
|
898
|
+
- \`.gtd/REQUIREMENTS.md\` already holds the settled acceptance
|
|
899
|
+
criteria. Add a \`## Impact\` section and change nothing else — a
|
|
900
|
+
turn that touches anything outside it is refused
|
|
901
|
+
- No human reviews this before the build: put any surprise in the
|
|
902
|
+
Impact prose, never as a question
|
|
903
|
+
${impactBlock}
|
|
904
|
+
- Leave \`.gtd/REQUIREMENTS.md\` uncommitted and finish once it holds \`## Impact\`
|
|
905
|
+
`;
|
|
871
906
|
const clearCriteriaQuestion = {
|
|
872
907
|
id: "clear",
|
|
873
908
|
primitive: "noul",
|
|
@@ -900,9 +935,9 @@ const slicingPrompt = (cap) => `${stateFileRules}
|
|
|
900
935
|
- Read \`.gtd/REQUIREMENTS.md\`: its \`## Acceptance Criteria\` are settled
|
|
901
936
|
and more than ${cap}, too many to build in one slice
|
|
902
937
|
- Group them into slices in \`.gtd/SLICES.md\`, one \`## <title>\` heading per
|
|
903
|
-
slice over a \`- AC-<n>\` list item per criterion it builds.
|
|
904
|
-
|
|
905
|
-
at most ${cap} per slice
|
|
938
|
+
slice over a \`- AC-<n>\` list item per criterion it builds. Read the
|
|
939
|
+
\`## Impact\` section of \`.gtd/REQUIREMENTS.md\` and slice along the units it
|
|
940
|
+
names; every criterion in exactly one slice, at most ${cap} per slice
|
|
906
941
|
- Keep it coarse: as few slices as the cap allows, never one per criterion
|
|
907
942
|
- Order the slices so each builds on the ones before: they run in that order,
|
|
908
943
|
each from where the previous one landed
|
|
@@ -1568,6 +1603,9 @@ const listed = (paths, unreadable = []) => paths.map((path) => ` - \`${displayP
|
|
|
1568
1603
|
const isRed = (retry) => "red" in retry;
|
|
1569
1604
|
const isFault = (retry) => "fault" in retry;
|
|
1570
1605
|
const pickUp = (hash, exclude) => `Pick it up — \`git diff --binary --no-color --no-ext-diff --no-textconv ${hash}^ ${hash}${exclude === void 0 ? "" : ` -- ${quote(":(top)")} ${quote(`:(top,exclude)${exclude}`)}`} | git apply\``;
|
|
1606
|
+
const impactHints = `- Its \`## Impact\` section maps where the change lands — reviewed at the design
|
|
1607
|
+
gate when design ran. A starting point and hints, not a list of allowed files
|
|
1608
|
+
— change whatever the work needs`;
|
|
1571
1609
|
const criteriaBinding = (refused) => `- Its \`## Acceptance Criteria\` (\`AC-<n>\`) bind this turn: re-read them from
|
|
1572
1610
|
the file, never from memory, and stop only when each one holds. They are
|
|
1573
1611
|
settled — ${refused ? "a turn that changes them is refused" : "leave them as they are"}`;
|
|
@@ -1614,6 +1652,7 @@ the context limit first if the refactor is too big`}. \`gtd abandon\` gives the
|
|
|
1614
1652
|
/** `from`: a continuation of a pass that stopped at its context limit, in place of `retry`'s pick-up. */
|
|
1615
1653
|
const naivePassPrompt = (retry, slice, from) => `${stateFileRules}
|
|
1616
1654
|
- Read \`.gtd/REQUIREMENTS.md\`: the settled requirements for this change
|
|
1655
|
+
${impactHints}
|
|
1617
1656
|
${sliceLine(slice)}${criteriaBinding(false)}
|
|
1618
1657
|
- Implement them the quickest way that works — the naive version. Do not
|
|
1619
1658
|
restructure, abstract or refactor around the change; it may land exactly as
|
|
@@ -1681,6 +1720,7 @@ const flagLine = (flagMode, tier, amend, sliced) => !flagMode ? "- Add no releas
|
|
|
1681
1720
|
repository's flag conventions`;
|
|
1682
1721
|
const implementBuildingPrompt = (reference, tier, amend, afterRefactor, flagMode = true, rebuild = {}, slice, from) => `${stateFileRules}
|
|
1683
1722
|
- Read \`.gtd/REQUIREMENTS.md\`: the settled requirements for this change
|
|
1723
|
+
${impactHints}
|
|
1684
1724
|
${sliceLine(slice)}${criteriaBinding(true)}
|
|
1685
1725
|
${afterRefactor === true ? afterRefactorLine(rebuild) : ""}${amend === true ? `- The change already exists in the tree from an earlier lap; amend it to meet
|
|
1686
1726
|
the re-derived requirements instead of rewriting it
|
|
@@ -1816,6 +1856,7 @@ ${retest ? `- This is a re-test: \`.gtd/PROTOTYPE.md\` holds the last round's re
|
|
|
1816
1856
|
`;
|
|
1817
1857
|
const prototypeFixingPrompt = (slice) => `${stateFileRules}
|
|
1818
1858
|
- Read \`.gtd/REQUIREMENTS.md\`: the settled requirements for this change
|
|
1859
|
+
${impactHints}
|
|
1819
1860
|
${sliceLine(slice)}${criteriaBinding(true)}
|
|
1820
1861
|
- Read \`.gtd/PROTOTYPE.md\`: a hands-on test of the change. Fix every
|
|
1821
1862
|
\`fail\` chunk of this change's criteria${slice === void 0 ? "" : " (this slice's only)"} or a problem found
|
|
@@ -2214,4 +2255,4 @@ const steering = {
|
|
|
2214
2255
|
[REVIEW]: "review"
|
|
2215
2256
|
};
|
|
2216
2257
|
//#endregion
|
|
2217
|
-
export {
|
|
2258
|
+
export { naivePassPrompt as $, reviewMissing as A, unwindFailedMessage as At, composedReview as B, conflictFor as Bt, coder as C, seamByHandMessage as Ct, fixQuality as D, testerSystem as Dt, fixNits as E, startGateBlockedMessage as Et, buildReviewTriageMessage as F, defaults as Ft, designTriagePrompt as G, renderStandards as Gt, designGateAnswerMessage as H, isConflictTitle as Ht, builderSystem as I, envDefaults as It, handOffAwaitReviewMessage as J, flagReferences as Jt, finisherSystem as K, standardKey as Kt, chunkTexts as L, testFileGlobs as Lt, reviewing as M, walkthroughBlock as Mt, agentWithSkills as N, withLapFindings as Nt, fixRisks as O, titledNotes as Ot, buildReviewCollectingPrompt as P, withWalkthrough as Pt, naiveApplyFailure as Q, clearCriteriaMessage as R, STANDARDS as Rt, awaitReview as S, reviewerSystem as St, fixCheck as T, slicingPrompt as Tt, designImpactPrompt as U, oneLine as Ut, criterionLine as V, conflictTitle as Vt, designSystem as W, parseStandards as Wt, implementBuildingPrompt as X, registryEntry as Xt, idleMessage as Y, flipProblems as Yt, implementFixPrompt as Z, requireFlag as Zt, REFACTOR_NOTE as _, reviewEditsCapture as _t, flagModeOn as a, prototypeOpenMessage as at, SLICES as b, reviewNotesCapture as bt, baseline as c, qualityFindingsFile as ct, healthy as d, refactorBuildingPrompt as dt, normaliseCriteriaScript as et, FEEDBACK as f, refactorDroppedRefusal as ft, REFACTOR as g, reviewEditNotesCapture as gt, QUALITY as h, refactorRules as ht, skills as i, prototypeFixingPrompt as it, reviewQuality as j, unwindFailure as jt, planner as k, unranked as kt, gate as l, qualityTriageMessage as lt, PROTOTYPE as m, refactorNotePrompt as mt, summary as n, observableQuestion as nt, flagShipped as o, prototypeTestingPrompt as ot, HANDOFF as p, refactorFixPrompt as pt, fixReviewNotesPrompt as q, flagMentions as qt, access as r, oversizedMessage as rt, shipped as s, prototypeUnguidedMessage as st, steering as t, observableMessage as tt, guarded as u, rankedReview as ut, REQUIREMENTS as v, reviewFeedbackFixPrompt as vt, collecting as w, seamSteerMessage as wt, answerReviewQuestions as x, reviewRankingMessage as xt, REVIEW as y, reviewGateBlockedMessage as yt, clearCriteriaQuestion as z, conflictBody as zt };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { answered, changesSince, head, judge, numeric, read, refuse, requireRevert, restoreScript, run, showScript, vars, writeScript } from "../flows.mjs";
|
|
2
2
|
import { b as sectionedReview, h as reviewChunks, m as REVIEW_SECTIONS, v as reviewRisks, y as reviewSections } from "./steering-CLhu8C7q.mjs";
|
|
3
3
|
import { removedAssertions, review } from "../workflow-kit.mjs";
|
|
4
|
-
import { A as reviewMissing, B as composedReview, Bt as
|
|
5
|
-
import { i as isOptionalObject, n as closeReview, o as tail, s as NO_FINDINGS } from "./tail-
|
|
4
|
+
import { A as reviewMissing, B as composedReview, Bt as conflictFor, E as fixNits, F as buildReviewTriageMessage, Gt as renderStandards, Ht as isConflictTitle, Kt as standardKey, L as chunkTexts, M as reviewing, Mt as walkthroughBlock, O as fixRisks, Ot as titledNotes, Pt as withWalkthrough, Rt as STANDARDS, S as awaitReview, T as fixCheck, Ut as oneLine, Vt as conflictTitle, Wt as parseStandards, _t as reviewEditsCapture, bt as reviewNotesCapture, d as healthy, gt as reviewEditNotesCapture, kt as unranked, u as guarded, ut as rankedReview, w as collecting, x as answerReviewQuestions, xt as reviewRankingMessage, y as REVIEW, zt as conflictBody } from "./reserved-DxB5CROj.mjs";
|
|
5
|
+
import { i as isOptionalObject, n as closeReview, o as tail, s as NO_FINDINGS } from "./tail-QZc7Uz2U.mjs";
|
|
6
6
|
//#region src/workflows/shared/learn.ts
|
|
7
7
|
const SUMMARY_MAX = 200;
|
|
8
8
|
const BANNER = /^_(?:The fixer left this unresolved\.|A fix turn removed this while renaming another finding — check whether it was fixed\.|No detail given\.)_\s*/;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { answered, head, judge, mark, numeric, read, refuse, removeScript, run, scope, sectionBodies, showScript, vars, writeScript } from "../flows.mjs";
|
|
2
2
|
import { lensEntriesOf, lensOf, qualityLap, reviewToHandOff } from "../workflow-kit.mjs";
|
|
3
|
-
import { A as reviewMissing, D as fixQuality, M as reviewing,
|
|
3
|
+
import { A as reviewMissing, D as fixQuality, J as handOffAwaitReviewMessage, M as reviewing, Nt as withLapFindings, O as fixRisks, S as awaitReview, T as fixCheck, ct as qualityFindingsFile, d as healthy, h as QUALITY, j as reviewQuality, lt as qualityTriageMessage, u as guarded, y as REVIEW } from "./reserved-DxB5CROj.mjs";
|
|
4
4
|
//#region src/workflows/shared/lenses.ts
|
|
5
5
|
const NO_FINDINGS = {
|
|
6
6
|
notes: [],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { agent, changes, glob, read, refuse, scope, start, vars } from "../flows.mjs";
|
|
2
|
-
import { C as coder, Ft as envDefaults,
|
|
3
|
-
import { a as refusePendingHandOff, r as handOffTail } from "../chunks/tail-
|
|
2
|
+
import { C as coder, Ft as defaults, It as envDefaults, Jt as flagReferences, Xt as registryEntry, Zt as requireFlag, i as skills, n as summary, o as flagShipped, r as access, t as steering } from "../chunks/reserved-DxB5CROj.mjs";
|
|
3
|
+
import { a as refusePendingHandOff, r as handOffTail } from "../chunks/tail-QZc7Uz2U.mjs";
|
|
4
4
|
//#region src/workflows/cleanup/cleanup.ts
|
|
5
5
|
const removingPrompt = (name, registry) => `Clean up the release flag "${name}", which is default-on: delete its entry in ${registry}, and remove every \`GTD_FLAG_${name.toUpperCase()}\` check from the shipped sources. Keep the flag-on path; delete code only the off path reached, including tests that pin the off path.`;
|
|
6
6
|
const cleanupFlow = async () => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { agent, answered, applyScript, changes, changesSince, check, codeChanges, env, hasThreadFor, head, human, judge, judgeDiffShape, kept, mark, matches, quote, read, refuse, removeScript, requireAnswers, requireProgress, requireReplies, requireThreadsClosed, revertScript, run, scope, slice, start, vars, wrote } from "../flows.mjs";
|
|
2
2
|
import { lensEntriesOf } from "../workflow-kit.mjs";
|
|
3
|
-
import { $ as
|
|
4
|
-
import { a as refusePendingHandOff, c as joinReports, o as tail } from "../chunks/tail-
|
|
5
|
-
import { i as reUnwind, n as humanReview, r as isCode$1, t as buildTail } from "../chunks/review-
|
|
3
|
+
import { $ as naivePassPrompt, At as unwindFailedMessage, C as coder, Ct as seamByHandMessage, Dt as testerSystem, E as fixNits, Et as startGateBlockedMessage, Ft as defaults, G as designTriagePrompt, H as designGateAnswerMessage, I as builderSystem, It as envDefaults, Lt as testFileGlobs, N as agentWithSkills, P as buildReviewCollectingPrompt, Q as naiveApplyFailure, R as clearCriteriaMessage, St as reviewerSystem, Tt as slicingPrompt, U as designImpactPrompt, V as criterionLine, W as designSystem, X as implementBuildingPrompt, Y as idleMessage, Z as implementFixPrompt, _ as REFACTOR_NOTE, a as flagModeOn, at as prototypeOpenMessage, b as SLICES, d as healthy, dt as refactorBuildingPrompt, et as normaliseCriteriaScript, f as FEEDBACK, ft as refactorDroppedRefusal, g as REFACTOR, ht as refactorRules, i as skills, it as prototypeFixingPrompt, jt as unwindFailure, k as planner, l as gate, m as PROTOTYPE, mt as refactorNotePrompt, n as summary, nt as observableQuestion, ot as prototypeTestingPrompt, p as HANDOFF, pt as refactorFixPrompt, r as access, rt as oversizedMessage, s as shipped, st as prototypeUnguidedMessage, t as steering, tt as observableMessage, v as REQUIREMENTS, w as collecting, wt as seamSteerMessage, x as answerReviewQuestions, z as clearCriteriaQuestion } from "../chunks/reserved-DxB5CROj.mjs";
|
|
4
|
+
import { a as refusePendingHandOff, c as joinReports, o as tail } from "../chunks/tail-QZc7Uz2U.mjs";
|
|
5
|
+
import { i as reUnwind, n as humanReview, r as isCode$1, t as buildTail } from "../chunks/review-CKMSdvgW.mjs";
|
|
6
6
|
import { posix } from "node:path";
|
|
7
7
|
//#region src/workflows/shared/fences.ts
|
|
8
8
|
const markFenced = (text) => {
|
|
@@ -121,6 +121,38 @@ const requireCriteria = (file) => {
|
|
|
121
121
|
if (criteria.length > 0 && unnamed.length === 0 && twice.length === 0) return;
|
|
122
122
|
refuse(`gtd land: acceptance-criteria: ${file} has ${criteria.length === 0 ? `no "## Acceptance Criteria" list` : unnamed.length > 0 ? `${unnamed.length} criterion without an ID:\n${unnamed.map((c) => ` - ${c.text}`).join("\n")}` : `duplicate IDs: ${[...new Set(twice)].join(", ")}`} — list every criterion under "## Acceptance Criteria" as "- AC-<n>: <checkable criterion>", each ID unique and never reused`);
|
|
123
123
|
};
|
|
124
|
+
const isImpactHeading = (h) => h !== null && h[1].length === 2 && /^impact$/i.test(h[2].trim());
|
|
125
|
+
/** Whether `text` has an unfenced, level-2 `## Impact` heading. */
|
|
126
|
+
const hasImpact = (text) => markFenced(text).some((l) => !l.fenced && isImpactHeading(HEADING.exec(l.line)));
|
|
127
|
+
/** `text` without its `## Impact` section, whitespace collapsed. */
|
|
128
|
+
const withoutImpact = (text) => {
|
|
129
|
+
let inImpact = false;
|
|
130
|
+
return markFenced(text).filter((l) => {
|
|
131
|
+
const h = l.fenced ? null : HEADING.exec(l.line);
|
|
132
|
+
if (h !== null && h[1].length <= 2) inImpact = isImpactHeading(h);
|
|
133
|
+
return !inImpact;
|
|
134
|
+
}).map((l) => l.line).join(" ").replace(/\s+/g, " ").trim();
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Refuse a turn that leaves `file` without a `## Impact` section. Only the
|
|
138
|
+
* pending turn (`head()` is `""`): a triage lap recorded before Impact existed
|
|
139
|
+
* replays without one, and refusing there would fail every in-flight process.
|
|
140
|
+
* A human's edit at a later gate is not checked — the human owns that file then.
|
|
141
|
+
*/
|
|
142
|
+
const requireImpact = (file) => {
|
|
143
|
+
if (head() !== "") return;
|
|
144
|
+
const text = read(file);
|
|
145
|
+
if (text === void 0) return;
|
|
146
|
+
if (hasImpact(text)) return;
|
|
147
|
+
refuse(`gtd land: impact: ${file} has no "## Impact" section — explore the codebase and add "## Impact" naming the units, public surfaces and surprises this change touches`);
|
|
148
|
+
};
|
|
149
|
+
/** Refuse a turn that changed `file` beyond its `## Impact` section. */
|
|
150
|
+
const requireImpactOnly = (file) => {
|
|
151
|
+
const change = changes().get(file);
|
|
152
|
+
if (change === void 0) return;
|
|
153
|
+
if (withoutImpact(change.before ?? "") === withoutImpact(change.after ?? "")) return;
|
|
154
|
+
refuse(`gtd land: impact-only: this turn may only add "## Impact" to ${file} — restore everything else`);
|
|
155
|
+
};
|
|
124
156
|
const idNumber = (id) => Number(id.slice(3));
|
|
125
157
|
/** Why `listed` renumbers or reuses an earlier ID; `undefined` when it does neither. */
|
|
126
158
|
const unstableIds = (listed, ids) => {
|
|
@@ -154,6 +186,19 @@ const clear = async (stated) => {
|
|
|
154
186
|
});
|
|
155
187
|
return truncated.length === 0 && answered(answers.clear, "yes", CLEAR_MIN_P);
|
|
156
188
|
};
|
|
189
|
+
/** The fast path's impact-only turn: add `## Impact`, leave the criteria alone. */
|
|
190
|
+
const impact = async () => {
|
|
191
|
+
await agentWithSkills("impact", designImpactPrompt(), {
|
|
192
|
+
label: "Mapping the change's impact",
|
|
193
|
+
file: REQUIREMENTS,
|
|
194
|
+
model: planner(),
|
|
195
|
+
system: designSystem()
|
|
196
|
+
});
|
|
197
|
+
requireProgress(REQUIREMENTS);
|
|
198
|
+
requireCriteriaFrozen(REQUIREMENTS);
|
|
199
|
+
requireImpact(REQUIREMENTS);
|
|
200
|
+
requireImpactOnly(REQUIREMENTS);
|
|
201
|
+
};
|
|
157
202
|
/**
|
|
158
203
|
* The skip path: when the sketch stated clear, checkable criteria, write them
|
|
159
204
|
* to `.gtd/REQUIREMENTS.md` as they are and resolve `true` — no triage, no
|
|
@@ -165,6 +210,7 @@ const skipDesign = (stated) => stated === void 0 ? Promise.resolve(false) : scop
|
|
|
165
210
|
label: "Recording the stated acceptance criteria",
|
|
166
211
|
file: REQUIREMENTS
|
|
167
212
|
});
|
|
213
|
+
await impact();
|
|
168
214
|
return true;
|
|
169
215
|
});
|
|
170
216
|
/** After a gate that invites narrowing the requirements: an edit must leave valid criteria. */
|
|
@@ -261,6 +307,7 @@ const design = (base, guard) => scope("design", async () => {
|
|
|
261
307
|
requireProgress(REQUIREMENTS);
|
|
262
308
|
requireReplies(REQUIREMENTS);
|
|
263
309
|
requireCriteria(REQUIREMENTS);
|
|
310
|
+
requireImpact(REQUIREMENTS);
|
|
264
311
|
guard?.();
|
|
265
312
|
} while (await noteGate(REQUIREMENTS, answerProductQuestions));
|
|
266
313
|
});
|
|
@@ -1345,4 +1392,4 @@ const feature = shipped(ordinaryStart);
|
|
|
1345
1392
|
//#region src/workflows/feature/index.ts
|
|
1346
1393
|
var feature_default = feature;
|
|
1347
1394
|
//#endregion
|
|
1348
|
-
export { COMMENT, REFACTOR_PACKAGE, acceptanceFault, access, afterTail, answerProductQuestions, answerReviewQuestions, buildFeature, buildTail, closeOut, collecting, criteriaOf, criterionIds, feature_default as default, defaults, design, envDefaults, feature, fixNits, handsOnIds, holdsCallSites, implement, implementing, isTestFile, judgeSeam, naiveAcceptance, naivePass, ordinaryStart, planAndBuild, reUnwind, refactorCollecting, refactorFirst, refactorNote, refactorStrays, requireAcceptance, requireAcceptanceKept, requireCriteria, requireCriteriaFrozen, requireCriteriaIfEdited, requireNoNewFlags, requireNoTestFiles, requireSlices, requireStableIds, requireTestCallSitesOnly, requireWithin, reviewedRefactor, seamBuild, skills, skipDesign, sliceCap, sliceCriteria, sliceIds, slicesOf, slicing, statedCriteria, steering, summary, triage, unstableIds, unwind };
|
|
1395
|
+
export { COMMENT, REFACTOR_PACKAGE, acceptanceFault, access, afterTail, answerProductQuestions, answerReviewQuestions, buildFeature, buildTail, closeOut, collecting, criteriaOf, criterionIds, feature_default as default, defaults, design, envDefaults, feature, fixNits, handsOnIds, hasImpact, holdsCallSites, implement, implementing, isTestFile, judgeSeam, naiveAcceptance, naivePass, ordinaryStart, planAndBuild, reUnwind, refactorCollecting, refactorFirst, refactorNote, refactorStrays, requireAcceptance, requireAcceptanceKept, requireCriteria, requireCriteriaFrozen, requireCriteriaIfEdited, requireImpact, requireImpactOnly, requireNoNewFlags, requireNoTestFiles, requireSlices, requireStableIds, requireTestCallSitesOnly, requireWithin, reviewedRefactor, seamBuild, skills, skipDesign, sliceCap, sliceCriteria, sliceIds, slicesOf, slicing, statedCriteria, steering, summary, triage, unstableIds, unwind };
|
package/dist/workflows/fix.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { read, refuse, removeScript, run, scope, start } from "../flows.mjs";
|
|
2
2
|
import { _ as reviewNotes, v as reviewRisks } from "../chunks/steering-CLhu8C7q.mjs";
|
|
3
|
-
import { C as coder, Ft as
|
|
4
|
-
import { r as handOffTail, t as REVIEW_ORIG } from "../chunks/tail-
|
|
3
|
+
import { C as coder, Ft as defaults, It as envDefaults, K as finisherSystem, N as agentWithSkills, c as baseline, i as skills, n as summary, q as fixReviewNotesPrompt, r as access, s as shipped, t as steering, y as REVIEW } from "../chunks/reserved-DxB5CROj.mjs";
|
|
4
|
+
import { r as handOffTail, t as REVIEW_ORIG } from "../chunks/tail-QZc7Uz2U.mjs";
|
|
5
5
|
//#region src/workflows/fix/fix.ts
|
|
6
6
|
/**
|
|
7
7
|
* Fix every note a human left in a handed-off `.gtd/REVIEW.md` and every
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { read, refuse, removeScript, run, start } from "../flows.mjs";
|
|
2
|
-
import { C as coder, Ft as
|
|
3
|
-
import { a as refusePendingHandOff } from "../chunks/tail-
|
|
4
|
-
import { i as reUnwind, t as buildTail } from "../chunks/review-
|
|
2
|
+
import { C as coder, Ft as defaults, It as envDefaults, K as finisherSystem, N as agentWithSkills, i as skills, l as gate, n as summary, r as access, s as shipped, t as steering, v as REQUIREMENTS, vt as reviewFeedbackFixPrompt, yt as reviewGateBlockedMessage } from "../chunks/reserved-DxB5CROj.mjs";
|
|
3
|
+
import { a as refusePendingHandOff } from "../chunks/tail-QZc7Uz2U.mjs";
|
|
4
|
+
import { i as reUnwind, t as buildTail } from "../chunks/review-CKMSdvgW.mjs";
|
|
5
5
|
//#region src/workflows/review/review.ts
|
|
6
6
|
const fixFeedback = async () => {
|
|
7
7
|
await agentWithSkills("feedback.fixing", reviewFeedbackFixPrompt(), {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { agent, changesSince, glob, head, mark, read, refuse, removeScript, run, scope, vars } from "../flows.mjs";
|
|
2
|
-
import { C as coder, Ft as
|
|
2
|
+
import { C as coder, Ft as defaults, It as envDefaults, Yt as flipProblems, Zt as requireFlag, f as FEEDBACK, i as skills, l as gate, n as summary, o as flagShipped, qt as flagMentions, r as access, t as steering } from "../chunks/reserved-DxB5CROj.mjs";
|
|
3
3
|
//#region src/workflows/rollout/rollout.ts
|
|
4
4
|
const flippingPrompt = (name, registry) => `Roll out the release flag "${name}": in ${registry}, set \`defaultOn: true\` on its entry. Change nothing else — no other entry, no other field, no other file, no comments.`;
|
|
5
5
|
const suiteBlockedMessage = () => "The suite is red after the rollout. Fix it by hand — a rollout may only touch the flag's registry entry — then land.";
|
package/dist/workflows.mjs
CHANGED
|
@@ -17982,6 +17982,19 @@ writing \`(no hands-on)\` between its ID and the colon:
|
|
|
17982
17982
|
Leave the tag off whatever a person can see by running the change. A
|
|
17983
17983
|
tag the human added or removed at the gate stays as they left it.
|
|
17984
17984
|
`;
|
|
17985
|
+
const impactBlock = `
|
|
17986
|
+
## Impact
|
|
17987
|
+
|
|
17988
|
+
\`.gtd/REQUIREMENTS.md\` carries a \`## Impact\` section: explore the
|
|
17989
|
+
codebase (not just the start diff) and name the units and boundaries
|
|
17990
|
+
this change touches, the public surfaces it affects (CLI commands and
|
|
17991
|
+
flags, config keys, driver protocol, exported API), and anything
|
|
17992
|
+
surprising. Name the project's own declared units first —
|
|
17993
|
+
dependency-cruiser rules, workspace packages, module boundaries named
|
|
17994
|
+
in its docs or agent instructions (\`AGENTS.md\`, \`CLAUDE.md\`). When
|
|
17995
|
+
none is declared, fall back to directories and packages. Landing is
|
|
17996
|
+
refused while the section is missing.
|
|
17997
|
+
`;
|
|
17985
17998
|
const riskTierBlock = `
|
|
17986
17999
|
## Risk tier and production signals
|
|
17987
18000
|
|
|
@@ -18021,7 +18034,14 @@ ${footnoteFoldIn}${codeThreadReplies()}
|
|
|
18021
18034
|
or both
|
|
18022
18035
|
- Whichever lap this is, leave \`.gtd/REQUIREMENTS.md\`
|
|
18023
18036
|
uncommitted and finish once it reflects this lap's own work
|
|
18024
|
-
${acceptanceCriteriaBlock}
|
|
18037
|
+
${acceptanceCriteriaBlock}${impactBlock}
|
|
18038
|
+
Every lap re-explores and leaves \`## Impact\` present. On a return
|
|
18039
|
+
lap or review loop-back the human may have edited \`## Impact\` (or
|
|
18040
|
+
footnoted it): read that edit from history (\`git log -1 -p --
|
|
18041
|
+
.gtd/REQUIREMENTS.md\`), keep the human's correction, and
|
|
18042
|
+
re-explore from it. A surprise the human must settle becomes an
|
|
18043
|
+
entry under \`## Open Questions\`.
|
|
18044
|
+
|
|
18025
18045
|
## First lap
|
|
18026
18046
|
|
|
18027
18047
|
\`.gtd/REQUIREMENTS.md\` does not exist yet (or holds whatever the
|
|
@@ -18076,6 +18096,21 @@ ${questionBarReturn}
|
|
|
18076
18096
|
made). If red, make that breakage the first concern, ahead of
|
|
18077
18097
|
everything else — the build assumes the suite started green
|
|
18078
18098
|
${riskTier ? riskTierBlock : ""}`;
|
|
18099
|
+
const designImpactPrompt = () => `${styleBlock}
|
|
18100
|
+
|
|
18101
|
+
${styleFormatContract}
|
|
18102
|
+
|
|
18103
|
+
${stateFileRules}
|
|
18104
|
+
- The only state file this turn touches is \`.gtd/REQUIREMENTS.md\`
|
|
18105
|
+
— no other files for notes or output
|
|
18106
|
+
- \`.gtd/REQUIREMENTS.md\` already holds the settled acceptance
|
|
18107
|
+
criteria. Add a \`## Impact\` section and change nothing else — a
|
|
18108
|
+
turn that touches anything outside it is refused
|
|
18109
|
+
- No human reviews this before the build: put any surprise in the
|
|
18110
|
+
Impact prose, never as a question
|
|
18111
|
+
${impactBlock}
|
|
18112
|
+
- Leave \`.gtd/REQUIREMENTS.md\` uncommitted and finish once it holds \`## Impact\`
|
|
18113
|
+
`;
|
|
18079
18114
|
const clearCriteriaQuestion = {
|
|
18080
18115
|
id: "clear",
|
|
18081
18116
|
primitive: "noul",
|
|
@@ -18108,9 +18143,9 @@ const slicingPrompt = (cap) => `${stateFileRules}
|
|
|
18108
18143
|
- Read \`.gtd/REQUIREMENTS.md\`: its \`## Acceptance Criteria\` are settled
|
|
18109
18144
|
and more than ${cap}, too many to build in one slice
|
|
18110
18145
|
- Group them into slices in \`.gtd/SLICES.md\`, one \`## <title>\` heading per
|
|
18111
|
-
slice over a \`- AC-<n>\` list item per criterion it builds.
|
|
18112
|
-
|
|
18113
|
-
at most ${cap} per slice
|
|
18146
|
+
slice over a \`- AC-<n>\` list item per criterion it builds. Read the
|
|
18147
|
+
\`## Impact\` section of \`.gtd/REQUIREMENTS.md\` and slice along the units it
|
|
18148
|
+
names; every criterion in exactly one slice, at most ${cap} per slice
|
|
18114
18149
|
- Keep it coarse: as few slices as the cap allows, never one per criterion
|
|
18115
18150
|
- Order the slices so each builds on the ones before: they run in that order,
|
|
18116
18151
|
each from where the previous one landed
|
|
@@ -18776,6 +18811,9 @@ const listed = (paths, unreadable = []) => paths.map((path) => ` - \`${displayP
|
|
|
18776
18811
|
const isRed = (retry) => "red" in retry;
|
|
18777
18812
|
const isFault = (retry) => "fault" in retry;
|
|
18778
18813
|
const pickUp = (hash, exclude) => `Pick it up — \`git diff --binary --no-color --no-ext-diff --no-textconv ${hash}^ ${hash}${exclude === void 0 ? "" : ` -- ${quote(":(top)")} ${quote(`:(top,exclude)${exclude}`)}`} | git apply\``;
|
|
18814
|
+
const impactHints = `- Its \`## Impact\` section maps where the change lands — reviewed at the design
|
|
18815
|
+
gate when design ran. A starting point and hints, not a list of allowed files
|
|
18816
|
+
— change whatever the work needs`;
|
|
18779
18817
|
const criteriaBinding = (refused) => `- Its \`## Acceptance Criteria\` (\`AC-<n>\`) bind this turn: re-read them from
|
|
18780
18818
|
the file, never from memory, and stop only when each one holds. They are
|
|
18781
18819
|
settled — ${refused ? "a turn that changes them is refused" : "leave them as they are"}`;
|
|
@@ -18822,6 +18860,7 @@ the context limit first if the refactor is too big`}. \`gtd abandon\` gives the
|
|
|
18822
18860
|
/** `from`: a continuation of a pass that stopped at its context limit, in place of `retry`'s pick-up. */
|
|
18823
18861
|
const naivePassPrompt = (retry, slice, from) => `${stateFileRules}
|
|
18824
18862
|
- Read \`.gtd/REQUIREMENTS.md\`: the settled requirements for this change
|
|
18863
|
+
${impactHints}
|
|
18825
18864
|
${sliceLine(slice)}${criteriaBinding(false)}
|
|
18826
18865
|
- Implement them the quickest way that works — the naive version. Do not
|
|
18827
18866
|
restructure, abstract or refactor around the change; it may land exactly as
|
|
@@ -18889,6 +18928,7 @@ const flagLine = (flagMode, tier, amend, sliced) => !flagMode ? "- Add no releas
|
|
|
18889
18928
|
repository's flag conventions`;
|
|
18890
18929
|
const implementBuildingPrompt = (reference, tier, amend, afterRefactor, flagMode = true, rebuild = {}, slice, from) => `${stateFileRules}
|
|
18891
18930
|
- Read \`.gtd/REQUIREMENTS.md\`: the settled requirements for this change
|
|
18931
|
+
${impactHints}
|
|
18892
18932
|
${sliceLine(slice)}${criteriaBinding(true)}
|
|
18893
18933
|
${afterRefactor === true ? afterRefactorLine(rebuild) : ""}${amend === true ? `- The change already exists in the tree from an earlier lap; amend it to meet
|
|
18894
18934
|
the re-derived requirements instead of rewriting it
|
|
@@ -19024,6 +19064,7 @@ ${retest ? `- This is a re-test: \`.gtd/PROTOTYPE.md\` holds the last round's re
|
|
|
19024
19064
|
`;
|
|
19025
19065
|
const prototypeFixingPrompt = (slice) => `${stateFileRules}
|
|
19026
19066
|
- Read \`.gtd/REQUIREMENTS.md\`: the settled requirements for this change
|
|
19067
|
+
${impactHints}
|
|
19027
19068
|
${sliceLine(slice)}${criteriaBinding(true)}
|
|
19028
19069
|
- Read \`.gtd/PROTOTYPE.md\`: a hands-on test of the change. Fix every
|
|
19029
19070
|
\`fail\` chunk of this change's criteria${slice === void 0 ? "" : " (this slice's only)"} or a problem found
|
|
@@ -39090,6 +39131,38 @@ const requireCriteria = (file) => {
|
|
|
39090
39131
|
if (criteria.length > 0 && unnamed.length === 0 && twice.length === 0) return;
|
|
39091
39132
|
refuse(`gtd land: acceptance-criteria: ${file} has ${criteria.length === 0 ? `no "## Acceptance Criteria" list` : unnamed.length > 0 ? `${unnamed.length} criterion without an ID:\n${unnamed.map((c) => ` - ${c.text}`).join("\n")}` : `duplicate IDs: ${[...new Set(twice)].join(", ")}`} — list every criterion under "## Acceptance Criteria" as "- AC-<n>: <checkable criterion>", each ID unique and never reused`);
|
|
39092
39133
|
};
|
|
39134
|
+
const isImpactHeading = (h) => h !== null && h[1].length === 2 && /^impact$/i.test(h[2].trim());
|
|
39135
|
+
/** Whether `text` has an unfenced, level-2 `## Impact` heading. */
|
|
39136
|
+
const hasImpact = (text) => markFenced(text).some((l) => !l.fenced && isImpactHeading(HEADING.exec(l.line)));
|
|
39137
|
+
/** `text` without its `## Impact` section, whitespace collapsed. */
|
|
39138
|
+
const withoutImpact = (text) => {
|
|
39139
|
+
let inImpact = false;
|
|
39140
|
+
return markFenced(text).filter((l) => {
|
|
39141
|
+
const h = l.fenced ? null : HEADING.exec(l.line);
|
|
39142
|
+
if (h !== null && h[1].length <= 2) inImpact = isImpactHeading(h);
|
|
39143
|
+
return !inImpact;
|
|
39144
|
+
}).map((l) => l.line).join(" ").replace(/\s+/g, " ").trim();
|
|
39145
|
+
};
|
|
39146
|
+
/**
|
|
39147
|
+
* Refuse a turn that leaves `file` without a `## Impact` section. Only the
|
|
39148
|
+
* pending turn (`head()` is `""`): a triage lap recorded before Impact existed
|
|
39149
|
+
* replays without one, and refusing there would fail every in-flight process.
|
|
39150
|
+
* A human's edit at a later gate is not checked — the human owns that file then.
|
|
39151
|
+
*/
|
|
39152
|
+
const requireImpact = (file) => {
|
|
39153
|
+
if (head$1() !== "") return;
|
|
39154
|
+
const text = read(file);
|
|
39155
|
+
if (text === void 0) return;
|
|
39156
|
+
if (hasImpact(text)) return;
|
|
39157
|
+
refuse(`gtd land: impact: ${file} has no "## Impact" section — explore the codebase and add "## Impact" naming the units, public surfaces and surprises this change touches`);
|
|
39158
|
+
};
|
|
39159
|
+
/** Refuse a turn that changed `file` beyond its `## Impact` section. */
|
|
39160
|
+
const requireImpactOnly = (file) => {
|
|
39161
|
+
const change = changes().get(file);
|
|
39162
|
+
if (change === void 0) return;
|
|
39163
|
+
if (withoutImpact(change.before ?? "") === withoutImpact(change.after ?? "")) return;
|
|
39164
|
+
refuse(`gtd land: impact-only: this turn may only add "## Impact" to ${file} — restore everything else`);
|
|
39165
|
+
};
|
|
39093
39166
|
const idNumber = (id) => Number(id.slice(3));
|
|
39094
39167
|
/** Why `listed` renumbers or reuses an earlier ID; `undefined` when it does neither. */
|
|
39095
39168
|
const unstableIds = (listed, ids) => {
|
|
@@ -39123,6 +39196,19 @@ const clear = async (stated) => {
|
|
|
39123
39196
|
});
|
|
39124
39197
|
return truncated.length === 0 && answered(answers.clear, "yes", CLEAR_MIN_P);
|
|
39125
39198
|
};
|
|
39199
|
+
/** The fast path's impact-only turn: add `## Impact`, leave the criteria alone. */
|
|
39200
|
+
const impact = async () => {
|
|
39201
|
+
await agentWithSkills("impact", designImpactPrompt(), {
|
|
39202
|
+
label: "Mapping the change's impact",
|
|
39203
|
+
file: REQUIREMENTS,
|
|
39204
|
+
model: planner(),
|
|
39205
|
+
system: designSystem()
|
|
39206
|
+
});
|
|
39207
|
+
requireProgress(REQUIREMENTS);
|
|
39208
|
+
requireCriteriaFrozen(REQUIREMENTS);
|
|
39209
|
+
requireImpact(REQUIREMENTS);
|
|
39210
|
+
requireImpactOnly(REQUIREMENTS);
|
|
39211
|
+
};
|
|
39126
39212
|
/**
|
|
39127
39213
|
* The skip path: when the sketch stated clear, checkable criteria, write them
|
|
39128
39214
|
* to `.gtd/REQUIREMENTS.md` as they are and resolve `true` — no triage, no
|
|
@@ -39134,6 +39220,7 @@ const skipDesign = (stated) => stated === void 0 ? Promise.resolve(false) : scop
|
|
|
39134
39220
|
label: "Recording the stated acceptance criteria",
|
|
39135
39221
|
file: REQUIREMENTS
|
|
39136
39222
|
});
|
|
39223
|
+
await impact();
|
|
39137
39224
|
return true;
|
|
39138
39225
|
});
|
|
39139
39226
|
/** After a gate that invites narrowing the requirements: an edit must leave valid criteria. */
|
|
@@ -39230,6 +39317,7 @@ const design = (base, guard) => scope("design", async () => {
|
|
|
39230
39317
|
requireProgress(REQUIREMENTS);
|
|
39231
39318
|
requireReplies(REQUIREMENTS);
|
|
39232
39319
|
requireCriteria(REQUIREMENTS);
|
|
39320
|
+
requireImpact(REQUIREMENTS);
|
|
39233
39321
|
guard?.();
|
|
39234
39322
|
} while (await noteGate(REQUIREMENTS, answerProductQuestions));
|
|
39235
39323
|
});
|
|
@@ -41023,4 +41111,4 @@ var workflows_default = feature;
|
|
|
41023
41111
|
*/
|
|
41024
41112
|
const doors = {};
|
|
41025
41113
|
//#endregion
|
|
41026
|
-
export { COMMENT, ESCALATION, FEEDBACK, FIX_CAP, FlagOptions, HANDOFF, PROTOTYPE, QUALITY, REFACTOR, REFACTOR_NOTE, REFACTOR_PACKAGE, REQUIREMENTS, REVIEW, REVIEW_ORIG, SLICES, ShippedOptions, acceptanceFault, access, afterTail, agentWithSkills, answerProductQuestions, answerReviewQuestions, awaitReview, base, baseline, buildFeature, buildTail, builtInLenses, cleanup, cleanupFlow, closeOut, closeReview, coder, collecting, criteriaOf, criterionIds, workflows_default as default, defaults, describeEscalation, design, doors, envDefaults, escalate, escalation, escalationExhausted, feature, fix, fixCheck, fixFlow, fixNits, fixQuality, fixReviewNotes, fixRisks, gate, guarded, handOffReview, handOffTail, handsOnIds, healthy, holdsCallSites, implement, implementing, isTestFile, judgeSeam, lensEntriesOf, lensOf, lensesOf, naiveAcceptance, naivePass, ordinaryStart, planAndBuild, planner, qualityLap, reUnwind, recheck, refactorCollecting, refactorFirst, refactorNote, refactorStrays, requireAcceptance, requireAcceptanceKept, requireCriteria, requireCriteriaFrozen, requireCriteriaIfEdited, requireNoNewFlags, requireNoTestFiles, requireSlices, requireStableIds, requireTestCallSitesOnly, requireWithin, retryQuestion, review, reviewFlow, reviewMissing, reviewQuality, reviewedRefactor, reviewing, rollout, rolloutFlow, seamBuild, skills, skipDesign, sliceCap, sliceCriteria, sliceIds, slicesOf, slicing, statedCriteria, steering, summary, tail, threads, triage, unstableIds, unwind };
|
|
41114
|
+
export { COMMENT, ESCALATION, FEEDBACK, FIX_CAP, FlagOptions, HANDOFF, PROTOTYPE, QUALITY, REFACTOR, REFACTOR_NOTE, REFACTOR_PACKAGE, REQUIREMENTS, REVIEW, REVIEW_ORIG, SLICES, ShippedOptions, acceptanceFault, access, afterTail, agentWithSkills, answerProductQuestions, answerReviewQuestions, awaitReview, base, baseline, buildFeature, buildTail, builtInLenses, cleanup, cleanupFlow, closeOut, closeReview, coder, collecting, criteriaOf, criterionIds, workflows_default as default, defaults, describeEscalation, design, doors, envDefaults, escalate, escalation, escalationExhausted, feature, fix, fixCheck, fixFlow, fixNits, fixQuality, fixReviewNotes, fixRisks, gate, guarded, handOffReview, handOffTail, handsOnIds, hasImpact, healthy, holdsCallSites, implement, implementing, isTestFile, judgeSeam, lensEntriesOf, lensOf, lensesOf, naiveAcceptance, naivePass, ordinaryStart, planAndBuild, planner, qualityLap, reUnwind, recheck, refactorCollecting, refactorFirst, refactorNote, refactorStrays, requireAcceptance, requireAcceptanceKept, requireCriteria, requireCriteriaFrozen, requireCriteriaIfEdited, requireImpact, requireImpactOnly, requireNoNewFlags, requireNoTestFiles, requireSlices, requireStableIds, requireTestCallSitesOnly, requireWithin, retryQuestion, review, reviewFlow, reviewMissing, reviewQuality, reviewedRefactor, reviewing, rollout, rolloutFlow, seamBuild, skills, skipDesign, sliceCap, sliceCriteria, sliceIds, slicesOf, slicing, statedCriteria, steering, summary, tail, threads, triage, unstableIds, unwind };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pmelab/gtd",
|
|
3
|
-
"version": "52.
|
|
3
|
+
"version": "52.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Git-aware CLI that emits the next prompt for an autonomous coding agent based on the current repository state",
|
|
6
6
|
"bin": {
|
|
@@ -165,8 +165,9 @@
|
|
|
165
165
|
"@types/react": "^19.2.7",
|
|
166
166
|
"@types/react-dom": "^19.2.3",
|
|
167
167
|
"@vitejs/plugin-react": "^5.2.0",
|
|
168
|
-
"@vitest/browser": "^
|
|
169
|
-
"@vitest/
|
|
168
|
+
"@vitest/browser": "^4.1.12",
|
|
169
|
+
"@vitest/browser-playwright": "^4.1.12",
|
|
170
|
+
"@vitest/coverage-v8": "^4.1.12",
|
|
170
171
|
"dependency-cruiser": "^18.3.1",
|
|
171
172
|
"fallow": "3.25.0",
|
|
172
173
|
"fast-check": "^4.8.0",
|
|
@@ -186,7 +187,7 @@
|
|
|
186
187
|
"tailwindcss": "^4.3.3",
|
|
187
188
|
"tsdown": "^0.22.8",
|
|
188
189
|
"turbo": "^2.10.9",
|
|
189
|
-
"vitest": "^
|
|
190
|
+
"vitest": "^4.1.12",
|
|
190
191
|
"yaml": "^2.8.2",
|
|
191
192
|
"zustand": "^5.0.15"
|
|
192
193
|
},
|
package/src/testkit/steps.ts
CHANGED
|
@@ -149,6 +149,10 @@ Given("the working tree is committed as {string}", (world: TestkitWorld, message
|
|
|
149
149
|
world.repo().commit(message)
|
|
150
150
|
})
|
|
151
151
|
|
|
152
|
+
Given("the working tree is committed with the message:", (world: TestkitWorld, message: string) => {
|
|
153
|
+
world.repo().commit(message)
|
|
154
|
+
})
|
|
155
|
+
|
|
152
156
|
Given("step {string} changes nothing", (world: TestkitWorld, step: string) => {
|
|
153
157
|
world.act(step, () => undefined)
|
|
154
158
|
})
|
|
@@ -180,6 +184,15 @@ Given(
|
|
|
180
184
|
},
|
|
181
185
|
)
|
|
182
186
|
|
|
187
|
+
Given(
|
|
188
|
+
"step {string} appends to {string}:",
|
|
189
|
+
(world: TestkitWorld, step: string, path: string, text: string) => {
|
|
190
|
+
world.act(step, (_, repo) => {
|
|
191
|
+
repo.write(path, `${(repo.read(path) ?? "").trimEnd()}\n\n${withNewline(text)}`)
|
|
192
|
+
})
|
|
193
|
+
},
|
|
194
|
+
)
|
|
195
|
+
|
|
183
196
|
Given("step {string} deletes {string}", (world: TestkitWorld, step: string, path: string) => {
|
|
184
197
|
world.act(step, (_, repo) => repo.remove(path))
|
|
185
198
|
})
|