@fnndsc/brasa 0.23.2 → 0.25.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 (92) hide show
  1. package/dist/buildinfo.json +1 -1
  2. package/dist/builtins/fs/pull.args.d.ts +1 -1
  3. package/dist/builtins/fs/pull.args.js +5 -3
  4. package/dist/builtins/fs/pull.args.js.map +1 -1
  5. package/dist/builtins/fs/pull.js +2 -2
  6. package/dist/builtins/fs/touch.js +1 -1
  7. package/dist/builtins/fs/touch.js.map +1 -1
  8. package/dist/builtins/help.js +134 -10
  9. package/dist/builtins/help.js.map +1 -1
  10. package/dist/builtins/index.d.ts +6 -0
  11. package/dist/builtins/index.js +6 -0
  12. package/dist/builtins/index.js.map +1 -1
  13. package/dist/builtins/net/query.csv.js +14 -0
  14. package/dist/builtins/net/query.csv.js.map +1 -1
  15. package/dist/builtins/net/query.js +3 -0
  16. package/dist/builtins/net/query.js.map +1 -1
  17. package/dist/builtins/pluginExecute.js +28 -3
  18. package/dist/builtins/pluginExecute.js.map +1 -1
  19. package/dist/builtins/proc.js +32 -2
  20. package/dist/builtins/proc.js.map +1 -1
  21. package/dist/builtins/res/dicom.d.ts +35 -1
  22. package/dist/builtins/res/dicom.js +15 -2
  23. package/dist/builtins/res/dicom.js.map +1 -1
  24. package/dist/builtins/res/expect.d.ts +40 -0
  25. package/dist/builtins/res/expect.js +447 -0
  26. package/dist/builtins/res/expect.js.map +1 -0
  27. package/dist/builtins/res/gather.d.ts +10 -0
  28. package/dist/builtins/res/gather.js +224 -0
  29. package/dist/builtins/res/gather.js.map +1 -0
  30. package/dist/builtins/res/gather.store.d.ts +131 -0
  31. package/dist/builtins/res/gather.store.js +225 -0
  32. package/dist/builtins/res/gather.store.js.map +1 -0
  33. package/dist/builtins/res/pipeline.args.d.ts +5 -2
  34. package/dist/builtins/res/pipeline.args.js +8 -3
  35. package/dist/builtins/res/pipeline.args.js.map +1 -1
  36. package/dist/builtins/res/pipeline.js +23 -0
  37. package/dist/builtins/res/pipeline.js.map +1 -1
  38. package/dist/builtins/res/play.d.ts +70 -0
  39. package/dist/builtins/res/play.js +334 -0
  40. package/dist/builtins/res/play.js.map +1 -0
  41. package/dist/builtins/res/plugin.js +21 -6
  42. package/dist/builtins/res/plugin.js.map +1 -1
  43. package/dist/builtins/res/record.d.ts +49 -0
  44. package/dist/builtins/res/record.js +150 -0
  45. package/dist/builtins/res/record.js.map +1 -0
  46. package/dist/builtins/res/runWait.d.ts +49 -0
  47. package/dist/builtins/res/runWait.js +193 -0
  48. package/dist/builtins/res/runWait.js.map +1 -0
  49. package/dist/builtins/sys/motd.d.ts +41 -0
  50. package/dist/builtins/sys/motd.js +139 -0
  51. package/dist/builtins/sys/motd.js.map +1 -0
  52. package/dist/builtins/sys/weather.d.ts +132 -0
  53. package/dist/builtins/sys/weather.js +297 -0
  54. package/dist/builtins/sys/weather.js.map +1 -0
  55. package/dist/command-keys.js +4 -0
  56. package/dist/command-keys.js.map +1 -1
  57. package/dist/core/connect.d.ts +31 -1
  58. package/dist/core/connect.js +32 -1
  59. package/dist/core/connect.js.map +1 -1
  60. package/dist/core/dispatch.d.ts +0 -14
  61. package/dist/core/dispatch.js +85 -27
  62. package/dist/core/dispatch.js.map +1 -1
  63. package/dist/core/engine.d.ts +10 -0
  64. package/dist/core/engine.js +9 -0
  65. package/dist/core/engine.js.map +1 -1
  66. package/dist/core/expansion.d.ts +70 -0
  67. package/dist/core/expansion.js +289 -0
  68. package/dist/core/expansion.js.map +1 -0
  69. package/dist/core/promptContext.js +5 -1
  70. package/dist/core/promptContext.js.map +1 -1
  71. package/dist/lib/duration.d.ts +17 -0
  72. package/dist/lib/duration.js +25 -0
  73. package/dist/lib/duration.js.map +1 -0
  74. package/dist/lib/parser.d.ts +50 -0
  75. package/dist/lib/parser.js +119 -0
  76. package/dist/lib/parser.js.map +1 -1
  77. package/dist/logo/brain.d.ts +6 -27
  78. package/dist/logo/brain.js +5 -250
  79. package/dist/logo/brain.js.map +1 -1
  80. package/dist/session/answer.d.ts +141 -0
  81. package/dist/session/answer.js +163 -0
  82. package/dist/session/answer.js.map +1 -0
  83. package/dist/session/answerAdapters.d.ts +4 -0
  84. package/dist/session/answerAdapters.js +106 -0
  85. package/dist/session/answerAdapters.js.map +1 -0
  86. package/dist/session/recent.d.ts +68 -0
  87. package/dist/session/recent.js +99 -0
  88. package/dist/session/recent.js.map +1 -0
  89. package/dist/session/recorder.d.ts +61 -0
  90. package/dist/session/recorder.js +95 -0
  91. package/dist/session/recorder.js.map +1 -0
  92. package/package.json +5 -5
@@ -0,0 +1,163 @@
1
+ /**
2
+ * @file The session's last answer, so a row can be named by its number.
3
+ *
4
+ * An operator reads a listing and wants to act on the third row. Until now
5
+ * the only way to say which row was to repeat its address, which for a PACS
6
+ * series is a line of text nobody types by hand — so acting on what you can
7
+ * see was a surface gesture, and a scripted session could not do it at all.
8
+ *
9
+ * A command that answers with rows records them here, and `@3` resolves
10
+ * against the most recent one. The numbering belongs to the MODEL rather
11
+ * than to any rendering of it: a console table and a graphical pane show the
12
+ * same answer differently, and an index that meant different rows on
13
+ * different surfaces would be worse than no index at all.
14
+ *
15
+ * What a row IS differs by listing, and each one says: a path for files and
16
+ * PACS series, a feed id for feeds, an instance id for jobs. A verb then
17
+ * receives the operand it already takes.
18
+ *
19
+ * @module
20
+ */
21
+ import { ambient_publish } from '../core/ambient.js';
22
+ /** Every kind an answer may carry, for a refusal that lists them. */
23
+ export const ANSWER_KINDS = ['PAT', 'STD', 'SER', 'FIL', 'DIR'];
24
+ /** Model kind to the rows it holds. */
25
+ const adapters = new Map();
26
+ /** The session's last answer, or null before anything has listed. */
27
+ let held = null;
28
+ /** Whether an index has been resolved against the held answer this line. */
29
+ let consulted = false;
30
+ /** Rises with each answer, so a surface can tell newer from older. */
31
+ let sequence = 0;
32
+ /** Past this many rows the addresses stay in the kernel and off the wire. */
33
+ const VALUES_ON_THE_WIRE_MAX = 500;
34
+ /**
35
+ * Registers what a model kind's rows are.
36
+ *
37
+ * @param kind - The envelope model kind.
38
+ * @param adapter - Reads the rows out of that model.
39
+ */
40
+ export function answerAdapter_register(kind, adapter) {
41
+ adapters.set(kind, adapter);
42
+ }
43
+ /**
44
+ * Notes an answer, when the model is one whose rows can be numbered.
45
+ *
46
+ * @param kind - The envelope model kind.
47
+ * @param data - The model's payload.
48
+ * @param source - The line that produced it.
49
+ */
50
+ export function answer_note(kind, data, source) {
51
+ const adapter = adapters.get(kind);
52
+ if (adapter === undefined)
53
+ return;
54
+ const rows = adapter(data);
55
+ // An answer with no rows does not replace one that has them: `ls` on an
56
+ // empty folder should not silently un-number the listing just read.
57
+ if (rows === null || rows.length === 0)
58
+ return;
59
+ sequence += 1;
60
+ held = { source, rows };
61
+ // A surface cannot light the index pills on the right listing unless it is
62
+ // told which one the numbers now count. Pills that lie are worse than none.
63
+ ambient_publish({
64
+ kind: 'numbered',
65
+ id: sequence,
66
+ source,
67
+ rows: rows.length,
68
+ // A surface matches a row by its address and draws the code, so the
69
+ // handles travel — up to a cap, past which a listing is numbered in the
70
+ // kernel and unnumbered on screen rather than flooding the wire.
71
+ handles: rows.length <= VALUES_ON_THE_WIRE_MAX ? answerHandles_get() : [],
72
+ });
73
+ }
74
+ /**
75
+ * The row a handle names.
76
+ *
77
+ * @param handle - The kind and 1-based ordinal the operator wrote.
78
+ * @returns The row, or null when nothing is numbered, the kind is absent
79
+ * from the answer, or the ordinal is past that kind's end.
80
+ */
81
+ export function answerRow_get(handle) {
82
+ if (held === null)
83
+ return null;
84
+ const ofKind = held.rows.filter((row) => row.kind === handle.kind);
85
+ const row = ofKind[handle.ordinal - 1];
86
+ if (row === undefined)
87
+ return null;
88
+ consulted = true;
89
+ return row;
90
+ }
91
+ /**
92
+ * How many rows of a kind the answer holds, for a refusal that says so.
93
+ *
94
+ * @param kind - The kind asked about.
95
+ * @returns The count, zero when nothing is numbered.
96
+ */
97
+ export function answerKind_count(kind) {
98
+ if (held === null)
99
+ return 0;
100
+ return held.rows.filter((row) => row.kind === kind).length;
101
+ }
102
+ /**
103
+ * Every row's handle beside its address, in answer order.
104
+ *
105
+ * A surface finds each of its rows by address and draws the code the
106
+ * operator would type.
107
+ *
108
+ * @returns The handles.
109
+ */
110
+ export function answerHandles_get() {
111
+ if (held === null)
112
+ return [];
113
+ const seen = new Map();
114
+ return held.rows.map((row) => {
115
+ const ordinal = (seen.get(row.kind) ?? 0) + 1;
116
+ seen.set(row.kind, ordinal);
117
+ return { kind: row.kind, ordinal, address: row.address ?? row.values[0] ?? '' };
118
+ });
119
+ }
120
+ /**
121
+ * What is currently numbered, for a surface that lights its index pills.
122
+ *
123
+ * @returns The held answer, or null when nothing has listed.
124
+ */
125
+ export function answer_get() {
126
+ return held;
127
+ }
128
+ /**
129
+ * Takes the note that an index was resolved, for the line's readout.
130
+ *
131
+ * A line that acts on a number says which listing it counted — the standing
132
+ * rule that a readout which acts says so.
133
+ *
134
+ * @returns What was consulted, or null when this line used no index.
135
+ */
136
+ export function answerConsulted_take() {
137
+ if (!consulted || held === null)
138
+ return null;
139
+ consulted = false;
140
+ return held;
141
+ }
142
+ /** Forgets the answer, for a test that needs a session that has listed nothing. */
143
+ export function answer_forget() {
144
+ held = null;
145
+ consulted = false;
146
+ sequence = 0;
147
+ }
148
+ /**
149
+ * Which answer is numbered, for a surface attaching late.
150
+ *
151
+ * @returns The current numbering, or null when nothing has listed.
152
+ */
153
+ export function numbering_get() {
154
+ if (held === null)
155
+ return null;
156
+ return {
157
+ id: sequence,
158
+ source: held.source,
159
+ rows: held.rows.length,
160
+ handles: held.rows.length <= VALUES_ON_THE_WIRE_MAX ? answerHandles_get() : [],
161
+ };
162
+ }
163
+ //# sourceMappingURL=answer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"answer.js","sourceRoot":"","sources":["../../src/session/answer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAarD,qEAAqE;AACrE,MAAM,CAAC,MAAM,YAAY,GAA8B,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAuD3F,uCAAuC;AACvC,MAAM,QAAQ,GAA+B,IAAI,GAAG,EAAE,CAAC;AAEvD,qEAAqE;AACrE,IAAI,IAAI,GAAyB,IAAI,CAAC;AAEtC,4EAA4E;AAC5E,IAAI,SAAS,GAAY,KAAK,CAAC;AAE/B,sEAAsE;AACtE,IAAI,QAAQ,GAAW,CAAC,CAAC;AAEzB,6EAA6E;AAC7E,MAAM,sBAAsB,GAAW,GAAG,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY,EAAE,OAAsB;IACzE,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,IAAa,EAAE,MAAc;IACrE,MAAM,OAAO,GAA8B,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9D,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO;IAClC,MAAM,IAAI,GAAuB,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,wEAAwE;IACxE,oEAAoE;IACpE,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC/C,QAAQ,IAAI,CAAC,CAAC;IACd,IAAI,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACxB,2EAA2E;IAC3E,4EAA4E;IAC5E,eAAe,CAAC;QACd,IAAI,EAAE,UAAU;QAChB,EAAE,EAAE,QAAQ;QACZ,MAAM;QACN,IAAI,EAAE,IAAI,CAAC,MAAM;QACjB,oEAAoE;QACpE,wEAAwE;QACxE,iEAAiE;QACjE,OAAO,EAAE,IAAI,CAAC,MAAM,IAAI,sBAAsB,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE;KAC1E,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,MAAoB;IAChD,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,MAAM,GAAgB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAc,EAAW,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC;IACpG,MAAM,GAAG,GAA0B,MAAM,CAAC,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IAC9D,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACnC,SAAS,GAAG,IAAI,CAAC;IACjB,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAgB;IAC/C,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,CAAC,CAAC;IAC5B,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAc,EAAW,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC;AACjF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IAC7B,MAAM,IAAI,GAA4B,IAAI,GAAG,EAAE,CAAC;IAChD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAc,EAAkB,EAAE;QACtD,MAAM,OAAO,GAAW,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACtD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC5B,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;IAClF,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB;IAClC,IAAI,CAAC,SAAS,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7C,SAAS,GAAG,KAAK,CAAC;IAClB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,aAAa;IAC3B,IAAI,GAAG,IAAI,CAAC;IACZ,SAAS,GAAG,KAAK,CAAC;IAClB,QAAQ,GAAG,CAAC,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,OAAO;QACL,EAAE,EAAE,QAAQ;QACZ,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;QACtB,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,sBAAsB,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE;KAC/E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Registers the adapters. Called once, when the engine is created.
3
+ */
4
+ export declare function answerAdapters_register(): void;
@@ -0,0 +1,106 @@
1
+ /**
2
+ * @file What each listing's rows are, for numbering.
3
+ *
4
+ * One adapter per model kind, registered once. A listing that has no adapter
5
+ * simply has no numbers, which is the honest default: a model whose rows
6
+ * nobody has said how to name cannot be acted on by index.
7
+ *
8
+ * @module
9
+ */
10
+ import path from 'path';
11
+ import { patientAddress_of } from '@fnndsc/menu';
12
+ import { answerAdapter_register } from './answer.js';
13
+ /**
14
+ * Registers the adapters. Called once, when the engine is created.
15
+ */
16
+ export function answerAdapters_register() {
17
+ // A file listing's rows are paths, in the order the listing rendered them,
18
+ // flattened across targets the way `ls a b` prints them.
19
+ answerAdapter_register('fs.listing', (data) => {
20
+ if (!Array.isArray(data))
21
+ return null;
22
+ const rows = [];
23
+ for (const listing of data) {
24
+ if (listing === null || typeof listing !== 'object' || !Array.isArray(listing.items))
25
+ continue;
26
+ for (const item of listing.items) {
27
+ rows.push({
28
+ kind: item.type === 'dir' ? 'DIR' : 'FIL',
29
+ values: [path.posix.join(listing.path, item.name)],
30
+ label: item.name,
31
+ });
32
+ }
33
+ }
34
+ return rows;
35
+ });
36
+ // A PACS answer numbers its PATIENTS, its STUDIES and its SERIES, each in
37
+ // its own sequence. A patient hands over every series of every study of
38
+ // theirs, a study hands over its series — what the surface's GATHER on
39
+ // each hands over — so `pull @PAT001` and `gather add @STD001` act on the
40
+ // whole of it, while `@SER003` names one series. A patient the PACS
41
+ // answered nothing for has nothing to hand and wears no number.
42
+ answerAdapter_register('pacs.query', (data) => {
43
+ const model = data;
44
+ if (model === null || !Array.isArray(model.studies))
45
+ return null;
46
+ const rows = [];
47
+ // An answer that names its patients is taken at its word; one that does
48
+ // not (a single question, an older daemon) has a patient for every
49
+ // study's patient, in the studies' order — the same rows the surface
50
+ // derives, so the numbers land on them.
51
+ const patients = Array.isArray(model.patients) && model.patients.length > 0
52
+ ? model.patients
53
+ : model.studies.reduce((seen, study) => {
54
+ if (!seen.some((one) => one.patientId === study.patientId)) {
55
+ seen.push({ patientId: study.patientId, ...(study.patientName !== undefined ? { patientName: study.patientName } : {}) });
56
+ }
57
+ return seen;
58
+ }, []);
59
+ for (const patient of patients) {
60
+ const theirs = model.studies.filter((study) => study.patientId === patient.patientId && (patient.server === undefined || study.server === undefined || study.server === patient.server));
61
+ const seriesPaths = theirs
62
+ .flatMap((study) => (Array.isArray(study.series) ? study.series : []))
63
+ .map((one) => one.vfsPath)
64
+ .filter((one) => typeof one === 'string');
65
+ if (seriesPaths.length === 0)
66
+ continue;
67
+ rows.push({ kind: 'PAT', address: patientAddress_of(patient), values: seriesPaths, label: patient.patientName || patient.patientId });
68
+ }
69
+ for (const study of model.studies) {
70
+ const series = Array.isArray(study.series) ? study.series : [];
71
+ const seriesPaths = series
72
+ .map((one) => one.vfsPath)
73
+ .filter((one) => typeof one === 'string');
74
+ if (typeof study.vfsPath === 'string') {
75
+ rows.push({
76
+ kind: 'STD',
77
+ // The study's own path leads, as the address a surface matches on;
78
+ // its series follow, as what a verb is handed.
79
+ values: [study.vfsPath, ...seriesPaths],
80
+ label: study.description || 'study',
81
+ });
82
+ }
83
+ for (const one of series) {
84
+ if (typeof one.vfsPath !== 'string')
85
+ continue;
86
+ rows.push({ kind: 'SER', values: [one.vfsPath], label: one.description || one.modality || 'series' });
87
+ }
88
+ }
89
+ return rows;
90
+ });
91
+ // The cohort's rows are its members, which is what makes `gather remove @2`
92
+ // read the same way as every other numbered act.
93
+ answerAdapter_register('gather.cohort', (data) => {
94
+ const state = data;
95
+ if (state === null || !Array.isArray(state.series))
96
+ return null;
97
+ return state.series
98
+ .filter((member) => typeof member.vfsPath === 'string')
99
+ .map((member) => ({
100
+ kind: member.kind === 'dir' ? 'DIR' : member.kind === 'file' ? 'FIL' : 'SER',
101
+ values: [member.vfsPath],
102
+ label: member.description ?? path.posix.basename(member.vfsPath),
103
+ }));
104
+ });
105
+ }
106
+ //# sourceMappingURL=answerAdapters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"answerAdapters.js","sourceRoot":"","sources":["../../src/session/answerAdapters.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @file What a pronoun in a manifest refers to.
3
+ *
4
+ * A workflow says "process what I just gathered" and "check the feed that
5
+ * made", which means something in the session has to remember what the last
6
+ * act produced. These are not new state: they are the addresses the kernel
7
+ * already handed back, kept for the length of the session so a later line
8
+ * can name them without the operator copying an id out of a readout.
9
+ *
10
+ * Deliberately small and deliberately not persisted. A pronoun refers to
11
+ * what THIS session did; a manifest replayed in a new session refers to
12
+ * what that session does, which is the only reading that can be right.
13
+ *
14
+ * @module
15
+ */
16
+ /**
17
+ * Notes the feed work just landed in.
18
+ *
19
+ * @param id - The feed's id.
20
+ */
21
+ export declare function recentFeed_note(id: number): void;
22
+ /**
23
+ * The feed the session most recently worked in.
24
+ *
25
+ * @returns The feed id, or null when this session has made none.
26
+ */
27
+ export declare function recentFeed_get(): number | null;
28
+ /**
29
+ * Notes the runs just scheduled.
30
+ *
31
+ * @param ids - The plugin instance ids, in the order they were scheduled.
32
+ */
33
+ export declare function recentRuns_note(ids: number[]): void;
34
+ /**
35
+ * The runs the session most recently scheduled.
36
+ *
37
+ * @returns The instance ids, empty when this session has scheduled none.
38
+ */
39
+ export declare function recentRuns_get(): number[];
40
+ /**
41
+ * Notes where a run's output will land.
42
+ *
43
+ * This is what makes a chain expressible: the next act works on what the
44
+ * last one produced, and only the kernel knows where CUBE put it.
45
+ *
46
+ * @param place - The run's output directory.
47
+ */
48
+ export declare function recentRunPlace_note(place: string): void;
49
+ /**
50
+ * Where the session's most recent run writes.
51
+ *
52
+ * @returns The output directory, or null when this session has run nothing.
53
+ */
54
+ export declare function recentRunPlace_get(): string | null;
55
+ /**
56
+ * Notes where a PACS answer was written.
57
+ *
58
+ * @param path - The query's projection path.
59
+ */
60
+ export declare function recentQuery_note(path: string): void;
61
+ /**
62
+ * Where the session's most recent PACS answer lives.
63
+ *
64
+ * @returns The query path, or null when this session has asked nothing.
65
+ */
66
+ export declare function recentQuery_get(): string | null;
67
+ /** Forgets everything, for a test that needs a session with no history. */
68
+ export declare function recent_forget(): void;
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @file What a pronoun in a manifest refers to.
3
+ *
4
+ * A workflow says "process what I just gathered" and "check the feed that
5
+ * made", which means something in the session has to remember what the last
6
+ * act produced. These are not new state: they are the addresses the kernel
7
+ * already handed back, kept for the length of the session so a later line
8
+ * can name them without the operator copying an id out of a readout.
9
+ *
10
+ * Deliberately small and deliberately not persisted. A pronoun refers to
11
+ * what THIS session did; a manifest replayed in a new session refers to
12
+ * what that session does, which is the only reading that can be right.
13
+ *
14
+ * @module
15
+ */
16
+ /** The feed the session most recently created work in. */
17
+ let feedID = null;
18
+ /** The runs the session most recently scheduled. */
19
+ let instanceIDs = [];
20
+ /** The PACS query the session most recently asked. */
21
+ let queryPath = null;
22
+ /** Where the session's most recent run writes its output. */
23
+ let runPlace = null;
24
+ /**
25
+ * Notes the feed work just landed in.
26
+ *
27
+ * @param id - The feed's id.
28
+ */
29
+ export function recentFeed_note(id) {
30
+ feedID = id;
31
+ }
32
+ /**
33
+ * The feed the session most recently worked in.
34
+ *
35
+ * @returns The feed id, or null when this session has made none.
36
+ */
37
+ export function recentFeed_get() {
38
+ return feedID;
39
+ }
40
+ /**
41
+ * Notes the runs just scheduled.
42
+ *
43
+ * @param ids - The plugin instance ids, in the order they were scheduled.
44
+ */
45
+ export function recentRuns_note(ids) {
46
+ if (ids.length > 0)
47
+ instanceIDs = [...ids];
48
+ }
49
+ /**
50
+ * The runs the session most recently scheduled.
51
+ *
52
+ * @returns The instance ids, empty when this session has scheduled none.
53
+ */
54
+ export function recentRuns_get() {
55
+ return [...instanceIDs];
56
+ }
57
+ /**
58
+ * Notes where a run's output will land.
59
+ *
60
+ * This is what makes a chain expressible: the next act works on what the
61
+ * last one produced, and only the kernel knows where CUBE put it.
62
+ *
63
+ * @param place - The run's output directory.
64
+ */
65
+ export function recentRunPlace_note(place) {
66
+ runPlace = place;
67
+ }
68
+ /**
69
+ * Where the session's most recent run writes.
70
+ *
71
+ * @returns The output directory, or null when this session has run nothing.
72
+ */
73
+ export function recentRunPlace_get() {
74
+ return runPlace;
75
+ }
76
+ /**
77
+ * Notes where a PACS answer was written.
78
+ *
79
+ * @param path - The query's projection path.
80
+ */
81
+ export function recentQuery_note(path) {
82
+ queryPath = path;
83
+ }
84
+ /**
85
+ * Where the session's most recent PACS answer lives.
86
+ *
87
+ * @returns The query path, or null when this session has asked nothing.
88
+ */
89
+ export function recentQuery_get() {
90
+ return queryPath;
91
+ }
92
+ /** Forgets everything, for a test that needs a session with no history. */
93
+ export function recent_forget() {
94
+ feedID = null;
95
+ instanceIDs = [];
96
+ queryPath = null;
97
+ runPlace = null;
98
+ }
99
+ //# sourceMappingURL=recent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recent.js","sourceRoot":"","sources":["../../src/session/recent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,0DAA0D;AAC1D,IAAI,MAAM,GAAkB,IAAI,CAAC;AACjC,oDAAoD;AACpD,IAAI,WAAW,GAAa,EAAE,CAAC;AAC/B,sDAAsD;AACtD,IAAI,SAAS,GAAkB,IAAI,CAAC;AACpC,6DAA6D;AAC7D,IAAI,QAAQ,GAAkB,IAAI,CAAC;AAEnC;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,EAAU;IACxC,MAAM,GAAG,EAAE,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAa;IAC3C,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;QAAE,WAAW,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,CAAC,GAAG,WAAW,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,QAAQ,GAAG,KAAK,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,SAAS,GAAG,IAAI,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,IAAI,CAAC;IACd,WAAW,GAAG,EAAE,CAAC;IACjB,SAAS,GAAG,IAAI,CAAC;IACjB,QAAQ,GAAG,IAAI,CAAC;AAClB,CAAC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @file Recording what a session did, as a manifest.
3
+ *
4
+ * The workflows worth sharing are the fiddly ones nobody will retype
5
+ * correctly. A recorder is how one gets written: the operator does the work
6
+ * once — typing, or pressing on a surface, which is the same thing by law —
7
+ * and the lines they ran come back as a file someone else can play.
8
+ *
9
+ * A recording is a TRANSCRIPT, faithful to what happened. It does not invent
10
+ * expectations: a file that guessed at assertions would be a fiction, and
11
+ * adding `expect` lines is the author's act, the one that turns a recording
12
+ * into a test.
13
+ *
14
+ * @module
15
+ */
16
+ /** What a recording is doing. */
17
+ export interface RecorderState {
18
+ /** Where it will be written, or null when nothing is recording. */
19
+ target: string | null;
20
+ /** How many lines it holds. */
21
+ lines: number;
22
+ /** How long it has been running. */
23
+ elapsedMs: number;
24
+ }
25
+ /**
26
+ * Begins a recording.
27
+ *
28
+ * @param path - Where the manifest will be written.
29
+ */
30
+ export declare function recorder_start(path: string): void;
31
+ /**
32
+ * Notes a line the session ran.
33
+ *
34
+ * Lines about recording itself are never captured — a manifest that starts
35
+ * and stops a recording when played is a machine that films its own camera —
36
+ * and neither are the lines a played manifest runs, which are already in the
37
+ * file being played.
38
+ *
39
+ * @param line - The line, as it was run.
40
+ */
41
+ export declare function recorder_note(line: string): void;
42
+ /** Stops capturing while a manifest plays its own lines. */
43
+ export declare function recorder_mute(): void;
44
+ /** Resumes capturing after a played manifest finishes. */
45
+ export declare function recorder_unmute(): void;
46
+ /**
47
+ * Ends the recording.
48
+ *
49
+ * @returns Where it was recording and what it captured, or null when nothing was.
50
+ */
51
+ export declare function recorder_stop(): {
52
+ target: string;
53
+ lines: string[];
54
+ elapsedMs: number;
55
+ } | null;
56
+ /**
57
+ * What the recorder is doing.
58
+ *
59
+ * @returns The current state.
60
+ */
61
+ export declare function recorder_state(): RecorderState;
@@ -0,0 +1,95 @@
1
+ /**
2
+ * @file Recording what a session did, as a manifest.
3
+ *
4
+ * The workflows worth sharing are the fiddly ones nobody will retype
5
+ * correctly. A recorder is how one gets written: the operator does the work
6
+ * once — typing, or pressing on a surface, which is the same thing by law —
7
+ * and the lines they ran come back as a file someone else can play.
8
+ *
9
+ * A recording is a TRANSCRIPT, faithful to what happened. It does not invent
10
+ * expectations: a file that guessed at assertions would be a fiction, and
11
+ * adding `expect` lines is the author's act, the one that turns a recording
12
+ * into a test.
13
+ *
14
+ * @module
15
+ */
16
+ /** Where the recording will be written, or null when nothing is recording. */
17
+ let target = null;
18
+ /** The lines captured so far, in the order they ran. */
19
+ let captured = [];
20
+ /** When the recording started. */
21
+ let startedAt = 0;
22
+ /** Depth of work that must not be captured: a played manifest's own lines. */
23
+ let muted = 0;
24
+ /**
25
+ * Begins a recording.
26
+ *
27
+ * @param path - Where the manifest will be written.
28
+ */
29
+ export function recorder_start(path) {
30
+ target = path;
31
+ captured = [];
32
+ startedAt = Date.now();
33
+ muted = 0;
34
+ }
35
+ /**
36
+ * Notes a line the session ran.
37
+ *
38
+ * Lines about recording itself are never captured — a manifest that starts
39
+ * and stops a recording when played is a machine that films its own camera —
40
+ * and neither are the lines a played manifest runs, which are already in the
41
+ * file being played.
42
+ *
43
+ * @param line - The line, as it was run.
44
+ */
45
+ export function recorder_note(line) {
46
+ if (target === null || muted > 0)
47
+ return;
48
+ const trimmed = line.trim();
49
+ if (trimmed.length === 0)
50
+ return;
51
+ const verb = trimmed.split(/\s+/)[0];
52
+ if (verb === 'record' || verb === 'play')
53
+ return;
54
+ captured.push(trimmed);
55
+ }
56
+ /** Stops capturing while a manifest plays its own lines. */
57
+ export function recorder_mute() {
58
+ muted += 1;
59
+ }
60
+ /** Resumes capturing after a played manifest finishes. */
61
+ export function recorder_unmute() {
62
+ if (muted > 0)
63
+ muted -= 1;
64
+ }
65
+ /**
66
+ * Ends the recording.
67
+ *
68
+ * @returns Where it was recording and what it captured, or null when nothing was.
69
+ */
70
+ export function recorder_stop() {
71
+ if (target === null)
72
+ return null;
73
+ const held = {
74
+ target,
75
+ lines: [...captured],
76
+ elapsedMs: Date.now() - startedAt,
77
+ };
78
+ target = null;
79
+ captured = [];
80
+ startedAt = 0;
81
+ return held;
82
+ }
83
+ /**
84
+ * What the recorder is doing.
85
+ *
86
+ * @returns The current state.
87
+ */
88
+ export function recorder_state() {
89
+ return {
90
+ target,
91
+ lines: captured.length,
92
+ elapsedMs: target === null ? 0 : Date.now() - startedAt,
93
+ };
94
+ }
95
+ //# sourceMappingURL=recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.js","sourceRoot":"","sources":["../../src/session/recorder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,8EAA8E;AAC9E,IAAI,MAAM,GAAkB,IAAI,CAAC;AACjC,wDAAwD;AACxD,IAAI,QAAQ,GAAa,EAAE,CAAC;AAC5B,kCAAkC;AAClC,IAAI,SAAS,GAAW,CAAC,CAAC;AAC1B,8EAA8E;AAC9E,IAAI,KAAK,GAAW,CAAC,CAAC;AAYtB;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,GAAG,IAAI,CAAC;IACd,QAAQ,GAAG,EAAE,CAAC;IACd,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,KAAK,GAAG,CAAC,CAAC;AACZ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO;IACzC,MAAM,OAAO,GAAW,IAAI,CAAC,IAAI,EAAE,CAAC;IACpC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IACjC,MAAM,IAAI,GAAW,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO;IACjD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,aAAa;IAC3B,KAAK,IAAI,CAAC,CAAC;AACb,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,eAAe;IAC7B,IAAI,KAAK,GAAG,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,IAAI,GAA2D;QACnE,MAAM;QACN,KAAK,EAAE,CAAC,GAAG,QAAQ,CAAC;QACpB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;KAClC,CAAC;IACF,MAAM,GAAG,IAAI,CAAC;IACd,QAAQ,GAAG,EAAE,CAAC;IACd,SAAS,GAAG,CAAC,CAAC;IACd,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,MAAM;QACN,KAAK,EAAE,QAAQ,CAAC,MAAM;QACtB,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;KACxD,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fnndsc/brasa",
3
- "version": "0.23.2",
3
+ "version": "0.25.0",
4
4
  "description": "BRASA Runs Abstracted Shell Actions - the hostable ChRIS shell engine (kernel)",
5
5
  "repository": {
6
6
  "type": "git",
@@ -43,15 +43,15 @@
43
43
  "author": "FNNDSC <dev@babyMRI.org>",
44
44
  "license": "MIT",
45
45
  "dependencies": {
46
- "@fnndsc/chili": "^3.6.6",
47
- "@fnndsc/cumin": "^3.22.1",
48
- "@fnndsc/salsa": "^3.18.1",
46
+ "@fnndsc/chili": "^3.6.7",
47
+ "@fnndsc/cumin": "^3.23.1",
48
+ "@fnndsc/salsa": "^3.18.2",
49
49
  "chalk": "^4.1.2",
50
50
  "cli-highlight": "^2.1.11",
51
51
  "js-yaml": "^4.1.0",
52
52
  "minimatch": "^10.1.1",
53
53
  "ws": "^8.21.0",
54
- "@fnndsc/menu": "^0.9.0"
54
+ "@fnndsc/menu": "^0.11.0"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@types/jest": "^30.0.0",