@cf-vibesdk/sdk 0.1.0 → 0.1.1

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 CHANGED
@@ -94,53 +94,6 @@ const session = await client.build('Build a weather dashboard', {
94
94
  });
95
95
  ```
96
96
 
97
- #### Blueprint Streaming
98
-
99
- The server streams blueprint chunks as the AI generates the project plan. By default, `build()` waits for all chunks before returning:
100
-
101
- ```ts
102
- // Default behavior: waits for blueprint to complete
103
- const session = await client.build('Build a todo app', {
104
- onBlueprintChunk: (chunk) => {
105
- // Called in real-time as chunks arrive
106
- blueprintText += chunk;
107
- },
108
- });
109
- // Session returned after all blueprint chunks received
110
- ```
111
-
112
- For faster startup, set `waitForBlueprint: false` to return immediately and stream chunks in the background:
113
-
114
- ```ts
115
- const session = await client.build('Build a todo app', {
116
- waitForBlueprint: false, // Return immediately after start event
117
- onBlueprintChunk: (chunk) => {
118
- // Still called in real-time as chunks arrive
119
- blueprintText += chunk;
120
- },
121
- onBlueprintError: (error) => {
122
- // Called if streaming fails (session is auto-closed)
123
- console.error('Blueprint streaming failed:', error);
124
- },
125
- });
126
- // Session returned immediately, blueprint streams in background
127
- ```
128
-
129
- Use the `BlueprintStreamParser` utility to convert chunks to readable Markdown:
130
-
131
- ```ts
132
- import { BlueprintStreamParser } from '@cf-vibesdk/sdk';
133
-
134
- const parser = new BlueprintStreamParser();
135
- const session = await client.build('Build a todo app', {
136
- waitForBlueprint: false,
137
- onBlueprintChunk: (chunk) => {
138
- const markdown = parser.append(chunk);
139
- console.log(markdown); // Rendered as Markdown
140
- },
141
- });
142
- ```
143
-
144
97
  ### `client.connect(agentId)`
145
98
 
146
99
  Connect to an existing app session. State is automatically restored from the agent, including:
@@ -369,14 +322,14 @@ session.workspace.onChange((change) => {
369
322
 
370
323
  ## WebSocket Reliability
371
324
 
372
- Connections automatically reconnect with exponential backoff. The first reconnect attempt is **immediate** (0ms delay) for fast recovery from brief network blips, followed by exponential backoff starting at 200ms.
325
+ Connections automatically reconnect with exponential backoff.
373
326
 
374
327
  ```ts
375
328
  // Custom retry config
376
329
  await session.connect({
377
330
  retry: {
378
331
  enabled: true, // Default: true
379
- initialDelayMs: 200, // Default: 200 (used from 2nd attempt onward)
332
+ initialDelayMs: 1000, // Default: 1000
380
333
  maxDelayMs: 30000, // Default: 30000
381
334
  maxRetries: 10, // Default: Infinity
382
335
  },
@@ -386,35 +339,6 @@ await session.connect({
386
339
  await session.connect({ retry: { enabled: false } });
387
340
  ```
388
341
 
389
- ### Auto-Preview on Reconnect
390
-
391
- When connecting to an **existing app** (via `client.connect()`), the SDK automatically sends a `preview` message on connect and reconnect to ensure the preview deployment stays active:
392
-
393
- ```ts
394
- // Existing app - auto-preview is enabled by default
395
- const session = await client.connect('agent-id');
396
- await session.connect(); // Sends preview message automatically
397
-
398
- // Override for new builds or disable
399
- await session.connect({ autoRequestPreview: false });
400
-
401
- // Force enable for new builds
402
- const session = await client.build('Build a todo app');
403
- await session.connect({ autoRequestPreview: true });
404
- ```
405
-
406
- ### Reconnect Events
407
-
408
- ```ts
409
- session.on('ws:reconnecting', ({ attempt, delayMs, reason }) => {
410
- console.log(`Reconnecting (attempt ${attempt}, delay ${delayMs}ms, reason: ${reason})`);
411
- });
412
-
413
- session.on('ws:reconnected', () => {
414
- console.log('Reconnected successfully');
415
- });
416
- ```
417
-
418
342
  ## HTTP Retry
419
343
 
420
344
  HTTP requests automatically retry on 5xx errors.
package/dist/index.d.ts CHANGED
@@ -271,6 +271,16 @@ declare const AgenticBlueprintSchema: z.ZodObject<{
271
271
  frameworks: z.ZodArray<z.ZodString, "many">;
272
272
  } & {
273
273
  plan: z.ZodArray<z.ZodString, "many">;
274
+ preflightAnswers: z.ZodOptional<z.ZodArray<z.ZodObject<{
275
+ question: z.ZodString;
276
+ answer: z.ZodString;
277
+ }, "strip", z.ZodTypeAny, {
278
+ question: string;
279
+ answer: string;
280
+ }, {
281
+ question: string;
282
+ answer: string;
283
+ }>, "many">>;
274
284
  }, "strip", z.ZodTypeAny, {
275
285
  description: string;
276
286
  title: string;
@@ -278,6 +288,10 @@ declare const AgenticBlueprintSchema: z.ZodObject<{
278
288
  colorPalette: string[];
279
289
  frameworks: string[];
280
290
  plan: string[];
291
+ preflightAnswers?: {
292
+ question: string;
293
+ answer: string;
294
+ }[] | undefined;
281
295
  }, {
282
296
  description: string;
283
297
  title: string;
@@ -285,6 +299,10 @@ declare const AgenticBlueprintSchema: z.ZodObject<{
285
299
  colorPalette: string[];
286
300
  frameworks: string[];
287
301
  plan: string[];
302
+ preflightAnswers?: {
303
+ question: string;
304
+ answer: string;
305
+ }[] | undefined;
288
306
  }>;
289
307
  type PhasicBlueprint = z.infer<typeof PhasicBlueprintSchema>;
290
308
  type AgenticBlueprint = z.infer<typeof AgenticBlueprintSchema>;
@@ -783,6 +801,8 @@ interface BaseProjectState {
783
801
  pendingUserInputs: string[];
784
802
  projectUpdatesAccumulator: string[];
785
803
  lastDeepDebugTranscript: string | null;
804
+ preflightQuestions?: string;
805
+ preflightCompleted?: boolean;
786
806
  mvpGenerated: boolean;
787
807
  reviewingInitiated: boolean;
788
808
  }
@@ -1145,6 +1165,7 @@ type ScreenshotCaptureSuccessMessage = {
1145
1165
  };
1146
1166
  screenshotSize: number;
1147
1167
  timestamp: string;
1168
+ screenshotUrl?: string;
1148
1169
  };
1149
1170
  type ScreenshotCaptureErrorMessage = {
1150
1171
  type: "screenshot_capture_error";
@@ -1322,6 +1343,8 @@ interface CodeGenArgs {
1322
1343
  images?: ImageAttachment[];
1323
1344
  /** Optional ephemeral credentials (BYOK / gateway override) for sdk */
1324
1345
  credentials?: CredentialsPayload;
1346
+ /** Optional preflight questions prompt. When provided, the agent asks these questions one-by-one before building and stores answers in the blueprint. */
1347
+ preflightQuestions?: string;
1325
1348
  }
1326
1349
  /**
1327
1350
  * Data structure for connectToExistingAgent response
@@ -2484,7 +2507,7 @@ declare const apps: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
2484
2507
  tableName: "apps";
2485
2508
  dataType: "string";
2486
2509
  columnType: "SQLiteText";
2487
- data: "private" | "public";
2510
+ data: "public" | "private";
2488
2511
  driverParam: string;
2489
2512
  notNull: true;
2490
2513
  hasDefault: true;
@@ -2572,7 +2595,7 @@ declare const apps: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
2572
2595
  tableName: "apps";
2573
2596
  dataType: "string";
2574
2597
  columnType: "SQLiteText";
2575
- data: "private" | "public";
2598
+ data: "public" | "private";
2576
2599
  driverParam: string;
2577
2600
  notNull: false;
2578
2601
  hasDefault: false;
@@ -5173,11 +5196,11 @@ type App = {
5173
5196
  framework: string | null;
5174
5197
  userId: string | null;
5175
5198
  sessionToken: string | null;
5176
- visibility: "private" | "public";
5199
+ visibility: "public" | "private";
5177
5200
  status: "completed" | "generating";
5178
5201
  deploymentId: string | null;
5179
5202
  githubRepositoryUrl: string | null;
5180
- githubRepositoryVisibility: "private" | "public" | null;
5203
+ githubRepositoryVisibility: "public" | "private" | null;
5181
5204
  isArchived: boolean | null;
5182
5205
  isFeatured: boolean | null;
5183
5206
  version: number | null;
@@ -5453,21 +5476,7 @@ type CodeGenArgs$1 = CodeGenArgs;
5453
5476
  export type BuildOptions = Omit<CodeGenArgs$1, "query"> & {
5454
5477
  autoConnect?: boolean;
5455
5478
  autoGenerate?: boolean;
5456
- /**
5457
- * Called for each blueprint chunk as it streams from the server.
5458
- */
5459
5479
  onBlueprintChunk?: (chunk: string) => void;
5460
- /**
5461
- * Called if blueprint streaming fails. The session will be closed automatically.
5462
- * Only relevant when `waitForBlueprint` is false.
5463
- */
5464
- onBlueprintError?: (error: Error) => void;
5465
- /**
5466
- * If true (default), `build()` waits for all blueprint chunks before returning.
5467
- * If false, `build()` returns immediately after receiving the start event,
5468
- * and blueprint chunks stream in the background via `onBlueprintChunk`.
5469
- */
5470
- waitForBlueprint?: boolean;
5471
5480
  };
5472
5481
  type TemplateFiles = Record<string, string>;
5473
5482
  export type BuildStartEvent = {
@@ -5494,11 +5503,11 @@ type App$1 = {
5494
5503
  framework: string | null;
5495
5504
  userId: string | null;
5496
5505
  sessionToken: string | null;
5497
- visibility: "private" | "public";
5506
+ visibility: "public" | "private";
5498
5507
  status: "completed" | "generating";
5499
5508
  deploymentId: string | null;
5500
5509
  githubRepositoryUrl: string | null;
5501
- githubRepositoryVisibility: "private" | "public" | null;
5510
+ githubRepositoryVisibility: "public" | "private" | null;
5502
5511
  isArchived: boolean | null;
5503
5512
  isFeatured: boolean | null;
5504
5513
  version: number | null;
@@ -5568,7 +5577,6 @@ export type AgentEventMap = {
5568
5577
  delayMs: number;
5569
5578
  reason: "close" | "error";
5570
5579
  };
5571
- "ws:reconnected": undefined;
5572
5580
  "ws:raw": {
5573
5581
  raw: unknown;
5574
5582
  };
@@ -5864,19 +5872,12 @@ type WaitUntilReadyOptions = WaitOptions;
5864
5872
  type BuildSessionConnectOptions = Omit<AgentConnectionOptions, "credentials"> & {
5865
5873
  /** If true (default), send `get_conversation_state` on socket open. */
5866
5874
  autoRequestConversationState?: boolean;
5867
- /**
5868
- * If true, send `preview` message on connect and reconnect to ensure preview exists.
5869
- * Defaults to true for existing apps (via `client.connect()`), false for new builds.
5870
- */
5871
- autoRequestPreview?: boolean;
5872
5875
  /** Credentials to send via session_init after connection. */
5873
5876
  credentials?: Credentials;
5874
5877
  };
5875
5878
  type BuildSessionInit = {
5876
5879
  httpClient: HttpClient;
5877
5880
  defaultCredentials?: Credentials;
5878
- /** True if this session is for an existing app (via client.connect). */
5879
- isExistingApp?: boolean;
5880
5881
  };
5881
5882
  export declare class BuildSession {
5882
5883
  private init;
@@ -5970,10 +5971,6 @@ export declare class VibeClient {
5970
5971
  get baseUrl(): string;
5971
5972
  /**
5972
5973
  * Creates a new agent/app from a prompt and returns a BuildSession.
5973
- *
5974
- * By default, waits for all blueprint chunks before returning. Set
5975
- * `waitForBlueprint: false` to return immediately after the start event,
5976
- * with blueprint chunks streaming in the background.
5977
5974
  */
5978
5975
  build(prompt: string, options?: BuildOptions): Promise<BuildSession>;
5979
5976
  /** Connect to an existing agent/app by id. */
@@ -6060,7 +6057,7 @@ export declare class VibeClient {
6060
6057
  finalPrompt: string | null;
6061
6058
  framework: string | null;
6062
6059
  sessionToken: string | null;
6063
- visibility: "private" | "public";
6060
+ visibility: "public" | "private";
6064
6061
  githubRepositoryUrl: string | null;
6065
6062
  githubRepositoryVisibility: string | null;
6066
6063
  isArchived: string | boolean | null;
@@ -6122,6 +6119,10 @@ type Blueprint$1 = {
6122
6119
  phase: string;
6123
6120
  description: string;
6124
6121
  }>;
6122
+ preflightAnswers?: Array<{
6123
+ question: string;
6124
+ answer: string;
6125
+ }>;
6125
6126
  };
6126
6127
  /**
6127
6128
  * Converts a Blueprint object to readable Markdown.
package/dist/index.js CHANGED
@@ -409,7 +409,7 @@ class SessionStateStore {
409
409
  const m = msg;
410
410
  const phaseInfo = extractPhaseInfo(m);
411
411
  const phaseFiles = extractPhaseFiles(m);
412
- const phases = this.updateOrAddPhase(phaseInfo, "completed", phaseFiles);
412
+ const phases = this.updateOrAddPhase(phaseInfo, "validating", phaseFiles);
413
413
  this.setState({
414
414
  phase: { status: "implemented", ...phaseInfo },
415
415
  phases
@@ -431,7 +431,7 @@ class SessionStateStore {
431
431
  const m = msg;
432
432
  const phaseInfo = extractPhaseInfo(m);
433
433
  const phaseFiles = extractPhaseFiles(m);
434
- const phases = this.updateOrAddPhase(phaseInfo, "validating", phaseFiles);
434
+ const phases = this.updateOrAddPhase(phaseInfo, "completed", phaseFiles);
435
435
  this.setState({
436
436
  phase: { status: "validated", ...phaseInfo },
437
437
  phases
@@ -618,7 +618,7 @@ async function withTimeout(promise, ms, message = "Operation timed out") {
618
618
  // src/ws.ts
619
619
  var WS_RETRY_DEFAULTS = {
620
620
  enabled: true,
621
- initialDelayMs: 200,
621
+ initialDelayMs: 1000,
622
622
  maxDelayMs: 30000,
623
623
  maxRetries: Infinity
624
624
  };
@@ -630,7 +630,6 @@ function createAgentConnection(getUrl, options = {}) {
630
630
  let closedByUser = false;
631
631
  let reconnectAttempts = 0;
632
632
  let reconnectTimer = null;
633
- let hasConnectedBefore = false;
634
633
  const pendingSends = [];
635
634
  const maxPendingSends = 1000;
636
635
  function clearReconnectTimer() {
@@ -656,34 +655,22 @@ function createAgentConnection(getUrl, options = {}) {
656
655
  return;
657
656
  if (reconnectTimer)
658
657
  return;
659
- const delayMs = reconnectAttempts === 0 ? 0 : computeBackoffMs(reconnectAttempts, retryCfg);
658
+ const delayMs = computeBackoffMs(reconnectAttempts, retryCfg);
660
659
  emitter.emit("ws:reconnecting", {
661
660
  attempt: reconnectAttempts + 1,
662
661
  delayMs,
663
662
  reason
664
663
  });
665
664
  reconnectAttempts += 1;
666
- if (delayMs === 0) {
667
- reconnectTimer = setTimeout(() => {
668
- reconnectTimer = null;
669
- connectNow();
670
- }, 0);
671
- } else {
672
- reconnectTimer = setTimeout(() => {
673
- reconnectTimer = null;
674
- connectNow();
675
- }, delayMs);
676
- }
665
+ reconnectTimer = setTimeout(() => {
666
+ reconnectTimer = null;
667
+ connectNow();
668
+ }, delayMs);
677
669
  }
678
670
  function onOpen() {
679
- const isReconnect = hasConnectedBefore;
680
- hasConnectedBefore = true;
681
671
  isOpen = true;
682
672
  reconnectAttempts = 0;
683
673
  emitter.emit("ws:open", undefined);
684
- if (isReconnect) {
685
- emitter.emit("ws:reconnected", undefined);
686
- }
687
674
  flushPendingSends();
688
675
  }
689
676
  function onClose(e) {
@@ -1018,7 +1005,7 @@ class BuildSession {
1018
1005
  async connect(options = {}) {
1019
1006
  if (this.connection)
1020
1007
  return this.connection;
1021
- const { autoRequestConversationState, autoRequestPreview, credentials, ...connectionOptions } = options;
1008
+ const { autoRequestConversationState, credentials, ...connectionOptions } = options;
1022
1009
  const getUrl = async () => {
1023
1010
  const { ticket } = await this.init.httpClient.getWsTicket(this.agentId);
1024
1011
  const base = this.websocketUrl;
@@ -1039,7 +1026,6 @@ class BuildSession {
1039
1026
  });
1040
1027
  const sessionCredentials = credentials ?? this.init.defaultCredentials;
1041
1028
  const shouldRequestConversationState = autoRequestConversationState ?? true;
1042
- const shouldRequestPreview = autoRequestPreview ?? (this.init.isExistingApp ?? false);
1043
1029
  this.connection.on("ws:open", () => {
1044
1030
  if (sessionCredentials) {
1045
1031
  this.connection?.send({
@@ -1050,14 +1036,6 @@ class BuildSession {
1050
1036
  if (shouldRequestConversationState) {
1051
1037
  this.connection?.send({ type: "get_conversation_state" });
1052
1038
  }
1053
- if (shouldRequestPreview) {
1054
- this.connection?.send({ type: "preview" });
1055
- }
1056
- });
1057
- this.connection.on("ws:reconnected", () => {
1058
- if (shouldRequestPreview) {
1059
- this.connection?.send({ type: "preview" });
1060
- }
1061
1039
  });
1062
1040
  return this.connection;
1063
1041
  }
@@ -1210,7 +1188,8 @@ class VibeClient {
1210
1188
  behaviorType: options.behaviorType,
1211
1189
  projectType: options.projectType,
1212
1190
  images: options.images,
1213
- credentials: options.credentials
1191
+ credentials: options.credentials,
1192
+ preflightQuestions: options.preflightQuestions
1214
1193
  };
1215
1194
  const resp = await this.http.fetchRaw("/api/agent", {
1216
1195
  method: "POST",
@@ -1220,35 +1199,24 @@ class VibeClient {
1220
1199
  if (!resp.body) {
1221
1200
  throw new Error("Missing response body from /api/agent");
1222
1201
  }
1223
- const iterator = parseNdjsonStream(resp.body)[Symbol.asyncIterator]();
1224
- const { value: start, done } = await iterator.next();
1225
- if (done || !start) {
1202
+ let start = null;
1203
+ for await (const obj of parseNdjsonStream(resp.body)) {
1204
+ if (!start) {
1205
+ start = obj;
1206
+ continue;
1207
+ }
1208
+ const o = obj;
1209
+ if (typeof o.chunk === "string") {
1210
+ options.onBlueprintChunk?.(o.chunk);
1211
+ }
1212
+ }
1213
+ if (!start) {
1226
1214
  throw new Error("No start event received from /api/agent");
1227
1215
  }
1228
1216
  const session = new BuildSession(start, {
1229
1217
  httpClient: this.http,
1230
1218
  ...options.credentials ? { defaultCredentials: options.credentials } : {}
1231
1219
  });
1232
- const waitForBlueprint = options.waitForBlueprint ?? true;
1233
- const processChunks = async () => {
1234
- let result = await iterator.next();
1235
- while (!result.done) {
1236
- const obj = result.value;
1237
- if (typeof obj.chunk === "string") {
1238
- options.onBlueprintChunk?.(obj.chunk);
1239
- }
1240
- result = await iterator.next();
1241
- }
1242
- };
1243
- if (waitForBlueprint) {
1244
- await processChunks();
1245
- } else {
1246
- processChunks().catch((error) => {
1247
- const err = error instanceof Error ? error : new Error(String(error));
1248
- options.onBlueprintError?.(err);
1249
- session.close();
1250
- });
1251
- }
1252
1220
  if (options.autoConnect ?? true) {
1253
1221
  await session.connect();
1254
1222
  if (options.autoGenerate ?? true) {
@@ -1268,7 +1236,6 @@ class VibeClient {
1268
1236
  };
1269
1237
  return new BuildSession(start, {
1270
1238
  httpClient: this.http,
1271
- isExistingApp: true,
1272
1239
  ...options.credentials ? { defaultCredentials: options.credentials } : {}
1273
1240
  });
1274
1241
  }
@@ -1397,6 +1364,12 @@ function blueprintToMarkdown(bp) {
1397
1364
  for (const p of bp.implementationRoadmap)
1398
1365
  lines.push(`- **${p.phase}**: ${p.description}`);
1399
1366
  }
1367
+ if (bp.preflightAnswers?.length) {
1368
+ lines.push("");
1369
+ lines.push("## Preflight Answers");
1370
+ for (const a of bp.preflightAnswers)
1371
+ lines.push(`- **${a.question}**: ${a.answer}`);
1372
+ }
1400
1373
  return lines.join(`
1401
1374
  `);
1402
1375
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cf-vibesdk/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {