grix-connector 2.0.2 → 2.0.3
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/adapter/agy/agy-adapter.js +4 -4
- package/dist/adapter/claude/claude-adapter.js +18 -18
- package/dist/adapter/claude/claude-bridge-server.js +1 -1
- package/dist/adapter/claude/claude-tools.js +1 -1
- package/dist/adapter/claude/claude-worker-client.js +1 -1
- package/dist/adapter/claude/mcp-http-launcher.js +2 -2
- package/dist/adapter/claude/result-timeout.js +1 -1
- package/dist/adapter/claude/usage-parser.js +1 -1
- package/dist/bridge/bridge.js +9 -9
- package/dist/core/file-ops/list-files.js +1 -1
- package/dist/core/mcp/tools.js +1 -1
- package/dist/default-skills/grix-access-control/SKILL.md +31 -0
- package/dist/default-skills/grix-admin/SKILL.md +35 -0
- package/dist/default-skills/grix-agent-dispatch/SKILL.md +35 -0
- package/dist/default-skills/grix-group/SKILL.md +35 -0
- package/dist/default-skills/grix-owner-relay/SKILL.md +37 -0
- package/dist/default-skills/grix-query/SKILL.md +38 -0
- package/dist/default-skills/grix-task-status/SKILL.md +36 -0
- package/dist/default-skills/message-send/SKILL.md +36 -0
- package/dist/default-skills/message-unsend/SKILL.md +27 -0
- package/dist/log.js +2 -2
- package/dist/mcp/acp-mcp-server.js +3 -3
- package/dist/mcp/stream-http/config.js +1 -1
- package/dist/mcp/stream-http/connection-binding.js +1 -1
- package/dist/mcp/stream-http/security.js +1 -1
- package/dist/mcp/stream-http/tool-executor.js +1 -1
- package/dist/mcp/stream-http/tool-registry.js +1 -1
- package/dist/mcp/stream-http/tool-schemas.js +1 -1
- package/openclaw-plugin/index.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readdir as r,stat as m}from"node:fs/promises";import{join as l,extname as d}from"node:path";const x={pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",txt:"text/plain",md:"text/markdown",csv:"text/csv",json:"application/json",xml:"application/xml",yaml:"text/yaml",yml:"text/yaml",html:"text/html",css:"text/css",js:"text/javascript",ts:"text/typescript",zip:"application/zip",rar:"application/x-rar-compressed","7z":"application/x-7z-compressed",tar:"application/x-tar",gz:"application/gzip",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",mp4:"video/mp4",mov:"video/quicktime",avi:"video/x-msvideo",mkv:"video/x-matroska",webm:"video/webm",mp3:"audio/mpeg",wav:"audio/wav",flac:"audio/flac",aac:"audio/aac"};function n(a){const p=d(a).slice(1).toLowerCase();return x[p]}async function f(a,p=!1){const c=await r(a,{withFileTypes:!0}),s=[];for(const
|
|
1
|
+
import{readdir as r,stat as m}from"node:fs/promises";import{join as l,extname as d}from"node:path";const x={pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",txt:"text/plain",md:"text/markdown",csv:"text/csv",json:"application/json",xml:"application/xml",yaml:"text/yaml",yml:"text/yaml",html:"text/html",css:"text/css",js:"text/javascript",ts:"text/typescript",zip:"application/zip",rar:"application/x-rar-compressed","7z":"application/x-7z-compressed",tar:"application/x-tar",gz:"application/gzip",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",mp4:"video/mp4",mov:"video/quicktime",avi:"video/x-msvideo",mkv:"video/x-matroska",webm:"video/webm",mp3:"audio/mpeg",wav:"audio/wav",flac:"audio/flac",aac:"audio/aac"};function n(a){const p=d(a).slice(1).toLowerCase();return x[p]}async function f(a,p=!1){const c=await r(a,{withFileTypes:!0}),s=[];for(const t of c){if(!p&&t.name.startsWith("."))continue;const i=l(a,t.name),e={id:i,name:t.name,is_directory:t.isDirectory()};try{if(t.isDirectory()){const o=await m(i);e.modified_at=o.mtime.toISOString()}else{const o=await m(i);e.size=o.size,e.modified_at=o.mtime.toISOString(),e.mime_type=n(t.name)}}catch{}s.push(e)}return s.sort((t,i)=>t.is_directory!==i.is_directory?t.is_directory?-1:1:t.name.localeCompare(i.name)),s}export{f as listFiles,n as resolveMimeType};
|
package/dist/core/mcp/tools.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const a=[{name:"grix_query",description:"Search contacts, sessions, message history, or messages by keyword in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"],description:"Query action type."},id:{type:"string",description:"Contact ID (contact_search) or Session ID (session_search)."},keyword:{type:"string",description:"Search keyword."},limit:{type:"integer",description:"Max results."},offset:{type:"integer",description:"Result offset."},sessionId:{type:"string",description:"Session ID (message_history, message_search)."},beforeId:{type:"string",description:"Pagination cursor (message_history, message_search)."}},required:["action"]},validation:{required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},id:{type:"string"},keyword:{type:"string",maxLength:200},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}}},{name:"grix_group",description:"Manage groups in the Grix/AIBot platform: create, get details, leave, dissolve, manage members and permissions.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"],description:"Group action type."},sessionId:{type:"string",description:"Group session ID."},name:{type:"string",description:"Group name (create)."},memberIds:{type:"array",items:{type:"string"},description:"Member IDs to add/remove."},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]},description:"Member types (1=user, 2=agent)."},memberId:{type:"string",description:"Target member ID."},role:{type:"integer",enum:[1,2],description:"New role (1=admin, 2=member)."},memberType:{type:"integer",description:"Member type."},allMembersMuted:{type:"boolean",description:"Whether to mute all members."},isSpeakMuted:{type:"boolean",description:"Whether member is muted."},canSpeakWhenAllMuted:{type:"boolean",description:"Allow speaking when all muted."}},required:["action"]},validation:{required:["action"],properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string",maxLength:128},memberIds:{type:"array",items:{type:"string"},maxItems:100},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer"},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean"}}}},{name:"grix_message_send",description:"Send a message to a session in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string",description:"Target session ID"},content:{type:"string",description:"Message content"},msgType:{type:"integer",description:"Message type (1=text, default 1)"},quotedMessageId:{type:"string",description:"Message ID to reply to"},threadId:{type:"string",description:"Thread ID for threaded reply"}},required:["sessionId","content"]},validation:{required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}}},{name:"grix_message_unsend",description:"Recall/unsend a message in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string",description:"Session ID"},msgId:{type:"string",description:"Message ID to unsend"}},required:["sessionId","msgId"]},validation:{required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}}},{name:"grix_file_link",description:"Create a direct, tailnet-only download link for a local file on this host. Use this whenever the user asks you to send, share, give, or deliver a file that exists on the machine where you run (a report, log, build artifact, export, or any local path). It returns a ready-to-use Markdown link in the `markdown` field \u2014 include that exact Markdown link in your reply so the user can click and download the file directly over the shared Tailscale network. Each link is one-time and expires, so call this again to produce a fresh link every time you deliver a file. Requires this host to be on a tailnet (Tailscale running).",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to a local file on this host to share with the user."},ttl_ms:{type:"integer",description:"Optional link lifetime in milliseconds (default 10 minutes)."}},required:["file_path"]},validation:{required:["file_path"],properties:{file_path:{type:"string",maxLength:4096},ttl_ms:{type:"integer",minimum:1e4,maximum:864e5}}}},{name:"grix_admin",description:"Agent and category management in the Grix/AIBot platform: create agents, manage categories, rotate API keys.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"],description:"Admin action type."},agentName:{type:"string",description:"Agent name (create_agent)."},introduction:{type:"string",description:"Agent introduction (create_agent)."},isMain:{type:"boolean",description:"Set as main agent (create_agent)."},agentId:{type:"string",description:"Agent ID (assign_category, rotate_api_key)."},categoryId:{type:"string",description:"Category ID (create_agent, update_category, assign_category)."},name:{type:"string",description:"Category name (create_category, update_category)."},parentId:{type:"string",description:"Parent category ID (create_category, update_category)."},sortOrder:{type:"integer",description:"Sort order (create_category, update_category)."}},required:["action"]},validation:{required:["action"],properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},agentId:{type:"string"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"integer"}}}},{name:"grix_call_owner",description:"Call your owner into this session to talk by voice. Use this when, during your work, you need to reach your owner \u2014 to discuss something or to get an approval/review. It sends the owner an offline notification; when they tap it they land directly in this conversation and a voice-brain call is started automatically. Requires the owner to have configured a voice brain. Rate-limited per session.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"The session ID to call the owner into."}},required:["session_id"]},validation:{required:["session_id"],properties:{session_id:{type:"string"}}}},{name:"grix_agent_update",description:"Update the text introduction of one of your owner's agents, identified by its numeric agent ID.",inputSchema:{type:"object",properties:{agent_id:{type:"string",description:"Target agent's numeric ID, passed as a string."},introduction:{type:"string",description:"New text introduction (max 300 characters)."}},required:["agent_id","introduction"]},validation:{required:["agent_id","introduction"],properties:{agent_id:{type:"string"},introduction:{type:"string",maxLength:300}}}},{name:"grix_dispatch_agent",description:"Dispatch one of your owner's agents to do work in a given working directory. Provide the target agent numeric ID, the working directory, and a text description of the task. The backend opens (or reuses) a private session between the owner and that agent, binds the working directory when the agent type requires it (claude/codex/etc.), and sends the task into the session as the owner so the agent starts working.",inputSchema:{type:"object",properties:{agent_id:{type:"string",description:"Target agent's numeric ID, passed as a string."},cwd:{type:"string",description:"Absolute working directory where the agent should do the work."},task:{type:"string",description:"Text description of the task to perform."}},required:["agent_id","cwd","task"]},validation:{required:["agent_id","cwd","task"],properties:{agent_id:{type:"string"},cwd:{type:"string",maxLength:4096},task:{type:"string",maxLength:1e4}}}},{name:"grix_session_send",description:"Send a message into a session as the owner (not as yourself). Use this to speak on the owner's behalf in a session the owner is a member of. The owner must be a member of the target session.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"Target session ID."},content:{type:"string",description:"Message content to send as the owner."}},required:["session_id","content"]},validation:{required:["session_id","content"],properties:{session_id:{type:"string"},content:{type:"string",maxLength:1e4}}}},{name:"grix_task_query",description:"Query the session-level task states of all your owner's sessions. Takes no parameters \u2014 owner and agent are resolved from your authenticated connection. Returns one entry per session with a single mutually-exclusive state: running (working), waiting_approval (blocked on your owner to approve/deny), waiting_question (asked the owner a question, awaiting their reply), completed, failed, or idle (no task / stopped). Use this to see at a glance which tasks are done, still running, or waiting on the owner.",inputSchema:{type:"object",properties:{}},validation:{required:[],properties:{}}}],d=[{name:"grix_reply",description:"Send a reply message to the specified session. Supports streaming in chunks; the frontend will automatically aggregate them into one complete message.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"Associated event ID from the inbound event."},session_id:{type:"string",description:"Target session ID."},text:{type:"string",description:"Reply text content."},quoted_message_id:{type:"string",description:"Quoted message ID (optional)."},is_final:{type:"boolean",description:"Whether this is a stage-final reply. Advisory only \u2014 does not trigger event completion; completion is handled by the complete tool or Stop hook."}},required:["session_id","text"]},validation:{required:["session_id","text"],properties:{event_id:{type:"string"},session_id:{type:"string"},text:{type:"string",maxLength:5e4},quoted_message_id:{type:"string"},is_final:{type:"boolean"}}}},{name:"grix_complete",description:"Mark event processing as complete, notifying the backend that no more replies are expected.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The event ID to complete."},status:{type:"string",enum:["responded","canceled","failed"],description:"Completion status."},msg:{type:"string",description:"Additional note (optional)."}},required:["event_id","status"]},validation:{required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}}},{name:"grix_event_ack",description:"Acknowledge event receipt (usually done automatically by the Dispatcher; agents typically do not need to call this manually).",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The event ID to acknowledge."},session_id:{type:"string",description:"Session ID."}},required:["event_id"]},validation:{required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}}},{name:"grix_composing",description:'Set the "typing" indicator status for a session.',inputSchema:{type:"object",properties:{session_id:{type:"string",description:"Session ID."},active:{type:"boolean",description:"true = typing, false = stopped."},event_id:{type:"string",description:"Associated event ID (optional)."}},required:["session_id","active"]},validation:{required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}}},{name:"grix_access_control",description:"Manage sender access control: pair approval, allow/remove senders, set policy.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"],description:"Access control action type."},code:{type:"string",description:"Pairing code (required for pair_approve/pair_deny)."},sender_id:{type:"string",description:"Sender ID (required for allow_sender/remove_sender)."},policy:{type:"string",enum:["allowlist","open","disabled"],description:"Access policy (required for set_policy)."}},required:["action"]},validation:{required:["action"],properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"]},code:{type:"string"},sender_id:{type:"string"},policy:{type:"string",enum:["allowlist","open","disabled"]}}}},{name:"grix_status",description:"Query the Grix connection status of the current MCP session.",inputSchema:{type:"object",properties:{}},validation:{required:[],properties:{}}}],p=[{name:"reply",description:"Send a visible message back to the chat for this grix-claude event.",inputSchema:{type:"object",properties:{text:{type:"string",description:"The visible reply text to send."},chat_id:{type:"string",description:"The target chat/session id from the <channel> tag."},event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},reply_to:{type:"string",description:"Optional message_id to quote instead of the inbound trigger message."},final:{type:"boolean",description:"Advisory flag only. It does not complete the event; completion is handled by complete tool or Stop hook."}},required:["chat_id","event_id","text"]}},{name:"complete",description:"Finish an event without sending a visible reply so the backend does not time out.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string"},code:{type:"string"}},required:["event_id","status"]}}],c=new Set(p.map(e=>e.name)),b=new Set(a.map(e=>e.name)),v=new Set(d.map(e=>e.name)),I=/([A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+)/,k=/[A-Za-z0-9._-]+/;function C(e){return!!(b.has(e)||v.has(e)||c.has(e)||e.startsWith("mcp__grix"))}const w=[...a,...d],x=[...w,...p],P=new Map(x.map(e=>[e.name,e]));function z(e,t){return e==="reply"?{name:"grix_reply",args:u("grix_reply",{event_id:t.event_id,session_id:t.chat_id,text:t.text,quoted_message_id:t.reply_to,is_final:t.final})}:e==="complete"?{name:"grix_complete",args:u("grix_complete",{event_id:t.event_id,status:t.status,msg:t.msg,code:t.code})}:{name:e,args:t}}function l(e){const t=String(e??"").trim();return t?t.match(I)?.[1]:void 0}function m(e){const t=String(e??"").trim();if(!t)return;const n=l(t);if(n)return _(n);const i=t.match(/(?:chat_id|session_id)\s*=\s*"([A-Za-z0-9._-]+)"/)?.[1];if(i)return i;const r=t.match(/[A-Za-z0-9._-]+/g)??[];for(const s of r)if(!(s==="event_id"||s==="chat_id"||s==="session_id")&&s.length>0)return s;return t.match(k)?.[0]}function _(e){if(!e)return;const t=e.split(":",1)[0]?.trim();if(t)return m(t)}function u(e,t){if(e!=="grix_reply"&&e!=="grix_complete")return t;const n={...t},i=l(n.event_id);if(i&&(n.event_id=i),e==="grix_reply"){const r=_(i),o=String(n.session_id??""),s=m(n.session_id),f=/\bevent_id\b|["'<>\s]/.test(o);s&&!(f&&r)?n.session_id=s:r&&(n.session_id=r)}return n}function U(e){return c.has(e)}function G(e,t){switch(e){case"grix_query":return S(t);case"grix_group":return A(t);case"grix_message_send":return q(t);case"grix_message_unsend":return T(t);case"grix_file_link":return M(t);case"grix_admin":return N(t);case"grix_call_owner":return O(t);case"grix_agent_update":return D(t);case"grix_dispatch_agent":return E(t);case"grix_session_send":return L(t);case"grix_task_query":return j();default:throw new Error(`Unknown tool: ${e}`)}}const g={contact_search:"contact_search",session_search:"session_search",message_history:"message_history",message_search:"message_search"};function S(e){const t=String(e.action??""),n=g[t];if(!n)throw new Error(`Unknown grix_query action: ${t}`);const i={};return e.id!=null&&(i.id=e.id),e.keyword!=null&&(i.keyword=e.keyword),e.limit!=null&&(i.limit=e.limit),e.offset!=null&&(i.offset=e.offset),e.sessionId!=null&&(i.session_id=e.sessionId),e.beforeId!=null&&(i.before_id=e.beforeId),{action:n,params:i}}const y={create:"group_create",detail:"group_detail_read",leave:"group_leave_self",add_members:"group_member_add",remove_members:"group_member_remove",update_member_role:"group_member_role_update",update_all_members_muted:"group_all_members_muted_update",update_member_speaking:"group_member_speaking_update",dissolve:"group_dissolve"};function A(e){const t=String(e.action??""),n=y[t];if(!n)throw new Error(`Unknown grix_group action: ${t}`);const i={};return e.sessionId!=null&&(i.session_id=e.sessionId),e.name!=null&&(i.name=e.name),e.memberIds!=null&&(i.member_ids=e.memberIds),e.memberTypes!=null&&(i.member_types=e.memberTypes),e.memberId!=null&&(i.member_id=e.memberId),e.role!=null&&(i.role=e.role),e.memberType!=null&&(i.member_type=e.memberType),e.allMembersMuted!=null&&(i.all_members_muted=e.allMembersMuted),e.isSpeakMuted!=null&&(i.is_speak_muted=e.isSpeakMuted),e.canSpeakWhenAllMuted!=null&&(i.can_speak_when_all_muted=e.canSpeakWhenAllMuted),{action:n,params:i}}function q(e){const t={session_id:e.sessionId,msg_type:e.msgType??1,content:e.content};return e.quotedMessageId!=null&&(t.quoted_message_id=e.quotedMessageId),e.threadId!=null&&(t.thread_id=e.threadId),{action:"send_msg",params:t}}function T(e){return{action:"delete_msg",params:{session_id:e.sessionId,msg_id:e.msgId}}}function M(e){const t={file_path:e.file_path};return e.ttl_ms!=null&&(t.ttl_ms=e.ttl_ms),{action:"file_link",params:t}}const h={create_agent:"agent_api_create",list_categories:"agent_category_list",create_category:"agent_category_create",update_category:"agent_category_update",assign_category:"agent_category_assign",rotate_api_key:"agent_api_key_rotate"};function O(e){return{action:"call_owner",params:{session_id:e.session_id}}}function D(e){return{action:"agent_introduction_update",params:{agent_id:e.agent_id,introduction:e.introduction}}}function E(e){return{action:"dispatch_agent",params:{agent_id:e.agent_id,cwd:e.cwd,task:e.task}}}function L(e){return{action:"session_send",params:{session_id:e.session_id,content:e.content}}}function j(){return{action:"agent_task_query",params:{}}}function N(e){const t=String(e.action??""),n=h[t];if(!n)throw new Error(`Unknown grix_admin action: ${t}`);const i={};return e.agentName!=null&&(i.agent_name=e.agentName),e.introduction!=null&&(i.introduction=e.introduction),e.isMain!=null&&(i.is_main=e.isMain),e.agentId!=null&&(i.agent_id=e.agentId),e.categoryId!=null&&(i.category_id=e.categoryId),e.name!=null&&(i.name=e.name),e.parentId!=null&&(i.parent_id=e.parentId),e.sortOrder!=null&&(i.sort_order=e.sortOrder),{action:n,params:i}}const R=new Set([...Object.values(g),...Object.values(y),...Object.values(h),"send_msg","delete_msg","file_link","call_owner","agent_introduction_update","dispatch_agent","session_send","agent_task_query"]),W={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"};export{W as ACCESS_CONTROL_ACTION_MAP,w as ALL_TOOLS,d as EVENT_TOOLS,x as EXPOSED_TOOLS,R as PHASE1_INVOKE_ACTIONS,b as PHASE1_TOOL_NAMES,v as PHASE2_TOOL_NAMES,a as TOOLS,p as TOOL_ALIASES,P as TOOL_MAP,U as isAlias,C as isGrixInternalToolName,z as mapToolAlias,u as normalizeEventToolArgs,G as toolCallToInvoke};
|
|
1
|
+
const a=[{name:"grix_query",description:"Search contacts, sessions, message history, or messages by keyword in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"],description:"Query action type."},id:{type:"string",description:"Contact ID (contact_search) or Session ID (session_search)."},keyword:{type:"string",description:"Search keyword."},limit:{type:"integer",description:"Max results."},offset:{type:"integer",description:"Result offset."},sessionId:{type:"string",description:"Session ID (message_history, message_search)."},beforeId:{type:"string",description:"Pagination cursor (message_history, message_search)."}},required:["action"]},validation:{required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},id:{type:"string"},keyword:{type:"string",maxLength:200},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}}},{name:"grix_group",description:"Manage groups in the Grix/AIBot platform: create, get details, leave, dissolve, manage members and permissions.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"],description:"Group action type."},sessionId:{type:"string",description:"Group session ID."},name:{type:"string",description:"Group name (create)."},memberIds:{type:"array",items:{type:"string"},description:"Member IDs to add/remove."},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]},description:"Member types (1=user, 2=agent)."},memberId:{type:"string",description:"Target member ID."},role:{type:"integer",enum:[1,2],description:"New role (1=admin, 2=member)."},memberType:{type:"integer",description:"Member type."},allMembersMuted:{type:"boolean",description:"Whether to mute all members."},isSpeakMuted:{type:"boolean",description:"Whether member is muted."},canSpeakWhenAllMuted:{type:"boolean",description:"Allow speaking when all muted."}},required:["action"]},validation:{required:["action"],properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string",maxLength:128},memberIds:{type:"array",items:{type:"string"},maxItems:100},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer"},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean"}}}},{name:"grix_message_send",description:"Send a message to a session in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string",description:"Target session ID"},content:{type:"string",description:"Message content"},msgType:{type:"integer",description:"Message type (1=text, default 1)"},quotedMessageId:{type:"string",description:"Message ID to reply to"},threadId:{type:"string",description:"Thread ID for threaded reply"}},required:["sessionId","content"]},validation:{required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}}},{name:"grix_message_unsend",description:"Recall/unsend a message in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string",description:"Session ID"},msgId:{type:"string",description:"Message ID to unsend"}},required:["sessionId","msgId"]},validation:{required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}}},{name:"grix_file_link",description:"Create a direct, tailnet-only download link for a local file on this host. Use this whenever the user asks you to send, share, give, or deliver a file that exists on the machine where you run (a report, log, build artifact, export, or any local path). It returns a ready-to-use Markdown link in the `markdown` field \u2014 include that exact Markdown link in your reply so the user can click and download the file directly over the shared Tailscale network. Each link is one-time and expires, so call this again to produce a fresh link every time you deliver a file. Requires this host to be on a tailnet (Tailscale running).",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to a local file on this host to share with the user."},ttl_ms:{type:"integer",description:"Optional link lifetime in milliseconds (default 10 minutes)."}},required:["file_path"]},validation:{required:["file_path"],properties:{file_path:{type:"string",maxLength:4096},ttl_ms:{type:"integer",minimum:1e4,maximum:864e5}}}},{name:"grix_admin",description:"Agent and category management in the Grix/AIBot platform: create agents, manage categories, rotate API keys.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"],description:"Admin action type."},agentName:{type:"string",description:"Agent name (create_agent)."},introduction:{type:"string",description:"Agent introduction (create_agent)."},isMain:{type:"boolean",description:"Set as main agent (create_agent)."},agentId:{type:"string",description:"Agent ID (assign_category, rotate_api_key)."},categoryId:{type:"string",description:"Category ID (create_agent, update_category, assign_category)."},name:{type:"string",description:"Category name (create_category, update_category)."},parentId:{type:"string",description:"Parent category ID (create_category, update_category)."},sortOrder:{type:"integer",description:"Sort order (create_category, update_category)."}},required:["action"]},validation:{required:["action"],properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},agentId:{type:"string"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"integer"}}}},{name:"grix_call_owner",description:"Call your owner into this session to talk by voice. Use this when, during your work, you need to reach your owner \u2014 to discuss something or to get an approval/review. It sends the owner an offline notification; when they tap it they land directly in this conversation and a voice-brain call is started automatically. Requires the owner to have configured a voice brain. Rate-limited per session.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"The session ID to call the owner into."}},required:["session_id"]},validation:{required:["session_id"],properties:{session_id:{type:"string"}}}},{name:"grix_agent_update",description:"Update the text introduction of one of your owner's agents, identified by its numeric agent ID.",inputSchema:{type:"object",properties:{agent_id:{type:"string",description:"Target agent's numeric ID, passed as a string."},introduction:{type:"string",description:"New text introduction (max 300 characters)."}},required:["agent_id","introduction"]},validation:{required:["agent_id","introduction"],properties:{agent_id:{type:"string"},introduction:{type:"string",maxLength:300}}}},{name:"grix_dispatch_agent",description:"Dispatch one of your owner's agents to do work in a given working directory. Provide the target agent numeric ID, the working directory, and a text description of the task. The backend opens (or reuses) a private session between the owner and that agent, binds the working directory when the agent type requires it (claude/codex/etc.), and sends the task into the session as the owner so the agent starts working.",inputSchema:{type:"object",properties:{agent_id:{type:"string",description:"Target agent's numeric ID, passed as a string."},cwd:{type:"string",description:"Absolute working directory where the agent should do the work."},task:{type:"string",description:"Text description of the task to perform."}},required:["agent_id","cwd","task"]},validation:{required:["agent_id","cwd","task"],properties:{agent_id:{type:"string"},cwd:{type:"string",maxLength:4096},task:{type:"string",maxLength:1e4}}}},{name:"grix_session_send",description:"Send a message into a session as the owner (not as yourself). Use this to speak on the owner's behalf in a session the owner is a member of. The owner must be a member of the target session.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"Target session ID."},content:{type:"string",description:"Message content to send as the owner."}},required:["session_id","content"]},validation:{required:["session_id","content"],properties:{session_id:{type:"string"},content:{type:"string",maxLength:1e4}}}},{name:"grix_task_query",description:"Query the session-level task states of all your owner's sessions. Takes no parameters \u2014 owner and agent are resolved from your authenticated connection. Returns one entry per session with a single mutually-exclusive state: running (working), waiting_approval (blocked on your owner to approve/deny), waiting_question (asked the owner a question, awaiting their reply), completed, failed, or idle (no task / stopped). Use this to see at a glance which tasks are done, still running, or waiting on the owner.",inputSchema:{type:"object",properties:{}},validation:{required:[],properties:{}}}],d=[{name:"grix_reply",description:"Send a reply message to the specified session. Supports streaming in chunks; the frontend will automatically aggregate them into one complete message. Any content meant for the user \u2014 including your final conclusion at the end of a turn \u2014 MUST be sent through this tool; text written outside this tool is not delivered to the user.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"Associated event ID from the inbound event."},session_id:{type:"string",description:"Target session ID."},text:{type:"string",description:"Reply text content."},quoted_message_id:{type:"string",description:"Quoted message ID (optional)."},is_final:{type:"boolean",description:"Whether this is a stage-final reply. Advisory only \u2014 does not trigger event completion; completion is handled by the complete tool or Stop hook."}},required:["session_id","text"]},validation:{required:["session_id","text"],properties:{event_id:{type:"string"},session_id:{type:"string"},text:{type:"string",maxLength:5e4},quoted_message_id:{type:"string"},is_final:{type:"boolean"}}}},{name:"grix_complete",description:"Mark event processing as complete, notifying the backend that no more replies are expected.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The event ID to complete."},status:{type:"string",enum:["responded","canceled","failed"],description:"Completion status."},msg:{type:"string",description:"Additional note (optional)."}},required:["event_id","status"]},validation:{required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}}},{name:"grix_event_ack",description:"Acknowledge event receipt (usually done automatically by the Dispatcher; agents typically do not need to call this manually).",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The event ID to acknowledge."},session_id:{type:"string",description:"Session ID."}},required:["event_id"]},validation:{required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}}},{name:"grix_composing",description:'Set the "typing" indicator status for a session.',inputSchema:{type:"object",properties:{session_id:{type:"string",description:"Session ID."},active:{type:"boolean",description:"true = typing, false = stopped."},event_id:{type:"string",description:"Associated event ID (optional)."}},required:["session_id","active"]},validation:{required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}}},{name:"grix_access_control",description:"Manage sender access control: pair approval, allow/remove senders, set policy.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"],description:"Access control action type."},code:{type:"string",description:"Pairing code (required for pair_approve/pair_deny)."},sender_id:{type:"string",description:"Sender ID (required for allow_sender/remove_sender)."},policy:{type:"string",enum:["allowlist","open","disabled"],description:"Access policy (required for set_policy)."}},required:["action"]},validation:{required:["action"],properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"]},code:{type:"string"},sender_id:{type:"string"},policy:{type:"string",enum:["allowlist","open","disabled"]}}}},{name:"grix_status",description:"Query the Grix connection status of the current MCP session.",inputSchema:{type:"object",properties:{}},validation:{required:[],properties:{}}}],p=[{name:"reply",description:"Send a visible message back to the chat for this grix-claude event.",inputSchema:{type:"object",properties:{text:{type:"string",description:"The visible reply text to send."},chat_id:{type:"string",description:"The target chat/session id from the <channel> tag."},event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},reply_to:{type:"string",description:"Optional message_id to quote instead of the inbound trigger message."},final:{type:"boolean",description:"Advisory flag only. It does not complete the event; completion is handled by complete tool or Stop hook."}},required:["chat_id","event_id","text"]}},{name:"complete",description:"Finish an event without sending a visible reply so the backend does not time out.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string"},code:{type:"string"}},required:["event_id","status"]}}],c=new Set(p.map(e=>e.name)),b=new Set(a.map(e=>e.name)),v=new Set(d.map(e=>e.name)),I=/([A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+)/,k=/[A-Za-z0-9._-]+/;function C(e){return!!(b.has(e)||v.has(e)||c.has(e)||e.startsWith("mcp__grix"))}const w=[...a,...d],x=[...w,...p],P=new Map(x.map(e=>[e.name,e]));function U(e,t){return e==="reply"?{name:"grix_reply",args:_("grix_reply",{event_id:t.event_id,session_id:t.chat_id,text:t.text,quoted_message_id:t.reply_to,is_final:t.final})}:e==="complete"?{name:"grix_complete",args:_("grix_complete",{event_id:t.event_id,status:t.status,msg:t.msg,code:t.code})}:{name:e,args:t}}function l(e){const t=String(e??"").trim();return t?t.match(I)?.[1]:void 0}function m(e){const t=String(e??"").trim();if(!t)return;const n=l(t);if(n)return u(n);const i=t.match(/(?:chat_id|session_id)\s*=\s*"([A-Za-z0-9._-]+)"/)?.[1];if(i)return i;const r=t.match(/[A-Za-z0-9._-]+/g)??[];for(const s of r)if(!(s==="event_id"||s==="chat_id"||s==="session_id")&&s.length>0)return s;return t.match(k)?.[0]}function u(e){if(!e)return;const t=e.split(":",1)[0]?.trim();if(t)return m(t)}function _(e,t){if(e!=="grix_reply"&&e!=="grix_complete")return t;const n={...t},i=l(n.event_id);if(i&&(n.event_id=i),e==="grix_reply"){const r=u(i),o=String(n.session_id??""),s=m(n.session_id),f=/\bevent_id\b|["'<>\s]/.test(o);s&&!(f&&r)?n.session_id=s:r&&(n.session_id=r)}return n}function z(e){return c.has(e)}function G(e,t){switch(e){case"grix_query":return S(t);case"grix_group":return A(t);case"grix_message_send":return q(t);case"grix_message_unsend":return T(t);case"grix_file_link":return M(t);case"grix_admin":return N(t);case"grix_call_owner":return O(t);case"grix_agent_update":return D(t);case"grix_dispatch_agent":return E(t);case"grix_session_send":return L(t);case"grix_task_query":return j();default:throw new Error(`Unknown tool: ${e}`)}}const g={contact_search:"contact_search",session_search:"session_search",message_history:"message_history",message_search:"message_search"};function S(e){const t=String(e.action??""),n=g[t];if(!n)throw new Error(`Unknown grix_query action: ${t}`);const i={};return e.id!=null&&(i.id=e.id),e.keyword!=null&&(i.keyword=e.keyword),e.limit!=null&&(i.limit=e.limit),e.offset!=null&&(i.offset=e.offset),e.sessionId!=null&&(i.session_id=e.sessionId),e.beforeId!=null&&(i.before_id=e.beforeId),{action:n,params:i}}const y={create:"group_create",detail:"group_detail_read",leave:"group_leave_self",add_members:"group_member_add",remove_members:"group_member_remove",update_member_role:"group_member_role_update",update_all_members_muted:"group_all_members_muted_update",update_member_speaking:"group_member_speaking_update",dissolve:"group_dissolve"};function A(e){const t=String(e.action??""),n=y[t];if(!n)throw new Error(`Unknown grix_group action: ${t}`);const i={};return e.sessionId!=null&&(i.session_id=e.sessionId),e.name!=null&&(i.name=e.name),e.memberIds!=null&&(i.member_ids=e.memberIds),e.memberTypes!=null&&(i.member_types=e.memberTypes),e.memberId!=null&&(i.member_id=e.memberId),e.role!=null&&(i.role=e.role),e.memberType!=null&&(i.member_type=e.memberType),e.allMembersMuted!=null&&(i.all_members_muted=e.allMembersMuted),e.isSpeakMuted!=null&&(i.is_speak_muted=e.isSpeakMuted),e.canSpeakWhenAllMuted!=null&&(i.can_speak_when_all_muted=e.canSpeakWhenAllMuted),{action:n,params:i}}function q(e){const t={session_id:e.sessionId,msg_type:e.msgType??1,content:e.content};return e.quotedMessageId!=null&&(t.quoted_message_id=e.quotedMessageId),e.threadId!=null&&(t.thread_id=e.threadId),{action:"send_msg",params:t}}function T(e){return{action:"delete_msg",params:{session_id:e.sessionId,msg_id:e.msgId}}}function M(e){const t={file_path:e.file_path};return e.ttl_ms!=null&&(t.ttl_ms=e.ttl_ms),{action:"file_link",params:t}}const h={create_agent:"agent_api_create",list_categories:"agent_category_list",create_category:"agent_category_create",update_category:"agent_category_update",assign_category:"agent_category_assign",rotate_api_key:"agent_api_key_rotate"};function O(e){return{action:"call_owner",params:{session_id:e.session_id}}}function D(e){return{action:"agent_introduction_update",params:{agent_id:e.agent_id,introduction:e.introduction}}}function E(e){return{action:"dispatch_agent",params:{agent_id:e.agent_id,cwd:e.cwd,task:e.task}}}function L(e){return{action:"session_send",params:{session_id:e.session_id,content:e.content}}}function j(){return{action:"agent_task_query",params:{}}}function N(e){const t=String(e.action??""),n=h[t];if(!n)throw new Error(`Unknown grix_admin action: ${t}`);const i={};return e.agentName!=null&&(i.agent_name=e.agentName),e.introduction!=null&&(i.introduction=e.introduction),e.isMain!=null&&(i.is_main=e.isMain),e.agentId!=null&&(i.agent_id=e.agentId),e.categoryId!=null&&(i.category_id=e.categoryId),e.name!=null&&(i.name=e.name),e.parentId!=null&&(i.parent_id=e.parentId),e.sortOrder!=null&&(i.sort_order=e.sortOrder),{action:n,params:i}}const R=new Set([...Object.values(g),...Object.values(y),...Object.values(h),"send_msg","delete_msg","file_link","call_owner","agent_introduction_update","dispatch_agent","session_send","agent_task_query"]),W={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"};export{W as ACCESS_CONTROL_ACTION_MAP,w as ALL_TOOLS,d as EVENT_TOOLS,x as EXPOSED_TOOLS,R as PHASE1_INVOKE_ACTIONS,b as PHASE1_TOOL_NAMES,v as PHASE2_TOOL_NAMES,a as TOOLS,p as TOOL_ALIASES,P as TOOL_MAP,z as isAlias,C as isGrixInternalToolName,U as mapToolAlias,_ as normalizeEventToolArgs,G as toolCallToInvoke};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grix-access-control
|
|
3
|
+
description: Manage sender access control with the typed `grix_access_control` tool — approve/deny a pairing code, allow/remove a sender, or set the access policy. Trigger when the user asks to approve a pairing request, allowlist or block a sender, or change who is allowed to message the agent.
|
|
4
|
+
trigger: 当用户要批准/拒绝配对码、允许或移除某个发送者、或调整谁可以给 Agent 发消息的访问策略时
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Grix Access Control
|
|
8
|
+
|
|
9
|
+
Use the `grix_access_control` tool to manage who may message this agent.
|
|
10
|
+
|
|
11
|
+
## Tool contract
|
|
12
|
+
|
|
13
|
+
Call `grix_access_control` with one `action`:
|
|
14
|
+
|
|
15
|
+
- `pair_approve` / `pair_deny` — approve or deny a pairing request. Requires the
|
|
16
|
+
`code` from the pairing request.
|
|
17
|
+
- `allow_sender` — add a sender to the allowlist. Requires `sender_id`.
|
|
18
|
+
- `remove_sender` — remove a sender. Requires `sender_id`.
|
|
19
|
+
- `set_policy` — set the access policy. Requires `policy`, one of:
|
|
20
|
+
- `allowlist` — only allowlisted senders may message
|
|
21
|
+
- `open` — anyone may message
|
|
22
|
+
- `disabled` — access control off
|
|
23
|
+
|
|
24
|
+
## Rules
|
|
25
|
+
|
|
26
|
+
1. Pick exactly one `action` and supply only the field it needs (`code` for
|
|
27
|
+
pairing, `sender_id` for allow/remove, `policy` for set_policy).
|
|
28
|
+
2. These actions change who can reach the agent — confirm with the user before
|
|
29
|
+
approving an unknown pairing code or switching the policy to `open`.
|
|
30
|
+
3. On failure, report the exact reason (e.g. expired/invalid code) instead of
|
|
31
|
+
retrying with a guessed value.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grix-admin
|
|
3
|
+
description: Use the typed `grix_admin` tool to manage agents and categories on the Grix platform — create agents, list/create/update categories, assign an agent to a category, and rotate an agent's API key. Trigger when the user asks to create a new agent, organize agents into categories, or rotate an agent key.
|
|
4
|
+
trigger: 当用户要在 Grix 平台创建 Agent、管理分类、给 Agent 分配分类、或轮换 Agent 的 API key 时
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Grix Admin
|
|
8
|
+
|
|
9
|
+
Use the `grix_admin` tool for agent and category management on the Grix
|
|
10
|
+
platform. This skill covers only platform-side management — it does not touch
|
|
11
|
+
any local connector configuration or binding.
|
|
12
|
+
|
|
13
|
+
## Tool contract
|
|
14
|
+
|
|
15
|
+
Call `grix_admin` with one `action`:
|
|
16
|
+
|
|
17
|
+
- `create_agent` — create an agent. Requires `agentName`; optional
|
|
18
|
+
`introduction`, `isMain`, `categoryId`.
|
|
19
|
+
- `list_categories` — list all categories. No extra fields.
|
|
20
|
+
- `create_category` — requires `name`; optional `parentId`, `sortOrder`.
|
|
21
|
+
- `update_category` — requires `categoryId`; optional `name`, `parentId`,
|
|
22
|
+
`sortOrder`.
|
|
23
|
+
- `assign_category` — assign an agent to a category. Requires `agentId` and
|
|
24
|
+
`categoryId`.
|
|
25
|
+
- `rotate_api_key` — rotate an agent's API key. Requires `agentId`.
|
|
26
|
+
|
|
27
|
+
## Rules
|
|
28
|
+
|
|
29
|
+
1. Pick exactly one `action` per call and supply only the fields that action
|
|
30
|
+
needs.
|
|
31
|
+
2. For `assign_category` / `rotate_api_key` you need the target `agentId`; for
|
|
32
|
+
category edits you need the `categoryId`. Resolve unknown IDs first
|
|
33
|
+
(`list_categories`, or `grix_query` for agents) rather than guessing.
|
|
34
|
+
3. `rotate_api_key` invalidates the old key. Confirm the target agent with the
|
|
35
|
+
user before rotating, and report the new key handling per platform policy.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grix-agent-dispatch
|
|
3
|
+
description: Dispatch one of the owner's other agents to do work in a given directory (`grix_dispatch_agent`), and update an agent's text introduction (`grix_agent_update`). Trigger when the user asks to hand a task to another agent, run work in a specific directory via a sibling agent, or change an agent's introduction.
|
|
4
|
+
trigger: 当用户要把任务派发给 owner 名下的另一个 Agent、让某个 Agent 在指定目录干活、或修改某个 Agent 的简介时
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Grix Agent Dispatch
|
|
8
|
+
|
|
9
|
+
Manage and delegate to the owner's other agents.
|
|
10
|
+
|
|
11
|
+
## Dispatch a task — `grix_dispatch_agent`
|
|
12
|
+
|
|
13
|
+
Hand work to another of the owner's agents. The backend opens (or reuses) a
|
|
14
|
+
private session between the owner and that agent, binds the working directory
|
|
15
|
+
when the agent type requires it (claude/codex/etc.), and sends the task in as
|
|
16
|
+
the owner so the agent starts working.
|
|
17
|
+
|
|
18
|
+
- `agent_id` (required) — target agent's numeric ID, as a string.
|
|
19
|
+
- `cwd` (required) — absolute working directory for the task.
|
|
20
|
+
- `task` (required) — text description of what to do.
|
|
21
|
+
|
|
22
|
+
## Update an introduction — `grix_agent_update`
|
|
23
|
+
|
|
24
|
+
Change the text introduction of one of the owner's agents.
|
|
25
|
+
|
|
26
|
+
- `agent_id` (required) — target agent's numeric ID, as a string.
|
|
27
|
+
- `introduction` (required) — new introduction text (max 300 chars).
|
|
28
|
+
|
|
29
|
+
## Rules
|
|
30
|
+
|
|
31
|
+
1. You need the exact numeric `agent_id`. Resolve it with `grix_query` first if
|
|
32
|
+
you only have a name; never guess an ID.
|
|
33
|
+
2. `cwd` must be an absolute path the target agent can access.
|
|
34
|
+
3. Dispatch runs the task as the owner in a separate session — confirm the
|
|
35
|
+
target agent and directory with the user when the task is consequential.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grix-group
|
|
3
|
+
description: Use the typed `grix_group` tool for Grix group lifecycle and membership operations. Trigger when users ask to create, inspect, leave, update, or dissolve groups, or when these operations fail with scope or permission errors.
|
|
4
|
+
trigger: 当用户要创建、查看、退出、更新或解散群组,或群成员/禁言权限相关操作时
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Grix Group
|
|
8
|
+
|
|
9
|
+
Use the `grix_group` tool for Grix group lifecycle and membership management.
|
|
10
|
+
|
|
11
|
+
## Tool contract
|
|
12
|
+
|
|
13
|
+
Call `grix_group` with one `action`:
|
|
14
|
+
|
|
15
|
+
- `create` — create a group. Requires `name`; optionally seed members with
|
|
16
|
+
`memberIds` + matching `memberTypes` (1=user, 2=agent).
|
|
17
|
+
- `detail` — get group details. Requires `sessionId`.
|
|
18
|
+
- `leave` — leave the group. Requires `sessionId`.
|
|
19
|
+
- `dissolve` — dissolve the group (owner/admin only). Requires `sessionId`.
|
|
20
|
+
- `add_members` / `remove_members` — requires `sessionId`, `memberIds`, and
|
|
21
|
+
`memberTypes` aligned by index.
|
|
22
|
+
- `update_member_role` — requires `sessionId`, `memberId`, `role` (1=admin,
|
|
23
|
+
2=member).
|
|
24
|
+
- `update_all_members_muted` — requires `sessionId`, `allMembersMuted`.
|
|
25
|
+
- `update_member_speaking` — requires `sessionId`, `memberId`, `isSpeakMuted`,
|
|
26
|
+
and optionally `canSpeakWhenAllMuted`.
|
|
27
|
+
|
|
28
|
+
## Rules
|
|
29
|
+
|
|
30
|
+
1. `memberIds` and `memberTypes` are parallel arrays — keep them the same length
|
|
31
|
+
and order.
|
|
32
|
+
2. Any action except `create` needs the target group's `sessionId`; resolve it
|
|
33
|
+
with `grix_query` (`session_search`) first if unknown.
|
|
34
|
+
3. Scope or permission errors usually mean the current agent is not an admin of
|
|
35
|
+
that group — surface the exact error and required role, don't retry blindly.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grix-owner-relay
|
|
3
|
+
description: Act on the owner's behalf in a session — send a message as the owner (`grix_session_send`), or call the owner into the current session for a voice talk/approval (`grix_call_owner`). Trigger when the user asks to speak as the owner in a session, or when you need to reach the owner to discuss or get approval.
|
|
4
|
+
trigger: 当需要以 owner 身份在某会话发言、或把 owner 叫进当前会话语音沟通/审批时
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Grix Owner Relay
|
|
8
|
+
|
|
9
|
+
Interact with sessions on the owner's behalf, or pull the owner in.
|
|
10
|
+
|
|
11
|
+
## Speak as the owner — `grix_session_send`
|
|
12
|
+
|
|
13
|
+
Send a message into a session **as the owner** (not as yourself). The owner must
|
|
14
|
+
be a member of the target session.
|
|
15
|
+
|
|
16
|
+
- `session_id` (required) — target session ID.
|
|
17
|
+
- `content` (required) — message text to send as the owner (max 10000 chars).
|
|
18
|
+
|
|
19
|
+
To send as yourself (the agent) instead, use the `message-send` skill
|
|
20
|
+
(`grix_message_send`).
|
|
21
|
+
|
|
22
|
+
## Call the owner in — `grix_call_owner`
|
|
23
|
+
|
|
24
|
+
Bring the owner into a session for a voice conversation — use this when you need
|
|
25
|
+
to discuss something or get an approval/review during your work. It sends the
|
|
26
|
+
owner an offline notification; tapping it lands them in the conversation and
|
|
27
|
+
auto-starts a voice-brain call.
|
|
28
|
+
|
|
29
|
+
- `session_id` (required) — the session to call the owner into.
|
|
30
|
+
|
|
31
|
+
## Rules
|
|
32
|
+
|
|
33
|
+
1. `grix_session_send` only works when the owner is a member of that session;
|
|
34
|
+
otherwise it fails on scope — surface the error, don't retry blindly.
|
|
35
|
+
2. `grix_call_owner` requires the owner to have configured a voice brain and is
|
|
36
|
+
rate-limited per session. Use it only when you genuinely need the owner, not
|
|
37
|
+
as a routine notification.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grix-query
|
|
3
|
+
description: Use the typed `grix_query` tool for Grix contact lookup, keyword search, session search, and session message history lookup. Trigger when users ask to find contacts, search conversations, list visible sessions, or inspect recent messages in a known session.
|
|
4
|
+
trigger: 当用户要查找联系人、搜索会话、列出可见会话、或查看某个已知会话的历史消息时
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Grix Query
|
|
8
|
+
|
|
9
|
+
Use the `grix_query` tool for read-only Grix lookup. This skill only queries
|
|
10
|
+
existing contacts, sessions, and raw session messages — it never sends or
|
|
11
|
+
changes anything.
|
|
12
|
+
|
|
13
|
+
## Tool contract
|
|
14
|
+
|
|
15
|
+
Always call the `grix_query` tool with one `action`:
|
|
16
|
+
|
|
17
|
+
- `contact_search` — find contacts. Use exactly one mode: exact lookup with
|
|
18
|
+
`id`, keyword search with `keyword`, or list-all with neither.
|
|
19
|
+
- `session_search` — find sessions. Same three modes as `contact_search`.
|
|
20
|
+
- `message_history` — read recent messages in a session. Requires `sessionId`;
|
|
21
|
+
page backwards with `beforeId`.
|
|
22
|
+
- `message_search` — keyword search inside a session. Requires `sessionId` and
|
|
23
|
+
`keyword`.
|
|
24
|
+
|
|
25
|
+
Other parameters: `limit` (1–100), `offset`.
|
|
26
|
+
|
|
27
|
+
## Rules
|
|
28
|
+
|
|
29
|
+
1. Parse the request into exactly one action before calling.
|
|
30
|
+
2. If both `id` and `keyword` are given, the backend prioritizes `id`; do not
|
|
31
|
+
send both unless you explicitly want exact-match behavior.
|
|
32
|
+
3. For message history or in-session search when no `sessionId` is known, first
|
|
33
|
+
locate the session via `session_search`, or ask the user for a precise target.
|
|
34
|
+
4. When a result is paginated and `has_more` is true, keep paging only when the
|
|
35
|
+
user asked for everything, the target is still unresolved, or one page is
|
|
36
|
+
clearly insufficient.
|
|
37
|
+
5. On scope/auth/parameter errors, report the exact failure and the fix; do not
|
|
38
|
+
silently retry with guessed parameters.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grix-task-status
|
|
3
|
+
description: Observe state — query the task state of all the owner's sessions (`grix_task_query`), and check the current MCP connection status (`grix_status`). Trigger when the user asks which tasks are running/done/waiting, or to verify the Grix connection is healthy.
|
|
4
|
+
trigger: 当用户问哪些任务在跑/已完成/在等待审批,或要确认 Grix 连接是否正常时
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Grix Task & Status
|
|
8
|
+
|
|
9
|
+
Read-only observation of task and connection state.
|
|
10
|
+
|
|
11
|
+
## Owner task states — `grix_task_query`
|
|
12
|
+
|
|
13
|
+
Query the session-level task state across all the owner's sessions. Takes no
|
|
14
|
+
parameters — owner and agent are resolved from the authenticated connection.
|
|
15
|
+
Returns one entry per session with a single mutually-exclusive state:
|
|
16
|
+
|
|
17
|
+
- `running` — working
|
|
18
|
+
- `waiting_approval` — blocked on the owner to approve/deny
|
|
19
|
+
- `waiting_question` — asked the owner a question, awaiting reply
|
|
20
|
+
- `completed` / `failed` — finished
|
|
21
|
+
- `idle` — no task / stopped
|
|
22
|
+
|
|
23
|
+
Use it to see at a glance which tasks are done, still running, or waiting on the
|
|
24
|
+
owner.
|
|
25
|
+
|
|
26
|
+
## Connection status — `grix_status`
|
|
27
|
+
|
|
28
|
+
Query the Grix connection status of the current MCP session. Takes no
|
|
29
|
+
parameters. Use it to confirm the agent is connected before relying on other
|
|
30
|
+
grix tools.
|
|
31
|
+
|
|
32
|
+
## Rules
|
|
33
|
+
|
|
34
|
+
1. Both tools are read-only — safe to call any time to orient yourself.
|
|
35
|
+
2. `grix_task_query` reports per-session state, not per-message; pair it with
|
|
36
|
+
`grix_query` (`message_history`) when you need the actual content.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: message-send
|
|
3
|
+
description: Send a message into a specific Grix session by session ID, including cross-session and proactive sends. For replying to the current event use the reply/complete tools instead. Trigger words: send DM, DM, send message, notify, message another session.
|
|
4
|
+
trigger: 当用户要主动给某个指定会话发消息、跨会话发送、或通知另一个会话时
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Message Send
|
|
8
|
+
|
|
9
|
+
Use the `grix_message_send` tool to deliver a message into a specific Grix
|
|
10
|
+
session identified by its `sessionId`.
|
|
11
|
+
|
|
12
|
+
## When to use which tool
|
|
13
|
+
|
|
14
|
+
- **Replying to the current event** (the one you are handling right now): use
|
|
15
|
+
the `reply` / `grix_reply` tool and finish with `complete`. Do NOT use
|
|
16
|
+
`grix_message_send` for this — it is for other sessions.
|
|
17
|
+
- **Sending to another session, or proactively starting one**: use
|
|
18
|
+
`grix_message_send` with that session's `sessionId`.
|
|
19
|
+
|
|
20
|
+
## Tool contract
|
|
21
|
+
|
|
22
|
+
Call `grix_message_send`:
|
|
23
|
+
|
|
24
|
+
- `sessionId` (required) — the exact target session ID.
|
|
25
|
+
- `content` (required) — the message text (max 10000 chars).
|
|
26
|
+
- `msgType` (optional) — message type, default 1 (text).
|
|
27
|
+
- `quotedMessageId` (optional) — message ID to quote/reply to.
|
|
28
|
+
- `threadId` (optional) — thread ID for a threaded reply.
|
|
29
|
+
|
|
30
|
+
## Rules
|
|
31
|
+
|
|
32
|
+
1. You must have an exact `sessionId`. If you only have a name or keyword,
|
|
33
|
+
resolve it first with `grix_query` (`session_search` / `contact_search`).
|
|
34
|
+
2. Never guess a `sessionId`. If it cannot be resolved, ask the user.
|
|
35
|
+
3. Sending as yourself (the agent). To speak on the owner's behalf in a session
|
|
36
|
+
the owner belongs to, use the `grix-owner-relay` skill (`grix_session_send`).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: message-unsend
|
|
3
|
+
description: Silently recall/unsend an already-sent message in a Grix session. After execution, end immediately without replying any confirmation text. Trigger words: recall, unsend, delete message, withdraw message.
|
|
4
|
+
trigger: 当用户要撤回、收回、删除一条已经发出的消息时
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Message Unsend
|
|
8
|
+
|
|
9
|
+
Use the `grix_message_unsend` tool to recall a message that was already sent.
|
|
10
|
+
|
|
11
|
+
## Tool contract
|
|
12
|
+
|
|
13
|
+
Call `grix_message_unsend`:
|
|
14
|
+
|
|
15
|
+
- `sessionId` (required) — the session the message lives in.
|
|
16
|
+
- `msgId` (required) — the ID of the message to recall.
|
|
17
|
+
|
|
18
|
+
## Rules
|
|
19
|
+
|
|
20
|
+
1. You need both the `sessionId` and the exact `msgId`. If the `msgId` is
|
|
21
|
+
unknown, find it first with `grix_query` (`message_history` /
|
|
22
|
+
`message_search`).
|
|
23
|
+
2. This is a silent operation: after a successful recall, end immediately — do
|
|
24
|
+
not send any confirmation message back to the chat.
|
|
25
|
+
3. Only recall messages that were actually sent; recalling someone else's
|
|
26
|
+
message will fail on scope/permission — surface that error rather than
|
|
27
|
+
retrying.
|
package/dist/log.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{createWriteStream as g,mkdirSync as l,existsSync as f}from"node:fs";import{join as
|
|
2
|
-
`)},error(o,r,...
|
|
1
|
+
import{createWriteStream as g,mkdirSync as l,existsSync as f}from"node:fs";import{join as t}from"node:path";import{homedir as m}from"node:os";const i=t(m(),".grix"),s={base:i,config:t(i,"config"),log:t(i,"log"),data:t(i,"data")};function S(){for(const o of Object.values(s))f(o)||l(o,{recursive:!0})}let a=null;function $(){const o=new Date().toISOString().slice(0,10),r=t(s.log,`grix-acp-${o}.log`);a=g(r,{flags:"a"})}function c(){return new Date().toISOString().slice(11,19)}const u={info(o,r,...n){const e=`${c()} [${o}] ${r}${n.length?" "+n.map(String).join(" "):""}`;console.log(e),a?.write(e+`
|
|
2
|
+
`)},error(o,r,...n){const e=`${c()} [${o}] ERROR ${r}${n.length?" "+n.map(String).join(" "):""}`;console.error(e),a?.write(e+`
|
|
3
3
|
`)}};export{s as GRIX_PATHS,S as ensureGrixDirs,$ as initLogger,u as log};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
`),i.exit(1)}const v
|
|
4
|
-
`);
|
|
2
|
+
import N from"node:http";import i from"node:process";import{TOOLS as y,toolCallToInvoke as O}from"../core/mcp/tools.js";function v(){const n=i.argv.slice(2);for(let r=0;r<n.length;r++)if(n[r]==="--api-url"&&n[r+1])return n[r+1];const t=i.env.GRIX_CONNECTOR_INTERNAL_API;if(t)return t;i.stderr.write(`FATAL: --api-url <url> required (or set GRIX_CONNECTOR_INTERNAL_API)
|
|
3
|
+
`),i.exit(1)}const w=v();function u(n,t){return{jsonrpc:"2.0",id:n,result:t}}function f(n,t,r){return{jsonrpc:"2.0",id:n,error:{code:t,message:r}}}async function S(n,t){const r=new URL(w),o=new URL("/api/invoke",r);o.search=r.search;const d=JSON.stringify({action:n,params:t,timeout_ms:15e3});return new Promise((e,s)=>{const p=N.request(o,{method:"POST",headers:{"content-type":"application/json","content-length":Buffer.byteLength(d)}},c=>{const g=[];c.on("data",l=>g.push(l)),c.on("end",()=>{const l=Buffer.concat(g).toString("utf8");try{const m=JSON.parse(l);m.ok?e(m.data??null):s(new Error(m.error??"invoke failed"))}catch{s(new Error(`invalid response: ${l.slice(0,200)}`))}})});p.on("error",c=>s(c)),p.write(d),p.end()})}function E(n){return u(n.id??null,{protocolVersion:"2024-11-05",capabilities:{tools:{}},serverInfo:{name:"grix-connector-tools",version:"1.0.0"}})}function I(n){return u(n.id??null,{tools:y})}async function L(n){const t=n.params??{},r=String(t.name??""),o=t.arguments??{};if(!y.find(e=>e.name===r))return f(n.id??null,-32602,`Unknown tool: ${r}`);try{const e=O(r,o),s=await S(e.action,e.params);return u(n.id??null,{content:[{type:"text",text:JSON.stringify(s,null,2)}]})}catch(e){const s=e instanceof Error?e.message:String(e);return u(n.id??null,{content:[{type:"text",text:JSON.stringify({error:s})}],isError:!0})}}let h="";i.stdin.setEncoding("utf8"),i.stdin.on("data",n=>{h+=n;const t=h.split(`
|
|
4
|
+
`);h=t.pop()??"";for(const r of t){const o=r.trim();o&&R(o)}}),i.stdin.on("end",()=>{i.exit(0)});async function R(n){let t;try{t=JSON.parse(n)}catch{a(f(null,-32700,"Parse error"));return}try{switch(t.method){case"initialize":a(E(t));return;case"notifications/initialized":return;case"tools/list":a(I(t));return;case"tools/call":a(await L(t));return;default:a(f(t.id??null,-32601,`Method not found: ${t.method}`))}}catch(r){const o=r instanceof Error?r.message:String(r);a(f(t.id??null,-32603,`Internal error: ${o}`))}}function a(n){n&&i.stdout.write(`${JSON.stringify(n)}
|
|
5
5
|
`)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as
|
|
1
|
+
import*as i from"node:net";const e={bind:"127.0.0.1",port:0,endpoint:"/mcp",sessionTimeoutMs:18e5,invokeTimeoutMs:3e4};function n(o){const u={bind:o?.bind??e.bind,port:o?.port??e.port,endpoint:o?.endpoint??e.endpoint,sessionTimeoutMs:o?.sessionTimeoutMs??e.sessionTimeoutMs,invokeTimeoutMs:o?.invokeTimeoutMs??e.invokeTimeoutMs,allowedOrigins:o?.allowedOrigins,allowedHosts:o?.allowedHosts};return s(u.bind),u.port!==0&&t(u.port),r(u.sessionTimeoutMs),u}function s(o){if(!o||!i.isIPv4(o)&&!i.isIPv6(o))throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: bind \u5730\u5740 "${o}" \u4E0D\u662F\u5408\u6CD5\u7684 IPv4 \u6216 IPv6 \u5730\u5740`)}function t(o){if(!Number.isInteger(o)||o<1||o>65535)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: port \u503C ${o} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1-65535 \u5185\u6216\u4E0D\u662F\u6574\u6570`)}function r(o){if(!Number.isInteger(o)||o<1e3||o>864e5)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: session_timeout_ms \u503C ${o} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1000-86400000 \u5185`)}export{n as createDefaultGatewayConfig};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const r=3e4;class c{connectionManager;onDisconnected;bindings=new Map;constructor(n,i){this.connectionManager=n,this.onDisconnected=i}async bind(n,i){if(this.bindings.has(n))throw new Error(`Session ${n} is already bound to a connection`);const e=await this.connectWithTimeout(i),t=[],s=e.onDisconnected(()=>{this.removeBinding(n),this.onDisconnected(n)});return t.push(s),this.bindings.set(n,{sessionId:n,handle:e,subscriptions:t}),e}getHandle(n){return this.bindings.get(n)?.handle}unbind(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e();i.handle.disconnect()}}unbindAll(){const n=[...this.bindings.keys()];for(const i of n)this.unbind(i)}connectWithTimeout(n){return new Promise((i,e)=>{let t=!1;const s=setTimeout(()=>{t||(t=!0,e(new Error("Connection bind timeout after 30000ms")))},3e4);this.connectionManager.connect({agentId:n.agentId,apiKey:n.apiKey,url:n.wsUrl,clientType:n.clientType,capabilities:["agent_invoke"],adapterHint:`${n.clientType}/base`},{maxRetries:0}).then(o=>{t?o.disconnect():(t=!0,clearTimeout(s),i(o))}).catch(o=>{t||(t=!0,clearTimeout(s),e(o))})})}removeBinding(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e()}}}export{c as ConnectionBindingImpl};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function a(
|
|
1
|
+
function a(e){const t=new Set([`http://127.0.0.1:${e.serverPort}`,`http://localhost:${e.serverPort}`,...e.allowedOrigins]),o=new Set([`127.0.0.1:${e.serverPort}`,`localhost:${e.serverPort}`,...e.allowedHosts]);return{validateRequest(s){const r=i(s,t);if(!r.ok)return r;const n=l(s,o);return n.ok?{ok:!0}:n}}}function i(e,t){const o=e.headers.origin;return o?t.has(o)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${o}`}:{ok:!0}}function l(e,t){const o=e.headers.host;return o?t.has(o)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${o}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{toolCallToInvoke as i}from"../../core/mcp/tools.js";import{ToolRegistryImpl as l}from"./tool-registry.js";import{validateToolArgs as a}from"./tool-schemas.js";import{isEventTool as p,executeEventTool as d}from"./event-tool-executor.js";class y{registry;constructor(){this.registry=new l}async execute(
|
|
1
|
+
import{toolCallToInvoke as i}from"../../core/mcp/tools.js";import{ToolRegistryImpl as l}from"./tool-registry.js";import{validateToolArgs as a}from"./tool-schemas.js";import{isEventTool as p,executeEventTool as d}from"./event-tool-executor.js";class y{registry;constructor(){this.registry=new l}async execute(t,e,r,n){if(!this.registry.hasTool(e))return this.errorResult(`\u672A\u77E5\u5DE5\u5177: ${e}`);const s=a(e,r);if(!s.valid)return this.errorResult(`\u53C2\u6570\u6821\u9A8C\u5931\u8D25: ${s.error}`);if(t.status!=="ready")return this.errorResult(`\u8FDE\u63A5\u4E0D\u53EF\u7528: \u5F53\u524D\u72B6\u6001\u4E3A ${t.status}`);if(p(e))return this.executeEventTool(t,e,r);const o=i(e,r);try{const u=await t.agentInvoke(o.action,o.params,n);return this.normalizeResult(u)}catch(u){const c=u instanceof Error?u.message:String(u);return c.toLowerCase().includes("timeout")?this.errorResult(`\u8C03\u7528\u8D85\u65F6: ${c}`):this.errorResult(`\u8C03\u7528\u5931\u8D25: ${c}`)}}normalizeResult(t){if(t==null||typeof t!="object")return this.successResult(t??null);const e=t,r=typeof e.code=="number"?e.code:0;if(r===0){const s="data"in e?e.data:null;return this.successResult(s??null)}const n=typeof e.msg=="string"?e.msg:"\u672A\u77E5\u9519\u8BEF";return this.errorResult(`\u4E0A\u6E38\u9519\u8BEF [code=${r}]: ${n}`)}successResult(t){return{content:[{type:"text",text:JSON.stringify(t)}],isError:!1}}errorResult(t){return{content:[{type:"text",text:t}],isError:!0}}async executeEventTool(t,e,r){return e==="grix_access_control"?this.executeAccessControl(t,r):d(t,e,r)}async executeAccessControl(t,e){const r=String(e.action??""),n={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"}[r];if(!n)return this.errorResult(`\u672A\u77E5 access_control action: ${r}`);const s={};e.code!=null&&(s.code=e.code),e.sender_id!=null&&(s.sender_id=e.sender_id),e.policy!=null&&(s.policy=e.policy);try{const o=await t.agentInvoke("claude_access_control",{verb:n,payload:s},3e4);return this.successResult(o)}catch(o){const u=o instanceof Error?o.message:String(o);return this.errorResult(`access_control \u8C03\u7528\u5931\u8D25: ${u}`)}}}export{y as ToolExecutorImpl};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{TOOLS as
|
|
1
|
+
import{TOOLS as s,EVENT_TOOLS as t}from"../../core/mcp/tools.js";const e=new Set(["grix_query","grix_group","grix_message_send","grix_message_unsend","grix_admin"]),r=new Set(["grix_reply","grix_complete","grix_event_ack","grix_composing","grix_access_control","grix_status"]);class a{tools;toolMap;constructor(){this.tools=[...s.filter(o=>e.has(o.name)),...t.filter(o=>r.has(o.name))],this.toolMap=new Map(this.tools.map(o=>[o.name,o]))}getTools(){return this.tools}getTool(o){return this.toolMap.get(o)}hasTool(o){return this.toolMap.has(o)}}export{a as ToolRegistryImpl};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const o={required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},id:{type:"string"},keyword:{type:"string",maxLength:200},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}},a={required:["action"],properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string",maxLength:128},memberIds:{type:"array",items:{type:"string"},maxItems:100},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer"},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean"}}},p={required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}},m={required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}},g={required:["action"],properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},agentId:{type:"string"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"integer"}}},y={required:["session_id","text"],properties:{event_id:{type:"string"},session_id:{type:"string"},text:{type:"string",maxLength:5e4},quoted_message_id:{type:"string"},is_final:{type:"boolean"}}},d={required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}},c={required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}},l={required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}},_={required:["action"],properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"]},code:{type:"string"},sender_id:{type:"string"},policy:{type:"string",enum:["allowlist","open","disabled"]}}},f={required:[],properties:{}},C={grix_query:o,grix_group:a,grix_message_send:p,grix_message_unsend:m,grix_admin:g,grix_reply:y,grix_complete:d,grix_event_ack:c,grix_composing:l,grix_access_control:_,grix_status:f};function B(
|
|
1
|
+
const o={required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},id:{type:"string"},keyword:{type:"string",maxLength:200},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}},a={required:["action"],properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string",maxLength:128},memberIds:{type:"array",items:{type:"string"},maxItems:100},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer"},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean"}}},p={required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}},m={required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}},g={required:["action"],properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},agentId:{type:"string"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"integer"}}},y={required:["session_id","text"],properties:{event_id:{type:"string"},session_id:{type:"string"},text:{type:"string",maxLength:5e4},quoted_message_id:{type:"string"},is_final:{type:"boolean"}}},d={required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}},c={required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}},l={required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}},_={required:["action"],properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"]},code:{type:"string"},sender_id:{type:"string"},policy:{type:"string",enum:["allowlist","open","disabled"]}}},f={required:[],properties:{}},C={grix_query:o,grix_group:a,grix_message_send:p,grix_message_unsend:m,grix_admin:g,grix_reply:y,grix_complete:d,grix_event_ack:c,grix_composing:l,grix_access_control:_,grix_status:f};function B(u,t){const e=C[u];if(!e)return{valid:!1,error:`\u672A\u77E5\u5DE5\u5177: ${u}`};for(const i of e.required)if(t[i]===void 0||t[i]===null)return{valid:!1,error:`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${i}`};for(const[i,r]of Object.entries(t)){if(r==null)continue;const n=e.properties[i];if(!n)continue;const s=$(i,r,n);if(s)return{valid:!1,error:s}}return{valid:!0}}function $(u,t,e){switch(e.type){case"string":if(typeof t!="string")return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxLength!==void 0&&t.length>e.maxLength)return`\u53C2\u6570 ${u} \u8D85\u8FC7\u6700\u5927\u957F\u5EA6 ${e.maxLength}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${u} \u503C "${t}" \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"integer":if(typeof t!="number"||!Number.isInteger(t))return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof t=="number"?"\u6D6E\u70B9\u6570":typeof t}`;if(e.minimum!==void 0&&t<e.minimum)return`\u53C2\u6570 ${u} \u503C ${t} \u5C0F\u4E8E\u6700\u5C0F\u503C ${e.minimum}`;if(e.maximum!==void 0&&t>e.maximum)return`\u53C2\u6570 ${u} \u503C ${t} \u5927\u4E8E\u6700\u5927\u503C ${e.maximum}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${u} \u503C ${t} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"boolean":if(typeof t!="boolean")return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B boolean\uFF0C\u5B9E\u9645 ${typeof t}`;break;case"array":if(!Array.isArray(t))return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B array\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxItems!==void 0&&t.length>e.maxItems)return`\u53C2\u6570 ${u} \u8D85\u8FC7\u6700\u5927\u5143\u7D20\u6570 ${e.maxItems}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.items)for(let i=0;i<t.length;i++){const r=t[i];if(e.items.type==="string"&&typeof r!="string")return`\u53C2\u6570 ${u}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof r}`;if(e.items.type==="integer"){if(typeof r!="number"||!Number.isInteger(r))return`\u53C2\u6570 ${u}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof r}`;if(e.items.enum&&!e.items.enum.includes(r))return`\u53C2\u6570 ${u}[${i}] \u503C ${r} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.items.enum.join(", ")}]`}}break}}export{B as validateToolArgs};
|
package/openclaw-plugin/index.js
CHANGED
|
@@ -9114,7 +9114,7 @@ var TOOLS = [
|
|
|
9114
9114
|
var EVENT_TOOLS = [
|
|
9115
9115
|
{
|
|
9116
9116
|
name: "grix_reply",
|
|
9117
|
-
description: "Send a reply message to the specified session. Supports streaming in chunks; the frontend will automatically aggregate them into one complete message.",
|
|
9117
|
+
description: "Send a reply message to the specified session. Supports streaming in chunks; the frontend will automatically aggregate them into one complete message. Any content meant for the user \u2014 including your final conclusion at the end of a turn \u2014 MUST be sent through this tool; text written outside this tool is not delivered to the user.",
|
|
9118
9118
|
inputSchema: {
|
|
9119
9119
|
type: "object",
|
|
9120
9120
|
properties: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grix-connector",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "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.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|