@vendian/cli 0.0.26 → 0.0.28

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
@@ -8,6 +8,7 @@ vendian
8
8
  vendian login
9
9
  vendian init --output-dir ./agents
10
10
  vendian create "My Agent" --output-dir ./agents
11
+ vendian cloud local run --collection-id YOUR_COLLECTION --path ./agents/my-agent --input-json '{}'
11
12
  vendian cloud local serve --agents-dir ./agents
12
13
  ```
13
14
 
@@ -23,11 +24,13 @@ vendian create "My Agent" --output-dir ./agents
23
24
  vendian validate ./agents/my-agent --runtime
24
25
  vendian test ./agents/my-agent --dry-run --mock-credentials
25
26
  vendian models
27
+ vendian cloud local run --collection-id YOUR_COLLECTION --path ./agents/my-agent --input-json '{}'
26
28
  vendian cloud local serve --agents-dir ./agents
27
29
  ```
28
30
 
29
31
  Run `vendian` with no arguments to open the interactive menu. It shows your
30
- current endpoint connections and guides common local workflows.
32
+ current endpoint connections and guides common local workflows, including
33
+ running one local agent immediately or starting the long-lived local daemon.
31
34
 
32
35
  `vendian login` opens a browser sign-in, prepares the local runtime, and stores
33
36
  the credentials needed by the CLI for the selected endpoint. `vendian setup` is
package/cli-wrapper.mjs CHANGED
@@ -1107,7 +1107,7 @@ import path8 from "node:path";
1107
1107
  import readlinePromises from "node:readline/promises";
1108
1108
 
1109
1109
  // src/version.js
1110
- var CLI_VERSION = true ? "0.0.26" : process.env.npm_package_version || "0.0.0-dev";
1110
+ var CLI_VERSION = true ? "0.0.28" : process.env.npm_package_version || "0.0.0-dev";
1111
1111
 
1112
1112
  // src/npm-update.js
1113
1113
  var NPM_CHECK_INTERVAL_MS = 30 * 60 * 1e3;
@@ -2412,12 +2412,12 @@ async function runTui({
2412
2412
  await refreshInteractiveManagedRuntime({ env, platform, output });
2413
2413
  await loadTerm();
2414
2414
  term.fullscreen(true);
2415
- term.hideCursor();
2415
+ setCursorVisible(false);
2416
2416
  term.grabInput({ mouse: "motion" });
2417
2417
  const cleanup = () => {
2418
2418
  try {
2419
2419
  term.grabInput(false);
2420
- term.showCursor();
2420
+ setCursorVisible(true);
2421
2421
  term.fullscreen(false);
2422
2422
  } catch {
2423
2423
  }
@@ -2451,6 +2451,9 @@ async function mainLoop({ env, platform }) {
2451
2451
  while (true) {
2452
2452
  let next;
2453
2453
  switch (screen) {
2454
+ case "run":
2455
+ next = await showRun({ env, platform });
2456
+ break;
2454
2457
  case "home":
2455
2458
  next = await showHome({ env, platform });
2456
2459
  break;
@@ -2532,6 +2535,7 @@ var HOME_ACTIONS = [
2532
2535
  { value: "connect", label: "Sign in", desc: "Connect to a different account or environment" },
2533
2536
  { value: "create", label: "Create Agent", desc: "Build a new agent from a template" },
2534
2537
  { value: "commands", label: "Commands", desc: "Show all available CLI commands" },
2538
+ { value: "run", label: "Run once", desc: "Execute one local agent immediately" },
2535
2539
  { value: "exit", label: "Exit", desc: "" }
2536
2540
  ];
2537
2541
  async function showHome({ env, platform }) {
@@ -2588,17 +2592,10 @@ async function showConnect({ env, platform }) {
2588
2592
  }
2589
2593
  const ep = ENDPOINTS[resp.selectedIndex];
2590
2594
  term("\n");
2591
- term.gray(` Connecting to ${ep.label}\u2026
2592
- `);
2593
- try {
2594
- await switchOrLoginEndpoint({ backend: ep.key, env, platform });
2595
- term.green(` ${fig.check} Signed in to ${ep.label} successfully
2596
- `);
2597
- } catch (error) {
2598
- term.red(` ${endpointErrorStatus(error)}
2599
- `);
2595
+ const outcome = await connectEndpointInteractive({ backend: ep.key, label: ep.label, env, platform });
2596
+ if (outcome.promptedInTui) {
2597
+ await pressEnterToContinue();
2600
2598
  }
2601
- await pressEnterToContinue({ grabActive: false });
2602
2599
  }
2603
2600
  }
2604
2601
  async function connectCustomUrl({ env, platform }) {
@@ -2611,15 +2608,10 @@ async function connectCustomUrl({ env, platform }) {
2611
2608
  if (!url) return;
2612
2609
  term("\n\n");
2613
2610
  term.gray(" Connecting\u2026\n");
2614
- try {
2615
- await switchOrLoginEndpoint({ apiUrl: url, env, platform });
2616
- term.green(` ${fig.check} Connected successfully
2617
- `);
2618
- } catch (error) {
2619
- term.red(` ${endpointErrorStatus(error)}
2620
- `);
2611
+ const outcome = await connectEndpointInteractive({ apiUrl: url, label: url, env, platform, successLabel: "Connected successfully" });
2612
+ if (outcome.promptedInTui) {
2613
+ await pressEnterToContinue();
2621
2614
  }
2622
- await pressEnterToContinue({ grabActive: false });
2623
2615
  }
2624
2616
  async function showCreate({ env, platform }) {
2625
2617
  term.clear();
@@ -2640,6 +2632,41 @@ async function showCreate({ env, platform }) {
2640
2632
  );
2641
2633
  return "home";
2642
2634
  }
2635
+ async function showRun({ env, platform }) {
2636
+ const candidates = findAgentDirectoryCandidates();
2637
+ const picked = await pickSingleAgentToRun({ env, platform, candidates });
2638
+ if (!picked) return "home";
2639
+ const workspace = await chooseCloudWorkspace({
2640
+ env,
2641
+ platform,
2642
+ loadingTitle: " Getting ready to run this agent\u2026",
2643
+ pickerTitle: " Which project should own this run?\n\n"
2644
+ });
2645
+ if (!workspace) return "home";
2646
+ term.clear();
2647
+ drawHeader({ env, platform });
2648
+ term("\n");
2649
+ term.bold(` Run ${picked.displayName}
2650
+
2651
+ `);
2652
+ term.gray(` Agent: ${picked.path}
2653
+ `);
2654
+ term.gray(` Project: ${workspace.label}
2655
+
2656
+ `);
2657
+ term.gray(" Input JSON: ");
2658
+ const inputJson = await term.inputField({ cancelable: true, style: term.cyan, default: "{}" }).promise;
2659
+ if (inputJson === null) return "home";
2660
+ await withOutputMode(
2661
+ `Running ${picked.displayName}`,
2662
+ () => forwardToPythonVendian(buildLocalRunArgs({
2663
+ agentPath: picked.path,
2664
+ collectionId: workspace.id,
2665
+ inputJson: inputJson || "{}"
2666
+ }), { env, platform })
2667
+ );
2668
+ return "home";
2669
+ }
2643
2670
  var COMMAND_GROUPS = [
2644
2671
  { section: "Getting started", commands: [
2645
2672
  { cmd: "vendian login", desc: "Sign in and set up your computer" },
@@ -2652,6 +2679,7 @@ var COMMAND_GROUPS = [
2652
2679
  { cmd: "vendian models", desc: "List available AI models" }
2653
2680
  ] },
2654
2681
  { section: "Running agents", commands: [
2682
+ { cmd: "vendian cloud local run --collection-id ID --path . --input-json '{}'", desc: "Run one local agent once" },
2655
2683
  { cmd: "vendian cloud local serve --agents-dir .", desc: "Start agents (advanced mode)" },
2656
2684
  { cmd: "vendian login --backend staging", desc: "Sign in to staging environment" }
2657
2685
  ] },
@@ -2692,57 +2720,14 @@ async function showServe({ env, platform }) {
2692
2720
  const picked = await pickAgentsToRun({ env, platform, candidates });
2693
2721
  if (!picked) return "home";
2694
2722
  const { agentsDir } = picked;
2695
- term.clear();
2696
- drawHeader({ env, platform });
2697
- term("\n");
2698
- term.bold(` Getting ready to run your agents\u2026
2699
-
2700
- `);
2701
- let wsResult;
2702
- try {
2703
- wsResult = await listCloudWorkspaces({
2704
- env,
2705
- platform,
2706
- onProgress: (msg) => {
2707
- term.moveTo(1, HEADER_ROWS_BASE + 3);
2708
- term.eraseLine();
2709
- term.gray(` ${clip(msg, 60)}
2710
- `);
2711
- }
2712
- });
2713
- } catch (error) {
2714
- term.red(`
2715
- Couldn't connect to the server: ${errMsg(error)}
2716
- `);
2717
- term.gray(" Make sure you are signed in (choose Sign in from the main menu).\n");
2718
- await pressEnterToContinue({ grabActive: false });
2719
- return "home";
2720
- }
2721
- if (!wsResult.ok) {
2722
- term.red(`
2723
- ${fig.cross} ${wsResult.error}
2724
- `);
2725
- await pressEnterToContinue({ grabActive: false });
2726
- return "home";
2727
- }
2728
- let collectionId = wsResult.workspaces[0]?.id || "";
2729
- if (wsResult.workspaces.length > 1) {
2730
- term.clear();
2731
- drawHeader({ env, platform });
2732
- term("\n");
2733
- term.bold(" Which project do you want to run?\n\n");
2734
- const wsItems = [...wsResult.workspaces.map((w) => workspaceLabel(w)), "\u2190 Back"];
2735
- const wsResp = await term.singleColumnMenu(wsItems, {
2736
- cancelable: true,
2737
- style: term.gray,
2738
- selectedStyle: term.bgCyan.black.bold,
2739
- leftPadding: " ",
2740
- selectedLeftPadding: " \u203A "
2741
- }).promise;
2742
- if (wsResp.canceled || wsResp.selectedIndex === wsItems.length - 1) return "home";
2743
- collectionId = wsResult.workspaces[wsResp.selectedIndex]?.id || "";
2744
- }
2745
- return await runServeDashboard({ env, platform, agentsDir, collectionId });
2723
+ const workspace = await chooseCloudWorkspace({
2724
+ env,
2725
+ platform,
2726
+ loadingTitle: " Getting ready to run your agents\u2026",
2727
+ pickerTitle: " Which project do you want to run?\n\n"
2728
+ });
2729
+ if (!workspace) return "home";
2730
+ return await runServeDashboard({ env, platform, agentsDir, collectionId: workspace.id });
2746
2731
  }
2747
2732
  async function pickAgentsToRun({ env, platform, candidates }) {
2748
2733
  if (candidates.length === 0) {
@@ -2816,6 +2801,107 @@ async function pickAgentsFromFolder({ env, platform, candidate }) {
2816
2801
  if (resp.selectedIndex === 0) return { agentsDir: candidate.path };
2817
2802
  return { agentsDir: named[resp.selectedIndex - 1].path };
2818
2803
  }
2804
+ async function pickSingleAgentToRun({ env, platform, candidates }) {
2805
+ if (candidates.length === 0) {
2806
+ term.clear();
2807
+ drawHeader({ env, platform });
2808
+ term("\n");
2809
+ term.bold(" I couldn't find any agents on your computer.\n\n");
2810
+ term.gray(" Enter the path to one agent folder:\n\n");
2811
+ term.gray(" Folder: ");
2812
+ const input = await term.inputField({ cancelable: true, style: term.cyan, default: "./agents/my-agent" }).promise;
2813
+ if (input === null) return null;
2814
+ const agentPath = input || "./agents/my-agent";
2815
+ return { path: agentPath, displayName: friendlyName(path8.basename(agentPath) || "Agent") };
2816
+ }
2817
+ const agents = candidates.flatMap((candidate) => {
2818
+ const folders = findAgentFolders(candidate.absolutePath);
2819
+ if (folders.length > 0) {
2820
+ return folders.map((folder) => ({
2821
+ path: folder.path,
2822
+ displayName: readManifestName(folder.absolutePath) || friendlyName(folder.name || path8.basename(folder.path))
2823
+ }));
2824
+ }
2825
+ return [{
2826
+ path: candidate.path,
2827
+ displayName: readManifestName(candidate.absolutePath) || friendlyName(path8.basename(candidate.absolutePath) || candidate.path)
2828
+ }];
2829
+ });
2830
+ if (agents.length === 1) return agents[0];
2831
+ term.clear();
2832
+ drawHeader({ env, platform });
2833
+ term("\n");
2834
+ term.bold(" Which agent do you want to run now?\n\n");
2835
+ const items = [...agents.map((agent) => `${agent.displayName.padEnd(32)} ${agent.path}`), "\u2190 Back"];
2836
+ const resp = await term.singleColumnMenu(items, {
2837
+ cancelable: true,
2838
+ style: term.gray,
2839
+ selectedStyle: term.bgCyan.black.bold,
2840
+ leftPadding: " ",
2841
+ selectedLeftPadding: " \u203A "
2842
+ }).promise;
2843
+ if (resp.canceled || resp.selectedIndex === items.length - 1) return null;
2844
+ return agents[resp.selectedIndex];
2845
+ }
2846
+ async function chooseCloudWorkspace({
2847
+ env,
2848
+ platform,
2849
+ loadingTitle,
2850
+ pickerTitle
2851
+ } = {}) {
2852
+ term.clear();
2853
+ drawHeader({ env, platform });
2854
+ term("\n");
2855
+ term.bold(`${loadingTitle}
2856
+
2857
+ `);
2858
+ let wsResult;
2859
+ try {
2860
+ wsResult = await listCloudWorkspaces({
2861
+ env,
2862
+ platform,
2863
+ onProgress: (msg) => {
2864
+ term.moveTo(1, HEADER_ROWS_BASE + 3);
2865
+ term.eraseLine();
2866
+ term.gray(` ${clip(msg, 60)}
2867
+ `);
2868
+ }
2869
+ });
2870
+ } catch (error) {
2871
+ term.red(`
2872
+ Couldn't connect to the server: ${errMsg(error)}
2873
+ `);
2874
+ term.gray(" Make sure you are signed in (choose Sign in from the main menu).\n");
2875
+ await pressEnterToContinue({ grabActive: false });
2876
+ return null;
2877
+ }
2878
+ if (!wsResult.ok) {
2879
+ term.red(`
2880
+ ${fig.cross} ${wsResult.error}
2881
+ `);
2882
+ await pressEnterToContinue({ grabActive: false });
2883
+ return null;
2884
+ }
2885
+ if (wsResult.workspaces.length <= 1) {
2886
+ const workspace2 = wsResult.workspaces[0];
2887
+ return workspace2 ? { id: workspace2.id || "", label: workspaceLabel(workspace2) } : null;
2888
+ }
2889
+ term.clear();
2890
+ drawHeader({ env, platform });
2891
+ term("\n");
2892
+ term.bold(pickerTitle);
2893
+ const wsItems = [...wsResult.workspaces.map((w) => workspaceLabel(w)), "\u2190 Back"];
2894
+ const wsResp = await term.singleColumnMenu(wsItems, {
2895
+ cancelable: true,
2896
+ style: term.gray,
2897
+ selectedStyle: term.bgCyan.black.bold,
2898
+ leftPadding: " ",
2899
+ selectedLeftPadding: " \u203A "
2900
+ }).promise;
2901
+ if (wsResp.canceled || wsResp.selectedIndex === wsItems.length - 1) return null;
2902
+ const workspace = wsResult.workspaces[wsResp.selectedIndex];
2903
+ return { id: workspace?.id || "", label: workspaceLabel(workspace) };
2904
+ }
2819
2905
  async function runServeDashboard({ env, platform, agentsDir, collectionId }) {
2820
2906
  let state = initialServeState();
2821
2907
  let child = null;
@@ -3362,7 +3448,7 @@ function attachServeChild(child, onUpdate, onExit, logStore = null) {
3362
3448
  }
3363
3449
  async function withOutputMode(label, fn) {
3364
3450
  term.fullscreen(false);
3365
- term.showCursor();
3451
+ setCursorVisible(true);
3366
3452
  term.grabInput(false);
3367
3453
  process.stdout.write(`
3368
3454
  ${label}
@@ -3378,7 +3464,7 @@ async function withOutputMode(label, fn) {
3378
3464
  }
3379
3465
  await pressEnterToContinue({ grabActive: false });
3380
3466
  term.fullscreen(true);
3381
- term.hideCursor();
3467
+ setCursorVisible(false);
3382
3468
  term.grabInput({ mouse: "motion" });
3383
3469
  }
3384
3470
  function waitForKey(keys = null) {
@@ -3392,6 +3478,19 @@ function waitForKey(keys = null) {
3392
3478
  term.on("key", handler);
3393
3479
  });
3394
3480
  }
3481
+ function setCursorVisible(visible) {
3482
+ if (typeof term?.hideCursor === "function") {
3483
+ term.hideCursor(!visible);
3484
+ return;
3485
+ }
3486
+ if (visible && typeof term?.showCursor === "function") {
3487
+ term.showCursor();
3488
+ return;
3489
+ }
3490
+ if (!visible && typeof term?.hideCursor === "function") {
3491
+ term.hideCursor();
3492
+ }
3493
+ }
3395
3494
  async function pressEnterToContinue({ grabActive = true } = {}) {
3396
3495
  if (grabActive) {
3397
3496
  term("\n Press any key to continue\u2026");
@@ -3477,10 +3576,57 @@ async function switchOrLoginEndpoint({
3477
3576
  await setupFn({ backend, apiUrl, forceAuth: true, env, platform });
3478
3577
  return { apiUrl: status.apiUrl, reused: false, activated: true };
3479
3578
  }
3579
+ async function connectEndpointInteractive({
3580
+ backend,
3581
+ apiUrl,
3582
+ label,
3583
+ env = process.env,
3584
+ platform = process.platform,
3585
+ setupFn = setup,
3586
+ activateFn = activateCloudProfile,
3587
+ successLabel
3588
+ } = {}) {
3589
+ const status = cloudAuthStatus({ backend, apiUrl, env, platform });
3590
+ const destination = label || envLabel(status.apiUrl);
3591
+ if (status.authenticated) {
3592
+ term.gray(` Connecting to ${destination}\u2026
3593
+ `);
3594
+ try {
3595
+ await switchOrLoginEndpoint({ backend, apiUrl, env, platform, setupFn, activateFn });
3596
+ term.green(` ${fig.check} ${successLabel || `Signed in to ${destination} successfully`}
3597
+ `);
3598
+ } catch (error) {
3599
+ term.red(` ${endpointErrorStatus(error)}
3600
+ `);
3601
+ }
3602
+ return { promptedInTui: true };
3603
+ }
3604
+ await withOutputMode(`Connecting to ${destination}`, async () => {
3605
+ await switchOrLoginEndpoint({ backend, apiUrl, env, platform, setupFn, activateFn });
3606
+ });
3607
+ return { promptedInTui: false };
3608
+ }
3480
3609
  function endpointErrorStatus(error) {
3481
3610
  const message = error && typeof error.message === "string" ? error.message : String(error || "Connection failed");
3482
3611
  return `${fig.cross} ${message}`;
3483
3612
  }
3613
+ function buildLocalRunArgs({
3614
+ agentPath = ".",
3615
+ collectionId = "",
3616
+ inputJson = "{}"
3617
+ } = {}) {
3618
+ return [
3619
+ "cloud",
3620
+ "local",
3621
+ "run",
3622
+ "--collection-id",
3623
+ collectionId,
3624
+ "--path",
3625
+ agentPath || ".",
3626
+ "--input-json",
3627
+ inputJson || "{}"
3628
+ ];
3629
+ }
3484
3630
  function runtimeSummary({ env = process.env, platform = process.platform, now = Date.now() } = {}) {
3485
3631
  const config = loadConfig(env, platform);
3486
3632
  const venvPath = managedVenvPath(env, platform);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vendian/cli",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
4
4
  "description": "Public Vendian CLI bootstrapper and launcher",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,