@tim-fs/cli 0.1.3 → 0.1.4-alpha

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 +1 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -19,7 +19,7 @@ ${r.map(o=>`- ${o}`).join(`
19
19
  `):""}function qp(e){let t=e.fileContent;if(typeof t?.text=="string")return t.text;if(typeof t=="string")return t;if(t?.text)return String(t.text);let r=ci(t);return r||JSON.stringify(t||{},null,2)}function Up(e){let t=Bp(e.fileName),r={...we(se.join(e.paths.nodeFull,`_captions.${t}.meta.json`)),...we(se.join(e.paths.nodeFull,"_captions",`${t}.meta.json`)),...we(se.join(e.paths.nodeFull,"_captions",`_captions.${t}.meta.json`)),...we(se.join(e.paths.nodeFull,"_meta",`${t}.meta.json`)),...we(se.join(e.paths.nodeFull,"_meta",`_captions.${t}.meta.json`))};return{url:r.url||e.fileContent?.url||"",flavour:e.settings?.analysisPromptId||r.flavour||e.fileContent?.flavour||e.settings?.flavour||pi,title:r.title||e.fileContent?.title||t,descriptorFileName:r.sourceFileName,sourceFileName:e.fileName,audioFileName:e.fileContent?.sourceFileName||r.audioFileName}}function Gp(e,t,r){let o=ee(Z()),n=e.settings?.analysisPromptId||e.settings?.textAnalysisPromptId||r.flavour||pi,i={...e.settings,...e.params,analysisText:t,text:t,transcriptText:t,transcript:e.fileContent,transcriptSegments:ci(e.fileContent),source:r,sourceTitle:r.title,sourceFileName:e.fileName,title:r.title,url:r.url,flavour:r.flavour},a=o.resolvePrompts(e,i)[n]?.promptTemplate;if(!a)throw new Error(`No prompt template found for promptId: ${n}`);return{prompt:a,promptId:n}}function Vp(e,t){let r=ui(e),o=String(t||"").replace(/^\.+|\.+$/g,"");return o?`${r}.${o}.md`:`${r}.md`}var Qt=async e=>{let t=E(e),r=Date.now(),o=ui(e.fileName),n=se.join("_analysis",`_analysis.${o}.json`),i=(s,a={})=>{t.node.ensureDir("_analysis"),t.node.write(n,{status:s,sourceFileName:e.fileName,startedAt:r,updatedAt:Date.now(),elapsedMs:Date.now()-r,...a})};try{let s=qp(e).trim();if(!s||s==="{}"){i("skipped",{reason:"empty text"});return}t.node.addToLog("Building analysis prompt"),i("building-prompt",{textLength:s.length});let a=Up(e),{prompt:u,promptId:c}=Gp(e,s,a),l=H(e.settings,"llm",{model:e.settings?.analysisModel||e.settings?.model,provider:e.settings?.analysisProvider,providerOptions:e.settings?.analysisProviderOptions}),d=l.model;i("calling-llm",{source:a,promptId:c,model:d,promptLength:u.length,textLength:s.length});let m=await Ur({provider:l.provider,model:d,prompt:u,providerOptions:l.providerOptions}),h=Jp(e);Ge(h);let y=Vp(e.fileName,e.settings?.analysisOutputSuffix),I=se.join(h,y),T=se.relative(h,e.paths.fileFull),x=[`# ${a.title||o}`,"",`- Source: ${a.url?`[${a.url}](${a.url})`:e.fileName}`,`- Input: [${e.fileName}](${T})`,`- Prompt: ${c}`,""].join(`
20
20
  `);Er(I,`${x}${m.output.trim()}
21
21
  `);let w=y.replace(/\.md$/i,".meta.json");t.node.write(w,{source:a,inputFileName:e.fileName,inputPath:e.paths.fileFull,outputFileName:y,promptId:c,provider:m.provider||l.provider,model:m.model||d,usage:m.usage,cost:m.cost,textLength:s.length,outputLength:m.output?.length||0}),i("done",{source:a,outputPath:I,outputFileName:y,promptId:c,provider:m.provider||l.provider,model:m.model||d,outputLength:m.output?.length||0,usage:m.usage,cost:m.cost}),t.node.addToLog(`Wrote ${y}`,{data:{outputFileName:y,outputPath:I}})}catch(s){throw i("error",{error:s?.message||"Unknown error"}),s}};var yo={name:"analyze-text",run:Qt};function ce(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function fe(e,t){let r=e.settings?.[t];return ce(r)?r:{}}function $e(e,t,r){return fe(e,t)[r]}function er(e,t,r,o){let n=$e(e,t,r);return typeof n=="string"?n:o}function tr(e,t,r,o){let n=Number($e(e,t,r)??o);return Number.isFinite(n)?n:o}function rt(e,t,r,o){let n=$e(e,t,r);return Array.isArray(n)?n.filter(i=>typeof i=="string"):o}function mi(e,t,r,o){let n=$e(e,t,r);return typeof n=="boolean"?n:o}import rr from"node:path";var li=["inputOutputPair","promptId","sameName"];function Wp(e,t,r="promptId"){let o=$e(e,t,"outputNamingConvention");if(typeof o=="string"){if(li.includes(o))return o;throw new Error(`${t}.outputNamingConvention must be one of: ${li.join(", ")}.`)}return r}function or(e,t){let r=er(e,t,"promptId");if(r?.trim())return r.trim();throw new Error(`${t} requires settings.${t}.promptId.`)}function Y(e,t,r,o="promptId"){let n=Wp(e,t,o);if(n==="sameName")return rr.basename(e.fileName,rr.extname(e.fileName));if(n==="inputOutputPair"){let i=Kp(e.fileName);return i?`${r}.${i}`:r}return r}function Kp(e){let r=rr.basename(e,rr.extname(e)).split(".").filter(Boolean);if(!(r.length<=1))return r[0]==="input"?r.slice(1).join("."):r[r.length-1]==="input"?r.slice(0,-1).join("."):r.slice(1).join(".")}var ot="req-edit-image";function Hp(e){return["Edit the referenced source image according to this fix.","Preserve the original frame composition, character identity, cinematic style, aspect ratio, and story continuity unless the fix explicitly asks otherwise.","","Fix:",e].join(`
22
- `)}var nr=async e=>{let t=E(e),r=String(e.fileContent?.text||"").trim();if(t.node.addToLog("Preparing image edit request"),r.length<tr(e,ot,"minPromptLength",1)){t.node.addToLog("Prompt is too short",{type:"skip"});return}if(!r)throw new Error("req-edit-image: fix text is required.");let o=er(e,ot,"fixSourceExtension","jpg"),n=e.fileName.replace(/\.fix\.txt$/i,""),i=Y(e,ot,ot,"sameName"),s=D(e.settings,"image");for(let a of s){let u=z(i,a.suffix),c={...a.output,prompt:Hp(r),referenceImagePaths:[`./${n}.${o}`],referenceTypes:rt(e,ot,"fixReferenceTypes",["composition","scenario","style","character"])};t.node.writeImageRequest(u,c)}};var ho={name:"req-edit-image",run:nr};import Yp from"node:path";var di="req-image-to-text";function Xp(e){return e.slice(0,e.length-Yp.extname(e).length)}function Zp(e){let t=fe(e,di);return ce(t.request)?t.request:{}}var ir=async e=>{let t=E(e);t.node.addToLog("Prepared image-to-text request");let r=Y(e,di,Xp(e.fileName),"sameName"),o={...Zp(e),imagePath:`./${e.fileName}`};t.node.writeVisionRequest(r,o)};var bo={name:"req-image-to-text",run:ir};var nt="req-image-to-image";function Qp(e){if(!mi(e,nt,"sourceImageAsReference",!0))return{};let t=e.fileName.split(".").pop()?.toLowerCase()||"";return rt(e,nt,"sourceImageExtensions",["jpg","jpeg","png","webp"]).map(o=>o.replace(/^\./,"").toLowerCase()).includes(t)?{referenceImagePaths:[`./${e.fileName}`],referenceTypes:rt(e,nt,"sourceImageReferenceTypes",["general"])}:{}}function eu(e,t){let n=ee(Z()).resolvePrompts(e,{...e.settings,...e.params,fileContent:e.fileContent?.text})[t]?.promptTemplate;return typeof n=="string"?n.trim():""}var sr=async e=>{let t=E(e),r=or(e,nt),o=eu(e,r);if(t.node.addToLog(`Using prompt ${r}`,{data:{promptId:r}}),!o)throw new Error(`req-image-to-image: no prompt template found for promptId: ${r}`);let n=Y(e,nt,r,"inputOutputPair"),i=D(e.settings,"image");for(let s of i){let a=z(n,s.suffix),u={...s.output,prompt:o,...Qp(e)};t.node.writeImageRequest(a,u)}};var vo={name:"req-image-to-image",run:sr};var ar="req-text-to-image";function tu(e){let t=fe(e,ar);return ce(t.request)?t.request:{}}var pr=async e=>{let t=E(e),r=String(e.fileContent?.text||"").trim();if(t.node.addToLog("Preparing text-to-image request"),r.length<tr(e,ar,"minPromptLength",1)){t.node.addToLog("Prompt is too short",{type:"skip"});return}if(!r)throw new Error("req-text-to-image: source prompt text is required.");let o=Y(e,ar,ar,"sameName"),n=D(e.settings,"image");for(let i of n){let s=z(o,i.suffix),a={...tu(e),...i.output,prompt:r};t.node.writeImageRequest(s,a)}};var Io={name:"req-text-to-image",run:pr};var it="req-text-to-speech";function ru(e){return String(e.fileContent?.text||"").trim()}function ou(e){return e.match(/^\s*([^:\n]{1,80}):\s+/)?.[1]?.trim()}function nu(e){let t=e.match(/line-[^.]*([A-Z])(?:\.[^.]+)?$/i);if(t?.[1])return t[1].toUpperCase().charCodeAt(0)-65}function iu(e,t){let r=fe(e,it);if(typeof r.voiceId=="string"&&r.voiceId.trim())return r.voiceId.trim();let o=ou(t),n=ce(r.characterVoices)?r.characterVoices:ce(e.settings?.characterVoices)?e.settings.characterVoices:void 0;if(o&&n){let c=n[o]||n[o.toLowerCase()];if(typeof c=="string"&&c.trim())return c.trim()}let i=Array.isArray(r.characterNames)?r.characterNames:Array.isArray(e.settings?.characterNames)?e.settings.characterNames:[],s=Array.isArray(r.characterVoiceIds)?r.characterVoiceIds:Array.isArray(e.settings?.characterVoiceIds)?e.settings.characterVoiceIds:[];if(o){let c=i.findIndex(d=>typeof d=="string"&&d.toLowerCase()===o.toLowerCase()),l=c>=0?s[c]:void 0;if(typeof l=="string"&&l.trim())return l.trim()}let a=nu(e.fileName),u=typeof a=="number"?s[a]:void 0;return typeof u=="string"&&u.trim()?u.trim():void 0}function su(e){let t=fe(e,it),r=ce(t.request)?t.request:{};return{...r,provider:t.provider??r.provider,model:t.model??r.model,languageCode:t.languageCode??r.languageCode,outputFormat:t.outputFormat??r.outputFormat,speed:t.speed??r.speed,instructions:t.instructions??r.instructions,providerOptions:t.providerOptions??r.providerOptions}}var ur=async e=>{let t=E(e),r=Ye(),o=ru(e);if(t.node.addToLog("Prepared text-to-speech request"),!o)throw new Error(`${it}: source text is required.`);let n=D(e.settings,"tts");for(let i of n){let s={...e,settings:i.settings},a=r.prepareTtsRequest(s,{...su(s),text:o,voiceId:iu(s,o)}),u=Y(s,it,it,"sameName"),c=z(u,i.suffix);t.node.writeTtsRequest(c,a)}};var So={name:"req-text-to-speech",run:ur};var gi="req-text-to-text",cr=async e=>{let t=E(e),r=Ye(),o=or(e,gi);t.node.addToLog(`Using prompt ${o}`,{data:{promptId:o}});let n=D(e.settings,"llm");for(let i of n){let s={...e,settings:i.settings},a=r.prepareTextToTextRequest(s,{promptId:o}),u=Y(s,gi,o),c=z(u,i.suffix);t.node.writeTextToTextRequest(c,a)}};var xo={name:"req-text-to-text",run:cr};import ye from"node:path";function au(e){return e==="~"?process.env.HOME||e:e.replace(/^~(?=\/|\\)/,process.env.HOME||"~")}function pu(e){return e==="move"?"move":"copy"}function uu(e,t){if(typeof e=="boolean")return e;if(typeof e=="string"){if(["true","1","yes"].includes(e.toLowerCase()))return!0;if(["false","0","no"].includes(e.toLowerCase()))return!1}return t}function cu(e){let t=e.settings||{},r=t["place-output"];if(r&&typeof r=="object")return r;let o=t.outputPlacement;return o&&typeof o=="object"?o:{}}function mu(e){let t=cu(e),r=t.dir??t.outputDir??t.destinationDir??t.destination,o=typeof r=="string"&&r.trim()?r.trim():e.paths.nodeFull;return{dir:au(o),mode:pu(t.mode),overwrite:uu(t.overwrite,!0)}}function lu(e,t){let r=ye.isAbsolute(t.dir)?t.dir:ye.resolve(e.paths.rootFull,t.dir);return ye.join(r,e.fileName)}function du(e){return`_placement.${e.replace(/[^a-z0-9._-]+/gi,"-").replace(/^-+|-+$/g,"").toLowerCase()||"output"}.json`}var mr=async e=>{let t=E(e),r=mu(e),o=lu(e,r),n=e.paths.fileFull,i=Date.now(),s=(a,u={})=>{_r(ye.join(e.paths.nodeFull,du(e.fileName)),{status:a,sourceFileName:e.fileName,sourcePath:n,destinationPath:o,mode:r.mode,startedAt:i,updatedAt:Date.now(),elapsedMs:Date.now()-i,...u})};try{if(ye.resolve(n)===ye.resolve(o)){s("skipped",{reason:"destination is source"}),t.node.addToLog("Destination is the source file",{type:"skip"});return}if(j(o)&&!r.overwrite){s("skipped",{reason:"destination exists"}),t.node.addToLog("Destination already exists",{type:"skip",data:{destinationPath:o}});return}Ge(ye.dirname(o)),Ar(n,o),r.mode==="move"&&Fr(n),s("done"),t.node.addToLog(`Placed output at ${ye.basename(o)}`,{data:{destinationPath:o}})}catch(a){throw s("error",{error:a?.message||"Unknown error"}),a}};var wo={name:"place-output",run:mr};var Co={name:"transcribe-audio",run:Te};import Po from"node:fs";import gu from"node:os";import To from"node:path";import fu from"sharp";var Fo="tinify-image",yu=/\.input\.(png|jpe?g|webp)$/i,te={force:!1,outputSuffix:"tiny",jpeg:{quality:80,progressive:!0,mozjpeg:!0},png:{quality:80,compressionLevel:9,palette:!0,effort:7},webp:{quality:80,effort:6}};function De(e,t,r,o){return typeof e=="number"&&Number.isFinite(e)?Math.min(o,Math.max(r,Math.round(e))):t}function lr(e,t){return typeof e=="boolean"?e:t}function dr(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function hu(e={}){let t=dr(e[Fo]),r=dr(t.jpeg),o=dr(t.png),n=dr(t.webp),s=(typeof t.outputSuffix=="string"?t.outputSuffix.trim():"").replace(/[^a-z0-9_-]+/gi,"-").replace(/^-+|-+$/g,"");return{force:lr(t.force,te.force),outputSuffix:s||te.outputSuffix,jpeg:{quality:De(r.quality,te.jpeg.quality,1,100),progressive:lr(r.progressive,te.jpeg.progressive),mozjpeg:lr(r.mozjpeg,te.jpeg.mozjpeg)},png:{quality:De(o.quality,te.png.quality,1,100),compressionLevel:De(o.compressionLevel,te.png.compressionLevel,0,9),palette:lr(o.palette,te.png.palette),effort:De(o.effort,te.png.effort,1,10)},webp:{quality:De(n.quality,te.webp.quality,1,100),effort:De(n.effort,te.webp.effort,0,6)}}}function bu(e,t){let r=e.match(yu);if(!r)throw new Error(`${Fo}: expected a *.input.png, *.input.jpg, *.input.jpeg, or *.input.webp file.`);let o=r[1].toLowerCase(),n=o==="png"?"png":o==="webp"?"webp":"jpeg",i=e.slice(0,-r[0].length),s=`${i}.${t}.${o}`;return{format:n,outputFileName:s,metadataFileName:`${i}.${t}.meta.json`}}async function vu(e,t,r,o){let n=fu(e).rotate();return r==="png"?n.png(o.png).toFile(t):r==="webp"?n.webp(o.webp).toFile(t):n.jpeg(o.jpeg).toFile(t)}var Iu={createFileManager:E,encode:vu,makeTempDir:()=>Po.mkdtempSync(To.join(gu.tmpdir(),"tim-tinify-image-")),pathExists:j,readBuffer:R,removeTempDir:e=>Po.rmSync(e,{recursive:!0,force:!0}),stat:e=>Po.statSync(e)};async function Su(e,t=Iu){let r=t.createFileManager(e),o=hu(e.settings||{}),{format:n,outputFileName:i,metadataFileName:s}=bu(e.fileName,o.outputSuffix),a=e.paths.fileFull,u=To.join(e.paths.nodeFull,i);if(!o.force&&t.pathExists(u)){let h=t.stat(a);if(t.stat(u).mtimeMs>=h.mtimeMs)return r.node.addToLog(`${i} is already current`,{type:"skip"}),{skipped:!0,outputFileName:i}}let c=Date.now(),l=t.stat(a),d=t.makeTempDir(),m=To.join(d,i);r.node.addToLog(`Tinyfying ${e.fileName}`);try{let h=await t.encode(a,m,n,o),y=t.readBuffer(m);r.node.write(i,y);let I=y.byteLength,T=l.size-I,x=l.size>0?Number((T/l.size*100).toFixed(2)):0;return r.node.write(s,{bot:Fo,sourceFileName:e.fileName,outputFileName:i,format:n,inputSizeBytes:l.size,outputSizeBytes:I,savedBytes:T,reductionPercent:x,width:h.width,height:h.height,elapsedMs:Date.now()-c,settings:o}),r.node.addToLog(`Wrote ${i}`,{data:{inputSizeBytes:l.size,outputSizeBytes:I,reductionPercent:x}}),{skipped:!1,outputFileName:i,metadataFileName:s}}catch(h){throw r.node.addToLog(`Failed to tinyfy ${e.fileName}`,{type:"error",data:{error:h?.message||"Unknown error"}}),h}finally{t.removeTempDir(d)}}var gr=async e=>{await Su(e)};var Ao={name:"tinify-image",run:gr};var fi=[uo,co,mo,go,fo,yo,wo,ho,vo,bo,Io,So,xo,Co,Ao];import Xu from"node:fs";import{fileURLToPath as _i}from"node:url";import{homedir as Fi}from"os";import Oo from"path";import{homedir as Ci}from"os";import xu from"node:path";function yi(e,t=[]){return Ke(e,"**/config.json",t).map(r=>xu.dirname(r)).filter((r,o,n)=>n.indexOf(r)===o).sort()}import ko from"lodash";import{minimatch as hi}from"minimatch";import je from"path";function wu(e){let t=ae();return e.replace(t,"")}function Cu(e){try{return j(e)?xt(e):{}}catch(t){return q(`Failed to read JSON from ${e}`,t,{filePath:e}),{}}}var bi=(e,t="create")=>{let r=ae(),o=wu(e),n=je.basename(o),i=je.dirname(o),s={fileName:n,fileContent:{},fileVerb:t,prompts:{},promptIds:[],paths:{},settings:{},params:{},global:We(void 0)},a={root:"/",rootFull:je.resolve(r),file:"",fileFull:"",node:"",nodeFull:""};switch(a.file=o,a.fileFull=je.resolve(`${r}${o}`),a.node=i,a.nodeFull=je.resolve(`${r}${i}`),je.extname(o).toLowerCase()){case".json":s.fileContent=Cu(a.fileFull);break;case".md":case".txt":let m=j(a.fileFull)?kr(a.fileFull):"";s.fileContent={text:m};break}s.paths=a;let l=ee(Z()).resolveConfig(s);s.config=l,s.global=We(l.global);let d=(l.triggers??{})[t]||{};return s.settings=Pu(l.settings||{},n),s.params=ko.merge({},l.params||{},s.params||{}),s.ioBots=d,s.command=Fu(d,o),s.promptIds=Tu(s.settings),s.paths=a,s};function Pu(e,t){let r=ko.cloneDeep(e);for(let[o,n]of Object.entries(r)){if(!n||typeof n!="object"||Array.isArray(n))continue;let i=n.fileOverrides;if(!Array.isArray(i))continue;let s=n;for(let a of i){if(!a||typeof a!="object"||Array.isArray(a))continue;let{glob:u,...c}=a;typeof u!="string"||!hi(t,u)||(s=ko.mergeWith({},s,c,(l,d)=>Array.isArray(d)?d:void 0))}r[o]=s}return r}function Tu(e){let t=new Set;function r(o){if(!(!o||typeof o!="object")){if(Array.isArray(o)){for(let n of o)r(n);return}for(let[n,i]of Object.entries(o))typeof i=="string"&&i.trim()&&(n==="promptId"||n.endsWith("PromptId"))&&t.add(i.trim()),r(i)}}return r(e),[...t]}function Fu(e,t){let r=[];for(let o in e){let n=o.includes("/")?o:`**/${o}`;hi(t,n)&&r.push(e[o])}return r}var Au=[{provider:"OpenAI",environmentVariables:["OPENAI_API_KEY"]},{provider:"Azure OpenAI",environmentVariables:["AZURE_OPENAI_API_KEY","AZURE_API_KEY"]},{provider:"Google",environmentVariables:["GOOGLE_API_KEY"]},{provider:"ElevenLabs",environmentVariables:["ELEVENLABS_API_KEY","ELEVEN_LABS_API_KEY"]},{provider:"Anthropic",environmentVariables:["ANTHROPIC_API_KEY"]},{provider:"xAI",environmentVariables:["XAI_API_KEY"]},{provider:"Hugging Face",environmentVariables:["HUGGINGFACE_API_KEY","HF_TOKEN"]},{provider:"ByteDance",environmentVariables:["ARK_API_KEY"]}];function ku(e=process.env){return Au.filter(({environmentVariables:t})=>t.some(r=>e[r]?.trim())).map(({provider:t})=>t)}function vi(e=process.env){return ku(e).join(", ")||"none"}var Eo={};function _o(e={}){let t=Array.isArray(e)?e.map(({name:r,run:o,lifecycle:n})=>[r,{run:o,lifecycle:n}]):Object.entries(e).map(([r,o])=>[r,{run:o}]);for(let[r,o]of t){if(!r||typeof o.run!="function")throw new TypeError("Each IO bot must provide a non-empty name and a run(context) function.");Eo[r]=o}}function Ii(e){return Eo[e]?.run}function Si(e){return Eo[e]?.lifecycle}var Eu=()=>"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){let t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)});var xi=()=>Eu().substring(0,4);function wi(e,t){let r=E(t),o=[...r.node.applyCleanupPolicy([e]),...r.node.applyCleanupManifests(t.fileName)];for(let n of o)K(t,{botName:e,kind:"diagnostic",level:"debug",message:`IO bot ${e} cleanup completed`,data:n},{console:!1,local:!0,operation:!0,workspace:!1});return o}var _u=async(e,t)=>{let r=new Date().toISOString(),o=Date.now(),n=Lu(new Date(o)),i={...t,botName:e,operationId:n},s=Si(e),a={};try{a=s?.start?.(i)??{}}catch{}let u={botName:e,command:e,eventType:"operation",operationId:n,phase:"started",sourceFileName:t.fileName,sourceFilePath:t.paths?.file,startedAt:r,...a};K(i,{botName:e,kind:"bot-start",level:"info",message:`IO bot ${e} started`,operationId:n,data:u});let c=(d,m={})=>{let h=new Date().toISOString(),y=Date.now()-o;K(i,{botName:e,duration:y,kind:d==="done"?"bot-done":"bot-error",level:d==="done"?"info":"error",message:d==="done"?`IO bot ${e} completed`:String(m.error??`IO bot ${e} failed`),operationId:n,data:{...u,...m,durationMs:y,endedAt:h,phase:d}}),un(i)},l=d=>{wi(e,i),c("done",d?.logData?{result:d.logData}:{})};try{let d=Ii(e);if(typeof d!="function"){c("error",{error:`No command found for: ${e}`});return}let m=await d(i);l(m)}catch(d){let m=d instanceof Error?d.message:String(d);c("error",{error:m,...d instanceof Error&&d.stack?{stack:d.stack}:{}})}};function Lu(e){let t=e.getFullYear(),r=Math.floor((Date.UTC(t,e.getMonth(),e.getDate())-Date.UTC(t,0,1))/864e5)+1,o=String(e.getHours()).padStart(2,"0"),n=String(e.getMinutes()).padStart(2,"0");return`${t}-${String(r).padStart(3,"0")}-${o}-${n}-${xi()}`}var st=async(e,t)=>{let r=[];for(let o of e){let n;Array.isArray(o)?n=st(o,t):n=_u(o,t),r.push(n)}return Promise.all(r)};var Lo=new Map,Nu=new Set(["_analysis","_cleanup","_done","_meta","_parts","_partial","_prompts","_temp","_transcript"]),Ou=["_partial.","_transcribing.","_transcript."],Ru=(e,t)=>e.split(/[\\/]+/).some(r=>Nu.has(r))||Ou.some(r=>t.startsWith(r));function $u(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function Du(e){if(typeof e=="number")return Number.isFinite(e)&&e>0?e:0;if(typeof e!="string")return 0;let t=e.trim().match(/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/i);if(!t)return 0;let r=Number(t[1]);if(!Number.isFinite(r)||r<=0)return 0;let o=(t[2]||"ms").toLowerCase(),n=o==="h"?3600*1e3:o==="m"?60*1e3:o==="s"?1e3:1;return Math.round(r*n)}function ju(e,t){let r=e.config?.triggers;if(!r||typeof r!="object")return 0;let o=r[`delay${$u(t)}`];return Du(o??r.delay)}function Me(e){return(Array.isArray(e.command)?e.command:[e.command]).filter(r=>typeof r=="string"&&r.length>0)}var Mu=e=>e.some(t=>t.startsWith("ai-"));function Bu(e){return Ru(e.paths.file,e.fileName)||e.fileName.endsWith("log.txt")}function Ju(e,t){for(let r of Me(e))K(e,{botName:r,duration:t,kind:"bot-delay",level:"info",message:`IO bot ${r} waiting ${t}ms`,crudVerb:e.fileVerb,data:{delayMs:t}},{operation:!1})}function zu(e){for(let t of Me(e))K(e,{botName:t,kind:"bot-skip",level:"info",message:"Delay superseded by a newer filesystem event",crudVerb:e.fileVerb},{operation:!1})}function No(e,t,r){if(Bu(e))return Promise.resolve();K(e,{crudVerb:t,kind:"crud",level:"info",message:`${t} ${e.fileName}`},{local:!1,operation:!1});let o=Me(e);if(o.length===0)return Promise.resolve();let n=Mu(o)?0:ju(e,t);if(n<=0)return r(e);let i=`${e.paths.nodeFull}:${t}`,s=Lo.get(i);return s&&(clearTimeout(s.timer),zu(s.context),s.resolve()),new Promise((a,u)=>{Ju(e,n);let c=setTimeout(()=>{Lo.delete(i),r(e).then(a,u)},n);Lo.set(i,{context:e,timer:c,resolve:a})})}var qu=async e=>{await st(Me(e),e)},Uu=async e=>{await st(Me(e),e)},Gu=async e=>{},Vu=async e=>{await st(Me(e),e)},Wu=e=>No(e,"create",qu),Ku=e=>No(e,"update",Uu),Hu=e=>No(e,"delete",Vu),fr={bootstrap:Gu,create:Wu,update:Ku,delete:Hu};var Pi=["_partial*","**/_partial*","_transcribing*","**/_transcribing*","_transcript.*","**/_transcript.*","_analysis/**","**/_analysis/**","_cleanup/**","**/_cleanup/**","_done/**","**/_done/**","_meta/**","**/_meta/**","_parts/**","**/_parts/**","_prompts/**","**/_prompts/**","_temp/**","**/_temp/**","_transcript/**","**/_transcript/**","**/node_modules/**","**/dist/**","**/__pycache__/**","**/*.egg-info/**","_tim/**","**/_tim/**"];async function Ti(e){let t=e.cwd,r=e.version||"unknown",o=t.startsWith(Ci())?t.replace(Ci(),"~"):t,n=yi(t,Pi);if(!n.length)throw new Error(`No config.json files found recursively under ${o}. Add config.json to each directory TIM should watch.`);Uo(t);let i=en(),s=vi();return await i.log({kind:"system",level:"info",message:`TIM version ${r}`,data:{version:r}}),await i.log({kind:"system",level:"info",message:`Listener started in ${o} with ${n.length} configured director${n.length===1?"y":"ies"}`,data:{root:o,configuredDirectories:n.length}}),await i.log({kind:"system",level:"info",message:`Providers: ${s}`,data:{providers:s}}),$r({cwd:t,watchPaths:n,depth:0,target:"**/*",ignore:Pi,createContext:bi,silent:!0,callbacks:{onAdd:fr.create,onChange:fr.update,onUnlink:fr.delete},ignoreLogs:!0})}function Ro(e,t=process.cwd()){if(!e)return Oo.resolve(t);let r=e==="~"?Fi():e.startsWith("~/")?Oo.join(Fi(),e.slice(2)):e;return Oo.resolve(t,r)}function Ai(e={}){return _o(e.bots),_e(e.galleries),Ti({cwd:Ro(e.cwd),version:e.version})}var ki={id:"character-sheets",title:"Character Sheets",description:"Reusable image-to-image workflow for generating polished character sheet outputs from input artwork.",triggers:{create:{"input.*.png":"req-image-to-image","*.image.json":"ai-image"},update:{"input.*.png":"req-image-to-image","*.image.json":"ai-image"}},settings:{"req-image-to-image":{outputNamingConvention:"inputOutputPair",promptId:"character-sheet",sourceImageAsReference:!0,sourceImageReferenceTypes:["character","style"]},"ai-image":{output:{provider:"google",model:"gemini-3-pro-image",aspectRatio:"3:2",imageSize:"4K"}}}};var Ei=_i(new URL("./prompts/character-sheets",import.meta.url)),Zu=_i(new URL("../src/character-sheets/_prompts",import.meta.url)),Qu=Xu.existsSync(Ei)?Ei:Zu,Li={name:"g-character-sheets",aliases:["character-sheets","character-sheet"],config:ki},yr=[Li],$o=[{gallery:Li.name,from:Qu}];_e(yr);var hr={name:"@tim-fs/cli",publishConfig:{access:"public",tag:"alpha"},version:"0.1.3",type:"module",description:"Turn ordinary folders into explicit, inspectable AI and code workflows that any person, agent, or program can invoke by writing a file",bin:{tim:"dist/index.js"},files:["dist"],scripts:{build:"npm run clean && npm run build:debug","build:release":"node build.mjs --release","build:debug":"node build.mjs",clean:"rm -rf dist",link:"npm run build && npm link",prepack:"npm run clean && npm run build:release",test:"npm run build && node --test test/*.test.mjs",typecheck:"tsc -p tsconfig.json",watch:'nodemon --watch src --ext ts --exec "npm run build"'},keywords:["automation","filesystem","file-watcher","ai","workflow"],license:"MIT",engines:{node:">=20"},repository:{type:"git",url:"git+https://github.com/dht/tim-fs.git",directory:"cli"},bugs:{url:"https://github.com/dht/tim-fs/issues"},homepage:"https://github.com/dht/tim-fs#readme",dependencies:{"@ai-sdk/anthropic":"^3.0.84","@ai-sdk/azure":"^3.0.87","@ai-sdk/bytedance":"^1.0.17","@ai-sdk/elevenlabs":"^2.0.35","@ai-sdk/google":"^3.0.82","@ai-sdk/huggingface":"^1.0.52","@ai-sdk/openai":"^3.0.71","@ai-sdk/xai":"^3.0.95","@elevenlabs/elevenlabs-js":"^2.58.0",ai:"^6.0.205",chokidar:"^5.0.0",commander:"^12.1.0",dotenv:"^17.2.3","fs-extra":"^11.3.2",glob:"13.0.0",kleur:"^4.1.5",lodash:"^4.18.1",logform:"^2.7.0",minimatch:"^10.2.5",openai:"^6.48.0","p-limit":"^7.2.0",sharp:"^0.34.5",winston:"^3.18.3","winston-transport":"^4.9.0",ws:"^8.21.1",yaml:"^2.9.0"},devDependencies:{"@tim-fs/core":"workspace:^","@tim-fs/io-core":"workspace:^","@tim-fs/io-gallery":"workspace:^","@types/node":"^20.19.25",esbuild:"^0.27.2",nodemon:"^3.1.7",typescript:"^5.9.3"}};import{config as ac}from"dotenv";import Be from"node:fs";import tc from"node:os";import br from"node:path";import{parse as rc}from"dotenv";var at=[{name:"OPENAI_API_KEY",label:"OpenAI"},{name:"ANTHROPIC_API_KEY",label:"Anthropic"},{name:"GOOGLE_API_KEY",label:"Google Gemini"},{name:"ELEVENLABS_API_KEY",label:"ElevenLabs",aliases:["ELEVEN_LABS_API_KEY"]},{name:"XAI_API_KEY",label:"xAI"},{name:"HUGGINGFACE_API_KEY",label:"Hugging Face",aliases:["HF_TOKEN","HF_ACCESS_TOKEN"]},{name:"ARK_API_KEY",label:"ByteDance ModelArk"},{name:"AZURE_OPENAI_API_KEY",label:"Azure OpenAI",aliases:["AZURE_API_KEY"]}];function oc(e=process.env){return e.TIM_HOME||br.join(tc.homedir(),".tim")}function Je(e=process.env){return e.TIM_ENV_FILE||br.join(oc(e),".env")}function nc(e){return Be.existsSync(e)?rc(Be.readFileSync(e)):{}}function ic(e,...t){for(let r of t)for(let o of[e.name,...e.aliases||[]]){let n=r[o]?.trim();if(n)return n}return""}function sc(e){return e?JSON.stringify(e):""}function Ni(e={}){let t=e.environment||process.env,r=e.destination||Je(t),o=nc(r);return Object.fromEntries(at.map(n=>[n.name,ic(n,o,t)]))}function Oi(e,t=Je()){let r=["# TIM provider credentials","# Run `npx @tim-fs/cli@alpha init` again to update this file.","",...at.map(o=>`${o.name}=${sc(e[o.name]||"")}`),""];Be.mkdirSync(br.dirname(t),{recursive:!0,mode:448}),Be.chmodSync(br.dirname(t),448),Be.writeFileSync(t,r.join(`
22
+ `)}var nr=async e=>{let t=E(e),r=String(e.fileContent?.text||"").trim();if(t.node.addToLog("Preparing image edit request"),r.length<tr(e,ot,"minPromptLength",1)){t.node.addToLog("Prompt is too short",{type:"skip"});return}if(!r)throw new Error("req-edit-image: fix text is required.");let o=er(e,ot,"fixSourceExtension","jpg"),n=e.fileName.replace(/\.fix\.txt$/i,""),i=Y(e,ot,ot,"sameName"),s=D(e.settings,"image");for(let a of s){let u=z(i,a.suffix),c={...a.output,prompt:Hp(r),referenceImagePaths:[`./${n}.${o}`],referenceTypes:rt(e,ot,"fixReferenceTypes",["composition","scenario","style","character"])};t.node.writeImageRequest(u,c)}};var ho={name:"req-edit-image",run:nr};import Yp from"node:path";var di="req-image-to-text";function Xp(e){return e.slice(0,e.length-Yp.extname(e).length)}function Zp(e){let t=fe(e,di);return ce(t.request)?t.request:{}}var ir=async e=>{let t=E(e);t.node.addToLog("Prepared image-to-text request");let r=Y(e,di,Xp(e.fileName),"sameName"),o={...Zp(e),imagePath:`./${e.fileName}`};t.node.writeVisionRequest(r,o)};var bo={name:"req-image-to-text",run:ir};var nt="req-image-to-image";function Qp(e){if(!mi(e,nt,"sourceImageAsReference",!0))return{};let t=e.fileName.split(".").pop()?.toLowerCase()||"";return rt(e,nt,"sourceImageExtensions",["jpg","jpeg","png","webp"]).map(o=>o.replace(/^\./,"").toLowerCase()).includes(t)?{referenceImagePaths:[`./${e.fileName}`],referenceTypes:rt(e,nt,"sourceImageReferenceTypes",["general"])}:{}}function eu(e,t){let n=ee(Z()).resolvePrompts(e,{...e.settings,...e.params,fileContent:e.fileContent?.text})[t]?.promptTemplate;return typeof n=="string"?n.trim():""}var sr=async e=>{let t=E(e),r=or(e,nt),o=eu(e,r);if(t.node.addToLog(`Using prompt ${r}`,{data:{promptId:r}}),!o)throw new Error(`req-image-to-image: no prompt template found for promptId: ${r}`);let n=Y(e,nt,r,"inputOutputPair"),i=D(e.settings,"image");for(let s of i){let a=z(n,s.suffix),u={...s.output,prompt:o,...Qp(e)};t.node.writeImageRequest(a,u)}};var vo={name:"req-image-to-image",run:sr};var ar="req-text-to-image";function tu(e){let t=fe(e,ar);return ce(t.request)?t.request:{}}var pr=async e=>{let t=E(e),r=String(e.fileContent?.text||"").trim();if(t.node.addToLog("Preparing text-to-image request"),r.length<tr(e,ar,"minPromptLength",1)){t.node.addToLog("Prompt is too short",{type:"skip"});return}if(!r)throw new Error("req-text-to-image: source prompt text is required.");let o=Y(e,ar,ar,"sameName"),n=D(e.settings,"image");for(let i of n){let s=z(o,i.suffix),a={...tu(e),...i.output,prompt:r};t.node.writeImageRequest(s,a)}};var Io={name:"req-text-to-image",run:pr};var it="req-text-to-speech";function ru(e){return String(e.fileContent?.text||"").trim()}function ou(e){return e.match(/^\s*([^:\n]{1,80}):\s+/)?.[1]?.trim()}function nu(e){let t=e.match(/line-[^.]*([A-Z])(?:\.[^.]+)?$/i);if(t?.[1])return t[1].toUpperCase().charCodeAt(0)-65}function iu(e,t){let r=fe(e,it);if(typeof r.voiceId=="string"&&r.voiceId.trim())return r.voiceId.trim();let o=ou(t),n=ce(r.characterVoices)?r.characterVoices:ce(e.settings?.characterVoices)?e.settings.characterVoices:void 0;if(o&&n){let c=n[o]||n[o.toLowerCase()];if(typeof c=="string"&&c.trim())return c.trim()}let i=Array.isArray(r.characterNames)?r.characterNames:Array.isArray(e.settings?.characterNames)?e.settings.characterNames:[],s=Array.isArray(r.characterVoiceIds)?r.characterVoiceIds:Array.isArray(e.settings?.characterVoiceIds)?e.settings.characterVoiceIds:[];if(o){let c=i.findIndex(d=>typeof d=="string"&&d.toLowerCase()===o.toLowerCase()),l=c>=0?s[c]:void 0;if(typeof l=="string"&&l.trim())return l.trim()}let a=nu(e.fileName),u=typeof a=="number"?s[a]:void 0;return typeof u=="string"&&u.trim()?u.trim():void 0}function su(e){let t=fe(e,it),r=ce(t.request)?t.request:{};return{...r,provider:t.provider??r.provider,model:t.model??r.model,languageCode:t.languageCode??r.languageCode,outputFormat:t.outputFormat??r.outputFormat,speed:t.speed??r.speed,instructions:t.instructions??r.instructions,providerOptions:t.providerOptions??r.providerOptions}}var ur=async e=>{let t=E(e),r=Ye(),o=ru(e);if(t.node.addToLog("Prepared text-to-speech request"),!o)throw new Error(`${it}: source text is required.`);let n=D(e.settings,"tts");for(let i of n){let s={...e,settings:i.settings},a=r.prepareTtsRequest(s,{...su(s),text:o,voiceId:iu(s,o)}),u=Y(s,it,it,"sameName"),c=z(u,i.suffix);t.node.writeTtsRequest(c,a)}};var So={name:"req-text-to-speech",run:ur};var gi="req-text-to-text",cr=async e=>{let t=E(e),r=Ye(),o=or(e,gi);t.node.addToLog(`Using prompt ${o}`,{data:{promptId:o}});let n=D(e.settings,"llm");for(let i of n){let s={...e,settings:i.settings},a=r.prepareTextToTextRequest(s,{promptId:o}),u=Y(s,gi,o),c=z(u,i.suffix);t.node.writeTextToTextRequest(c,a)}};var xo={name:"req-text-to-text",run:cr};import ye from"node:path";function au(e){return e==="~"?process.env.HOME||e:e.replace(/^~(?=\/|\\)/,process.env.HOME||"~")}function pu(e){return e==="move"?"move":"copy"}function uu(e,t){if(typeof e=="boolean")return e;if(typeof e=="string"){if(["true","1","yes"].includes(e.toLowerCase()))return!0;if(["false","0","no"].includes(e.toLowerCase()))return!1}return t}function cu(e){let t=e.settings||{},r=t["place-output"];if(r&&typeof r=="object")return r;let o=t.outputPlacement;return o&&typeof o=="object"?o:{}}function mu(e){let t=cu(e),r=t.dir??t.outputDir??t.destinationDir??t.destination,o=typeof r=="string"&&r.trim()?r.trim():e.paths.nodeFull;return{dir:au(o),mode:pu(t.mode),overwrite:uu(t.overwrite,!0)}}function lu(e,t){let r=ye.isAbsolute(t.dir)?t.dir:ye.resolve(e.paths.rootFull,t.dir);return ye.join(r,e.fileName)}function du(e){return`_placement.${e.replace(/[^a-z0-9._-]+/gi,"-").replace(/^-+|-+$/g,"").toLowerCase()||"output"}.json`}var mr=async e=>{let t=E(e),r=mu(e),o=lu(e,r),n=e.paths.fileFull,i=Date.now(),s=(a,u={})=>{_r(ye.join(e.paths.nodeFull,du(e.fileName)),{status:a,sourceFileName:e.fileName,sourcePath:n,destinationPath:o,mode:r.mode,startedAt:i,updatedAt:Date.now(),elapsedMs:Date.now()-i,...u})};try{if(ye.resolve(n)===ye.resolve(o)){s("skipped",{reason:"destination is source"}),t.node.addToLog("Destination is the source file",{type:"skip"});return}if(j(o)&&!r.overwrite){s("skipped",{reason:"destination exists"}),t.node.addToLog("Destination already exists",{type:"skip",data:{destinationPath:o}});return}Ge(ye.dirname(o)),Ar(n,o),r.mode==="move"&&Fr(n),s("done"),t.node.addToLog(`Placed output at ${ye.basename(o)}`,{data:{destinationPath:o}})}catch(a){throw s("error",{error:a?.message||"Unknown error"}),a}};var wo={name:"place-output",run:mr};var Co={name:"transcribe-audio",run:Te};import Po from"node:fs";import gu from"node:os";import To from"node:path";import fu from"sharp";var Fo="tinify-image",yu=/\.input\.(png|jpe?g|webp)$/i,te={force:!1,outputSuffix:"tiny",jpeg:{quality:80,progressive:!0,mozjpeg:!0},png:{quality:80,compressionLevel:9,palette:!0,effort:7},webp:{quality:80,effort:6}};function De(e,t,r,o){return typeof e=="number"&&Number.isFinite(e)?Math.min(o,Math.max(r,Math.round(e))):t}function lr(e,t){return typeof e=="boolean"?e:t}function dr(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function hu(e={}){let t=dr(e[Fo]),r=dr(t.jpeg),o=dr(t.png),n=dr(t.webp),s=(typeof t.outputSuffix=="string"?t.outputSuffix.trim():"").replace(/[^a-z0-9_-]+/gi,"-").replace(/^-+|-+$/g,"");return{force:lr(t.force,te.force),outputSuffix:s||te.outputSuffix,jpeg:{quality:De(r.quality,te.jpeg.quality,1,100),progressive:lr(r.progressive,te.jpeg.progressive),mozjpeg:lr(r.mozjpeg,te.jpeg.mozjpeg)},png:{quality:De(o.quality,te.png.quality,1,100),compressionLevel:De(o.compressionLevel,te.png.compressionLevel,0,9),palette:lr(o.palette,te.png.palette),effort:De(o.effort,te.png.effort,1,10)},webp:{quality:De(n.quality,te.webp.quality,1,100),effort:De(n.effort,te.webp.effort,0,6)}}}function bu(e,t){let r=e.match(yu);if(!r)throw new Error(`${Fo}: expected a *.input.png, *.input.jpg, *.input.jpeg, or *.input.webp file.`);let o=r[1].toLowerCase(),n=o==="png"?"png":o==="webp"?"webp":"jpeg",i=e.slice(0,-r[0].length),s=`${i}.${t}.${o}`;return{format:n,outputFileName:s,metadataFileName:`${i}.${t}.meta.json`}}async function vu(e,t,r,o){let n=fu(e).rotate();return r==="png"?n.png(o.png).toFile(t):r==="webp"?n.webp(o.webp).toFile(t):n.jpeg(o.jpeg).toFile(t)}var Iu={createFileManager:E,encode:vu,makeTempDir:()=>Po.mkdtempSync(To.join(gu.tmpdir(),"tim-tinify-image-")),pathExists:j,readBuffer:R,removeTempDir:e=>Po.rmSync(e,{recursive:!0,force:!0}),stat:e=>Po.statSync(e)};async function Su(e,t=Iu){let r=t.createFileManager(e),o=hu(e.settings||{}),{format:n,outputFileName:i,metadataFileName:s}=bu(e.fileName,o.outputSuffix),a=e.paths.fileFull,u=To.join(e.paths.nodeFull,i);if(!o.force&&t.pathExists(u)){let h=t.stat(a);if(t.stat(u).mtimeMs>=h.mtimeMs)return r.node.addToLog(`${i} is already current`,{type:"skip"}),{skipped:!0,outputFileName:i}}let c=Date.now(),l=t.stat(a),d=t.makeTempDir(),m=To.join(d,i);r.node.addToLog(`Tinyfying ${e.fileName}`);try{let h=await t.encode(a,m,n,o),y=t.readBuffer(m);r.node.write(i,y);let I=y.byteLength,T=l.size-I,x=l.size>0?Number((T/l.size*100).toFixed(2)):0;return r.node.write(s,{bot:Fo,sourceFileName:e.fileName,outputFileName:i,format:n,inputSizeBytes:l.size,outputSizeBytes:I,savedBytes:T,reductionPercent:x,width:h.width,height:h.height,elapsedMs:Date.now()-c,settings:o}),r.node.addToLog(`Wrote ${i}`,{data:{inputSizeBytes:l.size,outputSizeBytes:I,reductionPercent:x}}),{skipped:!1,outputFileName:i,metadataFileName:s}}catch(h){throw r.node.addToLog(`Failed to tinyfy ${e.fileName}`,{type:"error",data:{error:h?.message||"Unknown error"}}),h}finally{t.removeTempDir(d)}}var gr=async e=>{await Su(e)};var Ao={name:"tinify-image",run:gr};var fi=[uo,co,mo,go,fo,yo,wo,ho,vo,bo,Io,So,xo,Co,Ao];import Xu from"node:fs";import{fileURLToPath as _i}from"node:url";import{homedir as Fi}from"os";import Oo from"path";import{homedir as Ci}from"os";import xu from"node:path";function yi(e,t=[]){return Ke(e,"**/config.json",t).map(r=>xu.dirname(r)).filter((r,o,n)=>n.indexOf(r)===o).sort()}import ko from"lodash";import{minimatch as hi}from"minimatch";import je from"path";function wu(e){let t=ae();return e.replace(t,"")}function Cu(e){try{return j(e)?xt(e):{}}catch(t){return q(`Failed to read JSON from ${e}`,t,{filePath:e}),{}}}var bi=(e,t="create")=>{let r=ae(),o=wu(e),n=je.basename(o),i=je.dirname(o),s={fileName:n,fileContent:{},fileVerb:t,prompts:{},promptIds:[],paths:{},settings:{},params:{},global:We(void 0)},a={root:"/",rootFull:je.resolve(r),file:"",fileFull:"",node:"",nodeFull:""};switch(a.file=o,a.fileFull=je.resolve(`${r}${o}`),a.node=i,a.nodeFull=je.resolve(`${r}${i}`),je.extname(o).toLowerCase()){case".json":s.fileContent=Cu(a.fileFull);break;case".md":case".txt":let m=j(a.fileFull)?kr(a.fileFull):"";s.fileContent={text:m};break}s.paths=a;let l=ee(Z()).resolveConfig(s);s.config=l,s.global=We(l.global);let d=(l.triggers??{})[t]||{};return s.settings=Pu(l.settings||{},n),s.params=ko.merge({},l.params||{},s.params||{}),s.ioBots=d,s.command=Fu(d,o),s.promptIds=Tu(s.settings),s.paths=a,s};function Pu(e,t){let r=ko.cloneDeep(e);for(let[o,n]of Object.entries(r)){if(!n||typeof n!="object"||Array.isArray(n))continue;let i=n.fileOverrides;if(!Array.isArray(i))continue;let s=n;for(let a of i){if(!a||typeof a!="object"||Array.isArray(a))continue;let{glob:u,...c}=a;typeof u!="string"||!hi(t,u)||(s=ko.mergeWith({},s,c,(l,d)=>Array.isArray(d)?d:void 0))}r[o]=s}return r}function Tu(e){let t=new Set;function r(o){if(!(!o||typeof o!="object")){if(Array.isArray(o)){for(let n of o)r(n);return}for(let[n,i]of Object.entries(o))typeof i=="string"&&i.trim()&&(n==="promptId"||n.endsWith("PromptId"))&&t.add(i.trim()),r(i)}}return r(e),[...t]}function Fu(e,t){let r=[];for(let o in e){let n=o.includes("/")?o:`**/${o}`;hi(t,n)&&r.push(e[o])}return r}var Au=[{provider:"OpenAI",environmentVariables:["OPENAI_API_KEY"]},{provider:"Azure OpenAI",environmentVariables:["AZURE_OPENAI_API_KEY","AZURE_API_KEY"]},{provider:"Google",environmentVariables:["GOOGLE_API_KEY"]},{provider:"ElevenLabs",environmentVariables:["ELEVENLABS_API_KEY","ELEVEN_LABS_API_KEY"]},{provider:"Anthropic",environmentVariables:["ANTHROPIC_API_KEY"]},{provider:"xAI",environmentVariables:["XAI_API_KEY"]},{provider:"Hugging Face",environmentVariables:["HUGGINGFACE_API_KEY","HF_TOKEN"]},{provider:"ByteDance",environmentVariables:["ARK_API_KEY"]}];function ku(e=process.env){return Au.filter(({environmentVariables:t})=>t.some(r=>e[r]?.trim())).map(({provider:t})=>t)}function vi(e=process.env){return ku(e).join(", ")||"none"}var Eo={};function _o(e={}){let t=Array.isArray(e)?e.map(({name:r,run:o,lifecycle:n})=>[r,{run:o,lifecycle:n}]):Object.entries(e).map(([r,o])=>[r,{run:o}]);for(let[r,o]of t){if(!r||typeof o.run!="function")throw new TypeError("Each IO bot must provide a non-empty name and a run(context) function.");Eo[r]=o}}function Ii(e){return Eo[e]?.run}function Si(e){return Eo[e]?.lifecycle}var Eu=()=>"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){let t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)});var xi=()=>Eu().substring(0,4);function wi(e,t){let r=E(t),o=[...r.node.applyCleanupPolicy([e]),...r.node.applyCleanupManifests(t.fileName)];for(let n of o)K(t,{botName:e,kind:"diagnostic",level:"debug",message:`IO bot ${e} cleanup completed`,data:n},{console:!1,local:!0,operation:!0,workspace:!1});return o}var _u=async(e,t)=>{let r=new Date().toISOString(),o=Date.now(),n=Lu(new Date(o)),i={...t,botName:e,operationId:n},s=Si(e),a={};try{a=s?.start?.(i)??{}}catch{}let u={botName:e,command:e,eventType:"operation",operationId:n,phase:"started",sourceFileName:t.fileName,sourceFilePath:t.paths?.file,startedAt:r,...a};K(i,{botName:e,kind:"bot-start",level:"info",message:`IO bot ${e} started`,operationId:n,data:u});let c=(d,m={})=>{let h=new Date().toISOString(),y=Date.now()-o;K(i,{botName:e,duration:y,kind:d==="done"?"bot-done":"bot-error",level:d==="done"?"info":"error",message:d==="done"?`IO bot ${e} completed`:String(m.error??`IO bot ${e} failed`),operationId:n,data:{...u,...m,durationMs:y,endedAt:h,phase:d}}),un(i)},l=d=>{wi(e,i),c("done",d?.logData?{result:d.logData}:{})};try{let d=Ii(e);if(typeof d!="function"){c("error",{error:`No command found for: ${e}`});return}let m=await d(i);l(m)}catch(d){let m=d instanceof Error?d.message:String(d);c("error",{error:m,...d instanceof Error&&d.stack?{stack:d.stack}:{}})}};function Lu(e){let t=e.getFullYear(),r=Math.floor((Date.UTC(t,e.getMonth(),e.getDate())-Date.UTC(t,0,1))/864e5)+1,o=String(e.getHours()).padStart(2,"0"),n=String(e.getMinutes()).padStart(2,"0");return`${t}-${String(r).padStart(3,"0")}-${o}-${n}-${xi()}`}var st=async(e,t)=>{let r=[];for(let o of e){let n;Array.isArray(o)?n=st(o,t):n=_u(o,t),r.push(n)}return Promise.all(r)};var Lo=new Map,Nu=new Set(["_analysis","_cleanup","_done","_meta","_parts","_partial","_prompts","_temp","_transcript"]),Ou=["_partial.","_transcribing.","_transcript."],Ru=(e,t)=>e.split(/[\\/]+/).some(r=>Nu.has(r))||Ou.some(r=>t.startsWith(r));function $u(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function Du(e){if(typeof e=="number")return Number.isFinite(e)&&e>0?e:0;if(typeof e!="string")return 0;let t=e.trim().match(/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/i);if(!t)return 0;let r=Number(t[1]);if(!Number.isFinite(r)||r<=0)return 0;let o=(t[2]||"ms").toLowerCase(),n=o==="h"?3600*1e3:o==="m"?60*1e3:o==="s"?1e3:1;return Math.round(r*n)}function ju(e,t){let r=e.config?.triggers;if(!r||typeof r!="object")return 0;let o=r[`delay${$u(t)}`];return Du(o??r.delay)}function Me(e){return(Array.isArray(e.command)?e.command:[e.command]).filter(r=>typeof r=="string"&&r.length>0)}var Mu=e=>e.some(t=>t.startsWith("ai-"));function Bu(e){return Ru(e.paths.file,e.fileName)||e.fileName.endsWith("log.txt")}function Ju(e,t){for(let r of Me(e))K(e,{botName:r,duration:t,kind:"bot-delay",level:"info",message:`IO bot ${r} waiting ${t}ms`,crudVerb:e.fileVerb,data:{delayMs:t}},{operation:!1})}function zu(e){for(let t of Me(e))K(e,{botName:t,kind:"bot-skip",level:"info",message:"Delay superseded by a newer filesystem event",crudVerb:e.fileVerb},{operation:!1})}function No(e,t,r){if(Bu(e))return Promise.resolve();K(e,{crudVerb:t,kind:"crud",level:"info",message:`${t} ${e.fileName}`},{local:!1,operation:!1});let o=Me(e);if(o.length===0)return Promise.resolve();let n=Mu(o)?0:ju(e,t);if(n<=0)return r(e);let i=`${e.paths.nodeFull}:${t}`,s=Lo.get(i);return s&&(clearTimeout(s.timer),zu(s.context),s.resolve()),new Promise((a,u)=>{Ju(e,n);let c=setTimeout(()=>{Lo.delete(i),r(e).then(a,u)},n);Lo.set(i,{context:e,timer:c,resolve:a})})}var qu=async e=>{await st(Me(e),e)},Uu=async e=>{await st(Me(e),e)},Gu=async e=>{},Vu=async e=>{await st(Me(e),e)},Wu=e=>No(e,"create",qu),Ku=e=>No(e,"update",Uu),Hu=e=>No(e,"delete",Vu),fr={bootstrap:Gu,create:Wu,update:Ku,delete:Hu};var Pi=["_partial*","**/_partial*","_transcribing*","**/_transcribing*","_transcript.*","**/_transcript.*","_analysis/**","**/_analysis/**","_cleanup/**","**/_cleanup/**","_done/**","**/_done/**","_meta/**","**/_meta/**","_parts/**","**/_parts/**","_prompts/**","**/_prompts/**","_temp/**","**/_temp/**","_transcript/**","**/_transcript/**","**/node_modules/**","**/dist/**","**/__pycache__/**","**/*.egg-info/**","_tim/**","**/_tim/**"];async function Ti(e){let t=e.cwd,r=e.version||"unknown",o=t.startsWith(Ci())?t.replace(Ci(),"~"):t,n=yi(t,Pi);if(!n.length)throw new Error(`No config.json files found recursively under ${o}. Add config.json to each directory TIM should watch.`);Uo(t);let i=en(),s=vi();return await i.log({kind:"system",level:"info",message:`TIM version ${r}`,data:{version:r}}),await i.log({kind:"system",level:"info",message:`Listener started in ${o} with ${n.length} configured director${n.length===1?"y":"ies"}`,data:{root:o,configuredDirectories:n.length}}),await i.log({kind:"system",level:"info",message:`Providers: ${s}`,data:{providers:s}}),$r({cwd:t,watchPaths:n,depth:0,target:"**/*",ignore:Pi,createContext:bi,silent:!0,callbacks:{onAdd:fr.create,onChange:fr.update,onUnlink:fr.delete},ignoreLogs:!0})}function Ro(e,t=process.cwd()){if(!e)return Oo.resolve(t);let r=e==="~"?Fi():e.startsWith("~/")?Oo.join(Fi(),e.slice(2)):e;return Oo.resolve(t,r)}function Ai(e={}){return _o(e.bots),_e(e.galleries),Ti({cwd:Ro(e.cwd),version:e.version})}var ki={id:"character-sheets",title:"Character Sheets",description:"Reusable image-to-image workflow for generating polished character sheet outputs from input artwork.",triggers:{create:{"input.*.png":"req-image-to-image","*.image.json":"ai-image"},update:{"input.*.png":"req-image-to-image","*.image.json":"ai-image"}},settings:{"req-image-to-image":{outputNamingConvention:"inputOutputPair",promptId:"character-sheet",sourceImageAsReference:!0,sourceImageReferenceTypes:["character","style"]},"ai-image":{output:{provider:"google",model:"gemini-3-pro-image",aspectRatio:"3:2",imageSize:"4K"}}}};var Ei=_i(new URL("./prompts/character-sheets",import.meta.url)),Zu=_i(new URL("../src/character-sheets/_prompts",import.meta.url)),Qu=Xu.existsSync(Ei)?Ei:Zu,Li={name:"g-character-sheets",aliases:["character-sheets","character-sheet"],config:ki},yr=[Li],$o=[{gallery:Li.name,from:Qu}];_e(yr);var hr={name:"@tim-fs/cli",publishConfig:{access:"public",tag:"alpha"},version:"0.1.4-alpha",type:"module",description:"Turn ordinary folders into explicit, inspectable AI and code workflows that any person, agent, or program can invoke by writing a file",bin:{tim:"dist/index.js"},files:["dist"],scripts:{build:"npm run clean && npm run build:debug","build:release":"node build.mjs --release","build:debug":"node build.mjs",clean:"rm -rf dist",link:"npm run build && npm link",prepack:"npm run clean && npm run build:release",test:"npm run build && node --test test/*.test.mjs",typecheck:"tsc -p tsconfig.json",watch:'nodemon --watch src --ext ts --exec "npm run build"'},keywords:["automation","filesystem","file-watcher","ai","workflow"],license:"MIT",engines:{node:">=20"},repository:{type:"git",url:"git+https://github.com/dht/tim-fs.git",directory:"cli"},bugs:{url:"https://github.com/dht/tim-fs/issues"},homepage:"https://github.com/dht/tim-fs#readme",dependencies:{"@ai-sdk/anthropic":"^3.0.84","@ai-sdk/azure":"^3.0.87","@ai-sdk/bytedance":"^1.0.17","@ai-sdk/elevenlabs":"^2.0.35","@ai-sdk/google":"^3.0.82","@ai-sdk/huggingface":"^1.0.52","@ai-sdk/openai":"^3.0.71","@ai-sdk/xai":"^3.0.95","@elevenlabs/elevenlabs-js":"^2.58.0",ai:"^6.0.205",chokidar:"^5.0.0",commander:"^12.1.0",dotenv:"^17.2.3","fs-extra":"^11.3.2",glob:"13.0.0",kleur:"^4.1.5",lodash:"^4.18.1",logform:"^2.7.0",minimatch:"^10.2.5",openai:"^6.48.0","p-limit":"^7.2.0",sharp:"^0.34.5",winston:"^3.18.3","winston-transport":"^4.9.0",ws:"^8.21.1",yaml:"^2.9.0"},devDependencies:{"@tim-fs/core":"workspace:^","@tim-fs/io-core":"workspace:^","@tim-fs/io-gallery":"workspace:^","@types/node":"^20.19.25",esbuild:"^0.27.2",nodemon:"^3.1.7",typescript:"^5.9.3"}};import{config as ac}from"dotenv";import Be from"node:fs";import tc from"node:os";import br from"node:path";import{parse as rc}from"dotenv";var at=[{name:"OPENAI_API_KEY",label:"OpenAI"},{name:"ANTHROPIC_API_KEY",label:"Anthropic"},{name:"GOOGLE_API_KEY",label:"Google Gemini"},{name:"ELEVENLABS_API_KEY",label:"ElevenLabs",aliases:["ELEVEN_LABS_API_KEY"]},{name:"XAI_API_KEY",label:"xAI"},{name:"HUGGINGFACE_API_KEY",label:"Hugging Face",aliases:["HF_TOKEN","HF_ACCESS_TOKEN"]},{name:"ARK_API_KEY",label:"ByteDance ModelArk"},{name:"AZURE_OPENAI_API_KEY",label:"Azure OpenAI",aliases:["AZURE_API_KEY"]}];function oc(e=process.env){return e.TIM_HOME||br.join(tc.homedir(),".tim")}function Je(e=process.env){return e.TIM_ENV_FILE||br.join(oc(e),".env")}function nc(e){return Be.existsSync(e)?rc(Be.readFileSync(e)):{}}function ic(e,...t){for(let r of t)for(let o of[e.name,...e.aliases||[]]){let n=r[o]?.trim();if(n)return n}return""}function sc(e){return e?JSON.stringify(e):""}function Ni(e={}){let t=e.environment||process.env,r=e.destination||Je(t),o=nc(r);return Object.fromEntries(at.map(n=>[n.name,ic(n,o,t)]))}function Oi(e,t=Je()){let r=["# TIM provider credentials","# Run `npx @tim-fs/cli@alpha init` again to update this file.","",...at.map(o=>`${o.name}=${sc(e[o.name]||"")}`),""];Be.mkdirSync(br.dirname(t),{recursive:!0,mode:448}),Be.chmodSync(br.dirname(t),448),Be.writeFileSync(t,r.join(`
23
23
  `),{encoding:"utf8",mode:384}),Be.chmodSync(t,384)}ac({path:Je(),quiet:!0});import{emitKeypressEvents as pc}from"node:readline";import U from"kleur";var uc=["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557","\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D"," \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557"," \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551"," \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551"," \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"],cc=e=>U.enabled?`\x1B[38;5;208m${e}\x1B[39m`:e;function Ri(e){let t=uc.map((r,o)=>o<3?U.cyan(r):cc(r));console.log(`
24
24
  ${t.join(`
25
25
  `)}`),console.log(`${U.bold("TIM-FS")} ${U.dim(`v${e}`)} ${U.dim("\xB7")} Filesystem automation, made friendly.
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public",
5
5
  "tag": "alpha"
6
6
  },
7
- "version": "0.1.3",
7
+ "version": "0.1.4-alpha",
8
8
  "type": "module",
9
9
  "description": "Turn ordinary folders into explicit, inspectable AI and code workflows that any person, agent, or program can invoke by writing a file",
10
10
  "bin": {