@automagik/genie 4.260424.4 → 4.260424.6
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/genie.js +9 -9
- package/package.json +1 -1
- package/plugins/genie/.claude-plugin/plugin.json +1 -1
- package/plugins/genie/package.json +1 -1
- package/scripts/sec-scan.cjs +262 -107
package/dist/genie.js
CHANGED
|
@@ -21,7 +21,7 @@ Expecting one of '${allowedValues.join("', '")}'`);if(this._lifeCycleHooks[event
|
|
|
21
21
|
`),this.outputHelp({error:!0});let config=errorOptions||{},exitCode=config.exitCode||1,code=config.code||"commander.error";this._exit(exitCode,code,message)}_parseOptionsEnv(){this.options.forEach((option)=>{if(option.envVar&&option.envVar in process2.env){let optionKey=option.attributeName();if(this.getOptionValue(optionKey)===void 0||["default","config","env"].includes(this.getOptionValueSource(optionKey)))if(option.required||option.optional)this.emit(`optionEnv:${option.name()}`,process2.env[option.envVar]);else this.emit(`optionEnv:${option.name()}`)}})}_parseOptionsImplied(){let dualHelper=new DualOptions(this.options),hasCustomOptionValue=(optionKey)=>{return this.getOptionValue(optionKey)!==void 0&&!["default","implied"].includes(this.getOptionValueSource(optionKey))};this.options.filter((option)=>option.implied!==void 0&&hasCustomOptionValue(option.attributeName())&&dualHelper.valueFromOption(this.getOptionValue(option.attributeName()),option)).forEach((option)=>{Object.keys(option.implied).filter((impliedKey)=>!hasCustomOptionValue(impliedKey)).forEach((impliedKey)=>{this.setOptionValueWithSource(impliedKey,option.implied[impliedKey],"implied")})})}missingArgument(name){let message=`error: missing required argument '${name}'`;this.error(message,{code:"commander.missingArgument"})}optionMissingArgument(option){let message=`error: option '${option.flags}' argument missing`;this.error(message,{code:"commander.optionMissingArgument"})}missingMandatoryOptionValue(option){let message=`error: required option '${option.flags}' not specified`;this.error(message,{code:"commander.missingMandatoryOptionValue"})}_conflictingOption(option,conflictingOption){let findBestOptionFromValue=(option2)=>{let optionKey=option2.attributeName(),optionValue=this.getOptionValue(optionKey),negativeOption=this.options.find((target)=>target.negate&&optionKey===target.attributeName()),positiveOption=this.options.find((target)=>!target.negate&&optionKey===target.attributeName());if(negativeOption&&(negativeOption.presetArg===void 0&&optionValue===!1||negativeOption.presetArg!==void 0&&optionValue===negativeOption.presetArg))return negativeOption;return positiveOption||option2},getErrorMessage=(option2)=>{let bestOption=findBestOptionFromValue(option2),optionKey=bestOption.attributeName();if(this.getOptionValueSource(optionKey)==="env")return`environment variable '${bestOption.envVar}'`;return`option '${bestOption.flags}'`},message=`error: ${getErrorMessage(option)} cannot be used with ${getErrorMessage(conflictingOption)}`;this.error(message,{code:"commander.conflictingOption"})}unknownOption(flag){if(this._allowUnknownOption)return;let suggestion="";if(flag.startsWith("--")&&this._showSuggestionAfterError){let candidateFlags=[],command=this;do{let moreFlags=command.createHelp().visibleOptions(command).filter((option)=>option.long).map((option)=>option.long);candidateFlags=candidateFlags.concat(moreFlags),command=command.parent}while(command&&!command._enablePositionalOptions);suggestion=suggestSimilar(flag,candidateFlags)}let message=`error: unknown option '${flag}'${suggestion}`;this.error(message,{code:"commander.unknownOption"})}_excessArguments(receivedArgs){if(this._allowExcessArguments)return;let expected=this.registeredArguments.length,s=expected===1?"":"s",message=`error: too many arguments${this.parent?` for '${this.name()}'`:""}. Expected ${expected} argument${s} but got ${receivedArgs.length}.`;this.error(message,{code:"commander.excessArguments"})}unknownCommand(){let unknownName=this.args[0],suggestion="";if(this._showSuggestionAfterError){let candidateNames=[];this.createHelp().visibleCommands(this).forEach((command)=>{if(candidateNames.push(command.name()),command.alias())candidateNames.push(command.alias())}),suggestion=suggestSimilar(unknownName,candidateNames)}let message=`error: unknown command '${unknownName}'${suggestion}`;this.error(message,{code:"commander.unknownCommand"})}version(str,flags,description){if(str===void 0)return this._version;this._version=str,flags=flags||"-V, --version",description=description||"output the version number";let versionOption=this.createOption(flags,description);return this._versionOptionName=versionOption.attributeName(),this._registerOption(versionOption),this.on("option:"+versionOption.name(),()=>{this._outputConfiguration.writeOut(`${str}
|
|
22
22
|
`),this._exit(0,"commander.version",str)}),this}description(str,argsDescription){if(str===void 0&&argsDescription===void 0)return this._description;if(this._description=str,argsDescription)this._argsDescription=argsDescription;return this}summary(str){if(str===void 0)return this._summary;return this._summary=str,this}alias(alias){if(alias===void 0)return this._aliases[0];let command=this;if(this.commands.length!==0&&this.commands[this.commands.length-1]._executableHandler)command=this.commands[this.commands.length-1];if(alias===command._name)throw Error("Command alias can't be the same as its name");let matchingCommand=this.parent?._findCommand(alias);if(matchingCommand){let existingCmd=[matchingCommand.name()].concat(matchingCommand.aliases()).join("|");throw Error(`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`)}return command._aliases.push(alias),this}aliases(aliases){if(aliases===void 0)return this._aliases;return aliases.forEach((alias)=>this.alias(alias)),this}usage(str){if(str===void 0){if(this._usage)return this._usage;let args=this.registeredArguments.map((arg)=>{return humanReadableArgName(arg)});return[].concat(this.options.length||this._helpOption!==null?"[options]":[],this.commands.length?"[command]":[],this.registeredArguments.length?args:[]).join(" ")}return this._usage=str,this}name(str){if(str===void 0)return this._name;return this._name=str,this}nameFromFilename(filename){return this._name=path.basename(filename,path.extname(filename)),this}executableDir(path2){if(path2===void 0)return this._executableDir;return this._executableDir=path2,this}helpInformation(contextOptions){let helper=this.createHelp();if(helper.helpWidth===void 0)helper.helpWidth=contextOptions&&contextOptions.error?this._outputConfiguration.getErrHelpWidth():this._outputConfiguration.getOutHelpWidth();return helper.formatHelp(this,helper)}_getHelpContext(contextOptions){contextOptions=contextOptions||{};let context={error:!!contextOptions.error},write;if(context.error)write=(arg)=>this._outputConfiguration.writeErr(arg);else write=(arg)=>this._outputConfiguration.writeOut(arg);return context.write=contextOptions.write||write,context.command=this,context}outputHelp(contextOptions){let deprecatedCallback;if(typeof contextOptions==="function")deprecatedCallback=contextOptions,contextOptions=void 0;let context=this._getHelpContext(contextOptions);this._getCommandAndAncestors().reverse().forEach((command)=>command.emit("beforeAllHelp",context)),this.emit("beforeHelp",context);let helpInformation=this.helpInformation(context);if(deprecatedCallback){if(helpInformation=deprecatedCallback(helpInformation),typeof helpInformation!=="string"&&!Buffer.isBuffer(helpInformation))throw Error("outputHelp callback must return a string or a Buffer")}if(context.write(helpInformation),this._getHelpOption()?.long)this.emit(this._getHelpOption().long);this.emit("afterHelp",context),this._getCommandAndAncestors().forEach((command)=>command.emit("afterAllHelp",context))}helpOption(flags,description){if(typeof flags==="boolean"){if(flags)this._helpOption=this._helpOption??void 0;else this._helpOption=null;return this}return flags=flags??"-h, --help",description=description??"display help for command",this._helpOption=this.createOption(flags,description),this}_getHelpOption(){if(this._helpOption===void 0)this.helpOption(void 0,void 0);return this._helpOption}addHelpOption(option){return this._helpOption=option,this}help(contextOptions){this.outputHelp(contextOptions);let exitCode=process2.exitCode||0;if(exitCode===0&&contextOptions&&typeof contextOptions!=="function"&&contextOptions.error)exitCode=1;this._exit(exitCode,"commander.help","(outputHelp)")}addHelpText(position,text){let allowedValues=["beforeAll","before","after","afterAll"];if(!allowedValues.includes(position))throw Error(`Unexpected value for position to addHelpText.
|
|
23
23
|
Expecting one of '${allowedValues.join("', '")}'`);let helpEvent=`${position}Help`;return this.on(helpEvent,(context)=>{let helpStr;if(typeof text==="function")helpStr=text({error:context.error,command:context.command});else helpStr=text;if(helpStr)context.write(`${helpStr}
|
|
24
|
-
`)}),this}_outputHelpIfRequested(args){let helpOption=this._getHelpOption();if(helpOption&&args.find((arg)=>helpOption.is(arg)))this.outputHelp(),this._exit(0,"commander.helpDisplayed","(outputHelp)")}}function incrementNodeInspectorPort(args){return args.map((arg)=>{if(!arg.startsWith("--inspect"))return arg;let debugOption,debugHost="127.0.0.1",debugPort="9229",match;if((match=arg.match(/^(--inspect(-brk)?)$/))!==null)debugOption=match[1];else if((match=arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/))!==null)if(debugOption=match[1],/^\d+$/.test(match[3]))debugPort=match[3];else debugHost=match[3];else if((match=arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/))!==null)debugOption=match[1],debugHost=match[3],debugPort=match[4];if(debugOption&&debugPort!=="0")return`${debugOption}=${debugHost}:${parseInt(debugPort)+1}`;return arg})}exports.Command=Command});var require_commander=__commonJS((exports)=>{var{Argument}=require_argument(),{Command}=require_command(),{CommanderError,InvalidArgumentError}=require_error(),{Help}=require_help(),{Option}=require_option();exports.program=new Command;exports.createCommand=(name)=>new Command(name);exports.createOption=(flags,description)=>new Option(flags,description);exports.createArgument=(name,description)=>new Argument(name,description);exports.Command=Command;exports.Option=Option;exports.Argument=Argument;exports.Help=Help;exports.CommanderError=CommanderError;exports.InvalidArgumentError=InvalidArgumentError;exports.InvalidOptionArgumentError=InvalidArgumentError});import{existsSync,mkdirSync,readFileSync,unlinkSync,writeFileSync}from"fs";import{homedir}from"os";import{join}from"path";function getClaudeSettingsPath(){return CLAUDE_SETTINGS_FILE}function getGenieHookScriptPath(){return join(CLAUDE_HOOKS_DIR,GENIE_HOOK_SCRIPT_NAME)}function hookScriptExists(){return existsSync(getGenieHookScriptPath())}function removeHookScript(){let scriptPath=getGenieHookScriptPath();if(existsSync(scriptPath))unlinkSync(scriptPath)}function
|
|
24
|
+
`)}),this}_outputHelpIfRequested(args){let helpOption=this._getHelpOption();if(helpOption&&args.find((arg)=>helpOption.is(arg)))this.outputHelp(),this._exit(0,"commander.helpDisplayed","(outputHelp)")}}function incrementNodeInspectorPort(args){return args.map((arg)=>{if(!arg.startsWith("--inspect"))return arg;let debugOption,debugHost="127.0.0.1",debugPort="9229",match;if((match=arg.match(/^(--inspect(-brk)?)$/))!==null)debugOption=match[1];else if((match=arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/))!==null)if(debugOption=match[1],/^\d+$/.test(match[3]))debugPort=match[3];else debugHost=match[3];else if((match=arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/))!==null)debugOption=match[1],debugHost=match[3],debugPort=match[4];if(debugOption&&debugPort!=="0")return`${debugOption}=${debugHost}:${parseInt(debugPort)+1}`;return arg})}exports.Command=Command});var require_commander=__commonJS((exports)=>{var{Argument}=require_argument(),{Command}=require_command(),{CommanderError,InvalidArgumentError}=require_error(),{Help}=require_help(),{Option}=require_option();exports.program=new Command;exports.createCommand=(name)=>new Command(name);exports.createOption=(flags,description)=>new Option(flags,description);exports.createArgument=(name,description)=>new Argument(name,description);exports.Command=Command;exports.Option=Option;exports.Argument=Argument;exports.Help=Help;exports.CommanderError=CommanderError;exports.InvalidArgumentError=InvalidArgumentError;exports.InvalidOptionArgumentError=InvalidArgumentError});import{existsSync,mkdirSync,readFileSync,unlinkSync,writeFileSync}from"fs";import{homedir}from"os";import{join}from"path";function getClaudeSettingsPath(){return CLAUDE_SETTINGS_FILE}function getGenieHookScriptPath(){return join(CLAUDE_HOOKS_DIR,GENIE_HOOK_SCRIPT_NAME)}function hookScriptExists(){return existsSync(getGenieHookScriptPath())}function removeHookScript(){let scriptPath=getGenieHookScriptPath();if(existsSync(scriptPath))unlinkSync(scriptPath)}function ensureClaudeSettingsSafe(){let dir=join(homedir(),".claude");if(!existsSync(dir))mkdirSync(dir,{recursive:!0});let settings={};if(existsSync(CLAUDE_SETTINGS_FILE))try{settings=JSON.parse(readFileSync(CLAUDE_SETTINGS_FILE,"utf-8"))}catch{}let validTopologyValues=new Set(["auto","tmux","in-process"]),changed=!1;if("teammateMode"in settings&&!validTopologyValues.has(settings.teammateMode)){let{teammateMode:_removed,...rest}=settings;settings=rest,changed=!0}if(settings.skipDangerousModePermissionPrompt!==!0)settings.skipDangerousModePermissionPrompt=!0,changed=!0;if(changed)writeFileSync(CLAUDE_SETTINGS_FILE,`${JSON.stringify(settings,null,2)}
|
|
25
25
|
`,"utf-8")}function contractClaudePath(path){let home=homedir();if(path.startsWith(`${home}/`))return`~${path.slice(home.length)}`;if(path===home)return"~";return path}var CLAUDE_DIR,CLAUDE_HOOKS_DIR,CLAUDE_SETTINGS_FILE,GENIE_HOOK_SCRIPT_NAME="genie-bash-hook.sh";var init_claude_settings=__esm(()=>{CLAUDE_DIR=join(homedir(),".claude"),CLAUDE_HOOKS_DIR=join(CLAUDE_DIR,"hooks"),CLAUDE_SETTINGS_FILE=join(CLAUDE_DIR,"settings.json")});var exports_ensure_tmux={};__export(exports_ensure_tmux,{tmuxBin:()=>tmuxBin,ensureTmux:()=>ensureTmux});import{execSync}from"child_process";import{chmodSync,copyFileSync,existsSync as existsSync2,mkdirSync as mkdirSync2,rmSync,unlinkSync as unlinkSync2,writeFileSync as writeFileSync2}from"fs";import{arch,homedir as homedir2,platform,tmpdir}from"os";import{join as join2}from"path";function getPlatformAsset(){let os=platform(),cpu=arch(),key=`${os}-${cpu}`,asset={"linux-x64":`tmux-${TMUX_VERSION}-linux-x86_64.tar.gz`,"linux-arm64":`tmux-${TMUX_VERSION}-linux-arm64.tar.gz`,"darwin-arm64":`tmux-${TMUX_VERSION}-macos-arm64.tar.gz`,"darwin-x64":`tmux-${TMUX_VERSION}-macos-x86_64.tar.gz`}[key];if(!asset)throw Error(`Unsupported platform: ${key}
|
|
26
26
|
tmux auto-download supports: linux-x64, linux-arm64, macos-arm64, macos-x64.
|
|
27
27
|
Install tmux manually: https://github.com/tmux/tmux/wiki/Installing`);return asset}function genieHome(){return process.env.GENIE_HOME??join2(homedir2(),".genie")}function genieBinDir(){return join2(genieHome(),"bin")}function cachedTmuxPath(){return join2(genieBinDir(),"tmux")}function tmuxBin(){if(_resolved)return _resolved;try{let p=execSync("which tmux",{encoding:"utf-8",stdio:["pipe","pipe","ignore"]}).trim();if(p)return _resolved=p,p}catch{}let cached=cachedTmuxPath();if(existsSync2(cached))return _resolved=cached,cached;return"tmux"}async function ensureTmux(){let bin=tmuxBin();if(bin!=="tmux")return bin;return downloadTmux()}async function downloadTmux(){let asset=getPlatformAsset(),url=process.env.GENIE_TMUX_URL??`https://github.com/tmux/tmux-builds/releases/download/v${TMUX_VERSION}/${asset}`,dest=cachedTmuxPath(),tempDir=join2(tmpdir(),`genie-tmux-download-${Date.now()}`);console.log(" tmux not found \u2014 downloading static binary..."),console.log(` ${url}`);try{let response=await fetch(url);if(!response.ok)throw Error(`HTTP ${response.status} ${response.statusText}`);let buffer=Buffer.from(await response.arrayBuffer()),sizeMB=(buffer.byteLength/1024/1024).toFixed(1);console.log(` Downloaded ${sizeMB} MB`),mkdirSync2(tempDir,{recursive:!0});let tarballPath=join2(tempDir,asset);writeFileSync2(tarballPath,buffer),execSync(`tar -xzf '${tarballPath}' -C '${tempDir}'`,{stdio:"ignore"});let extractedBin=join2(tempDir,"tmux");if(!existsSync2(extractedBin))throw Error("Tarball did not contain a tmux binary");mkdirSync2(genieBinDir(),{recursive:!0}),copyFileSync(extractedBin,dest),chmodSync(dest,493);let version=execSync(`'${dest}' -V`,{encoding:"utf-8",stdio:["pipe","pipe","ignore"]}).trim();return _resolved=dest,console.log(` ${version} installed to ${dest}`),dest}catch(err){try{if(existsSync2(dest))unlinkSync2(dest)}catch{}let msg=err instanceof Error?err.message:String(err);throw Error(`Failed to download tmux: ${msg}
|
|
@@ -44,11 +44,11 @@ ${issues}`)}}function migrateWorkspaceConfig(raw){let config={...raw};if("tmuxSo
|
|
|
44
44
|
`,appliedSet=new Set(applied.map((r)=>r.name)),pending=files.filter((f)=>!appliedSet.has(f.name)),results=[];for(let migration of pending)await sql.begin(async(tx)=>{await tx.unsafe(migration.sql),await tx.unsafe("INSERT INTO _genie_migrations (name) VALUES ($1)",[migration.name])}),results.push({name:migration.name,applied_at:new Date().toISOString()});return results}async function getMigrationStatus(sql){await ensureMigrationsTable(sql);let files=await loadMigrationFiles(),applied=await sql`
|
|
45
45
|
SELECT name, applied_at FROM _genie_migrations ORDER BY name
|
|
46
46
|
`,appliedMap=new Map(applied.map((r)=>[r.name,r.applied_at.toISOString()])),appliedRecords=[],pendingRecords=[];for(let file of files){let appliedAt=appliedMap.get(file.name);if(appliedAt)appliedRecords.push({name:file.name,applied_at:appliedAt});else pendingRecords.push({name:file.name,applied_at:null})}return{applied:appliedRecords,pending:pendingRecords}}var init_db_migrations=()=>{};import{readFile,unlink,writeFile}from"fs/promises";function lockPath(filePath){return`${filePath}.lock`}function isPidAlive(pid){try{return process.kill(pid,0),!0}catch{return!1}}async function acquireLock(path){let lock=lockPath(path),deadline=Date.now()+LOCK_TIMEOUT_MS;while(Date.now()<deadline)try{await writeFile(lock,String(process.pid),{flag:"wx"});return}catch{try{let content=await readFile(lock,"utf-8"),holderPid=Number.parseInt(content.trim(),10);if(!Number.isNaN(holderPid)&&!isPidAlive(holderPid)){try{await unlink(lock)}catch{}continue}}catch{continue}let jitter=Math.floor(Math.random()*LOCK_POLL_MS);await new Promise((r)=>setTimeout(r,LOCK_POLL_MS+jitter))}console.warn(`[lockfile] Force-acquiring stale lock: ${lock}`),await writeFile(lock,String(process.pid))}async function releaseLock(path){try{await unlink(lockPath(path))}catch{}}var LOCK_TIMEOUT_MS=5000,LOCK_POLL_MS=50;var init_lockfile=()=>{};function isBlockingEvent(event){return BLOCKING_EVENTS.has(event)}var DISPATCHED_EVENTS,BLOCKING_EVENTS;var init_types2=__esm(()=>{DISPATCHED_EVENTS=["PreToolUse","PostToolUse","SessionStart","SessionEnd","TeammateIdle","TaskCompleted"],BLOCKING_EVENTS=new Set(["PreToolUse","UserPromptSubmit","TeammateIdle","TaskCompleted","PermissionRequest"])});var exports_inject={};__export(exports_inject,{isTeamHooked:()=>isTeamHooked,injectTeamHooks:()=>injectTeamHooks,buildDispatchCommand:()=>buildDispatchCommand});import{existsSync as existsSync6}from"fs";import{mkdir,readFile as readFile2,writeFile as writeFile2}from"fs/promises";import{homedir as homedir5}from"os";import{join as join7}from"path";import{fileURLToPath}from"url";function escapeShellArg(arg){return`'${arg.replace(/'/g,"'\\''")}'`}function buildDispatchCommand(){let entrypoint=fileURLToPath(new URL("../genie.ts",import.meta.url));if(!existsSync6(entrypoint))return"genie hook dispatch";let bun=process.execPath||"bun";return`${escapeShellArg(bun)} run ${escapeShellArg(entrypoint)} hook dispatch`}function isGenieDispatchCommand(command){return typeof command==="string"&&/(?:^|\s)hook\s+dispatch(?:\s|$)/.test(command)}function claudeConfigDir(){return process.env.CLAUDE_CONFIG_DIR??join7(homedir5(),".claude")}function teamSettingsPath(teamName){let sanitized=teamName.replace(/[^a-zA-Z0-9]/g,"-").toLowerCase();return join7(claudeConfigDir(),"teams",sanitized,"settings.json")}function buildHooksConfig(){let hooks={},dispatchCommand=buildDispatchCommand();for(let event of DISPATCHED_EVENTS)hooks[event]=[{matcher:"*",hooks:[{type:"command",command:dispatchCommand,timeout:DISPATCH_TIMEOUT}]}];return hooks}async function injectIntoFile(settingsPath){let settings={};if(existsSync6(settingsPath))try{let content=await readFile2(settingsPath,"utf-8");settings=JSON.parse(content)}catch{}let hooksConfig=buildHooksConfig(),existingHooks=settings.hooks;if(existingHooks){if(DISPATCHED_EVENTS.every((event)=>{let existing=existingHooks[event],desiredCommand=hooksConfig[event][0].hooks[0].command;return existing?.some((m)=>m.hooks?.some((h)=>h.command===desiredCommand))}))return!1}let mergedHooks=existingHooks?{...existingHooks}:{};for(let event of DISPATCHED_EVENTS){let genieEntry=hooksConfig[event][0],existingEntries=(mergedHooks[event]??[]).map((matcher)=>({...matcher,hooks:matcher.hooks?.map((hook)=>isGenieDispatchCommand(hook.command)?{...hook,command:genieEntry.hooks[0].command,timeout:DISPATCH_TIMEOUT}:hook)}));if(!existingEntries.some((m)=>m.hooks?.some((h)=>isGenieDispatchCommand(h.command))))mergedHooks[event]=[...existingEntries,genieEntry];else mergedHooks[event]=existingEntries}settings.hooks=mergedHooks;let dir=join7(settingsPath,"..");return await mkdir(dir,{recursive:!0}),await writeFile2(settingsPath,JSON.stringify(settings,null,2)),!0}async function injectTeamHooks(teamName){let path=teamSettingsPath(teamName);return injectIntoFile(path)}async function isTeamHooked(teamName){let path=teamSettingsPath(teamName);if(!existsSync6(path))return!1;try{let content=await readFile2(path,"utf-8"),hooks=JSON.parse(content).hooks;if(!hooks)return!1;return DISPATCHED_EVENTS.every((event)=>{return hooks[event]?.some((m)=>m.hooks?.some((h)=>isGenieDispatchCommand(h.command)))})}catch{return!1}}var DISPATCH_TIMEOUT=15;var init_inject=__esm(()=>{init_types2()});var exports_trace_context={};__export(exports_trace_context,{setAmbient:()=>setAmbient,propagateEnv:()=>propagateEnv,parseToken:()=>parseToken,newTraceId:()=>newTraceId,newSpanId:()=>newSpanId,mintToken:()=>mintToken,injectPromptPreamble:()=>injectPromptPreamble,getAmbient:()=>getAmbient,extractPromptPreamble:()=>extractPromptPreamble,adoptFromEnv:()=>adoptFromEnv,TRACE_SECRET_ENV_VAR:()=>TRACE_SECRET_ENV_VAR,TRACE_ID_ENV_VAR:()=>TRACE_ID_ENV_VAR,TRACE_ENV_VAR:()=>TRACE_ENV_VAR,TOKEN_MAX_AGE_MS:()=>TOKEN_MAX_AGE_MS,PREAMBLE_SUFFIX:()=>PREAMBLE_SUFFIX,PREAMBLE_PREFIX:()=>PREAMBLE_PREFIX});import{createHmac,randomBytes,timingSafeEqual}from"crypto";function getSecret(){let raw=process.env[TRACE_SECRET_ENV_VAR];if(!raw||raw.length<16)return Buffer.from("genie-trace-fallback-secret-dev-only-do-not-ship","utf8");return Buffer.from(raw,"utf8")}function toBase64Url(buf){return(typeof buf==="string"?Buffer.from(buf,"utf8"):buf).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function fromBase64Url(s){let pad=s.length%4===0?"":"=".repeat(4-s.length%4);return Buffer.from(s.replace(/-/g,"+").replace(/_/g,"/")+pad,"base64")}function mintToken(ctx){let body={trace_id:ctx.trace_id,parent_span_id:ctx.parent_span_id,tenant_id:ctx.tenant_id,iat:Date.now(),nonce:randomBytes(6).toString("hex")},payloadB64=toBase64Url(JSON.stringify(body)),sig=createHmac("sha256",getSecret()).update(payloadB64).digest(),sigB64=toBase64Url(sig);return`${payloadB64}.${sigB64}`}function parseToken(token,now=Date.now()){if(!token||typeof token!=="string")return{ok:!1,reason:"malformed"};let dot=token.indexOf(".");if(dot<=0||dot===token.length-1)return{ok:!1,reason:"malformed"};let payloadB64=token.slice(0,dot),sigB64=token.slice(dot+1),expected=createHmac("sha256",getSecret()).update(payloadB64).digest(),provided;try{provided=fromBase64Url(sigB64)}catch{return{ok:!1,reason:"malformed"}}if(provided.length!==expected.length)return{ok:!1,reason:"signature"};if(!timingSafeEqual(provided,expected))return{ok:!1,reason:"signature"};let body;try{body=JSON.parse(fromBase64Url(payloadB64).toString("utf8"))}catch{return{ok:!1,reason:"malformed"}}if(!body||typeof body.trace_id!=="string"||typeof body.iat!=="number")return{ok:!1,reason:"malformed"};let age=now-body.iat;if(age>TOKEN_MAX_AGE_MS)return{ok:!1,reason:"expired"};if(age<-TOKEN_MAX_AGE_MS)return{ok:!1,reason:"future-dated"};return{ok:!0,ctx:{trace_id:body.trace_id,parent_span_id:body.parent_span_id,tenant_id:body.tenant_id}}}function adoptFromEnv(env=process.env){let token=env[TRACE_ENV_VAR];if(token){let parsed=parseToken(token);if(parsed.ok&&parsed.ctx)return ambient=parsed.ctx,parsed.ctx}let legacyId=env[TRACE_ID_ENV_VAR];if(legacyId&&/^[a-f0-9-]{8,64}$/i.test(legacyId))return ambient={trace_id:legacyId.replace(/-/g,"").toLowerCase()},ambient;return null}function setAmbient(ctx){ambient=ctx}function getAmbient(){return ambient}function propagateEnv(ctx=ambient,base=process.env){let out={};for(let[k,v]of Object.entries(base))if(typeof v==="string")out[k]=v;if(!ctx)return out;return out[TRACE_ENV_VAR]=mintToken(ctx),out[TRACE_ID_ENV_VAR]=ctx.trace_id,out}function injectPromptPreamble(prompt,ctx=ambient){if(!ctx)return prompt;if(PREAMBLE_REGEX.test(prompt))return prompt;return`<genie-trace token="${mintToken(ctx)}" />
|
|
47
|
-
${prompt}`}function extractPromptPreamble(input){let match=input.match(PREAMBLE_REGEX);if(!match)return{ctx:null,rest:input};let parsed=parseToken(match[1]);if(!parsed.ok||!parsed.ctx)return{ctx:null,rest:input.slice(match[0].length)};return{ctx:parsed.ctx,rest:input.slice(match[0].length)}}function newTraceId(){return randomBytes(16).toString("hex")}function newSpanId(){return randomBytes(8).toString("hex")}var TRACE_ENV_VAR="GENIE_TRACE_TOKEN",TRACE_ID_ENV_VAR="GENIE_TRACE_ID",TRACE_SECRET_ENV_VAR="GENIE_TRACE_SECRET",TOKEN_MAX_AGE_MS=3600000,PREAMBLE_PREFIX="<genie-trace",PREAMBLE_SUFFIX="/>",PREAMBLE_REGEX,ambient=null;var init_trace_context=__esm(()=>{PREAMBLE_REGEX=/^<genie-trace\s+token="([A-Za-z0-9_\-.]+)"\s*\/>\s*/});var exports_provider_adapters={};__export(exports_provider_adapters,{validateSpawnParams:()=>validateSpawnParams,buildLaunchCommand:()=>buildLaunchCommand,buildCodexCommand:()=>buildCodexCommand,buildClaudeCommand:()=>buildClaudeCommand,CLAUDE_TEAM_COLORS:()=>CLAUDE_TEAM_COLORS});function validateSpawnParams(params){return spawnParamsSchema.parse(params)}function escapeShellArg2(arg){return`'${arg.replace(/'/g,"'\\''")}'`}function hasBinary(name){try{let BunExt=Bun;if(typeof BunExt.which==="function")return Boolean(BunExt.which(name));let{execSync:execSync2}=__require("child_process");return execSync2(`which ${name}`,{stdio:"ignore"}),!0}catch{return!1}}function resolveShellBinary(name){try{let{execFileSync}=__require("child_process"),shell=process.env.SHELL||"/bin/sh";return execFileSync(shell,["-lc",`command -v ${name}`],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()||null}catch{return null}}function preflightCheck(provider){if(!hasBinary(provider))throw Error(`Provider binary "${provider}" not found on PATH. Install ${provider} or check your environment.`)}function appendNativeTeamFlags(parts,env,nt,params){env.CLAUDECODE="1",env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS="1";let agentName=nt.agentName??params.role??"worker";if(env.GENIE_AGENT_NAME=agentName,parts.push("--agent-id",escapeShellArg2(`${agentName}@${params.team}`)),parts.push("--agent-name",escapeShellArg2(agentName)),parts.push("--team-name",escapeShellArg2(params.team)),nt.color)parts.push("--agent-color",escapeShellArg2(nt.color));if(nt.parentSessionId)parts.push("--parent-session-id",escapeShellArg2(nt.parentSessionId));if(nt.agentType)parts.push("--agent-type",escapeShellArg2(nt.agentType));if(nt.planModeRequired)parts.push("--plan-mode-required");let effectivePermMode=nt.permissionMode??"
|
|
47
|
+
${prompt}`}function extractPromptPreamble(input){let match=input.match(PREAMBLE_REGEX);if(!match)return{ctx:null,rest:input};let parsed=parseToken(match[1]);if(!parsed.ok||!parsed.ctx)return{ctx:null,rest:input.slice(match[0].length)};return{ctx:parsed.ctx,rest:input.slice(match[0].length)}}function newTraceId(){return randomBytes(16).toString("hex")}function newSpanId(){return randomBytes(8).toString("hex")}var TRACE_ENV_VAR="GENIE_TRACE_TOKEN",TRACE_ID_ENV_VAR="GENIE_TRACE_ID",TRACE_SECRET_ENV_VAR="GENIE_TRACE_SECRET",TOKEN_MAX_AGE_MS=3600000,PREAMBLE_PREFIX="<genie-trace",PREAMBLE_SUFFIX="/>",PREAMBLE_REGEX,ambient=null;var init_trace_context=__esm(()=>{PREAMBLE_REGEX=/^<genie-trace\s+token="([A-Za-z0-9_\-.]+)"\s*\/>\s*/});var exports_provider_adapters={};__export(exports_provider_adapters,{validateSpawnParams:()=>validateSpawnParams,buildLaunchCommand:()=>buildLaunchCommand,buildCodexCommand:()=>buildCodexCommand,buildClaudeCommand:()=>buildClaudeCommand,CLAUDE_TEAM_COLORS:()=>CLAUDE_TEAM_COLORS});function validateSpawnParams(params){return spawnParamsSchema.parse(params)}function escapeShellArg2(arg){return`'${arg.replace(/'/g,"'\\''")}'`}function hasBinary(name){try{let BunExt=Bun;if(typeof BunExt.which==="function")return Boolean(BunExt.which(name));let{execSync:execSync2}=__require("child_process");return execSync2(`which ${name}`,{stdio:"ignore"}),!0}catch{return!1}}function resolveShellBinary(name){try{let{execFileSync}=__require("child_process"),shell=process.env.SHELL||"/bin/sh";return execFileSync(shell,["-lc",`command -v ${name}`],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()||null}catch{return null}}function preflightCheck(provider){if(!hasBinary(provider))throw Error(`Provider binary "${provider}" not found on PATH. Install ${provider} or check your environment.`)}function appendNativeTeamFlags(parts,env,nt,params){env.CLAUDECODE="1",env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS="1";let agentName=nt.agentName??params.role??"worker";if(env.GENIE_AGENT_NAME=agentName,parts.push("--agent-id",escapeShellArg2(`${agentName}@${params.team}`)),parts.push("--agent-name",escapeShellArg2(agentName)),parts.push("--team-name",escapeShellArg2(params.team)),nt.color)parts.push("--agent-color",escapeShellArg2(nt.color));if(nt.parentSessionId)parts.push("--parent-session-id",escapeShellArg2(nt.parentSessionId));if(nt.agentType)parts.push("--agent-type",escapeShellArg2(nt.agentType));if(nt.planModeRequired)parts.push("--plan-mode-required");let effectivePermMode=nt.permissionMode??"auto";parts.push("--permission-mode",escapeShellArg2(effectivePermMode))}function appendSystemPromptFlags(parts,params){if(params.systemPrompt){let{mkdirSync:mkdirSync5,writeFileSync:writeFileSync5,readFileSync:readFileSync5}=__require("fs"),{join:join8}=__require("path"),dir="/tmp/genie-prompts";mkdirSync5("/tmp/genie-prompts",{recursive:!0});let ts=Date.now().toString(36),promptFile=join8("/tmp/genie-prompts",`${params.role||"agent"}-${ts}.md`),content=params.systemPrompt;if(params.systemPromptFile)content=`${readFileSync5(params.systemPromptFile,"utf-8")}
|
|
48
48
|
|
|
49
49
|
${content}`;if(params.extraArgs){let fileIdx=params.extraArgs.indexOf("--append-system-prompt-file");if(fileIdx!==-1&¶ms.extraArgs[fileIdx+1])content=`${content}
|
|
50
50
|
|
|
51
|
-
${readFileSync5(params.extraArgs[fileIdx+1],"utf-8")}`,params.extraArgs.splice(fileIdx,2)}writeFileSync5(promptFile,content);let flag=params.promptMode==="system"?"--system-prompt-file":"--append-system-prompt-file";parts.push(flag,escapeShellArg2(promptFile))}else if(params.systemPromptFile){let flag=params.promptMode==="system"?"--system-prompt-file":"--append-system-prompt-file";parts.push(flag,escapeShellArg2(params.systemPromptFile))}}function appendOtelEnv(env,params){if(!params.otelPort||process.env.OTEL_EXPORTER_OTLP_ENDPOINT)return;if(env.CLAUDE_CODE_ENABLE_TELEMETRY="1",env.OTEL_LOGS_EXPORTER="otlp",env.OTEL_METRICS_EXPORTER="otlp",env.OTEL_EXPORTER_OTLP_PROTOCOL="http/json",env.OTEL_EXPORTER_OTLP_ENDPOINT=`http://127.0.0.1:${params.otelPort}`,env.OTEL_LOG_TOOL_DETAILS="1",params.otelLogPrompts!==!1)env.OTEL_LOG_USER_PROMPTS="1";let resourceParts=[];if(params.role)resourceParts.push(`agent.name=${params.role}`);if(params.team)resourceParts.push(`team.name=${params.team}`);if(params.otelWishSlug)resourceParts.push(`wish.slug=${params.otelWishSlug}`);if(params.role)resourceParts.push(`agent.role=${params.role}`);if(resourceParts.length>0)env.OTEL_RESOURCE_ATTRIBUTES=resourceParts.join(",")}function appendTraceContext(parts,env,params){let ctx=getAmbient();if(params.initialPrompt){let prompt=ctx?injectPromptPreamble(params.initialPrompt,ctx):params.initialPrompt;parts.push(escapeShellArg2(prompt))}if(ctx)env[TRACE_ENV_VAR]=mintToken(ctx),env[TRACE_ID_ENV_VAR]=ctx.trace_id}function buildClaudeGenieEnv(params){let env={};if(env.GENIE_WORKER="1",params.role)env.GENIE_AGENT_NAME=params.role;if(params.team)env.GENIE_TEAM=params.team;if(params.executorId)env.GENIE_EXECUTOR_ID=params.executorId;if(params.agentId)env.GENIE_AGENT_ID=params.agentId;return env}function appendSessionFlags(parts,params){if(params.resume)parts.push("--resume",escapeShellArg2(params.resume));else if(params.sessionId)parts.push("--session-id",escapeShellArg2(params.sessionId));if(params.role)parts.push("--agent",escapeShellArg2(params.role));if(params.model)parts.push("--model",escapeShellArg2(params.model));if(params.name)parts.push("--name",escapeShellArg2(params.name))}function buildSettingsObject(params){let settingsObj={};if(!params.skipHooks){let hookEntry={type:"command",command:buildDispatchCommand(),timeout:15};settingsObj.hooks={PreToolUse:[{matcher:"*",hooks:[hookEntry]}],PostToolUse:[{matcher:"*",hooks:[hookEntry]}],UserPromptSubmit:[{hooks:[hookEntry]}],Stop:[{hooks:[hookEntry]}]}}if(params.permissions){let perms={};if(params.permissions.allow?.length)perms.allow=params.permissions.allow;if(params.permissions.deny?.length)perms.deny=params.permissions.deny;if(Object.keys(perms).length>0)settingsObj.permissions=perms}return settingsObj}function appendDisallowedAndExtraArgs(parts,params){if(params.disallowedTools?.length)for(let tool of params.disallowedTools)parts.push("--disallowedTools",escapeShellArg2(tool));if(params.extraArgs)for(let arg of params.extraArgs)parts.push(escapeShellArg2(arg))}function buildClaudeCommand(params){preflightCheck("claude");let parts=[resolveShellBinary("claude")??"claude","--
|
|
51
|
+
${readFileSync5(params.extraArgs[fileIdx+1],"utf-8")}`,params.extraArgs.splice(fileIdx,2)}writeFileSync5(promptFile,content);let flag=params.promptMode==="system"?"--system-prompt-file":"--append-system-prompt-file";parts.push(flag,escapeShellArg2(promptFile))}else if(params.systemPromptFile){let flag=params.promptMode==="system"?"--system-prompt-file":"--append-system-prompt-file";parts.push(flag,escapeShellArg2(params.systemPromptFile))}}function appendOtelEnv(env,params){if(!params.otelPort||process.env.OTEL_EXPORTER_OTLP_ENDPOINT)return;if(env.CLAUDE_CODE_ENABLE_TELEMETRY="1",env.OTEL_LOGS_EXPORTER="otlp",env.OTEL_METRICS_EXPORTER="otlp",env.OTEL_EXPORTER_OTLP_PROTOCOL="http/json",env.OTEL_EXPORTER_OTLP_ENDPOINT=`http://127.0.0.1:${params.otelPort}`,env.OTEL_LOG_TOOL_DETAILS="1",params.otelLogPrompts!==!1)env.OTEL_LOG_USER_PROMPTS="1";let resourceParts=[];if(params.role)resourceParts.push(`agent.name=${params.role}`);if(params.team)resourceParts.push(`team.name=${params.team}`);if(params.otelWishSlug)resourceParts.push(`wish.slug=${params.otelWishSlug}`);if(params.role)resourceParts.push(`agent.role=${params.role}`);if(resourceParts.length>0)env.OTEL_RESOURCE_ATTRIBUTES=resourceParts.join(",")}function appendTraceContext(parts,env,params){let ctx=getAmbient();if(params.initialPrompt){let prompt=ctx?injectPromptPreamble(params.initialPrompt,ctx):params.initialPrompt;parts.push(escapeShellArg2(prompt))}if(ctx)env[TRACE_ENV_VAR]=mintToken(ctx),env[TRACE_ID_ENV_VAR]=ctx.trace_id}function buildClaudeGenieEnv(params){let env={};if(env.GENIE_WORKER="1",params.role)env.GENIE_AGENT_NAME=params.role;if(params.team)env.GENIE_TEAM=params.team;if(params.executorId)env.GENIE_EXECUTOR_ID=params.executorId;if(params.agentId)env.GENIE_AGENT_ID=params.agentId;return env}function appendSessionFlags(parts,params){if(params.resume)parts.push("--resume",escapeShellArg2(params.resume));else if(params.sessionId)parts.push("--session-id",escapeShellArg2(params.sessionId));if(params.role)parts.push("--agent",escapeShellArg2(params.role));if(params.model)parts.push("--model",escapeShellArg2(params.model));if(params.name)parts.push("--name",escapeShellArg2(params.name))}function buildSettingsObject(params){let settingsObj={};if(!params.skipHooks){let hookEntry={type:"command",command:buildDispatchCommand(),timeout:15};settingsObj.hooks={PreToolUse:[{matcher:"*",hooks:[hookEntry]}],PostToolUse:[{matcher:"*",hooks:[hookEntry]}],UserPromptSubmit:[{hooks:[hookEntry]}],Stop:[{hooks:[hookEntry]}]}}if(params.permissions){let perms={};if(params.permissions.allow?.length)perms.allow=params.permissions.allow;if(params.permissions.deny?.length)perms.deny=params.permissions.deny;if(Object.keys(perms).length>0)settingsObj.permissions=perms}return settingsObj}function appendDisallowedAndExtraArgs(parts,params){if(params.disallowedTools?.length)for(let tool of params.disallowedTools)parts.push("--disallowedTools",escapeShellArg2(tool));if(params.extraArgs)for(let arg of params.extraArgs)parts.push(escapeShellArg2(arg))}function buildClaudeCommand(params){preflightCheck("claude");let parts=[resolveShellBinary("claude")??"claude","--permission-mode",escapeShellArg2("auto")],env=buildClaudeGenieEnv(params);if(appendOtelEnv(env,params),params.nativeTeam?.enabled)appendNativeTeamFlags(parts,env,params.nativeTeam,params);appendSessionFlags(parts,params),appendSystemPromptFlags(parts,params);let settingsObj=buildSettingsObject(params);if(Object.keys(settingsObj).length>0)parts.push("--settings",escapeShellArg2(JSON.stringify(settingsObj)));return appendDisallowedAndExtraArgs(parts,params),appendTraceContext(parts,env,params),{command:parts.join(" "),provider:"claude",env:Object.keys(env).length>0?env:void 0,meta:{role:params.role,skill:params.skill}}}function buildCodexCommand(params){preflightCheck("codex");let parts=["codex"],env={};if(params.executorId)env.GENIE_EXECUTOR_ID=params.executorId;if(params.agentId)env.GENIE_AGENT_ID=params.agentId;if(params.role)env.GENIE_AGENT_NAME=params.role;if(params.team)env.GENIE_TEAM=params.team;if(parts.push("--yolo"),parts.push("--no-alt-screen"),params.extraArgs)for(let arg of params.extraArgs)parts.push(escapeShellArg2(arg));let promptParts=[`Genie worker. Team: ${params.team}.`];if(params.role)promptParts.push(`Role: ${params.role}.`);if(params.skill)promptParts.push(`Execute the ${params.skill} skill instructions.`);let prompt=promptParts.join(" ");return parts.push(escapeShellArg2(prompt)),{command:parts.join(" "),provider:"codex",env:Object.keys(env).length>0?env:void 0,meta:{role:params.role,skill:params.skill}}}function buildLaunchCommand(params){let validated=validateSpawnParams(params);switch(validated.provider){case"claude":return buildClaudeCommand(validated);case"codex":return buildCodexCommand(validated);case"claude-sdk":return{command:"claude-sdk-in-process",provider:"claude-sdk",meta:{role:validated.role,skill:validated.skill}};default:throw Error(`Unknown provider "${validated.provider}". Valid providers: claude, codex, claude-sdk`)}}var CLAUDE_TEAM_COLORS,spawnParamsSchema;var init_provider_adapters=__esm(()=>{init_zod();init_inject();init_trace_context();CLAUDE_TEAM_COLORS=["red","blue","green","yellow","purple","orange","pink","cyan"],spawnParamsSchema=exports_external.object({provider:exports_external.enum(["claude","codex","claude-sdk","app-pty"]),team:exports_external.string().min(1,"Team name is required"),role:exports_external.string().optional(),skill:exports_external.string().optional(),agentId:exports_external.string().optional(),executorId:exports_external.string().uuid().optional(),extraArgs:exports_external.array(exports_external.string()).optional(),nativeTeam:exports_external.object({enabled:exports_external.boolean(),parentSessionId:exports_external.string().optional(),color:exports_external.string().optional(),agentType:exports_external.string().optional(),planModeRequired:exports_external.boolean().optional(),permissionMode:exports_external.string().optional(),agentName:exports_external.string().optional()}).optional(),sessionId:exports_external.string().uuid().optional(),resume:exports_external.string().optional(),systemPromptFile:exports_external.string().optional(),systemPrompt:exports_external.string().optional(),promptMode:exports_external.enum(["system","append"]).optional(),model:exports_external.string().optional(),initialPrompt:exports_external.string().optional(),name:exports_external.string().optional(),otelPort:exports_external.number().optional(),otelLogPrompts:exports_external.boolean().optional(),otelWishSlug:exports_external.string().optional(),newWindow:exports_external.boolean().optional(),windowTarget:exports_external.string().optional()})});var exports_audit={};__export(exports_audit,{recordAuditEvent:()=>recordAuditEvent,queryToolUsage:()=>queryToolUsage,queryTimeline:()=>queryTimeline,querySummary:()=>querySummary,queryErrorPatterns:()=>queryErrorPatterns,queryCostBreakdown:()=>queryCostBreakdown,queryAuditEvents:()=>queryAuditEvents,getActor:()=>getActor,generateTraceId:()=>generateTraceId,followAuditEvents:()=>followAuditEvents});async function recordAuditEvent(entityType,entityId,eventType,actor,details){try{if(!await isAvailable())return;let sql=await getConnection();await sql`
|
|
52
52
|
INSERT INTO audit_events (entity_type, entity_id, event_type, actor, details)
|
|
53
53
|
VALUES (${entityType}, ${entityId}, ${eventType}, ${actor??null}, ${sql.json(details??{})})
|
|
54
54
|
`}catch{}}function parseSince(since){let match=since.match(/^(\d+)([smhd])$/);if(!match)return since;let amount=Number.parseInt(match[1],10),unit=match[2],ms={s:1000,m:60000,h:3600000,d:86400000}[unit]??3600000;return new Date(Date.now()-amount*ms).toISOString()}async function queryAuditEvents(options={}){let sql=await getConnection(),conditions=[],values=[],paramIdx=1;if(options.type)conditions.push(`(event_type = $${paramIdx} OR entity_type = $${paramIdx})`),paramIdx++,values.push(options.type);if(options.entity)conditions.push(`(entity_type = $${paramIdx} OR entity_id = $${paramIdx})`),paramIdx++,values.push(options.entity);if(options.since)conditions.push(`created_at >= $${paramIdx++}::timestamptz`),values.push(parseSince(options.since));if(options.errorsOnly)conditions.push("event_type LIKE '%error%' OR (details::text LIKE '%error%')");let where=conditions.length>0?`WHERE ${conditions.join(" AND ")}`:"",limit=options.limit??50;return await sql.unsafe(`SELECT id, entity_type, entity_id, event_type, actor, details, created_at
|
|
@@ -136,7 +136,7 @@ ${readFileSync5(params.extraArgs[fileIdx+1],"utf-8")}`,params.extraArgs.splice(f
|
|
|
136
136
|
COUNT(*) FILTER (WHERE entity_type = 'otel_tool')::int AS tool_calls,
|
|
137
137
|
COUNT(*) FILTER (WHERE entity_type = 'otel_api')::int AS api_requests
|
|
138
138
|
FROM audit_events
|
|
139
|
-
WHERE created_at >= $1::timestamptz`,[sinceTs]))[0]??{};return{agents_spawned:r.agents_spawned??0,tasks_moved:r.tasks_moved??0,total_cost:r.total_cost??0,error_count:r.error_count??0,total_events:r.total_events??0,tool_calls:r.tool_calls??0,api_requests:r.api_requests??0}}function generateTraceId(){return crypto.randomUUID()}var init_audit=__esm(()=>{init_db()});var exports_team_lead_command={};__export(exports_team_lead_command,{shellQuote:()=>shellQuote,sessionExists:()=>sessionExists,ccProjectDirName:()=>ccProjectDirName,buildTeamLeadCommand:()=>buildTeamLeadCommand});import{readFileSync as readFileSync5,readdirSync as readdirSync3}from"fs";import{basename,join as join8}from"path";function shellQuote(s){return`'${s.replace(/'/g,"'\\''")}'`}function buildTeamLeadCommand(teamName,options){let sanitized=sanitizeTeamName(teamName),qTeam=shellQuote(sanitized),folderName=basename(process.cwd()),resolvedLeader=options?.leaderName??teamName,sanitizedLeader=sanitizeTeamName(resolvedLeader),parts=["GENIE_WORKER=1","CLAUDECODE=1","CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1",`GENIE_TEAM=${qTeam}`,`GENIE_AGENT_NAME=${shellQuote(folderName)}`,"claude",`--agent-id ${shellQuote(`${sanitizedLeader}@${sanitized}`)}`,`--agent-name ${shellQuote(sanitizedLeader)}`,`--team-name ${qTeam}`,"--agent-type team-lead","--
|
|
139
|
+
WHERE created_at >= $1::timestamptz`,[sinceTs]))[0]??{};return{agents_spawned:r.agents_spawned??0,tasks_moved:r.tasks_moved??0,total_cost:r.total_cost??0,error_count:r.error_count??0,total_events:r.total_events??0,tool_calls:r.tool_calls??0,api_requests:r.api_requests??0}}function generateTraceId(){return crypto.randomUUID()}var init_audit=__esm(()=>{init_db()});var exports_team_lead_command={};__export(exports_team_lead_command,{shellQuote:()=>shellQuote,sessionExists:()=>sessionExists,ccProjectDirName:()=>ccProjectDirName,buildTeamLeadCommand:()=>buildTeamLeadCommand});import{readFileSync as readFileSync5,readdirSync as readdirSync3}from"fs";import{basename,join as join8}from"path";function shellQuote(s){return`'${s.replace(/'/g,"'\\''")}'`}function buildTeamLeadCommand(teamName,options){let sanitized=sanitizeTeamName(teamName),qTeam=shellQuote(sanitized),folderName=basename(process.cwd()),resolvedLeader=options?.leaderName??teamName,sanitizedLeader=sanitizeTeamName(resolvedLeader),parts=["GENIE_WORKER=1","CLAUDECODE=1","CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1",`GENIE_TEAM=${qTeam}`,`GENIE_AGENT_NAME=${shellQuote(folderName)}`,"claude",`--agent-id ${shellQuote(`${sanitizedLeader}@${sanitized}`)}`,`--agent-name ${shellQuote(sanitizedLeader)}`,`--team-name ${qTeam}`,"--agent-type team-lead","--permission-mode auto"];if(parts.push(`--name ${shellQuote(sanitized)}`),options?.sessionId){let flag=options.resume?"--resume":"--session-id";parts.push(`${flag} ${shellQuote(options.sessionId)}`)}if(options?.systemPromptFile){let promptFlag=(options?.promptMode??loadGenieConfigSync().promptMode)==="system"?"--system-prompt-file":"--append-system-prompt-file";parts.push(`${promptFlag} ${shellQuote(options.systemPromptFile)}`)}return parts.join(" ")}function ccProjectDirName(dir){return dir.replace(/\//g,"-")}function fileHasSessionName(filePath,needle){try{let lines=readFileSync5(filePath,"utf-8").split(`
|
|
140
140
|
`).slice(0,10);for(let line of lines){if(!line.includes("custom-title"))continue;let entry=JSON.parse(line);if(entry.type==="custom-title"&&entry.customTitle?.toLowerCase()===needle)return!0}}catch{}return!1}function sessionExists(name,cwd){try{let home=process.env.HOME??"/root",projectDir=ccProjectDirName(cwd??process.cwd()),projectPath=join8(home,".claude","projects",projectDir),files;try{files=readdirSync3(projectPath).filter((f)=>f.endsWith(".jsonl"))}catch{return!1}let needle=name.toLowerCase();return files.some((file)=>{let full=join8(projectPath,file);return fileHasSessionName(full,needle)||fileHasSessionName(full,`${needle}-${needle}`)})}catch{return!1}}var init_team_lead_command=__esm(()=>{init_claude_native_teams();init_genie_config2()});var exports_tmux_wrapper={};__export(exports_tmux_wrapper,{prependEnvVars:()=>prependEnvVars,genieTmuxPrefix:()=>genieTmuxPrefix,genieTmuxCmd:()=>genieTmuxCmd,executeTmux:()=>executeTmux});import{exec as execCallback}from"child_process";import{existsSync as existsSync7,mkdirSync as mkdirSync5}from"fs";import{homedir as homedir6}from"os";import{join as join9}from"path";import{promisify}from"util";function resolveGenieTmuxConf(){let home=homedir6(),genieHome3=process.env.GENIE_HOME??join9(home,".genie");return[join9(genieHome3,"tmux.conf"),join9(__dirname,"..","..","scripts","tmux","genie.tmux.conf"),join9(home,".bun","install","global","node_modules","@automagik","genie","scripts","tmux","genie.tmux.conf")].find((p)=>existsSync7(p))??"/dev/null"}function genieTmuxPrefix(){return["-L",GENIE_TMUX_SOCKET,"-f",resolveGenieTmuxConf()]}function genieTmuxCmd(subcommand){return`${tmuxBin()} ${genieTmuxPrefix().join(" ")} ${subcommand}`}function prependEnvVars(command,env){if(!env||Object.keys(env).length===0)return command;return`env ${Object.entries(env).map(([k,v])=>`${k}=${v}`).join(" ")} ${command}`}function getLogDir(){let logDir=join9(homedir6(),".genie","logs","tmux");if(!existsSync7(logDir))mkdirSync5(logDir,{recursive:!0});return logDir}function stripVerboseFlags(args){return args.filter((arg)=>!/^-v+$/.test(arg))}function isTmuxDebugEnabled(){return process.env.GENIE_TMUX_DEBUG==="1"}async function executeTmux(args){let argList=typeof args==="string"?args.split(/\s+/).filter(Boolean):args,finalArgs=stripVerboseFlags(argList),debugMode=isTmuxDebugEnabled(),options={};if(debugMode)finalArgs=["-v",...finalArgs],options.cwd=getLogDir();finalArgs=[...genieTmuxPrefix(),...finalArgs];let command=`${tmuxBin()} ${finalArgs.join(" ")}`,{stdout}=await exec(command,options);return stdout.trim()}var __dirname="/home/runner/_work/genie/genie/src/lib",exec,GENIE_TMUX_SOCKET;var init_tmux_wrapper=__esm(()=>{init_ensure_tmux();exec=promisify(execCallback),GENIE_TMUX_SOCKET=process.env.GENIE_TMUX_SOCKET||"genie"});var exports_tmux={};__export(exports_tmux,{setWindowEnv:()=>setWindowEnv,resolveRepoSession:()=>resolveRepoSession,listWindows:()=>listWindows,listPanes:()=>listPanes,killWindow:()=>killWindow,killSession:()=>killSession,isTmuxServerReachable:()=>isTmuxServerReachable,isPaneProcessRunning:()=>isPaneProcessRunning,isPaneAlive:()=>isPaneAlive,getWindowEnv:()=>getWindowEnv,getCurrentSessionName:()=>getCurrentSessionName,findWindowByName:()=>findWindowByName,findSessionByName:()=>findSessionByName,executeTmux:()=>executeTmux2,ensureTeamWindow:()=>ensureTeamWindow,createSession:()=>createSession,capturePaneContent:()=>capturePaneContent,applyPaneColor:()=>applyPaneColor,TmuxUnreachableError:()=>TmuxUnreachableError});import{existsSync as existsSync8}from"fs";import{basename as basename2,join as join10}from"path";async function executeTmux2(tmuxCommand){let{executeTmux:wrapperExec}=await Promise.resolve().then(() => (init_tmux_wrapper(),exports_tmux_wrapper));try{return await wrapperExec(tmuxCommand)}catch(error){let message=error instanceof Error?error.message:String(error);throw Error(`Failed to execute tmux command: ${message}`)}}async function getCurrentSessionName(hint){if(process.env.TMUX)try{return(await executeTmux2("display-message -p '#{session_name}'")).trim()||null}catch{return null}try{let sessions=await listSessions();if(sessions.length===0)return null;if(hint){let match=sessions.find((s)=>s.name.includes(hint));if(match)return match.name}return sessions[0].name}catch{return null}}async function listSessions(){try{let output=await executeTmux2("list-sessions -F '#{session_id}:#{session_name}:#{?session_attached,1,0}:#{session_windows}'");if(!output)return[];return output.split(`
|
|
141
141
|
`).map((line)=>{let[id,name,attached,windows]=line.split(":");return{id,name,attached:attached==="1",windows:Number.parseInt(windows,10)}})}catch(error){if((error instanceof Error?error.message:String(error)).includes("no server running"))return[];throw error}}async function findSessionByName(name){try{return(await listSessions()).find((session)=>session.name===name)||null}catch(_error){return null}}async function getWindowEnv(target,varName){try{let output=await executeTmux2(`show-environment -t ${shellQuote(target)} ${shellQuote(varName)}`),prefix=`${varName}=`;if(output?.startsWith(prefix))return output.slice(prefix.length).trim();return null}catch{return null}}async function setWindowEnv(target,varName,value){await executeTmux2(`set-environment -t ${shellQuote(target)} ${shellQuote(varName)} ${shellQuote(value)}`)}async function killSession(sessionId){await executeTmux2(`kill-session -t '${sessionId}'`)}async function listWindows(sessionId){try{let output=await executeTmux2(`list-windows -t '=${sessionId}' -F '#{window_id}:#{window_name}:#{window_index}:#{?window_active,1,0}'`);if(!output)return[];return output.split(`
|
|
142
142
|
`).map((line)=>{let[id,name,indexStr,active]=line.split(":");return{id,name,index:Number.parseInt(indexStr,10),active:active==="1",sessionId}})}catch(error){let message=error instanceof Error?error.message:String(error);if(message.includes("no server running")||message.includes("session not found"))return[];throw error}}async function listPanes(windowId){try{let output=await executeTmux2(`list-panes -t '${windowId}' -F '#{pane_id}:#{pane_title}:#{?pane_active,1,0}'`);if(!output)return[];return output.split(`
|
|
@@ -262,7 +262,7 @@ ${bin} set-option -w pane-active-border-style "fg=$COLOR"
|
|
|
262
262
|
native_team_enabled, parent_session_id, current_executor_id, reports_to, title, created_at, updated_at
|
|
263
263
|
FROM agents
|
|
264
264
|
WHERE (${includeArchived} OR state IS DISTINCT FROM 'archived')
|
|
265
|
-
`;return rows.map(rowToAgentIdentity)}var DEAD_PANE_ZOMBIE_TTL_HOURS=24;var init_agent_registry=__esm(()=>{init_audit();init_db();init_tmux()});function normalizeValue(v){if(v===void 0||v===null)return;if(v==="")return;if(v==="inherit")return;return v}function resolveField(agent,field,ctx){return resolveFieldWithSource(agent,field,ctx).value}function resolveFieldWithSource(agent,field,ctx){let agentVal=normalizeValue(agent[field]);if(agentVal!==void 0)return{value:agentVal,source:"explicit"};if(ctx.parent){let parentVal=normalizeValue(ctx.parent.fields[field]);if(parentVal!==void 0)return{value:parentVal,source:`parent:${ctx.parent.name}`}}if(ctx.workspaceDefaults){let wsVal=normalizeValue(ctx.workspaceDefaults[field]);if(wsVal!==void 0)return{value:wsVal,source:"workspace"}}return{value:BUILTIN_DEFAULTS[field],source:"built-in"}}function computeEffectiveDefaults(workspaceDefaults){if(!workspaceDefaults)return{...BUILTIN_DEFAULTS};let result2={...BUILTIN_DEFAULTS};for(let key of Object.keys(BUILTIN_DEFAULTS)){let wsVal=normalizeValue(workspaceDefaults[key]);if(wsVal!==void 0)result2[key]=wsVal}return result2}var BUILTIN_DEFAULTS,RESOLVED_FIELDS;var init_defaults=__esm(()=>{BUILTIN_DEFAULTS={model:"opus",promptMode:"append",color:"blue",effort:"high",thinking:"enabled",permissionMode:"
|
|
265
|
+
`;return rows.map(rowToAgentIdentity)}var DEAD_PANE_ZOMBIE_TTL_HOURS=24;var init_agent_registry=__esm(()=>{init_audit();init_db();init_tmux()});function normalizeValue(v){if(v===void 0||v===null)return;if(v==="")return;if(v==="inherit")return;return v}function resolveField(agent,field,ctx){return resolveFieldWithSource(agent,field,ctx).value}function resolveFieldWithSource(agent,field,ctx){let agentVal=normalizeValue(agent[field]);if(agentVal!==void 0)return{value:agentVal,source:"explicit"};if(ctx.parent){let parentVal=normalizeValue(ctx.parent.fields[field]);if(parentVal!==void 0)return{value:parentVal,source:`parent:${ctx.parent.name}`}}if(ctx.workspaceDefaults){let wsVal=normalizeValue(ctx.workspaceDefaults[field]);if(wsVal!==void 0)return{value:wsVal,source:"workspace"}}return{value:BUILTIN_DEFAULTS[field],source:"built-in"}}function computeEffectiveDefaults(workspaceDefaults){if(!workspaceDefaults)return{...BUILTIN_DEFAULTS};let result2={...BUILTIN_DEFAULTS};for(let key of Object.keys(BUILTIN_DEFAULTS)){let wsVal=normalizeValue(workspaceDefaults[key]);if(wsVal!==void 0)result2[key]=wsVal}return result2}var BUILTIN_DEFAULTS,RESOLVED_FIELDS;var init_defaults=__esm(()=>{BUILTIN_DEFAULTS={model:"opus",promptMode:"append",color:"blue",effort:"high",thinking:"enabled",permissionMode:"auto"},RESOLVED_FIELDS=["model"]});var exports_js_yaml={};__export(exports_js_yaml,{types:()=>types2,safeLoadAll:()=>safeLoadAll,safeLoad:()=>safeLoad,safeDump:()=>safeDump,loadAll:()=>loadAll,load:()=>load,dump:()=>dump,default:()=>jsYaml,YAMLException:()=>YAMLException,Type:()=>Type,Schema:()=>Schema,JSON_SCHEMA:()=>JSON_SCHEMA,FAILSAFE_SCHEMA:()=>FAILSAFE_SCHEMA,DEFAULT_SCHEMA:()=>DEFAULT_SCHEMA,CORE_SCHEMA:()=>CORE_SCHEMA});function isNothing(subject){return typeof subject>"u"||subject===null}function isObject(subject){return typeof subject==="object"&&subject!==null}function toArray(sequence){if(Array.isArray(sequence))return sequence;else if(isNothing(sequence))return[];return[sequence]}function extend(target,source){var index,length,key,sourceKeys;if(source){sourceKeys=Object.keys(source);for(index=0,length=sourceKeys.length;index<length;index+=1)key=sourceKeys[index],target[key]=source[key]}return target}function repeat(string,count){var result2="",cycle;for(cycle=0;cycle<count;cycle+=1)result2+=string;return result2}function isNegativeZero(number){return number===0&&Number.NEGATIVE_INFINITY===1/number}function formatError(exception,compact){var where="",message=exception.reason||"(unknown reason)";if(!exception.mark)return message;if(exception.mark.name)where+='in "'+exception.mark.name+'" ';if(where+="("+(exception.mark.line+1)+":"+(exception.mark.column+1)+")",!compact&&exception.mark.snippet)where+=`
|
|
266
266
|
|
|
267
267
|
`+exception.mark.snippet;return message+" "+where}function YAMLException$1(reason,mark){if(Error.call(this),this.name="YAMLException",this.reason=reason,this.mark=mark,this.message=formatError(this,!1),Error.captureStackTrace)Error.captureStackTrace(this,this.constructor);else this.stack=Error().stack||""}function getLine(buffer,lineStart,lineEnd,position,maxLineLength){var head="",tail="",maxHalfLength=Math.floor(maxLineLength/2)-1;if(position-lineStart>maxHalfLength)head=" ... ",lineStart=position-maxHalfLength+head.length;if(lineEnd-position>maxHalfLength)tail=" ...",lineEnd=position+maxHalfLength-tail.length;return{str:head+buffer.slice(lineStart,lineEnd).replace(/\t/g,"\u2192")+tail,pos:position-lineStart+head.length}}function padStart(string,max){return common.repeat(" ",max-string.length)+string}function makeSnippet(mark,options){if(options=Object.create(options||null),!mark.buffer)return null;if(!options.maxLength)options.maxLength=79;if(typeof options.indent!=="number")options.indent=1;if(typeof options.linesBefore!=="number")options.linesBefore=3;if(typeof options.linesAfter!=="number")options.linesAfter=2;var re=/\r?\n|\r|\0/g,lineStarts=[0],lineEnds=[],match,foundLineNo=-1;while(match=re.exec(mark.buffer))if(lineEnds.push(match.index),lineStarts.push(match.index+match[0].length),mark.position<=match.index&&foundLineNo<0)foundLineNo=lineStarts.length-2;if(foundLineNo<0)foundLineNo=lineStarts.length-1;var result2="",i,line,lineNoLength=Math.min(mark.line+options.linesAfter,lineEnds.length).toString().length,maxLineLength=options.maxLength-(options.indent+lineNoLength+3);for(i=1;i<=options.linesBefore;i++){if(foundLineNo-i<0)break;line=getLine(mark.buffer,lineStarts[foundLineNo-i],lineEnds[foundLineNo-i],mark.position-(lineStarts[foundLineNo]-lineStarts[foundLineNo-i]),maxLineLength),result2=common.repeat(" ",options.indent)+padStart((mark.line-i+1).toString(),lineNoLength)+" | "+line.str+`
|
|
268
268
|
`+result2}line=getLine(mark.buffer,lineStarts[foundLineNo],lineEnds[foundLineNo],mark.position,maxLineLength),result2+=common.repeat(" ",options.indent)+padStart((mark.line+1).toString(),lineNoLength)+" | "+line.str+`
|
|
@@ -435,7 +435,7 @@ ${bin} set-option -w pane-active-border-style "fg=$COLOR"
|
|
|
435
435
|
`}async function getTeam(name){try{let rows=await(await getConnection())`SELECT * FROM teams WHERE name = ${name}`;if(rows.length===0)return null;return rowToTeamConfig(rows[0])}catch{return null}}async function listTeams(includeArchived=!1){try{let sql=await getConnection();if(includeArchived)return(await sql`SELECT * FROM teams ORDER BY created_at DESC`).map(rowToTeamConfig);return(await sql`SELECT * FROM teams WHERE status != 'archived' ORDER BY created_at DESC`).map(rowToTeamConfig)}catch{return[]}}async function listMembers(teamName){let config=await getTeam(teamName);if(!config)return null;return config.members}async function killTeamMembers(teamName){let config=await getTeam(teamName);if(!config)return;for(let member of config.members)try{await killWorkersByName(member,teamName)}catch{}}async function resolveLeaderName(teamName){try{let config=await getTeam(teamName);if(config?.leader&&config.leader!=="team-lead")return config.leader}catch{}return teamName}async function setTeamStatus(teamName,status){if((await(await getConnection())`
|
|
436
436
|
UPDATE teams SET status = ${status}
|
|
437
437
|
WHERE name = ${teamName}
|
|
438
|
-
`).count===0)throw Error(`Team "${teamName}" not found.`)}var init_team_manager=__esm(()=>{init_agent_registry();init_audit();init_builtin_agents();init_claude_native_teams();init_db();init_executor_registry();init_genie_config2();init_tmux()});var exports_claude_native_teams={};__export(exports_claude_native_teams,{writeNativeInbox:()=>writeNativeInbox,unregisterNativeMember:()=>unregisterNativeMember,sanitizeTeamName:()=>sanitizeTeamName,resolveNativeMemberName:()=>resolveNativeMemberName,registerNativeMember:()=>registerNativeMember,registerAsTeamLead:()=>registerAsTeamLead,loadNativeTeamConfig:()=>loadNativeTeamConfig,loadConfig:()=>loadConfig,loadAllNativeTeamConfigs:()=>loadAllNativeTeamConfigs,listTeamsWithUnreadInbox:()=>listTeamsWithUnreadInbox,listTeams:()=>listTeams2,isInsideClaudeCode:()=>isInsideClaudeCode,findTeamsContainingAgent:()=>findTeamsContainingAgent,ensureNativeTeamWithSessionId:()=>ensureNativeTeamWithSessionId,ensureNativeTeam:()=>ensureNativeTeam,discoverTeamName:()=>discoverTeamName,discoverClaudeParentSessionId:()=>discoverClaudeParentSessionId,deleteNativeTeam:()=>deleteNativeTeam,clearNativeInbox:()=>clearNativeInbox,assignColor:()=>assignColor});import{existsSync as existsSync11}from"fs";import{mkdir as mkdir3,open,readFile as readFile3,readdir,rm as rm2,stat,writeFile as writeFile3}from"fs/promises";import{homedir as homedir8}from"os";import{join as join13}from"path";function claudeConfigDir2(){return process.env.CLAUDE_CONFIG_DIR??join13(homedir8(),".claude")}function teamsBaseDir(){return join13(claudeConfigDir2(),"teams")}function sanitizeTeamName(name){return name.replace(/[^a-zA-Z0-9]/g,"-").toLowerCase()}async function listTeams2(){try{return(await readdir(teamsBaseDir())).filter((e)=>!e.startsWith("."))}catch{return[]}}function teamDir(teamName){return join13(teamsBaseDir(),sanitizeTeamName(teamName))}function configPath(teamName){return join13(teamDir(teamName),"config.json")}function inboxesDir(teamName){return join13(teamDir(teamName),"inboxes")}function inboxPath(teamName,agentName){return join13(inboxesDir(teamName),`${sanitizeTeamName(agentName)}.json`)}async function loadConfig(teamName){try{let content=await readFile3(configPath(teamName),"utf-8");return JSON.parse(content)}catch(err){if(err instanceof Error&&"code"in err&&err.code==="ENOENT")return null;let message=err instanceof Error?err.message:String(err);return console.warn(`[claude-native-teams] Failed to load config for "${teamName}": ${message}`),null}}async function loadNativeTeamConfig(teamName){return loadConfig(teamName)}async function loadAllNativeTeamConfigs(){let teamNames=await listTeams2(),configs=[];for(let name of teamNames){let cfg=await loadConfig(name);if(cfg)configs.push(cfg)}return configs}async function findTeamsContainingAgent(agentName){let teams=await listTeams2(),matches=[];for(let teamName of teams){let config=await loadConfig(teamName);if(!config)continue;if(config.members.some((m)=>m.name===agentName||m.agentType===agentName))matches.push(teamName)}return matches}async function saveConfig(teamName,config){await writeFile3(configPath(teamName),JSON.stringify(config,null,2))}async function countLeadSessionRefs(){let counts=new Map,teams=await listTeams2();for(let team of teams){let leadSessionId=(await loadConfig(team))?.leadSessionId;if(!leadSessionId)continue;counts.set(leadSessionId,(counts.get(leadSessionId)??0)+1)}return counts}async function ensureNativeTeam(teamName,description,leadSessionId,leaderName){let dir=teamDir(teamName),inboxDir=inboxesDir(teamName);await mkdir3(dir,{recursive:!0}),await mkdir3(inboxDir,{recursive:!0}),ensureTeammateBypassPermissions();let existing=await loadConfig(teamName);if(existing)return await backfillTeamRow(sanitizeTeamName(teamName),existing),existing;let sanitized=sanitizeTeamName(teamName),resolvedLeader=sanitizeTeamName(leaderName??teamName),config={name:sanitized,description,createdAt:Date.now(),leadAgentId:`${resolvedLeader}@${sanitized}`,leadSessionId,members:[]};return await saveConfig(teamName,config),await backfillTeamRow(sanitized,config),config}async function backfillTeamRow(name,nativeConfig){try{let{ensureTeamRow:ensureTeamRow2}=await Promise.resolve().then(() => (init_team_manager(),exports_team_manager));await ensureTeamRow2(name,{nativeConfig})}catch{}}function isHealthyLeadSessionId(id){if(typeof id!=="string"||id.length===0)return!1;return/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id)}async function ensureNativeTeamWithSessionId(teamName,description,sessionId,leaderName){let config=await ensureNativeTeam(teamName,description,sessionId,leaderName);if(config.leadSessionId===sessionId)return config;if(isHealthyLeadSessionId(config.leadSessionId))return config;return config.leadSessionId=sessionId,await saveConfig(teamName,config),config}async function registerNativeMember(teamName,member){let config=await loadConfig(teamName);if(!config)throw Error(`Native team "${teamName}" not found`);let sanitized=sanitizeTeamName(teamName),agentId=`${sanitizeTeamName(member.agentName)}@${sanitized}`;config.members=config.members.filter((m)=>m.agentId!==agentId),config.members.push({agentId,name:sanitizeTeamName(member.agentName),agentType:member.agentType??"general-purpose",joinedAt:Date.now(),tmuxPaneId:member.tmuxPaneId,cwd:member.cwd??process.cwd(),backendType:"tmux",color:member.color,planModeRequired:member.planModeRequired??!1,isActive:!0}),await saveConfig(teamName,config);let inbox=inboxPath(teamName,member.agentName);if(!existsSync11(inbox))await writeFile3(inbox,"[]")}async function unregisterNativeMember(teamName,agentName){let config=await loadConfig(teamName);if(!config)return;let sanitized=sanitizeTeamName(teamName),agentId=`${sanitizeTeamName(agentName)}@${sanitized}`,before=config.members.length;if(config.members=config.members.filter((m)=>m.agentId!==agentId),config.members.length===before)return;await saveConfig(teamName,config)}async function writeNativeInbox(teamName,agentName,message){let path2=inboxPath(teamName,agentName);await mkdir3(inboxesDir(teamName),{recursive:!0}),await acquireLock(path2);try{let messages=[];try{let content=await readFile3(path2,"utf-8");messages=JSON.parse(content)}catch{}messages.push(message),await writeFile3(path2,JSON.stringify(messages,null,2))}finally{await releaseLock(path2)}}async function resolveNativeMemberName(teamName,genieWorkerId){let config=await loadConfig(teamName);if(!config||config.members.length===0)return null;let sanitizedId=sanitizeTeamName(genieWorkerId),sanitizedTeam=sanitizeTeamName(teamName),exactMatch=config.members.find((m)=>m.name===sanitizedId&&m.isActive);if(exactMatch)return exactMatch.name;let agentIdMatch=config.members.find((m)=>m.agentId===`${sanitizedId}@${sanitizedTeam}`&&m.isActive);if(agentIdMatch)return agentIdMatch.name;let teamPrefix=`${sanitizedTeam}-`;if(sanitizedId.startsWith(teamPrefix)){let stripped=sanitizedId.slice(teamPrefix.length),prefixMatch=config.members.find((m)=>m.name===stripped&&m.isActive);if(prefixMatch)return prefixMatch.name}let inactiveMatch=config.members.find((m)=>m.name===sanitizedId);if(inactiveMatch)return inactiveMatch.name;return null}async function assignColor(teamName){let config=await loadConfig(teamName);if(!config)return CLAUDE_TEAM_COLORS[0];let usedColors=new Set(config.members.map((m)=>m.color));for(let color of CLAUDE_TEAM_COLORS)if(!usedColors.has(color))return color;return CLAUDE_TEAM_COLORS[config.members.length%CLAUDE_TEAM_COLORS.length]}async function clearNativeInbox(teamName,agentName){let path2=inboxPath(teamName,agentName);await acquireLock(path2);try{await writeFile3(path2,"[]")}finally{await releaseLock(path2)}}async function deleteNativeTeam(teamName){let dir=teamDir(teamName);if(!existsSync11(dir))return!1;return await rm2(dir,{recursive:!0,force:!0}),!0}function extractLeaderInboxName(config,teamName){if(!config?.leadAgentId)return teamName??"unknown";let atIdx=config.leadAgentId.indexOf("@");return atIdx>0?config.leadAgentId.slice(0,atIdx):teamName??"unknown"}function resolveLeadWorkingDir(config,leaderInboxName){let leadMember=config.members.find((m)=>m.agentId===config.leadAgentId||m.name===leaderInboxName);if(leadMember?.cwd)return leadMember.cwd;if(config.worktreePath)return config.worktreePath;if(config.repo)return config.repo;return config.members.find((m)=>m.cwd)?.cwd??null}async function scanTeamInbox(base,name){let config=null;try{let cfgContent=await readFile3(join13(base,name,"config.json"),"utf-8");config=JSON.parse(cfgContent)}catch{}let leaderInboxName=extractLeaderInboxName(config,name),inboxFile=join13(base,name,"inboxes",`${leaderInboxName}.json`),messages;try{let content=await readFile3(inboxFile,"utf-8");messages=JSON.parse(content)}catch{return null}if(!Array.isArray(messages))return null;let unread=messages.filter((m)=>m.read===!1);if(unread.length===0)return null;let workingDir=config?resolveLeadWorkingDir(config,leaderInboxName):null;return{teamName:name,unreadCount:unread.length,workingDir,firstUnreadText:unread[0]?.text??null}}async function listTeamsWithUnreadInbox(){let base=teamsBaseDir(),teamDirs;try{teamDirs=await readdir(base)}catch{return[]}let results=[];for(let name of teamDirs){let entry=await scanTeamInbox(base,name);if(entry)results.push(entry)}return results}function sanitizePath(p){return p.replace(/[^a-zA-Z0-9]/g,"-")}async function discoverClaudeSessionId(cwd){let envSessionId=process.env.CLAUDE_CODE_SESSION_ID;if(envSessionId)return envSessionId;let projectDir=join13(claudeConfigDir2(),"projects",sanitizePath(cwd??process.cwd()));try{let jsonls=(await readdir(projectDir)).filter((e)=>e.endsWith(".jsonl"));if(jsonls.length===0)return null;let newest=null;for(let name of jsonls){let s=await stat(join13(projectDir,name));if(!newest||s.mtimeMs>newest.mtime)newest={name,mtime:s.mtimeMs}}if(!newest)return null;return newest.name.replace(".jsonl","")}catch{return null}}async function readSessionMetadata(filePath){let handle=null;try{handle=await open(filePath,"r");let buffer=Buffer.alloc(8192),{bytesRead}=await handle.read(buffer,0,buffer.length,0),head=buffer.toString("utf-8",0,bytesRead);for(let line of head.split(`
|
|
438
|
+
`).count===0)throw Error(`Team "${teamName}" not found.`)}var init_team_manager=__esm(()=>{init_agent_registry();init_audit();init_builtin_agents();init_claude_native_teams();init_db();init_executor_registry();init_genie_config2();init_tmux()});var exports_claude_native_teams={};__export(exports_claude_native_teams,{writeNativeInbox:()=>writeNativeInbox,unregisterNativeMember:()=>unregisterNativeMember,sanitizeTeamName:()=>sanitizeTeamName,resolveNativeMemberName:()=>resolveNativeMemberName,registerNativeMember:()=>registerNativeMember,registerAsTeamLead:()=>registerAsTeamLead,loadNativeTeamConfig:()=>loadNativeTeamConfig,loadConfig:()=>loadConfig,loadAllNativeTeamConfigs:()=>loadAllNativeTeamConfigs,listTeamsWithUnreadInbox:()=>listTeamsWithUnreadInbox,listTeams:()=>listTeams2,isInsideClaudeCode:()=>isInsideClaudeCode,findTeamsContainingAgent:()=>findTeamsContainingAgent,ensureNativeTeamWithSessionId:()=>ensureNativeTeamWithSessionId,ensureNativeTeam:()=>ensureNativeTeam,discoverTeamName:()=>discoverTeamName,discoverClaudeParentSessionId:()=>discoverClaudeParentSessionId,deleteNativeTeam:()=>deleteNativeTeam,clearNativeInbox:()=>clearNativeInbox,assignColor:()=>assignColor});import{existsSync as existsSync11}from"fs";import{mkdir as mkdir3,open,readFile as readFile3,readdir,rm as rm2,stat,writeFile as writeFile3}from"fs/promises";import{homedir as homedir8}from"os";import{join as join13}from"path";function claudeConfigDir2(){return process.env.CLAUDE_CONFIG_DIR??join13(homedir8(),".claude")}function teamsBaseDir(){return join13(claudeConfigDir2(),"teams")}function sanitizeTeamName(name){return name.replace(/[^a-zA-Z0-9]/g,"-").toLowerCase()}async function listTeams2(){try{return(await readdir(teamsBaseDir())).filter((e)=>!e.startsWith("."))}catch{return[]}}function teamDir(teamName){return join13(teamsBaseDir(),sanitizeTeamName(teamName))}function configPath(teamName){return join13(teamDir(teamName),"config.json")}function inboxesDir(teamName){return join13(teamDir(teamName),"inboxes")}function inboxPath(teamName,agentName){return join13(inboxesDir(teamName),`${sanitizeTeamName(agentName)}.json`)}async function loadConfig(teamName){try{let content=await readFile3(configPath(teamName),"utf-8");return JSON.parse(content)}catch(err){if(err instanceof Error&&"code"in err&&err.code==="ENOENT")return null;let message=err instanceof Error?err.message:String(err);return console.warn(`[claude-native-teams] Failed to load config for "${teamName}": ${message}`),null}}async function loadNativeTeamConfig(teamName){return loadConfig(teamName)}async function loadAllNativeTeamConfigs(){let teamNames=await listTeams2(),configs=[];for(let name of teamNames){let cfg=await loadConfig(name);if(cfg)configs.push(cfg)}return configs}async function findTeamsContainingAgent(agentName){let teams=await listTeams2(),matches=[];for(let teamName of teams){let config=await loadConfig(teamName);if(!config)continue;if(config.members.some((m)=>m.name===agentName||m.agentType===agentName))matches.push(teamName)}return matches}async function saveConfig(teamName,config){await writeFile3(configPath(teamName),JSON.stringify(config,null,2))}async function countLeadSessionRefs(){let counts=new Map,teams=await listTeams2();for(let team of teams){let leadSessionId=(await loadConfig(team))?.leadSessionId;if(!leadSessionId)continue;counts.set(leadSessionId,(counts.get(leadSessionId)??0)+1)}return counts}async function ensureNativeTeam(teamName,description,leadSessionId,leaderName){let dir=teamDir(teamName),inboxDir=inboxesDir(teamName);await mkdir3(dir,{recursive:!0}),await mkdir3(inboxDir,{recursive:!0}),ensureClaudeSettingsSafe();let existing=await loadConfig(teamName);if(existing)return await backfillTeamRow(sanitizeTeamName(teamName),existing),existing;let sanitized=sanitizeTeamName(teamName),resolvedLeader=sanitizeTeamName(leaderName??teamName),config={name:sanitized,description,createdAt:Date.now(),leadAgentId:`${resolvedLeader}@${sanitized}`,leadSessionId,members:[]};return await saveConfig(teamName,config),await backfillTeamRow(sanitized,config),config}async function backfillTeamRow(name,nativeConfig){try{let{ensureTeamRow:ensureTeamRow2}=await Promise.resolve().then(() => (init_team_manager(),exports_team_manager));await ensureTeamRow2(name,{nativeConfig})}catch{}}function isHealthyLeadSessionId(id){if(typeof id!=="string"||id.length===0)return!1;return/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id)}async function ensureNativeTeamWithSessionId(teamName,description,sessionId,leaderName){let config=await ensureNativeTeam(teamName,description,sessionId,leaderName);if(config.leadSessionId===sessionId)return config;if(isHealthyLeadSessionId(config.leadSessionId))return config;return config.leadSessionId=sessionId,await saveConfig(teamName,config),config}async function registerNativeMember(teamName,member){let config=await loadConfig(teamName);if(!config)throw Error(`Native team "${teamName}" not found`);let sanitized=sanitizeTeamName(teamName),agentId=`${sanitizeTeamName(member.agentName)}@${sanitized}`;config.members=config.members.filter((m)=>m.agentId!==agentId),config.members.push({agentId,name:sanitizeTeamName(member.agentName),agentType:member.agentType??"general-purpose",joinedAt:Date.now(),tmuxPaneId:member.tmuxPaneId,cwd:member.cwd??process.cwd(),backendType:"tmux",color:member.color,planModeRequired:member.planModeRequired??!1,isActive:!0}),await saveConfig(teamName,config);let inbox=inboxPath(teamName,member.agentName);if(!existsSync11(inbox))await writeFile3(inbox,"[]")}async function unregisterNativeMember(teamName,agentName){let config=await loadConfig(teamName);if(!config)return;let sanitized=sanitizeTeamName(teamName),agentId=`${sanitizeTeamName(agentName)}@${sanitized}`,before=config.members.length;if(config.members=config.members.filter((m)=>m.agentId!==agentId),config.members.length===before)return;await saveConfig(teamName,config)}async function writeNativeInbox(teamName,agentName,message){let path2=inboxPath(teamName,agentName);await mkdir3(inboxesDir(teamName),{recursive:!0}),await acquireLock(path2);try{let messages=[];try{let content=await readFile3(path2,"utf-8");messages=JSON.parse(content)}catch{}messages.push(message),await writeFile3(path2,JSON.stringify(messages,null,2))}finally{await releaseLock(path2)}}async function resolveNativeMemberName(teamName,genieWorkerId){let config=await loadConfig(teamName);if(!config||config.members.length===0)return null;let sanitizedId=sanitizeTeamName(genieWorkerId),sanitizedTeam=sanitizeTeamName(teamName),exactMatch=config.members.find((m)=>m.name===sanitizedId&&m.isActive);if(exactMatch)return exactMatch.name;let agentIdMatch=config.members.find((m)=>m.agentId===`${sanitizedId}@${sanitizedTeam}`&&m.isActive);if(agentIdMatch)return agentIdMatch.name;let teamPrefix=`${sanitizedTeam}-`;if(sanitizedId.startsWith(teamPrefix)){let stripped=sanitizedId.slice(teamPrefix.length),prefixMatch=config.members.find((m)=>m.name===stripped&&m.isActive);if(prefixMatch)return prefixMatch.name}let inactiveMatch=config.members.find((m)=>m.name===sanitizedId);if(inactiveMatch)return inactiveMatch.name;return null}async function assignColor(teamName){let config=await loadConfig(teamName);if(!config)return CLAUDE_TEAM_COLORS[0];let usedColors=new Set(config.members.map((m)=>m.color));for(let color of CLAUDE_TEAM_COLORS)if(!usedColors.has(color))return color;return CLAUDE_TEAM_COLORS[config.members.length%CLAUDE_TEAM_COLORS.length]}async function clearNativeInbox(teamName,agentName){let path2=inboxPath(teamName,agentName);await acquireLock(path2);try{await writeFile3(path2,"[]")}finally{await releaseLock(path2)}}async function deleteNativeTeam(teamName){let dir=teamDir(teamName);if(!existsSync11(dir))return!1;return await rm2(dir,{recursive:!0,force:!0}),!0}function extractLeaderInboxName(config,teamName){if(!config?.leadAgentId)return teamName??"unknown";let atIdx=config.leadAgentId.indexOf("@");return atIdx>0?config.leadAgentId.slice(0,atIdx):teamName??"unknown"}function resolveLeadWorkingDir(config,leaderInboxName){let leadMember=config.members.find((m)=>m.agentId===config.leadAgentId||m.name===leaderInboxName);if(leadMember?.cwd)return leadMember.cwd;if(config.worktreePath)return config.worktreePath;if(config.repo)return config.repo;return config.members.find((m)=>m.cwd)?.cwd??null}async function scanTeamInbox(base,name){let config=null;try{let cfgContent=await readFile3(join13(base,name,"config.json"),"utf-8");config=JSON.parse(cfgContent)}catch{}let leaderInboxName=extractLeaderInboxName(config,name),inboxFile=join13(base,name,"inboxes",`${leaderInboxName}.json`),messages;try{let content=await readFile3(inboxFile,"utf-8");messages=JSON.parse(content)}catch{return null}if(!Array.isArray(messages))return null;let unread=messages.filter((m)=>m.read===!1);if(unread.length===0)return null;let workingDir=config?resolveLeadWorkingDir(config,leaderInboxName):null;return{teamName:name,unreadCount:unread.length,workingDir,firstUnreadText:unread[0]?.text??null}}async function listTeamsWithUnreadInbox(){let base=teamsBaseDir(),teamDirs;try{teamDirs=await readdir(base)}catch{return[]}let results=[];for(let name of teamDirs){let entry=await scanTeamInbox(base,name);if(entry)results.push(entry)}return results}function sanitizePath(p){return p.replace(/[^a-zA-Z0-9]/g,"-")}async function discoverClaudeSessionId(cwd){let envSessionId=process.env.CLAUDE_CODE_SESSION_ID;if(envSessionId)return envSessionId;let projectDir=join13(claudeConfigDir2(),"projects",sanitizePath(cwd??process.cwd()));try{let jsonls=(await readdir(projectDir)).filter((e)=>e.endsWith(".jsonl"));if(jsonls.length===0)return null;let newest=null;for(let name of jsonls){let s=await stat(join13(projectDir,name));if(!newest||s.mtimeMs>newest.mtime)newest={name,mtime:s.mtimeMs}}if(!newest)return null;return newest.name.replace(".jsonl","")}catch{return null}}async function readSessionMetadata(filePath){let handle=null;try{handle=await open(filePath,"r");let buffer=Buffer.alloc(8192),{bytesRead}=await handle.read(buffer,0,buffer.length,0),head=buffer.toString("utf-8",0,bytesRead);for(let line of head.split(`
|
|
439
439
|
`).slice(0,20)){let trimmed=line.trim();if(!trimmed)continue;try{let entry=JSON.parse(trimmed),teamName=typeof entry.teamName==="string"?entry.teamName:void 0,agentName=typeof entry.agentName==="string"?entry.agentName:void 0;if(teamName||agentName)return{teamName,agentName}}catch{}}}catch{return{}}finally{await handle?.close().catch(()=>{})}return{}}function rootScore(metadata){if(!metadata.teamName&&!metadata.agentName)return 2;if(metadata.teamName&&!metadata.agentName)return 1;return 0}function compareSessionRanking(a,b,leadRefs){let aLeadRefs=leadRefs.get(a.name.replace(".jsonl",""))??0,bLeadRefs=leadRefs.get(b.name.replace(".jsonl",""))??0;if(aLeadRefs!==bLeadRefs)return bLeadRefs-aLeadRefs;let aRoot=rootScore(a.metadata),bRoot=rootScore(b.metadata);if(aRoot!==bRoot)return bRoot-aRoot;return b.mtime-a.mtime}async function discoverClaudeParentSessionId(cwd){let envSessionId=process.env.CLAUDE_CODE_SESSION_ID;if(envSessionId)return envSessionId;let projectDir=join13(claudeConfigDir2(),"projects",sanitizePath(cwd??process.cwd()));try{let jsonls=(await readdir(projectDir)).filter((e)=>e.endsWith(".jsonl"));if(jsonls.length===0)return null;let ranked=await Promise.all(jsonls.map(async(name)=>{let filePath=join13(projectDir,name),s=await stat(filePath),metadata=await readSessionMetadata(filePath);return{name,mtime:s.mtimeMs,metadata}})),leadRefs=await countLeadSessionRefs();return ranked.sort((a,b)=>compareSessionRanking(a,b,leadRefs)),ranked[0]?.name.replace(".jsonl","")??null}catch{return null}}function isInsideClaudeCode(){return process.env.CLAUDECODE==="1"}async function discoverTeamName(cwd){let envTeam=process.env.GENIE_TEAM;if(envTeam)return envTeam;let base=teamsBaseDir(),sessionId=await discoverClaudeSessionId(cwd);if(sessionId)try{let teams=await readdir(base);for(let name of teams){let cfgPath=join13(base,name,"config.json");try{let content=await readFile3(cfgPath,"utf-8"),config=JSON.parse(content);if(config.leadSessionId===sessionId)return config.name}catch{}}}catch{}let tmuxSessionName=await currentTmuxSessionName();if(tmuxSessionName){let cfgPath=join13(base,tmuxSessionName,"config.json");try{let content=await readFile3(cfgPath,"utf-8");return JSON.parse(content).name}catch{}}return null}async function currentTmuxSessionName(){if(!process.env.TMUX)return null;try{let{getCurrentSessionName:getCurrentSessionName2}=await Promise.resolve().then(() => (init_tmux(),exports_tmux));return await getCurrentSessionName2()}catch{return null}}async function registerAsTeamLead(teamName,opts){let sessionId=await discoverClaudeSessionId(opts?.cwd);if(!sessionId)throw Error("Could not discover Claude Code session ID. Are you running inside Claude Code with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1?");let resolvedLeaderName=opts?.leaderName??teamName,config=await ensureNativeTeam(teamName,`Genie team: ${teamName}`,sessionId,resolvedLeaderName);if(config.leadSessionId!==sessionId)config.leadSessionId=sessionId,await saveConfig(teamName,config);let sanitized=sanitizeTeamName(teamName),leadAgentId=`${sanitizeTeamName(resolvedLeaderName)}@${sanitized}`,existingLead=config.members.find((m)=>m.agentId===leadAgentId),resolvedPaneId=opts?.tmuxPaneId??process.env.TMUX_PANE;if(!existingLead||!existingLead.isActive)await registerNativeMember(teamName,{agentName:resolvedLeaderName,agentType:"general-purpose",color:opts?.color??"blue",tmuxPaneId:resolvedPaneId,cwd:opts?.cwd??process.cwd()});else if(resolvedPaneId&&existingLead.tmuxPaneId!==resolvedPaneId)existingLead.tmuxPaneId=resolvedPaneId,await saveConfig(teamName,config);let inbox=inboxPath(teamName,resolvedLeaderName);if(!existsSync11(inbox))await writeFile3(inbox,"[]");let finalConfig=await loadConfig(teamName);if(!finalConfig)throw Error(`Failed to load config for team "${teamName}" after creation`);return{sessionId,config:finalConfig}}var init_claude_native_teams=__esm(()=>{init_claude_settings();init_lockfile();init_provider_adapters()});import{existsSync as existsSync12}from"fs";import{readFile as readFile4,readdir as readdir2,rename}from"fs/promises";import{homedir as homedir9}from"os";import{join as join14}from"path";function getGenieHome(){return process.env.GENIE_HOME??join14(homedir9(),".genie")}function workersJsonPath(){return join14(getGenieHome(),"workers.json")}function needsMigration(filePath){return existsSync12(filePath)&&!existsSync12(`${filePath}.migrated`)}async function readJson(filePath){try{let content=await readFile4(filePath,"utf-8");return JSON.parse(content)}catch{return null}}async function renameMatchingFiles(dir,filter){if(!existsSync12(dir))return;try{let files=await readdir2(dir);for(let f of files){if(!filter(f))continue;let fp=join14(dir,f);if(needsMigration(fp))await rename(fp,`${fp}.migrated`)}}catch{}}function needsSeed(){if(needsMigration(workersJsonPath()))return!0;let claudeTeamsDir=join14(process.env.CLAUDE_CONFIG_DIR??join14(homedir9(),".claude"),"teams");if(!existsSync12(claudeTeamsDir))return!1;try{return __require("fs").readdirSync(claudeTeamsDir).some((e)=>!e.startsWith("."))}catch{return!1}}function toAgentRow(a){let now=new Date().toISOString();return{id:a.id,pane_id:a.paneId??"",session:a.session??"",worktree:a.worktree??null,task_id:a.taskId??null,task_title:a.taskTitle??null,wish_slug:a.wishSlug??null,group_number:a.groupNumber??null,started_at:a.startedAt??now,state:a.state??"spawning",last_state_change:a.lastStateChange??now,repo_path:a.repoPath??"",window_name:a.windowName??null,window_id:a.windowId??null,role:a.role??null,custom_name:a.customName??null,sub_panes:a.subPanes??[],provider:a.provider??null,transport:a.transport??"tmux",skill:a.skill??null,team:a.team??null,tmux_window:a.window??null,native_agent_id:a.nativeAgentId??null,native_color:a.nativeColor??null,native_team_enabled:a.nativeTeamEnabled??!1,parent_session_id:a.parentSessionId??null,suspended_at:a.suspendedAt??null,auto_resume:a.autoResume??!0,resume_attempts:a.resumeAttempts??0,last_resume_attempt:a.lastResumeAttempt??null,max_resume_attempts:a.maxResumeAttempts??3,pane_color:null}}async function upsertAgent(sql,a){let r=toAgentRow(a);await sql`
|
|
440
440
|
INSERT INTO agents (
|
|
441
441
|
id, pane_id, session, worktree, task_id, task_title,
|
|
@@ -1289,7 +1289,7 @@ promptMode: append
|
|
|
1289
1289
|
color: cyan
|
|
1290
1290
|
effort: high
|
|
1291
1291
|
thinking: enabled
|
|
1292
|
-
permissionMode:
|
|
1292
|
+
permissionMode: auto
|
|
1293
1293
|
---
|
|
1294
1294
|
|
|
1295
1295
|
@HEARTBEAT.md
|
|
@@ -1366,7 +1366,7 @@ Stopping inbox watcher...`),stopInboxWatcher2(handle),process.exit(0)};process.o
|
|
|
1366
1366
|
ORDER BY created_at ASC
|
|
1367
1367
|
`}async function pollApprovalState(approvalId,defaultAction){let sql=await getConnection(),[approval]=await sql`
|
|
1368
1368
|
SELECT decision, timeout_at FROM approvals WHERE id = ${approvalId}
|
|
1369
|
-
`;if(!approval)return"deny";if(approval.decision==="allow"||approval.decision==="deny")return approval.decision;if(new Date(approval.timeout_at)<=new Date)return await resolveApproval(approvalId,defaultAction,"timeout"),defaultAction;return null}async function waitForResolution(approvalId,timeoutAt,defaultAction){let sql=await getConnection();return new Promise((resolve5)=>{let resolved=!1,listener=null,pollTimer=null,finish=(decision)=>{if(resolved)return;if(resolved=!0,listener)listener.unlisten().catch(()=>{});if(pollTimer)clearInterval(pollTimer);resolve5(decision)},checkResolution=async()=>{if(resolved)return;try{let result2=await pollApprovalState(approvalId,defaultAction);if(result2!==null)finish(result2)}catch{finish("deny")}};sql.listen("genie_approval_resolved",(payload)=>{if(payload===approvalId)checkResolution()}).then((l)=>{if(listener=l,resolved)l.unlisten().catch(()=>{})}).catch(()=>{}),pollTimer=setInterval(checkResolution,5000);let msUntilTimeout=Math.max(0,timeoutAt.getTime()-Date.now()+1000);setTimeout(()=>{if(!resolved)resolveApproval(approvalId,defaultAction,"timeout").catch(()=>{}),finish(defaultAction)},msUntilTimeout).unref(),checkResolution()})}function createRemoteApprovalGate(config){let timeoutSec=config.permissions?.timeout??300,defaultAction=config.permissions?.defaultAction??"deny";return async(input)=>{let hookInput=input,toolName=hookInput.tool_name,toolInput=hookInput.tool_input??{},preview=JSON.stringify(toolInput).slice(0,500),timeoutAt=new Date(Date.now()+timeoutSec*1000),approvalId=await insertApproval(config.executorId,config.agentName,toolName,preview,timeoutAt);if(config.permissions?.omniChat&&config.permissions?.omniInstance)sendApprovalToOmni(approvalId,config.agentName,toolName,preview,config.permissions).catch(()=>{});return{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:await waitForResolution(approvalId,timeoutAt,defaultAction)}}}}var recentOmniSends,BATCH_WINDOW_MS=1e4,BATCH_THRESHOLD=3;var init_claude_sdk_remote_approval=__esm(()=>{init_db();recentOmniSends=[]});var exports_claude_sdk={};__export(exports_claude_sdk,{translateSdkConfig:()=>translateSdkConfig,ClaudeSdkProvider:()=>ClaudeSdkProvider});import{readFileSync as readFileSync20}from"fs";import{query}from"@anthropic-ai/claude-agent-sdk";function translateSdkConfig(sdkConfig){let opts={};for(let key of SDK_TRUTHY_FIELDS)if(sdkConfig[key])opts[key]=sdkConfig[key];for(let key of SDK_NULLABLE_FIELDS)if(sdkConfig[key]!=null)opts[key]=sdkConfig[key];for(let key of SDK_CAST_FIELDS)if(sdkConfig[key])opts[key]=sdkConfig[key];return opts}function mergeHooks(...sources){let merged={};for(let src of sources){if(!src)continue;for(let[event,matchers]of Object.entries(src)){if(!matchers)continue;if(!merged[event])merged[event]=[...matchers];else merged[event].push(...matchers)}}return merged}class ClaudeSdkProvider{name="claude-sdk";transport="process";activeQueries=new Map;buildSpawnCommand(ctx){return{command:"claude-sdk-in-process",provider:"claude-sdk",meta:{role:ctx.role,skill:ctx.skill}}}runQuery(ctx,prompt2,permissionConfig,extraOptions,sdkConfig){
|
|
1369
|
+
`;if(!approval)return"deny";if(approval.decision==="allow"||approval.decision==="deny")return approval.decision;if(new Date(approval.timeout_at)<=new Date)return await resolveApproval(approvalId,defaultAction,"timeout"),defaultAction;return null}async function waitForResolution(approvalId,timeoutAt,defaultAction){let sql=await getConnection();return new Promise((resolve5)=>{let resolved=!1,listener=null,pollTimer=null,finish=(decision)=>{if(resolved)return;if(resolved=!0,listener)listener.unlisten().catch(()=>{});if(pollTimer)clearInterval(pollTimer);resolve5(decision)},checkResolution=async()=>{if(resolved)return;try{let result2=await pollApprovalState(approvalId,defaultAction);if(result2!==null)finish(result2)}catch{finish("deny")}};sql.listen("genie_approval_resolved",(payload)=>{if(payload===approvalId)checkResolution()}).then((l)=>{if(listener=l,resolved)l.unlisten().catch(()=>{})}).catch(()=>{}),pollTimer=setInterval(checkResolution,5000);let msUntilTimeout=Math.max(0,timeoutAt.getTime()-Date.now()+1000);setTimeout(()=>{if(!resolved)resolveApproval(approvalId,defaultAction,"timeout").catch(()=>{}),finish(defaultAction)},msUntilTimeout).unref(),checkResolution()})}function createRemoteApprovalGate(config){let timeoutSec=config.permissions?.timeout??300,defaultAction=config.permissions?.defaultAction??"deny";return async(input)=>{let hookInput=input,toolName=hookInput.tool_name,toolInput=hookInput.tool_input??{},preview=JSON.stringify(toolInput).slice(0,500),timeoutAt=new Date(Date.now()+timeoutSec*1000),approvalId=await insertApproval(config.executorId,config.agentName,toolName,preview,timeoutAt);if(config.permissions?.omniChat&&config.permissions?.omniInstance)sendApprovalToOmni(approvalId,config.agentName,toolName,preview,config.permissions).catch(()=>{});return{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:await waitForResolution(approvalId,timeoutAt,defaultAction)}}}}var recentOmniSends,BATCH_WINDOW_MS=1e4,BATCH_THRESHOLD=3;var init_claude_sdk_remote_approval=__esm(()=>{init_db();recentOmniSends=[]});var exports_claude_sdk={};__export(exports_claude_sdk,{translateSdkConfig:()=>translateSdkConfig,ClaudeSdkProvider:()=>ClaudeSdkProvider});import{readFileSync as readFileSync20}from"fs";import{query}from"@anthropic-ai/claude-agent-sdk";function translateSdkConfig(sdkConfig){let opts={};for(let key of SDK_TRUTHY_FIELDS)if(sdkConfig[key])opts[key]=sdkConfig[key];for(let key of SDK_NULLABLE_FIELDS)if(sdkConfig[key]!=null)opts[key]=sdkConfig[key];for(let key of SDK_CAST_FIELDS)if(sdkConfig[key])opts[key]=sdkConfig[key];return opts}function mergeHooks(...sources){let merged={};for(let src of sources){if(!src)continue;for(let[event,matchers]of Object.entries(src)){if(!matchers)continue;if(!merged[event])merged[event]=[...matchers];else merged[event].push(...matchers)}}return merged}class ClaudeSdkProvider{name="claude-sdk";transport="process";activeQueries=new Map;buildSpawnCommand(ctx){return{command:"claude-sdk-in-process",provider:"claude-sdk",meta:{role:ctx.role,skill:ctx.skill}}}runQuery(ctx,prompt2,permissionConfig,extraOptions,sdkConfig){ensureClaudeSettingsSafe();let abortController=new AbortController,tracker={abortController,done:!1};this.activeQueries.set(ctx.executorId,tracker);let permHooks;if(sdkConfig?.permissionMode==="remoteApproval"){let ws=findWorkspace(ctx.cwd),permissions=ws?getWorkspaceConfig(ws.root).permissions:void 0;permHooks={PreToolUse:[{matcher:"*",hooks:[createRemoteApprovalGate({executorId:ctx.executorId,agentName:ctx.agentId??ctx.role??"unknown",permissions})]}]}}else if(permissionConfig)permHooks={PreToolUse:[{matcher:"*",hooks:[createPermissionGate(permissionConfig)]}]};let translatedSdk=sdkConfig?translateSdkConfig(sdkConfig):void 0,mergedHooks=mergeHooks(permHooks,translatedSdk?.hooks,extraOptions?.hooks),hasHooks=Object.keys(mergedHooks).length>0,resolvedSystemPrompt=ctx.systemPrompt;if(!resolvedSystemPrompt&&ctx.systemPromptFile)try{resolvedSystemPrompt=readFileSync20(ctx.systemPromptFile,"utf-8")}catch{}let options={cwd:ctx.cwd,abortController,...ctx.model&&{model:ctx.model},...resolvedSystemPrompt&&{systemPrompt:resolvedSystemPrompt},...translatedSdk,...extraOptions,...hasHooks&&{hooks:mergedHooks},permissionMode:"auto",allowDangerouslySkipPermissions:!0},messages2=query({prompt:prompt2,options}),originalReturn=messages2.return.bind(messages2);messages2.return=async(value)=>{return tracker.done=!0,this.activeQueries.delete(ctx.executorId),originalReturn(value)};let self2=this,wrappedMessages=async function*(){try{for await(let msg of messages2)yield msg,routeSdkMessage(msg,ctx.executorId,ctx.agentId).catch(()=>{})}finally{tracker.done=!0,self2.activeQueries.delete(ctx.executorId)}}();return wrappedMessages.interrupt=messages2.interrupt.bind(messages2),wrappedMessages.setPermissionMode=messages2.setPermissionMode.bind(messages2),wrappedMessages.setModel=messages2.setModel.bind(messages2),wrappedMessages.return=messages2.return.bind(messages2),wrappedMessages.throw=messages2.throw.bind(messages2),{messages:wrappedMessages,abortController}}async extractSession(executor){let sessionId=executor.claudeSessionId;if(!sessionId)return null;return{sessionId}}async detectState(executor){let tracker=this.activeQueries.get(executor.id);if(!tracker)return"done";return tracker.done?"done":"running"}async terminate(executor){let tracker=this.activeQueries.get(executor.id);if(tracker)tracker.abortController.abort(),tracker.done=!0,this.activeQueries.delete(executor.id)}canResume(){return!1}}var SDK_TRUTHY_FIELDS,SDK_NULLABLE_FIELDS,SDK_CAST_FIELDS;var init_claude_sdk=__esm(()=>{init_claude_settings();init_workspace();init_claude_sdk_events();init_claude_sdk_permissions();init_claude_sdk_remote_approval();SDK_TRUTHY_FIELDS=["tools","allowedTools","disallowedTools","plugins","systemPrompt","betas","settingSources"],SDK_NULLABLE_FIELDS=["maxTurns","maxBudgetUsd","persistSession","enableFileCheckpointing","includePartialMessages","includeHookEvents","promptSuggestions","agentProgressSummaries"],SDK_CAST_FIELDS=["effort","thinking","agents","mcpServers","outputFormat","sandbox","settings"]});class CodexProvider{name="codex";transport="api";buildSpawnCommand(ctx){let params=spawnContextToParams3(ctx);return buildCodexCommand(params)}async extractSession(_executor){return null}async detectState(executor){if(executor.state==="terminated"||executor.endedAt)return"terminated";return"working"}async terminate(executor){if(executor.pid)try{process.kill(executor.pid,"SIGTERM")}catch{}}canResume(){return!1}async deliverMessage(_executorId,_message){}}function spawnContextToParams3(ctx){return{provider:"codex",team:ctx.team,role:ctx.role,skill:ctx.skill,agentId:ctx.agentId,executorId:ctx.executorId,extraArgs:ctx.extraArgs}}var init_codex=__esm(()=>{init_provider_adapters()});function getProvider(name){return providers.get(name)}var providers,claude,codex,appPty,claudeSdk;var init_registry2=__esm(()=>{init_app_pty();init_claude_code();init_claude_sdk();init_codex();providers=new Map;claude=new ClaudeCodeProvider,codex=new CodexProvider,appPty=new AppPtyProvider,claudeSdk=new ClaudeSdkProvider;providers.set("claude",claude);providers.set("codex",codex);providers.set("app-pty",appPty);providers.set("claude-sdk",claudeSdk)});var exports_wish_state={};__export(exports_wish_state,{wipeState:()=>wipeState,startGroup:()=>startGroup,resolveRepoPath:()=>resolveRepoPath,resetInProgressGroups:()=>resetInProgressGroups,resetGroup:()=>resetGroup,isWishComplete:()=>isWishComplete,getState:()=>getState,getOrCreateState:()=>getOrCreateState,getGroupState:()=>getGroupState,findGroupByAssignee:()=>findGroupByAssignee,findAnyGroupByAssignee:()=>findAnyGroupByAssignee,createState:()=>createState,computeGroupsSignature:()=>computeGroupsSignature,completeGroup:()=>completeGroup,WishStateMismatchError:()=>WishStateMismatchError});import{execSync as execSync9}from"child_process";import{createHash as createHash5}from"crypto";import{existsSync as existsSync31}from"fs";import{dirname as dirname7}from"path";function computeGroupsSignature(groups){let canonical=groups.map((g)=>({name:g.name,dependsOn:[...g.dependsOn??[]].sort()})).sort((a,b2)=>a.name<b2.name?-1:a.name>b2.name?1:0);return createHash5("sha256").update(JSON.stringify(canonical)).digest("hex")}function diffGroups(prev,next){let prevMap=new Map(prev.map((g)=>[g.name,[...g.dependsOn??[]].sort()])),nextMap=new Map(next.map((g)=>[g.name,[...g.dependsOn??[]].sort()])),added=[],removed=[],changed=[];for(let[name,deps]of nextMap)if(!prevMap.has(name))added.push(name);else if(JSON.stringify(prevMap.get(name))!==JSON.stringify(deps))changed.push(name);for(let name of prevMap.keys())if(!nextMap.has(name))removed.push(name);return{added:added.sort(),removed:removed.sort(),changed:changed.sort()}}function normalizeGitPath(path3){if(process.platform!=="darwin")return path3;if(!path3.startsWith("/private/"))return path3;let logicalPath=path3.slice(8);return existsSync31(logicalPath)?logicalPath:path3}function resolveRepoPath(cwd){if(cwd)return cwd;try{let currentDir=process.cwd(),commonDir=execSync9("git rev-parse --path-format=absolute --git-common-dir",{encoding:"utf-8",stdio:["pipe","pipe","pipe"],env:{...process.env,GIT_CEILING_DIRECTORIES:dirname7(currentDir)}}).trim();return normalizeGitPath(dirname7(commonDir))}catch{return normalizeGitPath(process.cwd())}}function wishFilePath(slug){return`.genie/wishes/${slug}/WISH.md`}function toISO(v){if(v==null)return;if(v instanceof Date)return v.toISOString();return String(v)}async function findParent(sql,slug,repoPath){let wishFile=wishFilePath(slug),rows=await sql`
|
|
1370
1370
|
SELECT * FROM tasks
|
|
1371
1371
|
WHERE wish_file = ${wishFile} AND repo_path = ${repoPath} AND parent_id IS NULL
|
|
1372
1372
|
LIMIT 1
|
|
@@ -3988,7 +3988,7 @@ coverage
|
|
|
3988
3988
|
`)}function formatWelcome(ctx){let lines=["",` Workspace: ${ctx.workspaceName}`,` Agents: ${ctx.canonicalAgentCount} registered`];if(ctx.discovered.length>0)lines.push(` Discovered: ${ctx.discovered.length} external agent(s) found`);return lines.push(""),lines.push(" Effective defaults:"),lines.push(formatDefaults(ctx.config.agents?.defaults)),lines.push(""),lines.join(`
|
|
3989
3989
|
`)}function formatNextSteps(ctx){let lines=[""," Next steps:"];if(ctx.canonicalAgentCount===0)lines.push(" genie init agent <name> Scaffold your first agent");return lines.push(" genie spawn <agent> Launch an agent"),lines.push(" genie team create <name> Create a multi-agent team"),lines.push(" /wizard Full guided onboarding"),lines.push(""),lines.join(`
|
|
3990
3990
|
`)}var MODEL_CHOICES=[{name:"opus (most capable)",value:"opus"},{name:"sonnet (balanced)",value:"sonnet"},{name:"haiku (fastest)",value:"haiku"}];async function runMiniWizard(ctx){let{confirm:confirm2}=await Promise.resolve().then(() => (init_esm14(),exports_esm));console.log(formatWelcome(ctx));let wantCustomize=await confirm2({message:"Customize workspace defaults?",default:!1}),result2={customized:!1,importedAgents:[],completed:!0};if(wantCustomize){let newDefaults=await customizeDefaults(ctx.config.agents?.defaults);if(newDefaults)result2.customized=!0,result2.defaults=newDefaults,persistDefaults(ctx.workspaceRoot,newDefaults)}if(ctx.pending.length>0){console.log(`
|
|
3991
|
-
Found ${ctx.pending.length} agent(s) in your project tree:`);for(let agent of ctx.pending)console.log(` ${agent.name} (${agent.relativePath})`);if(await confirm2({message:"Import discovered agents into workspace?",default:!0}))result2.importedAgents=ctx.pending.map((a)=>a.name)}return console.log(formatNextSteps(ctx)),result2}async function customizeDefaults(currentDefaults){let{select:select2}=await Promise.resolve().then(() => (init_esm14(),exports_esm)),effective=computeEffectiveDefaults(currentDefaults),updates={},changed=!1,model=await select2({message:"Default model:",choices:MODEL_CHOICES,default:effective.model});if(model!==BUILTIN_DEFAULTS.model)updates.model=model,changed=!0;let permissionMode=await select2({message:"Default permission mode:",choices:[{name:"default (ask for risky tools)",value:"default"},{name:"plan (require plan approval)",value:"plan"},{name:"bypassPermissions (auto-approve all)",value:"bypassPermissions"}],default:effective.permissionMode});if(permissionMode!==BUILTIN_DEFAULTS.permissionMode)updates.permissionMode=permissionMode,changed=!0;return changed?updates:null}function persistDefaults(workspaceRoot,newDefaults){let configPath2=join59(workspaceRoot,".genie","workspace.json");try{let raw=readFileSync33(configPath2,"utf-8"),config=JSON.parse(raw);if(!config.agents)config.agents={};if(!config.agents.defaults)config.agents.defaults={};Object.assign(config.agents.defaults,newDefaults),writeFileSync23(configPath2,`${JSON.stringify(config,null,2)}
|
|
3991
|
+
Found ${ctx.pending.length} agent(s) in your project tree:`);for(let agent of ctx.pending)console.log(` ${agent.name} (${agent.relativePath})`);if(await confirm2({message:"Import discovered agents into workspace?",default:!0}))result2.importedAgents=ctx.pending.map((a)=>a.name)}return console.log(formatNextSteps(ctx)),result2}async function customizeDefaults(currentDefaults){let{select:select2}=await Promise.resolve().then(() => (init_esm14(),exports_esm)),effective=computeEffectiveDefaults(currentDefaults),updates={},changed=!1,model=await select2({message:"Default model:",choices:MODEL_CHOICES,default:effective.model});if(model!==BUILTIN_DEFAULTS.model)updates.model=model,changed=!0;let permissionMode=await select2({message:"Default permission mode:",choices:[{name:"auto (tool-by-tool judgment \u2014 default)",value:"auto"},{name:"default (ask for risky tools)",value:"default"},{name:"plan (require plan approval)",value:"plan"},{name:"bypassPermissions (auto-approve all)",value:"bypassPermissions"}],default:effective.permissionMode});if(permissionMode!==BUILTIN_DEFAULTS.permissionMode)updates.permissionMode=permissionMode,changed=!0;return changed?updates:null}function persistDefaults(workspaceRoot,newDefaults){let configPath2=join59(workspaceRoot,".genie","workspace.json");try{let raw=readFileSync33(configPath2,"utf-8"),config=JSON.parse(raw);if(!config.agents)config.agents={};if(!config.agents.defaults)config.agents.defaults={};Object.assign(config.agents.defaults,newDefaults),writeFileSync23(configPath2,`${JSON.stringify(config,null,2)}
|
|
3992
3992
|
`,"utf-8"),console.log(" Workspace defaults updated.")}catch(err){console.error(` Failed to update workspace.json: ${err instanceof Error?err.message:String(err)}`)}}import{existsSync as existsSync52,mkdirSync as mkdirSync22,readFileSync as readFileSync34,writeFileSync as writeFileSync24}from"fs";import{join as join60}from"path";function pendingPath(workspaceRoot){return join60(workspaceRoot,".genie","pending-agents.json")}function loadPending(workspaceRoot){let filePath=pendingPath(workspaceRoot);if(!existsSync52(filePath))return{agents:[]};try{let raw=readFileSync34(filePath,"utf-8"),parsed=JSON.parse(raw);return{agents:Array.isArray(parsed.agents)?parsed.agents:[]}}catch{return{agents:[]}}}function savePending(workspaceRoot,store){let filePath=pendingPath(workspaceRoot);mkdirSync22(join60(workspaceRoot,".genie"),{recursive:!0}),writeFileSync24(filePath,`${JSON.stringify(store,null,2)}
|
|
3993
3993
|
`,"utf-8")}function refreshPending(workspaceRoot,discovered){let existing=loadPending(workspaceRoot),dismissedSet=new Set(existing.agents.filter((a)=>a.dismissed).map((a)=>a.path)),now=new Date().toISOString(),store={agents:discovered.map((d)=>({name:d.name,path:d.path,relativePath:d.relativePath,isSubAgent:d.isSubAgent,parentName:d.parentName,discoveredAt:existing.agents.find((a)=>a.path===d.path)?.discoveredAt??now,dismissed:dismissedSet.has(d.path)}))};return savePending(workspaceRoot,store),store}function listPending(workspaceRoot){return loadPending(workspaceRoot).agents.filter((a)=>!a.dismissed)}function removePending(workspaceRoot,agentPath){let store=loadPending(workspaceRoot),idx=store.agents.findIndex((a)=>a.path===agentPath);if(idx===-1)return!1;return store.agents.splice(idx,1),savePending(workspaceRoot,store),!0}init_workspace();init_templates();function detectPgUrl(){if(process.env.DATABASE_URL)return process.env.DATABASE_URL;if(process.env.PG_URL)return process.env.PG_URL;try{let{execSync:execSync16}=__require("child_process"),match=execSync16("pgrep -af pgserve 2>/dev/null",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).match(/postgres(?:ql)?:\/\/[^\s]+/);if(match)return match[0]}catch{}return}async function ensureSetupCompleteForInit(){let{isSetupComplete:isSetupComplete2}=await Promise.resolve().then(() => (init_genie_config2(),exports_genie_config));if(isSetupComplete2())return;console.log("Genie setup not complete. Running `genie setup` before continuing...");let{setupCommand:setupCommand2}=await Promise.resolve().then(() => (init_setup(),exports_setup));await setupCommand2()}function scaffoldAgentInWorkspace(workspaceRoot,name,agentsDir){let baseDir=agentsDir??join61(workspaceRoot,"agents"),agentDir=join61(baseDir,name);if(existsSync53(agentDir))throw Error(`Agent directory already exists: ${agentDir}`);mkdirSync23(agentDir,{recursive:!0}),mkdirSync23(join61(agentDir,"brain","memory"),{recursive:!0}),mkdirSync23(join61(agentDir,".claude"),{recursive:!0});let workspaceDefaults;try{workspaceDefaults=getWorkspaceConfig(workspaceRoot).agents?.defaults}catch{}scaffoldAgentFiles(agentDir,name,workspaceDefaults);let settings={agentName:name,autoMemoryEnabled:!0,autoMemoryDirectory:"./brain/memory"};writeFileSync25(join61(agentDir,".claude","settings.local.json"),`${JSON.stringify(settings,null,2)}
|
|
3994
3994
|
`),writeFileSync25(join61(agentDir,"brain","memory","MEMORY.md"),`# Memory Index
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genie",
|
|
3
|
-
"version": "4.260424.
|
|
3
|
+
"version": "4.260424.6",
|
|
4
4
|
"description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, turn them into wishes, execute with /work, validate with /review, and ship as one team.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Namastex Labs"
|
package/scripts/sec-scan.cjs
CHANGED
|
@@ -259,6 +259,10 @@ const MAX_TEXT_SNIPPETS = 6;
|
|
|
259
259
|
const MAX_SNIPPET_CHARS = 240;
|
|
260
260
|
const MAX_TEMP_WALK_ENTRIES = 25000;
|
|
261
261
|
const MAX_TEMP_FINDINGS = 200;
|
|
262
|
+
const DEFAULT_TEMP_FILES_BUDGET = 500;
|
|
263
|
+
const DEFAULT_TEMP_BYTES_BUDGET = 32 * 1024 * 1024;
|
|
264
|
+
const DEFAULT_TEMP_WALL_BUDGET_MS = 2000;
|
|
265
|
+
const TEMP_YIELD_INTERVAL = 128;
|
|
262
266
|
const MAX_TIMELINE_EVENTS = 120;
|
|
263
267
|
|
|
264
268
|
const TEMP_ARTIFACT_NAME_REGEX =
|
|
@@ -322,32 +326,32 @@ const TEXT_MATCHERS = [
|
|
|
322
326
|
{
|
|
323
327
|
label: 'install:npm @automagik/genie',
|
|
324
328
|
category: 'install',
|
|
325
|
-
regex: /\bnpm\b[^\n]
|
|
329
|
+
regex: /\bnpm\b[^\n]{0,200}\b(?:install|i|add|update|exec|ci)\b[^\n]{0,200}@automagik\/genie(?:@[0-9.]+)?/i,
|
|
326
330
|
},
|
|
327
331
|
{
|
|
328
332
|
label: 'install:pnpm @automagik/genie',
|
|
329
333
|
category: 'install',
|
|
330
|
-
regex: /\bpnpm\b[^\n]
|
|
334
|
+
regex: /\bpnpm\b[^\n]{0,200}\b(?:add|install|update|up)\b[^\n]{0,200}@automagik\/genie(?:@[0-9.]+)?/i,
|
|
331
335
|
},
|
|
332
336
|
{
|
|
333
337
|
label: 'install:yarn @automagik/genie',
|
|
334
338
|
category: 'install',
|
|
335
|
-
regex: /\byarn\b[^\n]
|
|
339
|
+
regex: /\byarn\b[^\n]{0,200}\b(?:add|install|up|upgrade)\b[^\n]{0,200}@automagik\/genie(?:@[0-9.]+)?/i,
|
|
336
340
|
},
|
|
337
341
|
{
|
|
338
342
|
label: 'install:bun @automagik/genie',
|
|
339
343
|
category: 'install',
|
|
340
|
-
regex: /\bbun\b[^\n]
|
|
344
|
+
regex: /\bbun\b[^\n]{0,200}\b(?:add|install|pm add)\b[^\n]{0,200}@automagik\/genie(?:@[0-9.]+)?/i,
|
|
341
345
|
},
|
|
342
346
|
{
|
|
343
347
|
label: 'exec:npx @automagik/genie',
|
|
344
348
|
category: 'execution',
|
|
345
|
-
regex: /\bnpx\b[^\n]
|
|
349
|
+
regex: /\bnpx\b[^\n]{0,200}@automagik\/genie(?:@[0-9.]+)?/i,
|
|
346
350
|
},
|
|
347
351
|
{
|
|
348
352
|
label: 'exec:bunx @automagik/genie',
|
|
349
353
|
category: 'execution',
|
|
350
|
-
regex: /\bbunx\b[^\n]
|
|
354
|
+
regex: /\bbunx\b[^\n]{0,200}@automagik\/genie(?:@[0-9.]+)?/i,
|
|
351
355
|
},
|
|
352
356
|
{
|
|
353
357
|
label: 'exec:node_modules/@automagik/genie',
|
|
@@ -357,12 +361,12 @@ const TEXT_MATCHERS = [
|
|
|
357
361
|
{
|
|
358
362
|
label: 'exec:env-compat',
|
|
359
363
|
category: 'execution',
|
|
360
|
-
regex: /\b(?:node|bun|bash|sh)\b[^\n]
|
|
364
|
+
regex: /\b(?:node|bun|bash|sh)\b[^\n]{0,200}env-compat\.(?:cjs|js)\b/i,
|
|
361
365
|
},
|
|
362
366
|
{
|
|
363
367
|
label: 'network:curl-wget IOC',
|
|
364
368
|
category: 'network',
|
|
365
|
-
regex: /\b(?:curl|wget|fetch|Invoke-WebRequest)\b[^\n]
|
|
369
|
+
regex: /\b(?:curl|wget|fetch|Invoke-WebRequest)\b[^\n]{0,200}(?:telemetry\.api-monitor\.com|raw\.icp0\.io\/drop)/i,
|
|
366
370
|
},
|
|
367
371
|
];
|
|
368
372
|
|
|
@@ -577,6 +581,31 @@ function createRuntime({
|
|
|
577
581
|
});
|
|
578
582
|
}
|
|
579
583
|
|
|
584
|
+
function recordPhaseCapHit(reason, detail = {}) {
|
|
585
|
+
const phaseId = currentPhase ? currentPhase.id : null;
|
|
586
|
+
const ts = nowFn();
|
|
587
|
+
const breachedAtMs = currentPhase ? ts - currentPhase.startMs : null;
|
|
588
|
+
const entry = {
|
|
589
|
+
kind: 'phase.cap_hit',
|
|
590
|
+
phase: phaseId,
|
|
591
|
+
ts_ms: ts,
|
|
592
|
+
reason,
|
|
593
|
+
breached_at_ms: breachedAtMs,
|
|
594
|
+
...detail,
|
|
595
|
+
};
|
|
596
|
+
capEvents.push(entry);
|
|
597
|
+
if (currentPhase) currentPhase.caps += 1;
|
|
598
|
+
walkEvents.push({
|
|
599
|
+
event: 'phase.cap_hit',
|
|
600
|
+
phase: phaseId,
|
|
601
|
+
ts_ms: ts,
|
|
602
|
+
reason,
|
|
603
|
+
breached_at_ms: breachedAtMs,
|
|
604
|
+
...detail,
|
|
605
|
+
});
|
|
606
|
+
emit({ kind: 'phase.cap_hit', phase: phaseId, reason, ...detail });
|
|
607
|
+
}
|
|
608
|
+
|
|
580
609
|
function recordSkip(kind, detail = {}) {
|
|
581
610
|
walkEvents.push({
|
|
582
611
|
event: 'walk.skipped',
|
|
@@ -673,6 +702,7 @@ function createRuntime({
|
|
|
673
702
|
endPhase,
|
|
674
703
|
emit,
|
|
675
704
|
recordCap,
|
|
705
|
+
recordPhaseCapHit,
|
|
676
706
|
recordSkip,
|
|
677
707
|
recordSymlinkCycle,
|
|
678
708
|
recordReaddirError,
|
|
@@ -1375,7 +1405,7 @@ function collectTextIndicators(text) {
|
|
|
1375
1405
|
const escapedName = escapeRegex(trackedPackage.name);
|
|
1376
1406
|
if (
|
|
1377
1407
|
new RegExp(
|
|
1378
|
-
`\\b(?:npm|pnpm|yarn|bun)\\b[^\\n]
|
|
1408
|
+
`\\b(?:npm|pnpm|yarn|bun)\\b[^\\n]{0,200}(?:install|i|add|update|up|upgrade|exec|ci|pm add)?[^\\n]{0,200}${escapedName}(?:@[0-9.]+)?`,
|
|
1379
1409
|
'i',
|
|
1380
1410
|
).test(text)
|
|
1381
1411
|
) {
|
|
@@ -1383,8 +1413,8 @@ function collectTextIndicators(text) {
|
|
|
1383
1413
|
}
|
|
1384
1414
|
|
|
1385
1415
|
if (
|
|
1386
|
-
new RegExp(`\\b(?:npx|bunx)\\b[^\\n]
|
|
1387
|
-
new RegExp(`${escapedName}[^\\n]
|
|
1416
|
+
new RegExp(`\\b(?:npx|bunx)\\b[^\\n]{0,200}${escapedName}(?:@[0-9.]+)?`, 'i').test(text) ||
|
|
1417
|
+
new RegExp(`${escapedName}[^\\n]{0,200}node_modules`, 'i').test(text)
|
|
1388
1418
|
) {
|
|
1389
1419
|
indicators.executionCommands.push(`exec:${trackedPackage.name}`);
|
|
1390
1420
|
}
|
|
@@ -2554,11 +2584,11 @@ function collectTempRoots(platformInfo, homes, roots) {
|
|
|
2554
2584
|
}
|
|
2555
2585
|
|
|
2556
2586
|
for (const homePath of homes) {
|
|
2587
|
+
// ~/.npm, ~/.npm/_npx, ~/.cache, ~/.bun intentionally omitted: dedicated
|
|
2588
|
+
// scanNpmCache / scanBunCache phases cover them with tighter caps; walking
|
|
2589
|
+
// them here surfaces hundreds of MB of content scans and bypasses
|
|
2590
|
+
// WALK_SKIP_DIRS (skip-set only filters sub-entries, not chosen roots).
|
|
2557
2591
|
for (const candidate of [
|
|
2558
|
-
join(homePath, '.npm'),
|
|
2559
|
-
join(homePath, '.npm', '_npx'),
|
|
2560
|
-
join(homePath, '.cache'),
|
|
2561
|
-
join(homePath, '.bun'),
|
|
2562
2592
|
join(homePath, 'Library', 'Caches'),
|
|
2563
2593
|
join(homePath, 'AppData', 'Local', 'Temp'),
|
|
2564
2594
|
join(homePath, 'AppData', 'Local', 'npm-cache'),
|
|
@@ -2579,8 +2609,185 @@ function collectTempRoots(platformInfo, homes, roots) {
|
|
|
2579
2609
|
});
|
|
2580
2610
|
}
|
|
2581
2611
|
|
|
2582
|
-
function
|
|
2612
|
+
function resolveTempBudgets(runtime) {
|
|
2613
|
+
const budgets = runtime?.options?.phaseBudgets || {};
|
|
2614
|
+
const filesOverride = Number(budgets['scanTempArtifacts.files']);
|
|
2615
|
+
const bytesOverride = Number(budgets['scanTempArtifacts.bytes']);
|
|
2616
|
+
const wallOverride = Number(budgets['scanTempArtifacts.wall_ms']);
|
|
2617
|
+
// Back-compat: `--phase-budget scanTempArtifacts=N` is interpreted as the
|
|
2618
|
+
// files-count cap (dominant failure mode for this phase).
|
|
2619
|
+
const shorthandOverride = Number(budgets.scanTempArtifacts);
|
|
2620
|
+
const files =
|
|
2621
|
+
Number.isFinite(filesOverride) && filesOverride >= 0
|
|
2622
|
+
? filesOverride
|
|
2623
|
+
: Number.isFinite(shorthandOverride) && shorthandOverride >= 0
|
|
2624
|
+
? shorthandOverride
|
|
2625
|
+
: DEFAULT_TEMP_FILES_BUDGET;
|
|
2626
|
+
const bytes = Number.isFinite(bytesOverride) && bytesOverride >= 0 ? bytesOverride : DEFAULT_TEMP_BYTES_BUDGET;
|
|
2627
|
+
const wallMs = Number.isFinite(wallOverride) && wallOverride >= 0 ? wallOverride : DEFAULT_TEMP_WALL_BUDGET_MS;
|
|
2628
|
+
return { files, bytes, wallMs };
|
|
2629
|
+
}
|
|
2630
|
+
|
|
2631
|
+
function pushSizeCappedTempFinding(report, fullPath, stat, namedHits) {
|
|
2632
|
+
const finding = {
|
|
2633
|
+
path: fullPath,
|
|
2634
|
+
realpath: safeRealpath(fullPath),
|
|
2635
|
+
size: stat.size,
|
|
2636
|
+
modifiedAt: isoTime(stat.mtimeMs),
|
|
2637
|
+
nameMatches: namedHits,
|
|
2638
|
+
sha256: null,
|
|
2639
|
+
expectedSha256: expectedMalwareHashForBasename(basename(fullPath)),
|
|
2640
|
+
knownMalwareHash: false,
|
|
2641
|
+
iocMatches: [],
|
|
2642
|
+
versions: [],
|
|
2643
|
+
packageRefs: [],
|
|
2644
|
+
executionCommands: [],
|
|
2645
|
+
networkCommands: [],
|
|
2646
|
+
snippets: [],
|
|
2647
|
+
size_capped_not_hashed: true,
|
|
2648
|
+
};
|
|
2649
|
+
report.tempArtifactFindings.push(finding);
|
|
2650
|
+
addTimeline(report, {
|
|
2651
|
+
time: finding.modifiedAt,
|
|
2652
|
+
category: 'temp-artifact',
|
|
2653
|
+
severity: namedHits.some((value) => /env-compat\.(?:cjs|js)/i.test(value)) ? 'compromised' : 'affected',
|
|
2654
|
+
summary: 'temp or cache artifact matched known-bad basename; size-capped, content not scanned',
|
|
2655
|
+
path: fullPath,
|
|
2656
|
+
});
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2659
|
+
function inspectTempFileSync(fullPath, report) {
|
|
2660
|
+
const stat = safeStat(fullPath);
|
|
2661
|
+
if (!stat || !stat.isFile()) return { bytesRead: 0, skipped: true };
|
|
2662
|
+
|
|
2663
|
+
const namedHits = collectNamedArtifactHits(fullPath);
|
|
2664
|
+
|
|
2665
|
+
// Size guard applies universally (hotfix: close DoS via name-regex fast path).
|
|
2666
|
+
// Basename hits still surface a finding but content is NOT read/hashed.
|
|
2667
|
+
if (stat.size > MAX_TEMP_CONTENT_SCAN_SIZE) {
|
|
2668
|
+
if (namedHits.length > 0 && report.tempArtifactFindings.length < MAX_TEMP_FINDINGS) {
|
|
2669
|
+
pushSizeCappedTempFinding(report, fullPath, stat, namedHits);
|
|
2670
|
+
}
|
|
2671
|
+
return { bytesRead: 0, skipped: true };
|
|
2672
|
+
}
|
|
2673
|
+
|
|
2674
|
+
const buffer = safeReadFile(fullPath);
|
|
2675
|
+
if (!buffer) return { bytesRead: 0, skipped: true };
|
|
2676
|
+
|
|
2677
|
+
const bytesRead = buffer.length;
|
|
2678
|
+
const expanded = maybeGunzip(buffer);
|
|
2679
|
+
const iocMatches = searchBufferForIocs(expanded);
|
|
2680
|
+
const fileSha256 = sha256(expanded);
|
|
2681
|
+
const expectedSha256 = expectedMalwareHashForBasename(basename(fullPath));
|
|
2682
|
+
|
|
2683
|
+
const text = expanded.toString('utf8');
|
|
2684
|
+
const indicators = collectTextIndicators(text);
|
|
2685
|
+
const versions = indicators.versions;
|
|
2686
|
+
const packageRefs = indicators.packageRefs;
|
|
2687
|
+
const executionCommands = indicators.executionCommands;
|
|
2688
|
+
const networkCommands = indicators.networkCommands;
|
|
2689
|
+
const snippets = extractInterestingSnippets(text);
|
|
2690
|
+
|
|
2691
|
+
if (
|
|
2692
|
+
namedHits.length === 0 &&
|
|
2693
|
+
iocMatches.length === 0 &&
|
|
2694
|
+
versions.length === 0 &&
|
|
2695
|
+
packageRefs.length === 0 &&
|
|
2696
|
+
executionCommands.length === 0 &&
|
|
2697
|
+
networkCommands.length === 0
|
|
2698
|
+
) {
|
|
2699
|
+
return { bytesRead, skipped: false };
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2702
|
+
const finding = {
|
|
2703
|
+
path: fullPath,
|
|
2704
|
+
realpath: safeRealpath(fullPath),
|
|
2705
|
+
size: stat.size,
|
|
2706
|
+
modifiedAt: isoTime(stat.mtimeMs),
|
|
2707
|
+
nameMatches: namedHits,
|
|
2708
|
+
sha256: fileSha256,
|
|
2709
|
+
expectedSha256,
|
|
2710
|
+
knownMalwareHash: Boolean(expectedSha256 && expectedSha256 === fileSha256),
|
|
2711
|
+
iocMatches,
|
|
2712
|
+
versions,
|
|
2713
|
+
packageRefs,
|
|
2714
|
+
executionCommands,
|
|
2715
|
+
networkCommands,
|
|
2716
|
+
snippets,
|
|
2717
|
+
};
|
|
2718
|
+
|
|
2719
|
+
report.tempArtifactFindings.push(finding);
|
|
2720
|
+
addTimeline(report, {
|
|
2721
|
+
time: finding.modifiedAt,
|
|
2722
|
+
category: 'temp-artifact',
|
|
2723
|
+
severity:
|
|
2724
|
+
iocMatches.length > 0 ||
|
|
2725
|
+
namedHits.some((value) => /env-compat\.(?:cjs|js)/i.test(value)) ||
|
|
2726
|
+
Boolean(expectedSha256 && expectedSha256 === fileSha256)
|
|
2727
|
+
? 'compromised'
|
|
2728
|
+
: 'affected',
|
|
2729
|
+
summary: 'temp or cache artifact retained suspicious package evidence',
|
|
2730
|
+
path: fullPath,
|
|
2731
|
+
});
|
|
2732
|
+
return { bytesRead, skipped: false };
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
async function processTempArtifactQueue(pending, report, runtime) {
|
|
2736
|
+
const { files: filesBudget, bytes: bytesBudget, wallMs: wallBudget } = resolveTempBudgets(runtime);
|
|
2737
|
+
let filesProcessed = 0;
|
|
2738
|
+
let bytesProcessed = 0;
|
|
2739
|
+
let capRecorded = false;
|
|
2740
|
+
const startMs = Date.now();
|
|
2741
|
+
|
|
2742
|
+
const recordCapOnce = (reason, limit) => {
|
|
2743
|
+
if (capRecorded) return;
|
|
2744
|
+
capRecorded = true;
|
|
2745
|
+
if (runtime && typeof runtime.recordPhaseCapHit === 'function') {
|
|
2746
|
+
runtime.recordPhaseCapHit(reason, {
|
|
2747
|
+
// `root` is what `envelopeFromReport` greps for in `coverage.cappedRoots`;
|
|
2748
|
+
// without it a phase-budget breach does not surface in the coverage banner.
|
|
2749
|
+
root: 'scanTempArtifacts',
|
|
2750
|
+
limit,
|
|
2751
|
+
entries_processed: filesProcessed,
|
|
2752
|
+
bytes_processed: bytesProcessed,
|
|
2753
|
+
});
|
|
2754
|
+
}
|
|
2755
|
+
};
|
|
2756
|
+
|
|
2757
|
+
for (const fullPath of pending) {
|
|
2758
|
+
if (runtime && typeof runtime.isInterrupted === 'function' && runtime.isInterrupted()) break;
|
|
2759
|
+
if (report.tempArtifactFindings.length >= MAX_TEMP_FINDINGS) break;
|
|
2760
|
+
// Wall first — a single slow `readFileSync` (spinning disk, NFS, large
|
|
2761
|
+
// near-limit file) can blow the other budgets' theoretical bounds; the
|
|
2762
|
+
// wall-clock check is the definitive "stop" signal.
|
|
2763
|
+
if (wallBudget > 0 && Date.now() - startMs >= wallBudget) {
|
|
2764
|
+
recordCapOnce('wall_budget', wallBudget);
|
|
2765
|
+
break;
|
|
2766
|
+
}
|
|
2767
|
+
if (filesProcessed >= filesBudget) {
|
|
2768
|
+
recordCapOnce('files_budget', filesBudget);
|
|
2769
|
+
break;
|
|
2770
|
+
}
|
|
2771
|
+
if (bytesProcessed >= bytesBudget) {
|
|
2772
|
+
recordCapOnce('bytes_budget', bytesBudget);
|
|
2773
|
+
break;
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2776
|
+
const { bytesRead } = inspectTempFileSync(fullPath, report);
|
|
2777
|
+
filesProcessed += 1;
|
|
2778
|
+
if (bytesRead > 0) bytesProcessed += bytesRead;
|
|
2779
|
+
if (runtime && typeof runtime.addBytes === 'function' && bytesRead > 0) runtime.addBytes(bytesRead);
|
|
2780
|
+
|
|
2781
|
+
if (filesProcessed % TEMP_YIELD_INTERVAL === 0) {
|
|
2782
|
+
await new Promise((resolvePromise) => setImmediate(resolvePromise));
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
return { filesProcessed, bytesProcessed, capRecorded };
|
|
2786
|
+
}
|
|
2787
|
+
|
|
2788
|
+
async function scanTempArtifacts(platformInfo, homes, roots, report, runtime) {
|
|
2583
2789
|
const tempRoots = collectTempRoots(platformInfo, homes, roots);
|
|
2790
|
+
const pending = [];
|
|
2584
2791
|
|
|
2585
2792
|
walkTreeFiles(
|
|
2586
2793
|
tempRoots,
|
|
@@ -2592,80 +2799,11 @@ function scanTempArtifacts(platformInfo, homes, roots, report, runtime) {
|
|
|
2592
2799
|
scope: 'temp-artifacts',
|
|
2593
2800
|
},
|
|
2594
2801
|
(fullPath) => {
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
const stat = safeStat(fullPath);
|
|
2598
|
-
if (!stat || !stat.isFile()) return;
|
|
2599
|
-
|
|
2600
|
-
const namedHits = collectNamedArtifactHits(fullPath);
|
|
2601
|
-
let iocMatches = [];
|
|
2602
|
-
let versions = [];
|
|
2603
|
-
let packageRefs = [];
|
|
2604
|
-
let executionCommands = [];
|
|
2605
|
-
let networkCommands = [];
|
|
2606
|
-
let snippets = [];
|
|
2607
|
-
|
|
2608
|
-
if (namedHits.length === 0 && stat.size > MAX_TEMP_CONTENT_SCAN_SIZE) return;
|
|
2609
|
-
|
|
2610
|
-
const buffer = safeReadFile(fullPath);
|
|
2611
|
-
if (!buffer) return;
|
|
2612
|
-
|
|
2613
|
-
const expanded = maybeGunzip(buffer);
|
|
2614
|
-
iocMatches = searchBufferForIocs(expanded);
|
|
2615
|
-
const fileSha256 = sha256(expanded);
|
|
2616
|
-
const expectedSha256 = expectedMalwareHashForBasename(basename(fullPath));
|
|
2617
|
-
|
|
2618
|
-
const text = expanded.toString('utf8');
|
|
2619
|
-
const indicators = collectTextIndicators(text);
|
|
2620
|
-
versions = indicators.versions;
|
|
2621
|
-
packageRefs = indicators.packageRefs;
|
|
2622
|
-
executionCommands = indicators.executionCommands;
|
|
2623
|
-
networkCommands = indicators.networkCommands;
|
|
2624
|
-
snippets = extractInterestingSnippets(text);
|
|
2625
|
-
|
|
2626
|
-
if (
|
|
2627
|
-
namedHits.length === 0 &&
|
|
2628
|
-
iocMatches.length === 0 &&
|
|
2629
|
-
versions.length === 0 &&
|
|
2630
|
-
packageRefs.length === 0 &&
|
|
2631
|
-
executionCommands.length === 0 &&
|
|
2632
|
-
networkCommands.length === 0
|
|
2633
|
-
) {
|
|
2634
|
-
return;
|
|
2635
|
-
}
|
|
2636
|
-
|
|
2637
|
-
const finding = {
|
|
2638
|
-
path: fullPath,
|
|
2639
|
-
realpath: safeRealpath(fullPath),
|
|
2640
|
-
size: stat.size,
|
|
2641
|
-
modifiedAt: isoTime(stat.mtimeMs),
|
|
2642
|
-
nameMatches: namedHits,
|
|
2643
|
-
sha256: fileSha256,
|
|
2644
|
-
expectedSha256,
|
|
2645
|
-
knownMalwareHash: Boolean(expectedSha256 && expectedSha256 === fileSha256),
|
|
2646
|
-
iocMatches,
|
|
2647
|
-
versions,
|
|
2648
|
-
packageRefs,
|
|
2649
|
-
executionCommands,
|
|
2650
|
-
networkCommands,
|
|
2651
|
-
snippets,
|
|
2652
|
-
};
|
|
2653
|
-
|
|
2654
|
-
report.tempArtifactFindings.push(finding);
|
|
2655
|
-
addTimeline(report, {
|
|
2656
|
-
time: finding.modifiedAt,
|
|
2657
|
-
category: 'temp-artifact',
|
|
2658
|
-
severity:
|
|
2659
|
-
iocMatches.length > 0 ||
|
|
2660
|
-
namedHits.some((value) => /env-compat\.(?:cjs|js)/i.test(value)) ||
|
|
2661
|
-
Boolean(expectedSha256 && expectedSha256 === fileSha256)
|
|
2662
|
-
? 'compromised'
|
|
2663
|
-
: 'affected',
|
|
2664
|
-
summary: 'temp or cache artifact retained suspicious package evidence',
|
|
2665
|
-
path: fullPath,
|
|
2666
|
-
});
|
|
2802
|
+
pending.push(fullPath);
|
|
2667
2803
|
},
|
|
2668
2804
|
);
|
|
2805
|
+
|
|
2806
|
+
await processTempArtifactQueue(pending, report, runtime);
|
|
2669
2807
|
}
|
|
2670
2808
|
|
|
2671
2809
|
function scanLiveProcesses(report) {
|
|
@@ -3217,10 +3355,10 @@ function emitSlowestRootsReport(envelope, options, stderr) {
|
|
|
3217
3355
|
}
|
|
3218
3356
|
}
|
|
3219
3357
|
|
|
3220
|
-
function runPhase(runtime, id, scope, path, fn, report) {
|
|
3358
|
+
async function runPhase(runtime, id, scope, path, fn, report) {
|
|
3221
3359
|
runtime.startPhase(id);
|
|
3222
3360
|
try {
|
|
3223
|
-
fn();
|
|
3361
|
+
await fn();
|
|
3224
3362
|
} catch (error) {
|
|
3225
3363
|
addError(report, scope, path, error);
|
|
3226
3364
|
} finally {
|
|
@@ -3228,7 +3366,7 @@ function runPhase(runtime, id, scope, path, fn, report) {
|
|
|
3228
3366
|
}
|
|
3229
3367
|
}
|
|
3230
3368
|
|
|
3231
|
-
function main() {
|
|
3369
|
+
async function main() {
|
|
3232
3370
|
const options = parseArgs(process.argv);
|
|
3233
3371
|
|
|
3234
3372
|
if (options.help) {
|
|
@@ -3298,11 +3436,11 @@ function main() {
|
|
|
3298
3436
|
runtime.startTicker();
|
|
3299
3437
|
|
|
3300
3438
|
for (const homePath of homes) {
|
|
3301
|
-
runPhase(runtime, 'scanNpmCache', 'npm-cache', homePath, () => scanNpmCache(homePath, report), report);
|
|
3302
|
-
runPhase(runtime, 'scanBunCache', 'bun-cache', homePath, () => scanBunCache(homePath, report), report);
|
|
3439
|
+
await runPhase(runtime, 'scanNpmCache', 'npm-cache', homePath, () => scanNpmCache(homePath, report), report);
|
|
3440
|
+
await runPhase(runtime, 'scanBunCache', 'bun-cache', homePath, () => scanBunCache(homePath, report), report);
|
|
3303
3441
|
}
|
|
3304
3442
|
|
|
3305
|
-
runPhase(
|
|
3443
|
+
await runPhase(
|
|
3306
3444
|
runtime,
|
|
3307
3445
|
'scanGlobalInstallCandidates',
|
|
3308
3446
|
'global-installs',
|
|
@@ -3310,7 +3448,7 @@ function main() {
|
|
|
3310
3448
|
() => scanGlobalInstallCandidates(homes, report),
|
|
3311
3449
|
report,
|
|
3312
3450
|
);
|
|
3313
|
-
runPhase(
|
|
3451
|
+
await runPhase(
|
|
3314
3452
|
runtime,
|
|
3315
3453
|
'scanProjectRoots',
|
|
3316
3454
|
'project-roots',
|
|
@@ -3318,7 +3456,7 @@ function main() {
|
|
|
3318
3456
|
() => scanProjectRoots(roots, report, runtime),
|
|
3319
3457
|
report,
|
|
3320
3458
|
);
|
|
3321
|
-
runPhase(
|
|
3459
|
+
await runPhase(
|
|
3322
3460
|
runtime,
|
|
3323
3461
|
'scanShellHistories',
|
|
3324
3462
|
'shell-histories',
|
|
@@ -3326,7 +3464,7 @@ function main() {
|
|
|
3326
3464
|
() => scanShellHistories(homes, report),
|
|
3327
3465
|
report,
|
|
3328
3466
|
);
|
|
3329
|
-
runPhase(
|
|
3467
|
+
await runPhase(
|
|
3330
3468
|
runtime,
|
|
3331
3469
|
'scanShellProfiles',
|
|
3332
3470
|
'shell-profiles',
|
|
@@ -3334,7 +3472,7 @@ function main() {
|
|
|
3334
3472
|
() => scanShellProfiles(homes, report, runtime),
|
|
3335
3473
|
report,
|
|
3336
3474
|
);
|
|
3337
|
-
runPhase(
|
|
3475
|
+
await runPhase(
|
|
3338
3476
|
runtime,
|
|
3339
3477
|
'scanPersistenceLocations',
|
|
3340
3478
|
'persistence',
|
|
@@ -3342,7 +3480,7 @@ function main() {
|
|
|
3342
3480
|
() => scanPersistenceLocations(platformInfo, homes, report, runtime),
|
|
3343
3481
|
report,
|
|
3344
3482
|
);
|
|
3345
|
-
runPhase(
|
|
3483
|
+
await runPhase(
|
|
3346
3484
|
runtime,
|
|
3347
3485
|
'scanPythonPthArtifacts',
|
|
3348
3486
|
'python-pth',
|
|
@@ -3350,7 +3488,7 @@ function main() {
|
|
|
3350
3488
|
() => scanPythonPthArtifacts(homes, roots, report, runtime),
|
|
3351
3489
|
report,
|
|
3352
3490
|
);
|
|
3353
|
-
runPhase(
|
|
3491
|
+
await runPhase(
|
|
3354
3492
|
runtime,
|
|
3355
3493
|
'scanTempArtifacts',
|
|
3356
3494
|
'temp-artifacts',
|
|
@@ -3358,7 +3496,7 @@ function main() {
|
|
|
3358
3496
|
() => scanTempArtifacts(platformInfo, homes, roots, report, runtime),
|
|
3359
3497
|
report,
|
|
3360
3498
|
);
|
|
3361
|
-
runPhase(
|
|
3499
|
+
await runPhase(
|
|
3362
3500
|
runtime,
|
|
3363
3501
|
'scanImpactSurface',
|
|
3364
3502
|
'impact-surface',
|
|
@@ -3366,7 +3504,14 @@ function main() {
|
|
|
3366
3504
|
() => scanImpactSurface(homes, roots, report, runtime),
|
|
3367
3505
|
report,
|
|
3368
3506
|
);
|
|
3369
|
-
runPhase(
|
|
3507
|
+
await runPhase(
|
|
3508
|
+
runtime,
|
|
3509
|
+
'scanLiveProcesses',
|
|
3510
|
+
'live-processes',
|
|
3511
|
+
'(process table)',
|
|
3512
|
+
() => scanLiveProcesses(report),
|
|
3513
|
+
report,
|
|
3514
|
+
);
|
|
3370
3515
|
|
|
3371
3516
|
report.timeline = sortTimeline(report.timeline);
|
|
3372
3517
|
report.summary = summarize(report);
|
|
@@ -3382,12 +3527,10 @@ function main() {
|
|
|
3382
3527
|
}
|
|
3383
3528
|
|
|
3384
3529
|
if (require.main === module) {
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
} catch (error) {
|
|
3388
|
-
process.stderr.write(`sec-scan.cjs failed: ${error.message}\n`);
|
|
3530
|
+
main().catch((error) => {
|
|
3531
|
+
process.stderr.write(`sec-scan.cjs failed: ${error?.message ? error.message : error}\n`);
|
|
3389
3532
|
process.exit(3);
|
|
3390
|
-
}
|
|
3533
|
+
});
|
|
3391
3534
|
} else {
|
|
3392
3535
|
module.exports = {
|
|
3393
3536
|
REPORT_VERSION,
|
|
@@ -3423,5 +3566,17 @@ if (require.main === module) {
|
|
|
3423
3566
|
printCoverageBanner,
|
|
3424
3567
|
printHumanReport,
|
|
3425
3568
|
emitSlowestRootsReport,
|
|
3569
|
+
collectTempRoots,
|
|
3570
|
+
scanTempArtifacts,
|
|
3571
|
+
processTempArtifactQueue,
|
|
3572
|
+
inspectTempFileSync,
|
|
3573
|
+
resolveTempBudgets,
|
|
3574
|
+
runPhase,
|
|
3575
|
+
MAX_TEMP_CONTENT_SCAN_SIZE,
|
|
3576
|
+
MAX_TEMP_WALK_ENTRIES,
|
|
3577
|
+
MAX_TEMP_FINDINGS,
|
|
3578
|
+
DEFAULT_TEMP_FILES_BUDGET,
|
|
3579
|
+
DEFAULT_TEMP_BYTES_BUDGET,
|
|
3580
|
+
TEMP_YIELD_INTERVAL,
|
|
3426
3581
|
};
|
|
3427
3582
|
}
|