@vendian/cli 0.0.6 → 0.0.7
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 +14 -0
- package/bin/vendian.cjs +0 -0
- package/cli-wrapper.cjs +336 -109
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,6 +6,8 @@ Command-line tools for signing in to Vendian and running local agent workflows.
|
|
|
6
6
|
npm install -g @vendian/cli
|
|
7
7
|
vendian
|
|
8
8
|
vendian login
|
|
9
|
+
vendian init --output-dir ./agents
|
|
10
|
+
vendian create "My Agent" --output-dir ./agents
|
|
9
11
|
vendian cloud local serve --agents-dir ./agents
|
|
10
12
|
```
|
|
11
13
|
|
|
@@ -16,6 +18,11 @@ vendian
|
|
|
16
18
|
vendian login
|
|
17
19
|
vendian doctor
|
|
18
20
|
vendian update
|
|
21
|
+
vendian init --output-dir ./agents
|
|
22
|
+
vendian create "My Agent" --output-dir ./agents
|
|
23
|
+
vendian validate ./agents/my-agent --runtime
|
|
24
|
+
vendian test ./agents/my-agent --dry-run --mock-credentials
|
|
25
|
+
vendian models
|
|
19
26
|
vendian cloud local serve --agents-dir ./agents
|
|
20
27
|
```
|
|
21
28
|
|
|
@@ -32,6 +39,13 @@ managed runtime without changing your agents.
|
|
|
32
39
|
After login, regular `vendian cloud ...` commands are forwarded to the managed
|
|
33
40
|
runtime installed by the CLI.
|
|
34
41
|
|
|
42
|
+
Agent authoring commands are also forwarded to the managed Python SDK CLI.
|
|
43
|
+
`vendian init` writes the current SDK-owned authoring docs into `.vendian-docs/`,
|
|
44
|
+
and `vendian create` scaffolds agents from the SDK templates. Updating the
|
|
45
|
+
managed runtime refreshes these docs and templates with the Python SDK. The CLI
|
|
46
|
+
remembers workspaces initialized with `vendian init` and refreshes their
|
|
47
|
+
`.vendian-docs/` automatically after `vendian update` or a managed auto-update.
|
|
48
|
+
|
|
35
49
|
## Local Data
|
|
36
50
|
|
|
37
51
|
Vendian stores its managed runtime and CLI state under your user profile:
|
package/bin/vendian.cjs
CHANGED
|
File without changes
|
package/cli-wrapper.cjs
CHANGED
|
@@ -52,15 +52,21 @@ var import_node_path = __toESM(require("node:path"), 1);
|
|
|
52
52
|
function pathApi(platform) {
|
|
53
53
|
return platform === "win32" ? import_node_path.default.win32 : import_node_path.default.posix;
|
|
54
54
|
}
|
|
55
|
+
function homeDir(env, platform) {
|
|
56
|
+
if (platform === "win32") {
|
|
57
|
+
return env.USERPROFILE || import_node_os.default.homedir();
|
|
58
|
+
}
|
|
59
|
+
return env.HOME || import_node_os.default.homedir();
|
|
60
|
+
}
|
|
55
61
|
function vendianHome(env = process.env, platform = process.platform) {
|
|
56
62
|
if (env.VENDIAN_CLI_HOME) {
|
|
57
63
|
return pathApi(platform).resolve(env.VENDIAN_CLI_HOME);
|
|
58
64
|
}
|
|
59
65
|
if (platform === "win32") {
|
|
60
|
-
const root = env.LOCALAPPDATA || import_node_path.default.join(
|
|
66
|
+
const root = env.LOCALAPPDATA || import_node_path.default.win32.join(homeDir(env, platform), "AppData", "Local");
|
|
61
67
|
return import_node_path.default.win32.join(root, "Vendian", "cli");
|
|
62
68
|
}
|
|
63
|
-
return import_node_path.default.posix.join(
|
|
69
|
+
return import_node_path.default.posix.join(homeDir(env, platform), ".vendian", "cli");
|
|
64
70
|
}
|
|
65
71
|
function configPath(env = process.env, platform = process.platform) {
|
|
66
72
|
if (env.VENDIAN_CLI_CONFIG) {
|
|
@@ -239,12 +245,10 @@ function run(command, args, options = {}) {
|
|
|
239
245
|
...options
|
|
240
246
|
});
|
|
241
247
|
}
|
|
242
|
-
function
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (platform === "darwin") {
|
|
247
|
-
const result = run("security", [
|
|
248
|
+
function buildMacKeychainSaveCommand(token) {
|
|
249
|
+
return [
|
|
250
|
+
"security",
|
|
251
|
+
[
|
|
248
252
|
"add-generic-password",
|
|
249
253
|
"-a",
|
|
250
254
|
PACKAGE_TOKEN_ACCOUNT,
|
|
@@ -253,7 +257,28 @@ function savePackageTokenSecret(token, config = {}, platform = process.platform)
|
|
|
253
257
|
"-w",
|
|
254
258
|
token,
|
|
255
259
|
"-U"
|
|
256
|
-
]
|
|
260
|
+
]
|
|
261
|
+
];
|
|
262
|
+
}
|
|
263
|
+
function buildMacKeychainLoadCommand() {
|
|
264
|
+
return [
|
|
265
|
+
"security",
|
|
266
|
+
[
|
|
267
|
+
"find-generic-password",
|
|
268
|
+
"-a",
|
|
269
|
+
PACKAGE_TOKEN_ACCOUNT,
|
|
270
|
+
"-s",
|
|
271
|
+
SERVICE,
|
|
272
|
+
"-w"
|
|
273
|
+
]
|
|
274
|
+
];
|
|
275
|
+
}
|
|
276
|
+
function savePackageTokenSecret(token, config = {}, platform = process.platform) {
|
|
277
|
+
if (!token) {
|
|
278
|
+
return { ok: false };
|
|
279
|
+
}
|
|
280
|
+
if (platform === "darwin") {
|
|
281
|
+
const result = run(...buildMacKeychainSaveCommand(token));
|
|
257
282
|
return { ok: result.status === 0, provider: "macos-keychain" };
|
|
258
283
|
}
|
|
259
284
|
if (platform === "win32") {
|
|
@@ -286,14 +311,7 @@ function savePackageTokenSecret(token, config = {}, platform = process.platform)
|
|
|
286
311
|
}
|
|
287
312
|
function loadPackageTokenSecret(config = {}, platform = process.platform) {
|
|
288
313
|
if (platform === "darwin") {
|
|
289
|
-
const result = run(
|
|
290
|
-
"find-generic-password",
|
|
291
|
-
"-a",
|
|
292
|
-
PACKAGE_TOKEN_ACCOUNT,
|
|
293
|
-
"-s",
|
|
294
|
-
SERVICE,
|
|
295
|
-
"-w"
|
|
296
|
-
]);
|
|
314
|
+
const result = run(...buildMacKeychainLoadCommand());
|
|
297
315
|
return result.status === 0 ? result.stdout.trim() : "";
|
|
298
316
|
}
|
|
299
317
|
if (platform === "win32") {
|
|
@@ -417,77 +435,96 @@ function doctor({ env = process.env, platform = process.platform } = {}) {
|
|
|
417
435
|
}
|
|
418
436
|
|
|
419
437
|
// src/forward.js
|
|
438
|
+
var import_node_fs8 = __toESM(require("node:fs"), 1);
|
|
439
|
+
|
|
440
|
+
// src/docs.js
|
|
420
441
|
var import_node_fs5 = __toESM(require("node:fs"), 1);
|
|
421
|
-
var
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
if (!import_node_fs5.default.existsSync(vendianPath)) {
|
|
426
|
-
throw new Error("Vendian is not set up yet. Run `vendian login` first.");
|
|
427
|
-
}
|
|
428
|
-
maybeAutoUpdateManagedEnv({ env, platform, venvPath });
|
|
429
|
-
const config = loadConfig(env, platform);
|
|
430
|
-
const code = await spawnForward(vendianPath, args, {
|
|
431
|
-
env: {
|
|
432
|
-
...env,
|
|
433
|
-
...packageIndexEnv(config, env, platform)
|
|
434
|
-
}
|
|
435
|
-
});
|
|
436
|
-
process.exitCode = code;
|
|
442
|
+
var import_node_path4 = __toESM(require("node:path"), 1);
|
|
443
|
+
var DOC_WORKSPACES_KEY = "agentDocWorkspaces";
|
|
444
|
+
function pathApi2(platform) {
|
|
445
|
+
return platform === "win32" ? import_node_path4.default.win32 : import_node_path4.default.posix;
|
|
437
446
|
}
|
|
438
|
-
function
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
447
|
+
function commandWritesAgentDocs(args = []) {
|
|
448
|
+
return args[0] === "init";
|
|
449
|
+
}
|
|
450
|
+
function initOutputDir(args = []) {
|
|
451
|
+
for (let index = 1; index < args.length; index += 1) {
|
|
452
|
+
const arg = args[index];
|
|
453
|
+
if (arg === "--output-dir" || arg === "-o") {
|
|
454
|
+
return args[index + 1] || ".";
|
|
455
|
+
}
|
|
456
|
+
if (arg.startsWith("--output-dir=")) {
|
|
457
|
+
return arg.slice("--output-dir=".length) || ".";
|
|
458
|
+
}
|
|
443
459
|
}
|
|
444
|
-
|
|
445
|
-
indexes.runtimeIndexUrl,
|
|
446
|
-
"https://pypi.org/simple",
|
|
447
|
-
env.VENDIAN_PIP_EXTRA_INDEX_URL
|
|
448
|
-
]);
|
|
449
|
-
const uvExtraIndexUrls = joinIndexUrls([
|
|
450
|
-
indexes.runtimeIndexUrl,
|
|
451
|
-
"https://pypi.org/simple",
|
|
452
|
-
env.VENDIAN_UV_EXTRA_INDEX_URL
|
|
453
|
-
]);
|
|
454
|
-
return {
|
|
455
|
-
VENDIAN_PIP_INDEX_URL: indexes.sdkIndexUrl,
|
|
456
|
-
VENDIAN_PIP_EXTRA_INDEX_URL: extraIndexUrls,
|
|
457
|
-
VENDIAN_UV_INDEX_URL: indexes.sdkIndexUrl,
|
|
458
|
-
VENDIAN_UV_EXTRA_INDEX_URL: uvExtraIndexUrls
|
|
459
|
-
};
|
|
460
|
+
return ".";
|
|
460
461
|
}
|
|
461
|
-
function
|
|
462
|
-
|
|
462
|
+
function resolveWorkspacePath(outputDir, { cwd = process.cwd(), platform = process.platform } = {}) {
|
|
463
|
+
const api = pathApi2(platform);
|
|
464
|
+
const raw = outputDir || ".";
|
|
465
|
+
return api.isAbsolute(raw) ? api.normalize(raw) : api.resolve(cwd, raw);
|
|
463
466
|
}
|
|
464
|
-
function
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
467
|
+
function recordAgentDocsWorkspace(outputDir, {
|
|
468
|
+
env = process.env,
|
|
469
|
+
platform = process.platform,
|
|
470
|
+
cwd = process.cwd(),
|
|
471
|
+
now = /* @__PURE__ */ new Date()
|
|
472
|
+
} = {}) {
|
|
473
|
+
const workspacePath = resolveWorkspacePath(outputDir, { cwd, platform });
|
|
468
474
|
const config = loadConfig(env, platform);
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
+
const existing = Array.isArray(config[DOC_WORKSPACES_KEY]) ? config[DOC_WORKSPACES_KEY] : [];
|
|
476
|
+
const workspaces = [workspacePath, ...existing.filter((entry) => entry !== workspacePath)];
|
|
477
|
+
const next = {
|
|
478
|
+
...config,
|
|
479
|
+
[DOC_WORKSPACES_KEY]: workspaces,
|
|
480
|
+
lastAgentDocsInitAt: now.toISOString()
|
|
481
|
+
};
|
|
482
|
+
saveConfig(next, env, platform);
|
|
483
|
+
return next;
|
|
484
|
+
}
|
|
485
|
+
function recordForwardedDocsCommand(args, code, options = {}) {
|
|
486
|
+
if (code !== 0 || !commandWritesAgentDocs(args)) {
|
|
475
487
|
return false;
|
|
476
488
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
489
|
+
recordAgentDocsWorkspace(initOutputDir(args), options);
|
|
490
|
+
return true;
|
|
491
|
+
}
|
|
492
|
+
function refreshAgentDocsWorkspaces({
|
|
493
|
+
config,
|
|
494
|
+
venvPath,
|
|
495
|
+
env = process.env,
|
|
496
|
+
platform = process.platform,
|
|
497
|
+
run: run2 = runInherit,
|
|
498
|
+
now = /* @__PURE__ */ new Date()
|
|
499
|
+
} = {}) {
|
|
500
|
+
const currentConfig = config || loadConfig(env, platform);
|
|
501
|
+
const workspaces = Array.isArray(currentConfig[DOC_WORKSPACES_KEY]) ? [...new Set(currentConfig[DOC_WORKSPACES_KEY].filter((entry) => typeof entry === "string" && entry.trim()))] : [];
|
|
502
|
+
if (workspaces.length === 0) {
|
|
503
|
+
saveConfig(currentConfig, env, platform);
|
|
504
|
+
return { config: currentConfig, refreshed: 0, failed: 0 };
|
|
480
505
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
506
|
+
const vendianPath = venvVendian(venvPath, platform);
|
|
507
|
+
let refreshed = 0;
|
|
508
|
+
let failed = 0;
|
|
509
|
+
for (const workspace of workspaces) {
|
|
510
|
+
if (!import_node_fs5.default.existsSync(workspace)) {
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
const status = run2(vendianPath, ["init", "--output-dir", workspace, "--yes"]);
|
|
514
|
+
if (status === 0) {
|
|
515
|
+
refreshed += 1;
|
|
516
|
+
} else {
|
|
517
|
+
failed += 1;
|
|
518
|
+
console.error(`[vendian] Could not refresh SDK docs in ${workspace}`);
|
|
519
|
+
}
|
|
490
520
|
}
|
|
521
|
+
const next = {
|
|
522
|
+
...currentConfig,
|
|
523
|
+
[DOC_WORKSPACES_KEY]: workspaces,
|
|
524
|
+
lastAgentDocsRefreshAt: now.toISOString()
|
|
525
|
+
};
|
|
526
|
+
saveConfig(next, env, platform);
|
|
527
|
+
return { config: next, refreshed, failed };
|
|
491
528
|
}
|
|
492
529
|
|
|
493
530
|
// src/setup.js
|
|
@@ -497,7 +534,7 @@ var import_node_fs7 = __toESM(require("node:fs"), 1);
|
|
|
497
534
|
var import_node_crypto = __toESM(require("node:crypto"), 1);
|
|
498
535
|
var import_node_http = __toESM(require("node:http"), 1);
|
|
499
536
|
var import_node_fs6 = __toESM(require("node:fs"), 1);
|
|
500
|
-
var
|
|
537
|
+
var import_node_path5 = __toESM(require("node:path"), 1);
|
|
501
538
|
var import_node_child_process3 = require("node:child_process");
|
|
502
539
|
var DEFAULT_OAUTH_REDIRECT_PORT = 8765;
|
|
503
540
|
function resolveApiUrl({ backend, apiUrl, env = process.env } = {}) {
|
|
@@ -541,6 +578,15 @@ async function loginWithVendianOAuth({ backend, apiUrl, noBrowser = false, env =
|
|
|
541
578
|
await callback.close();
|
|
542
579
|
}
|
|
543
580
|
}
|
|
581
|
+
async function fetchPackageCredentials({ apiUrl, accessToken }) {
|
|
582
|
+
if (!apiUrl || !accessToken) {
|
|
583
|
+
return void 0;
|
|
584
|
+
}
|
|
585
|
+
const payload = await getJson(`${String(apiUrl).replace(/\/$/, "")}/api/v1/cli/package-credentials`, {
|
|
586
|
+
Authorization: `Bearer ${accessToken}`
|
|
587
|
+
});
|
|
588
|
+
return payload.packageCredentials;
|
|
589
|
+
}
|
|
544
590
|
function loadCloudConfig(env = process.env, platform = process.platform) {
|
|
545
591
|
const file = cloudConfigPath(env, platform);
|
|
546
592
|
try {
|
|
@@ -565,6 +611,21 @@ function cloudAuthStatus({ backend, apiUrl, env = process.env, platform = proces
|
|
|
565
611
|
profiles
|
|
566
612
|
};
|
|
567
613
|
}
|
|
614
|
+
function activeCloudAuthStatus({ env = process.env, platform = process.platform } = {}) {
|
|
615
|
+
const config = loadCloudConfig(env, platform);
|
|
616
|
+
const profiles = config.profiles && typeof config.profiles === "object" ? config.profiles : {};
|
|
617
|
+
const apiUrl = typeof config.active_api_url === "string" ? config.active_api_url : void 0;
|
|
618
|
+
const profile = apiUrl ? profiles[apiUrl] : void 0;
|
|
619
|
+
return {
|
|
620
|
+
apiUrl,
|
|
621
|
+
activeApiUrl: apiUrl,
|
|
622
|
+
profile: profile && typeof profile === "object" ? profile : void 0,
|
|
623
|
+
authenticated: Boolean(profile?.access_token),
|
|
624
|
+
email: typeof profile?.email === "string" ? profile.email : void 0,
|
|
625
|
+
expiresAt: typeof profile?.expires_at === "string" ? profile.expires_at : void 0,
|
|
626
|
+
profiles
|
|
627
|
+
};
|
|
628
|
+
}
|
|
568
629
|
async function getOAuthConfig(apiUrl, redirectUri) {
|
|
569
630
|
const url = new URL(`${apiUrl}/api/v1/cli/auth/oauth/config`);
|
|
570
631
|
url.searchParams.set("redirectUri", redirectUri);
|
|
@@ -596,8 +657,8 @@ async function exchangeCodeForClerkToken(config, code, codeVerifier, redirectUri
|
|
|
596
657
|
}
|
|
597
658
|
return String(token);
|
|
598
659
|
}
|
|
599
|
-
async function getJson(url) {
|
|
600
|
-
const response = await fetch(url, { headers: { Accept: "application/json" } });
|
|
660
|
+
async function getJson(url, headers = {}) {
|
|
661
|
+
const response = await fetch(url, { headers: { Accept: "application/json", ...headers } });
|
|
601
662
|
return decodeResponse(response);
|
|
602
663
|
}
|
|
603
664
|
async function postJson(url, body) {
|
|
@@ -687,24 +748,30 @@ function openBrowser(url) {
|
|
|
687
748
|
return;
|
|
688
749
|
}
|
|
689
750
|
if (platform === "darwin") {
|
|
690
|
-
(0, import_node_child_process3.spawnSync)(
|
|
751
|
+
(0, import_node_child_process3.spawnSync)(...buildMacOpenCommand(url), { stdio: "ignore", shell: false });
|
|
691
752
|
return;
|
|
692
753
|
}
|
|
693
|
-
(0, import_node_child_process3.spawnSync)(
|
|
754
|
+
(0, import_node_child_process3.spawnSync)(...buildLinuxOpenCommand(url), { stdio: "ignore", shell: false });
|
|
694
755
|
}
|
|
695
756
|
function buildWindowsOpenCommand(url) {
|
|
696
757
|
return ["rundll32.exe", ["url.dll,FileProtocolHandler", String(url)]];
|
|
697
758
|
}
|
|
759
|
+
function buildMacOpenCommand(url) {
|
|
760
|
+
return ["open", [String(url)]];
|
|
761
|
+
}
|
|
762
|
+
function buildLinuxOpenCommand(url) {
|
|
763
|
+
return ["xdg-open", [String(url)]];
|
|
764
|
+
}
|
|
698
765
|
function cloudConfigPath(env = process.env, platform = process.platform) {
|
|
699
766
|
if (env.VENDIAN_CLOUD_CONFIG) {
|
|
700
|
-
return
|
|
767
|
+
return import_node_path5.default.resolve(env.VENDIAN_CLOUD_CONFIG);
|
|
701
768
|
}
|
|
702
769
|
if (platform === "win32") {
|
|
703
|
-
const root2 = env.APPDATA ||
|
|
704
|
-
return
|
|
770
|
+
const root2 = env.APPDATA || import_node_path5.default.join(process.env.USERPROFILE || "", "AppData", "Roaming");
|
|
771
|
+
return import_node_path5.default.win32.join(root2, "Vendian", "cloud-auth.json");
|
|
705
772
|
}
|
|
706
|
-
const root = env.XDG_CONFIG_HOME ||
|
|
707
|
-
return
|
|
773
|
+
const root = env.XDG_CONFIG_HOME || import_node_path5.default.join(process.env.HOME || "", ".config");
|
|
774
|
+
return import_node_path5.default.posix.join(root, "vendian", "cloud-auth.json");
|
|
708
775
|
}
|
|
709
776
|
function saveCloudToken(token, { env = process.env, platform = process.platform } = {}) {
|
|
710
777
|
const file = cloudConfigPath(env, platform);
|
|
@@ -726,7 +793,7 @@ function saveCloudToken(token, { env = process.env, platform = process.platform
|
|
|
726
793
|
scopes: token.scopes,
|
|
727
794
|
tooling_eligible: token.toolingEligible
|
|
728
795
|
};
|
|
729
|
-
import_node_fs6.default.mkdirSync(
|
|
796
|
+
import_node_fs6.default.mkdirSync(import_node_path5.default.dirname(file), { recursive: true });
|
|
730
797
|
import_node_fs6.default.writeFileSync(file, `${JSON.stringify(raw, null, 2)}
|
|
731
798
|
`, { encoding: "utf8", mode: 384 });
|
|
732
799
|
try {
|
|
@@ -771,24 +838,12 @@ async function setup({
|
|
|
771
838
|
throw new Error("Vendian login succeeded, but the backend did not return package credentials. Configure CLI_PACKAGE_REGISTRY_TOKEN on the backend.");
|
|
772
839
|
}
|
|
773
840
|
if (packageCredentials) {
|
|
774
|
-
next
|
|
775
|
-
next.gitlabUsername = packageCredentials.username || next.gitlabUsername;
|
|
776
|
-
next.sdkPublicProjectId = packageCredentials.sdkProjectId || next.sdkPublicProjectId;
|
|
777
|
-
next.sdkRuntimeProjectId = packageCredentials.runtimeProjectId || next.sdkRuntimeProjectId;
|
|
778
|
-
next.vendianAgentsVersion = packageCredentials.vendianAgentsVersion || next.vendianAgentsVersion;
|
|
779
|
-
next.vendianAgentsRuntimeVersion = packageCredentials.vendianAgentsRuntimeVersion || next.vendianAgentsRuntimeVersion;
|
|
780
|
-
const secret = savePackageTokenSecret(packageCredentials.token, next, platform);
|
|
781
|
-
if (secret.ok) {
|
|
782
|
-
Object.assign(next, secret.config || {});
|
|
783
|
-
delete next.gitlabToken;
|
|
784
|
-
console.log("Package access saved.");
|
|
785
|
-
} else {
|
|
786
|
-
next.gitlabToken = packageCredentials.token;
|
|
787
|
-
console.log("Package access saved in the local Vendian CLI config file.");
|
|
788
|
-
}
|
|
841
|
+
savePackageCredentials(next, packageCredentials, { platform });
|
|
789
842
|
}
|
|
790
843
|
} else if (auth.authenticated) {
|
|
791
844
|
console.log(`Cloud authentication already saved for ${auth.apiUrl}${auth.email ? ` (${auth.email})` : ""}.`);
|
|
845
|
+
const refreshed = await refreshPackageAccessFromCloudAuth({ config: next, auth, env, platform });
|
|
846
|
+
Object.assign(next, refreshed.config);
|
|
792
847
|
} else if (registry.token) {
|
|
793
848
|
if (registry.tokenSource !== "secret-store") {
|
|
794
849
|
next.gitlabToken = registry.token;
|
|
@@ -809,7 +864,8 @@ async function setup({
|
|
|
809
864
|
console.log(`Python: ${pythonVersion(pythonPath) || pythonPath}`);
|
|
810
865
|
saveConfig(next, env, platform);
|
|
811
866
|
installVendianPackages({ pythonPath, venvPath, config: next, env, platform });
|
|
812
|
-
|
|
867
|
+
const updated = { ...next, lastManagedUpdateAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
868
|
+
refreshAgentDocsWorkspaces({ config: updated, venvPath, env, platform });
|
|
813
869
|
if (!verifyVendianImports(pythonPath)) {
|
|
814
870
|
throw new Error("Vendian packages installed, but import verification failed.");
|
|
815
871
|
}
|
|
@@ -822,6 +878,57 @@ async function setup({
|
|
|
822
878
|
console.log(line);
|
|
823
879
|
}
|
|
824
880
|
}
|
|
881
|
+
function savePackageCredentials(config, packageCredentials, { platform = process.platform } = {}) {
|
|
882
|
+
if (!packageCredentials?.token) {
|
|
883
|
+
return false;
|
|
884
|
+
}
|
|
885
|
+
config.gitlabHost = packageCredentials.gitlabHost || config.gitlabHost;
|
|
886
|
+
config.gitlabUsername = packageCredentials.username || config.gitlabUsername;
|
|
887
|
+
config.sdkPublicProjectId = packageCredentials.sdkProjectId || config.sdkPublicProjectId;
|
|
888
|
+
config.sdkRuntimeProjectId = packageCredentials.runtimeProjectId || config.sdkRuntimeProjectId;
|
|
889
|
+
config.vendianAgentsVersion = packageCredentials.vendianAgentsVersion || config.vendianAgentsVersion;
|
|
890
|
+
config.vendianAgentsRuntimeVersion = packageCredentials.vendianAgentsRuntimeVersion || config.vendianAgentsRuntimeVersion;
|
|
891
|
+
const secret = savePackageTokenSecret(packageCredentials.token, config, platform);
|
|
892
|
+
if (secret.ok) {
|
|
893
|
+
Object.assign(config, secret.config || {});
|
|
894
|
+
delete config.gitlabToken;
|
|
895
|
+
console.log("Package access saved.");
|
|
896
|
+
} else {
|
|
897
|
+
config.gitlabToken = packageCredentials.token;
|
|
898
|
+
console.log("Package access saved in the local Vendian CLI config file.");
|
|
899
|
+
}
|
|
900
|
+
return true;
|
|
901
|
+
}
|
|
902
|
+
async function refreshPackageAccessFromCloudAuth({
|
|
903
|
+
config,
|
|
904
|
+
auth,
|
|
905
|
+
env = process.env,
|
|
906
|
+
platform = process.platform,
|
|
907
|
+
save = true
|
|
908
|
+
} = {}) {
|
|
909
|
+
const currentConfig = config || loadConfig(env, platform);
|
|
910
|
+
const registry = registryConfig(currentConfig, env, platform);
|
|
911
|
+
if (registry.token) {
|
|
912
|
+
return { config: currentConfig, refreshed: false };
|
|
913
|
+
}
|
|
914
|
+
const status = auth || activeCloudAuthStatus({ env, platform });
|
|
915
|
+
if (!status.authenticated || !status.apiUrl || !status.profile?.access_token) {
|
|
916
|
+
return { config: currentConfig, refreshed: false };
|
|
917
|
+
}
|
|
918
|
+
const packageCredentials = await fetchPackageCredentials({
|
|
919
|
+
apiUrl: status.apiUrl,
|
|
920
|
+
accessToken: status.profile.access_token
|
|
921
|
+
});
|
|
922
|
+
if (!packageCredentials?.token) {
|
|
923
|
+
return { config: currentConfig, refreshed: false };
|
|
924
|
+
}
|
|
925
|
+
const next = { ...currentConfig };
|
|
926
|
+
const stored = savePackageCredentials(next, packageCredentials, { platform });
|
|
927
|
+
if (stored && save) {
|
|
928
|
+
saveConfig(next, env, platform);
|
|
929
|
+
}
|
|
930
|
+
return { config: next, refreshed: stored };
|
|
931
|
+
}
|
|
825
932
|
function setupCompletionLines({ cloudAuthApiUrl, backend, apiUrl } = {}) {
|
|
826
933
|
const lines = ["Vendian login complete."];
|
|
827
934
|
if (cloudAuthApiUrl) {
|
|
@@ -843,13 +950,98 @@ function cloudAuthLoginCommand({ backend, apiUrl } = {}) {
|
|
|
843
950
|
return "vendian cloud auth login";
|
|
844
951
|
}
|
|
845
952
|
|
|
953
|
+
// src/forward.js
|
|
954
|
+
var AUTO_UPDATE_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
955
|
+
async function forwardToPythonVendian(args, { env = process.env, platform = process.platform } = {}) {
|
|
956
|
+
const venvPath = managedVenvPath(env, platform);
|
|
957
|
+
const vendianPath = venvVendian(venvPath, platform);
|
|
958
|
+
if (!import_node_fs8.default.existsSync(vendianPath)) {
|
|
959
|
+
throw new Error("Vendian is not set up yet. Run `vendian login` first.");
|
|
960
|
+
}
|
|
961
|
+
const loadedConfig = loadConfig(env, platform);
|
|
962
|
+
const requiresPackageAccess = commandNeedsPackageAccess(args);
|
|
963
|
+
const refreshed = requiresPackageAccess ? await refreshPackageAccessFromCloudAuth({ config: loadedConfig, env, platform }) : { config: loadedConfig };
|
|
964
|
+
maybeAutoUpdateManagedEnv({ env, platform, venvPath });
|
|
965
|
+
const config = refreshed.config;
|
|
966
|
+
const registry = registryConfig(config, env, platform);
|
|
967
|
+
if (requiresPackageAccess && !registry.token) {
|
|
968
|
+
throw new Error("Package access is missing. Run `vendian login` or `vendian update` before starting local agents.");
|
|
969
|
+
}
|
|
970
|
+
const code = await spawnForward(vendianPath, args, {
|
|
971
|
+
env: {
|
|
972
|
+
...env,
|
|
973
|
+
...packageIndexEnv(config, env, platform)
|
|
974
|
+
}
|
|
975
|
+
});
|
|
976
|
+
recordForwardedDocsCommand(args, code, { env, platform });
|
|
977
|
+
process.exitCode = code;
|
|
978
|
+
}
|
|
979
|
+
function commandNeedsPackageAccess(args = []) {
|
|
980
|
+
return args[0] === "cloud" && args[1] === "local" && ["serve", "run"].includes(args[2]);
|
|
981
|
+
}
|
|
982
|
+
function packageIndexEnv(config = {}, env = process.env, platform = process.platform) {
|
|
983
|
+
const registry = registryConfig(config, env, platform);
|
|
984
|
+
const indexes = buildIndexUrls(registry);
|
|
985
|
+
if (!indexes) {
|
|
986
|
+
return {};
|
|
987
|
+
}
|
|
988
|
+
const extraIndexUrls = joinIndexUrls([
|
|
989
|
+
indexes.runtimeIndexUrl,
|
|
990
|
+
"https://pypi.org/simple",
|
|
991
|
+
env.VENDIAN_PIP_EXTRA_INDEX_URL
|
|
992
|
+
]);
|
|
993
|
+
const uvExtraIndexUrls = joinIndexUrls([
|
|
994
|
+
indexes.runtimeIndexUrl,
|
|
995
|
+
"https://pypi.org/simple",
|
|
996
|
+
env.VENDIAN_UV_EXTRA_INDEX_URL
|
|
997
|
+
]);
|
|
998
|
+
return {
|
|
999
|
+
VENDIAN_PIP_INDEX_URL: indexes.sdkIndexUrl,
|
|
1000
|
+
VENDIAN_PIP_EXTRA_INDEX_URL: extraIndexUrls,
|
|
1001
|
+
VENDIAN_UV_INDEX_URL: indexes.sdkIndexUrl,
|
|
1002
|
+
VENDIAN_UV_EXTRA_INDEX_URL: uvExtraIndexUrls
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
function joinIndexUrls(urls) {
|
|
1006
|
+
return urls.flatMap((value) => String(value || "").split(/\s+/)).map((value) => value.trim()).filter(Boolean).filter((value, index, all) => all.indexOf(value) === index).join(" ");
|
|
1007
|
+
}
|
|
1008
|
+
function maybeAutoUpdateManagedEnv({ env = process.env, platform = process.platform, venvPath = managedVenvPath(env, platform) } = {}) {
|
|
1009
|
+
if (env.VENDIAN_SKIP_AUTO_UPDATE === "1") {
|
|
1010
|
+
return false;
|
|
1011
|
+
}
|
|
1012
|
+
const config = loadConfig(env, platform);
|
|
1013
|
+
const lastUpdate = Date.parse(config.lastManagedUpdateAt || "");
|
|
1014
|
+
if (Number.isFinite(lastUpdate) && Date.now() - lastUpdate < AUTO_UPDATE_INTERVAL_MS) {
|
|
1015
|
+
return false;
|
|
1016
|
+
}
|
|
1017
|
+
const registry = registryConfig(config, env);
|
|
1018
|
+
if (!registry.token) {
|
|
1019
|
+
return false;
|
|
1020
|
+
}
|
|
1021
|
+
const pythonPath = venvPython(venvPath, platform);
|
|
1022
|
+
if (!import_node_fs8.default.existsSync(pythonPath)) {
|
|
1023
|
+
return false;
|
|
1024
|
+
}
|
|
1025
|
+
try {
|
|
1026
|
+
console.error("[vendian] Checking managed CLI/runtime updates...");
|
|
1027
|
+
installVendianPackages({ pythonPath, venvPath, config, env });
|
|
1028
|
+
const next = { ...config, lastManagedUpdateAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
1029
|
+
refreshAgentDocsWorkspaces({ config: next, venvPath, env, platform });
|
|
1030
|
+
return true;
|
|
1031
|
+
} catch (error) {
|
|
1032
|
+
const message = error && typeof error.message === "string" ? error.message : String(error);
|
|
1033
|
+
console.error(`[vendian] Update check failed; continuing with installed CLI. ${message}`);
|
|
1034
|
+
return false;
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
846
1038
|
// src/tui.js
|
|
847
|
-
var
|
|
1039
|
+
var import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
848
1040
|
var import_node_readline = __toESM(require("node:readline"), 1);
|
|
849
1041
|
var import_promises = __toESM(require("node:readline/promises"), 1);
|
|
850
1042
|
|
|
851
1043
|
// src/version.js
|
|
852
|
-
var CLI_VERSION = true ? "0.0.
|
|
1044
|
+
var CLI_VERSION = true ? "0.0.7" : process.env.npm_package_version || "0.0.0-dev";
|
|
853
1045
|
|
|
854
1046
|
// src/tui.js
|
|
855
1047
|
var RESET = "\x1B[0m";
|
|
@@ -871,6 +1063,8 @@ var ENDPOINTS = [
|
|
|
871
1063
|
];
|
|
872
1064
|
var ACTIONS = [
|
|
873
1065
|
{ id: "connect", label: "Connect / switch endpoint", detail: "Sign in to local, dev, staging, production, or a custom API" },
|
|
1066
|
+
{ id: "init", label: "Initialize agent docs", detail: "Write SDK-owned authoring docs into a workspace" },
|
|
1067
|
+
{ id: "create", label: "Create agent", detail: "Scaffold a new agent through the Python SDK CLI" },
|
|
874
1068
|
{ id: "serve", label: "Start local agent server", detail: "Run agents from ./agents through the managed runtime" },
|
|
875
1069
|
{ id: "doctor", label: "Run doctor", detail: "Check Python, runtime, package access, and local paths" },
|
|
876
1070
|
{ id: "update", label: "Update managed runtime", detail: "Refresh the Vendian runtime packages" },
|
|
@@ -955,7 +1149,7 @@ function runtimeSummary({ env = process.env, platform = process.platform, now =
|
|
|
955
1149
|
const config = loadConfig(env, platform);
|
|
956
1150
|
const venvPath = managedVenvPath(env, platform);
|
|
957
1151
|
const vendianPath = venvVendian(venvPath, platform);
|
|
958
|
-
const installed =
|
|
1152
|
+
const installed = import_node_fs9.default.existsSync(vendianPath);
|
|
959
1153
|
const lastUpdate = Date.parse(config.lastManagedUpdateAt || "");
|
|
960
1154
|
const stale = !Number.isFinite(lastUpdate) || now - lastUpdate > 24 * 60 * 60 * 1e3;
|
|
961
1155
|
return {
|
|
@@ -969,6 +1163,30 @@ async function runAction(action, { env, platform, input, output }) {
|
|
|
969
1163
|
await connectEndpoint({ env, platform, input, output });
|
|
970
1164
|
return false;
|
|
971
1165
|
}
|
|
1166
|
+
if (action === "init") {
|
|
1167
|
+
const outputDir = await prompt(input, output, "Workspace directory", ".");
|
|
1168
|
+
output.write(`${CLEAR}${SHOW_CURSOR}`);
|
|
1169
|
+
output.write(`[vendian] Initializing agent docs in ${outputDir || "."}
|
|
1170
|
+
|
|
1171
|
+
`);
|
|
1172
|
+
await forwardToPythonVendian(["init", "--output-dir", outputDir || "."], { env, platform });
|
|
1173
|
+
return true;
|
|
1174
|
+
}
|
|
1175
|
+
if (action === "create") {
|
|
1176
|
+
const name = await prompt(input, output, "Agent name");
|
|
1177
|
+
if (!name) {
|
|
1178
|
+
output.write("Agent name is required.\n");
|
|
1179
|
+
await prompt(input, output, "Press Enter to return");
|
|
1180
|
+
return false;
|
|
1181
|
+
}
|
|
1182
|
+
const outputDir = await prompt(input, output, "Output directory", "./agents");
|
|
1183
|
+
output.write(`${CLEAR}${SHOW_CURSOR}`);
|
|
1184
|
+
output.write(`[vendian] Creating agent ${name} in ${outputDir || "./agents"}
|
|
1185
|
+
|
|
1186
|
+
`);
|
|
1187
|
+
await forwardToPythonVendian(["create", name, "--output-dir", outputDir || "./agents"], { env, platform });
|
|
1188
|
+
return true;
|
|
1189
|
+
}
|
|
972
1190
|
if (action === "serve") {
|
|
973
1191
|
const agentsDir = await prompt(input, output, "Agents directory", "./agents");
|
|
974
1192
|
output.write(`${CLEAR}${SHOW_CURSOR}`);
|
|
@@ -1037,6 +1255,11 @@ function helpText() {
|
|
|
1037
1255
|
"Common commands:",
|
|
1038
1256
|
" vendian",
|
|
1039
1257
|
" vendian login",
|
|
1258
|
+
" vendian init --output-dir ./agents",
|
|
1259
|
+
' vendian create "My Agent" --output-dir ./agents',
|
|
1260
|
+
" vendian validate ./agents/my-agent --runtime",
|
|
1261
|
+
" vendian test ./agents/my-agent --dry-run --mock-credentials",
|
|
1262
|
+
" vendian models",
|
|
1040
1263
|
" vendian login --backend staging",
|
|
1041
1264
|
" vendian login --api-url http://localhost:3000",
|
|
1042
1265
|
" vendian cloud local serve --agents-dir ./agents",
|
|
@@ -1101,10 +1324,14 @@ Usage:
|
|
|
1101
1324
|
vendian setup Alias for vendian login
|
|
1102
1325
|
vendian doctor Check local bootstrap health
|
|
1103
1326
|
vendian update Update the managed Vendian CLI/runtime
|
|
1104
|
-
vendian
|
|
1327
|
+
vendian init Write current SDK agent docs into a workspace
|
|
1328
|
+
vendian create "My Agent" Scaffold a new agent from SDK templates
|
|
1329
|
+
vendian <command> Run a managed Python SDK/cloud command
|
|
1105
1330
|
|
|
1106
1331
|
Examples:
|
|
1107
1332
|
vendian login
|
|
1333
|
+
vendian init --output-dir ./agents
|
|
1334
|
+
vendian create "Google Drive Processor" --output-dir ./agents
|
|
1108
1335
|
vendian login --backend staging
|
|
1109
1336
|
vendian cloud local serve --agents-dir ./agents
|
|
1110
1337
|
|