@tomflow/chatloop-tools 0.4.12 → 0.4.13
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/lib/adapters/mcp-child.mjs +4 -2
- package/lib/control.mjs +5 -0
- package/lib/gateway.mjs +4 -3
- package/lib/supervisor.mjs +1 -1
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import {createRequire} from 'node:module';
|
|
|
3
3
|
import {dirname,join} from 'node:path';
|
|
4
4
|
import {mkdirSync,readFileSync} from 'node:fs';
|
|
5
5
|
import {randomUUID} from 'node:crypto';
|
|
6
|
-
import {paths} from '../control.mjs';
|
|
6
|
+
import {paths,toolCallDeadlineMs} from '../control.mjs';
|
|
7
7
|
|
|
8
8
|
const require=createRequire(import.meta.url);
|
|
9
9
|
const catalog=JSON.parse(readFileSync(new URL('../desktop-commander-tools.json',import.meta.url),'utf8'));
|
|
@@ -131,7 +131,9 @@ export function createMcpChildAdapter({records,log}){
|
|
|
131
131
|
if(!catalog.some(t=>t.name===name))throw Object.assign(Error('No such tool'),{code:'UNKNOWN_TOOL'});
|
|
132
132
|
rec.active++;
|
|
133
133
|
try{
|
|
134
|
-
|
|
134
|
+
// Leave time for IPC and Gateway acknowledgements; never exceed the caller's deadline.
|
|
135
|
+
const ms=Math.max(0,Math.min(ctx.remaining(),toolCallDeadlineMs(args)-2000));
|
|
136
|
+
return await request(rec,'tools/call',{name,arguments:args},ms);
|
|
135
137
|
}catch(e){if(e.code==='TIMEOUT')rec.state='UNKNOWN';throw e;}
|
|
136
138
|
finally{rec.active--;}
|
|
137
139
|
}
|
package/lib/control.mjs
CHANGED
|
@@ -5,6 +5,11 @@ import {join} from 'node:path';
|
|
|
5
5
|
|
|
6
6
|
export const CONTRACT = 'chat-loop.local-control.v1';
|
|
7
7
|
export const VERSION = '0.4.7';
|
|
8
|
+
// Bounded end-to-end tool calls: long-running Desktop Commander operations may wait up to timeout_ms.
|
|
9
|
+
export const toolCallDeadlineMs = args => {
|
|
10
|
+
const requested = Number.isSafeInteger(args?.timeout_ms) && args.timeout_ms > 0 ? args.timeout_ms : 0;
|
|
11
|
+
return Math.min(42000, Math.max(12000, requested + 8000));
|
|
12
|
+
};
|
|
8
13
|
export const ACTIONS = new Set(['start','stop','restart','status']);
|
|
9
14
|
export const directory = () => process.env.CHAT_LOOP_LOCAL_TOOLS_STATE_DIR || join(homedir(), '.chat-loop', 'local-tools');
|
|
10
15
|
export const paths = () => ({dir: directory(), socket: join(directory(), 'control.sock'), lock: join(directory(), 'manager.lock'), log: join(directory(), 'events.jsonl')});
|
package/lib/gateway.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Stdio MCP entrypoint: protocol framing and routing only; never owns child processes.
|
|
2
2
|
import {randomUUID} from 'node:crypto';
|
|
3
3
|
import {readFileSync} from 'node:fs';
|
|
4
|
-
import {CONTRACT,registry,talk} from './control.mjs';
|
|
4
|
+
import {CONTRACT,registry,talk,toolCallDeadlineMs} from './control.mjs';
|
|
5
5
|
import {extensionTools,forwardExtensionAction} from './extension-proxy.mjs';
|
|
6
6
|
|
|
7
7
|
const desktopTools=JSON.parse(readFileSync(new URL('./desktop-commander-tools.json',import.meta.url),'utf8'));
|
|
@@ -46,7 +46,7 @@ export function runGateway(){
|
|
|
46
46
|
return reject(m.id,-32602,'UNSUPPORTED_MCP_VERSION');
|
|
47
47
|
connected=true;
|
|
48
48
|
return reply(m.id,{protocolVersion:m.params.protocolVersion,
|
|
49
|
-
capabilities:{tools:{}},serverInfo:{name:'chat-loop-local-tools',version:'0.4.
|
|
49
|
+
capabilities:{tools:{}},serverInfo:{name:'chat-loop-local-tools',version:'0.4.13'}});
|
|
50
50
|
}
|
|
51
51
|
// A modern MCP client probes discovery before falling back to legacy initialize.
|
|
52
52
|
// We only implement the legacy handshake era, so report unsupported method.
|
|
@@ -63,8 +63,9 @@ export function runGateway(){
|
|
|
63
63
|
try{
|
|
64
64
|
if(routed.toolId==='chat-loop-extension')
|
|
65
65
|
return reply(m.id,await forwardExtensionAction(routed.name,args));
|
|
66
|
+
const deadlineMs=toolCallDeadlineMs(args);
|
|
66
67
|
const res=await talk({contract:CONTRACT,requestId:randomUUID(),action:'call',
|
|
67
|
-
scope:'tool',toolId:routed.toolId,name:routed.name,args,deadlineMs
|
|
68
|
+
scope:'tool',toolId:routed.toolId,name:routed.name,args,deadlineMs},deadlineMs+2000);
|
|
68
69
|
if(res.status!=='OK')return reply(m.id,failure(res.error?.code||'TOOL_UNAVAILABLE'));
|
|
69
70
|
return reply(m.id,res.result);
|
|
70
71
|
}catch(e){
|
package/lib/supervisor.mjs
CHANGED
|
@@ -40,7 +40,7 @@ async function executeCall(req){
|
|
|
40
40
|
if(typeof req.requestId!=='string'||req.requestId.length<6||req.requestId.length>128||
|
|
41
41
|
req.scope!=='tool'||typeof req.toolId!=='string'||typeof req.name!=='string'||
|
|
42
42
|
!req.args||typeof req.args!=='object'||Array.isArray(req.args)||
|
|
43
|
-
!Number.isInteger(req.deadlineMs)||req.deadlineMs<1000||req.deadlineMs>
|
|
43
|
+
!Number.isInteger(req.deadlineMs)||req.deadlineMs<1000||req.deadlineMs>45000)return invalid();
|
|
44
44
|
const tool=catalog.find(t=>t.id===req.toolId);
|
|
45
45
|
if(!tool)return bad(req,'UNKNOWN_TOOL');
|
|
46
46
|
if(!tool.enabled)return bad(req,'DISABLED_TOOL');
|