@pmelab/gtd 24.3.0 → 25.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +28 -22
- package/dist/chunks/{reserved-DJwU5C4z.mjs → reserved-6pAgFGgB.mjs} +119 -135
- package/dist/chunks/{steering-D-PvRC5W.mjs → steering-DVILanVf.mjs} +16 -5
- package/dist/flows.mjs +9 -1
- package/dist/gtd.bundle.mjs +780 -813
- package/dist/steering.mjs +2 -2
- package/dist/testkit.mjs +666 -161
- package/dist/workflow-kit.mjs +55 -96
- package/dist/workflows/feature.mjs +171 -76
- package/dist/workflows/fix.mjs +2 -2
- package/dist/workflows/review.mjs +1 -1
- package/dist/workflows.mjs +353 -310
- package/package.json +1 -2
- package/src/cli/Program.test.ts +3 -8
- package/src/cli/Program.ts +1 -8
- package/src/edge/Edge.test.ts +5 -2
- package/src/edge/Edge.ts +3 -4
- package/src/emit/index.ts +1 -0
- package/src/flows/scripts.ts +6 -0
- package/src/platform/Git.test.ts +6 -9
- package/src/replay/Replay.ts +2 -1
- package/src/steering/FORMATS.md +1 -1
- package/src/steering/SteeringFormat.test.ts +9 -1
- package/src/steering/SteeringFormat.ts +7 -0
- package/src/steering/contract.test.ts +3 -0
- package/src/steering/index.ts +1 -0
- package/src/steering/review.test.ts +30 -0
- package/src/steering/review.ts +8 -2
- package/src/testkit/EmittedScriptRecognizer.test.ts +29 -30
- package/src/testkit/EmittedScriptRecognizer.ts +148 -51
- package/src/testkit/EmittedScripts.test.ts +166 -0
- package/src/testkit/FlowScripts.test.ts +242 -0
- package/src/testkit/FlowScripts.ts +326 -0
- package/src/testkit/GitTiers.ts +140 -49
- package/src/testkit/InMemRepo.ts +35 -2
- package/src/testkit/Layers.ts +10 -2
- package/src/testkit/TestRepo.ts +4 -1
- package/src/testkit/index.ts +1 -1
- package/src/workflow/discovery.test.ts +147 -0
- package/src/workflow/discovery.ts +5 -0
- package/src/workflow/fingerprint.test.ts +20 -4
- package/src/workflow/fingerprint.ts +8 -9
- package/src/workflow/index.ts +1 -6
- package/src/workflow/load.test.ts +5 -19
- package/src/workflow/load.ts +94 -10
- package/src/workflow-kit/review.test.ts +84 -0
- package/src/workflow-kit/review.ts +9 -6
- package/src/workflow-kit/scenarios.test.ts +116 -0
- package/src/workflow-kit/scenarios.ts +53 -113
- package/src/workflows/feature/feature.ts +2 -5
- package/src/workflows/feature/packages.test.ts +17 -34
- package/src/workflows/feature/packages.ts +13 -52
- package/src/workflows/feature/planning.ts +1 -1
- package/src/workflows/feature/review.test.ts +233 -54
- package/src/workflows/feature/review.ts +178 -41
- package/src/workflows/feature/steps.test.ts +12 -0
- package/src/workflows/feature/steps.ts +8 -1
- package/src/workflows/index.ts +0 -2
- package/src/workflows/shared/access.test.ts +4 -2
- package/src/workflows/shared/access.ts +1 -0
- package/src/workflows/shared/health.test.ts +1 -21
- package/src/workflows/shared/health.ts +4 -39
- package/src/workflows/shared/options.test.ts +8 -0
- package/src/workflows/shared/options.ts +1 -1
- package/src/workflows/shared/steps.ts +18 -11
- package/src/workflows/shared/tail.test.ts +1 -41
- package/src/workflows/shared/tail.ts +17 -41
- package/src/workflows/shared/text.fixture.ts +1 -0
- package/src/workflows/shared/text.test.ts +129 -41
- package/src/workflows/shared/text.ts +111 -75
- package/src/workflows/shared/vars.ts +1 -1
- package/src/workflows/shared/scenarios.test.ts +0 -256
- package/src/workflows/shared/scenarios.ts +0 -35
package/README.md
CHANGED
|
@@ -44,12 +44,6 @@ the read side to its agent. `read` is not a security boundary unless your driver
|
|
|
44
44
|
enforces it at the OS level. See
|
|
45
45
|
[Configuration](https://github.com/pmelab/gtd/blob/main/docs/configuration.md#file-access).
|
|
46
46
|
|
|
47
|
-
> **`fastTestCommand` is required, with no fallback to `testCommand`.** Set it
|
|
48
|
-
> (everything but e2e) as a workflow option in `gtd.config.ts`
|
|
49
|
-
> (`feature({ fastTestCommand: "npm run test:fast" })`) or as
|
|
50
|
-
> `GTD_FASTTESTCOMMAND`; gtd stops at the start gate, writing `.gtd/SETUP.md`,
|
|
51
|
-
> until it is.
|
|
52
|
-
|
|
53
47
|
> **A repository's `gtd.config.ts` is code, and gtd runs it.** A custom workflow
|
|
54
48
|
> is a TypeScript module, and every gtd command that looks at workflow state —
|
|
55
49
|
> `gtd next`, `gtd lsp`, `gtd door` and `gtd doors` included, not just
|
|
@@ -400,20 +394,21 @@ noted in steps 3 and 4 below.
|
|
|
400
394
|
questions and all. Every plan gets the technical pass: its document has four
|
|
401
395
|
sections, in order — `## Interfaces`, `## Call Stacks`, `## E2E Scenarios`,
|
|
402
396
|
`## Unit Tests` — behind a leading `## Open Questions` when there are any.
|
|
403
|
-
`## E2E Scenarios` is never empty: it
|
|
397
|
+
`## E2E Scenarios` is never empty: it names each user-visible behaviour in
|
|
398
|
+
plain words (the builder writes the scenario itself), or, when nothing
|
|
404
399
|
user-visible changes, the line `No e2e change.` with a one-line reason.
|
|
405
400
|
|
|
406
|
-
3. **You wait.** The work is split into
|
|
407
|
-
one starting from the unit tests it declares (a build turn
|
|
408
|
-
refused), checked against the
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
default, which never skips
|
|
416
|
-
`gtd judge run --provider fixed --answers <path>` — or the
|
|
401
|
+
3. **You wait.** The work is split into vertical slices and built one at a time,
|
|
402
|
+
each one starting from the unit and e2e tests it declares (a build turn
|
|
403
|
+
missing one is refused), checked against the full suite (`testCommand`) and
|
|
404
|
+
fixed until it passes before moving on — so keep that suite fast; gtd has no
|
|
405
|
+
lighter one. Scenario wording is not frozen: you sign the scenarios off once,
|
|
406
|
+
in the review's `## Scenarios` chunk, where any assertion an existing
|
|
407
|
+
scenario lost is marked `Weakened:`. After the last package the quality lap
|
|
408
|
+
runs. Two points along the process are judged rather than always asking you
|
|
409
|
+
outright — each stops and hands you a verdict to make (`gtd judge answer`, or
|
|
410
|
+
land with a clean tree to accept the conservative default, which never skips
|
|
411
|
+
work; `gtd judge run --provider fixed --answers <path>` — or the
|
|
417
412
|
`GTD_JUDGE_ANSWERS` env var, inline JSON — answers one from a file, piped
|
|
418
413
|
between `gtd judge --json` and `gtd judge answer`;
|
|
419
414
|
`gtd judge run --provider jev` asks TypeSafe's Jev instead, with the key in
|
|
@@ -475,10 +470,21 @@ noted in steps 3 and 4 below.
|
|
|
475
470
|
turns first), then a fresh review of the change stops at the review again.
|
|
476
471
|
`praise` is dropped; a round of only praise signs off. When a round mixes
|
|
477
472
|
them, questions are answered and nits fixed first, then the edits are planned
|
|
478
|
-
— risk: the planning lap may redo nit fixes it touches.
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
473
|
+
— risk: the planning lap may redo nit fixes it touches.
|
|
474
|
+
|
|
475
|
+
Each `edit` note also gets a severity tier from four judge questions
|
|
476
|
+
(security, reversibility, blast radius, new concept). `critical` and `should`
|
|
477
|
+
notes are re-planned this round; `could` notes are deferred. A leading `!` on
|
|
478
|
+
a note forces `critical` and skips the judge. Deferral appends to the
|
|
479
|
+
committed `.gtd/TODO.md`; it never starts a process on its own, and it ships
|
|
480
|
+
in the branch/PR unless you delete it. Landing clean at the gate after a
|
|
481
|
+
deferral signs off without the deferred notes; the gate lists them. To pull
|
|
482
|
+
one in, edit its line in `.gtd/TODO.md` when you start a process.
|
|
483
|
+
`reviewSeverityMinP` sets the confidence floor (see
|
|
484
|
+
[configuration](docs/configuration.md)). A hand-edit to code always plans a
|
|
485
|
+
lap. Only a confident non-`edit` verdict skips the replan — a note whose
|
|
486
|
+
evidence was cut, or that got no verdict, counts as `edit`. The same
|
|
487
|
+
`gtd judge answer` / conservative-default shape as step 3's own judged
|
|
482
488
|
points.
|
|
483
489
|
|
|
484
490
|
You never talk to it. Every exchange is a file in `.gtd/` that you edit in your
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { accessFor, agent, answered, check, codeThreads, defineWorkflow, env, head, human, judge, numeric, quote, read, refuse, removeScript, run, scope, skillsFor, start, vars } from "../flows.mjs";
|
|
2
|
-
import { escalation as escalation$1, fixFindings, gate as gate$1, healthy as healthy$1,
|
|
1
|
+
import { accessFor, agent, answered, changesSince, check, codeThreads, defineWorkflow, env, head, human, judge, numeric, quote, read, refuse, removeScript, run, scope, showScript, skillsFor, start, vars } from "../flows.mjs";
|
|
2
|
+
import { escalation as escalation$1, fixFindings, gate as gate$1, healthy as healthy$1, lensScopes, lensesOf, qualityLap as qualityLap$1, removedAssertions, reviewToHandOff } from "../workflow-kit.mjs";
|
|
3
3
|
import { c as String$, g as standardSchemaV1, h as optionalWith, l as Struct } from "./Schema-B5yK7QrT.mjs";
|
|
4
|
-
import { dirname } from "node:path";
|
|
5
4
|
//#region src/workflows/shared/prose.ts
|
|
6
5
|
const skillsPreamble = `- Load whatever's listed here that your harness actually has installed,
|
|
7
6
|
skip anything it doesn't — silently, never stopping or asking about a
|
|
@@ -310,6 +309,10 @@ ${stateFileRules}
|
|
|
310
309
|
${footnoteFoldIn}${codeThreadReplies()}
|
|
311
310
|
- The only state file this turn touches is \`.gtd/REQUIREMENTS.md\`
|
|
312
311
|
— no other files for notes or output
|
|
312
|
+
- Lines of a \`## Deferred review notes\` section of \`.gtd/TODO.md\`
|
|
313
|
+
that the start diff does not touch are parked by review, never folded;
|
|
314
|
+
the human's edits to such a line (or its removal) are input like any
|
|
315
|
+
other part of the start diff
|
|
313
316
|
- \`.gtd/TODO.md\` is the likely home of the sketch that started
|
|
314
317
|
this process — the human's input, folded into the concerns
|
|
315
318
|
below like any other part of the start diff; never a state
|
|
@@ -453,7 +456,8 @@ ${footnoteFoldIn}${codeThreadReplies()}
|
|
|
453
456
|
- Every open point here is TECHNICAL — triage already resolved
|
|
454
457
|
the product ones, one phase earlier. PERMISSIVE: answer it
|
|
455
458
|
yourself unless you genuinely cannot defend a default; a wrong
|
|
456
|
-
technical call is still caught by
|
|
459
|
+
technical call is still caught by each package's suite run and the
|
|
460
|
+
quality lap
|
|
457
461
|
- The narrow exception: a simplification that drops something
|
|
458
462
|
\`.gtd/REQUIREMENTS.md\` mentions is an open question, not a
|
|
459
463
|
silent default
|
|
@@ -465,11 +469,13 @@ ${footnoteFoldIn}${codeThreadReplies()}
|
|
|
465
469
|
only, as fenced TypeScript (or the repository's language)
|
|
466
470
|
3. \`## Call Stacks\` — seam level, entry point → module
|
|
467
471
|
boundary; one line per hop, never per line of code
|
|
468
|
-
4. \`## E2E Scenarios\` —
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
472
|
+
4. \`## E2E Scenarios\` — one line per user-visible behaviour,
|
|
473
|
+
\`- e2e: <path> — <behaviour> (covers <concern>)\`, in plain
|
|
474
|
+
words: the builder writes the scenario in the repository's
|
|
475
|
+
own e2e framework, so never spell out Gherkin here. With no
|
|
476
|
+
user-visible behaviour change, the literal line
|
|
477
|
+
\`No e2e change.\` plus a one-line reason — never empty or
|
|
478
|
+
missing
|
|
473
479
|
5. \`## Unit Tests\` — one \`### <interface>\` per entry of
|
|
474
480
|
\`## Interfaces\`, each test a line
|
|
475
481
|
\`- unit: <path> — <behaviour> (covers <concern>)\`;
|
|
@@ -495,35 +501,31 @@ const architectureDecomposePrompt = () => `${styleBlock}
|
|
|
495
501
|
${stateFileRules}
|
|
496
502
|
- The only state files this turn touches are the package files
|
|
497
503
|
under \`.gtd/packages/\` — no other files for notes or output.
|
|
498
|
-
Never delete \`.gtd/ARCHITECTURE.md\`:
|
|
499
|
-
|
|
504
|
+
Never delete \`.gtd/ARCHITECTURE.md\`: package files may
|
|
505
|
+
reference it, and it is removed with the last package
|
|
500
506
|
- Work from \`.gtd/ARCHITECTURE.md\` if you wrote it earlier this
|
|
501
507
|
conversation, otherwise read it (the converged technical
|
|
502
508
|
plan). It already lists the concerns, interfaces, e2e scenarios
|
|
503
509
|
and unit tests — this turn groups them into packages. A
|
|
504
510
|
\`## Merged Concerns\` heading there records merges, never a
|
|
505
511
|
concern of its own: write no package file for it
|
|
506
|
-
- A package is
|
|
507
|
-
green
|
|
508
|
-
|
|
509
|
-
same files stay in one package unless
|
|
510
|
-
an interface the earlier one creates.
|
|
511
|
-
|
|
512
|
-
interface-introducing packages first
|
|
512
|
+
- A package is one concern's slice, and each must leave the full
|
|
513
|
+
suite green — every package boundary costs a full run, so write
|
|
514
|
+
as few as the concerns allow. Keep the merge rule: concerns whose
|
|
515
|
+
footprints centre on the same files stay in one package unless
|
|
516
|
+
the later one only consumes an interface the earlier one creates.
|
|
517
|
+
Order them interface-introducing packages first
|
|
513
518
|
- Write the packages under \`.gtd/packages/\`, each carrying its
|
|
514
519
|
requirement(s) — both, independently, if merged — its tasks, and
|
|
515
520
|
each task's acceptance criteria as \`- [ ]\` checkboxes and
|
|
516
521
|
relevant paths:
|
|
517
|
-
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
- the last numbered package is the wiring package: CLI entry,
|
|
525
|
-
workflow composition, config. A red e2e after it is a bug, not
|
|
526
|
-
missing work
|
|
522
|
+
- \`01-…\` onward — one vertical slice each: the unit tests,
|
|
523
|
+
the code, the wiring (CLI entry, workflow composition, config)
|
|
524
|
+
and every \`## E2E Scenarios\` entry its concern covers, so the
|
|
525
|
+
slice ends with its scenarios passing. A requirement no test
|
|
526
|
+
covers (docs, README, deletions, config) is a task of the slice
|
|
527
|
+
it belongs to; only one no slice owns becomes a chore package,
|
|
528
|
+
which declares no tests
|
|
527
529
|
- Every package with tests has a \`## Tests\` section, one line per
|
|
528
530
|
declared test, copied from the architecture entries:
|
|
529
531
|
\`- unit: \\\`<path>\\\`\` or \`- e2e: \\\`<path>\\\`\`. Chore packages have
|
|
@@ -569,10 +571,10 @@ const packagesItemBuildingPrompt = (pkg) => `${stateFileRules}
|
|
|
569
571
|
- Write the tests the package declares under \`## Tests\` first,
|
|
570
572
|
then the code that makes them pass; the turn is refused unless
|
|
571
573
|
every declared test is in your diff
|
|
572
|
-
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
574
|
+
- A declared e2e test is a scenario in the repository's own e2e
|
|
575
|
+
framework for the behaviour its \`## E2E Scenarios\` entry names.
|
|
576
|
+
Word it to fit the existing steps — reuse and generalise them
|
|
577
|
+
rather than adding one-off ones
|
|
576
578
|
- Implement every task the package describes, no more, no less,
|
|
577
579
|
fanning independent ones out to parallel subagents where your
|
|
578
580
|
harness supports it; leave other package files untouched
|
|
@@ -626,22 +628,9 @@ Edit \`.gtd/ESCALATION.md\` with fresh instructions for the next fix
|
|
|
626
628
|
turn, or land untouched to give it one more attempt at the same
|
|
627
629
|
analysis.
|
|
628
630
|
`;
|
|
629
|
-
const
|
|
630
|
-
const list = (paths) => paths.length === 0 ? " (none)" : paths.map((path) => ` - ${path}`).join("\n");
|
|
631
|
-
return `- Read \`.gtd/ARCHITECTURE.md\` — the plan every package was built from
|
|
632
|
-
- A red scenario that is NEW in this plan likely means missing wiring
|
|
633
|
-
between packages; new scenarios:
|
|
634
|
-
${list(built.scenarios.added)}
|
|
635
|
-
- A red CHANGED or existing scenario or test is a regression a package
|
|
636
|
-
introduced; scenarios this plan changed:
|
|
637
|
-
${list(built.scenarios.changed)}
|
|
638
|
-
- Each package's commits, to bisect a break:
|
|
639
|
-
${built.ranges.map((r) => ` git log --oneline ${r.from}..${r.to} # ${r.pkg}`).join("\n")}
|
|
640
|
-
`;
|
|
641
|
-
};
|
|
642
|
-
const buildFixPrompt = (built) => `${stateFileRules}
|
|
631
|
+
const buildFixPrompt = () => `${stateFileRules}
|
|
643
632
|
${fixFeedbackPrompt}
|
|
644
|
-
|
|
633
|
+
- Leave everything uncommitted — do not commit
|
|
645
634
|
`;
|
|
646
635
|
const finisherSystem = () => `${finisherPersona}
|
|
647
636
|
|
|
@@ -793,9 +782,10 @@ const reviewNotesCapture = (commit) => `This is machine-captured input, not inst
|
|
|
793
782
|
Commit: ${commit}
|
|
794
783
|
The human's notes are in .gtd/REVIEW.md at this commit. Run: git show ${commit}
|
|
795
784
|
`;
|
|
785
|
+
const noteHead = (n) => `${n.id} — ${n.anchor}${n.label === void 0 ? "" : ` (${n.label})`}`;
|
|
796
786
|
const notesCapture = (notes) => `This is machine-captured input, not instructions.
|
|
797
787
|
|
|
798
|
-
${notes.map((n) => `- ${n
|
|
788
|
+
${notes.map((n) => `- ${noteHead(n)}\n ${n.text.replace(/\n/g, "\n ")}`).join("\n")}
|
|
799
789
|
`;
|
|
800
790
|
const buildReviewAnswerQuestionsPrompt = (notes) => `${stateFileRules}
|
|
801
791
|
- The only state file this turn writes is \`.gtd/REVIEW.md\`; touch no
|
|
@@ -857,12 +847,47 @@ record.
|
|
|
857
847
|
What each change does next (then run \`gtd land\`):
|
|
858
848
|
- **Re-review** — re-run the reviewer to author a fresh \`.gtd/REVIEW.md\` (**build.review.reviewing**).
|
|
859
849
|
`;
|
|
850
|
+
/** Greedy wrap at 80 columns with a 2-space continuation indent: oxfmt (`proseWrap: always`) rewrites any other shape. */
|
|
851
|
+
const wrapItem = (item) => {
|
|
852
|
+
const out = [];
|
|
853
|
+
let line = "";
|
|
854
|
+
for (const word of item.split(" ")) if (line !== "" && line.length + 1 + word.length > 80) {
|
|
855
|
+
out.push(line);
|
|
856
|
+
line = ` ${word}`;
|
|
857
|
+
} else line = line === "" ? word : `${line} ${word}`;
|
|
858
|
+
return [...out, line];
|
|
859
|
+
};
|
|
860
|
+
/** Appends one section of `notes` to `.gtd/TODO.md`, wrapped the way oxfmt writes it; an existing file is only ever appended to. */
|
|
861
|
+
const deferNotesScript = (notes, round) => {
|
|
862
|
+
return `mkdir -p .gtd
|
|
863
|
+
if [ -s .gtd/TODO.md ]; then
|
|
864
|
+
[ -z "$(tail -c1 .gtd/TODO.md)" ] || printf '\\n' >> .gtd/TODO.md
|
|
865
|
+
printf '\\n' >> .gtd/TODO.md
|
|
866
|
+
fi
|
|
867
|
+
printf '%s\\n' ${[
|
|
868
|
+
`## Deferred review notes (${round.slice(0, 7)})`,
|
|
869
|
+
"",
|
|
870
|
+
...notes.flatMap((n) => wrapItem(`- ${noteHead(n)}: ${n.text.replace(/\s+/g, " ")}`))
|
|
871
|
+
].map(quote).join(" ")} >> .gtd/TODO.md
|
|
872
|
+
`;
|
|
873
|
+
};
|
|
874
|
+
/** The gate right after a deferral: landing clean signs off without these notes. */
|
|
875
|
+
const buildReviewAwaitAfterDeferMessage = (base, deferred) => `${buildReviewAwaitReviewMessage(base)}
|
|
876
|
+
Deferred to \`.gtd/TODO.md\` just now, NOT acted on in this process — landing
|
|
877
|
+
clean signs off without them:
|
|
878
|
+
|
|
879
|
+
${deferred.map((n) => `- ${noteHead(n)}: ${n.text.replace(/\s*\n\s*/g, " ")}`).join("\n")}
|
|
880
|
+
`;
|
|
860
881
|
const buildReviewTriageMessage = () => `Judging each note the human added to \`.gtd/REVIEW.md\` (a line note, a
|
|
861
882
|
footnote, or prose under a chunk) with one verdict: \`edit\` (a change
|
|
862
883
|
request), \`question\`, \`nit\` (a small fix needing no re-plan) or
|
|
863
884
|
\`praise\`. Run \`gtd judge answer\` and pipe a choice per note — or land
|
|
864
885
|
untouched, which treats every note as \`edit\` (the conservative
|
|
865
886
|
default; a skipped judgment never dismisses a note).
|
|
887
|
+
|
|
888
|
+
Also judge each note's severity, one id per note: \`note-<n>.security\`,
|
|
889
|
+
\`note-<n>.reversibility\`, \`note-<n>.blastRadius\` and
|
|
890
|
+
\`note-<n>.newConcept\`.
|
|
866
891
|
`;
|
|
867
892
|
const buildReviewCollectingPrompt = (capture) => `${styleBlock}
|
|
868
893
|
|
|
@@ -883,6 +908,8 @@ ${footnoteFoldIn}${codeThreadReplies()}
|
|
|
883
908
|
- When the capture names an answering commit, carry each answered
|
|
884
909
|
question into \`.gtd/REQUIREMENTS.md\`'s \`## Answered Questions\` as
|
|
885
910
|
\`### <the note>\` plus its answer — the lap replaces \`.gtd/REVIEW.md\`
|
|
911
|
+
- Keep capture order, and carry each note's \`(tier: reason)\`
|
|
912
|
+
label into the concern folded from it
|
|
886
913
|
- Nit notes were already fixed: never re-raise a fixed nit as a concern
|
|
887
914
|
- Finish by running \`gtd check review .gtd/REVIEW.md\` and fix
|
|
888
915
|
what it reports
|
|
@@ -924,7 +951,18 @@ actionability, and never dismiss a real note or edit as approval.
|
|
|
924
951
|
- If not: finish without writing anything — changing nothing is
|
|
925
952
|
the sign-off
|
|
926
953
|
`;
|
|
927
|
-
const
|
|
954
|
+
const scenariosPrompt = (removed) => `- When a scenario in a \`.feature\` file was added or changed since the
|
|
955
|
+
base, the first chunk is \`## Scenarios\`: one pointer per such
|
|
956
|
+
scenario, its note saying in plain words what behaviour it now pins
|
|
957
|
+
down — the human signs off the scenarios here, nowhere else
|
|
958
|
+
${removed.length === 0 ? "" : `- These assertions of scenarios that existed at the base are gone:
|
|
959
|
+
${removed.map(({ path, lines }) => lines.map((a) => ` ${path} — ${a.scenario} — ${a.line}\n`).join("")).join("")} Open the note of each scenario that lost one with \`Weakened:\`,
|
|
960
|
+
naming the lost line and whether \`.gtd/REQUIREMENTS.md\` asked
|
|
961
|
+
for it. A scenario that no longer exists has no pointer of its own:
|
|
962
|
+
put its \`Weakened:\` note on a pointer of the chunk covering its
|
|
963
|
+
removal
|
|
964
|
+
`}`;
|
|
965
|
+
const buildReviewReviewingPrompt = (base, carry, removed = []) => `${styleBlock}
|
|
928
966
|
|
|
929
967
|
${styleFormatContract}
|
|
930
968
|
|
|
@@ -966,7 +1004,7 @@ review the changes:
|
|
|
966
1004
|
A note sitting entirely on the line(s) beneath the pointer is
|
|
967
1005
|
also valid. Either way, the note must never start with a bare \`./path\` token
|
|
968
1006
|
— that parses as a second pointer, not a note
|
|
969
|
-
No diff is given — read the changes yourself. The range runs
|
|
1007
|
+
${scenariosPrompt(removed)}No diff is given — read the changes yourself. The range runs
|
|
970
1008
|
from \`${base}\` to the working tree (committed turns
|
|
971
1009
|
plus anything pending); on a feedback round that's the previous
|
|
972
1010
|
review's boundary, so it covers only what's new.
|
|
@@ -1013,20 +1051,6 @@ ${it.processCostByModel.map((m) => `- ${m.model}: ${m.cost}\n`).join("")}
|
|
|
1013
1051
|
Print the closing message and stop — this writes nothing itself.
|
|
1014
1052
|
`;
|
|
1015
1053
|
};
|
|
1016
|
-
const scenarioWordingMessage = (at, drifted) => `The e2e scenario wording was frozen when package 0 landed, and the last
|
|
1017
|
-
turn changed it. Removed lines are marked \`-\`, added ones \`+\`:
|
|
1018
|
-
|
|
1019
|
-
${drifted.map(({ path, lines }) => `${path}\n${lines.join("\n")}`).join("\n\n")}
|
|
1020
|
-
|
|
1021
|
-
To accept the change, land untouched.
|
|
1022
|
-
|
|
1023
|
-
To reject it, run
|
|
1024
|
-
|
|
1025
|
-
git checkout ${at} -- ${drifted.map(({ path }) => quote(path)).join(" ")}
|
|
1026
|
-
|
|
1027
|
-
and land. Restoring only some of the files is a partial accept: every file
|
|
1028
|
-
still differing from the frozen wording is accepted.
|
|
1029
|
-
`;
|
|
1030
1054
|
//#endregion
|
|
1031
1055
|
//#region src/workflows/shared/steps.ts
|
|
1032
1056
|
const FEEDBACK = ".gtd/FEEDBACK.md";
|
|
@@ -1037,7 +1061,7 @@ const REVIEW = ".gtd/REVIEW.md";
|
|
|
1037
1061
|
const QUALITY = ".gtd/QUALITY.md";
|
|
1038
1062
|
const planner = () => env.plannerModel ?? "";
|
|
1039
1063
|
const coder = () => env.coderModel ?? "";
|
|
1040
|
-
const fixCheck = (
|
|
1064
|
+
const fixCheck = () => agentWithSkills("fix", buildFixPrompt(), {
|
|
1041
1065
|
label: "Fixing the check",
|
|
1042
1066
|
file: FEEDBACK,
|
|
1043
1067
|
model: coder(),
|
|
@@ -1093,7 +1117,7 @@ const fixQuality = () => agentWithSkills("fix.quality.fixing", buildFixQualityPr
|
|
|
1093
1117
|
allowEmpty: true
|
|
1094
1118
|
});
|
|
1095
1119
|
/** Write `.gtd/REVIEW.md` over everything since `base`, carrying the answers of commit `carry` when given. */
|
|
1096
|
-
const reviewing = (base, carry) => agentWithSkills("review.reviewing", buildReviewReviewingPrompt(base, carry), {
|
|
1120
|
+
const reviewing = (base, carry) => agentWithSkills("review.reviewing", buildReviewReviewingPrompt(base, carry, removedAssertions(changesSince(base))), {
|
|
1097
1121
|
label: "Reviewing",
|
|
1098
1122
|
file: REVIEW,
|
|
1099
1123
|
mode: "review",
|
|
@@ -1109,37 +1133,24 @@ const fixRisks = (notes) => agentWithSkills("review.fix.risks.fixing", buildRevi
|
|
|
1109
1133
|
system: reviewerSystem(),
|
|
1110
1134
|
allowEmpty: true
|
|
1111
1135
|
});
|
|
1112
|
-
const awaitReview = (base, message = buildReviewAwaitReviewMessage(base)) => human("review.await-review", {
|
|
1136
|
+
const awaitReview = (base, message = buildReviewAwaitReviewMessage(base), acceptClean = false) => human("review.await-review", {
|
|
1113
1137
|
message,
|
|
1114
1138
|
label: "Awaiting your review",
|
|
1115
1139
|
file: REVIEW,
|
|
1116
1140
|
mode: "review",
|
|
1117
|
-
base
|
|
1141
|
+
base,
|
|
1142
|
+
...acceptClean ? { acceptClean } : {}
|
|
1118
1143
|
});
|
|
1119
1144
|
/** The round at commit `round` left no `.gtd/REVIEW.md`. */
|
|
1120
1145
|
const reviewMissing = (round) => human("review.review-missing", {
|
|
1121
1146
|
message: buildReviewReviewMissingMessage(round),
|
|
1122
1147
|
label: "Nothing to review"
|
|
1123
1148
|
});
|
|
1124
|
-
//#endregion
|
|
1125
|
-
//#region src/workflows/shared/health.ts
|
|
1126
|
-
/** Written while `fastTestCommand` is unset; its presence rests the process at the check. */
|
|
1127
|
-
const SETUP = ".gtd/SETUP.md";
|
|
1128
|
-
const SETUP_TEXT = "The bundled workflow needs the `fastTestCommand` setting: the fast suite (everything but e2e).\nSet it as a workflow option in `gtd.config.ts` or as GTD_FASTTESTCOMMAND.";
|
|
1129
|
-
/** Shell lines for a check's preamble: unset (blank after trim) setting writes `SETUP` and skips the suite. */
|
|
1130
|
-
const fastSuiteGuard = () => (env.fastTestCommand ?? "").trim() === "" ? [
|
|
1131
|
-
`mkdir -p ${quote(dirname(SETUP))}`,
|
|
1132
|
-
`printf '%s\\n' ${quote(SETUP_TEXT)} > ${quote(SETUP)}`,
|
|
1133
|
-
`printf '%s\\n' ${quote(SETUP_TEXT)} >&2`,
|
|
1134
|
-
"exit 0"
|
|
1135
|
-
] : [`rm -f ${quote(SETUP)}`];
|
|
1136
|
-
const unconfigured = () => read(SETUP) !== void 0;
|
|
1137
1149
|
/** Run the suite as step `name`; resolves `true` when it passed. A failure is in `.gtd/FEEDBACK.md`. */
|
|
1138
|
-
const baseline = (name, label = "Checking the baseline") =>
|
|
1150
|
+
const baseline = (name, label = "Checking the baseline") => check(name, env.testCommand ?? "", {
|
|
1139
1151
|
report: FEEDBACK,
|
|
1140
|
-
label
|
|
1141
|
-
|
|
1142
|
-
}), unconfigured);
|
|
1152
|
+
label
|
|
1153
|
+
});
|
|
1143
1154
|
const escalationSteps = {
|
|
1144
1155
|
limit: 2,
|
|
1145
1156
|
describe: describeEscalation,
|
|
@@ -1177,22 +1188,18 @@ const sameFailure = async (previous, current) => {
|
|
|
1177
1188
|
});
|
|
1178
1189
|
return comparable && truncated.length === 0 && answered(answers.verdict, "identical", numeric(vars.judgeIdenticalMinP, Infinity));
|
|
1179
1190
|
};
|
|
1180
|
-
const runSuite = (options) => {
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
sweepOnGreen: [ESCALATION, ...options.sweepOnGreen ?? []],
|
|
1186
|
-
...fast ? { preamble: fastSuiteGuard() } : {}
|
|
1187
|
-
});
|
|
1188
|
-
};
|
|
1191
|
+
const runSuite = (options) => check("health.check", env.testCommand ?? "", {
|
|
1192
|
+
report: FEEDBACK,
|
|
1193
|
+
label: "Running checks",
|
|
1194
|
+
sweepOnGreen: [ESCALATION, ...options.sweepOnGreen ?? []]
|
|
1195
|
+
});
|
|
1189
1196
|
/**
|
|
1190
1197
|
* Loop until the suite is green: check, and on red run `fix` — escalating
|
|
1191
1198
|
* first once `FIX_CAP` fixes are spent, or a judge calls the failure
|
|
1192
1199
|
* identical to the previous round's.
|
|
1193
1200
|
*/
|
|
1194
1201
|
const healthy = (fix, options = {}) => healthy$1(fix, {
|
|
1195
|
-
check:
|
|
1202
|
+
check: () => runSuite(options),
|
|
1196
1203
|
report: FEEDBACK,
|
|
1197
1204
|
fixCap: 3,
|
|
1198
1205
|
fixesSoFar: options.fixesSoFar ?? 0,
|
|
@@ -1214,12 +1221,12 @@ const defaults = {
|
|
|
1214
1221
|
judgeBudgetBytes: "32768",
|
|
1215
1222
|
judgeIdenticalMinP: "0.7",
|
|
1216
1223
|
reviewNoteActionable: "0.7",
|
|
1224
|
+
reviewSeverityMinP: "0.7",
|
|
1217
1225
|
qualityReviews: "correctness, owasp-security, ponytail-review, test-audit, conventions, spec-challenge"
|
|
1218
1226
|
};
|
|
1219
1227
|
/** Environment settings. */
|
|
1220
1228
|
const envDefaults = {
|
|
1221
1229
|
testCommand: "npm test",
|
|
1222
|
-
fastTestCommand: "",
|
|
1223
1230
|
plannerModel: "smart",
|
|
1224
1231
|
coderModel: "base"
|
|
1225
1232
|
};
|
|
@@ -1231,9 +1238,9 @@ const ShippedOptions = Struct({
|
|
|
1231
1238
|
judgeBudgetBytes: setting,
|
|
1232
1239
|
judgeIdenticalMinP: setting,
|
|
1233
1240
|
reviewNoteActionable: setting,
|
|
1241
|
+
reviewSeverityMinP: setting,
|
|
1234
1242
|
qualityReviews: setting,
|
|
1235
1243
|
testCommand: setting,
|
|
1236
|
-
fastTestCommand: setting,
|
|
1237
1244
|
plannerModel: setting,
|
|
1238
1245
|
coderModel: setting
|
|
1239
1246
|
});
|
|
@@ -1253,21 +1260,6 @@ const shipped = (flow, doors, base) => defineWorkflow(standardSchemaV1(ShippedOp
|
|
|
1253
1260
|
base
|
|
1254
1261
|
}));
|
|
1255
1262
|
//#endregion
|
|
1256
|
-
//#region src/workflows/shared/scenarios.ts
|
|
1257
|
-
/** After a turn: stop at `scenario-wording` while wording drifted; accept moves the snapshot. */
|
|
1258
|
-
const holdWording = (frozen) => holdWording$1(frozen, (at, drifted) => human("scenario-wording", {
|
|
1259
|
-
message: scenarioWordingMessage(at, drifted),
|
|
1260
|
-
label: "Scenario wording changed",
|
|
1261
|
-
acceptClean: true,
|
|
1262
|
-
base: at
|
|
1263
|
-
}));
|
|
1264
|
-
/** `turn`, then `holdWording`; `within` names the scope the gate rests in. */
|
|
1265
|
-
const guarded = (frozen, turn, within) => async () => {
|
|
1266
|
-
await turn();
|
|
1267
|
-
if (within === void 0) await holdWording(frozen);
|
|
1268
|
-
else await scope(within, () => holdWording(frozen));
|
|
1269
|
-
};
|
|
1270
|
-
//#endregion
|
|
1271
1263
|
//#region src/workflows/shared/tail.ts
|
|
1272
1264
|
/** The reviewer's own `.gtd/REVIEW.md`, kept beside the human's notes so `fix` can tell them apart. */
|
|
1273
1265
|
const REVIEW_ORIG = ".gtd/REVIEW.orig.md";
|
|
@@ -1278,8 +1270,8 @@ const REVIEW_ORIG = ".gtd/REVIEW.orig.md";
|
|
|
1278
1270
|
*/
|
|
1279
1271
|
const qualityLap = () => qualityLap$1(lensesOf(vars.qualityReviews ?? ""), reviewQuality, QUALITY);
|
|
1280
1272
|
/** Resolves `true` once `.gtd/QUALITY.md` is resolved, `false` when the fix cap escalated instead. */
|
|
1281
|
-
const fixQualityFindings = (escalations
|
|
1282
|
-
fix:
|
|
1273
|
+
const fixQualityFindings = (escalations) => fixFindings({
|
|
1274
|
+
fix: fixQuality,
|
|
1283
1275
|
findings: QUALITY,
|
|
1284
1276
|
cap: 3,
|
|
1285
1277
|
escalate: () => escalation(escalations)
|
|
@@ -1295,34 +1287,25 @@ const refusePendingHandOff = () => {
|
|
|
1295
1287
|
};
|
|
1296
1288
|
/**
|
|
1297
1289
|
* The build tail: fix (when entered red), keep green, the quality lap, then
|
|
1298
|
-
* `finish` — the human review, as the calling workflow runs it.
|
|
1290
|
+
* `finish` — the human review, as the calling workflow runs it. `green`: the
|
|
1291
|
+
* caller just left the full suite green (the package loop), so no run opens it.
|
|
1299
1292
|
*/
|
|
1300
|
-
const tail = (fixFirst, finish,
|
|
1301
|
-
const frozen = built?.frozen;
|
|
1293
|
+
const tail = (fixFirst, finish, green = false) => scope("build", async () => {
|
|
1302
1294
|
const escalations = { rounds: 0 };
|
|
1303
|
-
const
|
|
1295
|
+
const fix = fixCheck;
|
|
1304
1296
|
const repair = async () => {
|
|
1305
|
-
await
|
|
1306
|
-
await healthy(
|
|
1297
|
+
await fix();
|
|
1298
|
+
await healthy(fix, {
|
|
1307
1299
|
fixesSoFar: 1,
|
|
1308
1300
|
escalations
|
|
1309
1301
|
});
|
|
1310
1302
|
};
|
|
1311
1303
|
if (fixFirst) await repair();
|
|
1312
|
-
else await healthy(
|
|
1313
|
-
|
|
1314
|
-
sweepOnGreen: [ARCHITECTURE]
|
|
1315
|
-
});
|
|
1316
|
-
if (await qualityLap() === "findings") if (await fixQualityFindings(escalations, frozen)) await healthy(guardedFix, { escalations });
|
|
1304
|
+
else if (!green) await healthy(fix, { escalations });
|
|
1305
|
+
if (await qualityLap() === "findings") if (await fixQualityFindings(escalations)) await healthy(fix, { escalations });
|
|
1317
1306
|
else await repair();
|
|
1318
|
-
return finish(escalations
|
|
1307
|
+
return finish(escalations);
|
|
1319
1308
|
});
|
|
1320
|
-
const handOffScript = (reviewed) => [
|
|
1321
|
-
"#!/usr/bin/env sh",
|
|
1322
|
-
"set -e",
|
|
1323
|
-
`git show ${quote(`${reviewed}:${REVIEW}`)} > ${quote(REVIEW_ORIG)}`,
|
|
1324
|
-
""
|
|
1325
|
-
].join("\n");
|
|
1326
1309
|
/**
|
|
1327
1310
|
* The review and fix workflows' human review since `base`: a sign-off closes
|
|
1328
1311
|
* `.gtd/REVIEW.md`; a note leaves it, with the reviewer's own version as
|
|
@@ -1332,11 +1315,11 @@ const handOffReview = (base, escalations) => reviewToHandOff(base, {
|
|
|
1332
1315
|
file: REVIEW,
|
|
1333
1316
|
reviewing,
|
|
1334
1317
|
fixRisks,
|
|
1335
|
-
keepGreen: () => healthy(
|
|
1318
|
+
keepGreen: () => healthy(fixCheck, { escalations }),
|
|
1336
1319
|
awaitReview: (b) => awaitReview(b, handOffAwaitReviewMessage(b)),
|
|
1337
1320
|
reviewMissing,
|
|
1338
1321
|
close: closeReview,
|
|
1339
|
-
handOff: (reviewed) => run("review.handing-off",
|
|
1322
|
+
handOff: (reviewed) => run("review.handing-off", showScript(reviewed, REVIEW, REVIEW_ORIG), { label: "Handing your notes to fix" }),
|
|
1340
1323
|
threadsPending: "gtd land: open-threads: a thread in .gtd/REVIEW.md or an `H:` code comment waits on the agent — nothing answers it here; delete it, or turn it into a note for fix.",
|
|
1341
1324
|
unparsed: "gtd land: review-doc: your edit to .gtd/REVIEW.md contains no note fix can read — restore the deleted chunk, or write the note as a line under its entry.",
|
|
1342
1325
|
deleted: "gtd land: review-doc: .gtd/REVIEW.md was deleted — restore it, or leave a note to hand to fix."
|
|
@@ -1372,6 +1355,7 @@ const access = (vars) => ({
|
|
|
1372
1355
|
architecture: { write: [".gtd/REQUIREMENTS.md"] },
|
|
1373
1356
|
"architecture.decompose": { write: [".gtd/packages/**", ".gtd/ARCHITECTURE.md"] },
|
|
1374
1357
|
"build.review": { write: [".gtd/REVIEW.md"] },
|
|
1358
|
+
"build.review.defer": { write: [".gtd/TODO.md"] },
|
|
1375
1359
|
"build.review.fix.nits": {},
|
|
1376
1360
|
"build.review.fix.risks": {},
|
|
1377
1361
|
...lensScopes("build.quality", lensesOf(vars.qualityReviews ?? ""), () => ({ write: [] }))
|
|
@@ -1385,4 +1369,4 @@ const steering = {
|
|
|
1385
1369
|
[REVIEW]: "review"
|
|
1386
1370
|
};
|
|
1387
1371
|
//#endregion
|
|
1388
|
-
export {
|
|
1372
|
+
export { unwindFailedMessage as $, architectureDecomposePrompt as A, designSystem as B, fixRisks as C, agentWithSkills as D, reviewing as E, buildReviewFixNitsPrompt as F, packagesItemBuildingPrompt as G, finisherSystem as H, buildReviewTriageMessage as I, reviewEditsCapture as J, packagesItemFixSuitePrompt as K, builderSystem as L, buildReviewAnswerQuestionsPrompt as M, buildReviewAwaitAfterDeferMessage as N, architectSystem as O, buildReviewCollectingPrompt as P, startGateBlockedMessage as Q, deferNotesScript as R, fixCheck as S, reviewMissing as T, fixReviewNotesPrompt as U, designTriagePrompt as V, idleMessage as W, reviewNotesCapture as X, reviewGateBlockedMessage as Y, reviewerSystem as Z, FEEDBACK as _, REVIEW_ORIG as a, awaitReview as b, refusePendingHandOff as c, defaults as d, unwindFailure as et, envDefaults as f, ARCHITECTURE as g, healthy as h, skills as i, architectureGateAnswerMessage as j, architectureAuthorPrompt as k, tail as l, gate as m, summary as n, closeReview as o, baseline as p, reviewEditNotesCapture as q, access as r, handOffTail as s, steering as t, shipped as u, REQUIREMENTS as v, planner as w, coder as x, REVIEW as y, designGateAnswerMessage as z };
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
|
|
2
|
+
//#region src/steering/SteeringFormat.ts
|
|
3
|
+
/** `file:line:col: message` — the shape editors and grep already jump on. Stored 0-based, printed 1-based. A finding with a `line` but no `range`, or none at all, degrades to the shorter forms. */
|
|
4
|
+
const formatFinding = (file, finding) => {
|
|
5
|
+
if (finding.line === void 0) return finding.message;
|
|
6
|
+
const col = finding.range !== void 0 ? `:${finding.range.start.character + 1}` : "";
|
|
7
|
+
return `${file}:${finding.line + 1}${col}: ${finding.message}`;
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
2
10
|
//#region node_modules/mdast-util-to-string/lib/index.js
|
|
3
11
|
/**
|
|
4
12
|
* @typedef {import('mdast').Nodes} Nodes
|
|
@@ -15912,10 +15920,13 @@ const reviewNotes = (before, after) => {
|
|
|
15912
15920
|
return [...parseReviewDoc(after).changesets.flatMap((chunk) => {
|
|
15913
15921
|
const prior = oldChunks.get(chunk.title);
|
|
15914
15922
|
return [...chunkNote(chunk, prior), ...pointerNotes(chunk, prior)];
|
|
15915
|
-
}), ...footnoteNotes(before, after)].sort((a, b) => a.line - b.line).map((f, i) =>
|
|
15916
|
-
|
|
15917
|
-
|
|
15918
|
-
|
|
15923
|
+
}), ...footnoteNotes(before, after)].sort((a, b) => a.line - b.line).map((f, i) => {
|
|
15924
|
+
return {
|
|
15925
|
+
id: `note-${i + 1}`,
|
|
15926
|
+
...f.note,
|
|
15927
|
+
forced: /^!(\s|$)/.test(f.note.text)
|
|
15928
|
+
};
|
|
15929
|
+
});
|
|
15919
15930
|
};
|
|
15920
15931
|
/** Pointer notes the reviewer opened with `Risk:`, in document order — the ones the workflow fixes before the human gate. */
|
|
15921
15932
|
const reviewRisks = (content) => parseReviewDoc(content).changesets.flatMap((chunk) => chunk.files.flatMap((file) => file.note?.startsWith("Risk:") ? [{
|
|
@@ -16293,4 +16304,4 @@ const viewOf = (format, content) => ({
|
|
|
16293
16304
|
/** Every OPEN thread — last entry is the agent's — as `{ name, line, firstMe }` (0-based line). `[]` for a format with no thread concept. */
|
|
16294
16305
|
const openThreads = (format, content) => format.openThreads?.(content) ?? [];
|
|
16295
16306
|
//#endregion
|
|
16296
|
-
export { headingSections as C, headingSectionBodies as S, openThreadFindings as _, unansweredQuestions as a, parseThreadsWithFindings as b, stripCodeThreads as c, reviewNotes as d, reviewRisks as f, THREAD_REPLY_ACTION_TITLE as g, FOOTNOTE_ACTION_TITLE as h, steeringFormatOrFreeForm as i, freeFormFormat as l, isAnswered as m, openThreads as n, viewOf as o, FREE_TEXT_PLACEHOLDER as p, steeringFormatFor as r, parseCodeThreads as s, BUILT_IN_MODE_NAMES as t, applySteeringEdits as u, parseFootnotes as v, getParseCount as x, parseThreads as y };
|
|
16307
|
+
export { headingSections as C, headingSectionBodies as S, openThreadFindings as _, unansweredQuestions as a, parseThreadsWithFindings as b, stripCodeThreads as c, reviewNotes as d, reviewRisks as f, THREAD_REPLY_ACTION_TITLE as g, FOOTNOTE_ACTION_TITLE as h, steeringFormatOrFreeForm as i, freeFormFormat as l, isAnswered as m, openThreads as n, viewOf as o, FREE_TEXT_PLACEHOLDER as p, steeringFormatFor as r, parseCodeThreads as s, BUILT_IN_MODE_NAMES as t, applySteeringEdits as u, parseFootnotes as v, formatFinding as w, getParseCount as x, parseThreads as y };
|
package/dist/flows.mjs
CHANGED
|
@@ -237,6 +237,13 @@ const moveScript = (from, to) => [
|
|
|
237
237
|
`mv -- ${quote(from)} ${quote(to)}`,
|
|
238
238
|
""
|
|
239
239
|
].join("\n");
|
|
240
|
+
/** Write `path` as committed at `ref` to `to`. */
|
|
241
|
+
const showScript = (ref, path, to) => [
|
|
242
|
+
"#!/usr/bin/env sh",
|
|
243
|
+
"set -e",
|
|
244
|
+
`git show ${quote(`${ref}:${path}`)} > ${quote(to)}`,
|
|
245
|
+
""
|
|
246
|
+
].join("\n");
|
|
240
247
|
//#endregion
|
|
241
248
|
//#region src/flows/helpers.ts
|
|
242
249
|
/** Whether a judge answered `expected` at a probability of at least `minP`. */
|
|
@@ -515,6 +522,7 @@ var flows_exports = /* @__PURE__ */ __exportAll({
|
|
|
515
522
|
scope: () => scope,
|
|
516
523
|
sectionBodies: () => sectionBodies,
|
|
517
524
|
sections: () => sections,
|
|
525
|
+
showScript: () => showScript,
|
|
518
526
|
skillsFor: () => skillsFor,
|
|
519
527
|
start: () => start,
|
|
520
528
|
threads: () => threads,
|
|
@@ -522,4 +530,4 @@ var flows_exports = /* @__PURE__ */ __exportAll({
|
|
|
522
530
|
wrote: () => wrote
|
|
523
531
|
});
|
|
524
532
|
//#endregion
|
|
525
|
-
export { FLOWS_PROTOCOL, FlowsProtocolError, accessFor, agent, answered, changes, changesSince, check, checkScript, codeChanges, codeThreads, configProblems, configure, defineConfig, defineWorkflow, env, glob, hasThreadFor, head, human, installContext, isFactoryWorkflow, judge, moveScript, numeric, openQuestions, protocolMismatch, quote, read, refuse, removeScript, requireAnswers, requireProgress, requireReplies, requireRevert, requireThreadsClosed, restart, restoreScript, revertScript, run, scope, sectionBodies, sections, skillsFor, start, flows_exports as t, threads, vars, wrote };
|
|
533
|
+
export { FLOWS_PROTOCOL, FlowsProtocolError, accessFor, agent, answered, changes, changesSince, check, checkScript, codeChanges, codeThreads, configProblems, configure, defineConfig, defineWorkflow, env, glob, hasThreadFor, head, human, installContext, isFactoryWorkflow, judge, moveScript, numeric, openQuestions, protocolMismatch, quote, read, refuse, removeScript, requireAnswers, requireProgress, requireReplies, requireRevert, requireThreadsClosed, restart, restoreScript, revertScript, run, scope, sectionBodies, sections, showScript, skillsFor, start, flows_exports as t, threads, vars, wrote };
|