grix-connector 3.1.13 → 3.1.15
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/README.md +241 -241
- package/dist/adapter/claude/claude-adapter.js +19 -19
- package/dist/adapter/claude/usage-parser.js +9 -7
- package/dist/default-skills/grix-access-control/SKILL.md +31 -31
- package/dist/default-skills/grix-admin/SKILL.md +35 -35
- package/dist/default-skills/grix-agent-dispatch/SKILL.md +89 -89
- package/dist/default-skills/grix-chat-state/SKILL.md +56 -56
- package/dist/default-skills/grix-egg/SKILL.md +90 -90
- package/dist/default-skills/grix-group/SKILL.md +35 -35
- package/dist/default-skills/grix-owner-relay/SKILL.md +66 -66
- package/dist/default-skills/grix-query/SKILL.md +38 -38
- package/dist/default-skills/message-send/SKILL.md +36 -36
- package/dist/default-skills/message-unsend/SKILL.md +27 -27
- package/dist/default-skills/tailnet-file-share/SKILL.md +65 -65
- package/dist/grix.js +0 -0
- package/dist/service/platform-adapter.js +59 -16
- package/openclaw-plugin/skills/grix-admin/SKILL.md +202 -202
- package/openclaw-plugin/skills/grix-admin/references/api-contract.md +210 -210
- package/openclaw-plugin/skills/grix-egg/SKILL.md +81 -81
- package/openclaw-plugin/skills/grix-egg/references/api-contract.md +40 -40
- package/openclaw-plugin/skills/grix-group/SKILL.md +164 -164
- package/openclaw-plugin/skills/grix-group/references/api-contract.md +97 -97
- package/openclaw-plugin/skills/grix-query/SKILL.md +247 -247
- package/openclaw-plugin/skills/grix-register/SKILL.md +86 -86
- package/openclaw-plugin/skills/grix-register/references/api-contract.md +76 -76
- package/openclaw-plugin/skills/grix-register/references/grix-concepts.md +26 -26
- package/openclaw-plugin/skills/grix-register/references/handoff-contract.md +24 -24
- package/openclaw-plugin/skills/grix-register/references/openclaw-setup.md +6 -6
- package/openclaw-plugin/skills/grix-register/references/user-replies.md +25 -25
- package/openclaw-plugin/skills/grix-update/SKILL.md +310 -310
- package/openclaw-plugin/skills/grix-update/references/cron-setup.md +56 -56
- package/openclaw-plugin/skills/grix-update/references/update-contract.md +149 -149
- package/openclaw-plugin/skills/message-send/SKILL.md +197 -197
- package/openclaw-plugin/skills/message-unsend/SKILL.md +186 -186
- package/openclaw-plugin/skills/message-unsend/flowchart.mermaid +27 -27
- package/openclaw-plugin/skills/openclaw-memory-setup/SKILL.md +282 -282
- package/openclaw-plugin/skills/openclaw-memory-setup/references/case-study-macpro.md +52 -52
- package/openclaw-plugin/skills/openclaw-memory-setup/references/host-readiness.md +147 -147
- package/openclaw.plugin.json +24 -24
- package/package.json +121 -121
- package/scripts/install-guardian.mjs +27 -27
- package/scripts/install-guardian.sh +25 -25
- package/scripts/upgrade-guardian.sh +104 -104
- package/dist/adapter/claude/claude-bridge-server.js +0 -1
- package/dist/adapter/claude/claude-tools.js +0 -1
- package/dist/adapter/claude/claude-worker-client.js +0 -1
- package/dist/adapter/claude/mcp-http-launcher.js +0 -2
- package/dist/adapter/claude/result-timeout.js +0 -1
- package/dist/adapter/deepseek/deepseek-adapter.js +0 -6
- package/dist/adapter/deepseek/index.js +0 -1
- package/dist/adapter/qwen/index.js +0 -1
- package/dist/adapter/qwen/qwen-adapter.js +0 -4
- package/dist/aibot/client.js +0 -1
- package/dist/aibot/index.js +0 -1
- package/dist/aibot/types.js +0 -0
- package/dist/core/file-ops/handler.js +0 -1
- package/dist/core/file-ops/list-files.js +0 -1
- package/dist/core/file-ops/types.js +0 -0
- package/dist/default-skills/grix-task-status/SKILL.md +0 -36
- package/dist/log.js +0 -3
- package/dist/main.js +0 -31
- package/dist/mcp/stream-http/config.js +0 -1
- package/dist/mcp/stream-http/connection-binding.js +0 -1
- package/dist/mcp/stream-http/event-tool-executor.js +0 -1
- package/dist/mcp/stream-http/gateway.js +0 -1
- package/dist/mcp/stream-http/index.js +0 -1
- package/dist/mcp/stream-http/security.js +0 -1
- package/dist/mcp/stream-http/session-manager.js +0 -1
- package/dist/mcp/stream-http/tool-executor.js +0 -1
- package/dist/mcp/stream-http/tool-registry.js +0 -1
- package/dist/mcp/stream-http/tool-schemas.js +0 -1
- package/dist/session/index.js +0 -1
- package/dist/session/manager.js +0 -1
- package/dist/transport/index.js +0 -1
- package/dist/transport/json-rpc.js +0 -3
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import{existsSync as
|
|
1
|
+
import{existsSync as E,readFileSync as O}from"node:fs";import{mkdir as P,readdir as v,readFile as g,rm as h,stat as U,writeFile as w}from"node:fs/promises";import l from"node:os";import u from"node:path";import{isProcessRunning as C,runCommand as d,spawnDetached as F,isWindowsElevated as H,killProcessesByCommandLine as _}from"./process-control.js";import{getServicePrefix as A,parseConfigDirFromPlistXML as G,parseConfigDirFromSystemdUnit as V,resolveBareDaemonMarkerPath as y,resolveLinuxUserUnitPath as X,resolveMacOSLaunchAgentPath as Q}from"./service-paths.js";function p(t){return String(t??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function T(t){return`'${String(t??"").replace(/'/g,"'\\''")}'`}function j(t){return[t.nodePath,t.cliPath,...t.configDir?["--config-dir",t.configDir]:[]]}function z(t){const e=j(t);return`<?xml version="1.0" encoding="UTF-8"?>
|
|
2
2
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
3
|
<plist version="1.0">
|
|
4
4
|
<dict>
|
|
5
5
|
<key>Label</key>
|
|
6
|
-
<string>${
|
|
6
|
+
<string>${p(t.serviceID)}</string>
|
|
7
7
|
<key>ProgramArguments</key>
|
|
8
8
|
<array>
|
|
9
|
-
${
|
|
9
|
+
${e.map(r=>` <string>${p(r)}</string>`).join(`
|
|
10
10
|
`)}
|
|
11
11
|
</array>
|
|
12
12
|
<key>RunAtLoad</key>
|
|
@@ -14,25 +14,25 @@ ${r.map(e=>` <string>${y(e)}</string>`).join(`
|
|
|
14
14
|
<key>KeepAlive</key>
|
|
15
15
|
<true/>
|
|
16
16
|
<key>WorkingDirectory</key>
|
|
17
|
-
<string>${
|
|
17
|
+
<string>${p(u.dirname(t.cliPath))}</string>
|
|
18
18
|
${t.environmentPath?` <key>EnvironmentVariables</key>
|
|
19
19
|
<dict>
|
|
20
20
|
<key>PATH</key>
|
|
21
|
-
<string>${
|
|
21
|
+
<string>${p(t.environmentPath)}</string>
|
|
22
22
|
</dict>
|
|
23
23
|
`:""} <key>StandardOutPath</key>
|
|
24
|
-
<string>${
|
|
24
|
+
<string>${p(t.stdoutPath)}</string>
|
|
25
25
|
<key>StandardErrorPath</key>
|
|
26
|
-
<string>${
|
|
26
|
+
<string>${p(t.stderrPath)}</string>
|
|
27
27
|
</dict>
|
|
28
28
|
</plist>
|
|
29
|
-
`}function
|
|
29
|
+
`}function J(t){const e=j(t).map(r=>T(r)).join(" ");return`[Unit]
|
|
30
30
|
Description=grix-connector daemon (${t.serviceID})
|
|
31
31
|
After=network.target
|
|
32
32
|
|
|
33
33
|
[Service]
|
|
34
34
|
Type=simple
|
|
35
|
-
ExecStart=${
|
|
35
|
+
ExecStart=${e}
|
|
36
36
|
WorkingDirectory=${u.dirname(t.cliPath)}
|
|
37
37
|
Restart=always
|
|
38
38
|
RestartSec=2
|
|
@@ -41,13 +41,56 @@ StandardError=append:${t.stderrPath}
|
|
|
41
41
|
|
|
42
42
|
[Install]
|
|
43
43
|
WantedBy=default.target
|
|
44
|
-
`}function k(t,
|
|
45
|
-
`);return{path:
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
`}function k(t,e){const r=t.replace(/[^a-zA-Z0-9._-]/g,"_");return u.join(e,".grix",`${r}-wrapper.vbs`)}function I(t,e){const r=t.replace(/[^a-zA-Z0-9._-]/g,"_"),n=u.join(e,"AppData","Roaming","Microsoft","Windows","Start Menu","Programs","Startup");return u.join(n,`${r}.lnk`)}function S(t){return String(t??"").replace(/"/g,'""')}function Z(t,e){const r=u.join(u.dirname(t),u.basename(e).replace(/\.lnk$/,"-create.vbs")),n=["Option Explicit","Dim shell, shortcut",'Set shell = CreateObject("WScript.Shell")',`Set shortcut = shell.CreateShortcut("${S(e)}")`,'shortcut.TargetPath = "wscript.exe"',`shortcut.Arguments = "//B //NoLogo \\"${S(t)}\\""`,"shortcut.WindowStyle = 7","shortcut.Save",""].join(`\r
|
|
45
|
+
`);return{path:r,content:n}}async function q(t){const{wrapperPath:e,shortcutPath:r,runCommand:n}=t,a=Z(e,r);for(let i=1;i<=3;i+=1){try{await w(a.path,a.content,"utf8"),await n("wscript.exe",[a.path,"//B","//NoLogo"])}catch{}finally{await h(a.path,{force:!0}).catch(()=>{})}if(E(r))return!0}return console.warn(`Warning: failed to create Windows logon-autostart shortcut at ${r}. The daemon will NOT start automatically after the next reboot/logon. Check Controlled Folder Access / antivirus blocking writes to the Startup folder, or create the shortcut manually.`),!1}async function K(t){try{const e=await t("whoami",["/user","/fo","csv","/nh"],{allowFailure:!0}),r=String(e?.stdout??"").match(/"(S-1-[0-9-]+)"/);if(r)return r[1]}catch{}return null}function Y(t){const e=`//B //NoLogo "${t.wrapperPath}"`;return`<?xml version="1.0" encoding="UTF-16"?>
|
|
46
|
+
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
|
47
|
+
<RegistrationInfo>
|
|
48
|
+
<Description>grix-connector daemon autostart</Description>
|
|
49
|
+
</RegistrationInfo>
|
|
50
|
+
<Triggers>
|
|
51
|
+
<LogonTrigger>
|
|
52
|
+
<Enabled>true</Enabled>
|
|
53
|
+
<UserId>${p(t.userId)}</UserId>
|
|
54
|
+
</LogonTrigger>
|
|
55
|
+
</Triggers>
|
|
56
|
+
<Principals>
|
|
57
|
+
<Principal id="Author">
|
|
58
|
+
<UserId>${p(t.userId)}</UserId>
|
|
59
|
+
<LogonType>InteractiveToken</LogonType>
|
|
60
|
+
<RunLevel>LeastPrivilege</RunLevel>
|
|
61
|
+
</Principal>
|
|
62
|
+
</Principals>
|
|
63
|
+
<Settings>
|
|
64
|
+
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
|
|
65
|
+
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
|
|
66
|
+
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
|
|
67
|
+
<AllowHardTerminate>true</AllowHardTerminate>
|
|
68
|
+
<StartWhenAvailable>true</StartWhenAvailable>
|
|
69
|
+
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
|
|
70
|
+
<IdleSettings>
|
|
71
|
+
<StopOnIdleEnd>false</StopOnIdleEnd>
|
|
72
|
+
<RestartOnIdle>false</RestartOnIdle>
|
|
73
|
+
</IdleSettings>
|
|
74
|
+
<AllowStartOnDemand>true</AllowStartOnDemand>
|
|
75
|
+
<Enabled>true</Enabled>
|
|
76
|
+
<Hidden>false</Hidden>
|
|
77
|
+
<RunOnlyIfIdle>false</RunOnlyIfIdle>
|
|
78
|
+
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
|
|
79
|
+
<Priority>7</Priority>
|
|
80
|
+
</Settings>
|
|
81
|
+
<Actions Context="Author">
|
|
82
|
+
<Exec>
|
|
83
|
+
<Command>wscript.exe</Command>
|
|
84
|
+
<Arguments>${p(e)}</Arguments>
|
|
85
|
+
</Exec>
|
|
86
|
+
</Actions>
|
|
87
|
+
</Task>
|
|
88
|
+
`}async function tt(t){const{serviceID:e,wrapperPath:r,runCommand:n}=t,a=await K(n)??l.userInfo().username,i=u.join(u.dirname(r),`${e}-task.xml`);try{const o=Y({userId:a,wrapperPath:r});return await w(i,"\uFEFF"+o,"utf16le"),await n("schtasks",["/Create","/TN",e,"/XML",i,"/F"]),!0}catch{return!1}finally{await h(i,{force:!0}).catch(()=>{})}}function et(t){const e=[`"${S(t.nodePath)}"`,`"${S(t.cliPath)}"`,...t.configDir?["--config-dir",`"${S(t.configDir)}"`]:[]].join(" ");return["Option Explicit","Dim shell, command, delayMs, rapidCount",`command = "${S(e)}"`,'Set shell = CreateObject("WScript.Shell")',"delayMs = 5000","rapidCount = 0","Do"," shell.Run command, 0, True"," rapidCount = rapidCount + 1"," If rapidCount >= 10 Then"," WScript.Sleep 300000"," rapidCount = 0"," Else"," WScript.Sleep delayMs"," End If","Loop",""].join(`\r
|
|
89
|
+
`)}function b(t){return`gui/${t??0}`}function N(t){const e=String(t?.stdout??"").trim();return String(t?.stderr??"").trim()||e||`exit=${Number(t?.exitCode??-1)}`}function R(t,e){if(Number(t?.exitCode??0)!==0)throw new Error(`${e}: ${N(t)}`)}function rt(){return{platform:"darwin",kind:"launchd",async install({serviceID:t,nodePath:e,cliPath:r,configDir:n,stdoutPath:a,stderrPath:i,environmentPath:s="",homeDir:o=l.homedir()}){const c=Q(t,o);return await P(u.dirname(c),{recursive:!0}),await w(c,z({serviceID:t,nodePath:e,cliPath:r,configDir:n,stdoutPath:a,stderrPath:i,environmentPath:s}),{encoding:"utf8",mode:384}),{definitionPath:c}},async start({serviceID:t,definitionPath:e,runCommand:r=d,uid:n=process.getuid?.()??0}){const a=b(n);let i=await r("launchctl",["bootstrap",a,e],{allowFailure:!0});Number(i?.exitCode??0)!==0&&(await r("launchctl",["bootout",`${a}/${t}`],{allowFailure:!0}),i=await r("launchctl",["bootstrap",a,e],{allowFailure:!0}),R(i,`launchctl bootstrap ${a}`));const s=await r("launchctl",["kickstart","-k",`${a}/${t}`],{allowFailure:!0});if(Number(s?.exitCode??0)!==0){const o=Number(i?.exitCode??0)===0?"":`, bootstrap=${N(i)}`;throw new Error(`launchctl start failed for ${a}/${t}: ${N(s)}${o}`)}},async stop({serviceID:t,runCommand:e=d,uid:r=process.getuid?.()??0}){const n=b(r);await e("launchctl",["bootout",`${n}/${t}`],{allowFailure:!0})},async restart({serviceID:t,definitionPath:e,runCommand:r=d,uid:n=process.getuid?.()??0}){const a=b(n);await r("launchctl",["bootout",`${a}/${t}`],{allowFailure:!0});for(let o=0;o<20&&(await r("launchctl",["print",`${a}/${t}`],{allowFailure:!0})).exitCode===0;o+=1)await new Promise(m=>setTimeout(m,250));try{await U(e)}catch{throw new Error(`launchd plist missing: ${e}`)}const i=await r("launchctl",["bootstrap",a,e],{allowFailure:!0});R(i,`launchctl bootstrap ${a}`);const s=await r("launchctl",["kickstart","-k",`${a}/${t}`],{allowFailure:!0});R(s,`launchctl kickstart ${a}/${t}`)},async uninstall({serviceID:t,definitionPath:e,runCommand:r=d,uid:n=process.getuid?.()??0}){const a=b(n);await r("launchctl",["bootout",`${a}/${t}`],{allowFailure:!0}),await h(e,{force:!0})},async discoverServices({homeDir:t=l.homedir()}={}){const e=u.join(t,"Library","LaunchAgents"),r=await v(e).catch(()=>[]),n=A("darwin"),a=[];for(const i of r){if(!i.startsWith(n)||!i.endsWith(".plist"))continue;const s=i.slice(0,-6),o=u.join(e,i);let c=null;try{const m=await g(o,"utf8");c=G(m)}catch{}a.push({serviceID:s,definitionPath:o,configDir:c})}return a},async isServiceLoaded({serviceID:t,runCommand:e=d,uid:r=process.getuid?.()??0}){const n=b(r),a=await e("launchctl",["print",`${n}/${t}`],{allowFailure:!0});return Number(a?.exitCode??1)===0}}}function nt(){return{platform:"win32",kind:"task-scheduler",async install({serviceID:t,nodePath:e,cliPath:r,configDir:n,runCommand:a=d,homeDir:i=l.homedir()}){const s=k(t,i);await P(u.dirname(s),{recursive:!0}),await w(s,et({nodePath:e,cliPath:r,configDir:n}),"utf8");let o=!1;H()&&(o=await tt({serviceID:t,wrapperPath:s,runCommand:a}));const c=I(t,i);return o?await h(c,{force:!0}).catch(()=>{}):await q({wrapperPath:s,shortcutPath:c,runCommand:a}),{definitionPath:o?`task:${t}`:`startup:${t}`}},async start({serviceID:t,definitionPath:e,runCommand:r=d,homeDir:n=l.homedir()}){const a=k(t,n);if(e.startsWith("task:"))try{await r("schtasks",["/Run","/TN",t]);return}catch{}F("wscript.exe",["//B","//NoLogo",a])},async stop({serviceID:t,runCommand:e=d,homeDir:r=l.homedir()}){await e("schtasks",["/End","/TN",t],{allowFailure:!0});const n=`${t}-wrapper.vbs`;await _(n,{platform:"win32"})},async restart({serviceID:t,definitionPath:e,runCommand:r=d,homeDir:n=l.homedir()}){await r("schtasks",["/End","/TN",t],{allowFailure:!0});const a=`${t}-wrapper.vbs`;await _(a,{platform:"win32"});const i=k(t,n);if(e?.startsWith("task:"))try{await r("schtasks",["/Run","/TN",t]);return}catch{}F("wscript.exe",["//B","//NoLogo",i])},async uninstall({serviceID:t,runCommand:e=d,homeDir:r=l.homedir()}){await e("schtasks",["/Delete","/TN",t,"/F"],{allowFailure:!0});const n=k(t,r);await h(n,{force:!0});const a=I(t,r);await h(a,{force:!0})},async discoverServices({homeDir:t=l.homedir(),runCommand:e=d}={}){const r=A("win32"),n=await e("schtasks",["/Query","/FO","CSV","/NH"],{allowFailure:!0}),a=[];if(Number(n?.exitCode??-1)===0){const o=String(n.stdout??"").split(/\r?\n/);for(const c of o){const m=c.match(/^"([^"]+)"/);if(!m)continue;const f=m[1];if(!f.startsWith(r))continue;let W=null;try{const x=k(f,t),D=(await g(x,"utf8")).match(/--config-dir\s+""([^""]+)""/);D&&(W=D[1])}catch{}a.push({serviceID:f,definitionPath:`task:${f}`,configDir:W})}}const i=u.join(t,"AppData","Roaming","Microsoft","Windows","Start Menu","Programs","Startup"),s=await v(i).catch(()=>[]);for(const o of s){if(!o.startsWith(r)||!o.endsWith(".lnk"))continue;const c=o.slice(0,-4);if(a.some(f=>f.serviceID===c))continue;let m=null;try{const f=k(c,t),x=(await g(f,"utf8")).match(/--config-dir\s+""([^""]+)""/);x&&(m=x[1])}catch{}a.push({serviceID:c,definitionPath:`startup:${c}`,configDir:m})}return a},async isServiceLoaded({serviceID:t,runCommand:e=d}){const r=await e("schtasks",["/Query","/TN",t,"/NH"],{allowFailure:!0});return Number(r?.exitCode??1)===0}}}function at(){return{platform:"linux",kind:"systemd-user",async install({serviceID:t,nodePath:e,cliPath:r,configDir:n,stdoutPath:a,stderrPath:i,homeDir:s=l.homedir(),runCommand:o=d}){const c=X(t,s);return await P(u.dirname(c),{recursive:!0}),await w(c,J({serviceID:t,nodePath:e,cliPath:r,configDir:n,stdoutPath:a,stderrPath:i}),{encoding:"utf8",mode:384}),await o("systemctl",["--user","daemon-reload"]),await o("systemctl",["--user","enable",`${t}.service`]),{definitionPath:c}},async start({serviceID:t,runCommand:e=d}){await e("systemctl",["--user","start",`${t}.service`])},async stop({serviceID:t,runCommand:e=d}){await e("systemctl",["--user","stop",`${t}.service`],{allowFailure:!0})},async restart({serviceID:t,runCommand:e=d}){await e("systemctl",["--user","restart",`${t}.service`])},async uninstall({serviceID:t,definitionPath:e,runCommand:r=d}){await r("systemctl",["--user","stop",`${t}.service`],{allowFailure:!0}),await r("systemctl",["--user","disable",`${t}.service`],{allowFailure:!0}),await h(e,{force:!0}),await r("systemctl",["--user","daemon-reload"])},async discoverServices({homeDir:t=l.homedir()}={}){const e=u.join(t,".config","systemd","user"),r=await v(e).catch(()=>[]),n=A("linux"),a=[];for(const i of r){if(!i.startsWith(n)||!i.endsWith(".service"))continue;const s=i.slice(0,-8),o=u.join(e,i);let c=null;try{const m=await g(o,"utf8");c=V(m)}catch{}a.push({serviceID:s,definitionPath:o,configDir:c})}return a},async isServiceLoaded({serviceID:t,runCommand:e=d}){const r=await e("systemctl",["--user","is-active",`${t}.service`],{allowFailure:!0});return String(r?.stdout??"").trim()==="active"}}}function $(t){try{const e=O(t,"utf8"),r=JSON.parse(e);if(r&&typeof r.service_id=="string"&&typeof r.node_path=="string"&&typeof r.cli_path=="string"&&typeof r.root_dir=="string")return r}catch{}return null}function it(t){return u.join(t,"daemon.lock.json")}function L(t){const e=it(t);try{const r=O(e,"utf8"),n=JSON.parse(r);if(typeof n?.pid=="number")return n.pid}catch{}return 0}function B(t){return u.join(t,".profile")}function ot(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function st(t){const e=[T(t.nodePath),T(t.cliPath)];t.configDir&&e.push("--config-dir",T(t.configDir));const r=e.join(" ");return`${r} status >/dev/null 2>&1 || (nohup ${r} start >/dev/null 2>&1 &)`}function ct(t,e){return`# >>> grix-connector autostart [${t}] >>>
|
|
90
|
+
${e}
|
|
48
91
|
# <<< grix-connector autostart [${t}] <<<
|
|
49
|
-
`}function
|
|
92
|
+
`}function M(t){const e=ot(t);return new RegExp(`(?:^|\\n)# >>> grix-connector autostart \\[${e}\\] >>>\\n[\\s\\S]*?\\n# <<< grix-connector autostart \\[${e}\\] <<<\\n?`,"m")}async function ut(t,e,r){let n="";try{n=await g(t,"utf8")}catch{}const a=ct(e,r),i=M(e);let s;if(i.test(n))s=n.replace(i,`
|
|
50
93
|
${a}`).replace(/^\n+/,"");else{const o=n.length===0||n.endsWith(`
|
|
51
94
|
`)?"":`
|
|
52
|
-
`;s=`${n}${o}${a}`}s!==n&&(await P(u.dirname(t),{recursive:!0}),await
|
|
53
|
-
`,{encoding:"utf8",mode:384});const
|
|
95
|
+
`;s=`${n}${o}${a}`}s!==n&&(await P(u.dirname(t),{recursive:!0}),await w(t,s,{encoding:"utf8"}))}async function lt(t,e){let r="";try{r=await g(t,"utf8")}catch{return}const n=M(e);if(!n.test(r))return;const a=r.replace(n,"").replace(/^\n+/,"");await w(t,a,{encoding:"utf8"})}function dt(){return{platform:"linux",kind:"bare-daemon",async install({serviceID:t,nodePath:e,cliPath:r,configDir:n,stdoutPath:a,stderrPath:i,homeDir:s=l.homedir()}){const o=y(t,s);await P(u.dirname(o),{recursive:!0});const c=u.resolve(u.dirname(u.dirname(a||i||o))),m={schema_version:1,service_id:t,node_path:e,cli_path:r,config_dir:n??"",root_dir:c,stdout_path:a,stderr_path:i,installed_at:Date.now()};await w(o,`${JSON.stringify(m,null,2)}
|
|
96
|
+
`,{encoding:"utf8",mode:384});const f=st({nodePath:e,cliPath:r,configDir:n??""});return await ut(B(s),t,f),{definitionPath:o}},async start({serviceID:t,homeDir:e=l.homedir()}){const r=y(t,e),n=$(r);if(!n)throw new Error(`bare-daemon marker missing: ${r}`);const a=[n.cli_path];n.config_dir&&a.push("--config-dir",n.config_dir),F(n.node_path,a)},async stop({serviceID:t,homeDir:e=l.homedir()}){const r=y(t,e),n=$(r);if(!n)return;const a=L(n.root_dir);if(a>0&&C(a))try{process.kill(a,"SIGTERM")}catch{}},async restart(t){await this.stop(t);const e=Date.now()+5e3,r=y(t.serviceID,t.homeDir??l.homedir()),n=$(r);for(;n&&Date.now()<e;){const a=L(n.root_dir);if(a<=0||!C(a))break;await new Promise(i=>setTimeout(i,100))}await this.start(t)},async uninstall({serviceID:t,homeDir:e=l.homedir()}){const r=y(t,e),n=$(r);if(n){const a=L(n.root_dir);if(a>0&&C(a))try{process.kill(a,"SIGTERM")}catch{}}await h(r,{force:!0}),await lt(B(e),t)},async discoverServices({homeDir:t=l.homedir()}={}){const e=u.join(t,".grix","service"),r=await v(e).catch(()=>[]),n=A("linux"),a=[];for(const i of r){if(!i.startsWith(n)||!i.endsWith(".bare.json"))continue;const s=i.slice(0,-10),o=u.join(e,i),c=$(o);a.push({serviceID:s,definitionPath:o,configDir:c?.config_dir||null})}return a},async isServiceLoaded({serviceID:t,homeDir:e=l.homedir()}){const r=y(t,e),n=$(r);if(!n)return!1;const a=L(n.root_dir);return a>0&&C(a)}}}function mt(t=process.getuid?.()??0){if(process.env.GRIX_FORCE_BARE_DAEMON==="1")return!1;const e=process.env.XDG_RUNTIME_DIR;return!!(e&&E(u.join(e,"bus"))||E(`/run/user/${t}/bus`))}function St(t=process.platform,e={}){return t==="darwin"?rt():t==="win32"?nt():e.systemdUserAvailable??mt()?at():dt()}export{St as getPlatformServiceAdapter,mt as isSystemdUserBusAvailable,lt as removeProfileAutostart,ut as upsertProfileAutostart};
|
|
@@ -1,202 +1,202 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: grix-admin
|
|
3
|
-
description: Responsible for OpenClaw local configuration, binding, and runtime convergence; can create new remote API agents through the current agent's WS channel, and supports querying, creating, modifying agent categories and assigning categories to agents, reusable across agent creation and management flows.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Grix Agent Admin
|
|
7
|
-
|
|
8
|
-
`grix-admin` is responsible for three things:
|
|
9
|
-
|
|
10
|
-
1. Landing existing remote agent parameters into local OpenClaw, and handling runtime convergence after binding.
|
|
11
|
-
2. When the current main agent is already online and has the corresponding scope, creating new remote API agents through `grix_admin`'s direct actions, then continuing with local landing.
|
|
12
|
-
3. During agent creation or subsequent agent management, reusing `grix_admin`'s direct actions to query categories, create categories, modify categories, and assign categories to agents.
|
|
13
|
-
|
|
14
|
-
## Entry Method
|
|
15
|
-
|
|
16
|
-
1. In most cases, enter this skill from `grix_admin`'s `task` entry; the first line of `task` must clearly state `bind-local`, `create-and-bind`, or `category-manage`.
|
|
17
|
-
2. Only when executing "remote API agent creation / category query / category creation / category modification / category assignment" remote steps within this skill should you directly call `grix_admin` once, without passing `task` again.
|
|
18
|
-
3. In new flows, always explicitly pass `action` when directly calling `grix_admin`:
|
|
19
|
-
- `create_agent`
|
|
20
|
-
- `list_categories`
|
|
21
|
-
- `create_category`
|
|
22
|
-
- `update_category`
|
|
23
|
-
- `assign_category`
|
|
24
|
-
4. The legacy direct call format for `create_agent` (passing only `agentName` and other fields without `action`) is still compatible, but should not be used in new flows.
|
|
25
|
-
|
|
26
|
-
## Direct Action List
|
|
27
|
-
|
|
28
|
-
1. `action=create_agent`
|
|
29
|
-
- Required: `agentName`
|
|
30
|
-
- Optional: `introduction`, `isMain`, `categoryId`, `categoryName`, `parentCategoryId`, `categorySortOrder`
|
|
31
|
-
- `categoryId` and `categoryName` cannot be provided simultaneously
|
|
32
|
-
- When `categoryName` is given, it first checks for duplicates under `parentCategoryId`; if not found, creates and assigns
|
|
33
|
-
2. `action=list_categories`
|
|
34
|
-
- Required: (none)
|
|
35
|
-
3. `action=create_category`
|
|
36
|
-
- Required: `name`, `parentId`
|
|
37
|
-
- Optional: `sortOrder`
|
|
38
|
-
4. `action=update_category`
|
|
39
|
-
- Required: `categoryId`, `name`, `parentId`
|
|
40
|
-
- Optional: `sortOrder`
|
|
41
|
-
5. `action=assign_category`
|
|
42
|
-
- Required: `agentId`, `categoryId`
|
|
43
|
-
- `categoryId=0` means clear the category
|
|
44
|
-
|
|
45
|
-
## Mode A: bind-local (Initial Handoff from grix-register)
|
|
46
|
-
|
|
47
|
-
Input fields (written in `grix_admin.task`, all required):
|
|
48
|
-
|
|
49
|
-
1. First line must be `bind-local`
|
|
50
|
-
2. `agent_name`
|
|
51
|
-
3. `agent_id`
|
|
52
|
-
4. `api_endpoint`
|
|
53
|
-
5. `api_key`
|
|
54
|
-
|
|
55
|
-
Execution rules:
|
|
56
|
-
|
|
57
|
-
1. Do not perform remote creation; execute local binding directly. Do not call any script that directly modifies `openclaw.json`.
|
|
58
|
-
2. Prepare local directories first:
|
|
59
|
-
- `workspace=~/.openclaw/workspace-<agent_name>`
|
|
60
|
-
- `agentDir=~/.openclaw/agents/<agent_name>/agent`
|
|
61
|
-
- Persona files go only in the `workspace` root: `IDENTITY.md`, `SOUL.md`, `AGENTS.md`, and optionally `USER.md` / `MEMORY.md`
|
|
62
|
-
- Do not put persona files in `agentDir`; `agentDir` is the per-agent runtime state directory managed by OpenClaw
|
|
63
|
-
- If `workspace` is missing required persona files, add minimal files to avoid an empty workspace for the new agent
|
|
64
|
-
3. Read existing configuration; if paths do not exist, treat as empty object / empty array:
|
|
65
|
-
- `channels.grix.accounts`
|
|
66
|
-
- `agents.list`
|
|
67
|
-
- `tools.profile`
|
|
68
|
-
- `tools.alsoAllow`
|
|
69
|
-
- `tools.sessions.visibility`
|
|
70
|
-
- To confirm existing Grix bindings, additionally use `openclaw agents bindings --agent <agent_name> --json` to view the current binding list
|
|
71
|
-
4. Calculate target values for this operation:
|
|
72
|
-
- `channels.grix.accounts.<agent_name>`: write `name`, `enabled=true`, `apiKey`, `wsUrl`, `agentId`
|
|
73
|
-
- `agents.list`: ensure entry exists with `id=<agent_name>`, `name=<agent_name>`, `workspace`, `agentDir`, `model`
|
|
74
|
-
- Grix binding: ensure the target agent is ultimately bound to `grix:<agent_name>`
|
|
75
|
-
- `tools.profile`: set to `"coding"`
|
|
76
|
-
- `tools.alsoAllow`: must include at least `message`, `grix_query`, `grix_group`, `grix_register`, `grix_message_send`, `grix_message_unsend`
|
|
77
|
-
- If the current binding target is the main agent, also ensure that agent's own `tools.alsoAllow` retains `grix_admin`, `grix_egg`, `grix_update`, `openclaw_memory_setup`; this set goes only at the agent level, not in global `tools.alsoAllow`
|
|
78
|
-
- `tools.sessions.visibility`: set to `"agent"`
|
|
79
|
-
- If `channels.grix.enabled=false`, change it back to `true`
|
|
80
|
-
5. Rules for determining `model`:
|
|
81
|
-
- First reuse the existing `model` from that local agent's entry
|
|
82
|
-
- If the existing entry has none, use `agents.defaults.model.primary`
|
|
83
|
-
- If still unavailable, clearly state that model is missing, stop execution, do not guess
|
|
84
|
-
6. Write using official CLI item by item; do not overwrite the entire config:
|
|
85
|
-
- `openclaw config set channels.grix.accounts.<agent_name> '<ACCOUNT_JSON>' --strict-json`
|
|
86
|
-
- `openclaw config set agents.list '<NEXT_AGENTS_LIST_JSON>' --strict-json`
|
|
87
|
-
- `openclaw agents bind --agent <agent_name> --bind grix:<agent_name>`
|
|
88
|
-
- `openclaw config set tools.profile '"coding"' --strict-json`
|
|
89
|
-
- `openclaw config set tools.alsoAllow '["message","grix_query","grix_group","grix_register","grix_message_send","grix_message_unsend"]' --strict-json`
|
|
90
|
-
- If the current binding target is the main agent, also merge `grix_admin`, `grix_egg`, `grix_update`, `openclaw_memory_setup` into that agent's own `agents.list` record's `tools.alsoAllow`; do not put this set in global `tools.alsoAllow`
|
|
91
|
-
- `openclaw config set tools.sessions.visibility '"agent"' --strict-json`
|
|
92
|
-
- Only when the current config explicitly has `channels.grix.enabled` turned off, execute `openclaw config set channels.grix.enabled true --strict-json`
|
|
93
|
-
7. After writing, must perform static validation:
|
|
94
|
-
- `openclaw config validate`
|
|
95
|
-
- `openclaw config get --json channels.grix.accounts.<agent_name>`
|
|
96
|
-
- `openclaw config get --json agents.list`
|
|
97
|
-
- `openclaw agents bindings --agent <agent_name> --json`
|
|
98
|
-
8. If this invocation already has real verification conditions, must immediately perform a real routing verification; prefer reusing the current install/acceptance context, do not invent a new probe. The following situations are all considered as binding runtime not yet switched successfully:
|
|
99
|
-
- Reply falls to the main agent
|
|
100
|
-
- Reply behaves as the default assistant
|
|
101
|
-
- Reply still shows old persona, old config, or obvious ID mismatch
|
|
102
|
-
9. Only when this `bind-local` invocation itself handles real verification, and step 7 static validation passed but step 8 real routing verification still fails, is one `openclaw gateway restart` allowed as targeted remediation; after restart, must redo the same round of real routing verification.
|
|
103
|
-
10. Success definition:
|
|
104
|
-
- Can perform real verification: only "static validation passed + real routing verification passed" counts as `bind-local` complete
|
|
105
|
-
- This invocation cannot yet perform real verification: can only clearly state "config has been written, runtime not yet tested, needs subsequent upper-level flow to continue verification"; do not claim it has fully taken effect
|
|
106
|
-
|
|
107
|
-
## Mode B: create-and-bind (Subsequent Management When Main Channel and Scope Are Available)
|
|
108
|
-
|
|
109
|
-
Fields written in `grix_admin.task`:
|
|
110
|
-
|
|
111
|
-
1. First line must be `create-and-bind`
|
|
112
|
-
2. `agentName` (required)
|
|
113
|
-
3. `introduction` (optional)
|
|
114
|
-
5. `isMain` (optional, default `false`)
|
|
115
|
-
6. `categoryId` (optional): assign the new agent directly to an existing category
|
|
116
|
-
7. `categoryName` (optional): create if not exists, then assign
|
|
117
|
-
8. `parentCategoryId` (optional): only used in the `categoryName` approach, default `0`
|
|
118
|
-
9. `categorySortOrder` (optional): only used when creating a category
|
|
119
|
-
|
|
120
|
-
Execution rules:
|
|
121
|
-
|
|
122
|
-
1. Confirm the current session is bound to a valid Grix account; cross-account execution is prohibited.
|
|
123
|
-
2. If both `categoryId` and `categoryName` are provided, report an error and stop immediately to avoid ambiguity.
|
|
124
|
-
3. Call `grix_admin` only once with `action=create_agent`, delegating remote creation and optional category handling to it; pass:
|
|
125
|
-
- `action=create_agent`
|
|
126
|
-
- `agentName`
|
|
127
|
-
- Optional `introduction`
|
|
128
|
-
- Optional `isMain`
|
|
129
|
-
- Optional `categoryId`
|
|
130
|
-
- Optional `categoryName`
|
|
131
|
-
- Optional `parentCategoryId`
|
|
132
|
-
- Optional `categorySortOrder`
|
|
133
|
-
4. After remote creation succeeds, read `createdAgent.id`, `createdAgent.agent_name`, `createdAgent.api_endpoint`, `createdAgent.api_key` from the return result.
|
|
134
|
-
5. If the request included category information, check whether the return already includes the category assignment result; if not, proceed with supplementary steps according to `categoryId` / `categoryName` rules and explain the reason.
|
|
135
|
-
6. In the `categoryName` flow, if multiple categories with the exact same name appear under the same parent, stop and ask the owner to clean up categories or use an explicit `categoryId` instead.
|
|
136
|
-
7. After remote creation and optional category steps succeed, immediately transition to the `bind-local` local binding steps; if this invocation already has real verification context, follow the same "static validation -> real routing verification -> one restart if needed -> same-round retest" convergence rules; otherwise explicitly hand the "continue real verification" responsibility back to the upper-level flow.
|
|
137
|
-
8. `isMain=true` should only be used when actually creating a new main API agent; generally subsequent new agents should not enable this by default.
|
|
138
|
-
9. Throughout the `create-and-bind` flow, do not treat "config written successfully" as completion; only when this invocation itself handles real routing verification and verification fails should one `openclaw gateway restart` be treated as targeted remediation.
|
|
139
|
-
|
|
140
|
-
## Mode C: category-manage (Category Management)
|
|
141
|
-
|
|
142
|
-
Fields written in `grix_admin.task`:
|
|
143
|
-
|
|
144
|
-
1. First line must be `category-manage`
|
|
145
|
-
2. `operation` (required): only `list`, `create`, `update`, `assign` are allowed
|
|
146
|
-
4. `name` (`create` / `update` required)
|
|
147
|
-
5. `parentId` (`create` / `update` required)
|
|
148
|
-
6. `sortOrder` (`create` / `update` optional)
|
|
149
|
-
7. `categoryId` (`update` / `assign` required; for `assign`, `0` means clear)
|
|
150
|
-
8. `agentId` (`assign` required)
|
|
151
|
-
|
|
152
|
-
Execution rules:
|
|
153
|
-
|
|
154
|
-
1. Strictly bound to the current session account; cross-account execution is prohibited.
|
|
155
|
-
2. All remote steps must only be completed through `grix_admin`'s direct actions; hand-written HTTP and temporary scripts are prohibited.
|
|
156
|
-
3. `operation=list`
|
|
157
|
-
- Call `action=list_categories`
|
|
158
|
-
4. `operation=create`
|
|
159
|
-
- Call `action=create_category`
|
|
160
|
-
5. `operation=update`
|
|
161
|
-
- Call `action=update_category`
|
|
162
|
-
6. `operation=assign`
|
|
163
|
-
- Call `action=assign_category`
|
|
164
|
-
- `categoryId=0` explicitly means clear the agent's current category
|
|
165
|
-
7. If the current management task also includes "creating a new agent", prefer using `create-and-bind`; do not split remote creation into other custom flows.
|
|
166
|
-
|
|
167
|
-
## Remote Creation Fallback Conditions
|
|
168
|
-
|
|
169
|
-
If the current task has neither an existing `agent_name`, `agent_id`, `api_endpoint`, `api_key`, nor an available online main channel or `agent.api.create` permission, stop this skill first and clearly prompt the user to create the remote agent through the backend admin path. After obtaining these parameters, proceed with `bind-local`.
|
|
170
|
-
|
|
171
|
-
## Guardrails (Applicable to All Three Modes)
|
|
172
|
-
|
|
173
|
-
1. Never ask user for website account/password.
|
|
174
|
-
2. `bind-local` mode must not call back to `grix-register` to avoid circular routing.
|
|
175
|
-
3. All remote creation / category-related actions must only go through `grix_admin` direct actions via the current account's WS channel; do not hand-write HTTP or fall back to legacy scripts.
|
|
176
|
-
4. The complete `api_key` is only passed back once; do not repeatedly echo it in plaintext.
|
|
177
|
-
5. Before local `openclaw config set` / `validate` succeeds, do not claim config is complete; when this invocation can perform real verification, do not claim `bind-local` / `create-and-bind` is complete until real routing verification passes.
|
|
178
|
-
6. During an install private chat, do not manually modify `openclaw.json` and then execute `openclaw gateway restart`.
|
|
179
|
-
7. Do not reference or call `grix_agent_bind.py`; this skill only uses official OpenClaw config commands.
|
|
180
|
-
|
|
181
|
-
## Error Handling Rules
|
|
182
|
-
|
|
183
|
-
1. `bind-local` missing fields: clearly state which field is missing and stop.
|
|
184
|
-
2. `create-and-bind` missing `agentName`: clearly state which field is missing and stop.
|
|
185
|
-
3. `create-and-bind` with both `categoryId` and `categoryName`: clearly state the conflict and stop.
|
|
186
|
-
4. `category-manage` missing `operation` or operation-specific fields: clearly state which field is missing and stop.
|
|
187
|
-
5. Remote returns `code=4003` or message explicitly mentions `agent.api.create`: tell the owner to grant `agent.api.create` on the Agent permissions page.
|
|
188
|
-
6. Remote returns `code=4003` or message explicitly mentions `agent.category.list` / `agent.category.create` / `agent.category.update` / `agent.category.assign`: tell the owner to grant the corresponding scope on the Agent permissions page.
|
|
189
|
-
7. Missing remote agent parameters and current account cannot create: clearly require backend admin creation first.
|
|
190
|
-
8. Local config failure: return the failed command and result, then stop; emphasize which `get` / `set` / `validate` step failed.
|
|
191
|
-
9. This invocation handles real routing verification, and after one `openclaw gateway restart` retest still fails: clearly state "static config has been written, but runtime has not yet switched successfully"; converge as failed or partially complete, do not write it as success.
|
|
192
|
-
|
|
193
|
-
## Response Style
|
|
194
|
-
|
|
195
|
-
1. Clearly state whether the current execution is `bind-local`, `create-and-bind`, or `category-manage`.
|
|
196
|
-
2. Report in phases: remote creation / category handling (if any) / local config writing / validation results.
|
|
197
|
-
3. Clearly state whether local config has taken effect; if only static config succeeded but this invocation cannot perform real verification, can only write "config has been written, runtime not yet tested, needs subsequent flow to continue verification"; if only the category step succeeded, also state that clearly.
|
|
198
|
-
4. If remote creation succeeded but category or local binding subsequently failed, clearly state it is "partially complete"; do not generically write it as success.
|
|
199
|
-
|
|
200
|
-
## References
|
|
201
|
-
|
|
202
|
-
1. [references/api-contract.md](references/api-contract.md)
|
|
1
|
+
---
|
|
2
|
+
name: grix-admin
|
|
3
|
+
description: Responsible for OpenClaw local configuration, binding, and runtime convergence; can create new remote API agents through the current agent's WS channel, and supports querying, creating, modifying agent categories and assigning categories to agents, reusable across agent creation and management flows.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Grix Agent Admin
|
|
7
|
+
|
|
8
|
+
`grix-admin` is responsible for three things:
|
|
9
|
+
|
|
10
|
+
1. Landing existing remote agent parameters into local OpenClaw, and handling runtime convergence after binding.
|
|
11
|
+
2. When the current main agent is already online and has the corresponding scope, creating new remote API agents through `grix_admin`'s direct actions, then continuing with local landing.
|
|
12
|
+
3. During agent creation or subsequent agent management, reusing `grix_admin`'s direct actions to query categories, create categories, modify categories, and assign categories to agents.
|
|
13
|
+
|
|
14
|
+
## Entry Method
|
|
15
|
+
|
|
16
|
+
1. In most cases, enter this skill from `grix_admin`'s `task` entry; the first line of `task` must clearly state `bind-local`, `create-and-bind`, or `category-manage`.
|
|
17
|
+
2. Only when executing "remote API agent creation / category query / category creation / category modification / category assignment" remote steps within this skill should you directly call `grix_admin` once, without passing `task` again.
|
|
18
|
+
3. In new flows, always explicitly pass `action` when directly calling `grix_admin`:
|
|
19
|
+
- `create_agent`
|
|
20
|
+
- `list_categories`
|
|
21
|
+
- `create_category`
|
|
22
|
+
- `update_category`
|
|
23
|
+
- `assign_category`
|
|
24
|
+
4. The legacy direct call format for `create_agent` (passing only `agentName` and other fields without `action`) is still compatible, but should not be used in new flows.
|
|
25
|
+
|
|
26
|
+
## Direct Action List
|
|
27
|
+
|
|
28
|
+
1. `action=create_agent`
|
|
29
|
+
- Required: `agentName`
|
|
30
|
+
- Optional: `introduction`, `isMain`, `categoryId`, `categoryName`, `parentCategoryId`, `categorySortOrder`
|
|
31
|
+
- `categoryId` and `categoryName` cannot be provided simultaneously
|
|
32
|
+
- When `categoryName` is given, it first checks for duplicates under `parentCategoryId`; if not found, creates and assigns
|
|
33
|
+
2. `action=list_categories`
|
|
34
|
+
- Required: (none)
|
|
35
|
+
3. `action=create_category`
|
|
36
|
+
- Required: `name`, `parentId`
|
|
37
|
+
- Optional: `sortOrder`
|
|
38
|
+
4. `action=update_category`
|
|
39
|
+
- Required: `categoryId`, `name`, `parentId`
|
|
40
|
+
- Optional: `sortOrder`
|
|
41
|
+
5. `action=assign_category`
|
|
42
|
+
- Required: `agentId`, `categoryId`
|
|
43
|
+
- `categoryId=0` means clear the category
|
|
44
|
+
|
|
45
|
+
## Mode A: bind-local (Initial Handoff from grix-register)
|
|
46
|
+
|
|
47
|
+
Input fields (written in `grix_admin.task`, all required):
|
|
48
|
+
|
|
49
|
+
1. First line must be `bind-local`
|
|
50
|
+
2. `agent_name`
|
|
51
|
+
3. `agent_id`
|
|
52
|
+
4. `api_endpoint`
|
|
53
|
+
5. `api_key`
|
|
54
|
+
|
|
55
|
+
Execution rules:
|
|
56
|
+
|
|
57
|
+
1. Do not perform remote creation; execute local binding directly. Do not call any script that directly modifies `openclaw.json`.
|
|
58
|
+
2. Prepare local directories first:
|
|
59
|
+
- `workspace=~/.openclaw/workspace-<agent_name>`
|
|
60
|
+
- `agentDir=~/.openclaw/agents/<agent_name>/agent`
|
|
61
|
+
- Persona files go only in the `workspace` root: `IDENTITY.md`, `SOUL.md`, `AGENTS.md`, and optionally `USER.md` / `MEMORY.md`
|
|
62
|
+
- Do not put persona files in `agentDir`; `agentDir` is the per-agent runtime state directory managed by OpenClaw
|
|
63
|
+
- If `workspace` is missing required persona files, add minimal files to avoid an empty workspace for the new agent
|
|
64
|
+
3. Read existing configuration; if paths do not exist, treat as empty object / empty array:
|
|
65
|
+
- `channels.grix.accounts`
|
|
66
|
+
- `agents.list`
|
|
67
|
+
- `tools.profile`
|
|
68
|
+
- `tools.alsoAllow`
|
|
69
|
+
- `tools.sessions.visibility`
|
|
70
|
+
- To confirm existing Grix bindings, additionally use `openclaw agents bindings --agent <agent_name> --json` to view the current binding list
|
|
71
|
+
4. Calculate target values for this operation:
|
|
72
|
+
- `channels.grix.accounts.<agent_name>`: write `name`, `enabled=true`, `apiKey`, `wsUrl`, `agentId`
|
|
73
|
+
- `agents.list`: ensure entry exists with `id=<agent_name>`, `name=<agent_name>`, `workspace`, `agentDir`, `model`
|
|
74
|
+
- Grix binding: ensure the target agent is ultimately bound to `grix:<agent_name>`
|
|
75
|
+
- `tools.profile`: set to `"coding"`
|
|
76
|
+
- `tools.alsoAllow`: must include at least `message`, `grix_query`, `grix_group`, `grix_register`, `grix_message_send`, `grix_message_unsend`
|
|
77
|
+
- If the current binding target is the main agent, also ensure that agent's own `tools.alsoAllow` retains `grix_admin`, `grix_egg`, `grix_update`, `openclaw_memory_setup`; this set goes only at the agent level, not in global `tools.alsoAllow`
|
|
78
|
+
- `tools.sessions.visibility`: set to `"agent"`
|
|
79
|
+
- If `channels.grix.enabled=false`, change it back to `true`
|
|
80
|
+
5. Rules for determining `model`:
|
|
81
|
+
- First reuse the existing `model` from that local agent's entry
|
|
82
|
+
- If the existing entry has none, use `agents.defaults.model.primary`
|
|
83
|
+
- If still unavailable, clearly state that model is missing, stop execution, do not guess
|
|
84
|
+
6. Write using official CLI item by item; do not overwrite the entire config:
|
|
85
|
+
- `openclaw config set channels.grix.accounts.<agent_name> '<ACCOUNT_JSON>' --strict-json`
|
|
86
|
+
- `openclaw config set agents.list '<NEXT_AGENTS_LIST_JSON>' --strict-json`
|
|
87
|
+
- `openclaw agents bind --agent <agent_name> --bind grix:<agent_name>`
|
|
88
|
+
- `openclaw config set tools.profile '"coding"' --strict-json`
|
|
89
|
+
- `openclaw config set tools.alsoAllow '["message","grix_query","grix_group","grix_register","grix_message_send","grix_message_unsend"]' --strict-json`
|
|
90
|
+
- If the current binding target is the main agent, also merge `grix_admin`, `grix_egg`, `grix_update`, `openclaw_memory_setup` into that agent's own `agents.list` record's `tools.alsoAllow`; do not put this set in global `tools.alsoAllow`
|
|
91
|
+
- `openclaw config set tools.sessions.visibility '"agent"' --strict-json`
|
|
92
|
+
- Only when the current config explicitly has `channels.grix.enabled` turned off, execute `openclaw config set channels.grix.enabled true --strict-json`
|
|
93
|
+
7. After writing, must perform static validation:
|
|
94
|
+
- `openclaw config validate`
|
|
95
|
+
- `openclaw config get --json channels.grix.accounts.<agent_name>`
|
|
96
|
+
- `openclaw config get --json agents.list`
|
|
97
|
+
- `openclaw agents bindings --agent <agent_name> --json`
|
|
98
|
+
8. If this invocation already has real verification conditions, must immediately perform a real routing verification; prefer reusing the current install/acceptance context, do not invent a new probe. The following situations are all considered as binding runtime not yet switched successfully:
|
|
99
|
+
- Reply falls to the main agent
|
|
100
|
+
- Reply behaves as the default assistant
|
|
101
|
+
- Reply still shows old persona, old config, or obvious ID mismatch
|
|
102
|
+
9. Only when this `bind-local` invocation itself handles real verification, and step 7 static validation passed but step 8 real routing verification still fails, is one `openclaw gateway restart` allowed as targeted remediation; after restart, must redo the same round of real routing verification.
|
|
103
|
+
10. Success definition:
|
|
104
|
+
- Can perform real verification: only "static validation passed + real routing verification passed" counts as `bind-local` complete
|
|
105
|
+
- This invocation cannot yet perform real verification: can only clearly state "config has been written, runtime not yet tested, needs subsequent upper-level flow to continue verification"; do not claim it has fully taken effect
|
|
106
|
+
|
|
107
|
+
## Mode B: create-and-bind (Subsequent Management When Main Channel and Scope Are Available)
|
|
108
|
+
|
|
109
|
+
Fields written in `grix_admin.task`:
|
|
110
|
+
|
|
111
|
+
1. First line must be `create-and-bind`
|
|
112
|
+
2. `agentName` (required)
|
|
113
|
+
3. `introduction` (optional)
|
|
114
|
+
5. `isMain` (optional, default `false`)
|
|
115
|
+
6. `categoryId` (optional): assign the new agent directly to an existing category
|
|
116
|
+
7. `categoryName` (optional): create if not exists, then assign
|
|
117
|
+
8. `parentCategoryId` (optional): only used in the `categoryName` approach, default `0`
|
|
118
|
+
9. `categorySortOrder` (optional): only used when creating a category
|
|
119
|
+
|
|
120
|
+
Execution rules:
|
|
121
|
+
|
|
122
|
+
1. Confirm the current session is bound to a valid Grix account; cross-account execution is prohibited.
|
|
123
|
+
2. If both `categoryId` and `categoryName` are provided, report an error and stop immediately to avoid ambiguity.
|
|
124
|
+
3. Call `grix_admin` only once with `action=create_agent`, delegating remote creation and optional category handling to it; pass:
|
|
125
|
+
- `action=create_agent`
|
|
126
|
+
- `agentName`
|
|
127
|
+
- Optional `introduction`
|
|
128
|
+
- Optional `isMain`
|
|
129
|
+
- Optional `categoryId`
|
|
130
|
+
- Optional `categoryName`
|
|
131
|
+
- Optional `parentCategoryId`
|
|
132
|
+
- Optional `categorySortOrder`
|
|
133
|
+
4. After remote creation succeeds, read `createdAgent.id`, `createdAgent.agent_name`, `createdAgent.api_endpoint`, `createdAgent.api_key` from the return result.
|
|
134
|
+
5. If the request included category information, check whether the return already includes the category assignment result; if not, proceed with supplementary steps according to `categoryId` / `categoryName` rules and explain the reason.
|
|
135
|
+
6. In the `categoryName` flow, if multiple categories with the exact same name appear under the same parent, stop and ask the owner to clean up categories or use an explicit `categoryId` instead.
|
|
136
|
+
7. After remote creation and optional category steps succeed, immediately transition to the `bind-local` local binding steps; if this invocation already has real verification context, follow the same "static validation -> real routing verification -> one restart if needed -> same-round retest" convergence rules; otherwise explicitly hand the "continue real verification" responsibility back to the upper-level flow.
|
|
137
|
+
8. `isMain=true` should only be used when actually creating a new main API agent; generally subsequent new agents should not enable this by default.
|
|
138
|
+
9. Throughout the `create-and-bind` flow, do not treat "config written successfully" as completion; only when this invocation itself handles real routing verification and verification fails should one `openclaw gateway restart` be treated as targeted remediation.
|
|
139
|
+
|
|
140
|
+
## Mode C: category-manage (Category Management)
|
|
141
|
+
|
|
142
|
+
Fields written in `grix_admin.task`:
|
|
143
|
+
|
|
144
|
+
1. First line must be `category-manage`
|
|
145
|
+
2. `operation` (required): only `list`, `create`, `update`, `assign` are allowed
|
|
146
|
+
4. `name` (`create` / `update` required)
|
|
147
|
+
5. `parentId` (`create` / `update` required)
|
|
148
|
+
6. `sortOrder` (`create` / `update` optional)
|
|
149
|
+
7. `categoryId` (`update` / `assign` required; for `assign`, `0` means clear)
|
|
150
|
+
8. `agentId` (`assign` required)
|
|
151
|
+
|
|
152
|
+
Execution rules:
|
|
153
|
+
|
|
154
|
+
1. Strictly bound to the current session account; cross-account execution is prohibited.
|
|
155
|
+
2. All remote steps must only be completed through `grix_admin`'s direct actions; hand-written HTTP and temporary scripts are prohibited.
|
|
156
|
+
3. `operation=list`
|
|
157
|
+
- Call `action=list_categories`
|
|
158
|
+
4. `operation=create`
|
|
159
|
+
- Call `action=create_category`
|
|
160
|
+
5. `operation=update`
|
|
161
|
+
- Call `action=update_category`
|
|
162
|
+
6. `operation=assign`
|
|
163
|
+
- Call `action=assign_category`
|
|
164
|
+
- `categoryId=0` explicitly means clear the agent's current category
|
|
165
|
+
7. If the current management task also includes "creating a new agent", prefer using `create-and-bind`; do not split remote creation into other custom flows.
|
|
166
|
+
|
|
167
|
+
## Remote Creation Fallback Conditions
|
|
168
|
+
|
|
169
|
+
If the current task has neither an existing `agent_name`, `agent_id`, `api_endpoint`, `api_key`, nor an available online main channel or `agent.api.create` permission, stop this skill first and clearly prompt the user to create the remote agent through the backend admin path. After obtaining these parameters, proceed with `bind-local`.
|
|
170
|
+
|
|
171
|
+
## Guardrails (Applicable to All Three Modes)
|
|
172
|
+
|
|
173
|
+
1. Never ask user for website account/password.
|
|
174
|
+
2. `bind-local` mode must not call back to `grix-register` to avoid circular routing.
|
|
175
|
+
3. All remote creation / category-related actions must only go through `grix_admin` direct actions via the current account's WS channel; do not hand-write HTTP or fall back to legacy scripts.
|
|
176
|
+
4. The complete `api_key` is only passed back once; do not repeatedly echo it in plaintext.
|
|
177
|
+
5. Before local `openclaw config set` / `validate` succeeds, do not claim config is complete; when this invocation can perform real verification, do not claim `bind-local` / `create-and-bind` is complete until real routing verification passes.
|
|
178
|
+
6. During an install private chat, do not manually modify `openclaw.json` and then execute `openclaw gateway restart`.
|
|
179
|
+
7. Do not reference or call `grix_agent_bind.py`; this skill only uses official OpenClaw config commands.
|
|
180
|
+
|
|
181
|
+
## Error Handling Rules
|
|
182
|
+
|
|
183
|
+
1. `bind-local` missing fields: clearly state which field is missing and stop.
|
|
184
|
+
2. `create-and-bind` missing `agentName`: clearly state which field is missing and stop.
|
|
185
|
+
3. `create-and-bind` with both `categoryId` and `categoryName`: clearly state the conflict and stop.
|
|
186
|
+
4. `category-manage` missing `operation` or operation-specific fields: clearly state which field is missing and stop.
|
|
187
|
+
5. Remote returns `code=4003` or message explicitly mentions `agent.api.create`: tell the owner to grant `agent.api.create` on the Agent permissions page.
|
|
188
|
+
6. Remote returns `code=4003` or message explicitly mentions `agent.category.list` / `agent.category.create` / `agent.category.update` / `agent.category.assign`: tell the owner to grant the corresponding scope on the Agent permissions page.
|
|
189
|
+
7. Missing remote agent parameters and current account cannot create: clearly require backend admin creation first.
|
|
190
|
+
8. Local config failure: return the failed command and result, then stop; emphasize which `get` / `set` / `validate` step failed.
|
|
191
|
+
9. This invocation handles real routing verification, and after one `openclaw gateway restart` retest still fails: clearly state "static config has been written, but runtime has not yet switched successfully"; converge as failed or partially complete, do not write it as success.
|
|
192
|
+
|
|
193
|
+
## Response Style
|
|
194
|
+
|
|
195
|
+
1. Clearly state whether the current execution is `bind-local`, `create-and-bind`, or `category-manage`.
|
|
196
|
+
2. Report in phases: remote creation / category handling (if any) / local config writing / validation results.
|
|
197
|
+
3. Clearly state whether local config has taken effect; if only static config succeeded but this invocation cannot perform real verification, can only write "config has been written, runtime not yet tested, needs subsequent flow to continue verification"; if only the category step succeeded, also state that clearly.
|
|
198
|
+
4. If remote creation succeeded but category or local binding subsequently failed, clearly state it is "partially complete"; do not generically write it as success.
|
|
199
|
+
|
|
200
|
+
## References
|
|
201
|
+
|
|
202
|
+
1. [references/api-contract.md](references/api-contract.md)
|