@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
|
@@ -1,387 +1,25 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
|
|
3
|
+
import { ENGINE_VOCABULARY } from './board-vocabulary-engine'
|
|
4
|
+
import { REVIEW_VOCABULARY } from './board-vocabulary-review'
|
|
5
|
+
import { RUN_VOCABULARY } from './board-vocabulary-run'
|
|
6
|
+
|
|
7
|
+
export type { LeftOutList } from './board-vocabulary-shapes'
|
|
8
|
+
|
|
3
9
|
/**
|
|
4
10
|
* The board's vocabulary: every journal kind the board reads, and the few
|
|
5
11
|
* fields it reads from each. Schemas are loose on purpose, so the engine can
|
|
6
12
|
* add fields without breaking the board, and the plugin never needs the
|
|
7
13
|
* engine's code. A record whose content doesn't fit is skipped and logged.
|
|
14
|
+
*
|
|
15
|
+
* The kinds are in three modules (`board-vocabulary-run.ts`,
|
|
16
|
+
* `board-vocabulary-engine.ts`, `board-vocabulary-review.ts`) and the pieces
|
|
17
|
+
* they share in `board-vocabulary-shapes.ts`.
|
|
8
18
|
*/
|
|
9
|
-
|
|
10
|
-
const FindingCountsSchema = z.looseObject({
|
|
11
|
-
blocker: z.number().int().min(0).catch(0),
|
|
12
|
-
should_fix: z.number().int().min(0).catch(0),
|
|
13
|
-
nit: z.number().int().min(0).catch(0),
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
const FindingListSchema = z.array(
|
|
17
|
-
z.looseObject({
|
|
18
|
-
id: z.string().catch(''),
|
|
19
|
-
severity: z.enum(['blocker', 'should_fix', 'nit']),
|
|
20
|
-
})
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
/** A re-reviewer's ruling on a fixer's "won't fix" of a review finding. */
|
|
24
|
-
const RulingListSchema = z
|
|
25
|
-
.array(
|
|
26
|
-
z.looseObject({
|
|
27
|
-
finding_id: z.string(),
|
|
28
|
-
ruling: z.enum(['accepted', 'rejected']),
|
|
29
|
-
reason: z.string().catch(''),
|
|
30
|
-
})
|
|
31
|
-
)
|
|
32
|
-
.catch([])
|
|
33
|
-
|
|
34
|
-
/** A review fixer's answer to each finding: `fixed` or `wont_fix`. */
|
|
35
|
-
const FindingResponseListSchema = z
|
|
36
|
-
.array(
|
|
37
|
-
z.looseObject({
|
|
38
|
-
finding_id: z.string(),
|
|
39
|
-
response: z.enum(['fixed', 'wont_fix']),
|
|
40
|
-
reason: z.string().catch(''),
|
|
41
|
-
})
|
|
42
|
-
)
|
|
43
|
-
.catch([])
|
|
44
|
-
|
|
45
|
-
const TestRunSchema = z.looseObject({
|
|
46
|
-
cases: z.array(z.looseObject({ status: z.string() })),
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
const WorktreeSchema = z.looseObject({ branch: z.string() })
|
|
50
|
-
|
|
51
|
-
const tokenCount = z.number().min(0).catch(0)
|
|
52
|
-
|
|
53
|
-
/** One plan window's reading: `utilization` 0 to 1, `resetsAt` in seconds. */
|
|
54
|
-
const WindowReadingSchema = z.looseObject({
|
|
55
|
-
utilization: z.number().optional().catch(undefined),
|
|
56
|
-
resetsAt: z.number().optional().catch(undefined),
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* One `rate_limit_event`'s info, as the Claude Agent SDK sends it:
|
|
61
|
-
* `utilization` is 0 to 1, `resetsAt` is in seconds since the epoch. Real
|
|
62
|
-
* readings carry no top-level `utilization`; each window's is in
|
|
63
|
-
* `unifiedWindows`, keyed by window name (`five_hour`, `seven_day`, ...).
|
|
64
|
-
*/
|
|
65
|
-
const RateLimitReadingSchema = z.looseObject({
|
|
66
|
-
rateLimitType: z.string().optional().catch(undefined),
|
|
67
|
-
utilization: z.number().optional().catch(undefined),
|
|
68
|
-
resetsAt: z.number().optional().catch(undefined),
|
|
69
|
-
unifiedWindows: z
|
|
70
|
-
.record(z.string(), WindowReadingSchema.catch({}))
|
|
71
|
-
.optional()
|
|
72
|
-
.catch(undefined),
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
const TokensSchema = z
|
|
76
|
-
.looseObject({
|
|
77
|
-
input_tokens: tokenCount,
|
|
78
|
-
output_tokens: tokenCount,
|
|
79
|
-
cache_read_input_tokens: tokenCount,
|
|
80
|
-
cache_creation_input_tokens: tokenCount,
|
|
81
|
-
})
|
|
82
|
-
.catch({
|
|
83
|
-
input_tokens: 0,
|
|
84
|
-
output_tokens: 0,
|
|
85
|
-
cache_read_input_tokens: 0,
|
|
86
|
-
cache_creation_input_tokens: 0,
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
/** The launcher's summary of an agent's session: tokens and readings. */
|
|
90
|
-
const AgentSessionSchema = z.looseObject({
|
|
91
|
-
/** The main loop's tokens. */
|
|
92
|
-
usage: TokensSchema,
|
|
93
|
-
/** The turn's tokens per model, subagents included; older journals have none. */
|
|
94
|
-
model_usage: z.record(z.string(), TokensSchema).catch({}).default({}),
|
|
95
|
-
rate_limit_events: z.array(RateLimitReadingSchema).catch([]),
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
const JevJobSchema = z.looseObject({ job: z.string() })
|
|
99
|
-
|
|
100
19
|
export const BOARD_VOCABULARY = {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
config: z
|
|
105
|
-
.looseObject({
|
|
106
|
-
run_budget_tokens: z
|
|
107
|
-
.number()
|
|
108
|
-
.int()
|
|
109
|
-
.positive()
|
|
110
|
-
.optional()
|
|
111
|
-
.catch(undefined),
|
|
112
|
-
})
|
|
113
|
-
.optional()
|
|
114
|
-
.catch(undefined),
|
|
115
|
-
/** Luca's version the run started on (#460); older journals have none. */
|
|
116
|
-
luca_version: z.string().nullable().catch(null),
|
|
117
|
-
}),
|
|
118
|
-
/** The engine started again on the run's journal, on Luca's `luca_version`. */
|
|
119
|
-
engine_resumed: z.looseObject({ luca_version: z.string() }),
|
|
120
|
-
intake_read: z.looseObject({
|
|
121
|
-
spec: z.looseObject({ number: z.number(), title: z.string() }),
|
|
122
|
-
}),
|
|
123
|
-
intake_refused: z.looseObject({
|
|
124
|
-
problems: z.array(
|
|
125
|
-
z.looseObject({
|
|
126
|
-
ticket: z.number().nullable(),
|
|
127
|
-
missing: z.array(z.string()),
|
|
128
|
-
})
|
|
129
|
-
),
|
|
130
|
-
}),
|
|
131
|
-
/** The run ends with nothing to do; `already_done` is empty at intake (#484). */
|
|
132
|
-
nothing_to_do: z.looseObject({
|
|
133
|
-
already_done: z.array(z.number().int()).catch([]).default([]),
|
|
134
|
-
}),
|
|
135
|
-
spec_snapshot: z.looseObject({
|
|
136
|
-
spec: z.looseObject({ number: z.number(), title: z.string() }),
|
|
137
|
-
ticket_order: z.array(z.number()).catch([]),
|
|
138
|
-
}),
|
|
139
|
-
ticket_snapshot: z.looseObject({
|
|
140
|
-
number: z.number().int(),
|
|
141
|
-
title: z.string(),
|
|
142
|
-
labels: z.array(z.string()).catch([]),
|
|
143
|
-
blockers: z.array(z.number().int()).catch([]),
|
|
144
|
-
}),
|
|
145
|
-
run_branch_created: WorktreeSchema,
|
|
146
|
-
ticket_worktree_created: WorktreeSchema,
|
|
147
|
-
baseline_tests: TestRunSchema,
|
|
148
|
-
/** Another ticket's baseline, taken from the same run-branch commit (#404). */
|
|
149
|
-
baseline_reused: z.looseObject({ from_ticket: z.number().int() }),
|
|
150
|
-
agent_started: z.looseObject({
|
|
151
|
-
role: z.string(),
|
|
152
|
-
/** The session a fix-loop or failed-try follow-up went to. */
|
|
153
|
-
follow_up_of: z.string().nullable().catch(null),
|
|
154
|
-
}),
|
|
155
|
-
agent_finished: z.looseObject({
|
|
156
|
-
role: z.string(),
|
|
157
|
-
result: z
|
|
158
|
-
.looseObject({
|
|
159
|
-
outcome: z.string().optional(),
|
|
160
|
-
verdict: z.string().optional(),
|
|
161
|
-
findings: FindingListSchema.optional(),
|
|
162
|
-
/** The ticket-reviewer's rulings on declined findings. */
|
|
163
|
-
rulings: RulingListSchema,
|
|
164
|
-
/** A review fixer's answer to each finding it got. */
|
|
165
|
-
finding_responses: FindingResponseListSchema,
|
|
166
|
-
/** The learner's proposed memories (#370). */
|
|
167
|
-
memories: z.array(z.unknown()).catch([]).optional(),
|
|
168
|
-
/** The shown memories the learner said helped. */
|
|
169
|
-
helped: z.array(z.string()).catch([]).optional(),
|
|
170
|
-
})
|
|
171
|
-
.catch({ rulings: [], finding_responses: [] }),
|
|
172
|
-
}),
|
|
173
|
-
agent_failed: z.looseObject({
|
|
174
|
-
role: z.string(),
|
|
175
|
-
error: z.string(),
|
|
176
|
-
/** `agent`, `result`, `guard`, or `engine`. */
|
|
177
|
-
failure: z.string().catch('agent'),
|
|
178
|
-
}),
|
|
179
|
-
agent_session: z.looseObject({
|
|
180
|
-
role: z.string(),
|
|
181
|
-
session: AgentSessionSchema,
|
|
182
|
-
}),
|
|
183
|
-
run_stopped: z.looseObject({
|
|
184
|
-
reason: z.string(),
|
|
185
|
-
role: z.string().nullable().catch(null),
|
|
186
|
-
/** A billing stop: the session would bill per token. */
|
|
187
|
-
billing: z.boolean().catch(false),
|
|
188
|
-
/** A stop after the same step crashed again and again. */
|
|
189
|
-
crashed: z.boolean().catch(false),
|
|
190
|
-
}),
|
|
191
|
-
worktree_reset: z.looseObject({}),
|
|
192
|
-
/** The engine's install in a new worktree; `check` is null with no manifest. */
|
|
193
|
-
dependencies_installed: z.looseObject({
|
|
194
|
-
target: z.string(),
|
|
195
|
-
check: z
|
|
196
|
-
.looseObject({ command: z.string(), ok: z.boolean() })
|
|
197
|
-
.nullable(),
|
|
198
|
-
}),
|
|
199
|
-
red_check: z.looseObject({
|
|
200
|
-
ok: z.boolean(),
|
|
201
|
-
problems: z.array(z.string()).catch([]),
|
|
202
|
-
tests: TestRunSchema.optional(),
|
|
203
|
-
}),
|
|
204
|
-
leftover_scan: z.looseObject({
|
|
205
|
-
/** `red`, `green`, or `fix` (a review fix round). */
|
|
206
|
-
stage: z.string(),
|
|
207
|
-
hits: z.array(z.looseObject({ path: z.string() })),
|
|
208
|
-
}),
|
|
209
|
-
/** `stage` is `red`, `green`, or `fix` (a review fix round). */
|
|
210
|
-
commit_made: z.looseObject({ stage: z.string() }),
|
|
211
|
-
gates_run: z.looseObject({
|
|
212
|
-
target: z.string(),
|
|
213
|
-
ok: z.boolean(),
|
|
214
|
-
checks: z.array(z.looseObject({ name: z.string(), ok: z.boolean() })),
|
|
215
|
-
}),
|
|
216
|
-
ticket_joined: z.looseObject({
|
|
217
|
-
ok: z.boolean(),
|
|
218
|
-
error: z.string().optional(),
|
|
219
|
-
}),
|
|
220
|
-
/** A joined ticket sent back to be fixed on top of the run branch. */
|
|
221
|
-
ticket_rebased: z.looseObject({
|
|
222
|
-
/** `clash` or `join_gates`. */
|
|
223
|
-
cause: z.string(),
|
|
224
|
-
tests: z.array(z.string()).catch([]),
|
|
225
|
-
code: z.array(z.string()).catch([]),
|
|
226
|
-
}),
|
|
227
|
-
run_branch_pushed: z.looseObject({ branch: z.string() }),
|
|
228
|
-
ticket_stuck: z.looseObject({
|
|
229
|
-
reason: z.string(),
|
|
230
|
-
detail: z.string().catch(''),
|
|
231
|
-
}),
|
|
232
|
-
/** The whole run is stuck (#435): `run_budget`, it used up its budget. */
|
|
233
|
-
run_stuck: z.looseObject({
|
|
234
|
-
reason: z.string(),
|
|
235
|
-
detail: z.string().catch(''),
|
|
236
|
-
}),
|
|
237
|
-
pull_request_opened: z.looseObject({
|
|
238
|
-
number: z.number().int(),
|
|
239
|
-
url: z.string(),
|
|
240
|
-
}),
|
|
241
|
-
/** The run's worktrees, removed at its end. Nothing visible changes. */
|
|
242
|
-
worktrees_removed: z.looseObject({
|
|
243
|
-
paths: z.array(z.string()).catch([]),
|
|
244
|
-
}),
|
|
245
|
-
// Jev in shadow mode: counted, never acted on.
|
|
246
|
-
jev_asked: JevJobSchema,
|
|
247
|
-
jev_answered: JevJobSchema,
|
|
248
|
-
jev_failed: JevJobSchema,
|
|
249
|
-
// Agent messages: sent inside an agent's turn, so they move nothing.
|
|
250
|
-
agent_message: z.looseObject({
|
|
251
|
-
from: z.string(),
|
|
252
|
-
to: z.string(),
|
|
253
|
-
text: z.string(),
|
|
254
|
-
status: z.enum(['queued', 'not_delivered', 'refused']),
|
|
255
|
-
reason: z.string().nullable().catch(null),
|
|
256
|
-
}),
|
|
257
|
-
agent_message_delivered: z.looseObject({
|
|
258
|
-
ids: z.array(z.string()).catch([]),
|
|
259
|
-
}),
|
|
260
|
-
/** Another process changed the shared `.git` during an agent's turn. */
|
|
261
|
-
shared_git_changed: z.looseObject({
|
|
262
|
-
role: z.string().catch(''),
|
|
263
|
-
changes: z.array(z.string()).catch([]),
|
|
264
|
-
}),
|
|
265
|
-
limit_wait_started: z.looseObject({
|
|
266
|
-
/** When the limit resets; `null` when not known. */
|
|
267
|
-
resets_at: z.string().nullable().catch(null),
|
|
268
|
-
/** When the engine wakes; always set by the engine. */
|
|
269
|
-
until: z.string().nullable().catch(null),
|
|
270
|
-
/** The window that was hit: `five_hour`, `seven_day`, ... */
|
|
271
|
-
rate_limit_type: z.string().nullable().catch(null),
|
|
272
|
-
}),
|
|
273
|
-
limit_wait_ended: z.looseObject({}),
|
|
274
|
-
/** The run paused at a usage line. */
|
|
275
|
-
usage_line_wait_started: z.looseObject({
|
|
276
|
-
/** `seven_day` or `five_hour`. */
|
|
277
|
-
window: z.string(),
|
|
278
|
-
/** The line, in percent. */
|
|
279
|
-
line: z.number(),
|
|
280
|
-
/** How full the window was, in percent. */
|
|
281
|
-
percent: z.number(),
|
|
282
|
-
/** When the window resets. */
|
|
283
|
-
resets_at: z.string(),
|
|
284
|
-
}),
|
|
285
|
-
/** The run carries on: `reason` is `reset` or `line_raised`. */
|
|
286
|
-
usage_line_wait_ended: z.looseObject({}),
|
|
287
|
-
/** How much of the plan a ticket (scope `ticket`) or the run used. */
|
|
288
|
-
usage_recorded: z.looseObject({
|
|
289
|
-
scope: z.enum(['ticket', 'run']),
|
|
290
|
-
ticket: z.number().int().nullable().catch(null),
|
|
291
|
-
/** Percents 0 to 100 per window, before and after, and the difference. */
|
|
292
|
-
windows: z
|
|
293
|
-
.record(z.string(), z.looseObject({ used: z.number() }))
|
|
294
|
-
.catch({}),
|
|
295
|
-
}),
|
|
296
|
-
|
|
297
|
-
/** The owner's reply on the spec issue, read by the engine (#366). */
|
|
298
|
-
reply_received: z.looseObject({
|
|
299
|
-
/** `ship` is only for a stuck final review. */
|
|
300
|
-
word: z.enum(['retry', 'skip', 'stop', 'ship']),
|
|
301
|
-
ticket: z.number().int().nullable().optional(),
|
|
302
|
-
}),
|
|
303
|
-
/** A reply the engine couldn't use; it answered why on the spec issue. */
|
|
304
|
-
reply_ignored: z.looseObject({
|
|
305
|
-
/** `no_ticket_named`, `not_stuck`, `nothing_stuck`, `ship_needs_final_review`, ... */
|
|
306
|
-
reason: z.string(),
|
|
307
|
-
}),
|
|
308
|
-
/** How the engine took a `retry` for a stuck ticket. */
|
|
309
|
-
ticket_retried: z.looseObject({
|
|
310
|
-
/** `resume`, `restart` (the ticket was edited), or `refused`. */
|
|
311
|
-
mode: z.enum(['resume', 'restart', 'refused']),
|
|
312
|
-
/** Why the edited ticket isn't ready to build, for `refused`. */
|
|
313
|
-
problems: z.array(z.string()).catch([]),
|
|
314
|
-
}),
|
|
315
|
-
/** `because`: `null` when the owner skipped it, else the skipped ticket it waits on. */
|
|
316
|
-
ticket_skipped: z.looseObject({
|
|
317
|
-
because: z.number().int().nullable().catch(null),
|
|
318
|
-
}),
|
|
319
|
-
/** A ticket whose work was already on the base branch (#484), done by `shas`. */
|
|
320
|
-
ticket_already_done: z.looseObject({
|
|
321
|
-
shas: z.array(z.string()).catch([]),
|
|
322
|
-
}),
|
|
323
|
-
/** The engine closed an already-done ticket, as the run opens no PR. */
|
|
324
|
-
ticket_closed: z.looseObject({}),
|
|
325
|
-
|
|
326
|
-
// The final review (#367). Its agent, gate, scan, commit, and push
|
|
327
|
-
// records are the usual kinds with `ticket: null`.
|
|
328
|
-
final_review_started: z.looseObject({}),
|
|
329
|
-
lens_started: z.looseObject({ lens: z.string() }),
|
|
330
|
-
lens_finished: z.looseObject({
|
|
331
|
-
lens: z.string(),
|
|
332
|
-
findings: FindingCountsSchema,
|
|
333
|
-
}),
|
|
334
|
-
final_review_fixing: z.looseObject({ round: z.number().int().min(0) }),
|
|
335
|
-
final_review_stuck: z.looseObject({
|
|
336
|
-
reason: z.string(),
|
|
337
|
-
detail: z.string().catch(''),
|
|
338
|
-
}),
|
|
339
|
-
final_review_passed: z.looseObject({}),
|
|
340
|
-
/** A `ship` reply to the stuck final review: the PR opens anyway. */
|
|
341
|
-
final_review_shipped: z.looseObject({}),
|
|
342
|
-
|
|
343
|
-
// Memory (#370): counted, and its learner shown. The learner's agent
|
|
344
|
-
// records are the usual kinds with `ticket: null` and role `learner`.
|
|
345
|
-
/** A search at a recall point: each vault's outcome, and what it showed. */
|
|
346
|
-
memory_recalled: z.looseObject({
|
|
347
|
-
/** `run_start`, `ticket`, `review`, or `fix_round`. */
|
|
348
|
-
point: z.string(),
|
|
349
|
-
vaults: z
|
|
350
|
-
.array(
|
|
351
|
-
z.looseObject({
|
|
352
|
-
vault: z.string(),
|
|
353
|
-
ok: z.boolean(),
|
|
354
|
-
error: z.string().nullable().catch(null),
|
|
355
|
-
})
|
|
356
|
-
)
|
|
357
|
-
.catch([]),
|
|
358
|
-
memories: z.array(z.unknown()).catch([]),
|
|
359
|
-
}),
|
|
360
|
-
/** The learner's memories saved, refused, or failed. */
|
|
361
|
-
memories_saved: z.looseObject({
|
|
362
|
-
saves: z
|
|
363
|
-
.array(
|
|
364
|
-
z.looseObject({
|
|
365
|
-
/** `added`, `updated`, `refused`, or `failed`. */
|
|
366
|
-
outcome: z.string(),
|
|
367
|
-
})
|
|
368
|
-
)
|
|
369
|
-
.catch([]),
|
|
370
|
-
}),
|
|
371
|
-
/** The engine gave up on the learner; the run ends without it. */
|
|
372
|
-
learning_skipped: z.looseObject({ reason: z.string().catch('') }),
|
|
373
|
-
/** With no PR, the new memories went on the spec issue. */
|
|
374
|
-
memories_reported: z.looseObject({ count: z.number().int().catch(0) }),
|
|
375
|
-
|
|
376
|
-
// The scheduler's steps (#403): what the engine is doing right now.
|
|
377
|
-
/**
|
|
378
|
-
* A step began. `key` is the scheduler's key (a ticket's number, `run`,
|
|
379
|
-
* `final`, `lens:<lens>`, ...); `step` its action type, plus `:<role>`
|
|
380
|
-
* for an agent's turn.
|
|
381
|
-
*/
|
|
382
|
-
step_started: z.looseObject({ key: z.string(), step: z.string() }),
|
|
383
|
-
/** The step on `key` settled. */
|
|
384
|
-
step_ended: z.looseObject({ key: z.string(), step: z.string() }),
|
|
20
|
+
...RUN_VOCABULARY,
|
|
21
|
+
...ENGINE_VOCABULARY,
|
|
22
|
+
...REVIEW_VOCABULARY,
|
|
385
23
|
} as const
|
|
386
24
|
|
|
387
25
|
export type BoardKind = keyof typeof BOARD_VOCABULARY
|
|
@@ -394,7 +32,11 @@ const entry = <Kind extends BoardKind>({ kind }: { kind: Kind }) =>
|
|
|
394
32
|
|
|
395
33
|
const BoardEntrySchema = z.discriminatedUnion('kind', [
|
|
396
34
|
entry({ kind: 'run_started' }),
|
|
35
|
+
entry({ kind: 'repo_wait_started' }),
|
|
36
|
+
entry({ kind: 'repo_wait_ended' }),
|
|
397
37
|
entry({ kind: 'engine_resumed' }),
|
|
38
|
+
entry({ kind: 'config_reloaded' }),
|
|
39
|
+
entry({ kind: 'config_reload_refused' }),
|
|
398
40
|
entry({ kind: 'intake_read' }),
|
|
399
41
|
entry({ kind: 'intake_refused' }),
|
|
400
42
|
entry({ kind: 'nothing_to_do' }),
|
|
@@ -417,6 +59,7 @@ const BoardEntrySchema = z.discriminatedUnion('kind', [
|
|
|
417
59
|
entry({ kind: 'gates_run' }),
|
|
418
60
|
entry({ kind: 'ticket_joined' }),
|
|
419
61
|
entry({ kind: 'ticket_rebased' }),
|
|
62
|
+
entry({ kind: 'tests_sent_back' }),
|
|
420
63
|
entry({ kind: 'run_branch_pushed' }),
|
|
421
64
|
entry({ kind: 'ticket_stuck' }),
|
|
422
65
|
entry({ kind: 'run_stuck' }),
|
|
@@ -425,6 +68,7 @@ const BoardEntrySchema = z.discriminatedUnion('kind', [
|
|
|
425
68
|
entry({ kind: 'jev_asked' }),
|
|
426
69
|
entry({ kind: 'jev_answered' }),
|
|
427
70
|
entry({ kind: 'jev_failed' }),
|
|
71
|
+
entry({ kind: 'decision_model_off' }),
|
|
428
72
|
entry({ kind: 'agent_message' }),
|
|
429
73
|
entry({ kind: 'agent_message_delivered' }),
|
|
430
74
|
entry({ kind: 'shared_git_changed' }),
|
|
@@ -452,6 +96,7 @@ const BoardEntrySchema = z.discriminatedUnion('kind', [
|
|
|
452
96
|
entry({ kind: 'memories_reported' }),
|
|
453
97
|
entry({ kind: 'step_started' }),
|
|
454
98
|
entry({ kind: 'step_ended' }),
|
|
99
|
+
entry({ kind: 'ticket_waiting' }),
|
|
455
100
|
])
|
|
456
101
|
|
|
457
102
|
/** A record the board understands, with its content parsed. */
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { type Harness } from './testing/board-harness'
|
|
2
|
+
import { intakeOfThree, stamp, type Entry } from './testing/journal-fixtures'
|
|
3
|
+
|
|
4
|
+
import type { EngineRecord } from '../shared/board-rpc'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Helpers shared by the current step tests (`current-step-panel.test.ts` and
|
|
8
|
+
* the `current-step-panel-*.test.ts` files beside it).
|
|
9
|
+
*
|
|
10
|
+
* The pure helpers that build and read journal records and the run header
|
|
11
|
+
* row. Each test file keeps its own `harness`, `extra`, `dirs`, and
|
|
12
|
+
* `runWith`, because the tests start boards of their own.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* `step_started` as the engine journals it: `key` is the ticket's number,
|
|
17
|
+
* or `run` for the run's own steps; `step` is the action type, plus
|
|
18
|
+
* `:<role>` for an agent's turn.
|
|
19
|
+
*/
|
|
20
|
+
export const stepStarted = ({
|
|
21
|
+
ticket,
|
|
22
|
+
step,
|
|
23
|
+
role = null,
|
|
24
|
+
first_seq = null,
|
|
25
|
+
}: {
|
|
26
|
+
ticket: number | null
|
|
27
|
+
step: string
|
|
28
|
+
role?: string | null
|
|
29
|
+
first_seq?: number | null
|
|
30
|
+
}): Entry => ({
|
|
31
|
+
kind: 'step_started',
|
|
32
|
+
ticket,
|
|
33
|
+
role,
|
|
34
|
+
content: {
|
|
35
|
+
key: ticket === null ? 'run' : String(ticket),
|
|
36
|
+
step,
|
|
37
|
+
first_seq,
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
/** `step_ended` as the engine journals it once the step settles. */
|
|
42
|
+
export const stepEnded = ({
|
|
43
|
+
ticket,
|
|
44
|
+
step,
|
|
45
|
+
role = null,
|
|
46
|
+
}: {
|
|
47
|
+
ticket: number | null
|
|
48
|
+
step: string
|
|
49
|
+
role?: string | null
|
|
50
|
+
}): Entry => ({
|
|
51
|
+
kind: 'step_ended',
|
|
52
|
+
ticket,
|
|
53
|
+
role,
|
|
54
|
+
content: { key: ticket === null ? 'run' : String(ticket), step },
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
/** The journal: three tickets through intake, then `entries`. */
|
|
58
|
+
export const journalWith = ({
|
|
59
|
+
entries,
|
|
60
|
+
}: {
|
|
61
|
+
entries: Entry[]
|
|
62
|
+
}): EngineRecord[] => stamp({ entries: [...intakeOfThree(), ...entries] })
|
|
63
|
+
|
|
64
|
+
/** The stamped time of the record at `seq`. */
|
|
65
|
+
export const timeOf = ({
|
|
66
|
+
records,
|
|
67
|
+
seq,
|
|
68
|
+
}: {
|
|
69
|
+
records: EngineRecord[]
|
|
70
|
+
seq: number
|
|
71
|
+
}): string => {
|
|
72
|
+
const found = records.find((record) => record.seq === seq)
|
|
73
|
+
if (!found) throw new Error(`no record ${seq}`)
|
|
74
|
+
return found.time
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** The seq of the last record of `kind` whose content has `step`. */
|
|
78
|
+
export const lastStepSeq = ({
|
|
79
|
+
records,
|
|
80
|
+
kind,
|
|
81
|
+
step,
|
|
82
|
+
ticket,
|
|
83
|
+
}: {
|
|
84
|
+
records: EngineRecord[]
|
|
85
|
+
kind: string
|
|
86
|
+
step: string
|
|
87
|
+
ticket: number | null
|
|
88
|
+
}): number => {
|
|
89
|
+
const found = records.findLast(
|
|
90
|
+
(record) =>
|
|
91
|
+
record.kind === kind &&
|
|
92
|
+
record.ticket === ticket &&
|
|
93
|
+
(record.content as { step: string }).step === step
|
|
94
|
+
)
|
|
95
|
+
if (!found) throw new Error(`no ${kind} for ${step}`)
|
|
96
|
+
return found.seq
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** The run's header row as the chat shows it now. */
|
|
100
|
+
export const headerOf = ({ board }: { board: Harness }) => {
|
|
101
|
+
const found = board
|
|
102
|
+
.latestRows()
|
|
103
|
+
.find(({ row }) => row.kind === 'luca-board-run')
|
|
104
|
+
if (!found || found.row.kind !== 'luca-board-run') {
|
|
105
|
+
throw new Error('no header row')
|
|
106
|
+
}
|
|
107
|
+
return found.row.data
|
|
108
|
+
}
|