@vm0/cli 9.59.1 → 9.59.3

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.
Files changed (2) hide show
  1. package/index.js +225 -195
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -45,7 +45,7 @@ if (DSN) {
45
45
  Sentry.init({
46
46
  dsn: DSN,
47
47
  environment: process.env.SENTRY_ENVIRONMENT ?? "production",
48
- release: "9.59.1",
48
+ release: "9.59.3",
49
49
  sendDefaultPii: false,
50
50
  tracesSampleRate: 0,
51
51
  shutdownTimeout: 500,
@@ -64,7 +64,7 @@ if (DSN) {
64
64
  }
65
65
  });
66
66
  Sentry.setContext("cli", {
67
- version: "9.59.1",
67
+ version: "9.59.3",
68
68
  command: process.argv.slice(2).join(" ")
69
69
  });
70
70
  Sentry.setContext("runtime", {
@@ -673,7 +673,7 @@ function getConfigPath() {
673
673
  return join2(homedir2(), ".vm0", "config.json");
674
674
  }
675
675
  var infoCommand = new Command6().name("info").description("Display environment and debug information").action(async () => {
676
- console.log(chalk4.bold(`VM0 CLI v${"9.59.1"}`));
676
+ console.log(chalk4.bold(`VM0 CLI v${"9.59.3"}`));
677
677
  console.log();
678
678
  const config = await loadConfig();
679
679
  const hasEnvToken = !!process.env.VM0_TOKEN;
@@ -1227,7 +1227,8 @@ var ALL_RUN_STATUSES = [
1227
1227
  "running",
1228
1228
  "completed",
1229
1229
  "failed",
1230
- "timeout"
1230
+ "timeout",
1231
+ "cancelled"
1231
1232
  ];
1232
1233
  var runStatusSchema = z5.enum(ALL_RUN_STATUSES);
1233
1234
  var unifiedRunRequestSchema = z5.object({
@@ -6571,6 +6572,33 @@ var SERVICE_CONFIGS = {
6571
6572
  "GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs"
6572
6573
  ]
6573
6574
  },
6575
+ {
6576
+ name: "user-read",
6577
+ description: "Read authenticated user profile and related data",
6578
+ rules: [
6579
+ "GET /user",
6580
+ "GET /user/emails",
6581
+ "GET /user/repos",
6582
+ "GET /user/orgs",
6583
+ "GET /user/teams",
6584
+ "GET /user/starred",
6585
+ "GET /user/subscriptions",
6586
+ "GET /users/{username}",
6587
+ "GET /users/{username}/repos",
6588
+ "GET /users/{username}/orgs"
6589
+ ]
6590
+ },
6591
+ {
6592
+ name: "user-write",
6593
+ description: "Update user profile, manage starred repos and email",
6594
+ rules: [
6595
+ "PATCH /user",
6596
+ "POST /user/emails",
6597
+ "DELETE /user/emails",
6598
+ "PUT /user/starred/{owner}/{repo}",
6599
+ "DELETE /user/starred/{owner}/{repo}"
6600
+ ]
6601
+ },
6574
6602
  {
6575
6603
  name: "search",
6576
6604
  description: "Search code, issues, and repositories",
@@ -7005,6 +7033,191 @@ function getServiceConfig(type2) {
7005
7033
  return { ...config, name: type2 };
7006
7034
  }
7007
7035
 
7036
+ // ../../packages/core/src/contracts/service-expander.ts
7037
+ var VALID_RULE_METHODS = /* @__PURE__ */ new Set([
7038
+ "GET",
7039
+ "POST",
7040
+ "PUT",
7041
+ "PATCH",
7042
+ "DELETE",
7043
+ "HEAD",
7044
+ "OPTIONS",
7045
+ "ANY"
7046
+ ]);
7047
+ function validateRule(rule, permName, serviceName) {
7048
+ const parts = rule.split(" ", 2);
7049
+ if (parts.length !== 2 || !parts[1]) {
7050
+ throw new Error(
7051
+ `Invalid rule "${rule}" in permission "${permName}" of service "${serviceName}": must be "METHOD /path"`
7052
+ );
7053
+ }
7054
+ const [method, path18] = parts;
7055
+ if (!VALID_RULE_METHODS.has(method)) {
7056
+ throw new Error(
7057
+ `Invalid rule "${rule}" in permission "${permName}" of service "${serviceName}": unknown method "${method}" (must be uppercase)`
7058
+ );
7059
+ }
7060
+ if (!path18.startsWith("/")) {
7061
+ throw new Error(
7062
+ `Invalid rule "${rule}" in permission "${permName}" of service "${serviceName}": path must start with "/"`
7063
+ );
7064
+ }
7065
+ if (path18.includes("?") || path18.includes("#")) {
7066
+ throw new Error(
7067
+ `Invalid rule "${rule}" in permission "${permName}" of service "${serviceName}": path must not contain query string or fragment`
7068
+ );
7069
+ }
7070
+ const segments = path18.split("/").filter(Boolean);
7071
+ const paramNames = /* @__PURE__ */ new Set();
7072
+ for (let i = 0; i < segments.length; i++) {
7073
+ const seg = segments[i];
7074
+ if (seg.startsWith("{") && seg.endsWith("}")) {
7075
+ const name = seg.slice(1, -1);
7076
+ const baseName = name.endsWith("+") ? name.slice(0, -1) : name;
7077
+ if (!baseName) {
7078
+ throw new Error(
7079
+ `Invalid rule "${rule}" in permission "${permName}" of service "${serviceName}": empty parameter name`
7080
+ );
7081
+ }
7082
+ if (paramNames.has(baseName)) {
7083
+ throw new Error(
7084
+ `Invalid rule "${rule}" in permission "${permName}" of service "${serviceName}": duplicate parameter name "{${baseName}}"`
7085
+ );
7086
+ }
7087
+ paramNames.add(baseName);
7088
+ if (name.endsWith("+") && i !== segments.length - 1) {
7089
+ throw new Error(
7090
+ `Invalid rule "${rule}" in permission "${permName}" of service "${serviceName}": {${name}} must be the last segment`
7091
+ );
7092
+ }
7093
+ }
7094
+ }
7095
+ }
7096
+ function validateBaseUrl(base, serviceName) {
7097
+ let url;
7098
+ try {
7099
+ url = new URL(base);
7100
+ } catch {
7101
+ throw new Error(
7102
+ `Invalid base URL "${base}" in service "${serviceName}": not a valid URL`
7103
+ );
7104
+ }
7105
+ if (url.search) {
7106
+ throw new Error(
7107
+ `Invalid base URL "${base}" in service "${serviceName}": must not contain query string`
7108
+ );
7109
+ }
7110
+ if (url.hash) {
7111
+ throw new Error(
7112
+ `Invalid base URL "${base}" in service "${serviceName}": must not contain fragment`
7113
+ );
7114
+ }
7115
+ }
7116
+ function resolveServiceConfig(ref) {
7117
+ const parsed = connectorTypeSchema.safeParse(ref);
7118
+ if (!parsed.success) {
7119
+ throw new Error(
7120
+ `Cannot resolve service ref "${ref}": no built-in service with this name`
7121
+ );
7122
+ }
7123
+ const serviceConfig = getServiceConfig(parsed.data);
7124
+ if (!serviceConfig) {
7125
+ throw new Error(
7126
+ `Service ref "${ref}" resolved to "${parsed.data}" but it does not support proxy-side token replacement`
7127
+ );
7128
+ }
7129
+ return serviceConfig;
7130
+ }
7131
+ function collectAndValidatePermissions(ref, serviceConfig) {
7132
+ if (serviceConfig.apis.length === 0) {
7133
+ throw new Error(
7134
+ `Service "${serviceConfig.name}" (ref "${ref}") has no api entries`
7135
+ );
7136
+ }
7137
+ const available = /* @__PURE__ */ new Set();
7138
+ for (const api2 of serviceConfig.apis) {
7139
+ validateBaseUrl(api2.base, serviceConfig.name);
7140
+ if (!api2.permissions || api2.permissions.length === 0) {
7141
+ throw new Error(
7142
+ `API entry "${api2.base}" in service "${serviceConfig.name}" (ref "${ref}") has no permissions`
7143
+ );
7144
+ }
7145
+ const seen = /* @__PURE__ */ new Set();
7146
+ for (const perm of api2.permissions) {
7147
+ if (!perm.name) {
7148
+ throw new Error(
7149
+ `Service "${serviceConfig.name}" (ref "${ref}") has a permission with empty name`
7150
+ );
7151
+ }
7152
+ if (perm.name === "all") {
7153
+ throw new Error(
7154
+ `Service "${serviceConfig.name}" (ref "${ref}") has a permission named "all", which is a reserved keyword`
7155
+ );
7156
+ }
7157
+ if (seen.has(perm.name)) {
7158
+ throw new Error(
7159
+ `Duplicate permission name "${perm.name}" in API entry "${api2.base}" of service "${serviceConfig.name}" (ref "${ref}")`
7160
+ );
7161
+ }
7162
+ if (perm.rules.length === 0) {
7163
+ throw new Error(
7164
+ `Permission "${perm.name}" in service "${serviceConfig.name}" (ref "${ref}") has no rules`
7165
+ );
7166
+ }
7167
+ for (const rule of perm.rules) {
7168
+ validateRule(rule, perm.name, serviceConfig.name);
7169
+ }
7170
+ seen.add(perm.name);
7171
+ available.add(perm.name);
7172
+ }
7173
+ }
7174
+ return available;
7175
+ }
7176
+ function expandServiceConfigs(config) {
7177
+ const compose = config;
7178
+ if (!compose?.agents) return;
7179
+ for (const agent of Object.values(compose.agents)) {
7180
+ const services = agent.experimental_services;
7181
+ if (!services) continue;
7182
+ if (Array.isArray(services)) continue;
7183
+ const expanded = [];
7184
+ for (const [ref, selection] of Object.entries(services)) {
7185
+ const serviceConfig = resolveServiceConfig(ref);
7186
+ const availablePermissions = collectAndValidatePermissions(
7187
+ ref,
7188
+ serviceConfig
7189
+ );
7190
+ if (selection.permissions !== "all") {
7191
+ for (const name of selection.permissions) {
7192
+ if (!availablePermissions.has(name)) {
7193
+ const available = [...availablePermissions].join(", ");
7194
+ throw new Error(
7195
+ `Permission "${name}" does not exist in service "${serviceConfig.name}" (ref "${ref}"). Available: ${available}`
7196
+ );
7197
+ }
7198
+ }
7199
+ }
7200
+ const selectedSet = selection.permissions === "all" ? null : new Set(selection.permissions);
7201
+ const filteredApis = serviceConfig.apis.map((api2) => ({
7202
+ ...api2,
7203
+ permissions: selectedSet ? (api2.permissions ?? []).filter((p) => selectedSet.has(p.name)) : api2.permissions
7204
+ })).filter((api2) => (api2.permissions ?? []).length > 0);
7205
+ if (filteredApis.length === 0) continue;
7206
+ const entry = {
7207
+ name: serviceConfig.name,
7208
+ ref,
7209
+ apis: filteredApis
7210
+ };
7211
+ if (serviceConfig.description !== void 0)
7212
+ entry.description = serviceConfig.description;
7213
+ if (serviceConfig.placeholders !== void 0)
7214
+ entry.placeholders = serviceConfig.placeholders;
7215
+ expanded.push(entry);
7216
+ }
7217
+ agent.experimental_services = expanded;
7218
+ }
7219
+ }
7220
+
7008
7221
  // ../../packages/core/src/contracts/user-preferences.ts
7009
7222
  import { z as z21 } from "zod";
7010
7223
  var c19 = initContract();
@@ -9498,189 +9711,6 @@ function mergeSkillVariables(agent, variables) {
9498
9711
  agent.environment = environment;
9499
9712
  }
9500
9713
  }
9501
- function resolveServiceConfig(ref) {
9502
- const parsed = connectorTypeSchema.safeParse(ref);
9503
- if (!parsed.success) {
9504
- throw new Error(
9505
- `Cannot resolve service ref "${ref}": no built-in service with this name`
9506
- );
9507
- }
9508
- const serviceConfig = getServiceConfig(parsed.data);
9509
- if (!serviceConfig) {
9510
- throw new Error(
9511
- `Service ref "${ref}" resolved to "${parsed.data}" but it does not support proxy-side token replacement`
9512
- );
9513
- }
9514
- return serviceConfig;
9515
- }
9516
- var VALID_RULE_METHODS = /* @__PURE__ */ new Set([
9517
- "GET",
9518
- "POST",
9519
- "PUT",
9520
- "PATCH",
9521
- "DELETE",
9522
- "HEAD",
9523
- "OPTIONS",
9524
- "ANY"
9525
- ]);
9526
- function validateRule(rule, permName, serviceName) {
9527
- const parts = rule.split(" ", 2);
9528
- if (parts.length !== 2 || !parts[1]) {
9529
- throw new Error(
9530
- `Invalid rule "${rule}" in permission "${permName}" of service "${serviceName}": must be "METHOD /path"`
9531
- );
9532
- }
9533
- const [method, path18] = parts;
9534
- if (!VALID_RULE_METHODS.has(method)) {
9535
- throw new Error(
9536
- `Invalid rule "${rule}" in permission "${permName}" of service "${serviceName}": unknown method "${method}" (must be uppercase)`
9537
- );
9538
- }
9539
- if (!path18.startsWith("/")) {
9540
- throw new Error(
9541
- `Invalid rule "${rule}" in permission "${permName}" of service "${serviceName}": path must start with "/"`
9542
- );
9543
- }
9544
- if (path18.includes("?") || path18.includes("#")) {
9545
- throw new Error(
9546
- `Invalid rule "${rule}" in permission "${permName}" of service "${serviceName}": path must not contain query string or fragment`
9547
- );
9548
- }
9549
- const segments = path18.split("/").filter(Boolean);
9550
- const paramNames = /* @__PURE__ */ new Set();
9551
- for (let i = 0; i < segments.length; i++) {
9552
- const seg = segments[i];
9553
- if (seg.startsWith("{") && seg.endsWith("}")) {
9554
- const name = seg.slice(1, -1);
9555
- const baseName = name.endsWith("+") ? name.slice(0, -1) : name;
9556
- if (!baseName) {
9557
- throw new Error(
9558
- `Invalid rule "${rule}" in permission "${permName}" of service "${serviceName}": empty parameter name`
9559
- );
9560
- }
9561
- if (paramNames.has(baseName)) {
9562
- throw new Error(
9563
- `Invalid rule "${rule}" in permission "${permName}" of service "${serviceName}": duplicate parameter name "{${baseName}}"`
9564
- );
9565
- }
9566
- paramNames.add(baseName);
9567
- if (name.endsWith("+") && i !== segments.length - 1) {
9568
- throw new Error(
9569
- `Invalid rule "${rule}" in permission "${permName}" of service "${serviceName}": {${name}} must be the last segment`
9570
- );
9571
- }
9572
- }
9573
- }
9574
- }
9575
- function validateBaseUrl(base, serviceName) {
9576
- let url;
9577
- try {
9578
- url = new URL(base);
9579
- } catch {
9580
- throw new Error(
9581
- `Invalid base URL "${base}" in service "${serviceName}": not a valid URL`
9582
- );
9583
- }
9584
- if (url.search) {
9585
- throw new Error(
9586
- `Invalid base URL "${base}" in service "${serviceName}": must not contain query string`
9587
- );
9588
- }
9589
- if (url.hash) {
9590
- throw new Error(
9591
- `Invalid base URL "${base}" in service "${serviceName}": must not contain fragment`
9592
- );
9593
- }
9594
- }
9595
- function collectAndValidatePermissions(ref, serviceConfig) {
9596
- if (serviceConfig.apis.length === 0) {
9597
- throw new Error(
9598
- `Service "${serviceConfig.name}" (ref "${ref}") has no api entries`
9599
- );
9600
- }
9601
- const available = /* @__PURE__ */ new Set();
9602
- for (const api2 of serviceConfig.apis) {
9603
- validateBaseUrl(api2.base, serviceConfig.name);
9604
- if (!api2.permissions || api2.permissions.length === 0) {
9605
- throw new Error(
9606
- `API entry "${api2.base}" in service "${serviceConfig.name}" (ref "${ref}") has no permissions`
9607
- );
9608
- }
9609
- const seen = /* @__PURE__ */ new Set();
9610
- for (const perm of api2.permissions) {
9611
- if (!perm.name) {
9612
- throw new Error(
9613
- `Service "${serviceConfig.name}" (ref "${ref}") has a permission with empty name`
9614
- );
9615
- }
9616
- if (perm.name === "all") {
9617
- throw new Error(
9618
- `Service "${serviceConfig.name}" (ref "${ref}") has a permission named "all", which is a reserved keyword`
9619
- );
9620
- }
9621
- if (seen.has(perm.name)) {
9622
- throw new Error(
9623
- `Duplicate permission name "${perm.name}" in API entry "${api2.base}" of service "${serviceConfig.name}" (ref "${ref}")`
9624
- );
9625
- }
9626
- if (perm.rules.length === 0) {
9627
- throw new Error(
9628
- `Permission "${perm.name}" in service "${serviceConfig.name}" (ref "${ref}") has no rules`
9629
- );
9630
- }
9631
- for (const rule of perm.rules) {
9632
- validateRule(rule, perm.name, serviceConfig.name);
9633
- }
9634
- seen.add(perm.name);
9635
- available.add(perm.name);
9636
- }
9637
- }
9638
- return available;
9639
- }
9640
- function expandServiceConfigs(config) {
9641
- const compose = config;
9642
- if (!compose?.agents) return;
9643
- for (const agent of Object.values(compose.agents)) {
9644
- const services = agent.experimental_services;
9645
- if (!services) continue;
9646
- if (Array.isArray(services)) continue;
9647
- const expanded = [];
9648
- for (const [ref, selection] of Object.entries(services)) {
9649
- const serviceConfig = resolveServiceConfig(ref);
9650
- const availablePermissions = collectAndValidatePermissions(
9651
- ref,
9652
- serviceConfig
9653
- );
9654
- if (selection.permissions !== "all") {
9655
- for (const name of selection.permissions) {
9656
- if (!availablePermissions.has(name)) {
9657
- const available = [...availablePermissions].join(", ");
9658
- throw new Error(
9659
- `Permission "${name}" does not exist in service "${serviceConfig.name}" (ref "${ref}"). Available: ${available}`
9660
- );
9661
- }
9662
- }
9663
- }
9664
- const selectedSet = selection.permissions === "all" ? null : new Set(selection.permissions);
9665
- const filteredApis = serviceConfig.apis.map((api2) => ({
9666
- ...api2,
9667
- permissions: selectedSet ? (api2.permissions ?? []).filter((p) => selectedSet.has(p.name)) : api2.permissions
9668
- })).filter((api2) => (api2.permissions ?? []).length > 0);
9669
- if (filteredApis.length === 0) continue;
9670
- const entry = {
9671
- name: serviceConfig.name,
9672
- ref,
9673
- apis: filteredApis
9674
- };
9675
- if (serviceConfig.description !== void 0)
9676
- entry.description = serviceConfig.description;
9677
- if (serviceConfig.placeholders !== void 0)
9678
- entry.placeholders = serviceConfig.placeholders;
9679
- expanded.push(entry);
9680
- }
9681
- agent.experimental_services = expanded;
9682
- }
9683
- }
9684
9714
  function getPlatformUrl(apiUrl) {
9685
9715
  const url = new URL(apiUrl);
9686
9716
  url.hostname = url.hostname.replace("www", "platform");
@@ -9883,7 +9913,7 @@ var composeCommand = new Command7().name("compose").description("Create or updat
9883
9913
  options.autoUpdate = false;
9884
9914
  }
9885
9915
  if (options.autoUpdate !== false) {
9886
- await startSilentUpgrade("9.59.1");
9916
+ await startSilentUpgrade("9.59.3");
9887
9917
  }
9888
9918
  try {
9889
9919
  let result;
@@ -11057,7 +11087,7 @@ var mainRunCommand = new Command8().name("run").description("Run an agent").argu
11057
11087
  withErrorHandler(
11058
11088
  async (identifier, prompt, options) => {
11059
11089
  if (options.autoUpdate !== false) {
11060
- await startSilentUpgrade("9.59.1");
11090
+ await startSilentUpgrade("9.59.3");
11061
11091
  }
11062
11092
  const { org, name, version } = parseIdentifier(identifier);
11063
11093
  if (org && !options.experimentalSharedAgent) {
@@ -12744,7 +12774,7 @@ var cookAction = new Command34().name("cook").description("Quick start: prepare,
12744
12774
  withErrorHandler(
12745
12775
  async (prompt, options) => {
12746
12776
  if (options.autoUpdate !== false) {
12747
- const shouldExit = await checkAndUpgrade("9.59.1", prompt);
12777
+ const shouldExit = await checkAndUpgrade("9.59.3", prompt);
12748
12778
  if (shouldExit) {
12749
12779
  process.exit(0);
12750
12780
  }
@@ -18095,13 +18125,13 @@ var upgradeCommand = new Command90().name("upgrade").description("Upgrade vm0 CL
18095
18125
  if (latestVersion === null) {
18096
18126
  throw new Error("Could not check for updates. Please try again later.");
18097
18127
  }
18098
- if (latestVersion === "9.59.1") {
18099
- console.log(chalk84.green(`\u2713 Already up to date (${"9.59.1"})`));
18128
+ if (latestVersion === "9.59.3") {
18129
+ console.log(chalk84.green(`\u2713 Already up to date (${"9.59.3"})`));
18100
18130
  return;
18101
18131
  }
18102
18132
  console.log(
18103
18133
  chalk84.yellow(
18104
- `Current version: ${"9.59.1"} -> Latest version: ${latestVersion}`
18134
+ `Current version: ${"9.59.3"} -> Latest version: ${latestVersion}`
18105
18135
  )
18106
18136
  );
18107
18137
  console.log();
@@ -18128,7 +18158,7 @@ var upgradeCommand = new Command90().name("upgrade").description("Upgrade vm0 CL
18128
18158
  const success = await performUpgrade(packageManager);
18129
18159
  if (success) {
18130
18160
  console.log(
18131
- chalk84.green(`\u2713 Upgraded from ${"9.59.1"} to ${latestVersion}`)
18161
+ chalk84.green(`\u2713 Upgraded from ${"9.59.3"} to ${latestVersion}`)
18132
18162
  );
18133
18163
  return;
18134
18164
  }
@@ -18142,7 +18172,7 @@ var upgradeCommand = new Command90().name("upgrade").description("Upgrade vm0 CL
18142
18172
 
18143
18173
  // src/index.ts
18144
18174
  var program = new Command91();
18145
- program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.59.1");
18175
+ program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.59.3");
18146
18176
  program.addCommand(authCommand);
18147
18177
  program.addCommand(infoCommand);
18148
18178
  program.addCommand(composeCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "9.59.1",
3
+ "version": "9.59.3",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",