hypha-cli 0.1.10 → 0.1.12
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-rK1_N8nw.mjs → apps-D9WCfzIl.mjs} +2 -2
- package/dist/{artifacts-8p2A4NMr.mjs → artifacts-DHPJIrSS.mjs} +208 -17
- package/dist/cli.mjs +11 -11
- package/dist/{helpers-BvfSCkvr.mjs → helpers-BC4AKy6a.mjs} +45 -9
- package/dist/index.mjs +1 -1
- package/dist/{workspace-XO_tEtii.mjs → workspace-DE2jBAXs.mjs} +4 -2
- package/package.json +2 -2
- package/dist/apps-CpJkx863.mjs +0 -512
- package/dist/apps-D659xu7q.mjs +0 -424
- package/dist/artifacts-C0yhSTgw.mjs +0 -629
- package/dist/artifacts-DdgZRh8t.mjs +0 -764
- package/dist/workspace-BwLwj61H.mjs +0 -206
- package/dist/workspace-DMqqSmvB.mjs +0 -283
- package/dist/workspace-RZLvWJpe.mjs +0 -128
- package/dist/workspace-wlyR33kp.mjs +0 -127
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { statSync, readFileSync, readdirSync } from 'fs';
|
|
2
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-
|
|
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-BC4AKy6a.mjs';
|
|
4
4
|
import 'os';
|
|
5
5
|
|
|
6
6
|
const IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
@@ -315,7 +315,7 @@ Alias: hypha apps rm`);
|
|
|
315
315
|
}
|
|
316
316
|
const [server, serverApps] = await getServerApps();
|
|
317
317
|
try {
|
|
318
|
-
const artifactManager = await server.getService("artifact-manager");
|
|
318
|
+
const artifactManager = await server.getService("public/artifact-manager");
|
|
319
319
|
await artifactManager.delete({
|
|
320
320
|
artifact_id: appId,
|
|
321
321
|
_rkwargs: true
|
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
import { statSync, readFileSync, mkdirSync, createWriteStream, readdirSync } from 'fs';
|
|
2
2
|
import { join, dirname, basename } from 'path';
|
|
3
|
-
import { e as hasFlag, p as positionalArgs, f as formatJson, a as formatTable, r as resolveServerUrl, i as getFlag, g as getFlagInt, c as connectToHypha, b as resolveToken, m as printProgress, h as humanSize } from './helpers-
|
|
3
|
+
import { e as hasFlag, p as positionalArgs, f as formatJson, a as formatTable, r as resolveServerUrl, i as getFlag, g as getFlagInt, c as connectToHypha, b as resolveToken, m as printAggregateProgress, n as printProgress, h as humanSize } from './helpers-BC4AKy6a.mjs';
|
|
4
4
|
import { p as parseArtifactPath, b as buildFileUrl, d as determineCpDirection, r as resolveArtifactId } from './artifactPath-DCtvp6Go.mjs';
|
|
5
5
|
import 'os';
|
|
6
6
|
|
|
7
|
+
function envInt(name, fallback) {
|
|
8
|
+
const raw = process.env[name];
|
|
9
|
+
if (!raw) return fallback;
|
|
10
|
+
const n = parseInt(raw, 10);
|
|
11
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
12
|
+
}
|
|
13
|
+
const DEFAULT_BATCH_SIZE = 200;
|
|
14
|
+
const DEFAULT_CONCURRENCY = 16;
|
|
15
|
+
function chunk(arr, n) {
|
|
16
|
+
if (n <= 0) throw new Error("chunk size must be positive");
|
|
17
|
+
const out = [];
|
|
18
|
+
for (let i = 0; i < arr.length; i += n) {
|
|
19
|
+
out.push(arr.slice(i, i + n));
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
7
23
|
async function uploadFile(artifactManager, artifactId, localPath, remotePath, onProgress) {
|
|
8
24
|
const stat = statSync(localPath);
|
|
9
25
|
const totalBytes = stat.size;
|
|
@@ -78,16 +94,85 @@ async function downloadFile(artifactManager, artifactId, remotePath, localPath,
|
|
|
78
94
|
});
|
|
79
95
|
onProgress?.({ phase: "complete", bytesTransferred, totalBytes: totalBytes || bytesTransferred, fileName: remotePath });
|
|
80
96
|
}
|
|
97
|
+
async function uploadFilesBatched(artifactManager, artifactId, files, onProgress, opts = {}) {
|
|
98
|
+
const batchSize = opts.batchSize ?? envInt("HYPHA_UPLOAD_BATCH", DEFAULT_BATCH_SIZE);
|
|
99
|
+
const concurrency = opts.concurrency ?? envInt("HYPHA_UPLOAD_CONCURRENCY", DEFAULT_CONCURRENCY);
|
|
100
|
+
const filesTotal = files.length;
|
|
101
|
+
const bytesTotal = files.reduce((s, f) => s + f.size, 0);
|
|
102
|
+
let filesDone = 0;
|
|
103
|
+
let bytesDone = 0;
|
|
104
|
+
const emit = (currentFile) => {
|
|
105
|
+
onProgress?.({ filesDone, filesTotal, bytesDone, bytesTotal, currentFile });
|
|
106
|
+
};
|
|
107
|
+
emit(filesTotal > 0 ? files[0].remotePath : "");
|
|
108
|
+
for (const group of chunk(files, batchSize)) {
|
|
109
|
+
const paths = group.map((f) => f.remotePath);
|
|
110
|
+
const result = await artifactManager.put_file({
|
|
111
|
+
artifact_id: artifactId,
|
|
112
|
+
file_path: paths,
|
|
113
|
+
_rkwargs: true
|
|
114
|
+
});
|
|
115
|
+
let urlMap;
|
|
116
|
+
if (result && typeof result === "object" && !Array.isArray(result)) {
|
|
117
|
+
urlMap = result;
|
|
118
|
+
} else {
|
|
119
|
+
urlMap = {};
|
|
120
|
+
for (const f of group) {
|
|
121
|
+
const u = await artifactManager.put_file({
|
|
122
|
+
artifact_id: artifactId,
|
|
123
|
+
file_path: f.remotePath,
|
|
124
|
+
_rkwargs: true
|
|
125
|
+
});
|
|
126
|
+
if (typeof u !== "string") {
|
|
127
|
+
throw new Error(`put_file returned unexpected value for ${f.remotePath}`);
|
|
128
|
+
}
|
|
129
|
+
urlMap[f.remotePath] = u;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
let cursor = 0;
|
|
133
|
+
const workers = [];
|
|
134
|
+
const worker = async () => {
|
|
135
|
+
while (true) {
|
|
136
|
+
const i = cursor++;
|
|
137
|
+
if (i >= group.length) return;
|
|
138
|
+
const f = group[i];
|
|
139
|
+
const url = urlMap[f.remotePath];
|
|
140
|
+
if (!url || typeof url !== "string") {
|
|
141
|
+
throw new Error(`No presigned URL returned for ${f.remotePath}`);
|
|
142
|
+
}
|
|
143
|
+
const body = readFileSync(f.localPath);
|
|
144
|
+
const resp = await fetch(url, {
|
|
145
|
+
method: "PUT",
|
|
146
|
+
body,
|
|
147
|
+
headers: {
|
|
148
|
+
"Content-Type": "application/octet-stream",
|
|
149
|
+
"Content-Length": String(f.size)
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
if (!resp.ok) {
|
|
153
|
+
const text = await resp.text().catch(() => "");
|
|
154
|
+
throw new Error(`Upload failed for ${f.remotePath}: ${resp.status} ${resp.statusText} ${text}`);
|
|
155
|
+
}
|
|
156
|
+
filesDone++;
|
|
157
|
+
bytesDone += f.size;
|
|
158
|
+
emit(f.remotePath);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const n = Math.min(concurrency, group.length);
|
|
162
|
+
for (let w = 0; w < n; w++) workers.push(worker());
|
|
163
|
+
await Promise.all(workers);
|
|
164
|
+
}
|
|
165
|
+
return filesDone;
|
|
166
|
+
}
|
|
81
167
|
async function uploadDirectory(artifactManager, artifactId, localDir, remoteBase, onProgress) {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
for (const relPath of files) {
|
|
168
|
+
const relPaths = collectLocalFiles(localDir);
|
|
169
|
+
const files = relPaths.map((relPath) => {
|
|
85
170
|
const localPath = join(localDir, relPath);
|
|
86
171
|
const remotePath = remoteBase ? `${remoteBase}/${relPath}` : relPath;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
return
|
|
172
|
+
const size = statSync(localPath).size;
|
|
173
|
+
return { localPath, remotePath, size };
|
|
174
|
+
});
|
|
175
|
+
return uploadFilesBatched(artifactManager, artifactId, files, onProgress);
|
|
91
176
|
}
|
|
92
177
|
async function downloadDirectory(artifactManager, artifactId, remotePath, localDir, onProgress) {
|
|
93
178
|
const files = await artifactManager.list_files({
|
|
@@ -154,6 +239,7 @@ Commands:
|
|
|
154
239
|
commit <artifact> [options] Commit staged changes
|
|
155
240
|
edit <artifact> [options] Edit artifact metadata
|
|
156
241
|
discard <artifact> Discard staged changes
|
|
242
|
+
serve <artifact> [options] Enable/disable static site hosting
|
|
157
243
|
|
|
158
244
|
Aliases: list \u2192 ls, mkdir \u2192 create, find \u2192 search
|
|
159
245
|
Shorthand: "hypha art" is an alias for "hypha artifacts"
|
|
@@ -186,6 +272,11 @@ function makeProgressCallback() {
|
|
|
186
272
|
}
|
|
187
273
|
};
|
|
188
274
|
}
|
|
275
|
+
function makeBatchProgressCallback(label) {
|
|
276
|
+
return (p) => {
|
|
277
|
+
printAggregateProgress(label, p.filesDone, p.filesTotal, p.bytesDone, p.bytesTotal);
|
|
278
|
+
};
|
|
279
|
+
}
|
|
189
280
|
async function fetchWithAuth(url, init) {
|
|
190
281
|
const token = resolveToken();
|
|
191
282
|
const headers = new Headers(init?.headers);
|
|
@@ -214,9 +305,9 @@ Alias: hypha artifacts list`);
|
|
|
214
305
|
const long = hasFlag(args, "--long", "-l");
|
|
215
306
|
const pos = positionalArgs(args)[0];
|
|
216
307
|
if (!pos) {
|
|
217
|
-
const { server: server2, am } = await connectAndGetArtifactManager();
|
|
308
|
+
const { server: server2, am: am2 } = await connectAndGetArtifactManager();
|
|
218
309
|
try {
|
|
219
|
-
const artifacts = await
|
|
310
|
+
const artifacts = await am2.list({
|
|
220
311
|
_rkwargs: true
|
|
221
312
|
});
|
|
222
313
|
const list = Array.isArray(artifacts) ? artifacts : artifacts?.items || [];
|
|
@@ -252,9 +343,53 @@ Alias: hypha artifacts list`);
|
|
|
252
343
|
}
|
|
253
344
|
const parsed = parseArtifactPath(pos);
|
|
254
345
|
const serverUrl = resolveServerUrl();
|
|
255
|
-
const { server } = await connectAndGetArtifactManager();
|
|
346
|
+
const { server, am } = await connectAndGetArtifactManager();
|
|
256
347
|
const workspace = parsed.workspace || server.config.workspace;
|
|
348
|
+
const artifactId = resolveArtifactId(parsed, server.config.workspace);
|
|
257
349
|
try {
|
|
350
|
+
if (!parsed.filePath) {
|
|
351
|
+
let info;
|
|
352
|
+
try {
|
|
353
|
+
info = await am.read({ artifact_id: artifactId, _rkwargs: true });
|
|
354
|
+
} catch (err) {
|
|
355
|
+
const msg = String(err?.message || err);
|
|
356
|
+
if (/not found|does not exist/i.test(msg)) {
|
|
357
|
+
console.error(`Artifact not found: ${pos}`);
|
|
358
|
+
process.exit(1);
|
|
359
|
+
}
|
|
360
|
+
throw err;
|
|
361
|
+
}
|
|
362
|
+
if (info?.type === "collection") {
|
|
363
|
+
const children = await am.list({ parent_id: artifactId, _rkwargs: true });
|
|
364
|
+
const list = Array.isArray(children) ? children : children?.items || [];
|
|
365
|
+
if (json) {
|
|
366
|
+
console.log(formatJson(list));
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
if (list.length === 0) {
|
|
370
|
+
console.log("No child artifacts in this collection.");
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
if (long) {
|
|
374
|
+
const rows = [["ALIAS", "TYPE", "MODIFIED", "DESCRIPTION"]];
|
|
375
|
+
for (const art of list) {
|
|
376
|
+
const manifest = art.manifest || {};
|
|
377
|
+
rows.push([
|
|
378
|
+
art.alias || art.id || "",
|
|
379
|
+
art.type || "",
|
|
380
|
+
art.last_modified ? new Date(art.last_modified * 1e3).toISOString().slice(0, 10) : "",
|
|
381
|
+
(manifest.description || "").slice(0, 50)
|
|
382
|
+
]);
|
|
383
|
+
}
|
|
384
|
+
console.log(formatTable(rows));
|
|
385
|
+
} else {
|
|
386
|
+
for (const art of list) {
|
|
387
|
+
console.log(art.alias || art.id || "");
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
258
393
|
const url = buildFileUrl(serverUrl, workspace, parsed.alias, parsed.filePath);
|
|
259
394
|
const resp = await fetchWithAuth(url);
|
|
260
395
|
if (!resp.ok) {
|
|
@@ -388,14 +523,19 @@ Examples:
|
|
|
388
523
|
console.error("Source is a directory. Use -r to copy directories.");
|
|
389
524
|
process.exit(1);
|
|
390
525
|
}
|
|
391
|
-
const
|
|
526
|
+
const dirLabel = `${basename(src)}/`;
|
|
527
|
+
const count = await uploadDirectory(
|
|
528
|
+
am,
|
|
529
|
+
artifactId,
|
|
530
|
+
src,
|
|
531
|
+
parsed.filePath || "",
|
|
532
|
+
makeBatchProgressCallback(dirLabel)
|
|
533
|
+
);
|
|
392
534
|
if (autoCommit) {
|
|
393
535
|
await am.commit({ artifact_id: artifactId, _rkwargs: true });
|
|
394
|
-
console.log(`
|
|
395
|
-
Uploaded ${count} files and committed.`);
|
|
536
|
+
console.log(`Uploaded ${count} files and committed.`);
|
|
396
537
|
} else {
|
|
397
|
-
console.log(`
|
|
398
|
-
Uploaded ${count} files. Run \`hypha artifacts commit ${parsed.alias}\` to finalize.`);
|
|
538
|
+
console.log(`Uploaded ${count} files. Run \`hypha artifacts commit ${parsed.alias}\` to finalize.`);
|
|
399
539
|
}
|
|
400
540
|
} else {
|
|
401
541
|
const remotePath = parsed.filePath || basename(src);
|
|
@@ -516,7 +656,6 @@ Alias: hypha artifacts mkdir`);
|
|
|
516
656
|
};
|
|
517
657
|
if (parent) createOpts.parent_id = parent;
|
|
518
658
|
const result = await am.create(createOpts);
|
|
519
|
-
await am.commit({ artifact_id: result.id || pos, _rkwargs: true });
|
|
520
659
|
if (json) {
|
|
521
660
|
console.log(formatJson(result));
|
|
522
661
|
} else {
|
|
@@ -727,6 +866,56 @@ Usage: hypha artifacts discard <artifact>`);
|
|
|
727
866
|
await server.disconnect();
|
|
728
867
|
}
|
|
729
868
|
}
|
|
869
|
+
async function artifactsServe(args) {
|
|
870
|
+
if (hasFlag(args, "--help", "-h")) {
|
|
871
|
+
console.log(`hypha artifacts serve \u2014 enable or disable static site hosting
|
|
872
|
+
|
|
873
|
+
Usage: hypha artifacts serve <artifact> [options]
|
|
874
|
+
|
|
875
|
+
Options:
|
|
876
|
+
--root <dir> Root directory to serve (default: /)
|
|
877
|
+
--disable Disable static site hosting
|
|
878
|
+
|
|
879
|
+
Examples:
|
|
880
|
+
hypha art serve my-site # Enable \u2014 serve from artifact root
|
|
881
|
+
hypha art serve my-site --root dist # Serve from /dist subdirectory
|
|
882
|
+
hypha art serve my-site --disable # Disable static site hosting`);
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
const pos = positionalArgs(args, ["--root"])[0];
|
|
886
|
+
if (!pos) {
|
|
887
|
+
console.error("Usage: hypha artifacts serve <artifact> [--root <dir>] [--disable]");
|
|
888
|
+
process.exit(1);
|
|
889
|
+
}
|
|
890
|
+
const disable = hasFlag(args, "--disable");
|
|
891
|
+
const root = getFlag(args, "--root") || "/";
|
|
892
|
+
const parsed = parseArtifactPath(pos);
|
|
893
|
+
const { server, am } = await connectAndGetArtifactManager();
|
|
894
|
+
const artifactId = resolveArtifactId(parsed, server.config.workspace);
|
|
895
|
+
const serverUrl = resolveServerUrl();
|
|
896
|
+
const workspace = parsed.workspace || server.config.workspace;
|
|
897
|
+
try {
|
|
898
|
+
const config = {
|
|
899
|
+
view_config: disable ? "disabled" : { root_directory: root }
|
|
900
|
+
};
|
|
901
|
+
await am.edit({
|
|
902
|
+
artifact_id: artifactId,
|
|
903
|
+
config,
|
|
904
|
+
_rkwargs: true
|
|
905
|
+
});
|
|
906
|
+
if (disable) {
|
|
907
|
+
console.log(`Static site hosting disabled: ${parsed.alias}`);
|
|
908
|
+
} else {
|
|
909
|
+
const url = `${serverUrl}/${workspace}/view/${parsed.alias}`;
|
|
910
|
+
console.log(`Static site enabled: ${url}`);
|
|
911
|
+
if (root && root !== "/") {
|
|
912
|
+
console.log(` Serving from: ${root}`);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
} finally {
|
|
916
|
+
await server.disconnect();
|
|
917
|
+
}
|
|
918
|
+
}
|
|
730
919
|
async function handleArtifactsCommand(args) {
|
|
731
920
|
const sub = args[0];
|
|
732
921
|
const commandArgs = args.slice(1);
|
|
@@ -754,6 +943,8 @@ async function handleArtifactsCommand(args) {
|
|
|
754
943
|
await artifactsEdit(commandArgs);
|
|
755
944
|
} else if (sub === "discard") {
|
|
756
945
|
await artifactsDiscard(commandArgs);
|
|
946
|
+
} else if (sub === "serve") {
|
|
947
|
+
await artifactsServe(commandArgs);
|
|
757
948
|
} else {
|
|
758
949
|
console.error(`Unknown artifacts command: ${sub}`);
|
|
759
950
|
printArtifactsHelp();
|
package/dist/cli.mjs
CHANGED
|
@@ -77,37 +77,37 @@ async function main() {
|
|
|
77
77
|
}
|
|
78
78
|
const commandArgs = args.slice(1);
|
|
79
79
|
if (subcommand === "login") {
|
|
80
|
-
const { loginCommand } = await import('./workspace-
|
|
80
|
+
const { loginCommand } = await import('./workspace-DE2jBAXs.mjs');
|
|
81
81
|
await loginCommand(commandArgs);
|
|
82
82
|
} else if (subcommand === "token") {
|
|
83
|
-
const { tokenCommand } = await import('./workspace-
|
|
83
|
+
const { tokenCommand } = await import('./workspace-DE2jBAXs.mjs');
|
|
84
84
|
await tokenCommand(commandArgs);
|
|
85
85
|
} else if (subcommand === "services") {
|
|
86
|
-
const { servicesCommand } = await import('./workspace-
|
|
86
|
+
const { servicesCommand } = await import('./workspace-DE2jBAXs.mjs');
|
|
87
87
|
await servicesCommand(commandArgs);
|
|
88
88
|
} else if (subcommand === "info") {
|
|
89
|
-
const { infoCommand } = await import('./workspace-
|
|
89
|
+
const { infoCommand } = await import('./workspace-DE2jBAXs.mjs');
|
|
90
90
|
await infoCommand(commandArgs);
|
|
91
91
|
} else if (subcommand === "clients") {
|
|
92
|
-
const { clientsCommand } = await import('./workspace-
|
|
92
|
+
const { clientsCommand } = await import('./workspace-DE2jBAXs.mjs');
|
|
93
93
|
await clientsCommand(commandArgs);
|
|
94
94
|
} else if (subcommand === "ping") {
|
|
95
|
-
const { pingCommand } = await import('./workspace-
|
|
95
|
+
const { pingCommand } = await import('./workspace-DE2jBAXs.mjs');
|
|
96
96
|
await pingCommand(commandArgs);
|
|
97
97
|
} else if (subcommand === "kick") {
|
|
98
|
-
const { kickCommand } = await import('./workspace-
|
|
98
|
+
const { kickCommand } = await import('./workspace-DE2jBAXs.mjs');
|
|
99
99
|
await kickCommand(commandArgs);
|
|
100
100
|
} else if (subcommand === "cleanup") {
|
|
101
|
-
const { cleanupCommand } = await import('./workspace-
|
|
101
|
+
const { cleanupCommand } = await import('./workspace-DE2jBAXs.mjs');
|
|
102
102
|
await cleanupCommand(commandArgs);
|
|
103
103
|
} else if (subcommand === "workspace-info") {
|
|
104
|
-
const { workspaceInfoCommand } = await import('./workspace-
|
|
104
|
+
const { workspaceInfoCommand } = await import('./workspace-DE2jBAXs.mjs');
|
|
105
105
|
await workspaceInfoCommand(commandArgs);
|
|
106
106
|
} else if (subcommand === "apps") {
|
|
107
|
-
const { handleAppsCommand } = await import('./apps-
|
|
107
|
+
const { handleAppsCommand } = await import('./apps-D9WCfzIl.mjs');
|
|
108
108
|
await handleAppsCommand(commandArgs);
|
|
109
109
|
} else if (subcommand === "artifacts" || subcommand === "art") {
|
|
110
|
-
const { handleArtifactsCommand } = await import('./artifacts-
|
|
110
|
+
const { handleArtifactsCommand } = await import('./artifacts-DHPJIrSS.mjs');
|
|
111
111
|
await handleArtifactsCommand(commandArgs);
|
|
112
112
|
} else {
|
|
113
113
|
console.error(`Unknown command: ${subcommand}`);
|
|
@@ -62,15 +62,33 @@ async function connectToHypha(opts) {
|
|
|
62
62
|
const token = resolveToken(opts);
|
|
63
63
|
const workspace = resolveWorkspace(opts);
|
|
64
64
|
if (!token) {
|
|
65
|
-
|
|
65
|
+
const envFile = getEnvFilePath();
|
|
66
|
+
console.error("No HYPHA_TOKEN found.");
|
|
67
|
+
console.error(` Looked in: process.env.HYPHA_TOKEN, ${envFile}`);
|
|
68
|
+
console.error(" Fix: run `hypha login`, or set HYPHA_TOKEN in the environment / that file.");
|
|
66
69
|
process.exit(1);
|
|
67
70
|
}
|
|
68
71
|
const { hyphaWebsocketClient } = await import('hypha-rpc');
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
let server;
|
|
73
|
+
try {
|
|
74
|
+
server = await hyphaWebsocketClient.connectToServer({
|
|
75
|
+
server_url: serverUrl,
|
|
76
|
+
token,
|
|
77
|
+
workspace: workspace || void 0,
|
|
78
|
+
// Suppress hypha-rpc connection/disconnection log noise
|
|
79
|
+
logger: null
|
|
80
|
+
});
|
|
81
|
+
} catch (err) {
|
|
82
|
+
const msg = String(err?.message || err);
|
|
83
|
+
if (workspace && /workspace/i.test(msg) && /(mismatch|denied|permission|forbidden|not allowed|unauthorized)/i.test(msg)) {
|
|
84
|
+
console.error(`Workspace '${workspace}' was requested but the token does not grant it.`);
|
|
85
|
+
console.error(` Source of override: process.env.HYPHA_WORKSPACE or ${getEnvFilePath()}`);
|
|
86
|
+
console.error(" Fix: run `hypha login` to refresh credentials, or unset HYPHA_WORKSPACE.");
|
|
87
|
+
console.error(` (server said: ${msg})`);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
74
92
|
return server;
|
|
75
93
|
}
|
|
76
94
|
async function loginToHypha(serverUrl) {
|
|
@@ -78,7 +96,8 @@ async function loginToHypha(serverUrl) {
|
|
|
78
96
|
const { hyphaWebsocketClient } = await import('hypha-rpc');
|
|
79
97
|
console.log(`Logging in to ${url}...`);
|
|
80
98
|
const token = await hyphaWebsocketClient.login({
|
|
81
|
-
server_url: url
|
|
99
|
+
server_url: url,
|
|
100
|
+
logger: null
|
|
82
101
|
});
|
|
83
102
|
if (!token) {
|
|
84
103
|
console.error("Login failed \u2014 no token received.");
|
|
@@ -86,7 +105,8 @@ async function loginToHypha(serverUrl) {
|
|
|
86
105
|
}
|
|
87
106
|
const server = await hyphaWebsocketClient.connectToServer({
|
|
88
107
|
server_url: url,
|
|
89
|
-
token
|
|
108
|
+
token,
|
|
109
|
+
logger: null
|
|
90
110
|
});
|
|
91
111
|
const ws = server.config.workspace;
|
|
92
112
|
writeEnvValue("HYPHA_SERVER_URL", url);
|
|
@@ -184,5 +204,21 @@ function printProgress(label, current, total) {
|
|
|
184
204
|
process.stderr.write("\n");
|
|
185
205
|
}
|
|
186
206
|
}
|
|
207
|
+
function printAggregateProgress(label, filesDone, filesTotal, bytesDone, bytesTotal) {
|
|
208
|
+
if (filesTotal <= 0) return;
|
|
209
|
+
const pct = Math.min(100, Math.round(filesDone / filesTotal * 100));
|
|
210
|
+
const barWidth = 30;
|
|
211
|
+
const filled = Math.round(barWidth * (filesDone / filesTotal));
|
|
212
|
+
const bar = "=".repeat(filled) + (filled < barWidth ? ">" : "") + " ".repeat(Math.max(0, barWidth - filled - 1));
|
|
213
|
+
const sizeStr = bytesTotal > 0 ? ` ${humanSize(bytesDone)}/${humanSize(bytesTotal)}` : "";
|
|
214
|
+
const maxLabel = 20;
|
|
215
|
+
const displayLabel = label.length > maxLabel ? "..." + label.slice(-17) : label;
|
|
216
|
+
process.stderr.write(
|
|
217
|
+
`\r ${displayLabel.padEnd(maxLabel)} [${bar}] ${pct}% ${filesDone}/${filesTotal} files${sizeStr} `
|
|
218
|
+
);
|
|
219
|
+
if (filesDone >= filesTotal) {
|
|
220
|
+
process.stderr.write("\n");
|
|
221
|
+
}
|
|
222
|
+
}
|
|
187
223
|
|
|
188
|
-
export { formatTable as a, resolveToken as b, connectToHypha as c, resolveWorkspace as d, hasFlag as e, formatJson as f, getFlagInt as g, humanSize as h, getFlag as i, relativeTime as j, getAllFlags as k, loginToHypha as l,
|
|
224
|
+
export { formatTable as a, resolveToken as b, connectToHypha as c, resolveWorkspace as d, hasFlag as e, formatJson as f, getFlagInt as g, humanSize as h, getFlag as i, relativeTime as j, getAllFlags as k, loginToHypha as l, printAggregateProgress as m, printProgress as n, positionalArgs as p, resolveServerUrl as r };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { c as connectToHypha, f as formatJson, a as formatTable, h as humanSize, l as loginToHypha, r as resolveServerUrl, b as resolveToken, d as resolveWorkspace } from './helpers-
|
|
1
|
+
export { c as connectToHypha, f as formatJson, a as formatTable, h as humanSize, l as loginToHypha, r as resolveServerUrl, b as resolveToken, d as resolveWorkspace } from './helpers-BC4AKy6a.mjs';
|
|
2
2
|
export { d as determineCpDirection, i as isArtifactPath, p as parseArtifactPath } from './artifactPath-DCtvp6Go.mjs';
|
|
3
3
|
import 'fs';
|
|
4
4
|
import 'path';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { e as hasFlag, l as loginToHypha, c as connectToHypha, g as getFlagInt, i as getFlag, f as formatJson, a as formatTable, r as resolveServerUrl } from './helpers-
|
|
1
|
+
import { e as hasFlag, l as loginToHypha, c as connectToHypha, g as getFlagInt, i as getFlag, f as formatJson, a as formatTable, r as resolveServerUrl } from './helpers-BC4AKy6a.mjs';
|
|
2
2
|
import 'fs';
|
|
3
3
|
import 'path';
|
|
4
4
|
import 'os';
|
|
@@ -120,7 +120,9 @@ Options:
|
|
|
120
120
|
console.log(`${clients.length} client(s) in workspace ${targetWs}`);
|
|
121
121
|
if (clients.length === 0) return;
|
|
122
122
|
for (const c of clients.slice(0, 50)) {
|
|
123
|
-
|
|
123
|
+
const id = typeof c === "string" ? c : c.id || String(c);
|
|
124
|
+
const email = typeof c === "object" ? c.user?.email || "" : "";
|
|
125
|
+
console.log(` ${id}${email ? " (" + email + ")" : ""}`);
|
|
124
126
|
}
|
|
125
127
|
if (clients.length > 50) {
|
|
126
128
|
console.log(` ... and ${clients.length - 50} more`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hypha-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "Hypha Cloud CLI — manage workspaces, apps, and artifacts",
|
|
5
5
|
"author": "Amun AI AB",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"postinstall": "node bin/postinstall.mjs",
|
|
22
22
|
"build": "tsc --noEmit && pkgroll",
|
|
23
23
|
"typecheck": "tsc --noEmit",
|
|
24
|
-
"test": "npx tsx test/test-cli-routing.mjs && npx tsx test/test-artifact-path.mjs && npx tsx test/test-apps-commands.mjs && npx tsx test/test-artifacts-commands.mjs && npx tsx test/test-helpers.mjs",
|
|
24
|
+
"test": "npx tsx test/test-cli-routing.mjs && npx tsx test/test-artifact-path.mjs && npx tsx test/test-apps-commands.mjs && npx tsx test/test-artifacts-commands.mjs && npx tsx test/test-helpers.mjs && npx tsx test/test-transfer.mjs",
|
|
25
25
|
"test:integration": "npx tsx test/test-integration.mjs",
|
|
26
26
|
"dev": "tsx src/cli.ts"
|
|
27
27
|
},
|