@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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +42 -13
- package/claude/hooks/access.ts +26 -1
- package/claude/hooks/assist.ts +135 -0
- package/claude/hooks/drive.ts +15 -7
- package/claude/hooks/judge.ts +27 -0
- package/claude/hooks/register.tsx +294 -135
- package/claude/hooks/tools.ts +121 -0
- package/claude/hooks/wording.ts +2 -35
- package/claude/types/index.d.ts +9 -0
- package/dist/chunks/Schema-Dh-mkwkq.mjs +25353 -0
- package/dist/chunks/reserved-ejn-LVYO.mjs +1388 -0
- package/dist/chunks/rolldown-runtime-8H4AJuhK.mjs +14 -0
- package/dist/chunks/steering-D-PvRC5W.mjs +16296 -0
- package/dist/chunks/wire-DA7q2ikx.mjs +473 -0
- package/dist/flows.mjs +525 -0
- package/dist/gtd.bundle.mjs +43339 -55575
- package/dist/steering.mjs +2 -0
- package/dist/testkit.mjs +13006 -0
- package/dist/wire.mjs +2 -0
- package/dist/workflow-kit.mjs +352 -0
- package/dist/workflows/feature.mjs +315 -0
- package/dist/workflows/fix.mjs +40 -0
- package/dist/workflows/review.mjs +25 -0
- package/dist/workflows.mjs +8 -6
- package/package.json +69 -8
- package/src/cli/Cli.test.ts +1329 -0
- package/src/cli/Cli.ts +1348 -0
- package/src/cli/Program.test.ts +2262 -0
- package/src/cli/Program.ts +1331 -0
- package/src/cli/ToolCommands.ts +43 -0
- package/src/cli/index.ts +14 -0
- package/src/edge/Edge.test.ts +1016 -0
- package/src/edge/Edge.ts +1225 -0
- package/src/edge/index.ts +16 -0
- package/src/emit/Emit.test.ts +425 -0
- package/src/emit/Emit.ts +139 -0
- package/src/emit/GitScript.test.ts +260 -0
- package/src/emit/GitScript.ts +131 -0
- package/src/emit/ModeContradiction.test.ts +120 -0
- package/src/emit/ModeContradiction.ts +66 -0
- package/src/emit/OutcomeScript.test.ts +238 -0
- package/src/emit/OutcomeScript.ts +73 -0
- package/src/emit/SteeringMode.test.ts +274 -0
- package/src/emit/SteeringMode.ts +256 -0
- package/src/emit/index.ts +40 -0
- package/src/install/ConfigScaffold.ts +19 -0
- package/src/install/Install.test.ts +426 -0
- package/src/install/Install.ts +634 -0
- package/src/install/Version.ts +27 -0
- package/src/install/index.ts +3 -0
- package/src/platform/CommandRunner.ts +74 -0
- package/src/platform/Commentary.test.ts +126 -0
- package/src/platform/Commentary.ts +92 -0
- package/src/platform/Git.test.ts +50 -0
- package/src/platform/Git.ts +552 -0
- package/src/platform/Host.ts +42 -0
- package/src/platform/RetainedHistory.test.ts +65 -0
- package/src/platform/RetainedHistory.ts +34 -0
- package/src/platform/Workspace.test.ts +669 -0
- package/src/platform/Workspace.ts +631 -0
- package/src/platform/WorktreeState.test.ts +162 -0
- package/src/platform/WorktreeState.ts +50 -0
- package/src/platform/index.ts +22 -0
- package/src/replay/Access.test.ts +53 -0
- package/src/replay/Access.ts +46 -0
- package/src/replay/Format.test.ts +20 -0
- package/src/replay/Format.ts +14 -0
- package/src/replay/Replay.test.ts +887 -0
- package/src/replay/Replay.ts +669 -0
- package/src/replay/Trailers.test.ts +117 -0
- package/src/replay/Trailers.ts +213 -0
- package/src/replay/Tree.test.ts +25 -0
- package/src/replay/Tree.ts +45 -0
- package/src/replay/index.ts +11 -0
- package/src/steering/Blocks.fixture.ts +6 -0
- package/src/steering/Blocks.test.ts +167 -0
- package/src/steering/Blocks.ts +321 -0
- package/src/steering/CodeThreads.test.ts +127 -0
- package/src/steering/CodeThreads.ts +197 -0
- package/src/steering/Edits.test.ts +19 -0
- package/src/steering/Edits.ts +20 -0
- package/src/steering/Eol.test.ts +16 -0
- package/src/steering/Eol.ts +2 -0
- package/src/steering/FORMATS.md +58 -0
- package/src/steering/Footnotes.test.ts +977 -0
- package/src/steering/Footnotes.ts +661 -0
- package/src/steering/Inline.fixture.ts +7 -0
- package/src/steering/Inline.test.ts +227 -0
- package/src/steering/Inline.ts +195 -0
- package/src/steering/MarkdownTree.test.ts +247 -0
- package/src/steering/MarkdownTree.ts +260 -0
- package/src/steering/Outline.ts +19 -0
- package/src/steering/SteeringFormat.test.ts +91 -0
- package/src/steering/SteeringFormat.ts +267 -0
- package/src/steering/SteeringFormats.test.ts +163 -0
- package/src/steering/Threads.ts +163 -0
- package/src/steering/contract.test.ts +264 -0
- package/src/steering/fixtures/code-threads/cache.stripped.ts.txt +6 -0
- package/src/steering/fixtures/code-threads/cache.ts.md +15 -0
- package/src/steering/fixtures/free-form/notes.md +12 -0
- package/src/steering/fixtures/free-form/notes.read.json +42 -0
- package/src/steering/fixtures/qa/answered.md +23 -0
- package/src/steering/fixtures/qa/answered.read.json +119 -0
- package/src/steering/fixtures/qa/requirements.md +160 -0
- package/src/steering/fixtures/qa/requirements.read.json +475 -0
- package/src/steering/fixtures/review/review.md +76 -0
- package/src/steering/fixtures/review/review.read.json +237 -0
- package/src/steering/fixtures/review/ticked.md +23 -0
- package/src/steering/fixtures/review/ticked.read.json +99 -0
- package/src/steering/fixtures/review-notes/baseline.md +14 -0
- package/src/steering/fixtures/review-notes/noted.md +19 -0
- package/src/steering/freeform.test.ts +311 -0
- package/src/steering/freeform.ts +148 -0
- package/src/steering/index.test.ts +62 -0
- package/src/steering/index.ts +140 -0
- package/src/steering/qa.test.ts +2160 -0
- package/src/steering/qa.ts +1104 -0
- package/src/steering/review.test.ts +1829 -0
- package/src/steering/review.ts +1180 -0
- package/src/step/LandStep.ts +31 -0
- package/src/step/RepoSnapshot.ts +29 -0
- package/src/step/accessRefusal.test.ts +58 -0
- package/src/step/accessRefusal.ts +26 -0
- package/src/step/index.ts +5 -0
- package/src/step/planStart.test.ts +202 -0
- package/src/step/planStart.ts +167 -0
- package/src/step/planStep.test.ts +104 -0
- package/src/step/planStep.ts +89 -0
- package/src/step/snapshot.fixture.ts +28 -0
- package/src/testkit/EmittedScriptRecognizer.test.ts +639 -0
- package/src/testkit/EmittedScriptRecognizer.ts +642 -0
- package/src/testkit/FakeGitOperations.ts +95 -0
- package/src/testkit/GitTiers.test.ts +11 -0
- package/src/testkit/GitTiers.ts +1052 -0
- package/src/testkit/InMemRepo.ts +467 -0
- package/src/testkit/Layers.test.ts +58 -0
- package/src/testkit/Layers.ts +241 -0
- package/src/testkit/StrictGitOperations.ts +31 -0
- package/src/testkit/TestRepo.test.ts +119 -0
- package/src/testkit/TestRepo.ts +274 -0
- package/src/testkit/cliIo.ts +36 -0
- package/src/testkit/index.ts +9 -0
- package/src/testkit/steps.ts +177 -0
- package/src/testkit/testkit.feature +65 -0
- package/src/wire/BeatDocument.test.ts +419 -0
- package/src/wire/BeatDocument.ts +114 -0
- package/src/wire/BeatPlain.test.ts +113 -0
- package/src/wire/BeatPlain.ts +127 -0
- package/src/wire/BeatStatus.test.ts +59 -0
- package/src/wire/BeatStatus.ts +81 -0
- package/src/wire/Demand.test.ts +142 -0
- package/src/wire/Demand.ts +108 -0
- package/src/wire/ExitCodes.test.ts +21 -0
- package/src/wire/ExitCodes.ts +16 -0
- package/src/wire/Glob.ts +29 -0
- package/src/wire/Judge.ts +22 -0
- package/src/wire/Land.test.ts +120 -0
- package/src/wire/Land.ts +75 -0
- package/src/wire/Select.test.ts +148 -0
- package/src/wire/Select.ts +78 -0
- package/src/wire/Sessions.test.ts +59 -0
- package/src/wire/Sessions.ts +39 -0
- package/src/wire/WireSchema.test.ts +162 -0
- package/src/wire/constants.ts +22 -0
- package/src/wire/golden/1/beat-capture.json +34 -0
- package/src/wire/golden/1/beat-message.json +34 -0
- package/src/wire/golden/1/beat-prompt.json +44 -0
- package/src/wire/golden/1/beat-script.json +34 -0
- package/src/wire/golden/1/beat-stalled.json +34 -0
- package/src/wire/golden/1/judge.json +14 -0
- package/src/wire/golden/1/land-noop.json +10 -0
- package/src/wire/golden/1/land.json +10 -0
- package/src/wire/index.ts +12 -0
- package/src/wire/types.ts +46 -0
- package/src/workflow/Diagnostic.test.ts +93 -0
- package/src/workflow/Diagnostic.ts +54 -0
- package/src/workflow/SteeringFormats.test.ts +27 -0
- package/src/workflow/SteeringFormats.ts +6 -0
- package/src/workflow/Workflow.ts +77 -0
- package/src/workflow/compile.test.ts +53 -0
- package/src/workflow/compile.ts +56 -0
- package/src/workflow/discovery.ts +122 -0
- package/src/workflow/fingerprint.test.ts +52 -0
- package/src/workflow/fingerprint.ts +53 -0
- package/src/workflow/index.ts +33 -0
- package/src/workflow/load.test.ts +1017 -0
- package/src/workflow/load.ts +836 -0
- package/src/workflow/skills.test.ts +109 -0
- package/src/workflow/skills.ts +90 -0
- package/src/workflow/vars.ts +33 -0
- package/src/workflows/feature/feature.test.ts +27 -33
- package/src/workflows/feature/index.ts +10 -0
- package/src/workflows/fix/fix.feature +80 -0
- package/src/workflows/fix/fix.test.ts +58 -78
- package/src/workflows/fix/index.ts +6 -0
- package/src/workflows/index.ts +2 -10
- package/src/workflows/review/index.ts +6 -0
- package/src/workflows/review/review.test.ts +85 -29
- package/src/workflows/review/review.ts +3 -1
- package/src/workflows/shared/config.fixture.ts +12 -0
- package/src/workflows/shared/reserved.ts +11 -0
- package/src/workflows/shared/workflows.steps.ts +7 -0
|
@@ -1,36 +1,92 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { describe, expect, it } from "vitest"
|
|
2
|
+
import { runsItsScript, testRepo, type TestRepo } from "../../testkit/index.js"
|
|
3
|
+
import { CONFIG_SCAFFOLD } from "../../install/index.js"
|
|
4
|
+
import { reviewDoc } from "../shared/config.fixture.js"
|
|
5
|
+
import { base } from "./review.js"
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
const REVIEW = ".gtd/REVIEW.md"
|
|
8
|
+
const ORIG = ".gtd/REVIEW.orig.md"
|
|
9
|
+
|
|
10
|
+
/** A repository with one commit to review, the review run until the human holds `.gtd/REVIEW.md`. */
|
|
11
|
+
const reviewed = async (): Promise<TestRepo> => {
|
|
12
|
+
const repo = testRepo({ workflow: CONFIG_SCAFFOLD, env: { GTD_QUALITYREVIEWS: "" } })
|
|
13
|
+
repo.write("src/calc.ts", "export const add = (a: number, b: number) => a + b\n")
|
|
14
|
+
repo.commit("feat: add calculator")
|
|
15
|
+
await repo.door("review", "HEAD~1")
|
|
16
|
+
const rest = await repo.drive({
|
|
17
|
+
"review-gate.check": () => undefined,
|
|
18
|
+
"build.health.check": () => undefined,
|
|
19
|
+
"build.review.reviewing": (beat, r) => {
|
|
20
|
+
expect(beat.file).toBe(REVIEW)
|
|
21
|
+
r.write(REVIEW, reviewDoc("new add function"))
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
expect(rest).toMatchObject({ state: "build.review.await-review", actor: "human" })
|
|
25
|
+
return repo
|
|
26
|
+
}
|
|
7
27
|
|
|
8
28
|
describe("the review workflow", () => {
|
|
9
|
-
it("
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
29
|
+
it("checks, reviews and hands the review to the human", async () => {
|
|
30
|
+
const repo = await reviewed()
|
|
31
|
+
expect(repo.subjects().slice(2)).toEqual([
|
|
32
|
+
"gtd(human): review-gate.check",
|
|
33
|
+
"gtd(check): review-gate.check → build.health.check",
|
|
34
|
+
"gtd(check): build.health.check → build.review.reviewing",
|
|
35
|
+
"gtd(agent): build.review.reviewing → build.review.await-review",
|
|
36
|
+
])
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it("closes a review the human signs off", async () => {
|
|
40
|
+
const repo = await reviewed()
|
|
41
|
+
repo.write(REVIEW, reviewDoc("new add function").replace("- [ ]", "- [x]"))
|
|
42
|
+
await repo.land()
|
|
43
|
+
const rest = await repo.drive({ "build.review.closing": runsItsScript })
|
|
44
|
+
expect(rest.state).toBe("idle")
|
|
45
|
+
expect(repo.subjects().slice(-2)).toEqual([
|
|
46
|
+
"gtd(human): build.review.await-review → build.review.closing",
|
|
47
|
+
"gtd(check): build.review.closing → idle",
|
|
48
|
+
])
|
|
49
|
+
expect(repo.read(REVIEW)).toBeUndefined()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it("never lands a review the review format rejects", async () => {
|
|
53
|
+
const repo = testRepo({ workflow: CONFIG_SCAFFOLD, env: { GTD_QUALITYREVIEWS: "" } })
|
|
54
|
+
repo.write("src/calc.ts", "export const add = (a: number, b: number) => a + b\n")
|
|
55
|
+
repo.commit("feat: add calculator")
|
|
56
|
+
await repo.door("review", "HEAD~1")
|
|
57
|
+
await expect(
|
|
58
|
+
repo.drive({
|
|
59
|
+
"review-gate.check": () => undefined,
|
|
60
|
+
"build.health.check": () => undefined,
|
|
61
|
+
"build.review.reviewing": (_, r) => r.write(REVIEW, "not a review\n"),
|
|
62
|
+
}),
|
|
63
|
+
).rejects.toThrow(/validating \.gtd\/REVIEW\.md/)
|
|
64
|
+
expect(repo.subjects().at(-1)).toBe("gtd(check): build.health.check → build.review.reviewing")
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it("ends with the review and the reviewer's copy kept when the human leaves a note", async () => {
|
|
68
|
+
const repo = await reviewed()
|
|
69
|
+
repo.write(REVIEW, reviewDoc("new add function — rename it to sum"))
|
|
70
|
+
await repo.land()
|
|
71
|
+
const rest = await repo.drive({
|
|
72
|
+
"build.review.handing-off": runsItsScript,
|
|
73
|
+
})
|
|
74
|
+
expect(rest.state).toBe("idle")
|
|
75
|
+
expect(repo.subjects().slice(-2)).toEqual([
|
|
76
|
+
"gtd(human): build.review.await-review → build.review.handing-off",
|
|
77
|
+
"gtd(check): build.review.handing-off → idle",
|
|
14
78
|
])
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
pushScope: () => undefined,
|
|
27
|
-
popScope: () => undefined,
|
|
28
|
-
read: (path) => files.get(path),
|
|
29
|
-
},
|
|
30
|
-
),
|
|
31
|
-
)
|
|
32
|
-
await expect(reviewFlow()).rejects.toThrow(".gtd/REVIEW.orig.md is a pending hand-off")
|
|
33
|
-
expect(requested).toEqual([])
|
|
79
|
+
expect(repo.read(REVIEW)).toContain("rename it to sum")
|
|
80
|
+
expect(repo.read(ORIG)).toBe(reviewDoc("new add function"))
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it("refuses a pending hand-off before requesting any step, the gate's check included", async () => {
|
|
84
|
+
const repo = testRepo({
|
|
85
|
+
workflow: CONFIG_SCAFFOLD,
|
|
86
|
+
files: { [REVIEW]: reviewDoc("note"), [ORIG]: reviewDoc("orig") },
|
|
87
|
+
})
|
|
88
|
+
await expect(repo.door("review")).rejects.toThrow(".gtd/REVIEW.orig.md is a pending hand-off")
|
|
89
|
+
expect(repo.subjects()).toEqual(["chore: initial commit"])
|
|
34
90
|
})
|
|
35
91
|
})
|
|
36
92
|
|
|
@@ -20,7 +20,9 @@ export const review = shipped(
|
|
|
20
20
|
{
|
|
21
21
|
review: {
|
|
22
22
|
args: [{ name: "base", optional: true }],
|
|
23
|
-
|
|
23
|
+
// Annotated: inferred, the literal union only fits under exactOptionalPropertyTypes.
|
|
24
|
+
vars: ({ base }): Readonly<Record<string, string>> =>
|
|
25
|
+
base === undefined ? {} : { reviewBase: base },
|
|
24
26
|
},
|
|
25
27
|
},
|
|
26
28
|
(_workflow, vars) => vars.reviewBase || "",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** A `.gtd/REVIEW.md` on the fixture calculator, one hunk per note. */
|
|
2
|
+
export const reviewDoc = (...notes: string[]): string =>
|
|
3
|
+
[
|
|
4
|
+
"# Review: abc1234",
|
|
5
|
+
"",
|
|
6
|
+
"<!-- base: 0000000 -->",
|
|
7
|
+
"",
|
|
8
|
+
"## calc",
|
|
9
|
+
"",
|
|
10
|
+
...notes.flatMap((note, i) => [`- [ ] ./src/calc.ts#${i + 1}-${i + 1}`, ` ${note}`]),
|
|
11
|
+
"",
|
|
12
|
+
].join("\n")
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Summary } from "../../flows/index.js"
|
|
2
|
+
import * as t from "./text.js"
|
|
3
|
+
import { ARCHITECTURE, REQUIREMENTS, REVIEW } from "./steps.js"
|
|
4
|
+
|
|
5
|
+
export { defaults, envDefaults } from "./vars.js"
|
|
6
|
+
export { skills } from "./skills.js"
|
|
7
|
+
export { access } from "./access.js"
|
|
8
|
+
|
|
9
|
+
export const summary: Summary = t.summaryPrompt
|
|
10
|
+
|
|
11
|
+
export const steering = { [REQUIREMENTS]: "qa", [ARCHITECTURE]: "qa", [REVIEW]: "review" }
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Given } from "quickpickle"
|
|
2
|
+
import { CONFIG_SCAFFOLD } from "../../install/index.js"
|
|
3
|
+
import type { TestkitWorld } from "../../testkit/index.js"
|
|
4
|
+
|
|
5
|
+
Given("the shipped workflows, as gtd install scaffolds them", (world: TestkitWorld) => {
|
|
6
|
+
world.configure(CONFIG_SCAFFOLD)
|
|
7
|
+
})
|