@vm0/cli 9.147.2 → 9.148.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/zero.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  EventRenderer,
9
9
  MODEL_PROVIDER_TYPES,
10
10
  Option,
11
- allowsCustomModel,
11
+ completePhoneFileUpload,
12
12
  completeSlackFileUpload,
13
13
  completeTelegramFileUpload,
14
14
  configureGlobalProxyFromEnv,
@@ -29,6 +29,7 @@ import {
29
29
  deleteZeroVariable,
30
30
  deployZeroSchedule,
31
31
  disableZeroSchedule,
32
+ downloadPhoneFile,
32
33
  downloadSlackFile,
33
34
  downloadTelegramFile,
34
35
  downloadWebFile,
@@ -45,10 +46,7 @@ import {
45
46
  getConnectorEnvironmentMapping,
46
47
  getConnectorFirewall,
47
48
  getConnectorTypeForSecretName,
48
- getCustomModelPlaceholder,
49
49
  getDefaultAuthMethod,
50
- getDefaultModel,
51
- getModels,
52
50
  getScopeDiff,
53
51
  getSecretsForAuthMethod,
54
52
  getSelectableProviderTypes,
@@ -65,8 +63,8 @@ import {
65
63
  getZeroRunContext,
66
64
  getZeroUserPreferences,
67
65
  hasAuthMethods,
68
- hasModelSelection,
69
66
  hasRequiredScopes,
67
+ initPhoneFileUpload,
70
68
  initSlackFileUpload,
71
69
  initTelegramFileUpload,
72
70
  inviteZeroOrgMember,
@@ -107,9 +105,9 @@ import {
107
105
  searchZeroConnectors,
108
106
  searchZeroLogs,
109
107
  sendChatMessage,
108
+ sendPhoneMessage,
110
109
  sendSlackMessage,
111
110
  sendTelegramMessage,
112
- setZeroOrgModelProviderDefault,
113
111
  setZeroOrgSecret,
114
112
  setZeroOrgVariable,
115
113
  setZeroSecret,
@@ -122,14 +120,13 @@ import {
122
120
  updateZeroAgent,
123
121
  updateZeroAgentInstructions,
124
122
  updateZeroOrg,
125
- updateZeroOrgModelProviderModel,
126
123
  updateZeroUserPreferences,
127
124
  uploadWebFile,
128
125
  upsertZeroOrgModelProvider,
129
126
  withErrorHandler,
130
127
  zeroAgentCustomSkillNameSchema,
131
128
  zeroRemoteAgentCommand
132
- } from "./chunk-EFG3ZEWH.js";
129
+ } from "./chunk-WSZTOGEW.js";
133
130
  import {
134
131
  __toESM,
135
132
  init_esm_shims
@@ -539,23 +536,8 @@ var listCommand4 = new Command().name("list").alias("ls").description("List all
539
536
  for (const [framework, providers] of Object.entries(byFramework)) {
540
537
  console.log(` ${source_default.cyan(framework)}:`);
541
538
  for (const provider of providers) {
542
- const defaultTag = provider.isDefault ? source_default.green(" (default)") : "";
543
- const modelTag = provider.selectedModel ? source_default.dim(` [${provider.selectedModel}]`) : "";
544
- console.log(` ${provider.type}${defaultTag}${modelTag}`);
539
+ console.log(` ${provider.type}`);
545
540
  console.log(source_default.dim(` ID: ${provider.id}`));
546
- if (provider.type in MODEL_PROVIDER_TYPES) {
547
- const type = provider.type;
548
- const available = getModels(type) ?? [];
549
- if (available.length > 0) {
550
- console.log(
551
- source_default.dim(` Available models: ${available.join(", ")}`)
552
- );
553
- } else if (allowsCustomModel(type)) {
554
- console.log(
555
- source_default.dim(" Available models: (custom \u2014 any model name)")
556
- );
557
- }
558
- }
559
541
  console.log(
560
542
  source_default.dim(
561
543
  ` Updated: ${new Date(provider.updatedAt).toLocaleString()}`
@@ -567,12 +549,6 @@ var listCommand4 = new Command().name("list").alias("ls").description("List all
567
549
  console.log(
568
550
  source_default.dim(`Total: ${result.modelProviders.length} provider(s)`)
569
551
  );
570
- console.log();
571
- console.log(
572
- source_default.dim(
573
- "Use a provider ID with: zero agent edit <agent-id> --model-provider <id> --model <name>"
574
- )
575
- );
576
552
  })
577
553
  );
578
554
 
@@ -592,18 +568,6 @@ function validateProviderType(typeStr) {
592
568
  }
593
569
  return typeStr;
594
570
  }
595
- function validateModel(type, modelStr) {
596
- const models = getModels(type);
597
- if (allowsCustomModel(type)) {
598
- return modelStr;
599
- }
600
- if (models && !models.includes(modelStr)) {
601
- throw new Error(`Invalid model "${modelStr}"`, {
602
- cause: new Error(`Valid models: ${models.join(", ")}`)
603
- });
604
- }
605
- return modelStr;
606
- }
607
571
  function validateAuthMethod(type, authMethodStr) {
608
572
  const authMethods = getAuthMethodsForType(type);
609
573
  if (!authMethods || !(authMethodStr in authMethods)) {
@@ -677,13 +641,6 @@ function validateSecrets(type, authMethod, secrets) {
677
641
  function handleNonInteractiveMode(options) {
678
642
  const type = validateProviderType(options.type);
679
643
  const cmdPrefix = options.commandPrefix ?? "zero org model-provider setup";
680
- let selectedModel;
681
- if (options.model) {
682
- selectedModel = validateModel(type, options.model);
683
- } else if (hasModelSelection(type)) {
684
- const defaultModel = getDefaultModel(type);
685
- selectedModel = defaultModel || void 0;
686
- }
687
644
  if (hasAuthMethods(type)) {
688
645
  let authMethod;
689
646
  if (options.authMethod) {
@@ -715,7 +672,6 @@ function handleNonInteractiveMode(options) {
715
672
  type,
716
673
  authMethod,
717
674
  secrets,
718
- selectedModel,
719
675
  isInteractiveMode: false
720
676
  };
721
677
  }
@@ -733,68 +689,9 @@ function handleNonInteractiveMode(options) {
733
689
  return {
734
690
  type,
735
691
  secret,
736
- selectedModel,
737
692
  isInteractiveMode: false
738
693
  };
739
694
  }
740
- async function promptForModelSelection(type) {
741
- if (!hasModelSelection(type)) {
742
- return void 0;
743
- }
744
- const models = getModels(type) ?? [];
745
- const defaultModel = getDefaultModel(type);
746
- const supportsCustomModel = allowsCustomModel(type);
747
- const modelChoices = [];
748
- if (defaultModel === "") {
749
- modelChoices.push({ title: "auto (Recommended)", value: "" });
750
- }
751
- for (const model of models) {
752
- modelChoices.push({
753
- title: model === defaultModel ? `${model} (Recommended)` : model,
754
- value: model
755
- });
756
- }
757
- if (supportsCustomModel) {
758
- modelChoices.push({ title: "Custom model ID", value: "__custom__" });
759
- }
760
- const modelResponse = await (0, import_prompts.default)(
761
- {
762
- type: "select",
763
- name: "model",
764
- message: "Select model:",
765
- choices: modelChoices
766
- },
767
- {
768
- onCancel: () => {
769
- return process.exit(0);
770
- }
771
- }
772
- );
773
- const selected = modelResponse.model;
774
- if (selected === "__custom__") {
775
- const placeholder = getCustomModelPlaceholder(type);
776
- if (placeholder) {
777
- console.log(source_default.dim(`Example: ${placeholder}`));
778
- }
779
- const customResponse = await (0, import_prompts.default)(
780
- {
781
- type: "text",
782
- name: "customModel",
783
- message: "Enter model ID:",
784
- validate: (value) => {
785
- return value.length > 0 || "Model ID is required";
786
- }
787
- },
788
- {
789
- onCancel: () => {
790
- return process.exit(0);
791
- }
792
- }
793
- );
794
- return customResponse.customModel;
795
- }
796
- return selected === "" ? void 0 : selected;
797
- }
798
695
  async function promptForAuthMethod(type) {
799
696
  const authMethods = getAuthMethodsForType(type);
800
697
  const defaultAuthMethod = getDefaultAuthMethod(type);
@@ -882,11 +779,6 @@ async function promptForSecrets(type, authMethod) {
882
779
  function collectSecrets(value, previous) {
883
780
  return previous.concat([value]);
884
781
  }
885
- function parseModelFlag(value) {
886
- if (value === void 0) return void 0;
887
- if (value === "default") return null;
888
- return value;
889
- }
890
782
 
891
783
  // src/commands/zero/org/model-provider/setup.ts
892
784
  async function handleInteractiveMode() {
@@ -962,11 +854,9 @@ async function handleInteractiveMode() {
962
854
  return null;
963
855
  }
964
856
  if (actionResponse.action === "keep") {
965
- const selectedModel2 = await promptForModelSelection(type);
966
857
  return {
967
858
  type,
968
859
  keepExistingSecret: true,
969
- selectedModel: selectedModel2,
970
860
  isInteractiveMode: true
971
861
  };
972
862
  }
@@ -980,12 +870,10 @@ async function handleInteractiveMode() {
980
870
  if (hasAuthMethods(type)) {
981
871
  const authMethod = await promptForAuthMethod(type);
982
872
  const secrets = await promptForSecrets(type, authMethod);
983
- const selectedModel2 = await promptForModelSelection(type);
984
873
  return {
985
874
  type,
986
875
  authMethod,
987
876
  secrets,
988
- selectedModel: selectedModel2,
989
877
  isInteractiveMode: true
990
878
  };
991
879
  }
@@ -1006,34 +894,7 @@ async function handleInteractiveMode() {
1006
894
  return null;
1007
895
  }
1008
896
  const secret = secretResponse.secret;
1009
- const selectedModel = await promptForModelSelection(type);
1010
- return { type, secret, selectedModel, isInteractiveMode: true };
1011
- }
1012
- async function promptSetAsDefault(type, framework, isDefault) {
1013
- if (isDefault) return;
1014
- let cancelled = false;
1015
- const response = await (0, import_prompts2.default)(
1016
- {
1017
- type: "confirm",
1018
- name: "setDefault",
1019
- message: "Set this provider as default?",
1020
- initial: false
1021
- },
1022
- {
1023
- onCancel: () => {
1024
- cancelled = true;
1025
- return false;
1026
- }
1027
- }
1028
- );
1029
- if (cancelled) {
1030
- console.log(source_default.dim("Cancelled"));
1031
- return;
1032
- }
1033
- if (response.setDefault) {
1034
- await setZeroOrgModelProviderDefault(type);
1035
- console.log(source_default.green(`\u2713 Default for ${framework} set to "${type}"`));
1036
- }
897
+ return { type, secret, isInteractiveMode: true };
1037
898
  }
1038
899
  var setupCommand = new Command().name("setup").description("Configure an org-level model provider").option("-t, --type <type>", "Provider type (for non-interactive mode)").option(
1039
900
  "-s, --secret <value>",
@@ -1043,7 +904,7 @@ var setupCommand = new Command().name("setup").description("Configure an org-lev
1043
904
  ).option(
1044
905
  "-a, --auth-method <method>",
1045
906
  "Auth method (required for multi-auth providers like aws-bedrock)"
1046
- ).option("-m, --model <model>", "Model selection (for non-interactive mode)").action(
907
+ ).action(
1047
908
  withErrorHandler(
1048
909
  async (options) => {
1049
910
  let input;
@@ -1053,7 +914,6 @@ var setupCommand = new Command().name("setup").description("Configure an org-lev
1053
914
  type: options.type,
1054
915
  secret: secretArgs,
1055
916
  authMethod: options.authMethod,
1056
- model: options.model,
1057
917
  commandPrefix: "zero org model-provider setup"
1058
918
  });
1059
919
  } else if (options.type || secretArgs.length > 0) {
@@ -1066,54 +926,21 @@ var setupCommand = new Command().name("setup").description("Configure an org-lev
1066
926
  input = result;
1067
927
  }
1068
928
  if (input.keepExistingSecret) {
1069
- const provider2 = await updateZeroOrgModelProviderModel(
1070
- input.type,
1071
- input.selectedModel
929
+ console.log(
930
+ source_default.green(`\u2713 Org model provider "${input.type}" unchanged`)
1072
931
  );
1073
- const defaultNote2 = provider2.isDefault ? ` (default for ${provider2.framework})` : "";
1074
- const modelNote2 = provider2.selectedModel ? ` with model: ${provider2.selectedModel}` : "";
1075
- if (!hasModelSelection(input.type)) {
1076
- console.log(
1077
- source_default.green(`\u2713 Org model provider "${input.type}" unchanged`)
1078
- );
1079
- } else {
1080
- console.log(
1081
- source_default.green(
1082
- `\u2713 Org model provider "${input.type}" updated${defaultNote2}${modelNote2}`
1083
- )
1084
- );
1085
- }
1086
- if (input.isInteractiveMode) {
1087
- await promptSetAsDefault(
1088
- input.type,
1089
- provider2.framework,
1090
- provider2.isDefault
1091
- );
1092
- }
1093
932
  return;
1094
933
  }
1095
- const { provider, created } = await upsertZeroOrgModelProvider({
934
+ const { created } = await upsertZeroOrgModelProvider({
1096
935
  type: input.type,
1097
936
  secret: input.secret,
1098
937
  authMethod: input.authMethod,
1099
- secrets: input.secrets,
1100
- selectedModel: input.selectedModel
938
+ secrets: input.secrets
1101
939
  });
1102
940
  const action = created ? "created" : "updated";
1103
- const defaultNote = provider.isDefault ? ` (default for ${provider.framework})` : "";
1104
- const modelNote = provider.selectedModel ? ` with model: ${provider.selectedModel}` : "";
1105
941
  console.log(
1106
- source_default.green(
1107
- `\u2713 Org model provider "${input.type}" ${action}${defaultNote}${modelNote}`
1108
- )
942
+ source_default.green(`\u2713 Org model provider "${input.type}" ${action}`)
1109
943
  );
1110
- if (input.isInteractiveMode) {
1111
- await promptSetAsDefault(
1112
- input.type,
1113
- provider.framework,
1114
- provider.isDefault
1115
- );
1116
- }
1117
944
  }
1118
945
  )
1119
946
  );
@@ -1133,29 +960,8 @@ var removeCommand4 = new Command().name("remove").description("Remove an org-lev
1133
960
  })
1134
961
  );
1135
962
 
1136
- // src/commands/zero/org/model-provider/set-default.ts
1137
- init_esm_shims();
1138
- var setDefaultCommand = new Command().name("set-default").description("Set an org-level model provider as default for its framework").argument("<type>", "Model provider type to set as default").action(
1139
- withErrorHandler(async (type) => {
1140
- if (!Object.keys(MODEL_PROVIDER_TYPES).includes(type)) {
1141
- const validTypes = Object.keys(MODEL_PROVIDER_TYPES).join(", ");
1142
- throw new Error(`Invalid type "${type}"`, {
1143
- cause: new Error(`Valid types: ${validTypes}`)
1144
- });
1145
- }
1146
- const provider = await setZeroOrgModelProviderDefault(
1147
- type
1148
- );
1149
- console.log(
1150
- source_default.green(
1151
- `\u2713 Default for ${provider.framework} set to "${provider.type}"`
1152
- )
1153
- );
1154
- })
1155
- );
1156
-
1157
963
  // src/commands/zero/org/model-provider/index.ts
1158
- var zeroOrgModelProviderCommand = new Command().name("model-provider").description("Manage org-level model providers").addCommand(listCommand4).addCommand(setupCommand).addCommand(removeCommand4).addCommand(setDefaultCommand);
964
+ var zeroOrgModelProviderCommand = new Command().name("model-provider").description("Manage org-level model providers").addCommand(listCommand4).addCommand(setupCommand).addCommand(removeCommand4);
1159
965
 
1160
966
  // src/commands/zero/org/index.ts
1161
967
  var zeroOrgCommand = new Command().name("org").description("Manage organization settings, members, and providers").addCommand(statusCommand).addCommand(setCommand).addCommand(listCommand).addCommand(useCommand).addCommand(membersCommand).addCommand(inviteCommand).addCommand(removeCommand).addCommand(leaveCommand).addCommand(deleteCommand).addCommand(zeroOrgSecretCommand).addCommand(zeroOrgVariableCommand).addCommand(zeroOrgModelProviderCommand);
@@ -1431,24 +1237,20 @@ function hasAvatarUpdate(options) {
1431
1237
  return options.avatar !== void 0 || options.avatarRotation !== void 0 || options.avatarSkin !== void 0 || options.avatarHairStyle !== void 0 || options.avatarHairColor !== void 0 || options.avatarExpression !== void 0 || options.avatarIntensity !== void 0;
1432
1238
  }
1433
1239
  function hasAgentFieldUpdate(options) {
1434
- return options.displayName !== void 0 || options.description !== void 0 || options.sound !== void 0 || hasAvatarUpdate(options) || options.skills !== void 0 || options.addSkill !== void 0 || options.removeSkill !== void 0 || options.modelProvider !== void 0 || options.model !== void 0;
1240
+ return options.displayName !== void 0 || options.description !== void 0 || options.sound !== void 0 || hasAvatarUpdate(options) || options.skills !== void 0 || options.addSkill !== void 0 || options.removeSkill !== void 0;
1435
1241
  }
1436
1242
  async function applyAgentUpdate(agentId, options) {
1437
1243
  const hasAvatar = hasAvatarUpdate(options);
1438
1244
  const resolvedAvatarUrl = hasAvatar ? resolveAvatarUrl(options) : void 0;
1439
1245
  const current = await getZeroAgent(agentId);
1440
1246
  const customSkills = resolveCustomSkills(options, current.customSkills ?? []);
1441
- const modelProviderId = options.modelProvider !== void 0 ? parseModelFlag(options.modelProvider) : current.modelProviderId;
1442
- const selectedModel = options.model !== void 0 ? parseModelFlag(options.model) : current.selectedModel;
1443
1247
  const avatarUrl = hasAvatar ? resolvedAvatarUrl : current.avatarUrl ?? void 0;
1444
1248
  await updateZeroAgent(agentId, {
1445
1249
  displayName: options.displayName !== void 0 ? options.displayName : current.displayName ?? void 0,
1446
1250
  description: options.description !== void 0 ? options.description : current.description ?? void 0,
1447
1251
  sound: options.sound !== void 0 ? options.sound : current.sound ?? void 0,
1448
1252
  avatarUrl,
1449
- customSkills,
1450
- modelProviderId,
1451
- selectedModel
1253
+ customSkills
1452
1254
  });
1453
1255
  }
1454
1256
  function validateSkillName(name) {
@@ -1511,13 +1313,7 @@ var editCommand = new Command().name("edit").description("Edit a zero agent").ar
1511
1313
  ).option("--avatar-intensity <level>", "Intensity: chill | normal | hyped").option(
1512
1314
  "--skills <items>",
1513
1315
  "Comma-separated custom skill names to attach (replaces existing)"
1514
- ).option("--add-skill <name>", "Add a custom skill to the agent").option("--remove-skill <name>", "Remove a custom skill from the agent").option("--instructions-file <path>", "Path to new instructions file").option(
1515
- "--model-provider <id>",
1516
- "Model provider UUID, or 'default' to inherit org default"
1517
- ).option(
1518
- "--model <name>",
1519
- "Model name (e.g. claude-sonnet-4-6, MiniMax-M2.7), or 'default' to inherit provider default"
1520
- ).addHelpText(
1316
+ ).option("--add-skill <name>", "Add a custom skill to the agent").option("--remove-skill <name>", "Remove a custom skill from the agent").option("--instructions-file <path>", "Path to new instructions file").addHelpText(
1521
1317
  "after",
1522
1318
  `
1523
1319
  Avatar:
@@ -1547,8 +1343,6 @@ Examples:
1547
1343
  Add a skill: zero agent edit <agent-id> --add-skill my-skill
1548
1344
  Remove a skill: zero agent edit <agent-id> --remove-skill my-skill
1549
1345
  Update instructions: zero agent edit <agent-id> --instructions-file ./instructions.md
1550
- Set model: zero agent edit <agent-id> --model-provider <provider-id> --model MiniMax-M2.7
1551
- Reset model: zero agent edit <agent-id> --model-provider default --model default
1552
1346
  Update yourself: zero agent edit $ZERO_AGENT_ID --description "new role"
1553
1347
 
1554
1348
  Notes:
@@ -1556,14 +1350,13 @@ Notes:
1556
1350
  - Unspecified fields are preserved (not cleared)
1557
1351
  - --skills replaces the entire skill list; --add-skill/--remove-skill modify incrementally
1558
1352
  - --skills cannot be combined with --add-skill or --remove-skill
1559
- - Use 'zero org model-provider list' to see available providers and models
1560
1353
  - To create or edit skill content, use: zero skill --help`
1561
1354
  ).action(
1562
1355
  withErrorHandler(async (agentId, options) => {
1563
1356
  const hasAgentUpdate = hasAgentFieldUpdate(options);
1564
1357
  if (!hasAgentUpdate && !options.instructionsFile) {
1565
1358
  throw new Error(
1566
- "At least one option is required (--display-name, --description, --sound, --avatar, --avatar-*, --skills, --add-skill, --remove-skill, --model-provider, --model, --instructions-file)"
1359
+ "At least one option is required (--display-name, --description, --sound, --avatar, --avatar-*, --skills, --add-skill, --remove-skill, --instructions-file)"
1567
1360
  );
1568
1361
  }
1569
1362
  if (hasAgentUpdate) {
@@ -3943,12 +3736,6 @@ Deploying schedule for agent ${source_default.cyan(params.agentName)}...`
3943
3736
  prompt: params.prompt,
3944
3737
  ...params.existingEnabled !== void 0 && {
3945
3738
  enabled: params.existingEnabled
3946
- },
3947
- ...params.modelProviderId !== void 0 && {
3948
- modelProviderId: params.modelProviderId
3949
- },
3950
- ...params.selectedModel !== void 0 && {
3951
- selectedModel: params.selectedModel
3952
3739
  }
3953
3740
  });
3954
3741
  return deployResult;
@@ -4031,13 +3818,7 @@ async function handleScheduleEnabling(params) {
4031
3818
  var setupCommand2 = new Command().name("setup").description("Create or edit a schedule for a zero agent").argument("<agent-id>", "Agent ID").option("-n, --name <schedule-name>", 'Schedule name (default: "default")').option("-f, --frequency <type>", "Frequency: daily|weekly|monthly|once|loop").option("-t, --time <HH:MM>", "Time to run (24-hour format)").option("-d, --day <day>", "Day of week (mon-sun) or day of month (1-31)").option("-i, --interval <seconds>", "Interval in seconds for loop mode").option("-z, --timezone <tz>", "IANA timezone").option("-p, --prompt <text>", "Prompt to run").option(
4032
3819
  "--prompt-file <path>",
4033
3820
  "Read prompt from file (cannot be used with --prompt)"
4034
- ).option("-e, --enable", "Enable schedule immediately after creation").option(
4035
- "--model-provider <id>",
4036
- "Model provider UUID, or 'default' to inherit from agent/org"
4037
- ).option(
4038
- "--model <name>",
4039
- "Model name (e.g. claude-sonnet-4-6, MiniMax-M2.7), or 'default' to inherit"
4040
- ).addHelpText(
3821
+ ).option("-e, --enable", "Enable schedule immediately after creation").addHelpText(
4041
3822
  "after",
4042
3823
  `
4043
3824
  Examples:
@@ -4048,14 +3829,10 @@ Examples:
4048
3829
  Loop every 5 minutes: zero schedule setup <agent-id> -f loop -i 300 -p "poll for updates"
4049
3830
  Prompt from file: zero schedule setup <agent-id> -f daily -t 09:00 --prompt-file ./prompt.md
4050
3831
  Create and enable: zero schedule setup <agent-id> -f daily -t 09:00 -p "run report" --enable
4051
- Override model: zero schedule setup <agent-id> -f daily -t 09:00 -p "..." --model-provider <id> --model MiniMax-M2.7
4052
- Reset model override: zero schedule setup <agent-id> -f daily -t 09:00 -p "..." --model-provider default --model default
4053
3832
 
4054
3833
  Notes:
4055
3834
  - Re-running setup with the same agent updates the existing "default" schedule
4056
3835
  - Use -n to manage multiple named schedules for the same agent
4057
- - --model-provider and --model default to inheriting the agent's configuration
4058
- - Use 'zero org model-provider list' to see available providers and models
4059
3836
  - All flags are required in non-interactive mode; interactive mode prompts for missing values
4060
3837
  - If the user wants to be notified when a schedule completes, ask them where they want to receive the notification: web chat or Slack, then include it in the prompt`
4061
3838
  ).action(
@@ -4119,9 +3896,7 @@ Notes:
4119
3896
  intervalSeconds,
4120
3897
  timezone,
4121
3898
  prompt: promptText_,
4122
- existingEnabled: existingSchedule?.enabled,
4123
- modelProviderId: parseModelFlag(options.modelProvider),
4124
- selectedModel: parseModelFlag(options.model)
3899
+ existingEnabled: existingSchedule?.enabled
4125
3900
  });
4126
3901
  displayDeployResult(scheduleName, deployResult);
4127
3902
  const shouldPromptEnable = deployResult.created || existingSchedule !== void 0 && !existingSchedule.enabled;
@@ -5097,6 +4872,179 @@ Examples:
5097
4872
  Download a file: zero telegram download-file <file-id> --bot-id <bot-id> -o /tmp/out.jpg`
5098
4873
  );
5099
4874
 
4875
+ // src/commands/zero/phone/index.ts
4876
+ init_esm_shims();
4877
+
4878
+ // src/commands/zero/phone/download-file.ts
4879
+ init_esm_shims();
4880
+ import { basename as basename5, join as join3 } from "path";
4881
+ import { tmpdir as tmpdir3 } from "os";
4882
+ function defaultOutPath3(fileId) {
4883
+ return join3(tmpdir3(), `phone-${basename5(fileId)}`);
4884
+ }
4885
+ var downloadFileCommand3 = new Command().name("download-file").description("Download an AgentPhone media file by id").argument(
4886
+ "<file-id>",
4887
+ "AgentPhone message id from an [AgentPhone file] block"
4888
+ ).option(
4889
+ "-o, --out <path>",
4890
+ "Output path for the downloaded file (default: /tmp/phone-<file-id>)"
4891
+ ).addHelpText(
4892
+ "after",
4893
+ `
4894
+ Examples:
4895
+ Download to default temp path: zero phone download-file msg_123
4896
+ Download to explicit path: zero phone download-file msg_123 -o /tmp/photo.jpg
4897
+
4898
+ Output:
4899
+ Prints a JSON object to stdout on success:
4900
+ {"path":"/tmp/phone-msg_123","mimetype":"image/jpeg","size":12345}
4901
+
4902
+ How to read the downloaded file:
4903
+ - Images (png/jpg/gif/webp/svg): open the file path with your image viewing tool
4904
+ - Videos (mp4/mov/webm): extract frames first with
4905
+ ffmpeg -i <path> -vf "fps=1" -q:v 2 /tmp/<file-id>_frame_%03d.jpg
4906
+ then view the extracted frames
4907
+ - PDF/text/csv/json/markdown: read the file directly`
4908
+ ).action(
4909
+ withErrorHandler(async (fileId, options) => {
4910
+ const outPath = options.out ?? defaultOutPath3(fileId);
4911
+ const result = await downloadPhoneFile(fileId, outPath);
4912
+ console.log(JSON.stringify(result));
4913
+ })
4914
+ );
4915
+
4916
+ // src/commands/zero/phone/message.ts
4917
+ init_esm_shims();
4918
+ import { readFileSync as readFileSync9 } from "fs";
4919
+ var messageCommand = new Command().name("message").description("Send an AgentPhone text message").requiredOption("--to <phone>", "Connected phone handle to message").option("--agent-id <id>", "AgentPhone agent ID (inferred when omitted)").option("-t, --text <message>", "Message text").addHelpText(
4920
+ "after",
4921
+ `
4922
+ Examples:
4923
+ Send a message: zero phone message --to +15551234567 -t "Hello!"
4924
+ From stdin: printf "Hello!" | zero phone message --to +15551234567
4925
+
4926
+ Notes:
4927
+ - The phone handle must already be connected to the authenticated VM0 user
4928
+ - AgentPhone agent ID is inferred from the conversation when omitted`
4929
+ ).action(
4930
+ withErrorHandler(
4931
+ async (options) => {
4932
+ let text = options.text;
4933
+ if (!text && process.stdin.isTTY === false) {
4934
+ text = readFileSync9("/dev/stdin", "utf8").trim();
4935
+ }
4936
+ if (!text) {
4937
+ throw new Error("Either --text or piped stdin must be provided", {
4938
+ cause: new Error(
4939
+ 'Usage: zero phone message --to +15551234567 -t "your message"'
4940
+ )
4941
+ });
4942
+ }
4943
+ const result = await sendPhoneMessage({
4944
+ toNumber: options.to,
4945
+ text,
4946
+ agentphoneAgentId: options.agentId
4947
+ });
4948
+ console.log(
4949
+ source_default.green(`\u2713 Message sent (message_id: ${result.messageId})`)
4950
+ );
4951
+ }
4952
+ )
4953
+ );
4954
+
4955
+ // src/commands/zero/phone/upload-file.ts
4956
+ init_esm_shims();
4957
+ import { readFileSync as readFileSync10, statSync as statSync3 } from "fs";
4958
+ import { basename as basename6, extname as extname2 } from "path";
4959
+ var MIME_BY_EXTENSION2 = {
4960
+ ".png": "image/png",
4961
+ ".jpg": "image/jpeg",
4962
+ ".jpeg": "image/jpeg",
4963
+ ".gif": "image/gif",
4964
+ ".webp": "image/webp",
4965
+ ".svg": "image/svg+xml",
4966
+ ".mp4": "video/mp4",
4967
+ ".webm": "video/webm",
4968
+ ".mov": "video/quicktime",
4969
+ ".pdf": "application/pdf",
4970
+ ".txt": "text/plain",
4971
+ ".csv": "text/csv",
4972
+ ".md": "text/markdown",
4973
+ ".json": "application/json"
4974
+ };
4975
+ function inferContentType2(localPath) {
4976
+ const ext = extname2(localPath).toLowerCase();
4977
+ return MIME_BY_EXTENSION2[ext] ?? "application/octet-stream";
4978
+ }
4979
+ var uploadFileCommand3 = new Command().name("upload-file").description("Upload a local file to an AgentPhone conversation").requiredOption("-f, --file <path>", "Local file path to upload").requiredOption("--to <phone>", "Connected phone handle to message").option("--agent-id <id>", "AgentPhone agent ID (inferred when omitted)").option("--caption <text>", "Caption to accompany the file").option("--content-type <mime>", "Override inferred content type").addHelpText(
4980
+ "after",
4981
+ `
4982
+ Examples:
4983
+ Upload a file: zero phone upload-file -f /tmp/report.pdf --to +15551234567
4984
+ With a caption: zero phone upload-file -f /tmp/photo.jpg --to +15551234567 --caption "Here it is"
4985
+
4986
+ Output:
4987
+ Prints a JSON object to stdout on success:
4988
+ {"messageId":"msg_123","toNumber":"+15551234567","filename":"report.pdf","mimetype":"application/pdf","size":12345,"url":"https://..."}`
4989
+ ).action(
4990
+ withErrorHandler(
4991
+ async (options) => {
4992
+ let fileSize;
4993
+ try {
4994
+ const stat = statSync3(options.file);
4995
+ if (!stat.isFile()) {
4996
+ throw new Error(`Not a regular file: ${options.file}`);
4997
+ }
4998
+ fileSize = stat.size;
4999
+ } catch (error) {
5000
+ if (error instanceof Error && error.message.startsWith("Not ")) {
5001
+ throw error;
5002
+ }
5003
+ throw new Error(`File not found: ${options.file}`);
5004
+ }
5005
+ if (fileSize === 0) {
5006
+ throw new Error("File is empty");
5007
+ }
5008
+ const filename = basename6(options.file);
5009
+ const contentType = options.contentType ?? inferContentType2(options.file);
5010
+ const prepared = await initPhoneFileUpload({
5011
+ filename,
5012
+ contentType,
5013
+ length: fileSize
5014
+ });
5015
+ const fileContent = readFileSync10(options.file);
5016
+ const uploadResponse = await fetch(prepared.uploadUrl, {
5017
+ method: "PUT",
5018
+ headers: { "Content-Type": prepared.contentType },
5019
+ body: new Uint8Array(fileContent)
5020
+ });
5021
+ if (!uploadResponse.ok) {
5022
+ throw new Error(
5023
+ `File upload failed: ${uploadResponse.status} ${uploadResponse.statusText}`
5024
+ );
5025
+ }
5026
+ const result = await completePhoneFileUpload({
5027
+ uploadId: prepared.uploadId,
5028
+ toNumber: options.to,
5029
+ agentphoneAgentId: options.agentId,
5030
+ contentType: prepared.contentType,
5031
+ caption: options.caption
5032
+ });
5033
+ console.log(JSON.stringify(result));
5034
+ }
5035
+ )
5036
+ );
5037
+
5038
+ // src/commands/zero/phone/index.ts
5039
+ var zeroPhoneCommand = new Command().name("phone").description("Send AgentPhone messages, upload files, and download media").addCommand(messageCommand).addCommand(downloadFileCommand3).addCommand(uploadFileCommand3).addHelpText(
5040
+ "after",
5041
+ `
5042
+ Examples:
5043
+ Send a message: zero phone message --to +15551234567 -t "Hello!"
5044
+ Upload a file: zero phone upload-file -f /tmp/report.pdf --to +15551234567
5045
+ Download a file: zero phone download-file <file-id> -o /tmp/out.jpg`
5046
+ );
5047
+
5100
5048
  // src/commands/zero/variable/index.ts
5101
5049
  init_esm_shims();
5102
5050
 
@@ -5344,8 +5292,8 @@ init_esm_shims();
5344
5292
 
5345
5293
  // src/lib/skill-directory.ts
5346
5294
  init_esm_shims();
5347
- import { readFileSync as readFileSync9, readdirSync } from "fs";
5348
- import { join as join3 } from "path";
5295
+ import { readFileSync as readFileSync11, readdirSync } from "fs";
5296
+ import { join as join4 } from "path";
5349
5297
  var IGNORED_NAMES = /* @__PURE__ */ new Set(["node_modules", ".git", ".DS_Store"]);
5350
5298
  function readSkillDirectory(dirPath) {
5351
5299
  const files = [];
@@ -5355,11 +5303,11 @@ function readSkillDirectory(dirPath) {
5355
5303
  if (entry.name.startsWith(".") || IGNORED_NAMES.has(entry.name)) continue;
5356
5304
  const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
5357
5305
  if (entry.isDirectory()) {
5358
- walk(join3(dir, entry.name), relPath);
5306
+ walk(join4(dir, entry.name), relPath);
5359
5307
  } else {
5360
5308
  files.push({
5361
5309
  path: relPath,
5362
- content: readFileSync9(join3(dir, entry.name), "utf-8")
5310
+ content: readFileSync11(join4(dir, entry.name), "utf-8")
5363
5311
  });
5364
5312
  }
5365
5313
  }
@@ -6125,12 +6073,12 @@ init_esm_shims();
6125
6073
  import { execFile } from "child_process";
6126
6074
  import { readFile, unlink } from "fs/promises";
6127
6075
  import { randomUUID } from "crypto";
6128
- import { join as join4 } from "path";
6129
- import { tmpdir as tmpdir3 } from "os";
6076
+ import { join as join5 } from "path";
6077
+ import { tmpdir as tmpdir4 } from "os";
6130
6078
  import { promisify } from "util";
6131
6079
  var execFileAsync = promisify(execFile);
6132
6080
  async function captureScreenshot() {
6133
- const tmpPath = join4(tmpdir3(), `vm0-screenshot-${randomUUID()}.jpg`);
6081
+ const tmpPath = join5(tmpdir4(), `vm0-screenshot-${randomUUID()}.jpg`);
6134
6082
  try {
6135
6083
  await execFileAsync("screencapture", ["-x", "-t", "jpg", tmpPath]);
6136
6084
  const info = await getScreenInfo();
@@ -6159,7 +6107,7 @@ async function captureScreenshot() {
6159
6107
  }
6160
6108
  }
6161
6109
  async function captureRegionScreenshot(region) {
6162
- const tmpPath = join4(tmpdir3(), `vm0-zoom-${randomUUID()}.jpg`);
6110
+ const tmpPath = join5(tmpdir4(), `vm0-zoom-${randomUUID()}.jpg`);
6163
6111
  try {
6164
6112
  const regionArg = `${region.x},${region.y},${region.width},${region.height}`;
6165
6113
  await execFileAsync("screencapture", [
@@ -6851,7 +6799,7 @@ var hostStopCommand = new Command().name("stop").description("Stop and unregiste
6851
6799
  // src/commands/zero/computer-use/client.ts
6852
6800
  init_esm_shims();
6853
6801
  import { writeFile, mkdir } from "fs/promises";
6854
- import { basename as basename5, join as join5 } from "path";
6802
+ import { basename as basename7, join as join6 } from "path";
6855
6803
 
6856
6804
  // src/lib/computer-use/client.ts
6857
6805
  init_esm_shims();
@@ -6896,7 +6844,7 @@ async function callHost(path, options) {
6896
6844
 
6897
6845
  // src/commands/zero/computer-use/client.ts
6898
6846
  function safeFormat(format) {
6899
- return basename5(format);
6847
+ return basename7(format);
6900
6848
  }
6901
6849
  function mouseClickCommand(name, action, description) {
6902
6850
  return new Command().name(name).description(description).argument("<x>", "X coordinate (points)").argument("<y>", "Y coordinate (points)").action(
@@ -6922,7 +6870,7 @@ var clientScreenshotCommand = new Command().name("screenshot").description("Capt
6922
6870
  const dir = "/tmp/computer-use";
6923
6871
  await mkdir(dir, { recursive: true });
6924
6872
  const timestamp = Date.now();
6925
- const filePath = join5(
6873
+ const filePath = join6(
6926
6874
  dir,
6927
6875
  `screenshot-${timestamp}.${safeFormat(data.format)}`
6928
6876
  );
@@ -6953,7 +6901,7 @@ var clientZoomCommand = new Command().name("zoom").description("Capture a region
6953
6901
  const dir = "/tmp/computer-use";
6954
6902
  await mkdir(dir, { recursive: true });
6955
6903
  const timestamp = Date.now();
6956
- const filePath = join5(
6904
+ const filePath = join6(
6957
6905
  dir,
6958
6906
  `zoom-${timestamp}.${safeFormat(data.format)}`
6959
6907
  );
@@ -7159,13 +7107,13 @@ init_esm_shims();
7159
7107
 
7160
7108
  // src/commands/zero/shared/image-generate.ts
7161
7109
  init_esm_shims();
7162
- import { readFileSync as readFileSync10 } from "fs";
7110
+ import { readFileSync as readFileSync12 } from "fs";
7163
7111
  function readPrompt(options, usageCommand) {
7164
7112
  if (options.prompt?.trim()) {
7165
7113
  return options.prompt.trim();
7166
7114
  }
7167
7115
  if (process.stdin.isTTY === false) {
7168
- const prompt = readFileSync10("/dev/stdin", "utf8").trim();
7116
+ const prompt = readFileSync12("/dev/stdin", "utf8").trim();
7169
7117
  if (prompt.length > 0) {
7170
7118
  return prompt;
7171
7119
  }
@@ -7239,13 +7187,13 @@ init_esm_shims();
7239
7187
 
7240
7188
  // src/commands/zero/shared/voice-generate.ts
7241
7189
  init_esm_shims();
7242
- import { readFileSync as readFileSync11 } from "fs";
7190
+ import { readFileSync as readFileSync13 } from "fs";
7243
7191
  function readText(options, usageCommand) {
7244
7192
  if (options.text?.trim()) {
7245
7193
  return options.text.trim();
7246
7194
  }
7247
7195
  if (process.stdin.isTTY === false) {
7248
- const text = readFileSync11("/dev/stdin", "utf8").trim();
7196
+ const text = readFileSync13("/dev/stdin", "utf8").trim();
7249
7197
  if (text.length > 0) {
7250
7198
  return text;
7251
7199
  }
@@ -7322,12 +7270,12 @@ init_esm_shims();
7322
7270
 
7323
7271
  // src/commands/zero/web/download-file.ts
7324
7272
  init_esm_shims();
7325
- import { basename as basename6, join as join6 } from "path";
7326
- import { tmpdir as tmpdir4 } from "os";
7327
- function defaultOutPath3(fileId) {
7328
- return join6(tmpdir4(), `web-${basename6(fileId)}`);
7273
+ import { basename as basename8, join as join7 } from "path";
7274
+ import { tmpdir as tmpdir5 } from "os";
7275
+ function defaultOutPath4(fileId) {
7276
+ return join7(tmpdir5(), `web-${basename8(fileId)}`);
7329
7277
  }
7330
- var downloadFileCommand3 = new Command().name("download-file").description("Download a web-uploaded file by id").argument("<file-id>", "File id (UUID returned by the upload API)").option(
7278
+ var downloadFileCommand4 = new Command().name("download-file").description("Download a web-uploaded file by id").argument("<file-id>", "File id (UUID returned by the upload API)").option(
7331
7279
  "-o, --out <path>",
7332
7280
  "Output path for the downloaded file (default: /tmp/web-<file-id>)"
7333
7281
  ).addHelpText(
@@ -7353,7 +7301,7 @@ Notes:
7353
7301
  - Streams the file bytes directly to disk`
7354
7302
  ).action(
7355
7303
  withErrorHandler(async (fileId, options) => {
7356
- const outPath = options.out ?? defaultOutPath3(fileId);
7304
+ const outPath = options.out ?? defaultOutPath4(fileId);
7357
7305
  const result = await downloadWebFile(fileId, outPath);
7358
7306
  console.log(JSON.stringify(result));
7359
7307
  })
@@ -7361,7 +7309,7 @@ Notes:
7361
7309
 
7362
7310
  // src/commands/zero/web/upload-file.ts
7363
7311
  init_esm_shims();
7364
- var uploadFileCommand3 = new Command().name("upload-file").description("Upload a local file and print a permanent URL").requiredOption("-f, --file <path>", "Local file path to upload").option("--content-type <mime>", "Override inferred content type").addHelpText(
7312
+ var uploadFileCommand4 = new Command().name("upload-file").description("Upload a local file and print a permanent URL").requiredOption("-f, --file <path>", "Local file path to upload").option("--content-type <mime>", "Override inferred content type").addHelpText(
7365
7313
  "after",
7366
7314
  `
7367
7315
  Examples:
@@ -7395,7 +7343,7 @@ Notes:
7395
7343
  );
7396
7344
 
7397
7345
  // src/commands/zero/web/index.ts
7398
- var zeroWebCommand = new Command().name("web").description("Upload and download files via the web chat endpoint").addCommand(downloadFileCommand3).addCommand(uploadFileCommand3).addHelpText(
7346
+ var zeroWebCommand = new Command().name("web").description("Upload and download files via the web chat endpoint").addCommand(downloadFileCommand4).addCommand(uploadFileCommand4).addHelpText(
7399
7347
  "after",
7400
7348
  `
7401
7349
  Examples:
@@ -7416,6 +7364,7 @@ var COMMAND_CAPABILITY_MAP = {
7416
7364
  chat: "chat-message:write",
7417
7365
  slack: "slack:write",
7418
7366
  telegram: ["telegram:read", "telegram:write"],
7367
+ phone: ["phone:read", "phone:write"],
7419
7368
  whoami: null,
7420
7369
  "developer-support": null,
7421
7370
  "computer-use": "computer-use:write",
@@ -7435,6 +7384,7 @@ var DEFAULT_COMMANDS = [
7435
7384
  zeroChatCommand,
7436
7385
  zeroSlackCommand,
7437
7386
  zeroTelegramCommand,
7387
+ zeroPhoneCommand,
7438
7388
  zeroVariableCommand,
7439
7389
  zeroLogsCommand,
7440
7390
  zeroSearchCommand,
@@ -7469,7 +7419,7 @@ function registerZeroCommands(prog, commands) {
7469
7419
  var program = new Command();
7470
7420
  program.name("zero").description(
7471
7421
  "Zero CLI \u2014 interact with the zero platform from inside the sandbox"
7472
- ).version("9.147.2").addHelpText(
7422
+ ).version("9.148.1").addHelpText(
7473
7423
  "after",
7474
7424
  `
7475
7425
  Examples:
@@ -7479,6 +7429,9 @@ Examples:
7479
7429
  Send Telegram? zero telegram message send --help
7480
7430
  Upload Telegram? zero telegram upload-file --help
7481
7431
  Download Telegram? zero telegram download-file --help
7432
+ Send AgentPhone? zero phone message --help
7433
+ Upload AgentPhone? zero phone upload-file --help
7434
+ Download AgentPhone? zero phone download-file --help
7482
7435
  Set up a schedule? zero schedule setup --help
7483
7436
  Update yourself? zero agent --help
7484
7437
  Manage custom skills? zero skill --help