unitbob 0.2.1 → 0.2.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/dist/verbs/suitePrepare.js +24 -6
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { materializeHelper } from "../files/guardrails.js";
|
|
4
4
|
import { recipeNameFor, writeSuiteBuildRequest } from "../files/suiteBuild.js";
|
|
5
5
|
import { anyStackPrecheck } from "../runner/precheck.js";
|
|
6
|
+
import { ensureRunner } from "../runner/provision.js";
|
|
6
7
|
import { Wire } from "../wire.js";
|
|
7
8
|
// Confirm at least one supported stack is present, materialize the Ruby boot
|
|
8
9
|
// helper a generated RSpec suite would require, then fetch both peer assignments
|
|
@@ -18,7 +19,7 @@ export async function suitePrepare(config, _args = [], deps) {
|
|
|
18
19
|
getRecipe: (name) => wire.getRecipe(name),
|
|
19
20
|
getSuitePacketsBatch: () => wire.getSuitePacketsBatch(),
|
|
20
21
|
precheck: anyStackPrecheck,
|
|
21
|
-
ensureRunner: deps?.ensureRunner ??
|
|
22
|
+
ensureRunner: deps?.ensureRunner ?? ensureRunner,
|
|
22
23
|
stdout: process.stdout,
|
|
23
24
|
...deps,
|
|
24
25
|
};
|
|
@@ -27,18 +28,27 @@ export async function suitePrepare(config, _args = [], deps) {
|
|
|
27
28
|
throw new Error(check.message ?? 'Unsupported runtime.');
|
|
28
29
|
materializeHelper(config.projectRoot);
|
|
29
30
|
const packets = await actual.getSuitePacketsBatch();
|
|
30
|
-
// Spec 32-1: Zero-touch sidecar provision for behavioral BDD runners during build preflight
|
|
31
|
+
// Spec 32-1: Zero-touch sidecar provision for behavioral BDD runners during build preflight.
|
|
32
|
+
// A `fixable` outcome (no package manager available to install the runner) is an infrastructure
|
|
33
|
+
// blocker the vibecoder clears with one command. Per the spec it must NOT surface as a
|
|
34
|
+
// build_error dead-end, must NOT abort the build, and must NOT block the structural peer. So we
|
|
35
|
+
// drop only the unprovisioned behavioral branch from this run, keep everything else buildable,
|
|
36
|
+
// and print a fixable checklist after the request is written.
|
|
37
|
+
const fixableNotices = [];
|
|
38
|
+
const buildable = [];
|
|
31
39
|
for (const packet of packets) {
|
|
32
40
|
const runner = packet.runner ?? (packet.suite_kind === 'behavioral' ? inferBddRunner(config.projectRoot) : undefined);
|
|
33
41
|
if (runner && (packet.suite_kind === 'behavioral' || ['cucumber', 'cucumber-js', 'pytest-bdd'].includes(runner))) {
|
|
34
42
|
const prov = await actual.ensureRunner(config.projectRoot, runner);
|
|
35
43
|
if (prov.status === 'fixable') {
|
|
36
|
-
const
|
|
37
|
-
|
|
44
|
+
const steps = prov.checklist?.length ? `\n - ${prov.checklist.join('\n - ')}` : '';
|
|
45
|
+
fixableNotices.push(` Behavioral runner "${runner}" not installed: ${prov.message ?? ''}${steps}`);
|
|
46
|
+
continue;
|
|
38
47
|
}
|
|
39
48
|
}
|
|
49
|
+
buildable.push(packet);
|
|
40
50
|
}
|
|
41
|
-
const branches = await Promise.all(
|
|
51
|
+
const branches = await Promise.all(buildable.map(async (packet) => ({
|
|
42
52
|
suite_kind: packet.suite_kind,
|
|
43
53
|
source_digest: packet.source_digest,
|
|
44
54
|
path_root: packet.path_root,
|
|
@@ -48,9 +58,17 @@ export async function suitePrepare(config, _args = [], deps) {
|
|
|
48
58
|
const request = writeSuiteBuildRequest(config.projectRoot, branches);
|
|
49
59
|
const kinds = branches.map((branch) => branch.suite_kind).join(' and ');
|
|
50
60
|
actual.stdout.write(`Suite build request written to ${request.project_root}/.unitbob/suite-build/request.json\n`);
|
|
51
|
-
actual.stdout.write(`Next: build both peer suites (${kinds}) following each branch's \`recipe\` and \`assignment\`, ` +
|
|
61
|
+
actual.stdout.write(`Next: build ${branches.length === 1 ? 'the' : 'both'} peer ${branches.length === 1 ? 'suite' : 'suites'} (${kinds}) following each branch's \`recipe\` and \`assignment\`, ` +
|
|
52
62
|
`write your answer to ${request.output_path} as a branches array, run each locally to green, ` +
|
|
53
63
|
'then run `unitbob put-suite-build`.\n');
|
|
64
|
+
// A fixable runner blocker is not a failure: the structural suite still builds this run. Tell the
|
|
65
|
+
// vibecoder the one command that unblocks the behavioral peer, then re-run suite-prepare.
|
|
66
|
+
if (fixableNotices.length > 0) {
|
|
67
|
+
actual.stdout.write('\nBehavioral suite skipped this run — its BDD runner is not installed yet. ' +
|
|
68
|
+
'This is a fixable setup step, not a build failure, and it does not affect the structural suite:\n' +
|
|
69
|
+
fixableNotices.join('\n') +
|
|
70
|
+
'\nFix the above, then re-run `unitbob suite-prepare` to build the behavioral peer.\n');
|
|
71
|
+
}
|
|
54
72
|
}
|
|
55
73
|
function inferBddRunner(projectRoot) {
|
|
56
74
|
if (existsSync(join(projectRoot, 'package.json')))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unitbob",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Unitbob connector — thin local hands for the Unitbob Rails brain. Owns no domain logic: it runs tools, relays bytes over the wire, and prints what the server returns.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|