@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.
@@ -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
- return await request(rec,'tools/call',{name,arguments:args},timeout(ctx));
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.12'}});
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:12000},13000);
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){
@@ -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>30000)return invalid();
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');
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.4.12",
6
+ "version": "0.4.13",
7
7
  "type": "module",
8
8
  "description": "Chat Loop local tools: MCP gateway, isolated bundled tunnel-client and unified CLI",
9
9
  "bin": {