pi-mega-compact 0.7.8 → 0.8.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/README.md +11 -12
- package/dist/extensions/dashboard-server/html.js +1023 -0
- package/dist/extensions/dashboard-server/html.test.js +41 -0
- package/dist/extensions/dashboard-server/index-reader.js +133 -0
- package/dist/extensions/dashboard-server/server.js +530 -0
- package/dist/extensions/dashboard-server/server.test.js +120 -0
- package/dist/extensions/dashboard-server/snapshot.js +43 -0
- package/dist/extensions/dashboard-server/state.js +30 -0
- package/dist/extensions/dashboard-server/types.js +5 -0
- package/dist/extensions/dashboard-server-s32.test.js +181 -0
- package/dist/extensions/dashboard-server.js +7 -1315
- package/dist/extensions/mega-commands.js +162 -134
- package/dist/extensions/mega-compact.js +3 -0
- package/dist/extensions/mega-compact.test.js +90 -21
- package/dist/extensions/mega-conflict-cmds.js +5 -1
- package/dist/extensions/mega-dashboard-cmds.js +29 -22
- package/dist/extensions/mega-db-cmds.js +11 -2
- package/dist/extensions/mega-events/agent-handlers.js +222 -0
- package/dist/extensions/mega-events/compact-handlers.js +162 -0
- package/dist/extensions/mega-events/context-handler.js +249 -0
- package/dist/extensions/mega-events/register.js +21 -0
- package/dist/extensions/mega-events/session-handlers.js +142 -0
- package/dist/extensions/mega-events.js +15 -699
- package/dist/extensions/mega-game-cmds.js +106 -0
- package/dist/extensions/mega-game-cmds.test.js +113 -0
- package/dist/extensions/mega-pipeline/compact.js +324 -0
- package/dist/extensions/mega-pipeline/memory-review.js +38 -0
- package/dist/extensions/mega-pipeline/recall.js +147 -0
- package/dist/extensions/mega-pipeline.js +9 -480
- package/dist/extensions/mega-runtime/helpers.js +40 -0
- package/dist/extensions/mega-runtime/query.js +29 -0
- package/dist/extensions/mega-runtime/state.js +877 -0
- package/dist/extensions/mega-runtime/state.test.js +171 -0
- package/dist/extensions/mega-runtime/widget.js +270 -0
- package/dist/extensions/mega-runtime/widget.test.js +160 -0
- package/dist/extensions/mega-runtime.js +15 -947
- package/dist/src/config/themes.js +84 -0
- package/dist/src/config/themes.test.js +94 -0
- package/dist/src/game/scoring.js +105 -0
- package/dist/src/game/scoring.test.js +98 -0
- package/dist/src/store/sqlite/checkpoints.js +145 -0
- package/dist/src/store/sqlite/dedup-mirror.js +64 -0
- package/dist/src/store/sqlite/foundation.js +38 -0
- package/dist/src/store/sqlite/game-achievements.js +111 -0
- package/dist/src/store/sqlite/game-achievements.test.js +67 -0
- package/dist/src/store/sqlite/game-scores.js +105 -0
- package/dist/src/store/sqlite/game-scores.test.js +106 -0
- package/dist/src/store/sqlite/game-state.js +54 -0
- package/dist/src/store/sqlite/game-state.test.js +76 -0
- package/dist/src/store/sqlite/global-index.js +224 -0
- package/dist/src/store/sqlite/maintenance.js +235 -0
- package/dist/src/store/sqlite/memories.js +164 -0
- package/dist/src/store/sqlite/meta.js +82 -0
- package/dist/src/store/sqlite/model-snapshots.js +47 -0
- package/dist/src/store/sqlite/raptor.js +57 -0
- package/dist/src/store/sqlite/raw-transcript.js +134 -0
- package/dist/src/store/sqlite/schema.js +294 -0
- package/dist/src/store/sqlite/session-state.js +28 -0
- package/dist/src/store/sqlite/stats.js +66 -0
- package/dist/src/store/sqlite/utils.js +120 -0
- package/dist/src/store/sqlite.js +23 -1607
- package/extensions/dashboard-server/html.test.ts +50 -0
- package/extensions/dashboard-server/html.ts +1026 -0
- package/extensions/dashboard-server/index-reader.ts +130 -0
- package/extensions/dashboard-server/server.test.ts +131 -0
- package/extensions/dashboard-server/server.ts +505 -0
- package/extensions/dashboard-server/snapshot.ts +44 -0
- package/extensions/dashboard-server/state.ts +33 -0
- package/extensions/dashboard-server/types.ts +134 -0
- package/extensions/dashboard-server-s32.test.ts +195 -0
- package/extensions/dashboard-server.ts +7 -1431
- package/extensions/mega-commands.ts +33 -10
- package/extensions/mega-compact.test.ts +198 -43
- package/extensions/mega-compact.ts +3 -0
- package/extensions/mega-conflict-cmds.ts +6 -2
- package/extensions/mega-dashboard-cmds.ts +30 -23
- package/extensions/mega-db-cmds.ts +11 -3
- package/extensions/mega-events/agent-handlers.ts +262 -0
- package/extensions/mega-events/compact-handlers.ts +192 -0
- package/extensions/mega-events/context-handler.ts +290 -0
- package/extensions/mega-events/register.ts +37 -0
- package/extensions/mega-events/session-handlers.ts +165 -0
- package/extensions/mega-events.ts +15 -780
- package/extensions/mega-game-cmds.test.ts +137 -0
- package/extensions/mega-game-cmds.ts +122 -0
- package/extensions/mega-pipeline/compact.ts +366 -0
- package/extensions/mega-pipeline/memory-review.ts +46 -0
- package/extensions/mega-pipeline/recall.ts +165 -0
- package/extensions/mega-pipeline.ts +9 -537
- package/extensions/mega-runtime/helpers.ts +68 -0
- package/extensions/mega-runtime/query.ts +29 -0
- package/extensions/mega-runtime/state.test.ts +171 -0
- package/extensions/mega-runtime/state.ts +967 -0
- package/extensions/mega-runtime/widget.test.ts +185 -0
- package/extensions/mega-runtime/widget.ts +359 -0
- package/extensions/mega-runtime.ts +15 -1093
- package/package.json +4 -3
- package/src/config/themes.test.ts +116 -0
- package/src/config/themes.ts +124 -0
- package/src/game/scoring.test.ts +103 -0
- package/src/game/scoring.ts +158 -0
- package/src/store/sqlite/checkpoints.ts +204 -0
- package/src/store/sqlite/dedup-mirror.ts +114 -0
- package/src/store/sqlite/foundation.ts +63 -0
- package/src/store/sqlite/game-achievements.test.ts +80 -0
- package/src/store/sqlite/game-achievements.ts +147 -0
- package/src/store/sqlite/game-scores.test.ts +132 -0
- package/src/store/sqlite/game-scores.ts +168 -0
- package/src/store/sqlite/game-state.test.ts +89 -0
- package/src/store/sqlite/game-state.ts +87 -0
- package/src/store/sqlite/global-index.ts +305 -0
- package/src/store/sqlite/maintenance.ts +294 -0
- package/src/store/sqlite/memories.ts +217 -0
- package/src/store/sqlite/meta.ts +108 -0
- package/src/store/sqlite/model-snapshots.ts +83 -0
- package/src/store/sqlite/raptor.ts +107 -0
- package/src/store/sqlite/raw-transcript.ts +221 -0
- package/src/store/sqlite/schema.ts +305 -0
- package/src/store/sqlite/session-state.ts +38 -0
- package/src/store/sqlite/stats.ts +127 -0
- package/src/store/sqlite/utils.ts +125 -0
- package/src/store/sqlite.ts +23 -2204
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-server/snapshot.ts — snapshot + events.log file readers.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
export function readSnapshot(snapshotPath) {
|
|
6
|
+
try {
|
|
7
|
+
const raw = readFileSync(snapshotPath, "utf-8");
|
|
8
|
+
return JSON.parse(raw);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return {
|
|
12
|
+
version: 1,
|
|
13
|
+
updatedAt: null,
|
|
14
|
+
tier: "unknown",
|
|
15
|
+
presetTier: "unknown",
|
|
16
|
+
pressure: 0,
|
|
17
|
+
config: { fastGatePct: 80, thresholdTokens: 100_000, tierPct: null, effectiveThresholdPct: null, anchorUserMessages: 1, preserveRecent: 2, auto: true, autoInlineK: 3 },
|
|
18
|
+
session: { id: null, state: null, persistedThisSession: false, lastCheckpointId: null, lastCompactedFrom: 0 },
|
|
19
|
+
context: { tokens: null, percent: null, contextWindow: 0 },
|
|
20
|
+
trigger: { armed: false, ready: false, currentTokens: null, thresholdTokens: 100_000, fastGatePct: 80, tierPct: null, effectiveThresholdPct: null },
|
|
21
|
+
store: { checkpointCount: 0, totalTokenEstimate: 0, originalTokens: 0, tokensSaved: 0, injectedCount: 0, dedupHitRate: 0, storageDedupRate: 0, dedupCollapsed: 0 },
|
|
22
|
+
crew: { activeAgents: 0, currentTurn: 0 },
|
|
23
|
+
repo: { checkpointCount: 0, totalTokenEstimate: 0, originalTokens: 0, tokensSaved: 0, sessionCount: 0, dedupAttempts: 0, dedupCollapsed: 0, storageDedupRate: 0 },
|
|
24
|
+
integrity: { regionsRetained: 0, compressedOriginalBytes: 0, duplicatesCollapsed: 0, bytesPermanentlyDeleted: 0 },
|
|
25
|
+
cacheHits: { session: 0, total: 0, sessionTokensSaved: 0, totalTokensSaved: 0 },
|
|
26
|
+
compacts: { session: 0, total: 0 },
|
|
27
|
+
timeSaved: { compact: { sessionSec: 0, totalSec: 0 }, cacheHit: { sessionSec: 0, totalSec: 0 } },
|
|
28
|
+
compression: { session: { tokensIn: 0, tokensOut: 0, tokensFreed: 0, compressionPct: 0, dedupPct: 0 }, repo: { tokensIn: 0, tokensOut: 0, tokensFreed: 0, compressionPct: 0, dedupPct: 0 } },
|
|
29
|
+
model: undefined,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function readFrom(path, charOffset) {
|
|
34
|
+
try {
|
|
35
|
+
const content = readFileSync(path, "utf-8");
|
|
36
|
+
if (content.length <= charOffset)
|
|
37
|
+
return { data: "", offset: charOffset };
|
|
38
|
+
return { data: content.slice(charOffset), offset: content.length };
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return { data: "", offset: charOffset };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-server/state.ts — local runtime log + version state.
|
|
3
|
+
*
|
|
4
|
+
* The dashboard server is spawned as a DETACHED child. When it is launched with
|
|
5
|
+
* `stdio: "ignore"` (the old default) any crash before the first console.log is
|
|
6
|
+
* invisible — there is no log to "check". We therefore mirror every lifecycle
|
|
7
|
+
* line to a file in the state dir so a failed start is always diagnosable. The
|
|
8
|
+
* launcher also captures stderr, so this doubles as defense-in-depth.
|
|
9
|
+
*/
|
|
10
|
+
import { appendFileSync } from "node:fs";
|
|
11
|
+
let LOG_PATH = null;
|
|
12
|
+
export function setLogPath(path) {
|
|
13
|
+
LOG_PATH = path;
|
|
14
|
+
}
|
|
15
|
+
export function log(...parts) {
|
|
16
|
+
const line = `[mega-compact][dashboard] ${parts.map((p) => (typeof p === "string" ? p : JSON.stringify(p))).join(" ")}`;
|
|
17
|
+
// eslint-disable-next-line no-console
|
|
18
|
+
console.error(line); // stderr — captured by the launcher pipe
|
|
19
|
+
if (LOG_PATH) {
|
|
20
|
+
try {
|
|
21
|
+
appendFileSync(LOG_PATH, new Date().toISOString() + " " + line + "\n");
|
|
22
|
+
}
|
|
23
|
+
catch { /* non-fatal */ }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Package version of this extension, surfaced in the dashboard header. */
|
|
27
|
+
export let dashboardServerVersion = "0.0.0";
|
|
28
|
+
export function setDashboardServerVersion(v) {
|
|
29
|
+
dashboardServerVersion = v;
|
|
30
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-server.test.ts — S32 game-state API + settings strip tests.
|
|
3
|
+
*
|
|
4
|
+
* GET/PUT /api/game-state round-trips the game_state SQLite row through the
|
|
5
|
+
* real server subprocess (spawn + waitFor + fetch), and the HTML template
|
|
6
|
+
* carries the data-theme attribute + settings strip + theme CSS-var blocks.
|
|
7
|
+
*/
|
|
8
|
+
import { test, describe } from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import { mkdtempSync, rmSync, readFileSync } from "node:fs";
|
|
11
|
+
import { tmpdir } from "node:os";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { spawn } from "node:child_process";
|
|
14
|
+
import { dashboardHtml } from "./dashboard-server/html.js";
|
|
15
|
+
import { setGameState, getGameState } from "../src/store/sqlite.js";
|
|
16
|
+
const SERVER_ENTRY = new URL("./dashboard-server.js", import.meta.url).pathname;
|
|
17
|
+
function waitFor(cond, timeoutMs = 6000) {
|
|
18
|
+
const start = Date.now();
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
const tick = async () => {
|
|
21
|
+
if (await cond())
|
|
22
|
+
return resolve();
|
|
23
|
+
if (Date.now() - start > timeoutMs)
|
|
24
|
+
return reject(new Error("timeout"));
|
|
25
|
+
setTimeout(tick, 50);
|
|
26
|
+
};
|
|
27
|
+
tick();
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function freshDir(prefix) {
|
|
31
|
+
return mkdtempSync(join(tmpdir(), prefix));
|
|
32
|
+
}
|
|
33
|
+
async function withServer(port, dir, fn) {
|
|
34
|
+
process.env.MEGACOMPACT_DASHBOARD_PORT = port;
|
|
35
|
+
const child = spawn(process.execPath, [SERVER_ENTRY, dir], { stdio: "ignore" });
|
|
36
|
+
try {
|
|
37
|
+
await waitFor(async () => {
|
|
38
|
+
try {
|
|
39
|
+
const raw = JSON.parse(readFileSync(join(dir, "port.pid"), "utf-8"));
|
|
40
|
+
const res = await fetch(`http://localhost:${raw.port}/api/version`);
|
|
41
|
+
return res.ok;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
const raw = JSON.parse(readFileSync(join(dir, "port.pid"), "utf-8"));
|
|
48
|
+
return await fn(raw.port);
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
child.kill("SIGTERM");
|
|
52
|
+
delete process.env.MEGACOMPACT_DASHBOARD_PORT;
|
|
53
|
+
rmSync(dir, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
describe("S32 /api/game-state", () => {
|
|
57
|
+
test("GET returns the current game_state row (seeded via setGameState)", async () => {
|
|
58
|
+
const dir = freshDir("dash-gs-get-");
|
|
59
|
+
setGameState({ game_mode_on: true, theme: "retro", tui_display_mode: "minimal" }, dir);
|
|
60
|
+
await withServer("19330", dir, async (port) => {
|
|
61
|
+
const gs = (await fetch(`http://localhost:${port}/api/game-state`).then((r) => r.json()));
|
|
62
|
+
assert.equal(gs.game_mode_on, true);
|
|
63
|
+
assert.equal(gs.theme, "retro");
|
|
64
|
+
assert.equal(gs.tui_display_mode, "minimal");
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
test("PUT {theme:'retro'} -> 200 and getGameState(dir).theme === 'retro'", async () => {
|
|
68
|
+
const dir = freshDir("dash-gs-theme-");
|
|
69
|
+
await withServer("19331", dir, async (port) => {
|
|
70
|
+
const res = await fetch(`http://localhost:${port}/api/game-state`, {
|
|
71
|
+
method: "PUT",
|
|
72
|
+
headers: { "Content-Type": "application/json" },
|
|
73
|
+
body: JSON.stringify({ theme: "retro" }),
|
|
74
|
+
});
|
|
75
|
+
assert.equal(res.status, 200);
|
|
76
|
+
const body = (await res.json());
|
|
77
|
+
assert.equal(body.theme, "retro");
|
|
78
|
+
// And the authoritative DB read reflects the write.
|
|
79
|
+
assert.equal(getGameState(dir).theme, "retro");
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
test("PUT invalid theme 'bogus' -> 400 and row unchanged", async () => {
|
|
83
|
+
const dir = freshDir("dash-gs-invalid-");
|
|
84
|
+
setGameState({ theme: "orange-bold" }, dir);
|
|
85
|
+
const before = getGameState(dir).theme;
|
|
86
|
+
await withServer("19332", dir, async (port) => {
|
|
87
|
+
const res = await fetch(`http://localhost:${port}/api/game-state`, {
|
|
88
|
+
method: "PUT",
|
|
89
|
+
headers: { "Content-Type": "application/json" },
|
|
90
|
+
body: JSON.stringify({ theme: "bogus" }),
|
|
91
|
+
});
|
|
92
|
+
assert.equal(res.status, 400);
|
|
93
|
+
});
|
|
94
|
+
assert.equal(getGameState(dir).theme, before, "row unchanged after invalid PUT");
|
|
95
|
+
});
|
|
96
|
+
test("PUT body 'null' (valid-but-non-object JSON) -> 400, server stays up (audit P1)", async () => {
|
|
97
|
+
const dir = freshDir("dash-gs-nullobj-");
|
|
98
|
+
setGameState({ theme: "amber-mono" }, dir);
|
|
99
|
+
const before = getGameState(dir).theme;
|
|
100
|
+
await withServer("19335", dir, async (port) => {
|
|
101
|
+
// A valid-JSON-but-non-object body must NOT crash the detached server
|
|
102
|
+
// (audit P1: unhandled TypeError on patch.game_mode_on deref).
|
|
103
|
+
const res = await fetch(`http://localhost:${port}/api/game-state`, {
|
|
104
|
+
method: "PUT",
|
|
105
|
+
headers: { "Content-Type": "application/json" },
|
|
106
|
+
body: JSON.stringify(null),
|
|
107
|
+
});
|
|
108
|
+
assert.equal(res.status, 400, "non-object JSON -> 400, not a crash");
|
|
109
|
+
const body = (await res.json());
|
|
110
|
+
assert.equal(body.error, "invalid_patch_object");
|
|
111
|
+
// Server must still be up — a follow-up GET must succeed.
|
|
112
|
+
const follow = await fetch(`http://localhost:${port}/api/game-state`);
|
|
113
|
+
assert.equal(follow.status, 200, "server survived the non-object PUT");
|
|
114
|
+
});
|
|
115
|
+
assert.equal(getGameState(dir).theme, before, "row unchanged after non-object PUT");
|
|
116
|
+
});
|
|
117
|
+
test("PUT body '[]' (array) -> 400, server stays up", async () => {
|
|
118
|
+
const dir = freshDir("dash-gs-arr-");
|
|
119
|
+
await withServer("19336", dir, async (port) => {
|
|
120
|
+
const res = await fetch(`http://localhost:${port}/api/game-state`, {
|
|
121
|
+
method: "PUT",
|
|
122
|
+
headers: { "Content-Type": "application/json" },
|
|
123
|
+
body: JSON.stringify([]),
|
|
124
|
+
});
|
|
125
|
+
assert.equal(res.status, 400);
|
|
126
|
+
const follow = await fetch(`http://localhost:${port}/api/game-state`);
|
|
127
|
+
assert.equal(follow.status, 200, "server survived the array PUT");
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
test("PUT {tui_display_mode:'minimal'} round-trips", async () => {
|
|
131
|
+
const dir = freshDir("dash-gs-tui-");
|
|
132
|
+
await withServer("19333", dir, async (port) => {
|
|
133
|
+
const res = await fetch(`http://localhost:${port}/api/game-state`, {
|
|
134
|
+
method: "PUT",
|
|
135
|
+
headers: { "Content-Type": "application/json" },
|
|
136
|
+
body: JSON.stringify({ tui_display_mode: "minimal" }),
|
|
137
|
+
});
|
|
138
|
+
assert.equal(res.status, 200);
|
|
139
|
+
const body = (await res.json());
|
|
140
|
+
assert.equal(body.tui_display_mode, "minimal");
|
|
141
|
+
assert.equal(getGameState(dir).tui_display_mode, "minimal");
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
test("PUT {game_mode_on:true} round-trips", async () => {
|
|
145
|
+
const dir = freshDir("dash-gs-mode-");
|
|
146
|
+
await withServer("19334", dir, async (port) => {
|
|
147
|
+
const res = await fetch(`http://localhost:${port}/api/game-state`, {
|
|
148
|
+
method: "PUT",
|
|
149
|
+
headers: { "Content-Type": "application/json" },
|
|
150
|
+
body: JSON.stringify({ game_mode_on: true }),
|
|
151
|
+
});
|
|
152
|
+
assert.equal(res.status, 200);
|
|
153
|
+
const body = (await res.json());
|
|
154
|
+
assert.equal(body.game_mode_on, true);
|
|
155
|
+
assert.equal(getGameState(dir).game_mode_on, true);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
describe("S32 dashboard HTML skin", () => {
|
|
160
|
+
test("carries data-theme on <html> + settings strip + theme CSS-var blocks", () => {
|
|
161
|
+
const html = dashboardHtml("custom");
|
|
162
|
+
// default transparent theme attribute on <html>
|
|
163
|
+
assert.match(html, /<html lang="en" data-theme="transparent">/);
|
|
164
|
+
// settings strip with the three controls
|
|
165
|
+
assert.match(html, /<div class="settings-strip">/);
|
|
166
|
+
assert.match(html, /id="set-game-mode"/);
|
|
167
|
+
assert.match(html, /id="set-theme"/);
|
|
168
|
+
assert.match(html, /id="set-tui-mode"/);
|
|
169
|
+
// all 6 theme ids appear as :root[data-theme="<id>"] override blocks
|
|
170
|
+
for (const id of ["transparent", "retro", "orange-bold", "cyan-neon", "amber-mono", "grayscale"]) {
|
|
171
|
+
assert.ok(html.includes(`:root[data-theme="${id}"]{`), `${id} data-theme block present`);
|
|
172
|
+
}
|
|
173
|
+
// core CSS vars defined in the base :root
|
|
174
|
+
assert.match(html, /--bg: #0d1117;/);
|
|
175
|
+
assert.match(html, /--fg: #c9d1d9;/);
|
|
176
|
+
assert.match(html, /--accent: #3fb950;/);
|
|
177
|
+
assert.match(html, /--mega: #f0883e;/);
|
|
178
|
+
// body uses the themed var (not a hardcoded hex)
|
|
179
|
+
assert.match(html, /body\s*\{[^}]*background: var\(--bg\)/);
|
|
180
|
+
});
|
|
181
|
+
});
|