@tomflow/chatloop-tools 0.4.14 → 0.4.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/extension-proxy.mjs +25 -3
- package/package.json +1 -1
package/lib/extension-proxy.mjs
CHANGED
|
@@ -17,6 +17,10 @@ export const extensionTools=[
|
|
|
17
17
|
extensionTool('clean','Clear composer text in one exact verified ChatGPT tab; never sends.',false,
|
|
18
18
|
{tabId:{type:'integer',minimum:1}},['tabId']),
|
|
19
19
|
extensionTool('reload','Request reload of Chat Loop Extension; final health is unverified.',false),
|
|
20
|
+
extensionTool('status','Read the unique current Mac Chrome Web Chat Owner; never starts or sends.',true),
|
|
21
|
+
extensionTool('start','After confirmed intent and preflight, ask Extension to start one unique Web Chat; fails if any task owns it.',false,
|
|
22
|
+
{projectId:{type:'string',minLength:1,maxLength:128},prompt:{type:'string',minLength:1,maxLength:4000},confirmed:{const:true}},
|
|
23
|
+
['projectId','prompt','confirmed']),
|
|
20
24
|
extensionTool('continue','Submit next-turn text with turnToken and nextPrompt; alternatively query its final status with turnToken and intentId. Only the Extension can send after Turn completion.',false,
|
|
21
25
|
{turnToken:{type:'string'},nextPrompt:{type:'string',minLength:1,maxLength:4000},
|
|
22
26
|
intentId:{type:'string',pattern:'^[a-f0-9]{32}$'},lookup:{type:'boolean'}},['turnToken']),
|
|
@@ -40,6 +44,8 @@ const commands={
|
|
|
40
44
|
chat_dom:['extension','chat','dom'],
|
|
41
45
|
chat_screenshot:['extension','chat','screenshot'],
|
|
42
46
|
reload:['extension','reload'],
|
|
47
|
+
status:['extension','status'],
|
|
48
|
+
start:['extension','start'],
|
|
43
49
|
clean:['extension','clean'],
|
|
44
50
|
continue:['extension','continue'],
|
|
45
51
|
handoff:['extension','handoff']
|
|
@@ -48,13 +54,19 @@ const fail=code=>({isError:true,content:[{type:'text',text:code}]});
|
|
|
48
54
|
export async function forwardExtensionAction(name,args={}) {
|
|
49
55
|
const invocation=extensionInvocation(name);
|
|
50
56
|
if(!invocation||!args||typeof args!=='object'||Array.isArray(args))return fail('INVALID_ARGUMENT');
|
|
51
|
-
const control=['continue','handoff'].includes(name);
|
|
57
|
+
const control=['continue','handoff','start'].includes(name);
|
|
52
58
|
if(name==='clean'){
|
|
53
59
|
if(Object.keys(args).length!==1||!Number.isSafeInteger(args.tabId)||args.tabId<1)
|
|
54
60
|
return fail('INVALID_ARGUMENT');
|
|
55
61
|
invocation.args.push(String(args.tabId));
|
|
56
62
|
}else if(!control && Object.keys(args).length)return fail('INVALID_ARGUMENT');
|
|
57
|
-
if(
|
|
63
|
+
if(name==='start'){
|
|
64
|
+
if(Object.keys(args).some(k=>!['projectId','prompt','confirmed'].includes(k))
|
|
65
|
+
||!(/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/).test(args.projectId||'')
|
|
66
|
+
||typeof args.prompt!=='string'||!args.prompt.trim()||args.prompt.length>4000
|
|
67
|
+
||args.confirmed!==true)return fail('INVALID_ARGUMENT');
|
|
68
|
+
}
|
|
69
|
+
if(control&&name!=='start'){
|
|
58
70
|
const query=Object.hasOwn(args,'intentId')||args.lookup===true;
|
|
59
71
|
if(typeof args.turnToken!=='string' || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(args.turnToken)
|
|
60
72
|
|| Object.keys(args).some(k=>k!=='turnToken' && (query?
|
|
@@ -77,7 +89,7 @@ export async function forwardExtensionAction(name,args={}) {
|
|
|
77
89
|
cwd:tmpdir(),windowsHide:true,env:process.env});
|
|
78
90
|
let stdout='',finished=false;
|
|
79
91
|
const settle=x=>{if(finished)return;finished=true;clearTimeout(timer);resolve(x);};
|
|
80
|
-
const timer=setTimeout(()=>{child.kill('SIGTERM');settle(fail('RESULT_TIMEOUT'));},90000);
|
|
92
|
+
const timer=setTimeout(()=>{child.kill('SIGTERM');settle(fail('RESULT_TIMEOUT'));},name==='start'?125000:90000);
|
|
81
93
|
if(control)child.stdin.end(JSON.stringify(args));
|
|
82
94
|
child.stdout.on('data',b=>{
|
|
83
95
|
stdout+=b.toString();
|
|
@@ -102,6 +114,16 @@ export function formatExtensionResult(name,response) {
|
|
|
102
114
|
return {content:[{type:'text',text:'ACCEPTED_UNVERIFIED: Extension reload requested; healthy restart not confirmed.'}]};
|
|
103
115
|
if(response?.status!=='OK'||response.action!==name||typeof response.path!=='string')
|
|
104
116
|
return fail('INVALID_EXTENSION_RESULT');
|
|
117
|
+
if(['start','status'].includes(name)){
|
|
118
|
+
try{
|
|
119
|
+
const proof=JSON.parse(response.content);
|
|
120
|
+
if(name==='start'){
|
|
121
|
+
if(proof.status!=='OK'||!proof.sessionId||!proof.activeChatId||!proof.activeChatUrl)
|
|
122
|
+
return fail('START_RESULT_UNVERIFIED');
|
|
123
|
+
}else if(!['OK','UNVERIFIED'].includes(proof.status))return fail('STATUS_RESULT_UNVERIFIED');
|
|
124
|
+
return {content:[{type:'text',text:JSON.stringify(proof)}]};
|
|
125
|
+
}catch{return fail('INVALID_SESSION_RESULT');}
|
|
126
|
+
}
|
|
105
127
|
if(['continue','handoff'].includes(name)){
|
|
106
128
|
try {
|
|
107
129
|
const proof=JSON.parse(response.content);
|