@cotal-ai/connector-claude-code 0.119.2 → 0.119.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/mcp.cjs +5 -5
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -69,7 +69,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
69
69
|
`,{mode:existsSync(path)?statSync(path).mode&511:384});renameSync(tmp,path);return before===void 0?"added":"updated"}import{existsSync as existsSync2,readFileSync as readFileSync2}from"node:fs";import{homedir as homedir2}from"node:os";import{join as join3}from"node:path";import{mcpServerProblem}from"@cotal-ai/core";function claudeUserMcpServers(){const path=join3(process.env.CLAUDE_CONFIG_DIR?.trim()||homedir2(),".claude.json");if(!existsSync2(path))return{};let config2;try{config2=JSON.parse(readFileSync2(path,"utf8"))}catch(e){throw new Error(`${path}: invalid JSON - ${e.message}`)}return config2?.mcpServers??{}}function claudeUserMcpEnvKeys(){const valid=Object.fromEntries(Object.entries(claudeUserMcpServers()).filter(([name,spec])=>mcpServerProblem(name,spec)===void 0));return mcpServerEnvKeys(valid)}var PACKAGE_ROOT=fileURLToPath(new URL("..",import.meta.url));var COTAL_ASSETS=[".claude-plugin",".mcp.json","hooks","monitors","dist/seat.cjs","dist/mcp.cjs","dist/hook.cjs","dist/monitor.cjs"];function pluginVersion(root,assets,files){const hash2=createHash2("sha256");const add=(path,bytes)=>hash2.update(`${path}\0${bytes.length}\0`).update(bytes);const walk=path=>{if(statSync2(path).isDirectory())for(const entry of readdirSync(path).sort())walk(join4(path,entry));else add(relative(root,path),readFileSync3(path))};for(const asset of[...assets].sort())walk(join4(root,asset));for(const[path,text]of Object.entries(files).sort(([a],[b])=>a.localeCompare(b)))add(path,text);const release=JSON.parse(readFileSync3(join4(PACKAGE_ROOT,"package.json"),"utf8")).version;return`${release}+${hash2.digest("hex").slice(0,12)}`}function materializeCotal(cotal){for(const asset of COTAL_ASSETS)if(!existsSync3(join4(PACKAGE_ROOT,asset)))throw new Error(`plugin asset missing: ${join4(PACKAGE_ROOT,asset)}`);const files=pluginFiles(cotal);const version2=pluginVersion(PACKAGE_ROOT,COTAL_ASSETS,files);materialize("cotal",PACKAGE_ROOT,COTAL_ASSETS,version2,files);return version2}function pluginFiles(cotal){const node=cotal[0];if(!node)throw new Error("the Cotal CLI record has no Node executable");if(process.platform==="win32"&&/[\"%!\r\n]/.test(node))throw new Error("the Node executable path contains characters Claude's Windows command hooks cannot safely run");const quoted=process.platform==="win32"?`"${node}"`:`'${node.replace(/'/g,"'\\''")}'`;const mcp=JSON.parse(readFileSync3(join4(PACKAGE_ROOT,".mcp.json"),"utf8"));mcp.mcpServers.cotal.command=node;const hooks=JSON.parse(readFileSync3(join4(PACKAGE_ROOT,"hooks","hooks.json"),"utf8"));for(const groups of Object.values(hooks.hooks))for(const group of groups)for(const hook of group.hooks){if(hook.command==='node "${CLAUDE_PLUGIN_ROOT}/dist/hook.cjs"')hook.command=quoted+' "${CLAUDE_PLUGIN_ROOT}/dist/hook.cjs"'}return{[`dist/${CLI_RECORD}`]:`${JSON.stringify({argv:cotal})}
|
|
70
70
|
`,".mcp.json":`${JSON.stringify(mcp,null,2)}
|
|
71
71
|
`,"hooks/hooks.json":`${JSON.stringify(hooks,null,2)}
|
|
72
|
-
`}}function desktopEntry(cotal){return{command:cotal[0],args:[join4(marketplaceDir(),"cotal","dist","seat.cjs"),"--desktop"],...process.env.COTAL_HOME?{env:{COTAL_HOME:process.env.COTAL_HOME}}:{}}}function hostedConnector(s){const next=s.hostedConnector?`add ${s.hostedConnector} under Settings > Connectors > Add custom connector`:s.unread?`its hosted connector could not be read (${s.unread})`:`"${s.space}" advertises no hosted connector`;return`chat joins signed-in space "${s.space}" only through a hosted connector: ${next}`}function desktop(cotal,add,signedIn){const path=desktopConfigPath();if(!path||!existsSync3(dirname2(path)))return void 0;if(signedIn)return`Claude Desktop ${hostedConnector(signedIn)}`;if(!add&&readDesktopEntry(path)===void 0)return void 0;const state=writeDesktopEntry(path,desktopEntry(cotal));if(state==="not added"||state==="not updated")return`Claude Desktop ${state}: Claude Desktop is running and writes back the config it read when it started, which would drop the entry. Quit Claude Desktop, then run \`cotal setup\` again from a terminal outside it`;return`Claude Desktop ${state}${state==="current"?"":"; quit and reopen Claude Desktop to load it"}`}var DOCS_URL="https://github.com/Cotal-AI/Cotal/blob/main/docs/connect-claude.md";var MARKETPLACE="cotal-mesh";function claudeCommand(){const terminal=spawnSync2("claude",["--version"],{stdio:"ignore",timeout:5e3,killSignal:"SIGKILL"});if(terminal.status===0)return"claude";if(terminal.error?.code!=="ENOENT")throw new Error("The installed Claude Code command could not run. Repair it before running cotal setup
|
|
72
|
+
`}}function desktopEntry(cotal){return{command:cotal[0],args:[join4(marketplaceDir(),"cotal","dist","seat.cjs"),"--desktop"],...process.env.COTAL_HOME?{env:{COTAL_HOME:process.env.COTAL_HOME}}:{}}}function hostedConnector(s){const next=s.hostedConnector?`add ${s.hostedConnector} under Settings > Connectors > Add custom connector`:s.unread?`its hosted connector could not be read (${s.unread})`:`"${s.space}" advertises no hosted connector`;return`chat joins signed-in space "${s.space}" only through a hosted connector: ${next}`}function desktop(cotal,add,signedIn){const path=desktopConfigPath();if(!path||!existsSync3(dirname2(path)))return void 0;if(signedIn)return`Claude Desktop ${hostedConnector(signedIn)}`;if(!add&&readDesktopEntry(path)===void 0)return void 0;const state=writeDesktopEntry(path,desktopEntry(cotal));if(state==="not added"||state==="not updated")return`Claude Desktop ${state}: Claude Desktop is running and writes back the config it read when it started, which would drop the entry. Quit Claude Desktop, then run \`cotal setup\` again from a terminal outside it`;return`Claude Desktop ${state}${state==="current"?"":"; quit and reopen Claude Desktop to load it"}`}var DOCS_URL="https://github.com/Cotal-AI/Cotal/blob/main/docs/connect-claude.md";var MARKETPLACE="cotal-mesh";function claudeCommand(){const terminal=spawnSync2("claude",["--version"],{stdio:"ignore",timeout:5e3,killSignal:"SIGKILL"});if(terminal.status===0)return"claude";if(terminal.error?.code!=="ENOENT")throw new Error("The installed Claude Code command could not run. Repair it before running `cotal setup`.");const config2=desktopConfigPath();const app=config2?dirname2(config2):process.platform==="linux"?join4(process.env.XDG_CONFIG_HOME||join4(homedir3(),".config"),"Claude"):void 0;if(!app||!existsSync3(join4(app,"claude-code")))throw new Error("Claude Code is unavailable. Install it or open Desktop's Code tab, then retry setup.");const cache=join4(app,"claude-code");const versions=readdirSync(cache,{withFileTypes:true}).filter(entry=>entry.isDirectory()&&/^\d+\.\d+\.\d+$/.test(entry.name)).sort((a,b)=>b.name.localeCompare(a.name,void 0,{numeric:true}));const executable=process.platform==="win32"?"claude.exe":"claude";for(const version2 of versions){const root=join4(cache,version2.name);for(const entry of readdirSync(root,{withFileTypes:true}).sort((a,b)=>a.name.localeCompare(b.name))){if(!entry.isDirectory())continue;const candidates=process.platform==="darwin"?[join4(root,entry.name,"claude.app","Contents","MacOS","claude"),join4(root,entry.name,executable)]:[join4(root,entry.name,executable)];for(const candidate of candidates){if(!existsSync3(candidate))continue;if(spawnSync2(candidate,["--version"],{stdio:"ignore",timeout:5e3,killSignal:"SIGKILL"}).status!==0)throw new Error("Claude Desktop's bundled Code executable could not run. Update or reinstall Claude Desktop.");return candidate}}}throw new Error("Claude Code is unavailable. Install it or open Desktop's Code tab, then retry setup.")}function claudeAvailable(){try{claudeCommand();return true}catch{return false}}function cotalHome(){if(process.env.COTAL_HOME)return process.env.COTAL_HOME;if(process.platform==="win32"&&process.env.LOCALAPPDATA)return join4(process.env.LOCALAPPDATA,"Cotal");return join4(homedir3(),".cotal")}function marketplaceDir(){return join4(cotalHome(),"claude-plugin")}function withPluginLock(run){const lock=acquireLock(join4(marketplaceDir(),".setup.lock"),{label:"Claude plugin setup"});try{return run()}finally{lock.release()}}function materialize(name,root,assets,version2,files={}){const market=marketplaceDir();mkdirSync(market,{recursive:true});const dest=join4(market,name);const staging=`${dest}.staging.${process.pid}`;const old=`${dest}.old.${process.pid}`;const orphans=readdirSync(market,{withFileTypes:true}).filter(entry=>entry.isDirectory()&&(entry.name.startsWith(`${name}.old.`)||entry.name.startsWith(`${name}.staging.`))).map(entry=>entry.name);if(!existsSync3(dest)){const recoverable=orphans.find(entry=>entry.startsWith(`${name}.old.`));if(recoverable)renameSync2(join4(market,recoverable),dest)}for(const entry of orphans)rmSync(join4(market,entry),{recursive:true,force:true});let movedAside=false;let swapped=false;try{mkdirSync(staging);for(const asset of assets){const destination=join4(staging,asset);mkdirSync(join4(destination,".."),{recursive:true});cpSync(join4(root,asset),destination,{recursive:true,dereference:true})}for(const[path,text]of Object.entries(files))writeFileSync2(join4(staging,path),text);if(version2){const manifestPath=join4(staging,".claude-plugin","plugin.json");const manifest=JSON.parse(readFileSync3(manifestPath,"utf8"));manifest.version=version2;writeFileSync2(manifestPath,JSON.stringify(manifest,null,2)+"\n")}if(existsSync3(dest)){renameSync2(dest,old);movedAside=true}renameSync2(staging,dest);swapped=true;if(movedAside)rmSync(old,{recursive:true,force:true})}catch(error51){if(movedAside&&!swapped&&!existsSync3(dest)&&existsSync3(old))renameSync2(old,dest);throw error51}finally{rmSync(staging,{recursive:true,force:true});if(swapped)rmSync(old,{recursive:true,force:true})}}var CLAUDE_OUTPUT_LIMIT=64*1024*1024;function command(...args){return commandIn(process.cwd(),...args)}function commandIn(cwd,...args){const result=spawnSync2(claudeCommand(),args,{cwd,encoding:"utf8",maxBuffer:CLAUDE_OUTPUT_LIMIT,timeout:12e4,killSignal:"SIGKILL"});if(result.error)return{status:null,output:result.error.message};return{status:result.status,output:`${result.stdout??""}${result.stderr??""}`.trim()}}function marketplaceEntry(market,name){const manifest=JSON.parse(readFileSync3(join4(market,name,".claude-plugin","plugin.json"),"utf8"));const description=typeof manifest.description==="string"?manifest.description:void 0;return{name,source:`./${name}`,...description?{description}:{}}}function marketplaceManifest(market){const plugins=["cotal","cotal-skills"].filter(name=>existsSync3(join4(market,name,".claude-plugin","plugin.json"))).map(name=>marketplaceEntry(market,name));return{name:MARKETPLACE,description:"Cotal for Claude Code",owner:{name:"Cotal"},plugins}}function writeMarketplaceManifest(market){const path=join4(market,".claude-plugin","marketplace.json");mkdirSync(dirname2(path),{recursive:true});writePrivateRecord(path,JSON.stringify(marketplaceManifest(market),null,2)+"\n");return path}function writeMarketplace(){const market=marketplaceDir();writeMarketplaceManifest(market);const add=command("plugin","marketplace","add",market);if(add.status!==0&&!/already (?:exists|added|on disk)/i.test(add.output))throw new Error(`plugin marketplace add failed:
|
|
73
73
|
${add.output}`);const update=command("plugin","marketplace","update",MARKETPLACE);if(update.status!==0)throw new Error(`plugin marketplace update failed:
|
|
74
74
|
${update.output}`)}function installedForRefresh(){const config2=process.env.CLAUDE_CONFIG_DIR?.trim()||join4(homedir3(),".claude");const cache=process.env.CLAUDE_CODE_PLUGIN_CACHE_DIR?.trim()||join4(config2,"plugins");const path=join4(cache,"installed_plugins.json");if(!existsSync3(path))return[];let records;try{records=JSON.parse(readFileSync3(path,"utf8")).plugins}catch{throw new Error("Claude's plugin records could not be read, so Cotal cannot verify their upgrade")}if(!records||typeof records!=="object"||Array.isArray(records))throw new Error("Claude's plugin records have an unsupported shape, so Cotal cannot verify their upgrade");for(const name of["cotal","cotal-skills"]){const entries=records[`${name}@${MARKETPLACE}`];if(entries!==void 0&&(!Array.isArray(entries)||entries.length>0)){if(!claudeAvailable())throw new Error(`${name}@${MARKETPLACE} is installed, but Claude Code is unavailable. Restore Claude Code or open Desktop's Code tab, then retry the Cotal update.`);return listPlugins()}}return[]}function listPlugins(cwd=process.cwd()){const result=commandIn(cwd,"plugin","list","--json");if(result.status!==0)throw new Error(`plugin list failed:
|
|
75
75
|
${result.output}`);let entries;try{entries=JSON.parse(result.output)}catch{throw new Error(`could not parse plugin list:
|