@vendoai/vendo 0.4.0 → 0.4.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/dist/cli/cloud/device-login.js +6 -4
- package/dist/cli/shared.d.ts +1 -1
- package/dist/cli/shared.js +1 -1
- package/dist/cli.js +2 -3
- package/dist/wire/shared.d.ts +1 -1
- package/dist/wire/shared.js +1 -1
- package/package.json +11 -11
- package/dist/cli/cloud/deploy.d.ts +0 -26
- package/dist/cli/cloud/deploy.js +0 -187
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { option
|
|
3
|
+
import { option } from "./args.js";
|
|
4
4
|
import { isVendoKey, resolveCloudBaseUrl } from "./client.js";
|
|
5
5
|
import { errorMessage, printJson } from "./output.js";
|
|
6
6
|
import { deletePendingClaim, readPendingClaim, writePendingClaim } from "./pending-claim.js";
|
|
@@ -118,9 +118,11 @@ export async function runDeviceLogin(args, options = {}) {
|
|
|
118
118
|
verificationUriComplete = resume.verification_uri_complete;
|
|
119
119
|
}
|
|
120
120
|
else {
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
// No identity hint by design: the human signs in as whoever they choose
|
|
122
|
+
// on the approval page. A guessed login_hint (git email, positional arg)
|
|
123
|
+
// is an assumption that mis-attributes the claim, so the ceremony never
|
|
124
|
+
// sends one.
|
|
125
|
+
const claim = await postJson(fetchImpl, `${base}${CLAIM_PATH}`, "application/json", "{}");
|
|
124
126
|
if (claim.status !== 200) {
|
|
125
127
|
const envelope = claim.body;
|
|
126
128
|
throw new Error(typeof envelope?.error?.message === "string"
|
package/dist/cli/shared.d.ts
CHANGED
package/dist/cli/shared.js
CHANGED
|
@@ -4,7 +4,7 @@ import { dirname, join } from "node:path";
|
|
|
4
4
|
import { createInterface } from "node:readline/promises";
|
|
5
5
|
import { stdin, stdout } from "node:process";
|
|
6
6
|
import { initTelemetry, repoHost } from "@vendoai/telemetry";
|
|
7
|
-
export const CLI_VERSION = "0.4.
|
|
7
|
+
export const CLI_VERSION = "0.4.1";
|
|
8
8
|
export const consoleOutput = {
|
|
9
9
|
log: (message) => console.log(message),
|
|
10
10
|
error: (message) => console.error(message),
|
package/dist/cli.js
CHANGED
|
@@ -18,7 +18,7 @@ Usage: vendo <command> [dir] [options]
|
|
|
18
18
|
|
|
19
19
|
Commands:
|
|
20
20
|
init [dir] Set up Vendo: wire the handler, extract tools + theme, resolve a model key
|
|
21
|
-
login
|
|
21
|
+
login Claim a Vendo Cloud key: approve in the browser; the key lands in .env.local
|
|
22
22
|
doctor [dir] Verify the install: wiring, live probes, and one real model turn (--json for agents)
|
|
23
23
|
|
|
24
24
|
Advanced:
|
|
@@ -38,7 +38,6 @@ Options:
|
|
|
38
38
|
--auth <preset> Init only: wire this auth preset without asking (authJs, clerk, supabase, auth0, jwt, none)
|
|
39
39
|
--framework <name> Init only: override framework detection (next, express) — required non-interactively when detection fails
|
|
40
40
|
--cloud-key <key> Init only: write this Vendo Cloud key to .env.local instead of the login offer
|
|
41
|
-
--email <address> Login only: pre-fill the approval page (login hint)
|
|
42
41
|
--wait <seconds> Login only: bound this call's polling to N seconds (agents loop re-runs; each resumes the same request), then exit resumably
|
|
43
42
|
--byo Init only: decline the Vendo Cloud offer (bring your own model key)
|
|
44
43
|
--ai-polish Init only: consent to the AI extraction pass without a prompt (works non-interactively)
|
|
@@ -88,7 +87,7 @@ const REFINE_FLAGS = new Set(["--yes"]);
|
|
|
88
87
|
const REFINE_VALUE_OPTIONS = ["--url", "--model-import", "--ask"];
|
|
89
88
|
const SYNC_FLAGS = new Set(["--strict", "--json", "--report"]);
|
|
90
89
|
const SYNC_VALUE_OPTIONS = ["--url", "--key", "--api-url"];
|
|
91
|
-
const LOGIN_VALUE_OPTIONS = ["--
|
|
90
|
+
const LOGIN_VALUE_OPTIONS = ["--api-url", "--wait"];
|
|
92
91
|
/** ENG-335: options the CLI does not recognize — or value options missing
|
|
93
92
|
their value — must fail loudly before anything runs. Silently dropping a
|
|
94
93
|
flag is how the "--agent writes nothing" promise broke in the field: an
|
package/dist/wire/shared.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ import type { RuntimeCaptureHandler } from "../runtime-capture.js";
|
|
|
14
14
|
shares. The anonymous-session + RunContext resolution lives in
|
|
15
15
|
wire/context.ts; server.ts assembles the table from the per-area modules
|
|
16
16
|
under src/wire/. */
|
|
17
|
-
export declare const VERSION = "0.4.
|
|
17
|
+
export declare const VERSION = "0.4.1";
|
|
18
18
|
export declare const BASE_PATH = "/api/vendo";
|
|
19
19
|
export type SandboxVenue = "e2b" | "cloud" | "custom" | false;
|
|
20
20
|
/** How inference is served: "custom" (a host-passed model) or "ladder" (the
|
package/dist/wire/shared.js
CHANGED
|
@@ -4,7 +4,7 @@ import { VendoError, } from "@vendoai/core";
|
|
|
4
4
|
shares. The anonymous-session + RunContext resolution lives in
|
|
5
5
|
wire/context.ts; server.ts assembles the table from the per-area modules
|
|
6
6
|
under src/wire/. */
|
|
7
|
-
export const VERSION = "0.4.
|
|
7
|
+
export const VERSION = "0.4.1";
|
|
8
8
|
export const BASE_PATH = "/api/vendo";
|
|
9
9
|
const STATUS_BY_CODE = {
|
|
10
10
|
validation: 400,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vendoai/vendo",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "The Vendo umbrella: default composition, public wire routes, React provider, and the vendo CLI.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -86,16 +86,16 @@
|
|
|
86
86
|
"ajv": "^8.20.0",
|
|
87
87
|
"ajv-formats": "^3.0.1",
|
|
88
88
|
"zod": "^3.25.0",
|
|
89
|
-
"@vendoai/actions": "0.4.
|
|
90
|
-
"@vendoai/
|
|
91
|
-
"@vendoai/apps": "0.4.
|
|
92
|
-
"@vendoai/
|
|
93
|
-
"@vendoai/
|
|
94
|
-
"@vendoai/agent": "0.4.
|
|
95
|
-
"@vendoai/
|
|
96
|
-
"@vendoai/
|
|
97
|
-
"@vendoai/
|
|
98
|
-
"@vendoai/
|
|
89
|
+
"@vendoai/actions": "0.4.1",
|
|
90
|
+
"@vendoai/automations": "0.4.1",
|
|
91
|
+
"@vendoai/apps": "0.4.1",
|
|
92
|
+
"@vendoai/core": "0.4.1",
|
|
93
|
+
"@vendoai/guard": "0.4.1",
|
|
94
|
+
"@vendoai/agent": "0.4.1",
|
|
95
|
+
"@vendoai/mcp": "0.4.1",
|
|
96
|
+
"@vendoai/telemetry": "0.3.1",
|
|
97
|
+
"@vendoai/store": "0.4.1",
|
|
98
|
+
"@vendoai/ui": "0.4.1"
|
|
99
99
|
},
|
|
100
100
|
"peerDependencies": {
|
|
101
101
|
"@auth/core": "^0.34.3",
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { AppDocument, PermissionGrant } from "@vendoai/core";
|
|
2
|
-
import { type VendoStore } from "@vendoai/store";
|
|
3
|
-
import { type CloudCommandOptions } from "./command.js";
|
|
4
|
-
export interface LocalDeployApp {
|
|
5
|
-
doc: AppDocument;
|
|
6
|
-
enabled: boolean;
|
|
7
|
-
}
|
|
8
|
-
export interface LocalDeployProject {
|
|
9
|
-
subject: string;
|
|
10
|
-
apps: LocalDeployApp[];
|
|
11
|
-
grants: PermissionGrant[];
|
|
12
|
-
}
|
|
13
|
-
export interface LocalProjectReadOptions {
|
|
14
|
-
subject?: string;
|
|
15
|
-
cwd?: string;
|
|
16
|
-
}
|
|
17
|
-
export interface ReadLocalProjectOptions extends LocalProjectReadOptions {
|
|
18
|
-
storeFactory?: () => VendoStore;
|
|
19
|
-
}
|
|
20
|
-
export type LocalProjectReader = (options: LocalProjectReadOptions) => Promise<LocalDeployProject>;
|
|
21
|
-
export interface CloudDeployOptions extends CloudCommandOptions {
|
|
22
|
-
cwd?: string;
|
|
23
|
-
localProjectReader?: LocalProjectReader;
|
|
24
|
-
}
|
|
25
|
-
export declare function readLocalProject(options?: ReadLocalProjectOptions): Promise<LocalDeployProject>;
|
|
26
|
-
export declare function runDeploy(args: string[], options?: CloudDeployOptions): Promise<number>;
|
package/dist/cli/cloud/deploy.js
DELETED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import { appStore, createStore, grantStore, } from "@vendoai/store";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { option, options as repeatedOptions } from "./args.js";
|
|
4
|
-
import { CloudError, resolveCloudBaseUrl } from "./client.js";
|
|
5
|
-
import { commandContext, } from "./command.js";
|
|
6
|
-
import { errorMessage, formatTable, printJson } from "./output.js";
|
|
7
|
-
export async function readLocalProject(options = {}) {
|
|
8
|
-
const store = options.storeFactory?.() ?? createStore({
|
|
9
|
-
dataDir: join(options.cwd ?? process.cwd(), ".vendo/data"),
|
|
10
|
-
});
|
|
11
|
-
try {
|
|
12
|
-
await store.ensureSchema();
|
|
13
|
-
const driver = store.raw();
|
|
14
|
-
const subjectRows = await driver.query("SELECT DISTINCT subject FROM vendo_apps ORDER BY subject ASC");
|
|
15
|
-
const subjects = subjectRows.rows.map((row) => row.subject);
|
|
16
|
-
if (subjects.length === 0)
|
|
17
|
-
throw new Error("No local Vendo apps found in .vendo/data");
|
|
18
|
-
let subject = options.subject;
|
|
19
|
-
if (subject === undefined) {
|
|
20
|
-
if (subjects.length > 1) {
|
|
21
|
-
throw new Error(`Multiple local Vendo subjects found: ${subjects.join(", ")}. Pass --subject <subject>.`);
|
|
22
|
-
}
|
|
23
|
-
subject = subjects[0];
|
|
24
|
-
}
|
|
25
|
-
else if (!subjects.includes(subject)) {
|
|
26
|
-
throw new Error(`Subject ${subject} was not found in the local Vendo store`);
|
|
27
|
-
}
|
|
28
|
-
const appIds = await driver.query("SELECT id FROM vendo_apps WHERE subject = $1 ORDER BY created_at ASC, id ASC", [subject]);
|
|
29
|
-
const apps = (await Promise.all(appIds.rows.map(async ({ id }) => {
|
|
30
|
-
const row = await appStore(store).get(id);
|
|
31
|
-
if (row === null || row.subject !== subject)
|
|
32
|
-
return null;
|
|
33
|
-
return { doc: row.doc, enabled: row.enabled };
|
|
34
|
-
}))).filter((row) => row !== null);
|
|
35
|
-
const grantIds = await driver.query(`SELECT id FROM vendo_grants
|
|
36
|
-
WHERE subject = $1 AND source = 'automation'
|
|
37
|
-
AND revoked_at IS NULL AND (expires_at IS NULL OR expires_at > now())
|
|
38
|
-
ORDER BY granted_at ASC, id ASC`, [subject]);
|
|
39
|
-
const grants = (await Promise.all(grantIds.rows.map(({ id }) => grantStore(store).get(id))))
|
|
40
|
-
.filter((grant) => grant !== null);
|
|
41
|
-
return { subject, apps, grants };
|
|
42
|
-
}
|
|
43
|
-
finally {
|
|
44
|
-
await store.close();
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
function machineOptions(args, context) {
|
|
48
|
-
return {
|
|
49
|
-
auth: "key",
|
|
50
|
-
apiKey: option(args, "--key"),
|
|
51
|
-
apiUrl: option(args, "--api-url"),
|
|
52
|
-
env: context.env,
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
function secretValues(args) {
|
|
56
|
-
const values = new Map();
|
|
57
|
-
for (const pair of repeatedOptions(args, "--secret")) {
|
|
58
|
-
const separator = pair.indexOf("=");
|
|
59
|
-
if (separator <= 0)
|
|
60
|
-
throw new Error("--secret must use NAME=VALUE");
|
|
61
|
-
values.set(pair.slice(0, separator), pair.slice(separator + 1));
|
|
62
|
-
}
|
|
63
|
-
return values;
|
|
64
|
-
}
|
|
65
|
-
function selectedApps(project, args) {
|
|
66
|
-
const requested = [...new Set(repeatedOptions(args, "--app"))];
|
|
67
|
-
if (requested.length === 0) {
|
|
68
|
-
const selected = project.apps.filter((app) => app.enabled && app.doc.trigger !== undefined);
|
|
69
|
-
if (selected.length === 0)
|
|
70
|
-
throw new Error("No enabled local automations found");
|
|
71
|
-
return selected;
|
|
72
|
-
}
|
|
73
|
-
const requestedIds = new Set(requested);
|
|
74
|
-
for (const appId of requested) {
|
|
75
|
-
const app = project.apps.find((candidate) => candidate.doc.id === appId);
|
|
76
|
-
if (app === undefined)
|
|
77
|
-
throw new Error(`App ${appId} was not found for subject ${project.subject}`);
|
|
78
|
-
if (app.doc.trigger === undefined)
|
|
79
|
-
throw new Error(`App ${appId} is not an automation`);
|
|
80
|
-
}
|
|
81
|
-
return project.apps.filter((app) => requestedIds.has(app.doc.id));
|
|
82
|
-
}
|
|
83
|
-
function warnUnsupportedFnSteps(context, apps) {
|
|
84
|
-
for (const app of apps) {
|
|
85
|
-
const run = app.doc.trigger?.run;
|
|
86
|
-
if (run?.kind === "steps" && run.steps.some((step) => step.tool.startsWith("fn:"))) {
|
|
87
|
-
context.output.error(`WARNING: Automation ${app.doc.id} has fn: steps that target the app's machine, which is unreachable from hosted sandboxes in v1; those steps will fail/park when fired hosted.`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
function deployResponse(value) {
|
|
92
|
-
if (typeof value !== "object" || value === null)
|
|
93
|
-
throw new Error("Vendo Cloud returned an invalid deploy response");
|
|
94
|
-
const result = value;
|
|
95
|
-
if (typeof result.org?.id !== "string"
|
|
96
|
-
|| typeof result.org.slug !== "string"
|
|
97
|
-
|| typeof result.instance?.status !== "string"
|
|
98
|
-
|| typeof result.applied?.apps !== "number"
|
|
99
|
-
|| typeof result.applied.grants !== "number"
|
|
100
|
-
|| typeof result.applied.secrets !== "number"
|
|
101
|
-
|| !Array.isArray(result.webhooks)
|
|
102
|
-
|| result.webhooks.some((webhook) => typeof webhook.app_id !== "string"
|
|
103
|
-
|| typeof webhook.source !== "string"
|
|
104
|
-
|| typeof webhook.url !== "string")) {
|
|
105
|
-
throw new Error("Vendo Cloud returned an invalid deploy response");
|
|
106
|
-
}
|
|
107
|
-
return result;
|
|
108
|
-
}
|
|
109
|
-
function printDeploySummary(context, response) {
|
|
110
|
-
const lines = [
|
|
111
|
-
`Vendo Cloud deploy: ${response.org.slug} (${response.instance.status})`,
|
|
112
|
-
"",
|
|
113
|
-
formatTable(["APPLIED", "COUNT"], [
|
|
114
|
-
["apps", String(response.applied.apps)],
|
|
115
|
-
["grants", String(response.applied.grants)],
|
|
116
|
-
["secrets", String(response.applied.secrets)],
|
|
117
|
-
]),
|
|
118
|
-
"",
|
|
119
|
-
];
|
|
120
|
-
if (response.webhooks.length === 0) {
|
|
121
|
-
lines.push("Webhooks: none");
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
lines.push(formatTable(["AUTOMATION", "SOURCE", "WEBHOOK URL"], response.webhooks.map((webhook) => [
|
|
125
|
-
webhook.app_id,
|
|
126
|
-
webhook.source,
|
|
127
|
-
webhook.url,
|
|
128
|
-
])));
|
|
129
|
-
}
|
|
130
|
-
context.output.log(lines.join("\n"));
|
|
131
|
-
}
|
|
132
|
-
export async function runDeploy(args, options = {}) {
|
|
133
|
-
const context = commandContext(options);
|
|
134
|
-
try {
|
|
135
|
-
const project = await (options.localProjectReader ?? readLocalProject)({
|
|
136
|
-
subject: option(args, "--subject"),
|
|
137
|
-
cwd: options.cwd ?? process.cwd(),
|
|
138
|
-
});
|
|
139
|
-
const apps = selectedApps(project, args);
|
|
140
|
-
warnUnsupportedFnSteps(context, apps);
|
|
141
|
-
const appIds = new Set(apps.map((app) => app.doc.id));
|
|
142
|
-
const grants = project.grants.filter((grant) => grant.subject === project.subject
|
|
143
|
-
&& grant.source === "automation"
|
|
144
|
-
&& grant.appId !== undefined
|
|
145
|
-
&& appIds.has(grant.appId));
|
|
146
|
-
const provided = secretValues(args);
|
|
147
|
-
const referenced = new Set();
|
|
148
|
-
for (const app of apps) {
|
|
149
|
-
for (const name of app.doc.secrets ?? []) {
|
|
150
|
-
referenced.add(name);
|
|
151
|
-
if (!provided.has(name)) {
|
|
152
|
-
context.output.error(`Automation ${app.doc.id} references missing secret ${name}; pass --secret ${name}=VALUE`);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
const secrets = [...referenced]
|
|
157
|
-
.filter((name) => provided.has(name))
|
|
158
|
-
.map((name) => ({ name, value: provided.get(name) }));
|
|
159
|
-
const requestOptions = machineOptions(args, context);
|
|
160
|
-
if (secrets.length > 0 && new URL(resolveCloudBaseUrl(requestOptions)).protocol !== "https:") {
|
|
161
|
-
throw new Error("Deploying secret values requires an HTTPS Vendo Cloud URL");
|
|
162
|
-
}
|
|
163
|
-
const response = deployResponse(await context.fetcher("/api/v1/hosted/deploy", {
|
|
164
|
-
...requestOptions,
|
|
165
|
-
method: "POST",
|
|
166
|
-
body: {
|
|
167
|
-
apps: apps.map((app) => ({ doc: app.doc, enabled: app.enabled })),
|
|
168
|
-
grants,
|
|
169
|
-
secrets,
|
|
170
|
-
},
|
|
171
|
-
}));
|
|
172
|
-
if (args.includes("--json"))
|
|
173
|
-
printJson(context.output, response);
|
|
174
|
-
else
|
|
175
|
-
printDeploySummary(context, response);
|
|
176
|
-
return 0;
|
|
177
|
-
}
|
|
178
|
-
catch (error) {
|
|
179
|
-
if (error instanceof CloudError && error.code === "cloud-required") {
|
|
180
|
-
context.output.error("This key's org needs a Cloud plan (cloud-required).");
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
context.output.error(errorMessage(error));
|
|
184
|
-
}
|
|
185
|
-
return 1;
|
|
186
|
-
}
|
|
187
|
-
}
|