shennian 0.3.62 → 0.3.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/publish-build-manifest.json +15 -5
- package/dist/src/native-fusion/codex-files.d.ts +2 -0
- package/dist/src/native-fusion/codex-files.js +1 -0
- package/dist/src/native-fusion/codex-parser.d.ts +1 -2
- package/dist/src/native-fusion/codex-parser.js +3 -5
- package/dist/src/native-fusion/codex-user-input.d.ts +2 -0
- package/dist/src/native-fusion/codex-user-input.js +3 -0
- package/dist/src/native-fusion/service.d.ts +1 -0
- package/dist/src/native-fusion/service.js +2 -2
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"jsMinified": true,
|
|
4
4
|
"minifier": "esbuild",
|
|
5
|
-
"fileCount":
|
|
5
|
+
"fileCount": 130,
|
|
6
6
|
"files": [
|
|
7
7
|
{
|
|
8
8
|
"file": "bin/shennian.js",
|
|
@@ -304,10 +304,20 @@
|
|
|
304
304
|
"beforeBytes": 71949,
|
|
305
305
|
"afterBytes": 36578
|
|
306
306
|
},
|
|
307
|
+
{
|
|
308
|
+
"file": "src/native-fusion/codex-files.js",
|
|
309
|
+
"beforeBytes": 2623,
|
|
310
|
+
"afterBytes": 1339
|
|
311
|
+
},
|
|
307
312
|
{
|
|
308
313
|
"file": "src/native-fusion/codex-parser.js",
|
|
309
|
-
"beforeBytes":
|
|
310
|
-
"afterBytes":
|
|
314
|
+
"beforeBytes": 28010,
|
|
315
|
+
"afterBytes": 11870
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
"file": "src/native-fusion/codex-user-input.js",
|
|
319
|
+
"beforeBytes": 1132,
|
|
320
|
+
"afterBytes": 618
|
|
311
321
|
},
|
|
312
322
|
{
|
|
313
323
|
"file": "src/native-fusion/config.js",
|
|
@@ -346,8 +356,8 @@
|
|
|
346
356
|
},
|
|
347
357
|
{
|
|
348
358
|
"file": "src/native-fusion/service.js",
|
|
349
|
-
"beforeBytes":
|
|
350
|
-
"afterBytes":
|
|
359
|
+
"beforeBytes": 26155,
|
|
360
|
+
"afterBytes": 12343
|
|
351
361
|
},
|
|
352
362
|
{
|
|
353
363
|
"file": "src/native-fusion/session-header.js",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import l from"node:fs";import c from"node:os";import s from"node:path";import{readJsonlLines as f,safeParse as d}from"./parser-common.js";const a=new Set(["untitled","new chat","new conversation","new task","new thread","codex","\u65E0\u6807\u9898","\u672A\u547D\u540D","\u65B0\u4EFB\u52A1","\u65B0\u4F1A\u8BDD","\u65B0\u5BF9\u8BDD"]);function m(t,n){if((typeof t.id=="string"?t.id:typeof t.thread_id=="string"?t.thread_id:typeof t.session_id=="string"?t.session_id:"")!==n)return null;const e=(typeof t.thread_name=="string"?t.thread_name:typeof t.title=="string"?t.title:"").trim();return e&&!u(e)?e.slice(0,120):null}function u(t){const n=t.trim().toLocaleLowerCase().replace(/[\s_-]+/g," ");return a.has(n)}function w(t){if(!t)return null;const n=s.join(c.homedir(),".codex","session_index.jsonl");if(!l.existsSync(n))return null;let i=null;return f(n,0,o=>{if(!o.trim())return;const e=d(o);if(!e)return;const r=m(e,t);r&&(i=r)}),i}function p(){const t=[s.join(c.homedir(),".codex","sessions"),s.join(c.homedir(),".codex","archived_sessions")],n=[],i=o=>{for(const e of l.readdirSync(o,{withFileTypes:!0})){const r=s.join(o,e.name);e.isDirectory()?i(r):e.isFile()&&e.name.endsWith(".jsonl")&&n.push(r)}};for(const o of t)l.existsSync(o)&&i(o);return[...new Set(n)].sort()}export{p as listCodexRolloutFiles,w as lookupCodexThreadName};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ParsedNativeEvent } from './types.js';
|
|
2
|
-
export
|
|
3
|
-
export declare function listCodexRolloutFiles(): string[];
|
|
2
|
+
export { listCodexRolloutFiles, lookupCodexThreadName } from './codex-files.js';
|
|
4
3
|
export declare function parseCodexRolloutChunk(filePath: string, startOffset: number): {
|
|
5
4
|
nextOffset: number;
|
|
6
5
|
events: ParsedNativeEvent[];
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import j from"node:fs";import
|
|
1
|
+
import j from"node:fs";import S from"node:path";import{createHash as X}from"node:crypto";import{buildApprovalPendingPayload as Y,buildUserMessagePayload as R,isSystemControlPayload as M,isToolPayload as W}from"@shennian/wire";import{buildImagePayload as Z,buildToolPayload as P,inferMimeType as $,makeCursor as k,makeEventKey as q,normalizeText as T,parseStructuredString as D,readJsonlLines as K,readTimestamp as O,safeParse as U}from"./parser-common.js";import{lookupCodexThreadName as H}from"./codex-files.js";import{parseCodexDelegationInput as ee,parseCodexTextElements as z}from"./codex-user-input.js";import{listCodexRolloutFiles as Ce,lookupCodexThreadName as ye}from"./codex-files.js";function te(t){if(typeof t=="string"){const s=t.trim();return s?{path:s,name:S.basename(s)||"image.png",mimeType:$(s),kind:"image"}:null}if(typeof t!="object"||t===null)return null;const r=t,n=typeof r.path=="string"?r.path:typeof r.file_path=="string"?r.file_path:typeof r.saved_path=="string"?r.saved_path:"";if(!n.trim())return null;const e=typeof r.name=="string"&&r.name.trim()?r.name:S.basename(n)||"image.png",o=typeof r.mimeType=="string"&&r.mimeType.trim()?r.mimeType:$(n);return{path:n,name:e,mimeType:o,kind:"image"}}function B(t){const r=T(t);if(!r)return{text:"",strippedWrapper:!1};const n=r.match(/My request for Codex:\s*([\s\S]*)$/i);return n&&n[1]?{text:ne(n[1]),strippedWrapper:!0}:{text:r,strippedWrapper:!1}}function ne(t){return T(t.replace(/<image>\s*<\/image>/gi,""))}function F(t){const r=T(t);if(!r)return!1;if(M(r)||/^<environment_context>[\s\S]*<\/environment_context>$/i.test(r)&&r.includes("<current_date>")&&r.includes("<timezone>")&&r.includes("<workspace_roots>"))return!0;const n=r.startsWith("<recommended_plugins>")&&r.includes("</recommended_plugins>"),e=r.includes("# AGENTS.md instructions for ")&&r.includes("<INSTRUCTIONS>")&&r.includes("</INSTRUCTIONS>"),o=r.includes("<environment_context>")&&r.includes("</environment_context>");return e&&o&&(r.startsWith("# AGENTS.md instructions for ")||n)}function L(t){const r=z(t.text_elements),n=Array.isArray(t.input)?z(t.input):"",e=typeof t.message=="string"?B(t.message):{text:"",strippedWrapper:!1},o=e.text,s=r||n||o,u=e.strippedWrapper?"codex_app_context_wrapper":void 0,a=Array.isArray(t.local_images)?t.local_images.map(te).filter(f=>f!=null):[];return!s&&a.length===0||M(s)&&a.length===0||F(s)&&a.length===0?null:a.length>0?{payload:R(s,a),titleText:s,repairHint:u}:{payload:s,titleText:s,repairHint:u}}function re(t){return t==="turn_completed"||t==="turn_complete"||t==="task_complete"}function oe(t){return/approval|permission|confirm|user[_-]?input|input[_-]?required/i.test(t)}function ie(t){const r=typeof t.command=="string"?t.command:Array.isArray(t.command)?t.command.join(" "):"",n=typeof t.prompt=="string"?t.prompt:typeof t.reason=="string"?t.reason:typeof t.message=="string"?t.message:r?`Codex \u8BF7\u6C42\u6267\u884C\u547D\u4EE4\uFF1A${r}`:"Codex \u6B63\u5728\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u540E\u7EE7\u7EED\u3002";return Y({title:"\u9700\u8981\u7528\u6237\u786E\u8BA4",content:n,source:"codex",actionHint:"\u5F53\u524D\u795E\u5FF5\u6682\u4E0D\u652F\u6301\u8FDC\u7A0B\u786E\u8BA4\uFF0C\u8BF7\u56DE\u5230\u8FD0\u884C Codex \u7684\u7535\u8111/\u7EC8\u7AEF\u5B8C\u6210\u786E\u8BA4\u3002"})}function w(t,r){return Array.isArray(t)?T(t.map(n=>{if(typeof n=="string")return n;if(typeof n!="object"||n===null)return"";const e=n;return e.type!==r?"":typeof e.text=="string"?e.text:""}).filter(Boolean).join(`
|
|
2
2
|
|
|
3
|
-
`):""}function
|
|
4
|
-
|
|
5
|
-
`)):""}function ct(t){if(!Array.isArray(t))return[];const r=[];for(const n of t){if(typeof n!="object"||n===null)continue;const e=n;if(e.type!=="input_image")continue;const o=typeof e.path=="string"?e.path:typeof e.file_path=="string"?e.file_path:typeof e.saved_path=="string"?e.saved_path:typeof e.image_path=="string"?e.image_path:"";o.trim()&&r.push({path:o,name:I.basename(o)||"image.png",mimeType:N(o),kind:"image"})}return r}function J(t){if(t.type!=="message")return null;const r=t.role==="assistant"?"agent":t.role==="user"?"user":null;if(!r)return null;if(r==="agent"){const i=G(t.content,"output_text");return M(i)?null:i?{role:r,payload:i,titleText:i}:null}const n=F(G(t.content,"input_text")),e=n.text,o=ct(t.content);return!e&&o.length===0||M(e)&&o.length===0||L(e)&&o.length===0?null:{role:r,payload:o.length>0?k(e,o):e,titleText:e,repairHint:n.strippedWrapper?"codex_app_context_wrapper":void 0}}function X(t){if(!t)return"";try{const r=JSON.parse(t);if(typeof r=="object"&&r!==null){const n=r;if(n.type==="user"&&typeof n.content=="string")return h(n.content)}}catch{}return h(t)}function ut(t,r,n,e){return t.agentType!=="codex"||t.role!==r||W(t.payload)||Math.abs(t.ts-e)>300*1e3?!1:X(t.payload)===X(n)}function $(t,r,n,e){for(let o=t.length-1;o>=0;o-=1){const i=t[o];if(i){if(ut(i,r,n,e))return o;if(i.agentType==="codex"&&Math.abs(i.ts-e)>300*1e3)break}}return-1}function v(t,r,n,e,o,i,u,a,f,c,s="agent",l=!1,m){u&&t.push({agentType:"codex",sourceMode:"codex_rollout_import",sourceSessionKey:o,sourceEventKey:H(r,n,e),cursor:q(r,n),role:s,ts:i,payload:u,title:a,modelId:f,workDir:c,terminal:l,repairHint:m})}function x(t,r,n,e,o,i,u,a,f,c,s,l,m){const A=H(r,n,e),y=typeof m?.callId=="string"&&m.callId.trim()?m.callId.trim():null,T=y?Z("sha256").update(`${o}\0${y}`).digest("hex").slice(0,32):null,p=T?`tool:${T}`:void 0,C=T?`native:tool:${T}`:`native:${A}`,g=m?.completed&&T?2:1,E=l!==void 0?"completed":"running";t.push({agentType:"codex",sourceMode:"codex_rollout_import",sourceSessionKey:o,sourceEventKey:A,cursor:q(r,n),role:"agent",ts:i,payload:K({name:u,toolCallId:C,detailRevision:g,status:E}),title:a,modelId:f,workDir:c,...p?{canonicalMessageKey:p,canonicalMutation:m?.completed?"upsert":"append"}:{},localToolDetail:{toolCallId:C,detailRevision:g,name:u,...s!==void 0?{args:s}:{},...l!==void 0?{result:l}:{},status:E}})}function at(t,r,n,e,o,i,u,a,f){const c=typeof e.type=="string"?e.type:"";if(c){if(c==="message"){const s=J(e);if(!s||$(t,s.role,s.payload,i)>=0)return;v(t,r,n,`${c}:${s.role}`,o,i,s.payload,u,a,f,s.role,!1,s.repairHint);return}if(c==="function_call"){const s=typeof e.name=="string"?e.name:"function_call";x(t,r,n,c,o,i,s,u,a,f,O(e.arguments),void 0,{callId:e.call_id});return}if(c==="function_call_output"){x(t,r,n,c,o,i,"function_call_output",u,a,f,void 0,e.output,{callId:e.call_id,completed:!0});return}if(c==="custom_tool_call"){const s=typeof e.name=="string"?e.name:"custom_tool_call",l=e.input!==void 0?{input:e.input}:void 0;x(t,r,n,c,o,i,s,u,a,f,l,void 0,{callId:e.call_id});return}if(c==="custom_tool_call_output"){const s=typeof e.name=="string"?e.name:"custom_tool_call_output",l=e.output??e.result??e.content;x(t,r,n,c,o,i,s,u,a,f,void 0,l,{callId:e.call_id,completed:!0});return}if(c==="web_search_call"){const s=typeof e.action=="object"&&e.action!==null?e.action:null;x(t,r,n,c,o,i,"web_search",u,a,f,s??e.query);return}}}function ft(t,r,n,e,o,i,u,a,f){const c=typeof e.type=="string"?e.type:"";if(c){if(c==="user_message"){const s=B(e);if(!s)return;v(t,r,n,c,o,i,s.payload,u,a,f,"user",!1,s.repairHint);return}if(c==="agent_message"){const s=typeof e.message=="string"?h(e.message):"";if(!s||M(s))return;v(t,r,n,c,o,i,s,u,a,f);return}if(c==="turn_aborted"||c==="error"){const s=typeof e.message=="string"?h(e.message):typeof e.error=="string"?h(e.error):"";if(!s)return;v(t,r,n,c,o,i,s,u,a,f,"agent",!0);return}if(it(c)){v(t,r,n,c,o,i,st(e),u,a,f,"agent");return}if(c==="exec_command_end"){const s=Array.isArray(e.command)?e.command:e.parsed_cmd??e.command,l=e.exit_code??e.exitCode,m=[typeof e.aggregated_output=="string"?e.aggregated_output:"",l!=null?`
|
|
6
|
-
(exit ${String(l)})`:""].join("");x(t,r,n,c,o,i,"command_execution",u,a,f,{command:s},m);return}if(c==="patch_apply_end"){x(t,r,n,c,o,i,"apply_patch",u,a,f,e.changes,{success:e.success,stdout:e.stdout,stderr:e.stderr});return}if(c==="mcp_tool_call_end"){const s=typeof e.invocation=="object"&&e.invocation!==null?e.invocation:null,l=typeof s?.tool=="string"?s.tool:"mcp_tool_call",m={server:s?.server,...typeof s?.arguments=="object"&&s.arguments!==null?s.arguments:{}};x(t,r,n,c,o,i,l,u,a,f,m,e.result);return}if(c==="dynamic_tool_call_request"){const s=typeof e.tool=="string"?e.tool:"dynamic_tool_call";x(t,r,n,c,o,i,s,u,a,f,e.arguments,void 0,{callId:e.callId??e.call_id});return}if(c==="dynamic_tool_call_response"){const s=typeof e.tool=="string"?e.tool:"dynamic_tool_call";x(t,r,n,c,o,i,s,u,a,f,void 0,e.result??e.output,{callId:e.callId??e.call_id,completed:!0});return}if(c==="web_search_end"){const s=typeof e.action=="object"&&e.action!==null?e.action:null;x(t,r,n,c,o,i,"web_search",u,a,f,s??e.query,e.query);return}if(c==="image_generation_end"){const s=typeof e.saved_path=="string"?e.saved_path.trim():"";if(!s)return;v(t,r,n,c,o,i,D(s),u,a,f);return}c==="view_image_tool_call"&&x(t,r,n,c,o,i,"view_image",u,a,f,e.path??e.image_path??e)}}function S(t=!1){return{sourceSessionKey:"",workDir:"",modelId:null,title:"",skipImport:t}}function Q(t){if((typeof t.thread_source=="string"?t.thread_source.trim().toLowerCase():"")==="subagent")return!0;const n=typeof t.source=="object"&&t.source!==null?t.source:null;if(n&&typeof n.subagent=="object"&&n.subagent!==null)return!0;const e=typeof t.parent_thread_id=="string"&&t.parent_thread_id.trim().length>0,o=typeof t.agent_nickname=="string"||typeof t.agent_role=="string"||typeof t.multi_agent_version=="string";return e&&o}function lt(t){const r=j.openSync(t,"r");try{const n=[];let e=0,o="";for(;e<1024*1024;){const f=Buffer.alloc(16384),c=j.readSync(r,f,0,f.length,e);if(c<=0)break;const s=f.subarray(0,c);n.push(s),e+=c;const l=Buffer.concat(n),m=l.indexOf(10);if(m>=0){o=l.subarray(0,m).toString("utf8");break}}!o&&n.length>0&&(o=Buffer.concat(n).toString("utf8"));const i=R(o);if(!i||i.type!=="session_meta")return S();const u=typeof i.payload=="object"&&i.payload!==null?i.payload:null;if(!u)return S();if(Q(u))return S(!0);const a=typeof u.id=="string"?u.id:"";return{sourceSessionKey:a,workDir:typeof u.cwd=="string"?u.cwd:"",modelId:V(u),title:Y(a)??"",skipImport:!1}}finally{j.closeSync(r)}return S()}function V(t){return(typeof t.model=="string"?t.model.trim():"")||null}function mt(t,r){if((typeof t.id=="string"?t.id:typeof t.thread_id=="string"?t.thread_id:typeof t.session_id=="string"?t.session_id:"")!==r)return null;const o=(typeof t.thread_name=="string"?t.thread_name:typeof t.title=="string"?t.title:"").trim();return o&&!pt(o)?o.slice(0,120):null}function pt(t){const r=t.trim().toLocaleLowerCase().replace(/[\s_-]+/g," ");return et.has(r)}function Y(t){if(!t)return null;const r=I.join(w.homedir(),".codex","session_index.jsonl");if(!j.existsSync(r))return null;let n=null;return U(r,0,e=>{if(!e.trim())return;const o=R(e);if(!o)return;const i=mt(o,t);i&&(n=i)}),n}function Tt(){const t=[I.join(w.homedir(),".codex","sessions"),I.join(w.homedir(),".codex","archived_sessions")],r=[],n=e=>{for(const o of j.readdirSync(e,{withFileTypes:!0})){const i=I.join(e,o.name);o.isDirectory()?n(i):o.isFile()&&o.name.endsWith(".jsonl")&&r.push(i)}};for(const e of t)j.existsSync(e)&&n(e);return[...new Set(r)].sort()}function Ct(t,r){const n=[],e=lt(t);let{sourceSessionKey:o,workDir:i,modelId:u,title:a,skipImport:f}=e,c=e.title;if(f)return{nextOffset:j.statSync(t).size,events:[]};let s=!1;const l=U(t,r,(m,A)=>{const y=R(m);if(!y)return;const T=typeof y.type=="string"?y.type:"",p=typeof y.payload=="object"&&y.payload!==null?y.payload:null,C=tt(y.timestamp);if(!(!p||!C)){if(T==="session_meta"){if(Q(p)){n.length=0,f=!0;return}o=typeof p.id=="string"?p.id:o,i=typeof p.cwd=="string"?p.cwd:i,u=V(p)??u;const g=Y(o);g&&(c=g,a=g);return}if(!f&&o){if(T==="response_item"){const g=J(p);g?.role==="user"&&g.titleText&&!a&&(a=g.titleText.slice(0,80)),at(n,t,A,p,o,C,a,u,i);return}if(T==="event_msg"){const g=typeof p.type=="string"?p.type:"";if(ot(g)){let d=!1;for(let _=n.length-1;_>=0;_-=1){const b=n[_];if(b?.agentType==="codex"&&b.role==="agent"&&!W(b.payload)){b.terminal=!0,d=!0,s=!1;break}}if(!d)for(let _=n.length-1;_>=0;_-=1){const b=n[_];if(!(b?.agentType!=="codex"||b.role!=="agent")){b.terminal=!0,d=!0,s=!1;break}}d||(s=!0);return}if(g==="user_message"){const d=B(p);if(d?.titleText&&!a&&(a=d.titleText.slice(0,80)),d){const _=$(n,"user",d.payload,C);_>=0&&n.splice(_,1)}}else if(g==="agent_message"){const d=typeof p.message=="string"?h(p.message):"";if(d&&!M(d)){const _=$(n,"agent",d,C);_>=0&&n.splice(_,1)}}const E=n.length;ft(n,t,A,p,o,C,a,u,i),s&&n.length>E&&(n[n.length-1].terminal=!0,s=!1)}}}});for(const m of n)m.titleSource=c&&m.title===c?"agent_native":"first_user_fallback";return{nextOffset:l,events:n}}export{Tt as listCodexRolloutFiles,Y as lookupCodexThreadName,Ct as parseCodexRolloutChunk};
|
|
3
|
+
`)):""}function se(t){if(!Array.isArray(t))return[];const r=[];for(const n of t){if(typeof n!="object"||n===null)continue;const e=n;if(e.type!=="input_image")continue;const o=typeof e.path=="string"?e.path:typeof e.file_path=="string"?e.file_path:typeof e.saved_path=="string"?e.saved_path:typeof e.image_path=="string"?e.image_path:"";o.trim()&&r.push({path:o,name:S.basename(o)||"image.png",mimeType:$(o),kind:"image"})}return r}function G(t){if(t.type!=="message")return null;const r=t.role==="assistant"?"agent":t.role==="user"?"user":null;if(!r)return null;if(r==="agent"){const s=w(t.content,"output_text");return M(s)?null:s?{role:r,payload:s,titleText:s}:null}const n=B(w(t.content,"input_text")),e=n.text,o=se(t.content);return!e&&o.length===0||M(e)&&o.length===0||F(e)&&o.length===0?null:{role:r,payload:o.length>0?R(e,o):e,titleText:e,repairHint:n.strippedWrapper?"codex_app_context_wrapper":void 0}}function J(t){if(!t)return"";try{const r=JSON.parse(t);if(typeof r=="object"&&r!==null){const n=r;if(n.type==="user"&&typeof n.content=="string")return T(n.content)}}catch{}return T(t)}function ce(t,r,n,e){return t.agentType!=="codex"||t.role!==r||W(t.payload)||Math.abs(t.ts-e)>300*1e3?!1:J(t.payload)===J(n)}function N(t,r,n,e){for(let o=t.length-1;o>=0;o-=1){const s=t[o];if(s){if(ce(s,r,n,e))return o;if(s.agentType==="codex"&&Math.abs(s.ts-e)>300*1e3)break}}return-1}function I(t,r,n,e,o,s,u,a,f,c,i="agent",m=!1,l){u&&t.push({agentType:"codex",sourceMode:"codex_rollout_import",sourceSessionKey:o,sourceEventKey:q(r,n,e),cursor:k(r,n),role:i,ts:s,payload:u,title:a,modelId:f,workDir:c,terminal:m,repairHint:l})}function x(t,r,n,e,o,s,u,a,f,c,i,m,l){const v=q(r,n,e),h=typeof l?.callId=="string"&&l.callId.trim()?l.callId.trim():null,b=h?X("sha256").update(`${o}\0${h}`).digest("hex").slice(0,32):null,p=b?`tool:${b}`:void 0,C=b?`native:tool:${b}`:`native:${v}`,g=l?.completed&&b?2:1,A=m!==void 0?"completed":"running";t.push({agentType:"codex",sourceMode:"codex_rollout_import",sourceSessionKey:o,sourceEventKey:v,cursor:k(r,n),role:"agent",ts:s,payload:P({name:u,toolCallId:C,detailRevision:g,status:A}),title:a,modelId:f,workDir:c,...p?{canonicalMessageKey:p,canonicalMutation:l?.completed?"upsert":"append"}:{},localToolDetail:{toolCallId:C,detailRevision:g,name:u,...i!==void 0?{args:i}:{},...m!==void 0?{result:m}:{},status:A}})}function ue(t,r,n,e,o,s,u,a,f){const c=typeof e.type=="string"?e.type:"";if(c){if(c==="message"){const i=G(e);if(!i||N(t,i.role,i.payload,s)>=0)return;I(t,r,n,`${c}:${i.role}`,o,s,i.payload,u,a,f,i.role,!1,i.repairHint);return}if(c==="function_call"){const i=typeof e.name=="string"?e.name:"function_call";x(t,r,n,c,o,s,i,u,a,f,D(e.arguments),void 0,{callId:e.call_id});return}if(c==="function_call_output"){const i=ee(e);if(i){I(t,r,n,"delegation:user",o,s,i,u||i.slice(0,80),a,f,"user");return}x(t,r,n,c,o,s,"function_call_output",u,a,f,void 0,e.output,{callId:e.call_id,completed:!0});return}if(c==="custom_tool_call"){const i=typeof e.name=="string"?e.name:"custom_tool_call",m=e.input!==void 0?{input:e.input}:void 0;x(t,r,n,c,o,s,i,u,a,f,m,void 0,{callId:e.call_id});return}if(c==="custom_tool_call_output"){const i=typeof e.name=="string"?e.name:"custom_tool_call_output",m=e.output??e.result??e.content;x(t,r,n,c,o,s,i,u,a,f,void 0,m,{callId:e.call_id,completed:!0});return}if(c==="web_search_call"){const i=typeof e.action=="object"&&e.action!==null?e.action:null;x(t,r,n,c,o,s,"web_search",u,a,f,i??e.query);return}}}function ae(t,r,n,e,o,s,u,a,f){const c=typeof e.type=="string"?e.type:"";if(c){if(c==="user_message"){const i=L(e);if(!i)return;I(t,r,n,c,o,s,i.payload,u,a,f,"user",!1,i.repairHint);return}if(c==="agent_message"){const i=typeof e.message=="string"?T(e.message):"";if(!i||M(i))return;I(t,r,n,c,o,s,i,u,a,f);return}if(c==="turn_aborted"||c==="error"){const i=typeof e.message=="string"?T(e.message):typeof e.error=="string"?T(e.error):"";if(!i)return;I(t,r,n,c,o,s,i,u,a,f,"agent",!0);return}if(oe(c)){I(t,r,n,c,o,s,ie(e),u,a,f,"agent");return}if(c==="exec_command_end"){const i=Array.isArray(e.command)?e.command:e.parsed_cmd??e.command,m=e.exit_code??e.exitCode,l=[typeof e.aggregated_output=="string"?e.aggregated_output:"",m!=null?`
|
|
4
|
+
(exit ${String(m)})`:""].join("");x(t,r,n,c,o,s,"command_execution",u,a,f,{command:i},l);return}if(c==="patch_apply_end"){x(t,r,n,c,o,s,"apply_patch",u,a,f,e.changes,{success:e.success,stdout:e.stdout,stderr:e.stderr});return}if(c==="mcp_tool_call_end"){const i=typeof e.invocation=="object"&&e.invocation!==null?e.invocation:null,m=typeof i?.tool=="string"?i.tool:"mcp_tool_call",l={server:i?.server,...typeof i?.arguments=="object"&&i.arguments!==null?i.arguments:{}};x(t,r,n,c,o,s,m,u,a,f,l,e.result);return}if(c==="dynamic_tool_call_request"){const i=typeof e.tool=="string"?e.tool:"dynamic_tool_call";x(t,r,n,c,o,s,i,u,a,f,e.arguments,void 0,{callId:e.callId??e.call_id});return}if(c==="dynamic_tool_call_response"){const i=typeof e.tool=="string"?e.tool:"dynamic_tool_call";x(t,r,n,c,o,s,i,u,a,f,void 0,e.result??e.output,{callId:e.callId??e.call_id,completed:!0});return}if(c==="web_search_end"){const i=typeof e.action=="object"&&e.action!==null?e.action:null;x(t,r,n,c,o,s,"web_search",u,a,f,i??e.query,e.query);return}if(c==="image_generation_end"){const i=typeof e.saved_path=="string"?e.saved_path.trim():"";if(!i)return;I(t,r,n,c,o,s,Z(i),u,a,f);return}c==="view_image_tool_call"&&x(t,r,n,c,o,s,"view_image",u,a,f,e.path??e.image_path??e)}}function E(t=!1){return{sourceSessionKey:"",workDir:"",modelId:null,title:"",skipImport:t}}function Q(t){if((typeof t.thread_source=="string"?t.thread_source.trim().toLowerCase():"")==="subagent")return!0;const n=typeof t.source=="object"&&t.source!==null?t.source:null;if(n&&typeof n.subagent=="object"&&n.subagent!==null)return!0;const e=typeof t.parent_thread_id=="string"&&t.parent_thread_id.trim().length>0,o=typeof t.agent_nickname=="string"||typeof t.agent_role=="string"||typeof t.multi_agent_version=="string";return e&&o}function fe(t){const r=j.openSync(t,"r");try{const n=[];let e=0,o="";for(;e<1024*1024;){const f=Buffer.alloc(16384),c=j.readSync(r,f,0,f.length,e);if(c<=0)break;const i=f.subarray(0,c);n.push(i),e+=c;const m=Buffer.concat(n),l=m.indexOf(10);if(l>=0){o=m.subarray(0,l).toString("utf8");break}}!o&&n.length>0&&(o=Buffer.concat(n).toString("utf8"));const s=U(o);if(!s||s.type!=="session_meta")return E();const u=typeof s.payload=="object"&&s.payload!==null?s.payload:null;if(!u)return E();if(Q(u))return E(!0);const a=typeof u.id=="string"?u.id:"";return{sourceSessionKey:a,workDir:typeof u.cwd=="string"?u.cwd:"",modelId:V(u),title:H(a)??"",skipImport:!1}}finally{j.closeSync(r)}return E()}function V(t){return(typeof t.model=="string"?t.model.trim():"")||null}function he(t,r){const n=[],e=fe(t);let{sourceSessionKey:o,workDir:s,modelId:u,title:a,skipImport:f}=e,c=e.title;if(f)return{nextOffset:j.statSync(t).size,events:[]};let i=!1;const m=K(t,r,(l,v)=>{const h=U(l);if(!h)return;const b=typeof h.type=="string"?h.type:"",p=typeof h.payload=="object"&&h.payload!==null?h.payload:null,C=O(h.timestamp);if(!(!p||!C)){if(b==="session_meta"){if(Q(p)){n.length=0,f=!0;return}o=typeof p.id=="string"?p.id:o,s=typeof p.cwd=="string"?p.cwd:s,u=V(p)??u;const g=H(o);g&&(c=g,a=g);return}if(!f&&o){if(b==="response_item"){const g=G(p);g?.role==="user"&&g.titleText&&!a&&(a=g.titleText.slice(0,80)),ue(n,t,v,p,o,C,a,u,s);return}if(b==="event_msg"){const g=typeof p.type=="string"?p.type:"";if(re(g)){let d=!1;for(let _=n.length-1;_>=0;_-=1){const y=n[_];if(y?.agentType==="codex"&&y.role==="agent"&&!W(y.payload)){y.terminal=!0,d=!0,i=!1;break}}if(!d)for(let _=n.length-1;_>=0;_-=1){const y=n[_];if(!(y?.agentType!=="codex"||y.role!=="agent")){y.terminal=!0,d=!0,i=!1;break}}d||(i=!0);return}if(g==="user_message"){const d=L(p);if(d?.titleText&&!a&&(a=d.titleText.slice(0,80)),d){const _=N(n,"user",d.payload,C);_>=0&&n.splice(_,1)}}else if(g==="agent_message"){const d=typeof p.message=="string"?T(p.message):"";if(d&&!M(d)){const _=N(n,"agent",d,C);_>=0&&n.splice(_,1)}}const A=n.length;ae(n,t,v,p,o,C,a,u,s),i&&n.length>A&&(n[n.length-1].terminal=!0,i=!1)}}}});for(const l of n)l.titleSource=c&&l.title===c?"agent_native":"first_user_fallback";return{nextOffset:m,events:n}}export{Ce as listCodexRolloutFiles,ye as lookupCodexThreadName,he as parseCodexRolloutChunk};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{normalizeText as r}from"./parser-common.js";function i(e){return Array.isArray(e)?e.map(t=>{if(typeof t=="string")return t;if(typeof t!="object"||t===null)return"";const n=t;return typeof n.text=="string"?n.text:""}).map(t=>r(t)).filter(Boolean).join(`
|
|
2
|
+
|
|
3
|
+
`):""}function u(e){if(e.namespace!=="codex_app"||typeof e.output!="string")return null;const t=r(e.output);if(!t.startsWith("<codex_delegation>")||!t.endsWith("</codex_delegation>"))return null;const n=t.match(/<input>([\s\S]*?)<\/input>\s*<\/codex_delegation>$/)?.[1];return n?r(n):null}export{u as parseCodexDelegationInput,i as parseCodexTextElements};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import A from"node:fs";import C from"node:crypto";import{publishPendingSessionIndexes as _}from"../session/index-publisher.js";import{NativeFusionFileWatcher as
|
|
2
|
-
`).trim()}function j(d){return d.split(/[\\/]+/).includes(".codex")}class ie{client;repository;timer=null;activeTimer=null;scanPromise=null;queuedTargetFiles=new Set;fullScanQueued=!1;watchEnabled=!1;lifecycleRevision=0;watcher=new N(e=>{this.scanNow(e).catch(s=>{console.error("[native-fusion] watched file scan failed",s)})});pendingClaims;suppressionWindows;externalObservations=new Map;constructor(e,s=new O){this.client=e,this.repository=s,this.pendingClaims=new Map((this.repository.listManagedClaims?.()??[]).map(t=>[t.canonicalMessageId,t])),this.suppressionWindows=new Map((this.repository.listManagedSuppressions?.()??[]).map(t=>[T(t.agentType,t.sourceSessionKey),t]))}start(){this.timer||(this.timer=setInterval(()=>{this.scanNow().catch(e=>{console.error("[native-fusion] periodic scan failed",e)})},E))}stop(){this.lifecycleRevision+=1,this.timer&&clearInterval(this.timer),this.timer=null,this.activeTimer&&clearInterval(this.activeTimer),this.activeTimer=null,this.watchEnabled=!1,this.watcher.stop()}handleConnected(){const e=++this.lifecycleRevision;this.watchEnabled=!0,this.scanNow().catch(s=>{console.error("[native-fusion] initial scan failed",s)}).finally(()=>{this.lifecycleRevision===e&&this.start()})}registerManagedSend(e){if(!e.canonicalMessageId)return;const s=e.sourceAgentType??e.agentType;if(s!=="codex"&&s!=="claude"&&s!=="opencode")return;const t=e.canonicalMessageId,n=this.pendingClaims.get(t),o=b(e.text);if(n&&(n.sessionId!==e.sessionId||n.sourceAgentType!==s||n.textHash!==o))throw new Error(`managed echo claim identity conflict: ${t}`);const l={sessionId:e.sessionId,agentType:e.agentType,sourceAgentType:s,canonicalMessageId:e.canonicalMessageId,textHash:o,createdAt:n?.createdAt??Date.now(),sourceSessionKey:e.sourceSessionKey??n?.sourceSessionKey??null,managedEchoPolicy:e.managedEchoPolicy??"suppress_following",externalRunId:e.externalRunId??null};if(this.repository.upsertManagedClaim?.(l),this.pendingClaims.set(t,l),e.externalRunId&&e.sourceSessionKey){const h=`${s}:${e.sourceSessionKey}`,f=this.externalObservations.get(h)??[];f.push({sessionId:e.sessionId,sourceSessionKey:e.sourceSessionKey,runId:e.externalRunId,canonicalMessageId:e.canonicalMessageId,state:"queued",createdAt:Date.now(),lastPublishedAt:Date.now()}),this.externalObservations.set(h,f),this.emitExternalActivity(f[f.length-1],"queued"),this.ensureActiveScanning()}}cancelManagedSend(e){this.repository.removeManagedClaim?.(e),this.pendingClaims.delete(e)}noteManagedSourceSession(e,s,t){if(t){this.repository.updateManagedClaimSource?.(e,s,t);for(const n of this.pendingClaims.values())n.sessionId===e&&n.sourceAgentType===s&&(n.sourceSessionKey=t)}}handleSessionDeleted(e){for(const[s,t]of this.pendingClaims.entries())t.sessionId===e&&this.pendingClaims.delete(s);for(const[s,t]of this.suppressionWindows.entries())t.sessionId===e&&this.suppressionWindows.delete(s);for(const[s,t]of this.externalObservations.entries()){const n=t.filter(o=>o.sessionId!==e);n.length===0?this.externalObservations.delete(s):this.externalObservations.set(s,n)}this.repository.purgeSession(e)}ensureActiveScanning(){this.activeTimer||(this.activeTimer=setInterval(()=>{if(this.externalObservations.size===0){this.activeTimer&&clearInterval(this.activeTimer),this.activeTimer=null;return}this.scanNow().catch(e=>{console.error("[native-fusion] active observation scan failed",e)})},H),this.scanNow().catch(()=>{}))}emitExternalActivity(e,s){this.client.sendAgentEvent({type:"event",event:"agent",id:`external-owner-${e.runId}-${s}-${e.lastPublishedAt}`,payload:{state:s==="queued"?"start":"heartbeat",sessionId:e.sessionId,runId:e.runId,seq:s==="queued"?0:1,runPhase:"thinking",canStop:!1,owner:"external",ownerLabel:"Codex Desktop",lifecycle:s}})}emitExternalTerminal(e){this.client.sendAgentEvent({type:"event",event:"agent",id:`external-owner-${e.runId}-final`,payload:{state:"final",sessionId:e.sessionId,runId:e.runId,seq:2,owner:"external",ownerLabel:"Codex Desktop"}})}pruneState(){const e=Date.now();for(const[s,t]of this.suppressionWindows.entries())t.endsAt>e||(this.repository.removeManagedSuppression?.(t.agentType,t.sourceSessionKey),this.suppressionWindows.delete(s))}async scanNow(e){if(this.client.getState()==="connected"){if(this.scanPromise){const s=this.scanPromise;if(e)for(const t of e)this.queuedTargetFiles.add(t);else this.fullScanQueued=!0;if(await s,this.fullScanQueued)return this.fullScanQueued=!1,this.queuedTargetFiles.clear(),this.scanNow();if(this.queuedTargetFiles.size>0){const t=[...this.queuedTargetFiles];return this.queuedTargetFiles.clear(),this.scanNow(t)}return}return this.scanPromise=this.runScanLoop(e).finally(()=>{this.scanPromise=null}),this.scanPromise}}async runScanLoop(e){let s=e?[...new Set(e)]:void 0;for(;;){if(await this.runScan(s),this.fullScanQueued){this.fullScanQueued=!1,this.queuedTargetFiles.clear(),s=void 0;continue}if(this.queuedTargetFiles.size>0){s=[...this.queuedTargetFiles],this.queuedTargetFiles.clear();continue}return}}async runScan(e){this.pruneState(),this.refreshExternalObservations();const s=D(),t={...s.files},n=[],o=new Map,l=new Map,h=new Map,f=e?[...e]:[...R(),...P(),...k()];!e&&this.watchEnabled&&this.watcher.refresh(f);for(const i of f){if(!A.existsSync(i))continue;const r=A.statSync(i),m=j(i),p=i.endsWith(".opencode-session.json"),c=q(i);if(c.status==="pending")continue;let u=s.files[i];const v=`${String(r.dev)}:${String(r.ino)}:${String(r.birthtimeMs)}`;let I=!u;if(u&&!p&&(r.size<u.offset||u.fileIdentity&&u.fileIdentity!==v)&&(u=void 0,I=!0),!p&&c.sources.length>0&&c.sources.every(a=>this.repository.isSourceDeleted?.(a.agentType,a.sourceSessionKey))){t[i]={...u??{daemonInstallationId:s.daemonInstallationId,classification:c.createdAtMs>=s.fusionEpochMs?"live":"historical",awaitingUserBoundary:!0,sessionCreatedAtMs:c.createdAtMs,sourceBoundaryEstablished:{}},offset:r.size,mtimeMs:r.mtimeMs,fileIdentity:v};continue}if(!u)u={daemonInstallationId:s.daemonInstallationId,offset:0,mtimeMs:r.mtimeMs,classification:c.createdAtMs>=s.fusionEpochMs?"live":"historical",awaitingUserBoundary:!0,sessionCreatedAtMs:c.createdAtMs,sourceBoundaryEstablished:{}};else if(p&&u.mtimeMs===r.mtimeMs)continue;const x=p?0:u.offset,g=p?B(i,x):m?L(i,x):W(i,x);for(const a of g.events)this.repository.isSourceDeleted?.(a.agentType,a.sourceSessionKey)||a.title?.trim()&&a.titleSource==="agent_native"&&h.set(`${a.agentType}:${a.sourceSessionKey}`,a);let w,S;if(p){const a=G(g.events,u,s.fusionEpochMs,I,r.mtimeMs,g.nextOffset);w=a.events,S=a.cursor}else if(I&&u.classification==="historical")w=[],S={...u,offset:g.nextOffset,mtimeMs:r.mtimeMs,awaitingUserBoundary:!0};else{const a=X(g.events,u,g.nextOffset,r.mtimeMs);w=a.events,S=a.cursor}S.fileIdentity=v,t[i]=S;for(const a of w){if(this.repository.isSourceDeleted?.(a.agentType,a.sourceSessionKey))continue;const y=this.tryClaimManagedEcho(a);if(y){n.push(y.event),o.set(y.claimKey,y.suppression??null),y.suppression&&l.set(T(y.suppression.agentType,y.suppression.sourceSessionKey),{window:y.suppression,claimKey:y.claimKey});continue}const M=this.suppressionFor(a,l,o);if(M){n.push({...a,claimSessionId:M.sessionId,localDisposition:"managed_echo_suppressed"});continue}n.push(a)}}this.repository.commitEvents(n);for(const[i,r]of o)this.repository.completeManagedClaim?.(i,r??void 0),this.pendingClaims.delete(i),r&&this.suppressionWindows.set(T(r.agentType,r.sourceSessionKey),r);for(const i of h.values())this.repository.observeNativeTitle(i.agentType,i.sourceSessionKey,i.title??"");for(const i of this.repository.listSourceBindings()){if(i.agentType!=="codex")continue;const r=F(i.sourceSessionKey);r&&this.repository.observeNativeTitle("codex",i.sourceSessionKey,r)}for(const i of n)this.observeExternalLifecycle(i);s.files=t,$(s),this.repository.repairMissingUserBoundaries?.(),await _(this.client).catch(i=>{console.error("[native-fusion] index projection sync failed; retained for retry",i)})}refreshExternalObservations(){const e=Date.now();for(const[s,t]of this.externalObservations.entries()){const n=t.filter(l=>e-l.createdAt<K);if(n.length===0){this.externalObservations.delete(s);continue}this.externalObservations.set(s,n);const o=n[0];e-o.lastPublishedAt<Q||(o.lastPublishedAt=e,this.emitExternalActivity(o,o.state))}}tryClaimManagedEcho(e){const s=Date.now();for(const[t,n]of this.pendingClaims.entries()){if(n.sourceAgentType!==e.agentType||e.role!=="user"||!n.sourceSessionKey||n.sourceSessionKey!==e.sourceSessionKey)continue;const o=n.externalRunId?K:U;if(Math.abs(e.ts-n.createdAt)>o||b(e.payload)!==n.textHash)continue;const l=n.managedEchoPolicy==="suppress_following"?{sessionId:n.sessionId,agentType:e.agentType,sourceSessionKey:e.sourceSessionKey,claimSourceEventKey:e.sourceEventKey,startedAt:e.ts,endsAt:Math.max(s,e.ts)+z}:void 0;return{claimKey:t,suppression:l,event:{...e,sourceMode:"managed_echo_claim",claimCanonicalMessageId:n.canonicalMessageId,claimSessionId:n.sessionId,managedEchoPolicy:n.managedEchoPolicy}}}return null}observeExternalLifecycle(e){const s=`${e.agentType}:${e.sourceSessionKey}`,t=this.externalObservations.get(s);if(!t?.length)return;const n=t[0];e.claimCanonicalMessageId===n.canonicalMessageId&&n.state==="queued"&&(n.state="running",n.lastPublishedAt=Date.now(),this.emitExternalActivity(n,"running")),!(!e.terminal||n.state!=="running")&&(this.emitExternalTerminal(n),t.shift(),t.length===0?this.externalObservations.delete(s):(this.externalObservations.set(s,t),t[0].lastPublishedAt=Date.now(),this.emitExternalActivity(t[0],"queued")))}suppressionFor(e,s,t){const n=T(e.agentType,e.sourceSessionKey),o=s.get(n),l=o?.window??this.suppressionWindows.get(n);return!l||e.ts<l.startedAt?null:e.ts>l.endsAt?(this.clearSuppression(n,l,o,s,t),null):e.role==="user"?(e.sourceEventKey===l.claimSourceEventKey||this.clearSuppression(n,l,o,s,t),null):l}clearSuppression(e,s,t,n,o){if(t){n.delete(e),o.set(t.claimKey,null);return}this.repository.removeManagedSuppression?.(s.agentType,s.sourceSessionKey),this.suppressionWindows.delete(e)}}function b(d){return C.createHash("sha256").update(V(d)).digest("hex")}function T(d,e){return`${d}:${e}`}function X(d,e,s,t){if(!e.awaitingUserBoundary)return{events:d,cursor:{...e,offset:s,mtimeMs:t}};if(d.length===0)return{events:[],cursor:{...e,offset:s,mtimeMs:t,awaitingUserBoundary:!0}};const n=d.findIndex(o=>o.role==="user");return n<0?{events:[],cursor:{...e,mtimeMs:t,awaitingUserBoundary:!0}}:{events:d.slice(n),cursor:{...e,offset:s,mtimeMs:t,awaitingUserBoundary:!1}}}function G(d,e,s,t,n,o){const l={...e.sourceBoundaryEstablished??{}},h=e.eventWatermarkTs??-1,f=new Set(e.eventKeysAtWatermark??[]),i=t?d:d.filter(c=>c.ts>h||c.ts===h&&!f.has(c.sourceEventKey)),r=[];for(const c of i){const u=c.sourceSessionKey;if(l[u]){r.push(c);continue}!(!t||(c.sourceSessionCreatedAtMs??0)>=s)||c.role!=="user"||(l[u]=!0,r.push(c))}const m=d.reduce((c,u)=>Math.max(c,u.ts),h),p=new Set(m===h?e.eventKeysAtWatermark??[]:[]);for(const c of d)c.ts===m&&p.add(c.sourceEventKey);return{events:r,cursor:{...e,offset:o,mtimeMs:n,eventWatermarkTs:m>=0?m:void 0,eventKeysAtWatermark:m>=0?[...p]:void 0,sourceBoundaryEstablished:l}}}export{ie as NativeSessionFusionService};
|
|
1
|
+
import A from"node:fs";import C from"node:crypto";import{publishPendingSessionIndexes as _}from"../session/index-publisher.js";import{NativeFusionFileWatcher as F}from"./file-watcher.js";import{NativeFusionLocalRepository as N}from"./local-repository.js";import{listClaudeTranscriptFiles as B,listCodexRolloutFiles as O,listOpenCodeSessionFiles as P,inspectNativeSessionFile as R,lookupCodexThreadName as k,parseClaudeTranscriptChunk as q,parseCodexRolloutChunk as W,parseOpenCodeSessionFile as L}from"./parsers.js";import{loadNativeScannerState as D,saveNativeScannerState as $}from"./state.js";const E=6e4,U=E*2,z=30*6e4,H=2e3,Q=3e4,b=240*6e4;function V(d){return d.replace(/\r\n/g,`
|
|
2
|
+
`).trim()}function j(d){return d.split(/[\\/]+/).includes(".codex")}class ne{client;repository;timer=null;activeTimer=null;scanPromise=null;queuedTargetFiles=new Set;pendingBoundaryFiles=new Set;fullScanQueued=!1;watchEnabled=!1;lifecycleRevision=0;watcher=new F(e=>{this.scanNow(e).catch(s=>{console.error("[native-fusion] watched file scan failed",s)})});pendingClaims;suppressionWindows;externalObservations=new Map;constructor(e,s=new N){this.client=e,this.repository=s,this.pendingClaims=new Map((this.repository.listManagedClaims?.()??[]).map(t=>[t.canonicalMessageId,t])),this.suppressionWindows=new Map((this.repository.listManagedSuppressions?.()??[]).map(t=>[T(t.agentType,t.sourceSessionKey),t]))}start(){this.timer||(this.timer=setInterval(()=>{this.scanNow().catch(e=>{console.error("[native-fusion] periodic scan failed",e)})},E))}stop(){this.lifecycleRevision+=1,this.timer&&clearInterval(this.timer),this.timer=null,this.activeTimer&&clearInterval(this.activeTimer),this.activeTimer=null,this.pendingBoundaryFiles.clear(),this.watchEnabled=!1,this.watcher.stop()}handleConnected(){const e=++this.lifecycleRevision;this.watchEnabled=!0,this.scanNow().catch(s=>{console.error("[native-fusion] initial scan failed",s)}).finally(()=>{this.lifecycleRevision===e&&this.start()})}registerManagedSend(e){if(!e.canonicalMessageId)return;const s=e.sourceAgentType??e.agentType;if(s!=="codex"&&s!=="claude"&&s!=="opencode")return;const t=e.canonicalMessageId,i=this.pendingClaims.get(t),o=K(e.text);if(i&&(i.sessionId!==e.sessionId||i.sourceAgentType!==s||i.textHash!==o))throw new Error(`managed echo claim identity conflict: ${t}`);const l={sessionId:e.sessionId,agentType:e.agentType,sourceAgentType:s,canonicalMessageId:e.canonicalMessageId,textHash:o,createdAt:i?.createdAt??Date.now(),sourceSessionKey:e.sourceSessionKey??i?.sourceSessionKey??null,managedEchoPolicy:e.managedEchoPolicy??"suppress_following",externalRunId:e.externalRunId??null};if(this.repository.upsertManagedClaim?.(l),this.pendingClaims.set(t,l),e.externalRunId&&e.sourceSessionKey){const h=`${s}:${e.sourceSessionKey}`,f=this.externalObservations.get(h)??[];f.push({sessionId:e.sessionId,sourceSessionKey:e.sourceSessionKey,runId:e.externalRunId,canonicalMessageId:e.canonicalMessageId,state:"queued",createdAt:Date.now(),lastPublishedAt:Date.now()}),this.externalObservations.set(h,f),this.emitExternalActivity(f[f.length-1],"queued"),this.ensureActiveScanning()}}cancelManagedSend(e){this.repository.removeManagedClaim?.(e),this.pendingClaims.delete(e)}noteManagedSourceSession(e,s,t){if(t){this.repository.updateManagedClaimSource?.(e,s,t);for(const i of this.pendingClaims.values())i.sessionId===e&&i.sourceAgentType===s&&(i.sourceSessionKey=t)}}handleSessionDeleted(e){for(const[s,t]of this.pendingClaims.entries())t.sessionId===e&&this.pendingClaims.delete(s);for(const[s,t]of this.suppressionWindows.entries())t.sessionId===e&&this.suppressionWindows.delete(s);for(const[s,t]of this.externalObservations.entries()){const i=t.filter(o=>o.sessionId!==e);i.length===0?this.externalObservations.delete(s):this.externalObservations.set(s,i)}this.repository.purgeSession(e)}ensureActiveScanning(e=!0){this.activeTimer||(this.activeTimer=setInterval(()=>{if(this.externalObservations.size===0&&this.pendingBoundaryFiles.size===0){this.activeTimer&&clearInterval(this.activeTimer),this.activeTimer=null;return}const s=this.externalObservations.size>0?void 0:[...this.pendingBoundaryFiles];this.scanNow(s).catch(t=>{console.error("[native-fusion] active observation scan failed",t)})},H),e&&this.scanNow().catch(()=>{}))}emitExternalActivity(e,s){this.client.sendAgentEvent({type:"event",event:"agent",id:`external-owner-${e.runId}-${s}-${e.lastPublishedAt}`,payload:{state:s==="queued"?"start":"heartbeat",sessionId:e.sessionId,runId:e.runId,seq:s==="queued"?0:1,runPhase:"thinking",canStop:!1,owner:"external",ownerLabel:"Codex Desktop",lifecycle:s}})}emitExternalTerminal(e){this.client.sendAgentEvent({type:"event",event:"agent",id:`external-owner-${e.runId}-final`,payload:{state:"final",sessionId:e.sessionId,runId:e.runId,seq:2,owner:"external",ownerLabel:"Codex Desktop"}})}pruneState(){const e=Date.now();for(const[s,t]of this.suppressionWindows.entries())t.endsAt>e||(this.repository.removeManagedSuppression?.(t.agentType,t.sourceSessionKey),this.suppressionWindows.delete(s))}async scanNow(e){if(this.client.getState()==="connected"){if(this.scanPromise){const s=this.scanPromise;if(e)for(const t of e)this.queuedTargetFiles.add(t);else this.fullScanQueued=!0;if(await s,this.fullScanQueued)return this.fullScanQueued=!1,this.queuedTargetFiles.clear(),this.scanNow();if(this.queuedTargetFiles.size>0){const t=[...this.queuedTargetFiles];return this.queuedTargetFiles.clear(),this.scanNow(t)}return}return this.scanPromise=this.runScanLoop(e).finally(()=>{this.scanPromise=null}),this.scanPromise}}async runScanLoop(e){let s=e?[...new Set(e)]:void 0;for(;;){if(await this.runScan(s),this.fullScanQueued){this.fullScanQueued=!1,this.queuedTargetFiles.clear(),s=void 0;continue}if(this.queuedTargetFiles.size>0){s=[...this.queuedTargetFiles],this.queuedTargetFiles.clear();continue}return}}async runScan(e){this.pruneState(),this.refreshExternalObservations();const s=D(),t={...s.files},i=[],o=new Map,l=new Map,h=new Map,f=e?[...e]:[...O(),...B(),...P()];!e&&this.watchEnabled&&this.watcher.refresh(f);for(const n of f){if(!A.existsSync(n)){this.pendingBoundaryFiles.delete(n);continue}const r=A.statSync(n),g=j(n),p=n.endsWith(".opencode-session.json"),c=R(n);if(c.status==="pending"){r.birthtimeMs>=s.fusionEpochMs&&this.pendingBoundaryFiles.add(n);continue}let u=s.files[n];const v=`${String(r.dev)}:${String(r.ino)}:${String(r.birthtimeMs)}`;let I=!u;if(u&&!p&&(r.size<u.offset||u.fileIdentity&&u.fileIdentity!==v)&&(u=void 0,I=!0),!p&&c.sources.length>0&&c.sources.every(a=>this.repository.isSourceDeleted?.(a.agentType,a.sourceSessionKey))){t[n]={...u??{daemonInstallationId:s.daemonInstallationId,classification:c.createdAtMs>=s.fusionEpochMs?"live":"historical",awaitingUserBoundary:!0,sessionCreatedAtMs:c.createdAtMs,sourceBoundaryEstablished:{}},offset:r.size,mtimeMs:r.mtimeMs,fileIdentity:v};continue}if(!u)u={daemonInstallationId:s.daemonInstallationId,offset:0,mtimeMs:r.mtimeMs,classification:c.createdAtMs>=s.fusionEpochMs?"live":"historical",awaitingUserBoundary:!0,sessionCreatedAtMs:c.createdAtMs,sourceBoundaryEstablished:{}};else if(p&&u.mtimeMs===r.mtimeMs)continue;const x=p?0:u.offset,S=p?L(n,x):g?W(n,x):q(n,x);for(const a of S.events)this.repository.isSourceDeleted?.(a.agentType,a.sourceSessionKey)||a.title?.trim()&&a.titleSource==="agent_native"&&h.set(`${a.agentType}:${a.sourceSessionKey}`,a);let w,m;if(p){const a=G(S.events,u,s.fusionEpochMs,I,r.mtimeMs,S.nextOffset);w=a.events,m=a.cursor}else if(I&&u.classification==="historical")w=[],m={...u,offset:S.nextOffset,mtimeMs:r.mtimeMs,awaitingUserBoundary:!0};else{const a=X(S.events,u,S.nextOffset,r.mtimeMs);w=a.events,m=a.cursor}m.fileIdentity=v,t[n]=m,m.classification==="live"&&m.awaitingUserBoundary?this.pendingBoundaryFiles.add(n):this.pendingBoundaryFiles.delete(n);for(const a of w){if(this.repository.isSourceDeleted?.(a.agentType,a.sourceSessionKey))continue;const y=this.tryClaimManagedEcho(a);if(y){i.push(y.event),o.set(y.claimKey,y.suppression??null),y.suppression&&l.set(T(y.suppression.agentType,y.suppression.sourceSessionKey),{window:y.suppression,claimKey:y.claimKey});continue}const M=this.suppressionFor(a,l,o);if(M){i.push({...a,claimSessionId:M.sessionId,localDisposition:"managed_echo_suppressed"});continue}i.push(a)}}this.repository.commitEvents(i);for(const[n,r]of o)this.repository.completeManagedClaim?.(n,r??void 0),this.pendingClaims.delete(n),r&&this.suppressionWindows.set(T(r.agentType,r.sourceSessionKey),r);for(const n of h.values())this.repository.observeNativeTitle(n.agentType,n.sourceSessionKey,n.title??"");for(const n of this.repository.listSourceBindings()){if(n.agentType!=="codex")continue;const r=k(n.sourceSessionKey);r&&this.repository.observeNativeTitle("codex",n.sourceSessionKey,r)}for(const n of i)this.observeExternalLifecycle(n);s.files=t,$(s),this.pendingBoundaryFiles.size>0&&this.ensureActiveScanning(!1),this.repository.repairMissingUserBoundaries?.(),await _(this.client).catch(n=>{console.error("[native-fusion] index projection sync failed; retained for retry",n)})}refreshExternalObservations(){const e=Date.now();for(const[s,t]of this.externalObservations.entries()){const i=t.filter(l=>e-l.createdAt<b);if(i.length===0){this.externalObservations.delete(s);continue}this.externalObservations.set(s,i);const o=i[0];e-o.lastPublishedAt<Q||(o.lastPublishedAt=e,this.emitExternalActivity(o,o.state))}}tryClaimManagedEcho(e){const s=Date.now();for(const[t,i]of this.pendingClaims.entries()){if(i.sourceAgentType!==e.agentType||e.role!=="user"||!i.sourceSessionKey||i.sourceSessionKey!==e.sourceSessionKey)continue;const o=i.externalRunId?b:U;if(Math.abs(e.ts-i.createdAt)>o||K(e.payload)!==i.textHash)continue;const l=i.managedEchoPolicy==="suppress_following"?{sessionId:i.sessionId,agentType:e.agentType,sourceSessionKey:e.sourceSessionKey,claimSourceEventKey:e.sourceEventKey,startedAt:e.ts,endsAt:Math.max(s,e.ts)+z}:void 0;return{claimKey:t,suppression:l,event:{...e,sourceMode:"managed_echo_claim",claimCanonicalMessageId:i.canonicalMessageId,claimSessionId:i.sessionId,managedEchoPolicy:i.managedEchoPolicy}}}return null}observeExternalLifecycle(e){const s=`${e.agentType}:${e.sourceSessionKey}`,t=this.externalObservations.get(s);if(!t?.length)return;const i=t[0];e.claimCanonicalMessageId===i.canonicalMessageId&&i.state==="queued"&&(i.state="running",i.lastPublishedAt=Date.now(),this.emitExternalActivity(i,"running")),!(!e.terminal||i.state!=="running")&&(this.emitExternalTerminal(i),t.shift(),t.length===0?this.externalObservations.delete(s):(this.externalObservations.set(s,t),t[0].lastPublishedAt=Date.now(),this.emitExternalActivity(t[0],"queued")))}suppressionFor(e,s,t){const i=T(e.agentType,e.sourceSessionKey),o=s.get(i),l=o?.window??this.suppressionWindows.get(i);return!l||e.ts<l.startedAt?null:e.ts>l.endsAt?(this.clearSuppression(i,l,o,s,t),null):e.role==="user"?(e.sourceEventKey===l.claimSourceEventKey||this.clearSuppression(i,l,o,s,t),null):l}clearSuppression(e,s,t,i,o){if(t){i.delete(e),o.set(t.claimKey,null);return}this.repository.removeManagedSuppression?.(s.agentType,s.sourceSessionKey),this.suppressionWindows.delete(e)}}function K(d){return C.createHash("sha256").update(V(d)).digest("hex")}function T(d,e){return`${d}:${e}`}function X(d,e,s,t){if(!e.awaitingUserBoundary)return{events:d,cursor:{...e,offset:s,mtimeMs:t}};if(d.length===0)return{events:[],cursor:{...e,offset:s,mtimeMs:t,awaitingUserBoundary:!0}};const i=d.findIndex(o=>o.role==="user");return i<0?{events:[],cursor:{...e,mtimeMs:t,awaitingUserBoundary:!0}}:{events:d.slice(i),cursor:{...e,offset:s,mtimeMs:t,awaitingUserBoundary:!1}}}function G(d,e,s,t,i,o){const l={...e.sourceBoundaryEstablished??{}},h=e.eventWatermarkTs??-1,f=new Set(e.eventKeysAtWatermark??[]),n=t?d:d.filter(c=>c.ts>h||c.ts===h&&!f.has(c.sourceEventKey)),r=[];for(const c of n){const u=c.sourceSessionKey;if(l[u]){r.push(c);continue}!(!t||(c.sourceSessionCreatedAtMs??0)>=s)||c.role!=="user"||(l[u]=!0,r.push(c))}const g=d.reduce((c,u)=>Math.max(c,u.ts),h),p=new Set(g===h?e.eventKeysAtWatermark??[]:[]);for(const c of d)c.ts===g&&p.add(c.sourceEventKey);return{events:r,cursor:{...e,offset:o,mtimeMs:i,eventWatermarkTs:g>=0?g:void 0,eventKeysAtWatermark:g>=0?[...p]:void 0,sourceBoundaryEstablished:l}}}export{ne as NativeSessionFusionService};
|