@alecsibilia/luca 14.0.0-alpha.2 → 14.0.0-alpha.21
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/CHANGELOG.md +76 -0
- package/README.md +7 -2
- package/board/client/board-look.ts +31 -1
- package/board/client/board-panel-parts.tsx +150 -0
- package/board/client/board-panel-stages.ts +99 -0
- package/board/client/board-panel-styles.ts +223 -0
- package/board/client/board-panel.tsx +77 -1275
- package/board/client/engine-life.ts +48 -0
- package/board/client/final-review-stack.tsx +144 -0
- package/board/client/heartbeat.tsx +61 -0
- package/board/client/helper-lines.tsx +69 -0
- package/board/client/live-feed.tsx +86 -0
- package/board/client/live-line.ts +73 -0
- package/board/client/model-line.tsx +178 -0
- package/board/client/needs-you-section.tsx +133 -0
- package/board/client/one-line.tsx +193 -0
- package/board/client/repo-wait-banner.tsx +69 -0
- package/board/client/run-footer.tsx +68 -0
- package/board/client/run-header.tsx +189 -0
- package/board/client/run-picker.tsx +98 -0
- package/board/client/status-bar.tsx +131 -0
- package/board/client/step-dots.tsx +127 -0
- package/board/client/stuck-actions.tsx +269 -0
- package/board/client/ticket-card-view.tsx +238 -0
- package/board/client/ticket-detail.tsx +87 -0
- package/board/client/ticket-stack.tsx +119 -0
- package/board/client/ticket-wait.ts +188 -0
- package/board/client/timeline-rows.tsx +41 -14
- package/board/client/usage-line.tsx +51 -0
- package/board/client/wait-line.tsx +39 -0
- package/board/index.client.tsx +1 -1
- package/board/index.server.ts +7 -1
- package/board/package.json +1 -1
- package/board/server/board-panel-state-helpers.ts +67 -0
- package/board/server/board-server-check.ts +294 -0
- package/board/server/board-server-engine.ts +129 -0
- package/board/server/board-server-events.ts +134 -0
- package/board/server/board-server-read.ts +190 -0
- package/board/server/board-server-resume.ts +164 -0
- package/board/server/board-server-start.ts +174 -0
- package/board/server/board-server-store.ts +281 -0
- package/board/server/board-server-types.ts +114 -0
- package/board/server/board-server-util.ts +4 -0
- package/board/server/board-server.ts +52 -943
- package/board/server/board-vocabulary-engine.ts +144 -0
- package/board/server/board-vocabulary-review.ts +115 -0
- package/board/server/board-vocabulary-run.ts +145 -0
- package/board/server/board-vocabulary-shapes.ts +153 -0
- package/board/server/board-vocabulary.ts +20 -375
- package/board/server/current-step-panel-helpers.ts +108 -0
- package/board/server/describe-record.ts +403 -0
- package/board/server/engine-launch.ts +20 -3
- package/board/server/engine-restart-helpers.ts +105 -0
- package/board/server/engine-watch.ts +45 -5
- package/board/server/journal-rebuild-helpers.ts +169 -0
- package/board/server/live-file.ts +130 -0
- package/board/server/luca-version.ts +1 -1
- package/board/server/make-rows.ts +14 -629
- package/board/server/record-texts.ts +350 -0
- package/board/server/reduce-board-agent-start.ts +224 -0
- package/board/server/reduce-board-agents.ts +160 -0
- package/board/server/reduce-board-counters.ts +138 -0
- package/board/server/reduce-board-create.ts +148 -0
- package/board/server/reduce-board-final-review.ts +174 -0
- package/board/server/reduce-board-needs-you.ts +283 -0
- package/board/server/reduce-board-reasons.ts +59 -0
- package/board/server/reduce-board-run.ts +255 -0
- package/board/server/reduce-board-settle.ts +88 -0
- package/board/server/reduce-board-steps.ts +226 -0
- package/board/server/reduce-board-text.ts +139 -0
- package/board/server/reduce-board-ticket-checks.ts +168 -0
- package/board/server/reduce-board-ticket-join.ts +144 -0
- package/board/server/reduce-board-ticket-start.ts +132 -0
- package/board/server/reduce-board-update.ts +117 -0
- package/board/server/reduce-board-usage.ts +247 -0
- package/board/server/reduce-board.ts +100 -1917
- package/board/server/reply-post.ts +407 -0
- package/board/server/run-registry.ts +8 -4
- package/board/server/ticket-stages-panel-helpers.ts +296 -0
- package/board/shared/board-rows.ts +9 -0
- package/board/shared/board-rpc.ts +42 -0
- package/board/shared/board-state-counts.ts +77 -0
- package/board/shared/board-state-live.ts +99 -0
- package/board/shared/board-state-review.ts +59 -0
- package/board/shared/board-state-run.ts +236 -0
- package/board/shared/board-state-ticket.ts +257 -0
- package/board/shared/board-state-usage.ts +107 -0
- package/board/shared/board-state.ts +97 -567
- package/board/shared/reply-actions.ts +207 -0
- package/engine/agents/agent-launcher.ts +27 -4
- package/engine/agents/claude-launcher-helpers.ts +233 -0
- package/engine/agents/claude-launcher.ts +28 -669
- package/engine/agents/claude-messages.ts +212 -0
- package/engine/agents/claude-options.ts +43 -8
- package/engine/agents/common-instructions.ts +138 -0
- package/engine/agents/input-channel.ts +36 -0
- package/engine/agents/launch-paths.ts +29 -0
- package/engine/agents/launch-session.ts +227 -0
- package/engine/agents/learner-instructions.ts +31 -0
- package/engine/agents/open-session.ts +210 -0
- package/engine/agents/prompt-sections.ts +95 -0
- package/engine/agents/rejoin-prompts.ts +135 -0
- package/engine/agents/reviewer-instructions.ts +99 -0
- package/engine/agents/role-instructions.ts +31 -244
- package/engine/agents/role-prompts.ts +39 -109
- package/engine/agents/role-results.ts +106 -7
- package/engine/agents/scripted-launcher.ts +21 -6
- package/engine/agents/session-pool.ts +124 -0
- package/engine/agents/turn-progress.ts +283 -0
- package/engine/agents/writer-instructions.ts +151 -0
- package/engine/cli/computer-adapters-real.ts +15 -3
- package/engine/cli/computer-adapters.ts +2 -0
- package/engine/cli/computer-checks.ts +87 -4
- package/engine/cli/config-reload-text.ts +39 -0
- package/engine/cli/decision-model-setup.ts +70 -0
- package/engine/cli/doctor-command.ts +1 -0
- package/engine/cli/doctor.ts +21 -3
- package/engine/cli/going-runs.ts +192 -36
- package/engine/cli/init-command.ts +1 -0
- package/engine/cli/init.ts +23 -1
- package/engine/cli/live-runs.ts +73 -0
- package/engine/cli/luca-run.ts +42 -7
- package/engine/cli/luca-skills.ts +183 -0
- package/engine/cli/luca.ts +8 -1
- package/engine/cli/models-command.ts +119 -0
- package/engine/cli/read-run.ts +81 -0
- package/engine/cli/run-args.ts +33 -6
- package/engine/cli/run-demo.ts +143 -0
- package/engine/cli/run-end.ts +184 -0
- package/engine/cli/run-modes-helpers.ts +81 -0
- package/engine/cli/run-modes.ts +62 -439
- package/engine/cli/setup.ts +5 -48
- package/engine/cli/unfinished-runs.ts +122 -0
- package/engine/cli/upgrade-command.ts +212 -30
- package/engine/cli/upgrade-finish.ts +149 -0
- package/engine/cli/upgrade.ts +112 -71
- package/engine/config/config-fields.ts +127 -0
- package/engine/config/config-reload.ts +250 -0
- package/engine/config/engine-config-schema.ts +235 -0
- package/engine/config/engine-config.ts +72 -142
- package/engine/config/test-commands.ts +102 -0
- package/engine/core/agent-guards-helpers.ts +84 -0
- package/engine/core/agent-turn.ts +395 -0
- package/engine/core/already-done.ts +44 -1
- package/engine/core/build-action.ts +214 -0
- package/engine/core/build-context.ts +135 -0
- package/engine/core/build-launch.ts +259 -0
- package/engine/core/commit-in.ts +282 -0
- package/engine/core/decide-build-early.ts +108 -0
- package/engine/core/decide-build-ending.ts +145 -0
- package/engine/core/decide-build-helpers.ts +87 -0
- package/engine/core/decide-build-tickets.ts +207 -0
- package/engine/core/decide-build-view.ts +103 -0
- package/engine/core/decide-build.ts +101 -1368
- package/engine/core/decide-final-fix.ts +203 -0
- package/engine/core/decide-final-review.ts +55 -310
- package/engine/core/decide-red-green.ts +398 -0
- package/engine/core/decide-rejoin.ts +259 -0
- package/engine/core/decide-repo-wait.ts +129 -0
- package/engine/core/decide-run-budget.ts +86 -12
- package/engine/core/decide-stuck-helpers.ts +127 -0
- package/engine/core/decide-stuck.ts +60 -8
- package/engine/core/decide-ticket-review.ts +95 -0
- package/engine/core/decide-ticket.ts +267 -0
- package/engine/core/decide-waits.ts +47 -0
- package/engine/core/decide.ts +74 -23
- package/engine/core/engine-chores.ts +163 -0
- package/engine/core/environment-rerun.ts +83 -0
- package/engine/core/evidence-text.ts +84 -0
- package/engine/core/execute-action.ts +303 -0
- package/engine/core/execute-already-done-check.ts +133 -0
- package/engine/core/execute-build.ts +68 -944
- package/engine/core/execute-changeset.ts +5 -7
- package/engine/core/execute-final-review.ts +125 -13
- package/engine/core/execute-gates.ts +182 -0
- package/engine/core/execute-intake.ts +130 -0
- package/engine/core/execute-join.ts +276 -0
- package/engine/core/execute-memory.ts +12 -0
- package/engine/core/execute-pull-request.ts +84 -0
- package/engine/core/execute-red-check.ts +219 -0
- package/engine/core/execute-repo-wait.ts +129 -0
- package/engine/core/execute-stuck.ts +25 -10
- package/engine/core/execute-waits.ts +158 -0
- package/engine/core/execute-with-jev.ts +118 -0
- package/engine/core/execute.ts +124 -831
- package/engine/core/final-failure-cap.ts +38 -0
- package/engine/core/final-review-action.ts +125 -0
- package/engine/core/final-review-text.ts +63 -17
- package/engine/core/final-stuck-text.ts +86 -0
- package/engine/core/fix-loop-text.ts +49 -2
- package/engine/core/left-out.ts +120 -0
- package/engine/core/live-file.ts +372 -0
- package/engine/core/loop-caps.ts +25 -2
- package/engine/core/not-in-run.ts +7 -3
- package/engine/core/pull-request-text.ts +255 -6
- package/engine/core/repo-wait-text.ts +81 -0
- package/engine/core/review-text.ts +55 -1
- package/engine/core/run-crash-recovery-helpers.ts +16 -0
- package/engine/core/run-session-close-helpers.ts +96 -0
- package/engine/core/run-start.ts +148 -0
- package/engine/core/run-stuck-text.ts +86 -0
- package/engine/core/schedule-rules.ts +193 -0
- package/engine/core/stuck-detail-text.ts +89 -0
- package/engine/core/stuck-format.ts +22 -0
- package/engine/core/stuck-text.ts +29 -332
- package/engine/core/ticket-stuck-text.ts +192 -0
- package/engine/core/worktree-changes.ts +106 -0
- package/engine/gates/already-done-check.ts +120 -0
- package/engine/gates/feature-map.ts +96 -0
- package/engine/gates/gate-runner.ts +108 -108
- package/engine/gates/gate-schemas.ts +61 -2
- package/engine/gates/leftover-scan.ts +154 -31
- package/engine/gates/new-tests.ts +45 -0
- package/engine/gates/own-files-check.ts +98 -0
- package/engine/gates/prepare-check.ts +60 -0
- package/engine/gates/prepare-slots.ts +99 -0
- package/engine/gates/red-check.ts +184 -16
- package/engine/gates/shell-check.ts +64 -0
- package/engine/gates/slot-waits.ts +55 -0
- package/engine/gates/slow-test-runner.ts +59 -0
- package/engine/gates/test-checks.ts +161 -0
- package/engine/gates/test-runner.ts +164 -5
- package/engine/gates/test-slots.ts +48 -0
- package/engine/git/git-adapter.ts +55 -396
- package/engine/git/git-commits.ts +132 -0
- package/engine/git/git-join.ts +139 -0
- package/engine/git/git-read.ts +123 -0
- package/engine/git/git-run.ts +32 -0
- package/engine/git/git-worktrees.ts +143 -0
- package/engine/git/outside-links.ts +55 -0
- package/engine/guards/after-turn-check.ts +31 -5
- package/engine/guards/guard-hook.ts +60 -12
- package/engine/guards/guard-roles.ts +68 -0
- package/engine/guards/helper-rules.ts +92 -0
- package/engine/guards/permission-rules.ts +161 -0
- package/engine/guards/role-rules-helpers.ts +48 -0
- package/engine/guards/role-rules.ts +34 -606
- package/engine/guards/shell-rules.ts +344 -0
- package/engine/guards/worktree-git.ts +208 -0
- package/engine/guards/worktree-snapshot.ts +412 -0
- package/engine/guards/worktree-state.ts +28 -825
- package/engine/guards/worktree-undo.ts +260 -0
- package/engine/guards/write-rules.ts +149 -0
- package/engine/index.ts +30 -9
- package/engine/intake/criteria-checks.ts +114 -0
- package/engine/intake/intake-checks.ts +164 -30
- package/engine/intake/intake-schemas.ts +37 -2
- package/engine/jev/clef-client.ts +259 -0
- package/engine/jev/decision-model-credentials.ts +212 -0
- package/engine/jev/jev-jobs.ts +144 -60
- package/engine/jev/jev-schemas.ts +86 -5
- package/engine/jev/jev-shadow-helpers.ts +218 -0
- package/engine/jev/jev-shadow.ts +109 -64
- package/engine/jev/model-pick.ts +275 -0
- package/engine/journal/agent-entries.ts +167 -0
- package/engine/journal/agent-message-entries.ts +72 -0
- package/engine/journal/agent-turn-replay.ts +203 -0
- package/engine/journal/already-done-entries.ts +55 -0
- package/engine/journal/commit-entries.ts +56 -0
- package/engine/journal/cross-ticket-replay.ts +222 -0
- package/engine/journal/decision-model-entries.ts +86 -0
- package/engine/journal/entry-fields.ts +10 -0
- package/engine/journal/final-review-entries.ts +128 -0
- package/engine/journal/final-review-replay.ts +324 -0
- package/engine/journal/final-review-round.ts +320 -0
- package/engine/journal/final-review-state.ts +180 -0
- package/engine/journal/gate-entries.ts +81 -0
- package/engine/journal/intake-entries.ts +87 -0
- package/engine/journal/join-entries.ts +126 -0
- package/engine/journal/journal-entry-schema.ts +218 -0
- package/engine/journal/journal-kinds.ts +97 -0
- package/engine/journal/journal-record-schema.ts +218 -0
- package/engine/journal/journal-record.ts +43 -1400
- package/engine/journal/journal.ts +6 -1
- package/engine/journal/limit-entries.ts +90 -0
- package/engine/journal/memory-entries.ts +124 -0
- package/engine/journal/memory-replay.ts +157 -0
- package/engine/journal/plan-replay.ts +139 -0
- package/engine/journal/pull-request-entries.ts +41 -0
- package/engine/journal/replay.ts +157 -2144
- package/engine/journal/reply-replay.ts +144 -0
- package/engine/journal/repo-wait-entries.ts +53 -0
- package/engine/journal/run-entries.ts +172 -0
- package/engine/journal/run-state.ts +264 -0
- package/engine/journal/shared-failure-replay.ts +133 -0
- package/engine/journal/stuck-entries.ts +193 -0
- package/engine/journal/ticket-progress.ts +392 -0
- package/engine/journal/ticket-replay.ts +411 -0
- package/engine/journal/ticket-result-replay.ts +364 -0
- package/engine/journal/ticket-retry-replay.ts +142 -0
- package/engine/journal/worktree-entries.ts +122 -0
- package/engine/models/model-score.ts +512 -0
- package/engine/shell/run-command.ts +187 -18
- package/engine/testing/agent-turn-fixtures.ts +287 -0
- package/engine/testing/already-done-fixtures.ts +97 -0
- package/engine/testing/build-fixtures.ts +68 -973
- package/engine/testing/checkouts-fixtures.ts +48 -0
- package/engine/testing/final-review-fixtures.ts +62 -1
- package/engine/testing/final-review-steps.ts +143 -0
- package/engine/testing/limit-fixtures.ts +85 -0
- package/engine/testing/live-file-fixtures.ts +57 -0
- package/engine/testing/practice-repo.ts +10 -4
- package/engine/testing/practice-run.ts +1 -1
- package/engine/testing/reply-fixtures.ts +88 -0
- package/engine/testing/run-budget-fixtures.ts +165 -0
- package/engine/testing/run-fixtures.ts +219 -0
- package/engine/testing/sdk-play.ts +177 -0
- package/engine/testing/setup-repo.ts +194 -0
- package/engine/testing/step-record-fixtures.ts +55 -0
- package/engine/testing/ticket-step-fixtures.ts +272 -0
- package/engine/testing/wait-scenarios.ts +186 -0
- package/engine/tracker/gh-retry.ts +217 -0
- package/engine/tracker/github-tracker.ts +310 -90
- package/engine/tracker/in-memory-tracker.ts +8 -4
- package/engine/tracker/tracker.ts +131 -6
- package/package.json +2 -1
- package/skills/luca-retro/SKILL.md +74 -0
- package/skills/luca-retro/scripts/retro-summary.ts +1356 -0
- package/skills/luca-unstick/SKILL.md +153 -0
- package/skills/luca-unstick/scripts/stuck-summary.ts +1063 -0
- package/engine/jev/jev-client.ts +0 -173
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where an agent's answer goes in its ticket's progress: a finished agent's
|
|
3
|
+
* result (fix rounds, bad tests, ticket reviews), the test setup change it
|
|
4
|
+
* asked for, and the engine's check of `already_done` evidence.
|
|
5
|
+
*/
|
|
6
|
+
import {
|
|
7
|
+
badTestOf,
|
|
8
|
+
declinedBy,
|
|
9
|
+
fixerAnswered,
|
|
10
|
+
handoffAnswered,
|
|
11
|
+
handoffRole,
|
|
12
|
+
ranCheaper,
|
|
13
|
+
type FinishedContent,
|
|
14
|
+
} from './agent-turn-replay'
|
|
15
|
+
import type { JournalRecord } from './journal-record'
|
|
16
|
+
import type { TicketProgress } from './ticket-progress'
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
isBlocking,
|
|
20
|
+
type AgentRole,
|
|
21
|
+
type BadTestSource,
|
|
22
|
+
type TicketReviewResult,
|
|
23
|
+
} from '../agents/role-results'
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A failed try for `role` on its ticket: one more of its tries used up,
|
|
27
|
+
* and, if its agent ran on a model cheaper than Opus, its later fresh
|
|
28
|
+
* agents on the ticket step up to Opus (#604). Engine failures are no try.
|
|
29
|
+
*/
|
|
30
|
+
export const failedTryChange = ({
|
|
31
|
+
progress,
|
|
32
|
+
role,
|
|
33
|
+
}: {
|
|
34
|
+
progress: TicketProgress
|
|
35
|
+
role: AgentRole
|
|
36
|
+
}): Pick<TicketProgress, 'failed_tries' | 'failed_cheaper'> => ({
|
|
37
|
+
failed_tries: {
|
|
38
|
+
...progress.failed_tries,
|
|
39
|
+
[role]: (progress.failed_tries[role] ?? 0) + 1,
|
|
40
|
+
},
|
|
41
|
+
failed_cheaper:
|
|
42
|
+
ranCheaper(progress.launched_on[role]) &&
|
|
43
|
+
!progress.failed_cheaper.includes(role)
|
|
44
|
+
? [...progress.failed_cheaper, role]
|
|
45
|
+
: progress.failed_cheaper,
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The bounce sources once `by` sends one more test back as bad (#581), each
|
|
50
|
+
* kept in order so a stuck detail can name who sent the first and who the
|
|
51
|
+
* second. They go together with `bad_test_bounces`.
|
|
52
|
+
*/
|
|
53
|
+
export const bouncedBy = ({
|
|
54
|
+
progress,
|
|
55
|
+
by,
|
|
56
|
+
}: {
|
|
57
|
+
progress: TicketProgress
|
|
58
|
+
by: BadTestSource
|
|
59
|
+
}): BadTestSource[] => [...progress.bad_test_sources, by]
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Where a finished agent's result goes in its ticket's progress. A result
|
|
63
|
+
* that answers a fix-loop follow-up counts a round and clears the failed
|
|
64
|
+
* check, so it runs again.
|
|
65
|
+
*/
|
|
66
|
+
export const resultChange = ({
|
|
67
|
+
progress,
|
|
68
|
+
finished,
|
|
69
|
+
seq,
|
|
70
|
+
}: {
|
|
71
|
+
progress: TicketProgress
|
|
72
|
+
finished: FinishedContent
|
|
73
|
+
seq: number
|
|
74
|
+
}): Partial<TicketProgress> => {
|
|
75
|
+
const fix = progress.review_fix
|
|
76
|
+
const { rejoin, test_update } = progress
|
|
77
|
+
switch (finished.role) {
|
|
78
|
+
case 'test-writer':
|
|
79
|
+
// The test-writer's answer to a test update after a rebase: the
|
|
80
|
+
// red check stands, as for clashed tests (#489).
|
|
81
|
+
if (test_update !== null && test_update.result === null) {
|
|
82
|
+
return {
|
|
83
|
+
test_update: { ...test_update, result: finished.result },
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// The fresh test-writer after a rebase fixed the clashed tests:
|
|
87
|
+
// no fix round, and the red check stands.
|
|
88
|
+
if (rejoin?.tests_pending) {
|
|
89
|
+
return { rejoin: { ...rejoin, tests_pending: false } }
|
|
90
|
+
}
|
|
91
|
+
if (fix !== null && !fix.tests_answered) {
|
|
92
|
+
return {
|
|
93
|
+
review_fix: {
|
|
94
|
+
...fix,
|
|
95
|
+
tests_answered: true,
|
|
96
|
+
...fixerAnswered({
|
|
97
|
+
fix,
|
|
98
|
+
role: 'test-writer',
|
|
99
|
+
responses: finished.result.finding_responses,
|
|
100
|
+
}),
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (fix !== null && handoffRole({ fix }) === 'test-writer') {
|
|
105
|
+
return {
|
|
106
|
+
review_fix: {
|
|
107
|
+
...fix,
|
|
108
|
+
...handoffAnswered({
|
|
109
|
+
fix,
|
|
110
|
+
role: 'test-writer',
|
|
111
|
+
responses: finished.result.finding_responses,
|
|
112
|
+
}),
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// An `environment` answer to a failed red check reruns it with
|
|
117
|
+
// the earlier tests, using no fix round (#613).
|
|
118
|
+
if (
|
|
119
|
+
finished.result.outcome === 'environment' &&
|
|
120
|
+
progress.red_check !== null &&
|
|
121
|
+
!progress.red_check.ok
|
|
122
|
+
) {
|
|
123
|
+
return {
|
|
124
|
+
red_check: null,
|
|
125
|
+
environment_reruns: progress.environment_reruns + 1,
|
|
126
|
+
environment: {
|
|
127
|
+
role: 'test-writer',
|
|
128
|
+
evidence: finished.result.environment?.evidence ?? '',
|
|
129
|
+
check: 'red_check',
|
|
130
|
+
failed: progress.red_check,
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// A new answer is checked afresh if it is `already_done` (#495).
|
|
135
|
+
return progress.red_check === null
|
|
136
|
+
? { test_writer: finished.result, already_done_check: null }
|
|
137
|
+
: {
|
|
138
|
+
test_writer: finished.result,
|
|
139
|
+
already_done_check: null,
|
|
140
|
+
red_check: null,
|
|
141
|
+
red_fix_rounds: progress.red_fix_rounds + 1,
|
|
142
|
+
}
|
|
143
|
+
case 'implementer': {
|
|
144
|
+
const { result } = finished
|
|
145
|
+
const bad_test = badTestOf(result)
|
|
146
|
+
// Its answer after the test-writer updated the tests closes the
|
|
147
|
+
// update; a done answer settles the bad test (#489).
|
|
148
|
+
if (test_update !== null && test_update.result !== null) {
|
|
149
|
+
return {
|
|
150
|
+
implementer: result,
|
|
151
|
+
test_update: null,
|
|
152
|
+
...(bad_test === null
|
|
153
|
+
? { bad_test: null, bad_test_source: null }
|
|
154
|
+
: {
|
|
155
|
+
bad_test,
|
|
156
|
+
bad_test_source: 'implementer',
|
|
157
|
+
bad_test_sources: bouncedBy({
|
|
158
|
+
progress,
|
|
159
|
+
by: 'implementer',
|
|
160
|
+
}),
|
|
161
|
+
bad_test_bounces: progress.bad_test_bounces + 1,
|
|
162
|
+
}),
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// The implementer's answer to the clash message is no fix round.
|
|
166
|
+
// A bad test is kept, for the test update or the stuck text.
|
|
167
|
+
if (rejoin?.code_pending) {
|
|
168
|
+
return {
|
|
169
|
+
implementer: result,
|
|
170
|
+
rejoin: { ...rejoin, code_pending: false },
|
|
171
|
+
...(bad_test === null
|
|
172
|
+
? {}
|
|
173
|
+
: {
|
|
174
|
+
bad_test,
|
|
175
|
+
bad_test_source: 'implementer',
|
|
176
|
+
bad_test_sources: bouncedBy({
|
|
177
|
+
progress,
|
|
178
|
+
by: 'implementer',
|
|
179
|
+
}),
|
|
180
|
+
bad_test_bounces: progress.bad_test_bounces + 1,
|
|
181
|
+
}),
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (fix !== null && fix.tests_answered && !fix.code_answered) {
|
|
185
|
+
return {
|
|
186
|
+
review_fix: {
|
|
187
|
+
...fix,
|
|
188
|
+
code_answered: true,
|
|
189
|
+
...fixerAnswered({
|
|
190
|
+
fix,
|
|
191
|
+
role: 'implementer',
|
|
192
|
+
responses: result.finding_responses,
|
|
193
|
+
}),
|
|
194
|
+
bad_test,
|
|
195
|
+
},
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (fix !== null && handoffRole({ fix }) === 'implementer') {
|
|
199
|
+
return {
|
|
200
|
+
review_fix: {
|
|
201
|
+
...fix,
|
|
202
|
+
...handoffAnswered({
|
|
203
|
+
fix,
|
|
204
|
+
role: 'implementer',
|
|
205
|
+
responses: result.finding_responses,
|
|
206
|
+
}),
|
|
207
|
+
bad_test,
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// An `environment` answer to failed gates reruns them, using no
|
|
212
|
+
// fix round (#613).
|
|
213
|
+
if (
|
|
214
|
+
result.outcome === 'environment' &&
|
|
215
|
+
progress.gates !== null &&
|
|
216
|
+
!progress.gates.ok
|
|
217
|
+
) {
|
|
218
|
+
return {
|
|
219
|
+
gates: null,
|
|
220
|
+
environment_reruns: progress.environment_reruns + 1,
|
|
221
|
+
environment: {
|
|
222
|
+
role: 'implementer',
|
|
223
|
+
evidence: result.environment?.evidence ?? '',
|
|
224
|
+
check: 'gates',
|
|
225
|
+
failed: progress.gates,
|
|
226
|
+
},
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const bounce: Partial<TicketProgress> =
|
|
230
|
+
bad_test === null
|
|
231
|
+
? {}
|
|
232
|
+
: {
|
|
233
|
+
bad_test_bounces: progress.bad_test_bounces + 1,
|
|
234
|
+
bad_test,
|
|
235
|
+
bad_test_source: 'implementer',
|
|
236
|
+
bad_test_sources: bouncedBy({
|
|
237
|
+
progress,
|
|
238
|
+
by: 'implementer',
|
|
239
|
+
}),
|
|
240
|
+
}
|
|
241
|
+
const round: Partial<TicketProgress> =
|
|
242
|
+
progress.gates === null
|
|
243
|
+
? {}
|
|
244
|
+
: {
|
|
245
|
+
gates: null,
|
|
246
|
+
gate_fix_rounds: progress.gate_fix_rounds + 1,
|
|
247
|
+
}
|
|
248
|
+
return { implementer: result, ...round, ...bounce }
|
|
249
|
+
}
|
|
250
|
+
case 'ticket-reviewer':
|
|
251
|
+
return reviewChange({ progress, review: finished.result, seq })
|
|
252
|
+
// Lenses review the run branch, never a ticket.
|
|
253
|
+
default:
|
|
254
|
+
return {}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* A finished ticket review: counts the round, settles the last round's
|
|
260
|
+
* "won't fix" answers, keeps its nits, and opens a fix round when a finding
|
|
261
|
+
* is a blocker or a should-fix. A new fix round starts its gates, gate fix
|
|
262
|
+
* rounds, and fix commit afresh.
|
|
263
|
+
*/
|
|
264
|
+
const reviewChange = ({
|
|
265
|
+
progress,
|
|
266
|
+
review,
|
|
267
|
+
seq,
|
|
268
|
+
}: {
|
|
269
|
+
progress: TicketProgress
|
|
270
|
+
review: TicketReviewResult
|
|
271
|
+
/** The review's record, for the join queue's order once it approves. */
|
|
272
|
+
seq: number
|
|
273
|
+
}): Partial<TicketProgress> => {
|
|
274
|
+
const review_rounds = progress.review_rounds + 1
|
|
275
|
+
const blocking = review.findings.filter(isBlocking)
|
|
276
|
+
const newNits = review.findings.filter(
|
|
277
|
+
(finding) =>
|
|
278
|
+
!isBlocking(finding) &&
|
|
279
|
+
!progress.nits.some(({ id }) => id === finding.id)
|
|
280
|
+
)
|
|
281
|
+
const settled: Partial<TicketProgress> = {
|
|
282
|
+
review,
|
|
283
|
+
review_rounds,
|
|
284
|
+
reviewed_sha: progress.commits.fix ?? progress.commits.green,
|
|
285
|
+
nits: [...progress.nits, ...newNits],
|
|
286
|
+
declined: [
|
|
287
|
+
...progress.declined,
|
|
288
|
+
...declinedBy({ fix: progress.review_fix, review }),
|
|
289
|
+
],
|
|
290
|
+
}
|
|
291
|
+
if (blocking.length === 0) {
|
|
292
|
+
return { ...settled, review_fix: null, approved_seq: seq }
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
...settled,
|
|
296
|
+
approved_seq: null,
|
|
297
|
+
review_fix: {
|
|
298
|
+
round: review_rounds,
|
|
299
|
+
findings: blocking,
|
|
300
|
+
tests_answered: !blocking.some(({ kind }) => kind === 'test'),
|
|
301
|
+
code_answered: !blocking.some(({ kind }) => kind === 'code'),
|
|
302
|
+
responses: [],
|
|
303
|
+
handed_off: {},
|
|
304
|
+
bad_test: null,
|
|
305
|
+
},
|
|
306
|
+
gates: null,
|
|
307
|
+
gate_fix_rounds: 0,
|
|
308
|
+
leftovers: { ...progress.leftovers, fix: null },
|
|
309
|
+
commits: { ...progress.commits, fix: null },
|
|
310
|
+
commit_files: { ...progress.commit_files, fix: [] },
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** The test setup change an agent asked for in its result, if any. */
|
|
315
|
+
export const setupChangeOf = ({
|
|
316
|
+
finished,
|
|
317
|
+
}: {
|
|
318
|
+
finished: FinishedContent
|
|
319
|
+
}): TicketProgress['setup_change'] => {
|
|
320
|
+
if (finished.role !== 'test-writer' && finished.role !== 'implementer') {
|
|
321
|
+
return null
|
|
322
|
+
}
|
|
323
|
+
const { outcome, setup_change } = finished.result
|
|
324
|
+
if (outcome !== 'needs_setup_change') return null
|
|
325
|
+
return {
|
|
326
|
+
role: finished.role,
|
|
327
|
+
file: setup_change?.file ?? '',
|
|
328
|
+
reason: setup_change?.reason ?? finished.result.summary,
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
type AlreadyDoneCheckedContent = Extract<
|
|
333
|
+
JournalRecord,
|
|
334
|
+
{ kind: 'already_done_checked' }
|
|
335
|
+
>['content']
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* The engine's check of a test-writer's `already_done` evidence (#495). A
|
|
339
|
+
* failed one is a failed try for the test-writer, in the session that gave
|
|
340
|
+
* the evidence, as if its turn had failed: the decision step sends it what
|
|
341
|
+
* did not check out, or makes the ticket stuck once its tries run out.
|
|
342
|
+
*/
|
|
343
|
+
export const alreadyDoneCheckedChange = ({
|
|
344
|
+
progress,
|
|
345
|
+
checked,
|
|
346
|
+
}: {
|
|
347
|
+
progress: TicketProgress
|
|
348
|
+
checked: AlreadyDoneCheckedContent
|
|
349
|
+
}): Partial<TicketProgress> => {
|
|
350
|
+
const { ok, problems } = checked
|
|
351
|
+
if (ok) return { already_done_check: { ok, problems } }
|
|
352
|
+
const role = 'test-writer'
|
|
353
|
+
return {
|
|
354
|
+
already_done_check: { ok, problems },
|
|
355
|
+
agent_failure: {
|
|
356
|
+
role,
|
|
357
|
+
error: problems.map((problem) => `- ${problem}`).join('\n'),
|
|
358
|
+
failure: 'evidence',
|
|
359
|
+
session_id: progress.sessions[role] ?? null,
|
|
360
|
+
},
|
|
361
|
+
engine_failures: 0,
|
|
362
|
+
...failedTryChange({ progress, role }),
|
|
363
|
+
}
|
|
364
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A stuck ticket's `retry` in replay: refused, restarted from scratch, or
|
|
3
|
+
* resumed where it stopped with a fresh agent and fresh counts.
|
|
4
|
+
*/
|
|
5
|
+
import type { JournalRecord } from './journal-record'
|
|
6
|
+
import { EMPTY_TICKET_PROGRESS, type TicketProgress } from './ticket-progress'
|
|
7
|
+
|
|
8
|
+
type RetriedContent = Extract<
|
|
9
|
+
JournalRecord,
|
|
10
|
+
{ kind: 'ticket_retried' }
|
|
11
|
+
>['content']
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A `retry` of a stuck ticket. `refused` leaves it stuck, waiting for the
|
|
15
|
+
* next reply. `restart` starts it over from scratch (its new snapshot was
|
|
16
|
+
* journaled just before), in its worktree reset to the run branch's tip.
|
|
17
|
+
* `resume` picks up where it stopped (see `resumedProgress`).
|
|
18
|
+
*/
|
|
19
|
+
export const retriedChange = ({
|
|
20
|
+
progress,
|
|
21
|
+
retried,
|
|
22
|
+
}: {
|
|
23
|
+
progress: TicketProgress
|
|
24
|
+
retried: RetriedContent
|
|
25
|
+
}): Partial<TicketProgress> => {
|
|
26
|
+
switch (retried.mode) {
|
|
27
|
+
case 'refused':
|
|
28
|
+
return { reply: null }
|
|
29
|
+
case 'restart':
|
|
30
|
+
return {
|
|
31
|
+
...EMPTY_TICKET_PROGRESS,
|
|
32
|
+
worktree:
|
|
33
|
+
progress.worktree === null || retried.base_sha === null
|
|
34
|
+
? progress.worktree
|
|
35
|
+
: { ...progress.worktree, base_sha: retried.base_sha },
|
|
36
|
+
}
|
|
37
|
+
case 'resume':
|
|
38
|
+
return resumedProgress({ progress })
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A stuck ticket resumed by `retry`: it picks up where it stopped, with a
|
|
44
|
+
* fresh agent (no session is kept) and fresh counts (fix rounds, failed
|
|
45
|
+
* tries, bad-test bounces, environment reruns, rebases, test updates), and keeps whatever the
|
|
46
|
+
* user changed in its worktree. An open test update is dropped. The step that got stuck runs again:
|
|
47
|
+
* - before the red commit, a fresh test-writer writes the tests;
|
|
48
|
+
* - before the green commit, a fresh implementer builds (on top of the run
|
|
49
|
+
* branch after a rebase), then the gates;
|
|
50
|
+
* - in a review fix round, the round starts over as round 1 with fresh
|
|
51
|
+
* fixers, so the user's changes are gated, committed, and re-reviewed;
|
|
52
|
+
* - a leftover scan, a failed install, a failed prepare command at the
|
|
53
|
+
* baseline, a reviewer's failed tries, a failed join, a refused undo of
|
|
54
|
+
* its join (#519), or a step crashes cut off just run again.
|
|
55
|
+
*/
|
|
56
|
+
const resumedProgress = ({
|
|
57
|
+
progress,
|
|
58
|
+
}: {
|
|
59
|
+
progress: TicketProgress
|
|
60
|
+
}): Partial<TicketProgress> => {
|
|
61
|
+
const { stuck, commits, review_fix, rejoin } = progress
|
|
62
|
+
const base: Partial<TicketProgress> = {
|
|
63
|
+
stuck: null,
|
|
64
|
+
stuck_report: null,
|
|
65
|
+
reply: null,
|
|
66
|
+
retried: stuck,
|
|
67
|
+
setup_change: null,
|
|
68
|
+
agent_failure: null,
|
|
69
|
+
failed_tries: {},
|
|
70
|
+
engine_failures: 0,
|
|
71
|
+
sessions: {},
|
|
72
|
+
red_fix_rounds: 0,
|
|
73
|
+
gate_fix_rounds: 0,
|
|
74
|
+
environment_reruns: 0,
|
|
75
|
+
environment: null,
|
|
76
|
+
bad_test_bounces: 0,
|
|
77
|
+
bad_test_sources: [],
|
|
78
|
+
rejoins: 0,
|
|
79
|
+
test_updates: 0,
|
|
80
|
+
test_update: null,
|
|
81
|
+
install:
|
|
82
|
+
progress.install?.check?.ok === false ? null : progress.install,
|
|
83
|
+
prepare: progress.prepare?.ok === false ? null : progress.prepare,
|
|
84
|
+
leftovers: {
|
|
85
|
+
red: commits.red === null ? null : progress.leftovers.red,
|
|
86
|
+
green: commits.green === null ? null : progress.leftovers.green,
|
|
87
|
+
fix: commits.fix === null ? null : progress.leftovers.fix,
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
const reason = stuck?.reason
|
|
91
|
+
const reviewerFailed = progress.agent_failure?.role === 'ticket-reviewer'
|
|
92
|
+
if (
|
|
93
|
+
reason === 'leftovers_found' ||
|
|
94
|
+
reason === 'install_failed' ||
|
|
95
|
+
reason === 'prepare_failed' ||
|
|
96
|
+
reason === 'join_failed' ||
|
|
97
|
+
reason === 'join_gates_failed' ||
|
|
98
|
+
reason === 'undo_refused' ||
|
|
99
|
+
reason === 'crashed' ||
|
|
100
|
+
reviewerFailed
|
|
101
|
+
) {
|
|
102
|
+
return base
|
|
103
|
+
}
|
|
104
|
+
if (commits.green === null) {
|
|
105
|
+
if (
|
|
106
|
+
rejoin === null &&
|
|
107
|
+
commits.red === null &&
|
|
108
|
+
progress.test_writer !== null
|
|
109
|
+
) {
|
|
110
|
+
return {
|
|
111
|
+
...base,
|
|
112
|
+
test_writer: null,
|
|
113
|
+
red_check: null,
|
|
114
|
+
red_tests: [],
|
|
115
|
+
already_done_check: null,
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return { ...base, implementer: null, gates: null }
|
|
119
|
+
}
|
|
120
|
+
if (review_fix === null) return base
|
|
121
|
+
return {
|
|
122
|
+
...base,
|
|
123
|
+
review_rounds: 1,
|
|
124
|
+
review_fix: {
|
|
125
|
+
...review_fix,
|
|
126
|
+
round: 1,
|
|
127
|
+
tests_answered: !review_fix.findings.some(
|
|
128
|
+
({ kind }) => kind === 'test'
|
|
129
|
+
),
|
|
130
|
+
code_answered: !review_fix.findings.some(
|
|
131
|
+
({ kind }) => kind === 'code'
|
|
132
|
+
),
|
|
133
|
+
responses: [],
|
|
134
|
+
handed_off: {},
|
|
135
|
+
bad_test: null,
|
|
136
|
+
},
|
|
137
|
+
gates: null,
|
|
138
|
+
leftovers: { ...base.leftovers!, fix: null },
|
|
139
|
+
commits: { ...commits, fix: null },
|
|
140
|
+
commit_files: { ...progress.commit_files, fix: [] },
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { ENTRY_FIELDS } from './entry-fields'
|
|
4
|
+
|
|
5
|
+
import { BadTestSchema } from '../agents/role-results'
|
|
6
|
+
import { GateCheckSchema, TestRunSchema } from '../gates/gate-schemas'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The journal entries of the run's worktrees: made, prepared, their
|
|
10
|
+
* baseline tests, reset, and removed.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** A git worktree the engine made: where, on which branch, from which commit. */
|
|
14
|
+
const WorktreeSchema = z.object({
|
|
15
|
+
branch: z.string().min(1),
|
|
16
|
+
path: z.string().min(1),
|
|
17
|
+
base_sha: z.string().min(1),
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The run branch's worktree. `changesets` is true when the repo had
|
|
22
|
+
* `.changeset/config.json` there, so the engine writes a changeset before
|
|
23
|
+
* the PR (#461).
|
|
24
|
+
*/
|
|
25
|
+
export const RunBranchCreatedEntrySchema = z.object({
|
|
26
|
+
...ENTRY_FIELDS,
|
|
27
|
+
kind: z.literal('run_branch_created'),
|
|
28
|
+
content: WorktreeSchema.extend({
|
|
29
|
+
changesets: z.boolean().default(false),
|
|
30
|
+
}),
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
export const TicketWorktreeCreatedEntrySchema = z.object({
|
|
34
|
+
...ENTRY_FIELDS,
|
|
35
|
+
kind: z.literal('ticket_worktree_created'),
|
|
36
|
+
content: WorktreeSchema,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The config's prepare command (#481), run in a new ticket worktree before
|
|
41
|
+
* its baseline tests. Journaled only with a prepare command. A failed one
|
|
42
|
+
* leaves the baseline tests unrun.
|
|
43
|
+
*/
|
|
44
|
+
export const BaselinePreparedEntrySchema = z.object({
|
|
45
|
+
...ENTRY_FIELDS,
|
|
46
|
+
kind: z.literal('baseline_prepared'),
|
|
47
|
+
content: z.object({ check: GateCheckSchema }),
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* New untracked paths a run of the config's prepare command made in a
|
|
52
|
+
* checkout (#486): there after it ran, not before, such as a symlinked
|
|
53
|
+
* tools folder or a build file the repo's `.gitignore` misses. They are not
|
|
54
|
+
* an agent's work, so the engine never commits them or judges them by role
|
|
55
|
+
* rules, in any checkout of the run. Journaled right after the prepare run
|
|
56
|
+
* (at the baseline, the red check, or the gates), only when it made any.
|
|
57
|
+
* `ticket` is the step's, as on its `gates_run`: `null` in the final review.
|
|
58
|
+
*
|
|
59
|
+
* With `outside_links`, the paths are untracked symlinks pointing outside
|
|
60
|
+
* their checkout, found just before a commit rather than around a prepare
|
|
61
|
+
* run (#496): most likely a prepare run's from before the engine noted what
|
|
62
|
+
* prepare made (an older engine's run, resumed). No commit may hold such a
|
|
63
|
+
* link, so the engine leaves them out the same way.
|
|
64
|
+
*/
|
|
65
|
+
export const PrepareMadeEntrySchema = z.object({
|
|
66
|
+
...ENTRY_FIELDS,
|
|
67
|
+
kind: z.literal('prepare_made'),
|
|
68
|
+
content: z.object({
|
|
69
|
+
/** Worktree-relative, as git lists them (`git ls-files --others`). */
|
|
70
|
+
paths: z.array(z.string()),
|
|
71
|
+
/** `true` when found as outside-pointing links before a commit. */
|
|
72
|
+
outside_links: z.boolean().optional(),
|
|
73
|
+
}),
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
/** The tests as they stood before any agent worked on a ticket. */
|
|
77
|
+
export const BaselineTestsEntrySchema = z.object({
|
|
78
|
+
...ENTRY_FIELDS,
|
|
79
|
+
kind: z.literal('baseline_tests'),
|
|
80
|
+
content: TestRunSchema,
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* A ticket took another ticket's baseline instead of running the tests
|
|
85
|
+
* again: both worktrees started from the same run-branch commit, `base_sha`.
|
|
86
|
+
*/
|
|
87
|
+
export const BaselineReusedEntrySchema = z.object({
|
|
88
|
+
...ENTRY_FIELDS,
|
|
89
|
+
kind: z.literal('baseline_reused'),
|
|
90
|
+
content: z.object({
|
|
91
|
+
from_ticket: z.number().int().positive(),
|
|
92
|
+
base_sha: z.string().min(1),
|
|
93
|
+
}),
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* The engine threw away every uncommitted change in a ticket's worktree, back
|
|
98
|
+
* to `sha`, so a fresh test-writer starts clean after a bad test.
|
|
99
|
+
*/
|
|
100
|
+
export const WorktreeResetEntrySchema = z.object({
|
|
101
|
+
...ENTRY_FIELDS,
|
|
102
|
+
kind: z.literal('worktree_reset'),
|
|
103
|
+
content: z.object({
|
|
104
|
+
sha: z.string().min(1),
|
|
105
|
+
/**
|
|
106
|
+
* The engine found this mapped test checks nothing (#581); a fresh
|
|
107
|
+
* test-writer replaces it. Left out when the implementer sent a test
|
|
108
|
+
* back.
|
|
109
|
+
*/
|
|
110
|
+
bad_test: BadTestSchema.optional(),
|
|
111
|
+
}),
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The engine removed these git worktrees at the end of a run. Their branches
|
|
116
|
+
* and the journal are kept.
|
|
117
|
+
*/
|
|
118
|
+
export const WorktreesRemovedEntrySchema = z.object({
|
|
119
|
+
...ENTRY_FIELDS,
|
|
120
|
+
kind: z.literal('worktrees_removed'),
|
|
121
|
+
content: z.object({ paths: z.array(z.string().min(1)) }),
|
|
122
|
+
})
|