@pmelab/gtd 24.0.0 → 24.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 +31 -5
- package/claude/hooks/access.ts +1 -1
- 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
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { join } from "node:path"
|
|
2
|
+
import { Effect } from "effect"
|
|
3
|
+
import { Host } from "../platform/index.js"
|
|
4
|
+
import {
|
|
5
|
+
isSeededValidateCommand,
|
|
6
|
+
knownModes,
|
|
7
|
+
type StateMode,
|
|
8
|
+
type WorkflowDefinition,
|
|
9
|
+
} from "../workflow/index.js"
|
|
10
|
+
import { steeringFormatFor, type SteeringFinding, type SteeringFormat } from "../steering/index.js"
|
|
11
|
+
import { buildModeContradictionCheck, modeContradictionSkipNotice } from "./ModeContradiction.js"
|
|
12
|
+
import {
|
|
13
|
+
binaryGuard,
|
|
14
|
+
emitScripts,
|
|
15
|
+
extractLeadingBinary,
|
|
16
|
+
fileExistsGuard,
|
|
17
|
+
withFileVar,
|
|
18
|
+
type EmitStep,
|
|
19
|
+
} from "./Emit.js"
|
|
20
|
+
|
|
21
|
+
/** How a resolved mode validates: a shell command, or a built-in format's own in-process parser. */
|
|
22
|
+
export type ResolvedValidator =
|
|
23
|
+
| { readonly kind: "command"; readonly command: string }
|
|
24
|
+
| { readonly kind: "builtin"; readonly format: SteeringFormat }
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* What a resolved mode can DO, for a consumer (the LSP, the sign-off/answer
|
|
28
|
+
* gates) that only cares about capability, not resolution mechanics:
|
|
29
|
+
* `liveValidate` is the built-in format's own `validate` function, present
|
|
30
|
+
* when the validator is either the built-in kind OR a command that is gtd's
|
|
31
|
+
* own SEEDED string for this mode (`isSeededValidateCommand` — the compiler
|
|
32
|
+
* seeding `qa`/`review`'s own `gtd check` command behind the scenes changes
|
|
33
|
+
* nothing about how the file is actually validated). `externalValidate` is
|
|
34
|
+
* `true` for a genuine user override of a built-in mode's `validate:`, or any
|
|
35
|
+
* command-validated non-built-in mode — the LSP shows a notice for that
|
|
36
|
+
* instead of live diagnostics.
|
|
37
|
+
*/
|
|
38
|
+
export interface SteeringCapabilities {
|
|
39
|
+
readonly format?: SteeringFormat
|
|
40
|
+
readonly liveValidate?: (content: string) => readonly SteeringFinding[]
|
|
41
|
+
readonly externalValidate?: boolean
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** A `mode:` name successfully resolved against a definition (or the built-in registry alone). */
|
|
45
|
+
export interface ResolvedMode {
|
|
46
|
+
readonly kind: "resolved"
|
|
47
|
+
readonly mode: StateMode
|
|
48
|
+
/** The built-in `SteeringFormat` registered under this mode's NAME (`src/workflow/SteeringFormats.ts`), independent of who ends up validating — present even when a declared `validate:` command overrides the format's own parser. Absent when the name is not in the built-in registry at all. */
|
|
49
|
+
readonly format?: SteeringFormat
|
|
50
|
+
/** The `format:` shell command, when some `modes:` layer declared one. Absent = this mode formats nothing. */
|
|
51
|
+
readonly formatCommand?: string
|
|
52
|
+
/** How to validate, or absent when neither a command nor a built-in parser applies (a declared mode with only a `format:`). */
|
|
53
|
+
readonly validate?: ResolvedValidator
|
|
54
|
+
readonly capabilities: SteeringCapabilities
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** A `mode:` name that resolved to nothing — the message names what IS known. */
|
|
58
|
+
export interface UnknownMode {
|
|
59
|
+
readonly kind: "unknown"
|
|
60
|
+
readonly message: string
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** A state's `mode:` resolved against the active definition, or the reason it couldn't be. */
|
|
64
|
+
export type ModeResolution = ResolvedMode | UnknownMode
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* `format` alone (no live/external verdict) when there's no validator at
|
|
68
|
+
* all; a live in-process validator for a `"builtin"` validate OR a command
|
|
69
|
+
* that is exactly the format's own seeded string; `externalValidate` for any
|
|
70
|
+
* other command. Each arm returns directly — a flat sequence, not nested
|
|
71
|
+
* ternaries — so the four outcomes stay each their own case to read, not a
|
|
72
|
+
* boolean expression to re-derive.
|
|
73
|
+
*/
|
|
74
|
+
const capabilitiesFor = (
|
|
75
|
+
mode: StateMode,
|
|
76
|
+
format: SteeringFormat | undefined,
|
|
77
|
+
validate: ResolvedValidator | undefined,
|
|
78
|
+
): SteeringCapabilities => {
|
|
79
|
+
if (format === undefined) {
|
|
80
|
+
return validate?.kind === "command" ? { externalValidate: true } : {}
|
|
81
|
+
}
|
|
82
|
+
if (validate?.kind === "builtin") return { format, liveValidate: format.validate }
|
|
83
|
+
if (validate === undefined) return { format }
|
|
84
|
+
if (isSeededValidateCommand(mode, validate.command)) {
|
|
85
|
+
return { format, liveValidate: format.validate }
|
|
86
|
+
}
|
|
87
|
+
return { format, externalValidate: true }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Resolve a `mode:` name against `def.modes` plus the built-in registry
|
|
92
|
+
* (`src/workflow/SteeringFormats.ts`) — half by half: a declared `format:`/`validate:`
|
|
93
|
+
* wins, and an undeclared `validate:` falls back to the built-in format's own
|
|
94
|
+
* parser when the name is registered. `format` is set from the registry
|
|
95
|
+
* ALONE, independent of which half of `validate` wins — a declared validator
|
|
96
|
+
* overrides validation, not the format identity.
|
|
97
|
+
*
|
|
98
|
+
* `def: undefined` is the LSP's built-in-only fallback — resolving `mode`
|
|
99
|
+
* against the registry alone, with no workflow definition in hand (e.g. the
|
|
100
|
+
* basename dispatch for a `REVIEW.md` no config maps).
|
|
101
|
+
*
|
|
102
|
+
* The `"unknown"` arm carries the whole refusal message, naming what IS known
|
|
103
|
+
* when `def` is given — this is the one place that message is built, so it
|
|
104
|
+
* can never drift from what actually resolved.
|
|
105
|
+
*/
|
|
106
|
+
export const resolveMode = (
|
|
107
|
+
def: Pick<WorkflowDefinition, "modes"> | undefined,
|
|
108
|
+
state: string,
|
|
109
|
+
mode: StateMode,
|
|
110
|
+
): ModeResolution => {
|
|
111
|
+
const declared = def?.modes?.[mode]
|
|
112
|
+
const format = steeringFormatFor(mode)
|
|
113
|
+
if (declared === undefined && format === undefined) {
|
|
114
|
+
return {
|
|
115
|
+
kind: "unknown",
|
|
116
|
+
message:
|
|
117
|
+
def !== undefined
|
|
118
|
+
? `state "${state}": mode "${mode}" is not defined by the active workflow (known modes: ${knownModes(def).join(", ")})`
|
|
119
|
+
: `mode "${mode}" is not a built-in steering format`,
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const validate: ResolvedValidator | undefined =
|
|
123
|
+
declared?.validate !== undefined
|
|
124
|
+
? { kind: "command", command: declared.validate }
|
|
125
|
+
: format !== undefined
|
|
126
|
+
? { kind: "builtin", format }
|
|
127
|
+
: undefined
|
|
128
|
+
return {
|
|
129
|
+
kind: "resolved",
|
|
130
|
+
mode,
|
|
131
|
+
...(format !== undefined ? { format } : {}),
|
|
132
|
+
...(declared?.format !== undefined ? { formatCommand: declared.format } : {}),
|
|
133
|
+
...(validate !== undefined ? { validate } : {}),
|
|
134
|
+
capabilities: capabilitiesFor(mode, format, validate),
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** `gtd next`'s fix-retry instruction, printed ahead of the failing command's captured output. */
|
|
139
|
+
const fixPromptInstruction = (file: string): string =>
|
|
140
|
+
`Your last turn does not pass its own validation script. Fix these format violations in ${file}, then finish:`
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Pushes a `binaryGuard` step ahead of `command` when its own leading word
|
|
144
|
+
* is unambiguous — BEFORE, not wrapped around: a guard that fails must stop
|
|
145
|
+
* the script on its own `exit 127`, without touching `failurePromptWrapper`'s
|
|
146
|
+
* captured-output path. Each command guards on its OWN leading word — a
|
|
147
|
+
* guard naming the wrong binary is worse than none.
|
|
148
|
+
*/
|
|
149
|
+
const pushGuardedCommand = (
|
|
150
|
+
steps: EmitStep[],
|
|
151
|
+
mode: StateMode,
|
|
152
|
+
key: "format" | "validate",
|
|
153
|
+
command: string,
|
|
154
|
+
file: string,
|
|
155
|
+
onFailure: string | undefined,
|
|
156
|
+
): void => {
|
|
157
|
+
const binary = extractLeadingBinary(command)
|
|
158
|
+
if (binary !== undefined) {
|
|
159
|
+
steps.push({ kind: "command", command: binaryGuard(binary, mode, key) })
|
|
160
|
+
}
|
|
161
|
+
steps.push({
|
|
162
|
+
kind: "command",
|
|
163
|
+
command: withFileVar(command, file),
|
|
164
|
+
...(onFailure !== undefined ? { onFailure } : {}),
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* `resolved`'s `format:`/`validate:` as `EmitStep[]` — format first,
|
|
170
|
+
* validate last, the last one wrapped with `onFailure` when the validator is
|
|
171
|
+
* a command (a built-in's own in-process parser has no shell step to wrap:
|
|
172
|
+
* `gtd check`'s seeded command carries that instead). Each command gets its
|
|
173
|
+
* own `binaryGuard` immediately ahead of it.
|
|
174
|
+
*/
|
|
175
|
+
const modeCommandSteps = (resolved: ResolvedMode, file: string): readonly EmitStep[] => {
|
|
176
|
+
const steps: EmitStep[] = []
|
|
177
|
+
if (resolved.formatCommand !== undefined) {
|
|
178
|
+
pushGuardedCommand(steps, resolved.mode, "format", resolved.formatCommand, file, undefined)
|
|
179
|
+
}
|
|
180
|
+
if (resolved.validate?.kind === "command") {
|
|
181
|
+
pushGuardedCommand(
|
|
182
|
+
steps,
|
|
183
|
+
resolved.mode,
|
|
184
|
+
"validate",
|
|
185
|
+
resolved.validate.command,
|
|
186
|
+
file,
|
|
187
|
+
fixPromptInstruction(file),
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
return steps
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** `<Host.scratchDir>/gtd-mode-sample-<mode>-<pid>.md` — an absolute literal baked in at emit time, never a shell variable. `<pid>` avoids collisions between concurrent `gtd` processes. Never a `/tmp` literal or `mktemp` (`tests/tooling/no-tmp-assumption.test.ts` scans for both). */
|
|
194
|
+
const scratchSamplePath = (scratchDir: string, mode: StateMode): string =>
|
|
195
|
+
join(scratchDir, `gtd-mode-sample-${mode}-${process.pid}.md`)
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* The contradiction round-trip/skip-notice steps for `resolved`'s `mode:`.
|
|
199
|
+
* No `formatCommand` means nothing to round-trip: empty. Otherwise: a live
|
|
200
|
+
* built-in validator runs the round-trip against that format's own canonical
|
|
201
|
+
* sample; an external validator prints a one-line skip notice instead, since
|
|
202
|
+
* silence there would read as a clean bill of health; a format-only mode with
|
|
203
|
+
* neither has nothing to round-trip either.
|
|
204
|
+
*/
|
|
205
|
+
const modeContradictionSteps = (
|
|
206
|
+
resolved: ResolvedMode,
|
|
207
|
+
): Effect.Effect<readonly EmitStep[], Error, Host> =>
|
|
208
|
+
Effect.gen(function* () {
|
|
209
|
+
if (resolved.formatCommand === undefined) return []
|
|
210
|
+
const { capabilities } = resolved
|
|
211
|
+
if (capabilities.format !== undefined && capabilities.liveValidate !== undefined) {
|
|
212
|
+
const { scratchDir } = yield* Host
|
|
213
|
+
const samplePath = scratchSamplePath(scratchDir, resolved.mode)
|
|
214
|
+
const formatCommand = withFileVar(resolved.formatCommand, samplePath)
|
|
215
|
+
return [
|
|
216
|
+
{
|
|
217
|
+
kind: "command",
|
|
218
|
+
command: buildModeContradictionCheck({
|
|
219
|
+
mode: resolved.mode,
|
|
220
|
+
samplePath,
|
|
221
|
+
sample: capabilities.format.sample,
|
|
222
|
+
formatCommand,
|
|
223
|
+
}),
|
|
224
|
+
},
|
|
225
|
+
]
|
|
226
|
+
}
|
|
227
|
+
if (capabilities.externalValidate === true) {
|
|
228
|
+
return [{ kind: "command", command: modeContradictionSkipNotice(resolved.mode) }]
|
|
229
|
+
}
|
|
230
|
+
return []
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
/** A resolved mode's full format-then-validate script text — a VALUE, never an execution. Carries the contradiction round-trip, the file-existence guard, and the format/validate commands, exactly as `gtd validate`/`gtd next --json`'s `validate` field emit them. */
|
|
234
|
+
export interface ValidateScript {
|
|
235
|
+
readonly script: string
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Renders `resolved`'s complete validate script for `file`: the mode's
|
|
240
|
+
* format/validate contradiction check, a guard for a not-yet-written file,
|
|
241
|
+
* then the format/validate commands themselves (format first). gtd never
|
|
242
|
+
* runs this script itself — `resolveMode`+`validateScriptFor` only render
|
|
243
|
+
* text for a driver to execute (`gtd renders; the driver executes`).
|
|
244
|
+
*/
|
|
245
|
+
export const validateScriptFor = (
|
|
246
|
+
resolved: ResolvedMode,
|
|
247
|
+
file: string,
|
|
248
|
+
): Effect.Effect<ValidateScript, Error, Host> =>
|
|
249
|
+
Effect.gen(function* () {
|
|
250
|
+
const steps: EmitStep[] = [
|
|
251
|
+
...(yield* modeContradictionSteps(resolved)),
|
|
252
|
+
{ kind: "command", command: fileExistsGuard(file) },
|
|
253
|
+
...modeCommandSteps(resolved, file),
|
|
254
|
+
]
|
|
255
|
+
return { script: emitScripts(steps).required }
|
|
256
|
+
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export {
|
|
2
|
+
type EmitStep,
|
|
3
|
+
fileExistsGuard,
|
|
4
|
+
commandForFile,
|
|
5
|
+
binaryGuard,
|
|
6
|
+
failurePromptWrapper,
|
|
7
|
+
emitScripts,
|
|
8
|
+
DID_NOT_RUN_COMMENT,
|
|
9
|
+
PRESENTATION_ONLY_COMMENT,
|
|
10
|
+
PRESENTATION_FAILURE_WARNING,
|
|
11
|
+
combinedScript,
|
|
12
|
+
} from "./Emit.js"
|
|
13
|
+
export {
|
|
14
|
+
shellQuote,
|
|
15
|
+
commitAll,
|
|
16
|
+
commitAsIs,
|
|
17
|
+
softResetTo,
|
|
18
|
+
mixedResetTo,
|
|
19
|
+
hardResetTo,
|
|
20
|
+
discardPending,
|
|
21
|
+
updateRef,
|
|
22
|
+
deleteRef,
|
|
23
|
+
type RunnableScript,
|
|
24
|
+
ScriptSurface,
|
|
25
|
+
} from "./GitScript.js"
|
|
26
|
+
export {
|
|
27
|
+
OUTCOME_MARKER,
|
|
28
|
+
transitionOutcome,
|
|
29
|
+
commitOutcome,
|
|
30
|
+
noteOutcome,
|
|
31
|
+
abandonedOutcome,
|
|
32
|
+
abandonNoopOutcome,
|
|
33
|
+
restoredOutcome,
|
|
34
|
+
} from "./OutcomeScript.js"
|
|
35
|
+
export {
|
|
36
|
+
contradictionMessage,
|
|
37
|
+
buildModeContradictionCheck,
|
|
38
|
+
modeContradictionSkipNotice,
|
|
39
|
+
} from "./ModeContradiction.js"
|
|
40
|
+
export { resolveMode, validateScriptFor } from "./SteeringMode.js"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// What `gtd install` writes as a repository's `gtd.config.ts`. The default
|
|
2
|
+
// export is also exported as `feature`, so a process shows that name.
|
|
3
|
+
export const CONFIG_SCAFFOLD = `// The workflows gtd runs here: gtd's shipped feature, review and fix.
|
|
4
|
+
// Every exported function is startable with \`gtd --workflow <name>\`; the
|
|
5
|
+
// default export is what a change in the tree starts. Each workflow brings
|
|
6
|
+
// its own doors: \`gtd door review [base]\` and \`gtd door fix\`.
|
|
7
|
+
export {
|
|
8
|
+
feature as default,
|
|
9
|
+
feature,
|
|
10
|
+
defaults,
|
|
11
|
+
envDefaults,
|
|
12
|
+
summary,
|
|
13
|
+
steering,
|
|
14
|
+
skills,
|
|
15
|
+
access,
|
|
16
|
+
} from "@pmelab/gtd/workflows/feature"
|
|
17
|
+
export { review } from "@pmelab/gtd/workflows/review"
|
|
18
|
+
export { fix } from "@pmelab/gtd/workflows/fix"
|
|
19
|
+
`
|