@vendian/cli 0.0.5 → 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 +355 -79
- package/package.json +3 -2
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,45 +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 code = await spawnForward(vendianPath, args, { env });
|
|
430
|
-
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;
|
|
431
446
|
}
|
|
432
|
-
function
|
|
433
|
-
|
|
434
|
-
|
|
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
|
+
}
|
|
435
459
|
}
|
|
460
|
+
return ".";
|
|
461
|
+
}
|
|
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);
|
|
466
|
+
}
|
|
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 });
|
|
436
474
|
const config = loadConfig(env, platform);
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
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)) {
|
|
443
487
|
return false;
|
|
444
488
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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 };
|
|
448
505
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
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
|
+
}
|
|
458
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 };
|
|
459
528
|
}
|
|
460
529
|
|
|
461
530
|
// src/setup.js
|
|
@@ -465,7 +534,7 @@ var import_node_fs7 = __toESM(require("node:fs"), 1);
|
|
|
465
534
|
var import_node_crypto = __toESM(require("node:crypto"), 1);
|
|
466
535
|
var import_node_http = __toESM(require("node:http"), 1);
|
|
467
536
|
var import_node_fs6 = __toESM(require("node:fs"), 1);
|
|
468
|
-
var
|
|
537
|
+
var import_node_path5 = __toESM(require("node:path"), 1);
|
|
469
538
|
var import_node_child_process3 = require("node:child_process");
|
|
470
539
|
var DEFAULT_OAUTH_REDIRECT_PORT = 8765;
|
|
471
540
|
function resolveApiUrl({ backend, apiUrl, env = process.env } = {}) {
|
|
@@ -509,6 +578,15 @@ async function loginWithVendianOAuth({ backend, apiUrl, noBrowser = false, env =
|
|
|
509
578
|
await callback.close();
|
|
510
579
|
}
|
|
511
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
|
+
}
|
|
512
590
|
function loadCloudConfig(env = process.env, platform = process.platform) {
|
|
513
591
|
const file = cloudConfigPath(env, platform);
|
|
514
592
|
try {
|
|
@@ -533,6 +611,21 @@ function cloudAuthStatus({ backend, apiUrl, env = process.env, platform = proces
|
|
|
533
611
|
profiles
|
|
534
612
|
};
|
|
535
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
|
+
}
|
|
536
629
|
async function getOAuthConfig(apiUrl, redirectUri) {
|
|
537
630
|
const url = new URL(`${apiUrl}/api/v1/cli/auth/oauth/config`);
|
|
538
631
|
url.searchParams.set("redirectUri", redirectUri);
|
|
@@ -564,8 +657,8 @@ async function exchangeCodeForClerkToken(config, code, codeVerifier, redirectUri
|
|
|
564
657
|
}
|
|
565
658
|
return String(token);
|
|
566
659
|
}
|
|
567
|
-
async function getJson(url) {
|
|
568
|
-
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 } });
|
|
569
662
|
return decodeResponse(response);
|
|
570
663
|
}
|
|
571
664
|
async function postJson(url, body) {
|
|
@@ -655,24 +748,30 @@ function openBrowser(url) {
|
|
|
655
748
|
return;
|
|
656
749
|
}
|
|
657
750
|
if (platform === "darwin") {
|
|
658
|
-
(0, import_node_child_process3.spawnSync)(
|
|
751
|
+
(0, import_node_child_process3.spawnSync)(...buildMacOpenCommand(url), { stdio: "ignore", shell: false });
|
|
659
752
|
return;
|
|
660
753
|
}
|
|
661
|
-
(0, import_node_child_process3.spawnSync)(
|
|
754
|
+
(0, import_node_child_process3.spawnSync)(...buildLinuxOpenCommand(url), { stdio: "ignore", shell: false });
|
|
662
755
|
}
|
|
663
756
|
function buildWindowsOpenCommand(url) {
|
|
664
757
|
return ["rundll32.exe", ["url.dll,FileProtocolHandler", String(url)]];
|
|
665
758
|
}
|
|
759
|
+
function buildMacOpenCommand(url) {
|
|
760
|
+
return ["open", [String(url)]];
|
|
761
|
+
}
|
|
762
|
+
function buildLinuxOpenCommand(url) {
|
|
763
|
+
return ["xdg-open", [String(url)]];
|
|
764
|
+
}
|
|
666
765
|
function cloudConfigPath(env = process.env, platform = process.platform) {
|
|
667
766
|
if (env.VENDIAN_CLOUD_CONFIG) {
|
|
668
|
-
return
|
|
767
|
+
return import_node_path5.default.resolve(env.VENDIAN_CLOUD_CONFIG);
|
|
669
768
|
}
|
|
670
769
|
if (platform === "win32") {
|
|
671
|
-
const root2 = env.APPDATA ||
|
|
672
|
-
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");
|
|
673
772
|
}
|
|
674
|
-
const root = env.XDG_CONFIG_HOME ||
|
|
675
|
-
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");
|
|
676
775
|
}
|
|
677
776
|
function saveCloudToken(token, { env = process.env, platform = process.platform } = {}) {
|
|
678
777
|
const file = cloudConfigPath(env, platform);
|
|
@@ -694,7 +793,7 @@ function saveCloudToken(token, { env = process.env, platform = process.platform
|
|
|
694
793
|
scopes: token.scopes,
|
|
695
794
|
tooling_eligible: token.toolingEligible
|
|
696
795
|
};
|
|
697
|
-
import_node_fs6.default.mkdirSync(
|
|
796
|
+
import_node_fs6.default.mkdirSync(import_node_path5.default.dirname(file), { recursive: true });
|
|
698
797
|
import_node_fs6.default.writeFileSync(file, `${JSON.stringify(raw, null, 2)}
|
|
699
798
|
`, { encoding: "utf8", mode: 384 });
|
|
700
799
|
try {
|
|
@@ -739,24 +838,12 @@ async function setup({
|
|
|
739
838
|
throw new Error("Vendian login succeeded, but the backend did not return package credentials. Configure CLI_PACKAGE_REGISTRY_TOKEN on the backend.");
|
|
740
839
|
}
|
|
741
840
|
if (packageCredentials) {
|
|
742
|
-
next
|
|
743
|
-
next.gitlabUsername = packageCredentials.username || next.gitlabUsername;
|
|
744
|
-
next.sdkPublicProjectId = packageCredentials.sdkProjectId || next.sdkPublicProjectId;
|
|
745
|
-
next.sdkRuntimeProjectId = packageCredentials.runtimeProjectId || next.sdkRuntimeProjectId;
|
|
746
|
-
next.vendianAgentsVersion = packageCredentials.vendianAgentsVersion || next.vendianAgentsVersion;
|
|
747
|
-
next.vendianAgentsRuntimeVersion = packageCredentials.vendianAgentsRuntimeVersion || next.vendianAgentsRuntimeVersion;
|
|
748
|
-
const secret = savePackageTokenSecret(packageCredentials.token, next, platform);
|
|
749
|
-
if (secret.ok) {
|
|
750
|
-
Object.assign(next, secret.config || {});
|
|
751
|
-
delete next.gitlabToken;
|
|
752
|
-
console.log("Package access saved.");
|
|
753
|
-
} else {
|
|
754
|
-
next.gitlabToken = packageCredentials.token;
|
|
755
|
-
console.log("Package access saved in the local Vendian CLI config file.");
|
|
756
|
-
}
|
|
841
|
+
savePackageCredentials(next, packageCredentials, { platform });
|
|
757
842
|
}
|
|
758
843
|
} else if (auth.authenticated) {
|
|
759
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);
|
|
760
847
|
} else if (registry.token) {
|
|
761
848
|
if (registry.tokenSource !== "secret-store") {
|
|
762
849
|
next.gitlabToken = registry.token;
|
|
@@ -777,7 +864,8 @@ async function setup({
|
|
|
777
864
|
console.log(`Python: ${pythonVersion(pythonPath) || pythonPath}`);
|
|
778
865
|
saveConfig(next, env, platform);
|
|
779
866
|
installVendianPackages({ pythonPath, venvPath, config: next, env, platform });
|
|
780
|
-
|
|
867
|
+
const updated = { ...next, lastManagedUpdateAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
868
|
+
refreshAgentDocsWorkspaces({ config: updated, venvPath, env, platform });
|
|
781
869
|
if (!verifyVendianImports(pythonPath)) {
|
|
782
870
|
throw new Error("Vendian packages installed, but import verification failed.");
|
|
783
871
|
}
|
|
@@ -790,6 +878,57 @@ async function setup({
|
|
|
790
878
|
console.log(line);
|
|
791
879
|
}
|
|
792
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
|
+
}
|
|
793
932
|
function setupCompletionLines({ cloudAuthApiUrl, backend, apiUrl } = {}) {
|
|
794
933
|
const lines = ["Vendian login complete."];
|
|
795
934
|
if (cloudAuthApiUrl) {
|
|
@@ -811,13 +950,98 @@ function cloudAuthLoginCommand({ backend, apiUrl } = {}) {
|
|
|
811
950
|
return "vendian cloud auth login";
|
|
812
951
|
}
|
|
813
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
|
+
|
|
814
1038
|
// src/tui.js
|
|
815
|
-
var
|
|
1039
|
+
var import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
816
1040
|
var import_node_readline = __toESM(require("node:readline"), 1);
|
|
817
1041
|
var import_promises = __toESM(require("node:readline/promises"), 1);
|
|
818
1042
|
|
|
819
1043
|
// src/version.js
|
|
820
|
-
var CLI_VERSION = true ? "0.0.
|
|
1044
|
+
var CLI_VERSION = true ? "0.0.7" : process.env.npm_package_version || "0.0.0-dev";
|
|
821
1045
|
|
|
822
1046
|
// src/tui.js
|
|
823
1047
|
var RESET = "\x1B[0m";
|
|
@@ -839,6 +1063,8 @@ var ENDPOINTS = [
|
|
|
839
1063
|
];
|
|
840
1064
|
var ACTIONS = [
|
|
841
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" },
|
|
842
1068
|
{ id: "serve", label: "Start local agent server", detail: "Run agents from ./agents through the managed runtime" },
|
|
843
1069
|
{ id: "doctor", label: "Run doctor", detail: "Check Python, runtime, package access, and local paths" },
|
|
844
1070
|
{ id: "update", label: "Update managed runtime", detail: "Refresh the Vendian runtime packages" },
|
|
@@ -923,7 +1149,7 @@ function runtimeSummary({ env = process.env, platform = process.platform, now =
|
|
|
923
1149
|
const config = loadConfig(env, platform);
|
|
924
1150
|
const venvPath = managedVenvPath(env, platform);
|
|
925
1151
|
const vendianPath = venvVendian(venvPath, platform);
|
|
926
|
-
const installed =
|
|
1152
|
+
const installed = import_node_fs9.default.existsSync(vendianPath);
|
|
927
1153
|
const lastUpdate = Date.parse(config.lastManagedUpdateAt || "");
|
|
928
1154
|
const stale = !Number.isFinite(lastUpdate) || now - lastUpdate > 24 * 60 * 60 * 1e3;
|
|
929
1155
|
return {
|
|
@@ -937,8 +1163,36 @@ async function runAction(action, { env, platform, input, output }) {
|
|
|
937
1163
|
await connectEndpoint({ env, platform, input, output });
|
|
938
1164
|
return false;
|
|
939
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
|
+
}
|
|
940
1190
|
if (action === "serve") {
|
|
941
1191
|
const agentsDir = await prompt(input, output, "Agents directory", "./agents");
|
|
1192
|
+
output.write(`${CLEAR}${SHOW_CURSOR}`);
|
|
1193
|
+
output.write(`[vendian] Starting local agent server for ${agentsDir || "./agents"}
|
|
1194
|
+
|
|
1195
|
+
`);
|
|
942
1196
|
await forwardToPythonVendian(["cloud", "local", "serve", "--agents-dir", agentsDir || "./agents"], { env, platform });
|
|
943
1197
|
return true;
|
|
944
1198
|
}
|
|
@@ -1001,6 +1255,11 @@ function helpText() {
|
|
|
1001
1255
|
"Common commands:",
|
|
1002
1256
|
" vendian",
|
|
1003
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",
|
|
1004
1263
|
" vendian login --backend staging",
|
|
1005
1264
|
" vendian login --api-url http://localhost:3000",
|
|
1006
1265
|
" vendian cloud local serve --agents-dir ./agents",
|
|
@@ -1065,10 +1324,14 @@ Usage:
|
|
|
1065
1324
|
vendian setup Alias for vendian login
|
|
1066
1325
|
vendian doctor Check local bootstrap health
|
|
1067
1326
|
vendian update Update the managed Vendian CLI/runtime
|
|
1068
|
-
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
|
|
1069
1330
|
|
|
1070
1331
|
Examples:
|
|
1071
1332
|
vendian login
|
|
1333
|
+
vendian init --output-dir ./agents
|
|
1334
|
+
vendian create "Google Drive Processor" --output-dir ./agents
|
|
1072
1335
|
vendian login --backend staging
|
|
1073
1336
|
vendian cloud local serve --agents-dir ./agents
|
|
1074
1337
|
|
|
@@ -1135,7 +1398,20 @@ function parseSetupOptions(args) {
|
|
|
1135
1398
|
return options;
|
|
1136
1399
|
}
|
|
1137
1400
|
|
|
1401
|
+
// src/terminal-title.js
|
|
1402
|
+
function setTerminalTitle(title, { output = process.stdout, processRef = process } = {}) {
|
|
1403
|
+
const safeTitle = String(title).replace(/[\x00-\x1f\x7f]/g, " ").trim();
|
|
1404
|
+
if (!safeTitle) {
|
|
1405
|
+
return;
|
|
1406
|
+
}
|
|
1407
|
+
processRef.title = safeTitle;
|
|
1408
|
+
if (output?.isTTY && typeof output.write === "function") {
|
|
1409
|
+
output.write(`\x1B]0;${safeTitle}\x07`);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1138
1413
|
// src/entry.js
|
|
1414
|
+
setTerminalTitle("Vendian CLI");
|
|
1139
1415
|
main(process.argv.slice(2)).catch((error) => {
|
|
1140
1416
|
const message = error && typeof error.message === "string" ? error.message : String(error);
|
|
1141
1417
|
console.error(`[vendian] ${message}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vendian/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "Public Vendian CLI bootstrapper and launcher",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"build": "node scripts/build-package.mjs",
|
|
23
23
|
"prepack": "npm run build",
|
|
24
|
-
"prepublishOnly": "npm test",
|
|
24
|
+
"prepublishOnly": "npm run release:sync-version && npm test",
|
|
25
|
+
"release:sync-version": "node scripts/sync-release-version.mjs",
|
|
25
26
|
"test": "node --test"
|
|
26
27
|
},
|
|
27
28
|
"engines": {
|