openhome-cli 0.1.13 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -855,11 +855,44 @@ async function resolveAbilityDir(pathArg) {
855
855
  return resolve(pathInput.trim());
856
856
  }
857
857
  async function deployCommand(pathArg, opts = {}) {
858
- p.intro("\u{1F680} Deploy ability");
858
+ p.intro("\u{1F680} Upload Ability");
859
859
  if (pathArg && pathArg.endsWith(".zip") && existsSync2(resolve(pathArg))) {
860
860
  await deployZip(resolve(pathArg), opts);
861
861
  return;
862
862
  }
863
+ if (!pathArg) {
864
+ const mode = await p.select({
865
+ message: "What do you want to upload?",
866
+ options: [
867
+ {
868
+ value: "zip",
869
+ label: "\u{1F4E6} Upload a zip file",
870
+ hint: "I already have a .zip ready"
871
+ },
872
+ {
873
+ value: "folder",
874
+ label: "\u{1F4C1} Upload from a folder",
875
+ hint: "Point me to an ability directory"
876
+ }
877
+ ]
878
+ });
879
+ handleCancel(mode);
880
+ if (mode === "zip") {
881
+ const zipInput = await p.text({
882
+ message: "Path to your zip file",
883
+ placeholder: "./my-ability.zip",
884
+ validate: (val) => {
885
+ if (!val || !val.trim()) return "Path is required";
886
+ const resolved = resolve(val.trim());
887
+ if (!existsSync2(resolved)) return `File not found: ${val.trim()}`;
888
+ if (!resolved.endsWith(".zip")) return "Must be a .zip file";
889
+ }
890
+ });
891
+ handleCancel(zipInput);
892
+ await deployZip(resolve(zipInput.trim()), opts);
893
+ return;
894
+ }
895
+ }
863
896
  const targetDir = await resolveAbilityDir(pathArg);
864
897
  const s = p.spinner();
865
898
  s.start("Validating ability...");
@@ -3418,10 +3451,15 @@ async function interactiveMenu() {
3418
3451
  const choice = await p.select({
3419
3452
  message: "What would you like to do?",
3420
3453
  options: [
3454
+ {
3455
+ value: "deploy",
3456
+ label: "\u2B06\uFE0F Upload Ability",
3457
+ hint: "Upload a zip file to OpenHome"
3458
+ },
3421
3459
  {
3422
3460
  value: "init",
3423
- label: "\u2728 Create Ability",
3424
- hint: "Scaffold and deploy a new ability"
3461
+ label: "\u2728 Scaffold Ability",
3462
+ hint: "Generate a new ability from a template"
3425
3463
  },
3426
3464
  {
3427
3465
  value: "list",
@@ -3468,6 +3506,9 @@ async function interactiveMenu() {
3468
3506
  });
3469
3507
  handleCancel(choice);
3470
3508
  switch (choice) {
3509
+ case "deploy":
3510
+ await deployCommand();
3511
+ break;
3471
3512
  case "init":
3472
3513
  await initCommand();
3473
3514
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openhome-cli",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "CLI for managing OpenHome voice AI abilities",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.ts CHANGED
@@ -108,10 +108,15 @@ async function interactiveMenu(): Promise<void> {
108
108
  const choice = await p.select({
109
109
  message: "What would you like to do?",
110
110
  options: [
111
+ {
112
+ value: "deploy",
113
+ label: "⬆️ Upload Ability",
114
+ hint: "Upload a zip file to OpenHome",
115
+ },
111
116
  {
112
117
  value: "init",
113
- label: "✨ Create Ability",
114
- hint: "Scaffold and deploy a new ability",
118
+ label: "✨ Scaffold Ability",
119
+ hint: "Generate a new ability from a template",
115
120
  },
116
121
  {
117
122
  value: "list",
@@ -159,6 +164,9 @@ async function interactiveMenu(): Promise<void> {
159
164
  handleCancel(choice);
160
165
 
161
166
  switch (choice) {
167
+ case "deploy":
168
+ await deployCommand();
169
+ break;
162
170
  case "init":
163
171
  await initCommand();
164
172
  break;
@@ -120,14 +120,50 @@ export async function deployCommand(
120
120
  pathArg?: string,
121
121
  opts: { dryRun?: boolean; mock?: boolean; personality?: string } = {},
122
122
  ): Promise<void> {
123
- p.intro("🚀 Deploy ability");
123
+ p.intro("🚀 Upload Ability");
124
124
 
125
- // Direct zip upload path
125
+ // Explicit zip file passed
126
126
  if (pathArg && pathArg.endsWith(".zip") && existsSync(resolve(pathArg))) {
127
127
  await deployZip(resolve(pathArg), opts);
128
128
  return;
129
129
  }
130
130
 
131
+ // No arg — ask whether they have a zip or a folder
132
+ if (!pathArg) {
133
+ const mode = await p.select({
134
+ message: "What do you want to upload?",
135
+ options: [
136
+ {
137
+ value: "zip",
138
+ label: "📦 Upload a zip file",
139
+ hint: "I already have a .zip ready",
140
+ },
141
+ {
142
+ value: "folder",
143
+ label: "📁 Upload from a folder",
144
+ hint: "Point me to an ability directory",
145
+ },
146
+ ],
147
+ });
148
+ handleCancel(mode);
149
+
150
+ if (mode === "zip") {
151
+ const zipInput = await p.text({
152
+ message: "Path to your zip file",
153
+ placeholder: "./my-ability.zip",
154
+ validate: (val) => {
155
+ if (!val || !val.trim()) return "Path is required";
156
+ const resolved = resolve(val.trim());
157
+ if (!existsSync(resolved)) return `File not found: ${val.trim()}`;
158
+ if (!resolved.endsWith(".zip")) return "Must be a .zip file";
159
+ },
160
+ });
161
+ handleCancel(zipInput);
162
+ await deployZip(resolve((zipInput as string).trim()), opts);
163
+ return;
164
+ }
165
+ }
166
+
131
167
  const targetDir = await resolveAbilityDir(pathArg);
132
168
 
133
169
  // Step 1: Validate