clauderipple 0.8.9 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +62 -0
- package/README.es.md +0 -4
- package/README.ja.md +0 -4
- package/README.ko.md +5 -1
- package/README.md +5 -1
- package/README.pt-BR.md +0 -4
- package/README.zh-CN.md +0 -4
- package/dist/app/dist/main.js +23 -3
- package/dist/app/package.json +1 -1
- package/dist/cli/src/codex.js +3 -1
- package/dist/cli/src/index.js +1 -1
- package/dist/cli/src/settings.js +5 -2
- package/dist/cli/src/tray.js +41 -5
- package/dist/mod/.claude-plugin/plugin.json +9 -1
- package/dist/mod/hooks/cache.ts +60 -0
- package/dist/mod/hooks/compact.ts +40 -0
- package/dist/mod/hooks/handoff.ts +43 -0
- package/dist/mod/hooks/i18n.ts +2716 -0
- package/dist/mod/hooks/judge.ts +226 -0
- package/dist/mod/hooks/ladder.js +179 -0
- package/dist/mod/hooks/ladder.ts +174 -0
- package/dist/mod/hooks/modes.ts +93 -0
- package/dist/mod/hooks/register.tsx +1458 -256
- package/dist/mod/hooks/session.ts +62 -0
- package/dist/mod/hooks/settings.js +342 -0
- package/dist/mod/hooks/settings.ts +321 -0
- package/dist/mod/hooks/stats.ts +59 -0
- package/dist/mod/hooks/ui/agents.tsx +138 -0
- package/dist/mod/hooks/ui/alerts.tsx +370 -0
- package/dist/mod/hooks/ui/art.ts +628 -0
- package/dist/mod/hooks/ui/band.tsx +836 -0
- package/dist/mod/hooks/ui/kit.tsx +258 -0
- package/dist/mod/hooks/ui/log.tsx +109 -0
- package/dist/mod/hooks/ui/parts.tsx +217 -0
- package/dist/mod/hooks/ui/ripple.ts +614 -0
- package/dist/mod/hooks/ui/settings.tsx +376 -0
- package/dist/mod/hooks/ui/setup.tsx +148 -0
- package/dist/mod/hooks/ui/theme.ts +217 -0
- package/dist/mod/hooks/ui/view.ts +371 -0
- package/dist/mod/hooks/worker.ts +1 -1
- package/dist/mod/hooks/workers.ts +217 -0
- package/dist/mod/tests/register.test.tsx +1730 -0
- package/dist/mod/tests/ui.test.tsx +853 -0
- package/dist/mod/tsconfig.json +2 -1
- package/dist/mod/types/index.d.ts +320 -1
- package/dist/router/src/admin.js +195 -53
- package/dist/router/src/agents.js +24 -5
- package/dist/router/src/bootstrap.js +4 -2
- package/dist/router/src/compat.js +10 -2
- package/dist/router/src/config.js +3 -0
- package/dist/router/src/health.js +33 -0
- package/dist/router/src/index.js +1 -0
- package/dist/router/src/ingress/models.js +4 -1
- package/dist/router/src/mod-settings.js +119 -0
- package/dist/router/src/model-policy.js +6 -0
- package/dist/router/src/model-scores.js +159 -0
- package/dist/router/src/picker.js +7 -0
- package/dist/router/src/providers/anthropic-account-pool.js +10 -4
- package/dist/router/src/providers/anthropic-accounts.js +26 -1
- package/dist/router/src/providers/chatgpt/catalog.js +45 -14
- package/dist/router/src/providers/chatgpt/index.js +9 -3
- package/dist/router/src/providers/chatgpt/translate.js +9 -5
- package/dist/router/src/providers/google/index.js +6 -2
- package/dist/router/src/providers/openai/index.js +4 -1
- package/dist/router/src/providers/openai/translate.js +1 -1
- package/dist/router/src/proxy.js +14 -3
- package/dist/router/src/version.js +1 -1
- package/dist/ui/app.js +932 -209
- package/dist/ui/favicon-32.png +0 -0
- package/dist/ui/favicon.svg +12 -0
- package/dist/ui/i18n.js +923 -237
- package/dist/ui/index.html +159 -87
- package/dist/ui/style.css +789 -408
- package/docs/ARCHITECTURE.md +134 -2
- package/package.json +7 -3
package/dist/mod/tsconfig.json
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
// The mod's shared shapes. The design and the reasons are in docs/specs/2026-10-10-ripple-mod.md.
|
|
2
|
+
|
|
3
|
+
// Engine contracts must be self-contained; i18n re-exports this language type.
|
|
4
|
+
export type Lang = 'ko' | 'en' | 'zh' | 'ja' | 'es' | 'pt'
|
|
5
|
+
|
|
1
6
|
export type StatusLine = string | null
|
|
2
7
|
|
|
3
8
|
export type StatusRequest = {
|
|
@@ -18,15 +23,329 @@ export type StatusRequest = {
|
|
|
18
23
|
mine?: boolean
|
|
19
24
|
}
|
|
20
25
|
|
|
26
|
+
export type Effort = 'low' | 'medium' | 'high' | 'xhigh' | 'max'
|
|
27
|
+
|
|
28
|
+
/** API usage may omit counts; the engine's ModelUsage does not expose cache TTL evidence. */
|
|
29
|
+
export type Usage = {
|
|
30
|
+
input_tokens?: number
|
|
31
|
+
output_tokens?: number
|
|
32
|
+
cache_read_input_tokens?: number
|
|
33
|
+
cache_creation_input_tokens?: number
|
|
34
|
+
cache_creation?: {
|
|
35
|
+
ephemeral_1h_input_tokens?: number
|
|
36
|
+
ephemeral_5m_input_tokens?: number
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The bounded excerpts shared by the effort judges; attachments carry counts, not contents. */
|
|
41
|
+
export type JudgeInput = {
|
|
42
|
+
messages: readonly { role: 'user' | 'assistant'; text: string }[]
|
|
43
|
+
next: string
|
|
44
|
+
attachments?: readonly { type: string }[]
|
|
45
|
+
current?: { model: string; effort: Effort } | null
|
|
46
|
+
contextPercent?: number
|
|
47
|
+
midTurn?: boolean
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Who judges: Haiku on the person's Claude login, TypeSafe's Jev, or a model through the router. */
|
|
51
|
+
export type JudgeKind = 'haiku' | 'jev' | 'model'
|
|
52
|
+
/**
|
|
53
|
+
* One verdict as the log pane lists it beside the router's requests: a Jev call never reaches the
|
|
54
|
+
* router, so without this nothing showed who judged, how long it took or that it fell back.
|
|
55
|
+
*/
|
|
56
|
+
export type JudgeRun = {
|
|
57
|
+
at: number
|
|
58
|
+
/** The effort of a prompt, or the worker for a spawn. */
|
|
59
|
+
for: 'prompt' | 'worker'
|
|
60
|
+
/** The judge the settings ask for, and the one that answered (Haiku when it fell back). */
|
|
61
|
+
asked: JudgeKind
|
|
62
|
+
by: JudgeKind
|
|
63
|
+
ms: number
|
|
64
|
+
effort?: Effort
|
|
65
|
+
sure?: number
|
|
66
|
+
/** Why the asked judge gave no verdict. */
|
|
67
|
+
error?: string
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Domain is the kind of work; level is its required capability, independently. */
|
|
71
|
+
export type Domain = 'design' | 'frontend' | 'backend' | 'infra' | 'data' | 'test' | 'docs' | 'research' | 'general'
|
|
72
|
+
export type Level = 'light' | 'standard' | 'deep'
|
|
73
|
+
/** Whether a task decides what to build (plan) or carries out what was decided (do). */
|
|
74
|
+
export type Kind = 'plan' | 'do'
|
|
75
|
+
/**
|
|
76
|
+
* The worker ladder's rungs (docs/specs/2026-10-11-worker-ladder.md): the judge's level picks
|
|
77
|
+
* light, standard or hard regardless of kind; only an explicit max tier selects plan.
|
|
78
|
+
*/
|
|
79
|
+
export type Rung = 'light' | 'standard' | 'hard' | 'plan'
|
|
80
|
+
/** One rung: what runs there and how hard it thinks. */
|
|
81
|
+
export type Step = { target: TierTarget; effort: Effort }
|
|
82
|
+
/** Historical stats include design counts from before the two-axis migration. */
|
|
83
|
+
export type Tier = Level | 'design'
|
|
84
|
+
/** How a pin stored before 2026-10-11 moved its efforts; read only to migrate it (`ladderFromPin`). */
|
|
85
|
+
export type Calibration = { effortOffset?: -2 | -1 | 0 | 1 | 2; floor?: Effort; ceiling?: Effort }
|
|
86
|
+
/**
|
|
87
|
+
* The four workers' rungs, each model + effort. Loading (`normalizeSettings`) reads pins from
|
|
88
|
+
* before 2026-10-11 and Auto (experimental, removed 2026-10-12) into it, and drops field rules.
|
|
89
|
+
*/
|
|
90
|
+
export type Rungs = Partial<Record<Rung, Step[]>>
|
|
91
|
+
export type Rule = { mode: 'ladder'; rungs: Rungs }
|
|
92
|
+
/** How a provider is paid for: what the Workers card tags each model with, and what presets read. */
|
|
93
|
+
export type Billing = 'free' | 'payg' | 'subscription'
|
|
94
|
+
/** A model a rung can run, as GET /api/mod-options describes it. */
|
|
95
|
+
export type LadderChoice = {
|
|
96
|
+
target: TierTarget
|
|
97
|
+
model: string
|
|
98
|
+
provider: string
|
|
99
|
+
billing: Billing
|
|
100
|
+
/** The model's own effort ladder, in order; empty when unknown. */
|
|
101
|
+
efforts: Effort[]
|
|
102
|
+
/** Its cheapest measured AA cost per task, when measured. */
|
|
103
|
+
cost?: number
|
|
104
|
+
}
|
|
105
|
+
/** The fill rule's wishes, by name; only `claudeGpt` is used now (the router fills empty rungs with it). */
|
|
106
|
+
export type PresetId = 'claude' | 'claudeGpt' | 'gpt' | 'cheap'
|
|
107
|
+
/** The fill as computed from the ticked models: the rungs, and the ones it had to fill otherwise. */
|
|
108
|
+
export type Preset = { rungs: Record<Rung, Step>; substituted: Rung[] }
|
|
109
|
+
export type ProviderAvailability = { usable: boolean; reason?: string; exhaustedUntil?: number }
|
|
110
|
+
export type LadderOptions = { until: number; choices: LadderChoice[]; providers?: Record<string, ProviderAvailability> }
|
|
111
|
+
export type RouterModel = { value: string; label: string; provider: string; name?: string }
|
|
112
|
+
export type WorkerCandidate = { target: TierTarget; model: string; provider: string }
|
|
113
|
+
/** A model's AA measurements (GET /api/mod-options `scores`): the fill's cost order reads them. */
|
|
114
|
+
export type ModelScore = { model: string; provider: string; variants: { effort: Effort | null; intelligence: number | null; costPerTask: number | null }[] }
|
|
115
|
+
|
|
116
|
+
/** An agent to spawn: a dispatchable `subagentType`, and a model only for Claude's own agents. */
|
|
117
|
+
export type TierTarget = { agent: string; model?: string }
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* An operating mode the user made (docs/specs/2026-10-12-worker-tiers.md "Operating modes").
|
|
121
|
+
* Each rung is an ordered worker list, independent of the base ladder, sharing its ticked models.
|
|
122
|
+
* `until` is an epoch-ms time, the named provider's next known quota reset ('chatgpt' or another
|
|
123
|
+
* ChatGPT provider, or 'anthropic' for Claude), or no automatic end.
|
|
124
|
+
*/
|
|
125
|
+
export type Mode = {
|
|
126
|
+
id: string
|
|
127
|
+
name: string
|
|
128
|
+
rungs: Rungs
|
|
129
|
+
delegation: 'normal' | 'eager'
|
|
130
|
+
until: 'none' | number | { reset: string }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export type Settings = {
|
|
134
|
+
effortAuto: boolean
|
|
135
|
+
judge: JudgeKind
|
|
136
|
+
/** The router model id the `model` judge asks. */
|
|
137
|
+
judgeModel: string
|
|
138
|
+
bias: -2 | -1 | 0 | 1 | 2
|
|
139
|
+
floor: Effort
|
|
140
|
+
ceiling: Effort
|
|
141
|
+
/** off: never; auto: spawns of ripple:auto; all: also general-purpose spawns with no model. */
|
|
142
|
+
agentAuto: 'off' | 'auto' | 'all'
|
|
143
|
+
jevSource: 'typesafe' | 'zen'
|
|
144
|
+
/** Only the general ladder: the four workers replaced the per-field rules (2026-10-12). */
|
|
145
|
+
rules: { general: Rule }
|
|
146
|
+
/**
|
|
147
|
+
* The models the user ticked (docs/specs/2026-10-12-worker-tiers.md): worker agent names and
|
|
148
|
+
* `general-purpose:<model>` for Claude's own. Empty means every model. Rungs run, and the fill
|
|
149
|
+
* picks, only among these.
|
|
150
|
+
*/
|
|
151
|
+
allow: string[]
|
|
152
|
+
/** The user's operating modes; none is built in. */
|
|
153
|
+
modes: Mode[]
|
|
154
|
+
/** The mode that is on, by id; absent when none is. */
|
|
155
|
+
activeMode?: string
|
|
156
|
+
/**
|
|
157
|
+
* When the active mode was turned on (epoch ms): a mode that runs until the quota resets ends at
|
|
158
|
+
* the first reset after this.
|
|
159
|
+
*/
|
|
160
|
+
activeSince?: number
|
|
161
|
+
providers: Record<string, boolean>
|
|
162
|
+
/**
|
|
163
|
+
* What ran when a pinned tier's agent was unavailable, before the ladder (2026-10-11). Kept so a
|
|
164
|
+
* stored choice survives; the ladder moves one rung up instead.
|
|
165
|
+
*/
|
|
166
|
+
fallback: TierTarget
|
|
167
|
+
keepWarm: boolean
|
|
168
|
+
keepWarmHours: 1 | 2 | 4 | 8
|
|
169
|
+
keepWarmMinTokens: number
|
|
170
|
+
compactWith: 'haiku' | 'session'
|
|
171
|
+
handoffSkill: string
|
|
172
|
+
handoffAfter: 'continue' | 'confirm' | 'copy'
|
|
173
|
+
handoffButton: 'advised' | 'always'
|
|
174
|
+
/** Context percent at which the context reads heavy (and the swamp band shows, when on). */
|
|
175
|
+
swampAt: number
|
|
176
|
+
/** The heavy-context band; off unless switched on. */
|
|
177
|
+
swampAlert: boolean
|
|
178
|
+
layout: 'dashboard' | 'minimal'
|
|
179
|
+
appearance: 'auto' | 'dark' | 'light'
|
|
180
|
+
language: 'auto' | Lang
|
|
181
|
+
/** Band parts switched off: 'timer' | 'reason' | 'route'. */
|
|
182
|
+
hide: string[]
|
|
183
|
+
/** Band chips switched on, off by default: 'context' | 'limits'. */
|
|
184
|
+
extras: string[]
|
|
185
|
+
setupDone: boolean
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** The admin API always returns a complete normalized settings object. */
|
|
189
|
+
export type ModSettingsSnapshot = {
|
|
190
|
+
settings: Settings
|
|
191
|
+
revision: number
|
|
192
|
+
stored: boolean
|
|
193
|
+
/** The stored settings still held field overrides or Auto, which the four workers replaced; true until the next save. */
|
|
194
|
+
legacy?: boolean
|
|
195
|
+
}
|
|
196
|
+
/** Arrays and rule mode changes are atomic; other edits are rebased by field path. */
|
|
197
|
+
export type SettingsChange = { path: string[]; value?: unknown; remove?: boolean }
|
|
198
|
+
export type SettingsSync = { schemaVersion?: number; revision: number | null; pending: SettingsChange[]; migrationChecked: boolean; migration: Settings | null }
|
|
199
|
+
|
|
200
|
+
/** A judge's answer for the main chat's next prompt. */
|
|
201
|
+
export type Verdict = { effort: Effort; sure?: number; why: string }
|
|
202
|
+
|
|
203
|
+
/** The effort the main chat runs at now, and who set it. */
|
|
204
|
+
export type Pick = Verdict & { by: JudgeKind | 'manual' | 'followup'; at: number }
|
|
205
|
+
|
|
206
|
+
/** A judge's answer for a delegated task; a judge that names no kind means do. */
|
|
207
|
+
export type WorkerVerdict = { domain: Domain; level: Level; kind?: Kind; effort: Effort; sure?: number; why: string }
|
|
208
|
+
|
|
209
|
+
/** What a spawn of ripple:auto (or a taken-over spawn) was turned into. */
|
|
210
|
+
export type WorkerPick = WorkerVerdict & {
|
|
211
|
+
/** The ladder rung that ran it (absent for explicit choices). */
|
|
212
|
+
rung?: Rung
|
|
213
|
+
/** One-based position in the selected rung; skipped entries explain ordered fallback. */
|
|
214
|
+
position?: number
|
|
215
|
+
skipped?: { rung: Rung; position: number; model: string; reason: string }[]
|
|
216
|
+
target: TierTarget
|
|
217
|
+
by: JudgeKind | 'marker' | 'default'
|
|
218
|
+
ms: number
|
|
219
|
+
/** Set when the tier's own agent could not run and the fallback did. */
|
|
220
|
+
fallbackReason?: string
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export type AgentState = 'running' | 'waiting' | 'done' | 'failed'
|
|
224
|
+
|
|
225
|
+
export type AgentRec = {
|
|
226
|
+
id: string
|
|
227
|
+
description: string
|
|
228
|
+
/** The agent type that ran. */
|
|
229
|
+
type: string
|
|
230
|
+
model?: string
|
|
231
|
+
pick?: WorkerPick
|
|
232
|
+
state: AgentState
|
|
233
|
+
/** The tool it is in now, in a few words. */
|
|
234
|
+
now?: string
|
|
235
|
+
toolSince?: number
|
|
236
|
+
startedAt: number
|
|
237
|
+
endedAt?: number
|
|
238
|
+
/** Weighted tokens (spec §5 stats weights). */
|
|
239
|
+
cost: number
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** The main chat's prompt cache as far as its responses show it. */
|
|
243
|
+
export type CacheMemo = {
|
|
244
|
+
ttlMs: number
|
|
245
|
+
lastReplyAt: number
|
|
246
|
+
expiresAt: number
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** Keep-warm bookkeeping for this chat. */
|
|
250
|
+
export type WarmState = {
|
|
251
|
+
pings: number
|
|
252
|
+
/** Weighted tokens the pings cost. */
|
|
253
|
+
cost: number
|
|
254
|
+
/** Set when keep-warm stopped by itself, with why. */
|
|
255
|
+
stopped?: string
|
|
256
|
+
lastPingAt?: number
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** The hottest plan window at or above the alert line. */
|
|
260
|
+
export type Hot = { kind: string; percent: number; resetsAt?: string }
|
|
261
|
+
|
|
262
|
+
export type Stats = {
|
|
263
|
+
prompts: number
|
|
264
|
+
requests: number
|
|
265
|
+
input: number
|
|
266
|
+
write: number
|
|
267
|
+
read: number
|
|
268
|
+
out: number
|
|
269
|
+
byEffort: Partial<Record<Effort, { prompts: number; cost: number }>>
|
|
270
|
+
judge: { haiku: number; jev: number; model: number; ms: number; tokens: number }
|
|
271
|
+
workers: Partial<Record<Tier, number>>
|
|
272
|
+
warm: { pings: number; cost: number }
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export type HandoffKind = 'quick' | 'full'
|
|
276
|
+
/** `ready`: written, waiting on Confirm first's card; `opened`: a new session was opened with it. */
|
|
277
|
+
export type HandoffStage = 'writing' | 'clearing' | 'done' | 'ready' | 'opened' | 'copied' | 'failed'
|
|
278
|
+
export type SetupStep = 1 | 2 | 3 | 4
|
|
279
|
+
export type ResultStage = 'handingOff' | 'handoffReady' | 'handoffDone' | 'compacting' | 'compacted' | 'failed'
|
|
280
|
+
export type JevState = {
|
|
281
|
+
source: 'env' | 'file' | 'pasted' | 'zen' | null
|
|
282
|
+
test: { state: 'idle' | 'testing' | 'ok' | 'fail'; message?: string }
|
|
283
|
+
}
|
|
284
|
+
|
|
21
285
|
declare module 'claude-code' {
|
|
22
286
|
interface PluginState {
|
|
23
|
-
|
|
287
|
+
ripple: {
|
|
24
288
|
line: StatusLine
|
|
25
289
|
last: StatusRequest | null
|
|
26
290
|
requests: StatusRequest[]
|
|
27
291
|
logOpen: boolean
|
|
28
292
|
onlySession: boolean
|
|
29
293
|
bandHidden: boolean
|
|
294
|
+
settings: Settings | null
|
|
295
|
+
settingsSync: SettingsSync
|
|
296
|
+
settingsBase: Settings | null
|
|
297
|
+
lang: Lang
|
|
298
|
+
pick: Pick | null
|
|
299
|
+
deciding: boolean
|
|
300
|
+
paused: boolean
|
|
301
|
+
agents: AgentRec[]
|
|
302
|
+
cache: CacheMemo | null
|
|
303
|
+
warm: WarmState
|
|
304
|
+
context: { percent: number; tokens: number; window: number } | null
|
|
305
|
+
hot: Hot | null
|
|
306
|
+
hotHidden: number | null
|
|
307
|
+
saveUntil: number | null
|
|
308
|
+
swampHidden: number | null
|
|
309
|
+
coldHidden: boolean
|
|
310
|
+
judgeDown: string | null
|
|
311
|
+
advice: string | null
|
|
312
|
+
handoff: { stage: HandoffStage; kind: HandoffKind; text?: string } | null
|
|
313
|
+
panel: 'settings' | 'setup' | 'compact' | 'handoff' | null
|
|
314
|
+
busy: boolean
|
|
315
|
+
decidingSince: number | null
|
|
316
|
+
heldPick: Pick | null
|
|
317
|
+
appEffort: Effort | number | null
|
|
318
|
+
modelIs: string | null
|
|
319
|
+
lastRequest: { model: string; appEffort?: string | number; sentEffort?: string | number } | null
|
|
320
|
+
lastSpawn: WorkerPick | null
|
|
321
|
+
lastRealReplyAt: number | null
|
|
322
|
+
stats: Stats
|
|
323
|
+
promptCount: number
|
|
324
|
+
adviceQueue: string | null
|
|
325
|
+
handoffQueued: boolean
|
|
326
|
+
handoffWaiting: boolean
|
|
327
|
+
handoffChoiceKind: HandoffKind
|
|
328
|
+
handoffChoiceAfter: 'continue' | 'confirm' | 'copy'
|
|
329
|
+
result: { stage: ResultStage; detail?: string } | null
|
|
330
|
+
settingsDraft: Settings | null
|
|
331
|
+
setupStep: SetupStep
|
|
332
|
+
compactNote: string
|
|
333
|
+
effortMenuOpen: boolean
|
|
334
|
+
agentsOpen: boolean
|
|
335
|
+
agentsShowDone: boolean
|
|
336
|
+
jev: JevState
|
|
337
|
+
routerModels: RouterModel[]
|
|
338
|
+
/** The router's rung choices and presets (GET /api/mod-options), for the quick settings. */
|
|
339
|
+
ladderOptions: LadderOptions | null
|
|
340
|
+
/** The active mode the eager note was last sent for (`modes.ts modeKey`); cleared on compaction. */
|
|
341
|
+
modeNoted: string | null
|
|
342
|
+
judgeDownHidden: string | null
|
|
343
|
+
/** Judge failure reasons already said this session. */
|
|
344
|
+
judgeSeen: string[]
|
|
345
|
+
judgeRuns: JudgeRun[]
|
|
346
|
+
judgeDownNetwork: boolean
|
|
347
|
+
limit: Hot | null
|
|
348
|
+
demo: 'cold' | 'swamp' | 'hot' | 'down' | null
|
|
30
349
|
}
|
|
31
350
|
}
|
|
32
351
|
}
|