@slycode/slycode 0.2.10 → 0.2.11

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 (70) hide show
  1. package/dist/web/.next/BUILD_ID +1 -1
  2. package/dist/web/.next/build-manifest.json +2 -2
  3. package/dist/web/.next/server/app/_global-error.html +2 -2
  4. package/dist/web/.next/server/app/_global-error.rsc +1 -1
  5. package/dist/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  6. package/dist/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  7. package/dist/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  8. package/dist/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  9. package/dist/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  10. package/dist/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  11. package/dist/web/.next/server/app/_not-found.html +1 -1
  12. package/dist/web/.next/server/app/_not-found.rsc +2 -2
  13. package/dist/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  14. package/dist/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  15. package/dist/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  16. package/dist/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  17. package/dist/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  18. package/dist/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  19. package/dist/web/.next/server/app/api/cli-assets/assistant/route.js.nft.json +1 -1
  20. package/dist/web/.next/server/app/api/cli-assets/fix/route.js.nft.json +1 -1
  21. package/dist/web/.next/server/app/api/cli-assets/import/route.js.nft.json +1 -1
  22. package/dist/web/.next/server/app/api/cli-assets/route.js.nft.json +1 -1
  23. package/dist/web/.next/server/app/api/cli-assets/store/preview/route.js.nft.json +1 -1
  24. package/dist/web/.next/server/app/api/cli-assets/store/route.js.nft.json +1 -1
  25. package/dist/web/.next/server/app/api/cli-assets/sync/route.js.nft.json +1 -1
  26. package/dist/web/.next/server/app/api/cli-assets/updates/route.js.nft.json +1 -1
  27. package/dist/web/.next/server/app/api/dashboard/route.js.nft.json +1 -1
  28. package/dist/web/.next/server/app/api/file/route.js.nft.json +1 -1
  29. package/dist/web/.next/server/app/api/git-status/route.js.nft.json +1 -1
  30. package/dist/web/.next/server/app/api/kanban/route.js.nft.json +1 -1
  31. package/dist/web/.next/server/app/api/kanban/stream/route.js.nft.json +1 -1
  32. package/dist/web/.next/server/app/api/projects/[id]/route.js.nft.json +1 -1
  33. package/dist/web/.next/server/app/api/projects/reorder/route.js.nft.json +1 -1
  34. package/dist/web/.next/server/app/api/projects/route.js.nft.json +1 -1
  35. package/dist/web/.next/server/app/api/scheduler/route.js.nft.json +1 -1
  36. package/dist/web/.next/server/app/api/search/route.js.nft.json +1 -1
  37. package/dist/web/.next/server/app/api/sly-actions/invalidate/route.js.nft.json +1 -1
  38. package/dist/web/.next/server/app/api/sly-actions/route.js.nft.json +1 -1
  39. package/dist/web/.next/server/app/api/transcribe/route.js +3 -3
  40. package/dist/web/.next/server/app/api/transcribe/route.js.nft.json +1 -1
  41. package/dist/web/.next/server/app/api/version-check/route.js.nft.json +1 -1
  42. package/dist/web/.next/server/app/page.js.nft.json +1 -1
  43. package/dist/web/.next/server/app/page_client-reference-manifest.js +1 -1
  44. package/dist/web/.next/server/app/project/[id]/page.js.nft.json +1 -1
  45. package/dist/web/.next/server/app/project/[id]/page_client-reference-manifest.js +1 -1
  46. package/dist/web/.next/server/chunks/{[root-of-the-server]__934c9bb4._.js → [root-of-the-server]__0f9b71fd._.js} +1 -1
  47. package/dist/web/.next/server/chunks/[root-of-the-server]__1dec5018._.js +3 -0
  48. package/dist/web/.next/server/chunks/{[root-of-the-server]__e00fb85f._.js → [root-of-the-server]__2605d761._.js} +1 -1
  49. package/dist/web/.next/server/chunks/{[root-of-the-server]__41df0777._.js → [root-of-the-server]__53ef96b9._.js} +2 -2
  50. package/dist/web/.next/server/chunks/{[root-of-the-server]__1cdc76ef._.js → [root-of-the-server]__8ce673c9._.js} +2 -2
  51. package/dist/web/.next/server/chunks/[root-of-the-server]__a43db24d._.js +19 -0
  52. package/dist/web/.next/server/chunks/{[root-of-the-server]__104b2da3._.js → [root-of-the-server]__a4d171b5._.js} +3 -3
  53. package/dist/web/.next/server/chunks/{[root-of-the-server]__3dc5531f._.js → [root-of-the-server]__c7ac3578._.js} +1 -1
  54. package/dist/web/.next/server/pages/404.html +1 -1
  55. package/dist/web/.next/server/pages/500.html +2 -2
  56. package/dist/web/.next/static/chunks/3df3846316317676.css +1 -0
  57. package/dist/web/package-lock.json +37 -0
  58. package/dist/web/package.json +1 -0
  59. package/dist/web/src/app/api/transcribe/route.ts +7 -1
  60. package/dist/web/src/components/VoiceControlBar.tsx +1 -0
  61. package/dist/web/src/lib/webm-to-ogg-opus.ts +254 -0
  62. package/dist/web/tsconfig.tsbuildinfo +1 -1
  63. package/package.json +1 -1
  64. package/templates/kanban-seed.json +1 -1
  65. package/dist/web/.next/server/chunks/[root-of-the-server]__3998d59e._.js +0 -19
  66. package/dist/web/.next/server/chunks/[root-of-the-server]__403750fd._.js +0 -3
  67. package/dist/web/.next/static/chunks/f3d7065d54a0b9ac.css +0 -1
  68. /package/dist/web/.next/static/{_fCicMElBguqtWA_EpzdZ → eGpcv9LfmamGIm1II8SKL}/_buildManifest.js +0 -0
  69. /package/dist/web/.next/static/{_fCicMElBguqtWA_EpzdZ → eGpcv9LfmamGIm1II8SKL}/_clientMiddlewareManifest.json +0 -0
  70. /package/dist/web/.next/static/{_fCicMElBguqtWA_EpzdZ → eGpcv9LfmamGIm1II8SKL}/_ssgManifest.js +0 -0
@@ -0,0 +1,254 @@
1
+ /**
2
+ * WebM/Opus → OGG/Opus remuxer (pure JS, no ffmpeg).
3
+ *
4
+ * Extracts Opus packets from a WebM container and wraps them in a valid
5
+ * OGG Opus stream per RFC 7845. Only handles single-track audio-only WebM
6
+ * from browser MediaRecorder — not arbitrary Matroska files.
7
+ */
8
+
9
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
10
+ const { Decoder: EbmlDecoder } = require('ebml');
11
+
12
+ // --- OGG CRC-32 (polynomial 0x04C11DB7, no bit reversal) ---
13
+
14
+ const crcTable = new Uint32Array(256);
15
+ for (let i = 0; i < 256; i++) {
16
+ let r = i << 24;
17
+ for (let j = 0; j < 8; j++) {
18
+ r = r & 0x80000000 ? ((r << 1) ^ 0x04C11DB7) : (r << 1);
19
+ r = r >>> 0; // keep unsigned 32-bit
20
+ }
21
+ crcTable[i] = r;
22
+ }
23
+
24
+ function oggCrc32(data: Uint8Array): number {
25
+ let crc = 0;
26
+ for (let i = 0; i < data.length; i++) {
27
+ crc = ((crc << 8) ^ crcTable[((crc >>> 24) ^ data[i]) & 0xff]) >>> 0;
28
+ }
29
+ return crc;
30
+ }
31
+
32
+ // --- Opus packet duration parsing ---
33
+
34
+ function getOpusPacketDuration48k(packet: Uint8Array): number {
35
+ if (packet.length < 1) return 960; // fallback: 20ms
36
+
37
+ const toc = packet[0];
38
+ const config = (toc >> 3) & 0x1f;
39
+ const frameCountCode = toc & 0x03;
40
+
41
+ // Frame size in 48kHz samples based on config number
42
+ let frameSamples: number;
43
+ if (config <= 11) {
44
+ // SILK: 10ms, 20ms, 40ms, 60ms
45
+ frameSamples = [480, 960, 1920, 2880][config % 4];
46
+ } else if (config <= 15) {
47
+ // Hybrid: 10ms, 20ms
48
+ frameSamples = [480, 960][(config - 12) % 2];
49
+ } else {
50
+ // CELT: 2.5ms, 5ms, 10ms, 20ms
51
+ frameSamples = [120, 240, 480, 960][(config - 16) % 4];
52
+ }
53
+
54
+ // Number of frames per packet
55
+ let frameCount: number;
56
+ switch (frameCountCode) {
57
+ case 0: frameCount = 1; break;
58
+ case 1: frameCount = 2; break;
59
+ case 2: frameCount = 2; break;
60
+ case 3:
61
+ frameCount = packet.length >= 2 ? (packet[1] & 0x3f) : 1;
62
+ break;
63
+ default: frameCount = 1;
64
+ }
65
+
66
+ return frameSamples * frameCount;
67
+ }
68
+
69
+ // --- OGG page writer ---
70
+
71
+ function writeOggPage(
72
+ serialNumber: number,
73
+ sequenceNumber: number,
74
+ granulePosition: bigint,
75
+ flags: number, // 0x02 = BOS, 0x04 = EOS, 0x01 = continued
76
+ packets: Uint8Array[],
77
+ ): Buffer {
78
+ // Build segment table: each packet is split into 255-byte segments + remainder
79
+ const segmentSizes: number[] = [];
80
+ for (const pkt of packets) {
81
+ let remaining = pkt.length;
82
+ while (remaining >= 255) {
83
+ segmentSizes.push(255);
84
+ remaining -= 255;
85
+ }
86
+ segmentSizes.push(remaining); // final segment (0-254), 0 means exactly N*255 bytes
87
+ }
88
+
89
+ const payloadSize = packets.reduce((sum, p) => sum + p.length, 0);
90
+ const headerSize = 27 + segmentSizes.length;
91
+ const pageSize = headerSize + payloadSize;
92
+ const page = Buffer.alloc(pageSize);
93
+
94
+ // Capture pattern
95
+ page.write('OggS', 0);
96
+ // Version
97
+ page[4] = 0;
98
+ // Header type flags
99
+ page[5] = flags;
100
+ // Granule position (64-bit little-endian)
101
+ page.writeBigInt64LE(granulePosition, 6);
102
+ // Serial number
103
+ page.writeUInt32LE(serialNumber, 14);
104
+ // Page sequence number
105
+ page.writeUInt32LE(sequenceNumber, 18);
106
+ // CRC placeholder (filled after)
107
+ page.writeUInt32LE(0, 22);
108
+ // Number of segments
109
+ page[26] = segmentSizes.length;
110
+ // Segment table
111
+ for (let i = 0; i < segmentSizes.length; i++) {
112
+ page[27 + i] = segmentSizes[i];
113
+ }
114
+ // Payload
115
+ let offset = headerSize;
116
+ for (const pkt of packets) {
117
+ Buffer.from(pkt).copy(page, offset);
118
+ offset += pkt.length;
119
+ }
120
+
121
+ // Compute and write CRC
122
+ const crc = oggCrc32(page);
123
+ page.writeUInt32LE(crc, 22);
124
+
125
+ return page;
126
+ }
127
+
128
+ // --- WebM parsing ---
129
+
130
+ interface WebmParseResult {
131
+ opusHead: Buffer;
132
+ codecDelay: number; // nanoseconds
133
+ packets: Uint8Array[];
134
+ }
135
+
136
+ function parseWebmOpus(webmBuffer: Buffer): WebmParseResult {
137
+ const decoder = new EbmlDecoder();
138
+ let opusHead: Buffer | null = null;
139
+ let codecDelay = 0;
140
+ let audioTrack = 1;
141
+ const packets: Uint8Array[] = [];
142
+
143
+ // Track whether we're inside a TrackEntry to associate CodecPrivate with the right track
144
+ let inTrackEntry = false;
145
+ let currentTrackNumber = 0;
146
+ let currentCodecId = '';
147
+
148
+ const events: Array<[string, Record<string, unknown>]> = [];
149
+ decoder.on('data', (chunk: [string, Record<string, unknown>]) => events.push(chunk));
150
+ decoder.write(webmBuffer);
151
+ decoder.end();
152
+
153
+ for (const [type, tag] of events) {
154
+ const name = tag.name as string;
155
+
156
+ if (type === 'start' && name === 'TrackEntry') {
157
+ inTrackEntry = true;
158
+ currentTrackNumber = 0;
159
+ currentCodecId = '';
160
+ }
161
+
162
+ if (type === 'end' && name === 'TrackEntry') {
163
+ if (currentCodecId === 'A_OPUS' && currentTrackNumber > 0) {
164
+ audioTrack = currentTrackNumber;
165
+ }
166
+ inTrackEntry = false;
167
+ }
168
+
169
+ if (type === 'tag' && inTrackEntry) {
170
+ if (name === 'TrackNumber') {
171
+ currentTrackNumber = tag.value as number;
172
+ }
173
+ if (name === 'CodecID') {
174
+ currentCodecId = tag.value as string;
175
+ }
176
+ if (name === 'CodecPrivate') {
177
+ opusHead = Buffer.from(tag.data as Uint8Array);
178
+ }
179
+ if (name === 'CodecDelay') {
180
+ codecDelay = tag.value as number;
181
+ }
182
+ }
183
+
184
+ if (type === 'tag' && name === 'SimpleBlock') {
185
+ const track = tag.track as number;
186
+ const payload = tag.payload as Uint8Array | null;
187
+ if (track === audioTrack && payload && payload.length > 0) {
188
+ packets.push(Uint8Array.from(payload));
189
+ }
190
+ }
191
+ }
192
+
193
+ if (!opusHead) {
194
+ throw new Error('No Opus CodecPrivate (OpusHead) found in WebM');
195
+ }
196
+ if (packets.length === 0) {
197
+ throw new Error('No Opus audio packets found in WebM');
198
+ }
199
+
200
+ return { opusHead, codecDelay, packets };
201
+ }
202
+
203
+ // --- Main remux function ---
204
+
205
+ export function remuxWebmToOgg(webmBuffer: Buffer): Buffer {
206
+ const { opusHead, codecDelay, packets } = parseWebmOpus(webmBuffer);
207
+
208
+ const serialNumber = Math.floor(Math.random() * 0xFFFFFFFF);
209
+ let sequenceNumber = 0;
210
+
211
+ // Pre-skip: convert CodecDelay from nanoseconds to 48kHz samples
212
+ // Also read pre-skip from OpusHead itself (bytes 10-11, little-endian uint16)
213
+ const opusHeadPreSkip = opusHead.readUInt16LE(10);
214
+ const preSkip = codecDelay > 0
215
+ ? Math.round(codecDelay / 1e9 * 48000)
216
+ : opusHeadPreSkip;
217
+
218
+ // If CodecDelay-derived pre-skip differs from OpusHead, patch OpusHead
219
+ const finalOpusHead = Buffer.from(opusHead);
220
+ if (preSkip !== opusHeadPreSkip) {
221
+ finalOpusHead.writeUInt16LE(preSkip, 10);
222
+ }
223
+
224
+ const pages: Buffer[] = [];
225
+
226
+ // Page 0: OpusHead (BOS)
227
+ pages.push(writeOggPage(serialNumber, sequenceNumber++, BigInt(0), 0x02, [finalOpusHead]));
228
+
229
+ // Page 1: OpusTags
230
+ const vendor = Buffer.from('remux');
231
+ const opusTags = Buffer.alloc(8 + 4 + vendor.length + 4);
232
+ opusTags.write('OpusTags', 0);
233
+ opusTags.writeUInt32LE(vendor.length, 8);
234
+ vendor.copy(opusTags, 12);
235
+ opusTags.writeUInt32LE(0, 12 + vendor.length); // zero user comments
236
+ pages.push(writeOggPage(serialNumber, sequenceNumber++, BigInt(0), 0, [opusTags]));
237
+
238
+ // Data pages: one packet per page for simplicity
239
+ let granulePosition = BigInt(preSkip); // starts at pre-skip per RFC 7845
240
+ for (let i = 0; i < packets.length; i++) {
241
+ const duration = getOpusPacketDuration48k(packets[i]);
242
+ granulePosition += BigInt(duration);
243
+ const isLast = i === packets.length - 1;
244
+ pages.push(writeOggPage(
245
+ serialNumber,
246
+ sequenceNumber++,
247
+ granulePosition,
248
+ isLast ? 0x04 : 0, // EOS on last page
249
+ [packets[i]],
250
+ ));
251
+ }
252
+
253
+ return Buffer.concat(pages);
254
+ }