@vm0/cli 9.202.1 → 9.203.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.
@@ -10,7 +10,7 @@ init_esm_shims();
10
10
  var firewallPermissionMetadata = {
11
11
  "type": "figma",
12
12
  "label": "Figma",
13
- "permissionCount": 20,
13
+ "permissionCount": 19,
14
14
  "permissions": [
15
15
  {
16
16
  "name": "current_user:read",
@@ -52,10 +52,6 @@ var firewallPermissionMetadata = {
52
52
  "name": "file_versions:read",
53
53
  "description": "Read the version history for files you can access."
54
54
  },
55
- {
56
- "name": "files:read",
57
- "description": "Deprecated. Read files, projects, users, versions, comments, components & styles, and webhooks."
58
- },
59
55
  {
60
56
  "name": "library_analytics:read",
61
57
  "description": "Read library analytics data."
@@ -101,4 +97,4 @@ var firewallPermissionMetadata = {
101
97
  export {
102
98
  firewallPermissionMetadata
103
99
  };
104
- //# sourceMappingURL=figma.generated-EYCDT6DM.js.map
100
+ //# sourceMappingURL=figma.generated-PICSV4JI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../packages/connectors/src/firewall-metadata/details/figma.generated.ts"],"sourcesContent":["// Auto-generated by @vm0/firewalls-generator.\n// Regenerate: cd turbo && pnpm -F @vm0/firewalls-generator generate\n//\n// DO NOT EDIT THIS FILE MANUALLY.\nimport type { FirewallPermissionDetailMetadata } from \"../types\";\n\nexport const firewallPermissionMetadata = {\n \"type\": \"figma\",\n \"label\": \"Figma\",\n \"permissionCount\": 19,\n \"permissions\": [\n {\n \"name\": \"current_user:read\",\n \"description\": \"Read your name, email, and profile image.\"\n },\n {\n \"name\": \"file_comments:read\",\n \"description\": \"Read the comments for files.\"\n },\n {\n \"name\": \"file_comments:write\",\n \"description\": \"Post and delete comments and comment reactions in files.\"\n },\n {\n \"name\": \"file_content:read\",\n \"description\": \"Read the contents of files, such as nodes and the editor type.\"\n },\n {\n \"name\": \"file_dev_resources:read\",\n \"description\": \"Read dev resources in files.\"\n },\n {\n \"name\": \"file_dev_resources:write\",\n \"description\": \"Write to dev resources in files.\"\n },\n {\n \"name\": \"file_metadata:read\",\n \"description\": \"Read metadata of files.\"\n },\n {\n \"name\": \"file_variables:read\",\n \"description\": \"Read variables in Figma file. Note: this is only available to members in Enterprise organizations.\"\n },\n {\n \"name\": \"file_variables:write\",\n \"description\": \"Write to variables in Figma file. Note: this is only available to members in Enterprise organizations.\"\n },\n {\n \"name\": \"file_versions:read\",\n \"description\": \"Read the version history for files you can access.\"\n },\n {\n \"name\": \"library_analytics:read\",\n \"description\": \"Read library analytics data.\"\n },\n {\n \"name\": \"library_assets:read\",\n \"description\": \"Read data of individual published components and styles.\"\n },\n {\n \"name\": \"library_content:read\",\n \"description\": \"Read published components and styles of files.\"\n },\n {\n \"name\": \"org:activity_log_read\",\n \"description\": \"Read activity logs in the organization.\"\n },\n {\n \"name\": \"project_metadata:read\",\n \"description\": \"Read metadata of projects.\"\n },\n {\n \"name\": \"projects:read\",\n \"description\": \"List projects and files in projects.\"\n },\n {\n \"name\": \"team_library_content:read\",\n \"description\": \"Read published components and styles of teams.\"\n },\n {\n \"name\": \"webhooks:read\",\n \"description\": \"Read metadata of webhooks.\"\n },\n {\n \"name\": \"webhooks:write\",\n \"description\": \"Create and manage webhooks.\"\n }\n ],\n \"defaultPolicy\": {\n \"permissionDefault\": \"allow\",\n \"unknownPolicy\": \"allow\"\n }\n} as const satisfies FirewallPermissionDetailMetadata;\n"],"mappings":";;;;;;;;AAAA;AAMO,IAAM,6BAA6B;AAAA,EACxC,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,mBAAmB;AAAA,EACnB,eAAe;AAAA,IACb;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,eAAe;AAAA,IACjB;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf,qBAAqB;AAAA,IACrB,iBAAiB;AAAA,EACnB;AACF;","names":[]}
package/index.js CHANGED
@@ -75,7 +75,7 @@ import {
75
75
  uo,
76
76
  volumeConfigSchema,
77
77
  withErrorHandler
78
- } from "./chunk-ZIO54LY7.js";
78
+ } from "./chunk-QVNEGQGL.js";
79
79
  import "./chunk-NR42YJMI.js";
80
80
  import {
81
81
  __toESM,
@@ -409,7 +409,7 @@ function getConfigPath() {
409
409
  return join(os.homedir(), ".vm0", "config.json");
410
410
  }
411
411
  var infoCommand = new Command().name("info").description("Display environment and debug information").action(async () => {
412
- console.log(source_default.bold(`VM0 CLI v${"9.202.1"}`));
412
+ console.log(source_default.bold(`VM0 CLI v${"9.203.0"}`));
413
413
  console.log();
414
414
  const config = await loadConfig();
415
415
  const hasEnvToken = !!process.env.VM0_TOKEN;
@@ -1111,7 +1111,7 @@ var composeCommand = new Command().name("compose").description("Create or update
1111
1111
  options.autoUpdate = false;
1112
1112
  }
1113
1113
  if (options.autoUpdate !== false) {
1114
- await startSilentUpgrade("9.202.1");
1114
+ await startSilentUpgrade("9.203.0");
1115
1115
  }
1116
1116
  try {
1117
1117
  const { config, agentName, agent, basePath } = await loadAndValidateConfig(resolvedConfigFile);
@@ -1208,7 +1208,7 @@ var mainRunCommand = new Command().name("run").description("Run an agent").argum
1208
1208
  withErrorHandler(
1209
1209
  async (identifier, prompt, options) => {
1210
1210
  if (options.autoUpdate !== false) {
1211
- await startSilentUpgrade("9.202.1");
1211
+ await startSilentUpgrade("9.203.0");
1212
1212
  }
1213
1213
  const { name, version } = parseIdentifier(identifier);
1214
1214
  let composeId;
@@ -3014,13 +3014,13 @@ var upgradeCommand = new Command().name("upgrade").description("Upgrade vm0 CLI
3014
3014
  if (latestVersion === null) {
3015
3015
  throw new Error("Could not check for updates. Please try again later.");
3016
3016
  }
3017
- if (latestVersion === "9.202.1") {
3018
- console.log(source_default.green(`\u2713 Already up to date (${"9.202.1"})`));
3017
+ if (latestVersion === "9.203.0") {
3018
+ console.log(source_default.green(`\u2713 Already up to date (${"9.203.0"})`));
3019
3019
  return;
3020
3020
  }
3021
3021
  console.log(
3022
3022
  source_default.yellow(
3023
- `Current version: ${"9.202.1"} -> Latest version: ${latestVersion}`
3023
+ `Current version: ${"9.203.0"} -> Latest version: ${latestVersion}`
3024
3024
  )
3025
3025
  );
3026
3026
  console.log();
@@ -3047,7 +3047,7 @@ var upgradeCommand = new Command().name("upgrade").description("Upgrade vm0 CLI
3047
3047
  const success = await performUpgrade(packageManager);
3048
3048
  if (success) {
3049
3049
  console.log(
3050
- source_default.green(`\u2713 Upgraded from ${"9.202.1"} to ${latestVersion}`)
3050
+ source_default.green(`\u2713 Upgraded from ${"9.203.0"} to ${latestVersion}`)
3051
3051
  );
3052
3052
  return;
3053
3053
  }
@@ -3114,7 +3114,7 @@ var whoamiCommand = new Command().name("whoami").description("Show current ident
3114
3114
 
3115
3115
  // src/index.ts
3116
3116
  var program = new Command();
3117
- program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.202.1");
3117
+ program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.203.0");
3118
3118
  program.addCommand(authCommand);
3119
3119
  program.addCommand(infoCommand);
3120
3120
  program.addCommand(composeCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "9.202.1",
3
+ "version": "9.203.0",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",
package/zero.js CHANGED
@@ -192,7 +192,7 @@ import {
192
192
  uploadWebFile,
193
193
  upsertZeroOrgModelProvider,
194
194
  withErrorHandler
195
- } from "./chunk-ZIO54LY7.js";
195
+ } from "./chunk-QVNEGQGL.js";
196
196
  import "./chunk-NR42YJMI.js";
197
197
  import {
198
198
  __toESM,
@@ -5876,9 +5876,57 @@ init_esm_shims();
5876
5876
 
5877
5877
  // src/commands/zero/workflow/trigger/display.ts
5878
5878
  init_esm_shims();
5879
+ var GMAIL_TEXT_FIELDS = [
5880
+ "from",
5881
+ "subject",
5882
+ "body",
5883
+ "to",
5884
+ "cc"
5885
+ ];
5886
+ function quote(value) {
5887
+ return `"${value}"`;
5888
+ }
5889
+ function quoteList(values) {
5890
+ return values.map(quote).join(", ");
5891
+ }
5892
+ function textMatcherParts(field, matcher) {
5893
+ const parts = [];
5894
+ if (matcher.contains) {
5895
+ parts.push(`${field} contains ${quote(matcher.contains)}`);
5896
+ }
5897
+ if (matcher.containsAny) {
5898
+ parts.push(`${field} contains any of ${quoteList(matcher.containsAny)}`);
5899
+ }
5900
+ if (matcher.doesNotContain) {
5901
+ parts.push(`${field} does not contain ${quote(matcher.doesNotContain)}`);
5902
+ }
5903
+ if (matcher.doesNotContainAny) {
5904
+ parts.push(
5905
+ `${field} does not contain any of ${quoteList(matcher.doesNotContainAny)}`
5906
+ );
5907
+ }
5908
+ return parts;
5909
+ }
5910
+ function formatGmailMatchSummary(config) {
5911
+ const match = config.match;
5912
+ if (!match) {
5913
+ return "all inbound messages";
5914
+ }
5915
+ const parts = [];
5916
+ for (const field of GMAIL_TEXT_FIELDS) {
5917
+ const matcher = match[field];
5918
+ if (matcher) {
5919
+ parts.push(...textMatcherParts(field, matcher));
5920
+ }
5921
+ }
5922
+ if (match.snippet || match.labels || match.hasAttachment !== void 0) {
5923
+ parts.push("custom match rules");
5924
+ }
5925
+ return parts.length > 0 ? parts.join("; ") : "all inbound messages";
5926
+ }
5879
5927
  function formatWorkflowTriggerEntry(trigger) {
5880
5928
  if (trigger.kind === "event") {
5881
- return "Gmail new message";
5929
+ return `Gmail new message: ${formatGmailMatchSummary(trigger.eventConfig)}`;
5882
5930
  }
5883
5931
  const { schedule } = trigger;
5884
5932
  switch (schedule.type) {
@@ -5936,7 +5984,14 @@ function printWorkflowTriggerDetails(trigger, options) {
5936
5984
  console.log(`${"Workflow:".padEnd(14)}${options.workflowRef}`);
5937
5985
  }
5938
5986
  console.log(`${"Status:".padEnd(14)}${status}`);
5939
- console.log(`${"Trigger:".padEnd(14)}${formatWorkflowTriggerEntry(trigger)}`);
5987
+ console.log(
5988
+ `${"Trigger:".padEnd(14)}${trigger.kind === "event" ? "Gmail new message" : formatWorkflowTriggerEntry(trigger)}`
5989
+ );
5990
+ if (trigger.kind === "event") {
5991
+ console.log(
5992
+ `${"Match:".padEnd(14)}${formatGmailMatchSummary(trigger.eventConfig)}`
5993
+ );
5994
+ }
5940
5995
  console.log(`${"Owner:".padEnd(14)}${trigger.ownerUserId}`);
5941
5996
  console.log(
5942
5997
  `${"Chat thread:".padEnd(14)}${trigger.chatThreadId ?? source_default.dim("-")}`
@@ -5945,9 +6000,208 @@ function printWorkflowTriggerDetails(trigger, options) {
5945
6000
  console.log(`${"Last run:".padEnd(14)}${formatRunTime(trigger.lastRunAt)}`);
5946
6001
  }
5947
6002
 
6003
+ // src/commands/zero/workflow/trigger/gmail-config.ts
6004
+ init_esm_shims();
6005
+ import { readFileSync as readFileSync13 } from "fs";
6006
+ var TEXT_FIELD_LABELS = {
6007
+ from: "from",
6008
+ subject: "subject",
6009
+ body: "body",
6010
+ to: "to",
6011
+ cc: "cc"
6012
+ };
6013
+ function isRecord(value) {
6014
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6015
+ }
6016
+ function textFieldFromKey(key) {
6017
+ switch (key) {
6018
+ case "from":
6019
+ case "subject":
6020
+ case "body":
6021
+ case "to":
6022
+ case "cc":
6023
+ return key;
6024
+ default:
6025
+ return null;
6026
+ }
6027
+ }
6028
+ function formatFieldName(field) {
6029
+ return TEXT_FIELD_LABELS[field];
6030
+ }
6031
+ function parseNonEmptyString(value, path2) {
6032
+ if (typeof value !== "string" || value.length === 0) {
6033
+ throw new Error(`${path2} must be a non-empty string`);
6034
+ }
6035
+ return value;
6036
+ }
6037
+ function parseNonEmptyStringArray(value, path2) {
6038
+ if (!Array.isArray(value) || value.length === 0) {
6039
+ throw new Error(`${path2} must be a non-empty string array`);
6040
+ }
6041
+ return value.map((item, index) => {
6042
+ return parseNonEmptyString(item, `${path2}[${index}]`);
6043
+ });
6044
+ }
6045
+ function parseTextMatcher(field, value) {
6046
+ if (!isRecord(value)) {
6047
+ throw new Error(`${formatFieldName(field)} must be an object`);
6048
+ }
6049
+ const matcher = {};
6050
+ for (const key of Object.keys(value)) {
6051
+ switch (key) {
6052
+ case "contains":
6053
+ matcher.contains = parseNonEmptyString(
6054
+ value[key],
6055
+ `${formatFieldName(field)}.contains`
6056
+ );
6057
+ break;
6058
+ case "containsAny":
6059
+ matcher.containsAny = parseNonEmptyStringArray(
6060
+ value[key],
6061
+ `${formatFieldName(field)}.containsAny`
6062
+ );
6063
+ break;
6064
+ case "doesNotContain":
6065
+ matcher.doesNotContain = parseNonEmptyString(
6066
+ value[key],
6067
+ `${formatFieldName(field)}.doesNotContain`
6068
+ );
6069
+ break;
6070
+ case "doesNotContainAny":
6071
+ matcher.doesNotContainAny = parseNonEmptyStringArray(
6072
+ value[key],
6073
+ `${formatFieldName(field)}.doesNotContainAny`
6074
+ );
6075
+ break;
6076
+ default:
6077
+ throw new Error(
6078
+ `Unsupported Gmail trigger text matcher "${key}" for ${formatFieldName(field)}`
6079
+ );
6080
+ }
6081
+ }
6082
+ if (matcher.contains === void 0 && matcher.containsAny === void 0 && matcher.doesNotContain === void 0 && matcher.doesNotContainAny === void 0) {
6083
+ throw new Error(
6084
+ `${formatFieldName(field)} must include at least one text matcher`
6085
+ );
6086
+ }
6087
+ return matcher;
6088
+ }
6089
+ function parseMatch(value) {
6090
+ if (value === void 0) {
6091
+ return void 0;
6092
+ }
6093
+ if (!isRecord(value)) {
6094
+ throw new Error("match must be an object");
6095
+ }
6096
+ const match = {};
6097
+ for (const key of Object.keys(value)) {
6098
+ const field = textFieldFromKey(key);
6099
+ if (field === null) {
6100
+ throw new Error(
6101
+ `Unsupported Gmail trigger match field "${key}". Supported fields: from, subject, body, to, cc`
6102
+ );
6103
+ }
6104
+ match[field] = parseTextMatcher(field, value[key]);
6105
+ }
6106
+ return Object.keys(match).length > 0 ? match : void 0;
6107
+ }
6108
+ function readConfigMatch(path2) {
6109
+ let parsed;
6110
+ try {
6111
+ parsed = JSON.parse(readFileSync13(path2, "utf-8"));
6112
+ } catch (error) {
6113
+ const message = error instanceof Error ? error.message : String(error);
6114
+ throw new Error(
6115
+ `Failed to read Gmail trigger config "${path2}": ${message}`
6116
+ );
6117
+ }
6118
+ if (!isRecord(parsed)) {
6119
+ throw new Error("Gmail trigger config must be a JSON object");
6120
+ }
6121
+ for (const key of Object.keys(parsed)) {
6122
+ if (key !== "match") {
6123
+ throw new Error(
6124
+ `Unsupported Gmail trigger config field "${key}". Use a top-level match object`
6125
+ );
6126
+ }
6127
+ }
6128
+ return parseMatch(parsed.match);
6129
+ }
6130
+ function textFlagSpecs(options) {
6131
+ return [
6132
+ {
6133
+ field: "from",
6134
+ contains: options.fromContains,
6135
+ doesNotContain: options.fromNotContains
6136
+ },
6137
+ {
6138
+ field: "subject",
6139
+ contains: options.subjectContains,
6140
+ doesNotContain: options.subjectNotContains
6141
+ },
6142
+ {
6143
+ field: "body",
6144
+ contains: options.bodyContains,
6145
+ doesNotContain: options.bodyNotContains
6146
+ },
6147
+ {
6148
+ field: "to",
6149
+ contains: options.toContains,
6150
+ doesNotContain: options.toNotContains
6151
+ },
6152
+ {
6153
+ field: "cc",
6154
+ contains: options.ccContains,
6155
+ doesNotContain: options.ccNotContains
6156
+ }
6157
+ ];
6158
+ }
6159
+ function hasGmailTriggerOptions(options) {
6160
+ return options.config !== void 0 || textFlagSpecs(options).some((spec) => {
6161
+ return spec.contains !== void 0 || spec.doesNotContain !== void 0;
6162
+ });
6163
+ }
6164
+ function buildMatchFromFlags(options) {
6165
+ const match = {};
6166
+ for (const spec of textFlagSpecs(options)) {
6167
+ const matcher = {};
6168
+ if (spec.contains !== void 0) {
6169
+ if (spec.contains.length === 0) {
6170
+ throw new Error(
6171
+ `${formatFieldName(spec.field)} contains must be non-empty`
6172
+ );
6173
+ }
6174
+ matcher.contains = spec.contains;
6175
+ }
6176
+ if (spec.doesNotContain !== void 0) {
6177
+ if (spec.doesNotContain.length === 0) {
6178
+ throw new Error(
6179
+ `${formatFieldName(spec.field)} doesNotContain must be non-empty`
6180
+ );
6181
+ }
6182
+ matcher.doesNotContain = spec.doesNotContain;
6183
+ }
6184
+ if (matcher.contains !== void 0 || matcher.doesNotContain !== void 0) {
6185
+ match[spec.field] = matcher;
6186
+ }
6187
+ }
6188
+ return Object.keys(match).length > 0 ? match : void 0;
6189
+ }
6190
+ function buildGmailNewMessageEventConfig(options) {
6191
+ if (options.config !== void 0 && textFlagSpecs(options).some((spec) => {
6192
+ return spec.contains !== void 0 || spec.doesNotContain !== void 0;
6193
+ })) {
6194
+ throw new Error("Use either --config or Gmail text match flags, not both");
6195
+ }
6196
+ const match = options.config !== void 0 ? readConfigMatch(options.config) : buildMatchFromFlags(options);
6197
+ return match ? { provider: "gmail", event: "new_message", match } : { provider: "gmail", event: "new_message" };
6198
+ }
6199
+
5948
6200
  // src/commands/zero/workflow/trigger/index.ts
5949
6201
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5950
6202
  var SCHEDULE_KINDS = ["cron", "once", "loop"];
6203
+ var EVENT_KINDS = ["gmail-new-message"];
6204
+ var TRIGGER_KINDS2 = [...SCHEDULE_KINDS, ...EVENT_KINDS];
5951
6205
  var EXACTLY_ONE_FLAG_MESSAGE2 = "Provide exactly one of --expr (cron), --at (once), --every (loop)";
5952
6206
  function timezoneOrUtc(timezone) {
5953
6207
  return timezone ?? "UTC";
@@ -6081,10 +6335,33 @@ function buildSchedule(kind, options) {
6081
6335
  };
6082
6336
  default:
6083
6337
  throw new Error(
6084
- `Unknown trigger kind: "${kind}". Use one of: ${SCHEDULE_KINDS.join(", ")}`
6338
+ `Unknown trigger kind: "${kind}". Use one of: ${TRIGGER_KINDS2.join(", ")}`
6085
6339
  );
6086
6340
  }
6087
6341
  }
6342
+ function hasScheduleAddOptions(options) {
6343
+ return options.expr !== void 0 || options.at !== void 0 || options.every !== void 0 || options.timezone !== void 0;
6344
+ }
6345
+ function buildCreateRequest(kind, options) {
6346
+ if (kind === "gmail-new-message") {
6347
+ if (hasScheduleAddOptions(options)) {
6348
+ throw new Error(
6349
+ "--expr, --at, --every, and --timezone only apply to schedule triggers"
6350
+ );
6351
+ }
6352
+ return {
6353
+ kind: "event",
6354
+ eventType: "gmail-new-message",
6355
+ eventConfig: buildGmailNewMessageEventConfig(options)
6356
+ };
6357
+ }
6358
+ if (hasGmailTriggerOptions(options)) {
6359
+ throw new Error(
6360
+ "Gmail match flags and --config only apply to gmail-new-message triggers"
6361
+ );
6362
+ }
6363
+ return { schedule: buildSchedule(kind, options) };
6364
+ }
6088
6365
  function buildUpdate2(options) {
6089
6366
  const flagCount = [options.expr, options.at, options.every].filter(
6090
6367
  (value) => {
@@ -6125,27 +6402,46 @@ async function resolveWorkflowId(ref, options) {
6125
6402
  }
6126
6403
  return matches[0].id;
6127
6404
  }
6128
- var addCommand2 = new Command().name("add").description("Add a schedule trigger to a workflow").argument("<workflow>", "Workflow ID or name").argument("<kind>", `Trigger kind: ${SCHEDULE_KINDS.join(" | ")}`).option("--expr <expression>", 'Cron expression for kind "cron"').option("--at <iso-time>", 'Fire time for kind "once"').option("--every <duration>", 'Interval for kind "loop" (e.g. 15m, 1h, 90s)').option("-z, --timezone <tz>", "IANA timezone for cron/once (default: UTC)").option("--agent <id>", "Agent ID for resolving a workflow name").addHelpText(
6405
+ var addCommand2 = new Command().name("add").description("Add a trigger to a workflow").argument("<workflow>", "Workflow ID or name").argument("<kind>", `Trigger type: ${TRIGGER_KINDS2.join(" | ")}`).option("--expr <expression>", 'Cron expression for kind "cron"').option("--at <iso-time>", 'Fire time for kind "once"').option("--every <duration>", 'Interval for kind "loop" (e.g. 15m, 1h, 90s)').option("-z, --timezone <tz>", "IANA timezone for cron/once (default: UTC)").option("--config <path>", "Path to a Gmail new message trigger config JSON").option("--from-contains <text>", "Require the From header to contain text").option(
6406
+ "--from-not-contains <text>",
6407
+ "Require the From header not to contain text"
6408
+ ).option(
6409
+ "--subject-contains <text>",
6410
+ "Require the Subject header to contain text"
6411
+ ).option(
6412
+ "--subject-not-contains <text>",
6413
+ "Require the Subject header not to contain text"
6414
+ ).option("--body-contains <text>", "Require the message body to contain text").option(
6415
+ "--body-not-contains <text>",
6416
+ "Require the message body not to contain text"
6417
+ ).option("--to-contains <text>", "Require the To header to contain text").option(
6418
+ "--to-not-contains <text>",
6419
+ "Require the To header not to contain text"
6420
+ ).option("--cc-contains <text>", "Require the Cc header to contain text").option(
6421
+ "--cc-not-contains <text>",
6422
+ "Require the Cc header not to contain text"
6423
+ ).option("--agent <id>", "Agent ID for resolving a workflow name").addHelpText(
6129
6424
  "after",
6130
6425
  `
6131
6426
  Examples:
6132
6427
  zero workflow trigger add tell-a-joke cron --expr "0 9 * * *" -z Asia/Shanghai
6133
6428
  zero workflow trigger add tell-a-joke once --at "2026-06-10T09:00" -z Asia/Shanghai
6134
6429
  zero workflow trigger add tell-a-joke loop --every 15m
6430
+ zero workflow trigger add triage gmail-new-message --from-contains "@example.com"
6431
+ zero workflow trigger add triage gmail-new-message --config ./gmail-trigger.json
6135
6432
 
6136
6433
  Notes:
6137
6434
  - Workflow names resolve under --agent, then ZERO_AGENT_ID, then all visible workflows
6435
+ - Gmail triggers match all inbound messages when no text match rules are provided
6138
6436
  - Use the workflow ID when a name is ambiguous`
6139
6437
  ).action(
6140
6438
  withErrorHandler(
6141
6439
  async (workflowRef, kind, options) => {
6142
- if (options.timezone && kind !== "cron" && kind !== "once") {
6440
+ if (options.timezone && kind !== "cron" && kind !== "once" && kind !== "gmail-new-message") {
6143
6441
  throw new Error("--timezone only applies to cron and once triggers");
6144
6442
  }
6145
6443
  const workflowId = await resolveWorkflowId(workflowRef, options);
6146
- const body = {
6147
- schedule: buildSchedule(kind, options)
6148
- };
6444
+ const body = buildCreateRequest(kind, options);
6149
6445
  const trigger = await createWorkflowTrigger(workflowId, body);
6150
6446
  console.log(
6151
6447
  source_default.green(`\u2713 Trigger added to workflow "${workflowRef}"`)
@@ -6168,7 +6464,7 @@ Examples:
6168
6464
  printWorkflowTriggerDetails(trigger);
6169
6465
  })
6170
6466
  );
6171
- var listCommand14 = new Command().name("list").alias("ls").description("List a workflow's schedule triggers").argument("<workflow>", "Workflow ID or name").option("--agent <id>", "Agent ID for resolving a workflow name").addHelpText(
6467
+ var listCommand14 = new Command().name("list").alias("ls").description("List a workflow's triggers").argument("<workflow>", "Workflow ID or name").option("--agent <id>", "Agent ID for resolving a workflow name").addHelpText(
6172
6468
  "after",
6173
6469
  `
6174
6470
  Examples:
@@ -6225,7 +6521,7 @@ var runCommand3 = new Command().name("run").description("Fire a workflow trigger
6225
6521
  console.log(`Stream logs: zero logs ${result.runId}`);
6226
6522
  })
6227
6523
  );
6228
- var triggerCommand2 = new Command().name("trigger").description("Manage a workflow's schedule triggers").addCommand(addCommand2).addCommand(updateCommand4).addCommand(listCommand14).addCommand(showCommand3).addCommand(rmCommand2).addCommand(enableCommand3).addCommand(disableCommand3).addCommand(runCommand3).addHelpText(
6524
+ var triggerCommand2 = new Command().name("trigger").description("Manage a workflow's triggers").addCommand(addCommand2).addCommand(updateCommand4).addCommand(listCommand14).addCommand(showCommand3).addCommand(rmCommand2).addCommand(enableCommand3).addCommand(disableCommand3).addCommand(runCommand3).addHelpText(
6229
6525
  "after",
6230
6526
  `
6231
6527
  Examples:
@@ -6986,7 +7282,7 @@ function extensionForMimeType(mimeType) {
6986
7282
  const suffix = mimeType.startsWith("image/") ? mimeType.slice(6) : "bin";
6987
7283
  return sanitizeFilenamePart(suffix, "bin").toLowerCase();
6988
7284
  }
6989
- function isRecord(value) {
7285
+ function isRecord2(value) {
6990
7286
  return typeof value === "object" && value !== null && !Array.isArray(value);
6991
7287
  }
6992
7288
  function stringField(value, key) {
@@ -7083,7 +7379,7 @@ async function formatComputerUseResultForConsole(result, commandId) {
7083
7379
  }
7084
7380
  }
7085
7381
  const action = result.action;
7086
- if (isRecord(action)) {
7382
+ if (isRecord2(action)) {
7087
7383
  printable.action = compactActionResult(action);
7088
7384
  }
7089
7385
  return JSON.stringify(printable, null, 2);
@@ -7440,7 +7736,7 @@ function canonicalizeRegistryId(prefix, value) {
7440
7736
 
7441
7737
  // src/commands/zero/generate/lib/dispatch.ts
7442
7738
  init_esm_shims();
7443
- import { readFileSync as readFileSync13 } from "fs";
7739
+ import { readFileSync as readFileSync14 } from "fs";
7444
7740
 
7445
7741
  // src/commands/zero/generate/lib/connector-guidance.ts
7446
7742
  init_esm_shims();
@@ -7995,7 +8291,7 @@ function resolvePrompt(prompt) {
7995
8291
  }
7996
8292
  if (!process.stdin.isTTY) {
7997
8293
  try {
7998
- const piped = readFileSync13("/dev/stdin", "utf8").trim();
8294
+ const piped = readFileSync14("/dev/stdin", "utf8").trim();
7999
8295
  if (piped.length > 0) {
8000
8296
  return piped;
8001
8297
  }
@@ -11372,7 +11668,7 @@ function registerZeroCommands(prog, commands) {
11372
11668
  var program = new Command();
11373
11669
  program.name("zero").description(
11374
11670
  "Zero CLI \u2014 interact with the zero platform from inside the sandbox"
11375
- ).version("9.202.1").addHelpText("after", () => {
11671
+ ).version("9.203.0").addHelpText("after", () => {
11376
11672
  return buildZeroHelpText();
11377
11673
  });
11378
11674
  if (process.argv[1]?.endsWith("zero.js") || process.argv[1]?.endsWith("zero.ts") || process.argv[1]?.endsWith("zero")) {