@marcoscale98/pi-extensible-workflows 5.14.1-fork.1 → 5.19.1-fork.1
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/CHANGELOG.md +135 -0
- package/dist/src/agent-execution.js +114 -87
- package/dist/src/background-widget.d.ts +61 -0
- package/dist/src/background-widget.js +23 -16
- package/dist/src/decoders.js +28 -1
- package/dist/src/execution.d.ts +4 -2
- package/dist/src/execution.js +43 -2
- package/dist/src/host-delivery.js +1 -0
- package/dist/src/host-navigator.d.ts +18 -0
- package/dist/src/host-navigator.js +71 -13
- package/dist/src/host-recovery.d.ts +5 -2
- package/dist/src/host-recovery.js +3 -3
- package/dist/src/host-view.d.ts +21 -1
- package/dist/src/host-view.js +138 -47
- package/dist/src/host.d.ts +2 -2
- package/dist/src/host.js +246 -60
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +1346 -622
- package/dist/src/index.js.map +3 -3
- package/dist/src/paths.d.ts +2 -0
- package/dist/src/paths.js +2 -0
- package/dist/src/registry.js +3 -2
- package/dist/src/roles.d.ts +70 -0
- package/dist/src/roles.js +326 -0
- package/dist/src/script-tools.d.ts +27 -0
- package/dist/src/script-tools.js +87 -0
- package/dist/src/settings.d.ts +26 -0
- package/dist/src/settings.js +277 -0
- package/dist/src/trajectory.d.ts +39 -4
- package/dist/src/trajectory.js +82 -5
- package/dist/src/types.d.ts +30 -3
- package/dist/src/types.js +1 -1
- package/dist/src/utils.d.ts +21 -1
- package/dist/src/utils.js +40 -0
- package/dist/src/validation.d.ts +10 -17
- package/dist/src/validation.js +29 -458
- package/dist/starter/index.js +0 -2
- package/dist/starter/index.js.map +1 -1
- package/dist/starter/review-loop.d.ts +0 -13
- package/dist/starter/review-loop.js +0 -2
- package/dist/subagents/index.js +1344 -798
- package/dist/subagents/index.js.map +3 -3
- package/dist/subagents/src/contracts.d.ts +49 -29
- package/dist/subagents/src/contracts.js +18 -7
- package/dist/subagents/src/index.d.ts +1 -1
- package/dist/subagents/src/index.js +15 -7
- package/dist/subagents/src/manager.js +32 -13
- package/dist/subagents/src/navigator.js +396 -247
- package/dist/subagents/src/view.d.ts +24 -2
- package/dist/subagents/src/view.js +107 -80
- package/dist/trajectory/assets/index.html +370 -232
- package/dist/trajectory/assets/prism.min.js +13 -0
- package/dist/trajectory/index.js +445 -277
- package/dist/trajectory/index.js.map +3 -3
- package/dist/trajectory/src/assets/index.html +370 -232
- package/dist/trajectory/src/assets/prism.min.js +13 -0
- package/dist/trajectory/src/export.js +4 -2
- package/dist/trajectory/src/index.d.ts +2 -0
- package/dist/trajectory/src/index.js +151 -60
- package/dist/trajectory/src/server.js +138 -11
- package/dist/trajectory/src/server.js.map +2 -2
- package/package.json +7 -6
- package/skills/pi-extensible-workflows/SKILL.md +2 -0
- package/src/agent-execution.ts +110 -80
- package/src/background-widget.ts +26 -19
- package/src/decoders.ts +22 -1
- package/src/execution.ts +41 -4
- package/src/host-delivery.ts +1 -0
- package/src/host-navigator.ts +58 -14
- package/src/host-recovery.ts +8 -7
- package/src/host-view.ts +116 -42
- package/src/host.ts +223 -55
- package/src/index.ts +3 -1
- package/src/paths.ts +3 -0
- package/src/registry.ts +3 -2
- package/src/roles.ts +327 -0
- package/src/script-tools.ts +76 -0
- package/src/settings.ts +224 -0
- package/src/trajectory.ts +97 -9
- package/src/types.ts +12 -5
- package/src/utils.ts +36 -1
- package/src/validation.ts +30 -356
- package/starter/review-loop.ts +0 -2
- package/subagents/README.md +3 -3
- package/subagents/src/contracts.ts +22 -7
- package/subagents/src/index.ts +18 -7
- package/subagents/src/manager.ts +31 -13
- package/subagents/src/navigator.ts +336 -180
- package/subagents/src/view.ts +108 -76
- package/trajectory/src/assets/index.html +370 -232
- package/trajectory/src/assets/prism.min.js +13 -0
- package/trajectory/src/export.ts +4 -2
- package/trajectory/src/index.ts +124 -47
- package/trajectory/src/server.ts +114 -14
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prism v1.30.0 (core, clike, javascript, typescript, json, bash, diff, python) - https://prismjs.com
|
|
3
|
+
* Copyright (c) 2012 Lea Verou. (MIT Licensed)
|
|
4
|
+
*/
|
|
5
|
+
window.Prism = window.Prism || {}; window.Prism.manual = true;
|
|
6
|
+
var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(e){var n=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,r={},a={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof i?new i(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function e(n,t){var r,i;switch(t=t||{},a.util.type(n)){case"Object":if(i=a.util.objId(n),t[i])return t[i];for(var l in r={},t[i]=r,n)n.hasOwnProperty(l)&&(r[l]=e(n[l],t));return r;case"Array":return i=a.util.objId(n),t[i]?t[i]:(r=[],t[i]=r,n.forEach((function(n,a){r[a]=e(n,t)})),r);default:return n}},getLanguage:function(e){for(;e;){var t=n.exec(e.className);if(t)return t[1].toLowerCase();e=e.parentElement}return"none"},setLanguage:function(e,t){e.className=e.className.replace(RegExp(n,"gi"),""),e.classList.add("language-"+t)},currentScript:function(){if("undefined"==typeof document)return null;if(document.currentScript&&"SCRIPT"===document.currentScript.tagName)return document.currentScript;try{throw new Error}catch(r){var e=(/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(r.stack)||[])[1];if(e){var n=document.getElementsByTagName("script");for(var t in n)if(n[t].src==e)return n[t]}return null}},isActive:function(e,n,t){for(var r="no-"+n;e;){var a=e.classList;if(a.contains(n))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!t}},languages:{plain:r,plaintext:r,text:r,txt:r,extend:function(e,n){var t=a.util.clone(a.languages[e]);for(var r in n)t[r]=n[r];return t},insertBefore:function(e,n,t,r){var i=(r=r||a.languages)[e],l={};for(var o in i)if(i.hasOwnProperty(o)){if(o==n)for(var s in t)t.hasOwnProperty(s)&&(l[s]=t[s]);t.hasOwnProperty(o)||(l[o]=i[o])}var u=r[e];return r[e]=l,a.languages.DFS(a.languages,(function(n,t){t===u&&n!=e&&(this[n]=l)})),l},DFS:function e(n,t,r,i){i=i||{};var l=a.util.objId;for(var o in n)if(n.hasOwnProperty(o)){t.call(n,o,n[o],r||o);var s=n[o],u=a.util.type(s);"Object"!==u||i[l(s)]?"Array"!==u||i[l(s)]||(i[l(s)]=!0,e(s,t,o,i)):(i[l(s)]=!0,e(s,t,null,i))}}},plugins:{},highlightAll:function(e,n){a.highlightAllUnder(document,e,n)},highlightAllUnder:function(e,n,t){var r={callback:t,container:e,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};a.hooks.run("before-highlightall",r),r.elements=Array.prototype.slice.apply(r.container.querySelectorAll(r.selector)),a.hooks.run("before-all-elements-highlight",r);for(var i,l=0;i=r.elements[l++];)a.highlightElement(i,!0===n,r.callback)},highlightElement:function(n,t,r){var i=a.util.getLanguage(n),l=a.languages[i];a.util.setLanguage(n,i);var o=n.parentElement;o&&"pre"===o.nodeName.toLowerCase()&&a.util.setLanguage(o,i);var s={element:n,language:i,grammar:l,code:n.textContent};function u(e){s.highlightedCode=e,a.hooks.run("before-insert",s),s.element.innerHTML=s.highlightedCode,a.hooks.run("after-highlight",s),a.hooks.run("complete",s),r&&r.call(s.element)}if(a.hooks.run("before-sanity-check",s),(o=s.element.parentElement)&&"pre"===o.nodeName.toLowerCase()&&!o.hasAttribute("tabindex")&&o.setAttribute("tabindex","0"),!s.code)return a.hooks.run("complete",s),void(r&&r.call(s.element));if(a.hooks.run("before-highlight",s),s.grammar)if(t&&e.Worker){var c=new Worker(a.filename);c.onmessage=function(e){u(e.data)},c.postMessage(JSON.stringify({language:s.language,code:s.code,immediateClose:!0}))}else u(a.highlight(s.code,s.grammar,s.language));else u(a.util.encode(s.code))},highlight:function(e,n,t){var r={code:e,grammar:n,language:t};if(a.hooks.run("before-tokenize",r),!r.grammar)throw new Error('The language "'+r.language+'" has no grammar.');return r.tokens=a.tokenize(r.code,r.grammar),a.hooks.run("after-tokenize",r),i.stringify(a.util.encode(r.tokens),r.language)},tokenize:function(e,n){var t=n.rest;if(t){for(var r in t)n[r]=t[r];delete n.rest}var a=new s;return u(a,a.head,e),o(e,a,n,a.head,0),function(e){for(var n=[],t=e.head.next;t!==e.tail;)n.push(t.value),t=t.next;return n}(a)},hooks:{all:{},add:function(e,n){var t=a.hooks.all;t[e]=t[e]||[],t[e].push(n)},run:function(e,n){var t=a.hooks.all[e];if(t&&t.length)for(var r,i=0;r=t[i++];)r(n)}},Token:i};function i(e,n,t,r){this.type=e,this.content=n,this.alias=t,this.length=0|(r||"").length}function l(e,n,t,r){e.lastIndex=n;var a=e.exec(t);if(a&&r&&a[1]){var i=a[1].length;a.index+=i,a[0]=a[0].slice(i)}return a}function o(e,n,t,r,s,g){for(var f in t)if(t.hasOwnProperty(f)&&t[f]){var h=t[f];h=Array.isArray(h)?h:[h];for(var d=0;d<h.length;++d){if(g&&g.cause==f+","+d)return;var v=h[d],p=v.inside,m=!!v.lookbehind,y=!!v.greedy,k=v.alias;if(y&&!v.pattern.global){var x=v.pattern.toString().match(/[imsuy]*$/)[0];v.pattern=RegExp(v.pattern.source,x+"g")}for(var b=v.pattern||v,w=r.next,A=s;w!==n.tail&&!(g&&A>=g.reach);A+=w.value.length,w=w.next){var P=w.value;if(n.length>e.length)return;if(!(P instanceof i)){var E,S=1;if(y){if(!(E=l(b,A,e,m))||E.index>=e.length)break;var L=E.index,O=E.index+E[0].length,C=A;for(C+=w.value.length;L>=C;)C+=(w=w.next).value.length;if(A=C-=w.value.length,w.value instanceof i)continue;for(var j=w;j!==n.tail&&(C<O||"string"==typeof j.value);j=j.next)S++,C+=j.value.length;S--,P=e.slice(A,C),E.index-=A}else if(!(E=l(b,0,P,m)))continue;L=E.index;var N=E[0],_=P.slice(0,L),M=P.slice(L+N.length),W=A+P.length;g&&W>g.reach&&(g.reach=W);var I=w.prev;if(_&&(I=u(n,I,_),A+=_.length),c(n,I,S),w=u(n,I,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),S>1){var T={cause:f+","+d,reach:W};o(e,n,t,w.prev,A,T),g&&T.reach>g.reach&&(g.reach=T.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a<t&&r!==e.tail;a++)r=r.next;n.next=r,r.prev=n,e.length-=a}if(e.Prism=a,i.stringify=function e(n,t){if("string"==typeof n)return n;if(Array.isArray(n)){var r="";return n.forEach((function(n){r+=e(n,t)})),r}var i={type:n.type,content:e(n.content,t),tag:"span",classes:["token",n.type],attributes:{},language:t},l=n.alias;l&&(Array.isArray(l)?Array.prototype.push.apply(i.classes,l):i.classes.push(l)),a.hooks.run("wrap",i);var o="";for(var s in i.attributes)o+=" "+s+'="'+(i.attributes[s]||"").replace(/"/g,""")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'"'+o+">"+i.content+"</"+i.tag+">"},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener("message",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute("data-manual")&&(a.manual=!0)),!a.manual){var h=document.readyState;"loading"===h||"interactive"===h&&g&&g.defer?document.addEventListener("DOMContentLoaded",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
|
|
7
|
+
Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/};
|
|
8
|
+
Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp("(^|[^\\w$])(?:NaN|Infinity|0[bB][01]+(?:_[01]+)*n?|0[oO][0-7]+(?:_[0-7]+)*n?|0[xX][\\dA-Fa-f]+(?:_[\\dA-Fa-f]+)*n?|\\d+(?:_\\d+)*n|(?:\\d+(?:_\\d+)*(?:\\.(?:\\d+(?:_\\d+)*)?)?|\\.\\d+(?:_\\d+)*)(?:[Ee][+-]?\\d+(?:_\\d+)*)?)(?![\\w$])"),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp("((?:^|[^$\\w\\xA0-\\uFFFF.\"'\\])\\s]|\\b(?:return|yield))\\s*)/(?:(?:\\[(?:[^\\]\\\\\r\n]|\\\\.)*\\]|\\\\.|[^/\\\\\\[\r\n])+/[dgimyus]{0,7}|(?:\\[(?:[^[\\]\\\\\r\n]|\\\\.|\\[(?:[^[\\]\\\\\r\n]|\\\\.|\\[(?:[^[\\]\\\\\r\n]|\\\\.)*\\])*\\])*\\]|\\\\.|[^/\\\\\\[\r\n])+/[dgimyus]{0,7}v[dgimyus]{0,7})(?=(?:\\s|/\\*(?:[^*]|\\*(?!/))*\\*/)*(?:$|[\r\n,.;:})\\]]|//))"),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:Prism.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),Prism.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),Prism.languages.markup&&(Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.markup.tag.addAttribute("on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)","javascript")),Prism.languages.js=Prism.languages.javascript;
|
|
9
|
+
!function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var s=e.languages.extend("typescript",{});delete s["class-name"],e.languages.typescript["class-name"].inside=s,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:s}}}}),e.languages.ts=e.languages.typescript}(Prism);
|
|
10
|
+
Prism.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},Prism.languages.webmanifest=Prism.languages.json;
|
|
11
|
+
!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",a={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},n={bash:a,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},parameter:{pattern:/(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/,alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:n},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:a}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:n},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:n.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:n.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},a.inside=e.languages.bash;for(var s=["comment","function-name","for-or-select","assign-left","parameter","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=n.variable[1].inside,i=0;i<s.length;i++)o[s[i]]=e.languages.bash[s[i]];e.languages.sh=e.languages.bash,e.languages.shell=e.languages.bash}(Prism);
|
|
12
|
+
!function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var n={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(n).forEach((function(a){var i=n[a],r=[];/^\w+$/.test(a)||r.push(/\w+/.exec(a)[0]),"diff"===a&&r.push("bold"),e.languages.diff[a]={pattern:RegExp("^(?:["+i+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:r,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(a)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:n})}(Prism);
|
|
13
|
+
Prism.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern://,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python["string-interpolation"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python;
|
|
@@ -22,15 +22,16 @@ export async function exportTrajectoryRunHtml(options) {
|
|
|
22
22
|
if (!run)
|
|
23
23
|
throw new Error(`Workflow run ${options.runId} was not found for session ${options.sessionId}`);
|
|
24
24
|
const assets = new URL("./assets/", import.meta.url);
|
|
25
|
-
const [html, marked, morphdom, favicon] = await Promise.all([
|
|
25
|
+
const [html, marked, morphdom, prism, favicon] = await Promise.all([
|
|
26
26
|
readFile(new URL("index.html", assets), "utf8"),
|
|
27
27
|
readFile(new URL("marked.min.js", assets)),
|
|
28
28
|
readFile(new URL("morphdom.min.js", assets)),
|
|
29
|
+
readFile(new URL("prism.min.js", assets)),
|
|
29
30
|
readFile(new URL("favicon.png", assets)),
|
|
30
31
|
]);
|
|
31
32
|
const state = {
|
|
32
33
|
type: "state",
|
|
33
|
-
publishers: [{ id: `export-${options.runId}`, title: `run ${options.runId.slice(0, 8)}`, cwd: options.cwd, sessionId: options.sessionId,
|
|
34
|
+
publishers: [{ id: `export-${options.runId}`, title: `run ${options.runId.slice(0, 8)}`, cwd: options.cwd, sessionId: options.sessionId, connected: true, runs: [run], subagents: [] }],
|
|
34
35
|
updatedAt: Date.now(),
|
|
35
36
|
};
|
|
36
37
|
// Base64 data URLs avoid </script> escaping issues inside inlined sources; JSON gets the standard \u003c escape.
|
|
@@ -39,6 +40,7 @@ export async function exportTrajectoryRunHtml(options) {
|
|
|
39
40
|
output = inlineAsset(output, '<link rel="icon" type="image/png" href="./favicon.png" />', `<link rel="icon" type="image/png" href="data:image/png;base64,${favicon.toString("base64")}" />`);
|
|
40
41
|
output = inlineAsset(output, '<script src="./marked.min.js"></script>', script(marked));
|
|
41
42
|
output = inlineAsset(output, '<script src="./morphdom.min.js"></script>', script(morphdom));
|
|
43
|
+
output = inlineAsset(output, '<script src="./prism.min.js"></script>', script(prism));
|
|
42
44
|
output = inlineAsset(output, '<body data-view="run">', `<body data-view="run">\n <script>window.__PIEWF_STATIC__ = ${JSON.stringify(state).replace(/</g, "\\u003c")};</script>`);
|
|
43
45
|
return output;
|
|
44
46
|
}
|
|
@@ -13,6 +13,8 @@ export type TrajectoryController = {
|
|
|
13
13
|
export declare function trajectoryServerPath(moduleDirectory?: string): string;
|
|
14
14
|
export declare function trajectoryUrl(port: number): string;
|
|
15
15
|
export declare function openTrajectoryUrl(url: string): void;
|
|
16
|
+
type LiveStateRecord = Record<string, unknown>;
|
|
17
|
+
export declare function minimalStatePublisher(publisher: LiveStateRecord): LiveStateRecord;
|
|
16
18
|
export declare function createTrajectoryController(agentDir: string): TrajectoryController;
|
|
17
19
|
export { DEFAULT_TRAJECTORY_PORT, TRAJECTORY_IDLE_EXIT_MS, TRAJECTORY_LOCK_NAME };
|
|
18
20
|
export { exportTrajectoryRunHtml, shareTrajectoryRun, type TrajectoryExportOptions, type TrajectoryShareOptions, type TrajectoryShareResult } from "./export.js";
|
|
@@ -8,7 +8,7 @@ import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
|
8
8
|
import { clearTrajectoryHost, setTrajectoryHost } from "../../src/trajectory-host-handle.js";
|
|
9
9
|
import { processAlive } from "../../src/session-lease.js";
|
|
10
10
|
import { errorText, isNodeError, object, positiveInteger } from "../../src/utils.js";
|
|
11
|
-
import { isTrajectoryAction, isTrajectoryTarget, trajectoryActionError, TRAJECTORY_MAX_TRANSCRIPT_BYTES } from "../../src/trajectory.js";
|
|
11
|
+
import { isTimingTranscriptEntry, isTrajectoryAction, isTrajectoryTarget, trajectoryActionError, TRAJECTORY_MAX_TRANSCRIPT_BYTES } from "../../src/trajectory.js";
|
|
12
12
|
import { shareTrajectoryRun } from "./export.js";
|
|
13
13
|
const DEFAULT_TRAJECTORY_PORT = 7432;
|
|
14
14
|
const TRAJECTORY_IDLE_EXIT_MS = 5 * 60 * 1000;
|
|
@@ -29,15 +29,22 @@ async function trajectoryFingerprint(serverPath) {
|
|
|
29
29
|
function publisherId(cwd, sessionId) { return createHash("sha256").update(`${cwd}\n${sessionId}`).digest("hex").slice(0, 16); }
|
|
30
30
|
function trajectoryPort(value) { return positiveInteger(value) && value <= 65535 ? value : DEFAULT_TRAJECTORY_PORT; }
|
|
31
31
|
function delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); }
|
|
32
|
-
|
|
32
|
+
// Servers older than the identity fields answer `{ ok: true }` alone, so every field is optional.
|
|
33
|
+
async function serverHealth(port) {
|
|
33
34
|
try {
|
|
34
35
|
const response = await fetch(`http://127.0.0.1:${String(port)}/health`, { signal: AbortSignal.timeout(300) });
|
|
35
|
-
|
|
36
|
+
if (!response.ok)
|
|
37
|
+
return undefined;
|
|
38
|
+
const body = await response.json().catch(() => undefined);
|
|
39
|
+
if (!object(body))
|
|
40
|
+
return {};
|
|
41
|
+
return { ...(positiveInteger(body.pid) ? { pid: body.pid } : {}), ...(typeof body.fingerprint === "string" ? { fingerprint: body.fingerprint } : {}), ...(positiveInteger(body.startedAt) ? { startedAt: body.startedAt } : {}) };
|
|
36
42
|
}
|
|
37
43
|
catch {
|
|
38
|
-
return
|
|
44
|
+
return undefined;
|
|
39
45
|
}
|
|
40
46
|
}
|
|
47
|
+
async function serverHealthy(port) { return await serverHealth(port) !== undefined; }
|
|
41
48
|
function signalProcess(pid, signal) {
|
|
42
49
|
try {
|
|
43
50
|
process.kill(pid, signal);
|
|
@@ -82,17 +89,22 @@ async function readLock(path) {
|
|
|
82
89
|
return undefined;
|
|
83
90
|
}
|
|
84
91
|
}
|
|
85
|
-
|
|
92
|
+
// Only a server reporting this fingerprint counts: an older one still bound to the port would otherwise be adopted forever.
|
|
93
|
+
async function waitForServer(port, fingerprint) {
|
|
94
|
+
let foreign = false;
|
|
86
95
|
for (let attempt = 0; attempt < 60; attempt += 1) {
|
|
87
|
-
|
|
96
|
+
const health = await serverHealth(port);
|
|
97
|
+
if (health?.fingerprint === fingerprint)
|
|
88
98
|
return;
|
|
99
|
+
foreign = health !== undefined;
|
|
89
100
|
await delay(50);
|
|
90
101
|
}
|
|
91
|
-
throw new Error(`Trajectory server did not start on port ${String(port)}`);
|
|
102
|
+
throw new Error(foreign ? `Trajectory port ${String(port)} is held by another Trajectory server; stop it and retry` : `Trajectory server did not start on port ${String(port)}`);
|
|
92
103
|
}
|
|
93
104
|
async function resolveExistingServer(lockPath, existing, fingerprint) {
|
|
94
|
-
|
|
95
|
-
|
|
105
|
+
const health = await serverHealth(existing.port);
|
|
106
|
+
if (health) {
|
|
107
|
+
if (existing.fingerprint === fingerprint && health.fingerprint === fingerprint)
|
|
96
108
|
return existing;
|
|
97
109
|
await stopStaleServer(existing);
|
|
98
110
|
await rm(lockPath, { force: true });
|
|
@@ -100,7 +112,7 @@ async function resolveExistingServer(lockPath, existing, fingerprint) {
|
|
|
100
112
|
}
|
|
101
113
|
if (await processAlive(existing.pid, existing.startedAt)) {
|
|
102
114
|
try {
|
|
103
|
-
await waitForServer(existing.port);
|
|
115
|
+
await waitForServer(existing.port, fingerprint);
|
|
104
116
|
return existing;
|
|
105
117
|
}
|
|
106
118
|
catch {
|
|
@@ -148,12 +160,16 @@ async function ensureTrajectoryServer(agentDir, configuredPort) {
|
|
|
148
160
|
finally {
|
|
149
161
|
await lockHandle?.close();
|
|
150
162
|
}
|
|
163
|
+
// A server can answer on the port without owning the lock, e.g. one whose lock was lost; it reports its pid, so replace it before spawning.
|
|
164
|
+
const occupant = await serverHealth(configuredPort);
|
|
165
|
+
if (occupant?.pid !== undefined && occupant.fingerprint !== fingerprint)
|
|
166
|
+
await stopStaleServer({ pid: occupant.pid, port: configuredPort, ...(occupant.startedAt === undefined ? {} : { startedAt: occupant.startedAt }) });
|
|
151
167
|
try {
|
|
152
168
|
// NOTE: under a Bun-compiled pi binary process.execPath is the pi CLI, and Bun's node:http never writes the WebSocket 101 upgrade (oven-sh/bun#28157), so the server must run on a real node from PATH.
|
|
153
169
|
const child = spawn(process.versions.bun ? "node" : process.execPath, [serverPath, "--port", String(configuredPort), "--lock", lockPath, "--fingerprint", fingerprint], { detached: true, stdio: "ignore" });
|
|
154
170
|
const startupError = new Promise((_resolve, reject) => { child.once("error", reject); });
|
|
155
171
|
child.unref();
|
|
156
|
-
await Promise.race([waitForServer(configuredPort), startupError]);
|
|
172
|
+
await Promise.race([waitForServer(configuredPort, fingerprint), startupError]);
|
|
157
173
|
return { port: configuredPort };
|
|
158
174
|
}
|
|
159
175
|
catch (error) {
|
|
@@ -181,9 +197,11 @@ const MAX_FRAME_BYTES = 32 * 1024 * 1024;
|
|
|
181
197
|
const MAX_LIVE_STATE_BYTES = MAX_FRAME_BYTES - 1024;
|
|
182
198
|
const MAX_TRANSCRIPT_REQUESTS = 64;
|
|
183
199
|
const TRANSCRIPT_REQUEST_TIMEOUT_MS = 10_000;
|
|
200
|
+
const ACTIVE_POLL_MS = 1_000;
|
|
201
|
+
// Nobody is watching, so the publisher stops reading run state every second.
|
|
202
|
+
const IDLE_POLL_MS = 10_000;
|
|
184
203
|
const RECONNECT_INITIAL_DELAY_MS = 100;
|
|
185
204
|
const RECONNECT_MAX_DELAY_MS = 5_000;
|
|
186
|
-
function isTimingEntry(value) { return object(value) && value.type === "custom" && value.customType === "pi-workflows:tool-timing"; }
|
|
187
205
|
function boundedString(value, maxLength = 1024) {
|
|
188
206
|
if (typeof value !== "string")
|
|
189
207
|
return value;
|
|
@@ -194,54 +212,111 @@ const MAX_LIVE_STRING_BYTES = 64 * 1024;
|
|
|
194
212
|
const MAX_LIVE_ARRAY_ENTRIES = 256;
|
|
195
213
|
const MAX_LIVE_OBJECT_KEYS = 64;
|
|
196
214
|
const LIVE_METADATA_ARRAY_KEYS = new Set(["agents", "runs", "subagents"]);
|
|
197
|
-
const LIVE_TRUNCATABLE_ARRAY_KEYS = new Set(["events", "phaseHistory"]);
|
|
215
|
+
const LIVE_TRUNCATABLE_ARRAY_KEYS = new Set(["events", "phaseHistory", "scriptCalls"]);
|
|
198
216
|
const LIVE_METADATA_OBJECT_KEYS = new Set(["transcripts"]);
|
|
217
|
+
function liveValueWillBeBounded(value, key = "", depth = 0) {
|
|
218
|
+
if (typeof value === "string")
|
|
219
|
+
return Buffer.byteLength(value) > MAX_LIVE_STRING_BYTES;
|
|
220
|
+
if (typeof value !== "object" || value === null)
|
|
221
|
+
return false;
|
|
222
|
+
if (depth >= 12)
|
|
223
|
+
return true;
|
|
224
|
+
if (Array.isArray(value)) {
|
|
225
|
+
const maxEntries = LIVE_TRUNCATABLE_ARRAY_KEYS.has(key) ? MAX_LIVE_ARRAY_ENTRIES - 1 : MAX_LIVE_ARRAY_ENTRIES;
|
|
226
|
+
if (key === "attemptDetails" && value.length > 8 || !LIVE_METADATA_ARRAY_KEYS.has(key) && value.length > maxEntries)
|
|
227
|
+
return true;
|
|
228
|
+
return value.some((entry) => liveValueWillBeBounded(entry, "", depth + 1));
|
|
229
|
+
}
|
|
230
|
+
if (!object(value))
|
|
231
|
+
return false;
|
|
232
|
+
const properties = LIVE_METADATA_OBJECT_KEYS.has(key) ? Object.keys(value) : Object.keys(value).sort().slice(0, MAX_LIVE_OBJECT_KEYS);
|
|
233
|
+
if (!LIVE_METADATA_OBJECT_KEYS.has(key) && Object.keys(value).length > MAX_LIVE_OBJECT_KEYS)
|
|
234
|
+
return true;
|
|
235
|
+
return properties.some((property) => liveValueWillBeBounded(value[property], property, depth + 1));
|
|
236
|
+
}
|
|
237
|
+
const MAX_LIVE_TIMING_BYTES = 64 * 1024;
|
|
238
|
+
/** Keeps the newest timing entries: dropping the oldest leaves a live agent's gantt growing instead of frozen. */
|
|
199
239
|
function boundedTiming(value) {
|
|
200
|
-
const entries = Array.isArray(value) ? value.filter(
|
|
240
|
+
const entries = Array.isArray(value) ? value.filter(isTimingTranscriptEntry) : [];
|
|
201
241
|
const retained = [];
|
|
202
242
|
let bytes = 2;
|
|
203
|
-
for (
|
|
243
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
204
244
|
let serialized;
|
|
205
245
|
try {
|
|
206
|
-
serialized = JSON.stringify(
|
|
246
|
+
serialized = JSON.stringify(entries[index]);
|
|
207
247
|
}
|
|
208
248
|
catch {
|
|
209
249
|
continue;
|
|
210
250
|
}
|
|
211
251
|
const nextBytes = bytes + (retained.length ? 1 : 0) + Buffer.byteLength(serialized);
|
|
212
|
-
if (nextBytes >=
|
|
252
|
+
if (nextBytes >= MAX_LIVE_TIMING_BYTES)
|
|
213
253
|
break;
|
|
214
|
-
retained.push(
|
|
254
|
+
retained.push(entries[index]);
|
|
215
255
|
bytes = nextBytes;
|
|
216
256
|
}
|
|
217
|
-
return retained;
|
|
257
|
+
return retained.reverse();
|
|
218
258
|
}
|
|
219
|
-
function boundedLiveValue(value, key = "", depth = 0) {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if (
|
|
259
|
+
function boundedLiveValue(value, key = "", depth = 0, bounds) {
|
|
260
|
+
const pathLength = bounds?.path.length ?? 0;
|
|
261
|
+
if (bounds && key)
|
|
262
|
+
bounds.path.push(key);
|
|
263
|
+
const argsValue = bounds !== undefined && bounds.path.length >= 3 && bounds.path[0] === "runs" && bounds.path[1] === "snapshot" && bounds.path[2] === "args";
|
|
264
|
+
const markArgsTruncated = () => { if (argsValue && bounds.runIndex !== undefined)
|
|
265
|
+
bounds.argsTruncatedRuns.add(bounds.runIndex); };
|
|
266
|
+
try {
|
|
267
|
+
if (typeof value === "string") {
|
|
268
|
+
if (argsValue && Buffer.byteLength(value) > MAX_LIVE_STRING_BYTES)
|
|
269
|
+
markArgsTruncated();
|
|
270
|
+
return boundedString(value, MAX_LIVE_STRING_BYTES);
|
|
271
|
+
}
|
|
272
|
+
if (typeof value === "number" || typeof value === "boolean" || value === null)
|
|
273
|
+
return value;
|
|
274
|
+
if (depth >= 12) {
|
|
275
|
+
markArgsTruncated();
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|
|
278
|
+
if (key === "timing" && !argsValue)
|
|
279
|
+
return boundedTiming(value);
|
|
280
|
+
if (key === "output" && object(value) && value.status === "available") {
|
|
281
|
+
const boundedOutput = boundedLiveValue(value.value, "value", depth + 1, bounds);
|
|
282
|
+
return liveValueWillBeBounded(value.value, "value", depth + 1) ? { status: "truncated", kind: "result", bytes: value.bytes } : { ...value, value: boundedOutput };
|
|
283
|
+
}
|
|
284
|
+
if (Array.isArray(value)) {
|
|
285
|
+
const array = value;
|
|
286
|
+
const maxEntries = !argsValue && LIVE_TRUNCATABLE_ARRAY_KEYS.has(key) ? MAX_LIVE_ARRAY_ENTRIES - 1 : MAX_LIVE_ARRAY_ENTRIES;
|
|
287
|
+
const entries = !argsValue && key === "attemptDetails" ? array.slice(-8) : !argsValue && LIVE_METADATA_ARRAY_KEYS.has(key) ? array : array.length <= maxEntries ? array : [...array.slice(0, 32), ...array.slice(-maxEntries + 32)];
|
|
288
|
+
if (entries.length !== array.length)
|
|
289
|
+
markArgsTruncated();
|
|
290
|
+
const publisherRuns = bounds?.path.length === 1 && bounds.path[0] === "runs";
|
|
291
|
+
const bounded = entries.map((entry, index) => {
|
|
292
|
+
const previousRunIndex = bounds?.runIndex;
|
|
293
|
+
if (publisherRuns)
|
|
294
|
+
bounds.runIndex = index;
|
|
295
|
+
const result = boundedLiveValue(entry, "", depth + 1, bounds);
|
|
296
|
+
if (bounds)
|
|
297
|
+
bounds.runIndex = previousRunIndex;
|
|
298
|
+
return result;
|
|
299
|
+
});
|
|
300
|
+
if (entries.length !== array.length && LIVE_TRUNCATABLE_ARRAY_KEYS.has(key))
|
|
301
|
+
bounded.push({ type: "trajectory:truncated", field: key, omitted: array.length - entries.length });
|
|
302
|
+
return bounded;
|
|
303
|
+
}
|
|
304
|
+
if (object(value)) {
|
|
305
|
+
const result = {};
|
|
306
|
+
const keys = Object.keys(value).sort();
|
|
307
|
+
const properties = !argsValue && LIVE_METADATA_OBJECT_KEYS.has(key) ? keys : keys.slice(0, MAX_LIVE_OBJECT_KEYS);
|
|
308
|
+
if (properties.length !== keys.length)
|
|
309
|
+
markArgsTruncated();
|
|
310
|
+
for (const property of properties)
|
|
311
|
+
result[property] = boundedLiveValue(value[property], property, depth + 1, bounds);
|
|
312
|
+
return result;
|
|
313
|
+
}
|
|
225
314
|
return undefined;
|
|
226
|
-
if (key === "timing")
|
|
227
|
-
return boundedTiming(value);
|
|
228
|
-
if (Array.isArray(value)) {
|
|
229
|
-
const array = value;
|
|
230
|
-
const maxEntries = LIVE_TRUNCATABLE_ARRAY_KEYS.has(key) ? MAX_LIVE_ARRAY_ENTRIES - 1 : MAX_LIVE_ARRAY_ENTRIES;
|
|
231
|
-
const entries = key === "attemptDetails" ? array.slice(-8) : LIVE_METADATA_ARRAY_KEYS.has(key) ? array : array.length <= maxEntries ? array : [...array.slice(0, 32), ...array.slice(-maxEntries + 32)];
|
|
232
|
-
const bounded = entries.map((entry) => boundedLiveValue(entry, "", depth + 1));
|
|
233
|
-
if (entries.length !== array.length && LIVE_TRUNCATABLE_ARRAY_KEYS.has(key))
|
|
234
|
-
bounded.push({ type: "trajectory:truncated", field: key, omitted: array.length - entries.length });
|
|
235
|
-
return bounded;
|
|
236
315
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
for (const property of properties)
|
|
241
|
-
result[property] = boundedLiveValue(value[property], property, depth + 1);
|
|
242
|
-
return result;
|
|
316
|
+
finally {
|
|
317
|
+
if (bounds)
|
|
318
|
+
bounds.path.length = pathLength;
|
|
243
319
|
}
|
|
244
|
-
return undefined;
|
|
245
320
|
}
|
|
246
321
|
function transcriptRevisionProjection(value, depth = 0) {
|
|
247
322
|
if (depth >= 8)
|
|
@@ -293,8 +368,21 @@ function projectPublisher(metadata, publisher, revisions) {
|
|
|
293
368
|
const publisherId = typeof publisher.id === "string" ? publisher.id : "";
|
|
294
369
|
return { ...publisher, runs: metadata.runs.map((run) => projectRun(run, `${publisherId}\t${run.run.id}`, revisions)), subagents: metadata.subagents.map((subagent) => projectSubagent(subagent, `${publisherId}\tsubagent\t${subagent.id}`, revisions)) };
|
|
295
370
|
}
|
|
296
|
-
function minimalStatePublisher(publisher) {
|
|
297
|
-
|
|
371
|
+
export function minimalStatePublisher(publisher) {
|
|
372
|
+
const bounds = { argsTruncatedRuns: new Set(), path: [], runIndex: undefined };
|
|
373
|
+
const bounded = boundedLiveValue(publisher, "", 0, bounds) ?? {};
|
|
374
|
+
const sourceRuns = Array.isArray(publisher.runs) ? publisher.runs : [];
|
|
375
|
+
const boundedRuns = Array.isArray(bounded.runs) ? bounded.runs : [];
|
|
376
|
+
if (!sourceRuns.length || !boundedRuns.length)
|
|
377
|
+
return bounded;
|
|
378
|
+
const runs = boundedRuns.map((run, index) => {
|
|
379
|
+
const sourceRun = sourceRuns[index];
|
|
380
|
+
const sourceSnapshot = object(sourceRun) && object(sourceRun.snapshot) ? sourceRun.snapshot : undefined;
|
|
381
|
+
const boundedSnapshot = object(run) && object(run.snapshot) ? run.snapshot : undefined;
|
|
382
|
+
const argsUnavailable = sourceSnapshot !== undefined && sourceSnapshot.args !== undefined && sourceSnapshot.args !== null && (boundedSnapshot === undefined || !Object.prototype.hasOwnProperty.call(boundedSnapshot, "args"));
|
|
383
|
+
return (bounds.argsTruncatedRuns.has(index) || argsUnavailable) && object(run) ? { ...run, snapshotArgsTruncated: true } : run;
|
|
384
|
+
});
|
|
385
|
+
return { ...bounded, runs };
|
|
298
386
|
}
|
|
299
387
|
function publisherStateFrame(publisher, runs, subagents, truncated = false) {
|
|
300
388
|
const publisherSummary = { ...publisher };
|
|
@@ -365,11 +453,12 @@ export function createTrajectoryController(agentDir) {
|
|
|
365
453
|
} };
|
|
366
454
|
const clearTranscriptRequests = () => { for (const request of pendingTranscripts.values())
|
|
367
455
|
clearTimeout(request.timer); pendingTranscripts.clear(); };
|
|
456
|
+
let viewers = 0;
|
|
368
457
|
const startPolling = () => { stopPolling(); pollTimer = setInterval(() => { void sendState().catch((error) => { if (!closing)
|
|
369
|
-
console.error(`Trajectory state publish failed: ${errorText(error)}`); }); },
|
|
458
|
+
console.error(`Trajectory state publish failed: ${errorText(error)}`); }); }, viewers > 0 ? ACTIVE_POLL_MS : IDLE_POLL_MS); pollTimer.unref(); };
|
|
370
459
|
let stateLoad;
|
|
371
460
|
let lastState;
|
|
372
|
-
const publisherValue = (input) => ({ id: publisherId(input.cwd, input.sessionId), title: `session ${input.sessionId.slice(0, 8)}`, cwd: input.cwd, sessionId: input.sessionId,
|
|
461
|
+
const publisherValue = (input) => ({ id: publisherId(input.cwd, input.sessionId), title: `session ${input.sessionId.slice(0, 8)}`, cwd: input.cwd, sessionId: input.sessionId, connected: true });
|
|
373
462
|
const sendState = async () => {
|
|
374
463
|
const activeSocket = socket;
|
|
375
464
|
if (activeSocket !== undefined && stateLoad?.socket === activeSocket)
|
|
@@ -423,23 +512,14 @@ export function createTrajectoryController(agentDir) {
|
|
|
423
512
|
}
|
|
424
513
|
};
|
|
425
514
|
const transcriptFromFallback = async (input, request) => {
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
if (result.status === "available" && Buffer.byteLength(JSON.stringify(result.entries)) > TRAJECTORY_MAX_TRANSCRIPT_BYTES)
|
|
429
|
-
return { status: "oversized", revision: result.revision, entries: [], error: "Transcript is too large" };
|
|
430
|
-
}
|
|
431
|
-
catch {
|
|
432
|
-
return { status: "failed", revision: result.revision, entries: [], error: "Transcript failed" };
|
|
433
|
-
}
|
|
434
|
-
return result;
|
|
435
|
-
};
|
|
436
|
-
const boundedResult = (entries, revision) => { try {
|
|
437
|
-
if (Buffer.byteLength(JSON.stringify(entries)) > TRAJECTORY_MAX_TRANSCRIPT_BYTES)
|
|
438
|
-
return { status: "oversized", revision, entries: [], error: "Transcript is too large" };
|
|
515
|
+
const oversized = (entries, revision) => { try {
|
|
516
|
+
return Buffer.byteLength(JSON.stringify(entries)) > TRAJECTORY_MAX_TRANSCRIPT_BYTES ? { status: "oversized", revision, entries: [], error: "Transcript is too large" } : undefined;
|
|
439
517
|
}
|
|
440
518
|
catch {
|
|
441
519
|
return { status: "failed", revision, entries: [], error: "Transcript failed" };
|
|
442
|
-
}
|
|
520
|
+
} };
|
|
521
|
+
const boundedTranscriptResult = (result) => (result.status === "available" ? oversized(result.entries, result.revision) : undefined) ?? result;
|
|
522
|
+
const boundedResult = (entries, revision) => oversized(entries, revision) ?? { status: entries.length ? "available" : "empty", revision, entries };
|
|
443
523
|
if (input.loadTranscript) {
|
|
444
524
|
const result = await input.loadTranscript(request);
|
|
445
525
|
const revisionChanged = request.revision !== undefined && result.revision !== request.revision && result.status !== "missing" && result.status !== "failed" && result.status !== "oversized" && result.status !== "disconnected";
|
|
@@ -547,6 +627,17 @@ export function createTrajectoryController(agentDir) {
|
|
|
547
627
|
established = false;
|
|
548
628
|
return;
|
|
549
629
|
}
|
|
630
|
+
if (message.type === "publisher:viewers" && typeof message.count === "number") {
|
|
631
|
+
const watched = viewers > 0;
|
|
632
|
+
viewers = message.count;
|
|
633
|
+
if (watched === viewers > 0)
|
|
634
|
+
return;
|
|
635
|
+
if (socket === next && !closing)
|
|
636
|
+
startPolling();
|
|
637
|
+
if (viewers > 0)
|
|
638
|
+
void sendState().catch(() => undefined);
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
550
641
|
if (message.type === "publisher:transcript" && typeof message.requestId === "string" && typeof message.publisherId === "string" && (typeof message.runId === "string" && typeof message.agentId === "string" || typeof message.subagentId === "string")) {
|
|
551
642
|
handleTranscriptRequest(next, generation, message, input);
|
|
552
643
|
return;
|