grix-connector
Version:
Connect local AI coding agents (Claude, Codex, Gemini, Qwen, DeepSeek, Cursor, OpenCode, Pi, OpenHuman, Reasonix) to the Grix scheduling platform. Also serves as an OpenClaw plugin for Grix channel transport.
18 lines (17 loc) • 5.99 kB
JavaScript
import{copyFile as O,readFile as R,rename as x,stat as C,writeFile as A}from"node:fs/promises";import S from"node:os";import{dirname as J,join as d}from"node:path";import{parseArgs as N}from"node:util";const T=["apikey","api_key","token","secret","authorization","password","passwd","credential"];function g(){return["Usage:"," node scripts/set_openclaw_memory_model.js --model <model> [--provider <provider>] [--set KEY=VALUE...] [--write] <target...>","","Targets:"," Profile directories (containing openclaw.json) or direct openclaw.json paths.","","Options:"," --model <model> Required, e.g. embeddinggemma:300m-qat-q8_0"," --provider <provider> Default: ollama"," --set KEY=VALUE Keys are relative to agents.defaults.memorySearch; repeatable"," --write Apply the change (otherwise preview only)"].join(`
`)}function D(e){const n=String(e??"");return n==="~"?S.homedir():n.startsWith("~/")?d(S.homedir(),n.slice(2)):n}function i(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}async function w(e){try{return await C(e),!0}catch{return!1}}async function $(e){const n=D(e);if(n.endsWith("/"))return $(n.slice(0,-1));if(n.endsWith("openclaw.json")){if(!n.endsWith("/openclaw.json")&&n.split("/").at(-1)!=="openclaw.json")throw new Error(`Refusing to edit non-OpenClaw config file: ${n}`);return n}const r=d(n,"openclaw.json");if(await w(r))return r;throw await w(n)?new Error(`Refusing to edit non-OpenClaw config file: ${n}`):new Error(`Config not found: ${r}`)}async function _(e){let n;try{n=await R(e,"utf8")}catch(t){const r=t instanceof Error?t.message:String(t);throw new Error(`Config not found: ${e} (${r})`)}try{const t=JSON.parse(n);if(!i(t))throw new Error("Top-level JSON must be an object");return t}catch(t){const r=t instanceof Error?t.message:String(t);throw new Error(`Invalid JSON in ${e}: ${r}`)}}function P(e){if(!("agents"in e))throw new Error("Refusing to edit a config without a top-level 'agents' object");const n=e.agents;if(!i(n))throw new Error("Top-level 'agents' must be a JSON object");const t=n.defaults;if(t===void 0)n.defaults={};else if(!i(t))throw new Error("'agents.defaults' must be a JSON object");const r=n.defaults,o=r.memorySearch;if(o===void 0)r.memorySearch={};else if(!i(o))throw new Error("'agents.defaults.memorySearch' must be a JSON object");return r.memorySearch}function b(e){return JSON.parse(JSON.stringify(e))}function V(e){return e.map(n=>{const t=n.indexOf("=");if(t<0)throw new Error(`Invalid --set value (expected KEY=VALUE): ${n}`);const r=n.slice(0,t),o=n.slice(t+1),s=r.split(".").map(f=>f.trim()).filter(Boolean);if(!s.length)throw new Error(`Invalid --set key: ${n}`);try{return{keyParts:s,value:JSON.parse(o)}}catch{return{keyParts:s,value:o}}})}function K(e,n,t){let r=e;for(const o of n.slice(0,-1)){const s=r[o];if(s===void 0)r[o]={};else if(!i(s))throw new Error(`Cannot set ${n.join(".")}: ${o} is not a JSON object`);r=r[o]}r[n[n.length-1]]=t}function p(e,n){if(e===n)return!0;if(typeof e!=typeof n||e===null||n===null)return!1;if(Array.isArray(e)&&Array.isArray(n)){if(e.length!==n.length)return!1;for(let t=0;t<e.length;t+=1)if(!p(e[t],n[t]))return!1;return!0}if(i(e)&&i(n)){const t=Object.keys(e).sort(),r=Object.keys(n).sort();if(t.length!==r.length)return!1;for(let o=0;o<t.length;o+=1)if(t[o]!==r[o])return!1;for(const o of t)if(!p(e[o],n[o]))return!1;return!0}return!1}function L(e){const n=P(e.config),t=b(n);if(String(n.provider??"")!==e.provider)for(const s of Object.keys(n))delete n[s];n.provider=e.provider,n.model=e.model;for(const s of V(e.extraSettings))K(n,s.keyParts,s.value);const o=b(n);return{before:t,after:o}}function B(e){const n=e.toLowerCase().replace(/[-_]/g,"");return T.some(t=>n.includes(t.replace(/_/g,"")))}function l(e){if(Array.isArray(e))return e.map(n=>l(n));if(i(e)){const n={};for(const[t,r]of Object.entries(e))n[t]=B(t)?"<redacted>":l(r);return n}return e}function m(e){if(Array.isArray(e))return e.map(n=>m(n));if(i(e)){const n={};for(const t of Object.keys(e).sort())n[t]=m(e[t]);return n}return e}function v(e){return JSON.stringify(m(e))}function F(e){const n=t=>String(t).padStart(2,"0");return`${e.getFullYear()}${n(e.getMonth()+1)}${n(e.getDate())}-${n(e.getHours())}${n(e.getMinutes())}${n(e.getSeconds())}`}async function I(e,n){let t=`${e}.bak.${n}`,r=1;for(;await w(t);)t=`${e}.bak.${n}-${r}`,r+=1;return t}async function M(e,n,t){const r=await I(e,t);await O(e,r);const o=d(J(e),`openclaw.json.tmp.${t}.${Math.random().toString(16).slice(2)}`);return await A(o,`${JSON.stringify(n,null,2)}
`,"utf8"),await x(o,e),r}async function U(){const e=N({args:process.argv.slice(2),allowPositionals:!0,options:{model:{type:"string"},provider:{type:"string",default:"ollama"},set:{type:"string",multiple:!0,default:[]},write:{type:"boolean",default:!1},help:{type:"boolean",default:!1}}});if(e.values.help)return process.stdout.write(`${g()}
`),0;const n=String(e.values.model??"").trim();if(!n)return process.stderr.write(`${g()}
`),1;const t=e.positionals.map(c=>String(c)).filter(Boolean);if(!t.length)return process.stderr.write(`${g()}
`),1;const r=String(e.values.provider??"ollama").trim()||"ollama",o=e.values.set??[],s=!!e.values.write,f=F(new Date);let y=0;for(const c of t)try{const a=await $(c),u=await _(a),{before:h,after:k}=L({config:u,provider:r,model:n,extraSettings:o}),E=!p(h,k);if(process.stdout.write(`${a}
`),process.stdout.write(` before: ${v(l(h))}
`),process.stdout.write(` after: ${v(l(k))}
`),!E){process.stdout.write(` result: unchanged
`);continue}if(s){const j=await M(a,u,f);process.stdout.write(` result: written
`),process.stdout.write(` backup: ${j}
`)}else process.stdout.write(` result: preview only (add --write to apply)
`)}catch(a){y=1;const u=a instanceof Error?a.message:String(a);process.stdout.write(`${c}
error: ${u}
`)}return y}U().then(e=>{process.exitCode=e}).catch(e=>{const n=e instanceof Error?e.message:String(e);process.stderr.write(`${n}
`),process.exitCode=1});