hypha-cli 0.1.7 → 0.1.9
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/apps-CpJkx863.mjs +512 -0
- package/dist/apps-D659xu7q.mjs +424 -0
- package/dist/artifacts-C0yhSTgw.mjs +629 -0
- package/dist/artifacts-DdgZRh8t.mjs +764 -0
- package/dist/cli.mjs +28 -6
- package/dist/workspace-BwLwj61H.mjs +206 -0
- package/dist/workspace-DCueGyht.mjs +127 -0
- package/dist/workspace-DDljPOfV.mjs +286 -0
- package/dist/workspace-DMqqSmvB.mjs +283 -0
- package/dist/{workspace-D63jR8RA.mjs → workspace-RZLvWJpe.mjs} +3 -2
- package/dist/workspace-XO_tEtii.mjs +284 -0
- package/package.json +1 -1
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import { statSync, readFileSync, readdirSync } from 'fs';
|
|
2
|
+
import { join, extname } from 'path';
|
|
3
|
+
import { e as hasFlag, f as formatJson, a as formatTable, p as positionalArgs, j as relativeTime, c as connectToHypha, k as getAllFlags, i as getFlag, g as getFlagInt } from './helpers-BvfSCkvr.mjs';
|
|
4
|
+
import 'os';
|
|
5
|
+
|
|
6
|
+
const IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
7
|
+
"__pycache__",
|
|
8
|
+
".git",
|
|
9
|
+
".venv",
|
|
10
|
+
".idea",
|
|
11
|
+
".pytest_cache",
|
|
12
|
+
".mypy_cache",
|
|
13
|
+
"build",
|
|
14
|
+
"dist",
|
|
15
|
+
"__pypackages__",
|
|
16
|
+
"node_modules"
|
|
17
|
+
]);
|
|
18
|
+
const IGNORED_FILES = /* @__PURE__ */ new Set([
|
|
19
|
+
".DS_Store",
|
|
20
|
+
".gitignore",
|
|
21
|
+
".gitattributes",
|
|
22
|
+
".env"
|
|
23
|
+
]);
|
|
24
|
+
const IGNORED_SUFFIXES = [".pyc", ".pyo", ".swp", ".tmp", ".bak"];
|
|
25
|
+
const TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
26
|
+
".py",
|
|
27
|
+
".js",
|
|
28
|
+
".ts",
|
|
29
|
+
".mjs",
|
|
30
|
+
".cjs",
|
|
31
|
+
".jsx",
|
|
32
|
+
".tsx",
|
|
33
|
+
".html",
|
|
34
|
+
".htm",
|
|
35
|
+
".css",
|
|
36
|
+
".scss",
|
|
37
|
+
".less",
|
|
38
|
+
".json",
|
|
39
|
+
".yaml",
|
|
40
|
+
".yml",
|
|
41
|
+
".toml",
|
|
42
|
+
".ini",
|
|
43
|
+
".cfg",
|
|
44
|
+
".conf",
|
|
45
|
+
".md",
|
|
46
|
+
".txt",
|
|
47
|
+
".rst",
|
|
48
|
+
".csv",
|
|
49
|
+
".tsv",
|
|
50
|
+
".sh",
|
|
51
|
+
".bash",
|
|
52
|
+
".zsh",
|
|
53
|
+
".fish",
|
|
54
|
+
".xml",
|
|
55
|
+
".svg",
|
|
56
|
+
".sql",
|
|
57
|
+
".r",
|
|
58
|
+
".R",
|
|
59
|
+
".jl",
|
|
60
|
+
".c",
|
|
61
|
+
".h",
|
|
62
|
+
".cpp",
|
|
63
|
+
".hpp",
|
|
64
|
+
".java",
|
|
65
|
+
".go",
|
|
66
|
+
".rs",
|
|
67
|
+
".dockerfile",
|
|
68
|
+
".env.example"
|
|
69
|
+
]);
|
|
70
|
+
function isTextFile(name) {
|
|
71
|
+
const ext = extname(name).toLowerCase();
|
|
72
|
+
if (TEXT_EXTENSIONS.has(ext)) return true;
|
|
73
|
+
if (!ext && !name.startsWith(".")) return true;
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
function isIgnored(name, isDir) {
|
|
77
|
+
if (isDir) return IGNORED_DIRS.has(name);
|
|
78
|
+
if (IGNORED_FILES.has(name)) return true;
|
|
79
|
+
return IGNORED_SUFFIXES.some((s) => name.endsWith(s));
|
|
80
|
+
}
|
|
81
|
+
function collectFiles(dir, base = "") {
|
|
82
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
83
|
+
const files = [];
|
|
84
|
+
for (const entry of entries) {
|
|
85
|
+
if (isIgnored(entry.name, entry.isDirectory())) continue;
|
|
86
|
+
const fullPath = join(dir, entry.name);
|
|
87
|
+
const relPath = base ? `${base}/${entry.name}` : entry.name;
|
|
88
|
+
if (entry.isDirectory()) {
|
|
89
|
+
files.push(...collectFiles(fullPath, relPath));
|
|
90
|
+
} else {
|
|
91
|
+
if (isTextFile(entry.name)) {
|
|
92
|
+
files.push({ name: relPath, content: readFileSync(fullPath, "utf-8"), format: "text" });
|
|
93
|
+
} else {
|
|
94
|
+
files.push({ name: relPath, content: readFileSync(fullPath).toString("base64"), format: "base64" });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return files;
|
|
99
|
+
}
|
|
100
|
+
function parseInstallArgs(args) {
|
|
101
|
+
const source = positionalArgs(args, ["--id", "--manifest", "--files"])[0];
|
|
102
|
+
return {
|
|
103
|
+
source,
|
|
104
|
+
id: getFlag(args, "--id"),
|
|
105
|
+
manifest: getFlag(args, "--manifest"),
|
|
106
|
+
files: getAllFlags(args, "--files"),
|
|
107
|
+
overwrite: hasFlag(args, "--overwrite")
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function parseStartArgs(args) {
|
|
111
|
+
const pos = positionalArgs(args, ["--timeout"])[0];
|
|
112
|
+
return {
|
|
113
|
+
appId: pos,
|
|
114
|
+
timeout: getFlagInt(args, "--timeout"),
|
|
115
|
+
wait: hasFlag(args, "--wait")
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function parseStopArgs(args) {
|
|
119
|
+
const pos = positionalArgs(args)[0];
|
|
120
|
+
return {
|
|
121
|
+
id: pos,
|
|
122
|
+
all: hasFlag(args, "--all")
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function parseLogsArgs(args) {
|
|
126
|
+
const pos = positionalArgs(args, ["--tail", "--type"])[0];
|
|
127
|
+
return {
|
|
128
|
+
instanceId: pos,
|
|
129
|
+
tail: getFlagInt(args, "--tail"),
|
|
130
|
+
type: getFlag(args, "--type")
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function printAppsHelp() {
|
|
134
|
+
console.log(`hypha apps \u2014 manage server apps
|
|
135
|
+
|
|
136
|
+
Usage: hypha apps <command> [options]
|
|
137
|
+
|
|
138
|
+
Commands:
|
|
139
|
+
list [--json] List installed app definitions
|
|
140
|
+
info <app-id> [--json] Show app details
|
|
141
|
+
install <source> [options] Install an app definition
|
|
142
|
+
uninstall <app-id> Remove an app definition
|
|
143
|
+
start <app-id> [options] Start an app instance
|
|
144
|
+
stop <id> [--all] Stop instance(s)
|
|
145
|
+
ps [--json] List running instances
|
|
146
|
+
logs <instance-id> [options] View instance logs
|
|
147
|
+
|
|
148
|
+
Install options:
|
|
149
|
+
--id <app-id> Custom app ID (default: derived from source)
|
|
150
|
+
--manifest <path> Manifest file (JSON/YAML)
|
|
151
|
+
--files <dir> Additional file directory (repeatable)
|
|
152
|
+
--overwrite Overwrite existing app
|
|
153
|
+
|
|
154
|
+
Start options:
|
|
155
|
+
--timeout <seconds> Start timeout (default: 60)
|
|
156
|
+
--wait Wait for service to be ready
|
|
157
|
+
|
|
158
|
+
Logs options:
|
|
159
|
+
--tail <n> Show last N log entries
|
|
160
|
+
--type <stdout|stderr> Filter by log type`);
|
|
161
|
+
}
|
|
162
|
+
async function getServerApps() {
|
|
163
|
+
const server = await connectToHypha();
|
|
164
|
+
const serverApps = await server.getService("server-apps");
|
|
165
|
+
return [server, serverApps];
|
|
166
|
+
}
|
|
167
|
+
async function appsList(args) {
|
|
168
|
+
const json = hasFlag(args, "--json");
|
|
169
|
+
const [server, serverApps] = await getServerApps();
|
|
170
|
+
try {
|
|
171
|
+
const apps = await serverApps.list_apps({ _rkwargs: true });
|
|
172
|
+
if (json) {
|
|
173
|
+
console.log(formatJson(apps));
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (!apps || apps.length === 0) {
|
|
177
|
+
console.log("No installed apps.");
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const rows = [["APP ID", "NAME", "TYPE"]];
|
|
181
|
+
for (const app of apps) {
|
|
182
|
+
const manifest = app.manifest || {};
|
|
183
|
+
rows.push([
|
|
184
|
+
app.id || app.alias || "",
|
|
185
|
+
manifest.name || "",
|
|
186
|
+
manifest.type || app.type || ""
|
|
187
|
+
]);
|
|
188
|
+
}
|
|
189
|
+
console.log(formatTable(rows));
|
|
190
|
+
} finally {
|
|
191
|
+
await server.disconnect();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async function appsInfo(args) {
|
|
195
|
+
const pos = positionalArgs(args)[0];
|
|
196
|
+
const json = hasFlag(args, "--json");
|
|
197
|
+
if (!pos) {
|
|
198
|
+
console.error("Usage: hypha apps info <app-id>");
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
const [server, serverApps] = await getServerApps();
|
|
202
|
+
try {
|
|
203
|
+
const info = await serverApps.get_app_info({
|
|
204
|
+
app_id: pos,
|
|
205
|
+
_rkwargs: true
|
|
206
|
+
});
|
|
207
|
+
if (json) {
|
|
208
|
+
console.log(formatJson(info));
|
|
209
|
+
} else {
|
|
210
|
+
const manifest = info.manifest || {};
|
|
211
|
+
console.log(`App ID: ${info.id || info.alias || pos}`);
|
|
212
|
+
console.log(`Name: ${manifest.name || "N/A"}`);
|
|
213
|
+
console.log(`Type: ${manifest.type || info.type || "N/A"}`);
|
|
214
|
+
console.log(`Description: ${manifest.description || "N/A"}`);
|
|
215
|
+
if (info.versions?.length) {
|
|
216
|
+
console.log(`Versions: ${info.versions.map((v) => v.name || v).join(", ")}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
} finally {
|
|
220
|
+
await server.disconnect();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
async function appsInstall(args) {
|
|
224
|
+
const parsed = parseInstallArgs(args);
|
|
225
|
+
if (!parsed.source) {
|
|
226
|
+
console.error("Usage: hypha apps install <source> [--id <app-id>] [--manifest <path>] [--files <dir>...] [--overwrite]");
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
const [server, serverApps] = await getServerApps();
|
|
230
|
+
try {
|
|
231
|
+
const installOpts = {
|
|
232
|
+
_rkwargs: true,
|
|
233
|
+
overwrite: parsed.overwrite
|
|
234
|
+
};
|
|
235
|
+
if (parsed.id) {
|
|
236
|
+
installOpts.app_id = parsed.id;
|
|
237
|
+
}
|
|
238
|
+
if (parsed.source.startsWith("http://") || parsed.source.startsWith("https://")) {
|
|
239
|
+
installOpts.source = parsed.source;
|
|
240
|
+
} else {
|
|
241
|
+
const stat = statSync(parsed.source);
|
|
242
|
+
if (stat.isFile()) {
|
|
243
|
+
installOpts.source = readFileSync(parsed.source, "utf-8");
|
|
244
|
+
} else if (stat.isDirectory()) {
|
|
245
|
+
installOpts.files = collectFiles(parsed.source);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (parsed.manifest) {
|
|
249
|
+
const manifestContent = readFileSync(parsed.manifest, "utf-8");
|
|
250
|
+
installOpts.manifest = JSON.parse(manifestContent);
|
|
251
|
+
}
|
|
252
|
+
if (parsed.files.length > 0) {
|
|
253
|
+
const existing = installOpts.files || [];
|
|
254
|
+
for (const fileDir of parsed.files) {
|
|
255
|
+
existing.push(...collectFiles(fileDir));
|
|
256
|
+
}
|
|
257
|
+
installOpts.files = existing;
|
|
258
|
+
}
|
|
259
|
+
const appId = await serverApps.install(installOpts);
|
|
260
|
+
console.log(`Installed: ${appId}`);
|
|
261
|
+
} finally {
|
|
262
|
+
await server.disconnect();
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
async function appsUninstall(args) {
|
|
266
|
+
const appId = positionalArgs(args)[0];
|
|
267
|
+
if (!appId) {
|
|
268
|
+
console.error("Usage: hypha apps uninstall <app-id>");
|
|
269
|
+
process.exit(1);
|
|
270
|
+
}
|
|
271
|
+
const [server, serverApps] = await getServerApps();
|
|
272
|
+
try {
|
|
273
|
+
const artifactManager = await server.getService("artifact-manager");
|
|
274
|
+
await artifactManager.delete({
|
|
275
|
+
artifact_id: appId,
|
|
276
|
+
_rkwargs: true
|
|
277
|
+
});
|
|
278
|
+
console.log(`Uninstalled: ${appId}`);
|
|
279
|
+
} finally {
|
|
280
|
+
await server.disconnect();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
async function appsStart(args) {
|
|
284
|
+
const parsed = parseStartArgs(args);
|
|
285
|
+
if (!parsed.appId) {
|
|
286
|
+
console.error("Usage: hypha apps start <app-id> [--timeout N] [--wait]");
|
|
287
|
+
process.exit(1);
|
|
288
|
+
}
|
|
289
|
+
const [server, serverApps] = await getServerApps();
|
|
290
|
+
try {
|
|
291
|
+
const startOpts = {
|
|
292
|
+
app_id: parsed.appId,
|
|
293
|
+
_rkwargs: true
|
|
294
|
+
};
|
|
295
|
+
if (parsed.timeout) startOpts.timeout = parsed.timeout;
|
|
296
|
+
if (parsed.wait) startOpts.wait_for_service = "default";
|
|
297
|
+
console.log(`Starting ${parsed.appId}...`);
|
|
298
|
+
const session = await serverApps.start(startOpts);
|
|
299
|
+
console.log(`Instance started:`);
|
|
300
|
+
console.log(` ID: ${session.id}`);
|
|
301
|
+
if (session.app_id) console.log(` App: ${session.app_id}`);
|
|
302
|
+
if (session.workspace) console.log(` WS: ${session.workspace}`);
|
|
303
|
+
} finally {
|
|
304
|
+
await server.disconnect();
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
async function appsStop(args) {
|
|
308
|
+
const parsed = parseStopArgs(args);
|
|
309
|
+
if (!parsed.id) {
|
|
310
|
+
console.error("Usage: hypha apps stop <id> [--all]");
|
|
311
|
+
console.error(" <id> can be an instance ID or app ID (with --all).");
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
const [server, serverApps] = await getServerApps();
|
|
315
|
+
try {
|
|
316
|
+
if (parsed.all) {
|
|
317
|
+
const running = await serverApps.list_running({ _rkwargs: true });
|
|
318
|
+
const matching = running.filter((s) => s.app_id === parsed.id);
|
|
319
|
+
if (matching.length === 0) {
|
|
320
|
+
console.log(`No running instances found for app: ${parsed.id}`);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
for (const instance of matching) {
|
|
324
|
+
try {
|
|
325
|
+
await serverApps.stop({ session_id: instance.id, _rkwargs: true });
|
|
326
|
+
console.log(`Stopped: ${instance.id}`);
|
|
327
|
+
} catch (err) {
|
|
328
|
+
console.error(`Failed to stop ${instance.id}: ${err.message}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
console.log(`Stopped ${matching.length} instance(s) of ${parsed.id}.`);
|
|
332
|
+
} else {
|
|
333
|
+
await serverApps.stop({ session_id: parsed.id, _rkwargs: true });
|
|
334
|
+
console.log(`Stopped: ${parsed.id}`);
|
|
335
|
+
}
|
|
336
|
+
} finally {
|
|
337
|
+
await server.disconnect();
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
async function appsPs(args) {
|
|
341
|
+
const json = hasFlag(args, "--json");
|
|
342
|
+
const [server, serverApps] = await getServerApps();
|
|
343
|
+
try {
|
|
344
|
+
const running = await serverApps.list_running({ _rkwargs: true });
|
|
345
|
+
if (json) {
|
|
346
|
+
console.log(formatJson(running));
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (!running || running.length === 0) {
|
|
350
|
+
console.log("No running instances.");
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const rows = [["INSTANCE ID", "APP ID", "STATUS", "CREATED"]];
|
|
354
|
+
for (const inst of running) {
|
|
355
|
+
rows.push([
|
|
356
|
+
inst.id || "",
|
|
357
|
+
inst.app_id || "",
|
|
358
|
+
inst.status || "running",
|
|
359
|
+
inst.created_at ? relativeTime(inst.created_at * 1e3) : ""
|
|
360
|
+
]);
|
|
361
|
+
}
|
|
362
|
+
console.log(formatTable(rows));
|
|
363
|
+
} finally {
|
|
364
|
+
await server.disconnect();
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
async function appsLogs(args) {
|
|
368
|
+
const parsed = parseLogsArgs(args);
|
|
369
|
+
if (!parsed.instanceId) {
|
|
370
|
+
console.error("Usage: hypha apps logs <instance-id> [--tail N] [--type stdout|stderr]");
|
|
371
|
+
process.exit(1);
|
|
372
|
+
}
|
|
373
|
+
const [server, serverApps] = await getServerApps();
|
|
374
|
+
try {
|
|
375
|
+
const logOpts = {
|
|
376
|
+
session_id: parsed.instanceId,
|
|
377
|
+
_rkwargs: true
|
|
378
|
+
};
|
|
379
|
+
if (parsed.type) logOpts.type = parsed.type;
|
|
380
|
+
if (parsed.tail) logOpts.limit = parsed.tail;
|
|
381
|
+
const logs = await serverApps.get_logs(logOpts);
|
|
382
|
+
if (!logs || !logs.items || logs.items.length === 0) {
|
|
383
|
+
console.log("No logs available.");
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
for (const entry of logs.items) {
|
|
387
|
+
const prefix = entry.type === "stderr" ? "[stderr] " : "";
|
|
388
|
+
console.log(`${prefix}${entry.content}`);
|
|
389
|
+
}
|
|
390
|
+
} finally {
|
|
391
|
+
await server.disconnect();
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
async function handleAppsCommand(args) {
|
|
395
|
+
const sub = args[0];
|
|
396
|
+
const commandArgs = args.slice(1);
|
|
397
|
+
if (!sub || sub === "--help" || sub === "-h") {
|
|
398
|
+
printAppsHelp();
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
if (sub === "list" || sub === "ls") {
|
|
402
|
+
await appsList(commandArgs);
|
|
403
|
+
} else if (sub === "info") {
|
|
404
|
+
await appsInfo(commandArgs);
|
|
405
|
+
} else if (sub === "install") {
|
|
406
|
+
await appsInstall(commandArgs);
|
|
407
|
+
} else if (sub === "uninstall" || sub === "rm") {
|
|
408
|
+
await appsUninstall(commandArgs);
|
|
409
|
+
} else if (sub === "start") {
|
|
410
|
+
await appsStart(commandArgs);
|
|
411
|
+
} else if (sub === "stop") {
|
|
412
|
+
await appsStop(commandArgs);
|
|
413
|
+
} else if (sub === "ps") {
|
|
414
|
+
await appsPs(commandArgs);
|
|
415
|
+
} else if (sub === "logs") {
|
|
416
|
+
await appsLogs(commandArgs);
|
|
417
|
+
} else {
|
|
418
|
+
console.error(`Unknown apps command: ${sub}`);
|
|
419
|
+
printAppsHelp();
|
|
420
|
+
process.exit(1);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export { handleAppsCommand, parseInstallArgs, parseLogsArgs, parseStartArgs, parseStopArgs };
|