@vendoai/vendo 0.4.0
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/LICENSE +202 -0
- package/README.md +28 -0
- package/bin/vendo.mjs +4 -0
- package/dist/ai-sdk.d.ts +35 -0
- package/dist/ai-sdk.js +62 -0
- package/dist/auth-presets/auth-js.d.ts +14 -0
- package/dist/auth-presets/auth-js.js +91 -0
- package/dist/auth-presets/auth0.d.ts +23 -0
- package/dist/auth-presets/auth0.js +98 -0
- package/dist/auth-presets/clerk.d.ts +23 -0
- package/dist/auth-presets/clerk.js +65 -0
- package/dist/auth-presets/conformance.d.ts +42 -0
- package/dist/auth-presets/conformance.js +139 -0
- package/dist/auth-presets/identity.d.ts +56 -0
- package/dist/auth-presets/identity.js +152 -0
- package/dist/auth-presets/index.d.ts +14 -0
- package/dist/auth-presets/index.js +12 -0
- package/dist/auth-presets/jwt.d.ts +16 -0
- package/dist/auth-presets/jwt.js +54 -0
- package/dist/auth-presets/shared.d.ts +35 -0
- package/dist/auth-presets/shared.js +1 -0
- package/dist/auth-presets/supabase.d.ts +42 -0
- package/dist/auth-presets/supabase.js +229 -0
- package/dist/byo-approvals.d.ts +37 -0
- package/dist/byo-approvals.js +189 -0
- package/dist/capability-misses.d.ts +38 -0
- package/dist/capability-misses.js +172 -0
- package/dist/catalog.d.ts +19 -0
- package/dist/catalog.js +152 -0
- package/dist/cli/cloud/args.d.ts +3 -0
- package/dist/cli/cloud/args.js +32 -0
- package/dist/cli/cloud/auth.d.ts +17 -0
- package/dist/cli/cloud/auth.js +123 -0
- package/dist/cli/cloud/client.d.ts +28 -0
- package/dist/cli/cloud/client.js +133 -0
- package/dist/cli/cloud/command.d.ts +22 -0
- package/dist/cli/cloud/command.js +73 -0
- package/dist/cli/cloud/deploy.d.ts +26 -0
- package/dist/cli/cloud/deploy.js +187 -0
- package/dist/cli/cloud/device-login.d.ts +32 -0
- package/dist/cli/cloud/device-login.js +259 -0
- package/dist/cli/cloud/index.d.ts +5 -0
- package/dist/cli/cloud/index.js +59 -0
- package/dist/cli/cloud/keys.d.ts +2 -0
- package/dist/cli/cloud/keys.js +31 -0
- package/dist/cli/cloud/members.d.ts +3 -0
- package/dist/cli/cloud/members.js +25 -0
- package/dist/cli/cloud/output.d.ts +4 -0
- package/dist/cli/cloud/output.js +12 -0
- package/dist/cli/cloud/pending-claim.d.ts +29 -0
- package/dist/cli/cloud/pending-claim.js +38 -0
- package/dist/cli/cloud/read.d.ts +3 -0
- package/dist/cli/cloud/read.js +12 -0
- package/dist/cli/cloud/services.d.ts +2 -0
- package/dist/cli/cloud/services.js +9 -0
- package/dist/cli/cloud/session.d.ts +13 -0
- package/dist/cli/cloud/session.js +41 -0
- package/dist/cli/cloud-init.d.ts +60 -0
- package/dist/cli/cloud-init.js +149 -0
- package/dist/cli/dep-versions.d.ts +26 -0
- package/dist/cli/dep-versions.js +77 -0
- package/dist/cli/doctor-codes.d.ts +58 -0
- package/dist/cli/doctor-codes.js +60 -0
- package/dist/cli/doctor-live.d.ts +67 -0
- package/dist/cli/doctor-live.js +169 -0
- package/dist/cli/doctor.d.ts +52 -0
- package/dist/cli/doctor.js +467 -0
- package/dist/cli/eject.d.ts +29 -0
- package/dist/cli/eject.js +141 -0
- package/dist/cli/extract/apply.d.ts +26 -0
- package/dist/cli/extract/apply.js +123 -0
- package/dist/cli/extract/claude-cli-harness.d.ts +18 -0
- package/dist/cli/extract/claude-cli-harness.js +132 -0
- package/dist/cli/extract/claude-harness.d.ts +14 -0
- package/dist/cli/extract/claude-harness.js +127 -0
- package/dist/cli/extract/codex-cli-harness.d.ts +31 -0
- package/dist/cli/extract/codex-cli-harness.js +154 -0
- package/dist/cli/extract/delegate.d.ts +21 -0
- package/dist/cli/extract/delegate.js +77 -0
- package/dist/cli/extract/extraction.d.ts +65 -0
- package/dist/cli/extract/extraction.js +300 -0
- package/dist/cli/extract/gateway-fuel.d.ts +69 -0
- package/dist/cli/extract/gateway-fuel.js +69 -0
- package/dist/cli/extract/harness.d.ts +114 -0
- package/dist/cli/extract/harness.js +84 -0
- package/dist/cli/extract/index.d.ts +9 -0
- package/dist/cli/extract/index.js +9 -0
- package/dist/cli/extract/npx-engine-harness.d.ts +73 -0
- package/dist/cli/extract/npx-engine-harness.js +225 -0
- package/dist/cli/extract/stages.d.ts +149 -0
- package/dist/cli/extract/stages.js +398 -0
- package/dist/cli/framework.d.ts +8 -0
- package/dist/cli/framework.js +36 -0
- package/dist/cli/init-auth.d.ts +67 -0
- package/dist/cli/init-auth.js +142 -0
- package/dist/cli/init-scaffolds.d.ts +28 -0
- package/dist/cli/init-scaffolds.js +235 -0
- package/dist/cli/init.d.ts +115 -0
- package/dist/cli/init.js +1008 -0
- package/dist/cli/mcp/index.d.ts +7 -0
- package/dist/cli/mcp/index.js +59 -0
- package/dist/cli/mcp/registry.d.ts +9 -0
- package/dist/cli/mcp/registry.js +117 -0
- package/dist/cli/mcp/server-json.d.ts +12 -0
- package/dist/cli/mcp/server-json.js +65 -0
- package/dist/cli/mcp/server.schema.json +574 -0
- package/dist/cli/mcp/verify-domain.d.ts +11 -0
- package/dist/cli/mcp/verify-domain.js +48 -0
- package/dist/cli/playground/app/embed-entry.d.ts +20 -0
- package/dist/cli/playground/app/embed-entry.js +46 -0
- package/dist/cli/playground/app/fake-client.d.ts +3 -0
- package/dist/cli/playground/app/fake-client.js +215 -0
- package/dist/cli/playground/app/fixtures.d.ts +47 -0
- package/dist/cli/playground/app/fixtures.js +472 -0
- package/dist/cli/playground/app/main.d.ts +1 -0
- package/dist/cli/playground/app/main.js +108 -0
- package/dist/cli/playground/app/scenario-mount.d.ts +13 -0
- package/dist/cli/playground/app/scenario-mount.js +48 -0
- package/dist/cli/playground/app/scenarios.d.ts +25 -0
- package/dist/cli/playground/app/scenarios.js +152 -0
- package/dist/cli/playground/app/theme-editor.d.ts +13 -0
- package/dist/cli/playground/app/theme-editor.js +149 -0
- package/dist/cli/playground/app/theme-state.d.ts +29 -0
- package/dist/cli/playground/app/theme-state.js +151 -0
- package/dist/cli/playground/bundle.gen.d.ts +2 -0
- package/dist/cli/playground/bundle.gen.js +2 -0
- package/dist/cli/playground/embed-bundle.gen.d.ts +2 -0
- package/dist/cli/playground/embed-bundle.gen.js +2 -0
- package/dist/cli/playground.d.ts +33 -0
- package/dist/cli/playground.js +120 -0
- package/dist/cli/pretty.d.ts +48 -0
- package/dist/cli/pretty.js +330 -0
- package/dist/cli/refine.d.ts +43 -0
- package/dist/cli/refine.js +181 -0
- package/dist/cli/semantics.d.ts +31 -0
- package/dist/cli/semantics.js +122 -0
- package/dist/cli/shared.d.ts +68 -0
- package/dist/cli/shared.js +184 -0
- package/dist/cli/sync.d.ts +36 -0
- package/dist/cli/sync.js +202 -0
- package/dist/cli/theme/color.d.ts +15 -0
- package/dist/cli/theme/color.js +188 -0
- package/dist/cli/theme/css-vars.d.ts +13 -0
- package/dist/cli/theme/css-vars.js +40 -0
- package/dist/cli/theme/entry-candidates.d.ts +5 -0
- package/dist/cli/theme/entry-candidates.js +22 -0
- package/dist/cli/theme/extract-theme.d.ts +184 -0
- package/dist/cli/theme/extract-theme.js +358 -0
- package/dist/cli/theme/walk.d.ts +2 -0
- package/dist/cli/theme/walk.js +24 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +333 -0
- package/dist/cloud-apps.d.ts +17 -0
- package/dist/cloud-apps.js +46 -0
- package/dist/cloud-console.d.ts +32 -0
- package/dist/cloud-console.js +72 -0
- package/dist/cloud-tools.d.ts +23 -0
- package/dist/cloud-tools.js +196 -0
- package/dist/connections.d.ts +71 -0
- package/dist/connections.js +192 -0
- package/dist/deployment-identity.d.ts +12 -0
- package/dist/deployment-identity.js +69 -0
- package/dist/dev-creds/model.d.ts +65 -0
- package/dist/dev-creds/model.js +159 -0
- package/dist/dev-creds/resolve.d.ts +36 -0
- package/dist/dev-creds/resolve.js +57 -0
- package/dist/hosted-store.d.ts +52 -0
- package/dist/hosted-store.js +322 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +1 -0
- package/dist/mastra.d.ts +46 -0
- package/dist/mastra.js +88 -0
- package/dist/react.d.ts +10 -0
- package/dist/react.js +32 -0
- package/dist/refine.d.ts +244 -0
- package/dist/refine.js +599 -0
- package/dist/remixable.d.ts +18 -0
- package/dist/remixable.js +42 -0
- package/dist/runtime-capture.d.ts +18 -0
- package/dist/runtime-capture.js +111 -0
- package/dist/sandbox-wire.d.ts +101 -0
- package/dist/sandbox-wire.js +101 -0
- package/dist/sandbox.d.ts +38 -0
- package/dist/sandbox.js +389 -0
- package/dist/server.d.ts +216 -0
- package/dist/server.js +1320 -0
- package/dist/sync-impact.d.ts +14 -0
- package/dist/sync-impact.js +75 -0
- package/dist/turn-liveness.d.ts +33 -0
- package/dist/turn-liveness.js +105 -0
- package/dist/wire/approvals.d.ts +10 -0
- package/dist/wire/approvals.js +59 -0
- package/dist/wire/apps.d.ts +5 -0
- package/dist/wire/apps.js +155 -0
- package/dist/wire/automations.d.ts +5 -0
- package/dist/wire/automations.js +57 -0
- package/dist/wire/box.d.ts +3 -0
- package/dist/wire/box.js +268 -0
- package/dist/wire/connections.d.ts +5 -0
- package/dist/wire/connections.js +47 -0
- package/dist/wire/context.d.ts +22 -0
- package/dist/wire/context.js +190 -0
- package/dist/wire/doctor.d.ts +19 -0
- package/dist/wire/doctor.js +116 -0
- package/dist/wire/misc.d.ts +18 -0
- package/dist/wire/misc.js +227 -0
- package/dist/wire/shared.d.ts +158 -0
- package/dist/wire/shared.js +134 -0
- package/dist/wire/threads.d.ts +3 -0
- package/dist/wire/threads.js +68 -0
- package/package.json +151 -0
- package/skills/vendo-setup/SKILL.md +128 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { realpathSync } from "node:fs";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
import { isVendoKey } from "./cli/cloud/client.js";
|
|
4
|
+
import { runLoginCommand } from "./cli/cloud/device-login.js";
|
|
5
|
+
import { runCloud } from "./cli/cloud/index.js";
|
|
6
|
+
import { runDoctor } from "./cli/doctor.js";
|
|
7
|
+
import { runEject } from "./cli/eject.js";
|
|
8
|
+
import { runExtractApply } from "./cli/extract/apply.js";
|
|
9
|
+
import { runInit } from "./cli/init.js";
|
|
10
|
+
import { runMcp } from "./cli/mcp/index.js";
|
|
11
|
+
import { runPlayground } from "./cli/playground.js";
|
|
12
|
+
import { runRefineCommand } from "./cli/refine.js";
|
|
13
|
+
import { CLI_VERSION } from "./cli/shared.js";
|
|
14
|
+
import { runSync } from "./cli/sync.js";
|
|
15
|
+
const HELP = `vendo — install your product's agent
|
|
16
|
+
|
|
17
|
+
Usage: vendo <command> [dir] [options]
|
|
18
|
+
|
|
19
|
+
Commands:
|
|
20
|
+
init [dir] Set up Vendo: wire the handler, extract tools + theme, resolve a model key
|
|
21
|
+
login [email] Claim a Vendo Cloud key: approve in the browser; the key lands in .env.local
|
|
22
|
+
doctor [dir] Verify the install: wiring, live probes, and one real model turn (--json for agents)
|
|
23
|
+
|
|
24
|
+
Advanced:
|
|
25
|
+
sync [dir] Re-extract tools and baselines (init hooks this into predev/prebuild; --strict is the CI gate)
|
|
26
|
+
eject <surface> [dir] Copy a shipped chrome surface's presentation source into your repo (--list to see surfaces)
|
|
27
|
+
extract [dir] Apply a coding agent's extraction draft through the deterministic guards (--apply <draft.json>)
|
|
28
|
+
refine [dir] Propose compound capabilities, risk corrections, and brief updates as reviewable diffs
|
|
29
|
+
playground Render every Vendo surface against scripted data in the browser — no model key needed
|
|
30
|
+
mcp <command> Generate MCP registry discovery and domain-verification files
|
|
31
|
+
cloud <command> Use the public Vendo Cloud API
|
|
32
|
+
|
|
33
|
+
Options:
|
|
34
|
+
--agent Init only: print a read-only JSON plan — code changes, extracted tools, risk recommendations, the aiPolish delegation contract
|
|
35
|
+
--apply <draft.json> Extract only: draft file an external agent produced from the plan's aiPolish contract
|
|
36
|
+
--yes Init: skip the cloud-login offer; refine: approve displayed diffs; doctor: auto-start the dev server
|
|
37
|
+
--force Init/server-json: overwrite owned or generated files; eject: overwrite an ejected dir
|
|
38
|
+
--auth <preset> Init only: wire this auth preset without asking (authJs, clerk, supabase, auth0, jwt, none)
|
|
39
|
+
--framework <name> Init only: override framework detection (next, express) — required non-interactively when detection fails
|
|
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
|
+
--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
|
+
--byo Init only: decline the Vendo Cloud offer (bring your own model key)
|
|
44
|
+
--ai-polish Init only: consent to the AI extraction pass without a prompt (works non-interactively)
|
|
45
|
+
--engine <name> Init only: pin the AI-polish engine (claude, codex, npx) instead of first-available
|
|
46
|
+
--theme <slot=value> Init only: override a theme slot value directly (repeatable)
|
|
47
|
+
--list Eject only: show the ejectable surfaces
|
|
48
|
+
--model-import <specifier> Refine only: module exporting the host's ai-SDK model
|
|
49
|
+
--ask <text> Refine only: interview answer (repeatable) for non-interactive runs
|
|
50
|
+
--url <url> Doctor/refine/server-json: mounted wire base or public MCP URL
|
|
51
|
+
--strict Sync only: exit 2 on breaking changes, 3 when saved references are impacted
|
|
52
|
+
--port <port> Playground only: listen on a fixed port (default: any free port)
|
|
53
|
+
--no-open Playground only: print the URL without opening the browser
|
|
54
|
+
--json Sync/doctor: print one machine-readable report object
|
|
55
|
+
--report Sync only: push the report to Vendo Cloud
|
|
56
|
+
--key <key> Sync/cloud: override VENDO_API_KEY
|
|
57
|
+
--api-url <url> Sync/cloud/login: override VENDO_CLOUD_URL
|
|
58
|
+
--version Print the version
|
|
59
|
+
`;
|
|
60
|
+
function option(args, name) {
|
|
61
|
+
const exact = args.indexOf(name);
|
|
62
|
+
if (exact >= 0)
|
|
63
|
+
return args[exact + 1];
|
|
64
|
+
return args.find((value) => value.startsWith(`${name}=`))?.slice(name.length + 1);
|
|
65
|
+
}
|
|
66
|
+
function options(args, name) {
|
|
67
|
+
const values = [];
|
|
68
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
69
|
+
if (args[index] === name && args[index + 1] !== undefined)
|
|
70
|
+
values.push(args[index + 1]);
|
|
71
|
+
else if (args[index].startsWith(`${name}=`))
|
|
72
|
+
values.push(args[index].slice(name.length + 1));
|
|
73
|
+
}
|
|
74
|
+
return values;
|
|
75
|
+
}
|
|
76
|
+
const INIT_FLAGS = new Set(["--agent", "--yes", "--force", "--byo", "--ai-polish"]);
|
|
77
|
+
const INIT_VALUE_OPTIONS = ["--auth", "--framework", "--cloud-key", "--theme", "--engine"];
|
|
78
|
+
/** Agent-install-dx: every init wizard question has a value-flag answer; a
|
|
79
|
+
bad value fails as loudly as an unknown flag, with the valid choices. */
|
|
80
|
+
const INIT_AUTH_VALUES = ["authJs", "clerk", "supabase", "auth0", "jwt", "none"];
|
|
81
|
+
const INIT_FRAMEWORK_VALUES = ["next", "express"];
|
|
82
|
+
const INIT_ENGINE_VALUES = ["claude", "codex", "npx"];
|
|
83
|
+
const EXTRACT_FLAGS = new Set(["--force"]);
|
|
84
|
+
const EXTRACT_VALUE_OPTIONS = ["--apply"];
|
|
85
|
+
const DOCTOR_FLAGS = new Set(["--json", "--yes"]);
|
|
86
|
+
const DOCTOR_VALUE_OPTIONS = ["--url"];
|
|
87
|
+
const REFINE_FLAGS = new Set(["--yes"]);
|
|
88
|
+
const REFINE_VALUE_OPTIONS = ["--url", "--model-import", "--ask"];
|
|
89
|
+
const SYNC_FLAGS = new Set(["--strict", "--json", "--report"]);
|
|
90
|
+
const SYNC_VALUE_OPTIONS = ["--url", "--key", "--api-url"];
|
|
91
|
+
const LOGIN_VALUE_OPTIONS = ["--email", "--api-url", "--wait"];
|
|
92
|
+
/** ENG-335: options the CLI does not recognize — or value options missing
|
|
93
|
+
their value — must fail loudly before anything runs. Silently dropping a
|
|
94
|
+
flag is how the "--agent writes nothing" promise broke in the field: an
|
|
95
|
+
older CLI ignored --agent and ran a full, writing init. */
|
|
96
|
+
function optionErrors(args, flags, valueOptions) {
|
|
97
|
+
const errors = [];
|
|
98
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
99
|
+
const arg = args[index];
|
|
100
|
+
if (!arg.startsWith("--"))
|
|
101
|
+
continue;
|
|
102
|
+
if (flags.has(arg))
|
|
103
|
+
continue;
|
|
104
|
+
if (valueOptions.includes(arg)) {
|
|
105
|
+
// A value that looks like another flag is a missing value, not a value —
|
|
106
|
+
// otherwise `--model-import --force` proceeds with modelImport "--force".
|
|
107
|
+
const value = args[index + 1];
|
|
108
|
+
if (value === undefined || value.startsWith("--"))
|
|
109
|
+
errors.push(`${arg} requires a value`);
|
|
110
|
+
else
|
|
111
|
+
index += 1;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (valueOptions.some((name) => arg.startsWith(`${name}=`)))
|
|
115
|
+
continue;
|
|
116
|
+
errors.push(`unknown option: ${arg}`);
|
|
117
|
+
}
|
|
118
|
+
return errors;
|
|
119
|
+
}
|
|
120
|
+
/** Playground follows the ENG-335 rule too: unknown flags fail loudly. */
|
|
121
|
+
function playgroundOptionErrors(args) {
|
|
122
|
+
const errors = [];
|
|
123
|
+
let port;
|
|
124
|
+
const parsePort = (value, flag) => {
|
|
125
|
+
const parsed = value !== undefined && /^\d+$/.test(value) ? Number(value) : NaN;
|
|
126
|
+
if (Number.isInteger(parsed) && parsed >= 1 && parsed <= 65_535)
|
|
127
|
+
port = parsed;
|
|
128
|
+
else
|
|
129
|
+
errors.push(`${flag} requires a port number (1-65535)`);
|
|
130
|
+
};
|
|
131
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
132
|
+
const arg = args[index];
|
|
133
|
+
if (arg === "--no-open")
|
|
134
|
+
continue;
|
|
135
|
+
if (arg === "--port") {
|
|
136
|
+
const value = args[index + 1];
|
|
137
|
+
parsePort(value !== undefined && value.startsWith("--") ? undefined : value, "--port");
|
|
138
|
+
if (value !== undefined && !value.startsWith("--"))
|
|
139
|
+
index += 1;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (arg.startsWith("--port=")) {
|
|
143
|
+
parsePort(arg.slice("--port=".length), "--port");
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
errors.push(arg.startsWith("--") ? `unknown option: ${arg}` : `unexpected argument: ${arg}`);
|
|
147
|
+
}
|
|
148
|
+
return { errors, port };
|
|
149
|
+
}
|
|
150
|
+
function target(args) {
|
|
151
|
+
const optionValues = new Set();
|
|
152
|
+
for (const name of ["--model-import", "--url", "--key", "--api-url", "--ask", "--apply",
|
|
153
|
+
"--auth", "--framework", "--cloud-key", "--theme"]) {
|
|
154
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
155
|
+
if (args[index] === name && args[index + 1] !== undefined)
|
|
156
|
+
optionValues.add(args[index + 1]);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return args.find((value) => !value.startsWith("--") && !optionValues.has(value)) ?? process.cwd();
|
|
160
|
+
}
|
|
161
|
+
export async function main(argv) {
|
|
162
|
+
const [command, ...args] = argv;
|
|
163
|
+
if (command === undefined || command === "--help" || command === "-h") {
|
|
164
|
+
console.log(HELP);
|
|
165
|
+
return 0;
|
|
166
|
+
}
|
|
167
|
+
if (command === "--version" || command === "-v") {
|
|
168
|
+
console.log(CLI_VERSION);
|
|
169
|
+
return 0;
|
|
170
|
+
}
|
|
171
|
+
if (command === "login") {
|
|
172
|
+
const problems = optionErrors(args, new Set(), LOGIN_VALUE_OPTIONS);
|
|
173
|
+
const wait = option(args, "--wait");
|
|
174
|
+
if (wait !== undefined && !/^\d+$/.test(wait)) {
|
|
175
|
+
problems.push("--wait takes a whole number of seconds (example: vendo login --wait 90)");
|
|
176
|
+
}
|
|
177
|
+
if (problems.length > 0) {
|
|
178
|
+
console.error(`vendo login: ${problems.join("; ")}\n\n${HELP}`);
|
|
179
|
+
return 1;
|
|
180
|
+
}
|
|
181
|
+
return runLoginCommand(args);
|
|
182
|
+
}
|
|
183
|
+
if (command === "cloud")
|
|
184
|
+
return runCloud(args);
|
|
185
|
+
if (command === "mcp")
|
|
186
|
+
return runMcp(args);
|
|
187
|
+
if (command === "init") {
|
|
188
|
+
const problems = optionErrors(args, INIT_FLAGS, INIT_VALUE_OPTIONS);
|
|
189
|
+
const auth = option(args, "--auth");
|
|
190
|
+
if (auth !== undefined && !INIT_AUTH_VALUES.includes(auth)) {
|
|
191
|
+
problems.push(`--auth must be one of ${INIT_AUTH_VALUES.join(", ")} (example: vendo init --auth clerk)`);
|
|
192
|
+
}
|
|
193
|
+
const framework = option(args, "--framework");
|
|
194
|
+
if (framework !== undefined && !INIT_FRAMEWORK_VALUES.includes(framework)) {
|
|
195
|
+
problems.push("--framework must be next or express (example: vendo init --framework next)");
|
|
196
|
+
}
|
|
197
|
+
const cloudKey = option(args, "--cloud-key");
|
|
198
|
+
if (cloudKey !== undefined && !isVendoKey(cloudKey)) {
|
|
199
|
+
problems.push("--cloud-key must be a Vendo Cloud key (vnd_ + 40 hex; `vendo login` issues one)");
|
|
200
|
+
}
|
|
201
|
+
const engine = option(args, "--engine");
|
|
202
|
+
if (engine !== undefined && !INIT_ENGINE_VALUES.includes(engine)) {
|
|
203
|
+
problems.push(`--engine must be one of ${INIT_ENGINE_VALUES.join(", ")} (example: vendo init --engine codex)`);
|
|
204
|
+
}
|
|
205
|
+
if (cloudKey !== undefined && args.includes("--byo")) {
|
|
206
|
+
problems.push("--cloud-key and --byo answer the same question — pass one or the other");
|
|
207
|
+
}
|
|
208
|
+
const themePairs = options(args, "--theme");
|
|
209
|
+
const badTheme = themePairs.find((pair) => !/^[A-Za-z]+=./.test(pair));
|
|
210
|
+
if (badTheme !== undefined) {
|
|
211
|
+
problems.push(`--theme takes slot=value (example: vendo init --theme accent=#7c3bed), got ${JSON.stringify(badTheme)}`);
|
|
212
|
+
}
|
|
213
|
+
if (problems.length > 0) {
|
|
214
|
+
console.error(`vendo init: ${problems.join("; ")}\n\n${HELP}`);
|
|
215
|
+
return 1;
|
|
216
|
+
}
|
|
217
|
+
return runInit({
|
|
218
|
+
targetDir: target(args),
|
|
219
|
+
agent: args.includes("--agent"),
|
|
220
|
+
yes: args.includes("--yes"),
|
|
221
|
+
force: args.includes("--force"),
|
|
222
|
+
...(auth === undefined ? {} : { auth: auth }),
|
|
223
|
+
...(framework === undefined ? {} : { framework: framework }),
|
|
224
|
+
...(cloudKey === undefined ? {} : { cloudKey }),
|
|
225
|
+
...(args.includes("--byo") ? { byo: true } : {}),
|
|
226
|
+
...(args.includes("--ai-polish") ? { aiPolish: true } : {}),
|
|
227
|
+
...(engine === undefined ? {} : { engine }),
|
|
228
|
+
...(themePairs.length === 0 ? {} : {
|
|
229
|
+
themeAnswers: Object.fromEntries(themePairs.map((pair) => {
|
|
230
|
+
const at = pair.indexOf("=");
|
|
231
|
+
return [pair.slice(0, at), pair.slice(at + 1)];
|
|
232
|
+
})),
|
|
233
|
+
}),
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
if (command === "extract") {
|
|
237
|
+
const problems = optionErrors(args, EXTRACT_FLAGS, EXTRACT_VALUE_OPTIONS);
|
|
238
|
+
if (!args.some((arg) => arg === "--apply" || arg.startsWith("--apply="))) {
|
|
239
|
+
problems.push("--apply <draft.json> is required");
|
|
240
|
+
}
|
|
241
|
+
else if (option(args, "--apply") === "") {
|
|
242
|
+
// `--apply=` slips past the missing-value check with an empty string,
|
|
243
|
+
// which would resolve to the cwd instead of failing loudly.
|
|
244
|
+
problems.push("--apply requires a value");
|
|
245
|
+
}
|
|
246
|
+
if (problems.length > 0) {
|
|
247
|
+
console.error(`vendo extract: ${problems.join("; ")}\n\n${HELP}`);
|
|
248
|
+
return 1;
|
|
249
|
+
}
|
|
250
|
+
return runExtractApply({
|
|
251
|
+
targetDir: target(args),
|
|
252
|
+
apply: option(args, "--apply"),
|
|
253
|
+
force: args.includes("--force"),
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
if (command === "eject") {
|
|
257
|
+
const positional = args.filter((value) => !value.startsWith("--"));
|
|
258
|
+
const list = args.includes("--list");
|
|
259
|
+
// `eject --list [dir]` has no surface positional — the first one is the dir.
|
|
260
|
+
return runEject({
|
|
261
|
+
surface: list ? undefined : positional[0],
|
|
262
|
+
targetDir: (list ? positional[0] : positional[1]) ?? process.cwd(),
|
|
263
|
+
list,
|
|
264
|
+
force: args.includes("--force"),
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
if (command === "doctor") {
|
|
268
|
+
const problems = optionErrors(args, DOCTOR_FLAGS, DOCTOR_VALUE_OPTIONS);
|
|
269
|
+
if (problems.length > 0) {
|
|
270
|
+
console.error(`vendo doctor: ${problems.join("; ")}\n\n${HELP}`);
|
|
271
|
+
return 1;
|
|
272
|
+
}
|
|
273
|
+
return runDoctor({
|
|
274
|
+
targetDir: target(args),
|
|
275
|
+
url: option(args, "--url"),
|
|
276
|
+
json: args.includes("--json"),
|
|
277
|
+
yes: args.includes("--yes"),
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
if (command === "refine") {
|
|
281
|
+
const problems = optionErrors(args, REFINE_FLAGS, REFINE_VALUE_OPTIONS);
|
|
282
|
+
if (problems.length > 0) {
|
|
283
|
+
console.error(`vendo refine: ${problems.join("; ")}\n\n${HELP}`);
|
|
284
|
+
return 1;
|
|
285
|
+
}
|
|
286
|
+
return runRefineCommand({
|
|
287
|
+
targetDir: target(args),
|
|
288
|
+
url: option(args, "--url"),
|
|
289
|
+
modelImport: option(args, "--model-import"),
|
|
290
|
+
asks: options(args, "--ask"),
|
|
291
|
+
yes: args.includes("--yes"),
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
if (command === "playground") {
|
|
295
|
+
const { errors, port } = playgroundOptionErrors(args);
|
|
296
|
+
if (errors.length > 0) {
|
|
297
|
+
console.error(`vendo playground: ${errors.join("; ")}\n\n${HELP}`);
|
|
298
|
+
return 1;
|
|
299
|
+
}
|
|
300
|
+
return runPlayground({ port, open: !args.includes("--no-open") });
|
|
301
|
+
}
|
|
302
|
+
if (command === "sync") {
|
|
303
|
+
const problems = optionErrors(args, SYNC_FLAGS, SYNC_VALUE_OPTIONS);
|
|
304
|
+
if (problems.length > 0) {
|
|
305
|
+
console.error(`vendo sync: ${problems.join("; ")}\n\n${HELP}`);
|
|
306
|
+
return 1;
|
|
307
|
+
}
|
|
308
|
+
return runSync({
|
|
309
|
+
targetDir: target(args),
|
|
310
|
+
strict: args.includes("--strict"),
|
|
311
|
+
url: option(args, "--url"),
|
|
312
|
+
json: args.includes("--json"),
|
|
313
|
+
report: args.includes("--report"),
|
|
314
|
+
apiKey: option(args, "--key"),
|
|
315
|
+
apiUrl: option(args, "--api-url"),
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
console.error(`Unknown command: ${command}\n\n${HELP}`);
|
|
319
|
+
return 1;
|
|
320
|
+
}
|
|
321
|
+
export function isCliEntrypoint(metaUrl, argv1) {
|
|
322
|
+
if (argv1 === undefined)
|
|
323
|
+
return false;
|
|
324
|
+
try {
|
|
325
|
+
return metaUrl === pathToFileURL(realpathSync(argv1)).href;
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (isCliEntrypoint(import.meta.url, process.argv[1])) {
|
|
332
|
+
void main(process.argv.slice(2)).then((code) => { process.exitCode = code; });
|
|
333
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type CloudAppsClient } from "@vendoai/apps";
|
|
2
|
+
/** The Cloud share/publish client — the implementation the composition seam
|
|
3
|
+
* (createVendo) injects into the apps block's CloudAppsClient seam when
|
|
4
|
+
* VENDO_API_KEY fills the unset slot (adapter rule — see selectConnections in
|
|
5
|
+
* server.ts; the block itself never reads the environment). Rides the shared
|
|
6
|
+
* console-client plumbing (cloud-console.ts): Bearer auth + deployment
|
|
7
|
+
* identity + per-request abort timeout + the honest 401/402 → cloud-required
|
|
8
|
+
* error table. */
|
|
9
|
+
export interface CloudAppsOptions {
|
|
10
|
+
apiKey: string;
|
|
11
|
+
/** Defaults to the Vendo console; the composition seam passes VENDO_CLOUD_URL. */
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
fetch?: typeof fetch;
|
|
14
|
+
/** Per-request abort budget (default 30s, hosted-store's). */
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function cloudApps(options: CloudAppsOptions): CloudAppsClient;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { publishRecordSchema, shareSnapshotSchema, } from "@vendoai/apps";
|
|
2
|
+
import { consoleSender, raiseCloudError } from "./cloud-console.js";
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
4
|
+
/** The console mounts the share/publish surface here. */
|
|
5
|
+
const CONSOLE_APPS_PATH = "/api/v1/apps";
|
|
6
|
+
/** Shared console error table: 401/402 → cloud-required, wire-legal envelope
|
|
7
|
+
* codes forward as VendoErrors, anything else (unknown codes, 5xx, non-JSON
|
|
8
|
+
* bodies) rides a plain Error with the server's code attached — never a
|
|
9
|
+
* "validation" error blaming the caller for the console misbehaving. */
|
|
10
|
+
const raiseAppsError = (response) => raiseCloudError(response, "apps", (code, message) => {
|
|
11
|
+
throw Object.assign(new Error(message), { code: code ?? "unavailable" });
|
|
12
|
+
});
|
|
13
|
+
export function cloudApps(options) {
|
|
14
|
+
const base = (options.baseUrl ?? "https://console.vendo.run").replace(/\/$/, "");
|
|
15
|
+
const send = consoleSender({
|
|
16
|
+
base,
|
|
17
|
+
mountPath: CONSOLE_APPS_PATH,
|
|
18
|
+
apiKey: options.apiKey,
|
|
19
|
+
timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
20
|
+
fetchImpl: options.fetch ?? globalThis.fetch,
|
|
21
|
+
raise: raiseAppsError,
|
|
22
|
+
});
|
|
23
|
+
const post = async (path, appId, doc, schema) => {
|
|
24
|
+
const response = await send(path, {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: { "content-type": "application/json" },
|
|
27
|
+
body: JSON.stringify({ appId, doc }),
|
|
28
|
+
});
|
|
29
|
+
let payload;
|
|
30
|
+
try {
|
|
31
|
+
payload = await response.json();
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// hosted-store's malformed-200 posture: a 2xx that isn't JSON means a
|
|
35
|
+
// misdeployed Cloud base — the SERVICE misbehaving, never the caller's
|
|
36
|
+
// fault, so this is a plain Error (not a wire-legal "validation" code
|
|
37
|
+
// that would blame the share/publish input).
|
|
38
|
+
throw new Error(`Vendo Cloud apps returned a non-JSON ${response.status} response — check VENDO_CLOUD_URL`);
|
|
39
|
+
}
|
|
40
|
+
return schema.parse(payload);
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
share: (appId, doc) => post("/share", appId, doc, shareSnapshotSchema),
|
|
44
|
+
publish: (appId, doc) => post("/publish", appId, doc, publishRecordSchema),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Console-client plumbing shared by the Cloud adapters (cloudSandbox,
|
|
2
|
+
* hostedStore, cloudConnections, cloudApps): the wire-legal error table, the
|
|
3
|
+
* enveloped-error raise, and the key-authed sender. Behavior still comes
|
|
4
|
+
* ONLY from each adapter's constructor arguments (adapter rule — see
|
|
5
|
+
* selectSandbox/selectStore in server.ts); nothing here reads the
|
|
6
|
+
* environment. */
|
|
7
|
+
/** Console error codes forwarded as-is when they are wire-legal VendoError
|
|
8
|
+
* codes (same posture as the cloudApps share/publish client). The
|
|
9
|
+
* console's "unavailable"/"unauthorized"/"quota-exhausted" have no VendoError
|
|
10
|
+
* twin; unknown codes fall to each adapter's own tail, and the 402/401 →
|
|
11
|
+
* cloud-required mapping handles the meter/key cases. */
|
|
12
|
+
export declare const CLOUD_ERROR_CODES: ReadonlySet<string>;
|
|
13
|
+
export declare const toArrayBuffer: (value: Uint8Array) => ArrayBuffer;
|
|
14
|
+
/** Parse the console's error envelope and throw. The console's meter gate
|
|
15
|
+
* (quota-exhausted) rides HTTP 402 — the one "pay/upgrade to proceed" signal,
|
|
16
|
+
* same mapping as cloudConnections. 401 (bad/revoked key) is the same "fix
|
|
17
|
+
* your Cloud standing" story for the host operator, so it keeps the ENG-295
|
|
18
|
+
* client's cloud-required mapping — with the server's own message preserved.
|
|
19
|
+
* Wire-legal codes forward as VendoErrors; anything else (unknown codes, 5xx,
|
|
20
|
+
* non-JSON bodies) goes to the adapter's own `onUnknownCode` tail. */
|
|
21
|
+
export declare function raiseCloudError(response: Response, service: string, onUnknownCode: (code: string | undefined, message: string) => never): Promise<never>;
|
|
22
|
+
/** The key-authed console sender: Bearer auth + deployment identity (the
|
|
23
|
+
* console meters usage from real traffic) + per-request abort timeout, raising
|
|
24
|
+
* through the adapter's own error mapping on any non-2xx. */
|
|
25
|
+
export declare function consoleSender(options: {
|
|
26
|
+
base: string;
|
|
27
|
+
mountPath: string;
|
|
28
|
+
apiKey: string;
|
|
29
|
+
timeoutMs: number;
|
|
30
|
+
fetchImpl: typeof fetch;
|
|
31
|
+
raise: (response: Response) => Promise<never>;
|
|
32
|
+
}): (path: string, init?: RequestInit) => Promise<Response>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { VendoError } from "@vendoai/core";
|
|
2
|
+
import { deploymentIdentityHeaders } from "./deployment-identity.js";
|
|
3
|
+
/** Console-client plumbing shared by the Cloud adapters (cloudSandbox,
|
|
4
|
+
* hostedStore, cloudConnections, cloudApps): the wire-legal error table, the
|
|
5
|
+
* enveloped-error raise, and the key-authed sender. Behavior still comes
|
|
6
|
+
* ONLY from each adapter's constructor arguments (adapter rule — see
|
|
7
|
+
* selectSandbox/selectStore in server.ts); nothing here reads the
|
|
8
|
+
* environment. */
|
|
9
|
+
/** Console error codes forwarded as-is when they are wire-legal VendoError
|
|
10
|
+
* codes (same posture as the cloudApps share/publish client). The
|
|
11
|
+
* console's "unavailable"/"unauthorized"/"quota-exhausted" have no VendoError
|
|
12
|
+
* twin; unknown codes fall to each adapter's own tail, and the 402/401 →
|
|
13
|
+
* cloud-required mapping handles the meter/key cases. */
|
|
14
|
+
export const CLOUD_ERROR_CODES = new Set([
|
|
15
|
+
"validation",
|
|
16
|
+
"blocked",
|
|
17
|
+
"not-implemented",
|
|
18
|
+
"cloud-required",
|
|
19
|
+
"not-found",
|
|
20
|
+
"conflict",
|
|
21
|
+
]);
|
|
22
|
+
export const toArrayBuffer = (value) => value.slice().buffer;
|
|
23
|
+
/** Parse the console's error envelope and throw. The console's meter gate
|
|
24
|
+
* (quota-exhausted) rides HTTP 402 — the one "pay/upgrade to proceed" signal,
|
|
25
|
+
* same mapping as cloudConnections. 401 (bad/revoked key) is the same "fix
|
|
26
|
+
* your Cloud standing" story for the host operator, so it keeps the ENG-295
|
|
27
|
+
* client's cloud-required mapping — with the server's own message preserved.
|
|
28
|
+
* Wire-legal codes forward as VendoErrors; anything else (unknown codes, 5xx,
|
|
29
|
+
* non-JSON bodies) goes to the adapter's own `onUnknownCode` tail. */
|
|
30
|
+
export async function raiseCloudError(response, service, onUnknownCode) {
|
|
31
|
+
let payload;
|
|
32
|
+
try {
|
|
33
|
+
payload = JSON.parse(await response.text());
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
payload = undefined;
|
|
37
|
+
}
|
|
38
|
+
const error = typeof payload === "object" && payload !== null && "error" in payload
|
|
39
|
+
? payload.error
|
|
40
|
+
: undefined;
|
|
41
|
+
const message = typeof error?.message === "string"
|
|
42
|
+
? error.message
|
|
43
|
+
: `Vendo Cloud ${service} request failed with ${response.status}`;
|
|
44
|
+
if (response.status === 402 || response.status === 401) {
|
|
45
|
+
throw new VendoError("cloud-required", message);
|
|
46
|
+
}
|
|
47
|
+
const code = typeof error?.code === "string" ? error.code : undefined;
|
|
48
|
+
if (code !== undefined && CLOUD_ERROR_CODES.has(code)) {
|
|
49
|
+
throw new VendoError(code, message);
|
|
50
|
+
}
|
|
51
|
+
return onUnknownCode(code, message);
|
|
52
|
+
}
|
|
53
|
+
/** The key-authed console sender: Bearer auth + deployment identity (the
|
|
54
|
+
* console meters usage from real traffic) + per-request abort timeout, raising
|
|
55
|
+
* through the adapter's own error mapping on any non-2xx. */
|
|
56
|
+
export function consoleSender(options) {
|
|
57
|
+
return async (path, init = {}) => {
|
|
58
|
+
const response = await options.fetchImpl(`${options.base}${options.mountPath}${path}`, {
|
|
59
|
+
...init,
|
|
60
|
+
headers: {
|
|
61
|
+
authorization: `Bearer ${options.apiKey}`,
|
|
62
|
+
accept: "application/json",
|
|
63
|
+
...(await deploymentIdentityHeaders()),
|
|
64
|
+
...init.headers,
|
|
65
|
+
},
|
|
66
|
+
signal: AbortSignal.timeout(options.timeoutMs),
|
|
67
|
+
});
|
|
68
|
+
if (!response.ok)
|
|
69
|
+
await options.raise(response);
|
|
70
|
+
return response;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Connector } from "@vendoai/actions";
|
|
2
|
+
/** The Cloud tools adapter — the execution half of the zero-key Composio
|
|
3
|
+
* seam (cloudConnections is the account half). Tools list and execute ride
|
|
4
|
+
* the console's broker (`GET /api/v1/tools`, `POST /api/v1/tools/execute`),
|
|
5
|
+
* which holds Vendo's Composio credentials and namespaces every call by the
|
|
6
|
+
* caller's org; this connector never sees a Composio key.
|
|
7
|
+
*
|
|
8
|
+
* The connector is named "composio" on purpose: connect-required outcomes,
|
|
9
|
+
* the connect dock's catalog rows, and connection initiation all carry the
|
|
10
|
+
* same connector name, so the whole connect-then-use loop stays one broker
|
|
11
|
+
* from the UI's point of view. */
|
|
12
|
+
export interface CloudToolsOptions {
|
|
13
|
+
apiKey: string;
|
|
14
|
+
/** Defaults to the Vendo console; the composition seam passes VENDO_CLOUD_URL. */
|
|
15
|
+
baseUrl?: string;
|
|
16
|
+
/** Toolkit scoping, same meaning as composioConnector's `apps`. Unset =
|
|
17
|
+
* everything the console's catalog advertises (enabled auth configs).
|
|
18
|
+
* When set, pass the SAME list to cloudConnections({ apps }) so the
|
|
19
|
+
* connect dock's catalog stays in lockstep with the executable tools. */
|
|
20
|
+
apps?: string[];
|
|
21
|
+
fetch?: typeof fetch;
|
|
22
|
+
}
|
|
23
|
+
export declare function cloudTools(options: CloudToolsOptions): Connector;
|