@sous-io/sous 1.0.11 → 1.0.12

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/sous.js CHANGED
@@ -247,7 +247,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
247
247
  `)+`
248
248
  Write the one you mean. A namespace is written with '/*' after it, as in '${written}', and a recipe as its canonical locator above.`)}let[choice]=matches,range3=readings.map(reading=>rangeOf2(tools,reading)).find(written=>written!==void 0);return{identity:choice.location.identity,keys:choice.keys,...range3===void 0?{}:{range:range3}}}function matchIndex(tools,reading,index){if(reading.kind==="recipe"){let key=keyOf2(tools,reading);return Object.hasOwn(index.recipes,key)?[key]:[]}if(reading.kind==="namespace"){let namespace=namespaceNameOf(tools,reading),keys=Object.keys(index.recipes).filter(key=>key.startsWith(`${namespace}/`)).sort();return keys.length>0||namespace!==void 0&&Object.hasOwn(index.namespaces,namespace)?keys:[]}if(reading.kind==="repo"&&reading.browsed!==void 0){let browsed=reading.browsed.replace(/\/+$/,"");return Object.entries(index.recipes).filter(([,recipe])=>browsed===recipe.path||browsed.endsWith(`/${recipe.path.replace(/\/+$/,"")}`)).map(([key])=>key).sort()}return[]}async function readIndexThroughHost(tools,location){let host=tools.entities.get("repository-host",location.provider);if(host===void 0)throw new ConfigError50(`No plugin reads repositories of the host '${location.provider}', so ${location.url} cannot be read.`);let ctx=tools.hostContext(),repository=host.canonicalize(location.url),token;for(let source of host.tokenSources??[])if(token=await source.token(repository,ctx).catch(()=>{}),token!==void 0)break;let attempts=[];for(let strategy of host.readStrategies){if(strategy.usesToken===!0&&token===void 0)continue;let outcome=await strategy.read({repository,path:INDEX_FILE,ref:"HEAD",...token===void 0?{}:{token}},ctx);if(outcome.ok&&"text"in outcome)return tools.indexFile.parse(JSON.parse(outcome.text),`${location.url}/${INDEX_FILE}`);attempts.push(`${strategy.label}: ${outcome.ok?"the host answered without the file":outcome.reason}`)}throw new ConfigError50(`Sous could not read ${INDEX_FILE} from ${location.url}.
249
249
  ${attempts.map(line=>` ${line}`).join(`
250
- `)}`)}var init_settle=__esm({"../plugin-authoring/src/release/settle.ts"(){"use strict";init_problems();init_refs();init_repository()}});import path78 from"node:path";function submissionPolicy(validation,recipe){let own=recipe.manifest.submissions;if(own!==void 0)return{allowed:own.allowed,...own.instead===void 0?{}:{instead:own.instead},declaredBy:"recipe"};let repo=validation.manifest.submissions;return repo!==void 0?{allowed:repo.allowed,...repo.instead===void 0?{}:{instead:repo.instead},declaredBy:"repository"}:{allowed:!0,declaredBy:"default"}}function recipesRefusingSubmissions(validation,changedPaths){let refusing=[];for(let recipe of validation.recipes){let policy=submissionPolicy(validation,recipe);if(policy.allowed||policy.declaredBy==="default")continue;let changed=pathsInside(recipe.path,changedPaths);changed.length>0&&refusing.push({key:recipe.key,path:toPosix2(recipe.path),...policy.instead===void 0?{}:{instead:policy.instead},declaredBy:policy.declaredBy,changed})}return refusing}function pathsInside(folder,paths){let base=toPosix2(path78.posix.normalize(toPosix2(folder))).replace(/\/+$/,"");return paths.map(toPosix2).filter(entry=>base==="."||entry===base||entry.startsWith(`${base}/`))}async function checkSubmissions(git2,validation){let guarded=validation.recipes.filter(recipe=>{let policy=submissionPolicy(validation,recipe);return!policy.allowed&&policy.declaredBy!=="default"});if(guarded.length===0)return{refusing:[],comparedWith:{kind:"none declined"}};let branch=await git2.defaultBranch()??"main",since=await git2.forkPoint(UPSTREAM_REMOTE2,branch);if(since!==void 0)return{refusing:recipesRefusingSubmissions(validation,await git2.pathsChangedSince(since)),comparedWith:{kind:"branch",branch}};let tags2=await listRecipeTags(git2),changed=[],comparedAny=!1;for(let recipe of guarded){let last2=tags2.filter(tag=>recipeTagKey(tag)===recipe.key&&import_semver18.default.valid(tag.version)!==null).sort((left,right)=>import_semver18.default.rcompare(left.version,right.version))[0];last2!==void 0&&(comparedAny=!0,changed.push(...lines2(await git2.run(["diff","--name-only",last2.tag,"HEAD","--",toPosix2(recipe.path)]))))}return{refusing:recipesRefusingSubmissions(validation,changed),comparedWith:comparedAny?{kind:"tags"}:{kind:"nothing"}}}var import_semver18,init_submissions=__esm({"../plugin-authoring/src/release/submissions.ts"(){"use strict";import_semver18=__toESM(require_semver2(),1);init_git();init_repository();init_tags()}});var release_exports={};__export(release_exports,{assertFlagsAgree:()=>assertFlagsAgree,handleRelease:()=>handleRelease,runRelease:()=>runRelease});import fs54 from"node:fs";import{ConfigError as ConfigError51,ReportEntryStyle as ReportEntryStyle7}from"@sous-io/plugin-api";async function handleRelease(input,ctx){let tools=toolsFrom(ctx),result=await runRelease(tools,input,{cwd:ctx.cwd});return!result.dryRun&&result.cancelled!==!0&&result.plan.length>0&&await ctx.emit("authoring.released",{repository:result.repository,recipes:result.plan.map(entry=>({key:entry.key,version:entry.to,tag:entry.tag})),pushed:result.pushed}),outputsOf(tools,result)}async function runRelease(tools,input,options){let reporter=tools.reporter,dryRun4=input.dryRun===!0,ci2=input.ci===!0,noBump=input.noBump===!0||ci2,accepted=input.yes===!0||ci2;assertFlagsAgree(input,noBump);let rootDir=findRepoRoot(tools,input.directory??options.cwd),git2=new RepoGit(tools.git,rootDir),scope=releaseScope(input.namespace??[],input.recipe??[]),base={repository:rootDir,indexPath:indexFilePath(rootDir),dryRun:dryRun4};tools.results.push(tools.commandVariables({Repository:rootDir,Mode:describeMode(input),Scope:describeScope(scope)})),reporter.operationStart("Checking the repository");let validation=await validateRepo(tools,rootDir),scoping=[...validation.problems,...scopeProblems(validation,scope)];reportProblems(tools,scoping),stopOnErrors(scoping),reporter.detail(`Read ${describeCount(validation.recipes.length,"recipe")}.`);let settling=await settleDependencyLocations(tools,validation);reportProblems(tools,settling.problems),stopOnErrors(settling.problems);let problems=[...scoping,...settling.problems];if(input.check===!0)return runCheck(tools,git2,validation,settling.settled,problems,base,options.now);let branch=await git2.currentBranch(),mainBranch=await git2.defaultBranch(),willTag=mainBranch===void 0||branch===void 0||branch===mainBranch||input.tag===!0,plan=await buildReleasePlan(tools,git2,{validation,scope,...input.bump===void 0?{}:{bump:input.bump},noBump,includeUnchanged:input.includeUnchanged===!0});reportProblems(tools,plan.problems),stopOnErrors(plan.problems),problems.push(...plan.problems),reportPlan(tools,plan,{willTag,branch,push:input.push===!0});let empty={...base,ok:!0,problems,indexChanged:!1,tagged:[],pushed:!1,skipped:plan.skipped};if(plan.releases.length===0)return{...empty,plan:[]};let entries=hashes2=>plan.releases.map(release=>planEntry(release,hashes2.get(release.key)??""));if(dryRun4)return tools.results.push(textOutput("Nothing was written; this was a dry run.",ReportEntryStyle7.DryRun)),{...empty,plan:entries(await workingHashes(tools,validation))};if(!accepted&&!await tools.prompter.confirm({message:"Publish these versions?",answeredBy:"--yes",default:!0}))return reporter.detail("Nothing was written."),{...empty,plan:entries(await workingHashes(tools,validation)),cancelled:!0};await assertNothingUncommitted(git2),await assertCommitIdentity(git2),reporter.operationStart("Publishing");let changedPaths=[];for(let release of plan.releases){if(release.bump===void 0){reporter.detail(`${release.key}: publishing version ${release.to}.`);continue}let bumped=bumpRecipeVersion(release.manifestPath,release.bump);reporter.detail(`${release.key}: ${bumped.from} becomes ${bumped.to}.`),changedPaths.push(release.manifestPath)}validation=await validateRepo(tools,rootDir),reportProblems(tools,validation.problems),stopOnErrors(validation.problems);let publishing={};for(let release of plan.releases)publishing[release.key]=release.to;let existing=readExistingIndex(tools,rootDir),rebuilt2=await buildIndex(tools,git2,{validation,...existing===void 0?{}:{existing},sousVersion:tools.sousVersion,publishing,settled:settling.settled,...options.now===void 0?{}:{now:options.now}});reportProblems(tools,rebuilt2.problems),stopOnErrors(rebuilt2.problems),problems.push(...rebuilt2.problems),rebuilt2.stale?(fs54.writeFileSync(indexFilePath(rootDir),rebuilt2.text,"utf8"),reporter.operation("written",indexFilePath(rootDir)),changedPaths.push(indexFilePath(rootDir))):reporter.detail(`The committed ${INDEX_FILE} was already current.`);let message2=`Release ${plan.releases.map(release=>`${release.key}@${release.to}`).join(", ")}`,committed=!1;await git2.anythingToCommit(changedPaths)?(await git2.commitPaths(changedPaths,message2),committed=!0,reporter.detail(`Committed: ${message2}`)):reporter.detail("Nothing to commit; the manifests and the index were already current.");let tagged=[];if(willTag)for(let release of plan.releases)await git2.createAnnotatedTag(release.tag,`Release ${release.key} version ${release.to}`),tagged.push(release.tag),reporter.detail(`Created the tag ${release.tag}.`);else tools.results.push(textOutput(`No tags were cut: this is the branch '${branch}', and tags are cut on the default branch '${mainBranch}'. Continuous integration does that after the merge, or pass '--tag' to cut them here.`,ReportEntryStyle7.Note));let pushed=!1;if(input.push===!0){if(await git2.remoteUrl(UPSTREAM_REMOTE2)===void 0)throw new ConfigError51(`The release was made, but this repository has no '${UPSTREAM_REMOTE2}' remote to push it to.
250
+ `)}`)}var init_settle=__esm({"../plugin-authoring/src/release/settle.ts"(){"use strict";init_problems();init_refs();init_repository()}});import path78 from"node:path";function submissionPolicy(validation,recipe){let own=recipe.manifest.submissions;if(own!==void 0)return{allowed:own.allowed,...own.instead===void 0?{}:{instead:own.instead},declaredBy:"recipe"};let repo=validation.manifest.submissions;return repo!==void 0?{allowed:repo.allowed,...repo.instead===void 0?{}:{instead:repo.instead},declaredBy:"repository"}:{allowed:!0,declaredBy:"default"}}function recipesRefusingSubmissions(validation,changedPaths){let refusing=[];for(let recipe of validation.recipes){let policy=submissionPolicy(validation,recipe);if(policy.allowed||policy.declaredBy==="default")continue;let changed=pathsInside(recipe.path,changedPaths);changed.length>0&&refusing.push({key:recipe.key,path:toPosix2(recipe.path),...policy.instead===void 0?{}:{instead:policy.instead},declaredBy:policy.declaredBy,changed})}return refusing}function pathsInside(folder,paths){let base=toPosix2(path78.posix.normalize(toPosix2(folder))).replace(/\/+$/,"");return paths.map(toPosix2).filter(entry=>base==="."||entry===base||entry.startsWith(`${base}/`))}async function checkSubmissions(git2,validation){let guarded=validation.recipes.filter(recipe=>{let policy=submissionPolicy(validation,recipe);return!policy.allowed&&policy.declaredBy!=="default"});if(guarded.length===0)return{refusing:[],comparedWith:{kind:"none declined"}};let branch=await git2.defaultBranch()??"main",since=await git2.forkPoint(UPSTREAM_REMOTE2,branch);if(since!==void 0)return{refusing:recipesRefusingSubmissions(validation,await git2.pathsChangedSince(since)),comparedWith:{kind:"branch",branch}};let tags2=await listRecipeTags(git2),changed=[],comparedAny=!1;for(let recipe of guarded){let last2=tags2.filter(tag=>recipeTagKey(tag)===recipe.key&&import_semver18.default.valid(tag.version)!==null).sort((left,right)=>import_semver18.default.rcompare(left.version,right.version))[0];last2!==void 0&&(comparedAny=!0,changed.push(...lines2(await git2.run(["diff","--name-only",last2.tag,"HEAD","--",toPosix2(recipe.path)]))))}return{refusing:recipesRefusingSubmissions(validation,changed),comparedWith:comparedAny?{kind:"tags"}:{kind:"nothing"}}}var import_semver18,init_submissions=__esm({"../plugin-authoring/src/release/submissions.ts"(){"use strict";import_semver18=__toESM(require_semver2(),1);init_git();init_repository();init_tags()}});var release_exports={};__export(release_exports,{assertFlagsAgree:()=>assertFlagsAgree,handleRelease:()=>handleRelease,runRelease:()=>runRelease});import fs54 from"node:fs";import{ConfigError as ConfigError51,ReportEntryStyle as ReportEntryStyle7}from"@sous-io/plugin-api";async function handleRelease(input,ctx){let tools=toolsFrom(ctx),result=await runRelease(tools,input,{cwd:ctx.cwd});return!result.dryRun&&result.cancelled!==!0&&result.plan.length>0&&await ctx.emit("authoring.released",{repository:result.repository,recipes:result.plan.map(entry=>({key:entry.key,version:entry.to,tag:entry.tag})),pushed:result.pushed}),outputsOf(tools,result)}async function runRelease(tools,input,options){let reporter=tools.reporter,dryRun4=input.dryRun===!0,ci2=input.ci===!0,noBump=input.noBump===!0||ci2,accepted=input.yes===!0||ci2;assertFlagsAgree(input,noBump);let rootDir=findRepoRoot(tools,input.directory??options.cwd);if(await tools.git.root(rootDir)===void 0)throw new ConfigError51(`${rootDir} is not inside a git repository, and a release reads its tags and commits.
251
+ Nothing was changed. Run 'git init' there and commit the repository, then run the release again.`);let git2=new RepoGit(tools.git,rootDir),scope=releaseScope(input.namespace??[],input.recipe??[]),base={repository:rootDir,indexPath:indexFilePath(rootDir),dryRun:dryRun4};tools.results.push(tools.commandVariables({Repository:rootDir,Mode:describeMode(input),Scope:describeScope(scope)})),reporter.operationStart("Checking the repository");let validation=await validateRepo(tools,rootDir),scoping=[...validation.problems,...scopeProblems(validation,scope)];reportProblems(tools,scoping),stopOnErrors(scoping),reporter.detail(`Read ${describeCount(validation.recipes.length,"recipe")}.`);let settling=await settleDependencyLocations(tools,validation);reportProblems(tools,settling.problems),stopOnErrors(settling.problems);let problems=[...scoping,...settling.problems];if(input.check===!0)return runCheck(tools,git2,validation,settling.settled,problems,base,options.now);let branch=await git2.currentBranch(),mainBranch=await git2.defaultBranch(),willTag=mainBranch===void 0||branch===void 0||branch===mainBranch||input.tag===!0,plan=await buildReleasePlan(tools,git2,{validation,scope,...input.bump===void 0?{}:{bump:input.bump},noBump,includeUnchanged:input.includeUnchanged===!0});reportProblems(tools,plan.problems),stopOnErrors(plan.problems),problems.push(...plan.problems),reportPlan(tools,plan,{willTag,branch,push:input.push===!0});let empty={...base,ok:!0,problems,indexChanged:!1,tagged:[],pushed:!1,skipped:plan.skipped};if(plan.releases.length===0)return{...empty,plan:[]};let entries=hashes2=>plan.releases.map(release=>planEntry(release,hashes2.get(release.key)??""));if(dryRun4)return tools.results.push(textOutput("Nothing was written; this was a dry run.",ReportEntryStyle7.DryRun)),{...empty,plan:entries(await workingHashes(tools,validation))};if(!accepted&&!await tools.prompter.confirm({message:"Publish these versions?",answeredBy:"--yes",default:!0}))return reporter.detail("Nothing was written."),{...empty,plan:entries(await workingHashes(tools,validation)),cancelled:!0};await assertNothingUncommitted(git2),await assertCommitIdentity(git2),reporter.operationStart("Publishing");let changedPaths=[];for(let release of plan.releases){if(release.bump===void 0){reporter.detail(`${release.key}: publishing version ${release.to}.`);continue}let bumped=bumpRecipeVersion(release.manifestPath,release.bump);reporter.detail(`${release.key}: ${bumped.from} becomes ${bumped.to}.`),changedPaths.push(release.manifestPath)}validation=await validateRepo(tools,rootDir),reportProblems(tools,validation.problems),stopOnErrors(validation.problems);let publishing={};for(let release of plan.releases)publishing[release.key]=release.to;let existing=readExistingIndex(tools,rootDir),rebuilt2=await buildIndex(tools,git2,{validation,...existing===void 0?{}:{existing},sousVersion:tools.sousVersion,publishing,settled:settling.settled,...options.now===void 0?{}:{now:options.now}});reportProblems(tools,rebuilt2.problems),stopOnErrors(rebuilt2.problems),problems.push(...rebuilt2.problems),rebuilt2.stale?(fs54.writeFileSync(indexFilePath(rootDir),rebuilt2.text,"utf8"),reporter.operation("written",indexFilePath(rootDir)),changedPaths.push(indexFilePath(rootDir))):reporter.detail(`The committed ${INDEX_FILE} was already current.`);let message2=`Release ${plan.releases.map(release=>`${release.key}@${release.to}`).join(", ")}`,committed=!1;await git2.anythingToCommit(changedPaths)?(await git2.commitPaths(changedPaths,message2),committed=!0,reporter.detail(`Committed: ${message2}`)):reporter.detail("Nothing to commit; the manifests and the index were already current.");let tagged=[];if(willTag)for(let release of plan.releases)await git2.createAnnotatedTag(release.tag,`Release ${release.key} version ${release.to}`),tagged.push(release.tag),reporter.detail(`Created the tag ${release.tag}.`);else tools.results.push(textOutput(`No tags were cut: this is the branch '${branch}', and tags are cut on the default branch '${mainBranch}'. Continuous integration does that after the merge, or pass '--tag' to cut them here.`,ReportEntryStyle7.Note));let pushed=!1;if(input.push===!0){if(await git2.remoteUrl(UPSTREAM_REMOTE2)===void 0)throw new ConfigError51(`The release was made, but this repository has no '${UPSTREAM_REMOTE2}' remote to push it to.
251
252
  Add one with 'git remote add ${UPSTREAM_REMOTE2} <url>', then push the commit and its tags yourself.`);branch!==void 0&&(await git2.pushBranch(UPSTREAM_REMOTE2,branch),reporter.detail(`Pushed the branch '${branch}' to ${UPSTREAM_REMOTE2}.`)),tagged.length>0&&(await git2.pushTags(UPSTREAM_REMOTE2,tagged),reporter.detail(`Pushed ${describeCount(tagged.length,"tag")} to ${UPSTREAM_REMOTE2}.`)),pushed=!0}else{let next=[`Push the commit with 'git push ${UPSTREAM_REMOTE2} ${branch??"<branch>"}'.`];tagged.length>0&&next.push(`Push the tags with 'git push ${UPSTREAM_REMOTE2} --tags'.`),next.push("Or run this command again with '--push', which does both."),tools.results.push(listOutput2(next,{title:"What to do next"}))}let hashes=new Map(plan.releases.map(release=>[release.key,rebuilt2.index.recipes[release.key]?.versions[release.to]?.hash??""]));return{...base,ok:!0,problems,plan:entries(hashes),index:rebuilt2.index,indexChanged:rebuilt2.stale,tagged,pushed,committed,skipped:plan.skipped}}async function runCheck(tools,git2,validation,settled,problems,base,now){let reporter=tools.reporter;reporter.operationStart("Checking the index");let existing=readExistingIndex(tools,validation.rootDir),result=await buildIndex(tools,git2,{validation,...existing===void 0?{}:{existing},sousVersion:tools.sousVersion,settled,...now===void 0?{}:{now}});reportProblems(tools,result.problems),stopOnErrors(result.problems),problems.push(...result.problems);let drift=result.stale?describeIndexDrift(existing,result.index):[];result.stale?tools.results.push(listOutput2(drift,{title:`Merging rewrites the committed ${INDEX_FILE}, because:`})):reporter.detail(`The committed ${INDEX_FILE} is current, and so are the dependencies it records for every version it publishes.`),result.pending.length>0&&tools.results.push(listOutput2(result.pending.map(entry=>`${entry.key}: ${entry.version} (the tag would be ${entry.tag})`),{title:"These versions have no tag yet; they publish when this merges:"})),reporter.operationStart("Checking the recipes that take no proposals");let submissions=await checkSubmissions(git2,validation);if(submissions.refusing.length>0){let refused=submissions.refusing.map(recipe=>({level:"error",recipe:recipe.key,where:recipe.path,message:`this change touches '${recipe.key}', which does not take proposed changes (${recipe.declaredBy==="recipe"?"its own manifest":"the repository manifest"} says so). Merging it would break whatever publishes the recipe.`+(recipe.instead===void 0?"":` Instead: ${recipe.instead}`)}));throw reportProblems(tools,refused),new ConfigError51(`This change cannot be merged: it touches ${describeCount(refused.length,"recipe")} that ${refused.length===1?"does":"do"} not take proposed changes, listed above.
252
253
  Take those edits out of the change, and send them where each recipe asks.`,{details:refused.map(problem=>`${problem.where}: ${problem.message}`)})}let compared=submissions.comparedWith;compared.kind==="branch"?reporter.detail(`Compared with the branch '${compared.branch}': this change touches no recipe that declines proposals.`):compared.kind==="tags"?reporter.detail("Compared with each recipe's last release tag: nothing that declines proposals changed."):compared.kind==="none declined"?reporter.detail("No recipe in this repository declines proposed changes."):tools.results.push(textOutput("This checkout holds neither a copy of the default branch nor a release tag of any recipe that declines proposed changes, so there was nothing to compare with.",ReportEntryStyle7.Note));let plan=result.pending.map(entry=>({key:entry.key,path:entry.path,to:entry.version,bump:"none",reason:"changed",tag:entry.tag,hash:entry.hash,changelog:[`${entry.key}: ${entry.version} publishes when this merges`]}));return{...base,dryRun:!0,ok:!0,problems,plan,index:result.index,indexChanged:result.stale,tagged:[],pushed:!1,drift}}function assertFlagsAgree(input,noBump){if(input.check===!0&&input.ci===!0)throw new ConfigError51(`'--check' and '--ci' cannot be used together.
253
254
  '--check' only reads, and reports whether a release is needed; '--ci' makes one.
@@ -759,7 +760,7 @@ ${problem}`}throw new CancelledError2(question.message,`the answer was not accep
759
760
  })`),!0}catch{return!1}}function isEsModuleSource(source){return!parsesAsCommonJs(source)}function declareConfigModule(file2,url2){let hooks=module.registerHooks;typeof hooks!="function"||!file2.endsWith(".js")||(registered.add(url2.split("?")[0]),!hooked&&(hooked=!0,hooks({load(loadUrl,context,nextLoad){if(!registered.has(loadUrl.split("?")[0])||!(context.format===void 0||context.format===null||context.format==="commonjs"))return nextLoad(loadUrl,context);let source;try{source=fs3.readFileSync(fileURLToPath(loadUrl.split("?")[0]),"utf8")}catch{return nextLoad(loadUrl,context)}return isEsModuleSource(source)?{format:"module",source,shortCircuit:!0}:nextLoad(loadUrl,context)}})))}var ConfigFilesLoaderImpl=class{constructor(host){this.host=host}cache=new Map;stamps=new Map;formatOf(fileName){return formatOf(fileName)}findMain(sousDir){return mainCandidates(sousDir)[0]}findPatches(directory,baseName=MAIN_CONFIG_BASE_NAME){let names2;try{names2=fs4.readdirSync(directory)}catch{return[]}let matches=names2.filter(name=>{let format3=formatOf(name);return(format3==="patch-json"||format3==="patch-jsonl")&&name.startsWith(`${baseName}.`)&&isFile(path6.join(directory,name))});return this.host.globs().sortBytewise(matches).map(name=>path6.join(directory,name))}forget(file2){file2===void 0?this.cache.clear():this.cache.delete(path6.resolve(file2))}async load(file2){let resolved=path6.resolve(file2),cached2=this.cache.get(resolved);if(cached2!==void 0)return cached2;let loaded=await this.read(resolved);return this.cache.set(resolved,loaded),loaded}async contribute(file2,config2,options={}){let label=options.label??this.label(file2.path);try{switch(file2.kind){case"data":this.mergeData(config2,file2.data,label,options.fromRecipe===!0);break;case"patch":config2.apply(file2.patches);break;case"module":await file2.configure(config2);break}}catch(error51){throw namingFile(error51,label,file2.path)}}label(file2){let sousDir=this.host.project?.sousDir;if(sousDir!==void 0){let relative4=path6.relative(sousDir,file2);if(relative4!==""&&!relative4.startsWith("..")&&!path6.isAbsolute(relative4))return relative4.split(path6.sep).join("/")}return file2}mergeData(config2,data,label,fromRecipe=!1){let evaluated=this.evaluate(config2,data,label,fromRecipe);if(evaluated!=null){if(!isJsonObject(evaluated))throw new ConfigError5(`${label} did not produce a plain object (got ${Array.isArray(evaluated)?"an array":typeof evaluated}).`);assertNotOldSchema(evaluated,label),config2.root().merge(evaluated)}}evaluate(config2,data,label,fromRecipe){let evaluator=this.host.evaluator();return evaluator===void 0||!evaluator.hasExpressions(data)?data:evaluator.evaluateLayer(data,{file:label,config:config2,ownVars:ownVars(data),fromRecipe}).value}async read(file2){let label=this.label(file2),format3=formatOf(path6.basename(file2));if(format3===void 0)throw new ConfigError5(`${label} is not a kind of file sous reads as config.`,{details:["Config files end in .json, .jsonc, .yaml, .yml, .js, .mjs, .ts, .patch.json or .patch.jsonl."]});let text;try{text=fs4.readFileSync(file2,"utf8")}catch(error51){throw new ConfigError5(`Could not read the config file ${label}.`,{cause:error51,details:[error51.message]})}try{switch(format3){case"json":case"jsonc":case"yaml":{let data=parseDocument2(text,format3).value()??{};return{kind:"data",path:file2,format:format3,data,text}}case"patch-json":case"patch-jsonl":{let set2=parsePatchFile(text,format3==="patch-json"?"json":"jsonl",label);return{kind:"patch",path:file2,format:format3,patches:set2.patches,text}}case"js":case"ts":{let exports=moduleExports(await this.importFile(file2,format3),label),configure=moduleConfigure(exports,{label,path:file2,sousDir:this.host.project?.sousDir,confDir:this.host.project?.confDir,mergeData:(config2,data)=>this.mergeData(config2,data,label),loadInto:(draft,specifier,glob,run)=>this.loadInto(draft,specifier,glob,run,file2)});return{kind:"module",path:file2,format:format3,configure,text}}}}catch(error51){throw namingFile(error51,label,file2)}}async importFile(file2,format3){let stat6=fs4.statSync(file2),stamp=`${stat6.mtimeMs}:${stat6.size}`,previous=this.stamps.get(file2),version2=previous===void 0?0:previous.stamp===stamp?previous.version:previous.version+1;this.stamps.set(file2,{stamp,version:version2});let base=pathToFileURL3(file2).href,url2=version2===0?base:`${base}?sous-reload=${version2}`;if(this.host.importModule!==void 0)return this.host.importModule(url2,file2);declareConfigModule(file2,url2);try{return await import(url2)}catch(error51){throw format3==="ts"&&needsTypeStripping(error51)?new ConfigError5(`${this.label(file2)} is TypeScript that this Node.js (${process.version}) cannot run.`,{details:["Node 22.18 or later runs TypeScript whose types can simply be removed; enums, namespaces and parameter properties need a compiler.","Use a newer Node, write the config without those, or write it as sous.config.js."]}):error51}}async loadInto(draft,specifier,glob,run,from){let where2=`${glob?"loadConfigs":"loadConfig"}(${JSON.stringify(specifier)}) in ${this.label(from)}`,variables=this.host.pathVariables(),substituted=String(specifier).replace(/\$\{([^}]+)\}/g,(_match,name)=>{let value=variables[name];if(value===void 0)throw new ConfigError5(`${where2}: \${${name}} cannot be used in a builder path.`,{details:["Builder paths are read before variables are resolved, so only these can be used:",Object.keys(variables).map(key=>`\${${key}}`).join(", ")]});return value}),resolved=path6.isAbsolute(substituted)?path6.normalize(substituted):path6.resolve(path6.dirname(from),substituted),files=glob?this.matchFiles(resolved):[resolved];for(let file2 of files){if(!isFile(file2))throw new ConfigError5(`${where2}: no config file at ${file2}.`);let loaded=await this.load(file2);switch(loaded.kind){case"data":mergeLegacy(draft,loaded.data,this.label(file2));break;case"module":{let exports=moduleExports(await this.importFile(file2,loaded.format),this.label(file2));await run(exports,file2);break}case"patch":throw new ConfigError5(`${where2}: ${this.label(file2)} is a patch file; list it in conf.d instead.`)}}}matchFiles(pattern){let globs=this.host.globs(),posix=globs.toPosix(pattern),base=globs.staticBase(posix);return globs.matchSync(path6.posix.relative(base,posix),{cwd:base,absolute:!0})}};function mainCandidates(sousDir){return MAIN_CONFIG_FILE_NAMES.map(name=>path6.join(sousDir,name)).filter(isFile)}function ownVars(data){if(!isJsonObject(data)||!isJsonObject(data._vars))return;let result={};for(let[key,value]of Object.entries(data._vars))typeof value=="string"&&(result[key]=value);return result}function assertNotOldSchema(data,label){if("projects"in data||"defaultProject"in data)throw new ConfigError5(`${label} uses the removed multi-project schema ('projects' / 'defaultProject').`,{details:["A sous config now describes exactly one project. To migrate:"," 1. Move your single project's fields (name, _vars, _aliases, compilation,"," runtimeContext, tools) to the top level of the config."," 2. Delete the 'projects' and 'defaultProject' keys.","A config with several projects must be split into one config per project."]})}function namingFile(error51,label,file2){let message2=error51 instanceof Error?error51.message:String(error51);return message2.includes(label)||message2.includes(file2)?error51:isSousError(error51)?new ConfigError5(`${label}: ${message2}`,{cause:error51,details:error51.details}):new ConfigError5(`${label} failed to load: ${message2}`,{cause:error51})}function needsTypeStripping(error51){let code=error51?.code;return code==="ERR_UNKNOWN_FILE_EXTENSION"||code==="ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX"||code==="ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING"||code==="ERR_INVALID_TYPESCRIPT_SYNTAX"||error51 instanceof SyntaxError&&/typescript|type annotation|Unexpected token/i.test(error51.message)}function isFile(file2){try{return fs4.statSync(file2).isFile()}catch{return!1}}init_src();import fs5 from"node:fs";import path7 from"node:path";import{InputError as InputError2,IntentOutputs as IntentOutputs2,SousError as SousError6}from"@sous-io/plugin-api";var CONFIG_SET="config.set",NEW_MAIN_NAME="sous.config.jsonc";function parseCliValue(text){try{return toPlainJson(JSON.parse(text))??text}catch{return text}}function resolveSetTarget(project,file2){if(file2===void 0||file2==="")return project.configPath??mainCandidates(project.sousDir)[0]??path7.join(project.sousDir,NEW_MAIN_NAME);if(path7.isAbsolute(file2))return file2;if(!file2.includes("/")&&!file2.includes(path7.sep)){let inConfd=path7.join(project.confDir,file2);return fs5.existsSync(inConfd)||!MAIN_CONFIG_FILE_NAMES.includes(file2)?inConfd:path7.join(project.sousDir,file2)}return path7.resolve(project.root,file2)}function describeSet(result){let removing=result.value===void 0;if(!result.changed)return removing?`${result.path} is not set in ${result.file}, so nothing changed.`:`${result.path} already has that value in ${result.file}, so nothing changed.`;let change=removing?`${result.path} removed`:`${result.path} set to ${JSON.stringify(result.value)}`;return result.dryRun?`Would change ${result.file}: ${change}.`:`Changed ${result.file}: ${change}.`}async function configSet(input,ctx){let project=ctx.project;if(project===void 0)throw new SousError6("There is no sous project here, so there is no config file to change.",{details:["Run sous init in the project root first."]});let segments;try{segments=parsePath(input.path)}catch(error51){throw new InputError2(CONFIG_SET,[{path:"path",message:error51.message}])}if(segments.length===0)throw new InputError2(CONFIG_SET,[{path:"path",message:"Name a key, such as compilation.includeSourceComments."}]);if(input.unset!==!0&&input.value===void 0)throw new InputError2(CONFIG_SET,[{path:"value",message:"Give a value, or --unset to remove the key."}]);let file2=resolveSetTarget(project,input.file),format3=formatOf(path7.basename(file2));if(format3!=="json"&&format3!=="jsonc"&&format3!=="yaml"){let name=path7.basename(file2),message2=input.file===void 0||input.file===""?`The main config ${name} is code, so sous cannot edit it. Pass --file with a JSON, JSONC or YAML file to write the value to, such as --file 600-settings.jsonc (created in .sous/conf.d/).`:`${name} is not a JSON, JSONC or YAML file, so sous cannot edit it. Pass --file with one that is, such as --file 600-settings.jsonc (created in .sous/conf.d/).`;throw new InputError2(CONFIG_SET,[{path:"file",message:message2}])}let text=fs5.existsSync(file2)?fs5.readFileSync(file2,"utf8"):format3==="yaml"?"":`{}
760
761
  `,document;try{document=parseDocument2(text,format3)}catch(error51){throw new SousError6(`Could not read ${file2}: ${error51.message}`,{cause:error51})}let node=document.atPath(segments),previous=node.get(),value=input.unset===!0?void 0:parseCliValue(input.value);value===void 0?previous!==void 0&&node.delete():node.set(value);let after=document.toString();after!==""&&!after.endsWith(`
761
762
  `)&&(after+=`
762
- `);let changed=after!==text,dryRun4=input.dryRun===!0;changed&&!dryRun4&&writeFileAtomically(file2,after,420);let result={file:file2,path:input.path,previous,value,changed,dryRun:dryRun4};return IntentOutputs2.of(result,{summary:describeSet(result)})}var package_default={name:"@sous-io/plugin-config-files",version:"1.0.11",description:"sous.config.* as a contributor, config.set, and the .env files.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/documents":"workspace:*","@sous-io/plugin-api":"workspace:*","@sous-io/plugin-expressions":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-variables":"workspace:*",tsx:"^4.21.0"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};import fs6 from"node:fs";import path8 from"node:path";function loadEnvFile(filePath,env){if(!fs6.existsSync(filePath))return{filePath,loaded:!1,applied:[],skipped:[]};let applied=[],skipped=[];for(let[key,value]of Object.entries(parseEnv(fs6.readFileSync(filePath,"utf8")))){if(env[key]!==void 0){skipped.push(key);continue}env[key]=value,applied.push(key)}return{filePath,loaded:!0,applied,skipped}}function loadEnvDefaults(sousDir,env){return loadEnvFile(path8.join(sousDir,ENV_SHARED_NAME),env)}function loadEnvLocal(sousDir,env){return loadEnvFile(path8.join(sousDir,ENV_LOCAL_NAME),env)}function loadEnvFiles(sousDir,env){let local2=loadEnvLocal(sousDir,env),defaults2=loadEnvDefaults(sousDir,env);return{local:local2,defaults:defaults2}}function projectEnvironment(project,env){let result={...env};return project!==void 0&&loadEnvFiles(project.sousDir,result),Object.freeze(result)}var PLUGIN_NAME="@sous-io/plugin-config-files",MAIN_CONTRIBUTOR="config-files.main",PATCH_CONTRIBUTOR_PREFIX="config-files/",MAIN_APPLY_ORDER=89900,configFilesPlugin=definePlugin({name:PLUGIN_NAME,version:package_default.version,description:"sous.config.* as a contributor, config.set, and the .env files.",dependsOn:{"@sous-io/plugin-expressions":`^${package_default.version}`,"@sous-io/plugin-variables":`^${package_default.version}`,"@sous-io/plugin-host":`^${package_default.version}`},register(sous){let loader=createLoader(sous);if(sous.services.add("config-files.loader",()=>loader,{lifetime:"singleton"}),sous.services.add("config-files.env",(_config,ctx)=>new EnvFilesService(ctx.project,ctx.env),{lifetime:"singleton"}),sous.config.contribute(mainContributor(loader)),sous.project!==void 0)for(let file2 of loader.findPatches(sous.project.sousDir,MAIN_CONFIG_BASE_NAME))sous.config.contribute(fileContributor(loader,file2,`${PATCH_CONTRIBUTOR_PREFIX}${path9.basename(file2)}`));sous.intents.add({intent:CONFIG_SET,requiresProject:!0,summary:"Set one value in a config file",description:"Writes one value into sous.config.* (or the file --file names), changing only that key: comments, key order and formatting stay. The value is read as JSON when it is valid JSON, else as text. A main config written as code (sous.config.js or .ts) cannot be edited; name a JSON, JSONC or YAML file with --file.",input:jsonSchema2({type:"object",properties:{path:{type:"string",description:'The key path: compilation.includeSourceComments, subscriptions."workflow/x".enabled.'},value:{type:"string",description:"The value: JSON when it is valid JSON, else text."},unset:{type:"boolean",description:"Remove the key instead."},file:{type:"string",description:"The file to write: a conf.d file name, or a path from the project root. Default: sous.config.* when it is JSON, JSONC or YAML; a code config needs this."},dryRun:{type:"boolean",description:"Show what would change, writing nothing."}},required:["path"]}),changesConfig:!0,cli:{command:["config","set"],positional:["path","value"],examples:["sous config set compilation.includeSourceComments false",'sous config set subscriptions."workflow/x".enabled false --file 610-mac.jsonc',"sous config set name --unset"]},agent:{tool:"sous_config_set",usage:"Call this to change one config value without rewriting the file.",whenNotToUse:"Not for subscriptions or repositories: use their own intents, which keep the lockfile in step."},handle:(input,ctx)=>configSet(input,ctx)}),sous.entities.add("config-key",{id:"$schema",description:"The JSON Schema the file declares, for editors. Sous ignores it.",schema:jsonSchema2({type:"string"})}),sous.entities.add("config-key",{id:"version",description:"The config format version. This sous understands version 1.",schema:jsonSchema2({const:1})}),sous.entities.add("config-key",{id:"name",description:"A display name for the project.",schema:jsonSchema2({type:"string"})})}});function createLoader(sous){return new ConfigFilesLoaderImpl({get project(){return sous.project},globs:()=>sous.services.get("host.globs"),evaluator:()=>sous.services.has("expressions.evaluator")?sous.services.get("expressions.evaluator"):void 0,pathVariables:()=>{let variables={};if(sous.project!==void 0&&(variables.sousDir=sous.project.sousDir,variables.sousConfDir=sous.project.confDir),sous.services.has("host.package")){let identity2=sous.services.get("host.package").identity();variables.sousRootPath=identity2.root,variables.sousVersion=identity2.version}return variables}})}function mainContributor(loader){return{id:MAIN_CONTRIBUTOR,applyOrder:MAIN_APPLY_ORDER,async contribute(config2){let project=config2.project;if(project===void 0)return;let candidates=mainCandidates(project.sousDir),file2=project.configPath??candidates[0];if(file2!==void 0){if(config2.contributor.run===1){if(candidates.length>1)throw new ConfigError6(`Duplicate config file baseName '${MAIN_CONFIG_BASE_NAME}':`,{details:[...candidates.map(candidate=>` ${candidate}`),"Two config files in one directory must not share a name once the final extension is removed. Delete or rename one of them."]});loader.forget(file2)}await applyFile(loader,file2,config2)}}}}function fileContributor(loader,file2,id){let format3=loader.formatOf(path9.basename(file2));return{id,applyOrder:MAIN_APPLY_ORDER,...format3==="patch-json"||format3==="patch-jsonl"?{monitors:[""]}:{},async contribute(config2){config2.contributor.run===1&&loader.forget(file2),await applyFile(loader,file2,config2)}}}async function applyFile(loader,file2,config2){isFile2(file2)&&await loader.contribute(await loader.load(file2),config2)}function isFile2(file2){try{return fs7.statSync(file2).isFile()}catch{return!1}}import{definePlugin as definePlugin30}from"@sous-io/plugin-api";import os from"node:os";import{definePlugin as definePlugin2,IntentOutput as IntentOutput4,IntentOutputs as IntentOutputs7,jsonSchema as jsonSchema5,LOG_LEVELS,TextBlock as TextBlock4,VariableSet as VariableSet2}from"@sous-io/plugin-api";import{ConflictError as ConflictError3,toJsonSchema}from"@sous-io/plugin-api";function toKebab(name){return name.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/_/g,"-").toLowerCase()}function suggest(typed,candidates){let limit2=Math.max(2,Math.floor(typed.length/3)),scored=[];for(let word of new Set(candidates)){let distance=editDistance(typed.toLowerCase(),word.toLowerCase());distance<=limit2?scored.push({word,score:distance}):typed.length>=2&&word.startsWith(typed)&&scored.push({word,score:limit2+1})}return scored.sort((a,b)=>a.score-b.score||(a.word<b.word?-1:1)).slice(0,3).map(item=>item.word)}function editDistance(a,b){let previous=Array.from({length:b.length+1},(_2,index)=>index);for(let i=1;i<=a.length;i++){let current=[i];for(let j2=1;j2<=b.length;j2++){let cost=a[i-1]===b[j2-1]?0:1;current[j2]=Math.min(previous[j2]+1,current[j2-1]+1,previous[j2-1]+cost)}previous=current}return previous[b.length]}function argumentsFromSchema(schema,cli={}){let properties=schema?.properties??{},required2=new Set(schema?.required??[]),flags=[];for(let[field,property]of Object.entries(properties)){let options=cli.flags?.[field]??{},{kind,multiple}=kindOf(property),name=toKebab(field),aliases=(options.aliases??[]).filter(alias=>alias.length>1),shorts=extraShorts(kind,[name,...aliases],options).filter(letter=>letter!==options.short);flags.push({field,name,aliases,short:options.short??shorts[0],shorts:options.short?shorts:shorts.slice(1),kind,multiple,description:property.description,defaultValue:property.default,choices:choicesOf(property),required:required2.has(field)&&property.default===void 0,hidden:options.hidden??!1})}let names2=cli.positional??[],positionals=names2.map((field,index)=>{let property=properties[field]??{},{kind,multiple}=kindOf(property);return{field,name:toKebab(field),kind,variadic:multiple&&index===names2.length-1,required:required2.has(field)&&property.default===void 0,description:property.description}});return{flags,positionals}}var CONFIRMATION_SHORTS={yes:"y",force:"f"};function extraShorts(kind,names2,options){let letters=(options.aliases??[]).filter(alias=>alias.length===1);if(kind==="boolean")for(let name of names2){let letter=CONFIRMATION_SHORTS[name];letter&&letters.push(letter)}return[...new Set(letters)]}function kindOf(property){let type=primaryType(property);if(type==="array"){let itemType=property.items?primaryType(property.items):"string";return{kind:scalarKind(itemType),multiple:!0}}return type===void 0&&property.enum?{kind:property.enum.every(item=>typeof item=="number")?"number":"string",multiple:!1}:{kind:scalarKind(type),multiple:!1}}function scalarKind(type){switch(type){case"boolean":case"number":case"integer":case"string":return type;case"object":return"json";default:return"string"}}function primaryType(property){if(Array.isArray(property.type))return property.type.find(type=>type!=="null");if(property.type)return property.type;let option=property.anyOf?.find(item=>item.type!=="null");return option?primaryType(option):void 0}function choicesOf(property){if(property.enum)return property.enum;if(property.items?.enum)return property.items.enum}function convertValue(raw2,kind,flag){switch(kind){case"number":case"integer":{let value=Number(raw2);return raw2.trim()===""||Number.isNaN(value)||kind==="integer"&&!Number.isInteger(value)?{error:`${flag} takes ${kind==="integer"?"a whole number":"a number"}, not "${raw2}".`}:{value}}case"json":try{return{value:JSON.parse(raw2)}}catch{return{error:`${flag} takes JSON, and "${raw2}" is not valid JSON.`}}case"boolean":return{value:raw2===""||raw2==="true"};default:return{value:raw2}}}var CommandTree=class _CommandTree{root=newNode([]);warnings=[];static build(intents,groups,picks={}){let tree=new _CommandTree,claims=new Map;for(let info of intents){let definition=info.definition;if(definition.internal)continue;let cli=definition.cli??{},path103=cli.command??definition.intent.split("."),command={intent:definition.intent,plugin:info.plugin,info,path:path103,aliases:cli.aliases??[],hidden:cli.hidden??!1,...argumentsFromSchema(toJsonSchema(definition.input),cli)};for(let[words,viaAlias]of[[path103,!1],...command.aliases.map(alias=>[alias,!0])]){let key=words.join(" "),list2=claims.get(key)??[];list2.push({command,viaAlias}),claims.set(key,list2)}}for(let[key,list2]of claims){let winner=tree.pick(key,list2,picks),node=tree.ensure(key.split(" "));node.command=winner.command,node.viaAlias=winner.viaAlias}for(let group of groups)tree.ensure(group.command).group=group;return markCanonical(tree.root),tree.shareAliasedGroups(groups),tree}find(words){let node=this.root,used=0;for(let word of words){let next=node.children.get(word);if(!next)break;node=next,used+=1}return{node,used}}commands(){let found=new Set,visit2=node=>{node.command&&!node.viaAlias&&found.add(node.command),node.children.forEach(visit2)};return visit2(this.root),[...found]}shareAliasedGroups(groups){for(let group of groups){let canonical=this.find(group.command);if(canonical.used===group.command.length)for(let alias of group.aliases??[]){let node=this.ensure(alias);node.group??=group,node.canonical=!1;for(let[word,child2]of canonical.node.children)child2.canonical&&node.children.set(word,child2);node.command??=canonical.node.command,node.viaAlias||=canonical.node.command!==void 0}}}pick(key,list2,picks){let distinct2=list2.filter((claim,index)=>list2.findIndex(other=>other.command===claim.command)===index);if(distinct2.length===1)return distinct2[0];let plugins=distinct2.map(claim=>claim.command.plugin),described=distinct2.map(claim=>`intent "${claim.command.intent}" (${claim.command.plugin})`).join(" and "),picked=picks[key],chosen=distinct2.find(claim=>claim.command.plugin===picked);if(!chosen)throw new ConflictError3(`cli:${key}`,plugins,`Two commands claim "${key}": ${described}.`,{details:[`Choose one in the config: cli.pick."${key}": "${plugins[0]}"`]});let others=distinct2.filter(claim=>claim!==chosen).map(claim=>claim.command.plugin).join(" and ");return this.warnings.push(`cli.pick picks ${chosen.command.plugin} for "${key}". ${others}'s command is ignored there, and may not work as expected.`),chosen}ensure(words){let node=this.root;for(let word of words){let next=node.children.get(word);next||(next=newNode([...node.path,word]),node.children.set(word,next)),node=next}return node}};function newNode(path103){return{path:path103,children:new Map,command:void 0,viaAlias:!1,group:void 0,canonical:!1}}function markCanonical(node){let canonical=node.command!==void 0&&!node.viaAlias;for(let child2 of node.children.values())canonical=markCanonical(child2)||canonical;return node.canonical=canonical||node.group!==void 0,node.canonical}import{isSousError as isSousError2,isSousErrorOfKind,SousError as SousError7}from"@sous-io/plugin-api";function describeError(error51,options={}){if(isSousError2(error51)){let details2=isSousErrorOfKind(error51,"input")&&options.command?inputDetails(error51,options.command):[...error51.details];return options.debug&&error51.stack&&details2.push(...stackLines(error51.stack)),{summary:error51.message,details:details2,exitCode:error51.exitCode}}let details=options.debug&&error51 instanceof Error&&error51.stack?stackLines(error51.stack):[];return{summary:error51 instanceof Error?error51.message:String(error51),details,exitCode:1}}function errorForDisplay(error51,command){if(!(error51 instanceof Error))return new Error(String(error51));if(command&&isSousErrorOfKind(error51,"input")){let input=error51,copy=new SousError7(input.message,{details:inputDetails(input,command),exitCode:input.exitCode,...input.cause===void 0?{}:{cause:input.cause}});return copy.stack=input.stack,copy}return error51}function viewError(error51,options={}){let parts=describeError(error51,options);return{lines:[`Error: ${parts.summary}`,...parts.details.map(line=>` ${line}`)],exitCode:parts.exitCode}}function inputDetails(error51,command){return error51.issues.map(issue2=>{let field=issue2.path.split(/[.[]/)[0]??"",positional=command.positionals.find(spec=>spec.field===field),flag=command.flags.find(spec=>spec.field===field),rest=issue2.path.slice(field.length),where2=positional?`<${positional.name}>${rest}`:flag?`--${flag.name}${rest}`:issue2.path;return where2?`${where2}: ${issue2.message}`:issue2.message})}function stackLines(stack){return stack.split(`
763
+ `);let changed=after!==text,dryRun4=input.dryRun===!0;changed&&!dryRun4&&writeFileAtomically(file2,after,420);let result={file:file2,path:input.path,previous,value,changed,dryRun:dryRun4};return IntentOutputs2.of(result,{summary:describeSet(result)})}var package_default={name:"@sous-io/plugin-config-files",version:"1.0.12",description:"sous.config.* as a contributor, config.set, and the .env files.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/documents":"workspace:*","@sous-io/plugin-api":"workspace:*","@sous-io/plugin-expressions":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-variables":"workspace:*",tsx:"^4.21.0"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};import fs6 from"node:fs";import path8 from"node:path";function loadEnvFile(filePath,env){if(!fs6.existsSync(filePath))return{filePath,loaded:!1,applied:[],skipped:[]};let applied=[],skipped=[];for(let[key,value]of Object.entries(parseEnv(fs6.readFileSync(filePath,"utf8")))){if(env[key]!==void 0){skipped.push(key);continue}env[key]=value,applied.push(key)}return{filePath,loaded:!0,applied,skipped}}function loadEnvDefaults(sousDir,env){return loadEnvFile(path8.join(sousDir,ENV_SHARED_NAME),env)}function loadEnvLocal(sousDir,env){return loadEnvFile(path8.join(sousDir,ENV_LOCAL_NAME),env)}function loadEnvFiles(sousDir,env){let local2=loadEnvLocal(sousDir,env),defaults2=loadEnvDefaults(sousDir,env);return{local:local2,defaults:defaults2}}function projectEnvironment(project,env){let result={...env};return project!==void 0&&loadEnvFiles(project.sousDir,result),Object.freeze(result)}var PLUGIN_NAME="@sous-io/plugin-config-files",MAIN_CONTRIBUTOR="config-files.main",PATCH_CONTRIBUTOR_PREFIX="config-files/",MAIN_APPLY_ORDER=89900,configFilesPlugin=definePlugin({name:PLUGIN_NAME,version:package_default.version,description:"sous.config.* as a contributor, config.set, and the .env files.",dependsOn:{"@sous-io/plugin-expressions":`^${package_default.version}`,"@sous-io/plugin-variables":`^${package_default.version}`,"@sous-io/plugin-host":`^${package_default.version}`},register(sous){let loader=createLoader(sous);if(sous.services.add("config-files.loader",()=>loader,{lifetime:"singleton"}),sous.services.add("config-files.env",(_config,ctx)=>new EnvFilesService(ctx.project,ctx.env),{lifetime:"singleton"}),sous.config.contribute(mainContributor(loader)),sous.project!==void 0)for(let file2 of loader.findPatches(sous.project.sousDir,MAIN_CONFIG_BASE_NAME))sous.config.contribute(fileContributor(loader,file2,`${PATCH_CONTRIBUTOR_PREFIX}${path9.basename(file2)}`));sous.intents.add({intent:CONFIG_SET,requiresProject:!0,summary:"Set one value in a config file",description:"Writes one value into sous.config.* (or the file --file names), changing only that key: comments, key order and formatting stay. The value is read as JSON when it is valid JSON, else as text. A main config written as code (sous.config.js or .ts) cannot be edited; name a JSON, JSONC or YAML file with --file.",input:jsonSchema2({type:"object",properties:{path:{type:"string",description:'The key path: compilation.includeSourceComments, subscriptions."workflow/x".enabled.'},value:{type:"string",description:"The value: JSON when it is valid JSON, else text."},unset:{type:"boolean",description:"Remove the key instead."},file:{type:"string",description:"The file to write: a conf.d file name, or a path from the project root. Default: sous.config.* when it is JSON, JSONC or YAML; a code config needs this."},dryRun:{type:"boolean",description:"Show what would change, writing nothing."}},required:["path"]}),changesConfig:!0,cli:{command:["config","set"],positional:["path","value"],examples:["sous config set compilation.includeSourceComments false",'sous config set subscriptions."workflow/x".enabled false --file 610-mac.jsonc',"sous config set name --unset"]},agent:{tool:"sous_config_set",usage:"Call this to change one config value without rewriting the file.",whenNotToUse:"Not for subscriptions or repositories: use their own intents, which keep the lockfile in step."},handle:(input,ctx)=>configSet(input,ctx)}),sous.entities.add("config-key",{id:"$schema",description:"The JSON Schema the file declares, for editors. Sous ignores it.",schema:jsonSchema2({type:"string"})}),sous.entities.add("config-key",{id:"version",description:"The config format version. This sous understands version 1.",schema:jsonSchema2({const:1})}),sous.entities.add("config-key",{id:"name",description:"A display name for the project.",schema:jsonSchema2({type:"string"})})}});function createLoader(sous){return new ConfigFilesLoaderImpl({get project(){return sous.project},globs:()=>sous.services.get("host.globs"),evaluator:()=>sous.services.has("expressions.evaluator")?sous.services.get("expressions.evaluator"):void 0,pathVariables:()=>{let variables={};if(sous.project!==void 0&&(variables.sousDir=sous.project.sousDir,variables.sousConfDir=sous.project.confDir),sous.services.has("host.package")){let identity2=sous.services.get("host.package").identity();variables.sousRootPath=identity2.root,variables.sousVersion=identity2.version}return variables}})}function mainContributor(loader){return{id:MAIN_CONTRIBUTOR,applyOrder:MAIN_APPLY_ORDER,async contribute(config2){let project=config2.project;if(project===void 0)return;let candidates=mainCandidates(project.sousDir),file2=project.configPath??candidates[0];if(file2!==void 0){if(config2.contributor.run===1){if(candidates.length>1)throw new ConfigError6(`Duplicate config file baseName '${MAIN_CONFIG_BASE_NAME}':`,{details:[...candidates.map(candidate=>` ${candidate}`),"Two config files in one directory must not share a name once the final extension is removed. Delete or rename one of them."]});loader.forget(file2)}await applyFile(loader,file2,config2)}}}}function fileContributor(loader,file2,id){let format3=loader.formatOf(path9.basename(file2));return{id,applyOrder:MAIN_APPLY_ORDER,...format3==="patch-json"||format3==="patch-jsonl"?{monitors:[""]}:{},async contribute(config2){config2.contributor.run===1&&loader.forget(file2),await applyFile(loader,file2,config2)}}}async function applyFile(loader,file2,config2){isFile2(file2)&&await loader.contribute(await loader.load(file2),config2)}function isFile2(file2){try{return fs7.statSync(file2).isFile()}catch{return!1}}import{definePlugin as definePlugin30}from"@sous-io/plugin-api";import os from"node:os";import{definePlugin as definePlugin2,IntentOutput as IntentOutput4,IntentOutputs as IntentOutputs7,jsonSchema as jsonSchema5,LOG_LEVELS,TextBlock as TextBlock4,VariableSet as VariableSet2}from"@sous-io/plugin-api";import{ConflictError as ConflictError3,toJsonSchema}from"@sous-io/plugin-api";function toKebab(name){return name.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/_/g,"-").toLowerCase()}function suggest(typed,candidates){let limit2=Math.max(2,Math.floor(typed.length/3)),scored=[];for(let word of new Set(candidates)){let distance=editDistance(typed.toLowerCase(),word.toLowerCase());distance<=limit2?scored.push({word,score:distance}):typed.length>=2&&word.startsWith(typed)&&scored.push({word,score:limit2+1})}return scored.sort((a,b)=>a.score-b.score||(a.word<b.word?-1:1)).slice(0,3).map(item=>item.word)}function editDistance(a,b){let previous=Array.from({length:b.length+1},(_2,index)=>index);for(let i=1;i<=a.length;i++){let current=[i];for(let j2=1;j2<=b.length;j2++){let cost=a[i-1]===b[j2-1]?0:1;current[j2]=Math.min(previous[j2]+1,current[j2-1]+1,previous[j2-1]+cost)}previous=current}return previous[b.length]}function argumentsFromSchema(schema,cli={}){let properties=schema?.properties??{},required2=new Set(schema?.required??[]),flags=[];for(let[field,property]of Object.entries(properties)){let options=cli.flags?.[field]??{},{kind,multiple}=kindOf(property),name=toKebab(field),aliases=(options.aliases??[]).filter(alias=>alias.length>1),shorts=extraShorts(kind,[name,...aliases],options).filter(letter=>letter!==options.short);flags.push({field,name,aliases,short:options.short??shorts[0],shorts:options.short?shorts:shorts.slice(1),kind,multiple,description:property.description,defaultValue:property.default,choices:choicesOf(property),required:required2.has(field)&&property.default===void 0,hidden:options.hidden??!1})}let names2=cli.positional??[],positionals=names2.map((field,index)=>{let property=properties[field]??{},{kind,multiple}=kindOf(property);return{field,name:toKebab(field),kind,variadic:multiple&&index===names2.length-1,required:required2.has(field)&&property.default===void 0,description:property.description}});return{flags,positionals}}var CONFIRMATION_SHORTS={yes:"y",force:"f"};function extraShorts(kind,names2,options){let letters=(options.aliases??[]).filter(alias=>alias.length===1);if(kind==="boolean")for(let name of names2){let letter=CONFIRMATION_SHORTS[name];letter&&letters.push(letter)}return[...new Set(letters)]}function kindOf(property){let type=primaryType(property);if(type==="array"){let itemType=property.items?primaryType(property.items):"string";return{kind:scalarKind(itemType),multiple:!0}}return type===void 0&&property.enum?{kind:property.enum.every(item=>typeof item=="number")?"number":"string",multiple:!1}:{kind:scalarKind(type),multiple:!1}}function scalarKind(type){switch(type){case"boolean":case"number":case"integer":case"string":return type;case"object":return"json";default:return"string"}}function primaryType(property){if(Array.isArray(property.type))return property.type.find(type=>type!=="null");if(property.type)return property.type;let option=property.anyOf?.find(item=>item.type!=="null");return option?primaryType(option):void 0}function choicesOf(property){if(property.enum)return property.enum;if(property.items?.enum)return property.items.enum}function convertValue(raw2,kind,flag){switch(kind){case"number":case"integer":{let value=Number(raw2);return raw2.trim()===""||Number.isNaN(value)||kind==="integer"&&!Number.isInteger(value)?{error:`${flag} takes ${kind==="integer"?"a whole number":"a number"}, not "${raw2}".`}:{value}}case"json":try{return{value:JSON.parse(raw2)}}catch{return{error:`${flag} takes JSON, and "${raw2}" is not valid JSON.`}}case"boolean":return{value:raw2===""||raw2==="true"};default:return{value:raw2}}}var CommandTree=class _CommandTree{root=newNode([]);warnings=[];static build(intents,groups,picks={}){let tree=new _CommandTree,claims=new Map;for(let info of intents){let definition=info.definition;if(definition.internal)continue;let cli=definition.cli??{},path103=cli.command??definition.intent.split("."),command={intent:definition.intent,plugin:info.plugin,info,path:path103,aliases:cli.aliases??[],hidden:cli.hidden??!1,...argumentsFromSchema(toJsonSchema(definition.input),cli)};for(let[words,viaAlias]of[[path103,!1],...command.aliases.map(alias=>[alias,!0])]){let key=words.join(" "),list2=claims.get(key)??[];list2.push({command,viaAlias}),claims.set(key,list2)}}for(let[key,list2]of claims){let winner=tree.pick(key,list2,picks),node=tree.ensure(key.split(" "));node.command=winner.command,node.viaAlias=winner.viaAlias}for(let group of groups)tree.ensure(group.command).group=group;return markCanonical(tree.root),tree.shareAliasedGroups(groups),tree}find(words){let node=this.root,used=0;for(let word of words){let next=node.children.get(word);if(!next)break;node=next,used+=1}return{node,used}}commands(){let found=new Set,visit2=node=>{node.command&&!node.viaAlias&&found.add(node.command),node.children.forEach(visit2)};return visit2(this.root),[...found]}shareAliasedGroups(groups){for(let group of groups){let canonical=this.find(group.command);if(canonical.used===group.command.length)for(let alias of group.aliases??[]){let node=this.ensure(alias);node.group??=group,node.canonical=!1;for(let[word,child2]of canonical.node.children)child2.canonical&&node.children.set(word,child2);node.command??=canonical.node.command,node.viaAlias||=canonical.node.command!==void 0}}}pick(key,list2,picks){let distinct2=list2.filter((claim,index)=>list2.findIndex(other=>other.command===claim.command)===index);if(distinct2.length===1)return distinct2[0];let plugins=distinct2.map(claim=>claim.command.plugin),described=distinct2.map(claim=>`intent "${claim.command.intent}" (${claim.command.plugin})`).join(" and "),picked=picks[key],chosen=distinct2.find(claim=>claim.command.plugin===picked);if(!chosen)throw new ConflictError3(`cli:${key}`,plugins,`Two commands claim "${key}": ${described}.`,{details:[`Choose one in the config: cli.pick."${key}": "${plugins[0]}"`]});let others=distinct2.filter(claim=>claim!==chosen).map(claim=>claim.command.plugin).join(" and ");return this.warnings.push(`cli.pick picks ${chosen.command.plugin} for "${key}". ${others}'s command is ignored there, and may not work as expected.`),chosen}ensure(words){let node=this.root;for(let word of words){let next=node.children.get(word);next||(next=newNode([...node.path,word]),node.children.set(word,next)),node=next}return node}};function newNode(path103){return{path:path103,children:new Map,command:void 0,viaAlias:!1,group:void 0,canonical:!1}}function markCanonical(node){let canonical=node.command!==void 0&&!node.viaAlias;for(let child2 of node.children.values())canonical=markCanonical(child2)||canonical;return node.canonical=canonical||node.group!==void 0,node.canonical}import{isSousError as isSousError2,isSousErrorOfKind,SousError as SousError7}from"@sous-io/plugin-api";function describeError(error51,options={}){if(isSousError2(error51)){let details2=isSousErrorOfKind(error51,"input")&&options.command?inputDetails(error51,options.command):[...error51.details];return options.debug&&error51.stack&&details2.push(...stackLines(error51.stack)),{summary:error51.message,details:details2,exitCode:error51.exitCode}}let details=options.debug&&error51 instanceof Error&&error51.stack?stackLines(error51.stack):[];return{summary:error51 instanceof Error?error51.message:String(error51),details,exitCode:1}}function errorForDisplay(error51,command){if(!(error51 instanceof Error))return new Error(String(error51));if(command&&isSousErrorOfKind(error51,"input")){let input=error51,copy=new SousError7(input.message,{details:inputDetails(input,command),exitCode:input.exitCode,...input.cause===void 0?{}:{cause:input.cause}});return copy.stack=input.stack,copy}return error51}function viewError(error51,options={}){let parts=describeError(error51,options);return{lines:[`Error: ${parts.summary}`,...parts.details.map(line=>` ${line}`)],exitCode:parts.exitCode}}function inputDetails(error51,command){return error51.issues.map(issue2=>{let field=issue2.path.split(/[.[]/)[0]??"",positional=command.positionals.find(spec=>spec.field===field),flag=command.flags.find(spec=>spec.field===field),rest=issue2.path.slice(field.length),where2=positional?`<${positional.name}>${rest}`:flag?`--${flag.name}${rest}`:issue2.path;return where2?`${where2}: ${issue2.message}`:issue2.message})}function stackLines(stack){return stack.split(`
763
764
  `).slice(1).map(line=>line.trim())}import{IntentOutput as IntentOutput2,IntentOutputs as IntentOutputs5,isLogLevel,isSousErrorOfKind as isSousErrorOfKind2,LogLevel as LogLevel2,SousError as SousError8,TextBlock as TextBlock3}from"@sous-io/plugin-api";import{IntentOutput,IntentOutputs as IntentOutputs3,jsonSchema as jsonSchema3,TextBlock}from"@sous-io/plugin-api";import{toJsonSchema as toJsonSchema2}from"@sous-io/plugin-api";function globalSpecs(entities){return entities.map(entity=>{let schema=toJsonSchema2(entity.schema)??{},type=Array.isArray(schema.type)?schema.type[0]:schema.type,kind=type==="boolean"||type==="number"||type==="integer"?type:(schema.enum||type==="string","string");return{field:entity.id,name:entity.id,aliases:[],short:entity.short,shorts:[],kind,multiple:type==="array",description:entity.description,defaultValue:schema.default,choices:schema.enum,required:!1,hidden:entity.hidden??!1,valueName:entity.valueName??"value"}})}var COMPLETION_SHELLS=["bash","zsh","fish"],COMPLETE_COMMAND="__complete";function completeWords(tree,words,globalNames){let typed=words.at(-1)??"",node=tree.root;for(let word of words.slice(0,-1)){if(word.startsWith("-"))continue;let next=node.children.get(word);if(!next)break;node=next}let candidates=typed.startsWith("-")?[...(node.command?.flags??[]).filter(flag=>!flag.hidden).flatMap(flag=>[`--${flag.name}`,...flag.aliases.map(alias=>`--${alias}`)]),...globalNames.map(name=>`--${name}`),"--help"]:[...node.children.values()].filter(child2=>child2.canonical&&!child2.group?.hidden&&!child2.command?.hidden).map(child2=>child2.path.at(-1));return[...new Set(candidates)].filter(word=>word.startsWith(typed)).sort()}function completionScript(shell,appName){let fn=`_${appName.replace(/[^A-Za-z0-9_]/g,"_")}_complete`;switch(shell){case"bash":return[`# ${appName} completion for bash. Add to ~/.bashrc: eval "$(${appName} completion bash)"`,`${fn}() {`," local IFS=$'\\n'",` COMPREPLY=($(${appName} ${COMPLETE_COMMAND} "\${COMP_WORDS[@]:1:COMP_CWORD}" 2>/dev/null))`,"}",`complete -o default -F ${fn} ${appName}`,""].join(`
764
765
  `);case"zsh":return[`# ${appName} completion for zsh. Add to ~/.zshrc: eval "$(${appName} completion zsh)"`,`${fn}() {`," local -a words_next",` words_next=("\${(@f)$(${appName} ${COMPLETE_COMMAND} "\${(@)words[2,CURRENT]}" 2>/dev/null)}")`," compadd -a words_next","}",`compdef ${fn} ${appName}`,""].join(`
765
766
  `);case"fish":return[`# ${appName} completion for fish. Add to ~/.config/fish/config.fish: ${appName} completion fish | source`,`function ${fn}`," set -l words (commandline -opc) (commandline -ct)",` ${appName} ${COMPLETE_COMMAND} $words[2..-1] 2>/dev/null`,"end",`complete -c ${appName} -f -a '(${fn})'`,""].join(`
@@ -785,7 +786,7 @@ ${lines3.join(`
785
786
  `)){let leading=/^[ \t]*/.exec(paragraph)?.[0]??"",words=paragraph.slice(leading.length).split(/\s+/).filter(word=>word.length>0);if(words.length===0){lines3.push("");continue}let continuation=leading+" ".repeat(hanging),prefix=leading,current="";for(let word of words){if(current.length===0){current=word;continue}if(displayWidth(prefix)+displayWidth(current)+1+displayWidth(word)<=limit2){current=`${current} ${word}`;continue}lines3.push(`${prefix}${current}`),prefix=continuation,current=word}lines3.push(`${prefix}${current}`)}return lines3}var SGR_SOURCE="\\u001B\\[[0-9;]*m",RESET="\x1B[0m",ELLIPSIS="\u2026",PRIORITY_RANK={low:0,medium:1,high:2};function renderTable(columns,rows,options={}){if(columns.length===0)return[];let gap=options.gap??2,indentWidth=options.indent??0,showHeader=options.header??!0,stream=options.stream??{},style=options.style??createStyle(!1),measured=options.width??(stream.isTTY===!0?terminalColumns(stream):100),mayHide=options.width!==void 0||stream.isTTY===!0,budget=Math.max(1,Math.floor(measured)-indentWidth),{widths,visible,hidden}=fitColumns(columns,rows,{budget,gap,showHeader,mayHide}),lines3=[];if(showHeader){let headers=visible.map((column,index)=>padTo(truncateToWidth(column.header,widths[index],"end"),widths[index],alignOf(column)));lines3.push(style.cyan(joinCells(headers,gap))),lines3.push(style.gray(joinCells(widths.map(width=>"-".repeat(width)),gap)))}if(rows.forEach((row,rowIndex)=>{for(let line of renderRow(row,visible,widths,gap))lines3.push(line);let note=options.rowNote?.(row,rowIndex);note!==void 0&&note!==""&&lines3.push(note)}),hidden.length>0){let names2=hidden.map(column=>column.header).join(", ");lines3.push(`Hidden at this width: ${names2}. Widen the terminal to see ${hidden.length===1?"it":"them"}.`)}return lines3}function fitColumns(columns,rows,input){let visible=[...columns];for(;;){let floors=visible.map(column=>minimumWidth(column,input.showHeader)),targets=visible.map((column,index)=>Math.max(naturalWidth(column,rows,input.showHeader),floors[index])),flexes=visible.map(column=>Math.max(0,column.flex??0)),ranks=visible.map(column=>PRIORITY_RANK[column.priority??"high"]),cellBudget=Math.max(visible.length,input.budget-input.gap*(visible.length-1)),fitted=distribute(targets,floors,flexes,ranks,cellBudget);if(fitted.shortBy===0)return{widths:fitted.widths,visible,hidden:columns.filter(column=>!visible.includes(column))};let victim=hideableColumn(visible);if(!input.mayHide||victim===void 0)return{widths:distribute(targets,targets.map(()=>1),flexes,ranks,cellBudget).widths,visible,hidden:columns.filter(column=>!visible.includes(column))};if(visible=visible.filter(column=>column!==victim),visible.length===0)return{widths:[],visible,hidden:columns}}}function distribute(targets,floors,flexes,ranks,budget){let widths=[...targets],total=sum(widths);if(total<=budget)return grow(widths,flexes,budget-total),{widths,shortBy:0};let deficit=total-budget;for(let band of[PRIORITY_RANK.low,PRIORITY_RANK.medium,PRIORITY_RANK.high]){if(deficit<=0)break;let members=[];ranks.forEach((rank,index)=>{rank===band&&members.push(index)}),deficit-=takeFrom(widths,floors,members,deficit)}return{widths,shortBy:Math.max(0,deficit)}}function takeFrom(widths,floors,members,wanted){let room=members.map(index=>widths[index]-floors[index]),totalRoom=sum(room);if(totalRoom<=0||wanted<=0)return 0;let target=Math.min(wanted,totalRoom),taken=0;for(members.forEach((index,slot)=>{let cut=Math.min(room[slot],Math.floor(target*room[slot]/totalRoom));widths[index]=widths[index]-cut,taken+=cut});taken<target;){let best=-1,bestRoom=0;for(let index of members){let left=widths[index]-floors[index];left>=bestRoom&&left>0&&(best=index,bestRoom=left)}if(best<0)break;widths[best]=widths[best]-1,taken+=1}return taken}function grow(widths,flexes,slack){let totalFlex=sum(flexes);if(slack<=0||totalFlex<=0)return;let given=0;for(let index=0;index<widths.length;index+=1){let share=Math.floor(slack*flexes[index]/totalFlex);widths[index]=widths[index]+share,given+=share}let rest=slack-given;for(let index=0;index<widths.length&&rest>0;index+=1)flexes[index]<=0||(widths[index]=widths[index]+1,rest-=1)}function hideableColumn(columns){let victim,victimRank=Number.POSITIVE_INFINITY;for(let column of columns){let rank=PRIORITY_RANK[column.priority??"high"];rank>=PRIORITY_RANK.high||rank<=victimRank&&(victim=column,victimRank=rank)}return victim}function naturalWidth(column,rows,showHeader){let widest=showHeader?displayWidth(column.header):0;for(let row of rows)widest=Math.max(widest,displayWidth(cellText(row,column)));return Math.max(1,widest)}function minimumWidth(column,showHeader){return column.minWidth!==void 0?Math.max(1,column.minWidth):showHeader?Math.max(1,displayWidth(column.header)):1}function cellText(row,column){let value=row[column.key];return value==null?"":String(value)}function alignOf(column){return column.align!==void 0?column.align:column.kind==="number"?"right":"left"}function truncateSideOf(column){return column.truncate!==void 0?column.truncate:column.kind==="path"||column.kind==="url"?"middle":"end"}function renderRow(row,columns,widths,gap){let cells=columns.map((column,index)=>{let width=widths[index],text=cellText(row,column);return(column.overflow??"wrap")==="wrap"?wrapCell(text,width):[truncateToWidth(text,width,truncateSideOf(column))]}),height=Math.max(1,...cells.map(lines3=>lines3.length)),rendered=[];for(let line=0;line<height;line+=1)rendered.push(joinCells(columns.map((column,index)=>padTo(cells[index][line]??"",widths[index],alignOf(column))),gap));return rendered}function joinCells(cells,gap){return cells.join(" ".repeat(gap)).trimEnd()}function wrapCell(text,width){let lines3=[];for(let line of wrapText(text,width,{hangingIndent:0})){if(displayWidth(line)<=width){lines3.push(line);continue}for(let start2=0;start2<displayWidth(line);start2+=width)lines3.push(sliceVisible(line,start2,start2+width))}return lines3}function truncateToWidth(text,width,side){let visible=displayWidth(text);if(visible<=width)return text;if(width<=1)return ELLIPSIS.slice(0,Math.max(0,width));if(side==="start")return`${ELLIPSIS}${sliceVisible(text,visible-(width-1),visible)}`;if(side==="end")return`${sliceVisible(text,0,width-1)}${ELLIPSIS}`;let head=Math.ceil((width-1)/2),tail=width-1-head;return`${sliceVisible(text,0,head)}${ELLIPSIS}${sliceVisible(text,visible-tail,visible)}`}function padTo(text,width,align){let room=width-displayWidth(text);if(room<=0)return text;if(align==="right")return`${" ".repeat(room)}${text}`;if(align==="center"){let left=Math.floor(room/2);return`${" ".repeat(left)}${text}${" ".repeat(room-left)}`}return`${text}${" ".repeat(room)}`}function sliceVisible(text,start2,end){let pattern=new RegExp(SGR_SOURCE,"g"),out="",visible=0,cursor=0,colored=!1;for(let match2 of text.matchAll(pattern)){let plain3=text.slice(cursor,match2.index),taken=takeVisible(plain3,visible,start2,end);out+=taken.text,visible+=plain3.length,out+=match2[0],colored=!0,cursor=match2.index+match2[0].length}let rest=text.slice(cursor);return out+=takeVisible(rest,visible,start2,end).text,colored?`${out}${RESET}`:out}function takeVisible(plain3,offset2,start2,end){let from=Math.max(0,start2-offset2),to=Math.min(plain3.length,end-offset2);return{text:from>=to?"":plain3.slice(from,to)}}function sum(values){return values.reduce((total,value)=>total+value,0)}var VARIABLE_INDENT=4,ERROR_PREFIX="Error: ",BLANK=" ",Layout=class{constructor(style,columns=100,isTTY=!1){this.style=style;this.columns=columns;this.isTTY=isTTY}get wrapWidth(){return wrapColumnsOf(this.columns)}heading(text,symbol2="\u25B6"){return this.style.heading(withSymbol(headingText(text),symbol2))}subheading(text,symbol2="\u2794"){return this.style.subheading(withSymbol(headingText(text),symbol2))}formatVariable(entry,options={}){let style=this.style,pad2=" ".repeat(Math.max(0,options.indent??VARIABLE_INDENT)),labelWidth=Math.max(options.labelWidth??entry.label.length,entry.label.length),gutter=labelWidth+2,width=options.width??this.wrapWidth,valueWidth=Math.max(20,width-pad2.length-gutter),valueLines=wrapText(valueText(entry.value),valueWidth,{hangingIndent:0}),detailLines=entry.detail===void 0||entry.detail===""?[]:wrapText(entry.detail,valueWidth,{hangingIndent:0}),cells=valueLines.map(line=>style.value(line));if(detailLines.length>0){let last2=valueLines[valueLines.length-1]??"",[first2="",...rest]=detailLines;last2!==""&&displayWidth(last2)+1+displayWidth(first2)<=valueWidth?cells[cells.length-1]=`${style.value(last2)} ${style.muted(first2)}`:cells.push(style.muted(first2));for(let line of rest)cells.push(style.muted(line))}return cells.length===0&&cells.push(""),cells.map((cell,index)=>index===0&&entry.label!==""?`${pad2}${style.label(entry.label.padEnd(labelWidth))}: ${cell}`:`${pad2}${" ".repeat(gutter)}${cell}`)}variableLines(entries,options={}){if(entries.length===0)return[];let labelWidth=options.labelWidth??Math.max(...entries.map(entry=>entry.label.length));return entries.flatMap(entry=>this.formatVariable(entry,{...options,labelWidth}))}paragraphLines(text,options={}){let pad2=Math.max(0,options.indent??2),width=options.width??this.wrapWidth,paint=options.color??(line=>line),wrap3=options.hangingIndent===void 0?{}:{hangingIndent:options.hangingIndent};return wrapText(text,Math.max(20,width-pad2),wrap3).map(line=>line===""?BLANK:" ".repeat(pad2)+paint(line))}noteLines(text,options={}){return this.paragraphLines(text,{...options,color:this.style.note})}dryRunLines(text){return this.noteLines(`[Dry Run] ${text}`,{indent:4})}countLine(count2,entity,verb="Found"){let prefix=verb?`${verb} `:"",shown=this.style.cyan("[")+this.style.whiteBright(count2.toLocaleString())+this.style.cyan("]");return`${prefix}${shown} ${entity}`}warningLines(text){let style=this.style,lines3=[style.banner(" WARNING: ")];for(let line of text.split(`
786
787
  `)){if(line.trim()===""){lines3.push(BLANK);continue}for(let wrapped of wrapText(line.trim(),this.wrapWidth-2))lines3.push(indent(style.warning(highlightUpperCaseWords(wrapped,style.highlight))))}return lines3}errorLines(text,prefix=ERROR_PREFIX){let lines3=text.split(`
787
788
  `),first2=lines3.findIndex(line=>line.trim()!==""),out=[];return lines3.forEach((line,index)=>{if(line.trim()===""){out.push(BLANK);return}let body2=index===first2?withPrefix(line.trimStart(),prefix):line;for(let wrapped of wrapText(body2,this.wrapWidth-2))out.push(this.style.error(wrapped))}),out}tableLines(columns,rows,options={}){let pad2=" ".repeat(options.indent??0);return renderTable(columns,rows,{style:this.style,stream:{columns:this.columns,isTTY:this.isTTY},...options}).flatMap(line=>line.split(`
788
- `).map(part=>`${pad2}${part}`))}};function withPrefix(text,prefix){return text.trimStart().toLowerCase().startsWith(prefix.toLowerCase())?text:`${prefix}${text}`}function valueText(value){if(value==null)return"";if(Array.isArray(value)&&value.every(item=>item===null||["string","number","boolean"].includes(typeof item)))return value.join(", ");if(typeof value=="object")try{return JSON.stringify(value,null,2)??String(value)}catch{return String(value)}return String(value)}function headingText(text){return text.endsWith(".")?text:`${text}:`}function withSymbol(text,symbol2){return symbol2?`${symbol2} ${text}`:text}function highlightUpperCaseWords(text,paint){return text.replace(/\b[A-Z][A-Z_'"()[\]{}<>|&*!@#%^\\-]+\b/g,match2=>paint(match2))}import{DataValue,errorChain,IntentOutputs as IntentOutputs4,isSousError as isSousError3,ItemList,Payload as Payload2,ReportEntryStyle,Table,TextBlock as TextBlock2,Tree,VariableSet}from"@sous-io/plugin-api";var LOGO=[" \u2584\u2588\u2588\u2588\u2588\u2588 \u2584\u2588\u2588\u2588\u2588\u2584 \u2588\u2588 \u2588\u2588 \u2584\u2588\u2588\u2588\u2588\u2588 "," \u2580\u2580\u2580\u2584\u2584\u2584 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2580\u2580\u2580\u2584\u2584\u2584 "," \u2588\u2588\u2588\u2588\u2588\u2580 \u2580\u2588\u2588\u2588\u2588\u2580 \u2580\u2588\u2588\u2588\u2588\u2580 \u2588\u2588\u2588\u2588\u2588\u2580 "];function renderBanner(style){return[" "," ",style.cyan(LOGO.join(`
789
+ `).map(part=>`${pad2}${part}`))}};function withPrefix(text,prefix){return text.trimStart().toLowerCase().startsWith(prefix.toLowerCase())?text:`${prefix}${text}`}function valueText(value){if(value==null)return"";if(Array.isArray(value)&&value.every(item=>item===null||["string","number","boolean"].includes(typeof item)))return value.join(", ");if(typeof value=="object")try{return JSON.stringify(value,null,2)??String(value)}catch{return String(value)}return String(value)}function headingText(text){return text.endsWith(".")||text.endsWith(":")?text:`${text}:`}function withSymbol(text,symbol2){return symbol2?`${symbol2} ${text}`:text}function highlightUpperCaseWords(text,paint){return text.replace(/\b[A-Z][A-Z_'"()[\]{}<>|&*!@#%^\\-]+\b/g,match2=>paint(match2))}import{DataValue,errorChain,IntentOutputs as IntentOutputs4,isSousError as isSousError3,ItemList,Payload as Payload2,ReportEntryStyle,Table,TextBlock as TextBlock2,Tree,VariableSet}from"@sous-io/plugin-api";var LOGO=[" \u2584\u2588\u2588\u2588\u2588\u2588 \u2584\u2588\u2588\u2588\u2588\u2584 \u2588\u2588 \u2588\u2588 \u2584\u2588\u2588\u2588\u2588\u2588 "," \u2580\u2580\u2580\u2584\u2584\u2584 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2580\u2580\u2580\u2584\u2584\u2584 "," \u2588\u2588\u2588\u2588\u2588\u2580 \u2580\u2588\u2588\u2588\u2588\u2580 \u2580\u2588\u2588\u2588\u2588\u2580 \u2588\u2588\u2588\u2588\u2588\u2580 "];function renderBanner(style){return[" "," ",style.cyan(LOGO.join(`
789
790
  `))," Agent Configuration Manager "," ",""].join(`
790
791
  `)}function colorizeJson(json3,style){let tokens=/"(?:\\.|[^"\\])*"|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|\b(?:true|false|null)\b/g;return json3.replace(tokens,(match2,offset2,whole)=>match2[0]==='"'?/^\s*:/.test(whole.slice(offset2+match2.length))?style.cyan(match2):style.green(match2):match2==="true"||match2==="false"||match2==="null"?style.magenta(match2):style.yellow(match2))}function formatResolvedReference(facts,reason,style,columns=100){let layout=new Layout(style,columns),optional2=[["Variable",facts.variable],["Recipe",facts.recipe],["Namespace",facts.namespace],["Repository",facts.repository],["Location",facts.location],["Description",facts.description]],entries=[{label:"Resolved to",value:facts.resolvedTo},...optional2.filter(entry=>entry[1]!==void 0).map(([label,value])=>({label,value}))];return[...layout.variableLines(entries),BLANK,...layout.paragraphLines(reason,{indent:2,width:layout.wrapWidth-2,hangingIndent:0})]}var LEVEL_PREFIX={debug:"Debug: ",warning:"Warning: ",error:ERROR_PREFIX,critical:"Critical: ",alert:"Alert: ",emergency:"Emergency: "},BODY_INDENT=2,ACTIONS={written:{glyph:"\u2713",word:"",keepNote:!1},unchanged:{glyph:"\u2298",word:"unchanged",keepNote:!1},"would-write":{glyph:"\u25CB",word:"would write",keepNote:!1},skipped:{glyph:"\u2298",word:"skipped",keepNote:!0},failed:{glyph:"\u2717",word:"failed",keepNote:!0},removed:{glyph:"\u2212",word:"removed",keepNote:!1},"would-remove":{glyph:"\u2212",word:"would remove",keepNote:!1}};function renderEntry(layout,state,level,message2,details,style){if(IntentOutputs4.is(message2))return renderResult(layout,state,message2);if(message2 instanceof Error)return renderError(layout,level,message2);let rendered=Payload2.is(message2)?renderPayload(layout,level,message2,style):renderStyled(layout,state,level,String(message2),details,style);return LEVEL_MARKED.has(style)||level==="debug"?rendered:markLevel(layout,level,rendered)}var LEVEL_MARKED=new Set([ReportEntryStyle.Plain,ReportEntryStyle.Problem,ReportEntryStyle.Text,ReportEntryStyle.Data,ReportEntryStyle.Banner,ReportEntryStyle.Progress,ReportEntryStyle.Question,ReportEntryStyle.Operation]);function markLevel(layout,level,rendered){let prefix=LEVEL_PREFIX[level],at2=rendered.lines.findIndex(line2=>line2.trim()!=="");if(prefix===void 0||at2<0)return rendered;let line=rendered.lines[at2],indent2=line.length-line.trimStart().length,lines3=[...rendered.lines];return lines3[at2]=`${line.slice(0,indent2)}${levelPaint(layout,level)(prefix)}${line.slice(indent2)}`,{...rendered,lines:lines3,gapBefore:Math.max(rendered.gapBefore??0,1)}}function renderStyled(layout,state,level,message2,details,style){let colors=layout.style,body2=BODY_INDENT+(state.step?BODY_INDENT:0),pad2=count2=>" ".repeat(count2);switch(style){case ReportEntryStyle.Text:return verbatim(message2);case ReportEntryStyle.Banner:return{lines:renderBanner(colors).replace(/\n$/,"").split(`
791
792
  `)};case ReportEntryStyle.Note:return{lines:layout.noteLines(message2),footer:!0};case ReportEntryStyle.OperationStart:return state.step=!1,{lines:[layout.heading(message2)],gapBefore:1,gapAfter:1,footer:!0};case ReportEntryStyle.StepStart:return state.step=!0,{lines:[`${pad2(BODY_INDENT)}${colors.subheading(`\u25B7 ${message2}`)}`],gapBefore:1,footer:!0};case ReportEntryStyle.Detail:return{lines:layout.paragraphLines(message2,{indent:body2,color:levelPaint(layout,level)}),footer:!0};case ReportEntryStyle.Operation:return operation(layout,details,message2,body2);case ReportEntryStyle.OperationEnd:{let ok=details?.ok!==!1;return state.step=!1,{lines:layout.paragraphLines(message2,{indent:0,color:ok?colors.greenBright:colors.error}),gapBefore:1,footer:!0}}case ReportEntryStyle.Count:{let count2=details;return count2===void 0?plain2(layout,level,message2):{lines:[layout.countLine(count2.count,count2.entity,count2.verb)],footer:!0}}case ReportEntryStyle.DryRun:return{lines:layout.dryRunLines(message2),footer:!0};case ReportEntryStyle.Problem:{let problem=details;return problem===void 0?plain2(layout,level,message2):problemEntry(layout,level,problem)}case ReportEntryStyle.ResolvedReference:{let facts=details;return facts===void 0||typeof facts.resolvedTo!="string"?plain2(layout,level,message2):{lines:formatResolvedReference(facts,message2,colors,layout.columns),gapAfter:1,footer:!0}}case ReportEntryStyle.Question:{let question=details;return question===void 0?plain2(layout,level,message2):questionEntry(layout,question)}case ReportEntryStyle.Command:{let command=details;if(command===void 0)return plain2(layout,level,message2);let line=[command.command,...command.args].join(" "),where2=command.cwd===void 0?"":` ${colors.muted(`(in ${command.cwd})`)}`;return{lines:[`${pad2(BODY_INDENT)}${colors.label(command.dryRun===!0?"Would run":"Running")}: ${colors.value(line)}${where2}`],footer:!0}}case ReportEntryStyle.Progress:case ReportEntryStyle.Plain:return plain2(layout,level,message2);default:return plain2(layout,level,message2)}}function verbatim(text){return{lines:text===""?[]:text.endsWith(`
@@ -800,7 +801,7 @@ ${lines3.join(`
800
801
  ${help(line.node)}`,LogLevel2.Error);break}case"run":{let prompter=new TerminalPrompter(io.stdin,io.stderr,canPrompt(io,env,line.globals),whyCannotPrompt(io,env,line.globals)),intent=line.command.intent,submitOptions={reporter,prompter,globals:line.globals,...options.cwd===void 0?{}:{cwd:options.cwd}},background=engine.intents.get(intent)?.definition.background===!0,show=async outputs=>{showOutputs(outputs,{reporter,stdout:io.stdout,json:line.globals.json===!0}),reporter.finish(),outputs.exitCode!==void 0&&outputs.exitCode!==0&&io.setExitCode(outputs.exitCode)},fail=error51=>{reportError(reporter,error51,{debug,command:line.command},io),wantsHelp(error51)&&reporter.text(`
801
802
  ${help(line.node)}`,LogLevel2.Error)};io.stderr.isTTY===!0&&!json3&&engine.intents.get(intent)?.definition.runsWithoutConfig!==!0&&reporter.banner();try{let outputs=await engine.submit({intent,input:line.input},submitOptions);background||await show(outputs),startedWatching(outputs)&&await watchUntilStopped(engine,io,reporter,intent,line.input,submitOptions,show,fail)}catch(error51){fail(error51)}break}}line.globals.timings===!0&&reportTimings(reporter,engine.timings.entries())}catch(error51){reportError(reporter,engine.configError??error51,{debug},io)}finally{reporter.finish()}}function commandLineNeedsConfig(engine,argv2){let tree=engine.config.services.get("cli.commands"),specs=globalSpecs(engine.config.entities.list("cli-global-argument")),line=parseLine(versionArgv(argv2,tree),tree,specs,engine.app.name);switch(line.kind){case"help":case"version":return!1;case"run":return engine.intents.get(line.command.intent)?.definition.runsWithoutConfig!==!0;default:return!0}}function reportError(reporter,error51,options,io){let parts=describeError(error51,{...options,debug:!1});reporter.critical(errorForDisplay(error51,options.command)),options.debug&&error51 instanceof Error&&error51.stack&&reporter.text(error51.stack.split(`
802
803
  `).slice(1).join(`
803
- `),LogLevel2.Error),io.setExitCode(parts.exitCode)}var DEBUG_OFF=new Set(["","0","false","no","off"]);function debugRequested(env){let raw2=env.SOUS_DEBUG;return raw2!==void 0&&!DEBUG_OFF.has(raw2.trim().toLowerCase())}function wantsHelp(error51){return isSousErrorOfKind2(error51,"input")||isSousErrorOfKind2(error51,"non-interactive")}function versionArgv(argv2,tree){return argv2[0]===COMPLETE_COMMAND?[COMPLETE_COMMAND,"--",...argv2.slice(1)]:argv2[0]==="--version"&&argv2.length>1&&argv2.slice(1).every(token=>token==="--verbose")&&tree.root.children.get("version")?.command?["version","--verbose"]:argv2}function thresholdOf(globals){if(globals.debug===!0)return LogLevel2.Debug;let level=globals["log-level"];return isLogLevel(level)?level:LogLevel2.Info}async function watchUntilStopped(engine,io,reporter,intent,input,submitOptions,show,fail){if(io.stdin.isTTY!==!0){await engine.whenBackgroundIntentsReturn();return}reporter.note(WATCH_KEYS_HINT);let rebuilding,stop=listenForWatchKeys(io.stdin,{quit:()=>{stop(),io.interrupt?.()},rebuild:()=>{rebuilding||(reporter.notice("Manual rebuild triggered."),rebuilding=engine.submit({intent,input:{...input,watch:!1}},submitOptions).then(show,fail).finally(()=>{rebuilding=void 0}))}});try{await engine.whenBackgroundIntentsReturn(),await rebuilding}finally{stop()}}var BUILT_IN_GROUPS=[{id:"config",command:["config"],summary:"Inspect the merged configuration",aliases:[["configs"]]},{id:"repo",command:["repo"],summary:"Manage the recipe repositories this project trusts",aliases:[["repos"]]},{id:"lock",command:["lock"],summary:"Inspect and repair this project's lockfile",aliases:[["locks"]]},{id:"namespace",command:["namespace"],summary:"Browse the namespaces the trusted repositories publish",aliases:[["namespaces"]]},{id:"recipe",command:["recipe"],summary:"Browse the recipes the trusted repositories publish",aliases:[["recipes"]]},{id:"subscription",command:["subscription"],summary:"Manage which recipes this project subscribes to",aliases:[["subscriptions"]]},{id:"vars",command:["vars"],summary:"Recipe variables and their answers",aliases:[["var"]]}];import{IntentOutput as IntentOutput3,IntentOutputs as IntentOutputs6,jsonSchema as jsonSchema4,SousError as SousError9}from"@sous-io/plugin-api";var helpIntent={intent:"help",summary:"Print the help for sous, or for one command or topic",input:jsonSchema4({type:"object",properties:{command:{type:"array",items:{type:"string"},description:"The command to show help for."}}}),cli:{positional:["command"],examples:["sous help repo add"]},parallel:!0,runsWithoutConfig:!0,handle:(rawInput,ctx)=>{let input=rawInput,tree=ctx.services.get("cli.commands"),words=input.command??[],{node,used}=tree.find(words);if(used<words.length){let prefix=used>0?`${words.slice(0,used).join(" ")} `:"",options=suggest(words[used],[...node.children.keys()]);throw new SousError9(`There is no command "${prefix}${words[used]}".`,{exitCode:2,details:options.length>0?[`Did you mean ${options.map(option=>`"${prefix}${option}"`).join(" or ")}?`]:[]})}let page=new HelpPage(node,{appName:ctx.engine.app.name,globals:globalSpecs(ctx.entities.list("cli-global-argument"))});return new IntentOutputs6(new IntentOutput3({result:page,data:{text:page.toText()}}))}};function processIo(){return{stdout:process.stdout,stderr:process.stderr,stdin:process.stdin,setExitCode(code){process.exitCode=code},interrupt(){process.kill(process.pid,"SIGINT")}}}var package_default2={name:"@sous-io/plugin-cli",version:"1.0.11",description:"The sous command-line front end, generated from intents",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*",zod:"^4.4.3"},engines:{node:">=22"}};var CLI_PLUGIN_NAME="@sous-io/plugin-cli",BUILT_IN_GLOBAL_ARGUMENTS=[{id:"config",short:"c",schema:jsonSchema5({type:"string"}),description:"Path to a sous config file (or a directory containing one). Overrides .sous/ discovery.",valueName:"path"},{id:"sous-config",schema:jsonSchema5({type:"string"}),description:"Alias of --config: path to a sous config file (or a directory containing one).",valueName:"path"},{id:"sous-dir",schema:jsonSchema5({type:"string"}),description:"Path to the .sous directory to use (overrides walk-up discovery).",valueName:"path"},{id:"sous-confd",schema:jsonSchema5({type:"string"}),description:"Path to the conf.d drop-in layer directory (overrides <sousDir>/conf.d).",valueName:"path"},{id:"debug",schema:jsonSchema5({type:"boolean",default:!1}),description:"Show every message, debug ones included (the same as --log-level debug)."},{id:"log-level",schema:jsonSchema5({type:"string",enum:[...LOG_LEVELS]}),description:"Show messages at this level and above.",valueName:"level"},{id:"timings",schema:jsonSchema5({type:"boolean",default:!1}),description:"Print every timing when the command finishes."},{id:"json",schema:jsonSchema5({type:"boolean",default:!1}),description:"Print the result as JSON instead of the formatted output."},{id:"non-interactive",schema:jsonSchema5({type:"boolean",default:!1}),description:"Never ask a question; fail with the flag that answers it instead."}];function createCliPlugin(options={}){let io=options.io??processIo;return definePlugin2({name:CLI_PLUGIN_NAME,version:package_default2.version,description:"The command-line front end, generated from intents.",register(sous){sous.entities.define("cli-global-argument",jsonSchema5({type:"object",properties:{id:{type:"string"},description:{type:"string"},short:{type:"string"},valueName:{type:"string"},hidden:{type:"boolean"}},required:["id","schema","description"]}),{description:"An argument every command accepts."}),sous.entities.define("cli-group",jsonSchema5({type:"object",properties:{id:{type:"string"},command:{type:"array",items:{type:"string"}},summary:{type:"string"},description:{type:"string"},hidden:{type:"boolean"}},required:["id","command","summary"]}),{description:"The help of a command group."});for(let argument of BUILT_IN_GLOBAL_ARGUMENTS)sous.entities.add("cli-global-argument",argument);sous.entities.add("config-key",{id:"cli",description:'CLI settings: cli.pick."<command words>": "<plugin>" picks between two commands claiming the same words.',schema:jsonSchema5({type:"object",properties:{pick:{type:"object",additionalProperties:{type:"string"},default:{}}}})});for(let group of BUILT_IN_GROUPS)sous.entities.add("cli-group",group);sous.services.add("cli.commands",(config2,ctx)=>CommandTree.build(sous.engine.intents.list(),ctx.entities.list("cli-group"),config2.get("cli.pick")??{}),{lifetime:"config"}),sous.services.add("cli.interactivity",()=>({canPrompt:globals=>canPrompt(io(),sous.env,globals)}),{lifetime:"singleton"}),sous.services.add("cli.errors",()=>({view:(error51,viewOptions)=>viewError(error51,viewOptions)}),{lifetime:"singleton"}),sous.intents.add(helpIntent),sous.intents.add(completionIntent),sous.intents.add(completeIntent),sous.intents.add({intent:"version",summary:"Print the version",input:jsonSchema5({type:"object",properties:{verbose:{type:"boolean",default:!1,description:"Also print the package, where it is installed, the platform and the Node build."}}}),parallel:!0,runsWithoutConfig:!0,agent:{tool:"sous_version",usage:"Call this to learn which sous version serves this project."},handle:(input,ctx)=>{let{name,version:version2}=ctx.engine.app,text=new TextBlock4(`v${version2}`,{verbatim:!0});if(!input.verbose)return new IntentOutputs7(new IntentOutput4({result:text,data:{name,version:version2}}));let identity2=ctx.services.has("host.package")?ctx.services.get("host.package").identity():void 0,platform=`${os.platform()}-${os.arch()}`,facts={Package:identity2?.name??name,...identity2===void 0?{}:{Install:identity2.root},Platform:platform,Node:process.version};return new IntentOutputs7([new IntentOutput4({result:text}),new IntentOutput4({result:new VariableSet2(facts),data:{name:identity2?.name??name,version:version2,...identity2===void 0?{}:{root:identity2.root},platform,node:process.version}})])}}),sous.frontEnds.add({id:"cli",start:(engine,argv2)=>runCommandLine(engine,argv2,{io:io(),env:sous.env,cwd:process.cwd()}),needsConfig:(engine,argv2)=>commandLineNeedsConfig(engine,argv2)})}})}var cliPlugin=createCliPlugin();import{definePlugin as definePlugin3,jsonSchema as jsonSchema6}from"@sous-io/plugin-api";import{promises as fs9}from"node:fs";import path12 from"node:path";import{fileURLToPath as Wi}from"node:url";import{posix as mi,win32 as re}from"node:path";import{fileURLToPath as gi}from"node:url";import{lstatSync as wi,readdir as yi,readdirSync as bi,readlinkSync as Si,realpathSync as Ei}from"fs";import*as xi from"node:fs";import{lstat as Ci,readdir as Ti,readlink as Ai,realpath as ki}from"node:fs/promises";import{EventEmitter as ee}from"node:events";import Pe from"node:stream";import{StringDecoder as ni}from"node:string_decoder";var Gt=(n7,t,e)=>{let s=n7 instanceof RegExp?ce(n7,e):n7,i=t instanceof RegExp?ce(t,e):t,r=s!==null&&i!=null&&ss(s,i,e);return r&&{start:r[0],end:r[1],pre:e.slice(0,r[0]),body:e.slice(r[0]+s.length,r[1]),post:e.slice(r[1]+i.length)}},ce=(n7,t)=>{let e=t.match(n7);return e?e[0]:null},ss=(n7,t,e)=>{let s,i,r,o,h,a=e.indexOf(n7),l=e.indexOf(t,a+1),u=a;if(a>=0&&l>0){if(n7===t)return[a,l];for(s=[],r=e.length;u>=0&&!h;){if(u===a)s.push(u),a=e.indexOf(n7,u+1);else if(s.length===1){let c=s.pop();c!==void 0&&(h=[c,l])}else i=s.pop(),i!==void 0&&i<r&&(r=i,o=l),l=e.indexOf(t,u+1);u=a<l&&a>=0?a:l}s.length&&o!==void 0&&(h=[r,o])}return h},fe="\0SLASH"+Math.random()+"\0",ue="\0OPEN"+Math.random()+"\0",qt="\0CLOSE"+Math.random()+"\0",de="\0COMMA"+Math.random()+"\0",pe="\0PERIOD"+Math.random()+"\0",is=new RegExp(fe,"g"),rs=new RegExp(ue,"g"),ns=new RegExp(qt,"g"),os2=new RegExp(de,"g"),hs=new RegExp(pe,"g"),as=/\\\\/g,ls=/\\{/g,cs=/\\}/g,fs8=/\\,/g,us=/\\./g,ds=1e5;function Ht(n7){return isNaN(n7)?n7.charCodeAt(0):parseInt(n7,10)}function ps(n7){return n7.replace(as,fe).replace(ls,ue).replace(cs,qt).replace(fs8,de).replace(us,pe)}function ms2(n7){return n7.replace(is,"\\").replace(rs,"{").replace(ns,"}").replace(os2,",").replace(hs,".")}function me(n7){if(!n7)return[""];let t=[],e=Gt("{","}",n7);if(!e)return n7.split(",");let{pre:s,body:i,post:r}=e,o=s.split(",");o[o.length-1]+="{"+i+"}";let h=me(r);return r.length&&(o[o.length-1]+=h.shift(),o.push.apply(o,h)),t.push.apply(t,o),t}function ge(n7,t={}){if(!n7)return[];let{max:e=ds}=t;return n7.slice(0,2)==="{}"&&(n7="\\{\\}"+n7.slice(2)),ht(ps(n7),e,!0).map(ms2)}function gs(n7){return"{"+n7+"}"}function ws(n7){return/^-?0\d/.test(n7)}function ys(n7,t){return n7<=t}function bs(n7,t){return n7>=t}function ht(n7,t,e){let s=[],i=Gt("{","}",n7);if(!i)return[n7];let r=i.pre,o=i.post.length?ht(i.post,t,!1):[""];if(/\$$/.test(i.pre))for(let h=0;h<o.length&&h<t;h++){let a=r+"{"+i.body+"}"+o[h];s.push(a)}else{let h=/^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(i.body),a=/^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(i.body),l=h||a,u=i.body.indexOf(",")>=0;if(!l&&!u)return i.post.match(/,(?!,).*\}/)?(n7=i.pre+"{"+i.body+qt+i.post,ht(n7,t,!0)):[n7];let c;if(l)c=i.body.split(/\.\./);else if(c=me(i.body),c.length===1&&c[0]!==void 0&&(c=ht(c[0],t,!1).map(gs),c.length===1))return o.map(f=>i.pre+c[0]+f);let d;if(l&&c[0]!==void 0&&c[1]!==void 0){let f=Ht(c[0]),m=Ht(c[1]),p=Math.max(c[0].length,c[1].length),w=c.length===3&&c[2]!==void 0?Math.abs(Ht(c[2])):1,g=ys;m<f&&(w*=-1,g=bs);let E=c.some(ws);d=[];for(let y=f;g(y,m);y+=w){let b;if(a)b=String.fromCharCode(y),b==="\\"&&(b="");else if(b=String(y),E){let z2=p-b.length;if(z2>0){let $=new Array(z2+1).join("0");y<0?b="-"+$+b.slice(1):b=$+b}}d.push(b)}}else{d=[];for(let f=0;f<c.length;f++)d.push.apply(d,ht(c[f],t,!1))}for(let f=0;f<d.length;f++)for(let m=0;m<o.length&&s.length<t;m++){let p=r+d[f]+o[m];(!e||l||p)&&s.push(p)}}return s}var at=n7=>{if(typeof n7!="string")throw new TypeError("invalid pattern");if(n7.length>65536)throw new TypeError("pattern is too long")},Ss={"[:alnum:]":["\\p{L}\\p{Nl}\\p{Nd}",!0],"[:alpha:]":["\\p{L}\\p{Nl}",!0],"[:ascii:]":["\\x00-\\x7f",!1],"[:blank:]":["\\p{Zs}\\t",!0],"[:cntrl:]":["\\p{Cc}",!0],"[:digit:]":["\\p{Nd}",!0],"[:graph:]":["\\p{Z}\\p{C}",!0,!0],"[:lower:]":["\\p{Ll}",!0],"[:print:]":["\\p{C}",!0],"[:punct:]":["\\p{P}",!0],"[:space:]":["\\p{Z}\\t\\r\\n\\v\\f",!0],"[:upper:]":["\\p{Lu}",!0],"[:word:]":["\\p{L}\\p{Nl}\\p{Nd}\\p{Pc}",!0],"[:xdigit:]":["A-Fa-f0-9",!1]},lt=n7=>n7.replace(/[[\]\\-]/g,"\\$&"),Es=n7=>n7.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),we=n7=>n7.join(""),ye=(n7,t)=>{let e=t;if(n7.charAt(e)!=="[")throw new Error("not in a brace expression");let s=[],i=[],r=e+1,o=!1,h=!1,a=!1,l=!1,u=e,c="";t:for(;r<n7.length;){let p=n7.charAt(r);if((p==="!"||p==="^")&&r===e+1){l=!0,r++;continue}if(p==="]"&&o&&!a){u=r+1;break}if(o=!0,p==="\\"&&!a){a=!0,r++;continue}if(p==="["&&!a){for(let[w,[g,S,E]]of Object.entries(Ss))if(n7.startsWith(w,r)){if(c)return["$.",!1,n7.length-e,!0];r+=w.length,E?i.push(g):s.push(g),h=h||S;continue t}}if(a=!1,c){p>c?s.push(lt(c)+"-"+lt(p)):p===c&&s.push(lt(p)),c="",r++;continue}if(n7.startsWith("-]",r+1)){s.push(lt(p+"-")),r+=2;continue}if(n7.startsWith("-",r+1)){c=p,r+=2;continue}s.push(lt(p)),r++}if(u<r)return["",!1,0,!1];if(!s.length&&!i.length)return["$.",!1,n7.length-e,!0];if(i.length===0&&s.length===1&&/^\\?.$/.test(s[0])&&!l){let p=s[0].length===2?s[0].slice(-1):s[0];return[Es(p),!1,u-e,!1]}let d="["+(l?"^":"")+we(s)+"]",f="["+(l?"":"^")+we(i)+"]";return[s.length&&i.length?"("+d+"|"+f+")":s.length?d:f,h,u-e,!0]},W=(n7,{windowsPathsNoEscape:t=!1,magicalBraces:e=!0}={})=>e?t?n7.replace(/\[([^\/\\])\]/g,"$1"):n7.replace(/((?!\\).|^)\[([^\/\\])\]/g,"$1$2").replace(/\\([^\/])/g,"$1"):t?n7.replace(/\[([^\/\\{}])\]/g,"$1"):n7.replace(/((?!\\).|^)\[([^\/\\{}])\]/g,"$1$2").replace(/\\([^\/{}])/g,"$1"),xs=new Set(["!","?","+","*","@"]),be=n7=>xs.has(n7),vs="(?!(?:^|/)\\.\\.?(?:$|/))",Ct="(?!\\.)",Cs=new Set(["[","."]),Ts=new Set(["..","."]),As=new Set("().*{}+?[]^$\\!"),ks=n7=>n7.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),Kt="[^/]",Se=Kt+"*?",Ee=Kt+"+?",Q=class n{type;#t;#s;#n=!1;#r=[];#o;#S;#w;#c=!1;#h;#u;#f=!1;constructor(t,e,s={}){this.type=t,t&&(this.#s=!0),this.#o=e,this.#t=this.#o?this.#o.#t:this,this.#h=this.#t===this?s:this.#t.#h,this.#w=this.#t===this?[]:this.#t.#w,t==="!"&&!this.#t.#c&&this.#w.push(this),this.#S=this.#o?this.#o.#r.length:0}get hasMagic(){if(this.#s!==void 0)return this.#s;for(let t of this.#r)if(typeof t!="string"&&(t.type||t.hasMagic))return this.#s=!0;return this.#s}toString(){return this.#u!==void 0?this.#u:this.type?this.#u=this.type+"("+this.#r.map(t=>String(t)).join("|")+")":this.#u=this.#r.map(t=>String(t)).join("")}#a(){if(this!==this.#t)throw new Error("should only call on root");if(this.#c)return this;this.toString(),this.#c=!0;let t;for(;t=this.#w.pop();){if(t.type!=="!")continue;let e=t,s=e.#o;for(;s;){for(let i=e.#S+1;!s.type&&i<s.#r.length;i++)for(let r of t.#r){if(typeof r=="string")throw new Error("string part in extglob AST??");r.copyIn(s.#r[i])}e=s,s=e.#o}}return this}push(...t){for(let e of t)if(e!==""){if(typeof e!="string"&&!(e instanceof n&&e.#o===this))throw new Error("invalid part: "+e);this.#r.push(e)}}toJSON(){let t=this.type===null?this.#r.slice().map(e=>typeof e=="string"?e:e.toJSON()):[this.type,...this.#r.map(e=>e.toJSON())];return this.isStart()&&!this.type&&t.unshift([]),this.isEnd()&&(this===this.#t||this.#t.#c&&this.#o?.type==="!")&&t.push({}),t}isStart(){if(this.#t===this)return!0;if(!this.#o?.isStart())return!1;if(this.#S===0)return!0;let t=this.#o;for(let e=0;e<this.#S;e++){let s=t.#r[e];if(!(s instanceof n&&s.type==="!"))return!1}return!0}isEnd(){if(this.#t===this||this.#o?.type==="!")return!0;if(!this.#o?.isEnd())return!1;if(!this.type)return this.#o?.isEnd();let t=this.#o?this.#o.#r.length:0;return this.#S===t-1}copyIn(t){typeof t=="string"?this.push(t):this.push(t.clone(this))}clone(t){let e=new n(this.type,t);for(let s of this.#r)e.copyIn(s);return e}static#i(t,e,s,i){let r=!1,o=!1,h=-1,a=!1;if(e.type===null){let f=s,m="";for(;f<t.length;){let p=t.charAt(f++);if(r||p==="\\"){r=!r,m+=p;continue}if(o){f===h+1?(p==="^"||p==="!")&&(a=!0):p==="]"&&!(f===h+2&&a)&&(o=!1),m+=p;continue}else if(p==="["){o=!0,h=f,a=!1,m+=p;continue}if(!i.noext&&be(p)&&t.charAt(f)==="("){e.push(m),m="";let w=new n(p,e);f=n.#i(t,w,f,i),e.push(w);continue}m+=p}return e.push(m),f}let l=s+1,u=new n(null,e),c=[],d="";for(;l<t.length;){let f=t.charAt(l++);if(r||f==="\\"){r=!r,d+=f;continue}if(o){l===h+1?(f==="^"||f==="!")&&(a=!0):f==="]"&&!(l===h+2&&a)&&(o=!1),d+=f;continue}else if(f==="["){o=!0,h=l,a=!1,d+=f;continue}if(be(f)&&t.charAt(l)==="("){u.push(d),d="";let m=new n(f,u);u.push(m),l=n.#i(t,m,l,i);continue}if(f==="|"){u.push(d),d="",c.push(u),u=new n(null,e);continue}if(f===")")return d===""&&e.#r.length===0&&(e.#f=!0),u.push(d),d="",e.push(...c,u),l;d+=f}return e.type=null,e.#s=void 0,e.#r=[t.substring(s-1)],l}static fromGlob(t,e={}){let s=new n(null,void 0,e);return n.#i(t,s,0,e),s}toMMPattern(){if(this!==this.#t)return this.#t.toMMPattern();let t=this.toString(),[e,s,i,r]=this.toRegExpSource();if(!(i||this.#s||this.#h.nocase&&!this.#h.nocaseMagicOnly&&t.toUpperCase()!==t.toLowerCase()))return s;let h=(this.#h.nocase?"i":"")+(r?"u":"");return Object.assign(new RegExp(`^${e}$`,h),{_src:e,_glob:t})}get options(){return this.#h}toRegExpSource(t){let e=t??!!this.#h.dot;if(this.#t===this&&this.#a(),!this.type){let a=this.isStart()&&this.isEnd()&&!this.#r.some(f=>typeof f!="string"),l=this.#r.map(f=>{let[m,p,w,g]=typeof f=="string"?n.#E(f,this.#s,a):f.toRegExpSource(t);return this.#s=this.#s||w,this.#n=this.#n||g,m}).join(""),u="";if(this.isStart()&&typeof this.#r[0]=="string"&&!(this.#r.length===1&&Ts.has(this.#r[0]))){let m=Cs,p=e&&m.has(l.charAt(0))||l.startsWith("\\.")&&m.has(l.charAt(2))||l.startsWith("\\.\\.")&&m.has(l.charAt(4)),w=!e&&!t&&m.has(l.charAt(0));u=p?vs:w?Ct:""}let c="";return this.isEnd()&&this.#t.#c&&this.#o?.type==="!"&&(c="(?:$|\\/)"),[u+l+c,W(l),this.#s=!!this.#s,this.#n]}let s=this.type==="*"||this.type==="+",i=this.type==="!"?"(?:(?!(?:":"(?:",r=this.#d(e);if(this.isStart()&&this.isEnd()&&!r&&this.type!=="!"){let a=this.toString();return this.#r=[a],this.type=null,this.#s=void 0,[a,W(this.toString()),!1,!1]}let o=!s||t||e||!Ct?"":this.#d(!0);o===r&&(o=""),o&&(r=`(?:${r})(?:${o})*?`);let h="";if(this.type==="!"&&this.#f)h=(this.isStart()&&!e?Ct:"")+Ee;else{let a=this.type==="!"?"))"+(this.isStart()&&!e&&!t?Ct:"")+Se+")":this.type==="@"?")":this.type==="?"?")?":this.type==="+"&&o?")":this.type==="*"&&o?")?":`)${this.type}`;h=i+r+a}return[h,W(r),this.#s=!!this.#s,this.#n]}#d(t){return this.#r.map(e=>{if(typeof e=="string")throw new Error("string type in extglob ast??");let[s,i,r,o]=e.toRegExpSource(t);return this.#n=this.#n||o,s}).filter(e=>!(this.isStart()&&this.isEnd())||!!e).join("|")}static#E(t,e,s=!1){let i=!1,r="",o=!1,h=!1;for(let a=0;a<t.length;a++){let l=t.charAt(a);if(i){i=!1,r+=(As.has(l)?"\\":"")+l;continue}if(l==="*"){if(h)continue;h=!0,r+=s&&/^[*]+$/.test(t)?Ee:Se,e=!0;continue}else h=!1;if(l==="\\"){a===t.length-1?r+="\\\\":i=!0;continue}if(l==="["){let[u,c,d,f]=ye(t,a);if(d){r+=u,o=o||c,a+=d-1,e=e||f;continue}}if(l==="?"){r+=Kt,e=!0;continue}r+=ks(l)}return[r,W(t),!!e,o]}},tt=(n7,{windowsPathsNoEscape:t=!1,magicalBraces:e=!1}={})=>e?t?n7.replace(/[?*()[\]{}]/g,"[$&]"):n7.replace(/[?*()[\]\\{}]/g,"\\$&"):t?n7.replace(/[?*()[\]]/g,"[$&]"):n7.replace(/[?*()[\]\\]/g,"\\$&"),O=(n7,t,e={})=>(at(t),!e.nocomment&&t.charAt(0)==="#"?!1:new D(t,e).match(n7)),Rs=/^\*+([^+@!?\*\[\(]*)$/,Os=n7=>t=>!t.startsWith(".")&&t.endsWith(n7),Fs=n7=>t=>t.endsWith(n7),Ds=n7=>(n7=n7.toLowerCase(),t=>!t.startsWith(".")&&t.toLowerCase().endsWith(n7)),Ms=n7=>(n7=n7.toLowerCase(),t=>t.toLowerCase().endsWith(n7)),Ns=/^\*+\.\*+$/,_s=n7=>!n7.startsWith(".")&&n7.includes("."),Ls=n7=>n7!=="."&&n7!==".."&&n7.includes("."),Ws=/^\.\*+$/,Ps=n7=>n7!=="."&&n7!==".."&&n7.startsWith("."),js=/^\*+$/,Is=n7=>n7.length!==0&&!n7.startsWith("."),zs=n7=>n7.length!==0&&n7!=="."&&n7!=="..",Bs=/^\?+([^+@!?\*\[\(]*)?$/,Us=([n7,t=""])=>{let e=Ce([n7]);return t?(t=t.toLowerCase(),s=>e(s)&&s.toLowerCase().endsWith(t)):e},$s=([n7,t=""])=>{let e=Te([n7]);return t?(t=t.toLowerCase(),s=>e(s)&&s.toLowerCase().endsWith(t)):e},Gs=([n7,t=""])=>{let e=Te([n7]);return t?s=>e(s)&&s.endsWith(t):e},Hs=([n7,t=""])=>{let e=Ce([n7]);return t?s=>e(s)&&s.endsWith(t):e},Ce=([n7])=>{let t=n7.length;return e=>e.length===t&&!e.startsWith(".")},Te=([n7])=>{let t=n7.length;return e=>e.length===t&&e!=="."&&e!==".."},Ae=typeof process=="object"&&process?typeof process.env=="object"&&process.env&&process.env.__MINIMATCH_TESTING_PLATFORM__||process.platform:"posix",xe={win32:{sep:"\\"},posix:{sep:"/"}},qs=Ae==="win32"?xe.win32.sep:xe.posix.sep;O.sep=qs;var A=Symbol("globstar **");O.GLOBSTAR=A;var Ks="[^/]",Vs=Ks+"*?",Ys="(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?",Xs="(?:(?!(?:\\/|^)\\.).)*?",Js=(n7,t={})=>e=>O(e,n7,t);O.filter=Js;var N=(n7,t={})=>Object.assign({},n7,t),Zs=n7=>{if(!n7||typeof n7!="object"||!Object.keys(n7).length)return O;let t=O;return Object.assign((s,i,r={})=>t(s,i,N(n7,r)),{Minimatch:class extends t.Minimatch{constructor(i,r={}){super(i,N(n7,r))}static defaults(i){return t.defaults(N(n7,i)).Minimatch}},AST:class extends t.AST{constructor(i,r,o={}){super(i,r,N(n7,o))}static fromGlob(i,r={}){return t.AST.fromGlob(i,N(n7,r))}},unescape:(s,i={})=>t.unescape(s,N(n7,i)),escape:(s,i={})=>t.escape(s,N(n7,i)),filter:(s,i={})=>t.filter(s,N(n7,i)),defaults:s=>t.defaults(N(n7,s)),makeRe:(s,i={})=>t.makeRe(s,N(n7,i)),braceExpand:(s,i={})=>t.braceExpand(s,N(n7,i)),match:(s,i,r={})=>t.match(s,i,N(n7,r)),sep:t.sep,GLOBSTAR:A})};O.defaults=Zs;var ke=(n7,t={})=>(at(n7),t.nobrace||!/\{(?:(?!\{).)*\}/.test(n7)?[n7]:ge(n7,{max:t.braceExpandMax}));O.braceExpand=ke;var Qs=(n7,t={})=>new D(n7,t).makeRe();O.makeRe=Qs;var ti=(n7,t,e={})=>{let s=new D(t,e);return n7=n7.filter(i=>s.match(i)),s.options.nonull&&!n7.length&&n7.push(t),n7};O.match=ti;var ve=/[?*]|[+@!]\(.*?\)|\[|\]/,ei=n7=>n7.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),D=class{options;set;pattern;windowsPathsNoEscape;nonegate;negate;comment;empty;preserveMultipleSlashes;partial;globSet;globParts;nocase;isWindows;platform;windowsNoMagicRoot;regexp;constructor(t,e={}){at(t),e=e||{},this.options=e,this.pattern=t,this.platform=e.platform||Ae,this.isWindows=this.platform==="win32";let s="allowWindowsEscape";this.windowsPathsNoEscape=!!e.windowsPathsNoEscape||e[s]===!1,this.windowsPathsNoEscape&&(this.pattern=this.pattern.replace(/\\/g,"/")),this.preserveMultipleSlashes=!!e.preserveMultipleSlashes,this.regexp=null,this.negate=!1,this.nonegate=!!e.nonegate,this.comment=!1,this.empty=!1,this.partial=!!e.partial,this.nocase=!!this.options.nocase,this.windowsNoMagicRoot=e.windowsNoMagicRoot!==void 0?e.windowsNoMagicRoot:!!(this.isWindows&&this.nocase),this.globSet=[],this.globParts=[],this.set=[],this.make()}hasMagic(){if(this.options.magicalBraces&&this.set.length>1)return!0;for(let t of this.set)for(let e of t)if(typeof e!="string")return!0;return!1}debug(...t){}make(){let t=this.pattern,e=this.options;if(!e.nocomment&&t.charAt(0)==="#"){this.comment=!0;return}if(!t){this.empty=!0;return}this.parseNegate(),this.globSet=[...new Set(this.braceExpand())],e.debug&&(this.debug=(...r)=>console.error(...r)),this.debug(this.pattern,this.globSet);let s=this.globSet.map(r=>this.slashSplit(r));this.globParts=this.preprocess(s),this.debug(this.pattern,this.globParts);let i=this.globParts.map((r,o,h)=>{if(this.isWindows&&this.windowsNoMagicRoot){let a=r[0]===""&&r[1]===""&&(r[2]==="?"||!ve.test(r[2]))&&!ve.test(r[3]),l=/^[a-z]:/i.test(r[0]);if(a)return[...r.slice(0,4),...r.slice(4).map(u=>this.parse(u))];if(l)return[r[0],...r.slice(1).map(u=>this.parse(u))]}return r.map(a=>this.parse(a))});if(this.debug(this.pattern,i),this.set=i.filter(r=>r.indexOf(!1)===-1),this.isWindows)for(let r=0;r<this.set.length;r++){let o=this.set[r];o[0]===""&&o[1]===""&&this.globParts[r][2]==="?"&&typeof o[3]=="string"&&/^[a-z]:$/i.test(o[3])&&(o[2]="?")}this.debug(this.pattern,this.set)}preprocess(t){if(this.options.noglobstar)for(let s=0;s<t.length;s++)for(let i=0;i<t[s].length;i++)t[s][i]==="**"&&(t[s][i]="*");let{optimizationLevel:e=1}=this.options;return e>=2?(t=this.firstPhasePreProcess(t),t=this.secondPhasePreProcess(t)):e>=1?t=this.levelOneOptimize(t):t=this.adjascentGlobstarOptimize(t),t}adjascentGlobstarOptimize(t){return t.map(e=>{let s=-1;for(;(s=e.indexOf("**",s+1))!==-1;){let i=s;for(;e[i+1]==="**";)i++;i!==s&&e.splice(s,i-s)}return e})}levelOneOptimize(t){return t.map(e=>(e=e.reduce((s,i)=>{let r=s[s.length-1];return i==="**"&&r==="**"?s:i===".."&&r&&r!==".."&&r!=="."&&r!=="**"?(s.pop(),s):(s.push(i),s)},[]),e.length===0?[""]:e))}levelTwoFileOptimize(t){Array.isArray(t)||(t=this.slashSplit(t));let e=!1;do{if(e=!1,!this.preserveMultipleSlashes){for(let i=1;i<t.length-1;i++){let r=t[i];i===1&&r===""&&t[0]===""||(r==="."||r==="")&&(e=!0,t.splice(i,1),i--)}t[0]==="."&&t.length===2&&(t[1]==="."||t[1]==="")&&(e=!0,t.pop())}let s=0;for(;(s=t.indexOf("..",s+1))!==-1;){let i=t[s-1];i&&i!=="."&&i!==".."&&i!=="**"&&(e=!0,t.splice(s-1,2),s-=2)}}while(e);return t.length===0?[""]:t}firstPhasePreProcess(t){let e=!1;do{e=!1;for(let s of t){let i=-1;for(;(i=s.indexOf("**",i+1))!==-1;){let o=i;for(;s[o+1]==="**";)o++;o>i&&s.splice(i+1,o-i);let h=s[i+1],a=s[i+2],l=s[i+3];if(h!==".."||!a||a==="."||a===".."||!l||l==="."||l==="..")continue;e=!0,s.splice(i,1);let u=s.slice(0);u[i]="**",t.push(u),i--}if(!this.preserveMultipleSlashes){for(let o=1;o<s.length-1;o++){let h=s[o];o===1&&h===""&&s[0]===""||(h==="."||h==="")&&(e=!0,s.splice(o,1),o--)}s[0]==="."&&s.length===2&&(s[1]==="."||s[1]==="")&&(e=!0,s.pop())}let r=0;for(;(r=s.indexOf("..",r+1))!==-1;){let o=s[r-1];if(o&&o!=="."&&o!==".."&&o!=="**"){e=!0;let a=r===1&&s[r+1]==="**"?["."]:[];s.splice(r-1,2,...a),s.length===0&&s.push(""),r-=2}}}}while(e);return t}secondPhasePreProcess(t){for(let e=0;e<t.length-1;e++)for(let s=e+1;s<t.length;s++){let i=this.partsMatch(t[e],t[s],!this.preserveMultipleSlashes);if(i){t[e]=[],t[s]=i;break}}return t.filter(e=>e.length)}partsMatch(t,e,s=!1){let i=0,r=0,o=[],h="";for(;i<t.length&&r<e.length;)if(t[i]===e[r])o.push(h==="b"?e[r]:t[i]),i++,r++;else if(s&&t[i]==="**"&&e[r]===t[i+1])o.push(t[i]),i++;else if(s&&e[r]==="**"&&t[i]===e[r+1])o.push(e[r]),r++;else if(t[i]==="*"&&e[r]&&(this.options.dot||!e[r].startsWith("."))&&e[r]!=="**"){if(h==="b")return!1;h="a",o.push(t[i]),i++,r++}else if(e[r]==="*"&&t[i]&&(this.options.dot||!t[i].startsWith("."))&&t[i]!=="**"){if(h==="a")return!1;h="b",o.push(e[r]),i++,r++}else return!1;return t.length===e.length&&o}parseNegate(){if(this.nonegate)return;let t=this.pattern,e=!1,s=0;for(let i=0;i<t.length&&t.charAt(i)==="!";i++)e=!e,s++;s&&(this.pattern=t.slice(s)),this.negate=e}matchOne(t,e,s=!1){let i=this.options;if(this.isWindows){let p=typeof t[0]=="string"&&/^[a-z]:$/i.test(t[0]),w=!p&&t[0]===""&&t[1]===""&&t[2]==="?"&&/^[a-z]:$/i.test(t[3]),g=typeof e[0]=="string"&&/^[a-z]:$/i.test(e[0]),S=!g&&e[0]===""&&e[1]===""&&e[2]==="?"&&typeof e[3]=="string"&&/^[a-z]:$/i.test(e[3]),E=w?3:p?0:void 0,y=S?3:g?0:void 0;if(typeof E=="number"&&typeof y=="number"){let[b,z2]=[t[E],e[y]];b.toLowerCase()===z2.toLowerCase()&&(e[y]=b,y>E?e=e.slice(y):E>y&&(t=t.slice(E)))}}let{optimizationLevel:r=1}=this.options;r>=2&&(t=this.levelTwoFileOptimize(t)),this.debug("matchOne",this,{file:t,pattern:e}),this.debug("matchOne",t.length,e.length);for(var o=0,h=0,a=t.length,l=e.length;o<a&&h<l;o++,h++){this.debug("matchOne loop");var u=e[h],c=t[o];if(this.debug(e,u,c),u===!1)return!1;if(u===A){this.debug("GLOBSTAR",[e,u,c]);var d=o,f=h+1;if(f===l){for(this.debug("** at the end");o<a;o++)if(t[o]==="."||t[o]===".."||!i.dot&&t[o].charAt(0)===".")return!1;return!0}for(;d<a;){var m=t[d];if(this.debug(`
804
+ `),LogLevel2.Error),io.setExitCode(parts.exitCode)}var DEBUG_OFF=new Set(["","0","false","no","off"]);function debugRequested(env){let raw2=env.SOUS_DEBUG;return raw2!==void 0&&!DEBUG_OFF.has(raw2.trim().toLowerCase())}function wantsHelp(error51){return isSousErrorOfKind2(error51,"input")||isSousErrorOfKind2(error51,"non-interactive")}function versionArgv(argv2,tree){return argv2[0]===COMPLETE_COMMAND?[COMPLETE_COMMAND,"--",...argv2.slice(1)]:argv2[0]==="--version"&&argv2.length>1&&argv2.slice(1).every(token=>token==="--verbose")&&tree.root.children.get("version")?.command?["version","--verbose"]:argv2}function thresholdOf(globals){if(globals.debug===!0)return LogLevel2.Debug;let level=globals["log-level"];return isLogLevel(level)?level:LogLevel2.Info}async function watchUntilStopped(engine,io,reporter,intent,input,submitOptions,show,fail){if(io.stdin.isTTY!==!0){await engine.whenBackgroundIntentsReturn();return}reporter.note(WATCH_KEYS_HINT);let rebuilding,stop=listenForWatchKeys(io.stdin,{quit:()=>{stop(),io.interrupt?.()},rebuild:()=>{rebuilding||(reporter.notice("Manual rebuild triggered."),rebuilding=engine.submit({intent,input:{...input,watch:!1}},submitOptions).then(show,fail).finally(()=>{rebuilding=void 0}))}});try{await engine.whenBackgroundIntentsReturn(),await rebuilding}finally{stop()}}var BUILT_IN_GROUPS=[{id:"config",command:["config"],summary:"Inspect the merged configuration",aliases:[["configs"]]},{id:"repo",command:["repo"],summary:"Manage the recipe repositories this project trusts",aliases:[["repos"]]},{id:"lock",command:["lock"],summary:"Inspect and repair this project's lockfile",aliases:[["locks"]]},{id:"namespace",command:["namespace"],summary:"Browse the namespaces the trusted repositories publish",aliases:[["namespaces"]]},{id:"recipe",command:["recipe"],summary:"Browse the recipes the trusted repositories publish",aliases:[["recipes"]]},{id:"subscription",command:["subscription"],summary:"Manage which recipes this project subscribes to",aliases:[["subscriptions"]]},{id:"vars",command:["vars"],summary:"Recipe variables and their answers",aliases:[["var"]]}];import{IntentOutput as IntentOutput3,IntentOutputs as IntentOutputs6,jsonSchema as jsonSchema4,SousError as SousError9}from"@sous-io/plugin-api";var helpIntent={intent:"help",summary:"Print the help for sous, or for one command or topic",input:jsonSchema4({type:"object",properties:{command:{type:"array",items:{type:"string"},description:"The command to show help for."}}}),cli:{positional:["command"],examples:["sous help repo add"]},parallel:!0,runsWithoutConfig:!0,handle:(rawInput,ctx)=>{let input=rawInput,tree=ctx.services.get("cli.commands"),words=input.command??[],{node,used}=tree.find(words);if(used<words.length){let prefix=used>0?`${words.slice(0,used).join(" ")} `:"",options=suggest(words[used],[...node.children.keys()]);throw new SousError9(`There is no command "${prefix}${words[used]}".`,{exitCode:2,details:options.length>0?[`Did you mean ${options.map(option=>`"${prefix}${option}"`).join(" or ")}?`]:[]})}let page=new HelpPage(node,{appName:ctx.engine.app.name,globals:globalSpecs(ctx.entities.list("cli-global-argument"))});return new IntentOutputs6(new IntentOutput3({result:page,data:{text:page.toText()}}))}};function processIo(){return{stdout:process.stdout,stderr:process.stderr,stdin:process.stdin,setExitCode(code){process.exitCode=code},interrupt(){process.kill(process.pid,"SIGINT")}}}var package_default2={name:"@sous-io/plugin-cli",version:"1.0.12",description:"The sous command-line front end, generated from intents",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*",zod:"^4.4.3"},engines:{node:">=22"}};var CLI_PLUGIN_NAME="@sous-io/plugin-cli",BUILT_IN_GLOBAL_ARGUMENTS=[{id:"config",short:"c",schema:jsonSchema5({type:"string"}),description:"Path to a sous config file (or a directory containing one). Overrides .sous/ discovery.",valueName:"path"},{id:"sous-config",schema:jsonSchema5({type:"string"}),description:"Alias of --config: path to a sous config file (or a directory containing one).",valueName:"path"},{id:"sous-dir",schema:jsonSchema5({type:"string"}),description:"Path to the .sous directory to use (overrides walk-up discovery).",valueName:"path"},{id:"sous-confd",schema:jsonSchema5({type:"string"}),description:"Path to the conf.d drop-in layer directory (overrides <sousDir>/conf.d).",valueName:"path"},{id:"debug",schema:jsonSchema5({type:"boolean",default:!1}),description:"Show every message, debug ones included (the same as --log-level debug)."},{id:"log-level",schema:jsonSchema5({type:"string",enum:[...LOG_LEVELS]}),description:"Show messages at this level and above.",valueName:"level"},{id:"timings",schema:jsonSchema5({type:"boolean",default:!1}),description:"Print every timing when the command finishes."},{id:"json",schema:jsonSchema5({type:"boolean",default:!1}),description:"Print the result as JSON instead of the formatted output."},{id:"non-interactive",schema:jsonSchema5({type:"boolean",default:!1}),description:"Never ask a question; fail with the flag that answers it instead."}];function createCliPlugin(options={}){let io=options.io??processIo;return definePlugin2({name:CLI_PLUGIN_NAME,version:package_default2.version,description:"The command-line front end, generated from intents.",register(sous){sous.entities.define("cli-global-argument",jsonSchema5({type:"object",properties:{id:{type:"string"},description:{type:"string"},short:{type:"string"},valueName:{type:"string"},hidden:{type:"boolean"}},required:["id","schema","description"]}),{description:"An argument every command accepts."}),sous.entities.define("cli-group",jsonSchema5({type:"object",properties:{id:{type:"string"},command:{type:"array",items:{type:"string"}},summary:{type:"string"},description:{type:"string"},hidden:{type:"boolean"}},required:["id","command","summary"]}),{description:"The help of a command group."});for(let argument of BUILT_IN_GLOBAL_ARGUMENTS)sous.entities.add("cli-global-argument",argument);sous.entities.add("config-key",{id:"cli",description:'CLI settings: cli.pick."<command words>": "<plugin>" picks between two commands claiming the same words.',schema:jsonSchema5({type:"object",properties:{pick:{type:"object",additionalProperties:{type:"string"},default:{}}}})});for(let group of BUILT_IN_GROUPS)sous.entities.add("cli-group",group);sous.services.add("cli.commands",(config2,ctx)=>CommandTree.build(sous.engine.intents.list(),ctx.entities.list("cli-group"),config2.get("cli.pick")??{}),{lifetime:"config"}),sous.services.add("cli.interactivity",()=>({canPrompt:globals=>canPrompt(io(),sous.env,globals)}),{lifetime:"singleton"}),sous.services.add("cli.errors",()=>({view:(error51,viewOptions)=>viewError(error51,viewOptions)}),{lifetime:"singleton"}),sous.intents.add(helpIntent),sous.intents.add(completionIntent),sous.intents.add(completeIntent),sous.intents.add({intent:"version",summary:"Print the version",input:jsonSchema5({type:"object",properties:{verbose:{type:"boolean",default:!1,description:"Also print the package, where it is installed, the platform and the Node build."}}}),parallel:!0,runsWithoutConfig:!0,agent:{tool:"sous_version",usage:"Call this to learn which sous version serves this project."},handle:(input,ctx)=>{let{name,version:version2}=ctx.engine.app,text=new TextBlock4(`v${version2}`,{verbatim:!0});if(!input.verbose)return new IntentOutputs7(new IntentOutput4({result:text,data:{name,version:version2}}));let identity2=ctx.services.has("host.package")?ctx.services.get("host.package").identity():void 0,platform=`${os.platform()}-${os.arch()}`,facts={Package:identity2?.name??name,...identity2===void 0?{}:{Install:identity2.root},Platform:platform,Node:process.version};return new IntentOutputs7([new IntentOutput4({result:text}),new IntentOutput4({result:new VariableSet2(facts),data:{name:identity2?.name??name,version:version2,...identity2===void 0?{}:{root:identity2.root},platform,node:process.version}})])}}),sous.frontEnds.add({id:"cli",start:(engine,argv2)=>runCommandLine(engine,argv2,{io:io(),env:sous.env,cwd:process.cwd()}),needsConfig:(engine,argv2)=>commandLineNeedsConfig(engine,argv2)})}})}var cliPlugin=createCliPlugin();import{definePlugin as definePlugin3,jsonSchema as jsonSchema6}from"@sous-io/plugin-api";import{promises as fs9}from"node:fs";import path12 from"node:path";import{fileURLToPath as Wi}from"node:url";import{posix as mi,win32 as re}from"node:path";import{fileURLToPath as gi}from"node:url";import{lstatSync as wi,readdir as yi,readdirSync as bi,readlinkSync as Si,realpathSync as Ei}from"fs";import*as xi from"node:fs";import{lstat as Ci,readdir as Ti,readlink as Ai,realpath as ki}from"node:fs/promises";import{EventEmitter as ee}from"node:events";import Pe from"node:stream";import{StringDecoder as ni}from"node:string_decoder";var Gt=(n7,t,e)=>{let s=n7 instanceof RegExp?ce(n7,e):n7,i=t instanceof RegExp?ce(t,e):t,r=s!==null&&i!=null&&ss(s,i,e);return r&&{start:r[0],end:r[1],pre:e.slice(0,r[0]),body:e.slice(r[0]+s.length,r[1]),post:e.slice(r[1]+i.length)}},ce=(n7,t)=>{let e=t.match(n7);return e?e[0]:null},ss=(n7,t,e)=>{let s,i,r,o,h,a=e.indexOf(n7),l=e.indexOf(t,a+1),u=a;if(a>=0&&l>0){if(n7===t)return[a,l];for(s=[],r=e.length;u>=0&&!h;){if(u===a)s.push(u),a=e.indexOf(n7,u+1);else if(s.length===1){let c=s.pop();c!==void 0&&(h=[c,l])}else i=s.pop(),i!==void 0&&i<r&&(r=i,o=l),l=e.indexOf(t,u+1);u=a<l&&a>=0?a:l}s.length&&o!==void 0&&(h=[r,o])}return h},fe="\0SLASH"+Math.random()+"\0",ue="\0OPEN"+Math.random()+"\0",qt="\0CLOSE"+Math.random()+"\0",de="\0COMMA"+Math.random()+"\0",pe="\0PERIOD"+Math.random()+"\0",is=new RegExp(fe,"g"),rs=new RegExp(ue,"g"),ns=new RegExp(qt,"g"),os2=new RegExp(de,"g"),hs=new RegExp(pe,"g"),as=/\\\\/g,ls=/\\{/g,cs=/\\}/g,fs8=/\\,/g,us=/\\./g,ds=1e5;function Ht(n7){return isNaN(n7)?n7.charCodeAt(0):parseInt(n7,10)}function ps(n7){return n7.replace(as,fe).replace(ls,ue).replace(cs,qt).replace(fs8,de).replace(us,pe)}function ms2(n7){return n7.replace(is,"\\").replace(rs,"{").replace(ns,"}").replace(os2,",").replace(hs,".")}function me(n7){if(!n7)return[""];let t=[],e=Gt("{","}",n7);if(!e)return n7.split(",");let{pre:s,body:i,post:r}=e,o=s.split(",");o[o.length-1]+="{"+i+"}";let h=me(r);return r.length&&(o[o.length-1]+=h.shift(),o.push.apply(o,h)),t.push.apply(t,o),t}function ge(n7,t={}){if(!n7)return[];let{max:e=ds}=t;return n7.slice(0,2)==="{}"&&(n7="\\{\\}"+n7.slice(2)),ht(ps(n7),e,!0).map(ms2)}function gs(n7){return"{"+n7+"}"}function ws(n7){return/^-?0\d/.test(n7)}function ys(n7,t){return n7<=t}function bs(n7,t){return n7>=t}function ht(n7,t,e){let s=[],i=Gt("{","}",n7);if(!i)return[n7];let r=i.pre,o=i.post.length?ht(i.post,t,!1):[""];if(/\$$/.test(i.pre))for(let h=0;h<o.length&&h<t;h++){let a=r+"{"+i.body+"}"+o[h];s.push(a)}else{let h=/^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(i.body),a=/^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(i.body),l=h||a,u=i.body.indexOf(",")>=0;if(!l&&!u)return i.post.match(/,(?!,).*\}/)?(n7=i.pre+"{"+i.body+qt+i.post,ht(n7,t,!0)):[n7];let c;if(l)c=i.body.split(/\.\./);else if(c=me(i.body),c.length===1&&c[0]!==void 0&&(c=ht(c[0],t,!1).map(gs),c.length===1))return o.map(f=>i.pre+c[0]+f);let d;if(l&&c[0]!==void 0&&c[1]!==void 0){let f=Ht(c[0]),m=Ht(c[1]),p=Math.max(c[0].length,c[1].length),w=c.length===3&&c[2]!==void 0?Math.abs(Ht(c[2])):1,g=ys;m<f&&(w*=-1,g=bs);let E=c.some(ws);d=[];for(let y=f;g(y,m);y+=w){let b;if(a)b=String.fromCharCode(y),b==="\\"&&(b="");else if(b=String(y),E){let z2=p-b.length;if(z2>0){let $=new Array(z2+1).join("0");y<0?b="-"+$+b.slice(1):b=$+b}}d.push(b)}}else{d=[];for(let f=0;f<c.length;f++)d.push.apply(d,ht(c[f],t,!1))}for(let f=0;f<d.length;f++)for(let m=0;m<o.length&&s.length<t;m++){let p=r+d[f]+o[m];(!e||l||p)&&s.push(p)}}return s}var at=n7=>{if(typeof n7!="string")throw new TypeError("invalid pattern");if(n7.length>65536)throw new TypeError("pattern is too long")},Ss={"[:alnum:]":["\\p{L}\\p{Nl}\\p{Nd}",!0],"[:alpha:]":["\\p{L}\\p{Nl}",!0],"[:ascii:]":["\\x00-\\x7f",!1],"[:blank:]":["\\p{Zs}\\t",!0],"[:cntrl:]":["\\p{Cc}",!0],"[:digit:]":["\\p{Nd}",!0],"[:graph:]":["\\p{Z}\\p{C}",!0,!0],"[:lower:]":["\\p{Ll}",!0],"[:print:]":["\\p{C}",!0],"[:punct:]":["\\p{P}",!0],"[:space:]":["\\p{Z}\\t\\r\\n\\v\\f",!0],"[:upper:]":["\\p{Lu}",!0],"[:word:]":["\\p{L}\\p{Nl}\\p{Nd}\\p{Pc}",!0],"[:xdigit:]":["A-Fa-f0-9",!1]},lt=n7=>n7.replace(/[[\]\\-]/g,"\\$&"),Es=n7=>n7.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),we=n7=>n7.join(""),ye=(n7,t)=>{let e=t;if(n7.charAt(e)!=="[")throw new Error("not in a brace expression");let s=[],i=[],r=e+1,o=!1,h=!1,a=!1,l=!1,u=e,c="";t:for(;r<n7.length;){let p=n7.charAt(r);if((p==="!"||p==="^")&&r===e+1){l=!0,r++;continue}if(p==="]"&&o&&!a){u=r+1;break}if(o=!0,p==="\\"&&!a){a=!0,r++;continue}if(p==="["&&!a){for(let[w,[g,S,E]]of Object.entries(Ss))if(n7.startsWith(w,r)){if(c)return["$.",!1,n7.length-e,!0];r+=w.length,E?i.push(g):s.push(g),h=h||S;continue t}}if(a=!1,c){p>c?s.push(lt(c)+"-"+lt(p)):p===c&&s.push(lt(p)),c="",r++;continue}if(n7.startsWith("-]",r+1)){s.push(lt(p+"-")),r+=2;continue}if(n7.startsWith("-",r+1)){c=p,r+=2;continue}s.push(lt(p)),r++}if(u<r)return["",!1,0,!1];if(!s.length&&!i.length)return["$.",!1,n7.length-e,!0];if(i.length===0&&s.length===1&&/^\\?.$/.test(s[0])&&!l){let p=s[0].length===2?s[0].slice(-1):s[0];return[Es(p),!1,u-e,!1]}let d="["+(l?"^":"")+we(s)+"]",f="["+(l?"":"^")+we(i)+"]";return[s.length&&i.length?"("+d+"|"+f+")":s.length?d:f,h,u-e,!0]},W=(n7,{windowsPathsNoEscape:t=!1,magicalBraces:e=!0}={})=>e?t?n7.replace(/\[([^\/\\])\]/g,"$1"):n7.replace(/((?!\\).|^)\[([^\/\\])\]/g,"$1$2").replace(/\\([^\/])/g,"$1"):t?n7.replace(/\[([^\/\\{}])\]/g,"$1"):n7.replace(/((?!\\).|^)\[([^\/\\{}])\]/g,"$1$2").replace(/\\([^\/{}])/g,"$1"),xs=new Set(["!","?","+","*","@"]),be=n7=>xs.has(n7),vs="(?!(?:^|/)\\.\\.?(?:$|/))",Ct="(?!\\.)",Cs=new Set(["[","."]),Ts=new Set(["..","."]),As=new Set("().*{}+?[]^$\\!"),ks=n7=>n7.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),Kt="[^/]",Se=Kt+"*?",Ee=Kt+"+?",Q=class n{type;#t;#s;#n=!1;#r=[];#o;#S;#w;#c=!1;#h;#u;#f=!1;constructor(t,e,s={}){this.type=t,t&&(this.#s=!0),this.#o=e,this.#t=this.#o?this.#o.#t:this,this.#h=this.#t===this?s:this.#t.#h,this.#w=this.#t===this?[]:this.#t.#w,t==="!"&&!this.#t.#c&&this.#w.push(this),this.#S=this.#o?this.#o.#r.length:0}get hasMagic(){if(this.#s!==void 0)return this.#s;for(let t of this.#r)if(typeof t!="string"&&(t.type||t.hasMagic))return this.#s=!0;return this.#s}toString(){return this.#u!==void 0?this.#u:this.type?this.#u=this.type+"("+this.#r.map(t=>String(t)).join("|")+")":this.#u=this.#r.map(t=>String(t)).join("")}#a(){if(this!==this.#t)throw new Error("should only call on root");if(this.#c)return this;this.toString(),this.#c=!0;let t;for(;t=this.#w.pop();){if(t.type!=="!")continue;let e=t,s=e.#o;for(;s;){for(let i=e.#S+1;!s.type&&i<s.#r.length;i++)for(let r of t.#r){if(typeof r=="string")throw new Error("string part in extglob AST??");r.copyIn(s.#r[i])}e=s,s=e.#o}}return this}push(...t){for(let e of t)if(e!==""){if(typeof e!="string"&&!(e instanceof n&&e.#o===this))throw new Error("invalid part: "+e);this.#r.push(e)}}toJSON(){let t=this.type===null?this.#r.slice().map(e=>typeof e=="string"?e:e.toJSON()):[this.type,...this.#r.map(e=>e.toJSON())];return this.isStart()&&!this.type&&t.unshift([]),this.isEnd()&&(this===this.#t||this.#t.#c&&this.#o?.type==="!")&&t.push({}),t}isStart(){if(this.#t===this)return!0;if(!this.#o?.isStart())return!1;if(this.#S===0)return!0;let t=this.#o;for(let e=0;e<this.#S;e++){let s=t.#r[e];if(!(s instanceof n&&s.type==="!"))return!1}return!0}isEnd(){if(this.#t===this||this.#o?.type==="!")return!0;if(!this.#o?.isEnd())return!1;if(!this.type)return this.#o?.isEnd();let t=this.#o?this.#o.#r.length:0;return this.#S===t-1}copyIn(t){typeof t=="string"?this.push(t):this.push(t.clone(this))}clone(t){let e=new n(this.type,t);for(let s of this.#r)e.copyIn(s);return e}static#i(t,e,s,i){let r=!1,o=!1,h=-1,a=!1;if(e.type===null){let f=s,m="";for(;f<t.length;){let p=t.charAt(f++);if(r||p==="\\"){r=!r,m+=p;continue}if(o){f===h+1?(p==="^"||p==="!")&&(a=!0):p==="]"&&!(f===h+2&&a)&&(o=!1),m+=p;continue}else if(p==="["){o=!0,h=f,a=!1,m+=p;continue}if(!i.noext&&be(p)&&t.charAt(f)==="("){e.push(m),m="";let w=new n(p,e);f=n.#i(t,w,f,i),e.push(w);continue}m+=p}return e.push(m),f}let l=s+1,u=new n(null,e),c=[],d="";for(;l<t.length;){let f=t.charAt(l++);if(r||f==="\\"){r=!r,d+=f;continue}if(o){l===h+1?(f==="^"||f==="!")&&(a=!0):f==="]"&&!(l===h+2&&a)&&(o=!1),d+=f;continue}else if(f==="["){o=!0,h=l,a=!1,d+=f;continue}if(be(f)&&t.charAt(l)==="("){u.push(d),d="";let m=new n(f,u);u.push(m),l=n.#i(t,m,l,i);continue}if(f==="|"){u.push(d),d="",c.push(u),u=new n(null,e);continue}if(f===")")return d===""&&e.#r.length===0&&(e.#f=!0),u.push(d),d="",e.push(...c,u),l;d+=f}return e.type=null,e.#s=void 0,e.#r=[t.substring(s-1)],l}static fromGlob(t,e={}){let s=new n(null,void 0,e);return n.#i(t,s,0,e),s}toMMPattern(){if(this!==this.#t)return this.#t.toMMPattern();let t=this.toString(),[e,s,i,r]=this.toRegExpSource();if(!(i||this.#s||this.#h.nocase&&!this.#h.nocaseMagicOnly&&t.toUpperCase()!==t.toLowerCase()))return s;let h=(this.#h.nocase?"i":"")+(r?"u":"");return Object.assign(new RegExp(`^${e}$`,h),{_src:e,_glob:t})}get options(){return this.#h}toRegExpSource(t){let e=t??!!this.#h.dot;if(this.#t===this&&this.#a(),!this.type){let a=this.isStart()&&this.isEnd()&&!this.#r.some(f=>typeof f!="string"),l=this.#r.map(f=>{let[m,p,w,g]=typeof f=="string"?n.#E(f,this.#s,a):f.toRegExpSource(t);return this.#s=this.#s||w,this.#n=this.#n||g,m}).join(""),u="";if(this.isStart()&&typeof this.#r[0]=="string"&&!(this.#r.length===1&&Ts.has(this.#r[0]))){let m=Cs,p=e&&m.has(l.charAt(0))||l.startsWith("\\.")&&m.has(l.charAt(2))||l.startsWith("\\.\\.")&&m.has(l.charAt(4)),w=!e&&!t&&m.has(l.charAt(0));u=p?vs:w?Ct:""}let c="";return this.isEnd()&&this.#t.#c&&this.#o?.type==="!"&&(c="(?:$|\\/)"),[u+l+c,W(l),this.#s=!!this.#s,this.#n]}let s=this.type==="*"||this.type==="+",i=this.type==="!"?"(?:(?!(?:":"(?:",r=this.#d(e);if(this.isStart()&&this.isEnd()&&!r&&this.type!=="!"){let a=this.toString();return this.#r=[a],this.type=null,this.#s=void 0,[a,W(this.toString()),!1,!1]}let o=!s||t||e||!Ct?"":this.#d(!0);o===r&&(o=""),o&&(r=`(?:${r})(?:${o})*?`);let h="";if(this.type==="!"&&this.#f)h=(this.isStart()&&!e?Ct:"")+Ee;else{let a=this.type==="!"?"))"+(this.isStart()&&!e&&!t?Ct:"")+Se+")":this.type==="@"?")":this.type==="?"?")?":this.type==="+"&&o?")":this.type==="*"&&o?")?":`)${this.type}`;h=i+r+a}return[h,W(r),this.#s=!!this.#s,this.#n]}#d(t){return this.#r.map(e=>{if(typeof e=="string")throw new Error("string type in extglob ast??");let[s,i,r,o]=e.toRegExpSource(t);return this.#n=this.#n||o,s}).filter(e=>!(this.isStart()&&this.isEnd())||!!e).join("|")}static#E(t,e,s=!1){let i=!1,r="",o=!1,h=!1;for(let a=0;a<t.length;a++){let l=t.charAt(a);if(i){i=!1,r+=(As.has(l)?"\\":"")+l;continue}if(l==="*"){if(h)continue;h=!0,r+=s&&/^[*]+$/.test(t)?Ee:Se,e=!0;continue}else h=!1;if(l==="\\"){a===t.length-1?r+="\\\\":i=!0;continue}if(l==="["){let[u,c,d,f]=ye(t,a);if(d){r+=u,o=o||c,a+=d-1,e=e||f;continue}}if(l==="?"){r+=Kt,e=!0;continue}r+=ks(l)}return[r,W(t),!!e,o]}},tt=(n7,{windowsPathsNoEscape:t=!1,magicalBraces:e=!1}={})=>e?t?n7.replace(/[?*()[\]{}]/g,"[$&]"):n7.replace(/[?*()[\]\\{}]/g,"\\$&"):t?n7.replace(/[?*()[\]]/g,"[$&]"):n7.replace(/[?*()[\]\\]/g,"\\$&"),O=(n7,t,e={})=>(at(t),!e.nocomment&&t.charAt(0)==="#"?!1:new D(t,e).match(n7)),Rs=/^\*+([^+@!?\*\[\(]*)$/,Os=n7=>t=>!t.startsWith(".")&&t.endsWith(n7),Fs=n7=>t=>t.endsWith(n7),Ds=n7=>(n7=n7.toLowerCase(),t=>!t.startsWith(".")&&t.toLowerCase().endsWith(n7)),Ms=n7=>(n7=n7.toLowerCase(),t=>t.toLowerCase().endsWith(n7)),Ns=/^\*+\.\*+$/,_s=n7=>!n7.startsWith(".")&&n7.includes("."),Ls=n7=>n7!=="."&&n7!==".."&&n7.includes("."),Ws=/^\.\*+$/,Ps=n7=>n7!=="."&&n7!==".."&&n7.startsWith("."),js=/^\*+$/,Is=n7=>n7.length!==0&&!n7.startsWith("."),zs=n7=>n7.length!==0&&n7!=="."&&n7!=="..",Bs=/^\?+([^+@!?\*\[\(]*)?$/,Us=([n7,t=""])=>{let e=Ce([n7]);return t?(t=t.toLowerCase(),s=>e(s)&&s.toLowerCase().endsWith(t)):e},$s=([n7,t=""])=>{let e=Te([n7]);return t?(t=t.toLowerCase(),s=>e(s)&&s.toLowerCase().endsWith(t)):e},Gs=([n7,t=""])=>{let e=Te([n7]);return t?s=>e(s)&&s.endsWith(t):e},Hs=([n7,t=""])=>{let e=Ce([n7]);return t?s=>e(s)&&s.endsWith(t):e},Ce=([n7])=>{let t=n7.length;return e=>e.length===t&&!e.startsWith(".")},Te=([n7])=>{let t=n7.length;return e=>e.length===t&&e!=="."&&e!==".."},Ae=typeof process=="object"&&process?typeof process.env=="object"&&process.env&&process.env.__MINIMATCH_TESTING_PLATFORM__||process.platform:"posix",xe={win32:{sep:"\\"},posix:{sep:"/"}},qs=Ae==="win32"?xe.win32.sep:xe.posix.sep;O.sep=qs;var A=Symbol("globstar **");O.GLOBSTAR=A;var Ks="[^/]",Vs=Ks+"*?",Ys="(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?",Xs="(?:(?!(?:\\/|^)\\.).)*?",Js=(n7,t={})=>e=>O(e,n7,t);O.filter=Js;var N=(n7,t={})=>Object.assign({},n7,t),Zs=n7=>{if(!n7||typeof n7!="object"||!Object.keys(n7).length)return O;let t=O;return Object.assign((s,i,r={})=>t(s,i,N(n7,r)),{Minimatch:class extends t.Minimatch{constructor(i,r={}){super(i,N(n7,r))}static defaults(i){return t.defaults(N(n7,i)).Minimatch}},AST:class extends t.AST{constructor(i,r,o={}){super(i,r,N(n7,o))}static fromGlob(i,r={}){return t.AST.fromGlob(i,N(n7,r))}},unescape:(s,i={})=>t.unescape(s,N(n7,i)),escape:(s,i={})=>t.escape(s,N(n7,i)),filter:(s,i={})=>t.filter(s,N(n7,i)),defaults:s=>t.defaults(N(n7,s)),makeRe:(s,i={})=>t.makeRe(s,N(n7,i)),braceExpand:(s,i={})=>t.braceExpand(s,N(n7,i)),match:(s,i,r={})=>t.match(s,i,N(n7,r)),sep:t.sep,GLOBSTAR:A})};O.defaults=Zs;var ke=(n7,t={})=>(at(n7),t.nobrace||!/\{(?:(?!\{).)*\}/.test(n7)?[n7]:ge(n7,{max:t.braceExpandMax}));O.braceExpand=ke;var Qs=(n7,t={})=>new D(n7,t).makeRe();O.makeRe=Qs;var ti=(n7,t,e={})=>{let s=new D(t,e);return n7=n7.filter(i=>s.match(i)),s.options.nonull&&!n7.length&&n7.push(t),n7};O.match=ti;var ve=/[?*]|[+@!]\(.*?\)|\[|\]/,ei=n7=>n7.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),D=class{options;set;pattern;windowsPathsNoEscape;nonegate;negate;comment;empty;preserveMultipleSlashes;partial;globSet;globParts;nocase;isWindows;platform;windowsNoMagicRoot;regexp;constructor(t,e={}){at(t),e=e||{},this.options=e,this.pattern=t,this.platform=e.platform||Ae,this.isWindows=this.platform==="win32";let s="allowWindowsEscape";this.windowsPathsNoEscape=!!e.windowsPathsNoEscape||e[s]===!1,this.windowsPathsNoEscape&&(this.pattern=this.pattern.replace(/\\/g,"/")),this.preserveMultipleSlashes=!!e.preserveMultipleSlashes,this.regexp=null,this.negate=!1,this.nonegate=!!e.nonegate,this.comment=!1,this.empty=!1,this.partial=!!e.partial,this.nocase=!!this.options.nocase,this.windowsNoMagicRoot=e.windowsNoMagicRoot!==void 0?e.windowsNoMagicRoot:!!(this.isWindows&&this.nocase),this.globSet=[],this.globParts=[],this.set=[],this.make()}hasMagic(){if(this.options.magicalBraces&&this.set.length>1)return!0;for(let t of this.set)for(let e of t)if(typeof e!="string")return!0;return!1}debug(...t){}make(){let t=this.pattern,e=this.options;if(!e.nocomment&&t.charAt(0)==="#"){this.comment=!0;return}if(!t){this.empty=!0;return}this.parseNegate(),this.globSet=[...new Set(this.braceExpand())],e.debug&&(this.debug=(...r)=>console.error(...r)),this.debug(this.pattern,this.globSet);let s=this.globSet.map(r=>this.slashSplit(r));this.globParts=this.preprocess(s),this.debug(this.pattern,this.globParts);let i=this.globParts.map((r,o,h)=>{if(this.isWindows&&this.windowsNoMagicRoot){let a=r[0]===""&&r[1]===""&&(r[2]==="?"||!ve.test(r[2]))&&!ve.test(r[3]),l=/^[a-z]:/i.test(r[0]);if(a)return[...r.slice(0,4),...r.slice(4).map(u=>this.parse(u))];if(l)return[r[0],...r.slice(1).map(u=>this.parse(u))]}return r.map(a=>this.parse(a))});if(this.debug(this.pattern,i),this.set=i.filter(r=>r.indexOf(!1)===-1),this.isWindows)for(let r=0;r<this.set.length;r++){let o=this.set[r];o[0]===""&&o[1]===""&&this.globParts[r][2]==="?"&&typeof o[3]=="string"&&/^[a-z]:$/i.test(o[3])&&(o[2]="?")}this.debug(this.pattern,this.set)}preprocess(t){if(this.options.noglobstar)for(let s=0;s<t.length;s++)for(let i=0;i<t[s].length;i++)t[s][i]==="**"&&(t[s][i]="*");let{optimizationLevel:e=1}=this.options;return e>=2?(t=this.firstPhasePreProcess(t),t=this.secondPhasePreProcess(t)):e>=1?t=this.levelOneOptimize(t):t=this.adjascentGlobstarOptimize(t),t}adjascentGlobstarOptimize(t){return t.map(e=>{let s=-1;for(;(s=e.indexOf("**",s+1))!==-1;){let i=s;for(;e[i+1]==="**";)i++;i!==s&&e.splice(s,i-s)}return e})}levelOneOptimize(t){return t.map(e=>(e=e.reduce((s,i)=>{let r=s[s.length-1];return i==="**"&&r==="**"?s:i===".."&&r&&r!==".."&&r!=="."&&r!=="**"?(s.pop(),s):(s.push(i),s)},[]),e.length===0?[""]:e))}levelTwoFileOptimize(t){Array.isArray(t)||(t=this.slashSplit(t));let e=!1;do{if(e=!1,!this.preserveMultipleSlashes){for(let i=1;i<t.length-1;i++){let r=t[i];i===1&&r===""&&t[0]===""||(r==="."||r==="")&&(e=!0,t.splice(i,1),i--)}t[0]==="."&&t.length===2&&(t[1]==="."||t[1]==="")&&(e=!0,t.pop())}let s=0;for(;(s=t.indexOf("..",s+1))!==-1;){let i=t[s-1];i&&i!=="."&&i!==".."&&i!=="**"&&(e=!0,t.splice(s-1,2),s-=2)}}while(e);return t.length===0?[""]:t}firstPhasePreProcess(t){let e=!1;do{e=!1;for(let s of t){let i=-1;for(;(i=s.indexOf("**",i+1))!==-1;){let o=i;for(;s[o+1]==="**";)o++;o>i&&s.splice(i+1,o-i);let h=s[i+1],a=s[i+2],l=s[i+3];if(h!==".."||!a||a==="."||a===".."||!l||l==="."||l==="..")continue;e=!0,s.splice(i,1);let u=s.slice(0);u[i]="**",t.push(u),i--}if(!this.preserveMultipleSlashes){for(let o=1;o<s.length-1;o++){let h=s[o];o===1&&h===""&&s[0]===""||(h==="."||h==="")&&(e=!0,s.splice(o,1),o--)}s[0]==="."&&s.length===2&&(s[1]==="."||s[1]==="")&&(e=!0,s.pop())}let r=0;for(;(r=s.indexOf("..",r+1))!==-1;){let o=s[r-1];if(o&&o!=="."&&o!==".."&&o!=="**"){e=!0;let a=r===1&&s[r+1]==="**"?["."]:[];s.splice(r-1,2,...a),s.length===0&&s.push(""),r-=2}}}}while(e);return t}secondPhasePreProcess(t){for(let e=0;e<t.length-1;e++)for(let s=e+1;s<t.length;s++){let i=this.partsMatch(t[e],t[s],!this.preserveMultipleSlashes);if(i){t[e]=[],t[s]=i;break}}return t.filter(e=>e.length)}partsMatch(t,e,s=!1){let i=0,r=0,o=[],h="";for(;i<t.length&&r<e.length;)if(t[i]===e[r])o.push(h==="b"?e[r]:t[i]),i++,r++;else if(s&&t[i]==="**"&&e[r]===t[i+1])o.push(t[i]),i++;else if(s&&e[r]==="**"&&t[i]===e[r+1])o.push(e[r]),r++;else if(t[i]==="*"&&e[r]&&(this.options.dot||!e[r].startsWith("."))&&e[r]!=="**"){if(h==="b")return!1;h="a",o.push(t[i]),i++,r++}else if(e[r]==="*"&&t[i]&&(this.options.dot||!t[i].startsWith("."))&&t[i]!=="**"){if(h==="a")return!1;h="b",o.push(e[r]),i++,r++}else return!1;return t.length===e.length&&o}parseNegate(){if(this.nonegate)return;let t=this.pattern,e=!1,s=0;for(let i=0;i<t.length&&t.charAt(i)==="!";i++)e=!e,s++;s&&(this.pattern=t.slice(s)),this.negate=e}matchOne(t,e,s=!1){let i=this.options;if(this.isWindows){let p=typeof t[0]=="string"&&/^[a-z]:$/i.test(t[0]),w=!p&&t[0]===""&&t[1]===""&&t[2]==="?"&&/^[a-z]:$/i.test(t[3]),g=typeof e[0]=="string"&&/^[a-z]:$/i.test(e[0]),S=!g&&e[0]===""&&e[1]===""&&e[2]==="?"&&typeof e[3]=="string"&&/^[a-z]:$/i.test(e[3]),E=w?3:p?0:void 0,y=S?3:g?0:void 0;if(typeof E=="number"&&typeof y=="number"){let[b,z2]=[t[E],e[y]];b.toLowerCase()===z2.toLowerCase()&&(e[y]=b,y>E?e=e.slice(y):E>y&&(t=t.slice(E)))}}let{optimizationLevel:r=1}=this.options;r>=2&&(t=this.levelTwoFileOptimize(t)),this.debug("matchOne",this,{file:t,pattern:e}),this.debug("matchOne",t.length,e.length);for(var o=0,h=0,a=t.length,l=e.length;o<a&&h<l;o++,h++){this.debug("matchOne loop");var u=e[h],c=t[o];if(this.debug(e,u,c),u===!1)return!1;if(u===A){this.debug("GLOBSTAR",[e,u,c]);var d=o,f=h+1;if(f===l){for(this.debug("** at the end");o<a;o++)if(t[o]==="."||t[o]===".."||!i.dot&&t[o].charAt(0)===".")return!1;return!0}for(;d<a;){var m=t[d];if(this.debug(`
804
805
  globstar while`,t,d,e,f,m),this.matchOne(t.slice(d),e.slice(f),s))return this.debug("globstar found match!",d,a,m),!0;if(m==="."||m===".."||!i.dot&&m.charAt(0)==="."){this.debug("dot detected!",t,d,e,f);break}this.debug("globstar swallow a segment, and continue"),d++}return!!(s&&(this.debug(`
805
806
  >>> no match, partial?`,t,d,e,f),d===a))}let p;if(typeof u=="string"?(p=c===u,this.debug("string match",u,c,p)):(p=u.test(c),this.debug("pattern match",u,c,p)),!p)return!1}if(o===a&&h===l)return!0;if(o===a)return s;if(h===l)return o===a-1&&t[o]==="";throw new Error("wtf?")}braceExpand(){return ke(this.pattern,this.options)}parse(t){at(t);let e=this.options;if(t==="**")return A;if(t==="")return"";let s,i=null;(s=t.match(js))?i=e.dot?zs:Is:(s=t.match(Rs))?i=(e.nocase?e.dot?Ms:Ds:e.dot?Fs:Os)(s[1]):(s=t.match(Bs))?i=(e.nocase?e.dot?$s:Us:e.dot?Gs:Hs)(s):(s=t.match(Ns))?i=e.dot?Ls:_s:(s=t.match(Ws))&&(i=Ps);let r=Q.fromGlob(t,this.options).toMMPattern();return i&&typeof r=="object"&&Reflect.defineProperty(r,"test",{value:i}),r}makeRe(){if(this.regexp||this.regexp===!1)return this.regexp;let t=this.set;if(!t.length)return this.regexp=!1,this.regexp;let e=this.options,s=e.noglobstar?Vs:e.dot?Ys:Xs,i=new Set(e.nocase?["i"]:[]),r=t.map(a=>{let l=a.map(c=>{if(c instanceof RegExp)for(let d of c.flags.split(""))i.add(d);return typeof c=="string"?ei(c):c===A?A:c._src});l.forEach((c,d)=>{let f=l[d+1],m=l[d-1];c!==A||m===A||(m===void 0?f!==void 0&&f!==A?l[d+1]="(?:\\/|"+s+"\\/)?"+f:l[d]=s:f===void 0?l[d-1]=m+"(?:\\/|\\/"+s+")?":f!==A&&(l[d-1]=m+"(?:\\/|\\/"+s+"\\/)"+f,l[d+1]=A))});let u=l.filter(c=>c!==A);if(this.partial&&u.length>=1){let c=[];for(let d=1;d<=u.length;d++)c.push(u.slice(0,d).join("/"));return"(?:"+c.join("|")+")"}return u.join("/")}).join("|"),[o,h]=t.length>1?["(?:",")"]:["",""];r="^"+o+r+h+"$",this.partial&&(r="^(?:\\/|"+o+r.slice(1,-1)+h+")$"),this.negate&&(r="^(?!"+r+").+$");try{this.regexp=new RegExp(r,[...i].join(""))}catch{this.regexp=!1}return this.regexp}slashSplit(t){return this.preserveMultipleSlashes?t.split("/"):this.isWindows&&/^\/\/[^\/]+/.test(t)?["",...t.split(/\/+/)]:t.split(/\/+/)}match(t,e=this.partial){if(this.debug("match",t,this.pattern),this.comment)return!1;if(this.empty)return t==="";if(t==="/"&&e)return!0;let s=this.options;this.isWindows&&(t=t.split("\\").join("/"));let i=this.slashSplit(t);this.debug(this.pattern,"split",i);let r=this.set;this.debug(this.pattern,"set",r);let o=i[i.length-1];if(!o)for(let h=i.length-2;!o&&h>=0;h--)o=i[h];for(let h=0;h<r.length;h++){let a=r[h],l=i;if(s.matchBase&&a.length===1&&(l=[o]),this.matchOne(l,a,e))return s.flipNegate?!0:!this.negate}return s.flipNegate?!1:this.negate}static defaults(t){return O.defaults(t).Minimatch}};O.AST=Q;O.Minimatch=D;O.escape=tt;O.unescape=W;var si=typeof performance=="object"&&performance&&typeof performance.now=="function"?performance:Date,Oe=new Set,Vt=typeof process=="object"&&process?process:{},Fe=(n7,t,e,s)=>{typeof Vt.emitWarning=="function"?Vt.emitWarning(n7,t,e,s):console.error(`[${e}] ${t}: ${n7}`)},At=globalThis.AbortController,Re=globalThis.AbortSignal;if(typeof At>"u"){Re=class{onabort;_onabort=[];reason;aborted=!1;addEventListener(e,s){this._onabort.push(s)}},At=class{constructor(){t()}signal=new Re;abort(e){if(!this.signal.aborted){this.signal.reason=e,this.signal.aborted=!0;for(let s of this.signal._onabort)s(e);this.signal.onabort?.(e)}}};let n7=Vt.env?.LRU_CACHE_IGNORE_AC_WARNING!=="1",t=()=>{n7&&(n7=!1,Fe("AbortController is not defined. If using lru-cache in node 14, load an AbortController polyfill from the `node-abort-controller` package. A minimal polyfill is provided for use by LRUCache.fetch(), but it should not be relied upon in other contexts (eg, passing it to other APIs that use AbortController/AbortSignal might have undesirable effects). You may disable this with LRU_CACHE_IGNORE_AC_WARNING=1 in the env.","NO_ABORT_CONTROLLER","ENOTSUP",t))}}var ii=n7=>!Oe.has(n7),q=n7=>n7&&n7===Math.floor(n7)&&n7>0&&isFinite(n7),De=n7=>q(n7)?n7<=Math.pow(2,8)?Uint8Array:n7<=Math.pow(2,16)?Uint16Array:n7<=Math.pow(2,32)?Uint32Array:n7<=Number.MAX_SAFE_INTEGER?Tt:null:null,Tt=class extends Array{constructor(n7){super(n7),this.fill(0)}},ri=class ct{heap;length;static#t=!1;static create(t){let e=De(t);if(!e)return[];ct.#t=!0;let s=new ct(t,e);return ct.#t=!1,s}constructor(t,e){if(!ct.#t)throw new TypeError("instantiate Stack using Stack.create(n)");this.heap=new e(t),this.length=0}push(t){this.heap[this.length++]=t}pop(){return this.heap[--this.length]}},ft=class Me{#t;#s;#n;#r;#o;#S;#w;#c;get perf(){return this.#c}ttl;ttlResolution;ttlAutopurge;updateAgeOnGet;updateAgeOnHas;allowStale;noDisposeOnSet;noUpdateTTL;maxEntrySize;sizeCalculation;noDeleteOnFetchRejection;noDeleteOnStaleGet;allowStaleOnFetchAbort;allowStaleOnFetchRejection;ignoreFetchAbort;#h;#u;#f;#a;#i;#d;#E;#b;#p;#R;#m;#C;#T;#g;#y;#x;#A;#e;#_;static unsafeExposeInternals(t){return{starts:t.#T,ttls:t.#g,autopurgeTimers:t.#y,sizes:t.#C,keyMap:t.#f,keyList:t.#a,valList:t.#i,next:t.#d,prev:t.#E,get head(){return t.#b},get tail(){return t.#p},free:t.#R,isBackgroundFetch:e=>t.#l(e),backgroundFetch:(e,s,i,r)=>t.#U(e,s,i,r),moveToTail:e=>t.#W(e),indexes:e=>t.#F(e),rindexes:e=>t.#D(e),isStale:e=>t.#v(e)}}get max(){return this.#t}get maxSize(){return this.#s}get calculatedSize(){return this.#u}get size(){return this.#h}get fetchMethod(){return this.#S}get memoMethod(){return this.#w}get dispose(){return this.#n}get onInsert(){return this.#r}get disposeAfter(){return this.#o}constructor(t){let{max:e=0,ttl:s,ttlResolution:i=1,ttlAutopurge:r,updateAgeOnGet:o,updateAgeOnHas:h,allowStale:a,dispose:l,onInsert:u,disposeAfter:c,noDisposeOnSet:d,noUpdateTTL:f,maxSize:m=0,maxEntrySize:p=0,sizeCalculation:w,fetchMethod:g,memoMethod:S,noDeleteOnFetchRejection:E,noDeleteOnStaleGet:y,allowStaleOnFetchRejection:b,allowStaleOnFetchAbort:z2,ignoreFetchAbort:$,perf:J}=t;if(J!==void 0&&typeof J?.now!="function")throw new TypeError("perf option must have a now() method if specified");if(this.#c=J??si,e!==0&&!q(e))throw new TypeError("max option must be a nonnegative integer");let Z=e?De(e):Array;if(!Z)throw new Error("invalid max value: "+e);if(this.#t=e,this.#s=m,this.maxEntrySize=p||this.#s,this.sizeCalculation=w,this.sizeCalculation){if(!this.#s&&!this.maxEntrySize)throw new TypeError("cannot set sizeCalculation without setting maxSize or maxEntrySize");if(typeof this.sizeCalculation!="function")throw new TypeError("sizeCalculation set to non-function")}if(S!==void 0&&typeof S!="function")throw new TypeError("memoMethod must be a function if defined");if(this.#w=S,g!==void 0&&typeof g!="function")throw new TypeError("fetchMethod must be a function if specified");if(this.#S=g,this.#A=!!g,this.#f=new Map,this.#a=new Array(e).fill(void 0),this.#i=new Array(e).fill(void 0),this.#d=new Z(e),this.#E=new Z(e),this.#b=0,this.#p=0,this.#R=ri.create(e),this.#h=0,this.#u=0,typeof l=="function"&&(this.#n=l),typeof u=="function"&&(this.#r=u),typeof c=="function"?(this.#o=c,this.#m=[]):(this.#o=void 0,this.#m=void 0),this.#x=!!this.#n,this.#_=!!this.#r,this.#e=!!this.#o,this.noDisposeOnSet=!!d,this.noUpdateTTL=!!f,this.noDeleteOnFetchRejection=!!E,this.allowStaleOnFetchRejection=!!b,this.allowStaleOnFetchAbort=!!z2,this.ignoreFetchAbort=!!$,this.maxEntrySize!==0){if(this.#s!==0&&!q(this.#s))throw new TypeError("maxSize must be a positive integer if specified");if(!q(this.maxEntrySize))throw new TypeError("maxEntrySize must be a positive integer if specified");this.#G()}if(this.allowStale=!!a,this.noDeleteOnStaleGet=!!y,this.updateAgeOnGet=!!o,this.updateAgeOnHas=!!h,this.ttlResolution=q(i)||i===0?i:1,this.ttlAutopurge=!!r,this.ttl=s||0,this.ttl){if(!q(this.ttl))throw new TypeError("ttl must be a positive integer if specified");this.#M()}if(this.#t===0&&this.ttl===0&&this.#s===0)throw new TypeError("At least one of max, maxSize, or ttl is required");if(!this.ttlAutopurge&&!this.#t&&!this.#s){let $t="LRU_CACHE_UNBOUNDED";ii($t)&&(Oe.add($t),Fe("TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption.","UnboundedCacheWarning",$t,Me))}}getRemainingTTL(t){return this.#f.has(t)?1/0:0}#M(){let t=new Tt(this.#t),e=new Tt(this.#t);this.#g=t,this.#T=e;let s=this.ttlAutopurge?new Array(this.#t):void 0;this.#y=s,this.#j=(o,h,a=this.#c.now())=>{if(e[o]=h!==0?a:0,t[o]=h,s?.[o]&&(clearTimeout(s[o]),s[o]=void 0),h!==0&&s){let l=setTimeout(()=>{this.#v(o)&&this.#O(this.#a[o],"expire")},h+1);l.unref&&l.unref(),s[o]=l}},this.#k=o=>{e[o]=t[o]!==0?this.#c.now():0},this.#N=(o,h)=>{if(t[h]){let a=t[h],l=e[h];if(!a||!l)return;o.ttl=a,o.start=l,o.now=i||r();let u=o.now-l;o.remainingTTL=a-u}};let i=0,r=()=>{let o=this.#c.now();if(this.ttlResolution>0){i=o;let h=setTimeout(()=>i=0,this.ttlResolution);h.unref&&h.unref()}return o};this.getRemainingTTL=o=>{let h=this.#f.get(o);if(h===void 0)return 0;let a=t[h],l=e[h];if(!a||!l)return 1/0;let u=(i||r())-l;return a-u},this.#v=o=>{let h=e[o],a=t[o];return!!a&&!!h&&(i||r())-h>a}}#k=()=>{};#N=()=>{};#j=()=>{};#v=()=>!1;#G(){let t=new Tt(this.#t);this.#u=0,this.#C=t,this.#P=e=>{this.#u-=t[e],t[e]=0},this.#I=(e,s,i,r)=>{if(this.#l(s))return 0;if(!q(i))if(r){if(typeof r!="function")throw new TypeError("sizeCalculation must be a function");if(i=r(s,e),!q(i))throw new TypeError("sizeCalculation return invalid (expect positive integer)")}else throw new TypeError("invalid size value (must be positive integer). When maxSize or maxEntrySize is used, sizeCalculation or size must be set.");return i},this.#L=(e,s,i)=>{if(t[e]=s,this.#s){let r=this.#s-t[e];for(;this.#u>r;)this.#B(!0)}this.#u+=t[e],i&&(i.entrySize=s,i.totalCalculatedSize=this.#u)}}#P=t=>{};#L=(t,e,s)=>{};#I=(t,e,s,i)=>{if(s||i)throw new TypeError("cannot set size without setting maxSize or maxEntrySize on cache");return 0};*#F({allowStale:t=this.allowStale}={}){if(this.#h)for(let e=this.#p;!(!this.#z(e)||((t||!this.#v(e))&&(yield e),e===this.#b));)e=this.#E[e]}*#D({allowStale:t=this.allowStale}={}){if(this.#h)for(let e=this.#b;!(!this.#z(e)||((t||!this.#v(e))&&(yield e),e===this.#p));)e=this.#d[e]}#z(t){return t!==void 0&&this.#f.get(this.#a[t])===t}*entries(){for(let t of this.#F())this.#i[t]!==void 0&&this.#a[t]!==void 0&&!this.#l(this.#i[t])&&(yield[this.#a[t],this.#i[t]])}*rentries(){for(let t of this.#D())this.#i[t]!==void 0&&this.#a[t]!==void 0&&!this.#l(this.#i[t])&&(yield[this.#a[t],this.#i[t]])}*keys(){for(let t of this.#F()){let e=this.#a[t];e!==void 0&&!this.#l(this.#i[t])&&(yield e)}}*rkeys(){for(let t of this.#D()){let e=this.#a[t];e!==void 0&&!this.#l(this.#i[t])&&(yield e)}}*values(){for(let t of this.#F())this.#i[t]!==void 0&&!this.#l(this.#i[t])&&(yield this.#i[t])}*rvalues(){for(let t of this.#D())this.#i[t]!==void 0&&!this.#l(this.#i[t])&&(yield this.#i[t])}[Symbol.iterator](){return this.entries()}[Symbol.toStringTag]="LRUCache";find(t,e={}){for(let s of this.#F()){let i=this.#i[s],r=this.#l(i)?i.__staleWhileFetching:i;if(r!==void 0&&t(r,this.#a[s],this))return this.get(this.#a[s],e)}}forEach(t,e=this){for(let s of this.#F()){let i=this.#i[s],r=this.#l(i)?i.__staleWhileFetching:i;r!==void 0&&t.call(e,r,this.#a[s],this)}}rforEach(t,e=this){for(let s of this.#D()){let i=this.#i[s],r=this.#l(i)?i.__staleWhileFetching:i;r!==void 0&&t.call(e,r,this.#a[s],this)}}purgeStale(){let t=!1;for(let e of this.#D({allowStale:!0}))this.#v(e)&&(this.#O(this.#a[e],"expire"),t=!0);return t}info(t){let e=this.#f.get(t);if(e===void 0)return;let s=this.#i[e],i=this.#l(s)?s.__staleWhileFetching:s;if(i===void 0)return;let r={value:i};if(this.#g&&this.#T){let o=this.#g[e],h=this.#T[e];if(o&&h){let a=o-(this.#c.now()-h);r.ttl=a,r.start=Date.now()}}return this.#C&&(r.size=this.#C[e]),r}dump(){let t=[];for(let e of this.#F({allowStale:!0})){let s=this.#a[e],i=this.#i[e],r=this.#l(i)?i.__staleWhileFetching:i;if(r===void 0||s===void 0)continue;let o={value:r};if(this.#g&&this.#T){o.ttl=this.#g[e];let h=this.#c.now()-this.#T[e];o.start=Math.floor(Date.now()-h)}this.#C&&(o.size=this.#C[e]),t.unshift([s,o])}return t}load(t){this.clear();for(let[e,s]of t){if(s.start){let i=Date.now()-s.start;s.start=this.#c.now()-i}this.set(e,s.value,s)}}set(t,e,s={}){if(e===void 0)return this.delete(t),this;let{ttl:i=this.ttl,start:r,noDisposeOnSet:o=this.noDisposeOnSet,sizeCalculation:h=this.sizeCalculation,status:a}=s,{noUpdateTTL:l=this.noUpdateTTL}=s,u=this.#I(t,e,s.size||0,h);if(this.maxEntrySize&&u>this.maxEntrySize)return a&&(a.set="miss",a.maxEntrySizeExceeded=!0),this.#O(t,"set"),this;let c=this.#h===0?void 0:this.#f.get(t);if(c===void 0)c=this.#h===0?this.#p:this.#R.length!==0?this.#R.pop():this.#h===this.#t?this.#B(!1):this.#h,this.#a[c]=t,this.#i[c]=e,this.#f.set(t,c),this.#d[this.#p]=c,this.#E[c]=this.#p,this.#p=c,this.#h++,this.#L(c,u,a),a&&(a.set="add"),l=!1,this.#_&&this.#r?.(e,t,"add");else{this.#W(c);let d=this.#i[c];if(e!==d){if(this.#A&&this.#l(d)){d.__abortController.abort(new Error("replaced"));let{__staleWhileFetching:f}=d;f!==void 0&&!o&&(this.#x&&this.#n?.(f,t,"set"),this.#e&&this.#m?.push([f,t,"set"]))}else o||(this.#x&&this.#n?.(d,t,"set"),this.#e&&this.#m?.push([d,t,"set"]));if(this.#P(c),this.#L(c,u,a),this.#i[c]=e,a){a.set="replace";let f=d&&this.#l(d)?d.__staleWhileFetching:d;f!==void 0&&(a.oldValue=f)}}else a&&(a.set="update");this.#_&&this.onInsert?.(e,t,e===d?"update":"replace")}if(i!==0&&!this.#g&&this.#M(),this.#g&&(l||this.#j(c,i,r),a&&this.#N(a,c)),!o&&this.#e&&this.#m){let d=this.#m,f;for(;f=d?.shift();)this.#o?.(...f)}return this}pop(){try{for(;this.#h;){let t=this.#i[this.#b];if(this.#B(!0),this.#l(t)){if(t.__staleWhileFetching)return t.__staleWhileFetching}else if(t!==void 0)return t}}finally{if(this.#e&&this.#m){let t=this.#m,e;for(;e=t?.shift();)this.#o?.(...e)}}}#B(t){let e=this.#b,s=this.#a[e],i=this.#i[e];return this.#A&&this.#l(i)?i.__abortController.abort(new Error("evicted")):(this.#x||this.#e)&&(this.#x&&this.#n?.(i,s,"evict"),this.#e&&this.#m?.push([i,s,"evict"])),this.#P(e),this.#y?.[e]&&(clearTimeout(this.#y[e]),this.#y[e]=void 0),t&&(this.#a[e]=void 0,this.#i[e]=void 0,this.#R.push(e)),this.#h===1?(this.#b=this.#p=0,this.#R.length=0):this.#b=this.#d[e],this.#f.delete(s),this.#h--,e}has(t,e={}){let{updateAgeOnHas:s=this.updateAgeOnHas,status:i}=e,r=this.#f.get(t);if(r!==void 0){let o=this.#i[r];if(this.#l(o)&&o.__staleWhileFetching===void 0)return!1;if(this.#v(r))i&&(i.has="stale",this.#N(i,r));else return s&&this.#k(r),i&&(i.has="hit",this.#N(i,r)),!0}else i&&(i.has="miss");return!1}peek(t,e={}){let{allowStale:s=this.allowStale}=e,i=this.#f.get(t);if(i===void 0||!s&&this.#v(i))return;let r=this.#i[i];return this.#l(r)?r.__staleWhileFetching:r}#U(t,e,s,i){let r=e===void 0?void 0:this.#i[e];if(this.#l(r))return r;let o=new At,{signal:h}=s;h?.addEventListener("abort",()=>o.abort(h.reason),{signal:o.signal});let a={signal:o.signal,options:s,context:i},l=(p,w=!1)=>{let{aborted:g}=o.signal,S=s.ignoreFetchAbort&&p!==void 0,E=s.ignoreFetchAbort||!!(s.allowStaleOnFetchAbort&&p!==void 0);if(s.status&&(g&&!w?(s.status.fetchAborted=!0,s.status.fetchError=o.signal.reason,S&&(s.status.fetchAbortIgnored=!0)):s.status.fetchResolved=!0),g&&!S&&!w)return c(o.signal.reason,E);let y=f,b=this.#i[e];return(b===f||S&&w&&b===void 0)&&(p===void 0?y.__staleWhileFetching!==void 0?this.#i[e]=y.__staleWhileFetching:this.#O(t,"fetch"):(s.status&&(s.status.fetchUpdated=!0),this.set(t,p,a.options))),p},u=p=>(s.status&&(s.status.fetchRejected=!0,s.status.fetchError=p),c(p,!1)),c=(p,w)=>{let{aborted:g}=o.signal,S=g&&s.allowStaleOnFetchAbort,E=S||s.allowStaleOnFetchRejection,y=E||s.noDeleteOnFetchRejection,b=f;if(this.#i[e]===f&&(!y||!w&&b.__staleWhileFetching===void 0?this.#O(t,"fetch"):S||(this.#i[e]=b.__staleWhileFetching)),E)return s.status&&b.__staleWhileFetching!==void 0&&(s.status.returnedStale=!0),b.__staleWhileFetching;if(b.__returned===b)throw p},d=(p,w)=>{let g=this.#S?.(t,r,a);g&&g instanceof Promise&&g.then(S=>p(S===void 0?void 0:S),w),o.signal.addEventListener("abort",()=>{(!s.ignoreFetchAbort||s.allowStaleOnFetchAbort)&&(p(void 0),s.allowStaleOnFetchAbort&&(p=S=>l(S,!0)))})};s.status&&(s.status.fetchDispatched=!0);let f=new Promise(d).then(l,u),m=Object.assign(f,{__abortController:o,__staleWhileFetching:r,__returned:void 0});return e===void 0?(this.set(t,m,{...a.options,status:void 0}),e=this.#f.get(t)):this.#i[e]=m,m}#l(t){if(!this.#A)return!1;let e=t;return!!e&&e instanceof Promise&&e.hasOwnProperty("__staleWhileFetching")&&e.__abortController instanceof At}async fetch(t,e={}){let{allowStale:s=this.allowStale,updateAgeOnGet:i=this.updateAgeOnGet,noDeleteOnStaleGet:r=this.noDeleteOnStaleGet,ttl:o=this.ttl,noDisposeOnSet:h=this.noDisposeOnSet,size:a=0,sizeCalculation:l=this.sizeCalculation,noUpdateTTL:u=this.noUpdateTTL,noDeleteOnFetchRejection:c=this.noDeleteOnFetchRejection,allowStaleOnFetchRejection:d=this.allowStaleOnFetchRejection,ignoreFetchAbort:f=this.ignoreFetchAbort,allowStaleOnFetchAbort:m=this.allowStaleOnFetchAbort,context:p,forceRefresh:w=!1,status:g,signal:S}=e;if(!this.#A)return g&&(g.fetch="get"),this.get(t,{allowStale:s,updateAgeOnGet:i,noDeleteOnStaleGet:r,status:g});let E={allowStale:s,updateAgeOnGet:i,noDeleteOnStaleGet:r,ttl:o,noDisposeOnSet:h,size:a,sizeCalculation:l,noUpdateTTL:u,noDeleteOnFetchRejection:c,allowStaleOnFetchRejection:d,allowStaleOnFetchAbort:m,ignoreFetchAbort:f,status:g,signal:S},y=this.#f.get(t);if(y===void 0){g&&(g.fetch="miss");let b=this.#U(t,y,E,p);return b.__returned=b}else{let b=this.#i[y];if(this.#l(b)){let Z=s&&b.__staleWhileFetching!==void 0;return g&&(g.fetch="inflight",Z&&(g.returnedStale=!0)),Z?b.__staleWhileFetching:b.__returned=b}let z2=this.#v(y);if(!w&&!z2)return g&&(g.fetch="hit"),this.#W(y),i&&this.#k(y),g&&this.#N(g,y),b;let $=this.#U(t,y,E,p),J=$.__staleWhileFetching!==void 0&&s;return g&&(g.fetch=z2?"stale":"refresh",J&&z2&&(g.returnedStale=!0)),J?$.__staleWhileFetching:$.__returned=$}}async forceFetch(t,e={}){let s=await this.fetch(t,e);if(s===void 0)throw new Error("fetch() returned undefined");return s}memo(t,e={}){let s=this.#w;if(!s)throw new Error("no memoMethod provided to constructor");let{context:i,forceRefresh:r,...o}=e,h=this.get(t,o);if(!r&&h!==void 0)return h;let a=s(t,h,{options:o,context:i});return this.set(t,a,o),a}get(t,e={}){let{allowStale:s=this.allowStale,updateAgeOnGet:i=this.updateAgeOnGet,noDeleteOnStaleGet:r=this.noDeleteOnStaleGet,status:o}=e,h=this.#f.get(t);if(h!==void 0){let a=this.#i[h],l=this.#l(a);return o&&this.#N(o,h),this.#v(h)?(o&&(o.get="stale"),l?(o&&s&&a.__staleWhileFetching!==void 0&&(o.returnedStale=!0),s?a.__staleWhileFetching:void 0):(r||this.#O(t,"expire"),o&&s&&(o.returnedStale=!0),s?a:void 0)):(o&&(o.get="hit"),l?a.__staleWhileFetching:(this.#W(h),i&&this.#k(h),a))}else o&&(o.get="miss")}#$(t,e){this.#E[e]=t,this.#d[t]=e}#W(t){t!==this.#p&&(t===this.#b?this.#b=this.#d[t]:this.#$(this.#E[t],this.#d[t]),this.#$(this.#p,t),this.#p=t)}delete(t){return this.#O(t,"delete")}#O(t,e){let s=!1;if(this.#h!==0){let i=this.#f.get(t);if(i!==void 0)if(this.#y?.[i]&&(clearTimeout(this.#y?.[i]),this.#y[i]=void 0),s=!0,this.#h===1)this.#H(e);else{this.#P(i);let r=this.#i[i];if(this.#l(r)?r.__abortController.abort(new Error("deleted")):(this.#x||this.#e)&&(this.#x&&this.#n?.(r,t,e),this.#e&&this.#m?.push([r,t,e])),this.#f.delete(t),this.#a[i]=void 0,this.#i[i]=void 0,i===this.#p)this.#p=this.#E[i];else if(i===this.#b)this.#b=this.#d[i];else{let o=this.#E[i];this.#d[o]=this.#d[i];let h=this.#d[i];this.#E[h]=this.#E[i]}this.#h--,this.#R.push(i)}}if(this.#e&&this.#m?.length){let i=this.#m,r;for(;r=i?.shift();)this.#o?.(...r)}return s}clear(){return this.#H("delete")}#H(t){for(let e of this.#D({allowStale:!0})){let s=this.#i[e];if(this.#l(s))s.__abortController.abort(new Error("deleted"));else{let i=this.#a[e];this.#x&&this.#n?.(s,i,t),this.#e&&this.#m?.push([s,i,t])}}if(this.#f.clear(),this.#i.fill(void 0),this.#a.fill(void 0),this.#g&&this.#T){this.#g.fill(0),this.#T.fill(0);for(let e of this.#y??[])e!==void 0&&clearTimeout(e);this.#y?.fill(void 0)}if(this.#C&&this.#C.fill(0),this.#b=0,this.#p=0,this.#R.length=0,this.#u=0,this.#h=0,this.#e&&this.#m){let e=this.#m,s;for(;s=e?.shift();)this.#o?.(...s)}}},Ne=typeof process=="object"&&process?process:{stdout:null,stderr:null},oi=n7=>!!n7&&typeof n7=="object"&&(n7 instanceof V||n7 instanceof Pe||hi(n7)||ai(n7)),hi=n7=>!!n7&&typeof n7=="object"&&n7 instanceof ee&&typeof n7.pipe=="function"&&n7.pipe!==Pe.Writable.prototype.pipe,ai=n7=>!!n7&&typeof n7=="object"&&n7 instanceof ee&&typeof n7.write=="function"&&typeof n7.end=="function",G=Symbol("EOF"),H=Symbol("maybeEmitEnd"),K=Symbol("emittedEnd"),kt=Symbol("emittingEnd"),ut=Symbol("emittedError"),Rt=Symbol("closed"),_e=Symbol("read"),Ot=Symbol("flush"),Le=Symbol("flushChunk"),P=Symbol("encoding"),et=Symbol("decoder"),v=Symbol("flowing"),dt=Symbol("paused"),st=Symbol("resume"),C=Symbol("buffer"),F=Symbol("pipes"),T=Symbol("bufferLength"),Yt=Symbol("bufferPush"),Ft=Symbol("bufferShift"),k=Symbol("objectMode"),x=Symbol("destroyed"),Xt=Symbol("error"),Jt=Symbol("emitData"),We=Symbol("emitEnd"),Zt=Symbol("emitEnd2"),B=Symbol("async"),Qt=Symbol("abort"),Dt=Symbol("aborted"),pt=Symbol("signal"),Y=Symbol("dataListeners"),M=Symbol("discarded"),mt=n7=>Promise.resolve().then(n7),li=n7=>n7(),ci=n7=>n7==="end"||n7==="finish"||n7==="prefinish",fi=n7=>n7 instanceof ArrayBuffer||!!n7&&typeof n7=="object"&&n7.constructor&&n7.constructor.name==="ArrayBuffer"&&n7.byteLength>=0,ui=n7=>!Buffer.isBuffer(n7)&&ArrayBuffer.isView(n7),Mt=class{src;dest;opts;ondrain;constructor(t,e,s){this.src=t,this.dest=e,this.opts=s,this.ondrain=()=>t[st](),this.dest.on("drain",this.ondrain)}unpipe(){this.dest.removeListener("drain",this.ondrain)}proxyErrors(t){}end(){this.unpipe(),this.opts.end&&this.dest.end()}},te=class extends Mt{unpipe(){this.src.removeListener("error",this.proxyErrors),super.unpipe()}constructor(t,e,s){super(t,e,s),this.proxyErrors=i=>this.dest.emit("error",i),t.on("error",this.proxyErrors)}},di=n7=>!!n7.objectMode,pi=n7=>!n7.objectMode&&!!n7.encoding&&n7.encoding!=="buffer",V=class extends ee{[v]=!1;[dt]=!1;[F]=[];[C]=[];[k];[P];[B];[et];[G]=!1;[K]=!1;[kt]=!1;[Rt]=!1;[ut]=null;[T]=0;[x]=!1;[pt];[Dt]=!1;[Y]=0;[M]=!1;writable=!0;readable=!0;constructor(...t){let e=t[0]||{};if(super(),e.objectMode&&typeof e.encoding=="string")throw new TypeError("Encoding and objectMode may not be used together");di(e)?(this[k]=!0,this[P]=null):pi(e)?(this[P]=e.encoding,this[k]=!1):(this[k]=!1,this[P]=null),this[B]=!!e.async,this[et]=this[P]?new ni(this[P]):null,e&&e.debugExposeBuffer===!0&&Object.defineProperty(this,"buffer",{get:()=>this[C]}),e&&e.debugExposePipes===!0&&Object.defineProperty(this,"pipes",{get:()=>this[F]});let{signal:s}=e;s&&(this[pt]=s,s.aborted?this[Qt]():s.addEventListener("abort",()=>this[Qt]()))}get bufferLength(){return this[T]}get encoding(){return this[P]}set encoding(t){throw new Error("Encoding must be set at instantiation time")}setEncoding(t){throw new Error("Encoding must be set at instantiation time")}get objectMode(){return this[k]}set objectMode(t){throw new Error("objectMode must be set at instantiation time")}get async(){return this[B]}set async(t){this[B]=this[B]||!!t}[Qt](){this[Dt]=!0,this.emit("abort",this[pt]?.reason),this.destroy(this[pt]?.reason)}get aborted(){return this[Dt]}set aborted(t){}write(t,e,s){if(this[Dt])return!1;if(this[G])throw new Error("write after end");if(this[x])return this.emit("error",Object.assign(new Error("Cannot call write after a stream was destroyed"),{code:"ERR_STREAM_DESTROYED"})),!0;typeof e=="function"&&(s=e,e="utf8"),e||(e="utf8");let i=this[B]?mt:li;if(!this[k]&&!Buffer.isBuffer(t)){if(ui(t))t=Buffer.from(t.buffer,t.byteOffset,t.byteLength);else if(fi(t))t=Buffer.from(t);else if(typeof t!="string")throw new Error("Non-contiguous data written to non-objectMode stream")}return this[k]?(this[v]&&this[T]!==0&&this[Ot](!0),this[v]?this.emit("data",t):this[Yt](t),this[T]!==0&&this.emit("readable"),s&&i(s),this[v]):t.length?(typeof t=="string"&&!(e===this[P]&&!this[et]?.lastNeed)&&(t=Buffer.from(t,e)),Buffer.isBuffer(t)&&this[P]&&(t=this[et].write(t)),this[v]&&this[T]!==0&&this[Ot](!0),this[v]?this.emit("data",t):this[Yt](t),this[T]!==0&&this.emit("readable"),s&&i(s),this[v]):(this[T]!==0&&this.emit("readable"),s&&i(s),this[v])}read(t){if(this[x])return null;if(this[M]=!1,this[T]===0||t===0||t&&t>this[T])return this[H](),null;this[k]&&(t=null),this[C].length>1&&!this[k]&&(this[C]=[this[P]?this[C].join(""):Buffer.concat(this[C],this[T])]);let e=this[_e](t||null,this[C][0]);return this[H](),e}[_e](t,e){if(this[k])this[Ft]();else{let s=e;t===s.length||t===null?this[Ft]():typeof s=="string"?(this[C][0]=s.slice(t),e=s.slice(0,t),this[T]-=t):(this[C][0]=s.subarray(t),e=s.subarray(0,t),this[T]-=t)}return this.emit("data",e),!this[C].length&&!this[G]&&this.emit("drain"),e}end(t,e,s){return typeof t=="function"&&(s=t,t=void 0),typeof e=="function"&&(s=e,e="utf8"),t!==void 0&&this.write(t,e),s&&this.once("end",s),this[G]=!0,this.writable=!1,(this[v]||!this[dt])&&this[H](),this}[st](){this[x]||(!this[Y]&&!this[F].length&&(this[M]=!0),this[dt]=!1,this[v]=!0,this.emit("resume"),this[C].length?this[Ot]():this[G]?this[H]():this.emit("drain"))}resume(){return this[st]()}pause(){this[v]=!1,this[dt]=!0,this[M]=!1}get destroyed(){return this[x]}get flowing(){return this[v]}get paused(){return this[dt]}[Yt](t){this[k]?this[T]+=1:this[T]+=t.length,this[C].push(t)}[Ft](){return this[k]?this[T]-=1:this[T]-=this[C][0].length,this[C].shift()}[Ot](t=!1){do;while(this[Le](this[Ft]())&&this[C].length);!t&&!this[C].length&&!this[G]&&this.emit("drain")}[Le](t){return this.emit("data",t),this[v]}pipe(t,e){if(this[x])return t;this[M]=!1;let s=this[K];return e=e||{},t===Ne.stdout||t===Ne.stderr?e.end=!1:e.end=e.end!==!1,e.proxyErrors=!!e.proxyErrors,s?e.end&&t.end():(this[F].push(e.proxyErrors?new te(this,t,e):new Mt(this,t,e)),this[B]?mt(()=>this[st]()):this[st]()),t}unpipe(t){let e=this[F].find(s=>s.dest===t);e&&(this[F].length===1?(this[v]&&this[Y]===0&&(this[v]=!1),this[F]=[]):this[F].splice(this[F].indexOf(e),1),e.unpipe())}addListener(t,e){return this.on(t,e)}on(t,e){let s=super.on(t,e);if(t==="data")this[M]=!1,this[Y]++,!this[F].length&&!this[v]&&this[st]();else if(t==="readable"&&this[T]!==0)super.emit("readable");else if(ci(t)&&this[K])super.emit(t),this.removeAllListeners(t);else if(t==="error"&&this[ut]){let i=e;this[B]?mt(()=>i.call(this,this[ut])):i.call(this,this[ut])}return s}removeListener(t,e){return this.off(t,e)}off(t,e){let s=super.off(t,e);return t==="data"&&(this[Y]=this.listeners("data").length,this[Y]===0&&!this[M]&&!this[F].length&&(this[v]=!1)),s}removeAllListeners(t){let e=super.removeAllListeners(t);return(t==="data"||t===void 0)&&(this[Y]=0,!this[M]&&!this[F].length&&(this[v]=!1)),e}get emittedEnd(){return this[K]}[H](){!this[kt]&&!this[K]&&!this[x]&&this[C].length===0&&this[G]&&(this[kt]=!0,this.emit("end"),this.emit("prefinish"),this.emit("finish"),this[Rt]&&this.emit("close"),this[kt]=!1)}emit(t,...e){let s=e[0];if(t!=="error"&&t!=="close"&&t!==x&&this[x])return!1;if(t==="data")return!this[k]&&!s?!1:this[B]?(mt(()=>this[Jt](s)),!0):this[Jt](s);if(t==="end")return this[We]();if(t==="close"){if(this[Rt]=!0,!this[K]&&!this[x])return!1;let r=super.emit("close");return this.removeAllListeners("close"),r}else if(t==="error"){this[ut]=s,super.emit(Xt,s);let r=!this[pt]||this.listeners("error").length?super.emit("error",s):!1;return this[H](),r}else if(t==="resume"){let r=super.emit("resume");return this[H](),r}else if(t==="finish"||t==="prefinish"){let r=super.emit(t);return this.removeAllListeners(t),r}let i=super.emit(t,...e);return this[H](),i}[Jt](t){for(let s of this[F])s.dest.write(t)===!1&&this.pause();let e=this[M]?!1:super.emit("data",t);return this[H](),e}[We](){return this[K]?!1:(this[K]=!0,this.readable=!1,this[B]?(mt(()=>this[Zt]()),!0):this[Zt]())}[Zt](){if(this[et]){let e=this[et].end();if(e){for(let s of this[F])s.dest.write(e);this[M]||super.emit("data",e)}}for(let e of this[F])e.end();let t=super.emit("end");return this.removeAllListeners("end"),t}async collect(){let t=Object.assign([],{dataLength:0});this[k]||(t.dataLength=0);let e=this.promise();return this.on("data",s=>{t.push(s),this[k]||(t.dataLength+=s.length)}),await e,t}async concat(){if(this[k])throw new Error("cannot concat in objectMode");let t=await this.collect();return this[P]?t.join(""):Buffer.concat(t,t.dataLength)}async promise(){return new Promise((t,e)=>{this.on(x,()=>e(new Error("stream destroyed"))),this.on("error",s=>e(s)),this.on("end",()=>t())})}[Symbol.asyncIterator](){this[M]=!1;let t=!1,e=async()=>(this.pause(),t=!0,{value:void 0,done:!0});return{next:()=>{if(t)return e();let i=this.read();if(i!==null)return Promise.resolve({done:!1,value:i});if(this[G])return e();let r,o,h=c=>{this.off("data",a),this.off("end",l),this.off(x,u),e(),o(c)},a=c=>{this.off("error",h),this.off("end",l),this.off(x,u),this.pause(),r({value:c,done:!!this[G]})},l=()=>{this.off("error",h),this.off("data",a),this.off(x,u),e(),r({done:!0,value:void 0})},u=()=>h(new Error("stream destroyed"));return new Promise((c,d)=>{o=d,r=c,this.once(x,u),this.once("error",h),this.once("end",l),this.once("data",a)})},throw:e,return:e,[Symbol.asyncIterator](){return this},[Symbol.asyncDispose]:async()=>{}}}[Symbol.iterator](){this[M]=!1;let t=!1,e=()=>(this.pause(),this.off(Xt,e),this.off(x,e),this.off("end",e),t=!0,{done:!0,value:void 0}),s=()=>{if(t)return e();let i=this.read();return i===null?e():{done:!1,value:i}};return this.once("end",e),this.once(Xt,e),this.once(x,e),{next:s,throw:e,return:e,[Symbol.iterator](){return this},[Symbol.dispose]:()=>{}}}destroy(t){if(this[x])return t?this.emit("error",t):this.emit(x),this;this[x]=!0,this[M]=!0,this[C].length=0,this[T]=0;let e=this;return typeof e.close=="function"&&!this[Rt]&&e.close(),t?this.emit("error",t):this.emit(x),this}static get isStream(){return oi}},vi=Ei.native,wt={lstatSync:wi,readdir:yi,readdirSync:bi,readlinkSync:Si,realpathSync:vi,promises:{lstat:Ci,readdir:Ti,readlink:Ai,realpath:ki}},Ue=n7=>!n7||n7===wt||n7===xi?wt:{...wt,...n7,promises:{...wt.promises,...n7.promises||{}}},$e=/^\\\\\?\\([a-z]:)\\?$/i,Ri=n7=>n7.replace(/\//g,"\\").replace($e,"$1\\"),Oi=/[\\\/]/,L=0,Ge=1,He=2,U=4,qe=6,Ke=8,X=10,Ve=12,_=15,gt=~_,se=16,je=32,yt=64,j=128,Nt=256,Lt=512,Ie=yt|j|Lt,Fi=1023,ie=n7=>n7.isFile()?Ke:n7.isDirectory()?U:n7.isSymbolicLink()?X:n7.isCharacterDevice()?He:n7.isBlockDevice()?qe:n7.isSocket()?Ve:n7.isFIFO()?Ge:L,ze=new ft({max:2**12}),bt=n7=>{let t=ze.get(n7);if(t)return t;let e=n7.normalize("NFKD");return ze.set(n7,e),e},Be=new ft({max:2**12}),_t=n7=>{let t=Be.get(n7);if(t)return t;let e=bt(n7.toLowerCase());return Be.set(n7,e),e},Wt=class extends ft{constructor(){super({max:256})}},ne=class extends ft{constructor(t=16*1024){super({maxSize:t,sizeCalculation:e=>e.length+1})}},Ye=Symbol("PathScurry setAsCwd"),R=class{name;root;roots;parent;nocase;isCWD=!1;#t;#s;get dev(){return this.#s}#n;get mode(){return this.#n}#r;get nlink(){return this.#r}#o;get uid(){return this.#o}#S;get gid(){return this.#S}#w;get rdev(){return this.#w}#c;get blksize(){return this.#c}#h;get ino(){return this.#h}#u;get size(){return this.#u}#f;get blocks(){return this.#f}#a;get atimeMs(){return this.#a}#i;get mtimeMs(){return this.#i}#d;get ctimeMs(){return this.#d}#E;get birthtimeMs(){return this.#E}#b;get atime(){return this.#b}#p;get mtime(){return this.#p}#R;get ctime(){return this.#R}#m;get birthtime(){return this.#m}#C;#T;#g;#y;#x;#A;#e;#_;#M;#k;get parentPath(){return(this.parent||this).fullpath()}get path(){return this.parentPath}constructor(t,e=L,s,i,r,o,h){this.name=t,this.#C=r?_t(t):bt(t),this.#e=e&Fi,this.nocase=r,this.roots=i,this.root=s||this,this.#_=o,this.#g=h.fullpath,this.#x=h.relative,this.#A=h.relativePosix,this.parent=h.parent,this.parent?this.#t=this.parent.#t:this.#t=Ue(h.fs)}depth(){return this.#T!==void 0?this.#T:this.parent?this.#T=this.parent.depth()+1:this.#T=0}childrenCache(){return this.#_}resolve(t){if(!t)return this;let e=this.getRootString(t),i=t.substring(e.length).split(this.splitSep);return e?this.getRoot(e).#N(i):this.#N(i)}#N(t){let e=this;for(let s of t)e=e.child(s);return e}children(){let t=this.#_.get(this);if(t)return t;let e=Object.assign([],{provisional:0});return this.#_.set(this,e),this.#e&=~se,e}child(t,e){if(t===""||t===".")return this;if(t==="..")return this.parent||this;let s=this.children(),i=this.nocase?_t(t):bt(t);for(let a of s)if(a.#C===i)return a;let r=this.parent?this.sep:"",o=this.#g?this.#g+r+t:void 0,h=this.newChild(t,L,{...e,parent:this,fullpath:o});return this.canReaddir()||(h.#e|=j),s.push(h),h}relative(){if(this.isCWD)return"";if(this.#x!==void 0)return this.#x;let t=this.name,e=this.parent;if(!e)return this.#x=this.name;let s=e.relative();return s+(!s||!e.parent?"":this.sep)+t}relativePosix(){if(this.sep==="/")return this.relative();if(this.isCWD)return"";if(this.#A!==void 0)return this.#A;let t=this.name,e=this.parent;if(!e)return this.#A=this.fullpathPosix();let s=e.relativePosix();return s+(!s||!e.parent?"":"/")+t}fullpath(){if(this.#g!==void 0)return this.#g;let t=this.name,e=this.parent;if(!e)return this.#g=this.name;let i=e.fullpath()+(e.parent?this.sep:"")+t;return this.#g=i}fullpathPosix(){if(this.#y!==void 0)return this.#y;if(this.sep==="/")return this.#y=this.fullpath();if(!this.parent){let i=this.fullpath().replace(/\\/g,"/");return/^[a-z]:\//i.test(i)?this.#y=`//?/${i}`:this.#y=i}let t=this.parent,e=t.fullpathPosix(),s=e+(!e||!t.parent?"":"/")+this.name;return this.#y=s}isUnknown(){return(this.#e&_)===L}isType(t){return this[`is${t}`]()}getType(){return this.isUnknown()?"Unknown":this.isDirectory()?"Directory":this.isFile()?"File":this.isSymbolicLink()?"SymbolicLink":this.isFIFO()?"FIFO":this.isCharacterDevice()?"CharacterDevice":this.isBlockDevice()?"BlockDevice":this.isSocket()?"Socket":"Unknown"}isFile(){return(this.#e&_)===Ke}isDirectory(){return(this.#e&_)===U}isCharacterDevice(){return(this.#e&_)===He}isBlockDevice(){return(this.#e&_)===qe}isFIFO(){return(this.#e&_)===Ge}isSocket(){return(this.#e&_)===Ve}isSymbolicLink(){return(this.#e&X)===X}lstatCached(){return this.#e&je?this:void 0}readlinkCached(){return this.#M}realpathCached(){return this.#k}readdirCached(){let t=this.children();return t.slice(0,t.provisional)}canReadlink(){if(this.#M)return!0;if(!this.parent)return!1;let t=this.#e&_;return!(t!==L&&t!==X||this.#e&Nt||this.#e&j)}calledReaddir(){return!!(this.#e&se)}isENOENT(){return!!(this.#e&j)}isNamed(t){return this.nocase?this.#C===_t(t):this.#C===bt(t)}async readlink(){let t=this.#M;if(t)return t;if(this.canReadlink()&&this.parent)try{let e=await this.#t.promises.readlink(this.fullpath()),s=(await this.parent.realpath())?.resolve(e);if(s)return this.#M=s}catch(e){this.#D(e.code);return}}readlinkSync(){let t=this.#M;if(t)return t;if(this.canReadlink()&&this.parent)try{let e=this.#t.readlinkSync(this.fullpath()),s=this.parent.realpathSync()?.resolve(e);if(s)return this.#M=s}catch(e){this.#D(e.code);return}}#j(t){this.#e|=se;for(let e=t.provisional;e<t.length;e++){let s=t[e];s&&s.#v()}}#v(){this.#e&j||(this.#e=(this.#e|j)&gt,this.#G())}#G(){let t=this.children();t.provisional=0;for(let e of t)e.#v()}#P(){this.#e|=Lt,this.#L()}#L(){if(this.#e&yt)return;let t=this.#e;(t&_)===U&&(t&=gt),this.#e=t|yt,this.#G()}#I(t=""){t==="ENOTDIR"||t==="EPERM"?this.#L():t==="ENOENT"?this.#v():this.children().provisional=0}#F(t=""){t==="ENOTDIR"?this.parent.#L():t==="ENOENT"&&this.#v()}#D(t=""){let e=this.#e;e|=Nt,t==="ENOENT"&&(e|=j),(t==="EINVAL"||t==="UNKNOWN")&&(e&=gt),this.#e=e,t==="ENOTDIR"&&this.parent&&this.parent.#L()}#z(t,e){return this.#U(t,e)||this.#B(t,e)}#B(t,e){let s=ie(t),i=this.newChild(t.name,s,{parent:this}),r=i.#e&_;return r!==U&&r!==X&&r!==L&&(i.#e|=yt),e.unshift(i),e.provisional++,i}#U(t,e){for(let s=e.provisional;s<e.length;s++){let i=e[s];if((this.nocase?_t(t.name):bt(t.name))===i.#C)return this.#l(t,i,s,e)}}#l(t,e,s,i){let r=e.name;return e.#e=e.#e&gt|ie(t),r!==t.name&&(e.name=t.name),s!==i.provisional&&(s===i.length-1?i.pop():i.splice(s,1),i.unshift(e)),i.provisional++,e}async lstat(){if((this.#e&j)===0)try{return this.#$(await this.#t.promises.lstat(this.fullpath())),this}catch(t){this.#F(t.code)}}lstatSync(){if((this.#e&j)===0)try{return this.#$(this.#t.lstatSync(this.fullpath())),this}catch(t){this.#F(t.code)}}#$(t){let{atime:e,atimeMs:s,birthtime:i,birthtimeMs:r,blksize:o,blocks:h,ctime:a,ctimeMs:l,dev:u,gid:c,ino:d,mode:f,mtime:m,mtimeMs:p,nlink:w,rdev:g,size:S,uid:E}=t;this.#b=e,this.#a=s,this.#m=i,this.#E=r,this.#c=o,this.#f=h,this.#R=a,this.#d=l,this.#s=u,this.#S=c,this.#h=d,this.#n=f,this.#p=m,this.#i=p,this.#r=w,this.#w=g,this.#u=S,this.#o=E;let y=ie(t);this.#e=this.#e&gt|y|je,y!==L&&y!==U&&y!==X&&(this.#e|=yt)}#W=[];#O=!1;#H(t){this.#O=!1;let e=this.#W.slice();this.#W.length=0,e.forEach(s=>s(null,t))}readdirCB(t,e=!1){if(!this.canReaddir()){e?t(null,[]):queueMicrotask(()=>t(null,[]));return}let s=this.children();if(this.calledReaddir()){let r=s.slice(0,s.provisional);e?t(null,r):queueMicrotask(()=>t(null,r));return}if(this.#W.push(t),this.#O)return;this.#O=!0;let i=this.fullpath();this.#t.readdir(i,{withFileTypes:!0},(r,o)=>{if(r)this.#I(r.code),s.provisional=0;else{for(let h of o)this.#z(h,s);this.#j(s)}this.#H(s.slice(0,s.provisional))})}#q;async readdir(){if(!this.canReaddir())return[];let t=this.children();if(this.calledReaddir())return t.slice(0,t.provisional);let e=this.fullpath();if(this.#q)await this.#q;else{let s=()=>{};this.#q=new Promise(i=>s=i);try{for(let i of await this.#t.promises.readdir(e,{withFileTypes:!0}))this.#z(i,t);this.#j(t)}catch(i){this.#I(i.code),t.provisional=0}this.#q=void 0,s()}return t.slice(0,t.provisional)}readdirSync(){if(!this.canReaddir())return[];let t=this.children();if(this.calledReaddir())return t.slice(0,t.provisional);let e=this.fullpath();try{for(let s of this.#t.readdirSync(e,{withFileTypes:!0}))this.#z(s,t);this.#j(t)}catch(s){this.#I(s.code),t.provisional=0}return t.slice(0,t.provisional)}canReaddir(){if(this.#e&Ie)return!1;let t=_&this.#e;return t===L||t===U||t===X}shouldWalk(t,e){return(this.#e&U)===U&&!(this.#e&Ie)&&!t.has(this)&&(!e||e(this))}async realpath(){if(this.#k)return this.#k;if(!((Lt|Nt|j)&this.#e))try{let t=await this.#t.promises.realpath(this.fullpath());return this.#k=this.resolve(t)}catch{this.#P()}}realpathSync(){if(this.#k)return this.#k;if(!((Lt|Nt|j)&this.#e))try{let t=this.#t.realpathSync(this.fullpath());return this.#k=this.resolve(t)}catch{this.#P()}}[Ye](t){if(t===this)return;t.isCWD=!1,this.isCWD=!0;let e=new Set([]),s=[],i=this;for(;i&&i.parent;)e.add(i),i.#x=s.join(this.sep),i.#A=s.join("/"),i=i.parent,s.push("..");for(i=t;i&&i.parent&&!e.has(i);)i.#x=void 0,i.#A=void 0,i=i.parent}},Pt=class n2 extends R{sep="\\";splitSep=Oi;constructor(t,e=L,s,i,r,o,h){super(t,e,s,i,r,o,h)}newChild(t,e=L,s={}){return new n2(t,e,this.root,this.roots,this.nocase,this.childrenCache(),s)}getRootString(t){return re.parse(t).root}getRoot(t){if(t=Ri(t.toUpperCase()),t===this.root.name)return this.root;for(let[e,s]of Object.entries(this.roots))if(this.sameRoot(t,e))return this.roots[t]=s;return this.roots[t]=new it(t,this).root}sameRoot(t,e=this.root.name){return t=t.toUpperCase().replace(/\//g,"\\").replace($e,"$1\\"),t===e}},jt=class n3 extends R{splitSep="/";sep="/";constructor(t,e=L,s,i,r,o,h){super(t,e,s,i,r,o,h)}getRootString(t){return t.startsWith("/")?"/":""}getRoot(t){return this.root}newChild(t,e=L,s={}){return new n3(t,e,this.root,this.roots,this.nocase,this.childrenCache(),s)}},It=class{root;rootPath;roots;cwd;#t;#s;#n;nocase;#r;constructor(t=process.cwd(),e,s,{nocase:i,childrenCacheSize:r=16*1024,fs:o=wt}={}){this.#r=Ue(o),(t instanceof URL||t.startsWith("file://"))&&(t=gi(t));let h=e.resolve(t);this.roots=Object.create(null),this.rootPath=this.parseRootPath(h),this.#t=new Wt,this.#s=new Wt,this.#n=new ne(r);let a=h.substring(this.rootPath.length).split(s);if(a.length===1&&!a[0]&&a.pop(),i===void 0)throw new TypeError("must provide nocase setting to PathScurryBase ctor");this.nocase=i,this.root=this.newRoot(this.#r),this.roots[this.rootPath]=this.root;let l=this.root,u=a.length-1,c=e.sep,d=this.rootPath,f=!1;for(let m of a){let p=u--;l=l.child(m,{relative:new Array(p).fill("..").join(c),relativePosix:new Array(p).fill("..").join("/"),fullpath:d+=(f?"":c)+m}),f=!0}this.cwd=l}depth(t=this.cwd){return typeof t=="string"&&(t=this.cwd.resolve(t)),t.depth()}childrenCache(){return this.#n}resolve(...t){let e="";for(let r=t.length-1;r>=0;r--){let o=t[r];if(!(!o||o===".")&&(e=e?`${o}/${e}`:o,this.isAbsolute(o)))break}let s=this.#t.get(e);if(s!==void 0)return s;let i=this.cwd.resolve(e).fullpath();return this.#t.set(e,i),i}resolvePosix(...t){let e="";for(let r=t.length-1;r>=0;r--){let o=t[r];if(!(!o||o===".")&&(e=e?`${o}/${e}`:o,this.isAbsolute(o)))break}let s=this.#s.get(e);if(s!==void 0)return s;let i=this.cwd.resolve(e).fullpathPosix();return this.#s.set(e,i),i}relative(t=this.cwd){return typeof t=="string"&&(t=this.cwd.resolve(t)),t.relative()}relativePosix(t=this.cwd){return typeof t=="string"&&(t=this.cwd.resolve(t)),t.relativePosix()}basename(t=this.cwd){return typeof t=="string"&&(t=this.cwd.resolve(t)),t.name}dirname(t=this.cwd){return typeof t=="string"&&(t=this.cwd.resolve(t)),(t.parent||t).fullpath()}async readdir(t=this.cwd,e={withFileTypes:!0}){typeof t=="string"?t=this.cwd.resolve(t):t instanceof R||(e=t,t=this.cwd);let{withFileTypes:s}=e;if(t.canReaddir()){let i=await t.readdir();return s?i:i.map(r=>r.name)}else return[]}readdirSync(t=this.cwd,e={withFileTypes:!0}){typeof t=="string"?t=this.cwd.resolve(t):t instanceof R||(e=t,t=this.cwd);let{withFileTypes:s=!0}=e;return t.canReaddir()?s?t.readdirSync():t.readdirSync().map(i=>i.name):[]}async lstat(t=this.cwd){return typeof t=="string"&&(t=this.cwd.resolve(t)),t.lstat()}lstatSync(t=this.cwd){return typeof t=="string"&&(t=this.cwd.resolve(t)),t.lstatSync()}async readlink(t=this.cwd,{withFileTypes:e}={withFileTypes:!1}){typeof t=="string"?t=this.cwd.resolve(t):t instanceof R||(e=t.withFileTypes,t=this.cwd);let s=await t.readlink();return e?s:s?.fullpath()}readlinkSync(t=this.cwd,{withFileTypes:e}={withFileTypes:!1}){typeof t=="string"?t=this.cwd.resolve(t):t instanceof R||(e=t.withFileTypes,t=this.cwd);let s=t.readlinkSync();return e?s:s?.fullpath()}async realpath(t=this.cwd,{withFileTypes:e}={withFileTypes:!1}){typeof t=="string"?t=this.cwd.resolve(t):t instanceof R||(e=t.withFileTypes,t=this.cwd);let s=await t.realpath();return e?s:s?.fullpath()}realpathSync(t=this.cwd,{withFileTypes:e}={withFileTypes:!1}){typeof t=="string"?t=this.cwd.resolve(t):t instanceof R||(e=t.withFileTypes,t=this.cwd);let s=t.realpathSync();return e?s:s?.fullpath()}async walk(t=this.cwd,e={}){typeof t=="string"?t=this.cwd.resolve(t):t instanceof R||(e=t,t=this.cwd);let{withFileTypes:s=!0,follow:i=!1,filter:r,walkFilter:o}=e,h=[];(!r||r(t))&&h.push(s?t:t.fullpath());let a=new Set,l=(c,d)=>{a.add(c),c.readdirCB((f,m)=>{if(f)return d(f);let p=m.length;if(!p)return d();let w=()=>{--p===0&&d()};for(let g of m)(!r||r(g))&&h.push(s?g:g.fullpath()),i&&g.isSymbolicLink()?g.realpath().then(S=>S?.isUnknown()?S.lstat():S).then(S=>S?.shouldWalk(a,o)?l(S,w):w()):g.shouldWalk(a,o)?l(g,w):w()},!0)},u=t;return new Promise((c,d)=>{l(u,f=>{if(f)return d(f);c(h)})})}walkSync(t=this.cwd,e={}){typeof t=="string"?t=this.cwd.resolve(t):t instanceof R||(e=t,t=this.cwd);let{withFileTypes:s=!0,follow:i=!1,filter:r,walkFilter:o}=e,h=[];(!r||r(t))&&h.push(s?t:t.fullpath());let a=new Set([t]);for(let l of a){let u=l.readdirSync();for(let c of u){(!r||r(c))&&h.push(s?c:c.fullpath());let d=c;if(c.isSymbolicLink()){if(!(i&&(d=c.realpathSync())))continue;d.isUnknown()&&d.lstatSync()}d.shouldWalk(a,o)&&a.add(d)}}return h}[Symbol.asyncIterator](){return this.iterate()}iterate(t=this.cwd,e={}){return typeof t=="string"?t=this.cwd.resolve(t):t instanceof R||(e=t,t=this.cwd),this.stream(t,e)[Symbol.asyncIterator]()}[Symbol.iterator](){return this.iterateSync()}*iterateSync(t=this.cwd,e={}){typeof t=="string"?t=this.cwd.resolve(t):t instanceof R||(e=t,t=this.cwd);let{withFileTypes:s=!0,follow:i=!1,filter:r,walkFilter:o}=e;(!r||r(t))&&(yield s?t:t.fullpath());let h=new Set([t]);for(let a of h){let l=a.readdirSync();for(let u of l){(!r||r(u))&&(yield s?u:u.fullpath());let c=u;if(u.isSymbolicLink()){if(!(i&&(c=u.realpathSync())))continue;c.isUnknown()&&c.lstatSync()}c.shouldWalk(h,o)&&h.add(c)}}}stream(t=this.cwd,e={}){typeof t=="string"?t=this.cwd.resolve(t):t instanceof R||(e=t,t=this.cwd);let{withFileTypes:s=!0,follow:i=!1,filter:r,walkFilter:o}=e,h=new V({objectMode:!0});(!r||r(t))&&h.write(s?t:t.fullpath());let a=new Set,l=[t],u=0,c=()=>{let d=!1;for(;!d;){let f=l.shift();if(!f){u===0&&h.end();return}u++,a.add(f);let m=(w,g,S=!1)=>{if(w)return h.emit("error",w);if(i&&!S){let E=[];for(let y of g)y.isSymbolicLink()&&E.push(y.realpath().then(b=>b?.isUnknown()?b.lstat():b));if(E.length){Promise.all(E).then(()=>m(null,g,!0));return}}for(let E of g)E&&(!r||r(E))&&(h.write(s?E:E.fullpath())||(d=!0));u--;for(let E of g){let y=E.realpathCached()||E;y.shouldWalk(a,o)&&l.push(y)}d&&!h.flowing?h.once("drain",c):p||c()},p=!0;f.readdirCB(m,!0),p=!1}};return c(),h}streamSync(t=this.cwd,e={}){typeof t=="string"?t=this.cwd.resolve(t):t instanceof R||(e=t,t=this.cwd);let{withFileTypes:s=!0,follow:i=!1,filter:r,walkFilter:o}=e,h=new V({objectMode:!0}),a=new Set;(!r||r(t))&&h.write(s?t:t.fullpath());let l=[t],u=0,c=()=>{let d=!1;for(;!d;){let f=l.shift();if(!f){u===0&&h.end();return}u++,a.add(f);let m=f.readdirSync();for(let p of m)(!r||r(p))&&(h.write(s?p:p.fullpath())||(d=!0));u--;for(let p of m){let w=p;if(p.isSymbolicLink()){if(!(i&&(w=p.realpathSync())))continue;w.isUnknown()&&w.lstatSync()}w.shouldWalk(a,o)&&l.push(w)}}d&&!h.flowing&&h.once("drain",c)};return c(),h}chdir(t=this.cwd){let e=this.cwd;this.cwd=typeof t=="string"?this.cwd.resolve(t):t,this.cwd[Ye](e)}},it=class extends It{sep="\\";constructor(t=process.cwd(),e={}){let{nocase:s=!0}=e;super(t,re,"\\",{...e,nocase:s}),this.nocase=s;for(let i=this.cwd;i;i=i.parent)i.nocase=this.nocase}parseRootPath(t){return re.parse(t).root.toUpperCase()}newRoot(t){return new Pt(this.rootPath,U,void 0,this.roots,this.nocase,this.childrenCache(),{fs:t})}isAbsolute(t){return t.startsWith("/")||t.startsWith("\\")||/^[a-z]:(\/|\\)/i.test(t)}},rt=class extends It{sep="/";constructor(t=process.cwd(),e={}){let{nocase:s=!1}=e;super(t,mi,"/",{...e,nocase:s}),this.nocase=s}parseRootPath(t){return"/"}newRoot(t){return new jt(this.rootPath,U,void 0,this.roots,this.nocase,this.childrenCache(),{fs:t})}isAbsolute(t){return t.startsWith("/")}},St=class extends rt{constructor(t=process.cwd(),e={}){let{nocase:s=!0}=e;super(t,{...e,nocase:s})}},Cr=process.platform==="win32"?Pt:jt,Xe=process.platform==="win32"?it:process.platform==="darwin"?St:rt,Di=n7=>n7.length>=1,Mi=n7=>n7.length>=1,Ni=Symbol.for("nodejs.util.inspect.custom"),nt=class n4{#t;#s;#n;length;#r;#o;#S;#w;#c;#h;#u=!0;constructor(t,e,s,i){if(!Di(t))throw new TypeError("empty pattern list");if(!Mi(e))throw new TypeError("empty glob list");if(e.length!==t.length)throw new TypeError("mismatched pattern list and glob list lengths");if(this.length=t.length,s<0||s>=this.length)throw new TypeError("index out of range");if(this.#t=t,this.#s=e,this.#n=s,this.#r=i,this.#n===0){if(this.isUNC()){let[r,o,h,a,...l]=this.#t,[u,c,d,f,...m]=this.#s;l[0]===""&&(l.shift(),m.shift());let p=[r,o,h,a,""].join("/"),w=[u,c,d,f,""].join("/");this.#t=[p,...l],this.#s=[w,...m],this.length=this.#t.length}else if(this.isDrive()||this.isAbsolute()){let[r,...o]=this.#t,[h,...a]=this.#s;o[0]===""&&(o.shift(),a.shift());let l=r+"/",u=h+"/";this.#t=[l,...o],this.#s=[u,...a],this.length=this.#t.length}}}[Ni](){return"Pattern <"+this.#s.slice(this.#n).join("/")+">"}pattern(){return this.#t[this.#n]}isString(){return typeof this.#t[this.#n]=="string"}isGlobstar(){return this.#t[this.#n]===A}isRegExp(){return this.#t[this.#n]instanceof RegExp}globString(){return this.#S=this.#S||(this.#n===0?this.isAbsolute()?this.#s[0]+this.#s.slice(1).join("/"):this.#s.join("/"):this.#s.slice(this.#n).join("/"))}hasMore(){return this.length>this.#n+1}rest(){return this.#o!==void 0?this.#o:this.hasMore()?(this.#o=new n4(this.#t,this.#s,this.#n+1,this.#r),this.#o.#h=this.#h,this.#o.#c=this.#c,this.#o.#w=this.#w,this.#o):this.#o=null}isUNC(){let t=this.#t;return this.#c!==void 0?this.#c:this.#c=this.#r==="win32"&&this.#n===0&&t[0]===""&&t[1]===""&&typeof t[2]=="string"&&!!t[2]&&typeof t[3]=="string"&&!!t[3]}isDrive(){let t=this.#t;return this.#w!==void 0?this.#w:this.#w=this.#r==="win32"&&this.#n===0&&this.length>1&&typeof t[0]=="string"&&/^[a-z]:$/i.test(t[0])}isAbsolute(){let t=this.#t;return this.#h!==void 0?this.#h:this.#h=t[0]===""&&t.length>1||this.isDrive()||this.isUNC()}root(){let t=this.#t[0];return typeof t=="string"&&this.isAbsolute()&&this.#n===0?t:""}checkFollowGlobstar(){return!(this.#n===0||!this.isGlobstar()||!this.#u)}markFollowGlobstar(){return this.#n===0||!this.isGlobstar()||!this.#u?!1:(this.#u=!1,!0)}},_i=typeof process=="object"&&process&&typeof process.platform=="string"?process.platform:"linux",ot=class{relative;relativeChildren;absolute;absoluteChildren;platform;mmopts;constructor(t,{nobrace:e,nocase:s,noext:i,noglobstar:r,platform:o=_i}){this.relative=[],this.absolute=[],this.relativeChildren=[],this.absoluteChildren=[],this.platform=o,this.mmopts={dot:!0,nobrace:e,nocase:s,noext:i,noglobstar:r,optimizationLevel:2,platform:o,nocomment:!0,nonegate:!0};for(let h of t)this.add(h)}add(t){let e=new D(t,this.mmopts);for(let s=0;s<e.set.length;s++){let i=e.set[s],r=e.globParts[s];if(!i||!r)throw new Error("invalid pattern object");for(;i[0]==="."&&r[0]===".";)i.shift(),r.shift();let o=new nt(i,r,0,this.platform),h=new D(o.globString(),this.mmopts),a=r[r.length-1]==="**",l=o.isAbsolute();l?this.absolute.push(h):this.relative.push(h),a&&(l?this.absoluteChildren.push(h):this.relativeChildren.push(h))}}ignored(t){let e=t.fullpath(),s=`${e}/`,i=t.relative()||".",r=`${i}/`;for(let o of this.relative)if(o.match(i)||o.match(r))return!0;for(let o of this.absolute)if(o.match(e)||o.match(s))return!0;return!1}childrenIgnored(t){let e=t.fullpath()+"/",s=(t.relative()||".")+"/";for(let i of this.relativeChildren)if(i.match(s))return!0;for(let i of this.absoluteChildren)if(i.match(e))return!0;return!1}},oe=class n5{store;constructor(t=new Map){this.store=t}copy(){return new n5(new Map(this.store))}hasWalked(t,e){return this.store.get(t.fullpath())?.has(e.globString())}storeWalked(t,e){let s=t.fullpath(),i=this.store.get(s);i?i.add(e.globString()):this.store.set(s,new Set([e.globString()]))}},he=class{store=new Map;add(t,e,s){let i=(e?2:0)|(s?1:0),r=this.store.get(t);this.store.set(t,r===void 0?i:i&r)}entries(){return[...this.store.entries()].map(([t,e])=>[t,!!(e&2),!!(e&1)])}},ae=class{store=new Map;add(t,e){if(!t.canReaddir())return;let s=this.store.get(t);s?s.find(i=>i.globString()===e.globString())||s.push(e):this.store.set(t,[e])}get(t){let e=this.store.get(t);if(!e)throw new Error("attempting to walk unknown path");return e}entries(){return this.keys().map(t=>[t,this.store.get(t)])}keys(){return[...this.store.keys()].filter(t=>t.canReaddir())}},Et=class n6{hasWalkedCache;matches=new he;subwalks=new ae;patterns;follow;dot;opts;constructor(t,e){this.opts=t,this.follow=!!t.follow,this.dot=!!t.dot,this.hasWalkedCache=e?e.copy():new oe}processPatterns(t,e){this.patterns=e;let s=e.map(i=>[t,i]);for(let[i,r]of s){this.hasWalkedCache.storeWalked(i,r);let o=r.root(),h=r.isAbsolute()&&this.opts.absolute!==!1;if(o){i=i.resolve(o==="/"&&this.opts.root!==void 0?this.opts.root:o);let c=r.rest();if(c)r=c;else{this.matches.add(i,!0,!1);continue}}if(i.isENOENT())continue;let a,l,u=!1;for(;typeof(a=r.pattern())=="string"&&(l=r.rest());)i=i.resolve(a),r=l,u=!0;if(a=r.pattern(),l=r.rest(),u){if(this.hasWalkedCache.hasWalked(i,r))continue;this.hasWalkedCache.storeWalked(i,r)}if(typeof a=="string"){let c=a===".."||a===""||a===".";this.matches.add(i.resolve(a),h,c);continue}else if(a===A){(!i.isSymbolicLink()||this.follow||r.checkFollowGlobstar())&&this.subwalks.add(i,r);let c=l?.pattern(),d=l?.rest();if(!l||(c===""||c===".")&&!d)this.matches.add(i,h,c===""||c===".");else if(c===".."){let f=i.parent||i;d?this.hasWalkedCache.hasWalked(f,d)||this.subwalks.add(f,d):this.matches.add(f,h,!0)}}else a instanceof RegExp&&this.subwalks.add(i,r)}return this}subwalkTargets(){return this.subwalks.keys()}child(){return new n6(this.opts,this.hasWalkedCache)}filterEntries(t,e){let s=this.subwalks.get(t),i=this.child();for(let r of e)for(let o of s){let h=o.isAbsolute(),a=o.pattern(),l=o.rest();a===A?i.testGlobstar(r,o,l,h):a instanceof RegExp?i.testRegExp(r,a,l,h):i.testString(r,a,l,h)}return i}testGlobstar(t,e,s,i){if((this.dot||!t.name.startsWith("."))&&(e.hasMore()||this.matches.add(t,i,!1),t.canReaddir()&&(this.follow||!t.isSymbolicLink()?this.subwalks.add(t,e):t.isSymbolicLink()&&(s&&e.checkFollowGlobstar()?this.subwalks.add(t,s):e.markFollowGlobstar()&&this.subwalks.add(t,e)))),s){let r=s.pattern();if(typeof r=="string"&&r!==".."&&r!==""&&r!==".")this.testString(t,r,s.rest(),i);else if(r===".."){let o=t.parent||t;this.subwalks.add(o,s)}else r instanceof RegExp&&this.testRegExp(t,r,s.rest(),i)}}testRegExp(t,e,s,i){e.test(t.name)&&(s?this.subwalks.add(t,s):this.matches.add(t,i,!1))}testString(t,e,s,i){t.isNamed(e)&&(s?this.subwalks.add(t,s):this.matches.add(t,i,!1))}},Li=(n7,t)=>typeof n7=="string"?new ot([n7],t):Array.isArray(n7)?new ot(n7,t):n7,zt=class{path;patterns;opts;seen=new Set;paused=!1;aborted=!1;#t=[];#s;#n;signal;maxDepth;includeChildMatches;constructor(t,e,s){if(this.patterns=t,this.path=e,this.opts=s,this.#n=!s.posix&&s.platform==="win32"?"\\":"/",this.includeChildMatches=s.includeChildMatches!==!1,(s.ignore||!this.includeChildMatches)&&(this.#s=Li(s.ignore??[],s),!this.includeChildMatches&&typeof this.#s.add!="function")){let i="cannot ignore child matches, ignore lacks add() method.";throw new Error(i)}this.maxDepth=s.maxDepth||1/0,s.signal&&(this.signal=s.signal,this.signal.addEventListener("abort",()=>{this.#t.length=0}))}#r(t){return this.seen.has(t)||!!this.#s?.ignored?.(t)}#o(t){return!!this.#s?.childrenIgnored?.(t)}pause(){this.paused=!0}resume(){if(this.signal?.aborted)return;this.paused=!1;let t;for(;!this.paused&&(t=this.#t.shift());)t()}onResume(t){this.signal?.aborted||(this.paused?this.#t.push(t):t())}async matchCheck(t,e){if(e&&this.opts.nodir)return;let s;if(this.opts.realpath){if(s=t.realpathCached()||await t.realpath(),!s)return;t=s}let r=t.isUnknown()||this.opts.stat?await t.lstat():t;if(this.opts.follow&&this.opts.nodir&&r?.isSymbolicLink()){let o=await r.realpath();o&&(o.isUnknown()||this.opts.stat)&&await o.lstat()}return this.matchCheckTest(r,e)}matchCheckTest(t,e){return t&&(this.maxDepth===1/0||t.depth()<=this.maxDepth)&&(!e||t.canReaddir())&&(!this.opts.nodir||!t.isDirectory())&&(!this.opts.nodir||!this.opts.follow||!t.isSymbolicLink()||!t.realpathCached()?.isDirectory())&&!this.#r(t)?t:void 0}matchCheckSync(t,e){if(e&&this.opts.nodir)return;let s;if(this.opts.realpath){if(s=t.realpathCached()||t.realpathSync(),!s)return;t=s}let r=t.isUnknown()||this.opts.stat?t.lstatSync():t;if(this.opts.follow&&this.opts.nodir&&r?.isSymbolicLink()){let o=r.realpathSync();o&&(o?.isUnknown()||this.opts.stat)&&o.lstatSync()}return this.matchCheckTest(r,e)}matchFinish(t,e){if(this.#r(t))return;if(!this.includeChildMatches&&this.#s?.add){let r=`${t.relativePosix()}/**`;this.#s.add(r)}let s=this.opts.absolute===void 0?e:this.opts.absolute;this.seen.add(t);let i=this.opts.mark&&t.isDirectory()?this.#n:"";if(this.opts.withFileTypes)this.matchEmit(t);else if(s){let r=this.opts.posix?t.fullpathPosix():t.fullpath();this.matchEmit(r+i)}else{let r=this.opts.posix?t.relativePosix():t.relative(),o=this.opts.dotRelative&&!r.startsWith(".."+this.#n)?"."+this.#n:"";this.matchEmit(r?o+r+i:"."+i)}}async match(t,e,s){let i=await this.matchCheck(t,s);i&&this.matchFinish(i,e)}matchSync(t,e,s){let i=this.matchCheckSync(t,s);i&&this.matchFinish(i,e)}walkCB(t,e,s){this.signal?.aborted&&s(),this.walkCB2(t,e,new Et(this.opts),s)}walkCB2(t,e,s,i){if(this.#o(t))return i();if(this.signal?.aborted&&i(),this.paused){this.onResume(()=>this.walkCB2(t,e,s,i));return}s.processPatterns(t,e);let r=1,o=()=>{--r===0&&i()};for(let[h,a,l]of s.matches.entries())this.#r(h)||(r++,this.match(h,a,l).then(()=>o()));for(let h of s.subwalkTargets()){if(this.maxDepth!==1/0&&h.depth()>=this.maxDepth)continue;r++;let a=h.readdirCached();h.calledReaddir()?this.walkCB3(h,a,s,o):h.readdirCB((l,u)=>this.walkCB3(h,u,s,o),!0)}o()}walkCB3(t,e,s,i){s=s.filterEntries(t,e);let r=1,o=()=>{--r===0&&i()};for(let[h,a,l]of s.matches.entries())this.#r(h)||(r++,this.match(h,a,l).then(()=>o()));for(let[h,a]of s.subwalks.entries())r++,this.walkCB2(h,a,s.child(),o);o()}walkCBSync(t,e,s){this.signal?.aborted&&s(),this.walkCB2Sync(t,e,new Et(this.opts),s)}walkCB2Sync(t,e,s,i){if(this.#o(t))return i();if(this.signal?.aborted&&i(),this.paused){this.onResume(()=>this.walkCB2Sync(t,e,s,i));return}s.processPatterns(t,e);let r=1,o=()=>{--r===0&&i()};for(let[h,a,l]of s.matches.entries())this.#r(h)||this.matchSync(h,a,l);for(let h of s.subwalkTargets()){if(this.maxDepth!==1/0&&h.depth()>=this.maxDepth)continue;r++;let a=h.readdirSync();this.walkCB3Sync(h,a,s,o)}o()}walkCB3Sync(t,e,s,i){s=s.filterEntries(t,e);let r=1,o=()=>{--r===0&&i()};for(let[h,a,l]of s.matches.entries())this.#r(h)||this.matchSync(h,a,l);for(let[h,a]of s.subwalks.entries())r++,this.walkCB2Sync(h,a,s.child(),o);o()}},xt=class extends zt{matches=new Set;constructor(t,e,s){super(t,e,s)}matchEmit(t){this.matches.add(t)}async walk(){if(this.signal?.aborted)throw this.signal.reason;return this.path.isUnknown()&&await this.path.lstat(),await new Promise((t,e)=>{this.walkCB(this.path,this.patterns,()=>{this.signal?.aborted?e(this.signal.reason):t(this.matches)})}),this.matches}walkSync(){if(this.signal?.aborted)throw this.signal.reason;return this.path.isUnknown()&&this.path.lstatSync(),this.walkCBSync(this.path,this.patterns,()=>{if(this.signal?.aborted)throw this.signal.reason}),this.matches}},vt=class extends zt{results;constructor(t,e,s){super(t,e,s),this.results=new V({signal:this.signal,objectMode:!0}),this.results.on("drain",()=>this.resume()),this.results.on("resume",()=>this.resume())}matchEmit(t){this.results.write(t),this.results.flowing||this.pause()}stream(){let t=this.path;return t.isUnknown()?t.lstat().then(()=>{this.walkCB(t,this.patterns,()=>this.results.end())}):this.walkCB(t,this.patterns,()=>this.results.end()),this.results}streamSync(){return this.path.isUnknown()&&this.path.lstatSync(),this.walkCBSync(this.path,this.patterns,()=>this.results.end()),this.results}},Pi=typeof process=="object"&&process&&typeof process.platform=="string"?process.platform:"linux",I=class{absolute;cwd;root;dot;dotRelative;follow;ignore;magicalBraces;mark;matchBase;maxDepth;nobrace;nocase;nodir;noext;noglobstar;pattern;platform;realpath;scurry;stat;signal;windowsPathsNoEscape;withFileTypes;includeChildMatches;opts;patterns;constructor(t,e){if(!e)throw new TypeError("glob options required");if(this.withFileTypes=!!e.withFileTypes,this.signal=e.signal,this.follow=!!e.follow,this.dot=!!e.dot,this.dotRelative=!!e.dotRelative,this.nodir=!!e.nodir,this.mark=!!e.mark,e.cwd?(e.cwd instanceof URL||e.cwd.startsWith("file://"))&&(e.cwd=Wi(e.cwd)):this.cwd="",this.cwd=e.cwd||"",this.root=e.root,this.magicalBraces=!!e.magicalBraces,this.nobrace=!!e.nobrace,this.noext=!!e.noext,this.realpath=!!e.realpath,this.absolute=e.absolute,this.includeChildMatches=e.includeChildMatches!==!1,this.noglobstar=!!e.noglobstar,this.matchBase=!!e.matchBase,this.maxDepth=typeof e.maxDepth=="number"?e.maxDepth:1/0,this.stat=!!e.stat,this.ignore=e.ignore,this.withFileTypes&&this.absolute!==void 0)throw new Error("cannot set absolute and withFileTypes:true");if(typeof t=="string"&&(t=[t]),this.windowsPathsNoEscape=!!e.windowsPathsNoEscape||e.allowWindowsEscape===!1,this.windowsPathsNoEscape&&(t=t.map(a=>a.replace(/\\/g,"/"))),this.matchBase){if(e.noglobstar)throw new TypeError("base matching requires globstar");t=t.map(a=>a.includes("/")?a:`./**/${a}`)}if(this.pattern=t,this.platform=e.platform||Pi,this.opts={...e,platform:this.platform},e.scurry){if(this.scurry=e.scurry,e.nocase!==void 0&&e.nocase!==e.scurry.nocase)throw new Error("nocase option contradicts provided scurry option")}else{let a=e.platform==="win32"?it:e.platform==="darwin"?St:e.platform?rt:Xe;this.scurry=new a(this.cwd,{nocase:e.nocase,fs:e.fs})}this.nocase=this.scurry.nocase;let s=this.platform==="darwin"||this.platform==="win32",i={braceExpandMax:1e4,...e,dot:this.dot,matchBase:this.matchBase,nobrace:this.nobrace,nocase:this.nocase,nocaseMagicOnly:s,nocomment:!0,noext:this.noext,nonegate:!0,optimizationLevel:2,platform:this.platform,windowsPathsNoEscape:this.windowsPathsNoEscape,debug:!!this.opts.debug},r=this.pattern.map(a=>new D(a,i)),[o,h]=r.reduce((a,l)=>(a[0].push(...l.set),a[1].push(...l.globParts),a),[[],[]]);this.patterns=o.map((a,l)=>{let u=h[l];if(!u)throw new Error("invalid pattern object");return new nt(a,u,0,this.platform)})}async walk(){return[...await new xt(this.patterns,this.scurry.cwd,{...this.opts,maxDepth:this.maxDepth!==1/0?this.maxDepth+this.scurry.cwd.depth():1/0,platform:this.platform,nocase:this.nocase,includeChildMatches:this.includeChildMatches}).walk()]}walkSync(){return[...new xt(this.patterns,this.scurry.cwd,{...this.opts,maxDepth:this.maxDepth!==1/0?this.maxDepth+this.scurry.cwd.depth():1/0,platform:this.platform,nocase:this.nocase,includeChildMatches:this.includeChildMatches}).walkSync()]}stream(){return new vt(this.patterns,this.scurry.cwd,{...this.opts,maxDepth:this.maxDepth!==1/0?this.maxDepth+this.scurry.cwd.depth():1/0,platform:this.platform,nocase:this.nocase,includeChildMatches:this.includeChildMatches}).stream()}streamSync(){return new vt(this.patterns,this.scurry.cwd,{...this.opts,maxDepth:this.maxDepth!==1/0?this.maxDepth+this.scurry.cwd.depth():1/0,platform:this.platform,nocase:this.nocase,includeChildMatches:this.includeChildMatches}).streamSync()}iterateSync(){return this.streamSync()[Symbol.iterator]()}[Symbol.iterator](){return this.iterateSync()}iterate(){return this.stream()[Symbol.asyncIterator]()}[Symbol.asyncIterator](){return this.iterate()}},le=(n7,t={})=>{Array.isArray(n7)||(n7=[n7]);for(let e of n7)if(new D(e,t).hasMagic())return!0;return!1};function Bt(n7,t={}){return new I(n7,t).streamSync()}function Qe(n7,t={}){return new I(n7,t).stream()}function ts(n7,t={}){return new I(n7,t).walkSync()}async function Je(n7,t={}){return new I(n7,t).walk()}function Ut(n7,t={}){return new I(n7,t).iterateSync()}function es(n7,t={}){return new I(n7,t).iterate()}var ji=Bt,Ii=Object.assign(Qe,{sync:Bt}),zi=Ut,Bi=Object.assign(es,{sync:Ut}),Ui=Object.assign(ts,{stream:Bt,iterate:Ut}),Ze=Object.assign(Je,{glob:Je,globSync:ts,sync:Ui,globStream:Qe,stream:Ii,globStreamSync:Bt,streamSync:ji,globIterate:es,iterate:Bi,globIterateSync:Ut,iterateSync:zi,Glob:I,hasMagic:le,escape:tt,unescape:W});Ze.glob=Ze;var balanced=(a,b,str)=>{let ma=a instanceof RegExp?maybeMatch(a,str):a,mb=b instanceof RegExp?maybeMatch(b,str):b,r=ma!==null&&mb!=null&&range(ma,mb,str);return r&&{start:r[0],end:r[1],pre:str.slice(0,r[0]),body:str.slice(r[0]+ma.length,r[1]),post:str.slice(r[1]+mb.length)}},maybeMatch=(reg,str)=>{let m=str.match(reg);return m?m[0]:null},range=(a,b,str)=>{let begs,beg,left,right,result,ai2=str.indexOf(a),bi2=str.indexOf(b,ai2+1),i=ai2;if(ai2>=0&&bi2>0){if(a===b)return[ai2,bi2];for(begs=[],left=str.length;i>=0&&!result;){if(i===ai2)begs.push(i),ai2=str.indexOf(a,i+1);else if(begs.length===1){let r=begs.pop();r!==void 0&&(result=[r,bi2])}else beg=begs.pop(),beg!==void 0&&beg<left&&(left=beg,right=bi2),bi2=str.indexOf(b,i+1);i=ai2<bi2&&ai2>=0?ai2:bi2}begs.length&&right!==void 0&&(result=[left,right])}return result};var escSlash="\0SLASH"+Math.random()+"\0",escOpen="\0OPEN"+Math.random()+"\0",escClose="\0CLOSE"+Math.random()+"\0",escComma="\0COMMA"+Math.random()+"\0",escPeriod="\0PERIOD"+Math.random()+"\0",escSlashPattern=new RegExp(escSlash,"g"),escOpenPattern=new RegExp(escOpen,"g"),escClosePattern=new RegExp(escClose,"g"),escCommaPattern=new RegExp(escComma,"g"),escPeriodPattern=new RegExp(escPeriod,"g"),slashPattern=/\\\\/g,openPattern=/\\{/g,closePattern=/\\}/g,commaPattern=/\\,/g,periodPattern=/\\\./g,EXPANSION_MAX=1e5;function numeric(str){return isNaN(str)?str.charCodeAt(0):parseInt(str,10)}function escapeBraces(str){return str.replace(slashPattern,escSlash).replace(openPattern,escOpen).replace(closePattern,escClose).replace(commaPattern,escComma).replace(periodPattern,escPeriod)}function unescapeBraces(str){return str.replace(escSlashPattern,"\\").replace(escOpenPattern,"{").replace(escClosePattern,"}").replace(escCommaPattern,",").replace(escPeriodPattern,".")}function parseCommaParts(str){if(!str)return[""];let parts=[],m=balanced("{","}",str);if(!m)return str.split(",");let{pre,body:body2,post}=m,p=pre.split(",");p[p.length-1]+="{"+body2+"}";let postParts=parseCommaParts(post);return post.length&&(p[p.length-1]+=postParts.shift(),p.push.apply(p,postParts)),parts.push.apply(parts,p),parts}function expand(str,options={}){if(!str)return[];let{max=EXPANSION_MAX}=options;return str.slice(0,2)==="{}"&&(str="\\{\\}"+str.slice(2)),expand_(escapeBraces(str),max,!0).map(unescapeBraces)}function embrace(str){return"{"+str+"}"}function isPadded(el){return/^-?0\d/.test(el)}function lte(i,y){return i<=y}function gte(i,y){return i>=y}function expand_(str,max,isTop){let expansions=[],m=balanced("{","}",str);if(!m)return[str];let pre=m.pre,post=m.post.length?expand_(m.post,max,!1):[""];if(/\$$/.test(m.pre))for(let k2=0;k2<post.length&&k2<max;k2++){let expansion=pre+"{"+m.body+"}"+post[k2];expansions.push(expansion)}else{let isNumericSequence=/^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body),isAlphaSequence=/^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body),isSequence=isNumericSequence||isAlphaSequence,isOptions=m.body.indexOf(",")>=0;if(!isSequence&&!isOptions)return m.post.match(/,(?!,).*\}/)?(str=m.pre+"{"+m.body+escClose+m.post,expand_(str,max,!0)):[str];let n7;if(isSequence)n7=m.body.split(/\.\./);else if(n7=parseCommaParts(m.body),n7.length===1&&n7[0]!==void 0&&(n7=expand_(n7[0],max,!1).map(embrace),n7.length===1))return post.map(p=>m.pre+n7[0]+p);let N2;if(isSequence&&n7[0]!==void 0&&n7[1]!==void 0){let x2=numeric(n7[0]),y=numeric(n7[1]),width=Math.max(n7[0].length,n7[1].length),incr=n7.length===3&&n7[2]!==void 0?Math.abs(numeric(n7[2])):1,test=lte;y<x2&&(incr*=-1,test=gte);let pad2=n7.some(isPadded);N2=[];for(let i=x2;test(i,y);i+=incr){let c;if(isAlphaSequence)c=String.fromCharCode(i),c==="\\"&&(c="");else if(c=String(i),pad2){let need=width-c.length;if(need>0){let z2=new Array(need+1).join("0");i<0?c="-"+z2+c.slice(1):c=z2+c}}N2.push(c)}}else{N2=[];for(let j2=0;j2<n7.length;j2++)N2.push.apply(N2,expand_(n7[j2],max,!1))}for(let j2=0;j2<N2.length;j2++)for(let k2=0;k2<post.length&&expansions.length<max;k2++){let expansion=pre+N2[j2]+post[k2];(!isTop||isSequence||expansion)&&expansions.push(expansion)}}return expansions}var assertValidPattern=pattern=>{if(typeof pattern!="string")throw new TypeError("invalid pattern");if(pattern.length>65536)throw new TypeError("pattern is too long")};var posixClasses={"[:alnum:]":["\\p{L}\\p{Nl}\\p{Nd}",!0],"[:alpha:]":["\\p{L}\\p{Nl}",!0],"[:ascii:]":["\\x00-\\x7f",!1],"[:blank:]":["\\p{Zs}\\t",!0],"[:cntrl:]":["\\p{Cc}",!0],"[:digit:]":["\\p{Nd}",!0],"[:graph:]":["\\p{Z}\\p{C}",!0,!0],"[:lower:]":["\\p{Ll}",!0],"[:print:]":["\\p{C}",!0],"[:punct:]":["\\p{P}",!0],"[:space:]":["\\p{Z}\\t\\r\\n\\v\\f",!0],"[:upper:]":["\\p{Lu}",!0],"[:word:]":["\\p{L}\\p{Nl}\\p{Nd}\\p{Pc}",!0],"[:xdigit:]":["A-Fa-f0-9",!1]},braceEscape=s=>s.replace(/[[\]\\-]/g,"\\$&"),regexpEscape=s=>s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),rangesToString=ranges=>ranges.join(""),parseClass=(glob,position)=>{let pos=position;if(glob.charAt(pos)!=="[")throw new Error("not in a brace expression");let ranges=[],negs=[],i=pos+1,sawStart=!1,uflag=!1,escaping=!1,negate=!1,endPos=pos,rangeStart="";WHILE:for(;i<glob.length;){let c=glob.charAt(i);if((c==="!"||c==="^")&&i===pos+1){negate=!0,i++;continue}if(c==="]"&&sawStart&&!escaping){endPos=i+1;break}if(sawStart=!0,c==="\\"&&!escaping){escaping=!0,i++;continue}if(c==="["&&!escaping){for(let[cls,[unip,u,neg]]of Object.entries(posixClasses))if(glob.startsWith(cls,i)){if(rangeStart)return["$.",!1,glob.length-pos,!0];i+=cls.length,neg?negs.push(unip):ranges.push(unip),uflag=uflag||u;continue WHILE}}if(escaping=!1,rangeStart){c>rangeStart?ranges.push(braceEscape(rangeStart)+"-"+braceEscape(c)):c===rangeStart&&ranges.push(braceEscape(c)),rangeStart="",i++;continue}if(glob.startsWith("-]",i+1)){ranges.push(braceEscape(c+"-")),i+=2;continue}if(glob.startsWith("-",i+1)){rangeStart=c,i+=2;continue}ranges.push(braceEscape(c)),i++}if(endPos<i)return["",!1,0,!1];if(!ranges.length&&!negs.length)return["$.",!1,glob.length-pos,!0];if(negs.length===0&&ranges.length===1&&/^\\?.$/.test(ranges[0])&&!negate){let r=ranges[0].length===2?ranges[0].slice(-1):ranges[0];return[regexpEscape(r),!1,endPos-pos,!1]}let sranges="["+(negate?"^":"")+rangesToString(ranges)+"]",snegs="["+(negate?"":"^")+rangesToString(negs)+"]";return[ranges.length&&negs.length?"("+sranges+"|"+snegs+")":ranges.length?sranges:snegs,uflag,endPos-pos,!0]};var unescape=(s,{windowsPathsNoEscape=!1,magicalBraces=!0}={})=>magicalBraces?windowsPathsNoEscape?s.replace(/\[([^\/\\])\]/g,"$1"):s.replace(/((?!\\).|^)\[([^\/\\])\]/g,"$1$2").replace(/\\([^\/])/g,"$1"):windowsPathsNoEscape?s.replace(/\[([^\/\\{}])\]/g,"$1"):s.replace(/((?!\\).|^)\[([^\/\\{}])\]/g,"$1$2").replace(/\\([^\/{}])/g,"$1");var _a,types=new Set(["!","?","+","*","@"]),isExtglobType=c=>types.has(c),isExtglobAST=c=>isExtglobType(c.type),adoptionMap=new Map([["!",["@"]],["?",["?","@"]],["@",["@"]],["*",["*","+","?","@"]],["+",["+","@"]]]),adoptionWithSpaceMap=new Map([["!",["?"]],["@",["?"]],["+",["?","*"]]]),adoptionAnyMap=new Map([["!",["?","@"]],["?",["?","@"]],["@",["?","@"]],["*",["*","+","?","@"]],["+",["+","@","?","*"]]]),usurpMap=new Map([["!",new Map([["!","@"]])],["?",new Map([["*","*"],["+","*"]])],["@",new Map([["!","!"],["?","?"],["@","@"],["*","*"],["+","+"]])],["+",new Map([["?","*"],["*","*"]])]]),startNoTraversal="(?!(?:^|/)\\.\\.?(?:$|/))",startNoDot="(?!\\.)",addPatternStart=new Set(["[","."]),justDots=new Set(["..","."]),reSpecials=new Set("().*{}+?[]^$\\!"),regExpEscape=s=>s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),qmark="[^/]",star=qmark+"*?",starNoEmpty=qmark+"+?",ID=0,AST=class{type;#root;#hasMagic;#uflag=!1;#parts=[];#parent;#parentIndex;#negs;#filledNegs=!1;#options;#toString;#emptyExt=!1;id=++ID;get depth(){return(this.#parent?.depth??-1)+1}[Symbol.for("nodejs.util.inspect.custom")](){return{"@@type":"AST",id:this.id,type:this.type,root:this.#root.id,parent:this.#parent?.id,depth:this.depth,partsLength:this.#parts.length,parts:this.#parts}}constructor(type,parent,options={}){this.type=type,type&&(this.#hasMagic=!0),this.#parent=parent,this.#root=this.#parent?this.#parent.#root:this,this.#options=this.#root===this?options:this.#root.#options,this.#negs=this.#root===this?[]:this.#root.#negs,type==="!"&&!this.#root.#filledNegs&&this.#negs.push(this),this.#parentIndex=this.#parent?this.#parent.#parts.length:0}get hasMagic(){if(this.#hasMagic!==void 0)return this.#hasMagic;for(let p of this.#parts)if(typeof p!="string"&&(p.type||p.hasMagic))return this.#hasMagic=!0;return this.#hasMagic}toString(){return this.#toString!==void 0?this.#toString:this.type?this.#toString=this.type+"("+this.#parts.map(p=>String(p)).join("|")+")":this.#toString=this.#parts.map(p=>String(p)).join("")}#fillNegs(){if(this!==this.#root)throw new Error("should only call on root");if(this.#filledNegs)return this;this.toString(),this.#filledNegs=!0;let n7;for(;n7=this.#negs.pop();){if(n7.type!=="!")continue;let p=n7,pp=p.#parent;for(;pp;){for(let i=p.#parentIndex+1;!pp.type&&i<pp.#parts.length;i++)for(let part of n7.#parts){if(typeof part=="string")throw new Error("string part in extglob AST??");part.copyIn(pp.#parts[i])}p=pp,pp=p.#parent}}return this}push(...parts){for(let p of parts)if(p!==""){if(typeof p!="string"&&!(p instanceof _a&&p.#parent===this))throw new Error("invalid part: "+p);this.#parts.push(p)}}toJSON(){let ret=this.type===null?this.#parts.slice().map(p=>typeof p=="string"?p:p.toJSON()):[this.type,...this.#parts.map(p=>p.toJSON())];return this.isStart()&&!this.type&&ret.unshift([]),this.isEnd()&&(this===this.#root||this.#root.#filledNegs&&this.#parent?.type==="!")&&ret.push({}),ret}isStart(){if(this.#root===this)return!0;if(!this.#parent?.isStart())return!1;if(this.#parentIndex===0)return!0;let p=this.#parent;for(let i=0;i<this.#parentIndex;i++){let pp=p.#parts[i];if(!(pp instanceof _a&&pp.type==="!"))return!1}return!0}isEnd(){if(this.#root===this||this.#parent?.type==="!")return!0;if(!this.#parent?.isEnd())return!1;if(!this.type)return this.#parent?.isEnd();let pl2=this.#parent?this.#parent.#parts.length:0;return this.#parentIndex===pl2-1}copyIn(part){typeof part=="string"?this.push(part):this.push(part.clone(this))}clone(parent){let c=new _a(this.type,parent);for(let p of this.#parts)c.copyIn(p);return c}static#parseAST(str,ast,pos,opt,extDepth){let maxDepth=opt.maxExtglobRecursion??2,escaping=!1,inBrace=!1,braceStart=-1,braceNeg=!1;if(ast.type===null){let i2=pos,acc2="";for(;i2<str.length;){let c=str.charAt(i2++);if(escaping||c==="\\"){escaping=!escaping,acc2+=c;continue}if(inBrace){i2===braceStart+1?(c==="^"||c==="!")&&(braceNeg=!0):c==="]"&&!(i2===braceStart+2&&braceNeg)&&(inBrace=!1),acc2+=c;continue}else if(c==="["){inBrace=!0,braceStart=i2,braceNeg=!1,acc2+=c;continue}if(!opt.noext&&isExtglobType(c)&&str.charAt(i2)==="("&&extDepth<=maxDepth){ast.push(acc2),acc2="";let ext2=new _a(c,ast);i2=_a.#parseAST(str,ext2,i2,opt,extDepth+1),ast.push(ext2);continue}acc2+=c}return ast.push(acc2),i2}let i=pos+1,part=new _a(null,ast),parts=[],acc="";for(;i<str.length;){let c=str.charAt(i++);if(escaping||c==="\\"){escaping=!escaping,acc+=c;continue}if(inBrace){i===braceStart+1?(c==="^"||c==="!")&&(braceNeg=!0):c==="]"&&!(i===braceStart+2&&braceNeg)&&(inBrace=!1),acc+=c;continue}else if(c==="["){inBrace=!0,braceStart=i,braceNeg=!1,acc+=c;continue}if(!opt.noext&&isExtglobType(c)&&str.charAt(i)==="("&&(extDepth<=maxDepth||ast&&ast.#canAdoptType(c))){let depthAdd=ast&&ast.#canAdoptType(c)?0:1;part.push(acc),acc="";let ext2=new _a(c,part);part.push(ext2),i=_a.#parseAST(str,ext2,i,opt,extDepth+depthAdd);continue}if(c==="|"){part.push(acc),acc="",parts.push(part),part=new _a(null,ast);continue}if(c===")")return acc===""&&ast.#parts.length===0&&(ast.#emptyExt=!0),part.push(acc),acc="",ast.push(...parts,part),i;acc+=c}return ast.type=null,ast.#hasMagic=void 0,ast.#parts=[str.substring(pos-1)],i}#canAdoptWithSpace(child2){return this.#canAdopt(child2,adoptionWithSpaceMap)}#canAdopt(child2,map3=adoptionMap){if(!child2||typeof child2!="object"||child2.type!==null||child2.#parts.length!==1||this.type===null)return!1;let gc=child2.#parts[0];return!gc||typeof gc!="object"||gc.type===null?!1:this.#canAdoptType(gc.type,map3)}#canAdoptType(c,map3=adoptionAnyMap){return!!map3.get(this.type)?.includes(c)}#adoptWithSpace(child2,index){let gc=child2.#parts[0],blank2=new _a(null,gc,this.options);blank2.#parts.push(""),gc.push(blank2),this.#adopt(child2,index)}#adopt(child2,index){let gc=child2.#parts[0];this.#parts.splice(index,1,...gc.#parts);for(let p of gc.#parts)typeof p=="object"&&(p.#parent=this);this.#toString=void 0}#canUsurpType(c){return!!usurpMap.get(this.type)?.has(c)}#canUsurp(child2){if(!child2||typeof child2!="object"||child2.type!==null||child2.#parts.length!==1||this.type===null||this.#parts.length!==1)return!1;let gc=child2.#parts[0];return!gc||typeof gc!="object"||gc.type===null?!1:this.#canUsurpType(gc.type)}#usurp(child2){let m=usurpMap.get(this.type),gc=child2.#parts[0],nt2=m?.get(gc.type);if(!nt2)return!1;this.#parts=gc.#parts;for(let p of this.#parts)typeof p=="object"&&(p.#parent=this);this.type=nt2,this.#toString=void 0,this.#emptyExt=!1}static fromGlob(pattern,options={}){let ast=new _a(null,void 0,options);return _a.#parseAST(pattern,ast,0,options,0),ast}toMMPattern(){if(this!==this.#root)return this.#root.toMMPattern();let glob=this.toString(),[re2,body2,hasMagic,uflag]=this.toRegExpSource();if(!(hasMagic||this.#hasMagic||this.#options.nocase&&!this.#options.nocaseMagicOnly&&glob.toUpperCase()!==glob.toLowerCase()))return body2;let flags=(this.#options.nocase?"i":"")+(uflag?"u":"");return Object.assign(new RegExp(`^${re2}$`,flags),{_src:re2,_glob:glob})}get options(){return this.#options}toRegExpSource(allowDot){let dot=allowDot??!!this.#options.dot;if(this.#root===this&&(this.#flatten(),this.#fillNegs()),!isExtglobAST(this)){let noEmpty=this.isStart()&&this.isEnd()&&!this.#parts.some(s=>typeof s!="string"),src=this.#parts.map(p=>{let[re2,_2,hasMagic,uflag]=typeof p=="string"?_a.#parseGlob(p,this.#hasMagic,noEmpty):p.toRegExpSource(allowDot);return this.#hasMagic=this.#hasMagic||hasMagic,this.#uflag=this.#uflag||uflag,re2}).join(""),start3="";if(this.isStart()&&typeof this.#parts[0]=="string"&&!(this.#parts.length===1&&justDots.has(this.#parts[0]))){let aps=addPatternStart,needNoTrav=dot&&aps.has(src.charAt(0))||src.startsWith("\\.")&&aps.has(src.charAt(2))||src.startsWith("\\.\\.")&&aps.has(src.charAt(4)),needNoDot=!dot&&!allowDot&&aps.has(src.charAt(0));start3=needNoTrav?startNoTraversal:needNoDot?startNoDot:""}let end="";return this.isEnd()&&this.#root.#filledNegs&&this.#parent?.type==="!"&&(end="(?:$|\\/)"),[start3+src+end,unescape(src),this.#hasMagic=!!this.#hasMagic,this.#uflag]}let repeated=this.type==="*"||this.type==="+",start2=this.type==="!"?"(?:(?!(?:":"(?:",body2=this.#partsToRegExp(dot);if(this.isStart()&&this.isEnd()&&!body2&&this.type!=="!"){let s=this.toString(),me2=this;return me2.#parts=[s],me2.type=null,me2.#hasMagic=void 0,[s,unescape(this.toString()),!1,!1]}let bodyDotAllowed=!repeated||allowDot||dot||!startNoDot?"":this.#partsToRegExp(!0);bodyDotAllowed===body2&&(bodyDotAllowed=""),bodyDotAllowed&&(body2=`(?:${body2})(?:${bodyDotAllowed})*?`);let final="";if(this.type==="!"&&this.#emptyExt)final=(this.isStart()&&!dot?startNoDot:"")+starNoEmpty;else{let close=this.type==="!"?"))"+(this.isStart()&&!dot&&!allowDot?startNoDot:"")+star+")":this.type==="@"?")":this.type==="?"?")?":this.type==="+"&&bodyDotAllowed?")":this.type==="*"&&bodyDotAllowed?")?":`)${this.type}`;final=start2+body2+close}return[final,unescape(body2),this.#hasMagic=!!this.#hasMagic,this.#uflag]}#flatten(){if(isExtglobAST(this)){let iterations=0,done2=!1;do{done2=!0;for(let i=0;i<this.#parts.length;i++){let c=this.#parts[i];typeof c=="object"&&(c.#flatten(),this.#canAdopt(c)?(done2=!1,this.#adopt(c,i)):this.#canAdoptWithSpace(c)?(done2=!1,this.#adoptWithSpace(c,i)):this.#canUsurp(c)&&(done2=!1,this.#usurp(c)))}}while(!done2&&++iterations<10)}else for(let p of this.#parts)typeof p=="object"&&p.#flatten();this.#toString=void 0}#partsToRegExp(dot){return this.#parts.map(p=>{if(typeof p=="string")throw new Error("string type in extglob ast??");let[re2,_2,_hasMagic,uflag]=p.toRegExpSource(dot);return this.#uflag=this.#uflag||uflag,re2}).filter(p=>!(this.isStart()&&this.isEnd())||!!p).join("|")}static#parseGlob(glob,hasMagic,noEmpty=!1){let escaping=!1,re2="",uflag=!1,inStar=!1;for(let i=0;i<glob.length;i++){let c=glob.charAt(i);if(escaping){escaping=!1,re2+=(reSpecials.has(c)?"\\":"")+c;continue}if(c==="*"){if(inStar)continue;inStar=!0,re2+=noEmpty&&/^[*]+$/.test(glob)?starNoEmpty:star,hasMagic=!0;continue}else inStar=!1;if(c==="\\"){i===glob.length-1?re2+="\\\\":escaping=!0;continue}if(c==="["){let[src,needUflag,consumed,magic]=parseClass(glob,i);if(consumed){re2+=src,uflag=uflag||needUflag,i+=consumed-1,hasMagic=hasMagic||magic;continue}}if(c==="?"){re2+=qmark,hasMagic=!0;continue}re2+=regExpEscape(c)}return[re2,unescape(glob),!!hasMagic,uflag]}};_a=AST;var escape2=(s,{windowsPathsNoEscape=!1,magicalBraces=!1}={})=>magicalBraces?windowsPathsNoEscape?s.replace(/[?*()[\]{}]/g,"[$&]"):s.replace(/[?*()[\]\\{}]/g,"\\$&"):windowsPathsNoEscape?s.replace(/[?*()[\]]/g,"[$&]"):s.replace(/[?*()[\]\\]/g,"\\$&");var minimatch=(p,pattern,options={})=>(assertValidPattern(pattern),!options.nocomment&&pattern.charAt(0)==="#"?!1:new Minimatch(pattern,options).match(p)),starDotExtRE=/^\*+([^+@!?\*\[\(]*)$/,starDotExtTest=ext2=>f=>!f.startsWith(".")&&f.endsWith(ext2),starDotExtTestDot=ext2=>f=>f.endsWith(ext2),starDotExtTestNocase=ext2=>(ext2=ext2.toLowerCase(),f=>!f.startsWith(".")&&f.toLowerCase().endsWith(ext2)),starDotExtTestNocaseDot=ext2=>(ext2=ext2.toLowerCase(),f=>f.toLowerCase().endsWith(ext2)),starDotStarRE=/^\*+\.\*+$/,starDotStarTest=f=>!f.startsWith(".")&&f.includes("."),starDotStarTestDot=f=>f!=="."&&f!==".."&&f.includes("."),dotStarRE=/^\.\*+$/,dotStarTest=f=>f!=="."&&f!==".."&&f.startsWith("."),starRE=/^\*+$/,starTest=f=>f.length!==0&&!f.startsWith("."),starTestDot=f=>f.length!==0&&f!=="."&&f!=="..",qmarksRE=/^\?+([^+@!?\*\[\(]*)?$/,qmarksTestNocase=([$0,ext2=""])=>{let noext=qmarksTestNoExt([$0]);return ext2?(ext2=ext2.toLowerCase(),f=>noext(f)&&f.toLowerCase().endsWith(ext2)):noext},qmarksTestNocaseDot=([$0,ext2=""])=>{let noext=qmarksTestNoExtDot([$0]);return ext2?(ext2=ext2.toLowerCase(),f=>noext(f)&&f.toLowerCase().endsWith(ext2)):noext},qmarksTestDot=([$0,ext2=""])=>{let noext=qmarksTestNoExtDot([$0]);return ext2?f=>noext(f)&&f.endsWith(ext2):noext},qmarksTest=([$0,ext2=""])=>{let noext=qmarksTestNoExt([$0]);return ext2?f=>noext(f)&&f.endsWith(ext2):noext},qmarksTestNoExt=([$0])=>{let len=$0.length;return f=>f.length===len&&!f.startsWith(".")},qmarksTestNoExtDot=([$0])=>{let len=$0.length;return f=>f.length===len&&f!=="."&&f!==".."},defaultPlatform=typeof process=="object"&&process?typeof process.env=="object"&&process.env&&process.env.__MINIMATCH_TESTING_PLATFORM__||process.platform:"posix",path10={win32:{sep:"\\"},posix:{sep:"/"}},sep=defaultPlatform==="win32"?path10.win32.sep:path10.posix.sep;minimatch.sep=sep;var GLOBSTAR=Symbol("globstar **");minimatch.GLOBSTAR=GLOBSTAR;var qmark2="[^/]",star2=qmark2+"*?",twoStarDot="(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?",twoStarNoDot="(?:(?!(?:\\/|^)\\.).)*?",filter=(pattern,options={})=>p=>minimatch(p,pattern,options);minimatch.filter=filter;var ext=(a,b={})=>Object.assign({},a,b),defaults=def=>{if(!def||typeof def!="object"||!Object.keys(def).length)return minimatch;let orig=minimatch;return Object.assign((p,pattern,options={})=>orig(p,pattern,ext(def,options)),{Minimatch:class extends orig.Minimatch{constructor(pattern,options={}){super(pattern,ext(def,options))}static defaults(options){return orig.defaults(ext(def,options)).Minimatch}},AST:class extends orig.AST{constructor(type,parent,options={}){super(type,parent,ext(def,options))}static fromGlob(pattern,options={}){return orig.AST.fromGlob(pattern,ext(def,options))}},unescape:(s,options={})=>orig.unescape(s,ext(def,options)),escape:(s,options={})=>orig.escape(s,ext(def,options)),filter:(pattern,options={})=>orig.filter(pattern,ext(def,options)),defaults:options=>orig.defaults(ext(def,options)),makeRe:(pattern,options={})=>orig.makeRe(pattern,ext(def,options)),braceExpand:(pattern,options={})=>orig.braceExpand(pattern,ext(def,options)),match:(list2,pattern,options={})=>orig.match(list2,pattern,ext(def,options)),sep:orig.sep,GLOBSTAR})};minimatch.defaults=defaults;var braceExpand=(pattern,options={})=>(assertValidPattern(pattern),options.nobrace||!/\{(?:(?!\{).)*\}/.test(pattern)?[pattern]:expand(pattern,{max:options.braceExpandMax}));minimatch.braceExpand=braceExpand;var makeRe=(pattern,options={})=>new Minimatch(pattern,options).makeRe();minimatch.makeRe=makeRe;var match=(list2,pattern,options={})=>{let mm=new Minimatch(pattern,options);return list2=list2.filter(f=>mm.match(f)),mm.options.nonull&&!list2.length&&list2.push(pattern),list2};minimatch.match=match;var globMagic=/[?*]|[+@!]\(.*?\)|\[|\]/,regExpEscape2=s=>s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),Minimatch=class{options;set;pattern;windowsPathsNoEscape;nonegate;negate;comment;empty;preserveMultipleSlashes;partial;globSet;globParts;nocase;isWindows;platform;windowsNoMagicRoot;maxGlobstarRecursion;regexp;constructor(pattern,options={}){assertValidPattern(pattern),options=options||{},this.options=options,this.maxGlobstarRecursion=options.maxGlobstarRecursion??200,this.pattern=pattern,this.platform=options.platform||defaultPlatform,this.isWindows=this.platform==="win32";let awe="allowWindowsEscape";this.windowsPathsNoEscape=!!options.windowsPathsNoEscape||options[awe]===!1,this.windowsPathsNoEscape&&(this.pattern=this.pattern.replace(/\\/g,"/")),this.preserveMultipleSlashes=!!options.preserveMultipleSlashes,this.regexp=null,this.negate=!1,this.nonegate=!!options.nonegate,this.comment=!1,this.empty=!1,this.partial=!!options.partial,this.nocase=!!this.options.nocase,this.windowsNoMagicRoot=options.windowsNoMagicRoot!==void 0?options.windowsNoMagicRoot:!!(this.isWindows&&this.nocase),this.globSet=[],this.globParts=[],this.set=[],this.make()}hasMagic(){if(this.options.magicalBraces&&this.set.length>1)return!0;for(let pattern of this.set)for(let part of pattern)if(typeof part!="string")return!0;return!1}debug(..._2){}make(){let pattern=this.pattern,options=this.options;if(!options.nocomment&&pattern.charAt(0)==="#"){this.comment=!0;return}if(!pattern){this.empty=!0;return}this.parseNegate(),this.globSet=[...new Set(this.braceExpand())],options.debug&&(this.debug=(...args)=>console.error(...args)),this.debug(this.pattern,this.globSet);let rawGlobParts=this.globSet.map(s=>this.slashSplit(s));this.globParts=this.preprocess(rawGlobParts),this.debug(this.pattern,this.globParts);let set2=this.globParts.map((s,_2,__)=>{if(this.isWindows&&this.windowsNoMagicRoot){let isUNC=s[0]===""&&s[1]===""&&(s[2]==="?"||!globMagic.test(s[2]))&&!globMagic.test(s[3]),isDrive=/^[a-z]:/i.test(s[0]);if(isUNC)return[...s.slice(0,4),...s.slice(4).map(ss2=>this.parse(ss2))];if(isDrive)return[s[0],...s.slice(1).map(ss2=>this.parse(ss2))]}return s.map(ss2=>this.parse(ss2))});if(this.debug(this.pattern,set2),this.set=set2.filter(s=>s.indexOf(!1)===-1),this.isWindows)for(let i=0;i<this.set.length;i++){let p=this.set[i];p[0]===""&&p[1]===""&&this.globParts[i][2]==="?"&&typeof p[3]=="string"&&/^[a-z]:$/i.test(p[3])&&(p[2]="?")}this.debug(this.pattern,this.set)}preprocess(globParts){if(this.options.noglobstar)for(let i=0;i<globParts.length;i++)for(let j2=0;j2<globParts[i].length;j2++)globParts[i][j2]==="**"&&(globParts[i][j2]="*");let{optimizationLevel=1}=this.options;return optimizationLevel>=2?(globParts=this.firstPhasePreProcess(globParts),globParts=this.secondPhasePreProcess(globParts)):optimizationLevel>=1?globParts=this.levelOneOptimize(globParts):globParts=this.adjascentGlobstarOptimize(globParts),globParts}adjascentGlobstarOptimize(globParts){return globParts.map(parts=>{let gs2=-1;for(;(gs2=parts.indexOf("**",gs2+1))!==-1;){let i=gs2;for(;parts[i+1]==="**";)i++;i!==gs2&&parts.splice(gs2,i-gs2)}return parts})}levelOneOptimize(globParts){return globParts.map(parts=>(parts=parts.reduce((set2,part)=>{let prev=set2[set2.length-1];return part==="**"&&prev==="**"?set2:part===".."&&prev&&prev!==".."&&prev!=="."&&prev!=="**"?(set2.pop(),set2):(set2.push(part),set2)},[]),parts.length===0?[""]:parts))}levelTwoFileOptimize(parts){Array.isArray(parts)||(parts=this.slashSplit(parts));let didSomething=!1;do{if(didSomething=!1,!this.preserveMultipleSlashes){for(let i=1;i<parts.length-1;i++){let p=parts[i];i===1&&p===""&&parts[0]===""||(p==="."||p==="")&&(didSomething=!0,parts.splice(i,1),i--)}parts[0]==="."&&parts.length===2&&(parts[1]==="."||parts[1]==="")&&(didSomething=!0,parts.pop())}let dd=0;for(;(dd=parts.indexOf("..",dd+1))!==-1;){let p=parts[dd-1];p&&p!=="."&&p!==".."&&p!=="**"&&(didSomething=!0,parts.splice(dd-1,2),dd-=2)}}while(didSomething);return parts.length===0?[""]:parts}firstPhasePreProcess(globParts){let didSomething=!1;do{didSomething=!1;for(let parts of globParts){let gs2=-1;for(;(gs2=parts.indexOf("**",gs2+1))!==-1;){let gss=gs2;for(;parts[gss+1]==="**";)gss++;gss>gs2&&parts.splice(gs2+1,gss-gs2);let next=parts[gs2+1],p=parts[gs2+2],p2=parts[gs2+3];if(next!==".."||!p||p==="."||p===".."||!p2||p2==="."||p2==="..")continue;didSomething=!0,parts.splice(gs2,1);let other=parts.slice(0);other[gs2]="**",globParts.push(other),gs2--}if(!this.preserveMultipleSlashes){for(let i=1;i<parts.length-1;i++){let p=parts[i];i===1&&p===""&&parts[0]===""||(p==="."||p==="")&&(didSomething=!0,parts.splice(i,1),i--)}parts[0]==="."&&parts.length===2&&(parts[1]==="."||parts[1]==="")&&(didSomething=!0,parts.pop())}let dd=0;for(;(dd=parts.indexOf("..",dd+1))!==-1;){let p=parts[dd-1];if(p&&p!=="."&&p!==".."&&p!=="**"){didSomething=!0;let splin=dd===1&&parts[dd+1]==="**"?["."]:[];parts.splice(dd-1,2,...splin),parts.length===0&&parts.push(""),dd-=2}}}}while(didSomething);return globParts}secondPhasePreProcess(globParts){for(let i=0;i<globParts.length-1;i++)for(let j2=i+1;j2<globParts.length;j2++){let matched=this.partsMatch(globParts[i],globParts[j2],!this.preserveMultipleSlashes);if(matched){globParts[i]=[],globParts[j2]=matched;break}}return globParts.filter(gs2=>gs2.length)}partsMatch(a,b,emptyGSMatch=!1){let ai2=0,bi2=0,result=[],which="";for(;ai2<a.length&&bi2<b.length;)if(a[ai2]===b[bi2])result.push(which==="b"?b[bi2]:a[ai2]),ai2++,bi2++;else if(emptyGSMatch&&a[ai2]==="**"&&b[bi2]===a[ai2+1])result.push(a[ai2]),ai2++;else if(emptyGSMatch&&b[bi2]==="**"&&a[ai2]===b[bi2+1])result.push(b[bi2]),bi2++;else if(a[ai2]==="*"&&b[bi2]&&(this.options.dot||!b[bi2].startsWith("."))&&b[bi2]!=="**"){if(which==="b")return!1;which="a",result.push(a[ai2]),ai2++,bi2++}else if(b[bi2]==="*"&&a[ai2]&&(this.options.dot||!a[ai2].startsWith("."))&&a[ai2]!=="**"){if(which==="a")return!1;which="b",result.push(b[bi2]),ai2++,bi2++}else return!1;return a.length===b.length&&result}parseNegate(){if(this.nonegate)return;let pattern=this.pattern,negate=!1,negateOffset=0;for(let i=0;i<pattern.length&&pattern.charAt(i)==="!";i++)negate=!negate,negateOffset++;negateOffset&&(this.pattern=pattern.slice(negateOffset)),this.negate=negate}matchOne(file2,pattern,partial2=!1){let fileStartIndex=0,patternStartIndex=0;if(this.isWindows){let fileDrive=typeof file2[0]=="string"&&/^[a-z]:$/i.test(file2[0]),fileUNC=!fileDrive&&file2[0]===""&&file2[1]===""&&file2[2]==="?"&&/^[a-z]:$/i.test(file2[3]),patternDrive=typeof pattern[0]=="string"&&/^[a-z]:$/i.test(pattern[0]),patternUNC=!patternDrive&&pattern[0]===""&&pattern[1]===""&&pattern[2]==="?"&&typeof pattern[3]=="string"&&/^[a-z]:$/i.test(pattern[3]),fdi=fileUNC?3:fileDrive?0:void 0,pdi=patternUNC?3:patternDrive?0:void 0;if(typeof fdi=="number"&&typeof pdi=="number"){let[fd,pd]=[file2[fdi],pattern[pdi]];fd.toLowerCase()===pd.toLowerCase()&&(pattern[pdi]=fd,patternStartIndex=pdi,fileStartIndex=fdi)}}let{optimizationLevel=1}=this.options;return optimizationLevel>=2&&(file2=this.levelTwoFileOptimize(file2)),pattern.includes(GLOBSTAR)?this.#matchGlobstar(file2,pattern,partial2,fileStartIndex,patternStartIndex):this.#matchOne(file2,pattern,partial2,fileStartIndex,patternStartIndex)}#matchGlobstar(file2,pattern,partial2,fileIndex,patternIndex){let firstgs=pattern.indexOf(GLOBSTAR,patternIndex),lastgs=pattern.lastIndexOf(GLOBSTAR),[head,body2,tail]=partial2?[pattern.slice(patternIndex,firstgs),pattern.slice(firstgs+1),[]]:[pattern.slice(patternIndex,firstgs),pattern.slice(firstgs+1,lastgs),pattern.slice(lastgs+1)];if(head.length){let fileHead=file2.slice(fileIndex,fileIndex+head.length);if(!this.#matchOne(fileHead,head,partial2,0,0))return!1;fileIndex+=head.length,patternIndex+=head.length}let fileTailMatch=0;if(tail.length){if(tail.length+fileIndex>file2.length)return!1;let tailStart=file2.length-tail.length;if(this.#matchOne(file2,tail,partial2,tailStart,0))fileTailMatch=tail.length;else{if(file2[file2.length-1]!==""||fileIndex+tail.length===file2.length||(tailStart--,!this.#matchOne(file2,tail,partial2,tailStart,0)))return!1;fileTailMatch=tail.length+1}}if(!body2.length){let sawSome=!!fileTailMatch;for(let i2=fileIndex;i2<file2.length-fileTailMatch;i2++){let f=String(file2[i2]);if(sawSome=!0,f==="."||f===".."||!this.options.dot&&f.startsWith("."))return!1}return partial2||sawSome}let bodySegments=[[[],0]],currentBody=bodySegments[0],nonGsParts=0,nonGsPartsSums=[0];for(let b of body2)b===GLOBSTAR?(nonGsPartsSums.push(nonGsParts),currentBody=[[],0],bodySegments.push(currentBody)):(currentBody[0].push(b),nonGsParts++);let i=bodySegments.length-1,fileLength=file2.length-fileTailMatch;for(let b of bodySegments)b[1]=fileLength-(nonGsPartsSums[i--]+b[0].length);return!!this.#matchGlobStarBodySections(file2,bodySegments,fileIndex,0,partial2,0,!!fileTailMatch)}#matchGlobStarBodySections(file2,bodySegments,fileIndex,bodyIndex,partial2,globStarDepth,sawTail){let bs2=bodySegments[bodyIndex];if(!bs2){for(let i=fileIndex;i<file2.length;i++){sawTail=!0;let f=file2[i];if(f==="."||f===".."||!this.options.dot&&f.startsWith("."))return!1}return sawTail}let[body2,after]=bs2;for(;fileIndex<=after;){if(this.#matchOne(file2.slice(0,fileIndex+body2.length),body2,partial2,fileIndex,0)&&globStarDepth<this.maxGlobstarRecursion){let sub=this.#matchGlobStarBodySections(file2,bodySegments,fileIndex+body2.length,bodyIndex+1,partial2,globStarDepth+1,sawTail);if(sub!==!1)return sub}let f=file2[fileIndex];if(f==="."||f===".."||!this.options.dot&&f.startsWith("."))return!1;fileIndex++}return partial2||null}#matchOne(file2,pattern,partial2,fileIndex,patternIndex){let fi2,pi2,pl2,fl;for(fi2=fileIndex,pi2=patternIndex,fl=file2.length,pl2=pattern.length;fi2<fl&&pi2<pl2;fi2++,pi2++){this.debug("matchOne loop");let p=pattern[pi2],f=file2[fi2];if(this.debug(pattern,p,f),p===!1||p===GLOBSTAR)return!1;let hit;if(typeof p=="string"?(hit=f===p,this.debug("string match",p,f,hit)):(hit=p.test(f),this.debug("pattern match",p,f,hit)),!hit)return!1}if(fi2===fl&&pi2===pl2)return!0;if(fi2===fl)return partial2;if(pi2===pl2)return fi2===fl-1&&file2[fi2]==="";throw new Error("wtf?")}braceExpand(){return braceExpand(this.pattern,this.options)}parse(pattern){assertValidPattern(pattern);let options=this.options;if(pattern==="**")return GLOBSTAR;if(pattern==="")return"";let m,fastTest=null;(m=pattern.match(starRE))?fastTest=options.dot?starTestDot:starTest:(m=pattern.match(starDotExtRE))?fastTest=(options.nocase?options.dot?starDotExtTestNocaseDot:starDotExtTestNocase:options.dot?starDotExtTestDot:starDotExtTest)(m[1]):(m=pattern.match(qmarksRE))?fastTest=(options.nocase?options.dot?qmarksTestNocaseDot:qmarksTestNocase:options.dot?qmarksTestDot:qmarksTest)(m):(m=pattern.match(starDotStarRE))?fastTest=options.dot?starDotStarTestDot:starDotStarTest:(m=pattern.match(dotStarRE))&&(fastTest=dotStarTest);let re2=AST.fromGlob(pattern,this.options).toMMPattern();return fastTest&&typeof re2=="object"&&Reflect.defineProperty(re2,"test",{value:fastTest}),re2}makeRe(){if(this.regexp||this.regexp===!1)return this.regexp;let set2=this.set;if(!set2.length)return this.regexp=!1,this.regexp;let options=this.options,twoStar=options.noglobstar?star2:options.dot?twoStarDot:twoStarNoDot,flags=new Set(options.nocase?["i"]:[]),re2=set2.map(pattern=>{let pp=pattern.map(p=>{if(p instanceof RegExp)for(let f of p.flags.split(""))flags.add(f);return typeof p=="string"?regExpEscape2(p):p===GLOBSTAR?GLOBSTAR:p._src});pp.forEach((p,i)=>{let next=pp[i+1],prev=pp[i-1];p!==GLOBSTAR||prev===GLOBSTAR||(prev===void 0?next!==void 0&&next!==GLOBSTAR?pp[i+1]="(?:\\/|"+twoStar+"\\/)?"+next:pp[i]=twoStar:next===void 0?pp[i-1]=prev+"(?:\\/|\\/"+twoStar+")?":next!==GLOBSTAR&&(pp[i-1]=prev+"(?:\\/|\\/"+twoStar+"\\/)"+next,pp[i+1]=GLOBSTAR))});let filtered=pp.filter(p=>p!==GLOBSTAR);if(this.partial&&filtered.length>=1){let prefixes=[];for(let i=1;i<=filtered.length;i++)prefixes.push(filtered.slice(0,i).join("/"));return"(?:"+prefixes.join("|")+")"}return filtered.join("/")}).join("|"),[open2,close]=set2.length>1?["(?:",")"]:["",""];re2="^"+open2+re2+close+"$",this.partial&&(re2="^(?:\\/|"+open2+re2.slice(1,-1)+close+")$"),this.negate&&(re2="^(?!"+re2+").+$");try{this.regexp=new RegExp(re2,[...flags].join(""))}catch{this.regexp=!1}return this.regexp}slashSplit(p){return this.preserveMultipleSlashes?p.split("/"):this.isWindows&&/^\/\/[^\/]+/.test(p)?["",...p.split(/\/+/)]:p.split(/\/+/)}match(f,partial2=this.partial){if(this.debug("match",f,this.pattern),this.comment)return!1;if(this.empty)return f==="";if(f==="/"&&partial2)return!0;let options=this.options;this.isWindows&&(f=f.split("\\").join("/"));let ff=this.slashSplit(f);this.debug(this.pattern,"split",ff);let set2=this.set;this.debug(this.pattern,"set",set2);let filename=ff[ff.length-1];if(!filename)for(let i=ff.length-2;!filename&&i>=0;i--)filename=ff[i];for(let i=0;i<set2.length;i++){let pattern=set2[i],file2=ff;if(options.matchBase&&pattern.length===1&&(file2=[filename]),this.matchOne(file2,pattern,partial2))return options.flipNegate?!0:!this.negate}return options.flipNegate?!1:this.negate}static defaults(def){return minimatch.defaults(def).Minimatch}};minimatch.AST=AST;minimatch.Minimatch=Minimatch;minimatch.escape=escape2;minimatch.unescape=unescape;import{realpathSync}from"node:fs";import path11 from"node:path";var GLOB_CHARS=/[*?[\]{}]/,BASE_STOP=/[*?{[]/;function hasGlob(text){return GLOB_CHARS.test(text)}function staticBase(pattern){let staticParts=[];for(let part of pattern.split("/")){if(BASE_STOP.test(part))break;staticParts.push(part)}return staticParts.length>0&&staticParts[staticParts.length-1]===""&&staticParts.pop(),staticParts.join("/")||"/"}function compareBytewise(left,right){return Buffer.compare(Buffer.from(left),Buffer.from(right))}function toPosix(value){return toGlobPattern(value)}function toGlobPattern(value,separator=path11.sep){return separator==="/"?value:value.split(separator).join("/")}function textInside(child2,parent){let relative4=path11.relative(path11.resolve(parent),path11.resolve(child2));return relative4===""||relative4!==".."&&!relative4.startsWith(`..${path11.sep}`)&&!path11.isAbsolute(relative4)}function realPathOfMaybeMissing(target){let missing=[],current=path11.resolve(target);for(;;)try{return path11.join(realpathSync(current),...missing.reverse())}catch{let parent=path11.dirname(current);if(parent===current)return;missing.push(path11.basename(current)),current=parent}}function toList(patterns){return(typeof patterns=="string"?[patterns]:[...patterns]).map(pattern=>toGlobPattern(pattern))}function globOptions(options){return{cwd:options.cwd,dot:options.dot??!1,absolute:options.absolute??!1,nodir:options.onlyFiles??!0,ignore:options.ignore===void 0?void 0:toList(options.ignore),follow:options.followSymlinks??!0}}function finish(matches,options){return matches.map(match2=>options.absolute===!0?match2:toPosix(match2)).sort(compareBytewise)}var hostGlobs={async match(patterns,options){return finish(await Ze(toList(patterns),globOptions(options)),options)},matchSync(patterns,options){return finish(ts(toList(patterns),globOptions(options)),options)},isMatch(candidate,pattern,options={}){let matcher2={dot:options.dot??!1,nocase:options.nocase??!1},posix=toGlobPattern(candidate);return toList(pattern).some(single=>minimatch(posix,single,matcher2))},hasGlob,staticBase,compareBytewise,sortBytewise(items2){return[...items2].sort(compareBytewise)},isInside(child2,parent,options={}){if(options.realPath!==!0)return textInside(child2,parent);let realChild=realPathOfMaybeMissing(child2),realParent=realPathOfMaybeMissing(parent);return realChild!==void 0&&realParent!==void 0&&textInside(realChild,realParent)},realPathInside(target,root){let real=realPathOfMaybeMissing(target),realRoot=realPathOfMaybeMissing(root);return real!==void 0&&realRoot!==void 0&&textInside(real,realRoot)?real:void 0},toPosix};var KNOWN_READMES={"sous-dir":{title:"The .sous directory",body:["This directory holds this project's sous configuration: the main `sous.config.*` file, the `conf.d/` drop-in layers, the answers files and the lockfile.","Most of it is committed to version control. Machine-specific files (the links map, the build state, the watcher's PID file and `.env.local`) are kept out by the sous-managed block in `.gitignore`."]},confd:{title:"conf.d: drop-in configuration layers",body:["Every `.js`, `.mjs`, `.json`, `.jsonc` or `.yaml` file directly inside this directory is a configuration layer. Sous loads them after the project's main `sous.config.*` file, in the order of the number their names start with (highest last), and merges each one over what came before it. A file whose name starts with no number is applied after the files numbered up to 499 and before those numbered 501 and up.","Layers numbered 500 through 599 are written by sous itself (for example `500-repos.jsonc`, recording the repositories this project trusts). Sous edits those files by key, so your comments, key order and formatting survive; it never touches the main config or any layer outside that band.","You may add, edit and delete layers here yourself, including the ones sous writes. This directory is normally committed to version control along with the rest of `.sous/`; keep machine-specific paths and secrets out of it and put them in `.sous/.env.local` instead."]},"project-repos":{title:"repos: linked repository checkouts",body:["`sous repo link` clones a recipe repository in here so you can work on it and on this project at the same time. Each checkout is an ordinary git working copy; sous reads from it and never writes to it.","Everything here is machine-local. The `.gitignore` beside this file holds a single `*`, so nothing in this directory (these explanatory files included) is visible to the project's own repository.","It is safe to delete a checkout once you have run `sous repo unlink` for it; sous goes back to the published version of that repository."]},"sous-home":{title:"Your user-level sous directory",body:["This is `$SOUS_HOME` (`~/.sous` unless you set that variable). It holds the sous state that belongs to this machine rather than to any one project: the recipe cache in `cache/`, globally linked checkouts in `repos/`, and the machine-wide links map `sous.links.json`.","No project reads its configuration from here, and nothing in here is committed anywhere. Sous recreates whatever it needs, so you can delete any of it; you will lose only cached downloads and the record of which repositories you linked globally."]},store:{title:"cache: the machine-wide recipe store",body:["Sous downloads every recipe version it needs into this directory, one immutable folder per version, and verifies each one against its content hash before using it. Builds read from here, so a version is downloaded once and shared by every project on this machine.","The store is disposable. Everything in it can be fetched again from the pins in each project's lockfile, so you may delete any part of it at any time; `sous repo gc` does the same thing tidily. Nothing here is committed, and editing a stored file only makes sous discard the entry as corrupted."]},"global-repos":{title:"repos: globally linked repository checkouts",body:["`sous repo link --global` clones a recipe repository in here, where every project on this machine can use the same checkout. Each one is an ordinary git working copy; sous reads from it and never writes to it.","Everything here is machine-local and is not committed anywhere. It is safe to delete a checkout once no project links to it any more; sous goes back to the published version of that repository."]},"index-cache":{title:"_indexes: cached repository indexes",body:["Each repository sous knows about publishes one small index file listing the recipes and versions it offers. Sous keeps a copy of each here, beside a `.meta.json` sidecar recording when that copy was fetched.","Sous writes these files; there is nothing here to edit. Deleting any of them is safe and costs only a refetch the next time the repository is consulted. Nothing here is committed."]}};var README_FILENAME="README.md",DEFAULT_POINTER_LINE="Read `./README.md` for information about this directory.";function renderReadme(readme){return`# ${readme.title}
806
807
 
@@ -826,14 +827,14 @@ ${readme.body.join(`
826
827
  `);return joined.endsWith(`
827
828
  `)?joined:`${joined}
828
829
  `}async function readIfPresent(file2){try{return await fs10.readFile(file2,"utf8")}catch(error51){if(error51.code==="ENOENT")return;throw error51}}async function setBlock(file2,entries,dryRun4){let existing=await readIfPresent(file2),next=applyManagedBlock(existing,entries,file2),changed=next!==(existing??"")&&!(existing===void 0&&next==="");return changed&&dryRun4!==!0&&(await fs10.mkdir(path13.dirname(file2),{recursive:!0}),await fs10.writeFile(file2,next,"utf8")),{file:file2,changed,lines:[...entries]}}function createGitignore(){return{async read(file2){return readManagedBlock(await readIfPresent(file2),file2)},write:(file2,lines3,options)=>setBlock(file2,lines3,options?.dryRun),async add(file2,lines3,options){let current=readManagedBlock(await readIfPresent(file2),file2),added=lines3.filter((line,index)=>!current.includes(line)&&lines3.indexOf(line)===index);return setBlock(file2,[...current,...added],options?.dryRun)},async remove(file2,lines3,options){let current=readManagedBlock(await readIfPresent(file2),file2);return setBlock(file2,current.filter(line=>!lines3.includes(line)),options?.dryRun)}}}import{SousError as SousError10}from"@sous-io/plugin-api";var DEFAULT_HTTP_TIMEOUT_MS=15e3,HttpError=class extends SousError10{url;timedOut;constructor(url2,message2,options={}){super(message2,{cause:options.cause,details:options.details}),this.url=url2,this.timedOut=options.timedOut??!1}};function headersOf(headers){let plain3={};return headers.forEach((value,name)=>{plain3[name.toLowerCase()]=value}),plain3}function wrap(response,durationMs,requested){let body2,read=()=>body2??=response.arrayBuffer().then(buffer=>new Uint8Array(buffer));return{status:response.status,statusText:response.statusText,url:response.url||requested,redirected:response.redirected,headers:headersOf(response.headers),durationMs,async text(){return new TextDecoder().decode(await read())},async json(){return JSON.parse(new TextDecoder().decode(await read()))},bytes:read}}function createHttp(deps={}){let request=async req=>{let fetchImpl=deps.fetch??globalThis.fetch;if(typeof fetchImpl!="function")throw new HttpError(req.url,`Sous cannot fetch ${req.url}: this Node runtime provides no global fetch. Sous requires Node 22 or newer.`);let timeoutMs=req.timeoutMs??DEFAULT_HTTP_TIMEOUT_MS,timeout=AbortSignal.timeout(timeoutMs),startedAt=performance.now(),init={method:req.method??"GET",headers:req.headers===void 0?void 0:{...req.headers},body:req.body,redirect:req.redirect??"follow",signal:req.signal===void 0?timeout:AbortSignal.any([timeout,req.signal])};try{let response=await fetchImpl(req.url,init);return wrap(response,performance.now()-startedAt,req.url)}catch(error51){if(timeout.aborted)throw new HttpError(req.url,`The request to ${req.url} did not finish within ${Math.round(timeoutMs/1e3)} seconds.`,{cause:error51,timedOut:!0});if(req.signal?.aborted===!0)throw error51;let reason=error51 instanceof Error?error51.cause instanceof Error?error51.cause.message:error51.message:String(error51);throw new HttpError(req.url,`Sous could not reach ${req.url}.`,{cause:error51,details:[reason]})}};return{request,get:(url2,options={})=>request({...options,url:url2})}}import{existsSync as existsSync2,readFileSync as readFileSync2,realpathSync as realpathSync2}from"node:fs";import path14 from"node:path";import{fileURLToPath as fileURLToPath2}from"node:url";import{PluginError as PluginError4}from"@sous-io/plugin-api";var SOUS_PACKAGE_NAMES=["@sous-io/sous"];function readPackage(file2){try{return JSON.parse(readFileSync2(file2,"utf8"))}catch{return}}function findRoot(from,names2){let current=path14.resolve(from);for(;;){for(let root of[current,path14.join(current,"packages","sous")]){let manifest=readPackage(path14.join(root,"package.json"));if(manifest?.name!==void 0&&names2.includes(manifest.name))return{root,version:manifest.version??"0.0.0"}}let parent=path14.dirname(current);if(parent===current)return;current=parent}}function createPackage(options={}){let identity2;return{identity(){if(identity2!==void 0)return identity2;let names2=options.names??SOUS_PACKAGE_NAMES,bin="bin"in options?options.bin:process.argv[1],startDir=options.startDir??path14.dirname(fileURLToPath2(import.meta.url)),starts=[startDir];bin!==void 0&&existsSync2(bin)&&starts.push(path14.dirname(realpathSync2(bin)));for(let start2 of starts){let found=findRoot(start2,names2);if(found!==void 0)return identity2={name:readPackage(path14.join(found.root,"package.json"))?.name??names2[0],version:found.version,root:found.root,realRoot:realpathSync2(found.root),bin},identity2}throw new PluginError4("@sous-io/plugin-host",`Could not find the installed sous: no package.json named ${names2.join(" or ")} above ${startDir}.`)}}}import{spawn,spawnSync}from"node:child_process";import{constants,existsSync as existsSync3,promises as fs11}from"node:fs";import path15 from"node:path";import{SousError as SousError11}from"@sous-io/plugin-api";var NOT_FOUND_EXIT_CODE=127,ProcessError=class extends SousError11{result;constructor(result){let label=[result.command,...result.args].join(" "),how=result.timedOut?"did not finish in time and was stopped":result.exitCode===null?`was ended by the signal ${result.signal}`:`failed with exit code ${result.exitCode}`,said=(result.stderr.trim()||result.stdout.trim()).split(`
829
- `).filter(line=>line.length>0);super(`The command '${label}' ${how}.`,{details:said}),this.result=result}};function cleanEnvironment(env){let clean2={};for(let[name,value]of Object.entries(env))value!==void 0&&(clean2[name]=value);return clean2}function failedToStart(command,args,error51,startedAt,cwd){let missing=error51.code==="ENOENT",reason=missing&&cwd!==void 0&&!existsSync3(cwd)?`The directory ${cwd} does not exist`:missing?`${command} is not installed, or is not on your PATH`:error51.message;return{command,args,exitCode:NOT_FOUND_EXIT_CODE,signal:null,stdout:"",stderr:reason,durationMs:performance.now()-startedAt,timedOut:!1}}function checked(result,options){if(options.reject===!0&&(result.exitCode!==0||result.timedOut))throw new ProcessError(result);return result}function fromSync(command,args,raw2,startedAt,cwd){let error51=raw2.error;return error51!==void 0&&error51.code!=="ETIMEDOUT"?failedToStart(command,args,error51,startedAt,cwd):{command,args,exitCode:raw2.status,signal:raw2.signal,stdout:raw2.stdout??"",stderr:raw2.stderr??"",durationMs:performance.now()-startedAt,timedOut:error51?.code==="ETIMEDOUT"}}function searchPlaces(env){let windows=process.platform==="win32",key=Object.keys(env).find(name=>name.toUpperCase()==="PATH")??"PATH",directories=(env[key]??"").split(path15.delimiter).filter(entry=>entry.length>0),extensions=windows?["",...(env.PATHEXT??".EXE;.CMD;.BAT").split(";").filter(entry=>entry.length>0)]:[""];return{directories,extensions}}async function isExecutable(file2){try{return(await fs11.stat(file2)).isFile()?(await fs11.access(file2,constants.X_OK),!0):!1}catch{return!1}}function createProcesses(deps){let environmentOf=options=>cleanEnvironment(options.env??deps.env),platform=deps.platform??process.platform,shellFor=(command,options)=>options.windowsShell===!0&&platform==="win32"&&!path15.isAbsolute(command);return{run(command,args,options={}){let startedAt=performance.now();return new Promise((resolve4,reject2)=>{let finish4=result=>{try{resolve4(checked(result,options))}catch(error51){reject2(error51)}},child2=spawn(command,[...args],{cwd:options.cwd,env:environmentOf(options),stdio:["pipe","pipe","pipe"],signal:options.signal,shell:shellFor(command,options)}),stdout="",stderr="",timedOut=!1,done2=!1,timer=options.timeoutMs===void 0?void 0:setTimeout(()=>{timedOut=!0,child2.kill("SIGKILL")},options.timeoutMs),end=result=>{done2||(done2=!0,clearTimeout(timer),finish4(result))};child2.stdout.setEncoding("utf8").on("data",chunk=>stdout+=chunk),child2.stderr.setEncoding("utf8").on("data",chunk=>stderr+=chunk),child2.stdin.on("error",()=>{}),child2.on("error",error51=>{error51.code!=="ABORT_ERR"&&end({...failedToStart(command,args,error51,startedAt,options.cwd),stdout})}),child2.on("close",(exitCode,signal)=>{end({command,args,exitCode,signal,stdout,stderr,durationMs:performance.now()-startedAt,timedOut})}),child2.stdin.end(options.input)})},runSync(command,args,options={}){let startedAt=performance.now(),raw2=spawnSync(command,[...args],{cwd:options.cwd,env:environmentOf(options),input:options.input,encoding:"utf8",timeout:options.timeoutMs,killSignal:"SIGKILL",shell:shellFor(command,options)});return checked(fromSync(command,args,raw2,startedAt,options.cwd),options)},runInteractive(command,args,options={}){let startedAt=performance.now();return new Promise(resolve4=>{let child2=spawn(command,[...args],{cwd:options.cwd,env:environmentOf(options),stdio:"inherit",signal:options.signal,shell:shellFor(command,options)});child2.on("error",()=>resolve4({exitCode:NOT_FOUND_EXIT_CODE,signal:null,durationMs:performance.now()-startedAt})),child2.on("close",(exitCode,signal)=>resolve4({exitCode,signal,durationMs:performance.now()-startedAt}))})},async which(command,env=deps.env){let{directories,extensions}=searchPlaces(env),candidates=path15.isAbsolute(command)||command.includes("/")?[command]:directories.map(directory=>path15.join(directory,command));for(let candidate of candidates)for(let extension of extensions)if(await isExecutable(candidate+extension))return candidate+extension}}}import os3 from"node:os";import path16 from"node:path";var SOUS_HOME_DIR_NAME=".sous",SOUS_HOME_ENV_VAR="SOUS_HOME",STORE_DIR_NAME="cache",INDEX_CACHE_DIR_NAME="_indexes",GLOBAL_REPOS_DIR_NAME="repos",GLOBAL_LINKS_FILENAME="sous.links.json",READ_STRATEGIES_FILENAME="read-strategies.json";function expandHome(value){return value==="~"?os3.homedir():value.startsWith("~/")||value.startsWith("~\\")?path16.join(os3.homedir(),value.slice(2)):value}function resolveSousHomePaths(env){let raw2=env[SOUS_HOME_ENV_VAR],root=typeof raw2=="string"&&raw2.trim().length>0?path16.normalize(path16.resolve(expandHome(raw2.trim()))):path16.join(os3.homedir(),SOUS_HOME_DIR_NAME),store2=path16.join(root,STORE_DIR_NAME);return{root,store:store2,indexCache:path16.join(store2,INDEX_CACHE_DIR_NAME),repos:path16.join(root,GLOBAL_REPOS_DIR_NAME),links:path16.join(root,GLOBAL_LINKS_FILENAME),readStrategies:path16.join(store2,READ_STRATEGIES_FILENAME)}}function createSousHome(getEnv){return{paths:env=>resolveSousHomePaths(env??getEnv()),resolve:(...segments)=>path16.join(resolveSousHomePaths(getEnv()).root,...segments)}}var package_default3={name:"@sous-io/plugin-host",version:"1.0.11",description:"The machine sous runs on: processes, HTTP, globs and paths, sous home, self-describing directories, the .gitignore block, package identity.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*",glob:"^13.0.6",minimatch:"^10.2.4"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME2="@sous-io/plugin-host",pointerFileSchema=jsonSchema6({type:"object",properties:{id:{type:"string"},fileName:{type:"string",minLength:1},content:{type:"string"}},required:["id","fileName"]}),hostPlugin=definePlugin3({name:PLUGIN_NAME2,version:package_default3.version,description:"The machine sous runs on: processes, HTTP, globs and paths, sous home, self-describing directories, the .gitignore block, package identity.",dependsOn:{},register(sous){sous.entities.define("pointer-file",pointerFileSchema,{description:"A one-line file written once into every self-describing directory, telling an agent to read its README."}),sous.services.add("host.processes",(_config,ctx)=>createProcesses({env:ctx.env}),{lifetime:"singleton"}),sous.services.add("host.http",()=>createHttp(),{lifetime:"singleton"}),sous.services.add("host.globs",()=>hostGlobs,{lifetime:"singleton"}),sous.services.add("host.sous-home",(_config,ctx)=>createSousHome(()=>ctx.env),{lifetime:"singleton"}),sous.services.add("host.gitignore",()=>createGitignore(),{lifetime:"singleton"}),sous.services.add("host.package",()=>createPackage(),{lifetime:"singleton"}),sous.services.add("host.directories",(_config,ctx)=>createDirectories({entities:ctx.entities,sousHome:ctx.services.get("host.sous-home")}),{lifetime:"config"})}});import{definePlugin as definePlugin4}from"@sous-io/plugin-api";import{promises as fs12}from"node:fs";import os4 from"node:os";import path17 from"node:path";import{SousError as SousError12}from"@sous-io/plugin-api";var GIT_TIMEOUT_EXIT_CODE=124,GitError=class extends SousError12{result;cwd;timedOut;constructor(result,options={}){let timedOut=options.timedOut??!1,said=(result.stderr.trim()||result.stdout.trim()).split(`
830
+ `).filter(line=>line.length>0);super(`The command '${label}' ${how}.`,{details:said}),this.result=result}};function cleanEnvironment(env){let clean2={};for(let[name,value]of Object.entries(env))value!==void 0&&(clean2[name]=value);return clean2}function failedToStart(command,args,error51,startedAt,cwd){let missing=error51.code==="ENOENT",reason=missing&&cwd!==void 0&&!existsSync3(cwd)?`The directory ${cwd} does not exist`:missing?`${command} is not installed, or is not on your PATH`:error51.message;return{command,args,exitCode:NOT_FOUND_EXIT_CODE,signal:null,stdout:"",stderr:reason,durationMs:performance.now()-startedAt,timedOut:!1}}function checked(result,options){if(options.reject===!0&&(result.exitCode!==0||result.timedOut))throw new ProcessError(result);return result}function fromSync(command,args,raw2,startedAt,cwd){let error51=raw2.error;return error51!==void 0&&error51.code!=="ETIMEDOUT"?failedToStart(command,args,error51,startedAt,cwd):{command,args,exitCode:raw2.status,signal:raw2.signal,stdout:raw2.stdout??"",stderr:raw2.stderr??"",durationMs:performance.now()-startedAt,timedOut:error51?.code==="ETIMEDOUT"}}function searchPlaces(env){let windows=process.platform==="win32",key=Object.keys(env).find(name=>name.toUpperCase()==="PATH")??"PATH",directories=(env[key]??"").split(path15.delimiter).filter(entry=>entry.length>0),extensions=windows?["",...(env.PATHEXT??".EXE;.CMD;.BAT").split(";").filter(entry=>entry.length>0)]:[""];return{directories,extensions}}async function isExecutable(file2){try{return(await fs11.stat(file2)).isFile()?(await fs11.access(file2,constants.X_OK),!0):!1}catch{return!1}}function createProcesses(deps){let environmentOf=options=>cleanEnvironment(options.env??deps.env),platform=deps.platform??process.platform,shellFor=(command,options)=>options.windowsShell===!0&&platform==="win32"&&!path15.isAbsolute(command);return{run(command,args,options={}){let startedAt=performance.now();return new Promise((resolve4,reject2)=>{let finish4=result=>{try{resolve4(checked(result,options))}catch(error51){reject2(error51)}},child2=spawn(command,[...args],{cwd:options.cwd,env:environmentOf(options),stdio:["pipe","pipe","pipe"],signal:options.signal,shell:shellFor(command,options)}),stdout="",stderr="",timedOut=!1,done2=!1,timer=options.timeoutMs===void 0?void 0:setTimeout(()=>{timedOut=!0,child2.kill("SIGKILL")},options.timeoutMs),end=result=>{done2||(done2=!0,clearTimeout(timer),finish4(result))};child2.stdout.setEncoding("utf8").on("data",chunk=>stdout+=chunk),child2.stderr.setEncoding("utf8").on("data",chunk=>stderr+=chunk),child2.stdin.on("error",()=>{}),child2.on("error",error51=>{error51.code!=="ABORT_ERR"&&end({...failedToStart(command,args,error51,startedAt,options.cwd),stdout})}),child2.on("close",(exitCode,signal)=>{end({command,args,exitCode,signal,stdout,stderr,durationMs:performance.now()-startedAt,timedOut})}),child2.stdin.end(options.input)})},runSync(command,args,options={}){let startedAt=performance.now(),raw2=spawnSync(command,[...args],{cwd:options.cwd,env:environmentOf(options),input:options.input,encoding:"utf8",timeout:options.timeoutMs,killSignal:"SIGKILL",shell:shellFor(command,options)});return checked(fromSync(command,args,raw2,startedAt,options.cwd),options)},runInteractive(command,args,options={}){let startedAt=performance.now();return new Promise(resolve4=>{let child2=spawn(command,[...args],{cwd:options.cwd,env:environmentOf(options),stdio:"inherit",signal:options.signal,shell:shellFor(command,options)});child2.on("error",()=>resolve4({exitCode:NOT_FOUND_EXIT_CODE,signal:null,durationMs:performance.now()-startedAt})),child2.on("close",(exitCode,signal)=>resolve4({exitCode,signal,durationMs:performance.now()-startedAt}))})},async which(command,env=deps.env){let{directories,extensions}=searchPlaces(env),candidates=path15.isAbsolute(command)||command.includes("/")?[command]:directories.map(directory=>path15.join(directory,command));for(let candidate of candidates)for(let extension of extensions)if(await isExecutable(candidate+extension))return candidate+extension}}}import os3 from"node:os";import path16 from"node:path";var SOUS_HOME_DIR_NAME=".sous",SOUS_HOME_ENV_VAR="SOUS_HOME",STORE_DIR_NAME="cache",INDEX_CACHE_DIR_NAME="_indexes",GLOBAL_REPOS_DIR_NAME="repos",GLOBAL_LINKS_FILENAME="sous.links.json",READ_STRATEGIES_FILENAME="read-strategies.json";function expandHome(value){return value==="~"?os3.homedir():value.startsWith("~/")||value.startsWith("~\\")?path16.join(os3.homedir(),value.slice(2)):value}function resolveSousHomePaths(env){let raw2=env[SOUS_HOME_ENV_VAR],root=typeof raw2=="string"&&raw2.trim().length>0?path16.normalize(path16.resolve(expandHome(raw2.trim()))):path16.join(os3.homedir(),SOUS_HOME_DIR_NAME),store2=path16.join(root,STORE_DIR_NAME);return{root,store:store2,indexCache:path16.join(store2,INDEX_CACHE_DIR_NAME),repos:path16.join(root,GLOBAL_REPOS_DIR_NAME),links:path16.join(root,GLOBAL_LINKS_FILENAME),readStrategies:path16.join(store2,READ_STRATEGIES_FILENAME)}}function createSousHome(getEnv){return{paths:env=>resolveSousHomePaths(env??getEnv()),resolve:(...segments)=>path16.join(resolveSousHomePaths(getEnv()).root,...segments)}}var package_default3={name:"@sous-io/plugin-host",version:"1.0.12",description:"The machine sous runs on: processes, HTTP, globs and paths, sous home, self-describing directories, the .gitignore block, package identity.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*",glob:"^13.0.6",minimatch:"^10.2.4"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME2="@sous-io/plugin-host",pointerFileSchema=jsonSchema6({type:"object",properties:{id:{type:"string"},fileName:{type:"string",minLength:1},content:{type:"string"}},required:["id","fileName"]}),hostPlugin=definePlugin3({name:PLUGIN_NAME2,version:package_default3.version,description:"The machine sous runs on: processes, HTTP, globs and paths, sous home, self-describing directories, the .gitignore block, package identity.",dependsOn:{},register(sous){sous.entities.define("pointer-file",pointerFileSchema,{description:"A one-line file written once into every self-describing directory, telling an agent to read its README."}),sous.services.add("host.processes",(_config,ctx)=>createProcesses({env:ctx.env}),{lifetime:"singleton"}),sous.services.add("host.http",()=>createHttp(),{lifetime:"singleton"}),sous.services.add("host.globs",()=>hostGlobs,{lifetime:"singleton"}),sous.services.add("host.sous-home",(_config,ctx)=>createSousHome(()=>ctx.env),{lifetime:"singleton"}),sous.services.add("host.gitignore",()=>createGitignore(),{lifetime:"singleton"}),sous.services.add("host.package",()=>createPackage(),{lifetime:"singleton"}),sous.services.add("host.directories",(_config,ctx)=>createDirectories({entities:ctx.entities,sousHome:ctx.services.get("host.sous-home")}),{lifetime:"config"})}});import{definePlugin as definePlugin4}from"@sous-io/plugin-api";import{promises as fs12}from"node:fs";import os4 from"node:os";import path17 from"node:path";import{SousError as SousError12}from"@sous-io/plugin-api";var GIT_TIMEOUT_EXIT_CODE=124,GitError=class extends SousError12{result;cwd;timedOut;constructor(result,options={}){let timedOut=options.timedOut??!1,said=(result.stderr.trim()||result.stdout.trim()).split(`
830
831
  `).filter(line=>line.length>0),details=[];options.cwd!==void 0&&details.push(`It was run in ${options.cwd}.`),details.push(...said),result.exitCode===127&&details.push("Sous fetches recipes with git, so git must be installed and on your PATH."),super(timedOut?`The command 'git ${result.args.join(" ")}' did not finish in time and was stopped.`:`The command 'git ${result.args.join(" ")}' failed with exit code ${result.exitCode}.`,{details}),this.result=result,this.cwd=options.cwd,this.timedOut=timedOut}};var LF_CHECKOUT_OPTIONS=["--config","core.autocrlf=false","--config","core.eol=lf"];function chomp(text){return text.replace(/\r?\n$/,"")}function looksLikeOption(text){return text.startsWith("-")}function createGitRunner(deps){let environmentFor=options=>({...deps.env,...options.env,GIT_TERMINAL_PROMPT:"0"}),toResult=(args,raw2)=>({args,exitCode:raw2.timedOut?GIT_TIMEOUT_EXIT_CODE:raw2.exitCode??1,stdout:chomp(raw2.stdout),stderr:raw2.stderr.trim(),durationMs:raw2.durationMs}),check3=(result,raw2,options)=>{if((options.reject??!0)&&result.exitCode!==0)throw new GitError(result,{cwd:options.cwd,timedOut:raw2.timedOut});return result},processOptions=(args,options)=>({cwd:options.cwd,env:environmentFor(options),input:options.input,timeoutMs:options.timeoutMs,signal:options.signal,label:`git ${args[0]??""}`.trim()}),run=async(args,options)=>{let raw2=await deps.processes.run("git",args,processOptions(args,options));return check3(toResult(args,raw2),raw2,options)},ask=async(args,cwd)=>{let result=await run(args,{cwd,reject:!1});return result.exitCode===0&&result.stdout.length>0?result.stdout:void 0},lines3=text=>(text??"").split(`
831
- `).map(line=>line.trim()).filter(line=>line.length>0);return{run,runSync(args,options){let raw2=deps.processes.runSync("git",args,processOptions(args,options));return check3(toResult(args,raw2),raw2,options)},async available(){return await deps.processes.which("git",deps.env)!==void 0},async version(){let raw2=await deps.processes.run("git",["--version"],{env:environmentFor({}),label:"git --version"});return raw2.exitCode===0?/(\d+\.\d+(?:\.\d+)?)/.exec(raw2.stdout)?.[1]:void 0},root:cwd=>ask(["rev-parse","--show-toplevel"],cwd),currentBranch:cwd=>ask(["symbolic-ref","--quiet","--short","HEAD"],cwd),async revParse(ref,cwd){if(!looksLikeOption(ref))return ask(["rev-parse","--verify","--quiet",`${ref}^{commit}`],cwd)},async status(cwd){let parts=(await run(["status","--porcelain=v1","-z"],{cwd})).stdout.split("\0"),entries=[];for(let index=0;index<parts.length;index+=1){let part=parts[index];if(part.length<4)continue;let code=part.slice(0,2),entryPath=part.slice(3);code.includes("R")||code.includes("C")?(entries.push({path:entryPath,code,from:parts[index+1]??""}),index+=1):entries.push({path:entryPath,code})}return entries},async tags(cwd,pattern){return lines3((await run(pattern===void 0?["tag","--list"]:["tag","--list",pattern],{cwd})).stdout)},async remoteUrl(cwd,remote="origin"){return looksLikeOption(remote)?void 0:ask(["remote","get-url",remote],cwd)},async clone(url2,directory,options={}){let parent=path17.dirname(directory),sparse=options.sparsePaths!==void 0&&options.sparsePaths.length>0,args=["clone",...LF_CHECKOUT_OPTIONS];options.depth!==void 0&&options.depth>0&&args.push("--depth",String(options.depth)),sparse&&args.push("--filter=blob:none","--sparse"),options.branch!==void 0&&args.push("--branch",options.branch),options.noCheckout===!0&&args.push("--no-checkout"),args.push("--",url2,directory),await fs12.mkdir(parent,{recursive:!0}),await run(args,{cwd:parent,env:options.env,signal:options.signal}),sparse&&await run(["sparse-checkout","set","--",...options.sparsePaths],{cwd:directory,env:options.env,signal:options.signal})},async readRemoteFile(url2,filePath,options={}){if(looksLikeOption(url2))throw new GitError({args:["fetch",url2],exitCode:1,stdout:"",stderr:`${url2} is not a repository address.`,durationMs:0});let ref=options.ref??"HEAD",tmp=await fs12.mkdtemp(path17.join(deps.env.TMPDIR??os4.tmpdir(),"sous-git-read-")),common={cwd:tmp,env:options.env,timeoutMs:options.timeoutMs,signal:options.signal};try{await run(["init","--quiet"],common),await run(["remote","add","origin","--",url2],common),await run(["fetch","--quiet","--depth","1","--filter=blob:none","origin",ref],common);let shown=await run(["show",`FETCH_HEAD:${filePath}`],{...common,reject:!1});if(shown.exitCode!==0)throw new GitError(shown,{cwd:tmp});return shown.stdout}finally{await fs12.rm(tmp,{recursive:!0,force:!0})}}}}var package_default4={name:"@sous-io/plugin-git",version:"1.0.11",description:"The one git runner.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME3="@sous-io/plugin-git",gitPlugin=definePlugin4({name:PLUGIN_NAME3,version:package_default4.version,description:"The one git runner.",dependsOn:{"@sous-io/plugin-host":`^${package_default4.version}`},register(sous){sous.services.add("git.runner",(_config,ctx)=>createGitRunner({processes:ctx.services.get("host.processes"),env:ctx.env}),{lifetime:"singleton"})}});import{definePlugin as definePlugin5,jsonSchema as jsonSchema7}from"@sous-io/plugin-api";import{ConfigError as ConfigError8}from"@sous-io/plugin-api";var REF_KINDS=["repo","namespace","recipe","recipeFile","variable","envVar"],KIND_LABELS={repo:"repository",namespace:"namespace",recipe:"recipe",recipeFile:"recipe file",variable:"variable",envVar:"environment variable"};function repoOf(ref){switch(ref.kind){case"repo":return ref;case"namespace":return ref.repo;case"recipe":return ref.namespace?.repo??ref.repo;case"recipeFile":return repoOf(ref.recipe);case"variable":return ref.recipe===void 0?ref.repo:repoOf(ref.recipe)??ref.repo;case"envVar":return}}function locationOf(ref){return repoOf(ref)?.location}function namespaceOf(ref){switch(ref.kind){case"namespace":return ref;case"recipe":return ref.namespace;case"recipeFile":return ref.recipe.namespace;case"variable":return ref.recipe?.namespace;default:return}}function recipeOf(ref){switch(ref.kind){case"recipe":return ref;case"recipeFile":case"variable":return ref.recipe;default:return}}function rangeOf(ref){return ref.kind==="recipe"||ref.kind==="recipeFile"||ref.kind==="repo"?ref.range:void 0}function qualificationOf(candidate){return candidate.kind==="envVar"?3:candidate.kind==="repo"||repoOf(candidate)!==void 0?0:candidate.kind==="recipe"&&candidate.namespace!==void 0||candidate.kind==="recipeFile"||candidate.kind==="variable"&&candidate.recipe!==void 0?1:2}function isStoredKind(ref){return ref.kind==="namespace"||ref.kind==="recipe"&&ref.namespace!==void 0}function shortKey(ref){let namespace=namespaceOf(ref)?.name,recipe=ref.kind==="namespace"?void 0:recipeOf(ref)?.name;return namespace===void 0?recipe??"":recipe===void 0?namespace:`${namespace}/${recipe}`}function repoPart(repo){return repo===void 0?void 0:repo.name??repo.location?.identity}function pathPart(ref){switch(ref.kind){case"repo":return ref.browsed===void 0?"":`tree/${ref.browsed}`;case"namespace":return ref.name;case"recipe":return ref.namespace===void 0?ref.name:`${ref.namespace.name}/${ref.name}`;case"recipeFile":return`${pathPart(ref.recipe)}/${ref.path}`;case"variable":return`${ref.recipe===void 0?"":`${pathPart(ref.recipe)}.`}${ref.name}`;case"envVar":return ref.name}}function refKey(ref){let repo=ref.kind==="envVar"?void 0:repoPart(repoOf(ref)),rest=pathPart(ref);return repo===void 0?rest:ref.kind==="repo"&&rest===""?repo:`${repo}:${rest}`}function storedKey(ref){return ref.kind==="repo"?refKey(ref):pathPart(ref)}function refIdentity(ref){return`${ref.kind} ${refKey(ref)}`}function repoLabel(repo){return repo?.name??repo?.location?.url??"unknown"}function isNamedRef(ref){return ref.kind==="namespace"||ref.kind==="recipe"&&ref.namespace!==void 0}function namespaceRef(name,repo){return{kind:"namespace",name,...repo===void 0?{}:{repo:{kind:"repo",name:repo}}}}function recipeRef(namespace,name,options={}){return{kind:"recipe",name,namespace:namespaceRef(namespace,options.repo),...options.range===void 0?{}:{range:options.range}}}function formatter(locations){let qualified=(repo,rest)=>{if(repo===void 0)return rest;if(repo.name!==void 0)return rest===""?repo.name:`${repo.name}:${rest}`;if(repo.location!==void 0){let{host,repoPath,url:url2,provider}=repo.location,reader=provider==="local"?void 0:locations().host(provider);return reader!==void 0?reader.formatLocator(host,repoPath,rest):rest===""?url2:`${url2}/${rest}`}return rest},format3=ref=>{let body2=qualified(ref.kind==="envVar"?void 0:repoOf(ref),pathPart(ref)),range3=rangeOf(ref),pairs=Object.entries(ref.vars??{}).map(([name,value])=>`${encodeURIComponent(name)}=${encodeURIComponent(value)}`);return`${body2}${range3===void 0?"":`@${range3}`}${pairs.length===0?"":`?${pairs.join("&")}`}`},spelling=ref=>{let repo=ref.kind==="envVar"?void 0:repoOf(ref);return repo!==void 0&&repo.name===void 0&&repo.location!==void 0?format3(ref):refKey(ref)};return{format:format3,spelling,describe:ref=>{let summary=ref.description===void 0?"":`: ${ref.description}`,key=spelling(ref);switch(ref.kind){case"repo":{let where2=ref.location?.url;return`${key} (the repository '${ref.name??key}'${where2===void 0?"":`, at ${where2}`})`}case"namespace":return`${key} (the whole namespace '${ref.name}' in the repository '${repoLabel(ref.repo)}')`;case"recipe":return`${key} (the recipe '${ref.name}' in the namespace '${ref.namespace?.name??"unknown"}' of the repository '${repoLabel(repoOf(ref))}'${summary})`;case"recipeFile":return`${key} (the file '${ref.path}' of the recipe '${pathPart(ref.recipe)}'${summary})`;case"variable":return`${key} (the variable '${ref.name}' of the recipe '${ref.recipe===void 0?"unknown":pathPart(ref.recipe)}'${summary})`;case"envVar":{let first2=ref.variables?.[0],answers=first2===void 0?"":` answering '${first2.name}' of the recipe '${first2.recipe===void 0?"unknown":pathPart(first2.recipe)}'`;return`${ref.name} (the environment variable${answers}${summary})`}}}}}function createRefsFormat(ctx){let written=formatter(()=>ctx.services.get("refs.locations")),storedKeys=new Map,parseNamedRef=(input,from="commandLine")=>{let{refs}=ctx.services.get("refs.resolver").parse(input,from),named=refs.filter(ref=>isNamedRef(ref)&&locationOf(ref)===void 0);if(named.length===1&&!refs.some(ref=>locationOf(ref)!==void 0))return named[0];throw new ConfigError8(`Invalid ref '${input}': this needs a namespace or a recipe named by its short form, such as 'workflow/alpha', and this ref names a location.`)},readStoredKey=key=>{let known=storedKeys.get(key);if(known!==void 0)return known;let parsed=parseNamedRef(key,"lockfile"),read=parsed.kind==="namespace"?{namespace:parsed.name}:{namespace:parsed.namespace.name,name:parsed.name};return storedKeys.set(key,read),read};return{key:storedKey,identity(ref){let location=locationOf(ref);if(location===void 0)return refKey(ref);let rest=pathPart(ref);return rest===""?location.identity:`${location.identity}:${rest}`},...written,kindLabel:ref=>KIND_LABELS[ref.kind],splitRecipeKey(key){let{namespace,name}=readStoredKey(key);if(name===void 0)throw new ConfigError8(`Invalid ref '${key}': a recipe key names a namespace and a recipe.`,{details:["A stored key is written as 'namespace' or 'namespace/recipe'."]});return{namespace,name}},namespaceOfKey:key=>readStoredKey(key).namespace,namespaceRef,recipeRef,parseNamedRef,partsOf(ref){let repo=repoOf(ref),namespace=namespaceOf(ref),recipe=recipeOf(ref),range3=rangeOf(ref);return{...repo===void 0?{}:{repo},...namespace===void 0?{}:{namespace},...recipe===void 0?{}:{recipe},...range3===void 0?{}:{range:range3}}}}}var VALID_NAME=/^[a-z][a-z0-9-]*$/,hashNameSchema={"~standard":{version:1,vendor:"sous",validate(value){let entry=value,issues=[];return typeof entry!="object"||entry===null?{issues:[{message:"Expected an object."}]}:((typeof entry.id!="string"||!VALID_NAME.test(entry.id))&&issues.push({message:`The name '#${String(entry.id)}' is invalid: a name is lowercase kebab-case, a letter then letters, digits or hyphens.`,path:["id"]}),typeof entry.description!="string"&&issues.push({message:"Required, but missing.",path:["description"]}),entry.bases!==void 0&&typeof entry.bases!="function"&&issues.push({message:"Expected a function.",path:["bases"]}),entry.view!==void 0&&typeof entry.view!="function"&&issues.push({message:"Expected a function.",path:["view"]}),entry.bases!==void 0&&entry.view!==void 0&&issues.push({message:"A name either stands for directories ('bases') or lists files ('view'), not both."}),issues.length>0?{issues}:{value:entry})}}},projectHashName={id:"project",description:"the root directory of the project being built.",bases:ctx=>ctx.project===void 0?[]:[ctx.project.root]};import{ConfigError as ConfigError9}from"@sous-io/plugin-api";var SHORT_NAME=/^[a-z][a-z0-9-]*$/;function repositoryIdentity(canonical){let name=canonical.name.replace(/\.git$/i,"");return identitySegments(`${canonical.host}/${canonical.owner}/${name}`).join("/")}function identitySegments(identity2){return identity2.split("/").map(segment=>segment.trim().toLowerCase()).filter(segment=>segment.length>0)}function shortNameFromIdentity(identity2){let segments=identitySegments(identity2),cleaned=(segments[segments.length-1]??"").replace(/[^a-z0-9-]+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"");return SHORT_NAME.test(cleaned)?cleaned:cleaned.length===0?"repository":`repo-${cleaned}`}var REPOSITORY_HOST_KIND="repository-host",URL_SCHEMES=new Set(["http","https","ssh","git","git+ssh","ssh+git"]),SCHEME=/^([a-z][a-z0-9+.-]*):\/\/(.*)$/is;function repositoryHosts(entities){return entities.list(REPOSITORY_HOST_KIND)}function schemesOf(host){return host.schemes??[host.id]}function hostedIds(hosts){return hosts.filter(host=>host.defaultHost!==void 0).map(host=>host.id).sort()}function createRefsLocations(entities){let hosts=()=>repositoryHosts(entities),hostById=id=>hosts().find(host=>host.id===id),hostFor2=url2=>hosts().find(host=>host.matches(url2)),asUrl=url2=>{let scheme=SCHEME.exec(url2.trim());if(scheme===null||URL_SCHEMES.has(scheme[1].toLowerCase()))return{url:url2};let name=scheme[1].toLowerCase(),host=hosts().find(entry=>schemesOf(entry).includes(name));if(host?.defaultHost===void 0)return{url:url2};let path103=scheme[2].replace(/^\/+/,"");return{url:`https://${(path103.split("/")[0]??"").includes(".")?path103:`${host.defaultHost}/${path103}`}`,host}},requireHost=(url2,provider)=>{let known=hosts().map(host=>host.id).join(", ")||"none";if(provider!==void 0){let named=hostById(provider);if(named===void 0)throw new ConfigError9(`The repository at ${url2} names the provider '${provider}', which sous does not have.`,{details:[`Sous has these providers: ${known}.`]});if(!named.matches(url2)){let owner=hostFor2(url2);if(owner!==void 0&&owner.id!==named.id)throw new ConfigError9(`The ${named.id} provider does not handle ${url2}; that is ${owner.id==="local"?"a local path":`a ${owner.id} URL`}, which the ${owner.id} provider handles.`,{details:[`Drop '--provider' and let sous work it out, or name '${owner.id}'.`]})}return named}let detected=hostFor2(url2);if(detected!==void 0)return detected;throw new ConfigError9(`Sous does not recognize the host in the repository URL ${url2}.`,{details:[`Sous has these providers: ${known}. For a self-hosted instance, name the provider that host runs on the repository entry, as in 'sous repo add ${url2} --provider <provider>'.`]})},canonicalize=(url2,provider)=>{let target=asUrl(url2);return(provider===void 0&&target.host!==void 0?target.host:requireHost(target.url,provider)).canonicalize(target.url)};return{fromUrl(url2,provider){try{let target=asUrl(url2),host=provider===void 0&&target.host!==void 0?target.host:requireHost(target.url,provider),canonical=host.canonicalize(target.url);return{provider:host.id,host:canonical.host,repoPath:`${canonical.owner}/${canonical.name}`,identity:repositoryIdentity(canonical),url:url2}}catch{return}},locationFor(provider,host,repoPath){let reader=hostById(provider);if(reader===void 0)throw new ConfigError9(`No provider '${provider}' reads the repository ${host}/${repoPath}.`);let url2=`https://${host}/${repoPath}`;return{provider,host,repoPath,identity:repositoryIdentity(reader.canonicalize(url2)),url:url2}},canonicalize,identity:(url2,provider)=>repositoryIdentity(canonicalize(url2,provider)),identityOf:repository=>repositoryIdentity(repository),hostFor:hostFor2,host:hostById,hosts,shortName:shortNameFromIdentity}}function tryLocationFor(locations,provider,host,repoPath){try{return locations.locationFor(provider,host,repoPath)}catch{return}}var SCHEME2=/^[a-z][a-z0-9+.-]*:\/\//i,SCP=/^[^@\s/:]+@([^@\s/:]+):(.+)$/s;function splitter(id,order,read){return{id,order,split:(state,ctx)=>state.ref!==void 0?[state]:read(state,ctx)}}function finishRef(state,ref){let withVars=state.vars===void 0?ref:{...ref,vars:state.vars};return{...state,rest:"",ref:withVars}}var SCHEME_PATTERN=/^([a-z][a-z0-9+.-]*):\/\/(.*)$/is,SCP_PATTERN=/^[^@\s/:]+@([^@\s/:]+):(.+)$/s,URL_SCHEMES2=new Set(["http","https","ssh","git","git+ssh","ssh+git"]),LOCAL_SCHEMES=new Set(["local","file"]);function looksLikeLocation(ref){let trimmed=ref.trim();if(SCHEME_PATTERN.test(trimmed)||SCP_PATTERN.test(trimmed))return!0;let first2=trimmed.split("/")[0]??"";return trimmed.includes("/")&&first2.includes(".")&&!first2.includes(":")}function pathSegments(pathname){return pathname.split(/[?#]/)[0].split("/").map(segment=>{try{return decodeURIComponent(segment)}catch{return segment}}).filter(segment=>segment.length>0)}function local(state,path103){return finishRef(state,{kind:"repo",location:{provider:"local",host:"localhost",repoPath:path103,identity:`localhost/${path103.replace(/^\/+/,"")}`,url:state.rest}})}function forHost(state,hosts,hostName,segments){let probe=`https://${hostName}/${segments.slice(0,2).join("/")}`,host=hosts.find(entry=>entry.matches(probe));if(host!==void 0&&host.defaultHost!==void 0)return{host,hostName,segments};let ids=hostedIds(hosts);state.problems.push(`sous does not recognize the host '${hostName}'. For a self-hosted instance, write the location with the provider's scheme and the host, as in '${ids[0]??"gitlab"}://${hostName}/owner/repository/namespace/recipe' (sous has these providers: ${ids.join(", ")||"none"}).`)}function take(state,hosts,scheme){let body2=state.rest;if(scheme!==null){let name=scheme[1].toLowerCase();if(URL_SCHEMES2.has(name)){let url2;try{url2=new URL(body2)}catch{state.problems.push("the URL could not be read.");return}return forHost(state,hosts,url2.host.toLowerCase(),pathSegments(url2.pathname))}let host=hosts.find(entry=>schemesOf(entry).includes(name));if(host?.defaultHost===void 0){state.problems.push(`'${name}' is not a provider sous can read a location from. The scheme of a locator is the provider's own identifier; sous has these: ${hostedIds(hosts).join(", ")||"none"}. An ordinary 'https://' URL works too.`);return}let segments=pathSegments(scheme[2]),hostName=host.defaultHost;return segments[0]?.includes(".")===!0&&(hostName=segments[0].toLowerCase(),segments=segments.slice(1)),{host,hostName,segments}}let scp=SCP_PATTERN.exec(body2);if(scp!==null)return forHost(state,hosts,scp[1].toLowerCase(),pathSegments(scp[2]));let all=pathSegments(body2);return forHost(state,hosts,all[0].toLowerCase(),all.slice(1))}function readLocation(state,locations){if(state.repo!==void 0||!looksLikeLocation(state.rest))return[state];let scheme=SCHEME_PATTERN.exec(state.rest);if(scheme!==null&&LOCAL_SCHEMES.has(scheme[1].toLowerCase()))return[local(state,scheme[2])];let taken=take(state,locations.hosts(),scheme);if(taken===void 0)return[];let{host,hostName,segments}=taken,specific=[],repositories=[];for(let reading of host.readLocation({host:hostName,segments})){let location=tryLocationFor(locations,host.id,hostName,reading.repoPath);if(location===void 0)continue;if(reading.browsed!==void 0){let browsed=reading.browsed.replace(/^\/+|\/+$/g,"");browsed.length>0&&specific.push(finishRef(state,{kind:"repo",location,browsed,...state.range===void 0?{}:{range:state.range}}));continue}let named=reading.named??[];named.length===0?repositories.push({kind:"repo",location}):specific.push({...state,rest:named.join("/"),repo:{kind:"repo",location}})}return specific.length>0?specific:repositories.length===0?(state.problems.push(`the ${host.id} provider cannot read a namespace or a recipe from this location. After the repository, a location names a namespace and optionally a recipe, as in '${host.formatLocator(hostName,"owner/repository","workflow/alpha")}'.`),[]):state.range!==void 0?(state.problems.push("a version range applies to a recipe, not to a repository."),[]):repositories.map(repo=>finishRef(state,repo))}var locationSplitter=splitter("location",30,(state,ctx)=>readLocation(state,ctx.services.get("refs.locations")));var NAME_ANY_CASE=/^[a-z][a-z0-9-]*$/i;var VARIABLE_NAME=/^[a-z][a-zA-Z0-9]*$/,ENV_VAR_NAME=/^[A-Za-z_][A-Za-z0-9_]*$/,GLOB_NAME=/^[A-Za-z0-9_\-.*?[\]{},!^]+$/;function isGlobName(text,globs){return globs.hasGlob(text)&&GLOB_NAME.test(text)}function splitSegments(text){let segments=[],depth=0,current="";for(let character of text){if(character==="{"&&(depth+=1),character==="}"&&depth>0&&(depth-=1),character==="/"&&depth===0){segments.push(current),current="";continue}current+=character}return segments.push(current),segments}var FILE_PATH=/^[^\s\\]+$/,NAMESPACE_NOT_VERSIONED="a version range applies to a recipe, and namespaces are not versioned. Name a recipe, as in 'workflow/task-files@^1.2.0'.";function isName(reader,segment){return NAME_ANY_CASE.test(segment)||isGlobName(segment,reader.globs)}function isVariableName(reader,segment){return VARIABLE_NAME.test(segment)||isGlobName(segment,reader.globs)}function badName(what,name){return`the ${what} '${name}' must be kebab-case: a letter, then letters, digits or hyphens.`}function withGlob(reader,names2){return names2.some(name=>reader.globs.hasGlob(name))?{glob:!0}:{}}function readOne(reader,text){let{state,make:make2,ns:ns2}=reader,{repo,range:range3}=state,dot=text.indexOf("."),located=repo?.location!==void 0,inRepo=repo===void 0?{}:{repo};if(!located&&dot>0&&dot<text.length-1&&range3===void 0){let left=text.slice(0,dot),right=text.slice(dot+1);isName(reader,left)&&isVariableName(reader,right)&&make2({kind:"variable",name:right,recipe:{kind:"recipe",name:left,...inRepo},...withGlob(reader,[left,right])})}isName(reader,text)&&(range3===void 0?(make2({...ns2(text),...withGlob(reader,[text])}),repo===void 0&&make2({kind:"repo",name:text,...withGlob(reader,[text])})):state.problems.push(NAMESPACE_NOT_VERSIONED),located||make2({kind:"recipe",name:text,...inRepo,...range3===void 0?{}:{range:range3},...withGlob(reader,[text])})),!located&&range3===void 0&&isVariableName(reader,text)&&make2({kind:"variable",name:text,...inRepo,...withGlob(reader,[text])});let readsAsOther=repo===void 0&&(VARIABLE_NAME.test(text)||ENV_VAR_NAME.test(text));!isName(reader,text)&&!readsAsOther&&dot<=0&&state.problems.push(badName("namespace",text))}function readTwo(reader,namespace,second){let{state,make:make2,ns:ns2}=reader,{range:range3}=state,dot=second.indexOf(".");if(second==="*"&&(range3===void 0?make2({...ns2(namespace),wildcard:!0,...withGlob(reader,[namespace])}):state.problems.push(NAMESPACE_NOT_VERSIONED)),dot>0&&dot<second.length-1&&range3===void 0){let left=second.slice(0,dot),right=second.slice(dot+1);isName(reader,left)&&isVariableName(reader,right)&&make2({kind:"variable",name:right,recipe:{kind:"recipe",name:left,namespace:ns2(namespace)},...withGlob(reader,[namespace,left,right])})}isName(reader,second)?make2({kind:"recipe",name:second,namespace:ns2(namespace),...range3===void 0?{}:{range:range3},...withGlob(reader,[namespace,second])}):dot<=0&&state.problems.push(badName("recipe name",second))}var namePathSplitter=splitter("name-path",60,(state,ctx)=>{let segments=splitSegments(state.rest),out=[state],make2=ref=>{out.push(finishRef(state,ref))},repo=state.repo,ns2=name=>({kind:"namespace",name,...repo===void 0?{}:{repo}}),reader={state,globs:ctx.services.get("host.globs"),make:make2,ns:ns2};if(segments[0]==="")return state.problems.push("the namespace is empty."),out;if(segments.length>1&&segments.includes(""))return state.problems.push(segments[segments.length-1]===""?"the recipe name after '/' is empty.":"a ref has an empty segment between two '/'."),out;if(segments.length===1)return readOne(reader,segments[0]),out;let[namespace,second]=segments;if(!isName(reader,namespace))return state.problems.push(badName("namespace",namespace)),out;if(segments.length===2)return readTwo(reader,namespace,second),out;let path103=segments.slice(2).join("/");if(!isName(reader,second))return state.problems.push(badName("recipe name",second)),out;if(!FILE_PATH.test(path103))return state.problems.push(`the path '${path103}' inside a recipe holds a space or a backslash.`),out;let recipe={kind:"recipe",name:second,namespace:ns2(namespace)};return make2({kind:"recipeFile",path:path103,recipe,...state.range===void 0?{}:{range:state.range},...withGlob(reader,[namespace,second,path103])}),out});import{ConfigError as ConfigError10}from"@sous-io/plugin-api";var SYNTAX_HELP="A ref is written as 'namespace', 'namespace/recipe', 'repo:namespace/recipe', 'namespace/recipe/path/to/file.md', 'namespace/recipe.variable', an environment variable name, any of those with '@<range>' or '?name=value', or a location such as 'github://owner/repository/namespace/recipe' or a URL copied from the browser.";function earlyProblem(input){if(typeof input!="string")return"a ref must be a string.";let trimmed=input.trim();if(trimmed.length===0)return"a ref must not be empty.";if(trimmed.startsWith("@"))return"refs take no '@' prefix. The '@' character introduces a version range only, as in 'workflow/task-files@^1.2.0'.";if(trimmed.startsWith("~"))return"refs take no '~' prefix. The '~' sigil belongs to template include lines ('@~workflow/file.md'); a ref itself is written without it."}function finished(states){let seen=new Set,refs=[];for(let state of states){if(state.ref===void 0||state.rest!=="")continue;let key=JSON.stringify(state.ref);seen.has(key)||(seen.add(key),refs.push(state.ref))}return refs.map((ref,position)=>({ref,position})).sort((left,right)=>REF_KINDS.indexOf(left.ref.kind)-REF_KINDS.indexOf(right.ref.kind)||left.position-right.position).map(entry=>entry.ref)}function parseWith(splitters,input,ctx){let early=earlyProblem(input);if(early!==void 0)return{input:String(input),readings:[],problems:[early]};let trimmed=input.trim(),problems=[],ordered2=[...splitters].sort((left,right)=>left.order-right.order),states=[{input:trimmed,rest:trimmed,problems}];for(let entry of ordered2)if(states=states.flatMap(state=>entry.split(state,ctx)),states.length===0)break;return{input,readings:finished(states),problems:[...new Set(problems)]}}function parseError(result){let reasons=result.problems,problem;return reasons.length===0?problem="it does not fit any form of a ref.":reasons.length===1?problem=reasons[0]:problem=`it fits no form of a ref:
832
+ `).map(line=>line.trim()).filter(line=>line.length>0);return{run,runSync(args,options){let raw2=deps.processes.runSync("git",args,processOptions(args,options));return check3(toResult(args,raw2),raw2,options)},async available(){return await deps.processes.which("git",deps.env)!==void 0},async version(){let raw2=await deps.processes.run("git",["--version"],{env:environmentFor({}),label:"git --version"});return raw2.exitCode===0?/(\d+\.\d+(?:\.\d+)?)/.exec(raw2.stdout)?.[1]:void 0},root:cwd=>ask(["rev-parse","--show-toplevel"],cwd),currentBranch:cwd=>ask(["symbolic-ref","--quiet","--short","HEAD"],cwd),async revParse(ref,cwd){if(!looksLikeOption(ref))return ask(["rev-parse","--verify","--quiet",`${ref}^{commit}`],cwd)},async status(cwd){let parts=(await run(["status","--porcelain=v1","-z"],{cwd})).stdout.split("\0"),entries=[];for(let index=0;index<parts.length;index+=1){let part=parts[index];if(part.length<4)continue;let code=part.slice(0,2),entryPath=part.slice(3);code.includes("R")||code.includes("C")?(entries.push({path:entryPath,code,from:parts[index+1]??""}),index+=1):entries.push({path:entryPath,code})}return entries},async tags(cwd,pattern){return lines3((await run(pattern===void 0?["tag","--list"]:["tag","--list",pattern],{cwd})).stdout)},async remoteUrl(cwd,remote="origin"){return looksLikeOption(remote)?void 0:ask(["remote","get-url",remote],cwd)},async clone(url2,directory,options={}){let parent=path17.dirname(directory),sparse=options.sparsePaths!==void 0&&options.sparsePaths.length>0,args=["clone",...LF_CHECKOUT_OPTIONS];options.depth!==void 0&&options.depth>0&&args.push("--depth",String(options.depth)),sparse&&args.push("--filter=blob:none","--sparse"),options.branch!==void 0&&args.push("--branch",options.branch),options.noCheckout===!0&&args.push("--no-checkout"),args.push("--",url2,directory),await fs12.mkdir(parent,{recursive:!0}),await run(args,{cwd:parent,env:options.env,signal:options.signal}),sparse&&await run(["sparse-checkout","set","--",...options.sparsePaths],{cwd:directory,env:options.env,signal:options.signal})},async readRemoteFile(url2,filePath,options={}){if(looksLikeOption(url2))throw new GitError({args:["fetch",url2],exitCode:1,stdout:"",stderr:`${url2} is not a repository address.`,durationMs:0});let ref=options.ref??"HEAD",tmp=await fs12.mkdtemp(path17.join(deps.env.TMPDIR??os4.tmpdir(),"sous-git-read-")),common={cwd:tmp,env:options.env,timeoutMs:options.timeoutMs,signal:options.signal};try{await run(["init","--quiet"],common),await run(["remote","add","origin","--",url2],common),await run(["fetch","--quiet","--depth","1","--filter=blob:none","origin",ref],common);let shown=await run(["show",`FETCH_HEAD:${filePath}`],{...common,reject:!1});if(shown.exitCode!==0)throw new GitError(shown,{cwd:tmp});return shown.stdout}finally{await fs12.rm(tmp,{recursive:!0,force:!0})}}}}var package_default4={name:"@sous-io/plugin-git",version:"1.0.12",description:"The one git runner.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME3="@sous-io/plugin-git",gitPlugin=definePlugin4({name:PLUGIN_NAME3,version:package_default4.version,description:"The one git runner.",dependsOn:{"@sous-io/plugin-host":`^${package_default4.version}`},register(sous){sous.services.add("git.runner",(_config,ctx)=>createGitRunner({processes:ctx.services.get("host.processes"),env:ctx.env}),{lifetime:"singleton"})}});import{definePlugin as definePlugin5,jsonSchema as jsonSchema7}from"@sous-io/plugin-api";import{ConfigError as ConfigError8}from"@sous-io/plugin-api";var REF_KINDS=["repo","namespace","recipe","recipeFile","variable","envVar"],KIND_LABELS={repo:"repository",namespace:"namespace",recipe:"recipe",recipeFile:"recipe file",variable:"variable",envVar:"environment variable"};function repoOf(ref){switch(ref.kind){case"repo":return ref;case"namespace":return ref.repo;case"recipe":return ref.namespace?.repo??ref.repo;case"recipeFile":return repoOf(ref.recipe);case"variable":return ref.recipe===void 0?ref.repo:repoOf(ref.recipe)??ref.repo;case"envVar":return}}function locationOf(ref){return repoOf(ref)?.location}function namespaceOf(ref){switch(ref.kind){case"namespace":return ref;case"recipe":return ref.namespace;case"recipeFile":return ref.recipe.namespace;case"variable":return ref.recipe?.namespace;default:return}}function recipeOf(ref){switch(ref.kind){case"recipe":return ref;case"recipeFile":case"variable":return ref.recipe;default:return}}function rangeOf(ref){return ref.kind==="recipe"||ref.kind==="recipeFile"||ref.kind==="repo"?ref.range:void 0}function qualificationOf(candidate){return candidate.kind==="envVar"?3:candidate.kind==="repo"||repoOf(candidate)!==void 0?0:candidate.kind==="recipe"&&candidate.namespace!==void 0||candidate.kind==="recipeFile"||candidate.kind==="variable"&&candidate.recipe!==void 0?1:2}function isStoredKind(ref){return ref.kind==="namespace"||ref.kind==="recipe"&&ref.namespace!==void 0}function shortKey(ref){let namespace=namespaceOf(ref)?.name,recipe=ref.kind==="namespace"?void 0:recipeOf(ref)?.name;return namespace===void 0?recipe??"":recipe===void 0?namespace:`${namespace}/${recipe}`}function repoPart(repo){return repo===void 0?void 0:repo.name??repo.location?.identity}function pathPart(ref){switch(ref.kind){case"repo":return ref.browsed===void 0?"":`tree/${ref.browsed}`;case"namespace":return ref.name;case"recipe":return ref.namespace===void 0?ref.name:`${ref.namespace.name}/${ref.name}`;case"recipeFile":return`${pathPart(ref.recipe)}/${ref.path}`;case"variable":return`${ref.recipe===void 0?"":`${pathPart(ref.recipe)}.`}${ref.name}`;case"envVar":return ref.name}}function refKey(ref){let repo=ref.kind==="envVar"?void 0:repoPart(repoOf(ref)),rest=pathPart(ref);return repo===void 0?rest:ref.kind==="repo"&&rest===""?repo:`${repo}:${rest}`}function storedKey(ref){return ref.kind==="repo"?refKey(ref):pathPart(ref)}function refIdentity(ref){return`${ref.kind} ${refKey(ref)}`}function repoLabel(repo){return repo?.name??repo?.location?.url??"unknown"}function isNamedRef(ref){return ref.kind==="namespace"||ref.kind==="recipe"&&ref.namespace!==void 0}function namespaceRef(name,repo){return{kind:"namespace",name,...repo===void 0?{}:{repo:{kind:"repo",name:repo}}}}function recipeRef(namespace,name,options={}){return{kind:"recipe",name,namespace:namespaceRef(namespace,options.repo),...options.range===void 0?{}:{range:options.range}}}function formatter(locations){let qualified=(repo,rest)=>{if(repo===void 0)return rest;if(repo.name!==void 0)return rest===""?repo.name:`${repo.name}:${rest}`;if(repo.location!==void 0){let{host,repoPath,url:url2,provider}=repo.location,reader=provider==="local"?void 0:locations().host(provider);return reader!==void 0?reader.formatLocator(host,repoPath,rest):rest===""?url2:`${url2}/${rest}`}return rest},format3=ref=>{let body2=qualified(ref.kind==="envVar"?void 0:repoOf(ref),pathPart(ref)),range3=rangeOf(ref),pairs=Object.entries(ref.vars??{}).map(([name,value])=>`${encodeURIComponent(name)}=${encodeURIComponent(value)}`);return`${body2}${range3===void 0?"":`@${range3}`}${pairs.length===0?"":`?${pairs.join("&")}`}`},spelling=ref=>{let repo=ref.kind==="envVar"?void 0:repoOf(ref);return repo!==void 0&&repo.name===void 0&&repo.location!==void 0?format3(ref):refKey(ref)};return{format:format3,spelling,describe:ref=>{let summary=ref.description===void 0?"":`: ${ref.description}`,key=spelling(ref);switch(ref.kind){case"repo":{let where2=ref.location?.url;return`${key} (the repository '${ref.name??key}'${where2===void 0?"":`, at ${where2}`})`}case"namespace":return`${key} (the whole namespace '${ref.name}' in the repository '${repoLabel(ref.repo)}')`;case"recipe":return`${key} (the recipe '${ref.name}' in the namespace '${ref.namespace?.name??"unknown"}' of the repository '${repoLabel(repoOf(ref))}'${summary})`;case"recipeFile":return`${key} (the file '${ref.path}' of the recipe '${pathPart(ref.recipe)}'${summary})`;case"variable":return`${key} (the variable '${ref.name}' of the recipe '${ref.recipe===void 0?"unknown":pathPart(ref.recipe)}'${summary})`;case"envVar":{let first2=ref.variables?.[0],answers=first2===void 0?"":` answering '${first2.name}' of the recipe '${first2.recipe===void 0?"unknown":pathPart(first2.recipe)}'`;return`${ref.name} (the environment variable${answers}${summary})`}}}}}function createRefsFormat(ctx){let written=formatter(()=>ctx.services.get("refs.locations")),storedKeys=new Map,parseNamedRef=(input,from="commandLine")=>{let{refs}=ctx.services.get("refs.resolver").parse(input,from),named=refs.filter(ref=>isNamedRef(ref)&&locationOf(ref)===void 0);if(named.length===1&&!refs.some(ref=>locationOf(ref)!==void 0))return named[0];throw new ConfigError8(`Invalid ref '${input}': this needs a namespace or a recipe named by its short form, such as 'workflow/alpha', and this ref names a location.`)},readStoredKey=key=>{let known=storedKeys.get(key);if(known!==void 0)return known;let parsed=parseNamedRef(key,"lockfile"),read=parsed.kind==="namespace"?{namespace:parsed.name}:{namespace:parsed.namespace.name,name:parsed.name};return storedKeys.set(key,read),read};return{key:storedKey,identity(ref){let location=locationOf(ref);if(location===void 0)return refKey(ref);let rest=pathPart(ref);return rest===""?location.identity:`${location.identity}:${rest}`},...written,kindLabel:ref=>KIND_LABELS[ref.kind],splitRecipeKey(key){let{namespace,name}=readStoredKey(key);if(name===void 0)throw new ConfigError8(`Invalid ref '${key}': a recipe key names a namespace and a recipe.`,{details:["A stored key is written as 'namespace' or 'namespace/recipe'."]});return{namespace,name}},namespaceOfKey:key=>readStoredKey(key).namespace,namespaceRef,recipeRef,parseNamedRef,partsOf(ref){let repo=repoOf(ref),namespace=namespaceOf(ref),recipe=recipeOf(ref),range3=rangeOf(ref);return{...repo===void 0?{}:{repo},...namespace===void 0?{}:{namespace},...recipe===void 0?{}:{recipe},...range3===void 0?{}:{range:range3}}}}}var VALID_NAME=/^[a-z][a-z0-9-]*$/,hashNameSchema={"~standard":{version:1,vendor:"sous",validate(value){let entry=value,issues=[];return typeof entry!="object"||entry===null?{issues:[{message:"Expected an object."}]}:((typeof entry.id!="string"||!VALID_NAME.test(entry.id))&&issues.push({message:`The name '#${String(entry.id)}' is invalid: a name is lowercase kebab-case, a letter then letters, digits or hyphens.`,path:["id"]}),typeof entry.description!="string"&&issues.push({message:"Required, but missing.",path:["description"]}),entry.bases!==void 0&&typeof entry.bases!="function"&&issues.push({message:"Expected a function.",path:["bases"]}),entry.view!==void 0&&typeof entry.view!="function"&&issues.push({message:"Expected a function.",path:["view"]}),entry.bases!==void 0&&entry.view!==void 0&&issues.push({message:"A name either stands for directories ('bases') or lists files ('view'), not both."}),issues.length>0?{issues}:{value:entry})}}},projectHashName={id:"project",description:"the root directory of the project being built.",bases:ctx=>ctx.project===void 0?[]:[ctx.project.root]};import{ConfigError as ConfigError9}from"@sous-io/plugin-api";var SHORT_NAME=/^[a-z][a-z0-9-]*$/;function repositoryIdentity(canonical){let name=canonical.name.replace(/\.git$/i,"");return identitySegments(`${canonical.host}/${canonical.owner}/${name}`).join("/")}function identitySegments(identity2){return identity2.split("/").map(segment=>segment.trim().toLowerCase()).filter(segment=>segment.length>0)}function shortNameFromIdentity(identity2){let segments=identitySegments(identity2),cleaned=(segments[segments.length-1]??"").replace(/[^a-z0-9-]+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"");return SHORT_NAME.test(cleaned)?cleaned:cleaned.length===0?"repository":`repo-${cleaned}`}var REPOSITORY_HOST_KIND="repository-host",URL_SCHEMES=new Set(["http","https","ssh","git","git+ssh","ssh+git"]),SCHEME=/^([a-z][a-z0-9+.-]*):\/\/(.*)$/is;function repositoryHosts(entities){return entities.list(REPOSITORY_HOST_KIND)}function schemesOf(host){return host.schemes??[host.id]}function hostedIds(hosts){return hosts.filter(host=>host.defaultHost!==void 0).map(host=>host.id).sort()}function createRefsLocations(entities){let hosts=()=>repositoryHosts(entities),hostById=id=>hosts().find(host=>host.id===id),hostFor2=url2=>hosts().find(host=>host.matches(url2)),asUrl=url2=>{let scheme=SCHEME.exec(url2.trim());if(scheme===null||URL_SCHEMES.has(scheme[1].toLowerCase()))return{url:url2};let name=scheme[1].toLowerCase(),host=hosts().find(entry=>schemesOf(entry).includes(name));if(host?.defaultHost===void 0)return{url:url2};let path103=scheme[2].replace(/^\/+/,"");return{url:`https://${(path103.split("/")[0]??"").includes(".")?path103:`${host.defaultHost}/${path103}`}`,host}},requireHost=(url2,provider)=>{let known=hosts().map(host=>host.id).join(", ")||"none";if(provider!==void 0){let named=hostById(provider);if(named===void 0)throw new ConfigError9(`The repository at ${url2} names the provider '${provider}', which sous does not have.`,{details:[`Sous has these providers: ${known}.`]});if(!named.matches(url2)){let owner=hostFor2(url2);if(owner!==void 0&&owner.id!==named.id)throw new ConfigError9(`The ${named.id} provider does not handle ${url2}; that is ${owner.id==="local"?"a local path":`a ${owner.id} URL`}, which the ${owner.id} provider handles.`,{details:[`Drop '--provider' and let sous work it out, or name '${owner.id}'.`]})}return named}let detected=hostFor2(url2);if(detected!==void 0)return detected;throw new ConfigError9(`Sous does not recognize the host in the repository URL ${url2}.`,{details:[`Sous has these providers: ${known}. For a self-hosted instance, name the provider that host runs on the repository entry, as in 'sous repo add ${url2} --provider <provider>'.`]})},canonicalize=(url2,provider)=>{let target=asUrl(url2);return(provider===void 0&&target.host!==void 0?target.host:requireHost(target.url,provider)).canonicalize(target.url)};return{fromUrl(url2,provider){try{let target=asUrl(url2),host=provider===void 0&&target.host!==void 0?target.host:requireHost(target.url,provider),canonical=host.canonicalize(target.url);return{provider:host.id,host:canonical.host,repoPath:`${canonical.owner}/${canonical.name}`,identity:repositoryIdentity(canonical),url:url2}}catch{return}},locationFor(provider,host,repoPath){let reader=hostById(provider);if(reader===void 0)throw new ConfigError9(`No provider '${provider}' reads the repository ${host}/${repoPath}.`);let url2=`https://${host}/${repoPath}`;return{provider,host,repoPath,identity:repositoryIdentity(reader.canonicalize(url2)),url:url2}},canonicalize,identity:(url2,provider)=>repositoryIdentity(canonicalize(url2,provider)),identityOf:repository=>repositoryIdentity(repository),hostFor:hostFor2,host:hostById,hosts,shortName:shortNameFromIdentity}}function tryLocationFor(locations,provider,host,repoPath){try{return locations.locationFor(provider,host,repoPath)}catch{return}}var SCHEME2=/^[a-z][a-z0-9+.-]*:\/\//i,SCP=/^[^@\s/:]+@([^@\s/:]+):(.+)$/s;function splitter(id,order,read){return{id,order,split:(state,ctx)=>state.ref!==void 0?[state]:read(state,ctx)}}function finishRef(state,ref){let withVars=state.vars===void 0?ref:{...ref,vars:state.vars};return{...state,rest:"",ref:withVars}}var SCHEME_PATTERN=/^([a-z][a-z0-9+.-]*):\/\/(.*)$/is,SCP_PATTERN=/^[^@\s/:]+@([^@\s/:]+):(.+)$/s,URL_SCHEMES2=new Set(["http","https","ssh","git","git+ssh","ssh+git"]),LOCAL_SCHEMES=new Set(["local","file"]);function looksLikeLocation(ref){let trimmed=ref.trim();if(SCHEME_PATTERN.test(trimmed)||SCP_PATTERN.test(trimmed))return!0;let first2=trimmed.split("/")[0]??"";return trimmed.includes("/")&&first2.includes(".")&&!first2.includes(":")}function pathSegments(pathname){return pathname.split(/[?#]/)[0].split("/").map(segment=>{try{return decodeURIComponent(segment)}catch{return segment}}).filter(segment=>segment.length>0)}function local(state,path103){return finishRef(state,{kind:"repo",location:{provider:"local",host:"localhost",repoPath:path103,identity:`localhost/${path103.replace(/^\/+/,"")}`,url:state.rest}})}function forHost(state,hosts,hostName,segments){let probe=`https://${hostName}/${segments.slice(0,2).join("/")}`,host=hosts.find(entry=>entry.matches(probe));if(host!==void 0&&host.defaultHost!==void 0)return{host,hostName,segments};let ids=hostedIds(hosts);state.problems.push(`sous does not recognize the host '${hostName}'. For a self-hosted instance, write the location with the provider's scheme and the host, as in '${ids[0]??"gitlab"}://${hostName}/owner/repository/namespace/recipe' (sous has these providers: ${ids.join(", ")||"none"}).`)}function take(state,hosts,scheme){let body2=state.rest;if(scheme!==null){let name=scheme[1].toLowerCase();if(URL_SCHEMES2.has(name)){let url2;try{url2=new URL(body2)}catch{state.problems.push("the URL could not be read.");return}return forHost(state,hosts,url2.host.toLowerCase(),pathSegments(url2.pathname))}let host=hosts.find(entry=>schemesOf(entry).includes(name));if(host?.defaultHost===void 0){state.problems.push(`'${name}' is not a provider sous can read a location from. The scheme of a locator is the provider's own identifier; sous has these: ${hostedIds(hosts).join(", ")||"none"}. An ordinary 'https://' URL works too.`);return}let segments=pathSegments(scheme[2]),hostName=host.defaultHost;return segments[0]?.includes(".")===!0&&(hostName=segments[0].toLowerCase(),segments=segments.slice(1)),{host,hostName,segments}}let scp=SCP_PATTERN.exec(body2);if(scp!==null)return forHost(state,hosts,scp[1].toLowerCase(),pathSegments(scp[2]));let all=pathSegments(body2);return forHost(state,hosts,all[0].toLowerCase(),all.slice(1))}function readLocation(state,locations){if(state.repo!==void 0||!looksLikeLocation(state.rest))return[state];let scheme=SCHEME_PATTERN.exec(state.rest);if(scheme!==null&&LOCAL_SCHEMES.has(scheme[1].toLowerCase()))return[local(state,scheme[2])];let taken=take(state,locations.hosts(),scheme);if(taken===void 0)return[];let{host,hostName,segments}=taken,specific=[],repositories=[];for(let reading of host.readLocation({host:hostName,segments})){let location=tryLocationFor(locations,host.id,hostName,reading.repoPath);if(location===void 0)continue;if(reading.browsed!==void 0){let browsed=reading.browsed.replace(/^\/+|\/+$/g,"");browsed.length>0&&specific.push(finishRef(state,{kind:"repo",location,browsed,...state.range===void 0?{}:{range:state.range}}));continue}let named=reading.named??[];named.length===0?repositories.push({kind:"repo",location}):specific.push({...state,rest:named.join("/"),repo:{kind:"repo",location}})}return specific.length>0?specific:repositories.length===0?(state.problems.push(`the ${host.id} provider cannot read a namespace or a recipe from this location. After the repository, a location names a namespace and optionally a recipe, as in '${host.formatLocator(hostName,"owner/repository","workflow/alpha")}'.`),[]):state.range!==void 0?(state.problems.push("a version range applies to a recipe, not to a repository."),[]):repositories.map(repo=>finishRef(state,repo))}var locationSplitter=splitter("location",30,(state,ctx)=>readLocation(state,ctx.services.get("refs.locations")));var NAME_ANY_CASE=/^[a-z][a-z0-9-]*$/i;var VARIABLE_NAME=/^[a-z][a-zA-Z0-9]*$/,ENV_VAR_NAME=/^[A-Za-z_][A-Za-z0-9_]*$/,GLOB_NAME=/^[A-Za-z0-9_\-.*?[\]{},!^]+$/;function isGlobName(text,globs){return globs.hasGlob(text)&&GLOB_NAME.test(text)}function splitSegments(text){let segments=[],depth=0,current="";for(let character of text){if(character==="{"&&(depth+=1),character==="}"&&depth>0&&(depth-=1),character==="/"&&depth===0){segments.push(current),current="";continue}current+=character}return segments.push(current),segments}var FILE_PATH=/^[^\s\\]+$/,NAMESPACE_NOT_VERSIONED="a version range applies to a recipe, and namespaces are not versioned. Name a recipe, as in 'workflow/task-files@^1.2.0'.";function isName(reader,segment){return NAME_ANY_CASE.test(segment)||isGlobName(segment,reader.globs)}function isVariableName(reader,segment){return VARIABLE_NAME.test(segment)||isGlobName(segment,reader.globs)}function badName(what,name){return`the ${what} '${name}' must be kebab-case: a letter, then letters, digits or hyphens.`}function withGlob(reader,names2){return names2.some(name=>reader.globs.hasGlob(name))?{glob:!0}:{}}function readOne(reader,text){let{state,make:make2,ns:ns2}=reader,{repo,range:range3}=state,dot=text.indexOf("."),located=repo?.location!==void 0,inRepo=repo===void 0?{}:{repo};if(!located&&dot>0&&dot<text.length-1&&range3===void 0){let left=text.slice(0,dot),right=text.slice(dot+1);isName(reader,left)&&isVariableName(reader,right)&&make2({kind:"variable",name:right,recipe:{kind:"recipe",name:left,...inRepo},...withGlob(reader,[left,right])})}isName(reader,text)&&(range3===void 0?(make2({...ns2(text),...withGlob(reader,[text])}),repo===void 0&&make2({kind:"repo",name:text,...withGlob(reader,[text])})):state.problems.push(NAMESPACE_NOT_VERSIONED),located||make2({kind:"recipe",name:text,...inRepo,...range3===void 0?{}:{range:range3},...withGlob(reader,[text])})),!located&&range3===void 0&&isVariableName(reader,text)&&make2({kind:"variable",name:text,...inRepo,...withGlob(reader,[text])});let readsAsOther=repo===void 0&&(VARIABLE_NAME.test(text)||ENV_VAR_NAME.test(text));!isName(reader,text)&&!readsAsOther&&dot<=0&&state.problems.push(badName("namespace",text))}function readTwo(reader,namespace,second){let{state,make:make2,ns:ns2}=reader,{range:range3}=state,dot=second.indexOf(".");if(second==="*"&&(range3===void 0?make2({...ns2(namespace),wildcard:!0,...withGlob(reader,[namespace])}):state.problems.push(NAMESPACE_NOT_VERSIONED)),dot>0&&dot<second.length-1&&range3===void 0){let left=second.slice(0,dot),right=second.slice(dot+1);isName(reader,left)&&isVariableName(reader,right)&&make2({kind:"variable",name:right,recipe:{kind:"recipe",name:left,namespace:ns2(namespace)},...withGlob(reader,[namespace,left,right])})}isName(reader,second)?make2({kind:"recipe",name:second,namespace:ns2(namespace),...range3===void 0?{}:{range:range3},...withGlob(reader,[namespace,second])}):dot<=0&&state.problems.push(badName("recipe name",second))}var namePathSplitter=splitter("name-path",60,(state,ctx)=>{let segments=splitSegments(state.rest),out=[state],make2=ref=>{out.push(finishRef(state,ref))},repo=state.repo,ns2=name=>({kind:"namespace",name,...repo===void 0?{}:{repo}}),reader={state,globs:ctx.services.get("host.globs"),make:make2,ns:ns2};if(segments[0]==="")return state.problems.push("the namespace is empty."),out;if(segments.length>1&&segments.includes(""))return state.problems.push(segments[segments.length-1]===""?"the recipe name after '/' is empty.":"a ref has an empty segment between two '/'."),out;if(segments.length===1)return readOne(reader,segments[0]),out;let[namespace,second]=segments;if(!isName(reader,namespace))return state.problems.push(badName("namespace",namespace)),out;if(segments.length===2)return readTwo(reader,namespace,second),out;let path103=segments.slice(2).join("/");if(!isName(reader,second))return state.problems.push(badName("recipe name",second)),out;if(!FILE_PATH.test(path103))return state.problems.push(`the path '${path103}' inside a recipe holds a space or a backslash.`),out;let recipe={kind:"recipe",name:second,namespace:ns2(namespace)};return make2({kind:"recipeFile",path:path103,recipe,...state.range===void 0?{}:{range:state.range},...withGlob(reader,[namespace,second,path103])}),out});import{ConfigError as ConfigError10}from"@sous-io/plugin-api";var SYNTAX_HELP="A ref is written as 'namespace', 'namespace/recipe', 'repo:namespace/recipe', 'namespace/recipe/path/to/file.md', 'namespace/recipe.variable', an environment variable name, any of those with '@<range>' or '?name=value', or a location such as 'github://owner/repository/namespace/recipe' or a URL copied from the browser.";function earlyProblem(input){if(typeof input!="string")return"a ref must be a string.";let trimmed=input.trim();if(trimmed.length===0)return"a ref must not be empty.";if(trimmed.startsWith("@"))return"refs take no '@' prefix. The '@' character introduces a version range only, as in 'workflow/task-files@^1.2.0'.";if(trimmed.startsWith("~"))return"refs take no '~' prefix. The '~' sigil belongs to template include lines ('@~workflow/file.md'); a ref itself is written without it."}function finished(states){let seen=new Set,refs=[];for(let state of states){if(state.ref===void 0||state.rest!=="")continue;let key=JSON.stringify(state.ref);seen.has(key)||(seen.add(key),refs.push(state.ref))}return refs.map((ref,position)=>({ref,position})).sort((left,right)=>REF_KINDS.indexOf(left.ref.kind)-REF_KINDS.indexOf(right.ref.kind)||left.position-right.position).map(entry=>entry.ref)}function parseWith(splitters,input,ctx){let early=earlyProblem(input);if(early!==void 0)return{input:String(input),readings:[],problems:[early]};let trimmed=input.trim(),problems=[],ordered2=[...splitters].sort((left,right)=>left.order-right.order),states=[{input:trimmed,rest:trimmed,problems}];for(let entry of ordered2)if(states=states.flatMap(state=>entry.split(state,ctx)),states.length===0)break;return{input,readings:finished(states),problems:[...new Set(problems)]}}function parseError(result){let reasons=result.problems,problem;return reasons.length===0?problem="it does not fit any form of a ref.":reasons.length===1?problem=reasons[0]:problem=`it fits no form of a ref:
832
833
  ${reasons.map(reason=>` ${reason}`).join(`
833
834
  `)}`,new ConfigError10(`Invalid ref '${result.input}': ${problem}`,{details:[SYNTAX_HELP]})}function createRefsParser(ctx){return{parse:input=>parseWith(ctx.entities.list("ref-splitter"),input,ctx)}}var import_semver=__toESM(require_semver2(),1);var PAIR=/^([A-Za-z0-9\-._~%+!*'(),:@/$]+)=([A-Za-z0-9\-._~%+!*'(),:@/$]*)$/;function decodeQuery(query){if(query.length===0)return;let vars={};for(let pair of query.split("&")){let match2=PAIR.exec(pair);if(match2===null)return;try{vars[decodeURIComponent(match2[1].replace(/\+/g," "))]=decodeURIComponent(match2[2].replace(/\+/g," "))}catch{return}}return vars}var querySplitter=splitter("query",10,state=>{if(SCHEME2.test(state.rest))return[state];let mark=state.rest.lastIndexOf("?");if(mark<=0)return[state];let vars=decodeQuery(state.rest.slice(mark+1));return vars===void 0?[state]:[{...state,rest:state.rest.slice(0,mark),vars:{...state.vars,...vars}},state]}),rangeSplitter=splitter("range",20,state=>{let text=state.rest,at2=text.lastIndexOf("@");if(at2===-1||at2<text.lastIndexOf("/"))return[state];let before=text.slice(0,at2).trim(),range3=text.slice(at2+1).trim();return range3.length===0?(state.problems.push("the '@' is not followed by a version range."),[]):before.includes("@")&&!SCHEME2.test(before)&&!SCP.test(before)?(state.problems.push("a ref may carry at most one '@' version range."),[]):import_semver.default.validRange(range3)===null?(state.problems.push(`'${range3}' is not a version range. Ranges follow npm's rules, such as '^1.2.0', '~2.1', '>=1.0.0 <2.0.0' or '*'.`),[state]):[{...state,rest:before,range:range3}]}),repoQualifierSplitter=splitter("repo-qualifier",40,(state,ctx)=>{let text=state.rest;if(state.repo!==void 0||SCHEME2.test(text)||SCP.test(text))return[state];let match2=/^([^:/\s]*):(.*)$/s.exec(text);if(match2===null)return[state];let name=match2[1],rest=match2[2];return name.length===0?(state.problems.push("the repo qualifier before ':' is empty."),[]):rest.includes(":")?(state.problems.push("a ref may carry at most one 'repo:' qualifier."),[]):!NAME_ANY_CASE.test(name)&&!isGlobName(name,ctx.services.get("host.globs"))?(state.problems.push(`the repo qualifier '${name}' must be kebab-case: a letter, then letters, digits or hyphens.`),[]):[{...state,rest,repo:{kind:"repo",name}}]}),envVarSplitter=splitter("env-var",50,state=>state.repo!==void 0||state.range!==void 0||!ENV_VAR_NAME.test(state.rest)?[state]:[state,finishRef(state,{kind:"envVar",name:state.rest})]);import{ConfigError as ConfigError11,NonInteractiveError as NonInteractiveError2}from"@sous-io/plugin-api";var ACCEPT_FIRST_FLAG="--accept-first";function resolvedRefFacts(ref,search2,reason){let subject2=ref.kind==="envVar"?ref.variables?.[0]??ref:ref,resolvedTo=refKey(subject2),repoName=repoOf(subject2)?.name,recipe=recipeOf(subject2),namespace=namespaceOf(subject2);return{search:search2,resolvedTo,kind:KIND_LABELS[ref.kind],...subject2.kind==="variable"?{variable:subject2.name}:{},...recipe===void 0||subject2.kind==="namespace"?{}:{recipe:recipe.name},...namespace===void 0?{}:{namespace:namespace.name},...repoName===void 0||repoName===resolvedTo?{}:{repository:repoName},...ref.kind==="repo"&&ref.location!==void 0?{location:ref.location.url}:{},...ref.kind!=="repo"&&subject2.description!==void 0?{description:subject2.description}:{},...reason===void 0?{}:{reason}}}function reasonOf(facts){return facts.reason??`'${facts.search}' named one ${facts.kind}, and nothing else, so that is what is being used.`}function createRefsPicker(locations){let{spelling,describe:describe5}=formatter(locations),announce=(io,ref,search2,reason)=>{let facts=resolvedRefFacts(ref,search2,reason);io.reporter.resolvedReference(reasonOf(facts),facts)};return{facts:resolvedRefFacts,async pick(matches,options,io){let{search:search2}=options,shouldAnnounce=options.announce??!0;if(matches.length===0)throw new ConfigError11(`Nothing called '${search2}' was found.`,{details:options.details??[]});let first2=matches[0];if(matches.length===1)return shouldAnnounce&&announce(io,first2,search2),first2;if(options.acceptFirst===!0){let reason=`'${search2}' named ${matches.length} things, and '${ACCEPT_FIRST_FLAG}' was passed, so the first one listed is being used.`;return shouldAnnounce?announce(io,first2,search2,reason):io.reporter.notice(reason),first2}let message2=options.prompt??`Which '${search2}' did you mean?`;if(!io.prompter.interactive){let example=spelling(matches.find(match2=>spelling(match2)!==search2)??first2);throw new NonInteractiveError2(message2,ACCEPT_FIRST_FLAG,{details:[`'${search2}' matched ${matches.length} things:`,...matches.map(match2=>` ${describe5(match2)}`),`Write the full reference (for example '${example}'), or pass '${ACCEPT_FIRST_FLAG}' to take the first one listed.`]})}return io.prompter.askChoice({message:message2,answeredBy:ACCEPT_FIRST_FLAG,choices:matches.map(match2=>({label:describe5(match2),value:match2}))})}}}import{ConfigError as ConfigError12}from"@sous-io/plugin-api";var SOURCE_LABELS={commandLine:"on the command line",config:"as a subscription key in a config file",manifest:"in a recipe manifest's 'depends' or 'subscribes' list",lockfile:"as a key sous stores",include:"in an include line"};function textOf(text,ref,input,ctx){return typeof text=="function"?text(ref,input,ctx):text}function rulePruner(options){let normalize3=options.normalize??(ref=>ref);return{id:options.id,source:options.source,place:options.place??SOURCE_LABELS[options.source]??`as '${options.source}'`,prune(candidates,input,ctx){let kept=[],dropped=[],warnings=[];for(let ref of candidates){let rule=options.rules.find(entry=>entry.matches(ref,input));if(rule===void 0){kept.push(normalize3(ref));continue}let message2=textOf(rule.message,ref,input,ctx);if(rule.action==="throw")throw new ConfigError12(message2);if(rule.action==="warn"){kept.push(normalize3(ref)),warnings.push(message2);continue}dropped.push(rule.instead===void 0?{ref,reason:message2}:{ref,reason:message2,instead:textOf(rule.instead,ref,input,ctx)})}return{kept,dropped,warnings}}}}function describeDropped(dropped){return dropped.instead===void 0?dropped.reason:`${dropped.reason}
834
835
  Write ${dropped.instead} instead.`}function isLocal(ref){return locationOf(ref)?.provider==="local"}function hasLocation(ref){return locationOf(ref)!==void 0}function hasRepoName(ref){return ref.kind!=="repo"&&repoOf(ref)?.name!==void 0}var KEBAB_REASON="only a namespace or a recipe can be named here, and their names must be kebab-case: a letter, then letters, digits or hyphens.";var NO_PATHS="a short ref has at most two path segments, a namespace and a recipe. A folder path inside a repository is written as a URL copied from the browser instead.",lowerKey=ref=>`'${shortKey(ref).toLowerCase()}'`,commandLinePruner=rulePruner({id:"commandLine",source:"commandLine",rules:[{matches:isLocal,action:"drop",message:"a repository on this machine is added by its path, and its recipes are then named by their short form.",instead:"'sous repo add <path>', then 'namespace/recipe'"},{matches:ref=>ref.kind==="recipeFile",action:"drop",message:NO_PATHS,instead:"'namespace/recipe', or the URL copied from the browser"},{matches:ref=>ref.glob===!0,action:"drop",message:"a name here must be kebab-case (a letter, then letters, digits or hyphens), so a glob pattern is not accepted.",instead:"the name itself"}]}),sharedStoredRules=[{matches:ref=>ref.kind==="namespace"&&ref.wildcard===!0,action:"drop",message:"a whole namespace is stored as its name alone.",instead:lowerKey},{matches:ref=>ref.vars!==void 0,action:"drop",message:"a stored key carries no query values.",instead:lowerKey},{matches:ref=>shortKey(ref)!==shortKey(ref).toLowerCase(),action:"drop",message:"stored names are lowercase.",instead:lowerKey}],configPruner=rulePruner({id:"config",source:"config",rules:[{matches:hasLocation,action:"drop",message:"a config file names a subscription by its short form; the repository it lives in is a separate entry under 'repos'.",instead:(_ref,input)=>`'namespace/recipe', or run 'sous subscribe ${input.trim()}', which adds the repository and writes the subscription in its short form`},{matches:ref=>!isStoredKind(ref),action:"drop",message:KEBAB_REASON,instead:"'namespace/recipe'"},{matches:hasRepoName,action:"drop",message:ref=>`the repository a subscription resolves into is recorded in the lockfile, not in the key. To choose between repositories, run 'sous subscribe ${repoOf(ref)?.name}:${shortKey(ref).toLowerCase()}', which records the choice.`,instead:lowerKey},{matches:ref=>ref.glob===!0,action:"drop",message:"a glob pattern is not a stored key; names here must be kebab-case.",instead:lowerKey},{matches:ref=>rangeOf(ref)!==void 0,action:"drop",message:"a subscription's version range belongs in the entry's own 'range' field.",instead:ref=>`${lowerKey(ref)}: { range: '${rangeOf(ref)}' }`},...sharedStoredRules]}),lockfilePruner=rulePruner({id:"lockfile",source:"lockfile",rules:[{matches:hasLocation,action:"drop",message:"a stored key never names a location.",instead:"'namespace/recipe'"},{matches:ref=>!isStoredKind(ref),action:"drop",message:KEBAB_REASON,instead:"'namespace/recipe'"},{matches:hasRepoName,action:"drop",message:"a stored key never names a repository.",instead:lowerKey},{matches:ref=>ref.glob===!0,action:"drop",message:"a glob pattern is not a stored key; names here must be kebab-case.",instead:lowerKey},{matches:ref=>rangeOf(ref)!==void 0,action:"drop",message:"a stored key carries no version range.",instead:lowerKey},...sharedStoredRules]});function lowercaseNames(ref){return ref.kind==="namespace"?{...ref,name:ref.name.toLowerCase()}:ref.kind==="recipe"?{...ref,name:ref.name.toLowerCase(),...ref.namespace===void 0?{}:{namespace:{...ref.namespace,name:ref.namespace.name.toLowerCase()}}}:ref}var manifestPruner=rulePruner({id:"manifest",source:"manifest",normalize:lowercaseNames,rules:[{matches:hasRepoName,action:"drop",message:"a 'repo:' qualifier names a short name that only the consuming project knows, so it cannot appear in a published manifest.",instead:ref=>`${lowerKey(ref)} for a recipe in this same repository, or name the other repository by its location, as in 'github://owner/repository/${shortKey(ref).toLowerCase()}'`},{matches:isLocal,action:"drop",message:"a local repository is a consumer's convenience, not a published location, so a manifest cannot depend on one.",instead:"the recipe's published location, such as 'github://owner/repository/namespace/recipe'"},{matches:ref=>ref.kind==="recipeFile",action:"drop",message:NO_PATHS,instead:"'namespace/recipe', or the URL copied from the browser"},{matches:ref=>ref.glob===!0,action:"drop",message:KEBAB_REASON,instead:"'namespace/recipe'"},{matches:ref=>ref.kind==="repo"&&ref.browsed===void 0&&ref.location!==void 0,action:"drop",message:ref=>`it names the repository at ${ref.kind==="repo"?ref.location?.url:"that location"} and nothing inside it, and a dependency is a namespace or a recipe.`,instead:(ref,_input,ctx)=>{if(ref.kind!=="repo"||ref.location===void 0)return"'github://owner/repository'";let{host,repoPath,url:url2,provider}=ref.location,reader=ctx.services.get("refs.locations").host(provider);return`'${reader===void 0?`${url2}/namespace/recipe`:reader.formatLocator(host,repoPath,"namespace/recipe")}'`}},{matches:ref=>ref.kind==="recipe"&&ref.namespace===void 0,action:"drop",message:ref=>rangeOf(ref)===void 0?"a recipe is named with its namespace here, and a bare name is read as a namespace.":"a version range applies to a recipe, and namespaces are not versioned. Name the recipe with its namespace.",instead:"'namespace/recipe', optionally with a range such as '@^1.1'"},{matches:ref=>!isStoredKind(ref)&&!(ref.kind==="repo"&&ref.browsed!==void 0),action:"drop",message:KEBAB_REASON,instead:"'namespace/recipe'"},{matches:ref=>ref.vars!==void 0,action:"drop",message:"a manifest's dependency carries no query values.",instead:lowerKey}]});function includeInstead(ref){return ref.kind!=="recipeFile"?"'namespace/recipe/path/to/file.md'":`'${ref.recipe.namespace?.name??"namespace"}/${ref.recipe.name}/${ref.path}'`}var includePruner=rulePruner({id:"include",source:"include",rules:[{matches:ref=>ref.kind!=="recipeFile",action:"drop",message:"an include line names a file inside a recipe: its namespace, its recipe and the path inside it.",instead:includeInstead},{matches:hasLocation,action:"drop",message:"an include line never names a location; it reads the recipes this project pins.",instead:includeInstead},{matches:ref=>rangeOf(ref)!==void 0,action:"drop",message:"an include line takes no version range; the version of a recipe is the one this project pins.",instead:includeInstead},{matches:ref=>ref.kind==="recipeFile"&&splitSegments(ref.path).some(part=>part==="."||part===".."),action:"drop",message:"the path inside a recipe may not contain '.' or '..' segments.",instead:includeInstead}]}),BUILT_IN_PRUNERS=[commandLinePruner,configPruner,manifestPruner,lockfilePruner,includePruner];import{ConfigError as ConfigError13}from"@sous-io/plugin-api";function browsedFits(ref,kinds){return ref.kind==="repo"&&ref.browsed!==void 0&&(kinds.includes("namespace")||kinds.includes("recipe"))}function answersFor(lookup,candidate){return lookup.kinds===void 0||lookup.kinds.includes(candidate.kind)||browsedFits(candidate,lookup.kinds)}function orderRefs(entries){let seen=new Set;return entries.map((entry,position)=>({...entry,position})).sort((left,right)=>qualificationOf(left.rank)-qualificationOf(right.rank)||REF_KINDS.indexOf(left.ref.kind)-REF_KINDS.indexOf(right.ref.kind)||left.position-right.position).map(entry=>entry.ref).filter(ref=>{let identity2=`${refIdentity(ref)} ${JSON.stringify(ref.vars??{})}`;return seen.has(identity2)?!1:(seen.add(identity2),!0)})}function selectLookups(all,selection){if(selection===void 0||selection===!0)return all.filter(lookup=>lookup.optIn!==!0);if(selection===!1)return[];let chosen=[];for(let selector of selection)for(let lookup of all)(lookup.id===selector||lookup.tags?.includes(selector)===!0)&&!chosen.includes(lookup)&&chosen.push(lookup);return chosen}function createRefsResolver(ctx){let prune3=(input,from)=>{let pruners=ctx.entities.list("ref-pruner").filter(pruner=>pruner.source===from);if(pruners.length===0)throw new ConfigError13(`No pruner is registered for a ref written as '${from}'.`,{details:["A plugin that adds a place to write refs adds a 'ref-pruner' entity for it."]});let parsed=ctx.services.get("refs.parser").parse(input);if(parsed.readings.length===0)throw parseError(parsed);let kept=parsed.readings,dropped=[],warnings=[];for(let pruner of pruners){let result=pruner.prune(kept,input.trim(),ctx);kept=result.kept,dropped.push(...result.dropped),warnings.push(...result.warnings)}return{kept,dropped,warnings,place:pruners[0].place}},refusal=(input,place,dropped)=>{let reasons=[...new Set(dropped.map(describeDropped))];return reasons.length===1?new ConfigError13(`The ref '${input.trim()}' cannot be written ${place}: ${reasons[0]}`):new ConfigError13(`The ref '${input.trim()}' cannot be written ${place}. Every way it reads is refused:
835
836
  `+reasons.map(reason=>` - ${reason}`).join(`
836
- `))},resolution=(input,refs,pruned,usedLookup)=>({input,refs,dropped:pruned.dropped,warnings:pruned.warnings,usedLookup}),parse6=(input,from="commandLine")=>{let pruned=prune3(input,from);if(pruned.kept.length===0)throw refusal(input,pruned.place,pruned.dropped);return resolution(input,orderRefs(pruned.kept.map(ref=>({ref,rank:ref}))),pruned,!1)},begin=request=>{let pruned;try{pruned=prune3(request.input,request.from??"commandLine")}catch(error51){if(request.refusedIsEmpty===!0)return{result:resolution(request.input,[],{dropped:[],warnings:[]},!0)};throw error51}if(pruned.kept.length===0){if(request.refusedIsEmpty===!0)return{result:resolution(request.input,[],pruned,!0)};throw refusal(request.input,pruned.place,pruned.dropped)}let kinds=request.kinds,kept=kinds===void 0?pruned.kept:pruned.kept.filter(ref=>kinds.includes(ref.kind)||browsedFits(ref,kinds)),selected=selectLookups(ctx.entities.list("ref-lookup"),request.lookups),lookups=[...request.extraLookups??[],...selected];if(Array.isArray(request.lookups)&&request.lookups.length>0&&selected.length===0&&request.extraLookups===void 0)throw new ConfigError13(`No ref lookup answers to ${request.lookups.map(name=>`'${name}'`).join(", ")}.`,{details:["The plugin that adds it may be disabled or missing."]});return lookups.length===0?{result:resolution(request.input,orderRefs(kept.map(ref=>({ref,rank:ref}))),pruned,!1)}:{kept,pruned,lookups}},finish4=(request,pruned,found)=>{let kinds=request.kinds,matching2=found.filter(entry=>kinds===void 0||kinds.includes(entry.match.ref.kind)),exact=matching2.filter(entry=>entry.match.exactSpelling),chosen=exact.length>0?exact:matching2;return resolution(request.input,orderRefs(chosen.map(entry=>({ref:entry.match.ref,rank:entry.rank}))),pruned,!0)};return{parse:parse6,async resolve(request){let early=begin(request);if("result"in early)return early.result;let found=[];for(let candidate of early.kept)for(let lookup of early.lookups)if(answersFor(lookup,candidate))for(let match2 of await lookup.find(candidate,ctx))found.push({match:match2,rank:candidate});return finish4(request,early.pruned,found)},resolveSync(request){let early=begin(request);if("result"in early)return early.result;let found=[];for(let candidate of early.kept)for(let lookup of early.lookups)if(lookup.findSync!==void 0&&answersFor(lookup,candidate))for(let match2 of lookup.findSync(candidate,ctx))found.push({match:match2,rank:candidate});return finish4(request,early.pruned,found)},isValid(input,from="commandLine"){try{return parse6(input,from),!0}catch{return!1}},findInString(text,from="commandLine"){let found=[];for(let word of text.matchAll(/\S+/g)){let bare=word[0].replace(/^[`"'([<{]+/,"").replace(/[`"')\]>},.;:!]+$/,"");if(bare.length!==0)try{found.push({text:bare,index:word.index+word[0].indexOf(bare),result:parse6(bare,from)})}catch{}}return found}}}var package_default5={name:"@sous-io/plugin-refs",version:"1.0.11",description:"Parsing and resolving refs, picking among matches, # names, repository locations and identity.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-host":"workspace:*",semver:"^7.8.5"},devDependencies:{"@sous-io/core":"workspace:*","@types/semver":"^7.8.0"},engines:{node:">=22"}};var BROWSE_WORDS=new Set(["tree","blob"]);function withoutGitSuffix(segment){return segment.replace(/\.git$/i,"")}function readingsAfterRepository(repoPath,rest){let after=rest[0]==="-"?rest.slice(1):[...rest],readings=[];return after.length>=2&&BROWSE_WORDS.has(after[0].toLowerCase())&&readings.push({repoPath,browsed:after.slice(1).join("/")}),readings.push({repoPath,named:after}),readings}function normalizeRepoUrl(url2){let value=url2.trim();for(;value.endsWith("/");)value=value.slice(0,-1);return value.endsWith(".git")&&(value=value.slice(0,-4)),value}function splitRepoUrl(url2){let normalized=normalizeRepoUrl(url2);if(normalized.length===0)return;let host,repoPath,scp=/^(?:([^@\s/]+)@)?([^@\s/:]+):(.+)$/.exec(normalized);if(/^[a-z][a-z0-9+.-]*:\/\//i.test(normalized)){let parsed;try{parsed=new URL(normalized)}catch{return}host=parsed.host.toLowerCase(),repoPath=parsed.pathname.replace(/^\/+/,"")}else if(scp!==null)host=scp[2].toLowerCase(),repoPath=scp[3].replace(/^\/+/,"");else return;let segments=repoPath.split("/").filter(segment=>segment.length>0);if(!(segments.length<2||host.length===0))return{host,owner:segments.slice(0,-1).join("/"),name:segments[segments.length-1]}}function buildCanonicalRepository(host,owner,name){return{host,owner,name,httpsUrl:`https://${host}/${owner}/${name}.git`,sshUrl:`git@${host}:${owner}/${name}.git`}}function defaultLocator(id,defaultHost,host,repoPath,rest){let where2=host===defaultHost?repoPath:`${host}/${repoPath}`;return`${id}://${where2}${rest.length===0?"":`/${rest}`}`}var PLUGIN_NAME4="@sous-io/plugin-refs",BUILT_IN_SPLITTERS=[querySplitter,rangeSplitter,locationSplitter,repoQualifierSplitter,envVarSplitter,namePathSplitter],refsPlugin=definePlugin5({name:PLUGIN_NAME4,version:package_default5.version,description:"Parsing and resolving refs, picking among matches, # names, repository locations and identity.",dependsOn:{"@sous-io/plugin-host":`^${package_default5.version}`},register(sous){sous.entities.define("ref-splitter",jsonSchema7({type:"object",properties:{id:{type:"string"},order:{type:"number"}},required:["id","order","split"]}),{description:"One step of the ref parser: reads part of a written ref, every way it can be read."}),sous.entities.define("ref-pruner",jsonSchema7({type:"object",properties:{id:{type:"string"},source:{type:"string"},place:{type:"string"}},required:["id","source","place","prune"]}),{description:"Which readings of a ref count in one place it is written."}),sous.entities.define("ref-lookup",jsonSchema7({type:"object",properties:{id:{type:"string"},description:{type:"string"},kinds:{type:"array",items:{type:"string"}},tags:{type:"array",items:{type:"string"}},optIn:{type:"boolean"}},required:["id","find"]}),{description:"What exists, for narrowing the readings of a ref."}),sous.entities.define("hash-name",hashNameSchema,{description:"A '#' name, such as '#project', and what it stands for."});for(let splitter2 of BUILT_IN_SPLITTERS)sous.entities.add("ref-splitter",splitter2);for(let pruner of BUILT_IN_PRUNERS)sous.entities.add("ref-pruner",pruner);sous.entities.add("hash-name",projectHashName),sous.services.add("refs.locations",(_config,ctx)=>createRefsLocations(ctx.entities),{lifetime:"config"}),sous.services.add("refs.parser",(_config,ctx)=>createRefsParser(ctx),{lifetime:"config"}),sous.services.add("refs.resolver",(_config,ctx)=>createRefsResolver(ctx),{lifetime:"config"}),sous.services.add("refs.format",(_config,ctx)=>createRefsFormat(ctx),{lifetime:"config"}),sous.services.add("refs.picker",(_config,ctx)=>createRefsPicker(()=>ctx.services.get("refs.locations")),{lifetime:"config"})}});import{definePlugin as definePlugin6}from"@sous-io/plugin-api";var AUTO_VARIABLE_NAMES=["projectRoot","sousDir","sousConfigPath","sousConfDir","sousHome","sousRootPath","sousVersion"],NAMES=new Set(AUTO_VARIABLE_NAMES);function isAutoVariable(name){return NAMES.has(name)}function buildAutoVariables(inputs){let vars={sousRootPath:inputs.packageRoot,sousVersion:inputs.version,sousHome:inputs.sousHome},project=inputs.project;return project&&(vars.projectRoot=project.root,vars.sousDir=project.sousDir,vars.sousConfDir=project.confDir,project.configPath!==void 0&&(vars.sousConfigPath=project.configPath)),vars}var ENV_PREFIX="SOUS_VAR_",VARIABLE_NAME_PATTERN=/^[a-z][a-zA-Z0-9]*$/,ENV_NAME_PATTERN=/^[A-Z][A-Z0-9_]*$/;function toUpperSnake(name){return name.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/[-\s.]+/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,"").toUpperCase()}function sharedName(variable){return`${ENV_PREFIX}${toUpperSnake(variable)}`}function recipeScopedName(namespace,recipe,variable){return`${ENV_PREFIX}${toUpperSnake(namespace)}_${toUpperSnake(recipe)}_${toUpperSnake(variable)}`}function namespaceScopedName(namespace,variable){return`${ENV_PREFIX}${toUpperSnake(namespace)}_${toUpperSnake(variable)}`}function bareName(definition){return definition.env??sharedName(definition.name)}var variablesNames={envPrefix:ENV_PREFIX,toUpperSnake,sharedName,recipeScopedName,namespaceScopedName,bareName,isVariableName:text=>VARIABLE_NAME_PATTERN.test(text),isEnvName:text=>ENV_NAME_PATTERN.test(text)};init_src();import path19 from"node:path";import{ConfigError as ConfigError15}from"@sous-io/plugin-api";import path18 from"node:path";import{ConfigError as ConfigError14}from"@sous-io/plugin-api";var REFERENCE=/\$\{([^}]+)\}/g;function substitute(text,scope){return text.replace(REFERENCE,(match2,name)=>Object.hasOwn(scope,name)?scope[name]:match2)}function references(text){return[...new Set([...text.matchAll(REFERENCE)].map(match2=>match2[1]))]}function unresolved(text,scope={}){return references(text).filter(name=>!Object.hasOwn(scope,name))}function substituteStrict(text,scope,context){let result=substitute(text,scope),missing=references(result);if(missing.length===0)return result;let names2=missing.map(name=>`\${${name}}`).join(", "),one=missing.length===1,available=Object.keys(scope).sort();throw new ConfigError14(`Unresolved ${one?"variable":"variables"} ${names2} in ${context}`,{details:[`raw value: ${text}`,`Define ${one?"it":"them"} in a _vars block, or map ${one?"it":"them"} from the environment via the top-level _env block (values can come from .sous/.env.local or .sous/.env).`,`Variables in scope here: ${available.length>0?available.join(", "):"(none)"}`]})}function substituteValue(value,scope,context){return walk2(value,scope,context)}function walk2(value,scope,context){if(typeof value=="string")return substituteStrict(value,scope,context);if(Array.isArray(value))return value.map((item,index)=>walk2(item,scope,`${context}[${index}]`));if(value!==null&&typeof value=="object"){let out={};for(let[key,item]of Object.entries(value))out[key]=walk2(item,scope,context===""?key:`${context}.${key}`);return out}return value}function normalizePath2(value,home){let result=value;return home!==void 0&&home!==""&&(result==="~"?result=home:result.startsWith("~/")&&(result=path18.join(home,result.slice(2)))),path18.isAbsolute(result)?path18.normalize(result):result}function resolveBlock(block,inherited,context,options={}){let entries=new Map;for(let[key,value]of Object.entries(block))if(value!=null){if(isAutoVariable(key)){if(options.partial||restatesAutoVariable(key,value,inherited))continue;throw autoVariableError(key,context)}entries.set(key,typeof value=="string"?value:String(value))}let scope={...inherited},waiting=new Set(entries.keys()),resolved=[],progressed=!0;for(;progressed&&waiting.size>0;){progressed=!1;for(let key of waiting){let substituted=substitute(entries.get(key),scope);references(substituted).length===0&&(scope[key]=substituted,waiting.delete(key),resolved.push(key),progressed=!0)}}if(waiting.size>0&&!options.partial)throw unresolvedBlockError(entries,scope,waiting,context);return{scope,resolved,pending:[...waiting]}}function restatesAutoVariable(name,value,inherited){let own=inherited[name];if(own===void 0||typeof value!="string")return!1;let written=substitute(value,inherited);return written===own||references(written).length===0&&path19.resolve(written)===path19.resolve(own)}function autoVariableError(name,context){return new ConfigError15(`${context} sets "${name}", which sous sets itself.`,{details:[`Remove "${name}" from ${context}; \${${name}} always holds the value sous gives it.`]})}function unresolvedBlockError(entries,scope,waiting,context){let needs=new Map;for(let key of waiting)needs.set(key,references(substitute(entries.get(key),scope)));let edges=new Map;for(let key of waiting)edges.set(key,needs.get(key).filter(name=>waiting.has(name)));let cycles=findCycles([...waiting],edges),undefinedRefs=new Map;for(let key of waiting)for(let name of needs.get(key))if(!waiting.has(name)){let referrers=undefinedRefs.get(name)??new Set;referrers.add(key),undefinedRefs.set(name,referrers)}let details=[];for(let key of[...waiting].sort()){let names2=needs.get(key).map(name=>`\${${name}}`).join(", ");details.push(`- ${key} still needs ${names2||"(nothing resolvable)"}`)}if(cycles.length>0){details.push("","Reference cycles (these variables reference each other):");for(let cycle of cycles){let sorted2=[...cycle].sort();details.push(`- ${[...sorted2,sorted2[0]].join(" -> ")}`)}}if(undefinedRefs.size>0){details.push("","Undefined references (names defined nowhere: no _vars, _env, or auto-variable):");for(let name of[...undefinedRefs.keys()].sort())details.push(`- \${${name}} (needed by ${[...undefinedRefs.get(name)].sort().join(", ")})`)}let inScope=Object.keys(scope).sort();return details.push("",`Variables in scope here: ${inScope.length>0?inScope.join(", "):"(none)"}`),new ConfigError15(`Unresolved variables in ${context}:`,{details})}function findCycles(nodes,edges){let index=new Map,low=new Map,onStack=new Set,stack=[],components=[],counter=0,connect=node=>{index.set(node,counter),low.set(node,counter),counter++,stack.push(node),onStack.add(node);for(let next of edges.get(node)??[])index.has(next)?onStack.has(next)&&low.set(node,Math.min(low.get(node),index.get(next))):(connect(next),low.set(node,Math.min(low.get(node),low.get(next))));if(low.get(node)===index.get(node)){let component=[],member;do member=stack.pop(),onStack.delete(member),component.push(member);while(member!==node);components.push(component)}};for(let node of nodes)index.has(node)||connect(node);return components.filter(component=>component.length>1||(edges.get(component[0])??[]).includes(component[0]))}import{ConfigError as ConfigError16,SousError as SousError13}from"@sous-io/plugin-api";var ENV_LOCAL_NAME2=".env.local",ENV_DEFAULTS_NAME=".env";function buildScope(view,autoVariables,request,partial2){let scope={},origins={},lay=(values,from,skipAuto)=>{for(let[name,value]of Object.entries(values??{}))typeof value!="string"||skipAuto&&isAutoVariable(name)||(scope[name]=value,origins[name]={from,value})};lay(autoVariables,"auto",!1);let sources=view.sources(),context={project:view.project,env:view.env,config:view.lookup};for(let source of sources)lay(source.variables(context),source.id,!0);if(request.scopeKey!==void 0)for(let source of sources)lay(source.scoped?.(request.scopeKey,context),source.id,!0);lay(envScope(view,partial2),"_env",!1);let current=scope,block=(path103,values)=>{if(!isRecord(values))return;let result=resolveBlock(values,current,path103,{partial:partial2});for(let name of result.resolved)origins[name]={from:path103,value:result.scope[name]};current=result.scope};block("_vars",view.get("_vars"));let level=request.level??"root";if(level!=="root"&&block("compilation._vars",view.get("compilation._vars")),level==="target"||level==="output"){let targetPath=`compilation.targets[${requireIndex(request.target,"target",level)}]`;if(block(`${targetPath}._vars`,view.get(`${targetPath}._vars`)),level==="output"){let output=requireIndex(request.output,"output",level),outputPath=`${targetPath}.outputs[${output}]`;block(`${outputPath}._vars`,view.get(`${outputPath}._vars`))}}request.extra!==void 0&&block("extra",request.extra);let kept={};for(let name of Object.keys(current))kept[name]=origins[name];return{scope:current,origins:kept}}function envScope(view,partial2){let mapping=view.get("_env"),scope={};if(!isRecord(mapping))return scope;for(let[name,envName]of Object.entries(mapping)){if(typeof envName!="string")continue;if(isAutoVariable(name)){if(partial2)continue;throw autoVariableError(name,"_env")}let value=view.env[envName];if(value===void 0){if(partial2)continue;throw unsetEnvError(name,envName,view.project)}scope[name]=value}return scope}function unsetEnvError(name,envName,project){let sousDir=project?.sousDir,local2=sousDir?`${sousDir}/${ENV_LOCAL_NAME2}`:`.sous/${ENV_LOCAL_NAME2}`,defaults2=sousDir?`${sousDir}/${ENV_DEFAULTS_NAME}`:`.sous/${ENV_DEFAULTS_NAME}`;return new ConfigError16(`_env resolution failed: environment variable '${envName}' (mapped to config var '${name}') is not set.`,{details:[`Define it in ${local2} as:`,` ${envName}=<value>`,`...or, if the value is shared by the whole team and is not a secret, in ${defaults2} (committed).`,"...or export it in your shell before running sous."]})}function requireIndex(index,what,level){if(index===void 0||!Number.isInteger(index)||index<0)throw new SousError13(`A scope at the ${level} level needs the ${what} index.`);return index}function isRecord(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}var Resolver=class{constructor(deps){this.deps=deps}cache=new WeakMap;substitute(text,scope){return substitute(text,scope)}substituteStrict(text,scope,context){return substituteStrict(text,scope,context)}substituteValue(value,scope,context){return substituteValue(value,scope,context)}references(text){return references(text)}unresolved(text,scope){return unresolved(text,scope)}normalizePath(value){return normalizePath2(value,this.deps.env.HOME??this.deps.env.USERPROFILE)}resolveBlock(block,inherited,context){return resolveBlock(block,inherited,context).scope}autoVariables(){return this.autoFor(this.deps.env,this.deps.project)}isAutoVariable(name){return isAutoVariable(name)}scope(request={}){return this.build(this.deps.engine.config,request).scope}scopeIn(config2,request={}){return this.build(config2,request).scope}origins(request={}){return this.build(this.deps.engine.config,request).origins}originsIn(config2,request={}){return this.build(config2,request).origins}requestAt(path103){let segments=typeof path103=="string"?parsePath(path103):path103;if(segments[0]!=="compilation")return{level:"root"};let target=segments[2];if(segments[1]!=="targets"||typeof target!="number")return{level:"compilation"};let output=segments[4];return segments[3]!=="outputs"||typeof output!="number"?{level:"target",target}:{level:"output",target,output}}build(config2,request){if(isBuilder(config2)){let view2=builderView(config2);return buildScope(view2,this.autoFor(view2.env,view2.project),request,request.partial??!0)}let cacheable=isBuiltConfig(config2),partial2=request.partial??!cacheable,key=JSON.stringify([request.level,request.target,request.output,request.scopeKey,request.extra,partial2]),cached2=cacheable?this.cache.get(config2)?.get(key):void 0;if(cached2)return cached2;let entities=cacheable?config2.entities:this.deps.engine.config.entities,view=lookupView(config2,entities,this.deps.env,this.deps.project),built=buildScope(view,this.autoFor(view.env,view.project),request,partial2);if(cacheable){let forConfig=this.cache.get(config2)??new Map;forConfig.set(key,built),this.cache.set(config2,forConfig)}return built}autoFor(env,project){let identity2=this.deps.services.get("host.package").identity();return buildAutoVariables({project,sousHome:this.deps.services.get("host.sous-home").paths(env).root,packageRoot:identity2.root,version:identity2.version})}};function isBuilder(config2){let candidate=config2;return typeof candidate.atPath=="function"&&typeof candidate.entities=="function"}function isBuiltConfig(config2){let candidate=config2;return typeof candidate.hash=="string"&&typeof candidate.entities?.list=="function"}function builderView(builder){let lookup={get:path103=>builder.atPath(path103).get()};return{get:path103=>lookup.get(path103),sources:()=>builder.entities("variable-source"),lookup,env:builder.env,project:builder.project}}function lookupView(config2,entities,env,project){return{get:path103=>config2.get(path103),sources:()=>entities.list("variable-source"),lookup:config2,env,project}}function variableMap(what){return{"~standard":{version:1,vendor:"sous",validate(value){if(value===void 0)return{value:void 0};if(value===null||typeof value!="object"||Array.isArray(value))return{issues:[{message:`Expected an object of ${what}.`}]};let issues=[];for(let[name,item]of Object.entries(value))isAutoVariable(name)&&name!=="projectRoot"?issues.push({message:`"${name}" is set by sous; it cannot be set here. Remove it: \${${name}} always holds the value sous gives it.`,path:[name]}):typeof item!="string"&&issues.push({message:`Expected a string (${what}), got ${item===null?"null":typeof item}.`,path:[name]});return issues.length>0?{issues}:{value}}}}}var CONFIG_KEYS=[{id:"_vars",description:"Config variables, used as ${name}. Values may refer to each other in any order.",schema:variableMap("variable values")},{id:"_env",description:"Config variables read from the environment: each name mapped to an environment variable.",schema:variableMap("environment variable names")}],VARIABLE_SOURCE_SCHEMA={"~standard":{version:1,vendor:"sous",validate(value){let entry=value,issues=[];(typeof entry?.id!="string"||entry.id==="")&&issues.push({message:"A variable-source entity needs an id.",path:["id"]}),typeof entry?.description!="string"&&issues.push({message:"A variable-source entity needs a description.",path:["description"]}),typeof entry?.variables!="function"&&issues.push({message:"A variable-source entity needs a variables function.",path:["variables"]});for(let name of["scoped","secrets"])entry?.[name]!==void 0&&typeof entry[name]!="function"&&issues.push({message:`A variable-source entity's ${name} must be a function.`,path:[name]});return entry?.forbiddenUnder!==void 0&&!Array.isArray(entry.forbiddenUnder)&&issues.push({message:"A variable-source entity's forbiddenUnder must be a list of keys.",path:["forbiddenUnder"]}),issues.length>0?{issues}:{value}}}};var HIDDEN_VALUE="(hidden)",SECRET_NAME_ENDINGS=[["token"],["secret"],["secrets"],["password"],["passwd"],["passphrase"],["credential"],["credentials"],["apikey"],["api","key"],["private","key"],["access","key"],["secret","key"],["signing","key"],["encryption","key"]],SECRET_VALUE_PATTERNS=[/-----BEGIN [A-Z ]*PRIVATE KEY-----/,/\bgh[pousr]_[A-Za-z0-9]{36,}/,/\bgithub_pat_[A-Za-z0-9_]{22,}/,/\bglpat-[A-Za-z0-9_-]{20,}/,/\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/,/\bxox[abposr]-[A-Za-z0-9-]{10,}/,/\b[rs]k_live_[A-Za-z0-9]{16,}/,/\bsk-ant-[A-Za-z0-9_-]{20,}/,/\bsk-(?:proj-)?[A-Za-z0-9_-]{32,}/,/\bAIza[0-9A-Za-z_-]{35}/,/\bnpm_[A-Za-z0-9]{36}\b/,/\beyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/,/^[a-z][a-z0-9+.-]*:\/\/[^/\s:@]+:[^/\s@]+@/i],PLAIN_VALUE=/^(?:|-?\d+(?:\.\d+)?|true|false|yes|no|on|off)$/i;function nameWords(name){return name.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").split(/[^A-Za-z0-9]+/).filter(word=>word.length>0).map(word=>word.toLowerCase())}function hasSecretName(name){let words=nameWords(name);return SECRET_NAME_ENDINGS.some(ending=>words.length>=ending.length&&ending.every((word,i)=>words[words.length-ending.length+i]===word))}function hasSecretValue(value){return SECRET_VALUE_PATTERNS.some(pattern=>pattern.test(value))}function looksLikeSecret(name,value){return hasSecretValue(value)?!0:hasSecretName(name)&&!PLAIN_VALUE.test(value.trim())}function isSecret(name,value,declared=new Set){return typeof value!="string"?!1:declared.has(name)?value.length>0:looksLikeSecret(name,value)}function hideSecrets(scope,declared=new Set){let out={};for(let[name,value]of Object.entries(scope))out[name]=isSecret(name,value,declared)?HIDDEN_VALUE:value;return out}var Secrets=class{constructor(sources,context){this.sources=sources;this.context=context}hiddenValue=HIDDEN_VALUE;cached;declared(){if(!this.cached){let names2=new Set,context=this.context();for(let source of this.sources())for(let name of source.secrets?.(context)??[])names2.add(name);this.cached=names2}return this.cached}isSecret(name,value,declared=this.declared()){return isSecret(name,value,declared)}hasSecretName(name){return hasSecretName(name)}hasSecretValue(value){return hasSecretValue(value)}hide(scope,declared=this.declared()){return hideSecrets(scope,declared)}};var package_default6={name:"@sous-io/plugin-variables",version:"1.0.11",description:"${var} substitution, _vars resolution, auto-variables, variable names and secrets.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/documents":"workspace:*","@sous-io/plugin-api":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME5="@sous-io/plugin-variables",RESERVED_NAMES_CONTRIBUTOR="variables/reserved-names",variablesPlugin=definePlugin6({name:PLUGIN_NAME5,version:package_default6.version,description:"${var} substitution, _vars resolution, auto-variables, variable names and secrets.",dependsOn:{"@sous-io/plugin-host":`^${package_default6.version}`},register(sous){sous.services.add("variables.resolver",(_config,ctx)=>new Resolver({services:sous.services,engine:sous.engine,env:ctx.env,project:ctx.project}),{lifetime:"singleton"}),sous.services.add("variables.names",()=>variablesNames,{lifetime:"singleton"}),sous.services.add("variables.secrets",(config2,ctx)=>new Secrets(()=>ctx.entities.list("variable-source"),()=>({project:ctx.project,env:ctx.env,config:config2})),{lifetime:"config"}),sous.entities.define("variable-source",VARIABLE_SOURCE_SCHEMA,{description:"An extra source of config variables, such as recipe answers."});for(let key of CONFIG_KEYS)sous.entities.add("config-key",key);sous.config.contribute({id:RESERVED_NAMES_CONTRIBUTOR,contribute(config2){let vars=config2.atPath("_vars");for(let name of vars.isObject()?vars.keys():[])name.startsWith("sous")&&!isAutoVariable(name)&&config2.warn(`The variable "${name}" uses the reserved "sous*" namespace and may clash with a variable sous sets.`)}})}});import{definePlugin as definePlugin7}from"@sous-io/plugin-api";import{PassThrough}from"stream";import{sep as sep2,extname,resolve as resolve$1,dirname as dirname$1}from"path";import{statSync,readFileSync as readFileSync$1,stat,readFile as readFile$1}from"fs";import{createRequire as createRequire2}from"module";var Token=class{constructor(kind,input,begin,end,file2){this.kind=kind,this.input=input,this.begin=begin,this.end=end,this.file=file2}getText(){return this.input.slice(this.begin,this.end)}getPosition(){let[row,col]=[1,1];for(let i=0;i<this.begin;i++)this.input[i]===`
837
+ `))},resolution=(input,refs,pruned,usedLookup)=>({input,refs,dropped:pruned.dropped,warnings:pruned.warnings,usedLookup}),parse6=(input,from="commandLine")=>{let pruned=prune3(input,from);if(pruned.kept.length===0)throw refusal(input,pruned.place,pruned.dropped);return resolution(input,orderRefs(pruned.kept.map(ref=>({ref,rank:ref}))),pruned,!1)},begin=request=>{let pruned;try{pruned=prune3(request.input,request.from??"commandLine")}catch(error51){if(request.refusedIsEmpty===!0)return{result:resolution(request.input,[],{dropped:[],warnings:[]},!0)};throw error51}if(pruned.kept.length===0){if(request.refusedIsEmpty===!0)return{result:resolution(request.input,[],pruned,!0)};throw refusal(request.input,pruned.place,pruned.dropped)}let kinds=request.kinds,kept=kinds===void 0?pruned.kept:pruned.kept.filter(ref=>kinds.includes(ref.kind)||browsedFits(ref,kinds)),selected=selectLookups(ctx.entities.list("ref-lookup"),request.lookups),lookups=[...request.extraLookups??[],...selected];if(Array.isArray(request.lookups)&&request.lookups.length>0&&selected.length===0&&request.extraLookups===void 0)throw new ConfigError13(`No ref lookup answers to ${request.lookups.map(name=>`'${name}'`).join(", ")}.`,{details:["The plugin that adds it may be disabled or missing."]});return lookups.length===0?{result:resolution(request.input,orderRefs(kept.map(ref=>({ref,rank:ref}))),pruned,!1)}:{kept,pruned,lookups}},finish4=(request,pruned,found)=>{let kinds=request.kinds,matching2=found.filter(entry=>kinds===void 0||kinds.includes(entry.match.ref.kind)),exact=matching2.filter(entry=>entry.match.exactSpelling),chosen=exact.length>0?exact:matching2;return resolution(request.input,orderRefs(chosen.map(entry=>({ref:entry.match.ref,rank:entry.rank}))),pruned,!0)};return{parse:parse6,async resolve(request){let early=begin(request);if("result"in early)return early.result;let found=[];for(let candidate of early.kept)for(let lookup of early.lookups)if(answersFor(lookup,candidate))for(let match2 of await lookup.find(candidate,ctx))found.push({match:match2,rank:candidate});return finish4(request,early.pruned,found)},resolveSync(request){let early=begin(request);if("result"in early)return early.result;let found=[];for(let candidate of early.kept)for(let lookup of early.lookups)if(lookup.findSync!==void 0&&answersFor(lookup,candidate))for(let match2 of lookup.findSync(candidate,ctx))found.push({match:match2,rank:candidate});return finish4(request,early.pruned,found)},isValid(input,from="commandLine"){try{return parse6(input,from),!0}catch{return!1}},findInString(text,from="commandLine"){let found=[];for(let word of text.matchAll(/\S+/g)){let bare=word[0].replace(/^[`"'([<{]+/,"").replace(/[`"')\]>},.;:!]+$/,"");if(bare.length!==0)try{found.push({text:bare,index:word.index+word[0].indexOf(bare),result:parse6(bare,from)})}catch{}}return found}}}var package_default5={name:"@sous-io/plugin-refs",version:"1.0.12",description:"Parsing and resolving refs, picking among matches, # names, repository locations and identity.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-host":"workspace:*",semver:"^7.8.5"},devDependencies:{"@sous-io/core":"workspace:*","@types/semver":"^7.8.0"},engines:{node:">=22"}};var BROWSE_WORDS=new Set(["tree","blob"]);function withoutGitSuffix(segment){return segment.replace(/\.git$/i,"")}function readingsAfterRepository(repoPath,rest){let after=rest[0]==="-"?rest.slice(1):[...rest],readings=[];return after.length>=2&&BROWSE_WORDS.has(after[0].toLowerCase())&&readings.push({repoPath,browsed:after.slice(1).join("/")}),readings.push({repoPath,named:after}),readings}function normalizeRepoUrl(url2){let value=url2.trim();for(;value.endsWith("/");)value=value.slice(0,-1);return value.endsWith(".git")&&(value=value.slice(0,-4)),value}function splitRepoUrl(url2){let normalized=normalizeRepoUrl(url2);if(normalized.length===0)return;let host,repoPath,scp=/^(?:([^@\s/]+)@)?([^@\s/:]+):(.+)$/.exec(normalized);if(/^[a-z][a-z0-9+.-]*:\/\//i.test(normalized)){let parsed;try{parsed=new URL(normalized)}catch{return}host=parsed.host.toLowerCase(),repoPath=parsed.pathname.replace(/^\/+/,"")}else if(scp!==null)host=scp[2].toLowerCase(),repoPath=scp[3].replace(/^\/+/,"");else return;let segments=repoPath.split("/").filter(segment=>segment.length>0);if(!(segments.length<2||host.length===0))return{host,owner:segments.slice(0,-1).join("/"),name:segments[segments.length-1]}}function buildCanonicalRepository(host,owner,name){return{host,owner,name,httpsUrl:`https://${host}/${owner}/${name}.git`,sshUrl:`git@${host}:${owner}/${name}.git`}}function defaultLocator(id,defaultHost,host,repoPath,rest){let where2=host===defaultHost?repoPath:`${host}/${repoPath}`;return`${id}://${where2}${rest.length===0?"":`/${rest}`}`}var PLUGIN_NAME4="@sous-io/plugin-refs",BUILT_IN_SPLITTERS=[querySplitter,rangeSplitter,locationSplitter,repoQualifierSplitter,envVarSplitter,namePathSplitter],refsPlugin=definePlugin5({name:PLUGIN_NAME4,version:package_default5.version,description:"Parsing and resolving refs, picking among matches, # names, repository locations and identity.",dependsOn:{"@sous-io/plugin-host":`^${package_default5.version}`},register(sous){sous.entities.define("ref-splitter",jsonSchema7({type:"object",properties:{id:{type:"string"},order:{type:"number"}},required:["id","order","split"]}),{description:"One step of the ref parser: reads part of a written ref, every way it can be read."}),sous.entities.define("ref-pruner",jsonSchema7({type:"object",properties:{id:{type:"string"},source:{type:"string"},place:{type:"string"}},required:["id","source","place","prune"]}),{description:"Which readings of a ref count in one place it is written."}),sous.entities.define("ref-lookup",jsonSchema7({type:"object",properties:{id:{type:"string"},description:{type:"string"},kinds:{type:"array",items:{type:"string"}},tags:{type:"array",items:{type:"string"}},optIn:{type:"boolean"}},required:["id","find"]}),{description:"What exists, for narrowing the readings of a ref."}),sous.entities.define("hash-name",hashNameSchema,{description:"A '#' name, such as '#project', and what it stands for."});for(let splitter2 of BUILT_IN_SPLITTERS)sous.entities.add("ref-splitter",splitter2);for(let pruner of BUILT_IN_PRUNERS)sous.entities.add("ref-pruner",pruner);sous.entities.add("hash-name",projectHashName),sous.services.add("refs.locations",(_config,ctx)=>createRefsLocations(ctx.entities),{lifetime:"config"}),sous.services.add("refs.parser",(_config,ctx)=>createRefsParser(ctx),{lifetime:"config"}),sous.services.add("refs.resolver",(_config,ctx)=>createRefsResolver(ctx),{lifetime:"config"}),sous.services.add("refs.format",(_config,ctx)=>createRefsFormat(ctx),{lifetime:"config"}),sous.services.add("refs.picker",(_config,ctx)=>createRefsPicker(()=>ctx.services.get("refs.locations")),{lifetime:"config"})}});import{definePlugin as definePlugin6}from"@sous-io/plugin-api";var AUTO_VARIABLE_NAMES=["projectRoot","sousDir","sousConfigPath","sousConfDir","sousHome","sousRootPath","sousVersion"],NAMES=new Set(AUTO_VARIABLE_NAMES);function isAutoVariable(name){return NAMES.has(name)}function buildAutoVariables(inputs){let vars={sousRootPath:inputs.packageRoot,sousVersion:inputs.version,sousHome:inputs.sousHome},project=inputs.project;return project&&(vars.projectRoot=project.root,vars.sousDir=project.sousDir,vars.sousConfDir=project.confDir,project.configPath!==void 0&&(vars.sousConfigPath=project.configPath)),vars}var ENV_PREFIX="SOUS_VAR_",VARIABLE_NAME_PATTERN=/^[a-z][a-zA-Z0-9]*$/,ENV_NAME_PATTERN=/^[A-Z][A-Z0-9_]*$/;function toUpperSnake(name){return name.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/[-\s.]+/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,"").toUpperCase()}function sharedName(variable){return`${ENV_PREFIX}${toUpperSnake(variable)}`}function recipeScopedName(namespace,recipe,variable){return`${ENV_PREFIX}${toUpperSnake(namespace)}_${toUpperSnake(recipe)}_${toUpperSnake(variable)}`}function namespaceScopedName(namespace,variable){return`${ENV_PREFIX}${toUpperSnake(namespace)}_${toUpperSnake(variable)}`}function bareName(definition){return definition.env??sharedName(definition.name)}var variablesNames={envPrefix:ENV_PREFIX,toUpperSnake,sharedName,recipeScopedName,namespaceScopedName,bareName,isVariableName:text=>VARIABLE_NAME_PATTERN.test(text),isEnvName:text=>ENV_NAME_PATTERN.test(text)};init_src();import path19 from"node:path";import{ConfigError as ConfigError15}from"@sous-io/plugin-api";import path18 from"node:path";import{ConfigError as ConfigError14}from"@sous-io/plugin-api";var REFERENCE=/\$\{([^}]+)\}/g;function substitute(text,scope){return text.replace(REFERENCE,(match2,name)=>Object.hasOwn(scope,name)?scope[name]:match2)}function references(text){return[...new Set([...text.matchAll(REFERENCE)].map(match2=>match2[1]))]}function unresolved(text,scope={}){return references(text).filter(name=>!Object.hasOwn(scope,name))}function substituteStrict(text,scope,context){let result=substitute(text,scope),missing=references(result);if(missing.length===0)return result;let names2=missing.map(name=>`\${${name}}`).join(", "),one=missing.length===1,available=Object.keys(scope).sort();throw new ConfigError14(`Unresolved ${one?"variable":"variables"} ${names2} in ${context}`,{details:[`raw value: ${text}`,`Define ${one?"it":"them"} in a _vars block, or map ${one?"it":"them"} from the environment via the top-level _env block (values can come from .sous/.env.local or .sous/.env).`,`Variables in scope here: ${available.length>0?available.join(", "):"(none)"}`]})}function substituteValue(value,scope,context){return walk2(value,scope,context)}function walk2(value,scope,context){if(typeof value=="string")return substituteStrict(value,scope,context);if(Array.isArray(value))return value.map((item,index)=>walk2(item,scope,`${context}[${index}]`));if(value!==null&&typeof value=="object"){let out={};for(let[key,item]of Object.entries(value))out[key]=walk2(item,scope,context===""?key:`${context}.${key}`);return out}return value}function normalizePath2(value,home){let result=value;return home!==void 0&&home!==""&&(result==="~"?result=home:result.startsWith("~/")&&(result=path18.join(home,result.slice(2)))),path18.isAbsolute(result)?path18.normalize(result):result}function resolveBlock(block,inherited,context,options={}){let entries=new Map;for(let[key,value]of Object.entries(block))if(value!=null){if(isAutoVariable(key)){if(options.partial||restatesAutoVariable(key,value,inherited))continue;throw autoVariableError(key,context)}entries.set(key,typeof value=="string"?value:String(value))}let scope={...inherited},waiting=new Set(entries.keys()),resolved=[],progressed=!0;for(;progressed&&waiting.size>0;){progressed=!1;for(let key of waiting){let substituted=substitute(entries.get(key),scope);references(substituted).length===0&&(scope[key]=substituted,waiting.delete(key),resolved.push(key),progressed=!0)}}if(waiting.size>0&&!options.partial)throw unresolvedBlockError(entries,scope,waiting,context);return{scope,resolved,pending:[...waiting]}}function restatesAutoVariable(name,value,inherited){let own=inherited[name];if(own===void 0||typeof value!="string")return!1;let written=substitute(value,inherited);return written===own||references(written).length===0&&path19.resolve(written)===path19.resolve(own)}function autoVariableError(name,context){return new ConfigError15(`${context} sets "${name}", which sous sets itself.`,{details:[`Remove "${name}" from ${context}; \${${name}} always holds the value sous gives it.`]})}function unresolvedBlockError(entries,scope,waiting,context){let needs=new Map;for(let key of waiting)needs.set(key,references(substitute(entries.get(key),scope)));let edges=new Map;for(let key of waiting)edges.set(key,needs.get(key).filter(name=>waiting.has(name)));let cycles=findCycles([...waiting],edges),undefinedRefs=new Map;for(let key of waiting)for(let name of needs.get(key))if(!waiting.has(name)){let referrers=undefinedRefs.get(name)??new Set;referrers.add(key),undefinedRefs.set(name,referrers)}let details=[];for(let key of[...waiting].sort()){let names2=needs.get(key).map(name=>`\${${name}}`).join(", ");details.push(`- ${key} still needs ${names2||"(nothing resolvable)"}`)}if(cycles.length>0){details.push("","Reference cycles (these variables reference each other):");for(let cycle of cycles){let sorted2=[...cycle].sort();details.push(`- ${[...sorted2,sorted2[0]].join(" -> ")}`)}}if(undefinedRefs.size>0){details.push("","Undefined references (names defined nowhere: no _vars, _env, or auto-variable):");for(let name of[...undefinedRefs.keys()].sort())details.push(`- \${${name}} (needed by ${[...undefinedRefs.get(name)].sort().join(", ")})`)}let inScope=Object.keys(scope).sort();return details.push("",`Variables in scope here: ${inScope.length>0?inScope.join(", "):"(none)"}`),new ConfigError15(`Unresolved variables in ${context}:`,{details})}function findCycles(nodes,edges){let index=new Map,low=new Map,onStack=new Set,stack=[],components=[],counter=0,connect=node=>{index.set(node,counter),low.set(node,counter),counter++,stack.push(node),onStack.add(node);for(let next of edges.get(node)??[])index.has(next)?onStack.has(next)&&low.set(node,Math.min(low.get(node),index.get(next))):(connect(next),low.set(node,Math.min(low.get(node),low.get(next))));if(low.get(node)===index.get(node)){let component=[],member;do member=stack.pop(),onStack.delete(member),component.push(member);while(member!==node);components.push(component)}};for(let node of nodes)index.has(node)||connect(node);return components.filter(component=>component.length>1||(edges.get(component[0])??[]).includes(component[0]))}import{ConfigError as ConfigError16,SousError as SousError13}from"@sous-io/plugin-api";var ENV_LOCAL_NAME2=".env.local",ENV_DEFAULTS_NAME=".env";function buildScope(view,autoVariables,request,partial2){let scope={},origins={},lay=(values,from,skipAuto)=>{for(let[name,value]of Object.entries(values??{}))typeof value!="string"||skipAuto&&isAutoVariable(name)||(scope[name]=value,origins[name]={from,value})};lay(autoVariables,"auto",!1);let sources=view.sources(),context={project:view.project,env:view.env,config:view.lookup};for(let source of sources)lay(source.variables(context),source.id,!0);if(request.scopeKey!==void 0)for(let source of sources)lay(source.scoped?.(request.scopeKey,context),source.id,!0);lay(envScope(view,partial2),"_env",!1);let current=scope,block=(path103,values)=>{if(!isRecord(values))return;let result=resolveBlock(values,current,path103,{partial:partial2});for(let name of result.resolved)origins[name]={from:path103,value:result.scope[name]};current=result.scope};block("_vars",view.get("_vars"));let level=request.level??"root";if(level!=="root"&&block("compilation._vars",view.get("compilation._vars")),level==="target"||level==="output"){let targetPath=`compilation.targets[${requireIndex(request.target,"target",level)}]`;if(block(`${targetPath}._vars`,view.get(`${targetPath}._vars`)),level==="output"){let output=requireIndex(request.output,"output",level),outputPath=`${targetPath}.outputs[${output}]`;block(`${outputPath}._vars`,view.get(`${outputPath}._vars`))}}request.extra!==void 0&&block("extra",request.extra);let kept={};for(let name of Object.keys(current))kept[name]=origins[name];return{scope:current,origins:kept}}function envScope(view,partial2){let mapping=view.get("_env"),scope={};if(!isRecord(mapping))return scope;for(let[name,envName]of Object.entries(mapping)){if(typeof envName!="string")continue;if(isAutoVariable(name)){if(partial2)continue;throw autoVariableError(name,"_env")}let value=view.env[envName];if(value===void 0){if(partial2)continue;throw unsetEnvError(name,envName,view.project)}scope[name]=value}return scope}function unsetEnvError(name,envName,project){let sousDir=project?.sousDir,local2=sousDir?`${sousDir}/${ENV_LOCAL_NAME2}`:`.sous/${ENV_LOCAL_NAME2}`,defaults2=sousDir?`${sousDir}/${ENV_DEFAULTS_NAME}`:`.sous/${ENV_DEFAULTS_NAME}`;return new ConfigError16(`_env resolution failed: environment variable '${envName}' (mapped to config var '${name}') is not set.`,{details:[`Define it in ${local2} as:`,` ${envName}=<value>`,`...or, if the value is shared by the whole team and is not a secret, in ${defaults2} (committed).`,"...or export it in your shell before running sous."]})}function requireIndex(index,what,level){if(index===void 0||!Number.isInteger(index)||index<0)throw new SousError13(`A scope at the ${level} level needs the ${what} index.`);return index}function isRecord(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}var Resolver=class{constructor(deps){this.deps=deps}cache=new WeakMap;substitute(text,scope){return substitute(text,scope)}substituteStrict(text,scope,context){return substituteStrict(text,scope,context)}substituteValue(value,scope,context){return substituteValue(value,scope,context)}references(text){return references(text)}unresolved(text,scope){return unresolved(text,scope)}normalizePath(value){return normalizePath2(value,this.deps.env.HOME??this.deps.env.USERPROFILE)}resolveBlock(block,inherited,context){return resolveBlock(block,inherited,context).scope}autoVariables(){return this.autoFor(this.deps.env,this.deps.project)}isAutoVariable(name){return isAutoVariable(name)}scope(request={}){return this.build(this.deps.engine.config,request).scope}scopeIn(config2,request={}){return this.build(config2,request).scope}origins(request={}){return this.build(this.deps.engine.config,request).origins}originsIn(config2,request={}){return this.build(config2,request).origins}requestAt(path103){let segments=typeof path103=="string"?parsePath(path103):path103;if(segments[0]!=="compilation")return{level:"root"};let target=segments[2];if(segments[1]!=="targets"||typeof target!="number")return{level:"compilation"};let output=segments[4];return segments[3]!=="outputs"||typeof output!="number"?{level:"target",target}:{level:"output",target,output}}build(config2,request){if(isBuilder(config2)){let view2=builderView(config2);return buildScope(view2,this.autoFor(view2.env,view2.project),request,request.partial??!0)}let cacheable=isBuiltConfig(config2),partial2=request.partial??!cacheable,key=JSON.stringify([request.level,request.target,request.output,request.scopeKey,request.extra,partial2]),cached2=cacheable?this.cache.get(config2)?.get(key):void 0;if(cached2)return cached2;let entities=cacheable?config2.entities:this.deps.engine.config.entities,view=lookupView(config2,entities,this.deps.env,this.deps.project),built=buildScope(view,this.autoFor(view.env,view.project),request,partial2);if(cacheable){let forConfig=this.cache.get(config2)??new Map;forConfig.set(key,built),this.cache.set(config2,forConfig)}return built}autoFor(env,project){let identity2=this.deps.services.get("host.package").identity();return buildAutoVariables({project,sousHome:this.deps.services.get("host.sous-home").paths(env).root,packageRoot:identity2.root,version:identity2.version})}};function isBuilder(config2){let candidate=config2;return typeof candidate.atPath=="function"&&typeof candidate.entities=="function"}function isBuiltConfig(config2){let candidate=config2;return typeof candidate.hash=="string"&&typeof candidate.entities?.list=="function"}function builderView(builder){let lookup={get:path103=>builder.atPath(path103).get()};return{get:path103=>lookup.get(path103),sources:()=>builder.entities("variable-source"),lookup,env:builder.env,project:builder.project}}function lookupView(config2,entities,env,project){return{get:path103=>config2.get(path103),sources:()=>entities.list("variable-source"),lookup:config2,env,project}}function variableMap(what){return{"~standard":{version:1,vendor:"sous",validate(value){if(value===void 0)return{value:void 0};if(value===null||typeof value!="object"||Array.isArray(value))return{issues:[{message:`Expected an object of ${what}.`}]};let issues=[];for(let[name,item]of Object.entries(value))isAutoVariable(name)&&name!=="projectRoot"?issues.push({message:`"${name}" is set by sous; it cannot be set here. Remove it: \${${name}} always holds the value sous gives it.`,path:[name]}):typeof item!="string"&&issues.push({message:`Expected a string (${what}), got ${item===null?"null":typeof item}.`,path:[name]});return issues.length>0?{issues}:{value}}}}}var CONFIG_KEYS=[{id:"_vars",description:"Config variables, used as ${name}. Values may refer to each other in any order.",schema:variableMap("variable values")},{id:"_env",description:"Config variables read from the environment: each name mapped to an environment variable.",schema:variableMap("environment variable names")}],VARIABLE_SOURCE_SCHEMA={"~standard":{version:1,vendor:"sous",validate(value){let entry=value,issues=[];(typeof entry?.id!="string"||entry.id==="")&&issues.push({message:"A variable-source entity needs an id.",path:["id"]}),typeof entry?.description!="string"&&issues.push({message:"A variable-source entity needs a description.",path:["description"]}),typeof entry?.variables!="function"&&issues.push({message:"A variable-source entity needs a variables function.",path:["variables"]});for(let name of["scoped","secrets"])entry?.[name]!==void 0&&typeof entry[name]!="function"&&issues.push({message:`A variable-source entity's ${name} must be a function.`,path:[name]});return entry?.forbiddenUnder!==void 0&&!Array.isArray(entry.forbiddenUnder)&&issues.push({message:"A variable-source entity's forbiddenUnder must be a list of keys.",path:["forbiddenUnder"]}),issues.length>0?{issues}:{value}}}};var HIDDEN_VALUE="(hidden)",SECRET_NAME_ENDINGS=[["token"],["secret"],["secrets"],["password"],["passwd"],["passphrase"],["credential"],["credentials"],["apikey"],["api","key"],["private","key"],["access","key"],["secret","key"],["signing","key"],["encryption","key"]],SECRET_VALUE_PATTERNS=[/-----BEGIN [A-Z ]*PRIVATE KEY-----/,/\bgh[pousr]_[A-Za-z0-9]{36,}/,/\bgithub_pat_[A-Za-z0-9_]{22,}/,/\bglpat-[A-Za-z0-9_-]{20,}/,/\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/,/\bxox[abposr]-[A-Za-z0-9-]{10,}/,/\b[rs]k_live_[A-Za-z0-9]{16,}/,/\bsk-ant-[A-Za-z0-9_-]{20,}/,/\bsk-(?:proj-)?[A-Za-z0-9_-]{32,}/,/\bAIza[0-9A-Za-z_-]{35}/,/\bnpm_[A-Za-z0-9]{36}\b/,/\beyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/,/^[a-z][a-z0-9+.-]*:\/\/[^/\s:@]+:[^/\s@]+@/i],PLAIN_VALUE=/^(?:|-?\d+(?:\.\d+)?|true|false|yes|no|on|off)$/i;function nameWords(name){return name.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").split(/[^A-Za-z0-9]+/).filter(word=>word.length>0).map(word=>word.toLowerCase())}function hasSecretName(name){let words=nameWords(name);return SECRET_NAME_ENDINGS.some(ending=>words.length>=ending.length&&ending.every((word,i)=>words[words.length-ending.length+i]===word))}function hasSecretValue(value){return SECRET_VALUE_PATTERNS.some(pattern=>pattern.test(value))}function looksLikeSecret(name,value){return hasSecretValue(value)?!0:hasSecretName(name)&&!PLAIN_VALUE.test(value.trim())}function isSecret(name,value,declared=new Set){return typeof value!="string"?!1:declared.has(name)?value.length>0:looksLikeSecret(name,value)}function hideSecrets(scope,declared=new Set){let out={};for(let[name,value]of Object.entries(scope))out[name]=isSecret(name,value,declared)?HIDDEN_VALUE:value;return out}var Secrets=class{constructor(sources,context){this.sources=sources;this.context=context}hiddenValue=HIDDEN_VALUE;cached;declared(){if(!this.cached){let names2=new Set,context=this.context();for(let source of this.sources())for(let name of source.secrets?.(context)??[])names2.add(name);this.cached=names2}return this.cached}isSecret(name,value,declared=this.declared()){return isSecret(name,value,declared)}hasSecretName(name){return hasSecretName(name)}hasSecretValue(value){return hasSecretValue(value)}hide(scope,declared=this.declared()){return hideSecrets(scope,declared)}};var package_default6={name:"@sous-io/plugin-variables",version:"1.0.12",description:"${var} substitution, _vars resolution, auto-variables, variable names and secrets.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/documents":"workspace:*","@sous-io/plugin-api":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME5="@sous-io/plugin-variables",RESERVED_NAMES_CONTRIBUTOR="variables/reserved-names",variablesPlugin=definePlugin6({name:PLUGIN_NAME5,version:package_default6.version,description:"${var} substitution, _vars resolution, auto-variables, variable names and secrets.",dependsOn:{"@sous-io/plugin-host":`^${package_default6.version}`},register(sous){sous.services.add("variables.resolver",(_config,ctx)=>new Resolver({services:sous.services,engine:sous.engine,env:ctx.env,project:ctx.project}),{lifetime:"singleton"}),sous.services.add("variables.names",()=>variablesNames,{lifetime:"singleton"}),sous.services.add("variables.secrets",(config2,ctx)=>new Secrets(()=>ctx.entities.list("variable-source"),()=>({project:ctx.project,env:ctx.env,config:config2})),{lifetime:"config"}),sous.entities.define("variable-source",VARIABLE_SOURCE_SCHEMA,{description:"An extra source of config variables, such as recipe answers."});for(let key of CONFIG_KEYS)sous.entities.add("config-key",key);sous.config.contribute({id:RESERVED_NAMES_CONTRIBUTOR,contribute(config2){let vars=config2.atPath("_vars");for(let name of vars.isObject()?vars.keys():[])name.startsWith("sous")&&!isAutoVariable(name)&&config2.warn(`The variable "${name}" uses the reserved "sous*" namespace and may clash with a variable sous sets.`)}})}});import{definePlugin as definePlugin7}from"@sous-io/plugin-api";import{PassThrough}from"stream";import{sep as sep2,extname,resolve as resolve$1,dirname as dirname$1}from"path";import{statSync,readFileSync as readFileSync$1,stat,readFile as readFile$1}from"fs";import{createRequire as createRequire2}from"module";var Token=class{constructor(kind,input,begin,end,file2){this.kind=kind,this.input=input,this.begin=begin,this.end=end,this.file=file2}getText(){return this.input.slice(this.begin,this.end)}getPosition(){let[row,col]=[1,1];for(let i=0;i<this.begin;i++)this.input[i]===`
837
838
  `?(row++,col=1):col++;return[row,col]}size(){return this.end-this.begin}},Drop=class{liquidMethodMissing(key,context){}},toString$1=Object.prototype.toString,toLowerCase=String.prototype.toLowerCase,hasOwnProperty=Object.hasOwnProperty;function isString(value){return typeof value=="string"}function isFunction(value){return typeof value=="function"}function isPromise(val){return val&&isFunction(val.then)}function isIterator(val){return val&&isFunction(val.next)&&isFunction(val.throw)&&isFunction(val.return)}function escapeRegex(str){return str.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")}function promisify(fn){return function(...args){return new Promise((resolve4,reject2)=>{fn(...args,(err,result)=>{err?reject2(err):resolve4(result)})})}}function stringify2(value){return value=toValue(value),isString(value)?value:isNil(value)?"":isArray(value)?value.map(x2=>stringify2(x2)).join(""):String(value)}function toEnumerable(val){return val=toValue(val),isArray(val)?val:isString(val)&&val.length>0?[val]:isIterable(val)?Array.from(val):isObject(val)?Object.keys(val).map(key=>[key,val[key]]):[]}function toArray(val){return val=toValue(val),isNil(val)?[]:isArray(val)?val:[val]}function toValue(value){return value instanceof Drop&&isFunction(value.valueOf)?value.valueOf():value}function toNumber(value){return+toValue(value)||0}function isNumber(value){return typeof value=="number"}function toLiquid(value){return value&&isFunction(value.toLiquid)?toLiquid(value.toLiquid()):value}function isNil(value){return value==null}function isUndefined(value){return value===void 0}function isArray(value){return toString$1.call(value)==="[object Array]"}function isArrayLike(value){return value&&isNumber(value.length)}function isIterable(value){return isObject(value)&&Symbol.iterator in value}function forOwn(obj,iteratee){obj=obj||{};for(let k2 in obj)if(hasOwnProperty.call(obj,k2)&&iteratee(obj[k2],k2,obj)===!1)break;return obj}function last(arr){return arr[arr.length-1]}function isObject(value){let type=typeof value;return value!==null&&(type==="object"||type==="function")}function range2(start2,stop,step=1){let arr=[];for(let i=start2;i<stop;i+=step)arr.push(i);return arr}function padStart(str,length,ch=" "){return pad(str,length,ch,(str2,ch2)=>ch2+str2)}function padEnd(str,length,ch=" "){return pad(str,length,ch,(str2,ch2)=>str2+ch2)}function pad(str,length,ch,add){str=String(str);let n7=length-str.length;for(;n7-- >0;)str=add(str,ch);return str}function identify(val){return val}function changeCase(str){return[...str].some(ch=>ch>="a"&&ch<="z")?str.toUpperCase():str.toLowerCase()}function ellipsis(str,N2){return str.length>N2?str.slice(0,N2-3)+"...":str}function caseInsensitiveCompare(a,b){return a==null&&b==null?0:a==null?1:b==null||(a=toLowerCase.call(a),b=toLowerCase.call(b),a<b)?-1:a>b?1:0}function argumentsToValue(fn){return function(...args){return fn.call(this,...args.map(toValue))}}function argumentsToNumber(fn){return function(...args){return fn.call(this,...args.map(toNumber))}}function escapeRegExp2(text){return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")}function*strictUniq(array2){let seen=new Set;for(let element of array2){let key=JSON.stringify(element);seen.has(key)||(seen.add(key),yield element)}}var TRAIT="__liquidClass__",LiquidError=class extends Error{constructor(err,token){super(typeof err=="string"?err:err.message),this.context="",typeof err!="string"&&Object.defineProperty(this,"originalError",{value:err,enumerable:!1}),Object.defineProperty(this,"token",{value:token,enumerable:!1}),Object.defineProperty(this,TRAIT,{value:"LiquidError",enumerable:!1})}update(){Object.defineProperty(this,"context",{value:mkContext(this.token),enumerable:!1}),this.message=mkMessage(this.message,this.token),this.stack=this.message+`
838
839
  `+this.context+`
839
840
  `+this.stack,this.originalError&&(this.stack+=`
@@ -846,7 +847,7 @@ From `+this.originalError.stack)}static is(obj){return obj?.[TRAIT]==="LiquidErr
846
847
  `)}function strip_html(v2){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.replace(/<script[\s\S]*?<\/script>|<style[\s\S]*?<\/style>|<.*?>|<!--[\s\S]*?-->/g,"")}var htmlFilters=Object.freeze({__proto__:null,escape:escape3,xml_escape,escape_once,newline_to_br,strip_html}),MapFS=class{constructor(mapping){this.mapping=mapping,this.sep="/"}exists(filepath){return __awaiter(this,void 0,void 0,function*(){return this.existsSync(filepath)})}existsSync(filepath){return!isNil(this.mapping[filepath])}readFile(filepath){return __awaiter(this,void 0,void 0,function*(){return this.readFileSync(filepath)})}readFileSync(filepath){let content=this.mapping[filepath];if(isNil(content))throw new Error(`ENOENT: ${filepath}`);return content}dirname(filepath){let segments=filepath.split(this.sep);return segments.pop(),segments.join(this.sep)}resolve(dir,file2,ext2){if(file2+=ext2,dir===".")return file2;let segments=dir.split(/\/+/);for(let segment of file2.split(this.sep))segment==="."||segment===""||(segment===".."?(segments.length>1||segments[0]!=="")&&segments.pop():segments.push(segment));return segments.join(this.sep)}},defaultOptions={root:["."],layouts:["."],partials:["."],relativeReference:!0,jekyllInclude:!1,keyValueSeparator:":",cache:void 0,extname:"",fs:fs13,dynamicPartials:!0,jsTruthy:!1,dateFormat:"%A, %B %-e, %Y at %-l:%M %P %z",locale:"",trimTagRight:!1,trimTagLeft:!1,trimOutputRight:!1,trimOutputLeft:!1,greedy:!0,tagDelimiterLeft:"{%",tagDelimiterRight:"%}",outputDelimiterLeft:"{{",outputDelimiterRight:"}}",preserveTimezones:!1,strictFilters:!1,strictVariables:!1,ownPropertyOnly:!0,lenientIf:!1,globals:{},keepOutputType:!1,operators:defaultOperators,memoryLimit:1/0,parseLimit:1/0,renderLimit:1/0};function normalize(options){var _a4,_b;if(options.hasOwnProperty("root")&&(options.hasOwnProperty("partials")||(options.partials=options.root),options.hasOwnProperty("layouts")||(options.layouts=options.root)),options.hasOwnProperty("cache")){let cache2;typeof options.cache=="number"?cache2=options.cache>0?new LRU(options.cache):void 0:typeof options.cache=="object"?cache2=options.cache:cache2=options.cache?new LRU(1024):void 0,options.cache=cache2}return options=Object.assign(Object.assign(Object.assign({},defaultOptions),options.jekyllInclude?{dynamicPartials:!1}:{}),options),(!options.fs.dirname||!options.fs.sep)&&options.relativeReference&&(console.warn("[LiquidJS] `fs.dirname` and `fs.sep` are required for relativeReference, set relativeReference to `false` to suppress this warning"),options.relativeReference=!1),options.root=normalizeDirectoryList(options.root),options.partials=normalizeDirectoryList(options.partials),options.layouts=normalizeDirectoryList(options.layouts),options.outputEscape=options.outputEscape&&getOutputEscapeFunction(options.outputEscape),options.locale||(options.locale=(_b=(_a4=getDateTimeFormat())===null||_a4===void 0?void 0:_a4().resolvedOptions().locale)!==null&&_b!==void 0?_b:"en-US"),options.templates&&(options.fs=new MapFS(options.templates),options.relativeReference=!0,options.root=options.partials=options.layouts="."),options}function getOutputEscapeFunction(nameOrFunction){return nameOrFunction==="escape"?escape3:nameOrFunction==="json"?misc.json:(assert(isFunction(nameOrFunction),"`outputEscape` need to be of type string or function"),nameOrFunction)}function normalizeDirectoryList(value){let list2=[];return isArray(value)&&(list2=value),isString(value)&&(list2=[value]),list2}function whiteSpaceCtrl(tokens,options){let inRaw=!1;for(let i=0;i<tokens.length;i++){let token=tokens[i];isDelimitedToken(token)&&(!inRaw&&token.trimLeft&&trimLeft(tokens[i-1],options.greedy),isTagToken(token)&&(token.name==="raw"?inRaw=!0:token.name==="endraw"&&(inRaw=!1)),!inRaw&&token.trimRight&&trimRight(tokens[i+1],options.greedy))}}function trimLeft(token,greedy){if(!token||!isHTMLToken(token))return;let mask=greedy?BLANK2:INLINE_BLANK;for(;TYPES[token.input.charCodeAt(token.end-1-token.trimRight)]&mask;)token.trimRight++}function trimRight(token,greedy){if(!token||!isHTMLToken(token))return;let mask=greedy?BLANK2:INLINE_BLANK;for(;TYPES[token.input.charCodeAt(token.begin+token.trimLeft)]&mask;)token.trimLeft++;token.input.charAt(token.begin+token.trimLeft)===`
847
848
  `&&token.trimLeft++}var Tokenizer=class{constructor(input,operators=defaultOptions.operators,file2,range3){this.input=input,this.file=file2,this.rawBeginAt=-1,this.p=range3?range3[0]:0,this.N=range3?range3[1]:input.length,this.opTrie=createTrie(operators),this.literalTrie=createTrie(literalValues)}readExpression(){return new Expression(this.readExpressionTokens())}*readExpressionTokens(){for(;this.p<this.N;){let operator=this.readOperator();if(operator){yield operator;continue}let operand=this.readValue();if(operand){yield operand;continue}return}}readOperator(){this.skipBlank();let end=this.matchTrie(this.opTrie);if(end!==-1)return new OperatorToken(this.input,this.p,this.p=end,this.file)}matchTrie(trie){let node=trie,i=this.p,info;for(;node[this.input[i]]&&i<this.N;)node=node[this.input[i++]],node.end&&(info=node);return!info||info.needBoundary&&isWord(this.peek(i-this.p))?-1:i}readFilteredValue(){let begin=this.p,initial=this.readExpression();this.assert(initial.valid(),`invalid value expression: ${this.snapshot()}`);let filters2=this.readFilters();return new FilteredValueToken(initial,filters2,this.input,begin,this.p,this.file)}readFilters(){let filters2=[];for(;;){let filter3=this.readFilter();if(!filter3)return filters2;filters2.push(filter3)}}readFilter(){if(this.skipBlank(),this.end())return null;this.assert(this.read()==="|",'expected "|" before filter');let name=this.readIdentifier();if(!name.size())return this.assert(this.end(),"expected filter name"),null;let args=[];if(this.skipBlank(),this.peek()===":")do{++this.p;let arg=this.readFilterArg();arg&&args.push(arg),this.skipBlank(),this.assert(this.end()||this.peek()===","||this.peek()==="|",()=>`unexpected character ${this.snapshot()}`)}while(this.peek()===",");else if(!(this.peek()==="|"||this.end()))throw this.error('expected ":" after filter name');return new FilterToken(name.getText(),args,this.input,name.begin,this.p,this.file)}readFilterArg(){let key=this.readValue();if(!key)return;if(this.skipBlank(),this.peek()!==":")return key;++this.p;let value=this.readValue();return[key.getText(),value]}readTopLevelTokens(options=defaultOptions){let tokens=[];for(;this.p<this.N;){let token=this.readTopLevelToken(options);tokens.push(token)}return whiteSpaceCtrl(tokens,options),tokens}readTopLevelToken(options){let{tagDelimiterLeft,outputDelimiterLeft}=options;return this.rawBeginAt>-1?this.readEndrawOrRawContent(options):this.match(tagDelimiterLeft)?this.readTagToken(options):this.match(outputDelimiterLeft)?this.readOutputToken(options):this.readHTMLToken([tagDelimiterLeft,outputDelimiterLeft])}readHTMLToken(stopStrings){let begin=this.p;for(;this.p<this.N&&!stopStrings.some(str=>this.match(str));)++this.p;return new HTMLToken(this.input,begin,this.p,this.file)}readTagToken(options){let{file:file2,input}=this,begin=this.p;if(this.readToDelimiter(options.tagDelimiterRight)===-1)throw this.error(`tag ${this.snapshot(begin)} not closed`,begin);let token=new TagToken(input,begin,this.p,options,file2);return token.name==="raw"&&(this.rawBeginAt=begin),token}readToDelimiter(delimiter,respectQuoted=!1){for(this.skipBlank();this.p<this.N;){if(respectQuoted&&this.peekType()&QUOTE){this.readQuoted();continue}if(++this.p,this.rmatch(delimiter))return this.p}return-1}readOutputToken(options=defaultOptions){let{file:file2,input}=this,{outputDelimiterRight}=options,begin=this.p;if(this.readToDelimiter(outputDelimiterRight,!0)===-1)throw this.error(`output ${this.snapshot(begin)} not closed`,begin);return new OutputToken(input,begin,this.p,options,file2)}readEndrawOrRawContent(options){let{tagDelimiterLeft,tagDelimiterRight}=options,begin=this.p,leftPos=this.readTo(tagDelimiterLeft)-tagDelimiterLeft.length;for(;this.p<this.N;){if(this.readIdentifier().getText()!=="endraw"){leftPos=this.readTo(tagDelimiterLeft)-tagDelimiterLeft.length;continue}for(;this.p<=this.N;){if(this.rmatch(tagDelimiterRight)){let end=this.p;return begin===leftPos?(this.rawBeginAt=-1,new TagToken(this.input,begin,end,options,this.file)):(this.p=leftPos,new HTMLToken(this.input,begin,leftPos,this.file))}if(this.rmatch(tagDelimiterLeft))break;this.p++}}throw this.error(`raw ${this.snapshot(this.rawBeginAt)} not closed`,begin)}readLiquidTagTokens(options=defaultOptions){let tokens=[];for(;this.p<this.N;){let token=this.readLiquidTagToken(options);token&&tokens.push(token)}return tokens}readLiquidTagToken(options){if(this.skipBlank(),this.end())return;let begin=this.p;this.readToDelimiter(`
848
849
  `);let end=this.p;return new LiquidTagToken(this.input,begin,end,options,this.file)}error(msg,pos=this.p){return new TokenizationError(msg,new IdentifierToken(this.input,pos,this.N,this.file))}assert(pred,msg,pos){if(!pred)throw this.error(typeof msg=="function"?msg():msg,pos)}snapshot(begin=this.p){return JSON.stringify(ellipsis(this.input.slice(begin,this.N),32))}readWord(){return this.readIdentifier()}readIdentifier(){this.skipBlank();let begin=this.p;for(;!this.end()&&isWord(this.peek());)++this.p;return new IdentifierToken(this.input,begin,this.p,this.file)}readNonEmptyIdentifier(){let id=this.readIdentifier();return id.size()?id:void 0}readTagName(){return this.skipBlank(),this.input[this.p]==="#"?this.input.slice(this.p,++this.p):this.readIdentifier().getText()}readHashes(jekyllStyle){let hashes=[];for(;;){let hash2=this.readHash(jekyllStyle);if(!hash2)return hashes;hashes.push(hash2)}}readHash(jekyllStyle){this.skipBlank(),this.peek()===","&&++this.p;let begin=this.p,name=this.readNonEmptyIdentifier();if(!name)return;let value;this.skipBlank();let sep3=isString(jekyllStyle)?jekyllStyle:jekyllStyle?"=":":";return this.peek()===sep3&&(++this.p,value=this.readValue()),new HashToken(this.input,begin,this.p,name,value,this.file)}remaining(){return this.input.slice(this.p,this.N)}advance(step=1){this.p+=step}end(){return this.p>=this.N}read(){return this.input[this.p++]}readTo(end){for(;this.p<this.N;)if(++this.p,this.rmatch(end))return this.p;return-1}readValue(){this.skipBlank();let begin=this.p,variable=this.readLiteral()||this.readQuoted()||this.readRange()||this.readNumber(),props=this.readProperties(!variable);return props.length?new PropertyAccessToken(variable,props,this.input,begin,this.p):variable}readScopeValue(){this.skipBlank();let begin=this.p,props=this.readProperties();if(props.length)return new PropertyAccessToken(void 0,props,this.input,begin,this.p)}readProperties(isBegin=!0){let props=[];for(;;){if(this.peek()==="["){this.p++;let prop=this.readValue()||new IdentifierToken(this.input,this.p,this.p,this.file);this.assert(this.readTo("]")!==-1,"[ not closed"),props.push(prop);continue}if(isBegin&&!props.length){let prop=this.readNonEmptyIdentifier();if(prop){props.push(prop);continue}}if(this.peek()==="."&&this.peek(1)!=="."){this.p++;let prop=this.readNonEmptyIdentifier();if(!prop)break;props.push(prop);continue}break}return props}readNumber(){this.skipBlank();let decimalFound=!1,digitFound=!1,n7=0;for(this.peekType()&SIGN&&n7++;this.p+n7<=this.N;)if(this.peekType(n7)&NUMBER)digitFound=!0,n7++;else if(this.peek(n7)==="."&&this.peek(n7+1)!=="."){if(decimalFound||!digitFound)return;decimalFound=!0,n7++}else break;if(digitFound&&!isWord(this.peek(n7))){let num=new NumberToken(this.input,this.p,this.p+n7,this.file);return this.advance(n7),num}}readLiteral(){this.skipBlank();let end=this.matchTrie(this.literalTrie);if(end===-1)return;let literal2=new LiteralToken(this.input,this.p,end,this.file);return this.p=end,literal2}readRange(){this.skipBlank();let begin=this.p;if(this.peek()!=="(")return;++this.p;let lhs=this.readValueOrThrow();this.skipBlank(),this.assert(this.read()==="."&&this.read()===".","invalid range syntax");let rhs=this.readValueOrThrow();return this.skipBlank(),this.assert(this.read()===")","invalid range syntax"),new RangeToken(this.input,begin,this.p,lhs,rhs,this.file)}readValueOrThrow(){let value=this.readValue();return this.assert(value,()=>`unexpected token ${this.snapshot()}, value expected`),value}readQuoted(){this.skipBlank();let begin=this.p;if(!(this.peekType()&QUOTE))return;++this.p;let escaped=!1;for(;this.p<this.N&&(++this.p,!(this.input[this.p-1]===this.input[begin]&&!escaped));)escaped?escaped=!1:this.input[this.p-1]==="\\"&&(escaped=!0);return new QuotedToken(this.input,begin,this.p,this.file)}*readFileNameTemplate(options){let{outputDelimiterLeft}=options,htmlStopStrings=[","," ","\r",`
849
- `," ",outputDelimiterLeft],htmlStopStringSet=new Set(htmlStopStrings);for(;this.p<this.N&&!htmlStopStringSet.has(this.peek());)yield this.match(outputDelimiterLeft)?this.readOutputToken(options):this.readHTMLToken(htmlStopStrings)}match(word){for(let i=0;i<word.length;i++)if(word[i]!==this.input[this.p+i])return!1;return!0}rmatch(pattern){for(let i=0;i<pattern.length;i++)if(pattern[pattern.length-1-i]!==this.input[this.p-1-i])return!1;return!0}peekType(n7=0){return this.p+n7>=this.N?0:TYPES[this.input.charCodeAt(this.p+n7)]}peek(n7=0){return this.p+n7>=this.N?"":this.input[this.p+n7]}skipBlank(){for(;this.peekType()&BLANK2;)++this.p}},ParseStream=class{constructor(tokens,parseToken){this.handlers={},this.stopRequested=!1,this.tokens=tokens,this.parseToken=parseToken}on(name,cb){return this.handlers[name]=cb,this}trigger(event,arg){let h=this.handlers[event];return h?(h.call(this,arg),!0):!1}start(){this.trigger("start");let token;for(;!this.stopRequested&&(token=this.tokens.shift());){if(this.trigger("token",token)||isTagToken(token)&&this.trigger(`tag:${token.name}`,token))continue;let template=this.parseToken(token,this.tokens);this.trigger("template",template)}return this.stopRequested||this.trigger("end"),this}stop(){return this.stopRequested=!0,this}},TemplateImpl=class{constructor(token){this.token=token}},Tag=class extends TemplateImpl{constructor(token,remainTokens,liquid){super(token),this.name=token.name,this.liquid=liquid,this.tokenizer=token.tokenizer}},Hash=class{constructor(input,jekyllStyle){this.hash={};let tokenizer=input instanceof Tokenizer?input:new Tokenizer(input,{});for(let hash2 of tokenizer.readHashes(jekyllStyle))this.hash[hash2.name.content]=hash2.value}*render(ctx){let hash2={};for(let key of Object.keys(this.hash))hash2[key]=this.hash[key]===void 0?!0:yield evalToken(this.hash[key],ctx);return hash2}};function createTagClass(options){return class extends Tag{constructor(token,tokens,liquid){super(token,tokens,liquid),isFunction(options.parse)&&options.parse.call(this,token,tokens)}*render(ctx,emitter){let hash2=yield new Hash(this.token.args,ctx.opts.keyValueSeparator).render(ctx);return yield options.render.call(this,ctx,emitter,hash2)}}}function isKeyValuePair(arr){return isArray(arr)}var Filter=class{constructor(token,options,liquid){this.token=token,this.name=token.name,this.handler=isFunction(options)?options:isFunction(options?.handler)?options.handler:identify,this.raw=!isFunction(options)&&!!options?.raw,this.args=token.args,this.liquid=liquid}*render(value,context){let argv2=[];for(let arg of this.args)isKeyValuePair(arg)?argv2.push([arg[0],yield evalToken(arg[1],context)]):argv2.push(yield evalToken(arg,context));return yield this.handler.apply({context,token:this.token,liquid:this.liquid},[value,...argv2])}},Value=class{constructor(input,liquid){this.filters=[];let token=typeof input=="string"?new Tokenizer(input,liquid.options.operators).readFilteredValue():input;this.initial=token.initial,this.filters=token.filters.map(token2=>new Filter(token2,this.getFilter(liquid,token2.name),liquid))}*value(ctx,lenient){lenient=lenient||ctx.opts.lenientIf&&this.filters.length>0&&this.filters[0].name==="default";let val=yield this.initial.evaluate(ctx,lenient);for(let filter3 of this.filters)val=yield filter3.render(val,ctx);return val}getFilter(liquid,name){let impl=liquid.filters[name];return assert(impl||!liquid.options.strictFilters,()=>`undefined filter: ${name}`),impl}},Output=class extends TemplateImpl{constructor(token,liquid){var _a4;super(token);let tokenizer=new Tokenizer(token.input,liquid.options.operators,token.file,token.contentRange);this.value=new Value(tokenizer.readFilteredValue(),liquid);let filters2=this.value.filters,outputEscape=liquid.options.outputEscape;if(!(!((_a4=filters2[filters2.length-1])===null||_a4===void 0)&&_a4.raw)&&outputEscape){let token2=new FilterToken(toString.call(outputEscape),[],"",0,0);filters2.push(new Filter(token2,outputEscape,liquid))}}*render(ctx,emitter){let val=yield this.value.value(ctx,!1);emitter.write(val)}*arguments(){yield this.value}},HTML=class extends TemplateImpl{constructor(token){super(token),this.str=token.getContent()}*render(ctx,emitter){emitter.write(this.str)}},Variable=class _Variable{constructor(segments,location){this.segments=segments,this.location=location}toString(){return segmentsString(this.segments,!0)}toArray(){function*_visit(...segments){for(let segment of segments)segment instanceof _Variable?yield Array.from(_visit(...segment.segments)):yield segment}return Array.from(_visit(...this.segments))}},VariableMap=class{constructor(){this.map=new Map}get(key){let k2=segmentsString([key.segments[0]]);return this.map.has(k2)||this.map.set(k2,[]),this.map.get(k2)}has(key){return this.map.has(segmentsString([key.segments[0]]))}push(variable){this.get(variable).push(variable)}asObject(){return Object.fromEntries(this.map)}},defaultStaticAnalysisOptions={partials:!0};function*_analyze(templates,partials,sync){let variables=new VariableMap,globals=new VariableMap,locals=new VariableMap,rootScope=new DummyScope(new Set),seen=new Set;function updateVariables(variable,scope){variables.push(variable);let aliased=scope.alias(variable);if(aliased!==void 0){let root=aliased.segments[0];isString(root)&&!rootScope.has(root)&&globals.push(aliased)}else{let root=variable.segments[0];isString(root)&&!scope.has(root)&&globals.push(variable)}for(let segment of variable.segments)segment instanceof Variable&&updateVariables(segment,scope)}function*visit2(template,scope){if(template.arguments)for(let arg of template.arguments())for(let variable of extractVariables(arg))updateVariables(variable,scope);if(template.localScope)for(let ident of template.localScope()){scope.add(ident.content),scope.deleteAlias(ident.content);let[row,col]=ident.getPosition();locals.push(new Variable([ident.content],{row,col,file:ident.file}))}if(template.children)if(template.partialScope){let partial2=template.partialScope();if(partial2===void 0){for(let child2 of yield template.children(partials,sync))yield visit2(child2,scope);return}if(seen.has(partial2.name))return;let partialScopeNames=new Set,partialScope=partial2.isolated?new DummyScope(partialScopeNames):scope.push(partialScopeNames);for(let name of partial2.scope)if(isString(name))partialScopeNames.add(name);else{let[alias,argument]=name;partialScopeNames.add(alias);let variables2=Array.from(extractVariables(argument));variables2.length&&partialScope.setAlias(alias,variables2[0].segments)}for(let child2 of yield template.children(partials,sync))yield visit2(child2,partialScope),seen.add(partial2.name);partialScope.pop()}else{template.blockScope&&scope.push(new Set(template.blockScope()));for(let child2 of yield template.children(partials,sync))yield visit2(child2,scope);template.blockScope&&scope.pop()}}for(let template of templates)yield visit2(template,rootScope);return{variables:variables.asObject(),globals:globals.asObject(),locals:locals.asObject()}}function analyze(template,options={}){let opts=Object.assign(Object.assign({},defaultStaticAnalysisOptions),options);return toPromise(_analyze(template,opts.partials,!1))}function analyzeSync(template,options={}){let opts=Object.assign(Object.assign({},defaultStaticAnalysisOptions),options);return toValueSync(_analyze(template,opts.partials,!0))}var DummyScope=class{constructor(globals){this.stack=[{names:globals,aliases:new Map}]}has(name){for(let scope of this.stack)if(scope.names.has(name))return!0;return!1}push(scope){return this.stack.push({names:scope,aliases:new Map}),this}pop(){var _a4;return(_a4=this.stack.pop())===null||_a4===void 0?void 0:_a4.names}add(name){this.stack[0].names.add(name)}alias(variable){let root=variable.segments[0];if(!isString(root))return;let alias=this.getAlias(root);if(alias!==void 0)return new Variable([...alias,...variable.segments.slice(1)],variable.location)}setAlias(from,to){this.stack[this.stack.length-1].aliases.set(from,to)}deleteAlias(name){this.stack[this.stack.length-1].aliases.delete(name)}getAlias(name){for(let scope of this.stack){if(scope.aliases.has(name))return scope.aliases.get(name);if(scope.names.has(name))return}}};function*extractVariables(value){isValueToken(value)?yield*extractValueTokenVariables(value):value instanceof Value&&(yield*extractFilteredValueVariables(value))}function*extractFilteredValueVariables(value){for(let token of value.initial.postfix)isValueToken(token)&&(yield*extractValueTokenVariables(token));for(let filter3 of value.filters)for(let arg of filter3.args)isKeyValuePair(arg)&&arg[1]?yield*extractValueTokenVariables(arg[1]):isValueToken(arg)&&(yield*extractValueTokenVariables(arg))}function*extractValueTokenVariables(token){isRangeToken(token)?(yield*extractValueTokenVariables(token.lhs),yield*extractValueTokenVariables(token.rhs)):isPropertyAccessToken(token)&&(yield extractPropertyAccessVariable(token))}function extractPropertyAccessVariable(token){let segments=[],file2=token.file,root=token.props[0];file2=file2||root.file,isQuotedToken(root)||isNumberToken(root)||isWordToken(root)?segments.push(root.content):isPropertyAccessToken(root)&&segments.push(...extractPropertyAccessVariable(root).segments);for(let prop of token.props.slice(1))file2=file2||prop.file,isQuotedToken(prop)||isNumberToken(prop)||isWordToken(prop)?segments.push(prop.content):isPropertyAccessToken(prop)&&segments.push(extractPropertyAccessVariable(prop));let[row,col]=token.getPosition();return new Variable(segments,{row,col,file:file2})}var RE_PROPERTY=/^[\u0080-\uFFFFa-zA-Z_][\u0080-\uFFFFa-zA-Z0-9_-]*$/;function segmentsString(segments,bracketedRoot=!1){let buf=[],root=segments[0];isString(root)&&(!bracketedRoot||root.match(RE_PROPERTY)?buf.push(`${root}`):buf.push(`['${root}']`));for(let segment of segments.slice(1))segment instanceof Variable?buf.push(`[${segmentsString(segment.segments)}]`):isString(segment)?segment.match(RE_PROPERTY)?buf.push(`.${segment}`):buf.push(`['${segment}']`):buf.push(`[${segment}]`);return buf.join("")}var LookupType;(function(LookupType2){LookupType2.Partials="partials",LookupType2.Layouts="layouts",LookupType2.Root="root"})(LookupType||(LookupType={}));var Loader=class{constructor(options){if(this.options=options,options.relativeReference){let sep3=options.fs.sep;assert(sep3,"`fs.sep` is required for relative reference");let rRelativePath=new RegExp(["."+sep3,".."+sep3,"./","../"].map(prefix=>escapeRegex(prefix)).join("|"));this.shouldLoadRelative=referencedFile=>rRelativePath.test(referencedFile)}else this.shouldLoadRelative=_referencedFile=>!1;this.contains=this.options.fs.contains||(()=>!0)}*lookup(file2,type,sync,currentFile){let{fs:fs68}=this.options,dirs=this.options[type];for(let filepath of this.candidates(file2,dirs,currentFile,type!==LookupType.Root))if(sync?fs68.existsSync(filepath):yield fs68.exists(filepath))return filepath;throw this.lookupError(file2,dirs)}*candidates(file2,dirs,currentFile,enforceRoot){let{fs:fs68,extname:extname3}=this.options,isAllowed=filepath=>{if(!enforceRoot)return!0;for(let dir of dirs)if(this.contains(dir,filepath))return!0;return!1};if(this.shouldLoadRelative(file2)&&currentFile){let referenced=fs68.resolve(this.dirname(currentFile),file2,extname3);isAllowed(referenced)&&(yield referenced)}for(let dir of dirs){let referenced=fs68.resolve(dir,file2,extname3);isAllowed(referenced)&&(yield referenced)}if(fs68.fallback!==void 0){let filepath=fs68.fallback(file2);filepath!==void 0&&isAllowed(filepath)&&(yield filepath)}}dirname(path103){let fs68=this.options.fs;return assert(fs68.dirname,"`fs.dirname` is required for relative reference"),fs68.dirname(path103)}lookupError(file2,roots){let err=new Error("ENOENT");return err.message=`ENOENT: Failed to lookup "${file2}" in "${roots}"`,err.code="ENOENT",err}},Parser=class{constructor(liquid){this.liquid=liquid,this.cache=this.liquid.options.cache,this.fs=this.liquid.options.fs,this.parseFile=this.cache?this._parseFileCached:this._parseFile,this.loader=new Loader(this.liquid.options),this.parseLimit=new Limiter("parse length",liquid.options.parseLimit)}parse(html,filepath){html=String(html),this.parseLimit.use(html.length);let tokens=new Tokenizer(html,this.liquid.options.operators,filepath).readTopLevelTokens(this.liquid.options);return this.parseTokens(tokens)}parseTokens(tokens){let token,templates=[],errors=[];for(;token=tokens.shift();)try{templates.push(this.parseToken(token,tokens))}catch(err){if(this.liquid.options.catchAllErrors)errors.push(err);else throw err}if(errors.length)throw new LiquidErrors(errors);return templates}parseToken(token,remainTokens){try{if(isTagToken(token)){let TagClass=this.liquid.tags[token.name];return assert(TagClass,`tag "${token.name}" not found`),new TagClass(token,remainTokens,this.liquid,this)}return isOutputToken(token)?new Output(token,this.liquid):new HTML(token)}catch(e){throw LiquidError.is(e)?e:new ParseError(e,token)}}parseStream(tokens){return new ParseStream(tokens,(token,tokens2)=>this.parseToken(token,tokens2))}*_parseFileCached(file2,sync,type=LookupType.Root,currentFile){let cache2=this.cache,key=this.loader.shouldLoadRelative(file2)?currentFile+","+file2:type+":"+file2,tpls=yield cache2.read(key);if(tpls)return tpls;let task=this._parseFile(file2,sync,type,currentFile),taskOrTpl=sync?yield task:toPromise(task);cache2.write(key,taskOrTpl);try{return yield taskOrTpl}catch(err){throw cache2.remove(key),err}}*_parseFile(file2,sync,type=LookupType.Root,currentFile){let filepath=yield this.loader.lookup(file2,type,sync,currentFile);return this.parse(sync?this.fs.readFileSync(filepath):yield this.fs.readFile(filepath),filepath)}},TokenKind;(function(TokenKind2){TokenKind2[TokenKind2.Number=1]="Number",TokenKind2[TokenKind2.Literal=2]="Literal",TokenKind2[TokenKind2.Tag=4]="Tag",TokenKind2[TokenKind2.Output=8]="Output",TokenKind2[TokenKind2.HTML=16]="HTML",TokenKind2[TokenKind2.Filter=32]="Filter",TokenKind2[TokenKind2.Hash=64]="Hash",TokenKind2[TokenKind2.PropertyAccess=128]="PropertyAccess",TokenKind2[TokenKind2.Word=256]="Word",TokenKind2[TokenKind2.Range=512]="Range",TokenKind2[TokenKind2.Quoted=1024]="Quoted",TokenKind2[TokenKind2.Operator=2048]="Operator",TokenKind2[TokenKind2.FilteredValue=4096]="FilteredValue",TokenKind2[TokenKind2.Delimited=12]="Delimited"})(TokenKind||(TokenKind={}));function isDelimitedToken(val){return!!(getKind(val)&TokenKind.Delimited)}function isOperatorToken(val){return getKind(val)===TokenKind.Operator}function isHTMLToken(val){return getKind(val)===TokenKind.HTML}function isOutputToken(val){return getKind(val)===TokenKind.Output}function isTagToken(val){return getKind(val)===TokenKind.Tag}function isQuotedToken(val){return getKind(val)===TokenKind.Quoted}function isNumberToken(val){return getKind(val)===TokenKind.Number}function isPropertyAccessToken(val){return getKind(val)===TokenKind.PropertyAccess}function isWordToken(val){return getKind(val)===TokenKind.Word}function isRangeToken(val){return getKind(val)===TokenKind.Range}function isValueToken(val){return(getKind(val)&1667)>0}function getKind(val){return val?val.kind:-1}var Context=class _Context{constructor(env={},opts=defaultOptions,renderOptions={},{memoryLimit,renderLimit}={}){var _a4,_b,_c,_d,_e2;this.scopes=[{}],this.registers={},this.breakCalled=!1,this.continueCalled=!1,this.sync=!!renderOptions.sync,this.opts=opts,this.globals=(_a4=renderOptions.globals)!==null&&_a4!==void 0?_a4:opts.globals,this.environments=isObject(env)?env:Object(env),this.strictVariables=(_b=renderOptions.strictVariables)!==null&&_b!==void 0?_b:this.opts.strictVariables,this.ownPropertyOnly=(_c=renderOptions.ownPropertyOnly)!==null&&_c!==void 0?_c:opts.ownPropertyOnly,this.memoryLimit=memoryLimit??new Limiter("memory alloc",(_d=renderOptions.memoryLimit)!==null&&_d!==void 0?_d:opts.memoryLimit),this.renderLimit=renderLimit??new Limiter("template render",getPerformance().now()+((_e2=renderOptions.renderLimit)!==null&&_e2!==void 0?_e2:opts.renderLimit))}getRegister(key){return this.registers[key]=this.registers[key]||{}}setRegister(key,value){return this.registers[key]=value}saveRegister(...keys){return keys.map(key=>[key,this.getRegister(key)])}restoreRegister(keyValues){return keyValues.forEach(([key,value])=>this.setRegister(key,value))}getAll(){return[this.globals,this.environments,...this.scopes].reduce((ctx,val)=>__assign(ctx,val),{})}get(paths){return this.getSync(paths)}getSync(paths){return toValueSync(this._get(paths))}*_get(paths){let scope=this.findScope(paths[0]);return yield this._getFromScope(scope,paths)}getFromScope(scope,paths){return toValueSync(this._getFromScope(scope,paths))}*_getFromScope(scope,paths,strictVariables=this.strictVariables){isString(paths)&&(paths=paths.split("."));for(let i=0;i<paths.length;i++)if(scope=yield this.readProperty(scope,paths[i]),strictVariables&&isUndefined(scope))throw new InternalUndefinedVariableError(paths.slice(0,i+1).join("."));return scope}push(ctx){return this.scopes.push(ctx)}pop(){return this.scopes.pop()}bottom(){return this.scopes[0]}spawn(scope={}){return new _Context(scope,this.opts,{sync:this.sync,globals:this.globals,strictVariables:this.strictVariables},{renderLimit:this.renderLimit,memoryLimit:this.memoryLimit})}findScope(key){for(let i=this.scopes.length-1;i>=0;i--){let candidate=this.scopes[i];if(key in candidate)return candidate}return key in this.environments?this.environments:this.globals}readProperty(obj,key){if(obj=toLiquid(obj),key=toValue(key),isNil(obj))return obj;if(isArray(obj)&&key<0)return obj[obj.length+ +key];let value=readJSProperty(obj,key,this.ownPropertyOnly);return value===void 0&&obj instanceof Drop?obj.liquidMethodMissing(key,this):isFunction(value)?value.call(obj):key==="size"?readSize(obj):key==="first"?readFirst(obj):key==="last"?readLast(obj):value}};function readJSProperty(obj,key,ownPropertyOnly){if(!(ownPropertyOnly&&!hasOwnProperty.call(obj,key)&&!(obj instanceof Drop)))return obj[key]}function readFirst(obj){return isArray(obj)?obj[0]:obj.first}function readLast(obj){return isArray(obj)?obj[obj.length-1]:obj.last}function readSize(obj){if(hasOwnProperty.call(obj,"size")||obj.size!==void 0)return obj.size;if(isArray(obj)||isString(obj))return obj.length;if(typeof obj=="object")return Object.keys(obj).length}var BlockMode;(function(BlockMode2){BlockMode2[BlockMode2.OUTPUT=0]="OUTPUT",BlockMode2[BlockMode2.STORE=1]="STORE"})(BlockMode||(BlockMode={}));var abs=argumentsToNumber(Math.abs),at_least=argumentsToNumber(Math.max),at_most=argumentsToNumber(Math.min),ceil=argumentsToNumber(Math.ceil),divided_by=argumentsToNumber((dividend,divisor,integerArithmetic=!1)=>integerArithmetic?Math.floor(dividend/divisor):dividend/divisor),floor=argumentsToNumber(Math.floor),minus=argumentsToNumber((v2,arg)=>v2-arg),plus=argumentsToNumber((lhs,rhs)=>lhs+rhs),modulo=argumentsToNumber((v2,arg)=>v2%arg),times=argumentsToNumber((v2,arg)=>v2*arg);function round(v2,arg=0){v2=toNumber(v2),arg=toNumber(arg);let amp=Math.pow(10,arg);return Math.round(v2*amp)/amp}var mathFilters=Object.freeze({__proto__:null,abs,at_least,at_most,ceil,divided_by,floor,minus,plus,modulo,times,round}),url_decode=x2=>decodeURIComponent(stringify2(x2)).replace(/\+/g," "),url_encode=x2=>encodeURIComponent(stringify2(x2)).replace(/%20/g,"+"),cgi_escape=x2=>encodeURIComponent(stringify2(x2)).replace(/%20/g,"+").replace(/[!'()*]/g,c=>"%"+c.charCodeAt(0).toString(16).toUpperCase()),uri_escape=x2=>encodeURI(stringify2(x2)).replace(/%5B/g,"[").replace(/%5D/g,"]"),rSlugifyDefault=/[^\p{M}\p{L}\p{Nd}]+/ug,rSlugifyReplacers={raw:/\s+/g,default:rSlugifyDefault,pretty:/[^\p{M}\p{L}\p{Nd}._~!$&'()+,;=@]+/ug,ascii:/[^A-Za-z0-9]+/g,latin:rSlugifyDefault,none:null};function slugify(str,mode="default",cased=!1){str=stringify2(str);let replacer=rSlugifyReplacers[mode];return replacer&&(mode==="latin"&&(str=removeAccents(str)),str=str.replace(replacer,"-").replace(/^-|-$/g,"")),cased?str:str.toLowerCase()}function removeAccents(str){return str.replace(/[àáâãäå]/g,"a").replace(/[æ]/g,"ae").replace(/[ç]/g,"c").replace(/[èéêë]/g,"e").replace(/[ìíîï]/g,"i").replace(/[ð]/g,"d").replace(/[ñ]/g,"n").replace(/[òóôõöø]/g,"o").replace(/[ùúûü]/g,"u").replace(/[ýÿ]/g,"y").replace(/[ß]/g,"ss").replace(/[œ]/g,"oe").replace(/[þ]/g,"th").replace(/[ẞ]/g,"SS").replace(/[Œ]/g,"OE").replace(/[Þ]/g,"TH")}var urlFilters=Object.freeze({__proto__:null,url_decode,url_encode,cgi_escape,uri_escape,slugify}),join=argumentsToValue(function(v2,arg){let array2=toArray(v2),sep3=isNil(arg)?" ":stringify2(arg),complexity=array2.length*(1+sep3.length);return this.context.memoryLimit.use(complexity),array2.join(sep3)}),last$1=argumentsToValue(v2=>isArrayLike(v2)?last(v2):""),first=argumentsToValue(v2=>isArrayLike(v2)?v2[0]:""),reverse=argumentsToValue(function(v2){let array2=toArray(v2);return this.context.memoryLimit.use(array2.length),[...array2].reverse()});function*sort(arr,property){let values=[],array2=toArray(arr);this.context.memoryLimit.use(array2.length);for(let item of array2)values.push([item,property?yield this.context._getFromScope(item,stringify2(property).split("."),!1):item]);return values.sort((lhs,rhs)=>{let lvalue=lhs[1],rvalue=rhs[1];return lvalue<rvalue?-1:lvalue>rvalue?1:0}).map(tuple2=>tuple2[0])}function sort_natural(input,property){let propertyString=stringify2(property),compare=property===void 0?caseInsensitiveCompare:(lhs,rhs)=>caseInsensitiveCompare(lhs[propertyString],rhs[propertyString]),array2=toArray(input);return this.context.memoryLimit.use(array2.length),[...array2].sort(compare)}var size=v2=>v2&&v2.length||0;function*map(arr,property){let results=[],array2=toArray(arr);this.context.memoryLimit.use(array2.length);for(let item of array2)results.push(yield this.context._getFromScope(item,stringify2(property),!1));return results}function*sum2(arr,property){let sum3=0,array2=toArray(arr);for(let item of array2){let data=Number(property?yield this.context._getFromScope(item,stringify2(property),!1):item);sum3+=Number.isNaN(data)?0:data}return sum3}function compact(arr){let array2=toArray(arr);return this.context.memoryLimit.use(array2.length),array2.filter(x2=>!isNil(toValue(x2)))}function concat(v2,arg=[]){let lhs=toArray(v2),rhs=toArray(arg);return this.context.memoryLimit.use(lhs.length+rhs.length),lhs.concat(rhs)}function push(v2,arg){return concat.call(this,v2,[arg])}function unshift(v2,arg){let array2=toArray(v2);this.context.memoryLimit.use(array2.length);let clone2=[...array2];return clone2.unshift(arg),clone2}function pop(v2){let clone2=[...toArray(v2)];return clone2.pop(),clone2}function shift(v2){let array2=toArray(v2);this.context.memoryLimit.use(array2.length);let clone2=[...array2];return clone2.shift(),clone2}function slice(v2,begin,length=1){return v2=toValue(v2),isNil(v2)?[]:(isArray(v2)||(v2=stringify2(v2)),begin=begin<0?v2.length+begin:begin,this.context.memoryLimit.use(length),v2.slice(begin,begin+length))}function expectedMatcher(expected){return this.context.opts.jekyllWhere?v2=>EmptyDrop.is(expected)?equals(v2,expected):isArray(v2)?arrayIncludes(v2,expected):equals(v2,expected):expected===void 0?v2=>isTruthy(v2,this.context):v2=>equals(v2,expected)}function*filter2(include,arr,property,expected){let values=[];arr=toArray(arr),this.context.memoryLimit.use(arr.length);let token=new Tokenizer(stringify2(property)).readScopeValue();for(let item of arr)values.push(yield evalToken(token,this.context.spawn(item)));let matcher2=expectedMatcher.call(this,expected);return arr.filter((_2,i)=>matcher2(values[i])===include)}function*filter_exp(include,arr,itemName,exp){let filtered=[],keyTemplate=new Value(stringify2(exp),this.liquid),array2=toArray(arr);this.context.memoryLimit.use(array2.length);for(let item of array2){this.context.push({[itemName]:item});let value=yield keyTemplate.value(this.context);this.context.pop(),value===include&&filtered.push(item)}return filtered}function*where(arr,property,expected){return yield*filter2.call(this,!0,arr,property,expected)}function*reject(arr,property,expected){return yield*filter2.call(this,!1,arr,property,expected)}function*where_exp(arr,itemName,exp){return yield*filter_exp.call(this,!0,arr,itemName,exp)}function*reject_exp(arr,itemName,exp){return yield*filter_exp.call(this,!1,arr,itemName,exp)}function*group_by(arr,property){let map3=new Map;arr=toEnumerable(arr);let token=new Tokenizer(stringify2(property)).readScopeValue();this.context.memoryLimit.use(arr.length);for(let item of arr){let key=yield evalToken(token,this.context.spawn(item));map3.has(key)||map3.set(key,[]),map3.get(key).push(item)}return[...map3.entries()].map(([name,items2])=>({name,items:items2}))}function*group_by_exp(arr,itemName,exp){let map3=new Map,keyTemplate=new Value(stringify2(exp),this.liquid);arr=toEnumerable(arr),this.context.memoryLimit.use(arr.length);for(let item of arr){this.context.push({[itemName]:item});let key=yield keyTemplate.value(this.context);this.context.pop(),map3.has(key)||map3.set(key,[]),map3.get(key).push(item)}return[...map3.entries()].map(([name,items2])=>({name,items:items2}))}function*search(arr,property,expected){let token=new Tokenizer(stringify2(property)).readScopeValue(),array2=toArray(arr),matcher2=expectedMatcher.call(this,expected);for(let index=0;index<array2.length;index++){let value=yield evalToken(token,this.context.spawn(array2[index]));if(matcher2(value))return[index,array2[index]]}}function*search_exp(arr,itemName,exp){let predicate=new Value(stringify2(exp),this.liquid),array2=toArray(arr);for(let index=0;index<array2.length;index++){this.context.push({[itemName]:array2[index]});let value=yield predicate.value(this.context);if(this.context.pop(),value)return[index,array2[index]]}}function*has(arr,property,expected){return!!(yield*search.call(this,arr,property,expected))}function*has_exp(arr,itemName,exp){return!!(yield*search_exp.call(this,arr,itemName,exp))}function*find_index(arr,property,expected){let result=yield*search.call(this,arr,property,expected);return result?result[0]:void 0}function*find_index_exp(arr,itemName,exp){let result=yield*search_exp.call(this,arr,itemName,exp);return result?result[0]:void 0}function*find(arr,property,expected){let result=yield*search.call(this,arr,property,expected);return result?result[1]:void 0}function*find_exp(arr,itemName,exp){let result=yield*search_exp.call(this,arr,itemName,exp);return result?result[1]:void 0}function uniq(arr){return arr=toArray(arr),this.context.memoryLimit.use(arr.length),[...new Set(arr)]}function sample(v2,count2=1){if(v2=toValue(v2),isNil(v2))return[];isArray(v2)||(v2=stringify2(v2)),this.context.memoryLimit.use(count2);let shuffled=[...v2].sort(()=>Math.random()-.5);return count2===1?shuffled[0]:shuffled.slice(0,count2)}var arrayFilters=Object.freeze({__proto__:null,join,last:last$1,first,reverse,sort,sort_natural,size,map,sum:sum2,compact,concat,push,unshift,pop,shift,slice,where,reject,where_exp,reject_exp,group_by,group_by_exp,has,has_exp,find_index,find_index_exp,find,find_exp,uniq,sample});function date(v2,format3,timezoneOffset){var _a4,_b,_c;let size2=((_a4=v2?.length)!==null&&_a4!==void 0?_a4:0)+((_b=format3?.length)!==null&&_b!==void 0?_b:0)+((_c=timezoneOffset?.length)!==null&&_c!==void 0?_c:0);this.context.memoryLimit.use(size2);let date6=parseDate(v2,this.context.opts,timezoneOffset);return date6?(format3=toValue(format3),format3=isNil(format3)?this.context.opts.dateFormat:stringify2(format3),strftime(date6,format3)):v2}function date_to_xmlschema(v2){return date.call(this,v2,"%Y-%m-%dT%H:%M:%S%:z")}function date_to_rfc822(v2){return date.call(this,v2,"%a, %d %b %Y %H:%M:%S %z")}function date_to_string(v2,type,style){return stringify_date.call(this,v2,"%b",type,style)}function date_to_long_string(v2,type,style){return stringify_date.call(this,v2,"%B",type,style)}function stringify_date(v2,month_type,type,style){let date6=parseDate(v2,this.context.opts);if(!date6)return v2;if(type==="ordinal"){let d=date6.getDate();return style==="US"?strftime(date6,`${month_type} ${d}%q, %Y`):strftime(date6,`${d}%q ${month_type} %Y`)}return strftime(date6,`%d ${month_type} %Y`)}function parseDate(v2,opts,timezoneOffset){let date6,defaultTimezoneOffset=timezoneOffset??opts.timezoneOffset,locale=opts.locale;return v2=toValue(v2),v2==="now"||v2==="today"?date6=new LiquidDate(Date.now(),locale,defaultTimezoneOffset):isNumber(v2)?date6=new LiquidDate(v2*1e3,locale,defaultTimezoneOffset):isString(v2)?/^\d+$/.test(v2)?date6=new LiquidDate(+v2*1e3,locale,defaultTimezoneOffset):opts.preserveTimezones&&timezoneOffset===void 0?date6=LiquidDate.createDateFixedToTimezone(v2,locale):date6=new LiquidDate(v2,locale,defaultTimezoneOffset):date6=new LiquidDate(v2,locale,defaultTimezoneOffset),date6.valid()?date6:void 0}var dateFilters=Object.freeze({__proto__:null,date,date_to_xmlschema,date_to_rfc822,date_to_string,date_to_long_string}),rCJKWord=/[\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF\u3040-\u309F\u30A0-\u30FF\uAC00-\uD7AF]/gu,rNonCJKWord=/[^\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF\u3040-\u309F\u30A0-\u30FF\uAC00-\uD7AF\s]+/gu;function append(v2,arg){assert(arguments.length===2,"append expect 2 arguments");let lhs=stringify2(v2),rhs=stringify2(arg);return this.context.memoryLimit.use(lhs.length+rhs.length),lhs+rhs}function prepend(v2,arg){assert(arguments.length===2,"prepend expect 2 arguments");let lhs=stringify2(v2),rhs=stringify2(arg);return this.context.memoryLimit.use(lhs.length+rhs.length),rhs+lhs}function lstrip(v2,chars){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),chars?(chars=escapeRegExp2(stringify2(chars)),str.replace(new RegExp(`^[${chars}]+`,"g"),"")):str.replace(/^\s+/,"")}function downcase(v2){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.toLowerCase()}function upcase(v2){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),stringify2(str).toUpperCase()}function remove(v2,arg){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.split(stringify2(arg)).join("")}function remove_first(v2,l){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.replace(stringify2(l),"")}function remove_last(v2,l){let str=stringify2(v2);this.context.memoryLimit.use(str.length);let pattern=stringify2(l),index=str.lastIndexOf(pattern);return index===-1?str:str.substring(0,index)+str.substring(index+pattern.length)}function rstrip(str,chars){return str=stringify2(str),this.context.memoryLimit.use(str.length),chars?(chars=escapeRegExp2(stringify2(chars)),str.replace(new RegExp(`[${chars}]+$`,"g"),"")):str.replace(/\s+$/,"")}function split(v2,arg){let str=stringify2(v2);this.context.memoryLimit.use(str.length);let arr=str.split(stringify2(arg));for(;arr.length&&arr[arr.length-1]==="";)arr.pop();return arr}function strip(v2,chars){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),chars?(chars=escapeRegExp2(stringify2(chars)),str.replace(new RegExp(`^[${chars}]+`,"g"),"").replace(new RegExp(`[${chars}]+$`,"g"),"")):str.trim()}function strip_newlines(v2){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.replace(/\r?\n/gm,"")}function capitalize(str){return str=stringify2(str),this.context.memoryLimit.use(str.length),str.charAt(0).toUpperCase()+str.slice(1).toLowerCase()}function replace(v2,pattern,replacement){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.split(stringify2(pattern)).join(replacement)}function replace_first(v2,arg1,arg2){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.replace(stringify2(arg1),arg2)}function replace_last(v2,arg1,arg2){let str=stringify2(v2);this.context.memoryLimit.use(str.length);let pattern=stringify2(arg1),index=str.lastIndexOf(pattern);if(index===-1)return str;let replacement=stringify2(arg2);return str.substring(0,index)+replacement+str.substring(index+pattern.length)}function truncate(v2,l=50,o="..."){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.length<=l?v2:str.substring(0,l-o.length)+o}function truncatewords(v2,words=15,o="..."){let str=stringify2(v2);this.context.memoryLimit.use(str.length);let arr=str.split(/\s+/);words<=0&&(words=1);let ret=arr.slice(0,words).join(" ");return arr.length>=words&&(ret+=o),ret}function normalize_whitespace(v2){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.replace(/\s+/g," ")}function number_of_words(input,mode){let str=stringify2(input);if(this.context.memoryLimit.use(str.length),input=str.trim(),!input)return 0;switch(mode){case"cjk":return(input.match(rCJKWord)||[]).length+(input.match(rNonCJKWord)||[]).length;case"auto":return rCJKWord.test(input)?input.match(rCJKWord).length+(input.match(rNonCJKWord)||[]).length:input.split(/\s+/).length;default:return input.split(/\s+/).length}}function array_to_sentence_string(array2,connector="and"){switch(this.context.memoryLimit.use(array2.length),array2.length){case 0:return"";case 1:return array2[0];case 2:return`${array2[0]} ${connector} ${array2[1]}`;default:return`${array2.slice(0,-1).join(", ")}, ${connector} ${array2[array2.length-1]}`}}var stringFilters=Object.freeze({__proto__:null,append,prepend,lstrip,downcase,upcase,remove,remove_first,remove_last,rstrip,split,strip,strip_newlines,capitalize,replace,replace_first,replace_last,truncate,truncatewords,normalize_whitespace,number_of_words,array_to_sentence_string});function base64Encode(str){return Buffer.from(str,"utf8").toString("base64")}function base64Decode(str){return Buffer.from(str,"base64").toString("utf8")}function base64_encode(value){let str=stringify2(value);return this.context.memoryLimit.use(str.length),base64Encode(str)}function base64_decode(value){let str=stringify2(value);return this.context.memoryLimit.use(str.length),base64Decode(str)}var base64Filters=Object.freeze({__proto__:null,base64_encode,base64_decode}),filters=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},htmlFilters),mathFilters),urlFilters),arrayFilters),dateFilters),stringFilters),base64Filters),misc),AssignTag=class extends Tag{constructor(token,remainTokens,liquid){super(token,remainTokens,liquid),this.identifier=this.tokenizer.readIdentifier(),this.key=this.identifier.content,this.tokenizer.assert(this.key,"expected variable name"),this.tokenizer.skipBlank(),this.tokenizer.assert(this.tokenizer.peek()==="=",'expected "="'),this.tokenizer.advance(),this.value=new Value(this.tokenizer.readFilteredValue(),this.liquid)}*render(ctx){ctx.bottom()[this.key]=yield this.value.value(ctx,this.liquid.options.lenientIf)}*arguments(){yield this.value}*localScope(){yield this.identifier}},MODIFIERS=["offset","limit","reversed"],ForTag=class extends Tag{constructor(token,remainTokens,liquid,parser){super(token,remainTokens,liquid);let variable=this.tokenizer.readIdentifier(),inStr=this.tokenizer.readIdentifier(),collection2=this.tokenizer.readValue();if(!variable.size()||inStr.content!=="in"||!collection2)throw new Error(`illegal tag: ${token.getText()}`);this.variable=variable.content,this.collection=collection2,this.hash=new Hash(this.tokenizer,liquid.options.keyValueSeparator),this.templates=[],this.elseTemplates=[];let p,stream=parser.parseStream(remainTokens).on("start",()=>p=this.templates).on("tag:else",tag=>{assertEmpty(tag.args),p=this.elseTemplates}).on("tag:endfor",tag=>{assertEmpty(tag.args),stream.stop()}).on("template",tpl=>p.push(tpl)).on("end",()=>{throw new Error(`tag ${token.getText()} not closed`)});stream.start()}*render(ctx,emitter){let r=this.liquid.renderer,collection2=toEnumerable(yield evalToken(this.collection,ctx));if(!collection2.length){yield r.renderTemplates(this.elseTemplates,ctx,emitter);return}let continueKey="continue-"+this.variable+"-"+this.collection.getText();ctx.push({continue:ctx.getRegister(continueKey)});let hash2=yield this.hash.render(ctx);ctx.pop(),collection2=(this.liquid.options.orderedFilterParameters?Object.keys(hash2).filter(x2=>MODIFIERS.includes(x2)):MODIFIERS.filter(x2=>hash2[x2]!==void 0)).reduce((collection3,modifier)=>modifier==="offset"?offset(collection3,hash2.offset):modifier==="limit"?limit(collection3,hash2.limit):reversed(collection3),collection2),ctx.setRegister(continueKey,(hash2.offset||0)+collection2.length);let scope={forloop:new ForloopDrop(collection2.length,this.collection.getText(),this.variable)};ctx.push(scope);for(let item of collection2){if(scope[this.variable]=item,ctx.continueCalled=ctx.breakCalled=!1,yield r.renderTemplates(this.templates,ctx,emitter),ctx.breakCalled)break;scope.forloop.next()}ctx.continueCalled=ctx.breakCalled=!1,ctx.pop()}*children(){let templates=this.templates.slice();return this.elseTemplates&&templates.push(...this.elseTemplates),templates}*arguments(){yield this.collection;for(let v2 of Object.values(this.hash.hash))isValueToken(v2)&&(yield v2)}blockScope(){return[this.variable,"forloop"]}};function reversed(arr){return[...arr].reverse()}function offset(arr,count2){return arr.slice(count2)}function limit(arr,count2){return arr.slice(0,count2)}var CaptureTag=class extends Tag{constructor(tagToken,remainTokens,liquid,parser){for(super(tagToken,remainTokens,liquid),this.templates=[],this.identifier=this.readVariable(),this.variable=this.identifier.content;remainTokens.length;){let token=remainTokens.shift();if(isTagToken(token)&&token.name==="endcapture")return;this.templates.push(parser.parseToken(token,remainTokens))}throw new Error(`tag ${tagToken.getText()} not closed`)}readVariable(){let ident=this.tokenizer.readIdentifier();if(ident.content||(ident=this.tokenizer.readQuoted(),ident))return ident;throw this.tokenizer.error("invalid capture name")}*render(ctx){let html=yield this.liquid.renderer.renderTemplates(this.templates,ctx);ctx.bottom()[this.variable]=html}*children(){return this.templates}*localScope(){yield this.identifier}},CaseTag=class extends Tag{constructor(tagToken,remainTokens,liquid,parser){super(tagToken,remainTokens,liquid),this.branches=[],this.elseTemplates=[],this.value=new Value(this.tokenizer.readFilteredValue(),this.liquid),this.elseTemplates=[];let p=[],elseCount=0,stream=parser.parseStream(remainTokens).on("tag:when",token=>{if(elseCount>0)return;p=[];let values=[];for(;!token.tokenizer.end();)values.push(token.tokenizer.readValueOrThrow()),token.tokenizer.skipBlank(),token.tokenizer.peek()===","?token.tokenizer.readTo(","):token.tokenizer.readTo("or");this.branches.push({values,templates:p})}).on("tag:else",()=>{elseCount++,p=this.elseTemplates}).on("tag:endcase",()=>stream.stop()).on("template",tpl=>{(p!==this.elseTemplates||elseCount===1)&&p.push(tpl)}).on("end",()=>{throw new Error(`tag ${tagToken.getText()} not closed`)});stream.start()}*render(ctx,emitter){let r=this.liquid.renderer,target=toValue(yield this.value.value(ctx,ctx.opts.lenientIf)),branchHit=!1;for(let branch of this.branches)for(let valueToken of branch.values){let value=yield evalToken(valueToken,ctx,ctx.opts.lenientIf);if(equals(target,value)){yield r.renderTemplates(branch.templates,ctx,emitter),branchHit=!0;break}}branchHit||(yield r.renderTemplates(this.elseTemplates,ctx,emitter))}*arguments(){yield this.value,yield*this.branches.flatMap(b=>b.values)}*children(){let templates=this.branches.flatMap(b=>b.templates);return this.elseTemplates&&templates.push(...this.elseTemplates),templates}},CommentTag=class extends Tag{constructor(tagToken,remainTokens,liquid){for(super(tagToken,remainTokens,liquid);remainTokens.length;){let token=remainTokens.shift();if(isTagToken(token)&&token.name==="endcomment")return}throw new Error(`tag ${tagToken.getText()} not closed`)}render(){}},RenderTag=class extends Tag{constructor(token,remainTokens,liquid,parser){super(token,remainTokens,liquid);let tokenizer=this.tokenizer;for(this.file=parseFilePath(tokenizer,this.liquid,parser),this.currentFile=token.file;!tokenizer.end();){tokenizer.skipBlank();let begin=tokenizer.p,keyword=tokenizer.readIdentifier();if((keyword.content==="with"||keyword.content==="for")&&(tokenizer.skipBlank(),tokenizer.peek()!==":")){let value=tokenizer.readValue();if(value){let beforeAs=tokenizer.p,asStr=tokenizer.readIdentifier(),alias;asStr.content==="as"?alias=tokenizer.readIdentifier():tokenizer.p=beforeAs,this[keyword.content]={value,alias:alias&&alias.content},tokenizer.skipBlank(),tokenizer.peek()===","&&tokenizer.advance();continue}}tokenizer.p=begin;break}this.hash=new Hash(tokenizer,liquid.options.keyValueSeparator)}*render(ctx,emitter){let{liquid,hash:hash2}=this,filepath=yield renderFilePath(this.file,ctx,liquid);assert(filepath,()=>`illegal file path "${filepath}"`);let childCtx=ctx.spawn(),scope=childCtx.bottom();if(__assign(scope,yield hash2.render(ctx)),this.with){let{value,alias}=this.with;scope[alias||filepath]=yield evalToken(value,ctx)}if(this.for){let{value,alias}=this.for,collection2=toEnumerable(yield evalToken(value,ctx));scope.forloop=new ForloopDrop(collection2.length,value.getText(),alias);for(let item of collection2){scope[alias]=item;let templates=yield liquid._parsePartialFile(filepath,childCtx.sync,this.currentFile);yield liquid.renderer.renderTemplates(templates,childCtx,emitter),scope.forloop.next()}}else{let templates=yield liquid._parsePartialFile(filepath,childCtx.sync,this.currentFile);yield liquid.renderer.renderTemplates(templates,childCtx,emitter)}}*children(partials,sync){return partials&&isString(this.file)?yield this.liquid._parsePartialFile(this.file,sync,this.currentFile):[]}partialScope(){if(isString(this.file)){let names2=Object.keys(this.hash.hash);if(this.with){let{value,alias}=this.with;isString(alias)?names2.push([alias,value]):isString(this.file)&&names2.push([this.file,value])}if(this.for){let{value,alias}=this.for;isString(alias)?names2.push([alias,value]):isString(this.file)&&names2.push([this.file,value])}return{name:this.file,isolated:!0,scope:names2}}}*arguments(){for(let v2 of Object.values(this.hash.hash))isValueToken(v2)&&(yield v2);if(this.with){let{value}=this.with;isValueToken(value)&&(yield value)}if(this.for){let{value}=this.for;isValueToken(value)&&(yield value)}}};function parseFilePath(tokenizer,liquid,parser){if(liquid.options.dynamicPartials){let file2=tokenizer.readValue();if(tokenizer.assert(file2,"illegal file path"),file2.getText()==="none")return;if(isQuotedToken(file2)){let templates2=parser.parse(evalQuotedToken(file2));return optimize(templates2)}return file2}let tokens=[...tokenizer.readFileNameTemplate(liquid.options)],templates=optimize(parser.parseTokens(tokens));return templates==="none"?void 0:templates}function optimize(templates){return templates.length===1&&isHTMLToken(templates[0].token)?templates[0].token.getContent():templates}function*renderFilePath(file2,ctx,liquid){return typeof file2=="string"?file2:Array.isArray(file2)?liquid.renderer.renderTemplates(file2,ctx):yield evalToken(file2,ctx)}var IncludeTag=class extends Tag{constructor(token,remainTokens,liquid,parser){super(token,remainTokens,liquid);let{tokenizer}=token;this.file=parseFilePath(tokenizer,this.liquid,parser),this.currentFile=token.file;let begin=tokenizer.p;tokenizer.readIdentifier().content==="with"?(tokenizer.skipBlank(),tokenizer.peek()!==":"?this.withVar=tokenizer.readValue():tokenizer.p=begin):tokenizer.p=begin,this.hash=new Hash(tokenizer,liquid.options.jekyllInclude||liquid.options.keyValueSeparator)}*render(ctx,emitter){let{liquid,hash:hash2,withVar}=this,{renderer}=liquid,filepath=yield renderFilePath(this.file,ctx,liquid);assert(filepath,()=>`illegal file path "${filepath}"`);let saved=ctx.saveRegister("blocks","blockMode");ctx.setRegister("blocks",{}),ctx.setRegister("blockMode",BlockMode.OUTPUT);let scope=yield hash2.render(ctx);withVar&&(scope[filepath]=yield evalToken(withVar,ctx));let templates=yield liquid._parsePartialFile(filepath,ctx.sync,this.currentFile);ctx.push(ctx.opts.jekyllInclude?{include:scope}:scope),yield renderer.renderTemplates(templates,ctx,emitter),ctx.pop(),ctx.restoreRegister(saved)}*children(partials,sync){return partials&&isString(this.file)?yield this.liquid._parsePartialFile(this.file,sync,this.currentFile):[]}partialScope(){if(isString(this.file)){let names2;return this.liquid.options.jekyllInclude?names2=["include"]:(names2=Object.keys(this.hash.hash),this.withVar&&names2.push([this.file,this.withVar])),{name:this.file,isolated:!1,scope:names2}}}*arguments(){yield*Object.values(this.hash.hash).filter(isValueToken),isValueToken(this.file)&&(yield this.file),isValueToken(this.withVar)&&(yield this.withVar)}},DecrementTag=class extends Tag{constructor(token,remainTokens,liquid){super(token,remainTokens,liquid),this.identifier=this.tokenizer.readIdentifier(),this.variable=this.identifier.content}render(context,emitter){let scope=context.environments;isNumber(scope[this.variable])||(scope[this.variable]=0),emitter.write(stringify2(--scope[this.variable]))}*localScope(){yield this.identifier}},CycleTag=class extends Tag{constructor(token,remainTokens,liquid){super(token,remainTokens,liquid),this.candidates=[];let group=this.tokenizer.readValue();for(this.tokenizer.skipBlank(),group&&(this.tokenizer.peek()===":"?(this.group=group,this.tokenizer.advance()):this.candidates.push(group));!this.tokenizer.end();){let value=this.tokenizer.readValue();value&&this.candidates.push(value),this.tokenizer.readTo(",")}this.tokenizer.assert(this.candidates.length,()=>`empty candidates: "${token.getText()}"`)}*render(ctx,emitter){let fingerprint=`cycle:${yield evalToken(this.group,ctx)}:`+this.candidates.join(","),groups=ctx.getRegister("cycle"),idx=groups[fingerprint];idx===void 0&&(idx=groups[fingerprint]=0);let candidate=this.candidates[idx];return idx=(idx+1)%this.candidates.length,groups[fingerprint]=idx,yield evalToken(candidate,ctx)}*arguments(){yield*this.candidates,this.group&&(yield this.group)}},IfTag=class extends Tag{constructor(tagToken,remainTokens,liquid,parser){super(tagToken,remainTokens,liquid),this.branches=[];let p=[];parser.parseStream(remainTokens).on("start",()=>this.branches.push({value:new Value(tagToken.tokenizer.readFilteredValue(),this.liquid),templates:p=[]})).on("tag:elsif",token=>{assert(!this.elseTemplates,"unexpected elsif after else"),this.branches.push({value:new Value(token.tokenizer.readFilteredValue(),this.liquid),templates:p=[]})}).on("tag:else",tag=>{assertEmpty(tag.args),assert(!this.elseTemplates,"duplicated else"),p=this.elseTemplates=[]}).on("tag:endif",function(tag){assertEmpty(tag.args),this.stop()}).on("template",tpl=>p.push(tpl)).on("end",()=>{throw new Error(`tag ${tagToken.getText()} not closed`)}).start()}*render(ctx,emitter){let r=this.liquid.renderer;for(let{value,templates}of this.branches){let v2=yield value.value(ctx,ctx.opts.lenientIf);if(isTruthy(v2,ctx)){yield r.renderTemplates(templates,ctx,emitter);return}}yield r.renderTemplates(this.elseTemplates||[],ctx,emitter)}*children(){let templates=this.branches.flatMap(b=>b.templates);return this.elseTemplates&&templates.push(...this.elseTemplates),templates}arguments(){return this.branches.map(b=>b.value)}},IncrementTag=class extends Tag{constructor(token,remainTokens,liquid){super(token,remainTokens,liquid),this.identifier=this.tokenizer.readIdentifier(),this.variable=this.identifier.content}render(context,emitter){let scope=context.environments;isNumber(scope[this.variable])||(scope[this.variable]=0);let val=scope[this.variable];scope[this.variable]++,emitter.write(stringify2(val))}*localScope(){yield this.identifier}},LayoutTag=class extends Tag{constructor(token,remainTokens,liquid,parser){super(token,remainTokens,liquid),this.file=parseFilePath(this.tokenizer,this.liquid,parser),this.currentFile=token.file,this.args=new Hash(this.tokenizer,liquid.options.keyValueSeparator),this.templates=parser.parseTokens(remainTokens)}*render(ctx,emitter){let{liquid,args,file:file2}=this,{renderer}=liquid;if(file2===void 0){ctx.setRegister("blockMode",BlockMode.OUTPUT),yield renderer.renderTemplates(this.templates,ctx,emitter);return}let filepath=yield renderFilePath(this.file,ctx,liquid);assert(filepath,()=>`illegal file path "${filepath}"`);let templates=yield liquid._parseLayoutFile(filepath,ctx.sync,this.currentFile);ctx.setRegister("blockMode",BlockMode.STORE);let html=yield renderer.renderTemplates(this.templates,ctx),blocks=ctx.getRegister("blocks");blocks[""]===void 0&&(blocks[""]=(parent,emitter2)=>emitter2.write(html)),ctx.setRegister("blockMode",BlockMode.OUTPUT),ctx.push(yield args.render(ctx)),yield renderer.renderTemplates(templates,ctx,emitter),ctx.pop()}*children(partials){let templates=this.templates.slice();return partials&&isString(this.file)&&templates.push(...yield this.liquid._parsePartialFile(this.file,!0,this.currentFile)),templates}*arguments(){for(let v2 of Object.values(this.args.hash))isValueToken(v2)&&(yield v2);isValueToken(this.file)&&(yield this.file)}partialScope(){if(isString(this.file))return{name:this.file,isolated:!1,scope:Object.keys(this.args.hash)}}},BlockTag=class extends Tag{constructor(token,remainTokens,liquid,parser){super(token,remainTokens,liquid),this.templates=[];let match2=/\w+/.exec(token.args);for(this.block=match2?match2[0]:"";remainTokens.length;){let token2=remainTokens.shift();if(isTagToken(token2)&&token2.name==="endblock")return;let template=parser.parseToken(token2,remainTokens);this.templates.push(template)}throw new Error(`tag ${token.getText()} not closed`)}*render(ctx,emitter){let blockRender=this.getBlockRender(ctx);ctx.getRegister("blockMode")===BlockMode.STORE?ctx.getRegister("blocks")[this.block]=blockRender:yield blockRender(new BlockDrop,emitter)}getBlockRender(ctx){let{liquid,templates}=this,renderChild=ctx.getRegister("blocks")[this.block],renderCurrent=function*(superBlock,emitter){ctx.push({block:superBlock}),yield liquid.renderer.renderTemplates(templates,ctx,emitter),ctx.pop()};return renderChild?(superBlock,emitter)=>renderChild(new BlockDrop(emitter2=>renderCurrent(superBlock,emitter2)),emitter):renderCurrent}*children(){return this.templates}blockScope(){return["block"]}},RawTag=class extends Tag{constructor(tagToken,remainTokens,liquid){for(super(tagToken,remainTokens,liquid),this.tokens=[];remainTokens.length;){let token=remainTokens.shift();if(isTagToken(token)&&token.name==="endraw")return;this.tokens.push(token)}throw new Error(`tag ${tagToken.getText()} not closed`)}render(){return this.tokens.map(token=>token.getText()).join("")}},TablerowloopDrop=class extends ForloopDrop{constructor(length,cols,collection2,variable){super(length,collection2,variable),this.length=length,this.cols=cols}row(){return Math.floor(this.i/this.cols)+1}col0(){return this.i%this.cols}col(){return this.col0()+1}col_first(){return this.col0()===0}col_last(){return this.col()===this.cols}},TablerowTag=class extends Tag{constructor(tagToken,remainTokens,liquid,parser){super(tagToken,remainTokens,liquid);let variable=this.tokenizer.readIdentifier();this.tokenizer.skipBlank();let predicate=this.tokenizer.readIdentifier(),collectionToken=this.tokenizer.readValue();if(predicate.content!=="in"||!collectionToken)throw new Error(`illegal tag: ${tagToken.getText()}`);this.variable=variable.content,this.collection=collectionToken,this.args=new Hash(this.tokenizer,liquid.options.keyValueSeparator),this.templates=[];let p,stream=parser.parseStream(remainTokens).on("start",()=>p=this.templates).on("tag:endtablerow",()=>stream.stop()).on("template",tpl=>p.push(tpl)).on("end",()=>{throw new Error(`tag ${tagToken.getText()} not closed`)});stream.start()}*render(ctx,emitter){let collection2=toEnumerable(yield evalToken(this.collection,ctx)),args=yield this.args.render(ctx),offset2=args.offset||0,limit2=args.limit===void 0?collection2.length:args.limit;collection2=collection2.slice(offset2,offset2+limit2);let cols=args.cols||collection2.length,r=this.liquid.renderer,tablerowloop=new TablerowloopDrop(collection2.length,cols,this.collection.getText(),this.variable),scope={tablerowloop};ctx.push(scope);for(let idx=0;idx<collection2.length;idx++,tablerowloop.next())scope[this.variable]=collection2[idx],tablerowloop.col0()===0&&(tablerowloop.row()!==1&&emitter.write("</tr>"),emitter.write(`<tr class="row${tablerowloop.row()}">`)),emitter.write(`<td class="col${tablerowloop.col()}">`),yield r.renderTemplates(this.templates,ctx,emitter),emitter.write("</td>");collection2.length&&emitter.write("</tr>"),ctx.pop()}*children(){return this.templates}*arguments(){yield this.collection;for(let v2 of Object.values(this.args.hash))isValueToken(v2)&&(yield v2)}blockScope(){return[this.variable,"tablerowloop"]}},UnlessTag=class extends Tag{constructor(tagToken,remainTokens,liquid,parser){super(tagToken,remainTokens,liquid),this.branches=[],this.elseTemplates=[];let p=[],elseCount=0;parser.parseStream(remainTokens).on("start",()=>this.branches.push({value:new Value(tagToken.tokenizer.readFilteredValue(),this.liquid),test:isFalsy,templates:p=[]})).on("tag:elsif",token=>{if(elseCount>0){p=[];return}this.branches.push({value:new Value(token.tokenizer.readFilteredValue(),this.liquid),test:isTruthy,templates:p=[]})}).on("tag:else",()=>{elseCount++,p=this.elseTemplates}).on("tag:endunless",function(){this.stop()}).on("template",tpl=>{(p!==this.elseTemplates||elseCount===1)&&p.push(tpl)}).on("end",()=>{throw new Error(`tag ${tagToken.getText()} not closed`)}).start()}*render(ctx,emitter){let r=this.liquid.renderer;for(let{value,test,templates}of this.branches){let v2=yield value.value(ctx,ctx.opts.lenientIf);if(test(v2,ctx)){yield r.renderTemplates(templates,ctx,emitter);return}}yield r.renderTemplates(this.elseTemplates,ctx,emitter)}*children(){let children=this.branches.flatMap(b=>b.templates);return this.elseTemplates&&children.push(...this.elseTemplates),children}arguments(){return this.branches.map(b=>b.value)}},BreakTag=class extends Tag{render(ctx,_emitter){ctx.breakCalled=!0}},ContinueTag=class extends Tag{render(ctx,_emitter){ctx.continueCalled=!0}},EchoTag=class extends Tag{constructor(token,remainTokens,liquid){super(token,remainTokens,liquid),this.tokenizer.skipBlank(),this.tokenizer.end()||(this.value=new Value(this.tokenizer.readFilteredValue(),this.liquid))}*render(ctx,emitter){if(!this.value)return;let val=yield this.value.value(ctx,!1);emitter.write(val)}*arguments(){this.value&&(yield this.value)}},LiquidTag=class extends Tag{constructor(token,remainTokens,liquid,parser){super(token,remainTokens,liquid);let tokens=this.tokenizer.readLiquidTagTokens(this.liquid.options);this.templates=parser.parseTokens(tokens)}*render(ctx,emitter){yield this.liquid.renderer.renderTemplates(this.templates,ctx,emitter)}*children(){return this.templates}},InlineCommentTag=class extends Tag{constructor(tagToken,remainTokens,liquid){if(super(tagToken,remainTokens,liquid),tagToken.args.search(/\n\s*[^#\s]/g)!==-1)throw new Error("every line of an inline comment must start with a '#' character")}render(){}},tags={assign:AssignTag,for:ForTag,capture:CaptureTag,case:CaseTag,comment:CommentTag,include:IncludeTag,render:RenderTag,decrement:DecrementTag,increment:IncrementTag,cycle:CycleTag,if:IfTag,layout:LayoutTag,block:BlockTag,raw:RawTag,tablerow:TablerowTag,unless:UnlessTag,break:BreakTag,continue:ContinueTag,echo:EchoTag,liquid:LiquidTag,"#":InlineCommentTag},Liquid=class _Liquid{constructor(opts={}){this.renderer=new Render,this.filters={},this.tags={},this.options=normalize(opts),this.parser=new Parser(this),forOwn(tags,(conf,name)=>this.registerTag(name,conf)),forOwn(filters,(handler,name)=>this.registerFilter(name,handler))}parse(html,filepath){return new Parser(this).parse(html,filepath)}_render(tpl,scope,renderOptions){let ctx=scope instanceof Context?scope:new Context(scope,this.options,renderOptions);return this.renderer.renderTemplates(tpl,ctx)}render(tpl,scope,renderOptions){return __awaiter(this,void 0,void 0,function*(){return toPromise(this._render(tpl,scope,Object.assign(Object.assign({},renderOptions),{sync:!1})))})}renderSync(tpl,scope,renderOptions){return toValueSync(this._render(tpl,scope,Object.assign(Object.assign({},renderOptions),{sync:!0})))}renderToNodeStream(tpl,scope,renderOptions={}){let ctx=new Context(scope,this.options,renderOptions);return this.renderer.renderTemplatesToNodeStream(tpl,ctx)}_parseAndRender(html,scope,renderOptions){let tpl=this.parse(html);return this._render(tpl,scope,renderOptions)}parseAndRender(html,scope,renderOptions){return __awaiter(this,void 0,void 0,function*(){return toPromise(this._parseAndRender(html,scope,Object.assign(Object.assign({},renderOptions),{sync:!1})))})}parseAndRenderSync(html,scope,renderOptions){return toValueSync(this._parseAndRender(html,scope,Object.assign(Object.assign({},renderOptions),{sync:!0})))}_parsePartialFile(file2,sync,currentFile){return new Parser(this).parseFile(file2,sync,LookupType.Partials,currentFile)}_parseLayoutFile(file2,sync,currentFile){return new Parser(this).parseFile(file2,sync,LookupType.Layouts,currentFile)}_parseFile(file2,sync,lookupType,currentFile){return new Parser(this).parseFile(file2,sync,lookupType,currentFile)}parseFile(file2,lookupType){return __awaiter(this,void 0,void 0,function*(){return toPromise(new Parser(this).parseFile(file2,!1,lookupType))})}parseFileSync(file2,lookupType){return toValueSync(new Parser(this).parseFile(file2,!0,lookupType))}*_renderFile(file2,ctx,renderFileOptions){let templates=yield this._parseFile(file2,renderFileOptions.sync,renderFileOptions.lookupType);return yield this._render(templates,ctx,renderFileOptions)}renderFile(file2,ctx,renderFileOptions){return __awaiter(this,void 0,void 0,function*(){return toPromise(this._renderFile(file2,ctx,Object.assign(Object.assign({},renderFileOptions),{sync:!1})))})}renderFileSync(file2,ctx,renderFileOptions){return toValueSync(this._renderFile(file2,ctx,Object.assign(Object.assign({},renderFileOptions),{sync:!0})))}renderFileToNodeStream(file2,scope,renderOptions){return __awaiter(this,void 0,void 0,function*(){let templates=yield this.parseFile(file2);return this.renderToNodeStream(templates,scope,renderOptions)})}_evalValue(str,scope){let value=new Value(str,this),ctx=scope instanceof Context?scope:new Context(scope,this.options);return value.value(ctx)}evalValue(str,scope){return __awaiter(this,void 0,void 0,function*(){return toPromise(this._evalValue(str,scope))})}evalValueSync(str,scope){return toValueSync(this._evalValue(str,scope))}registerFilter(name,filter3){this.filters[name]=filter3}registerTag(name,tag){this.tags[name]=isFunction(tag)?tag:createTagClass(tag)}plugin(plugin){return plugin.call(this,_Liquid)}express(){let self=this,firstCall=!0;return function(filePath,ctx,callback){if(firstCall){firstCall=!1;let dirs=normalizeDirectoryList(this.root);self.options.root.unshift(...dirs),self.options.layouts.unshift(...dirs),self.options.partials.unshift(...dirs)}self.renderFile(filePath,ctx).then(html=>callback(null,html),callback)}}analyze(template,options={}){return __awaiter(this,void 0,void 0,function*(){return analyze(template,options)})}analyzeSync(template,options={}){return analyzeSync(template,options)}parseAndAnalyze(html,filename,options={}){return __awaiter(this,void 0,void 0,function*(){return analyze(this.parse(html,filename),options)})}parseAndAnalyzeSync(html,filename,options={}){return analyzeSync(this.parse(html,filename),options)}variables(template,options={}){return __awaiter(this,void 0,void 0,function*(){let analysis=yield analyze(isString(template)?this.parse(template):template,options);return Object.keys(analysis.variables)})}variablesSync(template,options={}){let analysis=analyzeSync(isString(template)?this.parse(template):template,options);return Object.keys(analysis.variables)}fullVariables(template,options={}){return __awaiter(this,void 0,void 0,function*(){let analysis=yield analyze(isString(template)?this.parse(template):template,options);return Array.from(new Set(Object.values(analysis.variables).flatMap(a=>a.map(v2=>String(v2)))))})}fullVariablesSync(template,options={}){let analysis=analyzeSync(isString(template)?this.parse(template):template,options);return Array.from(new Set(Object.values(analysis.variables).flatMap(a=>a.map(v2=>String(v2)))))}variableSegments(template,options={}){return __awaiter(this,void 0,void 0,function*(){let analysis=yield analyze(isString(template)?this.parse(template):template,options);return Array.from(strictUniq(Object.values(analysis.variables).flatMap(a=>a.map(v2=>v2.toArray()))))})}variableSegmentsSync(template,options={}){let analysis=analyzeSync(isString(template)?this.parse(template):template,options);return Array.from(strictUniq(Object.values(analysis.variables).flatMap(a=>a.map(v2=>v2.toArray()))))}globalVariables(template,options={}){return __awaiter(this,void 0,void 0,function*(){let analysis=yield analyze(isString(template)?this.parse(template):template,options);return Object.keys(analysis.globals)})}globalVariablesSync(template,options={}){let analysis=analyzeSync(isString(template)?this.parse(template):template,options);return Object.keys(analysis.globals)}globalFullVariables(template,options={}){return __awaiter(this,void 0,void 0,function*(){let analysis=yield analyze(isString(template)?this.parse(template):template,options);return Array.from(new Set(Object.values(analysis.globals).flatMap(a=>a.map(v2=>String(v2)))))})}globalFullVariablesSync(template,options={}){let analysis=analyzeSync(isString(template)?this.parse(template):template,options);return Array.from(new Set(Object.values(analysis.globals).flatMap(a=>a.map(v2=>String(v2)))))}globalVariableSegments(template,options={}){return __awaiter(this,void 0,void 0,function*(){let analysis=yield analyze(isString(template)?this.parse(template):template,options);return Array.from(strictUniq(Object.values(analysis.globals).flatMap(a=>a.map(v2=>v2.toArray()))))})}globalVariableSegmentsSync(template,options={}){let analysis=analyzeSync(isString(template)?this.parse(template):template,options);return Array.from(strictUniq(Object.values(analysis.globals).flatMap(a=>a.map(v2=>v2.toArray()))))}};import{NotFoundError as NotFoundError3,PluginError as PluginError5}from"@sous-io/plugin-api";var DEFAULT_PURPOSE="template",CONFIG_EXPRESSION_PURPOSE="config-expression";function tagAllowed(tag,purpose){return tag.purposes?tag.purposes.includes(purpose):purpose!==CONFIG_EXPRESSION_PURPOSE}function filterAllowed(filter3,purpose){return filter3.purposes?filter3.purposes.includes(purpose):!0}function createLiquidEngines(deps){return{create:(options={})=>buildEngine(deps,options),available(purpose=DEFAULT_PURPOSE){return{tags:deps.entities.list("liquid-tag").filter(tag=>tagAllowed(tag,purpose)).map(tag=>tag.id),filters:deps.entities.list("liquid-filter").filter(filter3=>filterAllowed(filter3,purpose)).map(filter3=>filter3.id)}}}}function buildEngine(deps,options){let purpose=options.purpose??DEFAULT_PURPOSE,root=rootOf(options.root,deps.project),liquidOptions={extname:"",strictVariables:!1,strictFilters:!1,...options.liquid,...root===void 0?{}:{root},...options.fs===void 0?{}:{fs:options.fs}},engine=new Liquid(liquidOptions),ctx=Object.freeze({project:deps.project,env:deps.env,services:deps.services,entities:deps.entities,purpose,secretNames:new Set(options.secretNames??declaredSecrets(deps.services)),data:Object.freeze({...options.data})}),filters2=pick(deps.entities.describe("liquid-filter"),options.only?.filters,entry=>filterAllowed(entry,purpose),"Liquid filter");for(let record2 of filters2)engine.registerFilter(record2.id,make(record2,"filter",()=>record2.entry.filter(ctx)));let tags2=pick(deps.entities.describe("liquid-tag"),options.only?.tags,entry=>tagAllowed(entry,purpose),"Liquid tag");for(let record2 of tags2)engine.registerTag(record2.id,make(record2,"tag",()=>record2.entry.tag(ctx)));return engine}function rootOf(root,project){return root!==void 0?typeof root=="string"?root:[...root]:project?[project.root]:void 0}function declaredSecrets(services){return services.has("variables.secrets")?services.get("variables.secrets").declared():[]}function pick(records,only,allowed,thing){return only===void 0?records.filter(record2=>allowed(record2.entry)):only.map(id=>{let record2=records.find(candidate=>candidate.id===id);if(!record2)throw new NotFoundError3(thing,id);return record2})}function make(record2,what,factory2){try{return factory2()}catch(error51){throw new PluginError5(record2.plugin,`The Liquid ${what} "${record2.id}" from ${record2.plugin} could not be made.`,{cause:error51,details:[error51 instanceof Error?error51.message:String(error51)]})}}import{jsonSchema as jsonSchema8}from"@sous-io/plugin-api";var PURPOSES={type:"array",items:{type:"string"}};function extensionSchema(factory2){let base=jsonSchema8({type:"object",properties:{id:{type:"string"},description:{type:"string"},purposes:PURPOSES,[factory2]:{}},required:["id",factory2]});return{"~standard":{...base["~standard"],validate(value){let result=base["~standard"].validate(value);return result instanceof Promise||result.issues?result:typeof result.value[factory2]!="function"?{issues:[{message:"Expected a function.",path:[factory2]}]}:result}}}}var liquidTagSchema=extensionSchema("tag"),liquidFilterSchema=extensionSchema("filter");var package_default7={name:"@sous-io/plugin-liquid",version:"1.0.11",description:"A configured LiquidJS engine, and the Liquid tags and filters plugins add.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-host":"workspace:*",liquidjs:"^10.25.0"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME6="@sous-io/plugin-liquid",liquidPlugin=definePlugin7({name:PLUGIN_NAME6,version:package_default7.version,description:"A configured LiquidJS engine, and the Liquid tags and filters plugins add.",dependsOn:{"@sous-io/plugin-host":`^${package_default7.version}`},register(sous){sous.entities.define("liquid-tag",liquidTagSchema,{description:"A Liquid tag, as written in {% name %}."}),sous.entities.define("liquid-filter",liquidFilterSchema,{description:"A Liquid filter, as written after |. Config expressions see it too."}),sous.services.add("liquid.engine",(_config,ctx)=>createLiquidEngines(ctx),{lifetime:"factory"})}});import{definePlugin as definePlugin8,SousError as SousError14}from"@sous-io/plugin-api";var import_yaml2=__toESM(require_dist(),1);init_main();import fs14 from"node:fs";import fsPromises from"node:fs/promises";import path20 from"node:path";import{ConfigError as ConfigError18,NotFoundError as NotFoundError4}from"@sous-io/plugin-api";init_external();init_external();var import_semver2=__toESM(require_semver2(),1);import{ConfigError as ConfigError17}from"@sous-io/plugin-api";var KEBAB_NAME_PATTERN=/^[a-z][a-z0-9-]*$/;var REF_KEY_PATTERN=/^[a-z][a-z0-9-]*(\/[a-z][a-z0-9-]*)?$/,RECIPE_KEY_PATTERN=/^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/,REPO_IDENTITY_PATTERN=/^[^\s/]+(\/[^\s/]+)+$/,CONTENT_HASH_PATTERN=/^sha256-[0-9a-f]{64}$/,ENV_VAR_NAME_PATTERN=/^[A-Z][A-Z0-9_]*$/,VARIABLE_NAME_PATTERN2=/^[a-z][a-zA-Z0-9]*$/,ISO_TIMESTAMP_PATTERN=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?(Z|[+-]\d{2}:\d{2})$/;var SUPPORTED_FORMAT_VERSION=1,formatVersionSchema=external_exports.literal(SUPPORTED_FORMAT_VERSION,{message:`must be ${SUPPORTED_FORMAT_VERSION}; this version of sous understands no other on-disk format version`}),REPO_MANIFEST_BASENAME="sous.repo",RECIPE_MANIFEST_BASENAME="sous.recipe",INDEX_FILENAME="sous.index.json",LOCKFILE_FILENAME="sous.lock.json",STORE_ENTRY_FILENAME=".sous.entry.json";var LINKS_FILENAME="sous.links.json",MANIFEST_EXTENSIONS=[".yaml",".yml",".json",".jsonc"];function kebabName(label,example){return external_exports.string().regex(KEBAB_NAME_PATTERN,`a ${label} must be lowercase kebab-case: a letter, then letters, digits or hyphens (for example '${example}')`)}var repoNameSchema=kebabName("repo name","sous-recipes"),repoIdentitySchema=external_exports.string().regex(REPO_IDENTITY_PATTERN,"a repository identity must be its host followed by the path it lives at, all lowercase (for example 'github.com/sous-io/sous-recipes')"),namespaceNameSchema=kebabName("namespace name","tool-usage"),recipeNameSchema=kebabName("recipe name","task-files"),variableNameSchema=external_exports.string().regex(VARIABLE_NAME_PATTERN2,"a variable name must be camelCase: a lowercase letter, then letters or digits (for example 'apiBaseUrl')"),envVarNameSchema=external_exports.string().regex(ENV_VAR_NAME_PATTERN,"an environment variable name must be upper snake case: a capital letter, then capitals, digits or underscores (for example 'GITHUB_TOKEN')"),refKeySchema=external_exports.string().regex(REF_KEY_PATTERN,"a ref key must be a namespace ('workflow') or a namespace and recipe ('workflow/task-files'), with no repo qualifier and no version range"),recipeKeySchema=external_exports.string().regex(RECIPE_KEY_PATTERN,"a recipe key must be a namespace and recipe joined by a slash (for example 'workflow/task-files')"),DEPENDENCY_KINDS=["subscribes","depends"],dependencyKindSchema=external_exports.enum(DEPENDENCY_KINDS),semverVersionSchema=external_exports.string().refine(value=>import_semver2.default.valid(value)!==null,{message:"must be an exact semantic version, such as '1.4.0' or '2.0.0-beta.1'"}),semverRangeSchema=external_exports.string().refine(value=>import_semver2.default.validRange(value)!==null,{message:"must be a semantic version range, such as '^1.2.0', '~2.1', '>=1.0.0 <2.0.0' or '*'"}),contentHashSchema=external_exports.string().regex(CONTENT_HASH_PATTERN,"a content hash must be written as 'sha256-' followed by 64 lowercase hexadecimal characters"),isoTimestampSchema=external_exports.string().regex(ISO_TIMESTAMP_PATTERN,"must be an ISO 8601 timestamp with an offset, such as '2026-09-09T14:03:11.482Z'"),byteCountSchema=external_exports.number().int("must be a whole number of bytes").min(0,"must not be negative"),repoUrlSchema=external_exports.union([external_exports.url(),external_exports.string().min(1,"must not be empty").refine(value=>value.startsWith("/")||/^[A-Za-z]:[\\/]/.test(value),{message:"must be a repository URL, or an absolute path to one on this machine"})]),absolutePathSchema=external_exports.string().min(1,"must not be empty").refine(value=>value.startsWith("/")||/^[A-Za-z]:[\\/]/.test(value),{message:"must be an absolute path"});function relativePathSchema(label,allowGlobs=!1){return external_exports.string().superRefine((value,ctx)=>{let fail=message2=>{ctx.addIssue({code:"custom",message:`${label} ${message2}`})};if(value.length===0){fail("must not be empty");return}if(value.startsWith("/")||/^[A-Za-z]:[\\/]/.test(value)){fail("must be relative, not absolute");return}if(value.includes("\\")){fail("must use forward slashes, never backslashes");return}if(value.endsWith("/")){fail("must not end with a slash");return}if(!allowGlobs&&/[*?[\]{}]/.test(value)){fail("must be a plain path, with no glob characters");return}for(let segment of value.split("/")){if(segment.length===0){fail("must not contain an empty path segment");return}if(segment==="."||segment===".."){fail("must not contain a '.' or '..' segment");return}}})}function isPlainObject2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function stripExtensionKeys(value){if(!isPlainObject2(value))return value;let found=!1;for(let key of Object.keys(value))if(key.startsWith("x-")){found=!0;break}if(!found)return value;let copy={};for(let[key,entry]of Object.entries(value))key.startsWith("x-")||(copy[key]=entry);return copy}function extensibleObject(shape){return external_exports.preprocess(stripExtensionKeys,external_exports.strictObject(shape))}function forwardCompatibleObject(shape){return external_exports.looseObject(shape)}var submissionsSchema=extensibleObject({allowed:external_exports.boolean().default(!0),instead:external_exports.string().min(1,"must not be empty").optional()});function formatIssuePath(parts){let out="";for(let part of parts)typeof part=="number"?out+=`[${part}]`:out+=out.length>0?`.${String(part)}`:String(part);return out}function parseFormat(schema,value,sourceLabel2,formatLabel){let result=schema.safeParse(value);if(result.success)return result.data;throw new ConfigError17([`Invalid ${formatLabel} at ${sourceLabel2}:`,...describeIssues(result.error)].join(`
850
+ `," ",outputDelimiterLeft],htmlStopStringSet=new Set(htmlStopStrings);for(;this.p<this.N&&!htmlStopStringSet.has(this.peek());)yield this.match(outputDelimiterLeft)?this.readOutputToken(options):this.readHTMLToken(htmlStopStrings)}match(word){for(let i=0;i<word.length;i++)if(word[i]!==this.input[this.p+i])return!1;return!0}rmatch(pattern){for(let i=0;i<pattern.length;i++)if(pattern[pattern.length-1-i]!==this.input[this.p-1-i])return!1;return!0}peekType(n7=0){return this.p+n7>=this.N?0:TYPES[this.input.charCodeAt(this.p+n7)]}peek(n7=0){return this.p+n7>=this.N?"":this.input[this.p+n7]}skipBlank(){for(;this.peekType()&BLANK2;)++this.p}},ParseStream=class{constructor(tokens,parseToken){this.handlers={},this.stopRequested=!1,this.tokens=tokens,this.parseToken=parseToken}on(name,cb){return this.handlers[name]=cb,this}trigger(event,arg){let h=this.handlers[event];return h?(h.call(this,arg),!0):!1}start(){this.trigger("start");let token;for(;!this.stopRequested&&(token=this.tokens.shift());){if(this.trigger("token",token)||isTagToken(token)&&this.trigger(`tag:${token.name}`,token))continue;let template=this.parseToken(token,this.tokens);this.trigger("template",template)}return this.stopRequested||this.trigger("end"),this}stop(){return this.stopRequested=!0,this}},TemplateImpl=class{constructor(token){this.token=token}},Tag=class extends TemplateImpl{constructor(token,remainTokens,liquid){super(token),this.name=token.name,this.liquid=liquid,this.tokenizer=token.tokenizer}},Hash=class{constructor(input,jekyllStyle){this.hash={};let tokenizer=input instanceof Tokenizer?input:new Tokenizer(input,{});for(let hash2 of tokenizer.readHashes(jekyllStyle))this.hash[hash2.name.content]=hash2.value}*render(ctx){let hash2={};for(let key of Object.keys(this.hash))hash2[key]=this.hash[key]===void 0?!0:yield evalToken(this.hash[key],ctx);return hash2}};function createTagClass(options){return class extends Tag{constructor(token,tokens,liquid){super(token,tokens,liquid),isFunction(options.parse)&&options.parse.call(this,token,tokens)}*render(ctx,emitter){let hash2=yield new Hash(this.token.args,ctx.opts.keyValueSeparator).render(ctx);return yield options.render.call(this,ctx,emitter,hash2)}}}function isKeyValuePair(arr){return isArray(arr)}var Filter=class{constructor(token,options,liquid){this.token=token,this.name=token.name,this.handler=isFunction(options)?options:isFunction(options?.handler)?options.handler:identify,this.raw=!isFunction(options)&&!!options?.raw,this.args=token.args,this.liquid=liquid}*render(value,context){let argv2=[];for(let arg of this.args)isKeyValuePair(arg)?argv2.push([arg[0],yield evalToken(arg[1],context)]):argv2.push(yield evalToken(arg,context));return yield this.handler.apply({context,token:this.token,liquid:this.liquid},[value,...argv2])}},Value=class{constructor(input,liquid){this.filters=[];let token=typeof input=="string"?new Tokenizer(input,liquid.options.operators).readFilteredValue():input;this.initial=token.initial,this.filters=token.filters.map(token2=>new Filter(token2,this.getFilter(liquid,token2.name),liquid))}*value(ctx,lenient){lenient=lenient||ctx.opts.lenientIf&&this.filters.length>0&&this.filters[0].name==="default";let val=yield this.initial.evaluate(ctx,lenient);for(let filter3 of this.filters)val=yield filter3.render(val,ctx);return val}getFilter(liquid,name){let impl=liquid.filters[name];return assert(impl||!liquid.options.strictFilters,()=>`undefined filter: ${name}`),impl}},Output=class extends TemplateImpl{constructor(token,liquid){var _a4;super(token);let tokenizer=new Tokenizer(token.input,liquid.options.operators,token.file,token.contentRange);this.value=new Value(tokenizer.readFilteredValue(),liquid);let filters2=this.value.filters,outputEscape=liquid.options.outputEscape;if(!(!((_a4=filters2[filters2.length-1])===null||_a4===void 0)&&_a4.raw)&&outputEscape){let token2=new FilterToken(toString.call(outputEscape),[],"",0,0);filters2.push(new Filter(token2,outputEscape,liquid))}}*render(ctx,emitter){let val=yield this.value.value(ctx,!1);emitter.write(val)}*arguments(){yield this.value}},HTML=class extends TemplateImpl{constructor(token){super(token),this.str=token.getContent()}*render(ctx,emitter){emitter.write(this.str)}},Variable=class _Variable{constructor(segments,location){this.segments=segments,this.location=location}toString(){return segmentsString(this.segments,!0)}toArray(){function*_visit(...segments){for(let segment of segments)segment instanceof _Variable?yield Array.from(_visit(...segment.segments)):yield segment}return Array.from(_visit(...this.segments))}},VariableMap=class{constructor(){this.map=new Map}get(key){let k2=segmentsString([key.segments[0]]);return this.map.has(k2)||this.map.set(k2,[]),this.map.get(k2)}has(key){return this.map.has(segmentsString([key.segments[0]]))}push(variable){this.get(variable).push(variable)}asObject(){return Object.fromEntries(this.map)}},defaultStaticAnalysisOptions={partials:!0};function*_analyze(templates,partials,sync){let variables=new VariableMap,globals=new VariableMap,locals=new VariableMap,rootScope=new DummyScope(new Set),seen=new Set;function updateVariables(variable,scope){variables.push(variable);let aliased=scope.alias(variable);if(aliased!==void 0){let root=aliased.segments[0];isString(root)&&!rootScope.has(root)&&globals.push(aliased)}else{let root=variable.segments[0];isString(root)&&!scope.has(root)&&globals.push(variable)}for(let segment of variable.segments)segment instanceof Variable&&updateVariables(segment,scope)}function*visit2(template,scope){if(template.arguments)for(let arg of template.arguments())for(let variable of extractVariables(arg))updateVariables(variable,scope);if(template.localScope)for(let ident of template.localScope()){scope.add(ident.content),scope.deleteAlias(ident.content);let[row,col]=ident.getPosition();locals.push(new Variable([ident.content],{row,col,file:ident.file}))}if(template.children)if(template.partialScope){let partial2=template.partialScope();if(partial2===void 0){for(let child2 of yield template.children(partials,sync))yield visit2(child2,scope);return}if(seen.has(partial2.name))return;let partialScopeNames=new Set,partialScope=partial2.isolated?new DummyScope(partialScopeNames):scope.push(partialScopeNames);for(let name of partial2.scope)if(isString(name))partialScopeNames.add(name);else{let[alias,argument]=name;partialScopeNames.add(alias);let variables2=Array.from(extractVariables(argument));variables2.length&&partialScope.setAlias(alias,variables2[0].segments)}for(let child2 of yield template.children(partials,sync))yield visit2(child2,partialScope),seen.add(partial2.name);partialScope.pop()}else{template.blockScope&&scope.push(new Set(template.blockScope()));for(let child2 of yield template.children(partials,sync))yield visit2(child2,scope);template.blockScope&&scope.pop()}}for(let template of templates)yield visit2(template,rootScope);return{variables:variables.asObject(),globals:globals.asObject(),locals:locals.asObject()}}function analyze(template,options={}){let opts=Object.assign(Object.assign({},defaultStaticAnalysisOptions),options);return toPromise(_analyze(template,opts.partials,!1))}function analyzeSync(template,options={}){let opts=Object.assign(Object.assign({},defaultStaticAnalysisOptions),options);return toValueSync(_analyze(template,opts.partials,!0))}var DummyScope=class{constructor(globals){this.stack=[{names:globals,aliases:new Map}]}has(name){for(let scope of this.stack)if(scope.names.has(name))return!0;return!1}push(scope){return this.stack.push({names:scope,aliases:new Map}),this}pop(){var _a4;return(_a4=this.stack.pop())===null||_a4===void 0?void 0:_a4.names}add(name){this.stack[0].names.add(name)}alias(variable){let root=variable.segments[0];if(!isString(root))return;let alias=this.getAlias(root);if(alias!==void 0)return new Variable([...alias,...variable.segments.slice(1)],variable.location)}setAlias(from,to){this.stack[this.stack.length-1].aliases.set(from,to)}deleteAlias(name){this.stack[this.stack.length-1].aliases.delete(name)}getAlias(name){for(let scope of this.stack){if(scope.aliases.has(name))return scope.aliases.get(name);if(scope.names.has(name))return}}};function*extractVariables(value){isValueToken(value)?yield*extractValueTokenVariables(value):value instanceof Value&&(yield*extractFilteredValueVariables(value))}function*extractFilteredValueVariables(value){for(let token of value.initial.postfix)isValueToken(token)&&(yield*extractValueTokenVariables(token));for(let filter3 of value.filters)for(let arg of filter3.args)isKeyValuePair(arg)&&arg[1]?yield*extractValueTokenVariables(arg[1]):isValueToken(arg)&&(yield*extractValueTokenVariables(arg))}function*extractValueTokenVariables(token){isRangeToken(token)?(yield*extractValueTokenVariables(token.lhs),yield*extractValueTokenVariables(token.rhs)):isPropertyAccessToken(token)&&(yield extractPropertyAccessVariable(token))}function extractPropertyAccessVariable(token){let segments=[],file2=token.file,root=token.props[0];file2=file2||root.file,isQuotedToken(root)||isNumberToken(root)||isWordToken(root)?segments.push(root.content):isPropertyAccessToken(root)&&segments.push(...extractPropertyAccessVariable(root).segments);for(let prop of token.props.slice(1))file2=file2||prop.file,isQuotedToken(prop)||isNumberToken(prop)||isWordToken(prop)?segments.push(prop.content):isPropertyAccessToken(prop)&&segments.push(extractPropertyAccessVariable(prop));let[row,col]=token.getPosition();return new Variable(segments,{row,col,file:file2})}var RE_PROPERTY=/^[\u0080-\uFFFFa-zA-Z_][\u0080-\uFFFFa-zA-Z0-9_-]*$/;function segmentsString(segments,bracketedRoot=!1){let buf=[],root=segments[0];isString(root)&&(!bracketedRoot||root.match(RE_PROPERTY)?buf.push(`${root}`):buf.push(`['${root}']`));for(let segment of segments.slice(1))segment instanceof Variable?buf.push(`[${segmentsString(segment.segments)}]`):isString(segment)?segment.match(RE_PROPERTY)?buf.push(`.${segment}`):buf.push(`['${segment}']`):buf.push(`[${segment}]`);return buf.join("")}var LookupType;(function(LookupType2){LookupType2.Partials="partials",LookupType2.Layouts="layouts",LookupType2.Root="root"})(LookupType||(LookupType={}));var Loader=class{constructor(options){if(this.options=options,options.relativeReference){let sep3=options.fs.sep;assert(sep3,"`fs.sep` is required for relative reference");let rRelativePath=new RegExp(["."+sep3,".."+sep3,"./","../"].map(prefix=>escapeRegex(prefix)).join("|"));this.shouldLoadRelative=referencedFile=>rRelativePath.test(referencedFile)}else this.shouldLoadRelative=_referencedFile=>!1;this.contains=this.options.fs.contains||(()=>!0)}*lookup(file2,type,sync,currentFile){let{fs:fs68}=this.options,dirs=this.options[type];for(let filepath of this.candidates(file2,dirs,currentFile,type!==LookupType.Root))if(sync?fs68.existsSync(filepath):yield fs68.exists(filepath))return filepath;throw this.lookupError(file2,dirs)}*candidates(file2,dirs,currentFile,enforceRoot){let{fs:fs68,extname:extname3}=this.options,isAllowed=filepath=>{if(!enforceRoot)return!0;for(let dir of dirs)if(this.contains(dir,filepath))return!0;return!1};if(this.shouldLoadRelative(file2)&&currentFile){let referenced=fs68.resolve(this.dirname(currentFile),file2,extname3);isAllowed(referenced)&&(yield referenced)}for(let dir of dirs){let referenced=fs68.resolve(dir,file2,extname3);isAllowed(referenced)&&(yield referenced)}if(fs68.fallback!==void 0){let filepath=fs68.fallback(file2);filepath!==void 0&&isAllowed(filepath)&&(yield filepath)}}dirname(path103){let fs68=this.options.fs;return assert(fs68.dirname,"`fs.dirname` is required for relative reference"),fs68.dirname(path103)}lookupError(file2,roots){let err=new Error("ENOENT");return err.message=`ENOENT: Failed to lookup "${file2}" in "${roots}"`,err.code="ENOENT",err}},Parser=class{constructor(liquid){this.liquid=liquid,this.cache=this.liquid.options.cache,this.fs=this.liquid.options.fs,this.parseFile=this.cache?this._parseFileCached:this._parseFile,this.loader=new Loader(this.liquid.options),this.parseLimit=new Limiter("parse length",liquid.options.parseLimit)}parse(html,filepath){html=String(html),this.parseLimit.use(html.length);let tokens=new Tokenizer(html,this.liquid.options.operators,filepath).readTopLevelTokens(this.liquid.options);return this.parseTokens(tokens)}parseTokens(tokens){let token,templates=[],errors=[];for(;token=tokens.shift();)try{templates.push(this.parseToken(token,tokens))}catch(err){if(this.liquid.options.catchAllErrors)errors.push(err);else throw err}if(errors.length)throw new LiquidErrors(errors);return templates}parseToken(token,remainTokens){try{if(isTagToken(token)){let TagClass=this.liquid.tags[token.name];return assert(TagClass,`tag "${token.name}" not found`),new TagClass(token,remainTokens,this.liquid,this)}return isOutputToken(token)?new Output(token,this.liquid):new HTML(token)}catch(e){throw LiquidError.is(e)?e:new ParseError(e,token)}}parseStream(tokens){return new ParseStream(tokens,(token,tokens2)=>this.parseToken(token,tokens2))}*_parseFileCached(file2,sync,type=LookupType.Root,currentFile){let cache2=this.cache,key=this.loader.shouldLoadRelative(file2)?currentFile+","+file2:type+":"+file2,tpls=yield cache2.read(key);if(tpls)return tpls;let task=this._parseFile(file2,sync,type,currentFile),taskOrTpl=sync?yield task:toPromise(task);cache2.write(key,taskOrTpl);try{return yield taskOrTpl}catch(err){throw cache2.remove(key),err}}*_parseFile(file2,sync,type=LookupType.Root,currentFile){let filepath=yield this.loader.lookup(file2,type,sync,currentFile);return this.parse(sync?this.fs.readFileSync(filepath):yield this.fs.readFile(filepath),filepath)}},TokenKind;(function(TokenKind2){TokenKind2[TokenKind2.Number=1]="Number",TokenKind2[TokenKind2.Literal=2]="Literal",TokenKind2[TokenKind2.Tag=4]="Tag",TokenKind2[TokenKind2.Output=8]="Output",TokenKind2[TokenKind2.HTML=16]="HTML",TokenKind2[TokenKind2.Filter=32]="Filter",TokenKind2[TokenKind2.Hash=64]="Hash",TokenKind2[TokenKind2.PropertyAccess=128]="PropertyAccess",TokenKind2[TokenKind2.Word=256]="Word",TokenKind2[TokenKind2.Range=512]="Range",TokenKind2[TokenKind2.Quoted=1024]="Quoted",TokenKind2[TokenKind2.Operator=2048]="Operator",TokenKind2[TokenKind2.FilteredValue=4096]="FilteredValue",TokenKind2[TokenKind2.Delimited=12]="Delimited"})(TokenKind||(TokenKind={}));function isDelimitedToken(val){return!!(getKind(val)&TokenKind.Delimited)}function isOperatorToken(val){return getKind(val)===TokenKind.Operator}function isHTMLToken(val){return getKind(val)===TokenKind.HTML}function isOutputToken(val){return getKind(val)===TokenKind.Output}function isTagToken(val){return getKind(val)===TokenKind.Tag}function isQuotedToken(val){return getKind(val)===TokenKind.Quoted}function isNumberToken(val){return getKind(val)===TokenKind.Number}function isPropertyAccessToken(val){return getKind(val)===TokenKind.PropertyAccess}function isWordToken(val){return getKind(val)===TokenKind.Word}function isRangeToken(val){return getKind(val)===TokenKind.Range}function isValueToken(val){return(getKind(val)&1667)>0}function getKind(val){return val?val.kind:-1}var Context=class _Context{constructor(env={},opts=defaultOptions,renderOptions={},{memoryLimit,renderLimit}={}){var _a4,_b,_c,_d,_e2;this.scopes=[{}],this.registers={},this.breakCalled=!1,this.continueCalled=!1,this.sync=!!renderOptions.sync,this.opts=opts,this.globals=(_a4=renderOptions.globals)!==null&&_a4!==void 0?_a4:opts.globals,this.environments=isObject(env)?env:Object(env),this.strictVariables=(_b=renderOptions.strictVariables)!==null&&_b!==void 0?_b:this.opts.strictVariables,this.ownPropertyOnly=(_c=renderOptions.ownPropertyOnly)!==null&&_c!==void 0?_c:opts.ownPropertyOnly,this.memoryLimit=memoryLimit??new Limiter("memory alloc",(_d=renderOptions.memoryLimit)!==null&&_d!==void 0?_d:opts.memoryLimit),this.renderLimit=renderLimit??new Limiter("template render",getPerformance().now()+((_e2=renderOptions.renderLimit)!==null&&_e2!==void 0?_e2:opts.renderLimit))}getRegister(key){return this.registers[key]=this.registers[key]||{}}setRegister(key,value){return this.registers[key]=value}saveRegister(...keys){return keys.map(key=>[key,this.getRegister(key)])}restoreRegister(keyValues){return keyValues.forEach(([key,value])=>this.setRegister(key,value))}getAll(){return[this.globals,this.environments,...this.scopes].reduce((ctx,val)=>__assign(ctx,val),{})}get(paths){return this.getSync(paths)}getSync(paths){return toValueSync(this._get(paths))}*_get(paths){let scope=this.findScope(paths[0]);return yield this._getFromScope(scope,paths)}getFromScope(scope,paths){return toValueSync(this._getFromScope(scope,paths))}*_getFromScope(scope,paths,strictVariables=this.strictVariables){isString(paths)&&(paths=paths.split("."));for(let i=0;i<paths.length;i++)if(scope=yield this.readProperty(scope,paths[i]),strictVariables&&isUndefined(scope))throw new InternalUndefinedVariableError(paths.slice(0,i+1).join("."));return scope}push(ctx){return this.scopes.push(ctx)}pop(){return this.scopes.pop()}bottom(){return this.scopes[0]}spawn(scope={}){return new _Context(scope,this.opts,{sync:this.sync,globals:this.globals,strictVariables:this.strictVariables},{renderLimit:this.renderLimit,memoryLimit:this.memoryLimit})}findScope(key){for(let i=this.scopes.length-1;i>=0;i--){let candidate=this.scopes[i];if(key in candidate)return candidate}return key in this.environments?this.environments:this.globals}readProperty(obj,key){if(obj=toLiquid(obj),key=toValue(key),isNil(obj))return obj;if(isArray(obj)&&key<0)return obj[obj.length+ +key];let value=readJSProperty(obj,key,this.ownPropertyOnly);return value===void 0&&obj instanceof Drop?obj.liquidMethodMissing(key,this):isFunction(value)?value.call(obj):key==="size"?readSize(obj):key==="first"?readFirst(obj):key==="last"?readLast(obj):value}};function readJSProperty(obj,key,ownPropertyOnly){if(!(ownPropertyOnly&&!hasOwnProperty.call(obj,key)&&!(obj instanceof Drop)))return obj[key]}function readFirst(obj){return isArray(obj)?obj[0]:obj.first}function readLast(obj){return isArray(obj)?obj[obj.length-1]:obj.last}function readSize(obj){if(hasOwnProperty.call(obj,"size")||obj.size!==void 0)return obj.size;if(isArray(obj)||isString(obj))return obj.length;if(typeof obj=="object")return Object.keys(obj).length}var BlockMode;(function(BlockMode2){BlockMode2[BlockMode2.OUTPUT=0]="OUTPUT",BlockMode2[BlockMode2.STORE=1]="STORE"})(BlockMode||(BlockMode={}));var abs=argumentsToNumber(Math.abs),at_least=argumentsToNumber(Math.max),at_most=argumentsToNumber(Math.min),ceil=argumentsToNumber(Math.ceil),divided_by=argumentsToNumber((dividend,divisor,integerArithmetic=!1)=>integerArithmetic?Math.floor(dividend/divisor):dividend/divisor),floor=argumentsToNumber(Math.floor),minus=argumentsToNumber((v2,arg)=>v2-arg),plus=argumentsToNumber((lhs,rhs)=>lhs+rhs),modulo=argumentsToNumber((v2,arg)=>v2%arg),times=argumentsToNumber((v2,arg)=>v2*arg);function round(v2,arg=0){v2=toNumber(v2),arg=toNumber(arg);let amp=Math.pow(10,arg);return Math.round(v2*amp)/amp}var mathFilters=Object.freeze({__proto__:null,abs,at_least,at_most,ceil,divided_by,floor,minus,plus,modulo,times,round}),url_decode=x2=>decodeURIComponent(stringify2(x2)).replace(/\+/g," "),url_encode=x2=>encodeURIComponent(stringify2(x2)).replace(/%20/g,"+"),cgi_escape=x2=>encodeURIComponent(stringify2(x2)).replace(/%20/g,"+").replace(/[!'()*]/g,c=>"%"+c.charCodeAt(0).toString(16).toUpperCase()),uri_escape=x2=>encodeURI(stringify2(x2)).replace(/%5B/g,"[").replace(/%5D/g,"]"),rSlugifyDefault=/[^\p{M}\p{L}\p{Nd}]+/ug,rSlugifyReplacers={raw:/\s+/g,default:rSlugifyDefault,pretty:/[^\p{M}\p{L}\p{Nd}._~!$&'()+,;=@]+/ug,ascii:/[^A-Za-z0-9]+/g,latin:rSlugifyDefault,none:null};function slugify(str,mode="default",cased=!1){str=stringify2(str);let replacer=rSlugifyReplacers[mode];return replacer&&(mode==="latin"&&(str=removeAccents(str)),str=str.replace(replacer,"-").replace(/^-|-$/g,"")),cased?str:str.toLowerCase()}function removeAccents(str){return str.replace(/[àáâãäå]/g,"a").replace(/[æ]/g,"ae").replace(/[ç]/g,"c").replace(/[èéêë]/g,"e").replace(/[ìíîï]/g,"i").replace(/[ð]/g,"d").replace(/[ñ]/g,"n").replace(/[òóôõöø]/g,"o").replace(/[ùúûü]/g,"u").replace(/[ýÿ]/g,"y").replace(/[ß]/g,"ss").replace(/[œ]/g,"oe").replace(/[þ]/g,"th").replace(/[ẞ]/g,"SS").replace(/[Œ]/g,"OE").replace(/[Þ]/g,"TH")}var urlFilters=Object.freeze({__proto__:null,url_decode,url_encode,cgi_escape,uri_escape,slugify}),join=argumentsToValue(function(v2,arg){let array2=toArray(v2),sep3=isNil(arg)?" ":stringify2(arg),complexity=array2.length*(1+sep3.length);return this.context.memoryLimit.use(complexity),array2.join(sep3)}),last$1=argumentsToValue(v2=>isArrayLike(v2)?last(v2):""),first=argumentsToValue(v2=>isArrayLike(v2)?v2[0]:""),reverse=argumentsToValue(function(v2){let array2=toArray(v2);return this.context.memoryLimit.use(array2.length),[...array2].reverse()});function*sort(arr,property){let values=[],array2=toArray(arr);this.context.memoryLimit.use(array2.length);for(let item of array2)values.push([item,property?yield this.context._getFromScope(item,stringify2(property).split("."),!1):item]);return values.sort((lhs,rhs)=>{let lvalue=lhs[1],rvalue=rhs[1];return lvalue<rvalue?-1:lvalue>rvalue?1:0}).map(tuple2=>tuple2[0])}function sort_natural(input,property){let propertyString=stringify2(property),compare=property===void 0?caseInsensitiveCompare:(lhs,rhs)=>caseInsensitiveCompare(lhs[propertyString],rhs[propertyString]),array2=toArray(input);return this.context.memoryLimit.use(array2.length),[...array2].sort(compare)}var size=v2=>v2&&v2.length||0;function*map(arr,property){let results=[],array2=toArray(arr);this.context.memoryLimit.use(array2.length);for(let item of array2)results.push(yield this.context._getFromScope(item,stringify2(property),!1));return results}function*sum2(arr,property){let sum3=0,array2=toArray(arr);for(let item of array2){let data=Number(property?yield this.context._getFromScope(item,stringify2(property),!1):item);sum3+=Number.isNaN(data)?0:data}return sum3}function compact(arr){let array2=toArray(arr);return this.context.memoryLimit.use(array2.length),array2.filter(x2=>!isNil(toValue(x2)))}function concat(v2,arg=[]){let lhs=toArray(v2),rhs=toArray(arg);return this.context.memoryLimit.use(lhs.length+rhs.length),lhs.concat(rhs)}function push(v2,arg){return concat.call(this,v2,[arg])}function unshift(v2,arg){let array2=toArray(v2);this.context.memoryLimit.use(array2.length);let clone2=[...array2];return clone2.unshift(arg),clone2}function pop(v2){let clone2=[...toArray(v2)];return clone2.pop(),clone2}function shift(v2){let array2=toArray(v2);this.context.memoryLimit.use(array2.length);let clone2=[...array2];return clone2.shift(),clone2}function slice(v2,begin,length=1){return v2=toValue(v2),isNil(v2)?[]:(isArray(v2)||(v2=stringify2(v2)),begin=begin<0?v2.length+begin:begin,this.context.memoryLimit.use(length),v2.slice(begin,begin+length))}function expectedMatcher(expected){return this.context.opts.jekyllWhere?v2=>EmptyDrop.is(expected)?equals(v2,expected):isArray(v2)?arrayIncludes(v2,expected):equals(v2,expected):expected===void 0?v2=>isTruthy(v2,this.context):v2=>equals(v2,expected)}function*filter2(include,arr,property,expected){let values=[];arr=toArray(arr),this.context.memoryLimit.use(arr.length);let token=new Tokenizer(stringify2(property)).readScopeValue();for(let item of arr)values.push(yield evalToken(token,this.context.spawn(item)));let matcher2=expectedMatcher.call(this,expected);return arr.filter((_2,i)=>matcher2(values[i])===include)}function*filter_exp(include,arr,itemName,exp){let filtered=[],keyTemplate=new Value(stringify2(exp),this.liquid),array2=toArray(arr);this.context.memoryLimit.use(array2.length);for(let item of array2){this.context.push({[itemName]:item});let value=yield keyTemplate.value(this.context);this.context.pop(),value===include&&filtered.push(item)}return filtered}function*where(arr,property,expected){return yield*filter2.call(this,!0,arr,property,expected)}function*reject(arr,property,expected){return yield*filter2.call(this,!1,arr,property,expected)}function*where_exp(arr,itemName,exp){return yield*filter_exp.call(this,!0,arr,itemName,exp)}function*reject_exp(arr,itemName,exp){return yield*filter_exp.call(this,!1,arr,itemName,exp)}function*group_by(arr,property){let map3=new Map;arr=toEnumerable(arr);let token=new Tokenizer(stringify2(property)).readScopeValue();this.context.memoryLimit.use(arr.length);for(let item of arr){let key=yield evalToken(token,this.context.spawn(item));map3.has(key)||map3.set(key,[]),map3.get(key).push(item)}return[...map3.entries()].map(([name,items2])=>({name,items:items2}))}function*group_by_exp(arr,itemName,exp){let map3=new Map,keyTemplate=new Value(stringify2(exp),this.liquid);arr=toEnumerable(arr),this.context.memoryLimit.use(arr.length);for(let item of arr){this.context.push({[itemName]:item});let key=yield keyTemplate.value(this.context);this.context.pop(),map3.has(key)||map3.set(key,[]),map3.get(key).push(item)}return[...map3.entries()].map(([name,items2])=>({name,items:items2}))}function*search(arr,property,expected){let token=new Tokenizer(stringify2(property)).readScopeValue(),array2=toArray(arr),matcher2=expectedMatcher.call(this,expected);for(let index=0;index<array2.length;index++){let value=yield evalToken(token,this.context.spawn(array2[index]));if(matcher2(value))return[index,array2[index]]}}function*search_exp(arr,itemName,exp){let predicate=new Value(stringify2(exp),this.liquid),array2=toArray(arr);for(let index=0;index<array2.length;index++){this.context.push({[itemName]:array2[index]});let value=yield predicate.value(this.context);if(this.context.pop(),value)return[index,array2[index]]}}function*has(arr,property,expected){return!!(yield*search.call(this,arr,property,expected))}function*has_exp(arr,itemName,exp){return!!(yield*search_exp.call(this,arr,itemName,exp))}function*find_index(arr,property,expected){let result=yield*search.call(this,arr,property,expected);return result?result[0]:void 0}function*find_index_exp(arr,itemName,exp){let result=yield*search_exp.call(this,arr,itemName,exp);return result?result[0]:void 0}function*find(arr,property,expected){let result=yield*search.call(this,arr,property,expected);return result?result[1]:void 0}function*find_exp(arr,itemName,exp){let result=yield*search_exp.call(this,arr,itemName,exp);return result?result[1]:void 0}function uniq(arr){return arr=toArray(arr),this.context.memoryLimit.use(arr.length),[...new Set(arr)]}function sample(v2,count2=1){if(v2=toValue(v2),isNil(v2))return[];isArray(v2)||(v2=stringify2(v2)),this.context.memoryLimit.use(count2);let shuffled=[...v2].sort(()=>Math.random()-.5);return count2===1?shuffled[0]:shuffled.slice(0,count2)}var arrayFilters=Object.freeze({__proto__:null,join,last:last$1,first,reverse,sort,sort_natural,size,map,sum:sum2,compact,concat,push,unshift,pop,shift,slice,where,reject,where_exp,reject_exp,group_by,group_by_exp,has,has_exp,find_index,find_index_exp,find,find_exp,uniq,sample});function date(v2,format3,timezoneOffset){var _a4,_b,_c;let size2=((_a4=v2?.length)!==null&&_a4!==void 0?_a4:0)+((_b=format3?.length)!==null&&_b!==void 0?_b:0)+((_c=timezoneOffset?.length)!==null&&_c!==void 0?_c:0);this.context.memoryLimit.use(size2);let date6=parseDate(v2,this.context.opts,timezoneOffset);return date6?(format3=toValue(format3),format3=isNil(format3)?this.context.opts.dateFormat:stringify2(format3),strftime(date6,format3)):v2}function date_to_xmlschema(v2){return date.call(this,v2,"%Y-%m-%dT%H:%M:%S%:z")}function date_to_rfc822(v2){return date.call(this,v2,"%a, %d %b %Y %H:%M:%S %z")}function date_to_string(v2,type,style){return stringify_date.call(this,v2,"%b",type,style)}function date_to_long_string(v2,type,style){return stringify_date.call(this,v2,"%B",type,style)}function stringify_date(v2,month_type,type,style){let date6=parseDate(v2,this.context.opts);if(!date6)return v2;if(type==="ordinal"){let d=date6.getDate();return style==="US"?strftime(date6,`${month_type} ${d}%q, %Y`):strftime(date6,`${d}%q ${month_type} %Y`)}return strftime(date6,`%d ${month_type} %Y`)}function parseDate(v2,opts,timezoneOffset){let date6,defaultTimezoneOffset=timezoneOffset??opts.timezoneOffset,locale=opts.locale;return v2=toValue(v2),v2==="now"||v2==="today"?date6=new LiquidDate(Date.now(),locale,defaultTimezoneOffset):isNumber(v2)?date6=new LiquidDate(v2*1e3,locale,defaultTimezoneOffset):isString(v2)?/^\d+$/.test(v2)?date6=new LiquidDate(+v2*1e3,locale,defaultTimezoneOffset):opts.preserveTimezones&&timezoneOffset===void 0?date6=LiquidDate.createDateFixedToTimezone(v2,locale):date6=new LiquidDate(v2,locale,defaultTimezoneOffset):date6=new LiquidDate(v2,locale,defaultTimezoneOffset),date6.valid()?date6:void 0}var dateFilters=Object.freeze({__proto__:null,date,date_to_xmlschema,date_to_rfc822,date_to_string,date_to_long_string}),rCJKWord=/[\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF\u3040-\u309F\u30A0-\u30FF\uAC00-\uD7AF]/gu,rNonCJKWord=/[^\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF\u3040-\u309F\u30A0-\u30FF\uAC00-\uD7AF\s]+/gu;function append(v2,arg){assert(arguments.length===2,"append expect 2 arguments");let lhs=stringify2(v2),rhs=stringify2(arg);return this.context.memoryLimit.use(lhs.length+rhs.length),lhs+rhs}function prepend(v2,arg){assert(arguments.length===2,"prepend expect 2 arguments");let lhs=stringify2(v2),rhs=stringify2(arg);return this.context.memoryLimit.use(lhs.length+rhs.length),rhs+lhs}function lstrip(v2,chars){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),chars?(chars=escapeRegExp2(stringify2(chars)),str.replace(new RegExp(`^[${chars}]+`,"g"),"")):str.replace(/^\s+/,"")}function downcase(v2){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.toLowerCase()}function upcase(v2){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),stringify2(str).toUpperCase()}function remove(v2,arg){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.split(stringify2(arg)).join("")}function remove_first(v2,l){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.replace(stringify2(l),"")}function remove_last(v2,l){let str=stringify2(v2);this.context.memoryLimit.use(str.length);let pattern=stringify2(l),index=str.lastIndexOf(pattern);return index===-1?str:str.substring(0,index)+str.substring(index+pattern.length)}function rstrip(str,chars){return str=stringify2(str),this.context.memoryLimit.use(str.length),chars?(chars=escapeRegExp2(stringify2(chars)),str.replace(new RegExp(`[${chars}]+$`,"g"),"")):str.replace(/\s+$/,"")}function split(v2,arg){let str=stringify2(v2);this.context.memoryLimit.use(str.length);let arr=str.split(stringify2(arg));for(;arr.length&&arr[arr.length-1]==="";)arr.pop();return arr}function strip(v2,chars){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),chars?(chars=escapeRegExp2(stringify2(chars)),str.replace(new RegExp(`^[${chars}]+`,"g"),"").replace(new RegExp(`[${chars}]+$`,"g"),"")):str.trim()}function strip_newlines(v2){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.replace(/\r?\n/gm,"")}function capitalize(str){return str=stringify2(str),this.context.memoryLimit.use(str.length),str.charAt(0).toUpperCase()+str.slice(1).toLowerCase()}function replace(v2,pattern,replacement){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.split(stringify2(pattern)).join(replacement)}function replace_first(v2,arg1,arg2){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.replace(stringify2(arg1),arg2)}function replace_last(v2,arg1,arg2){let str=stringify2(v2);this.context.memoryLimit.use(str.length);let pattern=stringify2(arg1),index=str.lastIndexOf(pattern);if(index===-1)return str;let replacement=stringify2(arg2);return str.substring(0,index)+replacement+str.substring(index+pattern.length)}function truncate(v2,l=50,o="..."){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.length<=l?v2:str.substring(0,l-o.length)+o}function truncatewords(v2,words=15,o="..."){let str=stringify2(v2);this.context.memoryLimit.use(str.length);let arr=str.split(/\s+/);words<=0&&(words=1);let ret=arr.slice(0,words).join(" ");return arr.length>=words&&(ret+=o),ret}function normalize_whitespace(v2){let str=stringify2(v2);return this.context.memoryLimit.use(str.length),str.replace(/\s+/g," ")}function number_of_words(input,mode){let str=stringify2(input);if(this.context.memoryLimit.use(str.length),input=str.trim(),!input)return 0;switch(mode){case"cjk":return(input.match(rCJKWord)||[]).length+(input.match(rNonCJKWord)||[]).length;case"auto":return rCJKWord.test(input)?input.match(rCJKWord).length+(input.match(rNonCJKWord)||[]).length:input.split(/\s+/).length;default:return input.split(/\s+/).length}}function array_to_sentence_string(array2,connector="and"){switch(this.context.memoryLimit.use(array2.length),array2.length){case 0:return"";case 1:return array2[0];case 2:return`${array2[0]} ${connector} ${array2[1]}`;default:return`${array2.slice(0,-1).join(", ")}, ${connector} ${array2[array2.length-1]}`}}var stringFilters=Object.freeze({__proto__:null,append,prepend,lstrip,downcase,upcase,remove,remove_first,remove_last,rstrip,split,strip,strip_newlines,capitalize,replace,replace_first,replace_last,truncate,truncatewords,normalize_whitespace,number_of_words,array_to_sentence_string});function base64Encode(str){return Buffer.from(str,"utf8").toString("base64")}function base64Decode(str){return Buffer.from(str,"base64").toString("utf8")}function base64_encode(value){let str=stringify2(value);return this.context.memoryLimit.use(str.length),base64Encode(str)}function base64_decode(value){let str=stringify2(value);return this.context.memoryLimit.use(str.length),base64Decode(str)}var base64Filters=Object.freeze({__proto__:null,base64_encode,base64_decode}),filters=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},htmlFilters),mathFilters),urlFilters),arrayFilters),dateFilters),stringFilters),base64Filters),misc),AssignTag=class extends Tag{constructor(token,remainTokens,liquid){super(token,remainTokens,liquid),this.identifier=this.tokenizer.readIdentifier(),this.key=this.identifier.content,this.tokenizer.assert(this.key,"expected variable name"),this.tokenizer.skipBlank(),this.tokenizer.assert(this.tokenizer.peek()==="=",'expected "="'),this.tokenizer.advance(),this.value=new Value(this.tokenizer.readFilteredValue(),this.liquid)}*render(ctx){ctx.bottom()[this.key]=yield this.value.value(ctx,this.liquid.options.lenientIf)}*arguments(){yield this.value}*localScope(){yield this.identifier}},MODIFIERS=["offset","limit","reversed"],ForTag=class extends Tag{constructor(token,remainTokens,liquid,parser){super(token,remainTokens,liquid);let variable=this.tokenizer.readIdentifier(),inStr=this.tokenizer.readIdentifier(),collection2=this.tokenizer.readValue();if(!variable.size()||inStr.content!=="in"||!collection2)throw new Error(`illegal tag: ${token.getText()}`);this.variable=variable.content,this.collection=collection2,this.hash=new Hash(this.tokenizer,liquid.options.keyValueSeparator),this.templates=[],this.elseTemplates=[];let p,stream=parser.parseStream(remainTokens).on("start",()=>p=this.templates).on("tag:else",tag=>{assertEmpty(tag.args),p=this.elseTemplates}).on("tag:endfor",tag=>{assertEmpty(tag.args),stream.stop()}).on("template",tpl=>p.push(tpl)).on("end",()=>{throw new Error(`tag ${token.getText()} not closed`)});stream.start()}*render(ctx,emitter){let r=this.liquid.renderer,collection2=toEnumerable(yield evalToken(this.collection,ctx));if(!collection2.length){yield r.renderTemplates(this.elseTemplates,ctx,emitter);return}let continueKey="continue-"+this.variable+"-"+this.collection.getText();ctx.push({continue:ctx.getRegister(continueKey)});let hash2=yield this.hash.render(ctx);ctx.pop(),collection2=(this.liquid.options.orderedFilterParameters?Object.keys(hash2).filter(x2=>MODIFIERS.includes(x2)):MODIFIERS.filter(x2=>hash2[x2]!==void 0)).reduce((collection3,modifier)=>modifier==="offset"?offset(collection3,hash2.offset):modifier==="limit"?limit(collection3,hash2.limit):reversed(collection3),collection2),ctx.setRegister(continueKey,(hash2.offset||0)+collection2.length);let scope={forloop:new ForloopDrop(collection2.length,this.collection.getText(),this.variable)};ctx.push(scope);for(let item of collection2){if(scope[this.variable]=item,ctx.continueCalled=ctx.breakCalled=!1,yield r.renderTemplates(this.templates,ctx,emitter),ctx.breakCalled)break;scope.forloop.next()}ctx.continueCalled=ctx.breakCalled=!1,ctx.pop()}*children(){let templates=this.templates.slice();return this.elseTemplates&&templates.push(...this.elseTemplates),templates}*arguments(){yield this.collection;for(let v2 of Object.values(this.hash.hash))isValueToken(v2)&&(yield v2)}blockScope(){return[this.variable,"forloop"]}};function reversed(arr){return[...arr].reverse()}function offset(arr,count2){return arr.slice(count2)}function limit(arr,count2){return arr.slice(0,count2)}var CaptureTag=class extends Tag{constructor(tagToken,remainTokens,liquid,parser){for(super(tagToken,remainTokens,liquid),this.templates=[],this.identifier=this.readVariable(),this.variable=this.identifier.content;remainTokens.length;){let token=remainTokens.shift();if(isTagToken(token)&&token.name==="endcapture")return;this.templates.push(parser.parseToken(token,remainTokens))}throw new Error(`tag ${tagToken.getText()} not closed`)}readVariable(){let ident=this.tokenizer.readIdentifier();if(ident.content||(ident=this.tokenizer.readQuoted(),ident))return ident;throw this.tokenizer.error("invalid capture name")}*render(ctx){let html=yield this.liquid.renderer.renderTemplates(this.templates,ctx);ctx.bottom()[this.variable]=html}*children(){return this.templates}*localScope(){yield this.identifier}},CaseTag=class extends Tag{constructor(tagToken,remainTokens,liquid,parser){super(tagToken,remainTokens,liquid),this.branches=[],this.elseTemplates=[],this.value=new Value(this.tokenizer.readFilteredValue(),this.liquid),this.elseTemplates=[];let p=[],elseCount=0,stream=parser.parseStream(remainTokens).on("tag:when",token=>{if(elseCount>0)return;p=[];let values=[];for(;!token.tokenizer.end();)values.push(token.tokenizer.readValueOrThrow()),token.tokenizer.skipBlank(),token.tokenizer.peek()===","?token.tokenizer.readTo(","):token.tokenizer.readTo("or");this.branches.push({values,templates:p})}).on("tag:else",()=>{elseCount++,p=this.elseTemplates}).on("tag:endcase",()=>stream.stop()).on("template",tpl=>{(p!==this.elseTemplates||elseCount===1)&&p.push(tpl)}).on("end",()=>{throw new Error(`tag ${tagToken.getText()} not closed`)});stream.start()}*render(ctx,emitter){let r=this.liquid.renderer,target=toValue(yield this.value.value(ctx,ctx.opts.lenientIf)),branchHit=!1;for(let branch of this.branches)for(let valueToken of branch.values){let value=yield evalToken(valueToken,ctx,ctx.opts.lenientIf);if(equals(target,value)){yield r.renderTemplates(branch.templates,ctx,emitter),branchHit=!0;break}}branchHit||(yield r.renderTemplates(this.elseTemplates,ctx,emitter))}*arguments(){yield this.value,yield*this.branches.flatMap(b=>b.values)}*children(){let templates=this.branches.flatMap(b=>b.templates);return this.elseTemplates&&templates.push(...this.elseTemplates),templates}},CommentTag=class extends Tag{constructor(tagToken,remainTokens,liquid){for(super(tagToken,remainTokens,liquid);remainTokens.length;){let token=remainTokens.shift();if(isTagToken(token)&&token.name==="endcomment")return}throw new Error(`tag ${tagToken.getText()} not closed`)}render(){}},RenderTag=class extends Tag{constructor(token,remainTokens,liquid,parser){super(token,remainTokens,liquid);let tokenizer=this.tokenizer;for(this.file=parseFilePath(tokenizer,this.liquid,parser),this.currentFile=token.file;!tokenizer.end();){tokenizer.skipBlank();let begin=tokenizer.p,keyword=tokenizer.readIdentifier();if((keyword.content==="with"||keyword.content==="for")&&(tokenizer.skipBlank(),tokenizer.peek()!==":")){let value=tokenizer.readValue();if(value){let beforeAs=tokenizer.p,asStr=tokenizer.readIdentifier(),alias;asStr.content==="as"?alias=tokenizer.readIdentifier():tokenizer.p=beforeAs,this[keyword.content]={value,alias:alias&&alias.content},tokenizer.skipBlank(),tokenizer.peek()===","&&tokenizer.advance();continue}}tokenizer.p=begin;break}this.hash=new Hash(tokenizer,liquid.options.keyValueSeparator)}*render(ctx,emitter){let{liquid,hash:hash2}=this,filepath=yield renderFilePath(this.file,ctx,liquid);assert(filepath,()=>`illegal file path "${filepath}"`);let childCtx=ctx.spawn(),scope=childCtx.bottom();if(__assign(scope,yield hash2.render(ctx)),this.with){let{value,alias}=this.with;scope[alias||filepath]=yield evalToken(value,ctx)}if(this.for){let{value,alias}=this.for,collection2=toEnumerable(yield evalToken(value,ctx));scope.forloop=new ForloopDrop(collection2.length,value.getText(),alias);for(let item of collection2){scope[alias]=item;let templates=yield liquid._parsePartialFile(filepath,childCtx.sync,this.currentFile);yield liquid.renderer.renderTemplates(templates,childCtx,emitter),scope.forloop.next()}}else{let templates=yield liquid._parsePartialFile(filepath,childCtx.sync,this.currentFile);yield liquid.renderer.renderTemplates(templates,childCtx,emitter)}}*children(partials,sync){return partials&&isString(this.file)?yield this.liquid._parsePartialFile(this.file,sync,this.currentFile):[]}partialScope(){if(isString(this.file)){let names2=Object.keys(this.hash.hash);if(this.with){let{value,alias}=this.with;isString(alias)?names2.push([alias,value]):isString(this.file)&&names2.push([this.file,value])}if(this.for){let{value,alias}=this.for;isString(alias)?names2.push([alias,value]):isString(this.file)&&names2.push([this.file,value])}return{name:this.file,isolated:!0,scope:names2}}}*arguments(){for(let v2 of Object.values(this.hash.hash))isValueToken(v2)&&(yield v2);if(this.with){let{value}=this.with;isValueToken(value)&&(yield value)}if(this.for){let{value}=this.for;isValueToken(value)&&(yield value)}}};function parseFilePath(tokenizer,liquid,parser){if(liquid.options.dynamicPartials){let file2=tokenizer.readValue();if(tokenizer.assert(file2,"illegal file path"),file2.getText()==="none")return;if(isQuotedToken(file2)){let templates2=parser.parse(evalQuotedToken(file2));return optimize(templates2)}return file2}let tokens=[...tokenizer.readFileNameTemplate(liquid.options)],templates=optimize(parser.parseTokens(tokens));return templates==="none"?void 0:templates}function optimize(templates){return templates.length===1&&isHTMLToken(templates[0].token)?templates[0].token.getContent():templates}function*renderFilePath(file2,ctx,liquid){return typeof file2=="string"?file2:Array.isArray(file2)?liquid.renderer.renderTemplates(file2,ctx):yield evalToken(file2,ctx)}var IncludeTag=class extends Tag{constructor(token,remainTokens,liquid,parser){super(token,remainTokens,liquid);let{tokenizer}=token;this.file=parseFilePath(tokenizer,this.liquid,parser),this.currentFile=token.file;let begin=tokenizer.p;tokenizer.readIdentifier().content==="with"?(tokenizer.skipBlank(),tokenizer.peek()!==":"?this.withVar=tokenizer.readValue():tokenizer.p=begin):tokenizer.p=begin,this.hash=new Hash(tokenizer,liquid.options.jekyllInclude||liquid.options.keyValueSeparator)}*render(ctx,emitter){let{liquid,hash:hash2,withVar}=this,{renderer}=liquid,filepath=yield renderFilePath(this.file,ctx,liquid);assert(filepath,()=>`illegal file path "${filepath}"`);let saved=ctx.saveRegister("blocks","blockMode");ctx.setRegister("blocks",{}),ctx.setRegister("blockMode",BlockMode.OUTPUT);let scope=yield hash2.render(ctx);withVar&&(scope[filepath]=yield evalToken(withVar,ctx));let templates=yield liquid._parsePartialFile(filepath,ctx.sync,this.currentFile);ctx.push(ctx.opts.jekyllInclude?{include:scope}:scope),yield renderer.renderTemplates(templates,ctx,emitter),ctx.pop(),ctx.restoreRegister(saved)}*children(partials,sync){return partials&&isString(this.file)?yield this.liquid._parsePartialFile(this.file,sync,this.currentFile):[]}partialScope(){if(isString(this.file)){let names2;return this.liquid.options.jekyllInclude?names2=["include"]:(names2=Object.keys(this.hash.hash),this.withVar&&names2.push([this.file,this.withVar])),{name:this.file,isolated:!1,scope:names2}}}*arguments(){yield*Object.values(this.hash.hash).filter(isValueToken),isValueToken(this.file)&&(yield this.file),isValueToken(this.withVar)&&(yield this.withVar)}},DecrementTag=class extends Tag{constructor(token,remainTokens,liquid){super(token,remainTokens,liquid),this.identifier=this.tokenizer.readIdentifier(),this.variable=this.identifier.content}render(context,emitter){let scope=context.environments;isNumber(scope[this.variable])||(scope[this.variable]=0),emitter.write(stringify2(--scope[this.variable]))}*localScope(){yield this.identifier}},CycleTag=class extends Tag{constructor(token,remainTokens,liquid){super(token,remainTokens,liquid),this.candidates=[];let group=this.tokenizer.readValue();for(this.tokenizer.skipBlank(),group&&(this.tokenizer.peek()===":"?(this.group=group,this.tokenizer.advance()):this.candidates.push(group));!this.tokenizer.end();){let value=this.tokenizer.readValue();value&&this.candidates.push(value),this.tokenizer.readTo(",")}this.tokenizer.assert(this.candidates.length,()=>`empty candidates: "${token.getText()}"`)}*render(ctx,emitter){let fingerprint=`cycle:${yield evalToken(this.group,ctx)}:`+this.candidates.join(","),groups=ctx.getRegister("cycle"),idx=groups[fingerprint];idx===void 0&&(idx=groups[fingerprint]=0);let candidate=this.candidates[idx];return idx=(idx+1)%this.candidates.length,groups[fingerprint]=idx,yield evalToken(candidate,ctx)}*arguments(){yield*this.candidates,this.group&&(yield this.group)}},IfTag=class extends Tag{constructor(tagToken,remainTokens,liquid,parser){super(tagToken,remainTokens,liquid),this.branches=[];let p=[];parser.parseStream(remainTokens).on("start",()=>this.branches.push({value:new Value(tagToken.tokenizer.readFilteredValue(),this.liquid),templates:p=[]})).on("tag:elsif",token=>{assert(!this.elseTemplates,"unexpected elsif after else"),this.branches.push({value:new Value(token.tokenizer.readFilteredValue(),this.liquid),templates:p=[]})}).on("tag:else",tag=>{assertEmpty(tag.args),assert(!this.elseTemplates,"duplicated else"),p=this.elseTemplates=[]}).on("tag:endif",function(tag){assertEmpty(tag.args),this.stop()}).on("template",tpl=>p.push(tpl)).on("end",()=>{throw new Error(`tag ${tagToken.getText()} not closed`)}).start()}*render(ctx,emitter){let r=this.liquid.renderer;for(let{value,templates}of this.branches){let v2=yield value.value(ctx,ctx.opts.lenientIf);if(isTruthy(v2,ctx)){yield r.renderTemplates(templates,ctx,emitter);return}}yield r.renderTemplates(this.elseTemplates||[],ctx,emitter)}*children(){let templates=this.branches.flatMap(b=>b.templates);return this.elseTemplates&&templates.push(...this.elseTemplates),templates}arguments(){return this.branches.map(b=>b.value)}},IncrementTag=class extends Tag{constructor(token,remainTokens,liquid){super(token,remainTokens,liquid),this.identifier=this.tokenizer.readIdentifier(),this.variable=this.identifier.content}render(context,emitter){let scope=context.environments;isNumber(scope[this.variable])||(scope[this.variable]=0);let val=scope[this.variable];scope[this.variable]++,emitter.write(stringify2(val))}*localScope(){yield this.identifier}},LayoutTag=class extends Tag{constructor(token,remainTokens,liquid,parser){super(token,remainTokens,liquid),this.file=parseFilePath(this.tokenizer,this.liquid,parser),this.currentFile=token.file,this.args=new Hash(this.tokenizer,liquid.options.keyValueSeparator),this.templates=parser.parseTokens(remainTokens)}*render(ctx,emitter){let{liquid,args,file:file2}=this,{renderer}=liquid;if(file2===void 0){ctx.setRegister("blockMode",BlockMode.OUTPUT),yield renderer.renderTemplates(this.templates,ctx,emitter);return}let filepath=yield renderFilePath(this.file,ctx,liquid);assert(filepath,()=>`illegal file path "${filepath}"`);let templates=yield liquid._parseLayoutFile(filepath,ctx.sync,this.currentFile);ctx.setRegister("blockMode",BlockMode.STORE);let html=yield renderer.renderTemplates(this.templates,ctx),blocks=ctx.getRegister("blocks");blocks[""]===void 0&&(blocks[""]=(parent,emitter2)=>emitter2.write(html)),ctx.setRegister("blockMode",BlockMode.OUTPUT),ctx.push(yield args.render(ctx)),yield renderer.renderTemplates(templates,ctx,emitter),ctx.pop()}*children(partials){let templates=this.templates.slice();return partials&&isString(this.file)&&templates.push(...yield this.liquid._parsePartialFile(this.file,!0,this.currentFile)),templates}*arguments(){for(let v2 of Object.values(this.args.hash))isValueToken(v2)&&(yield v2);isValueToken(this.file)&&(yield this.file)}partialScope(){if(isString(this.file))return{name:this.file,isolated:!1,scope:Object.keys(this.args.hash)}}},BlockTag=class extends Tag{constructor(token,remainTokens,liquid,parser){super(token,remainTokens,liquid),this.templates=[];let match2=/\w+/.exec(token.args);for(this.block=match2?match2[0]:"";remainTokens.length;){let token2=remainTokens.shift();if(isTagToken(token2)&&token2.name==="endblock")return;let template=parser.parseToken(token2,remainTokens);this.templates.push(template)}throw new Error(`tag ${token.getText()} not closed`)}*render(ctx,emitter){let blockRender=this.getBlockRender(ctx);ctx.getRegister("blockMode")===BlockMode.STORE?ctx.getRegister("blocks")[this.block]=blockRender:yield blockRender(new BlockDrop,emitter)}getBlockRender(ctx){let{liquid,templates}=this,renderChild=ctx.getRegister("blocks")[this.block],renderCurrent=function*(superBlock,emitter){ctx.push({block:superBlock}),yield liquid.renderer.renderTemplates(templates,ctx,emitter),ctx.pop()};return renderChild?(superBlock,emitter)=>renderChild(new BlockDrop(emitter2=>renderCurrent(superBlock,emitter2)),emitter):renderCurrent}*children(){return this.templates}blockScope(){return["block"]}},RawTag=class extends Tag{constructor(tagToken,remainTokens,liquid){for(super(tagToken,remainTokens,liquid),this.tokens=[];remainTokens.length;){let token=remainTokens.shift();if(isTagToken(token)&&token.name==="endraw")return;this.tokens.push(token)}throw new Error(`tag ${tagToken.getText()} not closed`)}render(){return this.tokens.map(token=>token.getText()).join("")}},TablerowloopDrop=class extends ForloopDrop{constructor(length,cols,collection2,variable){super(length,collection2,variable),this.length=length,this.cols=cols}row(){return Math.floor(this.i/this.cols)+1}col0(){return this.i%this.cols}col(){return this.col0()+1}col_first(){return this.col0()===0}col_last(){return this.col()===this.cols}},TablerowTag=class extends Tag{constructor(tagToken,remainTokens,liquid,parser){super(tagToken,remainTokens,liquid);let variable=this.tokenizer.readIdentifier();this.tokenizer.skipBlank();let predicate=this.tokenizer.readIdentifier(),collectionToken=this.tokenizer.readValue();if(predicate.content!=="in"||!collectionToken)throw new Error(`illegal tag: ${tagToken.getText()}`);this.variable=variable.content,this.collection=collectionToken,this.args=new Hash(this.tokenizer,liquid.options.keyValueSeparator),this.templates=[];let p,stream=parser.parseStream(remainTokens).on("start",()=>p=this.templates).on("tag:endtablerow",()=>stream.stop()).on("template",tpl=>p.push(tpl)).on("end",()=>{throw new Error(`tag ${tagToken.getText()} not closed`)});stream.start()}*render(ctx,emitter){let collection2=toEnumerable(yield evalToken(this.collection,ctx)),args=yield this.args.render(ctx),offset2=args.offset||0,limit2=args.limit===void 0?collection2.length:args.limit;collection2=collection2.slice(offset2,offset2+limit2);let cols=args.cols||collection2.length,r=this.liquid.renderer,tablerowloop=new TablerowloopDrop(collection2.length,cols,this.collection.getText(),this.variable),scope={tablerowloop};ctx.push(scope);for(let idx=0;idx<collection2.length;idx++,tablerowloop.next())scope[this.variable]=collection2[idx],tablerowloop.col0()===0&&(tablerowloop.row()!==1&&emitter.write("</tr>"),emitter.write(`<tr class="row${tablerowloop.row()}">`)),emitter.write(`<td class="col${tablerowloop.col()}">`),yield r.renderTemplates(this.templates,ctx,emitter),emitter.write("</td>");collection2.length&&emitter.write("</tr>"),ctx.pop()}*children(){return this.templates}*arguments(){yield this.collection;for(let v2 of Object.values(this.args.hash))isValueToken(v2)&&(yield v2)}blockScope(){return[this.variable,"tablerowloop"]}},UnlessTag=class extends Tag{constructor(tagToken,remainTokens,liquid,parser){super(tagToken,remainTokens,liquid),this.branches=[],this.elseTemplates=[];let p=[],elseCount=0;parser.parseStream(remainTokens).on("start",()=>this.branches.push({value:new Value(tagToken.tokenizer.readFilteredValue(),this.liquid),test:isFalsy,templates:p=[]})).on("tag:elsif",token=>{if(elseCount>0){p=[];return}this.branches.push({value:new Value(token.tokenizer.readFilteredValue(),this.liquid),test:isTruthy,templates:p=[]})}).on("tag:else",()=>{elseCount++,p=this.elseTemplates}).on("tag:endunless",function(){this.stop()}).on("template",tpl=>{(p!==this.elseTemplates||elseCount===1)&&p.push(tpl)}).on("end",()=>{throw new Error(`tag ${tagToken.getText()} not closed`)}).start()}*render(ctx,emitter){let r=this.liquid.renderer;for(let{value,test,templates}of this.branches){let v2=yield value.value(ctx,ctx.opts.lenientIf);if(test(v2,ctx)){yield r.renderTemplates(templates,ctx,emitter);return}}yield r.renderTemplates(this.elseTemplates,ctx,emitter)}*children(){let children=this.branches.flatMap(b=>b.templates);return this.elseTemplates&&children.push(...this.elseTemplates),children}arguments(){return this.branches.map(b=>b.value)}},BreakTag=class extends Tag{render(ctx,_emitter){ctx.breakCalled=!0}},ContinueTag=class extends Tag{render(ctx,_emitter){ctx.continueCalled=!0}},EchoTag=class extends Tag{constructor(token,remainTokens,liquid){super(token,remainTokens,liquid),this.tokenizer.skipBlank(),this.tokenizer.end()||(this.value=new Value(this.tokenizer.readFilteredValue(),this.liquid))}*render(ctx,emitter){if(!this.value)return;let val=yield this.value.value(ctx,!1);emitter.write(val)}*arguments(){this.value&&(yield this.value)}},LiquidTag=class extends Tag{constructor(token,remainTokens,liquid,parser){super(token,remainTokens,liquid);let tokens=this.tokenizer.readLiquidTagTokens(this.liquid.options);this.templates=parser.parseTokens(tokens)}*render(ctx,emitter){yield this.liquid.renderer.renderTemplates(this.templates,ctx,emitter)}*children(){return this.templates}},InlineCommentTag=class extends Tag{constructor(tagToken,remainTokens,liquid){if(super(tagToken,remainTokens,liquid),tagToken.args.search(/\n\s*[^#\s]/g)!==-1)throw new Error("every line of an inline comment must start with a '#' character")}render(){}},tags={assign:AssignTag,for:ForTag,capture:CaptureTag,case:CaseTag,comment:CommentTag,include:IncludeTag,render:RenderTag,decrement:DecrementTag,increment:IncrementTag,cycle:CycleTag,if:IfTag,layout:LayoutTag,block:BlockTag,raw:RawTag,tablerow:TablerowTag,unless:UnlessTag,break:BreakTag,continue:ContinueTag,echo:EchoTag,liquid:LiquidTag,"#":InlineCommentTag},Liquid=class _Liquid{constructor(opts={}){this.renderer=new Render,this.filters={},this.tags={},this.options=normalize(opts),this.parser=new Parser(this),forOwn(tags,(conf,name)=>this.registerTag(name,conf)),forOwn(filters,(handler,name)=>this.registerFilter(name,handler))}parse(html,filepath){return new Parser(this).parse(html,filepath)}_render(tpl,scope,renderOptions){let ctx=scope instanceof Context?scope:new Context(scope,this.options,renderOptions);return this.renderer.renderTemplates(tpl,ctx)}render(tpl,scope,renderOptions){return __awaiter(this,void 0,void 0,function*(){return toPromise(this._render(tpl,scope,Object.assign(Object.assign({},renderOptions),{sync:!1})))})}renderSync(tpl,scope,renderOptions){return toValueSync(this._render(tpl,scope,Object.assign(Object.assign({},renderOptions),{sync:!0})))}renderToNodeStream(tpl,scope,renderOptions={}){let ctx=new Context(scope,this.options,renderOptions);return this.renderer.renderTemplatesToNodeStream(tpl,ctx)}_parseAndRender(html,scope,renderOptions){let tpl=this.parse(html);return this._render(tpl,scope,renderOptions)}parseAndRender(html,scope,renderOptions){return __awaiter(this,void 0,void 0,function*(){return toPromise(this._parseAndRender(html,scope,Object.assign(Object.assign({},renderOptions),{sync:!1})))})}parseAndRenderSync(html,scope,renderOptions){return toValueSync(this._parseAndRender(html,scope,Object.assign(Object.assign({},renderOptions),{sync:!0})))}_parsePartialFile(file2,sync,currentFile){return new Parser(this).parseFile(file2,sync,LookupType.Partials,currentFile)}_parseLayoutFile(file2,sync,currentFile){return new Parser(this).parseFile(file2,sync,LookupType.Layouts,currentFile)}_parseFile(file2,sync,lookupType,currentFile){return new Parser(this).parseFile(file2,sync,lookupType,currentFile)}parseFile(file2,lookupType){return __awaiter(this,void 0,void 0,function*(){return toPromise(new Parser(this).parseFile(file2,!1,lookupType))})}parseFileSync(file2,lookupType){return toValueSync(new Parser(this).parseFile(file2,!0,lookupType))}*_renderFile(file2,ctx,renderFileOptions){let templates=yield this._parseFile(file2,renderFileOptions.sync,renderFileOptions.lookupType);return yield this._render(templates,ctx,renderFileOptions)}renderFile(file2,ctx,renderFileOptions){return __awaiter(this,void 0,void 0,function*(){return toPromise(this._renderFile(file2,ctx,Object.assign(Object.assign({},renderFileOptions),{sync:!1})))})}renderFileSync(file2,ctx,renderFileOptions){return toValueSync(this._renderFile(file2,ctx,Object.assign(Object.assign({},renderFileOptions),{sync:!0})))}renderFileToNodeStream(file2,scope,renderOptions){return __awaiter(this,void 0,void 0,function*(){let templates=yield this.parseFile(file2);return this.renderToNodeStream(templates,scope,renderOptions)})}_evalValue(str,scope){let value=new Value(str,this),ctx=scope instanceof Context?scope:new Context(scope,this.options);return value.value(ctx)}evalValue(str,scope){return __awaiter(this,void 0,void 0,function*(){return toPromise(this._evalValue(str,scope))})}evalValueSync(str,scope){return toValueSync(this._evalValue(str,scope))}registerFilter(name,filter3){this.filters[name]=filter3}registerTag(name,tag){this.tags[name]=isFunction(tag)?tag:createTagClass(tag)}plugin(plugin){return plugin.call(this,_Liquid)}express(){let self=this,firstCall=!0;return function(filePath,ctx,callback){if(firstCall){firstCall=!1;let dirs=normalizeDirectoryList(this.root);self.options.root.unshift(...dirs),self.options.layouts.unshift(...dirs),self.options.partials.unshift(...dirs)}self.renderFile(filePath,ctx).then(html=>callback(null,html),callback)}}analyze(template,options={}){return __awaiter(this,void 0,void 0,function*(){return analyze(template,options)})}analyzeSync(template,options={}){return analyzeSync(template,options)}parseAndAnalyze(html,filename,options={}){return __awaiter(this,void 0,void 0,function*(){return analyze(this.parse(html,filename),options)})}parseAndAnalyzeSync(html,filename,options={}){return analyzeSync(this.parse(html,filename),options)}variables(template,options={}){return __awaiter(this,void 0,void 0,function*(){let analysis=yield analyze(isString(template)?this.parse(template):template,options);return Object.keys(analysis.variables)})}variablesSync(template,options={}){let analysis=analyzeSync(isString(template)?this.parse(template):template,options);return Object.keys(analysis.variables)}fullVariables(template,options={}){return __awaiter(this,void 0,void 0,function*(){let analysis=yield analyze(isString(template)?this.parse(template):template,options);return Array.from(new Set(Object.values(analysis.variables).flatMap(a=>a.map(v2=>String(v2)))))})}fullVariablesSync(template,options={}){let analysis=analyzeSync(isString(template)?this.parse(template):template,options);return Array.from(new Set(Object.values(analysis.variables).flatMap(a=>a.map(v2=>String(v2)))))}variableSegments(template,options={}){return __awaiter(this,void 0,void 0,function*(){let analysis=yield analyze(isString(template)?this.parse(template):template,options);return Array.from(strictUniq(Object.values(analysis.variables).flatMap(a=>a.map(v2=>v2.toArray()))))})}variableSegmentsSync(template,options={}){let analysis=analyzeSync(isString(template)?this.parse(template):template,options);return Array.from(strictUniq(Object.values(analysis.variables).flatMap(a=>a.map(v2=>v2.toArray()))))}globalVariables(template,options={}){return __awaiter(this,void 0,void 0,function*(){let analysis=yield analyze(isString(template)?this.parse(template):template,options);return Object.keys(analysis.globals)})}globalVariablesSync(template,options={}){let analysis=analyzeSync(isString(template)?this.parse(template):template,options);return Object.keys(analysis.globals)}globalFullVariables(template,options={}){return __awaiter(this,void 0,void 0,function*(){let analysis=yield analyze(isString(template)?this.parse(template):template,options);return Array.from(new Set(Object.values(analysis.globals).flatMap(a=>a.map(v2=>String(v2)))))})}globalFullVariablesSync(template,options={}){let analysis=analyzeSync(isString(template)?this.parse(template):template,options);return Array.from(new Set(Object.values(analysis.globals).flatMap(a=>a.map(v2=>String(v2)))))}globalVariableSegments(template,options={}){return __awaiter(this,void 0,void 0,function*(){let analysis=yield analyze(isString(template)?this.parse(template):template,options);return Array.from(strictUniq(Object.values(analysis.globals).flatMap(a=>a.map(v2=>v2.toArray()))))})}globalVariableSegmentsSync(template,options={}){let analysis=analyzeSync(isString(template)?this.parse(template):template,options);return Array.from(strictUniq(Object.values(analysis.globals).flatMap(a=>a.map(v2=>v2.toArray()))))}};import{NotFoundError as NotFoundError3,PluginError as PluginError5}from"@sous-io/plugin-api";var DEFAULT_PURPOSE="template",CONFIG_EXPRESSION_PURPOSE="config-expression";function tagAllowed(tag,purpose){return tag.purposes?tag.purposes.includes(purpose):purpose!==CONFIG_EXPRESSION_PURPOSE}function filterAllowed(filter3,purpose){return filter3.purposes?filter3.purposes.includes(purpose):!0}function createLiquidEngines(deps){return{create:(options={})=>buildEngine(deps,options),available(purpose=DEFAULT_PURPOSE){return{tags:deps.entities.list("liquid-tag").filter(tag=>tagAllowed(tag,purpose)).map(tag=>tag.id),filters:deps.entities.list("liquid-filter").filter(filter3=>filterAllowed(filter3,purpose)).map(filter3=>filter3.id)}}}}function buildEngine(deps,options){let purpose=options.purpose??DEFAULT_PURPOSE,root=rootOf(options.root,deps.project),liquidOptions={extname:"",strictVariables:!1,strictFilters:!1,...options.liquid,...root===void 0?{}:{root},...options.fs===void 0?{}:{fs:options.fs}},engine=new Liquid(liquidOptions),ctx=Object.freeze({project:deps.project,env:deps.env,services:deps.services,entities:deps.entities,purpose,secretNames:new Set(options.secretNames??declaredSecrets(deps.services)),data:Object.freeze({...options.data})}),filters2=pick(deps.entities.describe("liquid-filter"),options.only?.filters,entry=>filterAllowed(entry,purpose),"Liquid filter");for(let record2 of filters2)engine.registerFilter(record2.id,make(record2,"filter",()=>record2.entry.filter(ctx)));let tags2=pick(deps.entities.describe("liquid-tag"),options.only?.tags,entry=>tagAllowed(entry,purpose),"Liquid tag");for(let record2 of tags2)engine.registerTag(record2.id,make(record2,"tag",()=>record2.entry.tag(ctx)));return engine}function rootOf(root,project){return root!==void 0?typeof root=="string"?root:[...root]:project?[project.root]:void 0}function declaredSecrets(services){return services.has("variables.secrets")?services.get("variables.secrets").declared():[]}function pick(records,only,allowed,thing){return only===void 0?records.filter(record2=>allowed(record2.entry)):only.map(id=>{let record2=records.find(candidate=>candidate.id===id);if(!record2)throw new NotFoundError3(thing,id);return record2})}function make(record2,what,factory2){try{return factory2()}catch(error51){throw new PluginError5(record2.plugin,`The Liquid ${what} "${record2.id}" from ${record2.plugin} could not be made.`,{cause:error51,details:[error51 instanceof Error?error51.message:String(error51)]})}}import{jsonSchema as jsonSchema8}from"@sous-io/plugin-api";var PURPOSES={type:"array",items:{type:"string"}};function extensionSchema(factory2){let base=jsonSchema8({type:"object",properties:{id:{type:"string"},description:{type:"string"},purposes:PURPOSES,[factory2]:{}},required:["id",factory2]});return{"~standard":{...base["~standard"],validate(value){let result=base["~standard"].validate(value);return result instanceof Promise||result.issues?result:typeof result.value[factory2]!="function"?{issues:[{message:"Expected a function.",path:[factory2]}]}:result}}}}var liquidTagSchema=extensionSchema("tag"),liquidFilterSchema=extensionSchema("filter");var package_default7={name:"@sous-io/plugin-liquid",version:"1.0.12",description:"A configured LiquidJS engine, and the Liquid tags and filters plugins add.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-host":"workspace:*",liquidjs:"^10.25.0"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME6="@sous-io/plugin-liquid",liquidPlugin=definePlugin7({name:PLUGIN_NAME6,version:package_default7.version,description:"A configured LiquidJS engine, and the Liquid tags and filters plugins add.",dependsOn:{"@sous-io/plugin-host":`^${package_default7.version}`},register(sous){sous.entities.define("liquid-tag",liquidTagSchema,{description:"A Liquid tag, as written in {% name %}."}),sous.entities.define("liquid-filter",liquidFilterSchema,{description:"A Liquid filter, as written after |. Config expressions see it too."}),sous.services.add("liquid.engine",(_config,ctx)=>createLiquidEngines(ctx),{lifetime:"factory"})}});import{definePlugin as definePlugin8,SousError as SousError14}from"@sous-io/plugin-api";var import_yaml2=__toESM(require_dist(),1);init_main();import fs14 from"node:fs";import fsPromises from"node:fs/promises";import path20 from"node:path";import{ConfigError as ConfigError18,NotFoundError as NotFoundError4}from"@sous-io/plugin-api";init_external();init_external();var import_semver2=__toESM(require_semver2(),1);import{ConfigError as ConfigError17}from"@sous-io/plugin-api";var KEBAB_NAME_PATTERN=/^[a-z][a-z0-9-]*$/;var REF_KEY_PATTERN=/^[a-z][a-z0-9-]*(\/[a-z][a-z0-9-]*)?$/,RECIPE_KEY_PATTERN=/^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/,REPO_IDENTITY_PATTERN=/^[^\s/]+(\/[^\s/]+)+$/,CONTENT_HASH_PATTERN=/^sha256-[0-9a-f]{64}$/,ENV_VAR_NAME_PATTERN=/^[A-Z][A-Z0-9_]*$/,VARIABLE_NAME_PATTERN2=/^[a-z][a-zA-Z0-9]*$/,ISO_TIMESTAMP_PATTERN=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?(Z|[+-]\d{2}:\d{2})$/;var SUPPORTED_FORMAT_VERSION=1,formatVersionSchema=external_exports.literal(SUPPORTED_FORMAT_VERSION,{message:`must be ${SUPPORTED_FORMAT_VERSION}; this version of sous understands no other on-disk format version`}),REPO_MANIFEST_BASENAME="sous.repo",RECIPE_MANIFEST_BASENAME="sous.recipe",INDEX_FILENAME="sous.index.json",LOCKFILE_FILENAME="sous.lock.json",STORE_ENTRY_FILENAME=".sous.entry.json";var LINKS_FILENAME="sous.links.json",MANIFEST_EXTENSIONS=[".yaml",".yml",".json",".jsonc"];function kebabName(label,example){return external_exports.string().regex(KEBAB_NAME_PATTERN,`a ${label} must be lowercase kebab-case: a letter, then letters, digits or hyphens (for example '${example}')`)}var repoNameSchema=kebabName("repo name","sous-recipes"),repoIdentitySchema=external_exports.string().regex(REPO_IDENTITY_PATTERN,"a repository identity must be its host followed by the path it lives at, all lowercase (for example 'github.com/sous-io/sous-recipes')"),namespaceNameSchema=kebabName("namespace name","tool-usage"),recipeNameSchema=kebabName("recipe name","task-files"),variableNameSchema=external_exports.string().regex(VARIABLE_NAME_PATTERN2,"a variable name must be camelCase: a lowercase letter, then letters or digits (for example 'apiBaseUrl')"),envVarNameSchema=external_exports.string().regex(ENV_VAR_NAME_PATTERN,"an environment variable name must be upper snake case: a capital letter, then capitals, digits or underscores (for example 'GITHUB_TOKEN')"),refKeySchema=external_exports.string().regex(REF_KEY_PATTERN,"a ref key must be a namespace ('workflow') or a namespace and recipe ('workflow/task-files'), with no repo qualifier and no version range"),recipeKeySchema=external_exports.string().regex(RECIPE_KEY_PATTERN,"a recipe key must be a namespace and recipe joined by a slash (for example 'workflow/task-files')"),DEPENDENCY_KINDS=["subscribes","depends"],dependencyKindSchema=external_exports.enum(DEPENDENCY_KINDS),semverVersionSchema=external_exports.string().refine(value=>import_semver2.default.valid(value)!==null,{message:"must be an exact semantic version, such as '1.4.0' or '2.0.0-beta.1'"}),semverRangeSchema=external_exports.string().refine(value=>import_semver2.default.validRange(value)!==null,{message:"must be a semantic version range, such as '^1.2.0', '~2.1', '>=1.0.0 <2.0.0' or '*'"}),contentHashSchema=external_exports.string().regex(CONTENT_HASH_PATTERN,"a content hash must be written as 'sha256-' followed by 64 lowercase hexadecimal characters"),isoTimestampSchema=external_exports.string().regex(ISO_TIMESTAMP_PATTERN,"must be an ISO 8601 timestamp with an offset, such as '2026-09-09T14:03:11.482Z'"),byteCountSchema=external_exports.number().int("must be a whole number of bytes").min(0,"must not be negative"),repoUrlSchema=external_exports.union([external_exports.url(),external_exports.string().min(1,"must not be empty").refine(value=>value.startsWith("/")||/^[A-Za-z]:[\\/]/.test(value),{message:"must be a repository URL, or an absolute path to one on this machine"})]),absolutePathSchema=external_exports.string().min(1,"must not be empty").refine(value=>value.startsWith("/")||/^[A-Za-z]:[\\/]/.test(value),{message:"must be an absolute path"});function relativePathSchema(label,allowGlobs=!1){return external_exports.string().superRefine((value,ctx)=>{let fail=message2=>{ctx.addIssue({code:"custom",message:`${label} ${message2}`})};if(value.length===0){fail("must not be empty");return}if(value.startsWith("/")||/^[A-Za-z]:[\\/]/.test(value)){fail("must be relative, not absolute");return}if(value.includes("\\")){fail("must use forward slashes, never backslashes");return}if(value.endsWith("/")){fail("must not end with a slash");return}if(!allowGlobs&&/[*?[\]{}]/.test(value)){fail("must be a plain path, with no glob characters");return}for(let segment of value.split("/")){if(segment.length===0){fail("must not contain an empty path segment");return}if(segment==="."||segment===".."){fail("must not contain a '.' or '..' segment");return}}})}function isPlainObject2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function stripExtensionKeys(value){if(!isPlainObject2(value))return value;let found=!1;for(let key of Object.keys(value))if(key.startsWith("x-")){found=!0;break}if(!found)return value;let copy={};for(let[key,entry]of Object.entries(value))key.startsWith("x-")||(copy[key]=entry);return copy}function extensibleObject(shape){return external_exports.preprocess(stripExtensionKeys,external_exports.strictObject(shape))}function forwardCompatibleObject(shape){return external_exports.looseObject(shape)}var submissionsSchema=extensibleObject({allowed:external_exports.boolean().default(!0),instead:external_exports.string().min(1,"must not be empty").optional()});function formatIssuePath(parts){let out="";for(let part of parts)typeof part=="number"?out+=`[${part}]`:out+=out.length>0?`.${String(part)}`:String(part);return out}function parseFormat(schema,value,sourceLabel2,formatLabel){let result=schema.safeParse(value);if(result.success)return result.data;throw new ConfigError17([`Invalid ${formatLabel} at ${sourceLabel2}:`,...describeIssues(result.error)].join(`
850
851
  `))}function checkFormat(schema,value){let result=schema.safeParse(value);return result.success?{value:result.data}:{issues:describeIssues(result.error)}}function describeIssues(error51){let lines3=[];for(let issue2 of error51.issues){let where2=formatIssuePath(issue2.path);if(issue2.code==="unrecognized_keys"){let keys=issue2.keys.map(key=>`'${key}'`).join(", "),location=where2.length>0?`under '${where2}'`:"at the top level";lines3.push(` - unknown key ${keys} ${location}. This is likely a typo; sous ignores only keys that start with 'x-'.`)}else if(issue2.code==="invalid_key"){let reasons=issue2.issues.map(inner=>inner.message).join("; ");lines3.push(` - ${where2}: invalid key; ${reasons}`)}else lines3.push(` - ${where2.length>0?where2:"(root)"}: ${issue2.message}`)}return lines3}function stableJsonStringify(value){return JSON.stringify(sortKeysDeep(value),null,2)+`
851
852
  `}function sortKeysDeep(value){if(Array.isArray(value))return value.map(sortKeysDeep);if(!isPlainObject2(value))return value;let sorted2={};for(let key of Object.keys(value).sort())sorted2[key]=sortKeysDeep(value[key]);return sorted2}var VARIABLE_TYPES=["string","number","boolean","enum","path","url"],VARIABLE_SCOPES=["shared","local"],variableValidationShape={pattern:external_exports.string().refine(value=>{try{return new RegExp(value),!0}catch{return!1}},{message:"must be a valid regular expression"}).optional(),minLength:external_exports.number().int().min(0).optional(),maxLength:external_exports.number().int().min(0).optional(),min:external_exports.number().optional(),max:external_exports.number().optional(),enum:external_exports.array(external_exports.string()).min(1,"must list at least one option").optional()},variableValidationSchema=extensibleObject(variableValidationShape);function variableDefinitionShape(validate){return{name:variableNameSchema,env:envVarNameSchema.optional(),type:external_exports.enum(VARIABLE_TYPES),prompt:external_exports.string().min(1,"must not be empty"),description:external_exports.string({error:"is required: every published variable must explain itself in a sentence or two. The description is shown above the question when sous asks, and by 'sous vars <name>'"}).min(1,"must not be empty"),example:external_exports.union([external_exports.string(),external_exports.number(),external_exports.boolean()],{error:"is required: every published variable must show what a real answer looks like. The example is shown with the question and by 'sous vars <name>'; it is documentation only and is never stored as the answer (use 'default' for that)"}),default:external_exports.union([external_exports.string(),external_exports.number(),external_exports.boolean()]).optional(),required:external_exports.boolean().default(!0),secret:external_exports.boolean().default(!1),scope:external_exports.enum(VARIABLE_SCOPES).default("shared"),validate:validate.optional()}}function checkVariableDefinition(definition,ctx){let{type,validate}=definition;if(type==="enum"&&(validate?.enum===void 0||validate.enum.length===0)&&ctx.addIssue({code:"custom",path:["validate","enum"],message:"a variable of type 'enum' must list its options under 'validate.enum'"}),validate!==void 0){let{minLength,maxLength,min,max}=validate;minLength!==void 0&&maxLength!==void 0&&minLength>maxLength&&ctx.addIssue({code:"custom",path:["validate","maxLength"],message:"must not be smaller than 'validate.minLength'"}),min!==void 0&&max!==void 0&&min>max&&ctx.addIssue({code:"custom",path:["validate","max"],message:"must not be smaller than 'validate.min'"})}definition.secret&&definition.scope==="shared"&&ctx.addIssue({code:"custom",path:["scope"],message:"a secret variable is stored in the gitignored '.sous/.env.local', so its scope must be 'local' (or left unset)"}),checkDeclaredValue(definition.default,"default"),checkDeclaredValue(definition.example,"example");function checkDeclaredValue(value,field){if(value===void 0)return;let expected=type==="boolean"?"boolean":type==="number"?"number":"string";typeof value!==expected?ctx.addIssue({code:"custom",path:[field],message:`must be a ${expected}, to match the declared type '${type}'`}):type==="enum"&&validate?.enum!==void 0&&!validate.enum.includes(String(value))&&ctx.addIssue({code:"custom",path:[field],message:"must be one of the options listed under 'validate.enum'"})}}var variableDefinitionSchema=extensibleObject(variableDefinitionShape(variableValidationSchema)).superRefine(checkVariableDefinition),publishedVariableDefinitionSchema=forwardCompatibleObject(variableDefinitionShape(forwardCompatibleObject(variableValidationShape))).superRefine(checkVariableDefinition);function dependencyRefSchema(check3){return external_exports.string().superRefine((value,ctx)=>{try{check3(value)}catch(error51){ctx.addIssue({code:"custom",message:error51.message})}})}function refListSchema(label,check3){return external_exports.array(dependencyRefSchema(check3)).superRefine((refs,ctx)=>{let seen=new Set;refs.forEach((entry,index)=>{let trimmed=entry.trim();seen.has(trimmed)&&ctx.addIssue({code:"custom",path:[index],message:`'${trimmed}' is listed more than once in ${label}`}),seen.add(trimmed)})})}var CONTENT_KINDS=["skills","memories","prompts","config"],recipeContentSchema=extensibleObject({kind:external_exports.enum(CONTENT_KINDS),include:external_exports.array(relativePathSchema("an include pattern",!0)).min(1,"must list at least one include pattern"),exclude:external_exports.array(relativePathSchema("an exclude pattern",!0)).optional()}),recipePluginSchema=extensibleObject({bundle:relativePathSchema("the plugin bundle"),types:relativePathSchema("the plugin types file").optional()}),recipeRequirementsSchema=extensibleObject({plugins:external_exports.record(external_exports.string().min(1,"a plugin name must not be empty"),external_exports.string().min(1,"a version range must not be empty")).optional()});function createRecipeManifestSchema(check3=acceptAnyRef){return extensibleObject({formatVersion:formatVersionSchema,namespace:namespaceNameSchema,name:recipeNameSchema,version:semverVersionSchema,description:external_exports.string().optional(),submissions:submissionsSchema.optional(),depends:refListSchema("'depends'",check3).optional(),subscribes:refListSchema("'subscribes'",check3).optional(),contents:external_exports.array(recipeContentSchema).default([]),variables:external_exports.array(variableDefinitionSchema).superRefine((definitions,ctx)=>{let seenNames=new Set,seenEnv=new Map;definitions.forEach((definition,index)=>{if(seenNames.has(definition.name)&&ctx.addIssue({code:"custom",path:[index,"name"],message:`the variable '${definition.name}' is defined more than once`}),seenNames.add(definition.name),definition.env!==void 0){let first2=seenEnv.get(definition.env);first2!==void 0?ctx.addIssue({code:"custom",path:[index,"env"],message:`the environment variable '${definition.env}' is already claimed by variables[${first2}]; two definitions cannot share one environment variable`}):seenEnv.set(definition.env,index)}})}).optional(),plugin:recipePluginSchema.optional(),requires:recipeRequirementsSchema.optional()})}function acceptAnyRef(ref){if(ref.trim().length===0)throw new Error("a ref must not be empty")}var recipeManifestSchema=createRecipeManifestSchema();function parseRecipeManifest(value,sourceLabel2,check3){let schema=check3===void 0?recipeManifestSchema:createRecipeManifestSchema(check3);return parseFormat(schema,value,sourceLabel2,"recipe manifest")}var repoNamespaceSchema=extensibleObject({description:external_exports.string().optional()}),recipePathSchema=relativePathSchema("a recipe path"),repoManifestSchema=extensibleObject({formatVersion:formatVersionSchema,name:repoNameSchema,description:external_exports.string().optional(),contribute:external_exports.string().min(1,"must not be empty").optional(),submissions:submissionsSchema.optional(),namespaces:external_exports.record(namespaceNameSchema,repoNamespaceSchema),recipes:external_exports.array(recipePathSchema).superRefine((paths,ctx)=>{let seen=new Set;paths.forEach((entry,index)=>{seen.has(entry)&&ctx.addIssue({code:"custom",path:[index],message:`the recipe path '${entry}' is listed more than once`}),seen.add(entry)})})});function parseRepoManifest(value,sourceLabel2){return parseFormat(repoManifestSchema,value,sourceLabel2,"repo manifest")}function unreadable(filePath,label,error51){let reason=error51.code==="ENOENT"?"does not exist":"could not be read";return new ConfigError18(`The ${label} at ${filePath} ${reason}.
852
853
  ${error51.message}`)}function describeOffset(text,offset2){let before=text.slice(0,offset2),line=before.split(`
@@ -858,14 +859,14 @@ From `+this.originalError.stack)}static is(obj){return obj?.[TRAIT]==="LiquidErr
858
859
  A manifest is written as ${MANIFEST_EXTENSIONS.join(", ")}. Manifests are never JavaScript, because a manifest is data that sous reads, validates and browses without executing anything, including before the repository is trusted.`)}function isFile3(candidate){try{return fs14.statSync(candidate).isFile()}catch{return!1}}function findManifest(directory,baseName,label){let found=[];for(let extension of MANIFEST_EXTENSIONS){let candidate=path20.join(directory,`${baseName}${extension}`);isFile3(candidate)&&found.push(candidate)}if(found.length>1){let names2=found.map(entry=>path20.basename(entry)).join(", ");throw new ConfigError18(`Found more than one ${label} in ${directory}: ${names2}.
859
860
  A directory holds exactly one ${label}. Remove the copies you do not want, so it is never ambiguous which one sous reads.`)}return found[0]}function missingRepoManifestMessage(repoRoot){return`No repo manifest in ${repoRoot}.
860
861
  A sous repository declares itself with a '${REPO_MANIFEST_BASENAME}${MANIFEST_EXTENSIONS[0]}' file at its root.`}function missingRecipeManifestMessage(recipeDir){return`No recipe manifest in ${recipeDir}.
861
- Every directory listed under 'recipes' in a repo manifest holds a '${RECIPE_MANIFEST_BASENAME}${MANIFEST_EXTENSIONS[0]}' file.`}function createManifests(deps={}){let baseName=kind=>kind==="recipe"?RECIPE_MANIFEST_BASENAME:REPO_MANIFEST_BASENAME,label=kind=>kind==="recipe"?"recipe manifest":"repo manifest",find2=(directory,kind)=>findManifest(directory,baseName(kind),label(kind));async function read(directory,kind,parse6){let file2=find2(directory,kind);if(file2!==void 0)return{path:file2,manifest:parse6(await readManifestFile(file2),file2)}}let readRecipe2=directory=>read(directory,"recipe",(value,source)=>parseRecipeManifest(value,source,deps.checkRef)),readRepo=directory=>read(directory,"repo",(value,source)=>parseRepoManifest(value,source));async function require_(directory,kind,reader){let found=await reader(directory);if(found!==void 0)return found;let message2=kind==="recipe"?missingRecipeManifestMessage(directory):missingRepoManifestMessage(directory);throw new NotFoundError4(label(kind),directory,message2)}return{find:find2,readRecipe:readRecipe2,readRepo,requireRecipe:directory=>require_(directory,"recipe",readRecipe2),requireRepo:directory=>require_(directory,"repo",readRepo),parseText:(text,fileName)=>parseManifestText(text,fileName),readFile:filePath=>readManifestFile(filePath)}}function parseManifestText(text,fileName){let extension=path20.extname(fileName).toLowerCase();if(extension===".yaml"||extension===".yml")return parseYamlText2(text,fileName);if(extension===".json"||extension===".jsonc")return parseJsoncText2(text,fileName);throw notAManifestFormat(fileName,extension)}async function readManifestFile(filePath){let text;try{text=await fsPromises.readFile(filePath,"utf8")}catch(error51){throw unreadable(filePath,"manifest",error51)}return parseManifestText(text,filePath)}function namespaceOfKey(key){let slash=key.indexOf("/");return slash===-1?key:key.slice(0,slash)}var indexDependencySchema=forwardCompatibleObject({version:semverVersionSchema.optional(),range:semverRangeSchema.optional(),repo:repoIdentitySchema.optional(),declared:external_exports.string().min(1,"must not be empty").optional(),kind:dependencyKindSchema.optional()}).refine(entry=>entry.version!==void 0||entry.range!==void 0,{message:"must record either the exact version this dependency resolved to or the range the recipe declared"}),indexVersionSchema=forwardCompatibleObject({hash:contentHashSchema,tag:external_exports.string().min(1,"must not be empty"),prerelease:external_exports.boolean(),seeded:external_exports.boolean().optional(),releasedAt:isoTimestampSchema.optional(),dependencies:external_exports.record(recipeKeySchema,indexDependencySchema).optional(),variables:external_exports.array(publishedVariableDefinitionSchema).optional(),depends:external_exports.array(external_exports.string().min(1,"must not be empty")).optional(),subscribes:external_exports.array(external_exports.string().min(1,"must not be empty")).optional()}),indexRecipeSchema=forwardCompatibleObject({path:relativePathSchema("a recipe path"),description:external_exports.string().optional(),versions:external_exports.record(semverVersionSchema,indexVersionSchema).refine(versions=>Object.keys(versions).length>0,{message:"must list at least one published version"})}),indexNamespaceSchema=forwardCompatibleObject({description:external_exports.string().optional()}),indexFileSchema=forwardCompatibleObject({$comment:external_exports.string().optional(),formatVersion:formatVersionSchema,name:repoNameSchema,generatedAt:isoTimestampSchema,generator:semverVersionSchema,namespaces:external_exports.record(namespaceNameSchema,indexNamespaceSchema),recipes:external_exports.record(recipeKeySchema,indexRecipeSchema)}).superRefine((index,ctx)=>{for(let key of Object.keys(index.recipes)){let namespace=namespaceOfKey(key);Object.hasOwn(index.namespaces,namespace)||ctx.addIssue({code:"custom",path:["recipes",key],message:`belongs to the namespace '${namespace}', which this index does not declare under 'namespaces'`})}for(let[key,recipe]of Object.entries(index.recipes))for(let[version2,published]of Object.entries(recipe.versions)){let expected=`${key}@${version2}`;published.tag!==expected&&ctx.addIssue({code:"custom",path:["recipes",key,"versions",version2,"tag"],message:`is '${published.tag}', but a published version's tag names the recipe and the version it carries, so this one must be '${expected}'`})}});var LINK_ORIGINS=["clone","path"],repoLinkSchema=external_exports.strictObject({path:absolutePathSchema,linkedAt:isoTimestampSchema,origin:external_exports.enum(LINK_ORIGINS)}),linksMapSchema=external_exports.strictObject({formatVersion:formatVersionSchema,links:external_exports.record(repoNameSchema,repoLinkSchema)});function createEmptyLinksMap(){return{formatVersion:1,links:{}}}var LOCK_KINDS=DEPENDENCY_KINDS,lockedRepoSchema=external_exports.strictObject({url:repoUrlSchema,identity:repoIdentitySchema.optional(),indexHash:contentHashSchema.optional()}),lockedRecipeSchema=external_exports.strictObject({repo:repoNameSchema,version:semverVersionSchema,hash:contentHashSchema,requestedBy:external_exports.array(external_exports.string().min(1,"must not be empty")).min(1,"must name at least one holder"),kind:external_exports.enum(LOCK_KINDS)}),lockfileSchema=external_exports.strictObject({formatVersion:formatVersionSchema,repos:external_exports.record(repoNameSchema,lockedRepoSchema),recipes:external_exports.record(recipeKeySchema,lockedRecipeSchema)}).superRefine((lock,ctx)=>{for(let[key,entry]of Object.entries(lock.recipes))Object.hasOwn(lock.repos,entry.repo)||ctx.addIssue({code:"custom",path:["recipes",key,"repo"],message:`names the repo '${entry.repo}', which this lockfile does not describe under 'repos'`})});function createEmptyLockfile(){return{formatVersion:1,repos:{},recipes:{}}}var storeEntrySchema=external_exports.strictObject({formatVersion:formatVersionSchema,repo:repoIdentitySchema,namespace:namespaceNameSchema,name:recipeNameSchema,version:semverVersionSchema,hash:contentHashSchema,fetchedAt:isoTimestampSchema,lastAccessAt:isoTimestampSchema,sizeBytes:byteCountSchema,statFingerprint:external_exports.string().min(1).optional()});function readOnly(label,schema,fileName){return{label,...fileName===void 0?{}:{fileName},parse:(value,sourceLabel2)=>parseFormat(schema,value,sourceLabel2,label),check:(value,sourceLabel2)=>{let result=checkFormat(schema,value);return result.issues===void 0?{value:result.value}:{issues:[`Invalid ${label} at ${sourceLabel2}:`,...result.issues]}}}}function writable(label,schema,fileName,empty){return{...readOnly(label,schema,fileName),stringify:stableJsonStringify,empty}}var lockfileFormat=writable("lockfile",lockfileSchema,LOCKFILE_FILENAME,createEmptyLockfile),linksMapFormat=writable("links map",linksMapSchema,LINKS_FILENAME,createEmptyLinksMap),indexFileFormat=writable("index file",indexFileSchema,INDEX_FILENAME,()=>({formatVersion:1,name:"",generatedAt:new Date(0).toISOString(),generator:"",namespaces:{},recipes:{}})),storeEntryFormat=writable("store entry",storeEntrySchema,STORE_ENTRY_FILENAME,()=>({formatVersion:1,repo:"",namespace:"",name:"",version:"",hash:`sha256-${"0".repeat(64)}`,fetchedAt:new Date(0).toISOString(),lastAccessAt:new Date(0).toISOString(),sizeBytes:0})),repoManifestFormat=readOnly("repo manifest",repoManifestSchema),variableDefinitionFormat=readOnly("variable definition",variableDefinitionSchema);function createRecipeManifestFormat(checkRef){return readOnly("recipe manifest",createRecipeManifestSchema(checkRef))}import{createHash as createHash3}from"node:crypto";import fsSync from"node:fs";import fs15 from"node:fs/promises";import path21 from"node:path";var GIT_DIR_NAME=".git",FIELD_SEPARATOR=Buffer.from([0]);async function collectFiles(dir,prefix=""){let entries=await fs15.readdir(dir,{withFileTypes:!0}),found=[];for(let entry of entries){if(entry.name===GIT_DIR_NAME||entry.name===STORE_ENTRY_FILENAME||entry.isSymbolicLink())continue;let relative4=prefix.length>0?`${prefix}/${entry.name}`:entry.name,absolute=path21.join(dir,entry.name);entry.isDirectory()?found.push(...await collectFiles(absolute,relative4)):entry.isFile()&&found.push(relative4)}return found}function bytewiseCompare(a,b){return a<b?-1:a>b?1:0}async function hashDirectory(dir){let root=path21.resolve(dir),files=(await collectFiles(root)).sort(bytewiseCompare),hash2=createHash3("sha256");for(let relative4 of files)updateWithFile(hash2,relative4,await fs15.readFile(path21.join(root,...relative4.split("/"))));return`sha256-${hash2.digest("hex")}`}function hashDirectorySync(dir){let root=path21.resolve(dir),files=collectFilesSync(root).sort(bytewiseCompare),hash2=createHash3("sha256");for(let relative4 of files)updateWithFile(hash2,relative4,fsSync.readFileSync(path21.join(root,...relative4.split("/"))));return`sha256-${hash2.digest("hex")}`}function collectFilesSync(dir,prefix=""){let entries=fsSync.readdirSync(dir,{withFileTypes:!0}),found=[];for(let entry of entries){if(entry.name===GIT_DIR_NAME||entry.name===STORE_ENTRY_FILENAME||entry.isSymbolicLink())continue;let relative4=prefix.length>0?`${prefix}/${entry.name}`:entry.name,absolute=path21.join(dir,entry.name);entry.isDirectory()?found.push(...collectFilesSync(absolute,relative4)):entry.isFile()&&found.push(relative4)}return found}function updateWithFile(hash2,relative4,bytes){hash2.update(Buffer.from(relative4,"utf8")),hash2.update(FIELD_SEPARATOR),hash2.update(Buffer.from(String(bytes.byteLength),"utf8")),hash2.update(FIELD_SEPARATOR),hash2.update(bytes),hash2.update(FIELD_SEPARATOR)}function hashesEqual(a,b){return a.toLowerCase()===b.toLowerCase()}function isContentHash(text){return CONTENT_HASH_PATTERN.test(text)}var recipeHash={hashDirectory,hashDirectorySync,equal:hashesEqual,isHash:isContentHash};var package_default8={name:"@sous-io/plugin-formats",version:"1.0.11",description:"One parser per on-disk format, reading manifests, and the recipe content hash.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-refs":"workspace:*","jsonc-parser":"^3.3.1",semver:"^7.8.5",yaml:"^2.9.0",zod:"^4.4.3"},devDependencies:{"@sous-io/core":"workspace:*","@types/semver":"^7.8.0"},engines:{node:">=22"}};var PLUGIN_NAME7="@sous-io/plugin-formats";function manifestRefChecker(ctx){return ref=>{let resolver;try{resolver=ctx.services.get("refs.resolver")}catch(error51){if(error51 instanceof SousError14&&error51.message.includes("cannot be used while the config is being built"))return;throw error51}resolver.parse(ref,"manifest")}}var formatsPlugin=definePlugin8({name:PLUGIN_NAME7,version:package_default8.version,description:"One parser per on-disk format, reading manifests, and the recipe content hash.",dependsOn:{"@sous-io/plugin-refs":`^${package_default8.version}`},register(sous){let once={lifetime:"singleton"};sous.services.add("formats.lockfile",()=>lockfileFormat,once),sous.services.add("formats.repo-manifest",()=>repoManifestFormat,once),sous.services.add("formats.index-file",()=>indexFileFormat,once),sous.services.add("formats.links-map",()=>linksMapFormat,once),sous.services.add("formats.store-entry",()=>storeEntryFormat,once),sous.services.add("formats.variable-definition",()=>variableDefinitionFormat,once),sous.services.add("formats.recipe-hash",()=>recipeHash,once),sous.services.add("formats.recipe-manifest",(_config,ctx)=>createRecipeManifestFormat(manifestRefChecker(ctx)),once),sous.services.add("formats.manifests",(_config,ctx)=>createManifests({checkRef:manifestRefChecker(ctx)}),once)}});import{definePlugin as definePlugin9,jsonSchema as jsonSchema9}from"@sous-io/plugin-api";import{ConfigError as ConfigError19,formatIssuePath as formatIssuePath2}from"@sous-io/plugin-api";function formatPath2(path103){return path103.length===0?"(root)":formatIssuePath2(path103)}var ExpressionError=class extends ConfigError19{file;path;constructor(file2,path103,problem,options={}){let printed=typeof path103=="string"?path103:formatPath2(path103);super(`${printed} ${problem}`,{...options,details:[`in ${file2}`,...options.details??[]]}),this.file=file2,this.path=printed}};var QUALIFIED=/^\$(expr|if|elseif)(?::(.*))?$/s;function parseReservedKey(key){if(key==="$else")return{kind:"else",key};let match2=QUALIFIED.exec(key);if(!match2)return;let kind=match2[1],qualifier=match2[2];return kind==="expr"?{kind,key,language:qualifier}:{kind,key,name:qualifier}}function isReservedKey(key){return parseReservedKey(key)!==void 0}function isPlainObject3(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function isExpressionObject(value){return isPlainObject3(value)&&Object.keys(value).some(isReservedKey)}function hasExpressions(value){return Array.isArray(value)?value.some(hasExpressions):isPlainObject3(value)?isExpressionObject(value)||Object.values(value).some(hasExpressions):!1}function compareBytes(a,b){return Buffer.compare(Buffer.from(a,"utf8"),Buffer.from(b,"utf8"))}function chainOrder(keys){return[...keys].sort((a,b)=>a.name===void 0||b.name===void 0?a.name===b.name?0:a.name===void 0?-1:1:compareBytes(a.name,b.name))}import{ConfigError as ConfigError20}from"@sous-io/plugin-api";var LIQUID_LANGUAGE="liquid",LEFT="\0<",RIGHT=">\0",analyzerEngine;function analyzer(){return analyzerEngine??=new Liquid({outputDelimiterLeft:LEFT,outputDelimiterRight:RIGHT}),analyzerEngine}function createLiquidLanguage(){return{id:LIQUID_LANGUAGE,description:"Liquid expressions, as in a {% if %} condition (the default).",runsCode:!1,variables(expression,ctx){return guard(expression,ctx,()=>analyzer().globalVariablesSync(analyzer().parse(`${LEFT}${expression}${RIGHT}`)))},evaluate(expression,scope,ctx){return evaluateLiquid(expression,scope,ctx)}}}function evaluateLiquid(expression,scope,ctx){let engine=engineFor(ctx),used=guard(expression,ctx,()=>new Tokenizer(expression).readFilteredValue().filters.map(filter3=>filter3.name)),missing=[...new Set(used.filter(name=>!(name in engine.filters)))];if(missing.length>0)return{unknown:{variables:[],filters:missing}};let value=guard(expression,ctx,()=>engine.evalValueSync(expression,{...scope.vars,host:scope.host,env:scope.env}));return{value:toValue(value)}}function engineFor(ctx){let entities=ctx.entities??emptyEntities,cached2=engines.get(entities);if(cached2)return cached2;let engine=makeEngine(ctx,entities);return engines.set(entities,engine),engine}var engines=new WeakMap;function makeEngine(ctx,entities){let services=ctx.services??noServices;return createLiquidEngines({project:ctx.project,env:ctx.env??{},services,entities}).create({purpose:CONFIG_EXPRESSION_PURPOSE,secretNames:[],liquid:{strictFilters:!0}})}function guard(expression,ctx,run){try{return run()}catch(error51){if(error51 instanceof ConfigError20)throw error51;let reason=error51 instanceof Error?error51.message:String(error51);throw new ExpressionError(ctx.file,ctx.path,`holds the Liquid expression ${JSON.stringify(expression)}, which failed: ${reason}`,{cause:error51})}}var emptyEntities={get:()=>{},list:()=>[],has:()=>!1,describe:()=>[],kinds:()=>[]},noServices={get(name){throw new ConfigError20(`The service "${name}" is not available to config expressions.`)},has:()=>!1};function parseExpressionObject(object3,path103,file2){let exprKeys=[],ifs=[],elseifs=[],hasElse=!1,stray=[];for(let key of Object.keys(object3)){let reserved=parseReservedKey(key);reserved?reserved.kind==="expr"?exprKeys.push(reserved):reserved.kind==="else"?hasElse=!0:(reserved.kind==="if"?ifs:elseifs).push(reserved):stray.push(key)}let reservedKeys=Object.keys(object3).filter(key=>!stray.includes(key));if(stray.length>0)throw new ExpressionError(file2,path103,`mixes the expression key ${quote(reservedKeys[0])} with ${list(stray)}, which ${stray.length===1?"is":"are"} not one.`,{details:["An expression object holds only $expr, $if, $elseif and $else keys (with their qualifiers)."]});for(let key of[...ifs,...elseifs])if(key.name==="")throw new ExpressionError(file2,[...path103,key.key],"has an empty qualifier. Write a name after the colon, or leave the colon out.");if(exprKeys.length>0){if(exprKeys.length>1)throw new ExpressionError(file2,path103,`holds ${list(exprKeys.map(key2=>key2.key))}; write one.`);if(ifs.length>0||elseifs.length>0||hasElse)throw new ExpressionError(file2,path103,`holds ${quote(exprKeys[0].key)} together with ${list(reservedKeys.filter(key2=>key2!==exprKeys[0].key))}.`,{details:["$expr computes one value; $if, $elseif and $else choose between values. Use one or the other."]});let key=exprKeys[0];return{kind:"value",expression:expressionAt(object3[key.key],key.language,[...path103,key.key],file2)}}let keys=[...chainOrder(ifs),...chainOrder(elseifs)],branches=[];return keys.forEach((key,index)=>{let last2=index===keys.length-1;branches.push(...parseBranches(object3[key.key],[...path103,key.key],{last:last2,hasElse},file2))}),{kind:"chain",branches,otherwise:hasElse?{value:object3.$else,path:[...path103,"$else"]}:void 0}}function parseBranches(value,path103,place,file2){if(typeof value=="string")return[{condition:expressionAt(value,void 0,path103,file2),then:void 0}];if(Array.isArray(value))return value.map((item,index)=>{let itemPath=[...path103,index],branch2=typeof item=="string"?{condition:expressionAt(item,void 0,itemPath,file2),then:void 0}:parseBlock(item,itemPath,file2);return branch2.condition===void 0&&checkFallback(itemPath,index===value.length-1,place,file2),branch2});let branch=parseBlock(value,path103,file2);if(branch.condition===void 0)throw new ExpressionError(file2,path103,"has no expr. A branch block needs one; only an array item may leave it out, as a fallback.");return[branch]}function checkFallback(path103,lastItem,place,file2){if(place.hasElse)throw new ExpressionError(file2,path103,"is a fallback (an item with no expr), and the chain also has an $else. Keep one of them.");if(!lastItem||!place.last)throw new ExpressionError(file2,path103,"is a fallback (an item with no expr), which is only allowed as the last item of the last key in the chain.")}function parseBlock(value,path103,file2){if(!isPlainObject3(value))throw new ExpressionError(file2,path103,`is ${describe3(value)}. A branch is a string, a block with expr and then, or an array of those.`);let exprKeys=[],thenKeys=[],unknown2=[];for(let key of Object.keys(value))/^\$?expr(:.*)?$/s.test(key)?exprKeys.push(key):key==="then"||key==="$then"?thenKeys.push(key):unknown2.push(key);if(unknown2.length>0)throw new ExpressionError(file2,path103,`holds ${list(unknown2)}. A branch block holds only expr (or $expr) and then (or $then).`);if(exprKeys.length>1)throw new ExpressionError(file2,path103,`holds both ${list(exprKeys,"and")}. Write one.`);if(thenKeys.length>1)throw new ExpressionError(file2,path103,'holds both "then" and "$then". Write one.');if(exprKeys.length===0&&thenKeys.length===0)throw new ExpressionError(file2,path103,"is an empty branch block. Give it an expr, a then, or both.");let exprKey=exprKeys[0],thenKey=thenKeys[0],language=exprKey===void 0?void 0:qualifierOf(exprKey);return{condition:exprKey===void 0?void 0:expressionAt(value[exprKey],language,[...path103,exprKey],file2),then:thenKey===void 0?void 0:{value:value[thenKey],path:[...path103,thenKey]}}}function qualifierOf(key){let colon=key.indexOf(":");return colon===-1?void 0:key.slice(colon+1)}function expressionAt(value,language,path103,file2){if(language==="")throw new ExpressionError(file2,path103,"has an empty language qualifier. Name the language after the colon, or leave the colon out.");if(typeof value!="string")throw new ExpressionError(file2,path103,`is ${describe3(value)}. An expression is a string.`);return{language,source:value,path:path103}}function describe3(value){return value===null?"null":Array.isArray(value)?"an array":typeof value=="object"?"an object":`a ${typeof value} (${JSON.stringify(value)})`}function quote(key){return JSON.stringify(key)}function list(keys,join4="and"){let quoted=keys.map(quote);return quoted.length<=1?quoted.join(""):`${quoted.slice(0,-1).join(", ")} ${join4} ${quoted.at(-1)}`}var BUILT_IN_NAMES=new Set(["host","env"]);function createEvaluator(deps){let byFile=new Map,stale=!1;return{evaluateLayer(data,options){stale&&(byFile.clear(),stale=!1);let run=new LayerRun(data,options,deps),value=run.evaluate();return byFile.set(options.file,{expressions:run.expressions,unsettled:run.unsettled}),{value,expressions:run.expressions,pending:run.unsettled.length>0}},isExpressionObject,hasExpressions,evaluations(file2){return file2!==void 0?[...byFile.get(file2)?.expressions??[]]:[...byFile.values()].flatMap(entry=>entry.expressions)},unsettled(){return[...byFile.values()].flatMap(entry=>entry.unsettled)},languages(){return deps.entities.list("expression-language").map(language=>language.id)},settle(){let open2=this.unsettled();if(stale=!0,open2.length>0)throw unsettledError(open2)}}}function unsettledError(open2){let[first2,...rest]=open2;return new ExpressionError(first2.file,first2.path,`${describeUnknown(first2.unknown)}.`,{details:rest.map(entry=>`${entry.path} ${describeUnknown(entry.unknown)} (in ${entry.file})`)})}function describeUnknown(unknown2){let parts=[];if(unknown2.variables.length>0){let one=unknown2.variables.length===1;parts.push(`reads ${names(unknown2.variables)}, which ${one?"is":"are"} not set anywhere in the config`)}if(unknown2.filters.length>0){let one=unknown2.filters.length===1;parts.push(`uses the Liquid filter${one?"":"s"} ${names(unknown2.filters)}, which no plugin adds`)}return parts.join(", and ")}function names(list2){return list2.join(", ")}function isTruthy2(value){return value!==!1&&value!==void 0&&value!==null}var LayerRun=class{constructor(data,options,deps){this.data=data;this.options=options;this.deps=deps;this.config=options.config,this.file=options.file,this.entities=builderEntities(options.config),this.lookup={get:path103=>options.config.atPath(path103).get()}}expressions=[];unsettled=[];config;file;entities;lookup;reads;unknown;evaluate(){return this.walk(this.data,[],{})}walk(value,path103,levelVars){if(Array.isArray(value)){let out2=[];return value.forEach((item,index)=>{let result=this.walk(item,[...path103,index],levelVars);result!==void 0&&out2.push(result)}),out2}if(!isPlainObject3(value))return value;if(isExpressionObject(value))return this.expressionObject(value,path103,levelVars);let inner=isScopeLevel(path103)?{...levelVars,...this.ownVarsOf(value,path103)}:levelVars,out={};for(let[key,child2]of Object.entries(value)){let result=this.walk(child2,[...path103,key],inner);result!==void 0&&(out[key]=result)}return out}ownVarsOf(object3,path103){if(path103.length===0&&this.options.ownVars)return this.options.ownVars;let block=object3._vars;return isPlainObject3(block)?Object.fromEntries(Object.entries(block).filter(entry=>typeof entry[1]=="string")):{}}expressionObject(object3,path103,levelVars){let outermost=this.reads===void 0;outermost&&(this.reads={},this.unknown=void 0);try{let plan=parseExpressionObject(object3,path103,this.file),value=this.evaluatePlan(plan,path103,levelVars);return outermost&&this.expressions.push({path:formatPath2(path103),written:object3,value,reads:this.reads,...this.unknown?{unknown:this.unknown}:{}}),value}finally{outermost&&(this.reads=void 0,this.unknown=void 0)}}evaluatePlan(plan,path103,levelVars){if(plan.kind==="value"){let outcome=this.run(plan.expression,path103,levelVars);return"unknown"in outcome?this.pending(path103,outcome.unknown):toJson(outcome.value)}for(let branch of plan.branches){if(branch.condition===void 0)return this.chosen(branch.then,path103,levelVars);let outcome=this.run(branch.condition,path103,levelVars);if("unknown"in outcome)return this.pending(path103,outcome.unknown);if(isTruthy2(outcome.value))return branch.then?this.chosen(branch.then,path103,levelVars):!0}return plan.otherwise?this.chosen(plan.otherwise,path103,levelVars):void 0}chosen(written,path103,levelVars){return this.walk(written.value,path103,levelVars)}pending(path103,unknown2){this.unknown=unknown2,this.unsettled.push({file:this.file,path:formatPath2(path103),unknown:unknown2})}run(expression,path103,levelVars){let language=this.language(expression),ctx={project:this.deps.project,file:this.file,path:formatPath2(expression.path),env:this.config.env,entities:this.entities,services:this.deps.services},variables=[...new Set(language.variables(expression.source,ctx))].filter(name=>!BUILT_IN_NAMES.has(name));this.checkForbidden(variables,path103);let vars=variables.length>0?this.scope(path103,levelVars):levelVars,missing=[];for(let name of variables){let known=Object.hasOwn(vars,name);this.reads[name]=known?vars[name]:void 0,known||missing.push(name)}return missing.length>0?{unknown:{variables:missing,filters:[]}}:language.evaluate(expression.source,{host:{platform:this.deps.platform??process.platform},env:this.config.env,vars},ctx)}language(expression){let id=expression.language??LIQUID_LANGUAGE,languages=this.config.entities("expression-language"),language=languages.find(entry=>entry.id===id);if(!language){let known=languages.map(entry=>entry.id).join(", ")||"none";throw new ExpressionError(this.file,expression.path,`uses the expression language "${id}", which sous does not know. Known languages: ${known}.`)}if(this.options.fromRecipe&&language.runsCode){let allowed=languages.filter(entry=>!entry.runsCode).map(entry=>entry.id).join(", ")||"none";throw new ExpressionError(this.file,expression.path,`uses the expression language "${id}", which runs code. A recipe's config file may only use languages that do not (${allowed}).`)}return language}scope(path103,levelVars){if(!this.deps.services.has("variables.resolver"))return levelVars;let resolver=this.deps.services.get("variables.resolver"),level=path103[0]==="compilation"?"compilation":"root";return resolver.scopeIn(this.config,{level,extra:levelVars})}checkForbidden(variables,path103){let top=path103[0];if(!(variables.length===0||typeof top!="string"))for(let source of this.config.entities("variable-source")){if(!source.forbiddenUnder?.includes(top))continue;let given=source.variables({project:this.deps.project,env:this.config.env,config:this.lookup}),read=variables.find(name=>Object.hasOwn(given,name));if(read!==void 0)throw new ExpressionError(this.file,path103,forbiddenProblem(read,source))}}};function forbiddenProblem(name,source){let under=source.forbiddenUnder.map(key=>`"${key}"`).join(" or ");return source.description==="recipe answers"?`reads ${name}, which is an answer to a recipe. An expression that decides which recipes are subscribed or pinned (anything under ${under}) cannot read recipe answers.`:`reads ${name}, which comes from ${source.description}. An expression under ${under} cannot read ${source.description}.`}function isScopeLevel(path103){return path103.length===0?!0:path103[0]!=="compilation"?!1:path103.length===1||path103.length===3&&path103[1]==="targets"&&typeof path103[2]=="number"||path103.length===5&&path103[1]==="targets"&&typeof path103[2]=="number"&&path103[3]==="outputs"&&typeof path103[4]=="number"}function toJson(value){if(value==null||typeof value=="string"||typeof value=="boolean")return value;if(typeof value=="number")return Number.isFinite(value)?value:null;if(Array.isArray(value))return value.map(toJson).filter(item=>item!==void 0);if(isPlainObject3(value)&&Object.getPrototypeOf(value)===Object.prototype){let out={};for(let[key,item]of Object.entries(value)){let json3=toJson(item);json3!==void 0&&(out[key]=json3)}return out}if(!(typeof value=="function"||typeof value=="symbol"))return String(value)}function builderEntities(config2){return{get:(kind,id)=>config2.entity(kind,id),list:kind=>config2.entities(kind),has:(kind,id)=>config2.entity(kind,id)!==void 0,describe:kind=>config2.entities(kind).map(entry=>({kind,id:entry.id,entry,plugin:"a plugin"})),kinds:()=>[]}}var package_default9={name:"@sous-io/plugin-expressions",version:"1.0.11",description:"Config expressions (S5) and the expression languages plugins add.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-liquid":"workspace:*","@sous-io/plugin-variables":"workspace:*",liquidjs:"^10.25.0"},devDependencies:{"@sous-io/core":"workspace:*","@sous-io/plugin-host":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME8="@sous-io/plugin-expressions",expressionsPlugin=definePlugin9({name:PLUGIN_NAME8,version:package_default9.version,description:"Config expressions and the expression languages plugins add.",dependsOn:{"@sous-io/plugin-liquid":`^${package_default9.version}`,"@sous-io/plugin-variables":`^${package_default9.version}`},register(sous){sous.entities.define("expression-language",jsonSchema9({type:"object",properties:{id:{type:"string"},description:{type:"string"},runsCode:{type:"boolean"}},required:["id","variables","evaluate"]}),{description:"A language config expressions are written in, named after $expr: or expr:."}),sous.entities.add("expression-language",createLiquidLanguage());let evaluator=createEvaluator({services:sous.services,entities:sous.entities,get project(){return sous.project}});sous.services.add("expressions.evaluator",()=>evaluator,{lifetime:"singleton"}),sous.on("config.built",()=>evaluator.settle())}});import fs18 from"node:fs";import{ConfigError as ConfigError22,definePlugin as definePlugin10}from"@sous-io/plugin-api";import fs16 from"node:fs";import path22 from"node:path";var CONTRIBUTOR_PREFIX="confd/",MANAGED_NAME=/^5\d\d-/;function isManagedName(name){return MANAGED_NAME.test(name)}function contributorId(name){return`${CONTRIBUTOR_PREFIX}${name}`}function listConfdFiles(confDir,loader,compare){if(confDir===void 0)return[];let names2;try{names2=fs16.readdirSync(confDir)}catch{return[]}let files=[];for(let name of[...names2].sort(compare)){let format3=loader.formatOf(name),full=path22.join(confDir,name);format3===void 0||!isFile4(full)||files.push({name,path:full,format:format3,contributor:contributorId(name),managed:isManagedName(name)})}return files}function duplicateBaseNames(names2){let byBase=new Map;for(let name of names2){let dot=name.lastIndexOf("."),base=dot<=0?name:name.slice(0,dot);byBase.set(base,[...byBase.get(base)??[],name])}return[...byBase.values()].filter(group=>group.length>1)}var ConfdFilesImpl=class{constructor(confDir,loader,compare){this.confDir=confDir;this.loader=loader;this.compare=compare}directory(){return this.confDir}list(){return listConfdFiles(this.confDir,this.loader,this.compare)}};function isFile4(file2){try{return fs16.statSync(file2).isFile()}catch{return!1}}init_src();import fs17 from"node:fs";import path23 from"node:path";import{ConfigError as ConfigError21}from"@sous-io/plugin-api";var MANAGED_FILE_COMMENT="This file is managed by sous. Sous edits these files by key; you may edit them too, and your comments, key order and formatting are kept.",FORMAT_NOTE=["It is JSON with comments (.jsonc): line comments, block comments and trailing","commas are all allowed here."],DESCRIPTIONS={"500-repos.jsonc":["It records the repositories this project trusts. The 'sous repo add' and","'sous repo remove' commands write the entries under 'repos'."],"510-subscriptions.jsonc":["It records what this project subscribes to. The 'sous subscription add' and","'sous subscription remove' commands write the entries under 'subscriptions'."]};function wrap2(text,width=78){let lines3=[],current="";for(let word of text.split(/\s+/))current.length===0?current=word:`${current} ${word}`.length+3<=width?current=`${current} ${word}`:(lines3.push(current),current=word);return current.length>0&&lines3.push(current),lines3}function managedHeader(name,description){let what=description.length>0?description:DESCRIPTIONS[name]??[];return`${[wrap2(MANAGED_FILE_COMMENT),what,FORMAT_NOTE].filter(block=>block.length>0).map(block=>block.map(line=>`// ${line}`.trimEnd()).join(`
862
+ Every directory listed under 'recipes' in a repo manifest holds a '${RECIPE_MANIFEST_BASENAME}${MANIFEST_EXTENSIONS[0]}' file.`}function createManifests(deps={}){let baseName=kind=>kind==="recipe"?RECIPE_MANIFEST_BASENAME:REPO_MANIFEST_BASENAME,label=kind=>kind==="recipe"?"recipe manifest":"repo manifest",find2=(directory,kind)=>findManifest(directory,baseName(kind),label(kind));async function read(directory,kind,parse6){let file2=find2(directory,kind);if(file2!==void 0)return{path:file2,manifest:parse6(await readManifestFile(file2),file2)}}let readRecipe2=directory=>read(directory,"recipe",(value,source)=>parseRecipeManifest(value,source,deps.checkRef)),readRepo=directory=>read(directory,"repo",(value,source)=>parseRepoManifest(value,source));async function require_(directory,kind,reader){let found=await reader(directory);if(found!==void 0)return found;let message2=kind==="recipe"?missingRecipeManifestMessage(directory):missingRepoManifestMessage(directory);throw new NotFoundError4(label(kind),directory,message2)}return{find:find2,readRecipe:readRecipe2,readRepo,requireRecipe:directory=>require_(directory,"recipe",readRecipe2),requireRepo:directory=>require_(directory,"repo",readRepo),parseText:(text,fileName)=>parseManifestText(text,fileName),readFile:filePath=>readManifestFile(filePath)}}function parseManifestText(text,fileName){let extension=path20.extname(fileName).toLowerCase();if(extension===".yaml"||extension===".yml")return parseYamlText2(text,fileName);if(extension===".json"||extension===".jsonc")return parseJsoncText2(text,fileName);throw notAManifestFormat(fileName,extension)}async function readManifestFile(filePath){let text;try{text=await fsPromises.readFile(filePath,"utf8")}catch(error51){throw unreadable(filePath,"manifest",error51)}return parseManifestText(text,filePath)}function namespaceOfKey(key){let slash=key.indexOf("/");return slash===-1?key:key.slice(0,slash)}var indexDependencySchema=forwardCompatibleObject({version:semverVersionSchema.optional(),range:semverRangeSchema.optional(),repo:repoIdentitySchema.optional(),declared:external_exports.string().min(1,"must not be empty").optional(),kind:dependencyKindSchema.optional()}).refine(entry=>entry.version!==void 0||entry.range!==void 0,{message:"must record either the exact version this dependency resolved to or the range the recipe declared"}),indexVersionSchema=forwardCompatibleObject({hash:contentHashSchema,tag:external_exports.string().min(1,"must not be empty"),prerelease:external_exports.boolean(),seeded:external_exports.boolean().optional(),releasedAt:isoTimestampSchema.optional(),dependencies:external_exports.record(recipeKeySchema,indexDependencySchema).optional(),variables:external_exports.array(publishedVariableDefinitionSchema).optional(),depends:external_exports.array(external_exports.string().min(1,"must not be empty")).optional(),subscribes:external_exports.array(external_exports.string().min(1,"must not be empty")).optional()}),indexRecipeSchema=forwardCompatibleObject({path:relativePathSchema("a recipe path"),description:external_exports.string().optional(),versions:external_exports.record(semverVersionSchema,indexVersionSchema).refine(versions=>Object.keys(versions).length>0,{message:"must list at least one published version"})}),indexNamespaceSchema=forwardCompatibleObject({description:external_exports.string().optional()}),indexFileSchema=forwardCompatibleObject({$comment:external_exports.string().optional(),formatVersion:formatVersionSchema,name:repoNameSchema,generatedAt:isoTimestampSchema,generator:semverVersionSchema,namespaces:external_exports.record(namespaceNameSchema,indexNamespaceSchema),recipes:external_exports.record(recipeKeySchema,indexRecipeSchema)}).superRefine((index,ctx)=>{for(let key of Object.keys(index.recipes)){let namespace=namespaceOfKey(key);Object.hasOwn(index.namespaces,namespace)||ctx.addIssue({code:"custom",path:["recipes",key],message:`belongs to the namespace '${namespace}', which this index does not declare under 'namespaces'`})}for(let[key,recipe]of Object.entries(index.recipes))for(let[version2,published]of Object.entries(recipe.versions)){let expected=`${key}@${version2}`;published.tag!==expected&&ctx.addIssue({code:"custom",path:["recipes",key,"versions",version2,"tag"],message:`is '${published.tag}', but a published version's tag names the recipe and the version it carries, so this one must be '${expected}'`})}});var LINK_ORIGINS=["clone","path"],repoLinkSchema=external_exports.strictObject({path:absolutePathSchema,linkedAt:isoTimestampSchema,origin:external_exports.enum(LINK_ORIGINS)}),linksMapSchema=external_exports.strictObject({formatVersion:formatVersionSchema,links:external_exports.record(repoNameSchema,repoLinkSchema)});function createEmptyLinksMap(){return{formatVersion:1,links:{}}}var LOCK_KINDS=DEPENDENCY_KINDS,lockedRepoSchema=external_exports.strictObject({url:repoUrlSchema,identity:repoIdentitySchema.optional(),indexHash:contentHashSchema.optional()}),lockedRecipeSchema=external_exports.strictObject({repo:repoNameSchema,version:semverVersionSchema,hash:contentHashSchema,requestedBy:external_exports.array(external_exports.string().min(1,"must not be empty")).min(1,"must name at least one holder"),kind:external_exports.enum(LOCK_KINDS)}),lockfileSchema=external_exports.strictObject({formatVersion:formatVersionSchema,repos:external_exports.record(repoNameSchema,lockedRepoSchema),recipes:external_exports.record(recipeKeySchema,lockedRecipeSchema)}).superRefine((lock,ctx)=>{for(let[key,entry]of Object.entries(lock.recipes))Object.hasOwn(lock.repos,entry.repo)||ctx.addIssue({code:"custom",path:["recipes",key,"repo"],message:`names the repo '${entry.repo}', which this lockfile does not describe under 'repos'`})});function createEmptyLockfile(){return{formatVersion:1,repos:{},recipes:{}}}var storeEntrySchema=external_exports.strictObject({formatVersion:formatVersionSchema,repo:repoIdentitySchema,namespace:namespaceNameSchema,name:recipeNameSchema,version:semverVersionSchema,hash:contentHashSchema,fetchedAt:isoTimestampSchema,lastAccessAt:isoTimestampSchema,sizeBytes:byteCountSchema,statFingerprint:external_exports.string().min(1).optional()});function readOnly(label,schema,fileName){return{label,...fileName===void 0?{}:{fileName},parse:(value,sourceLabel2)=>parseFormat(schema,value,sourceLabel2,label),check:(value,sourceLabel2)=>{let result=checkFormat(schema,value);return result.issues===void 0?{value:result.value}:{issues:[`Invalid ${label} at ${sourceLabel2}:`,...result.issues]}}}}function writable(label,schema,fileName,empty){return{...readOnly(label,schema,fileName),stringify:stableJsonStringify,empty}}var lockfileFormat=writable("lockfile",lockfileSchema,LOCKFILE_FILENAME,createEmptyLockfile),linksMapFormat=writable("links map",linksMapSchema,LINKS_FILENAME,createEmptyLinksMap),indexFileFormat=writable("index file",indexFileSchema,INDEX_FILENAME,()=>({formatVersion:1,name:"",generatedAt:new Date(0).toISOString(),generator:"",namespaces:{},recipes:{}})),storeEntryFormat=writable("store entry",storeEntrySchema,STORE_ENTRY_FILENAME,()=>({formatVersion:1,repo:"",namespace:"",name:"",version:"",hash:`sha256-${"0".repeat(64)}`,fetchedAt:new Date(0).toISOString(),lastAccessAt:new Date(0).toISOString(),sizeBytes:0})),repoManifestFormat=readOnly("repo manifest",repoManifestSchema),variableDefinitionFormat=readOnly("variable definition",variableDefinitionSchema);function createRecipeManifestFormat(checkRef){return readOnly("recipe manifest",createRecipeManifestSchema(checkRef))}import{createHash as createHash3}from"node:crypto";import fsSync from"node:fs";import fs15 from"node:fs/promises";import path21 from"node:path";var GIT_DIR_NAME=".git",FIELD_SEPARATOR=Buffer.from([0]);async function collectFiles(dir,prefix=""){let entries=await fs15.readdir(dir,{withFileTypes:!0}),found=[];for(let entry of entries){if(entry.name===GIT_DIR_NAME||entry.name===STORE_ENTRY_FILENAME||entry.isSymbolicLink())continue;let relative4=prefix.length>0?`${prefix}/${entry.name}`:entry.name,absolute=path21.join(dir,entry.name);entry.isDirectory()?found.push(...await collectFiles(absolute,relative4)):entry.isFile()&&found.push(relative4)}return found}function bytewiseCompare(a,b){return a<b?-1:a>b?1:0}async function hashDirectory(dir){let root=path21.resolve(dir),files=(await collectFiles(root)).sort(bytewiseCompare),hash2=createHash3("sha256");for(let relative4 of files)updateWithFile(hash2,relative4,await fs15.readFile(path21.join(root,...relative4.split("/"))));return`sha256-${hash2.digest("hex")}`}function hashDirectorySync(dir){let root=path21.resolve(dir),files=collectFilesSync(root).sort(bytewiseCompare),hash2=createHash3("sha256");for(let relative4 of files)updateWithFile(hash2,relative4,fsSync.readFileSync(path21.join(root,...relative4.split("/"))));return`sha256-${hash2.digest("hex")}`}function collectFilesSync(dir,prefix=""){let entries=fsSync.readdirSync(dir,{withFileTypes:!0}),found=[];for(let entry of entries){if(entry.name===GIT_DIR_NAME||entry.name===STORE_ENTRY_FILENAME||entry.isSymbolicLink())continue;let relative4=prefix.length>0?`${prefix}/${entry.name}`:entry.name,absolute=path21.join(dir,entry.name);entry.isDirectory()?found.push(...collectFilesSync(absolute,relative4)):entry.isFile()&&found.push(relative4)}return found}function updateWithFile(hash2,relative4,bytes){hash2.update(Buffer.from(relative4,"utf8")),hash2.update(FIELD_SEPARATOR),hash2.update(Buffer.from(String(bytes.byteLength),"utf8")),hash2.update(FIELD_SEPARATOR),hash2.update(bytes),hash2.update(FIELD_SEPARATOR)}function hashesEqual(a,b){return a.toLowerCase()===b.toLowerCase()}function isContentHash(text){return CONTENT_HASH_PATTERN.test(text)}var recipeHash={hashDirectory,hashDirectorySync,equal:hashesEqual,isHash:isContentHash};var package_default8={name:"@sous-io/plugin-formats",version:"1.0.12",description:"One parser per on-disk format, reading manifests, and the recipe content hash.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-refs":"workspace:*","jsonc-parser":"^3.3.1",semver:"^7.8.5",yaml:"^2.9.0",zod:"^4.4.3"},devDependencies:{"@sous-io/core":"workspace:*","@types/semver":"^7.8.0"},engines:{node:">=22"}};var PLUGIN_NAME7="@sous-io/plugin-formats";function manifestRefChecker(ctx){return ref=>{let resolver;try{resolver=ctx.services.get("refs.resolver")}catch(error51){if(error51 instanceof SousError14&&error51.message.includes("cannot be used while the config is being built"))return;throw error51}resolver.parse(ref,"manifest")}}var formatsPlugin=definePlugin8({name:PLUGIN_NAME7,version:package_default8.version,description:"One parser per on-disk format, reading manifests, and the recipe content hash.",dependsOn:{"@sous-io/plugin-refs":`^${package_default8.version}`},register(sous){let once={lifetime:"singleton"};sous.services.add("formats.lockfile",()=>lockfileFormat,once),sous.services.add("formats.repo-manifest",()=>repoManifestFormat,once),sous.services.add("formats.index-file",()=>indexFileFormat,once),sous.services.add("formats.links-map",()=>linksMapFormat,once),sous.services.add("formats.store-entry",()=>storeEntryFormat,once),sous.services.add("formats.variable-definition",()=>variableDefinitionFormat,once),sous.services.add("formats.recipe-hash",()=>recipeHash,once),sous.services.add("formats.recipe-manifest",(_config,ctx)=>createRecipeManifestFormat(manifestRefChecker(ctx)),once),sous.services.add("formats.manifests",(_config,ctx)=>createManifests({checkRef:manifestRefChecker(ctx)}),once)}});import{definePlugin as definePlugin9,jsonSchema as jsonSchema9}from"@sous-io/plugin-api";import{ConfigError as ConfigError19,formatIssuePath as formatIssuePath2}from"@sous-io/plugin-api";function formatPath2(path103){return path103.length===0?"(root)":formatIssuePath2(path103)}var ExpressionError=class extends ConfigError19{file;path;constructor(file2,path103,problem,options={}){let printed=typeof path103=="string"?path103:formatPath2(path103);super(`${printed} ${problem}`,{...options,details:[`in ${file2}`,...options.details??[]]}),this.file=file2,this.path=printed}};var QUALIFIED=/^\$(expr|if|elseif)(?::(.*))?$/s;function parseReservedKey(key){if(key==="$else")return{kind:"else",key};let match2=QUALIFIED.exec(key);if(!match2)return;let kind=match2[1],qualifier=match2[2];return kind==="expr"?{kind,key,language:qualifier}:{kind,key,name:qualifier}}function isReservedKey(key){return parseReservedKey(key)!==void 0}function isPlainObject3(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function isExpressionObject(value){return isPlainObject3(value)&&Object.keys(value).some(isReservedKey)}function hasExpressions(value){return Array.isArray(value)?value.some(hasExpressions):isPlainObject3(value)?isExpressionObject(value)||Object.values(value).some(hasExpressions):!1}function compareBytes(a,b){return Buffer.compare(Buffer.from(a,"utf8"),Buffer.from(b,"utf8"))}function chainOrder(keys){return[...keys].sort((a,b)=>a.name===void 0||b.name===void 0?a.name===b.name?0:a.name===void 0?-1:1:compareBytes(a.name,b.name))}import{ConfigError as ConfigError20}from"@sous-io/plugin-api";var LIQUID_LANGUAGE="liquid",LEFT="\0<",RIGHT=">\0",analyzerEngine;function analyzer(){return analyzerEngine??=new Liquid({outputDelimiterLeft:LEFT,outputDelimiterRight:RIGHT}),analyzerEngine}function createLiquidLanguage(){return{id:LIQUID_LANGUAGE,description:"Liquid expressions, as in a {% if %} condition (the default).",runsCode:!1,variables(expression,ctx){return guard(expression,ctx,()=>analyzer().globalVariablesSync(analyzer().parse(`${LEFT}${expression}${RIGHT}`)))},evaluate(expression,scope,ctx){return evaluateLiquid(expression,scope,ctx)}}}function evaluateLiquid(expression,scope,ctx){let engine=engineFor(ctx),used=guard(expression,ctx,()=>new Tokenizer(expression).readFilteredValue().filters.map(filter3=>filter3.name)),missing=[...new Set(used.filter(name=>!(name in engine.filters)))];if(missing.length>0)return{unknown:{variables:[],filters:missing}};let value=guard(expression,ctx,()=>engine.evalValueSync(expression,{...scope.vars,host:scope.host,env:scope.env}));return{value:toValue(value)}}function engineFor(ctx){let entities=ctx.entities??emptyEntities,cached2=engines.get(entities);if(cached2)return cached2;let engine=makeEngine(ctx,entities);return engines.set(entities,engine),engine}var engines=new WeakMap;function makeEngine(ctx,entities){let services=ctx.services??noServices;return createLiquidEngines({project:ctx.project,env:ctx.env??{},services,entities}).create({purpose:CONFIG_EXPRESSION_PURPOSE,secretNames:[],liquid:{strictFilters:!0}})}function guard(expression,ctx,run){try{return run()}catch(error51){if(error51 instanceof ConfigError20)throw error51;let reason=error51 instanceof Error?error51.message:String(error51);throw new ExpressionError(ctx.file,ctx.path,`holds the Liquid expression ${JSON.stringify(expression)}, which failed: ${reason}`,{cause:error51})}}var emptyEntities={get:()=>{},list:()=>[],has:()=>!1,describe:()=>[],kinds:()=>[]},noServices={get(name){throw new ConfigError20(`The service "${name}" is not available to config expressions.`)},has:()=>!1};function parseExpressionObject(object3,path103,file2){let exprKeys=[],ifs=[],elseifs=[],hasElse=!1,stray=[];for(let key of Object.keys(object3)){let reserved=parseReservedKey(key);reserved?reserved.kind==="expr"?exprKeys.push(reserved):reserved.kind==="else"?hasElse=!0:(reserved.kind==="if"?ifs:elseifs).push(reserved):stray.push(key)}let reservedKeys=Object.keys(object3).filter(key=>!stray.includes(key));if(stray.length>0)throw new ExpressionError(file2,path103,`mixes the expression key ${quote(reservedKeys[0])} with ${list(stray)}, which ${stray.length===1?"is":"are"} not one.`,{details:["An expression object holds only $expr, $if, $elseif and $else keys (with their qualifiers)."]});for(let key of[...ifs,...elseifs])if(key.name==="")throw new ExpressionError(file2,[...path103,key.key],"has an empty qualifier. Write a name after the colon, or leave the colon out.");if(exprKeys.length>0){if(exprKeys.length>1)throw new ExpressionError(file2,path103,`holds ${list(exprKeys.map(key2=>key2.key))}; write one.`);if(ifs.length>0||elseifs.length>0||hasElse)throw new ExpressionError(file2,path103,`holds ${quote(exprKeys[0].key)} together with ${list(reservedKeys.filter(key2=>key2!==exprKeys[0].key))}.`,{details:["$expr computes one value; $if, $elseif and $else choose between values. Use one or the other."]});let key=exprKeys[0];return{kind:"value",expression:expressionAt(object3[key.key],key.language,[...path103,key.key],file2)}}let keys=[...chainOrder(ifs),...chainOrder(elseifs)],branches=[];return keys.forEach((key,index)=>{let last2=index===keys.length-1;branches.push(...parseBranches(object3[key.key],[...path103,key.key],{last:last2,hasElse},file2))}),{kind:"chain",branches,otherwise:hasElse?{value:object3.$else,path:[...path103,"$else"]}:void 0}}function parseBranches(value,path103,place,file2){if(typeof value=="string")return[{condition:expressionAt(value,void 0,path103,file2),then:void 0}];if(Array.isArray(value))return value.map((item,index)=>{let itemPath=[...path103,index],branch2=typeof item=="string"?{condition:expressionAt(item,void 0,itemPath,file2),then:void 0}:parseBlock(item,itemPath,file2);return branch2.condition===void 0&&checkFallback(itemPath,index===value.length-1,place,file2),branch2});let branch=parseBlock(value,path103,file2);if(branch.condition===void 0)throw new ExpressionError(file2,path103,"has no expr. A branch block needs one; only an array item may leave it out, as a fallback.");return[branch]}function checkFallback(path103,lastItem,place,file2){if(place.hasElse)throw new ExpressionError(file2,path103,"is a fallback (an item with no expr), and the chain also has an $else. Keep one of them.");if(!lastItem||!place.last)throw new ExpressionError(file2,path103,"is a fallback (an item with no expr), which is only allowed as the last item of the last key in the chain.")}function parseBlock(value,path103,file2){if(!isPlainObject3(value))throw new ExpressionError(file2,path103,`is ${describe3(value)}. A branch is a string, a block with expr and then, or an array of those.`);let exprKeys=[],thenKeys=[],unknown2=[];for(let key of Object.keys(value))/^\$?expr(:.*)?$/s.test(key)?exprKeys.push(key):key==="then"||key==="$then"?thenKeys.push(key):unknown2.push(key);if(unknown2.length>0)throw new ExpressionError(file2,path103,`holds ${list(unknown2)}. A branch block holds only expr (or $expr) and then (or $then).`);if(exprKeys.length>1)throw new ExpressionError(file2,path103,`holds both ${list(exprKeys,"and")}. Write one.`);if(thenKeys.length>1)throw new ExpressionError(file2,path103,'holds both "then" and "$then". Write one.');if(exprKeys.length===0&&thenKeys.length===0)throw new ExpressionError(file2,path103,"is an empty branch block. Give it an expr, a then, or both.");let exprKey=exprKeys[0],thenKey=thenKeys[0],language=exprKey===void 0?void 0:qualifierOf(exprKey);return{condition:exprKey===void 0?void 0:expressionAt(value[exprKey],language,[...path103,exprKey],file2),then:thenKey===void 0?void 0:{value:value[thenKey],path:[...path103,thenKey]}}}function qualifierOf(key){let colon=key.indexOf(":");return colon===-1?void 0:key.slice(colon+1)}function expressionAt(value,language,path103,file2){if(language==="")throw new ExpressionError(file2,path103,"has an empty language qualifier. Name the language after the colon, or leave the colon out.");if(typeof value!="string")throw new ExpressionError(file2,path103,`is ${describe3(value)}. An expression is a string.`);return{language,source:value,path:path103}}function describe3(value){return value===null?"null":Array.isArray(value)?"an array":typeof value=="object"?"an object":`a ${typeof value} (${JSON.stringify(value)})`}function quote(key){return JSON.stringify(key)}function list(keys,join4="and"){let quoted=keys.map(quote);return quoted.length<=1?quoted.join(""):`${quoted.slice(0,-1).join(", ")} ${join4} ${quoted.at(-1)}`}var BUILT_IN_NAMES=new Set(["host","env"]);function createEvaluator(deps){let byFile=new Map,stale=!1;return{evaluateLayer(data,options){stale&&(byFile.clear(),stale=!1);let run=new LayerRun(data,options,deps),value=run.evaluate();return byFile.set(options.file,{expressions:run.expressions,unsettled:run.unsettled}),{value,expressions:run.expressions,pending:run.unsettled.length>0}},isExpressionObject,hasExpressions,evaluations(file2){return file2!==void 0?[...byFile.get(file2)?.expressions??[]]:[...byFile.values()].flatMap(entry=>entry.expressions)},unsettled(){return[...byFile.values()].flatMap(entry=>entry.unsettled)},languages(){return deps.entities.list("expression-language").map(language=>language.id)},settle(){let open2=this.unsettled();if(stale=!0,open2.length>0)throw unsettledError(open2)}}}function unsettledError(open2){let[first2,...rest]=open2;return new ExpressionError(first2.file,first2.path,`${describeUnknown(first2.unknown)}.`,{details:rest.map(entry=>`${entry.path} ${describeUnknown(entry.unknown)} (in ${entry.file})`)})}function describeUnknown(unknown2){let parts=[];if(unknown2.variables.length>0){let one=unknown2.variables.length===1;parts.push(`reads ${names(unknown2.variables)}, which ${one?"is":"are"} not set anywhere in the config`)}if(unknown2.filters.length>0){let one=unknown2.filters.length===1;parts.push(`uses the Liquid filter${one?"":"s"} ${names(unknown2.filters)}, which no plugin adds`)}return parts.join(", and ")}function names(list2){return list2.join(", ")}function isTruthy2(value){return value!==!1&&value!==void 0&&value!==null}var LayerRun=class{constructor(data,options,deps){this.data=data;this.options=options;this.deps=deps;this.config=options.config,this.file=options.file,this.entities=builderEntities(options.config),this.lookup={get:path103=>options.config.atPath(path103).get()}}expressions=[];unsettled=[];config;file;entities;lookup;reads;unknown;evaluate(){return this.walk(this.data,[],{})}walk(value,path103,levelVars){if(Array.isArray(value)){let out2=[];return value.forEach((item,index)=>{let result=this.walk(item,[...path103,index],levelVars);result!==void 0&&out2.push(result)}),out2}if(!isPlainObject3(value))return value;if(isExpressionObject(value))return this.expressionObject(value,path103,levelVars);let inner=isScopeLevel(path103)?{...levelVars,...this.ownVarsOf(value,path103)}:levelVars,out={};for(let[key,child2]of Object.entries(value)){let result=this.walk(child2,[...path103,key],inner);result!==void 0&&(out[key]=result)}return out}ownVarsOf(object3,path103){if(path103.length===0&&this.options.ownVars)return this.options.ownVars;let block=object3._vars;return isPlainObject3(block)?Object.fromEntries(Object.entries(block).filter(entry=>typeof entry[1]=="string")):{}}expressionObject(object3,path103,levelVars){let outermost=this.reads===void 0;outermost&&(this.reads={},this.unknown=void 0);try{let plan=parseExpressionObject(object3,path103,this.file),value=this.evaluatePlan(plan,path103,levelVars);return outermost&&this.expressions.push({path:formatPath2(path103),written:object3,value,reads:this.reads,...this.unknown?{unknown:this.unknown}:{}}),value}finally{outermost&&(this.reads=void 0,this.unknown=void 0)}}evaluatePlan(plan,path103,levelVars){if(plan.kind==="value"){let outcome=this.run(plan.expression,path103,levelVars);return"unknown"in outcome?this.pending(path103,outcome.unknown):toJson(outcome.value)}for(let branch of plan.branches){if(branch.condition===void 0)return this.chosen(branch.then,path103,levelVars);let outcome=this.run(branch.condition,path103,levelVars);if("unknown"in outcome)return this.pending(path103,outcome.unknown);if(isTruthy2(outcome.value))return branch.then?this.chosen(branch.then,path103,levelVars):!0}return plan.otherwise?this.chosen(plan.otherwise,path103,levelVars):void 0}chosen(written,path103,levelVars){return this.walk(written.value,path103,levelVars)}pending(path103,unknown2){this.unknown=unknown2,this.unsettled.push({file:this.file,path:formatPath2(path103),unknown:unknown2})}run(expression,path103,levelVars){let language=this.language(expression),ctx={project:this.deps.project,file:this.file,path:formatPath2(expression.path),env:this.config.env,entities:this.entities,services:this.deps.services},variables=[...new Set(language.variables(expression.source,ctx))].filter(name=>!BUILT_IN_NAMES.has(name));this.checkForbidden(variables,path103);let vars=variables.length>0?this.scope(path103,levelVars):levelVars,missing=[];for(let name of variables){let known=Object.hasOwn(vars,name);this.reads[name]=known?vars[name]:void 0,known||missing.push(name)}return missing.length>0?{unknown:{variables:missing,filters:[]}}:language.evaluate(expression.source,{host:{platform:this.deps.platform??process.platform},env:this.config.env,vars},ctx)}language(expression){let id=expression.language??LIQUID_LANGUAGE,languages=this.config.entities("expression-language"),language=languages.find(entry=>entry.id===id);if(!language){let known=languages.map(entry=>entry.id).join(", ")||"none";throw new ExpressionError(this.file,expression.path,`uses the expression language "${id}", which sous does not know. Known languages: ${known}.`)}if(this.options.fromRecipe&&language.runsCode){let allowed=languages.filter(entry=>!entry.runsCode).map(entry=>entry.id).join(", ")||"none";throw new ExpressionError(this.file,expression.path,`uses the expression language "${id}", which runs code. A recipe's config file may only use languages that do not (${allowed}).`)}return language}scope(path103,levelVars){if(!this.deps.services.has("variables.resolver"))return levelVars;let resolver=this.deps.services.get("variables.resolver"),level=path103[0]==="compilation"?"compilation":"root";return resolver.scopeIn(this.config,{level,extra:levelVars})}checkForbidden(variables,path103){let top=path103[0];if(!(variables.length===0||typeof top!="string"))for(let source of this.config.entities("variable-source")){if(!source.forbiddenUnder?.includes(top))continue;let given=source.variables({project:this.deps.project,env:this.config.env,config:this.lookup}),read=variables.find(name=>Object.hasOwn(given,name));if(read!==void 0)throw new ExpressionError(this.file,path103,forbiddenProblem(read,source))}}};function forbiddenProblem(name,source){let under=source.forbiddenUnder.map(key=>`"${key}"`).join(" or ");return source.description==="recipe answers"?`reads ${name}, which is an answer to a recipe. An expression that decides which recipes are subscribed or pinned (anything under ${under}) cannot read recipe answers.`:`reads ${name}, which comes from ${source.description}. An expression under ${under} cannot read ${source.description}.`}function isScopeLevel(path103){return path103.length===0?!0:path103[0]!=="compilation"?!1:path103.length===1||path103.length===3&&path103[1]==="targets"&&typeof path103[2]=="number"||path103.length===5&&path103[1]==="targets"&&typeof path103[2]=="number"&&path103[3]==="outputs"&&typeof path103[4]=="number"}function toJson(value){if(value==null||typeof value=="string"||typeof value=="boolean")return value;if(typeof value=="number")return Number.isFinite(value)?value:null;if(Array.isArray(value))return value.map(toJson).filter(item=>item!==void 0);if(isPlainObject3(value)&&Object.getPrototypeOf(value)===Object.prototype){let out={};for(let[key,item]of Object.entries(value)){let json3=toJson(item);json3!==void 0&&(out[key]=json3)}return out}if(!(typeof value=="function"||typeof value=="symbol"))return String(value)}function builderEntities(config2){return{get:(kind,id)=>config2.entity(kind,id),list:kind=>config2.entities(kind),has:(kind,id)=>config2.entity(kind,id)!==void 0,describe:kind=>config2.entities(kind).map(entry=>({kind,id:entry.id,entry,plugin:"a plugin"})),kinds:()=>[]}}var package_default9={name:"@sous-io/plugin-expressions",version:"1.0.12",description:"Config expressions (S5) and the expression languages plugins add.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-liquid":"workspace:*","@sous-io/plugin-variables":"workspace:*",liquidjs:"^10.25.0"},devDependencies:{"@sous-io/core":"workspace:*","@sous-io/plugin-host":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME8="@sous-io/plugin-expressions",expressionsPlugin=definePlugin9({name:PLUGIN_NAME8,version:package_default9.version,description:"Config expressions and the expression languages plugins add.",dependsOn:{"@sous-io/plugin-liquid":`^${package_default9.version}`,"@sous-io/plugin-variables":`^${package_default9.version}`},register(sous){sous.entities.define("expression-language",jsonSchema9({type:"object",properties:{id:{type:"string"},description:{type:"string"},runsCode:{type:"boolean"}},required:["id","variables","evaluate"]}),{description:"A language config expressions are written in, named after $expr: or expr:."}),sous.entities.add("expression-language",createLiquidLanguage());let evaluator=createEvaluator({services:sous.services,entities:sous.entities,get project(){return sous.project}});sous.services.add("expressions.evaluator",()=>evaluator,{lifetime:"singleton"}),sous.on("config.built",()=>evaluator.settle())}});import fs18 from"node:fs";import{ConfigError as ConfigError22,definePlugin as definePlugin10}from"@sous-io/plugin-api";import fs16 from"node:fs";import path22 from"node:path";var CONTRIBUTOR_PREFIX="confd/",MANAGED_NAME=/^5\d\d-/;function isManagedName(name){return MANAGED_NAME.test(name)}function contributorId(name){return`${CONTRIBUTOR_PREFIX}${name}`}function listConfdFiles(confDir,loader,compare){if(confDir===void 0)return[];let names2;try{names2=fs16.readdirSync(confDir)}catch{return[]}let files=[];for(let name of[...names2].sort(compare)){let format3=loader.formatOf(name),full=path22.join(confDir,name);format3===void 0||!isFile4(full)||files.push({name,path:full,format:format3,contributor:contributorId(name),managed:isManagedName(name)})}return files}function duplicateBaseNames(names2){let byBase=new Map;for(let name of names2){let dot=name.lastIndexOf("."),base=dot<=0?name:name.slice(0,dot);byBase.set(base,[...byBase.get(base)??[],name])}return[...byBase.values()].filter(group=>group.length>1)}var ConfdFilesImpl=class{constructor(confDir,loader,compare){this.confDir=confDir;this.loader=loader;this.compare=compare}directory(){return this.confDir}list(){return listConfdFiles(this.confDir,this.loader,this.compare)}};function isFile4(file2){try{return fs16.statSync(file2).isFile()}catch{return!1}}init_src();import fs17 from"node:fs";import path23 from"node:path";import{ConfigError as ConfigError21}from"@sous-io/plugin-api";var MANAGED_FILE_COMMENT="This file is managed by sous. Sous edits these files by key; you may edit them too, and your comments, key order and formatting are kept.",FORMAT_NOTE=["It is JSON with comments (.jsonc): line comments, block comments and trailing","commas are all allowed here."],DESCRIPTIONS={"500-repos.jsonc":["It records the repositories this project trusts. The 'sous repo add' and","'sous repo remove' commands write the entries under 'repos'."],"510-subscriptions.jsonc":["It records what this project subscribes to. The 'sous subscription add' and","'sous subscription remove' commands write the entries under 'subscriptions'."]};function wrap2(text,width=78){let lines3=[],current="";for(let word of text.split(/\s+/))current.length===0?current=word:`${current} ${word}`.length+3<=width?current=`${current} ${word}`:(lines3.push(current),current=word);return current.length>0&&lines3.push(current),lines3}function managedHeader(name,description){let what=description.length>0?description:DESCRIPTIONS[name]??[];return`${[wrap2(MANAGED_FILE_COMMENT),what,FORMAT_NOTE].filter(block=>block.length>0).map(block=>block.map(line=>`// ${line}`.trimEnd()).join(`
862
863
  `)).join(`
863
864
  //
864
865
  `)}
865
866
  `}var ConfdManagedImpl=class{constructor(host){this.host=host}path(name){if(this.host.confDir===void 0)throw new ConfigError21(`There is no sous project here, so there is no ${name} to edit.`,{details:["Run sous init in the project root first."]});return path23.join(this.host.confDir,name)}header(name,description){return managedHeader(name,description)}async read(name){let existing=this.existing(name);if(existing!==void 0)return objectOf(parse5(readText(existing),existing).value(),existing)}async edit(name,edit,options={}){return this.change(name,`edit ${name}`,edit,options)}async set(name,keyPath,value,options={}){let segments=parsePath(keyPath);return this.change(name,`set ${keyPath}`,root=>root.atPath(segments).set(value),options)}async delete(name,keyPath,options={}){let segments=parsePath(keyPath);return this.change(name,`delete ${keyPath}`,root=>{let node=root.atPath(segments);node.exists()&&node.delete()},options)}existing(name){let current=this.path(name);if(isFile5(current))return current;let legacy=legacyPath(current);return legacy!==void 0&&isFile5(legacy)?legacy:void 0}async change(name,label,edit,options){let file2=this.path(name),existing=this.existing(name),original=existing===void 0?`${managedHeader(name,options.description??[])}{}
866
867
  `:readText(existing),document=parse5(original,existing??file2);objectOf(document.value(),existing??file2),edit(document.root());let text=document.toString();text.endsWith(`
867
868
  `)||(text+=`
868
- `);let patches={name:label,patches:document.patches().patches},migrating=existing!==void 0&&existing!==file2,created=existing===void 0,changed=created?patches.patches.length>0:text!==original||migrating;return changed&&options.dryRun!==!0&&(await this.write(file2,text),migrating&&fs17.rmSync(existing,{force:!0})),{file:file2,created:created&&changed,changed,patches,text}}async write(file2,text){let directory=path23.dirname(file2);await this.host.ensureDirectory(directory);let temporary=path23.join(directory,`.${path23.basename(file2)}.tmp-${process.pid}`);try{fs17.writeFileSync(temporary,text,"utf8"),fs17.renameSync(temporary,file2)}catch(error51){throw fs17.rmSync(temporary,{force:!0}),new ConfigError21(`Sous could not write its config file at ${file2}.`,{cause:error51,details:[error51.message]})}}};function legacyPath(file2){return file2.endsWith(".jsonc")?file2.slice(0,-1):void 0}function readText(file2){try{return fs17.readFileSync(file2,"utf8")}catch(error51){throw new ConfigError21(`Sous could not read its own config file at ${file2}.`,{cause:error51,details:[error51.message]})}}function parse5(text,file2){try{return parseDocument2(text,"jsonc")}catch(error51){throw new ConfigError21(`Sous could not read its own config file at ${file2}.`,{cause:error51,details:["The file is not valid JSON with comments.","Sous writes this file itself. Restoring it from version control, or deleting it and adding the entries again, both fix this."]})}}function objectOf(value,file2){if(!isJsonObject(value))throw new ConfigError21(`The config file at ${file2} is not a JSON object.`,{details:["Sous writes this file itself; it always holds one object."]});return value}function isFile5(file2){try{return fs17.statSync(file2).isFile()}catch{return!1}}var package_default10={name:"@sous-io/plugin-confd",version:"1.0.11",description:"The conf.d files, one contributor per file, and surgical edits to the managed conf.d/5xx files.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/documents":"workspace:*","@sous-io/plugin-api":"workspace:*","@sous-io/plugin-config-files":"workspace:*","@sous-io/plugin-expressions":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-variables":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME9="@sous-io/plugin-confd",USER_FILES_APPLY_ORDER=9e4,MAX_FILE_NUMBER=9999,UNNUMBERED_APPLY_ORDER=90500,SCAN_CONTRIBUTOR="confd.files",confdPlugin=definePlugin10({name:PLUGIN_NAME9,version:package_default10.version,description:"The conf.d files, one contributor per file, and surgical edits to the managed conf.d/5xx files.",dependsOn:{"@sous-io/plugin-config-files":`^${package_default10.version}`,"@sous-io/plugin-expressions":`^${package_default10.version}`,"@sous-io/plugin-variables":`^${package_default10.version}`,"@sous-io/plugin-host":`^${package_default10.version}`},register(sous){let confDir=()=>sous.project?.confDir,compare=(left,right)=>sous.services.get("host.globs").compareBytewise(left,right),loader=()=>sous.services.get("config-files.loader"),added=new Set,addContributors=files=>{for(let file2 of files)added.has(file2.contributor)||(added.add(file2.contributor),sous.config.contribute(fileContributor2(sous,file2)))};addContributors(listConfdFiles(confDir(),loader(),compare)),sous.config.contribute({id:SCAN_CONTRIBUTOR,applyOrder:USER_FILES_APPLY_ORDER,contribute(config2){let files=listConfdFiles(confDir(),loader(),compare),duplicate=duplicateBaseNames(files.map(file2=>file2.name))[0];if(duplicate!==void 0)throw duplicateBaseNameError(duplicate,files);addContributors(files)}}),sous.services.add("confd.files",()=>new ConfdFilesImpl(confDir(),loader(),compare),{lifetime:"config"}),sous.services.add("confd.managed",(_config,ctx)=>new ConfdManagedImpl({confDir:confDir(),ensureDirectory:async directory=>{ctx.services.has("host.directories")?await ctx.services.get("host.directories").ensureKnown("confd",directory):fs18.mkdirSync(directory,{recursive:!0})}}),{lifetime:"config"})}});function leadingFileNumber(name){let leading=/^\d+/.exec(name)?.[0];return leading===void 0?void 0:{read:Number(leading),used:Math.min(MAX_FILE_NUMBER,Number(leading))}}function confdApplyOrder(name){let number4=leadingFileNumber(name);return number4===void 0?UNNUMBERED_APPLY_ORDER:USER_FILES_APPLY_ORDER+number4.used}function fileContributor2(sous,file2){let isPatch2=file2.format==="patch-json"||file2.format==="patch-jsonl";return{id:contributorId(file2.name),applyOrder:confdApplyOrder(file2.name),...isPatch2?{monitors:[""]}:{},async contribute(config2){let loader=sous.services.get("config-files.loader");if(config2.contributor.run===1){loader.forget(file2.path);let number4=leadingFileNumber(file2.name);number4!==void 0&&number4.read>number4.used&&config2.debug(`The conf.d file ${file2.name} starts with the number ${number4.read}, which is more than ${MAX_FILE_NUMBER}; it is applied as number ${number4.used} (apply order ${confdApplyOrder(file2.name)}).`)}isFile6(file2.path)&&await loader.contribute(await loader.load(file2.path),config2)}}}function duplicateBaseNameError(names2,files){let dot=names2[0].lastIndexOf("."),base=dot<=0?names2[0]:names2[0].slice(0,dot),paths=names2.map(name=>files.find(file2=>file2.name===name)?.path??name);return new ConfigError22(`Duplicate config layer baseName '${base}':`,{details:[...paths.map(file2=>` ${file2}`),"Two config files in one directory must not share a name once the final extension is removed. Delete or rename one of them."]})}function isFile6(file2){try{return fs18.statSync(file2).isFile()}catch{return!1}}import{definePlugin as definePlugin11,jsonSchema as jsonSchema10}from"@sous-io/plugin-api";import path25 from"node:path";import os5 from"node:os";import path24 from"node:path";var INCLUDE_LINE_PATTERN=/^@([~#/a-zA-Z0-9_.${}*?[][a-zA-Z0-9_\-/.:${}*?[\],!~#%+^()]*\.md(?:\?[^?\s]*=\S*)?)$/;function isIncludeLine(line){return INCLUDE_LINE_PATTERN.test(line)}function looksLikeIncludeLine(line){if(!/^@\S+$/.test(line))return!1;let word=line.slice(1);return/[/]/.test(word)||/\.md\b/.test(word)||/^[~#.$]/.test(word)}var TEMPLATE_MARKER=".tpl";function templateTwin(filePath){let dir=path24.dirname(filePath),base=path24.basename(filePath),ext2=path24.extname(base);if(ext2===""||ext2===base)return;let stem=base.slice(0,-ext2.length),twin=stem.endsWith(TEMPLATE_MARKER)?`${stem.slice(0,-TEMPLATE_MARKER.length)}${ext2}`:`${stem}${TEMPLATE_MARKER}${ext2}`;return path24.join(dir,twin)}function withTemplateTwins(candidates){let out=[];for(let candidate of candidates){out.push(candidate);let twin=templateTwin(candidate);twin!==void 0&&out.push(twin)}return[...new Set(out)]}function splitAliasKey(value){let match2=value.match(/^([^/:]+)[/:]([\s\S]*)$/);return match2?{key:match2[1],rest:match2[2]}:{key:value,rest:""}}var QUERY_SUFFIX=/^(.*\.md)(\?[^?\s]*=\S*)$/;function splitIncludeQuery(raw2){let match2=QUERY_SUFFIX.exec(raw2);return match2===null?{path:raw2,query:""}:{path:match2[1],query:match2[2]}}function expandHome2(value,home=os5.homedir()){return value==="~"?home:value.startsWith("~/")?path24.join(home,value.slice(2)):value}function resolveOutputPath(unit,output){if(output.destinationFile)return output.destinationFile;if(!output.destinationDir)return;let sourceRelative=unit.globBase?path24.relative(unit.globBase,unit.source):path24.basename(unit.source);return path24.join(output.destinationDir,sourceRelative.replace(/\.tpl\./,"."))}function stableVarsFingerprint(vars){return JSON.stringify(Object.keys(vars).sort().map(key=>[key,vars[key]]))}function isReservedAliasName(name){return name.startsWith("~")||name.startsWith("#")}function buildAliasMap(options){let substitute2=options.substitute??(text=>text),out={};for(let[name,bases]of Object.entries(options.builtIns??{}))out[name]=[...bases];for(let block of options.userAliases??[])if(block)for(let[name,value]of Object.entries(block)){if(isReservedAliasName(name)){options.onError?.(`Alias "${name}" is invalid: names beginning with "~" or "#" are reserved ("~" for the home directory and recipe namespaces, "#" for built-in names).`);continue}let bases=(typeof value=="string"?[value]:[...value]).map(entry=>substitute2(entry));out[name]=[...bases,...out[name]??[]]}return out}function resolveAliasPrefix(value,aliases){if(path25.isAbsolute(value))return[value];let{key,rest}=splitAliasKey(value);return!key||!Object.prototype.hasOwnProperty.call(aliases,key)?[value]:aliases[key].map(base=>path25.resolve(base,rest))}var AliasService=class{constructor(map3){this.map=map3}all(){return Object.fromEntries(Object.entries(this.map).map(([name,bases])=>[name,[...bases]]))}get(name){return Object.prototype.hasOwnProperty.call(this.map,name)?[...this.map[name]]:void 0}split(value){let{key,rest}=splitAliasKey(value);return Object.prototype.hasOwnProperty.call(this.map,key)?{alias:key,rest}:void 0}};import fs20 from"node:fs";import path27 from"node:path";import fs19 from"node:fs";import path26 from"node:path";function expandPattern(globs,pattern,options={}){if(!globs.hasGlob(pattern))return isFile7(pattern)?[path26.resolve(pattern)]:[];let normalized=pattern.split(path26.sep).join("/"),base=globs.staticBase(normalized),relative4=base==="/"?normalized.replace(/^\/+/,""):normalized.slice(base.length).replace(/^\/+/,"");if(relative4==="")return[];try{let matches=globs.matchSync(relative4,{cwd:base,absolute:!0,dot:options.dot??!0,onlyFiles:!0});return globs.sortBytewise(new Set(matches.map(file2=>path26.resolve(file2))))}catch{return[]}}function isFile7(file2){try{return fs19.statSync(file2).isFile()}catch{return!1}}function literalGroups(candidate,root){return withTemplateTwins([candidate]).map(entry=>({paths:[entry],glob:!1,...root===void 0?{}:{roots:[root]}}))}function planInclude(rawPath,context,env){let baseDir=context.baseDir??path27.dirname(context.fromFile),withQuery=expandHome2(env.substitute(rawPath,context.scope),env.home),substituted=splitIncludeQuery(withQuery).path,glob=env.globs.hasGlob(substituted),finish4=(groups2,extra={})=>({groups:groups2,candidates:[...new Set(groups2.flatMap(group=>group.paths))],glob,view:extra.view??!1,...extra.namespaceProblem===void 0?{}:{namespaceProblem:extra.namespaceProblem},...extra.hashProblem===void 0?{}:{hashProblem:extra.hashProblem}}),single=candidate=>glob?[{paths:[candidate],glob:!0}]:literalGroups(candidate);if(path27.isAbsolute(substituted))return finish4(single(path27.normalize(substituted)));let{key,rest}=splitAliasKey(substituted);if(key.startsWith("#")&&Object.prototype.hasOwnProperty.call(env.views,key))return planView(key,rest,glob,context,env,finish4);let groups=[],namespaceProblem,hashProblem;if(key&&Object.prototype.hasOwnProperty.call(env.aliases,key))for(let base of env.aliases[key])groups.push(...single(path27.resolve(base,rest)));else if(key.startsWith("#")&&rest.length>0){let known=[...Object.keys(env.aliases),...Object.keys(env.views)].filter(name=>name.startsWith("#"));hashProblem=`There is no built-in name "${key}" available here.
869
+ `);let patches={name:label,patches:document.patches().patches},migrating=existing!==void 0&&existing!==file2,created=existing===void 0,changed=created?patches.patches.length>0:text!==original||migrating;return changed&&options.dryRun!==!0&&(await this.write(file2,text),migrating&&fs17.rmSync(existing,{force:!0})),{file:file2,created:created&&changed,changed,patches,text}}async write(file2,text){let directory=path23.dirname(file2);await this.host.ensureDirectory(directory);let temporary=path23.join(directory,`.${path23.basename(file2)}.tmp-${process.pid}`);try{fs17.writeFileSync(temporary,text,"utf8"),fs17.renameSync(temporary,file2)}catch(error51){throw fs17.rmSync(temporary,{force:!0}),new ConfigError21(`Sous could not write its config file at ${file2}.`,{cause:error51,details:[error51.message]})}}};function legacyPath(file2){return file2.endsWith(".jsonc")?file2.slice(0,-1):void 0}function readText(file2){try{return fs17.readFileSync(file2,"utf8")}catch(error51){throw new ConfigError21(`Sous could not read its own config file at ${file2}.`,{cause:error51,details:[error51.message]})}}function parse5(text,file2){try{return parseDocument2(text,"jsonc")}catch(error51){throw new ConfigError21(`Sous could not read its own config file at ${file2}.`,{cause:error51,details:["The file is not valid JSON with comments.","Sous writes this file itself. Restoring it from version control, or deleting it and adding the entries again, both fix this."]})}}function objectOf(value,file2){if(!isJsonObject(value))throw new ConfigError21(`The config file at ${file2} is not a JSON object.`,{details:["Sous writes this file itself; it always holds one object."]});return value}function isFile5(file2){try{return fs17.statSync(file2).isFile()}catch{return!1}}var package_default10={name:"@sous-io/plugin-confd",version:"1.0.12",description:"The conf.d files, one contributor per file, and surgical edits to the managed conf.d/5xx files.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/documents":"workspace:*","@sous-io/plugin-api":"workspace:*","@sous-io/plugin-config-files":"workspace:*","@sous-io/plugin-expressions":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-variables":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME9="@sous-io/plugin-confd",USER_FILES_APPLY_ORDER=9e4,MAX_FILE_NUMBER=9999,UNNUMBERED_APPLY_ORDER=90500,SCAN_CONTRIBUTOR="confd.files",confdPlugin=definePlugin10({name:PLUGIN_NAME9,version:package_default10.version,description:"The conf.d files, one contributor per file, and surgical edits to the managed conf.d/5xx files.",dependsOn:{"@sous-io/plugin-config-files":`^${package_default10.version}`,"@sous-io/plugin-expressions":`^${package_default10.version}`,"@sous-io/plugin-variables":`^${package_default10.version}`,"@sous-io/plugin-host":`^${package_default10.version}`},register(sous){let confDir=()=>sous.project?.confDir,compare=(left,right)=>sous.services.get("host.globs").compareBytewise(left,right),loader=()=>sous.services.get("config-files.loader"),added=new Set,addContributors=files=>{for(let file2 of files)added.has(file2.contributor)||(added.add(file2.contributor),sous.config.contribute(fileContributor2(sous,file2)))};addContributors(listConfdFiles(confDir(),loader(),compare)),sous.config.contribute({id:SCAN_CONTRIBUTOR,applyOrder:USER_FILES_APPLY_ORDER,contribute(config2){let files=listConfdFiles(confDir(),loader(),compare),duplicate=duplicateBaseNames(files.map(file2=>file2.name))[0];if(duplicate!==void 0)throw duplicateBaseNameError(duplicate,files);addContributors(files)}}),sous.services.add("confd.files",()=>new ConfdFilesImpl(confDir(),loader(),compare),{lifetime:"config"}),sous.services.add("confd.managed",(_config,ctx)=>new ConfdManagedImpl({confDir:confDir(),ensureDirectory:async directory=>{ctx.services.has("host.directories")?await ctx.services.get("host.directories").ensureKnown("confd",directory):fs18.mkdirSync(directory,{recursive:!0})}}),{lifetime:"config"})}});function leadingFileNumber(name){let leading=/^\d+/.exec(name)?.[0];return leading===void 0?void 0:{read:Number(leading),used:Math.min(MAX_FILE_NUMBER,Number(leading))}}function confdApplyOrder(name){let number4=leadingFileNumber(name);return number4===void 0?UNNUMBERED_APPLY_ORDER:USER_FILES_APPLY_ORDER+number4.used}function fileContributor2(sous,file2){let isPatch2=file2.format==="patch-json"||file2.format==="patch-jsonl";return{id:contributorId(file2.name),applyOrder:confdApplyOrder(file2.name),...isPatch2?{monitors:[""]}:{},async contribute(config2){let loader=sous.services.get("config-files.loader");if(config2.contributor.run===1){loader.forget(file2.path);let number4=leadingFileNumber(file2.name);number4!==void 0&&number4.read>number4.used&&config2.debug(`The conf.d file ${file2.name} starts with the number ${number4.read}, which is more than ${MAX_FILE_NUMBER}; it is applied as number ${number4.used} (apply order ${confdApplyOrder(file2.name)}).`)}isFile6(file2.path)&&await loader.contribute(await loader.load(file2.path),config2)}}}function duplicateBaseNameError(names2,files){let dot=names2[0].lastIndexOf("."),base=dot<=0?names2[0]:names2[0].slice(0,dot),paths=names2.map(name=>files.find(file2=>file2.name===name)?.path??name);return new ConfigError22(`Duplicate config layer baseName '${base}':`,{details:[...paths.map(file2=>` ${file2}`),"Two config files in one directory must not share a name once the final extension is removed. Delete or rename one of them."]})}function isFile6(file2){try{return fs18.statSync(file2).isFile()}catch{return!1}}import{definePlugin as definePlugin11,jsonSchema as jsonSchema10}from"@sous-io/plugin-api";import path25 from"node:path";import os5 from"node:os";import path24 from"node:path";var INCLUDE_LINE_PATTERN=/^@([~#/a-zA-Z0-9_.${}*?[][a-zA-Z0-9_\-/.:${}*?[\],!~#%+^()]*\.md(?:\?[^?\s]*=\S*)?)$/;function isIncludeLine(line){return INCLUDE_LINE_PATTERN.test(line)}function looksLikeIncludeLine(line){if(!/^@\S+$/.test(line))return!1;let word=line.slice(1);return/[/]/.test(word)||/\.md\b/.test(word)||/^[~#.$]/.test(word)}var TEMPLATE_MARKER=".tpl";function templateTwin(filePath){let dir=path24.dirname(filePath),base=path24.basename(filePath),ext2=path24.extname(base);if(ext2===""||ext2===base)return;let stem=base.slice(0,-ext2.length),twin=stem.endsWith(TEMPLATE_MARKER)?`${stem.slice(0,-TEMPLATE_MARKER.length)}${ext2}`:`${stem}${TEMPLATE_MARKER}${ext2}`;return path24.join(dir,twin)}function withTemplateTwins(candidates){let out=[];for(let candidate of candidates){out.push(candidate);let twin=templateTwin(candidate);twin!==void 0&&out.push(twin)}return[...new Set(out)]}function splitAliasKey(value){let match2=value.match(/^([^/:]+)[/:]([\s\S]*)$/);return match2?{key:match2[1],rest:match2[2]}:{key:value,rest:""}}var QUERY_SUFFIX=/^(.*\.md)(\?[^?\s]*=\S*)$/;function splitIncludeQuery(raw2){let match2=QUERY_SUFFIX.exec(raw2);return match2===null?{path:raw2,query:""}:{path:match2[1],query:match2[2]}}function expandHome2(value,home=os5.homedir()){return value==="~"?home:value.startsWith("~/")?path24.join(home,value.slice(2)):value}function resolveOutputPath(unit,output){if(output.destinationFile)return output.destinationFile;if(!output.destinationDir)return;let sourceRelative=unit.globBase?path24.relative(unit.globBase,unit.source):path24.basename(unit.source);return path24.join(output.destinationDir,sourceRelative.replace(/\.tpl\./,"."))}function stableVarsFingerprint(vars){return JSON.stringify(Object.keys(vars).sort().map(key=>[key,vars[key]]))}function isReservedAliasName(name){return name.startsWith("~")||name.startsWith("#")}function buildAliasMap(options){let substitute2=options.substitute??(text=>text),out={};for(let[name,bases]of Object.entries(options.builtIns??{}))out[name]=[...bases];for(let block of options.userAliases??[])if(block)for(let[name,value]of Object.entries(block)){if(isReservedAliasName(name)){options.onError?.(`Alias "${name}" is invalid: names beginning with "~" or "#" are reserved ("~" for the home directory and recipe namespaces, "#" for built-in names).`);continue}let bases=(typeof value=="string"?[value]:[...value]).map(entry=>substitute2(entry));out[name]=[...bases,...out[name]??[]]}return out}function resolveAliasPrefix(value,aliases){if(path25.isAbsolute(value))return[value];let{key,rest}=splitAliasKey(value);return!key||!Object.prototype.hasOwnProperty.call(aliases,key)?[value]:aliases[key].map(base=>path25.resolve(base,rest))}var AliasService=class{constructor(map3){this.map=map3}all(){return Object.fromEntries(Object.entries(this.map).map(([name,bases])=>[name,[...bases]]))}get(name){return Object.prototype.hasOwnProperty.call(this.map,name)?[...this.map[name]]:void 0}split(value){let{key,rest}=splitAliasKey(value);return Object.prototype.hasOwnProperty.call(this.map,key)?{alias:key,rest}:void 0}};import fs20 from"node:fs";import path27 from"node:path";import fs19 from"node:fs";import path26 from"node:path";function expandPattern(globs,pattern,options={}){if(!globs.hasGlob(pattern))return isFile7(pattern)?[path26.resolve(pattern)]:[];let normalized=pattern.split(path26.sep).join("/"),base=globs.staticBase(normalized),relative4=base==="/"?normalized.replace(/^\/+/,""):normalized.slice(base.length).replace(/^\/+/,"");if(relative4==="")return[];try{let matches=globs.matchSync(relative4,{cwd:base,absolute:!0,dot:options.dot??!0,onlyFiles:!0});return globs.sortBytewise(new Set(matches.map(file2=>path26.resolve(file2))))}catch{return[]}}function isFile7(file2){try{return fs19.statSync(file2).isFile()}catch{return!1}}function literalGroups(candidate,root){return withTemplateTwins([candidate]).map(entry=>({paths:[entry],glob:!1,...root===void 0?{}:{roots:[root]}}))}function planInclude(rawPath,context,env){let baseDir=context.baseDir??path27.dirname(context.fromFile),withQuery=expandHome2(env.substitute(rawPath,context.scope),env.home),substituted=splitIncludeQuery(withQuery).path,glob=env.globs.hasGlob(substituted),finish4=(groups2,extra={})=>({groups:groups2,candidates:[...new Set(groups2.flatMap(group=>group.paths))],glob,view:extra.view??!1,...extra.namespaceProblem===void 0?{}:{namespaceProblem:extra.namespaceProblem},...extra.hashProblem===void 0?{}:{hashProblem:extra.hashProblem}}),single=candidate=>glob?[{paths:[candidate],glob:!0}]:literalGroups(candidate);if(path27.isAbsolute(substituted))return finish4(single(path27.normalize(substituted)));let{key,rest}=splitAliasKey(substituted);if(key.startsWith("#")&&Object.prototype.hasOwnProperty.call(env.views,key))return planView(key,rest,glob,context,env,finish4);let groups=[],namespaceProblem,hashProblem;if(key&&Object.prototype.hasOwnProperty.call(env.aliases,key))for(let base of env.aliases[key])groups.push(...single(path27.resolve(base,rest)));else if(key.startsWith("#")&&rest.length>0){let known=[...Object.keys(env.aliases),...Object.keys(env.views)].filter(name=>name.startsWith("#"));hashProblem=`There is no built-in name "${key}" available here.
869
870
  `+(known.length>0?`Available names: ${known.sort().join(", ")}.`:"No '#' names are available in this project.")}if(env.namespaceResolver&&substituted.startsWith("~")&&substituted.length>1&&substituted.includes("/")){let reference=withQuery.slice(1),resolution=env.namespaceResolver.resolve({reference,fromFile:context.fromFile});resolution.kind==="candidates"&&resolution.glob===!0?groups.push({paths:[...resolution.candidates],glob:!0,...resolution.roots===void 0?{}:{roots:resolution.roots}}):resolution.kind==="candidates"&&resolution.candidates.length>0?resolution.candidates.forEach((candidate,index)=>{groups.push(...literalGroups(path27.normalize(candidate),resolution.roots?.[index]))}):resolution.kind!=="candidates"&&(namespaceProblem={reference,fromFile:context.fromFile,resolution})}return groups.push(...single(path27.resolve(baseDir,substituted))),finish4(groups,{...namespaceProblem===void 0?{}:{namespaceProblem},...hashProblem===void 0?{}:{hashProblem}})}function planView(key,wanted,glob,context,env,finish4){let includingRecipe=env.namespaceResolver?.includingRecipe?.(context.fromFile)??null;if(includingRecipe!==null)return finish4([],{view:!0,hashProblem:`The recipe "${includingRecipe}" may not include "${key}", because a view lists other recipes' files.
870
871
  A recipe includes another recipe's files with "@~namespace/recipe/..." and a dependency declared in its manifest ("depends" or "subscribes").`});let listed2=env.views[key],matched=listed2.filter(entry=>glob?env.globs.isMatch(entry.path,wanted,{dot:!0}):entry.path===wanted),problem=!glob&&matched.length===0?`The view "${key}" lists no file at "${wanted}".
871
872
  `+(listed2.length>0?`It lists:
@@ -898,7 +899,7 @@ ${candidates.join(`
898
899
  ${messageOf4(counterError)}`;ctx.reporter.problem(message2,{},LogLevel4.Warning),problems.push({level:"warning",message:message2})}let run=new CompileRun(deps,{strict,...input.rebuild?{rebuild:!0}:{},dryRun:dryRun4}),units=expanded.units;if(input.changedFiles!==void 0){let changed=new Set(input.changedFiles.map(file2=>path32.resolve(runtime.projectRoot(),file2)));units=units.filter(unit=>run.reads(unit,changed)),units.length===0&&ctx.reporter.detail(`No targets affected by change to ${input.changedFiles.join(", ")}; nothing compiled`)}try{let result=await run.run(units),allProblems=[...problems,...result.problems],errors=allProblems.filter(problem=>problem.level==="error").length;return await ctx.services.get("compiler.writer").commit({dryRun:dryRun4}),input.targets===void 0&&input.changedFiles===void 0&&(runtime.produced=result.produced),ctx.reporter.operationEnd(errors>0?`Done with ${errors} error(s).`:"Done.",errors===0),await ctx.emit("compiler.wrote",{files:result.outputs,dryRun:dryRun4}),{ok:errors===0&&(!strict||allProblems.every(problem=>problem.level!=="warning")),outputs:result.outputs,problems:allProblems,included:[...result.included],durationMs:performance.now()-started}}finally{counter?.free()}}async function producedNow(runtime,ctx){if(runtime.produced)return runtime.produced;let expanded=expandTargets(runtime.settings(),{resolver:runtime.resolver(),aliases:runtime.aliases(),globs:runtime.globs(),projectRoot:runtime.projectRoot()}),{deps}=await runDependencies(runtime,ctx,nullReporter2,!1);return(await new CompileRun(deps,{dryRun:!0}).run(expanded.units)).produced}function isDirectWrite(entry){return entry.target===void 0&&entry.origin?.plugin!==void 0}async function prune(input,ctx,runtime){return IntentOutputs8.of(await pruneOutputs(input,ctx,runtime))}async function pruneOutputs(input,ctx,runtime){let dryRun4=input.dryRun??!1,store2=runtime.store();store2.refresh();let entries=ctx.services.get("compiler.state").entries(),protectedRoots=runtime.protectedRoots(),keep=input.all?new Set:await producedNow(runtime,ctx),candidates=entries.filter(entry=>input.all||!isDirectWrite(entry)).map(entry=>path32.resolve(entry.dest)).filter(dest=>!keep.has(dest)&&!isProtectedPath(dest,protectedRoots)),writer=ctx.services.get("compiler.writer"),{removed,dirsRemoved}=await writer.remove(candidates,{dryRun:dryRun4});if(input.report!==!1)for(let file2 of removed)ctx.reporter.operation(dryRun4?"would-remove":"removed",file2);return dryRun4||(input.all?store2.delete():await writer.commit()),await ctx.emit("compiler.pruned",{removed,dryRun:dryRun4}),{removed,dirsRemoved,dryRun:dryRun4}}function messageOf4(error51){return error51 instanceof Error?error51.message:String(error51)}import path33 from"node:path";async function globFiles(globs,options){let include=options.include?.length?options.include:["**/*"],matches=await globs.match(include,{cwd:options.root,ignore:options.exclude??[],onlyFiles:!0,dot:!0});return[...new Set(matches.map(match2=>match2.split(path33.sep).join("/")))].sort((a,b)=>a.localeCompare(b)).map(relPath=>{let absPath=path33.resolve(options.root,relPath);return{path:absPath,dir:path33.dirname(absPath),relPath,name:path33.basename(absPath)}})}function parseGlobList(value){return value?value.split(",").map(pattern=>pattern.trim()).filter(pattern=>pattern.length>0):[]}import{pathToFileURL as pathToFileURL4}from"node:url";async function importNamedExport(absPath,exportName,onError){try{return(await import(pathToFileURL4(absPath).href))[exportName]}catch(error51){onError?.(absPath,error51);return}}var FALLBACK_HIDDEN="(hidden)";function secretCheck(ctx){let secrets=ctx.services.has("variables.secrets")?ctx.services.get("variables.secrets"):void 0;return secrets?{hiddenValue:secrets.hiddenValue,isSecret:(name,value)=>secrets.isSecret(name,value,ctx.secretNames)}:{hiddenValue:FALLBACK_HIDDEN,isSecret:(name,value)=>typeof value=="string"&&value.length>0&&ctx.secretNames.has(name)}}function sortObjectKeys(value){return Object.keys(value).sort().reduce((acc,key)=>(acc[key]=value[key],acc),{})}function splitPositionalName(args){let lead=args.match(/^\s*([a-zA-Z_][\w]*)(\s*=)?/);return lead&&!lead[2]?{name:lead[1],rest:args.slice(lead[0].length).trim()}:{name:null,rest:args.trim()}}function globsOf(ctx){return ctx.services.get("host.globs")}function isScalar2(value){return typeof value=="string"||typeof value=="boolean"||typeof value=="number"&&Number.isFinite(value)}var showVarsTag={id:"showVars",description:"Dumps every variable in scope as a fenced JSON block, secrets hidden.",tag(ctx){let secrets=secretCheck(ctx);return{parse(){},render(liquidCtx){let seen=new WeakSet,scope=sortObjectKeys(liquidCtx.getAll());return"# Sous Debug: Variable Dump\n```json\n"+JSON.stringify(scope,(key,value)=>{if(typeof value=="object"&&value!==null){if(seen.has(value))return"[Circular]";seen.add(value)}return key!==""&&secrets.isSecret(key,value)?secrets.hiddenValue:value},2)+"\n```"}}}},exportScalarVarsJsTag={id:"exportScalarVarsJs",description:"Writes every scalar variable in scope as an ES module default export, secrets left out.",tag(ctx){let secrets=secretCheck(ctx);return{parse(){},render(liquidCtx){let scalars={};for(let[key,value]of Object.entries(liquidCtx.getAll()))isScalar2(value)&&!secrets.isSecret(key,value)&&(scalars[key]=value);return`export default ${JSON.stringify(sortObjectKeys(scalars),null,2)};
899
900
  `}}}};async function resolveFiles(tag,ctx,hash2){let root=hash2.root!=null?String(hash2.root):"";if(!root)throw new Error(`${tag}: a "root" attribute is required`);return globFiles(globsOf(ctx),{root,include:parseGlobList(hash2.include!=null?String(hash2.include):void 0),exclude:parseGlobList(hash2.exclude!=null?String(hash2.exclude):void 0)})}async function attachImports(files,importName){return(await Promise.all(files.map(async file2=>{let value=await importNamedExport(file2.path,importName);return value===void 0?null:{...file2,[importName]:value}}))).filter(file2=>file2!==null)}var getFilesTag={id:"getFiles",description:"Finds files under a root and assigns them to a variable, optionally with an export of each.",tag(ctx){return{parse(token){let{name,rest}=splitPositionalName(token.args);this.varName=name,this.hash=new Hash(rest,!0)},*render(liquidCtx){let hash2=yield this.hash.render(liquidCtx),files=yield resolveFiles("getFiles",ctx,hash2),importName=hash2.import!=null?String(hash2.import).trim():"";return importName&&(files=yield attachImports(files,importName)),this.varName&&(liquidCtx.bottom()[this.varName]=files),""}}}},listFilesTag={id:"listFiles",description:"Renders the files under a root as a bullet list.",tag(ctx){return{parse(token){this.hash=new Hash(token.args,!0)},*render(liquidCtx){let hash2=yield this.hash.render(liquidCtx),files=yield resolveFiles("listFiles",ctx,hash2),relative4=String(hash2.relative??"")==="true";return files.map(file2=>`- ${relative4?file2.relPath:file2.name}`).join(`
900
901
  `)}}}},bulletListFilter={id:"bulletList",description:"Turns an array into a Markdown bullet list.",filter(){return items2=>Array.isArray(items2)?items2.map(item=>`- ${String(item)}`).join(`
901
- `):String(items2)}},BUILT_IN_TAGS=[showVarsTag,exportScalarVarsJsTag,getFilesTag,listFilesTag],BUILT_IN_FILTERS=[bulletListFilter];import path34 from"node:path";var DEFAULT_STATE_FILE="${sousDir}/sous.state.json",varsSchema=external_exports.record(external_exports.string(),external_exports.string()),outputSchema=external_exports.object({_if:external_exports.record(external_exports.string(),external_exports.object({eq:external_exports.string()}).strict()).optional(),_vars:varsSchema.optional(),destinationFile:external_exports.string().optional(),destinationDir:external_exports.string().optional(),transforms:external_exports.array(external_exports.string()).optional()}).strict(),originSchema=external_exports.object({plugin:external_exports.string().optional(),recipe:external_exports.string().optional(),repository:external_exports.string().optional()}).strict(),targetSchema=external_exports.object({id:external_exports.string().min(1).optional(),_vars:varsSchema.optional(),entryPoint:external_exports.string().optional(),entryGlob:external_exports.string().optional(),content:external_exports.string().optional(),globBase:external_exports.string().optional(),includeSourceComments:external_exports.boolean().optional(),generateRuntimeContext:external_exports.boolean().optional(),transforms:external_exports.array(external_exports.string()).optional(),origin:originSchema.optional(),outputs:external_exports.array(outputSchema)}).strict().superRefine((target,ctx)=>{[target.entryPoint,target.entryGlob,target.content].filter(source=>source!==void 0).length!==1&&ctx.addIssue({code:"custom",message:"a target must have exactly one of 'entryPoint', 'entryGlob' or 'content'"}),target.content!==void 0&&target.id===void 0&&ctx.addIssue({code:"custom",path:["id"],message:"a target whose source is 'content' needs an 'id', which names it in errors"})}),compilationSchema=external_exports.object({_vars:varsSchema.optional(),includeSourceComments:external_exports.boolean().default(!1),overwriteUntracked:external_exports.boolean().default(!0),stateFile:external_exports.string().default(DEFAULT_STATE_FILE),targets:external_exports.array(targetSchema).default([])}).strict(),aliasesSchema=external_exports.record(external_exports.string(),external_exports.union([external_exports.string(),external_exports.array(external_exports.string())])).superRefine((aliases,ctx)=>{for(let name of Object.keys(aliases))isReservedAliasName(name)&&ctx.addIssue({code:"custom",path:[name],message:`Alias "${name}" is invalid: names beginning with "~" or "#" are reserved ("~" for the home directory and recipe namespaces, "#" for built-in names).`})}),CONFIG_KEYS2=[{id:"compilation",schema:compilationSchema,description:"What to compile: targets, their outputs, source comments, the state file, overwriting files sous did not write."},{id:"_aliases",schema:aliasesSchema.optional(),description:"Include aliases: a name to one base directory or several, tried in order."}];function compilationSettings(config2){let value=config2.get("compilation")??{};return{...value,includeSourceComments:value.includeSourceComments??!1,overwriteUntracked:value.overwriteUntracked??!0,stateFile:value.stateFile??DEFAULT_STATE_FILE,targets:value.targets??[]}}var CompilerRuntime=class{constructor(source,stores){this.source=source;this.stores=stores}cachedScope;cachedNames;produced;get serviceContext(){let{plugin,config:config2,services,entities,project,env}=this.source;return{plugin,config:config2,services,entities,project,env}}settings(){return compilationSettings(this.source.config)}resolver(){let resolver=this.source.services.get("variables.resolver"),config2=this.source.config;return new Proxy(resolver,{get(target,key){if(key==="scope")return request=>target.scopeIn(config2,request);let value=Reflect.get(target,key,target);return typeof value=="function"?value.bind(target):value}})}globs(){return this.source.services.get("host.globs")}projectRoot(){return this.source.project?.root??path34.resolve("/")}rootScope(){return this.cachedScope??=this.resolver().scope(),this.cachedScope}namespaceResolver(){return this.source.services.has("compiler.namespace-resolver")?this.source.services.get("compiler.namespace-resolver"):void 0}hashNames(){if(this.cachedNames)return this.cachedNames;let context={...this.serviceContext,scope:this.rootScope()},aliases={},views={};for(let entity of this.source.entities.list("hash-name")){let name=`#${entity.id}`;entity.view?views[name]=entity.view(context):aliases[name]=(entity.bases?.(context)??[]).map(base=>path34.resolve(this.projectRoot(),base))}return this.cachedNames={aliases,views},this.cachedNames}aliases(){let resolver=this.resolver(),scope=this.rootScope(),user=this.source.config.get("_aliases");return buildAliasMap({builtIns:this.hashNames().aliases,userAliases:[user],substitute:text=>path34.resolve(this.projectRoot(),resolver.normalizePath(resolver.substitute(text,scope)))})}views(){return this.hashNames().views}includeEnvironment(){let resolver=this.resolver(),home=this.source.env.HOME;return{aliases:this.aliases(),views:this.views(),globs:this.globs(),namespaceResolver:this.namespaceResolver(),substitute:(text,scope)=>resolver.substitute(text,scope),...home?{home}:{}}}stateFile(){let scope=this.rootScope(),resolver=this.resolver(),written=scope.stateFilePath??this.settings().stateFile??DEFAULT_STATE_FILE;return path34.resolve(this.projectRoot(),resolver.normalizePath(resolver.substitute(written,scope)))}store(){let file2=this.stateFile(),store2=this.stores.get(file2);return store2||(store2=new StateStore(file2),this.stores.set(file2,store2)),store2}protectedRoots(){let roots=[];if(this.source.project&&roots.push(path34.join(this.source.project.sousDir,"repos")),this.source.services.has("host.sous-home")){let home=this.source.services.get("host.sous-home").paths(this.source.env);roots.push(home.repos,home.store)}return roots}},RuntimeCache=class{runtimes=new WeakMap;stores=new Map;for(source){let runtime=this.runtimes.get(source.config);return runtime||(runtime=new CompilerRuntime(source,this.stores),this.runtimes.set(source.config,runtime)),runtime}};import fs24 from"node:fs";import path35 from"node:path";var WriterService=class{constructor(store2,settings){this.store=store2;this.settings=settings}async write(file2,content,options){let dest=path35.resolve(file2),bytes=Buffer.byteLength(content,"utf8"),tracked=this.store.entry(dest),exists3=fs24.existsSync(dest),base={file:dest,bytes,...options.target===void 0?{}:{target:options.target},...options.origin===void 0?{}:{origin:options.origin}},sameContent=exists3&&readText3(dest)===content;if(exists3&&tracked===void 0&&!this.settings.overwriteUntracked)return{...base,action:"skipped-untracked"};if(options.dryRun)return{...base,action:exists3?sameContent&&!options.force?"unchanged":"would-update":"would-create"};let entry={dest,srcHash:options.sourceHash??hashContent(options.source),destHash:hashContent(content),size:bytes,builtAt:new Date().toISOString(),...options.target===void 0?{}:{target:options.target},...options.origin===void 0?{}:{origin:options.origin}};if(sameContent&&!options.force)return this.store.record(tracked===void 0?entry:{...entry,builtAt:tracked.builtAt}),{...base,action:"unchanged"};if(this.ensureDir(path35.dirname(dest)),fs24.writeFileSync(dest,content,"utf8"),options.mode!==void 0)try{fs24.chmodSync(dest,options.mode)}catch{}else dest.endsWith(".sh")&&fs24.chmodSync(dest,493);return this.store.record(entry),{...base,action:exists3?"updated":"created"}}async remove(files,options={}){let removed=[];for(let file2 of files){let dest=path35.resolve(file2);isProtectedPath(dest,this.settings.protectedRoots)||this.store.entry(dest)===void 0||(removed.push(dest),!options.dryRun&&(fs24.existsSync(dest)&&fs24.rmSync(dest),this.store.forget(dest)))}let dirsRemoved=options.dryRun?[]:this.removeEmptyDirs();return{removed,dirsRemoved}}async commit(options={}){this.store.commit(options)}ensureDir(dir){let missing=[],walk3=dir;for(;!fs24.existsSync(walk3);){missing.unshift(walk3);let parent=path35.dirname(walk3);if(parent===walk3)break;walk3=parent}if(missing.length!==0){fs24.mkdirSync(dir,{recursive:!0});for(let created of missing)this.store.recordDir(created)}}removeEmptyDirs(){let dirs=[...this.store.current().dirs].sort((a,b)=>b.split(path35.sep).length-a.split(path35.sep).length),removed=[];for(let dir of dirs)if(!isProtectedPath(dir,this.settings.protectedRoots))try{fs24.existsSync(dir)&&fs24.readdirSync(dir).length===0&&(fs24.rmdirSync(dir),removed.push(dir))}catch{}return removed}};function readText3(file2){try{return fs24.readFileSync(file2,"utf8")}catch{return}}var package_default11={name:"@sous-io/plugin-compiler",version:"1.0.11",description:"Compiling templates, includes, aliases, compilation settings, the built-in tags and filters, the state file, writing outputs, pruning.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-liquid":"workspace:*","@sous-io/plugin-refs":"workspace:*","@sous-io/plugin-variables":"workspace:*",liquidjs:"^10.25.0",tiktoken:"^1.0.22",zod:"^4.4.3"},devDependencies:{"@sous-io/core":"workspace:*",glob:"^13.0.6",minimatch:"^10.2.4"},engines:{node:">=22"}};var PLUGIN_NAME10="@sous-io/plugin-compiler",transformSchema={"~standard":{version:1,vendor:"sous",validate:value=>{let entry=value;return typeof entry?.id=="string"&&typeof entry.transform=="function"?{value}:{issues:[{message:"A compilation-transform entity needs an id and a transform function."}]}}}},compileInput=jsonSchema10({type:"object",properties:{targets:{type:"array",items:{anyOf:[{type:"string"},{type:"integer"}]},description:"Only these targets, by id or index."},changedFiles:{type:"array",items:{type:"string"},description:"Only the targets whose sources include one of these files."},strict:{type:"boolean",description:"Warnings fail the compile."},rebuild:{type:"boolean",description:"Writes every output, changed or not."},dryRun:{type:"boolean",description:"Writes nothing."}},additionalProperties:!1}),pruneInput=jsonSchema10({type:"object",properties:{all:{type:"boolean",description:"Removes every file the compiler wrote, not only those no target produces."},dryRun:{type:"boolean",description:"Removes nothing."},report:{type:"boolean",description:"Reports each removed file as progress. Default: true."}},additionalProperties:!1}),compilerPlugin=definePlugin11({name:PLUGIN_NAME10,version:package_default11.version,description:"Compiling templates, includes, aliases, compilation settings, the built-in tags and filters, the state file, writing outputs, pruning.",implementable:["compiler.namespace-resolver"],dependsOn:{"@sous-io/plugin-liquid":`^${package_default11.version}`,"@sous-io/plugin-refs":`^${package_default11.version}`,"@sous-io/plugin-variables":`^${package_default11.version}`,"@sous-io/plugin-host":`^${package_default11.version}`},register(sous){let runtimes=new RuntimeCache;sous.entities.define("compilation-transform",transformSchema,{description:"A change to an output's path or contents before it is written."});for(let key of CONFIG_KEYS2)sous.entities.add("config-key",key);for(let tag of BUILT_IN_TAGS)sous.entities.add("liquid-tag",tag);for(let filter3 of BUILT_IN_FILTERS)sous.entities.add("liquid-filter",filter3);sous.services.add("compiler.aliases",(_config,ctx)=>new AliasService(runtimes.for(ctx).aliases()),{lifetime:"config"}),sous.services.add("compiler.includes",(_config,ctx)=>new IncludeService(runtimes.for(ctx).includeEnvironment()),{lifetime:"config"}),sous.services.add("compiler.state",(_config,ctx)=>new StateService(runtimes.for(ctx).store()),{lifetime:"config"}),sous.services.add("compiler.writer",(_config,ctx)=>{let runtime=runtimes.for(ctx);return new WriterService(runtime.store(),{overwriteUntracked:runtime.settings().overwriteUntracked,protectedRoots:runtime.protectedRoots()})},{lifetime:"config"}),sous.intents.add({intent:"compiler.compile",summary:"Compile every compilation target into its outputs",internal:!0,input:compileInput,handle:(input,ctx)=>compile(input,ctx,runtimes.for(ctx))}),sous.intents.add({intent:"compiler.prune",summary:"Remove outputs no compilation target produces any more",internal:!0,input:pruneInput,handle:(input,ctx)=>prune(input,ctx,runtimes.for(ctx))})}});import{definePlugin as definePlugin12}from"@sous-io/plugin-api";import fs29 from"node:fs";import{jsonSchema as jsonSchema13}from"@sous-io/plugin-api";import fs25 from"node:fs";import path36 from"node:path";var RecipeContents=class{constructor(services){this.services=services}of(recipes,kind){let globs=this.services.get("host.globs"),found=[];for(let recipe of recipes)if(recipe.kind==="subscribes")for(let content of recipe.manifest.contents??[]){if(content.kind!==kind)continue;let seen=new Set,files=[];for(let include of content.include){let staticBase2=globs.hasGlob(include)?globs.staticBase(include):path36.posix.dirname(include),base=path36.join(recipe.dir,staticBase2==="/"?".":staticBase2),relative4=globs.matchSync(include,{cwd:recipe.dir,dot:!0,ignore:content.exclude??[]});for(let file2 of globs.sortBytewise(relative4)){let absolute=path36.join(recipe.dir,file2);seen.has(absolute)||!isFile8(absolute)||(seen.add(absolute),files.push({path:globs.toPosix(file2),file:absolute,base}))}}found.push({recipe,kind,files})}return found}};function isFile8(candidate){try{return fs25.statSync(candidate).isFile()}catch{return!1}}var RECIPES_PLUGIN="@sous-io/plugin-recipes",LOCKFILE_NAME="sous.lock.json",LINKS_FILE_NAME="sous.links.json",PROJECT_REPOS_DIRNAME="repos",TYPES_DIRNAME="types",PROJECT_HOLDER="project",BUILT_IN_ADDED_BY="sous",OFFICIAL_REPO_NAME="sous-recipes",OFFICIAL_REPO_URL="https://github.com/sous-io/sous-recipes",OFFICIAL_REPO_IDENTITY="github.com/sous-io/sous-recipes",OFFICIAL_REPO_PROVIDER="github",CORE_NAMESPACE="core",CORE_RECIPE_NAME="sous-skills",CORE_RECIPE_KEY=`${CORE_NAMESPACE}/${CORE_RECIPE_NAME}`,PACKAGED_RECIPES_DIRNAME="recipes",CORE_RECIPE_PATH=`${PACKAGED_RECIPES_DIRNAME}/${CORE_NAMESPACE}/${CORE_RECIPE_NAME}`,DEFAULT_FRESHNESS_SECONDS=300,CONTRIBUTORS={core:"recipes.core",fetch:"recipes.fetch",configLayers:"recipes.config-layers",plugins:"recipes.plugins"};import{ConfigError as ConfigError23}from"@sous-io/plugin-api";function splitStoredKey(key){let slash=key.indexOf("/");return slash===-1?{namespace:key,name:""}:{namespace:key.slice(0,slash),name:key.slice(slash+1)}}function identitySegments2(identity2){return identity2.split("/").filter(segment=>segment.length>0&&segment!=="."&&segment!=="..")}function enabledEntries(entries){let kept={};for(let[key,entry]of Object.entries(entries??{}))entry&&typeof entry=="object"&&entry.enabled!==!1&&(kept[key]=entry);return kept}function trustedWhileBuilding(repos){let kept={};for(let[name,entry]of Object.entries(enabledEntries(repos)))typeof entry.url=="string"&&(kept[name]=entry);return kept}function enabledSubscriptions(subscriptions){return enabledEntries(subscriptions)}function hostFor(hosts,url2,provider){if(provider!==void 0){let named=hosts.find(host=>host.id===provider);if(named)return named}return hosts.find(host=>{try{return host.matches(url2)}catch{return!1}})}function messageOf5(error51){return error51 instanceof Error?error51.message:String(error51)}function sortKeys2(keys){return[...keys].sort((left,right)=>left<right?-1:left>right?1:0)}function plural(count2,one,many=`${one}s`){return`${count2} ${count2===1?one:many}`}function emptyLockfile(){return{formatVersion:1,repos:{},recipes:{}}}function sortRecipes(recipes){let sorted2={};for(let key of sortKeys2(Object.keys(recipes)))sorted2[key]=recipes[key];return sorted2}function applyResolution(lock,resolved,repos,identityOf3=()=>{}){let recipes={...lock.recipes};for(let recipe of resolved){let previous=lock.recipes[recipe.key],holders=new Set([...previous?.requestedBy??[],...recipe.requestedBy]);recipes[recipe.key]={repo:recipe.repo,version:recipe.version,hash:recipe.hash,requestedBy:sortKeys2(holders),kind:previous?.kind==="subscribes"||recipe.kind==="subscribes"?"subscribes":"depends"}}let lockedRepos={};for(let name of usedRepos(recipes)){let known=repos[name],previous=lock.repos[name],url2=known?.url??previous?.url;if(url2===void 0)throw new ConfigError23(`The lockfile cannot record the recipes from '${name}' because nothing knows that repository's URL.`,{details:["Add it with 'sous repo add <url>', so the lockfile can name where its recipes came from."]});let identity2=known?.identity??previous?.identity??identityOf3(url2),indexHash=known?.indexHash??previous?.indexHash;lockedRepos[name]={url:url2,...identity2===void 0?{}:{identity:identity2},...indexHash===void 0?{}:{indexHash}}}return{formatVersion:1,repos:lockedRepos,recipes:sortRecipes(recipes)}}function removeHolder(lock,holder,label=LOCKFILE_LABEL){let recipes={};for(let[key,entry]of Object.entries(lock.recipes))recipes[key]={...entry,requestedBy:[...entry.requestedBy]};let pending=[holder];for(;pending.length>0;){let going=new Set(pending);pending=[];for(let[key,entry]of Object.entries(recipes)){let kept=entry.requestedBy.filter(name=>!going.has(name));kept.length!==entry.requestedBy.length&&(kept.length===0?(delete recipes[key],pending.push(key)):entry.requestedBy=kept)}}return withReposOf(lock,recipes,label)}var LOCKFILE_LABEL="the lockfile";function withReposOf(lock,recipes,label){let lockedRepos={},orphaned=[];for(let name of usedRepos(recipes)){let entry=lock.repos[name];if(entry===void 0){orphaned.push(name);continue}lockedRepos[name]=entry}if(orphaned.length>0)throw new ConfigError23(`The lockfile at ${label} pins recipes to repositories it does not describe: ${orphaned.join(", ")}.`,{details:["Every repository a locked recipe came from needs an entry in the lockfile's 'repos' block.","This usually means the file was edited by hand or merged badly. Run 'sous lock rebuild' to rebuild it from your config."]});return{formatVersion:1,repos:lockedRepos,recipes:sortRecipes(recipes)}}function usedRepos(recipes){return sortKeys2(new Set(Object.values(recipes).map(entry=>entry.repo)))}function lockedClosure(lock,roots){let reached=new Set([...roots].filter(key=>Object.hasOwn(lock.recipes,key))),queue=[...reached];for(;queue.length>0;){let holder=queue.shift();for(let[key,entry]of Object.entries(lock.recipes))!reached.has(key)&&entry.requestedBy.includes(holder)&&(reached.add(key),queue.push(key))}return sortKeys2(reached)}function keysHeldBySubscription(lock,key){let heldByProject=entry=>lock.recipes[entry]?.requestedBy.includes(PROJECT_HOLDER)===!0;return key.includes("/")?heldByProject(key)?[key]:[]:sortKeys2(Object.keys(lock.recipes).filter(entry=>entry.startsWith(`${key}/`)&&heldByProject(entry)))}function diffLockfiles(before,after){let added=[],removed=[],updated=[];for(let[key,entry]of Object.entries(after.recipes)){let previous=before.recipes[key];previous===void 0?added.push({key,to:entry.version}):previous.version!==entry.version&&updated.push({key,from:previous.version,to:entry.version})}for(let[key,entry]of Object.entries(before.recipes))Object.hasOwn(after.recipes,key)||removed.push({key,from:entry.version});let byKey=(left,right)=>left.key<right.key?-1:left.key>right.key?1:0,reposAdded=sortKeys2(Object.keys(after.repos).filter(name=>!Object.hasOwn(before.repos,name))),reposRemoved=sortKeys2(Object.keys(before.repos).filter(name=>!Object.hasOwn(after.repos,name)));return added.sort(byKey),removed.sort(byKey),updated.sort(byKey),{added,removed,updated,reposAdded,reposRemoved,unchanged:added.length+removed.length+updated.length+reposAdded.length+reposRemoved.length===0}}function describeLockDiff(diff){let lines3=[];for(let name of diff.reposAdded)lines3.push(`Repository added: ${name}`);for(let change of diff.added)lines3.push(`Adding ${change.key} version ${change.to}`);for(let change of diff.updated)lines3.push(`Updating ${change.key} from version ${change.from} to version ${change.to}`);for(let change of diff.removed)lines3.push(`Removing ${change.key}, which nothing needs any more`);for(let name of diff.reposRemoved)lines3.push(`Repository no longer needed: ${name}`);return diff.unchanged&&lines3.push("Nothing changed."),lines3}function describeError2(error51){return error51 instanceof Error?error51.message:String(error51)}function compareBytewise2(left,right){let a=Buffer.from(left,"utf8"),b=Buffer.from(right,"utf8");return Buffer.compare(a,b)}function sortBytewise(items2){return[...items2].sort(compareBytewise2)}function isPlainObject4(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function entryMap(value){return isPlainObject4(value)?value:{}}var REPO_NAME_PATTERN2=/^[a-z][a-z0-9-]*$/;function shortNameFromIdentity2(identity2){let segments=identity2.split("/").map(segment=>segment.trim().toLowerCase()).filter(segment=>segment.length>0),cleaned=(segments[segments.length-1]??"").replace(/[^a-z0-9-]+/g,"-").replace(/^-+|-+$/g,"");return REPO_NAME_PATTERN2.test(cleaned)?cleaned:cleaned.length===0?"repository":`repo-${cleaned}`}function proposeRepoName(taken,identity2){let used=new Set(taken),base=shortNameFromIdentity2(identity2);if(!used.has(base))return base;for(let suffix=2;;suffix++)if(!used.has(`${base}-${suffix}`))return`${base}-${suffix}`}function hasIntent(ctx,name){return ctx.engine.intents.get(name)!==void 0}function nowIso(){return new Date().toISOString()}function dropProjectHold(lock,key){let entry=lock.recipes[key];if(entry===void 0)return lock;let kept=entry.requestedBy.filter(holder=>holder!==PROJECT_HOLDER),recipes={...lock.recipes};return kept.length>0?(recipes[key]={...entry,requestedBy:kept},{...lock,recipes}):(delete recipes[key],removeHolder({...lock,recipes},key))}function mergeHolders(left,right){let requestedBy=[...new Set([...left.requestedBy,...right.requestedBy])].sort(compareBytewise2),ranges=[...left.ranges];for(let entry of right.ranges)ranges.some(seen=>seen.range===entry.range&&seen.requestedBy===entry.requestedBy)||ranges.push(entry);return{...left,requestedBy,ranges,kind:left.kind==="subscribes"||right.kind==="subscribes"?"subscribes":"depends"}}function covers(cover,key){return cover!==void 0&&(key===cover||key.startsWith(`${cover}/`))}function releaseDroppedHolds(lock,merged,resolvedCovers,otherCovers){let recipes={...lock.recipes},orphaned=[];for(let[key,entry]of Object.entries(lock.recipes)){let settled=merged.get(key),kept=entry.requestedBy.filter(holder=>holder===PROJECT_HOLDER?!resolvedCovers.some(cover=>covers(cover,key))||otherCovers.some(cover=>covers(cover,key))?!0:settled?.requestedBy.includes(PROJECT_HOLDER)===!0:!merged.has(holder)||settled?.requestedBy.includes(holder)===!0);kept.length!==entry.requestedBy.length&&(kept.length===0?(delete recipes[key],orphaned.push(key)):recipes[key]={...entry,requestedBy:kept})}let result={...lock,recipes};for(let key of orphaned)result=removeHolder(result,key);return result}function stayedAfter(after,held){return[...new Set(held)].filter(key=>Object.hasOwn(after.recipes,key)).sort(compareBytewise2).map(key=>({key,heldBy:[...after.recipes[key].requestedBy]}))}var import_semver3=__toESM(require_semver2(),1);import fs26 from"node:fs";import path37 from"node:path";var CORE_NAMESPACE_DESCRIPTION="Skills that teach an agent about sous itself: what sous manages, how its configuration works, how templates render, and how skills are written. Auto-subscribed in every project, with opt-out-only semantics.";function builtInRepoEntry(){return{url:OFFICIAL_REPO_URL,provider:OFFICIAL_REPO_PROVIDER,addedBy:BUILT_IN_ADDED_BY}}function builtInCoreSubscription(version2){return{range:version2,addedBy:BUILT_IN_ADDED_BY}}function isBuiltInEntry(entry){return entry?.addedBy===BUILT_IN_ADDED_BY}function packagedCoreRecipeDir(packageRoot){let root=path37.resolve(packageRoot);for(let tries=0;tries<4;tries+=1){let candidate=path37.join(root,PACKAGED_RECIPES_DIRNAME,CORE_NAMESPACE,CORE_RECIPE_NAME);if(fs26.existsSync(candidate))return candidate;let parent=path37.dirname(root);if(parent===root)break;root=parent}}function coreIndexOverlay(options){let warned=!1,packagedHash=()=>typeof options.hash=="function"?options.hash():options.hash;return(identity2,index)=>{if(identity2!==OFFICIAL_REPO_IDENTITY)return index;let hash2=packagedHash();if(hash2===void 0)return index;let recipe=index.recipes[CORE_RECIPE_KEY],published=recipe?.versions[options.version];if(published!==void 0)return published.hash!==hash2&&!warned&&(warned=!0,options.onMismatch?.(published.hash,hash2)),index;let description=recipe?.description??(typeof options.description=="function"?options.description():options.description);return{...index,namespaces:{...index.namespaces,[CORE_NAMESPACE]:index.namespaces[CORE_NAMESPACE]??{description:CORE_NAMESPACE_DESCRIPTION}},recipes:{...index.recipes,[CORE_RECIPE_KEY]:{...recipe,path:recipe?.path??CORE_RECIPE_PATH,...description===void 0?{}:{description},versions:{...recipe?.versions,[options.version]:{hash:hash2,tag:`${CORE_RECIPE_KEY}@${options.version}`,prerelease:import_semver3.default.prerelease(options.version)!==null,seeded:!0}}}}}}}var USER_ADDED_BY="user";function withoutDisabled(entries){return enabledEntries(typeof entries=="object"&&entries!==null&&!Array.isArray(entries)?entries:void 0)}var REPOS_LAYER="500-repos.jsonc",SUBSCRIPTIONS_LAYER="510-subscriptions.jsonc",REPOS_HEADER=["The recipe repositories this project trusts, written by `sous repo add`.","Sous edits this file key by key; your own edits outside the keys it touches are kept."],SUBSCRIPTIONS_HEADER=["What this project subscribes to, written by `sous subscription add`.","Sous edits this file key by key; your own edits outside the keys it touches are kept."];function configuredRepos(config2){return entryMap(config2.get("repos"))}function trustedRepos(config2){return withoutDisabled(config2.get("repos"))}function configuredSubscriptions(config2){return entryMap(config2.get("subscriptions"))}function enabledSubscriptions2(config2){return withoutDisabled(config2.get("subscriptions"))}function setBy(config2,path103){let layers=config2.layers([...path103]),last2=layers[layers.length-1];return last2===void 0?void 0:contributorLabel(last2.contributor)}function contributorLabel(contributor){return contributor.startsWith("confd/")?`conf.d/${contributor.slice(6)}`:contributor}function managedContributor(file2){return`confd/${file2}`}async function managedEntries(managed,file2,key){let data=await managed.read(file2);return entryMap(data?.[key])}function writeRepoEntry(managed,name,entry,dryRun4=!1){return managed.edit(REPOS_LAYER,root=>root.atPath(["repos",name]).set(entry),{description:REPOS_HEADER,dryRun:dryRun4})}function deleteRepoEntry(managed,name,dryRun4=!1){return managed.edit(REPOS_LAYER,root=>root.atPath(["repos",name]).delete(),{description:REPOS_HEADER,dryRun:dryRun4})}function writeSubscriptionEntry(managed,key,entry,dryRun4=!1){return managed.edit(SUBSCRIPTIONS_LAYER,root=>root.atPath(["subscriptions",key]).set(entry),{description:SUBSCRIPTIONS_HEADER,dryRun:dryRun4})}function deleteSubscriptionEntry(managed,key,dryRun4=!1){return managed.edit(SUBSCRIPTIONS_LAYER,root=>root.atPath(["subscriptions",key]).delete(),{description:SUBSCRIPTIONS_HEADER,dryRun:dryRun4})}function setSubscriptionEnabled(managed,key,enabled,dryRun4=!1){return managed.edit(SUBSCRIPTIONS_LAYER,root=>root.atPath(["subscriptions",key,"enabled"]).set(enabled),{description:SUBSCRIPTIONS_HEADER,dryRun:dryRun4})}function reachableKeys(lock,subscriptions){let roots=Object.entries(subscriptions).filter(([,entry])=>entry?.enabled!==!1).flatMap(([key])=>keysHeldBySubscription(lock,key));return lockedClosure(lock,roots)}var ActiveRecipes=class{constructor(config2,services){this.config=config2;this.services=services}skippedCache;list(){let order=Object.keys(this.lockfile().recipes),position=id=>{let index=order.indexOf(id);return index===-1?order.length:index};return[...this.config.entities.list("active-recipe")].sort((left,right)=>position(left.id)-position(right.id)||compareBytewise2(left.id,right.id))}get(key){return this.config.entities.get("active-recipe",key)}skipped(){return this.skippedCache??=this.findSkipped(),this.skippedCache}contents(kind){return this.services.get("recipes.contents").of(this.list(),kind)}variables(){return this.list().flatMap(recipe=>(recipe.manifest.variables??[]).map(definition=>({recipe,definition})))}lockfile(){try{return this.services.get("recipes.lock").read()}catch{return emptyLockfile()}}reachable(lock){try{return new Set(this.services.get("recipes.resolver").reachable(lock))}catch{return new Set(reachableKeys(lock,configuredSubscriptions(this.config)))}}findSkipped(){let lock=this.lockfile(),active=new Set(this.config.entities.list("active-recipe").map(entity=>entity.id)),reachable2=this.reachable(lock),repos=configuredRepos(this.config),subscriptions=configuredSubscriptions(this.config),skipped=[];for(let[key,entry]of Object.entries(lock.recipes)){if(active.has(key))continue;let repo=repos[entry.repo];if(repo===void 0){skipped.push({key,reason:"untrusted",message:`Skipped ${key}: this project does not trust its repository '${entry.repo}'.`});continue}if(repo.enabled===!1){let file2=setBy(this.config,["repos",entry.repo,"enabled"]);skipped.push({key,reason:"repository-disabled",...file2===void 0?{}:{setBy:file2},message:`Skipped ${key}: its repository '${entry.repo}' is switched off${file2===void 0?"":` (${file2})`}.`});continue}if(reachable2.has(key)){skipped.push({key,reason:"missing",message:`Skipped ${key}: its files are not on this machine yet.`});continue}let off=Object.keys(subscriptions).sort(compareBytewise2).find(subscription=>subscriptions[subscription]?.enabled===!1&&lockedClosure(lock,keysHeldBySubscription(lock,subscription)).includes(key));if(off!==void 0){let file2=setBy(this.config,["subscriptions",off,"enabled"]);skipped.push({key,reason:"subscription-disabled",subscription:off,...file2===void 0?{}:{setBy:file2},message:`Skipped ${key}: its subscription is switched off${file2===void 0?"":` (${file2})`}.`});continue}skipped.push({key,reason:"not-reached",message:`Skipped ${key}: no subscription in force reaches it.`})}return skipped}};var import_semver4=__toESM(require_semver2(),1);import{jsonSchema as jsonSchema11}from"@sous-io/plugin-api";var DEFAULT_STORE_MAX_BYTES=1024*1024*1024,DEFAULT_FRESHNESS_SECONDS2=300,DEFAULT_WATCH_POLL_SECONDS=300,repoEntry={type:"object",description:"One trusted repository. Adding it trusts it.",properties:{url:{type:"string",description:"Where the repository lives."},enabled:{type:"boolean",description:"False opts out of a repository sous provides itself."},provider:{type:"string",description:"The repository host, when the URL does not give it away."},alwaysPull:{type:"boolean",description:"Install a newer in-range version whenever one exists."},addedAt:{type:"string"},addedBy:{type:"string"}},required:["url"],additionalProperties:!1},subscriptionEntry={type:"object",description:"One subscription, to a namespace or to one recipe.",properties:{enabled:{type:"boolean",description:"False switches it off on this machine, keeping its pins."},range:{type:"string",description:"The version range. Default `*`."},prerelease:{type:"boolean"},alwaysPull:{type:"boolean"},addedAt:{type:"string"},addedBy:{type:"string"}},additionalProperties:!1},store={type:"object",description:"The machine-wide recipe store.",default:{},properties:{maxBytes:{type:"integer",default:DEFAULT_STORE_MAX_BYTES,description:"Size cap past which old entries are collected."},freshnessSeconds:{type:"integer",default:DEFAULT_FRESHNESS_SECONDS2,description:"How long a fetched index stays fresh."},watchPollSeconds:{type:"integer",default:DEFAULT_WATCH_POLL_SECONDS,description:"How often watch mode checks upstream."}},additionalProperties:!1},SUBSCRIPTION_KEY_PATTERN=/^[a-z][a-z0-9-]*(\/[a-z][a-z0-9-]*)?$/;function objectOf2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)?value:void 0}function isRepoUrl(url2){return/^[a-z][a-z0-9+.-]*:\/\/\S+$/i.test(url2)||/^[\w.-]+@[\w.-]+:\S+$/.test(url2)||url2.startsWith("/")||/^[A-Za-z]:[\\/]/.test(url2)}function checked2(schema,more){let standard=jsonSchema11(schema)["~standard"];return{"~standard":{...standard,validate(value){let result=standard.validate(value),object3=objectOf2(value),extra=object3===void 0?[]:more(object3);return extra.length===0?result:{issues:[...result.issues??[],...extra]}}}}}function repoIssues(repos){let issues=[];for(let[name,entry]of Object.entries(repos)){REPO_NAME_PATTERN2.test(name)||issues.push({path:[name],message:"invalid key; a repo name must be lowercase kebab-case: a letter, then letters, digits or hyphens (for example 'sous-recipes')"});let url2=objectOf2(entry)?.url;typeof url2=="string"&&!isRepoUrl(url2)&&issues.push({path:[name,"url"],message:"must be a repository URL, or an absolute path to one on this machine"})}return issues}function subscriptionIssues(subscriptions){let issues=[];for(let[key,entry]of Object.entries(subscriptions)){SUBSCRIPTION_KEY_PATTERN.test(key)||issues.push({path:[key],message:"invalid key; a subscription key must be a namespace ('workflow') or a namespace and recipe ('workflow/task-files'), with no repository qualifier and no version range (the range goes in the entry)"});let range3=objectOf2(entry)?.range;typeof range3=="string"&&import_semver4.default.validRange(range3)===null&&issues.push({path:[key,"range"],message:"must be a semantic version range, such as '^1.2.0', '~2.1', '>=1.0.0 <2.0.0' or '*'"})}return issues}function storeIssues(store2){let issues=[];for(let name of["maxBytes","freshnessSeconds","watchPollSeconds"]){let value=store2[name];typeof value=="number"&&(!Number.isInteger(value)||(name==="maxBytes"?value<=0:value<0))&&issues.push({path:[name],message:name==="maxBytes"?"must be a whole number of bytes, above zero":"must be a whole number of seconds, zero or more"})}return issues}function configKeys(){return[{id:"repos",description:"The repositories this project trusts, by short name.",schema:checked2({type:"object",default:{},additionalProperties:repoEntry},repoIssues)},{id:"subscriptions",description:"What this project subscribes to, keyed by namespace or namespace/recipe.",schema:checked2({type:"object",default:{},additionalProperties:subscriptionEntry},subscriptionIssues)},{id:"store",description:"The machine-wide recipe store's settings.",schema:checked2(store,storeIssues)}]}function foldDeclaration(before,entry){let keepBefore=before!==void 0&&!entry.named;return{declared:keepBefore?before.declared:entry.written.trim(),ref:keepBefore?before.ref:entry.ref,kind:before?.kind==="subscribes"||entry.kind==="subscribes"?"subscribes":"depends",named:entry.named||before?.named===!0}}function isNamed(ref){return ref.kind==="namespace"||ref.kind==="recipe"}var Declarations=class{constructor(resolver,format3){this.resolver=resolver;this.format=format3}of(source){let found=[];for(let[kind,entries]of this.lists(source))for(let written of entries){let ref=this.readings(written)[0];ref&&found.push({declared:written.trim(),kind,ref,named:ref.kind==="recipe"})}return found}covering(source,key){let format3=this.format(),gathered;for(let[kind,entries]of[...this.lists(source)].reverse())for(let written of entries)for(let ref of this.readings(written)){let named=ref.kind==="recipe";if(named?format3.key(ref)===key:format3.namespaceOfKey(key)===ref.name){gathered=foldDeclaration(gathered,{written,kind,named,ref});break}}return gathered}lists(source){return[["subscribes",source.subscribes??[]],["depends",source.depends??[]]]}readings(written){try{return this.resolver().parse(written,"manifest").refs.filter(isNamed)}catch{return[]}}};var import_semver7=__toESM(require_semver2(),1);import{SousError as SousError17}from"@sous-io/plugin-api";var import_semver5=__toESM(require_semver2(),1);import{SousError as SousError15}from"@sous-io/plugin-api";function namespaceOfKey3(key){let slash=key.indexOf("/");return slash===-1?key:key.slice(0,slash)}function splitRecipeKey(key){let slash=key.indexOf("/");return{namespace:key.slice(0,slash),name:key.slice(slash+1)}}function listNamespaces(inputs){let subscriptions=new Set(inputs.subscriptions),listings=[];for(let repo of inputs.repos)for(let[namespace,declared]of Object.entries(repo.index.namespaces))listings.push({repo:repo.name,namespace,...declared.description===void 0?{}:{description:declared.description},recipeCount:recipeKeysIn(repo.index,namespace).length,subscribed:coverageOf(namespace,repo.index,subscriptions)});return listings.sort((left,right)=>compareBytewise2(left.namespace,right.namespace)||compareBytewise2(left.repo,right.repo))}function listRecipes(inputs){let subscriptions=new Set(inputs.subscriptions),listings=[];for(let repo of inputs.repos)for(let key of Object.keys(repo.index.recipes))listings.push(recipeListing(key,repo,inputs,subscriptions));return listings.sort((left,right)=>compareBytewise2(left.key,right.key)||compareBytewise2(left.repo,right.repo))}function describeNamespace(inputs,found){let subscriptions=new Set(inputs.subscriptions),declared=found.repo.index.namespaces[found.namespace]??{};return{repo:found.repo.name,...found.repo.url===void 0?{}:{repoUrl:found.repo.url},namespace:found.namespace,...declared.description===void 0?{}:{description:declared.description},subscribed:coverageOf(found.namespace,found.repo.index,subscriptions),recipes:recipeKeysIn(found.repo.index,found.namespace).map(key=>recipeListing(key,found.repo,inputs,subscriptions))}}function describedLocation(inputs,found){let listing=recipeListing(found.key,found.repo,inputs,new Set(inputs.subscriptions)),version2=listing.pinned??listing.latest,entry=found.repo.index.recipes[found.key];return version2===void 0?void 0:{key:found.key,namespace:listing.namespace,name:listing.name,repo:found.repo.name,version:version2,path:entry.path}}function describeRecipe(inputs,found,manifest){let subscriptions=new Set(inputs.subscriptions),listing=recipeListing(found.key,found.repo,inputs,subscriptions),entry=found.repo.index.recipes[found.key],describing=listing.pinned??listing.latest,published=describing===void 0?void 0:entry.versions[describing];return{...listing,...found.repo.url===void 0?{}:{repoUrl:found.repo.url},path:entry.path,...describing===void 0?{}:{describing},versions:versionListings(entry.versions,listing.latest,listing.pinned),dependencies:dependencyListings(published?.dependencies,manifest,inputs),dependenciesRecorded:published?.dependencies!==void 0,contents:(manifest?.contents??[]).map(content=>({kind:content.kind,include:[...content.include],destinations:inputs.destinationsFor?.(content.kind)??[]})),variables:manifest?.variables??published?.variables??[],manifestRead:manifest!==void 0}}function narrowToInstalled(inputs){let repos=inputs.repos.map(repo=>{let recipes=Object.fromEntries(Object.entries(repo.index.recipes).filter(([key])=>inputs.lock.recipes[key]?.repo===repo.name)),held=new Set(Object.keys(recipes).map(namespaceOfKey3)),namespaces=Object.fromEntries(Object.entries(repo.index.namespaces).filter(([namespace])=>held.has(namespace)));return{...repo,index:{...repo.index,recipes,namespaces}}});return{...inputs,repos}}function repoOf2(ref){let repo=ref.kind==="namespace"?ref.repo:ref.namespace?.repo??ref.repo;if(repo!==void 0)return{...repo.name===void 0?{}:{name:repo.name},...repo.location?.identity===void 0?{}:{identity:repo.location.identity}}}function sameText(written,published){return written===published?"exact":written.toLowerCase()===published.toLowerCase()?"folded":void 0}function publishedNamespaceRef(repo,namespace){let declared=repo.index.namespaces[namespace];return{kind:"namespace",name:namespace,repo:{kind:"repo",name:repo.name},...declared?.description===void 0?{}:{description:declared.description}}}function publishedRecipeRef(repo,key){let{namespace,name}=splitRecipeKey(key),description=repo.index.recipes[key]?.description;return{kind:"recipe",name,namespace:{kind:"namespace",name:namespace,repo:{kind:"repo",name:repo.name}},...description===void 0?{}:{description}}}function findInCatalog(inputs,readings,kinds){let matches=new Map,add=match2=>{let id=`${match2.repo.name}:${match2.ref.kind}:${match2.key}`,known=matches.get(id);(known===void 0||!known.exact&&match2.exact)&&matches.set(id,match2)};for(let reading of readings){if(reading.kind!=="namespace"&&reading.kind!=="recipe"||!kinds.includes(reading.kind))continue;let wanted=repoOf2(reading),repos=inputs.repos.filter(repo=>wanted===void 0||wanted.name!==void 0&&sameText(wanted.name,repo.name)!==void 0||wanted.identity!==void 0&&repo.identity!==void 0&&wanted.identity.toLowerCase()===repo.identity.toLowerCase());for(let repo of repos){if(reading.kind==="namespace"){for(let namespace of Object.keys(repo.index.namespaces)){let same=sameText(reading.name,namespace);same&&add({ref:publishedNamespaceRef(repo,namespace),repo,key:namespace,exact:same==="exact"})}continue}for(let key of Object.keys(repo.index.recipes)){let{namespace,name}=splitRecipeKey(key),sameName=sameText(reading.name,name),sameNamespace=reading.namespace===void 0?"exact":sameText(reading.namespace.name,namespace);if(sameName&&sameNamespace){let ref={...publishedRecipeRef(repo,key),...reading.range===void 0?{}:{range:reading.range}};add({ref,repo,key,exact:sameName==="exact"&&sameNamespace==="exact"})}}}}let order=new Map(inputs.repos.map((repo,index)=>[repo.name,index]));return[...matches.values()].sort((left,right)=>Number(right.exact)-Number(left.exact)||(order.get(left.repo.name)??0)-(order.get(right.repo.name)??0)||compareBytewise2(left.key,right.key))}function unknownRefError(inputs,ref,what,notFetched=[]){let searched=inputs.repos.length===0?"none":inputs.repos.map(repo=>repo.name).join(", ");return new SousError15(`No repository this project trusts publishes a ${what} called '${ref}'.`,{details:[`Repositories with an index sous has read: ${searched}.`,...notFetched.length===0?[]:[`These repositories are trusted but their index could not be read, so nothing in them was searched: ${notFetched.join(", ")}.`],`Run 'sous repo search ${ref}' to look for something like it, or 'sous repo add <url>' to add the repository that publishes it.`]})}function recipeKeysIn(index,namespace){return Object.keys(index.recipes).filter(key=>namespaceOfKey3(key)===namespace).sort(compareBytewise2)}function coverageOf(namespace,index,subscriptions){return subscriptions.has(namespace)?"whole namespace":recipeKeysIn(index,namespace).some(key=>subscriptions.has(key))?"some recipes":"none"}function recipeListing(key,repo,inputs,subscriptions){let entry=repo.index.recipes[key],{namespace,name}=splitRecipeKey(key),latest2=latestVersion(entry.versions),locked=inputs.lock.recipes[key],pinned=locked!==void 0&&locked.repo===repo.name?locked.version:void 0,linkedPath=pinned===void 0?void 0:inputs.linked?.[repo.name];return{key,namespace,name,repo:repo.name,...latest2===void 0?{}:{latest:latest2},...pinned===void 0?{}:{pinned},...linkedPath===void 0?{}:{linkedPath},subscribed:subscriptions.has(key)||subscriptions.has(namespace),...entry.description===void 0?{}:{description:entry.description}}}function latestVersion(versions){let all=Object.keys(versions).filter(version2=>import_semver5.default.valid(version2,{loose:!0})!==null),stable=all.filter(version2=>versions[version2]?.prerelease!==!0);return import_semver5.default.maxSatisfying(stable.length>0?stable:all,"*",{includePrerelease:!0,loose:!0})??void 0}function versionListings(versions,latest2,pinned){return Object.keys(versions).sort((left,right)=>{let a=import_semver5.default.valid(left,{loose:!0}),b=import_semver5.default.valid(right,{loose:!0});return a!==null&&b!==null?import_semver5.default.rcompare(a,b,{loose:!0}):compareBytewise2(right,left)}).map(version2=>{let entry=versions[version2];return{version:version2,status:version2===latest2&&version2===pinned?"latest and pinned":version2===latest2?"latest":version2===pinned?"pinned":"other",prerelease:entry.prerelease,...entry.releasedAt===void 0?{}:{releasedAt:entry.releasedAt}}})}function dependencyListings(resolved,manifest,inputs){let rows=new Map,lists=manifest===void 0?void 0:{depends:manifest.depends??[],subscribes:manifest.subscribes??[]};for(let[key,entry]of Object.entries(resolved??{})){let declaration=entry.declared!==void 0&&entry.kind!==void 0?{declared:entry.declared,kind:entry.kind}:lists===void 0?void 0:inputs.declarationFor?.(lists,key);rows.set(key,{key,...entry.version===void 0?{}:{resolvedVersion:entry.version},...entry.range===void 0?{}:{resolvedRange:entry.range},...entry.repo===void 0?{}:{repo:entry.repo},...declaration===void 0?{}:{declared:declaration.declared,kind:declaration.kind}})}let covered=new Set([...rows.values()].map(row=>row.declared));for(let[kind,entries]of[["depends",lists?.depends??[]],["subscribes",lists?.subscribes??[]]])for(let written of entries){if(covered.has(written.trim()))continue;let key=written.trim().replace(/@.*$/,"");rows.set(key,{...rows.get(key)??{key},declared:written,kind})}return[...rows.values()].sort((left,right)=>compareBytewise2(left.key,right.key))}import path39 from"node:path";import path38 from"node:path";function listOf(ctx,kind){try{return ctx.entities.list(kind)}catch{return[]}}function resolveVariables(ctx,value){if(!value.includes("${")||ctx.services===void 0||!ctx.services.has("variables.resolver"))return value;try{let resolver=ctx.services.get("variables.resolver");return resolver.normalizePath(resolver.substituteStrict(value,resolver.scope({level:"root"}),"recipes.skills.outputs"))}catch{return value}}function underRoot(root,target){return root===void 0||path38.isAbsolute(target)||target.startsWith("${")?target:path38.join(root,target)}function distinct(paths){return[...new Set(paths)].sort(compareBytewise2)}function destinationsFor(ctx,kind){let root=ctx.project?.root;if(kind==="skills"){let targets=listOf(ctx,"skill-target").map(target=>target.directory).filter(directory=>typeof directory=="string"&&directory.length>0),outputs=ctx.config.get(["recipes","skills","outputs"]),extra=Array.isArray(outputs)?outputs.filter(output=>typeof output=="string"&&output.length>0):[];return distinct([...targets,...extra].map(target=>underRoot(root,resolveVariables(ctx,target))))}return kind==="memories"?distinct(listOf(ctx,"memory-target").filter(target=>typeof target.fileName=="string"&&target.fileName.length>0).map(target=>underRoot(root,path38.join(typeof target.directory=="string"?target.directory:"",target.fileName)))):[]}function repoSearchOrder(ctx){let repos=trustedRepos(ctx.config),names2=Object.keys(repos),builtIn=names2.filter(name=>isBuiltInEntry(repos[name]));return[...builtIn,...names2.filter(name=>!builtIn.includes(name))]}function identityOf(ctx,url2){try{return ctx.services.get("refs.locations").identity(url2)}catch{return}}async function readUpstream(ctx,name){let cache2=ctx.services.get("recipes.index-cache"),entry=trustedRepos(ctx.config)[name],identity2=entry===void 0?void 0:identityOf(ctx,entry.url),linked=ctx.services.has("recipes.links")&&ctx.services.get("recipes.links").get(name)!==void 0;if(entry===void 0||identity2===void 0||linked)return cache2.get(name,{latest:!0});let index=await cache2.fetchUpstream({name,url:entry.url,identity:identity2,...entry.provider===void 0?{}:{provider:entry.provider}});return{repo:name,index,source:"network"}}async function readIndexes(ctx,flags){let cache2=ctx.services.get("recipes.index-cache"),sources=new Map,notFetched=[],notChecked=[];for(let name of repoSearchOrder(ctx)){if(flags.latest===!0)try{let read=await readUpstream(ctx,name);read.source==="stale"&&notChecked.push({repo:name,reason:read.problem??"upstream could not be reached"}),sources.set(name,read);continue}catch(error51){notChecked.push({repo:name,reason:describeError2(error51)})}let cached2=cache2.cached(name);cached2===void 0?notFetched.push(name):sources.set(name,cached2)}return{notFetched:notFetched.filter(name=>!sources.has(name)),notChecked,sources}}async function loadCatalog(ctx,flags={}){let read=await readIndexes(ctx,flags),trusted=trustedRepos(ctx.config),repos=[...read.sources.entries()].map(([name,cached2])=>{let url2=trusted[name]?.url,identity2=cached2.meta?.identity??(url2===void 0?void 0:identityOf(ctx,url2));return{name,index:cached2.index,...url2===void 0?{}:{url:url2},...identity2===void 0?{}:{identity:identity2}}}),linked={};if(ctx.services.has("recipes.links"))for(let[name,link]of Object.entries(ctx.services.get("recipes.links").all()))linked[name]=link.path;let lock=emptyLockfile();try{lock=ctx.services.get("recipes.lock").read()}catch{}let declarations=ctx.services.has("recipes.declarations")?ctx.services.get("recipes.declarations"):void 0,inputs={repos,lock,subscriptions:Object.keys(enabledSubscriptions2(ctx.config)).sort(),linked,...ctx.entities===void 0?{}:{destinationsFor:kind=>destinationsFor({entities:ctx.entities,config:ctx.config,project:ctx.project,services:ctx.services},kind)},...declarations===void 0?{}:{declarationFor:(source,key)=>{let found=declarations.covering(source,key);return found===void 0?void 0:{declared:found.declared,kind:found.kind}}}};return{...read,inputs:flags.installed===!0?narrowToInstalled(inputs):inputs}}function recipeFilesDirectory(ctx,catalog,location){let checkout=catalog.linked?.[location.repo];if(checkout!==void 0)return path39.join(checkout,location.path);let identity2=catalog.repos.find(repo=>repo.name===location.repo)?.identity??catalog.lock.repos[location.repo]?.identity;if(identity2!==void 0)try{return ctx.services.get("recipes.store").entryDir({identity:identity2,namespace:location.namespace,name:location.name,version:location.version})}catch{return}}async function readPublishedManifest(ctx,catalog,location){let directory=recipeFilesDirectory(ctx,catalog,location);if(directory!==void 0)try{return(await ctx.services.get("formats.manifests").readRecipe(directory))?.manifest}catch{return}}function readingsOf(ctx,input){return ctx.services.get("refs.resolver").parse(input.trim(),"commandLine").refs}async function pickMatch(ctx,matches,search2,acceptFirst2,none,options={}){if(matches.length===0)throw none();let exact=matches.filter(match2=>match2.exact),settled=matches.length===1?matches[0]:acceptFirst2===!0?void 0:exact.length===1?exact[0]:void 0;if(options.announce===!0&&(settled!==void 0||acceptFirst2===!0)){let candidates=settled===void 0?matches:[settled],picked2=await ctx.services.get("refs.picker").pick(candidates.map(match2=>match2.ref),{search:search2,...acceptFirst2===void 0?{}:{acceptFirst:acceptFirst2}},ctx);return candidates.find(match2=>match2.ref===picked2)??candidates[0]}if(settled!==void 0)return settled;if(acceptFirst2===!0)return matches[0];let picked=await ctx.services.get("refs.picker").pick(matches.map(match2=>match2.ref),{search:search2,...acceptFirst2===void 0?{}:{acceptFirst:acceptFirst2}},ctx);return matches.find(match2=>match2.ref===picked)??matches[0]}async function resolveInCatalog(ctx,catalog,input,kinds,acceptFirst2,none){let matches=findInCatalog(catalog.inputs,readingsOf(ctx,input),kinds);return pickMatch(ctx,matches,input.trim(),acceptFirst2,none)}import path40 from"node:path";var import_semver6=__toESM(require_semver2(),1);import{SousError as SousError16}from"@sous-io/plugin-api";var INSTALL_INTENT="plugins.install";function describeUnmet(unmet){return unmet.installed===void 0?`'${unmet.recipe}' requires the plugin ${unmet.plugin} ${unmet.range}, which is not installed.`:`'${unmet.recipe}' requires the plugin ${unmet.plugin} ${unmet.range}, and version ${unmet.installed} is installed.`}function specsOf(unmet){return[...new Set(unmet.map(entry=>`${entry.plugin}@${entry.range}`))]}function unmetRequirements(required2,loaded){let unmet=[];for(let{recipe,plugins}of required2)for(let[plugin,range3]of Object.entries(plugins)){let found=loaded.find(entry=>entry.name===plugin),version2=found?.version;found!==void 0&&(version2===void 0||import_semver6.default.satisfies(version2,range3,{includePrerelease:!0}))||unmet.push({recipe,plugin,range:range3,...found===void 0||version2===void 0?{}:{installed:version2}})}return unmet}async function recipeDirectory(ctx,recipe,download2){let entry=trustedRepos(ctx.config)[recipe.repo];if(!(entry===void 0||!ctx.services.has("recipes.store")||!ctx.services.has("recipes.index-cache"))){if(!download2)try{return(await ctx.services.get("recipes.store").get({identity:recipe.identity,namespace:recipe.namespace,name:recipe.name,version:recipe.version}))?.dir}catch{return}try{return(await ctx.services.get("recipes.index-cache").ensureInStore({key:recipe.key,entry:{repo:recipe.repo,version:recipe.version,hash:recipe.hash,requestedBy:recipe.requestedBy,kind:recipe.kind},repo:recipe.repo,url:entry.url,identity:recipe.identity,...entry.provider===void 0?{}:{provider:entry.provider}},{store:ctx.services.get("recipes.store"),hosts:ctx.entities.list("repository-host"),context:{plugin:ctx.plugin,config:ctx.config,services:ctx.services,entities:ctx.entities,project:ctx.project,env:ctx.env,cwd:ctx.cwd,reporter:ctx.reporter}})).dir}catch{return}}}async function requiredPlugins(ctx,resolved,download2=!0){if(!ctx.services.has("formats.manifests"))return[];let manifests=ctx.services.get("formats.manifests"),required2=[];for(let recipe of resolved){let dir=await recipeDirectory(ctx,recipe,download2);if(dir===void 0)continue;let plugins;try{plugins=(await manifests.readRecipe(dir))?.manifest.requires?.plugins}catch{plugins=void 0}plugins!==void 0&&Object.keys(plugins).length>0&&required2.push({recipe:recipe.key,plugins})}return required2}async function ensureRequiredPlugins(ctx,resolved,flags,ref){let required2=await requiredPlugins(ctx,resolved,flags.dryRun!==!0),unmet=required2.length===0?[]:unmetRequirements(required2,ctx.engine.plugins());if(unmet.length===0)return;let specs=specsOf(unmet);for(let entry of unmet)ctx.reporter.note(describeUnmet(entry));if(flags.dryRun===!0)return{intent:INSTALL_INTENT,skipped:"--dry-run"};let install=flags.installPlugins===!0;if(!install&&ctx.prompter.interactive&&(install=await ctx.prompter.confirm({message:`Install ${specs.join(", ")} now?`,answeredBy:"--install-plugins",default:!0})),!install)throw new SousError16(unmet.length===1?describeUnmet(unmet[0]):`'${ref}' requires plugins that are not installed: ${specs.join(", ")}.`,{details:["Nothing was written.",`Run 'sous subscription add ${ref} --install-plugins' to install ${unmet.length===1?"it":"them"} through this project's package manager, or install ${unmet.length===1?"it":"them"} yourself (for example, 'npm install --save-dev ${specs.join(" ")}').`]});if(!hasIntent(ctx,INSTALL_INTENT))throw new SousError16(`'${ref}' requires ${specs.join(", ")}, and no plugin provides '${INSTALL_INTENT}' to install ${unmet.length===1?"it":"them"}.`,{details:["Nothing was written. Switch on @sous-io/plugin-update, or install the plugins yourself."]});let outputs=await ctx.run(INSTALL_INTENT,{plugins:specs,yes:!0}),result=outputs.toPlain();if(result.declined||result.exitCode!==void 0&&result.exitCode!==0)throw new SousError16(`Sous could not install ${specs.join(", ")}, so nothing was subscribed.`,{details:[result.declined?"The install was declined.":`${[result.command.command,...result.command.args].join(" ")} exited with code ${result.exitCode}.`]});return{intent:INSTALL_INTENT,result,outputs}}var RUNG_LABELS={mapping:"mapping record",recipe:"recipe scope",namespace:"namespace scope",shared:"shared scope",bare:"declared name"};function envFileOf(definition){return definition.secret===!0||definition.scope==="local"?".env.local":".env"}function describeSource(source){let where2=source.file==="shell"?"the shell environment":source.file==="local"?"the .env.local file":"the .env file";return`the ${RUNG_LABELS[source.rung]??source.rung} name ${source.envName}, from ${where2}`}async function variablesOf(ctx,recipe,download2){if(recipe.variables!==void 0)return recipe.variables;if(!ctx.services.has("formats.manifests"))return;let dir=await recipeDirectory(ctx,recipe,download2);if(dir!==void 0)try{return(await ctx.services.get("formats.manifests").readRecipe(dir))?.manifest.variables??[]}catch{return}}async function definedVariables(ctx,resolved,download2=!1){let format3=ctx.services.get("refs.format"),defined=[],unreadable2=[];for(let recipe of[...resolved].sort((left,right)=>left.key<right.key?-1:left.key>right.key?1:0)){let variables=await variablesOf(ctx,recipe,download2);if(variables===void 0){unreadable2.push(recipe.key);continue}for(let definition of variables)defined.push({definition,recipe:{repo:recipe.repo,namespace:recipe.namespace,name:recipe.name,version:recipe.version,identity:recipe.identity},ref:{kind:"variable",name:definition.name,recipe:format3.recipeRef(recipe.namespace,recipe.name,{repo:recipe.repo})},key:`${recipe.key}.${definition.name}`})}return{defined,unreadable:unreadable2}}function plannedQuestionsOf(ctx,defined){let ladder=ctx.services.has("recipe-answers.ladder")?ctx.services.get("recipe-answers.ladder"):void 0;return defined.map(variable=>{let{definition}=variable,found,storedAs;try{found=ladder?.resolve(variable),storedAs=ladder?.bareName(variable)}catch{}return{recipe:`${variable.recipe.namespace}/${variable.recipe.name}`,definition,...storedAs===void 0?{}:{storedAs},...ctx.project===void 0?{}:{storagePath:path40.join(ctx.project.sousDir,envFileOf(definition))},answered:found!==void 0,...found===void 0?{}:{answeredFrom:describeSource(found.source)}}})}async function planQuestions(ctx,resolved){let{defined,unreadable:unreadable2}=await definedVariables(ctx,resolved);return{questions:plannedQuestionsOf(ctx,defined),unreadable:unreadable2}}import{commandVariables}from"@sous-io/plugin-api";import{IntentOutput as IntentOutput5,IntentOutputs as IntentOutputs9,ItemList as ItemList2,ReportEntryStyle as ReportEntryStyle3,Table as Table2,TextBlock as TextBlock5,VariableSet as VariableSet3}from"@sous-io/plugin-api";function sentence(summary,title2){return new IntentOutput5({...title2===void 0?{}:{title:title2},summary})}function noteOutput(text,title2){return new IntentOutput5({...title2===void 0?{}:{title:title2},result:new TextBlock5(text),style:ReportEntryStyle3.Note})}function dryRunOutput(text,title2){return new IntentOutput5({...title2===void 0?{}:{title:title2},result:new TextBlock5(text),style:ReportEntryStyle3.DryRun})}function detailOutput(text,title2){return new IntentOutput5({...title2===void 0?{}:{title:title2},result:new TextBlock5(text),style:ReportEntryStyle3.Detail})}function listOutput(items2,options={}){return new IntentOutput5({...options.heading===void 0?{}:{title:options.heading},result:new ItemList2(items2,options.listTitle===void 0?{}:{title:options.listTitle})})}function blockOutput(entries,options={}){return new IntentOutput5({...options.heading===void 0?{}:{title:options.heading},result:new VariableSet3(entries,options.blockTitle===void 0?{}:{title:options.blockTitle})})}function tableOutput(columns,rows,options={}){return new IntentOutput5({...options.heading===void 0?{}:{title:options.heading},result:new Table2(columns,rows,{...options.tableTitle===void 0?{}:{title:options.tableTitle},...options.empty===void 0?{}:{empty:options.empty},...options.rowNotes===void 0?{}:{rowNotes:options.rowNotes}})})}function retitled(output,title2){return new IntentOutput5({title:title2,...output.summary===void 0?{}:{summary:output.summary},...output.result===void 0?{}:{result:output.result},...output.data===void 0?{}:{data:output.data},...output.style===void 0?{}:{style:output.style}})}function underHeading(heading,outputs){let[first2,...rest]=outputs;return first2===void 0?[new IntentOutput5({title:heading})]:first2.title===void 0?[retitled(first2,heading),...rest]:[new IntentOutput5({title:heading}),first2,...rest]}function finish2(own,data,options={}){let exit=options.exitCode===void 0?{}:{exitCode:options.exitCode};return new IntentOutputs9([...own,...options.after??[]],exit).withData(data)}function plainFollowUps(followUps){return followUps.map(entry=>({intent:entry.intent,...entry.result===void 0?{}:{result:entry.result},...entry.skipped===void 0?{}:{skipped:entry.skipped}}))}function plainResult(result){return{...result,followUps:plainFollowUps(result.followUps)}}function followUpOf(result,intent){return result.followUps?.find(entry=>entry.intent===intent)}function rebuilt(result){let build2=followUpOf(result,"build");return build2!==void 0&&build2.skipped===void 0}function buildFailed(entry){return(entry.outputs?.exitCode??0)!==0||entry.result?.ok===!1}function followUpOutputs(result){let outputs=[],failed=!1;for(let entry of result.followUps??[]){if(entry.skipped!==void 0||entry.outputs===void 0)continue;let shown=entry.outputs.toArray();outputs.push(...entry.intent==="vars.ask"?underHeading("Variables",shown):shown),entry.intent==="build"&&buildFailed(entry)&&(failed=!0)}return{outputs,failed}}function finishWithFollowUps(ctx,own,result,failedMessage){let{outputs,failed}=followUpOutputs(result);return failed&&ctx.reporter.error(failedMessage),finish2(own,plainResult(result),{after:outputs,...failed?{exitCode:1}:{}})}function lockDiffLines(diff){let byKey=(left,right)=>left.key<right.key?-1:left.key>right.key?1:0,lines3=[...diff.reposAdded.map(name=>`Repository added: ${name}`),...[...diff.added].sort(byKey).map(change=>`Adding ${change.key} version ${change.to}`),...[...diff.updated].sort(byKey).map(change=>`Updating ${change.key} from version ${change.from} to version ${change.to}`),...[...diff.removed].sort(byKey).map(change=>`Removing ${change.key}, which nothing needs any more`),...diff.reposRemoved.map(name=>`Repository no longer needed: ${name}`)];return lines3.length===0?["Nothing changed."]:lines3}function lockfileOutput(diff,whenUnchanged){return diff.unchanged?sentence(whenUnchanged,"Lockfile"):listOutput(lockDiffLines(diff),{heading:"Lockfile"})}function describeSize(bytes){if(bytes<1024)return`${bytes} bytes`;let units=["KB","MB","GB","TB"],value=bytes/1024,unit=0;for(;value>=1024&&unit<units.length-1;)value/=1024,unit+=1;return`${value.toFixed(1)} ${units[unit]}`}function firstSentence(text){return(/^.*?[.!?](?=\s|$)/s.exec(text.trim())?.[0]??text.trim()).replace(/\s+/g," ")}function questionCount(count2){return count2===1?"1 question":`${count2} questions`}function questionFacts(question,answerHint){let variable=question.definition,entries=[];return variable.description!==void 0&&variable.description!==""&&entries.push({label:"about",value:firstSentence(variable.description)}),variable.example!==void 0&&entries.push({label:"example",value:String(variable.example)}),question.storedAs!==void 0&&question.storedAs!==""&&entries.push({label:"stored-as",value:question.storedAs}),question.storagePath!==void 0&&question.storagePath!==""&&entries.push({label:"storage-path",value:question.storagePath}),entries.push({label:"answered",value:question.answered?`yes${question.answeredFrom===void 0?"":`, from ${question.answeredFrom}`}`:variable.required===!1?"no, and an answer is optional":"no, and this recipe requires an answer"}),answerHint&&entries.push({label:"answer-with",value:`--answer ${variable.name}=<value>`}),entries}function questionPlanOutputs(plan,options){let count2=plan.questions.length,unanswered=plan.questions.filter(question=>!question.answered).length,unreadable2=plan.unreadable.length===0?void 0:`Not on this machine yet, and their repository's index does not record their questions, so they cannot be listed: ${plan.unreadable.join(", ")}.`+(options.answerHints?" A dry run downloads nothing; run this command again without '--dry-run' to install them and be asked.":"");if(count2===0)return[unreadable2===void 0?sentence("None of these recipes ask any questions, so nothing needs answering."):noteOutput(unreadable2)];let subject2=plan.unreadable.length===0?"These recipes ask":"The recipes sous could read ask",outputs=[sentence(unanswered===0?`${subject2} ${questionCount(count2)}, and everything they ask is already answered.`:`${subject2} ${questionCount(count2)}, ${unanswered} of which nothing answers yet.`)],groups=new Map;for(let question of plan.questions)groups.set(question.recipe,[...groups.get(question.recipe)??[],question]);for(let[recipe,questions]of groups)questions.forEach((question,index)=>{outputs.push(blockOutput(questionFacts(question,options.answerHints),{blockTitle:question.definition.name,...index===0?{heading:`${recipe} asks ${questionCount(questions.length)}:`}:{}}))});return unreadable2!==void 0&&outputs.push(noteOutput(unreadable2)),options.answerHints&&unanswered>0&&outputs.push(noteOutput("Answer them all ahead of time by running this command again without '--dry-run', with one '--answer <name>=<value>' for each, or with '--answers-file <path>'.")),outputs}var RECIPE_COLUMNS=[{key:"key",header:"Recipe",kind:"path",overflow:"truncate",minWidth:12},{key:"repo",header:"Repository",overflow:"truncate",priority:"medium"},{key:"latest",header:"Latest",overflow:"truncate",minWidth:6},{key:"pinned",header:"Pinned",overflow:"truncate",minWidth:6},{key:"subscribed",header:"Subscribed",priority:"medium"},{key:"description",header:"What it is",overflow:"wrap",flex:1,priority:"low",minWidth:16}],NAMESPACE_COLUMNS=[{key:"namespace",header:"Namespace",overflow:"truncate",minWidth:10},{key:"repo",header:"Repository",overflow:"truncate",priority:"medium"},{key:"recipes",header:"Recipes",kind:"number",priority:"medium"},{key:"subscribed",header:"Subscribed",priority:"medium"},{key:"description",header:"What it is",overflow:"wrap",flex:1,priority:"low",minWidth:16}],VERSION_COLUMNS=[{key:"version",header:"Version",overflow:"truncate",minWidth:7},{key:"status",header:"What it is",overflow:"wrap",flex:1,minWidth:16},{key:"prerelease",header:"Prerelease",priority:"medium"},{key:"released",header:"Released",overflow:"truncate",priority:"low"}],DEPENDENCY_COLUMNS=[{key:"key",header:"Dependency",kind:"path",overflow:"truncate",minWidth:12},{key:"declared",header:"Declared as",overflow:"wrap",flex:1,minWidth:12},{key:"resolved",header:"Resolved to",overflow:"truncate",minWidth:11},{key:"repo",header:"Repository",overflow:"truncate",priority:"low",minWidth:12},{key:"kind",header:"Kind",overflow:"wrap",priority:"medium",minWidth:16}],INSTALLS_COLUMNS=[{key:"key",header:"Recipe",kind:"path",overflow:"truncate",minWidth:12},{key:"version",header:"Version",overflow:"truncate",minWidth:7},{key:"kind",header:"Kind",overflow:"wrap",minWidth:16},{key:"neededBy",header:"Needed by",overflow:"wrap",flex:1,priority:"low",minWidth:16}],CONTENT_COLUMNS=[{key:"kind",header:"Content",minWidth:7},{key:"include",header:"Files",overflow:"wrap",flex:1,minWidth:14},{key:"destination",header:"Where they land",kind:"path",overflow:"wrap",flex:2,minWidth:16}],SEARCH_COLUMNS=[{key:"key",header:"Match",kind:"path",overflow:"truncate",minWidth:12},{key:"kind",header:"Kind",minWidth:4},{key:"versions",header:"Versions",overflow:"truncate",minWidth:7},{key:"repo",header:"Repository",overflow:"truncate",priority:"medium"},{key:"description",header:"What it is",overflow:"wrap",flex:1,priority:"low",minWidth:16}],INSTALLED_SEARCH_COLUMNS=[{key:"key",header:"Recipe",kind:"path",overflow:"truncate",minWidth:12},{key:"installed",header:"Installed",overflow:"truncate",minWidth:9},{key:"versions",header:"Versions",overflow:"truncate",minWidth:7},{key:"repo",header:"Repository",overflow:"truncate",priority:"medium"},{key:"description",header:"What it is",overflow:"wrap",flex:1,priority:"low",minWidth:16}],REPO_COLUMNS=[{key:"name",header:"Repository",overflow:"truncate",minWidth:8},{key:"provider",header:"Provider",priority:"medium"},{key:"origin",header:"Origin"},{key:"linked",header:"Linked",kind:"path",overflow:"truncate",priority:"medium",minWidth:6},{key:"recipes",header:"Recipes",kind:"number",priority:"low",minWidth:11},{key:"url",header:"URL",kind:"url",overflow:"truncate",truncate:"middle",priority:"low",flex:1,minWidth:12}],SUBSCRIPTION_COLUMNS=[{key:"key",header:"Subscription",kind:"path",overflow:"truncate",minWidth:12},{key:"range",header:"Range",overflow:"truncate",minWidth:7},{key:"pinned",header:"Pinned version",flex:1,minWidth:14},{key:"latest",header:"Latest version",overflow:"wrap",priority:"medium",minWidth:14},{key:"origin",header:"Origin",priority:"medium"},{key:"enabled",header:"Enabled",priority:"medium"}],LINKED_NOTE="A recipe marked linked is pinned at the version shown, but builds currently read it from the linked checkout of its repository.";function recipeColumns(installed2){return installed2?RECIPE_COLUMNS.map(column=>column.key==="pinned"?{...column,header:"Installed"}:column):RECIPE_COLUMNS}function pinnedCell(pinned,linkedPath){return pinned===void 0?"":linkedPath===void 0?pinned:`${pinned} linked`}function recipeRows(listings){return listings.map(entry=>({key:entry.key,repo:entry.repo,latest:entry.latest??"none published",pinned:pinnedCell(entry.pinned,entry.linkedPath),subscribed:entry.subscribed?"yes":"no",description:entry.description??"no description published"}))}function describeCoverage(coverage){return coverage==="whole namespace"?"the whole namespace":coverage==="some recipes"?"some recipes":"no"}function describeVersionStatus(status){switch(status){case"latest and pinned":return"the latest version, and the one pinned here";case"latest":return"the latest version";case"pinned":return"the version pinned here";default:return"an earlier version"}}function describeDependencyKind(kind){return kind==="depends"?"build dependency":kind==="subscribes"?"co-subscription":"not recorded"}function describeOrigin(addedBy){return addedBy===BUILT_IN_ADDED_BY?"built in":addedBy===void 0||addedBy===USER_ADDED_BY?"user":`required by ${addedBy}`}function noDestinationText(kind){switch(kind){case"config":return"loaded as a config layer, so nothing is written";case"memories":return"reaches an agent through an include line in its instructions, so nothing is written";case"skills":return"nowhere: this project sets no 'recipes.skills.outputs' directory";default:return`nowhere: this project has no destination for ${kind} yet`}}function describeDeclaration(declared){let match2=/^(?:([a-z0-9][a-z0-9._-]*):)?([a-z][a-z0-9-]*)(?:@.*)?$/i.exec(declared.trim());return match2===null?declared:match2[1]===void 0?`the whole '${match2[2]}' namespace`:`the whole '${match2[2]}' namespace of ${match2[1]}`}function factIf(label,value){return value===void 0||value.length===0?[]:[{label,value}]}function browsingVariables(ctx,input,asked={}){let extra={};for(let[label,value]of Object.entries(asked))value!==void 0&&(extra[label]=value);return extra.Reading=input.latest===!0?"each repository, upstream":"the cached indexes",input.installed===!0&&(extra.Showing="only what this project has installed"),commandVariables(ctx,extra)}function namespaceListOutputs(ctx,input,result){let installed2=input.installed===!0,columns=installed2?NAMESPACE_COLUMNS.map(column=>column.key==="recipes"?{...column,header:"Installed"}:column):NAMESPACE_COLUMNS;return finish2([browsingVariables(ctx,input),tableOutput(columns,result.map(entry=>({namespace:entry.namespace,repo:entry.repo,recipes:String(entry.recipeCount),subscribed:describeCoverage(entry.subscribed),description:entry.description??"no description published"})),{heading:installed2?"Namespaces this project has installed recipes from":"Namespaces in the repositories this project trusts",empty:installed2?"This project has installed no recipe from the repositories it trusts.":"The repositories this project trusts publish no namespaces."})],{namespaces:[...result]})}function namespaceShowOutputs(ctx,input,detail){let installed2=input.installed===!0,outputs=[browsingVariables(ctx,input,{Namespace:input.ref}),blockOutput([{label:"Repository",value:detail.repo},...factIf("Location",detail.repoUrl),...factIf("About",detail.description),{label:installed2?"Installed recipes":"Recipes",value:String(detail.recipes.length)},{label:"Subscribed",value:describeCoverage(detail.subscribed)}],{heading:`The namespace ${detail.namespace}`}),tableOutput(recipeColumns(installed2),recipeRows(detail.recipes),{tableTitle:`Recipes in ${detail.namespace}`,empty:`The repository ${detail.repo} publishes no recipes in this namespace.`})];return detail.recipes.some(entry=>entry.linkedPath!==void 0)&&outputs.push(noteOutput(LINKED_NOTE)),finish2(outputs,detail)}function recipeListOutputs(ctx,input,result){let installed2=input.installed===!0,outputs=[browsingVariables(ctx,input),tableOutput(recipeColumns(installed2),recipeRows(result),{heading:installed2?"Recipes this project has installed":"Recipes in the repositories this project trusts",empty:installed2?"This project has installed no recipe from the repositories it trusts.":"The repositories this project trusts publish no recipes."})];return result.some(entry=>entry.linkedPath!==void 0)&&outputs.push(noteOutput(LINKED_NOTE)),finish2(outputs,{recipes:[...result]})}function installsOutputs(detail){let outputs=[tableOutput(INSTALLS_COLUMNS,(detail.installs??[]).map(recipe=>{let holders=recipe.requestedBy.filter(holder=>holder!=="project");return{key:recipe.key,version:recipe.version,kind:recipe.requestedBy.includes("project")?"the subscription itself":describeDependencyKind(recipe.kind),neededBy:holders.length===0?"this subscription":holders.join(", ")}}),{tableTitle:"What subscribing installs"})],missing=detail.installsNeed??[];return missing.length>0&&outputs.push(sentence(`Subscribing also needs ${missing.length===1?"a repository":"repositories"} this project does not trust yet, so what ${missing.length===1?"it publishes":"they publish"} is not listed above: `+missing.map(entry=>`${entry.name}${entry.url===void 0?"":` (${entry.url})`}, needed by ${entry.requiredBy.map(holder=>holder.requestedBy).join(", ")}`).join("; ")+".")),outputs}function recipeShowOutputs(ctx,input,detail){let installed2=input.installed===!0,outputs=[browsingVariables(ctx,input,{Recipe:input.ref}),blockOutput([{label:"Repository",value:detail.repo},...factIf("Location",detail.repoUrl),...factIf("About",detail.description),{label:"Folder",value:detail.path},{label:"Latest version",value:detail.latest??"none published"},{label:installed2?"Installed version":"Pinned version",value:detail.pinned??"this project pins none"},...factIf("Linked",detail.linkedPath===void 0?void 0:`builds currently read this recipe from the checkout at ${detail.linkedPath}`),{label:"Subscribed",value:detail.subscribed?"yes":"no"},...factIf("Described below",detail.describing)],{heading:detail.key}),tableOutput(VERSION_COLUMNS,detail.versions.map(entry=>({version:entry.version,status:describeVersionStatus(entry.status),prerelease:entry.prerelease?"yes":"no",released:entry.releasedAt??"not recorded"})),{tableTitle:"Published versions"}),tableOutput(DEPENDENCY_COLUMNS,detail.dependencies.map(entry=>({key:entry.key,declared:entry.declared===void 0?"not recorded in the index":describeDeclaration(entry.declared),resolved:entry.resolvedVersion??(entry.resolvedRange===void 0?"not recorded in the index":`the range ${entry.resolvedRange}`),repo:entry.repo??"this repository",kind:describeDependencyKind(entry.kind)})),{tableTitle:"What it depends on",empty:detail.manifestRead||detail.dependenciesRecorded?"This recipe depends on nothing else.":"The repository's index records no dependencies for this version."})];return detail.describing===void 0?outputs.push(sentence("This recipe publishes no version a subscription would install, so nothing is described below.")):detail.installsProblem!==void 0||detail.installs===void 0||detail.questions===void 0?outputs.push(sentence(detail.installsProblem??"Sous could not work out what subscribing would install.")):outputs.push(...installsOutputs(detail),...underHeading("What subscribing asks you",questionPlanOutputs(detail.questions,{answerHints:!1}))),outputs.push(tableOutput(CONTENT_COLUMNS,detail.manifestRead?detail.contents.map(entry=>({kind:entry.kind,include:entry.include.join(", "),destination:entry.destinations.length>0?entry.destinations.join(", "):noDestinationText(entry.kind)})):[],{tableTitle:"Where its files land in this project",empty:detail.manifestRead?"This recipe publishes no files.":"The recipe's own files are not on this machine, so the files it publishes are not known here. Subscribing to it fetches them."})),finish2(outputs,detail)}function repoSearchOutputs(ctx,input,result){let installed2=input.installed===!0,outputs=[browsingVariables(ctx,input,{Searching:input.text}),tableOutput(installed2?INSTALLED_SEARCH_COLUMNS:SEARCH_COLUMNS,result.map(match2=>({key:match2.key,kind:match2.kind,versions:match2.versions?.join(", ")??"",installed:match2.installed??"",repo:match2.repo,description:match2.description!==void 0&&match2.description.length>0?match2.description:"no description published"})),{heading:"Recipes matching your search",empty:installed2?`Nothing this project has installed matches '${input.text}'.`:`Nothing in the repositories this project trusts matches '${input.text}'.`})],limit2=input.limit??20;return result.length>0&&result.length>=limit2&&outputs.push(sentence(`Only the first ${limit2} matches are shown. Raise the number with '--limit'.`)),finish2(outputs,{matches:[...result]})}function repoNote(entry,verbose){let notes=[];if(entry.enabled||notes.push("Switched off in the config, so nothing is read from it."),verbose){let namespaces=entry.namespaces===void 0?"not fetched":entry.namespaces.length>0?entry.namespaces.join(", "):"none";notes.push(`Namespaces: ${namespaces}`)}return entry.installed!==void 0&&entry.installed.length>0&&notes.push(`Installed: ${entry.installed.map(pin=>`${pin.key} ${pin.version}`).join(", ")}`),notes.length>0?notes.join(" "):void 0}function repoListOutputs(ctx,input,result){let verbose=input.verbose===!0,outputs=[browsingVariables(ctx,input),tableOutput(REPO_COLUMNS,result.map(entry=>({name:entry.name,url:entry.url,provider:entry.provider,origin:describeOrigin(entry.addedBy),linked:entry.linkedPath===void 0?"no":`yes: ${entry.linkedPath}`,recipes:entry.recipeCount===void 0?"not fetched":String(entry.recipeCount)})),{heading:input.installed===!0?"Repositories this project has installed recipes from":"Repositories this project trusts",empty:"This project trusts no repositories yet. Add one with 'sous repo add <url>'; adding a repository is how you trust it.",rowNotes:result.map(entry=>repoNote(entry,verbose))})];for(let entry of result)entry.problem!==void 0&&ctx.reporter.warn(`${entry.name} could not be checked upstream, so it is shown from the cache: ${entry.problem}`);return finish2(outputs,{repos:[...result]})}function describePinned(pinned,enabled){return pinned.length>0?pinned.map(entry=>`${entry.key} ${entry.version}`).join(", "):enabled?"pinned on first build":"not pinned"}function describeLatest(listing){if(listing.pinned.length===0)return"";let published=new Map((listing.latest??[]).map(entry=>[entry.key,entry.version])),newer=new Map((listing.newer??[]).map(entry=>[entry.key,entry.version])),latestOf=(key,pinned)=>listing.latest===void 0?newer.get(key)??pinned:published.get(key)??"not in any index sous has read";if(listing.pinned.length===1){let only=listing.pinned[0];return latestOf(only.key,only.version)}return listing.pinned.map(pin=>`${pin.key} ${latestOf(pin.key,pin.version)}`).join(", ")}function describeSubscriptionOrigin(addedBy){return addedBy===BUILT_IN_ADDED_BY?"built in":addedBy===void 0||addedBy===USER_ADDED_BY?"user":addedBy}function subscriptionListOutputs(ctx,input,result){let installed2=input.installed===!0,listings=result.filter(entry=>!installed2||entry.pinned.length>0),columns=SUBSCRIPTION_COLUMNS.map(column=>installed2&&column.key==="pinned"?{...column,header:"Installed version"}:column);return finish2([browsingVariables(ctx,input),tableOutput(columns,listings.map(entry=>({key:entry.key,range:entry.range??"any version",pinned:describePinned(entry.pinned,entry.enabled),latest:describeLatest(entry),origin:describeSubscriptionOrigin(entry.addedBy),enabled:entry.enabled?"yes":"no"})),{heading:"Subscriptions",empty:installed2?"No subscription of this project has installed anything yet.":"This project subscribes to nothing yet."})],{subscriptions:listings})}import{jsonSchema as jsonSchema12}from"@sous-io/plugin-api";function inputSchema(properties,required2=[]){return jsonSchema12({type:"object",properties,required:required2,additionalProperties:!1})}var dryRun={type:"boolean",description:"Show what would change, writing nothing"},noBuild={type:"boolean",description:"Change it without rebuilding the project afterwards"},yes={type:"boolean",description:"Answer yes to every question, trusting new repositories without asking"},acceptFirst={type:"boolean",description:"When a ref matches several things, take the first one listed"},answer={type:"array",items:{type:"string"},description:"Answer a recipe question ahead of time, as name=value (repeatable)"},answersFile={type:"string",description:"A file of answers to recipe questions (YAML, JSON, JSONC or .env)"},latest={type:"boolean",description:"Check upstream for newer indexes first"},installed={type:"boolean",description:"Show only what this project has installed, never going upstream"},browsing={latest,installed},yesFlag={short:"y",aliases:["force","trust"]},yesFlagNoTrust={short:"y",aliases:["force"]},latestFlag={aliases:["remote"]};var browsingCli={flags:{latest:latestFlag}};function reportUnread(ctx,catalog){if(catalog.notFetched.length>0&&ctx.reporter.note(`These repositories are trusted and their index has not been fetched yet, so nothing in them is listed: ${catalog.notFetched.join(", ")}.`),catalog.notChecked.length>0){ctx.reporter.note(`These repositories could not be reached, so they are shown from the cache and were not checked: ${catalog.notChecked.map(entry=>entry.repo).join(", ")}.`);for(let entry of catalog.notChecked)ctx.reporter.debug(`${entry.repo}: ${entry.reason}`)}}async function showNamespace(input,ctx){let catalog=await loadCatalog(ctx,input);reportUnread(ctx,catalog);let readings=readingsOf(ctx,input.ref);if(readings.every(reading=>reading.kind==="recipe"&&reading.namespace!==void 0)){let recipe=findInCatalog(catalog.inputs,readings,["recipe"])[0];if(recipe!==void 0)throw new SousError17(`'${input.ref}' names the recipe '${recipe.key}', not a namespace.`,{details:[`The namespace it belongs to is '${recipe.key.split("/")[0]}'.`]})}let found=await resolveInCatalog(ctx,catalog,input.ref,["namespace"],input.acceptFirst,()=>{let asRecipe=findInCatalog(catalog.inputs,readings,["recipe"]);return input.installed!==!0&&asRecipe.length>0&&!readings.some(reading=>reading.kind==="namespace"&&reading.repo!==void 0)?new SousError17(`No repository this project trusts publishes a namespace called '${input.ref}'.`,{details:["It is the name of a recipe:",...asRecipe.map(match2=>` ${match2.repo.name}:${match2.key}`)]}):installedError(input,"namespace")??unknownRefError(catalog.inputs,input.ref,"namespace",catalog.notFetched)});return describeNamespace(catalog.inputs,{repo:found.repo,namespace:found.key})}async function showRecipe(input,ctx){let catalog=await loadCatalog(ctx,input);reportUnread(ctx,catalog);let found=await resolveInCatalog(ctx,catalog,input.ref,["recipe"],input.acceptFirst,()=>{let asNamespace=findInCatalog(catalog.inputs,readingsOf(ctx,input.ref),["namespace"]);return asNamespace.length>0?new SousError17(`No repository this project trusts publishes a recipe called '${input.ref}'.`,{details:["It is the name of a namespace:",...asNamespace.map(match2=>` ${match2.repo.name}:${match2.key}`)]}):installedError(input,"recipe")??unknownRefError(catalog.inputs,input.ref,"recipe",catalog.notFetched)}),location=describedLocation(catalog.inputs,{repo:found.repo,key:found.key}),manifest=location===void 0?void 0:await readPublishedManifest(ctx,catalog.inputs,location),detail=describeRecipe(catalog.inputs,{repo:found.repo,key:found.key},manifest);return{...detail,...await previewSubscription(ctx,catalog,detail)}}async function previewSubscription(ctx,catalog,detail){if(detail.describing===void 0)return{};let prerelease=import_semver7.default.prerelease(detail.describing)!==null;try{let result=await ctx.services.get("recipes.resolver").resolve([{ref:ctx.services.get("refs.format").recipeRef(detail.namespace,detail.name,{repo:detail.repo,range:detail.describing}),range:detail.describing,requestedBy:PROJECT_HOLDER,kind:"subscribes",...prerelease?{prerelease:!0}:{}}],{indexes:new Map(catalog.inputs.repos.map(repo=>[repo.name,repo.index])),...prerelease?{prerelease:!0}:{}});return{installs:result.resolved.map(recipe=>({key:recipe.key,version:recipe.version,kind:recipe.kind,requestedBy:recipe.requestedBy})),installsNeed:result.missingRepos,questions:await planQuestions(ctx,result.resolved)}}catch(error51){return{installsProblem:`Sous could not work out what subscribing to version ${detail.describing} would install. ${describeError2(error51)}`}}}function installedError(input,what){if(input.installed===!0)return new SousError17(what==="namespace"?`This project has installed no recipe from the namespace '${input.ref}', so there is nothing to show with '--installed'.`:`This project has not installed the recipe '${input.ref}', so there is nothing to show with '--installed'.`)}function registerCatalogIntents(sous){sous.intents.add({intent:"namespace.list",requiresProject:!0,summary:"List the namespaces in the repositories this project trusts",input:inputSchema(browsing),parallel:!0,cli:{aliases:[["namespaces","list"]],...browsingCli},agent:{usage:"Call this before subscribing, to find which namespaces exist."},handle:async(input,ctx)=>{let catalog=await loadCatalog(ctx,input);return reportUnread(ctx,catalog),namespaceListOutputs(ctx,input,listNamespaces(catalog.inputs))}}),sous.intents.add({intent:"namespace.show",requiresProject:!0,summary:"Show one namespace and every recipe in it",input:inputSchema({ref:{type:"string",description:"The namespace, optionally as repository:namespace"},...browsing,acceptFirst},["ref"]),parallel:!0,cli:{aliases:[["namespaces","show"]],positional:["ref"],...browsingCli},handle:async(input,ctx)=>namespaceShowOutputs(ctx,input,await showNamespace(input,ctx))}),sous.intents.add({intent:"recipe.list",requiresProject:!0,summary:"List the recipes in the repositories this project trusts",input:inputSchema(browsing),parallel:!0,cli:{aliases:[["recipes","list"]],...browsingCli},handle:async(input,ctx)=>{let catalog=await loadCatalog(ctx,input);return reportUnread(ctx,catalog),recipeListOutputs(ctx,input,listRecipes(catalog.inputs))}}),sous.intents.add({intent:"recipe.show",requiresProject:!0,summary:"Show one recipe: its versions, dependencies, contents and questions",input:inputSchema({ref:{type:"string",description:"The recipe: namespace/recipe, a bare name, or either as repository:ref"},...browsing,acceptFirst},["ref"]),parallel:!0,cli:{aliases:[["recipes","show"]],positional:["ref"],...browsingCli},handle:async(input,ctx)=>recipeShowOutputs(ctx,input,await showRecipe(input,ctx))})}var import_semver8=__toESM(require_semver2(),1);import fs27 from"node:fs";import os6 from"node:os";import path41 from"node:path";import{ConfigError as ConfigError24,LogLevel as LogLevel5,SousError as SousError19}from"@sous-io/plugin-api";async function askFollowUp(ctx,flags,recipes){if(flags.dryRun===!0)return{intent:"vars.ask",skipped:"--dry-run"};if(!hasIntent(ctx,"vars.ask"))return{intent:"vars.ask",skipped:"no plugin provides vars.ask"};if(recipes.length===0&&flags.answer===void 0&&flags.answersFile===void 0)return{intent:"vars.ask",skipped:"nothing new to ask"};let result=await ctx.run("vars.ask",{...recipes.length===0?{}:{within:[...recipes]},...flags.answer===void 0?{}:{answer:flags.answer},...flags.answersFile===void 0?{}:{answersFile:flags.answersFile}});return ctx.chain!==void 0&&!ctx.chain.parallel&&await ctx.refreshConfig(),{intent:"vars.ask",result:result.toPlain(),outputs:result}}async function buildFollowUp(ctx,flags){if(flags.dryRun===!0)return{intent:"build",skipped:"--dry-run"};if(flags.noBuild===!0)return{intent:"build",skipped:"--no-build"};if(!hasIntent(ctx,"build"))return{intent:"build",skipped:"no plugin provides build"};ctx.reporter.operationStart("Building the project");let built=await ctx.run("build",{});return{intent:"build",result:built.toPlain(),outputs:built}}import{SousError as SousError18}from"@sous-io/plugin-api";function isShortNamed(ref){if(ref.kind!=="namespace"&&ref.kind!=="recipe")return!1;let named=ref;return(named.kind==="namespace"?named.repo:named.namespace?.repo??named.repo)?.location===void 0}async function subscriptionKeyFor(ctx,written,keys){let readings=readingsOf(ctx,written),short=readings.find(isShortNamed);if(short!==void 0){let key=ctx.services.get("refs.format").key(short);return keys.find(candidate=>candidate===key)??keys.find(candidate=>candidate.toLowerCase()===key.toLowerCase())??key}let catalog=await loadCatalog(ctx);return(await pickMatch(ctx,findInCatalog(catalog.inputs,readings,["namespace","recipe"]),written.trim(),void 0,()=>new SousError18(`'${written.trim()}' names no namespace or recipe this project knows.`))).key}async function planSubscriptionRemoval(ctx,key,lock){let configured=configuredSubscriptions(ctx.config),managed=await managedEntries(ctx.services.get("confd.managed"),SUBSCRIPTIONS_LAYER,"subscriptions"),held=keysHeldBySubscription(lock,key),removable=Object.hasOwn(managed,key)&&managed[key]?.enabled!==!1,builtIn=!removable&&isBuiltInEntry(configured[key]);if(!removable&&!builtIn){if(!Object.hasOwn(configured,key)&&held.length===0){let known=sortBytewise(Object.keys(configured).filter(entry=>configured[entry]?.enabled!==!1));throw new SousError18(`This project does not subscribe to '${key}'.`,{details:[known.length>0?`It subscribes to: ${known.join(", ")}.`:"It has no subscriptions yet."]})}if(Object.hasOwn(configured,key))throw new SousError18(`The subscription to '${key}' is written in one of this project's own config files, not in the file sous manages.`,{details:["Remove its entry from the 'subscriptions' block of that file; sous never deletes what you wrote.",`To switch it off on this machine instead, run 'sous subscription disable ${key}'.`]})}let after=lock;for(let heldKey of held)after=dropProjectHold(after,heldKey);return{key,optedOut:builtIn,after,stayed:stayedAfter(after,held)}}async function writeSubscriptionRemoval(ctx,removal){let managed=ctx.services.get("confd.managed");removal.optedOut?await writeSubscriptionEntry(managed,removal.key,{enabled:!1}):await deleteSubscriptionEntry(managed,removal.key)}var STAYED_COLUMNS=[{key:"key",header:"Recipe",kind:"path",overflow:"truncate",minWidth:12},{key:"heldBy",header:"Still held by",overflow:"wrap",flex:1,minWidth:16}];function repoAddOutputs(result){let heading="Adding a repository";return result.dryRun?finish2([dryRunOutput("Nothing will be trusted, written or downloaded.",heading),noteOutput(`The repository would be added as '${result.name}', read through the ${result.provider} provider, and its index would be fetched.`)],result):finish2([blockOutput({Repository:result.name,Location:result.url,Provider:result.provider,Namespaces:result.namespaces.length>0?result.namespaces.join(", "):"none; this repository publishes nothing yet",Recipes:String(result.recipeCount)},{heading}),noteOutput(result.alreadyTrusted?`This project already trusted '${result.name}', so only its index was refreshed.`:`This project now trusts '${result.name}'. Nothing from it has been installed.`)],result)}function repoRemoveOutputs(ctx,result){let pruneHint=rebuilt(result)?"":" Run 'sous build' to prune what it used to write.",outputs=[];result.dryRun&&outputs.push(dryRunOutput("Nothing will be written."));let[first2,...rest]=result.plan??[];return first2!==void 0&&(outputs.push(sentence(first2)),rest.length>0&&outputs.push(listOutput(rest,{listTitle:"Here is what goes with it:"}))),outputs.push(lockfileOutput(result.diff,"Nothing changed; nothing was locked because of this repository.")),result.stayed.length>0&&outputs.push(tableOutput(STAYED_COLUMNS,result.stayed.map(entry=>({key:entry.key,heldBy:entry.heldBy.join(", ")})),{tableTitle:"What stayed, and why"})),result.dryRun?outputs.push(dryRunOutput("Nothing was written. Run the same command without '--dry-run' to remove it.")):outputs.push(sentence(result.optedOut?`The repository '${result.name}' is one sous provides itself, so it was switched off rather than deleted: this project's config now records '${result.name}: { enabled: false }'.${pruneHint}`:`This project no longer trusts '${result.name}'. Nothing is read from it any more, and its entry is gone from the repositories layer.${pruneHint}`)),finishWithFollowUps(ctx,underHeading("Removing a repository",outputs),result,`The repository '${result.name}' was removed, but the build that followed it failed, so this project may still hold files its recipes used to write. The removal itself is recorded and locked; fix what the build reported above and run 'sous build' again.`)}function repoTrustOutputs(result){let outputs=[];return result.dryRun&&outputs.push(dryRunOutput("Nothing will be written.")),outputs.push(blockOutput({Repository:result.name,Location:result.url})),result.alreadyTrusted?outputs.push(noteOutput(`This project already trusts '${result.name}'; nothing changed.`)):result.dryRun?outputs.push(dryRunOutput(`Nothing was written. Run the same command without '--dry-run' to trust '${result.name}'.`)):outputs.push(noteOutput(result.trusted?`This project now trusts '${result.name}'. Nothing from it has been installed.`:`'${result.name}' was not trusted; nothing changed.`)),finish2(underHeading("Trusting a repository",outputs),result)}var BUILT_IN_PROVIDERS=["github","gitlab","local"];function looksLikeLocalPath(typed){return typed.startsWith("/")||typed.startsWith("./")||typed.startsWith("../")||typed==="."||typed===".."||typed.startsWith("~")}function resolveLocalPath(typed,base,home){let expanded=typed==="~"||typed.startsWith("~/")?path41.join(home??os6.homedir(),typed.slice(1)):typed;return path41.resolve(base,expanded)}async function addRepo(input,ctx){let locations=ctx.services.get("refs.locations"),typed=input.url.trim(),url2=typed;if(looksLikeLocalPath(typed)){url2=resolveLocalPath(typed,ctx.cwd??ctx.project?.root??".",ctx.env.HOME);let id=input.provider??locations.hostFor(url2)?.id,host=ctx.entities.list("repository-host").find(entry=>entry.id===id);if(host?.checkTypedPath!==void 0)await host.checkTypedPath(typed,url2,ctx);else if(!fs27.existsSync(url2)||!fs27.statSync(url2).isDirectory())throw new SousError19(`'${typed}' is not a directory on this machine, so it cannot be added as a repository.`,{details:[`Sous looked at ${url2}.`]})}if(input.provider!==void 0&&locations.host(input.provider)===void 0)throw new SousError19(`'${input.provider}' is not a repository host sous knows.`,{details:[`The hosts loaded now: ${sortBytewise(locations.hosts().map(host=>host.id)).join(", ")||"none"}. A plugin can add another.`]});let canonical=locations.canonicalize(url2,input.provider),provider=input.provider??locations.hostFor(url2)?.id??"unknown",name=input.name??canonical.name.toLowerCase();if(!REPO_NAME_PATTERN2.test(name))throw new SousError19(`'${name}' is not a usable short name for a repository.`,{details:["A short name is lowercase kebab case: a letter, then letters, digits or hyphens. Refs use it as the 'repo:' qualifier.",`Choose one with --name, for example 'sous repo add ${typed} --name my-recipes'.`]});let existing=configuredRepos(ctx.config)[name],wanted=locations.identityOf(canonical),sameRepository=existing!==void 0&&identityOf(ctx,existing.url)===wanted,alreadyTrusted=sameRepository&&existing.enabled!==!1;if(existing!==void 0&&!sameRepository)throw new SousError19(`This project already has a repository called '${name}', and it is a different one.`,{details:[`Already added: ${existing.url}`,`Being added: ${url2}`,`Give this one a name of its own with --name, for example --name ${name}-2.`]});let result={name,url:url2,provider,alreadyTrusted,namespaces:[],recipeCount:0,dryRun:input.dryRun===!0};if(input.dryRun===!0)return result;alreadyTrusted||await ctx.services.get("recipes.trust").confirm([{name,url:url2,identity:wanted,provider,requiredBy:[{ref:name,requestedBy:"project"}]}],{...input.yes===void 0?{}:{yes:input.yes}},ctx),await writeRepoEntry(ctx.services.get("confd.managed"),name,{url:url2,...input.provider===void 0?{}:{provider:input.provider},addedAt:nowIso(),addedBy:USER_ADDED_BY}),ctx.configChanged();try{let cached2=await(await ctx.refreshConfig()).services.get("recipes.index-cache").get(name,{latest:!0});result.namespaces=sortBytewise(Object.keys(cached2.index.namespaces)),result.recipeCount=Object.keys(cached2.index.recipes).length}catch(error51){ctx.reporter.warning(`Trusted ${name}, but its index could not be read yet: ${describeError2(error51)}`)}return result}async function subscriptionsInto(ctx,name,lock){let fromRepo=new Set(Object.entries(lock.recipes).filter(([,recipe])=>recipe.repo===name).map(([key])=>key)),subscriptions=configuredSubscriptions(ctx.config),managed=await managedEntries(ctx.services.get("confd.managed"),SUBSCRIPTIONS_LAYER,"subscriptions"),format3=ctx.services.get("refs.format"),removable=[],kept=[];for(let key of sortBytewise(Object.keys(subscriptions))){if(subscriptions[key]?.enabled===!1)continue;let qualifier;try{qualifier=format3.partsOf(format3.parseNamedRef(key,"config")).repo?.name}catch{continue}qualifier!==name&&!keysHeldBySubscription(lock,key).some(held=>fromRepo.has(held))||(Object.hasOwn(managed,key)||isBuiltInEntry(subscriptions[key])?removable.push(key):kept.push(key))}return{removable,kept}}function removalPlan(result){let lines3=[result.optedOut?`The repository '${result.name}' at ${result.url} is one sous provides itself, so it is switched off instead, by recording '${result.name}: { enabled: false }' in conf.d/500-repos.jsonc.`:`The entry for '${result.name}' at ${result.url} is removed from conf.d/500-repos.jsonc, so sous stops reading anything from it.`];lines3.push(result.subscriptions.length===0?"Nothing this project subscribes to resolves into it.":`${result.subscriptions.length===1?"One subscription resolves into it and is":`${result.subscriptions.length} subscriptions resolve into it and are`} removed: ${result.subscriptions.join(", ")}.`),result.removedRecipes.length>0&&lines3.push(`These locked recipes were held only through those subscriptions and leave the lockfile: ${result.removedRecipes.join(", ")}.`);for(let stayed of result.stayed)lines3.push(`The recipe '${stayed.key}' stays, because ${stayed.heldBy.join(", ")} still holds it.`);result.outputs.length>0&&lines3.push(`Removing ${result.name} deletes ${result.outputs.length} built ${result.outputs.length===1?"file":"files"} on the next build:`,...result.outputs.map(file2=>` ${file2}`)),result.linkedPath!==void 0&&lines3.push(result.linkIsGlobal?`A machine-wide link points this repository at ${result.linkedPath}. Other projects share it, so it is left as it is.`:`This project links the repository to ${result.linkedPath}. The link is removed; the checkout stays on disk.`);for(let key of result.keptSubscriptions)lines3.push(`The subscription to '${key}' resolves into it and is written in this project's own config, which sous never edits, so it stays.`);return lines3}function reportRemovalPlan(reporter,plan){for(let index=0;index<plan.length;index++){let line=plan[index],items2=[];for(;plan[index+1]?.startsWith(" ")===!0;)items2.push(plan[++index].trim());items2.length>0?reporter.list(items2,{title:line},LogLevel5.Notice):reporter.note(line)}}async function removeRepo(input,ctx){let name=input.repo,trusted=ctx.services.get("recipes.trust").trusted(),entry=trusted[name];if(entry===void 0){let known=sortBytewise(Object.keys(trusted));throw new SousError19(`This project does not trust a repository called '${name}'.`,{details:[known.length>0?`It trusts: ${known.join(", ")}.`:"It trusts no repositories yet."]})}let managedRepos=await managedEntries(ctx.services.get("confd.managed"),REPOS_LAYER,"repos"),builtIn=!Object.hasOwn(managedRepos,name)&&isBuiltInEntry(entry);if(!Object.hasOwn(managedRepos,name)&&!builtIn)throw new SousError19(`The repository '${name}' is written in one of this project's own config files, not in the file sous manages.`,{details:["Remove its entry from the 'repos' block of that file; sous never deletes what you wrote."]});let lockService=ctx.services.get("recipes.lock"),before=lockService.read(),{removable,kept}=await subscriptionsInto(ctx,name,before),removals=[],after=before,held=[];for(let key of removable){let removal=await planSubscriptionRemoval(ctx,key,after);held.push(...keysHeldBySubscription(after,key)),after=removal.after,removals.push(removal)}let diff=lockService.diff(before,after),outputs=ctx.services.has("compiler.state")?sortBytewise(new Set(ctx.services.get("compiler.state").filesFrom({repository:name}).map(file2=>file2.dest))):[],link=ctx.services.has("recipes.links")?ctx.services.get("recipes.links").get(name):void 0,planned={name,url:entry.url,optedOut:builtIn,subscriptions:removable,keptSubscriptions:kept,removedRecipes:diff.removed.map(change=>change.key),stayed:stayedAfter(after,held),outputs,diff,...link===void 0?{}:{linkedPath:link.path},linkIsGlobal:link?.scope==="global",dryRun:input.dryRun===!0},plan=removalPlan(planned);if(input.dryRun===!0)return{...planned,plan,followUps:[{intent:"build",skipped:"--dry-run"}]};if(input.yes!==!0&&(reportRemovalPlan(ctx.reporter,plan),!await ctx.prompter.confirm({message:`Stop trusting '${name}'?`,answeredBy:"--yes",default:!1})))throw new SousError19(`Nothing was written: the repository '${name}' is still trusted.`);for(let removal of removals)await writeSubscriptionRemoval(ctx,removal);let written=await lockService.write(after);link!==void 0&&link.scope==="project"&&await ctx.services.get("recipes.links").remove(name,"project");let managed=ctx.services.get("confd.managed");return builtIn?await writeRepoEntry(managed,name,{enabled:!1}):await deleteRepoEntry(managed,name),ctx.configChanged(),input.noBuild!==!0&&await ctx.refreshConfig(),{...planned,...input.yes===!0?{plan}:{},diff:written,followUps:[await buildFollowUp(ctx,input)]}}async function trustRepo(input,ctx){let trust=ctx.services.get("recipes.trust"),already=trust.nameOf(input.repo),dry=input.dryRun===!0;if(already!==void 0)return{name:already,url:trust.trusted()[already].url,trusted:!0,alreadyTrusted:!0,dryRun:dry};let configured=configuredRepos(ctx.config),off=configured[input.repo];if(off!==void 0&&off.enabled===!1&&input.url===void 0)return dry||(await ctx.services.get("confd.managed").edit(REPOS_LAYER,root=>root.atPath(["repos",input.repo,"enabled"]).set(!0)),ctx.configChanged()),{name:input.repo,url:off.url,trusted:!dry,alreadyTrusted:!1,dryRun:dry};let url2=input.url??(REPO_NAME_PATTERN2.test(input.repo)?void 0:input.repo);if(url2===void 0)throw new ConfigError24(`Sous does not know where the repository '${input.repo}' lives.`,{details:[`Pass its URL: 'sous repo trust ${input.repo} --url <url>', or add it with 'sous repo add <url> --name ${input.repo}'.`]});let identity2=identityOf(ctx,url2),name=REPO_NAME_PATTERN2.test(input.repo)?input.repo:proposeRepoName(Object.keys(configured),identity2??url2),provider=ctx.services.get("refs.locations").hostFor(url2)?.id,done2=await trust.confirm([{name,url:url2,...identity2===void 0?{}:{identity:identity2},...provider===void 0?{}:{provider},requiredBy:[{ref:input.repo,requestedBy:"project"}]}],{...input.yes===void 0?{}:{yes:input.yes},dryRun:dry},ctx);return dry||ctx.configChanged(),{name,url:url2,trusted:done2.added.includes(name)&&!dry,alreadyTrusted:!1,dryRun:dry}}async function listRepos(input,ctx){let cache2=ctx.services.get("recipes.index-cache"),links=ctx.services.has("recipes.links")?ctx.services.get("recipes.links").all():{},locations=ctx.services.get("refs.locations"),listings=[];for(let[name,entry]of Object.entries(configuredRepos(ctx.config))){let enabled=entry.enabled!==!1,problem,cached2=cachedOrNothing(cache2,name);if(enabled&&input.latest===!0&&input.installed!==!0)try{cached2=await readUpstream(ctx,name)}catch(error51){problem=describeError2(error51),cached2=cachedOrNothing(cache2,name)}let installed2=input.installed===!0?pinsFrom(ctx,name):void 0;if(installed2!==void 0&&installed2.length===0)continue;let provider=entry.provider;try{provider??=locations.hostFor(entry.url)?.id}catch{}listings.push({name,url:entry.url,provider:provider??"unknown",enabled,alwaysPull:entry.alwaysPull===!0,...entry.addedBy===void 0?{}:{addedBy:entry.addedBy},...entry.addedAt===void 0?{}:{addedAt:entry.addedAt},...cached2===void 0?{}:{namespaces:sortBytewise(Object.keys(cached2.index.namespaces)),recipeCount:Object.keys(cached2.index.recipes).length,indexSource:cached2.source,...cached2.meta?.lastCheckedAt===void 0?{}:{lastCheckedAt:cached2.meta.lastCheckedAt}},...links[name]===void 0?{}:{linkedPath:links[name].path},...problem===void 0?{}:{problem},...installed2===void 0?{}:{installed:installed2}})}let repos=configuredRepos(ctx.config);return listings.sort((left,right)=>Number(isBuiltInEntry(repos[right.name]))-Number(isBuiltInEntry(repos[left.name]))||(left.name<right.name?-1:left.name>right.name?1:0))}function cachedOrNothing(cache2,name){try{return cache2.cached(name)}catch{return}}function pinsFrom(ctx,repo){let recipes;try{recipes=ctx.services.get("recipes.lock").read().recipes}catch{return[]}return sortBytewise(Object.keys(recipes).filter(key=>recipes[key].repo===repo)).map(key=>({key,version:recipes[key].version}))}function matchScore(text,name,description){let wanted=text.toLowerCase(),candidate=name.toLowerCase();return candidate===wanted?100:candidate.startsWith(wanted)?75:candidate.includes(wanted)?50:description?.toLowerCase().includes(wanted)===!0?20:0}function sortVersions(versions){return[...versions].sort((left,right)=>{let a=import_semver8.default.valid(left,{loose:!0}),b=import_semver8.default.valid(right,{loose:!0});return a!==null&&b!==null?import_semver8.default.compare(a,b):a!==null?-1:b!==null?1:left<right?-1:left>right?1:0})}async function searchRepos(input,ctx){let catalog=await loadCatalog(ctx,input),matches=[],lock=catalog.inputs.lock;for(let repo of catalog.inputs.repos){for(let[namespace,declared]of input.installed===!0?[]:Object.entries(repo.index.namespaces)){let score=matchScore(input.text,namespace,declared.description);score>0&&matches.push({ref:publishedNamespaceRef(repo,namespace),key:namespace,kind:"namespace",repo:repo.name,...declared.description===void 0?{}:{description:declared.description},score})}for(let[key,recipe]of Object.entries(repo.index.recipes)){let score=Math.max(matchScore(input.text,splitRecipeKey(key).name,recipe.description),matchScore(input.text,key)),pinned=lock.recipes[key]?.repo===repo.name?lock.recipes[key].version:void 0;if(score>0&&matches.push({ref:publishedRecipeRef(repo,key),key,kind:"recipe",repo:repo.name,...recipe.description===void 0?{}:{description:recipe.description},score,versions:sortVersions(Object.keys(recipe.versions)),...pinned===void 0?{}:{installed:pinned}}),input.installed===!0)continue;let version2=latestVersion(recipe.versions);for(let variable of(version2===void 0?void 0:recipe.versions[version2]?.variables)??[]){let variableScore=matchScore(input.text,variable.name,variable.description);if(variableScore>0){let ref={kind:"variable",name:variable.name,recipe:publishedRecipeRef(repo,key),description:variable.description};matches.push({ref,key:`${key}.${variable.name}`,kind:"variable",repo:repo.name,description:variable.description,score:variableScore-5})}}}}return matches.sort((left,right)=>right.score-left.score||(left.key<right.key?-1:left.key>right.key?1:0)).slice(0,input.limit??20)}function registerRepoIntents(sous){sous.intents.add({intent:"repo.add",requiresProject:!0,summary:"Add a recipe repository, which trusts it",input:inputSchema({url:{type:"string",description:"The repository's URL, or a path on this machine"},name:{type:"string",description:"The short name refs use for it; default from the URL"},provider:{type:"string",minLength:1,description:`The repository host, when the URL does not give it away: ${BUILT_IN_PROVIDERS.join(", ")}, or any host a plugin adds`},yes,dryRun},["url"]),changesConfig:!0,cli:{aliases:[["repos","add"]],positional:["url"],flags:{yes:yesFlag}},handle:async(input,ctx)=>repoAddOutputs(await addRepo(input,ctx))}),sous.intents.add({intent:"repo.remove",requiresProject:!0,summary:"Stop trusting a repository, removing the subscriptions that resolve into it",input:inputSchema({repo:{type:"string",description:"The repository's short name"},yes,dryRun,noBuild},["repo"]),changesConfig:!0,cli:{aliases:[["repos","remove"]],positional:["repo"],flags:{yes:yesFlagNoTrust}},handle:async(input,ctx)=>repoRemoveOutputs(ctx,await removeRepo(input,ctx))}),sous.intents.add({intent:"repo.trust",requiresProject:!0,summary:"Trust a repository by name, URL or identity",input:inputSchema({repo:{type:"string",description:"A short name, URL or identity"},url:{type:"string",description:"Its URL, when the name has none recorded"},yes,dryRun},["repo"]),changesConfig:!0,cli:{aliases:[["repos","trust"]],positional:["repo"],flags:{yes:yesFlag}},handle:async(input,ctx)=>repoTrustOutputs(await trustRepo(input,ctx))}),sous.intents.add({intent:"repo.list",requiresProject:!0,summary:"List the repositories this project trusts",input:inputSchema({latest,installed,verbose:{type:"boolean",description:"Show more about each repository"}}),parallel:!0,cli:{aliases:[["repos","list"]],flags:{latest:latestFlag}},handle:async(input,ctx)=>repoListOutputs(ctx,input,await listRepos(input,ctx))}),sous.intents.add({intent:"repo.search",requiresProject:!0,summary:"Search the trusted repositories for namespaces, recipes and variables",input:inputSchema({text:{type:"string",description:"What to look for"},latest,installed,limit:{type:"integer",description:"At most this many matches (default 20)"}},["text"]),parallel:!0,cli:{aliases:[["search"],["repos","search"]],positional:["text"],flags:{latest:latestFlag}},handle:async(input,ctx)=>repoSearchOutputs(ctx,input,await searchRepos(input,ctx))})}var import_semver9=__toESM(require_semver2(),1);import{LogLevel as LogLevel7,SousError as SousError23}from"@sous-io/plugin-api";import{SousError as SousError20}from"@sous-io/plugin-api";async function checkProvidedAnswers(ctx,resolved,flags,download2){if((flags.answer===void 0||flags.answer.length===0)&&flags.answersFile===void 0||!ctx.services.has("recipe-answers.preanswers"))return;let preanswers=ctx.services.get("recipe-answers.preanswers"),{defined}=await definedVariables(ctx,resolved,download2),keys=new Set(defined.map(variable=>variable.key)),existing=[];try{existing=ctx.services.has("recipe-answers.definitions")?ctx.services.get("recipe-answers.definitions").listSync():[]}catch{existing=[]}try{let answers=await preanswers.read({...flags.answer===void 0?{}:{answer:flags.answer},...flags.answersFile===void 0?{}:{answersFile:flags.answersFile}});preanswers.match(answers,[...defined,...existing.filter(variable=>!keys.has(variable.key))])}catch(error51){if(error51 instanceof SousError20&&error51.details.length>0){let[first2,...rest]=error51.details;throw new SousError20(first2??error51.message,{details:rest})}throw error51}}import{LogLevel as LogLevel6,NonInteractiveError as NonInteractiveError3,SousError as SousError21}from"@sous-io/plugin-api";var Trust=class{constructor(config2,services){this.config=config2;this.services=services}trusted(){return trustedRepos(this.config)}isTrusted(repository){return this.nameOf(repository)!==void 0}nameOf(repository){let trusted=this.trusted();if(Object.hasOwn(trusted,repository))return repository;let wanted=this.identityOf(repository);if(wanted!==void 0)return Object.keys(trusted).find(name=>this.identityOf(trusted[name].url)===wanted)}async confirm(missing,options,io){if(missing.length===0)return{accepted:[],added:[],needUrl:[]};if(options.yes!==!0&&options.dryRun!==!0){if(!io.prompter.interactive)throw new NonInteractiveError3(trustQuestion(missing),"--yes",{details:nonInteractiveDetails(missing)});if(reportTrustNotice(io.reporter,missing),!await io.prompter.confirm({message:trustQuestion(missing),answeredBy:"--yes",default:!1}))throw new SousError21(`Nothing was installed: trust was declined for ${missing.map(repo=>`'${repo.name}'`).join(", ")}.`,{details:["Sous installs a dependency closure whole or not at all, so declining any repository in it stops the install."]})}let managed=this.services.get("confd.managed"),added=[],needUrl=[];for(let repo of missing){if(repo.url===void 0){needUrl.push(repo.name);continue}let requesters=[...new Set(repo.requiredBy.map(entry=>entry.requestedBy))].sort(compareBytewise2);await writeRepoEntry(managed,repo.name,{url:repo.url,...repo.provider===void 0?{}:{provider:repo.provider},addedAt:nowIso(),addedBy:requesters.length>0?requesters.join(", "):USER_ADDED_BY},options.dryRun===!0),added.push(repo.name)}return{accepted:[...missing],added,needUrl}}identityOf(repository){try{return this.services.get("refs.locations").identity(repository).toLowerCase()}catch{return repository.includes("/")&&!repository.includes("://")?repository.toLowerCase():void 0}}};function trustQuestion(missing){return missing.length===1?`Do you trust the repository '${missing[0].name}'?`:`Do you trust these ${missing.length} repositories?`}function reportTrustNotice(reporter,missing){reporter.notice(missing.length===1?"One repository has to be trusted before this can continue.":`${missing.length} repositories have to be trusted before this can continue.`);for(let repo of missing){let entries=[{label:"Location",value:repo.url??"not known to sous; a ref named it by its short name only"}];repo.identity!==void 0&&entries.push({label:"Identity",value:repo.identity});for(let entry of repo.requiredBy)entries.push({label:"Required",value:`${entry.ref} (required by ${entry.requestedBy==="project"?"this project":`'${entry.requestedBy}'`})`});reporter.variables(entries,repo.name,LogLevel6.Notice)}reporter.note("Trusting a repository trusts every namespace and every recipe in it, including ones published later. Trusting on its own runs nothing; subscribing to something inside it can, and probably will, run scripts on this machine."),reporter.note("Sous cannot tell you whether a repository deserves trust. Look at the location above, and at who publishes it, before answering.")}function nonInteractiveDetails(missing){let lines3=[];for(let repo of missing){let provenance=repo.requiredBy.map(entry=>`${entry.ref} (required by ${entry.requestedBy})`).join(", ");lines3.push(`${repo.name}: ${repo.url??"URL not known to sous"}`,` ${provenance}`)}return lines3.push("Trusting a repository trusts every namespace and recipe in it, and subscribing to something inside it can run scripts on this machine.","Add each repository deliberately, with its URL:",...missing.map(repo=>` sous repo add ${repo.url??"<url>"} --name ${repo.name} --yes`)),lines3}function needUrlError(names2){return new SousError21(names2.length===1?`Sous does not know where the repository '${names2[0]}' lives, so it cannot add it for you.`:`Sous does not know where these repositories live, so it cannot add them for you: ${names2.map(name=>`'${name}'`).join(", ")}.`,{details:["A recipe names the repository it depends on by its short name only; the URL has to come from you.","Add each one with its URL, then run this command again:",...names2.map(name=>` sous repo add <url> --name ${name}`)]})}import{SousError as SousError22}from"@sous-io/plugin-api";function describeUpdateScope(scope){switch(scope.kind){case"all":return"every subscription in this project";case"repository":return`the recipes this project takes from the repository '${scope.repo}'`;case"namespace":return`the recipes in the namespace '${scope.repo}:${scope.namespace}'`;case"recipe":return`the recipe '${scope.repo}:${scope.key}'`}}function recipeInScope(scope,key,repo){switch(scope.kind){case"all":return!0;case"repository":return repo===scope.repo;case"namespace":return repo===scope.repo&&namespaceOfKey3(key)===scope.namespace;case"recipe":return repo===scope.repo&&key===scope.key}}function coverInScope(scope,cover,qualifier){if(scope.kind==="all")return!0;if(qualifier!==void 0&&qualifier!==scope.repo)return!1;switch(scope.kind){case"repository":return qualifier===scope.repo;case"namespace":return cover===scope.namespace||cover.startsWith(`${scope.namespace}/`);case"recipe":return cover===scope.key||scope.key.startsWith(`${cover}/`)}}function isEmptyUpdate(plan){return plan.diff.unchanged&&plan.missingRepos.length===0}async function freshIndexes(ctx){let cache2=ctx.services.get("recipes.index-cache"),repos=trustedRepos(ctx.config),indexes=new Map,unreachable=[];for(let name of repoSearchOrder(ctx))try{let read=await cache2.get(name,{latest:!0});read.source==="stale"&&unreachable.push({repo:name,reason:read.problem??"The repository could not be reached."}),indexes.set(name,read.index)}catch(error51){unreachable.push({repo:name,reason:describeError2(error51)});let cached2=cache2.cached(name);cached2!==void 0&&indexes.set(name,cached2.index)}return{indexes,unreachable,urls:new Map(Object.entries(repos).map(([name,entry])=>[name,entry.url]))}}async function resolveUpdateScope(ctx,input,catalog){if(input.ref===void 0||input.ref.trim()==="")return{kind:"all"};let readings=readingsOf(ctx,input.ref),trusted=trustedRepos(ctx.config);for(let reading of readings){if(reading.kind!=="repo")continue;if(reading.name!==void 0&&Object.hasOwn(trusted,reading.name))return{kind:"repository",repo:reading.name};let identity2=reading.location?.identity.toLowerCase(),byIdentity=catalog.repos.find(repo=>identity2!==void 0&&repo.identity?.toLowerCase()===identity2);if(byIdentity!==void 0)return{kind:"repository",repo:byIdentity.name}}let matches=findInCatalog(catalog,readings,["namespace","recipe"]),chosen=await pickMatch(ctx,matches,input.ref.trim(),input.acceptFirst,()=>new SousError22(`No trusted repository, namespace or recipe is called '${input.ref}'.`,{details:[`Searched: ${catalog.repos.map(repo=>repo.name).join(", ")||"nothing (no index could be read)"}.`]}));return chosen.ref.kind==="namespace"?{kind:"namespace",repo:chosen.repo.name,namespace:chosen.key}:{kind:"recipe",repo:chosen.repo.name,key:chosen.key}}async function planUpdate(input,ctx){let lockService=ctx.services.get("recipes.lock"),resolver=ctx.services.get("recipes.resolver"),format3=ctx.services.get("refs.format"),{indexes,unreachable,urls}=await freshIndexes(ctx),catalog={repos:[...indexes.entries()].map(([name,index])=>{let url2=urls.get(name),identity2=url2===void 0?void 0:identityOf(ctx,url2);return{name,index,...url2===void 0?{}:{url:url2},...identity2===void 0?{}:{identity:identity2}}}),lock:lockService.read(),subscriptions:[]},scope=await resolveUpdateScope(ctx,input,catalog),before=catalog.lock,configured=configuredSubscriptions(ctx.config),subscriptions=enabledSubscriptions2(ctx.config),unreachableNames=new Set(unreachable.map(entry=>entry.repo)),builtInKeys=Object.keys(subscriptions).filter(key=>isBuiltInEntry(subscriptions[key])),builtInHeld=new Set(builtInKeys.flatMap(key=>keysHeldBySubscription(before,key))),movable=(key,repo)=>!unreachableNames.has(repo)&&!builtInHeld.has(key)&&recipeInScope(scope,key,repo),keep={};for(let[key,entry]of Object.entries(before.recipes))movable(key,entry.repo)||(keep[key]=entry.version);let coverOf=key=>{try{let ref=format3.parseNamedRef(key,"config");return{cover:format3.key(ref),qualifier:format3.partsOf(ref).repo?.name}}catch{return}},touches=key=>{if(scope.kind==="all")return!0;let parsed=coverOf(key);return parsed===void 0?!1:lockedClosure(before,keysHeldBySubscription(before,parsed.cover)).some(held=>movable(held,before.recipes[held].repo))||coverInScope(scope,parsed.cover,parsed.qualifier)},targets=sortBytewise(Object.keys(subscriptions)).filter(key=>!isBuiltInEntry(subscriptions[key])&&touches(key)),merged=new Map,resolvedSubscriptions=[],missing=new Map,failed=[],cycles=[],unreadable2=new Set;for(let key of targets){let entry=subscriptions[key],request;try{request={ref:format3.parseNamedRef(key,"config"),...entry.range===void 0?{}:{range:entry.range},...entry.prerelease===!0?{prerelease:!0}:{},requestedBy:PROJECT_HOLDER,kind:"subscribes"}}catch(error51){failed.push({key,reason:describeError2(error51)});continue}let result;try{result=await resolver.resolve([request],{keep,indexes,...entry.prerelease===!0?{prerelease:!0}:{}})}catch(error51){failed.push({key,reason:describeError2(error51)});continue}cycles.push(...result.cycles),result.unreadable.forEach(item=>unreadable2.add(item));for(let repo of result.missingRepos){let known=missing.get(repo.name);missing.set(repo.name,known===void 0?repo:{...known,requiredBy:[...known.requiredBy,...repo.requiredBy]})}let conflict=result.resolved.find(recipe=>merged.has(recipe.key)&&merged.get(recipe.key).version!==recipe.version);if(conflict!==void 0){failed.push({key,reason:`It wants version ${conflict.version} of '${conflict.key}', and another subscription wants ${merged.get(conflict.key).version}.`});continue}for(let recipe of result.resolved){let already=merged.get(recipe.key);merged.set(recipe.key,already===void 0?recipe:mergeHolders(already,recipe))}resolvedSubscriptions.push(key)}let repoInputs={};for(let[name,url2]of urls)if(url2!==void 0){let identity2=identityOf(ctx,url2);repoInputs[name]={url:url2,...identity2===void 0?{}:{identity:identity2}}}let settled=[...merged.values()],covers2=keys=>keys.map(key=>coverOf(key)?.cover).filter(cover=>cover!==void 0),after=releaseDroppedHolds(applyResolution(before,settled,repoInputs),merged,covers2(resolvedSubscriptions),covers2(Object.keys(configured).filter(key=>!resolvedSubscriptions.includes(key)))),changed=settled.filter(recipe=>before.recipes[recipe.key]?.version!==recipe.version),links=ctx.services.has("recipes.links")?ctx.services.get("recipes.links"):void 0;return{scope,diff:lockService.diff(before,after),lockfile:after,missingRepos:[...missing.values()].sort((left,right)=>compareBytewise2(left.name,right.name)),newVariables:await newVariables(ctx,changed,before,indexes),unreadable:sortBytewise(unreadable2),unreachable,linked:sortBytewise(new Set(changed.map(recipe=>recipe.repo).filter(repo=>links?.get(repo)!==void 0))),builtIn:builtInKeys.filter(key=>keysHeldBySubscription(before,key).some(held=>recipeInScope(scope,held,before.recipes[held].repo))).map(key=>({key,...subscriptions[key]?.range===void 0?{}:{version:subscriptions[key].range}})),switchedOff:sortBytewise(Object.keys(configured).filter(key=>{let parsed=coverOf(key);return configured[key]?.enabled===!1&&parsed!==void 0&&coverInScope(scope,parsed.cover,parsed.qualifier)})),failed,cycles}}async function newVariables(ctx,changed,before,indexes){let{defined}=await definedVariables(ctx,changed),known=new Set;for(let recipe of changed){let pinned=before.recipes[recipe.key],old=pinned===void 0?void 0:indexes.get(pinned.repo)?.recipes[recipe.key]?.versions[pinned.version]?.variables;for(let variable of old??[])known.add(`${recipe.key}.${variable.name}`)}let added=defined.filter(variable=>!known.has(variable.key));return plannedQuestionsOf(ctx,added)}import"@sous-io/plugin-api";var INSTALLED_COLUMNS=[{key:"key",header:"Recipe",kind:"path",overflow:"truncate",minWidth:12},{key:"version",header:"Version",overflow:"truncate"},{key:"repo",header:"Repository",overflow:"truncate",priority:"medium"},{key:"why",header:"Why",overflow:"wrap",flex:1,minWidth:16}];function why(recipe){return recipe.requestedBy.includes("project")?"you subscribed to it":recipe.kind==="subscribes"?`co-subscribed by ${recipe.requestedBy.join(", ")}`:`needed by ${recipe.requestedBy.join(", ")}`}function reportCycles(ctx,cycles,hint){cycles.length>0&&ctx.reporter.problem("Some of these recipes co-subscribe to each other in a circle:",{cause:cycles.map(cycle=>cycle.join(" -> ")).join(`
902
+ `):String(items2)}},BUILT_IN_TAGS=[showVarsTag,exportScalarVarsJsTag,getFilesTag,listFilesTag],BUILT_IN_FILTERS=[bulletListFilter];import path34 from"node:path";var DEFAULT_STATE_FILE="${sousDir}/sous.state.json",varsSchema=external_exports.record(external_exports.string(),external_exports.string()),outputSchema=external_exports.object({_if:external_exports.record(external_exports.string(),external_exports.object({eq:external_exports.string()}).strict()).optional(),_vars:varsSchema.optional(),destinationFile:external_exports.string().optional(),destinationDir:external_exports.string().optional(),transforms:external_exports.array(external_exports.string()).optional()}).strict(),originSchema=external_exports.object({plugin:external_exports.string().optional(),recipe:external_exports.string().optional(),repository:external_exports.string().optional()}).strict(),targetSchema=external_exports.object({id:external_exports.string().min(1).optional(),_vars:varsSchema.optional(),entryPoint:external_exports.string().optional(),entryGlob:external_exports.string().optional(),content:external_exports.string().optional(),globBase:external_exports.string().optional(),includeSourceComments:external_exports.boolean().optional(),generateRuntimeContext:external_exports.boolean().optional(),transforms:external_exports.array(external_exports.string()).optional(),origin:originSchema.optional(),outputs:external_exports.array(outputSchema)}).strict().superRefine((target,ctx)=>{[target.entryPoint,target.entryGlob,target.content].filter(source=>source!==void 0).length!==1&&ctx.addIssue({code:"custom",message:"a target must have exactly one of 'entryPoint', 'entryGlob' or 'content'"}),target.content!==void 0&&target.id===void 0&&ctx.addIssue({code:"custom",path:["id"],message:"a target whose source is 'content' needs an 'id', which names it in errors"})}),compilationSchema=external_exports.object({_vars:varsSchema.optional(),includeSourceComments:external_exports.boolean().default(!1),overwriteUntracked:external_exports.boolean().default(!0),stateFile:external_exports.string().default(DEFAULT_STATE_FILE),targets:external_exports.array(targetSchema).default([])}).strict(),aliasesSchema=external_exports.record(external_exports.string(),external_exports.union([external_exports.string(),external_exports.array(external_exports.string())])).superRefine((aliases,ctx)=>{for(let name of Object.keys(aliases))isReservedAliasName(name)&&ctx.addIssue({code:"custom",path:[name],message:`Alias "${name}" is invalid: names beginning with "~" or "#" are reserved ("~" for the home directory and recipe namespaces, "#" for built-in names).`})}),CONFIG_KEYS2=[{id:"compilation",schema:compilationSchema,description:"What to compile: targets, their outputs, source comments, the state file, overwriting files sous did not write."},{id:"_aliases",schema:aliasesSchema.optional(),description:"Include aliases: a name to one base directory or several, tried in order."}];function compilationSettings(config2){let value=config2.get("compilation")??{};return{...value,includeSourceComments:value.includeSourceComments??!1,overwriteUntracked:value.overwriteUntracked??!0,stateFile:value.stateFile??DEFAULT_STATE_FILE,targets:value.targets??[]}}var CompilerRuntime=class{constructor(source,stores){this.source=source;this.stores=stores}cachedScope;cachedNames;produced;get serviceContext(){let{plugin,config:config2,services,entities,project,env}=this.source;return{plugin,config:config2,services,entities,project,env}}settings(){return compilationSettings(this.source.config)}resolver(){let resolver=this.source.services.get("variables.resolver"),config2=this.source.config;return new Proxy(resolver,{get(target,key){if(key==="scope")return request=>target.scopeIn(config2,request);let value=Reflect.get(target,key,target);return typeof value=="function"?value.bind(target):value}})}globs(){return this.source.services.get("host.globs")}projectRoot(){return this.source.project?.root??path34.resolve("/")}rootScope(){return this.cachedScope??=this.resolver().scope(),this.cachedScope}namespaceResolver(){return this.source.services.has("compiler.namespace-resolver")?this.source.services.get("compiler.namespace-resolver"):void 0}hashNames(){if(this.cachedNames)return this.cachedNames;let context={...this.serviceContext,scope:this.rootScope()},aliases={},views={};for(let entity of this.source.entities.list("hash-name")){let name=`#${entity.id}`;entity.view?views[name]=entity.view(context):aliases[name]=(entity.bases?.(context)??[]).map(base=>path34.resolve(this.projectRoot(),base))}return this.cachedNames={aliases,views},this.cachedNames}aliases(){let resolver=this.resolver(),scope=this.rootScope(),user=this.source.config.get("_aliases");return buildAliasMap({builtIns:this.hashNames().aliases,userAliases:[user],substitute:text=>path34.resolve(this.projectRoot(),resolver.normalizePath(resolver.substitute(text,scope)))})}views(){return this.hashNames().views}includeEnvironment(){let resolver=this.resolver(),home=this.source.env.HOME;return{aliases:this.aliases(),views:this.views(),globs:this.globs(),namespaceResolver:this.namespaceResolver(),substitute:(text,scope)=>resolver.substitute(text,scope),...home?{home}:{}}}stateFile(){let scope=this.rootScope(),resolver=this.resolver(),written=scope.stateFilePath??this.settings().stateFile??DEFAULT_STATE_FILE;return path34.resolve(this.projectRoot(),resolver.normalizePath(resolver.substitute(written,scope)))}store(){let file2=this.stateFile(),store2=this.stores.get(file2);return store2||(store2=new StateStore(file2),this.stores.set(file2,store2)),store2}protectedRoots(){let roots=[];if(this.source.project&&roots.push(path34.join(this.source.project.sousDir,"repos")),this.source.services.has("host.sous-home")){let home=this.source.services.get("host.sous-home").paths(this.source.env);roots.push(home.repos,home.store)}return roots}},RuntimeCache=class{runtimes=new WeakMap;stores=new Map;for(source){let runtime=this.runtimes.get(source.config);return runtime||(runtime=new CompilerRuntime(source,this.stores),this.runtimes.set(source.config,runtime)),runtime}};import fs24 from"node:fs";import path35 from"node:path";var WriterService=class{constructor(store2,settings){this.store=store2;this.settings=settings}async write(file2,content,options){let dest=path35.resolve(file2),bytes=Buffer.byteLength(content,"utf8"),tracked=this.store.entry(dest),exists3=fs24.existsSync(dest),base={file:dest,bytes,...options.target===void 0?{}:{target:options.target},...options.origin===void 0?{}:{origin:options.origin}},sameContent=exists3&&readText3(dest)===content;if(exists3&&tracked===void 0&&!this.settings.overwriteUntracked)return{...base,action:"skipped-untracked"};if(options.dryRun)return{...base,action:exists3?sameContent&&!options.force?"unchanged":"would-update":"would-create"};let entry={dest,srcHash:options.sourceHash??hashContent(options.source),destHash:hashContent(content),size:bytes,builtAt:new Date().toISOString(),...options.target===void 0?{}:{target:options.target},...options.origin===void 0?{}:{origin:options.origin}};if(sameContent&&!options.force)return this.store.record(tracked===void 0?entry:{...entry,builtAt:tracked.builtAt}),{...base,action:"unchanged"};if(this.ensureDir(path35.dirname(dest)),fs24.writeFileSync(dest,content,"utf8"),options.mode!==void 0)try{fs24.chmodSync(dest,options.mode)}catch{}else dest.endsWith(".sh")&&fs24.chmodSync(dest,493);return this.store.record(entry),{...base,action:exists3?"updated":"created"}}async remove(files,options={}){let removed=[];for(let file2 of files){let dest=path35.resolve(file2);isProtectedPath(dest,this.settings.protectedRoots)||this.store.entry(dest)===void 0||(removed.push(dest),!options.dryRun&&(fs24.existsSync(dest)&&fs24.rmSync(dest),this.store.forget(dest)))}let dirsRemoved=options.dryRun?[]:this.removeEmptyDirs();return{removed,dirsRemoved}}async commit(options={}){this.store.commit(options)}ensureDir(dir){let missing=[],walk3=dir;for(;!fs24.existsSync(walk3);){missing.unshift(walk3);let parent=path35.dirname(walk3);if(parent===walk3)break;walk3=parent}if(missing.length!==0){fs24.mkdirSync(dir,{recursive:!0});for(let created of missing)this.store.recordDir(created)}}removeEmptyDirs(){let dirs=[...this.store.current().dirs].sort((a,b)=>b.split(path35.sep).length-a.split(path35.sep).length),removed=[];for(let dir of dirs)if(!isProtectedPath(dir,this.settings.protectedRoots))try{fs24.existsSync(dir)&&fs24.readdirSync(dir).length===0&&(fs24.rmdirSync(dir),removed.push(dir))}catch{}return removed}};function readText3(file2){try{return fs24.readFileSync(file2,"utf8")}catch{return}}var package_default11={name:"@sous-io/plugin-compiler",version:"1.0.12",description:"Compiling templates, includes, aliases, compilation settings, the built-in tags and filters, the state file, writing outputs, pruning.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-liquid":"workspace:*","@sous-io/plugin-refs":"workspace:*","@sous-io/plugin-variables":"workspace:*",liquidjs:"^10.25.0",tiktoken:"^1.0.22",zod:"^4.4.3"},devDependencies:{"@sous-io/core":"workspace:*",glob:"^13.0.6",minimatch:"^10.2.4"},engines:{node:">=22"}};var PLUGIN_NAME10="@sous-io/plugin-compiler",transformSchema={"~standard":{version:1,vendor:"sous",validate:value=>{let entry=value;return typeof entry?.id=="string"&&typeof entry.transform=="function"?{value}:{issues:[{message:"A compilation-transform entity needs an id and a transform function."}]}}}},compileInput=jsonSchema10({type:"object",properties:{targets:{type:"array",items:{anyOf:[{type:"string"},{type:"integer"}]},description:"Only these targets, by id or index."},changedFiles:{type:"array",items:{type:"string"},description:"Only the targets whose sources include one of these files."},strict:{type:"boolean",description:"Warnings fail the compile."},rebuild:{type:"boolean",description:"Writes every output, changed or not."},dryRun:{type:"boolean",description:"Writes nothing."}},additionalProperties:!1}),pruneInput=jsonSchema10({type:"object",properties:{all:{type:"boolean",description:"Removes every file the compiler wrote, not only those no target produces."},dryRun:{type:"boolean",description:"Removes nothing."},report:{type:"boolean",description:"Reports each removed file as progress. Default: true."}},additionalProperties:!1}),compilerPlugin=definePlugin11({name:PLUGIN_NAME10,version:package_default11.version,description:"Compiling templates, includes, aliases, compilation settings, the built-in tags and filters, the state file, writing outputs, pruning.",implementable:["compiler.namespace-resolver"],dependsOn:{"@sous-io/plugin-liquid":`^${package_default11.version}`,"@sous-io/plugin-refs":`^${package_default11.version}`,"@sous-io/plugin-variables":`^${package_default11.version}`,"@sous-io/plugin-host":`^${package_default11.version}`},register(sous){let runtimes=new RuntimeCache;sous.entities.define("compilation-transform",transformSchema,{description:"A change to an output's path or contents before it is written."});for(let key of CONFIG_KEYS2)sous.entities.add("config-key",key);for(let tag of BUILT_IN_TAGS)sous.entities.add("liquid-tag",tag);for(let filter3 of BUILT_IN_FILTERS)sous.entities.add("liquid-filter",filter3);sous.services.add("compiler.aliases",(_config,ctx)=>new AliasService(runtimes.for(ctx).aliases()),{lifetime:"config"}),sous.services.add("compiler.includes",(_config,ctx)=>new IncludeService(runtimes.for(ctx).includeEnvironment()),{lifetime:"config"}),sous.services.add("compiler.state",(_config,ctx)=>new StateService(runtimes.for(ctx).store()),{lifetime:"config"}),sous.services.add("compiler.writer",(_config,ctx)=>{let runtime=runtimes.for(ctx);return new WriterService(runtime.store(),{overwriteUntracked:runtime.settings().overwriteUntracked,protectedRoots:runtime.protectedRoots()})},{lifetime:"config"}),sous.intents.add({intent:"compiler.compile",summary:"Compile every compilation target into its outputs",internal:!0,input:compileInput,handle:(input,ctx)=>compile(input,ctx,runtimes.for(ctx))}),sous.intents.add({intent:"compiler.prune",summary:"Remove outputs no compilation target produces any more",internal:!0,input:pruneInput,handle:(input,ctx)=>prune(input,ctx,runtimes.for(ctx))})}});import{definePlugin as definePlugin12}from"@sous-io/plugin-api";import fs29 from"node:fs";import{jsonSchema as jsonSchema13}from"@sous-io/plugin-api";import fs25 from"node:fs";import path36 from"node:path";var RecipeContents=class{constructor(services){this.services=services}of(recipes,kind){let globs=this.services.get("host.globs"),found=[];for(let recipe of recipes)if(recipe.kind==="subscribes")for(let content of recipe.manifest.contents??[]){if(content.kind!==kind)continue;let seen=new Set,files=[];for(let include of content.include){let staticBase2=globs.hasGlob(include)?globs.staticBase(include):path36.posix.dirname(include),base=path36.join(recipe.dir,staticBase2==="/"?".":staticBase2),relative4=globs.matchSync(include,{cwd:recipe.dir,dot:!0,ignore:content.exclude??[]});for(let file2 of globs.sortBytewise(relative4)){let absolute=path36.join(recipe.dir,file2);seen.has(absolute)||!isFile8(absolute)||(seen.add(absolute),files.push({path:globs.toPosix(file2),file:absolute,base}))}}found.push({recipe,kind,files})}return found}};function isFile8(candidate){try{return fs25.statSync(candidate).isFile()}catch{return!1}}var RECIPES_PLUGIN="@sous-io/plugin-recipes",LOCKFILE_NAME="sous.lock.json",LINKS_FILE_NAME="sous.links.json",PROJECT_REPOS_DIRNAME="repos",TYPES_DIRNAME="types",PROJECT_HOLDER="project",BUILT_IN_ADDED_BY="sous",OFFICIAL_REPO_NAME="sous-recipes",OFFICIAL_REPO_URL="https://github.com/sous-io/sous-recipes",OFFICIAL_REPO_IDENTITY="github.com/sous-io/sous-recipes",OFFICIAL_REPO_PROVIDER="github",CORE_NAMESPACE="core",CORE_RECIPE_NAME="sous-skills",CORE_RECIPE_KEY=`${CORE_NAMESPACE}/${CORE_RECIPE_NAME}`,PACKAGED_RECIPES_DIRNAME="recipes",CORE_RECIPE_PATH=`${PACKAGED_RECIPES_DIRNAME}/${CORE_NAMESPACE}/${CORE_RECIPE_NAME}`,DEFAULT_FRESHNESS_SECONDS=300,CONTRIBUTORS={core:"recipes.core",fetch:"recipes.fetch",configLayers:"recipes.config-layers",plugins:"recipes.plugins"};import{ConfigError as ConfigError23}from"@sous-io/plugin-api";function splitStoredKey(key){let slash=key.indexOf("/");return slash===-1?{namespace:key,name:""}:{namespace:key.slice(0,slash),name:key.slice(slash+1)}}function identitySegments2(identity2){return identity2.split("/").filter(segment=>segment.length>0&&segment!=="."&&segment!=="..")}function enabledEntries(entries){let kept={};for(let[key,entry]of Object.entries(entries??{}))entry&&typeof entry=="object"&&entry.enabled!==!1&&(kept[key]=entry);return kept}function trustedWhileBuilding(repos){let kept={};for(let[name,entry]of Object.entries(enabledEntries(repos)))typeof entry.url=="string"&&(kept[name]=entry);return kept}function enabledSubscriptions(subscriptions){return enabledEntries(subscriptions)}function hostFor(hosts,url2,provider){if(provider!==void 0){let named=hosts.find(host=>host.id===provider);if(named)return named}return hosts.find(host=>{try{return host.matches(url2)}catch{return!1}})}function messageOf5(error51){return error51 instanceof Error?error51.message:String(error51)}function sortKeys2(keys){return[...keys].sort((left,right)=>left<right?-1:left>right?1:0)}function plural(count2,one,many=`${one}s`){return`${count2} ${count2===1?one:many}`}function emptyLockfile(){return{formatVersion:1,repos:{},recipes:{}}}function sortRecipes(recipes){let sorted2={};for(let key of sortKeys2(Object.keys(recipes)))sorted2[key]=recipes[key];return sorted2}function applyResolution(lock,resolved,repos,identityOf3=()=>{}){let recipes={...lock.recipes};for(let recipe of resolved){let previous=lock.recipes[recipe.key],holders=new Set([...previous?.requestedBy??[],...recipe.requestedBy]);recipes[recipe.key]={repo:recipe.repo,version:recipe.version,hash:recipe.hash,requestedBy:sortKeys2(holders),kind:previous?.kind==="subscribes"||recipe.kind==="subscribes"?"subscribes":"depends"}}let lockedRepos={};for(let name of usedRepos(recipes)){let known=repos[name],previous=lock.repos[name],url2=known?.url??previous?.url;if(url2===void 0)throw new ConfigError23(`The lockfile cannot record the recipes from '${name}' because nothing knows that repository's URL.`,{details:["Add it with 'sous repo add <url>', so the lockfile can name where its recipes came from."]});let identity2=known?.identity??previous?.identity??identityOf3(url2),indexHash=known?.indexHash??previous?.indexHash;lockedRepos[name]={url:url2,...identity2===void 0?{}:{identity:identity2},...indexHash===void 0?{}:{indexHash}}}return{formatVersion:1,repos:lockedRepos,recipes:sortRecipes(recipes)}}function removeHolder(lock,holder,label=LOCKFILE_LABEL){let recipes={};for(let[key,entry]of Object.entries(lock.recipes))recipes[key]={...entry,requestedBy:[...entry.requestedBy]};let pending=[holder];for(;pending.length>0;){let going=new Set(pending);pending=[];for(let[key,entry]of Object.entries(recipes)){let kept=entry.requestedBy.filter(name=>!going.has(name));kept.length!==entry.requestedBy.length&&(kept.length===0?(delete recipes[key],pending.push(key)):entry.requestedBy=kept)}}return withReposOf(lock,recipes,label)}var LOCKFILE_LABEL="the lockfile";function withReposOf(lock,recipes,label){let lockedRepos={},orphaned=[];for(let name of usedRepos(recipes)){let entry=lock.repos[name];if(entry===void 0){orphaned.push(name);continue}lockedRepos[name]=entry}if(orphaned.length>0)throw new ConfigError23(`The lockfile at ${label} pins recipes to repositories it does not describe: ${orphaned.join(", ")}.`,{details:["Every repository a locked recipe came from needs an entry in the lockfile's 'repos' block.","This usually means the file was edited by hand or merged badly. Run 'sous lock rebuild' to rebuild it from your config."]});return{formatVersion:1,repos:lockedRepos,recipes:sortRecipes(recipes)}}function usedRepos(recipes){return sortKeys2(new Set(Object.values(recipes).map(entry=>entry.repo)))}function lockedClosure(lock,roots){let reached=new Set([...roots].filter(key=>Object.hasOwn(lock.recipes,key))),queue=[...reached];for(;queue.length>0;){let holder=queue.shift();for(let[key,entry]of Object.entries(lock.recipes))!reached.has(key)&&entry.requestedBy.includes(holder)&&(reached.add(key),queue.push(key))}return sortKeys2(reached)}function keysHeldBySubscription(lock,key){let heldByProject=entry=>lock.recipes[entry]?.requestedBy.includes(PROJECT_HOLDER)===!0;return key.includes("/")?heldByProject(key)?[key]:[]:sortKeys2(Object.keys(lock.recipes).filter(entry=>entry.startsWith(`${key}/`)&&heldByProject(entry)))}function diffLockfiles(before,after){let added=[],removed=[],updated=[];for(let[key,entry]of Object.entries(after.recipes)){let previous=before.recipes[key];previous===void 0?added.push({key,to:entry.version}):previous.version!==entry.version&&updated.push({key,from:previous.version,to:entry.version})}for(let[key,entry]of Object.entries(before.recipes))Object.hasOwn(after.recipes,key)||removed.push({key,from:entry.version});let byKey=(left,right)=>left.key<right.key?-1:left.key>right.key?1:0,reposAdded=sortKeys2(Object.keys(after.repos).filter(name=>!Object.hasOwn(before.repos,name))),reposRemoved=sortKeys2(Object.keys(before.repos).filter(name=>!Object.hasOwn(after.repos,name)));return added.sort(byKey),removed.sort(byKey),updated.sort(byKey),{added,removed,updated,reposAdded,reposRemoved,unchanged:added.length+removed.length+updated.length+reposAdded.length+reposRemoved.length===0}}function describeLockDiff(diff){let lines3=[];for(let name of diff.reposAdded)lines3.push(`Repository added: ${name}`);for(let change of diff.added)lines3.push(`Adding ${change.key} version ${change.to}`);for(let change of diff.updated)lines3.push(`Updating ${change.key} from version ${change.from} to version ${change.to}`);for(let change of diff.removed)lines3.push(`Removing ${change.key}, which nothing needs any more`);for(let name of diff.reposRemoved)lines3.push(`Repository no longer needed: ${name}`);return diff.unchanged&&lines3.push("Nothing changed."),lines3}function describeError2(error51){return error51 instanceof Error?error51.message:String(error51)}function compareBytewise2(left,right){let a=Buffer.from(left,"utf8"),b=Buffer.from(right,"utf8");return Buffer.compare(a,b)}function sortBytewise(items2){return[...items2].sort(compareBytewise2)}function isPlainObject4(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function entryMap(value){return isPlainObject4(value)?value:{}}var REPO_NAME_PATTERN2=/^[a-z][a-z0-9-]*$/;function shortNameFromIdentity2(identity2){let segments=identity2.split("/").map(segment=>segment.trim().toLowerCase()).filter(segment=>segment.length>0),cleaned=(segments[segments.length-1]??"").replace(/[^a-z0-9-]+/g,"-").replace(/^-+|-+$/g,"");return REPO_NAME_PATTERN2.test(cleaned)?cleaned:cleaned.length===0?"repository":`repo-${cleaned}`}function proposeRepoName(taken,identity2){let used=new Set(taken),base=shortNameFromIdentity2(identity2);if(!used.has(base))return base;for(let suffix=2;;suffix++)if(!used.has(`${base}-${suffix}`))return`${base}-${suffix}`}function hasIntent(ctx,name){return ctx.engine.intents.get(name)!==void 0}function nowIso(){return new Date().toISOString()}function dropProjectHold(lock,key){let entry=lock.recipes[key];if(entry===void 0)return lock;let kept=entry.requestedBy.filter(holder=>holder!==PROJECT_HOLDER),recipes={...lock.recipes};return kept.length>0?(recipes[key]={...entry,requestedBy:kept},{...lock,recipes}):(delete recipes[key],removeHolder({...lock,recipes},key))}function mergeHolders(left,right){let requestedBy=[...new Set([...left.requestedBy,...right.requestedBy])].sort(compareBytewise2),ranges=[...left.ranges];for(let entry of right.ranges)ranges.some(seen=>seen.range===entry.range&&seen.requestedBy===entry.requestedBy)||ranges.push(entry);return{...left,requestedBy,ranges,kind:left.kind==="subscribes"||right.kind==="subscribes"?"subscribes":"depends"}}function covers(cover,key){return cover!==void 0&&(key===cover||key.startsWith(`${cover}/`))}function releaseDroppedHolds(lock,merged,resolvedCovers,otherCovers){let recipes={...lock.recipes},orphaned=[];for(let[key,entry]of Object.entries(lock.recipes)){let settled=merged.get(key),kept=entry.requestedBy.filter(holder=>holder===PROJECT_HOLDER?!resolvedCovers.some(cover=>covers(cover,key))||otherCovers.some(cover=>covers(cover,key))?!0:settled?.requestedBy.includes(PROJECT_HOLDER)===!0:!merged.has(holder)||settled?.requestedBy.includes(holder)===!0);kept.length!==entry.requestedBy.length&&(kept.length===0?(delete recipes[key],orphaned.push(key)):recipes[key]={...entry,requestedBy:kept})}let result={...lock,recipes};for(let key of orphaned)result=removeHolder(result,key);return result}function stayedAfter(after,held){return[...new Set(held)].filter(key=>Object.hasOwn(after.recipes,key)).sort(compareBytewise2).map(key=>({key,heldBy:[...after.recipes[key].requestedBy]}))}var import_semver3=__toESM(require_semver2(),1);import fs26 from"node:fs";import path37 from"node:path";var CORE_NAMESPACE_DESCRIPTION="Skills that teach an agent about sous itself: what sous manages, how its configuration works, how templates render, and how skills are written. Auto-subscribed in every project, with opt-out-only semantics.";function builtInRepoEntry(){return{url:OFFICIAL_REPO_URL,provider:OFFICIAL_REPO_PROVIDER,addedBy:BUILT_IN_ADDED_BY}}function builtInCoreSubscription(version2){return{range:version2,addedBy:BUILT_IN_ADDED_BY}}function isBuiltInEntry(entry){return entry?.addedBy===BUILT_IN_ADDED_BY}function packagedCoreRecipeDir(packageRoot){let root=path37.resolve(packageRoot);for(let tries=0;tries<4;tries+=1){let candidate=path37.join(root,PACKAGED_RECIPES_DIRNAME,CORE_NAMESPACE,CORE_RECIPE_NAME);if(fs26.existsSync(candidate))return candidate;let parent=path37.dirname(root);if(parent===root)break;root=parent}}function coreIndexOverlay(options){let warned=!1,packagedHash=()=>typeof options.hash=="function"?options.hash():options.hash;return(identity2,index)=>{if(identity2!==OFFICIAL_REPO_IDENTITY)return index;let hash2=packagedHash();if(hash2===void 0)return index;let recipe=index.recipes[CORE_RECIPE_KEY],published=recipe?.versions[options.version];if(published!==void 0)return published.hash!==hash2&&!warned&&(warned=!0,options.onMismatch?.(published.hash,hash2)),index;let description=recipe?.description??(typeof options.description=="function"?options.description():options.description);return{...index,namespaces:{...index.namespaces,[CORE_NAMESPACE]:index.namespaces[CORE_NAMESPACE]??{description:CORE_NAMESPACE_DESCRIPTION}},recipes:{...index.recipes,[CORE_RECIPE_KEY]:{...recipe,path:recipe?.path??CORE_RECIPE_PATH,...description===void 0?{}:{description},versions:{...recipe?.versions,[options.version]:{hash:hash2,tag:`${CORE_RECIPE_KEY}@${options.version}`,prerelease:import_semver3.default.prerelease(options.version)!==null,seeded:!0}}}}}}}var USER_ADDED_BY="user";function withoutDisabled(entries){return enabledEntries(typeof entries=="object"&&entries!==null&&!Array.isArray(entries)?entries:void 0)}var REPOS_LAYER="500-repos.jsonc",SUBSCRIPTIONS_LAYER="510-subscriptions.jsonc",REPOS_HEADER=["The recipe repositories this project trusts, written by `sous repo add`.","Sous edits this file key by key; your own edits outside the keys it touches are kept."],SUBSCRIPTIONS_HEADER=["What this project subscribes to, written by `sous subscription add`.","Sous edits this file key by key; your own edits outside the keys it touches are kept."];function configuredRepos(config2){return entryMap(config2.get("repos"))}function trustedRepos(config2){return withoutDisabled(config2.get("repos"))}function configuredSubscriptions(config2){return entryMap(config2.get("subscriptions"))}function enabledSubscriptions2(config2){return withoutDisabled(config2.get("subscriptions"))}function setBy(config2,path103){let layers=config2.layers([...path103]),last2=layers[layers.length-1];return last2===void 0?void 0:contributorLabel(last2.contributor)}function contributorLabel(contributor){return contributor.startsWith("confd/")?`conf.d/${contributor.slice(6)}`:contributor}function managedContributor(file2){return`confd/${file2}`}async function managedEntries(managed,file2,key){let data=await managed.read(file2);return entryMap(data?.[key])}function writeRepoEntry(managed,name,entry,dryRun4=!1){return managed.edit(REPOS_LAYER,root=>root.atPath(["repos",name]).set(entry),{description:REPOS_HEADER,dryRun:dryRun4})}function deleteRepoEntry(managed,name,dryRun4=!1){return managed.edit(REPOS_LAYER,root=>root.atPath(["repos",name]).delete(),{description:REPOS_HEADER,dryRun:dryRun4})}function writeSubscriptionEntry(managed,key,entry,dryRun4=!1){return managed.edit(SUBSCRIPTIONS_LAYER,root=>root.atPath(["subscriptions",key]).set(entry),{description:SUBSCRIPTIONS_HEADER,dryRun:dryRun4})}function deleteSubscriptionEntry(managed,key,dryRun4=!1){return managed.edit(SUBSCRIPTIONS_LAYER,root=>root.atPath(["subscriptions",key]).delete(),{description:SUBSCRIPTIONS_HEADER,dryRun:dryRun4})}function setSubscriptionEnabled(managed,key,enabled,dryRun4=!1){return managed.edit(SUBSCRIPTIONS_LAYER,root=>root.atPath(["subscriptions",key,"enabled"]).set(enabled),{description:SUBSCRIPTIONS_HEADER,dryRun:dryRun4})}function reachableKeys(lock,subscriptions){let roots=Object.entries(subscriptions).filter(([,entry])=>entry?.enabled!==!1).flatMap(([key])=>keysHeldBySubscription(lock,key));return lockedClosure(lock,roots)}var ActiveRecipes=class{constructor(config2,services){this.config=config2;this.services=services}skippedCache;list(){let order=Object.keys(this.lockfile().recipes),position=id=>{let index=order.indexOf(id);return index===-1?order.length:index};return[...this.config.entities.list("active-recipe")].sort((left,right)=>position(left.id)-position(right.id)||compareBytewise2(left.id,right.id))}get(key){return this.config.entities.get("active-recipe",key)}skipped(){return this.skippedCache??=this.findSkipped(),this.skippedCache}contents(kind){return this.services.get("recipes.contents").of(this.list(),kind)}variables(){return this.list().flatMap(recipe=>(recipe.manifest.variables??[]).map(definition=>({recipe,definition})))}lockfile(){try{return this.services.get("recipes.lock").read()}catch{return emptyLockfile()}}reachable(lock){try{return new Set(this.services.get("recipes.resolver").reachable(lock))}catch{return new Set(reachableKeys(lock,configuredSubscriptions(this.config)))}}findSkipped(){let lock=this.lockfile(),active=new Set(this.config.entities.list("active-recipe").map(entity=>entity.id)),reachable2=this.reachable(lock),repos=configuredRepos(this.config),subscriptions=configuredSubscriptions(this.config),skipped=[];for(let[key,entry]of Object.entries(lock.recipes)){if(active.has(key))continue;let repo=repos[entry.repo];if(repo===void 0){skipped.push({key,reason:"untrusted",message:`Skipped ${key}: this project does not trust its repository '${entry.repo}'.`});continue}if(repo.enabled===!1){let file2=setBy(this.config,["repos",entry.repo,"enabled"]);skipped.push({key,reason:"repository-disabled",...file2===void 0?{}:{setBy:file2},message:`Skipped ${key}: its repository '${entry.repo}' is switched off${file2===void 0?"":` (${file2})`}.`});continue}if(reachable2.has(key)){skipped.push({key,reason:"missing",message:`Skipped ${key}: its files are not on this machine yet.`});continue}let off=Object.keys(subscriptions).sort(compareBytewise2).find(subscription=>subscriptions[subscription]?.enabled===!1&&lockedClosure(lock,keysHeldBySubscription(lock,subscription)).includes(key));if(off!==void 0){let file2=setBy(this.config,["subscriptions",off,"enabled"]);skipped.push({key,reason:"subscription-disabled",subscription:off,...file2===void 0?{}:{setBy:file2},message:`Skipped ${key}: its subscription is switched off${file2===void 0?"":` (${file2})`}.`});continue}skipped.push({key,reason:"not-reached",message:`Skipped ${key}: no subscription in force reaches it.`})}return skipped}};var import_semver4=__toESM(require_semver2(),1);import{jsonSchema as jsonSchema11}from"@sous-io/plugin-api";var DEFAULT_STORE_MAX_BYTES=1024*1024*1024,DEFAULT_FRESHNESS_SECONDS2=300,DEFAULT_WATCH_POLL_SECONDS=300,repoEntry={type:"object",description:"One trusted repository. Adding it trusts it.",properties:{url:{type:"string",description:"Where the repository lives."},enabled:{type:"boolean",description:"False opts out of a repository sous provides itself."},provider:{type:"string",description:"The repository host, when the URL does not give it away."},alwaysPull:{type:"boolean",description:"Install a newer in-range version whenever one exists."},addedAt:{type:"string"},addedBy:{type:"string"}},required:["url"],additionalProperties:!1},subscriptionEntry={type:"object",description:"One subscription, to a namespace or to one recipe.",properties:{enabled:{type:"boolean",description:"False switches it off on this machine, keeping its pins."},range:{type:"string",description:"The version range. Default `*`."},prerelease:{type:"boolean"},alwaysPull:{type:"boolean"},addedAt:{type:"string"},addedBy:{type:"string"}},additionalProperties:!1},store={type:"object",description:"The machine-wide recipe store.",default:{},properties:{maxBytes:{type:"integer",default:DEFAULT_STORE_MAX_BYTES,description:"Size cap past which old entries are collected."},freshnessSeconds:{type:"integer",default:DEFAULT_FRESHNESS_SECONDS2,description:"How long a fetched index stays fresh."},watchPollSeconds:{type:"integer",default:DEFAULT_WATCH_POLL_SECONDS,description:"How often watch mode checks upstream."}},additionalProperties:!1},SUBSCRIPTION_KEY_PATTERN=/^[a-z][a-z0-9-]*(\/[a-z][a-z0-9-]*)?$/;function objectOf2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)?value:void 0}function isRepoUrl(url2){return/^[a-z][a-z0-9+.-]*:\/\/\S+$/i.test(url2)||/^[\w.-]+@[\w.-]+:\S+$/.test(url2)||url2.startsWith("/")||/^[A-Za-z]:[\\/]/.test(url2)}function checked2(schema,more){let standard=jsonSchema11(schema)["~standard"];return{"~standard":{...standard,validate(value){let result=standard.validate(value),object3=objectOf2(value),extra=object3===void 0?[]:more(object3);return extra.length===0?result:{issues:[...result.issues??[],...extra]}}}}}function repoIssues(repos){let issues=[];for(let[name,entry]of Object.entries(repos)){REPO_NAME_PATTERN2.test(name)||issues.push({path:[name],message:"invalid key; a repo name must be lowercase kebab-case: a letter, then letters, digits or hyphens (for example 'sous-recipes')"});let url2=objectOf2(entry)?.url;typeof url2=="string"&&!isRepoUrl(url2)&&issues.push({path:[name,"url"],message:"must be a repository URL, or an absolute path to one on this machine"})}return issues}function subscriptionIssues(subscriptions){let issues=[];for(let[key,entry]of Object.entries(subscriptions)){SUBSCRIPTION_KEY_PATTERN.test(key)||issues.push({path:[key],message:"invalid key; a subscription key must be a namespace ('workflow') or a namespace and recipe ('workflow/task-files'), with no repository qualifier and no version range (the range goes in the entry)"});let range3=objectOf2(entry)?.range;typeof range3=="string"&&import_semver4.default.validRange(range3)===null&&issues.push({path:[key,"range"],message:"must be a semantic version range, such as '^1.2.0', '~2.1', '>=1.0.0 <2.0.0' or '*'"})}return issues}function storeIssues(store2){let issues=[];for(let name of["maxBytes","freshnessSeconds","watchPollSeconds"]){let value=store2[name];typeof value=="number"&&(!Number.isInteger(value)||(name==="maxBytes"?value<=0:value<0))&&issues.push({path:[name],message:name==="maxBytes"?"must be a whole number of bytes, above zero":"must be a whole number of seconds, zero or more"})}return issues}function configKeys(){return[{id:"repos",description:"The repositories this project trusts, by short name.",schema:checked2({type:"object",default:{},additionalProperties:repoEntry},repoIssues)},{id:"subscriptions",description:"What this project subscribes to, keyed by namespace or namespace/recipe.",schema:checked2({type:"object",default:{},additionalProperties:subscriptionEntry},subscriptionIssues)},{id:"store",description:"The machine-wide recipe store's settings.",schema:checked2(store,storeIssues)}]}function foldDeclaration(before,entry){let keepBefore=before!==void 0&&!entry.named;return{declared:keepBefore?before.declared:entry.written.trim(),ref:keepBefore?before.ref:entry.ref,kind:before?.kind==="subscribes"||entry.kind==="subscribes"?"subscribes":"depends",named:entry.named||before?.named===!0}}function isNamed(ref){return ref.kind==="namespace"||ref.kind==="recipe"}var Declarations=class{constructor(resolver,format3){this.resolver=resolver;this.format=format3}of(source){let found=[];for(let[kind,entries]of this.lists(source))for(let written of entries){let ref=this.readings(written)[0];ref&&found.push({declared:written.trim(),kind,ref,named:ref.kind==="recipe"})}return found}covering(source,key){let format3=this.format(),gathered;for(let[kind,entries]of[...this.lists(source)].reverse())for(let written of entries)for(let ref of this.readings(written)){let named=ref.kind==="recipe";if(named?format3.key(ref)===key:format3.namespaceOfKey(key)===ref.name){gathered=foldDeclaration(gathered,{written,kind,named,ref});break}}return gathered}lists(source){return[["subscribes",source.subscribes??[]],["depends",source.depends??[]]]}readings(written){try{return this.resolver().parse(written,"manifest").refs.filter(isNamed)}catch{return[]}}};var import_semver7=__toESM(require_semver2(),1);import{SousError as SousError17}from"@sous-io/plugin-api";var import_semver5=__toESM(require_semver2(),1);import{SousError as SousError15}from"@sous-io/plugin-api";function namespaceOfKey3(key){let slash=key.indexOf("/");return slash===-1?key:key.slice(0,slash)}function splitRecipeKey(key){let slash=key.indexOf("/");return{namespace:key.slice(0,slash),name:key.slice(slash+1)}}function listNamespaces(inputs){let subscriptions=new Set(inputs.subscriptions),listings=[];for(let repo of inputs.repos)for(let[namespace,declared]of Object.entries(repo.index.namespaces))listings.push({repo:repo.name,namespace,...declared.description===void 0?{}:{description:declared.description},recipeCount:recipeKeysIn(repo.index,namespace).length,subscribed:coverageOf(namespace,repo.index,subscriptions)});return listings.sort((left,right)=>compareBytewise2(left.namespace,right.namespace)||compareBytewise2(left.repo,right.repo))}function listRecipes(inputs){let subscriptions=new Set(inputs.subscriptions),listings=[];for(let repo of inputs.repos)for(let key of Object.keys(repo.index.recipes))listings.push(recipeListing(key,repo,inputs,subscriptions));return listings.sort((left,right)=>compareBytewise2(left.key,right.key)||compareBytewise2(left.repo,right.repo))}function describeNamespace(inputs,found){let subscriptions=new Set(inputs.subscriptions),declared=found.repo.index.namespaces[found.namespace]??{};return{repo:found.repo.name,...found.repo.url===void 0?{}:{repoUrl:found.repo.url},namespace:found.namespace,...declared.description===void 0?{}:{description:declared.description},subscribed:coverageOf(found.namespace,found.repo.index,subscriptions),recipes:recipeKeysIn(found.repo.index,found.namespace).map(key=>recipeListing(key,found.repo,inputs,subscriptions))}}function describedLocation(inputs,found){let listing=recipeListing(found.key,found.repo,inputs,new Set(inputs.subscriptions)),version2=listing.pinned??listing.latest,entry=found.repo.index.recipes[found.key];return version2===void 0?void 0:{key:found.key,namespace:listing.namespace,name:listing.name,repo:found.repo.name,version:version2,path:entry.path}}function describeRecipe(inputs,found,manifest){let subscriptions=new Set(inputs.subscriptions),listing=recipeListing(found.key,found.repo,inputs,subscriptions),entry=found.repo.index.recipes[found.key],describing=listing.pinned??listing.latest,published=describing===void 0?void 0:entry.versions[describing];return{...listing,...found.repo.url===void 0?{}:{repoUrl:found.repo.url},path:entry.path,...describing===void 0?{}:{describing},versions:versionListings(entry.versions,listing.latest,listing.pinned),dependencies:dependencyListings(published?.dependencies,manifest,inputs),dependenciesRecorded:published?.dependencies!==void 0,contents:(manifest?.contents??[]).map(content=>({kind:content.kind,include:[...content.include],destinations:inputs.destinationsFor?.(content.kind)??[]})),variables:manifest?.variables??published?.variables??[],manifestRead:manifest!==void 0}}function narrowToInstalled(inputs){let repos=inputs.repos.map(repo=>{let recipes=Object.fromEntries(Object.entries(repo.index.recipes).filter(([key])=>inputs.lock.recipes[key]?.repo===repo.name)),held=new Set(Object.keys(recipes).map(namespaceOfKey3)),namespaces=Object.fromEntries(Object.entries(repo.index.namespaces).filter(([namespace])=>held.has(namespace)));return{...repo,index:{...repo.index,recipes,namespaces}}});return{...inputs,repos}}function repoOf2(ref){let repo=ref.kind==="namespace"?ref.repo:ref.namespace?.repo??ref.repo;if(repo!==void 0)return{...repo.name===void 0?{}:{name:repo.name},...repo.location?.identity===void 0?{}:{identity:repo.location.identity}}}function sameText(written,published){return written===published?"exact":written.toLowerCase()===published.toLowerCase()?"folded":void 0}function publishedNamespaceRef(repo,namespace){let declared=repo.index.namespaces[namespace];return{kind:"namespace",name:namespace,repo:{kind:"repo",name:repo.name},...declared?.description===void 0?{}:{description:declared.description}}}function publishedRecipeRef(repo,key){let{namespace,name}=splitRecipeKey(key),description=repo.index.recipes[key]?.description;return{kind:"recipe",name,namespace:{kind:"namespace",name:namespace,repo:{kind:"repo",name:repo.name}},...description===void 0?{}:{description}}}function findInCatalog(inputs,readings,kinds){let matches=new Map,add=match2=>{let id=`${match2.repo.name}:${match2.ref.kind}:${match2.key}`,known=matches.get(id);(known===void 0||!known.exact&&match2.exact)&&matches.set(id,match2)};for(let reading of readings){if(reading.kind!=="namespace"&&reading.kind!=="recipe"||!kinds.includes(reading.kind))continue;let wanted=repoOf2(reading),repos=inputs.repos.filter(repo=>wanted===void 0||wanted.name!==void 0&&sameText(wanted.name,repo.name)!==void 0||wanted.identity!==void 0&&repo.identity!==void 0&&wanted.identity.toLowerCase()===repo.identity.toLowerCase());for(let repo of repos){if(reading.kind==="namespace"){for(let namespace of Object.keys(repo.index.namespaces)){let same=sameText(reading.name,namespace);same&&add({ref:publishedNamespaceRef(repo,namespace),repo,key:namespace,exact:same==="exact"})}continue}for(let key of Object.keys(repo.index.recipes)){let{namespace,name}=splitRecipeKey(key),sameName=sameText(reading.name,name),sameNamespace=reading.namespace===void 0?"exact":sameText(reading.namespace.name,namespace);if(sameName&&sameNamespace){let ref={...publishedRecipeRef(repo,key),...reading.range===void 0?{}:{range:reading.range}};add({ref,repo,key,exact:sameName==="exact"&&sameNamespace==="exact"})}}}}let order=new Map(inputs.repos.map((repo,index)=>[repo.name,index]));return[...matches.values()].sort((left,right)=>Number(right.exact)-Number(left.exact)||(order.get(left.repo.name)??0)-(order.get(right.repo.name)??0)||compareBytewise2(left.key,right.key))}function unknownRefError(inputs,ref,what,notFetched=[]){let searched=inputs.repos.length===0?"none":inputs.repos.map(repo=>repo.name).join(", ");return new SousError15(`No repository this project trusts publishes a ${what} called '${ref}'.`,{details:[`Repositories with an index sous has read: ${searched}.`,...notFetched.length===0?[]:[`These repositories are trusted but their index could not be read, so nothing in them was searched: ${notFetched.join(", ")}.`],`Run 'sous repo search ${ref}' to look for something like it, or 'sous repo add <url>' to add the repository that publishes it.`]})}function recipeKeysIn(index,namespace){return Object.keys(index.recipes).filter(key=>namespaceOfKey3(key)===namespace).sort(compareBytewise2)}function coverageOf(namespace,index,subscriptions){return subscriptions.has(namespace)?"whole namespace":recipeKeysIn(index,namespace).some(key=>subscriptions.has(key))?"some recipes":"none"}function recipeListing(key,repo,inputs,subscriptions){let entry=repo.index.recipes[key],{namespace,name}=splitRecipeKey(key),latest2=latestVersion(entry.versions),locked=inputs.lock.recipes[key],pinned=locked!==void 0&&locked.repo===repo.name?locked.version:void 0,linkedPath=pinned===void 0?void 0:inputs.linked?.[repo.name];return{key,namespace,name,repo:repo.name,...latest2===void 0?{}:{latest:latest2},...pinned===void 0?{}:{pinned},...linkedPath===void 0?{}:{linkedPath},subscribed:subscriptions.has(key)||subscriptions.has(namespace),...entry.description===void 0?{}:{description:entry.description}}}function latestVersion(versions){let all=Object.keys(versions).filter(version2=>import_semver5.default.valid(version2,{loose:!0})!==null),stable=all.filter(version2=>versions[version2]?.prerelease!==!0);return import_semver5.default.maxSatisfying(stable.length>0?stable:all,"*",{includePrerelease:!0,loose:!0})??void 0}function versionListings(versions,latest2,pinned){return Object.keys(versions).sort((left,right)=>{let a=import_semver5.default.valid(left,{loose:!0}),b=import_semver5.default.valid(right,{loose:!0});return a!==null&&b!==null?import_semver5.default.rcompare(a,b,{loose:!0}):compareBytewise2(right,left)}).map(version2=>{let entry=versions[version2];return{version:version2,status:version2===latest2&&version2===pinned?"latest and pinned":version2===latest2?"latest":version2===pinned?"pinned":"other",prerelease:entry.prerelease,...entry.releasedAt===void 0?{}:{releasedAt:entry.releasedAt}}})}function dependencyListings(resolved,manifest,inputs){let rows=new Map,lists=manifest===void 0?void 0:{depends:manifest.depends??[],subscribes:manifest.subscribes??[]};for(let[key,entry]of Object.entries(resolved??{})){let declaration=entry.declared!==void 0&&entry.kind!==void 0?{declared:entry.declared,kind:entry.kind}:lists===void 0?void 0:inputs.declarationFor?.(lists,key);rows.set(key,{key,...entry.version===void 0?{}:{resolvedVersion:entry.version},...entry.range===void 0?{}:{resolvedRange:entry.range},...entry.repo===void 0?{}:{repo:entry.repo},...declaration===void 0?{}:{declared:declaration.declared,kind:declaration.kind}})}let covered=new Set([...rows.values()].map(row=>row.declared));for(let[kind,entries]of[["depends",lists?.depends??[]],["subscribes",lists?.subscribes??[]]])for(let written of entries){if(covered.has(written.trim()))continue;let key=written.trim().replace(/@.*$/,"");rows.set(key,{...rows.get(key)??{key},declared:written,kind})}return[...rows.values()].sort((left,right)=>compareBytewise2(left.key,right.key))}import path39 from"node:path";import path38 from"node:path";function listOf(ctx,kind){try{return ctx.entities.list(kind)}catch{return[]}}function resolveVariables(ctx,value){if(!value.includes("${")||ctx.services===void 0||!ctx.services.has("variables.resolver"))return value;try{let resolver=ctx.services.get("variables.resolver");return resolver.normalizePath(resolver.substituteStrict(value,resolver.scope({level:"root"}),"recipes.skills.outputs"))}catch{return value}}function underRoot(root,target){return root===void 0||path38.isAbsolute(target)||target.startsWith("${")?target:path38.join(root,target)}function distinct(paths){return[...new Set(paths)].sort(compareBytewise2)}function destinationsFor(ctx,kind){let root=ctx.project?.root;if(kind==="skills"){let targets=listOf(ctx,"skill-target").map(target=>target.directory).filter(directory=>typeof directory=="string"&&directory.length>0),outputs=ctx.config.get(["recipes","skills","outputs"]),extra=Array.isArray(outputs)?outputs.filter(output=>typeof output=="string"&&output.length>0):[];return distinct([...targets,...extra].map(target=>underRoot(root,resolveVariables(ctx,target))))}return kind==="memories"?distinct(listOf(ctx,"memory-target").filter(target=>typeof target.fileName=="string"&&target.fileName.length>0).map(target=>underRoot(root,path38.join(typeof target.directory=="string"?target.directory:"",target.fileName)))):[]}function repoSearchOrder(ctx){let repos=trustedRepos(ctx.config),names2=Object.keys(repos),builtIn=names2.filter(name=>isBuiltInEntry(repos[name]));return[...builtIn,...names2.filter(name=>!builtIn.includes(name))]}function identityOf(ctx,url2){try{return ctx.services.get("refs.locations").identity(url2)}catch{return}}async function readUpstream(ctx,name){let cache2=ctx.services.get("recipes.index-cache"),entry=trustedRepos(ctx.config)[name],identity2=entry===void 0?void 0:identityOf(ctx,entry.url),linked=ctx.services.has("recipes.links")&&ctx.services.get("recipes.links").get(name)!==void 0;if(entry===void 0||identity2===void 0||linked)return cache2.get(name,{latest:!0});let index=await cache2.fetchUpstream({name,url:entry.url,identity:identity2,...entry.provider===void 0?{}:{provider:entry.provider}});return{repo:name,index,source:"network"}}async function readIndexes(ctx,flags){let cache2=ctx.services.get("recipes.index-cache"),sources=new Map,notFetched=[],notChecked=[];for(let name of repoSearchOrder(ctx)){if(flags.latest===!0)try{let read=await readUpstream(ctx,name);read.source==="stale"&&notChecked.push({repo:name,reason:read.problem??"upstream could not be reached"}),sources.set(name,read);continue}catch(error51){notChecked.push({repo:name,reason:describeError2(error51)})}let cached2=cache2.cached(name);cached2===void 0?notFetched.push(name):sources.set(name,cached2)}return{notFetched:notFetched.filter(name=>!sources.has(name)),notChecked,sources}}async function loadCatalog(ctx,flags={}){let read=await readIndexes(ctx,flags),trusted=trustedRepos(ctx.config),repos=[...read.sources.entries()].map(([name,cached2])=>{let url2=trusted[name]?.url,identity2=cached2.meta?.identity??(url2===void 0?void 0:identityOf(ctx,url2));return{name,index:cached2.index,...url2===void 0?{}:{url:url2},...identity2===void 0?{}:{identity:identity2}}}),linked={};if(ctx.services.has("recipes.links"))for(let[name,link]of Object.entries(ctx.services.get("recipes.links").all()))linked[name]=link.path;let lock=emptyLockfile();try{lock=ctx.services.get("recipes.lock").read()}catch{}let declarations=ctx.services.has("recipes.declarations")?ctx.services.get("recipes.declarations"):void 0,inputs={repos,lock,subscriptions:Object.keys(enabledSubscriptions2(ctx.config)).sort(),linked,...ctx.entities===void 0?{}:{destinationsFor:kind=>destinationsFor({entities:ctx.entities,config:ctx.config,project:ctx.project,services:ctx.services},kind)},...declarations===void 0?{}:{declarationFor:(source,key)=>{let found=declarations.covering(source,key);return found===void 0?void 0:{declared:found.declared,kind:found.kind}}}};return{...read,inputs:flags.installed===!0?narrowToInstalled(inputs):inputs}}function recipeFilesDirectory(ctx,catalog,location){let checkout=catalog.linked?.[location.repo];if(checkout!==void 0)return path39.join(checkout,location.path);let identity2=catalog.repos.find(repo=>repo.name===location.repo)?.identity??catalog.lock.repos[location.repo]?.identity;if(identity2!==void 0)try{return ctx.services.get("recipes.store").entryDir({identity:identity2,namespace:location.namespace,name:location.name,version:location.version})}catch{return}}async function readPublishedManifest(ctx,catalog,location){let directory=recipeFilesDirectory(ctx,catalog,location);if(directory!==void 0)try{return(await ctx.services.get("formats.manifests").readRecipe(directory))?.manifest}catch{return}}function readingsOf(ctx,input){return ctx.services.get("refs.resolver").parse(input.trim(),"commandLine").refs}async function pickMatch(ctx,matches,search2,acceptFirst2,none,options={}){if(matches.length===0)throw none();let exact=matches.filter(match2=>match2.exact),settled=matches.length===1?matches[0]:acceptFirst2===!0?void 0:exact.length===1?exact[0]:void 0;if(options.announce===!0&&(settled!==void 0||acceptFirst2===!0)){let candidates=settled===void 0?matches:[settled],picked2=await ctx.services.get("refs.picker").pick(candidates.map(match2=>match2.ref),{search:search2,...acceptFirst2===void 0?{}:{acceptFirst:acceptFirst2}},ctx);return candidates.find(match2=>match2.ref===picked2)??candidates[0]}if(settled!==void 0)return settled;if(acceptFirst2===!0)return matches[0];let picked=await ctx.services.get("refs.picker").pick(matches.map(match2=>match2.ref),{search:search2,...acceptFirst2===void 0?{}:{acceptFirst:acceptFirst2}},ctx);return matches.find(match2=>match2.ref===picked)??matches[0]}async function resolveInCatalog(ctx,catalog,input,kinds,acceptFirst2,none){let matches=findInCatalog(catalog.inputs,readingsOf(ctx,input),kinds);return pickMatch(ctx,matches,input.trim(),acceptFirst2,none)}import path40 from"node:path";var import_semver6=__toESM(require_semver2(),1);import{SousError as SousError16}from"@sous-io/plugin-api";var INSTALL_INTENT="plugins.install";function describeUnmet(unmet){return unmet.installed===void 0?`'${unmet.recipe}' requires the plugin ${unmet.plugin} ${unmet.range}, which is not installed.`:`'${unmet.recipe}' requires the plugin ${unmet.plugin} ${unmet.range}, and version ${unmet.installed} is installed.`}function specsOf(unmet){return[...new Set(unmet.map(entry=>`${entry.plugin}@${entry.range}`))]}function unmetRequirements(required2,loaded){let unmet=[];for(let{recipe,plugins}of required2)for(let[plugin,range3]of Object.entries(plugins)){let found=loaded.find(entry=>entry.name===plugin),version2=found?.version;found!==void 0&&(version2===void 0||import_semver6.default.satisfies(version2,range3,{includePrerelease:!0}))||unmet.push({recipe,plugin,range:range3,...found===void 0||version2===void 0?{}:{installed:version2}})}return unmet}async function recipeDirectory(ctx,recipe,download2){let entry=trustedRepos(ctx.config)[recipe.repo];if(!(entry===void 0||!ctx.services.has("recipes.store")||!ctx.services.has("recipes.index-cache"))){if(!download2)try{return(await ctx.services.get("recipes.store").get({identity:recipe.identity,namespace:recipe.namespace,name:recipe.name,version:recipe.version}))?.dir}catch{return}try{return(await ctx.services.get("recipes.index-cache").ensureInStore({key:recipe.key,entry:{repo:recipe.repo,version:recipe.version,hash:recipe.hash,requestedBy:recipe.requestedBy,kind:recipe.kind},repo:recipe.repo,url:entry.url,identity:recipe.identity,...entry.provider===void 0?{}:{provider:entry.provider}},{store:ctx.services.get("recipes.store"),hosts:ctx.entities.list("repository-host"),context:{plugin:ctx.plugin,config:ctx.config,services:ctx.services,entities:ctx.entities,project:ctx.project,env:ctx.env,cwd:ctx.cwd,reporter:ctx.reporter}})).dir}catch{return}}}async function requiredPlugins(ctx,resolved,download2=!0){if(!ctx.services.has("formats.manifests"))return[];let manifests=ctx.services.get("formats.manifests"),required2=[];for(let recipe of resolved){let dir=await recipeDirectory(ctx,recipe,download2);if(dir===void 0)continue;let plugins;try{plugins=(await manifests.readRecipe(dir))?.manifest.requires?.plugins}catch{plugins=void 0}plugins!==void 0&&Object.keys(plugins).length>0&&required2.push({recipe:recipe.key,plugins})}return required2}async function ensureRequiredPlugins(ctx,resolved,flags,ref){let required2=await requiredPlugins(ctx,resolved,flags.dryRun!==!0),unmet=required2.length===0?[]:unmetRequirements(required2,ctx.engine.plugins());if(unmet.length===0)return;let specs=specsOf(unmet);for(let entry of unmet)ctx.reporter.note(describeUnmet(entry));if(flags.dryRun===!0)return{intent:INSTALL_INTENT,skipped:"--dry-run"};let install=flags.installPlugins===!0;if(!install&&ctx.prompter.interactive&&(install=await ctx.prompter.confirm({message:`Install ${specs.join(", ")} now?`,answeredBy:"--install-plugins",default:!0})),!install)throw new SousError16(unmet.length===1?describeUnmet(unmet[0]):`'${ref}' requires plugins that are not installed: ${specs.join(", ")}.`,{details:["Nothing was written.",`Run 'sous subscription add ${ref} --install-plugins' to install ${unmet.length===1?"it":"them"} through this project's package manager, or install ${unmet.length===1?"it":"them"} yourself (for example, 'npm install --save-dev ${specs.join(" ")}').`]});if(!hasIntent(ctx,INSTALL_INTENT))throw new SousError16(`'${ref}' requires ${specs.join(", ")}, and no plugin provides '${INSTALL_INTENT}' to install ${unmet.length===1?"it":"them"}.`,{details:["Nothing was written. Switch on @sous-io/plugin-update, or install the plugins yourself."]});let outputs=await ctx.run(INSTALL_INTENT,{plugins:specs,yes:!0}),result=outputs.toPlain();if(result.declined||result.exitCode!==void 0&&result.exitCode!==0)throw new SousError16(`Sous could not install ${specs.join(", ")}, so nothing was subscribed.`,{details:[result.declined?"The install was declined.":`${[result.command.command,...result.command.args].join(" ")} exited with code ${result.exitCode}.`]});return{intent:INSTALL_INTENT,result,outputs}}var RUNG_LABELS={mapping:"mapping record",recipe:"recipe scope",namespace:"namespace scope",shared:"shared scope",bare:"declared name"};function envFileOf(definition){return definition.secret===!0||definition.scope==="local"?".env.local":".env"}function describeSource(source){let where2=source.file==="shell"?"the shell environment":source.file==="local"?"the .env.local file":"the .env file";return`${source.rung==="bare"?`the ${RUNG_LABELS.bare}`:`the ${RUNG_LABELS[source.rung]??source.rung} name`} ${source.envName}, from ${where2}`}async function variablesOf(ctx,recipe,download2){if(recipe.variables!==void 0)return recipe.variables;if(!ctx.services.has("formats.manifests"))return;let dir=await recipeDirectory(ctx,recipe,download2);if(dir!==void 0)try{return(await ctx.services.get("formats.manifests").readRecipe(dir))?.manifest.variables??[]}catch{return}}async function definedVariables(ctx,resolved,download2=!1){let format3=ctx.services.get("refs.format"),defined=[],unreadable2=[];for(let recipe of[...resolved].sort((left,right)=>left.key<right.key?-1:left.key>right.key?1:0)){let variables=await variablesOf(ctx,recipe,download2);if(variables===void 0){unreadable2.push(recipe.key);continue}for(let definition of variables)defined.push({definition,recipe:{repo:recipe.repo,namespace:recipe.namespace,name:recipe.name,version:recipe.version,identity:recipe.identity},ref:{kind:"variable",name:definition.name,recipe:format3.recipeRef(recipe.namespace,recipe.name,{repo:recipe.repo})},key:`${recipe.key}.${definition.name}`})}return{defined,unreadable:unreadable2}}function plannedQuestionsOf(ctx,defined){let ladder=ctx.services.has("recipe-answers.ladder")?ctx.services.get("recipe-answers.ladder"):void 0;return defined.map(variable=>{let{definition}=variable,found,storedAs;try{found=ladder?.resolve(variable),storedAs=ladder?.bareName(variable)}catch{}return{recipe:`${variable.recipe.namespace}/${variable.recipe.name}`,definition,...storedAs===void 0?{}:{storedAs},...ctx.project===void 0?{}:{storagePath:path40.join(ctx.project.sousDir,envFileOf(definition))},answered:found!==void 0,...found===void 0?{}:{answeredFrom:describeSource(found.source)}}})}async function planQuestions(ctx,resolved){let{defined,unreadable:unreadable2}=await definedVariables(ctx,resolved);return{questions:plannedQuestionsOf(ctx,defined),unreadable:unreadable2}}import{commandVariables}from"@sous-io/plugin-api";import{IntentOutput as IntentOutput5,IntentOutputs as IntentOutputs9,ItemList as ItemList2,ReportEntryStyle as ReportEntryStyle3,Table as Table2,TextBlock as TextBlock5,VariableSet as VariableSet3}from"@sous-io/plugin-api";function sentence(summary,title2){return new IntentOutput5({...title2===void 0?{}:{title:title2},summary})}function noteOutput(text,title2){return new IntentOutput5({...title2===void 0?{}:{title:title2},result:new TextBlock5(text),style:ReportEntryStyle3.Note})}function dryRunOutput(text,title2){return new IntentOutput5({...title2===void 0?{}:{title:title2},result:new TextBlock5(text),style:ReportEntryStyle3.DryRun})}function detailOutput(text,title2){return new IntentOutput5({...title2===void 0?{}:{title:title2},result:new TextBlock5(text),style:ReportEntryStyle3.Detail})}function listOutput(items2,options={}){return new IntentOutput5({...options.heading===void 0?{}:{title:options.heading},result:new ItemList2(items2,options.listTitle===void 0?{}:{title:options.listTitle})})}function blockOutput(entries,options={}){return new IntentOutput5({...options.heading===void 0?{}:{title:options.heading},result:new VariableSet3(entries,options.blockTitle===void 0?{}:{title:options.blockTitle})})}function tableOutput(columns,rows,options={}){return new IntentOutput5({...options.heading===void 0?{}:{title:options.heading},result:new Table2(columns,rows,{...options.tableTitle===void 0?{}:{title:options.tableTitle},...options.empty===void 0?{}:{empty:options.empty},...options.rowNotes===void 0?{}:{rowNotes:options.rowNotes}})})}function retitled(output,title2){return new IntentOutput5({title:title2,...output.summary===void 0?{}:{summary:output.summary},...output.result===void 0?{}:{result:output.result},...output.data===void 0?{}:{data:output.data},...output.style===void 0?{}:{style:output.style}})}function underHeading(heading,outputs){let[first2,...rest]=outputs;return first2===void 0?[new IntentOutput5({title:heading})]:first2.title===void 0?[retitled(first2,heading),...rest]:[new IntentOutput5({title:heading}),first2,...rest]}function finish2(own,data,options={}){let exit=options.exitCode===void 0?{}:{exitCode:options.exitCode};return new IntentOutputs9([...own,...options.after??[]],exit).withData(data)}function plainFollowUps(followUps){return followUps.map(entry=>({intent:entry.intent,...entry.result===void 0?{}:{result:entry.result},...entry.skipped===void 0?{}:{skipped:entry.skipped}}))}function plainResult(result){return{...result,followUps:plainFollowUps(result.followUps)}}function followUpOf(result,intent){return result.followUps?.find(entry=>entry.intent===intent)}function rebuilt(result){let build2=followUpOf(result,"build");return build2!==void 0&&build2.skipped===void 0}function buildFailed(entry){return(entry.outputs?.exitCode??0)!==0||entry.result?.ok===!1}function followUpOutputs(result){let outputs=[],failed=!1;for(let entry of result.followUps??[]){if(entry.skipped!==void 0||entry.outputs===void 0)continue;let shown=entry.outputs.toArray();outputs.push(...entry.intent==="vars.ask"?underHeading("Variables",shown):shown),entry.intent==="build"&&buildFailed(entry)&&(failed=!0)}return{outputs,failed}}function finishWithFollowUps(ctx,own,result,failedMessage){let{outputs,failed}=followUpOutputs(result);return failed&&ctx.reporter.error(failedMessage),finish2(own,plainResult(result),{after:outputs,...failed?{exitCode:1}:{}})}function lockDiffLines(diff){let byKey=(left,right)=>left.key<right.key?-1:left.key>right.key?1:0,lines3=[...diff.reposAdded.map(name=>`Repository added: ${name}`),...[...diff.added].sort(byKey).map(change=>`Adding ${change.key} version ${change.to}`),...[...diff.updated].sort(byKey).map(change=>`Updating ${change.key} from version ${change.from} to version ${change.to}`),...[...diff.removed].sort(byKey).map(change=>`Removing ${change.key}, which nothing needs any more`),...diff.reposRemoved.map(name=>`Repository no longer needed: ${name}`)];return lines3.length===0?["Nothing changed."]:lines3}function lockfileOutput(diff,whenUnchanged){return diff.unchanged?sentence(whenUnchanged,"Lockfile"):listOutput(lockDiffLines(diff),{heading:"Lockfile"})}function describeSize(bytes){if(bytes<1024)return`${bytes} bytes`;let units=["KB","MB","GB","TB"],value=bytes/1024,unit=0;for(;value>=1024&&unit<units.length-1;)value/=1024,unit+=1;return`${value.toFixed(1)} ${units[unit]}`}function firstSentence(text){return(/^.*?[.!?](?=\s|$)/s.exec(text.trim())?.[0]??text.trim()).replace(/\s+/g," ")}function questionCount(count2){return count2===1?"1 question":`${count2} questions`}function questionFacts(question,answerHint){let variable=question.definition,entries=[];return variable.description!==void 0&&variable.description!==""&&entries.push({label:"about",value:firstSentence(variable.description)}),variable.example!==void 0&&entries.push({label:"example",value:String(variable.example)}),question.storedAs!==void 0&&question.storedAs!==""&&entries.push({label:"stored-as",value:question.storedAs}),question.storagePath!==void 0&&question.storagePath!==""&&entries.push({label:"storage-path",value:question.storagePath}),entries.push({label:"answered",value:question.answered?`yes${question.answeredFrom===void 0?"":`, from ${question.answeredFrom}`}`:variable.required===!1?"no, and an answer is optional":"no, and this recipe requires an answer"}),answerHint&&entries.push({label:"answer-with",value:`--answer ${variable.name}=<value>`}),entries}function questionPlanOutputs(plan,options){let count2=plan.questions.length,unanswered=plan.questions.filter(question=>!question.answered).length,unreadable2=plan.unreadable.length===0?void 0:`Not on this machine yet, and their repository's index does not record their questions, so they cannot be listed: ${plan.unreadable.join(", ")}.`+(options.answerHints?" A dry run downloads nothing; run this command again without '--dry-run' to install them and be asked.":"");if(count2===0)return[unreadable2===void 0?sentence("None of these recipes ask any questions, so nothing needs answering."):noteOutput(unreadable2)];let subject2=plan.unreadable.length===0?"These recipes ask":"The recipes sous could read ask",outputs=[sentence(unanswered===0?`${subject2} ${questionCount(count2)}, and everything they ask is already answered.`:`${subject2} ${questionCount(count2)}, ${unanswered} of which nothing answers yet.`)],groups=new Map;for(let question of plan.questions)groups.set(question.recipe,[...groups.get(question.recipe)??[],question]);for(let[recipe,questions]of groups)questions.forEach((question,index)=>{outputs.push(blockOutput(questionFacts(question,options.answerHints),{blockTitle:question.definition.name,...index===0?{heading:`${recipe} asks ${questionCount(questions.length)}`}:{}}))});return unreadable2!==void 0&&outputs.push(noteOutput(unreadable2)),options.answerHints&&unanswered>0&&outputs.push(noteOutput("Answer them all ahead of time by running this command again without '--dry-run', with one '--answer <name>=<value>' for each, or with '--answers-file <path>'.")),outputs}var RECIPE_COLUMNS=[{key:"key",header:"Recipe",kind:"path",overflow:"truncate",minWidth:12},{key:"repo",header:"Repository",overflow:"truncate",priority:"medium"},{key:"latest",header:"Latest",overflow:"truncate",minWidth:6},{key:"pinned",header:"Pinned",overflow:"truncate",minWidth:6},{key:"subscribed",header:"Subscribed",priority:"medium"},{key:"description",header:"What it is",overflow:"wrap",flex:1,priority:"low",minWidth:16}],NAMESPACE_COLUMNS=[{key:"namespace",header:"Namespace",overflow:"truncate",minWidth:10},{key:"repo",header:"Repository",overflow:"truncate",priority:"medium"},{key:"recipes",header:"Recipes",kind:"number",priority:"medium"},{key:"subscribed",header:"Subscribed",priority:"medium"},{key:"description",header:"What it is",overflow:"wrap",flex:1,priority:"low",minWidth:16}],VERSION_COLUMNS=[{key:"version",header:"Version",overflow:"truncate",minWidth:7},{key:"status",header:"What it is",overflow:"wrap",flex:1,minWidth:16},{key:"prerelease",header:"Prerelease",priority:"medium"},{key:"released",header:"Released",overflow:"truncate",priority:"low"}],DEPENDENCY_COLUMNS=[{key:"key",header:"Dependency",kind:"path",overflow:"truncate",minWidth:12},{key:"declared",header:"Declared as",overflow:"wrap",flex:1,minWidth:12},{key:"resolved",header:"Resolved to",overflow:"truncate",minWidth:11},{key:"repo",header:"Repository",overflow:"truncate",priority:"low",minWidth:12},{key:"kind",header:"Kind",overflow:"wrap",priority:"medium",minWidth:16}],INSTALLS_COLUMNS=[{key:"key",header:"Recipe",kind:"path",overflow:"truncate",minWidth:12},{key:"version",header:"Version",overflow:"truncate",minWidth:7},{key:"kind",header:"Kind",overflow:"wrap",minWidth:16},{key:"neededBy",header:"Needed by",overflow:"wrap",flex:1,priority:"low",minWidth:16}],CONTENT_COLUMNS=[{key:"kind",header:"Content",minWidth:7},{key:"include",header:"Files",overflow:"wrap",flex:1,minWidth:14},{key:"destination",header:"Where they land",kind:"path",overflow:"wrap",flex:2,minWidth:16}],SEARCH_COLUMNS=[{key:"key",header:"Match",kind:"path",overflow:"truncate",minWidth:12},{key:"kind",header:"Kind",overflow:"truncate",minWidth:9},{key:"versions",header:"Versions",overflow:"truncate",minWidth:7},{key:"repo",header:"Repository",overflow:"truncate",priority:"medium"},{key:"description",header:"What it is",overflow:"wrap",flex:1,priority:"low",minWidth:16}],INSTALLED_SEARCH_COLUMNS=[{key:"key",header:"Recipe",kind:"path",overflow:"truncate",minWidth:12},{key:"installed",header:"Installed",overflow:"truncate",minWidth:9},{key:"versions",header:"Versions",overflow:"truncate",minWidth:7},{key:"repo",header:"Repository",overflow:"truncate",priority:"medium"},{key:"description",header:"What it is",overflow:"wrap",flex:1,priority:"low",minWidth:16}],REPO_COLUMNS=[{key:"name",header:"Repository",overflow:"truncate",minWidth:8},{key:"provider",header:"Provider",priority:"medium"},{key:"origin",header:"Origin"},{key:"linked",header:"Linked",kind:"path",overflow:"truncate",priority:"medium",minWidth:6},{key:"recipes",header:"Recipes",kind:"number",priority:"low",minWidth:11},{key:"url",header:"URL",kind:"url",overflow:"truncate",truncate:"middle",priority:"low",flex:1,minWidth:12}],SUBSCRIPTION_COLUMNS=[{key:"key",header:"Subscription",kind:"path",overflow:"truncate",minWidth:12},{key:"range",header:"Range",overflow:"truncate",minWidth:7},{key:"pinned",header:"Pinned version",flex:1,minWidth:14},{key:"latest",header:"Latest version",overflow:"wrap",priority:"medium",minWidth:14},{key:"origin",header:"Origin",priority:"medium"},{key:"enabled",header:"Enabled",priority:"medium"}],LINKED_NOTE="A recipe marked linked is pinned at the version shown, but builds currently read it from the linked checkout of its repository.";function recipeColumns(installed2){return installed2?RECIPE_COLUMNS.map(column=>column.key==="pinned"?{...column,header:"Installed"}:column):RECIPE_COLUMNS}function pinnedCell(pinned,linkedPath){return pinned===void 0?"":linkedPath===void 0?pinned:`${pinned} linked`}function recipeRows(listings){return listings.map(entry=>({key:entry.key,repo:entry.repo,latest:entry.latest??"none published",pinned:pinnedCell(entry.pinned,entry.linkedPath),subscribed:entry.subscribed?"yes":"no",description:entry.description??"no description published"}))}function describeCoverage(coverage){return coverage==="whole namespace"?"the whole namespace":coverage==="some recipes"?"some recipes":"no"}function describeVersionStatus(status){switch(status){case"latest and pinned":return"the latest version, and the one pinned here";case"latest":return"the latest version";case"pinned":return"the version pinned here";default:return"an earlier version"}}function describeDependencyKind(kind){return kind==="depends"?"build dependency":kind==="subscribes"?"co-subscription":"not recorded"}function describeOrigin(addedBy){return addedBy===BUILT_IN_ADDED_BY?"built in":addedBy===void 0||addedBy===USER_ADDED_BY?"user":`required by ${addedBy}`}function noDestinationText(kind){switch(kind){case"config":return"loaded as a config layer, so nothing is written";case"memories":return"reaches an agent through an include line in its instructions, so nothing is written";case"skills":return"nowhere: this project sets no 'recipes.skills.outputs' directory";default:return`nowhere: this project has no destination for ${kind} yet`}}function describeDeclaration(declared){let match2=/^(?:([a-z0-9][a-z0-9._-]*):)?([a-z][a-z0-9-]*)(?:@.*)?$/i.exec(declared.trim());return match2===null?declared:match2[1]===void 0?`the whole '${match2[2]}' namespace`:`the whole '${match2[2]}' namespace of ${match2[1]}`}function factIf(label,value){return value===void 0||value.length===0?[]:[{label,value}]}function browsingVariables(ctx,input,asked={}){let extra={};for(let[label,value]of Object.entries(asked))value!==void 0&&(extra[label]=value);return extra.Reading=input.latest===!0?"each repository, upstream":"the cached indexes",input.installed===!0&&(extra.Showing="only what this project has installed"),commandVariables(ctx,extra)}function namespaceListOutputs(ctx,input,result){let installed2=input.installed===!0,columns=installed2?NAMESPACE_COLUMNS.map(column=>column.key==="recipes"?{...column,header:"Installed"}:column):NAMESPACE_COLUMNS;return finish2([browsingVariables(ctx,input),tableOutput(columns,result.map(entry=>({namespace:entry.namespace,repo:entry.repo,recipes:String(entry.recipeCount),subscribed:describeCoverage(entry.subscribed),description:entry.description??"no description published"})),{heading:installed2?"Namespaces this project has installed recipes from":"Namespaces in the repositories this project trusts",empty:installed2?"This project has installed no recipe from the repositories it trusts.":"The repositories this project trusts publish no namespaces."})],{namespaces:[...result]})}function namespaceShowOutputs(ctx,input,detail){let installed2=input.installed===!0,outputs=[browsingVariables(ctx,input,{Namespace:input.ref}),blockOutput([{label:"Repository",value:detail.repo},...factIf("Location",detail.repoUrl),...factIf("About",detail.description),{label:installed2?"Installed recipes":"Recipes",value:String(detail.recipes.length)},{label:"Subscribed",value:describeCoverage(detail.subscribed)}],{heading:`The namespace ${detail.namespace}`}),tableOutput(recipeColumns(installed2),recipeRows(detail.recipes),{tableTitle:`Recipes in ${detail.namespace}`,empty:`The repository ${detail.repo} publishes no recipes in this namespace.`})];return detail.recipes.some(entry=>entry.linkedPath!==void 0)&&outputs.push(noteOutput(LINKED_NOTE)),finish2(outputs,detail)}function recipeListOutputs(ctx,input,result){let installed2=input.installed===!0,outputs=[browsingVariables(ctx,input),tableOutput(recipeColumns(installed2),recipeRows(result),{heading:installed2?"Recipes this project has installed":"Recipes in the repositories this project trusts",empty:installed2?"This project has installed no recipe from the repositories it trusts.":"The repositories this project trusts publish no recipes."})];return result.some(entry=>entry.linkedPath!==void 0)&&outputs.push(noteOutput(LINKED_NOTE)),finish2(outputs,{recipes:[...result]})}function installsOutputs(detail){let outputs=[tableOutput(INSTALLS_COLUMNS,(detail.installs??[]).map(recipe=>{let holders=recipe.requestedBy.filter(holder=>holder!=="project");return{key:recipe.key,version:recipe.version,kind:recipe.requestedBy.includes("project")?"the subscription itself":describeDependencyKind(recipe.kind),neededBy:holders.length===0?"this subscription":holders.join(", ")}}),{tableTitle:"What subscribing installs"})],missing=detail.installsNeed??[];return missing.length>0&&outputs.push(sentence(`Subscribing also needs ${missing.length===1?"a repository":"repositories"} this project does not trust yet, so what ${missing.length===1?"it publishes":"they publish"} is not listed above: `+missing.map(entry=>`${entry.name}${entry.url===void 0?"":` (${entry.url})`}, needed by ${entry.requiredBy.map(holder=>holder.requestedBy).join(", ")}`).join("; ")+".")),outputs}function recipeShowOutputs(ctx,input,detail){let installed2=input.installed===!0,outputs=[browsingVariables(ctx,input,{Recipe:input.ref}),blockOutput([{label:"Repository",value:detail.repo},...factIf("Location",detail.repoUrl),...factIf("About",detail.description),{label:"Folder",value:detail.path},{label:"Latest version",value:detail.latest??"none published"},{label:installed2?"Installed version":"Pinned version",value:detail.pinned??"this project pins none"},...factIf("Linked",detail.linkedPath===void 0?void 0:`builds currently read this recipe from the checkout at ${detail.linkedPath}`),{label:"Subscribed",value:detail.subscribed?"yes":"no"},...factIf("Described below",detail.describing)],{heading:detail.key}),tableOutput(VERSION_COLUMNS,detail.versions.map(entry=>({version:entry.version,status:describeVersionStatus(entry.status),prerelease:entry.prerelease?"yes":"no",released:entry.releasedAt??"not recorded"})),{tableTitle:"Published versions"}),tableOutput(DEPENDENCY_COLUMNS,detail.dependencies.map(entry=>({key:entry.key,declared:entry.declared===void 0?"not recorded in the index":describeDeclaration(entry.declared),resolved:entry.resolvedVersion??(entry.resolvedRange===void 0?"not recorded in the index":`the range ${entry.resolvedRange}`),repo:entry.repo??"this repository",kind:describeDependencyKind(entry.kind)})),{tableTitle:"What it depends on",empty:detail.manifestRead||detail.dependenciesRecorded?"This recipe depends on nothing else.":"The repository's index records no dependencies for this version."})];return detail.describing===void 0?outputs.push(sentence("This recipe publishes no version a subscription would install, so nothing is described below.")):detail.installsProblem!==void 0||detail.installs===void 0||detail.questions===void 0?outputs.push(sentence(detail.installsProblem??"Sous could not work out what subscribing would install.")):outputs.push(...installsOutputs(detail),...underHeading("What subscribing asks you",questionPlanOutputs(detail.questions,{answerHints:!1}))),outputs.push(tableOutput(CONTENT_COLUMNS,detail.manifestRead?detail.contents.map(entry=>({kind:entry.kind,include:entry.include.join(", "),destination:entry.destinations.length>0?entry.destinations.join(", "):noDestinationText(entry.kind)})):[],{tableTitle:"Where its files land in this project",empty:detail.manifestRead?"This recipe publishes no files.":"The recipe's own files are not on this machine, so the files it publishes are not known here. Subscribing to it fetches them."})),finish2(outputs,detail)}function repoSearchOutputs(ctx,input,result){let installed2=input.installed===!0,outputs=[browsingVariables(ctx,input,{Searching:input.text}),tableOutput(installed2?INSTALLED_SEARCH_COLUMNS:SEARCH_COLUMNS,result.map(match2=>({key:match2.key,kind:match2.kind,versions:match2.versions?.join(", ")??"",installed:match2.installed??"",repo:match2.repo,description:match2.description!==void 0&&match2.description.length>0?match2.description:"no description published"})),{heading:"Recipes matching your search",empty:installed2?`Nothing this project has installed matches '${input.text}'.`:`Nothing in the repositories this project trusts matches '${input.text}'.`})],limit2=input.limit??20;return result.length>0&&result.length>=limit2&&outputs.push(sentence(`Only the first ${limit2} matches are shown. Raise the number with '--limit'.`)),finish2(outputs,{matches:[...result]})}function repoNote(entry,verbose){let notes=[];if(entry.enabled||notes.push("Switched off in the config, so nothing is read from it."),verbose){let namespaces=entry.namespaces===void 0?"not fetched":entry.namespaces.length>0?entry.namespaces.join(", "):"none";notes.push(`Namespaces: ${namespaces}`)}return entry.installed!==void 0&&entry.installed.length>0&&notes.push(`Installed: ${entry.installed.map(pin=>`${pin.key} ${pin.version}`).join(", ")}`),notes.length>0?notes.join(" "):void 0}function repoListOutputs(ctx,input,result){let verbose=input.verbose===!0,outputs=[browsingVariables(ctx,input),tableOutput(REPO_COLUMNS,result.map(entry=>({name:entry.name,url:entry.url,provider:entry.provider,origin:describeOrigin(entry.addedBy),linked:entry.linkedPath===void 0?"no":`yes: ${entry.linkedPath}`,recipes:entry.recipeCount===void 0?"not fetched":String(entry.recipeCount)})),{heading:input.installed===!0?"Repositories this project has installed recipes from":"Repositories this project trusts",empty:"This project trusts no repositories yet. Add one with 'sous repo add <url>'; adding a repository is how you trust it.",rowNotes:result.map(entry=>repoNote(entry,verbose))})];for(let entry of result)entry.problem!==void 0&&ctx.reporter.warn(`${entry.name} could not be checked upstream, so it is shown from the cache: ${entry.problem}`);return finish2(outputs,{repos:[...result]})}function describePinned(pinned,enabled){return pinned.length>0?pinned.map(entry=>`${entry.key} ${entry.version}`).join(", "):enabled?"pinned on first build":"not pinned"}function describeLatest(listing){if(listing.pinned.length===0)return"";let published=new Map((listing.latest??[]).map(entry=>[entry.key,entry.version])),newer=new Map((listing.newer??[]).map(entry=>[entry.key,entry.version])),latestOf=(key,pinned)=>listing.latest===void 0?newer.get(key)??pinned:published.get(key)??"not in any index sous has read";if(listing.pinned.length===1){let only=listing.pinned[0];return latestOf(only.key,only.version)}return listing.pinned.map(pin=>`${pin.key} ${latestOf(pin.key,pin.version)}`).join(", ")}function describeSubscriptionOrigin(addedBy){return addedBy===BUILT_IN_ADDED_BY?"built in":addedBy===void 0||addedBy===USER_ADDED_BY?"user":addedBy}function subscriptionListOutputs(ctx,input,result){let installed2=input.installed===!0,listings=result.filter(entry=>!installed2||entry.pinned.length>0),columns=SUBSCRIPTION_COLUMNS.map(column=>installed2&&column.key==="pinned"?{...column,header:"Installed version"}:column);return finish2([browsingVariables(ctx,input),tableOutput(columns,listings.map(entry=>({key:entry.key,range:entry.range??"any version",pinned:describePinned(entry.pinned,entry.enabled),latest:describeLatest(entry),origin:describeSubscriptionOrigin(entry.addedBy),enabled:entry.enabled?"yes":"no"})),{heading:"Subscriptions",empty:installed2?"No subscription of this project has installed anything yet.":"This project subscribes to nothing yet."})],{subscriptions:listings})}import{jsonSchema as jsonSchema12}from"@sous-io/plugin-api";function inputSchema(properties,required2=[]){return jsonSchema12({type:"object",properties,required:required2,additionalProperties:!1})}var dryRun={type:"boolean",description:"Show what would change, writing nothing"},noBuild={type:"boolean",description:"Change it without rebuilding the project afterwards"},yes={type:"boolean",description:"Answer yes to every question, trusting new repositories without asking"},acceptFirst={type:"boolean",description:"When a ref matches several things, take the first one listed"},answer={type:"array",items:{type:"string"},description:"Answer a recipe question ahead of time, as name=value (repeatable)"},answersFile={type:"string",description:"A file of answers to recipe questions (YAML, JSON, JSONC or .env)"},latest={type:"boolean",description:"Check upstream for newer indexes first"},installed={type:"boolean",description:"Show only what this project has installed, never going upstream"},browsing={latest,installed},yesFlag={short:"y",aliases:["force","trust"]},yesFlagNoTrust={short:"y",aliases:["force"]},latestFlag={aliases:["remote"]};var browsingCli={flags:{latest:latestFlag}};function reportUnread(ctx,catalog){if(catalog.notFetched.length>0&&ctx.reporter.note(`These repositories are trusted and their index has not been fetched yet, so nothing in them is listed: ${catalog.notFetched.join(", ")}.`),catalog.notChecked.length>0){ctx.reporter.note(`These repositories could not be reached, so they are shown from the cache and were not checked: ${catalog.notChecked.map(entry=>entry.repo).join(", ")}.`);for(let entry of catalog.notChecked)ctx.reporter.debug(`${entry.repo}: ${entry.reason}`)}}async function showNamespace(input,ctx){let catalog=await loadCatalog(ctx,input);reportUnread(ctx,catalog);let readings=readingsOf(ctx,input.ref);if(readings.every(reading=>reading.kind==="recipe"&&reading.namespace!==void 0)){let recipe=findInCatalog(catalog.inputs,readings,["recipe"])[0];if(recipe!==void 0)throw new SousError17(`'${input.ref}' names the recipe '${recipe.key}', not a namespace.`,{details:[`The namespace it belongs to is '${recipe.key.split("/")[0]}'.`]})}let found=await resolveInCatalog(ctx,catalog,input.ref,["namespace"],input.acceptFirst,()=>{let asRecipe=findInCatalog(catalog.inputs,readings,["recipe"]);return input.installed!==!0&&asRecipe.length>0&&!readings.some(reading=>reading.kind==="namespace"&&reading.repo!==void 0)?new SousError17(`No repository this project trusts publishes a namespace called '${input.ref}'.`,{details:["It is the name of a recipe:",...asRecipe.map(match2=>` ${match2.repo.name}:${match2.key}`)]}):installedError(input,"namespace")??unknownRefError(catalog.inputs,input.ref,"namespace",catalog.notFetched)});return describeNamespace(catalog.inputs,{repo:found.repo,namespace:found.key})}async function showRecipe(input,ctx){let catalog=await loadCatalog(ctx,input);reportUnread(ctx,catalog);let found=await resolveInCatalog(ctx,catalog,input.ref,["recipe"],input.acceptFirst,()=>{let asNamespace=findInCatalog(catalog.inputs,readingsOf(ctx,input.ref),["namespace"]);return asNamespace.length>0?new SousError17(`No repository this project trusts publishes a recipe called '${input.ref}'.`,{details:["It is the name of a namespace:",...asNamespace.map(match2=>` ${match2.repo.name}:${match2.key}`)]}):installedError(input,"recipe")??unknownRefError(catalog.inputs,input.ref,"recipe",catalog.notFetched)}),location=describedLocation(catalog.inputs,{repo:found.repo,key:found.key}),manifest=location===void 0?void 0:await readPublishedManifest(ctx,catalog.inputs,location),detail=describeRecipe(catalog.inputs,{repo:found.repo,key:found.key},manifest);return{...detail,...await previewSubscription(ctx,catalog,detail)}}async function previewSubscription(ctx,catalog,detail){if(detail.describing===void 0)return{};let prerelease=import_semver7.default.prerelease(detail.describing)!==null;try{let result=await ctx.services.get("recipes.resolver").resolve([{ref:ctx.services.get("refs.format").recipeRef(detail.namespace,detail.name,{repo:detail.repo,range:detail.describing}),range:detail.describing,requestedBy:PROJECT_HOLDER,kind:"subscribes",...prerelease?{prerelease:!0}:{}}],{indexes:new Map(catalog.inputs.repos.map(repo=>[repo.name,repo.index])),...prerelease?{prerelease:!0}:{}});return{installs:result.resolved.map(recipe=>({key:recipe.key,version:recipe.version,kind:recipe.kind,requestedBy:recipe.requestedBy})),installsNeed:result.missingRepos,questions:await planQuestions(ctx,result.resolved)}}catch(error51){return{installsProblem:`Sous could not work out what subscribing to version ${detail.describing} would install. ${describeError2(error51)}`}}}function installedError(input,what){if(input.installed===!0)return new SousError17(what==="namespace"?`This project has installed no recipe from the namespace '${input.ref}', so there is nothing to show with '--installed'.`:`This project has not installed the recipe '${input.ref}', so there is nothing to show with '--installed'.`)}function registerCatalogIntents(sous){sous.intents.add({intent:"namespace.list",requiresProject:!0,summary:"List the namespaces in the repositories this project trusts",input:inputSchema(browsing),parallel:!0,cli:{aliases:[["namespaces","list"]],...browsingCli},agent:{usage:"Call this before subscribing, to find which namespaces exist."},handle:async(input,ctx)=>{let catalog=await loadCatalog(ctx,input);return reportUnread(ctx,catalog),namespaceListOutputs(ctx,input,listNamespaces(catalog.inputs))}}),sous.intents.add({intent:"namespace.show",requiresProject:!0,summary:"Show one namespace and every recipe in it",input:inputSchema({ref:{type:"string",description:"The namespace, optionally as repository:namespace"},...browsing,acceptFirst},["ref"]),parallel:!0,cli:{aliases:[["namespaces","show"]],positional:["ref"],...browsingCli},handle:async(input,ctx)=>namespaceShowOutputs(ctx,input,await showNamespace(input,ctx))}),sous.intents.add({intent:"recipe.list",requiresProject:!0,summary:"List the recipes in the repositories this project trusts",input:inputSchema(browsing),parallel:!0,cli:{aliases:[["recipes","list"]],...browsingCli},handle:async(input,ctx)=>{let catalog=await loadCatalog(ctx,input);return reportUnread(ctx,catalog),recipeListOutputs(ctx,input,listRecipes(catalog.inputs))}}),sous.intents.add({intent:"recipe.show",requiresProject:!0,summary:"Show one recipe: its versions, dependencies, contents and questions",input:inputSchema({ref:{type:"string",description:"The recipe: namespace/recipe, a bare name, or either as repository:ref"},...browsing,acceptFirst},["ref"]),parallel:!0,cli:{aliases:[["recipes","show"]],positional:["ref"],...browsingCli},handle:async(input,ctx)=>recipeShowOutputs(ctx,input,await showRecipe(input,ctx))})}var import_semver8=__toESM(require_semver2(),1);import fs27 from"node:fs";import os6 from"node:os";import path41 from"node:path";import{ConfigError as ConfigError24,LogLevel as LogLevel5,SousError as SousError19}from"@sous-io/plugin-api";async function askFollowUp(ctx,flags,recipes){if(flags.dryRun===!0)return{intent:"vars.ask",skipped:"--dry-run"};if(!hasIntent(ctx,"vars.ask"))return{intent:"vars.ask",skipped:"no plugin provides vars.ask"};if(recipes.length===0&&flags.answer===void 0&&flags.answersFile===void 0)return{intent:"vars.ask",skipped:"nothing new to ask"};let result=await ctx.run("vars.ask",{...recipes.length===0?{}:{within:[...recipes]},...flags.answer===void 0?{}:{answer:flags.answer},...flags.answersFile===void 0?{}:{answersFile:flags.answersFile}});return ctx.chain!==void 0&&!ctx.chain.parallel&&await ctx.refreshConfig(),{intent:"vars.ask",result:result.toPlain(),outputs:result}}async function buildFollowUp(ctx,flags){if(flags.dryRun===!0)return{intent:"build",skipped:"--dry-run"};if(flags.noBuild===!0)return{intent:"build",skipped:"--no-build"};if(!hasIntent(ctx,"build"))return{intent:"build",skipped:"no plugin provides build"};ctx.reporter.operationStart("Building the project");let built=await ctx.run("build",{});return{intent:"build",result:built.toPlain(),outputs:built}}import{SousError as SousError18}from"@sous-io/plugin-api";function isShortNamed(ref){if(ref.kind!=="namespace"&&ref.kind!=="recipe")return!1;let named=ref;return(named.kind==="namespace"?named.repo:named.namespace?.repo??named.repo)?.location===void 0}async function subscriptionKeyFor(ctx,written,keys){let readings=readingsOf(ctx,written),short=readings.find(isShortNamed);if(short!==void 0){let key=ctx.services.get("refs.format").key(short);return keys.find(candidate=>candidate===key)??keys.find(candidate=>candidate.toLowerCase()===key.toLowerCase())??key}let catalog=await loadCatalog(ctx);return(await pickMatch(ctx,findInCatalog(catalog.inputs,readings,["namespace","recipe"]),written.trim(),void 0,()=>new SousError18(`'${written.trim()}' names no namespace or recipe this project knows.`))).key}async function planSubscriptionRemoval(ctx,key,lock){let configured=configuredSubscriptions(ctx.config),managed=await managedEntries(ctx.services.get("confd.managed"),SUBSCRIPTIONS_LAYER,"subscriptions"),held=keysHeldBySubscription(lock,key),removable=Object.hasOwn(managed,key)&&managed[key]?.enabled!==!1,builtIn=!removable&&isBuiltInEntry(configured[key]);if(!removable&&!builtIn){if(!Object.hasOwn(configured,key)&&held.length===0){let known=sortBytewise(Object.keys(configured).filter(entry=>configured[entry]?.enabled!==!1));throw new SousError18(`This project does not subscribe to '${key}'.`,{details:[known.length>0?`It subscribes to: ${known.join(", ")}.`:"It has no subscriptions yet."]})}if(Object.hasOwn(configured,key))throw new SousError18(`The subscription to '${key}' is written in one of this project's own config files, not in the file sous manages.`,{details:["Remove its entry from the 'subscriptions' block of that file; sous never deletes what you wrote.",`To switch it off on this machine instead, run 'sous subscription disable ${key}'.`]})}let after=lock;for(let heldKey of held)after=dropProjectHold(after,heldKey);return{key,optedOut:builtIn,after,stayed:stayedAfter(after,held)}}async function writeSubscriptionRemoval(ctx,removal){let managed=ctx.services.get("confd.managed");removal.optedOut?await writeSubscriptionEntry(managed,removal.key,{enabled:!1}):await deleteSubscriptionEntry(managed,removal.key)}var STAYED_COLUMNS=[{key:"key",header:"Recipe",kind:"path",overflow:"truncate",minWidth:12},{key:"heldBy",header:"Still held by",overflow:"wrap",flex:1,minWidth:16}];function repoAddOutputs(result){let heading="Adding a repository";return result.dryRun?finish2([dryRunOutput("Nothing will be trusted, written or downloaded.",heading),noteOutput(`The repository would be added as '${result.name}', read through the ${result.provider} provider, and its index would be fetched.`)],result):finish2([blockOutput({Repository:result.name,Location:result.url,Provider:result.provider,Namespaces:result.namespaces.length>0?result.namespaces.join(", "):"none; this repository publishes nothing yet",Recipes:String(result.recipeCount)},{heading}),noteOutput(result.alreadyTrusted?`This project already trusted '${result.name}', so only its index was refreshed.`:`This project now trusts '${result.name}'. Nothing from it has been installed.`)],result)}function repoRemoveOutputs(ctx,result){let pruneHint=rebuilt(result)?"":" Run 'sous build' to prune what it used to write.",outputs=[];result.dryRun&&outputs.push(dryRunOutput("Nothing will be written."));let[first2,...rest]=result.plan??[];return first2!==void 0&&(outputs.push(sentence(first2)),rest.length>0&&outputs.push(listOutput(rest,{listTitle:"Here is what goes with it:"}))),outputs.push(lockfileOutput(result.diff,"Nothing changed; nothing was locked because of this repository.")),result.stayed.length>0&&outputs.push(tableOutput(STAYED_COLUMNS,result.stayed.map(entry=>({key:entry.key,heldBy:entry.heldBy.join(", ")})),{tableTitle:"What stayed, and why"})),result.dryRun?outputs.push(dryRunOutput("Nothing was written. Run the same command without '--dry-run' to remove it.")):outputs.push(sentence(result.optedOut?`The repository '${result.name}' is one sous provides itself, so it was switched off rather than deleted: this project's config now records '${result.name}: { enabled: false }'.${pruneHint}`:`This project no longer trusts '${result.name}'. Nothing is read from it any more, and its entry is gone from the repositories layer.${pruneHint}`)),finishWithFollowUps(ctx,underHeading("Removing a repository",outputs),result,`The repository '${result.name}' was removed, but the build that followed it failed, so this project may still hold files its recipes used to write. The removal itself is recorded and locked; fix what the build reported above and run 'sous build' again.`)}function repoTrustOutputs(result){let outputs=[];return result.dryRun&&outputs.push(dryRunOutput("Nothing will be written.")),outputs.push(blockOutput({Repository:result.name,Location:result.url})),result.alreadyTrusted?outputs.push(noteOutput(`This project already trusts '${result.name}'; nothing changed.`)):result.dryRun?outputs.push(dryRunOutput(`Nothing was written. Run the same command without '--dry-run' to trust '${result.name}'.`)):outputs.push(noteOutput(result.trusted?`This project now trusts '${result.name}'. Nothing from it has been installed.`:`'${result.name}' was not trusted; nothing changed.`)),finish2(underHeading("Trusting a repository",outputs),result)}var BUILT_IN_PROVIDERS=["github","gitlab","local"];function looksLikeLocalPath(typed){return typed.startsWith("/")||typed.startsWith("./")||typed.startsWith("../")||typed==="."||typed===".."||typed.startsWith("~")}function resolveLocalPath(typed,base,home){let expanded=typed==="~"||typed.startsWith("~/")?path41.join(home??os6.homedir(),typed.slice(1)):typed;return path41.resolve(base,expanded)}async function addRepo(input,ctx){let locations=ctx.services.get("refs.locations"),typed=input.url.trim(),url2=typed;if(looksLikeLocalPath(typed)){url2=resolveLocalPath(typed,ctx.cwd??ctx.project?.root??".",ctx.env.HOME);let id=input.provider??locations.hostFor(url2)?.id,host=ctx.entities.list("repository-host").find(entry=>entry.id===id);if(host?.checkTypedPath!==void 0)await host.checkTypedPath(typed,url2,ctx);else if(!fs27.existsSync(url2)||!fs27.statSync(url2).isDirectory())throw new SousError19(`'${typed}' is not a directory on this machine, so it cannot be added as a repository.`,{details:[`Sous looked at ${url2}.`]})}if(input.provider!==void 0&&locations.host(input.provider)===void 0)throw new SousError19(`'${input.provider}' is not a repository host sous knows.`,{details:[`The hosts loaded now: ${sortBytewise(locations.hosts().map(host=>host.id)).join(", ")||"none"}. A plugin can add another.`]});let canonical=locations.canonicalize(url2,input.provider),provider=input.provider??locations.hostFor(url2)?.id??"unknown",name=input.name??canonical.name.toLowerCase();if(!REPO_NAME_PATTERN2.test(name))throw new SousError19(`'${name}' is not a usable short name for a repository.`,{details:["A short name is lowercase kebab case: a letter, then letters, digits or hyphens. Refs use it as the 'repo:' qualifier.",`Choose one with --name, for example 'sous repo add ${typed} --name my-recipes'.`]});let existing=configuredRepos(ctx.config)[name],wanted=locations.identityOf(canonical),sameRepository=existing!==void 0&&identityOf(ctx,existing.url)===wanted,alreadyTrusted=sameRepository&&existing.enabled!==!1;if(existing!==void 0&&!sameRepository)throw new SousError19(`This project already has a repository called '${name}', and it is a different one.`,{details:[`Already added: ${existing.url}`,`Being added: ${url2}`,`Give this one a name of its own with --name, for example --name ${name}-2.`]});let result={name,url:url2,provider,alreadyTrusted,namespaces:[],recipeCount:0,dryRun:input.dryRun===!0};if(input.dryRun===!0)return result;alreadyTrusted||await ctx.services.get("recipes.trust").confirm([{name,url:url2,identity:wanted,provider,requiredBy:[{ref:name,requestedBy:"project"}]}],{...input.yes===void 0?{}:{yes:input.yes}},ctx),await writeRepoEntry(ctx.services.get("confd.managed"),name,{url:url2,...input.provider===void 0?{}:{provider:input.provider},addedAt:nowIso(),addedBy:USER_ADDED_BY}),ctx.configChanged();try{let cached2=await(await ctx.refreshConfig()).services.get("recipes.index-cache").get(name,{latest:!0});result.namespaces=sortBytewise(Object.keys(cached2.index.namespaces)),result.recipeCount=Object.keys(cached2.index.recipes).length}catch(error51){ctx.reporter.warning(`Trusted ${name}, but its index could not be read yet: ${describeError2(error51)}`)}return result}async function subscriptionsInto(ctx,name,lock){let fromRepo=new Set(Object.entries(lock.recipes).filter(([,recipe])=>recipe.repo===name).map(([key])=>key)),subscriptions=configuredSubscriptions(ctx.config),managed=await managedEntries(ctx.services.get("confd.managed"),SUBSCRIPTIONS_LAYER,"subscriptions"),format3=ctx.services.get("refs.format"),removable=[],kept=[];for(let key of sortBytewise(Object.keys(subscriptions))){if(subscriptions[key]?.enabled===!1)continue;let qualifier;try{qualifier=format3.partsOf(format3.parseNamedRef(key,"config")).repo?.name}catch{continue}qualifier!==name&&!keysHeldBySubscription(lock,key).some(held=>fromRepo.has(held))||(Object.hasOwn(managed,key)||isBuiltInEntry(subscriptions[key])?removable.push(key):kept.push(key))}return{removable,kept}}function removalPlan(result){let lines3=[result.optedOut?`The repository '${result.name}' at ${result.url} is one sous provides itself, so it is switched off instead, by recording '${result.name}: { enabled: false }' in conf.d/500-repos.jsonc.`:`The entry for '${result.name}' at ${result.url} is removed from conf.d/500-repos.jsonc, so sous stops reading anything from it.`];lines3.push(result.subscriptions.length===0?"Nothing this project subscribes to resolves into it.":`${result.subscriptions.length===1?"One subscription resolves into it and is":`${result.subscriptions.length} subscriptions resolve into it and are`} removed: ${result.subscriptions.join(", ")}.`),result.removedRecipes.length>0&&lines3.push(`These locked recipes were held only through those subscriptions and leave the lockfile: ${result.removedRecipes.join(", ")}.`);for(let stayed of result.stayed)lines3.push(`The recipe '${stayed.key}' stays, because ${stayed.heldBy.join(", ")} still holds it.`);result.outputs.length>0&&lines3.push(`Removing ${result.name} deletes ${result.outputs.length} built ${result.outputs.length===1?"file":"files"} on the next build:`,...result.outputs.map(file2=>` ${file2}`)),result.linkedPath!==void 0&&lines3.push(result.linkIsGlobal?`A machine-wide link points this repository at ${result.linkedPath}. Other projects share it, so it is left as it is.`:`This project links the repository to ${result.linkedPath}. The link is removed; the checkout stays on disk.`);for(let key of result.keptSubscriptions)lines3.push(`The subscription to '${key}' resolves into it and is written in this project's own config, which sous never edits, so it stays.`);return lines3}function reportRemovalPlan(reporter,plan){for(let index=0;index<plan.length;index++){let line=plan[index],items2=[];for(;plan[index+1]?.startsWith(" ")===!0;)items2.push(plan[++index].trim());items2.length>0?reporter.list(items2,{title:line},LogLevel5.Notice):reporter.note(line)}}async function removeRepo(input,ctx){let name=input.repo,trusted=ctx.services.get("recipes.trust").trusted(),entry=trusted[name];if(entry===void 0){let known=sortBytewise(Object.keys(trusted));throw new SousError19(`This project does not trust a repository called '${name}'.`,{details:[known.length>0?`It trusts: ${known.join(", ")}.`:"It trusts no repositories yet."]})}let managedRepos=await managedEntries(ctx.services.get("confd.managed"),REPOS_LAYER,"repos"),builtIn=!Object.hasOwn(managedRepos,name)&&isBuiltInEntry(entry);if(!Object.hasOwn(managedRepos,name)&&!builtIn)throw new SousError19(`The repository '${name}' is written in one of this project's own config files, not in the file sous manages.`,{details:["Remove its entry from the 'repos' block of that file; sous never deletes what you wrote."]});let lockService=ctx.services.get("recipes.lock"),before=lockService.read(),{removable,kept}=await subscriptionsInto(ctx,name,before),removals=[],after=before,held=[];for(let key of removable){let removal=await planSubscriptionRemoval(ctx,key,after);held.push(...keysHeldBySubscription(after,key)),after=removal.after,removals.push(removal)}let diff=lockService.diff(before,after),outputs=ctx.services.has("compiler.state")?sortBytewise(new Set(ctx.services.get("compiler.state").filesFrom({repository:name}).map(file2=>file2.dest))):[],link=ctx.services.has("recipes.links")?ctx.services.get("recipes.links").get(name):void 0,planned={name,url:entry.url,optedOut:builtIn,subscriptions:removable,keptSubscriptions:kept,removedRecipes:diff.removed.map(change=>change.key),stayed:stayedAfter(after,held),outputs,diff,...link===void 0?{}:{linkedPath:link.path},linkIsGlobal:link?.scope==="global",dryRun:input.dryRun===!0},plan=removalPlan(planned);if(input.dryRun===!0)return{...planned,plan,followUps:[{intent:"build",skipped:"--dry-run"}]};if(input.yes!==!0&&(reportRemovalPlan(ctx.reporter,plan),!await ctx.prompter.confirm({message:`Stop trusting '${name}'?`,answeredBy:"--yes",default:!1})))throw new SousError19(`Nothing was written: the repository '${name}' is still trusted.`);for(let removal of removals)await writeSubscriptionRemoval(ctx,removal);let written=await lockService.write(after);link!==void 0&&link.scope==="project"&&await ctx.services.get("recipes.links").remove(name,"project");let managed=ctx.services.get("confd.managed");return builtIn?await writeRepoEntry(managed,name,{enabled:!1}):await deleteRepoEntry(managed,name),ctx.configChanged(),input.noBuild!==!0&&await ctx.refreshConfig(),{...planned,...input.yes===!0?{plan}:{},diff:written,followUps:[await buildFollowUp(ctx,input)]}}async function trustRepo(input,ctx){let trust=ctx.services.get("recipes.trust"),already=trust.nameOf(input.repo),dry=input.dryRun===!0;if(already!==void 0)return{name:already,url:trust.trusted()[already].url,trusted:!0,alreadyTrusted:!0,dryRun:dry};let configured=configuredRepos(ctx.config),off=configured[input.repo];if(off!==void 0&&off.enabled===!1&&input.url===void 0)return dry||(await ctx.services.get("confd.managed").edit(REPOS_LAYER,root=>root.atPath(["repos",input.repo,"enabled"]).set(!0)),ctx.configChanged()),{name:input.repo,url:off.url,trusted:!dry,alreadyTrusted:!1,dryRun:dry};let url2=input.url??(REPO_NAME_PATTERN2.test(input.repo)?void 0:input.repo);if(url2===void 0)throw new ConfigError24(`Sous does not know where the repository '${input.repo}' lives.`,{details:[`Pass its URL: 'sous repo trust ${input.repo} --url <url>', or add it with 'sous repo add <url> --name ${input.repo}'.`]});let identity2=identityOf(ctx,url2),name=REPO_NAME_PATTERN2.test(input.repo)?input.repo:proposeRepoName(Object.keys(configured),identity2??url2),provider=ctx.services.get("refs.locations").hostFor(url2)?.id,done2=await trust.confirm([{name,url:url2,...identity2===void 0?{}:{identity:identity2},...provider===void 0?{}:{provider},requiredBy:[{ref:input.repo,requestedBy:"project"}]}],{...input.yes===void 0?{}:{yes:input.yes},dryRun:dry},ctx);return dry||ctx.configChanged(),{name,url:url2,trusted:done2.added.includes(name)&&!dry,alreadyTrusted:!1,dryRun:dry}}async function listRepos(input,ctx){let cache2=ctx.services.get("recipes.index-cache"),links=ctx.services.has("recipes.links")?ctx.services.get("recipes.links").all():{},locations=ctx.services.get("refs.locations"),listings=[];for(let[name,entry]of Object.entries(configuredRepos(ctx.config))){let enabled=entry.enabled!==!1,problem,cached2=cachedOrNothing(cache2,name);if(enabled&&input.latest===!0&&input.installed!==!0)try{cached2=await readUpstream(ctx,name)}catch(error51){problem=describeError2(error51),cached2=cachedOrNothing(cache2,name)}let installed2=input.installed===!0?pinsFrom(ctx,name):void 0;if(installed2!==void 0&&installed2.length===0)continue;let provider=entry.provider;try{provider??=locations.hostFor(entry.url)?.id}catch{}listings.push({name,url:entry.url,provider:provider??"unknown",enabled,alwaysPull:entry.alwaysPull===!0,...entry.addedBy===void 0?{}:{addedBy:entry.addedBy},...entry.addedAt===void 0?{}:{addedAt:entry.addedAt},...cached2===void 0?{}:{namespaces:sortBytewise(Object.keys(cached2.index.namespaces)),recipeCount:Object.keys(cached2.index.recipes).length,indexSource:cached2.source,...cached2.meta?.lastCheckedAt===void 0?{}:{lastCheckedAt:cached2.meta.lastCheckedAt}},...links[name]===void 0?{}:{linkedPath:links[name].path},...problem===void 0?{}:{problem},...installed2===void 0?{}:{installed:installed2}})}let repos=configuredRepos(ctx.config);return listings.sort((left,right)=>Number(isBuiltInEntry(repos[right.name]))-Number(isBuiltInEntry(repos[left.name]))||(left.name<right.name?-1:left.name>right.name?1:0))}function cachedOrNothing(cache2,name){try{return cache2.cached(name)}catch{return}}function pinsFrom(ctx,repo){let recipes;try{recipes=ctx.services.get("recipes.lock").read().recipes}catch{return[]}return sortBytewise(Object.keys(recipes).filter(key=>recipes[key].repo===repo)).map(key=>({key,version:recipes[key].version}))}function matchScore(text,name,description){let wanted=text.toLowerCase(),candidate=name.toLowerCase();return candidate===wanted?100:candidate.startsWith(wanted)?75:candidate.includes(wanted)?50:description?.toLowerCase().includes(wanted)===!0?20:0}function sortVersions(versions){return[...versions].sort((left,right)=>{let a=import_semver8.default.valid(left,{loose:!0}),b=import_semver8.default.valid(right,{loose:!0});return a!==null&&b!==null?import_semver8.default.compare(a,b):a!==null?-1:b!==null?1:left<right?-1:left>right?1:0})}async function searchRepos(input,ctx){let catalog=await loadCatalog(ctx,input),matches=[],lock=catalog.inputs.lock;for(let repo of catalog.inputs.repos){for(let[namespace,declared]of input.installed===!0?[]:Object.entries(repo.index.namespaces)){let score=matchScore(input.text,namespace,declared.description);score>0&&matches.push({ref:publishedNamespaceRef(repo,namespace),key:namespace,kind:"namespace",repo:repo.name,...declared.description===void 0?{}:{description:declared.description},score})}for(let[key,recipe]of Object.entries(repo.index.recipes)){let score=Math.max(matchScore(input.text,splitRecipeKey(key).name,recipe.description),matchScore(input.text,key)),pinned=lock.recipes[key]?.repo===repo.name?lock.recipes[key].version:void 0;if(score>0&&matches.push({ref:publishedRecipeRef(repo,key),key,kind:"recipe",repo:repo.name,...recipe.description===void 0?{}:{description:recipe.description},score,versions:sortVersions(Object.keys(recipe.versions)),...pinned===void 0?{}:{installed:pinned}}),input.installed===!0)continue;let version2=latestVersion(recipe.versions);for(let variable of(version2===void 0?void 0:recipe.versions[version2]?.variables)??[]){let variableScore=matchScore(input.text,variable.name,variable.description);if(variableScore>0){let ref={kind:"variable",name:variable.name,recipe:publishedRecipeRef(repo,key),description:variable.description};matches.push({ref,key:`${key}.${variable.name}`,kind:"variable",repo:repo.name,description:variable.description,score:variableScore-5})}}}}return matches.sort((left,right)=>right.score-left.score||(left.key<right.key?-1:left.key>right.key?1:0)).slice(0,input.limit??20)}function registerRepoIntents(sous){sous.intents.add({intent:"repo.add",requiresProject:!0,summary:"Add a recipe repository, which trusts it",input:inputSchema({url:{type:"string",description:"The repository's URL, or a path on this machine"},name:{type:"string",description:"The short name refs use for it; default from the URL"},provider:{type:"string",minLength:1,description:`The repository host, when the URL does not give it away: ${BUILT_IN_PROVIDERS.join(", ")}, or any host a plugin adds`},yes,dryRun},["url"]),changesConfig:!0,cli:{aliases:[["repos","add"]],positional:["url"],flags:{yes:yesFlag}},handle:async(input,ctx)=>repoAddOutputs(await addRepo(input,ctx))}),sous.intents.add({intent:"repo.remove",requiresProject:!0,summary:"Stop trusting a repository, removing the subscriptions that resolve into it",input:inputSchema({repo:{type:"string",description:"The repository's short name"},yes,dryRun,noBuild},["repo"]),changesConfig:!0,cli:{aliases:[["repos","remove"]],positional:["repo"],flags:{yes:yesFlagNoTrust}},handle:async(input,ctx)=>repoRemoveOutputs(ctx,await removeRepo(input,ctx))}),sous.intents.add({intent:"repo.trust",requiresProject:!0,summary:"Trust a repository by name, URL or identity",input:inputSchema({repo:{type:"string",description:"A short name, URL or identity"},url:{type:"string",description:"Its URL, when the name has none recorded"},yes,dryRun},["repo"]),changesConfig:!0,cli:{aliases:[["repos","trust"]],positional:["repo"],flags:{yes:yesFlag}},handle:async(input,ctx)=>repoTrustOutputs(await trustRepo(input,ctx))}),sous.intents.add({intent:"repo.list",requiresProject:!0,summary:"List the repositories this project trusts",input:inputSchema({latest,installed,verbose:{type:"boolean",description:"Show more about each repository"}}),parallel:!0,cli:{aliases:[["repos","list"]],flags:{latest:latestFlag}},handle:async(input,ctx)=>repoListOutputs(ctx,input,await listRepos(input,ctx))}),sous.intents.add({intent:"repo.search",requiresProject:!0,summary:"Search the trusted repositories for namespaces, recipes and variables",input:inputSchema({text:{type:"string",description:"What to look for"},latest,installed,limit:{type:"integer",description:"At most this many matches (default 20)"}},["text"]),parallel:!0,cli:{aliases:[["search"],["repos","search"]],positional:["text"],flags:{latest:latestFlag}},handle:async(input,ctx)=>repoSearchOutputs(ctx,input,await searchRepos(input,ctx))})}var import_semver9=__toESM(require_semver2(),1);import{LogLevel as LogLevel7,SousError as SousError23}from"@sous-io/plugin-api";import{SousError as SousError20}from"@sous-io/plugin-api";async function checkProvidedAnswers(ctx,resolved,flags,download2){if((flags.answer===void 0||flags.answer.length===0)&&flags.answersFile===void 0||!ctx.services.has("recipe-answers.preanswers"))return;let preanswers=ctx.services.get("recipe-answers.preanswers"),{defined}=await definedVariables(ctx,resolved,download2),keys=new Set(defined.map(variable=>variable.key)),existing=[];try{existing=ctx.services.has("recipe-answers.definitions")?ctx.services.get("recipe-answers.definitions").listSync():[]}catch{existing=[]}try{let answers=await preanswers.read({...flags.answer===void 0?{}:{answer:flags.answer},...flags.answersFile===void 0?{}:{answersFile:flags.answersFile}});preanswers.match(answers,[...defined,...existing.filter(variable=>!keys.has(variable.key))])}catch(error51){if(error51 instanceof SousError20&&error51.details.length>0){let[first2,...rest]=error51.details;throw new SousError20(first2??error51.message,{details:rest})}throw error51}}import{LogLevel as LogLevel6,NonInteractiveError as NonInteractiveError3,SousError as SousError21}from"@sous-io/plugin-api";var Trust=class{constructor(config2,services){this.config=config2;this.services=services}trusted(){return trustedRepos(this.config)}isTrusted(repository){return this.nameOf(repository)!==void 0}nameOf(repository){let trusted=this.trusted();if(Object.hasOwn(trusted,repository))return repository;let wanted=this.identityOf(repository);if(wanted!==void 0)return Object.keys(trusted).find(name=>this.identityOf(trusted[name].url)===wanted)}async confirm(missing,options,io){if(missing.length===0)return{accepted:[],added:[],needUrl:[]};if(options.yes!==!0&&options.dryRun!==!0){if(!io.prompter.interactive)throw new NonInteractiveError3(trustQuestion(missing),"--yes",{details:nonInteractiveDetails(missing)});if(reportTrustNotice(io.reporter,missing),!await io.prompter.confirm({message:trustQuestion(missing),answeredBy:"--yes",default:!1}))throw new SousError21(`Nothing was installed: trust was declined for ${missing.map(repo=>`'${repo.name}'`).join(", ")}.`,{details:["Sous installs a dependency closure whole or not at all, so declining any repository in it stops the install."]})}let managed=this.services.get("confd.managed"),added=[],needUrl=[];for(let repo of missing){if(repo.url===void 0){needUrl.push(repo.name);continue}let requesters=[...new Set(repo.requiredBy.map(entry=>entry.requestedBy))].sort(compareBytewise2);await writeRepoEntry(managed,repo.name,{url:repo.url,...repo.provider===void 0?{}:{provider:repo.provider},addedAt:nowIso(),addedBy:requesters.length>0?requesters.join(", "):USER_ADDED_BY},options.dryRun===!0),added.push(repo.name)}return{accepted:[...missing],added,needUrl}}identityOf(repository){try{return this.services.get("refs.locations").identity(repository).toLowerCase()}catch{return repository.includes("/")&&!repository.includes("://")?repository.toLowerCase():void 0}}};function trustQuestion(missing){return missing.length===1?`Do you trust the repository '${missing[0].name}'?`:`Do you trust these ${missing.length} repositories?`}function reportTrustNotice(reporter,missing){reporter.notice(missing.length===1?"One repository has to be trusted before this can continue.":`${missing.length} repositories have to be trusted before this can continue.`);for(let repo of missing){let entries=[{label:"Location",value:repo.url??"not known to sous; a ref named it by its short name only"}];repo.identity!==void 0&&entries.push({label:"Identity",value:repo.identity});for(let entry of repo.requiredBy)entries.push({label:"Required",value:`${entry.ref} (required by ${entry.requestedBy==="project"?"this project":`'${entry.requestedBy}'`})`});reporter.variables(entries,repo.name,LogLevel6.Notice)}reporter.note("Trusting a repository trusts every namespace and every recipe in it, including ones published later. Trusting on its own runs nothing; subscribing to something inside it can, and probably will, run scripts on this machine."),reporter.note("Sous cannot tell you whether a repository deserves trust. Look at the location above, and at who publishes it, before answering.")}function nonInteractiveDetails(missing){let lines3=[];for(let repo of missing){let provenance=repo.requiredBy.map(entry=>`${entry.ref} (required by ${entry.requestedBy})`).join(", ");lines3.push(`${repo.name}: ${repo.url??"URL not known to sous"}`,` ${provenance}`)}return lines3.push("Trusting a repository trusts every namespace and recipe in it, and subscribing to something inside it can run scripts on this machine.","Add each repository deliberately, with its URL:",...missing.map(repo=>` sous repo add ${repo.url??"<url>"} --name ${repo.name} --yes`)),lines3}function needUrlError(names2){return new SousError21(names2.length===1?`Sous does not know where the repository '${names2[0]}' lives, so it cannot add it for you.`:`Sous does not know where these repositories live, so it cannot add them for you: ${names2.map(name=>`'${name}'`).join(", ")}.`,{details:["A recipe names the repository it depends on by its short name only; the URL has to come from you.","Add each one with its URL, then run this command again:",...names2.map(name=>` sous repo add <url> --name ${name}`)]})}import{SousError as SousError22}from"@sous-io/plugin-api";function describeUpdateScope(scope){switch(scope.kind){case"all":return"every subscription in this project";case"repository":return`the recipes this project takes from the repository '${scope.repo}'`;case"namespace":return`the recipes in the namespace '${scope.repo}:${scope.namespace}'`;case"recipe":return`the recipe '${scope.repo}:${scope.key}'`}}function recipeInScope(scope,key,repo){switch(scope.kind){case"all":return!0;case"repository":return repo===scope.repo;case"namespace":return repo===scope.repo&&namespaceOfKey3(key)===scope.namespace;case"recipe":return repo===scope.repo&&key===scope.key}}function coverInScope(scope,cover,qualifier){if(scope.kind==="all")return!0;if(qualifier!==void 0&&qualifier!==scope.repo)return!1;switch(scope.kind){case"repository":return qualifier===scope.repo;case"namespace":return cover===scope.namespace||cover.startsWith(`${scope.namespace}/`);case"recipe":return cover===scope.key||scope.key.startsWith(`${cover}/`)}}function isEmptyUpdate(plan){return plan.diff.unchanged&&plan.missingRepos.length===0}async function freshIndexes(ctx){let cache2=ctx.services.get("recipes.index-cache"),repos=trustedRepos(ctx.config),indexes=new Map,unreachable=[];for(let name of repoSearchOrder(ctx))try{let read=await cache2.get(name,{latest:!0});read.source==="stale"&&unreachable.push({repo:name,reason:read.problem??"The repository could not be reached."}),indexes.set(name,read.index)}catch(error51){unreachable.push({repo:name,reason:describeError2(error51)});let cached2=cache2.cached(name);cached2!==void 0&&indexes.set(name,cached2.index)}return{indexes,unreachable,urls:new Map(Object.entries(repos).map(([name,entry])=>[name,entry.url]))}}async function resolveUpdateScope(ctx,input,catalog){if(input.ref===void 0||input.ref.trim()==="")return{kind:"all"};let readings=readingsOf(ctx,input.ref),trusted=trustedRepos(ctx.config);for(let reading of readings){if(reading.kind!=="repo")continue;if(reading.name!==void 0&&Object.hasOwn(trusted,reading.name))return{kind:"repository",repo:reading.name};let identity2=reading.location?.identity.toLowerCase(),byIdentity=catalog.repos.find(repo=>identity2!==void 0&&repo.identity?.toLowerCase()===identity2);if(byIdentity!==void 0)return{kind:"repository",repo:byIdentity.name}}let matches=findInCatalog(catalog,readings,["namespace","recipe"]),chosen=await pickMatch(ctx,matches,input.ref.trim(),input.acceptFirst,()=>new SousError22(`No trusted repository, namespace or recipe is called '${input.ref}'.`,{details:[`Searched: ${catalog.repos.map(repo=>repo.name).join(", ")||"nothing (no index could be read)"}.`]}));return chosen.ref.kind==="namespace"?{kind:"namespace",repo:chosen.repo.name,namespace:chosen.key}:{kind:"recipe",repo:chosen.repo.name,key:chosen.key}}async function planUpdate(input,ctx){let lockService=ctx.services.get("recipes.lock"),resolver=ctx.services.get("recipes.resolver"),format3=ctx.services.get("refs.format"),{indexes,unreachable,urls}=await freshIndexes(ctx),catalog={repos:[...indexes.entries()].map(([name,index])=>{let url2=urls.get(name),identity2=url2===void 0?void 0:identityOf(ctx,url2);return{name,index,...url2===void 0?{}:{url:url2},...identity2===void 0?{}:{identity:identity2}}}),lock:lockService.read(),subscriptions:[]},scope=await resolveUpdateScope(ctx,input,catalog),before=catalog.lock,configured=configuredSubscriptions(ctx.config),subscriptions=enabledSubscriptions2(ctx.config),unreachableNames=new Set(unreachable.map(entry=>entry.repo)),builtInKeys=Object.keys(subscriptions).filter(key=>isBuiltInEntry(subscriptions[key])),builtInHeld=new Set(builtInKeys.flatMap(key=>keysHeldBySubscription(before,key))),movable=(key,repo)=>!unreachableNames.has(repo)&&!builtInHeld.has(key)&&recipeInScope(scope,key,repo),keep={};for(let[key,entry]of Object.entries(before.recipes))movable(key,entry.repo)||(keep[key]=entry.version);let coverOf=key=>{try{let ref=format3.parseNamedRef(key,"config");return{cover:format3.key(ref),qualifier:format3.partsOf(ref).repo?.name}}catch{return}},touches=key=>{if(scope.kind==="all")return!0;let parsed=coverOf(key);return parsed===void 0?!1:lockedClosure(before,keysHeldBySubscription(before,parsed.cover)).some(held=>movable(held,before.recipes[held].repo))||coverInScope(scope,parsed.cover,parsed.qualifier)},targets=sortBytewise(Object.keys(subscriptions)).filter(key=>!isBuiltInEntry(subscriptions[key])&&touches(key)),merged=new Map,resolvedSubscriptions=[],missing=new Map,failed=[],cycles=[],unreadable2=new Set;for(let key of targets){let entry=subscriptions[key],request;try{request={ref:format3.parseNamedRef(key,"config"),...entry.range===void 0?{}:{range:entry.range},...entry.prerelease===!0?{prerelease:!0}:{},requestedBy:PROJECT_HOLDER,kind:"subscribes"}}catch(error51){failed.push({key,reason:describeError2(error51)});continue}let result;try{result=await resolver.resolve([request],{keep,indexes,...entry.prerelease===!0?{prerelease:!0}:{}})}catch(error51){failed.push({key,reason:describeError2(error51)});continue}cycles.push(...result.cycles),result.unreadable.forEach(item=>unreadable2.add(item));for(let repo of result.missingRepos){let known=missing.get(repo.name);missing.set(repo.name,known===void 0?repo:{...known,requiredBy:[...known.requiredBy,...repo.requiredBy]})}let conflict=result.resolved.find(recipe=>merged.has(recipe.key)&&merged.get(recipe.key).version!==recipe.version);if(conflict!==void 0){failed.push({key,reason:`It wants version ${conflict.version} of '${conflict.key}', and another subscription wants ${merged.get(conflict.key).version}.`});continue}for(let recipe of result.resolved){let already=merged.get(recipe.key);merged.set(recipe.key,already===void 0?recipe:mergeHolders(already,recipe))}resolvedSubscriptions.push(key)}let repoInputs={};for(let[name,url2]of urls)if(url2!==void 0){let identity2=identityOf(ctx,url2);repoInputs[name]={url:url2,...identity2===void 0?{}:{identity:identity2}}}let settled=[...merged.values()],covers2=keys=>keys.map(key=>coverOf(key)?.cover).filter(cover=>cover!==void 0),after=releaseDroppedHolds(applyResolution(before,settled,repoInputs),merged,covers2(resolvedSubscriptions),covers2(Object.keys(configured).filter(key=>!resolvedSubscriptions.includes(key)))),changed=settled.filter(recipe=>before.recipes[recipe.key]?.version!==recipe.version),links=ctx.services.has("recipes.links")?ctx.services.get("recipes.links"):void 0;return{scope,diff:lockService.diff(before,after),lockfile:after,missingRepos:[...missing.values()].sort((left,right)=>compareBytewise2(left.name,right.name)),newVariables:await newVariables(ctx,changed,before,indexes),unreadable:sortBytewise(unreadable2),unreachable,linked:sortBytewise(new Set(changed.map(recipe=>recipe.repo).filter(repo=>links?.get(repo)!==void 0))),builtIn:builtInKeys.filter(key=>keysHeldBySubscription(before,key).some(held=>recipeInScope(scope,held,before.recipes[held].repo))).map(key=>({key,...subscriptions[key]?.range===void 0?{}:{version:subscriptions[key].range}})),switchedOff:sortBytewise(Object.keys(configured).filter(key=>{let parsed=coverOf(key);return configured[key]?.enabled===!1&&parsed!==void 0&&coverInScope(scope,parsed.cover,parsed.qualifier)})),failed,cycles}}async function newVariables(ctx,changed,before,indexes){let{defined}=await definedVariables(ctx,changed),known=new Set;for(let recipe of changed){let pinned=before.recipes[recipe.key],old=pinned===void 0?void 0:indexes.get(pinned.repo)?.recipes[recipe.key]?.versions[pinned.version]?.variables;for(let variable of old??[])known.add(`${recipe.key}.${variable.name}`)}let added=defined.filter(variable=>!known.has(variable.key));return plannedQuestionsOf(ctx,added)}import"@sous-io/plugin-api";var INSTALLED_COLUMNS=[{key:"key",header:"Recipe",kind:"path",overflow:"truncate",minWidth:12},{key:"version",header:"Version",overflow:"truncate"},{key:"repo",header:"Repository",overflow:"truncate",priority:"medium"},{key:"why",header:"Why",overflow:"wrap",flex:1,minWidth:16}];function why(recipe){return recipe.requestedBy.includes("project")?"you subscribed to it":recipe.kind==="subscribes"?`co-subscribed by ${recipe.requestedBy.join(", ")}`:`needed by ${recipe.requestedBy.join(", ")}`}function reportCycles(ctx,cycles,hint){cycles.length>0&&ctx.reporter.problem("Some of these recipes co-subscribe to each other in a circle:",{cause:cycles.map(cycle=>cycle.join(" -> ")).join(`
902
903
  `),hint})}function subscriptionAddOutputs(ctx,result){let outputs=[];return result.dryRun&&outputs.push(dryRunOutput("Nothing will be downloaded, written or asked.")),outputs.push(tableOutput(INSTALLED_COLUMNS,result.resolved.map(recipe=>({key:recipe.key,version:recipe.version,repo:recipe.repo,why:why(recipe)})),{tableTitle:result.dryRun?"What would be installed":"What was installed"})),result.trusted.length>0&&outputs.push(sentence(`Repositories trusted along the way: ${result.trusted.join(", ")}. They are now recorded in this project's config, and your colleagues inherit them.`)),outputs.push(lockfileOutput(result.diff,"Nothing changed; everything asked for was already locked.")),reportCycles(ctx,result.cycles,"That is unusual but not broken, and everything above was installed."),result.dryRun&&result.questions!==void 0&&outputs.push(...underHeading("Questions these recipes ask",questionPlanOutputs(result.questions,{answerHints:!0}))),result.dryRun?outputs.push(dryRunOutput("Nothing was written. Run the same command without '--dry-run' to install it.")):outputs.push(sentence(`The subscription to '${result.key}' is recorded in this project's config, and the exact versions above are recorded in its lockfile.${rebuilt(result)?"":" Run 'sous build' to compile what they contribute."}`)),finishWithFollowUps(ctx,underHeading("Subscribing",outputs),result,`The subscription to '${result.key}' was saved, but the build that followed it failed, so this project's outputs may be incomplete. The subscription itself is recorded and locked; fix what the build reported above and run 'sous build' again.`)}function subscriptionRemoveOutputs(ctx,result){let pruneHint=rebuilt(result)?"":" Run 'sous build' to prune what it used to write.",outputs=[];return result.dryRun&&outputs.push(dryRunOutput("Nothing will be written.")),outputs.push(lockfileOutput(result.diff,"Nothing changed; nothing was locked because of this subscription.")),result.dryRun?outputs.push(dryRunOutput("Nothing was written. Run the same command without '--dry-run' to remove it.")):outputs.push(sentence(result.optedOut?`The subscription to '${result.key}' is one sous provides itself, so it was switched off rather than deleted: this project's config now records '${result.key}: { enabled: false }'. The repository it came from is still trusted.${pruneHint}`:`The subscription to '${result.key}' is gone. The repositories it came from are still trusted; remove one of those deliberately if you want to withdraw that too.${pruneHint}`)),finishWithFollowUps(ctx,underHeading("Unsubscribing",outputs),result,`The subscription to '${result.key}' was removed, but the build that followed it failed, so this project may still hold files it used to write. The removal itself is recorded and locked; fix what the build reported above and run 'sous build' again.`)}function subscriptionToggleOutputs(ctx,result){let word=result.enabled?"on":"off",outputs=[];return result.dryRun&&outputs.push(dryRunOutput("Nothing will be written.")),outputs.push(blockOutput({Subscription:result.key,Enabled:result.enabled?"yes":"no","Recorded in":result.file})),result.changed?result.dryRun?outputs.push(dryRunOutput(`Nothing was written. Run the same command without '--dry-run' to switch '${result.key}' ${word}.`)):outputs.push(sentence(`The subscription to '${result.key}' is now switched ${word}.${rebuilt(result)?"":" Run 'sous build' to bring the outputs in line."}`)):outputs.push(sentence(`The subscription to '${result.key}' was already switched ${word}; nothing changed.`)),finishWithFollowUps(ctx,underHeading(result.enabled?"Enabling a subscription":"Disabling a subscription",outputs),result,`The subscription to '${result.key}' was switched ${word}, but the build that followed failed; fix what the build reported above and run 'sous build' again.`)}function subscriptionUpdateOutputs(ctx,result){let scope=describeUpdateScope(result.plan.scope);if(result.nothingToUpdate)return finish2([],plainResult(result));if(result.dryRun||!result.applied)return finish2([dryRunOutput(`Nothing was written. Run the same command without '--dry-run' to update ${scope}.`)],plainResult(result));let outputs=[result.plan.diff.unchanged?sentence("Nothing changed.","Lockfile"):listOutput(lockDiffLines(result.plan.diff),{heading:"Lockfile"})];result.trusted.length>0&&outputs.push(sentence(`Repositories trusted along the way: ${result.trusted.join(", ")}. They are now recorded in this project's config, and your colleagues inherit them.`));let ask=followUpOf(result,"vars.ask");ask?.outputs!==void 0&&outputs.push(...underHeading("Variables",ask.outputs.toArray())),reportCycles(ctx,result.plan.cycles,"That is unusual but not broken, and the lockfile was updated.");let build2=followUpOf(result,"build");outputs.push(sentence(`The lockfile now pins the newest versions the ranges allow for ${scope}. This project's subscriptions are exactly as they were.`+(build2?.outputs!==void 0||result.plan.diff.unchanged?"":" The project was not rebuilt.")));let built=followUpOutputs({followUps:build2===void 0?[]:[build2]});return built.failed&&ctx.reporter.error("The lockfile was updated, but the build that followed it failed, so this project's outputs may not match the new versions yet. The update itself is recorded; fix what the build reported above and run 'sous build' again."),finish2(outputs,plainResult(result),{after:built.outputs,...built.failed?{exitCode:1}:{}})}function firstLine(text){return(text.split(`
903
904
  `)[0]??"").trim()}function updatePlanOutputs(plan){let outputs=[];isEmptyUpdate(plan)?outputs.push(sentence(`Nothing to update: every pin in ${describeUpdateScope(plan.scope)} is already the newest published version its range allows.`)):outputs.push(listOutput(plan.diff.unchanged?["No pin moves until the repositories below are trusted and read."]:lockDiffLines(plan.diff),{listTitle:`Updating ${describeUpdateScope(plan.scope)} changes the lockfile:`})),plan.missingRepos.length>0&&outputs.push(listOutput(plan.missingRepos.map(missing=>{let where2=missing.url===void 0?"":` at ${missing.url}`;return`${missing.name}${where2}, needed by ${missing.requiredBy.map(entry=>entry.requestedBy).join(", ")}`}),{listTitle:`A newer version needs ${plan.missingRepos.length===1?"a repository":"repositories"} this project does not trust yet. You are asked about each one by name before anything is fetched from it:`})),(plan.newVariables.length>0||plan.unreadable.length>0)&&(outputs.push(sentence("Questions the new versions ask that nothing answers yet:")),outputs.push(...questionPlanOutputs({questions:plan.newVariables,unreadable:plan.unreadable},{answerHints:!0}))),plan.unreadable.length>0&&outputs.push(noteOutput(`A dry run downloads no recipe, so the dependencies of the versions not on this machine yet, and not described by their index, are not shown: ${plan.unreadable.join(", ")}.`));for(let entry of plan.unreachable)outputs.push(noteOutput(`The index of '${entry.repo}' could not be fetched, so its pins stay where they are. ${firstLine(entry.reason)}`));for(let entry of plan.failed)outputs.push(noteOutput(`The subscription to '${entry.key}' could not be resolved, so its pins stay where they are. ${firstLine(entry.reason)}`));for(let repo of plan.linked)outputs.push(noteOutput(`The repository '${repo}' is linked to a working copy, so builds keep reading that checkout until it is unlinked; the pins above take effect then.`));for(let entry of plan.builtIn)outputs.push(noteOutput(`The subscription to '${entry.key}' is one sous provides itself, and it stays at ${entry.version===void 0?"the version":`version ${entry.version}, the version`} this installation of sous ships.`));return plan.switchedOff.length>0&&outputs.push(noteOutput(`Switched off, so left alone: ${plan.switchedOff.join(", ")}.`)),outputs}function recipeUpdateOutputs(plan){return finish2(underHeading("Update plan",[...updatePlanOutputs(plan),dryRunOutput("Nothing was written. Run 'sous subscription update' to apply it.")]),plan)}var MAX_TRUST_ROUNDS=10;async function refreshed(ctx){return await ctx.refreshConfig(),ctx}function lockRepoInputs(ctx){let inputs={};for(let[name,entry]of Object.entries(trustedRepos(ctx.config))){let identity2=identityOf(ctx,entry.url);inputs[name]={url:entry.url,...identity2===void 0?{}:{identity:identity2}}}return inputs}async function rebuild(ctx){try{return await refreshed(ctx)}catch(error51){ctx.reporter.warning(`The lockfile was written, but the recipes it pins could not all be downloaded yet: ${describeError2(error51)}`);return}}async function resolveWrittenRef(input,ctx){let readings=readingsOf(ctx,input.ref),short=readings.find(isShortNamed);if(short!==void 0){if(short.kind==="recipe"&&short.namespace!==void 0){let key=ctx.services.get("refs.format").key(short);if(key===key.toLowerCase())return{ref:short,trusted:[],ctx}}let catalog2=await loadCatalog(ctx);return{ref:await pickNamed(ctx,catalog2,readings.filter(isShortNamed),input,short),trusted:[],ctx}}let located=readings.filter(reading=>(reading.kind==="namespace"||reading.kind==="recipe")&&locationOf2(reading)!==void 0);if(located.length===0)throw new SousError23(`'${input.ref}' does not name a namespace or a recipe.`,{details:["Write 'namespace', 'namespace/recipe', either with '@<range>', or either as 'repository:ref' or a repository URL."]});let trust=ctx.services.get("recipes.trust"),current=ctx,trusted=[];if(!located.some(reading=>trust.isTrusted(locationOf2(reading).identity))){let chosen=located[0];new Set(located.map(reading=>locationOf2(reading).identity)).size>1&&(chosen=await ctx.services.get("refs.picker").pick(located,{search:input.ref.trim(),prompt:`'${input.ref.trim()}' can be read as more than one repository. Which one?`,...input.acceptFirst===void 0?{}:{acceptFirst:input.acceptFirst}},ctx));let location=locationOf2(chosen),name=proposeRepoName(Object.keys(trustedRepos(ctx.config)),location.identity),done2=await trust.confirm([{name,url:location.url,identity:location.identity,provider:location.provider,requiredBy:[{ref:input.ref.trim(),requestedBy:PROJECT_HOLDER}]}],{...input.yes===void 0?{}:{yes:input.yes},...input.dryRun===void 0?{}:{dryRun:input.dryRun}},ctx);if(trusted.push(...done2.added),input.dryRun===!0)return{ref:chosen,trusted,ctx};ctx.configChanged(),current=await refreshed(ctx)}let catalog=await loadCatalog(current,{latest:trusted.length>0});return{ref:await pickNamed(current,catalog,located,input,located[0]),trusted,ctx:current}}function locationOf2(ref){return(ref.kind==="namespace"?ref.repo:ref.namespace?.repo??ref.repo)?.location}async function pickNamed(ctx,catalog,readings,input,written){let matches=findInCatalog(catalog.inputs,readings,["namespace","recipe"]),match2=await pickMatch(ctx,matches,input.ref.trim(),input.acceptFirst,()=>{let searched=catalog.inputs.repos.map(repo=>repo.name);return new SousError23(`Nothing called '${input.ref.trim()}' was found: no namespace has that name, and no recipe does either.`,{details:[searched.length===0?"No repository index could be read, so there was nothing to search.":`Searched the namespaces and recipes of: ${searched.join(", ")}.`,...catalog.notFetched.length===0?[]:[`Trusted, but their index has not been read, so nothing in them was searched: ${catalog.notFetched.join(", ")}.`],`Run 'sous repo search ${input.ref.trim()}' to look for something like it, or 'sous repo add <url>' to add the repository that publishes it.`]})},{announce:!0});return match2.ref.kind==="recipe"&&written.kind==="recipe"&&written.range!==void 0?{...match2.ref,range:written.range}:match2.ref}function reportSubscriptionPlan(reporter,key,ref){reporter.list(["The files it ships are compiled into this project's agent directories on the next build.","Any scripts it ships can be run on this machine when an agent uses them. Sous does not run them itself, and cannot vouch for what they do.","The variables it publishes are asked about afterwards, and the answers are written to this project's env files.","Its dependencies are pinned in this project's lockfile at the versions resolved now. A dependency in a repository this project does not trust is asked about by name first."],{title:ref.kind==="namespace"?`Subscribing to '${key}' subscribes this project to the whole namespace '${ref.name}': every recipe in it, including ones published later.`:`Subscribing to '${key}' installs the recipe '${ref.name}' from the namespace '${ref.namespace?.name??"?"}'.`},LogLevel7.Notice)}async function resolveClosure(input,ref,start2){let trusted=[],tried=new Set,ctx=start2;for(let round2=0;;round2++){let result=await ctx.services.get("recipes.resolver").resolve([{ref,...ref.kind==="recipe"&&ref.range!==void 0?{range:ref.range}:{},...input.prerelease===!0?{prerelease:!0}:{},requestedBy:PROJECT_HOLDER,kind:"subscribes"}],{...input.prerelease===!0?{prerelease:!0}:{}}),missing=result.missingRepos;if(missing.length===0&&round2<MAX_TRUST_ROUNDS&&input.dryRun!==!0&&await downloadUnreadable(ctx,result.resolved,result.unreadable,tried))continue;if(missing.length===0||round2>=MAX_TRUST_ROUNDS){if(missing.length>0)throw new SousError23(`Resolving '${input.ref}' kept turning up repositories to trust: ${missing.map(repo=>repo.name).join(", ")}.`);return{resolved:result.resolved,unreadable:result.unreadable,cycles:result.cycles,trusted,ctx}}let done2=await ctx.services.get("recipes.trust").confirm(missing,{...input.yes===void 0?{}:{yes:input.yes},...input.dryRun===void 0?{}:{dryRun:input.dryRun}},ctx);if(done2.needUrl.length>0)throw needUrlError(done2.needUrl);if(trusted.push(...done2.added),input.dryRun===!0)return ctx.reporter.dryRun(`A dry run trusts nothing, so what ${sortBytewise(done2.added).join(", ")} would add is not resolved.`),{resolved:result.resolved,unreadable:result.unreadable,cycles:result.cycles,trusted,ctx};ctx.configChanged(),ctx=await refreshed(ctx)}}async function downloadUnreadable(ctx,resolved,unreadable2,tried){let downloaded=!1;for(let key of unreadable2){let recipe=resolved.find(entry=>entry.key===key);tried.has(key)||(tried.add(key),recipe!==void 0&&await recipeDirectory(ctx,recipe,!0)!==void 0&&(downloaded=!0))}return downloaded}async function addSubscription(input,ctx){let written=await resolveWrittenRef(input,ctx),format3=ctx.services.get("refs.format"),key=format3.key(written.ref),canonical=format3.format(written.ref);if(reportSubscriptionPlan(ctx.reporter,key,written.ref),input.dryRun!==!0&&input.yes!==!0&&!await ctx.prompter.confirm({message:`Subscribe to '${canonical}'?`,answeredBy:"--yes",default:!0}))throw new SousError23(`Nothing was written: the subscription to '${canonical}' was declined.`);let closure=await resolveClosure(input,written.ref,written.ctx),current=closure.ctx,lockService=current.services.get("recipes.lock"),before=lockService.read(),after=applyResolution(before,closure.resolved,lockRepoInputs(current)),result={ref:canonical,key,...input.ref.trim()===canonical?{}:{resolvedFrom:input.ref.trim()},resolved:closure.resolved,trusted:[...written.trusted,...closure.trusted],unreadable:closure.unreadable,cycles:closure.cycles,dryRun:input.dryRun===!0},installed2=await ensureRequiredPlugins(current,closure.resolved,input,input.ref.trim()),installFollowUp=installed2===void 0?[]:[installed2];if(await checkProvidedAnswers(current,closure.resolved,input,input.dryRun!==!0),input.dryRun===!0)return{...result,diff:lockService.diff(before,after),followUps:[...installFollowUp,{intent:"vars.ask",skipped:"--dry-run"},{intent:"build",skipped:"--dry-run"}],questions:await planQuestions(current,closure.resolved)};let range3=written.ref.kind==="recipe"?written.ref.range:void 0;await writeSubscriptionEntry(current.services.get("confd.managed"),key,{...range3===void 0?{}:{range:range3},...input.prerelease===!0?{prerelease:!0}:{},...input.alwaysPull===!0?{alwaysPull:!0}:{},addedAt:nowIso(),addedBy:USER_ADDED_BY});let diff=await writeLock(current,after);ctx.configChanged(),await rebuild(current);let asking=closure.resolved.filter(recipe=>recipe.variables===void 0||recipe.variables.length>0).map(recipe=>recipe.key);return{...result,diff,followUps:[...installFollowUp,await askFollowUp(ctx,input,asking),await buildFollowUp(ctx,input)]}}async function writeLock(ctx,lockfile){let lock=ctx.services.get("recipes.lock"),diff=await lock.write(lockfile);return await ctx.emit("recipes.locked",{path:lock.path(),diff}),diff}async function removeSubscription(input,ctx){let key=await subscriptionKeyFor(ctx,input.ref,Object.keys(configuredSubscriptions(ctx.config))),lockService=ctx.services.get("recipes.lock"),before=lockService.read(),removal=await planSubscriptionRemoval(ctx,key,before),planned={key,stayed:removal.stayed,optedOut:removal.optedOut,dryRun:input.dryRun===!0};for(let stayed of removal.stayed)ctx.reporter.note(`The recipe '${stayed.key}' stays, because ${stayed.heldBy.join(", ")} still holds it.`);if(input.dryRun===!0)return{...planned,diff:lockService.diff(before,removal.after),followUps:[{intent:"build",skipped:"--dry-run"}]};await writeSubscriptionRemoval(ctx,removal);let diff=await writeLock(ctx,removal.after);return ctx.configChanged(),input.noBuild!==!0&&await rebuild(ctx),{...planned,diff,followUps:[await buildFollowUp(ctx,input)]}}async function toggleSubscription(input,ctx,enabled){let configured=configuredSubscriptions(ctx.config),key=await subscriptionKeyFor(ctx,input.ref,Object.keys(configured)),managed=ctx.services.get("confd.managed"),file2=managed.path(SUBSCRIPTIONS_LAYER);if(!Object.hasOwn(configured,key)){let known=sortBytewise(Object.keys(configured));throw new SousError23(`This project does not subscribe to '${key}'.`,{details:[known.length>0?`It subscribes to: ${known.join(", ")}.`:"It has no subscriptions yet.",`Subscribe with 'sous subscription add ${key}'.`]})}let changed=configured[key]?.enabled!==!1!==enabled,edit=await setSubscriptionEnabled(managed,key,enabled,input.dryRun===!0),later=laterSetters(ctx.config,key);return later.length>0&&ctx.reporter.warning(`${later[later.length-1]} also sets subscriptions.${key}.enabled and is applied after conf.d/${SUBSCRIPTIONS_LAYER}, so its value still wins.`),input.dryRun===!0||!edit.changed?{key,enabled,file:file2,changed,dryRun:input.dryRun===!0,followUps:[{intent:"build",skipped:input.dryRun===!0?"--dry-run":"nothing changed"}]}:(ctx.configChanged(),changed&&input.noBuild!==!0&&await rebuild(ctx),{key,enabled,file:file2,changed,dryRun:!1,followUps:changed?[await buildFollowUp(ctx,input)]:[{intent:"build",skipped:"nothing changed"}]})}function laterSetters(config2,key){let own=managedContributor(SUBSCRIPTIONS_LAYER),contributors=config2.layers(["subscriptions",key,"enabled"]).map(layer=>layer.contributor),ownIndex=contributors.lastIndexOf(own),later=contributors.filter((contributor,index)=>contributor!==own&&(index>ownIndex&&ownIndex!==-1?!0:contributor.startsWith("confd/")&&contributor>own));return[...new Set(later)].map(contributorLabel)}function safeCached(cache2,repo){try{return cache2.cached(repo)}catch{return}}async function listSubscriptions(input,ctx){let lock=ctx.services.get("recipes.lock").read(),configured=configuredSubscriptions(ctx.config),cache2=ctx.services.get("recipes.index-cache"),fresh=new Map,indexOf=async repo=>{if(!fresh.has(repo))try{fresh.set(repo,input.latest===!0?await readUpstream(ctx,repo):cache2.cached(repo))}catch{fresh.set(repo,safeCached(cache2,repo))}return fresh.get(repo)},listings=[];for(let key of sortBytewise(Object.keys(configured))){let entry=configured[key],pinned=keysHeldBySubscription(lock,key).map(held=>({key:held,version:lock.recipes[held].version})),newer=[];if(input.latest===!0)for(let pin of pinned){let versions=(await indexOf(lock.recipes[pin.key].repo))?.index?.recipes[pin.key]?.versions??{},inRange=Object.fromEntries(Object.entries(versions).filter(([version2])=>import_semver9.default.satisfies(version2,entry.range??"*",{includePrerelease:entry.prerelease===!0,loose:!0}))),best=latestVersion(inRange);best!==void 0&&import_semver9.default.valid(pin.version,{loose:!0})!==null&&import_semver9.default.gt(best,pin.version,{loose:!0})&&newer.push({key:pin.key,version:best})}let latest2=[];for(let pin of pinned){let best=latestVersion((await indexOf(lock.recipes[pin.key].repo))?.index.recipes[pin.key]?.versions??{});latest2.push({key:pin.key,...best===void 0?{}:{version:best}})}listings.push({key,range:entry.range,enabled:entry.enabled!==!1,addedBy:entry.addedBy,pinned,latest:latest2,...input.latest===!0?{newer}:{}})}return listings}function reportUpdatePlan(reporter,plan){let scope=describeUpdateScope(plan.scope);if(isEmptyUpdate(plan)?reporter.notice(`Nothing to update: every pin in ${scope} is already the newest published version its range allows.`):reporter.list(plan.diff.unchanged?["No pin moves until the repositories below are trusted and read."]:describeDiff(plan.diff),{title:`Updating ${scope} changes the lockfile:`},LogLevel7.Notice),plan.missingRepos.length>0&&reporter.list(plan.missingRepos.map(missing=>`${missing.name}${missing.url===void 0?"":` at ${missing.url}`}, needed by ${missing.requiredBy.map(entry=>entry.requestedBy).join(", ")}`),{title:`A newer version needs ${plan.missingRepos.length===1?"a repository":"repositories"} this project does not trust yet. You are asked about each one by name before anything is fetched from it:`},LogLevel7.Notice),plan.newVariables.length>0||plan.unreadable.length>0){let questions=plan.newVariables.map(variable=>`${variable.recipe} asks ${variable.definition.name}: answer it with --answer ${variable.definition.name}=<value>`);plan.unreadable.length>0&&questions.push(`Not on this machine yet, and their repository's index does not record their questions, so they cannot be listed: ${plan.unreadable.join(", ")}. A dry run downloads nothing; run this command again without '--dry-run' to install them and be asked.`),reporter.list(questions,{title:"Questions the new versions ask that nothing answers yet:"},LogLevel7.Notice)}let notes=[];plan.unreadable.length>0&&notes.push(`A dry run downloads no recipe, so the dependencies of the versions not on this machine yet, and not described by their index, are not shown: ${plan.unreadable.join(", ")}.`);for(let entry of plan.unreachable)notes.push(`The index of '${entry.repo}' could not be fetched, so its pins stay where they are. ${firstLine2(entry.reason)}`);for(let entry of plan.failed)notes.push(`The subscription to '${entry.key}' could not be resolved, so its pins stay where they are. ${firstLine2(entry.reason)}`);for(let repo of plan.linked)notes.push(`The repository '${repo}' is linked to a working copy, so builds keep reading that checkout until it is unlinked; the pins above take effect then.`);for(let entry of plan.builtIn)notes.push(`The subscription to '${entry.key}' is one sous provides itself, and it stays at ${entry.version===void 0?"the version":`version ${entry.version}, the version`} this installation of sous ships.`);plan.switchedOff.length>0&&notes.push(`Switched off, so left alone: ${plan.switchedOff.join(", ")}.`),notes.length>0&&reporter.list(notes,{},LogLevel7.Notice)}function firstLine2(text){return(text.split(`
904
905
  `)[0]??"").trim()}function describeDiff(diff){let byKey=(left,right)=>left.key<right.key?-1:left.key>right.key?1:0;return[...diff.reposAdded.map(name=>`Repository added: ${name}`),...[...diff.added].sort(byKey).map(change=>`Adding ${change.key} version ${change.to}`),...[...diff.updated].sort(byKey).map(change=>`Updating ${change.key} from version ${change.from} to version ${change.to}`),...[...diff.removed].sort(byKey).map(change=>`Removing ${change.key}, which nothing needs any more`),...diff.reposRemoved.map(name=>`Repository no longer needed: ${name}`)]}function plannedRecipes(lockfile,keys){return keys.flatMap(key=>{let entry=lockfile.recipes[key],identity2=entry===void 0?void 0:lockfile.repos[entry.repo]?.identity,slash=key.indexOf("/");return entry===void 0||identity2===void 0||slash<0?[]:[{key,namespace:key.slice(0,slash),name:key.slice(slash+1),repo:entry.repo,identity:identity2,version:entry.version,hash:entry.hash,tag:"",path:"",kind:entry.kind,requestedBy:entry.requestedBy,ranges:[],prerelease:!1}]})}async function updateSubscriptions(input,ctx){let planInput={...input.ref===void 0?{}:{ref:input.ref},...input.acceptFirst===void 0?{}:{acceptFirst:input.acceptFirst}},plan=(await ctx.run("recipe.update",planInput)).toPlain(),base={trusted:[],dryRun:input.dryRun===!0},tried=new Set;for(;input.dryRun!==!0&&await downloadUnreadable(ctx,plannedRecipes(plan.lockfile,plan.unreadable),plan.unreadable,tried);)plan=await planUpdate(planInput,ctx);if(reportUpdatePlan(ctx.reporter,plan),isEmptyUpdate(plan))return{...base,plan,applied:!1,nothingToUpdate:!0,followUps:[]};if(input.dryRun===!0)return{...base,plan,applied:!1,nothingToUpdate:!1,followUps:[{intent:"vars.ask",skipped:"--dry-run"},{intent:"build",skipped:"--dry-run"}]};if(input.yes!==!0&&!await ctx.prompter.confirm({message:"Update the lockfile?",answeredBy:"--yes",default:!0}))throw new SousError23("Nothing was written: the update was declined.");let current=ctx;for(let round2=0;plan.missingRepos.length>0;round2++){if(round2>=MAX_TRUST_ROUNDS)throw new SousError23(`The update kept turning up repositories to trust: ${plan.missingRepos.map(repo=>repo.name).join(", ")}.`);let done2=await current.services.get("recipes.trust").confirm(plan.missingRepos,{...input.yes===void 0?{}:{yes:input.yes}},current);if(done2.needUrl.length>0)throw needUrlError(done2.needUrl);for(base.trusted.push(...done2.added),ctx.configChanged(),current=await refreshed(ctx),plan=await planUpdate(planInput,current);await downloadUnreadable(current,plannedRecipes(plan.lockfile,plan.unreadable),plan.unreadable,tried);)plan=await planUpdate(planInput,current)}await writeLock(current,plan.lockfile),ctx.configChanged(),await rebuild(current);let asking=sortBytewise(new Set(plan.newVariables.map(variable=>variable.recipe)));return{...base,plan,applied:!0,nothingToUpdate:!1,followUps:[await askFollowUp(ctx,input,asking),await buildFollowUp(ctx,input)]}}function registerSubscriptionIntents(sous){let ref={type:"string",description:"A namespace or a recipe: 'namespace', 'namespace/recipe', either with '@<range>' or as 'repository:ref'"},toggleInput=inputSchema({ref,dryRun,noBuild},["ref"]);sous.intents.add({intent:"subscription.add",requiresProject:!0,summary:"Subscribe this project to a recipe, or to a whole namespace of them",input:inputSchema({ref,prerelease:{type:"boolean",description:"Let prerelease versions take part in range matching"},alwaysPull:{type:"boolean",description:"Install a newer in-range version whenever one exists"},yes,acceptFirst,dryRun,noBuild,answer,answersFile,installPlugins:{type:"boolean",description:"Install npm plugins the recipe requires"}},["ref"]),changesConfig:!0,cli:{aliases:[["subscriptions","add"],["subscribe"]],positional:["ref"],flags:{yes:yesFlag},examples:["sous subscription add workflow/task-files","sous subscription add workflow/task-files@^1.2.0 --yes --answer apiUrl=https://api.example.com"]},agent:{usage:"Run with --dry-run first to see what it installs and asks; pass --yes and --answer to subscribe without prompts."},handle:async(input,ctx)=>subscriptionAddOutputs(ctx,await addSubscription(input,ctx))}),sous.intents.add({intent:"subscription.remove",requiresProject:!0,summary:"Remove a subscription and the recipes only it held",input:inputSchema({ref,dryRun,noBuild},["ref"]),changesConfig:!0,cli:{aliases:[["subscriptions","remove"],["unsubscribe"]],positional:["ref"]},handle:async(input,ctx)=>subscriptionRemoveOutputs(ctx,await removeSubscription(input,ctx))}),sous.intents.add({intent:"subscription.enable",requiresProject:!0,summary:"Switch a subscription back on, on this machine",input:toggleInput,changesConfig:!0,cli:{aliases:[["subscriptions","enable"]],positional:["ref"]},handle:async(input,ctx)=>subscriptionToggleOutputs(ctx,await toggleSubscription(input,ctx,!0))}),sous.intents.add({intent:"subscription.disable",requiresProject:!0,summary:"Switch a subscription off on this machine, keeping its pins",input:toggleInput,changesConfig:!0,cli:{aliases:[["subscriptions","disable"]],positional:["ref"]},handle:async(input,ctx)=>subscriptionToggleOutputs(ctx,await toggleSubscription(input,ctx,!1))}),sous.intents.add({intent:"subscription.list",requiresProject:!0,summary:"List what this project subscribes to",input:inputSchema(browsing),parallel:!0,cli:{aliases:[["subscriptions","list"]],flags:{latest:latestFlag}},handle:async(input,ctx)=>subscriptionListOutputs(ctx,input,await listSubscriptions(input,ctx))}),sous.intents.add({intent:"subscription.update",requiresProject:!0,summary:"Move pinned versions to the newest their ranges allow",input:inputSchema({ref:{type:"string",description:"Only this repository, namespace or recipe"},yes,acceptFirst,dryRun,noBuild,answer,answersFile}),changesConfig:!0,cli:{aliases:[["subscriptions","update"]],positional:["ref"],flags:{yes:yesFlag}},handle:async(input,ctx)=>subscriptionUpdateOutputs(ctx,await updateSubscriptions(input,ctx))}),sous.intents.add({intent:"recipe.update",requiresProject:!0,summary:"Plan an update of pinned versions, writing nothing",input:inputSchema({ref:{type:"string",description:"Only this repository, namespace or recipe"},acceptFirst}),parallel:!0,cli:{aliases:[["recipes","update"]],positional:["ref"]},handle:async(input,ctx)=>recipeUpdateOutputs(await planUpdate(input,ctx))})}import{ConfigError as ConfigError25}from"@sous-io/plugin-api";var CACHED_INDEX_LOOKUP_ID="recipes.cached-index",FETCHED_INDEX_LOOKUP_ID="recipes.fetched-index",FETCHED_INDEX_REUSE_MS=6e4;function catalogRepoOfIndex(index,repo={}){return{...repo.name===void 0?{}:{name:repo.name},...repo.location===void 0?{}:{location:repo.location},namespaces:Object.entries(index.namespaces).map(([name,declared])=>({name,...declared?.description===void 0?{}:{description:declared.description}})),recipes:Object.entries(index.recipes).map(([key,recipe])=>{let slash=key.indexOf("/");return{namespace:key.slice(0,slash),name:key.slice(slash+1),path:recipe.path,...recipe.description===void 0?{}:{description:recipe.description}}})}}function globNameMatcher(globs){let isMatch=(known,pattern,nocase)=>globs.isMatch(known,pattern,{nocase,dot:!0});return(written,known)=>isGlobName(written,globs)?isMatch(known,written,!1)?"exact":isMatch(known,written,!0)?"folded":void 0:written===known?"exact":written.toLowerCase()===known.toLowerCase()?"folded":void 0}function both(left,right){if(!(left===void 0||right===void 0))return left==="folded"||right==="folded"?"folded":"exact"}function knownRepo(repo,revision){return{kind:"repo",...repo.name===void 0?{}:{name:repo.name},...repo.location===void 0?{}:{location:repo.location},...revision===void 0?{}:{revision}}}function knownRecipe(repo,recipe,revision){let namespace={kind:"namespace",name:recipe.namespace,repo:knownRepo(repo,revision)};return{kind:"recipe",name:recipe.name,namespace,...recipe.description===void 0?{}:{description:recipe.description}}}function carry(candidate,known){return{...known,...candidate.kind==="recipe"&&candidate.range!==void 0?{range:candidate.range}:{},...candidate.vars===void 0?{}:{vars:candidate.vars}}}function qualifies(qualifier,repo,matchName2){if(qualifier===void 0)return"exact";let result="exact";if(!(qualifier.name!==void 0&&(repo.name===void 0||(result=matchName2(qualifier.name,repo.name),result===void 0)))&&!(qualifier.location!==void 0&&repo.location?.identity!==qualifier.location.identity))return result}function settleBrowsed(candidate,repo){if(candidate.location===void 0||repo.location?.identity!==candidate.location.identity)return[];let segments=(candidate.browsed??"").split("/").filter(segment=>segment.length>0),recipes=repo.recipes.map(recipe=>({recipe,path:(recipe.path??"").replace(/^\.?\/+|\/+$/g,"")})).filter(entry=>entry.path.length>0),range3=candidate.range===void 0?{}:{range:candidate.range},found=new Map;for(let start2=1;start2<segments.length;start2++){let folder=segments.slice(start2).join("/"),deepest=recipes.filter(entry=>folder===entry.path||folder.startsWith(`${entry.path}/`)).sort((left,right)=>right.path.length-left.path.length)[0];deepest!==void 0&&found.set(`${deepest.recipe.namespace}/${deepest.recipe.name}`,{...knownRecipe(repo,deepest.recipe,segments.slice(0,start2).join("/")),...range3})}if(found.size>0)return[...found.values()];for(let start2=1;start2<segments.length;start2++){let folder=segments.slice(start2).join("/"),namespaces=new Set(recipes.filter(entry=>entry.path.startsWith(`${folder}/`)).map(entry=>entry.recipe.namespace));if(namespaces.size===1){let name=[...namespaces][0];found.set(name,{kind:"namespace",name,repo:knownRepo(repo,segments.slice(0,start2).join("/"))})}}return[...found.values()]}function matchRecipes(candidate,repo,matchName2){let qualifier=qualifies(candidate.namespace?.repo??candidate.repo,repo,matchName2);return repo.recipes.map(recipe=>{let inNamespace=candidate.namespace===void 0?"exact":matchName2(candidate.namespace.name,recipe.namespace);return[carry(candidate,knownRecipe(repo,recipe)),both(both(qualifier,inNamespace),matchName2(candidate.name,recipe.name))]})}function matchIndexes(repos,candidate,tools){let found=[];return repos.forEach((repo,repoIndex)=>{let add=(ref,spelling)=>{spelling!==void 0&&found.push({ref,exactSpelling:spelling==="exact",repoIndex})};switch(candidate.kind){case"repo":if(candidate.browsed!==void 0)for(let settled of settleBrowsed(candidate,repo))add(settled,"exact");else(candidate.name!==void 0||candidate.location!==void 0)&&add({...knownRepo(repo),...candidate.vars===void 0?{}:{vars:candidate.vars}},qualifies(candidate,repo,tools.matchName));break;case"namespace":{let qualifier=qualifies(candidate.repo,repo,tools.matchName);for(let namespace of repo.namespaces)add(carry(candidate,{kind:"namespace",name:namespace.name,repo:knownRepo(repo),...namespace.description===void 0?{}:{description:namespace.description}}),both(qualifier,tools.matchName(candidate.name,namespace.name)));break}case"recipe":for(let[ref,spelling]of matchRecipes(candidate,repo,tools.matchName))add(ref,spelling);break;case"recipeFile":for(let[recipe,spelling]of matchRecipes(candidate.recipe,repo,tools.matchName))add({...candidate,recipe},spelling);break;default:break}}),found.sort((left,right)=>{if(left.repoIndex!==right.repoIndex)return left.repoIndex-right.repoIndex;let a=tools.key(left.ref),b=tools.key(right.ref);return a<b?-1:a>b?1:0}).map(({ref,exactSpelling})=>({ref,exactSpelling}))}function toolsOf(ctx){let globs=ctx.services.get("host.globs"),format3=ctx.services.get("refs.format");return{matchName:globNameMatcher(globs),key:ref=>format3.key(ref)}}function locationOfEntry(ctx,entry){if(entry!==void 0)try{return ctx.services.get("refs.locations").fromUrl(entry.url,entry.provider)}catch{return}}function trustedInOrder(ctx){let trusted=trustedRepos(ctx.config);return repoSearchOrder(ctx).map(name=>({name,location:locationOfEntry(ctx,trusted[name])}))}function ready(ctx){return ctx.services.has("recipes.index-cache")&&ctx.services.has("refs.format")&&ctx.services.has("host.globs")}function cachedCatalog(ctx){let cache2=ctx.services.get("recipes.index-cache"),repos=[];for(let{name,location}of trustedInOrder(ctx)){let cached2;try{cached2=cache2.cached(name)}catch{cached2=void 0}cached2!==void 0&&repos.push(catalogRepoOfIndex(cached2.index,{name,...location===void 0?{}:{location}}))}return repos}function cachedIndexLookup(){let findSync=(candidate,ctx)=>{if(!ready(ctx))return[];try{return matchIndexes(cachedCatalog(ctx),candidate,toolsOf(ctx))}catch{return[]}};return{id:CACHED_INDEX_LOOKUP_ID,description:"the repository indexes cached on this machine",kinds:["repo","namespace","recipe","recipeFile"],tags:["cached","index"],find:async(candidate,ctx)=>findSync(candidate,ctx),findSync}}async function readThroughCache(ctx,repo){let cache2=ctx.services.get("recipes.index-cache");return repo.name!==void 0?(await cache2.get(repo.name,{latest:!0})).index:cache2.fetchUpstream({name:repo.location.identity,url:repo.location.url,identity:repo.location.identity,provider:repo.location.provider})}function fetchedIndexLookup(options={}){let read=options.read??readThroughCache,now=options.now??Date.now,reads=new Map,indexOf=(ctx,repo)=>{let id=repo.location.identity,known=reads.get(id);if(known!==void 0&&now()-known.at<FETCHED_INDEX_REUSE_MS)return known.index;let index=read(ctx,repo);return reads.set(id,{at:now(),index}),index.catch(()=>reads.delete(id)),index};return{id:FETCHED_INDEX_LOOKUP_ID,description:"the repository indexes, read upstream",kinds:["repo","namespace","recipe","recipeFile"],tags:["latest","index"],optIn:!0,async find(candidate,ctx){if(!ready(ctx))return[];let tools=toolsOf(ctx),trusted=trustedInOrder(ctx),location=locationOf(candidate);if(location!==void 0){let name=trusted.find(repo=>repo.location?.identity===location.identity)?.name,index;try{index=await indexOf(ctx,{...name===void 0?{}:{name},location})}catch(error51){let folder=candidate.kind==="repo"&&candidate.browsed!==void 0;throw new ConfigError25(`The ref reads ${folder?"as a folder in":"as something in"} the repository at ${location.url}, and its index could not be read, so sous cannot settle what it means.`,{details:["Sous never guesses past an index it could not read.",describeError2(error51)]})}return matchIndexes([catalogRepoOfIndex(index,{...name===void 0?{}:{name},location})],candidate,tools)}let repos=[];for(let{name,location:at2}of trusted)if(at2!==void 0)try{repos.push(catalogRepoOfIndex(await indexOf(ctx,{name,location:at2}),{name,location:at2}))}catch{}return matchIndexes(repos,candidate,tools)}}}import{createHash as createHash4,randomBytes}from"node:crypto";import fs28 from"node:fs/promises";import path42 from"node:path";import{ConfigError as ConfigError26}from"@sous-io/plugin-api";var STORE_ENTRY_FILENAME2=".sous.entry.json",INDEX_CACHE_DIRNAME2="_indexes",ACCESS_GRANULARITY_MS=1440*60*1e3,TEMP_PREFIX=".sous-tmp-",GIT_DIR_NAME2=".git",MAX_STORE_DEPTH=12;function formatStoreKey(key){return`${key.identity}:${key.namespace}/${key.name}@${key.version}`}function storeKeyOf(entry){return{identity:entry.repo,namespace:entry.namespace,name:entry.name,version:entry.version}}function identitySegments3(identity2){return identity2.split("/").map(segment=>segment.trim().toLowerCase()).filter(segment=>segment.length>0)}function assertSafeSegment(value,label){if(value.length===0||value==="."||value===".."||/[/\\\0]/.test(value))throw new ConfigError26(`Invalid store key: the ${label} '${value}' is not a usable directory name.`,{details:["Every part of a store key (the identity's segments, the namespace, the recipe name and the version) must be one usable path segment."]})}async function removeTree(target){await fs28.rm(target,{recursive:!0,force:!0})}async function copyTree(source,destination){await fs28.mkdir(destination,{recursive:!0});let bytes=0;for(let entry of await fs28.readdir(source,{withFileTypes:!0})){if(entry.name===GIT_DIR_NAME2||entry.name===STORE_ENTRY_FILENAME2||entry.isSymbolicLink())continue;let from=path42.join(source,entry.name),to=path42.join(destination,entry.name);if(entry.isDirectory())bytes+=await copyTree(from,to);else if(entry.isFile()){let stats=await fs28.stat(from);await fs28.copyFile(from,to),await fs28.chmod(to,stats.mode&511),bytes+=stats.size}}return bytes}var RecipeStore=class{constructor(deps){this.deps=deps;this.root=path42.normalize(path42.resolve(deps.root))}root;entryDir(key){let identity2=identitySegments3(key.identity);if(identity2.length<2)throw new ConfigError26(`Invalid store key: '${key.identity}' is not a repository identity.`,{details:["An identity is the repository's host followed by its path, as in 'github.com/sous-io/sous-recipes'."]});for(let segment of identity2)assertSafeSegment(segment,"repository identity");return assertSafeSegment(key.namespace,"namespace"),assertSafeSegment(key.name,"recipe name"),assertSafeSegment(key.version,"version"),path42.join(this.root,...identity2,key.namespace,key.name,key.version)}async put(key,sourceDir,expectedHash){let target=this.entryDir(key),parent=path42.dirname(target);await this.deps.ensureRoot?.(this.root),await fs28.mkdir(parent,{recursive:!0});let staging=path42.join(parent,`${TEMP_PREFIX}${key.version}-${randomBytes(6).toString("hex")}`);try{let sizeBytes=await copyTree(sourceDir,staging),hash2=await this.deps.hashDirectory(staging);if(expectedHash!==void 0&&!this.deps.hashesEqual(hash2,expectedHash))throw new ConfigError26(`The content of ${formatStoreKey(key)} does not match the hash it is pinned to.`,{details:[`Expected: ${expectedHash}`,`Actual: ${hash2}`,"Nothing was written to the store. Either the upstream files changed under a published version, or the download was damaged."]});let existing=await this.readMarker(key);if(existing!==void 0&&!this.deps.hashesEqual(existing.hash,hash2))throw new ConfigError26(`The store already holds ${formatStoreKey(key)} with different content.`,{details:[`Stored: ${existing.hash}`,`Incoming: ${hash2}`,"A published version never changes, so sous will not overwrite it. Remove the entry on purpose if the version was really published again."]});let now=new Date().toISOString(),entry={formatVersion:1,repo:key.identity,namespace:key.namespace,name:key.name,version:key.version,hash:hash2,fetchedAt:existing?.fetchedAt??now,lastAccessAt:now,sizeBytes};return await fs28.writeFile(path42.join(staging,STORE_ENTRY_FILENAME2),this.deps.stringifyEntry(entry),"utf8"),await this.swapIntoPlace(staging,target),entry}finally{await removeTree(staging)}}async get(key){let entry=await this.readMarker(key);if(entry===void 0)return;let dir=this.entryDir(key),fingerprint=await this.statFingerprint(dir);if(entry.statFingerprint===void 0||entry.statFingerprint!==fingerprint){let actual=await this.deps.hashDirectory(dir);if(!this.deps.hashesEqual(actual,entry.hash)){await this.remove(key),this.deps.warn?.(`The cached copy of ${formatStoreKey(key)} did not match its recorded content hash, so it was removed and will be fetched again.`);return}}let now=new Date,stale=now.getTime()-Date.parse(entry.lastAccessAt)>=ACCESS_GRANULARITY_MS||Number.isNaN(Date.parse(entry.lastAccessAt));if(!stale&&entry.statFingerprint===fingerprint)return{dir,entry};let touched={...entry,statFingerprint:fingerprint,lastAccessAt:stale?now.toISOString():entry.lastAccessAt};return await fs28.writeFile(path42.join(dir,STORE_ENTRY_FILENAME2),this.deps.stringifyEntry(touched),"utf8"),{dir,entry:touched}}async statFingerprint(dir){let lines3=[],walk3=async(current,prefix)=>{let children=await fs28.readdir(current,{withFileTypes:!0});await Promise.all(children.map(async child2=>{let relative4=prefix===""?child2.name:`${prefix}/${child2.name}`;if(child2.isDirectory())lines3.push(`d ${relative4}`),await walk3(path42.join(current,child2.name),relative4);else if(!(prefix===""&&child2.name===STORE_ENTRY_FILENAME2)){let stats=await fs28.lstat(path42.join(current,child2.name));lines3.push(`f ${relative4} ${stats.size} ${stats.mtimeMs}`)}}))};return await walk3(dir,""),createHash4("sha1").update(lines3.sort().join(`
@@ -915,7 +916,7 @@ ${candidates.join(`
915
916
  `).map(line=>line.trimEnd()).filter(line=>line.trim().length>0)}function sanitize(segment){let cleaned=segment.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^\.+/,"");return cleaned.length>0?cleaned:"repo"}function isDirectory(candidate){try{return fs40.statSync(candidate).isDirectory()}catch{return!1}}async function linkRepo(input,ctx,runtime){let git2=ctx.services.get("git.runner"),links=ctx.services.get("recipes.links"),scope=input.global?"global":"project",dryRun4=input.dryRun===!0,inSlot=trustedRepos2(ctx)[input.repo]===void 0&&looksLikeLocalPath2(input.repo)?await requireRepoDirectory(ctx,input.repo):void 0;if(inSlot!==void 0&&input.path!==void 0)throw new ConfigError35(`'${input.repo}' is the path of a checkout on this machine, so it already says which checkout to link, and a second path cannot say it again.`,{details:[`Link a checkout where it already is: sous repo link ${input.repo}`,`Link a checkout to a named repository: sous repo link <name-or-url> ${input.path}`]});let{name,url:url2,added}=await resolveRepo(input,ctx,inSlot),existing=inSlot??(input.path===void 0?void 0:await requireRepoDirectory(ctx,input.path)),plan=existing!==void 0?{directory:existing,origin:"path",kind:"path",notes:[`Linked the checkout already at ${existing}.`]}:await planClone(ctx,runtime,git2,name,url2,scope,dryRun4),request=branchRequest(input);if(dryRun4){let wouldDo=[`would link '${name}' to ${plan.directory}`,...plan.notes.filter(note=>note.startsWith("Would")).map(note=>`w${note.slice(1).replace(/\.$/,"")}`),...describeBranchRequest(request),`would record it in ${scope==="global"?"the machine-wide":"this project's"} links map`];return{repo:name,path:plan.directory,origin:plan.origin,scope,cloned:!1,trusted:added,dryRun:dryRun4,wouldDo}}(request.switchTo!==void 0||request.create!==void 0||request.latest)&&(scope==="global"&&ctx.reporter.warn(`This checkout is SHARED by every project on this machine that links '${name}' with --global. Changing its branch changes what all of them build from.`),plan.notes.push(...await applyBranchRequest(git2,plan.directory,request,input.yes===!0,ctx)));let previous=links.getIn(name,scope),link=await links.set(name,{path:plan.directory,origin:plan.origin},scope);if(ctx.project!==void 0)try{await ensureLocalFilesIgnored(ctx.project.sousDir,ctx.services.get("host.gitignore"),ctx.services.get("host.directories"))}catch(error51){ctx.reporter.warn(`Sous could not update .sous/.gitignore, so git may see the links map: ${messageOf5(error51)}`)}let branch=await isGitCheckout(git2,plan.directory)?await currentBranch(git2,plan.directory):void 0,upstream=plan.kind==="cloned"?{}:await compareUpstream(git2,plan.directory,ctx);return ctx.reporter.problem(`The repository '${name}' is now LINKED. Its recipes are read from the checkout above, so versions, the lockfile and freshness checks no longer apply to it.`,{hint:`Run 'sous repo unlink ${name}${scope==="global"?" --global":""}' to go back to published versions.`}),{repo:name,path:link.path,origin:plan.origin,scope,cloned:plan.kind==="cloned",...branch===void 0?{}:{branch},trusted:added,dryRun:dryRun4,notes:plan.notes,recordedIn:links.path(scope),...previous!==void 0&&previous.path!==link.path?{replaced:previous.path}:{},...upstream}}async function resolveRepo(input,ctx,inSlot){let trusted=trustedRepos2(ctx),configured=trusted[input.repo];if(configured!==void 0)return{name:input.repo,url:configured.url,added:[]};if(inSlot!==void 0||looksLikeRepoUrl(input.repo)){let suggested=inSlot===void 0?void 0:await suggestedName(ctx,inSlot),outcome=(await ctx.run("repo.add",{url:inSlot??input.repo,...suggested===void 0?{}:{name:suggested},...input.yes===void 0?{}:{yes:input.yes},...input.dryRun===void 0?{}:{dryRun:input.dryRun}})).toPlain();return{name:outcome.name,url:outcome.url,added:outcome.alreadyTrusted?[]:[outcome.name]}}let known=Object.keys(trusted).sort();throw new ConfigError35(`'${input.repo}' is not a repository this project knows about, and it is neither a URL nor the path of a checkout on this machine.`,{details:[known.length>0?`This project knows about: ${known.join(", ")}.`:"This project has no repositories configured yet.","Add the repository first with 'sous repo add <url>', then link it by its short name."]})}async function suggestedName(ctx,directory){try{return(await ctx.services.get("formats.manifests").readRepo(directory))?.manifest.name}catch{return}}async function requireRepoDirectory(ctx,given){let home=ctx.env.HOME??os7.homedir(),expanded=given==="~"?home:given.startsWith("~/")?path53.join(home,given.slice(2)):given,directory=path53.resolve(ctx.cwd??ctx.project?.root??".",expanded);if(!fs41.existsSync(directory))throw new ConfigError35(`There is no directory at ${directory}.`,{details:["Pass the path of a checkout that already exists, or leave the path off to have sous clone the repository for you."]});if(!fs41.statSync(directory).isDirectory())throw new ConfigError35(`${directory} is a file, not a directory.`,{details:["Pass the root directory of a repository checkout."]});if(ctx.services.get("formats.manifests").find(directory,"repo")===void 0)throw new ConfigError35(`${directory} is not a sous repository.`,{details:["A repository declares itself with a 'sous.repo.yaml' file at its root, and there is none there.","Check the path, or create a repository with 'sous repo init'."]});return directory}async function planClone(ctx,runtime,git2,name,url2,scope,dryRun4){let slug=repoSlugFromUrl(url2),base=scope==="global"?runtime.homePaths().repos:path53.join(requireProject(ctx).sousDir,PROJECT_REPOS_DIRNAME),directory=path53.join(base,slug.owner,slug.name);if(await isGitCheckout(git2,directory)){let existing=await remoteUrlOf(git2,directory);if(existing!==void 0&&!sameRemote(existing,url2))throw new ConfigError35(`${directory} is already a checkout of a different repository.`,{details:[`It points at ${existing}, but '${name}' is ${url2}.`,"Move or delete that directory, or pass an explicit path to link the checkout you meant."]});return{directory,origin:"clone",kind:"reused",notes:[`Reused the checkout already at ${directory}; nothing was cloned.`]}}if(dryRun4)return{directory,origin:"clone",kind:"cloned",notes:[`Would clone ${url2} into ${directory}.`]};try{await ctx.services.get("host.directories").ensureKnown(scope==="global"?"global-repos":"project-repos",base)}catch{fs41.mkdirSync(base,{recursive:!0})}ctx.reporter.progress({label:`Cloning ${url2}`,item:directory});let clone2=await cloneRepo(git2,url2,directory);if(ctx.reporter.progress({label:`Cloning ${url2}`,item:directory,finished:!0}),ctx.services.get("formats.manifests").find(directory,"repo")===void 0)throw new ConfigError35(`${url2} was cloned into ${directory}, but it is not a sous repository.`,{details:["A repository declares itself with a 'sous.repo.yaml' file at its root, and there is none there.","The checkout has been left in place so you can look at it."]});return{directory,origin:"clone",kind:"cloned",notes:[`Cloned ${url2} into ${directory}.`,...clone2.fellBackToFullClone?["That remote would not serve a shallow clone, so the full history was fetched."]:[]]}}function requireProject(ctx){if(ctx.project===void 0)throw new ConfigError35("There is no sous project here to link a repository into.",{details:["Link with --global, or run sous from inside a project."]});return ctx.project}function branchRequest(input){let generated=input.generateBranch===!0,create=generated?generatedBranchName():input.createBranch,chosen=[input.branch===void 0?void 0:"--branch",input.createBranch===void 0?void 0:"--create-branch",generated?"--generate-branch":void 0].filter(flag=>flag!==void 0);if(chosen.length>1)throw new ConfigError35(`${chosen[0]} cannot also be provided when using ${chosen.slice(1).join(" and ")}.`,{details:["--branch, --create-branch and --generate-branch each say which branch to work on; pass only one of them."]});if(input.from!==void 0&&create===void 0)throw new ConfigError35("--from says where a new branch starts, so it needs --create-branch or --generate-branch.");return{...input.branch===void 0?{}:{switchTo:input.branch},...create===void 0?{}:{create},generated,...input.from===void 0?{}:{from:input.from},latest:input.latest===!0}}function describeBranchRequest(request){let lines3=[],from=request.switchTo??request.from,quoted=from===void 0?"the default branch":`'${from}'`;return request.latest?lines3.push(`would fetch ${quoted}, list any local work on it that would be discarded, and make it match upstream's`):request.switchTo!==void 0&&lines3.push(`would switch the checkout to the branch '${request.switchTo}'`),request.create!==void 0&&lines3.push(`would create the branch '${request.create}' from upstream's ${request.from===void 0?"the default branch":`'${request.from}'`} and switch to it`),lines3}async function applyBranchRequest(git2,directory,request,yes4,ctx){if(!await isGitCheckout(git2,directory))throw new ConfigError35(`${directory} is not a git checkout, so it has no branches to switch or create.`,{details:["Link it without the branch flags, or turn it into a git repository first."]});for(let name of[request.switchTo,request.create,request.from])name!==void 0&&await assertBranchName(git2,directory,name);let hasUpstream=await remoteUrlOf(git2,directory)!==void 0,fallback2=request.create!==void 0&&request.from===void 0||request.latest&&request.switchTo===void 0&&request.from===void 0?await requireDefaultBranch(git2,directory):void 0,notes=[];if(request.latest){let target=request.switchTo??request.from??fallback2;if(!hasUpstream)throw new ConfigError35(`--latest makes '${target}' match upstream's, and this checkout has no '${UPSTREAM_REMOTE}' remote to be upstream.`,{details:[`Add one with 'git remote add ${UPSTREAM_REMOTE} <url>' in ${directory}, or link without --latest.`]});await fetchBranch(git2,directory,target),await confirmDiscard(target,await discardableWork(git2,directory,target),yes4,ctx),await resetBranchToUpstream(git2,directory,target),notes.push(`Made the branch '${target}' match ${UPSTREAM_REMOTE}/${target}.`)}else request.switchTo!==void 0&&(hasUpstream&&!await localBranchExists(git2,directory,request.switchTo)&&await fetchBranch(git2,directory,request.switchTo),await switchBranch(git2,directory,request.switchTo),notes.push(`Switched to the branch '${request.switchTo}'.`));if(request.create!==void 0){let base=request.from??fallback2,startPoint=base;hasUpstream&&(request.latest||await fetchBranch(git2,directory,base),startPoint=`${UPSTREAM_REMOTE}/${base}`),await createBranch(git2,directory,request.create,startPoint),notes.push(`Created the branch '${request.create}'${request.generated?" (a generated name)":""} from ${startPoint}, and switched to it.`)}return notes}async function requireDefaultBranch(git2,directory){let found=await defaultBranch(git2,directory);if(found!==void 0)return found;throw new ConfigError35(`Could not work out the default branch of the repository checked out at ${directory}.`,{details:[`git records it as '${UPSTREAM_REMOTE}/HEAD' when it clones, and this checkout has no such record, nor could '${UPSTREAM_REMOTE}' be asked for it.`,"Name the branch to work from with --from, or with --branch."]})}async function confirmDiscard(branch,work,yes4,ctx){if(work.uncommitted.length===0&&work.localCommits.length===0||(ctx.reporter.warn(`Making '${branch}' match ${UPSTREAM_REMOTE}/${branch} discards the local work below.`),work.uncommitted.length>0&&ctx.reporter.list(work.uncommitted,{title:`Uncommitted changes: ${work.uncommitted.length}`},LogLevel8.Warning),work.localCommits.length>0&&ctx.reporter.list(work.localCommits,{title:`Commits ${UPSTREAM_REMOTE} does not have: ${work.localCommits.length}`},LogLevel8.Warning),yes4))return;if(!await ctx.prompter.confirm({message:"Discard it?",default:!1,answeredBy:"--yes"}))throw new ConfigError35(`Nothing was changed: the local work on '${branch}' was kept.`,{details:["The checkout is on the branch it was on before, and no link was recorded."]})}async function compareUpstream(git2,directory,ctx){if(!await isGitCheckout(git2,directory))return{};if(await remoteUrlOf(git2,directory)===void 0)return{upstreamNote:`The checkout has no '${UPSTREAM_REMOTE}' remote, so there is no upstream to compare it with.`};let fetched=await tryFetchUpstream(git2,directory),branch=await defaultBranch(git2,directory);if(!fetched.ok){let since=await lastFetchedAt(git2,directory,branch);return ctx.reporter.problem(`Could not reach upstream; the checkout may have diverged since ${since===void 0?"it was last fetched, and git has no record of when that was.":`${formatWhen(since)}, when it was last fetched.`}`,{cause:`Git said: ${fetched.reason}`,hint:"The link was recorded all the same, and nothing in the checkout was changed."}),{}}if(branch===void 0)return{upstreamNote:"Upstream was fetched, but its default branch could not be worked out, so there is nothing to compare the checkout with."};let comparison=await compareWithUpstream(git2,directory,branch);return{upstream:{upstream:`${UPSTREAM_REMOTE}/${branch}`,...comparison.merged===void 0?{}:{merged:comparison.merged},...comparison.behind===void 0?{}:{behind:comparison.behind},...comparison.branch===void 0?{detachedAt:comparison.commit??"an unknown commit"}:{}}}}function formatWhen(when){let pad2=value=>String(value).padStart(2,"0");return`${when.getFullYear()}-${pad2(when.getMonth()+1)}-${pad2(when.getDate())} ${pad2(when.getHours())}:${pad2(when.getMinutes())}`}function linkOutputs(result){let heading="Linking a repository";if(result.dryRun)return finish2(underHeading(heading,(result.wouldDo??[]).map(line=>dryRunOutput(line))),result);let outputs=(result.notes??[]).map(line=>detailOutput(line));if(outputs.push(blockOutput({Repository:result.repo,Checkout:result.path,...result.branch===void 0?{}:{Branch:result.branch},Scope:result.scope==="global"?"every project on this machine":"this project",...result.recordedIn===void 0?{}:{"Recorded in":result.recordedIn}})),result.replaced!==void 0&&outputs.push(sentence(`This replaces an earlier link to ${result.replaced}, which is untouched.`)),result.upstream!==void 0){let upstream=result.upstream.upstream,yesNo=value=>value===void 0?"unknown":value?"yes":"no";outputs.push(blockOutput({...result.upstream.detachedAt===void 0?{}:{"Checked out":`no branch; HEAD is detached at ${result.upstream.detachedAt}`},"Compared with":upstream,[`Merged into ${upstream}`]:yesNo(result.upstream.merged),[`Behind ${upstream}`]:result.upstream.behind===void 0?"unknown":`${result.upstream.behind} ${result.upstream.behind===1?"commit":"commits"}`}),noteOutput("Upstream was fetched just now; nothing in the checkout was changed."))}else result.upstreamNote!==void 0&&outputs.push(noteOutput(result.upstreamNote));return result.trusted.length>0&&outputs.push(sentence(`Repositories trusted along the way: ${result.trusted.join(", ")}.`)),finish2(underHeading(heading,outputs),result)}import fs42 from"node:fs";import path54 from"node:path";import{ConfigError as ConfigError36,LogLevel as LogLevel9,isSousError as isSousError4,isSousErrorOfKind as isSousErrorOfKind3}from"@sous-io/plugin-api";async function unlinkRepo(input,ctx,runtime){let links=ctx.services.get("recipes.links"),scope=input.global?"global":"project",name=input.repo,dryRun4=input.dryRun===!0,entry=links.getIn(name,scope);if(entry===void 0)throw new ConfigError36(notLinkedMessage(links,name,scope));if(input.update&&trustedRepos2(ctx)[name]===void 0)throw new ConfigError36(`'${name}' is linked, but this project does not trust a repository by that name, so it has no pins to update.`,{details:["Nothing was changed; the link is still in place."]});input.remove&&assertRemovable(name,entry,scope,runtime,ctx);let git2=ctx.services.get("git.runner"),work=input.remove?await unsavedWork(git2,entry.path):void 0,followUps=[];if(dryRun4){let wouldDo=[`would unlink '${name}', which points at ${entry.path}`,input.remove?"the checkout would be deleted":"the checkout itself would be left where it is"];if(work!==void 0&&!hasNoUnsavedWork(work)&&describeUnsavedWork(work,ctx),input.update){let planned=await ctx.run("subscription.update",{ref:name,dryRun:!0,noBuild:!0});followUps.push({intent:"subscription.update",result:planned.toPlain(),outputs:planned})}return{repo:name,path:entry.path,scope,removedCheckout:!1,dryRun:dryRun4,followUps,wouldDo}}work!==void 0&&await confirmRemoval(entry.path,work,input.yes===!0,ctx),await links.remove(name,scope),ctx.configChanged();let diff,published;if(input.update)try{let updated=await ctx.run("subscription.update",{ref:name,noBuild:!0,...input.yes===void 0?{}:{yes:input.yes},...input.answer===void 0?{}:{answer:input.answer},...input.answersFile===void 0?{}:{answersFile:input.answersFile}});diff=updated.toPlain().plan.diff,followUps.push({intent:"subscription.update",result:updated.toPlain(),outputs:updated})}catch(error51){let message2=`'${name}' was unlinked, but its pins were not updated. ${messageOf5(error51)}`;throw isSousErrorOfKind3(error51,"non-interactive")?Object.assign(error51,{message:message2}):new ConfigError36(message2,{cause:error51})}else published=await newerVersions(name,ctx);let checkoutNote;return input.remove?(fs42.rmSync(entry.path,{recursive:!0,force:!0}),checkoutNote=`The checkout sous cloned at ${entry.path} was deleted.`):checkoutNote=entry.origin==="clone"?`The checkout sous cloned is still at ${entry.path}.`:`The checkout at ${entry.path} was yours to begin with, and has not been touched.`,input.noBuild?followUps.push({intent:"build",skipped:"--no-build"}):followUps.push(await rebuild2(name,ctx)),{repo:name,path:entry.path,scope,removedCheckout:input.remove===!0,...diff===void 0?{}:{diff},dryRun:dryRun4,followUps,recordedIn:links.path(scope),...published===void 0?{}:{published},checkoutNote}}async function rebuild2(name,ctx){if(ctx.engine.intents.get("build")===void 0)return{intent:"build",skipped:"no plugin provides the build intent"};try{let built=await ctx.run("build",{});return{intent:"build",result:built.toPlain(),outputs:built}}catch(error51){throw new ConfigError36(`'${name}' was unlinked, but the build that followed failed, so this project's outputs may still hold what the checkout contributed.`,{cause:error51,details:[isSousError4(error51)?error51.message:messageOf5(error51),"The unlink itself is recorded; fix what the build reported and run 'sous build' again."]})}}function assertRemovable(name,entry,scope,runtime,ctx){if(entry.origin!=="clone")throw new ConfigError36(`Sous did not create the checkout at ${entry.path}, so it will not delete it.`,{details:[`'${name}' was linked to a checkout that was already there. Nothing was changed; unlink without '--remove' to keep the checkout, and delete it yourself if you want it gone.`]});let root=scope==="global"?runtime.homePaths().repos:path54.join(ctx.project?.sousDir??"",PROJECT_REPOS_DIRNAME),relative4=path54.relative(root,entry.path);if(relative4===""||relative4.startsWith("..")||path54.isAbsolute(relative4))throw new ConfigError36(`The checkout at ${entry.path} is not inside ${root}, where sous clones checkouts, so sous will not delete it.`,{details:["Nothing was changed; unlink without '--remove' and delete it yourself if you want it gone."]})}async function confirmRemoval(checkoutPath,work,yes4,ctx){if(hasNoUnsavedWork(work)||(describeUnsavedWork(work,ctx),yes4))return;if(!await ctx.prompter.confirm({message:"Delete the checkout, and this work with it?",default:!1,answeredBy:"--yes"}))throw new ConfigError36(`Nothing was changed: the checkout at ${checkoutPath} was not deleted, and the link is still in place.`)}function describeUnsavedWork(work,ctx){let group=(title2,items2)=>{items2.length>0&&ctx.reporter.list(items2,{title:title2},LogLevel9.Warning)};ctx.reporter.warn("The checkout holds work that exists nowhere else, and deleting it loses that work."),work.unknown!==void 0&&group("Sous could not inspect it, so it may hold anything:",[work.unknown]),group("Uncommitted changes:",work.uncommitted),group("Commits no remote has:",work.unpushed),group("Stashes:",work.stashes)}async function newerVersions(name,ctx){if(trustedRepos2(ctx)[name]===void 0)return;let newer=[];try{let index=(await withDeadline(signal=>ctx.services.get("recipes.index-cache").get(name,{signal,latest:!0}),NEWER_VERSION_CHECK_TIMEOUT_MS)).index,lockfile=ctx.services.get("recipes.lock").read(),subscriptions=ctx.config.get("subscriptions")??{};for(let[key,entry]of Object.entries(lockfile.recipes)){if(entry.repo!==name)continue;let range3=effectiveRangeForHolders(key,entry.requestedBy,{subscriptionRange:recipe=>subscriptionRange(recipe,subscriptions),dependencyRange:(holder,recipe)=>{let pinned=lockfile.recipes[holder],recorded=pinned===void 0?void 0:index.recipes[holder]?.versions[pinned.version]?.dependencies?.[recipe];return recorded===void 0?void 0:recorded.range??"*"}}),found=range3===void 0?void 0:findNewerInRange({index,key,lockedVersion:entry.version,range:range3});found!==void 0&&newer.push({key:found.key,from:found.from,to:found.to})}}catch(error51){return{checked:!1,reason:(messageOf5(error51).split(`
916
917
  `)[0]??"").trim(),newer:[]}}return{checked:!0,newer}}function subscriptionRange(key,subscriptions){let namespace=key.slice(0,key.indexOf("/"));for(let[subscription,entry]of Object.entries(subscriptions)){let stored=plainSubscriptionKey(subscription);if(stored===key||stored===namespace)return entry?.range??"*"}}function notLinkedMessage(links,name,scope){let other=scope==="global"?"project":"global",searched=scope==="global"?"the machine-wide links map":"this project's links map",elsewhere;try{elsewhere=links.getIn(name,other)}catch{elsewhere=void 0}if(elsewhere!==void 0)return`'${name}' is not linked in ${searched}. It is linked in the ${other==="project"?"project":"machine-wide"} map, at ${elsewhere.path}. Run the same command ${scope==="global"?"without":"with"} --global to remove that one.`;let linked=Object.keys(links.read(scope).links).sort();return`'${name}' is not linked in ${searched}. ${linked.length>0?`Linked there: ${linked.join(", ")}.`:"Nothing is linked there."} Run 'sous repo link ${name}' to link it.`}function unlinkOutputs(ctx,result){let outputs=[];if(result.dryRun?outputs.push(...(result.wouldDo??[]).map(line=>dryRunOutput(line))):outputs.push(blockOutput({Repository:result.repo,Checkout:result.path,Scope:result.scope==="global"?"every project on this machine":"this project",...result.recordedIn===void 0?{}:{Updated:result.recordedIn}}),sentence(`'${result.repo}' is read from the versions the lockfile pins again.`)),result.published!==void 0){let published=result.published,section2=[];published.checked?published.newer.length===0?section2.push(sentence(`Every pin from '${result.repo}' is the newest published version its range allows.`)):section2.push(sentence(`'${result.repo}' publishes newer versions within range. The lockfile still pins the older ones:`),blockOutput(published.newer.map(entry=>({label:entry.key,value:`${entry.from} pinned, ${entry.to} published`})))):section2.push(noteOutput(`Sous could not check '${result.repo}' for newer published versions. ${published.reason??""}`.trim())),outputs.push(...underHeading("Published versions",section2))}for(let entry of result.followUps)entry.intent==="subscription.update"&&entry.outputs!==void 0&&outputs.push(...underHeading("Updating the pins",entry.outputs.toArray()));result.checkoutNote!==void 0&&outputs.push(sentence(result.checkoutNote));let rest=followUpOutputs({followUps:result.followUps.filter(entry=>entry.intent!=="subscription.update")});return rest.failed&&ctx.reporter.error(`The repository '${result.repo}' was unlinked, but the build that followed it failed; fix what the build reported above and run 'sous build' again.`),finish2(underHeading("Unlinking a repository",outputs),plainResult(result),{after:rest.outputs,...rest.failed?{exitCode:1}:{}})}var LOCKFILE_LOOKUP_ID="recipes.lockfile";function matchPinned(candidate,lockfile,isMatch){let entries=sortKeys2(Object.keys(lockfile.recipes)).map(key=>({key,...splitStoredKey(key),repo:lockfile.recipes[key].repo})),name=(written,known)=>isMatch(known,written,!1)?"exact":isMatch(known,written,!0)?"folded":void 0,both3=(...matches)=>matches.includes(void 0)?void 0:matches.every(match2=>match2==="exact")?"exact":"folded",found=[];if(candidate.kind==="namespace"){let seen=new Set;for(let entry of entries){let match2=both3(name(candidate.name,entry.namespace),candidate.repo?.name===void 0?"exact":name(candidate.repo.name,entry.repo));match2!==void 0&&!seen.has(entry.namespace)&&(seen.add(entry.namespace),found.push({ref:{kind:"namespace",name:entry.namespace,repo:{kind:"repo",name:entry.repo}},exactSpelling:match2==="exact"}))}return found}let recipe=candidate.kind==="recipe"?candidate:candidate.kind==="recipeFile"?candidate.recipe:void 0;if(recipe?.namespace===void 0)return found;let repo=recipe.namespace.repo?.name??recipe.repo?.name;for(let entry of entries){let match2=both3(name(recipe.namespace.name,entry.namespace),name(recipe.name,entry.name),repo===void 0?"exact":name(repo,entry.repo));if(match2===void 0)continue;let known={kind:"recipe",name:entry.name,namespace:{kind:"namespace",name:entry.namespace,repo:{kind:"repo",name:entry.repo}},...recipe.range===void 0?{}:{range:recipe.range}},ref=candidate.kind==="recipeFile"?{kind:"recipeFile",path:candidate.path,recipe:known,...candidate.glob?{glob:!0}:{},...candidate.vars?{vars:candidate.vars}:{}}:known;found.push({ref,exactSpelling:match2==="exact"})}return found}function lockfileLookup(){let findSync=(candidate,ctx)=>{if(ctx.project===void 0||!ctx.services.has("recipes.lock"))return[];let globs=ctx.services.get("host.globs");return matchPinned(candidate,ctx.services.get("recipes.lock").read(),(known,written,nocase)=>globs.isMatch(known,written,{nocase}))};return{id:LOCKFILE_LOOKUP_ID,description:"the recipes this project's lockfile pins",kinds:["namespace","recipe","recipeFile"],tags:["lockfile","installed"],optIn:!0,find:async(candidate,ctx)=>findSync(candidate,ctx),findSync}}var import_semver12=__toESM(require_semver2(),1);function explainMissing(recipe,input){let namespace=recipe.slice(0,recipe.indexOf("/"));for(let[key,entry]of Object.entries(input.subscriptions??{})){if(entry?.enabled!==!1)continue;let stored;try{stored=input.keyOf(key)}catch{continue}if(stored===recipe||stored===namespace)return{by:"disabled-subscription",subscription:key}}let lock;try{lock=input.lockfile()}catch{return}let published=new Map;for(let identity2 of sortKeys2(new Set(Object.values(lock.repos).flatMap(repo=>repo.identity===void 0?[]:[repo.identity]))))for(let[key,entry]of Object.entries(input.cachedIndex(identity2)?.recipes??{}))published.has(key)||published.set(key,entry.versions);let declaredBy=(key,version2)=>Object.keys(published.get(key)?.[version2]?.dependencies??{}),queue=[];for(let holder of sortKeys2(Object.keys(lock.recipes))){let pinned=lock.recipes[holder].version,versions=Object.keys(published.get(holder)??{}).filter(version2=>version2!==pinned&&import_semver12.default.valid(version2)!==null).sort(import_semver12.default.rcompare);for(let version2 of versions)for(let key of declaredBy(holder,version2))queue.push({key,root:{recipe:holder,version:version2},through:[]})}let seen=new Set;for(;queue.length>0;){let step=queue.shift();if(step.key===recipe)return{by:"recipe",recipe:step.root.recipe,declaredAt:step.root.version,pinned:lock.recipes[step.root.recipe].version,...step.through.length>0?{through:step.through}:{}};if(!(Object.hasOwn(lock.recipes,step.key)||seen.has(step.key))){seen.add(step.key);for(let version2 of Object.keys(published.get(step.key)??{}))for(let key of declaredBy(step.key,version2))queue.push({key,root:step.root,through:[...step.through,step.key]})}}}import path55 from"node:path";var ActiveNamespaceResolver=class{constructor(options){this.options=options;for(let recipe of options.recipes){this.dirs.set(recipe.id,path55.resolve(recipe.dir)),this.repos.set(recipe.id,recipe.repo);for(let holder of recipe.requestedBy){let held=this.dependencies.get(holder)??[];held.push(recipe.id),this.dependencies.set(holder,held)}}}dirs=new Map;repos=new Map;dependencies=new Map;includingRecipe(fromFile){let target=path55.resolve(fromFile),best=null,bestLength=-1;for(let[key,dir]of this.dirs)(target===dir||target.startsWith(dir+path55.sep))&&dir.length>bestLength&&(best=key,bestLength=dir.length);return best}resolve(request){let{reference,fromFile}=request,parsed;try{parsed=this.options.parse(reference)}catch(error51){return{kind:"invalid",reference,message:error51 instanceof Error?error51.message:String(error51)}}let kept=parsed.refs.filter(ref=>ref.kind==="recipeFile");if(kept.length===0)return this.refused(reference,parsed);let written=kept.find(ref=>ref.vars!==void 0)??kept[0],namespace=written.recipe.namespace?.name??"",wanted=`${namespace}/${written.recipe.name}`,matched=this.match(written);if(matched.length===0)return written.glob===!0?{kind:"candidates",candidates:[],glob:!0}:this.knowsNamespace(namespace)?{kind:"unknown-recipe",recipe:wanted,known:this.recipesInNamespace(namespace),...this.droppedFor(wanted,fromFile)}:{kind:"unknown-namespace",namespace,recipe:wanted,known:this.namespaces(),...this.droppedFor(wanted,fromFile)};let including=this.includingRecipe(fromFile),declared=including===null?void 0:[including,...this.dependencies.get(including)??[]],candidates=[],roots=[];for(let key of matched){let dir=this.dirs.get(key);if(declared!==void 0&&!declared.some(entry=>entry===key||entry===key.slice(0,key.indexOf("/")))){if(written.glob===!0)continue;return{kind:"not-a-dependency",recipe:key,includingRecipe:including}}if(written.glob===!0){if(climbs(written.path))return{kind:"escapes-recipe",recipe:key,reference};candidates.push(`${escapeGlob(dir)}/${written.path}`),roots.push({recipe:key,dir});continue}let resolved=path55.resolve(dir,written.path),relative4=path55.relative(dir,resolved);if(resolved!==dir&&(relative4===""||relative4.startsWith("..")||path55.isAbsolute(relative4)))return{kind:"escapes-recipe",recipe:key,reference};candidates.push(resolved),roots.push({recipe:key,dir})}return written.glob===!0?{kind:"candidates",candidates,glob:!0,roots}:{kind:"candidates",candidates,roots}}namespaces(){return sortKeys2(new Set([...this.dirs.keys()].map(key=>key.slice(0,key.indexOf("/")))))}recipesInNamespace(written){let hits=[...this.dirs.keys()].map(key=>({key,match:this.matchName(written,key.slice(0,key.indexOf("/")))})).filter(hit=>hit.match!==void 0),exact=hits.filter(hit=>hit.match==="exact");return sortKeys2((exact.length>0?exact:hits).map(hit=>hit.key))}knowsNamespace(written){return[...this.dirs.keys()].some(key=>this.matchName(written,key.slice(0,key.indexOf("/")))!==void 0)}match(ref){let namespace=ref.recipe.namespace?.name;if(namespace===void 0)return[];let repo=ref.recipe.namespace?.repo?.name??ref.recipe.repo?.name,hits=[];for(let key of this.dirs.keys()){let slash=key.indexOf("/"),match2=combine(this.matchName(namespace,key.slice(0,slash)),this.matchName(ref.recipe.name,key.slice(slash+1)));if(repo!==void 0){let known=this.repos.get(key);match2=combine(match2,known===void 0?void 0:this.matchName(repo,known))}match2!==void 0&&hits.push({key,match:match2})}let exact=hits.filter(hit=>hit.match==="exact");return sortKeys2((exact.length>0?exact:hits).map(hit=>hit.key))}matchName(written,known){return this.options.isMatch(known,written,{nocase:!1})?"exact":this.options.isMatch(known,written,{nocase:!0})?"folded":void 0}refused(reference,parsed){for(let entry of parsed.dropped){let ref=entry.ref;if(ref.kind==="recipeFile"&&ref.path.split("/").some(part=>part==="."||part===".."))return{kind:"escapes-recipe",recipe:`${ref.recipe.namespace?.name??""}/${ref.recipe.name}`,reference}}let reasons=parsed.dropped.map(entry=>entry.instead===void 0?entry.reason:`${entry.reason} Write ${entry.instead}.`);return{kind:"invalid",reference,message:reasons.length>0?[...new Set(reasons)].join(`
917
918
  `):`'~${reference}' does not name a file inside a recipe.`}}droppedFor(recipe,fromFile){if(this.options.explainMissing===void 0||this.includingRecipe(fromFile)!==null)return{};let dropped=this.options.explainMissing(recipe);return dropped===void 0?{}:{dropped}}};function combine(left,right){if(!(left===void 0||right===void 0))return left==="exact"&&right==="exact"?"exact":"folded"}function climbs(pattern){return pattern.split(/[/{},]/).some(part=>part==="."||part==="..")}function escapeGlob(dir){return dir.replace(/[*?[\]{}()!+@\\]/g,char=>`\\${char}`)}import fs43 from"node:fs";import path56 from"node:path";import{pathToFileURL as pathToFileURL5}from"node:url";function pluginBundleOf(recipe){let entry=recipe.manifest.plugin;if(entry===void 0)return;let file2=insideRecipe(recipe.dir,entry.bundle);if(file2===void 0)return{problem:`The recipe ${recipe.id} names a plugin bundle outside its own files (${entry.bundle}), so it was not loaded.`};if(!fs43.existsSync(file2))return{problem:`The recipe ${recipe.id} names a plugin bundle that is not there (${entry.bundle}), so it was not loaded.`};let types2=entry.types===void 0?void 0:insideRecipe(recipe.dir,entry.types);return{file:file2,...types2!==void 0&&fs43.existsSync(types2)?{types:types2}:{}}}function insideRecipe(dir,relative4){if(path56.isAbsolute(relative4))return;let file2=path56.resolve(dir,relative4),real,root;try{root=fs43.realpathSync(dir),real=fs43.existsSync(file2)?fs43.realpathSync(file2):file2}catch{return}let from=path56.relative(root,real);return from===""||from.startsWith("..")||path56.isAbsolute(from)?void 0:file2}function pluginsContributor(){return{id:CONTRIBUTORS.plugins,after:[CONTRIBUTORS.fetch],contribute(config2){let repos=config2.atPath("repos").get()??{};for(let recipe of config2.entities("active-recipe")){let repo=repos[recipe.repo];if(repo===void 0||repo.enabled===!1)continue;let bundle=pluginBundleOf(recipe);if(bundle!==void 0){if("problem"in bundle){config2.warn(bundle.problem);continue}config2.atPath(["plugins","load"]).append(pathToFileURL5(bundle.file).href)}}}}}function writeRecipeTypes(sousDir,recipes){let directory=path56.join(sousDir,TYPES_DIRNAME),wanted=new Map;for(let recipe of recipes){let bundle=pluginBundleOf(recipe);bundle!==void 0&&!("problem"in bundle)&&bundle.types!==void 0&&wanted.set(path56.join(recipe.namespace,`${recipe.name}.d.ts`),bundle.types)}let written=[],removed=[];if(wanted.size===0&&!fs43.existsSync(directory))return{directory,written,removed};for(let existing of listDeclarations(directory))existing!=="index.d.ts"&&!wanted.has(existing)&&(fs43.rmSync(path56.join(directory,existing),{force:!0}),removed.push(existing));let references2=[];for(let relative4 of[...wanted.keys()].sort()){let target=path56.join(directory,relative4),text=fs43.readFileSync(wanted.get(relative4),"utf8");writeIfChanged(target,text)&&written.push(relative4),references2.push(`/// <reference path="./${relative4.split(path56.sep).join("/")}" />`)}let index=["// Written by sous on every build: the types of the plugins the active recipes ship.",...references2,""].join(`
918
- `);return writeIfChanged(path56.join(directory,"index.d.ts"),index)&&written.push("index.d.ts"),{directory,written,removed}}function listDeclarations(directory){try{return fs43.readdirSync(directory,{recursive:!0}).filter(entry=>entry.endsWith(".d.ts"))}catch{return[]}}function writeIfChanged(file2,text){try{if(fs43.readFileSync(file2,"utf8")===text)return!1}catch{}return fs43.mkdirSync(path56.dirname(file2),{recursive:!0}),fs43.writeFileSync(file2,text,"utf8"),!0}var import_semver13=__toESM(require_semver2(),1);import{ConfigError as ConfigError37}from"@sous-io/plugin-api";async function resolveWanted(requests,context){let resolved=new Map,missingRepos=new Map,unreadable2=new Set,cycles=[],parents=new Map,walked=new Map,queue=requests.map(request=>({...request,kind:request.kind??"subscribes",written:request.written??describeWanted(request)}));for(;queue.length>0;){let item=queue.shift();if(item.repo!==void 0&&!Object.hasOwn(context.repos,item.repo)&&item.remote===void 0){recordMissing(missingRepos,{name:item.repo,requiredBy:[{ref:item.written,requestedBy:item.requestedBy}]});continue}if(item.remote!==void 0){let added=repoNamedByIdentity(context.repos,item.remote.identity);if(added===void 0){recordMissing(missingRepos,{name:proposeRepoName2(context.repos,item.remote.identity),url:item.remote.url,identity:item.remote.identity,...item.remote.provider===void 0?{}:{provider:item.remote.provider},requiredBy:[{ref:item.written,requestedBy:item.requestedBy}]});continue}item.repo=added,item.remote.browsed!==void 0&&settleBrowsedItem(item,context.indexes.get(added))}if(item.name===void 0){queue.push(...expandNamespace(item,context));continue}let recipe=resolveRecipe(item,context,resolved);if(resolved.set(recipe.key,recipe),item.requestedBy!==PROJECT_HOLDER&&!parents.has(recipe.key)&&parents.set(recipe.key,item.requestedBy),walked.get(recipe.key)===recipe.version){let cycle=findCycle(recipe.key,item.requestedBy,parents);cycle!==void 0&&cycles.push(cycle);continue}walked.set(recipe.key,recipe.version);let lists=await safeLoad(context,recipe)??recipe.declares;if(lists===void 0){unreadable2.add(recipe.key);continue}for(let[kind,refs]of[["depends",lists.depends],["subscribes",lists.subscribes]])for(let written of refs)queue.push(dependencyRequest(written,recipe,kind,context))}return await keepOnlyReachable(resolved,context),{resolved:sortKeys2(resolved.keys()).map(key=>{let recipe=resolved.get(key);return recipe.requestedBy.sort(),recipe}),missingRepos:[...missingRepos.values()].sort((left,right)=>left.name<right.name?-1:left.name>right.name?1:0),unreadable:sortKeys2(unreadable2),cycles}}async function safeLoad(context,recipe){try{return await context.loadManifest(recipe)}catch{return}}function repoNamedByIdentity(repos,identity2){return Object.entries(repos).find(([,entry])=>entry.identity===identity2)?.[0]}function proposeRepoName2(repos,identity2){let base=identitySegments2(identity2).at(-1)??"repository";if(!Object.hasOwn(repos,base))return base;for(let suffix=2;;suffix+=1)if(!Object.hasOwn(repos,`${base}-${suffix}`))return`${base}-${suffix}`}function indexDependencyLists(version2){if(!(version2===void 0||version2.depends===void 0&&version2.subscribes===void 0))return{depends:version2.depends??[],subscribes:version2.subscribes??[]}}function wantedOf(ref){if(ref.kind==="namespace")return{namespace:ref.name,...repoParts(ref.repo)};if(ref.kind==="recipe"){let repo=ref.namespace?.repo??ref.repo;return ref.namespace===void 0?void 0:{namespace:ref.namespace.name,name:ref.name,...ref.range===void 0?{}:{range:ref.range},...repoParts(repo)}}if(ref.kind==="repo"&&ref.browsed!==void 0)return{namespace:"",...repoParts(ref),browsed:{path:ref.browsed,...ref.range===void 0?{}:{range:ref.range}}}}function repoParts(repo){return{...repo?.name===void 0?{}:{repo:repo.name},...repo?.location===void 0?{}:{location:repo.location}}}function describeWanted(wanted){let key=wanted.name===void 0?wanted.namespace:`${wanted.namespace}/${wanted.name}`;return`${wanted.repo===void 0?"":`${wanted.repo}:`}${key}${wanted.range===void 0?"":`@${wanted.range}`}`}function dependencyRequest(written,parent,kind,context){let reading=settleDependency(written,parent,context),base={requestedBy:parent.key,kind,written:written.trim(),...parent.prerelease?{prerelease:!0}:{}},wanted=reading===void 0?void 0:wantedOf(reading);if(wanted===void 0)throw unsettledDependencyError(written,parent,context);if(wanted.browsed!==void 0&&wanted.location!==void 0)return{namespace:"",...base,remote:{identity:wanted.location.identity,url:wanted.location.url,provider:wanted.location.provider,browsed:wanted.browsed,...parent.dependencies===void 0?{}:{pins:parent.dependencies}}};let key=wanted.name===void 0?void 0:`${wanted.namespace}/${wanted.name}`,pinned=key===void 0?void 0:parent.dependencies?.[key],range3=wanted.name===void 0?void 0:pinned?.version??wanted.range??pinned?.range,target={namespace:wanted.namespace,...wanted.name===void 0?{}:{name:wanted.name},...range3===void 0?{}:{range:range3}};return wanted.location===void 0?{...target,...base,repo:wanted.repo??parent.repo}:{...target,...base,remote:{identity:pinned?.repo??wanted.location.identity,url:wanted.location.url,provider:wanted.location.provider}}}function settleDependency(written,parent,context){let readings=context.parseDependency(written);if(readings.length===1)return readings[0];let confirmed=readings.filter(reading=>isConfirmedByRecord(reading,parent.dependencies));if(confirmed.length===1)return confirmed[0];let known=readings.filter(reading=>knownLocally(reading,context));return known.length===1?known[0]:void 0}function isConfirmedByRecord(candidate,recorded){let wanted=wantedOf(candidate);if(wanted===void 0)return!1;let identity2=wanted.location?.identity,records=Object.entries(recorded??{}).filter(([,record2])=>identity2===void 0?record2?.repo===void 0:record2?.repo===identity2);return wanted.browsed!==void 0?identity2!==void 0&&records.length>0:wanted.name===void 0?records.some(([key])=>key.startsWith(`${wanted.namespace}/`)):records.some(([key])=>key===`${wanted.namespace}/${wanted.name}`)}function knownLocally(reading,context){let wanted=wantedOf(reading);if(wanted?.location===void 0)return!1;let added=repoNamedByIdentity(context.repos,wanted.location.identity),index=added===void 0?void 0:context.indexes.get(added);return index===void 0?!1:wanted.browsed!==void 0?settleBrowsed2(wanted.browsed.path,index).length>0:wanted.name===void 0?Object.hasOwn(index.namespaces,wanted.namespace):Object.hasOwn(index.recipes,`${wanted.namespace}/${wanted.name}`)}function settleBrowsed2(browsed,index){let segments=browsed.split("/").filter(segment=>segment.length>0),recipes=Object.entries(index.recipes).map(([key,recipe])=>({key,path:(recipe.path??"").replace(/^\.?\/+|\/+$/g,"")})).filter(entry=>entry.path.length>0),found=new Map;for(let start2=1;start2<segments.length;start2+=1){let folder=segments.slice(start2).join("/"),deepest=recipes.filter(entry=>folder===entry.path||folder.startsWith(`${entry.path}/`)).sort((left,right)=>right.path.length-left.path.length)[0];deepest!==void 0&&found.set(deepest.key,splitStoredKey(deepest.key))}if(found.size>0)return[...found.values()];for(let start2=1;start2<segments.length;start2+=1){let folder=segments.slice(start2).join("/"),namespaces=new Set(recipes.filter(entry=>entry.path.startsWith(`${folder}/`)).map(entry=>splitStoredKey(entry.key).namespace));if(namespaces.size===1){let[namespace]=namespaces;found.set(namespace,{namespace})}}return[...found.values()]}function settleBrowsedItem(item,index){let remote=item.remote,browsed=remote.browsed,settled=index===void 0?[]:settleBrowsed2(browsed.path,index),found=settled.length===1?settled[0]:void 0;if(found===void 0){let recorded=Object.keys(remote.pins??{}).filter(key2=>remote.pins?.[key2]?.repo===remote.identity);recorded.length===1&&(found=splitStoredKey(recorded[0]))}if(found===void 0)throw new ConfigError37(`The dependency '${item.written}' names a folder, and the index of the repository at ${remote.url} ${settled.length===0?"publishes no recipe there":"publishes several recipes there"}.`,{details:[`It was required by the recipe '${item.requestedBy}'. Write the dependency as the recipe it means, such as '${remote.url}/<namespace>/<recipe>'.`]});let key=found.name===void 0?void 0:`${found.namespace}/${found.name}`,pinned=key===void 0?void 0:remote.pins?.[key];item.namespace=found.namespace,item.name=found.name,item.range=found.name===void 0?void 0:pinned?.version??browsed.range??pinned?.range}function unsettledDependencyError(written,parent,context){let readings=context.parseDependency(written);return new ConfigError37(`The dependency '${written.trim()}' of the recipe '${parent.key}' can be read ${readings.length} ways, and nothing says which one it means.`,{details:[`A release records which one it settled on in the index; the index of '${parent.repo}' records none for this version.`,"Release the recipe again with this version of sous, or write the dependency so it reads one way."]})}function expandNamespace(item,context){let expanded=[],seen=new Set,found=!1;for(let[repoName,index]of context.indexes)if(!(item.repo!==void 0&&repoName!==item.repo||!Object.hasOwn(index.namespaces,item.namespace))){found=!0;for(let key of Object.keys(index.recipes))!key.startsWith(`${item.namespace}/`)||seen.has(key)||(seen.add(key),expanded.push({namespace:item.namespace,name:key.slice(item.namespace.length+1),...item.range===void 0?{}:{range:item.range},...item.repo===void 0?{}:{repo:item.repo},requestedBy:item.requestedBy,kind:item.kind,written:item.written,...item.prerelease===void 0?{}:{prerelease:item.prerelease}}))}if(!found)throw unknownRefError2(item,context,"namespace");return expanded}function resolveRecipe(item,context,resolved){let key=`${item.namespace}/${item.name}`,candidates=[];for(let[repoName,index]of context.indexes)(item.repo===void 0||repoName===item.repo)&&Object.hasOwn(index.recipes,key)&&candidates.push(repoName);if(candidates.length===0)throw unknownRefError2(item,context,"recipe");if(candidates.length>1)throw ambiguousRefError(item,key,candidates);let repo=candidates[0],entry=context.indexes.get(repo).recipes[key],previous=resolved.get(key);if(previous!==void 0&&previous.repo!==repo)throw new ConfigError37(`The recipe '${key}' is being taken from two repositories at once: '${previous.repo}' and '${repo}'.`,{details:["Qualify the refs that ask for it, so each one says which repository it means."]});let ranges=[...previous?.ranges??[]],range3=item.range??"*";ranges.some(known=>known.range===range3&&known.requestedBy===item.requestedBy)||ranges.push({range:range3,requestedBy:item.requestedBy});let prerelease=(previous?.prerelease??!1)||(item.prerelease??context.prerelease??!1),version2=pickVersion(key,entry,ranges,prerelease,context.keep?.[key]),versionEntry=entry.versions[version2],declares=indexDependencyLists(versionEntry),requestedBy=[...previous?.requestedBy??[]];return requestedBy.includes(item.requestedBy)||requestedBy.push(item.requestedBy),{key,namespace:item.namespace,name:item.name,repo,identity:context.repos[repo]?.identity??repo,version:version2,hash:versionEntry.hash,tag:versionEntry.tag,path:entry.path,...versionEntry.dependencies===void 0?{}:{dependencies:versionEntry.dependencies},...versionEntry.variables===void 0?{}:{variables:versionEntry.variables},...declares===void 0?{}:{declares:{depends:[...declares.depends],subscribes:[...declares.subscribes]}},kind:previous?.kind==="subscribes"||item.kind==="subscribes"?"subscribes":"depends",requestedBy,ranges,prerelease}}function pickVersion(key,entry,ranges,prerelease,keep){let published=Object.keys(entry.versions),candidates=prerelease?published:published.filter(version2=>entry.versions[version2].prerelease!==!0);for(let{range:range3}of ranges)candidates=candidates.filter(version2=>import_semver13.default.satisfies(version2,range3,{includePrerelease:prerelease}));if(keep!==void 0&&Object.hasOwn(entry.versions,keep)&&ranges.every(({range:range3})=>import_semver13.default.satisfies(keep,range3,{includePrerelease:!0})))return keep;let best=import_semver13.default.maxSatisfying(candidates,"*",{includePrerelease:prerelease});if(best!==null)return best;let asked=ranges.map(({range:range3,requestedBy})=>` ${range3} (required by ${requestedBy})`),available=[...published].sort((left,right)=>import_semver13.default.rcompare(left,right,{loose:!0})).join(", ");throw new ConfigError37(`No published version of '${key}' satisfies what was asked for.`,{details:[`Version ${ranges.length===1?"range":"ranges"} asked for:`,...asked,`Versions this repository publishes: ${available}.`,...prerelease?[]:["Prerelease versions were not considered. A subscription may opt into them with 'prerelease: true', and 'sous subscribe' with '--prerelease'."]]})}function unknownRefError2(item,context,what){let searched=[...context.indexes.keys()],index=item.repo===void 0?void 0:context.indexes.get(item.repo),details=[searched.length===0?"This project has added no repositories yet.":`Repositories searched: ${searched.join(", ")}.`,...item.requestedBy===PROJECT_HOLDER?[]:[`It was required by the recipe '${item.requestedBy}'.`],...index===void 0?[]:[`The repository '${item.repo}' publishes: ${Object.keys(index.recipes).length===0?"nothing yet":sortKeys2(Object.keys(index.recipes)).join(", ")}.`],"Add the repository that publishes it with 'sous repo add <url>', then try again."];return new ConfigError37(`No added repository publishes the ${what} '${item.written}'.`,{details})}function ambiguousRefError(item,key,repos){let range3=item.range===void 0||item.range==="*"?"":`@${item.range}`;return new ConfigError37(`The ref '${key}' is published by more than one added repository: ${repos.join(", ")}.`,{details:[...item.requestedBy===PROJECT_HOLDER?[]:[`It was required by the recipe '${item.requestedBy}'.`],"Say which repository you mean by qualifying the ref with its name:",...repos.map(repo=>` ${repo}:${key}${range3}`)]})}function recordMissing(into,missing){let existing=into.get(missing.name);if(existing===void 0){into.set(missing.name,missing);return}for(let entry of missing.requiredBy)existing.requiredBy.some(known=>known.ref===entry.ref&&known.requestedBy===entry.requestedBy)||existing.requiredBy.push(entry)}function findCycle(key,from,parents){if(from===PROJECT_HOLDER)return;let chain=[key],guard2=new Set,current=from;for(;current!==void 0&&current!==PROJECT_HOLDER;){if(chain.push(current),current===key)return chain.reverse();if(guard2.has(current))return;guard2.add(current),current=parents.get(current)}}async function keepOnlyReachable(resolved,context){let holders=new Map,declare=(parent,child2,kind)=>{let existing=holders.get(child2);if(existing===void 0)return holders.set(child2,new Map([[parent,kind]])),!0;let previous=existing.get(parent);return existing.set(parent,previous==="subscribes"||kind==="subscribes"?"subscribes":kind),!1},queue=[];for(let recipe of resolved.values())recipe.requestedBy.includes(PROJECT_HOLDER)&&declare(PROJECT_HOLDER,recipe.key,"subscribes")&&queue.push(recipe.key);for(;queue.length>0;){let key=queue.shift(),recipe=resolved.get(key);if(recipe===void 0)continue;let lists=await safeLoad(context,recipe)??recipe.declares;if(lists===void 0){for(let other of resolved.values())other.requestedBy.includes(key)&&declare(key,other.key,other.kind)&&queue.push(other.key);continue}for(let[kind,refs]of[["depends",lists.depends],["subscribes",lists.subscribes]])for(let written of refs)for(let target of dependencyTargets(written,recipe,context,resolved))resolved.has(target)&&declare(key,target,kind)&&queue.push(target)}for(let[key,recipe]of[...resolved]){let reached=holders.get(key);if(reached===void 0){resolved.delete(key);continue}recipe.requestedBy=[...reached.keys()],recipe.ranges=recipe.ranges.filter(entry=>reached.has(entry.requestedBy)),recipe.kind=[...reached.values()].includes("subscribes")?"subscribes":"depends"}}function dependencyTargets(written,holder,context,resolved){let item;try{if(item=dependencyRequest(written,holder,"depends",context),item.remote?.browsed!==void 0){let added=repoNamedByIdentity(context.repos,item.remote.identity);settleBrowsedItem(item,added===void 0?void 0:context.indexes.get(added))}}catch{return[]}return item.name===void 0?[...resolved.keys()].filter(key=>key.startsWith(`${item.namespace}/`)):[`${item.namespace}/${item.name}`]}var ResolverService=class{constructor(ctx,runtime){this.ctx=ctx;this.runtime=runtime}linked=new Map;async resolve(requests,options={}){let trusted=trustedRepos2(this.ctx),repos={};for(let[name,entry]of Object.entries(trusted)){let identity2=this.runtime.tryIdentity(entry.url);identity2!==void 0&&(repos[name]={url:entry.url,identity:identity2,...entry.provider===void 0?{}:{provider:entry.provider}})}let indexes=options.indexes??await this.indexes(Object.keys(repos),options.latest===!0,options.quiet===!0),wanted=[];for(let request of requests){let parts=wantedOf(request.ref);parts!==void 0&&wanted.push({...parts,...request.range!==void 0&&parts.range===void 0?{range:request.range}:{},requestedBy:request.requestedBy,...request.kind===void 0?{}:{kind:request.kind},...request.prerelease===void 0?{}:{prerelease:request.prerelease},written:this.format(request)})}return resolveWanted(wanted,{indexes,repos,loadManifest:recipe=>this.loadManifest(recipe),parseDependency:written=>this.parseDependency(written),...options.prerelease===void 0?{}:{prerelease:options.prerelease},...options.keep===void 0?{}:{keep:options.keep}})}async resolveSubscriptions(options={}){let subscriptions=enabledSubscriptions(this.ctx.config.get("subscriptions")),format3=this.ctx.services.get("refs.format"),requests=sortKeys2(Object.keys(subscriptions)).map(key=>{let entry=subscriptions[key];return{ref:format3.parseNamedRef(key,"config"),...entry.range===void 0?{}:{range:entry.range},...entry.prerelease===!0?{prerelease:!0}:{},requestedBy:PROJECT_HOLDER,kind:"subscribes"}});return this.resolve(requests,options)}reachable(lockfile){return reachability({lockfile,subscriptions:this.ctx.config.get("subscriptions"),repos:this.ctx.config.get("repos"),keyOf:key=>this.keyOf(key)}).reached}keyOf(subscription){try{let format3=this.ctx.services.get("refs.format");return format3.key(format3.parseNamedRef(subscription,"config"))}catch{return plainSubscriptionKey(subscription)}}async indexes(names2,latest2,quiet){let cache2=this.ctx.services.get("recipes.index-cache"),found=new Map;for(let name of sortKeys2(names2))try{let read=await cache2.get(name,{latest:latest2});if(read.source==="stale"&&!quiet){let problem=read.problem;this.runtime.host.reporter.problem(`Sous could not check the repository '${name}' for updates, so it is using the copy of its index that it already had.`,problem===void 0?{}:{cause:problem})}found.set(name,read.index)}catch{let cached2=cache2.cached(name);cached2!==void 0&&found.set(name,cached2.index)}return found}async loadManifest(recipe){let manifests=this.ctx.services.get("formats.manifests"),link=this.ctx.services.get("recipes.links").get(recipe.repo);if(link!==void 0){let map3=this.linked.get(link.path);map3===void 0&&(map3=mapLinkedRecipes(link.path,manifests),this.linked.set(link.path,map3));let found=(await map3).get(recipe.key);if(found!==void 0)return{depends:found.manifest.depends??[],subscribes:found.manifest.subscribes??[]}}let hit=await this.ctx.services.get("recipes.store").get(storeKeyOf2(recipe.key,recipe.identity,recipe.version));if(hit===void 0)return;let manifest=await manifests.readRecipe(hit.dir);return manifest===void 0?void 0:{depends:manifest.manifest.depends??[],subscribes:manifest.manifest.subscribes??[]}}parseDependency(written){try{return this.ctx.services.get("refs.resolver").resolveSync({input:written,from:"manifest",lookups:!1,refusedIsEmpty:!0}).refs}catch{return[]}}format(request){try{return this.ctx.services.get("refs.format").format(request.ref)}catch{return request.ref.name}}};import{nullReporter as nullReporter3}from"@sous-io/plugin-api";var PartBRuntime=class{constructor(host){this.host=host}core;fetched=new Set;noteFetched(keys){for(let key of keys)this.fetched.add(key)}takeFetched(){let keys=[...this.fetched];return this.fetched.clear(),keys}get services(){return this.host.services}get entities(){return this.host.entities}homePaths(){return this.services.get("host.sous-home").paths(this.host.env)}hosts(){return this.entities.list("repository-host")}identity(url2){return this.services.get("refs.locations").identity(url2)}tryIdentity(url2,hosts){try{return this.identity(url2)}catch{}try{let host=hostFor(hosts??this.hosts(),url2);if(host===void 0)return;let canonical=host.canonicalize(url2);return`${canonical.host}/${canonical.owner}/${canonical.name.replace(/\.git$/i,"")}`.split("/").filter(segment=>segment.length>0).map(segment=>segment.toLowerCase()).join("/")}catch{return}}indexCore(){if(this.core===void 0){let paths=this.homePaths();this.core=new IndexCacheCore({directory:paths.indexCache,strategiesFile:paths.readStrategies,parser:this.services.get("formats.index-file"),hosts:()=>this.hosts(),hostContext:()=>this.hostContext()})}return this.core}hostContext(reporter=nullReporter3,signal){return{plugin:RECIPES_PLUGIN,config:this.host.engine.config,services:this.services,entities:this.entities,project:this.host.project,env:this.host.env,cwd:this.host.project?.root??process.cwd(),reporter,...signal===void 0?{}:{signal}}}async emit(name,payload){try{await this.host.emit(name,payload)}catch{}}};import{jsonSchema as jsonSchema14}from"@sous-io/plugin-api";var dryRun2={type:"boolean",description:"Print what would change without writing anything"},yes2={type:"boolean",description:"Answer yes to every question this command can ask (trusting a repository, discarding work)"},lockRebuildInputSchema=jsonSchema14({type:"object",properties:{dryRun:{...dryRun2,description:"Print what would change without writing the lockfile"}},additionalProperties:!1}),lockShowInputSchema=jsonSchema14({type:"object",properties:{},additionalProperties:!1}),repoGcInputSchema=jsonSchema14({type:"object",properties:{maxBytes:{type:"integer",description:"The size cap to collect down to, instead of the one this project's config sets"},dryRun:{...dryRun2,description:"Print what would be evicted without removing anything"}},additionalProperties:!1}),repoLinkInputSchema=jsonSchema14({type:"object",properties:{repo:{type:"string",description:"The repository's short name from this project's config, its full URL, or the path of a checkout to link in place"},path:{type:"string",description:"An existing checkout to link. Without it, the repository is cloned."},global:{type:"boolean",description:"Link for every project on this machine, sharing one checkout, rather than for this project"},yes:yes2,dryRun:{...dryRun2,description:"Print what would change without cloning or writing anything"},branch:{type:"string",description:"Switch the checkout to this existing branch, fetching it from upstream first"},createBranch:{type:"string",description:"Create this new branch in the checkout and switch to it"},generateBranch:{type:"boolean",description:"Create a new branch named sous/edit-<date>-<time> in the checkout and switch to it"},from:{type:"string",description:"Start the new branch from this branch instead of the repository's default branch"},latest:{type:"boolean",description:"Make the branch being worked from match upstream's, after listing any local work that would be discarded"}},required:["repo"],additionalProperties:!1}),repoUnlinkInputSchema=jsonSchema14({type:"object",properties:{repo:{type:"string",description:"The repository's short name, as it appears in the links map"},global:{type:"boolean",description:"Remove the machine-wide link rather than this project's link"},update:{type:"boolean",description:"Move this repository's pins to the newest versions their ranges allow before rebuilding"},remove:{type:"boolean",description:"Delete the checkout as well, when sous cloned it"},yes:yes2,dryRun:dryRun2,noBuild:{type:"boolean",description:"Unlink without rebuilding the project"},answer:{type:"array",items:{type:"string"},description:"Answer a recipe question ahead of time: <name>=<value>; repeatable"},answersFile:{type:"string",description:"A file of answers to recipe questions"}},required:["repo"],additionalProperties:!1}),activeRecipeSchema=jsonSchema14({type:"object",properties:{id:{type:"string"},namespace:{type:"string"},name:{type:"string"},repo:{type:"string"},identity:{type:"string"},version:{type:"string"},hash:{type:"string"},kind:{enum:["subscribes","depends"]},requestedBy:{type:"array",items:{type:"string"}},dir:{type:"string"},source:{enum:["store","link","core","project"]},manifest:{type:"object"}},required:["id","namespace","name","repo","identity","version","hash","kind","requestedBy","dir","source","manifest"]});async function registerPartB(sous){let runtime=new PartBRuntime(sous),seeder=new CoreSeeder(runtime);sous.entities.kinds().includes("active-recipe")||sous.entities.define("active-recipe",activeRecipeSchema,{description:"A locked recipe reached from the subscriptions switched on on this machine, its files on disk."}),registerServices(sous,runtime),registerContributors(sous,runtime,seeder),registerIntents(sous,runtime),sous.entities.add("ref-lookup",lockfileLookup()),sous.on("config.built",event=>{let project=sous.project;if(!(project===void 0||!fs44.existsSync(project.sousDir)))try{writeRecipeTypes(project.sousDir,event.payload.config.entities.list("active-recipe"))}catch(error51){sous.reporter.warning(`Sous could not write the recipe plugin types into ${project.sousDir}/types: ${error51 instanceof Error?error51.message:String(error51)}`)}})}function registerServices(sous,runtime){sous.services.add("recipes.lock",(_config,ctx)=>new LockService(ctx,runtime),{lifetime:"config"}),sous.services.add("recipes.resolver",(_config,ctx)=>new ResolverService(ctx,runtime),{lifetime:"config"}),sous.services.add("recipes.links",(_config,ctx)=>new LinksFiles({sousDir:ctx.project?.sousDir,globalFile:runtime.homePaths().links,parser:ctx.services.get("formats.links-map")}),{lifetime:"config"}),sous.services.add("recipes.index-cache",()=>{let core=runtime.indexCore();return installPackagedOverlay(runtime),new IndexCacheService(core,{trusted:()=>trustedRepos2({services:sous.services,config:sous.engine.config}),identity:url2=>runtime.tryIdentity(url2)??url2,freshnessSeconds:()=>sous.engine.config.get("store")?.freshnessSeconds??DEFAULT_FRESHNESS_SECONDS,linkedPath:repo=>{try{return sous.services.get("recipes.links").get(repo)?.path}catch{return}}})},{lifetime:"singleton"}),sous.services.add("compiler.namespace-resolver",(_config,ctx)=>{let resolver=ctx.services.get("refs.resolver"),globs=ctx.services.get("host.globs"),recipesResolver=ctx.services.get("recipes.resolver");return new ActiveNamespaceResolver({recipes:ctx.entities.list("active-recipe"),parse:reference=>resolver.resolveSync({input:reference,from:"include",kinds:["recipeFile"],lookups:!1,refusedIsEmpty:!0}),isMatch:(name,pattern,options)=>globs.isMatch(name,pattern,{nocase:options.nocase,dot:!0}),explainMissing:recipe=>explainMissing(recipe,{subscriptions:ctx.config.get("subscriptions"),keyOf:key=>recipesResolver.keyOf(key),lockfile:()=>ctx.services.get("recipes.lock").read(),cachedIndex:identity2=>runtime.indexCore().readCached(identity2)})})},{lifetime:"config"})}function installPackagedOverlay(runtime){let hash2;try{let identity2=runtime.services.get("host.package").identity(),dir=packagedCoreRecipeDir(identity2.root);if(dir===void 0)return;runtime.indexCore().setOverlayIfNone(coreIndexOverlay({version:identity2.version,hash:()=>{if(hash2===void 0)try{hash2=runtime.services.get("formats.recipe-hash").hashDirectorySync(dir)}catch{hash2=null}return hash2??void 0}}))}catch{}}function registerContributors(sous,runtime,seeder){sous.config.contribute(coreContributor(runtime,seeder)),sous.config.contribute(fetchContributor(runtime)),sous.config.contribute(configLayersContributor(runtime)),sous.config.contribute(pluginsContributor())}function registerIntents(sous,runtime){sous.intents.add({intent:"lock.rebuild",requiresProject:!0,summary:"Rebuild this project's lockfile from its subscriptions and the cached repository indexes",input:lockRebuildInputSchema,changesConfig:!0,cli:{aliases:[["locks","rebuild"]],examples:["sous lock rebuild","sous lock rebuild --dry-run"]},handle:async(input,ctx)=>rebuildLock(input,ctx)}),sous.intents.add({intent:"lock.show",requiresProject:!0,summary:"Show every recipe version this project's lockfile pins",input:lockShowInputSchema,parallel:!0,cli:{aliases:[["locks","show"]],examples:["sous lock show"]},handle:(_input,ctx)=>lockShowOutputs(showLock(ctx))}),sous.intents.add({intent:"repo.gc",requiresProject:!0,summary:"Collect the machine-wide recipe store back down to its size cap",input:repoGcInputSchema,cli:{aliases:[["repos","gc"]],examples:["sous repo gc","sous repo gc --dry-run","sous repo gc --max-bytes 268435456"]},handle:async(input,ctx)=>storeGcOutputs(await collectStore(input,ctx))}),sous.intents.add({intent:"repo.link",requiresProject:!0,summary:"Point a repository at a working copy on this machine instead of a published version",description:"'sous repo link <path>' links the checkout already at that path, where it is, adding the repository to this project first if it has not been added yet. 'sous repo link <name-or-url>' clones the repository into .sous/repos and links that clone. 'sous repo link <name-or-url> <path>' links the checkout at that path to that repository, and clones nothing. A checkout that was already on disk is fetched and compared with upstream; only the branch flags and --latest change it.",input:repoLinkInputSchema,changesConfig:!0,cli:{aliases:[["repos","link"]],positional:["repo","path"],flags:{yes:{short:"y",aliases:["force","trust"]}},examples:["sous repo link ../sous-recipes","sous repo link sous-recipes","sous repo link sous-recipes ~/Projects/sous-recipes","sous repo link https://github.com/sous-io/sous-recipes","sous repo link sous-recipes --global","sous repo link sous-recipes --latest","sous repo link sous-recipes --generate-branch","sous repo link sous-recipes --branch my-change --latest"]},agent:{usage:"Use to edit a repository's recipes in a working copy. Pass yes: true to trust a repository the project does not trust yet."},handle:async(input,ctx)=>linkOutputs(await linkRepo(input,ctx,runtime))}),sous.intents.add({intent:"repo.unlink",requiresProject:!0,summary:"Stop reading a repository from a working copy and go back to its pinned versions",input:repoUnlinkInputSchema,changesConfig:!0,cli:{aliases:[["repos","unlink"]],positional:["repo"],flags:{yes:{short:"y",aliases:["force","trust"]}},examples:["sous repo unlink sous-recipes","sous repo unlink sous-recipes --update","sous repo unlink sous-recipes --remove","sous repo unlink sous-recipes --global"]},handle:async(input,ctx)=>unlinkOutputs(ctx,await unlinkRepo(input,ctx,runtime))})}var package_default12={name:"@sous-io/plugin-recipes",version:"1.0.11",description:"Repositories, trust, subscriptions, the lockfile, the store, the index cache, links, the core recipe, the catalog and recipe plugins.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-compiler":"workspace:*","@sous-io/plugin-confd":"workspace:*","@sous-io/plugin-formats":"workspace:*","@sous-io/plugin-git":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-refs":"workspace:*","@sous-io/plugin-variables":"workspace:*",semver:"^7.8.5"},devDependencies:{"@sous-io/core":"workspace:*","@sous-io/plugin-update":"workspace:*","@types/semver":"^7.8.0",glob:"^13.0.6",yaml:"^2.9.0"},engines:{node:">=22"}};var PLUGIN_NAME11="@sous-io/plugin-recipes",recipesPlugin=definePlugin12({name:PLUGIN_NAME11,version:package_default12.version,description:"Repositories, trust, subscriptions, the lockfile, the store, the index cache, links, the core recipe, the catalog and recipe plugins.",dependsOn:{"@sous-io/plugin-confd":`^${package_default12.version}`,"@sous-io/plugin-formats":`^${package_default12.version}`,"@sous-io/plugin-refs":`^${package_default12.version}`,"@sous-io/plugin-variables":`^${package_default12.version}`,"@sous-io/plugin-git":`^${package_default12.version}`,"@sous-io/plugin-compiler":`^${package_default12.version}`,"@sous-io/plugin-host":`^${package_default12.version}`},async register(sous){await registerPartB(sous),defineEntityKinds(sous),registerPartA(sous)}});import{definePlugin as definePlugin13,jsonSchema as jsonSchema16}from"@sous-io/plugin-api";import path58 from"node:path";import{ConfigError as ConfigError38}from"@sous-io/plugin-api";import path57 from"node:path";function resolveUserPath(file2,base){if(path57.isAbsolute(file2))return file2;let from=base.cwd??base.project?.root;return from===void 0?file2:path57.resolve(from,file2)}var LOCAL_FILE_REPO="local",LOCAL_FILE_NAMESPACE="local";function recipeKey(recipe){return`${recipe.namespace}/${recipe.name}`}function variableKey(recipe,variable){return`${recipeKey(recipe)}.${variable}`}function qualifiedKey(defined){return`${defined.recipe.repo}:${defined.key}`}function variableRefOf(recipe,definition){return{kind:"variable",name:definition.name,description:definition.prompt,recipe:{kind:"recipe",name:recipe.name,namespace:{kind:"namespace",name:recipe.namespace,repo:{kind:"repo",name:recipe.repo}}}}}function defineVariable(recipe,definition,requiredBy){return{definition,recipe,ref:variableRefOf(recipe,definition),key:variableKey(recipe,definition.name),...requiredBy===void 0||requiredBy.length===0?{}:{requiredBy}}}function linkSharedNames(variables){let byName=new Map;for(let entry of variables){let recipes=byName.get(entry.definition.name)??[];recipes.push(entry.recipe),byName.set(entry.definition.name,recipes)}return variables.map(entry=>{let others=(byName.get(entry.definition.name)??[]).filter(recipe=>recipe!==entry.recipe);return others.length===0?entry:defineVariable(entry.recipe,entry.definition,others)})}function definitionsFromRecipes(recipes,repos={}){let defined=[];for(let active of recipes){let url2=repos[active.repo]?.url,recipe={repo:active.repo,namespace:active.namespace,name:active.name,version:active.version,dir:active.dir,identity:active.identity,direct:active.requestedBy.includes("project"),...url2===void 0?{}:{url:url2}};for(let definition of active.manifest.variables??[])defined.push(defineVariable(recipe,definition))}return linkSharedNames(defined)}function pseudoRecipeName(filePath){let slug=path58.basename(filePath).replace(/\.[^.]+$/,"").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");return slug.length===0||!/^[a-z]/.test(slug)?`file-${slug}`:slug}async function loadDefinitionsFile(filePath,reader){let raw2=await reader.readFile(filePath),variables=raw2?.variables;if(raw2===null||typeof raw2!="object"||Array.isArray(raw2)||!Array.isArray(variables)||variables.length===0)throw new ConfigError38(`The variable definitions file at ${filePath} is not valid.`,{details:["variables: must list at least one variable, in the form a recipe manifest uses."]});let recipe={repo:LOCAL_FILE_REPO,namespace:LOCAL_FILE_NAMESPACE,name:pseudoRecipeName(filePath),version:"0.0.0",dir:filePath,direct:!0},problems=[],defined=[];for(let[index,value]of variables.entries()){let checked3=reader.definition.check(value,`${filePath}, variables[${index}]`);if(checked3.issues===void 0)defined.push(defineVariable(recipe,checked3.value));else{let issues=checked3.issues.filter(issue2=>!/^Invalid .*:$/.test(issue2));problems.push(...issues.map(issue2=>placeIssue(issue2,index)))}}if(problems.length>0)throw new ConfigError38(`Invalid variable definitions file at ${filePath}:`,{details:problems});return linkSharedNames(defined)}function placeIssue(issue2,index){let text=issue2.replace(/^\s*-\s*/,"");return/^([\w.[\]]+): /.exec(text)===null?`- variables[${index}]: ${text}`:`- variables[${index}].${text}`}function namesVariable(defined,name){return defined.definition.name===name||defined.key===name||qualifiedKey(defined)===name}var DefinitionsService=class{constructor(ctx){this.ctx=ctx}listSync(){let recipes=this.ctx.entities.kinds().includes("active-recipe")?this.ctx.entities.list("active-recipe"):[];return definitionsFromRecipes(recipes,this.ctx.config.get("repos")??{})}async list(options={}){return options.file===void 0?this.listSync():loadDefinitionsFile(resolveUserPath(options.file,this.ctx),{readFile:file2=>this.ctx.services.get("formats.manifests").readFile(file2),definition:this.ctx.services.get("formats.variable-definition")})}async find(nameOrRef,options={}){return(await this.list(options)).filter(entry=>namesVariable(entry,nameOrRef))}};function answerFor(variable,ladder){let resolved=ladder.resolve(variable);if(resolved!==void 0)return resolved.value;let fallback2=variable.definition.default;return fallback2===void 0?void 0:String(fallback2)}function computeAnswers(variables,ladder){let merged={},byRecipe={},unanswered=[],secrets=new Set;for(let variable of variables){let name=variable.definition.name,value=answerFor(variable,ladder);if(variable.definition.secret&&secrets.add(name),value===void 0){variable.definition.required&&unanswered.push(variable);continue}name in merged||(merged[name]=value);let key=recipeKey(variable.recipe);byRecipe[key]={...byRecipe[key]??{},[name]:value}}return{merged,byRecipe,unanswered,secrets}}function answersForRecipe(answers,key){return{...answers.merged,...answers.byRecipe[key]??{}}}var AnswersService=class{constructor(compute){this.compute=compute}cached;get(){return this.cached??=this.compute(),this.cached}forRecipe(key){return answersForRecipe(this.get(),key)}};import{commandVariables as commandVariables2,ConfigError as ConfigError42,InputError as InputError5,IntentOutput as IntentOutput9,IntentOutputs as IntentOutputs10,jsonSchema as jsonSchema15,ReportEntryStyle as ReportEntryStyle4,TextBlock as TextBlock6}from"@sous-io/plugin-api";import{LogLevel as LogLevel10,NonInteractiveError as NonInteractiveError4}from"@sous-io/plugin-api";import{ConfigError as ConfigError39,InputError as InputError3}from"@sous-io/plugin-api";var VAR_MAPPINGS_FILE="520-var-mappings.jsonc",VAR_MAPPINGS_DESCRIPTION=["Each entry under 'varMappings' binds an environment variable to one recipe","variable, so an answer can be stored under a name of your choosing when the","usual names are taken. The 'sous vars ask' and 'sous vars map' commands write","them; run 'sous vars' to see which name answered what."],TARGET_HELP="A mapping target is written as 'namespace/recipe/variableName', optionally qualified with a repository as 'repo:namespace/recipe/variableName'.",STORED_NAME=/^[a-z][a-z0-9-]*$/,VARIABLE_NAME2=/^[a-z][a-zA-Z0-9]*$/;function parseMappingTarget(input){let fail=problem=>{throw new ConfigError39(`Invalid variable mapping target '${input}': ${problem}`,{details:[TARGET_HELP]})},trimmed=typeof input=="string"?input.trim():"";trimmed.length===0&&fail("a target must not be empty.");let colon=trimmed.indexOf(":"),repo=colon===-1?void 0:trimmed.slice(0,colon),parts=trimmed.slice(colon+1).split("/");(parts.length!==3||parts.some(part=>part.length===0))&&fail("a target names a namespace, a recipe and a variable, joined by slashes.");let[namespace,recipe,variable]=parts,named=[...repo===void 0?[]:[repo],namespace,recipe];for(let name of named)STORED_NAME.test(name)||fail(name.toLowerCase()!==name&&STORED_NAME.test(name.toLowerCase())?`the repository, namespace and recipe in '${trimmed.slice(0,trimmed.lastIndexOf("/"))}' must be lowercase.`:`'${name}' is not a repository, namespace or recipe name: a lowercase letter, then lowercase letters, digits or dashes.`);return VARIABLE_NAME2.test(variable)||fail(`the variable name '${variable}' must be camelCase: a lowercase letter, then letters or digits.`),{...repo===void 0?{}:{repo},namespace,recipe,variable}}function formatMappingTarget(target){return`${target.repo===void 0?"":`${target.repo}:`}${target.namespace}/${target.recipe}/${target.variable}`}function mappingTargetFor(defined){return{repo:defined.recipe.repo,namespace:defined.recipe.namespace,recipe:defined.recipe.name,variable:defined.definition.name}}function mappingMatches(target,defined){return target.repo!==void 0&&target.repo!==defined.recipe.repo?!1:target.namespace===defined.recipe.namespace&&target.recipe===defined.recipe.name&&target.variable===defined.definition.name}function mappedNamesFor(mappings,defined){let names2=[];for(let[envName,target]of Object.entries(mappings))mappingMatches(parseMappingTarget(target),defined)&&names2.push(envName);return names2.sort()}var MappingsService=class{constructor(ctx){this.ctx=ctx}list(){let records=this.ctx.config.get("varMappings")??{},parsed={};for(let[envName,target]of Object.entries(records))parsed[envName]=parseMappingTarget(target);return parsed}parseTarget(text){return parseMappingTarget(text)}formatTarget(target){return formatMappingTarget(target)}async set(envName,target,options={}){this.checkEnvName(envName);let written=formatMappingTarget(parseMappingTarget(formatMappingTarget(target))),result=await this.ctx.services.get("confd.managed").set(VAR_MAPPINGS_FILE,`varMappings.${envName}`,written,{description:VAR_MAPPINGS_DESCRIPTION,...options.dryRun===void 0?{}:{dryRun:options.dryRun}});return{file:result.file,changed:result.changed}}async remove(envName,options={}){this.checkEnvName(envName);let result=await this.ctx.services.get("confd.managed").delete(VAR_MAPPINGS_FILE,`varMappings.${envName}`,{description:VAR_MAPPINGS_DESCRIPTION,...options.dryRun===void 0?{}:{dryRun:options.dryRun}});return{file:result.file,changed:result.changed}}checkEnvName(envName){if(!this.ctx.services.get("variables.names").isEnvName(envName))throw new InputError3("vars.map",[{path:"envName",message:`'${envName}' is not an environment variable name: a letter or underscore, then letters, digits or underscores.`}])}};var RUNG_LABELS2={mapping:"mapping record",recipe:"recipe scope",namespace:"namespace scope",shared:"shared scope",bare:"declared name"},SOURCE_LABELS2={shell:"the shell environment",local:"the .env.local file",shared:"the .env file"},ENV_FILE_NAMES={shared:".env",local:".env.local"};function layersFrom(files,env){let local2={...files?.local??{}},shared={...files?.shared??{}},shell={};for(let[name,value]of Object.entries(env))value===void 0||local2[name]===value||shared[name]===value||(shell[name]=value);return{shell,local:local2,shared}}var Ladder=class{constructor(names2,layers,mappings={}){this.names=names2;this.layers={shell:{...layers.shell},local:{...layers.local},shared:{...layers.shared}},this.mappingRecords={...mappings}}layers;mappingRecords;get mappings(){return this.mappingRecords}namesInFiles(){return new Set([...Object.keys(this.layers.local),...Object.keys(this.layers.shared)])}candidates(variable){let{namespace,name:recipe}=variable.recipe,name=variable.definition.name,ordered2=[...mappedNamesFor(this.mappingRecords,variable).map(envName=>({rung:"mapping",envName})),{rung:"recipe",envName:this.names.recipeScopedName(namespace,recipe,name)},{rung:"namespace",envName:this.names.namespaceScopedName(namespace,name)},{rung:"shared",envName:this.names.sharedName(name)},{rung:"bare",envName:this.names.bareName(variable.definition)}],seen=new Set;return ordered2.filter(candidate=>seen.has(candidate.envName)?!1:(seen.add(candidate.envName),!0))}bareName(variable){return this.names.bareName(variable.definition)}recipeScopedName(variable){return this.names.recipeScopedName(variable.recipe.namespace,variable.recipe.name,variable.definition.name)}lookupIn(file2,envName){return this.layers[file2][envName]}lookup(envName){for(let file2 of["shell","local","shared"]){let value=this.layers[file2][envName];if(value!==void 0)return{value,file:file2}}}resolve(variable){return this.diagnose(variable).resolved}diagnose(variable){let candidates=this.candidates(variable);for(let candidate of candidates){let hit=this.lookup(candidate.envName);if(hit!==void 0)return{resolved:{value:hit.value,source:{...candidate,file:hit.file}},candidates}}return{candidates}}record(file2,envName,value){this.layers[file2][envName]=value}addMapping(envName,target){this.mappingRecords={...this.mappingRecords,[envName]:target}}};function describeSource2(source){return`the ${RUNG_LABELS2[source.rung]} name ${source.envName}, from ${SOURCE_LABELS2[source.file]??source.file}`}function buildLadder(inputs){let files=inputs.services.has("config-files.env")?inputs.services.get("config-files.env").readSync():void 0;return new Ladder(inputs.services.get("variables.names"),layersFrom(files,inputs.env),inputs.config.get("varMappings")??{})}function answerFileFor(definition){return definition.secret||definition.scope==="local"?"local":"shared"}var UNANSWERED_VALUE="(unanswered)";function displayValue(value,secret,hidden){return value===void 0?UNANSWERED_VALUE:secret?hidden:value}function hiddenValue(services){return services.has("variables.secrets")?services.get("variables.secrets").hiddenValue:"(hidden)"}import{Worker}from"node:worker_threads";var DEFAULT_PATTERN_BUDGET_MS=100,STARTUP_GRACE_MS=5e3,STATUS=0,STARTED=1,PENDING=0,MATCHED=1,DID_NOT_MATCH=2,FAILED=3,WORKER_SOURCE=`
919
+ `);return writeIfChanged(path56.join(directory,"index.d.ts"),index)&&written.push("index.d.ts"),{directory,written,removed}}function listDeclarations(directory){try{return fs43.readdirSync(directory,{recursive:!0}).filter(entry=>entry.endsWith(".d.ts"))}catch{return[]}}function writeIfChanged(file2,text){try{if(fs43.readFileSync(file2,"utf8")===text)return!1}catch{}return fs43.mkdirSync(path56.dirname(file2),{recursive:!0}),fs43.writeFileSync(file2,text,"utf8"),!0}var import_semver13=__toESM(require_semver2(),1);import{ConfigError as ConfigError37}from"@sous-io/plugin-api";async function resolveWanted(requests,context){let resolved=new Map,missingRepos=new Map,unreadable2=new Set,cycles=[],parents=new Map,walked=new Map,queue=requests.map(request=>({...request,kind:request.kind??"subscribes",written:request.written??describeWanted(request)}));for(;queue.length>0;){let item=queue.shift();if(item.repo!==void 0&&!Object.hasOwn(context.repos,item.repo)&&item.remote===void 0){recordMissing(missingRepos,{name:item.repo,requiredBy:[{ref:item.written,requestedBy:item.requestedBy}]});continue}if(item.remote!==void 0){let added=repoNamedByIdentity(context.repos,item.remote.identity);if(added===void 0){recordMissing(missingRepos,{name:proposeRepoName2(context.repos,item.remote.identity),url:item.remote.url,identity:item.remote.identity,...item.remote.provider===void 0?{}:{provider:item.remote.provider},requiredBy:[{ref:item.written,requestedBy:item.requestedBy}]});continue}item.repo=added,item.remote.browsed!==void 0&&settleBrowsedItem(item,context.indexes.get(added))}if(item.name===void 0){queue.push(...expandNamespace(item,context));continue}let recipe=resolveRecipe(item,context,resolved);if(resolved.set(recipe.key,recipe),item.requestedBy!==PROJECT_HOLDER&&!parents.has(recipe.key)&&parents.set(recipe.key,item.requestedBy),walked.get(recipe.key)===recipe.version){let cycle=findCycle(recipe.key,item.requestedBy,parents);cycle!==void 0&&cycles.push(cycle);continue}walked.set(recipe.key,recipe.version);let lists=await safeLoad(context,recipe)??recipe.declares;if(lists===void 0){unreadable2.add(recipe.key);continue}for(let[kind,refs]of[["depends",lists.depends],["subscribes",lists.subscribes]])for(let written of refs)queue.push(dependencyRequest(written,recipe,kind,context))}return await keepOnlyReachable(resolved,context),{resolved:sortKeys2(resolved.keys()).map(key=>{let recipe=resolved.get(key);return recipe.requestedBy.sort(),recipe}),missingRepos:[...missingRepos.values()].sort((left,right)=>left.name<right.name?-1:left.name>right.name?1:0),unreadable:sortKeys2(unreadable2),cycles}}async function safeLoad(context,recipe){try{return await context.loadManifest(recipe)}catch{return}}function repoNamedByIdentity(repos,identity2){return Object.entries(repos).find(([,entry])=>entry.identity===identity2)?.[0]}function proposeRepoName2(repos,identity2){let base=identitySegments2(identity2).at(-1)??"repository";if(!Object.hasOwn(repos,base))return base;for(let suffix=2;;suffix+=1)if(!Object.hasOwn(repos,`${base}-${suffix}`))return`${base}-${suffix}`}function indexDependencyLists(version2){if(!(version2===void 0||version2.depends===void 0&&version2.subscribes===void 0))return{depends:version2.depends??[],subscribes:version2.subscribes??[]}}function wantedOf(ref){if(ref.kind==="namespace")return{namespace:ref.name,...repoParts(ref.repo)};if(ref.kind==="recipe"){let repo=ref.namespace?.repo??ref.repo;return ref.namespace===void 0?void 0:{namespace:ref.namespace.name,name:ref.name,...ref.range===void 0?{}:{range:ref.range},...repoParts(repo)}}if(ref.kind==="repo"&&ref.browsed!==void 0)return{namespace:"",...repoParts(ref),browsed:{path:ref.browsed,...ref.range===void 0?{}:{range:ref.range}}}}function repoParts(repo){return{...repo?.name===void 0?{}:{repo:repo.name},...repo?.location===void 0?{}:{location:repo.location}}}function describeWanted(wanted){let key=wanted.name===void 0?wanted.namespace:`${wanted.namespace}/${wanted.name}`;return`${wanted.repo===void 0?"":`${wanted.repo}:`}${key}${wanted.range===void 0?"":`@${wanted.range}`}`}function dependencyRequest(written,parent,kind,context){let reading=settleDependency(written,parent,context),base={requestedBy:parent.key,kind,written:written.trim(),...parent.prerelease?{prerelease:!0}:{}},wanted=reading===void 0?void 0:wantedOf(reading);if(wanted===void 0)throw unsettledDependencyError(written,parent,context);if(wanted.browsed!==void 0&&wanted.location!==void 0)return{namespace:"",...base,remote:{identity:wanted.location.identity,url:wanted.location.url,provider:wanted.location.provider,browsed:wanted.browsed,...parent.dependencies===void 0?{}:{pins:parent.dependencies}}};let key=wanted.name===void 0?void 0:`${wanted.namespace}/${wanted.name}`,pinned=key===void 0?void 0:parent.dependencies?.[key],range3=wanted.name===void 0?void 0:pinned?.version??wanted.range??pinned?.range,target={namespace:wanted.namespace,...wanted.name===void 0?{}:{name:wanted.name},...range3===void 0?{}:{range:range3}};return wanted.location===void 0?{...target,...base,repo:wanted.repo??parent.repo}:{...target,...base,remote:{identity:pinned?.repo??wanted.location.identity,url:wanted.location.url,provider:wanted.location.provider}}}function settleDependency(written,parent,context){let readings=context.parseDependency(written);if(readings.length===1)return readings[0];let confirmed=readings.filter(reading=>isConfirmedByRecord(reading,parent.dependencies));if(confirmed.length===1)return confirmed[0];let known=readings.filter(reading=>knownLocally(reading,context));return known.length===1?known[0]:void 0}function isConfirmedByRecord(candidate,recorded){let wanted=wantedOf(candidate);if(wanted===void 0)return!1;let identity2=wanted.location?.identity,records=Object.entries(recorded??{}).filter(([,record2])=>identity2===void 0?record2?.repo===void 0:record2?.repo===identity2);return wanted.browsed!==void 0?identity2!==void 0&&records.length>0:wanted.name===void 0?records.some(([key])=>key.startsWith(`${wanted.namespace}/`)):records.some(([key])=>key===`${wanted.namespace}/${wanted.name}`)}function knownLocally(reading,context){let wanted=wantedOf(reading);if(wanted?.location===void 0)return!1;let added=repoNamedByIdentity(context.repos,wanted.location.identity),index=added===void 0?void 0:context.indexes.get(added);return index===void 0?!1:wanted.browsed!==void 0?settleBrowsed2(wanted.browsed.path,index).length>0:wanted.name===void 0?Object.hasOwn(index.namespaces,wanted.namespace):Object.hasOwn(index.recipes,`${wanted.namespace}/${wanted.name}`)}function settleBrowsed2(browsed,index){let segments=browsed.split("/").filter(segment=>segment.length>0),recipes=Object.entries(index.recipes).map(([key,recipe])=>({key,path:(recipe.path??"").replace(/^\.?\/+|\/+$/g,"")})).filter(entry=>entry.path.length>0),found=new Map;for(let start2=1;start2<segments.length;start2+=1){let folder=segments.slice(start2).join("/"),deepest=recipes.filter(entry=>folder===entry.path||folder.startsWith(`${entry.path}/`)).sort((left,right)=>right.path.length-left.path.length)[0];deepest!==void 0&&found.set(deepest.key,splitStoredKey(deepest.key))}if(found.size>0)return[...found.values()];for(let start2=1;start2<segments.length;start2+=1){let folder=segments.slice(start2).join("/"),namespaces=new Set(recipes.filter(entry=>entry.path.startsWith(`${folder}/`)).map(entry=>splitStoredKey(entry.key).namespace));if(namespaces.size===1){let[namespace]=namespaces;found.set(namespace,{namespace})}}return[...found.values()]}function settleBrowsedItem(item,index){let remote=item.remote,browsed=remote.browsed,settled=index===void 0?[]:settleBrowsed2(browsed.path,index),found=settled.length===1?settled[0]:void 0;if(found===void 0){let recorded=Object.keys(remote.pins??{}).filter(key2=>remote.pins?.[key2]?.repo===remote.identity);recorded.length===1&&(found=splitStoredKey(recorded[0]))}if(found===void 0)throw new ConfigError37(`The dependency '${item.written}' names a folder, and the index of the repository at ${remote.url} ${settled.length===0?"publishes no recipe there":"publishes several recipes there"}.`,{details:[`It was required by the recipe '${item.requestedBy}'. Write the dependency as the recipe it means, such as '${remote.url}/<namespace>/<recipe>'.`]});let key=found.name===void 0?void 0:`${found.namespace}/${found.name}`,pinned=key===void 0?void 0:remote.pins?.[key];item.namespace=found.namespace,item.name=found.name,item.range=found.name===void 0?void 0:pinned?.version??browsed.range??pinned?.range}function unsettledDependencyError(written,parent,context){let readings=context.parseDependency(written);return new ConfigError37(`The dependency '${written.trim()}' of the recipe '${parent.key}' can be read ${readings.length} ways, and nothing says which one it means.`,{details:[`A release records which one it settled on in the index; the index of '${parent.repo}' records none for this version.`,"Release the recipe again with this version of sous, or write the dependency so it reads one way."]})}function expandNamespace(item,context){let expanded=[],seen=new Set,found=!1;for(let[repoName,index]of context.indexes)if(!(item.repo!==void 0&&repoName!==item.repo||!Object.hasOwn(index.namespaces,item.namespace))){found=!0;for(let key of Object.keys(index.recipes))!key.startsWith(`${item.namespace}/`)||seen.has(key)||(seen.add(key),expanded.push({namespace:item.namespace,name:key.slice(item.namespace.length+1),...item.range===void 0?{}:{range:item.range},...item.repo===void 0?{}:{repo:item.repo},requestedBy:item.requestedBy,kind:item.kind,written:item.written,...item.prerelease===void 0?{}:{prerelease:item.prerelease}}))}if(!found)throw unknownRefError2(item,context,"namespace");return expanded}function resolveRecipe(item,context,resolved){let key=`${item.namespace}/${item.name}`,candidates=[];for(let[repoName,index]of context.indexes)(item.repo===void 0||repoName===item.repo)&&Object.hasOwn(index.recipes,key)&&candidates.push(repoName);if(candidates.length===0)throw unknownRefError2(item,context,"recipe");if(candidates.length>1)throw ambiguousRefError(item,key,candidates);let repo=candidates[0],entry=context.indexes.get(repo).recipes[key],previous=resolved.get(key);if(previous!==void 0&&previous.repo!==repo)throw new ConfigError37(`The recipe '${key}' is being taken from two repositories at once: '${previous.repo}' and '${repo}'.`,{details:["Qualify the refs that ask for it, so each one says which repository it means."]});let ranges=[...previous?.ranges??[]],range3=item.range??"*";ranges.some(known=>known.range===range3&&known.requestedBy===item.requestedBy)||ranges.push({range:range3,requestedBy:item.requestedBy});let prerelease=(previous?.prerelease??!1)||(item.prerelease??context.prerelease??!1),version2=pickVersion(key,entry,ranges,prerelease,context.keep?.[key]),versionEntry=entry.versions[version2],declares=indexDependencyLists(versionEntry),requestedBy=[...previous?.requestedBy??[]];return requestedBy.includes(item.requestedBy)||requestedBy.push(item.requestedBy),{key,namespace:item.namespace,name:item.name,repo,identity:context.repos[repo]?.identity??repo,version:version2,hash:versionEntry.hash,tag:versionEntry.tag,path:entry.path,...versionEntry.dependencies===void 0?{}:{dependencies:versionEntry.dependencies},...versionEntry.variables===void 0?{}:{variables:versionEntry.variables},...declares===void 0?{}:{declares:{depends:[...declares.depends],subscribes:[...declares.subscribes]}},kind:previous?.kind==="subscribes"||item.kind==="subscribes"?"subscribes":"depends",requestedBy,ranges,prerelease}}function pickVersion(key,entry,ranges,prerelease,keep){let published=Object.keys(entry.versions),candidates=prerelease?published:published.filter(version2=>entry.versions[version2].prerelease!==!0);for(let{range:range3}of ranges)candidates=candidates.filter(version2=>import_semver13.default.satisfies(version2,range3,{includePrerelease:prerelease}));if(keep!==void 0&&Object.hasOwn(entry.versions,keep)&&ranges.every(({range:range3})=>import_semver13.default.satisfies(keep,range3,{includePrerelease:!0})))return keep;let best=import_semver13.default.maxSatisfying(candidates,"*",{includePrerelease:prerelease});if(best!==null)return best;let asked=ranges.map(({range:range3,requestedBy})=>` ${range3} (required by ${requestedBy})`),available=[...published].sort((left,right)=>import_semver13.default.rcompare(left,right,{loose:!0})).join(", ");throw new ConfigError37(`No published version of '${key}' satisfies what was asked for.`,{details:[`Version ${ranges.length===1?"range":"ranges"} asked for:`,...asked,`Versions this repository publishes: ${available}.`,...prerelease?[]:["Prerelease versions were not considered. A subscription may opt into them with 'prerelease: true', and 'sous subscribe' with '--prerelease'."]]})}function unknownRefError2(item,context,what){let searched=[...context.indexes.keys()],index=item.repo===void 0?void 0:context.indexes.get(item.repo),details=[searched.length===0?"This project has added no repositories yet.":`Repositories searched: ${searched.join(", ")}.`,...item.requestedBy===PROJECT_HOLDER?[]:[`It was required by the recipe '${item.requestedBy}'.`],...index===void 0?[]:[`The repository '${item.repo}' publishes: ${Object.keys(index.recipes).length===0?"nothing yet":sortKeys2(Object.keys(index.recipes)).join(", ")}.`],"Add the repository that publishes it with 'sous repo add <url>', then try again."];return new ConfigError37(`No added repository publishes the ${what} '${item.written}'.`,{details})}function ambiguousRefError(item,key,repos){let range3=item.range===void 0||item.range==="*"?"":`@${item.range}`;return new ConfigError37(`The ref '${key}' is published by more than one added repository: ${repos.join(", ")}.`,{details:[...item.requestedBy===PROJECT_HOLDER?[]:[`It was required by the recipe '${item.requestedBy}'.`],"Say which repository you mean by qualifying the ref with its name:",...repos.map(repo=>` ${repo}:${key}${range3}`)]})}function recordMissing(into,missing){let existing=into.get(missing.name);if(existing===void 0){into.set(missing.name,missing);return}for(let entry of missing.requiredBy)existing.requiredBy.some(known=>known.ref===entry.ref&&known.requestedBy===entry.requestedBy)||existing.requiredBy.push(entry)}function findCycle(key,from,parents){if(from===PROJECT_HOLDER)return;let chain=[key],guard2=new Set,current=from;for(;current!==void 0&&current!==PROJECT_HOLDER;){if(chain.push(current),current===key)return chain.reverse();if(guard2.has(current))return;guard2.add(current),current=parents.get(current)}}async function keepOnlyReachable(resolved,context){let holders=new Map,declare=(parent,child2,kind)=>{let existing=holders.get(child2);if(existing===void 0)return holders.set(child2,new Map([[parent,kind]])),!0;let previous=existing.get(parent);return existing.set(parent,previous==="subscribes"||kind==="subscribes"?"subscribes":kind),!1},queue=[];for(let recipe of resolved.values())recipe.requestedBy.includes(PROJECT_HOLDER)&&declare(PROJECT_HOLDER,recipe.key,"subscribes")&&queue.push(recipe.key);for(;queue.length>0;){let key=queue.shift(),recipe=resolved.get(key);if(recipe===void 0)continue;let lists=await safeLoad(context,recipe)??recipe.declares;if(lists===void 0){for(let other of resolved.values())other.requestedBy.includes(key)&&declare(key,other.key,other.kind)&&queue.push(other.key);continue}for(let[kind,refs]of[["depends",lists.depends],["subscribes",lists.subscribes]])for(let written of refs)for(let target of dependencyTargets(written,recipe,context,resolved))resolved.has(target)&&declare(key,target,kind)&&queue.push(target)}for(let[key,recipe]of[...resolved]){let reached=holders.get(key);if(reached===void 0){resolved.delete(key);continue}recipe.requestedBy=[...reached.keys()],recipe.ranges=recipe.ranges.filter(entry=>reached.has(entry.requestedBy)),recipe.kind=[...reached.values()].includes("subscribes")?"subscribes":"depends"}}function dependencyTargets(written,holder,context,resolved){let item;try{if(item=dependencyRequest(written,holder,"depends",context),item.remote?.browsed!==void 0){let added=repoNamedByIdentity(context.repos,item.remote.identity);settleBrowsedItem(item,added===void 0?void 0:context.indexes.get(added))}}catch{return[]}return item.name===void 0?[...resolved.keys()].filter(key=>key.startsWith(`${item.namespace}/`)):[`${item.namespace}/${item.name}`]}var ResolverService=class{constructor(ctx,runtime){this.ctx=ctx;this.runtime=runtime}linked=new Map;async resolve(requests,options={}){let trusted=trustedRepos2(this.ctx),repos={};for(let[name,entry]of Object.entries(trusted)){let identity2=this.runtime.tryIdentity(entry.url);identity2!==void 0&&(repos[name]={url:entry.url,identity:identity2,...entry.provider===void 0?{}:{provider:entry.provider}})}let indexes=options.indexes??await this.indexes(Object.keys(repos),options.latest===!0,options.quiet===!0),wanted=[];for(let request of requests){let parts=wantedOf(request.ref);parts!==void 0&&wanted.push({...parts,...request.range!==void 0&&parts.range===void 0?{range:request.range}:{},requestedBy:request.requestedBy,...request.kind===void 0?{}:{kind:request.kind},...request.prerelease===void 0?{}:{prerelease:request.prerelease},written:this.format(request)})}return resolveWanted(wanted,{indexes,repos,loadManifest:recipe=>this.loadManifest(recipe),parseDependency:written=>this.parseDependency(written),...options.prerelease===void 0?{}:{prerelease:options.prerelease},...options.keep===void 0?{}:{keep:options.keep}})}async resolveSubscriptions(options={}){let subscriptions=enabledSubscriptions(this.ctx.config.get("subscriptions")),format3=this.ctx.services.get("refs.format"),requests=sortKeys2(Object.keys(subscriptions)).map(key=>{let entry=subscriptions[key];return{ref:format3.parseNamedRef(key,"config"),...entry.range===void 0?{}:{range:entry.range},...entry.prerelease===!0?{prerelease:!0}:{},requestedBy:PROJECT_HOLDER,kind:"subscribes"}});return this.resolve(requests,options)}reachable(lockfile){return reachability({lockfile,subscriptions:this.ctx.config.get("subscriptions"),repos:this.ctx.config.get("repos"),keyOf:key=>this.keyOf(key)}).reached}keyOf(subscription){try{let format3=this.ctx.services.get("refs.format");return format3.key(format3.parseNamedRef(subscription,"config"))}catch{return plainSubscriptionKey(subscription)}}async indexes(names2,latest2,quiet){let cache2=this.ctx.services.get("recipes.index-cache"),found=new Map;for(let name of sortKeys2(names2))try{let read=await cache2.get(name,{latest:latest2});if(read.source==="stale"&&!quiet){let problem=read.problem;this.runtime.host.reporter.problem(`Sous could not check the repository '${name}' for updates, so it is using the copy of its index that it already had.`,problem===void 0?{}:{cause:problem})}found.set(name,read.index)}catch{let cached2=cache2.cached(name);cached2!==void 0&&found.set(name,cached2.index)}return found}async loadManifest(recipe){let manifests=this.ctx.services.get("formats.manifests"),link=this.ctx.services.get("recipes.links").get(recipe.repo);if(link!==void 0){let map3=this.linked.get(link.path);map3===void 0&&(map3=mapLinkedRecipes(link.path,manifests),this.linked.set(link.path,map3));let found=(await map3).get(recipe.key);if(found!==void 0)return{depends:found.manifest.depends??[],subscribes:found.manifest.subscribes??[]}}let hit=await this.ctx.services.get("recipes.store").get(storeKeyOf2(recipe.key,recipe.identity,recipe.version));if(hit===void 0)return;let manifest=await manifests.readRecipe(hit.dir);return manifest===void 0?void 0:{depends:manifest.manifest.depends??[],subscribes:manifest.manifest.subscribes??[]}}parseDependency(written){try{return this.ctx.services.get("refs.resolver").resolveSync({input:written,from:"manifest",lookups:!1,refusedIsEmpty:!0}).refs}catch{return[]}}format(request){try{return this.ctx.services.get("refs.format").format(request.ref)}catch{return request.ref.name}}};import{nullReporter as nullReporter3}from"@sous-io/plugin-api";var PartBRuntime=class{constructor(host){this.host=host}core;fetched=new Set;noteFetched(keys){for(let key of keys)this.fetched.add(key)}takeFetched(){let keys=[...this.fetched];return this.fetched.clear(),keys}get services(){return this.host.services}get entities(){return this.host.entities}homePaths(){return this.services.get("host.sous-home").paths(this.host.env)}hosts(){return this.entities.list("repository-host")}identity(url2){return this.services.get("refs.locations").identity(url2)}tryIdentity(url2,hosts){try{return this.identity(url2)}catch{}try{let host=hostFor(hosts??this.hosts(),url2);if(host===void 0)return;let canonical=host.canonicalize(url2);return`${canonical.host}/${canonical.owner}/${canonical.name.replace(/\.git$/i,"")}`.split("/").filter(segment=>segment.length>0).map(segment=>segment.toLowerCase()).join("/")}catch{return}}indexCore(){if(this.core===void 0){let paths=this.homePaths();this.core=new IndexCacheCore({directory:paths.indexCache,strategiesFile:paths.readStrategies,parser:this.services.get("formats.index-file"),hosts:()=>this.hosts(),hostContext:()=>this.hostContext()})}return this.core}hostContext(reporter=nullReporter3,signal){return{plugin:RECIPES_PLUGIN,config:this.host.engine.config,services:this.services,entities:this.entities,project:this.host.project,env:this.host.env,cwd:this.host.project?.root??process.cwd(),reporter,...signal===void 0?{}:{signal}}}async emit(name,payload){try{await this.host.emit(name,payload)}catch{}}};import{jsonSchema as jsonSchema14}from"@sous-io/plugin-api";var dryRun2={type:"boolean",description:"Print what would change without writing anything"},yes2={type:"boolean",description:"Answer yes to every question this command can ask (trusting a repository, discarding work)"},lockRebuildInputSchema=jsonSchema14({type:"object",properties:{dryRun:{...dryRun2,description:"Print what would change without writing the lockfile"}},additionalProperties:!1}),lockShowInputSchema=jsonSchema14({type:"object",properties:{},additionalProperties:!1}),repoGcInputSchema=jsonSchema14({type:"object",properties:{maxBytes:{type:"integer",description:"The size cap to collect down to, instead of the one this project's config sets"},dryRun:{...dryRun2,description:"Print what would be evicted without removing anything"}},additionalProperties:!1}),repoLinkInputSchema=jsonSchema14({type:"object",properties:{repo:{type:"string",description:"The repository's short name from this project's config, its full URL, or the path of a checkout to link in place"},path:{type:"string",description:"An existing checkout to link. Without it, the repository is cloned."},global:{type:"boolean",description:"Link for every project on this machine, sharing one checkout, rather than for this project"},yes:yes2,dryRun:{...dryRun2,description:"Print what would change without cloning or writing anything"},branch:{type:"string",description:"Switch the checkout to this existing branch, fetching it from upstream first"},createBranch:{type:"string",description:"Create this new branch in the checkout and switch to it"},generateBranch:{type:"boolean",description:"Create a new branch named sous/edit-<date>-<time> in the checkout and switch to it"},from:{type:"string",description:"Start the new branch from this branch instead of the repository's default branch"},latest:{type:"boolean",description:"Make the branch being worked from match upstream's, after listing any local work that would be discarded"}},required:["repo"],additionalProperties:!1}),repoUnlinkInputSchema=jsonSchema14({type:"object",properties:{repo:{type:"string",description:"The repository's short name, as it appears in the links map"},global:{type:"boolean",description:"Remove the machine-wide link rather than this project's link"},update:{type:"boolean",description:"Move this repository's pins to the newest versions their ranges allow before rebuilding"},remove:{type:"boolean",description:"Delete the checkout as well, when sous cloned it"},yes:yes2,dryRun:dryRun2,noBuild:{type:"boolean",description:"Unlink without rebuilding the project"},answer:{type:"array",items:{type:"string"},description:"Answer a recipe question ahead of time: <name>=<value>; repeatable"},answersFile:{type:"string",description:"A file of answers to recipe questions"}},required:["repo"],additionalProperties:!1}),activeRecipeSchema=jsonSchema14({type:"object",properties:{id:{type:"string"},namespace:{type:"string"},name:{type:"string"},repo:{type:"string"},identity:{type:"string"},version:{type:"string"},hash:{type:"string"},kind:{enum:["subscribes","depends"]},requestedBy:{type:"array",items:{type:"string"}},dir:{type:"string"},source:{enum:["store","link","core","project"]},manifest:{type:"object"}},required:["id","namespace","name","repo","identity","version","hash","kind","requestedBy","dir","source","manifest"]});async function registerPartB(sous){let runtime=new PartBRuntime(sous),seeder=new CoreSeeder(runtime);sous.entities.kinds().includes("active-recipe")||sous.entities.define("active-recipe",activeRecipeSchema,{description:"A locked recipe reached from the subscriptions switched on on this machine, its files on disk."}),registerServices(sous,runtime),registerContributors(sous,runtime,seeder),registerIntents(sous,runtime),sous.entities.add("ref-lookup",lockfileLookup()),sous.on("config.built",event=>{let project=sous.project;if(!(project===void 0||!fs44.existsSync(project.sousDir)))try{writeRecipeTypes(project.sousDir,event.payload.config.entities.list("active-recipe"))}catch(error51){sous.reporter.warning(`Sous could not write the recipe plugin types into ${project.sousDir}/types: ${error51 instanceof Error?error51.message:String(error51)}`)}})}function registerServices(sous,runtime){sous.services.add("recipes.lock",(_config,ctx)=>new LockService(ctx,runtime),{lifetime:"config"}),sous.services.add("recipes.resolver",(_config,ctx)=>new ResolverService(ctx,runtime),{lifetime:"config"}),sous.services.add("recipes.links",(_config,ctx)=>new LinksFiles({sousDir:ctx.project?.sousDir,globalFile:runtime.homePaths().links,parser:ctx.services.get("formats.links-map")}),{lifetime:"config"}),sous.services.add("recipes.index-cache",()=>{let core=runtime.indexCore();return installPackagedOverlay(runtime),new IndexCacheService(core,{trusted:()=>trustedRepos2({services:sous.services,config:sous.engine.config}),identity:url2=>runtime.tryIdentity(url2)??url2,freshnessSeconds:()=>sous.engine.config.get("store")?.freshnessSeconds??DEFAULT_FRESHNESS_SECONDS,linkedPath:repo=>{try{return sous.services.get("recipes.links").get(repo)?.path}catch{return}}})},{lifetime:"singleton"}),sous.services.add("compiler.namespace-resolver",(_config,ctx)=>{let resolver=ctx.services.get("refs.resolver"),globs=ctx.services.get("host.globs"),recipesResolver=ctx.services.get("recipes.resolver");return new ActiveNamespaceResolver({recipes:ctx.entities.list("active-recipe"),parse:reference=>resolver.resolveSync({input:reference,from:"include",kinds:["recipeFile"],lookups:!1,refusedIsEmpty:!0}),isMatch:(name,pattern,options)=>globs.isMatch(name,pattern,{nocase:options.nocase,dot:!0}),explainMissing:recipe=>explainMissing(recipe,{subscriptions:ctx.config.get("subscriptions"),keyOf:key=>recipesResolver.keyOf(key),lockfile:()=>ctx.services.get("recipes.lock").read(),cachedIndex:identity2=>runtime.indexCore().readCached(identity2)})})},{lifetime:"config"})}function installPackagedOverlay(runtime){let hash2;try{let identity2=runtime.services.get("host.package").identity(),dir=packagedCoreRecipeDir(identity2.root);if(dir===void 0)return;runtime.indexCore().setOverlayIfNone(coreIndexOverlay({version:identity2.version,hash:()=>{if(hash2===void 0)try{hash2=runtime.services.get("formats.recipe-hash").hashDirectorySync(dir)}catch{hash2=null}return hash2??void 0}}))}catch{}}function registerContributors(sous,runtime,seeder){sous.config.contribute(coreContributor(runtime,seeder)),sous.config.contribute(fetchContributor(runtime)),sous.config.contribute(configLayersContributor(runtime)),sous.config.contribute(pluginsContributor())}function registerIntents(sous,runtime){sous.intents.add({intent:"lock.rebuild",requiresProject:!0,summary:"Rebuild this project's lockfile from its subscriptions and the cached repository indexes",input:lockRebuildInputSchema,changesConfig:!0,cli:{aliases:[["locks","rebuild"]],examples:["sous lock rebuild","sous lock rebuild --dry-run"]},handle:async(input,ctx)=>rebuildLock(input,ctx)}),sous.intents.add({intent:"lock.show",requiresProject:!0,summary:"Show every recipe version this project's lockfile pins",input:lockShowInputSchema,parallel:!0,cli:{aliases:[["locks","show"]],examples:["sous lock show"]},handle:(_input,ctx)=>lockShowOutputs(showLock(ctx))}),sous.intents.add({intent:"repo.gc",requiresProject:!0,summary:"Collect the machine-wide recipe store back down to its size cap",input:repoGcInputSchema,cli:{aliases:[["repos","gc"]],examples:["sous repo gc","sous repo gc --dry-run","sous repo gc --max-bytes 268435456"]},handle:async(input,ctx)=>storeGcOutputs(await collectStore(input,ctx))}),sous.intents.add({intent:"repo.link",requiresProject:!0,summary:"Point a repository at a working copy on this machine instead of a published version",description:"'sous repo link <path>' links the checkout already at that path, where it is, adding the repository to this project first if it has not been added yet. 'sous repo link <name-or-url>' clones the repository into .sous/repos and links that clone. 'sous repo link <name-or-url> <path>' links the checkout at that path to that repository, and clones nothing. A checkout that was already on disk is fetched and compared with upstream; only the branch flags and --latest change it.",input:repoLinkInputSchema,changesConfig:!0,cli:{aliases:[["repos","link"]],positional:["repo","path"],flags:{yes:{short:"y",aliases:["force","trust"]}},examples:["sous repo link ../sous-recipes","sous repo link sous-recipes","sous repo link sous-recipes ~/Projects/sous-recipes","sous repo link https://github.com/sous-io/sous-recipes","sous repo link sous-recipes --global","sous repo link sous-recipes --latest","sous repo link sous-recipes --generate-branch","sous repo link sous-recipes --branch my-change --latest"]},agent:{usage:"Use to edit a repository's recipes in a working copy. Pass yes: true to trust a repository the project does not trust yet."},handle:async(input,ctx)=>linkOutputs(await linkRepo(input,ctx,runtime))}),sous.intents.add({intent:"repo.unlink",requiresProject:!0,summary:"Stop reading a repository from a working copy and go back to its pinned versions",input:repoUnlinkInputSchema,changesConfig:!0,cli:{aliases:[["repos","unlink"]],positional:["repo"],flags:{yes:{short:"y",aliases:["force","trust"]}},examples:["sous repo unlink sous-recipes","sous repo unlink sous-recipes --update","sous repo unlink sous-recipes --remove","sous repo unlink sous-recipes --global"]},handle:async(input,ctx)=>unlinkOutputs(ctx,await unlinkRepo(input,ctx,runtime))})}var package_default12={name:"@sous-io/plugin-recipes",version:"1.0.12",description:"Repositories, trust, subscriptions, the lockfile, the store, the index cache, links, the core recipe, the catalog and recipe plugins.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-compiler":"workspace:*","@sous-io/plugin-confd":"workspace:*","@sous-io/plugin-formats":"workspace:*","@sous-io/plugin-git":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-refs":"workspace:*","@sous-io/plugin-variables":"workspace:*",semver:"^7.8.5"},devDependencies:{"@sous-io/core":"workspace:*","@sous-io/plugin-update":"workspace:*","@types/semver":"^7.8.0",glob:"^13.0.6",yaml:"^2.9.0"},engines:{node:">=22"}};var PLUGIN_NAME11="@sous-io/plugin-recipes",recipesPlugin=definePlugin12({name:PLUGIN_NAME11,version:package_default12.version,description:"Repositories, trust, subscriptions, the lockfile, the store, the index cache, links, the core recipe, the catalog and recipe plugins.",dependsOn:{"@sous-io/plugin-confd":`^${package_default12.version}`,"@sous-io/plugin-formats":`^${package_default12.version}`,"@sous-io/plugin-refs":`^${package_default12.version}`,"@sous-io/plugin-variables":`^${package_default12.version}`,"@sous-io/plugin-git":`^${package_default12.version}`,"@sous-io/plugin-compiler":`^${package_default12.version}`,"@sous-io/plugin-host":`^${package_default12.version}`},async register(sous){await registerPartB(sous),defineEntityKinds(sous),registerPartA(sous)}});import{definePlugin as definePlugin13,jsonSchema as jsonSchema16}from"@sous-io/plugin-api";import path58 from"node:path";import{ConfigError as ConfigError38}from"@sous-io/plugin-api";import path57 from"node:path";function resolveUserPath(file2,base){if(path57.isAbsolute(file2))return file2;let from=base.cwd??base.project?.root;return from===void 0?file2:path57.resolve(from,file2)}var LOCAL_FILE_REPO="local",LOCAL_FILE_NAMESPACE="local";function recipeKey(recipe){return`${recipe.namespace}/${recipe.name}`}function variableKey(recipe,variable){return`${recipeKey(recipe)}.${variable}`}function qualifiedKey(defined){return`${defined.recipe.repo}:${defined.key}`}function variableRefOf(recipe,definition){return{kind:"variable",name:definition.name,description:definition.prompt,recipe:{kind:"recipe",name:recipe.name,namespace:{kind:"namespace",name:recipe.namespace,repo:{kind:"repo",name:recipe.repo}}}}}function defineVariable(recipe,definition,requiredBy){return{definition,recipe,ref:variableRefOf(recipe,definition),key:variableKey(recipe,definition.name),...requiredBy===void 0||requiredBy.length===0?{}:{requiredBy}}}function linkSharedNames(variables){let byName=new Map;for(let entry of variables){let recipes=byName.get(entry.definition.name)??[];recipes.push(entry.recipe),byName.set(entry.definition.name,recipes)}return variables.map(entry=>{let others=(byName.get(entry.definition.name)??[]).filter(recipe=>recipe!==entry.recipe);return others.length===0?entry:defineVariable(entry.recipe,entry.definition,others)})}function definitionsFromRecipes(recipes,repos={}){let defined=[];for(let active of recipes){let url2=repos[active.repo]?.url,recipe={repo:active.repo,namespace:active.namespace,name:active.name,version:active.version,dir:active.dir,identity:active.identity,direct:active.requestedBy.includes("project"),...url2===void 0?{}:{url:url2}};for(let definition of active.manifest.variables??[])defined.push(defineVariable(recipe,definition))}return linkSharedNames(defined)}function pseudoRecipeName(filePath){let slug=path58.basename(filePath).replace(/\.[^.]+$/,"").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");return slug.length===0||!/^[a-z]/.test(slug)?`file-${slug}`:slug}async function loadDefinitionsFile(filePath,reader){let raw2=await reader.readFile(filePath),variables=raw2?.variables;if(raw2===null||typeof raw2!="object"||Array.isArray(raw2)||!Array.isArray(variables)||variables.length===0)throw new ConfigError38(`The variable definitions file at ${filePath} is not valid.`,{details:["variables: must list at least one variable, in the form a recipe manifest uses."]});let recipe={repo:LOCAL_FILE_REPO,namespace:LOCAL_FILE_NAMESPACE,name:pseudoRecipeName(filePath),version:"0.0.0",dir:filePath,direct:!0},problems=[],defined=[];for(let[index,value]of variables.entries()){let checked3=reader.definition.check(value,`${filePath}, variables[${index}]`);if(checked3.issues===void 0)defined.push(defineVariable(recipe,checked3.value));else{let issues=checked3.issues.filter(issue2=>!/^Invalid .*:$/.test(issue2));problems.push(...issues.map(issue2=>placeIssue(issue2,index)))}}if(problems.length>0)throw new ConfigError38(`Invalid variable definitions file at ${filePath}:`,{details:problems});return linkSharedNames(defined)}function placeIssue(issue2,index){let text=issue2.replace(/^\s*-\s*/,"");return/^([\w.[\]]+): /.exec(text)===null?`- variables[${index}]: ${text}`:`- variables[${index}].${text}`}function namesVariable(defined,name){return defined.definition.name===name||defined.key===name||qualifiedKey(defined)===name}var DefinitionsService=class{constructor(ctx){this.ctx=ctx}listSync(){let recipes=this.ctx.entities.kinds().includes("active-recipe")?this.ctx.entities.list("active-recipe"):[];return definitionsFromRecipes(recipes,this.ctx.config.get("repos")??{})}async list(options={}){return options.file===void 0?this.listSync():loadDefinitionsFile(resolveUserPath(options.file,this.ctx),{readFile:file2=>this.ctx.services.get("formats.manifests").readFile(file2),definition:this.ctx.services.get("formats.variable-definition")})}async find(nameOrRef,options={}){return(await this.list(options)).filter(entry=>namesVariable(entry,nameOrRef))}};function answerFor(variable,ladder){let resolved=ladder.resolve(variable);if(resolved!==void 0)return resolved.value;let fallback2=variable.definition.default;return fallback2===void 0?void 0:String(fallback2)}function computeAnswers(variables,ladder){let merged={},byRecipe={},unanswered=[],secrets=new Set;for(let variable of variables){let name=variable.definition.name,value=answerFor(variable,ladder);if(variable.definition.secret&&secrets.add(name),value===void 0){variable.definition.required&&unanswered.push(variable);continue}name in merged||(merged[name]=value);let key=recipeKey(variable.recipe);byRecipe[key]={...byRecipe[key]??{},[name]:value}}return{merged,byRecipe,unanswered,secrets}}function answersForRecipe(answers,key){return{...answers.merged,...answers.byRecipe[key]??{}}}var AnswersService=class{constructor(compute){this.compute=compute}cached;get(){return this.cached??=this.compute(),this.cached}forRecipe(key){return answersForRecipe(this.get(),key)}};import{commandVariables as commandVariables2,ConfigError as ConfigError42,InputError as InputError5,IntentOutput as IntentOutput9,IntentOutputs as IntentOutputs10,jsonSchema as jsonSchema15,ReportEntryStyle as ReportEntryStyle4,TextBlock as TextBlock6}from"@sous-io/plugin-api";import{LogLevel as LogLevel10,NonInteractiveError as NonInteractiveError4}from"@sous-io/plugin-api";import{ConfigError as ConfigError39,InputError as InputError3}from"@sous-io/plugin-api";var VAR_MAPPINGS_FILE="520-var-mappings.jsonc",VAR_MAPPINGS_DESCRIPTION=["Each entry under 'varMappings' binds an environment variable to one recipe","variable, so an answer can be stored under a name of your choosing when the","usual names are taken. The 'sous vars ask' and 'sous vars map' commands write","them; run 'sous vars' to see which name answered what."],TARGET_HELP="A mapping target is written as 'namespace/recipe/variableName', optionally qualified with a repository as 'repo:namespace/recipe/variableName'.",STORED_NAME=/^[a-z][a-z0-9-]*$/,VARIABLE_NAME2=/^[a-z][a-zA-Z0-9]*$/;function parseMappingTarget(input){let fail=problem=>{throw new ConfigError39(`Invalid variable mapping target '${input}': ${problem}`,{details:[TARGET_HELP]})},trimmed=typeof input=="string"?input.trim():"";trimmed.length===0&&fail("a target must not be empty.");let colon=trimmed.indexOf(":"),repo=colon===-1?void 0:trimmed.slice(0,colon),parts=trimmed.slice(colon+1).split("/");(parts.length!==3||parts.some(part=>part.length===0))&&fail("a target names a namespace, a recipe and a variable, joined by slashes.");let[namespace,recipe,variable]=parts,named=[...repo===void 0?[]:[repo],namespace,recipe];for(let name of named)STORED_NAME.test(name)||fail(name.toLowerCase()!==name&&STORED_NAME.test(name.toLowerCase())?`the repository, namespace and recipe in '${trimmed.slice(0,trimmed.lastIndexOf("/"))}' must be lowercase.`:`'${name}' is not a repository, namespace or recipe name: a lowercase letter, then lowercase letters, digits or dashes.`);return VARIABLE_NAME2.test(variable)||fail(`the variable name '${variable}' must be camelCase: a lowercase letter, then letters or digits.`),{...repo===void 0?{}:{repo},namespace,recipe,variable}}function formatMappingTarget(target){return`${target.repo===void 0?"":`${target.repo}:`}${target.namespace}/${target.recipe}/${target.variable}`}function mappingTargetFor(defined){return{repo:defined.recipe.repo,namespace:defined.recipe.namespace,recipe:defined.recipe.name,variable:defined.definition.name}}function mappingMatches(target,defined){return target.repo!==void 0&&target.repo!==defined.recipe.repo?!1:target.namespace===defined.recipe.namespace&&target.recipe===defined.recipe.name&&target.variable===defined.definition.name}function mappedNamesFor(mappings,defined){let names2=[];for(let[envName,target]of Object.entries(mappings))mappingMatches(parseMappingTarget(target),defined)&&names2.push(envName);return names2.sort()}var MappingsService=class{constructor(ctx){this.ctx=ctx}list(){let records=this.ctx.config.get("varMappings")??{},parsed={};for(let[envName,target]of Object.entries(records))parsed[envName]=parseMappingTarget(target);return parsed}parseTarget(text){return parseMappingTarget(text)}formatTarget(target){return formatMappingTarget(target)}async set(envName,target,options={}){this.checkEnvName(envName);let written=formatMappingTarget(parseMappingTarget(formatMappingTarget(target))),result=await this.ctx.services.get("confd.managed").set(VAR_MAPPINGS_FILE,`varMappings.${envName}`,written,{description:VAR_MAPPINGS_DESCRIPTION,...options.dryRun===void 0?{}:{dryRun:options.dryRun}});return{file:result.file,changed:result.changed}}async remove(envName,options={}){this.checkEnvName(envName);let result=await this.ctx.services.get("confd.managed").delete(VAR_MAPPINGS_FILE,`varMappings.${envName}`,{description:VAR_MAPPINGS_DESCRIPTION,...options.dryRun===void 0?{}:{dryRun:options.dryRun}});return{file:result.file,changed:result.changed}}checkEnvName(envName){if(!this.ctx.services.get("variables.names").isEnvName(envName))throw new InputError3("vars.map",[{path:"envName",message:`'${envName}' is not an environment variable name: a letter or underscore, then letters, digits or underscores.`}])}};var RUNG_LABELS2={mapping:"mapping record",recipe:"recipe scope",namespace:"namespace scope",shared:"shared scope",bare:"declared name"},SOURCE_LABELS2={shell:"the shell environment",local:"the .env.local file",shared:"the .env file"},ENV_FILE_NAMES={shared:".env",local:".env.local"};function layersFrom(files,env){let local2={...files?.local??{}},shared={...files?.shared??{}},shell={};for(let[name,value]of Object.entries(env))value===void 0||local2[name]===value||shared[name]===value||(shell[name]=value);return{shell,local:local2,shared}}var Ladder=class{constructor(names2,layers,mappings={}){this.names=names2;this.layers={shell:{...layers.shell},local:{...layers.local},shared:{...layers.shared}},this.mappingRecords={...mappings}}layers;mappingRecords;get mappings(){return this.mappingRecords}namesInFiles(){return new Set([...Object.keys(this.layers.local),...Object.keys(this.layers.shared)])}candidates(variable){let{namespace,name:recipe}=variable.recipe,name=variable.definition.name,ordered2=[...mappedNamesFor(this.mappingRecords,variable).map(envName=>({rung:"mapping",envName})),{rung:"recipe",envName:this.names.recipeScopedName(namespace,recipe,name)},{rung:"namespace",envName:this.names.namespaceScopedName(namespace,name)},{rung:"shared",envName:this.names.sharedName(name)},{rung:"bare",envName:this.names.bareName(variable.definition)}],seen=new Set;return ordered2.filter(candidate=>seen.has(candidate.envName)?!1:(seen.add(candidate.envName),!0))}bareName(variable){return this.names.bareName(variable.definition)}recipeScopedName(variable){return this.names.recipeScopedName(variable.recipe.namespace,variable.recipe.name,variable.definition.name)}lookupIn(file2,envName){return this.layers[file2][envName]}lookup(envName){for(let file2 of["shell","local","shared"]){let value=this.layers[file2][envName];if(value!==void 0)return{value,file:file2}}}resolve(variable){return this.diagnose(variable).resolved}diagnose(variable){let candidates=this.candidates(variable);for(let candidate of candidates){let hit=this.lookup(candidate.envName);if(hit!==void 0)return{resolved:{value:hit.value,source:{...candidate,file:hit.file}},candidates}}return{candidates}}record(file2,envName,value){this.layers[file2][envName]=value}addMapping(envName,target){this.mappingRecords={...this.mappingRecords,[envName]:target}}};function describeSource2(source){return`the ${RUNG_LABELS2[source.rung]} name ${source.envName}, from ${SOURCE_LABELS2[source.file]??source.file}`}function buildLadder(inputs){let files=inputs.services.has("config-files.env")?inputs.services.get("config-files.env").readSync():void 0;return new Ladder(inputs.services.get("variables.names"),layersFrom(files,inputs.env),inputs.config.get("varMappings")??{})}function answerFileFor(definition){return definition.secret||definition.scope==="local"?"local":"shared"}var UNANSWERED_VALUE="(unanswered)";function displayValue(value,secret,hidden){return value===void 0?UNANSWERED_VALUE:secret?hidden:value}function hiddenValue(services){return services.has("variables.secrets")?services.get("variables.secrets").hiddenValue:"(hidden)"}import{Worker}from"node:worker_threads";var DEFAULT_PATTERN_BUDGET_MS=100,STARTUP_GRACE_MS=5e3,STATUS=0,STARTED=1,PENDING=0,MATCHED=1,DID_NOT_MATCH=2,FAILED=3,WORKER_SOURCE=`
919
920
  const { parentPort } = require("node:worker_threads");
920
921
  parentPort.on("message", (task) => {
921
922
  const slots = new Int32Array(task.shared);
@@ -930,9 +931,9 @@ parentPort.on("message", (task) => {
930
931
  Atomics.store(slots, ${STATUS}, code);
931
932
  Atomics.notify(slots, ${STATUS});
932
933
  });
933
- `,defaultFactory=()=>{let worker2=new Worker(WORKER_SOURCE,{eval:!0});return worker2.unref(),worker2},factory=defaultFactory,worker,workersUnavailable=!1;function disposeMatcherWorker(){let running=worker;if(worker=void 0,running!==void 0)try{running.terminate()}catch{}}function matcher(){if(!workersUnavailable){if(worker!==void 0)return worker;try{worker=factory()}catch{worker=void 0}return worker===void 0&&(workersUnavailable=!0),worker}}function matchWithBudget(pattern,input,budgetMs=DEFAULT_PATTERN_BUDGET_MS){let running=matcher();if(running===void 0)return inProcessMatch(pattern,input);let shared=new SharedArrayBuffer(2*Int32Array.BYTES_PER_ELEMENT),slots=new Int32Array(shared);try{running.postMessage({pattern,input,shared})}catch{return disposeMatcherWorker(),inProcessMatch(pattern,input)}if(!waitForStart(slots))return disposeMatcherWorker(),workersUnavailable=!0,inProcessMatch(pattern,input);switch(Atomics.load(slots,STATUS)===PENDING&&Atomics.wait(slots,STATUS,PENDING,budgetMs),Atomics.load(slots,STATUS)){case MATCHED:return"match";case DID_NOT_MATCH:return"no-match";case FAILED:return inProcessMatch(pattern,input);default:return disposeMatcherWorker(),"timeout"}}function waitForStart(slots){let deadline=Date.now()+STARTUP_GRACE_MS;for(;Atomics.load(slots,STARTED)===0&&Atomics.load(slots,STATUS)===PENDING;){let remaining=deadline-Date.now();if(remaining<=0)return!1;Atomics.wait(slots,STARTED,0,remaining)}return!0}function inProcessMatch(pattern,input){return new RegExp(pattern).test(input)?"match":"no-match"}var TRUE_WORDS=new Set(["true","yes","y","on","1"]),FALSE_WORDS=new Set(["false","no","n","off","0"]);function validateAnswer(definition,raw2,context={}){let trimmed=typeof raw2=="string"?raw2.trim():"";if(trimmed.length===0&&!definition.required)return{ok:!0,value:""};let rules=definition.validate,fail=reason=>({ok:!1,message:`${definition.name} ${reason}.`});switch(definition.type){case"number":{if(trimmed.length===0||!Number.isFinite(Number(trimmed)))return fail("must be a number");let value=Number(trimmed);return rules?.min!==void 0&&value<rules.min?fail(`must be at least ${rules.min}`):rules?.max!==void 0&&value>rules.max?fail(`must be at most ${rules.max}`):{ok:!0,value}}case"boolean":{let word=trimmed.toLowerCase();return!TRUE_WORDS.has(word)&&!FALSE_WORDS.has(word)?fail("must be 'true' or 'false'"):{ok:!0,value:TRUE_WORDS.has(word)}}case"enum":{let options=rules?.enum??[];return runString(trimmed,[value=>options.includes(value)?void 0:`must be one of: ${options.join(", ")}`,...stringChecks()])}case"url":return runString(trimmed,[value=>isUrl(value)?void 0:"must be a URL, including its scheme (for example 'https://example.com')",...stringChecks()]);case"path":return runString(trimmed,[value=>value.includes("\0")?"must be a filesystem path, with no null characters in it":void 0,...stringChecks()]);default:return runString(trimmed,stringChecks())}function runString(value,checks){for(let check3 of checks){let reason=check3(value);if(reason!==void 0)return fail(reason)}return{ok:!0,value}}function stringChecks(){let checks=[];if(definition.required&&checks.push(value=>value.length>0?void 0:"must not be empty"),rules?.minLength!==void 0){let min=rules.minLength;checks.push(value=>value.length>=min?void 0:`must be at least ${min} characters long`)}if(rules?.maxLength!==void 0){let max=rules.maxLength;checks.push(value=>value.length<=max?void 0:`must be at most ${max} characters long`)}if(rules?.pattern!==void 0){let pattern=rules.pattern,budget=context.patternBudgetMs??DEFAULT_PATTERN_BUDGET_MS;checks.push(value=>{let outcome=matchWithBudget(pattern,value,budget);if(outcome!=="match")return outcome==="timeout"?patternTooSlowMessage(pattern,budget,context.recipe):`must match the pattern ${pattern}`})}return checks}}function isUrl(value){try{return new URL(value).protocol.length>1}catch{return!1}}function patternTooSlowMessage(pattern,budgetMs,recipe){let publisher=recipe===void 0?"the recipe that defines it":`the recipe ${recipe}`;return`could not be checked: the pattern ${pattern}, published by ${publisher}, took longer than ${budgetMs} milliseconds to run, so sous stopped waiting for it. The pattern is too slow to run, and the answer was not the problem; this needs to be reported to whoever publishes the recipe`}function characters(count2){return count2===1?"1 character":`${count2} characters`}function constraintBullets(definition){let rules=definition.validate,options=rules?.enum,bullets=definition.type==="enum"&&options!==void 0?[`must be one of: ${options.join(", ")} (type: enum)`]:[`must be a value of the type ${definition.type} (type: ${definition.type})`];return options!==void 0&&definition.type!=="enum"&&bullets.push(`must be one of: ${options.join(", ")} (enum: ${options.join(", ")})`),rules?.minLength!==void 0&&bullets.push(`must be at least ${characters(rules.minLength)} long (minLength: ${rules.minLength})`),rules?.maxLength!==void 0&&bullets.push(`must be at most ${characters(rules.maxLength)} long (maxLength: ${rules.maxLength})`),rules?.min!==void 0&&bullets.push(`must be no less than ${rules.min} (min: ${rules.min})`),rules?.max!==void 0&&bullets.push(`must be no more than ${rules.max} (max: ${rules.max})`),rules?.pattern!==void 0&&bullets.push(`must match the pattern /${rules.pattern}/ (pattern: ${rules.pattern})`),definition.required||bullets.push("an answer is optional"),bullets}var validator={validate:(definition,answer2,options)=>validateAnswer(definition,answer2,options)};var TRUE_WORDS2=["true","yes","y","on","1"];function answerCount(count2){return count2===1?"1 answer":`${count2} answers`}function answeredBy(variable){return`--answer ${variable.definition.name}=<value>`}function askLeadIn(groups){if(groups.length<2)return;let parts=groups.map((group,index)=>{let relation=index===0||group.direct?"":", which it depends on,",needs=index===0?answerCount(group.count):String(group.count);return`${group.key}${relation} needs ${needs}`}),last2=parts.pop();return`${[...parts,`and ${last2}`].join(", ")}.`}function recipeOpeningLine(key,count2){return`${key} needs ${answerCount(count2)} before it can be used.`}function answerComment(variable){return`Set by sous for ${recipeKey(variable.recipe)}: ${variable.definition.prompt}`}function nonInteractiveError(pending){let details=["Set one of the environment variables listed under each variable, pass --answer <name>=<value>, or run 'sous vars ask' from a terminal."];for(let entry of pending){details.push("",`${entry.variable.definition.name} (${recipeKey(entry.variable.recipe)}): ${entry.variable.definition.prompt}`),entry.current!==void 0&&details.push(` The value currently in scope does not fit this variable: ${entry.current}`);for(let candidate of entry.candidates)details.push(` ${candidate.envName} (${RUNG_LABELS2[candidate.rung]})`)}let first2=pending[0],question=pending.length===1?first2.variable.definition.prompt:`${pending.length} questions about recipe variables`,error51=new NonInteractiveError4(question,pending.length===1?answeredBy(first2.variable):"--answer <name>=<value>",{details,exitCode:1});return error51.message=pending.length===1?"One variable still needs an answer, and there is no terminal to ask on.":`${pending.length} variables still need answers, and there is no terminal to ask on.`,error51}function committedFileWarning(variable,file2){let why2=variable.definition.secret?"declared this variable a secret":"declared this variable machine-specific";return`${recipeKey(variable.recipe)} ${why2}, and ${file2} is committed to git. An answer stored there enters your project's git history, is pushed with every clone, and is visible to everyone who can read the repository.`}async function allowedFile(variable,file2,run){if(file2!=="shared"||run.envFile!=="shared"||answerFileFor(variable.definition)!=="local"||run.yes===!0)return!0;let name=ENV_FILE_NAMES.shared;return run.reporter.warning(committedFileWarning(variable,`.sous/${name}`)),run.prompter.confirm({message:`Store this answer in .sous/${name} anyway?`,answeredBy:"--yes",default:!1})}function check2(variable,value){return validateAnswer(variable.definition,value,{recipe:recipeKey(variable.recipe)})}async function storeGivenAnswers(applicable,ladder,run){let stored=[],keys=new Set,written=new Set;for(let entry of applicable){keys.add(entry.target.key);let existing=ladder.resolve(entry.target),fallback2={file:run.envFile??answerFileFor(entry.target.definition),envName:ladder.bareName(entry.target)},plan=run.envFile===void 0&&existing!==void 0&&existing.source.file!=="shell"?{file:existing.source.file,envName:existing.source.envName}:fallback2,slot=`${plan.file}:${plan.envName}`;if(written.has(slot)||(written.add(slot),!await allowedFile(entry.target,plan.file,run)))continue;let outcome=run.dryRun?"not written":ladder.lookupIn(plan.file,plan.envName)===void 0?"appended":"updated";run.dryRun||await run.store.writeAnswer(plan.file,plan.envName,entry.value,answerComment(entry.target)),ladder.record(plan.file,plan.envName,entry.value),stored.push({variable:entry.target,envName:plan.envName,file:plan.file,filePath:run.store.envPath(plan.file),value:displayValue(entry.value,entry.target.definition.secret,run.hidden),outcome,...existing===void 0||existing.value===entry.value?{}:{replaced:displayValue(existing.value,entry.target.definition.secret,run.hidden)},...existing?.source.file==="shell"?{shadowedBy:existing.source.envName}:{}})}return{stored,keys}}async function askForMissing(variables,ladder,options,run){let report={answered:[],inherited:[],skipped:[]},pending=[],questions=[],deferred=[],plannedNames=new Set,named=options.only!==void 0;for(let variable of variables){if(options.only!==void 0&&!options.only.has(variable.key)||options.within!==void 0&&!options.within.has(recipeKey(variable.recipe))||options.skip?.has(variable.key)===!0)continue;let{definition}=variable,diagnosis=ladder.diagnose(variable),existing=diagnosis.resolved,validity=existing===void 0?void 0:check2(variable,existing.value);if(existing!==void 0&&validity?.ok===!0&&options.reask!==!0&&!named){report.inherited.push({variable,resolved:existing});continue}if(existing===void 0&&options.reask!==!0&&!named&&diagnosis.candidates.some(candidate=>plannedNames.has(candidate.envName))){deferred.push(variable);continue}if(!(existing!==void 0&&validity?.ok===!1||existing===void 0&&definition.required||options.reask===!0||named)){report.skipped.push({variable,reason:"no answer yet, and this variable is optional"});continue}if(!run.prompter.interactive){pending.push({variable,candidates:diagnosis.candidates,...validity?.ok===!1?{current:validity.message}:{}});continue}let suggestion=existing!==void 0&&validity?.ok===!0?existing.value:definition.default!==void 0?String(definition.default):void 0;plannedNames.add(ladder.bareName(variable)),questions.push({variable,...suggestion===void 0?{}:{suggestion}})}if(pending.length>0)throw nonInteractiveError(pending);let groups=groupQuestions(questions),leadIn=askLeadIn(groups.map(group=>({key:group.key,count:group.questions.length,direct:group.direct})));leadIn!==void 0&&run.reporter.note(leadIn);for(let group of groups){run.reporter.note(recipeOpeningLine(group.key,group.questions.length));for(let[position,question]of group.questions.entries())await runQuestion(question,{index:position+1,total:group.questions.length},ladder,run,report)}for(let variable of deferred){let resolved=ladder.resolve(variable);if(resolved!==void 0&&check2(variable,resolved.value).ok){report.inherited.push({variable,resolved});continue}run.reporter.note(recipeOpeningLine(recipeKey(variable.recipe),1)),await runQuestion({variable},{index:1,total:1},ladder,run,report)}return report}function groupQuestions(questions){let groups=new Map;for(let question of questions){let key=recipeKey(question.variable.recipe),group=groups.get(key);group===void 0?groups.set(key,{key,direct:question.variable.recipe.direct!==!1,questions:[question]}):group.questions.push(question)}return[...groups.values()]}async function askByType(definition,variable,suggestion,prompter){let by2=answeredBy(variable);if(definition.type==="enum"){let options=definition.validate?.enum??[],index=suggestion===void 0?-1:options.indexOf(suggestion);return prompter.askChoice({message:definition.prompt,answeredBy:by2,choices:options.map(option=>({label:option,value:option})),...index===-1?{}:{defaultIndex:index}})}if(definition.type==="boolean"){let current=suggestion??String(definition.default??"");return String(await prompter.confirm({message:definition.prompt,answeredBy:by2,default:TRUE_WORDS2.includes(current.toLowerCase())}))}return prompter.askValue({message:definition.prompt,answeredBy:by2,validate:value=>{let result=check2(variable,value);return result.ok?void 0:result.message},...suggestion===void 0?{}:{default:suggestion},...definition.secret?{secret:!0}:{}})}async function runQuestion(question,place,ladder,run,report){let{variable}=question,{definition}=variable,plan={file:run.envFile??answerFileFor(definition),envName:ladder.bareName(variable)};if(!await allowedFile(variable,plan.file,run)){report.skipped.push({variable,reason:`not stored in .sous/${ENV_FILE_NAMES.shared}, which is committed to git`});return}run.reporter.question({index:place.index,total:place.total,name:definition.name,...definition.description===void 0?{}:{description:definition.description},...definition.example===void 0?{}:{example:String(definition.example)},recipe:recipeKey(variable.recipe),storedIn:run.store.envPath(plan.file),storedAs:plan.envName});let answer2=await askByType(definition,variable,question.suggestion,run.prompter),checked3=check2(variable,answer2);if(!checked3.ok){report.skipped.push({variable,reason:checked3.message});return}let stored=await storeAnswer(variable,String(checked3.value),plan,ladder,run);report.answered.push(stored),run.reporter.variables([{label:"Answer",value:`${stored.envName}=${stored.value}`},{label:run.dryRun?"Would be saved to":"Saved to",value:stored.filePath}],void 0,LogLevel10.Notice)}async function storeAnswer(variable,value,plan,ladder,run){let envName=plan.envName,mapping,occupant=ladder.lookup(envName);if(occupant!==void 0&&!check2(variable,occupant.value).ok){let scoped=ladder.recipeScopedName(variable),target=formatMappingTarget(mappingTargetFor(variable));(!run.prompter.interactive||await run.prompter.askChoice({message:`${envName} already holds a value that does not fit ${variable.definition.name}. Where should this answer go?`,choices:[{label:`${scoped}, with a mapping record (recommended)`,value:!0},{label:`${envName}, replacing what is there`,value:!1}]}))&&(envName=scoped,mapping={envName:scoped,target,filePath:run.dryRun?run.store.mappingPath():await run.store.writeMapping(scoped,target)},ladder.addMapping(scoped,target))}let outcome=run.dryRun?"not written":ladder.lookupIn(plan.file,envName)===void 0?"appended":"updated";run.dryRun||(await run.store.writeAnswer(plan.file,envName,value,answerComment(variable)),ladder.record(plan.file,envName,value));let winner=ladder.resolve(variable),shadowedBy=winner?.source.file==="shell"&&(winner.source.envName!==envName||winner.value!==value)?winner.source.envName:void 0;return{variable,envName,file:plan.file,filePath:run.store.envPath(plan.file),value:displayValue(value,variable.definition.secret,run.hidden),outcome,...mapping===void 0?{}:{mapping},...shadowedBy===void 0?{}:{shadowedBy}}}import path59 from"node:path";import{ConfigError as ConfigError40}from"@sous-io/plugin-api";var ENV_FILE_CHOICES="The allowed files are .sous/.env (committed, shared with everyone on the project) and .sous/.env.local (gitignored, this machine only).";function resolveEnvFile(value,paths,root,cwd=root){let wanted=new Set([path59.resolve(cwd,value),path59.resolve(root,value),path59.resolve(root,".sous",value)]);for(let kind of["shared","local"])if(wanted.has(path59.resolve(root,paths[kind])))return kind;throw new ConfigError40(`'${value}' is not an env file sous can write answers to. ${ENV_FILE_CHOICES}`)}import path60 from"node:path";import{IntentOutput as IntentOutput8,Table as Table3,VariableSet as VariableSet4}from"@sous-io/plugin-api";function rungLabel(rung){return RUNG_LABELS2[rung]??rung}function sourceLabel(file2){return SOURCE_LABELS2[file2]??file2}function envFileName(file2){return ENV_FILE_NAMES[file2]??file2}function variableKeyOf(variable){return`${recipeKey(variable.recipe)}.${variable.definition.name}`}function isHostedUrl(location){return/^[a-z][a-z0-9+.-]*:\/\//i.test(location)||location.startsWith("git@")}function recipeLocation(recipe){let{url:url2,path:folder,dir}=recipe;if(url2!==void 0&&isHostedUrl(url2)){let base=url2.replace(/\/+$/,"");return folder===void 0?base:`${base}/${folder}`}return url2!==void 0?folder===void 0?url2:`${url2.replace(/\/+$/,"")}/${folder}`:dir}function recipeLink(recipe,label){let location=recipeLocation(recipe);return location===void 0?{label,value:recipeKey(recipe)}:{label,value:recipeKey(recipe),detail:location}}function variableFacts(detail,sousDir){let{variable}=detail,{definition}=variable,entries=[];definition.default!==void 0&&entries.push({label:"default",value:String(definition.default)}),entries.push({label:"example",value:String(definition.example)});let chain=variable.requiredBy!==void 0&&variable.requiredBy.length>0?variable.requiredBy:[variable.recipe];return entries.push(recipeLink(chain[0]??variable.recipe,"required-by")),chain.length>1&&entries.push({label:"",value:`pulled in through ${chain.map(recipeKey).join(" then ")}`}),entries.push(recipeLink(variable.recipe,"defined-by")),entries.push({label:"storage-path",value:sousDir===void 0?envFileName(detail.storeIn):path60.join(sousDir,envFileName(detail.storeIn))}),entries.push({label:"stored-as",value:detail.storedAs}),detail.constraints.forEach((line,index)=>entries.push({label:index===0?"constraints":"",value:line})),entries}var LIST_COLUMNS=[{key:"name",header:"Variable",overflow:"truncate",minWidth:8},{key:"recipe",header:"Recipe",kind:"path",overflow:"truncate",priority:"medium",minWidth:8},{key:"envName",header:"Answered by",overflow:"truncate",truncate:"start",priority:"medium",minWidth:11},{key:"value",header:"Value",overflow:"truncate",truncate:"end",flex:1,minWidth:10},{key:"source",header:"Source",priority:"low"}],LADDER_COLUMNS=[{key:"envName",header:"Environment variable",overflow:"truncate",truncate:"start"},{key:"rung",header:"Rung",priority:"medium"},{key:"status",header:"Status",flex:1,priority:"medium"}];function variableListOutput(listings,hidden){let rows=[...listings].sort((left,right)=>variableKeyOf(left.variable).localeCompare(variableKeyOf(right.variable))).map(listing=>({name:listing.variable.definition.name,recipe:recipeKey(listing.variable.recipe),envName:listing.source?.envName??"",value:displayValue(listing.answered?listing.value??"":void 0,listing.variable.definition.secret,hidden),source:listing.source===void 0?"nothing yet":`${rungLabel(listing.source.rung)}, ${sourceLabel(listing.source.file)}`}));return new IntentOutput8({title:"Variables in play",result:new Table3(LIST_COLUMNS,rows,{empty:"No recipe in this project defines any variables yet. Subscribe to a recipe that publishes some, or read a definitions file with --file."})})}function variableDetailOutputs(detail,hidden,sousDir){let{variable}=detail,{definition}=variable,resolved=detail.diagnosis.resolved,key=recipeKey(variable.recipe),rows=detail.diagnosis.candidates.map(candidate=>({envName:candidate.envName,rung:rungLabel(candidate.rung),status:candidate.envName===resolved?.source.envName?`answered it, from ${sourceLabel(resolved.source.file)}`:"not set"}));return[new IntentOutput8({title:`${definition.name} (${key})`,result:new VariableSet4({Question:definition.prompt,About:definition.description,"For example":String(definition.example),Recipe:`${key} version ${variable.recipe.version} from ${variable.recipe.repo}`,"Stored in":envFileName(detail.storeIn),Value:displayValue(resolved===void 0?void 0:resolved.value,definition.secret,hidden),Answer:resolved===void 0?"nothing in scope answers this variable yet":detail.problem===void 0?"the value in scope fits this definition":`the value in scope does not fit: ${detail.problem}`})}),new IntentOutput8({result:new VariableSet4(variableFacts(detail,sousDir))}),new IntentOutput8({result:new Table3(LADDER_COLUMNS,rows,{title:"Environment variables sous looks at, most specific first"})})]}function answeredEntries(entry,dryRun4,hidden){let secret=entry.variable.definition.secret,note=text=>({label:"",value:text}),entries=[{label:entry.variable.definition.name,value:displayValue(entry.value,secret,hidden),detail:`${entry.envName} in ${envFileName(entry.file)}`}];return entry.mapping!==void 0&&entries.push(note(`mapped to ${entry.mapping.target} in the conf.d layer`)),entry.replaced!==void 0&&entries.push(note(`${dryRun4?"replacing":"replaced"} the answer already there: ${displayValue(entry.replaced,secret,hidden)}`)),entry.shadowedBy!==void 0&&entries.push(note(`${entry.shadowedBy} is set in your shell environment and answers this variable first; unset it for the stored answer to take effect`)),entries}function askReportOutputs(report,hidden){let outputs=[];return report.inherited.length>0&&outputs.push(new IntentOutput8({title:"Answers already in scope",result:new VariableSet4(report.inherited.map(entry=>({label:entry.variable.definition.name,value:displayValue(entry.resolved.value,entry.variable.definition.secret,hidden),detail:`from ${describeSource2(entry.resolved.source)}`})))})),report.answered.length>0&&outputs.push(new IntentOutput8({title:report.dryRun?"Answers that would be stored":"Answers stored",result:new VariableSet4(report.answered.flatMap(entry=>answeredEntries(entry,report.dryRun,hidden)))})),report.skipped.length>0&&outputs.push(new IntentOutput8({title:"Left unanswered",result:new VariableSet4(report.skipped.map(entry=>({label:entry.variable.definition.name,value:entry.reason})))})),outputs.length===0&&outputs.push(new IntentOutput8({summary:"Every variable in play already has an answer that fits its definition."})),outputs}import{readFile as readFile2}from"node:fs/promises";import path61 from"node:path";import{InputError as InputError4}from"@sous-io/plugin-api";var ANSWER_FLAG_FORM="--answer <name>=<value>",ANSWER_NAME_HELP="A name is spelled exactly as the recipe declares it, in camelCase; the full 'namespace/recipe.name' key works too.",INTENT="vars.ask";function answerError(field,lines3){return new InputError4(INTENT,[{path:field,message:lines3[0]??""}],{details:lines3})}function parseAnswerPair(entry,from="--answer"){let at2=entry.indexOf("="),name=at2===-1?"":entry.slice(0,at2).trim();if(at2===-1||name.length===0)throw answerError("answer",[`'${entry}' is not an answer sous can read.`,`Write one as '${ANSWER_FLAG_FORM}', for example '--answer apiUrl=https://api.example.com'.`,"Everything after the first '=' is the answer, so a value may contain more of them."]);return{name,value:entry.slice(at2+1),from}}function isEnvFile(filePath){let base=path61.basename(filePath);return base===".env"||base.startsWith(".env.")||base.endsWith(".env")}function answersFromData(raw2,filePath){if(typeof raw2!="object"||raw2===null||Array.isArray(raw2))throw answerError("answersFile",[`The answers file at ${filePath} is not a map of answers.`,"It holds one entry per variable, written as 'name: value'."]);let answers=[];for(let[name,value]of Object.entries(raw2)){if(typeof value=="object"&&value!==null)throw answerError("answersFile",[`The answer for '${name}' in ${filePath} is a list or a map, and an answer is a single value.`,"Answers are stored in environment files, which hold text; write the answer as a string, a number or a boolean."]);if(value==null)throw answerError("answersFile",[`The answer for '${name}' in ${filePath} is empty.`,"Write the value the variable should be given, or leave the entry out entirely so sous asks for it."]);answers.push({name:name.trim(),value:String(value),from:filePath})}return answers}function collectAnswers(fromFile,flags){let collected=new Map;for(let answer2 of fromFile)collected.set(answer2.name,answer2);for(let entry of flags){let answer2=parseAnswerPair(entry);collected.set(answer2.name,answer2)}return[...collected.values()]}function unknownAnswerError(answer2,variables){let lines3=[`Nothing in this project defines a variable called '${answer2.name}', so the answer given with ${answer2.from} cannot be stored.`];if(variables.length===0)return lines3.push("No recipe this project subscribes to defines any variables yet, so there is nothing to answer."),answerError(answer2.from==="--answer"?"answer":"answersFile",lines3);let groups=new Map;for(let entry of variables){let key=recipeKey(entry.recipe),names2=groups.get(key)??[];names2.includes(entry.definition.name)||names2.push(entry.definition.name),groups.set(key,names2)}lines3.push("","These are the variables in play, and the recipes that declare them:","");for(let[key,names2]of groups)lines3.push(` ${key}`,...names2.map(name=>` ${name}`));return lines3.push("",ANSWER_NAME_HELP),answerError(answer2.from==="--answer"?"answer":"answersFile",lines3)}function invalidAnswerError(answer2,variable,message2,hidden){let shown=variable.definition.secret?hidden:answer2.value;return answerError(answer2.from==="--answer"?"answer":"answersFile",[`The answer given for '${answer2.name}' does not fit the definition ${recipeKey(variable.recipe)} publishes.`,message2,`For example: ${String(variable.definition.example)}`,`The answer given with ${answer2.from} was: ${shown}`,"Nothing was written; fix the answer and run the command again."])}function matchAnswers(answers,variables,hidden="(hidden)"){let applicable=[];for(let answer2 of answers){let targets=variables.filter(entry=>namesVariable(entry,answer2.name));if(targets.length===0)throw unknownAnswerError(answer2,variables);for(let target of targets){let checked3=validateAnswer(target.definition,answer2.value,{recipe:recipeKey(target.recipe)});if(!checked3.ok)throw invalidAnswerError(answer2,target,checked3.message,hidden);applicable.push({answer:answer2,target,value:String(checked3.value)})}}return applicable}var PreanswersService=class{constructor(ctx){this.ctx=ctx}async read(inputs){let fromFile=inputs.answersFile===void 0?[]:await this.readFile(resolveUserPath(inputs.answersFile,this.ctx));return collectAnswers(fromFile,inputs.answer??[])}match(answers,variables){let secrets=this.ctx.services.has("variables.secrets")?this.ctx.services.get("variables.secrets"):void 0;return matchAnswers(answers,variables,secrets?.hiddenValue)}async readFile(filePath){if(isEnvFile(filePath)){let text;try{text=await readFile2(filePath,"utf8")}catch(error51){throw answerError("answersFile",[`Could not read the answers file at ${filePath}: ${error51.message}`])}return answersFromData(this.ctx.services.get("config-files.env").parse(text),filePath)}return answersFromData(await this.ctx.services.get("formats.manifests").readFile(filePath),filePath)}};import{ConfigError as ConfigError41,isSousErrorOfKind as isSousErrorOfKind4,NonInteractiveError as NonInteractiveError5}from"@sous-io/plugin-api";var GLOB_CHARS2=/[*?[\]{}]/;function globToRegExp(pattern,ignoreCase){let source="",braces=0;for(let index=0;index<pattern.length;index+=1){let character=pattern[index];if(character==="*")source+=".*";else if(character==="?")source+=".";else if(character==="["){let end=pattern.indexOf("]",index+1);if(end===-1)source+="\\[";else{let body2=pattern.slice(index+1,end).replace(/^!/,"^").replace(/\\/g,"\\\\");source+=`[${body2}]`,index=end}}else character==="{"?(braces+=1,source+="(?:"):character==="}"&&braces>0?(braces-=1,source+=")"):character===","&&braces>0?source+="|":source+=character.replace(/[.+^$()|\\]/g,"\\$&")}return new RegExp(`^${source}$`,ignoreCase?"i":"")}function matchName(written,known){return GLOB_CHARS2.test(written)?globToRegExp(written,!1).test(known)?"exact":globToRegExp(written,!0).test(known)?"folded":void 0:written===known?"exact":written.toLowerCase()===known.toLowerCase()?"folded":void 0}function both2(left,right){if(!(left===void 0||right===void 0))return left==="folded"||right==="folded"?"folded":"exact"}function qualifies2(qualifier,variable){if(qualifier===void 0)return"exact";let result="exact";if(qualifier.name!==void 0&&(result=matchName(qualifier.name,variable.recipe.repo)),!(qualifier.location!==void 0&&qualifier.location.identity!==variable.recipe.identity))return result}function repoRef(variable){return{kind:"repo",name:variable.recipe.repo}}function namespaceRef2(variable){return{kind:"namespace",name:variable.recipe.namespace,repo:repoRef(variable)}}function recipeRef2(variable){return{kind:"recipe",name:variable.recipe.name,namespace:namespaceRef2(variable)}}function keyOf(ref){switch(ref.kind){case"repo":return`repo ${ref.name??""}`;case"namespace":return`namespace ${ref.repo?.name??""}:${ref.name}`;case"recipe":return`recipe ${ref.namespace?.repo?.name??""}:${ref.namespace?.name??""}/${ref.name}`;case"variable":return`variable ${ref.recipe?.namespace?.repo?.name??""}:${ref.recipe?.namespace?.name??""}/${ref.recipe?.name??""}.${ref.name}`;default:return`${ref.kind} ${"name"in ref?String(ref.name):""}`}}function carry2(candidate,known){return candidate.vars===void 0?known:{...known,vars:candidate.vars}}function envNamesOf(variable,ladder){let inUse=ladder.namesInFiles(),names2=new Set([ladder.bareName(variable)]);for(let candidate of ladder.candidates(variable))inUse.has(candidate.envName)&&names2.add(candidate.envName);return names2}function matchVariables(pool,candidate,ladder){let found=new Map,add=(ref,spelling)=>{if(spelling===void 0)return;let key=keyOf(ref),known=found.get(key);(known===void 0||!known.exactSpelling&&spelling==="exact")&&found.set(key,{ref,exactSpelling:spelling==="exact"})};if(candidate.kind==="envVar"){if(ladder===void 0)return[];let variables=pool.filter(entry=>envNamesOf(entry,ladder).has(candidate.name)).map(entry=>entry.ref);return variables.length===0?[]:[{ref:carry2(candidate,{kind:"envVar",name:candidate.name,variables}),exactSpelling:!0}]}for(let variable of pool)switch(candidate.kind){case"repo":(candidate.name!==void 0||candidate.location!==void 0)&&add(carry2(candidate,repoRef(variable)),qualifies2(candidate,variable));break;case"namespace":add(carry2(candidate,namespaceRef2(variable)),both2(qualifies2(candidate.repo,variable),matchName(candidate.name,variable.recipe.namespace)));break;case"recipe":{let inNamespace=candidate.namespace===void 0?"exact":matchName(candidate.namespace.name,variable.recipe.namespace),spelling=both2(both2(qualifies2(candidate.namespace?.repo??candidate.repo,variable),inNamespace),matchName(candidate.name,variable.recipe.name));add(carry2(candidate,{...recipeRef2(variable),...candidate.range===void 0?{}:{range:candidate.range}}),spelling);break}case"variable":{let spelling=qualifies2(candidate.recipe?.namespace?.repo??candidate.recipe?.repo??candidate.repo,variable);candidate.recipe!==void 0&&(spelling=both2(spelling,matchName(candidate.recipe.name,variable.recipe.name)),candidate.recipe.namespace!==void 0&&(spelling=both2(spelling,matchName(candidate.recipe.namespace.name,variable.recipe.namespace)))),add(carry2(candidate,variable.ref),both2(spelling,matchName(candidate.name,variable.definition.name)));break}default:break}return[...found.values()].sort((left,right)=>keyOf(left.ref)<keyOf(right.ref)?-1:keyOf(left.ref)>keyOf(right.ref)?1:0)}function partsOf(ref){switch(ref.kind){case"repo":return{...ref.name===void 0?{}:{repo:ref.name}};case"namespace":return{...ref.repo?.name===void 0?{}:{repo:ref.repo.name},namespace:ref.name};case"recipe":{let repo=ref.namespace?.repo?.name??ref.repo?.name;return{...repo===void 0?{}:{repo},...ref.namespace===void 0?{}:{namespace:ref.namespace.name},recipe:ref.name}}case"variable":return ref.recipe===void 0?{...ref.repo?.name===void 0?{}:{repo:ref.repo.name}}:partsOf(ref.recipe);default:return{}}}function narrowTo(pool,match2){let target=match2.kind==="envVar"?match2.variables?.[0]:match2;if(target===void 0||target.kind==="recipeFile")return[];let{repo,namespace,recipe}=partsOf(target);return pool.filter(entry=>repo!==void 0&&entry.recipe.repo!==repo?!1:target.kind==="repo"?!0:namespace!==void 0&&entry.recipe.namespace!==namespace?!1:target.kind==="namespace"?!0:recipe!==void 0&&entry.recipe.name!==recipe?!1:target.kind==="recipe"?!0:entry.definition.name===target.name)}var SEE_ALL="Run 'sous vars' to see every variable this project's recipes define.";function describeSelection(input){let parts=[];input.repo!==void 0&&parts.push(`the repository '${input.repo}'`),input.namespace!==void 0&&parts.push(`the namespace '${input.namespace}'`),input.recipe!==void 0&&parts.push(`the recipe '${input.recipe}'`),input.name!==void 0&&parts.push(`'${input.name}'`);for(let wanted of input.var??[])parts.push(`the variable '${wanted}'`);return parts.length===0?input.all===!0?"every variable":"everything unanswered":parts.join(", ")}async function resolveSelection(pool,ladder,input,io){let{name,repo,namespace,recipe}=input,vars=input.var;if(name===void 0&&repo===void 0&&namespace===void 0&&recipe===void 0&&vars===void 0)return;let left=[...pool],pick3=(search2,kinds)=>pickOne(search2,left,ladder,kinds,input.acceptFirst===!0,io);if(repo!==void 0&&(left=narrowTo(left,await pick3(repo,["repo"]))),namespace!==void 0&&(left=narrowTo(left,await pick3(namespace,["namespace"]))),recipe!==void 0){let exact=left.filter(entry=>recipeKey(entry.recipe)===recipe);left=exact.length>0?exact:narrowTo(left,await pick3(recipe,["recipe"]))}if(name!==void 0&&(left=narrowTo(left,await pick3(name))),vars!==void 0){let chosen=[];for(let wanted of vars)chosen.push(...narrowTo(left,await pick3(wanted,["variable","envVar"])));left=chosen}if(left.length===0)throw new ConfigError41(`Nothing is left to ask: ${describeSelection({...input,all:!1})} names no variable this project holds.`,{details:[SEE_ALL]});return new Set(left.map(entry=>entry.key))}function candidatesFor(search2,pool,ladder,kinds,services){let readings;try{readings=services.get("refs.resolver").parse(search2,"commandLine").refs}catch{readings=[]}let found=new Map;for(let reading of readings)if(!(kinds!==void 0&&!kinds.includes(reading.kind)))for(let match2 of matchVariables(pool,reading,ladder)){let key=`${match2.ref.kind} ${JSON.stringify(match2.ref)}`;found.has(key)||found.set(key,{ref:match2.ref,exact:match2.exactSpelling})}let all=[...found.values()];return(all.some(entry=>entry.exact)?all.filter(entry=>entry.exact):all).flatMap(({ref})=>ref.kind==="envVar"&&(ref.variables?.length??0)>1?ref.variables.map(variable=>({...ref,variables:[variable]})):[ref])}async function pickOne(search2,pool,ladder,kinds,acceptFirst2,io){let candidates=candidatesFor(search2,pool,ladder,kinds,io.services);if(candidates.length===0)throw new ConfigError41(`Nothing called '${search2}' was found.`,{details:[SEE_ALL]});if(candidates.length===1)return candidates[0];try{return await io.services.get("refs.picker").pick(candidates,{search:search2,acceptFirst:acceptFirst2,announce:!1,details:[SEE_ALL]},io)}catch(error51){throw isSousErrorOfKind4(error51,"non-interactive")?ambiguityError(search2,error51):error51}}function ambiguityError(search2,cause){let error51=new NonInteractiveError5(cause.question,cause.answeredBy,{cause,details:cause.details,exitCode:1});return error51.message=`Sous has to ask which '${search2}' you meant, and it is not running where it can ask.`,error51}var FILE_FIELD={type:"string",description:"Read the variable definitions from a standalone definitions file instead of the project's recipes"};function definitionsLabel(file2){return file2??"the project's subscribed recipes"}function ladderFor(ctx){return buildLadder({services:ctx.services,env:ctx.env,config:ctx.config})}function listingOf(variable,ladder,hidden){let resolved=ladder.resolve(variable);return{variable,answered:resolved!==void 0,...resolved===void 0?{}:{value:displayValue(resolved.value,variable.definition.secret,hidden),source:resolved.source},storedAs:resolved?.source.envName??ladder.bareName(variable),storeIn:answerFileFor(variable.definition)}}function detailOf(variable,ladder,hidden){let diagnosis=ladder.diagnose(variable),checked3=diagnosis.resolved===void 0?void 0:validateAnswer(variable.definition,diagnosis.resolved.value,{recipe:recipeKey(variable.recipe)}),mapping=diagnosis.resolved?.source.rung==="mapping"?diagnosis.resolved.source.envName:void 0,shownDiagnosis=diagnosis.resolved===void 0||!variable.definition.secret?diagnosis:{...diagnosis,resolved:{...diagnosis.resolved,value:hidden}};return{...listingOf(variable,ladder,hidden),diagnosis:shownDiagnosis,constraints:constraintBullets(variable.definition),...checked3?.ok===!1?{problem:checked3.message}:{},...mapping===void 0?{}:{mapping:{envName:mapping,target:ladder.mappings[mapping]??""}}}}function variablesNamed(variables,name){let matches=variables.filter(entry=>namesVariable(entry,name));if(matches.length===0)throw new ConfigError42(`No variable named '${name}' is in play.`,{details:["Run 'sous vars list' to see every variable this project's recipes define."]});return matches}function storeFor(ctx){let env=ctx.services.get("config-files.env");return{envPath:file2=>env.paths()?.[file2]??(file2==="local"?".sous/.env.local":".sous/.env"),mappingPath:()=>ctx.services.get("confd.managed").path(VAR_MAPPINGS_FILE),writeAnswer:async(file2,envName,value,comment)=>{await env.write(file2,{[envName]:value},{comment})},writeMapping:async(envName,target)=>{let mappings=ctx.services.get("recipe-answers.mappings");return(await mappings.set(envName,mappings.parseTarget(target))).file}}}async function handleAsk(input,ctx){let dryRun4=input.dryRun===!0,hidden=hiddenValue(ctx.services),store2=storeFor(ctx),root=ctx.project?.root??ctx.cwd??".",envFile=input.envFile===void 0?void 0:resolveEnvFile(input.envFile,{shared:store2.envPath("shared"),local:store2.envPath("local")},root,ctx.cwd??root);ctx.reporter.variables([{label:"Definitions",value:definitionsLabel(input.file)},{label:"Asking",value:describeSelection(input)},...envFile===void 0?[]:[{label:"Env file",value:store2.envPath(envFile)}]]),dryRun4&&ctx.reporter.dryRun("No answers will be written.");let preanswers=ctx.services.get("recipe-answers.preanswers"),provided=await preanswers.read(input.answersFile===void 0?input:{...input,answersFile:resolveUserPath(input.answersFile,ctx)}),variables=await ctx.services.get("recipe-answers.definitions").list(input.file===void 0?{}:{file:resolveUserPath(input.file,ctx)});if(variables.length===0){if(provided[0]!==void 0)throw unknownAnswerError(provided[0],variables);let empty={answered:[],inherited:[],skipped:[],dryRun:dryRun4};return new IntentOutputs10([new IntentOutput9({title:"Answering variables"}),new IntentOutput9({result:new TextBlock6("No recipe in this project defines any variables yet, so there is nothing to ask. Subscribe to a recipe that publishes some, or read a definitions file with --file."),style:ReportEntryStyle4.Note})]).withData(empty)}let ladder=ladderFor(ctx),only=await resolveSelection(variables,ladder,input,ctx),run={prompter:ctx.prompter,reporter:ctx.reporter,store:store2,hidden,dryRun:dryRun4,...envFile===void 0?{}:{envFile},yes:input.yes===!0},given=await storeGivenAnswers(preanswers.match(provided,variables),ladder,run),report=await askForMissing(variables,ladder,{...only===void 0?{}:{only},...input.within===void 0?{}:{within:new Set(input.within)},skip:given.keys,reask:input.all===!0},run),result={answered:[...given.stored,...report.answered],inherited:report.inherited.map(({variable,resolved})=>({variable,resolved:variable.definition.secret?{...resolved,value:hidden}:resolved})),skipped:report.skipped,dryRun:dryRun4};!dryRun4&&result.answered.some(entry=>entry.outcome!=="not written")&&ctx.configChanged();let entries=result.answered.length>0||result.inherited.length>0||result.skipped.length>0?askReportOutputs(result,hidden):[];return new IntentOutputs10([new IntentOutput9({title:"Answering variables"}),...entries]).withData(result)}async function handleList(input,ctx){let variables=await ctx.services.get("recipe-answers.definitions").list(input.file===void 0?{}:{file:resolveUserPath(input.file,ctx)}),ladder=ladderFor(ctx),hidden=hiddenValue(ctx.services),opening=commandVariables2(ctx,{Definitions:definitionsLabel(input.file)});if(input.name!==void 0){let details=variablesNamed(variables,input.name).map(variable=>detailOf(variable,ladder,hidden)),shown=details.flatMap(detail=>variableDetailOutputs(detail,hidden,ctx.project?.sousDir));return new IntentOutputs10([opening,...shown]).withData({variables:details})}let listings=variables.map(variable=>listingOf(variable,ladder,hidden));return new IntentOutputs10([opening,variableListOutput(listings,hidden)]).withData({variables:listings})}async function handleShow(input,ctx){let variables=await ctx.services.get("recipe-answers.definitions").list(input.file===void 0?{}:{file:resolveUserPath(input.file,ctx)}),matches=variablesNamed(variables,input.name),ladder=ladderFor(ctx),hidden=hiddenValue(ctx.services),opening=commandVariables2(ctx,{Definitions:definitionsLabel(input.file)}),outputsOf2=variable=>{let detail=detailOf(variable,ladder,hidden);return new IntentOutputs10([opening,...variableDetailOutputs(detail,hidden,ctx.project?.sousDir)]).withData(detail)};if(matches.length===1)return outputsOf2(matches[0]);let picked=await ctx.services.get("refs.picker").pick(matches.map(entry=>entry.ref),{search:input.name,acceptFirst:input.acceptFirst===!0,announce:!1,details:[SEE_ALL]},ctx),chosen=matches.find(entry=>entry.ref===picked)??matches.find(entry=>JSON.stringify(entry.ref)===JSON.stringify(picked))??matches[0];return outputsOf2(chosen)}async function handleMap(input,ctx){let mappings=ctx.services.get("recipe-answers.mappings"),dryRun4=input.dryRun===!0;if(input.remove===!0){let{file:file3,changed:changed2}=await mappings.remove(input.envName,{dryRun:dryRun4});changed2&&!dryRun4&&ctx.configChanged();let removal=changed2?`${dryRun4?"Would remove":"Removed"} the mapping of ${input.envName} in ${file3}.`:`${input.envName} has no mapping in ${file3}.`;return IntentOutputs10.of({envName:input.envName,file:file3,changed:changed2,dryRun:dryRun4},{summary:removal})}if(input.target===void 0)throw new InputError5("vars.map",[{path:"target",message:"Name the variable to bind, as 'namespace/recipe/variableName', or pass --remove."}]);let target=mappings.formatTarget(mappings.parseTarget(input.target)),{file:file2,changed}=await mappings.set(input.envName,mappings.parseTarget(target),{dryRun:dryRun4});return changed&&!dryRun4&&ctx.configChanged(),IntentOutputs10.of({envName:input.envName,target,file:file2,changed,dryRun:dryRun4},{summary:changed?`${dryRun4?"Would map":"Mapped"} ${input.envName} to ${target} in ${file2}.`:`${input.envName} is already mapped to ${target}.`})}var varsIntents=[{intent:"vars.ask",summary:"Answer the variables this project's recipes define, storing the answers in the .sous env files",description:"Asks only what is unanswered or no longer fits; --all asks everything again. The name may be a variable, an environment variable name, a recipe, a namespace or a repository. Every question can be answered ahead of time with --answer <name>=<value> or --answers-file.",input:jsonSchema15({type:"object",properties:{name:{type:"string",description:"What to ask about: a variable, an environment variable name, a recipe, a namespace or a repository"},all:{type:"boolean",default:!1,description:"Ask every variable again, including the ones already answered"},repo:{type:"string",description:"Ask only the variables published by this repository"},namespace:{type:"string",description:"Ask only the variables published in this namespace"},recipe:{type:"string",description:"Ask only the variables published by this recipe (namespace/recipe)"},var:{type:"array",items:{type:"string"},description:"Ask only this variable. Repeat it for each variable"},within:{type:"array",items:{type:"string"},description:"Ask only what the recipes named here (namespace/recipe) still need"},acceptFirst:{type:"boolean",default:!1,description:"When a name matches several things, take the first one listed"},file:FILE_FIELD,dryRun:{type:"boolean",default:!1,description:"Report what would be asked and written, without writing anything"},answer:{type:"array",items:{type:"string"},description:"Answer a variable ahead of its question, as <name>=<value>. Repeat it for each answer"},answersFile:{type:"string",description:"Read answers from a YAML, JSON or .env file of name: value pairs"},envFile:{type:"string",description:"Write every answer of this run to this env file: .sous/.env (committed) or .sous/.env.local (this machine only)"},yes:{type:"boolean",default:!1,description:"Answer yes to storing a secret or machine-specific answer in the committed .sous/.env"}},additionalProperties:!1}),cli:{command:["vars","ask"],aliases:[["var","ask"]],positional:["name"],examples:["sous vars ask","sous vars ask apiUrl","sous vars ask SOUS_VAR_API_URL","sous vars ask workflow/task-files","sous vars ask workflow --accept-first","sous vars ask --namespace workflow --var apiUrl","sous vars ask --all","sous vars ask --file ./questions.yaml","sous vars ask --answer apiUrl=https://api.example.com","sous vars ask --answers-file ./answers.yaml","sous vars ask --env-file .env.local"],flags:{within:{hidden:!0},yes:{short:"y",aliases:["force"]}}},agent:{usage:"Pass every answer with `answer` (name=value pairs) or `answersFile`; questions cannot be asked through MCP unless the client supports elicitation."},requiresProject:!0,handle:handleAsk},{intent:"vars.list",summary:"List every variable this project's recipes define, with its answer",input:jsonSchema15({type:"object",properties:{name:{type:"string",description:"A variable's name (or its namespace/recipe.name key) to show in full"},file:FILE_FIELD},additionalProperties:!1}),parallel:!0,cli:{command:["vars","list"],aliases:[["var","list"],["vars"]],positional:["name"],examples:["sous vars","sous vars apiUrl","sous vars list","sous vars list --file ./questions.yaml"]},requiresProject:!0,handle:handleList},{intent:"vars.show",summary:"Show everything about one variable, including how it was answered",input:jsonSchema15({type:"object",properties:{name:{type:"string",description:"A variable's name, or its namespace/recipe.name key"},file:FILE_FIELD,acceptFirst:{type:"boolean",default:!1,description:"When the name matches several variables, take the first one listed"}},required:["name"],additionalProperties:!1}),parallel:!0,cli:{command:["vars","show"],aliases:[["var","show"]],positional:["name"],examples:["sous vars show apiUrl","sous vars show workflow/task-files.apiUrl"]},requiresProject:!0,handle:handleShow},{intent:"vars.map",summary:"Bind an environment variable to one recipe variable, in conf.d/520-var-mappings.jsonc",input:jsonSchema15({type:"object",properties:{envName:{type:"string",description:"The environment variable name, in upper snake case"},target:{type:"string",description:"The variable it answers: namespace/recipe/variableName, optionally repo:-qualified"},remove:{type:"boolean",default:!1,description:"Remove the mapping instead"},dryRun:{type:"boolean",default:!1,description:"Report what would change, without writing anything"}},required:["envName"],additionalProperties:!1}),changesConfig:!0,cli:{command:["vars","map"],aliases:[["var","map"]],positional:["envName","target"],examples:["sous vars map TEAM_API_URL sous-recipes:misc/stuff/apiUrl","sous vars map TEAM_API_URL --remove"]},requiresProject:!0,handle:handleMap}];var VARIABLES_TAG="variables",variableLookup={id:"recipe-answers.variables",description:"the variables the active recipes define",kinds:["repo","namespace","recipe","variable"],tags:[VARIABLES_TAG],optIn:!0,find:async(candidate,ctx)=>variableLookup.findSync(candidate,ctx),findSync:(candidate,ctx)=>matchVariables(ctx.services.get("recipe-answers.definitions").listSync(),candidate)},envVarLookup={id:"recipe-answers.env-vars",description:"the environment variable names that answer recipe variables",kinds:["envVar"],tags:[VARIABLES_TAG],optIn:!0,find:async(candidate,ctx)=>envVarLookup.findSync(candidate,ctx),findSync:(candidate,ctx)=>matchVariables(ctx.services.get("recipe-answers.definitions").listSync(),candidate,buildLadder({services:ctx.services,env:ctx.env,config:ctx.config}))};var VARIABLE_SOURCE_ID="recipe-answers",FORBIDDEN_UNDER=["subscriptions","repos"];function recipeAnswersSource(variables,services){let answers=ctx=>computeAnswers(variables,buildLadder({services,env:ctx.env,config:ctx.config}));return{id:VARIABLE_SOURCE_ID,description:"recipe answers",variables:ctx=>variables.length===0?{}:answers(ctx).merged,scoped:(scopeKey,ctx)=>{if(variables.some(entry=>`${entry.recipe.namespace}/${entry.recipe.name}`===scopeKey))return answersForRecipe(answers(ctx),scopeKey)},secrets:()=>variables.filter(entry=>entry.definition.secret).map(entry=>entry.definition.name),forbiddenUnder:FORBIDDEN_UNDER}}function variableSourceContributor(services){return{id:"recipe-answers.variable-source",after:["@sous-io/plugin-recipes"],contribute(config2){let variables=definitionsFromRecipes(config2.entities("active-recipe"));config2.addEntity("variable-source",recipeAnswersSource(variables,services))}}}var package_default13={name:"@sous-io/plugin-recipe-answers",version:"1.0.11",description:"Recipe variable definitions, the answer ladder, asking for answers, answer files and variable mappings.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/plugin-confd":"workspace:*","@sous-io/plugin-config-files":"workspace:*","@sous-io/plugin-formats":"workspace:*","@sous-io/plugin-refs":"workspace:*","@sous-io/plugin-variables":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME12="@sous-io/plugin-recipe-answers",recipeAnswersPlugin=definePlugin13({name:PLUGIN_NAME12,version:package_default13.version,description:"Recipe variable definitions, the answer ladder, asking for answers, answer files and variable mappings.",dependsOn:{"@sous-io/plugin-recipes":`^${package_default13.version}`,"@sous-io/plugin-confd":`^${package_default13.version}`,"@sous-io/plugin-config-files":`^${package_default13.version}`,"@sous-io/plugin-formats":`^${package_default13.version}`,"@sous-io/plugin-refs":`^${package_default13.version}`,"@sous-io/plugin-variables":`^${package_default13.version}`},register(sous){sous.services.add("recipe-answers.definitions",(_config,ctx)=>new DefinitionsService(ctx),{lifetime:"config"}),sous.services.add("recipe-answers.ladder",(config2,ctx)=>buildLadder({services:ctx.services,env:ctx.env,config:config2}),{lifetime:"config"}),sous.services.add("recipe-answers.answers",(_config,ctx)=>new AnswersService(()=>computeAnswers(ctx.services.get("recipe-answers.definitions").listSync(),ctx.services.get("recipe-answers.ladder"))),{lifetime:"config"}),sous.services.add("recipe-answers.preanswers",(_config,ctx)=>new PreanswersService(ctx),{lifetime:"factory"}),sous.services.add("recipe-answers.mappings",(_config,ctx)=>new MappingsService(ctx),{lifetime:"config"}),sous.services.add("recipe-answers.validator",()=>validator,{lifetime:"singleton"}),sous.entities.add("config-key",{id:"varMappings",description:"Environment variable names bound to recipe variables (conf.d/520-var-mappings.jsonc).",schema:jsonSchema16({type:"object",additionalProperties:{type:"string"},default:{}})}),sous.entities.add("ref-lookup",variableLookup),sous.entities.add("ref-lookup",envVarLookup),sous.config.contribute(variableSourceContributor(sous.services));for(let intent of varsIntents)sous.intents.add(intent)}});import{definePlugin as definePlugin14}from"@sous-io/plugin-api";import path62 from"node:path";function transformIdFor(targetId){return`skills/${targetId}`}function outputDir(directory){let trimmed=directory.trim();if(path62.isAbsolute(trimmed))return stripTrailingSlash(path62.normalize(trimmed));if(trimmed.startsWith("${"))return stripTrailingSlash(trimmed);let relative4=path62.posix.normalize(trimmed.split(path62.sep).join("/"));return relative4==="."?"${projectRoot}":`\${projectRoot}/${stripTrailingSlash(relative4.replace(/^\.\//,""))}`}function skillDestinations(outputs,targets){let destinations=[],seen=new Set;for(let target of targets){if(typeof target.directory!="string"||target.directory.trim()==="")continue;let dir=outputDir(target.directory);seen.has(dir)||(seen.add(dir),destinations.push(typeof target.transform=="function"?{dir,target:target.id,transform:transformIdFor(target.id)}:{dir,target:target.id}))}for(let output of outputs){let dir=outputDir(output);seen.has(dir)||(seen.add(dir),destinations.push({dir}))}return destinations}function stripTrailingSlash(value){return value.length>1&&value.endsWith("/")?value.slice(0,-1):value}import{jsonSchema as jsonSchema17}from"@sous-io/plugin-api";var SKILLS_KEY="recipes.skills",stringList2={type:"array",items:{type:"string"},default:[]},skillsConfigKey={id:SKILLS_KEY,description:"Where skills go (outputs, `${var}` allowed) and directories of your own skills (include).",schema:jsonSchema17({type:"object",properties:{outputs:{...stringList2,description:"Directories skills are also written to."},include:{...stringList2,description:"Directories of your own skills, compiled like a recipe's."}},additionalProperties:!1,default:{}})};function stringsOf(value){return Array.isArray(value)?value.filter(item=>typeof item=="string"&&item.trim()!==""):[]}function describeNowhere(sources){let recipes=new Set(sources.flatMap(source=>source.recipe===void 0?[]:[source.recipe])).size,own=sources.filter(source=>source.origin==="project").length,parts=[];if(recipes>0&&parts.push(`the skills of ${recipes} ${recipes===1?"recipe":"recipes"}`),own>0&&parts.push(`${own} ${own===1?"skill":"skills"} of your own`),parts.length!==0)return{summary:`Skipped ${parts.join(" and ")}: nothing says where skills go.`,hint:"Set recipes.skills.outputs in the config, or enable an agent plugin (such as @sous-io/plugin-claude-code)."}}function skillWarnings(ctx){if(!ctx.services.has("skills.sources"))return[];let sources=ctx.services.get("skills.sources"),warnings=(sources.problems?.()??[]).map(summary=>({summary}));if(skillDestinations(stringsOf(ctx.config.get("recipes.skills.outputs")),ctx.entities.list("skill-target")).length===0){let nowhere=describeNowhere(sources.list());nowhere&&warnings.push(nowhere)}return warnings}import fs45 from"node:fs";import path63 from"node:path";function bytewise(a,b){return a<b?-1:a>b?1:0}function findSkills(input){let skills=[],problems=[];for(let content of input.contents.of(input.recipes,"skills"))skills.push(...recipeSkills(content));return input.include.forEach((entry,index)=>{let setting=`recipes.skills.include[${index}]`,dir=resolveProjectDir(entry,input.project);if(typeof dir!="string"){problems.push({setting,message:`${setting} is "${entry}": ${dir.reason}`});return}if(!isDirectory2(dir)){problems.push({setting,message:`${setting} is "${entry}", which is not a directory, so it was skipped.`});return}skills.push(...groupSkills({origin:"project"},[{base:dir,files:listFiles(dir,"**/*",[])}]))}),{skills,problems}}function recipeSkills(content){let byBase=new Map;for(let{base,file:file2}of content.files)byBase.set(base,[...byBase.get(base)??[],file2]);return groupSkills({origin:"recipe",recipe:content.recipe.id,repository:content.recipe.repo},[...byBase].map(([base,files])=>({base,files})))}function groupSkills(from,groups){let byDir=new Map;for(let group of groups)for(let file2 of group.files){let relative4=path63.relative(group.base,file2);if(relative4===""||relative4.startsWith("..")||path63.isAbsolute(relative4))continue;let[first2]=relative4.split(path63.sep),nested=relative4!==first2,dir=nested?path63.join(group.base,first2):group.base,name=nested?first2:withoutExtensions(first2),key=`${dir}\0${nested?"":name}`,skill=byDir.get(key);skill||(skill={name,base:group.base,files:new Set},byDir.set(key,skill)),skill.files.add(path63.relative(dir,file2).split(path63.sep).join("/"))}return[...byDir.entries()].map(([key,skill])=>({name:skill.name,...from,dir:key.slice(0,key.indexOf("\0")),base:skill.base,files:[...skill.files].sort(bytewise)})).sort((a,b)=>bytewise(a.name,b.name)||bytewise(a.dir,b.dir))}function listFiles(cwd,pattern,exclude){return isDirectory2(cwd)?ts(pattern,{cwd,absolute:!0,nodir:!0,ignore:[...exclude]}).filter(isFile9).sort(bytewise):[]}function resolveProjectDir(entry,project){let substituted=entry.replace(/\$\{(projectRoot|sousDir)\}/g,(_match,name)=>project?name==="projectRoot"?project.root:project.sousDir:_match);return/\$\{[^}]*\}/.test(substituted)?{reason:project?"only ${projectRoot} and ${sousDir} can be used here, so it was skipped.":"there is no project to resolve it in, so it was skipped."}:path63.isAbsolute(substituted)?path63.normalize(substituted):project?path63.resolve(project.root,substituted):{reason:"a relative directory needs a project, and there is none, so it was skipped."}}function withoutExtensions(name){let dot=name.indexOf(".",1);return dot===-1?name:name.slice(0,dot)}function isDirectory2(candidate){try{return fs45.statSync(candidate).isDirectory()}catch{return!1}}function isFile9(candidate){try{return fs45.statSync(candidate).isFile()}catch{return!1}}var ConfigSkillsSources=class{constructor(config2,ctx){this.config=config2;this.ctx=ctx}found;list(){return this.find().skills.map(({base:_base,...source})=>source)}recipes(){return[...new Set(this.find().skills.flatMap(skill=>skill.recipe===void 0?[]:[skill.recipe]))]}problems(){return this.find().problems.map(problem=>problem.message)}find(){return this.found??=findSkills({recipes:this.ctx.entities.list("active-recipe"),contents:this.ctx.services.get("recipes.contents"),include:stringsOf(this.config.get("recipes.skills.include")),project:this.ctx.project}),this.found}};import{jsonSchema as jsonSchema18}from"@sous-io/plugin-api";var SKILL_TARGET="skill-target",skillTargetSchema=jsonSchema18({type:"object",properties:{id:{type:"string",description:"The target's name: `claude-code`."},harness:{type:"string",description:"The `harness` entity that reads it."},directory:{type:"string",description:"The directory skills go into; relative paths are under the project root."},description:{type:"string"}},required:["id","directory"]}),SKILL_TARGET_DESCRIPTION="A place a harness reads skills from, with an optional transform of each file.";import path64 from"node:path";var TARGETS_CONTRIBUTOR="skills.targets";function contributeSkillTargets(config2,plugin,contents){let outputs=stringsOf(config2.atPath("recipes.skills.outputs").get()),include=stringsOf(config2.atPath("recipes.skills.include").get()),targets=config2.entities("skill-target"),recipes=config2.entities("active-recipe"),destinations=skillDestinations(outputs,targets);if(destinations.length===0)return;let{skills}=findSkills({recipes,contents,include,project:config2.project});if(skills.length===0)return;let origins=new Map,list2=config2.atPath("compilation.targets");for(let skill of skills)for(let file2 of skill.files){let entryPoint=path64.join(skill.dir,file2);origins.set(entryPoint,skill.recipe===void 0?{skill:skill.name}:{skill:skill.name,recipe:skill.recipe}),list2.append(compilationTarget(skill,entryPoint,destinations,plugin,config2.project?.root))}for(let target of targets)typeof target.transform=="function"&&destinations.some(d=>d.target===target.id)&&config2.addEntity("compilation-transform",transformEntity(target,origins))}function compilationTarget(skill,entryPoint,destinations,plugin,projectRoot){let fromBase=path64.relative(skill.base,entryPoint).split(path64.sep).join("/");return{id:`skills/${skill.recipe??`project:${projectRoot?path64.relative(projectRoot,skill.base).split(path64.sep).join("/")||".":skill.base}`}/${fromBase}`,entryPoint,globBase:skill.base,origin:{plugin,...skill.recipe===void 0?{}:{recipe:skill.recipe},...skill.repository===void 0?{}:{repository:skill.repository}},outputs:destinations.map(destination=>destination.transform?{destinationDir:destination.dir,transforms:[destination.transform]}:{destinationDir:destination.dir})}}function transformEntity(target,origins){let transform2=target.transform;return{id:transformIdFor(target.id),description:`The transform of the skill target "${target.id}".`,async transform(file2,ctx){let origin=origins.get(file2.source)??{skill:path64.basename(path64.dirname(file2.source))},skillFile={...file2,...origin};return transform2(skillFile,ctx)}}}var package_default14={name:"@sous-io/plugin-skills",version:"1.0.11",description:"Skills: where they come from, the skill-target entity, and the compilation targets for them.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-compiler":"workspace:*","@sous-io/plugin-recipes":"workspace:*",glob:"^13.0.6"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME13="@sous-io/plugin-skills",skillsPlugin=definePlugin14({name:PLUGIN_NAME13,version:package_default14.version,description:"Skills: where they come from, the skill-target entity, and the compilation targets for them.",dependsOn:{"@sous-io/plugin-compiler":`^${package_default14.version}`,"@sous-io/plugin-recipes":`^${package_default14.version}`},register(sous){sous.entities.define(SKILL_TARGET,skillTargetSchema,{description:SKILL_TARGET_DESCRIPTION}),sous.entities.add("config-key",skillsConfigKey),sous.services.add("skills.sources",(config2,ctx)=>new ConfigSkillsSources(config2,ctx),{lifetime:"config"});let services=sous.services;sous.config.contribute({id:TARGETS_CONTRIBUTOR,after:["@sous-io/plugin-recipes"],contribute:config2=>contributeSkillTargets(config2,PLUGIN_NAME13,services.get("recipes.contents"))}),sous.on("compiler.compile.before",(_event,ctx)=>{for(let warning of skillWarnings(ctx))ctx.reporter.problem(warning.summary,warning.hint===void 0?{}:{hint:warning.hint})})}});import{definePlugin as definePlugin15}from"@sous-io/plugin-api";import path65 from"node:path";import{ConfigError as ConfigError43}from"@sous-io/plugin-api";function isRegexSpelling(entry){return entry.length>=3&&entry.startsWith("/")&&entry.endsWith("/")}function compileEntry(entry,where2,isMatch){if(!isRegexSpelling(entry))return key=>isMatch(key,entry);let expression;try{expression=new RegExp(entry.slice(1,-1))}catch(error51){let reason=error51 instanceof Error?error51.message:String(error51);throw new ConfigError43(`The value ${JSON.stringify(entry)} in '${where2}' is written as a regular expression, but it is not a valid one: ${reason}`)}return key=>expression.test(key)}function compileRecipeKeyMatcher(entries,where2,isMatch){let matchers=(entries??[]).map(entry=>compileEntry(entry,where2,isMatch));return recipeKey2=>matchers.some(matches=>matches(recipeKey2))}function compileRecipeKeyFinder(entries,where2,isMatch){let matchers=(entries??[]).map(entry=>compileEntry(entry,where2,isMatch));return recipeKey2=>{let index=matchers.findIndex(matches=>matches(recipeKey2));return index===-1?void 0:`${where2}[${index}]`}}var FIRST_KEY="recipes.memories.first",EXCLUDE_KEY="recipes.memories.exclude";function dependencyOrder(recipes,compare){let waitingOn=new Map;for(let recipe of recipes)waitingOn.set(recipe.id,new Set);for(let dependency of recipes)for(let holder of dependency.requestedBy)holder!==dependency.id&&waitingOn.get(holder)?.add(dependency.id);let ordered2=[],done2=new Set,remaining=[...waitingOn.keys()].sort(compare);for(;remaining.length>0;){let index=remaining.findIndex(key2=>[...waitingOn.get(key2)].every(dep=>done2.has(dep)));if(index===-1){ordered2.push(...remaining);break}let[key]=remaining.splice(index,1);ordered2.push(key),done2.add(key)}return ordered2}function recipeMemories(recipe,globs,contents,onWarning=()=>{}){let byFile=new Map;for(let content of contents.of([recipe],"memories"))for(let{file:file2,base}of content.files)if(!byFile.has(file2)){if(globs.realPathInside(file2,recipe.dir)===void 0){onWarning(`The memory ${file2} of the recipe ${recipe.id} was left out, because it is a link that leads outside the recipe's directory. Replace the link with the file itself.`);continue}byFile.set(file2,{recipe:recipe.id,repository:recipe.repo,name:globs.toPosix(path65.relative(base,file2)),path:file2})}return[...byFile.values()].sort((a,b)=>globs.compareBytewise(a.name,b.name))}function selectMemories(options){let{recipes,globs,contents}=options,isMatch=(key,pattern)=>globs.isMatch(key,pattern),isFirst=compileRecipeKeyMatcher(options.settings?.first,FIRST_KEY,isMatch),excludedBy=compileRecipeKeyFinder(options.settings?.exclude,EXCLUDE_KEY,isMatch),byKey=new Map(recipes.map(recipe=>[recipe.id,recipe])),order=dependencyOrder(recipes,(a,b)=>globs.compareBytewise(a,b)),leading=order.filter(key=>isFirst(key)),rest=order.filter(key=>!isFirst(key)),selected=[],excluded=[];for(let key of[...leading,...rest]){let recipe=byKey.get(key),memories=recipeMemories(recipe,globs,contents,options.onWarning),by2=excludedBy(key);by2===void 0?selected.push(...memories):excluded.push(...memories.map(memory=>({memory,by:by2})))}return{selected,excluded}}function viewPath(memory){return`${memory.recipe}/${memory.name}`}var memoriesHashName={id:"memories",description:"the memories of every active recipe, listed in dependency order as #memories/<namespace>/<recipe>/<path>.",view:ctx=>ctx.services.get("memories.selection").selected().map(memory=>({path:viewPath(memory),file:memory.path}))};import{jsonSchema as jsonSchema19}from"@sous-io/plugin-api";function refine2(base,extra){let standard=base["~standard"];return{"~standard":{...standard,validate(value){let result=standard.validate(value);if(result.issues)return result;let issues=extra(result.value);return issues.length>0?{issues}:result}}}}var memoryTargetSchema=refine2(jsonSchema19({type:"object",required:["id","fileName"],properties:{id:{type:"string",description:"The target's id: `claude-code`."},harness:{type:"string",description:"The `harness` entity that reads the file."},fileName:{type:"string",description:"The file name: `CLAUDE.md`, `AGENTS.md`."},readIn:{enum:["project-root","any-directory"],default:"project-root",description:"Where the harness reads the file; `any-directory` also makes it a pointer file."},directory:{type:"string",description:"Where the file is written, relative to the project root."}}}),target=>["filter","format"].filter(name=>target[name]!==void 0&&typeof target[name]!="function").map(name=>({path:[name],message:"Expected a function."})));function keyListIssues(entries,where2,key){return entries.flatMap((entry,index)=>{try{return compileRecipeKeyMatcher([entry],`${where2}[${index}]`,()=>!1),[]}catch(error51){return[{path:[key,index],message:error51 instanceof Error?error51.message:String(error51)}]}})}var memoriesSettingsSchema=refine2(jsonSchema19({type:"object",additionalProperties:!1,properties:{first:{type:"array",items:{type:"string"},default:[],description:"Recipe keys, globs or /regular expressions/ whose memories come first, in this order."},exclude:{type:"array",items:{type:"string"},default:[],description:"Recipe keys, globs or /regular expressions/ whose memories are left out."}},default:{},description:"Which recipe memories memory targets and the #memories view take, and in what order."}),settings=>[...keyListIssues(settings.first,FIRST_KEY,"first"),...keyListIssues(settings.exclude,EXCLUDE_KEY,"exclude")]);import{NotFoundError as NotFoundError7}from"@sous-io/plugin-api";init_src();import{nullReporter as nullReporter4,Reporting as Reporting3,SousError as SousError24}from"@sous-io/plugin-api";var BuiltConfigBuilder=class extends Reporting3(Object){constructor(config2,ctx,contributorId2){super();this.config=config2;this.ctx=ctx;this.document=createDocument(config2.value()),this.contributor={id:contributorId2,plugin:ctx.plugin,stage:0,pass:0,run:0},this.project=ctx.project,this.env=ctx.env}contributor;project;env;document;get reporter(){return nullReporter4}log(){}root(){return this.document.root()}atPath(input){return this.document.atPath(input)}entities(kind){return this.ctx.entities.list(kind)}entity(kind,id){return this.ctx.entities.get(kind,id)}addEntity(){throw new SousError24("A memory target's filter cannot add entities after the config is built.")}previousPatches(){}apply(){}options(){return this.config.get(["plugins","options"])?.[this.ctx.plugin]}};function builderOver(config2,ctx,contributorId2){return new BuiltConfigBuilder(config2,ctx,contributorId2)}var TARGETS_CONTRIBUTOR2="memories.targets";function compilationTargetId(target){return`memories/${target.id}`}function pointerFileId(target){return`memories/${target.id}`}function defaultFormat(memories){return memories.map(memory=>`@${memory.path}`).join(`
934
+ `,defaultFactory=()=>{let worker2=new Worker(WORKER_SOURCE,{eval:!0});return worker2.unref(),worker2},factory=defaultFactory,worker,workersUnavailable=!1;function disposeMatcherWorker(){let running=worker;if(worker=void 0,running!==void 0)try{running.terminate()}catch{}}function matcher(){if(!workersUnavailable){if(worker!==void 0)return worker;try{worker=factory()}catch{worker=void 0}return worker===void 0&&(workersUnavailable=!0),worker}}function matchWithBudget(pattern,input,budgetMs=DEFAULT_PATTERN_BUDGET_MS){let running=matcher();if(running===void 0)return inProcessMatch(pattern,input);let shared=new SharedArrayBuffer(2*Int32Array.BYTES_PER_ELEMENT),slots=new Int32Array(shared);try{running.postMessage({pattern,input,shared})}catch{return disposeMatcherWorker(),inProcessMatch(pattern,input)}if(!waitForStart(slots))return disposeMatcherWorker(),workersUnavailable=!0,inProcessMatch(pattern,input);switch(Atomics.load(slots,STATUS)===PENDING&&Atomics.wait(slots,STATUS,PENDING,budgetMs),Atomics.load(slots,STATUS)){case MATCHED:return"match";case DID_NOT_MATCH:return"no-match";case FAILED:return inProcessMatch(pattern,input);default:return disposeMatcherWorker(),"timeout"}}function waitForStart(slots){let deadline=Date.now()+STARTUP_GRACE_MS;for(;Atomics.load(slots,STARTED)===0&&Atomics.load(slots,STATUS)===PENDING;){let remaining=deadline-Date.now();if(remaining<=0)return!1;Atomics.wait(slots,STARTED,0,remaining)}return!0}function inProcessMatch(pattern,input){return new RegExp(pattern).test(input)?"match":"no-match"}var TRUE_WORDS=new Set(["true","yes","y","on","1"]),FALSE_WORDS=new Set(["false","no","n","off","0"]);function validateAnswer(definition,raw2,context={}){let trimmed=typeof raw2=="string"?raw2.trim():"";if(trimmed.length===0&&!definition.required)return{ok:!0,value:""};let rules=definition.validate,fail=reason=>({ok:!1,message:`${definition.name} ${reason}.`});switch(definition.type){case"number":{if(trimmed.length===0||!Number.isFinite(Number(trimmed)))return fail("must be a number");let value=Number(trimmed);return rules?.min!==void 0&&value<rules.min?fail(`must be at least ${rules.min}`):rules?.max!==void 0&&value>rules.max?fail(`must be at most ${rules.max}`):{ok:!0,value}}case"boolean":{let word=trimmed.toLowerCase();return!TRUE_WORDS.has(word)&&!FALSE_WORDS.has(word)?fail("must be 'true' or 'false'"):{ok:!0,value:TRUE_WORDS.has(word)}}case"enum":{let options=rules?.enum??[];return runString(trimmed,[value=>options.includes(value)?void 0:`must be one of: ${options.join(", ")}`,...stringChecks()])}case"url":return runString(trimmed,[value=>isUrl(value)?void 0:"must be a URL, including its scheme (for example 'https://example.com')",...stringChecks()]);case"path":return runString(trimmed,[value=>value.includes("\0")?"must be a filesystem path, with no null characters in it":void 0,...stringChecks()]);default:return runString(trimmed,stringChecks())}function runString(value,checks){for(let check3 of checks){let reason=check3(value);if(reason!==void 0)return fail(reason)}return{ok:!0,value}}function stringChecks(){let checks=[];if(definition.required&&checks.push(value=>value.length>0?void 0:"must not be empty"),rules?.minLength!==void 0){let min=rules.minLength;checks.push(value=>value.length>=min?void 0:`must be at least ${min} characters long`)}if(rules?.maxLength!==void 0){let max=rules.maxLength;checks.push(value=>value.length<=max?void 0:`must be at most ${max} characters long`)}if(rules?.pattern!==void 0){let pattern=rules.pattern,budget=context.patternBudgetMs??DEFAULT_PATTERN_BUDGET_MS;checks.push(value=>{let outcome=matchWithBudget(pattern,value,budget);if(outcome!=="match")return outcome==="timeout"?patternTooSlowMessage(pattern,budget,context.recipe):`must match the pattern ${pattern}`})}return checks}}function isUrl(value){try{return new URL(value).protocol.length>1}catch{return!1}}function patternTooSlowMessage(pattern,budgetMs,recipe){let publisher=recipe===void 0?"the recipe that defines it":`the recipe ${recipe}`;return`could not be checked: the pattern ${pattern}, published by ${publisher}, took longer than ${budgetMs} milliseconds to run, so sous stopped waiting for it. The pattern is too slow to run, and the answer was not the problem; this needs to be reported to whoever publishes the recipe`}function characters(count2){return count2===1?"1 character":`${count2} characters`}function constraintBullets(definition){let rules=definition.validate,options=rules?.enum,bullets=definition.type==="enum"&&options!==void 0?[`must be one of: ${options.join(", ")} (type: enum)`]:[`must be a value of the type ${definition.type} (type: ${definition.type})`];return options!==void 0&&definition.type!=="enum"&&bullets.push(`must be one of: ${options.join(", ")} (enum: ${options.join(", ")})`),rules?.minLength!==void 0&&bullets.push(`must be at least ${characters(rules.minLength)} long (minLength: ${rules.minLength})`),rules?.maxLength!==void 0&&bullets.push(`must be at most ${characters(rules.maxLength)} long (maxLength: ${rules.maxLength})`),rules?.min!==void 0&&bullets.push(`must be no less than ${rules.min} (min: ${rules.min})`),rules?.max!==void 0&&bullets.push(`must be no more than ${rules.max} (max: ${rules.max})`),rules?.pattern!==void 0&&bullets.push(`must match the pattern /${rules.pattern}/ (pattern: ${rules.pattern})`),definition.required||bullets.push("an answer is optional"),bullets}var validator={validate:(definition,answer2,options)=>validateAnswer(definition,answer2,options)};var TRUE_WORDS2=["true","yes","y","on","1"];function answerCount(count2){return count2===1?"1 answer":`${count2} answers`}function answeredBy(variable){return`--answer ${variable.definition.name}=<value>`}function askLeadIn(groups){if(groups.length<2)return;let parts=groups.map((group,index)=>{let relation=index===0||group.direct?"":", which it depends on,",needs=index===0?answerCount(group.count):String(group.count);return`${group.key}${relation} needs ${needs}`}),last2=parts.pop();return`${[...parts,`and ${last2}`].join(", ")}.`}function recipeOpeningLine(key,count2){return`${key} needs ${answerCount(count2)} before it can be used.`}function answerComment(variable){return`Set by sous for ${recipeKey(variable.recipe)}: ${variable.definition.prompt}`}function nonInteractiveError(pending){let details=["Set one of the environment variables listed under each variable, pass --answer <name>=<value>, or run 'sous vars ask' from a terminal."];for(let entry of pending){details.push("",`${entry.variable.definition.name} (${recipeKey(entry.variable.recipe)}): ${entry.variable.definition.prompt}`),entry.current!==void 0&&details.push(` The value currently in scope does not fit this variable: ${entry.current}`);for(let candidate of entry.candidates)details.push(` ${candidate.envName} (${RUNG_LABELS2[candidate.rung]})`)}let first2=pending[0],question=pending.length===1?first2.variable.definition.prompt:`${pending.length} questions about recipe variables`,error51=new NonInteractiveError4(question,pending.length===1?answeredBy(first2.variable):"--answer <name>=<value>",{details,exitCode:1});return error51.message=pending.length===1?"One variable still needs an answer, and there is no terminal to ask on.":`${pending.length} variables still need answers, and there is no terminal to ask on.`,error51}function committedFileWarning(variable,file2){let why2=variable.definition.secret?"declared this variable a secret":"declared this variable machine-specific";return`${recipeKey(variable.recipe)} ${why2}, and ${file2} is committed to git. An answer stored there enters your project's git history, is pushed with every clone, and is visible to everyone who can read the repository.`}async function allowedFile(variable,file2,run){if(file2!=="shared"||run.envFile!=="shared"||answerFileFor(variable.definition)!=="local"||run.yes===!0)return!0;let name=ENV_FILE_NAMES.shared;return run.reporter.warning(committedFileWarning(variable,`.sous/${name}`)),run.prompter.confirm({message:`Store this answer in .sous/${name} anyway?`,answeredBy:"--yes",default:!1})}function check2(variable,value){return validateAnswer(variable.definition,value,{recipe:recipeKey(variable.recipe)})}async function storeGivenAnswers(applicable,ladder,run){let stored=[],keys=new Set,written=new Set;for(let entry of applicable){keys.add(entry.target.key);let existing=ladder.resolve(entry.target),fallback2={file:run.envFile??answerFileFor(entry.target.definition),envName:ladder.bareName(entry.target)},plan=run.envFile===void 0&&existing!==void 0&&existing.source.file!=="shell"?{file:existing.source.file,envName:existing.source.envName}:fallback2,slot=`${plan.file}:${plan.envName}`;if(written.has(slot)||(written.add(slot),!await allowedFile(entry.target,plan.file,run)))continue;let outcome=run.dryRun?"not written":ladder.lookupIn(plan.file,plan.envName)===void 0?"appended":"updated";run.dryRun||await run.store.writeAnswer(plan.file,plan.envName,entry.value,answerComment(entry.target)),ladder.record(plan.file,plan.envName,entry.value),stored.push({variable:entry.target,envName:plan.envName,file:plan.file,filePath:run.store.envPath(plan.file),value:displayValue(entry.value,entry.target.definition.secret,run.hidden),outcome,...existing===void 0||existing.value===entry.value?{}:{replaced:displayValue(existing.value,entry.target.definition.secret,run.hidden)},...existing?.source.file==="shell"?{shadowedBy:existing.source.envName}:{}})}return{stored,keys}}async function askForMissing(variables,ladder,options,run){let report={answered:[],inherited:[],skipped:[]},pending=[],questions=[],deferred=[],plannedNames=new Set,named=options.only!==void 0;for(let variable of variables){if(options.only!==void 0&&!options.only.has(variable.key)||options.within!==void 0&&!options.within.has(recipeKey(variable.recipe))||options.skip?.has(variable.key)===!0)continue;let{definition}=variable,diagnosis=ladder.diagnose(variable),existing=diagnosis.resolved,validity=existing===void 0?void 0:check2(variable,existing.value);if(existing!==void 0&&validity?.ok===!0&&options.reask!==!0&&!named){report.inherited.push({variable,resolved:existing});continue}if(existing===void 0&&options.reask!==!0&&!named&&diagnosis.candidates.some(candidate=>plannedNames.has(candidate.envName))){deferred.push(variable);continue}if(!(existing!==void 0&&validity?.ok===!1||existing===void 0&&definition.required||options.reask===!0||named)){report.skipped.push({variable,reason:"no answer yet, and this variable is optional"});continue}if(!run.prompter.interactive){pending.push({variable,candidates:diagnosis.candidates,...validity?.ok===!1?{current:validity.message}:{}});continue}let suggestion=existing!==void 0&&validity?.ok===!0?existing.value:definition.default!==void 0?String(definition.default):void 0;plannedNames.add(ladder.bareName(variable)),questions.push({variable,...suggestion===void 0?{}:{suggestion}})}if(pending.length>0)throw nonInteractiveError(pending);let groups=groupQuestions(questions),leadIn=askLeadIn(groups.map(group=>({key:group.key,count:group.questions.length,direct:group.direct})));leadIn!==void 0&&run.reporter.note(leadIn);for(let group of groups){run.reporter.note(recipeOpeningLine(group.key,group.questions.length));for(let[position,question]of group.questions.entries())await runQuestion(question,{index:position+1,total:group.questions.length},ladder,run,report)}for(let variable of deferred){let resolved=ladder.resolve(variable);if(resolved!==void 0&&check2(variable,resolved.value).ok){report.inherited.push({variable,resolved});continue}run.reporter.note(recipeOpeningLine(recipeKey(variable.recipe),1)),await runQuestion({variable},{index:1,total:1},ladder,run,report)}return report}function groupQuestions(questions){let groups=new Map;for(let question of questions){let key=recipeKey(question.variable.recipe),group=groups.get(key);group===void 0?groups.set(key,{key,direct:question.variable.recipe.direct!==!1,questions:[question]}):group.questions.push(question)}return[...groups.values()]}async function askByType(definition,variable,suggestion,prompter){let by2=answeredBy(variable);if(definition.type==="enum"){let options=definition.validate?.enum??[],index=suggestion===void 0?-1:options.indexOf(suggestion);return prompter.askChoice({message:definition.prompt,answeredBy:by2,choices:options.map(option=>({label:option,value:option})),...index===-1?{}:{defaultIndex:index}})}if(definition.type==="boolean"){let current=suggestion??String(definition.default??"");return String(await prompter.confirm({message:definition.prompt,answeredBy:by2,default:TRUE_WORDS2.includes(current.toLowerCase())}))}return prompter.askValue({message:definition.prompt,answeredBy:by2,validate:value=>{let result=check2(variable,value);return result.ok?void 0:result.message},...suggestion===void 0?{}:{default:suggestion},...definition.secret?{secret:!0}:{}})}async function runQuestion(question,place,ladder,run,report){let{variable}=question,{definition}=variable,plan={file:run.envFile??answerFileFor(definition),envName:ladder.bareName(variable)};if(!await allowedFile(variable,plan.file,run)){report.skipped.push({variable,reason:`not stored in .sous/${ENV_FILE_NAMES.shared}, which is committed to git`});return}run.reporter.question({index:place.index,total:place.total,name:definition.name,...definition.description===void 0?{}:{description:definition.description},...definition.example===void 0?{}:{example:String(definition.example)},recipe:recipeKey(variable.recipe),storedIn:run.store.envPath(plan.file),storedAs:plan.envName});let answer2=await askByType(definition,variable,question.suggestion,run.prompter),checked3=check2(variable,answer2);if(!checked3.ok){report.skipped.push({variable,reason:checked3.message});return}let stored=await storeAnswer(variable,String(checked3.value),plan,ladder,run);report.answered.push(stored),run.reporter.variables([{label:"Answer",value:`${stored.envName}=${stored.value}`},{label:run.dryRun?"Would be saved to":"Saved to",value:stored.filePath}],void 0,LogLevel10.Notice)}async function storeAnswer(variable,value,plan,ladder,run){let envName=plan.envName,mapping,occupant=ladder.lookup(envName);if(occupant!==void 0&&!check2(variable,occupant.value).ok){let scoped=ladder.recipeScopedName(variable),target=formatMappingTarget(mappingTargetFor(variable));(!run.prompter.interactive||await run.prompter.askChoice({message:`${envName} already holds a value that does not fit ${variable.definition.name}. Where should this answer go?`,choices:[{label:`${scoped}, with a mapping record (recommended)`,value:!0},{label:`${envName}, replacing what is there`,value:!1}]}))&&(envName=scoped,mapping={envName:scoped,target,filePath:run.dryRun?run.store.mappingPath():await run.store.writeMapping(scoped,target)},ladder.addMapping(scoped,target))}let outcome=run.dryRun?"not written":ladder.lookupIn(plan.file,envName)===void 0?"appended":"updated";run.dryRun||(await run.store.writeAnswer(plan.file,envName,value,answerComment(variable)),ladder.record(plan.file,envName,value));let winner=ladder.resolve(variable),shadowedBy=winner?.source.file==="shell"&&(winner.source.envName!==envName||winner.value!==value)?winner.source.envName:void 0;return{variable,envName,file:plan.file,filePath:run.store.envPath(plan.file),value:displayValue(value,variable.definition.secret,run.hidden),outcome,...mapping===void 0?{}:{mapping},...shadowedBy===void 0?{}:{shadowedBy}}}import path59 from"node:path";import{ConfigError as ConfigError40}from"@sous-io/plugin-api";var ENV_FILE_CHOICES="The allowed files are .sous/.env (committed, shared with everyone on the project) and .sous/.env.local (gitignored, this machine only).";function resolveEnvFile(value,paths,root,cwd=root){let wanted=new Set([path59.resolve(cwd,value),path59.resolve(root,value),path59.resolve(root,".sous",value)]);for(let kind of["shared","local"])if(wanted.has(path59.resolve(root,paths[kind])))return kind;throw new ConfigError40(`'${value}' is not an env file sous can write answers to. ${ENV_FILE_CHOICES}`)}import path60 from"node:path";import{IntentOutput as IntentOutput8,Table as Table3,VariableSet as VariableSet4}from"@sous-io/plugin-api";function rungLabel(rung){return RUNG_LABELS2[rung]??rung}function sourceLabel(file2){return SOURCE_LABELS2[file2]??file2}function envFileName(file2){return ENV_FILE_NAMES[file2]??file2}function variableKeyOf(variable){return`${recipeKey(variable.recipe)}.${variable.definition.name}`}function isHostedUrl(location){return/^[a-z][a-z0-9+.-]*:\/\//i.test(location)||location.startsWith("git@")}function recipeLocation(recipe){let{url:url2,path:folder,dir}=recipe;if(url2!==void 0&&isHostedUrl(url2)){let base=url2.replace(/\/+$/,"");return folder===void 0?base:`${base}/${folder}`}return url2!==void 0?folder===void 0?url2:`${url2.replace(/\/+$/,"")}/${folder}`:dir}function recipeLink(recipe,label){let location=recipeLocation(recipe);return location===void 0?{label,value:recipeKey(recipe)}:{label,value:recipeKey(recipe),detail:location}}function variableFacts(detail,sousDir){let{variable}=detail,{definition}=variable,entries=[];definition.default!==void 0&&entries.push({label:"default",value:String(definition.default)}),entries.push({label:"example",value:String(definition.example)});let chain=variable.requiredBy!==void 0&&variable.requiredBy.length>0?variable.requiredBy:[variable.recipe];return entries.push(recipeLink(chain[0]??variable.recipe,"required-by")),chain.length>1&&entries.push({label:"",value:`pulled in through ${chain.map(recipeKey).join(" then ")}`}),entries.push(recipeLink(variable.recipe,"defined-by")),entries.push({label:"storage-path",value:sousDir===void 0?envFileName(detail.storeIn):path60.join(sousDir,envFileName(detail.storeIn))}),entries.push({label:"stored-as",value:detail.storedAs}),detail.constraints.forEach((line,index)=>entries.push({label:index===0?"constraints":"",value:line})),entries}var LIST_COLUMNS=[{key:"name",header:"Variable",overflow:"truncate",minWidth:8},{key:"recipe",header:"Recipe",kind:"path",overflow:"truncate",priority:"medium",minWidth:8},{key:"envName",header:"Answered by",overflow:"truncate",truncate:"start",priority:"medium",minWidth:11},{key:"value",header:"Value",overflow:"truncate",truncate:"end",flex:1,minWidth:10},{key:"source",header:"Source",priority:"low"}],LADDER_COLUMNS=[{key:"envName",header:"Environment variable",overflow:"truncate",truncate:"start"},{key:"rung",header:"Rung",priority:"medium"},{key:"status",header:"Status",flex:1,priority:"medium"}];function variableListOutput(listings,hidden){let rows=[...listings].sort((left,right)=>variableKeyOf(left.variable).localeCompare(variableKeyOf(right.variable))).map(listing=>({name:listing.variable.definition.name,recipe:recipeKey(listing.variable.recipe),envName:listing.source?.envName??"",value:displayValue(listing.answered?listing.value??"":void 0,listing.variable.definition.secret,hidden),source:listing.source===void 0?"nothing yet":`${rungLabel(listing.source.rung)}, ${sourceLabel(listing.source.file)}`}));return new IntentOutput8({title:"Variables in play",result:new Table3(LIST_COLUMNS,rows,{empty:"No recipe in this project defines any variables yet. Subscribe to a recipe that publishes some, or read a definitions file with --file."})})}function variableDetailOutputs(detail,hidden,sousDir){let{variable}=detail,{definition}=variable,resolved=detail.diagnosis.resolved,key=recipeKey(variable.recipe),rows=detail.diagnosis.candidates.map(candidate=>({envName:candidate.envName,rung:rungLabel(candidate.rung),status:candidate.envName===resolved?.source.envName?`answered it, from ${sourceLabel(resolved.source.file)}`:"not set"}));return[new IntentOutput8({title:`${definition.name} (${key})`,result:new VariableSet4({Question:definition.prompt,About:definition.description,"For example":String(definition.example),Recipe:`${key} version ${variable.recipe.version} from ${variable.recipe.repo}`,"Stored in":envFileName(detail.storeIn),Value:displayValue(resolved===void 0?void 0:resolved.value,definition.secret,hidden),Answer:resolved===void 0?"nothing in scope answers this variable yet":detail.problem===void 0?"the value in scope fits this definition":`the value in scope does not fit: ${detail.problem}`})}),new IntentOutput8({result:new VariableSet4(variableFacts(detail,sousDir))}),new IntentOutput8({result:new Table3(LADDER_COLUMNS,rows,{title:"Environment variables sous looks at, most specific first"})})]}function answeredEntries(entry,dryRun4,hidden){let secret=entry.variable.definition.secret,note=text=>({label:"",value:text}),entries=[{label:entry.variable.definition.name,value:displayValue(entry.value,secret,hidden),detail:`${entry.envName} in ${envFileName(entry.file)}`}];return entry.mapping!==void 0&&entries.push(note(`mapped to ${entry.mapping.target} in the conf.d layer`)),entry.replaced!==void 0&&entries.push(note(`${dryRun4?"replacing":"replaced"} the answer already there: ${displayValue(entry.replaced,secret,hidden)}`)),entry.shadowedBy!==void 0&&entries.push(note(`${entry.shadowedBy} is set in your shell environment and answers this variable first; unset it for the stored answer to take effect`)),entries}function askReportOutputs(report,hidden){let outputs=[];return report.inherited.length>0&&outputs.push(new IntentOutput8({title:"Answers already in scope",result:new VariableSet4(report.inherited.map(entry=>({label:entry.variable.definition.name,value:displayValue(entry.resolved.value,entry.variable.definition.secret,hidden),detail:`from ${describeSource2(entry.resolved.source)}`})))})),report.answered.length>0&&outputs.push(new IntentOutput8({title:report.dryRun?"Answers that would be stored":"Answers stored",result:new VariableSet4(report.answered.flatMap(entry=>answeredEntries(entry,report.dryRun,hidden)))})),report.skipped.length>0&&outputs.push(new IntentOutput8({title:"Left unanswered",result:new VariableSet4(report.skipped.map(entry=>({label:entry.variable.definition.name,value:entry.reason})))})),outputs.length===0&&outputs.push(new IntentOutput8({summary:"Every variable in play already has an answer that fits its definition."})),outputs}import{readFile as readFile2}from"node:fs/promises";import path61 from"node:path";import{InputError as InputError4}from"@sous-io/plugin-api";var ANSWER_FLAG_FORM="--answer <name>=<value>",ANSWER_NAME_HELP="A name is spelled exactly as the recipe declares it, in camelCase; the full 'namespace/recipe.name' key works too.",INTENT="vars.ask";function answerError(field,lines3){return new InputError4(INTENT,[{path:field,message:lines3[0]??""}],{details:lines3})}function parseAnswerPair(entry,from="--answer"){let at2=entry.indexOf("="),name=at2===-1?"":entry.slice(0,at2).trim();if(at2===-1||name.length===0)throw answerError("answer",[`'${entry}' is not an answer sous can read.`,`Write one as '${ANSWER_FLAG_FORM}', for example '--answer apiUrl=https://api.example.com'.`,"Everything after the first '=' is the answer, so a value may contain more of them."]);return{name,value:entry.slice(at2+1),from}}function isEnvFile(filePath){let base=path61.basename(filePath);return base===".env"||base.startsWith(".env.")||base.endsWith(".env")}function answersFromData(raw2,filePath){if(typeof raw2!="object"||raw2===null||Array.isArray(raw2))throw answerError("answersFile",[`The answers file at ${filePath} is not a map of answers.`,"It holds one entry per variable, written as 'name: value'."]);let answers=[];for(let[name,value]of Object.entries(raw2)){if(typeof value=="object"&&value!==null)throw answerError("answersFile",[`The answer for '${name}' in ${filePath} is a list or a map, and an answer is a single value.`,"Answers are stored in environment files, which hold text; write the answer as a string, a number or a boolean."]);if(value==null)throw answerError("answersFile",[`The answer for '${name}' in ${filePath} is empty.`,"Write the value the variable should be given, or leave the entry out entirely so sous asks for it."]);answers.push({name:name.trim(),value:String(value),from:filePath})}return answers}function collectAnswers(fromFile,flags){let collected=new Map;for(let answer2 of fromFile)collected.set(answer2.name,answer2);for(let entry of flags){let answer2=parseAnswerPair(entry);collected.set(answer2.name,answer2)}return[...collected.values()]}function unknownAnswerError(answer2,variables){let lines3=[`Nothing in this project defines a variable called '${answer2.name}', so the answer given with ${answer2.from} cannot be stored.`];if(variables.length===0)return lines3.push("No recipe this project subscribes to defines any variables yet, so there is nothing to answer."),answerError(answer2.from==="--answer"?"answer":"answersFile",lines3);let groups=new Map;for(let entry of variables){let key=recipeKey(entry.recipe),names2=groups.get(key)??[];names2.includes(entry.definition.name)||names2.push(entry.definition.name),groups.set(key,names2)}lines3.push("","These are the variables in play, and the recipes that declare them:","");for(let[key,names2]of groups)lines3.push(` ${key}`,...names2.map(name=>` ${name}`));return lines3.push("",ANSWER_NAME_HELP),answerError(answer2.from==="--answer"?"answer":"answersFile",lines3)}function invalidAnswerError(answer2,variable,message2,hidden){let shown=variable.definition.secret?hidden:answer2.value;return answerError(answer2.from==="--answer"?"answer":"answersFile",[`The answer given for '${answer2.name}' does not fit the definition ${recipeKey(variable.recipe)} publishes.`,message2,`For example: ${String(variable.definition.example)}`,`The answer given with ${answer2.from} was: ${shown}`,"Nothing was written; fix the answer and run the command again."])}function matchAnswers(answers,variables,hidden="(hidden)"){let applicable=[];for(let answer2 of answers){let targets=variables.filter(entry=>namesVariable(entry,answer2.name));if(targets.length===0)throw unknownAnswerError(answer2,variables);for(let target of targets){let checked3=validateAnswer(target.definition,answer2.value,{recipe:recipeKey(target.recipe)});if(!checked3.ok)throw invalidAnswerError(answer2,target,checked3.message,hidden);applicable.push({answer:answer2,target,value:String(checked3.value)})}}return applicable}var PreanswersService=class{constructor(ctx){this.ctx=ctx}async read(inputs){let fromFile=inputs.answersFile===void 0?[]:await this.readFile(resolveUserPath(inputs.answersFile,this.ctx));return collectAnswers(fromFile,inputs.answer??[])}match(answers,variables){let secrets=this.ctx.services.has("variables.secrets")?this.ctx.services.get("variables.secrets"):void 0;return matchAnswers(answers,variables,secrets?.hiddenValue)}async readFile(filePath){if(isEnvFile(filePath)){let text;try{text=await readFile2(filePath,"utf8")}catch(error51){throw answerError("answersFile",[`Could not read the answers file at ${filePath}: ${error51.message}`])}return answersFromData(this.ctx.services.get("config-files.env").parse(text),filePath)}return answersFromData(await this.ctx.services.get("formats.manifests").readFile(filePath),filePath)}};import{ConfigError as ConfigError41,isSousErrorOfKind as isSousErrorOfKind4,NonInteractiveError as NonInteractiveError5}from"@sous-io/plugin-api";var GLOB_CHARS2=/[*?[\]{}]/;function globToRegExp(pattern,ignoreCase){let source="",braces=0;for(let index=0;index<pattern.length;index+=1){let character=pattern[index];if(character==="*")source+=".*";else if(character==="?")source+=".";else if(character==="["){let end=pattern.indexOf("]",index+1);if(end===-1)source+="\\[";else{let body2=pattern.slice(index+1,end).replace(/^!/,"^").replace(/\\/g,"\\\\");source+=`[${body2}]`,index=end}}else character==="{"?(braces+=1,source+="(?:"):character==="}"&&braces>0?(braces-=1,source+=")"):character===","&&braces>0?source+="|":source+=character.replace(/[.+^$()|\\]/g,"\\$&")}return new RegExp(`^${source}$`,ignoreCase?"i":"")}function matchName(written,known){return GLOB_CHARS2.test(written)?globToRegExp(written,!1).test(known)?"exact":globToRegExp(written,!0).test(known)?"folded":void 0:written===known?"exact":written.toLowerCase()===known.toLowerCase()?"folded":void 0}function both2(left,right){if(!(left===void 0||right===void 0))return left==="folded"||right==="folded"?"folded":"exact"}function qualifies2(qualifier,variable){if(qualifier===void 0)return"exact";let result="exact";if(qualifier.name!==void 0&&(result=matchName(qualifier.name,variable.recipe.repo)),!(qualifier.location!==void 0&&qualifier.location.identity!==variable.recipe.identity))return result}function repoRef(variable){return{kind:"repo",name:variable.recipe.repo}}function namespaceRef2(variable){return{kind:"namespace",name:variable.recipe.namespace,repo:repoRef(variable)}}function recipeRef2(variable){return{kind:"recipe",name:variable.recipe.name,namespace:namespaceRef2(variable)}}function keyOf(ref){switch(ref.kind){case"repo":return`repo ${ref.name??""}`;case"namespace":return`namespace ${ref.repo?.name??""}:${ref.name}`;case"recipe":return`recipe ${ref.namespace?.repo?.name??""}:${ref.namespace?.name??""}/${ref.name}`;case"variable":return`variable ${ref.recipe?.namespace?.repo?.name??""}:${ref.recipe?.namespace?.name??""}/${ref.recipe?.name??""}.${ref.name}`;default:return`${ref.kind} ${"name"in ref?String(ref.name):""}`}}function carry2(candidate,known){return candidate.vars===void 0?known:{...known,vars:candidate.vars}}function envNamesOf(variable,ladder){let inUse=ladder.namesInFiles(),names2=new Set([ladder.bareName(variable)]);for(let candidate of ladder.candidates(variable))inUse.has(candidate.envName)&&names2.add(candidate.envName);return names2}function matchVariables(pool,candidate,ladder){let found=new Map,add=(ref,spelling)=>{if(spelling===void 0)return;let key=keyOf(ref),known=found.get(key);(known===void 0||!known.exactSpelling&&spelling==="exact")&&found.set(key,{ref,exactSpelling:spelling==="exact"})};if(candidate.kind==="envVar"){if(ladder===void 0)return[];let variables=pool.filter(entry=>envNamesOf(entry,ladder).has(candidate.name)).map(entry=>entry.ref);return variables.length===0?[]:[{ref:carry2(candidate,{kind:"envVar",name:candidate.name,variables}),exactSpelling:!0}]}for(let variable of pool)switch(candidate.kind){case"repo":(candidate.name!==void 0||candidate.location!==void 0)&&add(carry2(candidate,repoRef(variable)),qualifies2(candidate,variable));break;case"namespace":add(carry2(candidate,namespaceRef2(variable)),both2(qualifies2(candidate.repo,variable),matchName(candidate.name,variable.recipe.namespace)));break;case"recipe":{let inNamespace=candidate.namespace===void 0?"exact":matchName(candidate.namespace.name,variable.recipe.namespace),spelling=both2(both2(qualifies2(candidate.namespace?.repo??candidate.repo,variable),inNamespace),matchName(candidate.name,variable.recipe.name));add(carry2(candidate,{...recipeRef2(variable),...candidate.range===void 0?{}:{range:candidate.range}}),spelling);break}case"variable":{let spelling=qualifies2(candidate.recipe?.namespace?.repo??candidate.recipe?.repo??candidate.repo,variable);candidate.recipe!==void 0&&(spelling=both2(spelling,matchName(candidate.recipe.name,variable.recipe.name)),candidate.recipe.namespace!==void 0&&(spelling=both2(spelling,matchName(candidate.recipe.namespace.name,variable.recipe.namespace)))),add(carry2(candidate,variable.ref),both2(spelling,matchName(candidate.name,variable.definition.name)));break}default:break}return[...found.values()].sort((left,right)=>keyOf(left.ref)<keyOf(right.ref)?-1:keyOf(left.ref)>keyOf(right.ref)?1:0)}function partsOf(ref){switch(ref.kind){case"repo":return{...ref.name===void 0?{}:{repo:ref.name}};case"namespace":return{...ref.repo?.name===void 0?{}:{repo:ref.repo.name},namespace:ref.name};case"recipe":{let repo=ref.namespace?.repo?.name??ref.repo?.name;return{...repo===void 0?{}:{repo},...ref.namespace===void 0?{}:{namespace:ref.namespace.name},recipe:ref.name}}case"variable":return ref.recipe===void 0?{...ref.repo?.name===void 0?{}:{repo:ref.repo.name}}:partsOf(ref.recipe);default:return{}}}function narrowTo(pool,match2){let target=match2.kind==="envVar"?match2.variables?.[0]:match2;if(target===void 0||target.kind==="recipeFile")return[];let{repo,namespace,recipe}=partsOf(target);return pool.filter(entry=>repo!==void 0&&entry.recipe.repo!==repo?!1:target.kind==="repo"?!0:namespace!==void 0&&entry.recipe.namespace!==namespace?!1:target.kind==="namespace"?!0:recipe!==void 0&&entry.recipe.name!==recipe?!1:target.kind==="recipe"?!0:entry.definition.name===target.name)}var SEE_ALL="Run 'sous vars' to see every variable this project's recipes define.";function describeSelection(input){let parts=[];input.repo!==void 0&&parts.push(`the repository '${input.repo}'`),input.namespace!==void 0&&parts.push(`the namespace '${input.namespace}'`),input.recipe!==void 0&&parts.push(`the recipe '${input.recipe}'`),input.name!==void 0&&parts.push(`'${input.name}'`);for(let wanted of input.var??[])parts.push(`the variable '${wanted}'`);return parts.length===0?input.all===!0?"every variable":"everything unanswered":parts.join(", ")}async function resolveSelection(pool,ladder,input,io){let{name,repo,namespace,recipe}=input,vars=input.var;if(name===void 0&&repo===void 0&&namespace===void 0&&recipe===void 0&&vars===void 0)return;let left=[...pool],pick3=(search2,kinds)=>pickOne(search2,left,ladder,kinds,input.acceptFirst===!0,io);if(repo!==void 0&&(left=narrowTo(left,await pick3(repo,["repo"]))),namespace!==void 0&&(left=narrowTo(left,await pick3(namespace,["namespace"]))),recipe!==void 0){let exact=left.filter(entry=>recipeKey(entry.recipe)===recipe);left=exact.length>0?exact:narrowTo(left,await pick3(recipe,["recipe"]))}if(name!==void 0&&(left=narrowTo(left,await pick3(name))),vars!==void 0){let chosen=[];for(let wanted of vars)chosen.push(...narrowTo(left,await pick3(wanted,["variable","envVar"])));left=chosen}if(left.length===0)throw new ConfigError41(`Nothing is left to ask: ${describeSelection({...input,all:!1})} names no variable this project holds.`,{details:[SEE_ALL]});return new Set(left.map(entry=>entry.key))}function candidatesFor(search2,pool,ladder,kinds,services){let readings;try{readings=services.get("refs.resolver").parse(search2,"commandLine").refs}catch{readings=[]}let found=new Map;for(let reading of readings)if(!(kinds!==void 0&&!kinds.includes(reading.kind)))for(let match2 of matchVariables(pool,reading,ladder)){let key=`${match2.ref.kind} ${JSON.stringify(match2.ref)}`;found.has(key)||found.set(key,{ref:match2.ref,exact:match2.exactSpelling})}let all=[...found.values()];return(all.some(entry=>entry.exact)?all.filter(entry=>entry.exact):all).flatMap(({ref})=>ref.kind==="envVar"&&(ref.variables?.length??0)>1?ref.variables.map(variable=>({...ref,variables:[variable]})):[ref])}async function pickOne(search2,pool,ladder,kinds,acceptFirst2,io){let candidates=candidatesFor(search2,pool,ladder,kinds,io.services);if(candidates.length===0)throw new ConfigError41(`Nothing called '${search2}' was found.`,{details:[SEE_ALL]});if(candidates.length===1)return candidates[0];try{return await io.services.get("refs.picker").pick(candidates,{search:search2,acceptFirst:acceptFirst2,announce:!1,details:[SEE_ALL]},io)}catch(error51){throw isSousErrorOfKind4(error51,"non-interactive")?ambiguityError(search2,error51):error51}}function ambiguityError(search2,cause){let error51=new NonInteractiveError5(cause.question,cause.answeredBy,{cause,details:cause.details,exitCode:1});return error51.message=`Sous has to ask which '${search2}' you meant, and it is not running where it can ask.`,error51}var FILE_FIELD={type:"string",description:"Read the variable definitions from a standalone definitions file instead of the project's recipes"};function definitionsLabel(file2){return file2??"the project's subscribed recipes"}function ladderFor(ctx){return buildLadder({services:ctx.services,env:ctx.env,config:ctx.config})}function listingOf(variable,ladder,hidden){let resolved=ladder.resolve(variable);return{variable,answered:resolved!==void 0,...resolved===void 0?{}:{value:displayValue(resolved.value,variable.definition.secret,hidden),source:resolved.source},storedAs:resolved?.source.envName??ladder.bareName(variable),storeIn:answerFileFor(variable.definition)}}function detailOf(variable,ladder,hidden){let diagnosis=ladder.diagnose(variable),checked3=diagnosis.resolved===void 0?void 0:validateAnswer(variable.definition,diagnosis.resolved.value,{recipe:recipeKey(variable.recipe)}),mapping=diagnosis.resolved?.source.rung==="mapping"?diagnosis.resolved.source.envName:void 0,shownDiagnosis=diagnosis.resolved===void 0||!variable.definition.secret?diagnosis:{...diagnosis,resolved:{...diagnosis.resolved,value:hidden}};return{...listingOf(variable,ladder,hidden),diagnosis:shownDiagnosis,constraints:constraintBullets(variable.definition),...checked3?.ok===!1?{problem:checked3.message}:{},...mapping===void 0?{}:{mapping:{envName:mapping,target:ladder.mappings[mapping]??""}}}}function variablesNamed(variables,name){let matches=variables.filter(entry=>namesVariable(entry,name));if(matches.length===0)throw new ConfigError42(`No variable named '${name}' is in play.`,{details:["Run 'sous vars list' to see every variable this project's recipes define."]});return matches}function storeFor(ctx){let env=ctx.services.get("config-files.env");return{envPath:file2=>env.paths()?.[file2]??(file2==="local"?".sous/.env.local":".sous/.env"),mappingPath:()=>ctx.services.get("confd.managed").path(VAR_MAPPINGS_FILE),writeAnswer:async(file2,envName,value,comment)=>{await env.write(file2,{[envName]:value},{comment})},writeMapping:async(envName,target)=>{let mappings=ctx.services.get("recipe-answers.mappings");return(await mappings.set(envName,mappings.parseTarget(target))).file}}}async function handleAsk(input,ctx){let dryRun4=input.dryRun===!0,hidden=hiddenValue(ctx.services),store2=storeFor(ctx),root=ctx.project?.root??ctx.cwd??".",envFile=input.envFile===void 0?void 0:resolveEnvFile(input.envFile,{shared:store2.envPath("shared"),local:store2.envPath("local")},root,ctx.cwd??root);ctx.reporter.variables([{label:"Definitions",value:definitionsLabel(input.file)},{label:"Asking",value:describeSelection(input)},...envFile===void 0?[]:[{label:"Env file",value:store2.envPath(envFile)}]]),dryRun4&&ctx.reporter.dryRun("No answers will be written.");let preanswers=ctx.services.get("recipe-answers.preanswers"),provided=await preanswers.read(input.answersFile===void 0?input:{...input,answersFile:resolveUserPath(input.answersFile,ctx)}),variables=await ctx.services.get("recipe-answers.definitions").list(input.file===void 0?{}:{file:resolveUserPath(input.file,ctx)});if(variables.length===0){if(provided[0]!==void 0)throw unknownAnswerError(provided[0],variables);let empty={answered:[],inherited:[],skipped:[],dryRun:dryRun4};return new IntentOutputs10([new IntentOutput9({title:"Answering variables"}),new IntentOutput9({result:new TextBlock6("No recipe in this project defines any variables yet, so there is nothing to ask. Subscribe to a recipe that publishes some, or read a definitions file with --file."),style:ReportEntryStyle4.Note})]).withData(empty)}let ladder=ladderFor(ctx),only=await resolveSelection(variables,ladder,input,ctx),run={prompter:ctx.prompter,reporter:ctx.reporter,store:store2,hidden,dryRun:dryRun4,...envFile===void 0?{}:{envFile},yes:input.yes===!0},given=await storeGivenAnswers(preanswers.match(provided,variables),ladder,run),report=await askForMissing(variables,ladder,{...only===void 0?{}:{only},...input.within===void 0?{}:{within:new Set(input.within)},skip:given.keys,reask:input.all===!0},run),result={answered:[...given.stored,...report.answered],inherited:report.inherited.map(({variable,resolved})=>({variable,resolved:variable.definition.secret?{...resolved,value:hidden}:resolved})),skipped:report.skipped,dryRun:dryRun4};!dryRun4&&result.answered.some(entry=>entry.outcome!=="not written")&&ctx.configChanged();let entries=result.answered.length>0||result.inherited.length>0||result.skipped.length>0?askReportOutputs(result,hidden):[];return new IntentOutputs10([new IntentOutput9({title:"Answering variables"}),...entries]).withData(result)}async function handleList(input,ctx){let variables=await ctx.services.get("recipe-answers.definitions").list(input.file===void 0?{}:{file:resolveUserPath(input.file,ctx)}),ladder=ladderFor(ctx),hidden=hiddenValue(ctx.services),opening=commandVariables2(ctx,{Definitions:definitionsLabel(input.file)});if(input.name!==void 0){let details=variablesNamed(variables,input.name).map(variable=>detailOf(variable,ladder,hidden)),shown=details.flatMap(detail=>variableDetailOutputs(detail,hidden,ctx.project?.sousDir));return new IntentOutputs10([opening,...shown]).withData({variables:details})}let listings=variables.map(variable=>listingOf(variable,ladder,hidden));return new IntentOutputs10([opening,variableListOutput(listings,hidden)]).withData({variables:listings})}async function handleShow(input,ctx){let variables=await ctx.services.get("recipe-answers.definitions").list(input.file===void 0?{}:{file:resolveUserPath(input.file,ctx)}),matches=variablesNamed(variables,input.name),ladder=ladderFor(ctx),hidden=hiddenValue(ctx.services),opening=commandVariables2(ctx,{Definitions:definitionsLabel(input.file)}),outputsOf2=variable=>{let detail=detailOf(variable,ladder,hidden);return new IntentOutputs10([opening,...variableDetailOutputs(detail,hidden,ctx.project?.sousDir)]).withData(detail)};if(matches.length===1)return outputsOf2(matches[0]);let picked=await ctx.services.get("refs.picker").pick(matches.map(entry=>entry.ref),{search:input.name,acceptFirst:input.acceptFirst===!0,announce:!1,details:[SEE_ALL]},ctx),chosen=matches.find(entry=>entry.ref===picked)??matches.find(entry=>JSON.stringify(entry.ref)===JSON.stringify(picked))??matches[0];return outputsOf2(chosen)}async function handleMap(input,ctx){let mappings=ctx.services.get("recipe-answers.mappings"),dryRun4=input.dryRun===!0;if(input.remove===!0){let{file:file3,changed:changed2}=await mappings.remove(input.envName,{dryRun:dryRun4});changed2&&!dryRun4&&ctx.configChanged();let removal=changed2?`${dryRun4?"Would remove":"Removed"} the mapping of ${input.envName} in ${file3}.`:`${input.envName} has no mapping in ${file3}.`;return IntentOutputs10.of({envName:input.envName,file:file3,changed:changed2,dryRun:dryRun4},{summary:removal})}if(input.target===void 0)throw new InputError5("vars.map",[{path:"target",message:"Name the variable to bind, as 'namespace/recipe/variableName', or pass --remove."}]);let target=mappings.formatTarget(mappings.parseTarget(input.target)),{file:file2,changed}=await mappings.set(input.envName,mappings.parseTarget(target),{dryRun:dryRun4});return changed&&!dryRun4&&ctx.configChanged(),IntentOutputs10.of({envName:input.envName,target,file:file2,changed,dryRun:dryRun4},{summary:changed?`${dryRun4?"Would map":"Mapped"} ${input.envName} to ${target} in ${file2}.`:`${input.envName} is already mapped to ${target}.`})}var varsIntents=[{intent:"vars.ask",summary:"Answer the variables this project's recipes define, storing the answers in the .sous env files",description:"Asks only what is unanswered or no longer fits; --all asks everything again. The name may be a variable, an environment variable name, a recipe, a namespace or a repository. Every question can be answered ahead of time with --answer <name>=<value> or --answers-file.",input:jsonSchema15({type:"object",properties:{name:{type:"string",description:"What to ask about: a variable, an environment variable name, a recipe, a namespace or a repository"},all:{type:"boolean",default:!1,description:"Ask every variable again, including the ones already answered"},repo:{type:"string",description:"Ask only the variables published by this repository"},namespace:{type:"string",description:"Ask only the variables published in this namespace"},recipe:{type:"string",description:"Ask only the variables published by this recipe (namespace/recipe)"},var:{type:"array",items:{type:"string"},description:"Ask only this variable. Repeat it for each variable"},within:{type:"array",items:{type:"string"},description:"Ask only what the recipes named here (namespace/recipe) still need"},acceptFirst:{type:"boolean",default:!1,description:"When a name matches several things, take the first one listed"},file:FILE_FIELD,dryRun:{type:"boolean",default:!1,description:"Report what would be asked and written, without writing anything"},answer:{type:"array",items:{type:"string"},description:"Answer a variable ahead of its question, as <name>=<value>. Repeat it for each answer"},answersFile:{type:"string",description:"Read answers from a YAML, JSON or .env file of name: value pairs"},envFile:{type:"string",description:"Write every answer of this run to this env file: .sous/.env (committed) or .sous/.env.local (this machine only)"},yes:{type:"boolean",default:!1,description:"Answer yes to storing a secret or machine-specific answer in the committed .sous/.env"}},additionalProperties:!1}),cli:{command:["vars","ask"],aliases:[["var","ask"]],positional:["name"],examples:["sous vars ask","sous vars ask apiUrl","sous vars ask SOUS_VAR_API_URL","sous vars ask workflow/task-files","sous vars ask workflow --accept-first","sous vars ask --namespace workflow --var apiUrl","sous vars ask --all","sous vars ask --file ./questions.yaml","sous vars ask --answer apiUrl=https://api.example.com","sous vars ask --answers-file ./answers.yaml","sous vars ask --env-file .env.local"],flags:{within:{hidden:!0},yes:{short:"y",aliases:["force"]}}},agent:{usage:"Pass every answer with `answer` (name=value pairs) or `answersFile`; questions cannot be asked through MCP unless the client supports elicitation."},requiresProject:!0,handle:handleAsk},{intent:"vars.list",summary:"List every variable this project's recipes define, with its answer",input:jsonSchema15({type:"object",properties:{name:{type:"string",description:"A variable's name (or its namespace/recipe.name key) to show in full"},file:FILE_FIELD},additionalProperties:!1}),parallel:!0,cli:{command:["vars","list"],aliases:[["var","list"],["vars"]],positional:["name"],examples:["sous vars","sous vars apiUrl","sous vars list","sous vars list --file ./questions.yaml"]},requiresProject:!0,handle:handleList},{intent:"vars.show",summary:"Show everything about one variable, including how it was answered",input:jsonSchema15({type:"object",properties:{name:{type:"string",description:"A variable's name, or its namespace/recipe.name key"},file:FILE_FIELD,acceptFirst:{type:"boolean",default:!1,description:"When the name matches several variables, take the first one listed"}},required:["name"],additionalProperties:!1}),parallel:!0,cli:{command:["vars","show"],aliases:[["var","show"]],positional:["name"],examples:["sous vars show apiUrl","sous vars show workflow/task-files.apiUrl"]},requiresProject:!0,handle:handleShow},{intent:"vars.map",summary:"Bind an environment variable to one recipe variable, in conf.d/520-var-mappings.jsonc",input:jsonSchema15({type:"object",properties:{envName:{type:"string",description:"The environment variable name, in upper snake case"},target:{type:"string",description:"The variable it answers: namespace/recipe/variableName, optionally repo:-qualified"},remove:{type:"boolean",default:!1,description:"Remove the mapping instead"},dryRun:{type:"boolean",default:!1,description:"Report what would change, without writing anything"}},required:["envName"],additionalProperties:!1}),changesConfig:!0,cli:{command:["vars","map"],aliases:[["var","map"]],positional:["envName","target"],examples:["sous vars map TEAM_API_URL sous-recipes:misc/stuff/apiUrl","sous vars map TEAM_API_URL --remove"]},requiresProject:!0,handle:handleMap}];var VARIABLES_TAG="variables",variableLookup={id:"recipe-answers.variables",description:"the variables the active recipes define",kinds:["repo","namespace","recipe","variable"],tags:[VARIABLES_TAG],optIn:!0,find:async(candidate,ctx)=>variableLookup.findSync(candidate,ctx),findSync:(candidate,ctx)=>matchVariables(ctx.services.get("recipe-answers.definitions").listSync(),candidate)},envVarLookup={id:"recipe-answers.env-vars",description:"the environment variable names that answer recipe variables",kinds:["envVar"],tags:[VARIABLES_TAG],optIn:!0,find:async(candidate,ctx)=>envVarLookup.findSync(candidate,ctx),findSync:(candidate,ctx)=>matchVariables(ctx.services.get("recipe-answers.definitions").listSync(),candidate,buildLadder({services:ctx.services,env:ctx.env,config:ctx.config}))};var VARIABLE_SOURCE_ID="recipe-answers",FORBIDDEN_UNDER=["subscriptions","repos"];function recipeAnswersSource(variables,services){let answers=ctx=>computeAnswers(variables,buildLadder({services,env:ctx.env,config:ctx.config}));return{id:VARIABLE_SOURCE_ID,description:"recipe answers",variables:ctx=>variables.length===0?{}:answers(ctx).merged,scoped:(scopeKey,ctx)=>{if(variables.some(entry=>`${entry.recipe.namespace}/${entry.recipe.name}`===scopeKey))return answersForRecipe(answers(ctx),scopeKey)},secrets:()=>variables.filter(entry=>entry.definition.secret).map(entry=>entry.definition.name),forbiddenUnder:FORBIDDEN_UNDER}}function variableSourceContributor(services){return{id:"recipe-answers.variable-source",after:["@sous-io/plugin-recipes"],contribute(config2){let variables=definitionsFromRecipes(config2.entities("active-recipe"));config2.addEntity("variable-source",recipeAnswersSource(variables,services))}}}var package_default13={name:"@sous-io/plugin-recipe-answers",version:"1.0.12",description:"Recipe variable definitions, the answer ladder, asking for answers, answer files and variable mappings.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/plugin-confd":"workspace:*","@sous-io/plugin-config-files":"workspace:*","@sous-io/plugin-formats":"workspace:*","@sous-io/plugin-refs":"workspace:*","@sous-io/plugin-variables":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME12="@sous-io/plugin-recipe-answers",recipeAnswersPlugin=definePlugin13({name:PLUGIN_NAME12,version:package_default13.version,description:"Recipe variable definitions, the answer ladder, asking for answers, answer files and variable mappings.",dependsOn:{"@sous-io/plugin-recipes":`^${package_default13.version}`,"@sous-io/plugin-confd":`^${package_default13.version}`,"@sous-io/plugin-config-files":`^${package_default13.version}`,"@sous-io/plugin-formats":`^${package_default13.version}`,"@sous-io/plugin-refs":`^${package_default13.version}`,"@sous-io/plugin-variables":`^${package_default13.version}`},register(sous){sous.services.add("recipe-answers.definitions",(_config,ctx)=>new DefinitionsService(ctx),{lifetime:"config"}),sous.services.add("recipe-answers.ladder",(config2,ctx)=>buildLadder({services:ctx.services,env:ctx.env,config:config2}),{lifetime:"config"}),sous.services.add("recipe-answers.answers",(_config,ctx)=>new AnswersService(()=>computeAnswers(ctx.services.get("recipe-answers.definitions").listSync(),ctx.services.get("recipe-answers.ladder"))),{lifetime:"config"}),sous.services.add("recipe-answers.preanswers",(_config,ctx)=>new PreanswersService(ctx),{lifetime:"factory"}),sous.services.add("recipe-answers.mappings",(_config,ctx)=>new MappingsService(ctx),{lifetime:"config"}),sous.services.add("recipe-answers.validator",()=>validator,{lifetime:"singleton"}),sous.entities.add("config-key",{id:"varMappings",description:"Environment variable names bound to recipe variables (conf.d/520-var-mappings.jsonc).",schema:jsonSchema16({type:"object",additionalProperties:{type:"string"},default:{}})}),sous.entities.add("ref-lookup",variableLookup),sous.entities.add("ref-lookup",envVarLookup),sous.config.contribute(variableSourceContributor(sous.services));for(let intent of varsIntents)sous.intents.add(intent)}});import{definePlugin as definePlugin14}from"@sous-io/plugin-api";import path62 from"node:path";function transformIdFor(targetId){return`skills/${targetId}`}function outputDir(directory){let trimmed=directory.trim();if(path62.isAbsolute(trimmed))return stripTrailingSlash(path62.normalize(trimmed));if(trimmed.startsWith("${"))return stripTrailingSlash(trimmed);let relative4=path62.posix.normalize(trimmed.split(path62.sep).join("/"));return relative4==="."?"${projectRoot}":`\${projectRoot}/${stripTrailingSlash(relative4.replace(/^\.\//,""))}`}function skillDestinations(outputs,targets){let destinations=[],seen=new Set;for(let target of targets){if(typeof target.directory!="string"||target.directory.trim()==="")continue;let dir=outputDir(target.directory);seen.has(dir)||(seen.add(dir),destinations.push(typeof target.transform=="function"?{dir,target:target.id,transform:transformIdFor(target.id)}:{dir,target:target.id}))}for(let output of outputs){let dir=outputDir(output);seen.has(dir)||(seen.add(dir),destinations.push({dir}))}return destinations}function stripTrailingSlash(value){return value.length>1&&value.endsWith("/")?value.slice(0,-1):value}import{jsonSchema as jsonSchema17}from"@sous-io/plugin-api";var SKILLS_KEY="recipes.skills",stringList2={type:"array",items:{type:"string"},default:[]},skillsConfigKey={id:SKILLS_KEY,description:"Where skills go (outputs, `${var}` allowed) and directories of your own skills (include).",schema:jsonSchema17({type:"object",properties:{outputs:{...stringList2,description:"Directories skills are also written to."},include:{...stringList2,description:"Directories of your own skills, compiled like a recipe's."}},additionalProperties:!1,default:{}})};function stringsOf(value){return Array.isArray(value)?value.filter(item=>typeof item=="string"&&item.trim()!==""):[]}function describeNowhere(sources){let recipes=new Set(sources.flatMap(source=>source.recipe===void 0?[]:[source.recipe])).size,own=sources.filter(source=>source.origin==="project").length,parts=[];if(recipes>0&&parts.push(`the skills of ${recipes} ${recipes===1?"recipe":"recipes"}`),own>0&&parts.push(`${own} ${own===1?"skill":"skills"} of your own`),parts.length!==0)return{summary:`Skipped ${parts.join(" and ")}: nothing says where skills go.`,hint:"Set recipes.skills.outputs in the config, or enable an agent plugin (such as @sous-io/plugin-claude-code)."}}function skillWarnings(ctx){if(!ctx.services.has("skills.sources"))return[];let sources=ctx.services.get("skills.sources"),warnings=(sources.problems?.()??[]).map(summary=>({summary}));if(skillDestinations(stringsOf(ctx.config.get("recipes.skills.outputs")),ctx.entities.list("skill-target")).length===0){let nowhere=describeNowhere(sources.list());nowhere&&warnings.push(nowhere)}return warnings}import fs45 from"node:fs";import path63 from"node:path";function bytewise(a,b){return a<b?-1:a>b?1:0}function findSkills(input){let skills=[],problems=[];for(let content of input.contents.of(input.recipes,"skills"))skills.push(...recipeSkills(content));return input.include.forEach((entry,index)=>{let setting=`recipes.skills.include[${index}]`,dir=resolveProjectDir(entry,input.project);if(typeof dir!="string"){problems.push({setting,message:`${setting} is "${entry}": ${dir.reason}`});return}if(!isDirectory2(dir)){problems.push({setting,message:`${setting} is "${entry}", which is not a directory, so it was skipped.`});return}skills.push(...groupSkills({origin:"project"},[{base:dir,files:listFiles(dir,"**/*",[])}]))}),{skills,problems}}function recipeSkills(content){let byBase=new Map;for(let{base,file:file2}of content.files)byBase.set(base,[...byBase.get(base)??[],file2]);return groupSkills({origin:"recipe",recipe:content.recipe.id,repository:content.recipe.repo},[...byBase].map(([base,files])=>({base,files})))}function groupSkills(from,groups){let byDir=new Map;for(let group of groups)for(let file2 of group.files){let relative4=path63.relative(group.base,file2);if(relative4===""||relative4.startsWith("..")||path63.isAbsolute(relative4))continue;let[first2]=relative4.split(path63.sep),nested=relative4!==first2,dir=nested?path63.join(group.base,first2):group.base,name=nested?first2:withoutExtensions(first2),key=`${dir}\0${nested?"":name}`,skill=byDir.get(key);skill||(skill={name,base:group.base,files:new Set},byDir.set(key,skill)),skill.files.add(path63.relative(dir,file2).split(path63.sep).join("/"))}return[...byDir.entries()].map(([key,skill])=>({name:skill.name,...from,dir:key.slice(0,key.indexOf("\0")),base:skill.base,files:[...skill.files].sort(bytewise)})).sort((a,b)=>bytewise(a.name,b.name)||bytewise(a.dir,b.dir))}function listFiles(cwd,pattern,exclude){return isDirectory2(cwd)?ts(pattern,{cwd,absolute:!0,nodir:!0,ignore:[...exclude]}).filter(isFile9).sort(bytewise):[]}function resolveProjectDir(entry,project){let substituted=entry.replace(/\$\{(projectRoot|sousDir)\}/g,(_match,name)=>project?name==="projectRoot"?project.root:project.sousDir:_match);return/\$\{[^}]*\}/.test(substituted)?{reason:project?"only ${projectRoot} and ${sousDir} can be used here, so it was skipped.":"there is no project to resolve it in, so it was skipped."}:path63.isAbsolute(substituted)?path63.normalize(substituted):project?path63.resolve(project.root,substituted):{reason:"a relative directory needs a project, and there is none, so it was skipped."}}function withoutExtensions(name){let dot=name.indexOf(".",1);return dot===-1?name:name.slice(0,dot)}function isDirectory2(candidate){try{return fs45.statSync(candidate).isDirectory()}catch{return!1}}function isFile9(candidate){try{return fs45.statSync(candidate).isFile()}catch{return!1}}var ConfigSkillsSources=class{constructor(config2,ctx){this.config=config2;this.ctx=ctx}found;list(){return this.find().skills.map(({base:_base,...source})=>source)}recipes(){return[...new Set(this.find().skills.flatMap(skill=>skill.recipe===void 0?[]:[skill.recipe]))]}problems(){return this.find().problems.map(problem=>problem.message)}find(){return this.found??=findSkills({recipes:this.ctx.entities.list("active-recipe"),contents:this.ctx.services.get("recipes.contents"),include:stringsOf(this.config.get("recipes.skills.include")),project:this.ctx.project}),this.found}};import{jsonSchema as jsonSchema18}from"@sous-io/plugin-api";var SKILL_TARGET="skill-target",skillTargetSchema=jsonSchema18({type:"object",properties:{id:{type:"string",description:"The target's name: `claude-code`."},harness:{type:"string",description:"The `harness` entity that reads it."},directory:{type:"string",description:"The directory skills go into; relative paths are under the project root."},description:{type:"string"}},required:["id","directory"]}),SKILL_TARGET_DESCRIPTION="A place a harness reads skills from, with an optional transform of each file.";import path64 from"node:path";var TARGETS_CONTRIBUTOR="skills.targets";function contributeSkillTargets(config2,plugin,contents){let outputs=stringsOf(config2.atPath("recipes.skills.outputs").get()),include=stringsOf(config2.atPath("recipes.skills.include").get()),targets=config2.entities("skill-target"),recipes=config2.entities("active-recipe"),destinations=skillDestinations(outputs,targets);if(destinations.length===0)return;let{skills}=findSkills({recipes,contents,include,project:config2.project});if(skills.length===0)return;let origins=new Map,list2=config2.atPath("compilation.targets");for(let skill of skills)for(let file2 of skill.files){let entryPoint=path64.join(skill.dir,file2);origins.set(entryPoint,skill.recipe===void 0?{skill:skill.name}:{skill:skill.name,recipe:skill.recipe}),list2.append(compilationTarget(skill,entryPoint,destinations,plugin,config2.project?.root))}for(let target of targets)typeof target.transform=="function"&&destinations.some(d=>d.target===target.id)&&config2.addEntity("compilation-transform",transformEntity(target,origins))}function compilationTarget(skill,entryPoint,destinations,plugin,projectRoot){let fromBase=path64.relative(skill.base,entryPoint).split(path64.sep).join("/");return{id:`skills/${skill.recipe??`project:${projectRoot?path64.relative(projectRoot,skill.base).split(path64.sep).join("/")||".":skill.base}`}/${fromBase}`,entryPoint,globBase:skill.base,origin:{plugin,...skill.recipe===void 0?{}:{recipe:skill.recipe},...skill.repository===void 0?{}:{repository:skill.repository}},outputs:destinations.map(destination=>destination.transform?{destinationDir:destination.dir,transforms:[destination.transform]}:{destinationDir:destination.dir})}}function transformEntity(target,origins){let transform2=target.transform;return{id:transformIdFor(target.id),description:`The transform of the skill target "${target.id}".`,async transform(file2,ctx){let origin=origins.get(file2.source)??{skill:path64.basename(path64.dirname(file2.source))},skillFile={...file2,...origin};return transform2(skillFile,ctx)}}}var package_default14={name:"@sous-io/plugin-skills",version:"1.0.12",description:"Skills: where they come from, the skill-target entity, and the compilation targets for them.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-compiler":"workspace:*","@sous-io/plugin-recipes":"workspace:*",glob:"^13.0.6"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME13="@sous-io/plugin-skills",skillsPlugin=definePlugin14({name:PLUGIN_NAME13,version:package_default14.version,description:"Skills: where they come from, the skill-target entity, and the compilation targets for them.",dependsOn:{"@sous-io/plugin-compiler":`^${package_default14.version}`,"@sous-io/plugin-recipes":`^${package_default14.version}`},register(sous){sous.entities.define(SKILL_TARGET,skillTargetSchema,{description:SKILL_TARGET_DESCRIPTION}),sous.entities.add("config-key",skillsConfigKey),sous.services.add("skills.sources",(config2,ctx)=>new ConfigSkillsSources(config2,ctx),{lifetime:"config"});let services=sous.services;sous.config.contribute({id:TARGETS_CONTRIBUTOR,after:["@sous-io/plugin-recipes"],contribute:config2=>contributeSkillTargets(config2,PLUGIN_NAME13,services.get("recipes.contents"))}),sous.on("compiler.compile.before",(_event,ctx)=>{for(let warning of skillWarnings(ctx))ctx.reporter.problem(warning.summary,warning.hint===void 0?{}:{hint:warning.hint})})}});import{definePlugin as definePlugin15}from"@sous-io/plugin-api";import path65 from"node:path";import{ConfigError as ConfigError43}from"@sous-io/plugin-api";function isRegexSpelling(entry){return entry.length>=3&&entry.startsWith("/")&&entry.endsWith("/")}function compileEntry(entry,where2,isMatch){if(!isRegexSpelling(entry))return key=>isMatch(key,entry);let expression;try{expression=new RegExp(entry.slice(1,-1))}catch(error51){let reason=error51 instanceof Error?error51.message:String(error51);throw new ConfigError43(`The value ${JSON.stringify(entry)} in '${where2}' is written as a regular expression, but it is not a valid one: ${reason}`)}return key=>expression.test(key)}function compileRecipeKeyMatcher(entries,where2,isMatch){let matchers=(entries??[]).map(entry=>compileEntry(entry,where2,isMatch));return recipeKey2=>matchers.some(matches=>matches(recipeKey2))}function compileRecipeKeyFinder(entries,where2,isMatch){let matchers=(entries??[]).map(entry=>compileEntry(entry,where2,isMatch));return recipeKey2=>{let index=matchers.findIndex(matches=>matches(recipeKey2));return index===-1?void 0:`${where2}[${index}]`}}var FIRST_KEY="recipes.memories.first",EXCLUDE_KEY="recipes.memories.exclude";function dependencyOrder(recipes,compare){let waitingOn=new Map;for(let recipe of recipes)waitingOn.set(recipe.id,new Set);for(let dependency of recipes)for(let holder of dependency.requestedBy)holder!==dependency.id&&waitingOn.get(holder)?.add(dependency.id);let ordered2=[],done2=new Set,remaining=[...waitingOn.keys()].sort(compare);for(;remaining.length>0;){let index=remaining.findIndex(key2=>[...waitingOn.get(key2)].every(dep=>done2.has(dep)));if(index===-1){ordered2.push(...remaining);break}let[key]=remaining.splice(index,1);ordered2.push(key),done2.add(key)}return ordered2}function recipeMemories(recipe,globs,contents,onWarning=()=>{}){let byFile=new Map;for(let content of contents.of([recipe],"memories"))for(let{file:file2,base}of content.files)if(!byFile.has(file2)){if(globs.realPathInside(file2,recipe.dir)===void 0){onWarning(`The memory ${file2} of the recipe ${recipe.id} was left out, because it is a link that leads outside the recipe's directory. Replace the link with the file itself.`);continue}byFile.set(file2,{recipe:recipe.id,repository:recipe.repo,name:globs.toPosix(path65.relative(base,file2)),path:file2})}return[...byFile.values()].sort((a,b)=>globs.compareBytewise(a.name,b.name))}function selectMemories(options){let{recipes,globs,contents}=options,isMatch=(key,pattern)=>globs.isMatch(key,pattern),isFirst=compileRecipeKeyMatcher(options.settings?.first,FIRST_KEY,isMatch),excludedBy=compileRecipeKeyFinder(options.settings?.exclude,EXCLUDE_KEY,isMatch),byKey=new Map(recipes.map(recipe=>[recipe.id,recipe])),order=dependencyOrder(recipes,(a,b)=>globs.compareBytewise(a,b)),leading=order.filter(key=>isFirst(key)),rest=order.filter(key=>!isFirst(key)),selected=[],excluded=[];for(let key of[...leading,...rest]){let recipe=byKey.get(key),memories=recipeMemories(recipe,globs,contents,options.onWarning),by2=excludedBy(key);by2===void 0?selected.push(...memories):excluded.push(...memories.map(memory=>({memory,by:by2})))}return{selected,excluded}}function viewPath(memory){return`${memory.recipe}/${memory.name}`}var memoriesHashName={id:"memories",description:"the memories of every active recipe, listed in dependency order as #memories/<namespace>/<recipe>/<path>.",view:ctx=>ctx.services.get("memories.selection").selected().map(memory=>({path:viewPath(memory),file:memory.path}))};import{jsonSchema as jsonSchema19}from"@sous-io/plugin-api";function refine2(base,extra){let standard=base["~standard"];return{"~standard":{...standard,validate(value){let result=standard.validate(value);if(result.issues)return result;let issues=extra(result.value);return issues.length>0?{issues}:result}}}}var memoryTargetSchema=refine2(jsonSchema19({type:"object",required:["id","fileName"],properties:{id:{type:"string",description:"The target's id: `claude-code`."},harness:{type:"string",description:"The `harness` entity that reads the file."},fileName:{type:"string",description:"The file name: `CLAUDE.md`, `AGENTS.md`."},readIn:{enum:["project-root","any-directory"],default:"project-root",description:"Where the harness reads the file; `any-directory` also makes it a pointer file."},directory:{type:"string",description:"Where the file is written, relative to the project root."}}}),target=>["filter","format"].filter(name=>target[name]!==void 0&&typeof target[name]!="function").map(name=>({path:[name],message:"Expected a function."})));function keyListIssues(entries,where2,key){return entries.flatMap((entry,index)=>{try{return compileRecipeKeyMatcher([entry],`${where2}[${index}]`,()=>!1),[]}catch(error51){return[{path:[key,index],message:error51 instanceof Error?error51.message:String(error51)}]}})}var memoriesSettingsSchema=refine2(jsonSchema19({type:"object",additionalProperties:!1,properties:{first:{type:"array",items:{type:"string"},default:[],description:"Recipe keys, globs or /regular expressions/ whose memories come first, in this order."},exclude:{type:"array",items:{type:"string"},default:[],description:"Recipe keys, globs or /regular expressions/ whose memories are left out."}},default:{},description:"Which recipe memories memory targets and the #memories view take, and in what order."}),settings=>[...keyListIssues(settings.first,FIRST_KEY,"first"),...keyListIssues(settings.exclude,EXCLUDE_KEY,"exclude")]);import{NotFoundError as NotFoundError7}from"@sous-io/plugin-api";init_src();import{nullReporter as nullReporter4,Reporting as Reporting3,SousError as SousError24}from"@sous-io/plugin-api";var BuiltConfigBuilder=class extends Reporting3(Object){constructor(config2,ctx,contributorId2){super();this.config=config2;this.ctx=ctx;this.document=createDocument(config2.value()),this.contributor={id:contributorId2,plugin:ctx.plugin,stage:0,pass:0,run:0},this.project=ctx.project,this.env=ctx.env}contributor;project;env;document;get reporter(){return nullReporter4}log(){}root(){return this.document.root()}atPath(input){return this.document.atPath(input)}entities(kind){return this.ctx.entities.list(kind)}entity(kind,id){return this.ctx.entities.get(kind,id)}addEntity(){throw new SousError24("A memory target's filter cannot add entities after the config is built.")}previousPatches(){}apply(){}options(){return this.config.get(["plugins","options"])?.[this.ctx.plugin]}};function builderOver(config2,ctx,contributorId2){return new BuiltConfigBuilder(config2,ctx,contributorId2)}var TARGETS_CONTRIBUTOR2="memories.targets";function compilationTargetId(target){return`memories/${target.id}`}function pointerFileId(target){return`memories/${target.id}`}function defaultFormat(memories){return memories.map(memory=>`@${memory.path}`).join(`
934
935
 
935
- `)}function memoriesForTarget(target,selected,config2){return target.filter?selected.filter(memory=>target.filter(memory,config2)):[...selected]}function destinationFile(target){let directory=(target.directory??"").replace(/^\.?\/+|\/+$/g,"");return directory===""?`\${projectRoot}/${target.fileName}`:`\${projectRoot}/${directory}/${target.fileName}`}function compilationTargetFor(target,selected,config2,plugin){let memories=memoriesForTarget(target,selected,config2),content=target.format?target.format(memories,config2):defaultFormat(memories);if(content!=="")return{id:compilationTargetId(target),content,origin:{plugin},outputs:[{destinationFile:destinationFile(target)}]}}function readSettings(config2){let value=config2.atPath(["recipes","memories"]).get();return value!==null&&typeof value=="object"?value:{}}function targetsContributor(plugin,services){let warned=new Set;return{id:TARGETS_CONTRIBUTOR2,contribute(config2){let targets=config2.entities("memory-target");for(let target of targets)target.readIn==="any-directory"&&config2.addEntity("pointer-file",{id:pointerFileId(target),fileName:target.fileName});if(targets.length===0)return;let globs=services.get("host.globs"),{selected}=selectMemories({recipes:config2.entities("active-recipe"),settings:readSettings(config2),globs,contents:services.get("recipes.contents"),onWarning:message2=>{warned.has(message2)||(warned.add(message2),config2.warn(message2))}});for(let target of targets){let compilation=compilationTargetFor(target,selected,config2,plugin);compilation&&config2.atPath(["compilation","targets"]).appendValue(compilation)}}}}var MemoriesSelectionService=class{constructor(config2,ctx){this.config=config2;this.ctx=ctx}result;selected(){return[...this.select().selected]}forTarget(targetId){let target=this.ctx.entities.get("memory-target",targetId);if(!target)throw new NotFoundError7("memory-target",targetId,`No memory target "${targetId}" exists.`);let builder=builderOver(this.ctx.config,this.ctx,TARGETS_CONTRIBUTOR2);return memoriesForTarget(target,this.select().selected,builder)}excluded(){return[...this.select().excluded]}select(){return this.result??=selectMemories({recipes:this.ctx.entities.list("active-recipe"),settings:this.config.get(["recipes","memories"]),globs:this.ctx.services.get("host.globs"),contents:this.ctx.services.get("recipes.contents")}),this.result}};var package_default15={name:"@sous-io/plugin-memories",version:"1.0.11",description:"Memories: selecting them, the memory-target entity, the compilation targets for them, the #memories name.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/documents":"workspace:*","@sous-io/plugin-api":"workspace:*","@sous-io/plugin-compiler":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/plugin-refs":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*",glob:"^13.0.6",minimatch:"^10.2.4"},engines:{node:">=22"}};var PLUGIN_NAME14="@sous-io/plugin-memories",memoriesPlugin=definePlugin15({name:PLUGIN_NAME14,version:package_default15.version,description:"Memories: selecting them, the memory-target entity, the compilation targets for them, the #memories name.",dependsOn:{"@sous-io/plugin-compiler":`^${package_default15.version}`,"@sous-io/plugin-recipes":`^${package_default15.version}`,"@sous-io/plugin-refs":`^${package_default15.version}`,"@sous-io/plugin-host":`^${package_default15.version}`},register(sous){sous.entities.define("memory-target",memoryTargetSchema,{description:"A file a harness reads into every session, built from the selected recipe memories."}),sous.entities.add("config-key",{id:"recipes.memories",schema:memoriesSettingsSchema,description:"Which recipe memories go to memory targets and the #memories view, and in what order."}),sous.entities.add("hash-name",memoriesHashName),sous.services.add("memories.selection",(config2,ctx)=>new MemoriesSelectionService(config2,ctx),{lifetime:"config"}),sous.config.contribute(targetsContributor(PLUGIN_NAME14,sous.services))}});init_pid();import{definePlugin as definePlugin16}from"@sous-io/plugin-api";init_schemas3();import fs47 from"node:fs";import path67 from"node:path";var UNKNOWN_BRANCH="unknown",RUNTIME_CONTEXT_SOURCE="runtime-context",RuntimeContextService=class{constructor(deps){this.deps=deps}settings(){return this.deps.settings}async generate(){let settings=this.deps.settings;if(!settings)return;let branch=await this.readBranch(settings.gitRoot),pattern=new RegExp(settings.branchPattern??DEFAULT_BRANCH_PATTERN),taskFile,taskContent;branch!==void 0&&pattern.test(branch)&&(taskFile=path67.join(settings.taskFileRoot,`${branch}.md`),taskContent=readIfExists(taskFile));let content=renderRuntimeContext({branch:branch??UNKNOWN_BRANCH,matched:taskFile!==void 0,...taskFile===void 0?{}:{taskFile},...taskContent===void 0?{}:{taskContent}});return{...branch===void 0?{}:{branch},...taskFile!==void 0&&taskContent!==void 0?{taskFile}:{},outputPath:settings.outputPath,content}}async write(options={}){let context=await this.generate();if(context)return this.deps.writer().write(context.outputPath,context.content,{source:RUNTIME_CONTEXT_SOURCE,origin:{plugin:this.deps.plugin},...options.dryRun?{dryRun:!0}:{}})}async readBranch(gitRoot){try{return await this.deps.git().currentBranch(gitRoot)}catch{return}}};function readIfExists(file2){try{return fs47.readFileSync(file2,"utf8")}catch{return}}function renderRuntimeContext(facts){let header=`## Runtime Session Context
936
+ `)}function memoriesForTarget(target,selected,config2){return target.filter?selected.filter(memory=>target.filter(memory,config2)):[...selected]}function destinationFile(target){let directory=(target.directory??"").replace(/^\.?\/+|\/+$/g,"");return directory===""?`\${projectRoot}/${target.fileName}`:`\${projectRoot}/${directory}/${target.fileName}`}function compilationTargetFor(target,selected,config2,plugin){let memories=memoriesForTarget(target,selected,config2),content=target.format?target.format(memories,config2):defaultFormat(memories);if(content!=="")return{id:compilationTargetId(target),content,origin:{plugin},outputs:[{destinationFile:destinationFile(target)}]}}function readSettings(config2){let value=config2.atPath(["recipes","memories"]).get();return value!==null&&typeof value=="object"?value:{}}function targetsContributor(plugin,services){let warned=new Set;return{id:TARGETS_CONTRIBUTOR2,contribute(config2){let targets=config2.entities("memory-target");for(let target of targets)target.readIn==="any-directory"&&config2.addEntity("pointer-file",{id:pointerFileId(target),fileName:target.fileName});if(targets.length===0)return;let globs=services.get("host.globs"),{selected}=selectMemories({recipes:config2.entities("active-recipe"),settings:readSettings(config2),globs,contents:services.get("recipes.contents"),onWarning:message2=>{warned.has(message2)||(warned.add(message2),config2.warn(message2))}});for(let target of targets){let compilation=compilationTargetFor(target,selected,config2,plugin);compilation&&config2.atPath(["compilation","targets"]).appendValue(compilation)}}}}var MemoriesSelectionService=class{constructor(config2,ctx){this.config=config2;this.ctx=ctx}result;selected(){return[...this.select().selected]}forTarget(targetId){let target=this.ctx.entities.get("memory-target",targetId);if(!target)throw new NotFoundError7("memory-target",targetId,`No memory target "${targetId}" exists.`);let builder=builderOver(this.ctx.config,this.ctx,TARGETS_CONTRIBUTOR2);return memoriesForTarget(target,this.select().selected,builder)}excluded(){return[...this.select().excluded]}select(){return this.result??=selectMemories({recipes:this.ctx.entities.list("active-recipe"),settings:this.config.get(["recipes","memories"]),globs:this.ctx.services.get("host.globs"),contents:this.ctx.services.get("recipes.contents")}),this.result}};var package_default15={name:"@sous-io/plugin-memories",version:"1.0.12",description:"Memories: selecting them, the memory-target entity, the compilation targets for them, the #memories name.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/documents":"workspace:*","@sous-io/plugin-api":"workspace:*","@sous-io/plugin-compiler":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/plugin-refs":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*",glob:"^13.0.6",minimatch:"^10.2.4"},engines:{node:">=22"}};var PLUGIN_NAME14="@sous-io/plugin-memories",memoriesPlugin=definePlugin15({name:PLUGIN_NAME14,version:package_default15.version,description:"Memories: selecting them, the memory-target entity, the compilation targets for them, the #memories name.",dependsOn:{"@sous-io/plugin-compiler":`^${package_default15.version}`,"@sous-io/plugin-recipes":`^${package_default15.version}`,"@sous-io/plugin-refs":`^${package_default15.version}`,"@sous-io/plugin-host":`^${package_default15.version}`},register(sous){sous.entities.define("memory-target",memoryTargetSchema,{description:"A file a harness reads into every session, built from the selected recipe memories."}),sous.entities.add("config-key",{id:"recipes.memories",schema:memoriesSettingsSchema,description:"Which recipe memories go to memory targets and the #memories view, and in what order."}),sous.entities.add("hash-name",memoriesHashName),sous.services.add("memories.selection",(config2,ctx)=>new MemoriesSelectionService(config2,ctx),{lifetime:"config"}),sous.config.contribute(targetsContributor(PLUGIN_NAME14,sous.services))}});init_pid();import{definePlugin as definePlugin16}from"@sous-io/plugin-api";init_schemas3();import fs47 from"node:fs";import path67 from"node:path";var UNKNOWN_BRANCH="unknown",RUNTIME_CONTEXT_SOURCE="runtime-context",RuntimeContextService=class{constructor(deps){this.deps=deps}settings(){return this.deps.settings}async generate(){let settings=this.deps.settings;if(!settings)return;let branch=await this.readBranch(settings.gitRoot),pattern=new RegExp(settings.branchPattern??DEFAULT_BRANCH_PATTERN),taskFile,taskContent;branch!==void 0&&pattern.test(branch)&&(taskFile=path67.join(settings.taskFileRoot,`${branch}.md`),taskContent=readIfExists(taskFile));let content=renderRuntimeContext({branch:branch??UNKNOWN_BRANCH,matched:taskFile!==void 0,...taskFile===void 0?{}:{taskFile},...taskContent===void 0?{}:{taskContent}});return{...branch===void 0?{}:{branch},...taskFile!==void 0&&taskContent!==void 0?{taskFile}:{},outputPath:settings.outputPath,content}}async write(options={}){let context=await this.generate();if(context)return this.deps.writer().write(context.outputPath,context.content,{source:RUNTIME_CONTEXT_SOURCE,origin:{plugin:this.deps.plugin},...options.dryRun?{dryRun:!0}:{}})}async readBranch(gitRoot){try{return await this.deps.git().currentBranch(gitRoot)}catch{return}}};function readIfExists(file2){try{return fs47.readFileSync(file2,"utf8")}catch{return}}function renderRuntimeContext(facts){let header=`## Runtime Session Context
936
937
 
937
938
  The following information is specific to this chat session. It was generated automatically and
938
939
  embedded into this AGENTS.md file in order to save you and the user some effort in setting up
@@ -956,11 +957,11 @@ file are included below:
956
957
  ${facts.taskContent.replace(/\n+$/u,"")}
957
958
  --- End Task File: ${facts.taskFile} ---
958
959
  `),`${header}${block}
959
- `}init_schemas3();var package_default16={name:"@sous-io/plugin-build",version:"1.0.11",description:"The build, compile, prune and clear intents, preparing for a build, watch mode, the PID file, the runtime context file.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-compiler":"workspace:*","@sous-io/plugin-git":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-memories":"workspace:*","@sous-io/plugin-recipe-answers":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/plugin-variables":"workspace:*",chokidar:"^5.0.0",semver:"^7.8.5"},devDependencies:{"@sous-io/core":"workspace:*","@types/semver":"^7.8.0"},engines:{node:">=22"}};init_report();var PLUGIN_NAME15="@sous-io/plugin-build",PLUGIN_VERSION=package_default16.version;function createBuildPlugin(options={}){let cwd=options.cwd;return definePlugin16({name:PLUGIN_NAME15,version:PLUGIN_VERSION,description:"The build, compile, prune and clear intents, preparing for a build, watch mode, the PID file, the runtime context file.",dependsOn:{"@sous-io/plugin-compiler":`^${package_default16.version}`,"@sous-io/plugin-recipes":`^${package_default16.version}`,"@sous-io/plugin-recipe-answers":`^${package_default16.version}`,"@sous-io/plugin-git":`^${package_default16.version}`,"@sous-io/plugin-host":`^${package_default16.version}`,"@sous-io/plugin-variables":`^${package_default16.version}`},register(sous){sous.entities.add("config-key",{id:"watch",schema:watchSettingsSchema,description:"Watch mode: more paths that trigger a full rebuild, the debounce, and how often to check upstream."}),sous.entities.add("config-key",{id:"runtimeContext",schema:runtimeContextSchema,description:"The runtime context file a target with generateRuntimeContext includes: git branch and task file."}),sous.services.add("build.pid",(_config,ctx)=>new PidFile({...explicitPidPath(ctx.services),project:ctx.project,cwd:cwd?.()??ctx.cwd??".",isAlive:options.isProcessAlive??isProcessAlive}),{lifetime:"singleton"}),sous.services.add("build.runtime-context",(config2,ctx)=>new RuntimeContextService({settings:runtimeContextSettings(config2.get("runtimeContext"),ctx.services),git:()=>ctx.services.get("git.runner"),writer:()=>ctx.services.get("compiler.writer"),plugin:PLUGIN_NAME15}),{lifetime:"config"}),sous.intents.add({intent:"build",requiresProject:!0,summary:"Compile this project's outputs and remove the ones its config no longer produces",input:buildInputSchema,cli:{examples:["sous build","sous build --no-prune","sous build --rebuild","sous build --dry-run"],flags:{watch:{short:"w"},changedFiles:{hidden:!0},reportRemoved:{hidden:!0}}},agent:{usage:"Run after changing the config, a subscription or a template, to write every output again.",whenNotToUse:"Not with watch: an agent cannot stop a watcher; build again instead."},load:async()=>(await Promise.resolve().then(()=>(init_build(),build_exports))).build}),sous.intents.add({intent:"compile",requiresProject:!0,summary:"Compile markdown templates into output files",description:"Compiles every target in the config without preparing recipes or pruning.",input:compileInputSchema,cli:{examples:["sous compile","sous compile --rebuild","sous compile --dry-run","sous compile --strict"],flags:{watch:{short:"w"},changedFiles:{hidden:!0}}},load:async()=>(await Promise.resolve().then(()=>(init_build(),build_exports))).compile}),sous.intents.add({intent:"build.prepare",requiresProject:!0,summary:"Seed core, lock new subscriptions, restore the store and check upstream",input:prepareInputSchema,internal:!0,load:async()=>(await Promise.resolve().then(()=>(init_prepare(),prepare_exports))).prepare}),sous.intents.add({intent:"prune",requiresProject:!0,summary:"Remove output files that are no longer in the current config",input:pruneInputSchema,cli:{examples:["sous prune","sous prune --dry-run"]},load:async()=>(await Promise.resolve().then(()=>(init_build(),build_exports))).prune}),sous.intents.add({intent:"clear",requiresProject:!0,summary:"Delete all files and directories written by Sous for a project",input:clearInputSchema,cli:{examples:["sous clear","sous clear --force","sous clear --yes"],flags:{force:{short:"f",aliases:["yes"]}}},agent:{usage:"Pass force: true; an agent cannot answer the confirmation."},load:async()=>(await Promise.resolve().then(()=>(init_build(),build_exports))).clear}),sous.intents.add({intent:"build.watch",requiresProject:!0,summary:"Watch the sources and build on every change",input:watchInputSchema,background:!0,cli:{hidden:!0},agent:{hidden:!0},async handle(input,ctx){let{chokidarWatcher:chokidarWatcher2}=await Promise.resolve().then(()=>(init_watcher(),watcher_exports)),{createWatchHandler:createWatchHandler2,processSignals:processSignals2}=await Promise.resolve().then(()=>(init_intent(),intent_exports));return createWatchHandler2({createWatcher:options.createWatcher??chokidarWatcher2,signals:options.signals??processSignals2,cwd,...options.timers?{timers:options.timers}:{},...options.onWatchSession?{onSession:options.onWatchSession}:{}})(input,ctx)}})}})}function explicitPidPath(services){if(!services.has("variables.resolver"))return{};let value=services.get("variables.resolver").scope().pidFilePath;return value?{explicitPath:value}:{}}function runtimeContextSettings(raw2,services){if(!raw2)return;let resolver=services.get("variables.resolver"),scope=resolver.scope(),substitute2=(value,field)=>resolver.substituteStrict(value,scope,`runtimeContext.${field}`);return{gitRoot:substitute2(raw2.gitRoot,"gitRoot"),outputPath:substitute2(raw2.outputPath,"outputPath"),taskFileRoot:substitute2(raw2.taskFileRoot,"taskFileRoot"),...raw2.branchPattern===void 0?{}:{branchPattern:raw2.branchPattern}}}var buildPlugin=createBuildPlugin();import{definePlugin as definePlugin17,jsonSchema as jsonSchema22}from"@sous-io/plugin-api";import path71 from"node:path";import{jsonSchema as jsonSchema21}from"@sous-io/plugin-api";var TOOLS_KEY="tools",toolsKeySchema=jsonSchema21({type:"object",additionalProperties:{type:"object",properties:{command:{type:"string",description:"The command to run."},args:{type:"array",items:{type:"string"},description:"Arguments always passed, before yours."},promptFile:{type:"string",description:"A file whose content is passed as the last argument."},headless:{type:"object",properties:{command:{type:"string"},args:{type:"array",items:{type:"string"}}},additionalProperties:!1,description:"The command and arguments for a headless run; the prompt is sent on standard input."}},additionalProperties:!1},default:{}});function toolSettings(config2,id){let value=config2.get(`${TOOLS_KEY}.${id}`);return value&&typeof value=="object"?value:{}}function promptFilePath(settings,ctx){if(settings.promptFile!==void 0)return path71.resolve(ctx.project?.root??process.cwd(),settings.promptFile)}import fs49 from"node:fs";import{ConfigError as ConfigError45,SousError as SousError26}from"@sous-io/plugin-api";function launchArguments(settings,extra,ctx){let args=[...settings.args??[],...extra],file2=promptFilePath(settings,ctx);if(file2!==void 0){if(!fs49.existsSync(file2))throw new ConfigError45(`promptFile not found: ${file2}`);args.push(fs49.readFileSync(file2,"utf8"))}return args}function headlessArguments(settings){return[...settings.headless?.args??(settings.headless?.command===void 0?settings.args??[]:[])]}function toolHarness(id){return{id,description:`The tool "${id}", as written under "tools" in the config.`,async launch(args,ctx){let settings=toolSettings(ctx.config,id);if(settings.command===void 0)throw new ConfigError45(`tools.${id} has no "command".`,{details:[`Set tools.${id}.command in your config.`]});return ctx.services.get("host.processes").runInteractive(settings.command,launchArguments(settings,args,ctx),{...ctx.project?{cwd:ctx.project.root}:{},env:ctx.env,label:id})},async runHeadless(request,ctx){let settings=toolSettings(ctx.config,id),command=settings.headless?.command??settings.command;if(command===void 0)throw new ConfigError45(`tools.${id} has no "command" or "headless.command".`);let result=await ctx.services.get("host.processes").run(command,headlessArguments(settings),{...request.cwd??ctx.project?.root?{cwd:request.cwd??ctx.project?.root}:{},env:ctx.env,input:request.prompt,...request.timeoutMs===void 0?{}:{timeoutMs:request.timeoutMs},...request.signal===void 0?{}:{signal:request.signal},label:`${id} (headless)`});if(result.timedOut)throw new SousError26(`${id} did not finish within ${request.timeoutMs}ms.`);return{harness:id,exitCode:result.exitCode,output:result.stdout.trimEnd(),durationMs:result.durationMs,raw:result}}}}var TOOLS_CONTRIBUTOR="harnesses.tools";function contributeToolHarnesses(config2){let tools=config2.atPath(TOOLS_KEY).get();if(!(!tools||typeof tools!="object"||Array.isArray(tools)))for(let id of Object.keys(tools))config2.entity("harness",id)===void 0&&config2.addEntity("harness",toolHarness(id))}var toolsContributor={id:TOOLS_CONTRIBUTOR,after:["*"],contribute:contributeToolHarnesses};var package_default17={name:"@sous-io/plugin-harnesses",version:"1.0.11",description:"The harness entity, launching a harness, headless runs, and the tools settings.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-build":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME16="@sous-io/plugin-harnesses",harnessSchema=jsonSchema22({type:"object",required:["id"],properties:{id:{type:"string",description:"What `sous launch <id>` names: `claude`."},description:{type:"string"}}}),launchInput=jsonSchema22({type:"object",required:["tool"],properties:{tool:{type:"array",items:{type:"string"},description:"The tool, then arguments passed through to it."},noBuild:{type:"boolean",default:!1,description:"Skip sous build before launching."},continuous:{type:"boolean",default:!1,description:"Restart the tool automatically on exit."}},additionalProperties:!1}),runHeadlessInput=jsonSchema22({type:"object",required:["prompt"],properties:{harness:{type:"string",description:"The harness to run. Default: the only one that can run headless."},prompt:{type:"string",description:"The prompt."},cwd:{type:"string",description:"The directory it runs in. Default: the project root."},model:{type:"string",description:"A model, when the harness lets one be chosen."},timeoutMs:{type:"integer",description:"Stops it after this many milliseconds."},transcript:{type:"boolean",default:!1,description:"Also read the transcript."}},additionalProperties:!1}),harnessesPlugin=definePlugin17({name:PLUGIN_NAME16,version:package_default17.version,description:"The harness entity, launching a harness, headless runs, and the tools settings.",dependsOn:{"@sous-io/plugin-build":`^${package_default17.version}`,"@sous-io/plugin-host":`^${package_default17.version}`},register(sous){sous.entities.define("harness",harnessSchema,{description:"A program that wraps a model, used interactively, headless, or both."}),sous.entities.add("config-key",{id:TOOLS_KEY,schema:toolsKeySchema,description:"Tools you can launch with `sous launch <name>`: command, args, promptFile, headless."}),sous.config.contribute(toolsContributor),sous.intents.add({intent:"launch",summary:"Build this project's outputs, then start a coding agent configured in its config",input:launchInput,requiresProject:!0,cli:{positional:["tool"],passThrough:!0,examples:["sous launch claude","sous launch codex --no-build","sous launch claude --continuous","sous launch claude -- -c"]},load:()=>Promise.resolve().then(()=>(init_launch(),launch_exports))}),sous.intents.add({intent:"harness.run-headless",summary:"Run a coding agent with no person at the keyboard, and read its transcript",input:runHeadlessInput,cli:{command:["harness","run-headless"],hidden:!0},load:()=>Promise.resolve().then(()=>(init_run_headless(),run_headless_exports))})}});import{definePlugin as definePlugin18}from"@sous-io/plugin-api";import{jsonSchema as jsonSchema23}from"@sous-io/plugin-api";var yes3={type:"boolean",description:"Answer yes to every confirmation, so nothing is asked"},dryRun3={type:"boolean",description:"Show what would happen, changing nothing"},title={type:"string",description:"The proposal's title; required for a new proposal, and replaces an open one's"},body={type:"string",description:"The proposal's description; required for a new proposal, and replaces an open one's"},releaseInput=jsonSchema23({type:"object",additionalProperties:!1,properties:{directory:{type:"string",description:"The repository to release, or a directory inside it (default: the working directory)"},check:{type:"boolean",description:"Only check: validate, and fail on any problem; reports how merging rewrites the index"},ci:{type:"boolean",description:"Run the way a merge does: never bump, accept the plan, never ask, and fail on anything unbumped"},namespace:{type:"array",items:{type:"string"},description:"Release only this namespace. Repeat to name several"},recipe:{type:"array",items:{type:"string"},description:"Release only this recipe, as 'namespace/name'. Repeat to name several"},bump:{type:"string",enum:["patch","minor","major","prerelease"],description:"How far to raise a changed recipe's version. Defaults to a patch step"},noBump:{type:"boolean",description:"Raise no versions; a changed recipe that was never raised is an error"},includeUnchanged:{type:"boolean",description:"Release every recipe in scope, whether its files changed or not"},tag:{type:"boolean",description:"Cut the tags even on a branch other than the default one"},push:{type:"boolean",description:"Push the commit, and the tags this run created, to the remote"},yes:{...yes3,description:"Accept the plan without being asked"},dryRun:{...dryRun3,description:"Print the plan and stop, changing nothing"}}}),submitInput=jsonSchema23({type:"object",additionalProperties:!1,properties:{repo:{type:"string",description:"The linked repository to propose a change from, when run inside a project"},directory:{type:"string",description:"The directory to start from (default: the working directory)"},title,body,branch:{type:"string",description:"The branch to work with, instead of the one that is checked out"},status:{type:"boolean",description:"Only report where the branch's proposal stands"},commit:{type:"boolean",description:"Commit uncommitted changes for you, after listing them and asking once"},draft:{type:"boolean",description:"Open a new proposal as a draft"},nextBranch:{type:"string",description:"The new branch to continue on when the branch's proposal was already merged"},acceptFirst:{type:"boolean",description:"When the repository named matches several, take the first one listed"},yes:yes3,dryRun:{...dryRun3,description:"Check everything and print the plan without writing or sending anything"}}}),contributeInput=jsonSchema23({type:"object",additionalProperties:!1,required:["ref"],properties:{ref:{type:"string",description:"The repository to contribute to, or a namespace or recipe it publishes"},finish:{type:"boolean",description:"Finish the contribution: submit what no proposal carries yet, then unlink and update the pins"},branch:{type:"string",description:"The existing branch to work on when starting, or to submit from when finishing"},createBranch:{type:"string",description:"Start the contribution on a new branch with this name"},generateBranch:{type:"boolean",description:"Start the contribution on a new branch named sous/edit-<date>-<time>, which is what happens when no branch is named"},from:{type:"string",description:"Start the new branch from this branch instead of the repository's default branch"},global:{type:"boolean",description:"Work with the machine-wide link, sharing one checkout, rather than this project's link"},submit:{type:"boolean",description:"Submit what no proposal carries yet without asking, or with --no-submit, finish without submitting it"},title,body,draft:{type:"boolean",description:"Open a new proposal as a draft"},commit:{type:"boolean",description:"Commit uncommitted changes for you when submitting, after listing them and asking once"},remove:{type:"boolean",description:"Delete the checkout as well when unlinking, when sous cloned it"},yes:yes3,acceptFirst:{type:"boolean",description:"When the reference matches several things, take the first one listed"},dryRun:{...dryRun3,description:"Print each step this would run without running any of them"}}}),initInput=jsonSchema23({type:"object",additionalProperties:!1,properties:{directory:{type:"string",description:"Directory to create the repository in (defaults to the current one)"},name:{type:"string",description:"Short name for the repository (defaults to the directory's own name)"},namespace:{type:"string",description:"Name of the one namespace to declare (defaults to the repository's name)"},force:{type:"boolean",description:"Write the scaffold over a repository that already exists"},host:{type:"string",description:"The repository host whose CI workflow and files to add, such as 'github' (default: from the git remote, else none)"},dryRun:{...dryRun3,description:"Print the files that would be written without writing them"}}});var package_default18={name:"@sous-io/plugin-authoring",version:"1.0.11",description:"Releasing, submitting and contributing to recipe repositories, and scaffolding one.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/documents":"workspace:*","@sous-io/plugin-api":"workspace:*","@sous-io/plugin-formats":"workspace:*","@sous-io/plugin-git":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/plugin-refs":"workspace:*","@sous-io/plugin-variables":"workspace:*",semver:"^7.8.5"},devDependencies:{"@sous-io/core":"workspace:*","@sous-io/plugin-cli":"workspace:*","@sous-io/plugin-host":"workspace:*","@types/semver":"^7.8.0"},engines:{node:">=22"}};var PLUGIN_NAME17="@sous-io/plugin-authoring",yesFlag2={yes:{short:"y",aliases:["force"]}},authoringPlugin=definePlugin18({name:PLUGIN_NAME17,version:package_default18.version,description:"Releasing, submitting and contributing to recipe repositories, and scaffolding one.",dependsOn:{"@sous-io/plugin-recipes":`^${package_default18.version}`,"@sous-io/plugin-formats":`^${package_default18.version}`,"@sous-io/plugin-refs":`^${package_default18.version}`,"@sous-io/plugin-variables":`^${package_default18.version}`,"@sous-io/plugin-git":`^${package_default18.version}`},register(sous){sous.intents.add({intent:"repo.release",summary:"Publish new versions of this repository's recipes: bump, regenerate the index, commit and tag",description:"Runs inside a recipe repository. Validates it, raises the version of every changed recipe, regenerates sous.index.json, commits the manifests and the index, and tags each version. --check only reads (for a pull request); --ci runs the way a merge does.",input:releaseInput,cli:{aliases:[["repos","release"]],flags:{...yesFlag2,directory:{hidden:!0}},examples:["sous repo release","sous repo release --dry-run","sous repo release --namespace workflow --bump minor","sous repo release --recipe workflow/task-files --yes --push","sous repo release --check","sous repo release --ci --push"]},agent:{usage:"Call this inside a recipe repository to publish its changed recipes. Use check: true to validate without writing.",whenNotToUse:"Not for a sous project; it releases the recipe repository it runs in."},load:async()=>(await Promise.resolve().then(()=>(init_release(),release_exports))).handleRelease}),sous.intents.add({intent:"repo.submit",summary:"Propose a recipe repository's changes to its maintainers, and follow the proposal through",description:"Validates the checkout, then pushes its branch and opens or updates a proposal through the repository host. Needs the host's command line tool (gh, glab) signed in.",input:submitInput,cli:{aliases:[["repos","submit"]],positional:["repo"],flags:{...yesFlag2,directory:{hidden:!0}},examples:['sous repo submit --title "Add a linting recipe" --body "Adds lint rules."',"sous repo submit sous-recipes","sous repo submit --status",'sous repo submit --commit --yes --title "Fix a typo" --body "Fixes it."',"sous repo submit --dry-run"]},agent:{usage:"Call this to propose committed changes in a recipe repository checkout. A new proposal needs title and body."},load:async()=>(await Promise.resolve().then(()=>(init_submit(),submit_exports))).handleSubmit}),sous.intents.add({intent:"repo.contribute",summary:"Start a contribution to a recipe repository on a fresh branch, or finish one with --finish",description:"Starting links the repository on a new branch (repo link --latest). Finishing submits what no proposal carries yet (repo submit), then unlinks and updates the pins (repo unlink --update).",input:contributeInput,changesConfig:!0,requiresProject:!0,cli:{aliases:[["repos","contribute"],["repo","contrib"],["repos","contrib"]],positional:["ref"],flags:yesFlag2,examples:["sous repo contribute sous-recipes","sous repo contribute workflow/task-files","sous repo contribute sous-recipes --create-branch fix-a-typo",'sous repo contribute sous-recipes --finish --title "Fix a typo" --body "Fixes it."',"sous repo contribute sous-recipes --finish --no-submit --remove","sous repo contribute sous-recipes --finish --dry-run"]},agent:{usage:"Call this to start editing a recipe repository from a project, and again with finish: true to propose and unlink."},load:async()=>(await Promise.resolve().then(()=>(init_contribute(),contribute_exports))).handleContribute}),sous.intents.add({intent:"repo.init",summary:"Create a new sous recipe repository in a directory",input:initInput,cli:{aliases:[["repos","init"]],positional:["directory"],examples:["sous repo init","sous repo init ./my-recipes","sous repo init ./my-recipes --name team-recipes --namespace workflow","sous repo init ./my-recipes --host github","sous repo init ./my-recipes --dry-run"]},agent:{usage:"Call this to scaffold a new recipe repository."},load:async()=>(await Promise.resolve().then(()=>(init_scaffold(),scaffold_exports))).handleInit})}});import{definePlugin as definePlugin19,jsonSchema as jsonSchema24}from"@sous-io/plugin-api";var package_default19={name:"@sous-io/plugin-init",version:"1.0.11",description:"Scaffolding a project's .sous/ (sous init).",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-build":"workspace:*","@sous-io/plugin-config-files":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};init_templates2();init_package_json();init_scaffold2();var PLUGIN_NAME18="@sous-io/plugin-init",initInput2=jsonSchema24({type:"object",properties:{directory:{type:"string",description:"Project directory to set up (defaults to the current one)."},name:{type:"string",description:"Display name for the project (defaults to the directory's own name)."},yes:{type:"boolean",default:!1,description:"Answer yes to the one question init can ask: setting a project up inside another one."},dryRun:{type:"boolean",default:!1,description:"Show the files that would be written without writing them."},noBuild:{type:"boolean",default:!1,description:"Write the setup without running the first build."}},additionalProperties:!1}),initPlugin=definePlugin19({name:PLUGIN_NAME18,version:package_default19.version,description:"Scaffolding a project's .sous/ (sous init).",dependsOn:{"@sous-io/plugin-build":`^${package_default19.version}`,"@sous-io/plugin-config-files":`^${package_default19.version}`,"@sous-io/plugin-host":`^${package_default19.version}`},register(sous){sous.intents.add({intent:"init",summary:"Set a project up for sous: write its .sous/ directory, then run the first build",input:initInput2,changesConfig:!0,cli:{positional:["directory"],examples:["sous init","sous init ./my-project","sous init --name 'My Project' --no-build","sous init --dry-run"],flags:{yes:{short:"y",aliases:["force"]}}},agent:{usage:"Set up a new project. Pass yes so no question is asked, and dryRun first to see the files."},load:()=>Promise.resolve().then(()=>(init_init(),init_exports))})}});import{definePlugin as definePlugin20,jsonSchema as jsonSchema25}from"@sous-io/plugin-api";var SCAN_CONTRIBUTOR2="update.scan";function scanContext(sous){return{plugin:sous.plugin.name,get config(){return sous.engine.config},services:sous.services,entities:sous.entities,project:sous.project,env:sous.env}}function scanContributor(sous){return{id:SCAN_CONTRIBUTOR2,monitors:["plugins.discover","plugins.load",{entities:"package-manager"}],async contribute(config2){if(config2.atPath("plugins.discover").valueOr("dependencies")!=="scan"||config2.project===void 0)return;let ctx=scanContext(sous),root=config2.project.root,load=config2.atPath("plugins.load"),known=new Set(load.valueOr([])),found=new Set;for(let manager of config2.entities("package-manager"))try{if(await manager.detect(root,ctx)===void 0)continue;for(let pkg of await manager.installed("project",root,ctx))pkg.isSousPlugin&&!known.has(pkg.name)&&found.add(pkg.name)}catch(error51){config2.warn(`${manager.id} could not list the installed packages: ${error51 instanceof Error?error51.message:String(error51)}`)}for(let name of[...found].sort())load.append(name)}}}var package_default20={name:"@sous-io/plugin-update",version:"1.0.11",description:"Updating sous itself, installing plugins a recipe requires, the package-manager entity, scanning for installed plugins.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-host":"workspace:*",semver:"^7.8.5"},devDependencies:{"@sous-io/core":"workspace:*","@types/semver":"^7.8.0"},engines:{node:">=22"}};var PLUGIN_NAME19="@sous-io/plugin-update",packageManagerSchema=jsonSchema25({type:"object",required:["id"],properties:{id:{type:"string",description:"What names the manager: `npm`, `pnpm`, `yarn`."},description:{type:"string"}}}),updateInput=jsonSchema25({type:"object",properties:{major:{type:"boolean",default:!1,description:"Install the newest published version, whatever its major version."},version:{type:"string",description:"Install this version, the newest version in this range, or the version this dist-tag names."},prerelease:{type:"boolean",description:"Count prerelease versions as candidates; on by default when the installed version is a prerelease."},global:{type:"boolean",default:!1,description:"Update only the global install."},project:{type:"boolean",default:!1,description:"Update only this project's own install."},yes:{type:"boolean",default:!1,description:"Answer yes to every question."},dryRun:{type:"boolean",default:!1,description:"Show every install's plan without installing anything."},noBuild:{type:"boolean",default:!1,description:"Update the project install without building the project afterwards."}},additionalProperties:!1}),pluginsInstallInput=jsonSchema25({type:"object",required:["plugins"],properties:{plugins:{type:"array",items:{type:"string"},description:"Plugins to install, as `name` or `name@range`."},section:{enum:["dependencies","devDependencies"],default:"devDependencies",description:"The package.json section to add them to."},yes:{type:"boolean",default:!1,description:"Install without asking."},dryRun:{type:"boolean",default:!1,description:"Show the command without running it."}},additionalProperties:!1}),updatePlugin=definePlugin20({name:PLUGIN_NAME19,version:package_default20.version,description:"Updating sous itself, installing plugins a recipe requires, the package-manager entity, scanning for installed plugins.",dependsOn:{"@sous-io/plugin-host":`^${package_default20.version}`},register(sous){sous.entities.define("package-manager",packageManagerSchema,{description:"A package manager: detecting it, listing installed packages, planning installs."}),sous.config.contribute(scanContributor(sous)),sous.intents.add({intent:"update",summary:"Update sous itself, globally and in this project, through the package manager that installed each copy",input:updateInput,toleratesConfigErrors:!0,cli:{examples:["sous update","sous update --global","sous update --major","sous update --version 0.2.18","sous update --version next","sous update --dry-run"],flags:{yes:{short:"y",aliases:["force"]},prerelease:{aliases:["pre"]}}},agent:{usage:"Move sous to a newer version. Pass yes so no question is asked; use dryRun first to see the plan."},load:()=>Promise.resolve().then(()=>(init_update(),update_exports))}),sous.intents.add({intent:"plugins.install",summary:"Install npm plugins through the project's package manager",input:pluginsInstallInput,cli:{command:["plugins","install"],positional:["plugins"],examples:["sous plugins install sous-plugin-claude-code","sous plugins install sous-plugin-x@^1.0.0 --yes"],flags:{yes:{short:"y",aliases:["force"]}}},load:()=>Promise.resolve().then(()=>(init_plugins_install(),plugins_install_exports))})}});import{definePlugin as definePlugin21}from"@sous-io/plugin-api";init_src();import nodePath from"node:path";import{IntentOutputs as IntentOutputs22,NotFoundError as NotFoundError11,SousError as SousError29}from"@sous-io/plugin-api";import{ConfigError as ConfigError64,DataValue as DataValue2,IntentOutput as IntentOutput18,ReportEntryStyle as ReportEntryStyle14,Table as Table5,TextBlock as TextBlock11,Tree as Tree2,VariableSet as VariableSet10}from"@sous-io/plugin-api";function truncateJson(value,max=80){let encoded=JSON.stringify(value);return encoded===void 0?"undefined":encoded.length>max?`${encoded.slice(0,max-1)}\u2026`:encoded}function isScalar3(value){return value===null||typeof value=="string"||typeof value=="number"||typeof value=="boolean"}function plural2(count2,singular,pluralForm=`${singular}s`){return`${count2} ${count2===1?singular:pluralForm}`}function missingValue(path103){return new ConfigError64(`No value at config path '${path103}'.`,{details:["It is not present in the built config.","Run 'sous config show' to see the whole config."]})}function missingInLayers(path103){return new ConfigError64(`No value at config path '${path103}' in any config layer.`,{details:["Run 'sous config show' to see the whole config."]})}function rawFileOutputs(files){return files.map(file2=>new IntentOutput18({result:new TextBlock11(`# ${file2.path} (${file2.contributor})
960
+ `}init_schemas3();var package_default16={name:"@sous-io/plugin-build",version:"1.0.12",description:"The build, compile, prune and clear intents, preparing for a build, watch mode, the PID file, the runtime context file.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-compiler":"workspace:*","@sous-io/plugin-git":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-memories":"workspace:*","@sous-io/plugin-recipe-answers":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/plugin-variables":"workspace:*",chokidar:"^5.0.0",semver:"^7.8.5"},devDependencies:{"@sous-io/core":"workspace:*","@types/semver":"^7.8.0"},engines:{node:">=22"}};init_report();var PLUGIN_NAME15="@sous-io/plugin-build",PLUGIN_VERSION=package_default16.version;function createBuildPlugin(options={}){let cwd=options.cwd;return definePlugin16({name:PLUGIN_NAME15,version:PLUGIN_VERSION,description:"The build, compile, prune and clear intents, preparing for a build, watch mode, the PID file, the runtime context file.",dependsOn:{"@sous-io/plugin-compiler":`^${package_default16.version}`,"@sous-io/plugin-recipes":`^${package_default16.version}`,"@sous-io/plugin-recipe-answers":`^${package_default16.version}`,"@sous-io/plugin-git":`^${package_default16.version}`,"@sous-io/plugin-host":`^${package_default16.version}`,"@sous-io/plugin-variables":`^${package_default16.version}`},register(sous){sous.entities.add("config-key",{id:"watch",schema:watchSettingsSchema,description:"Watch mode: more paths that trigger a full rebuild, the debounce, and how often to check upstream."}),sous.entities.add("config-key",{id:"runtimeContext",schema:runtimeContextSchema,description:"The runtime context file a target with generateRuntimeContext includes: git branch and task file."}),sous.services.add("build.pid",(_config,ctx)=>new PidFile({...explicitPidPath(ctx.services),project:ctx.project,cwd:cwd?.()??ctx.cwd??".",isAlive:options.isProcessAlive??isProcessAlive}),{lifetime:"singleton"}),sous.services.add("build.runtime-context",(config2,ctx)=>new RuntimeContextService({settings:runtimeContextSettings(config2.get("runtimeContext"),ctx.services),git:()=>ctx.services.get("git.runner"),writer:()=>ctx.services.get("compiler.writer"),plugin:PLUGIN_NAME15}),{lifetime:"config"}),sous.intents.add({intent:"build",requiresProject:!0,summary:"Compile this project's outputs and remove the ones its config no longer produces",input:buildInputSchema,cli:{examples:["sous build","sous build --no-prune","sous build --rebuild","sous build --dry-run"],flags:{watch:{short:"w"},changedFiles:{hidden:!0},reportRemoved:{hidden:!0}}},agent:{usage:"Run after changing the config, a subscription or a template, to write every output again.",whenNotToUse:"Not with watch: an agent cannot stop a watcher; build again instead."},load:async()=>(await Promise.resolve().then(()=>(init_build(),build_exports))).build}),sous.intents.add({intent:"compile",requiresProject:!0,summary:"Compile markdown templates into output files",description:"Compiles every target in the config without preparing recipes or pruning.",input:compileInputSchema,cli:{examples:["sous compile","sous compile --rebuild","sous compile --dry-run","sous compile --strict"],flags:{watch:{short:"w"},changedFiles:{hidden:!0}}},load:async()=>(await Promise.resolve().then(()=>(init_build(),build_exports))).compile}),sous.intents.add({intent:"build.prepare",requiresProject:!0,summary:"Seed core, lock new subscriptions, restore the store and check upstream",input:prepareInputSchema,internal:!0,load:async()=>(await Promise.resolve().then(()=>(init_prepare(),prepare_exports))).prepare}),sous.intents.add({intent:"prune",requiresProject:!0,summary:"Remove output files that are no longer in the current config",input:pruneInputSchema,cli:{examples:["sous prune","sous prune --dry-run"]},load:async()=>(await Promise.resolve().then(()=>(init_build(),build_exports))).prune}),sous.intents.add({intent:"clear",requiresProject:!0,summary:"Delete all files and directories written by Sous for a project",input:clearInputSchema,cli:{examples:["sous clear","sous clear --force","sous clear --yes"],flags:{force:{short:"f",aliases:["yes"]}}},agent:{usage:"Pass force: true; an agent cannot answer the confirmation."},load:async()=>(await Promise.resolve().then(()=>(init_build(),build_exports))).clear}),sous.intents.add({intent:"build.watch",requiresProject:!0,summary:"Watch the sources and build on every change",input:watchInputSchema,background:!0,cli:{hidden:!0},agent:{hidden:!0},async handle(input,ctx){let{chokidarWatcher:chokidarWatcher2}=await Promise.resolve().then(()=>(init_watcher(),watcher_exports)),{createWatchHandler:createWatchHandler2,processSignals:processSignals2}=await Promise.resolve().then(()=>(init_intent(),intent_exports));return createWatchHandler2({createWatcher:options.createWatcher??chokidarWatcher2,signals:options.signals??processSignals2,cwd,...options.timers?{timers:options.timers}:{},...options.onWatchSession?{onSession:options.onWatchSession}:{}})(input,ctx)}})}})}function explicitPidPath(services){if(!services.has("variables.resolver"))return{};let value=services.get("variables.resolver").scope().pidFilePath;return value?{explicitPath:value}:{}}function runtimeContextSettings(raw2,services){if(!raw2)return;let resolver=services.get("variables.resolver"),scope=resolver.scope(),substitute2=(value,field)=>resolver.substituteStrict(value,scope,`runtimeContext.${field}`);return{gitRoot:substitute2(raw2.gitRoot,"gitRoot"),outputPath:substitute2(raw2.outputPath,"outputPath"),taskFileRoot:substitute2(raw2.taskFileRoot,"taskFileRoot"),...raw2.branchPattern===void 0?{}:{branchPattern:raw2.branchPattern}}}var buildPlugin=createBuildPlugin();import{definePlugin as definePlugin17,jsonSchema as jsonSchema22}from"@sous-io/plugin-api";import path71 from"node:path";import{jsonSchema as jsonSchema21}from"@sous-io/plugin-api";var TOOLS_KEY="tools",toolsKeySchema=jsonSchema21({type:"object",additionalProperties:{type:"object",properties:{command:{type:"string",description:"The command to run."},args:{type:"array",items:{type:"string"},description:"Arguments always passed, before yours."},promptFile:{type:"string",description:"A file whose content is passed as the last argument."},headless:{type:"object",properties:{command:{type:"string"},args:{type:"array",items:{type:"string"}}},additionalProperties:!1,description:"The command and arguments for a headless run; the prompt is sent on standard input."}},additionalProperties:!1},default:{}});function toolSettings(config2,id){let value=config2.get(`${TOOLS_KEY}.${id}`);return value&&typeof value=="object"?value:{}}function promptFilePath(settings,ctx){if(settings.promptFile!==void 0)return path71.resolve(ctx.project?.root??process.cwd(),settings.promptFile)}import fs49 from"node:fs";import{ConfigError as ConfigError45,SousError as SousError26}from"@sous-io/plugin-api";function launchArguments(settings,extra,ctx){let args=[...settings.args??[],...extra],file2=promptFilePath(settings,ctx);if(file2!==void 0){if(!fs49.existsSync(file2))throw new ConfigError45(`promptFile not found: ${file2}`);args.push(fs49.readFileSync(file2,"utf8"))}return args}function headlessArguments(settings){return[...settings.headless?.args??(settings.headless?.command===void 0?settings.args??[]:[])]}function toolHarness(id){return{id,description:`The tool "${id}", as written under "tools" in the config.`,async launch(args,ctx){let settings=toolSettings(ctx.config,id);if(settings.command===void 0)throw new ConfigError45(`tools.${id} has no "command".`,{details:[`Set tools.${id}.command in your config.`]});return ctx.services.get("host.processes").runInteractive(settings.command,launchArguments(settings,args,ctx),{...ctx.project?{cwd:ctx.project.root}:{},env:ctx.env,label:id})},async runHeadless(request,ctx){let settings=toolSettings(ctx.config,id),command=settings.headless?.command??settings.command;if(command===void 0)throw new ConfigError45(`tools.${id} has no "command" or "headless.command".`);let result=await ctx.services.get("host.processes").run(command,headlessArguments(settings),{...request.cwd??ctx.project?.root?{cwd:request.cwd??ctx.project?.root}:{},env:ctx.env,input:request.prompt,...request.timeoutMs===void 0?{}:{timeoutMs:request.timeoutMs},...request.signal===void 0?{}:{signal:request.signal},label:`${id} (headless)`});if(result.timedOut)throw new SousError26(`${id} did not finish within ${request.timeoutMs}ms.`);return{harness:id,exitCode:result.exitCode,output:result.stdout.trimEnd(),durationMs:result.durationMs,raw:result}}}}var TOOLS_CONTRIBUTOR="harnesses.tools";function contributeToolHarnesses(config2){let tools=config2.atPath(TOOLS_KEY).get();if(!(!tools||typeof tools!="object"||Array.isArray(tools)))for(let id of Object.keys(tools))config2.entity("harness",id)===void 0&&config2.addEntity("harness",toolHarness(id))}var toolsContributor={id:TOOLS_CONTRIBUTOR,after:["*"],contribute:contributeToolHarnesses};var package_default17={name:"@sous-io/plugin-harnesses",version:"1.0.12",description:"The harness entity, launching a harness, headless runs, and the tools settings.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-build":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME16="@sous-io/plugin-harnesses",harnessSchema=jsonSchema22({type:"object",required:["id"],properties:{id:{type:"string",description:"What `sous launch <id>` names: `claude`."},description:{type:"string"}}}),launchInput=jsonSchema22({type:"object",required:["tool"],properties:{tool:{type:"array",items:{type:"string"},description:"The tool, then arguments passed through to it."},noBuild:{type:"boolean",default:!1,description:"Skip sous build before launching."},continuous:{type:"boolean",default:!1,description:"Restart the tool automatically on exit."}},additionalProperties:!1}),runHeadlessInput=jsonSchema22({type:"object",required:["prompt"],properties:{harness:{type:"string",description:"The harness to run. Default: the only one that can run headless."},prompt:{type:"string",description:"The prompt."},cwd:{type:"string",description:"The directory it runs in. Default: the project root."},model:{type:"string",description:"A model, when the harness lets one be chosen."},timeoutMs:{type:"integer",description:"Stops it after this many milliseconds."},transcript:{type:"boolean",default:!1,description:"Also read the transcript."}},additionalProperties:!1}),harnessesPlugin=definePlugin17({name:PLUGIN_NAME16,version:package_default17.version,description:"The harness entity, launching a harness, headless runs, and the tools settings.",dependsOn:{"@sous-io/plugin-build":`^${package_default17.version}`,"@sous-io/plugin-host":`^${package_default17.version}`},register(sous){sous.entities.define("harness",harnessSchema,{description:"A program that wraps a model, used interactively, headless, or both."}),sous.entities.add("config-key",{id:TOOLS_KEY,schema:toolsKeySchema,description:"Tools you can launch with `sous launch <name>`: command, args, promptFile, headless."}),sous.config.contribute(toolsContributor),sous.intents.add({intent:"launch",summary:"Build this project's outputs, then start a coding agent configured in its config",input:launchInput,requiresProject:!0,cli:{positional:["tool"],passThrough:!0,examples:["sous launch claude","sous launch codex --no-build","sous launch claude --continuous","sous launch claude -- -c"]},load:()=>Promise.resolve().then(()=>(init_launch(),launch_exports))}),sous.intents.add({intent:"harness.run-headless",summary:"Run a coding agent with no person at the keyboard, and read its transcript",input:runHeadlessInput,cli:{command:["harness","run-headless"],hidden:!0},load:()=>Promise.resolve().then(()=>(init_run_headless(),run_headless_exports))})}});import{definePlugin as definePlugin18}from"@sous-io/plugin-api";import{jsonSchema as jsonSchema23}from"@sous-io/plugin-api";var yes3={type:"boolean",description:"Answer yes to every confirmation, so nothing is asked"},dryRun3={type:"boolean",description:"Show what would happen, changing nothing"},title={type:"string",description:"The proposal's title; required for a new proposal, and replaces an open one's"},body={type:"string",description:"The proposal's description; required for a new proposal, and replaces an open one's"},releaseInput=jsonSchema23({type:"object",additionalProperties:!1,properties:{directory:{type:"string",description:"The repository to release, or a directory inside it (default: the working directory)"},check:{type:"boolean",description:"Only check: validate, and fail on any problem; reports how merging rewrites the index"},ci:{type:"boolean",description:"Run the way a merge does: never bump, accept the plan, never ask, and fail on anything unbumped"},namespace:{type:"array",items:{type:"string"},description:"Release only this namespace. Repeat to name several"},recipe:{type:"array",items:{type:"string"},description:"Release only this recipe, as 'namespace/name'. Repeat to name several"},bump:{type:"string",enum:["patch","minor","major","prerelease"],description:"How far to raise a changed recipe's version. Defaults to a patch step"},noBump:{type:"boolean",description:"Raise no versions; a changed recipe that was never raised is an error"},includeUnchanged:{type:"boolean",description:"Release every recipe in scope, whether its files changed or not"},tag:{type:"boolean",description:"Cut the tags even on a branch other than the default one"},push:{type:"boolean",description:"Push the commit, and the tags this run created, to the remote"},yes:{...yes3,description:"Accept the plan without being asked"},dryRun:{...dryRun3,description:"Print the plan and stop, changing nothing"}}}),submitInput=jsonSchema23({type:"object",additionalProperties:!1,properties:{repo:{type:"string",description:"The linked repository to propose a change from, when run inside a project"},directory:{type:"string",description:"The directory to start from (default: the working directory)"},title,body,branch:{type:"string",description:"The branch to work with, instead of the one that is checked out"},status:{type:"boolean",description:"Only report where the branch's proposal stands"},commit:{type:"boolean",description:"Commit uncommitted changes for you, after listing them and asking once"},draft:{type:"boolean",description:"Open a new proposal as a draft"},nextBranch:{type:"string",description:"The new branch to continue on when the branch's proposal was already merged"},acceptFirst:{type:"boolean",description:"When the repository named matches several, take the first one listed"},yes:yes3,dryRun:{...dryRun3,description:"Check everything and print the plan without writing or sending anything"}}}),contributeInput=jsonSchema23({type:"object",additionalProperties:!1,required:["ref"],properties:{ref:{type:"string",description:"The repository to contribute to, or a namespace or recipe it publishes"},finish:{type:"boolean",description:"Finish the contribution: submit what no proposal carries yet, then unlink and update the pins"},branch:{type:"string",description:"The existing branch to work on when starting, or to submit from when finishing"},createBranch:{type:"string",description:"Start the contribution on a new branch with this name"},generateBranch:{type:"boolean",description:"Start the contribution on a new branch named sous/edit-<date>-<time>, which is what happens when no branch is named"},from:{type:"string",description:"Start the new branch from this branch instead of the repository's default branch"},global:{type:"boolean",description:"Work with the machine-wide link, sharing one checkout, rather than this project's link"},submit:{type:"boolean",description:"Submit what no proposal carries yet without asking, or with --no-submit, finish without submitting it"},title,body,draft:{type:"boolean",description:"Open a new proposal as a draft"},commit:{type:"boolean",description:"Commit uncommitted changes for you when submitting, after listing them and asking once"},remove:{type:"boolean",description:"Delete the checkout as well when unlinking, when sous cloned it"},yes:yes3,acceptFirst:{type:"boolean",description:"When the reference matches several things, take the first one listed"},dryRun:{...dryRun3,description:"Print each step this would run without running any of them"}}}),initInput=jsonSchema23({type:"object",additionalProperties:!1,properties:{directory:{type:"string",description:"Directory to create the repository in (defaults to the current one)"},name:{type:"string",description:"Short name for the repository (defaults to the directory's own name)"},namespace:{type:"string",description:"Name of the one namespace to declare (defaults to the repository's name)"},force:{type:"boolean",description:"Write the scaffold over a repository that already exists"},host:{type:"string",description:"The repository host whose CI workflow and files to add, such as 'github' (default: from the git remote, else none)"},dryRun:{...dryRun3,description:"Print the files that would be written without writing them"}}});var package_default18={name:"@sous-io/plugin-authoring",version:"1.0.12",description:"Releasing, submitting and contributing to recipe repositories, and scaffolding one.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/documents":"workspace:*","@sous-io/plugin-api":"workspace:*","@sous-io/plugin-formats":"workspace:*","@sous-io/plugin-git":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/plugin-refs":"workspace:*","@sous-io/plugin-variables":"workspace:*",semver:"^7.8.5"},devDependencies:{"@sous-io/core":"workspace:*","@sous-io/plugin-cli":"workspace:*","@sous-io/plugin-host":"workspace:*","@types/semver":"^7.8.0"},engines:{node:">=22"}};var PLUGIN_NAME17="@sous-io/plugin-authoring",yesFlag2={yes:{short:"y",aliases:["force"]}},authoringPlugin=definePlugin18({name:PLUGIN_NAME17,version:package_default18.version,description:"Releasing, submitting and contributing to recipe repositories, and scaffolding one.",dependsOn:{"@sous-io/plugin-recipes":`^${package_default18.version}`,"@sous-io/plugin-formats":`^${package_default18.version}`,"@sous-io/plugin-refs":`^${package_default18.version}`,"@sous-io/plugin-variables":`^${package_default18.version}`,"@sous-io/plugin-git":`^${package_default18.version}`},register(sous){sous.intents.add({intent:"repo.release",summary:"Publish new versions of this repository's recipes: bump, regenerate the index, commit and tag",description:"Runs inside a recipe repository. Validates it, raises the version of every changed recipe, regenerates sous.index.json, commits the manifests and the index, and tags each version. --check only reads (for a pull request); --ci runs the way a merge does.",input:releaseInput,cli:{aliases:[["repos","release"]],flags:{...yesFlag2,directory:{hidden:!0}},examples:["sous repo release","sous repo release --dry-run","sous repo release --namespace workflow --bump minor","sous repo release --recipe workflow/task-files --yes --push","sous repo release --check","sous repo release --ci --push"]},agent:{usage:"Call this inside a recipe repository to publish its changed recipes. Use check: true to validate without writing.",whenNotToUse:"Not for a sous project; it releases the recipe repository it runs in."},load:async()=>(await Promise.resolve().then(()=>(init_release(),release_exports))).handleRelease}),sous.intents.add({intent:"repo.submit",summary:"Propose a recipe repository's changes to its maintainers, and follow the proposal through",description:"Validates the checkout, then pushes its branch and opens or updates a proposal through the repository host. Needs the host's command line tool (gh, glab) signed in.",input:submitInput,cli:{aliases:[["repos","submit"]],positional:["repo"],flags:{...yesFlag2,directory:{hidden:!0}},examples:['sous repo submit --title "Add a linting recipe" --body "Adds lint rules."',"sous repo submit sous-recipes","sous repo submit --status",'sous repo submit --commit --yes --title "Fix a typo" --body "Fixes it."',"sous repo submit --dry-run"]},agent:{usage:"Call this to propose committed changes in a recipe repository checkout. A new proposal needs title and body."},load:async()=>(await Promise.resolve().then(()=>(init_submit(),submit_exports))).handleSubmit}),sous.intents.add({intent:"repo.contribute",summary:"Start a contribution to a recipe repository on a fresh branch, or finish one with --finish",description:"Starting links the repository on a new branch (repo link --latest). Finishing submits what no proposal carries yet (repo submit), then unlinks and updates the pins (repo unlink --update).",input:contributeInput,changesConfig:!0,requiresProject:!0,cli:{aliases:[["repos","contribute"],["repo","contrib"],["repos","contrib"]],positional:["ref"],flags:yesFlag2,examples:["sous repo contribute sous-recipes","sous repo contribute workflow/task-files","sous repo contribute sous-recipes --create-branch fix-a-typo",'sous repo contribute sous-recipes --finish --title "Fix a typo" --body "Fixes it."',"sous repo contribute sous-recipes --finish --no-submit --remove","sous repo contribute sous-recipes --finish --dry-run"]},agent:{usage:"Call this to start editing a recipe repository from a project, and again with finish: true to propose and unlink."},load:async()=>(await Promise.resolve().then(()=>(init_contribute(),contribute_exports))).handleContribute}),sous.intents.add({intent:"repo.init",summary:"Create a new sous recipe repository in a directory",input:initInput,cli:{aliases:[["repos","init"]],positional:["directory"],examples:["sous repo init","sous repo init ./my-recipes","sous repo init ./my-recipes --name team-recipes --namespace workflow","sous repo init ./my-recipes --host github","sous repo init ./my-recipes --dry-run"]},agent:{usage:"Call this to scaffold a new recipe repository."},load:async()=>(await Promise.resolve().then(()=>(init_scaffold(),scaffold_exports))).handleInit})}});import{definePlugin as definePlugin19,jsonSchema as jsonSchema24}from"@sous-io/plugin-api";var package_default19={name:"@sous-io/plugin-init",version:"1.0.12",description:"Scaffolding a project's .sous/ (sous init).",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-build":"workspace:*","@sous-io/plugin-config-files":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};init_templates2();init_package_json();init_scaffold2();var PLUGIN_NAME18="@sous-io/plugin-init",initInput2=jsonSchema24({type:"object",properties:{directory:{type:"string",description:"Project directory to set up (defaults to the current one)."},name:{type:"string",description:"Display name for the project (defaults to the directory's own name)."},yes:{type:"boolean",default:!1,description:"Answer yes to the one question init can ask: setting a project up inside another one."},dryRun:{type:"boolean",default:!1,description:"Show the files that would be written without writing them."},noBuild:{type:"boolean",default:!1,description:"Write the setup without running the first build."}},additionalProperties:!1}),initPlugin=definePlugin19({name:PLUGIN_NAME18,version:package_default19.version,description:"Scaffolding a project's .sous/ (sous init).",dependsOn:{"@sous-io/plugin-build":`^${package_default19.version}`,"@sous-io/plugin-config-files":`^${package_default19.version}`,"@sous-io/plugin-host":`^${package_default19.version}`},register(sous){sous.intents.add({intent:"init",summary:"Set a project up for sous: write its .sous/ directory, then run the first build",input:initInput2,changesConfig:!0,cli:{positional:["directory"],examples:["sous init","sous init ./my-project","sous init --name 'My Project' --no-build","sous init --dry-run"],flags:{yes:{short:"y",aliases:["force"]}}},agent:{usage:"Set up a new project. Pass yes so no question is asked, and dryRun first to see the files."},load:()=>Promise.resolve().then(()=>(init_init(),init_exports))})}});import{definePlugin as definePlugin20,jsonSchema as jsonSchema25}from"@sous-io/plugin-api";var SCAN_CONTRIBUTOR2="update.scan";function scanContext(sous){return{plugin:sous.plugin.name,get config(){return sous.engine.config},services:sous.services,entities:sous.entities,project:sous.project,env:sous.env}}function scanContributor(sous){return{id:SCAN_CONTRIBUTOR2,monitors:["plugins.discover","plugins.load",{entities:"package-manager"}],async contribute(config2){if(config2.atPath("plugins.discover").valueOr("dependencies")!=="scan"||config2.project===void 0)return;let ctx=scanContext(sous),root=config2.project.root,load=config2.atPath("plugins.load"),known=new Set(load.valueOr([])),found=new Set;for(let manager of config2.entities("package-manager"))try{if(await manager.detect(root,ctx)===void 0)continue;for(let pkg of await manager.installed("project",root,ctx))pkg.isSousPlugin&&!known.has(pkg.name)&&found.add(pkg.name)}catch(error51){config2.warn(`${manager.id} could not list the installed packages: ${error51 instanceof Error?error51.message:String(error51)}`)}for(let name of[...found].sort())load.append(name)}}}var package_default20={name:"@sous-io/plugin-update",version:"1.0.12",description:"Updating sous itself, installing plugins a recipe requires, the package-manager entity, scanning for installed plugins.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-host":"workspace:*",semver:"^7.8.5"},devDependencies:{"@sous-io/core":"workspace:*","@types/semver":"^7.8.0"},engines:{node:">=22"}};var PLUGIN_NAME19="@sous-io/plugin-update",packageManagerSchema=jsonSchema25({type:"object",required:["id"],properties:{id:{type:"string",description:"What names the manager: `npm`, `pnpm`, `yarn`."},description:{type:"string"}}}),updateInput=jsonSchema25({type:"object",properties:{major:{type:"boolean",default:!1,description:"Install the newest published version, whatever its major version."},version:{type:"string",description:"Install this version, the newest version in this range, or the version this dist-tag names."},prerelease:{type:"boolean",description:"Count prerelease versions as candidates; on by default when the installed version is a prerelease."},global:{type:"boolean",default:!1,description:"Update only the global install."},project:{type:"boolean",default:!1,description:"Update only this project's own install."},yes:{type:"boolean",default:!1,description:"Answer yes to every question."},dryRun:{type:"boolean",default:!1,description:"Show every install's plan without installing anything."},noBuild:{type:"boolean",default:!1,description:"Update the project install without building the project afterwards."}},additionalProperties:!1}),pluginsInstallInput=jsonSchema25({type:"object",required:["plugins"],properties:{plugins:{type:"array",items:{type:"string"},description:"Plugins to install, as `name` or `name@range`."},section:{enum:["dependencies","devDependencies"],default:"devDependencies",description:"The package.json section to add them to."},yes:{type:"boolean",default:!1,description:"Install without asking."},dryRun:{type:"boolean",default:!1,description:"Show the command without running it."}},additionalProperties:!1}),updatePlugin=definePlugin20({name:PLUGIN_NAME19,version:package_default20.version,description:"Updating sous itself, installing plugins a recipe requires, the package-manager entity, scanning for installed plugins.",dependsOn:{"@sous-io/plugin-host":`^${package_default20.version}`},register(sous){sous.entities.define("package-manager",packageManagerSchema,{description:"A package manager: detecting it, listing installed packages, planning installs."}),sous.config.contribute(scanContributor(sous)),sous.intents.add({intent:"update",summary:"Update sous itself, globally and in this project, through the package manager that installed each copy",input:updateInput,toleratesConfigErrors:!0,cli:{examples:["sous update","sous update --global","sous update --major","sous update --version 0.2.18","sous update --version next","sous update --dry-run"],flags:{yes:{short:"y",aliases:["force"]},prerelease:{aliases:["pre"]}}},agent:{usage:"Move sous to a newer version. Pass yes so no question is asked; use dryRun first to see the plan."},load:()=>Promise.resolve().then(()=>(init_update(),update_exports))}),sous.intents.add({intent:"plugins.install",summary:"Install npm plugins through the project's package manager",input:pluginsInstallInput,cli:{command:["plugins","install"],positional:["plugins"],examples:["sous plugins install sous-plugin-claude-code","sous plugins install sous-plugin-x@^1.0.0 --yes"],flags:{yes:{short:"y",aliases:["force"]}}},load:()=>Promise.resolve().then(()=>(init_plugins_install(),plugins_install_exports))})}});import{definePlugin as definePlugin21}from"@sous-io/plugin-api";init_src();import nodePath from"node:path";import{IntentOutputs as IntentOutputs22,NotFoundError as NotFoundError11,SousError as SousError29}from"@sous-io/plugin-api";import{ConfigError as ConfigError64,DataValue as DataValue2,IntentOutput as IntentOutput18,ReportEntryStyle as ReportEntryStyle14,Table as Table5,TextBlock as TextBlock11,Tree as Tree2,VariableSet as VariableSet10}from"@sous-io/plugin-api";function truncateJson(value,max=80){let encoded=JSON.stringify(value);return encoded===void 0?"undefined":encoded.length>max?`${encoded.slice(0,max-1)}\u2026`:encoded}function isScalar3(value){return value===null||typeof value=="string"||typeof value=="number"||typeof value=="boolean"}function plural2(count2,singular,pluralForm=`${singular}s`){return`${count2} ${count2===1?singular:pluralForm}`}function missingValue(path103){return new ConfigError64(`No value at config path '${path103}'.`,{details:["It is not present in the built config.","Run 'sous config show' to see the whole config."]})}function missingInLayers(path103){return new ConfigError64(`No value at config path '${path103}' in any config layer.`,{details:["Run 'sous config show' to see the whole config."]})}function rawFileOutputs(files){return files.map(file2=>new IntentOutput18({result:new TextBlock11(`# ${file2.path} (${file2.contributor})
960
961
  ${file2.text.replace(/\n$/,"")}`,{verbatim:!0})}))}function configShowOutputs(result){if(!result.layers&&!result.raw)return[new IntentOutput18({result:new DataValue2(result.config)})];let outputs=[];return result.raw&&outputs.push(...rawFileOutputs(result.raw)),result.layers&&(outputs.push(new IntentOutput18({result:layerTree(result.layers)})),outputs.push(new IntentOutput18({result:new VariableSet10([{label:"result",value:`settled after ${plural2(result.passes,"pass","passes")}`}])}))),outputs}function configGetOutputs(result){let outputs=result.raw?rawFileOutputs(result.raw):[];if(result.layers){if(!result.exists&&result.layers.length===0)throw missingInLayers(result.path);outputs.push(new IntentOutput18({result:layerTable(result)}));let shown=result.exists&&result.value!==void 0?truncateJson(result.value):"(not set)";return outputs.push(new IntentOutput18({result:new VariableSet10([{label:"result",value:shown,detail:`settled after ${plural2(result.passes,"pass","passes")}`}])})),outputs}if(!result.exists||result.value===void 0)throw missingValue(result.path);return outputs.push(new IntentOutput18({result:isScalar3(result.value)?new TextBlock11(String(result.value),{verbatim:!0}):new DataValue2(result.value)})),outputs}function configValidateOutputs(result){if(result.ok){let summary=result.summary;return[new IntentOutput18({title:"Config is valid",...summary===void 0?{}:{result:new VariableSet10({"Config File":summary.configFile??"(none)",Layers:summary.layers,Targets:summary.targets,Tools:summary.tools.length>0?summary.tools.join(", "):"(none)"})}})]}return[new IntentOutput18({title:`The config has ${plural2(result.issues.length,"problem")}`}),...result.issues.map(issue2=>new IntentOutput18({result:new TextBlock11(issue2),style:ReportEntryStyle14.Problem}))]}var REGISTRATION_LABELS={intent:"intents","intent wrapper":"wraps intents",service:"services","service replacement":"replaces","service wrapper":"wraps","entity kind":"entity kinds",entity:"entities",contributor:"contributors","front end":"front ends",listener:"listeners"};function pluginsShowOutputs(plugins){return plugins.map(plugin=>{let notes=[plugin.builtIn?"built in":plugin.loadedBy?`loaded by ${plugin.loadedBy}`:void 0,plugin.active?void 0:"inactive"].filter(note=>note!==void 0),version2=plugin.version?` ${plugin.version}`:"",groups=new Map;for(let registration of plugin.registrations){let label=REGISTRATION_LABELS[registration.kind]??registration.kind,names2=groups.get(label)??[];names2.push(registration.name),groups.set(label,names2)}let entries=[...groups].map(([label,names2])=>({label,value:names2.join(" ")}));plugin.options&&Object.keys(plugin.options).length>0&&entries.push({label:"options",value:JSON.stringify(plugin.options,null,1).replace(/\n\s*/g," ")});let title2=`${plugin.name}${version2}${notes.length>0?` (${notes.join(", ")})`:""}`;return new IntentOutput18(entries.length>0?{title:title2,result:new VariableSet10(entries)}:{title:title2})})}function timingsShowOutput(entries){let rows=[...entries].sort((a,b)=>b.totalMs-a.totalMs).map(entry=>({name:entry.key,calls:entry.count,total:`${entry.totalMs.toFixed(1)} ms`,max:`${entry.maxMs.toFixed(1)} ms`,budget:`${entry.budgetMs===!1?"no budget warning":`budget ${entry.budgetMs} ms`}${entry.overBudget>0?`, ${entry.overBudget} over`:""}`}));return new IntentOutput18({result:new Table5([{key:"name",header:"Name",overflow:"truncate",truncate:"middle"},{key:"calls",header:"Calls",kind:"number"},{key:"total",header:"Total",kind:"number"},{key:"max",header:"Max",kind:"number"},{key:"budget",header:"Budget",priority:"low"}],rows,{title:"Timings",empty:"No timings yet."})})}function layerTree(layers){let roots=[],contributor;for(let layer of layers){if(layer.contributor!==contributor||roots.length===0){contributor=layer.contributor;let details=[...layer.source?[layer.contributor]:[],layer.plugin,...applyOrderText(layer)];roots.push({label:layer.source??layer.contributor,detail:details.join(", "),children:[]})}let parent=roots[roots.length-1];for(let helper of layer.helpers){let last2=parent.children[parent.children.length-1];if(last2!==void 0&&last2.label===helper&&last2.children.length>0)parent=last2;else{let node={label:helper,children:[]};parent.children.push(node),parent=node}}parent.children.push({label:describePatch(layer.patch),children:annotationLines(layer).map(line=>({label:line,children:[]}))})}return new Tree2(roots)}function applyOrderText(layer){return layer.actualApplyOrder===layer.applyOrder?[`apply order ${layer.applyOrder}`]:[`apply order ${layer.applyOrder}, moved to ${layer.actualApplyOrder}`]}var LAYER_COLUMNS=[{key:"source",header:"Config",overflow:"truncate",kind:"path"},{key:"change",header:"Change",overflow:"wrap",flex:1}];function layerTable(result){let rows=[];for(let layer of result.layers??[]){let text=layer.change?`${shownOrUnset(layer.change,"from")} -> ${shownOrUnset(layer.change,"to")}`:changeAt(layer.patch,result.path);rows.push({source:layer.source??layer.contributor,change:text});for(let line of annotationLines(layer))rows.push({source:"",change:line})}return new Table5(LAYER_COLUMNS,rows)}function shownOrUnset(change,side){return side in change&&change[side]!==void 0?truncateJson(change[side]):"(unset)"}function changeAt(patch,path103){if(targetOf(patch)===path103)switch(patch.op){case"setKey":case"setIndex":case"insertAt":return truncateJson(patch.value);case"deleteKey":case"removeIndex":return"(not set)";case"renameKey":return`(renamed to ${patch.to})`}return describePatch(patch)}function describePatch(patch){let target=targetOf(patch);switch(patch.op){case"setKey":case"setIndex":case"insertAt":return`${patch.op} ${target} = ${truncateJson(patch.value)}`;case"renameKey":return`${patch.op} ${target} \u2192 ${patch.to}`;default:return`${patch.op} ${target}`}}function targetOf(patch){let base=patch.path;return patch.op==="setIndex"||patch.op==="insertAt"||patch.op==="removeIndex"?`${base}[${patch.index}]`:/^[A-Za-z_$][\w$-]*$/.test(patch.key)?base===""?patch.key:`${base}.${patch.key}`:`${base}${base===""?"":"."}"${patch.key}"`}function annotationLines(layer){return Object.entries(layer.annotations??{}).map(([key,value])=>`${key}: ${typeof value=="string"?value:truncateJson(value)}`)}import path89 from"node:path";var HIDDEN="(hidden)",SECRET_KEY=/(pass(word|wd|phrase)?|secret|token|api[-_]?key|private[-_]?key|credential|authorization|bearer)/i;function isSecretKey(key){return SECRET_KEY.test(key)}var KEY_NAME_POLICY={isSecret:(key,value)=>isSecretKey(key)&&value!==null&&value!=="",isSecretName:isSecretKey};function servicePolicy(secrets){let declared=secrets.declared();return{isSecret:(key,value)=>secrets.isSecret(key,value,declared)||typeof value=="string"&&secrets.hasSecretValue(value),isSecretName:name=>declared.has(name)||secrets.hasSecretName(name)}}function redactValue(value,policy=KEY_NAME_POLICY){if(Array.isArray(value))return value.map(item=>redactValue(item,policy));if(value!==null&&typeof value=="object"){let out={};for(let[key,inner]of Object.entries(value))out[key]=redactUnder(key,inner,policy);return out}return value}function redactUnder(key,value,policy=KEY_NAME_POLICY){return(value!==null&&typeof value=="object"?policy.isSecretName(key):policy.isSecret(key,value))?HIDDEN:redactValue(value,policy)}function pathHasSecret(path103,policy){return path103.split(/[.[\]"]+/).some(segment=>segment!==""&&policy.isSecretName(segment))}function redactPatch(patch,policy=KEY_NAME_POLICY){if(patch.op==="setKey"){let secret=policy.isSecretName(patch.key)||pathHasSecret(patch.path,policy);return{...patch,value:secret?HIDDEN:redactUnder(patch.key,patch.value,policy)}}return patch.op==="setIndex"||patch.op==="insertAt"?{...patch,value:pathHasSecret(patch.path,policy)?HIDDEN:redactValue(patch.value,policy)}:patch}function redactLayer(layer,policy=KEY_NAME_POLICY){return{...layer,patch:redactPatch(layer.patch,policy)}}var KEY_VALUE=/(["']?)([\w$.-]+)\1(\s*[:=]\s*)("(?:\\.|[^"\\])*"|'[^']*'|[^\s,{}[\]#]+)/g;function redactText(text,policy=KEY_NAME_POLICY){return text.replace(KEY_VALUE,(whole,quote2,key,separator)=>policy.isSecretName(key)?`${quote2}${key}${quote2}${separator}"${HIDDEN}"`:whole)}var MAIN_CONTRIBUTOR2="config-files.main",MAIN_PATCH_PREFIX="config-files/";function configFiles(project,services){let files=[],loader=services.has("config-files.loader")?services.get("config-files.loader"):void 0;project.configPath!==void 0&&files.push({contributor:MAIN_CONTRIBUTOR2,path:project.configPath});for(let file2 of loader?.findPatches(project.sousDir)??[])files.push({contributor:`${MAIN_PATCH_PREFIX}${path89.basename(file2)}`,path:file2});return services.has("confd.files")&&files.push(...services.get("confd.files").list()),files}async function readRawConfigFiles(project,services,policy=KEY_NAME_POLICY){if(project===void 0||!services.has("config-files.loader"))return[];let loader=services.get("config-files.loader"),raw2=[];for(let file2 of configFiles(project,services))try{let loaded=await loader.load(file2.path);raw2.push({contributor:file2.contributor,path:file2.path,text:redactText(loaded.text,policy)})}catch{}return raw2}function policyOf(ctx){return ctx.services.has("variables.secrets")?servicePolicy(ctx.services.get("variables.secrets")):KEY_NAME_POLICY}var MAIN_CONTRIBUTOR3="config-files.main",MAIN_PATCH_PREFIX2="config-files/";function layersOf(ctx,path103,policy){let target=parsePath(path103),sources=sourcesOf(ctx),views=[],before;for(let layer of ctx.config.layers(path103)){let view={...redactLayer(layer,policy),...withSource(sources.get(layer.contributor))},after=valueAfter(view.patch,target);if(after===UNKNOWN){views.push(view);continue}JSON.stringify(after)!==JSON.stringify(before)&&(views.push({...view,change:{...before===void 0?{}:{from:before},...after===void 0?{}:{to:after}}}),before=after)}return views}function withSource(source){return source===void 0?{}:{source}}var UNKNOWN=Symbol("unknown");function valueAfter(patch,target){if(patch.op==="renameKey")return UNKNOWN;let at2=[...parsePath(patch.path),patch.op==="setKey"||patch.op==="deleteKey"?patch.key:patch.index];if(!isPathPrefix(at2,target))return UNKNOWN;let rest=target.slice(at2.length);switch(patch.op){case"setKey":case"setIndex":return getAtPath(patch.value,rest);case"deleteKey":return;case"insertAt":case"removeIndex":return rest.length>0?UNKNOWN:patch.op==="insertAt"?patch.value:UNKNOWN}}function sourcesOf(ctx){let sources=new Map,project=ctx.project;if(project===void 0)return sources;let fromSousDir=file2=>{let relative4=nodePath.relative(project.sousDir,file2);return relative4!==""&&!relative4.startsWith("..")?relative4:file2};project.configPath!==void 0&&sources.set(MAIN_CONTRIBUTOR3,fromSousDir(project.configPath));for(let contribution of ctx.config.contributions())contribution.contributor.startsWith(MAIN_PATCH_PREFIX2)&&sources.set(contribution.contributor,fromSousDir(nodePath.join(project.sousDir,contribution.contributor.slice(MAIN_PATCH_PREFIX2.length))));for(let file2 of ctx.services.has("confd.files")?ctx.services.get("confd.files").list():[])sources.set(file2.contributor,fromSousDir(file2.path));return sources}async function configShow(input,ctx){let policy=policyOf(ctx),result={config:redactValue(ctx.config.value(),policy),passes:ctx.config.passes,...input.layers===!0?{layers:layersOf(ctx,"",policy)}:{},...input.raw===!0?{raw:await readRawConfigFiles(ctx.project,ctx.services,policy)}:{}};return new IntentOutputs22(configShowOutputs(result)).withData(result)}async function configGet(input,ctx){let exists3=ctx.config.has(input.path),value=exists3?ctx.config.get(input.path):void 0,lastKey=input.path.split(/[.[\]"]+/).filter(part=>part!=="").pop()??"",policy=policyOf(ctx),shown=value===void 0?void 0:redactUnder(lastKey,value,policy),result={path:input.path,exists:exists3,value:shown,passes:ctx.config.passes,...input.layers===!0?{layers:layersOf(ctx,input.path,policy)}:{},...input.raw===!0?{raw:await readRawConfigFiles(ctx.project,ctx.services,policy)}:{}};return new IntentOutputs22(configGetOutputs(result)).withData(result)}async function configValidate(_input,ctx){let issues=[];for(let key of ctx.entities.list("config-key")){if(!ctx.config.has(key.id))continue;let value=ctx.config.get(key.id),result2=await key.schema["~standard"].validate(value);if(result2.issues===void 0)continue;let setBy2=[...new Set(ctx.config.layers(key.id).map(layer=>layer.contributor))],who=setBy2.length>0?` (set by ${setBy2.join(", ")})`:"";for(let issue2 of result2.issues){let inner=(issue2.path??[]).map(segment=>String(typeof segment=="object"?segment.key:segment)),at2=[key.id,...inner].join(".");issues.push(`${at2}: ${issue2.message}${who}`)}}issues.push(...variableIssues(ctx));let result={ok:issues.length===0,issues,summary:summaryOf2(ctx)};return new IntentOutputs22(configValidateOutputs(result),result.ok?{}:{exitCode:1}).withData(result)}function variableIssues(ctx){if(!ctx.services.has("variables.resolver"))return[];let resolver=ctx.services.get("variables.resolver"),targets=ctx.config.get("compilation.targets")??[],issues=[],attempt=work=>{try{return work(),!0}catch(error51){if(!(error51 instanceof SousError29))throw error51;return issues.push([error51.message,...error51.details].join(`
961
- `)),!1}};if(!attempt(()=>resolver.scope({level:"root"})))return issues;for(let[target,value]of targets.entries()){let{outputs,...own}=value??{};attempt(()=>resolver.substituteValue(withoutVars(own),resolver.scope({level:"target",target}),`compilation.targets[${target}]`));for(let[output,outputValue]of(Array.isArray(outputs)?outputs:[]).entries())attempt(()=>resolver.substituteValue(withoutVars(outputValue??{}),resolver.scope({level:"output",target,output}),`compilation.targets[${target}].outputs[${output}]`))}return issues}function withoutVars(value){let{_vars:_ignored,...rest}=value;return rest}function summaryOf2(ctx){let confd=ctx.services.has("confd.files")?ctx.services.get("confd.files").list().length:0,main2=ctx.project?.configPath===void 0?0:1,tools=ctx.config.get("tools")??{};return{configFile:ctx.project?.configPath,layers:main2+confd,targets:(ctx.config.get("compilation.targets")??[]).length,tools:Object.keys(tools)}}function pluginsShow(input,ctx){let policy=policyOf(ctx),plugins=ctx.engine.plugins().map(plugin=>plugin.options===void 0?plugin:{...plugin,options:redactValue(plugin.options,policy)}),done2=shown=>new IntentOutputs22(pluginsShowOutputs(shown)).withData({plugins:shown});if(input.name===void 0)return done2(plugins);let found=plugins.filter(plugin=>plugin.name===input.name);if(found.length===0)throw new NotFoundError11("plugin",input.name,`No plugin named "${input.name}" is loaded.`,{details:["Run 'sous plugins show' to see every loaded plugin."]});return done2(found)}function timingsShow(input,ctx){let timings=ctx.engine.timings.entries().filter(entry=>(input.overBudget!==!0||entry.overBudget>0)&&(input.category===void 0||entry.category===input.category)).sort((a,b)=>b.totalMs-a.totalMs);return new IntentOutputs22([timingsShowOutput(timings)]).withData({timings})}import{jsonSchema as jsonSchema26}from"@sous-io/plugin-api";var configShowSchema=jsonSchema26({type:"object",properties:{layers:{type:"boolean",description:"Show each contributor's changes, in order, and the passes."},raw:{type:"boolean",description:"Show each config file as written, in order."}}}),configGetSchema=jsonSchema26({type:"object",properties:{path:{type:"string",description:"Path into the config, with [n] for array indices."},layers:{type:"boolean",description:"Show each contributor's changes to the value, in order."},raw:{type:"boolean",description:"Show each config file as written, in order."}},required:["path"]}),pluginsShowSchema=jsonSchema26({type:"object",properties:{name:{type:"string",description:"Only this plugin."}}}),timingsShowSchema=jsonSchema26({type:"object",properties:{overBudget:{type:"boolean",description:"Only entries that went over budget."},category:{type:"string",description:"Only one category, such as contributor or intent."}}});var package_default21={name:"@sous-io/plugin-inspect",version:"1.0.11",description:"Showing the engine's state: config show, config get, config validate, plugins show, timings.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/documents":"workspace:*","@sous-io/plugin-api":"workspace:*","@sous-io/plugin-confd":"workspace:*","@sous-io/plugin-config-files":"workspace:*","@sous-io/plugin-variables":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*","@sous-io/plugin-host":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME20="@sous-io/plugin-inspect",inspectPlugin=definePlugin21({name:PLUGIN_NAME20,version:package_default21.version,description:"Showing the engine's state: config show, config get, config validate, plugins show, timings.",dependsOn:{},register(sous){sous.intents.add({intent:"config.show",requiresProject:!0,summary:"Print the built config",description:"Prints what sous does on this machine. --layers adds each contributor's changes, in order; --raw adds each config file as written.",input:configShowSchema,parallel:!0,cli:{examples:["sous config show","sous config show --layers","sous config show --raw"]},agent:{usage:"Read the config as sous built it. Secrets are hidden."},handle:configShow}),sous.intents.add({intent:"config.get",requiresProject:!0,summary:"Print one value from the built config by path",description:"A path like compilation.targets[0].entryPoint. --layers shows who set the value, in order.",input:configGetSchema,parallel:!0,cli:{positional:["path"],examples:["sous config get name","sous config get compilation.targets[0].entryPoint","sous config get compilation --layers"]},agent:{usage:"Read one config value by path. Secrets are hidden."},handle:configGet}),sous.intents.add({intent:"config.validate",requiresProject:!0,summary:"Check the built config against every config key's schema",parallel:!0,cli:{examples:["sous config validate"]},handle:configValidate}),sous.intents.add({intent:"plugins.show",summary:"Show every plugin, and what it registered, wrapped or replaced",input:pluginsShowSchema,parallel:!0,cli:{positional:["name"],examples:["sous plugins show","sous plugins show @sous-io/plugin-git"]},handle:pluginsShow}),sous.intents.add({intent:"timings.show",summary:"Show every timing of this run and its budget",input:timingsShowSchema,parallel:!0,cli:{examples:["sous timings show","sous timings show --over-budget"]},handle:timingsShow})}});import{definePlugin as definePlugin22,IntentOutputs as IntentOutputs23,jsonSchema as jsonSchema27}from"@sous-io/plugin-api";import{InputError as InputError8,toJsonSchema as toJsonSchema3}from"@sous-io/plugin-api";function toolName(definition){return definition.agent?.tool??definition.intent.replace(/\./g,"_")}function isAgentVisible(definition){return definition.internal!==!0&&definition.agent?.hidden!==!0&&definition.background!==!0}function toolDescription(definition){let parts=[],summary=definition.summary??definition.description;return parts.push(summary??`Runs the sous intent "${definition.intent}".`),definition.agent?.usage&&parts.push(definition.agent.usage),definition.agent?.whenNotToUse&&parts.push(`When not to use it: ${definition.agent.whenNotToUse}`),parts.join(`
962
+ `)),!1}};if(!attempt(()=>resolver.scope({level:"root"})))return issues;for(let[target,value]of targets.entries()){let{outputs,...own}=value??{};attempt(()=>resolver.substituteValue(withoutVars(own),resolver.scope({level:"target",target}),`compilation.targets[${target}]`));for(let[output,outputValue]of(Array.isArray(outputs)?outputs:[]).entries())attempt(()=>resolver.substituteValue(withoutVars(outputValue??{}),resolver.scope({level:"output",target,output}),`compilation.targets[${target}].outputs[${output}]`))}return issues}function withoutVars(value){let{_vars:_ignored,...rest}=value;return rest}function summaryOf2(ctx){let confd=ctx.services.has("confd.files")?ctx.services.get("confd.files").list().length:0,main2=ctx.project?.configPath===void 0?0:1,tools=ctx.config.get("tools")??{};return{configFile:ctx.project?.configPath,layers:main2+confd,targets:(ctx.config.get("compilation.targets")??[]).length,tools:Object.keys(tools)}}function pluginsShow(input,ctx){let policy=policyOf(ctx),plugins=ctx.engine.plugins().map(plugin=>plugin.options===void 0?plugin:{...plugin,options:redactValue(plugin.options,policy)}),done2=shown=>new IntentOutputs22(pluginsShowOutputs(shown)).withData({plugins:shown});if(input.name===void 0)return done2(plugins);let found=plugins.filter(plugin=>plugin.name===input.name);if(found.length===0)throw new NotFoundError11("plugin",input.name,`No plugin named "${input.name}" is loaded.`,{details:["Run 'sous plugins show' to see every loaded plugin."]});return done2(found)}function timingsShow(input,ctx){let timings=ctx.engine.timings.entries().filter(entry=>(input.overBudget!==!0||entry.overBudget>0)&&(input.category===void 0||entry.category===input.category)).sort((a,b)=>b.totalMs-a.totalMs);return new IntentOutputs22([timingsShowOutput(timings)]).withData({timings})}import{jsonSchema as jsonSchema26}from"@sous-io/plugin-api";var configShowSchema=jsonSchema26({type:"object",properties:{layers:{type:"boolean",description:"Show each contributor's changes, in order, and the passes."},raw:{type:"boolean",description:"Show each config file as written, in order."}}}),configGetSchema=jsonSchema26({type:"object",properties:{path:{type:"string",description:"Path into the config, with [n] for array indices."},layers:{type:"boolean",description:"Show each contributor's changes to the value, in order."},raw:{type:"boolean",description:"Show each config file as written, in order."}},required:["path"]}),pluginsShowSchema=jsonSchema26({type:"object",properties:{name:{type:"string",description:"Only this plugin."}}}),timingsShowSchema=jsonSchema26({type:"object",properties:{overBudget:{type:"boolean",description:"Only entries that went over budget."},category:{type:"string",description:"Only one category, such as contributor or intent."}}});var package_default21={name:"@sous-io/plugin-inspect",version:"1.0.12",description:"Showing the engine's state: config show, config get, config validate, plugins show, timings.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/documents":"workspace:*","@sous-io/plugin-api":"workspace:*","@sous-io/plugin-confd":"workspace:*","@sous-io/plugin-config-files":"workspace:*","@sous-io/plugin-variables":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*","@sous-io/plugin-host":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME20="@sous-io/plugin-inspect",inspectPlugin=definePlugin21({name:PLUGIN_NAME20,version:package_default21.version,description:"Showing the engine's state: config show, config get, config validate, plugins show, timings.",dependsOn:{},register(sous){sous.intents.add({intent:"config.show",requiresProject:!0,summary:"Print the built config",description:"Prints what sous does on this machine. --layers adds each contributor's changes, in order; --raw adds each config file as written.",input:configShowSchema,parallel:!0,cli:{examples:["sous config show","sous config show --layers","sous config show --raw"]},agent:{usage:"Read the config as sous built it. Secrets are hidden."},handle:configShow}),sous.intents.add({intent:"config.get",requiresProject:!0,summary:"Print one value from the built config by path",description:"A path like compilation.targets[0].entryPoint. --layers shows who set the value, in order.",input:configGetSchema,parallel:!0,cli:{positional:["path"],examples:["sous config get name","sous config get compilation.targets[0].entryPoint","sous config get compilation --layers"]},agent:{usage:"Read one config value by path. Secrets are hidden."},handle:configGet}),sous.intents.add({intent:"config.validate",requiresProject:!0,summary:"Check the built config against every config key's schema",parallel:!0,cli:{examples:["sous config validate"]},handle:configValidate}),sous.intents.add({intent:"plugins.show",summary:"Show every plugin, and what it registered, wrapped or replaced",input:pluginsShowSchema,parallel:!0,cli:{positional:["name"],examples:["sous plugins show","sous plugins show @sous-io/plugin-git"]},handle:pluginsShow}),sous.intents.add({intent:"timings.show",summary:"Show every timing of this run and its budget",input:timingsShowSchema,parallel:!0,cli:{examples:["sous timings show","sous timings show --over-budget"]},handle:timingsShow})}});import{definePlugin as definePlugin22,IntentOutputs as IntentOutputs23,jsonSchema as jsonSchema27}from"@sous-io/plugin-api";import{InputError as InputError8,toJsonSchema as toJsonSchema3}from"@sous-io/plugin-api";function toolName(definition){return definition.agent?.tool??definition.intent.replace(/\./g,"_")}function isAgentVisible(definition){return definition.internal!==!0&&definition.agent?.hidden!==!0&&definition.background!==!0}function toolDescription(definition){let parts=[],summary=definition.summary??definition.description;return parts.push(summary??`Runs the sous intent "${definition.intent}".`),definition.agent?.usage&&parts.push(definition.agent.usage),definition.agent?.whenNotToUse&&parts.push(`When not to use it: ${definition.agent.whenNotToUse}`),parts.join(`
962
963
 
963
- `)}function toolInputSchema(definition){let schema=toJsonSchema3(definition.input);return schema?schema.type===void 0&&schema.properties!==void 0?{...schema,type:"object"}:{...schema}:{type:"object",properties:{}}}function toolOutputSchema(definition){let schema=toJsonSchema3(definition.output);return schema?.type==="object"?{...schema}:void 0}function matchesGlob(name,glob){let pattern=glob.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".");return new RegExp(`^${pattern}$`).test(name)}function buildTools(intents,settings={}){let tools=[],warnings=[],owners=new Map,include=settings.include,exclude=settings.exclude??[];for(let info of intents){let definition=info.definition;if(!isAgentVisible(definition))continue;let name=toolName(definition);if(include&&!include.some(glob=>matchesGlob(name,glob))||exclude.some(glob=>matchesGlob(name,glob)))continue;let owner=owners.get(name);if(owner){warnings.push(`Two intents claim the MCP tool "${name}": "${owner.definition.intent}" (${owner.plugin}) and "${definition.intent}" (${info.plugin}). The first keeps it; set agent.tool on one of them.`);continue}owners.set(name,info);let outputSchema2=toolOutputSchema(definition);tools.push({name,intent:definition.intent,description:toolDescription(definition),inputSchema:toolInputSchema(definition),...outputSchema2?{outputSchema:outputSchema2}:{}})}return{tools,warnings}}function createMcpTools(set2){let byName=new Map(set2.tools.map(tool=>[tool.name,tool]));return{warnings:set2.warnings,list:()=>[...set2.tools],toRequest(tool,args){let found=byName.get(tool);if(!found)throw new InputError8(tool,[{path:"",message:`No MCP tool is named "${tool}".`}]);return{intent:found.intent,input:{...args}}}}}var package_default22={name:"@sous-io/plugin-mcp",version:"1.0.11",description:"The sous mcp front end: tools generated from intents, MCP logging and elicitation.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@modelcontextprotocol/sdk":"^1.32.2","@sous-io/plugin-api":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*","@sous-io/plugin-cli":"workspace:*",zod:"^4.4.3"},engines:{node:">=22"}};init_reporter();init_prompter();var PLUGIN_NAME21="@sous-io/plugin-mcp",settingsSchema=jsonSchema27({type:"object",properties:{include:{type:"array",items:{type:"string"},description:"Only tools whose names match these globs."},exclude:{type:"array",items:{type:"string"},default:[],description:"Leaves out tools whose names match these globs."}},additionalProperties:!1}),serveInputSchema=jsonSchema27({type:"object",properties:{transport:{type:"string",enum:["stdio"],default:"stdio",description:"How the client talks to the server."}},additionalProperties:!1});function createMcpPlugin(options={}){return definePlugin22({name:PLUGIN_NAME21,version:package_default22.version,description:"The sous mcp front end: tools generated from intents, MCP logging and elicitation.",dependsOn:{},register(sous){sous.entities.add("config-key",{id:"mcp",description:"MCP server settings: mcp.include and mcp.exclude pick tools by name, with globs.",schema:settingsSchema}),sous.services.add("mcp.tools",config2=>createMcpTools(buildTools(sous.engine.intents.list(),{...config2.get("mcp.include")===void 0?{}:{include:config2.get("mcp.include")},exclude:config2.get("mcp.exclude")??[]})),{lifetime:"config"}),sous.intents.add({intent:"mcp.serve",summary:"Serve this project to agents over MCP",description:"Starts an MCP server on standard input and output. Every command is a tool, and each tool call runs as its own chain, with its messages sent as MCP log messages and its questions as MCP elicitation.",input:serveInputSchema,background:!0,cli:{command:["mcp"],aliases:[["mcp","serve"]],examples:["sous mcp"]},agent:{hidden:!0},async load(){let{serveMcp:serveMcp2}=await Promise.resolve().then(()=>(init_server3(),server_exports));return async(_input,ctx)=>{if(options.transport)return IntentOutputs23.of(await serveMcp2(ctx,{transport:await options.transport()}));let{StdioServerTransport:StdioServerTransport2}=await Promise.resolve().then(()=>(init_stdio2(),stdio_exports)),transport=new StdioServerTransport2;return process.stdin.once("end",()=>{transport.close()}),IntentOutputs23.of(await serveMcp2(ctx,{transport,handleSignals:!0}))}}})}})}var mcpPlugin=createMcpPlugin();import{definePlugin as definePlugin23}from"@sous-io/plugin-api";import fs62 from"node:fs";import path91 from"node:path";import fs61 from"node:fs";import path90 from"node:path";var PLUGIN_KEYWORD="sous-plugin";function readPackageJson3(dir){try{let parsed=JSON.parse(fs61.readFileSync(path90.join(dir,"package.json"),"utf8"));return parsed!==null&&typeof parsed=="object"&&!Array.isArray(parsed)?parsed:void 0}catch{return}}function realpathOr3(target){try{return fs61.realpathSync(target)}catch{return target}}function declaredIn(pkg,name){if(pkg!==void 0)for(let section2 of["devDependencies","dependencies"]){let block=pkg[section2],range3=block!==null&&typeof block=="object"?block[name]:void 0;if(typeof range3=="string")return{section:section2,range:range3}}}function isSousPlugin(pkg){return Array.isArray(pkg.keywords)&&pkg.keywords.includes(PLUGIN_KEYWORD)}function packageNames(modules){let entries;try{entries=fs61.readdirSync(modules,{withFileTypes:!0})}catch{return[]}let names2=[];for(let entry of entries.sort((a,b)=>a.name<b.name?-1:1))if(!entry.name.startsWith("."))if(entry.name.startsWith("@"))try{for(let inner of fs61.readdirSync(path90.join(modules,entry.name)).sort())inner.startsWith(".")||names2.push(`${entry.name}/${inner}`)}catch{}else names2.push(entry.name);return names2}function readInstalled(modules,declaring){let installed2=[];for(let name of packageNames(modules)){let location=path90.join(modules,...name.split("/")),pkg=readPackageJson3(location);if(pkg===void 0)continue;let declared=declaredIn(declaring,name);installed2.push({name,version:typeof pkg.version=="string"?pkg.version:"unknown",location,realPath:realpathOr3(location),isSousPlugin:isSousPlugin(pkg),...declared===void 0?{}:{declared}})}return installed2}function packageManagerField(pkg,manager){let field=pkg?.packageManager;if(typeof field!="string")return;let match2=/^([^@]+)@([^+]+)/.exec(field);return match2!==null&&match2[1]===manager?match2[2]:void 0}function packageManagerName(pkg){let field=pkg?.packageManager;return typeof field=="string"?/^([^@]+)@/.exec(field)?.[1]:void 0}var OTHER_MANAGER_FILES=["yarn.lock",".yarnrc.yml",".pnp.cjs","pnpm-lock.yaml","pnpm-workspace.yaml","bun.lock","bun.lockb","deno.lock"];function lastLine(output){let line=output.trim().split(/\r?\n/).pop()?.trim();return line===void 0||line.length===0?void 0:line}var PLUGIN="@sous-io/plugin-npm";function commandOf(ctx){return ctx.config.get(["plugins","options",PLUGIN])?.command??"npm"}function has2(dir,file2){return fs62.existsSync(path91.join(dir,file2))}var npmManager={id:"npm",description:"npm, the package manager that comes with Node.js.",async detect(projectRoot){let pkg=readPackageJson3(projectRoot),named=packageManagerName(pkg),version2=packageManagerField(pkg,"npm");if(named==="npm"||has2(projectRoot,"package-lock.json")||has2(projectRoot,"npm-shrinkwrap.json"))return{id:"npm",detected:!0,...version2===void 0?{}:{version:version2}};if(!(named!==void 0||OTHER_MANAGER_FILES.some(file2=>has2(projectRoot,file2))))return{id:"npm",detected:!1}},async installed(scope,projectRoot,ctx){if(scope==="project")return projectRoot===void 0?[]:readInstalled(path91.join(projectRoot,"node_modules"),readPackageJson3(projectRoot));let root=await npmManager.globalRoot?.(ctx);return root===void 0?[]:readInstalled(root)},async globalRoot(ctx){try{let result=await ctx.services.get("host.processes").run(commandOf(ctx),["root","-g"],{label:"npm root -g",windowsShell:!0});return result.exitCode===0?lastLine(result.stdout):void 0}catch{return}},addCommand(specs,options){return{command:"npm",args:["i",...options.section==="devDependencies"?["-D","-E"]:["-E"],...specs],cwd:options.cwd}},globalInstallCommand(specs){return{command:"npm",args:["i","-g",...specs]}}};var package_default23={name:"@sous-io/plugin-npm",version:"1.0.11",description:"A package-manager entity for npm.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-update":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME22="@sous-io/plugin-npm",npmPlugin=definePlugin23({name:PLUGIN_NAME22,version:package_default23.version,description:"A package-manager entity for npm.",dependsOn:{"@sous-io/plugin-update":`^${package_default23.version}`,"@sous-io/plugin-host":`^${package_default23.version}`},register(sous){sous.entities.add("package-manager",npmManager)}});import{definePlugin as definePlugin24}from"@sous-io/plugin-api";import fs64 from"node:fs";import path93 from"node:path";import fs63 from"node:fs";import path92 from"node:path";var PLUGIN_KEYWORD2="sous-plugin";function readPackageJson4(dir){try{let parsed=JSON.parse(fs63.readFileSync(path92.join(dir,"package.json"),"utf8"));return parsed!==null&&typeof parsed=="object"&&!Array.isArray(parsed)?parsed:void 0}catch{return}}function realpathOr4(target){try{return fs63.realpathSync(target)}catch{return target}}function findUp(start2,test){let dir=path92.resolve(start2);for(;;){if(test(dir))return dir;let parent=path92.dirname(dir);if(parent===dir)return;dir=parent}}function declaredIn2(pkg,name){if(pkg!==void 0)for(let section2 of["devDependencies","dependencies"]){let block=pkg[section2],range3=block!==null&&typeof block=="object"?block[name]:void 0;if(typeof range3=="string")return{section:section2,range:range3}}}function isSousPlugin2(pkg){return Array.isArray(pkg.keywords)&&pkg.keywords.includes(PLUGIN_KEYWORD2)}function packageNames2(modules){let entries;try{entries=fs63.readdirSync(modules,{withFileTypes:!0})}catch{return[]}let names2=[];for(let entry of entries.sort((a,b)=>a.name<b.name?-1:1))if(!entry.name.startsWith("."))if(entry.name.startsWith("@"))try{for(let inner of fs63.readdirSync(path92.join(modules,entry.name)).sort())inner.startsWith(".")||names2.push(`${entry.name}/${inner}`)}catch{}else names2.push(entry.name);return names2}function readInstalled2(modules,declaring){let installed2=[];for(let name of packageNames2(modules)){let location=path92.join(modules,...name.split("/")),pkg=readPackageJson4(location);if(pkg===void 0)continue;let declared=declaredIn2(declaring,name);installed2.push({name,version:typeof pkg.version=="string"?pkg.version:"unknown",location,realPath:realpathOr4(location),isSousPlugin:isSousPlugin2(pkg),...declared===void 0?{}:{declared}})}return installed2}function packageManagerField2(pkg,manager){let field=pkg?.packageManager;if(typeof field!="string")return;let match2=/^([^@]+)@([^+]+)/.exec(field);return match2!==null&&match2[1]===manager?match2[2]:void 0}function packageManagerName2(pkg){let field=pkg?.packageManager;return typeof field=="string"?/^([^@]+)@/.exec(field)?.[1]:void 0}function lastLine2(output){let line=output.trim().split(/\r?\n/).pop()?.trim();return line===void 0||line.length===0?void 0:line}var PLUGIN2="@sous-io/plugin-pnpm",WORKSPACE_FILE="pnpm-workspace.yaml";function commandOf2(ctx){return ctx.config.get(["plugins","options",PLUGIN2])?.command??"pnpm"}function has3(dir,file2){return fs64.existsSync(path93.join(dir,file2))}var pnpmManager={id:"pnpm",description:"pnpm, with its workspaces.",async detect(projectRoot){let pkg=readPackageJson4(projectRoot);if(packageManagerName2(pkg)!=="pnpm"&&!has3(projectRoot,"pnpm-lock.yaml")&&!has3(projectRoot,WORKSPACE_FILE))return;let version2=packageManagerField2(pkg,"pnpm"),workspaceRoot=findUp(projectRoot,dir=>has3(dir,WORKSPACE_FILE));return{id:"pnpm",detected:!0,...version2===void 0?{}:{version:version2},...workspaceRoot===void 0?{}:{workspaceRoot}}},async installed(scope,projectRoot,ctx){if(scope==="project")return projectRoot===void 0?[]:readInstalled2(path93.join(projectRoot,"node_modules"),readPackageJson4(projectRoot));let root=await pnpmManager.globalRoot?.(ctx);return root===void 0?[]:readInstalled2(root)},async globalRoot(ctx){try{let result=await ctx.services.get("host.processes").run(commandOf2(ctx),["root","-g"],{label:"pnpm root -g",windowsShell:!0});return result.exitCode===0?lastLine2(result.stdout):void 0}catch{return}},addCommand(specs,options){return{command:"pnpm",args:["add",...[...options.section==="devDependencies"?["-D"]:[],"-E",...options.workspaceRoot?["-w"]:[]],...specs],cwd:options.cwd}},globalInstallCommand(specs){return{command:"pnpm",args:["add","-g",...specs]}}};var package_default24={name:"@sous-io/plugin-pnpm",version:"1.0.11",description:"A package-manager entity for pnpm.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-update":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME23="@sous-io/plugin-pnpm",pnpmPlugin=definePlugin24({name:PLUGIN_NAME23,version:package_default24.version,description:"A package-manager entity for pnpm.",dependsOn:{"@sous-io/plugin-update":`^${package_default24.version}`,"@sous-io/plugin-host":`^${package_default24.version}`},register(sous){sous.entities.add("package-manager",pnpmManager)}});import{definePlugin as definePlugin25}from"@sous-io/plugin-api";import fs67 from"node:fs";import path96 from"node:path";import fs65 from"node:fs";import path94 from"node:path";var PLUGIN_KEYWORD3="sous-plugin";function readPackageJson5(dir){try{let parsed=JSON.parse(fs65.readFileSync(path94.join(dir,"package.json"),"utf8"));return parsed!==null&&typeof parsed=="object"&&!Array.isArray(parsed)?parsed:void 0}catch{return}}function realpathOr5(target){try{return fs65.realpathSync(target)}catch{return target}}function findUp2(start2,test){let dir=path94.resolve(start2);for(;;){if(test(dir))return dir;let parent=path94.dirname(dir);if(parent===dir)return;dir=parent}}function declaredIn3(pkg,name){if(pkg!==void 0)for(let section2 of["devDependencies","dependencies"]){let block=pkg[section2],range3=block!==null&&typeof block=="object"?block[name]:void 0;if(typeof range3=="string")return{section:section2,range:range3}}}function isSousPlugin3(pkg){return Array.isArray(pkg.keywords)&&pkg.keywords.includes(PLUGIN_KEYWORD3)}function packageNames3(modules){let entries;try{entries=fs65.readdirSync(modules,{withFileTypes:!0})}catch{return[]}let names2=[];for(let entry of entries.sort((a,b)=>a.name<b.name?-1:1))if(!entry.name.startsWith("."))if(entry.name.startsWith("@"))try{for(let inner of fs65.readdirSync(path94.join(modules,entry.name)).sort())inner.startsWith(".")||names2.push(`${entry.name}/${inner}`)}catch{}else names2.push(entry.name);return names2}function readInstalled3(modules,declaring){let installed2=[];for(let name of packageNames3(modules)){let location=path94.join(modules,...name.split("/")),pkg=readPackageJson5(location);if(pkg===void 0)continue;let declared=declaredIn3(declaring,name);installed2.push({name,version:typeof pkg.version=="string"?pkg.version:"unknown",location,realPath:realpathOr5(location),isSousPlugin:isSousPlugin3(pkg),...declared===void 0?{}:{declared}})}return installed2}function packageManagerField3(pkg,manager){let field=pkg?.packageManager;if(typeof field!="string")return;let match2=/^([^@]+)@([^+]+)/.exec(field);return match2!==null&&match2[1]===manager?match2[2]:void 0}function packageManagerName3(pkg){let field=pkg?.packageManager;return typeof field=="string"?/^([^@]+)@/.exec(field)?.[1]:void 0}function lastLine3(output){let line=output.trim().split(/\r?\n/).pop()?.trim();return line===void 0||line.length===0?void 0:line}import{createRequire as createRequire3}from"node:module";import fs66 from"node:fs";import path95 from"node:path";import{pathToFileURL as pathToFileURL6}from"node:url";var PNP_FILE=".pnp.cjs";function findPnpFile(start2){let dir=findUp2(start2,candidate=>fs66.existsSync(path95.join(candidate,PNP_FILE)));return dir===void 0?void 0:path95.join(dir,PNP_FILE)}function loadPnp(file2){try{let api=createRequire3(file2)(file2);return api!==void 0&&typeof api.resolveRequest=="function"?api:void 0}catch{return}}function versionOfReference(reference){return/npm:([^#:]+)$/.exec(reference)?.[1]??"unknown"}function inZip(location){return/\.zip(\/|$)/.test(location)}function pnpInstalled(projectRoot){let file2=findPnpFile(projectRoot);if(file2===void 0)return[];let api=loadPnp(file2),locator=api?.findPackageLocator(`${projectRoot}/`)??null,info=locator===null?null:api?.getPackageInformation(locator)??null;if(api===void 0||info===null)return lockfileInstalled(projectRoot,file2);let declaring=readPackageJson5(projectRoot),installed2=[];for(let[name,entry]of[...info.packageDependencies].sort(([a],[b])=>a<b?-1:1)){if(entry===null)continue;let reference=typeof entry=="string"?entry:entry[1],dependency=api.getPackageInformation({name,reference});if(dependency===null)continue;let location=dependency.packageLocation.replace(/\/$/,""),pkg=inZip(location)?void 0:readPackageJson5(location),declared=declaredIn3(declaring,name);installed2.push({name,version:typeof pkg?.version=="string"?pkg.version:versionOfReference(reference),location,realPath:realpathOr5(location),isSousPlugin:pkg!==void 0&&isSousPlugin3(pkg),...declared===void 0?{}:{declared}})}return installed2}function lockfileInstalled(projectRoot,pnpFile){let declaring=readPackageJson5(projectRoot),lockfile="";try{lockfile=fs66.readFileSync(path95.join(path95.dirname(pnpFile),"yarn.lock"),"utf8")}catch{}let names2=new Set;for(let section2 of["devDependencies","dependencies"]){let block=declaring?.[section2];if(block!==null&&typeof block=="object")for(let name of Object.keys(block))names2.add(name)}return[...names2].sort().flatMap(name=>{let declared=declaredIn3(declaring,name);return declared===void 0?[]:[{name,version:yarnLockVersion(lockfile,name,declared.range)??"unknown",location:pnpFile,realPath:realpathOr5(pnpFile),isSousPlugin:!1,declared}]})}function yarnLockVersion(lockfile,name,range3){let prefix=`${name}@`,wanted=new Set([`${prefix}${range3}`,`${prefix}npm:${range3}`]),entries=[],entry;for(let line of lockfile.split(/\r?\n/)){if(/^[^\s#].*:$/.test(line)){let descriptors=line.slice(0,-1).split(",").map(part=>part.trim().replace(/^"|"$/g,"")).filter(descriptor=>descriptor.startsWith(prefix));entry=descriptors.length>0?{descriptors}:void 0,entry!==void 0&&entries.push(entry);continue}let version2=/^\s+version:\s*"?([^"\s]+)"?\s*$/.exec(line);entry!==void 0&&version2!==null&&entry.version===void 0&&(entry.version=version2[1])}let exact=entries.find(candidate=>candidate.descriptors.some(descriptor=>wanted.has(descriptor)));if(exact!==void 0)return exact.version;let versions=new Set(entries.flatMap(candidate=>candidate.version??[]));return versions.size===1?[...versions][0]:void 0}function isBare(specifier){return!/^(\.{0,2}\/|[a-z][a-z0-9+.-]*:|\.\.?$)/i.test(specifier)&&!path95.isAbsolute(specifier)}var yarnPnpLocator={id:"yarn-pnp",locate(specifier,context){let root=context.project?.root;if(root===void 0||!isBare(specifier))return;let file2=findPnpFile(root),api=file2===void 0?void 0:loadPnp(file2);if(api!==void 0)try{let resolved=api.resolveRequest(specifier,`${root}/`);return resolved===null||inZip(resolved)?void 0:pathToFileURL6(resolved)}catch{return}}};var PLUGIN3="@sous-io/plugin-yarn";function commandOf3(ctx){return ctx.config.get(["plugins","options",PLUGIN3])?.command??"yarn"}function has4(dir,file2){return fs67.existsSync(path96.join(dir,file2))}function hasWorkspaces(dir){let pkg=readPackageJson5(dir);return pkg!==void 0&&"workspaces"in pkg}function isBerry(dir){if(has4(dir,".yarnrc.yml")||has4(dir,PNP_FILE))return!0;let version2=packageManagerField3(readPackageJson5(dir),"yarn");if(version2!==void 0)return!version2.startsWith("1.");try{return/^__metadata:/m.test(fs67.readFileSync(path96.join(dir,"yarn.lock"),"utf8"))}catch{return!1}}var yarnManager={id:"yarn",description:"Yarn, Classic (1.x) and Berry (2 and later), with Plug'n'Play.",async detect(projectRoot){let pkg=readPackageJson5(projectRoot);if(packageManagerName3(pkg)!=="yarn"&&!has4(projectRoot,"yarn.lock")&&!has4(projectRoot,".yarnrc.yml")&&!has4(projectRoot,PNP_FILE))return;let version2=packageManagerField3(pkg,"yarn"),workspaceRoot=findUp2(projectRoot,hasWorkspaces),pnpFile=findPnpFile(projectRoot);return{id:isBerry(projectRoot)?"yarn@berry":"yarn",detected:!0,...version2===void 0?{}:{version:version2},...workspaceRoot===void 0?{}:{workspaceRoot},...pnpFile===void 0?{}:{pnpRoot:path96.dirname(pnpFile)}}},async installed(scope,projectRoot,ctx){if(scope==="project")return projectRoot===void 0?[]:findPnpFile(projectRoot)!==void 0&&!has4(projectRoot,"node_modules")?pnpInstalled(projectRoot):readInstalled3(path96.join(projectRoot,"node_modules"),readPackageJson5(projectRoot));let root=await yarnManager.globalRoot?.(ctx);return root===void 0?[]:readInstalled3(root)},async globalRoot(ctx){try{let result=await ctx.services.get("host.processes").run(commandOf3(ctx),["global","dir"],{label:"yarn global dir",windowsShell:!0}),dir=result.exitCode===0?lastLine3(result.stdout):void 0;return dir===void 0?void 0:path96.join(dir,"node_modules")}catch{return}},addCommand(specs,options){let classicRoot=options.workspaceRoot&&!isBerry(options.cwd);return{command:"yarn",args:["add",...[...options.section==="devDependencies"?["-D"]:[],"-E",...classicRoot?["-W"]:[]],...specs],cwd:options.cwd}},globalInstallCommand(specs){return{command:"yarn",args:["global","add",...specs]}}};var package_default25={name:"@sous-io/plugin-yarn",version:"1.0.11",description:"A package-manager entity for Yarn, and Yarn Plug'n'Play's plugin locator.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-update":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME24="@sous-io/plugin-yarn",yarnPlugin=definePlugin25({name:PLUGIN_NAME24,version:package_default25.version,description:"A package-manager entity for Yarn, and Yarn Plug'n'Play's plugin locator.",dependsOn:{"@sous-io/plugin-update":`^${package_default25.version}`,"@sous-io/plugin-host":`^${package_default25.version}`},register(sous){sous.entities.add("package-manager",yarnManager),sous.entities.add("plugin-locator",yarnPnpLocator)}});import{definePlugin as definePlugin26}from"@sous-io/plugin-api";import{ConfigError as ConfigError65}from"@sous-io/plugin-api";import{tmpdir}from"node:os";function tokenFromOutput(output){if(output.exitCode===0)return singleWord(output.stdout)}function singleWord(text){let body2=text.replace(/\r?\n$/,"");if(!(body2.length===0||/\s/.test(body2)))return body2}var TOKEN_COMMAND_TIMEOUT_MS=1e4;function commandDirectory(ctx){return ctx.project?.root??tmpdir()}function tokenOf(source){return async(repository,ctx)=>{let found=await source.find(repository,ctx);return"token"in found?found.token:void 0}}function listed(names2){return names2.length<=1?names2[0]??"":`${names2.slice(0,-1).join(", ")} and ${names2[names2.length-1]}`}function envTokenSource(options){let{variables}=options,source={id:"env",label:listed(variables),async find(_repository,ctx){for(let name of variables){let value=ctx.env[name]?.trim();if(value!==void 0&&value.length>0)return{token:{value,source:name}}}return{missing:`${listed(variables)} unset`}},token:async()=>{},fix:()=>variables.length===0?void 0:`export ${variables[0]}=<${options.tokenHint}>`};return source.token=tokenOf(source),source}function gitCredentialTokenSource(){let source={id:"git-credential",label:"git credential fill",async find(repository,ctx){let missing={missing:`git has no stored credential for ${repository.host}`};if(!ctx.services.has("git.runner"))return missing;let result;try{result=await ctx.services.get("git.runner").run(["credential","fill"],{cwd:commandDirectory(ctx),input:`protocol=https
964
+ `)}function toolInputSchema(definition){let schema=toJsonSchema3(definition.input);return schema?schema.type===void 0&&schema.properties!==void 0?{...schema,type:"object"}:{...schema}:{type:"object",properties:{}}}function toolOutputSchema(definition){let schema=toJsonSchema3(definition.output);return schema?.type==="object"?{...schema}:void 0}function matchesGlob(name,glob){let pattern=glob.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".");return new RegExp(`^${pattern}$`).test(name)}function buildTools(intents,settings={}){let tools=[],warnings=[],owners=new Map,include=settings.include,exclude=settings.exclude??[];for(let info of intents){let definition=info.definition;if(!isAgentVisible(definition))continue;let name=toolName(definition);if(include&&!include.some(glob=>matchesGlob(name,glob))||exclude.some(glob=>matchesGlob(name,glob)))continue;let owner=owners.get(name);if(owner){warnings.push(`Two intents claim the MCP tool "${name}": "${owner.definition.intent}" (${owner.plugin}) and "${definition.intent}" (${info.plugin}). The first keeps it; set agent.tool on one of them.`);continue}owners.set(name,info);let outputSchema2=toolOutputSchema(definition);tools.push({name,intent:definition.intent,description:toolDescription(definition),inputSchema:toolInputSchema(definition),...outputSchema2?{outputSchema:outputSchema2}:{}})}return{tools,warnings}}function createMcpTools(set2){let byName=new Map(set2.tools.map(tool=>[tool.name,tool]));return{warnings:set2.warnings,list:()=>[...set2.tools],toRequest(tool,args){let found=byName.get(tool);if(!found)throw new InputError8(tool,[{path:"",message:`No MCP tool is named "${tool}".`}]);return{intent:found.intent,input:{...args}}}}}var package_default22={name:"@sous-io/plugin-mcp",version:"1.0.12",description:"The sous mcp front end: tools generated from intents, MCP logging and elicitation.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@modelcontextprotocol/sdk":"^1.32.2","@sous-io/plugin-api":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*","@sous-io/plugin-cli":"workspace:*",zod:"^4.4.3"},engines:{node:">=22"}};init_reporter();init_prompter();var PLUGIN_NAME21="@sous-io/plugin-mcp",settingsSchema=jsonSchema27({type:"object",properties:{include:{type:"array",items:{type:"string"},description:"Only tools whose names match these globs."},exclude:{type:"array",items:{type:"string"},default:[],description:"Leaves out tools whose names match these globs."}},additionalProperties:!1}),serveInputSchema=jsonSchema27({type:"object",properties:{transport:{type:"string",enum:["stdio"],default:"stdio",description:"How the client talks to the server."}},additionalProperties:!1});function createMcpPlugin(options={}){return definePlugin22({name:PLUGIN_NAME21,version:package_default22.version,description:"The sous mcp front end: tools generated from intents, MCP logging and elicitation.",dependsOn:{},register(sous){sous.entities.add("config-key",{id:"mcp",description:"MCP server settings: mcp.include and mcp.exclude pick tools by name, with globs.",schema:settingsSchema}),sous.services.add("mcp.tools",config2=>createMcpTools(buildTools(sous.engine.intents.list(),{...config2.get("mcp.include")===void 0?{}:{include:config2.get("mcp.include")},exclude:config2.get("mcp.exclude")??[]})),{lifetime:"config"}),sous.intents.add({intent:"mcp.serve",summary:"Serve this project to agents over MCP",description:"Starts an MCP server on standard input and output. Every command is a tool, and each tool call runs as its own chain, with its messages sent as MCP log messages and its questions as MCP elicitation.",input:serveInputSchema,background:!0,cli:{command:["mcp"],aliases:[["mcp","serve"]],examples:["sous mcp"]},agent:{hidden:!0},async load(){let{serveMcp:serveMcp2}=await Promise.resolve().then(()=>(init_server3(),server_exports));return async(_input,ctx)=>{if(options.transport)return IntentOutputs23.of(await serveMcp2(ctx,{transport:await options.transport()}));let{StdioServerTransport:StdioServerTransport2}=await Promise.resolve().then(()=>(init_stdio2(),stdio_exports)),transport=new StdioServerTransport2;return process.stdin.once("end",()=>{transport.close()}),IntentOutputs23.of(await serveMcp2(ctx,{transport,handleSignals:!0}))}}})}})}var mcpPlugin=createMcpPlugin();import{definePlugin as definePlugin23}from"@sous-io/plugin-api";import fs62 from"node:fs";import path91 from"node:path";import fs61 from"node:fs";import path90 from"node:path";var PLUGIN_KEYWORD="sous-plugin";function readPackageJson3(dir){try{let parsed=JSON.parse(fs61.readFileSync(path90.join(dir,"package.json"),"utf8"));return parsed!==null&&typeof parsed=="object"&&!Array.isArray(parsed)?parsed:void 0}catch{return}}function realpathOr3(target){try{return fs61.realpathSync(target)}catch{return target}}function declaredIn(pkg,name){if(pkg!==void 0)for(let section2 of["devDependencies","dependencies"]){let block=pkg[section2],range3=block!==null&&typeof block=="object"?block[name]:void 0;if(typeof range3=="string")return{section:section2,range:range3}}}function isSousPlugin(pkg){return Array.isArray(pkg.keywords)&&pkg.keywords.includes(PLUGIN_KEYWORD)}function packageNames(modules){let entries;try{entries=fs61.readdirSync(modules,{withFileTypes:!0})}catch{return[]}let names2=[];for(let entry of entries.sort((a,b)=>a.name<b.name?-1:1))if(!entry.name.startsWith("."))if(entry.name.startsWith("@"))try{for(let inner of fs61.readdirSync(path90.join(modules,entry.name)).sort())inner.startsWith(".")||names2.push(`${entry.name}/${inner}`)}catch{}else names2.push(entry.name);return names2}function readInstalled(modules,declaring){let installed2=[];for(let name of packageNames(modules)){let location=path90.join(modules,...name.split("/")),pkg=readPackageJson3(location);if(pkg===void 0)continue;let declared=declaredIn(declaring,name);installed2.push({name,version:typeof pkg.version=="string"?pkg.version:"unknown",location,realPath:realpathOr3(location),isSousPlugin:isSousPlugin(pkg),...declared===void 0?{}:{declared}})}return installed2}function packageManagerField(pkg,manager){let field=pkg?.packageManager;if(typeof field!="string")return;let match2=/^([^@]+)@([^+]+)/.exec(field);return match2!==null&&match2[1]===manager?match2[2]:void 0}function packageManagerName(pkg){let field=pkg?.packageManager;return typeof field=="string"?/^([^@]+)@/.exec(field)?.[1]:void 0}var OTHER_MANAGER_FILES=["yarn.lock",".yarnrc.yml",".pnp.cjs","pnpm-lock.yaml","pnpm-workspace.yaml","bun.lock","bun.lockb","deno.lock"];function lastLine(output){let line=output.trim().split(/\r?\n/).pop()?.trim();return line===void 0||line.length===0?void 0:line}var PLUGIN="@sous-io/plugin-npm";function commandOf(ctx){return ctx.config.get(["plugins","options",PLUGIN])?.command??"npm"}function has2(dir,file2){return fs62.existsSync(path91.join(dir,file2))}var npmManager={id:"npm",description:"npm, the package manager that comes with Node.js.",async detect(projectRoot){let pkg=readPackageJson3(projectRoot),named=packageManagerName(pkg),version2=packageManagerField(pkg,"npm");if(named==="npm"||has2(projectRoot,"package-lock.json")||has2(projectRoot,"npm-shrinkwrap.json"))return{id:"npm",detected:!0,...version2===void 0?{}:{version:version2}};if(!(named!==void 0||OTHER_MANAGER_FILES.some(file2=>has2(projectRoot,file2))))return{id:"npm",detected:!1}},async installed(scope,projectRoot,ctx){if(scope==="project")return projectRoot===void 0?[]:readInstalled(path91.join(projectRoot,"node_modules"),readPackageJson3(projectRoot));let root=await npmManager.globalRoot?.(ctx);return root===void 0?[]:readInstalled(root)},async globalRoot(ctx){try{let result=await ctx.services.get("host.processes").run(commandOf(ctx),["root","-g"],{label:"npm root -g",windowsShell:!0});return result.exitCode===0?lastLine(result.stdout):void 0}catch{return}},addCommand(specs,options){return{command:"npm",args:["i",...options.section==="devDependencies"?["-D","-E"]:["-E"],...specs],cwd:options.cwd}},globalInstallCommand(specs){return{command:"npm",args:["i","-g",...specs]}}};var package_default23={name:"@sous-io/plugin-npm",version:"1.0.12",description:"A package-manager entity for npm.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-update":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME22="@sous-io/plugin-npm",npmPlugin=definePlugin23({name:PLUGIN_NAME22,version:package_default23.version,description:"A package-manager entity for npm.",dependsOn:{"@sous-io/plugin-update":`^${package_default23.version}`,"@sous-io/plugin-host":`^${package_default23.version}`},register(sous){sous.entities.add("package-manager",npmManager)}});import{definePlugin as definePlugin24}from"@sous-io/plugin-api";import fs64 from"node:fs";import path93 from"node:path";import fs63 from"node:fs";import path92 from"node:path";var PLUGIN_KEYWORD2="sous-plugin";function readPackageJson4(dir){try{let parsed=JSON.parse(fs63.readFileSync(path92.join(dir,"package.json"),"utf8"));return parsed!==null&&typeof parsed=="object"&&!Array.isArray(parsed)?parsed:void 0}catch{return}}function realpathOr4(target){try{return fs63.realpathSync(target)}catch{return target}}function findUp(start2,test){let dir=path92.resolve(start2);for(;;){if(test(dir))return dir;let parent=path92.dirname(dir);if(parent===dir)return;dir=parent}}function declaredIn2(pkg,name){if(pkg!==void 0)for(let section2 of["devDependencies","dependencies"]){let block=pkg[section2],range3=block!==null&&typeof block=="object"?block[name]:void 0;if(typeof range3=="string")return{section:section2,range:range3}}}function isSousPlugin2(pkg){return Array.isArray(pkg.keywords)&&pkg.keywords.includes(PLUGIN_KEYWORD2)}function packageNames2(modules){let entries;try{entries=fs63.readdirSync(modules,{withFileTypes:!0})}catch{return[]}let names2=[];for(let entry of entries.sort((a,b)=>a.name<b.name?-1:1))if(!entry.name.startsWith("."))if(entry.name.startsWith("@"))try{for(let inner of fs63.readdirSync(path92.join(modules,entry.name)).sort())inner.startsWith(".")||names2.push(`${entry.name}/${inner}`)}catch{}else names2.push(entry.name);return names2}function readInstalled2(modules,declaring){let installed2=[];for(let name of packageNames2(modules)){let location=path92.join(modules,...name.split("/")),pkg=readPackageJson4(location);if(pkg===void 0)continue;let declared=declaredIn2(declaring,name);installed2.push({name,version:typeof pkg.version=="string"?pkg.version:"unknown",location,realPath:realpathOr4(location),isSousPlugin:isSousPlugin2(pkg),...declared===void 0?{}:{declared}})}return installed2}function packageManagerField2(pkg,manager){let field=pkg?.packageManager;if(typeof field!="string")return;let match2=/^([^@]+)@([^+]+)/.exec(field);return match2!==null&&match2[1]===manager?match2[2]:void 0}function packageManagerName2(pkg){let field=pkg?.packageManager;return typeof field=="string"?/^([^@]+)@/.exec(field)?.[1]:void 0}function lastLine2(output){let line=output.trim().split(/\r?\n/).pop()?.trim();return line===void 0||line.length===0?void 0:line}var PLUGIN2="@sous-io/plugin-pnpm",WORKSPACE_FILE="pnpm-workspace.yaml";function commandOf2(ctx){return ctx.config.get(["plugins","options",PLUGIN2])?.command??"pnpm"}function has3(dir,file2){return fs64.existsSync(path93.join(dir,file2))}var pnpmManager={id:"pnpm",description:"pnpm, with its workspaces.",async detect(projectRoot){let pkg=readPackageJson4(projectRoot);if(packageManagerName2(pkg)!=="pnpm"&&!has3(projectRoot,"pnpm-lock.yaml")&&!has3(projectRoot,WORKSPACE_FILE))return;let version2=packageManagerField2(pkg,"pnpm"),workspaceRoot=findUp(projectRoot,dir=>has3(dir,WORKSPACE_FILE));return{id:"pnpm",detected:!0,...version2===void 0?{}:{version:version2},...workspaceRoot===void 0?{}:{workspaceRoot}}},async installed(scope,projectRoot,ctx){if(scope==="project")return projectRoot===void 0?[]:readInstalled2(path93.join(projectRoot,"node_modules"),readPackageJson4(projectRoot));let root=await pnpmManager.globalRoot?.(ctx);return root===void 0?[]:readInstalled2(root)},async globalRoot(ctx){try{let result=await ctx.services.get("host.processes").run(commandOf2(ctx),["root","-g"],{label:"pnpm root -g",windowsShell:!0});return result.exitCode===0?lastLine2(result.stdout):void 0}catch{return}},addCommand(specs,options){return{command:"pnpm",args:["add",...[...options.section==="devDependencies"?["-D"]:[],"-E",...options.workspaceRoot?["-w"]:[]],...specs],cwd:options.cwd}},globalInstallCommand(specs){return{command:"pnpm",args:["add","-g",...specs]}}};var package_default24={name:"@sous-io/plugin-pnpm",version:"1.0.12",description:"A package-manager entity for pnpm.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-update":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME23="@sous-io/plugin-pnpm",pnpmPlugin=definePlugin24({name:PLUGIN_NAME23,version:package_default24.version,description:"A package-manager entity for pnpm.",dependsOn:{"@sous-io/plugin-update":`^${package_default24.version}`,"@sous-io/plugin-host":`^${package_default24.version}`},register(sous){sous.entities.add("package-manager",pnpmManager)}});import{definePlugin as definePlugin25}from"@sous-io/plugin-api";import fs67 from"node:fs";import path96 from"node:path";import fs65 from"node:fs";import path94 from"node:path";var PLUGIN_KEYWORD3="sous-plugin";function readPackageJson5(dir){try{let parsed=JSON.parse(fs65.readFileSync(path94.join(dir,"package.json"),"utf8"));return parsed!==null&&typeof parsed=="object"&&!Array.isArray(parsed)?parsed:void 0}catch{return}}function realpathOr5(target){try{return fs65.realpathSync(target)}catch{return target}}function findUp2(start2,test){let dir=path94.resolve(start2);for(;;){if(test(dir))return dir;let parent=path94.dirname(dir);if(parent===dir)return;dir=parent}}function declaredIn3(pkg,name){if(pkg!==void 0)for(let section2 of["devDependencies","dependencies"]){let block=pkg[section2],range3=block!==null&&typeof block=="object"?block[name]:void 0;if(typeof range3=="string")return{section:section2,range:range3}}}function isSousPlugin3(pkg){return Array.isArray(pkg.keywords)&&pkg.keywords.includes(PLUGIN_KEYWORD3)}function packageNames3(modules){let entries;try{entries=fs65.readdirSync(modules,{withFileTypes:!0})}catch{return[]}let names2=[];for(let entry of entries.sort((a,b)=>a.name<b.name?-1:1))if(!entry.name.startsWith("."))if(entry.name.startsWith("@"))try{for(let inner of fs65.readdirSync(path94.join(modules,entry.name)).sort())inner.startsWith(".")||names2.push(`${entry.name}/${inner}`)}catch{}else names2.push(entry.name);return names2}function readInstalled3(modules,declaring){let installed2=[];for(let name of packageNames3(modules)){let location=path94.join(modules,...name.split("/")),pkg=readPackageJson5(location);if(pkg===void 0)continue;let declared=declaredIn3(declaring,name);installed2.push({name,version:typeof pkg.version=="string"?pkg.version:"unknown",location,realPath:realpathOr5(location),isSousPlugin:isSousPlugin3(pkg),...declared===void 0?{}:{declared}})}return installed2}function packageManagerField3(pkg,manager){let field=pkg?.packageManager;if(typeof field!="string")return;let match2=/^([^@]+)@([^+]+)/.exec(field);return match2!==null&&match2[1]===manager?match2[2]:void 0}function packageManagerName3(pkg){let field=pkg?.packageManager;return typeof field=="string"?/^([^@]+)@/.exec(field)?.[1]:void 0}function lastLine3(output){let line=output.trim().split(/\r?\n/).pop()?.trim();return line===void 0||line.length===0?void 0:line}import{createRequire as createRequire3}from"node:module";import fs66 from"node:fs";import path95 from"node:path";import{pathToFileURL as pathToFileURL6}from"node:url";var PNP_FILE=".pnp.cjs";function findPnpFile(start2){let dir=findUp2(start2,candidate=>fs66.existsSync(path95.join(candidate,PNP_FILE)));return dir===void 0?void 0:path95.join(dir,PNP_FILE)}function loadPnp(file2){try{let api=createRequire3(file2)(file2);return api!==void 0&&typeof api.resolveRequest=="function"?api:void 0}catch{return}}function versionOfReference(reference){return/npm:([^#:]+)$/.exec(reference)?.[1]??"unknown"}function inZip(location){return/\.zip(\/|$)/.test(location)}function pnpInstalled(projectRoot){let file2=findPnpFile(projectRoot);if(file2===void 0)return[];let api=loadPnp(file2),locator=api?.findPackageLocator(`${projectRoot}/`)??null,info=locator===null?null:api?.getPackageInformation(locator)??null;if(api===void 0||info===null)return lockfileInstalled(projectRoot,file2);let declaring=readPackageJson5(projectRoot),installed2=[];for(let[name,entry]of[...info.packageDependencies].sort(([a],[b])=>a<b?-1:1)){if(entry===null)continue;let reference=typeof entry=="string"?entry:entry[1],dependency=api.getPackageInformation({name,reference});if(dependency===null)continue;let location=dependency.packageLocation.replace(/\/$/,""),pkg=inZip(location)?void 0:readPackageJson5(location),declared=declaredIn3(declaring,name);installed2.push({name,version:typeof pkg?.version=="string"?pkg.version:versionOfReference(reference),location,realPath:realpathOr5(location),isSousPlugin:pkg!==void 0&&isSousPlugin3(pkg),...declared===void 0?{}:{declared}})}return installed2}function lockfileInstalled(projectRoot,pnpFile){let declaring=readPackageJson5(projectRoot),lockfile="";try{lockfile=fs66.readFileSync(path95.join(path95.dirname(pnpFile),"yarn.lock"),"utf8")}catch{}let names2=new Set;for(let section2 of["devDependencies","dependencies"]){let block=declaring?.[section2];if(block!==null&&typeof block=="object")for(let name of Object.keys(block))names2.add(name)}return[...names2].sort().flatMap(name=>{let declared=declaredIn3(declaring,name);return declared===void 0?[]:[{name,version:yarnLockVersion(lockfile,name,declared.range)??"unknown",location:pnpFile,realPath:realpathOr5(pnpFile),isSousPlugin:!1,declared}]})}function yarnLockVersion(lockfile,name,range3){let prefix=`${name}@`,wanted=new Set([`${prefix}${range3}`,`${prefix}npm:${range3}`]),entries=[],entry;for(let line of lockfile.split(/\r?\n/)){if(/^[^\s#].*:$/.test(line)){let descriptors=line.slice(0,-1).split(",").map(part=>part.trim().replace(/^"|"$/g,"")).filter(descriptor=>descriptor.startsWith(prefix));entry=descriptors.length>0?{descriptors}:void 0,entry!==void 0&&entries.push(entry);continue}let version2=/^\s+version:\s*"?([^"\s]+)"?\s*$/.exec(line);entry!==void 0&&version2!==null&&entry.version===void 0&&(entry.version=version2[1])}let exact=entries.find(candidate=>candidate.descriptors.some(descriptor=>wanted.has(descriptor)));if(exact!==void 0)return exact.version;let versions=new Set(entries.flatMap(candidate=>candidate.version??[]));return versions.size===1?[...versions][0]:void 0}function isBare(specifier){return!/^(\.{0,2}\/|[a-z][a-z0-9+.-]*:|\.\.?$)/i.test(specifier)&&!path95.isAbsolute(specifier)}var yarnPnpLocator={id:"yarn-pnp",locate(specifier,context){let root=context.project?.root;if(root===void 0||!isBare(specifier))return;let file2=findPnpFile(root),api=file2===void 0?void 0:loadPnp(file2);if(api!==void 0)try{let resolved=api.resolveRequest(specifier,`${root}/`);return resolved===null||inZip(resolved)?void 0:pathToFileURL6(resolved)}catch{return}}};var PLUGIN3="@sous-io/plugin-yarn";function commandOf3(ctx){return ctx.config.get(["plugins","options",PLUGIN3])?.command??"yarn"}function has4(dir,file2){return fs67.existsSync(path96.join(dir,file2))}function hasWorkspaces(dir){let pkg=readPackageJson5(dir);return pkg!==void 0&&"workspaces"in pkg}function isBerry(dir){if(has4(dir,".yarnrc.yml")||has4(dir,PNP_FILE))return!0;let version2=packageManagerField3(readPackageJson5(dir),"yarn");if(version2!==void 0)return!version2.startsWith("1.");try{return/^__metadata:/m.test(fs67.readFileSync(path96.join(dir,"yarn.lock"),"utf8"))}catch{return!1}}var yarnManager={id:"yarn",description:"Yarn, Classic (1.x) and Berry (2 and later), with Plug'n'Play.",async detect(projectRoot){let pkg=readPackageJson5(projectRoot);if(packageManagerName3(pkg)!=="yarn"&&!has4(projectRoot,"yarn.lock")&&!has4(projectRoot,".yarnrc.yml")&&!has4(projectRoot,PNP_FILE))return;let version2=packageManagerField3(pkg,"yarn"),workspaceRoot=findUp2(projectRoot,hasWorkspaces),pnpFile=findPnpFile(projectRoot);return{id:isBerry(projectRoot)?"yarn@berry":"yarn",detected:!0,...version2===void 0?{}:{version:version2},...workspaceRoot===void 0?{}:{workspaceRoot},...pnpFile===void 0?{}:{pnpRoot:path96.dirname(pnpFile)}}},async installed(scope,projectRoot,ctx){if(scope==="project")return projectRoot===void 0?[]:findPnpFile(projectRoot)!==void 0&&!has4(projectRoot,"node_modules")?pnpInstalled(projectRoot):readInstalled3(path96.join(projectRoot,"node_modules"),readPackageJson5(projectRoot));let root=await yarnManager.globalRoot?.(ctx);return root===void 0?[]:readInstalled3(root)},async globalRoot(ctx){try{let result=await ctx.services.get("host.processes").run(commandOf3(ctx),["global","dir"],{label:"yarn global dir",windowsShell:!0}),dir=result.exitCode===0?lastLine3(result.stdout):void 0;return dir===void 0?void 0:path96.join(dir,"node_modules")}catch{return}},addCommand(specs,options){let classicRoot=options.workspaceRoot&&!isBerry(options.cwd);return{command:"yarn",args:["add",...[...options.section==="devDependencies"?["-D"]:[],"-E",...classicRoot?["-W"]:[]],...specs],cwd:options.cwd}},globalInstallCommand(specs){return{command:"yarn",args:["global","add",...specs]}}};var package_default25={name:"@sous-io/plugin-yarn",version:"1.0.12",description:"A package-manager entity for Yarn, and Yarn Plug'n'Play's plugin locator.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-update":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME24="@sous-io/plugin-yarn",yarnPlugin=definePlugin25({name:PLUGIN_NAME24,version:package_default25.version,description:"A package-manager entity for Yarn, and Yarn Plug'n'Play's plugin locator.",dependsOn:{"@sous-io/plugin-update":`^${package_default25.version}`,"@sous-io/plugin-host":`^${package_default25.version}`},register(sous){sous.entities.add("package-manager",yarnManager),sous.entities.add("plugin-locator",yarnPnpLocator)}});import{definePlugin as definePlugin26}from"@sous-io/plugin-api";import{ConfigError as ConfigError65}from"@sous-io/plugin-api";import{tmpdir}from"node:os";function tokenFromOutput(output){if(output.exitCode===0)return singleWord(output.stdout)}function singleWord(text){let body2=text.replace(/\r?\n$/,"");if(!(body2.length===0||/\s/.test(body2)))return body2}var TOKEN_COMMAND_TIMEOUT_MS=1e4;function commandDirectory(ctx){return ctx.project?.root??tmpdir()}function tokenOf(source){return async(repository,ctx)=>{let found=await source.find(repository,ctx);return"token"in found?found.token:void 0}}function listed(names2){return names2.length<=1?names2[0]??"":`${names2.slice(0,-1).join(", ")} and ${names2[names2.length-1]}`}function envTokenSource(options){let{variables}=options,source={id:"env",label:listed(variables),async find(_repository,ctx){for(let name of variables){let value=ctx.env[name]?.trim();if(value!==void 0&&value.length>0)return{token:{value,source:name}}}return{missing:`${listed(variables)} unset`}},token:async()=>{},fix:()=>variables.length===0?void 0:`export ${variables[0]}=<${options.tokenHint}>`};return source.token=tokenOf(source),source}function gitCredentialTokenSource(){let source={id:"git-credential",label:"git credential fill",async find(repository,ctx){let missing={missing:`git has no stored credential for ${repository.host}`};if(!ctx.services.has("git.runner"))return missing;let result;try{result=await ctx.services.get("git.runner").run(["credential","fill"],{cwd:commandDirectory(ctx),input:`protocol=https
964
965
  host=${repository.host}
965
966
 
966
967
  `,env:{GIT_TERMINAL_PROMPT:"0",GCM_INTERACTIVE:"never",GIT_ASKPASS:"",SSH_ASKPASS:""},timeoutMs:TOKEN_COMMAND_TIMEOUT_MS,reject:!1,...ctx.signal===void 0?{}:{signal:ctx.signal}})}catch{return missing}if(result.exitCode!==0)return missing;let password=passwordIn(result.stdout);return password===void 0?missing:{token:{value:password,source:"git credential fill"}}},token:async()=>{}};return source.token=tokenOf(source),source}function passwordIn(output){for(let line of output.split(/\r?\n/))if(line.startsWith("password="))return singleWord(line.slice(9))}function cliTokenSource(options){let{command}=options,source={id:options.id,label:command,async find(repository,ctx){let processes=ctx.services.get("host.processes");if(await processes.which(command,ctx.env)===void 0)return{missing:void 0};let args=options.args(repository),result;try{result=await processes.run(command,args,{cwd:commandDirectory(ctx),env:ctx.env,timeoutMs:TOKEN_COMMAND_TIMEOUT_MS,label:`${command} token`,...ctx.signal===void 0?{}:{signal:ctx.signal}})}catch{return{missing:`${command} could not be run`}}let value=tokenFromOutput(result);return value===void 0?{missing:`${command} printed no token for ${repository.host}`}:{token:{value,source:command}}},token:async()=>{}};return source.token=tokenOf(source),source}async function runCli(cli,args,ctx,options={}){let processes=ctx.services.get("host.processes");if(await processes.which(cli.command,ctx.env)===void 0)throw new ConfigError65(`${capitalized(cli.label)} ('${cli.command}') is not installed.`,{details:[`Sous needs it only to propose changes. Install it from ${cli.install}, then run '${cli.command} auth login'.`]});return processes.run(cli.command,args,{cwd:commandDirectory(ctx),env:{...ctx.env,...options.env},label:`${cli.command} ${args.slice(0,2).join(" ")}`,...ctx.signal===void 0?{}:{signal:ctx.signal}})}async function cliOutput(cli,args,ctx,options={}){try{let result=await runCli(cli,args,ctx,options),output=result.stdout.trim();return result.exitCode===0&&output.length>0?output:void 0}catch{return}}async function cliJson(cli,args,what,noun2,ctx,options={}){let result=await runCli(cli,args,ctx,options);if(result.exitCode!==0)throw cliFailure(cli,what,result,"");try{return JSON.parse(result.stdout)}catch{throw new ConfigError65(`'${cli.command} ${what}' printed something that is not JSON, so sous cannot read the ${noun2} it describes.`)}}function cliFailure(cli,what,result,consequence){let reported=result.stderr.trim()||result.stdout.trim();return new ConfigError65(`'${cli.command} ${what}' did not succeed${consequence.length===0?"":`, ${consequence}`}.`,{details:reported.length===0?[]:reported.split(`
@@ -1034,7 +1035,7 @@ jobs:
1034
1035
  git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
1035
1036
  - name: Publish every new version
1036
1037
  run: npx --yes @sous-io/sous repo release --ci --push --yes
1037
- `}var GH={command:"gh",label:"the GitHub CLI",install:"https://cli.github.com"};function repoArg(repository){return`${repository.owner}/${repository.name}`}function ghEnv(repository){return{env:repository.host==="github.com"?{}:{GH_HOST:repository.host}}}import{ConfigError as ConfigError68}from"@sous-io/plugin-api";var NOUN="pull request";function githubProposals(){return{async canPush(repository,ctx){let answer2=await cliOutput(GH,["api",`repos/${repoArg(repository)}`,"--jq",".permissions.push"],ctx,ghEnv(repository));return answer2==="true"?!0:answer2==="false"?!1:void 0},async fork(repository,ctx){let forked=await runCli(GH,["repo","fork",repoArg(repository),"--remote=false"],ctx,ghEnv(repository));if(forked.exitCode!==0)throw cliFailure(GH,"repo fork",forked,"");let owner=await cliOutput(GH,["api","user","--jq",".login"],ctx,ghEnv(repository));if(owner===void 0)throw new ConfigError68(`The fork was requested, but sous could not read your GitHub login from '${GH.command} api user', so it does not know where the fork lives.`);return{owner,name:repository.name,httpsUrl:`https://${repository.host}/${owner}/${repository.name}.git`,sshUrl:`git@${repository.host}:${owner}/${repository.name}.git`}},async proposeChange(repository,proposal,ctx){let head=proposal.head===void 0?proposal.branch:`${proposal.head.owner}:${proposal.branch}`,args=["pr","create","--repo",repoArg(repository)];proposal.base!==void 0&&args.push("--base",proposal.base),args.push("--head",head,"--title",proposal.title,"--body",proposal.body),proposal.draft&&args.push("--draft");let result=await runCli(GH,args,ctx,ghEnv(repository));if(result.exitCode!==0)throw cliFailure(GH,"pr create",result,"so no proposal was opened");let url2=firstUrlIn(result.stdout);return url2===void 0?{detail:`The ${NOUN} was opened, but '${GH.command}' printed no address for it.`}:{url:url2,detail:`The ${NOUN} is at ${url2}.`}},async findProposal(repository,query,ctx){let forkOwner=query.fromFork?query.forkOwner??await signedInLogin(repository,ctx):void 0,mine=(await cliJson(GH,["pr","list","--repo",repoArg(repository),"--head",query.branch,"--state","all","--limit","50","--json","number,url,state,title,isDraft,baseRefName,headRepositoryOwner,isCrossRepository"],"pr list",NOUN,ctx,ghEnv(repository))).filter(entry=>query.fromFork?entry.isCrossRepository===!0&&entry.headRepositoryOwner?.login===forkOwner:entry.isCrossRepository!==!0);if(mine.length===0)return;let chosen=mine.find(entry=>entry.state==="OPEN")??[...mine].sort((a,b)=>b.number-a.number)[0];return summarizePullRequest(chosen)},async proposalStatus(repository,id,ctx){let viewed=await cliJson(GH,["pr","view",id,"--repo",repoArg(repository),"--json","number,url,state,title,isDraft,baseRefName,reviewDecision,statusCheckRollup,mergeable"],"pr view",NOUN,ctx,ghEnv(repository));return statusOf(viewed)},async updateProposal(repository,id,update,ctx){let args=["pr","edit",id,"--repo",repoArg(repository)];update.title!==void 0&&args.push("--title",update.title),update.body!==void 0&&args.push("--body",update.body);let result=await runCli(GH,args,ctx,ghEnv(repository));if(result.exitCode!==0)throw cliFailure(GH,"pr edit",result,`so the ${NOUN} kept its title and body`);let url2=firstUrlIn(result.stdout);return url2===void 0?{detail:`The ${NOUN} was updated.`}:{url:url2,detail:`The ${NOUN} at ${url2} was updated.`}}}}async function signedInLogin(repository,ctx){let login=await cliOutput(GH,["api","user","--jq",".login"],ctx,ghEnv(repository));if(login===void 0)throw new ConfigError68(`Sous could not read your GitHub login from '${GH.command} api user', so it cannot tell which fork a ${NOUN} would come from.`);return login}function stateOf(state){return state==="MERGED"?"merged":state==="CLOSED"?"closed":"open"}function summarizePullRequest(entry){return{id:String(entry.number),...entry.url===void 0?{}:{url:entry.url},state:stateOf(entry.state),title:entry.title??"",draft:entry.isDraft===!0,...entry.baseRefName===void 0?{}:{base:entry.baseRefName}}}function statusOf(viewed){let review=reviewOf(viewed.reviewDecision),checks=checksOf(viewed.statusCheckRollup),mergeable=viewed.mergeable==="MERGEABLE"?!0:viewed.mergeable==="CONFLICTING"?!1:void 0;return{proposal:summarizePullRequest(viewed),...review===void 0?{}:{review},...checks===void 0?{}:{checks},...mergeable===void 0?{}:{mergeable}}}function reviewOf(decision){switch(decision){case"APPROVED":return"approved";case"CHANGES_REQUESTED":return"changes requested";case"REVIEW_REQUIRED":return"review required";default:return}}var PASSING=new Set(["SUCCESS","NEUTRAL","SKIPPED"]);function checksOf(rollup){if(rollup==null||rollup.length===0)return;let counts={passed:0,failed:0,pending:0};for(let check3 of rollup)check3.__typename==="StatusContext"||check3.status===void 0&&check3.state!==void 0?check3.state==="SUCCESS"?counts.passed+=1:check3.state==="PENDING"||check3.state==="EXPECTED"?counts.pending+=1:counts.failed+=1:check3.status!=="COMPLETED"?counts.pending+=1:PASSING.has(check3.conclusion??"")?counts.passed+=1:counts.failed+=1;return counts}var GITHUB_HOST="github.com",GITHUB_TOKEN_VARIABLES=["GITHUB_TOKEN","GH_TOKEN"];function encodedPath(path103){return path103.split("/").map(encodeURIComponent).join("/")}function githubApiFileUrl(request){let{repository}=request;return`${repository.host===GITHUB_HOST?"https://api.github.com":`https://${repository.host}/api/v3`}/repos/${repository.owner}/${repository.name}/contents/${encodedPath(request.path)}?ref=${encodeURIComponent(request.ref)}`}function githubRawFileUrl(request){let{repository}=request;return`${repository.host===GITHUB_HOST?`https://raw.githubusercontent.com/${repository.owner}/${repository.name}`:`https://${repository.host}/${repository.owner}/${repository.name}/raw`}/${encodeURIComponent(request.ref)}/${encodedPath(request.path)}`}var API_HEADERS={Accept:"application/vnd.github.raw+json","X-GitHub-Api-Version":"2022-11-28"};function createGithubHost(options={}){let extraHosts=new Set((options.hosts??[]).map(host=>host.toLowerCase())),variables=options.tokenVariables??GITHUB_TOKEN_VARIABLES;return{id:"github",defaultHost:GITHUB_HOST,schemes:["github"],features:["fetch","submit","proposals"],readLocation:readGithubLocation,formatLocator:(host,repoPath,rest)=>formatHostedLocator("github",GITHUB_HOST,host,repoPath,rest),matches(url2){let parts=splitRepoUrl(url2);return parts!==void 0&&(parts.host===GITHUB_HOST||extraHosts.has(parts.host))},canonicalize(url2){let parts=splitRepoUrl(url2);if(parts===void 0)throw invalidRepoUrl("github",url2,GITHUB_HOST);return canonicalRepository(parts.host,parts.owner,parts.name)},tokenSources:[envTokenSource({variables,tokenHint:"a token that can read the repository"}),gitCredentialTokenSource(),cliTokenSource({id:"gh",command:GH.command,args:repository=>["auth","token","--hostname",repository.host]})],readStrategies:[httpReadStrategy({id:"http-token",label:"HTTP with token",usesToken:!0,url:githubApiFileUrl,headers:()=>API_HEADERS}),httpReadStrategy({id:"http",label:"HTTP without token",usesToken:!1,url:githubRawFileUrl,headers:()=>({Accept:"*/*"})}),gitReadStrategy()],fetchRecipeTree:(repository,recipePath,tag,destination,ctx)=>fetchRecipeTree({urls:[repository.httpsUrl,repository.sshUrl],tag,recipePath,destination},ctx),proposalNoun:"pull request",cli:GH,authStatus:ctx=>cliAuthStatus(GH,ctx),...githubProposals(),scaffoldFiles:githubWorkflowFiles}}function readGithubLocation(location){let{segments}=location;return segments.length<2?[]:readingsAfterRepository(`${segments[0]}/${withoutGitSuffix(segments[1])}`,segments.slice(2))}var package_default26={name:"@sous-io/plugin-github",version:"1.0.11",description:"A repository-host entity for GitHub: reading indexes, the token, proposing changes, the CI workflow.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-git":"workspace:*","@sous-io/repository-hosts":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME25="@sous-io/plugin-github",githubPlugin=definePlugin26({name:PLUGIN_NAME25,version:package_default26.version,description:"A repository-host entity for GitHub: reading indexes, the token, proposing changes, the CI workflow.",dependsOn:{"@sous-io/plugin-recipes":`^${package_default26.version}`,"@sous-io/plugin-host":`^${package_default26.version}`,"@sous-io/plugin-git":`^${package_default26.version}`},register(sous){sous.config.contribute({id:"github/repository-host",before:["@sous-io/plugin-recipes"],contribute(config2){config2.addEntity("repository-host",createGithubHost(config2.options()??{}))}})}});import{definePlugin as definePlugin27}from"@sous-io/plugin-api";var GITLAB_CI_PATH=".gitlab-ci.yml";function gitlabCiFiles(_options){return[{path:GITLAB_CI_PATH,content:buildGitlabPipeline()}]}function buildGitlabPipeline(){return`# Release automation for this sous recipe repository.
1038
+ `}var GH={command:"gh",label:"the GitHub CLI",install:"https://cli.github.com"};function repoArg(repository){return`${repository.owner}/${repository.name}`}function ghEnv(repository){return{env:repository.host==="github.com"?{}:{GH_HOST:repository.host}}}import{ConfigError as ConfigError68}from"@sous-io/plugin-api";var NOUN="pull request";function githubProposals(){return{async canPush(repository,ctx){let answer2=await cliOutput(GH,["api",`repos/${repoArg(repository)}`,"--jq",".permissions.push"],ctx,ghEnv(repository));return answer2==="true"?!0:answer2==="false"?!1:void 0},async fork(repository,ctx){let forked=await runCli(GH,["repo","fork",repoArg(repository),"--remote=false"],ctx,ghEnv(repository));if(forked.exitCode!==0)throw cliFailure(GH,"repo fork",forked,"");let owner=await cliOutput(GH,["api","user","--jq",".login"],ctx,ghEnv(repository));if(owner===void 0)throw new ConfigError68(`The fork was requested, but sous could not read your GitHub login from '${GH.command} api user', so it does not know where the fork lives.`);return{owner,name:repository.name,httpsUrl:`https://${repository.host}/${owner}/${repository.name}.git`,sshUrl:`git@${repository.host}:${owner}/${repository.name}.git`}},async proposeChange(repository,proposal,ctx){let head=proposal.head===void 0?proposal.branch:`${proposal.head.owner}:${proposal.branch}`,args=["pr","create","--repo",repoArg(repository)];proposal.base!==void 0&&args.push("--base",proposal.base),args.push("--head",head,"--title",proposal.title,"--body",proposal.body),proposal.draft&&args.push("--draft");let result=await runCli(GH,args,ctx,ghEnv(repository));if(result.exitCode!==0)throw cliFailure(GH,"pr create",result,"so no proposal was opened");let url2=firstUrlIn(result.stdout);return url2===void 0?{detail:`The ${NOUN} was opened, but '${GH.command}' printed no address for it.`}:{url:url2,detail:`The ${NOUN} is at ${url2}.`}},async findProposal(repository,query,ctx){let forkOwner=query.fromFork?query.forkOwner??await signedInLogin(repository,ctx):void 0,mine=(await cliJson(GH,["pr","list","--repo",repoArg(repository),"--head",query.branch,"--state","all","--limit","50","--json","number,url,state,title,isDraft,baseRefName,headRepositoryOwner,isCrossRepository"],"pr list",NOUN,ctx,ghEnv(repository))).filter(entry=>query.fromFork?entry.isCrossRepository===!0&&entry.headRepositoryOwner?.login===forkOwner:entry.isCrossRepository!==!0);if(mine.length===0)return;let chosen=mine.find(entry=>entry.state==="OPEN")??[...mine].sort((a,b)=>b.number-a.number)[0];return summarizePullRequest(chosen)},async proposalStatus(repository,id,ctx){let viewed=await cliJson(GH,["pr","view",id,"--repo",repoArg(repository),"--json","number,url,state,title,isDraft,baseRefName,reviewDecision,statusCheckRollup,mergeable"],"pr view",NOUN,ctx,ghEnv(repository));return statusOf(viewed)},async updateProposal(repository,id,update,ctx){let args=["pr","edit",id,"--repo",repoArg(repository)];update.title!==void 0&&args.push("--title",update.title),update.body!==void 0&&args.push("--body",update.body);let result=await runCli(GH,args,ctx,ghEnv(repository));if(result.exitCode!==0)throw cliFailure(GH,"pr edit",result,`so the ${NOUN} kept its title and body`);let url2=firstUrlIn(result.stdout);return url2===void 0?{detail:`The ${NOUN} was updated.`}:{url:url2,detail:`The ${NOUN} at ${url2} was updated.`}}}}async function signedInLogin(repository,ctx){let login=await cliOutput(GH,["api","user","--jq",".login"],ctx,ghEnv(repository));if(login===void 0)throw new ConfigError68(`Sous could not read your GitHub login from '${GH.command} api user', so it cannot tell which fork a ${NOUN} would come from.`);return login}function stateOf(state){return state==="MERGED"?"merged":state==="CLOSED"?"closed":"open"}function summarizePullRequest(entry){return{id:String(entry.number),...entry.url===void 0?{}:{url:entry.url},state:stateOf(entry.state),title:entry.title??"",draft:entry.isDraft===!0,...entry.baseRefName===void 0?{}:{base:entry.baseRefName}}}function statusOf(viewed){let review=reviewOf(viewed.reviewDecision),checks=checksOf(viewed.statusCheckRollup),mergeable=viewed.mergeable==="MERGEABLE"?!0:viewed.mergeable==="CONFLICTING"?!1:void 0;return{proposal:summarizePullRequest(viewed),...review===void 0?{}:{review},...checks===void 0?{}:{checks},...mergeable===void 0?{}:{mergeable}}}function reviewOf(decision){switch(decision){case"APPROVED":return"approved";case"CHANGES_REQUESTED":return"changes requested";case"REVIEW_REQUIRED":return"review required";default:return}}var PASSING=new Set(["SUCCESS","NEUTRAL","SKIPPED"]);function checksOf(rollup){if(rollup==null||rollup.length===0)return;let counts={passed:0,failed:0,pending:0};for(let check3 of rollup)check3.__typename==="StatusContext"||check3.status===void 0&&check3.state!==void 0?check3.state==="SUCCESS"?counts.passed+=1:check3.state==="PENDING"||check3.state==="EXPECTED"?counts.pending+=1:counts.failed+=1:check3.status!=="COMPLETED"?counts.pending+=1:PASSING.has(check3.conclusion??"")?counts.passed+=1:counts.failed+=1;return counts}var GITHUB_HOST="github.com",GITHUB_TOKEN_VARIABLES=["GITHUB_TOKEN","GH_TOKEN"];function encodedPath(path103){return path103.split("/").map(encodeURIComponent).join("/")}function githubApiFileUrl(request){let{repository}=request;return`${repository.host===GITHUB_HOST?"https://api.github.com":`https://${repository.host}/api/v3`}/repos/${repository.owner}/${repository.name}/contents/${encodedPath(request.path)}?ref=${encodeURIComponent(request.ref)}`}function githubRawFileUrl(request){let{repository}=request;return`${repository.host===GITHUB_HOST?`https://raw.githubusercontent.com/${repository.owner}/${repository.name}`:`https://${repository.host}/${repository.owner}/${repository.name}/raw`}/${encodeURIComponent(request.ref)}/${encodedPath(request.path)}`}var API_HEADERS={Accept:"application/vnd.github.raw+json","X-GitHub-Api-Version":"2022-11-28"};function createGithubHost(options={}){let extraHosts=new Set((options.hosts??[]).map(host=>host.toLowerCase())),variables=options.tokenVariables??GITHUB_TOKEN_VARIABLES;return{id:"github",defaultHost:GITHUB_HOST,schemes:["github"],features:["fetch","submit","proposals"],readLocation:readGithubLocation,formatLocator:(host,repoPath,rest)=>formatHostedLocator("github",GITHUB_HOST,host,repoPath,rest),matches(url2){let parts=splitRepoUrl(url2);return parts!==void 0&&(parts.host===GITHUB_HOST||extraHosts.has(parts.host))},canonicalize(url2){let parts=splitRepoUrl(url2);if(parts===void 0)throw invalidRepoUrl("github",url2,GITHUB_HOST);return canonicalRepository(parts.host,parts.owner,parts.name)},tokenSources:[envTokenSource({variables,tokenHint:"a token that can read the repository"}),gitCredentialTokenSource(),cliTokenSource({id:"gh",command:GH.command,args:repository=>["auth","token","--hostname",repository.host]})],readStrategies:[httpReadStrategy({id:"http-token",label:"HTTP with token",usesToken:!0,url:githubApiFileUrl,headers:()=>API_HEADERS}),httpReadStrategy({id:"http",label:"HTTP without token",usesToken:!1,url:githubRawFileUrl,headers:()=>({Accept:"*/*"})}),gitReadStrategy()],fetchRecipeTree:(repository,recipePath,tag,destination,ctx)=>fetchRecipeTree({urls:[repository.httpsUrl,repository.sshUrl],tag,recipePath,destination},ctx),proposalNoun:"pull request",cli:GH,authStatus:ctx=>cliAuthStatus(GH,ctx),...githubProposals(),scaffoldFiles:githubWorkflowFiles}}function readGithubLocation(location){let{segments}=location;return segments.length<2?[]:readingsAfterRepository(`${segments[0]}/${withoutGitSuffix(segments[1])}`,segments.slice(2))}var package_default26={name:"@sous-io/plugin-github",version:"1.0.12",description:"A repository-host entity for GitHub: reading indexes, the token, proposing changes, the CI workflow.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-git":"workspace:*","@sous-io/repository-hosts":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME25="@sous-io/plugin-github",githubPlugin=definePlugin26({name:PLUGIN_NAME25,version:package_default26.version,description:"A repository-host entity for GitHub: reading indexes, the token, proposing changes, the CI workflow.",dependsOn:{"@sous-io/plugin-recipes":`^${package_default26.version}`,"@sous-io/plugin-host":`^${package_default26.version}`,"@sous-io/plugin-git":`^${package_default26.version}`},register(sous){sous.config.contribute({id:"github/repository-host",before:["@sous-io/plugin-recipes"],contribute(config2){config2.addEntity("repository-host",createGithubHost(config2.options()??{}))}})}});import{definePlugin as definePlugin27}from"@sous-io/plugin-api";var GITLAB_CI_PATH=".gitlab-ci.yml";function gitlabCiFiles(_options){return[{path:GITLAB_CI_PATH,content:buildGitlabPipeline()}]}function buildGitlabPipeline(){return`# Release automation for this sous recipe repository.
1038
1039
  #
1039
1040
  # Two jobs, both running the sous CLI straight from npm so nothing needs to be
1040
1041
  # installed into this repository:
@@ -1084,13 +1085,13 @@ release:
1084
1085
  - git checkout -B "$CI_COMMIT_BRANCH"
1085
1086
  - git remote set-url origin "https://oauth2:$SOUS_RELEASE_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git"
1086
1087
  - npx --yes @sous-io/sous repo release --ci --push --yes
1087
- `}var GLAB={command:"glab",label:"the GitLab CLI",install:"https://gitlab.com/gitlab-org/cli"};function projectArg(repository){return`${repository.owner}/${repository.name}`}import{ConfigError as ConfigError69}from"@sous-io/plugin-api";var NOUN2="merge request";function glabEnv(repository){return{env:{GITLAB_HOST:repository.host}}}function gitlabProposals(){return{canPush:async()=>{},async fork(repository){throw new ConfigError69(`Sous does not fork ${repository.owner}/${repository.name} for you on ${GLAB.label}; it opens a ${NOUN2} from a branch you can already push.`,{details:[`Fork the project yourself, push your branch to the fork, then open the ${NOUN2} from there.`]})},async proposeChange(repository,proposal,ctx){let args=["mr","create","--repo",projectArg(repository),"--source-branch",proposal.branch];proposal.base!==void 0&&args.push("--target-branch",proposal.base),args.push("--title",proposal.title,"--description",proposal.body,"--yes"),proposal.draft&&args.push("--draft");let result=await runCli(GLAB,args,ctx,glabEnv(repository));if(result.exitCode!==0)throw cliFailure(GLAB,"mr create",result,"so no proposal was opened");let url2=firstUrlIn(result.stdout);return url2===void 0?{detail:`The ${NOUN2} was opened, but '${GLAB.command}' printed no address for it.`}:{url:url2,detail:`The ${NOUN2} is at ${url2}.`}},async findProposal(repository,query,ctx){let forkOwner=query.fromFork?query.forkOwner??await signedInUser(repository,ctx):void 0,mine=(await cliJson(GLAB,["mr","list","--repo",projectArg(repository),"--source-branch",query.branch,"--all","--per-page","50","--output","json"],"mr list",NOUN2,ctx,glabEnv(repository))).filter(entry=>{let crossProject=entry.source_project_id!==void 0&&entry.source_project_id!==entry.target_project_id;return query.fromFork?crossProject&&entry.author?.username===forkOwner:!crossProject});if(mine.length===0)return;let chosen=mine.find(entry=>stateOf2(entry.state)==="open")??[...mine].sort((a,b)=>b.iid-a.iid)[0];return summarize(chosen)},async proposalStatus(repository,id,ctx){let viewed=await cliJson(GLAB,["mr","view",id,"--repo",projectArg(repository),"--output","json"],"mr view",NOUN2,ctx,glabEnv(repository));return statusOf2(viewed)},async updateProposal(repository,id,update,ctx){let args=["mr","update",id,"--repo",projectArg(repository)];update.title!==void 0&&args.push("--title",update.title),update.body!==void 0&&args.push("--description",update.body);let result=await runCli(GLAB,args,ctx,glabEnv(repository));if(result.exitCode!==0)throw cliFailure(GLAB,"mr update",result,`so the ${NOUN2} kept its title and body`);let url2=firstUrlIn(result.stdout);return url2===void 0?{detail:`The ${NOUN2} was updated.`}:{url:url2,detail:`The ${NOUN2} at ${url2} was updated.`}}}}async function signedInUser(repository,ctx){let output=await cliOutput(GLAB,["api","user"],ctx,glabEnv(repository)),username;try{username=output===void 0?void 0:JSON.parse(output).username}catch{username=void 0}if(typeof username!="string"||username.length===0)throw new ConfigError69(`Sous could not read your GitLab username from '${GLAB.command} api user', so it cannot tell which fork a ${NOUN2} would come from.`);return username}function stateOf2(state){return state==="merged"?"merged":state==="closed"||state==="locked"?"closed":"open"}function summarize(entry){return{id:String(entry.iid),...entry.web_url===void 0?{}:{url:entry.web_url},state:stateOf2(entry.state),title:entry.title??"",draft:entry.draft===!0||entry.work_in_progress===!0,...entry.target_branch===void 0?{}:{base:entry.target_branch}}}var PENDING_PIPELINES=new Set(["created","waiting_for_resource","preparing","pending","running","scheduled","manual"]);function statusOf2(entry){let pipeline=entry.head_pipeline?.status,checks=pipeline===void 0?void 0:{passed:pipeline==="success"?1:0,failed:pipeline==="failed"||pipeline==="canceled"?1:0,pending:PENDING_PIPELINES.has(pipeline)?1:0},review=entry.detailed_merge_status==="not_approved"?"review required":void 0,mergeable=entry.has_conflicts===!0||entry.merge_status==="cannot_be_merged"?!1:entry.merge_status==="can_be_merged"||entry.detailed_merge_status==="mergeable"?!0:void 0;return{proposal:summarize(entry),...review===void 0?{}:{review},...checks===void 0?{}:{checks},...mergeable===void 0?{}:{mergeable}}}var GITLAB_HOST="gitlab.com",GITLAB_TOKEN_VARIABLES=["GITLAB_TOKEN"];function gitlabFileUrl(request){let{repository}=request,project=encodeURIComponent(`${repository.owner}/${repository.name}`);return`https://${repository.host}/api/v4/projects/${project}/repository/files/${encodeURIComponent(request.path)}/raw?ref=${encodeURIComponent(request.ref)}`}function createGitlabHost(options={}){let extraHosts=new Set((options.hosts??[]).map(host=>host.toLowerCase())),variables=options.tokenVariables??GITLAB_TOKEN_VARIABLES,isGitlab=host=>host===GITLAB_HOST||host.startsWith("gitlab.")||extraHosts.has(host);return{id:"gitlab",defaultHost:GITLAB_HOST,schemes:["gitlab"],features:["fetch","submit","proposals"],readLocation:readGitlabLocation,formatLocator:(host,repoPath,rest)=>formatHostedLocator("gitlab",GITLAB_HOST,host,repoPath,rest,"/-/"),matches(url2){let parts=splitRepoUrl(url2);return parts!==void 0&&isGitlab(parts.host)},canonicalize(url2){let parts=splitRepoUrl(url2);if(parts===void 0)throw invalidRepoUrl("gitlab",url2,GITLAB_HOST);return canonicalRepository(parts.host,parts.owner,parts.name)},tokenSources:[envTokenSource({variables,tokenHint:"a token with read_repository"}),gitCredentialTokenSource(),cliTokenSource({id:"glab",command:GLAB.command,args:repository=>["config","get","token","--host",repository.host]})],readStrategies:[httpReadStrategy({id:"http-token",label:"HTTP with token",usesToken:!0,url:gitlabFileUrl}),httpReadStrategy({id:"http",label:"HTTP without token",usesToken:!1,url:gitlabFileUrl}),gitReadStrategy()],fetchRecipeTree:(repository,recipePath,tag,destination,ctx)=>fetchRecipeTree({urls:[repository.httpsUrl,repository.sshUrl],tag,recipePath,destination},ctx),proposalNoun:"merge request",cli:GLAB,authStatus:ctx=>cliAuthStatus(GLAB,ctx),...gitlabProposals(),scaffoldFiles:gitlabCiFiles}}function readGitlabLocation(location){let{segments}=location,separator=segments.indexOf("-");if(separator>=2)return readingsAfterRepository(projectPath(segments.slice(0,separator)),segments.slice(separator));let suffixed=segments.findIndex(segment=>/\.git$/i.test(segment));if(suffixed>=1)return readingsAfterRepository(projectPath(segments.slice(0,suffixed+1)),segments.slice(suffixed+1));let readings=[];for(let end=2;end<=segments.length;end++){let rest=segments.slice(end);rest.length<=2&&readings.push({repoPath:projectPath(segments.slice(0,end)),named:rest})}return readings}function projectPath(segments){let last2=segments.length-1;return segments.map((segment,index)=>index===last2?withoutGitSuffix(segment):segment).join("/")}var package_default27={name:"@sous-io/plugin-gitlab",version:"1.0.11",description:"A repository-host entity for GitLab, with S4's fixes to the index address and the token.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-git":"workspace:*","@sous-io/repository-hosts":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME26="@sous-io/plugin-gitlab",gitlabPlugin=definePlugin27({name:PLUGIN_NAME26,version:package_default27.version,description:"A repository-host entity for GitLab, with fixes to the index address and the token.",dependsOn:{"@sous-io/plugin-recipes":`^${package_default27.version}`,"@sous-io/plugin-host":`^${package_default27.version}`,"@sous-io/plugin-git":`^${package_default27.version}`},register(sous){sous.config.contribute({id:"gitlab/repository-host",before:["@sous-io/plugin-recipes"],contribute(config2){config2.addEntity("repository-host",createGitlabHost(config2.options()??{}))}})}});import{definePlugin as definePlugin28}from"@sous-io/plugin-api";import{existsSync as existsSync5}from"node:fs";import{readFile as readFile3}from"node:fs/promises";import path99 from"node:path";import{pathToFileURL as pathToFileURL7}from"node:url";import{ConfigError as ConfigError71}from"@sous-io/plugin-api";import path98 from"node:path";import{fileURLToPath as fileURLToPath3}from"node:url";function localRepoPath(url2){let trimmed=url2.trim();if(trimmed.length!==0){if(trimmed.toLowerCase().startsWith("file://"))try{return path98.normalize(fileURLToPath3(trimmed))}catch{return}return path98.isAbsolute(trimmed)?path98.normalize(trimmed):void 0}}function identityOwnerPath(directory,paths=path98){let{root}=paths.parse(directory);return`/${[...root.split(/[\\/]/).map(segment=>segment.replace(/:$/,"")),...directory.slice(root.length).split(paths.sep)].filter(segment=>segment.length>0).join("/")}`}import{statSync as statSync2}from"node:fs";import{ConfigError as ConfigError70}from"@sous-io/plugin-api";function assertLocalRepoDirectory(typed,resolved,manifests){let manifestName=`${REPO_MANIFEST_BASENAME}${MANIFEST_EXTENSIONS[0]}`,spellings=MANIFEST_EXTENSIONS.map(extension=>`${REPO_MANIFEST_BASENAME}${extension}`).join(", "),stats;try{stats=statSync2(resolved)}catch{throw new ConfigError70(`There is no directory at '${typed}'.`,{details:[`Sous read that as the path ${resolved}, and nothing is there.`,`A repository on this machine is a directory holding a '${manifestName}' file at its root. Check the path, or create one with 'sous repo init'.`]})}if(!stats.isDirectory())throw new ConfigError70(`'${typed}' is a file, not a directory.`,{details:[`Sous read that as the path ${resolved}.`,`Name the root directory of a repository: the directory holding its '${manifestName}' file.`]});if(manifests.find(resolved,"repo")===void 0)throw new ConfigError70(`The directory '${typed}' is not a sous repository.`,{details:[`Sous read that as the path ${resolved}, and it holds no repository manifest.`,`A repository declares itself with one of ${spellings} at its root. Check the path, or create a repository there with 'sous repo init'.`]})}var LOCAL_HOST="localhost";function repoDirectory(repository){return repository.httpsUrl}var fileStrategy={id:"file",label:"working tree",async read(request){let directory=repoDirectory(request.repository);if(request.ref!=="HEAD")return{ok:!1,reason:`the working tree is not ${request.ref}`};if(!existsSync5(directory))return{ok:!1,reason:`there is no directory at ${directory}`};let file2=path99.join(directory,request.path);return existsSync5(file2)?{ok:!0,text:await readFile3(file2,"utf8"),ref:"working tree"}:{ok:!1,reason:`the working tree has no ${request.path}`}}},gitStrategy={id:"git",label:"git",async read(request,ctx){let directory=repoDirectory(request.repository);if(!existsSync5(directory))return{ok:!1,reason:`there is no directory at ${directory}`};let result=await ctx.services.get("git.runner").run(["show",`${request.ref}:${request.path}`],{cwd:directory,reject:!1,...ctx.signal===void 0?{}:{signal:ctx.signal}});return result.exitCode!==0?{ok:!1,reason:gitFailureReason(new Error(result.stderr||"git show failed"))}:{ok:!0,text:result.stdout,ref:request.ref}}};function createLocalHost(){return{id:"local",features:["fetch"],readLocation:()=>[],formatLocator:(host,repoPath,rest)=>formatHostedLocator("local",void 0,host,repoPath,rest),matches:url2=>localRepoPath(url2)!==void 0,canonicalize(url2){let directory=localRepoPath(url2);if(directory===void 0)throw new ConfigError71(`'${url2}' is not a local repository path that sous can read.`,{details:["A local repository is named by an absolute path, or by the same path in 'file:///...' form. A relative path is not accepted, because a repository entry is read from a config file that several working directories may run against."]});return{host:LOCAL_HOST,owner:identityOwnerPath(path99.dirname(directory)),name:path99.basename(directory),httpsUrl:directory,sshUrl:pathToFileURL7(directory).href}},readStrategies:[fileStrategy,gitStrategy],checkTypedPath:(typed,resolved,ctx)=>assertLocalRepoDirectory(typed,resolved,ctx.services.get("formats.manifests")),fetchRecipeTree:(repository,recipePath,tag,destination,ctx)=>fetchLocalRecipeTree(repository,recipePath,tag,destination,ctx)}}async function fetchLocalRecipeTree(repository,recipePath,tag,destination,ctx){let directory=repoDirectory(repository),git2=ctx.services.get("git.runner");if(await git2.root(directory)!==void 0&&await git2.revParse(`refs/tags/${tag}`,directory)!==void 0){await fetchRecipeTree({urls:[directory],tag,recipePath,destination},ctx);return}let source=path99.join(directory,recipePath);if(!existsSync5(source))throw new ConfigError71(`The repository at ${directory} has no folder '${recipePath}'.`,{details:["Its index says the recipe lives there, so either the index is out of date or the folder has been moved."]});await copyRecipeTree(source,destination)}var package_default28={name:"@sous-io/plugin-local",version:"1.0.11",description:"A repository-host entity for a repository on disk.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-formats":"workspace:*","@sous-io/plugin-git":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/repository-hosts":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME27="@sous-io/plugin-local",localPlugin=definePlugin28({name:PLUGIN_NAME27,version:package_default28.version,description:"A repository-host entity for a repository on disk.",dependsOn:{"@sous-io/plugin-recipes":`^${package_default28.version}`,"@sous-io/plugin-host":`^${package_default28.version}`,"@sous-io/plugin-git":`^${package_default28.version}`,"@sous-io/plugin-formats":`^${package_default28.version}`},register(sous){sous.entities.add("repository-host",createLocalHost())}});import{definePlugin as definePlugin29}from"@sous-io/plugin-api";import{SousError as SousError30}from"@sous-io/plugin-api";function parseStream(stdout){let lines3=[];for(let text of stdout.split(`
1088
+ `}var GLAB={command:"glab",label:"the GitLab CLI",install:"https://gitlab.com/gitlab-org/cli"};function projectArg(repository){return`${repository.owner}/${repository.name}`}import{ConfigError as ConfigError69}from"@sous-io/plugin-api";var NOUN2="merge request";function glabEnv(repository){return{env:{GITLAB_HOST:repository.host}}}function gitlabProposals(){return{canPush:async()=>{},async fork(repository){throw new ConfigError69(`Sous does not fork ${repository.owner}/${repository.name} for you on ${GLAB.label}; it opens a ${NOUN2} from a branch you can already push.`,{details:[`Fork the project yourself, push your branch to the fork, then open the ${NOUN2} from there.`]})},async proposeChange(repository,proposal,ctx){let args=["mr","create","--repo",projectArg(repository),"--source-branch",proposal.branch];proposal.base!==void 0&&args.push("--target-branch",proposal.base),args.push("--title",proposal.title,"--description",proposal.body,"--yes"),proposal.draft&&args.push("--draft");let result=await runCli(GLAB,args,ctx,glabEnv(repository));if(result.exitCode!==0)throw cliFailure(GLAB,"mr create",result,"so no proposal was opened");let url2=firstUrlIn(result.stdout);return url2===void 0?{detail:`The ${NOUN2} was opened, but '${GLAB.command}' printed no address for it.`}:{url:url2,detail:`The ${NOUN2} is at ${url2}.`}},async findProposal(repository,query,ctx){let forkOwner=query.fromFork?query.forkOwner??await signedInUser(repository,ctx):void 0,mine=(await cliJson(GLAB,["mr","list","--repo",projectArg(repository),"--source-branch",query.branch,"--all","--per-page","50","--output","json"],"mr list",NOUN2,ctx,glabEnv(repository))).filter(entry=>{let crossProject=entry.source_project_id!==void 0&&entry.source_project_id!==entry.target_project_id;return query.fromFork?crossProject&&entry.author?.username===forkOwner:!crossProject});if(mine.length===0)return;let chosen=mine.find(entry=>stateOf2(entry.state)==="open")??[...mine].sort((a,b)=>b.iid-a.iid)[0];return summarize(chosen)},async proposalStatus(repository,id,ctx){let viewed=await cliJson(GLAB,["mr","view",id,"--repo",projectArg(repository),"--output","json"],"mr view",NOUN2,ctx,glabEnv(repository));return statusOf2(viewed)},async updateProposal(repository,id,update,ctx){let args=["mr","update",id,"--repo",projectArg(repository)];update.title!==void 0&&args.push("--title",update.title),update.body!==void 0&&args.push("--description",update.body);let result=await runCli(GLAB,args,ctx,glabEnv(repository));if(result.exitCode!==0)throw cliFailure(GLAB,"mr update",result,`so the ${NOUN2} kept its title and body`);let url2=firstUrlIn(result.stdout);return url2===void 0?{detail:`The ${NOUN2} was updated.`}:{url:url2,detail:`The ${NOUN2} at ${url2} was updated.`}}}}async function signedInUser(repository,ctx){let output=await cliOutput(GLAB,["api","user"],ctx,glabEnv(repository)),username;try{username=output===void 0?void 0:JSON.parse(output).username}catch{username=void 0}if(typeof username!="string"||username.length===0)throw new ConfigError69(`Sous could not read your GitLab username from '${GLAB.command} api user', so it cannot tell which fork a ${NOUN2} would come from.`);return username}function stateOf2(state){return state==="merged"?"merged":state==="closed"||state==="locked"?"closed":"open"}function summarize(entry){return{id:String(entry.iid),...entry.web_url===void 0?{}:{url:entry.web_url},state:stateOf2(entry.state),title:entry.title??"",draft:entry.draft===!0||entry.work_in_progress===!0,...entry.target_branch===void 0?{}:{base:entry.target_branch}}}var PENDING_PIPELINES=new Set(["created","waiting_for_resource","preparing","pending","running","scheduled","manual"]);function statusOf2(entry){let pipeline=entry.head_pipeline?.status,checks=pipeline===void 0?void 0:{passed:pipeline==="success"?1:0,failed:pipeline==="failed"||pipeline==="canceled"?1:0,pending:PENDING_PIPELINES.has(pipeline)?1:0},review=entry.detailed_merge_status==="not_approved"?"review required":void 0,mergeable=entry.has_conflicts===!0||entry.merge_status==="cannot_be_merged"?!1:entry.merge_status==="can_be_merged"||entry.detailed_merge_status==="mergeable"?!0:void 0;return{proposal:summarize(entry),...review===void 0?{}:{review},...checks===void 0?{}:{checks},...mergeable===void 0?{}:{mergeable}}}var GITLAB_HOST="gitlab.com",GITLAB_TOKEN_VARIABLES=["GITLAB_TOKEN"];function gitlabFileUrl(request){let{repository}=request,project=encodeURIComponent(`${repository.owner}/${repository.name}`);return`https://${repository.host}/api/v4/projects/${project}/repository/files/${encodeURIComponent(request.path)}/raw?ref=${encodeURIComponent(request.ref)}`}function createGitlabHost(options={}){let extraHosts=new Set((options.hosts??[]).map(host=>host.toLowerCase())),variables=options.tokenVariables??GITLAB_TOKEN_VARIABLES,isGitlab=host=>host===GITLAB_HOST||host.startsWith("gitlab.")||extraHosts.has(host);return{id:"gitlab",defaultHost:GITLAB_HOST,schemes:["gitlab"],features:["fetch","submit","proposals"],readLocation:readGitlabLocation,formatLocator:(host,repoPath,rest)=>formatHostedLocator("gitlab",GITLAB_HOST,host,repoPath,rest,"/-/"),matches(url2){let parts=splitRepoUrl(url2);return parts!==void 0&&isGitlab(parts.host)},canonicalize(url2){let parts=splitRepoUrl(url2);if(parts===void 0)throw invalidRepoUrl("gitlab",url2,GITLAB_HOST);return canonicalRepository(parts.host,parts.owner,parts.name)},tokenSources:[envTokenSource({variables,tokenHint:"a token with read_repository"}),gitCredentialTokenSource(),cliTokenSource({id:"glab",command:GLAB.command,args:repository=>["config","get","token","--host",repository.host]})],readStrategies:[httpReadStrategy({id:"http-token",label:"HTTP with token",usesToken:!0,url:gitlabFileUrl}),httpReadStrategy({id:"http",label:"HTTP without token",usesToken:!1,url:gitlabFileUrl}),gitReadStrategy()],fetchRecipeTree:(repository,recipePath,tag,destination,ctx)=>fetchRecipeTree({urls:[repository.httpsUrl,repository.sshUrl],tag,recipePath,destination},ctx),proposalNoun:"merge request",cli:GLAB,authStatus:ctx=>cliAuthStatus(GLAB,ctx),...gitlabProposals(),scaffoldFiles:gitlabCiFiles}}function readGitlabLocation(location){let{segments}=location,separator=segments.indexOf("-");if(separator>=2)return readingsAfterRepository(projectPath(segments.slice(0,separator)),segments.slice(separator));let suffixed=segments.findIndex(segment=>/\.git$/i.test(segment));if(suffixed>=1)return readingsAfterRepository(projectPath(segments.slice(0,suffixed+1)),segments.slice(suffixed+1));let readings=[];for(let end=2;end<=segments.length;end++){let rest=segments.slice(end);rest.length<=2&&readings.push({repoPath:projectPath(segments.slice(0,end)),named:rest})}return readings}function projectPath(segments){let last2=segments.length-1;return segments.map((segment,index)=>index===last2?withoutGitSuffix(segment):segment).join("/")}var package_default27={name:"@sous-io/plugin-gitlab",version:"1.0.12",description:"A repository-host entity for GitLab, with S4's fixes to the index address and the token.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-git":"workspace:*","@sous-io/repository-hosts":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME26="@sous-io/plugin-gitlab",gitlabPlugin=definePlugin27({name:PLUGIN_NAME26,version:package_default27.version,description:"A repository-host entity for GitLab, with fixes to the index address and the token.",dependsOn:{"@sous-io/plugin-recipes":`^${package_default27.version}`,"@sous-io/plugin-host":`^${package_default27.version}`,"@sous-io/plugin-git":`^${package_default27.version}`},register(sous){sous.config.contribute({id:"gitlab/repository-host",before:["@sous-io/plugin-recipes"],contribute(config2){config2.addEntity("repository-host",createGitlabHost(config2.options()??{}))}})}});import{definePlugin as definePlugin28}from"@sous-io/plugin-api";import{existsSync as existsSync5}from"node:fs";import{readFile as readFile3}from"node:fs/promises";import path99 from"node:path";import{pathToFileURL as pathToFileURL7}from"node:url";import{ConfigError as ConfigError71}from"@sous-io/plugin-api";import path98 from"node:path";import{fileURLToPath as fileURLToPath3}from"node:url";function localRepoPath(url2){let trimmed=url2.trim();if(trimmed.length!==0){if(trimmed.toLowerCase().startsWith("file://"))try{return path98.normalize(fileURLToPath3(trimmed))}catch{return}return path98.isAbsolute(trimmed)?path98.normalize(trimmed):void 0}}function identityOwnerPath(directory,paths=path98){let{root}=paths.parse(directory);return`/${[...root.split(/[\\/]/).map(segment=>segment.replace(/:$/,"")),...directory.slice(root.length).split(paths.sep)].filter(segment=>segment.length>0).join("/")}`}import{statSync as statSync2}from"node:fs";import{ConfigError as ConfigError70}from"@sous-io/plugin-api";function assertLocalRepoDirectory(typed,resolved,manifests){let manifestName=`${REPO_MANIFEST_BASENAME}${MANIFEST_EXTENSIONS[0]}`,spellings=MANIFEST_EXTENSIONS.map(extension=>`${REPO_MANIFEST_BASENAME}${extension}`).join(", "),stats;try{stats=statSync2(resolved)}catch{throw new ConfigError70(`There is no directory at '${typed}'.`,{details:[`Sous read that as the path ${resolved}, and nothing is there.`,`A repository on this machine is a directory holding a '${manifestName}' file at its root. Check the path, or create one with 'sous repo init'.`]})}if(!stats.isDirectory())throw new ConfigError70(`'${typed}' is a file, not a directory.`,{details:[`Sous read that as the path ${resolved}.`,`Name the root directory of a repository: the directory holding its '${manifestName}' file.`]});if(manifests.find(resolved,"repo")===void 0)throw new ConfigError70(`The directory '${typed}' is not a sous repository.`,{details:[`Sous read that as the path ${resolved}, and it holds no repository manifest.`,`A repository declares itself with one of ${spellings} at its root. Check the path, or create a repository there with 'sous repo init'.`]})}var LOCAL_HOST="localhost";function repoDirectory(repository){return repository.httpsUrl}var fileStrategy={id:"file",label:"working tree",async read(request){let directory=repoDirectory(request.repository);if(request.ref!=="HEAD")return{ok:!1,reason:`the working tree is not ${request.ref}`};if(!existsSync5(directory))return{ok:!1,reason:`there is no directory at ${directory}`};let file2=path99.join(directory,request.path);return existsSync5(file2)?{ok:!0,text:await readFile3(file2,"utf8"),ref:"working tree"}:{ok:!1,reason:`the working tree has no ${request.path}`}}},gitStrategy={id:"git",label:"git",async read(request,ctx){let directory=repoDirectory(request.repository);if(!existsSync5(directory))return{ok:!1,reason:`there is no directory at ${directory}`};let result=await ctx.services.get("git.runner").run(["show",`${request.ref}:${request.path}`],{cwd:directory,reject:!1,...ctx.signal===void 0?{}:{signal:ctx.signal}});return result.exitCode!==0?{ok:!1,reason:gitFailureReason(new Error(result.stderr||"git show failed"))}:{ok:!0,text:result.stdout,ref:request.ref}}};function createLocalHost(){return{id:"local",features:["fetch"],readLocation:()=>[],formatLocator:(host,repoPath,rest)=>formatHostedLocator("local",void 0,host,repoPath,rest),matches:url2=>localRepoPath(url2)!==void 0,canonicalize(url2){let directory=localRepoPath(url2);if(directory===void 0)throw new ConfigError71(`'${url2}' is not a local repository path that sous can read.`,{details:["A local repository is named by an absolute path, or by the same path in 'file:///...' form. A relative path is not accepted, because a repository entry is read from a config file that several working directories may run against."]});return{host:LOCAL_HOST,owner:identityOwnerPath(path99.dirname(directory)),name:path99.basename(directory),httpsUrl:directory,sshUrl:pathToFileURL7(directory).href}},readStrategies:[fileStrategy,gitStrategy],checkTypedPath:(typed,resolved,ctx)=>assertLocalRepoDirectory(typed,resolved,ctx.services.get("formats.manifests")),fetchRecipeTree:(repository,recipePath,tag,destination,ctx)=>fetchLocalRecipeTree(repository,recipePath,tag,destination,ctx)}}async function fetchLocalRecipeTree(repository,recipePath,tag,destination,ctx){let directory=repoDirectory(repository),git2=ctx.services.get("git.runner");if(await git2.root(directory)!==void 0&&await git2.revParse(`refs/tags/${tag}`,directory)!==void 0){await fetchRecipeTree({urls:[directory],tag,recipePath,destination},ctx);return}let source=path99.join(directory,recipePath);if(!existsSync5(source))throw new ConfigError71(`The repository at ${directory} has no folder '${recipePath}'.`,{details:["Its index says the recipe lives there, so either the index is out of date or the folder has been moved."]});await copyRecipeTree(source,destination)}var package_default28={name:"@sous-io/plugin-local",version:"1.0.12",description:"A repository-host entity for a repository on disk.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-formats":"workspace:*","@sous-io/plugin-git":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/repository-hosts":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME27="@sous-io/plugin-local",localPlugin=definePlugin28({name:PLUGIN_NAME27,version:package_default28.version,description:"A repository-host entity for a repository on disk.",dependsOn:{"@sous-io/plugin-recipes":`^${package_default28.version}`,"@sous-io/plugin-host":`^${package_default28.version}`,"@sous-io/plugin-git":`^${package_default28.version}`,"@sous-io/plugin-formats":`^${package_default28.version}`},register(sous){sous.entities.add("repository-host",createLocalHost())}});import{definePlugin as definePlugin29}from"@sous-io/plugin-api";import{SousError as SousError30}from"@sous-io/plugin-api";function parseStream(stdout){let lines3=[];for(let text of stdout.split(`
1088
1089
  `))if(text.trim().startsWith("{"))try{let value=JSON.parse(text);value&&typeof value=="object"&&!Array.isArray(value)&&lines3.push(value)}catch{}return lines3}function blocksOf(line){let message2=line.message,content=message2&&typeof message2=="object"?message2.content:void 0;return typeof content=="string"?[{type:"text",text:content}]:Array.isArray(content)?content.filter(block=>!!block&&typeof block=="object"):[]}function resultText(content){return typeof content=="string"?content:Array.isArray(content)?content.map(part=>part&&typeof part=="object"&&typeof part.text=="string"?part.text:"").filter(text=>text!=="").join(`
1089
1090
  `):""}function finalText(lines3){let result=[...lines3].reverse().find(line=>line.type==="result");if(result&&typeof result.result=="string")return result.result;for(let line of[...lines3].reverse())if(line.type==="assistant"){let text=blocksOf(line).filter(block=>block.type==="text"&&typeof block.text=="string").map(block=>block.text).join(`
1090
- `);if(text!=="")return text}return""}function transcriptEntries(lines3){let entries=[],toolNames=new Map;for(let line of lines3)if(line.type==="system"&&line.subtype==="init"){let model=typeof line.model=="string"?` (${line.model})`:"";entries.push({role:"system",text:`Session started${model}`})}else if(line.type==="assistant")for(let block of blocksOf(line))block.type==="text"&&typeof block.text=="string"?entries.push({role:"assistant",text:block.text}):block.type==="tool_use"&&typeof block.name=="string"&&(typeof block.id=="string"&&toolNames.set(block.id,block.name),entries.push({role:"assistant",text:"",tool:block.name,input:block.input}));else if(line.type==="user")for(let block of blocksOf(line))if(block.type==="tool_result"){let tool=typeof block.tool_use_id=="string"?toolNames.get(block.tool_use_id):void 0;entries.push({role:"tool",text:resultText(block.content),...tool===void 0?{}:{tool}})}else block.type==="text"&&typeof block.text=="string"&&entries.push({role:"user",text:block.text});return entries}var HARNESS_ID="claude",DEFAULT_COMMAND="claude",HEADLESS_ARGS=["-p","--output-format","stream-json","--verbose"],claudeHarness={id:HARNESS_ID,description:"Claude Code, started with the `claude` command.",async launch(args,ctx){let settings=ctx.config.get("tools.claude")??{};return ctx.services.get("host.processes").runInteractive(settings.command??DEFAULT_COMMAND,launchArguments(settings,args,ctx),{...ctx.project?{cwd:ctx.project.root}:{},env:ctx.env,label:HARNESS_ID})},async runHeadless(request,ctx){let settings=ctx.config.get("tools.claude")??{},model=request.model??ctx.options()?.model,command=settings.headless?.command??settings.command??DEFAULT_COMMAND,args=[...settings.headless?.args??[],...HEADLESS_ARGS,...model===void 0?[]:["--model",model],...passed(request.options)],cwd=request.cwd??ctx.project?.root,result=await ctx.services.get("host.processes").run(command,args,{...cwd===void 0?{}:{cwd},env:ctx.env,input:request.prompt,...request.timeoutMs===void 0?{}:{timeoutMs:request.timeoutMs},...request.signal===void 0?{}:{signal:request.signal},label:`${HARNESS_ID} (headless)`});if(result.timedOut)throw new SousError30(`claude did not finish within ${request.timeoutMs}ms.`);let raw2={stdout:result.stdout,stderr:result.stderr},output=finalText(parseStream(result.stdout));return{harness:HARNESS_ID,exitCode:result.exitCode,output,durationMs:result.durationMs,raw:raw2}},readTranscript(run){let raw2=run.raw;return{harness:HARNESS_ID,entries:transcriptEntries(parseStream(raw2?.stdout??""))}}};function passed(options){let args=options?.args;return Array.isArray(args)?args.filter(arg=>typeof arg=="string"):[]}var TARGETS_CONTRIBUTOR3="claude-code/targets",TARGET_ID="claude-code",SKILLS_DIRECTORY=".claude/skills",MEMORY_FILE="CLAUDE.md";function contributeTargets(config2){let options=config2.options()??{},skills={id:TARGET_ID,harness:"claude",directory:options.skillsDirectory??SKILLS_DIRECTORY,description:"Claude Code reads skills from .claude/skills."};if(config2.addEntity("skill-target",skills),options.memories!==!1){let memories={id:TARGET_ID,harness:"claude",fileName:MEMORY_FILE,readIn:"any-directory"};config2.addEntity("memory-target",memories)}}var targetsContributor2={id:TARGETS_CONTRIBUTOR3,contribute:contributeTargets};var package_default29={name:"@sous-io/plugin-claude-code",version:"1.0.11",description:"Everything sous knows about Claude Code: its harness, skill-target and memory-target entities.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-skills":"workspace:*","@sous-io/plugin-memories":"workspace:*","@sous-io/plugin-harnesses":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME28="@sous-io/plugin-claude-code",claudeCodePlugin=definePlugin29({name:PLUGIN_NAME28,version:package_default29.version,description:"Everything sous knows about Claude Code: its harness, skill-target and memory-target entities.",dependsOn:{"@sous-io/plugin-skills":`^${package_default29.version}`,"@sous-io/plugin-memories":`^${package_default29.version}`,"@sous-io/plugin-harnesses":`^${package_default29.version}`,"@sous-io/plugin-host":`^${package_default29.version}`},register(sous){sous.entities.add("harness",claudeHarness),sous.config.contribute(targetsContributor2)}});var package_default30={name:"@sous-io/sous",version:"1.0.11",description:"Compiles AI coding agent configuration (CLAUDE.md, skills, memories) from LiquidJS templates",type:"module",license:"Apache-2.0",author:"Luke Chavers",repository:{type:"git",url:"git+https://github.com/sous-io/sous.git",directory:"packages/sous"},homepage:"https://sous.io",bugs:"https://github.com/sous-io/sous/issues",keywords:["cli","ai","agents","claude","claude-code","codex","prompts","skills","templates","liquidjs"],publishConfig:{access:"public"},bin:{sous:"./dist/bin.js"},files:["dist/bin.js","dist/sous.js","dist/tiktoken_bg.wasm","recipes","docs/markdown/*.md","sous.config.schema.json"],scripts:{test:"vitest run",typecheck:"tsc --noEmit -p .",build:"node scripts/bundle.mjs",prepack:"node scripts/bundle.mjs && node scripts/pack-files.mjs copy",postpack:"node scripts/pack-files.mjs clean"},dependencies:{"@sous-io/plugin-api":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*","@sous-io/documents":"workspace:*","@sous-io/plugin-authoring":"workspace:*","@sous-io/plugin-build":"workspace:*","@sous-io/plugin-claude-code":"workspace:*","@sous-io/plugin-cli":"workspace:*","@sous-io/plugin-compiler":"workspace:*","@sous-io/plugin-confd":"workspace:*","@sous-io/plugin-config-files":"workspace:*","@sous-io/plugin-expressions":"workspace:*","@sous-io/plugin-formats":"workspace:*","@sous-io/plugin-git":"workspace:*","@sous-io/plugin-github":"workspace:*","@sous-io/plugin-gitlab":"workspace:*","@sous-io/plugin-harnesses":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-init":"workspace:*","@sous-io/plugin-inspect":"workspace:*","@sous-io/plugin-liquid":"workspace:*","@sous-io/plugin-local":"workspace:*","@sous-io/plugin-mcp":"workspace:*","@sous-io/plugin-memories":"workspace:*","@sous-io/plugin-npm":"workspace:*","@sous-io/plugin-pnpm":"workspace:*","@sous-io/plugin-recipe-answers":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/plugin-refs":"workspace:*","@sous-io/plugin-skills":"workspace:*","@sous-io/plugin-update":"workspace:*","@sous-io/plugin-variables":"workspace:*","@sous-io/plugin-yarn":"workspace:*",esbuild:"^0.27.4","jsonc-parser":"^3.3.1",yaml:"^2.9.0",zod:"^4.4.3"},engines:{node:">=22"}};var envPluginsPlugin=definePlugin30({name:"@sous-io/sous",version:package_default30.version,description:"Loads the plugins named in SOUS_PLUGINS.",register(sous){sous.config.contribute({id:"sous/env-plugins",contribute(config2){let listed2=(config2.env.SOUS_PLUGINS??"").split(",").map(item=>item.trim()).filter(item=>item!=="");for(let specifier of listed2)config2.atPath("plugins.load").append(specifier)}})}}),BUILT_IN_PLUGINS=[hostPlugin,gitPlugin,refsPlugin,variablesPlugin,liquidPlugin,formatsPlugin,expressionsPlugin,configFilesPlugin,confdPlugin,compilerPlugin,recipesPlugin,recipeAnswersPlugin,skillsPlugin,memoriesPlugin,buildPlugin,harnessesPlugin,authoringPlugin,initPlugin,updatePlugin,cliPlugin,inspectPlugin,mcpPlugin,npmPlugin,pnpmPlugin,yarnPlugin,githubPlugin,gitlabPlugin,localPlugin,claudeCodePlugin,envPluginsPlugin];import{existsSync as existsSync6,statSync as statSync3}from"node:fs";import path100 from"node:path";var CONFIG_FILE_NAMES=["sous.config.ts","sous.config.mts","sous.config.js","sous.config.mjs","sous.config.jsonc","sous.config.json","sous.config.yaml","sous.config.yml"];function findProject(cwd,confDir){for(let dir=path100.resolve(cwd);;dir=path100.dirname(dir)){let sousDir=path100.join(dir,".sous"),configPath=isDirectory5(sousDir)?configIn(sousDir):void 0;if(configPath!==void 0)return projectAt(sousDir,configPath,confDir);if(path100.dirname(dir)===dir)return}}function readOverrides(argv2,env,cwd){let flags=readFlags(argv2,["config","c","sous-config","sous-dir","sous-confd"]),chosen=[[flags.config??flags.c,flags.c!==void 0&&flags.config===void 0?"-c":"--config"],[flags["sous-config"],"--sous-config"],[blank(env.SOUS_CONFIG),"SOUS_CONFIG"],[flags["sous-dir"],"--sous-dir"],[blank(env.SOUS_DIR),"SOUS_DIR"]].find(([value])=>value!==void 0),confd=flags["sous-confd"]??blank(env.SOUS_CONFD);return{config:chosen===void 0?void 0:{value:resolvePath(chosen[0],cwd,env),source:chosen[1]},confDir:confd===void 0?void 0:resolvePath(confd,cwd,env)}}function locateProject(cwd,overrides){if(overrides.config===void 0)return findProject(cwd,overrides.confDir);let{value,source}=overrides.config;if(!existsSync6(value))throw new Error(`${source} path not found: ${value}`);if(!isDirectory5(value))return projectAt(path100.dirname(value),value,overrides.confDir);let direct=configIn(value);if(direct!==void 0)return projectAt(value,direct,overrides.confDir);let nested=path100.join(value,".sous"),nestedConfig=isDirectory5(nested)?configIn(nested):void 0;if(nestedConfig!==void 0)return projectAt(nested,nestedConfig,overrides.confDir);throw new Error(`${source} points at a directory with no sous config file: ${value}
1091
+ `);if(text!=="")return text}return""}function transcriptEntries(lines3){let entries=[],toolNames=new Map;for(let line of lines3)if(line.type==="system"&&line.subtype==="init"){let model=typeof line.model=="string"?` (${line.model})`:"";entries.push({role:"system",text:`Session started${model}`})}else if(line.type==="assistant")for(let block of blocksOf(line))block.type==="text"&&typeof block.text=="string"?entries.push({role:"assistant",text:block.text}):block.type==="tool_use"&&typeof block.name=="string"&&(typeof block.id=="string"&&toolNames.set(block.id,block.name),entries.push({role:"assistant",text:"",tool:block.name,input:block.input}));else if(line.type==="user")for(let block of blocksOf(line))if(block.type==="tool_result"){let tool=typeof block.tool_use_id=="string"?toolNames.get(block.tool_use_id):void 0;entries.push({role:"tool",text:resultText(block.content),...tool===void 0?{}:{tool}})}else block.type==="text"&&typeof block.text=="string"&&entries.push({role:"user",text:block.text});return entries}var HARNESS_ID="claude",DEFAULT_COMMAND="claude",HEADLESS_ARGS=["-p","--output-format","stream-json","--verbose"],claudeHarness={id:HARNESS_ID,description:"Claude Code, started with the `claude` command.",async launch(args,ctx){let settings=ctx.config.get("tools.claude")??{};return ctx.services.get("host.processes").runInteractive(settings.command??DEFAULT_COMMAND,launchArguments(settings,args,ctx),{...ctx.project?{cwd:ctx.project.root}:{},env:ctx.env,label:HARNESS_ID})},async runHeadless(request,ctx){let settings=ctx.config.get("tools.claude")??{},model=request.model??ctx.options()?.model,command=settings.headless?.command??settings.command??DEFAULT_COMMAND,args=[...settings.headless?.args??[],...HEADLESS_ARGS,...model===void 0?[]:["--model",model],...passed(request.options)],cwd=request.cwd??ctx.project?.root,result=await ctx.services.get("host.processes").run(command,args,{...cwd===void 0?{}:{cwd},env:ctx.env,input:request.prompt,...request.timeoutMs===void 0?{}:{timeoutMs:request.timeoutMs},...request.signal===void 0?{}:{signal:request.signal},label:`${HARNESS_ID} (headless)`});if(result.timedOut)throw new SousError30(`claude did not finish within ${request.timeoutMs}ms.`);let raw2={stdout:result.stdout,stderr:result.stderr},output=finalText(parseStream(result.stdout));return{harness:HARNESS_ID,exitCode:result.exitCode,output,durationMs:result.durationMs,raw:raw2}},readTranscript(run){let raw2=run.raw;return{harness:HARNESS_ID,entries:transcriptEntries(parseStream(raw2?.stdout??""))}}};function passed(options){let args=options?.args;return Array.isArray(args)?args.filter(arg=>typeof arg=="string"):[]}var TARGETS_CONTRIBUTOR3="claude-code/targets",TARGET_ID="claude-code",SKILLS_DIRECTORY=".claude/skills",MEMORY_FILE="CLAUDE.md";function contributeTargets(config2){let options=config2.options()??{},skills={id:TARGET_ID,harness:"claude",directory:options.skillsDirectory??SKILLS_DIRECTORY,description:"Claude Code reads skills from .claude/skills."};if(config2.addEntity("skill-target",skills),options.memories!==!1){let memories={id:TARGET_ID,harness:"claude",fileName:MEMORY_FILE,readIn:"any-directory"};config2.addEntity("memory-target",memories)}}var targetsContributor2={id:TARGETS_CONTRIBUTOR3,contribute:contributeTargets};var package_default29={name:"@sous-io/plugin-claude-code",version:"1.0.12",description:"Everything sous knows about Claude Code: its harness, skill-target and memory-target entities.",type:"module",license:"Apache-2.0",private:!0,exports:{".":{source:"./src/index.ts",types:"./dist/index.d.ts",default:"./dist/index.js"},"./types":{source:"./src/types.ts",types:"./dist/types.d.ts",default:"./dist/types.js"}},scripts:{test:"vitest run",typecheck:"tsc --noEmit -p ."},dependencies:{"@sous-io/plugin-api":"workspace:*","@sous-io/plugin-skills":"workspace:*","@sous-io/plugin-memories":"workspace:*","@sous-io/plugin-harnesses":"workspace:*","@sous-io/plugin-host":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*"},engines:{node:">=22"}};var PLUGIN_NAME28="@sous-io/plugin-claude-code",claudeCodePlugin=definePlugin29({name:PLUGIN_NAME28,version:package_default29.version,description:"Everything sous knows about Claude Code: its harness, skill-target and memory-target entities.",dependsOn:{"@sous-io/plugin-skills":`^${package_default29.version}`,"@sous-io/plugin-memories":`^${package_default29.version}`,"@sous-io/plugin-harnesses":`^${package_default29.version}`,"@sous-io/plugin-host":`^${package_default29.version}`},register(sous){sous.entities.add("harness",claudeHarness),sous.config.contribute(targetsContributor2)}});var package_default30={name:"@sous-io/sous",version:"1.0.12",description:"Compiles AI coding agent configuration (CLAUDE.md, skills, memories) from LiquidJS templates",type:"module",license:"Apache-2.0",author:"Luke Chavers",repository:{type:"git",url:"git+https://github.com/sous-io/sous.git",directory:"packages/sous"},homepage:"https://sous.io",bugs:"https://github.com/sous-io/sous/issues",keywords:["cli","ai","agents","claude","claude-code","codex","prompts","skills","templates","liquidjs"],publishConfig:{access:"public"},bin:{sous:"./dist/bin.js"},files:["dist/bin.js","dist/sous.js","dist/tiktoken_bg.wasm","recipes","docs/markdown/*.md","sous.config.schema.json"],scripts:{test:"vitest run",typecheck:"tsc --noEmit -p .",build:"node scripts/bundle.mjs",prepack:"node scripts/bundle.mjs && node scripts/pack-files.mjs copy",postpack:"node scripts/pack-files.mjs clean"},dependencies:{"@sous-io/plugin-api":"workspace:*"},devDependencies:{"@sous-io/core":"workspace:*","@sous-io/documents":"workspace:*","@sous-io/plugin-authoring":"workspace:*","@sous-io/plugin-build":"workspace:*","@sous-io/plugin-claude-code":"workspace:*","@sous-io/plugin-cli":"workspace:*","@sous-io/plugin-compiler":"workspace:*","@sous-io/plugin-confd":"workspace:*","@sous-io/plugin-config-files":"workspace:*","@sous-io/plugin-expressions":"workspace:*","@sous-io/plugin-formats":"workspace:*","@sous-io/plugin-git":"workspace:*","@sous-io/plugin-github":"workspace:*","@sous-io/plugin-gitlab":"workspace:*","@sous-io/plugin-harnesses":"workspace:*","@sous-io/plugin-host":"workspace:*","@sous-io/plugin-init":"workspace:*","@sous-io/plugin-inspect":"workspace:*","@sous-io/plugin-liquid":"workspace:*","@sous-io/plugin-local":"workspace:*","@sous-io/plugin-mcp":"workspace:*","@sous-io/plugin-memories":"workspace:*","@sous-io/plugin-npm":"workspace:*","@sous-io/plugin-pnpm":"workspace:*","@sous-io/plugin-recipe-answers":"workspace:*","@sous-io/plugin-recipes":"workspace:*","@sous-io/plugin-refs":"workspace:*","@sous-io/plugin-skills":"workspace:*","@sous-io/plugin-update":"workspace:*","@sous-io/plugin-variables":"workspace:*","@sous-io/plugin-yarn":"workspace:*",esbuild:"^0.27.4","jsonc-parser":"^3.3.1",yaml:"^2.9.0",zod:"^4.4.3"},engines:{node:">=22"}};var envPluginsPlugin=definePlugin30({name:"@sous-io/sous",version:package_default30.version,description:"Loads the plugins named in SOUS_PLUGINS.",register(sous){sous.config.contribute({id:"sous/env-plugins",contribute(config2){let listed2=(config2.env.SOUS_PLUGINS??"").split(",").map(item=>item.trim()).filter(item=>item!=="");for(let specifier of listed2)config2.atPath("plugins.load").append(specifier)}})}}),BUILT_IN_PLUGINS=[hostPlugin,gitPlugin,refsPlugin,variablesPlugin,liquidPlugin,formatsPlugin,expressionsPlugin,configFilesPlugin,confdPlugin,compilerPlugin,recipesPlugin,recipeAnswersPlugin,skillsPlugin,memoriesPlugin,buildPlugin,harnessesPlugin,authoringPlugin,initPlugin,updatePlugin,cliPlugin,inspectPlugin,mcpPlugin,npmPlugin,pnpmPlugin,yarnPlugin,githubPlugin,gitlabPlugin,localPlugin,claudeCodePlugin,envPluginsPlugin];import{existsSync as existsSync6,statSync as statSync3}from"node:fs";import path100 from"node:path";var CONFIG_FILE_NAMES=["sous.config.ts","sous.config.mts","sous.config.js","sous.config.mjs","sous.config.jsonc","sous.config.json","sous.config.yaml","sous.config.yml"];function findProject(cwd,confDir){for(let dir=path100.resolve(cwd);;dir=path100.dirname(dir)){let sousDir=path100.join(dir,".sous"),configPath=isDirectory5(sousDir)?configIn(sousDir):void 0;if(configPath!==void 0)return projectAt(sousDir,configPath,confDir);if(path100.dirname(dir)===dir)return}}function readOverrides(argv2,env,cwd){let flags=readFlags(argv2,["config","c","sous-config","sous-dir","sous-confd"]),chosen=[[flags.config??flags.c,flags.c!==void 0&&flags.config===void 0?"-c":"--config"],[flags["sous-config"],"--sous-config"],[blank(env.SOUS_CONFIG),"SOUS_CONFIG"],[flags["sous-dir"],"--sous-dir"],[blank(env.SOUS_DIR),"SOUS_DIR"]].find(([value])=>value!==void 0),confd=flags["sous-confd"]??blank(env.SOUS_CONFD);return{config:chosen===void 0?void 0:{value:resolvePath(chosen[0],cwd,env),source:chosen[1]},confDir:confd===void 0?void 0:resolvePath(confd,cwd,env)}}function locateProject(cwd,overrides){if(overrides.config===void 0)return findProject(cwd,overrides.confDir);let{value,source}=overrides.config;if(!existsSync6(value))throw new Error(`${source} path not found: ${value}`);if(!isDirectory5(value))return projectAt(path100.dirname(value),value,overrides.confDir);let direct=configIn(value);if(direct!==void 0)return projectAt(value,direct,overrides.confDir);let nested=path100.join(value,".sous"),nestedConfig=isDirectory5(nested)?configIn(nested):void 0;if(nestedConfig!==void 0)return projectAt(nested,nestedConfig,overrides.confDir);throw new Error(`${source} points at a directory with no sous config file: ${value}
1091
1092
  Looked for: ${CONFIG_FILE_NAMES.join(", ")}`)}function projectAt(sousDir,configPath,confDir){return{root:path100.dirname(sousDir),sousDir,configPath,confDir:confDir??path100.join(sousDir,"conf.d")}}function configIn(sousDir){let name=CONFIG_FILE_NAMES.find(candidate=>isFile10(path100.join(sousDir,candidate)));return name===void 0?void 0:path100.join(sousDir,name)}function readFlags(argv2,names2){let found={};for(let i=0;i<argv2.length;i++){let arg=argv2[i];if(arg==="--")break;for(let name of names2){let flag=name.length===1?`-${name}`:`--${name}`;found[name]===void 0&&(arg===flag?found[name]=blank(argv2[i+1]):arg.startsWith(`${flag}=`)?found[name]=blank(arg.slice(flag.length+1)):name.length===1&&arg.startsWith(flag)&&arg.length>2&&!arg.startsWith(`${flag}-`)&&(found[name]=blank(arg.slice(2))))}}return found}function blank(value){return value===void 0||value.trim()===""?void 0:value}function resolvePath(value,cwd,env){let home=env.HOME;return home!==void 0&&(value==="~"||value.startsWith("~/"))?path100.join(home,value.slice(1)):path100.resolve(cwd,value)}function isDirectory5(file2){try{return statSync3(file2).isDirectory()}catch{return!1}}function isFile10(file2){try{return statSync3(file2).isFile()}catch{return!1}}import{createHash as createHash7}from"node:crypto";import{existsSync as existsSync7,mkdirSync,readdirSync,readFileSync as readFileSync4,statSync as statSync4,writeFileSync}from"node:fs";import path101 from"node:path";var STARTUP_FACT_FILENAME="sous.startup.json",IGNORED_FILES=new Set([STARTUP_FACT_FILENAME,"sous.state.json","sous.pid"]),IGNORED_HOME_DIRECTORIES=new Set(["cache","repos"]);function factFile(project,env){let name=project===void 0?"no-project":createHash7("sha256").update(project.sousDir).digest("hex").slice(0,16);return path101.join(resolveSousHomePaths(env).root,"cache","startup",`${name}.json`)}function signature(file2){try{let stats=statSync4(file2);return`${file2} ${stats.size} ${stats.mtimeMs}`}catch{return`${file2} -`}}function signaturesIn(directory,recurse,skip=new Set){let entries;try{entries=readdirSync(directory,{withFileTypes:!0})}catch{return[]}let lines3=[];for(let entry of entries){let full=path101.join(directory,entry.name);entry.isDirectory()?recurse&&!skip.has(entry.name)&&lines3.push(...signaturesIn(full,!0)):IGNORED_FILES.has(entry.name)||lines3.push(signature(full))}return lines3}function startupKey(project,env,version2,bundle){let lines3=[version2,signature(bundle),JSON.stringify(project??null)];for(let name of Object.keys(env).sort())name.startsWith("SOUS_")&&lines3.push(`${name}=${env[name]}`);project!==void 0&&(lines3.push(...signaturesIn(project.sousDir,!1)),lines3.push(...signaturesIn(project.confDir,!0)),project.configPath!==void 0&&lines3.push(signature(project.configPath)));let home=resolveSousHomePaths(env).root;return lines3.push(...signaturesIn(home,!0,IGNORED_HOME_DIRECTORIES)),createHash7("sha1").update(lines3.sort().join(`
1092
1093
  `)).digest("hex")}function readFact(file2){try{let parsed=JSON.parse(readFileSync4(file2,"utf8"));return typeof parsed.key=="string"&&typeof parsed.builtInsOnly=="boolean"?{key:parsed.key,builtInsOnly:parsed.builtInsOnly}:void 0}catch{return}}function loadsOnlyBuiltIns(project,env,key){let fact=readFact(factFile(project,env));return fact!==void 0&&fact.key===key&&fact.builtInsOnly}function recordStartupFact(project,env,key,builtInsOnly){let file2=factFile(project,env),previous=readFact(file2);if(!(previous?.key===key&&previous.builtInsOnly===builtInsOnly))try{if(!existsSync7(resolveSousHomePaths(env).root))return;mkdirSync(path101.dirname(file2),{recursive:!0}),writeFileSync(file2,`${JSON.stringify({key,builtInsOnly})}
1093
- `,"utf8")}catch{}}function sousVersion(){try{let manifest=JSON.parse(readFileSync5(new URL("../package.json",import.meta.url),"utf8"));if(manifest.name==="@sous-io/sous"&&typeof manifest.version=="string")return manifest.version}catch{}return"1.0.11"}async function main(argv2,options){let overrides=readOverrides(argv2,options.env,options.cwd),project;try{project=locateProject(options.cwd,overrides)}catch(error51){options.stderr.write(`Error: ${error51 instanceof Error?error51.message:String(error51)}
1094
+ `,"utf8")}catch{}}function sousVersion(){try{let manifest=JSON.parse(readFileSync5(new URL("../package.json",import.meta.url),"utf8"));if(manifest.name==="@sous-io/sous"&&typeof manifest.version=="string")return manifest.version}catch{}return"1.0.12"}async function main(argv2,options){let overrides=readOverrides(argv2,options.env,options.cwd),project;try{project=locateProject(options.cwd,overrides)}catch(error51){options.stderr.write(`Error: ${error51 instanceof Error?error51.message:String(error51)}
1094
1095
  `),options.setExitCode(1);return}let engine=createEngine({project,env:projectEnvironment(project,options.env),cwd:options.cwd,app:{name:"sous",version:sousVersion()},builtIns:BUILT_IN_PLUGINS,budgets:budgetsOff(options.env.SOUS_BUDGETS)?noBudgets():void 0,locateProject:directory=>findProject(directory,overrides.confDir)}),key=startupKey(project,options.env,sousVersion(),fileURLToPath4(import.meta.url)),quiet=!1;if(await engine.loadBuiltInsOnly(),hasFrontEnd(engine,"cli")&&!engine.frontEnd("cli").needsConfig(argv2)){if(loadsOnlyBuiltIns(project,options.env,key)){await engine.frontEnd("cli").start(argv2),await engine.whenBackgroundIntentsReturn();return}quiet=!0}try{await engine.buildConfig(quiet?{reportBudgets:!1}:{}),recordStartupFact(project,options.env,key,engine.pluginInfo().every(plugin=>plugin.builtIn))}catch(error51){if(hasFrontEnd(engine,"cli")){await engine.frontEnd("cli").start(argv2),await engine.whenBackgroundIntentsReturn();return}let message2=error51 instanceof Error?error51.message:String(error51),details=isSousError6(error51)?error51.details.map(line=>`
1095
1096
  ${line}`).join(""):"";options.stderr.write(`Error: ${message2}${details}
1096
1097
  `),options.setExitCode(isSousError6(error51)?error51.exitCode:1);return}await engine.frontEnd("cli").start(argv2),await engine.whenBackgroundIntentsReturn()}function budgetsOff(value){return["0","false","no","off"].includes((value??"").trim().toLowerCase())}function noBudgets(){return Object.fromEntries(Object.keys(DEFAULT_BUDGETS).map(category=>[category,!1]))}function hasFrontEnd(engine,id){try{return engine.frontEnd(id),!0}catch{return!1}}var argv=process.argv.slice(2),ownRoot=path102.resolve(path102.dirname(fileURLToPath5(import.meta.url)),".."),handedOff=await handOffToProjectInstall({ownRoot,cwd:process.cwd(),env:process.env,argv,stderr:process.stderr});handedOff||await main(argv,{cwd:process.cwd(),env:process.env,stderr:process.stderr,setExitCode(code){process.exitCode=code}});