@fnndsc/chili 3.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +113 -0
- package/dist/chefs/chefs.d.ts +15 -0
- package/dist/chefs/chefs.js +195 -0
- package/dist/commands/compute/fields.d.ts +6 -0
- package/dist/commands/compute/fields.js +13 -0
- package/dist/commands/compute/list.d.ts +19 -0
- package/dist/commands/compute/list.js +20 -0
- package/dist/commands/connect/login.d.ts +16 -0
- package/dist/commands/connect/login.js +18 -0
- package/dist/commands/connect/logout.d.ts +6 -0
- package/dist/commands/connect/logout.js +16 -0
- package/dist/commands/feed/comments.d.ts +41 -0
- package/dist/commands/feed/comments.js +45 -0
- package/dist/commands/feed/create.d.ts +13 -0
- package/dist/commands/feed/create.js +40 -0
- package/dist/commands/feed/note.d.ts +21 -0
- package/dist/commands/feed/note.js +24 -0
- package/dist/commands/feeds/delete.d.ts +14 -0
- package/dist/commands/feeds/delete.js +34 -0
- package/dist/commands/feeds/fields.d.ts +6 -0
- package/dist/commands/feeds/fields.js +17 -0
- package/dist/commands/feeds/list.d.ts +17 -0
- package/dist/commands/feeds/list.js +38 -0
- package/dist/commands/feeds/share.d.ts +17 -0
- package/dist/commands/feeds/share.js +19 -0
- package/dist/commands/file/view.d.ts +8 -0
- package/dist/commands/file/view.js +25 -0
- package/dist/commands/files/delete.d.ts +16 -0
- package/dist/commands/files/delete.js +36 -0
- package/dist/commands/files/fields.d.ts +7 -0
- package/dist/commands/files/fields.js +18 -0
- package/dist/commands/files/list.d.ts +11 -0
- package/dist/commands/files/list.js +23 -0
- package/dist/commands/fs/cat.d.ts +15 -0
- package/dist/commands/fs/cat.js +26 -0
- package/dist/commands/fs/cp.d.ts +17 -0
- package/dist/commands/fs/cp.js +26 -0
- package/dist/commands/fs/create.d.ts +15 -0
- package/dist/commands/fs/create.js +83 -0
- package/dist/commands/fs/download.d.ts +25 -0
- package/dist/commands/fs/download.js +235 -0
- package/dist/commands/fs/edit.d.ts +16 -0
- package/dist/commands/fs/edit.js +25 -0
- package/dist/commands/fs/ls.d.ts +18 -0
- package/dist/commands/fs/ls.js +142 -0
- package/dist/commands/fs/mkdir.d.ts +8 -0
- package/dist/commands/fs/mkdir.js +21 -0
- package/dist/commands/fs/mv.d.ts +13 -0
- package/dist/commands/fs/mv.js +73 -0
- package/dist/commands/fs/rm.d.ts +24 -0
- package/dist/commands/fs/rm.js +108 -0
- package/dist/commands/fs/touch.d.ts +16 -0
- package/dist/commands/fs/touch.js +62 -0
- package/dist/commands/fs/upload.d.ts +55 -0
- package/dist/commands/fs/upload.js +221 -0
- package/dist/commands/groups/fields.d.ts +6 -0
- package/dist/commands/groups/fields.js +13 -0
- package/dist/commands/groups/list.d.ts +16 -0
- package/dist/commands/groups/list.js +26 -0
- package/dist/commands/man/doc.d.ts +16 -0
- package/dist/commands/man/doc.js +32 -0
- package/dist/commands/man/topics.d.ts +6 -0
- package/dist/commands/man/topics.js +27 -0
- package/dist/commands/pipeline/fields.d.ts +6 -0
- package/dist/commands/pipeline/fields.js +13 -0
- package/dist/commands/pipeline/run.d.ts +18 -0
- package/dist/commands/pipeline/run.js +33 -0
- package/dist/commands/plugin/readme.d.ts +14 -0
- package/dist/commands/plugin/readme.js +49 -0
- package/dist/commands/plugin/run.d.ts +10 -0
- package/dist/commands/plugin/run.js +29 -0
- package/dist/commands/plugin/search.d.ts +7 -0
- package/dist/commands/plugin/search.js +18 -0
- package/dist/commands/plugininstances/fields.d.ts +6 -0
- package/dist/commands/plugininstances/fields.js +13 -0
- package/dist/commands/plugininstances/list.d.ts +16 -0
- package/dist/commands/plugininstances/list.js +26 -0
- package/dist/commands/pluginmetas/fields.d.ts +6 -0
- package/dist/commands/pluginmetas/fields.js +13 -0
- package/dist/commands/pluginmetas/list.d.ts +16 -0
- package/dist/commands/pluginmetas/list.js +26 -0
- package/dist/commands/plugins/add.d.ts +34 -0
- package/dist/commands/plugins/add.js +374 -0
- package/dist/commands/plugins/delete.d.ts +14 -0
- package/dist/commands/plugins/delete.js +34 -0
- package/dist/commands/plugins/fields.d.ts +6 -0
- package/dist/commands/plugins/fields.js +17 -0
- package/dist/commands/plugins/list.d.ts +17 -0
- package/dist/commands/plugins/list.js +40 -0
- package/dist/commands/plugins/overview.d.ts +6 -0
- package/dist/commands/plugins/overview.js +17 -0
- package/dist/commands/store/list.d.ts +23 -0
- package/dist/commands/store/list.js +48 -0
- package/dist/commands/tags/fields.d.ts +6 -0
- package/dist/commands/tags/fields.js +13 -0
- package/dist/commands/tags/list.d.ts +16 -0
- package/dist/commands/tags/list.js +26 -0
- package/dist/commands/workflows/fields.d.ts +6 -0
- package/dist/commands/workflows/fields.js +13 -0
- package/dist/commands/workflows/list.d.ts +16 -0
- package/dist/commands/workflows/list.js +26 -0
- package/dist/config/colorConfig.d.ts +56 -0
- package/dist/config/colorConfig.js +161 -0
- package/dist/connect/connectHandler.d.ts +15 -0
- package/dist/connect/connectHandler.js +48 -0
- package/dist/context/contextCommand.d.ts +13 -0
- package/dist/context/contextCommand.js +193 -0
- package/dist/controllers/baseController.d.ts +43 -0
- package/dist/controllers/baseController.js +67 -0
- package/dist/controllers/feedController.d.ts +35 -0
- package/dist/controllers/feedController.js +53 -0
- package/dist/controllers/fileController.d.ts +56 -0
- package/dist/controllers/fileController.js +93 -0
- package/dist/controllers/pluginContextController.d.ts +24 -0
- package/dist/controllers/pluginContextController.js +49 -0
- package/dist/controllers/pluginController.d.ts +70 -0
- package/dist/controllers/pluginController.js +98 -0
- package/dist/controllers/pluginMetaController.d.ts +41 -0
- package/dist/controllers/pluginMetaController.js +52 -0
- package/dist/feeds/feedHandler.d.ts +64 -0
- package/dist/feeds/feedHandler.js +203 -0
- package/dist/filesystem/fileGroupHandler.d.ts +92 -0
- package/dist/filesystem/fileGroupHandler.js +318 -0
- package/dist/filesystem/filesystemHandler.d.ts +12 -0
- package/dist/filesystem/filesystemHandler.js +135 -0
- package/dist/filesystem/inodeCommand.d.ts +12 -0
- package/dist/filesystem/inodeCommand.js +37 -0
- package/dist/handlers/baseGroupHandler.d.ts +103 -0
- package/dist/handlers/baseGroupHandler.js +342 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +239 -0
- package/dist/lfs/lfs.d.ts +25 -0
- package/dist/lfs/lfs.js +74 -0
- package/dist/man/man.d.ts +15 -0
- package/dist/man/man.js +31 -0
- package/dist/man/renderer.d.ts +26 -0
- package/dist/man/renderer.js +187 -0
- package/dist/models/feed.d.ts +18 -0
- package/dist/models/feed.js +8 -0
- package/dist/models/listing.d.ts +33 -0
- package/dist/models/listing.js +9 -0
- package/dist/models/plugin.d.ts +27 -0
- package/dist/models/plugin.js +1 -0
- package/dist/models/resource.d.ts +39 -0
- package/dist/models/resource.js +9 -0
- package/dist/pacs/pacsQueryHandler.d.ts +55 -0
- package/dist/pacs/pacsQueryHandler.js +196 -0
- package/dist/pacs/pacsQueryPayload.d.ts +19 -0
- package/dist/pacs/pacsQueryPayload.js +44 -0
- package/dist/pacs/pacsResultRender.d.ts +20 -0
- package/dist/pacs/pacsResultRender.js +141 -0
- package/dist/pacs/pacsRetrieveHandler.d.ts +87 -0
- package/dist/pacs/pacsRetrieveHandler.js +272 -0
- package/dist/pacs/pacsServerHandler.d.ts +15 -0
- package/dist/pacs/pacsServerHandler.js +32 -0
- package/dist/path/pathCommand.d.ts +64 -0
- package/dist/path/pathCommand.js +805 -0
- package/dist/path/pathMapper.d.ts +189 -0
- package/dist/path/pathMapper.js +382 -0
- package/dist/plugins/pluginGroupHandler.d.ts +42 -0
- package/dist/plugins/pluginGroupHandler.js +90 -0
- package/dist/plugins/pluginHandler.d.ts +87 -0
- package/dist/plugins/pluginHandler.js +303 -0
- package/dist/plugins/pluginMetaHandler.d.ts +21 -0
- package/dist/plugins/pluginMetaHandler.js +27 -0
- package/dist/screen/screen.d.ts +214 -0
- package/dist/screen/screen.js +478 -0
- package/dist/utils/admin_prompt.d.ts +42 -0
- package/dist/utils/admin_prompt.js +105 -0
- package/dist/utils/cli.d.ts +67 -0
- package/dist/utils/cli.js +112 -0
- package/dist/utils/docker.d.ts +74 -0
- package/dist/utils/docker.js +155 -0
- package/dist/utils/input_format.d.ts +77 -0
- package/dist/utils/input_format.js +135 -0
- package/dist/utils/sort.d.ts +29 -0
- package/dist/utils/sort.js +63 -0
- package/dist/utils/ui.d.ts +7 -0
- package/dist/utils/ui.js +26 -0
- package/dist/utils.d.ts +15 -0
- package/dist/utils.js +14 -0
- package/dist/views/compute.d.ts +17 -0
- package/dist/views/compute.js +40 -0
- package/dist/views/connect.d.ts +13 -0
- package/dist/views/connect.js +35 -0
- package/dist/views/feed.d.ts +44 -0
- package/dist/views/feed.js +110 -0
- package/dist/views/file.d.ts +25 -0
- package/dist/views/file.js +71 -0
- package/dist/views/fs.d.ts +51 -0
- package/dist/views/fs.js +105 -0
- package/dist/views/ls.d.ts +37 -0
- package/dist/views/ls.js +190 -0
- package/dist/views/plugin.d.ts +28 -0
- package/dist/views/plugin.js +71 -0
- package/dist/views/pluginParameters.d.ts +17 -0
- package/dist/views/pluginParameters.js +79 -0
- package/docs/00_intro.adoc +25 -0
- package/docs/01_setup.adoc +63 -0
- package/docs/02_context.adoc +128 -0
- package/docs/03_searchable.adoc +134 -0
- package/docs/10_everyday_examples.adoc +9 -0
- package/docs/11_upload_data.adoc +146 -0
- package/docs/12_create_a_feed.adoc +9 -0
- package/docs/13_run_a_plugin.adoc +271 -0
- package/docs/20_plugins.adoc +16 -0
- package/docs/21_pluginReadme.adoc +123 -0
- package/docs/30_filesystem.adoc +93 -0
- package/docs/31_fileops.adoc +51 -0
- package/docs/32_file_content.adoc +471 -0
- package/docs/_architecture.adoc +48 -0
- package/docs/_deepContext.adoc +84 -0
- package/docs/_roadmap.adoc +42 -0
- package/docs/_searchable.adoc +187 -0
- package/docs/_state.adoc +68 -0
- package/docs/pacs.adoc +101 -0
- package/docs/pathMapper.md +246 -0
- package/package.json +92 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
= Architecture of "Searchable" Strings
|
|
2
|
+
:toc: left
|
|
3
|
+
:toclevels: 3
|
|
4
|
+
|
|
5
|
+
The **"Searchable"** architecture is a core ChILI concept designed to unify resource identification and searching into a single, flexible string format. It allows users to specify resources by ID, Name, or complex query parameters seamlessly within CLI arguments and context strings.
|
|
6
|
+
|
|
7
|
+
As of version 0.4.1 of cumin, searchables are implemented as a formal `Searchable` class providing type safety, validation, and a unified API for all searchable operations.
|
|
8
|
+
|
|
9
|
+
== The Concept: "One String to Find Them All"
|
|
10
|
+
|
|
11
|
+
In a traditional REST API, fetching a resource by ID (`GET /plugins/14/`) is distinct from searching for resources (`GET /plugins/?name=pl-dircopy`). The Searchable concept blurs this line for the CLI user.
|
|
12
|
+
|
|
13
|
+
A "Searchable" string is an input argument that the system automatically interprets as either:
|
|
14
|
+
1. **A Direct ID/Name**: `"14"`, `"pl-dircopy"`
|
|
15
|
+
2. **An Explicit Query**: `"name_exact:pl-dircopy"`, `"version:1.0.2, min_creation_date:2023-01-01"`
|
|
16
|
+
|
|
17
|
+
== Syntax Specification
|
|
18
|
+
|
|
19
|
+
The explicit syntax is a comma-separated list of key-value pairs:
|
|
20
|
+
|
|
21
|
+
`"key1: value1, key2: value2, ..."`
|
|
22
|
+
|
|
23
|
+
* **Keys**: Correspond directly to the Django filter fields supported by the ChRIS API (e.g., `name`, `name_exact`, `id`, `min_creation_date`).
|
|
24
|
+
* **Values**: The values to search for.
|
|
25
|
+
* **Separator**: A colon (`:`) separates key and value. A comma (`,`) separates pairs.
|
|
26
|
+
|
|
27
|
+
=== Batch Operations (`++` Separator)
|
|
28
|
+
|
|
29
|
+
For commands that support batch operations (such as `delete`), multiple searchables can be combined using the `++` separator:
|
|
30
|
+
|
|
31
|
+
`"searchable1++searchable2++searchable3"`
|
|
32
|
+
|
|
33
|
+
Each searchable is processed independently. For example:
|
|
34
|
+
|
|
35
|
+
[source,bash]
|
|
36
|
+
----
|
|
37
|
+
chili plugins delete "id:77++id:33++name:pl-test"
|
|
38
|
+
----
|
|
39
|
+
|
|
40
|
+
This command will:
|
|
41
|
+
1. Resolve `id:77` and delete plugin 77
|
|
42
|
+
2. Resolve `id:33` and delete plugin 33
|
|
43
|
+
3. Resolve `name:pl-test` and delete matching plugin(s)
|
|
44
|
+
|
|
45
|
+
The implementation splits on `++` and iterates through each part (`pluginHandler.ts:83`).
|
|
46
|
+
|
|
47
|
+
== Implementation Mechanism
|
|
48
|
+
|
|
49
|
+
The logic resides in the `Searchable` class (`cumin/src/utils/searchable.ts`) which integrates with the existing parsing utilities (`cumin/src/utils/keypair.ts`) and ChRIS plugin operations (`cumin/src/plugins/chrisPlugins.ts`).
|
|
50
|
+
|
|
51
|
+
=== The Searchable Class
|
|
52
|
+
|
|
53
|
+
The `Searchable` class encapsulates all searchable logic in a type-safe, testable module:
|
|
54
|
+
|
|
55
|
+
[source,typescript]
|
|
56
|
+
----
|
|
57
|
+
import { Searchable } from '@fnndsc/cumin';
|
|
58
|
+
|
|
59
|
+
// Auto-detect type
|
|
60
|
+
const s1 = Searchable.from("pl-dircopy"); // simple
|
|
61
|
+
const s2 = Searchable.from("name:pl-dircopy"); // compound
|
|
62
|
+
const s3 = Searchable.from("id:77++id:33"); // batch
|
|
63
|
+
|
|
64
|
+
// Explicit constructors
|
|
65
|
+
const simple = Searchable.simple("pl-dircopy");
|
|
66
|
+
const compound = Searchable.compound("name:foo,version:1.0");
|
|
67
|
+
const batch = Searchable.batch("id:77++id:33");
|
|
68
|
+
|
|
69
|
+
// Type checking
|
|
70
|
+
if (s1.isSimple()) { /* ... */ }
|
|
71
|
+
if (s2.isCompound()) { /* ... */ }
|
|
72
|
+
if (s3.isBatch()) { /* ... */ }
|
|
73
|
+
|
|
74
|
+
// Convert to query parameters
|
|
75
|
+
const params = s2.toQueryParams(); // { name: "pl-dircopy" }
|
|
76
|
+
|
|
77
|
+
// Split batch into individual searchables
|
|
78
|
+
const parts = s3.toBatchSearchables(); // [Searchable, Searchable]
|
|
79
|
+
|
|
80
|
+
// Validate
|
|
81
|
+
if (s1.validate()) { /* searchable is valid */ }
|
|
82
|
+
----
|
|
83
|
+
|
|
84
|
+
All ChRIS resource methods accept either strings or `Searchable` objects, providing backward compatibility while enabling explicit type safety when desired.
|
|
85
|
+
|
|
86
|
+
=== 1. Type Detection (`Searchable.from`)
|
|
87
|
+
|
|
88
|
+
When a string is passed to `Searchable.from()`, the system automatically detects the type:
|
|
89
|
+
|
|
90
|
+
* **Batch Mode**: If the string contains `++`, it is treated as a batch searchable.
|
|
91
|
+
* Input: `"id:77++id:33"` -> Type: `batch`
|
|
92
|
+
* **Compound Mode**: If the string contains a colon (`:`) but no `++`, it is treated as a key-value search.
|
|
93
|
+
* Input: `"id:14"` -> Type: `compound`
|
|
94
|
+
* **Simple Mode**: If the string contains neither `:` nor `++`, it is assumed to be a plain name.
|
|
95
|
+
* Input: `"pl-dircopy"` -> Type: `simple`, normalized to `"name: pl-dircopy"`
|
|
96
|
+
|
|
97
|
+
For backward compatibility, `pluginString_makeSearchable()` still exists but is deprecated in favor of the `Searchable` class.
|
|
98
|
+
|
|
99
|
+
=== 2. Parsing (`Searchable.toQueryParams`)
|
|
100
|
+
|
|
101
|
+
The Searchable instance provides parsed key-value pairs via `toQueryParams()`:
|
|
102
|
+
|
|
103
|
+
[source,typescript]
|
|
104
|
+
----
|
|
105
|
+
const searchable = Searchable.from("name: foo, version: 1.0");
|
|
106
|
+
const params = searchable.toQueryParams();
|
|
107
|
+
// Result: { name: "foo", version: "1.0" }
|
|
108
|
+
----
|
|
109
|
+
|
|
110
|
+
Internally, this uses the existing `keyPairString_parse()` utility for compound searchables.
|
|
111
|
+
|
|
112
|
+
=== 3. Normalization (`Searchable.toNormalizedString`)
|
|
113
|
+
|
|
114
|
+
Before passing to the API, the searchable is normalized:
|
|
115
|
+
|
|
116
|
+
[source,typescript]
|
|
117
|
+
----
|
|
118
|
+
const s1 = Searchable.simple("pl-dircopy");
|
|
119
|
+
s1.toNormalizedString(); // "name: pl-dircopy"
|
|
120
|
+
|
|
121
|
+
const s2 = Searchable.compound("name:foo,version:1.0");
|
|
122
|
+
s2.toNormalizedString(); // "name:foo,version:1.0" (unchanged)
|
|
123
|
+
----
|
|
124
|
+
|
|
125
|
+
This normalized string is then passed through `options_toParams()`, merged with pagination options, and sent to the `@fnndsc/chrisapi` client as a standard HTTP Query String:
|
|
126
|
+
|
|
127
|
+
`GET /api/v1/endpoint/?name=foo&version=1.0`
|
|
128
|
+
|
|
129
|
+
=== 4. Resolution
|
|
130
|
+
|
|
131
|
+
The API returns a list of matching objects. The system then extracts the relevant identifier (typically `id`) from the first result (or handles errors if multiple/zero results are found).
|
|
132
|
+
|
|
133
|
+
==== Multiple Match Warning
|
|
134
|
+
|
|
135
|
+
When a searchable resolves to more than one result, the system:
|
|
136
|
+
|
|
137
|
+
1. Issues a warning: `"Multiple plugins conformed to '<searchable>'"`
|
|
138
|
+
2. Continues execution using the **first match**
|
|
139
|
+
3. Pushes the warning to the error stack for user visibility
|
|
140
|
+
|
|
141
|
+
[source,typescript]
|
|
142
|
+
----
|
|
143
|
+
// From chrisPlugins.ts:214-219
|
|
144
|
+
if (pluginList.hits.length > 1) {
|
|
145
|
+
errorStack.stack_push(
|
|
146
|
+
"warning",
|
|
147
|
+
`Multiple plugins conformed to "${searchable}.`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
----
|
|
151
|
+
|
|
152
|
+
This behavior helps users identify when their search criteria are too broad. Best practice is to use more specific searchables (e.g., `name_exact` instead of `name`, or include version constraints) to ensure deterministic results.
|
|
153
|
+
|
|
154
|
+
== Integration Points
|
|
155
|
+
|
|
156
|
+
The Searchable concept is integrated deeply into two main areas:
|
|
157
|
+
|
|
158
|
+
=== Resource Commands
|
|
159
|
+
|
|
160
|
+
Commands that operate on resources accept searchable strings as arguments.
|
|
161
|
+
|
|
162
|
+
[source,bash]
|
|
163
|
+
----
|
|
164
|
+
chili plugin run "name_exact:pl-dircopy, version:2.0.1"
|
|
165
|
+
----
|
|
166
|
+
|
|
167
|
+
=== Context Initialization
|
|
168
|
+
|
|
169
|
+
The Context parser (`chrisContextURL_parse` in `cumin`) supports searchables within the query string of a context URI.
|
|
170
|
+
|
|
171
|
+
[source,bash]
|
|
172
|
+
----
|
|
173
|
+
chili "user@http://cube.org?plugin=name_exact:pl-dircopy" ...
|
|
174
|
+
----
|
|
175
|
+
|
|
176
|
+
When the parser encounters a key like `plugin` with a value containing a colon (`:`), it triggers the full resolution logic (API call -> Search -> Resolve ID) *before* setting the persistent session state.
|
|
177
|
+
|
|
178
|
+
== Data Flow Summary
|
|
179
|
+
|
|
180
|
+
1. **User Input**: `"name_exact:foo"`
|
|
181
|
+
2. **CLI Parser**: Passes string to Resolver.
|
|
182
|
+
3. **Resolver**: calls `keyPairString_parse("name_exact:foo")`.
|
|
183
|
+
4. **Object**: `{ name_exact: "foo" }`.
|
|
184
|
+
5. **API Client**: `GET .../?name_exact=foo`.
|
|
185
|
+
6. **Response**: `[{ id: 42, name: "foo", ... }]`.
|
|
186
|
+
7. **Resolution**: Returns ID `42`.
|
|
187
|
+
8. **Action**: Command operates on Resource ID `42`.
|
package/docs/_state.adoc
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
= ChILI Context & State Management
|
|
2
|
+
:toc: left
|
|
3
|
+
:toclevels: 2
|
|
4
|
+
|
|
5
|
+
The ChRIS Interactive Line Interface (ChILI) implements a robust "Context" system to provide a stateful, shell-like experience over the stateless ChRIS REST API. This design allows the CLI to remember "who you are," "where you are," and "what you are doing" across multiple sessions, users, and CUBE instances.
|
|
6
|
+
|
|
7
|
+
== The Concept: "Where am I and Who am I?"
|
|
8
|
+
|
|
9
|
+
The "Context" is a state management mechanism that persists critical session information. It allows a user to navigate the ChRIS filesystem, switch between different user identities, or connect to different ChRIS backends (CUBEs) without needing to re-authenticate or re-specify parameters for every command.
|
|
10
|
+
|
|
11
|
+
It answers three fundamental questions:
|
|
12
|
+
1. **Who is acting?** (Current User)
|
|
13
|
+
2. **Where are they acting?** (Current ChRIS URL/CUBE instance)
|
|
14
|
+
3. **What are they working on?** (Current Folder, Feed, or Plugin)
|
|
15
|
+
|
|
16
|
+
== Data Structure Hierarchy
|
|
17
|
+
|
|
18
|
+
The context is organized hierarchically to support multi-tenancy and multi-backend operations.
|
|
19
|
+
|
|
20
|
+
* **`FullContext`**: The root state object. It maintains a registry of all known users.
|
|
21
|
+
** **`UserContext`**: For each specific user (e.g., "alice", "bob"), it stores a map of all CUBE URLs they have interacted with.
|
|
22
|
+
*** **`URLContext`**: The leaf node of the state tree. For a specific *User* at a specific *CUBE URL*, it persists the following session details:
|
|
23
|
+
**** `folder`: The current working directory path (e.g., `/home/alice/data`).
|
|
24
|
+
**** `feed`: The ID of the active feed.
|
|
25
|
+
**** `plugin`: The ID of the active plugin instance.
|
|
26
|
+
**** `token`: The active authentication token for this session.
|
|
27
|
+
|
|
28
|
+
== Persistence
|
|
29
|
+
|
|
30
|
+
This state is not ephemeral. It is persisted to the local filesystem (typically in `~/.chris/` or a similar configuration directory managed by `cumin`).
|
|
31
|
+
|
|
32
|
+
* **Session Continuity**: You can set a working directory (`chili context set --ChRISfolder /tmp`), close your terminal, open a new one days later, and `chili chefs ls` will still list the contents of `/tmp`.
|
|
33
|
+
* **Multi-Tasking**: You can seamlessly switch contexts. For example, you can work as user "dev" on a local testing CUBE, then switch context to user "prod_admin" on a remote production CUBE, and ChILI will instantly recall the correct tokens and working directories for each environment.
|
|
34
|
+
|
|
35
|
+
== CLI Usage
|
|
36
|
+
|
|
37
|
+
The context is managed via the `chili context` command group.
|
|
38
|
+
|
|
39
|
+
=== Viewing State
|
|
40
|
+
|
|
41
|
+
[source,bash]
|
|
42
|
+
----
|
|
43
|
+
# View the current active context (User, URL, Folder, etc.)
|
|
44
|
+
chili context get
|
|
45
|
+
|
|
46
|
+
# View details for a specific context aspect
|
|
47
|
+
chili context get --ChRISuser
|
|
48
|
+
chili context get --ChRISurl
|
|
49
|
+
|
|
50
|
+
# View the entire stored state tree (all users, all URLs)
|
|
51
|
+
chili context get --full
|
|
52
|
+
----
|
|
53
|
+
|
|
54
|
+
=== Modifying State
|
|
55
|
+
|
|
56
|
+
[source,bash]
|
|
57
|
+
----
|
|
58
|
+
# Switch active user (if previously authenticated)
|
|
59
|
+
chili context set --ChRISuser alice
|
|
60
|
+
|
|
61
|
+
# Switch active CUBE instance
|
|
62
|
+
chili context set --ChRISurl https://chris.example.org/api/v1/
|
|
63
|
+
|
|
64
|
+
# Change current working directory (cd equivalent)
|
|
65
|
+
chili context set --ChRISfolder /home/alice/analysis/
|
|
66
|
+
----
|
|
67
|
+
|
|
68
|
+
This architecture effectively turns the stateless ChRIS API into a stateful, interactive environment, significantly reducing the friction of repetitive tasks and complex workflows.
|
package/docs/pacs.adoc
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
= PACS Commands in Chili
|
|
2
|
+
:toc:
|
|
3
|
+
:toclevels: 2
|
|
4
|
+
:sectnums:
|
|
5
|
+
|
|
6
|
+
== Overview
|
|
7
|
+
|
|
8
|
+
`chili` is the CLI layer where PACS interactions become user-facing commands. It handles context management, tabular output, and decoding/presentation of PACS query results, while delegating business logic to `salsa`/`cumin`. The goal is to give an operator a concise, line-friendly workflow: pick a PACS server, launch a query, and view its structured results (studies with nested series) without touching raw JSON.
|
|
9
|
+
|
|
10
|
+
== PACS Servers
|
|
11
|
+
|
|
12
|
+
- `chili pacsservers list [--identifier <id>] [--limit <n>] [--offset <n>]`
|
|
13
|
+
- `chili pacsservers fieldslist`
|
|
14
|
+
|
|
15
|
+
== PACS Context
|
|
16
|
+
|
|
17
|
+
- `chili context set --pacsserver <id|identifier>` (stores PACS server target)
|
|
18
|
+
- `chili context get --pacsserver` (displays current PACS server)
|
|
19
|
+
- Inline override on commands: `--pacsserver <id|identifier>`
|
|
20
|
+
|
|
21
|
+
== PACS Queries
|
|
22
|
+
|
|
23
|
+
- **Create**: `chili pacsqueries create "<query>" [--title <title>] [--description <desc>] [--pacsserver <pacs>]`
|
|
24
|
+
- `<query>` can be JSON (`{"PatientID":"12345"}`) or comma-separated `key:value` pairs (`PatientID:12345,StudyDate:20251003`).
|
|
25
|
+
- On success prints: `Created PACS query id=<ID> status=<status> pacs=<pacs> title="<title>"`.
|
|
26
|
+
- **List**: `chili pacsqueries list [--pacsserver <pacs>] [--fields ...] [--table|--csv]`
|
|
27
|
+
- Filters to current/override PACS server. Use `fieldslist` to discover columns.
|
|
28
|
+
- **Fields**: `chili pacsqueries fieldslist`
|
|
29
|
+
- **Decode result**: `chili pacsqueries decode <queryId> [--raw]`
|
|
30
|
+
- Decodes the query `result` payload (base64 → zlib/gzip → JSON/text).
|
|
31
|
+
- Renders studies with nested series when JSON is present.
|
|
32
|
+
- `--raw` prints the decoded JSON prettified.
|
|
33
|
+
|
|
34
|
+
== PACS Retrieves
|
|
35
|
+
|
|
36
|
+
- **Pull**: `chili pacsretrieve pull <queryId>`
|
|
37
|
+
- Triggers a PACS retrieve to pull DICOM data from PACS to ChRIS.
|
|
38
|
+
- Creates a retrieve record and initiates the external service.
|
|
39
|
+
- Prints: `Created PACS retrieve id=<ID> query=<queryId> status=<status>`.
|
|
40
|
+
- **Report**: `chili pacsretrieve report <queryId>`
|
|
41
|
+
- Shows detailed status report with series-level progress.
|
|
42
|
+
- Displays studies, series descriptions, and file counts (`Pulling (X/Y images)`).
|
|
43
|
+
- Automatically detects completion when all series are pulled.
|
|
44
|
+
- Example output:
|
|
45
|
+
```
|
|
46
|
+
Query ID: 123
|
|
47
|
+
Retrieve ID: 456
|
|
48
|
+
Retrieve Status: Retrieving / Completed
|
|
49
|
+
|
|
50
|
+
Study 1
|
|
51
|
+
Description: XR-Wrist 3+ Views Left
|
|
52
|
+
PA: Pulled (1 images)
|
|
53
|
+
OBLIQUE: Pulling (50/220 images)
|
|
54
|
+
LATERAL: Pending (0/180 images)
|
|
55
|
+
```
|
|
56
|
+
- **Cancel**: `chili pacsretrieve cancel <retrieveId>`
|
|
57
|
+
- Cancels (deletes) an in-progress retrieve.
|
|
58
|
+
- Note: Partially-pulled data may remain in ChRIS.
|
|
59
|
+
|
|
60
|
+
== Typical Flow
|
|
61
|
+
|
|
62
|
+
=== Query Only
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
chili context set --pacsserver PACSDCM
|
|
66
|
+
chili pacsservers list --table
|
|
67
|
+
chili pacsqueries create "PatientID:4456554" --title "PID 4456554"
|
|
68
|
+
chili pacsqueries list --fields id,title,status,pacs_id,query
|
|
69
|
+
chili pacsqueries decode <id>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
=== Query + Retrieve with Monitoring
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# 1. Set PACS context
|
|
76
|
+
chili context set --pacsserver PACSDCM
|
|
77
|
+
|
|
78
|
+
# 2. Create query
|
|
79
|
+
chili pacsqueries create "PatientID:4456554" --title "Patient scan"
|
|
80
|
+
# Returns: Created PACS query id=123
|
|
81
|
+
|
|
82
|
+
# 3. See what's available on PACS
|
|
83
|
+
chili pacsqueries decode 123
|
|
84
|
+
|
|
85
|
+
# 4. Pull DICOM data to ChRIS
|
|
86
|
+
chili pacsretrieve pull 123
|
|
87
|
+
# Returns: Created PACS retrieve id=456
|
|
88
|
+
|
|
89
|
+
# 5. Monitor progress
|
|
90
|
+
chili pacsretrieve report 123
|
|
91
|
+
# Shows series-level status: Pending / Pulling / Pulled
|
|
92
|
+
|
|
93
|
+
# 6. Cancel if needed
|
|
94
|
+
chili pacsretrieve cancel 456
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
== Notes
|
|
98
|
+
|
|
99
|
+
- Commands rely on existing ChRIS auth/token; ensure `chili connect` is done.
|
|
100
|
+
- Decoding/parsing happens client-side; no changes to the PACS service.
|
|
101
|
+
- The CLI prints only at the presentation layer; underlying intents remain quiet for programmatic reuse.
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# PathMapper Implementation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `PathMapper` singleton class implements hierarchical path mapping from logical ChRIS paths to physical storage locations, with aggressive prefix caching to optimize repeated resolutions.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
### Problem Solved
|
|
10
|
+
|
|
11
|
+
**Before:** Every path resolution walked the entire tree from root, causing redundant API calls:
|
|
12
|
+
```
|
|
13
|
+
/home/user/public/feed_4 → 4 API calls
|
|
14
|
+
/home/user/public/feed_5 → 4 API calls (redundant!)
|
|
15
|
+
/home/user/public/feed_6 → 4 API calls (redundant!)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**After:** Hierarchical prefix caching eliminates redundant operations:
|
|
19
|
+
```
|
|
20
|
+
/home/user/public/feed_4 → 4 API calls (initial resolution)
|
|
21
|
+
/home/user/public/feed_5 → 1 API call (reuses cached prefix!)
|
|
22
|
+
/home/user/public/feed_6 → 1 API call (reuses cached prefix!)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Key Design Decisions
|
|
26
|
+
|
|
27
|
+
1. **Path-Level Caching**: Cache complete logical → physical mappings
|
|
28
|
+
2. **Incremental Resolution**: Find longest cached prefix, resolve only the suffix
|
|
29
|
+
3. **Intermediate Caching**: Cache every path segment for maximum reuse
|
|
30
|
+
4. **TTL-Based Expiration**: 30-second TTL balances freshness vs performance
|
|
31
|
+
5. **Singleton Pattern**: Single source of truth for all path mappings
|
|
32
|
+
|
|
33
|
+
## API
|
|
34
|
+
|
|
35
|
+
### Core Methods
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { pathMapper_get } from '@fnndsc/chili';
|
|
39
|
+
|
|
40
|
+
const mapper = pathMapper_get();
|
|
41
|
+
|
|
42
|
+
// Resolve logical path to physical location
|
|
43
|
+
const result = await mapper.logical_toPhysical('/home/user/public/feed_4');
|
|
44
|
+
if (result.ok) {
|
|
45
|
+
console.log(result.value); // '/SHARED/feed_4'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Invalidate cache when links change
|
|
49
|
+
mapper.cache_invalidate('/home/user/public');
|
|
50
|
+
|
|
51
|
+
// Clear all cached mappings
|
|
52
|
+
mapper.cache_clear();
|
|
53
|
+
|
|
54
|
+
// Get performance statistics
|
|
55
|
+
const stats = mapper.stats_get();
|
|
56
|
+
console.log(`Hit rate: ${stats.hitRate * 100}%`);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Statistics
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
interface CacheStats {
|
|
63
|
+
hits: number; // Number of cache hits
|
|
64
|
+
misses: number; // Number of cache misses
|
|
65
|
+
size: number; // Current cache size
|
|
66
|
+
hitRate: number; // Hit rate (0-1)
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Performance Characteristics
|
|
71
|
+
|
|
72
|
+
### Time Complexity
|
|
73
|
+
|
|
74
|
+
| Operation | Without Cache | With Cache | Improvement |
|
|
75
|
+
|-----------|---------------|------------|-------------|
|
|
76
|
+
| First resolution | O(depth) | O(depth) | - |
|
|
77
|
+
| Repeated resolution | O(depth) | **O(1)** | ✅ |
|
|
78
|
+
| Prefix reuse | O(depth) | **O(suffix)** | ✅ |
|
|
79
|
+
|
|
80
|
+
### Real-World Example
|
|
81
|
+
|
|
82
|
+
Resolving 1000 files in `/home/user/feeds/feed_123/files/`:
|
|
83
|
+
|
|
84
|
+
**Without caching:**
|
|
85
|
+
- 1000 × 6 components = 6,000 API calls
|
|
86
|
+
|
|
87
|
+
**With PathMapper:**
|
|
88
|
+
- First file: 6 API calls (cache miss)
|
|
89
|
+
- Remaining 999 files: 1 API call each (prefix reuse)
|
|
90
|
+
- **Total: 1,005 API calls (83% reduction)**
|
|
91
|
+
|
|
92
|
+
## Implementation Details
|
|
93
|
+
|
|
94
|
+
### Resolution Algorithm
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
logical_toPhysical(logicalPath):
|
|
98
|
+
1. Check exact cache hit → return if found
|
|
99
|
+
2. Find longest cached prefix
|
|
100
|
+
3. Resolve only the uncached suffix
|
|
101
|
+
4. Cache all intermediate segments
|
|
102
|
+
5. Return final physical path
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Example Resolution
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
Input: '/home/user/public/feed_4'
|
|
109
|
+
Cache state: { '/home/user/public': '/SHARED' }
|
|
110
|
+
|
|
111
|
+
Step 1: Check exact cache for '/home/user/public/feed_4' → miss
|
|
112
|
+
Step 2: Find longest prefix:
|
|
113
|
+
- Check '/home/user/public/feed_4' → miss
|
|
114
|
+
- Check '/home/user/public' → HIT! ✓
|
|
115
|
+
Step 3: Resolve suffix 'feed_4' from '/SHARED':
|
|
116
|
+
- Check if '/SHARED/feed_4' is a link → no
|
|
117
|
+
Step 4: Cache '/home/user/public/feed_4' → '/SHARED/feed_4'
|
|
118
|
+
Step 5: Return '/SHARED/feed_4'
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Cache Management
|
|
122
|
+
|
|
123
|
+
### When to Invalidate
|
|
124
|
+
|
|
125
|
+
Call `cache_invalidate()` when:
|
|
126
|
+
- Links are created: `mapper.cache_invalidate(parentDir)`
|
|
127
|
+
- Links are deleted: `mapper.cache_invalidate(parentDir)`
|
|
128
|
+
- Links are modified: `mapper.cache_invalidate(linkPath)`
|
|
129
|
+
|
|
130
|
+
### TTL Behavior
|
|
131
|
+
|
|
132
|
+
- Default TTL: 30 seconds
|
|
133
|
+
- Expired entries are removed on access
|
|
134
|
+
- Balances freshness vs performance
|
|
135
|
+
|
|
136
|
+
### Memory Considerations
|
|
137
|
+
|
|
138
|
+
- Cache grows with unique paths accessed
|
|
139
|
+
- Each entry: ~100 bytes (path strings + metadata)
|
|
140
|
+
- 10,000 paths ≈ 1 MB memory
|
|
141
|
+
- TTL ensures bounded growth
|
|
142
|
+
|
|
143
|
+
## Testing
|
|
144
|
+
|
|
145
|
+
Comprehensive test suite with 31 tests covering:
|
|
146
|
+
|
|
147
|
+
✅ Singleton pattern enforcement
|
|
148
|
+
✅ Basic path resolution
|
|
149
|
+
✅ Link resolution (single and multiple)
|
|
150
|
+
✅ Caching behavior
|
|
151
|
+
✅ **Prefix reuse optimization** (key feature)
|
|
152
|
+
✅ Cache invalidation
|
|
153
|
+
✅ TTL expiration
|
|
154
|
+
✅ Error handling
|
|
155
|
+
✅ Statistics tracking
|
|
156
|
+
✅ Edge cases (malformed paths, deep nesting, etc.)
|
|
157
|
+
|
|
158
|
+
Run tests:
|
|
159
|
+
```bash
|
|
160
|
+
npm test -- pathMapper.test.ts
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Integration
|
|
164
|
+
|
|
165
|
+
### Automatic Usage
|
|
166
|
+
|
|
167
|
+
The existing `logical_toPhysical()` function now delegates to PathMapper:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
// Old code continues to work unchanged
|
|
171
|
+
import { logical_toPhysical } from '@fnndsc/chili';
|
|
172
|
+
|
|
173
|
+
const result = await logical_toPhysical('/home/user/files');
|
|
174
|
+
// Automatically uses PathMapper under the hood
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Direct Usage
|
|
178
|
+
|
|
179
|
+
For advanced scenarios requiring cache control:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { pathMapper_get } from '@fnndsc/chili';
|
|
183
|
+
|
|
184
|
+
const mapper = pathMapper_get();
|
|
185
|
+
|
|
186
|
+
// Batch operations with cache awareness
|
|
187
|
+
for (const file of manyFiles) {
|
|
188
|
+
const result = await mapper.logical_toPhysical(file.logicalPath);
|
|
189
|
+
// ...
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Check performance
|
|
193
|
+
const stats = mapper.stats_get();
|
|
194
|
+
console.log(`Resolved ${stats.hits + stats.misses} paths with ${stats.hitRate * 100}% hit rate`);
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Migration Notes
|
|
198
|
+
|
|
199
|
+
### Backward Compatibility
|
|
200
|
+
|
|
201
|
+
✅ **Fully backward compatible**
|
|
202
|
+
- Existing `logical_toPhysical()` calls work unchanged
|
|
203
|
+
- Same function signature and return type
|
|
204
|
+
- No breaking changes
|
|
205
|
+
|
|
206
|
+
### Performance Impact
|
|
207
|
+
|
|
208
|
+
- **First access**: Identical to previous implementation
|
|
209
|
+
- **Subsequent accesses**: Up to 83% faster for common patterns
|
|
210
|
+
- **Memory overhead**: ~1 MB per 10,000 unique paths
|
|
211
|
+
|
|
212
|
+
### Future Enhancements
|
|
213
|
+
|
|
214
|
+
Potential improvements:
|
|
215
|
+
1. **LRU eviction**: Limit cache size with least-recently-used eviction
|
|
216
|
+
2. **Persistent cache**: Serialize cache to disk across sessions
|
|
217
|
+
3. **Metrics export**: Export detailed performance metrics
|
|
218
|
+
4. **Link prefetching**: Proactively fetch links for common paths
|
|
219
|
+
|
|
220
|
+
## Files
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
chili/
|
|
224
|
+
├── src/
|
|
225
|
+
│ ├── path/
|
|
226
|
+
│ │ └── pathMapper.ts # PathMapper implementation (new)
|
|
227
|
+
│ ├── utils/
|
|
228
|
+
│ │ └── cli.ts # Updated to use PathMapper
|
|
229
|
+
│ └── utils.ts # Exports PathMapper
|
|
230
|
+
├── tests/
|
|
231
|
+
│ └── pathMapper.test.ts # Comprehensive test suite (new)
|
|
232
|
+
└── docs/
|
|
233
|
+
└── pathMapper.md # This document
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## References
|
|
237
|
+
|
|
238
|
+
- Original implementation: `chili/src/utils/cli.ts` (lines 133-258, now replaced)
|
|
239
|
+
- Issue: Unacceptable lag in path resolution due to repeated tree walking
|
|
240
|
+
- Solution: Hierarchical prefix caching with singleton pattern
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
**Author:** Claude + User collaboration
|
|
245
|
+
**Date:** 2025-01-31
|
|
246
|
+
**Status:** ✅ Implemented and tested
|
package/package.json
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fnndsc/chili",
|
|
3
|
+
"version": "3.2.5",
|
|
4
|
+
"description": "ChILI handles Intelligent Line Interactions: A CLI and library for ChRIS, acting as the controller layer for business logic and user presentation.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/FNNDSC/chili.git"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/FNNDSC/chili#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/FNNDSC/chili/issues"
|
|
12
|
+
},
|
|
13
|
+
"main": "dist/index.js",
|
|
14
|
+
"types": "dist/index.d.ts",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": "./dist/index.js",
|
|
18
|
+
"./utils": "./dist/utils.js",
|
|
19
|
+
"./*": "./dist/*",
|
|
20
|
+
"./package.json": "./package.json"
|
|
21
|
+
},
|
|
22
|
+
"bin": {
|
|
23
|
+
"chili": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc && chmod +x ./dist/index.js",
|
|
27
|
+
"start": "node dist/index.js",
|
|
28
|
+
"test": "jest",
|
|
29
|
+
"test:coverage": "jest --coverage --coverageProvider=v8",
|
|
30
|
+
"clean": "rm -rf dist types fnndsc-chili*tgz",
|
|
31
|
+
"build:cumin": "cd ../cumin && npm run build",
|
|
32
|
+
"build:chili": "npm run clean && npm install && npm run build",
|
|
33
|
+
"build:all": "npm run build:cumin && npm run build:chili && npm run pack",
|
|
34
|
+
"pack": "npm pack",
|
|
35
|
+
"install:local": "npm i --ignore-scripts $(npm pack | tail -1)",
|
|
36
|
+
"deploy": "npm run build:all && npm run install:local"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist/**/*",
|
|
40
|
+
"docs/**/*"
|
|
41
|
+
],
|
|
42
|
+
"keywords": [
|
|
43
|
+
"chris",
|
|
44
|
+
"cli",
|
|
45
|
+
"repl"
|
|
46
|
+
],
|
|
47
|
+
"author": "FNNDSC <dev@babyMRI.org>",
|
|
48
|
+
"license": "MIT",
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@fnndsc/cumin": "^3.2.4",
|
|
51
|
+
"@fnndsc/salsa": "^3.2.4",
|
|
52
|
+
"@fortawesome/fontawesome-free": "^6.6.0",
|
|
53
|
+
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
|
54
|
+
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
|
55
|
+
"@mermaid-js/mermaid-cli": "^11.12.0",
|
|
56
|
+
"archy": "^1.0.0",
|
|
57
|
+
"asciidoctor": "^3.0.4",
|
|
58
|
+
"axios": "^1.6.0",
|
|
59
|
+
"chalk": "^4.1.2",
|
|
60
|
+
"cli-highlight": "^2.1.11",
|
|
61
|
+
"cli-progress": "^3.12.0",
|
|
62
|
+
"cli-table3": "^0.6.3",
|
|
63
|
+
"commander": "^12.1.0",
|
|
64
|
+
"figlet": "^1.7.0",
|
|
65
|
+
"js-yaml": "^4.1.0",
|
|
66
|
+
"marked": "^9.1.0",
|
|
67
|
+
"marked-terminal": "^6.1.0",
|
|
68
|
+
"node-fetch": "^3.3.2",
|
|
69
|
+
"omelette": "^0.4.17",
|
|
70
|
+
"open": "^10.1.0",
|
|
71
|
+
"table": "^6.8.1"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@types/archy": "^0.0.36",
|
|
75
|
+
"@types/cli-progress": "^3.11.6",
|
|
76
|
+
"@types/figlet": "^1.5.8",
|
|
77
|
+
"@types/jest": "^30.0.0",
|
|
78
|
+
"@types/js-yaml": "^4.0.5",
|
|
79
|
+
"@types/marked-terminal": "^6.1.1",
|
|
80
|
+
"@types/node": "^24.10.1",
|
|
81
|
+
"@types/node-fetch": "^2.6.11",
|
|
82
|
+
"@types/omelette": "^0.4.4",
|
|
83
|
+
"jest": "^30.2.0",
|
|
84
|
+
"ts-jest": "^29.4.5",
|
|
85
|
+
"typescript": "^5.5.2"
|
|
86
|
+
},
|
|
87
|
+
"overrides": {
|
|
88
|
+
"glob": "^10.0.0",
|
|
89
|
+
"inflight": "npm:@aashutoshrathi/word-wrap@^1.2.6",
|
|
90
|
+
"node-domexception": "npm:undici-types@^6.19.8"
|
|
91
|
+
}
|
|
92
|
+
}
|