nemar-cli 0.9.10-dev.2069 → 0.9.10-dev.2080

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 (2) hide show
  1. package/dist/index.js +4 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -102,7 +102,7 @@ ${u.dim(`eta: ${e.eta}`)}`:"";process.stderr.write(`${t}
102
102
  ${r} ${e.message}
103
103
  ${n}${i}
104
104
  ${t}
105
- `)}var LV=!1;var T_=k(()=>{Ke()});var VV;var UV=k(()=>{VV={name:"nemar-cli",version:"0.9.10-dev.2069",description:"CLI for NEMAR (Neuroelectromagnetic Data Archive and Tools Resource) dataset management",type:"module",main:"dist/index.js",bin:{nemar:"dist/index.js"},scripts:{dev:"bun run src/index.ts",build:"bun build src/index.ts --outdir dist --target bun --minify && sed '1s|#!/usr/bin/env node|#!/usr/bin/env bun|' dist/index.js > dist/index.js.tmp && mv dist/index.js.tmp dist/index.js",test:"bun test",lint:"biome check src/","lint:fix":"biome check --fix src/",format:"biome format --write src/",typecheck:"tsc --noEmit && tsc --noEmit -p backend",prepublishOnly:"bun run build",prepare:"husky",postinstall:"bun scripts/postinstall-check.mjs",deploy:"wrangler deploy",preview:"wrangler dev"},keywords:["nemar","bids","neuroimaging","eeg","emg","datalad","cli"],author:"NEMAR Team",license:"CC-BY-NC-ND-4.0",repository:{type:"git",url:"git+https://github.com/nemarOrg/nemar-cli.git"},bugs:{url:"https://github.com/nemarOrg/nemar-cli/issues"},homepage:"https://docs.nemar.org",engines:{bun:">=1.0.0"},files:["dist","scripts/postinstall-check.mjs","README.md","LICENSE"],dependencies:{chalk:"^5.3.0",commander:"^12.1.0",conf:"^13.0.1","fuse.js":"^7.1.0",inquirer:"^9.2.15",ora:"^8.0.1",zod:"^3.23.8"},"lint-staged":{"src/**/*.{ts,tsx}":["biome check --fix"],"backend/src/**/*.{ts,tsx}":["biome check --fix"]},devDependencies:{"@biomejs/biome":"1.9.4","@types/bcryptjs":"^3.0.0","@types/bun":"latest","@types/inquirer":"^9.0.7",ajv:"^8.20.0","ajv-formats":"^3.0.1",bcryptjs:"^3.0.3",husky:"^9.1.7","lint-staged":"^16.3.2",typescript:"^5.5.4",wrangler:"^4.70.0",yaml:"^2.8.4"}}});var Ao;var bm=k(()=>{UV();Ao=VV.version});function U(e){if(e instanceof Error)return e.message;return String(e)}var M,ko;var gr=k(()=>{M=class M extends Error{statusCode;details;step;constructor(e,t,r,n){super(t);this.statusCode=e;this.details=r;this.step=n;this.name="ApiError"}};ko=class ko extends M{mode;eta;constructor(e,t,r,n){super(503,t,n);this.mode=e;this.eta=r;this.name="MaintenanceError"}}});function zV(){if(process.env.TEST_API_URL)return process.env.TEST_API_URL;if(q_)return N_;return ht().apiUrl||N_}async function I(e,t={},r=!1,n){let i=`${zV()}${e}`,s={"Content-Type":"application/json","X-CLI-Version":Ao,...t.headers};if(r){let c=ht();if(!c.apiKey&&r===!0)throw new M(401,"Not authenticated. Run 'nemar auth login' first.");if(c.apiKey)s.Authorization=`Bearer ${c.apiKey}`}let o;try{o=await fetch(i,{...t,headers:s})}catch(c){throw new M(0,`Network error: Could not connect to ${zV()}`,{originalError:c instanceof Error?c.message:String(c)})}let a;try{a=await o.json()}catch{throw new M(o.status,`Invalid response from server (status ${o.status})`)}if(!o.ok){if(o.status===503&&(a.mode==="read-only"||a.mode==="full")){let c=typeof a.message==="string"?a.message:"NEMAR is in maintenance mode. Please retry shortly.",l=typeof a.eta==="string"?a.eta:null,d=new ko(a.mode,c,l,a.details);throw xm(d),d}throw new M(o.status,a.error||a.message||"Request failed",a.details,typeof a.step==="string"?a.step:void 0)}if(n){let c=n.safeParse(a);if(!c.success)throw new M(o.status,`Response for ${e} did not match the expected NEMAR contract`,{issues:c.error.issues});return c.data}return a}var N_="https://nemar-api-dev.sccn-org.workers.dev",q_;var Ps=k(()=>{ks();T_();bm();gr();q_=N_.includes("workers.dev")});async function HV(e,t){let r=new URLSearchParams;if(e)r.set("status",e);if(t)r.set("role",t);let n=r.toString()?`?${r.toString()}`:"";return I(`/admin/users${n}`,{},!0)}async function GV(e){return I(`/admin/approve/${e}`,{method:"POST"},!0)}async function WV(e){return I(`/admin/approve/by-id/${e}`,{method:"POST"},!0)}async function KV(e){return I(`/admin/revoke/${e}`,{method:"POST"},!0)}async function YV(e,t){return I(`/admin/users/${e}/role`,{method:"POST",body:JSON.stringify({role:t})},!0)}async function j_(e,t){return I(`/admin/datasets/${e}/visibility`,{method:"PATCH",body:JSON.stringify({visibility:t})},!0)}async function JV(e){return I(`/datasets/${e}/publish`,{method:"POST"},!0)}async function XV(e){return I(`/admin/datasets/${e}/ci`,{},!0)}async function Ri(e){return I(`/admin/datasets/${e}/ci`,{method:"POST"},!0)}async function M_(e){return I(`/admin/datasets/${e}/ci/validate`,{method:"POST"},!0)}async function B_(e){return I(`/admin/datasets/${e}/ci/sync`,{method:"POST"},!0)}async function QV(e,t){return I(`/admin/datasets/${e}/doi/concept`,{method:"POST",body:JSON.stringify(t)},!0)}async function dd(e){return I(`/admin/datasets/${e}/doi`,{},!0)}async function L_(e,t){return I(`/admin/datasets/${e}/doi/update`,{method:"POST",body:JSON.stringify(t)},!0)}async function ZV(e,t){return I(`/admin/datasets/${e}/withdraw`,{method:"POST",body:JSON.stringify({reason:t.reason,dry_run:t.dryRun})},!0)}async function ez(e,t){return I(`/admin/datasets/${e}/restore`,{method:"POST",body:JSON.stringify({dry_run:t.dryRun})},!0)}async function tz(e){return I(`/admin/datasets/${e}/reset`,{method:"POST"},!0)}async function rz(e,t=!1){return I(`/admin/datasets/${e}`,{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({force:t})},!0)}async function nz(e){return I("/admin/datasets/bulk-delete",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({dataset_ids:e})},!0)}async function iz(e){return I("/admin/datasets/import",{method:"POST",body:JSON.stringify(e)},!0)}async function sz(e){return I("/admin/datasets/exemplar",{method:"POST",body:JSON.stringify(e)},!0)}async function oz(e){return I(`/admin/datasets/${e}/exemplar/remint-dois`,{method:"POST"},!0)}async function U_(e,t){let r=new URLSearchParams;if(e)r.set("status",e);if(t!==void 0)r.set("blocklisted",t?"1":"0");let n=r.toString();return I(`/admin/imports${n?`?${n}`:""}`,{},!0)}async function az(e){return I(`/admin/imports/${e}/rollback`,{method:"POST"},!0)}async function cz(e){return I(`/admin/imports/${e}/retry`,{method:"POST"},!0)}async function V_(e){return I(`/admin/imports/${e}/verify`,{method:"POST"},!0)}async function uz(e){return I("/admin/imports/dispatch-cooldown",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({dataset_ids:e})},!0)}async function Oc(e,t){return I(`/admin/datasets/${e}/reindex`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t??{})},!0)}async function lz(e,t){return I("/admin/datasets/reindex/bulk",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({filter:e,...t??{}})},!0)}async function dz(e){let t=e?.limit??15;return I(`/admin/datasets/hed-sweep?limit=${encodeURIComponent(String(t))}`,{method:"POST",headers:{"Content-Type":"application/json"}},!0)}async function fz(){return I("/admin/datasets/hed-sweep?reset=1",{method:"POST",headers:{"Content-Type":"application/json"}},!0)}async function pz(e){let t=e?.limit??15,r=new URLSearchParams({limit:String(t)});if(e?.olderThan!=null)r.set("older-than",String(e.olderThan));if(e?.before!=null)r.set("before",e.before);return I(`/admin/datasets/data-integrity-sweep?${r.toString()}`,{method:"POST",headers:{"Content-Type":"application/json"}},!0)}async function mz(){return I("/admin/datasets/data-integrity-sweep?reset=1",{method:"POST",headers:{"Content-Type":"application/json"}},!0)}async function hz(e,t){let r=t?.write?"":"?dry_run=1";return I(`/admin/datasets/${e}/availability-report${r}`,{method:"POST",headers:{"Content-Type":"application/json"}},!0)}async function gz(e){let t=e?.limit??30,r=new URLSearchParams({limit:String(t)});if(e?.missingOnly)r.set("missing-only","1");return I(`/admin/datasets/availability-report-sweep?${r.toString()}`,{method:"POST",headers:{"Content-Type":"application/json"}},!0)}async function yz(){return I("/admin/datasets/availability-report-sweep?reset=1",{method:"POST",headers:{"Content-Type":"application/json"}},!0)}async function xz(e){let t=new URLSearchParams;if(e?.prefix)t.set("prefix",e.prefix);if(e?.visibility)t.set("visibility",e.visibility);if(e?.limit)t.set("limit",String(e.limit));let r=t.toString()?`?${t.toString()}`:"";return I(`/admin/fleet/drift${r}`,{},!0)}async function Ac(e,t){return I(`/admin/datasets/${e}/enforce`,{method:"POST",body:JSON.stringify({dry_run:t})},!0)}async function bz(e){return I("/admin/datasets/enforce/bulk",{method:"POST",body:JSON.stringify({prefix:e.prefix,visibility:e.visibility,limit:e.limit,dry_run:e.dryRun})},!0)}async function vz(e,t=!1){return I(`/admin/datasets/${e}/revalidate${t?"?force=true":""}`,{method:"POST"},!0)}async function _z(e){let t=e?`?user=${encodeURIComponent(e)}`:"";return I(`/admin/email-preferences${t}`,{},!0)}async function Dz(e,t){let r=t?`?user=${encodeURIComponent(t)}`:"";return I(`/admin/email-preferences${r}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)},!0)}async function z_(e){return I("/admin/notify",{method:"POST",body:JSON.stringify(e)},!0)}async function wz(){return I("/admin/summary/coverage",{},!0)}async function Ez(e,t,r){return I("/admin/manifest/dispatch",{method:"POST",body:JSON.stringify({dataset_id:e,version:t,skip_canary:r?.skipCanary??!1})},!0)}async function H_(e){return I("/admin/doctor/scan",{method:"POST",body:JSON.stringify({...e?.check&&{check:e.check},...e?.datasetId&&{dataset_id:e.datasetId}})},!0)}async function G_(e){return I("/admin/doctor/fix",{method:"POST",body:JSON.stringify({check:e.check,...e.datasetId&&{dataset_id:e.datasetId},...e.dryRun&&{dry_run:!0}})},!0)}var kc=k(()=>{Ps()});async function Zn(e,t){return I(`/datasets/${e}/upload-credentials`,{method:"POST",body:JSON.stringify({duration_seconds:t})},!0)}async function W_(e,t){return I(`/datasets/${e}/download-credentials`,{method:"POST",body:JSON.stringify({duration_seconds:t})},!0)}async function Sz(e){return I(`/admin/datasets/${e}/files`,{},!0)}async function $z(e){let t,r=0,n=[],i=!0;while(i){let s=await I(`/admin/datasets/${e}/s3-lock`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({continuation_token:t})},!0);if(r+=s.locked,s.failed?.length)n.push(...s.failed);if(i=s.hasMore,t=s.continuation_token,i&&!t)throw new M(500,"S3 lock paginated response missing continuation_token; aborting to avoid infinite loop")}return{locked:r,failed:n}}var Pc=k(()=>{Ps();gr()});async function _m(e){return I(`/datasets/${e}/ci/status`,{},!0)}async function Cz(e){return I(`/datasets/${e}/manifest`,{},!0)}async function Dm(e,t){return I(`/datasets/${e}/manifest/${t}`,{},!0)}function Fz(e){let t=e;if(!t.status)t.status="active";else if(!["active","archived","deleted"].includes(t.status))throw Error(`Invalid dataset status: ${t.status}`);if(!t.visibility)t.visibility="private";else if(!["public","private"].includes(t.visibility))throw Error(`Invalid dataset visibility: ${t.visibility}`);return t}async function Ic(e={}){let t=new URLSearchParams;if(e.mine)t.set("mine","true");if(e.search)t.set("search",e.search);if(e.modality)t.set("modality",e.modality);if(e.author)t.set("author",e.author);if(e.task)t.set("task",e.task);if(e.license)t.set("license",e.license);if(e.hasDoi)t.set("has_doi","true");if(e.hasHed)t.set("has_hed","1");if(e.dataComplete)t.set("data_complete","1");if(e.recent)t.set("recent",String(e.recent));if(e.sort)t.set("sort",e.sort);if(e.limit!=null)t.set("limit",String(e.limit));if(e.offset!=null)t.set("offset",String(e.offset));if(e.owner)t.set("owner",e.owner);let r=t.toString()?`?${t.toString()}`:"",n=await I(`/datasets${r}`,{},e.mine?!0:"optional");return n.datasets=n.datasets.map(Fz),n}async function Rz(e){return I(`/datasets/resolve/${e}`,{},"optional")}async function Oz(e,t={}){let r=new URLSearchParams({q:e});if(t.modality)r.set("modality",t.modality);if(t.limit)r.set("limit",String(t.limit));if(t.hasHed)r.set("has_hed","1");return I(`/datasets/search?${r.toString()}`,{},"optional")}async function gt(e){let t=await I(`/datasets/${e}`,{},"optional");return Fz(t.dataset)}async function Az(e){return I(`/datasets/${e}/versions`,{},!0)}async function wm(e){return I("/datasets",{method:"POST",body:JSON.stringify(e)},!0)}async function Em(e){return I(`/datasets/${e}/finalize`,{method:"POST"},!0)}async function K_(e){return I(`/datasets/${e}/request-access`,{method:"POST"},!0)}async function kz(e,t){let r=t?`?status=${t}`:"";return I(`/datasets/${e}/access-requests${r}`,{},!0)}async function Pz(e,t){return I(`/datasets/${e}/access-requests/${t}/approve`,{method:"POST"},!0)}async function Iz(e,t){return I(`/datasets/${e}/access-requests/${t}/deny`,{method:"POST"},!0)}async function Tz(e,t){return I(`/datasets/${e}/invite`,{method:"POST",body:JSON.stringify({username:t})},!0)}async function Nz(e){return I(`/datasets/${e}/collaborators`,{},!0)}async function qz(e,t){return I(`/admin/datasets/${e}/enrichment`,{method:"POST",body:JSON.stringify(t)},!0)}var vm;var Po=k(()=>{Ps();vm=/^\d{4}-\d{4}-\d{4}-\d{3}[\dX]$/});var Tc;var Uz=k(()=>{Tc=["ci_check","enrichment_check","s3_public_read","repo_public","tag_protect","doi_create","update_metadata","update_readme","create_tag","create_release","upload_to_zenodo","publish_doi","version_doi","s3_lock","sync_nemar","notify_user"]});async function Nc(e){return I(`/datasets/${e}/publish/request`,{method:"POST"},!0)}async function zz(e){return I(`/datasets/${e}/publish/status`,{},!0)}async function Hz(e){return I(`/datasets/${e}/publish/resend`,{method:"POST"},!0)}async function Gz(e){let t=e?`?status=${e}`:"";return I(`/admin/publish/requests${t}`,{},!0)}async function Wz(e,t){return I(`/admin/publish/${e}/deny`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({reason:t})},!0)}function A3e(e,t=[]){if(e){let r=Tc.indexOf(e);if(r>=0)return r+1}return Math.min(t.length+1,Tc.length)}function k3e(e){if(!(e instanceof M))return!1;if(e.statusCode===0)return!0;if(e.statusCode===429)return!0;if(e.statusCode>=500&&e.statusCode<600)return!0;if(e.statusCode===403&&/repository has been locked/i.test(e.message))return!0;return!1}async function qc(e,t=!1,r=!1,n=!1,i,s){let c,l,d=0,f=!1,m,p=t,g=[],y;function x(v,_,E,S){if(!s)return;s({step:v,stepIndex:A3e(v,_),stepTotal:Tc.length,s3LockLocked:E,s3LockTotal:S,s3LockResumed:v==="s3_lock"&&f?!0:void 0})}for(let v=1;v<=5;v++)try{let _,E=!0;do{if(_=await I(`/admin/publish/${e}/approve`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({resume:E?p:!0,sandbox:r,s3_lock_continuation_token:c,s3_lock_total:l,skip_ci_check:n})},!0),E=!1,_.step_results)g.push(..._.step_results);if(_.s3_lock_total!==void 0)l=_.s3_lock_total;if(_.s3_lock_batch_count!==void 0)d+=_.s3_lock_batch_count;let S=_.step??_.step_results?.[_.step_results.length-1]?.step;if(S&&(S!==m||S==="s3_lock"))x(S,_.steps_completed??[],S==="s3_lock"?d:void 0,S==="s3_lock"?l:void 0),m=S;if(_.hasMore&&_.s3_lock_continuation_token!==void 0)c=_.s3_lock_continuation_token;else break}while(_.hasMore);if(g.length>0)_.step_results=Vz(g);return _}catch(_){if(y=_,v===5||!k3e(_)){if(_ instanceof M&&g.length>0)_.stepResults=Vz(g);throw _}let S=_;if(i?.({attempt:v,maxAttempts:5,delayMs:1e4,step:S.step,error:S.message}),await new Promise((D)=>setTimeout(D,1e4)),p=!0,c!==void 0)f=!0}throw y}function Vz(e){let t=new Map;for(let r of e)t.set(r.step,r);return Array.from(t.values())}var fd=k(()=>{Uz();Ps();gr()});function Jz(e){X_=e}function Q_(){return X_}function pd(e){if(X_)process.stderr.write(`${e}
105
+ `)}var LV=!1;var T_=k(()=>{Ke()});var VV;var UV=k(()=>{VV={name:"nemar-cli",version:"0.9.10-dev.2080",description:"CLI for NEMAR (Neuroelectromagnetic Data Archive and Tools Resource) dataset management",type:"module",main:"dist/index.js",bin:{nemar:"dist/index.js"},scripts:{dev:"bun run src/index.ts",build:"bun build src/index.ts --outdir dist --target bun --minify && sed '1s|#!/usr/bin/env node|#!/usr/bin/env bun|' dist/index.js > dist/index.js.tmp && mv dist/index.js.tmp dist/index.js",test:"bun test",lint:"biome check src/","lint:fix":"biome check --fix src/",format:"biome format --write src/",typecheck:"tsc --noEmit && tsc --noEmit -p backend",prepublishOnly:"bun run build",prepare:"husky",postinstall:"bun scripts/postinstall-check.mjs",deploy:"wrangler deploy",preview:"wrangler dev"},keywords:["nemar","bids","neuroimaging","eeg","emg","datalad","cli"],author:"NEMAR Team",license:"CC-BY-NC-ND-4.0",repository:{type:"git",url:"git+https://github.com/nemarOrg/nemar-cli.git"},bugs:{url:"https://github.com/nemarOrg/nemar-cli/issues"},homepage:"https://docs.nemar.org",engines:{bun:">=1.0.0"},files:["dist","scripts/postinstall-check.mjs","README.md","LICENSE"],dependencies:{chalk:"^5.3.0",commander:"^12.1.0",conf:"^13.0.1","fuse.js":"^7.1.0",inquirer:"^9.2.15",ora:"^8.0.1",zod:"^3.23.8"},"lint-staged":{"src/**/*.{ts,tsx}":["biome check --fix"],"backend/src/**/*.{ts,tsx}":["biome check --fix"]},devDependencies:{"@biomejs/biome":"1.9.4","@types/bcryptjs":"^3.0.0","@types/bun":"latest","@types/inquirer":"^9.0.7",ajv:"^8.20.0","ajv-formats":"^3.0.1",bcryptjs:"^3.0.3",husky:"^9.1.7","lint-staged":"^16.3.2",typescript:"^5.5.4",wrangler:"^4.70.0",yaml:"^2.8.4"}}});var Ao;var bm=k(()=>{UV();Ao=VV.version});function U(e){if(e instanceof Error)return e.message;return String(e)}var M,ko;var gr=k(()=>{M=class M extends Error{statusCode;details;step;constructor(e,t,r,n){super(t);this.statusCode=e;this.details=r;this.step=n;this.name="ApiError"}};ko=class ko extends M{mode;eta;constructor(e,t,r,n){super(503,t,n);this.mode=e;this.eta=r;this.name="MaintenanceError"}}});function zV(){if(process.env.TEST_API_URL)return process.env.TEST_API_URL;if(q_)return N_;return ht().apiUrl||N_}async function I(e,t={},r=!1,n){let i=`${zV()}${e}`,s={"Content-Type":"application/json","X-CLI-Version":Ao,...t.headers};if(r){let c=ht();if(!c.apiKey&&r===!0)throw new M(401,"Not authenticated. Run 'nemar auth login' first.");if(c.apiKey)s.Authorization=`Bearer ${c.apiKey}`}let o;try{o=await fetch(i,{...t,headers:s})}catch(c){throw new M(0,`Network error: Could not connect to ${zV()}`,{originalError:c instanceof Error?c.message:String(c)})}let a;try{a=await o.json()}catch{throw new M(o.status,`Invalid response from server (status ${o.status})`)}if(!o.ok){if(o.status===503&&(a.mode==="read-only"||a.mode==="full")){let c=typeof a.message==="string"?a.message:"NEMAR is in maintenance mode. Please retry shortly.",l=typeof a.eta==="string"?a.eta:null,d=new ko(a.mode,c,l,a.details);throw xm(d),d}throw new M(o.status,a.error||a.message||"Request failed",a.details,typeof a.step==="string"?a.step:void 0)}if(n){let c=n.safeParse(a);if(!c.success)throw new M(o.status,`Response for ${e} did not match the expected NEMAR contract`,{issues:c.error.issues});return c.data}return a}var N_="https://nemar-api-dev.sccn-org.workers.dev",q_;var Ps=k(()=>{ks();T_();bm();gr();q_=N_.includes("workers.dev")});async function HV(e,t){let r=new URLSearchParams;if(e)r.set("status",e);if(t)r.set("role",t);let n=r.toString()?`?${r.toString()}`:"";return I(`/admin/users${n}`,{},!0)}async function GV(e){return I(`/admin/approve/${e}`,{method:"POST"},!0)}async function WV(e){return I(`/admin/approve/by-id/${e}`,{method:"POST"},!0)}async function KV(e){return I(`/admin/revoke/${e}`,{method:"POST"},!0)}async function YV(e,t){return I(`/admin/users/${e}/role`,{method:"POST",body:JSON.stringify({role:t})},!0)}async function j_(e,t){return I(`/admin/datasets/${e}/visibility`,{method:"PATCH",body:JSON.stringify({visibility:t})},!0)}async function JV(e){return I(`/datasets/${e}/publish`,{method:"POST"},!0)}async function XV(e){return I(`/admin/datasets/${e}/ci`,{},!0)}async function Ri(e){return I(`/admin/datasets/${e}/ci`,{method:"POST"},!0)}async function M_(e){return I(`/admin/datasets/${e}/ci/validate`,{method:"POST"},!0)}async function B_(e){return I(`/admin/datasets/${e}/ci/sync`,{method:"POST"},!0)}async function QV(e,t){return I(`/admin/datasets/${e}/doi/concept`,{method:"POST",body:JSON.stringify(t)},!0)}async function dd(e){return I(`/admin/datasets/${e}/doi`,{},!0)}async function L_(e,t){return I(`/admin/datasets/${e}/doi/update`,{method:"POST",body:JSON.stringify(t)},!0)}async function ZV(e,t){return I(`/admin/datasets/${e}/withdraw`,{method:"POST",body:JSON.stringify({reason:t.reason,dry_run:t.dryRun})},!0)}async function ez(e,t){return I(`/admin/datasets/${e}/restore`,{method:"POST",body:JSON.stringify({dry_run:t.dryRun})},!0)}async function tz(e){return I(`/admin/datasets/${e}/reset`,{method:"POST"},!0)}async function rz(e,t=!1){return I(`/admin/datasets/${e}`,{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({force:t})},!0)}async function nz(e){return I("/admin/datasets/bulk-delete",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({dataset_ids:e})},!0)}async function iz(e){return I("/admin/datasets/import",{method:"POST",body:JSON.stringify(e)},!0)}async function sz(e){return I("/admin/datasets/exemplar",{method:"POST",body:JSON.stringify(e)},!0)}async function oz(e){return I(`/admin/datasets/${e}/exemplar/remint-dois`,{method:"POST"},!0)}async function U_(e,t){let r=new URLSearchParams;if(e)r.set("status",e);if(t!==void 0)r.set("blocklisted",t?"1":"0");let n=r.toString();return I(`/admin/imports${n?`?${n}`:""}`,{},!0)}async function az(e){return I(`/admin/imports/${e}/rollback`,{method:"POST"},!0)}async function cz(e){return I(`/admin/imports/${e}/retry`,{method:"POST"},!0)}async function V_(e){return I(`/admin/imports/${e}/verify`,{method:"POST"},!0)}async function uz(e){return I("/admin/imports/dispatch-cooldown",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({dataset_ids:e})},!0)}async function Oc(e,t){return I(`/admin/datasets/${e}/reindex`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t??{})},!0)}async function lz(e,t){return I("/admin/datasets/reindex/bulk",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({filter:e,...t??{}})},!0)}async function dz(e){let t=e?.limit??15;return I(`/admin/datasets/hed-sweep?limit=${encodeURIComponent(String(t))}`,{method:"POST",headers:{"Content-Type":"application/json"}},!0)}async function fz(){return I("/admin/datasets/hed-sweep?reset=1",{method:"POST",headers:{"Content-Type":"application/json"}},!0)}async function pz(e){let t=e?.limit??15,r=new URLSearchParams({limit:String(t)});if(e?.olderThan!=null)r.set("older-than",String(e.olderThan));if(e?.before!=null)r.set("before",e.before);return I(`/admin/datasets/data-integrity-sweep?${r.toString()}`,{method:"POST",headers:{"Content-Type":"application/json"}},!0)}async function mz(){return I("/admin/datasets/data-integrity-sweep?reset=1",{method:"POST",headers:{"Content-Type":"application/json"}},!0)}async function hz(e,t){let r=t?.write?"":"?dry_run=1";return I(`/admin/datasets/${e}/availability-report${r}`,{method:"POST",headers:{"Content-Type":"application/json"}},!0)}async function gz(e){let t=e?.limit??30,r=new URLSearchParams({limit:String(t)});if(e?.missingOnly)r.set("missing-only","1");return I(`/admin/datasets/availability-report-sweep?${r.toString()}`,{method:"POST",headers:{"Content-Type":"application/json"}},!0)}async function yz(){return I("/admin/datasets/availability-report-sweep?reset=1",{method:"POST",headers:{"Content-Type":"application/json"}},!0)}async function xz(e){let t=new URLSearchParams;if(e?.prefix)t.set("prefix",e.prefix);if(e?.visibility)t.set("visibility",e.visibility);if(e?.limit)t.set("limit",String(e.limit));let r=t.toString()?`?${t.toString()}`:"";return I(`/admin/fleet/drift${r}`,{},!0)}async function Ac(e,t){return I(`/admin/datasets/${e}/enforce`,{method:"POST",body:JSON.stringify({dry_run:t})},!0)}async function bz(e){return I("/admin/datasets/enforce/bulk",{method:"POST",body:JSON.stringify({prefix:e.prefix,visibility:e.visibility,limit:e.limit,dry_run:e.dryRun})},!0)}async function vz(e,t=!1){return I(`/admin/datasets/${e}/revalidate${t?"?force=true":""}`,{method:"POST"},!0)}async function _z(e){let t=e?`?user=${encodeURIComponent(e)}`:"";return I(`/admin/email-preferences${t}`,{},!0)}async function Dz(e,t){let r=t?`?user=${encodeURIComponent(t)}`:"";return I(`/admin/email-preferences${r}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)},!0)}async function z_(e){return I("/admin/notify",{method:"POST",body:JSON.stringify(e)},!0)}async function wz(){return I("/admin/summary/coverage",{},!0)}async function Ez(e,t,r){return I("/admin/manifest/dispatch",{method:"POST",body:JSON.stringify({dataset_id:e,version:t,skip_canary:r?.skipCanary??!1})},!0)}async function H_(e){return I("/admin/doctor/scan",{method:"POST",body:JSON.stringify({...e?.check&&{check:e.check},...e?.datasetId&&{dataset_id:e.datasetId}})},!0)}async function G_(e){return I("/admin/doctor/fix",{method:"POST",body:JSON.stringify({check:e.check,...e.datasetId&&{dataset_id:e.datasetId},...e.dryRun&&{dry_run:!0}})},!0)}var kc=k(()=>{Ps()});async function Zn(e,t){return I(`/datasets/${e}/upload-credentials`,{method:"POST",body:JSON.stringify({duration_seconds:t})},!0)}async function W_(e,t){return I(`/datasets/${e}/download-credentials`,{method:"POST",body:JSON.stringify({duration_seconds:t})},!0)}async function Sz(e){return I(`/admin/datasets/${e}/files`,{},!0)}async function $z(e){let t,r=0,n=[],i=!0;while(i){let s=await I(`/admin/datasets/${e}/s3-lock`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({continuation_token:t})},!0);if(r+=s.locked,s.failed?.length)n.push(...s.failed);if(i=s.hasMore,t=s.continuation_token,i&&!t)throw new M(500,"S3 lock paginated response missing continuation_token; aborting to avoid infinite loop")}return{locked:r,failed:n}}var Pc=k(()=>{Ps();gr()});async function _m(e){return I(`/datasets/${e}/ci/status`,{},!0)}async function Cz(e){return I(`/datasets/${e}/manifest`,{},!0)}async function Dm(e,t){return I(`/datasets/${e}/manifest/${t}`,{},!0)}function Fz(e){let t=e;if(!t.status)t.status="active";else if(!["active","archived","deleted"].includes(t.status))throw Error(`Invalid dataset status: ${t.status}`);if(!t.visibility)t.visibility="private";else if(!["public","private"].includes(t.visibility))throw Error(`Invalid dataset visibility: ${t.visibility}`);return t}async function Ic(e={}){let t=new URLSearchParams;if(e.mine)t.set("mine","true");if(e.search)t.set("search",e.search);if(e.modality)t.set("modality",e.modality);if(e.author)t.set("author",e.author);if(e.task)t.set("task",e.task);if(e.license)t.set("license",e.license);if(e.hasDoi)t.set("has_doi","true");if(e.hasHed)t.set("has_hed","1");if(e.dataComplete)t.set("data_complete","1");if(e.recent)t.set("recent",String(e.recent));if(e.sort)t.set("sort",e.sort);if(e.limit!=null)t.set("limit",String(e.limit));if(e.offset!=null)t.set("offset",String(e.offset));if(e.owner)t.set("owner",e.owner);let r=t.toString()?`?${t.toString()}`:"",n=await I(`/datasets${r}`,{},e.mine?!0:"optional");return n.datasets=n.datasets.map(Fz),n}async function Rz(e){return I(`/datasets/resolve/${e}`,{},"optional")}async function Oz(e,t={}){let r=new URLSearchParams({q:e});if(t.modality)r.set("modality",t.modality);if(t.limit)r.set("limit",String(t.limit));if(t.hasHed)r.set("has_hed","1");return I(`/datasets/search?${r.toString()}`,{},"optional")}async function gt(e){let t=await I(`/datasets/${e}`,{},"optional");return Fz(t.dataset)}async function Az(e){return I(`/datasets/${e}/versions`,{},!0)}async function wm(e){return I("/datasets",{method:"POST",body:JSON.stringify(e)},!0)}async function Em(e){return I(`/datasets/${e}/finalize`,{method:"POST"},!0)}async function K_(e){return I(`/datasets/${e}/request-access`,{method:"POST"},!0)}async function kz(e,t){let r=t?`?status=${t}`:"";return I(`/datasets/${e}/access-requests${r}`,{},!0)}async function Pz(e,t){return I(`/datasets/${e}/access-requests/${t}/approve`,{method:"POST"},!0)}async function Iz(e,t){return I(`/datasets/${e}/access-requests/${t}/deny`,{method:"POST"},!0)}async function Tz(e,t){return I(`/datasets/${e}/invite`,{method:"POST",body:JSON.stringify({username:t})},!0)}async function Nz(e){return I(`/datasets/${e}/collaborators`,{},!0)}async function qz(e,t){return I(`/admin/datasets/${e}/enrichment`,{method:"POST",body:JSON.stringify(t)},!0)}var vm;var Po=k(()=>{Ps();vm=/^\d{4}-\d{4}-\d{4}-\d{3}[\dX]$/});var Tc;var Uz=k(()=>{Tc=["ci_check","enrichment_check","s3_public_read","repo_public","tag_protect","doi_create","update_metadata","update_readme","create_tag","create_release","upload_to_zenodo","publish_doi","version_doi","s3_lock","sync_nemar","notify_user"]});async function Nc(e){return I(`/datasets/${e}/publish/request`,{method:"POST"},!0)}async function zz(e){return I(`/datasets/${e}/publish/status`,{},!0)}async function Hz(e){return I(`/datasets/${e}/publish/resend`,{method:"POST"},!0)}async function Gz(e){let t=e?`?status=${e}`:"";return I(`/admin/publish/requests${t}`,{},!0)}async function Wz(e,t){return I(`/admin/publish/${e}/deny`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({reason:t})},!0)}function A3e(e,t=[]){if(e){let r=Tc.indexOf(e);if(r>=0)return r+1}return Math.min(t.length+1,Tc.length)}function k3e(e){if(!(e instanceof M))return!1;if(e.statusCode===0)return!0;if(e.statusCode===429)return!0;if(e.statusCode>=500&&e.statusCode<600)return!0;if(e.statusCode===403&&/repository has been locked/i.test(e.message))return!0;return!1}async function qc(e,t=!1,r=!1,n=!1,i,s){let c,l,d=0,f=!1,m,p=t,g=[],y;function x(v,_,E,S){if(!s)return;s({step:v,stepIndex:A3e(v,_),stepTotal:Tc.length,s3LockLocked:E,s3LockTotal:S,s3LockResumed:v==="s3_lock"&&f?!0:void 0})}for(let v=1;v<=5;v++)try{let _,E=!0;do{if(_=await I(`/admin/publish/${e}/approve`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({resume:E?p:!0,sandbox:r,s3_lock_continuation_token:c,s3_lock_total:l,skip_ci_check:n})},!0),E=!1,_.step_results)g.push(..._.step_results);if(_.s3_lock_total!==void 0)l=_.s3_lock_total;if(_.s3_lock_batch_count!==void 0)d+=_.s3_lock_batch_count;let S=_.step??_.step_results?.[_.step_results.length-1]?.step;if(S&&(S!==m||S==="s3_lock"))x(S,_.steps_completed??[],S==="s3_lock"?d:void 0,S==="s3_lock"?l:void 0),m=S;if(_.hasMore&&_.s3_lock_continuation_token!==void 0)c=_.s3_lock_continuation_token;else break}while(_.hasMore);if(g.length>0)_.step_results=Vz(g);return _}catch(_){if(y=_,v===5||!k3e(_)){if(_ instanceof M&&g.length>0)_.stepResults=Vz(g);throw _}let S=_;if(i?.({attempt:v,maxAttempts:5,delayMs:1e4,step:S.step,error:S.message}),await new Promise((D)=>setTimeout(D,1e4)),p=!0,c!==void 0)f=!0}throw y}function Vz(e){let t=new Map;for(let r of e)t.set(r.step,r);return Array.from(t.values())}var fd=k(()=>{Uz();Ps();gr()});function Jz(e){X_=e}function Q_(){return X_}function pd(e){if(X_)process.stderr.write(`${e}
106
106
  `)}var X_=!1;var Xz={};Ti(Xz,{runCommand:()=>F});var{spawn:P3e}=globalThis.Bun;async function F(e,t={}){let r={...process.env,GIT_TERMINAL_PROMPT:"0",...t.env};for(let l of t.unsetEnv??[])delete r[l];let n=P3e({cmd:e,cwd:t.cwd,stdout:"pipe",stderr:"pipe",env:r}),i=!1,s;if(t.timeout)s=setTimeout(()=>{i=!0,n.kill()},t.timeout);if(Q_()){let l=t.cwd?` (cwd=${t.cwd})`:"";pd(u.dim(`$ ${e.join(" ")}${l}`))}let o=await new Response(n.stdout).text(),a=await new Response(n.stderr).text(),c=await n.exited;if(s)clearTimeout(s);if(Q_()){if(o.trim())pd(u.dim(o.trimEnd()));if(a.trim())pd(u.yellow(a.trimEnd()));pd(u.dim(`(exit ${c})`))}if(i)return{stdout:o,stderr:a||`Command timed out after ${Math.round(t.timeout/1000)}s`,exitCode:c??1};return{stdout:o,stderr:a,exitCode:c}}var Bt=k(()=>{Ke()});async function I3e(){try{let{exitCode:e,stderr:t}=await F(["ssh","-T","-o","BatchMode=yes","-o","ConnectTimeout=5","git@github.com"]),r=t.includes("successfully authenticated");if(!r)console.warn("SSH test to github.com failed:",{exitCode:e,stderr:t.trim().slice(0,500)});return{works:r,error:r?void 0:t.trim().slice(0,500)}}catch(e){let t=e instanceof Error?e.message:String(e);return console.warn("SSH test exception:",t),{works:!1,error:t}}}async function md(){try{let{stdout:e,exitCode:t,stderr:r}=await F(["gh","auth","token"]);if(t!==0)return console.warn("gh CLI returned non-zero exit code:",t),console.warn("stderr:",r),{token:null,error:`gh auth token failed: ${r.trim()||"unknown error"}`};if(!e.trim())return console.warn("gh auth token returned empty output"),{token:null,error:"gh CLI returned empty token"};return{token:e.trim()}}catch(e){let t=e instanceof Error?e.message:String(e);if(console.error("Failed to get GitHub token from gh CLI:",t),t.includes("ENOENT")||t.includes("not found"))return{token:null,error:"gh CLI not installed (command not found)"};return{token:null,error:`gh CLI error: ${t}`}}}async function Sm(e){try{let{stdout:t,exitCode:r,stderr:n}=await F(["gh","api","user","--jq",".login"]);if(r!==0){if(n.includes("not logged in")||n.includes("auth login"))return{authenticated:!1,error:"gh CLI not authenticated. Run 'gh auth login' to authenticate."};return{authenticated:!1,error:`gh CLI error: ${n.trim()||"unknown error"}`}}let i=t.trim();if(!i)return{authenticated:!1,error:"gh CLI returned empty username"};if(e){let s=i.toLowerCase()===e.toLowerCase();return{authenticated:!0,username:i,matches:s,error:s?void 0:`gh CLI authenticated as '${i}', expected '${e}'`}}return{authenticated:!0,username:i}}catch(t){let r=t instanceof Error?t.message:String(t);if(r.includes("ENOENT")||r.includes("not found"))return{authenticated:!1,error:"gh CLI not installed. Install from https://cli.github.com/"};return{authenticated:!1,error:`Failed to verify gh CLI: ${r}`}}}async function $m(e){if(!/^[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+$/.test(e))return{accepted:!1,error:`Invalid repository format: ${e}`};let{stdout:t,exitCode:r,stderr:n}=await F(["gh","api","/user/repository_invitations"]);if(r!==0){if(n.includes("not logged in")||n.includes("auth login"))return{accepted:!1,error:"gh CLI not authenticated. Run 'gh auth login' to authenticate."};if(n.includes("API rate limit")||n.includes("403"))return{accepted:!1,error:"GitHub API rate limit exceeded. Please try again in a few minutes."};if(n.includes("ENOENT")||n.includes("not found"))return{accepted:!1,error:"gh CLI not installed. Install from https://cli.github.com/"};return{accepted:!1,error:`Failed to list invitations: ${n.trim()||"unknown error"}`}}let i=null;try{i=JSON.parse(t||"[]").find((l)=>l.repository.full_name===e)?.id??null}catch(a){let c=a instanceof Error?a.message:String(a);return console.error("Failed to parse GitHub invitations response:",c),console.error(" Raw response (first 500 chars):",(t||"").slice(0,500)),{accepted:!1,error:`Failed to parse GitHub API response: ${c}`}}if(!i){let{exitCode:a}=await F(["gh","api",`/repos/${e}`,"--silent"]);if(a===0)return{accepted:!0,alreadyCollaborator:!0};return{accepted:!1,error:`No pending invitation found for ${e}. You may need to accept it manually via GitHub.`}}let{exitCode:s,stderr:o}=await F(["gh","api","--method","PATCH",`/user/repository_invitations/${i}`]);if(s!==0)return{accepted:!1,error:`Failed to accept invitation: ${o.trim()||"unknown error"}`};return{accepted:!0}}async function ei(e,t,r="origin"){let n=t;if(process.env.GH_TOKEN&&t.startsWith("git@github.com:")){let i=process.env.GH_TOKEN.trim();if(!i||/\s/.test(i))return{success:!1,error:"GH_TOKEN environment variable is set but appears malformed (empty or contains whitespace)"};n=`https://github.com/${t.replace("git@github.com:","")}`,await F(["git","config","credential.https://github.com.helper",`!printf 'username=x-access-token\\npassword=${i}'`],{cwd:e})}else if(t.startsWith("git@github.com:")){let i=t.replace("git@github.com:",""),s=await md();if(s.token)n=`https://github.com/${i}`,await F(["git","config","credential.https://github.com.helper",`!printf 'username=x-access-token\\npassword=${s.token}'`],{cwd:e});else{let o=await I3e();if(o.works)n=t;else return{success:!1,error:`GitHub authentication not configured.
107
107
 
108
108
  gh CLI failed: ${s.error||"could not get token"}
@@ -240,7 +240,7 @@ Deploy CI workflows to: ${e}
240
240
  `)),console.log("This will add the following workflows:"),console.log(" 1. BIDS Validation (runs on PRs)"),console.log(" 2. Version Check (ensures version bump on PRs)"),console.log(" 3. PR Merge Handler (creates releases, publishes DOIs)"),r)console.log(u.dim(" (post-deploy parseability poll disabled via --no-validate)"));console.log();let n=await Fe(`Deploy CI workflows to ${e}?`,t);if(n!=="confirmed"){console.log(u.dim(n==="declined"?"Skipped":"Cancelled"));return}let i=w(`Deploying CI workflows to ${e}...`).start(),s;try{s=await Ri(e)}catch(o){Ze(o,i,"Failed to deploy CI workflows",{404:"Dataset not found"});return}i.succeed("CI workflows deployed"),console.log();for(let o of s.workflows_deployed)console.log(` ${u.green("[x]")} ${o}`);if(!r){let o=w("Verifying GitHub Actions can parse the workflows...").start(),a=await tTe(e);if(!a)o.warn("Could not verify workflow parseability (deploy succeeded)");else if(a.missing.length===0&&a.errors.length===0)o.succeed("All workflows parseable by GitHub Actions");else{let c=a.missing.length>0?"Some workflows missing from GitHub Actions listing":"Could not fully verify workflow parseability (GitHub API error)";o.warn(c),kG(a)}}console.log()});Ed.command("validate").description("Check whether GitHub Actions can parse the deployed CI workflows").argument("<dataset-id>","Dataset ID (e.g., nm000104)").action(async(e)=>{if(!oe())return;let t=w(`Validating CI workflows for ${e}...`).start();try{let r=await M_(e);if(r.missing.length===0&&r.errors.length===0)t.succeed(`All ${r.valid.length} workflows parseable by GitHub Actions`);else t.warn("Some workflows missing or unreadable"),kG({missing:r.missing,errors:r.errors})}catch(r){Ze(r,t,"Failed to validate CI workflows",{404:"Dataset not found"})}});Ed.command("sync").description("Sync deployed CI workflows to current templates (only writes drifted/missing files)").argument("[dataset-id]","Dataset ID (e.g., nm000104)").option("--all","Sync across all dataset repositories").option(Re,Oe).option(qe,Te).action(async(e,t)=>{if(!oe())return;if(t.all){let n=w("Fetching dataset list...").start(),i;try{if(i=(await Ic({limit:1000})).datasets,n.succeed(`Found ${i.length} datasets`),i.length>=1000)console.log(u.yellow("Warning: reached 1000 dataset limit; some datasets may be skipped"))}catch(l){Ze(l,n,"Failed to fetch datasets");return}console.log(u.cyan(`
241
241
  Sync CI templates across ${i.length} datasets (writes only diffs)
242
242
  `));let s=await Fe(`Sync templates on all ${i.length} datasets?`,t);if(s!=="confirmed"){console.log(u.dim(s==="declined"?"Skipped":"Cancelled"));return}let o=0,a=0,c=0;for(let l of i){let d=w(`Syncing ${l.dataset_id}...`).start();try{let f=await B_(l.dataset_id),m=f.changed.length+f.added.length;if(f.errors.length>0)d.warn(`${l.dataset_id}: ${m} updated, ${f.errors.length} error(s)`),c++;else if(m===0)d.succeed(`${l.dataset_id}: up to date`),o++;else{let p=[];if(f.added.length>0)p.push(`+${f.added.length} added`);if(f.changed.length>0)p.push(`~${f.changed.length} updated`);d.succeed(`${l.dataset_id}: ${p.join(", ")}`),a++}}catch(f){let m=f instanceof M?f.message:String(f);d.fail(`${l.dataset_id}: ${m}`),c++}}console.log(),console.log(u.cyan(`Done: ${o} up-to-date, ${a} updated, ${c} with errors`));return}if(!e){console.error(u.red("Error: dataset-id is required (or use --all)"));return}let r=w(`Syncing CI templates for ${e}...`).start();try{let n=await B_(e),i=n.changed.length+n.added.length;if(n.errors.length>0)r.warn(`${e}: ${n.errors.length} error(s)`);else if(i===0)r.succeed(`${e}: already up to date`);else r.succeed(`${e}: synced`);if(console.log(),console.log(` ${u.dim("Checked:")} ${n.checked.join(", ")}`),n.added.length>0)console.log(` ${u.green("Added:")} ${n.added.join(", ")}`);if(n.changed.length>0)console.log(` ${u.yellow("Updated:")} ${n.changed.join(", ")}`);if(!n.committed&&i>0&&n.errors.length===0)console.log(` ${u.yellow("Note:")} listed changes were not committed`);if(n.list_failed)console.log(` ${u.red("Warning:")} workflow directory listing failed; presence is unknown`);if(n.errors.length>0){console.log(` ${u.red("Errors:")}`);for(let s of n.errors)console.log(` - ${s}`)}console.log()}catch(n){Ze(n,r,"Failed to sync CI templates",{404:"Dataset not found"})}});Ie.addCommand(Ed);var Sd=new Ee("doi").description("DOI management");Sd.command("create").description("Create concept DOI for a dataset").argument("<dataset-id>","Dataset ID (e.g., nm000104)").option("--title <title>","DOI title (defaults to dataset name)").option("--description <desc>","DOI description").option("--provider <provider>","DOI provider: ezid (default) or zenodo","ezid").option("--sandbox","Use sandbox/test DOI").option(Re,Oe).option(qe,Te).action(async(e,t)=>{if(!oe())return;let r=w("Fetching dataset info...").start(),n;try{n=await gt(e),r.succeed(`Found dataset: ${n.name}`)}catch(c){if(c instanceof M){if(r.fail(c.message),c.statusCode===404)console.log(u.dim(" Dataset not found"))}else r.fail("Failed to fetch dataset");return}try{let c=await dd(e);if(c.concept_doi){if(console.log(u.yellow(`
243
- Dataset already has a concept DOI:`)),console.log(` Concept DOI: ${u.cyan(c.concept_doi)}`),c.zenodo_concept_url)console.log(` Zenodo URL: ${c.zenodo_concept_url}`);return}}catch(c){if(process.env.DEBUG)console.error("[debug] DOI info fetch:",c)}if(console.log(),console.log(u.cyan("Dataset Information:")),console.log(` ID: ${n.dataset_id}`),console.log(` Name: ${n.name}`),n.github_repo)console.log(` GitHub: ${n.github_repo}`);if(t.sandbox)console.log(` Mode: ${u.yellow("SANDBOX (test DOI)")}`);console.log();let i=t.provider==="zenodo"?"zenodo":"ezid";if(t.sandbox){if(console.log(u.yellow("\u2501".repeat(60))),console.log(u.yellow.bold(" SANDBOX MODE ENABLED")),console.log(u.yellow("\u2501".repeat(60))),i==="zenodo")console.log(u.yellow(" \u2022 Using Zenodo sandbox (sandbox.zenodo.org)"));else console.log(u.yellow(" \u2022 Using EZID test shoulder (doi:10.5072/FK2)")),console.log(u.yellow(" \u2022 Test DOIs auto-delete after 2 weeks"));console.log(u.yellow(" \u2022 DOI will NOT be indexed by DataCite")),console.log(u.yellow(" \u2022 DOI will NOT resolve in production")),console.log(u.yellow(" \u2022 Use this for testing workflows only")),console.log(u.yellow("\u2501".repeat(60))),console.log()}console.log(u.red("WARNING: DOIs are PERMANENT and cannot be deleted!")),console.log(u.dim("The DOI will be pre-reserved but not published until the first version release.")),console.log(` Provider: ${u.cyan(i.toUpperCase())}`),console.log();let s=t.sandbox?`Create TEST concept DOI via ${i.toUpperCase()} SANDBOX?`:`Create PERMANENT concept DOI via ${i.toUpperCase()} PRODUCTION?`,o=await Fe(s,t);if(o!=="confirmed"){console.log(u.dim(o==="declined"?"Skipped":"Cancelled"));return}let a=w(`Creating concept DOI via ${i.toUpperCase()}...`).start();try{let c=await QV(e,{title:t.title,description:t.description,sandbox:t.sandbox,provider:i});a.succeed("Concept DOI created successfully");let l=w("Applying branch protection...").start();try{let d=await Em(e);if(d.warnings&&d.warnings.length>0){l.warn("Branch protection applied with warnings");for(let f of d.warnings)console.log(u.yellow(` Warning: ${f}`))}else l.succeed("Branch protection applied")}catch(d){if(l.warn("Could not apply branch protection"),d instanceof M){if(console.log(u.dim(` ${d.message}`)),d.statusCode===403)console.log(u.dim(" Check admin credentials and permissions"))}else console.log(u.dim(` ${d instanceof Error?d.message:"Unknown error"}`));console.log(u.dim(" Manual setup: Go to GitHub repo Settings > Branches > Add rule"))}if(console.log(),console.log(u.green("DOI Information:")),console.log(` Concept DOI: ${u.cyan(c.concept_doi)}`),console.log(` Provider: ${c.provider.toUpperCase()}`),c.provider==="ezid")console.log(` DOI URL: ${c.doi_url}`),console.log(` EZID ID: ${c.ezid_identifier}`);else console.log(` Zenodo URL: ${c.zenodo_url}`);if(c.metadata_warning)console.log(u.yellow(` Warning: ${c.metadata_warning}`));if(console.log(),console.log(u.yellow("Next steps:")),console.log(" 1. Update dataset_description.json with DatasetDOI field"),console.log(" 2. Create a PR and merge it to trigger version DOI publication"),console.log(),t.sandbox)console.log(u.dim("Note: This is a sandbox DOI and will not resolve in production."))}catch(c){if(c instanceof M){if(a.fail(c.message),c.statusCode===403)console.log(u.dim(" This command requires admin privileges"))}else a.fail("Failed to create concept DOI"),console.log(u.dim(` ${U(c)}`))}});Sd.command("info").description("Get DOI info for a dataset").argument("<dataset-id>","Dataset ID (e.g., nm000104)").action(async(e)=>{if(!oe())return;let t=w("Fetching DOI info...").start();try{let r=await dd(e);if(t.stop(),console.log(),console.log(u.cyan(`DOI Information for ${e}:`)),console.log(` Dataset Name: ${r.name}`),console.log(),r.concept_doi){if(console.log(u.green("Concept DOI:")),console.log(` DOI: ${r.concept_doi}`),console.log(` URL: https://doi.org/${r.concept_doi}`),console.log(` Provider: ${(r.doi_provider||"zenodo").toUpperCase()}`),r.doi_provider==="ezid"){if(r.ezid_identifier)console.log(` EZID ID: ${r.ezid_identifier}`);if(r.ezid_status){let n=r.ezid_status==="public"?u.green:u.yellow;console.log(` Status: ${n(r.ezid_status)}`)}}if(r.zenodo_concept_url){if(console.log(` Zenodo: ${r.zenodo_concept_url}`),r.zenodo_concept_url.includes("sandbox.zenodo.org"))console.log(),console.log(u.yellow("Mode: SANDBOX (test DOI)")),console.log(u.yellow(" This DOI is not indexed by DataCite and will not resolve in production"))}}else console.log(u.yellow("No concept DOI created yet")),console.log(u.dim(" Use 'nemar admin doi create' to create one"));if(console.log(),r.latest_version_doi){if(console.log(u.green("Latest Version DOI:")),console.log(` DOI: ${r.latest_version_doi}`),console.log(` URL: https://doi.org/${r.latest_version_doi}`),r.zenodo_latest_version_url)console.log(` Zenodo: ${r.zenodo_latest_version_url}`)}else if(r.concept_doi)console.log(u.yellow("No version DOI published yet")),console.log(u.dim(" Version DOIs are created automatically on PR merge"))}catch(r){if(r instanceof M){if(t.fail(r.message),r.statusCode===404)console.log(u.dim(" Dataset not found"));else if(r.statusCode===403)console.log(u.dim(" This command requires admin privileges"))}else t.fail("Failed to fetch DOI info")}});Sd.command("update").description("Update EZID DOI metadata or status").argument("<dataset-id>","Dataset ID (e.g., nm000104)").option("--make-public","Transition DOI from reserved to public (permanent)").option("--unavailable","Tombstone the concept DOI (EZID _status=unavailable); concept-only, reversible via --make-public. For a full withdrawal (visibility + every version DOI) use 'nemar admin withdraw' instead.").option("--refresh","Refresh metadata from dataset_description.json and .nemar/metadata.json").option(Re,Oe).option(qe,Te).action(async(e,t)=>{if(!oe())return;if(t.makePublic&&t.unavailable){console.log(u.red("Use --make-public or --unavailable, not both."));return}if(!t.makePublic&&!t.unavailable&&!t.refresh){console.log(u.yellow("No action specified. Use --make-public, --unavailable, and/or --refresh."));return}if(t.makePublic){console.log(u.red("WARNING: Making a DOI public is PERMANENT!")),console.log(u.dim(" The DOI will be findable in DataCite and cannot be reverted.")),console.log();let n=await Fe(`Make DOI for ${e} PUBLIC and permanent?`,t);if(n!=="confirmed"){console.log(u.dim(n==="declined"?"Skipped":"Cancelled"));return}}if(t.unavailable){console.log(u.yellow("This tombstones the concept DOI (EZID _status=unavailable).")),console.log(u.dim(" Reversible with --make-public. Version DOIs are untouched.")),console.log();let n=await Fe(`Mark DOI for ${e} unavailable (tombstone)?`,t);if(n!=="confirmed"){console.log(u.dim(n==="declined"?"Skipped":"Cancelled"));return}}let r=w("Updating DOI...").start();try{let n=await L_(e,{status:t.makePublic?"public":t.unavailable?"unavailable":void 0,refresh_metadata:t.refresh});r.succeed("DOI updated successfully"),console.log(),console.log(` EZID ID: ${u.cyan(n.ezid_identifier)}`),console.log(` Status: ${n.status==="public"?u.green(n.status):u.yellow(n.status)}`),console.log(` URL: ${n.doi_url}`)}catch(n){if(n instanceof M){if(r.fail(n.message),n.statusCode===400)console.log(u.dim(" DOI update is only supported for EZID-managed DOIs"))}else r.fail("Failed to update DOI"),console.log(u.dim(` ${U(n)}`))}});Sd.command("enrich").description("Enrich DOI metadata with ORCIDs, descriptions, funding, and more").argument("<dataset-id>","Dataset ID (e.g., nm000104)").option("--no-llm","Skip LLM-based enrichment from README").option("--sandbox","Use sandbox DOI").option(Re,Oe).option(qe,Te).action(async(e,t)=>{if(!oe())return;let r=w("Fetching dataset and existing enrichment...").start(),n;try{n=await gt(e),r.succeed(`Dataset: ${n.name}`)}catch(p){if(p instanceof M)r.fail(p.message);else r.fail("Failed to fetch dataset");return}let i,s=!1;try{i=await dd(e)}catch(p){if(p instanceof M&&p.statusCode===404);else s=!0,console.log(u.yellow(` Warning: Could not fetch DOI info: ${U(p)}`))}if(i?.concept_doi)console.log(` DOI: ${u.cyan(i.concept_doi)}`);let o={version:"2.0"};if(n.github_repo){let p=w("Reading existing metadata...").start(),g=await $G(n.github_repo,".nemar/metadata.json");if(g)try{let y=JSON.parse(g);if(y&&typeof y==="object"&&y.version==="2.0")o=y,p.succeed(`Loaded existing metadata (stage: ${y.pipeline_stage||"unknown"})`);else p.warn("Existing metadata has unsupported version, starting fresh")}catch(y){p.warn(`Could not parse existing metadata (${y instanceof Error?y.message:String(y)}), starting fresh`)}else p.info("No existing .nemar/metadata.json found, starting fresh")}if(t.llm!==!1&&n.github_repo){console.log(),console.log(u.cyan("--- Running LLM enrichment pipeline (CI workflow) ---"));let p=w("Triggering run-enrichment workflow...").start();try{let{spawn:g}=awaitPromise.resolve(globalThis.Bun),y=n.github_repo,x="nemarDatasets/.github",v="run-enrichment.yml",_=g({cmd:["gh","workflow","run","run-enrichment.yml","--repo","nemarDatasets/.github","--ref","main","-f",`dataset_id=${e}`,"-f","ref=main","-f","force=true"],stdout:"pipe",stderr:"pipe"}),E=await new Response(_.stderr).text();if(await _.exited!==0)throw Error(`Failed to trigger workflow: ${E.trim()}`);p.text="Waiting for workflow to register...",await new Promise((A)=>setTimeout(A,3000)),p.text="Polling workflow status...";let D=60,R="",C=0;for(let A=0;A<D;A++){let q=g({cmd:["gh","run","list","--repo","nemarDatasets/.github","--workflow","run-enrichment.yml","-L","10","--json","databaseId,status,conclusion,displayTitle,event"],stdout:"pipe",stderr:"pipe"}),Z=await new Response(q.stdout).text(),ve=await new Response(q.stderr).text();if(await q.exited!==0){if(C++,C>=3){p.warn(`gh CLI error: ${ve.trim()}`);break}await new Promise((je)=>setTimeout(je,5000));continue}try{let je=JSON.parse(Z.trim());C=0;let T=je.find((H)=>H.event==="workflow_dispatch");if(T){if(T.status==="completed"){R=T.conclusion||"unknown";break}p.text=`Workflow ${T.status}... (${A*5}s)`}}catch(je){if(C++,C>=3){p.warn(`Unable to parse workflow status: ${je instanceof Error?je.message:String(je)} (raw: ${Z.trim().slice(0,200)})`);break}}await new Promise((je)=>setTimeout(je,5000))}let j=!1;if(!R)p.warn("Workflow timed out after 5 minutes (may still be running)");else if(R==="success"){p.succeed("LLM enrichment workflow completed successfully");let A=await $G(y,".nemar/metadata.json");if(A)try{let q=JSON.parse(A);if(q&&typeof q==="object"&&q.version==="2.0"){Object.assign(o,q),j=!0;let Z=q.pipeline_stage||"unknown";if(console.log(u.dim(` Pipeline stage: ${Z}`)),o.authors){let ve=Object.keys(o.authors).length;console.log(u.dim(` Authors: ${ve}`))}}}catch(q){console.log(u.yellow(` Warning: Could not parse updated metadata: ${q instanceof Error?q.message:String(q)}`)),console.log(u.dim(" Using pre-workflow enrichment data"))}else console.log(u.yellow(" Warning: Could not fetch updated metadata after successful workflow.")),console.log(u.dim(" Author data below may be from a previous run."))}else p.fail(`LLM enrichment workflow failed (conclusion: ${R})`);if(!j)console.log(u.yellow(" ORCID discovery did not complete. Authors below may be from previous metadata."))}catch(g){p.fail("LLM enrichment pipeline failed"),console.log(u.dim(` ${U(g)}`)),console.log(u.yellow(" ORCID discovery did not run. You will need to enter ORCIDs manually."))}}console.log(),console.log(u.cyan("--- Author ORCIDs ---"));let a=o.authors||{},c=Object.keys(a);if(c.length>0){let p=c.filter((y)=>a[y]?.orcid),g=c.filter((y)=>!a[y]?.orcid);console.log(u.dim(` Discovered ${c.length} authors from pipeline:`));for(let y of p)console.log(u.green(` [x] ${y}: ${a[y]?.orcid}`));for(let y of g)console.log(u.yellow(` [ ] ${y}: no ORCID found`));if(g.length>0)console.log(u.dim(` ${g.length} author(s) missing ORCIDs.`))}let{updateAuthors:l}=await X.prompt([{type:"confirm",name:"updateAuthors",message:c.length>0?"Add or correct author ORCIDs?":"Add author ORCIDs manually?",default:!1}]);if(l){let p={},g=!0;while(g){let{authorName:y}=await X.prompt([{type:"input",name:"authorName",message:'Author name (as in BIDS, e.g., "Shirazi, Yahya"):'}]);if(!y)break;let x=a[y];if(x?.orcid)console.log(u.dim(` Current ORCID: ${x.orcid}`));let{orcid:v}=await X.prompt([{type:"input",name:"orcid",message:`ORCID for "${y}" (Enter to ${x?.orcid?"keep current":"skip"}):`,validate:(D)=>{if(!D)return!0;return vm.test(D)||"Invalid ORCID format (XXXX-XXXX-XXXX-XXXX)"}}]),_={};if(v)_.orcid=v;let{affiliation:E}=await X.prompt([{type:"input",name:"affiliation",message:`Affiliation for "${y}" (optional):`}]);if(E)_.affiliations=[{name:E}];if(_.orcid||_.affiliations)p[y]=_;let{more:S}=await X.prompt([{type:"confirm",name:"more",message:"Add another author?",default:!0}]);g=S}if(Object.keys(p).length>0){let y={...o.authors||{}};for(let[x,v]of Object.entries(p)){let _=y[x]||{};y[x]={..._,...v,orcid:v.orcid||_.orcid}}o.authors=y}}console.log(),console.log(u.cyan("--- Dataset stats ---"));let d=w("Computing dataset sizes and formats...").start();try{let p=await Sz(e),g=Qe(p.total_size);o.sizes=[`${g} (${p.file_count} files)`],o.formats=p.extensions,d.succeed(`Sizes: ${g} (${p.file_count} files), Formats: ${p.extensions.join(", ")}`)}catch(p){d.warn("Could not compute dataset stats"),console.log(u.dim(` ${U(p)}`))}console.log(),console.log(u.cyan("--- Review ---")),console.log(JSON.stringify(o,null,2)),console.log();let f=await Fe("Commit to repo and refresh DOI?",t,!0);if(f!=="confirmed"){console.log(u.dim(f==="declined"?"Skipped":"Cancelled"));return}let m=w("Saving enrichment...").start();try{let p=await qz(e,o);if(m.succeed(p.message),p.bidsignore_updated)console.log(u.dim(" .bidsignore updated to include .nemar/"));if(!i&&s)try{i=await dd(e)}catch(g){if(process.env.DEBUG)console.error("[debug] DOI info re-fetch:",g)}if(i?.ezid_identifier){let g=w("Refreshing DOI metadata...").start();try{await L_(e,{refresh_metadata:!0}),g.succeed("DOI metadata refreshed")}catch(y){g.warn("Could not refresh DOI metadata"),console.log(u.dim(` ${U(y)}`))}}else if(s)console.log(u.yellow(" DOI refresh skipped: could not verify DOI exists. Run 'nemar admin doi update --refresh' manually."))}catch(p){if(p instanceof M)m.fail(p.message);else m.fail("Failed to save enrichment"),console.log(u.dim(` ${U(p)}`))}});Ie.addCommand(Sd);var Vm=new Ee("publish").description("Publication workflow management");Vm.command("list").description("List publication requests").option("-s, --status <status>","Filter by status (requested, approving, published, denied)").addHelpText("after",`
243
+ Dataset already has a concept DOI:`)),console.log(` Concept DOI: ${u.cyan(c.concept_doi)}`),c.zenodo_concept_url)console.log(` Zenodo URL: ${c.zenodo_concept_url}`);return}}catch(c){if(process.env.DEBUG)console.error("[debug] DOI info fetch:",c)}if(console.log(),console.log(u.cyan("Dataset Information:")),console.log(` ID: ${n.dataset_id}`),console.log(` Name: ${n.name}`),n.github_repo)console.log(` GitHub: ${n.github_repo}`);if(t.sandbox)console.log(` Mode: ${u.yellow("SANDBOX (test DOI)")}`);console.log();let i=t.provider==="zenodo"?"zenodo":"ezid";if(t.sandbox){if(console.log(u.yellow("\u2501".repeat(60))),console.log(u.yellow.bold(" SANDBOX MODE ENABLED")),console.log(u.yellow("\u2501".repeat(60))),i==="zenodo")console.log(u.yellow(" \u2022 Using Zenodo sandbox (sandbox.zenodo.org)"));else console.log(u.yellow(" \u2022 Using EZID test shoulder (doi:10.5072/FK2)")),console.log(u.yellow(" \u2022 Test DOIs auto-delete after 2 weeks"));console.log(u.yellow(" \u2022 DOI will NOT be indexed by DataCite")),console.log(u.yellow(" \u2022 DOI will NOT resolve in production")),console.log(u.yellow(" \u2022 Use this for testing workflows only")),console.log(u.yellow("\u2501".repeat(60))),console.log()}console.log(u.red("WARNING: DOIs are PERMANENT and cannot be deleted!")),console.log(u.dim("The DOI will be pre-reserved but not published until the first version release.")),console.log(` Provider: ${u.cyan(i.toUpperCase())}`),console.log();let s=t.sandbox?`Create TEST concept DOI via ${i.toUpperCase()} SANDBOX?`:`Create PERMANENT concept DOI via ${i.toUpperCase()} PRODUCTION?`,o=await Fe(s,t);if(o!=="confirmed"){console.log(u.dim(o==="declined"?"Skipped":"Cancelled"));return}let a=w(`Creating concept DOI via ${i.toUpperCase()}...`).start();try{let c=await QV(e,{title:t.title,description:t.description,sandbox:t.sandbox,provider:i});a.succeed("Concept DOI created successfully");let l=w("Finalizing repository setup...").start();try{let d=await Em(e);if(d.warnings&&d.warnings.length>0){l.warn("Repository setup finalized with warnings");for(let f of d.warnings)console.log(u.yellow(` Warning: ${f}`))}else l.succeed("Repository setup finalized")}catch(d){if(l.warn("Could not finalize repository setup"),d instanceof M){if(console.log(u.dim(` ${d.message}`)),d.statusCode===403)console.log(u.dim(" Check admin credentials and permissions"))}else console.log(u.dim(` ${d instanceof Error?d.message:"Unknown error"}`))}if(console.log(),console.log(u.green("DOI Information:")),console.log(` Concept DOI: ${u.cyan(c.concept_doi)}`),console.log(` Provider: ${c.provider.toUpperCase()}`),c.provider==="ezid")console.log(` DOI URL: ${c.doi_url}`),console.log(` EZID ID: ${c.ezid_identifier}`);else console.log(` Zenodo URL: ${c.zenodo_url}`);if(c.metadata_warning)console.log(u.yellow(` Warning: ${c.metadata_warning}`));if(console.log(),console.log(u.yellow("Next steps:")),console.log(" 1. Update dataset_description.json with DatasetDOI field"),console.log(" 2. Create a PR and merge it to trigger version DOI publication"),console.log(),t.sandbox)console.log(u.dim("Note: This is a sandbox DOI and will not resolve in production."))}catch(c){if(c instanceof M){if(a.fail(c.message),c.statusCode===403)console.log(u.dim(" This command requires admin privileges"))}else a.fail("Failed to create concept DOI"),console.log(u.dim(` ${U(c)}`))}});Sd.command("info").description("Get DOI info for a dataset").argument("<dataset-id>","Dataset ID (e.g., nm000104)").action(async(e)=>{if(!oe())return;let t=w("Fetching DOI info...").start();try{let r=await dd(e);if(t.stop(),console.log(),console.log(u.cyan(`DOI Information for ${e}:`)),console.log(` Dataset Name: ${r.name}`),console.log(),r.concept_doi){if(console.log(u.green("Concept DOI:")),console.log(` DOI: ${r.concept_doi}`),console.log(` URL: https://doi.org/${r.concept_doi}`),console.log(` Provider: ${(r.doi_provider||"zenodo").toUpperCase()}`),r.doi_provider==="ezid"){if(r.ezid_identifier)console.log(` EZID ID: ${r.ezid_identifier}`);if(r.ezid_status){let n=r.ezid_status==="public"?u.green:u.yellow;console.log(` Status: ${n(r.ezid_status)}`)}}if(r.zenodo_concept_url){if(console.log(` Zenodo: ${r.zenodo_concept_url}`),r.zenodo_concept_url.includes("sandbox.zenodo.org"))console.log(),console.log(u.yellow("Mode: SANDBOX (test DOI)")),console.log(u.yellow(" This DOI is not indexed by DataCite and will not resolve in production"))}}else console.log(u.yellow("No concept DOI created yet")),console.log(u.dim(" Use 'nemar admin doi create' to create one"));if(console.log(),r.latest_version_doi){if(console.log(u.green("Latest Version DOI:")),console.log(` DOI: ${r.latest_version_doi}`),console.log(` URL: https://doi.org/${r.latest_version_doi}`),r.zenodo_latest_version_url)console.log(` Zenodo: ${r.zenodo_latest_version_url}`)}else if(r.concept_doi)console.log(u.yellow("No version DOI published yet")),console.log(u.dim(" Version DOIs are created automatically on PR merge"))}catch(r){if(r instanceof M){if(t.fail(r.message),r.statusCode===404)console.log(u.dim(" Dataset not found"));else if(r.statusCode===403)console.log(u.dim(" This command requires admin privileges"))}else t.fail("Failed to fetch DOI info")}});Sd.command("update").description("Update EZID DOI metadata or status").argument("<dataset-id>","Dataset ID (e.g., nm000104)").option("--make-public","Transition DOI from reserved to public (permanent)").option("--unavailable","Tombstone the concept DOI (EZID _status=unavailable); concept-only, reversible via --make-public. For a full withdrawal (visibility + every version DOI) use 'nemar admin withdraw' instead.").option("--refresh","Refresh metadata from dataset_description.json and .nemar/metadata.json").option(Re,Oe).option(qe,Te).action(async(e,t)=>{if(!oe())return;if(t.makePublic&&t.unavailable){console.log(u.red("Use --make-public or --unavailable, not both."));return}if(!t.makePublic&&!t.unavailable&&!t.refresh){console.log(u.yellow("No action specified. Use --make-public, --unavailable, and/or --refresh."));return}if(t.makePublic){console.log(u.red("WARNING: Making a DOI public is PERMANENT!")),console.log(u.dim(" The DOI will be findable in DataCite and cannot be reverted.")),console.log();let n=await Fe(`Make DOI for ${e} PUBLIC and permanent?`,t);if(n!=="confirmed"){console.log(u.dim(n==="declined"?"Skipped":"Cancelled"));return}}if(t.unavailable){console.log(u.yellow("This tombstones the concept DOI (EZID _status=unavailable).")),console.log(u.dim(" Reversible with --make-public. Version DOIs are untouched.")),console.log();let n=await Fe(`Mark DOI for ${e} unavailable (tombstone)?`,t);if(n!=="confirmed"){console.log(u.dim(n==="declined"?"Skipped":"Cancelled"));return}}let r=w("Updating DOI...").start();try{let n=await L_(e,{status:t.makePublic?"public":t.unavailable?"unavailable":void 0,refresh_metadata:t.refresh});r.succeed("DOI updated successfully"),console.log(),console.log(` EZID ID: ${u.cyan(n.ezid_identifier)}`),console.log(` Status: ${n.status==="public"?u.green(n.status):u.yellow(n.status)}`),console.log(` URL: ${n.doi_url}`)}catch(n){if(n instanceof M){if(r.fail(n.message),n.statusCode===400)console.log(u.dim(" DOI update is only supported for EZID-managed DOIs"))}else r.fail("Failed to update DOI"),console.log(u.dim(` ${U(n)}`))}});Sd.command("enrich").description("Enrich DOI metadata with ORCIDs, descriptions, funding, and more").argument("<dataset-id>","Dataset ID (e.g., nm000104)").option("--no-llm","Skip LLM-based enrichment from README").option("--sandbox","Use sandbox DOI").option(Re,Oe).option(qe,Te).action(async(e,t)=>{if(!oe())return;let r=w("Fetching dataset and existing enrichment...").start(),n;try{n=await gt(e),r.succeed(`Dataset: ${n.name}`)}catch(p){if(p instanceof M)r.fail(p.message);else r.fail("Failed to fetch dataset");return}let i,s=!1;try{i=await dd(e)}catch(p){if(p instanceof M&&p.statusCode===404);else s=!0,console.log(u.yellow(` Warning: Could not fetch DOI info: ${U(p)}`))}if(i?.concept_doi)console.log(` DOI: ${u.cyan(i.concept_doi)}`);let o={version:"2.0"};if(n.github_repo){let p=w("Reading existing metadata...").start(),g=await $G(n.github_repo,".nemar/metadata.json");if(g)try{let y=JSON.parse(g);if(y&&typeof y==="object"&&y.version==="2.0")o=y,p.succeed(`Loaded existing metadata (stage: ${y.pipeline_stage||"unknown"})`);else p.warn("Existing metadata has unsupported version, starting fresh")}catch(y){p.warn(`Could not parse existing metadata (${y instanceof Error?y.message:String(y)}), starting fresh`)}else p.info("No existing .nemar/metadata.json found, starting fresh")}if(t.llm!==!1&&n.github_repo){console.log(),console.log(u.cyan("--- Running LLM enrichment pipeline (CI workflow) ---"));let p=w("Triggering run-enrichment workflow...").start();try{let{spawn:g}=awaitPromise.resolve(globalThis.Bun),y=n.github_repo,x="nemarDatasets/.github",v="run-enrichment.yml",_=g({cmd:["gh","workflow","run","run-enrichment.yml","--repo","nemarDatasets/.github","--ref","main","-f",`dataset_id=${e}`,"-f","ref=main","-f","force=true"],stdout:"pipe",stderr:"pipe"}),E=await new Response(_.stderr).text();if(await _.exited!==0)throw Error(`Failed to trigger workflow: ${E.trim()}`);p.text="Waiting for workflow to register...",await new Promise((A)=>setTimeout(A,3000)),p.text="Polling workflow status...";let D=60,R="",C=0;for(let A=0;A<D;A++){let q=g({cmd:["gh","run","list","--repo","nemarDatasets/.github","--workflow","run-enrichment.yml","-L","10","--json","databaseId,status,conclusion,displayTitle,event"],stdout:"pipe",stderr:"pipe"}),Z=await new Response(q.stdout).text(),ve=await new Response(q.stderr).text();if(await q.exited!==0){if(C++,C>=3){p.warn(`gh CLI error: ${ve.trim()}`);break}await new Promise((je)=>setTimeout(je,5000));continue}try{let je=JSON.parse(Z.trim());C=0;let T=je.find((H)=>H.event==="workflow_dispatch");if(T){if(T.status==="completed"){R=T.conclusion||"unknown";break}p.text=`Workflow ${T.status}... (${A*5}s)`}}catch(je){if(C++,C>=3){p.warn(`Unable to parse workflow status: ${je instanceof Error?je.message:String(je)} (raw: ${Z.trim().slice(0,200)})`);break}}await new Promise((je)=>setTimeout(je,5000))}let j=!1;if(!R)p.warn("Workflow timed out after 5 minutes (may still be running)");else if(R==="success"){p.succeed("LLM enrichment workflow completed successfully");let A=await $G(y,".nemar/metadata.json");if(A)try{let q=JSON.parse(A);if(q&&typeof q==="object"&&q.version==="2.0"){Object.assign(o,q),j=!0;let Z=q.pipeline_stage||"unknown";if(console.log(u.dim(` Pipeline stage: ${Z}`)),o.authors){let ve=Object.keys(o.authors).length;console.log(u.dim(` Authors: ${ve}`))}}}catch(q){console.log(u.yellow(` Warning: Could not parse updated metadata: ${q instanceof Error?q.message:String(q)}`)),console.log(u.dim(" Using pre-workflow enrichment data"))}else console.log(u.yellow(" Warning: Could not fetch updated metadata after successful workflow.")),console.log(u.dim(" Author data below may be from a previous run."))}else p.fail(`LLM enrichment workflow failed (conclusion: ${R})`);if(!j)console.log(u.yellow(" ORCID discovery did not complete. Authors below may be from previous metadata."))}catch(g){p.fail("LLM enrichment pipeline failed"),console.log(u.dim(` ${U(g)}`)),console.log(u.yellow(" ORCID discovery did not run. You will need to enter ORCIDs manually."))}}console.log(),console.log(u.cyan("--- Author ORCIDs ---"));let a=o.authors||{},c=Object.keys(a);if(c.length>0){let p=c.filter((y)=>a[y]?.orcid),g=c.filter((y)=>!a[y]?.orcid);console.log(u.dim(` Discovered ${c.length} authors from pipeline:`));for(let y of p)console.log(u.green(` [x] ${y}: ${a[y]?.orcid}`));for(let y of g)console.log(u.yellow(` [ ] ${y}: no ORCID found`));if(g.length>0)console.log(u.dim(` ${g.length} author(s) missing ORCIDs.`))}let{updateAuthors:l}=await X.prompt([{type:"confirm",name:"updateAuthors",message:c.length>0?"Add or correct author ORCIDs?":"Add author ORCIDs manually?",default:!1}]);if(l){let p={},g=!0;while(g){let{authorName:y}=await X.prompt([{type:"input",name:"authorName",message:'Author name (as in BIDS, e.g., "Shirazi, Yahya"):'}]);if(!y)break;let x=a[y];if(x?.orcid)console.log(u.dim(` Current ORCID: ${x.orcid}`));let{orcid:v}=await X.prompt([{type:"input",name:"orcid",message:`ORCID for "${y}" (Enter to ${x?.orcid?"keep current":"skip"}):`,validate:(D)=>{if(!D)return!0;return vm.test(D)||"Invalid ORCID format (XXXX-XXXX-XXXX-XXXX)"}}]),_={};if(v)_.orcid=v;let{affiliation:E}=await X.prompt([{type:"input",name:"affiliation",message:`Affiliation for "${y}" (optional):`}]);if(E)_.affiliations=[{name:E}];if(_.orcid||_.affiliations)p[y]=_;let{more:S}=await X.prompt([{type:"confirm",name:"more",message:"Add another author?",default:!0}]);g=S}if(Object.keys(p).length>0){let y={...o.authors||{}};for(let[x,v]of Object.entries(p)){let _=y[x]||{};y[x]={..._,...v,orcid:v.orcid||_.orcid}}o.authors=y}}console.log(),console.log(u.cyan("--- Dataset stats ---"));let d=w("Computing dataset sizes and formats...").start();try{let p=await Sz(e),g=Qe(p.total_size);o.sizes=[`${g} (${p.file_count} files)`],o.formats=p.extensions,d.succeed(`Sizes: ${g} (${p.file_count} files), Formats: ${p.extensions.join(", ")}`)}catch(p){d.warn("Could not compute dataset stats"),console.log(u.dim(` ${U(p)}`))}console.log(),console.log(u.cyan("--- Review ---")),console.log(JSON.stringify(o,null,2)),console.log();let f=await Fe("Commit to repo and refresh DOI?",t,!0);if(f!=="confirmed"){console.log(u.dim(f==="declined"?"Skipped":"Cancelled"));return}let m=w("Saving enrichment...").start();try{let p=await qz(e,o);if(m.succeed(p.message),p.bidsignore_updated)console.log(u.dim(" .bidsignore updated to include .nemar/"));if(!i&&s)try{i=await dd(e)}catch(g){if(process.env.DEBUG)console.error("[debug] DOI info re-fetch:",g)}if(i?.ezid_identifier){let g=w("Refreshing DOI metadata...").start();try{await L_(e,{refresh_metadata:!0}),g.succeed("DOI metadata refreshed")}catch(y){g.warn("Could not refresh DOI metadata"),console.log(u.dim(` ${U(y)}`))}}else if(s)console.log(u.yellow(" DOI refresh skipped: could not verify DOI exists. Run 'nemar admin doi update --refresh' manually."))}catch(p){if(p instanceof M)m.fail(p.message);else m.fail("Failed to save enrichment"),console.log(u.dim(` ${U(p)}`))}});Ie.addCommand(Sd);var Vm=new Ee("publish").description("Publication workflow management");Vm.command("list").description("List publication requests").option("-s, --status <status>","Filter by status (requested, approving, published, denied)").addHelpText("after",`
244
244
  Description:
245
245
  List all publication requests from users, with optional filtering by status.
246
246
  Shows dataset ID, status, requesting user, and current progress.
@@ -357,7 +357,7 @@ Description:
357
357
  Requirements:
358
358
  - Dataset must not be a sandbox dataset
359
359
  - Dataset must have a GitHub repository
360
- - Must be dataset owner or admin
360
+ - Admin only; owners request publication via 'nemar dataset publish request'
361
361
 
362
362
  Examples:
363
363
  $ nemar admin make-public nm000104
@@ -369,7 +369,7 @@ WARNING: Publishing is PERMANENT and IRREVERSIBLE
369
369
  `)),console.log("This will:"),console.log(" 1. Make the GitHub repository PUBLIC"),console.log(" 2. Allow public S3 access to all dataset files"),console.log(` 3. Update git-annex configuration for web access
370
370
  `),console.log(`Dataset: ${u.cyan(r.dataset_id)} - ${r.name}`),r.owner_username)console.log(`Owner: ${r.owner_username}`);if(r.github_repo)console.log(`Repository: ${r.github_repo}`);if(console.log(),(await X.prompt([{type:"input",name:"datasetId",message:`Type '${t}' to confirm:`,validate:(s)=>{if(s.trim()===t)return!0;return`Please type exactly '${t}' to confirm`}}])).datasetId!==t)console.log(u.dim("Cancelled.")),process.exit(0);let i=w("Publishing dataset...").start();try{let s=await JV(t);i.succeed(u.green("Dataset published successfully")),console.log(`
371
371
  GitHub: ${u.cyan(s.github_url)}`),console.log(`S3: ${u.cyan(s.s3_url)}`)}catch(s){if(i.fail(u.red("Failed to publish dataset")),s instanceof M){if(console.error(u.red(`
372
- ${s.message}`)),s.details)console.error(u.dim(JSON.stringify(s.details,null,2)));if(s.statusCode===403)console.log(u.dim(" You must be the dataset owner or an admin to publish"));else if(s.statusCode===400&&s.message.includes("sandbox"))console.log(u.dim(" Sandbox datasets cannot be published"))}else console.error(u.red(`
372
+ ${s.message}`)),s.details)console.error(u.dim(JSON.stringify(s.details,null,2)));if(s.statusCode===403)console.log(u.dim(" Admin only; owners request publication via 'nemar dataset publish request'"));else if(s.statusCode===400&&s.message.includes("sandbox"))console.log(u.dim(" Sandbox datasets cannot be published"))}else console.error(u.red(`
373
373
  ${s instanceof Error?s.message:String(s)}`));process.exit(1)}});Ie.command("delete-dataset").description("Delete a dataset and all associated resources (GitHub, S3, D1)").argument("<dataset-id>","Dataset ID (e.g., nm000108)").option("--force","Force deletion of published datasets with DOIs (owner only)").action(async(e,t)=>{if(!oe())return;let r=w("Looking up dataset...").start();try{let n=await gt(e);if(r.stop(),console.log(u.bold(`
374
374
  Dataset: ${n.dataset_id}`)),console.log(` Name: ${n.name||"(unnamed)"}`),console.log(` Visibility: ${n.visibility}`),n.concept_doi){if(console.log(` DOI: ${n.concept_doi}`),console.log(u.yellow(`
375
375
  WARNING: This dataset has a DOI. Only the NEMAR owner can delete it.`)),!t.force)console.log(u.dim(" Use --force to confirm deletion of published datasets.")),process.exit(1)}let{proceed:i}=await X.prompt([{type:"confirm",name:"proceed",message:u.red(`Delete dataset ${e}? This will remove the GitHub repo, S3 data, and all database records. This cannot be undone.`),default:!1}]);if(!i){console.log(u.dim("Cancelled."));return}r.start("Deleting dataset...");let s=await rz(e,t.force??!1);if(!s.deleted)r.fail("Dataset deletion incomplete");else if(s.warnings.length>0)r.warn("Dataset deleted with warnings");else r.succeed("Dataset deleted");if(console.log(u.bold(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nemar-cli",
3
- "version": "0.9.10-dev.2069",
3
+ "version": "0.9.10-dev.2080",
4
4
  "description": "CLI for NEMAR (Neuroelectromagnetic Data Archive and Tools Resource) dataset management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",