@fnndsc/brasa 0.56.3 → 0.57.0

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 (96) hide show
  1. package/dist/buildinfo.json +1 -1
  2. package/dist/builtins/argumentTokens.d.ts +13 -0
  3. package/dist/builtins/argumentTokens.js +15 -3
  4. package/dist/builtins/argumentTokens.js.map +1 -1
  5. package/dist/builtins/berth/berth.d.ts +11 -0
  6. package/dist/builtins/berth/berth.js +53 -22
  7. package/dist/builtins/berth/berth.js.map +1 -1
  8. package/dist/builtins/berth/berthCube.d.ts +14 -0
  9. package/dist/builtins/berth/berthCube.js +17 -0
  10. package/dist/builtins/berth/berthCube.js.map +1 -1
  11. package/dist/builtins/fs/download.d.ts +12 -1
  12. package/dist/builtins/fs/download.js +24 -4
  13. package/dist/builtins/fs/download.js.map +1 -1
  14. package/dist/builtins/fs/transferJobs.d.ts +64 -0
  15. package/dist/builtins/fs/transferJobs.js +98 -0
  16. package/dist/builtins/fs/transferJobs.js.map +1 -0
  17. package/dist/builtins/fs/upload.d.ts +14 -1
  18. package/dist/builtins/fs/upload.js +22 -5
  19. package/dist/builtins/fs/upload.js.map +1 -1
  20. package/dist/builtins/fs/url.d.ts +27 -2
  21. package/dist/builtins/fs/url.js +60 -10
  22. package/dist/builtins/fs/url.js.map +1 -1
  23. package/dist/builtins/help.d.ts +6 -10
  24. package/dist/builtins/help.js +34 -87
  25. package/dist/builtins/help.js.map +1 -1
  26. package/dist/builtins/helpSections.js +4 -1
  27. package/dist/builtins/helpSections.js.map +1 -1
  28. package/dist/builtins/pluginExecute.d.ts +21 -3
  29. package/dist/builtins/pluginExecute.js +69 -33
  30. package/dist/builtins/pluginExecute.js.map +1 -1
  31. package/dist/builtins/res/pipeline.d.ts +231 -2
  32. package/dist/builtins/res/pipeline.js +225 -107
  33. package/dist/builtins/res/pipeline.js.map +1 -1
  34. package/dist/builtins/res/plugin.d.ts +343 -3
  35. package/dist/builtins/res/plugin.js +221 -67
  36. package/dist/builtins/res/plugin.js.map +1 -1
  37. package/dist/builtins/res/plugin.sync.js +5 -3
  38. package/dist/builtins/res/plugin.sync.js.map +1 -1
  39. package/dist/chris/binDeclarations.d.ts +312 -0
  40. package/dist/chris/binDeclarations.js +572 -0
  41. package/dist/chris/binDeclarations.js.map +1 -0
  42. package/dist/chris/chrisCommands.d.ts +1 -0
  43. package/dist/chris/chrisCommands.js +5 -30
  44. package/dist/chris/chrisCommands.js.map +1 -1
  45. package/dist/chris/commandFallback.d.ts +30 -3
  46. package/dist/chris/commandFallback.js +163 -94
  47. package/dist/chris/commandFallback.js.map +1 -1
  48. package/dist/chris/completion.d.ts +37 -0
  49. package/dist/chris/completion.js +41 -121
  50. package/dist/chris/completion.js.map +1 -1
  51. package/dist/chris/kinds.d.ts +11 -0
  52. package/dist/chris/kinds.js +32 -1
  53. package/dist/chris/kinds.js.map +1 -1
  54. package/dist/core/argumentKinds.d.ts +18 -0
  55. package/dist/core/argumentKinds.js +33 -0
  56. package/dist/core/argumentKinds.js.map +1 -1
  57. package/dist/core/backend.d.ts +12 -5
  58. package/dist/core/backend.js.map +1 -1
  59. package/dist/core/commandDeclaration.d.ts +40 -0
  60. package/dist/core/commandDeclaration.js.map +1 -1
  61. package/dist/core/commandOrder.js +3 -3
  62. package/dist/core/commandOrder.js.map +1 -1
  63. package/dist/core/commandParse.d.ts +14 -0
  64. package/dist/core/commandParse.js +39 -5
  65. package/dist/core/commandParse.js.map +1 -1
  66. package/dist/core/commandRegistry.d.ts +22 -36
  67. package/dist/core/commandRegistry.js +19 -10
  68. package/dist/core/commandRegistry.js.map +1 -1
  69. package/dist/core/commandSchema.js +4 -0
  70. package/dist/core/commandSchema.js.map +1 -1
  71. package/dist/core/coreCommands.d.ts +1 -0
  72. package/dist/core/coreCommands.js +6 -19
  73. package/dist/core/coreCommands.js.map +1 -1
  74. package/dist/core/dispatch.js +12 -41
  75. package/dist/core/dispatch.js.map +1 -1
  76. package/dist/core/preprocess.d.ts +0 -15
  77. package/dist/core/preprocess.js +0 -17
  78. package/dist/core/preprocess.js.map +1 -1
  79. package/dist/core/shellWords.d.ts +34 -0
  80. package/dist/core/shellWords.js +60 -0
  81. package/dist/core/shellWords.js.map +1 -0
  82. package/dist/core.d.ts +5 -0
  83. package/dist/core.js +4 -0
  84. package/dist/core.js.map +1 -1
  85. package/dist/lib/completer/declared.js +22 -6
  86. package/dist/lib/completer/declared.js.map +1 -1
  87. package/dist/lib/completer/index.js +15 -53
  88. package/dist/lib/completer/index.js.map +1 -1
  89. package/dist/notes.json +1 -1
  90. package/package.json +5 -5
  91. package/dist/builtins/res/pipeline.args.d.ts +0 -35
  92. package/dist/builtins/res/pipeline.args.js +0 -94
  93. package/dist/builtins/res/pipeline.args.js.map +0 -1
  94. package/dist/chris/help.d.ts +0 -18
  95. package/dist/chris/help.js +0 -229
  96. package/dist/chris/help.js.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import { chrisfetchCommand, pingCommand } from '../builtins/games/chrislab.js';
2
- import { builtin_pipeline, builtin_plugin } from '../builtins/index.js';
2
+ import { pluginCommand } from '../builtins/res/plugin.js';
3
+ import { pipelineCommand } from '../builtins/res/pipeline.js';
3
4
  import { chmodCommand, getfaclCommand, setfaclCommand } from '../builtins/fs/acl.js';
4
5
  import { getfattrCommand, setfattrCommand } from '../builtins/fs/xattr.js';
5
6
  import { pacsCommand } from '../builtins/net/pacs.js';
@@ -16,7 +17,6 @@ import { contextCommand } from '../builtins/sys/context.js';
16
17
  import { physicalmodeCommand } from '../builtins/sys/physicalmode.js';
17
18
  import { idCommand, whereamiCommand, whoamiCommand } from '../builtins/sys/whoami.js';
18
19
  import { procCommand } from '../builtins/proc.js';
19
- import { envelopeHandler_wrap } from '../core/sink.js';
20
20
  import { fileCommand, md5sumCommand, sha256sumCommand, stringsCommand, xxdCommand } from '../builtins/games/bytes.js';
21
21
  import { duCommand } from '../builtins/fs/du.js';
22
22
  import { editCommand } from '../builtins/fs/edit.js';
@@ -27,7 +27,6 @@ import { recordCommand } from '../builtins/res/record.js';
27
27
  import { gatherCommand } from '../builtins/res/gather.js';
28
28
  import { userCommand } from '../builtins/res/user.js';
29
29
  import { motdCommand } from '../builtins/sys/motd.js';
30
- import { chrisHelp } from './help.js';
31
30
  import { whatifCommand } from './commandFallback.js';
32
31
  import { berthCommand } from '../builtins/berth/berth.js';
33
32
  import { downloadCommand } from '../builtins/fs/download.js';
@@ -41,29 +40,6 @@ import { workflowCommand } from '../builtins/res/workflow.js';
41
40
  import { dirsCommand, filesCommand, linksCommand } from '../builtins/res/files.js';
42
41
  import { parametersofpluginCommand } from '../builtins/parametersofplugin.js';
43
42
  import { storeCommand } from '../builtins/store.js';
44
- const envelope = {
45
- plugin: builtin_plugin,
46
- plugins: builtin_plugin,
47
- pipeline: builtin_pipeline,
48
- pipelines: builtin_pipeline,
49
- };
50
- const plain = {
51
- pipeline: envelopeHandler_wrap(builtin_pipeline),
52
- pipelines: envelopeHandler_wrap(builtin_pipeline),
53
- plugin: envelopeHandler_wrap(builtin_plugin),
54
- plugins: envelopeHandler_wrap(builtin_plugin),
55
- };
56
- /** The ChRIS backend commands: their handlers. Their help is registered from `builtins/help.ts`, which holds it. */
57
- /**
58
- * What the ChRIS commands hold of the session: a read holds nothing and
59
- * runs beside anything. A command not named holds the whole session; a
60
- * declared command says in its declaration (`gather` holds the cohort).
61
- */
62
- const holds = {
63
- ...Object.fromEntries([
64
- 'pipelines', 'plugins',
65
- ].map((name) => [name, []])),
66
- };
67
43
  /** The ChRIS commands declared in one record each: grammar, kinds, handler, holds and help together. */
68
44
  const declarations = [
69
45
  downloadCommand, berthCommand,
@@ -80,12 +56,11 @@ const declarations = [
80
56
  xxdCommand, stringsCommand, sha256sumCommand, md5sumCommand, motdCommand, recordCommand,
81
57
  // Files.
82
58
  editCommand, configCommand, uploadCommand, fileCommand,
59
+ // Resources.
60
+ pluginCommand, pipelineCommand,
83
61
  ];
62
+ /** The ChRIS backend's commands, every one declared in one record. */
84
63
  export const chrisCommands = {
85
- envelope,
86
- plain,
87
- help: chrisHelp,
88
- holds,
89
64
  declarations,
90
65
  };
91
66
  //# sourceMappingURL=chrisCommands.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chrisCommands.js","sourceRoot":"","sources":["../../src/chris/chrisCommands.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chrisCommands.js","sourceRoot":"","sources":["../../src/chris/chrisCommands.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,37 @@
1
1
  import type { CommandEnvelope } from '@fnndsc/menu';
2
2
  import type { BackendFallback } from '../core/backend.js';
3
3
  import type { ExpressionDeclaration } from '../core/commandDeclaration.js';
4
+ import { type PipelineLine } from './binDeclarations.js';
5
+ /** The built-in names the ChRIS session answers, for `help variables`. */
6
+ export declare const CHRIS_BUILTIN_LINES: ReadonlyArray<string>;
7
+ /**
8
+ * Answers a pipeline line already read: the look it asks for, or its runs.
9
+ * --diagram (with --withargs, or --signalflow) → the diagram
10
+ * --signalflow → SignalFlow YAML
11
+ * --help / -h → the pipeline's page
12
+ * --nodes / --parameters → pipeline info
13
+ * --manifest → pipeline manifest
14
+ * --source / --readme → pipeline source
15
+ * otherwise → a run
16
+ *
17
+ * @param name - The pipeline's `/bin` name.
18
+ * @param line - The line, read against its declaration.
19
+ * @param dry - Resolve a run and print it, creating and running nothing.
20
+ * @returns The answer's envelope.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * await pipelineParsed_run('PHI_detection_id12', line);
25
+ * ```
26
+ */
27
+ export declare function pipelineParsed_run(name: string, line: PipelineLine, dry?: boolean): Promise<CommandEnvelope>;
4
28
  /**
5
29
  * `whatif <plugin or Pipeline line>`: resolves the line as a run would, to
6
30
  * the version, the operands, the stage, the node and the parameters, prints
7
31
  * that, and stops before anything is created or run. A prefix, as `time`
8
- * and `env` are, since every flag after a `/bin` name is the plugin's.
32
+ * and `env` are, since every flag after a `/bin` name is the plugin's: the
33
+ * line after it is parsed against that plugin's or pipeline's declaration,
34
+ * and refused as the real line would be.
9
35
  *
10
36
  * @param args - The line: the `/bin` name and its words.
11
37
  * @returns An ok envelope when the real line would be accepted; an error after the refusal the real line would give.
@@ -13,8 +39,9 @@ import type { ExpressionDeclaration } from '../core/commandDeclaration.js';
13
39
  export declare function builtin_whatif(args: string[]): Promise<CommandEnvelope>;
14
40
  /**
15
41
  * `whatif <plugin or Pipeline line>`: the declaration. Its words are a whole
16
- * line of another command, whose flags are that command's, so it parses
17
- * them itself (an expression grammar), as `time` and `env` would.
42
+ * line of another command, whose grammar is that command's (the declaration
43
+ * CUBE's parameters make), so it hands them on as they came, as `time` and
44
+ * `env` would.
18
45
  *
19
46
  * @example
20
47
  * ```ts
@@ -3,19 +3,20 @@
3
3
  *
4
4
  * A plugin named with its version runs as that plugin. A word naming a
5
5
  * plugin or a pipeline in `/bin` runs it (a captured line runs only a
6
- * pipeline: a plugin's run prints live). Anything else goes to chili, when
7
- * chili has the command, with a notice ahead of its output.
6
+ * pipeline: a plugin's run prints live). Its line is parsed first against
7
+ * the declaration made from CUBE's parameters (`binDeclarations.ts`), and a
8
+ * bad line is refused before anything runs. Anything else goes to chili,
9
+ * when chili has the command, with a notice ahead of its output.
8
10
  *
9
11
  * @module
10
12
  */
11
13
  import chalk from 'chalk';
12
- import { CHRIS_BUILTIN_LINES } from './help.js';
13
14
  import { variablesPage_render } from '../builtins/variablesPage.js';
14
15
  import { envelope_deliver, sink_get } from '../core/sink.js';
15
16
  import { exitCode_read, exitCode_set, handler_runDirect } from '../core/handlerRun.js';
16
17
  import { runs_awaitSettled, settlement_render } from '../builtins/res/runWait.js';
17
18
  import { binExecutableMatches_get, binPluginHighest_find } from './binExecutables.js';
18
- import { builtin_pipeline } from '../builtins/res/pipeline.js';
19
+ import { pipelineDiagramCommand_handle, pipelineInfo_handle, pipelineManifestCommand_handle, pipelineRun_execute, pipelineSource_handle, } from '../builtins/res/pipeline.js';
19
20
  import { builtin_executePlugin } from '../builtins/pluginExecute.js';
20
21
  import { pluginExecutable_handle } from '../builtins/executable.js';
21
22
  import { pipelineExecutableHelp_render, pluginExecutableHelp_render } from '../builtins/help.js';
@@ -28,6 +29,14 @@ import { newFeed_cacheAdd } from '../builtins/feedCreation.js';
28
29
  import { OperandRefusal, operands_read, stage_lines, stage_make, stageMade_lines, stageWriter_default, stageWriter_none } from '../builtins/operands.js';
29
30
  import { echoNode_render } from '../builtins/runEcho.js';
30
31
  import { operandRuns_split } from '../builtins/operandRuns.js';
32
+ import { shellWords_values } from '../lib/parser.js';
33
+ import { binDeclaration_get, binEntry_resolve, pipelineDeclaration_get, pipelineWords_parse, pluginDeclaration_get, } from './binDeclarations.js';
34
+ /** The built-in names the ChRIS session answers, for `help variables`. */
35
+ export const CHRIS_BUILTIN_LINES = [
36
+ ' ${gather} every gathered member, as operands (where it was gathered FROM); read live',
37
+ ' ${gather.series.folderPath} the same members, where they LANDED in CUBE',
38
+ ' ${gather.name} ${gather.feed.id} any field of the cohort, as `gather` answers it',
39
+ ];
31
40
  /**
32
41
  * The node a pipeline run starts from, read from its operand (#1303): a
33
42
  * directory inside a feed is that node; outside one, or a set of files
@@ -35,14 +44,14 @@ import { operandRuns_split } from '../builtins/operandRuns.js';
35
44
  * name (or the subjects') as its title, and the run goes on from that root.
36
45
  *
37
46
  * @param name - The pipeline's `/bin` name, for the refusal lines.
38
- * @param args - The words after it.
47
+ * @param line - The line, read.
39
48
  * @param dry - Say where the run would start, staging and rooting nothing (`whatif`).
40
- * @returns The words to run with (`--previous` set) and whether a feed was rooted, or null after a refusal was said.
49
+ * @returns Where the run starts, or null after a refusal was said.
41
50
  */
42
- async function pipelineOperand_place(name, args, dry = false) {
51
+ async function pipelineOperand_place(name, line, dry = false) {
43
52
  let operands;
44
53
  try {
45
- operands = await operands_read(args);
54
+ operands = await operands_read(line.operands);
46
55
  }
47
56
  catch (error) {
48
57
  if (!(error instanceof OperandRefusal))
@@ -54,14 +63,14 @@ async function pipelineOperand_place(name, args, dry = false) {
54
63
  // No operand: the working directory is the input, as it is for a plugin run from /bin. Inside a feed node the
55
64
  // run goes on from that node (`pipeline run` reads it); outside one, pl-dircopy roots a new feed on it first,
56
65
  // as the directory operand would (#1364).
57
- if (operands.rest.some((word) => word.split('=')[0] === '--previous'))
58
- return { words: args, rooted: false };
66
+ if (line.previous !== undefined)
67
+ return { previous: line.previous, dryNewFeed: false, rooted: false };
59
68
  const cwd = await path_resolve('.');
60
69
  if (path_isInFeed(cwd))
61
- return { words: args, rooted: false };
70
+ return { dryNewFeed: false, rooted: false };
62
71
  operands = { ...operands, directory: cwd, typed: [cwd] };
63
72
  }
64
- if (operands.rest.some((word) => word.split('=')[0] === '--previous')) {
73
+ if (line.previous !== undefined) {
65
74
  sink_get().err_write(chalk.red(`${name}: the operand and --previous say the input twice\n`));
66
75
  return null;
67
76
  }
@@ -71,7 +80,7 @@ async function pipelineOperand_place(name, args, dry = false) {
71
80
  sink_get().err_write(chalk.red(`${name}: ${operands.typed[0]} is in a feed but not at a node (…/feeds/feed_N/pl-x_ID)\n`));
72
81
  return null;
73
82
  }
74
- return { words: ['--previous', String(here), ...operands.rest], rooted: false };
83
+ return { previous: here, dryNewFeed: false, rooted: false };
75
84
  }
76
85
  let stage = null;
77
86
  let root = operands.directory ?? '';
@@ -88,14 +97,14 @@ async function pipelineOperand_place(name, args, dry = false) {
88
97
  }
89
98
  if (dry)
90
99
  sink_get().data_write(chalk.cyan(`would stage under ${stage.path}\n`));
91
- for (const line of stage_lines(stage))
92
- sink_get().data_write(chalk.cyan(`${line}\n`));
100
+ for (const stageLine of stage_lines(stage))
101
+ sink_get().data_write(chalk.cyan(`${stageLine}\n`));
93
102
  root = stage.path;
94
103
  title = stage.subjects.map((subject) => subject.name).join(', ');
95
104
  }
96
105
  if (dry) {
97
106
  sink_get().data_write(chalk.gray(`${echoNode_render(root, title)}\n`));
98
- return { words: ['--whatif-new-feed', ...operands.rest], rooted: false };
107
+ return { dryNewFeed: true, rooted: false };
99
108
  }
100
109
  const feed = await feed_create([root], { title });
101
110
  if (feed === null) {
@@ -106,27 +115,39 @@ async function pipelineOperand_place(name, args, dry = false) {
106
115
  newFeed_cacheAdd({ feedID: feed.id, title, ownerUsername: feed.owner_username, rootInstanceID });
107
116
  sink_get().data_write(chalk.green(`Feed created: ${feed.id}\n`));
108
117
  if (stage !== null) {
109
- for (const line of stageMade_lines(stage, `/home/${feed.owner_username}/feeds/feed_${feed.id}/pl-dircopy_${rootInstanceID}/data`))
110
- sink_get().data_write(chalk.cyan(`${line}\n`));
118
+ for (const made of stageMade_lines(stage, `/home/${feed.owner_username}/feeds/feed_${feed.id}/pl-dircopy_${rootInstanceID}/data`))
119
+ sink_get().data_write(chalk.cyan(`${made}\n`));
111
120
  }
112
- return { words: ['--previous', String(rootInstanceID), ...operands.rest], rooted: true };
121
+ return { previous: rootInstanceID, dryNewFeed: false, rooted: true };
113
122
  }
114
123
  /**
115
124
  * Runs a pipeline once from the node its operand names.
116
125
  *
117
126
  * @param name - The pipeline's `/bin` name.
118
- * @param args - The words after it: at most one directory operand.
127
+ * @param line - The line, read: at most one directory operand.
119
128
  * @param dry - Resolve the run and print it, creating and running nothing.
120
129
  * @returns The run's envelope; an error envelope after a refusal was said.
121
130
  */
122
- async function pipelineRun_start(name, args, dry = false) {
131
+ async function pipelineRun_start(name, line, dry = false) {
123
132
  // The operand says where the run starts (#1303); refused, nothing runs.
124
- const placed = await pipelineOperand_place(name, args, dry);
125
- const words = placed === null || !dry || placed.words.includes('--whatif-new-feed') ? (placed?.words ?? []) : [...placed.words, '--whatif'];
126
- const envelope = placed === null ? { status: 'error', rendered: '' } : await builtin_pipeline(['run', name, ...words]);
133
+ const placed = await pipelineOperand_place(name, line, dry);
134
+ if (placed === null)
135
+ return { status: 'error', rendered: '' };
136
+ const request = {
137
+ pipeline: name,
138
+ ...(line.compute !== undefined ? { compute: line.compute } : {}),
139
+ ...(placed.previous !== undefined ? { previous: placed.previous } : {}),
140
+ ...(line.paramFile !== undefined ? { paramFile: line.paramFile } : {}),
141
+ bindings: line.bindings.map((binding) => ({ node: binding.node, field: binding.field, value: binding.value })),
142
+ detach: line.detach,
143
+ verbose: line.verbose,
144
+ dry,
145
+ dryNewFeed: placed.dryNewFeed,
146
+ };
147
+ const envelope = await pipelineRun_execute(request);
127
148
  // The model says when the run rooted a feed first: the fallback rooted it, so the fallback says so (the kind is
128
149
  // `pipeline.scheduled`, PIPELINE_SCHEDULED_KIND; named here so a test's stub of the pipeline module need not carry it).
129
- if (placed?.rooted === true && envelope.model?.kind === 'pipeline.scheduled')
150
+ if (placed.rooted && envelope.model?.kind === 'pipeline.scheduled')
130
151
  envelope.model.data.newFeed = true;
131
152
  return envelope;
132
153
  }
@@ -135,14 +156,14 @@ async function pipelineRun_start(name, args, dry = false) {
135
156
  * names several, each run headed by its operand.
136
157
  *
137
158
  * @param name - The pipeline's `/bin` name.
138
- * @param args - The words after it.
159
+ * @param line - The line, read.
139
160
  * @param dry - Resolve every run and print it, creating and running nothing.
140
161
  * @returns The last run's envelope, an error when any run failed or the line was refused.
141
162
  */
142
- async function pipelineRuns_start(name, args, dry = false) {
163
+ async function pipelineRuns_start(name, line, dry = false) {
143
164
  let runs;
144
165
  try {
145
- runs = await operandRuns_split(args);
166
+ runs = await operandRuns_split(line.operands);
146
167
  }
147
168
  catch (error) {
148
169
  if (!(error instanceof OperandRefusal))
@@ -151,21 +172,20 @@ async function pipelineRuns_start(name, args, dry = false) {
151
172
  return { status: 'error', rendered: '' };
152
173
  }
153
174
  if (runs.length === 1)
154
- return pipelineRun_start(name, args, dry);
175
+ return pipelineRun_start(name, line, dry);
155
176
  // Every run is dispatched before any is waited for; then one wait holds the line for them all.
156
- const detach = args.includes('--detach');
157
177
  const instanceIDs = [];
158
178
  let last = { status: 'ok', rendered: '' };
159
179
  let failed = false;
160
180
  for (const words of runs) {
161
181
  sink_get().data_write(chalk.gray(`${name} ${words[0]}:\n`));
162
- last = await pipelineRun_start(name, detach ? words : [...words, '--detach'], dry);
182
+ last = await pipelineRun_start(name, { ...line, operands: words, detach: true }, dry);
163
183
  failed ||= last.status === 'error';
164
184
  if (last.model?.kind === 'pipeline.scheduled') {
165
185
  instanceIDs.push(...last.model.data.instances.map((node) => node.instanceId));
166
186
  }
167
187
  }
168
- if (!detach && instanceIDs.length > 0) {
188
+ if (!line.detach && instanceIDs.length > 0) {
169
189
  const settlement = await runs_awaitSettled(instanceIDs, name);
170
190
  sink_get().data_write(`${settlement_render(settlement, name)}\n`);
171
191
  if (settlement.outcome === 'settled' && settlement.failed > 0)
@@ -174,51 +194,80 @@ async function pipelineRuns_start(name, args, dry = false) {
174
194
  return failed ? { ...last, status: 'error' } : last;
175
195
  }
176
196
  /**
177
- * Handles a pipeline name invoked directly as an executable from /bin.
178
- * Routes flag combinations to the appropriate pipeline subcommand:
179
- * --diagram → pipeline diagram (preserving renderer flags)
180
- * --signalflow → pipeline diagram --signalflow
181
- * --help / -h → contextual pipeline-executable help
182
- * --nodes / --parameters → pipeline info
183
- * --manifest → pipeline manifest
184
- * --source / --readme → pipeline source
185
- * (bare or --compute) → pipeline run
197
+ * Answers a pipeline line already read: the look it asks for, or its runs.
198
+ * --diagram (with --withargs, or --signalflow) → the diagram
199
+ * --signalflow → SignalFlow YAML
200
+ * --help / -h → the pipeline's page
201
+ * --nodes / --parameters → pipeline info
202
+ * --manifest → pipeline manifest
203
+ * --source / --readme → pipeline source
204
+ * otherwise → a run
186
205
  *
187
- * @param name - The pipeline name as typed.
188
- * @param args - Arguments following the pipeline name.
206
+ * @param name - The pipeline's `/bin` name.
207
+ * @param line - The line, read against its declaration.
189
208
  * @param dry - Resolve a run and print it, creating and running nothing.
190
- * @returns The pipeline builtin's envelope, preserving diagram models and text.
209
+ * @returns The answer's envelope.
210
+ *
211
+ * @example
212
+ * ```ts
213
+ * await pipelineParsed_run('PHI_detection_id12', line);
214
+ * ```
191
215
  */
192
- async function pipelineExecutable_handle(name, args, dry = false) {
216
+ export async function pipelineParsed_run(name, line, dry = false) {
193
217
  const exitCodeBefore = exitCode_read();
194
218
  let envelope;
195
- if (args.includes('--help') || args.includes('-h')) {
196
- envelope = { status: 'ok', rendered: pipelineExecutableHelp_render(name) };
197
- }
198
- else if (args.includes('--diagram')) {
199
- const diagramArgs = args.filter((argument) => argument !== '--diagram');
200
- envelope = await builtin_pipeline(['diagram', name, ...diagramArgs]);
219
+ switch (line.look) {
220
+ case 'help':
221
+ envelope = { status: 'ok', rendered: pipelineExecutableHelp_render(name, (await pipelineDeclaration_get(name)) ?? undefined) };
222
+ break;
223
+ case 'diagram':
224
+ envelope = await pipelineDiagramCommand_handle(name, line.withArguments, line.signalflow);
225
+ break;
226
+ case 'signalflow':
227
+ envelope = await pipelineDiagramCommand_handle(name, false, true);
228
+ break;
229
+ case 'manifest':
230
+ envelope = await pipelineManifestCommand_handle(name);
231
+ break;
232
+ case 'nodes':
233
+ envelope = await pipelineInfo_handle(name);
234
+ break;
235
+ case 'source':
236
+ envelope = await pipelineSource_handle(name);
237
+ break;
238
+ case null:
239
+ envelope = await pipelineRuns_start(name, line, dry);
240
+ break;
201
241
  }
202
- else if (args.includes('--signalflow')) {
203
- envelope = await builtin_pipeline(['diagram', name, '--signalflow']);
204
- }
205
- else if (args.includes('--manifest')) {
206
- envelope = await builtin_pipeline(['manifest', name]);
207
- }
208
- else if (args.includes('--nodes') || args.includes('--parameters')) {
209
- envelope = await builtin_pipeline(['info', name]);
210
- }
211
- else if (args.includes('--source') || args.includes('--readme')) {
212
- envelope = await builtin_pipeline(['source', name]);
213
- }
214
- else {
215
- envelope = await pipelineRuns_start(name, args, dry);
216
- }
217
- const result = envelope ?? { status: 'ok', rendered: '' };
218
242
  const exitCodeAfter = exitCode_read();
219
243
  if (exitCodeAfter !== 0 && exitCodeAfter !== exitCodeBefore)
220
- result.status = 'error';
221
- return result;
244
+ envelope.status = 'error';
245
+ return envelope;
246
+ }
247
+ /**
248
+ * Handles a pipeline name invoked directly as an executable from /bin: its
249
+ * line parsed against the declaration made from its manifest, a bad line
250
+ * refused before anything runs.
251
+ *
252
+ * @param name - The pipeline's `/bin` name.
253
+ * @param args - Arguments following the pipeline name.
254
+ * @param dry - Resolve a run and print it, creating and running nothing.
255
+ * @returns The answer's envelope; an error after a refusal.
256
+ */
257
+ async function pipelineExecutable_handle(name, args, dry = false) {
258
+ const declaration = await pipelineDeclaration_get(name);
259
+ if (declaration === null) {
260
+ sink_get().err_write(chalk.red(`${name}: could not read the pipeline's manifest from CUBE, so the line cannot be read\n`));
261
+ exitCode_set(1);
262
+ return { status: 'error', rendered: '' };
263
+ }
264
+ const parsed = await pipelineWords_parse(declaration, args);
265
+ if (!parsed.ok) {
266
+ sink_get().err_write(`${chalk.red(parsed.refusal)}\n`);
267
+ exitCode_set(1);
268
+ return { status: 'error', rendered: '' };
269
+ }
270
+ return pipelineParsed_run(name, parsed.line, dry);
222
271
  }
223
272
  /**
224
273
  * Hands a word to chili when chili has it, with the hand-off notice on the
@@ -240,7 +289,9 @@ async function chili_delegate(command, args) {
240
289
  * `whatif <plugin or Pipeline line>`: resolves the line as a run would, to
241
290
  * the version, the operands, the stage, the node and the parameters, prints
242
291
  * that, and stops before anything is created or run. A prefix, as `time`
243
- * and `env` are, since every flag after a `/bin` name is the plugin's.
292
+ * and `env` are, since every flag after a `/bin` name is the plugin's: the
293
+ * line after it is parsed against that plugin's or pipeline's declaration,
294
+ * and refused as the real line would be.
244
295
  *
245
296
  * @param args - The line: the `/bin` name and its words.
246
297
  * @returns An ok envelope when the real line would be accepted; an error after the refusal the real line would give.
@@ -251,49 +302,51 @@ export async function builtin_whatif(args) {
251
302
  sink_get().err_write(chalk.red('whatif: usage: whatif <plugin or Pipeline> [operands] [options]\n'));
252
303
  return { status: 'error', rendered: '' };
253
304
  }
305
+ // The words after the /bin name keep the shell words the line carried, so its operands glob by kind.
306
+ const carried = args.words;
307
+ const lineWords = carried !== undefined && carried.length === args.length ? shellWords_values(carried.slice(1)) : words;
254
308
  const binMatches = await binExecutableMatches_get(command);
255
309
  if (binMatches.plugin)
256
- return builtin_executePlugin(command, words, undefined, true);
310
+ return builtin_executePlugin(command, lineWords, undefined, true);
257
311
  if (binMatches.pipeline) {
258
- const envelope = await pipelineExecutable_handle(binMatches.pipeline.name, words, true);
312
+ const envelope = await pipelineExecutable_handle(binMatches.pipeline.name, lineWords, true);
259
313
  envelope_deliver(envelope);
260
314
  return { ...envelope, rendered: '' };
261
315
  }
262
316
  const highest = await binPluginHighest_find(command);
263
317
  if (highest !== null) {
264
318
  sink_get().data_write(chalk.gray(`running ${highest.executable} (highest of ${highest.versions.join(', ')})\n`));
265
- return builtin_executePlugin(highest.executable, words, undefined, true);
319
+ return builtin_executePlugin(highest.executable, lineWords, undefined, true);
266
320
  }
267
321
  sink_get().err_write(chalk.red(`whatif: ${command}: not a plugin or a Pipeline in /bin\n`));
268
322
  return { status: 'error', rendered: '' };
269
323
  }
270
324
  /**
271
325
  * Completes a word of a `whatif` line as the line after it completes: its
272
- * first word a plugin `/bin` lists, an option the plugin or pipeline takes,
273
- * and an operand a path when the `/bin` entry takes paths.
326
+ * first word a plugin or pipeline `/bin` lists, then the rest from that
327
+ * entry's declaration (its options, and its input paths).
274
328
  *
275
329
  * @param words - The words after `whatif`, before the one completed.
276
330
  * @param word - The word typed so far.
277
331
  * @returns The candidates.
278
332
  */
279
333
  async function whatifWord_complete(words, word) {
280
- const { chrisCompletion } = await import('./completion.js');
281
334
  const first = words[0];
282
335
  if (first === undefined) {
283
- const names = (await chrisCompletion.commandWords?.()) ?? [];
284
- return names.filter((name) => name.startsWith(word));
336
+ const { binNames_list } = await import('./completion.js');
337
+ return (await binNames_list()).filter((name) => name.startsWith(word));
285
338
  }
286
- if (word.startsWith('-'))
287
- return (await chrisCompletion.options?.([...words], word)) ?? [];
288
- if (words[words.length - 1] === 'as' || !(await chrisCompletion.pathArguments?.(first)))
339
+ const declaration = await binDeclaration_get(first);
340
+ if (declaration === null)
289
341
  return [];
290
- const { cfsPaths_complete } = await import('../lib/completer/cfsPaths.js');
291
- return cfsPaths_complete(word);
342
+ const { declaredWord_complete } = await import('../lib/completer/declared.js');
343
+ return declaredWord_complete(declaration, words.slice(1), word);
292
344
  }
293
345
  /**
294
346
  * `whatif <plugin or Pipeline line>`: the declaration. Its words are a whole
295
- * line of another command, whose flags are that command's, so it parses
296
- * them itself (an expression grammar), as `time` and `env` would.
347
+ * line of another command, whose grammar is that command's (the declaration
348
+ * CUBE's parameters make), so it hands them on as they came, as `time` and
349
+ * `env` would.
297
350
  *
298
351
  * @example
299
352
  * ```ts
@@ -306,7 +359,7 @@ export const whatifCommand = {
306
359
  help: {
307
360
  usage: 'whatif <plugin or Pipeline> [operands] [options]',
308
361
  summary: 'Print what a plugin or Pipeline line would do, and run nothing',
309
- description: 'Resolve the line as a run would and print it: the version picked, the operands as read, the stage, the node it would attach to or the feed it would root, and every parameter with defaults marked. Nothing is staged, no feed is made, no job starts. When the real line would refuse, whatif prints the same refusal and exits non-zero. A prefix, as time and env are: every flag after a /bin name belongs to the plugin, and several directory operands print one resolution per run.',
362
+ description: 'Resolve the line as a run would and print it: the version picked, the operands as read, the stage, the node it would attach to or the feed it would root, and every parameter with defaults marked. Nothing is staged, no feed is made, no job starts. When the real line would refuse, whatif prints the same refusal and exits non-zero: the line is parsed against the plugin\'s or Pipeline\'s own declaration, made from CUBE\'s parameters. A prefix, as time and env are: every flag after a /bin name belongs to the plugin, and several directory operands print one resolution per run.',
310
363
  category: 'Resources',
311
364
  examples: ['whatif pl-freesurfer ~/uploads/t1.nii as sub-01', 'whatif pl-dcm2niix ~/feeds/feed_12/pl-dircopy_40/data'],
312
365
  },
@@ -314,9 +367,27 @@ export const whatifCommand = {
314
367
  handler: builtin_whatif,
315
368
  complete: whatifWord_complete,
316
369
  };
370
+ /**
371
+ * The page of a `/bin` entry, its usage and every option from the
372
+ * declaration CUBE's parameters make.
373
+ *
374
+ * @param entry - The entry.
375
+ * @returns The page.
376
+ */
377
+ async function binEntryHelp_render(entry) {
378
+ if (entry.kind === 'plugin')
379
+ return pluginExecutableHelp_render(entry.executable, (await pluginDeclaration_get(entry.executable)) ?? undefined);
380
+ return pipelineExecutableHelp_render(entry.name, (await pipelineDeclaration_get(entry.name)) ?? undefined);
381
+ }
317
382
  /** The ChRIS backend's fallback. */
318
383
  export const chrisFallback = {
319
- claim: pluginExecutable_handle,
384
+ claim: async (command, args) => {
385
+ // A plugin version's page is its declaration's, read from CUBE.
386
+ if (/-v[^/]+$/.test(command) && (args.includes('--help') || args.includes('-h'))) {
387
+ return { status: 'ok', rendered: pluginExecutableHelp_render(command, (await pluginDeclaration_get(command)) ?? undefined) };
388
+ }
389
+ return pluginExecutable_handle(command, args);
390
+ },
320
391
  unknown: async (command, args, captured) => {
321
392
  const binMatches = await binExecutableMatches_get(command);
322
393
  // A bare /bin plugin name runs the plugin, and a run is a CUBE job: typed
@@ -349,13 +420,11 @@ export const chrisFallback = {
349
420
  return variablesPage_render(CHRIS_BUILTIN_LINES);
350
421
  // A plugin version (`pl-dircopy-v2.1.2`) is its own executable.
351
422
  if (/-v[^/]+$/.test(command))
352
- return pluginExecutableHelp_render(command);
353
- const binMatches = await binExecutableMatches_get(command);
354
- if (binMatches.pipeline)
355
- return pipelineExecutableHelp_render(binMatches.pipeline.name);
356
- // A bare plugin name's help is its highest version's.
357
- const highest = await binPluginHighest_find(command);
358
- return highest === null ? null : pluginExecutableHelp_render(highest.executable);
423
+ return pluginExecutableHelp_render(command, (await pluginDeclaration_get(command)) ?? undefined);
424
+ // A pipeline, or a bare plugin name (its highest version's page).
425
+ const entry = await binEntry_resolve(command);
426
+ return entry === null ? null : binEntryHelp_render(entry);
359
427
  },
428
+ declaration: binDeclaration_get,
360
429
  };
361
430
  //# sourceMappingURL=commandFallback.js.map