@agent-native/core 0.153.10 → 0.154.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/corpus/README.md +1 -1
- package/corpus/templates/analytics/AGENTS.md +20 -30
- package/corpus/templates/analytics/actions/search-dashboard-references.ts +58 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/analytics/app/lib/utils.ts +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/ViewSqlPopover.tsx +1 -1
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -0
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +366 -3
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +3 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +6 -2
- package/corpus/templates/calendar/app/components/calendar/EventDialog.tsx +1 -1
- package/corpus/templates/calendar/app/lib/utils.ts +1 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +32 -5
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +15 -15
- package/corpus/templates/clips/app/i18n/en-US.ts +3 -3
- package/corpus/templates/clips/app/lib/utils.ts +5 -6
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +43 -8
- package/corpus/templates/clips/desktop/src/app.tsx +26 -12
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +23 -9
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +261 -11
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +21 -3
- package/corpus/templates/clips/shared/mic-audio-cleanup.ts +350 -0
- package/corpus/templates/content/app/i18n-data.ts +10 -10
- package/corpus/templates/content/scripts/check-native-deps.mjs +181 -15
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +79 -7
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +14 -2
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +2 -2
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +35 -11
- package/corpus/templates/design/actions/get-design-system.ts +103 -3
- package/corpus/templates/design/actions/import-design-tokens.ts +37 -8
- package/corpus/templates/design/actions/import-github.ts +32 -138
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +49 -16
- package/corpus/templates/design/actions/present-design-variants.ts +93 -4
- package/corpus/templates/design/actions/run-design-audit.ts +229 -0
- package/corpus/templates/design/actions/sync-design-system-with-builder.ts +64 -0
- package/corpus/templates/design/app/components/design/code-workbench/commands.ts +2 -2
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +17 -4
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +5 -1
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +5 -1
- package/corpus/templates/design/app/hooks/use-question-flow.ts +81 -5
- package/corpus/templates/design/app/i18n/en-US.ts +1 -1
- package/corpus/templates/design/app/i18n-data.ts +32 -1
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +10 -10
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +83 -11
- package/corpus/templates/design/app/pages/DesignSystems.tsx +14 -0
- package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +22 -0
- package/corpus/templates/design/changelog/2026-08-13-a-screen-that-would-render-behind-an-invisible-alpine-overla.md +6 -0
- package/corpus/templates/design/changelog/2026-08-13-attach-a-ui-screenshot-and-the-design-is-reproduced-not-rein.md +6 -0
- package/corpus/templates/design/changelog/2026-08-13-linking-a-design-system-means-you-never-get-generic-directio.md +6 -0
- package/corpus/templates/design/changelog/2026-08-13-the-design-audit-now-reports-when-a-screen-ignores-its-linke.md +6 -0
- package/corpus/templates/design/changelog/2026-08-13-the-design-system-preview-now-shows-how-many-named-tokens-we.md +6 -0
- package/corpus/templates/design/changelog/2026-08-13-your-design-system-prompt-and-reference-screenshots-now-reac.md +6 -0
- package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +18 -2
- package/corpus/templates/design/shared/design-review.ts +1 -0
- package/corpus/templates/design/shared/html-integrity.ts +171 -0
- package/corpus/templates/mail/app/lib/utils.ts +1 -1
- package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +10 -6
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +41 -3
- package/corpus/templates/slides/actions/sync-design-system-with-builder.ts +64 -0
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +1 -1
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +193 -20
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +58 -33
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +28 -41
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +119 -91
- package/corpus/templates/slides/app/components/editor/ImageOverlay.tsx +16 -0
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +158 -31
- package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +30 -14
- package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +2 -2
- package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +4 -1
- package/corpus/templates/slides/app/components/editor/rich-text-selection.ts +14 -0
- package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +24 -0
- package/corpus/templates/slides/app/global.css +24 -0
- package/corpus/templates/slides/app/hooks/use-navigation-state.ts +5 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +19 -10
- package/corpus/templates/slides/app/lib/deck-filter.ts +47 -0
- package/corpus/templates/slides/app/lib/export-google-slides-client.ts +15 -4
- package/corpus/templates/slides/app/lib/export-pptx-client.ts +637 -1
- package/corpus/templates/slides/app/lib/image-download.ts +84 -0
- package/corpus/templates/slides/app/lib/utils.ts +1 -1
- package/corpus/templates/slides/app/pages/Index.tsx +25 -9
- package/corpus/templates/slides/netlify.toml +1 -0
- package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +14 -2
- package/dist/agent/production-agent.js +1 -1
- package/dist/brand-kit/types.d.ts +10 -2
- package/dist/cli/code.js +1 -1
- package/dist/cli/index.js +30 -1
- package/dist/cli/native-dependencies.d.ts +24 -0
- package/dist/cli/native-dependencies.js +264 -0
- package/dist/cli/plan-local.js +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.js +2 -2
- package/dist/cli/visualize-repo.js +1 -1
- package/dist/client/FeedbackButton.js +12 -12
- package/dist/client/agent-chat-adapter.js +3 -4
- package/dist/client/assistant-ui-recovery.d.ts +1 -1
- package/dist/client/assistant-ui-recovery.js +4 -0
- package/dist/client/chat/message-components.d.ts +11 -3
- package/dist/client/chat/message-components.js +31 -5
- package/dist/client/chat/tool-call-display.d.ts +2 -1
- package/dist/client/chat/tool-call-display.js +33 -15
- package/dist/client/db-admin/SqlEditor.js +1 -1
- package/dist/client/dev-overlay/DevOverlay.js +2 -2
- package/dist/client/extensions/portable-extension.js +4 -0
- package/dist/client/guided-questions.d.ts +8 -0
- package/dist/client/guided-questions.js +12 -3
- package/dist/client/sharing/ShareButton.js +16 -24
- package/dist/client/sse-event-processor.js +35 -15
- package/dist/client/tool-display.d.ts +9 -0
- package/dist/client/tool-display.js +39 -0
- package/dist/client/vite-dev-recovery-script.js +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/extensions/html-shell.js +5 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/agent-chat/prompt-resources.js +17 -16
- package/dist/server/agent-chat-plugin.d.ts +9 -0
- package/dist/server/agent-chat-plugin.js +29 -7
- package/dist/server/builder-design-systems.d.ts +33 -1
- package/dist/server/builder-design-systems.js +293 -11
- package/dist/server/design-token-utils.d.ts +11 -0
- package/dist/server/design-token-utils.js +68 -16
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conservative browser-side mic cleanup for Clips recorders.
|
|
3
|
+
*
|
|
4
|
+
* The goal is not to "fix" bad audio with a heavy denoiser. Instead we trim
|
|
5
|
+
* obvious AC rumble, notch the mains hum that sits under cheap mics, and only
|
|
6
|
+
* apply a gentle downward expander when the signal is already quiet.
|
|
7
|
+
*
|
|
8
|
+
* Safe failure rule: if the browser does not support the needed Web Audio
|
|
9
|
+
* pieces, or if graph setup fails for any reason, callers get the original
|
|
10
|
+
* stream back with a no-op cleanup handle rather than a thrown error.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const MIC_AUDIO_HIGH_PASS_HZ = 70;
|
|
14
|
+
export const MIC_AUDIO_HUM_NOTCH_FREQUENCIES = [50, 60, 100, 120] as const;
|
|
15
|
+
export const MIC_AUDIO_HUM_NOTCH_Q = 35;
|
|
16
|
+
export const MIC_AUDIO_EXPANDER_INTERVAL_MS = 40;
|
|
17
|
+
export const MIC_AUDIO_EXPANDER_FLOOR_GAIN = 0.24;
|
|
18
|
+
export const MIC_AUDIO_EXPANDER_OPEN_DB = -42;
|
|
19
|
+
export const MIC_AUDIO_EXPANDER_CLOSE_DB = -58;
|
|
20
|
+
export const MIC_AUDIO_EXPANDER_SMOOTHING_SECONDS = 0.09;
|
|
21
|
+
|
|
22
|
+
export type MicAudioCleanupPreset = "balanced" | "strong";
|
|
23
|
+
|
|
24
|
+
export interface MicAudioCleanupOptions {
|
|
25
|
+
audioContext?: AudioContext | null;
|
|
26
|
+
preset?: MicAudioCleanupPreset;
|
|
27
|
+
intervalMs?: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface MicAudioCleanupHandle {
|
|
31
|
+
readonly inputStream: MediaStream;
|
|
32
|
+
readonly stream: MediaStream;
|
|
33
|
+
readonly active: boolean;
|
|
34
|
+
stop(): void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type AudioContextLike = Pick<
|
|
38
|
+
AudioContext,
|
|
39
|
+
| "state"
|
|
40
|
+
| "currentTime"
|
|
41
|
+
| "resume"
|
|
42
|
+
| "close"
|
|
43
|
+
| "createAnalyser"
|
|
44
|
+
| "createBiquadFilter"
|
|
45
|
+
| "createGain"
|
|
46
|
+
| "createMediaStreamDestination"
|
|
47
|
+
| "createMediaStreamSource"
|
|
48
|
+
>;
|
|
49
|
+
|
|
50
|
+
type AudioNodeLike = {
|
|
51
|
+
connect(destination: unknown): unknown;
|
|
52
|
+
disconnect(): void;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
type GainNodeLike = AudioNodeLike & {
|
|
56
|
+
gain: AudioParam & {
|
|
57
|
+
setTargetAtTime?: (
|
|
58
|
+
value: number,
|
|
59
|
+
startTime: number,
|
|
60
|
+
timeConstant: number,
|
|
61
|
+
) => void;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
type BiquadFilterNodeLike = AudioNodeLike & {
|
|
66
|
+
type: BiquadFilterType;
|
|
67
|
+
frequency: AudioParam;
|
|
68
|
+
Q: AudioParam;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
type AnalyserNodeLike = AudioNodeLike & {
|
|
72
|
+
fftSize: number;
|
|
73
|
+
getFloatTimeDomainData: (dataArray: Float32Array<ArrayBuffer>) => void;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
type MediaStreamDestinationNodeLike = AudioNodeLike & {
|
|
77
|
+
stream: MediaStream;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
type MediaStreamSourceNodeLike = AudioNodeLike;
|
|
81
|
+
|
|
82
|
+
interface MicAudioCleanupRuntime {
|
|
83
|
+
ctx: AudioContextLike;
|
|
84
|
+
ownsContext: boolean;
|
|
85
|
+
source: MediaStreamSourceNodeLike;
|
|
86
|
+
highPass: BiquadFilterNodeLike;
|
|
87
|
+
notches: BiquadFilterNodeLike[];
|
|
88
|
+
gain: GainNodeLike;
|
|
89
|
+
analyser: AnalyserNodeLike;
|
|
90
|
+
destination: MediaStreamDestinationNodeLike;
|
|
91
|
+
intervalId: ReturnType<typeof setInterval>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function getAudioContextCtor(): typeof AudioContext | null {
|
|
95
|
+
const global = globalThis as typeof globalThis & {
|
|
96
|
+
AudioContext?: typeof AudioContext;
|
|
97
|
+
webkitAudioContext?: typeof AudioContext;
|
|
98
|
+
};
|
|
99
|
+
return global.AudioContext ?? global.webkitAudioContext ?? null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function normalizePreset(preset: MicAudioCleanupPreset | undefined) {
|
|
103
|
+
return preset === "strong"
|
|
104
|
+
? {
|
|
105
|
+
floorGain: 0.16,
|
|
106
|
+
openDb: -38,
|
|
107
|
+
closeDb: -56,
|
|
108
|
+
smoothingSeconds: 0.07,
|
|
109
|
+
intervalMs: 32,
|
|
110
|
+
}
|
|
111
|
+
: {
|
|
112
|
+
floorGain: MIC_AUDIO_EXPANDER_FLOOR_GAIN,
|
|
113
|
+
openDb: MIC_AUDIO_EXPANDER_OPEN_DB,
|
|
114
|
+
closeDb: MIC_AUDIO_EXPANDER_CLOSE_DB,
|
|
115
|
+
smoothingSeconds: MIC_AUDIO_EXPANDER_SMOOTHING_SECONDS,
|
|
116
|
+
intervalMs: MIC_AUDIO_EXPANDER_INTERVAL_MS,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function hasAudioTrack(stream: MediaStream): boolean {
|
|
121
|
+
try {
|
|
122
|
+
return stream.getAudioTracks().length > 0;
|
|
123
|
+
// coercion-ok: an unreadable track is a typed inactive cleanup fallback.
|
|
124
|
+
} catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function buildTargetGain(
|
|
130
|
+
levelDb: number,
|
|
131
|
+
preset: ReturnType<typeof normalizePreset>,
|
|
132
|
+
) {
|
|
133
|
+
if (!Number.isFinite(levelDb)) return preset.floorGain;
|
|
134
|
+
if (levelDb >= preset.openDb) return 1;
|
|
135
|
+
if (levelDb <= preset.closeDb) return preset.floorGain;
|
|
136
|
+
|
|
137
|
+
const span = preset.openDb - preset.closeDb;
|
|
138
|
+
const t = (levelDb - preset.closeDb) / span;
|
|
139
|
+
// Ease in so the expander stays out of the way until the signal is
|
|
140
|
+
// genuinely quiet, then falls away a little more decisively.
|
|
141
|
+
return preset.floorGain + (1 - preset.floorGain) * t * t;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function measureRmsDb(samples: Float32Array): number {
|
|
145
|
+
let sumSquares = 0;
|
|
146
|
+
for (let i = 0; i < samples.length; i++) {
|
|
147
|
+
const sample = samples[i] ?? 0;
|
|
148
|
+
sumSquares += sample * sample;
|
|
149
|
+
}
|
|
150
|
+
if (sumSquares <= 0) return Number.NEGATIVE_INFINITY;
|
|
151
|
+
const rms = Math.sqrt(sumSquares / samples.length);
|
|
152
|
+
if (rms <= 0) return Number.NEGATIVE_INFINITY;
|
|
153
|
+
return 20 * Math.log10(rms);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function disconnectNode(node: AudioNodeLike | null | undefined): void {
|
|
157
|
+
if (!node) return;
|
|
158
|
+
try {
|
|
159
|
+
node.disconnect();
|
|
160
|
+
// coercion-ok: disconnect is teardown-only and may race an ended track.
|
|
161
|
+
} catch {
|
|
162
|
+
// ignore — cleanup must be best-effort.
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function stopDestinationStream(stream: MediaStream): void {
|
|
167
|
+
try {
|
|
168
|
+
for (const track of stream.getTracks()) {
|
|
169
|
+
try {
|
|
170
|
+
track.stop();
|
|
171
|
+
// coercion-ok: stopping an already-ended destination track is cleanup-only.
|
|
172
|
+
} catch {
|
|
173
|
+
// ignore
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// coercion-ok: destination teardown is best-effort after capture has ended.
|
|
177
|
+
} catch {
|
|
178
|
+
// ignore
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function createInactiveHandle(stream: MediaStream): MicAudioCleanupHandle {
|
|
183
|
+
return {
|
|
184
|
+
inputStream: stream,
|
|
185
|
+
stream,
|
|
186
|
+
active: false,
|
|
187
|
+
stop() {
|
|
188
|
+
// no-op
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function tryBuildMicAudioCleanup(
|
|
194
|
+
stream: MediaStream,
|
|
195
|
+
options: MicAudioCleanupOptions,
|
|
196
|
+
): MicAudioCleanupHandle {
|
|
197
|
+
// The browser path can hand us the actual `AudioContext` instance, while
|
|
198
|
+
// tests can inject a fake object. If neither exists, there is nothing to do.
|
|
199
|
+
const audioContextCtor = getAudioContextCtor();
|
|
200
|
+
const providedContext = options.audioContext ?? null;
|
|
201
|
+
const audioContext: AudioContextLike | null =
|
|
202
|
+
providedContext ?? (audioContextCtor ? new audioContextCtor() : null);
|
|
203
|
+
const ownsContext = !providedContext;
|
|
204
|
+
|
|
205
|
+
if (!audioContext || !hasAudioTrack(stream)) {
|
|
206
|
+
return createInactiveHandle(stream);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const preset = normalizePreset(options.preset);
|
|
210
|
+
const intervalMs = Math.max(
|
|
211
|
+
16,
|
|
212
|
+
Math.round(options.intervalMs ?? preset.intervalMs),
|
|
213
|
+
);
|
|
214
|
+
const supportsNodes =
|
|
215
|
+
typeof audioContext.createAnalyser === "function" &&
|
|
216
|
+
typeof audioContext.createBiquadFilter === "function" &&
|
|
217
|
+
typeof audioContext.createGain === "function" &&
|
|
218
|
+
typeof audioContext.createMediaStreamDestination === "function" &&
|
|
219
|
+
typeof audioContext.createMediaStreamSource === "function";
|
|
220
|
+
if (!supportsNodes) {
|
|
221
|
+
return createInactiveHandle(stream);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
let runtime: MicAudioCleanupRuntime | null = null;
|
|
225
|
+
try {
|
|
226
|
+
const source = audioContext.createMediaStreamSource(stream);
|
|
227
|
+
const highPass = audioContext.createBiquadFilter();
|
|
228
|
+
highPass.type = "highpass";
|
|
229
|
+
highPass.frequency.value = MIC_AUDIO_HIGH_PASS_HZ;
|
|
230
|
+
highPass.Q.value = 0.707;
|
|
231
|
+
|
|
232
|
+
const notches = MIC_AUDIO_HUM_NOTCH_FREQUENCIES.map((frequency) => {
|
|
233
|
+
const filter = audioContext.createBiquadFilter();
|
|
234
|
+
filter.type = "notch";
|
|
235
|
+
filter.frequency.value = frequency;
|
|
236
|
+
filter.Q.value = MIC_AUDIO_HUM_NOTCH_Q;
|
|
237
|
+
return filter;
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const gain = audioContext.createGain();
|
|
241
|
+
gain.gain.value = 1;
|
|
242
|
+
const analyser = audioContext.createAnalyser();
|
|
243
|
+
analyser.fftSize = 1024;
|
|
244
|
+
const destination = audioContext.createMediaStreamDestination();
|
|
245
|
+
|
|
246
|
+
source.connect(highPass);
|
|
247
|
+
let node: AudioNodeLike = highPass;
|
|
248
|
+
for (const notch of notches) {
|
|
249
|
+
node.connect(notch);
|
|
250
|
+
node = notch;
|
|
251
|
+
}
|
|
252
|
+
node.connect(gain);
|
|
253
|
+
node.connect(analyser);
|
|
254
|
+
gain.connect(destination);
|
|
255
|
+
|
|
256
|
+
if (
|
|
257
|
+
audioContext.state === "suspended" &&
|
|
258
|
+
typeof audioContext.resume === "function"
|
|
259
|
+
) {
|
|
260
|
+
void audioContext.resume().catch(() => {});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const samples = new Float32Array(analyser.fftSize);
|
|
264
|
+
const tick = () => {
|
|
265
|
+
if (!runtime) return;
|
|
266
|
+
try {
|
|
267
|
+
runtime.analyser.getFloatTimeDomainData(samples);
|
|
268
|
+
const nextGain = buildTargetGain(measureRmsDb(samples), preset);
|
|
269
|
+
const now = runtime.ctx.currentTime;
|
|
270
|
+
if (typeof runtime.gain.gain.setTargetAtTime === "function") {
|
|
271
|
+
runtime.gain.gain.setTargetAtTime(
|
|
272
|
+
nextGain,
|
|
273
|
+
now,
|
|
274
|
+
preset.smoothingSeconds,
|
|
275
|
+
);
|
|
276
|
+
} else {
|
|
277
|
+
runtime.gain.gain.value = nextGain;
|
|
278
|
+
}
|
|
279
|
+
// coercion-ok: a transient analyser/meter failure must not stop recording.
|
|
280
|
+
} catch {
|
|
281
|
+
// Keep the recording alive even if the meter path glitches.
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const intervalId = globalThis.setInterval(tick, intervalMs);
|
|
286
|
+
runtime = {
|
|
287
|
+
ctx: audioContext,
|
|
288
|
+
ownsContext,
|
|
289
|
+
source,
|
|
290
|
+
highPass,
|
|
291
|
+
notches,
|
|
292
|
+
gain,
|
|
293
|
+
analyser,
|
|
294
|
+
destination,
|
|
295
|
+
intervalId,
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
inputStream: stream,
|
|
300
|
+
stream: destination.stream,
|
|
301
|
+
active: true,
|
|
302
|
+
stop() {
|
|
303
|
+
if (!runtime) return;
|
|
304
|
+
const current = runtime;
|
|
305
|
+
runtime = null;
|
|
306
|
+
try {
|
|
307
|
+
clearInterval(current.intervalId);
|
|
308
|
+
// coercion-ok: timer cleanup is best-effort after the interval ends.
|
|
309
|
+
} catch {
|
|
310
|
+
// ignore
|
|
311
|
+
}
|
|
312
|
+
disconnectNode(current.source);
|
|
313
|
+
disconnectNode(current.highPass);
|
|
314
|
+
for (const notch of current.notches) disconnectNode(notch);
|
|
315
|
+
disconnectNode(current.gain);
|
|
316
|
+
disconnectNode(current.analyser);
|
|
317
|
+
stopDestinationStream(current.destination.stream);
|
|
318
|
+
if (current.ownsContext && typeof current.ctx.close === "function") {
|
|
319
|
+
void current.ctx.close().catch(() => {});
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
} catch {
|
|
324
|
+
if (runtime) {
|
|
325
|
+
try {
|
|
326
|
+
clearInterval(runtime.intervalId);
|
|
327
|
+
} catch {
|
|
328
|
+
// ignore
|
|
329
|
+
}
|
|
330
|
+
disconnectNode(runtime.source);
|
|
331
|
+
disconnectNode(runtime.highPass);
|
|
332
|
+
for (const notch of runtime.notches) disconnectNode(notch);
|
|
333
|
+
disconnectNode(runtime.gain);
|
|
334
|
+
disconnectNode(runtime.analyser);
|
|
335
|
+
stopDestinationStream(runtime.destination.stream);
|
|
336
|
+
}
|
|
337
|
+
return createInactiveHandle(stream);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export function createMicAudioCleanup(
|
|
342
|
+
stream: MediaStream,
|
|
343
|
+
options: MicAudioCleanupOptions = {},
|
|
344
|
+
): MicAudioCleanupHandle {
|
|
345
|
+
try {
|
|
346
|
+
return tryBuildMicAudioCleanup(stream, options);
|
|
347
|
+
} catch {
|
|
348
|
+
return createInactiveHandle(stream);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
@@ -2915,7 +2915,7 @@ const editorSlashMessages = {
|
|
|
2915
2915
|
equationPreview: "Preview",
|
|
2916
2916
|
equationPreviewEmpty: "Your equation will appear here.",
|
|
2917
2917
|
equationSubmitHint:
|
|
2918
|
-
"Preview updates as you type. Press Cmd/Ctrl
|
|
2918
|
+
"Preview updates as you type. Press Cmd/Ctrl Enter to insert.",
|
|
2919
2919
|
quote: "Quote",
|
|
2920
2920
|
quoteDescription: "Block quote",
|
|
2921
2921
|
table: "Table",
|
|
@@ -11195,7 +11195,7 @@ const contentExactEnglishTranslations = {
|
|
|
11195
11195
|
equationPlaceholder: String.raw`输入 LaTeX,例如 \frac{a}{b}`,
|
|
11196
11196
|
equationPreview: "预览",
|
|
11197
11197
|
equationPreviewEmpty: "公式将在此处显示。",
|
|
11198
|
-
equationSubmitHint: "输入时会实时更新预览。按 Cmd/Ctrl
|
|
11198
|
+
equationSubmitHint: "输入时会实时更新预览。按 Cmd/Ctrl Enter 插入。",
|
|
11199
11199
|
},
|
|
11200
11200
|
toolbar: {
|
|
11201
11201
|
info: "信息",
|
|
@@ -11242,7 +11242,7 @@ const contentExactEnglishTranslations = {
|
|
|
11242
11242
|
equationPreview: "Vista previa",
|
|
11243
11243
|
equationPreviewEmpty: "Tu ecuación aparecerá aquí.",
|
|
11244
11244
|
equationSubmitHint:
|
|
11245
|
-
"La vista previa se actualiza mientras escribes. Pulsa Cmd/Ctrl
|
|
11245
|
+
"La vista previa se actualiza mientras escribes. Pulsa Cmd/Ctrl Enter para insertar.",
|
|
11246
11246
|
},
|
|
11247
11247
|
toolbar: {
|
|
11248
11248
|
info: "Información",
|
|
@@ -11291,7 +11291,7 @@ const contentExactEnglishTranslations = {
|
|
|
11291
11291
|
equationPreview: "Aperçu",
|
|
11292
11292
|
equationPreviewEmpty: "Votre équation apparaîtra ici.",
|
|
11293
11293
|
equationSubmitHint:
|
|
11294
|
-
"L’aperçu se met à jour pendant la saisie. Appuyez sur Cmd/Ctrl
|
|
11294
|
+
"L’aperçu se met à jour pendant la saisie. Appuyez sur Cmd/Ctrl Entrée pour insérer.",
|
|
11295
11295
|
},
|
|
11296
11296
|
toolbar: {
|
|
11297
11297
|
info: "Informations",
|
|
@@ -11341,7 +11341,7 @@ const contentExactEnglishTranslations = {
|
|
|
11341
11341
|
equationPreview: "Vorschau",
|
|
11342
11342
|
equationPreviewEmpty: "Ihre Gleichung wird hier angezeigt.",
|
|
11343
11343
|
equationSubmitHint:
|
|
11344
|
-
"Die Vorschau wird während der Eingabe aktualisiert. Mit Cmd/Ctrl
|
|
11344
|
+
"Die Vorschau wird während der Eingabe aktualisiert. Mit Cmd/Ctrl Enter einfügen.",
|
|
11345
11345
|
},
|
|
11346
11346
|
toolbar: {
|
|
11347
11347
|
info: "Informationen",
|
|
@@ -11390,7 +11390,7 @@ const contentExactEnglishTranslations = {
|
|
|
11390
11390
|
equationPreview: "プレビュー",
|
|
11391
11391
|
equationPreviewEmpty: "ここに数式が表示されます。",
|
|
11392
11392
|
equationSubmitHint:
|
|
11393
|
-
"入力中にプレビューが更新されます。Cmd/Ctrl
|
|
11393
|
+
"入力中にプレビューが更新されます。Cmd/Ctrl Enter で挿入します。",
|
|
11394
11394
|
},
|
|
11395
11395
|
toolbar: {
|
|
11396
11396
|
info: "情報",
|
|
@@ -11438,7 +11438,7 @@ const contentExactEnglishTranslations = {
|
|
|
11438
11438
|
equationPreview: "미리보기",
|
|
11439
11439
|
equationPreviewEmpty: "여기에 수식이 표시됩니다.",
|
|
11440
11440
|
equationSubmitHint:
|
|
11441
|
-
"입력하는 동안 미리보기가 업데이트됩니다. Cmd/Ctrl
|
|
11441
|
+
"입력하는 동안 미리보기가 업데이트됩니다. Cmd/Ctrl Enter로 삽입하세요.",
|
|
11442
11442
|
},
|
|
11443
11443
|
toolbar: {
|
|
11444
11444
|
info: "정보",
|
|
@@ -11487,7 +11487,7 @@ const contentExactEnglishTranslations = {
|
|
|
11487
11487
|
equationPreview: "Prévia",
|
|
11488
11488
|
equationPreviewEmpty: "Sua equação aparecerá aqui.",
|
|
11489
11489
|
equationSubmitHint:
|
|
11490
|
-
"A prévia é atualizada enquanto você digita. Pressione Cmd/Ctrl
|
|
11490
|
+
"A prévia é atualizada enquanto você digita. Pressione Cmd/Ctrl Enter para inserir.",
|
|
11491
11491
|
},
|
|
11492
11492
|
toolbar: {
|
|
11493
11493
|
info: "Informações",
|
|
@@ -11535,7 +11535,7 @@ const contentExactEnglishTranslations = {
|
|
|
11535
11535
|
equationPreview: "पूर्वावलोकन",
|
|
11536
11536
|
equationPreviewEmpty: "आपका समीकरण यहाँ दिखाई देगा।",
|
|
11537
11537
|
equationSubmitHint:
|
|
11538
|
-
"लिखते समय पूर्वावलोकन अपडेट होता है। सम्मिलित करने के लिए Cmd/Ctrl
|
|
11538
|
+
"लिखते समय पूर्वावलोकन अपडेट होता है। सम्मिलित करने के लिए Cmd/Ctrl Enter दबाएँ।",
|
|
11539
11539
|
},
|
|
11540
11540
|
toolbar: {
|
|
11541
11541
|
info: "जानकारी",
|
|
@@ -11581,7 +11581,7 @@ const contentExactEnglishTranslations = {
|
|
|
11581
11581
|
equationPreview: "معاينة",
|
|
11582
11582
|
equationPreviewEmpty: "ستظهر معادلتك هنا.",
|
|
11583
11583
|
equationSubmitHint:
|
|
11584
|
-
"تتحدث المعاينة أثناء الكتابة. اضغط Cmd/Ctrl
|
|
11584
|
+
"تتحدث المعاينة أثناء الكتابة. اضغط Cmd/Ctrl Enter للإدراج.",
|
|
11585
11585
|
},
|
|
11586
11586
|
toolbar: {
|
|
11587
11587
|
info: "معلومات",
|
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
import {
|
|
4
|
+
closeSync,
|
|
5
|
+
existsSync,
|
|
6
|
+
openSync,
|
|
7
|
+
readFileSync,
|
|
8
|
+
readdirSync,
|
|
9
|
+
statSync,
|
|
10
|
+
unlinkSync,
|
|
11
|
+
writeSync,
|
|
12
|
+
} from "node:fs";
|
|
3
13
|
import { createRequire } from "node:module";
|
|
4
14
|
import { dirname, join } from "node:path";
|
|
5
|
-
import { fileURLToPath
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
6
16
|
|
|
7
17
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
18
|
const require = createRequire(import.meta.url);
|
|
19
|
+
const REBUILD_LOCK = ".agent-native-better-sqlite3-rebuild.lock";
|
|
20
|
+
const LOCK_INITIALIZATION_TIMEOUT_MS = 5_000;
|
|
21
|
+
const REBUILD_WAIT_MS = 250;
|
|
22
|
+
const REBUILD_TIMEOUT_MS = 10 * 60 * 1000;
|
|
9
23
|
|
|
10
24
|
function resolveBetterSqlite3() {
|
|
11
25
|
try {
|
|
@@ -29,29 +43,181 @@ function resolveBetterSqlite3() {
|
|
|
29
43
|
}
|
|
30
44
|
}
|
|
31
45
|
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
46
|
+
function npmExecutable() {
|
|
47
|
+
const sibling = join(
|
|
48
|
+
dirname(process.execPath),
|
|
49
|
+
process.platform === "win32" ? "npm.cmd" : "npm",
|
|
35
50
|
);
|
|
51
|
+
return existsSync(sibling) ? sibling : "npm";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function sleepSync(milliseconds) {
|
|
55
|
+
const signal = new Int32Array(new SharedArrayBuffer(4));
|
|
56
|
+
Atomics.wait(signal, 0, 0, milliseconds);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function processIsRunning(pid) {
|
|
60
|
+
try {
|
|
61
|
+
process.kill(pid, 0);
|
|
62
|
+
return true;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
return error instanceof Error && "code" in error && error.code !== "ESRCH";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function acquireRebuildLock(packageDir) {
|
|
69
|
+
const lockPath = join(packageDir, REBUILD_LOCK);
|
|
70
|
+
const startedWaiting = Date.now();
|
|
71
|
+
|
|
72
|
+
while (true) {
|
|
73
|
+
try {
|
|
74
|
+
const lockFd = openSync(lockPath, "wx");
|
|
75
|
+
writeSync(
|
|
76
|
+
lockFd,
|
|
77
|
+
JSON.stringify({
|
|
78
|
+
pid: process.pid,
|
|
79
|
+
startedAt: new Date().toISOString(),
|
|
80
|
+
}),
|
|
81
|
+
);
|
|
82
|
+
return () => {
|
|
83
|
+
try {
|
|
84
|
+
closeSync(lockFd);
|
|
85
|
+
} finally {
|
|
86
|
+
try {
|
|
87
|
+
unlinkSync(lockPath);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
if (
|
|
90
|
+
!(
|
|
91
|
+
error instanceof Error &&
|
|
92
|
+
"code" in error &&
|
|
93
|
+
error.code === "ENOENT"
|
|
94
|
+
)
|
|
95
|
+
) {
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
} catch (error) {
|
|
102
|
+
if (
|
|
103
|
+
!(error instanceof Error && "code" in error && error.code === "EEXIST")
|
|
104
|
+
) {
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let ownerPid = null;
|
|
109
|
+
let lockAge = 0;
|
|
110
|
+
try {
|
|
111
|
+
const lock = JSON.parse(readFileSync(lockPath, "utf8"));
|
|
112
|
+
ownerPid = typeof lock.pid === "number" ? lock.pid : null;
|
|
113
|
+
} catch {
|
|
114
|
+
// The owner may be between creating and writing the lock metadata.
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
lockAge = Date.now() - statSync(lockPath).mtimeMs;
|
|
118
|
+
} catch {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (
|
|
123
|
+
(ownerPid !== null && !processIsRunning(ownerPid)) ||
|
|
124
|
+
(ownerPid === null && lockAge > LOCK_INITIALIZATION_TIMEOUT_MS)
|
|
125
|
+
) {
|
|
126
|
+
try {
|
|
127
|
+
unlinkSync(lockPath);
|
|
128
|
+
continue;
|
|
129
|
+
} catch (unlinkError) {
|
|
130
|
+
if (
|
|
131
|
+
!(
|
|
132
|
+
unlinkError instanceof Error &&
|
|
133
|
+
"code" in unlinkError &&
|
|
134
|
+
unlinkError.code === "ENOENT"
|
|
135
|
+
)
|
|
136
|
+
) {
|
|
137
|
+
throw unlinkError;
|
|
138
|
+
}
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (Date.now() - startedWaiting > REBUILD_TIMEOUT_MS) {
|
|
144
|
+
throw new Error(
|
|
145
|
+
"Timed out waiting for another process to rebuild better-sqlite3",
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
sleepSync(REBUILD_WAIT_MS);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function verifyBetterSqlite3(entry) {
|
|
154
|
+
const requireFromPackage = createRequire(entry);
|
|
155
|
+
const Database = requireFromPackage(entry);
|
|
36
156
|
const db = new Database(":memory:");
|
|
37
157
|
db.close();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
let packageEntry;
|
|
161
|
+
try {
|
|
162
|
+
packageEntry = resolveBetterSqlite3();
|
|
38
163
|
} catch (error) {
|
|
39
164
|
const message = error instanceof Error ? error.message : String(error);
|
|
40
165
|
console.error(`
|
|
41
166
|
[content dev preflight] better-sqlite3 could not load its native binding.
|
|
42
167
|
|
|
43
|
-
This usually means the local install was restored without rebuilding native
|
|
44
|
-
modules. Try:
|
|
45
|
-
|
|
46
|
-
pnpm rebuild better-sqlite3
|
|
47
|
-
|
|
48
|
-
If that still fails, rebuild the package directly:
|
|
49
|
-
|
|
50
|
-
cd ../../node_modules/.pnpm/better-sqlite3@*/node_modules/better-sqlite3
|
|
51
|
-
npm run build-release
|
|
52
|
-
|
|
53
168
|
Original error:
|
|
54
169
|
${message}
|
|
55
170
|
`);
|
|
56
171
|
process.exit(1);
|
|
57
172
|
}
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
verifyBetterSqlite3(packageEntry);
|
|
176
|
+
} catch (firstError) {
|
|
177
|
+
const packageDir = dirname(dirname(packageEntry));
|
|
178
|
+
const releaseLock = acquireRebuildLock(packageDir);
|
|
179
|
+
let repairError;
|
|
180
|
+
try {
|
|
181
|
+
let alreadyRepaired = false;
|
|
182
|
+
try {
|
|
183
|
+
verifyBetterSqlite3(packageEntry);
|
|
184
|
+
alreadyRepaired = true;
|
|
185
|
+
} catch {
|
|
186
|
+
// Another preflight may have repaired the package while we waited.
|
|
187
|
+
}
|
|
188
|
+
if (!alreadyRepaired) {
|
|
189
|
+
console.warn(
|
|
190
|
+
`[content dev preflight] Rebuilding ${packageDir} with Node ${process.version} (ABI ${process.versions.modules})...`,
|
|
191
|
+
);
|
|
192
|
+
execFileSync(
|
|
193
|
+
npmExecutable(),
|
|
194
|
+
["run", "build-release", "--prefix", packageDir],
|
|
195
|
+
{
|
|
196
|
+
cwd: packageDir,
|
|
197
|
+
stdio: "inherit",
|
|
198
|
+
},
|
|
199
|
+
);
|
|
200
|
+
verifyBetterSqlite3(packageEntry);
|
|
201
|
+
}
|
|
202
|
+
} catch (error) {
|
|
203
|
+
repairError = error;
|
|
204
|
+
} finally {
|
|
205
|
+
releaseLock();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (repairError) {
|
|
209
|
+
const original =
|
|
210
|
+
firstError instanceof Error ? firstError.message : String(firstError);
|
|
211
|
+
const repaired =
|
|
212
|
+
repairError instanceof Error ? repairError.message : String(repairError);
|
|
213
|
+
console.error(`
|
|
214
|
+
[content dev preflight] better-sqlite3 is still unusable after a direct rebuild.
|
|
215
|
+
|
|
216
|
+
Package: ${packageDir}
|
|
217
|
+
Node: ${process.version} (ABI ${process.versions.modules})
|
|
218
|
+
Original error: ${original}
|
|
219
|
+
Rebuild error: ${repaired}
|
|
220
|
+
`);
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
}
|