dsh-thoughtdag 0.4.9 → 0.4.11
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-app/assets/{canonical-Df0ckIdq.js → canonical-Cw94rYnE.js} +2 -2
- package/dist-app/assets/{canvas-record-CEy9ts1U.js → canvas-record-BYGoWCSi.js} +1 -1
- package/dist-app/assets/{claude-code-session-gxApIV4E.js → claude-code-session-D7_MMzYc.js} +1 -1
- package/dist-app/assets/{codex-session-rjwyINLc.js → codex-session-DVFc0JXs.js} +1 -1
- package/dist-app/assets/{dsh-session-9FrjljDY.js → dsh-session-BsZRbFip.js} +1 -1
- package/dist-app/assets/{experiment-loop-B8B2uvfc.js → experiment-loop-C9Q1W_wR.js} +1 -1
- package/dist-app/assets/http-bridge-mmwHcDuo.js +1 -0
- package/dist-app/assets/index-2pggDGtC.css +1 -0
- package/dist-app/assets/{index-Dbevq-w7.js → index-BEqQ5wV9.js} +1 -1
- package/dist-app/assets/{index-CCSkzpjj.js → index-Dyq9QwYZ.js} +3 -3
- package/dist-app/assets/index-Y8weIZcr.js +788 -0
- package/dist-app/assets/{index-DsWaXdBk.js → index-z0ZTt6U1.js} +1 -1
- package/dist-app/assets/{live-mirror-Bs_UiNg0.js → live-mirror-BlUlIINC.js} +2 -2
- package/dist-app/assets/{pi-session-_RCMhkfD.js → pi-session-wpL6N_gb.js} +1 -1
- package/dist-app/assets/{sensitive-scan-Dm_K56VK.js → sensitive-scan-Kz-yplyP.js} +1 -1
- package/dist-app/assets/{session-handoff-asoyabQy.js → session-handoff-BLHyTTl7.js} +2 -2
- package/dist-app/assets/{shared-BFDd9vhH.js → shared-BoxE2SdQ.js} +1 -1
- package/dist-app/assets/{turndown-plugin-gfm.cjs-DvWuwycM.js → turndown-plugin-gfm.cjs-2uYHu5V7.js} +1 -1
- package/dist-app/assets/{update-check-BhinDEBL.js → update-check-B1wesdxM.js} +1 -1
- package/dist-app/index.html +2 -2
- package/lib/client.js +8 -3
- package/lib/index.js +93 -7
- package/lib/runtime/agents/README.md +26 -0
- package/lib/runtime/agents/claude.cjs +303 -0
- package/lib/runtime/agents/codex.cjs +380 -0
- package/lib/runtime/agents/fs-diff.cjs +44 -0
- package/lib/runtime/agents/http.cjs +95 -0
- package/lib/runtime/agents/ops.cjs +54 -0
- package/lib/runtime/agents/pi-guard.mjs +81 -0
- package/lib/runtime/agents/pi.cjs +358 -0
- package/lib/runtime/sessions-fs.cjs +100 -0
- package/lib/runtime/terminal.cjs +105 -0
- package/package.json +1 -1
- package/dist-app/assets/index-BfIl0Oie.css +0 -1
- package/dist-app/assets/index-J-uxm9B7.js +0 -787
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{y as Os,z as pn,A as Is}from"./index-
|
|
1
|
+
import{y as Os,z as pn,A as Is}from"./index-Y8weIZcr.js";function Ns(e,n){for(var t=0;t<n.length;t++){const r=n[t];if(typeof r!="string"&&!Array.isArray(r)){for(const c in r)if(c!=="default"&&!(c in e)){const i=Object.getOwnPropertyDescriptor(r,c);i&&Object.defineProperty(e,c,i.get?i:{enumerable:!0,get:()=>r[c]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}var Ze={},Ii="1.13.8",Fa=typeof self=="object"&&self.self===self&&self||typeof global=="object"&&global.global===global&&global||Function("return this")()||{},nr=Array.prototype,Ni=Object.prototype,Ca=typeof Symbol<"u"?Symbol.prototype:null,Ls=nr.push,dt=nr.slice,it=Ni.toString,Ms=Ni.hasOwnProperty,$c=typeof ArrayBuffer<"u",qs=typeof DataView<"u",Ps=Array.isArray,Sa=Object.keys,Ba=Object.create,ka=$c&&ArrayBuffer.isView,zs=isNaN,js=isFinite,Yc=!{toString:null}.propertyIsEnumerable("toString"),Wa=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"],Xs=Math.pow(2,53)-1;function ze(e,n){return n=n==null?e.length-1:+n,function(){for(var t=Math.max(arguments.length-n,0),r=Array(t),c=0;c<t;c++)r[c]=arguments[c+n];switch(n){case 0:return e.call(this,r);case 1:return e.call(this,arguments[0],r);case 2:return e.call(this,arguments[0],arguments[1],r)}var i=Array(n+1);for(c=0;c<n;c++)i[c]=arguments[c];return i[n]=r,e.apply(this,i)}}function bn(e){var n=typeof e;return n==="function"||n==="object"&&!!e}function Kc(e){return e===null}function Li(e){return e===void 0}function Mi(e){return e===!0||e===!1||it.call(e)==="[object Boolean]"}function Qc(e){return!!(e&&e.nodeType===1)}function Pe(e){var n="[object "+e+"]";return function(t){return it.call(t)===n}}const tr=Pe("String"),qi=Pe("Number"),Jc=Pe("Date"),eu=Pe("RegExp"),nu=Pe("Error"),Pi=Pe("Symbol"),zi=Pe("ArrayBuffer");var tu=Pe("Function"),Vs=Fa.document&&Fa.document.childNodes;typeof/./!="function"&&typeof Int8Array!="object"&&typeof Vs!="function"&&(tu=function(e){return typeof e=="function"||!1});const qe=tu,ru=Pe("Object");var iu=qs&&(!/\[native code\]/.test(String(DataView))||ru(new DataView(new ArrayBuffer(8)))),ji=typeof Map<"u"&&ru(new Map),Hs=Pe("DataView");function Gs(e){return e!=null&&qe(e.getInt8)&&zi(e.buffer)}const at=iu?Gs:Hs,yn=Ps||Pe("Array");function Dn(e,n){return e!=null&&Ms.call(e,n)}var Ri=Pe("Arguments");(function(){Ri(arguments)||(Ri=function(e){return Dn(e,"callee")})})();const rr=Ri;function au(e){return!Pi(e)&&js(e)&&!isNaN(parseFloat(e))}function Xi(e){return qi(e)&&zs(e)}function Vi(e){return function(){return e}}function ou(e){return function(n){var t=e(n);return typeof t=="number"&&t>=0&&t<=Xs}}function cu(e){return function(n){return n?.[e]}}const Yt=cu("byteLength"),Zs=ou(Yt);var $s=/\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;function Ys(e){return ka?ka(e)&&!at(e):Zs(e)&&$s.test(it.call(e))}const Hi=$c?Ys:Vi(!1),Me=cu("length");function Ks(e){for(var n={},t=e.length,r=0;r<t;++r)n[e[r]]=!0;return{contains:function(c){return n[c]===!0},push:function(c){return n[c]=!0,e.push(c)}}}function uu(e,n){n=Ks(n);var t=Wa.length,r=e.constructor,c=qe(r)&&r.prototype||Ni,i="constructor";for(Dn(e,i)&&!n.contains(i)&&n.push(i);t--;)i=Wa[t],i in e&&e[i]!==c[i]&&!n.contains(i)&&n.push(i)}function Oe(e){if(!bn(e))return[];if(Sa)return Sa(e);var n=[];for(var t in e)Dn(e,t)&&n.push(t);return Yc&&uu(e,n),n}function su(e){if(e==null)return!0;var n=Me(e);return typeof n=="number"&&(yn(e)||tr(e)||rr(e))?n===0:Me(Oe(e))===0}function Gi(e,n){var t=Oe(n),r=t.length;if(e==null)return!r;for(var c=Object(e),i=0;i<r;i++){var a=t[i];if(n[a]!==c[a]||!(a in c))return!1}return!0}function Ae(e){if(e instanceof Ae)return e;if(!(this instanceof Ae))return new Ae(e);this._wrapped=e}Ae.VERSION=Ii;Ae.prototype.value=function(){return this._wrapped};Ae.prototype.valueOf=Ae.prototype.toJSON=Ae.prototype.value;Ae.prototype.toString=function(){return String(this._wrapped)};function Ra(e){return new Uint8Array(e.buffer||e,e.byteOffset||0,Yt(e))}var Oa="[object DataView]";function du(e,n){for(var t=[{a:e,b:n}],r=[],c=[];t.length;){var i=t.pop();if(i===!0){r.pop(),c.pop();continue}if(e=i.a,n=i.b,e===n){if(e!==0||1/e===1/n)continue;return!1}if(e==null||n==null)return!1;if(e!==e){if(n!==n)continue;return!1}var a=typeof e;if(a!=="function"&&a!=="object"&&typeof n!="object")return!1;e instanceof Ae&&(e=e._wrapped),n instanceof Ae&&(n=n._wrapped);var o=it.call(e);if(o!==it.call(n))return!1;if(iu&&o=="[object Object]"&&at(e)){if(!at(n))return!1;o=Oa}switch(o){case"[object RegExp]":case"[object String]":if(""+e==""+n)continue;return!1;case"[object Number]":t.push({a:+e,b:+n});continue;case"[object Date]":case"[object Boolean]":if(+e==+n)continue;return!1;case"[object Symbol]":if(Ca.valueOf.call(e)===Ca.valueOf.call(n))continue;return!1;case"[object ArrayBuffer]":case Oa:t.push({a:Ra(e),b:Ra(n)});continue}var u=o==="[object Array]";if(!u&&Hi(e)){var h=Yt(e);if(h!==Yt(n))return!1;if(e.buffer===n.buffer&&e.byteOffset===n.byteOffset)continue;u=!0}if(!u){if(typeof e!="object"||typeof n!="object")return!1;var b=e.constructor,m=n.constructor;if(b!==m&&!(qe(b)&&b instanceof b&&qe(m)&&m instanceof m)&&"constructor"in e&&"constructor"in n)return!1}for(var g=r.length;g--;)if(r[g]===e){if(c[g]===n)break;return!1}if(!(g>=0))if(r.push(e),c.push(n),t.push(!0),u){if(g=e.length,g!==n.length)return!1;for(;g--;)t.push({a:e[g],b:n[g]})}else{var f=Oe(e),y;if(g=f.length,Oe(n).length!==g)return!1;for(;g--;){if(y=f[g],!Dn(n,y))return!1;t.push({a:e[y],b:n[y]})}}}return!0}function jn(e){if(!bn(e))return[];var n=[];for(var t in e)n.push(t);return Yc&&uu(e,n),n}function Zi(e){var n=Me(e);return function(t){if(t==null)return!1;var r=jn(t);if(Me(r))return!1;for(var c=0;c<n;c++)if(!qe(t[e[c]]))return!1;return e!==hu||!qe(t[$i])}}var $i="forEach",lu="has",Yi=["clear","delete"],fu=["get",lu,"set"],Qs=Yi.concat($i,fu),hu=Yi.concat(fu),Js=["add"].concat(Yi,$i,lu);const pu=ji?Zi(Qs):Pe("Map"),gu=ji?Zi(hu):Pe("WeakMap"),mu=ji?Zi(Js):Pe("Set"),bu=Pe("WeakSet");function kn(e){for(var n=Oe(e),t=n.length,r=Array(t),c=0;c<t;c++)r[c]=e[n[c]];return r}function yu(e){for(var n=Oe(e),t=n.length,r=Array(t),c=0;c<t;c++)r[c]=[n[c],e[n[c]]];return r}function Ki(e){for(var n={},t=Oe(e),r=0,c=t.length;r<c;r++)n[e[t[r]]]=t[r];return n}function ot(e){var n=[];for(var t in e)qe(e[t])&&n.push(t);return n.sort()}function Qi(e,n){return function(t){var r=arguments.length;if(n&&(t=Object(t)),r<2||t==null)return t;for(var c=1;c<r;c++)for(var i=arguments[c],a=e(i),o=a.length,u=0;u<o;u++){var h=a[u];(!n||t[h]===void 0)&&(t[h]=i[h])}return t}}const Ji=Qi(jn),Pn=Qi(Oe),ea=Qi(jn,!0);function ed(){return function(){}}function Du(e){if(!bn(e))return{};if(Ba)return Ba(e);var n=ed();n.prototype=e;var t=new n;return n.prototype=null,t}function vu(e,n){var t=Du(e);return n&&Pn(t,n),t}function xu(e){return bn(e)?yn(e)?e.slice():Ji({},e):e}function _u(e,n){return n(e),e}function na(e){return yn(e)?e:[e]}Ae.toPath=na;function lt(e){return Ae.toPath(e)}function ta(e,n){for(var t=n.length,r=0;r<t;r++){if(e==null)return;e=e[n[r]]}return t?e:void 0}function ra(e,n,t){var r=ta(e,lt(n));return Li(r)?t:r}function Uu(e,n){n=lt(n);for(var t=n.length,r=0;r<t;r++){var c=n[r];if(!Dn(e,c))return!1;e=e[c]}return!!t}function ir(e){return e}function Bn(e){return e=Pn({},e),function(n){return Gi(n,e)}}function ar(e){return e=lt(e),function(n){return ta(n,e)}}function ft(e,n,t){if(n===void 0)return e;switch(t??3){case 1:return function(r){return e.call(n,r)};case 3:return function(r,c,i){return e.call(n,r,c,i)};case 4:return function(r,c,i,a){return e.call(n,r,c,i,a)}}return function(){return e.apply(n,arguments)}}function Tu(e,n,t){return e==null?ir:qe(e)?ft(e,n,t):bn(e)&&!yn(e)?Bn(e):ar(e)}function or(e,n){return Tu(e,n,1/0)}Ae.iteratee=or;function je(e,n,t){return Ae.iteratee!==or?Ae.iteratee(e,n):Tu(e,n,t)}function wu(e,n,t){n=je(n,t);for(var r=Oe(e),c=r.length,i={},a=0;a<c;a++){var o=r[a];i[o]=n(e[o],o,e)}return i}function ia(){}function Eu(e){return e==null?ia:function(n){return ra(e,n)}}function Au(e,n,t){var r=Array(Math.max(0,e));n=ft(n,t,1);for(var c=0;c<e;c++)r[c]=n(c);return r}function Kt(e,n){return n==null&&(n=e,e=0),e+Math.floor(Math.random()*(n-e+1))}const zn=Date.now||function(){return new Date().getTime()};function Fu(e){var n=function(i){return e[i]},t="(?:"+Oe(e).join("|")+")",r=RegExp(t),c=RegExp(t,"g");return function(i){return i=i==null?"":""+i,r.test(i)?i.replace(c,n):i}}const Cu={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},Su=Fu(Cu),nd=Ki(Cu),Bu=Fu(nd),ku=Ae.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var Fr=/(.)^/,td={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},rd=/\\|'|\r|\n|\u2028|\u2029/g;function id(e){return"\\"+td[e]}var ad=/^\s*(\w|\$)+\s*$/;function Wu(e,n,t){!n&&t&&(n=t),n=ea({},n,Ae.templateSettings);var r=RegExp([(n.escape||Fr).source,(n.interpolate||Fr).source,(n.evaluate||Fr).source].join("|")+"|$","g"),c=0,i="__p+='";e.replace(r,function(h,b,m,g,f){return i+=e.slice(c,f).replace(rd,id),c=f+h.length,b?i+=`'+
|
|
2
2
|
((__t=(`+b+`))==null?'':_.escape(__t))+
|
|
3
3
|
'`:m?i+=`'+
|
|
4
4
|
((__t=(`+m+`))==null?'':__t)+
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-
|
|
2
|
-
import{_ as l,i as
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-Y8weIZcr.js","assets/index-2pggDGtC.css","assets/experiment-loop-C9Q1W_wR.js","assets/index-Dyq9QwYZ.js","assets/canonical-Cw94rYnE.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{_ as l,i as b,t as p,a as h,f as R}from"./index-Y8weIZcr.js";function K(d,S){return d.find(y=>(y.rel.split("/").pop()??y.rel).includes(S))}let j=!1,I=null;function H(){I?.()}function z(){const d=window.desktopSessions;if(!d||j)return;j=!0,d.watchStart();let S=!1,y=null;const g=async s=>{if(S){y=s;return}S=!0;try{window.dispatchEvent(new CustomEvent("td:sessions-changed"));const{useProjects:a,subscribedSessionIds:i}=await l(async()=>{const{useProjects:w,subscribedSessionIds:E}=await import("./index-Y8weIZcr.js").then(D=>D.H);return{useProjects:w,subscribedSessionIds:E}},__vite__mapDeps([0,1])),{activeId:c,projects:o}=a.getState(),m=o.find(w=>w.id===c),t=await d.head(s.rootKey,s.rel,262144).catch(()=>"");if(!t)return;const e=b(t);if(!e)return;const f=!!m&&i(m).includes(e);let r=null;if(!f){if(o.some(v=>i(v).includes(e)))return;const{useStore:E}=await l(async()=>{const{useStore:v}=await import("./index-Y8weIZcr.js").then(A=>A.G);return{useStore:v}},__vite__mapDeps([0,1]));if(!E.getState().nodes.some(v=>v.data.importSource?.sessionId===e)){const{parseAnchor:v}=await l(async()=>{const{parseAnchor:k}=await import("./experiment-loop-C9Q1W_wR.js");return{parseAnchor:k}},__vite__mapDeps([2,0,1])),A=v(t);if(!A||!o.some(k=>k.id===A.project))return;if(r=A.project,r!==c){p("info",h("atlas.mountPending"),9e3);return}}}const{streamRunnerConversation:n}=await l(async()=>{const{streamRunnerConversation:w}=await import("./index-Dyq9QwYZ.js");return{streamRunnerConversation:w}},__vite__mapDeps([3,0,1])),{importOrAppendConversation:u,shellSessionReader:_}=await l(async()=>{const{importOrAppendConversation:w,shellSessionReader:E}=await import("./canonical-Cw94rYnE.js");return{importOrAppendConversation:w,shellSessionReader:E}},__vite__mapDeps([4,0,1])),V=await n(_(s.rootKey,s.rel)).catch(()=>null),P=await u(V);P?.kind==="appended"?p("success",R(h("atlas.liveAppended"),{n:P.turns}),8e3):P?.kind==="mounted"&&p("success",R(h(P.mode==="continue"?"atlas.mountedChapter":"atlas.mountedBranch"),{n:P.turns}),9e3)}finally{if(S=!1,y){const a=y;y=null,g(a)}}};d.onSessionsChanged(s=>{g(s)});const C=async s=>{if(!s)return;const{useStore:a}=await l(async()=>{const{useStore:o}=await import("./index-Y8weIZcr.js").then(m=>m.G);return{useStore:o}},__vite__mapDeps([0,1])),{useUiStore:i}=await l(async()=>{const{useUiStore:o}=await import("./index-Y8weIZcr.js").then(m=>m.D);return{useUiStore:o}},__vite__mapDeps([0,1])),c=a.getState().nodes.find(o=>o.data.importSource?.itemIds?.includes(s));c&&i.getState().setArrivalFocusNodeId(c.id)},T=async(s,a)=>{const{useProjects:i,switchProject:c}=await l(async()=>{const{useProjects:e,switchProject:f}=await import("./index-Y8weIZcr.js").then(r=>r.H);return{useProjects:e,switchProject:f}},__vite__mapDeps([0,1])),o=i.getState().projects,m=o.filter(e=>e.name===s),t=o.find(e=>e.id===s)??(m.length===1?m[0]:void 0);if(!t){p("error",h("handoff.deeplinkMiss"));return}if(await c(t.id),a){const{useStore:e}=await l(async()=>{const{useStore:r}=await import("./index-Y8weIZcr.js").then(n=>n.G);return{useStore:r}},__vite__mapDeps([0,1])),{useUiStore:f}=await l(async()=>{const{useUiStore:r}=await import("./index-Y8weIZcr.js").then(n=>n.D);return{useUiStore:r}},__vite__mapDeps([0,1]));e.getState().nodes.some(r=>r.id===a)&&f.getState().setArrivalFocusNodeId(a)}},O=async s=>{let a="",i="";try{const n=new URL(s),u=n.searchParams.get("canvas");if(u){await T(u,n.searchParams.get("node")??"");return}a=n.searchParams.get("session")??"",i=n.searchParams.get("turn")??""}catch{return}if(!/^[A-Za-z0-9_-]{8,}$/.test(a))return;/^[A-Za-z0-9_-]*$/.test(i)||(i="");const c=await d.roots().catch(()=>[]);let o=null;for(const n of c){const u=await d.list(n.key).catch(()=>[]),_=K(u,a);if(_){o={rootKey:n.key,rel:_.rel};break}}if(!o){const n=[];for(const u of c)for(const _ of await d.list(u.key).catch(()=>[]))n.push({rootKey:u.key,rel:_.rel,mtime:_.mtime});n.sort((u,_)=>_.mtime-u.mtime);for(const u of n.slice(0,40)){const _=await d.head(u.rootKey,u.rel,262144).catch(()=>"");if(_&&b(_)===a){o=u;break}}}if(!o){p("error",h("handoff.deeplinkMiss"));return}const{streamRunnerConversation:m}=await l(async()=>{const{streamRunnerConversation:n}=await import("./index-Dyq9QwYZ.js");return{streamRunnerConversation:n}},__vite__mapDeps([3,0,1])),{importOrAppendConversation:t,shellSessionReader:e}=await l(async()=>{const{importOrAppendConversation:n,shellSessionReader:u}=await import("./canonical-Cw94rYnE.js");return{importOrAppendConversation:n,shellSessionReader:u}},__vite__mapDeps([4,0,1])),f=await m(e(o.rootKey,o.rel)).catch(()=>null),r=await t(f);r?r.kind==="appended"?p("success",R(h("atlas.liveAppended"),{n:r.turns}),8e3):r.kind==="mounted"?p("success",R(h(r.mode==="continue"?"atlas.mountedChapter":"atlas.mountedBranch"),{n:r.turns}),9e3):r.kind==="imported"&&p("success",R(h("toast.importedChats"),{n:1,m:r.nodeCount}),8e3):p("error",h("handoff.notASession")),r&&i&&await C(i)};d.onDeepLink?.(s=>{O(s)}),(async()=>{const{bootProjects:s}=await l(async()=>{const{bootProjects:i}=await import("./index-Y8weIZcr.js").then(c=>c.H);return{bootProjects:i}},__vite__mapDeps([0,1]));await s();const a=await d.pendingDeepLink?.().catch(()=>null);a&&O(a)})();const L="thoughtdag.atlas.sweepmark";I=async()=>{const{bootProjects:s}=await l(async()=>{const{bootProjects:t}=await import("./index-Y8weIZcr.js").then(e=>e.H);return{bootProjects:t}},__vite__mapDeps([0,1]));await s();const a=await d.roots().catch(()=>[]),i=[];for(const t of a){const e=await d.list(t.key).catch(()=>[]);for(const f of e)i.push({rootKey:t.key,rel:f.rel,mtime:f.mtime,size:f.size})}let c={};try{c=JSON.parse(localStorage.getItem(L)??"{}")}catch{}const o=Object.keys(c).length===0;i.sort((t,e)=>e.mtime-t.mtime);const m=i.filter((t,e)=>{const f=`${t.mtime}|${t.size}`;return c[`${t.rootKey}|${t.rel}`]===f?!1:o?e<30:!0});for(const t of m)await g({rootKey:t.rootKey,rel:t.rel});for(const t of i)c[`${t.rootKey}|${t.rel}`]=`${t.mtime}|${t.size}`;localStorage.setItem(L,JSON.stringify(c))},I()}export{K as pickSessionFile,z as startLiveMirror,H as sweepRecentSessions};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{v as w,B as x,o as T}from"./index-
|
|
1
|
+
import{v as w,B as x,o as T}from"./index-Y8weIZcr.js";import{t as A,a as I,e as l,d as C,T as L,A as h,g as m,f as O,s as S}from"./shared-BoxE2SdQ.js";const f=r=>typeof r=="string"?r:Array.isArray(r)?r.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
|
|
2
2
|
`):"";function b(r,t){const s=t&&typeof t=="object"?t:{},e=I(r),n=typeof s.path=="string"&&s.path&&(e==="read"||e==="edit"||e==="write")?[s.path]:[];let o;if(e==="read"&&(typeof s.offset=="number"||typeof s.limit=="number")){const c=Math.max(1,typeof s.offset=="number"?s.offset:1),d=typeof s.limit=="number"?c+Math.max(0,s.limit)-1:c;o={lines:[c,Math.max(c,d)]}}if(e==="write"&&typeof s.content=="string")return{...l(`${s.path??""}
|
|
3
3
|
|
|
4
4
|
${s.content}`,h),paths:n};if(e==="edit"){const c=Array.isArray(s.edits)?s.edits:typeof s.newText=="string"?[{oldText:s.oldText,newText:s.newText}]:[];if(c.length){const d=c.map(i=>`${s.path??""}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{f as c,a,w as g}from"./index-
|
|
1
|
+
import{f as c,a,w as g}from"./index-Y8weIZcr.js";const k=[{kind:"sk-… key",re:/\bsk-[A-Za-z0-9_-]{16,}\b/g},{kind:"GitHub token",re:/\bgh[pousr]_[A-Za-z0-9]{20,}\b/g},{kind:"AWS access key",re:/\bAKIA[0-9A-Z]{16}\b/g},{kind:"Slack token",re:/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g},{kind:"Google API key",re:/\bAIza[0-9A-Za-z_-]{35}\b/g},{kind:"JWT",re:/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{6,}\b/g},{kind:"private key block",re:/-----BEGIN [A-Z ]*PRIVATE KEY-----/g},{kind:"token assignment",re:/\b(?:API_KEY|APIKEY|SECRET|TOKEN|PASSWORD|ACCESS_KEY|AUTH_TOKEN)[A-Z_]*\s*[=:]\s*['"]?[A-Za-z0-9_/+-]{16,}/g},{kind:"HuggingFace token",re:/\bhf_[A-Za-z0-9]{30,}\b/g},{kind:"npm token",re:/\bnpm_[A-Za-z0-9]{30,}\b/g}],f=t=>t.length<=10?`${t.slice(0,4)}…`:`${t.slice(0,6)}…${t.slice(-2)}`;function o(t,e,s){if(t)for(const{kind:i,re:n}of k){n.lastIndex=0;const r=n.exec(t);if(r&&s.push({where:e,kind:i,sample:f(r[0])}),s.length>=20)return}}function l(t){const e=[];for(const s of t){const i=(s.data.question||s.data.summaries?.[0]||s.id).replace(/\s+/g," ").slice(0,28);o(s.data.question,i,e);for(const n of s.data.responses??[])o(n,i,e);for(const n of s.data.attachments??[])n.type.startsWith("image/")||o(n.content,`${i} · ${n.name}`,e);if(e.length>=20)break}return e}async function b(t){const e=l(t);if(e.length===0)return!0;const s=e.slice(0,5).map(n=>`· ${n.where} — ${n.kind}(${n.sample})`).join(`
|
|
2
2
|
`),i=e.length>5?`
|
|
3
3
|
${c(a("sensitive.more"),{n:e.length-5})}`:"";return g({title:a("sensitive.title"),message:`${c(a("sensitive.body"),{n:e.length})}
|
|
4
4
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/canonical-
|
|
2
|
-
import{t as n,a as e,_ as p,f as a,u as h}from"./index-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/canonical-Cw94rYnE.js","assets/index-Y8weIZcr.js","assets/index-2pggDGtC.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{t as n,a as e,_ as p,f as a,u as h}from"./index-Y8weIZcr.js";const l=/^http:\/\/(127\.0\.0\.1|localhost|\[::1\])(:\d+)?\//i;async function w(){const s=window.location.hash,r=s.match(/[#&]import-url=([^&]+)/);if(!r)return;const c=/[#&]mode=harvest\b/.test(s);history.replaceState(null,"",window.location.pathname+window.location.search);const i=decodeURIComponent(r[1]);if(!l.test(i)){n("error",e("handoff.notLoopback"),9e3);return}try{const o=await fetch(i);if(!o.ok)throw new Error(`HTTP ${o.status}`);const d=await o.text(),{importOrAppendSession:f}=await p(async()=>{const{importOrAppendSession:u}=await import("./canonical-Cw94rYnE.js");return{importOrAppendSession:u}},__vite__mapDeps([0,1,2])),t=await f(d);if(!t)throw new Error(e("handoff.notASession"));t.kind==="appended"?n("success",a(e("atlas.appended"),{n:t.turns}),9e3):t.kind==="mounted"?n("success",a(e(t.mode==="continue"?"atlas.mountedChapter":"atlas.mountedBranch"),{n:t.turns}),12e3):t.kind==="opened"?n("info",e("atlas.upToDate"),6e3):n("info",a(e("handoff.saved"),{n:t.nodeCount}),12e3,{label:e("handoff.backupAction"),run:()=>h.getState().setBackupDialogOpen(!0)})}catch(o){n("error",a(e("handoff.failed"),{msg:o instanceof Error?o.message:String(o)}),12e3)}}export{w as consumeSessionHandoff};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{v as m,o as p,B as h,C as g}from"./index-
|
|
1
|
+
import{v as m,o as p,B as h,C as g}from"./index-Y8weIZcr.js";const _=[[/^(Read|NotebookRead|read_file|view_image)$/i,"read"],[/^(Write|write_file)$/i,"write"],[/^(Edit|MultiEdit|NotebookEdit|apply_patch)$/i,"edit"],[/^(Bash|BashOutput|Shell|exec_command|local_shell|write_stdin)$/i,"run"],[/^(Grep|Glob|LS|Search|WebSearch|web_search)$/i,"search"],[/^(WebFetch|Fetch)$/i,"fetch"],[/^(Task|Agent)$/i,"agent"]];function y(e){return _.find(([t])=>t.test(e))?.[1]??"other"}const x=800,O=32e3,S=4e3,I=(e,t)=>e.length>t?{text:`${e.slice(0,t)}
|
|
2
2
|
…[truncated, ${e.length} chars total]`,truncated:!0}:{text:e,truncated:!1},$=["<command-name>/thoughtdag</command-name>","[[thoughtdag:command]]"];function M(e){return e.filter(t=>!$.some(n=>t.question.includes(n)))}function w(e){e.width=460}function b(e){const t=g(e.data.response,90);t&&(e.data.summaries=[t])}function L(e){return e.tools.map(t=>({id:p(),name:`tool: ${t.name}${t.truncated?" (truncated)":""}`,type:"text/plain",size:t.call.length+t.result.length,content:`[call] ${t.call}
|
|
3
3
|
[result]
|
|
4
4
|
${t.result}`,...t.paths?.length?{paths:t.paths}:{},...t.op?{op:t.op}:{}}))}function k(e,t,n,s,i){if(e.length===0)return null;const r=[],l=[];let u={id:s.id};for(const o of e){const a=m(o.question||"(tool-only turn)",o.response,!1);a.data.importSource={runner:n,sessionId:t,itemIds:o.itemIds,...i?{cwd:i}:{}},a.data.source={question:a.data.question,response:a.data.response},a.data.attachments=L(o),b(a),r.length===0&&(a.data.isBranch=!0),r.push(a),l.push({id:p(),source:u.id,target:a.id,type:"smoothstep"}),u=a}const c=h(r,l.filter(o=>o.source!==s.id)),f=Math.min(...c.map(o=>o.position.x)),d=Math.min(...c.map(o=>o.position.y));for(const o of c)o.position={x:o.position.x-f+s.x+560,y:o.position.y-d+s.y};return{nodes:c,edges:l,turnCount:e.length}}function A(e){const t=e??{},n={};typeof t.url=="string"&&/^https?:\/\//.test(t.url)&&(n.url=t.url);const s={};if(typeof t.pages=="string"&&t.pages.trim()&&(s.pages=t.pages.trim()),typeof t.offset=="number"||typeof t.limit=="number"){const i=Math.max(1,typeof t.offset=="number"?t.offset:1),r=typeof t.limit=="number"?i+Math.max(0,t.limit)-1:i;s.lines=[i,Math.max(i,r)]}return Object.keys(s).length&&(n.locator=s),n}function C(e){const t=e??{},n=t.file_path??t.notebook_path;return typeof n=="string"&&n?[n]:[]}function q(e,t){const n=t??{},s=y(e);return s==="write"&&typeof n.content=="string"?`${n.file_path??""}
|
package/dist-app/assets/{turndown-plugin-gfm.cjs-DvWuwycM.js → turndown-plugin-gfm.cjs-2uYHu5V7.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{A as W}from"./index-
|
|
1
|
+
import{A as W}from"./index-Y8weIZcr.js";function Y(d,p){for(var g=0;g<p.length;g++){const s=p[g];if(typeof s!="string"&&!Array.isArray(s)){for(const c in s)if(c!=="default"&&!(c in d)){const o=Object.getOwnPropertyDescriptor(s,c);o&&Object.defineProperty(d,c,o.get?o:{enumerable:!0,get:()=>s[c]})}}}return Object.freeze(Object.defineProperty(d,Symbol.toStringTag,{value:"Module"}))}var u={},E;function J(){if(E)return u;E=1,Object.defineProperty(u,"__esModule",{value:!0});var d=/highlight-(?:text|source)-([a-z0-9]+)/;function p(t){t.addRule("highlightedCodeBlock",{filter:function(e){var r=e.firstChild;return e.nodeName==="DIV"&&d.test(e.className)&&r&&r.nodeName==="PRE"},replacement:function(e,r,n){var l=r.className||"",i=(l.match(d)||[null,""])[1];return`
|
|
2
2
|
|
|
3
3
|
`+n.fence+i+`
|
|
4
4
|
`+r.firstChild.textContent+`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as u,a as n,f}from"./index-
|
|
1
|
+
import{t as u,a as n,f}from"./index-Y8weIZcr.js";const h=15*6e4;let i=!1;const d=new URLSearchParams(window.location.search),s=d.get("dv"),p=d.get("su")==="1",w=30*6e4;let c=!1,r=0;async function a(){if(!(!s||p||c)&&!(Date.now()-r<w)){r=Date.now();try{const t=await fetch("https://api.github.com/repos/chenxiachan/thoughtdag/releases?per_page=1");if(!t.ok)return;const o=(await t.json())?.[0]?.tag_name?.replace(/^v/,"");if(!o||o===s)return;c=!0,u("info",f(n("update.desktopAvailable"),{v:o}),0,{label:n("update.desktopDownload"),run:()=>window.open("https://chenxiachan.github.io/thoughtdag/#download","_blank")})}catch{}}}function v(){for(const t of document.querySelectorAll("script[src]")){const e=t.src.match(/assets\/index-[^/?#]+\.js/);if(e)return e[0]}return null}async function m(){try{const t=await fetch(`${window.location.pathname}?u=${Date.now()}`,{cache:"no-store"});if(!t.ok)return null;const e=(await t.text()).match(/assets\/index-[^"'?#]+\.js/);return e?e[0]:null}catch{return null}}async function l(){if(i)return;const t=v();if(!t)return;const e=await m();e&&e!==t&&(i=!0,u("info",n("update.available"),0,{label:n("update.refresh"),run:()=>window.location.reload()}))}function b(){document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&(l(),a())}),setInterval(()=>{l(),a()},h),s&&setTimeout(()=>{a()},5e3)}export{b as bootUpdateCheck};
|
package/dist-app/index.html
CHANGED
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
<meta name="twitter:title" content="ThoughtDAG — Your thinking deserves a map" />
|
|
23
23
|
<meta name="twitter:description" content="Wires are the context: an infinite canvas where LLM conversations grow into an editable thought graph. No signup; the example canvas needs no key." />
|
|
24
24
|
<meta name="twitter:image" content="https://app.thoughtdag.workers.dev/og-twitter.jpg" />
|
|
25
|
-
<script type="module" crossorigin src="/thoughtdag/assets/index-
|
|
26
|
-
<link rel="stylesheet" crossorigin href="/thoughtdag/assets/index-
|
|
25
|
+
<script type="module" crossorigin src="/thoughtdag/assets/index-Y8weIZcr.js"></script>
|
|
26
|
+
<link rel="stylesheet" crossorigin href="/thoughtdag/assets/index-2pggDGtC.css">
|
|
27
27
|
</head>
|
|
28
28
|
<body>
|
|
29
29
|
<div id="root"></div>
|
package/lib/client.js
CHANGED
|
@@ -33,6 +33,10 @@ window.__ModuleLoader__.load({
|
|
|
33
33
|
host.innerHTML = '<div class="dsh-td-switch" role="group" aria-label="view switch"><button type="button" data-view="dialog" class="active" aria-pressed="true">对话</button><button type="button" data-view="map" aria-pressed="false">思维图</button></div><section class="dsh-td-overlay" hidden><iframe title="ThoughtDAG" data-src="/thoughtdag/"></iframe></section>'
|
|
34
34
|
document.body.append(host)
|
|
35
35
|
|
|
36
|
+
// the plugin's version, for the canvas's update dialog and release history
|
|
37
|
+
let pluginVersion = null
|
|
38
|
+
fetch('/thoughtdag/api/version').then(r => (r.ok ? r.json() : null)).then(j => { if (j && typeof j.version === 'string') pluginVersion = j.version }).catch(() => {})
|
|
39
|
+
|
|
36
40
|
const dialogBtn = host.querySelector('[data-view="dialog"]')
|
|
37
41
|
const mapBtn = host.querySelector('[data-view="map"]')
|
|
38
42
|
const overlay = host.querySelector('.dsh-td-overlay')
|
|
@@ -44,7 +48,7 @@ window.__ModuleLoader__.load({
|
|
|
44
48
|
mapBtn.classList.toggle('active', map)
|
|
45
49
|
mapBtn.setAttribute('aria-pressed', String(map))
|
|
46
50
|
}
|
|
47
|
-
const close = () => { overlay.hidden = true; setView(false) }
|
|
51
|
+
const close = () => { overlay.hidden = true; setView(false); send('td:view', { shown: false }) }
|
|
48
52
|
const send = (type, payload) => frame.contentWindow?.postMessage({ source: 'dsh-thoughtdag', type, ...payload }, location.origin)
|
|
49
53
|
|
|
50
54
|
const syncCurrent = () => {
|
|
@@ -58,10 +62,11 @@ window.__ModuleLoader__.load({
|
|
|
58
62
|
// the SPA boots on first open, never while hidden: a canvas that
|
|
59
63
|
// measures itself inside a display:none frame fits its view to a 0×0
|
|
60
64
|
// box and shows nothing when revealed
|
|
61
|
-
if (!frame.src) frame.src = frame.dataset.src
|
|
65
|
+
if (!frame.src) frame.src = frame.dataset.src + (pluginVersion ? (frame.dataset.src.includes('?') ? '&' : '?') + 'dv=' + encodeURIComponent(pluginVersion) : '')
|
|
62
66
|
syncCurrent()
|
|
67
|
+
send('td:view', { shown: true })
|
|
63
68
|
// let the SPA boot, then re-sync so its listener is ready
|
|
64
|
-
window.setTimeout(syncCurrent, 400)
|
|
69
|
+
window.setTimeout(() => { syncCurrent(); send('td:view', { shown: true }) }, 400)
|
|
65
70
|
})
|
|
66
71
|
dialogBtn.addEventListener('click', close)
|
|
67
72
|
|
package/lib/index.js
CHANGED
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
import { randomUUID } from 'node:crypto'
|
|
71
71
|
import { open, readFile, readdir, stat } from 'node:fs/promises'
|
|
72
72
|
import { extname, join, normalize, resolve, sep } from 'node:path'
|
|
73
|
+
import { createRequire } from 'node:module'
|
|
73
74
|
import os from 'node:os'
|
|
74
75
|
import { fileURLToPath } from 'node:url'
|
|
75
76
|
import { zstdDecompressSync } from 'node:zlib'
|
|
@@ -78,8 +79,34 @@ export const name = 'thoughtdag'
|
|
|
78
79
|
export const inject = ['webServer', 'sessions', 'sessionController', 'agents', 'llm', 'attachments', 'web', 'tools', 'commands', 'systemPrompt', 'approval']
|
|
79
80
|
|
|
80
81
|
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
|
82
|
+
const require = createRequire(import.meta.url)
|
|
81
83
|
const APP_DIR = resolve(__dirname, '../dist-app')
|
|
82
84
|
|
|
85
|
+
// The plugin's own version travels into the canvas's URL (?dv=), so the
|
|
86
|
+
// update dialog and the release history know which release runs here, as
|
|
87
|
+
// they do in the desktop shell. The registry is asked for the newest
|
|
88
|
+
// version at most once a day; a failed lookup is silence, not an error.
|
|
89
|
+
const PLUGIN_VERSION = (() => { try { return require(resolve(__dirname, '..', 'package.json')).version ?? null } catch { return null } })()
|
|
90
|
+
let latestLookup = { value: null, at: 0 }
|
|
91
|
+
async function latestPluginVersion() {
|
|
92
|
+
if (Date.now() - latestLookup.at < 24 * 60 * 60 * 1000) return latestLookup.value
|
|
93
|
+
latestLookup = { value: latestLookup.value, at: Date.now() }
|
|
94
|
+
try {
|
|
95
|
+
const r = await fetch('https://registry.npmjs.org/dsh-thoughtdag/latest', { signal: AbortSignal.timeout(5000), headers: { accept: 'application/json' } })
|
|
96
|
+
if (r.ok) { const j = await r.json(); if (typeof j?.version === 'string') latestLookup.value = j.version }
|
|
97
|
+
} catch { /* offline, or the registry is slow: keep what we had */ }
|
|
98
|
+
return latestLookup.value
|
|
99
|
+
}
|
|
100
|
+
// the shared runtime, copied under lib/runtime by the build (Node code, no harness dependency)
|
|
101
|
+
let agentsHttpInstance = null
|
|
102
|
+
function agentsHttp() {
|
|
103
|
+
if (!agentsHttpInstance) {
|
|
104
|
+
const { createAgentsHttp } = require(resolve(__dirname, 'runtime', 'agents', 'http.cjs'))
|
|
105
|
+
agentsHttpInstance = createAgentsHttp({ log: (line) => console.error(line) })
|
|
106
|
+
}
|
|
107
|
+
return agentsHttpInstance
|
|
108
|
+
}
|
|
109
|
+
|
|
83
110
|
const MAX_BODY_BYTES = 32 * 1024
|
|
84
111
|
// a compiled canvas context can be long; the write endpoints take up to this
|
|
85
112
|
const MAX_WRITE_BODY_BYTES = 4 * 1024 * 1024
|
|
@@ -191,6 +218,14 @@ function sessionToJsonl(session) {
|
|
|
191
218
|
return lines.join('\n')
|
|
192
219
|
}
|
|
193
220
|
|
|
221
|
+
/** The events after `since`, as lines — the tail a reader appends to the
|
|
222
|
+
* log it already holds, instead of fetching the whole log again. */
|
|
223
|
+
function eventsJsonlSince(session, since) {
|
|
224
|
+
const lines = []
|
|
225
|
+
for (const event of allEvents(session)) if (typeof event.seq === 'number' && event.seq > since) lines.push(JSON.stringify(event))
|
|
226
|
+
return lines.join('\n')
|
|
227
|
+
}
|
|
228
|
+
|
|
194
229
|
// ── durable-session bridge (disk) ──────────────────────────────────────
|
|
195
230
|
// DSH persists each session as session.jsonl.zstd under
|
|
196
231
|
// $DSH_HOME/sessions/<encoded-cwd>/<session-id>/. The zstd log is a
|
|
@@ -279,6 +314,18 @@ async function findSessionFiles(dshHome) {
|
|
|
279
314
|
* header names the id+cwd; session/title arrives right after in live logs.
|
|
280
315
|
* Falls back to the session id when the frame boundary cuts early. */
|
|
281
316
|
const HEAD_READ_BYTES = 256 * 1024 // covers the first frames: header + title + opening turns
|
|
317
|
+
// a session's head is decoded once per (path, size, mtime): the listing is
|
|
318
|
+
// polled, and a poll must not decompress sixty files it already knows
|
|
319
|
+
const headCache = new Map()
|
|
320
|
+
async function cachedHead(f) {
|
|
321
|
+
const key = `${f.log}|${f.size}|${f.mtime}`
|
|
322
|
+
const hit = headCache.get(key)
|
|
323
|
+
if (hit) return hit
|
|
324
|
+
const head = await sessionTitleFromHead(f.log)
|
|
325
|
+
if (headCache.size > 4000) headCache.clear()
|
|
326
|
+
headCache.set(key, head)
|
|
327
|
+
return head
|
|
328
|
+
}
|
|
282
329
|
async function sessionTitleFromHead(logPath) {
|
|
283
330
|
try {
|
|
284
331
|
const fh = await open(logPath, 'r')
|
|
@@ -385,9 +432,13 @@ function fileInRoot(rootKey, rel) {
|
|
|
385
432
|
}
|
|
386
433
|
|
|
387
434
|
/** Every session file under a root, two-to-five levels deep like the desktop's walk. */
|
|
435
|
+
const listCache = new Map() // rootKey → { at, files }: a walk is reused for a few seconds
|
|
436
|
+
const LIST_CACHE_MS = 5000
|
|
388
437
|
async function listRoot(rootKey) {
|
|
389
438
|
const root = FILE_ROOTS[rootKey]
|
|
390
439
|
if (!root) throw new HttpError(404, 'no such root')
|
|
440
|
+
const hit = listCache.get(rootKey)
|
|
441
|
+
if (hit && Date.now() - hit.at < LIST_CACHE_MS) return hit.files
|
|
391
442
|
const out = []
|
|
392
443
|
const walk = async (dir, depth) => {
|
|
393
444
|
if (depth > 5) return
|
|
@@ -402,6 +453,7 @@ async function listRoot(rootKey) {
|
|
|
402
453
|
}
|
|
403
454
|
}
|
|
404
455
|
await walk(root, 0)
|
|
456
|
+
listCache.set(rootKey, { at: Date.now(), files: out })
|
|
405
457
|
return out
|
|
406
458
|
}
|
|
407
459
|
|
|
@@ -449,6 +501,18 @@ function splitModelId(id) {
|
|
|
449
501
|
* seeing images: a model is marked vision when its adapter declares image
|
|
450
502
|
* input; those images then enter the attachment store and ride the call. */
|
|
451
503
|
const AGENT_MODEL = 'harness/agent'
|
|
504
|
+
/** One agent entry per catalog model: 'harness/agent/<provider>/<model>'.
|
|
505
|
+
* The bare 'harness/agent' stays accepted (older canvases) and means the
|
|
506
|
+
* session's current model. */
|
|
507
|
+
const isAgentModelId = (id) => typeof id === 'string' && (id === AGENT_MODEL || id.startsWith(AGENT_MODEL + '/'))
|
|
508
|
+
function agentTargetOf(id) {
|
|
509
|
+
if (!isAgentModelId(id) || id === AGENT_MODEL) return null
|
|
510
|
+
const rest = id.slice(AGENT_MODEL.length + 1)
|
|
511
|
+
const i = rest.indexOf('/')
|
|
512
|
+
return i > 0 && i < rest.length - 1 ? { provider: rest.slice(0, i), model: rest.slice(i + 1) } : null
|
|
513
|
+
}
|
|
514
|
+
// the picker groups every agent-run entry under this key (the SPA's AGENT_PROVIDER)
|
|
515
|
+
const AGENT_GROUP = '__agent__'
|
|
452
516
|
|
|
453
517
|
/** Which of a provider's models take images: the adapter's declared input
|
|
454
518
|
* modalities; a name that says "vision" only when the adapter says nothing. */
|
|
@@ -465,11 +529,18 @@ async function visionIdsOf(ctx, providerId, catalogModels) {
|
|
|
465
529
|
async function modelsPayload(ctx) {
|
|
466
530
|
const cat = await ctx.sessionController.modelCatalog()
|
|
467
531
|
// the harness itself, as an entry: the agent loop with tools, not a bare model
|
|
468
|
-
|
|
532
|
+
// the harness's agent loop with tools, once per model it can run on —
|
|
533
|
+
// grouped with the other agent runtimes; the bare models follow by provider
|
|
534
|
+
const models = []
|
|
535
|
+
const agents = []
|
|
469
536
|
for (const g of cat.groups ?? []) {
|
|
470
537
|
const vision = await visionIdsOf(ctx, g.id, g.models ?? [])
|
|
471
|
-
for (const m of g.models ?? [])
|
|
538
|
+
for (const m of g.models ?? []) {
|
|
539
|
+
models.push({ id: `${g.id}/${m.id}`, name: m.name ?? m.id, provider: g.name ?? g.id, vision: vision.has(m.id) })
|
|
540
|
+
agents.push({ id: `${AGENT_MODEL}/${g.id}/${m.id}`, name: `Harness · ${m.name ?? m.id}`, provider: AGENT_GROUP, vision: vision.has(m.id) })
|
|
541
|
+
}
|
|
472
542
|
}
|
|
543
|
+
models.push(...agents)
|
|
473
544
|
const def = cat.default ? `${cat.default.provider}/${cat.default.model}` : null
|
|
474
545
|
return {
|
|
475
546
|
models,
|
|
@@ -617,6 +688,10 @@ async function runAgentTurn(ctx, body, emit, isClosed, { answerApprovals = true
|
|
|
617
688
|
const vm = await visionModel(ctx).catch(() => null)
|
|
618
689
|
if (vm) await ctx.sessionController.selectModel({ sessionId, provider: vm.provider, model: vm.model }).catch(() => {})
|
|
619
690
|
}
|
|
691
|
+
// the model the canvas picked for this agent turn, unless images already
|
|
692
|
+
// moved the session to a vision model
|
|
693
|
+
const picked = agentTargetOf(body?.model)
|
|
694
|
+
if (picked && !hasImages) await ctx.sessionController.selectModel({ sessionId, provider: picked.provider, model: picked.model }).catch(() => {})
|
|
620
695
|
const agent = await agentOf(ctx, sessionId)
|
|
621
696
|
let sawChunk = false
|
|
622
697
|
let fullText = ''
|
|
@@ -794,7 +869,7 @@ export async function apply(ctx, config) {
|
|
|
794
869
|
const files = await findSessionFiles(dshHome)
|
|
795
870
|
const sessions = []
|
|
796
871
|
for (const f of files) {
|
|
797
|
-
const head = await
|
|
872
|
+
const head = await cachedHead(f)
|
|
798
873
|
sessions.push({
|
|
799
874
|
id: head.id ?? f.sessionDir,
|
|
800
875
|
title: head.title,
|
|
@@ -830,22 +905,28 @@ export async function apply(ctx, config) {
|
|
|
830
905
|
const id = decodeURIComponent(one[1])
|
|
831
906
|
const session = liveSession(ctx, id)
|
|
832
907
|
if (session === undefined) return sendJson(res, 404, { error: 'no such session' })
|
|
833
|
-
if (one[2] === '/log')
|
|
908
|
+
if (one[2] === '/log') {
|
|
909
|
+
const since = url.searchParams.get('since')
|
|
910
|
+
if (since !== null && since !== '') return sendFile(res, 'application/x-ndjson; charset=utf-8', eventsJsonlSince(session, Number(since)))
|
|
911
|
+
return sendFile(res, 'application/x-ndjson; charset=utf-8', sessionToJsonl(session))
|
|
912
|
+
}
|
|
834
913
|
return sendJson(res, 200, { session: sessionSummary(session) })
|
|
835
914
|
}
|
|
836
915
|
if (path === '/why/status' && req.method === 'GET') return sendJson(res, 200, whyStatus)
|
|
916
|
+
if (path === '/version' && req.method === 'GET') return sendJson(res, 200, { version: PLUGIN_VERSION, latest: await latestPluginVersion(), checkedAt: latestLookup.at || null })
|
|
837
917
|
// ── the other agents' session files ──
|
|
838
918
|
if (path === '/roots' && req.method === 'GET') {
|
|
839
919
|
const roots = []
|
|
840
920
|
for (const [key, p] of Object.entries(FILE_ROOTS)) roots.push({ key, path: p, builtin: true, exists: await stat(p).then(st => st.isDirectory()).catch(() => false) })
|
|
841
921
|
return sendJson(res, 200, { roots })
|
|
842
922
|
}
|
|
843
|
-
const rootRoute = /^\/roots\/([a-z-]+)\/(list|head|read|range)$/.exec(path)
|
|
923
|
+
const rootRoute = /^\/roots\/([a-z-]+)\/(list|head|read|range|stat)$/.exec(path)
|
|
844
924
|
if (rootRoute !== null && req.method === 'GET') {
|
|
845
925
|
const key = rootRoute[1]
|
|
846
926
|
if (rootRoute[2] === 'list') return sendJson(res, 200, { files: await listRoot(key) })
|
|
847
927
|
const rel = url.searchParams.get('rel') ?? ''
|
|
848
928
|
const abs = fileInRoot(key, rel)
|
|
929
|
+
if (rootRoute[2] === 'stat') { const st = await stat(abs).catch(() => null); return st ? sendJson(res, 200, { size: st.size, mtime: st.mtimeMs }) : sendJson(res, 404, { error: 'no such file' }) }
|
|
849
930
|
if (rootRoute[2] === 'head') return sendFile(res, 'text/plain; charset=utf-8', await headOfFile(abs, Number(url.searchParams.get('bytes')) || 16384).catch(() => ''))
|
|
850
931
|
if (rootRoute[2] === 'read') {
|
|
851
932
|
const st = await stat(abs).catch(() => null)
|
|
@@ -870,6 +951,11 @@ export async function apply(ctx, config) {
|
|
|
870
951
|
: String(r.body?.content ?? '')
|
|
871
952
|
return sendJson(res, 200, { title, text, fetchedAt: new Date().toISOString(), ...(html ? { html } : {}), url: r.url ?? target, truncated: !!r.truncated })
|
|
872
953
|
}
|
|
954
|
+
// ── agent runtimes on this machine (Pi today), the same surface the desktop shell has ──
|
|
955
|
+
if (path.startsWith('/agents/')) {
|
|
956
|
+
const body = req.method === 'POST' ? await readJson(req, MAX_WRITE_BODY_BYTES).catch(() => null) : null
|
|
957
|
+
if (await agentsHttp().handle(req, res, path, body)) return
|
|
958
|
+
}
|
|
873
959
|
// ── model connection (the SPA's proxy protocol, on the harness's providers) ──
|
|
874
960
|
if (path === '/models' && req.method === 'GET') return sendJson(res, 200, await modelsPayload(ctx))
|
|
875
961
|
const approvalRoute = /^\/approvals\/([^/]+)$/.exec(path)
|
|
@@ -884,10 +970,10 @@ export async function apply(ctx, config) {
|
|
|
884
970
|
}
|
|
885
971
|
if ((path === '/stream' || path === '/claude') && req.method === 'POST') {
|
|
886
972
|
const body = await readJson(req, MAX_CALL_BODY_BYTES)
|
|
887
|
-
if (body?.model
|
|
973
|
+
if (isAgentModelId(body?.model)) {
|
|
888
974
|
if (path === '/claude') {
|
|
889
975
|
const r = await runAgentTurn(ctx, body, () => {}, () => false, { answerApprovals: false })
|
|
890
|
-
return sendJson(res, 200, { text: r.text, model:
|
|
976
|
+
return sendJson(res, 200, { text: r.text, model: body.model, harnessSession: r.sessionId })
|
|
891
977
|
}
|
|
892
978
|
res.writeHead(200, { 'content-type': 'text/event-stream', 'cache-control': 'no-cache', connection: 'keep-alive' })
|
|
893
979
|
let closed = false
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Agent runtimes
|
|
2
|
+
|
|
3
|
+
One file per runtime (CommonJS, `.cjs`, so it loads the same under any package type): `pi.cjs` over `pi --mode rpc`, `codex.cjs` over `codex app-server`, `claude.cjs` over `claude -p` with stream-json both ways. Each exports a factory returning the same surface:
|
|
4
|
+
|
|
5
|
+
- `available()` → where the binary is, or null
|
|
6
|
+
- `models()` → `{ installed, models: [{ provider, id, name, reasoning, vision, efforts, defaultEffort }], default }` — `efforts` are the effort levels the CLI accepts for that model, in its own words, read from the CLI (empty when it has none); `defaultEffort` its own default when it says
|
|
7
|
+
- `run(request, onEvent)` → run id at once; events follow, tagged with it. The request names the runtime, an absolute `cwd`, one `prompt`, optional `images`, a `model` from that runtime's own list, a session to continue (`sessionPath`, plus `forkEntryId` to branch it), and optionally `effort`: one of the levels the runtime itself listed for that model, in its own words (Codex from `model/list`, Claude Code and Pi from their `--help`), which it passes on as is (`--effort`, the turn's `effort`, `set_thinking_level`). A word the runtime did not list is dropped: the CLI's own setting stands.
|
|
8
|
+
- `abort(runId)`, `answer(runId, requestId, { confirmed } | { value } | { cancelled: true })`, `shutdown()`
|
|
9
|
+
|
|
10
|
+
A run emits exactly these event kinds (the renderer reads nothing else):
|
|
11
|
+
|
|
12
|
+
| kind | meaning |
|
|
13
|
+
|---|---|
|
|
14
|
+
| `session` | which session file this run writes to, and where (cwd); `model.resolved` names the real model when the run used an alias (Claude Code's `opus` → `claude-opus-5`); `effort` is the level the turn actually ran at, read back from the runtime's own record (Pi's state, Codex's rollout `turn_context`, Claude Code's transcript entries), never assumed |
|
|
15
|
+
| `message_update` with a text or thinking delta | the answer or the reasoning growing |
|
|
16
|
+
| `tool_execution_start` / `tool_execution_end` | a tool call, for the live trace |
|
|
17
|
+
| `question` | the agent asks the person: confirm / select / input / editor. A confirm may carry `rule`, an opaque key naming what "allow for this conversation" would cover (Claude Code: its own permission suggestion; Codex: the command, or all file changes); the answer `{ confirmed: true, scope: 'session' }` allows it for good — the runtime tells the CLI where it can (Claude Code `updatedPermissions` scoped to the session, Codex `acceptForSession`) and the canvas keeps the rule on the record, sending every such rule back as `allowRules` on later runs of this conversation |
|
|
18
|
+
| `question_answered` | the person's answer went back (record); with `auto: true` the runtime decided from a standing rule of this conversation and nobody was asked — the record is made from its `title`/`message`/`rule` |
|
|
19
|
+
| `fs_changes` | what the shell saw change on disk (produced here, not by the agent) |
|
|
20
|
+
| `run_end` / `run_error` | the turn is over |
|
|
21
|
+
|
|
22
|
+
Nothing starts at launch. A runtime's process (Pi's rpc, Codex's app-server, a Pi catalog read) is started by the first request that needs it and retires after ten minutes without one (`TD_AGENT_IDLE_MS`); Claude Code runs one process per turn. A launch that never opens the agent group never starts a CLI.
|
|
23
|
+
|
|
24
|
+
The finished turn is adopted from the session file by the atlas's adapter for that
|
|
25
|
+
runtime; the stream is for showing, the file is the truth. Anything a runtime does
|
|
26
|
+
beyond these kinds stays inside its own file.
|