@lobehub/cli 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/man/man1/lh.1 +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -491,7 +491,7 @@ ${e.pageContent}
|
|
|
491
491
|
`)}return}if(!d.body){U.error(`No response body received`),process.exit(1);return}await toe(d.body,t.json)})}async function toe(e,t){let n=e.getReader(),r=new TextDecoder,i=``;try{for(;;){let{done:e,value:a}=await n.read();if(e)break;i+=r.decode(a,{stream:!0});let o=i.split(`
|
|
492
492
|
`);i=o.pop()||``;for(let e of o){if(!e.startsWith(`data:`))continue;let n=e.slice(5).trim();if(n===`[DONE]`){t||process.stdout.write(`
|
|
493
493
|
`);return}try{let e=JSON.parse(n);t?console.log(JSON.stringify(e)):typeof e==`string`&&e!==`stop`?process.stdout.write(e):e?.choices?.[0]?.delta?.content&&process.stdout.write(e.choices[0].delta.content)}catch{t||process.stdout.write(n)}}}t||process.stdout.write(`
|
|
494
|
-
`)}finally{n.releaseLock()}}function noe(e){e.command(`tts <text>`).description(`Convert text to speech`).option(`-o, --output <file>`,`Output audio file path`,`output.mp3`).option(`--voice <voice>`,`Voice name`,`alloy`).option(`--speed <n>`,`Speed multiplier (0.25-4.0)`,`1`).option(`--model <model>`,`TTS model`,`tts-1`).option(`--backend <backend>`,`TTS backend: openai, microsoft, edge`,`openai`).action(async(e,t)=>{let n=[`openai`,`microsoft`,`edge`];if(!n.includes(t.backend)){U.error(`Invalid backend. Must be one of: ${n.join(`, `)}`),process.exit(1);return}let{serverUrl:r,headers:i}=await mr(),a={input:e,model:t.model,options:{model:t.model,voice:t.voice},speed:Number.parseFloat(t.speed),voice:t.voice},o=await fetch(`${r}/webapi/tts/${t.backend}`,{body:JSON.stringify(a),headers:i,method:`POST`});if(!o.ok){let e=await o.text();U.error(`TTS failed: ${o.status} ${e}`),process.exit(1);return}let s=Buffer.from(await o.arrayBuffer());u(t.output,s),console.log(`${V.default.green(`✓`)} Audio saved to ${V.default.bold(t.output)} (${Math.round(s.length/1024)}KB)`)})}function roe(e){e.command(`video <prompt>`).description(`Generate a video from text`).requiredOption(`-m, --model <model>`,`Model ID`).requiredOption(`-p, --provider <provider>`,`Provider name`).option(`--aspect-ratio <ratio>`,`Aspect ratio (e.g. 16:9)`).option(`--duration <sec>`,`Duration in seconds`).option(`--resolution <res>`,`Resolution (e.g. 720p, 1080p)`).option(`--seed <n>`,`Random seed`).option(`--json`,`Output raw JSON`).action(async(e,t)=>{let n=await W(),r=await n.generationTopic.createTopic.mutate({type:`video`}),i={prompt:e};t.aspectRatio&&(i.aspectRatio=t.aspectRatio),t.duration&&(i.duration=Number.parseInt(t.duration,10)),t.resolution&&(i.resolution=t.resolution),t.seed&&(i.seed=Number.parseInt(t.seed,10));let a=await n.video.createVideo.mutate({generationTopicId:r,model:t.model,params:i,provider:t.provider});if(t.json){console.log(JSON.stringify(a,null,2));return}let o=a.data||a;console.log(`${V.default.green(`✓`)} Video generation started`),o.batch?.id&&console.log(` Batch ID: ${V.default.bold(o.batch.id)}`);let s=o.generations||[];if(s.length>0){for(let e of s)e.asyncTaskId&&console.log(` Generation ${V.default.bold(e.id)} → Task ${V.default.dim(e.asyncTaskId)}`);console.log(),console.log(V.default.dim(`Use "lh generate status <generationId> <taskId>" to check progress.`))}})}function ioe(e){let t=e.command(`generate`).alias(`gen`).description(`Generate content (text, image, video, speech)`);eoe(t),$ae(t),roe(t),noe(t),Zae(t),t.command(`status <generationId> <taskId>`).description(`Check generation task status`).option(`--json`,`Output raw JSON`).action(async(e,t,n)=>{let r=await(await W()).generation.getGenerationStatus.query({asyncTaskId:t,generationId:e});if(n.json){console.log(JSON.stringify(r,null,2));return}let i=r;if(console.log(`Status: ${z9(i.status)}`),i.error&&console.log(`Error: ${V.default.red(i.error.message||JSON.stringify(i.error))}`),i.generation){let e=i.generation;console.log(` ID: ${e.id}`),e.asset?.url&&console.log(` URL: ${e.asset.url}`),e.asset?.thumbnailUrl&&console.log(` Thumb: ${e.asset.thumbnailUrl}`)}}),t.command(`download <generationId> <taskId>`).description(`Wait for generation to complete and download the result`).option(`-o, --output <path>`,`Output file path (default: auto-detect from asset)`).option(`--interval <sec>`,`Polling interval in seconds`,`5`).option(`--timeout <sec>`,`Timeout in seconds (0 = no timeout)`,`300`).action(async(e,t,n)=>{let r=await W(),i=Number.parseInt(n.interval||`5`,10)*1e3,a=Number.parseInt(n.timeout||`300`,10)*1e3,o=Date.now();for(console.log(`${V.default.yellow(`⋯`)} Waiting for generation ${V.default.bold(e)}...`);;){let s=await r.generation.getGenerationStatus.query({asyncTaskId:t,generationId:e});if(s.status===`success`&&s.generation){let t=s.generation,r=t.asset?.url;r||(console.log(`${V.default.red(`✗`)} Generation succeeded but no asset URL found.`),process.exit(1));let i=r.split(`?`)[0].split(`.`).pop()||`bin`,a=n.output||`${e}.${i}`;console.log(`${V.default.green(`✓`)} Generation complete. Downloading...`);let o=await fetch(r);o.ok||(console.log(`${V.default.red(`✗`)} Download failed: ${o.status} ${o.statusText}`),process.exit(1));let{writeFile:c}=await import(`node:fs/promises`),l=Buffer.from(await o.arrayBuffer());await c(a,l),console.log(`${V.default.green(`✓`)} Saved to ${V.default.bold(a)} (${(l.length/1024).toFixed(1)} KB)`),t.asset?.thumbnailUrl&&console.log(` Thumbnail: ${V.default.dim(t.asset.thumbnailUrl)}`);return}if(s.status===`error`){let e=s.error?.body?.detail||s.error?.message||JSON.stringify(s.error);console.log(`${V.default.red(`✗`)} Generation failed: ${e}`),process.exit(1)}a>0&&Date.now()-o>a&&(console.log(`${V.default.red(`✗`)} Timed out after ${n.timeout}s. Task still ${s.status}.`),console.log(V.default.dim(`Run "lh gen status ${e} ${t}" to check later.`)),process.exit(1)),process.stdout.write(`\r${V.default.yellow(`⋯`)} Status: ${z9(s.status)}... (${Math.round((Date.now()-o)/1e3)}s)`),await new Promise(e=>setTimeout(e,i))}}),t.command(`delete <generationId>`).description(`Delete a generation record`).option(`--yes`,`Skip confirmation prompt`).action(async(e,t)=>{if(!t.yes&&!await ii(`Are you sure you want to delete this generation?`)){console.log(`Cancelled.`);return}await(await W()).generation.deleteGeneration.mutate({generationId:e}),console.log(`${V.default.green(`✓`)} Deleted generation ${V.default.bold(e)}`)}),t.command(`list`).description(`List generation topics`).option(`--json [fields]`,`Output JSON, optionally specify fields (comma-separated)`).action(async e=>{let t=await(await W()).generationTopic.getAllGenerationTopics.query(),n=Array.isArray(t)?t:[];if(e.json!==void 0){$r(n,typeof e.json==`string`?e.json:void 0);return}if(n.length===0){console.log(`No generation topics found.`);return}Gr(n.map(e=>[e.id||``,Wr(e.title||`Untitled`,40),e.type||``,e.updatedAt?Ur(e.updatedAt):``]),[`ID`,`TITLE`,`TYPE`,`UPDATED`])})}function z9(e){switch(e){case`success`:return V.default.green(e);case`error`:return V.default.red(e);case`processing`:return V.default.yellow(e);case`pending`:return V.default.cyan(e);default:return e}}function aoe(e){if(!e)return``;let t={"application/msword":`doc`,"application/pdf":`pdf`,"application/vnd.openxmlformats-officedocument.presentationml.presentation":`pptx`,"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":`xlsx`,"application/vnd.openxmlformats-officedocument.wordprocessingml.document":`docx`,"custom/folder":`folder`,"text/markdown":`md`,"text/plain":`txt`};if(t[e])return t[e];let n=e.split(`/`);return n.length>1?n[1]:e}function ooe(e){let t=e.command(`kb`).description(`Manage knowledge bases, folders, documents, and files`);t.command(`list`).description(`List knowledge bases`).option(`--json [fields]`,`Output JSON, optionally specify fields (comma-separated)`).action(async e=>{let t=await(await W()).knowledgeBase.getKnowledgeBases.query(),n=Array.isArray(t)?t:[];if(e.json!==void 0){$r(n,typeof e.json==`string`?e.json:void 0);return}if(n.length===0){console.log(`No knowledge bases found.`);return}Gr(n.map(e=>[e.id,Wr(e.name||`Untitled`,40),Wr(e.description||``,50),e.updatedAt?Ur(e.updatedAt):``]),[`ID`,`NAME`,`DESCRIPTION`,`UPDATED`])}),t.command(`view <id>`).description(`View a knowledge base`).option(`--json [fields]`,`Output JSON, optionally specify fields (comma-separated)`).action(async(e,t)=>{let n=await W(),r=await n.knowledgeBase.getKnowledgeBaseById.query({id:e});if(!r){U.error(`Knowledge base not found: ${e}`),process.exit(1);return}let i=[];async function a(t,r=0){let o=0,s=!0;for(;s;){let c={knowledgeBaseId:e,limit:100,offset:o,parentId:t},l=await n.file.getKnowledgeItems.query(c),u=Array.isArray(l)?l:l.items??[];s=Array.isArray(l)?!1:l.hasMore??!1,o+=u.length;let d=[];for(let e of u)i.push({...e,_depth:r}),e.fileType===`custom/folder`&&d.push(e);d.length>0&&await Promise.all(d.map(e=>a(e.id,r+1)))}}if(await a(null),t.json!==void 0){let e=typeof t.json==`string`?t.json:void 0;$r({...r,files:i},e);return}console.log(V.default.bold(r.name||`Untitled`));let o=[];r.description&&o.push(r.description),r.updatedAt&&o.push(`Updated ${Ur(r.updatedAt)}`),o.length>0&&console.log(V.default.dim(o.join(` · `))),i.length>0?(console.log(),console.log(V.default.bold(`Items (${i.length}):`)),Gr(i.map(e=>{let t=` `.repeat(e._depth),n=e.name||e.filename||``;return[e.id,e.sourceType===`document`?`Doc`:`File`,Wr(`${t}${n}`,45),aoe(e.fileType||``),e.size?`${Math.round(e.size/1024)}KB`:``]}),[`ID`,`SOURCE`,`NAME`,`TYPE`,`SIZE`])):console.log(V.default.dim(`
|
|
494
|
+
`)}finally{n.releaseLock()}}function noe(e){e.command(`tts <text>`).description(`Convert text to speech`).option(`-o, --output <file>`,`Output audio file path`,`output.mp3`).option(`--voice <voice>`,`Voice name`,`alloy`).option(`--speed <n>`,`Speed multiplier (0.25-4.0)`,`1`).option(`--model <model>`,`TTS model`,`tts-1`).option(`--backend <backend>`,`TTS backend: openai, microsoft, edge`,`openai`).action(async(e,t)=>{let n=[`openai`,`microsoft`,`edge`];if(!n.includes(t.backend)){U.error(`Invalid backend. Must be one of: ${n.join(`, `)}`),process.exit(1);return}let{serverUrl:r,headers:i}=await mr(),a={input:e,model:t.model,options:{model:t.model,voice:t.voice},speed:Number.parseFloat(t.speed),voice:t.voice},o=await fetch(`${r}/webapi/tts/${t.backend}`,{body:JSON.stringify(a),headers:i,method:`POST`});if(!o.ok){let e=await o.text();U.error(`TTS failed: ${o.status} ${e}`),process.exit(1);return}let s=Buffer.from(await o.arrayBuffer());u(t.output,s),console.log(`${V.default.green(`✓`)} Audio saved to ${V.default.bold(t.output)} (${Math.round(s.length/1024)}KB)`)})}function roe(e){e.command(`video <prompt>`).description(`Generate a video from text or image(s)`).requiredOption(`-m, --model <model>`,`Model ID`).requiredOption(`-p, --provider <provider>`,`Provider name`).option(`--aspect-ratio <ratio>`,`Aspect ratio (e.g. 16:9)`).option(`--duration <sec>`,`Duration in seconds`).option(`--resolution <res>`,`Resolution (e.g. 720p, 1080p)`).option(`--seed <n>`,`Random seed`).option(`--image <url>`,`First-frame image URL (image-to-video)`).option(`--images <urls...>`,`Multiple reference image URLs`).option(`--end-image <url>`,`Last-frame image URL`).option(`--json`,`Output raw JSON`).action(async(e,t)=>{let n=await W(),r=await n.generationTopic.createTopic.mutate({type:`video`}),i={prompt:e};t.aspectRatio&&(i.aspectRatio=t.aspectRatio),t.duration&&(i.duration=Number.parseInt(t.duration,10)),t.resolution&&(i.resolution=t.resolution),t.seed&&(i.seed=Number.parseInt(t.seed,10)),t.image&&(i.imageUrl=t.image),t.images&&t.images.length>0&&(i.imageUrls=t.images),t.endImage&&(i.endImageUrl=t.endImage);let a=await n.video.createVideo.mutate({generationTopicId:r,model:t.model,params:i,provider:t.provider});if(t.json){console.log(JSON.stringify(a,null,2));return}let o=a.data||a;console.log(`${V.default.green(`✓`)} Video generation started`),o.batch?.id&&console.log(` Batch ID: ${V.default.bold(o.batch.id)}`);let s=o.generations||[];if(s.length>0){for(let e of s)e.asyncTaskId&&console.log(` Generation ${V.default.bold(e.id)} → Task ${V.default.dim(e.asyncTaskId)}`);console.log(),console.log(V.default.dim(`Use "lh generate status <generationId> <taskId>" to check progress.`))}})}function ioe(e){let t=e.command(`generate`).alias(`gen`).description(`Generate content (text, image, video, speech)`);eoe(t),$ae(t),roe(t),noe(t),Zae(t),t.command(`status <generationId> <taskId>`).description(`Check generation task status`).option(`--json`,`Output raw JSON`).action(async(e,t,n)=>{let r=await(await W()).generation.getGenerationStatus.query({asyncTaskId:t,generationId:e});if(n.json){console.log(JSON.stringify(r,null,2));return}let i=r;if(console.log(`Status: ${z9(i.status)}`),i.error&&console.log(`Error: ${V.default.red(i.error.message||JSON.stringify(i.error))}`),i.generation){let e=i.generation;console.log(` ID: ${e.id}`),e.asset?.url&&console.log(` URL: ${e.asset.url}`),e.asset?.thumbnailUrl&&console.log(` Thumb: ${e.asset.thumbnailUrl}`)}}),t.command(`download <generationId> <taskId>`).description(`Wait for generation to complete and download the result`).option(`-o, --output <path>`,`Output file path (default: auto-detect from asset)`).option(`--interval <sec>`,`Polling interval in seconds`,`5`).option(`--timeout <sec>`,`Timeout in seconds (0 = no timeout)`,`300`).action(async(e,t,n)=>{let r=await W(),i=Number.parseInt(n.interval||`5`,10)*1e3,a=Number.parseInt(n.timeout||`300`,10)*1e3,o=Date.now();for(console.log(`${V.default.yellow(`⋯`)} Waiting for generation ${V.default.bold(e)}...`);;){let s=await r.generation.getGenerationStatus.query({asyncTaskId:t,generationId:e});if(s.status===`success`&&s.generation){let t=s.generation,r=t.asset?.url;r||(console.log(`${V.default.red(`✗`)} Generation succeeded but no asset URL found.`),process.exit(1));let i=r.split(`?`)[0].split(`.`).pop()||`bin`,a=n.output||`${e}.${i}`;console.log(`${V.default.green(`✓`)} Generation complete. Downloading...`);let o=await fetch(r);o.ok||(console.log(`${V.default.red(`✗`)} Download failed: ${o.status} ${o.statusText}`),process.exit(1));let{writeFile:c}=await import(`node:fs/promises`),l=Buffer.from(await o.arrayBuffer());await c(a,l),console.log(`${V.default.green(`✓`)} Saved to ${V.default.bold(a)} (${(l.length/1024).toFixed(1)} KB)`),t.asset?.thumbnailUrl&&console.log(` Thumbnail: ${V.default.dim(t.asset.thumbnailUrl)}`);return}if(s.status===`error`){let e=s.error?.body?.detail||s.error?.message||JSON.stringify(s.error);console.log(`${V.default.red(`✗`)} Generation failed: ${e}`),process.exit(1)}a>0&&Date.now()-o>a&&(console.log(`${V.default.red(`✗`)} Timed out after ${n.timeout}s. Task still ${s.status}.`),console.log(V.default.dim(`Run "lh gen status ${e} ${t}" to check later.`)),process.exit(1)),process.stdout.write(`\r${V.default.yellow(`⋯`)} Status: ${z9(s.status)}... (${Math.round((Date.now()-o)/1e3)}s)`),await new Promise(e=>setTimeout(e,i))}}),t.command(`delete <generationId>`).description(`Delete a generation record`).option(`--yes`,`Skip confirmation prompt`).action(async(e,t)=>{if(!t.yes&&!await ii(`Are you sure you want to delete this generation?`)){console.log(`Cancelled.`);return}await(await W()).generation.deleteGeneration.mutate({generationId:e}),console.log(`${V.default.green(`✓`)} Deleted generation ${V.default.bold(e)}`)}),t.command(`list`).description(`List generation topics`).option(`--json [fields]`,`Output JSON, optionally specify fields (comma-separated)`).action(async e=>{let t=await(await W()).generationTopic.getAllGenerationTopics.query(),n=Array.isArray(t)?t:[];if(e.json!==void 0){$r(n,typeof e.json==`string`?e.json:void 0);return}if(n.length===0){console.log(`No generation topics found.`);return}Gr(n.map(e=>[e.id||``,Wr(e.title||`Untitled`,40),e.type||``,e.updatedAt?Ur(e.updatedAt):``]),[`ID`,`TITLE`,`TYPE`,`UPDATED`])})}function z9(e){switch(e){case`success`:return V.default.green(e);case`error`:return V.default.red(e);case`processing`:return V.default.yellow(e);case`pending`:return V.default.cyan(e);default:return e}}function aoe(e){if(!e)return``;let t={"application/msword":`doc`,"application/pdf":`pdf`,"application/vnd.openxmlformats-officedocument.presentationml.presentation":`pptx`,"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":`xlsx`,"application/vnd.openxmlformats-officedocument.wordprocessingml.document":`docx`,"custom/folder":`folder`,"text/markdown":`md`,"text/plain":`txt`};if(t[e])return t[e];let n=e.split(`/`);return n.length>1?n[1]:e}function ooe(e){let t=e.command(`kb`).description(`Manage knowledge bases, folders, documents, and files`);t.command(`list`).description(`List knowledge bases`).option(`--json [fields]`,`Output JSON, optionally specify fields (comma-separated)`).action(async e=>{let t=await(await W()).knowledgeBase.getKnowledgeBases.query(),n=Array.isArray(t)?t:[];if(e.json!==void 0){$r(n,typeof e.json==`string`?e.json:void 0);return}if(n.length===0){console.log(`No knowledge bases found.`);return}Gr(n.map(e=>[e.id,Wr(e.name||`Untitled`,40),Wr(e.description||``,50),e.updatedAt?Ur(e.updatedAt):``]),[`ID`,`NAME`,`DESCRIPTION`,`UPDATED`])}),t.command(`view <id>`).description(`View a knowledge base`).option(`--json [fields]`,`Output JSON, optionally specify fields (comma-separated)`).action(async(e,t)=>{let n=await W(),r=await n.knowledgeBase.getKnowledgeBaseById.query({id:e});if(!r){U.error(`Knowledge base not found: ${e}`),process.exit(1);return}let i=[];async function a(t,r=0){let o=0,s=!0;for(;s;){let c={knowledgeBaseId:e,limit:100,offset:o,parentId:t},l=await n.file.getKnowledgeItems.query(c),u=Array.isArray(l)?l:l.items??[];s=Array.isArray(l)?!1:l.hasMore??!1,o+=u.length;let d=[];for(let e of u)i.push({...e,_depth:r}),e.fileType===`custom/folder`&&d.push(e);d.length>0&&await Promise.all(d.map(e=>a(e.id,r+1)))}}if(await a(null),t.json!==void 0){let e=typeof t.json==`string`?t.json:void 0;$r({...r,files:i},e);return}console.log(V.default.bold(r.name||`Untitled`));let o=[];r.description&&o.push(r.description),r.updatedAt&&o.push(`Updated ${Ur(r.updatedAt)}`),o.length>0&&console.log(V.default.dim(o.join(` · `))),i.length>0?(console.log(),console.log(V.default.bold(`Items (${i.length}):`)),Gr(i.map(e=>{let t=` `.repeat(e._depth),n=e.name||e.filename||``;return[e.id,e.sourceType===`document`?`Doc`:`File`,Wr(`${t}${n}`,45),aoe(e.fileType||``),e.size?`${Math.round(e.size/1024)}KB`:``]}),[`ID`,`SOURCE`,`NAME`,`TYPE`,`SIZE`])):console.log(V.default.dim(`
|
|
495
495
|
No files in this knowledge base.`))}),t.command(`create`).description(`Create a knowledge base`).requiredOption(`-n, --name <name>`,`Knowledge base name`).option(`-d, --description <desc>`,`Description`).option(`--avatar <url>`,`Avatar URL`).action(async e=>{let t=await W(),n={name:e.name};e.description&&(n.description=e.description),e.avatar&&(n.avatar=e.avatar);let r=await t.knowledgeBase.createKnowledgeBase.mutate(n);console.log(`${V.default.green(`✓`)} Created knowledge base ${V.default.bold(String(r))}`)}),t.command(`edit <id>`).description(`Update a knowledge base`).option(`-n, --name <name>`,`New name`).option(`-d, --description <desc>`,`New description`).option(`--avatar <url>`,`New avatar URL`).action(async(e,t)=>{!t.name&&!t.description&&!t.avatar&&(U.error(`No changes specified. Use --name, --description, or --avatar.`),process.exit(1));let n=await W(),r={};t.name&&(r.name=t.name),t.description&&(r.description=t.description),t.avatar&&(r.avatar=t.avatar),await n.knowledgeBase.updateKnowledgeBase.mutate({id:e,value:r}),console.log(`${V.default.green(`✓`)} Updated knowledge base ${V.default.bold(e)}`)}),t.command(`delete <id>`).description(`Delete a knowledge base`).option(`--remove-files`,`Also delete associated files`).option(`--yes`,`Skip confirmation prompt`).action(async(e,t)=>{if(!t.yes&&!await ii(`Are you sure you want to delete this knowledge base?`)){console.log(`Cancelled.`);return}await(await W()).knowledgeBase.removeKnowledgeBase.mutate({id:e,removeFiles:t.removeFiles}),console.log(`${V.default.green(`✓`)} Deleted knowledge base ${V.default.bold(e)}`)}),t.command(`add-files <knowledgeBaseId>`).description(`Add files to a knowledge base`).requiredOption(`--ids <ids...>`,`File IDs to add`).action(async(e,t)=>{await(await W()).knowledgeBase.addFilesToKnowledgeBase.mutate({ids:t.ids,knowledgeBaseId:e}),console.log(`${V.default.green(`✓`)} Added ${t.ids.length} file(s) to knowledge base ${V.default.bold(e)}`)}),t.command(`remove-files <knowledgeBaseId>`).description(`Remove files from a knowledge base`).requiredOption(`--ids <ids...>`,`File IDs to remove`).option(`--yes`,`Skip confirmation prompt`).action(async(e,t)=>{if(!t.yes&&!await ii(`Remove ${t.ids.length} file(s) from knowledge base?`)){console.log(`Cancelled.`);return}await(await W()).knowledgeBase.removeFilesFromKnowledgeBase.mutate({ids:t.ids,knowledgeBaseId:e}),console.log(`${V.default.green(`✓`)} Removed ${t.ids.length} file(s) from knowledge base ${V.default.bold(e)}`)}),t.command(`mkdir <knowledgeBaseId>`).description(`Create a folder in a knowledge base`).requiredOption(`-n, --name <name>`,`Folder name`).option(`--parent <parentId>`,`Parent folder ID`).action(async(e,t)=>{let n=await(await W()).document.createDocument.mutate({editorData:JSON.stringify({}),fileType:`custom/folder`,knowledgeBaseId:e,parentId:t.parent,title:t.name});console.log(`${V.default.green(`✓`)} Created folder ${V.default.bold(n.id)}`)}),t.command(`create-doc <knowledgeBaseId>`).description(`Create a document in a knowledge base`).requiredOption(`-t, --title <title>`,`Document title`).option(`-c, --content <content>`,`Document content (text)`).option(`--parent <parentId>`,`Parent folder ID`).action(async(e,t)=>{let n=await(await W()).document.createDocument.mutate({content:t.content,editorData:JSON.stringify({}),fileType:`custom/document`,knowledgeBaseId:e,parentId:t.parent,title:t.title});console.log(`${V.default.green(`✓`)} Created document ${V.default.bold(n.id)}`)}),t.command(`move <id>`).description(`Move a file or document to a different folder`).option(`--parent <parentId>`,`Target folder ID (omit to move to root)`).option(`--type <type>`,`Item type: file or doc`,`file`).action(async(e,t)=>{let n=await W(),r=t.parent??null;t.type===`doc`?await n.document.updateDocument.mutate({id:e,parentId:r}):await n.file.updateFile.mutate({id:e,parentId:r});let i=r?`folder ${V.default.bold(r)}`:`root`;console.log(`${V.default.green(`✓`)} Moved ${V.default.bold(e)} to ${i}`)}),t.command(`upload <knowledgeBaseId> <filePath>`).description(`Upload a file to a knowledge base`).option(`--parent <parentId>`,`Parent folder ID`).action(async(e,t,n)=>{let r=a.resolve(t);o.existsSync(r)||(U.error(`File not found: ${r}`),process.exit(1));let i=o.statSync(r),s=a.basename(r),c=o.readFileSync(r),l=f.createHash(`sha256`).update(c).digest(`hex`),u=a.extname(s).toLowerCase().slice(1),d={csv:`text/csv`,doc:`application/msword`,docx:`application/vnd.openxmlformats-officedocument.wordprocessingml.document`,gif:`image/gif`,jpeg:`image/jpeg`,jpg:`image/jpeg`,json:`application/json`,md:`text/markdown`,mp3:`audio/mpeg`,mp4:`video/mp4`,pdf:`application/pdf`,png:`image/png`,pptx:`application/vnd.openxmlformats-officedocument.presentationml.presentation`,svg:`image/svg+xml`,txt:`text/plain`,webp:`image/webp`,xlsx:`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`}[u]||`application/octet-stream`,p=await W(),{serverUrl:m,headers:h}=await mr(),g=new Date().toLocaleDateString(`en-CA`),_=`files/${g}/${l}.${u}`,v=await p.upload.createS3PreSignedUrl.mutate({pathname:_}),y=typeof v==`string`?v:v.url,b=await fetch(y,{body:c,headers:{"Content-Type":d},method:`PUT`});b.ok||(U.error(`Upload failed: ${b.status} ${b.statusText}`),process.exit(1));let x=await p.file.createFile.mutate({fileType:d,hash:l,knowledgeBaseId:e,metadata:{date:g,dirname:``,filename:s,path:_},name:s,parentId:n.parent,size:i.size,url:_});console.log(`${V.default.green(`✓`)} Uploaded ${V.default.bold(s)} → ${V.default.bold(x.id)}`)})}const B9=`lobehub-cli`;async function V9(e,t){try{return await e.json()}catch{let n=e.headers.get(`content-type`)||`unknown`;throw Error(`Expected JSON from ${t}, got non-JSON response (status=${e.status}, content-type=${n}).`)}}function soe(e){e.command(`login`).description(`Log in to LobeHub via browser (Device Code Flow) or configure API key server`).option(`--server <url>`,`LobeHub server URL`,`https://app.lobehub.com`).action(async e=>{let t=Qn(e.server)||`https://app.lobehub.com`;U.info(`Starting login...`);let n=process.env[lr];if(n)try{await Kc(n,t);let e=nr();tr(e?.serverUrl===t?{gatewayUrl:e.gatewayUrl,serverUrl:t}:{serverUrl:t}),U.info(`Login successful! Credentials saved.`);return}catch(e){let t=e instanceof Error?e.message:String(e);U.error(`API key validation failed: ${t}`),process.exit(1);return}let r;try{let e=await fetch(`${t}/oidc/device/auth`,{body:new URLSearchParams({client_id:B9,resource:`urn:lobehub:chat`,scope:`openid profile email offline_access`}),headers:{"Content-Type":`application/x-www-form-urlencoded`},method:`POST`});if(!e.ok){let t=await e.text();U.error(`Failed to start device authorization: ${e.status} ${t}`),process.exit(1);return}r=await V9(e,`/oidc/device/auth`)}catch(e){U.error(`Failed to reach server: ${e.message}`),U.error(`Make sure ${t} is reachable.`),process.exit(1);return}let i=r.verification_uri_complete||r.verification_uri;U.info(``),U.info(` Open this URL in your browser:`),U.info(` ${i}`),U.info(``),U.info(` Enter code: ${r.user_code}`),U.info(``),await uoe(i)||U.warn(`Could not open browser automatically.`),U.info(`Waiting for authorization...`);let a=(r.interval||5)*1e3,o=Date.now()+r.expires_in*1e3,s=a;for(;Date.now()<o;){await coe(s);try{let e=await V9(await fetch(`${t}/oidc/token`,{body:new URLSearchParams({client_id:B9,device_code:r.device_code,grant_type:`urn:ietf:params:oauth:grant-type:device_code`}),headers:{"Content-Type":`application/x-www-form-urlencoded`},method:`POST`}),`/oidc/token`);if(e.error)switch(e.error){case`authorization_pending`:break;case`slow_down`:s+=5e3;break;case`access_denied`:U.error(`Authorization denied by user.`),process.exit(1);return;case`expired_token`:U.error(`Device code expired. Please run login again.`),process.exit(1);return;default:U.error(`Authorization error: ${e.error} - ${e.error_description||``}`),process.exit(1);return}else if(e.access_token){sr({accessToken:e.access_token,expiresAt:e.expires_in?Math.floor(Date.now()/1e3)+e.expires_in:void 0,refreshToken:e.refresh_token});let n=nr();tr(n?.serverUrl===t?{gatewayUrl:n.gatewayUrl,serverUrl:t}:{serverUrl:t}),U.info(`Login successful! Credentials saved.`);return}}catch{}}U.error(`Device code expired. Please run login again.`),process.exit(1)})}function coe(e){return new Promise(t=>setTimeout(t,e))}function loe(e,t=process.platform){if(!e)return;if(e.includes(`/`)||e.includes(`\\`))return o.existsSync(e)?e:void 0;let n=process.env.PATH||``;if(!n)return;if(t===`win32`){let t=n.split(`;`).filter(Boolean),r=(process.env.PATHEXT||`.COM;.EXE;.BAT;.CMD`).split(`;`).filter(Boolean),i=a.win32.extname(e).length>0?[e]:[e,...r.map(t=>`${e}${t}`)],s=process.env.SystemRoot||process.env.WINDIR;s&&t.push(a.win32.join(s,`System32`));for(let e of t)for(let t of i){let n=a.win32.join(e,t);if(o.existsSync(n))return n}return}let r=n.split(a.delimiter).filter(Boolean);for(let t of r){let n=a.join(t,e);if(o.existsSync(n))return n}}async function uoe(e){let t=(e,t)=>new Promise(r=>{let i=loe(e);if(!i){U.debug(`Could not open browser automatically: command not found in PATH: ${e}`),r(!1);return}try{n(i,t,e=>{if(e){U.debug(`Could not open browser automatically: ${e.message}`),r(!1);return}r(!0)})}catch(e){U.debug(`Could not open browser automatically: ${e?.message||String(e)}`),r(!1)}});return process.platform===`win32`?t(`rundll32`,[`url.dll,FileProtocolHandler`,e]):t(process.platform===`darwin`?`open`:`xdg-open`,[e])}function doe(e){e.command(`logout`).description(`Log out and remove stored credentials`).action(()=>{hee()?U.info(`Logged out. Credentials removed.`):U.info(`No credentials found. Already logged out.`)})}const foe=[`lobe`,`lobehub`];function poe(e){e.command(`man [command...]`).description(`Show a manual page for the CLI or a subcommand`).action(t=>{let n=moe(e,t??[]);if(!n.command){e.error(n.error||`Unknown command path.`);return}console.log(hoe(e,n.command))})}function moe(e,t){let n=e;for(let e of t){let t=H9(n).find(t=>t.name()===e||t.aliases().includes(e));if(!t)return{error:`Unknown command "${e}" under "${U9(n).join(` `)}". Available: ${H9(n).map(e=>e.name()).join(`, `)||`none`}.`};n=t}return{command:n}}function hoe(e,t){return[goe(t),_oe(t),voe(e,t),yoe(t),boe(t),xoe(t),Soe(t),Coe(t),woe(e,t)].filter(Boolean).join(`
|
|
496
496
|
|
|
497
497
|
`)}function goe(e){return`${U9(e).join(`-`).toUpperCase()}(1)`}function _oe(e){return[`NAME`,` ${U9(e).join(` `)} - ${e.description()}`].join(`
|
package/man/man1/lh.1
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
.\" Code generated by `npm run man:generate`; DO NOT EDIT.
|
|
2
2
|
.\" Manual command details come from the Commander command tree.
|
|
3
|
-
.TH LH 1 "" "@lobehub/cli 0.0.
|
|
3
|
+
.TH LH 1 "" "@lobehub/cli 0.0.5" "User Commands"
|
|
4
4
|
.SH NAME
|
|
5
5
|
lh \- LobeHub CLI \- manage and connect to LobeHub services
|
|
6
6
|
.SH SYNOPSIS
|