@nexusbloom/cli 0.9.0 → 0.9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexusbloom/cli",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "NexusBloom CLI — run tools and workflows from your terminal",
5
5
  "type": "module",
6
6
  "bin": {
package/src/pipe.js CHANGED
@@ -135,7 +135,7 @@ function tokenize(spec) {
135
135
  * @returns {{kind:"stdin"|"connection"|"literal", headPath?: string,
136
136
  * accessors?: Array, chain?: Array, literal?: any}}
137
137
  */
138
- function parseValueExpr(expr) {
138
+ export function parseValueExpr(expr) {
139
139
  const raw = String(expr ?? "");
140
140
 
141
141
  if (raw === "@in" || raw === "@stdin") return { kind: "stdin" };
package/src/wizard.js CHANGED
@@ -33,7 +33,8 @@ import { execInSandbox } from "./sandbox.js";
33
33
  import { configGet } from "./tools.js";
34
34
  import { runRemote } from "./run.js";
35
35
  import { inferType, schemaTypes, typeLabel, compatibility } from "./types.js";
36
- import { formatPath, parsePath, preview, transformNames } from "./values.js";
36
+ import { formatPath, parsePath, preview, transformNames, MISSING } from "./values.js";
37
+ import { parseValueExpr, resolveAccessors } from "./pipe.js";
37
38
  import { isInteractive } from "./ui.js";
38
39
  import { renderHeader } from "./ui.js";
39
40
 
@@ -283,7 +284,10 @@ export async function buildWizard(opts = {}) {
283
284
 
284
285
  console.log(chalk.gray(`\n Running ${spec}\n`));
285
286
  const started = Date.now();
286
- const result = await execute(tool.slug, literalInput(assignments));
287
+ const result = await execute(
288
+ tool.slug,
289
+ literalInput(assignments, outputs.length ? outputs[outputs.length - 1].value : undefined)
290
+ );
287
291
 
288
292
  if (!result.ok) {
289
293
  console.log(chalk.red(` ✗ ${result.error}`));
@@ -328,15 +332,51 @@ export async function buildWizard(opts = {}) {
328
332
  return { ok: true, spec: pipeline };
329
333
  }
330
334
 
331
- /** Build the input object for the trial run from literal assignments. */
332
- function literalInput(assignments) {
335
+ /**
336
+ * Build the input object for a step's trial run.
337
+ *
338
+ * Wired fields (`$path`, `$path|transform`) are resolved against the previous
339
+ * step's real output, using the *same* parser and resolver the pipeline engine
340
+ * uses at run time. That matters twice over:
341
+ *
342
+ * - correctness: a step whose required input is wired previously ran with that
343
+ * input simply absent, so `password-generator → base64-tool` failed with
344
+ * "text must be a non-empty string" no matter what the user chose;
345
+ * - consistency: the trial the wizard shows is the run the replay command
346
+ * will later reproduce, because both go through `parseValueExpr` +
347
+ * `resolveAccessors` rather than a second, drifting implementation.
348
+ *
349
+ * A reference that resolves to nothing is omitted rather than passed as
350
+ * `undefined`, so schema validation reports the field by name.
351
+ */
352
+ function literalInput(assignments, upstream) {
333
353
  const input = {};
334
354
  for (const a of assignments) {
335
355
  const eq = a.text.indexOf("=");
336
356
  if (eq === -1) continue;
337
357
  const key = a.text.slice(0, eq);
338
358
  const raw = a.text.slice(eq + 1);
339
- if (raw.startsWith("$")) continue; // wired fields are not needed for a first run
359
+
360
+ if (raw.startsWith("$")) {
361
+ if (upstream === undefined) continue;
362
+ let expr;
363
+ try {
364
+ expr = parseValueExpr(raw);
365
+ } catch {
366
+ continue;
367
+ }
368
+ if (expr.kind !== "connection" || !expr.accessors) continue;
369
+ let value;
370
+ try {
371
+ value = resolveAccessors(upstream, expr.accessors);
372
+ } catch {
373
+ continue;
374
+ }
375
+ if (value === MISSING || value === undefined) continue;
376
+ input[key] = value;
377
+ continue;
378
+ }
379
+
340
380
  try {
341
381
  input[key] = JSON.parse(raw);
342
382
  } catch {