@pmelab/gtd 59.0.1 → 60.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +37 -33
  3. package/claude/hooks/doors.ts +8 -4
  4. package/dist/chunks/flows-DENt0uWV.mjs +707 -0
  5. package/dist/chunks/{steering-CCNvngSH.mjs → steering-DF_BMadH.mjs} +292 -289
  6. package/dist/chunks/{testkit-07Z_ENch.mjs → testkit-BvecVjQ0.mjs} +570 -390
  7. package/dist/chunks/{wire-BTUhRGXj.mjs → wire-DZ8R1RU9.mjs} +8 -1
  8. package/dist/flows.mjs +2 -676
  9. package/dist/gtd.bundle.mjs +751 -645
  10. package/dist/steering.mjs +2 -2
  11. package/dist/testkit/gherkin.mjs +245 -36
  12. package/dist/testkit.mjs +3 -2
  13. package/dist/web/main.js +234 -232
  14. package/dist/wire.mjs +2 -2
  15. package/dist/workflow-kit.mjs +3 -3
  16. package/package.json +1 -1
  17. package/skills/authoring/SKILL.md +66 -60
  18. package/src/cli/Cli.test.ts +183 -182
  19. package/src/cli/Cli.ts +164 -186
  20. package/src/cli/History.ts +9 -4
  21. package/src/cli/Judges.ts +1 -1
  22. package/src/cli/Output.test.ts +35 -0
  23. package/src/cli/Output.ts +31 -1
  24. package/src/cli/Program.test.ts +65 -79
  25. package/src/cli/Program.ts +157 -118
  26. package/src/edge/Edge.test.ts +64 -56
  27. package/src/edge/Edge.ts +3 -3
  28. package/src/flows/factory.test.ts +14 -0
  29. package/src/flows/factory.ts +22 -5
  30. package/src/flows/helpers.test.ts +35 -0
  31. package/src/flows/helpers.ts +19 -10
  32. package/src/flows/index.test.ts +66 -0
  33. package/src/flows/index.ts +109 -5
  34. package/src/flows/internal.ts +7 -0
  35. package/src/flows/runtime.test.ts +192 -1
  36. package/src/flows/runtime.ts +188 -54
  37. package/src/gherkin/git-control.feature +6 -6
  38. package/src/gherkin/index.test.ts +127 -0
  39. package/src/gherkin/index.ts +370 -51
  40. package/src/gherkin/messages.test.ts +38 -4
  41. package/src/gherkin/messages.ts +21 -4
  42. package/src/gherkin/more-steps.feature +170 -0
  43. package/src/gherkin/scenario-end.feature +101 -0
  44. package/src/gherkin/testkit.feature +83 -7
  45. package/src/install/Install.test.ts +7 -7
  46. package/src/install/Install.ts +8 -8
  47. package/src/replay/Replay.test.ts +13 -2
  48. package/src/replay/Replay.ts +19 -30
  49. package/src/replay/judgeDiffShape.test.ts +1 -1
  50. package/src/steering/Footnotes.test.ts +1 -1
  51. package/src/steering/SteeringFormats.test.ts +1 -1
  52. package/src/steering/freeform.test.ts +1 -1
  53. package/src/steering/index.test.ts +27 -1
  54. package/src/steering/index.ts +6 -104
  55. package/src/steering/internal.ts +11 -0
  56. package/src/steering/qa.test.ts +7 -2
  57. package/src/steering/reads.test.ts +42 -0
  58. package/src/steering/reads.ts +43 -0
  59. package/src/steering/registry.ts +93 -0
  60. package/src/steering/review.test.ts +2 -2
  61. package/src/step/planStart.test.ts +18 -16
  62. package/src/step/planStart.ts +9 -9
  63. package/src/testkit/TestRepo.test.ts +245 -7
  64. package/src/testkit/TestRepo.ts +271 -40
  65. package/src/testkit/imports.test.ts +58 -0
  66. package/src/testkit/imports.ts +102 -0
  67. package/src/testkit/index.test.ts +28 -0
  68. package/src/testkit/index.ts +14 -2
  69. package/src/twins/EmittedScriptRecognizer.ts +2 -6
  70. package/src/twins/EmittedScripts.test.ts +4 -2
  71. package/src/twins/InMemRepo.ts +1 -0
  72. package/src/wire/Script.ts +11 -0
  73. package/src/wire/WireSchema.test.ts +3 -0
  74. package/src/wire/golden/1/script.json +4 -0
  75. package/src/wire/index.ts +1 -0
  76. package/src/workflow/SteeringFormats.test.ts +1 -1
  77. package/src/workflow/compile.ts +2 -2
  78. package/src/workflow/discovery.test.ts +3 -3
  79. package/src/workflow/load.test.ts +256 -116
  80. package/src/workflow/load.ts +169 -146
  81. package/src/workflow-kit/index.test.ts +25 -0
  82. package/src/workflow-kit/index.ts +37 -4
  83. package/src/workflow-kit/review.ts +2 -2
@@ -30,7 +30,7 @@ import {
30
30
  formatFinding,
31
31
  steeringFormatFor,
32
32
  type SteeringFormat,
33
- } from "../steering/index.js"
33
+ } from "../steering/internal.js"
34
34
  import { refNameFault } from "../replay/index.js"
35
35
  import { renderFormat } from "../wire/index.js"
36
36
  import { applyFlowScript, rewritten } from "./FlowScripts.js"
@@ -518,12 +518,8 @@ const recognizeGtdCheck = (repo: InMemRepo, block: string): BlockOutcome | undef
518
518
  const known = BUILT_IN_MODE_NAMES.join(", ")
519
519
  return { kind: "failed", error: `gtd check: unknown mode "${mode}" — known modes: ${known}` }
520
520
  }
521
- // An ABSENT file has nothing to check and exits 0 — `runCheckCommand`'s own
522
- // documented behavior. Validating `""` instead would report every "missing
523
- // header" finding the format has, turning "the reviewer deleted the file"
524
- // (a case the review-doc guard owns) into a script failure.
525
521
  const content = repo.readFile(file)
526
- if (content === undefined) return { kind: "noop" }
522
+ if (content === undefined) return { kind: "failed", error: `gtd check: no such file: ${file}` }
527
523
  const findings = format.validate(content).map((finding) => formatFinding(file, finding))
528
524
  if (findings.length === 0) return { kind: "noop" }
529
525
  return {
@@ -140,8 +140,10 @@ for (const makeTier of gitTiers) {
140
140
  })
141
141
 
142
142
  describe("gtd check", () => {
143
- it("passes a valid file, and an absent one", () => {
144
- expect(run(script(`gtd check qa '${FILE}'`)).ok).toBe(true)
143
+ it("refuses an absent file, and passes a valid one", () => {
144
+ const absent = run(script(`gtd check qa '${FILE}'`))
145
+ expect(absent).toMatchObject({ ok: false, status: 1 })
146
+ expect(absent.output).toContain(`gtd check: no such file: ${FILE}`)
145
147
  t.seed.writeFile(FILE, "## Open Questions\n")
146
148
  expect(run(script(`gtd check qa '${FILE}'`))).toEqual({ ok: true, status: 0, output: "" })
147
149
  })
@@ -30,6 +30,7 @@ function makeHash(message: string, parent: string | null, tree: Map<string, stri
30
30
  export class InMemRepo {
31
31
  // Data-only marker read by no code path: embeds the sentinel in every
32
32
  // instance so a leaked object still carries it.
33
+ // fallow-ignore-next-line unused-class-member
33
34
  readonly testDouble = TEST_DOUBLE_SENTINEL
34
35
 
35
36
  private commits: Map<string, Commit> = new Map()
@@ -0,0 +1,11 @@
1
+ import { WIRE_SCHEMA } from "./constants.js"
2
+
3
+ /** `--json` of every command that prints a script and nothing else to decide on: abandon, restore, start, door, validate, history fetch. */
4
+ export interface ScriptFields {
5
+ readonly schema: number
6
+ readonly script: string
7
+ }
8
+
9
+ export const scriptFields = (script: string): ScriptFields => ({ schema: WIRE_SCHEMA, script })
10
+
11
+ export const renderScriptJson = (fields: ScriptFields): string => JSON.stringify(fields) + "\n"
@@ -9,6 +9,8 @@ import {
9
9
  landFields,
10
10
  renderBeatJson,
11
11
  renderLandJson,
12
+ renderScriptJson,
13
+ scriptFields,
12
14
  statusOf,
13
15
  WIRE_SCHEMA,
14
16
  type BeatKind,
@@ -116,6 +118,7 @@ const documents: Readonly<Record<string, string>> = {
116
118
  }),
117
119
  ),
118
120
  "judge.json": JUDGE,
121
+ "script.json": renderScriptJson(scriptFields("git reset --mixed ...\n")),
119
122
  }
120
123
 
121
124
  describe(`wire schema ${WIRE_SCHEMA}`, () => {
@@ -0,0 +1,4 @@
1
+ {
2
+ "schema": 1,
3
+ "script": "git reset --mixed ...\n"
4
+ }
package/src/wire/index.ts CHANGED
@@ -6,6 +6,7 @@ export * from "./BeatStatus.js"
6
6
  export * from "./BeatDocument.js"
7
7
  export * from "./BeatPlain.js"
8
8
  export * from "./Land.js"
9
+ export * from "./Script.js"
9
10
  export * from "./Judge.js"
10
11
  export { selectPath } from "./Select.js"
11
12
  export { resolveSession } from "./Sessions.js"
@@ -1,7 +1,7 @@
1
1
  import { describe, expect, it } from "vitest"
2
2
  import fc from "fast-check"
3
3
  import { isSeededValidateCommand, seededValidateCommand } from "./SteeringFormats.js"
4
- import { BUILT_IN_MODE_NAMES } from "../steering/index.js"
4
+ import { BUILT_IN_MODE_NAMES } from "../steering/internal.js"
5
5
 
6
6
  describe("seededValidateCommand / isSeededValidateCommand", () => {
7
7
  it("recognizes its own seeded command for every built-in mode", () => {
@@ -1,7 +1,7 @@
1
1
  import { seededValidateCommand } from "./SteeringFormats.js"
2
- import { BUILT_IN_MODE_NAMES } from "../steering/index.js"
2
+ import { BUILT_IN_MODE_NAMES } from "../steering/internal.js"
3
3
  import type { ModeDef } from "./Workflow.js"
4
- import { configProblems, type GtdConfig, type UiSettings } from "../flows/index.js"
4
+ import { configProblems, type GtdConfig, type UiSettings } from "../flows/internal.js"
5
5
  import type { Diagnostic } from "./Diagnostic.js"
6
6
 
7
7
  export interface CompiledConfig {
@@ -22,15 +22,15 @@ interface Tier {
22
22
 
23
23
  const config = (imports: string): string =>
24
24
  [
25
- 'import { agent, human } from "@pmelab/gtd/flows"',
25
+ 'import { agent, human, workflow } from "@pmelab/gtd/flows"',
26
26
  imports,
27
27
  "export default async () => {",
28
28
  ' await human("idle", { message: "go" })',
29
29
  ' await agent("working", brief)',
30
30
  "}",
31
- "export const named = async () => {",
31
+ "export const named = workflow(async () => {",
32
32
  ' await agent("working", brief)',
33
- "}",
33
+ "})",
34
34
  "",
35
35
  ].join("\n")
36
36