yaver-feedback-react-native 0.8.13 → 0.9.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/dist/FeedbackModal.js +318 -61
- package/dist/MachinePickerScreen.js +14 -5
- package/dist/P2PClient.d.ts +31 -1
- package/dist/P2PClient.js +59 -0
- package/dist/VibeChatScreen.d.ts +6 -1
- package/dist/VibeChatScreen.js +204 -1
- package/dist/capture.d.ts +6 -0
- package/dist/capture.js +53 -0
- package/dist/types.d.ts +57 -2
- package/dist/voice.d.ts +61 -0
- package/dist/voice.js +246 -0
- package/package.json +14 -3
- package/src/FeedbackModal.tsx +388 -74
- package/src/MachinePickerScreen.tsx +12 -3
- package/src/P2PClient.ts +79 -0
- package/src/VibeChatScreen.tsx +219 -0
- package/src/capture.ts +51 -0
- package/src/types.ts +53 -2
- package/src/voice.ts +270 -0
package/dist/FeedbackModal.js
CHANGED
|
@@ -45,6 +45,81 @@ const VibeChatScreen_1 = require("./VibeChatScreen");
|
|
|
45
45
|
const DeployPanel_1 = require("./DeployPanel");
|
|
46
46
|
const auth_1 = require("./auth");
|
|
47
47
|
const preferences_1 = require("./preferences");
|
|
48
|
+
const PRIMARY_RUNNER_IDS = ['claude', 'codex', 'opencode'];
|
|
49
|
+
function normalizeRunnerStatusRows(rows) {
|
|
50
|
+
const byId = new Map();
|
|
51
|
+
for (const row of rows) {
|
|
52
|
+
const raw = String(row.id || '').trim().toLowerCase();
|
|
53
|
+
if (!raw)
|
|
54
|
+
continue;
|
|
55
|
+
const normalized = raw === 'claude-code' ? 'claude' : raw;
|
|
56
|
+
if (!PRIMARY_RUNNER_IDS.includes(normalized))
|
|
57
|
+
continue;
|
|
58
|
+
byId.set(normalized, { ...row, id: normalized });
|
|
59
|
+
}
|
|
60
|
+
return PRIMARY_RUNNER_IDS.map((id) => {
|
|
61
|
+
const baseName = id === 'claude' ? 'Claude Code' : id === 'codex' ? 'OpenAI Codex' : 'OpenCode';
|
|
62
|
+
const row = byId.get(id);
|
|
63
|
+
if (!row) {
|
|
64
|
+
return {
|
|
65
|
+
id,
|
|
66
|
+
name: baseName,
|
|
67
|
+
installed: false,
|
|
68
|
+
authConfigured: false,
|
|
69
|
+
ready: false,
|
|
70
|
+
tone: 'warning',
|
|
71
|
+
statusLine: 'Not installed on the selected machine',
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const versionPrefix = row.version?.trim() ? `${row.version.trim()} · ` : '';
|
|
75
|
+
const detail = row.error?.trim() || row.warning?.trim() || row.detail?.trim() || undefined;
|
|
76
|
+
if (!row.installed) {
|
|
77
|
+
return {
|
|
78
|
+
id,
|
|
79
|
+
name: row.name || baseName,
|
|
80
|
+
installed: false,
|
|
81
|
+
authConfigured: false,
|
|
82
|
+
ready: false,
|
|
83
|
+
version: row.version,
|
|
84
|
+
tone: 'warning',
|
|
85
|
+
statusLine: 'Not installed on the selected machine',
|
|
86
|
+
detail,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (id === 'opencode') {
|
|
90
|
+
const configured = row.authConfigured || row.ready;
|
|
91
|
+
return {
|
|
92
|
+
id,
|
|
93
|
+
name: row.name || baseName,
|
|
94
|
+
installed: row.installed,
|
|
95
|
+
authConfigured: row.authConfigured,
|
|
96
|
+
ready: row.ready,
|
|
97
|
+
version: row.version,
|
|
98
|
+
tone: configured ? 'ok' : 'warning',
|
|
99
|
+
statusLine: configured
|
|
100
|
+
? `${versionPrefix}Configured on the selected machine`
|
|
101
|
+
: `${versionPrefix}Needs provider config on the selected machine`,
|
|
102
|
+
detail,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const authed = row.authConfigured || row.ready;
|
|
106
|
+
return {
|
|
107
|
+
id,
|
|
108
|
+
name: row.name || baseName,
|
|
109
|
+
installed: row.installed,
|
|
110
|
+
authConfigured: row.authConfigured,
|
|
111
|
+
ready: row.ready,
|
|
112
|
+
version: row.version,
|
|
113
|
+
tone: authed ? 'ok' : 'warning',
|
|
114
|
+
statusLine: authed
|
|
115
|
+
? `${versionPrefix}Signed in on the selected machine`
|
|
116
|
+
: `${versionPrefix}Not signed in on the selected machine`,
|
|
117
|
+
detail,
|
|
118
|
+
actionLabel: authed ? 'Re-auth' : 'Sign in',
|
|
119
|
+
actionRunner: id,
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
}
|
|
48
123
|
const FeedbackModal = () => {
|
|
49
124
|
const { width: winW, height: winH } = (0, react_native_1.useWindowDimensions)();
|
|
50
125
|
const isTablet = Math.min(winW, winH) >= 600;
|
|
@@ -81,6 +156,12 @@ const FeedbackModal = () => {
|
|
|
81
156
|
title: 'No machine selected',
|
|
82
157
|
detail: 'Pick a remote dev machine before using the feedback actions.',
|
|
83
158
|
});
|
|
159
|
+
const [runnerCards, setRunnerCards] = (0, react_1.useState)(() => normalizeRunnerStatusRows([]));
|
|
160
|
+
const [runnerStatusLoading, setRunnerStatusLoading] = (0, react_1.useState)(false);
|
|
161
|
+
const [runnerStatusError, setRunnerStatusError] = (0, react_1.useState)(null);
|
|
162
|
+
const [preferredRunner, setPreferredRunnerState] = (0, react_1.useState)(null);
|
|
163
|
+
const [preferredModel, setPreferredModelState] = (0, react_1.useState)('');
|
|
164
|
+
const [showOpenCodeConfig, setShowOpenCodeConfig] = (0, react_1.useState)(false);
|
|
84
165
|
const mountedRef = (0, react_1.useRef)(true);
|
|
85
166
|
const loadSelectedMachine = (0, react_1.useCallback)(async () => {
|
|
86
167
|
const cfg = YaverFeedback_1.YaverFeedback.getConfig();
|
|
@@ -178,6 +259,72 @@ const FeedbackModal = () => {
|
|
|
178
259
|
}
|
|
179
260
|
}
|
|
180
261
|
}, []);
|
|
262
|
+
const loadRunnerStatuses = (0, react_1.useCallback)(async () => {
|
|
263
|
+
const cfg = YaverFeedback_1.YaverFeedback.getConfig();
|
|
264
|
+
if (!cfg?.authToken) {
|
|
265
|
+
if (mountedRef.current) {
|
|
266
|
+
setRunnerCards(normalizeRunnerStatusRows([]));
|
|
267
|
+
setRunnerStatusError('Sign in to inspect coding-agent status.');
|
|
268
|
+
setRunnerStatusLoading(false);
|
|
269
|
+
}
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (!cfg.preferredDeviceId) {
|
|
273
|
+
if (mountedRef.current) {
|
|
274
|
+
setRunnerCards(normalizeRunnerStatusRows([]));
|
|
275
|
+
setRunnerStatusError('Pick a machine to inspect coding-agent status.');
|
|
276
|
+
setRunnerStatusLoading(false);
|
|
277
|
+
}
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
if (mountedRef.current) {
|
|
281
|
+
setRunnerStatusLoading(true);
|
|
282
|
+
setRunnerStatusError(null);
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
let client = YaverFeedback_1.YaverFeedback.getP2PClient();
|
|
286
|
+
if (!client) {
|
|
287
|
+
const ok = await YaverFeedback_1.YaverFeedback.reconnect();
|
|
288
|
+
if (ok)
|
|
289
|
+
client = YaverFeedback_1.YaverFeedback.getP2PClient();
|
|
290
|
+
}
|
|
291
|
+
if (!client) {
|
|
292
|
+
throw new Error('Not connected to the selected machine yet.');
|
|
293
|
+
}
|
|
294
|
+
const rows = await client.getRunnerAuthStatus();
|
|
295
|
+
if (mountedRef.current) {
|
|
296
|
+
setRunnerCards(normalizeRunnerStatusRows(rows));
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
if (mountedRef.current) {
|
|
301
|
+
setRunnerCards(normalizeRunnerStatusRows([]));
|
|
302
|
+
setRunnerStatusError(err instanceof Error ? err.message : String(err));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
finally {
|
|
306
|
+
if (mountedRef.current)
|
|
307
|
+
setRunnerStatusLoading(false);
|
|
308
|
+
}
|
|
309
|
+
}, []);
|
|
310
|
+
const loadRoutingPrefs = (0, react_1.useCallback)(async () => {
|
|
311
|
+
try {
|
|
312
|
+
const [runner, model] = await Promise.all([
|
|
313
|
+
(0, preferences_1.getPreferredRunner)(),
|
|
314
|
+
(0, preferences_1.getPreferredModel)(),
|
|
315
|
+
]);
|
|
316
|
+
if (!mountedRef.current)
|
|
317
|
+
return;
|
|
318
|
+
setPreferredRunnerState(runner);
|
|
319
|
+
setPreferredModelState(model ?? '');
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
if (!mountedRef.current)
|
|
323
|
+
return;
|
|
324
|
+
setPreferredRunnerState(null);
|
|
325
|
+
setPreferredModelState('');
|
|
326
|
+
}
|
|
327
|
+
}, []);
|
|
181
328
|
(0, react_1.useEffect)(() => {
|
|
182
329
|
mountedRef.current = true;
|
|
183
330
|
const sub = react_native_1.DeviceEventEmitter.addListener('yaverFeedback:startReport', () => {
|
|
@@ -205,6 +352,7 @@ const FeedbackModal = () => {
|
|
|
205
352
|
})
|
|
206
353
|
.catch(() => { });
|
|
207
354
|
void loadSelectedMachine();
|
|
355
|
+
void loadRunnerStatuses();
|
|
208
356
|
}
|
|
209
357
|
});
|
|
210
358
|
// Agent streams build / compile progress through the BlackBox
|
|
@@ -232,15 +380,16 @@ const FeedbackModal = () => {
|
|
|
232
380
|
sub.remove();
|
|
233
381
|
statusSub.remove();
|
|
234
382
|
};
|
|
235
|
-
}, [loadSelectedMachine]);
|
|
383
|
+
}, [loadRunnerStatuses, loadSelectedMachine]);
|
|
236
384
|
(0, react_1.useEffect)(() => {
|
|
237
385
|
if (!visible)
|
|
238
386
|
return;
|
|
239
387
|
const interval = setInterval(() => {
|
|
240
388
|
void loadSelectedMachine();
|
|
389
|
+
void loadRunnerStatuses();
|
|
241
390
|
}, 5000);
|
|
242
391
|
return () => clearInterval(interval);
|
|
243
|
-
}, [loadSelectedMachine, visible]);
|
|
392
|
+
}, [loadRunnerStatuses, loadSelectedMachine, visible]);
|
|
244
393
|
(0, react_1.useEffect)(() => {
|
|
245
394
|
if (!visible) {
|
|
246
395
|
setKeyboardInset(0);
|
|
@@ -273,6 +422,7 @@ const FeedbackModal = () => {
|
|
|
273
422
|
setAction('idle');
|
|
274
423
|
setShowVibeInput(false);
|
|
275
424
|
setVibePrompt('');
|
|
425
|
+
setRunnerStatusError(null);
|
|
276
426
|
}, []);
|
|
277
427
|
// Helper: run a P2P call; on network failure, ask YaverFeedback to
|
|
278
428
|
// re-query Convex for the fresh IP and retry once. Solves the common
|
|
@@ -557,7 +707,13 @@ const FeedbackModal = () => {
|
|
|
557
707
|
setLastVibeTaskId(result.taskId);
|
|
558
708
|
// Hand off to VibeChatScreen — it streams the SSE transcript,
|
|
559
709
|
// accepts follow-ups, and surfaces a Reload button.
|
|
560
|
-
setActiveVibe({
|
|
710
|
+
setActiveVibe({
|
|
711
|
+
taskId: result.taskId,
|
|
712
|
+
initialPrompt: promptText,
|
|
713
|
+
project: identity.projectName,
|
|
714
|
+
runner: preferredRunner ?? undefined,
|
|
715
|
+
model: preferredModel ?? undefined,
|
|
716
|
+
});
|
|
561
717
|
setVibePrompt('');
|
|
562
718
|
setShowVibeInput(false);
|
|
563
719
|
}
|
|
@@ -575,6 +731,9 @@ const FeedbackModal = () => {
|
|
|
575
731
|
}, [closeSoon, isRecordingVideo, lastVideo]);
|
|
576
732
|
*/
|
|
577
733
|
const busy = action !== 'idle';
|
|
734
|
+
const readyRunnerCount = runnerCards.filter((row) => row.ready || row.authConfigured).length;
|
|
735
|
+
const missingRunnerCount = runnerCards.filter((row) => !row.installed).length;
|
|
736
|
+
const needsAuthRunnerCount = runnerCards.filter((row) => row.installed && !row.authConfigured && !row.ready).length;
|
|
578
737
|
// Once the user fires off a vibe task, swap the entire modal body
|
|
579
738
|
// for the live chat screen. The chat manages its own SSE
|
|
580
739
|
// subscription, multi-turn follow-ups, and Reload button. Closing
|
|
@@ -585,7 +744,7 @@ const FeedbackModal = () => {
|
|
|
585
744
|
<AuthOverlay_1.AuthOverlay />
|
|
586
745
|
<QuickActionIcon_1.QuickActionIcon />
|
|
587
746
|
<react_native_1.Modal visible={visible} animationType="slide" transparent onRequestClose={() => setActiveVibe(null)}>
|
|
588
|
-
{client ? (<VibeChatScreen_1.VibeChatScreen client={client} initialTaskId={activeVibe.taskId} initialUserPrompt={activeVibe.initialPrompt} onClose={() => setActiveVibe(null)} onReload={async () => {
|
|
747
|
+
{client ? (<VibeChatScreen_1.VibeChatScreen client={client} initialTaskId={activeVibe.taskId} initialUserPrompt={activeVibe.initialPrompt} project={activeVibe.project} runner={activeVibe.runner} model={activeVibe.model} onClose={() => setActiveVibe(null)} onReload={async () => {
|
|
589
748
|
const c = YaverFeedback_1.YaverFeedback.getP2PClient();
|
|
590
749
|
if (!c)
|
|
591
750
|
throw new Error('Not connected');
|
|
@@ -664,6 +823,57 @@ const FeedbackModal = () => {
|
|
|
664
823
|
<react_native_1.Text style={styles.machineMeta}>{machineCard.detail}</react_native_1.Text>
|
|
665
824
|
</react_native_1.Pressable>
|
|
666
825
|
|
|
826
|
+
<react_native_1.View style={styles.runnerSection}>
|
|
827
|
+
<react_native_1.View style={styles.runnerSectionHeader}>
|
|
828
|
+
<react_native_1.View style={{ flex: 1 }}>
|
|
829
|
+
<react_native_1.Text style={styles.runnerSectionTitle}>Coding Agents</react_native_1.Text>
|
|
830
|
+
<react_native_1.Text style={styles.runnerSectionSubtitle}>
|
|
831
|
+
{runnerStatusLoading
|
|
832
|
+
? 'Refreshing runner status on the selected machine…'
|
|
833
|
+
: `${readyRunnerCount} ready · ${needsAuthRunnerCount} need sign-in · ${missingRunnerCount} missing`}
|
|
834
|
+
</react_native_1.Text>
|
|
835
|
+
</react_native_1.View>
|
|
836
|
+
<react_native_1.Pressable onPress={() => void loadRunnerStatuses()} style={({ pressed }) => [
|
|
837
|
+
styles.runnerRefreshBtn,
|
|
838
|
+
pressed && styles.buttonPressed,
|
|
839
|
+
]} accessibilityRole="button" accessibilityLabel="Refresh coding-agent status">
|
|
840
|
+
<react_native_1.Text style={styles.runnerRefreshBtnText}>
|
|
841
|
+
{runnerStatusLoading ? 'Refreshing…' : 'Refresh'}
|
|
842
|
+
</react_native_1.Text>
|
|
843
|
+
</react_native_1.Pressable>
|
|
844
|
+
</react_native_1.View>
|
|
845
|
+
|
|
846
|
+
{runnerCards.map((row) => (<react_native_1.View key={row.id} style={[
|
|
847
|
+
styles.runnerCard,
|
|
848
|
+
row.tone === 'ok' && styles.runnerCardOk,
|
|
849
|
+
row.tone === 'warning' && styles.runnerCardWarning,
|
|
850
|
+
row.tone === 'error' && styles.runnerCardError,
|
|
851
|
+
]}>
|
|
852
|
+
<react_native_1.View style={styles.runnerCardTop}>
|
|
853
|
+
<react_native_1.View style={{ flex: 1 }}>
|
|
854
|
+
<react_native_1.Text style={styles.runnerCardTitle}>{row.name}</react_native_1.Text>
|
|
855
|
+
<react_native_1.Text style={[
|
|
856
|
+
styles.runnerCardStatus,
|
|
857
|
+
row.tone === 'ok' && styles.runnerCardStatusOk,
|
|
858
|
+
row.tone === 'warning' && styles.runnerCardStatusWarning,
|
|
859
|
+
row.tone === 'error' && styles.runnerCardStatusError,
|
|
860
|
+
]}>
|
|
861
|
+
{row.statusLine}
|
|
862
|
+
</react_native_1.Text>
|
|
863
|
+
</react_native_1.View>
|
|
864
|
+
{row.actionRunner ? (<react_native_1.Pressable onPress={() => setRunnerAuthModal(row.actionRunner ?? null)} style={({ pressed }) => [
|
|
865
|
+
styles.runnerActionBtn,
|
|
866
|
+
pressed && styles.buttonPressed,
|
|
867
|
+
]} accessibilityRole="button" accessibilityLabel={`${row.actionLabel} ${row.name}`}>
|
|
868
|
+
<react_native_1.Text style={styles.runnerActionBtnText}>{row.actionLabel}</react_native_1.Text>
|
|
869
|
+
</react_native_1.Pressable>) : null}
|
|
870
|
+
</react_native_1.View>
|
|
871
|
+
{row.detail ? (<react_native_1.Text style={styles.runnerCardDetail}>{row.detail}</react_native_1.Text>) : null}
|
|
872
|
+
</react_native_1.View>))}
|
|
873
|
+
|
|
874
|
+
{runnerStatusError ? (<react_native_1.Text style={styles.runnerSectionError}>{runnerStatusError}</react_native_1.Text>) : null}
|
|
875
|
+
</react_native_1.View>
|
|
876
|
+
|
|
667
877
|
{quickIconHidden && (<react_native_1.View style={styles.quickIconNote}>
|
|
668
878
|
<react_native_1.Text style={styles.quickIconNoteText}>
|
|
669
879
|
Quick access icon is hidden. Shake the phone if you want feedback back fast.
|
|
@@ -755,29 +965,6 @@ const FeedbackModal = () => {
|
|
|
755
965
|
platform smarts here. */}
|
|
756
966
|
{!showDeploy ? (<ActionRow label="Deploy" tint="#7f8cf7" onPress={() => setShowDeploy(true)} disabled={busy}/>) : (<DeployPanel_1.DeployPanel onClose={() => setShowDeploy(false)}/>)}
|
|
757
967
|
|
|
758
|
-
{/* Remote sign-in buttons — trigger codex/claude device-auth
|
|
759
|
-
on the selected agent without leaving the app. Opens a
|
|
760
|
-
small native modal showing the verification URL + 8-char
|
|
761
|
-
code the user enters in any browser. No API keys. */}
|
|
762
|
-
<react_native_1.View style={runnerAuthRowStyles.container}>
|
|
763
|
-
<react_native_1.Pressable onPress={() => setRunnerAuthModal('codex')} disabled={busy} style={({ pressed }) => [
|
|
764
|
-
runnerAuthRowStyles.button,
|
|
765
|
-
pressed && runnerAuthRowStyles.buttonPressed,
|
|
766
|
-
busy && runnerAuthRowStyles.buttonDisabled,
|
|
767
|
-
]} accessibilityRole="button" accessibilityLabel="Remote sign-in Codex">
|
|
768
|
-
<react_native_1.Text style={runnerAuthRowStyles.buttonLabel}>Remote sign-in</react_native_1.Text>
|
|
769
|
-
<react_native_1.Text style={runnerAuthRowStyles.buttonName}>Codex</react_native_1.Text>
|
|
770
|
-
</react_native_1.Pressable>
|
|
771
|
-
<react_native_1.Pressable onPress={() => setRunnerAuthModal('claude')} disabled={busy} style={({ pressed }) => [
|
|
772
|
-
runnerAuthRowStyles.button,
|
|
773
|
-
pressed && runnerAuthRowStyles.buttonPressed,
|
|
774
|
-
busy && runnerAuthRowStyles.buttonDisabled,
|
|
775
|
-
]} accessibilityRole="button" accessibilityLabel="Remote sign-in Claude">
|
|
776
|
-
<react_native_1.Text style={runnerAuthRowStyles.buttonLabel}>Remote sign-in</react_native_1.Text>
|
|
777
|
-
<react_native_1.Text style={runnerAuthRowStyles.buttonName}>Claude</react_native_1.Text>
|
|
778
|
-
</react_native_1.Pressable>
|
|
779
|
-
</react_native_1.View>
|
|
780
|
-
|
|
781
968
|
{progress !== null && (<react_native_1.View style={styles.progressTrack}>
|
|
782
969
|
<react_native_1.View style={[
|
|
783
970
|
styles.progressFill,
|
|
@@ -798,7 +985,10 @@ const FeedbackModal = () => {
|
|
|
798
985
|
</react_native_1.KeyboardAvoidingView>
|
|
799
986
|
</react_native_1.Pressable>
|
|
800
987
|
</react_native_1.Modal>)}
|
|
801
|
-
{runnerAuthModal ? (<RunnerAuthNativeModal runner={runnerAuthModal} onClose={() =>
|
|
988
|
+
{runnerAuthModal ? (<RunnerAuthNativeModal runner={runnerAuthModal} onClose={() => {
|
|
989
|
+
setRunnerAuthModal(null);
|
|
990
|
+
void loadRunnerStatuses();
|
|
991
|
+
}}/>) : null}
|
|
802
992
|
</>);
|
|
803
993
|
};
|
|
804
994
|
exports.FeedbackModal = FeedbackModal;
|
|
@@ -996,6 +1186,106 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
996
1186
|
marginTop: 4,
|
|
997
1187
|
lineHeight: 17,
|
|
998
1188
|
},
|
|
1189
|
+
runnerSection: {
|
|
1190
|
+
marginTop: 2,
|
|
1191
|
+
gap: 10,
|
|
1192
|
+
},
|
|
1193
|
+
runnerSectionHeader: {
|
|
1194
|
+
flexDirection: 'row',
|
|
1195
|
+
alignItems: 'center',
|
|
1196
|
+
gap: 10,
|
|
1197
|
+
},
|
|
1198
|
+
runnerSectionTitle: {
|
|
1199
|
+
color: '#f8fafc',
|
|
1200
|
+
fontSize: 16,
|
|
1201
|
+
fontWeight: '700',
|
|
1202
|
+
},
|
|
1203
|
+
runnerSectionSubtitle: {
|
|
1204
|
+
marginTop: 2,
|
|
1205
|
+
color: '#94a3b8',
|
|
1206
|
+
fontSize: 12,
|
|
1207
|
+
},
|
|
1208
|
+
runnerRefreshBtn: {
|
|
1209
|
+
borderRadius: 10,
|
|
1210
|
+
borderWidth: 1,
|
|
1211
|
+
borderColor: 'rgba(148,163,184,0.22)',
|
|
1212
|
+
backgroundColor: 'rgba(15,23,42,0.65)',
|
|
1213
|
+
paddingHorizontal: 10,
|
|
1214
|
+
paddingVertical: 8,
|
|
1215
|
+
},
|
|
1216
|
+
runnerRefreshBtnText: {
|
|
1217
|
+
color: '#cbd5e1',
|
|
1218
|
+
fontSize: 12,
|
|
1219
|
+
fontWeight: '600',
|
|
1220
|
+
},
|
|
1221
|
+
runnerCard: {
|
|
1222
|
+
borderRadius: 12,
|
|
1223
|
+
borderWidth: 1,
|
|
1224
|
+
borderColor: 'rgba(148,163,184,0.14)',
|
|
1225
|
+
backgroundColor: 'rgba(15,23,42,0.45)',
|
|
1226
|
+
paddingHorizontal: 12,
|
|
1227
|
+
paddingVertical: 11,
|
|
1228
|
+
gap: 6,
|
|
1229
|
+
},
|
|
1230
|
+
runnerCardOk: {
|
|
1231
|
+
borderColor: 'rgba(34,197,94,0.28)',
|
|
1232
|
+
backgroundColor: 'rgba(20,83,45,0.20)',
|
|
1233
|
+
},
|
|
1234
|
+
runnerCardWarning: {
|
|
1235
|
+
borderColor: 'rgba(251,191,36,0.28)',
|
|
1236
|
+
backgroundColor: 'rgba(120,53,15,0.18)',
|
|
1237
|
+
},
|
|
1238
|
+
runnerCardError: {
|
|
1239
|
+
borderColor: 'rgba(248,113,113,0.28)',
|
|
1240
|
+
backgroundColor: 'rgba(127,29,29,0.18)',
|
|
1241
|
+
},
|
|
1242
|
+
runnerCardTop: {
|
|
1243
|
+
flexDirection: 'row',
|
|
1244
|
+
alignItems: 'center',
|
|
1245
|
+
gap: 10,
|
|
1246
|
+
},
|
|
1247
|
+
runnerCardTitle: {
|
|
1248
|
+
color: '#f8fafc',
|
|
1249
|
+
fontSize: 14,
|
|
1250
|
+
fontWeight: '700',
|
|
1251
|
+
},
|
|
1252
|
+
runnerCardStatus: {
|
|
1253
|
+
marginTop: 2,
|
|
1254
|
+
fontSize: 12,
|
|
1255
|
+
color: '#cbd5e1',
|
|
1256
|
+
},
|
|
1257
|
+
runnerCardStatusOk: {
|
|
1258
|
+
color: '#86efac',
|
|
1259
|
+
},
|
|
1260
|
+
runnerCardStatusWarning: {
|
|
1261
|
+
color: '#fcd34d',
|
|
1262
|
+
},
|
|
1263
|
+
runnerCardStatusError: {
|
|
1264
|
+
color: '#fca5a5',
|
|
1265
|
+
},
|
|
1266
|
+
runnerCardDetail: {
|
|
1267
|
+
color: '#94a3b8',
|
|
1268
|
+
fontSize: 11,
|
|
1269
|
+
lineHeight: 16,
|
|
1270
|
+
},
|
|
1271
|
+
runnerActionBtn: {
|
|
1272
|
+
borderRadius: 10,
|
|
1273
|
+
borderWidth: 1,
|
|
1274
|
+
borderColor: 'rgba(129,140,248,0.35)',
|
|
1275
|
+
backgroundColor: 'rgba(67,56,202,0.22)',
|
|
1276
|
+
paddingHorizontal: 12,
|
|
1277
|
+
paddingVertical: 8,
|
|
1278
|
+
},
|
|
1279
|
+
runnerActionBtnText: {
|
|
1280
|
+
color: '#c7d2fe',
|
|
1281
|
+
fontSize: 12,
|
|
1282
|
+
fontWeight: '700',
|
|
1283
|
+
},
|
|
1284
|
+
runnerSectionError: {
|
|
1285
|
+
color: '#fca5a5',
|
|
1286
|
+
fontSize: 12,
|
|
1287
|
+
lineHeight: 18,
|
|
1288
|
+
},
|
|
999
1289
|
captureChoices: {
|
|
1000
1290
|
gap: 10,
|
|
1001
1291
|
},
|
|
@@ -1328,39 +1618,6 @@ const RunnerAuthNativeModal = ({ runner, onClose }) => {
|
|
|
1328
1618
|
</react_native_1.View>
|
|
1329
1619
|
</react_native_1.Modal>);
|
|
1330
1620
|
};
|
|
1331
|
-
const runnerAuthRowStyles = react_native_1.StyleSheet.create({
|
|
1332
|
-
container: {
|
|
1333
|
-
flexDirection: 'row',
|
|
1334
|
-
gap: 8,
|
|
1335
|
-
marginTop: 8,
|
|
1336
|
-
flexWrap: 'wrap',
|
|
1337
|
-
},
|
|
1338
|
-
button: {
|
|
1339
|
-
flexGrow: 1,
|
|
1340
|
-
flexBasis: 0,
|
|
1341
|
-
minWidth: 120,
|
|
1342
|
-
paddingHorizontal: 12,
|
|
1343
|
-
paddingVertical: 10,
|
|
1344
|
-
borderRadius: 10,
|
|
1345
|
-
borderWidth: 1,
|
|
1346
|
-
borderColor: 'rgba(148,163,184,0.22)',
|
|
1347
|
-
backgroundColor: 'rgba(15,23,42,0.6)',
|
|
1348
|
-
},
|
|
1349
|
-
buttonPressed: { opacity: 0.7 },
|
|
1350
|
-
buttonDisabled: { opacity: 0.4 },
|
|
1351
|
-
buttonLabel: {
|
|
1352
|
-
fontSize: 10,
|
|
1353
|
-
color: '#94a3b8',
|
|
1354
|
-
textTransform: 'uppercase',
|
|
1355
|
-
letterSpacing: 0.8,
|
|
1356
|
-
},
|
|
1357
|
-
buttonName: {
|
|
1358
|
-
marginTop: 2,
|
|
1359
|
-
fontSize: 14,
|
|
1360
|
-
fontWeight: '600',
|
|
1361
|
-
color: '#f1f5f9',
|
|
1362
|
-
},
|
|
1363
|
-
});
|
|
1364
1621
|
const runnerAuthModalStyles = react_native_1.StyleSheet.create({
|
|
1365
1622
|
overlay: {
|
|
1366
1623
|
flex: 1,
|
|
@@ -104,7 +104,14 @@ const YaverMachinePickerScreen = ({ token, currentDeviceId, onPick, onCancel, })
|
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
106
|
const direct = await (0, auth_1.probeDeviceReachability)(device);
|
|
107
|
-
|
|
107
|
+
// Do not hard-block selection just because the LAN /health probe
|
|
108
|
+
// failed. The standalone SDK can still reach a healthy machine via
|
|
109
|
+
// the normal selected-device discovery path (including relay), and
|
|
110
|
+
// the Yaver host path may already be proving the machine works.
|
|
111
|
+
// Only treat the machine as unpickable when BOTH:
|
|
112
|
+
// 1. Convex says it is offline, and
|
|
113
|
+
// 2. the direct probe also failed.
|
|
114
|
+
if (!device.isOnline && !direct.reachable && !device.needsAuth) {
|
|
108
115
|
setError('Selected machine is not responding. Start `yaver serve` on it and try again.');
|
|
109
116
|
setReachability((prev) => ({ ...prev, [device.deviceId]: direct }));
|
|
110
117
|
return;
|
|
@@ -131,9 +138,11 @@ const YaverMachinePickerScreen = ({ token, currentDeviceId, onPick, onCancel, })
|
|
|
131
138
|
? '#f59e0b'
|
|
132
139
|
: effectivelyReachable
|
|
133
140
|
? '#22c55e'
|
|
134
|
-
:
|
|
135
|
-
? '#
|
|
136
|
-
:
|
|
141
|
+
: device.isOnline
|
|
142
|
+
? '#f59e0b'
|
|
143
|
+
: explicitlyOffline || !device.isOnline
|
|
144
|
+
? '#ef4444'
|
|
145
|
+
: '#22c55e';
|
|
137
146
|
// Derive a single short status phrase the user can act on.
|
|
138
147
|
let statusLine = device.platform;
|
|
139
148
|
if (probe === undefined) {
|
|
@@ -150,7 +159,7 @@ const YaverMachinePickerScreen = ({ token, currentDeviceId, onPick, onCancel, })
|
|
|
150
159
|
'Needs pairing — open the Yaver app to adopt this machine';
|
|
151
160
|
}
|
|
152
161
|
else if (explicitlyOffline) {
|
|
153
|
-
statusLine = '
|
|
162
|
+
statusLine = 'Online, but direct probe failed — relay / selected-machine path may still work';
|
|
154
163
|
}
|
|
155
164
|
else if (device.runnerDown) {
|
|
156
165
|
statusLine = 'Runner down — restart the coding agent on the Mac';
|
package/dist/P2PClient.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CapabilitySnapshot, FeedbackBundle, IncidentEvent, OperationState, RunnerBrowserAuthSession, TestSession, VoiceCapability } from './types';
|
|
1
|
+
import { CapabilitySnapshot, FeedbackBundle, IncidentEvent, OpenCodeConfigSummary, OperationState, RunnerBrowserAuthSession, RunnerAuthStatusRow, TestSession, VoiceCapability } from './types';
|
|
2
2
|
export interface FeedbackEvent {
|
|
3
3
|
type: string;
|
|
4
4
|
timestamp: string;
|
|
@@ -51,6 +51,16 @@ export declare class P2PClient {
|
|
|
51
51
|
setAuthToken(token: string): void;
|
|
52
52
|
/** Update the relay password (used for managed-relay baseUrls). */
|
|
53
53
|
setRelayPassword(password: string): void;
|
|
54
|
+
/** Read-only base URL — used by the voice vibe-coding path to probe
|
|
55
|
+
* GET /voice/status before opening the stream. */
|
|
56
|
+
get agentBaseUrl(): string;
|
|
57
|
+
/** WebSocket URL for the agent's voice stream (WS /voice/stream). The
|
|
58
|
+
* voice vibe-coding loop streams mic audio here and receives the
|
|
59
|
+
* transcript + agent task + TTS frames back. */
|
|
60
|
+
voiceStreamUrl(): string;
|
|
61
|
+
/** Auth headers for the voice WS + status probe — same bearer (and
|
|
62
|
+
* relay password) as every other agent request. */
|
|
63
|
+
voiceAuthHeaders(): Record<string, string>;
|
|
54
64
|
/** Merge in Authorization + (optional) X-Relay-Password on top of a header block. */
|
|
55
65
|
private authHeaders;
|
|
56
66
|
/**
|
|
@@ -69,6 +79,26 @@ export declare class P2PClient {
|
|
|
69
79
|
* the SDK still exposes it for symmetry with mobile/src/components/
|
|
70
80
|
* RunnerAuthModal.tsx and the Swift YaverRunnerAuthFlowPane. */
|
|
71
81
|
submitRunnerBrowserAuthCode(sessionId: string, code: string): Promise<RunnerBrowserAuthSession>;
|
|
82
|
+
getRunnerAuthStatus(): Promise<RunnerAuthStatusRow[]>;
|
|
83
|
+
getOpenCodeConfig(): Promise<OpenCodeConfigSummary | null>;
|
|
84
|
+
saveOpenCodeConfig(patch: {
|
|
85
|
+
defaultAgent?: string;
|
|
86
|
+
model?: string;
|
|
87
|
+
smallModel?: string;
|
|
88
|
+
buildModel?: string;
|
|
89
|
+
planModel?: string;
|
|
90
|
+
providers?: Array<{
|
|
91
|
+
id: string;
|
|
92
|
+
name?: string;
|
|
93
|
+
baseUrl?: string;
|
|
94
|
+
apiKey?: string;
|
|
95
|
+
delete?: boolean;
|
|
96
|
+
}>;
|
|
97
|
+
}): Promise<{
|
|
98
|
+
ok: boolean;
|
|
99
|
+
config?: OpenCodeConfigSummary;
|
|
100
|
+
error?: string;
|
|
101
|
+
}>;
|
|
72
102
|
capabilitySnapshot(): Promise<CapabilitySnapshot | null>;
|
|
73
103
|
incidents(opts?: {
|
|
74
104
|
category?: string;
|
package/dist/P2PClient.js
CHANGED
|
@@ -143,6 +143,22 @@ class P2PClient {
|
|
|
143
143
|
setRelayPassword(password) {
|
|
144
144
|
this.relayPassword = password;
|
|
145
145
|
}
|
|
146
|
+
/** Read-only base URL — used by the voice vibe-coding path to probe
|
|
147
|
+
* GET /voice/status before opening the stream. */
|
|
148
|
+
get agentBaseUrl() {
|
|
149
|
+
return this.baseUrl;
|
|
150
|
+
}
|
|
151
|
+
/** WebSocket URL for the agent's voice stream (WS /voice/stream). The
|
|
152
|
+
* voice vibe-coding loop streams mic audio here and receives the
|
|
153
|
+
* transcript + agent task + TTS frames back. */
|
|
154
|
+
voiceStreamUrl() {
|
|
155
|
+
return this.baseUrl.replace(/^http/, 'ws') + '/voice/stream';
|
|
156
|
+
}
|
|
157
|
+
/** Auth headers for the voice WS + status probe — same bearer (and
|
|
158
|
+
* relay password) as every other agent request. */
|
|
159
|
+
voiceAuthHeaders() {
|
|
160
|
+
return this.authHeaders();
|
|
161
|
+
}
|
|
146
162
|
/** Merge in Authorization + (optional) X-Relay-Password on top of a header block. */
|
|
147
163
|
authHeaders(extra = {}) {
|
|
148
164
|
const h = { ...extra };
|
|
@@ -208,6 +224,45 @@ class P2PClient {
|
|
|
208
224
|
const data = await resp.json();
|
|
209
225
|
return data.session;
|
|
210
226
|
}
|
|
227
|
+
async getRunnerAuthStatus() {
|
|
228
|
+
const resp = await fetch(`${this.baseUrl}/runner-auth/status`, {
|
|
229
|
+
headers: this.authHeaders(),
|
|
230
|
+
});
|
|
231
|
+
if (!resp.ok) {
|
|
232
|
+
const text = await resp.text().catch(() => '');
|
|
233
|
+
throw new Error(`getRunnerAuthStatus HTTP ${resp.status}: ${text}`);
|
|
234
|
+
}
|
|
235
|
+
const data = await resp.json().catch(() => ({}));
|
|
236
|
+
return Array.isArray(data.runners) ? data.runners : [];
|
|
237
|
+
}
|
|
238
|
+
async getOpenCodeConfig() {
|
|
239
|
+
const resp = await fetch(`${this.baseUrl}/runner/opencode/config`, {
|
|
240
|
+
headers: this.authHeaders(),
|
|
241
|
+
});
|
|
242
|
+
if (!resp.ok) {
|
|
243
|
+
const text = await resp.text().catch(() => '');
|
|
244
|
+
throw new Error(`getOpenCodeConfig HTTP ${resp.status}: ${text}`);
|
|
245
|
+
}
|
|
246
|
+
const data = await resp.json().catch(() => ({}));
|
|
247
|
+
return (data.config ?? null);
|
|
248
|
+
}
|
|
249
|
+
async saveOpenCodeConfig(patch) {
|
|
250
|
+
try {
|
|
251
|
+
const resp = await fetch(`${this.baseUrl}/runner/opencode/config`, {
|
|
252
|
+
method: 'POST',
|
|
253
|
+
headers: { ...this.authHeaders(), 'Content-Type': 'application/json' },
|
|
254
|
+
body: JSON.stringify(patch),
|
|
255
|
+
});
|
|
256
|
+
const data = await resp.json().catch(() => ({}));
|
|
257
|
+
if (!resp.ok) {
|
|
258
|
+
return { ok: false, error: data.error || `HTTP ${resp.status}` };
|
|
259
|
+
}
|
|
260
|
+
return { ok: true, config: data.config };
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
264
|
+
}
|
|
265
|
+
}
|
|
211
266
|
async capabilitySnapshot() {
|
|
212
267
|
try {
|
|
213
268
|
const resp = await fetch(`${this.baseUrl}/capabilities/snapshot`, { headers: this.authHeaders() });
|
|
@@ -390,6 +445,10 @@ class P2PClient {
|
|
|
390
445
|
s2sReady: data.s2sReady ?? false,
|
|
391
446
|
sttProvider: data.sttProvider ?? undefined,
|
|
392
447
|
sttReady: data.sttReady ?? false,
|
|
448
|
+
ttsProvider: data.ttsProvider ?? undefined,
|
|
449
|
+
ttsReady: data.ttsReady ?? false,
|
|
450
|
+
enabled: data.enabled ?? false,
|
|
451
|
+
defaultProject: data.defaultProject ?? undefined,
|
|
393
452
|
};
|
|
394
453
|
}
|
|
395
454
|
/**
|
package/dist/VibeChatScreen.d.ts
CHANGED
|
@@ -15,6 +15,11 @@ interface Props {
|
|
|
15
15
|
/** Called when the user taps Reload after a task completes — uses
|
|
16
16
|
* P2PClient.reloadApp() with the active project context. */
|
|
17
17
|
onReload?: () => Promise<void>;
|
|
18
|
+
/** Optional context forwarded to the voice stream so the agent runs
|
|
19
|
+
* the task against the right project / runner / model. */
|
|
20
|
+
project?: string;
|
|
21
|
+
model?: string;
|
|
22
|
+
runner?: string;
|
|
18
23
|
}
|
|
19
|
-
export declare function VibeChatScreen({ client, initialTaskId, initialUserPrompt, onClose, onReload, }: Props): React.JSX.Element;
|
|
24
|
+
export declare function VibeChatScreen({ client, initialTaskId, initialUserPrompt, onClose, onReload, project, model, runner, }: Props): React.JSX.Element;
|
|
20
25
|
export {};
|