yaver-feedback-react-native 0.9.2 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -1
- package/dist/AuthOverlay.d.ts +1 -14
- package/dist/AuthOverlay.js +9 -62
- package/dist/Discovery.js +0 -6
- package/dist/DogfoodRuntime.d.ts +124 -0
- package/dist/DogfoodRuntime.js +273 -0
- package/dist/FeedbackModal.js +347 -61
- package/dist/LoginScreen.d.ts +1 -5
- package/dist/LoginScreen.js +2 -6
- package/dist/MachinePickerScreen.d.ts +1 -3
- package/dist/MachinePickerScreen.js +6 -18
- package/dist/P2PClient.d.ts +116 -3
- package/dist/P2PClient.js +273 -3
- package/dist/P2PDogfoodDriver.d.ts +12 -0
- package/dist/P2PDogfoodDriver.js +118 -0
- package/dist/PairDeviceModal.d.ts +2 -3
- package/dist/VibeChatScreen.d.ts +11 -1
- package/dist/VibeChatScreen.js +200 -41
- package/dist/YaverFeedback.d.ts +34 -0
- package/dist/YaverFeedback.js +124 -19
- package/dist/YaverModeBadge.d.ts +22 -0
- package/dist/YaverModeBadge.js +219 -0
- package/dist/__tests__/AuthDevices.test.js +1 -48
- package/dist/__tests__/DogfoodRuntime.test.d.ts +1 -0
- package/dist/__tests__/DogfoodRuntime.test.js +116 -0
- package/dist/__tests__/P2PDogfoodDriver.test.d.ts +1 -0
- package/dist/__tests__/P2PDogfoodDriver.test.js +64 -0
- package/dist/__tests__/ReportIdentity.test.d.ts +25 -1
- package/dist/__tests__/ReportIdentity.test.js +34 -22
- package/dist/__tests__/YaverFeedback.test.js +13 -3
- package/dist/__tests__/deviceDogfood.test.d.ts +1 -0
- package/dist/__tests__/deviceDogfood.test.js +86 -0
- package/dist/__tests__/dogfoodPolicy.test.d.ts +1 -0
- package/dist/__tests__/dogfoodPolicy.test.js +33 -0
- package/dist/_core/ansi.d.ts +117 -0
- package/dist/_core/ansi.js +468 -0
- package/dist/_core/ansi.test.d.ts +1 -0
- package/dist/_core/ansi.test.js +225 -0
- package/dist/_core/buildFeedbackPrompt.d.ts +4 -9
- package/dist/_core/buildFeedbackPrompt.js +18 -72
- package/dist/_core/constants.d.ts +19 -6
- package/dist/_core/constants.js +20 -7
- package/dist/_core/device.d.ts +9 -23
- package/dist/_core/device.js +13 -28
- package/dist/_core/endpoints.d.ts +0 -7
- package/dist/_core/endpoints.js +0 -7
- package/dist/_core/index.d.ts +4 -0
- package/dist/_core/index.js +4 -0
- package/dist/_core/remoteless.d.ts +44 -0
- package/dist/_core/remoteless.js +75 -0
- package/dist/_core/trace.d.ts +47 -0
- package/dist/_core/trace.js +38 -0
- package/dist/_core/trace.test.d.ts +1 -0
- package/dist/_core/trace.test.js +60 -0
- package/dist/auth.d.ts +3 -60
- package/dist/auth.js +6 -88
- package/dist/deviceDogfood.d.ts +53 -0
- package/dist/deviceDogfood.js +137 -0
- package/dist/dogfoodPolicy.d.ts +25 -0
- package/dist/dogfoodPolicy.js +24 -0
- package/dist/index.d.ts +13 -4
- package/dist/index.js +24 -8
- package/dist/reloadActions.js +2 -2
- package/dist/types.d.ts +50 -7
- package/package.json +12 -3
- package/src/AuthOverlay.tsx +20 -106
- package/src/Discovery.ts +0 -6
- package/src/DogfoodRuntime.ts +373 -0
- package/src/FeedbackModal.tsx +445 -67
- package/src/LoginScreen.tsx +2 -22
- package/src/MachinePickerScreen.tsx +6 -21
- package/src/P2PClient.ts +347 -4
- package/src/P2PDogfoodDriver.ts +132 -0
- package/src/PairDeviceModal.tsx +2 -3
- package/src/VibeChatScreen.tsx +232 -42
- package/src/YaverFeedback.ts +133 -22
- package/src/YaverModeBadge.tsx +234 -0
- package/src/__tests__/AuthDevices.test.ts +1 -52
- package/src/__tests__/DogfoodRuntime.test.ts +135 -0
- package/src/__tests__/P2PDogfoodDriver.test.ts +80 -0
- package/src/__tests__/ReportIdentity.test.ts +36 -27
- package/src/__tests__/YaverFeedback.test.ts +15 -3
- package/src/__tests__/deviceDogfood.test.ts +77 -0
- package/src/__tests__/dogfoodPolicy.test.ts +34 -0
- package/src/_core/ansi.test.ts +250 -0
- package/src/_core/ansi.ts +475 -0
- package/src/_core/buildFeedbackPrompt.ts +18 -95
- package/src/_core/constants.ts +20 -6
- package/src/_core/device.ts +13 -30
- package/src/_core/endpoints.ts +0 -7
- package/src/_core/index.ts +4 -0
- package/src/_core/remoteless.ts +110 -0
- package/src/_core/trace.test.ts +58 -0
- package/src/_core/trace.ts +75 -0
- package/src/auth.ts +7 -156
- package/src/deviceDogfood.ts +171 -0
- package/src/dogfoodPolicy.ts +40 -0
- package/src/index.ts +40 -11
- package/src/reloadActions.ts +2 -2
- package/src/types.ts +45 -7
- package/dist/GuestOnboardingScreen.d.ts +0 -8
- package/dist/GuestOnboardingScreen.js +0 -282
- package/src/GuestOnboardingScreen.tsx +0 -307
package/dist/LoginScreen.d.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
export interface YaverLoginScreenProps {
|
|
3
3
|
/** Invoked once a session token is issued and the user is loaded. */
|
|
4
|
-
onLoggedIn: (token: string
|
|
5
|
-
inviteCode?: string;
|
|
6
|
-
}) => void;
|
|
4
|
+
onLoggedIn: (token: string) => void;
|
|
7
5
|
/** Optional cancel button shown in header. */
|
|
8
6
|
onCancel?: () => void;
|
|
9
|
-
/** Optional prefilled guest invite code from config / deep link. */
|
|
10
|
-
initialInviteCode?: string;
|
|
11
7
|
}
|
|
12
8
|
/**
|
|
13
9
|
* Full-screen in-SDK login. Mirrors the Yaver mobile app login UX: native
|
package/dist/LoginScreen.js
CHANGED
|
@@ -91,7 +91,7 @@ const iconStyles = react_native_1.StyleSheet.create({
|
|
|
91
91
|
* Apple Sign-In on iOS, in-app browser OAuth for Google/GitHub/GitLab/
|
|
92
92
|
* Microsoft (no codes, no leaving the app), and inline email/password.
|
|
93
93
|
*/
|
|
94
|
-
const YaverLoginScreen = ({ onLoggedIn, onCancel,
|
|
94
|
+
const YaverLoginScreen = ({ onLoggedIn, onCancel, }) => {
|
|
95
95
|
const [busyProvider, setBusyProvider] = (0, react_1.useState)(null);
|
|
96
96
|
const [showEmailForm, setShowEmailForm] = (0, react_1.useState)(false);
|
|
97
97
|
const [isSignUp, setIsSignUp] = (0, react_1.useState)(false);
|
|
@@ -99,7 +99,6 @@ const YaverLoginScreen = ({ onLoggedIn, onCancel, initialInviteCode, }) => {
|
|
|
99
99
|
const [email, setEmail] = (0, react_1.useState)('');
|
|
100
100
|
const [password, setPassword] = (0, react_1.useState)('');
|
|
101
101
|
const [confirmPassword, setConfirmPassword] = (0, react_1.useState)('');
|
|
102
|
-
const [inviteCode, setInviteCode] = (0, react_1.useState)((initialInviteCode ?? '').toUpperCase());
|
|
103
102
|
const [emailBusy, setEmailBusy] = (0, react_1.useState)(false);
|
|
104
103
|
const [emailError, setEmailError] = (0, react_1.useState)('');
|
|
105
104
|
const finish = async (token) => {
|
|
@@ -107,8 +106,7 @@ const YaverLoginScreen = ({ onLoggedIn, onCancel, initialInviteCode, }) => {
|
|
|
107
106
|
await (0, auth_1.saveToken)(token);
|
|
108
107
|
if (user)
|
|
109
108
|
await (0, auth_1.saveUser)(user);
|
|
110
|
-
|
|
111
|
-
onLoggedIn(token, cleanedInviteCode ? { inviteCode: cleanedInviteCode } : undefined);
|
|
109
|
+
onLoggedIn(token);
|
|
112
110
|
};
|
|
113
111
|
const handleApple = async () => {
|
|
114
112
|
setBusyProvider('apple');
|
|
@@ -218,8 +216,6 @@ const YaverLoginScreen = ({ onLoggedIn, onCancel, initialInviteCode, }) => {
|
|
|
218
216
|
<react_native_1.TextInput style={styles.input} placeholder="Email" placeholderTextColor="#666" value={email} onChangeText={setEmail} keyboardType="email-address" autoCapitalize="none" autoCorrect={false}/>
|
|
219
217
|
<react_native_1.TextInput style={styles.input} placeholder="Password" placeholderTextColor="#666" value={password} onChangeText={setPassword} secureTextEntry autoCapitalize="none"/>
|
|
220
218
|
{isSignUp && (<react_native_1.TextInput style={styles.input} placeholder="Confirm Password" placeholderTextColor="#666" value={confirmPassword} onChangeText={setConfirmPassword} secureTextEntry/>)}
|
|
221
|
-
{isSignUp && (<react_native_1.TextInput style={styles.input} placeholder="Invite Code (optional)" placeholderTextColor="#666" value={inviteCode} onChangeText={(value) => setInviteCode(value.toUpperCase().replace(/[^A-Z0-9]/g, '').slice(0, 6))} autoCapitalize="characters" autoCorrect={false} maxLength={6}/>)}
|
|
222
|
-
|
|
223
219
|
{emailError ? (<react_native_1.Text style={styles.errorText}>{emailError}</react_native_1.Text>) : null}
|
|
224
220
|
|
|
225
221
|
<react_native_1.Pressable style={({ pressed }) => [
|
|
@@ -8,9 +8,7 @@ export interface YaverMachinePickerProps {
|
|
|
8
8
|
onCancel?: () => void;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* List of remote dev machines the signed-in user
|
|
12
|
-
* - Owned machines (user is the host)
|
|
13
|
-
* - Shared machines (host invited them as a guest)
|
|
11
|
+
* List of remote dev machines owned by the signed-in user.
|
|
14
12
|
*
|
|
15
13
|
* Tapping a device persists it to AsyncStorage and invokes `onPick`. The
|
|
16
14
|
* SDK then uses that device's deviceId for agent discovery (LAN probe +
|
|
@@ -39,9 +39,7 @@ const react_native_1 = require("react-native");
|
|
|
39
39
|
const auth_1 = require("./auth");
|
|
40
40
|
const PairDeviceModal_1 = require("./PairDeviceModal");
|
|
41
41
|
/**
|
|
42
|
-
* List of remote dev machines the signed-in user
|
|
43
|
-
* - Owned machines (user is the host)
|
|
44
|
-
* - Shared machines (host invited them as a guest)
|
|
42
|
+
* List of remote dev machines owned by the signed-in user.
|
|
45
43
|
*
|
|
46
44
|
* Tapping a device persists it to AsyncStorage and invokes `onPick`. The
|
|
47
45
|
* SDK then uses that device's deviceId for agent discovery (LAN probe +
|
|
@@ -51,7 +49,7 @@ const YaverMachinePickerScreen = ({ token, currentDeviceId, onPick, onCancel, })
|
|
|
51
49
|
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
52
50
|
const [refreshing, setRefreshing] = (0, react_1.useState)(false);
|
|
53
51
|
const [error, setError] = (0, react_1.useState)(null);
|
|
54
|
-
const [list, setList] = (0, react_1.useState)({ owned: []
|
|
52
|
+
const [list, setList] = (0, react_1.useState)({ owned: [] });
|
|
55
53
|
const [pairingDevice, setPairingDevice] = (0, react_1.useState)(null);
|
|
56
54
|
const [reachability, setReachability] = (0, react_1.useState)({});
|
|
57
55
|
const load = (0, react_1.useCallback)(async (silent = false) => {
|
|
@@ -63,7 +61,7 @@ const YaverMachinePickerScreen = ({ token, currentDeviceId, onPick, onCancel, })
|
|
|
63
61
|
setList(result);
|
|
64
62
|
setReachability({});
|
|
65
63
|
void (async () => {
|
|
66
|
-
const devices =
|
|
64
|
+
const devices = result.owned;
|
|
67
65
|
const settled = await Promise.allSettled(devices.map(async (device) => ({
|
|
68
66
|
deviceId: device.deviceId,
|
|
69
67
|
result: await (0, auth_1.probeDeviceReachability)(device),
|
|
@@ -78,8 +76,8 @@ const YaverMachinePickerScreen = ({ token, currentDeviceId, onPick, onCancel, })
|
|
|
78
76
|
return next;
|
|
79
77
|
});
|
|
80
78
|
})();
|
|
81
|
-
if (result.owned.length === 0
|
|
82
|
-
setError('No machines found yet.
|
|
79
|
+
if (result.owned.length === 0) {
|
|
80
|
+
setError('No machines found yet. Run `yaver auth` + `yaver serve` on your machine.');
|
|
83
81
|
}
|
|
84
82
|
}
|
|
85
83
|
catch (err) {
|
|
@@ -165,14 +163,8 @@ const YaverMachinePickerScreen = ({ token, currentDeviceId, onPick, onCancel, })
|
|
|
165
163
|
statusLine = 'Runner down — restart the coding agent on the Mac';
|
|
166
164
|
}
|
|
167
165
|
else {
|
|
168
|
-
// Happy-path subtitle
|
|
166
|
+
// Happy-path subtitle.
|
|
169
167
|
statusLine = device.platform;
|
|
170
|
-
if (device.isGuest && device.hostEmail) {
|
|
171
|
-
statusLine = `${statusLine} • ${device.hostEmail}`;
|
|
172
|
-
}
|
|
173
|
-
else if (device.accessScope === 'shared-scoped') {
|
|
174
|
-
statusLine = `${statusLine} • paylaşılan`;
|
|
175
|
-
}
|
|
176
168
|
}
|
|
177
169
|
return (<react_native_1.TouchableOpacity key={device.deviceId} style={[styles.deviceRow, selected && styles.deviceSelected]} onPress={() => handlePick(device)}>
|
|
178
170
|
<react_native_1.View style={[styles.health, { backgroundColor: healthColor }]}/>
|
|
@@ -200,10 +192,6 @@ const YaverMachinePickerScreen = ({ token, currentDeviceId, onPick, onCancel, })
|
|
|
200
192
|
<react_native_1.Text style={styles.sectionTitle}>Kendi makinelerim</react_native_1.Text>
|
|
201
193
|
{list.owned.map(renderDevice)}
|
|
202
194
|
</react_native_1.View>)}
|
|
203
|
-
{list.shared.length > 0 && (<react_native_1.View style={styles.section}>
|
|
204
|
-
<react_native_1.Text style={styles.sectionTitle}>Paylaşılan (guest)</react_native_1.Text>
|
|
205
|
-
{list.shared.map(renderDevice)}
|
|
206
|
-
</react_native_1.View>)}
|
|
207
195
|
{error && <react_native_1.Text style={styles.error}>{error}</react_native_1.Text>}
|
|
208
196
|
</>)}
|
|
209
197
|
</react_native_1.ScrollView>
|
package/dist/P2PClient.d.ts
CHANGED
|
@@ -13,6 +13,54 @@ export interface ReloadAck {
|
|
|
13
13
|
nativeChangesDetected?: boolean;
|
|
14
14
|
changeClass?: string;
|
|
15
15
|
}
|
|
16
|
+
export interface DogfoodDevServerStatus {
|
|
17
|
+
running?: boolean;
|
|
18
|
+
serving?: boolean;
|
|
19
|
+
starting?: boolean;
|
|
20
|
+
building?: boolean;
|
|
21
|
+
framework?: string;
|
|
22
|
+
workDir?: string;
|
|
23
|
+
bundleUrl?: string;
|
|
24
|
+
previewUrl?: string;
|
|
25
|
+
error?: string;
|
|
26
|
+
capabilityGap?: unknown;
|
|
27
|
+
}
|
|
28
|
+
export interface DogfoodDevEvent {
|
|
29
|
+
type: string;
|
|
30
|
+
framework?: string;
|
|
31
|
+
logLine?: string;
|
|
32
|
+
message?: string;
|
|
33
|
+
phase?: string;
|
|
34
|
+
pct?: number;
|
|
35
|
+
currentFile?: string;
|
|
36
|
+
snapshot?: {
|
|
37
|
+
recentLogs?: string[];
|
|
38
|
+
[key: string]: unknown;
|
|
39
|
+
};
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
}
|
|
42
|
+
export interface DogfoodRemoteRuntimeTarget {
|
|
43
|
+
id: string;
|
|
44
|
+
label: string;
|
|
45
|
+
enabled: boolean;
|
|
46
|
+
reason?: string;
|
|
47
|
+
platform?: string;
|
|
48
|
+
surface?: string;
|
|
49
|
+
displaySurface?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface DogfoodRemoteRuntimeCapabilities {
|
|
52
|
+
remoteRuntimeEligible?: boolean;
|
|
53
|
+
targets: DogfoodRemoteRuntimeTarget[];
|
|
54
|
+
}
|
|
55
|
+
export interface DogfoodRemoteRuntimeSession {
|
|
56
|
+
id: string;
|
|
57
|
+
status: string;
|
|
58
|
+
targetId?: string;
|
|
59
|
+
targetLabel?: string;
|
|
60
|
+
transportMode?: string;
|
|
61
|
+
note?: string;
|
|
62
|
+
[key: string]: unknown;
|
|
63
|
+
}
|
|
16
64
|
/**
|
|
17
65
|
* Try to resolve `{projectName, bundleId}` for the running app so the
|
|
18
66
|
* agent can map the reload request to a MobileProject in its scan
|
|
@@ -120,6 +168,17 @@ export declare class P2PClient {
|
|
|
120
168
|
* RunnerAuthModal.tsx and the Swift YaverRunnerAuthFlowPane. */
|
|
121
169
|
submitRunnerBrowserAuthCode(sessionId: string, code: string): Promise<RunnerBrowserAuthSession>;
|
|
122
170
|
getRunnerAuthStatus(): Promise<RunnerAuthStatusRow[]>;
|
|
171
|
+
/** Canonical runner + model catalogue used by Vibing routing controls. */
|
|
172
|
+
getAvailableRunners(): Promise<RunnerAuthStatusRow[]>;
|
|
173
|
+
/** Discovered runnable projects on the selected owner machine. Paths stay
|
|
174
|
+
* on that machine/transport; they are never registered in Yaver's backend. */
|
|
175
|
+
listDogfoodProjects(): Promise<Array<{
|
|
176
|
+
name: string;
|
|
177
|
+
path: string;
|
|
178
|
+
framework?: string;
|
|
179
|
+
frameworks?: string[];
|
|
180
|
+
surfaces?: string[];
|
|
181
|
+
}>>;
|
|
123
182
|
getOpenCodeConfig(): Promise<OpenCodeConfigSummary | null>;
|
|
124
183
|
saveOpenCodeConfig(patch: {
|
|
125
184
|
defaultAgent?: string;
|
|
@@ -212,6 +271,35 @@ export declare class P2PClient {
|
|
|
212
271
|
* Those are two different problems with two different fixes.
|
|
213
272
|
*/
|
|
214
273
|
getDevServerStatus(): Promise<DevServerSnapshot | null>;
|
|
274
|
+
/**
|
|
275
|
+
* Start the ordinary Projects runtime for an embedded Dogfood host.
|
|
276
|
+
* Requires a full signed-in-user token because /dev/start can spawn tools;
|
|
277
|
+
* a narrow feedback SDK token intentionally cannot use it.
|
|
278
|
+
*/
|
|
279
|
+
startDogfoodDevServer(input: {
|
|
280
|
+
framework: string;
|
|
281
|
+
workDir: string;
|
|
282
|
+
lane: 'browser' | 'hermes';
|
|
283
|
+
}): Promise<DogfoodDevServerStatus>;
|
|
284
|
+
/** Full status for Dogfood startup; unlike the compact feedback snapshot,
|
|
285
|
+
* this retains render URLs and structured startup failures. */
|
|
286
|
+
getDogfoodDevServerStatus(): Promise<DogfoodDevServerStatus | null>;
|
|
287
|
+
getDogfoodRemoteRuntimeCapabilities(workDir: string, framework: string): Promise<DogfoodRemoteRuntimeCapabilities>;
|
|
288
|
+
startDogfoodRemoteRuntime(workDir: string, framework: string, targetId: string): Promise<DogfoodRemoteRuntimeSession>;
|
|
289
|
+
stopDogfoodRemoteRuntime(sessionId: string): Promise<void>;
|
|
290
|
+
/** Stop the runtime this SDK host started. Full user auth, same as start. */
|
|
291
|
+
stopDogfoodDevServer(): Promise<void>;
|
|
292
|
+
/** Resolve an agent-reported /dev/ or /dev-web/ route without putting auth in the URL. */
|
|
293
|
+
resolveDogfoodUrl(path: string): string;
|
|
294
|
+
/**
|
|
295
|
+
* React-Native-safe /dev/events stream. XHR is intentional: Hermes fetch
|
|
296
|
+
* exposes no streaming response body. Reconnects are bounded and every
|
|
297
|
+
* reconnect/loss is surfaced to the host console.
|
|
298
|
+
*/
|
|
299
|
+
subscribeDogfoodDevEvents(onEvent: (event: DogfoodDevEvent) => void, onHealth?: (health: {
|
|
300
|
+
kind: 'reattaching' | 'lost';
|
|
301
|
+
message: string;
|
|
302
|
+
} | null) => void): () => void;
|
|
215
303
|
/**
|
|
216
304
|
* Trigger a reload with an EXPLICIT fast/full mode — no bundle fallback.
|
|
217
305
|
*
|
|
@@ -222,8 +310,8 @@ export declare class P2PClient {
|
|
|
222
310
|
* told. So this method reports the failure instead, with a named cause.
|
|
223
311
|
*
|
|
224
312
|
* Auth: the SAME bearer used for the feedback POST. `/dev/reload` is
|
|
225
|
-
* registered under `
|
|
226
|
-
*
|
|
313
|
+
* registered under `authSDK` in desktop/agent/httpserver.go and is already
|
|
314
|
+
* in the `reload` SDK-token scope list — nothing widens.
|
|
227
315
|
*/
|
|
228
316
|
reloadWithMode(mode: ReloadWireMode, snapshot?: DevServerSnapshot | null): Promise<ReloadAck>;
|
|
229
317
|
reloadApp(mode?: 'dev' | 'bundle', opts?: {
|
|
@@ -237,7 +325,7 @@ export declare class P2PClient {
|
|
|
237
325
|
* the project context plus the user's prompt. Returns the task id the
|
|
238
326
|
* caller can poll via `/tasks/{id}` if needed.
|
|
239
327
|
*
|
|
240
|
-
* Requires an owner/CLI
|
|
328
|
+
* Requires an owner/CLI token — the `/vibing*` routes do not
|
|
241
329
|
* currently accept SDK-minted tokens. Power users typically drive
|
|
242
330
|
* vibing from Claude Code / the Yaver mobile app; this method is a
|
|
243
331
|
* convenience for the SDK's one-tap bug-report-to-vibing path.
|
|
@@ -246,6 +334,8 @@ export declare class P2PClient {
|
|
|
246
334
|
projectName?: string;
|
|
247
335
|
bundleId?: string;
|
|
248
336
|
projectPath?: string;
|
|
337
|
+
runner?: string;
|
|
338
|
+
model?: string;
|
|
249
339
|
}): Promise<{
|
|
250
340
|
taskId: string;
|
|
251
341
|
}>;
|
|
@@ -365,6 +455,29 @@ export declare class P2PClient {
|
|
|
365
455
|
taskId: string;
|
|
366
456
|
raw?: unknown;
|
|
367
457
|
}>;
|
|
458
|
+
/** Existing task history, filtered by the agent to Vibing/feedback topics. */
|
|
459
|
+
listVibeThreads(input?: {
|
|
460
|
+
projectName?: string;
|
|
461
|
+
projectPath?: string;
|
|
462
|
+
}): Promise<Array<{
|
|
463
|
+
id: string;
|
|
464
|
+
title: string;
|
|
465
|
+
status: string;
|
|
466
|
+
createdAt?: string;
|
|
467
|
+
projectName?: string;
|
|
468
|
+
turnCount?: number;
|
|
469
|
+
}>>;
|
|
470
|
+
getVibeThread(taskId: string): Promise<{
|
|
471
|
+
id: string;
|
|
472
|
+
title: string;
|
|
473
|
+
status: string;
|
|
474
|
+
turns?: Array<{
|
|
475
|
+
role: 'user' | 'assistant';
|
|
476
|
+
content: string;
|
|
477
|
+
timestamp?: string;
|
|
478
|
+
}>;
|
|
479
|
+
}>;
|
|
480
|
+
deleteVibeThread(taskId: string): Promise<void>;
|
|
368
481
|
/**
|
|
369
482
|
* Subscribe to a task's live stdout/stderr stream. Returns an abort
|
|
370
483
|
* function — call it to detach. The agent emits NDJSON lines on
|
package/dist/P2PClient.js
CHANGED
|
@@ -45,6 +45,17 @@ function unrefTimer(timer) {
|
|
|
45
45
|
maybeNodeTimer.unref();
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
+
async function dogfoodFetch(url, init, timeoutMs) {
|
|
49
|
+
const ctrl = new AbortController();
|
|
50
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
51
|
+
unrefTimer(timer);
|
|
52
|
+
try {
|
|
53
|
+
return await fetch(url, { ...init, signal: ctrl.signal });
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
48
59
|
/**
|
|
49
60
|
* Try to resolve `{projectName, bundleId}` for the running app so the
|
|
50
61
|
* agent can map the reload request to a MobileProject in its scan
|
|
@@ -378,6 +389,29 @@ class P2PClient {
|
|
|
378
389
|
const data = await resp.json().catch(() => ({}));
|
|
379
390
|
return Array.isArray(data.runners) ? data.runners : [];
|
|
380
391
|
}
|
|
392
|
+
/** Canonical runner + model catalogue used by Vibing routing controls. */
|
|
393
|
+
async getAvailableRunners() {
|
|
394
|
+
const resp = await fetch(`${this.baseUrl}/agent/runners`, {
|
|
395
|
+
headers: this.authHeaders(),
|
|
396
|
+
});
|
|
397
|
+
if (!resp.ok) {
|
|
398
|
+
const text = await resp.text().catch(() => '');
|
|
399
|
+
throw new Error(`getAvailableRunners HTTP ${resp.status}: ${text}`);
|
|
400
|
+
}
|
|
401
|
+
const data = await resp.json().catch(() => ({}));
|
|
402
|
+
return Array.isArray(data.runners) ? data.runners : [];
|
|
403
|
+
}
|
|
404
|
+
/** Discovered runnable projects on the selected owner machine. Paths stay
|
|
405
|
+
* on that machine/transport; they are never registered in Yaver's backend. */
|
|
406
|
+
async listDogfoodProjects() {
|
|
407
|
+
const resp = await fetch(`${this.baseUrl}/projects`, { headers: this.authHeaders() });
|
|
408
|
+
if (!resp.ok) {
|
|
409
|
+
const body = await resp.text().catch(() => '');
|
|
410
|
+
throw new Error(`listDogfoodProjects HTTP ${resp.status}: ${body}`);
|
|
411
|
+
}
|
|
412
|
+
const data = await resp.json().catch(() => ({}));
|
|
413
|
+
return Array.isArray(data.projects) ? data.projects : [];
|
|
414
|
+
}
|
|
381
415
|
async getOpenCodeConfig() {
|
|
382
416
|
const resp = await fetch(`${this.baseUrl}/runner/opencode/config`, {
|
|
383
417
|
headers: this.authHeaders(),
|
|
@@ -662,6 +696,200 @@ class P2PClient {
|
|
|
662
696
|
return null;
|
|
663
697
|
}
|
|
664
698
|
}
|
|
699
|
+
/**
|
|
700
|
+
* Start the ordinary Projects runtime for an embedded Dogfood host.
|
|
701
|
+
* Requires a full signed-in-user token because /dev/start can spawn tools;
|
|
702
|
+
* a narrow feedback SDK token intentionally cannot use it.
|
|
703
|
+
*/
|
|
704
|
+
async startDogfoodDevServer(input) {
|
|
705
|
+
if (input.lane === 'hermes') {
|
|
706
|
+
const ack = await this.reloadApp('bundle', { projectPath: input.workDir });
|
|
707
|
+
return { running: ack.ok, framework: input.framework, workDir: input.workDir };
|
|
708
|
+
}
|
|
709
|
+
const ctrl = new AbortController();
|
|
710
|
+
const timer = setTimeout(() => ctrl.abort(), 45000);
|
|
711
|
+
unrefTimer(timer);
|
|
712
|
+
try {
|
|
713
|
+
const response = await fetch(`${this.baseUrl}/dev/start`, {
|
|
714
|
+
method: 'POST',
|
|
715
|
+
headers: this.authHeaders({ 'Content-Type': 'application/json' }),
|
|
716
|
+
body: JSON.stringify({
|
|
717
|
+
framework: input.framework,
|
|
718
|
+
workDir: input.workDir,
|
|
719
|
+
platform: 'web',
|
|
720
|
+
caller: 'sdk',
|
|
721
|
+
}),
|
|
722
|
+
signal: ctrl.signal,
|
|
723
|
+
});
|
|
724
|
+
const data = (await response.json().catch(() => ({})));
|
|
725
|
+
if (!response.ok) {
|
|
726
|
+
const error = new Error(data.error || `Dogfood preview start failed with HTTP ${response.status}`);
|
|
727
|
+
error.code = data.code || `DOGFOOD_DEV_START_HTTP_${response.status}`;
|
|
728
|
+
error.remedy = data.remedy || 'Fix the named dev-server failure, then retry Dogfood.';
|
|
729
|
+
error.retryable = data.retryable !== false;
|
|
730
|
+
error.capabilityGap = data.capabilityGap;
|
|
731
|
+
throw error;
|
|
732
|
+
}
|
|
733
|
+
return data;
|
|
734
|
+
}
|
|
735
|
+
finally {
|
|
736
|
+
clearTimeout(timer);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
/** Full status for Dogfood startup; unlike the compact feedback snapshot,
|
|
740
|
+
* this retains render URLs and structured startup failures. */
|
|
741
|
+
async getDogfoodDevServerStatus() {
|
|
742
|
+
const ctrl = new AbortController();
|
|
743
|
+
const timer = setTimeout(() => ctrl.abort(), 10000);
|
|
744
|
+
unrefTimer(timer);
|
|
745
|
+
try {
|
|
746
|
+
const response = await fetch(`${this.baseUrl}${endpoints_1.AGENT_ENDPOINTS.devStatus}`, {
|
|
747
|
+
headers: this.authHeaders(),
|
|
748
|
+
signal: ctrl.signal,
|
|
749
|
+
});
|
|
750
|
+
if (!response.ok)
|
|
751
|
+
return null;
|
|
752
|
+
return await response.json().catch(() => null);
|
|
753
|
+
}
|
|
754
|
+
catch {
|
|
755
|
+
return null;
|
|
756
|
+
}
|
|
757
|
+
finally {
|
|
758
|
+
clearTimeout(timer);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
async getDogfoodRemoteRuntimeCapabilities(workDir, framework) {
|
|
762
|
+
const query = `?workDir=${encodeURIComponent(workDir)}&framework=${encodeURIComponent(framework)}`;
|
|
763
|
+
const response = await dogfoodFetch(`${this.baseUrl}/remote-runtime/capabilities${query}`, {
|
|
764
|
+
headers: this.authHeaders(),
|
|
765
|
+
}, 20000);
|
|
766
|
+
const data = await response.json().catch(() => ({}));
|
|
767
|
+
if (!response.ok)
|
|
768
|
+
throw new Error(data?.error || `Remote-runtime capabilities failed with HTTP ${response.status}`);
|
|
769
|
+
return { ...data, targets: Array.isArray(data?.targets) ? data.targets : [] };
|
|
770
|
+
}
|
|
771
|
+
async startDogfoodRemoteRuntime(workDir, framework, targetId) {
|
|
772
|
+
const response = await dogfoodFetch(`${this.baseUrl}/remote-runtime/sessions`, {
|
|
773
|
+
method: 'POST',
|
|
774
|
+
headers: this.authHeaders({ 'Content-Type': 'application/json' }),
|
|
775
|
+
body: JSON.stringify({ workDir, framework, targetId, surface: 'sdk' }),
|
|
776
|
+
}, 45000);
|
|
777
|
+
const data = await response.json().catch(() => ({}));
|
|
778
|
+
if (!response.ok)
|
|
779
|
+
throw new Error(data?.error || `Remote-runtime start failed with HTTP ${response.status}`);
|
|
780
|
+
return data;
|
|
781
|
+
}
|
|
782
|
+
async stopDogfoodRemoteRuntime(sessionId) {
|
|
783
|
+
const response = await dogfoodFetch(`${this.baseUrl}/remote-runtime/sessions/${encodeURIComponent(sessionId)}`, {
|
|
784
|
+
method: 'DELETE', headers: this.authHeaders(),
|
|
785
|
+
}, 15000);
|
|
786
|
+
if (!response.ok)
|
|
787
|
+
throw new Error(`Remote-runtime stop failed with HTTP ${response.status}`);
|
|
788
|
+
}
|
|
789
|
+
/** Stop the runtime this SDK host started. Full user auth, same as start. */
|
|
790
|
+
async stopDogfoodDevServer() {
|
|
791
|
+
const ctrl = new AbortController();
|
|
792
|
+
const timer = setTimeout(() => ctrl.abort(), 15000);
|
|
793
|
+
unrefTimer(timer);
|
|
794
|
+
try {
|
|
795
|
+
const response = await fetch(`${this.baseUrl}/dev/stop`, {
|
|
796
|
+
method: 'POST', headers: this.authHeaders(), signal: ctrl.signal,
|
|
797
|
+
});
|
|
798
|
+
if (!response.ok)
|
|
799
|
+
throw new Error(`Dogfood preview stop failed with HTTP ${response.status}`);
|
|
800
|
+
}
|
|
801
|
+
finally {
|
|
802
|
+
clearTimeout(timer);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
/** Resolve an agent-reported /dev/ or /dev-web/ route without putting auth in the URL. */
|
|
806
|
+
resolveDogfoodUrl(path) {
|
|
807
|
+
return new URL(path, `${this.baseUrl.replace(/\/+$/, '')}/`).toString();
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* React-Native-safe /dev/events stream. XHR is intentional: Hermes fetch
|
|
811
|
+
* exposes no streaming response body. Reconnects are bounded and every
|
|
812
|
+
* reconnect/loss is surfaced to the host console.
|
|
813
|
+
*/
|
|
814
|
+
subscribeDogfoodDevEvents(onEvent, onHealth) {
|
|
815
|
+
let disposed = false;
|
|
816
|
+
let xhr = null;
|
|
817
|
+
let retryTimer = null;
|
|
818
|
+
let attempt = 0;
|
|
819
|
+
const open = () => {
|
|
820
|
+
if (disposed)
|
|
821
|
+
return;
|
|
822
|
+
const request = new XMLHttpRequest();
|
|
823
|
+
xhr = request;
|
|
824
|
+
let parsed = 0;
|
|
825
|
+
let carry = '';
|
|
826
|
+
const consume = () => {
|
|
827
|
+
const text = request.responseText || '';
|
|
828
|
+
if (text.length <= parsed)
|
|
829
|
+
return;
|
|
830
|
+
carry += text.slice(parsed);
|
|
831
|
+
parsed = text.length;
|
|
832
|
+
const normalized = carry.replace(/\r\n/g, '\n');
|
|
833
|
+
const frames = normalized.split('\n\n');
|
|
834
|
+
carry = frames.pop() || '';
|
|
835
|
+
for (const frame of frames) {
|
|
836
|
+
const data = frame.split('\n')
|
|
837
|
+
.filter((line) => line.startsWith('data:'))
|
|
838
|
+
.map((line) => line.slice(5).replace(/^ /, ''))
|
|
839
|
+
.join('\n');
|
|
840
|
+
if (!data)
|
|
841
|
+
continue;
|
|
842
|
+
try {
|
|
843
|
+
attempt = 0;
|
|
844
|
+
onHealth?.(null);
|
|
845
|
+
onEvent(JSON.parse(data));
|
|
846
|
+
}
|
|
847
|
+
catch { /* comments and non-JSON keepalives are valid SSE */ }
|
|
848
|
+
}
|
|
849
|
+
};
|
|
850
|
+
const reconnect = (reason) => {
|
|
851
|
+
if (disposed)
|
|
852
|
+
return;
|
|
853
|
+
if (attempt >= 5) {
|
|
854
|
+
onHealth?.({ kind: 'lost', message: `Dev-server logs stopped: ${reason}` });
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
const wait = Math.min(8000, 500 * (2 ** attempt));
|
|
858
|
+
attempt += 1;
|
|
859
|
+
onHealth?.({ kind: 'reattaching', message: `Dev-server logs interrupted; reconnecting (${attempt}/5): ${reason}` });
|
|
860
|
+
retryTimer = setTimeout(open, wait);
|
|
861
|
+
unrefTimer(retryTimer);
|
|
862
|
+
};
|
|
863
|
+
request.open('GET', `${this.baseUrl}/dev/events`, true);
|
|
864
|
+
for (const [key, value] of Object.entries(this.authHeaders({ Accept: 'text/event-stream' }))) {
|
|
865
|
+
try {
|
|
866
|
+
request.setRequestHeader(key, value);
|
|
867
|
+
}
|
|
868
|
+
catch { /* restricted RN header */ }
|
|
869
|
+
}
|
|
870
|
+
request.onprogress = consume;
|
|
871
|
+
request.onload = () => { consume(); reconnect(`HTTP ${request.status || 0}`); };
|
|
872
|
+
request.onerror = () => reconnect('connection failed');
|
|
873
|
+
request.onabort = () => reconnect('connection aborted');
|
|
874
|
+
request.ontimeout = () => reconnect('connection timed out');
|
|
875
|
+
try {
|
|
876
|
+
request.send();
|
|
877
|
+
}
|
|
878
|
+
catch (error) {
|
|
879
|
+
reconnect(error instanceof Error ? error.message : 'connection could not start');
|
|
880
|
+
}
|
|
881
|
+
};
|
|
882
|
+
open();
|
|
883
|
+
return () => {
|
|
884
|
+
disposed = true;
|
|
885
|
+
if (retryTimer)
|
|
886
|
+
clearTimeout(retryTimer);
|
|
887
|
+
try {
|
|
888
|
+
xhr?.abort();
|
|
889
|
+
}
|
|
890
|
+
catch { /* idempotent */ }
|
|
891
|
+
};
|
|
892
|
+
}
|
|
665
893
|
/**
|
|
666
894
|
* Trigger a reload with an EXPLICIT fast/full mode — no bundle fallback.
|
|
667
895
|
*
|
|
@@ -672,8 +900,8 @@ class P2PClient {
|
|
|
672
900
|
* told. So this method reports the failure instead, with a named cause.
|
|
673
901
|
*
|
|
674
902
|
* Auth: the SAME bearer used for the feedback POST. `/dev/reload` is
|
|
675
|
-
* registered under `
|
|
676
|
-
*
|
|
903
|
+
* registered under `authSDK` in desktop/agent/httpserver.go and is already
|
|
904
|
+
* in the `reload` SDK-token scope list — nothing widens.
|
|
677
905
|
*/
|
|
678
906
|
async reloadWithMode(mode, snapshot) {
|
|
679
907
|
if (mode === 'bundle')
|
|
@@ -785,7 +1013,7 @@ class P2PClient {
|
|
|
785
1013
|
* the project context plus the user's prompt. Returns the task id the
|
|
786
1014
|
* caller can poll via `/tasks/{id}` if needed.
|
|
787
1015
|
*
|
|
788
|
-
* Requires an owner/CLI
|
|
1016
|
+
* Requires an owner/CLI token — the `/vibing*` routes do not
|
|
789
1017
|
* currently accept SDK-minted tokens. Power users typically drive
|
|
790
1018
|
* vibing from Claude Code / the Yaver mobile app; this method is a
|
|
791
1019
|
* convenience for the SDK's one-tap bug-report-to-vibing path.
|
|
@@ -807,6 +1035,8 @@ class P2PClient {
|
|
|
807
1035
|
projectPath: identity.projectPath ?? opts?.projectPath ?? '',
|
|
808
1036
|
projectName: identity.projectName,
|
|
809
1037
|
bundleId: identity.bundleId,
|
|
1038
|
+
runner: opts?.runner,
|
|
1039
|
+
model: opts?.model,
|
|
810
1040
|
}),
|
|
811
1041
|
});
|
|
812
1042
|
if (!response.ok) {
|
|
@@ -1047,6 +1277,46 @@ class P2PClient {
|
|
|
1047
1277
|
}
|
|
1048
1278
|
return { taskId: json.taskId, raw: json };
|
|
1049
1279
|
}
|
|
1280
|
+
/** Existing task history, filtered by the agent to Vibing/feedback topics. */
|
|
1281
|
+
async listVibeThreads(input) {
|
|
1282
|
+
const params = new URLSearchParams();
|
|
1283
|
+
if (input?.projectName)
|
|
1284
|
+
params.set('projectName', input.projectName);
|
|
1285
|
+
if (input?.projectPath)
|
|
1286
|
+
params.set('projectPath', input.projectPath);
|
|
1287
|
+
const query = params.toString();
|
|
1288
|
+
const resp = await fetch(`${this.baseUrl}/vibing/tasks${query ? `?${query}` : ''}`, {
|
|
1289
|
+
headers: this.authHeaders(),
|
|
1290
|
+
});
|
|
1291
|
+
if (!resp.ok)
|
|
1292
|
+
throw new Error(`listVibeThreads HTTP ${resp.status}`);
|
|
1293
|
+
const json = (await resp.json().catch(() => ({})));
|
|
1294
|
+
return (json.tasks || []).map((task) => ({
|
|
1295
|
+
id: String(task.id),
|
|
1296
|
+
title: String(task.title || 'New topic'),
|
|
1297
|
+
status: String(task.status || 'completed'),
|
|
1298
|
+
createdAt: task.createdAt,
|
|
1299
|
+
projectName: task.projectName,
|
|
1300
|
+
turnCount: task.turnCount,
|
|
1301
|
+
}));
|
|
1302
|
+
}
|
|
1303
|
+
async getVibeThread(taskId) {
|
|
1304
|
+
const resp = await fetch(`${this.baseUrl}/vibing/task/${encodeURIComponent(taskId)}`, {
|
|
1305
|
+
headers: this.authHeaders(),
|
|
1306
|
+
});
|
|
1307
|
+
if (!resp.ok)
|
|
1308
|
+
throw new Error(`getVibeThread HTTP ${resp.status}`);
|
|
1309
|
+
const json = (await resp.json().catch(() => ({})));
|
|
1310
|
+
return json.task || json;
|
|
1311
|
+
}
|
|
1312
|
+
async deleteVibeThread(taskId) {
|
|
1313
|
+
const resp = await fetch(`${this.baseUrl}/vibing/task/${encodeURIComponent(taskId)}`, {
|
|
1314
|
+
method: 'DELETE',
|
|
1315
|
+
headers: this.authHeaders(),
|
|
1316
|
+
});
|
|
1317
|
+
if (!resp.ok)
|
|
1318
|
+
throw new Error(`deleteVibeThread HTTP ${resp.status}`);
|
|
1319
|
+
}
|
|
1050
1320
|
/**
|
|
1051
1321
|
* Subscribe to a task's live stdout/stderr stream. Returns an abort
|
|
1052
1322
|
* function — call it to detach. The agent emits NDJSON lines on
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { P2PClient } from './P2PClient';
|
|
2
|
+
import { type DogfoodDriver } from './DogfoodRuntime';
|
|
3
|
+
export interface P2PDogfoodDriverOptions {
|
|
4
|
+
startupTimeoutMs?: number;
|
|
5
|
+
pollIntervalMs?: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Ready-to-use driver for app owners who authenticate with Yaver's normal
|
|
9
|
+
* account flow. Their UI owns the trigger and preview surface; this adapter
|
|
10
|
+
* owns the existing Projects endpoints and raw build log stream.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createP2PDogfoodDriver(client: P2PClient, options?: P2PDogfoodDriverOptions): DogfoodDriver;
|