Clawd animates above the prompt by tool use and mirrors to a Cardputer over BLE — follow if you like : https://x.com/hawkieslab

Hawkies' Lab の Claude Code プラグイン(Mods)マーケットプレイス。
follow if you like : https://x.com/hawkieslab
/plugin marketplace add hawkymisc/claude-plugins
/plugin install clawd-mods@hawkymisc-claude-plugins
/plugin install gh-board@hawkymisc-claude-plugins
| 名前 | 説明 |
|---|---|
| clawd-mods | ツール使用に応じた Clawd アニメをプロンプト上部に表示し、BLE で Cardputer ADV にミラーする(プラグイン本体は mod/、bridge/ と firmware/ は任意の周辺機器向け) |
| gh-board | セッション開始時とターン終了時に GitHub の PR / Issue 一覧を右ペインに表示する |
hooks/register.tsx 367 lines1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register, Timer } from 'claude-code'
3
4import type { BleState, View } from '../types'
5import { RASTER_COLUMNS, RASTER_ROWS, animSvg, rasterCells, tickFor } from './draw'
6import { Tracker, animOf, captionOf, eventBody, sameView } from './logic'
7import { ANIMS } from './sprites'
8import type { AnimName } from './sprites'
9
10const PLUGIN = 'clawd-mods'
11const viewAtom = atom({ plugin: 'clawd-mods', key: 'view' } as const, { state: 'idle' } as View)
12const bleAtom = atom({ plugin: 'clawd-mods', key: 'ble' } as const, 'unknown' as BleState)
13const tickAtom = atom({ plugin: 'clawd-mods', key: 'tick' } as const, 0)
14// `/clawd-mods demo` 再生中のアニメ番号。null なら通常表示
15const demoAtom = atom({ plugin: 'clawd-mods', key: 'demo' } as const, null as number | null)
16
17const ERROR_MS = 1500
18const FLUSH_MS = 150
19const STATUS_MS = 5000
20const TERMINAL_TICK_MS = 100
21// bridge 再起動・10 分の stale 掃除 (SPEC §4) で消えないよう、現在の状態を定期再送する
22const HEARTBEAT_MS = 60_000
23const DEMO_STEP_MS = 3000
24const DEMO_NAMES = Object.keys(ANIMS) as AnimName[]
25const USAGE = '使い方: /clawd-mods demo — プロンプト上の帯で全アニメを 1 つ 3 秒ずつ再生します'
26
27type Ctx = {
28 tracker: Tracker
29 session: string
30 label: string
31 socketPath: string
32 shown: View
33 pending: View | null
34 isSending: boolean
35 lastError: string
36 isStarted: boolean
37 startScheduled: boolean
38 transient: Timer | undefined
39 terminalTimer: Timer | undefined
40 loops: Timer[]
41 demoTimer: Timer | undefined
42 isCommandRegistered: boolean
43}
44
45function newCtx(): Ctx {
46 return {
47 tracker: new Tracker(),
48 session: '',
49 label: '',
50 socketPath: '',
51 shown: { state: 'idle' },
52 pending: null,
53 isSending: false,
54 lastError: '',
55 isStarted: false,
56 startScheduled: false,
57 transient: undefined,
58 terminalTimer: undefined,
59 loops: [],
60 demoTimer: undefined,
61 isCommandRegistered: false,
62 }
63}
64
65function errText(e: unknown): string {
66 if (e instanceof Error) return e.message
67 if (typeof e === 'object' && e !== null) return JSON.stringify(e) // HookFailure 等
68 return String(e)
69}
70
71function logOnce($: EngineInterface, ctx: Ctx, text: string): void {
72 // 同じ失敗を毎回ログに積まない (bridge 停止中は FLUSH_MS 毎に失敗しうる)
73 if (text === ctx.lastError) return
74 ctx.lastError = text
75 $.ui.log(`${PLUGIN}: ${text}`)
76}
77
78async function publish($: EngineInterface, ctx: Ctx): Promise<void> {
79 const view = ctx.tracker.view()
80 if (sameView(view, ctx.shown)) return
81 ctx.shown = view
82 ctx.pending = view
83 await update($, viewAtom, () => view)
84}
85
86function later($: EngineInterface, ctx: Ctx, ms: number, fn: () => void): void {
87 ctx.transient?.cancel()
88 ctx.transient = $.clock.after(ms, () => {
89 fn()
90 void publish($, ctx)
91 })
92}
93
94async function post($: EngineInterface, ctx: Ctx, body: string): Promise<void> {
95 if (!ctx.socketPath) return
96 const res = await $.http.fetch('http://clawd/event', {
97 method: 'POST',
98 headers: { 'content-type': 'application/json' },
99 body,
100 socketPath: ctx.socketPath,
101 })
102 if (!res.ok) throw new Error(`bridge answered ${res.status}`)
103}
104
105async function flush($: EngineInterface, ctx: Ctx): Promise<void> {
106 if (ctx.isSending || ctx.pending === null) return
107 const view = ctx.pending
108 ctx.pending = null
109 ctx.isSending = true
110 try {
111 await post($, ctx, eventBody(ctx.session, ctx.label, view))
112 ctx.lastError = ''
113 // 停止表示のままにしない: 送れたなら bridge は生きている
114 if ((await read($, bleAtom)) === 'no-bridge') await pollStatus($, ctx)
115 } catch (e) {
116 // bridge 未起動は想定内 (D12): 帯の「未接続」で見せ、ログは同じ文面につき 1 回
117 logOnce($, ctx, `send failed: ${errText(e)}`)
118 await update($, bleAtom, () => 'no-bridge')
119 } finally {
120 ctx.isSending = false
121 }
122}
123
124async function pollStatus($: EngineInterface, ctx: Ctx): Promise<void> {
125 if (!ctx.socketPath) return
126 try {
127 const res = await $.http.fetch('http://clawd/status', { socketPath: ctx.socketPath })
128 if (!res.ok) throw new Error(`bridge answered ${res.status}`)
129 const ble = (JSON.parse(res.text) as { ble?: string }).ble
130 const next: BleState = ble === 'connected' ? 'connected' : ble === 'scanning' ? 'scanning' : 'disconnected'
131 await update($, bleAtom, () => next)
132 } catch (e) {
133 logOnce($, ctx, `status failed: ${errText(e)}`)
134 await update($, bleAtom, () => 'no-bridge')
135 }
136}
137
138function bleNoteOf(ble: BleState): string | undefined {
139 if (ble === 'connected' || ble === 'unknown') return undefined
140 return ble === 'no-bridge' ? 'Cardputer: 未接続 (bridge停止)' : 'Cardputer: 未接続'
141}
142
143function stopLoops(ctx: Ctx): void {
144 for (const t of ctx.loops) t.cancel()
145 ctx.loops = []
146}
147
148/**
149 * セッション情報を読み、送信ループを張る。session.start が来ない途中ロード
150 * (ホットリロード等) でも最初のフックで呼ばれる。再呼び出し時は張り直す。
151 */
152async function start($: EngineInterface, ctx: Ctx): Promise<void> {
153 ctx.isStarted = true
154 ctx.session = await $.session.id()
155 const cwd = await $.session.cwd()
156 ctx.label = cwd.split('/').filter(Boolean).pop() ?? 'claude'
157 const home = await $.env.get('HOME')
158 ctx.socketPath = home ? `${home}/.clawd-bridge/bridge.sock` : ''
159 stopLoops(ctx)
160 ctx.loops.push(
161 $.clock.every(FLUSH_MS, () => void flush($, ctx)),
162 $.clock.every(STATUS_MS, () => void pollStatus($, ctx)),
163 $.clock.every(HEARTBEAT_MS, () => {
164 ctx.pending ??= ctx.shown
165 }),
166 )
167 ctx.pending = ctx.shown
168 await pollStatus($, ctx)
169 if (!ctx.isCommandRegistered) {
170 try {
171 await $.command.register({ name: 'clawd-mods', description: 'Clawd: `demo` で全アニメを帯で再生' })
172 ctx.isCommandRegistered = true
173 } catch (err) {
174 // コマンドが無くても表示・送信は続ける
175 logHookFailure($, 'command.register', err)
176 }
177 }
178}
179
180/** 帯だけのローカル demo (bridge には送らない)。再実行で最初から。 */
181async function startDemo($: EngineInterface, ctx: Ctx): Promise<void> {
182 ctx.demoTimer?.cancel()
183 await update($, demoAtom, () => 0)
184 ctx.demoTimer = $.clock.every(DEMO_STEP_MS, () => {
185 void update($, demoAtom, i => (i === null || i + 1 >= DEMO_NAMES.length ? null : i + 1)).then(async () => {
186 if ((await read($, demoAtom)) === null) {
187 ctx.demoTimer?.cancel()
188 ctx.demoTimer = undefined
189 }
190 })
191 })
192}
193
194async function ensureStarted($: EngineInterface, ctx: Ctx): Promise<void> {
195 if (!ctx.isStarted) await start($, ctx)
196}
197
198function logHookFailure($: EngineInterface, hook: string, e: unknown): void {
199 $.ui.log(`${PLUGIN}: ${hook} hook failed: ${errText(e)}`)
200}
201
202function startTerminalTicks($: EngineInterface, ctx: Ctx): void {
203 // ターミナルだけフレームを自前で送る。Desktop は SVG の SMIL が回す。
204 ctx.terminalTimer ??= $.clock.every(TERMINAL_TICK_MS, () => void update($, tickAtom, t => t + 1))
205}
206
207export const register: Register = on => {
208 const ctx = newCtx()
209
210 // 方針 (D12): 表示用 Mod の失敗で Claude を止めない。自前の処理は try で囲んでログに残し、
211 // next(e) はちょうど 1 回だけ呼ぶ。.catch は想定外の throw の最後の受け皿 (ログ付き)。
212
213 on('session.start', async ($, e, next) => {
214 const result = await next(e)
215 try {
216 ctx.tracker.reset()
217 ctx.shown = { state: 'idle' }
218 await update($, viewAtom, () => ctx.shown)
219 await start($, ctx)
220 } catch (err) {
221 logHookFailure($, 'session.start', err)
222 }
223 return result
224 })
225
226 on('session.end', async ($, e, next) => {
227 // 送信待ち・ループを先に止め、end の後に古い状態が届いてセッションが蘇るのを防ぐ
228 stopLoops(ctx)
229 ctx.pending = null
230 try {
231 await post($, ctx, eventBody(ctx.session || e.sessionId, ctx.label, 'end'))
232 } catch (err) {
233 logOnce($, ctx, `end failed: ${errText(err)}`)
234 }
235 ctx.isStarted = false
236 return next(e)
237 })
238
239 on('prompt.submit', async ($, e, next) => {
240 try {
241 await ensureStarted($, ctx)
242 ctx.transient?.cancel()
243 ctx.tracker.submit()
244 await publish($, ctx)
245 } catch (err) {
246 logHookFailure($, 'prompt.submit', err)
247 }
248 return next(e)
249 }).catch(($, e, next) => {
250 logHookFailure($, 'prompt.submit (catch)', next.error)
251 return next(e)
252 })
253
254 on('tool.call', async ($, e, next) => {
255 // サブエージェント内の呼び出しは親の Agent 表示で代表する (D10)
256 if (e.agentId !== undefined || e.tool_use_id === undefined) return next(e)
257 const id = e.tool_use_id
258 try {
259 await ensureStarted($, ctx)
260 ctx.tracker.toolStart(id, e.tool)
261 await publish($, ctx)
262 } catch (err) {
263 logHookFailure($, 'tool.call (before)', err)
264 }
265 const result = await next(e)
266 try {
267 // ユーザーの拒否 (deny) は失敗ではないので error にしない。ツール自身のエラーだけ
268 const isError = result.isError === true
269 ctx.tracker.toolEnd(id, isError)
270 await publish($, ctx)
271 if (isError) later($, ctx, ERROR_MS, () => ctx.tracker.recover())
272 } catch (err) {
273 logHookFailure($, 'tool.call (after)', err)
274 }
275 return result
276 }).catch(($, e, next) => {
277 logHookFailure($, 'tool.call (catch)', next.error)
278 return next(e)
279 })
280
281 // waiting は実際に許可ダイアログが出る時だけ。tool.check の ask は auto mode では
282 // 分類器が自動判定してユーザーに聞かないので使わない
283 on('classic.PermissionRequest', async ($, e, next) => {
284 try {
285 if (e.agent_id === undefined) {
286 ctx.tracker.toolAskByName(e.tool_name)
287 await publish($, ctx)
288 }
289 } catch (err) {
290 logHookFailure($, 'classic.PermissionRequest', err)
291 }
292 return next(e)
293 }).catch(($, e, next) => {
294 logHookFailure($, 'classic.PermissionRequest (catch)', next.error)
295 return next(e)
296 })
297
298 on('turn.complete', async ($, e, next) => {
299 if (e.agentId !== undefined) return next(e) // サブエージェントのターン完了は対象外 (D10)
300 try {
301 // done は次のプロンプトまで維持する (残っている error 復帰タイマーも止める)
302 ctx.transient?.cancel()
303 ctx.tracker.complete()
304 await publish($, ctx)
305 } catch (err) {
306 logHookFailure($, 'turn.complete', err)
307 }
308 return next(e)
309 })
310
311 on('command.run', { command: 'clawd-mods' }, async ($, e) => {
312 if (e.args.trim() !== 'demo') return { text: USAGE }
313 await startDemo($, ctx)
314 return { text: `Clawd demo: ${DEMO_NAMES.length} 種を ${DEMO_STEP_MS / 1000} 秒ずつ再生します` }
315 })
316
317 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
318 if (e.props.hasSurvey) return next(e)
319 // 描画は純粋でなければならない (state 書き込み禁止) ので、途中ロード時の初期化はタイマーで外に出す
320 if (!ctx.isStarted && !ctx.startScheduled) {
321 ctx.startScheduled = true
322 $.clock.after(0, () => void ensureStarted($, ctx).catch(err => logHookFailure($, 'lazy start', err)))
323 }
324 const view = await read($, viewAtom)
325 const bleNote = bleNoteOf(await read($, bleAtom))
326 const demo = await read($, demoAtom)
327 const demoName = demo === null ? undefined : DEMO_NAMES[demo]
328 const anim = demoName ?? animOf(view)
329 const caption = demoName ? `demo ${(demo ?? 0) + 1}/${DEMO_NAMES.length} · ${demoName}` : captionOf(view)
330
331 if (e.surface === 'terminal') {
332 const { Box, Text, Raster } = $.ui.resolve(e)
333 startTerminalTicks($, ctx)
334 const tick = await read($, tickAtom)
335 const cells = rasterCells(anim, tickFor(anim, tick * TERMINAL_TICK_MS))
336 return (
337 <Box flexDirection="row" alignItems="center">
338 <Raster key="clawd" columns={RASTER_COLUMNS} rows={RASTER_ROWS} cells={cells} />
339 <Box flexDirection="column" marginLeft={1}>
340 <Text>{caption}</Text>
341 {bleNote ? <Text dimColor>{bleNote}</Text> : null}
342 </Box>
343 </Box>
344 )
345 }
346
347 if (e.surface === 'desktop') {
348 const { Box, Text, Svg } = $.ui.resolve(e)
349 return (
350 <Box flexDirection="row" alignItems="center">
351 <Svg source={animSvg(anim, 3)} alt={`Clawd: ${caption}`} width={48} height={36} isInteractive />
352 <Box flexDirection="column" marginLeft={1}>
353 <Text>{caption}</Text>
354 {bleNote ? <Text dimColor>{bleNote}</Text> : null}
355 </Box>
356 </Box>
357 )
358 }
359
360 return next(e)
361 }).catch(($, e, next) => {
362 // 描画に失敗したら engine 既定の帯に戻す (プロンプトを壊さない)
363 logHookFailure($, 'ui.render (catch)', next.error)
364 return next(e)
365 })
366}
367hooks/draw.ts 101 lines1import { ANIMS, PALETTE, SPRITE_H, SPRITE_W } from './sprites'
2import type { AnimName } from './sprites'
3
4function px(frame: number[][], x: number, y: number): number {
5 return frame[y]?.[x] ?? 0
6}
7
8/** 1 フレームを横方向のランにまとめた rect 列 (SVG サイズ節約)。 */
9function frameRects(frame: number[][], size: number): string {
10 let out = ''
11 for (let y = 0; y < SPRITE_H; y++) {
12 let x = 0
13 while (x < SPRITE_W) {
14 const c = px(frame, x, y)
15 if (c === 0) {
16 x++
17 continue
18 }
19 let end = x + 1
20 while (end < SPRITE_W && px(frame, end, y) === c) end++
21 out += `<rect x="${x * size}" y="${y * size}" width="${(end - x) * size}" height="${size}" fill="${PALETTE[c] ?? '#000'}"/>`
22 x = end
23 }
24 }
25 return out
26}
27
28/**
29 * アニメーションを SMIL の discrete 切替で 1 枚の SVG にする。
30 * Desktop の `Svg isInteractive` が自前で回すので再描画は要らない。
31 */
32export function animSvg(name: AnimName, size: number): string {
33 const { ms, frames } = ANIMS[name]
34 const n = frames.length
35 const dur = `${(ms * n) / 1000}s`
36 const keyTimes = Array.from({ length: n + 1 }, (_, i) => (i / n).toFixed(4)).join(';')
37 const groups = frames
38 .map((f, i) => {
39 const values = Array.from({ length: n + 1 }, (_, k) => (k === i ? 'visible' : 'hidden')).join(';')
40 const anim =
41 n > 1
42 ? `<animate attributeName="visibility" values="${values}" keyTimes="${keyTimes}" calcMode="discrete" dur="${dur}" repeatCount="indefinite"/>`
43 : ''
44 return `<g visibility="${i === 0 ? 'visible' : 'hidden'}">${anim}${frameRects(f, size)}</g>`
45 })
46 .join('')
47 const w = SPRITE_W * size
48 const h = SPRITE_H * size
49 return `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}" shape-rendering="crispEdges">${groups}</svg>`
50}
51
52const DEFAULT = 0x01000000
53
54function rgb(c: number): number {
55 const hex = PALETTE[c]
56 return c === 0 || hex === undefined ? DEFAULT : parseInt(hex.slice(1), 16)
57}
58
59/** ターミナル用: `▀` 1 セルで縦 2 ドット。SPRITE_W 列 × SPRITE_H/2 行。 */
60export function rasterCells(name: AnimName, tick: number): string {
61 const { frames } = ANIMS[name]
62 const frame = frames[tick % frames.length] ?? []
63 const words = new Uint32Array(SPRITE_W * (SPRITE_H / 2) * 3)
64 let i = 0
65 for (let row = 0; row < SPRITE_H / 2; row++) {
66 for (let x = 0; x < SPRITE_W; x++) {
67 const top = px(frame, x, row * 2)
68 const bottom = px(frame, x, row * 2 + 1)
69 words[i++] = top === 0 && bottom === 0 ? 0x20 : top === 0 ? 0x2584 : 0x2580
70 words[i++] = top === 0 ? rgb(bottom) : rgb(top)
71 words[i++] = top === 0 ? DEFAULT : rgb(bottom)
72 }
73 }
74 return toBase64(new Uint8Array(words.buffer))
75}
76
77const B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
78
79/** 標準パディング付き base64 (実行環境の toBase64 有無に依存しない)。 */
80export function toBase64(bytes: Uint8Array): string {
81 let out = ''
82 for (let i = 0; i < bytes.length; i += 3) {
83 const a = bytes[i] ?? 0
84 const b = bytes[i + 1]
85 const c = bytes[i + 2]
86 const n = (a << 16) | ((b ?? 0) << 8) | (c ?? 0)
87 out += B64[(n >> 18) & 63]! + B64[(n >> 12) & 63]!
88 out += b === undefined ? '=' : B64[(n >> 6) & 63]!
89 out += c === undefined ? '=' : B64[n & 63]!
90 }
91 return out
92}
93
94/** フレーム送り間隔: アニメの ms をターミナル tick (ms) で割った数。 */
95export function tickFor(name: AnimName, elapsedMs: number): number {
96 return Math.floor(elapsedMs / ANIMS[name].ms)
97}
98
99export const RASTER_COLUMNS = SPRITE_W
100export const RASTER_ROWS = SPRITE_H / 2
101hooks/logic.ts 136 lines1import type { Category, View } from '../types'
2import type { AnimName } from './sprites'
3
4export type Phase = 'idle' | 'thinking' | 'done' | 'error'
5
6const CATEGORY: Record<string, Category> = {
7 Read: 'read',
8 Grep: 'read',
9 Glob: 'read',
10 LS: 'read',
11 NotebookRead: 'read',
12 Edit: 'write',
13 MultiEdit: 'write',
14 Write: 'write',
15 NotebookEdit: 'write',
16 Bash: 'bash',
17 BashOutput: 'bash',
18 KillShell: 'bash',
19 WebFetch: 'web',
20 WebSearch: 'web',
21 Agent: 'agent',
22 Task: 'agent',
23}
24
25export function categoryOf(tool: string): Category {
26 return CATEGORY[tool] ?? 'other'
27}
28
29/** BLE に載せるツール名: MCP は末尾のツール名だけ、12 文字まで (SPEC §3)。 */
30export function shortToolName(tool: string): string {
31 const tail = tool.startsWith('mcp__') ? (tool.split('__').pop() ?? '') : tool
32 // bridge はスナップショット区切り (| ,) を含む名前を 400 で拒否するので、許可文字以外は _ に
33 const name = tail.replace(/[^A-Za-z0-9_.-]/g, '_').slice(0, 12)
34 return name || 'mcp'
35}
36
37type Call = { id: string; tool: string; isWaiting: boolean }
38
39/**
40 * メインループのツール呼び出しと turn の進行から、今見せる状態を決める。
41 * 優先度: waiting > error > 実行中ツール (最後に始まったもの) > phase。
42 */
43export class Tracker {
44 phase: Phase = 'idle'
45 private calls: Call[] = []
46
47 submit(): void {
48 this.phase = 'thinking'
49 this.calls = []
50 }
51
52 toolStart(id: string, tool: string): void {
53 this.calls.push({ id, tool, isWaiting: false })
54 if (this.phase !== 'error') this.phase = 'thinking'
55 }
56
57 /**
58 * 許可ダイアログ (classic.PermissionRequest) は tool_use_id を持たないので、
59 * 同名で実行中かつまだ待っていない最新の呼び出しを待ち状態にする。
60 */
61 toolAskByName(tool: string): void {
62 const call = [...this.calls].reverse().find(c => c.tool === tool && !c.isWaiting)
63 if (call) call.isWaiting = true
64 }
65
66 toolEnd(id: string, isError: boolean): void {
67 this.calls = this.calls.filter(c => c.id !== id)
68 if (isError) this.phase = 'error'
69 else if (this.phase !== 'error') this.phase = 'thinking'
70 }
71
72 /** error 表示の時間切れ。 */
73 recover(): void {
74 if (this.phase === 'error') this.phase = 'thinking'
75 }
76
77 complete(): void {
78 this.calls = []
79 this.phase = 'done'
80 }
81
82 reset(): void {
83 this.calls = []
84 this.phase = 'idle'
85 }
86
87 view(): View {
88 const waiting = this.calls.find(c => c.isWaiting)
89 if (waiting) return { state: 'waiting', tool: waiting.tool }
90 if (this.phase === 'error') return { state: 'error' }
91 const top = this.calls[this.calls.length - 1]
92 if (top) return { state: 'tool', category: categoryOf(top.tool), tool: top.tool }
93 return { state: this.phase }
94 }
95}
96
97export function animOf(view: View): AnimName {
98 return view.state === 'tool' ? (view.category ?? 'other') : view.state
99}
100
101const VERB: Record<AnimName, string> = {
102 idle: 'Idle',
103 thinking: 'Thinking…',
104 read: 'Reading',
105 write: 'Writing',
106 bash: 'Running',
107 web: 'Browsing',
108 agent: 'Delegating',
109 other: 'Working',
110 done: 'Done!',
111 error: 'Oops',
112 waiting: 'Waiting for you',
113}
114
115export function captionOf(view: View): string {
116 const verb = VERB[animOf(view)]
117 return view.tool ? `${verb} · ${view.tool}` : verb
118}
119
120export function sameView(a: View, b: View): boolean {
121 return a.state === b.state && a.category === b.category && a.tool === b.tool
122}
123
124/** bridge へ送る JSON (SPEC §3)。パス・コマンドは含めない (D7)。 */
125export function eventBody(session: string, label: string, view: View | 'end'): string {
126 if (view === 'end') return JSON.stringify({ v: 1, session, label, state: 'end' })
127 return JSON.stringify({
128 v: 1,
129 session,
130 label: label.slice(0, 12),
131 state: view.state,
132 ...(view.category ? { category: view.category } : {}),
133 ...(view.tool ? { tool: shortToolName(view.tool) } : {}),
134 })
135}
136hooks/sprites.ts 8 lines1// 生成ファイル: sprites/gen.py から生成。直接編集しない。
2export const SPRITE_W = 16
3export const SPRITE_H = 12
4export const PALETTE: readonly string[] = ["#000000", "#D97757", "#1F1F1F", "#FFFFFF", "#9A9A9A", "#5BA4E6", "#F2C94C", "#E5484D"]
5export type AnimName = 'idle' | 'thinking' | 'read' | 'write' | 'bash' | 'web' | 'agent' | 'other' | 'done' | 'error' | 'waiting'
6export type Anim = { ms: number; frames: number[][][] }
7export const ANIMS: Record<AnimName, Anim> = {"idle": {"ms": 600, "frames": [[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]}, "thinking": {"ms": 300, "frames": [[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]}, "read": {"ms": 450, "frames": [[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 1, 0, 0], [0, 0, 0, 3, 2, 2, 3, 4, 4, 3, 2, 2, 3, 0, 0, 0], [0, 0, 0, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 1, 0, 0], [0, 0, 0, 3, 2, 2, 3, 4, 4, 3, 2, 2, 3, 0, 0, 0], [0, 0, 0, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 1, 0, 0], [0, 0, 0, 3, 2, 2, 3, 4, 4, 3, 2, 2, 3, 0, 0, 0], [0, 0, 0, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 1, 0, 0], [0, 0, 0, 3, 2, 2, 3, 4, 4, 3, 2, 2, 3, 0, 0, 0], [0, 0, 0, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 0], [0, 0, 1, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 1, 0, 0], [0, 0, 0, 3, 2, 2, 3, 4, 4, 3, 3, 3, 3, 0, 0, 0], [0, 0, 0, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 1, 0, 0], [0, 0, 0, 3, 3, 3, 3, 4, 4, 3, 2, 3, 2, 0, 0, 0], [0, 0, 0, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 1, 0, 0], [0, 0, 0, 3, 2, 3, 2, 4, 4, 3, 2, 3, 2, 0, 0, 0], [0, 0, 0, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 1, 0, 0], [0, 0, 0, 3, 2, 3, 2, 4, 4, 3, 2, 3, 2, 0, 0, 0], [0, 0, 0, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]}, "write": {"ms": 220, "frames": [[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 6, 0, 0, 0, 0], [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 3, 6, 3, 3, 3, 3], [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 5, 3, 3, 3, 3], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 6, 0, 0, 0], [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 3, 3, 6, 3, 3, 3], [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 5, 3, 3, 3], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 6, 0, 0], [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 3, 3, 3, 6, 3, 3], [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 2, 5, 3, 3], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 6, 0], [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 3, 3, 3, 3, 6, 3], [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 2, 3, 5, 3], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 6], [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 3, 3, 3, 3, 3, 6], [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 2, 3, 2, 5], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3]]]}, "bash": {"ms": 250, "frames": [[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0], [0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 1, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 4], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 4], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 4], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]}, "web": {"ms": 260, "frames": [[[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0], [0, 0, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [3, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0], [5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0], [5, 0, 0, 5, 5, 0, 0, 5, 5, 0, 0, 5, 5, 0, 0, 5]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0], [0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 1, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 3], [0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0], [0, 0, 5, 5, 0, 0, 5, 5, 0, 0, 5, 5, 0, 0, 5, 5]], [[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0], [0, 0, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [3, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0], [0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 5, 0], [0, 5, 5, 0, 0, 5, 5, 0, 0, 5, 5, 0, 0, 5, 5, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0], [0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 1, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 3], [0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0], [5, 5, 0, 0, 5, 5, 0, 0, 5, 5, 0, 0, 5, 5, 0, 0]]]}, "agent": {"ms": 300, "frames": [[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 0, 4], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4], [0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]}, "other": {"ms": 300, "frames": [[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 0, 4], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 4, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]}, "done": {"ms": 250, "frames": [[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 6, 0], [0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0], [6, 1, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 1, 6], [0, 0, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]}, "error": {"ms": 500, "frames": [[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 0, 0], [0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0], [0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0], [0, 6, 6, 6, 6, 2, 6, 6, 6, 6, 2, 6, 6, 6, 6, 0], [0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0], [0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0], [0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0], [0, 0, 0, 6, 0, 6, 0, 0, 0, 0, 6, 0, 6, 0, 0, 0], [0, 0, 0, 6, 0, 6, 0, 0, 0, 0, 6, 0, 6, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0], [0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 0, 0], [0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0], [0, 6, 6, 6, 6, 2, 6, 6, 6, 6, 2, 6, 6, 6, 6, 0], [0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0], [0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0], [0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0], [0, 0, 0, 6, 0, 6, 0, 0, 0, 0, 6, 0, 6, 0, 0, 0], [0, 0, 0, 6, 0, 6, 0, 0, 0, 0, 6, 0, 6, 0, 0, 0]]]}, "waiting": {"ms": 300, "frames": [[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0], [0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 1, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]}}
8types/index.d.ts 11 lines1export type Category = 'read' | 'write' | 'bash' | 'web' | 'agent' | 'other'
2export type State = 'idle' | 'thinking' | 'tool' | 'done' | 'error' | 'waiting'
3export type View = { state: State; category?: Category; tool?: string }
4export type BleState = 'unknown' | 'connected' | 'scanning' | 'disconnected' | 'no-bridge'
5
6declare module 'claude-code' {
7 interface PluginState {
8 'clawd-mods': { view: View; ble: BleState; tick: number; demo: number | null }
9 }
10}
11