Repository navigation
Conversation
…ndow-ingest BIDSvue's NeuroFlow work is now one PR (niivue/BIDSvue#18), the headless ingest that bidsvue-ingest runs; it is headed for main. The window's NeuroFlow mode, which the bidsvue tool and the crlab-ingest demo need, stays on the neuroflow/window-ingest branch for now. That branch carries both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks — this consolidation is much easier to review than #11–#15, and the window path is untouched. Before merging, could you address:
Nits: Follow-up issues, not blockers: a guard keeping |
`bun run neuroflow-ingest` runs the app's DICOM import (runImport and the post-pass) under Bun with no window and no user input, moves the BIDS root to <out>/bids, and writes the NeuroFlow handoff file and provenance line. This makes BIDSvue's ingest runnable as a NeuroFlow step, including from hosts that cannot wait on an app, such as NeuroFlow's MCP server. The window is unchanged. It takes a NeuroFlow session (context.json), a step of a workflow document (constants and inputs.* bindings), or plain flags. Settings come from flags, then the step inputs, then defaults: importer dcm2niix-reproin, subject, session, anonymize, shift_dates, save_derivatives, heuristic, config. Importers: dcm2niix-reproin, pet2bids, heudiconv, dcm2bids. Exit codes: 0 done, 1 import failed, 2 usage error. - $lib/neuroflow/contract: the session contract's file formats (context, handoff, provenance line), host-independent and unit-tested. - $lib/neuroflow/relocate: move the single BIDS root an import produced from the staging folder to <out>/bids; refuses several roots, a root outside staging, or an existing target. - $lib/neuroflow/headless: settings resolution, workflow step binding, runHeadlessIngest (refuses an existing <out>/bids before converting). - $lib/neuroflow/nodeExecutor: spawn-based ImportExecutor. Uses the bundled dcm2niix sidecar for the host triple, then $DCM2NIIX / PATH; keeps the Rust side's partial-success exit codes (8, 10) and the dcm2bids PATH shim. - The node:fs adapters move out of test-only files (mutate/testFs.ts -> mutate/nodeFs.ts, postpass/__testFs.ts -> postpass/nodeFs.ts) so the CLI can use them; exists() now stats and a non-recursive remove() deletes an empty directory, matching plugin-fs. Test imports updated. - scripts/neuroflow-ingest.ts and the package.json script; README section. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`bun run neuroflow-ingest -- --check` runs no import. It resolves dcm2niix the way an import does (--dcm2niix, $DCM2NIIX, the bundled sidecar, PATH), starts `dcm2niix -v`, and prints one JSON line: ready, the dcm2niix path and version, and any problems. Exit 0 when ready, 1 when not. NeuroFlow's Environment panel runs it as the tool's probe, so a missing or broken dcm2niix shows up before a run instead of as the run's first error, and NeuroFlow does not have to copy BIDSvue's dcm2niix lookup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- No undo, documented: the CLI's state dir is a temp dir deleted on exit (and on SIGINT/SIGTERM); README and headless.ts say a headless run is not journaled and how to redo one. - Refuse to start when <out>/bids or <out>/bidsvue-import exists; this is a runtime error (exit 1), not a usage error. - finalizeNewFileNoReplace copies with COPYFILE_EXCL and removes the source instead of link(), which exFAT and SMB don't support. - The package script runs svelte-kit sync first, so $lib resolves in a fresh clone. - A heuristic file from a session's context.json runs arbitrary Python via heudiconv; require --allow-heuristic-file for it. - Drop --workflow mode (and --step/--input/--state-dir). - Resolve a relative --dcm2niix path; accept UNC paths as absolute. - Share dcm2niix's partial-success exit codes between process.rs and nodeExecutor.ts through src/lib/import/dcm2niixPartialExit.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
e27c1ca to
b6a4dcd
Compare
|
Thanks for the careful review. All of it is addressed in b6a4dcd, which is rebased onto main.
Nits:
Follow-ups: I'm happy to open issues for the |
Replaces the five-PR stack #11–#15 with one PR: the command-line import from #15, plus only the parts of #11, #12 and #14 it needs. The window is unchanged.
What it does
bun run neuroflow-ingestruns BIDSvue's DICOM import (runImportand the post-pass) under Bun, with no window and no user input. It moves the BIDS root to<out>/bids, then writes the NeuroFlow handoff file and provenance line. A NeuroFlow workflow, or an AI agent through NeuroFlow's MCP server, can then run DICOM to BIDS unattended.--dcm2niix(a relative path is resolved) or$DCM2NIIX, then the bundled sidecar for the host, thenPATH.src/lib/import/dcm2niixPartialExit.json, whichprocess.rs(include_str!) and the CLI both read.--check: a preflight for NeuroFlow's Environment panel. It resolves dcm2niix as an import would, runsdcm2niix -v, prints one JSON line{ ready, dcm2niix, dcm2niixVersion, problems[] }, and exits 0 if ready, 1 if not.svelte-kit syncfirst, so$libresolves afterbun install.No undo
A headless run is not recorded in an
operations.logand cannot be reverted. Its state dir is a temp dir deleted when the run ends, including on SIGINT/SIGTERM. To redo a run, delete<out>. The CLI refuses to start if<out>/bidsor the staging folder<out>/bidsvue-importalready exists. This is documented inheadless.tsand the README.Heuristics run Python
heudiconv runs a heuristic
.pyas Python. A heuristic file from a session'scontext.jsonis refused unless--allow-heuristic-fileis passed. A file named with--heuristicon the command line, or a built-in name such asreproin, needs no flag. A dcm2bidsconfigis JSON, not code.Files
src/lib/neuroflow/contract.ts(from [1/5] feat(neuroflow): session contract and Rust commands #11): the session contract's file formats (context, handoff, provenance line). It has no host dependency and is unit-tested.src/lib/neuroflow/relocate.ts(from [2/5] feat(neuroflow): place an import's BIDS root at a chosen path #12): moves the single BIDS root an import produced from staging to<out>/bids. It refuses when there are several roots, a root is outside staging, or the target already exists.mutate/testFs.tsis renamed tomutate/nodeFs.ts, andpostpass/__testFs.tstopostpass/nodeFs.ts; the CLI uses them.exists()uses stat, and a non-recursiveremove()deletes an empty directory, both matching plugin-fs.finalizeNewFileNoReplacecopies withCOPYFILE_EXCLand then removes the source, so it works on exFAT and SMB, wherelink()fails.src/lib/neuroflow/headless.ts,nodeExecutor.ts,scripts/neuroflow-ingest.ts(from [5/5] feat(neuroflow): headless DICOM ingest CLI #15): the CLI, plus thepackage.jsonscript and a README section.src-tauri/src/process.rs: reads the partial-success table from the shared JSON instead of hardcoding it. Behavior is unchanged, and a unit test covers it.Testing
bun run lintandbun testpass (2472 tests, 0 fail).bun run typecheckpasses here except for main's@brainchop/mindgrabimport, which my local node_modules doesn't have yet.cargo testlocally because main's mindgrab sidecar isn't staged here; CI covers it.--checkreports ready with dcm2niix v1.0.20260724, and reportsready: falseand exits 1 withDCM2NIIX=./nope.<out>was refused with exit 1..bidsignorethat the window doesn't; I'll follow up on that separately.Window mode, for later
#13's window mode isn't in this PR. It's on the branch
neuroflow/window-ingest, which will be rebased onto this PR.🤖 Generated with Claude Code