@vercel/dream 0.2.13 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/dream.js +46 -23
  2. package/package.json +1 -1
package/dist/dream.js CHANGED
@@ -163,21 +163,22 @@ Each iteration should complete a coherent unit (not trivial single-file churn),
163
163
 
164
164
  **If tasks remain:** update \`PROGRESS.md\` and stop. Do NOT output completion signal.
165
165
 
166
- **When all work is done**, output completion signal only after all are true:
167
- - Every task in \`PROGRESS.md\` is complete
168
- - All specs in \`specs/\` are implemented
169
- - Required verification commands pass
170
- - No active blockers remain
171
- - Implementation artifacts are source-code-compliant with specs (not forbidden static fallback)
172
- - Generated deployment output conforms to Build Output API for the target deploy platform
166
+ **When all work is done**, output completion signal. The bar is:
167
+ 1. All tasks in \`PROGRESS.md\` are checked off
168
+ 2. \`npm run build\` (or equivalent) exits 0
169
+ 3. No blockers in \`PROGRESS.md\`
170
+
171
+ That's it. Do NOT loop on cosmetic verification (curling pages, grepping HTML, re-reading files you just wrote). If it builds clean and tasks are done, you are done.
173
172
 
174
173
  When complete, output exactly this on its own line:
175
174
 
176
175
  ${STOP_WORD}
177
176
 
178
- Without this signal, the system keeps launching new iterations.`;
177
+ **You MUST include text in every response.** If you only used tools, still output a one-line status summary. Responses with zero text cause unnecessary continuation.
178
+
179
+ Without the completion signal, the system keeps launching new iterations.`;
179
180
  var DEFAULT_TIMEOUT = 36e5;
180
- var DEFAULT_MAX_ITERATIONS = 100;
181
+ var DEFAULT_MAX_ITERATIONS = 20;
181
182
  var DEFAULT_MODEL = "vercel/anthropic/claude-opus-4.6";
182
183
  var DREAM_VERSION = readDreamVersion();
183
184
  var DEFAULT_BOOTSTRAP_SKILL_REPOS = [
@@ -362,6 +363,8 @@ ${INDENT_MAIN}${red("\u2717")} Runtime bootstrap failed: ${message}
362
363
  }
363
364
  printStep("Starting OpenCode...");
364
365
  const oidcToken = process.env.VERCEL_OIDC_TOKEN;
366
+ const gatewayApiKey = process.env.AI_GATEWAY_API_KEY;
367
+ const providerOptions = oidcToken ? { apiKey: oidcToken, headers: { "ai-gateway-auth-method": "oidc" } } : gatewayApiKey ? { apiKey: gatewayApiKey } : void 0;
365
368
  const { client, server } = await createOpencode({
366
369
  port: 0,
367
370
  config: {
@@ -379,15 +382,8 @@ ${INDENT_MAIN}${red("\u2717")} Runtime bootstrap failed: ${message}
379
382
  },
380
383
  provider: {
381
384
  vercel: {
382
- env: ["VERCEL_API_KEY", "VERCEL_OIDC_TOKEN"],
383
- ...oidcToken && {
384
- options: {
385
- apiKey: oidcToken,
386
- headers: {
387
- "ai-gateway-auth-method": "oidc"
388
- }
389
- }
390
- }
385
+ env: ["AI_GATEWAY_API_KEY", "VERCEL_API_KEY", "VERCEL_OIDC_TOKEN"],
386
+ ...providerOptions && { options: providerOptions }
391
387
  }
392
388
  },
393
389
  enabled_providers: ["vercel"]
@@ -426,6 +422,8 @@ ${INDENT_MAIN}Run ${cyan("opencode")} and authenticate the ${bold(providerId)} p
426
422
  process.on("SIGTERM", cleanup);
427
423
  const startTime = Date.now();
428
424
  let iteration = 0;
425
+ let noEditStreak = 0;
426
+ const MAX_NO_EDIT_STREAK = 3;
429
427
  try {
430
428
  while (iteration < maxIterations) {
431
429
  const elapsed = Date.now() - startTime;
@@ -466,10 +464,27 @@ ${INDENT_MAIN}${red("\u2717")} Session failed after ${bold(String(iteration))} i
466
464
  );
467
465
  process.exit(1);
468
466
  }
469
- printLine(
470
- `${INDENT_MAIN}${cyan(`[${iteration}]`)} ${dim(`${formatTime(iterElapsed)} \xB7 continuing...`)}
467
+ if (result === "stalled") {
468
+ noEditStreak++;
469
+ if (noEditStreak >= MAX_NO_EDIT_STREAK) {
470
+ printLine(
471
+ `
472
+ ${INDENT_MAIN}${red("\u2717")} Stalled: ${MAX_NO_EDIT_STREAK} consecutive iterations with no file edits. Stopping.
471
473
  `
472
- );
474
+ );
475
+ process.exit(1);
476
+ }
477
+ printLine(
478
+ `${INDENT_MAIN}${cyan(`[${iteration}]`)} ${dim(`${formatTime(iterElapsed)} \xB7 no edits (${noEditStreak}/${MAX_NO_EDIT_STREAK}) \xB7 continuing...`)}
479
+ `
480
+ );
481
+ } else {
482
+ noEditStreak = 0;
483
+ printLine(
484
+ `${INDENT_MAIN}${cyan(`[${iteration}]`)} ${dim(`${formatTime(iterElapsed)} \xB7 continuing...`)}
485
+ `
486
+ );
487
+ }
473
488
  }
474
489
  printLine(`
475
490
  ${INDENT_MAIN}${red("\u2717")} Max iterations reached
@@ -504,6 +519,7 @@ async function runSession(client, title, systemPrompt, verbose) {
504
519
  }
505
520
  let responseText = "";
506
521
  let toolCalls = 0;
522
+ let fileEdits = 0;
507
523
  let totalCost = 0;
508
524
  let totalTokensIn = 0;
509
525
  let totalTokensOut = 0;
@@ -528,6 +544,11 @@ async function runSession(client, title, systemPrompt, verbose) {
528
544
  if (event.type === "message.part.updated") {
529
545
  const { part } = event.properties;
530
546
  const delta = event.properties.delta;
547
+ if (verbose && !["text", "reasoning", "tool", "step-finish"].includes(part.type)) {
548
+ printSessionDim(
549
+ `unhandled part type: ${part.type} ${JSON.stringify(part).slice(0, 200)}`
550
+ );
551
+ }
531
552
  if (part.type === "text" && delta) {
532
553
  responseText += delta;
533
554
  if (lastOutput === "tool") process.stdout.write("\n");
@@ -577,6 +598,7 @@ ${INDENT_SESSION}`);
577
598
  if (event.type === "file.edited") {
578
599
  const file = event.properties.file;
579
600
  if (file) {
601
+ fileEdits++;
580
602
  if (lastOutput === "text") process.stdout.write("\n");
581
603
  const relative = file.replace(`${process.cwd()}/`, "");
582
604
  printSession(`${green("\u270E")} ${relative}`);
@@ -601,12 +623,13 @@ ${INDENT_SESSION}`);
601
623
  if (responseText.length === 0) {
602
624
  if (toolCalls > 0) {
603
625
  printSessionDim("no text response, continuing...");
604
- return "continue";
626
+ return fileEdits > 0 ? "continue" : "stalled";
605
627
  }
606
628
  printSessionError("No response from model");
607
629
  return "error";
608
630
  }
609
- return responseText.includes(STOP_WORD) ? "done" : "continue";
631
+ if (responseText.includes(STOP_WORD)) return "done";
632
+ return fileEdits > 0 ? "continue" : "stalled";
610
633
  }
611
634
  function formatTime(ms) {
612
635
  if (ms < 1e3) return `${ms}ms`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/dream",
3
- "version": "0.2.13",
3
+ "version": "0.3.2",
4
4
  "description": "A CLI that runs OpenCode in a loop until specs are complete",
5
5
  "type": "module",
6
6
  "bin": {