From 77d9af6bc8cae74e95bab38c97b8d732c29cc366 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Thu, 8 Oct 2026 18:46:01 -0700 Subject: [PATCH] fix(chatgpt): pin browser targets for reproducible bundles --- plugin/chatgpt-extension/embedded/app.html | 26 +++++++++++----------- plugin/chatgpt-extension/rsbuild.config.ts | 2 ++ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/plugin/chatgpt-extension/embedded/app.html b/plugin/chatgpt-extension/embedded/app.html index d68cb59e33..2371c9d6e6 100644 --- a/plugin/chatgpt-extension/embedded/app.html +++ b/plugin/chatgpt-extension/embedded/app.html @@ -4,12 +4,12 @@ TraceDecay Code Explorer - +
- +- "app": Tool callable by the app from this server only`),csp:a.never().optional(),permissions:a.never().optional()}),a.object({mimeTypes:a.array(a.string()).optional().describe('Array of supported MIME types for UI resources.\nMust include `"text/html;profile=mcp-app"` for MCP Apps support.')}),a.object({method:a.literal("ui/download-file"),params:a.object({contents:a.array(a.union([eL,eR])).describe("Resource contents to download — embedded (inline data) or linked (host fetches). Uses standard MCP resource types.")})}),a.object({method:a.literal("ui/message"),params:a.object({role:a.literal("user").describe('Message role, currently only "user" is supported.'),content:a.array(eM).describe("Message content blocks (text, image, etc.).")})}),a.object({method:a.literal("ui/notifications/sandbox-resource-ready"),params:a.object({html:a.string().describe("HTML content to load into the inner iframe."),sandbox:a.string().optional().describe("Optional override for the inner iframe's sandbox attribute."),csp:tX.optional().describe("CSP configuration from resource metadata."),permissions:tY.optional().describe("Sandbox permissions from resource metadata.")})}),a.object({method:a.literal("ui/notifications/tool-result"),params:eG.describe("Standard MCP tool execution result.")})),it=a.object({toolInfo:a.object({id:b.optional().describe("JSON-RPC id of the tools/call request."),tool:eH.describe("Tool definition including name, inputSchema, etc.")}).optional().describe("Metadata of the tool call that instantiated this App."),theme:tF.optional().describe("Current color theme preference."),styles:t1.optional().describe("Style configuration for theming the app."),displayMode:tJ.optional().describe("How the UI is currently displayed."),availableDisplayModes:a.array(tJ).optional().describe("Display modes the host supports."),containerDimensions:a.union([a.object({height:a.number().describe("Fixed container height in pixels.")}),a.object({maxHeight:a.union([a.number(),a.undefined()]).optional().describe("Maximum container height in pixels.")})]).and(a.union([a.object({width:a.number().describe("Fixed container width in pixels.")}),a.object({maxWidth:a.union([a.number(),a.undefined()]).optional().describe("Maximum container width in pixels.")})])).optional().describe(`Container dimensions. Represents the dimensions of the iframe or other +container holding the app. Specify either width or maxWidth, and either height or maxHeight.`),locale:a.string().optional().describe("User's language and region preference in BCP 47 format."),timeZone:a.string().optional().describe("User's timezone in IANA format."),userAgent:a.string().optional().describe("Host application identifier."),platform:a.union([a.literal("web"),a.literal("desktop"),a.literal("mobile")]).optional().describe("Platform type for responsive design decisions."),deviceCapabilities:a.object({touch:a.boolean().optional().describe("Whether the device supports touch input."),hover:a.boolean().optional().describe("Whether the device supports hover interactions.")}).optional().describe("Device input capabilities."),safeAreaInsets:a.object({top:a.number().describe("Top safe area inset in pixels."),right:a.number().describe("Right safe area inset in pixels."),bottom:a.number().describe("Bottom safe area inset in pixels."),left:a.number().describe("Left safe area inset in pixels.")}).optional().describe("Mobile safe area boundaries in pixels.")}).passthrough(),ii=a.object({method:a.literal("ui/notifications/host-context-changed"),params:it.describe("Partial context update containing only changed fields.")}),ir=(a.object({method:a.literal("ui/update-model-context"),params:a.object({content:a.array(eM).optional().describe("Context content blocks (text, image, etc.)."),structuredContent:a.record(a.string(),a.unknown().describe("Structured content for machine-readable context data.")).optional().describe("Structured content for machine-readable context data.")})}),a.object({method:a.literal("ui/initialize"),params:a.object({appInfo:D.describe("App identification (name and version)."),appCapabilities:t7.describe("Features and capabilities this app provides."),protocolVersion:a.string().describe("Protocol version this app supports.")})}),a.object({protocolVersion:a.string().describe('Negotiated protocol version string (e.g., "2025-11-21").'),hostInfo:D.describe("Host application identification and version."),hostCapabilities:t3.describe("Features and capabilities provided by the host."),hostContext:it.describe("Rich context about the host environment.")}).passthrough()),ia={target:"draft-2020-12"};async function io(e,t){let r=e["~standard"];if(r.jsonSchema)return r.jsonSchema[t](ia);if("zod"===r.vendor){let{z:r}=await Promise.resolve().then(i.bind(i,"H"));return r.toJSONSchema(e,{io:t})}throw Error(`Schema (vendor: ${r.vendor}) does not implement Standard JSON Schema (~standard.jsonSchema). Use a library that does (zod v4, ArkType, Valibot) or wrap your schema accordingly.`)}async function is(e,t,i=""){let r=await e["~standard"].validate(t);if(r.issues)throw Error(i+r.issues.map(e=>{let t=e.path?.map(e=>"object"==typeof e?e.key:e).join(".");return t?`${t}: ${e.message}`:e.message}).join("; "));return r.value}class il extends tV{_appInfo;_capabilities;options;_hostCapabilities;_hostInfo;_hostContext;_registeredTools={};_initializedSent=!1;_assertInitialized(e){if(this._initializedSent)return;let t=`[ext-apps] App.${e}() called before connect() completed the ui/initialize handshake. Await app.connect() before calling this method, or move data loading to an ontoolresult handler.`;if(this.options?.strict)throw Error(t);console.warn(`${t}. This will throw in a future release.`)}eventSchemas={toolinput:tQ,toolinputpartial:t0,toolresult:ie,toolcancelled:t4,hostcontextchanged:ii};static ONE_SHOT_EVENTS=new Set(["toolinput","toolinputpartial","toolresult","toolcancelled"]);_everHadListener=new Set;_assertHandlerTiming(e){if(!il.ONE_SHOT_EVENTS.has(e)||this._everHadListener.has(e)||(this._everHadListener.add(e),!this._initializedSent))return;let t=`[ext-apps] "${String(e)}" handler registered after connect() completed the ui/initialize handshake. The host may have already sent this notification. Register handlers before calling app.connect().`;if(this.options?.strict)throw Error(t);console.warn(t)}setEventHandler(e,t){t&&this._assertHandlerTiming(e),super.setEventHandler(e,t)}addEventListener(e,t){this._assertHandlerTiming(e),super.addEventListener(e,t)}onEventDispatch(e,t){"hostcontextchanged"===e&&(this._hostContext={...this._hostContext,...t})}constructor(e,t={},i={autoResize:!0}){super(i),this._appInfo=e,this._capabilities=t,this.options=i,i.allowUnsafeEval||tM.$W({jitless:!0}),this.setRequestHandler(F,e=>(console.log("Received ping:",e.params),{})),this.setEventHandler("hostcontextchanged",void 0)}registerCapabilities(e){if(this.transport)throw Error("Cannot register capabilities after transport is established");this._capabilities=function(e,t){let i={...e};for(let e in t){let r=t[e];if(void 0===r)continue;let n=i[e];tR(n)&&tR(r)?i[e]={...n,...r}:i[e]=r}return i}(this._capabilities,e)}registerTool(e,t,i){if(this._registeredTools[e])throw Error(`Tool ${e} is already registered`);let r=this,n=()=>{r._initializedSent&&r._capabilities.tools?.listChanged&&r.sendToolListChanged()},a=void 0!==t.inputSchema,o={title:t.title,description:t.description,inputSchema:t.inputSchema,outputSchema:t.outputSchema,annotations:t.annotations,_meta:t._meta,enabled:!0,enable(){this.enabled=!0,n()},disable(){this.enabled=!1,n()},update(e){Object.assign(this,e),n()},remove(){r._registeredTools[e]===o&&(delete r._registeredTools[e],n())},handler:async(t,r)=>{let n;if(!o.enabled)throw Error(`Tool ${e} is disabled`);if(a){let a=o.inputSchema,s=a?await is(a,t??{},`Invalid input for tool ${e}: `):t??{};n=await i(s,r)}else n=await i(r);return o.outputSchema&&!n.isError&&(n.structuredContent=await is(o.outputSchema,n.structuredContent,`Invalid output for tool ${e}: `)),n}};return this._registeredTools[e]=o,this._capabilities.tools||this.transport||this.registerCapabilities({tools:{listChanged:!0}}),this.ensureToolHandlersInitialized(),n(),o}_toolHandlersInitialized=!1;ensureToolHandlersInitialized(){this._toolHandlersInitialized||(this._toolHandlersInitialized=!0,this.oncalltool=async(e,t)=>{let i=this._registeredTools[e.name];if(!i)throw Error(`Tool ${e.name} not found`);return i.handler(e.arguments,t)},this.onlisttools=async(e,t)=>({tools:await Promise.all(Object.entries(this._registeredTools).filter(([e,t])=>t.enabled).map(async([e,t])=>{let i={name:e,title:t.title,description:t.description,inputSchema:t.inputSchema?await io(t.inputSchema,"input"):{type:"object",properties:{}}};return t.outputSchema&&(i.outputSchema=await io(t.outputSchema,"output")),t.annotations&&(i.annotations=t.annotations),t._meta&&(i._meta=t._meta),i}))}))}async sendToolListChanged(e={}){this._assertInitialized("sendToolListChanged"),await this.notification({method:"notifications/tools/list_changed",params:e})}getHostCapabilities(){return this._hostCapabilities}getHostVersion(){return this._hostInfo}getHostContext(){return this._hostContext}get ontoolinput(){return this.getEventHandler("toolinput")}set ontoolinput(e){this.setEventHandler("toolinput",e)}get ontoolinputpartial(){return this.getEventHandler("toolinputpartial")}set ontoolinputpartial(e){this.setEventHandler("toolinputpartial",e)}get ontoolresult(){return this.getEventHandler("toolresult")}set ontoolresult(e){this.setEventHandler("toolresult",e)}get ontoolcancelled(){return this.getEventHandler("toolcancelled")}set ontoolcancelled(e){this.setEventHandler("toolcancelled",e)}get onhostcontextchanged(){return this.getEventHandler("hostcontextchanged")}set onhostcontextchanged(e){this.setEventHandler("hostcontextchanged",e)}_onteardown;get onteardown(){return this._onteardown}set onteardown(e){this.warnIfRequestHandlerReplaced("onteardown",this._onteardown,e),this._onteardown=e,this.replaceRequestHandler(t2,(e,t)=>{if(!this._onteardown)throw Error("No onteardown handler set");return this._onteardown(e.params,t)})}_oncalltool;get oncalltool(){return this._oncalltool}set oncalltool(e){this.warnIfRequestHandlerReplaced("oncalltool",this._oncalltool,e),this._oncalltool=e,this.replaceRequestHandler(eY,(e,t)=>{if(!this._oncalltool)throw Error("No oncalltool handler set");return this._oncalltool(e.params,t)})}_onlisttools;get onlisttools(){return this._onlisttools}set onlisttools(e){this.warnIfRequestHandlerReplaced("onlisttools",this._onlisttools,e),this._onlisttools=e,this.replaceRequestHandler(eK,(e,t)=>{if(!this._onlisttools)throw Error("No onlisttools handler set");return this._onlisttools(e.params,t)})}assertCapabilityForMethod(e){if("sampling/createMessage"===e&&!this._hostCapabilities?.sampling)throw Error(`Host does not support sampling (required for ${e})`)}assertRequestHandlerCapability(e){switch(e){case"tools/call":case"tools/list":if(!this._capabilities.tools)throw Error(`Client does not support tool capability (required for ${e})`);return;case"ping":case"ui/resource-teardown":return;default:throw Error(`No handler for method ${e} registered`)}}assertNotificationCapability(e){}assertTaskCapability(e){throw Error("Tasks are not supported in MCP Apps")}assertTaskHandlerCapability(e){throw Error("Task handlers are not supported in MCP Apps")}async callServerTool(e,t){if(this._assertInitialized("callServerTool"),"string"==typeof e)throw Error(`callServerTool() expects an object as its first argument, but received a string ("${e}"). Did you mean: callServerTool({ name: "${e}", arguments: { ... } })?`);return await this.request({method:"tools/call",params:e},eG,{onprogress:()=>{},resetTimeoutOnProgress:!0,...t})}async readServerResource(e,t){return this._assertInitialized("readServerResource"),await this.request({method:"resources/read",params:e},eI,t)}async listServerResources(e,t){return this._assertInitialized("listServerResources"),await this.request({method:"resources/list",params:e},e$,t)}async createSamplingMessage(e,t){this._assertInitialized("createSamplingMessage");let i=e.tools?ta:tn;return await this.request({method:"sampling/createMessage",params:e},i,t)}sendMessage(e,t){return this._assertInitialized("sendMessage"),this.request({method:"ui/message",params:e},tG,t)}sendLog(e){return this.notification({method:"notifications/message",params:e})}updateModelContext(e,t){return this._assertInitialized("updateModelContext"),this.request({method:"ui/update-model-context",params:e},z,t)}openLink(e,t){return this._assertInitialized("openLink"),this.request({method:"ui/open-link",params:e},tK,t)}sendOpenLink=this.openLink;downloadFile(e,t){return this._assertInitialized("downloadFile"),this.request({method:"ui/download-file",params:e},tW,t)}requestTeardown(e={}){return this.notification({method:"ui/notifications/request-teardown",params:e})}requestDisplayMode(e,t){return this._assertInitialized("requestDisplayMode"),this.request({method:"ui/request-display-mode",params:e},t5,t)}sendSizeChanged(e){return this.notification({method:"ui/notifications/size-changed",params:e})}setupSizeChangedNotifications(){let e=!1,t=0,i=0,r=()=>{e||(e=!0,requestAnimationFrame(()=>{e=!1;let r=document.documentElement,n=r.style.height;r.style.height="max-content";let a=Math.ceil(r.getBoundingClientRect().height);r.style.height=n;let o=Math.ceil(window.innerWidth);(o!==t||a!==i)&&(t=o,i=a,this.sendSizeChanged({width:o,height:a}))}))};r();let n=new ResizeObserver(r);return n.observe(document.documentElement),n.observe(document.body),()=>n.disconnect()}async connect(e=new tq(window.parent,window.parent),t){if(this.transport)throw Error("App is already connected. Call close() before connecting again.");this._initializedSent=!1,await super.connect(e);try{let e=await this.request({method:"ui/initialize",params:{appCapabilities:this._capabilities,appInfo:this._appInfo,protocolVersion:"2026-01-26"}},ir,t);if(void 0===e)throw Error(`Server sent invalid initialize result: ${e}`);this._hostCapabilities=e.hostCapabilities,this._hostInfo=e.hostInfo,this._hostContext=e.hostContext,await this.notification({method:"ui/notifications/initialized"}),this._initializedSent=!0,this.options?.autoResize&&this.setupSizeChangedNotifications()}catch(e){throw this.close(),e}}}let iu=new Set(["projects","search","symbol","failure"]);function id(e){switch(e.kind){case"projects":return"/";case"project":return`/projects/${encodeURIComponent(e.project_id)}`;case"search":return`/projects/${encodeURIComponent(e.project_id)}/search?q=${encodeURIComponent(e.query)}`;case"symbol":return`/projects/${encodeURIComponent(e.project_id)}/symbols/${encodeURIComponent(e.node_id)}`}}let ic=document.getElementById("root");if(null===ic)throw Error("app root element missing");let im=new il({name:"tracedecay-code-explorer",version:"0.0.0"},{availableDisplayModes:["inline","fullscreen"]}),ip={phase:"connecting"},ig=[],iv=null;function ih(e){ip=e,iM()}function i$(){return"view"===ip.phase?ip.view:"loading"===ip.phase?ip.previous:null}function iy(e){"projects"===e.page&&"ready"===e.projects.state&&(ig=e.projects.data),ih({phase:"view",view:e}),ix(e)}function ib(e){var t;return"object"==typeof(t=e.structuredContent)&&null!==t&&"page"in t&&"string"==typeof t.page&&iu.has(t.page)?e.structuredContent:null}async function i_(e,t,i){ih({phase:"loading",label:i,previous:i$()});try{let i=await im.callServerTool({name:e,arguments:t}),r=ib(i);if(null===r)return void ih({phase:"host_error",message:`${e} returned no view payload`});iy(r)}catch(e){ih({phase:"host_error",message:e instanceof Error?e.message:String(e)})}}async function ix(e){let t=function(e){switch(e.page){case"projects":return null;case"search":var t;return{content:[{type:"text",text:`TraceDecay search in ${e.project.label} for "${e.query}": ${function(e,t){switch(e.state){case"ready":return t(e.data);case"empty":return e.message;case"failed":return`${e.failure.kind}: ${e.failure.message}`}}(e.results,e=>`${e.hits.length} hit(s), recall ${e.recall}${e.undisplayable.length>0?`, ${e.undisplayable.length} undisplayable`:""}`)}${null===(t=e.provenance)?"":` [reported project status: branch ${t.branch??"?"} commit ${t.commit??"?"} generation ${t.generation??"?"} freshness ${t.freshness.state}]`}`}],structuredContent:{page:"search",project_id:e.project.project_id,query:e.query,deep_link:id({kind:"search",project_id:e.project.project_id,query:e.query}),provenance:e.provenance}};case"symbol":if(null===e.evidence)return null;return{content:[{type:"text",text:e.evidence.markdown}],structuredContent:e.evidence.structured};case"failure":return{content:[{type:"text",text:`TraceDecay could not answer (${e.failure.kind}/${e.failure.code}): ${e.failure.message}`}],structuredContent:{page:"failure",failure:e.failure}}}}(e);if(null!==t)try{await im.updateModelContext(t)}catch{}}function iI(){i_("tracedecay_workspace",{},"Loading registered projects…")}function ik(e){iy({page:"search",project:e,query:"",results:{state:"empty",message:"Type a symbol name or phrase to search this project."},provenance:null})}function iw(e,t){i_("tracedecay_search_code",{project_id:e,query:t},`Searching for "${t}"…`)}function iS(e,t){i_("tracedecay_inspect_symbol",{project_id:e,node_id:t},"Loading symbol…")}function iz(e){let t,i="string"==typeof(t=Reflect.get(e,"openai/deepLink"))?t:"object"==typeof t&&null!==t&&"url"in t&&"string"==typeof t.url?t.url:null;if(null===i||i===iv)return;iv=i;let r=function(e){let t;try{t=new URL(e,"https://tracedecay.invalid")}catch{return null}let i=t.pathname.split("/").filter(e=>e.length>0).map(decodeURIComponent);if(0===i.length)return{kind:"projects"};if("projects"!==i[0]||void 0===i[1])return null;let r=i[1];return 2===i.length?{kind:"project",project_id:r}:"search"===i[2]&&3===i.length?{kind:"search",project_id:r,query:t.searchParams.get("q")??""}:"symbols"===i[2]&&void 0!==i[3]&&4===i.length?{kind:"symbol",project_id:r,node_id:i[3]}:null}(i);null!==r&&function(e){switch(e.kind){case"projects":iI();return;case"project":{let t=ig.find(t=>t.project_id===e.project_id);void 0!==t?ik(t):iw(e.project_id,"");return}case"search":iw(e.project_id,e.query);return;case"symbol":iS(e.project_id,e.node_id);return}}(r)}function ij(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=document.createElement(e);for(let[e,i]of Object.entries(t))r.setAttribute(e,i);return r.append(...i),r}function iP(e,t){let i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=ij("button",{type:"button",...i},[e]);return r.addEventListener("click",t),r}function iN(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"neutral",i=arguments.length>2?arguments[2]:void 0,r={class:"neutral"===t?"badge":`badge ${t}`};return void 0!==i&&(r["data-testid"]=i),ij("span",r,[e])}function iU(e){return"stale"===e.kind||"unavailable"===e.kind?"warn":"bad"}function iO(e){switch(e){case"current":case"fresh":return"ok";case"stale":case"possibly_stale":case"warming":case"restoring":return"warn";case"parked":case"unavailable":return"bad"}}function iD(e,t,i){return ij("p",{class:"neutral"===t?"notice":`notice ${t}`,"data-testid":i},[e])}function iT(e,t){let i=iD(`${e.message} (${e.code})`,iU(e),t);return i.prepend(iN(e.kind,iU(e),`${t}-kind`)," "),i}function iA(e,t,i){switch(e.state){case"ready":return i(e.data);case"empty":return iD(e.message,"neutral",`${t}-empty`);case"failed":return iT(e.failure,`${t}-failed`)}}function iZ(e,t,i){let r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:[];return ij("section",{class:"panel","data-testid":t},[ij("h2",{},[e,...r]),...i])}function iE(e,t){return iP(t.qualified_name||t.name,()=>iS(e,t.node_id),{class:"mono","data-testid":"symbol-link","data-node-id":t.node_id})}function iC(e){let t=null===e.start_line?"":`:${e.start_line}`;return ij("span",{class:"loc"},[`${e.file}${t}`])}function iL(e,t){let i=ij("input",{type:"search",name:"q",placeholder:`Search ${e.label}…`,value:t,"data-testid":"search-input","aria-label":"Search query"}),r=()=>{let t=i.value.trim();t.length>0&&iw(e.project_id,t)},n=ij("form",{class:"search","data-testid":"search-form"},[i,iP("Search",r,{class:"primary","data-testid":"search-submit"})]);return i.addEventListener("keydown",e=>{"Enter"===e.key&&(e.preventDefault(),r())}),n.addEventListener("submit",e=>e.preventDefault()),n}function iR(e,t){if(null===e)return iZ("Project status","provenance",[iD("Project status is reported once the project answers a request.","neutral","provenance-pending")]);let i=[["project",ij("code",{},[e.project_id])],["worktree",ij("code",{},[e.worktree_id??e.project_root])],["repository",ij("code",{},[e.repository_id??"—"])],["ref",e.reference??e.branch??"—"],["commit",ij("code",{"data-testid":"provenance-commit"},[e.commit??"—"])],["generation",ij("code",{},[e.generation??"—"])],["coverage",ij("span",{},[iN(e.coverage.recall,"full"===e.coverage.recall?"ok":"warn","coverage-badge"),null===e.coverage.detail?"":` ${e.coverage.detail}`])],["daemon",null===e.authority?"unavailable":`${e.authority.daemon_version} \xb7 pid ${e.authority.daemon_pid}`],["deep link",ij("code",{"data-testid":"deep-link"},[id(t)])]],r=ij("dl",{class:"prov"},i.flatMap(e=>{let[t,i]=e;return[ij("dt",{},[t]),ij("dd",{},[i])]})),n=iN(e.freshness.state,iO(e.freshness.state),"freshness-badge"),a=[r];return null!==e.freshness.detail&&a.unshift(iD(e.freshness.detail,"ok"===iO(e.freshness.state)?"neutral":"warn","freshness-detail")),iZ("Project status (separate read)","provenance",a,[n])}function iM(){ic.replaceChildren(function(e){let t=ij("nav",{class:"crumbs","aria-label":"Breadcrumb"});t.append(iP("Projects",iI,{"data-testid":"crumb-projects"}));let i=null!==e&&"projects"!==e.page?e.project:null;null!==i&&t.append("/",iP(i.label,()=>ik(i),{"data-testid":"crumb-project"})),e?.page==="search"&&""!==e.query&&t.append("/",ij("span",{},[`"${e.query}"`])),e?.page==="symbol"&&"ready"===e.symbol.state&&t.append("/",ij("span",{class:"mono"},[e.symbol.data.name]));let r=ij("header",{class:"bar"},[ij("h1",{},["TraceDecay"]),t,ij("span",{class:"spacer"})]),n=im.getHostContext()?.displayMode;if(void 0!==n){let e="fullscreen"===n?"inline":"fullscreen";r.append(iP("fullscreen"===e?"Expand":"Collapse",()=>void im.requestDisplayMode({mode:e}),{"data-testid":"toggle-display-mode"}))}return r}(i$()),...function(){switch(ip.phase){case"connecting":return[ij("p",{class:"loading","data-testid":"connecting"},["Connecting to ChatGPT…"])];case"loading":return[ij("p",{class:"loading","data-testid":"loading"},[ip.label])];case"host_error":return[iT({kind:"protocol",code:"host_call_failed",message:ip.message},"host-error"),ij("div",{class:"actions"},[iP("Back to projects",iI,{class:"primary","data-testid":"back-to-projects"})])];case"view":var e,t,i,r;switch(ip.view.page){case"projects":return["connected"===(e=ip.view).daemon.state?ij("p",{class:"notice","data-testid":"daemon-state"},[iN("connected","ok","daemon-badge"),` tracedecay ${e.daemon.version} (pid ${e.daemon.pid}) \xb7 profile `,ij("code",{},[e.daemon.profile_root])]):iT(e.daemon.failure,"daemon-state"),iZ("Recent registered projects","projects-panel",[iA(e.projects,"projects",e=>ij("ul",{class:"list"},e.map(e=>ij("li",{"data-testid":"project-row"},[iP(e.label,()=>ik(e),{class:"primary","data-testid":"project-open","data-project-id":e.project_id}),ij("span",{class:"loc"},[e.project_root]),null===e.head_branch?"":iN(e.head_branch)])))),ij("p",{class:"notice"},["Showing up to 10 recently used projects. Only projects registered in this TraceDecay profile (via `tracedecay init`) can be explored. Nothing here writes to your code."])])];case"search":let n;return n=iA((t=ip.view).results,"results",e=>{let i=[ij("ul",{class:"list"},e.hits.map(e=>ij("li",{"data-testid":"search-hit"},[iN(e.kind),iE(t.project.project_id,e),iC(e)])))];if("partial"===e.recall&&i.push(iD("Partial recall: the index is still converging, so some matches may be missing.","warn","results-partial")),e.truncated&&i.push(iD("Results were truncated to the first page.","neutral","results-truncated")),e.undisplayable.length>0){let t=[...new Set(e.undisplayable)].join(", ");i.push(iD(`${e.undisplayable.length} candidate(s) could not be displayed (${t}).`,"warn","results-undisplayable"))}return"ready"===t.results.state&&void 0!==t.results.generation&&t.provenance?.generation!==void 0&&t.results.generation!==t.provenance.generation&&i.push(iD(`Results were served from generation ${t.results.generation}, which differs from the reported project generation ${t.provenance.generation}.`,"warn","results-generation")),ij("div",{},i)}),[iL(t.project,t.query),iZ(""===t.query?"Search":`Results for "${t.query}"`,"results-panel",[n]),iR(t.provenance,{kind:"search",project_id:t.project.project_id,query:t.query})];case"symbol":let a,o,s,l,u,d,c;return a=(i=ip.view).project.project_id,o=iA(i.symbol,"symbol",e=>{let t=[ij("p",{},[iN(e.kind)," ",ij("code",{"data-testid":"symbol-qualified-name"},[e.qualified_name])," ",iC(e)])];return null!==e.signature&&t.push(ij("pre",{class:"mono"},[e.signature])),null!==e.complexity&&t.push(ij("p",{class:"notice"},[`Cyclomatic complexity ${e.complexity}`])),e.unavailable_fields.length>0&&t.push(iD(`Not available for this symbol: ${e.unavailable_fields.join(", ")}`,"neutral","symbol-unavailable-fields")),ij("div",{},t)}),s=(e,t)=>iA(e,t,r=>{let n=[ij("ul",{class:"list"},r.map(e=>ij("li",{"data-testid":`${t}-row`},[iN(e.edge_kind),iE(a,e.symbol),iC(e.symbol),e.dispatch_via_trait?iN("via trait"):""])))];return"ready"===e.state&&!0===e.truncated&&n.push(iD("Only the first page of relations is shown.","neutral",`${t}-truncated`)),"ready"===e.state&&void 0!==e.generation&&i.provenance?.generation!==void 0&&e.generation!==i.provenance.generation&&n.push(iD(`Served from generation ${e.generation}, which differs from the reported project generation ${i.provenance.generation}.`,"warn",`${t}-generation`)),ij("div",{},n)}),l=iA(i.impact,"impact",e=>{let t=[ij("ul",{class:"list"},e.nodes.map(e=>ij("li",{"data-testid":"impact-row"},[iN(`depth ${e.depth}`),iP(e.name,()=>iS(a,e.node_id),{class:"mono"}),ij("span",{class:"loc"},[`${e.file}:${e.line}`])])))];return t.push(e.complete?iD(`Complete within depth ${e.max_depth}.`,"neutral","impact-complete"):iD(`Partial: traversal stopped at depth ${e.max_depth}.`,"warn","impact-partial")),ij("div",{},t)}),u=iA(i.graph,"graph",e=>(function(e,t){let i=t.nodes.filter(e=>"caller"===e.role),r=t.nodes.filter(e=>"callee"===e.role),n=t.nodes.find(e=>"focus"===e.role),a=28*Math.max(i.length,r.length,1)+20,o="http://www.w3.org/2000/svg",s=document.createElementNS(o,"svg");s.setAttribute("class","graph"),s.setAttribute("viewBox",`0 0 640 ${a}`),s.setAttribute("role","img"),s.setAttribute("aria-label","Bounded caller/callee graph"),s.dataset.testid="graph";let l={caller:10,focus:220,callee:430},u=new Map,d=(t,i,r)=>{let n=l[r],d="focus"===r?a/2-10:10+28*i;u.set(t.node_id,{x:n,y:d});let c=document.createElementNS(o,"g");c.setAttribute("class",`node ${t.role}`),c.dataset.testid="graph-node",c.dataset.nodeId=t.node_id;let m=document.createElementNS(o,"rect");m.setAttribute("x",String(n)),m.setAttribute("y",String(d)),m.setAttribute("width","200"),m.setAttribute("height","20"),m.setAttribute("rx","4");let f=document.createElementNS(o,"text");f.setAttribute("x",String(n+6)),f.setAttribute("y",String(d+14)),f.textContent=t.name.length>28?`${t.name.slice(0,27)}…`:t.name;let p=document.createElementNS(o,"title");p.textContent=`${t.qualified_name} (${t.file})`,c.append(p,m,f),"focus"!==t.role&&c.addEventListener("click",()=>iS(e,t.node_id)),s.append(c)};for(let e of(i.forEach((e,t)=>d(e,t,"caller")),r.forEach((e,t)=>d(e,t,"callee")),void 0!==n&&d(n,0,"focus"),t.edges)){let t=u.get(e.from),i=u.get(e.to);if(void 0===t||void 0===i)continue;let r=document.createElementNS(o,"path");r.setAttribute("class","edge"),r.setAttribute("d",`M ${t.x+200} ${t.y+10} C ${t.x+240} ${t.y+10}, ${i.x-40} ${i.y+10}, ${i.x} ${i.y+10}`),s.prepend(r)}let c=ij("div",{},[s]);return t.truncated&&c.append(iD(`Graph bounded to depth ${t.max_depth}; more relations exist than shown.`,"neutral","graph-truncated")),c})(a,e)),d=ij("div",{class:"actions"}),null!==(c=i.evidence)&&d.append(iP("Send evidence to chat",()=>void im.sendMessage({role:"user",content:[{type:"text",text:c.markdown}]}),{class:"primary","data-testid":"send-evidence"}),iP("Re-share with model",()=>void ix(i),{"data-testid":"share-context"})),[iL(i.project,""),iZ("Symbol","symbol-panel",[o,iD("Symbol and impact reads do not report a generation; their snapshot identity is unverified.","neutral","symbol-generation"),d]),iZ("Callers","callers-panel",[s(i.callers,"callers")]),iZ("Callees","callees-panel",[s(i.callees,"callees")]),iZ("Impact","impact-panel",[l]),iZ("Graph","graph-panel",[u]),iR(i.provenance,"ready"===i.symbol.state?{kind:"symbol",project_id:a,node_id:i.symbol.data.node_id}:{kind:"project",project_id:a})];case"failure":let m;return m=[iT((r=ip.view).failure,"page-failure")],"denied"===r.failure.kind&&m.push(iD("Only projects registered in this TraceDecay profile can be explored. Run `tracedecay init` in the repository and reopen the workspace.","neutral","denied-help")),"disconnected"===r.failure.kind&&m.push(iD("Start the daemon with `tracedecay daemon run` (or any tracedecay command) and retry.","neutral","disconnected-help")),m.push(ij("div",{class:"actions"},[iP("Back to projects",iI,{class:"primary","data-testid":"back-to-projects"})])),null!==r.project&&m.unshift(iL(r.project,"")),[iZ("Request failed","failure-panel",m)]}}}()),ic.dataset.phase=ip.phase,ic.dataset.page=i$()?.page??""}im.ontoolinput=e=>{ih({phase:"loading",label:`Loading ${e.arguments?.query!==void 0?`search for "${String(e.arguments.query)}"`:"from TraceDecay"}…`,previous:i$()})},im.ontoolresult=e=>{let t=ib(e);null===t?ih({phase:"host_error",message:"The tool result carried no TraceDecay view payload."}):iy(t)},im.onhostcontextchanged=e=>{iz(e),iM()},iM(),im.connect().then(()=>{let e=im.getHostContext();void 0!==e&&iz(e),"connecting"===ip.phase&&ih({phase:"loading",label:"Waiting for TraceDecay…",previous:null})}).catch(e=>ih({phase:"host_error",message:e instanceof Error?e.message:String(e)}))})()})(); diff --git a/plugin/chatgpt-extension/rsbuild.config.ts b/plugin/chatgpt-extension/rsbuild.config.ts index d8bcd4277a..b3319c2298 100644 --- a/plugin/chatgpt-extension/rsbuild.config.ts +++ b/plugin/chatgpt-extension/rsbuild.config.ts @@ -7,6 +7,8 @@ export default defineConfig({ html: { template: "./src/app/index.html", inject: "body" }, output: { target: "web", + // Committed artifacts must not inherit browser targets from ancestor directories. + overrideBrowserslist: ["chrome >= 107", "edge >= 107", "firefox >= 104", "safari >= 16"], distPath: { root: "dist/app" }, inlineScripts: true, inlineStyles: true,