openhome-cli 0.1.13 → 0.1.15
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 +99 -3
- package/package.json +1 -1
- package/src/cli.ts +10 -2
- package/src/commands/deploy.ts +101 -2
package/dist/cli.js
CHANGED
|
@@ -855,11 +855,99 @@ async function resolveAbilityDir(pathArg) {
|
|
|
855
855
|
return resolve(pathInput.trim());
|
|
856
856
|
}
|
|
857
857
|
async function deployCommand(pathArg, opts = {}) {
|
|
858
|
-
p.intro("\u{1F680}
|
|
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 home = homedir();
|
|
882
|
+
const scanDirs = [
|
|
883
|
+
process.cwd(),
|
|
884
|
+
join2(home, "Desktop"),
|
|
885
|
+
join2(home, "Downloads"),
|
|
886
|
+
join2(home, "Documents")
|
|
887
|
+
];
|
|
888
|
+
const foundZips = [];
|
|
889
|
+
for (const dir of scanDirs) {
|
|
890
|
+
if (!existsSync2(dir)) continue;
|
|
891
|
+
try {
|
|
892
|
+
for (const file of readdirSync2(dir)) {
|
|
893
|
+
if (file.endsWith(".zip")) {
|
|
894
|
+
const full = join2(dir, file);
|
|
895
|
+
const shortDir = dir.startsWith(home) ? `~${dir.slice(home.length)}` : dir;
|
|
896
|
+
foundZips.push({ path: full, label: `${file} (${shortDir})` });
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
} catch {
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
let zipPath;
|
|
903
|
+
if (foundZips.length > 0) {
|
|
904
|
+
const zipOptions = [
|
|
905
|
+
...foundZips.map((z) => ({ value: z.path, label: z.label })),
|
|
906
|
+
{
|
|
907
|
+
value: "__custom__",
|
|
908
|
+
label: "Other...",
|
|
909
|
+
hint: "Enter a path manually"
|
|
910
|
+
}
|
|
911
|
+
];
|
|
912
|
+
const selected = await p.select({
|
|
913
|
+
message: "Select your zip file",
|
|
914
|
+
options: zipOptions
|
|
915
|
+
});
|
|
916
|
+
handleCancel(selected);
|
|
917
|
+
if (selected === "__custom__") {
|
|
918
|
+
const zipInput = await p.text({
|
|
919
|
+
message: "Path to your zip file",
|
|
920
|
+
placeholder: "~/path/to/ability.zip",
|
|
921
|
+
validate: (val) => {
|
|
922
|
+
if (!val || !val.trim()) return "Path is required";
|
|
923
|
+
if (!existsSync2(resolve(val.trim())))
|
|
924
|
+
return `File not found: ${val.trim()}`;
|
|
925
|
+
if (!val.trim().endsWith(".zip")) return "Must be a .zip file";
|
|
926
|
+
}
|
|
927
|
+
});
|
|
928
|
+
handleCancel(zipInput);
|
|
929
|
+
zipPath = resolve(zipInput.trim());
|
|
930
|
+
} else {
|
|
931
|
+
zipPath = selected;
|
|
932
|
+
}
|
|
933
|
+
} else {
|
|
934
|
+
const zipInput = await p.text({
|
|
935
|
+
message: "Path to your zip file",
|
|
936
|
+
placeholder: "~/Downloads/my-ability.zip",
|
|
937
|
+
validate: (val) => {
|
|
938
|
+
if (!val || !val.trim()) return "Path is required";
|
|
939
|
+
if (!existsSync2(resolve(val.trim())))
|
|
940
|
+
return `File not found: ${val.trim()}`;
|
|
941
|
+
if (!val.trim().endsWith(".zip")) return "Must be a .zip file";
|
|
942
|
+
}
|
|
943
|
+
});
|
|
944
|
+
handleCancel(zipInput);
|
|
945
|
+
zipPath = resolve(zipInput.trim());
|
|
946
|
+
}
|
|
947
|
+
await deployZip(zipPath, opts);
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
863
951
|
const targetDir = await resolveAbilityDir(pathArg);
|
|
864
952
|
const s = p.spinner();
|
|
865
953
|
s.start("Validating ability...");
|
|
@@ -3418,10 +3506,15 @@ async function interactiveMenu() {
|
|
|
3418
3506
|
const choice = await p.select({
|
|
3419
3507
|
message: "What would you like to do?",
|
|
3420
3508
|
options: [
|
|
3509
|
+
{
|
|
3510
|
+
value: "deploy",
|
|
3511
|
+
label: "\u2B06\uFE0F Upload Ability",
|
|
3512
|
+
hint: "Upload a zip file to OpenHome"
|
|
3513
|
+
},
|
|
3421
3514
|
{
|
|
3422
3515
|
value: "init",
|
|
3423
|
-
label: "\u2728
|
|
3424
|
-
hint: "
|
|
3516
|
+
label: "\u2728 Scaffold Ability",
|
|
3517
|
+
hint: "Generate a new ability from a template"
|
|
3425
3518
|
},
|
|
3426
3519
|
{
|
|
3427
3520
|
value: "list",
|
|
@@ -3468,6 +3561,9 @@ async function interactiveMenu() {
|
|
|
3468
3561
|
});
|
|
3469
3562
|
handleCancel(choice);
|
|
3470
3563
|
switch (choice) {
|
|
3564
|
+
case "deploy":
|
|
3565
|
+
await deployCommand();
|
|
3566
|
+
break;
|
|
3471
3567
|
case "init":
|
|
3472
3568
|
await initCommand();
|
|
3473
3569
|
break;
|
package/package.json
CHANGED
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: "✨
|
|
114
|
-
hint: "
|
|
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;
|
package/src/commands/deploy.ts
CHANGED
|
@@ -120,14 +120,113 @@ export async function deployCommand(
|
|
|
120
120
|
pathArg?: string,
|
|
121
121
|
opts: { dryRun?: boolean; mock?: boolean; personality?: string } = {},
|
|
122
122
|
): Promise<void> {
|
|
123
|
-
p.intro("🚀
|
|
123
|
+
p.intro("🚀 Upload Ability");
|
|
124
124
|
|
|
125
|
-
//
|
|
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 home = homedir();
|
|
152
|
+
const scanDirs = [
|
|
153
|
+
process.cwd(),
|
|
154
|
+
join(home, "Desktop"),
|
|
155
|
+
join(home, "Downloads"),
|
|
156
|
+
join(home, "Documents"),
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
const foundZips: { path: string; label: string }[] = [];
|
|
160
|
+
for (const dir of scanDirs) {
|
|
161
|
+
if (!existsSync(dir)) continue;
|
|
162
|
+
try {
|
|
163
|
+
for (const file of readdirSync(dir)) {
|
|
164
|
+
if (file.endsWith(".zip")) {
|
|
165
|
+
const full = join(dir, file);
|
|
166
|
+
const shortDir = dir.startsWith(home)
|
|
167
|
+
? `~${dir.slice(home.length)}`
|
|
168
|
+
: dir;
|
|
169
|
+
foundZips.push({ path: full, label: `${file} (${shortDir})` });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
// skip unreadable dirs
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
let zipPath: string;
|
|
178
|
+
|
|
179
|
+
if (foundZips.length > 0) {
|
|
180
|
+
const zipOptions = [
|
|
181
|
+
...foundZips.map((z) => ({ value: z.path, label: z.label })),
|
|
182
|
+
{
|
|
183
|
+
value: "__custom__",
|
|
184
|
+
label: "Other...",
|
|
185
|
+
hint: "Enter a path manually",
|
|
186
|
+
},
|
|
187
|
+
];
|
|
188
|
+
const selected = await p.select({
|
|
189
|
+
message: "Select your zip file",
|
|
190
|
+
options: zipOptions,
|
|
191
|
+
});
|
|
192
|
+
handleCancel(selected);
|
|
193
|
+
|
|
194
|
+
if (selected === "__custom__") {
|
|
195
|
+
const zipInput = await p.text({
|
|
196
|
+
message: "Path to your zip file",
|
|
197
|
+
placeholder: "~/path/to/ability.zip",
|
|
198
|
+
validate: (val) => {
|
|
199
|
+
if (!val || !val.trim()) return "Path is required";
|
|
200
|
+
if (!existsSync(resolve(val.trim())))
|
|
201
|
+
return `File not found: ${val.trim()}`;
|
|
202
|
+
if (!val.trim().endsWith(".zip")) return "Must be a .zip file";
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
handleCancel(zipInput);
|
|
206
|
+
zipPath = resolve((zipInput as string).trim());
|
|
207
|
+
} else {
|
|
208
|
+
zipPath = selected as string;
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
const zipInput = await p.text({
|
|
212
|
+
message: "Path to your zip file",
|
|
213
|
+
placeholder: "~/Downloads/my-ability.zip",
|
|
214
|
+
validate: (val) => {
|
|
215
|
+
if (!val || !val.trim()) return "Path is required";
|
|
216
|
+
if (!existsSync(resolve(val.trim())))
|
|
217
|
+
return `File not found: ${val.trim()}`;
|
|
218
|
+
if (!val.trim().endsWith(".zip")) return "Must be a .zip file";
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
handleCancel(zipInput);
|
|
222
|
+
zipPath = resolve((zipInput as string).trim());
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
await deployZip(zipPath, opts);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
131
230
|
const targetDir = await resolveAbilityDir(pathArg);
|
|
132
231
|
|
|
133
232
|
// Step 1: Validate
|