@scrylog/cli 0.1.4 → 0.3.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.
Files changed (97) hide show
  1. package/README.md +46 -7
  2. package/package.json +13 -10
  3. package/src/api/docs/sessions.ts +3 -2
  4. package/src/api/docs/system.ts +3 -0
  5. package/src/api/docs/usage.ts +2 -2
  6. package/src/api/routes/sessions.ts +6 -2
  7. package/src/api/routes/system.ts +4 -1
  8. package/src/api/routes/webhooks/claude.ts +9 -21
  9. package/src/api/routes/webhooks/opencode.ts +6 -1
  10. package/src/api/routes.ts +1 -1
  11. package/src/api/schemas/common.ts +8 -0
  12. package/src/api/schemas/sessions.ts +15 -1
  13. package/src/api/schemas/usage.ts +1 -0
  14. package/src/cli/commands.ts +170 -26
  15. package/src/cli/index.ts +18 -0
  16. package/src/cli/program.ts +175 -0
  17. package/src/daemon/collectors/claude/collector.ts +11 -1
  18. package/src/daemon/collectors/claude/discovery.ts +2 -23
  19. package/src/daemon/collectors/codex/collector.ts +3 -3
  20. package/src/daemon/collectors/git.ts +60 -2
  21. package/src/daemon/collectors/herdr/collector.ts +128 -0
  22. package/src/daemon/collectors/herdr/index.ts +2 -0
  23. package/src/daemon/collectors/herdr/normalization.ts +111 -0
  24. package/src/daemon/collectors/opencode/collector.ts +4 -2
  25. package/src/daemon/collectors/opencode-db.ts +17 -5
  26. package/src/daemon/collectors/tmux/collector.ts +21 -1
  27. package/src/daemon/collectors/tmux/enrichment.ts +1 -0
  28. package/src/daemon/collectors/usage.ts +115 -49
  29. package/src/daemon/index.ts +2 -0
  30. package/src/daemon/store.ts +109 -14
  31. package/src/postinstall.cjs +11 -0
  32. package/src/shared/config.ts +33 -0
  33. package/src/shared/session-exclusions.ts +5 -0
  34. package/src/shared/session-view.ts +67 -6
  35. package/src/shared/terminal-capabilities.ts +130 -0
  36. package/src/shared/types.ts +33 -2
  37. package/src/shared/version.ts +44 -0
  38. package/src/tui/App.tsx +240 -0
  39. package/src/tui/assets/providers/SOURCES.md +21 -0
  40. package/src/tui/assets/providers/claude-terminal.png +0 -0
  41. package/src/tui/assets/providers/claude-terminal.svg +62 -0
  42. package/src/tui/assets/providers/claude.png +0 -0
  43. package/src/tui/assets/providers/copilot.png +0 -0
  44. package/src/tui/assets/providers/copilot.svg +44 -0
  45. package/src/tui/assets/providers/openai-terminal.png +0 -0
  46. package/src/tui/assets/providers/openai-terminal.svg +62 -0
  47. package/src/tui/assets/providers/openai.png +0 -0
  48. package/src/tui/assets/providers/opencode-terminal.png +0 -0
  49. package/src/tui/assets/providers/opencode-terminal.svg +62 -0
  50. package/src/tui/assets/providers/opencode.png +0 -0
  51. package/src/tui/assets/providers/shell.png +0 -0
  52. package/src/tui/assets/providers/shell.svg +23 -0
  53. package/src/tui/assets/providers/unknown.png +0 -0
  54. package/src/tui/assets/providers/unknown.svg +23 -0
  55. package/src/tui/client.ts +22 -8
  56. package/src/tui/components/BindingsModal.tsx +82 -0
  57. package/src/tui/components/DashboardHeader.tsx +256 -0
  58. package/src/tui/components/KeyBar.tsx +67 -0
  59. package/src/tui/components/SessionDetailModal.tsx +169 -0
  60. package/src/tui/components/SessionsView.tsx +184 -0
  61. package/src/tui/components/TabBar.tsx +40 -0
  62. package/src/tui/components/UsageSummaryPane.tsx +272 -0
  63. package/src/tui/components/UsageView.tsx +242 -0
  64. package/src/tui/components/tool-icons.ts +24 -0
  65. package/src/tui/index.tsx +106 -0
  66. package/src/tui/keybindings.ts +49 -0
  67. package/src/tui/model.ts +295 -0
  68. package/src/tui/state.ts +77 -0
  69. package/src/tui/theme.ts +110 -0
  70. package/src/usage/README.md +3 -3
  71. package/src/usage/clients/anthropic-oauth-usage.ts +100 -20
  72. package/src/usage/clients/anthropic-web-usage.ts +133 -49
  73. package/src/usage/clients/claude-cli-probe.ts +458 -132
  74. package/src/usage/clients/codex-app-server.ts +354 -0
  75. package/src/usage/clients/codex-oauth-usage.ts +143 -16
  76. package/src/usage/clients/opencode-go-api.ts +100 -0
  77. package/src/usage/clients/opencode-go-usage.ts +163 -27
  78. package/src/usage/errors.ts +33 -0
  79. package/src/usage/index.ts +2 -1
  80. package/src/usage/local/opencode-go-local.ts +194 -0
  81. package/src/usage/mappers.ts +24 -15
  82. package/src/usage/planner.ts +89 -25
  83. package/src/usage/providers/claude.ts +203 -83
  84. package/src/usage/providers/codex.ts +92 -11
  85. package/src/usage/providers/opencode-go.ts +94 -16
  86. package/src/usage/resolvers/browser-cookies.ts +679 -69
  87. package/src/usage/resolvers/claude-auth.ts +150 -41
  88. package/src/usage/resolvers/claude-desktop-auth.ts +170 -0
  89. package/src/usage/resolvers/claude-web.ts +72 -6
  90. package/src/usage/resolvers/codex-auth.ts +74 -17
  91. package/src/usage/resolvers/keychain-coordinator.ts +397 -0
  92. package/src/usage/resolvers/opencode-go-web.ts +47 -6
  93. package/src/usage/types.ts +37 -2
  94. package/src/usage/web-session-cache.ts +37 -0
  95. package/src/neo-blessed.d.ts +0 -4
  96. package/src/tui/app.ts +0 -920
  97. package/src/tui/index.ts +0 -193
@@ -0,0 +1,240 @@
1
+ import { useKeyboard, useTerminalDimensions } from "@opentui/react";
2
+ import { useEffect, useReducer, useRef, useState } from "react";
3
+ import type { ScrylogConfig } from "../shared/config";
4
+ import type { SessionModel, StoreEvent } from "../shared/types";
5
+ import type { SessionListItem } from "../shared/session-view";
6
+ import { applySessionFilters, buildRows, moveSelection, sessionAttachCommand, visibleRowWindow } from "./model";
7
+ import { dashboardReducer, INITIAL_DASHBOARD_STATE } from "./state";
8
+ import type { DaemonClient } from "./client";
9
+ import { SessionsView } from "./components/SessionsView";
10
+ import { UsageView } from "./components/UsageView";
11
+ import { TabBar } from "./components/TabBar";
12
+ import { KeyBar } from "./components/KeyBar";
13
+ import { BindingsModal } from "./components/BindingsModal";
14
+ import { DashboardHeader, dashboardHeaderHeight } from "./components/DashboardHeader";
15
+ import { isInsideTmux } from "../shared/utils";
16
+ import type { DaemonVersionMismatch } from "../shared/version";
17
+
18
+ export interface AppOptions {
19
+ refreshMs: number;
20
+ includeUnknown?: boolean;
21
+ }
22
+
23
+ export interface AppProps {
24
+ client: DaemonClient;
25
+ options: AppOptions;
26
+ config: ScrylogConfig;
27
+ versionMismatch?: DaemonVersionMismatch;
28
+ onExit(): void;
29
+ onAttach(command: string[], sessionId: string): void;
30
+ }
31
+
32
+ export function App({ client, options, config, versionMismatch, onExit, onAttach }: AppProps) {
33
+ const { width, height } = useTerminalDimensions();
34
+ const paneHeight = Math.max(1, height - dashboardHeaderHeight(width) - 2);
35
+ const [state, dispatch] = useReducer(dashboardReducer, INITIAL_DASHBOARD_STATE);
36
+ const [spinnerFrame, setSpinnerFrame] = useState(0);
37
+ const stateRef = useRef(state);
38
+ const rowsRef = useRef<ReturnType<typeof buildRows>>([]);
39
+ const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
40
+ const knownStatesRef = useRef(new Map<string, SessionModel["state"]>());
41
+ stateRef.current = state;
42
+
43
+ useEffect(() => {
44
+ let active = true;
45
+ const refreshSessions = async () => {
46
+ const [status, sessionData] = await Promise.all([
47
+ client.getStatusSummary(options.includeUnknown),
48
+ client.getSessions(options.includeUnknown),
49
+ ]);
50
+ if (!active) return;
51
+ if (!status || !sessionData) {
52
+ dispatch({ type: "connection", connected: false });
53
+ return;
54
+ }
55
+ knownStatesRef.current = new Map(sessionData.sessions.map((session) => [session.id, session.state]));
56
+ dispatch({ type: "sessions-loaded", sessions: sessionData.sessions, counts: status.counts });
57
+ };
58
+ const refreshAll = async () => {
59
+ const usage = await client.getUsage();
60
+ if (active && usage) dispatch({ type: "usage-loaded", usage });
61
+ await refreshSessions();
62
+ };
63
+ const scheduleRefresh = (immediate: boolean) => {
64
+ if (debounceRef.current) clearTimeout(debounceRef.current);
65
+ if (immediate || config.tui.pushDebounceMs <= 0) {
66
+ debounceRef.current = null;
67
+ void refreshSessions();
68
+ return;
69
+ }
70
+ debounceRef.current = setTimeout(() => {
71
+ debounceRef.current = null;
72
+ void refreshSessions();
73
+ }, config.tui.pushDebounceMs);
74
+ };
75
+ const onStoreEvent = (event: StoreEvent | { type: "connected" } | { type: "disconnected" }) => {
76
+ if (event.type === "connected") {
77
+ dispatch({ type: "connection", connected: true });
78
+ void refreshAll();
79
+ } else if (event.type === "disconnected") {
80
+ dispatch({ type: "connection", connected: false });
81
+ } else if (event.type === "usage:updated") {
82
+ dispatch({ type: "usage-loaded", usage: event.usage });
83
+ } else if (event.type === "session:added" || event.type === "session:removed") {
84
+ scheduleRefresh(true);
85
+ } else if (event.type === "session:updated") {
86
+ const known = knownStatesRef.current.get(event.session.id);
87
+ scheduleRefresh(known === undefined || known !== event.session.state);
88
+ }
89
+ };
90
+
91
+ void refreshAll();
92
+ const polling = setInterval(() => void refreshAll(), options.refreshMs);
93
+ const unsubscribe = config.tui.usePushUpdates ? client.subscribeEvents(onStoreEvent) : undefined;
94
+ return () => {
95
+ active = false;
96
+ clearInterval(polling);
97
+ unsubscribe?.();
98
+ if (debounceRef.current) clearTimeout(debounceRef.current);
99
+ debounceRef.current = null;
100
+ };
101
+ }, [client, config.tui.pushDebounceMs, config.tui.usePushUpdates, options.includeUnknown, options.refreshMs]);
102
+
103
+ useEffect(() => {
104
+ if (state.view !== "sessions") return;
105
+ const animation = setInterval(() => setSpinnerFrame((frame) => (frame + 1) % 10), 180);
106
+ return () => clearInterval(animation);
107
+ }, [state.view]);
108
+
109
+ const filtered = applySessionFilters(state.sessions, state.filters, config.tui.standaloneMaxAgeHours);
110
+ const rows = buildRows(filtered, width < 110);
111
+ rowsRef.current = rows;
112
+ const usagePaneRows = state.view === "sessions" && state.usage ? 3 : 0;
113
+ const visibleRows = visibleRowWindow(rows, state.selectedSessionId, Math.max(4, height - dashboardHeaderHeight(width) - usagePaneRows - (state.mode === "search" ? 8 : 5)));
114
+
115
+ const openDetail = async (session: SessionListItem | undefined) => {
116
+ if (!session) return;
117
+ const detail = await client.getSessionDetail(session.id) ?? ({ ...session } as SessionModel);
118
+ dispatch({ type: "detail", session: detail });
119
+ };
120
+
121
+ const attach = (session: SessionListItem | undefined) => {
122
+ if (!session) return;
123
+ const command = sessionAttachCommand(session, isInsideTmux());
124
+ if (!command) {
125
+ dispatch({
126
+ type: "message",
127
+ message: session.source === "herdr"
128
+ ? "Herdr attach is unavailable because this pane has no terminal ID."
129
+ : "Attach is only available for sessions running inside tmux or herdr.",
130
+ });
131
+ return;
132
+ }
133
+ onAttach(command, session.id);
134
+ };
135
+
136
+ useKeyboard((key) => {
137
+ const currentState = stateRef.current;
138
+ const currentSelected = currentState.sessions.find((session) => session.id === currentState.selectedSessionId);
139
+ if ((key.ctrl && key.name === "c") || (key.name === "q" && currentState.mode === "list")) return onExit();
140
+ if (currentState.mode === "search") {
141
+ if (key.name === "escape" || key.name === "return" || key.name === "enter") dispatch({ type: "close-overlay" });
142
+ return;
143
+ }
144
+ if (currentState.mode === "detail" || currentState.mode === "message" || currentState.mode === "bindings") {
145
+ if (key.name === "escape" || key.name === "q") dispatch({ type: "close-overlay" });
146
+ if (key.name === "t" && currentState.detail) attach(currentState.detail as SessionListItem);
147
+ return;
148
+ }
149
+ if (key.name === "tab") {
150
+ dispatch({ type: "view", view: key.shift ? "sessions" : currentState.view === "sessions" ? "usage" : "sessions" });
151
+ return;
152
+ }
153
+ if (key.name === "u") return dispatch({ type: "view", view: "usage" });
154
+ if (key.name === "s") return dispatch({ type: "view", view: "sessions" });
155
+ if (key.name === "r") {
156
+ void Promise.all([client.getStatusSummary(options.includeUnknown), client.getSessions(options.includeUnknown), client.getUsage()])
157
+ .then(([status, sessions, usage]) => {
158
+ if (status && sessions) dispatch({ type: "sessions-loaded", sessions: sessions.sessions, counts: status.counts });
159
+ if (usage) dispatch({ type: "usage-loaded", usage });
160
+ });
161
+ return;
162
+ }
163
+ if (key.name === "?") return dispatch({ type: "bindings" });
164
+ if (currentState.view !== "sessions") return;
165
+ if (key.name === "up" || key.name === "k") return dispatch({ type: "select", id: moveSelection(rowsRef.current, currentState.selectedSessionId, -1) });
166
+ if (key.name === "down" || key.name === "j") return dispatch({ type: "select", id: moveSelection(rowsRef.current, currentState.selectedSessionId, 1) });
167
+ if (key.name === "escape") return dispatch({ type: "select", id: undefined });
168
+ if (key.name === "return" || key.name === "enter") return void openDetail(currentSelected);
169
+ if (key.name === "t") return attach(currentSelected);
170
+ if (key.name === "/") return dispatch({ type: "search" });
171
+ if (key.name === "a") return dispatch({ type: "toggle-actionable" });
172
+ if (key.name === "f") return dispatch({ type: "cycle-filters" });
173
+ });
174
+
175
+ const filterSummary = [
176
+ state.filters.query ? `q=${state.filters.query}` : null,
177
+ state.filters.actionableOnly ? "actionable" : null,
178
+ state.filters.tool !== "all" ? `tool=${state.filters.tool}` : null,
179
+ state.filters.state !== "all" ? `state=${state.filters.state}` : null,
180
+ ].filter(Boolean).join(" ");
181
+ const selectedSession = state.sessions.find((session) => session.id === state.selectedSessionId);
182
+
183
+ return (
184
+ <box width="100%" height="100%" flexDirection="column">
185
+ <DashboardHeader
186
+ sessions={state.sessions}
187
+ connected={state.daemonConnected}
188
+ spinnerFrame={spinnerFrame}
189
+ width={width}
190
+ versionMismatch={versionMismatch}
191
+ />
192
+ <TabBar
193
+ view={state.view}
194
+ onSelect={(next) => dispatch({ type: "view", view: next })}
195
+ />
196
+ <box
197
+ position={state.view === "sessions" ? "relative" : "absolute"}
198
+ top={state.view === "sessions" ? 0 : height + 2}
199
+ width="100%"
200
+ height={paneHeight}
201
+ >
202
+ <SessionsView
203
+ rows={visibleRows}
204
+ sessions={state.sessions}
205
+ selectedSessionId={state.selectedSessionId}
206
+ filters={state.filters}
207
+ mode={state.mode}
208
+ detail={state.detail}
209
+ message={state.message}
210
+ usage={state.usage}
211
+ iconMode={config.tui.providerIcons}
212
+ spinnerFrame={spinnerFrame}
213
+ width={width}
214
+ interactive={state.mode === "list" && state.view === "sessions"}
215
+ onQueryChange={(query) => dispatch({ type: "query", query })}
216
+ onSearchSubmit={() => dispatch({ type: "close-overlay" })}
217
+ onSelectSession={(id) => dispatch({ type: "select", id })}
218
+ onOpenSessionDetail={(session) => void openDetail(session)}
219
+ onScrollSelection={(direction) => dispatch({ type: "select", id: moveSelection(rowsRef.current, stateRef.current.selectedSessionId, direction) })}
220
+ />
221
+ </box>
222
+ <box
223
+ position={state.view === "usage" ? "relative" : "absolute"}
224
+ top={state.view === "usage" ? 0 : height + 2}
225
+ width="100%"
226
+ height={paneHeight}
227
+ >
228
+ <UsageView usage={state.usage} width={width} iconMode={config.tui.providerIcons} hidden={state.view !== "usage"} />
229
+ </box>
230
+ <KeyBar
231
+ view={state.view}
232
+ width={width}
233
+ context={state.view === "sessions"
234
+ ? `${selectedSession ? `${selectedSession.tool} ${selectedSession.state} ${selectedSession.project?.compactLabel ?? selectedSession.id}` : "no selection"}${filterSummary ? ` ${filterSummary}` : ""}`
235
+ : undefined}
236
+ />
237
+ {state.mode === "bindings" && <BindingsModal width={width} iconMode={config.tui.providerIcons} />}
238
+ </box>
239
+ );
240
+ }
@@ -0,0 +1,21 @@
1
+ # Provider artwork sources
2
+
3
+ Retrieved from official provider properties. The images are bundled so the dashboard never fetches artwork at runtime.
4
+
5
+ | File | Official source |
6
+ | --- | --- |
7
+ | `claude.png` | `https://assets-proxy.anthropic.com/claude-ai/v2/assets/v1/c129d018a-0ZbJsTbu.png` |
8
+ | `opencode.png` | `https://opencode.ai/apple-touch-icon-v3.png` |
9
+ | `openai.png` | OpenAI official app icon (`https://cdn.oaistatic.com/assets/apple-touch-icon-mz9nytnj.webp`, white tile with black Blossom from the official brand guidelines); the standalone mono Blossom SVG (`File:OpenAI_logo_2025_(symbol).svg`, Wikimedia Commons, PD-textlogo) served as design reference. Formerly `codex.png` (OpenAI Codex app art). |
10
+
11
+ The `*-terminal.svg` files are editable 8x8, square integer-grid adaptations of those marks. Their generated `*-terminal.png` counterparts map directly to a compact 8x4-cell block target with square half-block pixels (2 pixel rows per cell), avoiding destructive downsampling and aspect distortion. Hand-drawn tool glyphs (no official small-mark equivalent; used for the 2x1-cell mini column icon in image-capable modes, replaced by a brand monogram in blocks mode):
12
+
13
+ | File | Source |
14
+ | --- | --- |
15
+ | `copilot.svg` / `copilot.png` | Original 8x8 grid drawing modelled on GitHub Copilot's goggles mark |
16
+ | `shell.svg` / `shell.png` | Original 8x8 grid drawing of a `>_` prompt glyph |
17
+ | `unknown.svg` / `unknown.png` | Original 8x8 grid drawing of a `?` marker |
18
+
19
+ They deliberately avoid gradients and antialiasing so Claude's inverted cream spark on an orange tile, OpenCode's light "O" plate, and OpenAI's black Blossom on a white tile remain identifiable after character-cell rendering. Square official artwork uses a separate 6x3-cell fitted target.
20
+
21
+ Claude, OpenCode, Codex, OpenAI, Anthropic, and their marks belong to their respective owners.
@@ -0,0 +1,62 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" shape-rendering="crispEdges">
2
+ <rect x="1" y="0" width="1" height="1" fill="#d97757"/>
3
+ <rect x="2" y="0" width="1" height="1" fill="#d97757"/>
4
+ <rect x="5" y="0" width="1" height="1" fill="#d97757"/>
5
+ <rect x="6" y="0" width="1" height="1" fill="#d97757"/>
6
+ <rect x="0" y="1" width="1" height="1" fill="#d97757"/>
7
+ <rect x="2" y="1" width="1" height="1" fill="#d97757"/>
8
+ <rect x="5" y="1" width="1" height="1" fill="#d97757"/>
9
+ <rect x="7" y="1" width="1" height="1" fill="#d97757"/>
10
+ <rect x="0" y="2" width="1" height="1" fill="#d97757"/>
11
+ <rect x="1" y="2" width="1" height="1" fill="#d97757"/>
12
+ <rect x="6" y="2" width="1" height="1" fill="#d97757"/>
13
+ <rect x="7" y="2" width="1" height="1" fill="#d97757"/>
14
+ <rect x="0" y="3" width="1" height="1" fill="#d97757"/>
15
+ <rect x="7" y="3" width="1" height="1" fill="#d97757"/>
16
+ <rect x="0" y="4" width="1" height="1" fill="#d97757"/>
17
+ <rect x="7" y="4" width="1" height="1" fill="#d97757"/>
18
+ <rect x="0" y="5" width="1" height="1" fill="#d97757"/>
19
+ <rect x="1" y="5" width="1" height="1" fill="#d97757"/>
20
+ <rect x="6" y="5" width="1" height="1" fill="#d97757"/>
21
+ <rect x="7" y="5" width="1" height="1" fill="#d97757"/>
22
+ <rect x="0" y="6" width="1" height="1" fill="#d97757"/>
23
+ <rect x="2" y="6" width="1" height="1" fill="#d97757"/>
24
+ <rect x="5" y="6" width="1" height="1" fill="#d97757"/>
25
+ <rect x="7" y="6" width="1" height="1" fill="#d97757"/>
26
+ <rect x="1" y="7" width="1" height="1" fill="#d97757"/>
27
+ <rect x="2" y="7" width="1" height="1" fill="#d97757"/>
28
+ <rect x="5" y="7" width="1" height="1" fill="#d97757"/>
29
+ <rect x="6" y="7" width="1" height="1" fill="#d97757"/>
30
+ <rect x="3" y="0" width="1" height="1" fill="#f5f1e8"/>
31
+ <rect x="4" y="0" width="1" height="1" fill="#f5f1e8"/>
32
+ <rect x="1" y="1" width="1" height="1" fill="#f5f1e8"/>
33
+ <rect x="3" y="1" width="1" height="1" fill="#f5f1e8"/>
34
+ <rect x="4" y="1" width="1" height="1" fill="#f5f1e8"/>
35
+ <rect x="6" y="1" width="1" height="1" fill="#f5f1e8"/>
36
+ <rect x="2" y="2" width="1" height="1" fill="#f5f1e8"/>
37
+ <rect x="3" y="2" width="1" height="1" fill="#f5f1e8"/>
38
+ <rect x="4" y="2" width="1" height="1" fill="#f5f1e8"/>
39
+ <rect x="5" y="2" width="1" height="1" fill="#f5f1e8"/>
40
+ <rect x="1" y="3" width="1" height="1" fill="#f5f1e8"/>
41
+ <rect x="2" y="3" width="1" height="1" fill="#f5f1e8"/>
42
+ <rect x="3" y="3" width="1" height="1" fill="#f5f1e8"/>
43
+ <rect x="4" y="3" width="1" height="1" fill="#f5f1e8"/>
44
+ <rect x="5" y="3" width="1" height="1" fill="#f5f1e8"/>
45
+ <rect x="6" y="3" width="1" height="1" fill="#f5f1e8"/>
46
+ <rect x="1" y="4" width="1" height="1" fill="#f5f1e8"/>
47
+ <rect x="2" y="4" width="1" height="1" fill="#f5f1e8"/>
48
+ <rect x="3" y="4" width="1" height="1" fill="#f5f1e8"/>
49
+ <rect x="4" y="4" width="1" height="1" fill="#f5f1e8"/>
50
+ <rect x="5" y="4" width="1" height="1" fill="#f5f1e8"/>
51
+ <rect x="6" y="4" width="1" height="1" fill="#f5f1e8"/>
52
+ <rect x="2" y="5" width="1" height="1" fill="#f5f1e8"/>
53
+ <rect x="3" y="5" width="1" height="1" fill="#f5f1e8"/>
54
+ <rect x="4" y="5" width="1" height="1" fill="#f5f1e8"/>
55
+ <rect x="5" y="5" width="1" height="1" fill="#f5f1e8"/>
56
+ <rect x="1" y="6" width="1" height="1" fill="#f5f1e8"/>
57
+ <rect x="3" y="6" width="1" height="1" fill="#f5f1e8"/>
58
+ <rect x="4" y="6" width="1" height="1" fill="#f5f1e8"/>
59
+ <rect x="6" y="6" width="1" height="1" fill="#f5f1e8"/>
60
+ <rect x="3" y="7" width="1" height="1" fill="#f5f1e8"/>
61
+ <rect x="4" y="7" width="1" height="1" fill="#f5f1e8"/>
62
+ </svg>
@@ -0,0 +1,44 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" shape-rendering="crispEdges">
2
+ <rect x="2" y="0" width="1" height="1" fill="#c8cdd8"/>
3
+ <rect x="3" y="0" width="1" height="1" fill="#c8cdd8"/>
4
+ <rect x="4" y="0" width="1" height="1" fill="#c8cdd8"/>
5
+ <rect x="5" y="0" width="1" height="1" fill="#c8cdd8"/>
6
+ <rect x="1" y="1" width="1" height="1" fill="#c8cdd8"/>
7
+ <rect x="2" y="1" width="1" height="1" fill="#c8cdd8"/>
8
+ <rect x="3" y="1" width="1" height="1" fill="#c8cdd8"/>
9
+ <rect x="4" y="1" width="1" height="1" fill="#c8cdd8"/>
10
+ <rect x="5" y="1" width="1" height="1" fill="#c8cdd8"/>
11
+ <rect x="6" y="1" width="1" height="1" fill="#c8cdd8"/>
12
+ <rect x="0" y="2" width="1" height="1" fill="#c8cdd8"/>
13
+ <rect x="1" y="2" width="1" height="1" fill="#c8cdd8"/>
14
+ <rect x="3" y="2" width="1" height="1" fill="#c8cdd8"/>
15
+ <rect x="4" y="2" width="1" height="1" fill="#c8cdd8"/>
16
+ <rect x="6" y="2" width="1" height="1" fill="#c8cdd8"/>
17
+ <rect x="7" y="2" width="1" height="1" fill="#c8cdd8"/>
18
+ <rect x="0" y="3" width="1" height="1" fill="#c8cdd8"/>
19
+ <rect x="1" y="3" width="1" height="1" fill="#c8cdd8"/>
20
+ <rect x="3" y="3" width="1" height="1" fill="#c8cdd8"/>
21
+ <rect x="4" y="3" width="1" height="1" fill="#c8cdd8"/>
22
+ <rect x="6" y="3" width="1" height="1" fill="#c8cdd8"/>
23
+ <rect x="7" y="3" width="1" height="1" fill="#c8cdd8"/>
24
+ <rect x="0" y="4" width="1" height="1" fill="#c8cdd8"/>
25
+ <rect x="1" y="4" width="1" height="1" fill="#c8cdd8"/>
26
+ <rect x="2" y="4" width="1" height="1" fill="#c8cdd8"/>
27
+ <rect x="3" y="4" width="1" height="1" fill="#c8cdd8"/>
28
+ <rect x="4" y="4" width="1" height="1" fill="#c8cdd8"/>
29
+ <rect x="5" y="4" width="1" height="1" fill="#c8cdd8"/>
30
+ <rect x="6" y="4" width="1" height="1" fill="#c8cdd8"/>
31
+ <rect x="7" y="4" width="1" height="1" fill="#c8cdd8"/>
32
+ <rect x="1" y="5" width="1" height="1" fill="#c8cdd8"/>
33
+ <rect x="2" y="5" width="1" height="1" fill="#c8cdd8"/>
34
+ <rect x="3" y="5" width="1" height="1" fill="#c8cdd8"/>
35
+ <rect x="4" y="5" width="1" height="1" fill="#c8cdd8"/>
36
+ <rect x="5" y="5" width="1" height="1" fill="#c8cdd8"/>
37
+ <rect x="6" y="5" width="1" height="1" fill="#c8cdd8"/>
38
+ <rect x="2" y="6" width="1" height="1" fill="#c8cdd8"/>
39
+ <rect x="3" y="6" width="1" height="1" fill="#c8cdd8"/>
40
+ <rect x="4" y="6" width="1" height="1" fill="#c8cdd8"/>
41
+ <rect x="5" y="6" width="1" height="1" fill="#c8cdd8"/>
42
+ <rect x="3" y="7" width="1" height="1" fill="#c8cdd8"/>
43
+ <rect x="4" y="7" width="1" height="1" fill="#c8cdd8"/>
44
+ </svg>
@@ -0,0 +1,62 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" shape-rendering="crispEdges">
2
+ <rect x="1" y="0" width="1" height="1" fill="#ffffff"/>
3
+ <rect x="2" y="0" width="1" height="1" fill="#ffffff"/>
4
+ <rect x="3" y="0" width="1" height="1" fill="#ffffff"/>
5
+ <rect x="4" y="0" width="1" height="1" fill="#ffffff"/>
6
+ <rect x="5" y="0" width="1" height="1" fill="#ffffff"/>
7
+ <rect x="6" y="0" width="1" height="1" fill="#ffffff"/>
8
+ <rect x="0" y="1" width="1" height="1" fill="#ffffff"/>
9
+ <rect x="1" y="1" width="1" height="1" fill="#ffffff"/>
10
+ <rect x="6" y="1" width="1" height="1" fill="#ffffff"/>
11
+ <rect x="7" y="1" width="1" height="1" fill="#ffffff"/>
12
+ <rect x="0" y="2" width="1" height="1" fill="#ffffff"/>
13
+ <rect x="3" y="2" width="1" height="1" fill="#ffffff"/>
14
+ <rect x="4" y="2" width="1" height="1" fill="#ffffff"/>
15
+ <rect x="7" y="2" width="1" height="1" fill="#ffffff"/>
16
+ <rect x="0" y="3" width="1" height="1" fill="#ffffff"/>
17
+ <rect x="2" y="3" width="1" height="1" fill="#ffffff"/>
18
+ <rect x="5" y="3" width="1" height="1" fill="#ffffff"/>
19
+ <rect x="7" y="3" width="1" height="1" fill="#ffffff"/>
20
+ <rect x="0" y="4" width="1" height="1" fill="#ffffff"/>
21
+ <rect x="2" y="4" width="1" height="1" fill="#ffffff"/>
22
+ <rect x="5" y="4" width="1" height="1" fill="#ffffff"/>
23
+ <rect x="7" y="4" width="1" height="1" fill="#ffffff"/>
24
+ <rect x="0" y="5" width="1" height="1" fill="#ffffff"/>
25
+ <rect x="3" y="5" width="1" height="1" fill="#ffffff"/>
26
+ <rect x="4" y="5" width="1" height="1" fill="#ffffff"/>
27
+ <rect x="7" y="5" width="1" height="1" fill="#ffffff"/>
28
+ <rect x="0" y="6" width="1" height="1" fill="#ffffff"/>
29
+ <rect x="1" y="6" width="1" height="1" fill="#ffffff"/>
30
+ <rect x="6" y="6" width="1" height="1" fill="#ffffff"/>
31
+ <rect x="7" y="6" width="1" height="1" fill="#ffffff"/>
32
+ <rect x="1" y="7" width="1" height="1" fill="#ffffff"/>
33
+ <rect x="2" y="7" width="1" height="1" fill="#ffffff"/>
34
+ <rect x="3" y="7" width="1" height="1" fill="#ffffff"/>
35
+ <rect x="4" y="7" width="1" height="1" fill="#ffffff"/>
36
+ <rect x="5" y="7" width="1" height="1" fill="#ffffff"/>
37
+ <rect x="6" y="7" width="1" height="1" fill="#ffffff"/>
38
+ <rect x="2" y="1" width="1" height="1" fill="#000000"/>
39
+ <rect x="3" y="1" width="1" height="1" fill="#000000"/>
40
+ <rect x="4" y="1" width="1" height="1" fill="#000000"/>
41
+ <rect x="5" y="1" width="1" height="1" fill="#000000"/>
42
+ <rect x="1" y="2" width="1" height="1" fill="#000000"/>
43
+ <rect x="2" y="2" width="1" height="1" fill="#000000"/>
44
+ <rect x="5" y="2" width="1" height="1" fill="#000000"/>
45
+ <rect x="6" y="2" width="1" height="1" fill="#000000"/>
46
+ <rect x="1" y="3" width="1" height="1" fill="#000000"/>
47
+ <rect x="3" y="3" width="1" height="1" fill="#000000"/>
48
+ <rect x="4" y="3" width="1" height="1" fill="#000000"/>
49
+ <rect x="6" y="3" width="1" height="1" fill="#000000"/>
50
+ <rect x="1" y="4" width="1" height="1" fill="#000000"/>
51
+ <rect x="3" y="4" width="1" height="1" fill="#000000"/>
52
+ <rect x="4" y="4" width="1" height="1" fill="#000000"/>
53
+ <rect x="6" y="4" width="1" height="1" fill="#000000"/>
54
+ <rect x="1" y="5" width="1" height="1" fill="#000000"/>
55
+ <rect x="2" y="5" width="1" height="1" fill="#000000"/>
56
+ <rect x="5" y="5" width="1" height="1" fill="#000000"/>
57
+ <rect x="6" y="5" width="1" height="1" fill="#000000"/>
58
+ <rect x="2" y="6" width="1" height="1" fill="#000000"/>
59
+ <rect x="3" y="6" width="1" height="1" fill="#000000"/>
60
+ <rect x="4" y="6" width="1" height="1" fill="#000000"/>
61
+ <rect x="5" y="6" width="1" height="1" fill="#000000"/>
62
+ </svg>
@@ -0,0 +1,62 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" shape-rendering="crispEdges">
2
+ <rect x="1" y="0" width="1" height="1" fill="#111111"/>
3
+ <rect x="2" y="0" width="1" height="1" fill="#111111"/>
4
+ <rect x="3" y="0" width="1" height="1" fill="#111111"/>
5
+ <rect x="4" y="0" width="1" height="1" fill="#111111"/>
6
+ <rect x="5" y="0" width="1" height="1" fill="#111111"/>
7
+ <rect x="6" y="0" width="1" height="1" fill="#111111"/>
8
+ <rect x="0" y="1" width="1" height="1" fill="#111111"/>
9
+ <rect x="7" y="1" width="1" height="1" fill="#111111"/>
10
+ <rect x="0" y="2" width="1" height="1" fill="#111111"/>
11
+ <rect x="3" y="2" width="1" height="1" fill="#111111"/>
12
+ <rect x="4" y="2" width="1" height="1" fill="#111111"/>
13
+ <rect x="7" y="2" width="1" height="1" fill="#111111"/>
14
+ <rect x="0" y="3" width="1" height="1" fill="#111111"/>
15
+ <rect x="3" y="3" width="1" height="1" fill="#111111"/>
16
+ <rect x="4" y="3" width="1" height="1" fill="#111111"/>
17
+ <rect x="7" y="3" width="1" height="1" fill="#111111"/>
18
+ <rect x="0" y="4" width="1" height="1" fill="#111111"/>
19
+ <rect x="3" y="4" width="1" height="1" fill="#111111"/>
20
+ <rect x="4" y="4" width="1" height="1" fill="#111111"/>
21
+ <rect x="7" y="4" width="1" height="1" fill="#111111"/>
22
+ <rect x="0" y="5" width="1" height="1" fill="#111111"/>
23
+ <rect x="3" y="5" width="1" height="1" fill="#111111"/>
24
+ <rect x="4" y="5" width="1" height="1" fill="#111111"/>
25
+ <rect x="7" y="5" width="1" height="1" fill="#111111"/>
26
+ <rect x="0" y="6" width="1" height="1" fill="#111111"/>
27
+ <rect x="7" y="6" width="1" height="1" fill="#111111"/>
28
+ <rect x="1" y="7" width="1" height="1" fill="#111111"/>
29
+ <rect x="2" y="7" width="1" height="1" fill="#111111"/>
30
+ <rect x="3" y="7" width="1" height="1" fill="#111111"/>
31
+ <rect x="4" y="7" width="1" height="1" fill="#111111"/>
32
+ <rect x="5" y="7" width="1" height="1" fill="#111111"/>
33
+ <rect x="6" y="7" width="1" height="1" fill="#111111"/>
34
+ <rect x="1" y="1" width="1" height="1" fill="#f3f3f3"/>
35
+ <rect x="2" y="1" width="1" height="1" fill="#f3f3f3"/>
36
+ <rect x="3" y="1" width="1" height="1" fill="#f3f3f3"/>
37
+ <rect x="4" y="1" width="1" height="1" fill="#f3f3f3"/>
38
+ <rect x="5" y="1" width="1" height="1" fill="#f3f3f3"/>
39
+ <rect x="6" y="1" width="1" height="1" fill="#f3f3f3"/>
40
+ <rect x="1" y="2" width="1" height="1" fill="#f3f3f3"/>
41
+ <rect x="2" y="2" width="1" height="1" fill="#f3f3f3"/>
42
+ <rect x="5" y="2" width="1" height="1" fill="#f3f3f3"/>
43
+ <rect x="6" y="2" width="1" height="1" fill="#f3f3f3"/>
44
+ <rect x="1" y="3" width="1" height="1" fill="#f3f3f3"/>
45
+ <rect x="2" y="3" width="1" height="1" fill="#f3f3f3"/>
46
+ <rect x="5" y="3" width="1" height="1" fill="#f3f3f3"/>
47
+ <rect x="6" y="3" width="1" height="1" fill="#f3f3f3"/>
48
+ <rect x="1" y="4" width="1" height="1" fill="#f3f3f3"/>
49
+ <rect x="2" y="4" width="1" height="1" fill="#f3f3f3"/>
50
+ <rect x="5" y="4" width="1" height="1" fill="#f3f3f3"/>
51
+ <rect x="6" y="4" width="1" height="1" fill="#f3f3f3"/>
52
+ <rect x="1" y="5" width="1" height="1" fill="#f3f3f3"/>
53
+ <rect x="2" y="5" width="1" height="1" fill="#f3f3f3"/>
54
+ <rect x="5" y="5" width="1" height="1" fill="#f3f3f3"/>
55
+ <rect x="6" y="5" width="1" height="1" fill="#f3f3f3"/>
56
+ <rect x="1" y="6" width="1" height="1" fill="#f3f3f3"/>
57
+ <rect x="2" y="6" width="1" height="1" fill="#f3f3f3"/>
58
+ <rect x="3" y="6" width="1" height="1" fill="#f3f3f3"/>
59
+ <rect x="4" y="6" width="1" height="1" fill="#f3f3f3"/>
60
+ <rect x="5" y="6" width="1" height="1" fill="#f3f3f3"/>
61
+ <rect x="6" y="6" width="1" height="1" fill="#f3f3f3"/>
62
+ </svg>
@@ -0,0 +1,23 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" shape-rendering="crispEdges">
2
+ <rect x="0" y="0" width="1" height="1" fill="#c8cdd8"/>
3
+ <rect x="0" y="1" width="1" height="1" fill="#c8cdd8"/>
4
+ <rect x="1" y="1" width="1" height="1" fill="#c8cdd8"/>
5
+ <rect x="0" y="2" width="1" height="1" fill="#c8cdd8"/>
6
+ <rect x="1" y="2" width="1" height="1" fill="#c8cdd8"/>
7
+ <rect x="2" y="2" width="1" height="1" fill="#c8cdd8"/>
8
+ <rect x="0" y="3" width="1" height="1" fill="#c8cdd8"/>
9
+ <rect x="1" y="3" width="1" height="1" fill="#c8cdd8"/>
10
+ <rect x="2" y="3" width="1" height="1" fill="#c8cdd8"/>
11
+ <rect x="3" y="3" width="1" height="1" fill="#c8cdd8"/>
12
+ <rect x="0" y="4" width="1" height="1" fill="#c8cdd8"/>
13
+ <rect x="1" y="4" width="1" height="1" fill="#c8cdd8"/>
14
+ <rect x="2" y="4" width="1" height="1" fill="#c8cdd8"/>
15
+ <rect x="0" y="5" width="1" height="1" fill="#c8cdd8"/>
16
+ <rect x="1" y="5" width="1" height="1" fill="#c8cdd8"/>
17
+ <rect x="0" y="6" width="1" height="1" fill="#c8cdd8"/>
18
+ <rect x="3" y="7" width="1" height="1" fill="#c8cdd8"/>
19
+ <rect x="4" y="7" width="1" height="1" fill="#c8cdd8"/>
20
+ <rect x="5" y="7" width="1" height="1" fill="#c8cdd8"/>
21
+ <rect x="6" y="7" width="1" height="1" fill="#c8cdd8"/>
22
+ <rect x="7" y="7" width="1" height="1" fill="#c8cdd8"/>
23
+ </svg>
@@ -0,0 +1,23 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" shape-rendering="crispEdges">
2
+ <rect x="1" y="0" width="1" height="1" fill="#8b93a7"/>
3
+ <rect x="2" y="0" width="1" height="1" fill="#8b93a7"/>
4
+ <rect x="3" y="0" width="1" height="1" fill="#8b93a7"/>
5
+ <rect x="4" y="0" width="1" height="1" fill="#8b93a7"/>
6
+ <rect x="0" y="1" width="1" height="1" fill="#8b93a7"/>
7
+ <rect x="1" y="1" width="1" height="1" fill="#8b93a7"/>
8
+ <rect x="4" y="1" width="1" height="1" fill="#8b93a7"/>
9
+ <rect x="5" y="1" width="1" height="1" fill="#8b93a7"/>
10
+ <rect x="0" y="2" width="1" height="1" fill="#8b93a7"/>
11
+ <rect x="1" y="2" width="1" height="1" fill="#8b93a7"/>
12
+ <rect x="4" y="2" width="1" height="1" fill="#8b93a7"/>
13
+ <rect x="5" y="2" width="1" height="1" fill="#8b93a7"/>
14
+ <rect x="2" y="3" width="1" height="1" fill="#8b93a7"/>
15
+ <rect x="3" y="3" width="1" height="1" fill="#8b93a7"/>
16
+ <rect x="4" y="3" width="1" height="1" fill="#8b93a7"/>
17
+ <rect x="2" y="4" width="1" height="1" fill="#8b93a7"/>
18
+ <rect x="3" y="4" width="1" height="1" fill="#8b93a7"/>
19
+ <rect x="2" y="5" width="1" height="1" fill="#8b93a7"/>
20
+ <rect x="3" y="5" width="1" height="1" fill="#8b93a7"/>
21
+ <rect x="2" y="7" width="1" height="1" fill="#8b93a7"/>
22
+ <rect x="3" y="7" width="1" height="1" fill="#8b93a7"/>
23
+ </svg>