dsh-theme-endfield 0.0.0-stage → 1.2.2
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/LICENSE +21 -0
- package/README.md +117 -2
- package/client.js +10152 -0
- package/cordis.patch.yml +17 -0
- package/docs/PR-description.md +141 -0
- package/docs/audio-notifications.md +133 -0
- package/docs/contour-scan-bounds.md +24 -0
- package/docs/contour-trail.md +61 -0
- package/docs/contour-worker.md +38 -0
- package/docs/design-language.md +212 -0
- package/docs/engineering-notes.md +1147 -0
- package/docs/features.md +295 -0
- package/docs/glass.md +32 -0
- package/docs/testing.md +427 -0
- package/index.js +1403 -0
- package/lib/audio.js +426 -0
- package/lib/slots.js +97 -0
- package/lib/tone.js +216 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +111 -4
- package/sounds/attention.wav +0 -0
- package/sounds/boot.wav +0 -0
- package/sounds/turn-done.wav +0 -0
- package/sounds/turn-fail.wav +0 -0
- package/sounds/turn-start.wav +0 -0
package/lib/tone.js
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* Zero-dependency PCM WAV tone synthesizer.
|
|
4
|
+
*
|
|
5
|
+
* The audio-notification feature needs four short sounds and must NOT ship
|
|
6
|
+
* binary audio assets (no licensing question, no repo weight). This module
|
|
7
|
+
* computes the samples instead: a note is a fundamental plus a few harmonics
|
|
8
|
+
* under an attack/decay envelope, and the mix is normalized so every slot lands
|
|
9
|
+
* at the same loudness.
|
|
10
|
+
*
|
|
11
|
+
* Output format is deliberately the one the whole stack already proved it can
|
|
12
|
+
* play (verified end to end with Windows Media.SoundPlayer): RIFF/WAVE,
|
|
13
|
+
* 16-bit PCM, mono, 44.1 kHz.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const SAMPLE_RATE = 44100;
|
|
17
|
+
|
|
18
|
+
/** Equal-temperament pitch of one note name against A4 = 440 Hz. */
|
|
19
|
+
const SEMITONES = { C: -9, 'C#': -8, D: -7, 'D#': -6, E: -5, F: -4, 'F#': -3, G: -2, 'G#': -1, A: 0, 'A#': 1, B: 2 };
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Resolve a note name such as `C5`, `F#4` or `A4` to hertz.
|
|
23
|
+
* @param name - letter, optional `#`, then the octave digit(s).
|
|
24
|
+
* @returns frequency in hertz.
|
|
25
|
+
*/
|
|
26
|
+
function noteHz(name) {
|
|
27
|
+
const match = /^([A-G]#?)(-?\d+)$/.exec(String(name));
|
|
28
|
+
if (match === null) throw new Error(`bad note name: ${name}`);
|
|
29
|
+
const semitone = SEMITONES[match[1]];
|
|
30
|
+
const octave = Number(match[2]);
|
|
31
|
+
return 440 * Math.pow(2, (semitone + (octave - 4) * 12) / 12);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Timbre presets: [harmonic multiplier, amplitude] pairs. */
|
|
35
|
+
const TIMBRES = {
|
|
36
|
+
// Warm chime: fundamental with a soft octave and a faint twelfth.
|
|
37
|
+
chime: [[1, 1], [2, 0.3], [3, 0.08]],
|
|
38
|
+
// Bright, more present top end — for the short "received" blip.
|
|
39
|
+
blip: [[1, 1], [2, 0.42], [3, 0.12]],
|
|
40
|
+
// Hollow and darker — used where the sound must read as a warning.
|
|
41
|
+
hollow: [[1, 1], [2, 0.12], [3, 0.3]],
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Mix one note into the sample buffer.
|
|
46
|
+
*
|
|
47
|
+
* @param data - mono sample buffer, added into (not overwritten).
|
|
48
|
+
* @param spec - frequency (Hz), start (s), duration (s), gain, timbre, detune
|
|
49
|
+
* in cents applied to the whole note, and envelope shape.
|
|
50
|
+
*/
|
|
51
|
+
function addNote(data, spec) {
|
|
52
|
+
const {
|
|
53
|
+
freq,
|
|
54
|
+
start,
|
|
55
|
+
duration,
|
|
56
|
+
gain,
|
|
57
|
+
timbre = 'chime',
|
|
58
|
+
detuneCents = 0,
|
|
59
|
+
attack = 0.006,
|
|
60
|
+
decay = 1.15,
|
|
61
|
+
curve = 2.2,
|
|
62
|
+
} = spec;
|
|
63
|
+
const hz = freq * Math.pow(2, detuneCents / 1200);
|
|
64
|
+
const from = Math.floor(start * SAMPLE_RATE);
|
|
65
|
+
const length = Math.floor(duration * SAMPLE_RATE);
|
|
66
|
+
const attackSamples = Math.max(1, Math.floor(attack * SAMPLE_RATE));
|
|
67
|
+
const voices = TIMBRES[timbre];
|
|
68
|
+
if (voices === undefined) throw new Error(`unknown timbre: ${timbre}`);
|
|
69
|
+
for (let i = 0; i < length; i++) {
|
|
70
|
+
const cursor = from + i;
|
|
71
|
+
if (cursor >= data.length) break;
|
|
72
|
+
const t = i / SAMPLE_RATE;
|
|
73
|
+
const envelope =
|
|
74
|
+
(i < attackSamples ? i / attackSamples : 1) *
|
|
75
|
+
Math.pow(1 - i / length, curve) *
|
|
76
|
+
Math.exp(-decay * t);
|
|
77
|
+
let sample = 0;
|
|
78
|
+
for (const [multiplier, amplitude] of voices) {
|
|
79
|
+
sample += amplitude * Math.sin(2 * Math.PI * hz * multiplier * t);
|
|
80
|
+
}
|
|
81
|
+
data[cursor] += sample * envelope * gain;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Render a slot definition to a complete WAV file.
|
|
87
|
+
*
|
|
88
|
+
* @param slot - `{ duration, peakDbfs, notes: [...] }` where each note uses the
|
|
89
|
+
* `addNote` fields plus a `note` name instead of a raw frequency.
|
|
90
|
+
* @returns the file bytes.
|
|
91
|
+
*/
|
|
92
|
+
function renderWav(slot) {
|
|
93
|
+
const total = Math.floor(SAMPLE_RATE * slot.duration);
|
|
94
|
+
const data = new Float64Array(total);
|
|
95
|
+
for (const note of slot.notes) {
|
|
96
|
+
addNote(data, Object.assign({}, note, {
|
|
97
|
+
freq: note.freq === undefined ? noteHz(note.note) : note.freq,
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
let peak = 0;
|
|
101
|
+
for (let i = 0; i < total; i++) peak = Math.max(peak, Math.abs(data[i]));
|
|
102
|
+
const target = Math.pow(10, (slot.peakDbfs === undefined ? -2 : slot.peakDbfs) / 20);
|
|
103
|
+
const scale = peak > 0 ? target / peak : 1;
|
|
104
|
+
const pcm = Buffer.alloc(total * 2);
|
|
105
|
+
for (let i = 0; i < total; i++) {
|
|
106
|
+
let value = Math.round(data[i] * scale * 32767);
|
|
107
|
+
if (value > 32767) value = 32767;
|
|
108
|
+
if (value < -32768) value = -32768;
|
|
109
|
+
pcm.writeInt16LE(value, i * 2);
|
|
110
|
+
}
|
|
111
|
+
const header = Buffer.alloc(44);
|
|
112
|
+
header.write('RIFF', 0, 'ascii');
|
|
113
|
+
header.writeUInt32LE(36 + pcm.length, 4);
|
|
114
|
+
header.write('WAVE', 8, 'ascii');
|
|
115
|
+
header.write('fmt ', 12, 'ascii');
|
|
116
|
+
header.writeUInt32LE(16, 16);
|
|
117
|
+
header.writeUInt16LE(1, 20); // PCM
|
|
118
|
+
header.writeUInt16LE(1, 22); // mono
|
|
119
|
+
header.writeUInt32LE(SAMPLE_RATE, 24);
|
|
120
|
+
header.writeUInt32LE(SAMPLE_RATE * 2, 28);
|
|
121
|
+
header.writeUInt16LE(2, 32);
|
|
122
|
+
header.writeUInt16LE(16, 34);
|
|
123
|
+
header.write('data', 36, 'ascii');
|
|
124
|
+
header.writeUInt32LE(pcm.length, 40);
|
|
125
|
+
return Buffer.concat([header, pcm]);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Parse a WAV buffer far enough to locate its PCM data and format. */
|
|
129
|
+
function parseWav(buffer) {
|
|
130
|
+
if (buffer.length < 44) return undefined;
|
|
131
|
+
if (buffer.toString('ascii', 0, 4) !== 'RIFF' || buffer.toString('ascii', 8, 12) !== 'WAVE') return undefined;
|
|
132
|
+
let offset = 12;
|
|
133
|
+
let audioFormat = 0;
|
|
134
|
+
let bitsPerSample = 0;
|
|
135
|
+
let channels = 0;
|
|
136
|
+
let sampleRate = 0;
|
|
137
|
+
let dataOffset = -1;
|
|
138
|
+
let dataSize = 0;
|
|
139
|
+
while (offset + 8 <= buffer.length) {
|
|
140
|
+
const id = buffer.toString('ascii', offset, offset + 4);
|
|
141
|
+
const chunkSize = buffer.readUInt32LE(offset + 4);
|
|
142
|
+
const body = offset + 8;
|
|
143
|
+
/* chunkSize is file-controlled, so every read below is also bounded by the
|
|
144
|
+
real buffer length: a truncated fmt chunk (declared size past the end of
|
|
145
|
+
the file) would otherwise throw RangeError out of parseWav — and
|
|
146
|
+
scaleWavVolume runs it on user-dropped files whenever volume < 100. */
|
|
147
|
+
if (id === 'fmt ' && chunkSize >= 16 && buffer.length >= body + 16) {
|
|
148
|
+
audioFormat = buffer.readUInt16LE(body);
|
|
149
|
+
channels = buffer.readUInt16LE(body + 2);
|
|
150
|
+
sampleRate = buffer.readUInt32LE(body + 4);
|
|
151
|
+
bitsPerSample = buffer.readUInt16LE(body + 14);
|
|
152
|
+
// WAVE_FORMAT_EXTENSIBLE wraps the real format in the first two bytes of
|
|
153
|
+
// the sub-format GUID.
|
|
154
|
+
if (audioFormat === 0xfffe && chunkSize >= 40 && buffer.length >= body + 26
|
|
155
|
+
&& buffer.readUInt16LE(body + 24) === 1) audioFormat = 1;
|
|
156
|
+
} else if (id === 'data') {
|
|
157
|
+
dataOffset = body;
|
|
158
|
+
dataSize = Math.min(chunkSize, buffer.length - body);
|
|
159
|
+
}
|
|
160
|
+
if (dataOffset >= 0 && bitsPerSample > 0) break;
|
|
161
|
+
offset = body + chunkSize + (chunkSize % 2);
|
|
162
|
+
}
|
|
163
|
+
if (dataOffset < 0 || audioFormat !== 1) return undefined;
|
|
164
|
+
if (channels <= 0 || sampleRate <= 0) return undefined;
|
|
165
|
+
return { dataOffset, dataSize, bitsPerSample, channels, sampleRate };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Rescale a PCM WAV's samples by `volume` percent without touching the system
|
|
170
|
+
* volume. Returns the original buffer when the format is not rescalable, so a
|
|
171
|
+
* caller can always write the result out.
|
|
172
|
+
*
|
|
173
|
+
* @param buffer - the source WAV bytes.
|
|
174
|
+
* @param volume - 0..100.
|
|
175
|
+
* @returns scaled WAV bytes (or the input, unchanged, when scaling is a no-op).
|
|
176
|
+
*/
|
|
177
|
+
function scaleWavVolume(buffer, volume) {
|
|
178
|
+
const gain = volume / 100;
|
|
179
|
+
if (gain === 1) return buffer;
|
|
180
|
+
const parsed = parseWav(buffer);
|
|
181
|
+
if (parsed === undefined) return buffer;
|
|
182
|
+
const { dataOffset, dataSize, bitsPerSample, channels } = parsed;
|
|
183
|
+
if (bitsPerSample !== 16 && bitsPerSample !== 8) return buffer;
|
|
184
|
+
/* Scale EVERY channel. The first version assumed mono and stepped 2 bytes per
|
|
185
|
+
sample, so on stereo input it scaled only the left channel — volume 50 would
|
|
186
|
+
have produced a left channel at half level and an untouched right one. The
|
|
187
|
+
bundled tones are mono, but a user-supplied file need not be, and the whole
|
|
188
|
+
point of this path is honouring a user's own audio. */
|
|
189
|
+
const frameBytes = (bitsPerSample / 8) * channels;
|
|
190
|
+
const out = Buffer.from(buffer);
|
|
191
|
+
const frames = Math.floor(dataSize / frameBytes);
|
|
192
|
+
if (bitsPerSample === 16) {
|
|
193
|
+
for (let frame = 0; frame < frames; frame++) {
|
|
194
|
+
for (let channel = 0; channel < channels; channel++) {
|
|
195
|
+
const pos = dataOffset + frame * frameBytes + channel * 2;
|
|
196
|
+
let value = Math.round(out.readInt16LE(pos) * gain);
|
|
197
|
+
if (value > 32767) value = 32767;
|
|
198
|
+
else if (value < -32768) value = -32768;
|
|
199
|
+
out.writeInt16LE(value, pos);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
for (let frame = 0; frame < frames; frame++) {
|
|
204
|
+
for (let channel = 0; channel < channels; channel++) {
|
|
205
|
+
const pos = dataOffset + frame * frameBytes + channel;
|
|
206
|
+
let value = Math.round((out.readUInt8(pos) - 128) * gain + 128);
|
|
207
|
+
if (value > 255) value = 255;
|
|
208
|
+
else if (value < 0) value = 0;
|
|
209
|
+
out.writeUInt8(value, pos);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return out;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
module.exports = { SAMPLE_RATE, noteHz, renderWav, scaleWavVolume, parseWav };
|
package/locale/en.json
ADDED
package/locale/zh.json
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,113 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-theme-endfield",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.2.2",
|
|
4
|
+
"description": "DeepSeek Harness web theme: the industrial editorial look of the Arknights: Endfield official site — cream paper, ink text, signal-yellow accents, zero radius. Settings persist through the DSH volatile Config + configForms transport (0.2.0-rc.2 and 0.1.7+), with a ctx.settingsScope fallback for older hosts.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"deepseek-harness",
|
|
7
|
+
"dsh",
|
|
8
|
+
"dsh-plugin",
|
|
9
|
+
"plugin",
|
|
10
|
+
"theme",
|
|
11
|
+
"endfield",
|
|
12
|
+
"arknights",
|
|
13
|
+
"client"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/ymh0000123/dsh-theme-endfield.git"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/ymh0000123/dsh-theme-endfield#readme",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/ymh0000123/dsh-theme-endfield/issues"
|
|
23
|
+
},
|
|
24
|
+
"main": "index.js",
|
|
25
|
+
"scripts": {
|
|
26
|
+
"check": "node scripts/build-host.js --check && node scripts/build-client.js --check && node scripts/build-contour-worker.js --check && node check.js",
|
|
27
|
+
"selftest": "node selftest.js",
|
|
28
|
+
"sound:build": "node scripts/build-sounds.js",
|
|
29
|
+
"sound:check": "node scripts/build-sounds.js --check",
|
|
30
|
+
"test:audio": "node test/audio-notify.test.js",
|
|
31
|
+
"test:audio-watch": "node test/audio-attention-watch.test.js && node test/host-no-inject.test.js",
|
|
32
|
+
"test:contour": "node test/contour-render.test.js",
|
|
33
|
+
"test:settings": "node test/settings-rows.test.js && node test/settings-durable-hold.test.js && node test/settings-config-forms.test.js && node test/settings-config-fallback.test.js && node test/settings-namespace.test.js && node test/settings-off.test.js && node test/settings-locale.test.js",
|
|
34
|
+
"test:font": "node test/font-scope.test.js",
|
|
35
|
+
"test:thunder": "node test/thunder-edges.test.js && node test/thunder-shot.js && node test/thunder-dismiss.test.js",
|
|
36
|
+
"test:palette": "node test/palette-contrast.test.js && node test/palette-switch.test.js",
|
|
37
|
+
"test:menu": "node test/menu-surface.test.js dark && node test/menu-surface.test.js light",
|
|
38
|
+
"test:selector": "node test/selector-guard.test.js && node test/preset-chip.test.js",
|
|
39
|
+
"test:buttons": "node test/settings-buttons.test.js && node test/hover-check.js",
|
|
40
|
+
"test:balance": "node test/balance-window.test.js && node test/balance-capsule.test.js && node test/credit-capsule.test.js",
|
|
41
|
+
"test:live": "node test/live-check.js",
|
|
42
|
+
"test:specks": "node test/contour-specks.test.js",
|
|
43
|
+
"test:watermark": "node test/watermark-stacking.test.js",
|
|
44
|
+
"test:smoothness": "node test/contour-smoothness.test.js",
|
|
45
|
+
"test:cusps": "node test/contour-cusps.test.js",
|
|
46
|
+
"test:a11y": "node test/contour-a11y.test.js",
|
|
47
|
+
"test:coverage": "node test/contour-coverage.test.js",
|
|
48
|
+
"test:perf": "node test/contour-perf.test.js",
|
|
49
|
+
"test:loader": "node test/loader-performance.test.js && node test/loader-late-prefs.test.js",
|
|
50
|
+
"test": "node check.js && node selftest.js && node test/font-scope.test.js && node test/palette-contrast.test.js && node test/palette-switch.test.js && node test/menu-surface.test.js dark && node test/menu-surface.test.js light && node test/settings-buttons.test.js && node test/hover-check.js && node test/selector-guard.test.js && node test/preset-chip.test.js && node test/balance-window.test.js && node test/balance-capsule.test.js && node test/credit-capsule.test.js && node test/settings-rows.test.js && node test/settings-durable-hold.test.js && node test/settings-config-forms.test.js && node test/settings-config-fallback.test.js && node test/settings-namespace.test.js && node test/settings-off.test.js && node test/settings-locale.test.js && node test/audio-notify.test.js && node test/audio-attention-watch.test.js && node test/host-no-inject.test.js && node scripts/build-sounds.js --check && node test/thunder-edges.test.js && node test/thunder-shot.js && node test/thunder-dismiss.test.js && node test/contour-render.test.js && node test/loader-performance.test.js && node test/loader-late-prefs.test.js && node test/contour-specks.test.js && node test/watermark-stacking.test.js && node test/contour-smoothness.test.js && node test/contour-cusps.test.js && node test/contour-a11y.test.js && node test/contour-coverage.test.js && node test/contour-perf.test.js && node test/contour-density.test.js && node test/contour-bounds.test.js && node scripts/build-host.js --check && node scripts/build-client.js --check && node scripts/build-contour-worker.js --check && node test/worker-eol.test.js && node test/contour-worker.test.js && node test/theme-sheet-refresh.test.js && node test/titlebar-probe.test.js && node test/corner-shape.test.js && node test/glass.test.js && node test/contour-trail.test.js && node test/contour-trail-browser.test.js && node test/scroll-anim.test.js && node test/contour-loop-reentry.test.js",
|
|
51
|
+
"test:ci": "node check.js && node selftest.js && node test/font-scope.test.js && node test/palette-contrast.test.js && node test/palette-switch.test.js && node test/menu-surface.test.js dark && node test/menu-surface.test.js light && node test/settings-buttons.test.js && node test/hover-check.js && node test/selector-guard.test.js && node test/preset-chip.test.js && node test/balance-window.test.js && node test/balance-capsule.test.js && node test/credit-capsule.test.js && node test/settings-rows.test.js && node test/settings-durable-hold.test.js && node test/settings-config-forms.test.js && node test/settings-config-fallback.test.js && node test/settings-namespace.test.js && node test/settings-off.test.js && node test/settings-locale.test.js && node test/audio-notify.test.js && node test/audio-attention-watch.test.js && node test/host-no-inject.test.js && node scripts/build-sounds.js --check && node test/thunder-edges.test.js && node test/thunder-shot.js && node test/thunder-dismiss.test.js && node test/contour-render.test.js && node test/loader-performance.test.js && node test/loader-late-prefs.test.js && node test/contour-specks.test.js && node test/watermark-stacking.test.js && node test/contour-smoothness.test.js && node test/contour-cusps.test.js && node test/contour-a11y.test.js && node test/contour-bounds.test.js && node scripts/build-host.js --check && node scripts/build-client.js --check && node scripts/build-contour-worker.js --check && node test/worker-eol.test.js && node test/contour-worker.test.js && node test/theme-sheet-refresh.test.js && node test/titlebar-probe.test.js && node test/corner-shape.test.js && node test/glass.test.js && node test/contour-trail.test.js && node test/contour-trail-browser.test.js && node test/scroll-anim.test.js && node test/contour-loop-reentry.test.js",
|
|
52
|
+
"shots": "node test/shoot.js",
|
|
53
|
+
"shots:verify": "node test/shoot.js && node test/verify-shots.js",
|
|
54
|
+
"test:bounds": "node test/contour-bounds.test.js",
|
|
55
|
+
"build:host": "node scripts/build-host.js",
|
|
56
|
+
"check:host": "node scripts/build-host.js --check",
|
|
57
|
+
"build:client": "node scripts/build-client.js",
|
|
58
|
+
"check:client": "node scripts/build-client.js --check",
|
|
59
|
+
"build:worker": "node scripts/build-contour-worker.js",
|
|
60
|
+
"check:worker": "node scripts/build-contour-worker.js --check",
|
|
61
|
+
"test:worker": "node scripts/build-host.js --check && node scripts/build-client.js --check && node scripts/build-contour-worker.js --check && node test/worker-eol.test.js && node test/contour-worker.test.js",
|
|
62
|
+
"test:glass": "node test/glass.test.js",
|
|
63
|
+
"test:sheet": "node test/theme-sheet-refresh.test.js",
|
|
64
|
+
"test:corners": "node test/corner-shape.test.js",
|
|
65
|
+
"test:trail": "node test/contour-trail.test.js",
|
|
66
|
+
"test:trail-browser": "node test/contour-trail-browser.test.js",
|
|
67
|
+
"test:scroll": "node test/scroll-anim.test.js"
|
|
68
|
+
},
|
|
69
|
+
"exports": {
|
|
70
|
+
".": "./index.js",
|
|
71
|
+
"./client": "./client.js",
|
|
72
|
+
"./package.json": "./package.json",
|
|
73
|
+
"./locale/*.json": "./locale/*.json"
|
|
74
|
+
},
|
|
75
|
+
"dsh": {
|
|
76
|
+
"bundle": {
|
|
77
|
+
"patch": "./cordis.patch.yml"
|
|
78
|
+
},
|
|
79
|
+
"client": {
|
|
80
|
+
"platform": "web",
|
|
81
|
+
"immediately": true,
|
|
82
|
+
"inject": [
|
|
83
|
+
"@deepseek-ai/dsh-client-ui-theme",
|
|
84
|
+
"@deepseek-ai/dsh-client-ui-renderer",
|
|
85
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
86
|
+
"@deepseek-ai/dsh-client-locale",
|
|
87
|
+
"@deepseek-ai/dsh-api-session-controller"
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"files": [
|
|
92
|
+
"index.js",
|
|
93
|
+
"client.js",
|
|
94
|
+
"cordis.patch.yml",
|
|
95
|
+
"locale",
|
|
96
|
+
"README.md",
|
|
97
|
+
"docs",
|
|
98
|
+
"lib",
|
|
99
|
+
"sounds",
|
|
100
|
+
"LICENSE"
|
|
101
|
+
],
|
|
102
|
+
"engines": {
|
|
103
|
+
"node": ">=18"
|
|
104
|
+
},
|
|
105
|
+
"peerDependencies": {
|
|
106
|
+
"@deepseek-ai/cordis": "^4.0.1"
|
|
107
|
+
},
|
|
108
|
+
"peerDependenciesMeta": {
|
|
109
|
+
"@deepseek-ai/cordis": {
|
|
110
|
+
"optional": true
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
Binary file
|
package/sounds/boot.wav
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|