@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,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Needs you": the stuck work waiting for a reply on the spec issue, each as
|
|
3
|
+
* a card with its reason, detail, what was tried and its reply buttons, and
|
|
4
|
+
* what came of the replies the board already posted.
|
|
5
|
+
*/
|
|
6
|
+
import { Icon } from '@getpaseo/plugin/client/react-native'
|
|
7
|
+
import { Text, View } from 'react-native'
|
|
8
|
+
|
|
9
|
+
import { Section, StageHeader } from './board-panel-parts'
|
|
10
|
+
import type { Look } from './board-panel-styles'
|
|
11
|
+
import { StuckActions } from './stuck-actions'
|
|
12
|
+
|
|
13
|
+
import type { BoardState, NeedsYou } from '../shared/board-state'
|
|
14
|
+
import { postedText, type PostedReply } from '../shared/reply-actions'
|
|
15
|
+
|
|
16
|
+
const NeedsYouCard = ({
|
|
17
|
+
item,
|
|
18
|
+
run_id,
|
|
19
|
+
spec_number,
|
|
20
|
+
posted,
|
|
21
|
+
chat_agent_id,
|
|
22
|
+
theme,
|
|
23
|
+
styles,
|
|
24
|
+
}: {
|
|
25
|
+
item: NeedsYou
|
|
26
|
+
run_id: string
|
|
27
|
+
spec_number: number | null
|
|
28
|
+
posted: PostedReply[]
|
|
29
|
+
chat_agent_id: string | null
|
|
30
|
+
} & Look) => (
|
|
31
|
+
<View style={[styles.card, styles.cardStuck]}>
|
|
32
|
+
<View style={styles.cardTop}>
|
|
33
|
+
<Icon
|
|
34
|
+
name="OctagonAlert"
|
|
35
|
+
size={14}
|
|
36
|
+
color={theme.colors.statusDanger}
|
|
37
|
+
/>
|
|
38
|
+
<Text
|
|
39
|
+
style={[styles.cardTitle, { color: theme.colors.statusDanger }]}
|
|
40
|
+
>
|
|
41
|
+
{item.subject}
|
|
42
|
+
</Text>
|
|
43
|
+
</View>
|
|
44
|
+
<Text style={styles.text}>{item.reason}</Text>
|
|
45
|
+
{item.detail ? (
|
|
46
|
+
<Text style={styles.muted} numberOfLines={8} selectable>
|
|
47
|
+
{item.detail}
|
|
48
|
+
</Text>
|
|
49
|
+
) : null}
|
|
50
|
+
{item.tried.length > 0 ? (
|
|
51
|
+
<>
|
|
52
|
+
<Text style={styles.label}>Tried</Text>
|
|
53
|
+
{item.tried.map((line, index) => (
|
|
54
|
+
<Text key={`${index}-${line}`} style={styles.muted}>
|
|
55
|
+
{index + 1}. {line}
|
|
56
|
+
</Text>
|
|
57
|
+
))}
|
|
58
|
+
</>
|
|
59
|
+
) : null}
|
|
60
|
+
<StuckActions
|
|
61
|
+
run_id={run_id}
|
|
62
|
+
item={item}
|
|
63
|
+
spec_number={spec_number}
|
|
64
|
+
posted={posted}
|
|
65
|
+
chat_agent_id={chat_agent_id}
|
|
66
|
+
theme={theme}
|
|
67
|
+
/>
|
|
68
|
+
</View>
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
export const NeedsYouSection = ({
|
|
72
|
+
state,
|
|
73
|
+
posted,
|
|
74
|
+
chat_agent_id,
|
|
75
|
+
theme,
|
|
76
|
+
styles,
|
|
77
|
+
}: {
|
|
78
|
+
state: BoardState
|
|
79
|
+
posted: PostedReply[]
|
|
80
|
+
chat_agent_id: string | null
|
|
81
|
+
} & Look) => {
|
|
82
|
+
const { run } = state
|
|
83
|
+
const look = { theme, styles }
|
|
84
|
+
// Replies the board posted whose stuck item is gone: say what came of them.
|
|
85
|
+
const answered = posted.filter(
|
|
86
|
+
(entry) =>
|
|
87
|
+
!state.needs_you.some(
|
|
88
|
+
(item) => item.key === entry.key && item.since === entry.since
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<Section styles={styles}>
|
|
94
|
+
<StageHeader
|
|
95
|
+
title="Needs you"
|
|
96
|
+
hint="stuck work waiting for your reply on the spec issue"
|
|
97
|
+
icon="OctagonAlert"
|
|
98
|
+
count={state.needs_you.length}
|
|
99
|
+
color={theme.colors.statusDanger}
|
|
100
|
+
folded={null}
|
|
101
|
+
onPress={null}
|
|
102
|
+
{...look}
|
|
103
|
+
/>
|
|
104
|
+
{state.needs_you.length > 0 ? (
|
|
105
|
+
<View style={styles.stageBody}>
|
|
106
|
+
{state.needs_you.map((item) => (
|
|
107
|
+
<NeedsYouCard
|
|
108
|
+
key={`${item.key}-${item.since}`}
|
|
109
|
+
item={item}
|
|
110
|
+
run_id={run.run_id}
|
|
111
|
+
spec_number={run.spec_number}
|
|
112
|
+
posted={posted}
|
|
113
|
+
chat_agent_id={chat_agent_id}
|
|
114
|
+
{...look}
|
|
115
|
+
/>
|
|
116
|
+
))}
|
|
117
|
+
</View>
|
|
118
|
+
) : null}
|
|
119
|
+
{answered.length > 0 ? (
|
|
120
|
+
<View style={styles.stageBody}>
|
|
121
|
+
{answered.map((entry) => (
|
|
122
|
+
<Text
|
|
123
|
+
key={`${entry.key}-${entry.since}`}
|
|
124
|
+
style={styles.muted}
|
|
125
|
+
>
|
|
126
|
+
{postedText({ posted: entry })}
|
|
127
|
+
</Text>
|
|
128
|
+
))}
|
|
129
|
+
</View>
|
|
130
|
+
) : null}
|
|
131
|
+
</Section>
|
|
132
|
+
)
|
|
133
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The side panel's one-line rule (#626): every card line and the footer
|
|
3
|
+
* stay on one line, cut at the end with "…". A tap on a cut line opens a
|
|
4
|
+
* bubble with its full text; a second tap, or a tap anywhere else, closes
|
|
5
|
+
* it. On a computer, hovering opens it too.
|
|
6
|
+
*
|
|
7
|
+
* A card or the footer is a bubble scope (`useBubbles` and `BubbleScope`):
|
|
8
|
+
* it shows the open bubble of its lines under them. Inside the panel
|
|
9
|
+
* (`SharedBubbles`), one bubble is open at a time across every scope; a
|
|
10
|
+
* card or footer drawn on its own keeps its bubble itself.
|
|
11
|
+
*/
|
|
12
|
+
import {
|
|
13
|
+
createContext,
|
|
14
|
+
useContext,
|
|
15
|
+
useId,
|
|
16
|
+
useState,
|
|
17
|
+
type Dispatch,
|
|
18
|
+
type ReactNode,
|
|
19
|
+
type SetStateAction,
|
|
20
|
+
} from 'react'
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
Pressable,
|
|
24
|
+
Text,
|
|
25
|
+
type StyleProp,
|
|
26
|
+
type TextStyle,
|
|
27
|
+
type ViewStyle,
|
|
28
|
+
} from 'react-native'
|
|
29
|
+
|
|
30
|
+
import type { Styles } from './board-panel-styles'
|
|
31
|
+
|
|
32
|
+
type OpenBubble = {
|
|
33
|
+
/** The card or footer that shows it. */
|
|
34
|
+
scope: string
|
|
35
|
+
/** The cut line it belongs to. */
|
|
36
|
+
line: string
|
|
37
|
+
text: string
|
|
38
|
+
/** Opened by hovering: leaving the line closes it, a tap keeps it. */
|
|
39
|
+
hovered: boolean
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type Shared = {
|
|
43
|
+
open: OpenBubble | null
|
|
44
|
+
show: Dispatch<SetStateAction<OpenBubble | null>>
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type Bubbles = Shared & { scope: string }
|
|
48
|
+
|
|
49
|
+
const SharedContext = createContext<Shared | null>(null)
|
|
50
|
+
|
|
51
|
+
const ScopeContext = createContext<Bubbles | null>(null)
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* One open bubble for everything under it: the scrolling panel and the
|
|
55
|
+
* status bar pinned below it.
|
|
56
|
+
*/
|
|
57
|
+
export const BubbleProvider = ({ children }: { children: ReactNode }) => {
|
|
58
|
+
const [open, show] = useState<OpenBubble | null>(null)
|
|
59
|
+
return (
|
|
60
|
+
<SharedContext.Provider value={{ open, show }}>
|
|
61
|
+
{children}
|
|
62
|
+
</SharedContext.Provider>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const ClosesBubble = ({
|
|
67
|
+
style,
|
|
68
|
+
children,
|
|
69
|
+
}: {
|
|
70
|
+
style: StyleProp<ViewStyle>
|
|
71
|
+
children: ReactNode
|
|
72
|
+
}) => {
|
|
73
|
+
const shared = useContext(SharedContext)
|
|
74
|
+
return (
|
|
75
|
+
<Pressable
|
|
76
|
+
accessible={false}
|
|
77
|
+
onPress={() => shared?.show(null)}
|
|
78
|
+
style={style}
|
|
79
|
+
>
|
|
80
|
+
{children}
|
|
81
|
+
</Pressable>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* One open bubble for the whole panel (a `BubbleProvider`'s, when inside
|
|
87
|
+
* one). A tap on any part of the panel that isn't a button of its own
|
|
88
|
+
* closes it.
|
|
89
|
+
*/
|
|
90
|
+
export const SharedBubbles = ({
|
|
91
|
+
style,
|
|
92
|
+
children,
|
|
93
|
+
}: {
|
|
94
|
+
style: StyleProp<ViewStyle>
|
|
95
|
+
children: ReactNode
|
|
96
|
+
}) => {
|
|
97
|
+
const shared = useContext(SharedContext)
|
|
98
|
+
const body = <ClosesBubble style={style}>{children}</ClosesBubble>
|
|
99
|
+
return shared ? body : <BubbleProvider>{body}</BubbleProvider>
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Closes the panel's open bubble: for a button's tap that does more. */
|
|
103
|
+
export const useCloseBubble = (): (() => void) => {
|
|
104
|
+
const shared = useContext(SharedContext)
|
|
105
|
+
return () => shared?.show(null)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** A card's or the footer's bubbles: the panel's, or its own outside one. */
|
|
109
|
+
export const useBubbles = (): Bubbles => {
|
|
110
|
+
const shared = useContext(SharedContext)
|
|
111
|
+
const [open, show] = useState<OpenBubble | null>(null)
|
|
112
|
+
const scope = useId()
|
|
113
|
+
return { scope, ...(shared ?? { open, show }) }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Gives its cut lines their bubble, and shows it under them when open. */
|
|
117
|
+
export const BubbleScope = ({
|
|
118
|
+
bubbles,
|
|
119
|
+
styles,
|
|
120
|
+
children,
|
|
121
|
+
}: {
|
|
122
|
+
bubbles: Bubbles
|
|
123
|
+
styles: Styles
|
|
124
|
+
children: ReactNode
|
|
125
|
+
}) => (
|
|
126
|
+
<ScopeContext.Provider value={bubbles}>
|
|
127
|
+
{children}
|
|
128
|
+
{bubbles.open?.scope === bubbles.scope ? (
|
|
129
|
+
<Text style={styles.bubble} onPress={() => bubbles.show(null)}>
|
|
130
|
+
{bubbles.open.text}
|
|
131
|
+
</Text>
|
|
132
|
+
) : null}
|
|
133
|
+
</ScopeContext.Provider>
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* A line of text cut at its end with "…". Inside a `BubbleScope`, a tap
|
|
138
|
+
* (or hovering) opens its full text in a bubble, or `full` when given: a
|
|
139
|
+
* short line's longer sentence. `children`, when given, draw the line in
|
|
140
|
+
* place of `text` (as nested, colored texts), which stays its plain words.
|
|
141
|
+
*/
|
|
142
|
+
export const CutLine = ({
|
|
143
|
+
text,
|
|
144
|
+
full,
|
|
145
|
+
style,
|
|
146
|
+
styles,
|
|
147
|
+
children,
|
|
148
|
+
}: {
|
|
149
|
+
text: string
|
|
150
|
+
full?: string
|
|
151
|
+
style: StyleProp<TextStyle>
|
|
152
|
+
styles: Styles
|
|
153
|
+
children?: ReactNode
|
|
154
|
+
}) => {
|
|
155
|
+
const bubbles = useContext(ScopeContext)
|
|
156
|
+
const line = useId()
|
|
157
|
+
const shown = full ?? text
|
|
158
|
+
const label = (
|
|
159
|
+
<Text style={style} numberOfLines={1} ellipsizeMode="tail">
|
|
160
|
+
{children ?? text}
|
|
161
|
+
</Text>
|
|
162
|
+
)
|
|
163
|
+
if (!bubbles) return label
|
|
164
|
+
const { scope, show } = bubbles
|
|
165
|
+
return (
|
|
166
|
+
<Pressable
|
|
167
|
+
accessibilityRole="button"
|
|
168
|
+
accessibilityHint="Shows the full text"
|
|
169
|
+
onPress={() =>
|
|
170
|
+
show((open) =>
|
|
171
|
+
open?.line === line && !open.hovered
|
|
172
|
+
? null
|
|
173
|
+
: { scope, line, text: shown, hovered: false }
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
onHoverIn={() =>
|
|
177
|
+
show((open) =>
|
|
178
|
+
open === null || open.hovered
|
|
179
|
+
? { scope, line, text: shown, hovered: true }
|
|
180
|
+
: open
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
onHoverOut={() =>
|
|
184
|
+
show((open) =>
|
|
185
|
+
open?.line === line && open.hovered ? null : open
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
style={styles.cut}
|
|
189
|
+
>
|
|
190
|
+
{label}
|
|
191
|
+
</Pressable>
|
|
192
|
+
)
|
|
193
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The repo wait's banner (#632): the run waits for an earlier run on the
|
|
3
|
+
* same repo (#615), from `repo_wait_started` until `repo_wait_ended`. It
|
|
4
|
+
* says which run, how long it has waited, counting up by itself, and has
|
|
5
|
+
* the amber bar of a wait on purpose. In a run with no sign of life
|
|
6
|
+
* (#635), it says so instead, in red, and its time stops at the last sign.
|
|
7
|
+
*/
|
|
8
|
+
import { Icon } from '@getpaseo/plugin/client/react-native'
|
|
9
|
+
import { Text, View } from 'react-native'
|
|
10
|
+
|
|
11
|
+
import { useNow } from './board-look'
|
|
12
|
+
import type { Look } from './board-panel-styles'
|
|
13
|
+
|
|
14
|
+
import { elapsedText, type BoardState } from '../shared/board-state'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The banner's words.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* repoWaitText({ runs: ['20260923t113000z-5b1e0c2a'], ms: 725_000 })
|
|
21
|
+
* // 'waiting for run 20260923t113000z-5b1e0c2a on this repo · 12m 5s'
|
|
22
|
+
*/
|
|
23
|
+
export const repoWaitText = ({
|
|
24
|
+
runs,
|
|
25
|
+
ms,
|
|
26
|
+
}: {
|
|
27
|
+
runs: string[]
|
|
28
|
+
ms: number
|
|
29
|
+
}): string => {
|
|
30
|
+
const which =
|
|
31
|
+
runs.length === 0
|
|
32
|
+
? 'an earlier run'
|
|
33
|
+
: runs.map((run_id) => `run ${run_id}`).join(', ')
|
|
34
|
+
return `waiting for ${which} on this repo · ${elapsedText({ ms })}`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const RepoWaitBanner = ({
|
|
38
|
+
wait,
|
|
39
|
+
lifeless = null,
|
|
40
|
+
theme,
|
|
41
|
+
styles,
|
|
42
|
+
}: {
|
|
43
|
+
wait: NonNullable<BoardState['repo_wait']>
|
|
44
|
+
/** The run's lack of a sign of life (#635), from `noLife`. */
|
|
45
|
+
lifeless?: { text: string; at: number } | null
|
|
46
|
+
} & Look) => {
|
|
47
|
+
const ticking = useNow()
|
|
48
|
+
const now = lifeless?.at ?? ticking
|
|
49
|
+
const color = lifeless
|
|
50
|
+
? theme.colors.statusDanger
|
|
51
|
+
: theme.colors.statusWarning
|
|
52
|
+
const text = repoWaitText({
|
|
53
|
+
runs: wait.runs,
|
|
54
|
+
ms: now - Date.parse(wait.since),
|
|
55
|
+
})
|
|
56
|
+
return (
|
|
57
|
+
<View style={[styles.banner, { borderColor: color }]}>
|
|
58
|
+
<Icon name="Hourglass" size={13} color={color} />
|
|
59
|
+
<Text style={[styles.bannerText, { color }]}>
|
|
60
|
+
{lifeless ? `${text} · ${lifeless.text}` : text}
|
|
61
|
+
</Text>
|
|
62
|
+
<View style={styles.spacer} />
|
|
63
|
+
<View
|
|
64
|
+
accessibilityLabel={lifeless ? 'no sign of life' : 'waiting'}
|
|
65
|
+
style={[styles.waitBar, { backgroundColor: color }]}
|
|
66
|
+
/>
|
|
67
|
+
</View>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bottom of the side panel's scrolling part: the run id, the event
|
|
3
|
+
* count and engine state, and the counters (the decision model, memory,
|
|
4
|
+
* agent messages, outside changes to the shared .git). The latest event's
|
|
5
|
+
* age is in the status bar (`status-bar.tsx`). Each stays on one line
|
|
6
|
+
* (`one-line.tsx`); a tap shows it whole in a bubble.
|
|
7
|
+
*/
|
|
8
|
+
import { View } from 'react-native'
|
|
9
|
+
|
|
10
|
+
import { useNow } from './board-look'
|
|
11
|
+
import type { Look } from './board-panel-styles'
|
|
12
|
+
import { noLife } from './engine-life'
|
|
13
|
+
import { BubbleScope, CutLine, useBubbles } from './one-line'
|
|
14
|
+
|
|
15
|
+
import type { BoardState } from '../shared/board-state'
|
|
16
|
+
|
|
17
|
+
export const RunFooter = ({ state, styles }: { state: BoardState } & Look) => {
|
|
18
|
+
const bubbles = useBubbles()
|
|
19
|
+
const now = useNow()
|
|
20
|
+
const { run, memory } = state
|
|
21
|
+
const line = (text: string) => (
|
|
22
|
+
<CutLine text={text} style={styles.small} styles={styles} />
|
|
23
|
+
)
|
|
24
|
+
// A run with no sign of life says so here too, not "engine running".
|
|
25
|
+
const engine =
|
|
26
|
+
noLife({ state, now })?.text ??
|
|
27
|
+
`engine ${
|
|
28
|
+
run.engine_ended
|
|
29
|
+
? run.engine_ended.ok
|
|
30
|
+
? 'finished'
|
|
31
|
+
: 'stopped'
|
|
32
|
+
: 'running'
|
|
33
|
+
}`
|
|
34
|
+
const memoryChanges =
|
|
35
|
+
memory.added + memory.updated + memory.refused + memory.failed > 0
|
|
36
|
+
? `; ${memory.added} added, ${memory.updated} updated, ${memory.refused} refused, ${memory.failed} failed`
|
|
37
|
+
: ''
|
|
38
|
+
return (
|
|
39
|
+
<>
|
|
40
|
+
<View style={styles.rule} />
|
|
41
|
+
<BubbleScope bubbles={bubbles} styles={styles}>
|
|
42
|
+
{line(
|
|
43
|
+
`${run.run_id} · ${state.event_count} events · ${engine}`
|
|
44
|
+
)}
|
|
45
|
+
{state.jev.asked > 0
|
|
46
|
+
? line(
|
|
47
|
+
`Decision model, in shadow mode: ${state.jev.asked} asked, ${state.jev.answered} answered, ${state.jev.failed} without an answer. The engine doesn't act on them.`
|
|
48
|
+
)
|
|
49
|
+
: null}
|
|
50
|
+
{memory.searches > 0 || memory.learner !== 'waiting'
|
|
51
|
+
? line(
|
|
52
|
+
`Memory: ${memory.searches} searches (${memory.search_errors} vault errors), ${memory.shown} shown. Learner: ${memory.learner}${memoryChanges}.`
|
|
53
|
+
)
|
|
54
|
+
: null}
|
|
55
|
+
{state.messages.sent + state.messages.refused > 0
|
|
56
|
+
? line(
|
|
57
|
+
`Agent messages: ${state.messages.sent} sent, ${state.messages.delivered} handed over, ${state.messages.refused} refused.`
|
|
58
|
+
)
|
|
59
|
+
: null}
|
|
60
|
+
{state.shared_git_changed > 0
|
|
61
|
+
? line(
|
|
62
|
+
`Outside changes to the shared .git: ${state.shared_git_changed}. Other processes made them, not the agents.`
|
|
63
|
+
)
|
|
64
|
+
: null}
|
|
65
|
+
</BubbleScope>
|
|
66
|
+
</>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The top of the side panel: the title and status, the run tabs, the run's
|
|
3
|
+
* title and pull request, plan usage, what the engine is doing now, the
|
|
4
|
+
* run's tokens and plan used, and the banners (a repo wait, a limit wait, a
|
|
5
|
+
* version note, a stop, the engine ending, intake refusing the run).
|
|
6
|
+
*/
|
|
7
|
+
import type { PluginWorkspacePanelProps } from '@getpaseo/plugin/client'
|
|
8
|
+
import { ExternalLink } from '@getpaseo/plugin/client/ui'
|
|
9
|
+
import { Text, View } from 'react-native'
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
limitWaitText,
|
|
13
|
+
runTitle,
|
|
14
|
+
statusColor,
|
|
15
|
+
statusText,
|
|
16
|
+
tokensText,
|
|
17
|
+
usageLineWaitText,
|
|
18
|
+
useNow,
|
|
19
|
+
} from './board-look'
|
|
20
|
+
import { Banner, StepLine } from './board-panel-parts'
|
|
21
|
+
import type { Look } from './board-panel-styles'
|
|
22
|
+
import { noLife } from './engine-life'
|
|
23
|
+
import { RepoWaitBanner } from './repo-wait-banner'
|
|
24
|
+
import { RunPicker } from './run-picker'
|
|
25
|
+
import { UsageLine } from './usage-line'
|
|
26
|
+
|
|
27
|
+
import {
|
|
28
|
+
planUsedText,
|
|
29
|
+
stoppedText,
|
|
30
|
+
type BoardState,
|
|
31
|
+
type RunSummary,
|
|
32
|
+
} from '../shared/board-state'
|
|
33
|
+
|
|
34
|
+
export const RunHeader = ({
|
|
35
|
+
state,
|
|
36
|
+
runs,
|
|
37
|
+
setPicked,
|
|
38
|
+
layout,
|
|
39
|
+
theme,
|
|
40
|
+
styles,
|
|
41
|
+
}: {
|
|
42
|
+
state: BoardState
|
|
43
|
+
runs: RunSummary[]
|
|
44
|
+
setPicked: (run_id: string) => void
|
|
45
|
+
layout: PluginWorkspacePanelProps['layout']
|
|
46
|
+
} & Look) => {
|
|
47
|
+
const { run } = state
|
|
48
|
+
const look = { theme, styles }
|
|
49
|
+
// With no sign of life (#635), the step's time and the repo wait's stop.
|
|
50
|
+
const lifeless = noLife({ state, now: useNow() })
|
|
51
|
+
return (
|
|
52
|
+
<>
|
|
53
|
+
<View style={styles.row}>
|
|
54
|
+
<Text style={styles.title}>Luca board</Text>
|
|
55
|
+
<View style={styles.spacer} />
|
|
56
|
+
<Text
|
|
57
|
+
style={[
|
|
58
|
+
styles.pill,
|
|
59
|
+
{
|
|
60
|
+
color: statusColor({ status: run.status, theme }),
|
|
61
|
+
borderColor: statusColor({
|
|
62
|
+
status: run.status,
|
|
63
|
+
theme,
|
|
64
|
+
}),
|
|
65
|
+
},
|
|
66
|
+
]}
|
|
67
|
+
>
|
|
68
|
+
{statusText({ status: run.status })}
|
|
69
|
+
</Text>
|
|
70
|
+
</View>
|
|
71
|
+
{runs.length > 1 ? (
|
|
72
|
+
<RunPicker
|
|
73
|
+
runs={runs}
|
|
74
|
+
selected={run.run_id}
|
|
75
|
+
onPick={setPicked}
|
|
76
|
+
{...look}
|
|
77
|
+
/>
|
|
78
|
+
) : null}
|
|
79
|
+
<Text style={styles.text} numberOfLines={layout.compact ? 3 : 2}>
|
|
80
|
+
{runTitle(run)}
|
|
81
|
+
{run.branch ? (
|
|
82
|
+
<Text style={styles.muted}> · {run.branch}</Text>
|
|
83
|
+
) : null}
|
|
84
|
+
</Text>
|
|
85
|
+
{run.pr_url ? (
|
|
86
|
+
<ExternalLink href={run.pr_url}>
|
|
87
|
+
<Text style={styles.prLink}>
|
|
88
|
+
Pull request{run.pr_number ? ` #${run.pr_number}` : ''}:{' '}
|
|
89
|
+
{run.pr_url}
|
|
90
|
+
</Text>
|
|
91
|
+
</ExternalLink>
|
|
92
|
+
) : null}
|
|
93
|
+
<UsageLine state={state} {...look} />
|
|
94
|
+
{state.current_step ? (
|
|
95
|
+
<StepLine
|
|
96
|
+
step={state.current_step}
|
|
97
|
+
prefix="Now: "
|
|
98
|
+
at={lifeless?.at ?? null}
|
|
99
|
+
styles={styles}
|
|
100
|
+
/>
|
|
101
|
+
) : null}
|
|
102
|
+
{state.run_tokens > 0 ? (
|
|
103
|
+
<Text style={styles.mono}>
|
|
104
|
+
This run's tokens:{' '}
|
|
105
|
+
{tokensText({ tokens: state.run_tokens })} of its run budget{' '}
|
|
106
|
+
{tokensText({ tokens: state.run_budget_tokens })}
|
|
107
|
+
</Text>
|
|
108
|
+
) : null}
|
|
109
|
+
{state.run_plan_used.length > 0 ? (
|
|
110
|
+
<Text style={styles.mono}>
|
|
111
|
+
This run used:{' '}
|
|
112
|
+
{planUsedText({ used: state.run_plan_used, sign: '' })}
|
|
113
|
+
</Text>
|
|
114
|
+
) : null}
|
|
115
|
+
{state.repo_wait && run.engine_ended === null ? (
|
|
116
|
+
<RepoWaitBanner
|
|
117
|
+
wait={state.repo_wait}
|
|
118
|
+
lifeless={lifeless}
|
|
119
|
+
{...look}
|
|
120
|
+
/>
|
|
121
|
+
) : null}
|
|
122
|
+
{state.limit_wait ? (
|
|
123
|
+
<Banner
|
|
124
|
+
icon="Hourglass"
|
|
125
|
+
color={theme.colors.statusWarning}
|
|
126
|
+
styles={styles}
|
|
127
|
+
>
|
|
128
|
+
{limitWaitText({
|
|
129
|
+
window: state.limit_wait.window,
|
|
130
|
+
resets_at: state.limit_wait.resets_at,
|
|
131
|
+
now: Date.now(),
|
|
132
|
+
})}
|
|
133
|
+
</Banner>
|
|
134
|
+
) : null}
|
|
135
|
+
{state.usage_line_wait ? (
|
|
136
|
+
<Banner
|
|
137
|
+
icon="Hourglass"
|
|
138
|
+
color={theme.colors.statusWarning}
|
|
139
|
+
styles={styles}
|
|
140
|
+
>
|
|
141
|
+
{usageLineWaitText({
|
|
142
|
+
...state.usage_line_wait,
|
|
143
|
+
now: Date.now(),
|
|
144
|
+
})}
|
|
145
|
+
</Banner>
|
|
146
|
+
) : null}
|
|
147
|
+
{run.version_note ? (
|
|
148
|
+
<Banner
|
|
149
|
+
icon="Info"
|
|
150
|
+
color={theme.colors.statusWarning}
|
|
151
|
+
styles={styles}
|
|
152
|
+
>
|
|
153
|
+
{run.version_note}
|
|
154
|
+
</Banner>
|
|
155
|
+
) : null}
|
|
156
|
+
{run.stopped ? (
|
|
157
|
+
<Banner
|
|
158
|
+
icon="OctagonX"
|
|
159
|
+
color={theme.colors.statusDanger}
|
|
160
|
+
styles={styles}
|
|
161
|
+
>
|
|
162
|
+
{stoppedText(run.stopped)}
|
|
163
|
+
</Banner>
|
|
164
|
+
) : null}
|
|
165
|
+
{run.engine_ended && !run.engine_ended.ok ? (
|
|
166
|
+
<Banner
|
|
167
|
+
icon="OctagonX"
|
|
168
|
+
color={theme.colors.statusDanger}
|
|
169
|
+
styles={styles}
|
|
170
|
+
>
|
|
171
|
+
The engine stopped: {run.engine_ended.message}
|
|
172
|
+
</Banner>
|
|
173
|
+
) : null}
|
|
174
|
+
{run.refusal.length > 0 ? (
|
|
175
|
+
<Banner
|
|
176
|
+
icon="Ban"
|
|
177
|
+
color={theme.colors.statusDanger}
|
|
178
|
+
styles={styles}
|
|
179
|
+
>
|
|
180
|
+
Intake refused the run. {run.refusal.join(' ')}
|
|
181
|
+
</Banner>
|
|
182
|
+
) : null}
|
|
183
|
+
<Text style={styles.small}>
|
|
184
|
+
Step dots: tests → red check → code → checks → review. Tap a
|
|
185
|
+
card for details.
|
|
186
|
+
</Text>
|
|
187
|
+
</>
|
|
188
|
+
)
|
|
189
|
+
}
|