@vercel/dream 0.3.3 → 0.4.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/dream.js +110 -9
- package/package.json +1 -1
package/dist/dream.js
CHANGED
|
@@ -44,10 +44,12 @@ Environment variables required by the project are injected into the runtime envi
|
|
|
44
44
|
|
|
45
45
|
## Implementation Artifact Policy
|
|
46
46
|
|
|
47
|
-
1. The deliverable is
|
|
48
|
-
2.
|
|
49
|
-
3.
|
|
50
|
-
4.
|
|
47
|
+
1. The deliverable is \`.vercel/output/\` conforming to Build Output API v3.
|
|
48
|
+
2. \`.vercel/output/config.json\` must exist with \`{ "version": 3 }\`.
|
|
49
|
+
3. Static assets go in \`.vercel/output/static/\`. Serverless functions go in \`.vercel/output/functions/\`.
|
|
50
|
+
4. You may use any method to produce this: hand-write HTML, use a framework build, or any other approach.
|
|
51
|
+
5. Run \`dream validate\` to verify the output before signaling completion.
|
|
52
|
+
6. If required prerequisites are missing (for example env vars, credentials, unavailable services), do not produce a static fallback. Record a blocker in \`PROGRESS.md\` and stop the iteration.
|
|
51
53
|
|
|
52
54
|
## Critical: State Lives on Disk
|
|
53
55
|
|
|
@@ -165,7 +167,7 @@ Each iteration should complete a coherent unit (not trivial single-file churn),
|
|
|
165
167
|
|
|
166
168
|
**When all work is done**, output completion signal. The bar is:
|
|
167
169
|
1. All tasks in \`PROGRESS.md\` are checked off
|
|
168
|
-
2. \`
|
|
170
|
+
2. \`dream validate\` passes
|
|
169
171
|
3. No blockers in \`PROGRESS.md\`
|
|
170
172
|
|
|
171
173
|
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.
|
|
@@ -276,6 +278,21 @@ ${INDENT_MAIN}${dim("specs")} ${dim(`(${specFiles.length})`)}`
|
|
|
276
278
|
}
|
|
277
279
|
printLine();
|
|
278
280
|
});
|
|
281
|
+
program.command("validate").description("Validate .vercel/output/ conforms to Build Output API v3").action(() => {
|
|
282
|
+
const workDir = path.resolve(program.opts().dir);
|
|
283
|
+
const result = validateBuildOutput(workDir);
|
|
284
|
+
if (result.valid) {
|
|
285
|
+
printSuccess("Build output is valid");
|
|
286
|
+
printLine();
|
|
287
|
+
process.exit(0);
|
|
288
|
+
}
|
|
289
|
+
printError("Build output validation failed:");
|
|
290
|
+
for (const error of result.errors) {
|
|
291
|
+
printListItem(error);
|
|
292
|
+
}
|
|
293
|
+
printLine();
|
|
294
|
+
process.exit(1);
|
|
295
|
+
});
|
|
279
296
|
program.command("models").description("List available models and check provider auth").action(async () => {
|
|
280
297
|
printTitle("models");
|
|
281
298
|
printStep("Starting OpenCode...");
|
|
@@ -449,12 +466,67 @@ ${INDENT_MAIN}${red("\u2717")} Timeout after ${formatTime(elapsed)}
|
|
|
449
466
|
printLine(
|
|
450
467
|
`${INDENT_MAIN}${cyan(`[${iteration}]`)} ${green("\u2713")} Done ${dim(`(${formatTime(iterElapsed)})`)}`
|
|
451
468
|
);
|
|
452
|
-
|
|
453
|
-
|
|
469
|
+
let validation = validateBuildOutput(workDir);
|
|
470
|
+
if (validation.valid) {
|
|
471
|
+
printSuccess("Build output validated");
|
|
472
|
+
printLine(
|
|
473
|
+
`
|
|
454
474
|
${INDENT_MAIN}${green("\u2713")} Completed in ${bold(String(iteration))} iteration(s) ${dim(`(${formatTime(Date.now() - startTime)})`)}
|
|
455
475
|
`
|
|
456
|
-
|
|
457
|
-
|
|
476
|
+
);
|
|
477
|
+
process.exit(0);
|
|
478
|
+
}
|
|
479
|
+
const MAX_REMEDIATION_ATTEMPTS = 3;
|
|
480
|
+
for (let attempt = 1; attempt <= MAX_REMEDIATION_ATTEMPTS; attempt++) {
|
|
481
|
+
const remElapsed = Date.now() - startTime;
|
|
482
|
+
if (remElapsed >= timeout) {
|
|
483
|
+
printError(
|
|
484
|
+
`Timeout during remediation after ${formatTime(remElapsed)}`
|
|
485
|
+
);
|
|
486
|
+
printLine();
|
|
487
|
+
process.exit(1);
|
|
488
|
+
}
|
|
489
|
+
printError("Build output validation failed:");
|
|
490
|
+
for (const error of validation.errors) {
|
|
491
|
+
printListItem(error);
|
|
492
|
+
}
|
|
493
|
+
printLine(
|
|
494
|
+
`${INDENT_MAIN}${cyan(`[remediate ${attempt}/${MAX_REMEDIATION_ATTEMPTS}]`)} Running remediation session...`
|
|
495
|
+
);
|
|
496
|
+
const remediationMessage = [
|
|
497
|
+
"Build output validation failed:",
|
|
498
|
+
...validation.errors.map((e) => `- ${e}`),
|
|
499
|
+
"",
|
|
500
|
+
"Produce .vercel/output/ conforming to Build Output API v3.",
|
|
501
|
+
"Run `dream validate` to verify before signaling completion."
|
|
502
|
+
].join("\n");
|
|
503
|
+
await runSession(
|
|
504
|
+
client,
|
|
505
|
+
title,
|
|
506
|
+
`${effectivePrompt}
|
|
507
|
+
|
|
508
|
+
## Remediation
|
|
509
|
+
|
|
510
|
+
${remediationMessage}`,
|
|
511
|
+
verbose
|
|
512
|
+
);
|
|
513
|
+
validation = validateBuildOutput(workDir);
|
|
514
|
+
if (validation.valid) {
|
|
515
|
+
printSuccess("Build output validated after remediation");
|
|
516
|
+
printLine(
|
|
517
|
+
`
|
|
518
|
+
${INDENT_MAIN}${green("\u2713")} Completed in ${bold(String(iteration))} iteration(s) ${dim(`(${formatTime(Date.now() - startTime)})`)}
|
|
519
|
+
`
|
|
520
|
+
);
|
|
521
|
+
process.exit(0);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
printError("Build output validation failed after remediation");
|
|
525
|
+
for (const error of validation.errors) {
|
|
526
|
+
printListItem(error);
|
|
527
|
+
}
|
|
528
|
+
printLine();
|
|
529
|
+
process.exit(1);
|
|
458
530
|
}
|
|
459
531
|
if (result === "error") {
|
|
460
532
|
printLine(
|
|
@@ -684,6 +756,35 @@ function toolContext(tool, input) {
|
|
|
684
756
|
return void 0;
|
|
685
757
|
}
|
|
686
758
|
}
|
|
759
|
+
function validateBuildOutput(workDir) {
|
|
760
|
+
const errors = [];
|
|
761
|
+
const outputDir = path.join(workDir, ".vercel", "output");
|
|
762
|
+
const configPath = path.join(outputDir, "config.json");
|
|
763
|
+
if (!fs.existsSync(configPath)) {
|
|
764
|
+
errors.push(".vercel/output/config.json does not exist");
|
|
765
|
+
} else {
|
|
766
|
+
try {
|
|
767
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
768
|
+
if (config.version !== 3) {
|
|
769
|
+
errors.push(
|
|
770
|
+
`.vercel/output/config.json has version ${config.version}, expected 3`
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
} catch {
|
|
774
|
+
errors.push(".vercel/output/config.json is not valid JSON");
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
const staticDir = path.join(outputDir, "static");
|
|
778
|
+
const functionsDir = path.join(outputDir, "functions");
|
|
779
|
+
const hasStatic = fs.existsSync(staticDir) && fs.readdirSync(staticDir).length > 0;
|
|
780
|
+
const hasFunctions = fs.existsSync(functionsDir) && fs.readdirSync(functionsDir).length > 0;
|
|
781
|
+
if (!hasStatic && !hasFunctions) {
|
|
782
|
+
errors.push(
|
|
783
|
+
".vercel/output/ must contain a non-empty static/ or functions/ directory"
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
return { valid: errors.length === 0, errors };
|
|
787
|
+
}
|
|
687
788
|
function loadProjectPrompt(specsDir) {
|
|
688
789
|
for (const file of PROJECT_PROMPT_FILES) {
|
|
689
790
|
const fullPath = path.join(specsDir, file);
|