@zenku/cli-node 0.1.29 → 0.1.30
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/package.json +1 -1
- package/zenku-bundle.cjs +1 -1
package/package.json
CHANGED
package/zenku-bundle.cjs
CHANGED
|
@@ -254,4 +254,4 @@ ${JSON.stringify(o.data,null,2)}
|
|
|
254
254
|
`),process.stdout.write(`Timezone: ${Q(o.timezone)}
|
|
255
255
|
`),process.stdout.write(`Next Run: ${qt(o.next)}
|
|
256
256
|
`)}})}),t.command("upsert").description("Create or update a scheduler").requiredOption("-q, --queue <name>","queue name").requiredOption("--id <id>","scheduler ID").requiredOption("--pattern <cron>","cron pattern").option("--timezone <tz>","timezone (e.g., America/New_York)").option("--data <json>","job data as JSON string").action(async n=>{let i={queue:n.queue,id:n.id,pattern:n.pattern};if(n.timezone&&(i.timezone=n.timezone),n.data)try{i.data=JSON.parse(n.data)}catch{D("invalid JSON for --data")}let r=await K("jobs"),o=await k("Upserting scheduler...",()=>r.mutate("schedulers.upsert",i));g({json:()=>o,human:()=>I("Scheduler upserted: %s",o.schedulerId)})}),t.command("remove").description("Remove a scheduler").requiredOption("-q, --queue <name>","queue name").argument("<id>","scheduler ID").action(async(n,i)=>{let r=await K("jobs");await k("Removing scheduler...",()=>r.mutate("schedulers.remove",{queue:i.queue,id:n})),g({json:()=>({success:!0,id:n,queue:i.queue}),human:()=>I("Scheduler %s removed",n)})}),e.addCommand(t),e.command("web").description("Open the Bull Board dashboard in the browser").option("--no-open","print the URL without opening the browser").action(async({open:n})=>{let i=oe(ue()),{profile:r}=se(i),o=r.services.jobs;o||D("no jobs API URL configured (run `zenku profile show` to check)");let a=`${o.replace(/\/+$/,"")}/dashboard`;if(n){let s=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";(0,kD.exec)(`${s} "${a}"`)}g({json:()=>({url:a}),human:()=>E("Opening %s",a)})}),e}function CD(e){e.addCommand(Lx())}var le=require("node:fs"),Se=require("node:path"),Un=require("node:os");function om(e){return e||(process.env.CLAUDE_CONFIG_DIR?process.env.CLAUDE_CONFIG_DIR:(0,Se.join)((0,Un.homedir)(),".claude"))}function ID(e){return e||(process.env.ZENKU_MACHINE_ID?process.env.ZENKU_MACHINE_ID:(0,Un.hostname)())}function am(e){let t=[],n;try{n=(0,le.readdirSync)(e,{withFileTypes:!0})}catch{return t}for(let i of n){let r=(0,Se.join)(e,i.name);i.isDirectory()?t.push(...am(r)):i.isFile()&&i.name.endsWith(".jsonl")&&t.push(r)}return t}function it(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function Mx(e,t){let n=(0,le.statSync)(e);return Date.now()-n.mtimeMs>=t*86400*1e3}function SD(e,t,n){let i=(0,Se.relative)(t,e);return`${n}/${i}`}function sm(e){return e.replace(/'/g,"\\'")}async function ED(e,t,n,i,r,o,a){let u=(0,le.statSync)(t).size,c=null;try{let p=await e.collection("session_files").getFirstListItem(`key='${sm(n)}'`);c={id:p.id,size:p.size}}catch{}if(c&&c.size===u)return{status:"skipped",key:n,size:u};if(a)return c?E("[DRY-RUN] Would update: %s (%s -> %s)",n,it(c.size),it(u)):E("[DRY-RUN] Would upload: %s (%s)",n,it(u)),{status:c?"updated":"uploaded",key:n,size:u};let l=(0,le.readFileSync)(t),d=new File([l],(0,Se.basename)(t),{type:"application/x-ndjson"});try{return c?(await e.collection("session_files").update(c.id,{size:u,file:d}),I("Updated: %s (%s -> %s)",n,it(c.size),it(u)),{status:"updated",key:n,size:u}):(await e.collection("session_files").create({key:n,machine_id:i,size:u,tenant_id:r,account_id:o,file:d}),I("Uploaded: %s (%s)",n,it(u)),{status:"uploaded",key:n,size:u})}catch(p){let f=p instanceof Error?p.message:String(p);return{status:"failed",key:n,size:u,error:f}}}function qx(){let e=new z("sessions").description("Upload and manage Claude Code session transcripts");return e.command("sync").description("Scan local Claude Code sessions and upload new/changed files").option("--machine-id <id>","machine identifier for R2 key namespacing").option("--claude-dir <path>","Claude config directory").option("--dry-run","show what would be uploaded without uploading").option("--cleanup-days <days>","delete local files older than N days after successful upload").action(async t=>{let n=om(t.claudeDir),i=ID(t.machineId),r=t.dryRun??!1,o=t.cleanupDays?Number(t.cleanupDays):0;o&&(Number.isNaN(o)||o<1)&&D("--cleanup-days requires a positive integer");let a=(0,Se.join)(n,"projects"),s=am(a);if(s.length===0){E("No session files found in %s",a);return}let{client:u,profile:c}=await P("library"),l=Ge(c),d=Je(c);o>0&&E("Cleanup mode: syncing files older than %s days",o),E("Scanning %s sessions in %s",s.length,a);let p=0,f=0,$=0,x=0,S=0,N=0;for(let H of s){if(o>0&&!Mx(H,o)){N++;continue}let O=SD(H,a,i),W=await ED(u,H,O,i,l,d,r);switch(W.status){case"uploaded":p++;break;case"updated":f++;break;case"skipped":$++;break;case"failed":E("Failed: %s \u2014 %s",O,W.error),x++;continue}if(o>0)if(r)E("[DRY-RUN] Would delete local: %s",H);else try{(0,le.unlinkSync)(H),S++}catch{E("Failed to delete local: %s",H)}}E(""),o>0?E("Summary: %s total, %s too new (<%sd), %s uploaded, %s updated, %s unchanged, %s deleted locally, %s failed",s.length,N,o,p,f,$,S,x):E("Summary: %s total, %s uploaded, %s updated, %s unchanged, %s failed",s.length,p,f,$,x)}),e.command("list").description("List Claude Code session files").option("--remote","list uploaded session files from PocketBase").option("--claude-dir <path>","Claude config directory").action(async t=>{if(t.remote){let{client:n}=await P("library"),i=await k("Fetching session files...",()=>n.collection("session_files").getList(1,200,{sort:"-created"}));g({json:()=>i.items,human:()=>{let r=i.items.map(o=>[o.id,o.key,o.machine_id,it(o.size),o.created]);L(["ID","KEY","MACHINE","SIZE","CREATED"],r)}})}else{let n=om(t.claudeDir),i=(0,Se.join)(n,"projects"),r=am(i);g({json:()=>r.map(o=>{let a=(0,le.statSync)(o);return{path:o,size:a.size,modified:a.mtime}}),human:()=>{let o=r.map(a=>{let s=(0,le.statSync)(a);return[(0,Se.relative)(i,a),it(s.size),s.mtime.toISOString().slice(0,19)]});L(["PATH","SIZE","MODIFIED"],o),E(`
|
|
257
|
-
%s files, %s total`,r.length,it(r.reduce((a,s)=>a+(0,le.statSync)(s).size,0)))}})}}),e.command("upload").description("Upload a single session file").option("--hook","hook mode: read session path from stdin JSON").option("--machine-id <id>","machine identifier for R2 key namespacing").option("--claude-dir <path>","Claude config directory").argument("[file]","path to .jsonl file (when not using --hook)").action(async(t,n)=>{let i=om(n.claudeDir),r=ID(n.machineId),o=(0,Se.join)(i,"projects"),a;if(n.hook){let f;try{f=(0,le.readFileSync)(0,"utf-8")}catch{D("failed to read from stdin")}let $;try{$=JSON.parse(f)}catch{D("invalid JSON on stdin")}let x=$.transcript_path;x||D("no transcript_path in hook input"),a=x.replace(/^~/,(0,Un.homedir)())}else t?a=t:D("provide a file path or use --hook to read from stdin");try{(0,le.statSync)(a)}catch{D("file not found: %s",a)}let s=SD(a,o,r),{client:u,profile:c}=await P("library"),l=Ge(c),d=Je(c),p=await ED(u,a,s,r,l,d,!1);p.status==="failed"&&D("upload failed: %s",p.error),g({json:()=>p,human:()=>{p.status==="skipped"&&E("Skipped (unchanged): %s",s)}})}),e.command("download").description("Download session files from PocketBase").argument("[dir]","output directory",".").option("--key <key>","download a specific file by key").option("--machine-id <id>","download all files from a specific machine").action(async(t,n)=>{let{client:i}=await P("library"),r=[];n.key&&r.push(`key='${sm(n.key)}'`),n.machineId&&r.push(`machine_id='${sm(n.machineId)}'`);let o=r.length>0?r.join(" && "):"",a=await k("Fetching session files...",()=>i.collection("session_files").getFullList({sort:"key",filter:o}));if(a.length===0){E("No session files found");return}E("Downloading %s files to %s",a.length,t);let s=await i.files.getToken(),u=0,c=0;for(let l of a){let d=l.key,p=l.file,f=(0,Se.join)(t,d),$=i.files.getURL(l,p,{token:s});try{let x=await fetch($);if(!x.ok){E("Failed: %s \u2014 HTTP %s",d,x.status),c++;continue}let S=Buffer.from(await x.arrayBuffer());(0,le.mkdirSync)((0,Se.dirname)(f),{recursive:!0}),(0,le.writeFileSync)(f,S),I("Downloaded: %s (%s)",d,it(S.length)),u++}catch(x){let S=x instanceof Error?x.message:String(x);E("Failed: %s \u2014 %s",d,S),c++}}E(""),E("Summary: %s total, %s downloaded, %s failed",a.length,u,c),g({json:()=>a.map(l=>({id:l.id,key:l.key,machine_id:l.machine_id,size:l.size})),human:()=>{}})}),e}function FD(e){e.addCommand(qx())}var ha=require("node:child_process"),he=require("node:fs"),zD=require("node:os"),St=require("node:path");function OD(){return!0}var PD="https://registry.npmjs.org",Vx=15e3,AD="@zenku";function Wx(){let{platform:e,arch:t}=process,n=["darwin-arm64","darwin-x64","linux-arm64","linux-x64"],i=`${e}-${t}`;return n.includes(i)||D("Unsupported platform: %s",i),`cli-${i}`}async function Gx(e){let t=`${PD}/${AD}/${e}/latest`,n=new AbortController,i=setTimeout(()=>n.abort(),Vx);try{let r=await fetch(t,{signal:n.signal});if(!r.ok)throw new Error(`HTTP ${r.status}`);return(await r.json()).version}catch(r){throw r instanceof DOMException&&r.name==="AbortError"?new Error("request timed out"):r}finally{clearTimeout(i)}}function Jx(e,t){let n=`${e}-${t}.tgz`,i=`${PD}/${AD}/${e}/-/${n}`,r=(0,he.mkdtempSync)((0,St.join)((0,zD.tmpdir)(),"zenku-upgrade-"));try{(0,ha.execSync)(`curl -fsSL "${i}" -o "${(0,St.join)(r,n)}"`,{stdio:"pipe"}),(0,ha.execSync)(`tar xzf "${(0,St.join)(r,n)}" -C "${r}"`,{stdio:"pipe"});let o=(0,St.join)(r,"package","zenku"),a=process.execPath,s=(0,St.dirname)(a),u=(0,St.join)(s,`.zenku-upgrade-${process.pid}`),c=!1;try{(0,he.accessSync)(s,he.constants.W_OK)}catch{c=!0}if(c)(0,ha.execSync)(`sudo install -m 755 "${o}" "${a}"`,{stdio:"inherit"});else{(0,he.copyFileSync)(o,u),(0,he.chmodSync)(u,493);try{(0,he.renameSync)(u,a)}catch{try{(0,he.unlinkSync)(u)}catch{}throw new Error(`failed to replace binary at ${a}`)}}}finally{(0,he.rmSync)(r,{recursive:!0,force:!0})}}function TD(e){e.addCommand(new z("upgrade").description("Upgrade zenku to the latest version").action(async()=>{if(OD()){g({json:()=>({mode:"bundle",message:"Self-upgrade not available in bundle mode. Use: npm update -g @zenku/cli-node"}),human:()=>{E("Self-upgrade is not available in bundle mode."),E("Update via npm: npm update -g @zenku/cli-node")}});return}let t=um(),n=Wx(),i=await k("Checking for updates...",()=>Gx(n));if(t===i){g({json:()=>({previous:t,latest:i,upgraded:!1}),human:()=>E("Already up to date (v%s).",t)});return}E("v%s \u2192 v%s",t,i),await k(`Downloading v${i}...`,async()=>{Jx(n,i)}),g({json:()=>({previous:t,latest:i,upgraded:!0}),human:()=>E("Upgraded zenku to v%s.",i)})}))}var Kx={};function um(){return"0.1.
|
|
257
|
+
%s files, %s total`,r.length,it(r.reduce((a,s)=>a+(0,le.statSync)(s).size,0)))}})}}),e.command("upload").description("Upload a single session file").option("--hook","hook mode: read session path from stdin JSON").option("--machine-id <id>","machine identifier for R2 key namespacing").option("--claude-dir <path>","Claude config directory").argument("[file]","path to .jsonl file (when not using --hook)").action(async(t,n)=>{let i=om(n.claudeDir),r=ID(n.machineId),o=(0,Se.join)(i,"projects"),a;if(n.hook){let f;try{f=(0,le.readFileSync)(0,"utf-8")}catch{D("failed to read from stdin")}let $;try{$=JSON.parse(f)}catch{D("invalid JSON on stdin")}let x=$.transcript_path;x||D("no transcript_path in hook input"),a=x.replace(/^~/,(0,Un.homedir)())}else t?a=t:D("provide a file path or use --hook to read from stdin");try{(0,le.statSync)(a)}catch{D("file not found: %s",a)}let s=SD(a,o,r),{client:u,profile:c}=await P("library"),l=Ge(c),d=Je(c),p=await ED(u,a,s,r,l,d,!1);p.status==="failed"&&D("upload failed: %s",p.error),g({json:()=>p,human:()=>{p.status==="skipped"&&E("Skipped (unchanged): %s",s)}})}),e.command("download").description("Download session files from PocketBase").argument("[dir]","output directory",".").option("--key <key>","download a specific file by key").option("--machine-id <id>","download all files from a specific machine").action(async(t,n)=>{let{client:i}=await P("library"),r=[];n.key&&r.push(`key='${sm(n.key)}'`),n.machineId&&r.push(`machine_id='${sm(n.machineId)}'`);let o=r.length>0?r.join(" && "):"",a=await k("Fetching session files...",()=>i.collection("session_files").getFullList({sort:"key",filter:o}));if(a.length===0){E("No session files found");return}E("Downloading %s files to %s",a.length,t);let s=await i.files.getToken(),u=0,c=0;for(let l of a){let d=l.key,p=l.file,f=(0,Se.join)(t,d),$=i.files.getURL(l,p,{token:s});try{let x=await fetch($);if(!x.ok){E("Failed: %s \u2014 HTTP %s",d,x.status),c++;continue}let S=Buffer.from(await x.arrayBuffer());(0,le.mkdirSync)((0,Se.dirname)(f),{recursive:!0}),(0,le.writeFileSync)(f,S),I("Downloaded: %s (%s)",d,it(S.length)),u++}catch(x){let S=x instanceof Error?x.message:String(x);E("Failed: %s \u2014 %s",d,S),c++}}E(""),E("Summary: %s total, %s downloaded, %s failed",a.length,u,c),g({json:()=>a.map(l=>({id:l.id,key:l.key,machine_id:l.machine_id,size:l.size})),human:()=>{}})}),e}function FD(e){e.addCommand(qx())}var ha=require("node:child_process"),he=require("node:fs"),zD=require("node:os"),St=require("node:path");function OD(){return!0}var PD="https://registry.npmjs.org",Vx=15e3,AD="@zenku";function Wx(){let{platform:e,arch:t}=process,n=["darwin-arm64","darwin-x64","linux-arm64","linux-x64"],i=`${e}-${t}`;return n.includes(i)||D("Unsupported platform: %s",i),`cli-${i}`}async function Gx(e){let t=`${PD}/${AD}/${e}/latest`,n=new AbortController,i=setTimeout(()=>n.abort(),Vx);try{let r=await fetch(t,{signal:n.signal});if(!r.ok)throw new Error(`HTTP ${r.status}`);return(await r.json()).version}catch(r){throw r instanceof DOMException&&r.name==="AbortError"?new Error("request timed out"):r}finally{clearTimeout(i)}}function Jx(e,t){let n=`${e}-${t}.tgz`,i=`${PD}/${AD}/${e}/-/${n}`,r=(0,he.mkdtempSync)((0,St.join)((0,zD.tmpdir)(),"zenku-upgrade-"));try{(0,ha.execSync)(`curl -fsSL "${i}" -o "${(0,St.join)(r,n)}"`,{stdio:"pipe"}),(0,ha.execSync)(`tar xzf "${(0,St.join)(r,n)}" -C "${r}"`,{stdio:"pipe"});let o=(0,St.join)(r,"package","zenku"),a=process.execPath,s=(0,St.dirname)(a),u=(0,St.join)(s,`.zenku-upgrade-${process.pid}`),c=!1;try{(0,he.accessSync)(s,he.constants.W_OK)}catch{c=!0}if(c)(0,ha.execSync)(`sudo install -m 755 "${o}" "${a}"`,{stdio:"inherit"});else{(0,he.copyFileSync)(o,u),(0,he.chmodSync)(u,493);try{(0,he.renameSync)(u,a)}catch{try{(0,he.unlinkSync)(u)}catch{}throw new Error(`failed to replace binary at ${a}`)}}}finally{(0,he.rmSync)(r,{recursive:!0,force:!0})}}function TD(e){e.addCommand(new z("upgrade").description("Upgrade zenku to the latest version").action(async()=>{if(OD()){g({json:()=>({mode:"bundle",message:"Self-upgrade not available in bundle mode. Use: npm update -g @zenku/cli-node"}),human:()=>{E("Self-upgrade is not available in bundle mode."),E("Update via npm: npm update -g @zenku/cli-node")}});return}let t=um(),n=Wx(),i=await k("Checking for updates...",()=>Gx(n));if(t===i){g({json:()=>({previous:t,latest:i,upgraded:!1}),human:()=>E("Already up to date (v%s).",t)});return}E("v%s \u2192 v%s",t,i),await k(`Downloading v${i}...`,async()=>{Jx(n,i)}),g({json:()=>({previous:t,latest:i,upgraded:!0}),human:()=>E("Upgraded zenku to v%s.",i)})}))}var Kx={};function um(){return"0.1.30"}function ND(){let e=new z;return e.name("zenku").description("Zenku CLI \u2014 manage PocketBase services from the terminal.").version(um()).option("--profile <name>","config profile to use").option("--tenant <id>","override tenant ID for this command").option("--account <id>","override account ID for this command").option("--json","output as JSON").option("--interactive","force interactive mode").option("--non-interactive","force non-interactive mode").hook("preAction",t=>{let n=t.optsWithGlobals();Mv(n.profile??""),Ev(n.tenant??""),Fv(n.account??""),Cv(!!n.json),n.interactive&&n.nonInteractive&&D("--interactive and --non-interactive cannot be used together"),n.interactive?Ld("interactive"):n.nonInteractive&&Ld("non-interactive")}),e.commandsGroup("Core Commands:"),rD(e),oD(e),sD(e),wD(e),e.commandsGroup("Platform Commands:"),Qv(e),eD(e),CD(e),e.commandsGroup("Auth & Config:"),Gv(e),Jv(e),Kv(e),Yv(e),e.commandsGroup("Other:"),FD(e),TD(e),e.addHelpCommand(new z("help").argument("[command]")),e}var Hx=ND();Hx.parse();
|