grix-connector 1.0.2
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 +149 -0
- package/dist/adapter/acp/acp-adapter.js +13 -0
- package/dist/adapter/acp/index.js +1 -0
- package/dist/adapter/acp/usage-parser.js +1 -0
- package/dist/adapter/claude/activity-status-manager.js +1 -0
- package/dist/adapter/claude/channel-notification.js +1 -0
- package/dist/adapter/claude/claude-adapter.js +15 -0
- package/dist/adapter/claude/claude-bridge-server.js +1 -0
- package/dist/adapter/claude/claude-tools.js +1 -0
- package/dist/adapter/claude/claude-worker-client.js +1 -0
- package/dist/adapter/claude/index.js +1 -0
- package/dist/adapter/claude/interaction-protocol.js +1 -0
- package/dist/adapter/claude/mcp-http-launcher.js +2 -0
- package/dist/adapter/claude/model-list.js +1 -0
- package/dist/adapter/claude/protocol-contract.js +1 -0
- package/dist/adapter/claude/result-timeout.js +1 -0
- package/dist/adapter/claude/skill-scanner.js +2 -0
- package/dist/adapter/claude/usage-parser.js +3 -0
- package/dist/adapter/codewhale/codewhale-adapter.js +6 -0
- package/dist/adapter/codewhale/index.js +1 -0
- package/dist/adapter/codex/codex-bridge.js +10 -0
- package/dist/adapter/codex/codex-trust.js +8 -0
- package/dist/adapter/codex/index.js +1 -0
- package/dist/adapter/codex/usage-parser.js +1 -0
- package/dist/adapter/cursor/cursor-adapter.js +8 -0
- package/dist/adapter/cursor/index.js +1 -0
- package/dist/adapter/deepseek/deepseek-adapter.js +6 -0
- package/dist/adapter/deepseek/index.js +1 -0
- package/dist/adapter/index.js +1 -0
- package/dist/adapter/opencode/index.js +1 -0
- package/dist/adapter/opencode/opencode-adapter.js +8 -0
- package/dist/adapter/opencode/opencode-transport.js +5 -0
- package/dist/adapter/opencode/opencode-types.js +0 -0
- package/dist/adapter/openhuman/index.js +1 -0
- package/dist/adapter/openhuman/openhuman-adapter.js +7 -0
- package/dist/adapter/openhuman/openhuman-transport.js +1 -0
- package/dist/adapter/openhuman/openhuman-types.js +0 -0
- package/dist/adapter/pi/index.js +1 -0
- package/dist/adapter/pi/pi-adapter.js +10 -0
- package/dist/adapter/pi/pi-transport.js +4 -0
- package/dist/adapter/pi/pi-types.js +0 -0
- package/dist/adapter/pi/usage-parser.js +1 -0
- package/dist/adapter/qwen/index.js +1 -0
- package/dist/adapter/qwen/qwen-adapter.js +4 -0
- package/dist/adapter/types.js +1 -0
- package/dist/agent/index.js +1 -0
- package/dist/agent/process.js +2 -0
- package/dist/aibot/client.js +1 -0
- package/dist/aibot/index.js +1 -0
- package/dist/aibot/types.js +0 -0
- package/dist/bridge/adapter-pool.js +1 -0
- package/dist/bridge/bridge.js +10 -0
- package/dist/bridge/deferred-events.js +1 -0
- package/dist/bridge/event-queue.js +1 -0
- package/dist/bridge/index.js +1 -0
- package/dist/bridge/respawn-manager.js +1 -0
- package/dist/bridge/revoke-handler.js +1 -0
- package/dist/bridge/runtime-config.js +1 -0
- package/dist/bridge/send-controller.js +1 -0
- package/dist/bridge/session-controller.js +9 -0
- package/dist/bridge/tool-card-utils.js +1 -0
- package/dist/core/access/allowlist-gate.js +1 -0
- package/dist/core/access/allowlist-store.js +1 -0
- package/dist/core/access/index.js +1 -0
- package/dist/core/aibot/client.js +1 -0
- package/dist/core/aibot/connection-handle.js +1 -0
- package/dist/core/aibot/connection-manager.js +1 -0
- package/dist/core/aibot/event-lifecycle-types.js +0 -0
- package/dist/core/aibot/index.js +1 -0
- package/dist/core/aibot/types.js +0 -0
- package/dist/core/config/index.js +1 -0
- package/dist/core/config/paths.js +1 -0
- package/dist/core/context/channel-context-resolution.js +1 -0
- package/dist/core/context/channel-context-store.js +1 -0
- package/dist/core/context/index.js +1 -0
- package/dist/core/context/transcript-channel-context.js +1 -0
- package/dist/core/file-ops/handler.js +1 -0
- package/dist/core/file-ops/list-files.js +1 -0
- package/dist/core/file-ops/types.js +0 -0
- package/dist/core/files/create-folder.js +1 -0
- package/dist/core/files/index.js +1 -0
- package/dist/core/files/list-files.js +1 -0
- package/dist/core/files/list-handler.js +1 -0
- package/dist/core/files/types.js +0 -0
- package/dist/core/files/utils.js +1 -0
- package/dist/core/hooks/hook-signal-store.js +2 -0
- package/dist/core/hooks/index.js +1 -0
- package/dist/core/log/bridge-event-log.js +2 -0
- package/dist/core/log/conversation-log.js +3 -0
- package/dist/core/log/index.js +1 -0
- package/dist/core/log/logger.js +6 -0
- package/dist/core/log/packet-log.js +2 -0
- package/dist/core/log/rotation.js +2 -0
- package/dist/core/mcp/event-tool-executor.js +1 -0
- package/dist/core/mcp/index.js +1 -0
- package/dist/core/mcp/internal-api-server.js +1 -0
- package/dist/core/mcp/tool-schemas.js +1 -0
- package/dist/core/mcp/tools.js +1 -0
- package/dist/core/persistence/active-event-store.js +1 -0
- package/dist/core/persistence/agent-global-config-store.js +1 -0
- package/dist/core/persistence/elicitation-store.js +1 -0
- package/dist/core/persistence/event-results-store.js +1 -0
- package/dist/core/persistence/permission-store.js +1 -0
- package/dist/core/persistence/question-store.js +1 -0
- package/dist/core/persistence/session-binding-store.js +1 -0
- package/dist/core/protocol/agent-api-media.js +1 -0
- package/dist/core/protocol/attachment-file.js +1 -0
- package/dist/core/protocol/index.js +1 -0
- package/dist/core/protocol/interaction-parser.js +1 -0
- package/dist/core/protocol/message-metadata.js +2 -0
- package/dist/core/protocol/message-reference.js +2 -0
- package/dist/core/protocol/payload-parser.js +11 -0
- package/dist/core/protocol/protocol-descriptor.js +1 -0
- package/dist/core/protocol/protocol-text.js +1 -0
- package/dist/core/provider-quota/index.js +1 -0
- package/dist/core/provider-quota/kiro.js +1 -0
- package/dist/core/provider-quota/providers.js +1 -0
- package/dist/core/provider-quota/types.js +0 -0
- package/dist/core/runtime/health.js +1 -0
- package/dist/core/runtime/index.js +1 -0
- package/dist/core/runtime/pidfile.js +2 -0
- package/dist/core/runtime/spawn.js +1 -0
- package/dist/core/text-segmentation/index.js +1 -0
- package/dist/core/text-segmentation/safe-markdown-stream-segmenter.js +6 -0
- package/dist/core/transport/index.js +1 -0
- package/dist/core/transport/json-rpc.js +3 -0
- package/dist/core/upgrade/npm-upgrader.js +2 -0
- package/dist/core/upgrade/upgrade-checker.js +1 -0
- package/dist/core/util/client-version.js +1 -0
- package/dist/core/util/codex-output-policy.js +1 -0
- package/dist/core/util/event-buffer.js +1 -0
- package/dist/core/util/index.js +1 -0
- package/dist/core/util/json-file.js +2 -0
- package/dist/core/util/normalize-string.js +1 -0
- package/dist/core/util/quoted-message-stream.js +3 -0
- package/dist/grix.js +28 -0
- package/dist/index.js +1 -0
- package/dist/log.js +3 -0
- package/dist/main.js +31 -0
- package/dist/manager.js +1 -0
- package/dist/mcp/acp-mcp-server.js +5 -0
- package/dist/mcp/stdio/server.js +10 -0
- package/dist/mcp/stream-http/config.js +1 -0
- package/dist/mcp/stream-http/connection-binding.js +1 -0
- package/dist/mcp/stream-http/event-tool-executor.js +1 -0
- package/dist/mcp/stream-http/gateway.js +1 -0
- package/dist/mcp/stream-http/index.js +1 -0
- package/dist/mcp/stream-http/security.js +1 -0
- package/dist/mcp/stream-http/session-manager.js +1 -0
- package/dist/mcp/stream-http/tool-executor.js +1 -0
- package/dist/mcp/stream-http/tool-registry.js +1 -0
- package/dist/mcp/stream-http/tool-schemas.js +1 -0
- package/dist/protocol/acp-client.js +1 -0
- package/dist/protocol/event-mapper.js +5 -0
- package/dist/protocol/index.js +1 -0
- package/dist/runtime/daemon-lock.js +2 -0
- package/dist/runtime/service-state.js +2 -0
- package/dist/scripts/approve-plan-hook.js +2 -0
- package/dist/scripts/elicitation-hook.js +6 -0
- package/dist/scripts/lib/read-stdin.js +1 -0
- package/dist/scripts/lifecycle-hook.js +2 -0
- package/dist/scripts/notification-hook.js +4 -0
- package/dist/scripts/permission-hook.js +5 -0
- package/dist/scripts/status-line-forwarder.js +2 -0
- package/dist/scripts/user-prompt-submit-hook.js +2 -0
- package/dist/service/platform-adapter.js +45 -0
- package/dist/service/process-control.js +1 -0
- package/dist/service/service-install-store.js +1 -0
- package/dist/service/service-manager.js +1 -0
- package/dist/service/service-paths.js +1 -0
- package/dist/session/index.js +1 -0
- package/dist/session/manager.js +1 -0
- package/dist/transport/index.js +1 -0
- package/dist/transport/json-rpc.js +3 -0
- package/dist/types/events.js +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/protocol.js +0 -0
- package/dist/types/session-state.js +0 -0
- package/dist/types/usage.js +0 -0
- package/openclaw-plugin/index.js +11271 -0
- package/openclaw-plugin/skills/grix-admin/SKILL.md +202 -0
- package/openclaw-plugin/skills/grix-admin/references/api-contract.md +210 -0
- package/openclaw-plugin/skills/grix-egg/SKILL.md +81 -0
- package/openclaw-plugin/skills/grix-egg/references/api-contract.md +40 -0
- package/openclaw-plugin/skills/grix-group/SKILL.md +164 -0
- package/openclaw-plugin/skills/grix-group/references/api-contract.md +97 -0
- package/openclaw-plugin/skills/grix-query/SKILL.md +247 -0
- package/openclaw-plugin/skills/grix-register/SKILL.md +86 -0
- package/openclaw-plugin/skills/grix-register/references/api-contract.md +76 -0
- package/openclaw-plugin/skills/grix-register/references/grix-concepts.md +26 -0
- package/openclaw-plugin/skills/grix-register/references/handoff-contract.md +24 -0
- package/openclaw-plugin/skills/grix-register/references/openclaw-setup.md +6 -0
- package/openclaw-plugin/skills/grix-register/references/user-replies.md +25 -0
- package/openclaw-plugin/skills/grix-register/scripts/grix_auth.ts +599 -0
- package/openclaw-plugin/skills/grix-update/SKILL.md +310 -0
- package/openclaw-plugin/skills/grix-update/references/cron-setup.md +56 -0
- package/openclaw-plugin/skills/grix-update/references/update-contract.md +149 -0
- package/openclaw-plugin/skills/message-send/SKILL.md +197 -0
- package/openclaw-plugin/skills/message-unsend/SKILL.md +186 -0
- package/openclaw-plugin/skills/message-unsend/flowchart.mermaid +27 -0
- package/openclaw-plugin/skills/openclaw-memory-setup/SKILL.md +282 -0
- package/openclaw-plugin/skills/openclaw-memory-setup/references/case-study-macpro.md +52 -0
- package/openclaw-plugin/skills/openclaw-memory-setup/references/host-readiness.md +147 -0
- package/openclaw-plugin/skills/openclaw-memory-setup/scripts/bench_ollama_embeddings.ts +326 -0
- package/openclaw-plugin/skills/openclaw-memory-setup/scripts/set_openclaw_memory_model.ts +385 -0
- package/openclaw-plugin/skills/openclaw-memory-setup/scripts/survey_host_readiness.ts +294 -0
- package/openclaw.plugin.json +24 -0
- package/package.json +114 -0
- package/scripts/install-guardian.mjs +30 -0
- package/scripts/install-guardian.sh +30 -0
- package/scripts/upgrade-guardian.sh +98 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{TOOLS as A,EVENT_TOOLS as T,TOOL_ALIASES as S,ALL_TOOLS as e,EXPOSED_TOOLS as E,TOOL_MAP as _,PHASE1_TOOL_NAMES as r,PHASE2_TOOL_NAMES as L,PHASE1_INVOKE_ACTIONS as l,ACCESS_CONTROL_ACTION_MAP as t,toolCallToInvoke as a,mapToolAlias as N,isAlias as i}from"./tools.js";import{validateToolArgs as C}from"./tool-schemas.js";import{executeEventTool as P,isEventTool as m}from"./event-tool-executor.js";import{InternalApiServer as s}from"./internal-api-server.js";export{t as ACCESS_CONTROL_ACTION_MAP,e as ALL_TOOLS,T as EVENT_TOOLS,E as EXPOSED_TOOLS,s as InternalApiServer,l as PHASE1_INVOKE_ACTIONS,r as PHASE1_TOOL_NAMES,L as PHASE2_TOOL_NAMES,A as TOOLS,S as TOOL_ALIASES,_ as TOOL_MAP,P as executeEventTool,i as isAlias,m as isEventTool,N as mapToolAlias,a as toolCallToInvoke,C as validateToolArgs};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import y from"node:http";import{randomBytes as S}from"node:crypto";import{log as c}from"../log/index.js";import{PHASE1_INVOKE_ACTIONS as v}from"./tools.js";const f=1024*1024,g=50,w=1e3,p=6e4,O=new Set([...v,"event_tool_call"]);class T{server=null;port=0;authToken;invokeHandler=null;statusLineHandler=null;activeInvokes=0;constructor(){this.authToken=S(32).toString("hex")}setInvokeHandler(e){this.invokeHandler=e}setStatusLineHandler(e){this.statusLineHandler=e}async start(e=0){return new Promise((t,i)=>{this.server=y.createServer((n,o)=>this.handleRequest(n,o)),this.server.on("error",i),this.server.listen(e,"127.0.0.1",()=>{const n=this.server.address();typeof n=="object"&&n&&(this.port=n.port),this.server.removeListener("error",i),t(this.port)})})}get url(){return`http://127.0.0.1:${this.port}?token=${this.authToken}`}get baseUrl(){return`http://127.0.0.1:${this.port}`}get token(){return this.authToken}async stop(){if(this.server)return new Promise(e=>{this.server.close(()=>{this.server=null,e()})})}checkAuth(e){return e.headers.authorization===`Bearer ${this.authToken}`||new URL(e.url??"/",`http://127.0.0.1:${this.port}`).searchParams.get("token")===this.authToken}handleRequest(e,t){if(e.method!=="POST"){t.writeHead(405),t.end(JSON.stringify({error:"method not allowed"}));return}if(!this.checkAuth(e)){t.writeHead(401),t.end(JSON.stringify({ok:!1,error:"unauthorized"}));return}const i=new URL(e.url??"/",`http://127.0.0.1:${this.port}`);if(i.pathname==="/api/status-line"){this.handleStatusLine(e,t);return}if(!i.pathname.startsWith("/api/invoke")){t.writeHead(404),t.end(JSON.stringify({error:"not found"}));return}const n=[];let o=0;e.on("data",r=>{if(o+=r.length,o>f){t.writeHead(413),t.end(JSON.stringify({ok:!1,error:"request body too large"})),e.destroy();return}n.push(r)}),e.on("end",async()=>{let r;try{r=JSON.parse(Buffer.concat(n).toString("utf8"))}catch{t.writeHead(400),t.end(JSON.stringify({ok:!1,error:"invalid JSON"}));return}const a=r.action,l=r.params??{};if(!a||!this.invokeHandler){t.writeHead(400),t.end(JSON.stringify({ok:!1,error:"missing action or no handler"}));return}if(!O.has(a)){t.writeHead(400),t.end(JSON.stringify({ok:!1,error:`action '${a}' is not allowed`}));return}if(this.activeInvokes>=g){t.writeHead(429),t.end(JSON.stringify({ok:!1,error:"too many concurrent invokes"}));return}const k=r.timeout_ms!=null?Math.max(w,Math.min(r.timeout_ms,p)):p,h=Date.now();this.activeInvokes++;const u=new AbortController;try{const s=await Promise.race([this.invokeHandler(a,l,u.signal),new Promise((d,m)=>setTimeout(()=>{u.abort(),m(new Error("invoke timeout"))},k))]);t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!0,data:s})),c.info("internal-api",`invoke ok action=${a} tool=${l.tool_name??"-"} ms=${Date.now()-h}`)}catch(s){u.abort();const d=s instanceof Error?s.message:String(s);t.writeHead(500),t.end(JSON.stringify({ok:!1,error:d})),c.error("internal-api",`invoke error action=${a} tool=${l.tool_name??"-"} ms=${Date.now()-h} err=${d}`)}finally{this.activeInvokes--}})}handleStatusLine(e,t){const i=[];let n=0;e.on("data",o=>{if(n+=o.length,n>f){t.writeHead(413),t.end(JSON.stringify({ok:!1,error:"request body too large"})),e.destroy();return}i.push(o)}),e.on("end",async()=>{let o;try{o=JSON.parse(Buffer.concat(i).toString("utf8"))}catch{t.writeHead(400),t.end(JSON.stringify({ok:!1,error:"invalid JSON"}));return}if(!this.statusLineHandler){t.writeHead(200),t.end(JSON.stringify({ok:!0}));return}try{await this.statusLineHandler(o),t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!0}))}catch(r){console.error("[internal-api] statusLine handler error:",r instanceof Error?r.message:r),t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!0}))}})}}export{T as InternalApiServer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ALL_TOOLS as m}from"./tools.js";const s=new Map(m.filter(i=>i.validation).map(i=>[i.name,i.validation]));function p(i,n){const t=s.get(i);if(!t)return{valid:!1,error:`\u672A\u77E5\u5DE5\u5177: ${i}`};for(const e of t.required)if(n[e]===void 0||n[e]===null)return{valid:!1,error:`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${e}`};for(const[e,r]of Object.entries(n)){if(r==null)continue;const f=t.properties[e];if(!f)continue;const o=$(e,r,f);if(o)return{valid:!1,error:o}}return{valid:!0}}function $(i,n,t){switch(t.type){case"string":if(typeof n!="string")return`\u53C2\u6570 ${i} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof n}`;if(t.maxLength!==void 0&&n.length>t.maxLength)return`\u53C2\u6570 ${i} \u8D85\u8FC7\u6700\u5927\u957F\u5EA6 ${t.maxLength}\uFF0C\u5B9E\u9645 ${n.length}`;if(t.enum&&!t.enum.includes(n))return`\u53C2\u6570 ${i} \u503C "${n}" \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${t.enum.join(", ")}]`;break;case"integer":if(typeof n!="number"||!Number.isInteger(n))return`\u53C2\u6570 ${i} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof n=="number"?"\u6D6E\u70B9\u6570":typeof n}`;if(t.minimum!==void 0&&n<t.minimum)return`\u53C2\u6570 ${i} \u503C ${n} \u5C0F\u4E8E\u6700\u5C0F\u503C ${t.minimum}`;if(t.maximum!==void 0&&n>t.maximum)return`\u53C2\u6570 ${i} \u503C ${n} \u5927\u4E8E\u6700\u5927\u503C ${t.maximum}`;if(t.enum&&!t.enum.includes(n))return`\u53C2\u6570 ${i} \u503C ${n} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${t.enum.join(", ")}]`;break;case"boolean":if(typeof n!="boolean")return`\u53C2\u6570 ${i} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B boolean\uFF0C\u5B9E\u9645 ${typeof n}`;break;case"array":if(!Array.isArray(n))return`\u53C2\u6570 ${i} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B array\uFF0C\u5B9E\u9645 ${typeof n}`;if(t.maxItems!==void 0&&n.length>t.maxItems)return`\u53C2\u6570 ${i} \u8D85\u8FC7\u6700\u5927\u5143\u7D20\u6570 ${t.maxItems}\uFF0C\u5B9E\u9645 ${n.length}`;if(t.items)for(let e=0;e<n.length;e++){const r=n[e];if(t.items.type==="string"&&typeof r!="string")return`\u53C2\u6570 ${i}[${e}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof r}`;if(t.items.type==="integer"){if(typeof r!="number"||!Number.isInteger(r))return`\u53C2\u6570 ${i}[${e}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof r}`;if(t.items.enum&&!t.items.enum.includes(r))return`\u53C2\u6570 ${i}[${e}] \u503C ${r} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${t.items.enum.join(", ")}]`}}break}}export{p as validateToolArgs};
|
|
@@ -0,0 +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_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"}}}}],d=[{name:"grix_reply",description:"\u5411\u6307\u5B9A\u4F1A\u8BDD\u53D1\u9001\u56DE\u590D\u6D88\u606F\u3002\u652F\u6301\u6D41\u5F0F\u5206\u7247\u53D1\u9001\uFF0C\u524D\u7AEF\u4F1A\u81EA\u52A8\u805A\u5408\u4E3A\u4E00\u6761\u5B8C\u6574\u6D88\u606F\u3002",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"\u5173\u8054\u7684\u4E8B\u4EF6 ID\uFF0C\u6765\u81EA\u5165\u7AD9\u4E8B\u4EF6\u7684 event_id\u3002"},session_id:{type:"string",description:"\u76EE\u6807\u4F1A\u8BDD ID\u3002"},text:{type:"string",description:"\u56DE\u590D\u6587\u672C\u5185\u5BB9\u3002"},quoted_message_id:{type:"string",description:"\u5F15\u7528\u7684\u6D88\u606F ID\uFF08\u53EF\u9009\uFF09\u3002"},is_final:{type:"boolean",description:"\u662F\u5426\u4E3A\u9636\u6BB5\u6027\u56DE\u590D\u3002\u8BE5\u53C2\u6570\u4EC5\u7528\u4E8E\u63D0\u793A\u8BED\u4E49\uFF0C\u4E0D\u4F1A\u89E6\u53D1\u4E8B\u4EF6\u5B8C\u6210\uFF1B\u4E8B\u4EF6\u5B8C\u6210\u7531 complete \u5DE5\u5177\u6216 Stop hook \u7EDF\u4E00\u5904\u7406\u3002"}},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:"\u6807\u8BB0\u4E8B\u4EF6\u5904\u7406\u5B8C\u6210\uFF0C\u901A\u77E5\u540E\u7AEF\u4E0D\u518D\u7B49\u5F85\u56DE\u590D\u3002",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"\u8981\u5B8C\u6210\u7684\u4E8B\u4EF6 ID\u3002"},status:{type:"string",enum:["responded","canceled","failed"],description:"\u5B8C\u6210\u72B6\u6001\u3002"},msg:{type:"string",description:"\u9644\u52A0\u8BF4\u660E\uFF08\u53EF\u9009\uFF09\u3002"}},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:"\u786E\u8BA4\u6536\u5230\u4E8B\u4EF6\uFF08\u901A\u5E38\u7531 Dispatcher \u81EA\u52A8\u5B8C\u6210\uFF0CAgent \u4E00\u822C\u4E0D\u9700\u8981\u624B\u52A8\u8C03\u7528\uFF09\u3002",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"\u8981\u786E\u8BA4\u7684\u4E8B\u4EF6 ID\u3002"},session_id:{type:"string",description:"\u4F1A\u8BDD ID\u3002"}},required:["event_id"]},validation:{required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}}},{name:"grix_composing",description:'\u8BBE\u7F6E\u4F1A\u8BDD\u7684"\u6B63\u5728\u8F93\u5165"\u72B6\u6001\u6307\u793A\u3002',inputSchema:{type:"object",properties:{session_id:{type:"string",description:"\u4F1A\u8BDD ID\u3002"},active:{type:"boolean",description:"true \u8868\u793A\u6B63\u5728\u8F93\u5165\uFF0Cfalse \u8868\u793A\u505C\u6B62\u3002"},event_id:{type:"string",description:"\u5173\u8054\u7684\u4E8B\u4EF6 ID\uFF08\u53EF\u9009\uFF09\u3002"}},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:"\u7BA1\u7406\u53D1\u9001\u8005\u8BBF\u95EE\u63A7\u5236\uFF1A\u914D\u5BF9\u5BA1\u6279\u3001\u5141\u8BB8/\u79FB\u9664\u53D1\u9001\u8005\u3001\u8BBE\u7F6E\u7B56\u7565\u3002",inputSchema:{type:"object",properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"],description:"\u8BBF\u95EE\u63A7\u5236\u64CD\u4F5C\u7C7B\u578B\u3002"},code:{type:"string",description:"\u914D\u5BF9\u7801\uFF08pair_approve/pair_deny \u65F6\u5FC5\u586B\uFF09\u3002"},sender_id:{type:"string",description:"\u53D1\u9001\u8005 ID\uFF08allow_sender/remove_sender \u65F6\u5FC5\u586B\uFF09\u3002"},policy:{type:"string",enum:["allowlist","open","disabled"],description:"\u8BBF\u95EE\u7B56\u7565\uFF08set_policy \u65F6\u5FC5\u586B\uFF09\u3002"}},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:"\u67E5\u8BE2\u5F53\u524D MCP session \u7684 Grix \u8FDE\u63A5\u72B6\u6001\u3002",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)),f=new Set(a.map(e=>e.name)),b=new Set(d.map(e=>e.name)),v=/([A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+)/,x=/[A-Za-z0-9._-]+/;function O(e){return!!(f.has(e)||b.has(e)||c.has(e)||e.startsWith("mcp__grix"))}const S=[...a,...d],A=[...S,...p],D=new Map(A.map(e=>[e.name,e]));function E(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 m(e){const t=String(e??"").trim();return t?t.match(v)?.[1]:void 0}function _(e){const t=String(e??"").trim();if(!t)return;const n=m(t);if(n)return l(n);const i=t.match(/(?:chat_id|session_id)\s*=\s*"([A-Za-z0-9._-]+)"/)?.[1];if(i)return i;const s=t.match(/[A-Za-z0-9._-]+/g)??[];for(const r of s)if(!(r==="event_id"||r==="chat_id"||r==="session_id")&&r.length>0)return r;return t.match(x)?.[0]}function l(e){if(!e)return;const t=e.split(":",1)[0]?.trim();if(t)return _(t)}function u(e,t){if(e!=="grix_reply"&&e!=="grix_complete")return t;const n={...t},i=m(n.event_id);if(i&&(n.event_id=i),e==="grix_reply"){const s=l(i),o=String(n.session_id??""),r=_(n.session_id),I=/\bevent_id\b|["'<>\s]/.test(o);r&&!(I&&s)?n.session_id=r:s&&(n.session_id=s)}return n}function L(e){return c.has(e)}function N(e,t){switch(e){case"grix_query":return k(t);case"grix_group":return M(t);case"grix_message_send":return w(t);case"grix_message_unsend":return T(t);case"grix_admin":return q(t);default:throw new Error(`Unknown tool: ${e}`)}}const y={contact_search:"contact_search",session_search:"session_search",message_history:"message_history",message_search:"message_search"};function k(e){const t=String(e.action??""),n=y[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 g={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 M(e){const t=String(e.action??""),n=g[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 w(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}}}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 q(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 j=new Set([...Object.values(y),...Object.values(g),...Object.values(h),"send_msg","delete_msg"]),P={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"};export{P as ACCESS_CONTROL_ACTION_MAP,S as ALL_TOOLS,d as EVENT_TOOLS,A as EXPOSED_TOOLS,j as PHASE1_INVOKE_ACTIONS,f as PHASE1_TOOL_NAMES,b as PHASE2_TOOL_NAMES,a as TOOLS,p as TOOL_ALIASES,D as TOOL_MAP,L as isAlias,O as isGrixInternalToolName,E as mapToolAlias,u as normalizeEventToolArgs,N as toolCallToInvoke};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readJSONFile as r,writeJSONFileAtomic as a}from"../util/json-file.js";import{log as o}from"../log/index.js";import{unlink as n}from"node:fs/promises";class v{filePath;constructor(t){this.filePath=t}async save(t){if(t.length===0){await this.remove();return}const i=t.map(e=>({eventId:e,savedAt:Date.now()}));await a(this.filePath,i),o.info("active-event-store",`Saved ${i.length} active event(s)`)}async drain(){const t=r(this.filePath);if(await this.remove(),!Array.isArray(t))return[];const i=[];for(const e of t)e&&typeof e=="object"&&typeof e.eventId=="string"&&i.push(e.eventId);return i}async remove(){try{await n(this.filePath)}catch{}}}export{v as ActiveEventStore};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readJSONFile as s,writeJSONFileAtomic as o}from"../util/json-file.js";import{log as r}from"../log/index.js";class n{configs=new Map;filePath;writePromise=Promise.resolve();constructor(t){this.filePath=t??null}load(){if(!this.filePath)return;const t=s(this.filePath);if(!(!t||typeof t!="object"||Array.isArray(t))){this.configs.clear();for(const[i,e]of Object.entries(t))e&&typeof e=="object"&&this.configs.set(i,e)}}get(t){return this.configs.get(t)}set(t,i){const e=this.configs.get(t);this.configs.set(t,{...e,...i,updatedAt:Date.now()}),this.scheduleWrite()}delete(t){this.configs.delete(t),this.scheduleWrite()}async flush(){await this.writePromise}scheduleWrite(){this.filePath&&(this.writePromise=this.writePromise.then(()=>this.write()).catch(t=>{r.error("agent-global-config-store",`Persist failed: ${t instanceof Error?t.message:t}`)}))}async write(){if(!this.filePath)return;const t={};for(const[i,e]of this.configs)t[i]=e;await o(this.filePath,t)}}export{n as AgentGlobalConfigStore};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{mkdir as u,readdir as c}from"node:fs/promises";import{join as a}from"node:path";import{readJSONFile as r,writeJSONFileAtomic as o}from"../util/json-file.js";class _{requestsDir;constructor(t){this.requestsDir=t}async init(){await u(this.requestsDir,{recursive:!0})}resolvePath(t){return a(this.requestsDir,`${t}.json`)}async createRequest(t){const e={request_id:t.request_id,status:"pending",created_at:Date.now(),fields:t.fields,channel_context:t.channel_context};return await o(this.resolvePath(t.request_id),e),e}async getRequest(t){const e=r(this.resolvePath(t));return!e||typeof e!="object"?null:this.normalizeRequest(e)}async saveRequest(t){await o(this.resolvePath(t.request_id),t)}async listPendingDispatches(){const t=await c(this.requestsDir).catch(()=>[]),e=[];for(const s of t){if(!s.endsWith(".json"))continue;const i=r(a(this.requestsDir,s));if(!i||typeof i!="object")continue;const n=this.normalizeRequest(i);n&&n.status==="pending"&&n.channel_context?.chat_id&&e.push(n)}return e.sort((s,i)=>s.created_at-i.created_at)}async markDispatched(t){const e=await this.getRequest(t);e&&(e.status="dispatched",e.dispatched_at=Date.now(),await this.saveRequest(e))}async markDispatchFailed(t,e){const s=await this.getRequest(t);s&&(s.status="pending",await this.saveRequest(s))}async resolveRequest(t,e){const s=await this.getRequest(t);s&&(s.status="resolved",s.response_action=e.action,s.response_content=e.content,await this.saveRequest(s))}async markExpired(t){const e=await this.getRequest(t);!e||e.status!=="pending"||(e.status="expired",await this.saveRequest(e))}async getStatus(){const t=await c(this.requestsDir).catch(()=>[]);let e=0;for(const s of t){if(!s.endsWith(".json"))continue;const i=r(a(this.requestsDir,s));if(!i||typeof i!="object")continue;i.status==="pending"&&e++}return{pending_count:e}}normalizeRequest(t){return t.request_id?{request_id:String(t.request_id),status:["pending","dispatched","resolved","expired"].includes(t.status)?t.status:"pending",created_at:t.created_at??0,dispatched_at:t.dispatched_at,fields:t.fields??{},channel_context:t.channel_context??{chat_id:"",message_id:""},response_action:t.response_action,response_content:t.response_content}:null}}export{_ as ElicitationStore};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readJSONFile as n,writeJSONFileAtomic as h}from"../util/json-file.js";import{log as d}from"../log/index.js";const r=5e3,f=1440*60*1e3;class p{data=new Map;filePath;persistQueue=Promise.resolve();constructor(t){this.filePath=t??null,this.load()}get(t,s){return this.data.get(this.key(t,s))}set(t){this.data.set(this.key(t.sessionId,t.eventId),t),this.prune(),this.schedulePersist()}has(t,s){return this.data.has(this.key(t,s))}key(t,s){return`${t}:${s}`}load(){if(!this.filePath)return;const t=n(this.filePath);if(Array.isArray(t)){for(const s of t)if(s&&typeof s=="object"){const e=s;e.sessionId&&e.eventId&&this.data.set(this.key(e.sessionId,e.eventId),e)}}}prune(){const t=Date.now(),s=Array.from(this.data.values()).sort((e,a)=>a.updatedAt-e.updatedAt);for(const e of s)t-e.updatedAt>f&&this.data.delete(this.key(e.sessionId,e.eventId));if(this.data.size>r){const e=Array.from(this.data.values()).sort((i,o)=>i.updatedAt-o.updatedAt),a=this.data.size-r;for(let i=0;i<a;i++)this.data.delete(this.key(e[i].sessionId,e[i].eventId))}}schedulePersist(){this.filePath&&(this.persistQueue=this.persistQueue.catch(()=>{}).then(()=>this.persist()).catch(t=>{d.error("event-results-store",`Persist failed: ${t instanceof Error?t.message:t}`)}))}async persist(){if(!this.filePath)return;const t=Array.from(this.data.values());await h(this.filePath,t)}}export{p as EventResultsStore};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readdir as c,readFile as a,writeFile as o,mkdir as d,unlink as u}from"node:fs/promises";import{join as n}from"node:path";class w{dir;constructor(t){this.dir=t}async ensureDir(){await d(this.dir,{recursive:!0})}async writeRequest(t){await this.ensureDir();const i=n(this.dir,`${t.request_id}.json`);await o(i,JSON.stringify(t,null,2))}async listPending(){await this.ensureDir();try{const t=await c(this.dir),i=[];for(const e of t)if(e.endsWith(".json"))try{const r=await a(n(this.dir,e),"utf8"),s=JSON.parse(r);s.resolved||i.push(s)}catch{}return i.sort((e,r)=>e.created_at-r.created_at)}catch{return[]}}async resolveRequest(t,i){await this.ensureDir();const e=n(this.dir,`${t}.json`);try{const r=await a(e,"utf8"),s=JSON.parse(r);s.resolved=!0,s.resolution=i,await o(e,JSON.stringify(s,null,2))}catch{await o(e,JSON.stringify({request_id:t,resolved:!0,resolution:i,created_at:Date.now()}))}}async cleanResolved(){await this.ensureDir();try{const t=await c(this.dir);for(const i of t)if(i.endsWith(".json"))try{const e=await a(n(this.dir,i),"utf8");JSON.parse(e).resolved&&await u(n(this.dir,i))}catch{}}catch{}}}export{w as PermissionStore};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readdir as u,readFile as c,writeFile as o,unlink as f,mkdir as h}from"node:fs/promises";import{join as n}from"node:path";class p{dir;constructor(t){this.dir=t}async ensureDir(){await h(this.dir,{recursive:!0})}async listPending(){await this.ensureDir();try{const t=await u(this.dir),i=[];for(const e of t)if(e.endsWith(".json"))try{const s=await c(n(this.dir,e),"utf8"),r=JSON.parse(s);r.resolved||i.push(r)}catch{}return i.sort((e,s)=>e.created_at-s.created_at)}catch{return[]}}async getRequest(t){await this.ensureDir();const i=n(this.dir,`${t}.json`);try{const e=await c(i,"utf8");return JSON.parse(e)}catch{return null}}async updateRequest(t,i){await this.ensureDir();const e=n(this.dir,`${t}.json`),s=await this.getRequest(t);if(!s)return;const r={...s,...i};await o(e,JSON.stringify(r,null,2))}async resolveRequest(t,i,e,s){await this.ensureDir();const r=n(this.dir,`${t}.json`);try{const d=await c(r,"utf8"),a=JSON.parse(d);a.resolved=!0,a.resolution=i,e!==void 0&&(a.answer=e),s!==void 0&&(a.resolution_payload=s),await o(r,JSON.stringify(a,null,2))}catch{await o(r,JSON.stringify({request_id:t,resolved:!0,resolution:i,...e!==void 0?{answer:e}:{},...s!==void 0?{resolution_payload:s}:{},created_at:Date.now()}))}}async writeRequest(t){await this.ensureDir();const i=n(this.dir,`${t.request_id}.json`);await o(i,JSON.stringify(t,null,2))}async cleanResolved(){await this.ensureDir();try{const t=await u(this.dir);for(const i of t)if(i.endsWith(".json"))try{const e=await c(n(this.dir,i),"utf8");JSON.parse(e).resolved&&await f(n(this.dir,i))}catch{}}catch{}}}export{p as QuestionStore};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readJSONFile as c,writeJSONFileAtomic as l}from"../util/json-file.js";import{log as h}from"../log/index.js";import{SESSION_MODE_IDS as n}from"../../adapter/claude/protocol-contract.js";const a=n.fullAuto;function s(r){const e=String(r??"").trim().toLowerCase();return e===n.approval||e===n.fullAuto?e:a}class x{bindings=new Map;filePath;writePromise=Promise.resolve();constructor(e){this.filePath=e??null}load(){if(!this.filePath)return;const e=c(this.filePath);if(Array.isArray(e)){this.bindings.clear();for(const d of e)d.aibotSessionId&&this.bindings.set(d.aibotSessionId,{...d,modeId:s(d.modeId)})}}set(e,d,t){const o=this.bindings.get(e),i=s(t?.modeId??o?.modeId);this.bindings.set(e,{aibotSessionId:e,cwd:d,acpSessionId:o?.acpSessionId,claudeSessionId:o?.claudeSessionId,codexThreadId:o?.codexThreadId,codexModelId:o?.codexModelId,codexModeId:o?.codexModeId,codewhaleThreadId:o?.codewhaleThreadId,codexReasoningEffort:o?.codexReasoningEffort,codexSandboxMode:o?.codexSandboxMode,piSessionPath:o?.piSessionPath,modeId:i,modelId:o?.modelId,updatedAt:Date.now()}),this.scheduleWrite()}setAcpSessionId(e,d){this.updateBinding(e,{acpSessionId:d})}setClaudeSessionId(e,d){this.updateBinding(e,{claudeSessionId:d})}getClaudeSessionId(e){return this.bindings.get(e)?.claudeSessionId}setCodexThreadId(e,d){this.updateBinding(e,{codexThreadId:d})}getCodexThreadId(e){return this.bindings.get(e)?.codexThreadId}setCodexContext(e,d){this.updateBinding(e,{codexModelId:d.modelId,codexModeId:d.modeId,codexReasoningEffort:d.reasoningEffort,codexSandboxMode:d.sandboxMode})}getCodexModelId(e){return this.bindings.get(e)?.codexModelId}getCodexModeId(e){return this.bindings.get(e)?.codexModeId}getCodexReasoningEffort(e){return this.bindings.get(e)?.codexReasoningEffort}getCodexSandboxMode(e){return this.bindings.get(e)?.codexSandboxMode}setPiSessionPath(e,d){this.updateBinding(e,{piSessionPath:d})}getPiSessionPath(e){return this.bindings.get(e)?.piSessionPath}setCodeWhaleThreadId(e,d){this.updateBinding(e,{codewhaleThreadId:d})}getCodeWhaleThreadId(e){return this.bindings.get(e)?.codewhaleThreadId}setModeId(e,d){const t=this.bindings.get(e);if(!t)return;const o=s(d);t.modeId!==o&&(this.bindings.set(e,{...t,modeId:o,updatedAt:Date.now()}),this.scheduleWrite())}ensureModeId(e,d=a){const t=this.bindings.get(e);t&&(t.modeId||(this.bindings.set(e,{...t,modeId:s(d),updatedAt:Date.now()}),this.scheduleWrite()))}getAcpSessionId(e){return this.bindings.get(e)?.acpSessionId}getModeId(e){const d=this.bindings.get(e)?.modeId;return d?s(d):void 0}setModelId(e,d){const t=this.bindings.get(e);if(!t)return;const o=d.trim();t.modelId!==o&&(this.bindings.set(e,{...t,modelId:o,updatedAt:Date.now()}),this.scheduleWrite())}getModelId(e){return this.bindings.get(e)?.modelId}get(e){return this.bindings.get(e)}getMostRecentlyUpdatedSessionId(e){const d=e?.requireCwd!==!1;let t,o=-1;for(const i of this.bindings.values())d&&!String(i.cwd??"").trim()||i.updatedAt>o&&(o=i.updatedAt,t=i.aibotSessionId);return t}delete(e){this.bindings.delete(e),this.scheduleWrite()}async flush(){await this.writePromise}scheduleWrite(){this.filePath&&(this.writePromise=this.writePromise.then(()=>this.write()).catch(e=>{h.error("session-binding-store",`Persist failed: ${e instanceof Error?e.message:e}`)}))}async write(){if(!this.filePath)return;const e=Array.from(this.bindings.values());await l(this.filePath,e)}updateBinding(e,d){const t=this.bindings.get(e),o={aibotSessionId:e,acpSessionId:Object.prototype.hasOwnProperty.call(d,"acpSessionId")?d.acpSessionId:t?.acpSessionId,claudeSessionId:Object.prototype.hasOwnProperty.call(d,"claudeSessionId")?d.claudeSessionId:t?.claudeSessionId,codexThreadId:Object.prototype.hasOwnProperty.call(d,"codexThreadId")?d.codexThreadId:t?.codexThreadId,codexModelId:Object.prototype.hasOwnProperty.call(d,"codexModelId")?d.codexModelId:t?.codexModelId,codexModeId:Object.prototype.hasOwnProperty.call(d,"codexModeId")?d.codexModeId:t?.codexModeId,codewhaleThreadId:Object.prototype.hasOwnProperty.call(d,"codewhaleThreadId")?d.codewhaleThreadId:t?.codewhaleThreadId,codexReasoningEffort:Object.prototype.hasOwnProperty.call(d,"codexReasoningEffort")?d.codexReasoningEffort:t?.codexReasoningEffort,codexSandboxMode:Object.prototype.hasOwnProperty.call(d,"codexSandboxMode")?d.codexSandboxMode:t?.codexSandboxMode,piSessionPath:Object.prototype.hasOwnProperty.call(d,"piSessionPath")?d.piSessionPath:t?.piSessionPath,cwd:t?.cwd,modeId:s(t?.modeId),modelId:t?.modelId,updatedAt:Date.now()};this.bindings.set(e,o),this.scheduleWrite()}}export{x as SessionBindingStore};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readReplyFile as l,buildAttachmentExtra as p}from"./attachment-file.js";import{normalizeString as n}from"../util/normalize-string.js";function i(t){return t.replace(/\/+$/u,"")}function u(t){return n(t)?JSON.parse(t):{}}function d(t){const e=new URL(n(t));if(e.protocol!=="ws:"&&e.protocol!=="wss:")throw new Error("ws_url must start with ws:// or wss://");const o=i(e.pathname).replace(/\/ws$/u,"");if(!o||o===i(e.pathname))throw new Error("ws_url must end with /ws");return e.protocol=e.protocol==="wss:"?"https:":"http:",e.pathname=`${o}/oss/presign`,e.search="",e.hash="",e.toString()}async function w(t){const e=await fetch(d(t.wsURL),{method:"POST",headers:{Authorization:`Bearer ${n(t.apiKey)}`,"Content-Type":"application/json"},body:JSON.stringify({session_id:n(t.sessionID),filename:n(t.fileName),content_type:n(t.contentType)})}),o=await e.text(),s=u(o);if(!e.ok||Number(s?.code??-1)!==0){const c=n(s?.msg)||e.statusText||"agent media presign failed";throw new Error(`agent media presign failed: ${c}`)}const r=n(s?.data?.upload_url),a=n(s?.data?.media_access_url);if(!r||!a)throw new Error("agent media presign returned incomplete upload_url/media_access_url");return{upload_url:r,access_url:a}}async function y(t){const e=await fetch(t.uploadURL,{method:"PUT",headers:{"Content-Type":n(t.contentType)},body:new Uint8Array(t.bytes)});if(!e.ok)throw new Error(`agent media upload failed: ${e.status} ${e.statusText}`)}async function m(t){const e=await l(t.filePath),o=await w({wsURL:t.wsURL,apiKey:t.apiKey,sessionID:t.sessionID,fileName:e.file_name,contentType:e.content_type});return await y({uploadURL:o.upload_url,contentType:e.content_type,bytes:e.bytes}),{...e,access_url:o.access_url,extra:p({attachmentType:e.attachment_type,fileName:e.file_name,accessURL:o.access_url,contentType:e.content_type})}}export{d as resolveAgentAPIPresignURL,m as uploadReplyFileToAgentMedia};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import i from"node:path";import{readFile as l,stat as u}from"node:fs/promises";import{normalizeString as n}from"../util/normalize-string.js";const f=50*1024*1024,d=new Set(["pdf","doc","docx","xls","xlsx","ppt","pptx","txt","md","csv","json","xml","zip","rar","7z","tar","gz","jpg","jpeg","png","webp","gif","bmp","heic","heif","mp4","mov","m4v","webm","mkv","avi"]);function c(t){const e=i.extname(n(t)).toLowerCase();return e.startsWith(".")?e.slice(1):e}function x(t){const e=n(t).toLowerCase();return e.startsWith("image/")?"image":e.startsWith("video/")?"video":"file"}function h(t){switch(c(t)){case"jpg":case"jpeg":return"image/jpeg";case"png":return"image/png";case"webp":return"image/webp";case"gif":return"image/gif";case"bmp":return"image/bmp";case"heic":return"image/heic";case"heif":return"image/heif";case"mp4":return"video/mp4";case"mov":return"video/quicktime";case"m4v":return"video/x-m4v";case"webm":return"video/webm";case"mkv":return"video/x-matroska";case"avi":return"video/x-msvideo";case"pdf":return"application/pdf";case"doc":return"application/msword";case"docx":return"application/vnd.openxmlformats-officedocument.wordprocessingml.document";case"xls":return"application/vnd.ms-excel";case"xlsx":return"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";case"ppt":return"application/vnd.ms-powerpoint";case"pptx":return"application/vnd.openxmlformats-officedocument.presentationml.presentation";case"txt":return"text/plain";case"md":return"text/markdown";case"csv":return"text/csv";case"json":return"application/json";case"xml":return"application/xml";case"zip":return"application/zip";case"rar":return"application/vnd.rar";case"7z":return"application/x-7z-compressed";case"tar":return"application/x-tar";case"gz":return"application/gzip";default:return"application/octet-stream"}}async function b(t){const e=n(t);if(!e)throw new Error("file path must be a non-empty absolute path");if(!i.isAbsolute(e))throw new Error(`file requires an absolute path: ${e}`);const a=await u(e);if(!a.isFile())throw new Error(`path is not a file: ${e}`);if(a.size<=0)throw new Error(`file is empty: ${e}`);if(a.size>f)throw new Error(`file exceeds 50MB: ${e}`);const r=i.basename(e),o=c(r);if(!o||!d.has(o))throw new Error(`unsupported file type: ${r}`);const s=h(r),p=x(s),m=await l(e);return{file_path:e,file_name:r,content_type:s,attachment_type:p,bytes:m}}function y(t){const e={media_url:n(t.accessURL),attachment_type:n(t.attachmentType),file_name:n(t.fileName),content_type:n(t.contentType)};return{...e,attachments:[e]}}export{y as buildAttachmentExtra,b as readReplyFile,x as resolveAttachmentType,h as resolveContentType};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{splitTextForAibotProtocol as o,resolveOutboundTextChunkLimit as r,resolveStreamTextChunkLimit as O,DEFAULT_OUTBOUND_TEXT_CHUNK_LIMIT as E}from"./protocol-text.js";import{uploadReplyFileToAgentMedia as T,resolveAgentAPIPresignURL as C}from"./agent-api-media.js";import{readReplyFile as _,buildAttachmentExtra as a,resolveAttachmentType as i,resolveContentType as l}from"./attachment-file.js";import{parseInteractionMessage as A,readCardSubmissionParam as I}from"./interaction-parser.js";import{getProtocolDescriptor as p,getRequiredUserCommandTemplate as s,SERVICE_NAME as N,CONTRACT_VERSION as L,PROTOCOL_VERSION as M,USER_COMMAND_FAMILY as d,USER_COMMAND_TEMPLATES as x,SESSION_CONTROL_VERBS as U,SESSION_CONTROL_OUTCOMES as u,SESSION_CONTROL_ERROR_CODES as P,SERVICE_CAPABILITIES as c}from"./protocol-descriptor.js";export{L as CONTRACT_VERSION,E as DEFAULT_OUTBOUND_TEXT_CHUNK_LIMIT,M as PROTOCOL_VERSION,c as SERVICE_CAPABILITIES,N as SERVICE_NAME,P as SESSION_CONTROL_ERROR_CODES,u as SESSION_CONTROL_OUTCOMES,U as SESSION_CONTROL_VERBS,d as USER_COMMAND_FAMILY,x as USER_COMMAND_TEMPLATES,a as buildAttachmentExtra,p as getProtocolDescriptor,s as getRequiredUserCommandTemplate,A as parseInteractionMessage,I as readCardSubmissionParam,_ as readReplyFile,C as resolveAgentAPIPresignURL,i as resolveAttachmentType,l as resolveContentType,r as resolveOutboundTextChunkLimit,O as resolveStreamTextChunkLimit,o as splitTextForAibotProtocol,T as uploadReplyFileToAgentMedia};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const a="grix://card/",c="grix://open/",u="_submit",l=/\(\s*(grix:\/\/card\/[\s\S]+?)\s*\)/gi,d=/grix:\/\/card\/[^\s)\]]+/gi,m=/grix:\/\/open\/[^\s)\]]+/gi;function g(t){const n=[],r=new Set;for(const e of f(t)){const s=p(e);!s||r.has(s.normalizedUri)||(r.add(s.normalizedUri),n.push(s))}return{cardSubmissions:n}}function U(t,n){return S(t.params.get(n))}function f(t){const n=_(t),r=[];for(const s of n.matchAll(l)){const i=o(s[1]);i&&r.push(i)}for(const s of n.matchAll(d)){const i=o(s[0]);i&&r.push(i)}for(const s of n.matchAll(m)){const i=o(s[0]);i&&r.push(i)}const e=o(n.trim());return(e.startsWith(a)||e.startsWith(c))&&r.push(e),R(r)}function p(t){if(t.startsWith(c))return h(t);if(!t.startsWith(a))return null;let n;try{n=new URL(t)}catch{return null}if(n.hostname!=="card")return null;const r=n.pathname.replace(/^\/+/,"").trim();if(!r.endsWith(u))return null;const e=r.slice(0,-u.length).trim();return!e||e==="agent_open_session"?null:{cardId:e,rawUri:t,normalizedUri:n.toString(),params:n.searchParams}}function h(t){let n;try{n=new URL(t)}catch{return null}if(n.hostname!=="open")return null;const r=n.pathname.split("/").map(e=>e.trim()).filter(Boolean);return r.length!==1||r[0]!=="session"?null:{cardId:"agent_open_session",rawUri:t,normalizedUri:n.toString(),params:n.searchParams}}function _(t){return t.replace(/&/gi,"&")}function o(t){return t.replace(/\s+/g,"").trim()}function R(t){const n=[...new Set(t)];return n.filter(r=>!n.some(e=>e!==r&&e.startsWith(r)))}function S(t){if(!t)return;let n=t.trim();for(let r=0;r<3;r++)try{const e=decodeURIComponent(n);if(e===n)break;n=e}catch{break}return n.trim()||void 0}export{g as parseInteractionMessage,U as readCardSubmissionParam};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{normalizeString as o}from"../util/normalize-string.js";const a=/^\[\[quoted_message_id:([^\]\r\n]+)\]\](?:\r?\n)?/u;function g(r,{messageId:e="",quotedMessageId:t=""}={}){const u=String(r??""),d=o(e),n=o(t),s=[];return n&&s.push(`[[quoted_message_id:${n}]]`),u&&s.push(u),d&&s.push(`[[message_id:${d}]]`),s.join(`
|
|
2
|
+
`)}function i(r){const e=String(r??""),t=a.exec(e);return t?{text:e.slice(t[0].length),quotedMessageId:o(t[1])}:{text:e,quotedMessageId:""}}function f({replyTo:r="",text:e="",inboundQuotedMessageId:t="",inboundMessageId:u=""}={}){const d=o(r);if(d)return{text:String(e??""),quotedMessageId:d};const n=i(e);if(n.quotedMessageId)return n;const s=o(t)||o(u);return{text:n.text,quotedMessageId:s}}export{i as extractOutboundQuotedMessageReference,g as formatInboundMessageReferenceText,f as resolveOutboundQuotedMessageId};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import{isAbsolute as d}from"node:path";const l="[\u5F15\u7528\u6D88\u606F]",p=/^(?:(?:[ \t]*>[^\r\n]*(?:\r?\n|$))+)(?:[ \t]*\r?\n)*[ \t]*-{3,}[ \t]*(?:\r?\n|$)(?:[ \t]*\r?\n)*/;function E(t,e){const n=g(t),r=_(n,e),o=y(t,n),i=w(n),s=I(n,"additional_directories","additionalDirectories"),c=m(n,"mode_id","modeId"),f=m(n,"model_id","modelId"),a=C(n,"timeout_ms","timeoutMs");return{cwd:r,prompt:o,mcpServers:i,additionalDirectories:s??[],modeId:c,modelId:f,timeoutMs:a}}function g(t){const e=u(t.extra),n=[t,u(t.acp),u(t.gemini_acp)];return e&&(n.push(e),n.push(u(e.acp)),n.push(u(e.gemini_acp))),n.filter(r=>r!==null)}function _(t,e){const r=m(t,"cwd","workdir","working_directory")?.trim()||e?.trim()||"";if(!r)return process.cwd();if(!d(r))throw new Error(`CWD must be an absolute path: ${r}`);return r}function y(t,e){const n=v(e,"prompt");if(n&&n.length>0){const f=n.map(a=>a?.type==="text"?a.text:"").filter(Boolean);if(f.length>0)return f.join(`
|
|
2
|
+
`)}const r=t.context_messages??[],o=t.quoted_message_id,i=t.msg_id;let s=m(e,"text")??t.content?.trim()??"";s=x(s,r,o);const c=A(r,i);return!c&&!s?"":c?s?`Conversation context:
|
|
3
|
+
`+c+`
|
|
4
|
+
|
|
5
|
+
Latest user message:
|
|
6
|
+
`+s:`Conversation context:
|
|
7
|
+
`+c:s}function A(t,e){if(!t||t.length===0)return"";const n=[];for(const r of t){if(e&&r.msg_id===e)continue;const o=r.content?.trim();if(!o)continue;const i=h(o);if(i)n.push(`Quoted message:
|
|
8
|
+
`+i);else{const s=r.sender_type===2?"Assistant message":"User message";n.push(`${s}:
|
|
9
|
+
${o}`)}}return n.join(`
|
|
10
|
+
|
|
11
|
+
`)}function h(t){return t.startsWith(l)?t.slice(l.length).replace(/^\s*\n?/,"").trim()||l:null}function x(t,e,n){return!n||!e?.some(r=>r.msg_id===n&&r.content?.trim())?t:t.replace(p,"")}function w(t){for(const e of t){const n=e.mcp_servers??e.mcpServers,r=b(n);if(r&&r.every(o=>!!o&&typeof o=="object"&&!Array.isArray(o)))return r.map(o=>({name:o.name??"unknown",command:o.command??"",args:o.args,env:o.env}))}return[]}function m(t,...e){for(const n of t)for(const r of e){const o=n[r];if(typeof o=="string"&&o.trim())return o.trim()}return null}function v(t,e){for(const n of t){const r=n[e];if(Array.isArray(r)&&r.length>0)return r}return null}function I(t,...e){for(const n of t)for(const r of e){const o=n[r];if(!Array.isArray(o))continue;const i=o.filter(s=>typeof s=="string");if(i.length>0)return i}return null}function u(t){return!t||typeof t!="object"||Array.isArray(t)?null:t}function b(t){return Array.isArray(t)?t:null}function C(t,...e){for(const n of t)for(const r of e){const o=n[r];if(typeof o=="number"&&Number.isFinite(o)&&o>0)return Math.floor(o)}return null}export{E as extractAcpTurnInput};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const s="grix-connector",d=1,n="aibot-agent-api-v1",e="/grix",o=Object.freeze({open:`${e} open <working-directory>`,status:`${e} status`,where:`${e} where`,stop:`${e} stop`}),r=["open","status","where","stop"],t=["opened","already_bound","status","where","stopped"],i=["session_id_required","session_cwd_required","session_invalid_cwd","session_binding_missing","session_rebind_forbidden","session_bridge_inactive","session_thread_missing","session_thread_locked","session_thread_mismatch","session_cwd_conflict","session_verb_invalid","session_runtime_error"],a=["sender_unauthorized"],c=["daemon_cli_v1","session_control_v1","bridge_lifecycle_v1","multi_adapter_v1","codex_raw_jsonrpc_passthrough_v1","claude_mcp_channel_v1"];function p(){return{service:s,command:s,contract_version:1,protocol_version:n,capabilities:c,user_command_family:e,user_command_templates:o,new_session_cwd_required:!0,session_control_verbs:r,session_control_outcomes:t,session_control_error_codes:i}}function O(_){switch(_){case"session_binding_missing":case"session_cwd_required":return o.open;default:return null}}export{a as ACCESS_CONTROL_ERROR_CODES,d as CONTRACT_VERSION,n as PROTOCOL_VERSION,c as SERVICE_CAPABILITIES,s as SERVICE_NAME,i as SESSION_CONTROL_ERROR_CODES,t as SESSION_CONTROL_OUTCOMES,r as SESSION_CONTROL_VERBS,e as USER_COMMAND_FAMILY,o as USER_COMMAND_TEMPLATES,p as getProtocolDescriptor,O as getRequiredUserCommandTemplate};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const A=2e3,I=12288,E=1200,M=48;function i(t,r){const n=Number(t);return!Number.isFinite(n)||n<=0?r:Math.floor(n)}function U(t,r=1200){return Math.min(2e3,i(t,r))}function f(t){return Math.min(2e3,i(t,48))}function B(t,r){const n=String(t??"");if(!n)return[];const s=U(r,1200),T=[];let e="",o=0,_=0;for(const u of n){const O=Buffer.byteLength(u,"utf8"),c=o+1,L=_+O;e&&(c>s||L>12288)&&(T.push(e),e="",o=0,_=0),e+=u,o+=1,_+=O}return e&&T.push(e),T}export{E as DEFAULT_OUTBOUND_TEXT_CHUNK_LIMIT,U as resolveOutboundTextChunkLimit,f as resolveStreamTextChunkLimit,B as splitTextForAibotProtocol};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{detectProvider as o,queryProviderQuota as t}from"./providers.js";export{o as detectProvider,t as queryProviderQuota};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFile as l}from"node:fs/promises";import{homedir as a}from"node:os";import{join as s}from"node:path";import{spawn as u}from"node:child_process";const m=s(a(),".aws/sso/cache/kiro-auth-token-cli.json"),p="https://codewhisperer.us-east-1.amazonaws.com",d="AmazonCodeWhispererService.GetUsageLimits",w=1e4;async function c(){const t=await l(m,"utf-8");return JSON.parse(t)}function f(t){return Date.now()>new Date(t.expiresAt).getTime()}async function T(){return new Promise((t,o)=>{const e=s(a(),".local/bin/kiro-cli"),i=u(e,["whoami"],{stdio:["ignore","pipe","pipe"],timeout:15e3});let r="";i.stdout.on("data",n=>{r+=n.toString()}),i.stderr.on("data",()=>{}),i.on("close",n=>{n===0?t():o(new Error(`kiro-cli whoami exited with code ${n}: ${r.trim()}`))}),i.on("error",o)})}async function g(t,o){const e=new AbortController,i=setTimeout(()=>e.abort(),w);try{const r=await fetch(p,{method:"POST",headers:{"Content-Type":"application/x-amz-json-1.0","X-Amz-Target":d,Authorization:`Bearer ${t}`,Accept:"application/json"},body:JSON.stringify({profileArn:o}),signal:e.signal});if(!r.ok){const n=await r.text();throw new Error(`GetUsageLimits ${r.status}: ${n}`)}return await r.json()}finally{clearTimeout(i)}}async function b(){try{let t=await c();f(t)&&(await T(),t=await c());const o=await g(t.accessToken,t.profileArn),e=o.usageBreakdownList?.find(r=>r.resourceType==="CREDIT");let i=null;if(e){const r=e.currentUsageWithPrecision??e.currentUsage,n=e.usageLimitWithPrecision??e.usageLimit;i={remaining:Math.max(0,n-r),total:n,used:r,unit:e.unit||e.displayName||"Credits"}}return{provider:"kiro",providerLabel:"Kiro",planName:o.subscriptionInfo?.subscriptionTitle??null,tiers:[],balance:i,success:!0,error:null}}catch(t){const o=t instanceof Error?t.message:String(t);return{provider:"kiro",providerLabel:"Kiro",planName:null,tiers:[],balance:null,success:!1,error:o}}}export{b as queryKiroQuota};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function N(s){const t=s.toLowerCase();return t.includes("open.bigmodel.cn")||t.includes("bigmodel.cn")||t.includes("api.z.ai")?{id:"zhipu",label:"Zhipu GLM"}:t.includes("api.kimi.com")?{id:"kimi",label:"Kimi"}:t.includes("api.minimaxi.com")?{id:"minimax_cn",label:"MiniMax"}:t.includes("api.minimax.io")?{id:"minimax_en",label:"MiniMax"}:t.includes("api.deepseek.com")?{id:"deepseek",label:"DeepSeek"}:t.includes("api.stepfun.ai")||t.includes("api.stepfun.com")?{id:"stepfun",label:"StepFun"}:t.includes("api.siliconflow.cn")?{id:"siliconflow_cn",label:"SiliconFlow"}:t.includes("api.siliconflow.com")?{id:"siliconflow_en",label:"SiliconFlow"}:t.includes("openrouter.ai")?{id:"openrouter",label:"OpenRouter"}:t.includes("api.novita.ai")?{id:"novita",label:"Novita AI"}:null}const f=1e4;function u(s,t,r){return{provider:s,providerLabel:t,planName:null,tiers:[],balance:null,success:!1,error:r}}function m(s){if(typeof s=="number")return s;if(typeof s=="string"){const t=Number(s);return Number.isFinite(t)?t:null}return null}function y(s){if(!Number.isFinite(s)||s<=0)return null;try{return new Date(s).toISOString()}catch{return null}}function v(s){if(typeof s=="string")return s;if(typeof s=="number"){const t=s<1e12?s*1e3:s;return y(t)}return null}async function P(s){const t="zhipu",r="Zhipu GLM";try{const e=await fetch("https://api.z.ai/api/monitor/usage/quota/limit",{method:"GET",headers:{Authorization:s,"Content-Type":"application/json","Accept-Language":"en-US,en"},signal:AbortSignal.timeout(f)});if(e.status===401||e.status===403)return u(t,r,`Authentication failed (HTTP ${e.status})`);if(!e.ok){const l=await e.text().catch(()=>"");return u(t,r,`API error (HTTP ${e.status}): ${l.slice(0,200)}`)}const o=await e.json();if(o.success===!1)return u(t,r,`API error: ${o.msg??"Unknown error"}`);const i=o.data;if(!i)return u(t,r,"Missing data field");const n=typeof i.level=="string"?i.level:null,a=A(i);return{provider:t,providerLabel:r,planName:n,tiers:a,balance:null,success:!0,error:null}}catch(e){return u(t,r,`Network error: ${e instanceof Error?e.message:String(e)}`)}}function A(s){const t=Array.isArray(s.limits)?s.limits:[],r=[];for(const e of t){if(String(e.type??"").toUpperCase()!=="TOKENS_LIMIT")continue;const i=m(e.percentage)??0,n=typeof e.nextResetTime=="number"?e.nextResetTime:Number.MAX_SAFE_INTEGER,a=n===Number.MAX_SAFE_INTEGER?null:y(n);r.push({percentage:i,resetMs:n,resetIso:a})}return r.sort((e,o)=>e.resetMs-o.resetMs),r.slice(0,2).map((e,o)=>({name:o===0?"five_hour":"weekly_limit",label:o===0?"5h limit":"Weekly limit",usedPercent:Math.round(e.percentage*100)/100,resetsAt:e.resetIso}))}async function E(s){const t="kimi",r="Kimi";try{const e=await fetch("https://api.kimi.com/coding/v1/usages",{method:"GET",headers:{Authorization:`Bearer ${s}`,Accept:"application/json"},signal:AbortSignal.timeout(f)});if(e.status===401||e.status===403)return u(t,r,`Authentication failed (HTTP ${e.status})`);if(!e.ok){const l=await e.text().catch(()=>"");return u(t,r,`API error (HTTP ${e.status}): ${l.slice(0,200)}`)}const o=await e.json(),i=[],n=Array.isArray(o.limits)?o.limits:[];for(const l of n){const d=l.detail;if(!d)continue;const c=m(d.limit)??1,p=m(d.remaining)??0,b=v(d.resetTime),h=Math.max(0,c-p);i.push({name:"five_hour",label:"5h limit",usedPercent:c>0?Math.round(h/c*1e4)/100:0,resetsAt:b})}const a=o.usage;if(a){const l=m(a.limit)??1,d=m(a.remaining)??0,c=v(a.resetTime),p=Math.max(0,l-d);i.push({name:"weekly_limit",label:"Weekly limit",usedPercent:l>0?Math.round(p/l*1e4)/100:0,resetsAt:c})}return{provider:t,providerLabel:r,planName:null,tiers:i,balance:null,success:!0,error:null}}catch(e){return u(t,r,`Network error: ${e instanceof Error?e.message:String(e)}`)}}async function T(s,t){const r=t?"minimax_cn":"minimax_en",e="MiniMax",o=t?"api.minimaxi.com":"api.minimax.io";try{const i=await fetch(`https://${o}/v1/api/openplatform/coding_plan/remains`,{method:"GET",headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json"},signal:AbortSignal.timeout(f)});if(i.status===401||i.status===403)return u(r,e,`Authentication failed (HTTP ${i.status})`);if(!i.ok){const p=await i.text().catch(()=>"");return u(r,e,`API error (HTTP ${i.status}): ${p.slice(0,200)}`)}const n=await i.json(),a=n.base_resp;if(a&&typeof a.status_code=="number"&&a.status_code!==0)return u(r,e,`API error (code ${a.status_code}): ${a.status_msg??"Unknown"}`);const l=[],c=(Array.isArray(n.model_remains)?n.model_remains:[])[0];if(c){const p=m(c.current_interval_total_count)??0,b=m(c.current_interval_usage_count)??0,h=typeof c.end_time=="number"?c.end_time:null;p>0&&l.push({name:"five_hour",label:"5h limit",usedPercent:Math.round(b/p*1e4)/100,resetsAt:h!==null?y(h):null});const g=m(c.current_weekly_total_count)??0,$=m(c.current_weekly_usage_count)??0,_=typeof c.weekly_end_time=="number"?c.weekly_end_time:null;g>0&&l.push({name:"weekly_limit",label:"Weekly limit",usedPercent:Math.round($/g*1e4)/100,resetsAt:_!==null?y(_):null})}return{provider:r,providerLabel:e,planName:null,tiers:l,balance:null,success:!0,error:null}}catch(i){return u(r,e,`Network error: ${i instanceof Error?i.message:String(i)}`)}}async function M(s){const t="deepseek",r="DeepSeek";try{const e=await fetch("https://api.deepseek.com/user/balance",{method:"GET",headers:{Authorization:`Bearer ${s}`,Accept:"application/json"},signal:AbortSignal.timeout(f)});if(e.status===401||e.status===403)return u(t,r,`Authentication failed (HTTP ${e.status})`);if(!e.ok){const c=await e.text().catch(()=>"");return u(t,r,`API error (HTTP ${e.status}): ${c.slice(0,200)}`)}const o=await e.json(),i=o.is_available===!0,a=(Array.isArray(o.balance_infos)?o.balance_infos:[])[0];if(!a)return u(t,r,"No balance info returned");const l=String(a.currency??"CNY"),d=m(a.total_balance);return{provider:t,providerLabel:r,planName:null,tiers:[],balance:{remaining:d??0,total:null,used:null,unit:l},success:!0,error:i?null:"Insufficient balance"}}catch(e){return u(t,r,`Network error: ${e instanceof Error?e.message:String(e)}`)}}async function x(s){const t="stepfun",r="StepFun";try{const e=await fetch("https://api.stepfun.com/v1/accounts",{method:"GET",headers:{Authorization:`Bearer ${s}`,Accept:"application/json"},signal:AbortSignal.timeout(f)});if(e.status===401||e.status===403)return u(t,r,`Authentication failed (HTTP ${e.status})`);if(!e.ok){const n=await e.text().catch(()=>"");return u(t,r,`API error (HTTP ${e.status}): ${n.slice(0,200)}`)}const o=await e.json(),i=m(o.balance)??0;return{provider:t,providerLabel:r,planName:null,tiers:[],balance:{remaining:i,total:null,used:null,unit:"CNY"},success:!0,error:null}}catch(e){return u(t,r,`Network error: ${e instanceof Error?e.message:String(e)}`)}}async function k(s,t){const r=t?"siliconflow_cn":"siliconflow_en",e=t?"SiliconFlow":"SiliconFlow (EN)",o=t?"api.siliconflow.cn":"api.siliconflow.com",i=t?"CNY":"USD";try{const n=await fetch(`https://${o}/v1/user/info`,{method:"GET",headers:{Authorization:`Bearer ${s}`,Accept:"application/json"},signal:AbortSignal.timeout(f)});if(n.status===401||n.status===403)return u(r,e,`Authentication failed (HTTP ${n.status})`);if(!n.ok){const c=await n.text().catch(()=>"");return u(r,e,`API error (HTTP ${n.status}): ${c.slice(0,200)}`)}const l=(await n.json()).data;if(!l)return u(r,e,"Missing data field");const d=m(l.totalBalance)??0;return{provider:r,providerLabel:e,planName:null,tiers:[],balance:{remaining:d,total:null,used:null,unit:i},success:!0,error:null}}catch(n){return u(r,e,`Network error: ${n instanceof Error?n.message:String(n)}`)}}async function I(s){const t="openrouter",r="OpenRouter";try{const e=await fetch("https://openrouter.ai/api/v1/credits",{method:"GET",headers:{Authorization:`Bearer ${s}`,Accept:"application/json"},signal:AbortSignal.timeout(f)});if(e.status===401||e.status===403)return u(t,r,`Authentication failed (HTTP ${e.status})`);if(!e.ok){const d=await e.text().catch(()=>"");return u(t,r,`API error (HTTP ${e.status}): ${d.slice(0,200)}`)}const o=await e.json(),i=o.data??o,n=m(i.total_credits)??0,a=m(i.total_usage)??0,l=n-a;return{provider:t,providerLabel:r,planName:null,tiers:[],balance:{remaining:l,total:n,used:a,unit:"USD"},success:!0,error:null}}catch(e){return u(t,r,`Network error: ${e instanceof Error?e.message:String(e)}`)}}async function L(s){const t="novita",r="Novita AI";try{const e=await fetch("https://api.novita.ai/v3/user/balance",{method:"GET",headers:{Authorization:`Bearer ${s}`,Accept:"application/json"},signal:AbortSignal.timeout(f)});if(e.status===401||e.status===403)return u(t,r,`Authentication failed (HTTP ${e.status})`);if(!e.ok){const n=await e.text().catch(()=>"");return u(t,r,`API error (HTTP ${e.status}): ${n.slice(0,200)}`)}const o=await e.json(),i=(m(o.availableBalance)??0)/1e4;return{provider:t,providerLabel:r,planName:null,tiers:[],balance:{remaining:i,total:null,used:null,unit:"USD"},success:!0,error:null}}catch(e){return u(t,r,`Network error: ${e instanceof Error?e.message:String(e)}`)}}const w=new Map,j=300*1e3;async function G(s,t){const r=`${t.slice(0,8)}@${s}`,e=w.get(r);if(e&&Date.now()-e.timestamp<=j){const n=await S(e.providerId,s,t);if(n)return n;w.delete(r)}else e&&w.delete(r);const o=["zhipu","deepseek","kimi","openrouter","stepfun","minimax_cn","siliconflow_cn","novita"],i=await Promise.allSettled(o.map(n=>S(n,s,t)));for(let n=0;n<i.length;n++){const a=i[n];if(a.status==="fulfilled"&&a.value?.success)return w.set(r,{providerId:o[n],timestamp:Date.now()}),a.value}return null}async function S(s,t,r){const e=t.replace(/\/+$/,""),o={Authorization:"Bearer ${apiKey}",Accept:"application/json"};try{switch(s){case"zhipu":{const i=await fetch("${origin}/api/monitor/usage/quota/limit",{method:"GET",headers:{...o,Authorization:r,"Content-Type":"application/json","Accept-Language":"en-US,en"},signal:AbortSignal.timeout(f)});if(!i.ok)return null;const n=await i.json();if(n.success===!1)return null;const a=n.data;if(!a)return null;const l=typeof a.level=="string"?a.level:null,d=A(a);return{provider:"zhipu",providerLabel:"Zhipu GLM",planName:l,tiers:d,balance:null,success:!0,error:null}}case"deepseek":{const i=await fetch("${origin}/user/balance",{method:"GET",headers:o,signal:AbortSignal.timeout(f)});if(!i.ok)return null;const n=await i.json(),a=n.is_available===!0,d=(Array.isArray(n.balance_infos)?n.balance_infos:[])[0];if(!d)return null;const c=String(d.currency??"CNY"),p=m(d.total_balance);return{provider:"deepseek",providerLabel:"DeepSeek",planName:null,tiers:[],balance:{remaining:p??0,total:null,used:null,unit:c},success:!0,error:a?null:"Insufficient balance"}}case"kimi":{const i=await fetch("${origin}/coding/v1/usages",{method:"GET",headers:o,signal:AbortSignal.timeout(f)});if(!i.ok)return null;const n=await i.json(),a=[],l=Array.isArray(n.limits)?n.limits:[];for(const d of l){const c=d.detail;if(!c)continue;const p=m(c.limit)??1,b=m(c.remaining)??0,h=v(c.resetTime),g=Math.max(0,p-b);a.push({name:"five_hour",label:"5h limit",usedPercent:p>0?Math.round(g/p*1e4)/100:0,resetsAt:h})}return{provider:"kimi",providerLabel:"Kimi",planName:null,tiers:a,balance:null,success:!0,error:null}}case"openrouter":{const i=await fetch("${origin}/api/v1/credits",{method:"GET",headers:o,signal:AbortSignal.timeout(f)});if(!i.ok)return null;const n=await i.json(),a=n.data??n,l=m(a.total_credits)??0,d=m(a.total_usage)??0,c=l-d;return{provider:"openrouter",providerLabel:"OpenRouter",planName:null,tiers:[],balance:{remaining:c,total:l,used:d,unit:"USD"},success:!0,error:null}}case"stepfun":{const i=await fetch("${origin}/v1/accounts",{method:"GET",headers:o,signal:AbortSignal.timeout(f)});if(!i.ok)return null;const n=await i.json(),a=m(n.balance)??0;return{provider:"stepfun",providerLabel:"StepFun",planName:null,tiers:[],balance:{remaining:a,total:null,used:null,unit:"CNY"},success:!0,error:null}}case"minimax_cn":{const i=await fetch("${origin}/v1/api/openplatform/coding_plan/remains",{method:"GET",headers:o,signal:AbortSignal.timeout(f)});if(!i.ok)return null;const n=await i.json(),a=n.base_resp;if(a&&typeof a.status_code=="number"&&a.status_code!==0)return null;const d=(Array.isArray(n.model_remains)?n.model_remains:[])[0];if(!d)return null;const c=[],p=m(d.current_interval_total_count)??0,b=m(d.current_interval_usage_count)??0;return p>0&&c.push({name:"five_hour",label:"5h limit",usedPercent:Math.round(b/p*1e4)/100,resetsAt:null}),{provider:"minimax_cn",providerLabel:"MiniMax",planName:null,tiers:c,balance:null,success:!0,error:null}}case"siliconflow_cn":{const i=await fetch("${origin}/v1/user/info",{method:"GET",headers:o,signal:AbortSignal.timeout(f)});if(!i.ok)return null;const a=(await i.json()).data;if(!a)return null;const l=m(a.totalBalance)??0;return{provider:"siliconflow_cn",providerLabel:"SiliconFlow",planName:null,tiers:[],balance:{remaining:l,total:null,used:null,unit:"CNY"},success:!0,error:null}}case"novita":{const i=await fetch("${origin}/v3/user/balance",{method:"GET",headers:o,signal:AbortSignal.timeout(f)});if(!i.ok)return null;const n=await i.json(),a=(m(n.availableBalance)??0)/1e4;return{provider:"novita",providerLabel:"Novita AI",planName:null,tiers:[],balance:{remaining:a,total:null,used:null,unit:"USD"},success:!0,error:null}}default:return null}}catch{return null}}async function R(s,t){if(!t.trim())return{provider:"unknown",providerLabel:"Unknown",planName:null,tiers:[],balance:null,success:!1,error:"API key is empty"};const r=N(s);if(r)switch(r.id){case"zhipu":return P(t);case"kimi":return E(t);case"minimax_cn":return T(t,!0);case"minimax_en":return T(t,!1);case"deepseek":return M(t);case"stepfun":return x(t);case"siliconflow_cn":return k(t,!0);case"siliconflow_en":return k(t,!1);case"openrouter":return I(t);case"novita":return L(t)}const e=await G(s,t);return e||{provider:"unknown",providerLabel:"Unknown",planName:null,tiers:[],balance:null,success:!1,error:"Could not identify provider for base URL: ${baseUrl}"}}export{N as detectProvider,R as queryProviderQuota};
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createServer as a}from"node:http";import{log as o}from"../log/logger.js";class v{server=null;startTime=Date.now();alive=!0;statusProvider=null;setStatusProvider(t){this.statusProvider=t}async start(t){return new Promise((s,i)=>{this.server=a((n,e)=>{if(n.url==="/healthz")if(this.alive){const r=this.statusProvider?.();e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:"ok",uptime:Math.floor((Date.now()-this.startTime)/1e3),pid:process.pid,...r?{agents:r}:{}}))}else e.writeHead(503,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:"shutting_down"}));else e.writeHead(404),e.end()}),this.server.listen(t,"127.0.0.1",()=>{o.info("health",`Listening on 127.0.0.1:${t}`),s()}),this.server.on("error",i)})}markShuttingDown(){this.alive=!1}async stop(){if(this.server)return new Promise(t=>{this.server.close(()=>t())})}}export{v as HealthServer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{HealthServer as i}from"./health.js";import{writePidFile as t,removePidFile as l}from"./pidfile.js";export{i as HealthServer,l as removePidFile,t as writePidFile};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{writeFileSync as c,readFileSync as s,unlinkSync as a,existsSync as l}from"node:fs";import{join as p}from"node:path";import{GRIX_PATHS as w}from"../log/logger.js";const i=p(w.base,"grix-acp.pid");async function m(r,t){const n=Date.now()+t;for(;Date.now()<n;){try{process.kill(r,0)}catch{return!0}await new Promise(e=>setTimeout(e,100))}return!1}function y(){if(l(i)){const r=s(i,"utf-8").trim(),t=parseInt(r,10);if(!Number.isNaN(t)&&t!==process.pid)try{process.kill(t,0),process.kill(t,"SIGTERM");const n=Date.now()+3e3;let e=!0;for(;Date.now()<n;){try{process.kill(t,0)}catch{e=!1;break}const o=Date.now()+100;for(;Date.now()<o;);}if(e)try{process.kill(t,"SIGKILL")}catch{}}catch{}}c(i,`${process.pid}
|
|
2
|
+
`,"utf-8")}function h(){try{a(i)}catch{}}export{h as removePidFile,y as writePidFile};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{accessSync as u,constants as l}from"node:fs";import{spawn as f,execSync as w}from"node:child_process";import{isAbsolute as h,join as m}from"node:path";const S=process.platform==="win32"?";":":";function v(t){try{return u(t,l.X_OK),!0}catch{return!1}}function k(t,s){const e=String(t??"").trim();if(!e||h(e))return e;const a=process.platform==="win32",o=String(s??process.env.PATH??""),i=[],n=new Set;for(const r of o.split(S)){const c=r.trim();if(!c)continue;if(a){const p=m(c,e+".cmd");n.has(p)||(n.add(p),i.push(p))}const d=m(c,e);n.has(d)||(n.add(d),i.push(d))}for(const r of i)if(v(r))return r;return console.warn(`[spawn:resolve] command="${e}" not found in PATH. candidates tried: [${i.join(", ")}] PATH=${o.substring(0,500)}${o.length>500?"...(truncated)":""}`),e}function x(t,s,e={}){const{cwd:a,env:o,...i}=e,n={stdio:i.stdio??["pipe","pipe","pipe"],env:o??{...process.env},cwd:a,windowsHide:!0,...i};if(process.platform==="win32"&&/\.(cmd|bat)$/i.test(t)){const c=process.env.ComSpec||"cmd.exe",d=`""${t}" ${s.join(" ")}"`;return{process:f(c,["/d","/s","/c",d],{...n,windowsVerbatimArguments:!0}),isCmdSpawn:!0}}return{process:f(t,s,{...n,detached:n.detached??!0}),isCmdSpawn:!1}}function P(t,s="SIGTERM"){if(t.pid){if(process.platform==="win32"){try{w(`taskkill /pid ${t.pid} /T /F`,{stdio:"pipe",timeout:5e3})}catch{t.kill(s)}return}try{process.kill(-t.pid,s)}catch{t.kill(s)}}}export{P as killProcessGroup,k as resolveCommandPath,x as spawnCommand};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{SafeMarkdownStreamSegmenter as a}from"./safe-markdown-stream-segmenter.js";export{a as SafeMarkdownStreamSegmenter};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
const k=3e3,p=4500;class L{enabled;targetChars;hardLimitChars;segmentChars=0;state={inFence:!1,fenceMarker:"```"};constructor(s){this.enabled=s?.enabled??!0,this.targetChars=Math.max(256,Number(s?.targetChars??3e3)),this.hardLimitChars=Math.max(this.targetChars+128,Number(s?.hardLimitChars??4500))}push(s){if(!s)return[];if(!this.enabled)return this.segmentChars+=s.length,this.state=o(s,this.state),[{text:s,closeAfter:!1}];const e=[];let t=s;for(;t.length>0;){const n=this.targetChars-this.segmentChars;if(n>0&&t.length<=n){this.segmentChars+=t.length,this.state=o(t,this.state),e.push({text:t,closeAfter:!1});break}const c=M(t,this.state),i=Math.max(64,Math.floor(this.targetChars*.75)-this.segmentChars),r=Math.max(128,this.hardLimitChars-this.segmentChars),a=A(c,i,r);if(a>0&&a<t.length){const l=t.slice(0,a),C=o(l,this.state);this.segmentChars+=l.length,e.push({text:l,closeAfter:!0,reason:"threshold"}),t=t.slice(a),this.segmentChars=0,this.state=C;continue}if(this.segmentChars+t.length<this.hardLimitChars){this.segmentChars+=t.length,this.state=o(t,this.state),e.push({text:t,closeAfter:!1});break}const u=Math.max(128,this.hardLimitChars-this.segmentChars),f=Math.min(t.length,u);if(f>=t.length){this.segmentChars+=t.length,this.state=o(t,this.state),e.push({text:t,closeAfter:!1});break}let g=t.slice(0,f),m=t.slice(f);if(this.state.inFence){const l=this.state.fenceMarker||"```";g=`${g}
|
|
2
|
+
${l}`,m=`${l}
|
|
3
|
+
${m}`}e.push({text:g,closeAfter:!0,reason:"hard_limit"}),t=m,this.segmentChars=0,this.state={inFence:!1,fenceMarker:this.state.fenceMarker||"```"}}return d(e)}finish(){return[]}reset(){this.segmentChars=0,this.state={inFence:!1,fenceMarker:"```"}}}function d(h){const s=[];for(const e of h){if(!e.text)continue;const t=s[s.length-1];if(t&&!t.closeAfter&&!e.closeAfter&&!t.reason&&!e.reason){t.text+=e.text;continue}s.push(e)}return s}function A(h,s,e){let t=-1;for(const n of h)n>=s&&n<=e&&(t=n);return t}function M(h,s){const e=[];let t={...s};const n=h.split(`
|
|
4
|
+
`);let c=0;for(let i=0;i<n.length;i++){const r=n[i]??"",a=i<n.length-1?`${r}
|
|
5
|
+
`:r;if(t=o(a,t),c+=a.length,!t.inFence){if(r.trim()===""&&i<n.length-1){e.push(c);continue}/[。!?.!?]\s*$/.test(r)&&i<n.length-1&&e.push(c)}}return e}function o(h,s){let e=s.inFence,t=s.fenceMarker;const n=h.split(`
|
|
6
|
+
`);for(const c of n){const r=(c??"").trimStart();if(r.startsWith("```")||r.startsWith("~~~")){const a=r.startsWith("~~~")?"~~~":"```";e?a===t&&(e=!1):(e=!0,t=a)}}return{inFence:e,fenceMarker:t}}export{L as SafeMarkdownStreamSegmenter};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{JsonRpcTransport as p}from"./json-rpc.js";export{p as JsonRpcTransport};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{EventEmitter as m}from"events";import{log as l}from"../log/index.js";class _ extends m{nextId=1;pending=new Map;writeLock=Promise.resolve();closed=!1;_readable;_writable;_onNotify;_onRequest;constructor(t,e,r,o){super(),this._readable=t,this._writable=e,this._onNotify=r,this._onRequest=o,this.startReadLoop()}setHandlers(t,e){t&&(this._onNotify=t),e&&(this._onRequest=e)}async call(t,e,r){if(this.closed)throw new Error("transport closed");const o=this.nextId++,s=String(o),a=await new Promise((i,c)=>{if(this.pending.set(s,{resolve:i}),r){const n=()=>{this.pending.delete(s),c(new Error(`aborted: ${r.reason??"request cancelled"}`))};if(r.aborted){n();return}r.addEventListener("abort",n,{once:!0});const d=i,h=p=>{r.removeEventListener("abort",n),d(p)};this.pending.set(s,{resolve:h})}this.write({jsonrpc:"2.0",id:o,method:t,params:e??null}).catch(n=>{this.pending.delete(s),c(n)})});if(a.error){const i=new Error(a.error.message);throw i.code=a.error.code,i.data=a.error.data,i}return a.result}async notify(t,e){if(this.closed)throw new Error("transport closed");await this.write({jsonrpc:"2.0",method:t,params:e??null})}async respondSuccess(t,e){await this.write({jsonrpc:"2.0",id:t,result:e})}async respondError(t,e,r){await this.write({jsonrpc:"2.0",id:t,error:{code:e,message:r}})}close(){if(!this.closed){this.closed=!0;for(const[t,{resolve:e}]of this.pending)e({error:{code:-32e3,message:"transport closed"}});this.pending.clear(),this._readable.destroy(),this.emit("close")}}startReadLoop(){let t="";this._readable.on("data",e=>{t+=e.toString();const r=t.split(`
|
|
2
|
+
`);t=r.pop()??"";for(const o of r){const s=o.trim();s.length!==0&&this.dispatch(s)}}),this._readable.on("end",()=>{t.trim()&&this.dispatch(t.trim()),this.close()}),this._readable.on("error",e=>{this.emitTransportError(e),this.close()})}dispatch(t){let e;try{e=JSON.parse(t)}catch{return}if(e.id!=null&&!e.method){this.completePending(e.id,e.result,e.error);return}if(e.method&&(e.id==null||e.id===null)){this._onNotify?.(e.method,e.params);return}e.method&&e.id!=null&&this._onRequest?.(e.method,e.id,e.params)}completePending(t,e,r){const o=String(t),s=this.pending.get(o);s&&(this.pending.delete(o),s.resolve({result:e,error:r}))}async write(t){if(this.closed)throw new Error("transport closed");const e=this.writeLock.then(()=>new Promise((r,o)=>{const s=JSON.stringify(t)+`
|
|
3
|
+
`;if(this._writable.write(s,"utf-8"))r();else{const i=()=>{n(),r()},c=d=>{n(),o(d)},n=()=>{this._writable.removeListener("drain",i),this._writable.removeListener("error",c)};this._writable.once("drain",i),this._writable.once("error",c)}}));return this.writeLock=e.catch(r=>{l.error("json-rpc",`Write failed: ${r instanceof Error?r.message:r}`)}),e}emitTransportError(t){if(this.listenerCount("error")===0){l.warn("json-rpc",`Transport error (no listeners): ${t.message}`);return}this.emit("error",t)}}export{_ as JsonRpcTransport};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{execFile as N,execFileSync as p}from"node:child_process";import{appendFileSync as I,existsSync as a,readFileSync as d,renameSync as y,statfsSync as x,unlinkSync as F,writeFileSync as M}from"node:fs";import{join as m}from"node:path";import{GRIX_PATHS as g}from"../log/index.js";import{resolveClientVersion as A}from"../util/client-version.js";class o extends Error{code;constructor(n,t){super(t),this.name="UpgradeError",this.code=n}}function _(){return m(g.log,"upgrade.log")}function l(){return m(g.data,"upgrade-pending.json")}function $(){return a(l())}function b(){const e=l();if(!a(e))return null;try{return JSON.parse(d(e,"utf-8"))}catch{return null}}function O(e,n){const t={from_version:e,target_version:n,upgraded_at:new Date().toISOString(),crash_count:0},i=l(),c=i+".tmp";M(c,JSON.stringify(t),"utf-8"),y(c,i)}function D(){const e=l();if(a(e))try{F(e)}catch{}}function f(e){const n=`[${new Date().toISOString()}] ${e}
|
|
2
|
+
`;try{I(_(),n,"utf-8")}catch{}}function C(e=4096){const n=_();if(!a(n))return"";try{const t=d(n,"utf-8");return t.length<=e?t:t.slice(-e)}catch{return""}}function S(){try{return p("npm",["--version"],{encoding:"utf-8",timeout:1e4}).trim()}catch{throw new o("NPM_NOT_FOUND","npm is not available or timed out")}}function h(){let e;try{e=p("npm",["prefix","-g"],{encoding:"utf-8",timeout:1e4}).trim()}catch{return Number.MAX_SAFE_INTEGER}try{if(process.platform==="win32")return Number.MAX_SAFE_INTEGER;const n=x(e);return Math.floor(n.bsize*n.bavail/(1024*1024))}catch{return Number.MAX_SAFE_INTEGER}}function U(){let e;try{e=S()}catch(t){return{ok:!1,errorCode:"NPM_NOT_FOUND",errorMsg:t instanceof Error?t.message:"npm not available"}}const n=h();return n<100?{ok:!1,errorCode:"DISK_FULL",errorMsg:`Only ${n}MB free disk space (need >= 100MB)`,npmVersion:e,diskFreeMb:n}:{ok:!0,npmVersion:e,diskFreeMb:n}}function R(){let e="";try{e=S()}catch{}let n=Number.MAX_SAFE_INTEGER;try{n=h()}catch{}return{npm_version:e,node_version:process.version,disk_free_mb:n,platform:process.platform,arch:process.arch}}async function G(e,n,t=12e4){const i=`${e}@${n}`;return f(`npm install -g ${i} starting`),new Promise((c,s)=>{N("npm",["install","-g",i,"--prefer-online","--no-audit","--no-fund"],{timeout:t,maxBuffer:10*1024*1024},(u,P,E)=>{if(u){const r=E?.trim()||u.message;f(`npm install failed: ${r}`),u.killed?s(new o("NPM_TIMEOUT",`npm install timed out after ${t/1e3}s`)):r.includes("EACCES")||r.includes("permission denied")?s(new o("NPM_INSTALL_FAILED",`Permission denied: ${r}`)):r.includes("ENOSPC")||r.includes("no space left")?s(new o("DISK_FULL",`Disk full: ${r}`)):r.includes("404")||r.includes("not found")?s(new o("NPM_INSTALL_FAILED",`Package not found: ${r}`)):s(new o("NPM_INSTALL_FAILED",r));return}f("npm install succeeded"),c()})})}function X(e){const n=A();if(n!==e)throw new o("VERSION_MISMATCH",`Installed version ${n} does not match expected ${e}`);return n}export{o as UpgradeError,h as checkDiskSpace,S as checkNpmAvailable,R as collectEnvInfo,C as getUpgradeLogTail,G as npmInstall,$ as pendingExists,U as preflightCheck,b as readPending,D as removePending,f as upgradeLog,X as verifyInstalledVersion,O as writePending};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as m,mkdirSync as C,readFileSync as I,renameSync as U,writeFileSync as P}from"node:fs";import{join as h,dirname as $}from"node:path";import{spawn as b}from"node:child_process";import{log as n}from"../log/index.js";import{GRIX_PATHS as _}from"../log/index.js";import{resolveClientVersion as p}from"../util/client-version.js";import{UpgradeError as E,collectEnvInfo as L,getUpgradeLogTail as M,npmInstall as O,pendingExists as v,preflightCheck as D,readPending as N,removePending as u,upgradeLog as o,verifyInstalledVersion as R,writePending as F}from"./npm-upgrader.js";const G=360*60*1e3,x=300*1e3,y=1800*1e3,V=2,j=3,H="grix-connector",w=1e4;function S(s){return s.replace(/^wss:/,"https:").replace(/^ws:/,"http:")}function T(){return h(_.data,"upgrade-state.json")}function A(){const s=T();if(!m(s))return{daily_attempts:{},version_attempts:{}};try{return JSON.parse(I(s,"utf-8"))}catch{return{daily_attempts:{},version_attempts:{}}}}function K(s){const t=T();C($(t),{recursive:!0});const e=t+".tmp";P(e,JSON.stringify(s),"utf-8"),U(e,t)}function k(){return new Date().toISOString().slice(0,10)}class Q{agentConfigs;timer=null;initialTimer=null;running=!1;stopped=!1;constructor(t){this.agentConfigs=t}async start(){await this.handlePendingOnStartup(),this.initialTimer=setTimeout(()=>{this.stopped||(this.runCheck(),!this.stopped&&(this.timer=setInterval(()=>this.runCheck(),G)))},x)}stop(){this.stopped=!0,this.initialTimer&&(clearTimeout(this.initialTimer),this.initialTimer=null),this.timer&&(clearInterval(this.timer),this.timer=null)}triggerCheck(){this.stopped||this.runCheck()}async handlePendingOnStartup(){if(!v())return;const t=N();if(!t){u();return}const e=p();e===t.target_version?(o(`daemon startup: version matches target ${t.target_version}, upgrade succeeded`),await this.reportUpgrade({from_version:t.from_version,to_version:t.target_version,status:"success"})):(o(`daemon startup: version ${e} != target ${t.target_version}, rolled back`),await this.reportUpgrade({from_version:t.from_version,to_version:t.target_version,status:"rolled_back",error_code:"STARTUP_CRASH",crash_count:t.crash_count})),u()}async runCheck(){if(!this.running){this.running=!0;try{await this.check()}catch(t){n.error("upgrade",`Check failed: ${t instanceof Error?t.message:t}`)}finally{this.running=!1}}}async check(){if(v())return;const t=this.agentConfigs[0];if(!t)return;const e=await this.queryUpgrade(t);if(!e.available||!e.release)return;const r=e.release.version,a=p();if(!e.release.force&&!this.checkRateLimit(r))return;const c=D();if(!c.ok){await this.reportUpgrade({from_version:a,to_version:r,status:"failed",error_code:c.errorCode,error_msg:c.errorMsg});return}o(`upgrade start: ${a} -> ${r}`);const d=Date.now();try{F(a,r),await O(H,r),R(r),this.startGuardian(),o("npm install verified, reporting installed"),await this.reportUpgrade({from_version:a,to_version:r,status:"installed",duration_ms:Date.now()-d}),o("shutting down for restart"),process.kill(process.pid,"SIGTERM")}catch(l){const f=l instanceof E?l.code:"NPM_INSTALL_FAILED",g=l instanceof Error?l.message:String(l);o(`upgrade failed: ${f} ${g}`),u(),this.recordFailure(r),await this.reportUpgrade({from_version:a,to_version:r,status:"failed",error_code:f,error_msg:g,duration_ms:Date.now()-d,upgrade_log:M()})}}checkRateLimit(t){const e=A();if(e.last_failure_at){const c=Date.now()-new Date(e.last_failure_at).getTime();if(c<y)return n.info("upgrade",`In cooldown, ${(y-c)/6e4}m remaining`),!1}const r=e.version_attempts[t]??0;if(r>=j)return n.info("upgrade",`Version ${t} already tried ${r} times, skipping`),!1;const a=k(),i=e.daily_attempts[a]??0;return i>=V?(n.info("upgrade",`Already ${i} attempts today, skipping`),!1):!0}recordFailure(t){const e=A(),r=k();e.last_failure_at=new Date().toISOString(),e.last_failure_version=t,e.daily_attempts[r]=(e.daily_attempts[r]??0)+1,e.version_attempts[t]=(e.version_attempts[t]??0)+1,K(e)}async queryUpgrade(t){const r=`${S(t.wsUrl)}/v1/agent-api/upgrade/check?`+new URLSearchParams({client_type:"grix-connector",client_version:p(),channel:t.channel??"stable",platform:process.platform,arch:process.arch}).toString();try{const a=await fetch(r,{headers:{Authorization:`Bearer ${t.apiKey}`},signal:AbortSignal.timeout(w)});if(!a.ok)return n.warn("upgrade",`Check API returned ${a.status}`),{available:!1};const i=await a.json();return i.code!==0?{available:!1}:i.data}catch(a){return n.warn("upgrade",`Check API error: ${a instanceof Error?a.message:a}`),{available:!1}}}async reportUpgrade(t){const e=this.agentConfigs[0];if(!e)return;const a=`${S(e.wsUrl)}/v1/agent-api/upgrade/report`,i=t.npm_version?t:{...t,...L()};try{await fetch(a,{method:"POST",headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify(i),signal:AbortSignal.timeout(w)})}catch{}}startGuardian(){const t=h(_.base,"bin","upgrade-guardian.sh");if(process.platform==="win32"||!m(t)){n.info("upgrade","Guardian not available on this platform, skipping");return}try{const e=b(t,[],{detached:!0,stdio:"ignore"});e.unref(),o(`guardian started (pid ${e.pid})`)}catch(e){n.warn("upgrade",`Failed to start guardian: ${e instanceof Error?e.message:e}`)}}}export{Q as UpgradeChecker};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as i,readFileSync as s}from"node:fs";import o from"node:path";const c="0.1.0";function l(n=process.env){return a()??t(n.npm_package_version)??c}function a(){for(const n of p())if(i(n))try{const e=JSON.parse(s(n,"utf8")),r=t(e.version);if(r)return r}catch{continue}return null}function p(){return[o.resolve(import.meta.dirname??__dirname,"../../package.json"),o.resolve(process.cwd(),"package.json")]}function t(n){if(typeof n!="string")return null;const e=n.trim();return e===""?null:e}export{l as resolveClientVersion};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o=Object.freeze(["commentary","final_answer"]),t=Object.freeze([]);function n(e){if(!e||!e.trim())return t;const r=e.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);return r.length>0?Object.freeze(r):t}function E(){const e=n(process.env.CODEX_VISIBLE_PHASES);return e.length>0?e:o}const i=E(),S=n(process.env.CODEX_HIDDEN_PHASES);function c(e){if(typeof e!="string")return!0;const r=e.trim().toLowerCase();return r?S.includes(r)?!1:i.includes(r):!0}export{c as isUserVisibleAgentMessagePhase};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class s{limit;entries=[];constructor(t){this.limit=t}append(t){this.entries.push(t),this.entries.length>this.limit&&this.entries.shift()}listAfter(t){return this.entries.filter(e=>e.sequence>t)}}export{s as EventBuffer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readJSONFile as o,writeJSONFileAtomic as t}from"./json-file.js";import{EventBuffer as i}from"./event-buffer.js";import{QuotedMessageStream as m}from"./quoted-message-stream.js";import{resolveClientVersion as l}from"./client-version.js";import{isUserVisibleAgentMessagePhase as x}from"./codex-output-policy.js";export{i as EventBuffer,m as QuotedMessageStream,x as isUserVisibleAgentMessagePhase,o as readJSONFile,l as resolveClientVersion,t as writeJSONFileAtomic};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{chmod as i,rename as c,writeFile as m}from"node:fs/promises";import{existsSync as a,readFileSync as u}from"node:fs";import{randomUUID as p}from"node:crypto";function f(t){if(!a(t))return null;try{return JSON.parse(u(t,"utf8"))}catch{return null}}async function y(t,o,e){const r=e?.mode??384,n=`${t}.${p()}.tmp`;await m(n,`${JSON.stringify(o,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:r}),await c(n,t);try{await i(t,r)}catch{}}export{f as readJSONFile,y as writeJSONFileAtomic};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function n(r){return String(r??"").trim()}export{n as normalizeString};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
const r="[[quoted_message_id:";class n{mode="pending";buffer="";quotedMessageId;consume(e){if(!e)return{deltaContent:"",quotedMessageId:this.quotedMessageId};if(this.mode==="streaming")return{deltaContent:e,quotedMessageId:this.quotedMessageId};this.buffer+=e;const t=this.tryParseBuffer();return t.status==="need_more"?{deltaContent:"",quotedMessageId:this.quotedMessageId}:(this.mode="streaming",this.buffer="",t.status==="matched"?(this.quotedMessageId=t.quotedMessageId,{deltaContent:t.remainingContent,quotedMessageId:this.quotedMessageId}):{deltaContent:t.remainingContent,quotedMessageId:this.quotedMessageId})}flush(){if(this.mode==="streaming"||!this.buffer)return{deltaContent:"",quotedMessageId:this.quotedMessageId};const e=this.buffer;return this.buffer="",this.mode="streaming",{deltaContent:e,quotedMessageId:this.quotedMessageId}}getQuotedMessageId(){return this.quotedMessageId}tryParseBuffer(){if(!this.buffer.startsWith("[["))return{status:"plain_text",remainingContent:this.buffer};if(!r.startsWith(this.buffer)&&!this.buffer.startsWith(r))return{status:"plain_text",remainingContent:this.buffer};if(r.startsWith(this.buffer))return{status:"need_more"};const e=this.buffer.indexOf("]]",r.length);if(e<0)return{status:"need_more"};const t=this.buffer.slice(r.length,e).trim();if(!t)return{status:"plain_text",remainingContent:this.buffer};let s=this.buffer.slice(e+2);return s.startsWith(`\r
|
|
2
|
+
`)?s=s.slice(2):s.startsWith(`
|
|
3
|
+
`)&&(s=s.slice(1)),{status:"matched",quotedMessageId:t,remainingContent:s}}}export{n as QuotedMessageStream};
|
package/dist/grix.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import g from"node:path";import{writeFileSync as P}from"node:fs";import{Manager as R}from"./manager.js";import{ensureGrixDirs as $,initLogger as y,log as i}from"./core/log/index.js";import{HealthServer as T}from"./core/runtime/index.js";import{writePidFile as F,removePidFile as d}from"./core/runtime/index.js";import{resolveRuntimePaths as w}from"./core/config/index.js";import{ServiceManager as I}from"./service/service-manager.js";import{acquireDaemonLock as N,releaseDaemonLock as u}from"./runtime/daemon-lock.js";import{writeDaemonStatus as D,removeDaemonStatus as O}from"./runtime/service-state.js";const n=process.argv.slice(2),E=[],a={};for(let t=0;t<n.length;t++)n[t].startsWith("--")&&n[t+1]&&!n[t+1].startsWith("--")?(a[n[t].slice(2)]=n[t+1],t++):n[t].startsWith("--")?a[n[t].slice(2)]="true":E.push(n[t]);a.help&&(console.log(`grix-connector \u2014 Unified AI Agent Bridge
|
|
3
|
+
|
|
4
|
+
Usage: grix-connector <command> [options]
|
|
5
|
+
|
|
6
|
+
Commands:
|
|
7
|
+
start Start the daemon as a system service
|
|
8
|
+
stop Stop the daemon service
|
|
9
|
+
restart Restart the daemon service
|
|
10
|
+
status Show service and daemon status
|
|
11
|
+
|
|
12
|
+
Options:
|
|
13
|
+
--config-dir <path> Config directory (default: ~/.grix/config)
|
|
14
|
+
--profile <name> Profile name for config subdirectory
|
|
15
|
+
--health-port <port> Health check port (default: 19579)
|
|
16
|
+
--help Show this help message
|
|
17
|
+
|
|
18
|
+
Platform services:
|
|
19
|
+
macOS: launchd (LaunchAgent)
|
|
20
|
+
Linux: systemd --user
|
|
21
|
+
Windows: Task Scheduler (hidden WScript launcher)
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
grix-connector start # Start as system service
|
|
25
|
+
grix-connector status # Check service status
|
|
26
|
+
grix-connector restart # Restart the service
|
|
27
|
+
`),process.exit(0));const m=E[0],x=["start","stop","restart","status"];if(m&&x.includes(m)){const t=w(),l=a["config-dir"]??(a.profile?g.join(t.configDir,a.profile):void 0),c=g.resolve(process.argv[1]||`${t.rootDir}/dist/grix.js`),e=new I({cliPath:c,nodePath:process.execPath});try{let r;switch(m){case"start":(await e.status({rootDir:t.rootDir})).installed?r=await e.start({rootDir:t.rootDir}):r=await e.install({rootDir:t.rootDir,configDir:l});break;case"stop":r=await e.stop({rootDir:t.rootDir});break;case"restart":(await e.status({rootDir:t.rootDir})).installed?r=await e.restart({rootDir:t.rootDir}):r=await e.install({rootDir:t.rootDir,configDir:l});break;case"status":r=await e.status({rootDir:t.rootDir});break}console.log(JSON.stringify(r,null,2)),process.exit(0)}catch(r){console.error(`${m} failed: ${r instanceof Error?r.message:r}`),process.exit(1)}}else m&&(console.error(`Unknown command: ${m}
|
|
28
|
+
Valid commands: ${x.join(", ")}`),process.exit(1));const s=w(),A=a["config-dir"]??(a.profile?`${s.configDir}/${a.profile}`:void 0),S=new R,p=new T;let v=!1;async function f(t){if(v)return;v=!0,i.info("main",`Received ${t}, shutting down...`),p.markShuttingDown();const l=setTimeout(()=>{i.error("main","Shutdown timed out, forcing exit"),u(s.daemonLockFile).catch(()=>{}),d(),process.exit(2)},1e4);try{await S.stop(),await p.stop(),await u(s.daemonLockFile),await O(s.daemonStatusFile).catch(()=>{}),clearTimeout(l),d(),i.info("main","Shutdown complete"),process.exit(0)}catch(c){i.error("main",`Shutdown error: ${c}`),u(s.daemonLockFile).catch(()=>{}),d(),process.exit(2)}}async function L(){$(),y();try{await N(s.daemonLockFile,s.rootDir)}catch(o){console.error(o instanceof Error?o.message:o),process.exit(1)}F(),i.info("main",`grix-connector starting (PID ${process.pid})`),await D(s.daemonStatusFile,{state:"starting",pid:process.pid,updated_at:Date.now()});const t=parseInt(a["health-port"]??process.env.GRIX_HEALTH_PORT??"19579",10);await p.start(t);const l=g.join(s.dataDir,"health-port");P(l,String(t),"utf-8"),process.on("SIGINT",()=>f("SIGINT")),process.on("SIGTERM",()=>f("SIGTERM"));let c="",e=0,r;process.on("uncaughtException",o=>{const h=o instanceof Error?o.stack??o.message:String(o);h===c?(e++,(e<=3||e%100===0)&&i.error("main",`Uncaught exception (x${e}): ${h}`)):(e>3&&i.error("main",`Previous exception repeated ${e} times total`),c=h,e=1,i.error("main",`Uncaught exception: ${o instanceof Error?o.stack:o}`),r||(r=setTimeout(()=>{e>3&&i.error("main",`Previous exception repeated ${e} times total`),c="",e=0,r=void 0},1e4).unref())),!k(o)&&f("uncaughtException")}),process.on("unhandledRejection",o=>{i.error("main",`Unhandled rejection: ${o}`),!k(o)&&f("unhandledRejection")}),p.setStatusProvider(()=>S.getAgentsStatus()),await S.start(A),await D(s.daemonStatusFile,{state:"running",pid:process.pid,updated_at:Date.now()}),process.send&&process.send("ready"),i.info("main","grix-connector ready")}L().catch(t=>{i.error("main",`Fatal: ${t}`),u(s.daemonLockFile).catch(()=>{}),d(),process.exit(1)});const C=new Set(["ECONNRESET","ECONNREFUSED","ETIMEDOUT","EPIPE","EAI_AGAIN","ENOTFOUND","EHOSTUNREACH","ENETUNREACH","EIO"]);function k(t){return t instanceof Error&&"code"in t?C.has(t.code):!1}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{JsonRpcTransport as t}from"./core/transport/index.js";import{AcpClient as i}from"./protocol/index.js";import{AgentProcess as l}from"./agent/index.js";import{AgentEventType as p}from"./types/index.js";import{AibotClient as s}from"./core/aibot/index.js";import{AgentInstance as A}from"./bridge/index.js";import{CodexAdapter as S}from"./adapter/codex/index.js";import{Manager as E}from"./manager.js";import{GRIX_PATHS as I,ensureGrixDirs as T,initLogger as O,log as d}from"./core/log/index.js";import{HealthServer as u,writePidFile as c,removePidFile as C}from"./core/runtime/index.js";import{readJSONFile as N,writeJSONFileAtomic as v,EventBuffer as P,QuotedMessageStream as M}from"./core/util/index.js";import{SafeMarkdownStreamSegmenter as G}from"./core/text-segmentation/index.js";import{AllowlistGate as w,readAllowlist as y,writeAllowlist as H}from"./core/access/index.js";import{ConversationLog as h,DEFAULT_LOG_MAX_BYTES as k,DEFAULT_LOG_MAX_FILES as D,LOG_MAX_BYTES_ENV as B,LOG_MAX_FILES_ENV as U,resolveLogRotationOptions as V}from"./core/log/index.js";import{TOOLS as Y,toolCallToInvoke as q}from"./core/mcp/index.js";import{resolveRuntimePaths as Q,ensureRuntimeDirs as j,GRIX_HOME_ENV as z,DEFAULT_GRIX_HOME as W}from"./core/config/index.js";import{splitTextForAibotProtocol as $,resolveOutboundTextChunkLimit as ee,uploadReplyFileToAgentMedia as oe,resolveAgentAPIPresignURL as te}from"./core/protocol/index.js";import{CHANNEL_NAME as ie,INTERACTION_KINDS as ne,LOCAL_ACTION_TYPES as le,SESSION_CONTROL_VERBS as ae}from"./adapter/claude/protocol-contract.js";import{buildInteractionRequestInvokeParams as me,buildPermissionInteractionPayload as se,buildElicitationInteractionPayload as xe,parseInteractionReplyAction as Ae,buildInteractionReplyResult as fe}from"./adapter/claude/interaction-protocol.js";import{ChannelContextStore as _e,extractLatestGrixChannelTag as Ee,resolveHookChannelContext as Le}from"./core/context/index.js";import{HookSignalStore as Te}from"./core/hooks/index.js";import{ElicitationStore as de}from"./core/persistence/elicitation-store.js";import{ActivityStatusManager as ue}from"./adapter/claude/activity-status-manager.js";export{i as AcpClient,ue as ActivityStatusManager,p as AgentEventType,A as AgentInstance,l as AgentProcess,s as AibotClient,w as AllowlistGate,ie as CHANNEL_NAME,_e as ChannelContextStore,S as CodexAdapter,h as ConversationLog,W as DEFAULT_GRIX_HOME,k as DEFAULT_LOG_MAX_BYTES,D as DEFAULT_LOG_MAX_FILES,de as ElicitationStore,P as EventBuffer,z as GRIX_HOME_ENV,I as GRIX_PATHS,u as HealthServer,Te as HookSignalStore,ne as INTERACTION_KINDS,t as JsonRpcTransport,le as LOCAL_ACTION_TYPES,B as LOG_MAX_BYTES_ENV,U as LOG_MAX_FILES_ENV,E as Manager,M as QuotedMessageStream,ae as SESSION_CONTROL_VERBS,G as SafeMarkdownStreamSegmenter,Y as TOOLS,xe as buildElicitationInteractionPayload,fe as buildInteractionReplyResult,me as buildInteractionRequestInvokeParams,se as buildPermissionInteractionPayload,T as ensureGrixDirs,j as ensureRuntimeDirs,Ee as extractLatestGrixChannelTag,O as initLogger,d as log,Ae as parseInteractionReplyAction,y as readAllowlist,N as readJSONFile,C as removePidFile,te as resolveAgentAPIPresignURL,Le as resolveHookChannelContext,V as resolveLogRotationOptions,ee as resolveOutboundTextChunkLimit,Q as resolveRuntimePaths,$ as splitTextForAibotProtocol,q as toolCallToInvoke,oe as uploadReplyFileToAgentMedia,H as writeAllowlist,v as writeJSONFileAtomic,c as writePidFile};
|
package/dist/log.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{createWriteStream as g,mkdirSync as l,existsSync as f}from"node:fs";import{join as i}from"node:path";import{homedir as m}from"node:os";const e=i(m(),".grix"),s={base:e,config:i(e,"config"),log:i(e,"log"),data:i(e,"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),n=i(s.log,`grix-acp-${o}.log`);a=g(n,{flags:"a"})}function c(){return new Date().toISOString().slice(11,19)}const u={info(o,n,...r){const t=`${c()} [${o}] ${n}${r.length?" "+r.map(String).join(" "):""}`;console.log(t),a?.write(t+`
|
|
2
|
+
`)},error(o,n,...r){const t=`${c()} [${o}] ERROR ${n}${r.length?" "+r.map(String).join(" "):""}`;console.error(t),a?.write(t+`
|
|
3
|
+
`)}};export{s as GRIX_PATHS,S as ensureGrixDirs,$ as initLogger,u as log};
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import x from"node:path";import{Manager as E}from"./manager.js";import{ensureGrixDirs as k,initLogger as O,log as a}from"./core/log/index.js";import{HealthServer as I}from"./core/runtime/index.js";import{writePidFile as R,removePidFile as l}from"./core/runtime/index.js";import{resolveRuntimePaths as g}from"./core/config/index.js";import{ServiceManager as T}from"./service/service-manager.js";import{acquireDaemonLock as $,releaseDaemonLock as p}from"./runtime/daemon-lock.js";import{writeDaemonStatus as f,removeDaemonStatus as F}from"./runtime/service-state.js";const n=process.argv.slice(2),m=[],s={};for(let e=0;e<n.length;e++)n[e].startsWith("--")&&n[e+1]&&!n[e+1].startsWith("--")?(s[n[e].slice(2)]=n[e+1],e++):n[e].startsWith("--")?s[n[e].slice(2)]="true":m.push(n[e]);if(s.help&&(console.log(`grix-connector \u2014 Unified AI Agent Bridge
|
|
3
|
+
|
|
4
|
+
Usage: grix-connector [options]
|
|
5
|
+
grix-connector service <action> [options]
|
|
6
|
+
|
|
7
|
+
Actions (service):
|
|
8
|
+
install Install and start as OS service
|
|
9
|
+
start Start the OS service
|
|
10
|
+
stop Stop the OS service
|
|
11
|
+
restart Restart the OS service
|
|
12
|
+
uninstall Uninstall the OS service
|
|
13
|
+
status Show service and daemon status
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
--config-dir <path> Config directory (default: ~/.grix/config)
|
|
17
|
+
--profile <name> Profile name for config subdirectory
|
|
18
|
+
--health-port <port> Health check port (default: 19579)
|
|
19
|
+
--help Show this help message
|
|
20
|
+
|
|
21
|
+
Platform services:
|
|
22
|
+
macOS: launchd (LaunchAgent)
|
|
23
|
+
Linux: systemd --user
|
|
24
|
+
Windows: Task Scheduler
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
grix-connector # Run in foreground
|
|
28
|
+
grix-connector service install # Install as OS service
|
|
29
|
+
grix-connector service status # Check service status
|
|
30
|
+
grix-connector service uninstall # Remove OS service
|
|
31
|
+
`),process.exit(0)),m[0]==="service"){const e=m[1],t=["install","start","stop","restart","uninstall","status"];(!e||!t.includes(e))&&(console.error(`Usage: grix-connector service <${t.join("|")}>`),process.exit(1));const o=g(),w=s["config-dir"]??(s.profile?`${o.configDir}/${s.profile}`:void 0),D=x.resolve(process.argv[1]||`${o.rootDir}/dist/main.js`),c=new T({cliPath:D,nodePath:process.execPath});try{let r;switch(e){case"install":r=await c.install({rootDir:o.rootDir,configDir:w});break;case"start":r=await c.start({rootDir:o.rootDir});break;case"stop":r=await c.stop({rootDir:o.rootDir});break;case"restart":r=await c.restart({rootDir:o.rootDir});break;case"uninstall":r=await c.uninstall({rootDir:o.rootDir});break;case"status":r=await c.status({rootDir:o.rootDir});break}console.log(JSON.stringify(r,null,2)),process.exit(0)}catch(r){console.error(`service ${e} failed: ${r instanceof Error?r.message:r}`),process.exit(1)}}const i=g(),N=s["config-dir"]??(s.profile?`${i.configDir}/${s.profile}`:void 0),h=new E,d=new I;let S=!1;async function u(e){if(S)return;S=!0,a.info("main",`Received ${e}, shutting down...`),d.markShuttingDown();const t=setTimeout(()=>{a.error("main","Shutdown timed out, forcing exit"),p(i.daemonLockFile).catch(()=>{}),l(),process.exit(2)},1e4);try{await h.stop(),await d.stop(),await p(i.daemonLockFile),await F(i.daemonStatusFile).catch(()=>{}),clearTimeout(t),l(),a.info("main","Shutdown complete"),process.exit(0)}catch(o){a.error("main",`Shutdown error: ${o}`),p(i.daemonLockFile).catch(()=>{}),l(),process.exit(2)}}async function P(){k(),O();try{await $(i.daemonLockFile,i.rootDir)}catch(t){console.error(t instanceof Error?t.message:t),process.exit(1)}R(),a.info("main",`grix-connector starting (PID ${process.pid})`),await f(i.daemonStatusFile,{state:"starting",pid:process.pid,updated_at:Date.now()});const e=parseInt(s["health-port"]??process.env.GRIX_HEALTH_PORT??"19579",10);await d.start(e),process.on("SIGINT",()=>u("SIGINT")),process.on("SIGTERM",()=>u("SIGTERM")),process.on("uncaughtException",t=>{a.error("main",`Uncaught exception: ${t instanceof Error?t.stack:t}`),!v(t)&&u("uncaughtException")}),process.on("unhandledRejection",t=>{a.error("main",`Unhandled rejection: ${t}`),!v(t)&&u("unhandledRejection")}),d.setStatusProvider(()=>h.getAgentsStatus()),await h.start(N),await f(i.daemonStatusFile,{state:"running",pid:process.pid,updated_at:Date.now()}),process.send&&process.send("ready"),a.info("main","grix-connector ready")}P().catch(e=>{a.error("main",`Fatal: ${e}`),p(i.daemonLockFile).catch(()=>{}),l(),process.exit(1)});const A=new Set(["ECONNRESET","ECONNREFUSED","ETIMEDOUT","EPIPE","EAI_AGAIN","ENOTFOUND","EHOSTUNREACH","ENETUNREACH"]);function v(e){return e instanceof Error&&"code"in e?A.has(e.code):!1}
|
package/dist/manager.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFileSync as M,readdirSync as q}from"node:fs";import{join as A}from"node:path";import{AgentInstance as j}from"./bridge/bridge.js";import{GRIX_PATHS as x,log as l}from"./core/log/index.js";import{resolveClientVersion as I}from"./core/util/client-version.js";import{UpgradeChecker as D}from"./core/upgrade/upgrade-checker.js";import{AgentGlobalConfigStore as E}from"./core/persistence/agent-global-config-store.js";import{scanSkills as H}from"./adapter/claude/skill-scanner.js";const P=8e3;function Q(e){switch(e){case"claude":return{adapterType:"claude",command:"claude"};case"codex":return{adapterType:"codex",command:"codex",options:{sandboxMode:"danger-full-access"}};case"gemini":return{adapterType:"acp",command:"gemini",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"qwen":return{adapterType:"acp",command:"qwen",adapterHint:"qwen/base",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"pi":return{adapterType:"pi",command:"pi"};case"cursor":return{adapterType:"cursor",command:"agent"};case"reasonix":return{adapterType:"acp",command:"reasonix",args:["acp"],enableSessionBinding:!0};case"codewhale":return{adapterType:"codewhale",command:"codewhale",enableSessionBinding:!0};case"openhuman":return{adapterType:"openhuman",command:"openhuman-core",enableSessionBinding:!0};case"kiro":return{adapterType:"acp",command:"kiro-cli",args:["acp"],enableSessionBinding:!0};case"opencode":return{adapterType:"opencode",command:"opencode",args:["serve"],enableSessionBinding:!0};default:throw new Error(`Unsupported client_type: ${e}`)}}function L(e){const t=String(e??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||"default";return A(x.data,`session-bindings-${t}.json`)}function B(e){const t=String(e??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||"default";return A(x.data,`active-events-${t}.json`)}function N(...e){const t=[],o=new Set;for(const i of e)for(const d of i??[]){const r=String(d??"").trim(),p=r.toLowerCase();!r||o.has(p)||(o.add(p),t.push(r))}return t.length>0?t:void 0}function U(e,t){const o={claude:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:3e5},codex:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:3e5},cursor:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:18e4},acp:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:3e5},pi:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:3e5},codewhale:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:3e5},openhuman:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:3e5},opencode:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:3e5}},i=o[e]??o.acp;return{maxConcurrent:t?.max_concurrent??i.maxConcurrent??1,maxQueued:t?.max_queued??i.maxQueued??3,queueTimeoutMs:t?.queue_timeout_ms??i.queueTimeoutMs??3e5,cancelableQueued:!0,cancelableRunning:!0}}function R(e){const t=I(),o=String(e.client_type??"").trim().toLowerCase(),i=Q(o),d=String(e.ws_url??"").trim(),r="get_session_usage",p="get_rate_limits",s="get_agent_global_config";if(!e.name?.trim())throw new Error("agent name is required");if(!d)throw new Error(`agent ${e.name}: ws_url is required`);if(!e.agent_id?.trim())throw new Error(`agent ${e.name}: agent_id is required`);if(!e.api_key?.trim())throw new Error(`agent ${e.name}: api_key is required`);const a=i.adapterType,m=a==="acp",f=o==="qwen",c={...i.options??{}},n=a==="codex"?{capabilities:["local_action_v1","agent_invoke"],localActions:["session_control","get_context","set_model","set_mode","set_reasoning_effort","set_sandbox_mode","exec_approve","exec_reject","file_list","create_folder","turn_interrupt","permission_approve","permission_reject","thread_compact",r,p]}:null,u=a==="claude"?{localActions:["session_control","set_mode","set_model","claude_interaction_reply","exec_approve","exec_reject","file_list","create_folder","thread_compact",r,p]}:null,_=f?{capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",r],adapterHint:"qwen/base"}:null,g=a==="pi"?{adapterHint:"pi/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","get_context","file_list","create_folder",r]}:null,h=a==="openhuman"?{adapterHint:"openhuman/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",r]}:null,b=a==="cursor"?{adapterHint:"cursor/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","set_mode","get_context","file_list","create_folder",r,p]}:null,S=a==="codewhale"?{capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",r]}:null,T=a==="opencode"?{adapterHint:"opencode/base",capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",r]}:null,v=m&&!f?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",r]}:null,k=a==="codex"||a==="claude"||o==="gemini"?["session_control","set_model","set_mode"]:void 0,C=[r,p];m&&c.raw_transport===void 0&&(c.raw_transport=o==="gemini"),o==="kiro"&&c.acp_mcp_tools===void 0&&(c.acp_mcp_tools=!1);const $=`${o}/base`,y=a==="claude"?"claude":a==="codex"?"codex":a==="pi"?"pi":o==="kiro"?"kiro":"gemini";let w;try{w=H({mode:y,projectDir:process.cwd()})??void 0,w&&w.length===0&&(w=void 0)}catch{}return{name:e.name,adapterType:a,aibot:{url:d,agentId:e.agent_id,apiKey:e.api_key,clientType:o,clientVersion:t,adapterHint:i.adapterHint??_?.adapterHint??g?.adapterHint??h?.adapterHint??b?.adapterHint??T?.adapterHint??$,capabilities:n?.capabilities??S?.capabilities??g?.capabilities??h?.capabilities??b?.capabilities??T?.capabilities??_?.capabilities??["stream_chunk","local_action_v1","connector_upgrade"],localActions:N(n?.localActions??S?.localActions??u?.localActions??g?.localActions??h?.localActions??b?.localActions??T?.localActions??_?.localActions??v?.localActions??["exec_approve","exec_reject"],k,C,["connector_rollback","connector_upgrade_push",s]),skills:w},agent:{command:i.command,args:i.args,env:void 0},adapterOptions:c,acpAuthMethod:c.auth_method,acpInitialMode:c.initial_mode,acpMcpTools:c.acp_mcp_tools,promptTimeoutMs:e.prompt_timeout_ms,bindingsPath:L(e.name),activeEventStorePath:B(e.name),...i.enableSessionBinding||m?{enableSessionBinding:!0}:{},...i.autoInjectArgs?{autoInjectArgs:i.autoInjectArgs}:{},poolMaxSize:e.pool?.maxSize,poolIdleTimeoutMs:e.pool?.idleTimeoutMs,eventQueue:U(a,e.event_queue),logDir:x.log,providerBaseUrl:e.provider_base_url?.trim()||void 0,providerApiKey:e.provider_api_key?.trim()||void 0}}function z(){const e=process.env.GRIX_AGENT_STARTUP_WAIT_MS,t=Number(e);return Number.isFinite(t)&&t>=500?Math.floor(t):P}class Y{instances=[];upgradeChecker=null;globalConfigStore;async start(t){const o=t??x.config;l.info("manager",`Loading configs from ${o}`),this.globalConfigStore=new E(A(x.data,"agent-global-configs.json")),this.globalConfigStore.load();const i=q(o).filter(s=>s.endsWith(".json")).sort();if(i.length===0)throw new Error(`No config files found in ${o}`);const d=[];let r=0;for(const s of i)try{const a=M(A(o,s),"utf-8"),m=JSON.parse(a);if(Array.isArray(m.agents)){if(m.agents.length===0){l.error("manager",`No agents array found in ${s}`),r++;continue}for(const f of m.agents)try{const c=R(f);d.push({config:c,file:s}),l.info("manager",`Loaded ${c.name} (${c.adapterType??"acp"}) from ${s}`)}catch(c){const n=typeof f?.name=="string"?f.name:"<unknown>";l.error("manager",`Invalid agent config in ${s} (name=${n}): ${c}`),r++}}else l.error("manager",`Unrecognized config format in ${s}`)}catch(a){l.error("manager",`Failed to load ${s}: ${a}`)}let p=0;if(d.length>0){const s=z();l.info("manager",`Starting ${d.length} agent(s), startup wait=${s}ms`);const a=()=>this.upgradeChecker?.triggerCheck(),m=n=>{this.instances=this.instances.filter(u=>u!==n)},f=d.map(({config:n})=>{const u=new j(n,this.globalConfigStore);return u.setUpgradeTrigger(a),this.instances.push(u),{config:n,instance:u,startPromise:u.start()}}),c=await Promise.all(f.map(async n=>{const u=await new Promise(_=>{let g=!1;const h=setTimeout(()=>{g||(g=!0,_({kind:"timeout"}))},s);n.startPromise.then(()=>{g||(g=!0,clearTimeout(h),_({kind:"started"}))}).catch(b=>{g||(g=!0,clearTimeout(h),_({kind:"failed",error:b}))})});return{task:n,outcome:u}}));for(const{task:n,outcome:u}of c)if(u.kind!=="started"){if(u.kind==="failed"){m(n.instance),l.error("manager",`Failed to start ${n.config.name}: ${u.error}`);continue}p++,l.warn("manager",`Startup pending for ${n.config.name}, continue retrying in background`),n.startPromise.then(()=>{l.info("manager",`Delayed start succeeded: ${n.config.name}`)}).catch(_=>{m(n.instance),l.error("manager",`Delayed start failed: ${n.config.name}: ${_}`)})}if(this.instances.length>0){const n=Math.max(0,this.instances.length-p);l.info("manager",`${n}/${d.length} agent(s) running now`)}p>0&&l.warn("manager",`${p} agent(s) still connecting in background`)}if(this.instances.length===0&&d.length>0)throw new Error("All agent configurations failed to start");if(d.length>0){const s=d[0].config;this.upgradeChecker=new D([{apiKey:s.aibot.apiKey,wsUrl:s.aibot.url}]),await this.upgradeChecker.start()}}async stop(){l.info("manager","Stopping all agents..."),this.upgradeChecker?.stop(),await Promise.allSettled(this.instances.map(t=>t.stop())),await this.globalConfigStore?.flush(),this.instances=[],l.info("manager","All stopped")}getAgentsStatus(){return this.instances.map(t=>t.getStatus())}}export{Y as Manager};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import y from"node:http";import i from"node:process";import{TOOLS as h,toolCallToInvoke as N}from"../core/mcp/tools.js";function O(){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 S=O();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 v(n,t){const r=new URL("/api/invoke",S),o=JSON.stringify({action:n,params:t,timeout_ms:15e3});return new Promise((m,e)=>{const s=y.request(r,{method:"POST",headers:{"content-type":"application/json","content-length":Buffer.byteLength(o)}},l=>{const g=[];l.on("data",c=>g.push(c)),l.on("end",()=>{const c=Buffer.concat(g).toString("utf8");try{const d=JSON.parse(c);d.ok?m(d.data??null):e(new Error(d.error??"invoke failed"))}catch{e(new Error(`invalid response: ${c.slice(0,200)}`))}})});s.on("error",l=>e(l)),s.write(o),s.end()})}function w(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:h})}async function E(n){const t=n.params??{},r=String(t.name??""),o=t.arguments??{};if(!h.find(e=>e.name===r))return f(n.id??null,-32602,`Unknown tool: ${r}`);try{const e=N(r,o),s=await v(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 p="";i.stdin.on("data",n=>{p+=n.toString("utf8");const t=p.split(`
|
|
4
|
+
`);p=t.pop()??"";for(const r of t){const o=r.trim();o&&T(o)}}),i.stdin.on("end",()=>{i.exit(0)});async function T(n){let t;try{t=JSON.parse(n)}catch{a(f(null,-32700,"Parse error"));return}try{switch(t.method){case"initialize":a(w(t));return;case"notifications/initialized":return;case"tools/list":a(I(t));return;case"tools/call":a(await E(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
|
+
`)}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import S from"node:http";import R from"node:net";import c from"node:process";import{Server as v}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as A}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as I,ListToolsRequestSchema as x}from"@modelcontextprotocol/sdk/types.js";import{toolCallToInvoke as P,mapToolAlias as k,EXPOSED_TOOLS as L,TOOL_MAP as $,PHASE2_TOOL_NAMES as C}from"../../core/mcp/tools.js";function O(t,e){const r=c.argv.slice(2);for(let n=0;n<r.length;n++)if(r[n]===`--${t}`&&r[n+1])return r[n+1];return c.env[e]||void 0}const w=O("handle-url","GRIX_CONNECTOR_INTERNAL_API")??"";w||(c.stderr.write(`FATAL: --handle-url <url> required (or set GRIX_CONNECTOR_INTERNAL_API)
|
|
3
|
+
`),c.exit(1));const M=parseInt(O("notify-port","GRIX_MCP_NOTIFY_PORT")??"0",10),u=[1e3,2e3,4e3];function Y(t){if(t instanceof Error){const e=t.message;if(e.includes("ECONNREFUSED")||e.includes("ECONNRESET")||e.includes("ETIMEDOUT")||e.includes("socket hang up"))return!0;if(e.includes("invoke timeout"))return!1}return!1}async function y(t,e,r=15e3,n=0){try{return await D(t,e,r)}catch(o){if(n>0&&Y(o)){const i=u[u.length-n]??u[u.length-1];return c.stderr.write(`[grix-stdio] invokeApi retry (${u.length-n+1}/${u.length}) action=${t} after ${i}ms: ${o instanceof Error?o.message:o}
|
|
4
|
+
`),await new Promise(s=>setTimeout(s,i)),y(t,e,r,n-1)}throw o}}function D(t,e,r){const n=new URL(w),o=new URL("/api/invoke",n),i=n.searchParams.get("token")??"";i&&o.searchParams.set("token",i);const s=JSON.stringify({action:t,params:e,timeout_ms:r});return new Promise((l,a)=>{const T=setTimeout(()=>a(new Error("invoke timeout")),r+5e3),h=S.request(o,{method:"POST",headers:{"content-type":"application/json","content-length":Buffer.byteLength(s),...i?{authorization:`Bearer ${i}`}:{}}},m=>{const N=[];m.on("data",f=>N.push(f)),m.on("end",()=>{clearTimeout(T);const f=Buffer.concat(N).toString("utf8");try{const g=JSON.parse(f);g.ok?l(g.data??null):a(new Error(g.error??"invoke failed"))}catch{a(new Error(`invalid response: ${f.slice(0,200)}`))}})});h.on("error",m=>{clearTimeout(T),a(m)}),h.write(s),h.end()})}const p=new v({name:"grix",version:"1.0.0"},{capabilities:{experimental:{"claude/channel":{},"claude/channel/permission":{}},tools:{}},instructions:['Messages arrive as <channel source="grix-claude" chat_id="..." event_id="..." message_id="..." user_id="...">text</channel>.',"IMPORTANT: You MUST use the reply tool to send any response to the user.","Your plain text output is NOT delivered to the chat \u2014 only the reply tool delivers messages.","Always call the reply tool with chat_id, event_id, and your response text.","If you intentionally do not want to send a visible reply, you must call the complete tool with event_id and a final status."].join(" ")});p.setRequestHandler(x,async()=>({tools:L.map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema}))})),p.setRequestHandler(I,async t=>{const e=String(t.params.name??""),r=t.params.arguments??{},n=k(e,r),o=n.name,i=n.args;if(!$.has(e))return{content:[{type:"text",text:`Unknown tool: ${e}`}],isError:!0};try{if(C.has(o)){const a=await y("event_tool_call",{tool_name:o,arguments:i},3e4,0);return{content:[{type:"text",text:typeof a=="string"?a:JSON.stringify(a,null,2)}]}}const s=P(o,i),l=await y(s.action,s.params);return{content:[{type:"text",text:JSON.stringify(l,null,2)}]}}catch(s){const l=s instanceof Error?s.message:String(s);return{content:[{type:"text",text:JSON.stringify({error:l})}],isError:!0}}});let _=!1;const d=[],F=100;async function E(t,e){if(!_){d.push({method:t,params:e}),d.length>F&&d.shift();return}try{await p.notification({method:t,params:e})}catch(r){c.stderr.write(`DISPATCH_ERROR:${t}:${r}
|
|
5
|
+
`)}}async function U(){for(;_&&d.length>0;){const t=d.shift();await E(t.method,t.params)}}function b(t){if(t<=0)return;const e=R.createServer(r=>{let n="";r.on("data",o=>{n+=o.toString("utf8");const i=n.split(`
|
|
6
|
+
`);n=i.pop()??"";for(const s of i){const l=s.trim();if(l)try{const a=JSON.parse(l);a.method&&E(a.method,a.params??{}).catch(()=>{})}catch{}}}),r.on("error",()=>{})});e.listen(t,"127.0.0.1",()=>{c.stderr.write(`NOTIFY_READY:${t}
|
|
7
|
+
`)}),e.on("error",r=>{c.stderr.write(`NOTIFY_ERROR: ${r.message}
|
|
8
|
+
`)})}async function q(){b(M);const t=new A;await p.connect(t),_=!0,c.stderr.write(`[MAIN] MCP connected, ready to dispatch notifications
|
|
9
|
+
`),await U()}q().catch(t=>{c.stderr.write(`FATAL: ${t}
|
|
10
|
+
`),c.exit(1)});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as n from"node:net";const i={bind:"127.0.0.1",port:0,endpoint:"/mcp",sessionTimeoutMs:18e5,invokeTimeoutMs:3e4};function s(u){const e={bind:u?.bind??i.bind,port:u?.port??i.port,endpoint:u?.endpoint??i.endpoint,sessionTimeoutMs:u?.sessionTimeoutMs??i.sessionTimeoutMs,invokeTimeoutMs:u?.invokeTimeoutMs??i.invokeTimeoutMs,allowedOrigins:u?.allowedOrigins,allowedHosts:u?.allowedHosts};return t(e.bind),e.port!==0&&o(e.port),r(e.sessionTimeoutMs),e}function t(u){if(!u||!n.isIPv4(u)&&!n.isIPv6(u))throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: bind \u5730\u5740 "${u}" \u4E0D\u662F\u5408\u6CD5\u7684 IPv4 \u6216 IPv6 \u5730\u5740`)}function o(u){if(!Number.isInteger(u)||u<1||u>65535)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: port \u503C ${u} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1-65535 \u5185\u6216\u4E0D\u662F\u6574\u6570`)}function r(u){if(!Number.isInteger(u)||u<1e3||u>864e5)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: session_timeout_ms \u503C ${u} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1000-86400000 \u5185`)}export{s as createDefaultGatewayConfig};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const a=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};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{splitTextForAibotProtocol as v}from"../../core/protocol/protocol-text.js";const d=new Set(["grix_reply","grix_complete","grix_event_ack","grix_composing","grix_access_control","grix_status"]);function g(n){return d.has(n)}function p(n,e,t){switch(e){case"grix_reply":return f(n,t);case"grix_complete":return x(n,t);case"grix_event_ack":return C(n,t);case"grix_composing":return S(n,t);case"grix_access_control":return m(n,t);case"grix_status":return y(n);default:return r(`\u672A\u77E5\u4E8B\u4EF6\u5DE5\u5177: ${e}`)}}function f(n,e){const t=String(e.event_id??""),s=String(e.session_id??""),i=String(e.text??""),a=e.quoted_message_id,l=e.is_final===!0;if(!s)return r("\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: session_id");if(!i)return r("\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: text");const _=v(i),c=`reply_${t||"proactive"}_${Date.now()}`;for(let o=0;o<_.length;o++)n.sendStreamChunk({event_id:t||void 0,session_id:s,delta_content:_[o],chunk_seq:o+1,is_finish:!1,client_msg_id:c,quoted_message_id:o===0?a:void 0});return n.sendStreamChunk({event_id:t||void 0,session_id:s,delta_content:"",chunk_seq:_.length+1,is_finish:!0,client_msg_id:c}),l&&t&&n.sendEventResult({event_id:t,status:"responded"}),u({ok:!0,chunks:_.length,client_msg_id:c})}function x(n,e){const t=String(e.event_id??""),s=String(e.status??""),i=e.msg;return t?["responded","canceled","failed"].includes(s)?(n.sendEventResult({event_id:t,status:s,msg:i}),u({ok:!0,event_id:t,status:s})):r("status \u5FC5\u987B\u4E3A responded\u3001canceled \u6216 failed"):r("\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: event_id")}function C(n,e){const t=String(e.event_id??""),s=e.session_id;return t?(n.sendEventAck({event_id:t,session_id:s,received_at:Date.now()}),u({ok:!0,event_id:t})):r("\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: event_id")}function S(n,e){const t=String(e.session_id??""),s=e.active===!0,i=e.event_id;return t?(n.sendSessionActivitySet({session_id:t,kind:"composing",active:s,ref_event_id:i,ttl_ms:s?3e4:void 0}),u({ok:!0,session_id:t,active:s})):r("\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: session_id")}function m(n,e){const t=String(e.action??""),s={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"}[t];if(!s)return r(`\u672A\u77E5 access_control action: ${t}`);const i={};return e.code!=null&&(i.code=e.code),e.sender_id!=null&&(i.sender_id=e.sender_id),e.policy!=null&&(i.policy=e.policy),{content:[{type:"text",text:"__ASYNC_ACCESS_CONTROL__"}],_async:{verb:s,payload:i}}}function y(n){const e=n.status,t=n.getStatusSnapshot();return u({connected:e==="ready",status:e,connected_at:t.connectedAt})}function u(n){return{content:[{type:"text",text:JSON.stringify(n)}],isError:!1}}function r(n){return{content:[{type:"text",text:n}],isError:!0}}export{d as EVENT_TOOL_NAMES,p as executeEventTool,g as isEventTool};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createServer as N}from"node:http";import{Server as O}from"@modelcontextprotocol/sdk/server/index.js";import{StreamableHTTPServerTransport as j}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{ListToolsRequestSchema as R,CallToolRequestSchema as E}from"@modelcontextprotocol/sdk/types.js";import{createSecurityPolicy as h}from"./security.js";import{SessionManagerImpl as A}from"./session-manager.js";import{ToolRegistryImpl as C}from"./tool-registry.js";import{ToolExecutorImpl as J}from"./tool-executor.js";function q(n,r){let a=null,p=!1,m,c;const S=new C,v=new J;let s=null;return{async start(){m=h({serverPort:n.port,allowedOrigins:n.allowedOrigins??[],allowedHosts:n.allowedHosts??[]}),c=new A({maxSessions:1,sessionTimeoutMs:n.sessionTimeoutMs,onSessionExpired:e=>{w(e)}}),a=N((e,t)=>{g(e,t)}),await new Promise((e,t)=>{a.on("error",t),a.listen(n.port,n.bind,()=>{a.removeListener("error",t),p=!0;const i=a.address();i&&typeof i=="object"&&(n.port=i.port,m=h({serverPort:n.port,allowedOrigins:n.allowedOrigins??[],allowedHosts:n.allowedHosts??[]})),e()})})},async stop(){if(p=!1,a&&(await new Promise(e=>{a.close(()=>e())}),a=null),s){try{await s.transport.close()}catch{}try{await s.mcpServer.close()}catch{}s=null}c&&(await c.closeAll(),c.dispose())},getStatus(){return{listening:p,url:`http://${n.bind}:${n.port}${n.endpoint}`,activeSessions:s?1:0}},pushEvent(e){s&&y(s.mcpServer,"notifications/message",{event_id:e.event_id,session_id:e.session_id,sender_id:e.sender_id??"",content:e.content,msg_type:e.msg_type??1,msg_id:e.msg_id??"",session_type:e.session_type??1,quoted_message_id:e.quoted_message_id??"",attachments:e.attachments??[],context_messages:e.context_messages??[]},s.transport)},pushStop(e){s&&y(s.mcpServer,"notifications/event_stop",{event_id:e.event_id,stop_id:e.stop_id,session_id:e.session_id,reason:e.reason??""},s.transport)},pushRevoke(e){s&&y(s.mcpServer,"notifications/event_revoke",{event_id:e.event_id,session_id:e.session_id,reason:e.reason??""},s.transport)},pushLocalAction(e){s&&y(s.mcpServer,"notifications/local_action",e,s.transport)}};async function g(e,t){if(new URL(e.url??"/",`http://${e.headers.host??"localhost"}`).pathname!==n.endpoint){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not Found"}));return}const i=m.validateRequest(e);if(!i.ok){t.writeHead(i.statusCode??403,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:i.message}));return}const o=e.method?.toUpperCase();if(o==="GET"){const d=f(e);if(!d||!s||s.sessionId!==d){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Bad Request: missing or invalid session"}));return}c.touchActivity(d),await s.transport.handleRequest(e,t);return}if(o==="DELETE"){await x(e,t);return}if(o==="POST"){await _(e,t);return}t.writeHead(405,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Method Not Allowed"}))}async function _(e,t){const i=await b(e);let o;try{o=JSON.parse(i)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON body"}));return}const d=I(o),l=e.headers.accept??"";if(!l.includes("application/json")||!l.includes("text/event-stream")){t.writeHead(406,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not Acceptable: Accept header must include both application/json and text/event-stream"}));return}if(d)await T(e,t,o);else{const u=f(e);if(!u){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Bad Request: missing Mcp-Session-Id header"}));return}if(!s||s.sessionId!==u){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not Found: session does not exist or has expired"}));return}c.touchActivity(u),await s.transport.handleRequest(e,t,o)}}async function T(e,t,i){if(s){t.writeHead(503,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Service Unavailable: gateway already has an active session"}));return}const o=c.createSession().sessionId,d=new j({sessionIdGenerator:()=>o,enableJsonResponse:!1,onsessioninitialized:()=>{},onsessionclosed:()=>{w(o)}}),l=new O({name:"grix-mcp-server",version:"1.0.0"},{capabilities:{tools:{}}});H(l,o),await l.connect(d),s={transport:d,mcpServer:l,sessionId:o},await d.handleRequest(e,t,i);try{c.markReady(o)}catch{}}async function x(e,t){const i=f(e);if(!i){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Bad Request: missing Mcp-Session-Id header"}));return}if(!s||s.sessionId!==i){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not Found: session does not exist or has expired"}));return}await s.transport.handleRequest(e,t)}function H(e,t){const i=S.getTools();e.setRequestHandler(R,async()=>({tools:i.map(o=>({name:o.name,description:o.description,inputSchema:o.inputSchema}))})),e.setRequestHandler(E,async o=>{const{name:d,arguments:l}=o.params,u=c.getSession(t);return!u||u.state!=="ready"?{content:[{type:"text",text:`Session \u72B6\u6001\u4E0D\u53EF\u7528: ${u?.state??"unknown"}`}],isError:!0}:r.status!=="ready"?{content:[{type:"text",text:`\u8FDE\u63A5\u4E0D\u53EF\u7528: \u5F53\u524D\u72B6\u6001\u4E3A ${r.status}`}],isError:!0}:(c.touchActivity(t),v.execute(r,d,l??{},n.invokeTimeoutMs))})}async function w(e){if(s?.sessionId===e){try{await s.mcpServer.close()}catch{}s=null}try{await c.closeSession(e)}catch{}}}function y(n,r,a,p){return p?p.send({jsonrpc:"2.0",method:r,params:a}):Promise.resolve()}function f(n){const r=n.headers["mcp-session-id"];return Array.isArray(r)?r[0]:r||void 0}function I(n){return n&&typeof n=="object"&&"method"in n?n.method==="initialize":Array.isArray(n)?n.some(r=>r&&typeof r=="object"&&r.method==="initialize"):!1}function b(n){return new Promise((r,a)=>{const p=[];n.on("data",m=>p.push(m)),n.on("end",()=>r(Buffer.concat(p).toString("utf-8"))),n.on("error",a)})}export{q as createMcpGateway};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createMcpGateway as a}from"./gateway.js";import{createSecurityPolicy as e}from"./security.js";import{SessionManagerImpl as r}from"./session-manager.js";import{createDefaultGatewayConfig as t}from"./config.js";export{r as SessionManagerImpl,t as createDefaultGatewayConfig,a as createMcpGateway,e as createSecurityPolicy};
|