@fnndsc/brasa 0.55.3 → 0.56.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.
Files changed (33) hide show
  1. package/dist/buildinfo.json +1 -1
  2. package/dist/builtins/berth/berth.d.ts +18 -0
  3. package/dist/builtins/berth/berth.js +471 -0
  4. package/dist/builtins/berth/berth.js.map +1 -0
  5. package/dist/builtins/berth/berthClose.d.ts +23 -0
  6. package/dist/builtins/berth/berthClose.js +475 -0
  7. package/dist/builtins/berth/berthClose.js.map +1 -0
  8. package/dist/builtins/berth/berthCube.d.ts +238 -0
  9. package/dist/builtins/berth/berthCube.js +366 -0
  10. package/dist/builtins/berth/berthCube.js.map +1 -0
  11. package/dist/builtins/berth/berthDisk.d.ts +13 -0
  12. package/dist/builtins/berth/berthDisk.js +34 -0
  13. package/dist/builtins/berth/berthDisk.js.map +1 -0
  14. package/dist/builtins/berth/berthProcesses.d.ts +47 -0
  15. package/dist/builtins/berth/berthProcesses.js +204 -0
  16. package/dist/builtins/berth/berthProcesses.js.map +1 -0
  17. package/dist/builtins/berth/berthRecord.d.ts +210 -0
  18. package/dist/builtins/berth/berthRecord.js +130 -0
  19. package/dist/builtins/berth/berthRecord.js.map +1 -0
  20. package/dist/builtins/berth/berthState.d.ts +139 -0
  21. package/dist/builtins/berth/berthState.js +194 -0
  22. package/dist/builtins/berth/berthState.js.map +1 -0
  23. package/dist/builtins/berth/berthWords.d.ts +87 -0
  24. package/dist/builtins/berth/berthWords.js +78 -0
  25. package/dist/builtins/berth/berthWords.js.map +1 -0
  26. package/dist/builtins/helpSections.js +59 -1
  27. package/dist/builtins/helpSections.js.map +1 -1
  28. package/dist/chris/chrisCommands.js +6 -0
  29. package/dist/chris/chrisCommands.js.map +1 -1
  30. package/dist/chris/help.js +50 -0
  31. package/dist/chris/help.js.map +1 -1
  32. package/dist/notes.json +1 -1
  33. package/package.json +2 -2
@@ -1 +1 @@
1
- {"hash":"ca8a23"}
1
+ {"hash":"ce89dc"}
@@ -0,0 +1,18 @@
1
+ import { type CommandEnvelope } from '@fnndsc/menu';
2
+ /** The verb's usage line. */
3
+ export declare const BERTH_USAGE: string;
4
+ /** The size above which an anchor asks before it downloads: 10 GB. */
5
+ export declare const ANCHOR_ASK_BYTES: number;
6
+ /**
7
+ * `berth [anchor … | close … | drop <name> | clear]`: the anchors of this session's berth, and its close.
8
+ *
9
+ * @param args - The words after `berth`.
10
+ * @returns The answer, or a refusal in POSIX tone.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * await builtin_berth(['anchor', '~/uploads/weights', 'w']);
15
+ * await builtin_berth([]); // the anchors
16
+ * ```
17
+ */
18
+ export declare function builtin_berth(args: string[]): Promise<CommandEnvelope>;
@@ -0,0 +1,471 @@
1
+ /**
2
+ * @file `berth`: the anchors of the berth a session runs in. `berth` lists
3
+ * them, `berth anchor` downloads a ChRIS path into one, `berth close` returns
4
+ * the outgoing folder to ChRIS as one node (berthClose.ts), `berth drop`
5
+ * removes one anchor, and `berth clear` removes them all and empties the
6
+ * outgoing folder.
7
+ *
8
+ * An anchor is a mount in the shell's sense: any ChRIS path the person can
9
+ * read, downloaded through the CUBE API with the session's token into
10
+ * `<anchors>/<name>/`. The path alone says whether it has a node: under the
11
+ * person's own `/home/<user>/feeds/` the plugin instance the path runs
12
+ * through is its node, and a node not `finishedSuccessfully` is refused;
13
+ * anywhere else it has none. The size is said before the download, above
14
+ * 10 GB it asks, and what does not fit is refused. The files downloaded lose
15
+ * their write permission, and the state file keeps what was downloaded, for
16
+ * the close.
17
+ *
18
+ * Key components:
19
+ * - builtin_berth: the verb and its subcommands.
20
+ * - BERTH_USAGE: its usage line.
21
+ * - ANCHOR_ASK_BYTES: the size above which an anchor asks first.
22
+ *
23
+ * Typical usage:
24
+ * ```ts
25
+ * await builtin_berth(['anchor', '~/feeds/feed_5/pl-fshack_41/data/sub-01']);
26
+ * await builtin_berth([]);
27
+ * await builtin_berth(['drop', 'sub-01']);
28
+ * ```
29
+ *
30
+ * Dependencies: the berth's places from the environment (berthState.ts);
31
+ * ChRIS through berthCube.ts; the session's sink and question.
32
+ *
33
+ * @module
34
+ */
35
+ import { chmodSync, createWriteStream, existsSync, mkdirSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
36
+ import { dirname, join, posix } from 'node:path';
37
+ import { pipeline } from 'node:stream/promises';
38
+ import chalk from 'chalk';
39
+ import { size_format } from '@fnndsc/fond';
40
+ import { envelope_error, envelope_ok } from '@fnndsc/menu';
41
+ import { exitCode_set } from '../../core/handlerRun.js';
42
+ import { repl_confirm } from '../../core/question.js';
43
+ import { sink_dataLine, sink_get } from '../../core/sink.js';
44
+ import { berthHome_get, berthPath_resolve, nodeStatus_get, remoteEntry_read, remoteFile_locate, remoteFile_open, remoteTree_list, } from './berthCube.js';
45
+ import { close_run } from './berthClose.js';
46
+ import { freeBytes_get } from './berthDisk.js';
47
+ import { BERTH_STATE_FILE, berthPlaces_read, berthState_read, berthState_update, } from './berthState.js';
48
+ import { anchorNode_show, BerthRefusal, bytes_sum, columns_render, count_say } from './berthWords.js';
49
+ /** The verb's usage line. */
50
+ export const BERTH_USAGE = 'berth [anchor <path> [name] [--refresh] [--yes] | close [--infeed <anchor> | --newfeed] [--name <feed>] [--title <text>] [--force] | drop <name> | clear]';
51
+ /** The anchor subcommand's usage line. */
52
+ const ANCHOR_USAGE = 'berth anchor <path> [name] [--refresh] [--yes]';
53
+ /** The size above which an anchor asks before it downloads: 10 GB. */
54
+ export const ANCHOR_ASK_BYTES = 10 * 1024 ** 3;
55
+ /** The one status of a node whose output is anchored. */
56
+ const NODE_FINISHED = 'finishedSuccessfully';
57
+ /** The prefix of the folder an anchor is downloaded into before it takes its name. */
58
+ const PARTIAL_PREFIX = '.partial-';
59
+ /** The write bits a downloaded file loses. */
60
+ const WRITE_BITS = 0o222;
61
+ /**
62
+ * Says a refusal on the error channel and fails the line.
63
+ *
64
+ * @param message - The words after `berth: `.
65
+ * @returns The error envelope.
66
+ */
67
+ function berth_refuse(message) {
68
+ exitCode_set(1);
69
+ return envelope_error('', undefined, `${chalk.red(`berth: ${message}`)}\n`);
70
+ }
71
+ /**
72
+ * The berth's places, or a refusal for a session on a host.
73
+ *
74
+ * @param subcommand - The subcommand refused, for the words.
75
+ * @returns The places.
76
+ * @throws {BerthRefusal} When the session runs on a host.
77
+ */
78
+ function places_require(subcommand) {
79
+ const places = berthPlaces_read();
80
+ if (places === null)
81
+ throw new BerthRefusal(`${subcommand}: this session runs on the host, not in a berth`);
82
+ return places;
83
+ }
84
+ /**
85
+ * Reads `berth anchor`'s words.
86
+ *
87
+ * @param args - The words after `anchor`.
88
+ * @returns The request.
89
+ * @throws {BerthRefusal} For an unknown option, or a missing or extra operand.
90
+ */
91
+ function anchorRequest_parse(args) {
92
+ const operands = [];
93
+ let refresh = false;
94
+ let yes = false;
95
+ for (const arg of args) {
96
+ if (arg === '--refresh')
97
+ refresh = true;
98
+ else if (arg === '--yes' || arg === '-y')
99
+ yes = true;
100
+ else if (arg.startsWith('-') && arg !== '-')
101
+ throw new BerthRefusal(`anchor: unknown option ${arg}; ${ANCHOR_USAGE}`);
102
+ else
103
+ operands.push(arg);
104
+ }
105
+ if (operands.length === 0 || operands.length > 2)
106
+ throw new BerthRefusal(`anchor: usage: ${ANCHOR_USAGE}`);
107
+ return { typed: operands[0], name: operands[1], refresh, yes };
108
+ }
109
+ /**
110
+ * Refuses a name that cannot be a folder of the anchors place: empty, with a
111
+ * `/`, `.` or `..`, or starting with `.` (the state file's and a download's own).
112
+ *
113
+ * @param name - The anchor's name.
114
+ * @throws {BerthRefusal} For a name that cannot be one.
115
+ */
116
+ function anchorName_check(name) {
117
+ if (name === '' || name.includes('/') || name.startsWith('.')) {
118
+ throw new BerthRefusal(`anchor: ${name === '' ? 'an empty name' : name} cannot name an anchor; a name is one folder name, not starting with .`);
119
+ }
120
+ }
121
+ /**
122
+ * Where a resolved path stands: under the person's own feeds its node is
123
+ * the plugin instance it runs through, and a path that names the node's own
124
+ * folder is its output, `data`; anywhere else it has no node.
125
+ *
126
+ * @param resolved - The absolute ChRIS path.
127
+ * @param home - The person's home, `/home/<user>`.
128
+ * @returns The source.
129
+ * @throws {BerthRefusal} For a path in the person's feeds that is at no node.
130
+ */
131
+ async function anchorSource_find(resolved, home) {
132
+ const defaultName = posix.basename(resolved);
133
+ if (!resolved.startsWith(`${home.replace(/\/$/, '')}/feeds/`)) {
134
+ return { path: resolved, defaultName, node: null, feed: null, nodeName: null };
135
+ }
136
+ const { path_extractFeedID, path_extractPluginInstanceID } = await import('@fnndsc/cumin');
137
+ const node = path_extractPluginInstanceID(resolved);
138
+ const feed = path_extractFeedID(resolved);
139
+ if (node === null || feed === null) {
140
+ throw new BerthRefusal(`anchor: ${resolved} is in your feeds but not at a node (…/feeds/feed_N/pl-x_ID)`);
141
+ }
142
+ const segments = resolved.split('/');
143
+ const nodeName = [...segments].reverse().find((segment) => segment.endsWith(`_${node}`)) ?? `${node}`;
144
+ // A path that ends at the node's own folder names the node, whose output
145
+ // is its data: its child nodes are other nodes, not this one's output.
146
+ const path = segments[segments.length - 1] === nodeName ? `${resolved}/data` : resolved;
147
+ return { path, defaultName, node, feed, nodeName };
148
+ }
149
+ /**
150
+ * Refuses a node CUBE does not report as finished: its output is incomplete
151
+ * and may change under the work.
152
+ *
153
+ * @param source - The anchor's source.
154
+ * @throws {BerthRefusal} When the node is anything but finishedSuccessfully.
155
+ */
156
+ async function nodeFinished_check(source) {
157
+ if (source.node === null)
158
+ return;
159
+ const status = await nodeStatus_get(source.node);
160
+ if (status !== NODE_FINISHED) {
161
+ throw new BerthRefusal(`anchor: ${source.nodeName ?? source.node} is ${status}, not ${NODE_FINISHED}; its output may still change`);
162
+ }
163
+ }
164
+ /**
165
+ * Writes one ChRIS file to the berth's disk, without its write permission.
166
+ *
167
+ * @param file - The file to read.
168
+ * @param target - Where it is written.
169
+ * @param bytes_add - Told the bytes as they arrive.
170
+ */
171
+ async function file_download(file, target, bytes_add) {
172
+ mkdirSync(dirname(target), { recursive: true });
173
+ const bytes = await remoteFile_open(file.source);
174
+ if (Buffer.isBuffer(bytes.stream)) {
175
+ writeFileSync(target, bytes.stream);
176
+ bytes_add(bytes.stream.length);
177
+ }
178
+ else {
179
+ bytes.stream.on('data', (chunk) => bytes_add(chunk.length));
180
+ await pipeline(bytes.stream, createWriteStream(target));
181
+ }
182
+ chmodSync(target, statSync(target).mode & ~WRITE_BITS);
183
+ }
184
+ /**
185
+ * Downloads files into a folder, saying the bytes as they arrive.
186
+ *
187
+ * @param files - The files.
188
+ * @param folder - The folder they are written under, by their relative names.
189
+ * @param label - The anchor's name, for the progress.
190
+ */
191
+ async function files_download(files, folder, label) {
192
+ mkdirSync(folder, { recursive: true });
193
+ const total = bytes_sum(files);
194
+ let current = 0;
195
+ const progress = (phase) => sink_get().progress_write({
196
+ operation: 'download', kind: 'transfer', phase, label, current, total, unit: 'bytes',
197
+ status: phase === 'complete' ? 'done' : 'running',
198
+ });
199
+ for (const file of files) {
200
+ await file_download(file, join(folder, ...file.name.split('/')), (count) => { current += count; progress('transferring'); });
201
+ }
202
+ progress('complete');
203
+ }
204
+ /**
205
+ * The files of a source: one file, or every file under a folder.
206
+ *
207
+ * @param source - The anchor's source.
208
+ * @param typed - The path as typed, for the words.
209
+ * @returns The files.
210
+ * @throws {BerthRefusal} When nothing stands at the path.
211
+ */
212
+ async function sourceFiles_list(source, typed) {
213
+ const entry = await remoteEntry_read(source.path);
214
+ if (entry === null)
215
+ throw new BerthRefusal(`anchor: ${typed}: no such file or directory`);
216
+ if (entry.kind === 'file')
217
+ return [await remoteFile_locate(source.path, entry.size)];
218
+ return remoteTree_list(source.path);
219
+ }
220
+ /**
221
+ * Checks the name against the anchors that stand, and the folder it takes.
222
+ *
223
+ * @param places - The berth's places.
224
+ * @param name - The anchor's name.
225
+ * @param source - The anchor's source.
226
+ * @param request - What was asked.
227
+ * @returns The anchor of that name being refreshed, or null for a new one.
228
+ * @throws {BerthRefusal} For a name another path holds, an anchor that stands without --refresh, or a folder that is not an anchor.
229
+ */
230
+ function anchorName_claim(places, name, source, request) {
231
+ const standing = berthState_read(places.anchors).anchors.find((anchor) => anchor.name === name);
232
+ if (standing !== undefined && standing.path !== source.path) {
233
+ throw new BerthRefusal(`anchor: the anchor ${name} holds ${standing.path}; name this one: ${ANCHOR_USAGE.replace('[name]', '<name>')}`);
234
+ }
235
+ if (standing !== undefined && !request.refresh) {
236
+ throw new BerthRefusal(`anchor: ${name} is anchored already; --refresh downloads it again`);
237
+ }
238
+ if (standing === undefined && existsSync(join(places.anchors, name))) {
239
+ throw new BerthRefusal(`anchor: ${join(places.anchors, name)} is there and is not an anchor`);
240
+ }
241
+ return standing ?? null;
242
+ }
243
+ /**
244
+ * Says the size and the room, and refuses or asks as the size wants: what
245
+ * does not fit is refused, above {@link ANCHOR_ASK_BYTES} the person is asked.
246
+ *
247
+ * @param places - The berth's places.
248
+ * @param name - The anchor's name.
249
+ * @param files - The files to download.
250
+ * @param freed - Bytes a refresh frees before it downloads.
251
+ * @param yes - Whether the question is answered already.
252
+ * @returns True to download, false when the person said no.
253
+ * @throws {BerthRefusal} When it does not fit.
254
+ */
255
+ async function anchorSize_settle(places, name, files, freed, yes) {
256
+ const bytes = bytes_sum(files);
257
+ const room = freeBytes_get(places.anchors) + freed;
258
+ sink_dataLine(`berth: anchor: ${name}: ${count_say(files.length, 'file')}, ${size_format(bytes)}; ${size_format(room)} free in ${places.anchors}`);
259
+ if (bytes > room) {
260
+ throw new BerthRefusal(`anchor: ${name} does not fit: ${size_format(bytes)} with ${size_format(room)} free; anchor a folder inside it`);
261
+ }
262
+ if (bytes <= ANCHOR_ASK_BYTES || yes)
263
+ return true;
264
+ return repl_confirm(`berth: anchor: download ${size_format(bytes)} into ${join(places.anchors, name)}?`);
265
+ }
266
+ /**
267
+ * `berth anchor <path> [name] [--refresh] [--yes]`: downloads a ChRIS path
268
+ * into `<anchors>/<name>/` and records it.
269
+ *
270
+ * @param args - The words after `anchor`.
271
+ * @returns What was anchored, or the refusal.
272
+ * @throws {BerthRefusal} As the steps refuse.
273
+ */
274
+ async function anchor_run(args) {
275
+ const places = places_require('anchor');
276
+ const request = anchorRequest_parse(args);
277
+ const resolved = await berthPath_resolve(request.typed);
278
+ const source = await anchorSource_find(resolved, await berthHome_get());
279
+ const name = request.name ?? source.defaultName;
280
+ anchorName_check(name);
281
+ const standing = anchorName_claim(places, name, source, request);
282
+ await nodeFinished_check(source);
283
+ const files = await sourceFiles_list(source, request.typed);
284
+ const freed = standing === null ? 0 : bytes_sum(standing.files);
285
+ if (!await anchorSize_settle(places, name, files, freed, request.yes)) {
286
+ exitCode_set(1);
287
+ return envelope_ok(`berth: anchor: ${name}: nothing downloaded\n`);
288
+ }
289
+ const final = join(places.anchors, name);
290
+ const partial = join(places.anchors, `${PARTIAL_PREFIX}${name}`);
291
+ if (standing !== null) {
292
+ // A refresh lets the old copy go first, as drop does: ChRIS still holds it.
293
+ rmSync(final, { recursive: true, force: true });
294
+ berthState_update(places.anchors, (state) => ({ ...state, anchors: state.anchors.filter((anchor) => anchor.name !== name) }));
295
+ }
296
+ rmSync(partial, { recursive: true, force: true });
297
+ try {
298
+ await files_download(files, partial, name);
299
+ }
300
+ catch (error) {
301
+ rmSync(partial, { recursive: true, force: true });
302
+ throw new BerthRefusal(`anchor: ${name}: ${error instanceof Error ? error.message : String(error)}; nothing anchored`);
303
+ }
304
+ renameSync(partial, final);
305
+ const anchor = {
306
+ name,
307
+ path: source.path,
308
+ node: source.node,
309
+ feed: source.feed,
310
+ files: files.map((file) => ({ name: file.name, size: file.size })),
311
+ anchoredAt: new Date().toISOString(),
312
+ };
313
+ berthState_update(places.anchors, (state) => ({ ...state, anchors: [...state.anchors, anchor] }));
314
+ const node = source.nodeName === null ? 'no node' : `node ${source.nodeName}`;
315
+ return envelope_ok(`${chalk.green(`${name}`)} ${chalk.gray(`${source.path} → ${final} ${count_say(files.length, 'file')}, ${size_format(bytes_sum(files))}, ${node}`)}\n`);
316
+ }
317
+ /**
318
+ * A time as the listing shows it: local date and minute.
319
+ *
320
+ * @param iso - An ISO 8601 time.
321
+ * @returns `2026-11-13 10:22`, or the text as it is when it is not a time.
322
+ */
323
+ function time_show(iso) {
324
+ const at = new Date(iso);
325
+ if (Number.isNaN(at.getTime()))
326
+ return iso;
327
+ const two = (value) => String(value).padStart(2, '0');
328
+ return `${at.getFullYear()}-${two(at.getMonth() + 1)}-${two(at.getDate())} ${two(at.getHours())}:${two(at.getMinutes())}`;
329
+ }
330
+ /**
331
+ * `berth`: every anchor with its path, node, files, size and time, and when
332
+ * the berth last closed; on a host, that the session runs there.
333
+ *
334
+ * @returns The listing.
335
+ */
336
+ function berth_list() {
337
+ const places = berthPlaces_read();
338
+ if (places === null)
339
+ return envelope_ok('berth: this session runs on the host, not in a berth\n');
340
+ const state = berthState_read(places.anchors);
341
+ const closed = `last close: ${state.lastClosedAt === null ? 'never' : time_show(state.lastClosedAt)}`;
342
+ if (state.anchors.length === 0) {
343
+ return envelope_ok(`no anchors in ${places.anchors}; ${ANCHOR_USAGE} downloads one\n${chalk.gray(closed)}\n`);
344
+ }
345
+ const rows = [
346
+ ['NAME', 'PATH', 'NODE', 'FILES', 'SIZE', 'ANCHORED'],
347
+ ...state.anchors.map((anchor) => [
348
+ anchor.name, anchor.path, anchorNode_show(anchor), String(anchor.files.length), size_format(bytes_sum(anchor.files)), time_show(anchor.anchoredAt),
349
+ ]),
350
+ ];
351
+ const [header, ...lines] = columns_render(rows);
352
+ return envelope_ok(`${chalk.bold(header ?? '')}\n${lines.join('\n')}\n${chalk.gray(closed)}\n`);
353
+ }
354
+ /**
355
+ * `berth drop <name>`: removes one anchor, with no question, since ChRIS still holds it.
356
+ *
357
+ * @param args - The words after `drop`.
358
+ * @returns What was dropped.
359
+ * @throws {BerthRefusal} For no name, or no anchor of that name.
360
+ */
361
+ function drop_run(args) {
362
+ const places = places_require('drop');
363
+ if (args.length !== 1)
364
+ throw new BerthRefusal('drop: usage: berth drop <name>');
365
+ const name = args[0];
366
+ const anchor = berthState_read(places.anchors).anchors.find((one) => one.name === name);
367
+ if (anchor === undefined)
368
+ throw new BerthRefusal(`drop: no anchor named ${name}`);
369
+ rmSync(join(places.anchors, name), { recursive: true, force: true });
370
+ berthState_update(places.anchors, (state) => ({ ...state, anchors: state.anchors.filter((one) => one.name !== name) }));
371
+ return envelope_ok(`${chalk.gray(`dropped ${name}; ChRIS still holds ${anchor.path}`)}\n`);
372
+ }
373
+ /**
374
+ * The files under a folder changed since a time: every file when there is none.
375
+ *
376
+ * @param folder - The folder.
377
+ * @param since - The time, in milliseconds since the epoch; null for every file.
378
+ * @returns Their paths.
379
+ */
380
+ function filesChanged_list(folder, since) {
381
+ const changed = [];
382
+ const entries = existsSync(folder) ? readdirSync(folder, { withFileTypes: true, recursive: true }) : [];
383
+ for (const entry of entries) {
384
+ if (entry.isDirectory())
385
+ continue;
386
+ const path = join(entry.parentPath, entry.name);
387
+ const modified = statSync(path, { throwIfNoEntry: false })?.mtimeMs;
388
+ if (since === null || modified === undefined || modified > since)
389
+ changed.push(path);
390
+ }
391
+ return changed;
392
+ }
393
+ /**
394
+ * Removes everything inside a folder, leaving the folder: a berth's places
395
+ * are mounts, which the session does not remove.
396
+ *
397
+ * @param folder - The folder.
398
+ */
399
+ function folder_empty(folder) {
400
+ if (!existsSync(folder))
401
+ return;
402
+ for (const name of readdirSync(folder))
403
+ rmSync(join(folder, name), { recursive: true, force: true });
404
+ }
405
+ /**
406
+ * `berth clear`: removes every anchor and empties the outgoing folder, asking
407
+ * first only when the outgoing folder holds files not yet closed.
408
+ *
409
+ * @param args - The words after `clear`.
410
+ * @returns What was removed, or that nothing was.
411
+ * @throws {BerthRefusal} For any word after clear.
412
+ */
413
+ async function clear_run(args) {
414
+ const places = places_require('clear');
415
+ if (args.length !== 0)
416
+ throw new BerthRefusal('clear: usage: berth clear');
417
+ const state = berthState_read(places.anchors);
418
+ const since = state.lastClosedAt === null ? null : Date.parse(state.lastClosedAt);
419
+ const unclosed = filesChanged_list(places.outgoing, since);
420
+ if (unclosed.length > 0) {
421
+ const asked = `berth: clear: ${places.outgoing} holds ${count_say(unclosed.length, 'file')} not yet closed; remove them and every anchor?`;
422
+ if (!await repl_confirm(asked)) {
423
+ exitCode_set(1);
424
+ return envelope_ok('berth: clear: nothing removed\n');
425
+ }
426
+ }
427
+ for (const name of readdirSync(places.anchors)) {
428
+ if (name !== BERTH_STATE_FILE)
429
+ rmSync(join(places.anchors, name), { recursive: true, force: true });
430
+ }
431
+ berthState_update(places.anchors, (now) => ({ ...now, anchors: [] }));
432
+ folder_empty(places.outgoing);
433
+ return envelope_ok(`${chalk.gray(`cleared ${count_say(state.anchors.length, 'anchor')} and emptied ${places.outgoing}`)}\n`);
434
+ }
435
+ /**
436
+ * `berth [anchor … | close … | drop <name> | clear]`: the anchors of this session's berth, and its close.
437
+ *
438
+ * @param args - The words after `berth`.
439
+ * @returns The answer, or a refusal in POSIX tone.
440
+ *
441
+ * @example
442
+ * ```ts
443
+ * await builtin_berth(['anchor', '~/uploads/weights', 'w']);
444
+ * await builtin_berth([]); // the anchors
445
+ * ```
446
+ */
447
+ export async function builtin_berth(args) {
448
+ const [subcommand, ...rest] = args;
449
+ try {
450
+ if (subcommand === undefined)
451
+ return berth_list();
452
+ if (subcommand === 'anchor')
453
+ return await anchor_run(rest);
454
+ if (subcommand === 'drop')
455
+ return drop_run(rest);
456
+ if (subcommand === 'clear')
457
+ return await clear_run(rest);
458
+ if (subcommand === 'close')
459
+ return await close_run(places_require('close'), rest);
460
+ if (berthPlaces_read() === null)
461
+ return berth_refuse(`${subcommand}: this session runs on the host, not in a berth`);
462
+ return berth_refuse(`${subcommand}: unknown subcommand; usage: ${BERTH_USAGE}`);
463
+ }
464
+ catch (error) {
465
+ if (error instanceof BerthRefusal)
466
+ return berth_refuse(error.message);
467
+ const reason = error instanceof Error ? error.message : String(error);
468
+ return berth_refuse(subcommand === undefined ? reason : `${subcommand}: ${reason}`);
469
+ }
470
+ }
471
+ //# sourceMappingURL=berth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"berth.js","sourceRoot":"","sources":["../../../src/builtins/berth/berth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { type CommandEnvelope } from '@fnndsc/menu';
2
+ import { type BerthPlaces } from './berthState.js';
3
+ /** The subcommand's usage line. */
4
+ export declare const CLOSE_USAGE: string;
5
+ /** The registered ds plugin the work's node runs: it copies its `dir` and does nothing else. */
6
+ export declare const WORK_PLUGIN: string;
7
+ /** The work node's title unless one is given. */
8
+ export declare const WORK_TITLE: string;
9
+ /**
10
+ * `berth close [--infeed <anchor> | --newfeed] [--name <feed>] [--title <text>] [--force]`:
11
+ * returns the outgoing folder to ChRIS as one node.
12
+ *
13
+ * @param places - The berth's places.
14
+ * @param args - The words after `close`.
15
+ * @returns Where the work went and its files folder, or that nothing closed.
16
+ * @throws {BerthRefusal} For an empty outgoing folder, a placement the anchors do not decide, and an upload that fails.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * await close_run({ anchors: '/anchors', outgoing: '/outgoing' }, ['--newfeed', '--name', 'seg run']);
21
+ * ```
22
+ */
23
+ export declare function close_run(places: BerthPlaces, args: readonly string[]): Promise<CommandEnvelope>;