@north-light/crouter 0.3.240 → 0.3.241
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/clients/attach/viewer.js +1 -1
- package/dist/commands/node/inspect.js +1 -1
- package/dist/commands/sys/context/admin/detail-panel.d.ts +3 -0
- package/dist/commands/sys/context/admin/detail-panel.js +32 -3
- package/dist/commands/sys/context/admin/docs-panel.d.ts +23 -13
- package/dist/commands/sys/context/admin/docs-panel.js +101 -103
- package/dist/commands/sys/context/admin/list-view.d.ts +53 -0
- package/dist/commands/sys/context/admin/list-view.js +125 -0
- package/dist/commands/sys/context/admin/model.d.ts +11 -0
- package/dist/commands/sys/context/admin/model.js +28 -1
- package/dist/commands/sys/context/admin/rail-panel.d.ts +46 -0
- package/dist/commands/sys/context/admin/{axes-panel.js → rail-panel.js} +64 -21
- package/dist/commands/sys/context/admin/shell.d.ts +19 -2
- package/dist/commands/sys/context/admin/shell.js +142 -46
- package/dist/core/canvas/browse/model.d.ts +0 -9
- package/dist/core/canvas/browse/model.js +1 -37
- package/dist/core/canvas/browse/render.js +2 -1
- package/dist/core/runtime/tmux-bindings.js +4 -3
- package/dist/core/tui/fuzzy.d.ts +9 -0
- package/dist/core/tui/fuzzy.js +38 -0
- package/package.json +1 -1
- package/runtime.lock.json +2 -2
- package/dist/commands/sys/context/admin/axes-panel.d.ts +0 -21
|
@@ -1643,7 +1643,7 @@ Please report this to https://github.com/markedjs/marked.`,e){let i="<p>An error
|
|
|
1643
1643
|
${e}`:t}function KOi(e){if(e!==void 0)try{return e()}catch{return}}var XOi="crtr-context",ZOi="crtr-situational-context",eDi="crtr-context-nudge",tDi="crtr-review-boundary";var ITr="Provider credentials were just updated (a new login landed). Your previous turn stopped on a provider authentication failure. Continue from where you left off and retry the work that failed.",wTr="The network connection is back online. Your previous turn stopped on a connection error (the network was down). Continue from where you left off and retry the work that failed.",RTr="Your previous turn stopped on a provider fault. Continue from where you left off and retry the work that failed.";function rDi(e){switch(e){case eDi:return"context-nudge";case XOi:return"bearings";case tDi:return"review-boundary";case ZOi:return"situational";default:return}}var b3e=/\s+([A-Za-z_:][A-Za-z0-9_:.-]*)\s*=\s*(?:"([^"]*)"|'([^']*)')/gy;function USt(e){return e.replace(/&(?:amp|lt|gt|quot|apos);/g,t=>({"&":"&","<":"<",">":">",""":'"',"'":"'"})[t])}function BSt(e){let t={};b3e.lastIndex=0;let r=0;for(;r<e.length&&!/^\s*$/.test(e.slice(r));){b3e.lastIndex=r;let i=b3e.exec(e);if(i===null)return null;let[,o,a,u]=i;if(o===void 0||Object.hasOwn(t,o))return null;t[o]=USt(a??u??""),r=b3e.lastIndex}return t}function $St(e){return typeof e.content=="string"?e.content:Array.isArray(e.content)?e.content.filter(t=>typeof t=="object"&&t!==null&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(""):""}function nDi(e){let t=[],r=/<from\b([^>]*)>([\s\S]*?)<\/from>/g;for(let i of e.matchAll(r)){let o=BSt(i[1]??"");if(o?.id===void 0)continue;let a=[],u=i[2]??"",p=/<entry\b([^>]*)>([\s\S]*?)<\/entry>/g;for(let _ of u.matchAll(p)){let m=BSt(_[1]??"");if(m?.kind===void 0)continue;let g=m.disposition==="human-answer"||m.disposition==="human-canceled"?m.disposition:"report";a.push({kind:m.kind,disposition:g,body:USt(_[2]??""),...m.ref===void 0?{}:{ref:m.ref}})}let f=o.updates===void 0?Number.NaN:Number(o.updates);t.push({id:o.id,updates:Number.isFinite(f)?f:a.length,finished:o.finished==="true"||a.some(_=>_.kind==="final"),entries:a})}return t}function iDi(e,t,r,i){return{kind:e,facts:t,body:r,senders:i}}function oDi(e){let t=/^<runtime\b([^>]*)>/.exec(e);if(t===null||!e.endsWith("</runtime>"))return null;let r=BSt(t[1]??"");if(r?.kind===void 0)return null;let i=e.slice(t[0].length,-10),{kind:o,...a}=r,u=Object.freeze(a),p=o.includes(":")?USt(i):i;return iDi(o,u,p,o==="inbox"?nDi(p):[])}function b0e(e){let t=$St(e),r=oDi(t);if(r!==null)return r;if(e.role!=="custom")return null;let i=rDi(e.customType);return i===void 0?null:{kind:i,facts:Object.freeze({}),body:t,senders:[]}}var m0s=256*1024;var h7=class extends f8{payload;constructor(t,r=eM.USAGE){super(t.error,t.message,r,{...t}),this.name="InputError",this.payload=t}};var sDi={400:"invalid_request",404:"not_found",409:"conflict",422:"unprocessable",503:"daemon_unavailable"};function kTr(e,t){if(e.code==="daemon_restarting")return new f8("daemon_restarting",e.message,eM.NETWORK,{next:"crtrd is now on the new generation \u2014 retry the command."});if(e.status===503||e.code==="daemon_unavailable")return new f8("daemon_unavailable",e.message,eM.NETWORK,{next:"Start it with `crtr sys daemon start`, then retry."});let r=e.details,i=r&&typeof r.error=="string"&&typeof r.message=="string"&&typeof r.next=="string"?r:{error:sDi[e.status]??e.code,message:e.message,next:t??(e.status>=500?"This is a crtr bug, not a bad call. Retry; if it persists, report it (the daemon log holds the full cause).":e.status===404?"List nodes with `crtr node inspect list`.":"Inspect the error and adjust the call. See -h for the schema.")};return new h7(i,aDi(i.error,e.status))}function aDi(e,t){return e==="not_found"||t===404?eM.NOT_FOUND:e==="ambiguous"?eM.AMBIGUOUS:eM.USAGE}function lDi(e){return cDi(e,Q0r,H0r)}function NTr(e){return m8(lDi(e))}function uDi(e){let t=m8(zSt(e,s3e));return t&&t.plugins&&typeof t.plugins=="object"?t.plugins:{}}function E0e(e,t){let r=zSt(t,"plugins");if(!RSt(r))return[];let i=uDi(t),o=[];for(let a of kSt(r)){let u=zSt(r,a),p=NTr(u);if(!p)continue;let f=i[a],_=typeof f?.version=="string"?f.version:p.version;o.push({name:a,scope:e,root:u,manifest:p,enabled:typeof f?.enabled=="boolean"?f.enabled:!0,sourceMarketplace:typeof f?.source_marketplace=="string"?f.source_marketplace:void 0,version:_})}return o}function A0e(e,t,r){let i=e.indexOf(t),o=i>=0?i:0;return e[(o+r+e.length)%e.length]}function jSt(e,t,r){let i=e.indexOf(t);return i>=0?e[(i+r+e.length)%e.length]:r>=0?e.find(o=>o>t)??e[0]:[...e].reverse().find(o=>o<t)??e[e.length-1]}function _7(e,t){return e==="true"?!0:e==="false"?!1:`${t} must be true or false`}function DTr(e,t){if(!/^\d+$/.test(e))return`${t} must be an integer >= 0`;let r=Number(e);return Number.isSafeInteger(r)?r:`${t} must be an integer >= 0`}function PTr(e,t){let r=DTr(e,t);return typeof r=="string"||r<1?`${t} must be an integer >= 1`:r}var OTr=[!1,"notify","apply"],pDi=[0,1,6,12,24,48,72,168],dDi=[1,2,3,4,5,6,8,10,12],fDi=[1,2,3,4,5,6],MTr={schema_version:{surface:"specialized",owner:"internal schema migration"},marketplaces:{surface:"specialized",owner:"Plugins and pkg market commands"},plugins:{surface:"specialized",owner:"Plugins tab and pkg plugin commands"},auto_update:{surface:"settings",settings:{crtr:{key:"auto_update.crtr",label:"crouter updates",description:"Notify about crouter releases, install them automatically, or turn checks off.",valueConstraint:"true|false|notify|apply; true stores notify",applies:"Applies on the next crouter command.",group:"updates",order:70,format:e=>e.auto_update.crtr===!1?"off":e.auto_update.crtr,cycle:(e,t)=>{e.auto_update.crtr=A0e(OTr,e.auto_update.crtr,t)},setFromString:(e,t)=>{let r=t==="true"?"notify":t;return r!=="notify"&&r!=="apply"&&r!=="false"?"auto_update.crtr must be notify, apply, or false":(e.auto_update.crtr=r==="false"?!1:r,null)}},content:{key:"auto_update.content",label:"Content updates",description:"Notify about plugin and marketplace updates, apply them automatically, or turn checks off.",valueConstraint:"false|notify|apply",applies:"Applies on the next crouter command.",group:"updates",order:80,format:e=>e.auto_update.content===!1?"off":e.auto_update.content,cycle:(e,t)=>{e.auto_update.content=A0e(OTr,e.auto_update.content,t)},setFromString:(e,t)=>t!=="notify"&&t!=="apply"&&t!=="false"?"auto_update.content must be notify, apply, or false":(e.auto_update.content=t==="false"?!1:t,null)},interval_hours:{key:"auto_update.interval_hours",label:"Update interval",description:"Minimum hours between automatic update checks. Zero checks on every command.",valueConstraint:"integer >= 0",applies:"Applies on the next crouter command.",group:"updates",order:90,format:e=>`${e.auto_update.interval_hours}h`,cycle:(e,t)=>{e.auto_update.interval_hours=jSt(pDi,e.auto_update.interval_hours,t)},setFromString:(e,t)=>{let r=DTr(t,"auto_update.interval_hours");return typeof r=="string"?r:(e.auto_update.interval_hours=r,null)}}}},max_panes_per_window:{surface:"settings",setting:{key:"max_panes_per_window",label:"Maximum panes",description:"Maximum human-review panes placed in one tmux window before using another window.",valueConstraint:"integer >= 1",applies:"Applies to the next pane placement.",group:"panes",order:20,format:e=>String(e.max_panes_per_window),cycle:(e,t)=>{e.max_panes_per_window=jSt(dDi,e.max_panes_per_window,t)},setFromString:(e,t)=>{let r=PTr(t,"max_panes_per_window");return typeof r=="string"?r:(e.max_panes_per_window=r,null)}}},auto_open_child_viewers:{surface:"settings",setting:{key:"auto_open_child_viewers",label:"Open child panes",description:"Open each managed child beside its watched parent. Off keeps new children running in the background.",valueConstraint:"true|false",applies:"Applies to the next managed child created; independent roots still open their attended viewer.",group:"panes",order:10,format:e=>e.auto_open_child_viewers?"on":"off",cycle:e=>{e.auto_open_child_viewers=!e.auto_open_child_viewers},setFromString:(e,t)=>{let r=_7(t,"auto_open_child_viewers");return typeof r=="string"?r:(e.auto_open_child_viewers=r,null)}}},brokerThresholds:{surface:"specialized",owner:"Broker limits tab"},completion_bell:{surface:"settings",setting:{key:"completion_bell",label:"Completion bell",description:"Ring a short sound when the node in an attached viewer finishes a turn.",valueConstraint:"true|false",applies:"Applies on the next turn end.",group:"display",order:41,format:e=>e.completion_bell?"on":"off",cycle:e=>{e.completion_bell=!e.completion_bell},setFromString:(e,t)=>{let r=_7(t,"completion_bell");return typeof r=="string"?r:(e.completion_bell=r,null)}}},working_gerunds:{surface:"specialized",owner:"sys config set working_gerunds"},whip_mode:{surface:"settings",setting:{key:"whip_mode",label:"Whip mode",description:"Play the whip animation when you send a prompt and when a viewer opens for an agent with an initial prompt.",valueConstraint:"true|false",applies:"Applies on the next attach.",group:"display",order:39,format:e=>e.whip_mode?"on":"off",cycle:e=>{e.whip_mode=!e.whip_mode},setFromString:(e,t)=>{let r=_7(t,"whip_mode");return typeof r=="string"?r:(e.whip_mode=r,null)}}},page_surface:{surface:"settings",setting:{key:"page_surface",label:"Page human surface",description:"This host reads pages in a browser rather than a terminal. Agents are told the page module runs as written, HTML pages are offered, and document review and live display leave the command tree.",valueConstraint:"true|false",applies:"Applies when human command help is assembled.",group:"display",order:37,format:e=>e.page_surface?"on":"off",cycle:e=>{e.page_surface=!e.page_surface},setFromString:(e,t)=>{let r=_7(t,"page_surface");return typeof r=="string"?r:(e.page_surface=r,null)}}},whip_messages:{surface:"specialized",owner:"sys config set whip_messages"},whip_message_mode:{surface:"settings",setting:{key:"whip_message_mode",label:"Whip message",description:"What the whip action sends: a random line from whip_messages, or the fixed \u201CGo faster\u201D.",valueConstraint:HY.join("|"),applies:"Applies on the next attach.",group:"display",order:40,format:e=>e.whip_message_mode==="go-faster"?"go faster":"random",cycle:(e,t)=>{e.whip_message_mode=A0e(HY,e.whip_message_mode,t)},setFromString:(e,t)=>HY.includes(t)?(e.whip_message_mode=t,null):`whip_message_mode must be one of: ${HY.join("|")}`}},mouse_mode_default:{surface:"settings",setting:{key:"mouse_mode_default",label:"Default mouse mode",description:"Initial mouse wheel scrolling for each attached viewer.",valueConstraint:JY.join("|"),applies:"Applies on the next attach.",group:"display",order:38,format:e=>e.mouse_mode_default==="tmux"?"follow tmux":e.mouse_mode_default,cycle:(e,t)=>{e.mouse_mode_default=A0e(JY,e.mouse_mode_default,t)},setFromString:(e,t)=>JY.includes(t)?(e.mouse_mode_default=t,null):`mouse_mode_default must be one of: ${JY.join("|")}`}},live_cycles:{surface:"settings",setting:{key:"live_cycles",label:"Live cycles",description:"Trailing refresh cycles rendered at full fidelity; older cycles condense to text.",valueConstraint:"integer >= 1",applies:"Applies on the next attach.",group:"display",order:50,format:e=>String(e.live_cycles),cycle:(e,t)=>{e.live_cycles=jSt(fDi,e.live_cycles,t)},setFromString:(e,t)=>{let r=PTr(t,"live_cycles");return typeof r=="string"?r:(e.live_cycles=r,null)}}},condensed_history:{surface:"settings",setting:{key:"condensed_history",label:"Condensed history",description:"Messages retained from condensed cycles. Tool calls are never kept.",valueConstraint:YY.join("|"),applies:"Applies on the next attach.",group:"display",order:60,format:e=>e.condensed_history,cycle:(e,t)=>{e.condensed_history=A0e(YY,e.condensed_history,t)},setFromString:(e,t)=>YY.includes(t)?(e.condensed_history=t,null):`condensed_history must be one of: ${YY.join("|")}`}},bash_tool_purpose:{surface:"settings",setting:{key:"bash_tool_purpose",label:"Bash purpose field",description:"Expose the optional purpose label to agents in the bash tool schema. Off removes the field without disabling the bash valve.",valueConstraint:"true|false",applies:"Applies on the next node session.",group:"display",order:25,format:e=>e.bash_tool_purpose?"on":"off",cycle:e=>{e.bash_tool_purpose=!e.bash_tool_purpose},setFromString:(e,t)=>{let r=_7(t,"bash_tool_purpose");return typeof r=="string"?r:(e.bash_tool_purpose=r,null)}}},fold_finished_tools:{surface:"settings",setting:{key:"fold_finished_tools",label:"Fold finished tools",description:"Fold every settled tool call to its call line. Toggle live with /fold-tools.",valueConstraint:"true|false",applies:"Applies on the next attach.",group:"display",order:30,format:e=>e.fold_finished_tools?"on":"off",cycle:e=>{e.fold_finished_tools=!e.fold_finished_tools},setFromString:(e,t)=>{let r=_7(t,"fold_finished_tools");return typeof r=="string"?r:(e.fold_finished_tools=r,null)}}},summarize_tool_calls:{surface:"settings",setting:{key:"summarize_tool_calls",label:"Summarize tool calls",description:"Replace completed folded tool-call groups with a one-line broker summary when available.",valueConstraint:"true|false",applies:"Applies when the next visible message closes a tool-call group.",group:"display",order:35,format:e=>e.summarize_tool_calls?"on":"off",cycle:e=>{e.summarize_tool_calls=!e.summarize_tool_calls},setFromString:(e,t)=>{let r=_7(t,"summarize_tool_calls");return typeof r=="string"?r:(e.summarize_tool_calls=r,null)}}},detailed_tool_recaps:{surface:"settings",setting:{key:"detailed_tool_recaps",label:"Detailed tool recaps",description:"Show each memory read and edited file in folded tool recaps. Off shows a compact count line instead.",valueConstraint:"true|false",applies:"Applies on the next attach.",group:"display",order:36,format:e=>e.detailed_tool_recaps?"on":"off",cycle:e=>{e.detailed_tool_recaps=!e.detailed_tool_recaps},setFromString:(e,t)=>{let r=_7(t,"detailed_tool_recaps");return typeof r=="string"?r:(e.detailed_tool_recaps=r,null)}}},keybindings:{surface:"specialized",owner:"Keybindings tab"},tmux_passthrough:{surface:"specialized",owner:"Keybindings tab"},modelLadders:{surface:"specialized",owner:"Models tab"},modelRoutes:{surface:"specialized",owner:"Models route declarations"},modelRouting:{surface:"specialized",owner:"Models route declarations"},kinds:{surface:"specialized",owner:"Models tab and kind registry"},page_components:{surface:"specialized",owner:"Page component catalog: product-registered page component kinds"},remoteCanvas:{surface:"specialized",owner:"canvas config commands"},spawnEnv:{surface:"specialized",owner:"spawn environment allow-list"},bin:{surface:"specialized",owner:"bare-binary contributions on every node PATH"},humanActions:{surface:"specialized",owner:"scope-configured human completion actions"}},mDi=Object.keys(MTr);function hDi(){let e=[];for(let t of Object.values(MTr))t.surface==="settings"&&("setting"in t?e.push(t.setting):e.push(...Object.values(t.settings)));return e.sort((t,r)=>t.order-r.order)}var V0s=hDi();var qSt=["options","text","table","cards","chart"],_Di=["page","step"],gDi=/^[a-z][a-z0-9-]{0,63}$/,yDi=new Set(qSt),LTr=[{kind:"page",tag:"Page",description:"the page itself: title, subtitle, and every step it contains",useWhen:"use as the single root element every page returns",builtin:!0,structural:!0},{kind:"step",tag:"Step",description:"one step inside a Page",useWhen:"use for each step the user sees and completes in sequence",builtin:!0,structural:!0},{kind:"options",tag:"UserQuestion",description:"known alternatives with single or multiple selection",useWhen:"use when the user picks among known alternatives, optionally with freetext",builtin:!0,structural:!1},{kind:"text",tag:"UserText",description:"writing surface whose answer is the text the user hands back",useWhen:"use when you need prose from the user \u2014 a value they write, or a draft they revise; prose they only read is a plain element",builtin:!0,structural:!1},{kind:"table",tag:"UserTable",description:"rows and columns with optional selection",useWhen:"use when structured records are easiest to compare in rows and columns",builtin:!0,structural:!1},{kind:"cards",tag:"UserCards",description:"visual records with optional selection",useWhen:"use when the user compares or picks richer items than a compact option list can carry",builtin:!0,structural:!1},{kind:"chart",tag:"Chart",description:"line, bar, or area data visualization",useWhen:"use when shape, trend, or magnitude matters more than exact tabular values",builtin:!0,structural:!1}];function S0e(e){return e.split("-").map(t=>t===""?"":`${t[0].toUpperCase()}${t.slice(1)}`).join("")}var GSt=Object.fromEntries(LTr.filter(e=>!e.structural).map(e=>[e.tag,e.kind])),E3e=new Set(LTr.map(e=>e.tag)),VSt=new Set(["Card","CardHeader","CardTitle","CardDescription","CardContent","CardFooter","CardAction","Badge","Button","Separator","Progress","Alert","AlertTitle","AlertDescription","Table","TableHeader","TableBody","TableFooter","TableRow","TableHead","TableCell","TableCaption","Tabs","TabsList","TabsTrigger","TabsContent","Accordion","AccordionItem","AccordionTrigger","AccordionContent"]);function gae(e){try{let t=JSON.stringify(e);return t===void 0?String(e):t}catch{return String(e)}}function _ae(e,t,r,i){if(e!==void 0){if(typeof e!="string"||e.trim()==="")throw new Error(`${r}[${i}].${t} must be a non-empty string; received ${gae(e)}`);return e.trim()}}function WSt(e,t="page_components"){if(e===void 0)return[];if(!Array.isArray(e))throw new Error(`${t} must be an array; received ${gae(e)}`);let r=new Set,i=new Set;return e.map((o,a)=>{let u;if(typeof o=="string")u={kind:o.trim()};else if(o!==null&&typeof o=="object"&&!Array.isArray(o)){let _=o,m=Object.keys(_).filter(g=>!["kind","description","useWhen","doc","display"].includes(g));if(m.length>0)throw new Error(`${t}[${a}] has unknown field(s): ${m.join(", ")}`);if(typeof _.kind!="string")throw new Error(`${t}[${a}].kind must be a string; offending entry: ${gae(o)}`);if(_.display!==void 0&&typeof _.display!="boolean")throw new Error(`${t}[${a}].display must be a boolean; offending entry: ${gae(o)}`);u={kind:_.kind.trim(),..._ae(_.description,"description",t,a)===void 0?{}:{description:_ae(_.description,"description",t,a)},..._ae(_.useWhen,"useWhen",t,a)===void 0?{}:{useWhen:_ae(_.useWhen,"useWhen",t,a)},..._ae(_.doc,"doc",t,a)===void 0?{}:{doc:_ae(_.doc,"doc",t,a)},..._.display===!0?{display:!0}:{}}}else throw new Error(`${t}[${a}] must be a string or component object; offending entry: ${gae(o)}`);let p=u.kind;if(!gDi.test(p))throw new Error(`${t}[${a}] has invalid page kind ${gae(p)}; expected /^[a-z][a-z0-9-]{0,63}$/`);if(yDi.has(p)||_Di.includes(p))throw new Error(`${t}[${a}] collides with built-in page kind "${p}"`);if(r.has(p))throw new Error(`${t}[${a}] duplicates page kind "${p}"`);let f=S0e(p);if(E3e.has(f))throw new Error(`${t}[${a}] kind "${p}" derives JSX tag "${f}", which collides with a built-in page component`);if(i.has(f))throw new Error(`${t}[${a}] kind "${p}" derives JSX tag "${f}", which duplicates another product page component`);return r.add(p),i.add(f),u})}function FTr(e){let t=new Map,r=new Map,i=[];for(let o of e)for(let a of o.components){let u=t.get(a.kind);if(u!==void 0)throw new Error(`page component kind "${a.kind}" is registered by both ${u} and ${o.origin}`);let p=S0e(a.kind),f=r.get(p);if(f!==void 0)throw new Error(`page component kind "${a.kind}" (${o.origin}) derives JSX tag "${p}", which duplicates kind "${f.kind}" from ${f.origin}`);t.set(a.kind,o.origin),r.set(p,{kind:a.kind,origin:o.origin}),i.push(a)}return i}function BTr(e,t){return t.find(r=>r.kind===e)}function QSt(e){return jTr(e,s3e)}function EDi(e){return jTr(e,J0r)}function tk(e){let t=_8(e);return t?ADi(t):c3e()}function ADi(e){let t=m8(QSt(e));return t?jDi(t):c3e()}function qTr(e){let t=_8(e);if(!t)return ASt();let r=m8(EDi(t));return r?{marketplaces:r.marketplaces??{},plugins:r.plugins??{},last_self_check:r.last_self_check,activeCanvas:r.activeCanvas??null}:ASt()}function SDi(e,t){return _0e(bDi(e)),bP(`${e}.lock`,()=>t(e),{timeoutError:()=>new Error(`timed out waiting for config lock: ${e}`)})}function TDi(e,t){let r=LSt(e);return SDi(QSt(r),t)}function HSt(e,t){return TDi(e,r=>{let i=m8(r)??{},o=t(i);return tK(r,o),o})}function vDi(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};let t={};for(let[r,i]of Object.entries(e))Array.isArray(i)&&i.every(o=>typeof o=="string")&&(t[r]=[...i]);return t}var CDi=new Set(gP.filter(p0e).map(e=>e.id));function yae(e){return Array.isArray(e)?[...new Set(e.filter(t=>typeof t=="string"&&QY.has(t)&&CDi.has(t)))]:[]}function xDi(e,t=ESt()){let r=t;if(e===null||typeof e!="object")return r;let i=e,o={anthropic:{...r.anthropic},openai:{...r.openai},...r.defaultProvider!==void 0?{defaultProvider:r.defaultProvider}:{}};(i.defaultProvider==="anthropic"||i.defaultProvider==="openai")&&(o.defaultProvider=i.defaultProvider);for(let a of["anthropic","openai"]){let u=i[a];if(!(u===null||typeof u!="object"))for(let[p,f]of Object.entries(u))(p==="ultra"||p==="strong"||p==="medium"||p==="light")&&typeof f=="string"&&(o[a][p]=f)}return o}function GTr(e){return e==="ultra"||e==="strong"||e==="medium"||e==="light"}function IDi(e,t={}){let r={...t};if(e===null||typeof e!="object"||Array.isArray(e))return r;for(let[i,o]of Object.entries(e)){let a=o,u=m=>{F4({level:"warn",event:"config.model_routes.invalid",fields:{route_id:i,rule:m}})};if(!a||typeof a!="object"||Array.isArray(a)){u("route must be an object");continue}let p={...r[i],...a,models:{...r[i]?.models,...a.models}};if(typeof p.family!="string"||p.family.trim()===""){u("family must be a non-empty string");continue}if(typeof p.credentialSource!="string"||p.credentialSource.trim()===""){u("credentialSource must be a non-empty string");continue}if(typeof p.providerId!="string"||p.providerId.trim()===""){u("providerId must be a non-empty string");continue}if(!p.models||typeof p.models!="object"||Array.isArray(p.models)){u("models must be an object");continue}let f={},_;for(let[m,g]of Object.entries(p.models)){if(!GTr(m)){_=`models.${m} is not a model strength`;break}if(typeof g!="string"||g.trim()===""){_=`models.${m} must be a non-empty provider/id ref`;break}let E=g.indexOf("/");if(E<=0||E===g.length-1){_=`models.${m} must be provider/id`;break}if(g.slice(0,E)!==p.providerId){_=`models.${m} provider prefix must equal providerId`;break}f[m]=g}if(_!==void 0){u(_);continue}r[i]={family:p.family,credentialSource:p.credentialSource,providerId:p.providerId,models:f}}return r}function wDi(e,t){if(e===void 0||e===null||typeof e!="object"||Array.isArray(e))return t;let r=e,i=a=>Array.isArray(a)&&a.every(u=>typeof u=="string"&&u.trim()!=="")?[...a]:void 0,o=Array.isArray(r.strengthFallback)&&r.strengthFallback.every(a=>GTr(a))?[...r.strengthFallback]:void 0;return{...i(r.credentialSourceOrder)!==void 0?{credentialSourceOrder:i(r.credentialSourceOrder)}:{},...i(r.familyOrder)!==void 0?{familyOrder:i(r.familyOrder)}:{},...o!==void 0?{strengthFallback:o}:{}}}function RDi(e){return e!==""&&e.replace(/\*/g,"")===""}function kDi(e,t=[]){let r=e,i=Array.isArray(r?.allow)?r.allow.filter(o=>typeof o=="string"):[];for(let o of i)if(RDi(o))throw new Error(`spawnEnv.allow: "${o}" matches every env var name (inherit-all) \u2014 this is exactly the leak the spawn-env boundary closes. Name the specific vars/prefixes you actually need instead (e.g. "AWS_*", "GIT_ASKPASS").`);return{allow:[...new Set([...t,...i])]}}var UTr=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,NDi=new Set(["crtr","crtrd"]);function PDi(e,t){if(t==="bin"&&NDi.has(e))return`${t}.${e} is reserved by crouter \u2014 pick another bare command name`;if(!UTr.test(e))return`${t}.${e} is not a safe bare command name (expected ${UTr.source})`}function ODi(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};let t={};for(let[r,i]of Object.entries(e))PDi(r,"bin")===void 0&&(typeof i!="string"||i.trim()===""||(t[r]=i));return t}var $Tr=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function DDi(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"humanActions",reason:"humanActions must be a JSON object mapping action names to {argv, cwd}",block:!0}];let t=[];for(let[r,i]of Object.entries(e)){let o=[];if($Tr.test(r)||o.push(`action name must match ${$Tr.source}`),i===null||typeof i!="object"||Array.isArray(i))o.push("action must be an object with argv and cwd");else{let a=i,u=Object.keys(a).filter(p=>p!=="argv"&&p!=="cwd");u.length>0&&o.push(`action has unsupported field${u.length===1?"":"s"}: ${u.join(", ")}`),(!Array.isArray(a.argv)||a.argv.length===0||!a.argv.every(p=>typeof p=="string"&&p.length>0))&&o.push("argv must be a non-empty array of non-empty strings"),(typeof a.cwd!="string"||a.cwd.length===0)&&o.push("cwd is required and must be a non-empty string")}o.length>0&&t.push({name:r,reason:o.join("; ")})}return t}function MDi(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};let t=new Set(DDi(e).map(i=>i.name)),r={};for(let[i,o]of Object.entries(e)){if(t.has(i))continue;let a=o;r[i]={argv:[...a.argv],cwd:a.cwd}}return r}function LDi(e){if(e===null||typeof e!="object")return null;let t=e,r={};typeof t.whenToUse=="string"&&t.whenToUse.trim()!==""&&(r.whenToUse=t.whenToUse),typeof t.model=="string"&&t.model.trim()!==""&&(r.model=t.model),typeof t.orchestratorModel=="string"&&t.orchestratorModel.trim()!==""&&(r.orchestratorModel=t.orchestratorModel);let i=o=>Array.isArray(o)&&o.every(a=>typeof a=="string");return i(t.tools)&&(r.tools=t.tools),i(t.extensions)&&(r.extensions=t.extensions),i(t.availableTo)&&(r.availableTo=t.availableTo),Object.keys(r).length>0?r:null}function FDi(e,t=bSt()){let r={...t};if(e!==null&&typeof e=="object")for(let[i,o]of Object.entries(e)){let a=LDi(o);if(a===null)continue;let u=r[i];u!==void 0?r[i]={...u,...a}:a.whenToUse!==void 0&&(r[i]=a)}return r}function S3e(){let e=[{origin:"config.json",components:tk("user").page_components}],t=_8("user");if(t!==null){let r=E0e("user",t).filter(i=>i.enabled&&i.manifest.page_components!==void 0).sort((i,o)=>i.name.localeCompare(o.name));for(let i of r){let o=`plugin "${i.name}" page_components`;e.push({origin:`plugin "${i.name}"`,components:WSt(i.manifest.page_components,o)})}}return FTr(e)}function BDi(e){if(e===null||typeof e!="object")return null;let t=e;if(typeof t.previewEndpoint!="string"||t.previewEndpoint.trim()===""||typeof t.relayTokenRef!="string"||t.relayTokenRef.trim()==="")return null;let r={previewEndpoint:t.previewEndpoint,relayTokenRef:t.relayTokenRef};return typeof t.cpOrigin=="string"&&t.cpOrigin.trim()!==""&&(r.cpOrigin=t.cpOrigin),r}function UDi(e,t=ySt()){let r={...t.targets};if(e!==null&&typeof e=="object"){let i=e;if(i.targets!==null&&typeof i.targets=="object")for(let[o,a]of Object.entries(i.targets)){let u=BDi(a);u!==null&&(r[o]=u)}}return{targets:r}}function zTr(e,t){return e===!0?"notify":e===!1?!1:e==="notify"||e==="apply"?e:t}function A3e(e,t){return typeof e=="number"&&Number.isSafeInteger(e)&&e>=1?e:t}function $Di(e,t){let r=e!==null&&typeof e=="object"?e:{},i=A3e(r.warning,t.warning),o=A3e(r.automaticReviveCap,t.automaticReviveCap);return i<=o?{warning:i,automaticReviveCap:o}:{...t}}function zDi(e){if(!Array.isArray(e))return[...a3e];let t=e.filter(r=>typeof r=="string"&&r.trim()!=="").map(r=>r.trim());return t.length>0?t:[...a3e]}function jDi(e){let t=c3e(),r=t.schema_version,i=e.marketplaces===void 0?{}:e.marketplaces,o=e.plugins===void 0?{}:e.plugins,a=e.auto_update,u=a&&typeof a.interval_hours=="number"?a.interval_hours:void 0,p=u!==void 0&&Number.isFinite(u)&&u>=0?u:t.auto_update.interval_hours,f={crtr:zTr(a?.crtr,t.auto_update.crtr),content:zTr(a?.content,t.auto_update.content),interval_hours:p},_=e.max_panes_per_window,m=A3e(_,t.max_panes_per_window),g=typeof e.auto_open_child_viewers=="boolean"?e.auto_open_child_viewers:t.auto_open_child_viewers,E=$Di(e.brokerThresholds,t.brokerThresholds),v=typeof e.completion_bell=="boolean"?e.completion_bell:t.completion_bell,T=e.working_gerunds===void 0?[...t.working_gerunds]:V0r(e.working_gerunds),C=typeof e.whip_mode=="boolean"?e.whip_mode:t.whip_mode,I=WSt(e.page_components),N=typeof e.page_surface=="boolean"?e.page_surface:t.page_surface,k=zDi(e.whip_messages),D=HY.includes(e.whip_message_mode)?e.whip_message_mode:t.whip_message_mode,z=JY.includes(e.mouse_mode_default)?e.mouse_mode_default:t.mouse_mode_default,Z=A3e(e.live_cycles,t.live_cycles),Q=YY.includes(e.condensed_history)?e.condensed_history:t.condensed_history,J=typeof e.bash_tool_purpose=="boolean"?e.bash_tool_purpose:t.bash_tool_purpose,ie=typeof e.fold_finished_tools=="boolean"?e.fold_finished_tools:t.fold_finished_tools,ne=typeof e.summarize_tool_calls=="boolean"?e.summarize_tool_calls:t.summarize_tool_calls,be=typeof e.detailed_tool_recaps=="boolean"?e.detailed_tool_recaps:t.detailed_tool_recaps,Ue=vDi(e.keybindings),He=yae(e.tmux_passthrough),$e=xDi(e.modelLadders),et=IDi(e.modelRoutes),Nt=wDi(e.modelRouting,void 0),It=FDi(e.kinds),Fe=UDi(e.remoteCanvas),We=kDi(e.spawnEnv,t.spawnEnv?.allow),mt=ODi(e.bin),tr=MDi(e.humanActions);return{bin:mt,humanActions:tr,schema_version:r,marketplaces:i,plugins:o,auto_update:f,max_panes_per_window:m,auto_open_child_viewers:g,brokerThresholds:E,completion_bell:v,working_gerunds:T,whip_mode:C,page_components:I,page_surface:N,whip_messages:k,whip_message_mode:D,mouse_mode_default:z,live_cycles:Z,condensed_history:Q,bash_tool_purpose:J,fold_finished_tools:ie,summarize_tool_calls:ne,detailed_tool_recaps:be,keybindings:Ue,tmux_passthrough:He,modelLadders:$e,...Object.keys(et).length>0?{modelRoutes:et}:{},...Nt!==void 0?{modelRouting:Nt}:{},kinds:It,remoteCanvas:Fe,spawnEnv:We}}function qDi(e){return m8(QSt(e))}function VTr(e){let t=_8(e);return t?qDi(t):null}var GDi=["ctrl","alt","shift"],VDi=new Set(["ctrl","alt","shift","meta"]),WDi=new Set(["enter","escape","tab","backspace","delete","space","up","down","left","right","pageup","pagedown","home","end"]),QDi={return:"enter",esc:"escape"},Sx=class extends Error{constructor(t){super(t),this.name="GestureSyntaxError"}};function HDi(e){let t=e.match(/^((?:[CMS]-)+)(.+)$/i);return t===null?e:`${t[1].split("-").filter(Boolean).map(i=>i.toUpperCase()==="C"?"ctrl":i.toUpperCase()==="M"?"alt":"shift").join("+")}+${t[2]}`}function XSt(e){let t=HDi(e.trim());if(t==="")throw new Sx("a stroke cannot be empty");let r,i;if(t==="+")r="+",i=[];else if(t.endsWith("++"))r="+",i=t.slice(0,-2).split("+");else{let f=t.split("+");if(f.some(_=>_===""))throw new Sx(`invalid stroke "${e}"`);r=f.pop(),i=f}let o=i.map(f=>f.toLowerCase());if(o.some(f=>!VDi.has(f)))throw new Sx(`unsupported modifier in "${e}"`);let a=o.map(f=>f==="meta"?"alt":f);if(new Set(a).size!==a.length)throw new Sx(`duplicate modifier in "${e}"`);let u=QDi[r.toLowerCase()]??r;if(u.length===1&&u>="A"&&u<="Z"?(u=u.toLowerCase(),a.includes("shift")||a.push("shift")):u.length!==1&&(u=u.toLowerCase()),!(u.length===1&&u.charCodeAt(0)>=32&&u.charCodeAt(0)<=126)&&!WDi.has(u))throw new Sx(`unsupported key "${r}"`);return[...GDi.filter(f=>a.includes(f)),u].join("+")}function ZSt(e,t){let r=e.trim().split(/\s+>\s+/);if(r.length>2)throw new Sx("a gesture may contain at most two strokes");let i=r.map(XSt);if(i.length===2&&t?.inputKind!=="tmux-sequence")throw new Sx("two-stroke sequences are supported only by tmux sequence actions");if(t?.inputKind==="tmux-sequence"&&i.length!==2)throw new Sx("this action requires a two-stroke tmux sequence");if(t?.inputKind==="tmux-menu-selector"){if(i.length!==1)throw new Sx("a menu selector must be one stroke");let a=i[0].split("+"),u=a.at(-1),p=a.slice(0,-1);if(u.length!==1&&u!=="space"||p.some(f=>f!=="shift"))throw new Sx("a menu selector must be one printable character")}if(t?.inputKind==="tmux-global-action"){if(i.length!==1)throw new Sx("a global menu shortcut must be one stroke");let o=i[0].split("+").slice(0,-1);if(!o.includes("ctrl")&&!o.includes("alt"))throw new Sx("a global menu shortcut must include Ctrl or Alt")}return i.join(" > ")}function JDi(e,t){if(!Array.isArray(e))throw new Sx("the override must be an array of gesture strings");let r=[];for(let i of e){if(typeof i!="string")throw new Sx("every override entry must be a gesture string");let o=ZSt(i,t);r.includes(o)||r.push(o)}return Object.freeze(r)}function YDi(e,t){return e.contexts.some(r=>t.contexts.includes(r))}function JSt(e){return e.contexts.includes("tmux.root")}function WTr(e){return!JSt(e)&&e.inputKind!=="tmux-menu-selector"&&e.inputKind!=="tmux-sequence"}function bae(e){return e.split(" > ")[0]}function KDi(e,t,r,i){let o=t.includes(" > "),a=i.includes(" > ");if(YDi(e,r))return o&&a?t===i:o||a?bae(t)===bae(i):t===i;let u=JSt(e),p=JSt(r);return!u&&!p?!1:u&&p&&o&&a?t===i:u&&p?bae(t)===bae(i):u&&WTr(r)?bae(t)===i:p&&WTr(e)?t===bae(i):!1}function YSt(e){return Object.freeze(e.defaults.map(t=>ZSt(t,e)))}var KSt=class{#e;constructor(t){this.#e=new Map(t)}get size(){return this.#e.size}get(t){return this.#e.get(t)}has(t){return this.#e.has(t)}entries(){return this.#e.entries()}keys(){return this.#e.keys()}values(){return this.#e.values()}forEach(t,r){for(let[i,o]of this.#e)t.call(r,o,i,this)}[Symbol.iterator](){return this.#e[Symbol.iterator]()}};function T0e(e,t,r,i,o){return Object.freeze({severity:"error",code:e,message:t,offendingValue:r,...i?{bindingId:i}:{},...o?{relatedBindingIds:Object.freeze([...o])}:{}})}function XDi(e){let t=[];for(let r=0;r<e.length;r+=1){let i=e[r];for(let o=r+1;o<e.length;o+=1){let a=e[o];for(let u of i.gestures){let p=a.gestures.find(f=>KDi(i.definition,u,a.definition,f));if(p!==void 0){t.push([i,a,u.includes(" > ")?u:p]);break}}}}return t}function ZDi(e,t,r){return e.some(i=>i.definition.safety===r&&i.gestures.length>0&&i.definition.contexts.includes(t))}function QTr(e,t){for(;;){let r=new Set;for(let[i,o,a]of XDi(e)){if(i.source==="user"&&r.add(i),o.source==="user"&&r.add(o),i.source==="default"&&o.source==="default")throw new Error(`keybinding catalog default collision: ${i.definition.id} / ${o.definition.id} (${a})`);t.push(T0e("collision",`${i.definition.id} and ${o.definition.id} both claim ${a} in overlapping contexts`,a,i.source==="user"?i.definition.id:o.definition.id,[i.definition.id,o.definition.id]))}if(r.size===0)return;for(let i of r)i.gestures=YSt(i.definition),i.source="default"}}function HTr(e=void 0){let t=[],r={};e!==void 0&&(e===null||typeof e!="object"||Array.isArray(e)?t.push(T0e("invalid-keybindings","keybindings must be an object keyed by catalog binding ID",e)):r=e);for(let[p,f]of Object.entries(r))QY.has(p)||t.push(T0e("unknown-binding",`unknown keybinding ID: ${p}`,f,p));let i=gP.map(p=>{let f=YSt(p);if(!Object.hasOwn(r,p.id))return{definition:p,gestures:f,source:"default"};let _=r[p.id];try{return{definition:p,gestures:JDi(_,p),source:"user",rawOverride:_}}catch(m){let g=m instanceof Error?m.message:String(m);return t.push(T0e("invalid-override",`${p.id}: ${g}`,_,p.id)),{definition:p,gestures:f,source:"default"}}});QTr(i,t);for(let p of mSt){if(ZDi(i,p.context,p.capability))continue;let f=i.filter(_=>_.source==="user"&&_.definition.safety===p.capability&&_.definition.contexts.includes(p.context));t.push(T0e("unreachable",`${p.context} must retain an enabled ${p.capability} binding`,f.map(_=>_.rawOverride),f[0]?.definition.id,f.map(_=>_.definition.id)));for(let _ of f)_.gestures=YSt(_.definition),_.source="default"}QTr(i,t);let o=i.map(p=>{let f=Object.freeze({definition:p.definition,gestures:p.gestures,source:p.source});return[p.definition.id,f]}),a=new KSt(o),u={bindings:a,diagnostics:Object.freeze(t),get(p){let f=a.get(p);if(f===void 0)throw new Error(`unknown crouter keybinding ID: ${p}`);return f},gestures(p){return this.get(p).gestures}};return Object.freeze(u)}function rK(){let e=VTr("user");return Object.freeze({bindings:HTr(e?.keybindings),tmuxPassthrough:Object.freeze(yae(e?.tmux_passthrough))})}function v0e(){return rK().bindings}var eMi={enter:"Enter",escape:"Esc",tab:"Tab",backspace:"Backspace",delete:"Delete",space:"Space",up:"Up",down:"Down",left:"Left",right:"Right",pageup:"PageUp",pagedown:"PageDown",home:"Home",end:"End"};function JTr(e){let t,r;if(e==="+")t="+",r=[];else if(e.endsWith("++"))t="+",r=e.slice(0,-2).split("+");else{let o=e.split("+");t=o.pop(),r=o}let i=r.map(o=>o[0].toUpperCase()+o.slice(1));return i.push(eMi[t]??(t.length===1&&r.length>0?t.toUpperCase():t)),i.join("+")}function g7(e){return e.split(" > ").map(JTr).join(" then ")}function BI(e,t){let r=e.gestures(t);return r.length===0?"Disabled":r.map(g7).join(" / ")}function nK(e){if(e.length===2&&e[0]==="\x1B"&&/[A-Z]/.test(e[1]))return`\x1B[${e.charCodeAt(1)};4u`;let t=/^\x1b\[(\d+);3u$/.exec(e);if(t!==null){let r=Number(t[1]);if(r>=65&&r<=90)return`\x1B[${r};4u`}return e}function iK(e,t,r,i){return e.gestures(t).some(o=>!o.includes(" > ")&&i(r,o))}var tMi="crtr.tmux.inbox.toggle";function YTr(e=v0e()){let t=e.gestures(tMi);return t.length>0?t.map(g7).join(" / "):null}function Eae(e){let t=YTr(e);return t!==null?`${t} inbox`:"crtr human list"}var rMi="crtr.tmux.menu.open",nMi="crtr.tmux.menu.background-bash";function iMi(e){let t=e.split("+"),r=t.at(-1);return t.includes("shift")&&/[a-z]/.test(r)?r.toUpperCase():r==="space"?" ":r}function KTr(e=v0e()){let t=e.gestures(rMi),r=e.gestures(nMi);return t.length===0||r.length===0?null:`${t.map(g7).join(" / ")} ${iMi(r[0])}`}function e0t(e){let t=KTr(e);return t!==null?`${t} to background`:null}var B4=[{menuId:"crtr.tmux.menu.attach.detach",actionId:"crtr.attach.detach"},{menuId:"crtr.tmux.menu.attach.clear-or-detach",actionId:"crtr.attach.clear-or-detach"},{menuId:"crtr.tmux.menu.attach.graph.toggle",actionId:"crtr.attach.graph.toggle"},{menuId:"crtr.tmux.menu.attach.help.toggle",actionId:"crtr.attach.help.toggle"},{menuId:"crtr.tmux.menu.attach.inbox.toggle",actionId:"crtr.attach.inbox.toggle"},{menuId:"crtr.tmux.menu.attach.inbox-strip",actionId:"crtr.attach.inbox-strip"},{menuId:"crtr.tmux.menu.attach.model-ladder.next",actionId:"crtr.attach.model-ladder.next"},{menuId:"crtr.tmux.menu.attach.model-ladder.previous",actionId:"crtr.attach.model-ladder.previous"},{menuId:"crtr.tmux.menu.attach.command.inspect",actionId:"crtr.attach.command.inspect"},{menuId:"crtr.tmux.menu.attach.file-review",actionId:"crtr.attach.file-review"},{menuId:"crtr.tmux.menu.attach.profile-files",actionId:"crtr.attach.profile-files"},{menuId:"crtr.tmux.menu.attach.search",actionId:"crtr.attach.search"},{menuId:"crtr.tmux.menu.attach.whip",actionId:"crtr.attach.whip"}],oMi="\x1B_crtr;",sMi="\x1B\\",ATs=new Set(B4.map(({actionId:e})=>e));function C0e(e){return`${oMi}${e}${sMi}`}function t0t(e){let t;for(let{actionId:r}of B4){let i=C0e(r),o=e.indexOf(i);o>=0&&(t===void 0||o<t.index)&&(t={actionId:r,encoded:i,index:o})}if(t!==void 0)return{actionId:t.actionId,remaining:e.slice(0,t.index)+e.slice(t.index+t.encoded.length)}}function Rm(e){return`'${e.replace(/'/g,"'\\''")}'`}function _g(e){let t=tvr("tmux",e,{encoding:"utf8"});return{ok:t.status===0,stdout:(t.stdout??"").trim(),stderr:(t.stderr??"").trim()}}function XTr(e,t){return _g(e===void 0||e===""?t:["-S",e,...t])}function hv(){return process.env.TMUX!==void 0&&process.env.TMUX!==""}function g8(){if(!hv())return null;let e=_g(["display-message","-p","#{session_name} #{window_id} #{pane_id}"]);if(!e.ok)return null;let[t,r,i]=e.stdout.split(" ");return{session:t,window:r,pane:i}}function n0t(e){let t=[];for(let[r,i]of Object.entries(e))t.push("-e",`${r}=${i}`);return t}function x0e(e){let t=_g(["new-window","-d","-a","-P","-F","#{window_id} #{pane_id}","-t",`${e.session}:`,"-n",e.name,"-c",e.cwd,...n0t(e.env),e.command]);if(!t.ok)return null;let[r,i]=t.stdout.split(" ");return r===void 0||r===""||i===void 0||i===""?null:{window:r,pane:i}}function Aae(e,t){let r=_g(["split-window","-d",...t.vertical===!0?[]:["-h"],...t.before===!0?["-b"]:[],...t.size!==void 0?["-l",String(t.size)]:[],"-P","-F","#{pane_id}","-t",e,"-c",t.cwd,...n0t(t.env),t.command]);return r.ok&&r.stdout!==""?r.stdout:null}function i0t(e,t){return _g(["rename-window","-t",e,t]).ok}function y7(e){return _g(["kill-pane","-t",e]).ok}function o0t(e){let t=_g(["display-message","-p","-t",e,"#{window_id}"]);return t.ok&&t.stdout!==""?t.stdout:null}function b7(e){let t=_g(["display-message","-p","-t",e,"#{session_name} #{window_id}"]);if(!t.ok)return null;let[r,i]=t.stdout.split(" ");return r===void 0||r===""||i===void 0||i===""?null:{session:r,window:i}}function oK(e){let t=_g(["display-message","-p","-t",e,"#{pane_id}"]);return t.ok&&t.stdout===e}function T3e(e){let t=_g(["display-message","-p","-t",e,"#{pane_id} #{pane_dead}"]);return t.ok&&t.stdout===`${e} 0`}function s0t(){let e=_g(["list-panes","-a","-F","#{pane_id}"]);return e.ok?new Set(e.stdout.split(`
|
|
1644
1644
|
`).filter(t=>t!=="")):null}function a0t(e){let t=_g(["display-message","-p","-t",e,"#{pane_width} #{pane_height}"]);if(!t.ok)return null;let[r,i]=t.stdout.split(" "),o=Number.parseInt(r,10),a=Number.parseInt(i,10);return Number.isInteger(o)&&o>0&&Number.isInteger(a)&&a>0?{cols:o,rows:a}:null}function U4(e,t,r){return _g(["set-option","-p","-t",e,t,r]).ok}function $4(e,t){let r=_g(["show-options","-p","-t",e,"-q","-v",t]);return r.ok?r.stdout:void 0}var I0e="@crtr_viewer_at",ZTr=0,evr=Promise.resolve();function c0t(e){if(e==="")return;let t=Math.max(Date.now(),ZTr+1);ZTr=t,evr=evr.then(()=>new Promise(r=>{try{cMi("tmux",["set-option","-p","-t",e,I0e,String(t)],()=>r())}catch{r()}}))}function lMi(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function r0t(e,t){let r=e.replace(/^"|"$/g,"");return new RegExp(`(?:^|\\s)surface\\s+attach\\s+to\\s+${lMi(t)}(?:\\s|$)`).test(r)}function uMi(){let e=tvr("ps",["-ax","-o","pid=,ppid=,command="],{encoding:"utf8"});if(e.status!==0||typeof e.stdout!="string")return null;let t=new Map,r=new Map;for(let i of e.stdout.split(`
|
|
1645
1645
|
`)){let o=/^\s*(\d+)\s+(\d+)\s+(.*)$/.exec(i);if(o===null)continue;let a=Number(o[1]),u=Number(o[2]);r.set(a,o[3]);let p=t.get(u)??[];p.push(a),t.set(u,p)}return{childrenOf:t,commandOf:r}}function pMi(e,t,r){let i=[t];for(;i.length>0;){let o=i.pop();if(r0t(e.commandOf.get(o)??"",r))return!0;let a=e.childrenOf.get(o);a!==void 0&&i.push(...a)}return!1}function l0t(e){let t=XTr(e,["list-panes","-a","-F","#{pane_id} #{session_name} #{@crtr_node} #{@crtr_viewer_at}"]);if(!t.ok||t.stdout==="")return[];let r=[],i;for(let o of t.stdout.split(`
|
|
1646
|
-
`)){let[a,u,p,f]=o.split(" ");if(a===void 0||a===""||u===void 0||u===""||p===void 0||p==="")continue;let _=XTr(e,["display-message","-p","-t",a,"#{pane_current_command} #{pane_start_command} #{pane_pid}"]);if(!_.ok)continue;let[m="",g="",E]=_.stdout.split(" ");if(!(r0t(m,p)||r0t(g,p))){i??=uMi();let C=Number.parseInt(E,10);if(i===null||!Number.isInteger(C)||C<=0||!pMi(i,C,p))continue}let T=Number.parseInt(f??"",10);r.push({pane:a,session:u,nodeId:p,stampMs:Number.isSafeInteger(T)&&T>=0?T:0})}return r}function rvr(e){return["respawn-pane","-k","-c",e.cwd,...n0t(e.env),"-t",e.pane,e.command]}function u0t(e){return _g(rvr(e)).ok}function p0t(e){let t=`tmux ${rvr(e).map(Rm).join(" ")} >/dev/null 2>&1`;return _g(["run-shell","-b",t]).ok}function w0e(e,t){return _g(["select-window","-t",`${e}:${t}`]).ok}function v3e(e,t){return _g(["select-layout","-t",e,t]).ok}function C3e(e){return _g(["select-pane","-t",e]).ok}function d0t(e){return _g(["switch-client","-t",e]).ok}import{mkdtempSync as mMi,rmSync as hMi,writeFileSync as _Mi}from"node:fs";import{tmpdir as lvr}from"node:os";import{join as f0t}from"node:path";var dMi=Symbol.for("@earendil-works/pi-coding-agent:theme");function nvr(){return globalThis[dMi]??void 0}function ivr(){let e=nvr();if(e===void 0)throw new Error("surfaceBgAnsi: pi theme not initialized in this process");return e.getBgAnsi("selectedBg")}function fMi(){let e=nvr();if(e===void 0)return;let t=e.getBgAnsi("selectedBg"),r=/48;2;(\d+);(\d+);(\d+)/.exec(t);if(r!==null){let o=a=>Number(a).toString(16).padStart(2,"0");return`#${o(r[1])}${o(r[2])}${o(r[3])}`}let i=/48;5;(\d+)/.exec(t);if(i!==null)return`colour${i[1]}`}function oF(){let e=fMi();return e===void 0?[]:["-b","rounded","-s",`bg=${e}`,"-S",`bg=${e}`]}var w3e="@crtr_keybindings_manifest",rk="root",gMi={"crtr.tmux.menu.promote":{description:"promote to orchestrator",action:{kind:"keys",keys:"/promote"}},"crtr.tmux.menu.resume":{description:"find node",action:{kind:"keys",keys:"/resume-node"}},"crtr.tmux.menu.fork":{description:"fork into idle root",action:{kind:"direct",run:"node fork --pane {pane}"}},"crtr.tmux.menu.demote-mode":{description:"demote to base node",action:{kind:"command",run:"node config --mode base --pane {pane}"}},"crtr.tmux.menu.demote":{description:"demote to terminal (finish when done)",action:{kind:"command",run:"node lifecycle demote --pane {pane}"}},"crtr.tmux.menu.make-resident":{description:"make resident (interactable)",action:{kind:"command",run:"node config --lifecycle resident --pane {pane}"}},"crtr.tmux.menu.detach":{description:"demote + close viewer",action:{kind:"command",run:"node lifecycle demote --pane {pane} --detach"}},"crtr.tmux.menu.close-subtree":{description:"close agent + subtree",action:{kind:"command",run:"node lifecycle close --pane {pane}"}},"crtr.tmux.menu.background-bash":{description:"background running bash",action:{kind:"direct",run:"node bash background --pane {pane}"}},"crtr.tmux.menu.file-review":{description:"review a file",action:{kind:"raw-keys",keys:"M-S-r"}},"crtr.tmux.menu.metadata":{description:"metadata",action:{kind:"keys",keys:"/node-metadata"}},"crtr.tmux.menu.fold-tools":{description:"fold finished tool calls",action:{kind:"keys",keys:"/fold-tools"}},"crtr.tmux.menu.context":{description:"context + reports",action:{kind:"keys",keys:"/context"}},"crtr.tmux.menu.providers":{description:"settings",action:{kind:"popup",run:"sys settings",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.plugins":{description:"plugins",action:{kind:"popup",run:"pkg browse",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.context-admin":{description:"context surface",action:{kind:"popup",run:"sys context admin",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.graph":{description:"canvas graph",action:{kind:"keys",keys:"/graph"}},"crtr.tmux.menu.focus-manager":{description:"go to manager",action:{kind:"command",run:"surface node focus {manager}"}},"crtr.tmux.menu.copy-id":{description:"copy node id",action:{kind:"command",run:"surface node id --pane {pane}"}},"crtr.tmux.menu.reload-viewer":{description:"reload viewer",action:{kind:"direct",run:"surface reload --pane {pane}"}},"crtr.tmux.menu.recap":{description:"generate recap",action:{kind:"keys",keys:"/recap"}},"crtr.tmux.menu.pin":{description:"pin conversation",action:{kind:"direct",run:"surface node pin --pane {pane}"}},"crtr.tmux.menu.issue.idea":{description:"idea",action:{kind:"popup",run:"canvas issue new --type idea"}},"crtr.tmux.menu.issue.bug":{description:"bug",action:{kind:"popup",run:"canvas issue new --type bug"}}};function sK(e){return e.replace(/#/g,"##")}function yMi(e){return e.map(Rm).join(" ")}var bMi={w:"60%",h:"50%"};function ovr(e,t=!1,r=bMi){let i=`crtr canvas chord --pane '#{pane_id}' --run ${Rm(sK(e))}${t?" --interactive":""}`;return t?{argv:["display-popup","-E","-w",r.w,"-h",r.h,"-d","#{pane_current_path}",i],menu:`display-popup -E -w ${r.w} -h ${r.h} -d "#{pane_current_path}" ${Rm(i)}`}:{argv:["run-shell",`${i} >/dev/null 2>&1`],menu:`run-shell ${Rm(`${i} >/dev/null 2>&1`)}`}}function EMi(e){let r=`crtr ${sK(e).replace("{pane}","#{pane_id}")} >/dev/null 2>&1`;return{argv:["run-shell","-b",r],menu:`run-shell -b ${Rm(r)}`}}function uvr(e){switch(e.kind){case"disabled":return null;case"separator":return null;case"dismiss":return{argv:["refresh-client"],menu:"refresh-client"};case"keys":{let t=sK(e.keys);return{argv:["send-keys",t,"Enter"],menu:`send-keys -t '#{pane_id}' ${Rm(t)} Enter`}}case"raw-keys":{let t=sK(e.keys);return{argv:["send-keys",t],menu:`send-keys -t '#{pane_id}' ${Rm(t)}`}}case"literal-input":{let t=sK(e.input);return{argv:["send-keys","-l",t],menu:`send-keys -l -t '#{pane_id}' ${Rm(t)}`}}case"command":return ovr(e.run);case"direct":return EMi(e.run);case"popup":return ovr(e.run,!0,e.size);case"submenu":{let t=pvr(e.title,e.items);return{argv:t,menu:yMi(t)}}}}function AMi(e){return uvr(e)?.menu??""}function SMi(e){return e.replace(/#\[[^\]]*\]/g,"").length}function pvr(e,t){let r=sK(e),i=t.reduce((a,u)=>Math.max(a,SMi(u.description)),0),o=["display-menu","-T",`#[align=centre]${r}`,...oF()];o.push("-x",`#{e|-:#{pane_right},${Math.max(r.length,i)+7}}`,"-y","#{e|+:#{pane_top},3}","--");for(let a of t){if(a.action.kind==="separator"){o.push("");continue}let u=a.action.kind==="disabled"?a.description:sK(a.description);o.push(u,a.selector,AMi(a.action))}return o.push("","-esc / q to close","",""),o}var TMi={enter:"Enter",escape:"Escape",tab:"Tab",backspace:"BSpace",delete:"DC",space:"Space",up:"Up",down:"Down",left:"Left",right:"Right",pageup:"PPage",pagedown:"NPage",home:"Home",end:"End"};function dvr(e){if(e==="+")return{key:"+",modifiers:[]};if(e.endsWith("++"))return{key:"+",modifiers:e.slice(0,-2).split("+")};let t=e.split("+");return{key:t.pop(),modifiers:t}}function vMi(e){return R0e(e)[0]}function R0e(e){let{key:t,modifiers:r}=dvr(e),i=new Set(r),o=(a,u)=>[i.has("ctrl")?"C-":"",i.has("alt")?"M-":"",u?"S-":"",TMi[a]??a].join("");if(i.has("shift")&&t.length===1&&/[a-z]/.test(t)){let a=t.toUpperCase();return!i.has("ctrl")&&!i.has("alt")?[o(a,!1)]:[o(a,!0),o(a,!1),o(t,!0)]}return[o(t,i.has("shift"))]}function CMi(e){let{key:t,modifiers:r}=dvr(e);return r.includes("shift")&&/[a-z]/.test(t)?t.toUpperCase():t==="space"?" ":t}function k0e(e,t,r){let i=[];for(let o of e){let a=t.get(o);if(a!==void 0)for(let u of r.gestures(o))i.push({description:a.description,selector:CMi(u),action:a.action})}return i}function xMi(e){let t=new Map;for(let[u,p]of Object.entries(gMi))p!==void 0&&t.set(u,p);for(let{menuId:u,actionId:p}of B4){let f=gP.find(_=>_.id===p);if(f===void 0)throw new Error(`missing attach binding definition ${p}`);t.set(u,{description:f.name.toLowerCase(),action:{kind:"literal-input",input:C0e(p)}})}let r=k0e(B4.map(({menuId:u})=>u),t,e);r.length>0&&t.set("crtr.tmux.menu.attach",{description:"attach viewer \u203A",action:{kind:"submenu",title:" attach viewer ",items:r}});let i=k0e(["crtr.tmux.menu.metadata","crtr.tmux.menu.context"],t,e);t.set("crtr.tmux.menu.show",{description:"inspect \u203A",action:{kind:"submenu",title:" inspect node ",items:i}});let o=k0e(["crtr.tmux.menu.fold-tools"],t,e);t.set("crtr.tmux.menu.view-settings",{description:"display \u203A",action:{kind:"submenu",title:" display ",items:o}});let a=k0e(["crtr.tmux.menu.issue.idea","crtr.tmux.menu.issue.bug"],t,e);return t.set("crtr.tmux.menu.issues",{description:"create \u203A",action:{kind:"submenu",title:" create ",items:a}}),t}function IMi(e,t){let r=u=>k0e(u,t,e),i=[],o=(u,p)=>{p.length!==0&&(i.length>0&&i.push({description:"",selector:"",action:{kind:"separator"}}),i.push({description:`-#[bold]${u}`,selector:"",action:{kind:"disabled"}},...p))};o("Explore",r(["crtr.tmux.menu.resume","crtr.tmux.menu.graph","crtr.tmux.menu.focus-manager","crtr.tmux.menu.show","crtr.tmux.menu.view-settings"])),o("Current node",r(["crtr.tmux.menu.attach","crtr.tmux.menu.background-bash","crtr.tmux.menu.file-review","crtr.tmux.menu.pin","crtr.tmux.menu.copy-id","crtr.tmux.menu.reload-viewer","crtr.tmux.menu.recap"])),o("Lifecycle",r(["crtr.tmux.menu.fork","crtr.tmux.menu.promote","crtr.tmux.menu.demote-mode","crtr.tmux.menu.demote","crtr.tmux.menu.make-resident","crtr.tmux.menu.detach","crtr.tmux.menu.close-subtree"])),o("System",r(["crtr.tmux.menu.providers","crtr.tmux.menu.plugins","crtr.tmux.menu.context-admin","crtr.tmux.menu.issues"]));let a=e.gestures("crtr.tmux.menu.open");if(a.length>0&&i.length>0){i.push({description:"",selector:"",action:{kind:"separator"}});for(let u of a)i.push({description:`${g7(u)} to close`,selector:vMi(u),action:{kind:"dismiss"}})}return i}function x3e(e,t){let r=t;for(;r<e.length&&/\s/.test(e[r]);)r+=1;if(r>=e.length)return null;let i=null,o="";for(;r<e.length;){let a=e[r];if(i===null&&/\s/.test(a))break;if(i===null&&(a==="'"||a==='"')){i=a,r+=1;continue}if(i===a){i=null,r+=1;continue}if(a==="\\"&&i!=="'"&&r+1<e.length){o+=e[r+1],r+=2;continue}o+=a,r+=1}return{value:o,end:r}}function fvr(e){let t=x3e(e,0);if(t?.value!=="bind-key")return null;let r=t.end,i=!1;for(;;){let o=x3e(e,r);if(o===null)return null;if(r=o.end,o.value==="-r"){i=!0;continue}if(o.value!=="-T")continue;let a=x3e(e,r);if(a===null)return null;let u=x3e(e,a.end);return u===null?null:{table:a.value,key:u.value,command:e.slice(u.end).trimStart(),repeat:i}}}function Sae(e,t){let r=_g(["list-keys","-T",e]);return r.ok?r.stdout.split(`
|
|
1646
|
+
`)){let[a,u,p,f]=o.split(" ");if(a===void 0||a===""||u===void 0||u===""||p===void 0||p==="")continue;let _=XTr(e,["display-message","-p","-t",a,"#{pane_current_command} #{pane_start_command} #{pane_pid}"]);if(!_.ok)continue;let[m="",g="",E]=_.stdout.split(" ");if(!(r0t(m,p)||r0t(g,p))){i??=uMi();let C=Number.parseInt(E,10);if(i===null||!Number.isInteger(C)||C<=0||!pMi(i,C,p))continue}let T=Number.parseInt(f??"",10);r.push({pane:a,session:u,nodeId:p,stampMs:Number.isSafeInteger(T)&&T>=0?T:0})}return r}function rvr(e){return["respawn-pane","-k","-c",e.cwd,...n0t(e.env),"-t",e.pane,e.command]}function u0t(e){return _g(rvr(e)).ok}function p0t(e){let t=`tmux ${rvr(e).map(Rm).join(" ")} >/dev/null 2>&1`;return _g(["run-shell","-b",t]).ok}function w0e(e,t){return _g(["select-window","-t",`${e}:${t}`]).ok}function v3e(e,t){return _g(["select-layout","-t",e,t]).ok}function C3e(e){return _g(["select-pane","-t",e]).ok}function d0t(e){return _g(["switch-client","-t",e]).ok}import{mkdtempSync as mMi,rmSync as hMi,writeFileSync as _Mi}from"node:fs";import{tmpdir as lvr}from"node:os";import{join as f0t}from"node:path";var dMi=Symbol.for("@earendil-works/pi-coding-agent:theme");function nvr(){return globalThis[dMi]??void 0}function ivr(){let e=nvr();if(e===void 0)throw new Error("surfaceBgAnsi: pi theme not initialized in this process");return e.getBgAnsi("selectedBg")}function fMi(){let e=nvr();if(e===void 0)return;let t=e.getBgAnsi("selectedBg"),r=/48;2;(\d+);(\d+);(\d+)/.exec(t);if(r!==null){let o=a=>Number(a).toString(16).padStart(2,"0");return`#${o(r[1])}${o(r[2])}${o(r[3])}`}let i=/48;5;(\d+)/.exec(t);if(i!==null)return`colour${i[1]}`}function oF(){let e=fMi();return e===void 0?[]:["-b","rounded","-s",`bg=${e}`,"-S",`bg=${e}`]}var w3e="@crtr_keybindings_manifest",rk="root",gMi={"crtr.tmux.menu.promote":{description:"promote to orchestrator",action:{kind:"keys",keys:"/promote"}},"crtr.tmux.menu.resume":{description:"find node",action:{kind:"keys",keys:"/resume-node"}},"crtr.tmux.menu.fork":{description:"fork into idle root",action:{kind:"direct",run:"node fork --pane {pane}"}},"crtr.tmux.menu.demote-mode":{description:"demote to base node",action:{kind:"command",run:"node config --mode base --pane {pane}"}},"crtr.tmux.menu.demote":{description:"demote to terminal (finish when done)",action:{kind:"command",run:"node lifecycle demote --pane {pane}"}},"crtr.tmux.menu.make-resident":{description:"make resident (interactable)",action:{kind:"command",run:"node config --lifecycle resident --pane {pane}"}},"crtr.tmux.menu.detach":{description:"demote + close viewer",action:{kind:"command",run:"node lifecycle demote --pane {pane} --detach"}},"crtr.tmux.menu.close-subtree":{description:"close agent + subtree",action:{kind:"command",run:"node lifecycle close --pane {pane}"}},"crtr.tmux.menu.background-bash":{description:"background running bash",action:{kind:"direct",run:"node bash background --pane {pane}"}},"crtr.tmux.menu.file-review":{description:"review a file",action:{kind:"raw-keys",keys:"M-S-r"}},"crtr.tmux.menu.metadata":{description:"metadata",action:{kind:"keys",keys:"/node-metadata"}},"crtr.tmux.menu.fold-tools":{description:"fold finished tool calls",action:{kind:"keys",keys:"/fold-tools"}},"crtr.tmux.menu.context":{description:"context + reports",action:{kind:"keys",keys:"/context"}},"crtr.tmux.menu.providers":{description:"settings",action:{kind:"popup",run:"sys settings",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.plugins":{description:"plugins",action:{kind:"popup",run:"pkg browse",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.context-admin":{description:"context surface",action:{kind:"popup",run:"sys context admin",size:{w:"98%",h:"96%"}}},"crtr.tmux.menu.graph":{description:"canvas graph",action:{kind:"keys",keys:"/graph"}},"crtr.tmux.menu.focus-manager":{description:"go to manager",action:{kind:"command",run:"surface node focus {manager}"}},"crtr.tmux.menu.copy-id":{description:"copy node id",action:{kind:"command",run:"surface node id --pane {pane}"}},"crtr.tmux.menu.reload-viewer":{description:"reload viewer",action:{kind:"direct",run:"surface reload --pane {pane}"}},"crtr.tmux.menu.recap":{description:"generate recap",action:{kind:"keys",keys:"/recap"}},"crtr.tmux.menu.pin":{description:"pin conversation",action:{kind:"direct",run:"surface node pin --pane {pane}"}},"crtr.tmux.menu.issue.idea":{description:"idea",action:{kind:"popup",run:"canvas issue new --type idea"}},"crtr.tmux.menu.issue.bug":{description:"bug",action:{kind:"popup",run:"canvas issue new --type bug"}}};function sK(e){return e.replace(/#/g,"##")}function yMi(e){return e.map(Rm).join(" ")}var bMi={w:"60%",h:"50%"};function ovr(e,t=!1,r=bMi){let i=`crtr canvas chord --pane '#{pane_id}' --run ${Rm(sK(e))}${t?" --interactive":""}`;return t?{argv:["display-popup","-E","-w",r.w,"-h",r.h,"-d","#{pane_current_path}",i],menu:`display-popup -E -w ${r.w} -h ${r.h} -d "#{pane_current_path}" ${Rm(i)}`}:{argv:["run-shell",`${i} >/dev/null 2>&1`],menu:`run-shell ${Rm(`${i} >/dev/null 2>&1`)}`}}function EMi(e){let r=`crtr ${sK(e).replace("{pane}","#{pane_id}")} >/dev/null 2>&1`;return{argv:["run-shell","-b",r],menu:`run-shell -b ${Rm(r)}`}}function uvr(e){switch(e.kind){case"disabled":return null;case"separator":return null;case"dismiss":return{argv:["refresh-client"],menu:"refresh-client"};case"keys":{let t=sK(e.keys);return{argv:["send-keys",t,"Enter"],menu:`send-keys -t '#{pane_id}' ${Rm(t)} Enter`}}case"raw-keys":{let t=sK(e.keys);return{argv:["send-keys",t],menu:`send-keys -t '#{pane_id}' ${Rm(t)}`}}case"literal-input":{let t=sK(e.input);return{argv:["send-keys","-l",t],menu:`send-keys -l -t '#{pane_id}' ${Rm(t)}`}}case"command":return ovr(e.run);case"direct":return EMi(e.run);case"popup":return ovr(e.run,!0,e.size);case"submenu":{let t=pvr(e.title,e.items);return{argv:t,menu:yMi(t)}}}}function AMi(e){return uvr(e)?.menu??""}function SMi(e){return e.replace(/#\[[^\]]*\]/g,"").length}function pvr(e,t){let r=sK(e),i=t.reduce((a,u)=>Math.max(a,SMi(u.description)),0),o=["display-menu","-T",`#[align=centre]${r}`,...oF()];o.push("-x",`#{e|-:#{pane_right},${Math.max(r.length,i)+7}}`,"-y","#{e|+:#{pane_top},3}","--");for(let a of t){if(a.action.kind==="separator"){o.push("");continue}let u=a.action.kind==="disabled"?a.description:sK(a.description);o.push(u,a.selector,AMi(a.action))}return o.push("","-esc / q to close","",""),o}var TMi={enter:"Enter",escape:"Escape",tab:"Tab",backspace:"BSpace",delete:"DC",space:"Space",up:"Up",down:"Down",left:"Left",right:"Right",pageup:"PPage",pagedown:"NPage",home:"Home",end:"End"};function dvr(e){if(e==="+")return{key:"+",modifiers:[]};if(e.endsWith("++"))return{key:"+",modifiers:e.slice(0,-2).split("+")};let t=e.split("+");return{key:t.pop(),modifiers:t}}function vMi(e){return R0e(e)[0]}function R0e(e){let{key:t,modifiers:r}=dvr(e),i=new Set(r),o=(a,u)=>[i.has("ctrl")?"C-":"",i.has("alt")?"M-":"",u?"S-":"",TMi[a]??a].join("");if(i.has("shift")&&t.length===1&&/[a-z]/.test(t)){let a=t.toUpperCase();return!i.has("ctrl")&&!i.has("alt")?[o(a,!1)]:[o(a,!0),o(a,!1),o(t,!0)]}return[o(t,i.has("shift"))]}function CMi(e){let{key:t,modifiers:r}=dvr(e);return r.includes("shift")&&/[a-z]/.test(t)?t.toUpperCase():t==="space"?" ":t}function k0e(e,t,r){let i=[];for(let o of e){let a=t.get(o);if(a!==void 0)for(let u of r.gestures(o))i.push({description:a.description,selector:CMi(u),action:a.action})}return i}function xMi(e){let t=new Map;for(let[u,p]of Object.entries(gMi))p!==void 0&&t.set(u,p);for(let{menuId:u,actionId:p}of B4){let f=gP.find(_=>_.id===p);if(f===void 0)throw new Error(`missing attach binding definition ${p}`);t.set(u,{description:f.name.toLowerCase(),action:{kind:"literal-input",input:C0e(p)}})}let r=k0e(B4.map(({menuId:u})=>u),t,e);r.length>0&&t.set("crtr.tmux.menu.attach",{description:"attach viewer \u203A",action:{kind:"submenu",title:" attach viewer ",items:r}});let i=k0e(["crtr.tmux.menu.metadata","crtr.tmux.menu.context"],t,e);t.set("crtr.tmux.menu.show",{description:"inspect \u203A",action:{kind:"submenu",title:" inspect node ",items:i}});let o=k0e(["crtr.tmux.menu.fold-tools"],t,e);t.set("crtr.tmux.menu.view-settings",{description:"display \u203A",action:{kind:"submenu",title:" display ",items:o}});let a=k0e(["crtr.tmux.menu.issue.idea","crtr.tmux.menu.issue.bug"],t,e);return t.set("crtr.tmux.menu.issues",{description:"create \u203A",action:{kind:"submenu",title:" create ",items:a}}),t}function IMi(e,t){let r=u=>k0e(u,t,e),i=[],o=(u,p)=>{p.length!==0&&(i.length>0&&i.push({description:"",selector:"",action:{kind:"separator"}}),i.push({description:`-#[bold]${u}`,selector:"",action:{kind:"disabled"}},...p))};o("Explore",r(["crtr.tmux.menu.resume","crtr.tmux.menu.graph","crtr.tmux.menu.focus-manager","crtr.tmux.menu.show","crtr.tmux.menu.view-settings"])),o("Current node",r(["crtr.tmux.menu.attach","crtr.tmux.menu.background-bash","crtr.tmux.menu.file-review","crtr.tmux.menu.pin","crtr.tmux.menu.copy-id","crtr.tmux.menu.reload-viewer","crtr.tmux.menu.recap"])),o("Lifecycle",r(["crtr.tmux.menu.fork","crtr.tmux.menu.promote","crtr.tmux.menu.demote-mode","crtr.tmux.menu.demote","crtr.tmux.menu.make-resident","crtr.tmux.menu.detach","crtr.tmux.menu.close-subtree"])),o("System",r(["crtr.tmux.menu.providers","crtr.tmux.menu.plugins","crtr.tmux.menu.context-admin","crtr.tmux.menu.issues"]));let a=e.gestures("crtr.tmux.menu.open");if(a.length>0&&i.length>0){i.push({description:"",selector:"",action:{kind:"separator"}});for(let u of a)i.push({description:`${g7(u)} to close`,selector:vMi(u),action:{kind:"dismiss"}})}return i}function x3e(e,t){let r=t;for(;r<e.length&&/\s/.test(e[r]);)r+=1;if(r>=e.length)return null;let i=null,o="";for(;r<e.length;){let a=e[r];if(i===null&&/\s/.test(a))break;if(i===null&&(a==="'"||a==='"')){i=a,r+=1;continue}if(i===a){i=null,r+=1;continue}if(a==="\\"&&i!=="'"&&r+1<e.length){o+=e[r+1],r+=2;continue}o+=a,r+=1}return{value:o,end:r}}function fvr(e){let t=x3e(e,0);if(t?.value!=="bind-key")return null;let r=t.end,i=!1;for(;;){let o=x3e(e,r);if(o===null)return null;if(r=o.end,o.value==="-r"){i=!0;continue}if(o.value!=="-T")continue;let a=x3e(e,r);if(a===null)return null;let u=x3e(e,a.end);return u===null?null:{table:a.value,key:u.value,command:e.slice(u.end).trimStart(),repeat:i}}}function Sae(e,t){let r=_g(["list-keys","-T",e]);return r.ok?r.stdout.split(`
|
|
1647
1647
|
`).find(i=>{let o=fvr(i);return o?.table===e&&o.key===t})??null:null}function svr(e){return typeof e=="object"&&e!==null&&typeof e.table=="string"&&typeof e.key=="string"}function wMi(e){if(typeof e!="object"||e===null)return!1;let t=e;return typeof t.bindingId=="string"&&QY.has(t.bindingId)&&typeof t.gesture=="string"&&typeof t.key=="string"&&(typeof t.original=="string"||t.original===null)&&typeof t.wrapper=="string"&&(t.state==="owned"||t.state==="relinquished")}function RMi(){let e=_g(["show-options","-s","-q",w3e]);if(!e.ok)return null;if(e.stdout==="")return{pairs:[],wrappers:[]};let t=_g(["show-options","-s","-qv",w3e]);if(!t.ok)return null;try{let r=JSON.parse(t.stdout);if(Array.isArray(r))return r.every(svr)?{pairs:r,wrappers:[]}:null;if(typeof r!="object"||r===null)return null;let i=r;return!Array.isArray(i.pairs)||!i.pairs.every(svr)||!Array.isArray(i.wrappers)||!i.wrappers.every(wMi)?null:{pairs:i.pairs,wrappers:i.wrappers}}catch{return null}}function avr(e){return _g(["set-option","-s",w3e,JSON.stringify(e)])}function I3e(e){return e.replace(/\\/g,"\\\\").replace(/;/g,"\\;")}function kMi(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/;/g,"\\;")}"`}function NMi(e){let t=null,r="";for(let i=0;i<e.length;i+=1){let o=e[i];if(t===null&&(o==="'"||o==='"')){t=o,r+=o;continue}if(t===o){t=null,r+=o;continue}if(o==="\\"&&i+1<e.length){let a=e[i+1];t===null&&a===";"?r+=";":r+=o+a,i+=1;continue}r+=o}return r}function PMi(e){let t=mMi(f0t(lvr(),"crtr-tmux-binding-")),r=f0t(t,"binding.conf");try{return _Mi(r,`${e}
|
|
1648
1648
|
`,"utf8"),_g(["source-file",r])}finally{hMi(t,{recursive:!0,force:!0})}}function cvr(e){return e.original===null?_g(["unbind-key","-T",rk,I3e(e.key)]):PMi(e.original)}function OMi(){return["run-shell","-b",'crtr surface inbox --quiet --tmux-socket "#{socket_path}" --tmux-client "#{client_name}" --target-pane "#{pane_id}"']}function DMi(e){switch(e){case"crtr.tmux.node.next":return["run-shell","crtr surface node cycle --dir next --pane '#{pane_id}' >/dev/null 2>&1"];case"crtr.tmux.node.previous":return["run-shell","crtr surface node cycle --dir prev --pane '#{pane_id}' >/dev/null 2>&1"];case"crtr.tmux.inbox.toggle":return OMi();default:throw new Error(`no tmux command for ${e}`)}}function MMi(){let e=process.env.TMUX?.split(",")[0]?.trim();if(e!==void 0&&e!=="")return`${e}.crtr-keybindings.lock`;let t=_g(["display-message","-p","#{socket_path}"]);if(t.ok&&t.stdout!=="")return`${t.stdout}.crtr-keybindings.lock`;let r=typeof process.getuid=="function"?process.getuid():"user";return f0t(lvr(),`crtr-tmux-keybindings-${r}.lock`)}function R3e(e,t=[]){return bP(MMi(),()=>LMi(e,t))}function LMi(e,t=[]){let r=e===void 0?rK():void 0,i=e??r.bindings,o=e===void 0?r.tmuxPassthrough:yae(t),a=[],u=[],p=RMi();if(p===null)return a.push({code:"tmux-error",message:`tmux is unavailable or ${w3e} is malformed`}),{ok:!1,installed:u,diagnostics:a};let f=new Map;for(let I of o){let N=gP.find(k=>k.id===I);if(!(N===void 0||!p0e(N))){for(let k of i.gestures(I))if(!k.includes(" > "))for(let D of R0e(k))f.has(D)||f.set(D,{bindingId:I,gesture:k})}}let _=new Set,m=[];for(let I of p.wrappers){let N=f.get(I.key),k=Sae(rk,I.key);if(I.state==="relinquished"||k!==I.wrapper){_.add(I.key),N!==void 0&&m.push({...I,...N,state:"relinquished"});continue}let D=cvr(I);D.ok||(_.add(I.key),m.push(I),a.push({code:"tmux-error",bindingId:I.bindingId,gesture:I.gesture,message:`could not restore tmux binding ${rk}:${I.key}: ${D.stderr}`}))}for(let I of p.pairs){if(I.table===rk&&_.has(I.key))continue;let N=_g(["unbind-key","-T",I.table,I3e(I.key)]);!N.ok&&Sae(I.table,I.key)!==null&&a.push({code:"tmux-error",message:`could not remove crouter binding ${I.table}:${I.key}: ${N.stderr}`})}if(a.some(I=>I.code==="tmux-error")){let I=avr({pairs:p.pairs,wrappers:m});return I.ok||a.push({code:"tmux-error",message:`could not save crouter tmux ownership manifest: ${I.stderr}`}),{ok:!1,installed:u,diagnostics:a}}let g=(I,N,k,D,z)=>{if(Sae(I,N)!==null)return a.push({code:"occupied",bindingId:D,gesture:z,message:`${I}:${N} is already bound by tmux; ${D} was not installed`}),!1;let Z=_g(["bind-key","-T",I,I3e(N),...k]);return Z.ok?(u.push({table:I,key:N}),!0):(a.push({code:"tmux-error",bindingId:D,gesture:z,message:`could not install ${D}: ${Z.stderr}`}),!1)},E=xMi(i),v=pvr(" crtr ",IMi(i,E));for(let I of i.gestures("crtr.tmux.menu.open"))for(let N of R0e(I))g(rk,N,v,"crtr.tmux.menu.open",I);for(let I of gP){if(I.pair?.field!=="menu")continue;let N=gP.find(Q=>Q.id===I.pair?.pairedId);if(N?.pair?.field!=="global")continue;let k=I.id,D=N.id,z=E.get(k),Z=z===void 0?null:uvr(z.action);if(Z===null)throw new Error(`no direct tmux action for paired menu binding ${k}`);for(let Q of i.gestures(D))for(let J of R0e(Q))g(rk,J,Z.argv,D,Q)}for(let I of["crtr.tmux.node.next","crtr.tmux.node.previous","crtr.tmux.inbox.toggle"])for(let N of i.gestures(I))for(let k of R0e(N))g(rk,k,DMi(I),I,N);let T=[];for(let[I,N]of f){if(_.has(I))continue;let k=Sae(rk,I);if(k===null)continue;let D=fvr(k);if(D===null||D.command===""){a.push({code:"tmux-error",bindingId:N.bindingId,gesture:N.gesture,message:`could not parse occupied tmux binding ${rk}:${I}`});continue}let z=_g(["bind-key",...D.repeat?["-r"]:[],"-T",rk,I3e(I),"if-shell","-F","#{!=:#{@crtr_attach},}",`send-keys ${kMi(I)}`,NMi(D.command)]);if(!z.ok){a.push({code:"tmux-error",bindingId:N.bindingId,gesture:N.gesture,message:`could not wrap ${rk}:${I}: ${z.stderr}`});continue}let Z=Sae(rk,I);if(Z===null||!Z.includes("@crtr_attach")){a.push({code:"tmux-error",bindingId:N.bindingId,gesture:N.gesture,message:`could not fingerprint wrapped tmux binding ${rk}:${I}`});continue}let Q={...N,key:I,original:k,wrapper:Z,state:"owned"};m.push(Q),T.push(Q)}let C=avr({pairs:u,wrappers:m});if(!C.ok){a.push({code:"tmux-error",message:`could not save crouter tmux ownership manifest: ${C.stderr}`});for(let I of T)Sae(rk,I.key)===I.wrapper&&cvr(I)}return{ok:a.every(I=>I.code!=="tmux-error"),installed:u,diagnostics:a}}function N0e(){let e=o7();return e!==void 0?{CRTR_HOME:e}:{}}var hvr=(e=0)=>t=>`\x1B[${t+e}m`,_vr=(e=0)=>t=>`\x1B[${38+e};5;${t}m`,gvr=(e=0)=>(t,r,i)=>`\x1B[${38+e};2;${t};${r};${i}m`,HE={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],overline:[53,55],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],gray:[90,39],grey:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgGray:[100,49],bgGrey:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}},Vvs=Object.keys(HE.modifier),qMi=Object.keys(HE.color),GMi=Object.keys(HE.bgColor),Wvs=[...qMi,...GMi];function VMi(){let e=new Map;for(let[t,r]of Object.entries(HE)){for(let[i,o]of Object.entries(r))HE[i]={open:`\x1B[${o[0]}m`,close:`\x1B[${o[1]}m`},r[i]=HE[i],e.set(o[0],o[1]);Object.defineProperty(HE,t,{value:r,enumerable:!1})}return Object.defineProperty(HE,"codes",{value:e,enumerable:!1}),HE.color.close="\x1B[39m",HE.bgColor.close="\x1B[49m",HE.color.ansi=hvr(),HE.color.ansi256=_vr(),HE.color.ansi16m=gvr(),HE.bgColor.ansi=hvr(10),HE.bgColor.ansi256=_vr(10),HE.bgColor.ansi16m=gvr(10),Object.defineProperties(HE,{rgbToAnsi256:{value(t,r,i){return t===r&&r===i?t<8?16:t>248?231:Math.round((t-8)/247*24)+232:16+36*Math.round(t/255*5)+6*Math.round(r/255*5)+Math.round(i/255*5)},enumerable:!1},hexToRgb:{value(t){let r=/[a-f\d]{6}|[a-f\d]{3}/i.exec(t.toString(16));if(!r)return[0,0,0];let[i]=r;i.length===3&&(i=[...i].map(a=>a+a).join(""));let o=Number.parseInt(i,16);return[o>>16&255,o>>8&255,o&255]},enumerable:!1},hexToAnsi256:{value:t=>HE.rgbToAnsi256(...HE.hexToRgb(t)),enumerable:!1},ansi256ToAnsi:{value(t){if(t<8)return 30+t;if(t<16)return 90+(t-8);let r,i,o;if(t>=232)r=((t-232)*10+8)/255,i=r,o=r;else{t-=16;let p=t%36;r=Math.floor(t/36)/5,i=Math.floor(p/6)/5,o=p%6/5}let a=Math.max(r,i,o)*2;if(a===0)return 30;let u=30+(Math.round(o)<<2|Math.round(i)<<1|Math.round(r));return a===2&&(u+=60),u},enumerable:!1},rgbToAnsi:{value:(t,r,i)=>HE.ansi256ToAnsi(HE.rgbToAnsi256(t,r,i)),enumerable:!1},hexToAnsi:{value:t=>HE.ansi256ToAnsi(HE.hexToAnsi256(t)),enumerable:!1}}),HE}var WMi=VMi(),sF=WMi;import m0t from"node:process";import QMi from"node:os";import yvr from"node:tty";function tM(e,t=globalThis.Deno?globalThis.Deno.args:m0t.argv){let r=e.startsWith("-")?"":e.length===1?"-":"--",i=t.indexOf(r+e),o=t.indexOf("--");return i!==-1&&(o===-1||i<o)}var{env:JE}=m0t,k3e;tM("no-color")||tM("no-colors")||tM("color=false")||tM("color=never")?k3e=0:(tM("color")||tM("colors")||tM("color=true")||tM("color=always"))&&(k3e=1);function HMi(){if("FORCE_COLOR"in JE)return JE.FORCE_COLOR==="true"?1:JE.FORCE_COLOR==="false"?0:JE.FORCE_COLOR.length===0?1:Math.min(Number.parseInt(JE.FORCE_COLOR,10),3)}function JMi(e){return e===0?!1:{level:e,hasBasic:!0,has256:e>=2,has16m:e>=3}}function YMi(e,{streamIsTTY:t,sniffFlags:r=!0}={}){let i=HMi();i!==void 0&&(k3e=i);let o=r?k3e:i;if(o===0)return 0;if(r){if(tM("color=16m")||tM("color=full")||tM("color=truecolor"))return 3;if(tM("color=256"))return 2}if("TF_BUILD"in JE&&"AGENT_NAME"in JE)return 1;if(e&&!t&&o===void 0)return 0;let a=o||0;if(JE.TERM==="dumb")return a;if(m0t.platform==="win32"){let u=QMi.release().split(".");return Number(u[0])>=10&&Number(u[2])>=10586?Number(u[2])>=14931?3:2:1}if("CI"in JE)return["GITHUB_ACTIONS","GITEA_ACTIONS","CIRCLECI"].some(u=>u in JE)?3:["TRAVIS","APPVEYOR","GITLAB_CI","BUILDKITE","DRONE"].some(u=>u in JE)||JE.CI_NAME==="codeship"?1:a;if("TEAMCITY_VERSION"in JE)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(JE.TEAMCITY_VERSION)?1:0;if(JE.COLORTERM==="truecolor"||JE.TERM==="xterm-kitty"||JE.TERM==="xterm-ghostty"||JE.TERM==="wezterm")return 3;if("TERM_PROGRAM"in JE){let u=Number.parseInt((JE.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(JE.TERM_PROGRAM){case"iTerm.app":return u>=3?3:2;case"Apple_Terminal":return 2}}return/-256(color)?$/i.test(JE.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(JE.TERM)||"COLORTERM"in JE?1:a}function bvr(e,t={}){let r=YMi(e,{streamIsTTY:e&&e.isTTY,...t});return JMi(r)}var KMi={stdout:bvr({isTTY:yvr.isatty(1)}),stderr:bvr({isTTY:yvr.isatty(2)})},Evr=KMi;function Avr(e,t,r){let i=e.indexOf(t);if(i===-1)return e;let o=t.length,a=0,u="";do u+=e.slice(a,i)+t+r,a=i+o,i=e.indexOf(t,a);while(i!==-1);return u+=e.slice(a),u}function Svr(e,t,r,i){let o=0,a="";do{let u=e[i-1]==="\r";a+=e.slice(o,u?i-1:i)+t+(u?`\r
|
|
1649
1649
|
`:`
|
|
@@ -3,7 +3,7 @@ import { defineBranch, defineLeaf } from '../../core/command.js';
|
|
|
3
3
|
import { InputError } from '../../core/io.js';
|
|
4
4
|
import { isPidAlive } from '../../core/canvas/pid.js';
|
|
5
5
|
import { fullName } from '../../core/canvas/labels.js';
|
|
6
|
-
import { fuzzyMatch } from '../../core/
|
|
6
|
+
import { fuzzyMatch } from '../../core/tui/fuzzy.js';
|
|
7
7
|
import { resolveProfileOperand } from '../../core/profiles/manifest.js';
|
|
8
8
|
import { profilesStateBlock } from '../../core/profiles/state-block.js';
|
|
9
9
|
import { nodeSnapshotLeaf } from '../node-snapshot.js';
|
|
@@ -47,6 +47,9 @@ export declare class ContextDetailPanel {
|
|
|
47
47
|
move(delta: number): void;
|
|
48
48
|
render(width: number, height: number, focused: boolean): string[];
|
|
49
49
|
private verdict;
|
|
50
|
+
/** All three rungs, not just the current one, so "what would demoting this
|
|
51
|
+
* save" is read rather than computed. */
|
|
52
|
+
private costs;
|
|
50
53
|
private acrossEvents;
|
|
51
54
|
}
|
|
52
55
|
/** The editable rows for one document, in the order the panel draws them. */
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// The dossier: one document's editable configuration above the read-only
|
|
2
|
-
// verdict that configuration produces
|
|
3
|
-
//
|
|
2
|
+
// verdict that configuration produces, and below that the document's own
|
|
3
|
+
// opening lines. Every selectable row here is a field the shell can write;
|
|
4
|
+
// everything below the rule is what the planner decided.
|
|
4
5
|
import { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';
|
|
5
6
|
import { padAnsi, theme, wrapText } from '../../../../core/tui/panel.js';
|
|
6
7
|
import { SURFACE_EVENTS } from '../../../../core/substrate/schema.js';
|
|
7
|
-
import { EVENT_INITIALS, cellStateOf, describeSurfaceEntry, plural } from './model.js';
|
|
8
|
+
import { EVENT_INITIALS, cellStateOf, describeSurfaceEntry, formatCost, plural, rungCostsOf } from './model.js';
|
|
8
9
|
const STATE_WORD = {
|
|
9
10
|
pending: 'planning…',
|
|
10
11
|
delivers: 'delivers',
|
|
@@ -104,8 +105,14 @@ export class ContextDetailPanel {
|
|
|
104
105
|
lines.push(theme.fg('dim', ` VERDICT · ${this.event}`));
|
|
105
106
|
lines.push(...this.verdict(record, width));
|
|
106
107
|
lines.push('');
|
|
108
|
+
lines.push(theme.fg('dim', ' COST IF DELIVERED · approximate'));
|
|
109
|
+
lines.push(...this.costs(record, width));
|
|
110
|
+
lines.push('');
|
|
107
111
|
lines.push(theme.fg('dim', ' ACROSS EVENTS'));
|
|
108
112
|
lines.push(...this.acrossEvents(row, width));
|
|
113
|
+
lines.push('');
|
|
114
|
+
lines.push(theme.fg('dim', ' BODY'));
|
|
115
|
+
lines.push(...bodyPreview(record.doc.body, width, height));
|
|
109
116
|
const cursorLine = rowLines.get(this.index) ?? 0;
|
|
110
117
|
const maxStart = Math.max(0, lines.length - height);
|
|
111
118
|
let start = Math.min(Math.max(0, cursorLine - Math.floor(height / 3)), maxStart);
|
|
@@ -133,6 +140,16 @@ export class ContextDetailPanel {
|
|
|
133
140
|
}
|
|
134
141
|
return out;
|
|
135
142
|
}
|
|
143
|
+
/** All three rungs, not just the current one, so "what would demoting this
|
|
144
|
+
* save" is read rather than computed. */
|
|
145
|
+
costs(record, width) {
|
|
146
|
+
const costs = rungCostsOf(record);
|
|
147
|
+
const cells = ['content', 'preview', 'name'].map((rung) => {
|
|
148
|
+
const text = `${padAnsi(rung, 8)}${padAnsi(formatCost(costs[rung]) || '~0', 8)}`;
|
|
149
|
+
return rung === record.finalRung ? theme.fg('success', text) : theme.fg('dim', text);
|
|
150
|
+
});
|
|
151
|
+
return [truncateToWidth(` ${cells.join(' ')}`, width)];
|
|
152
|
+
}
|
|
136
153
|
acrossEvents(row, width) {
|
|
137
154
|
return SURFACE_EVENTS.map((event) => {
|
|
138
155
|
const record = row.records.get(event);
|
|
@@ -165,6 +182,18 @@ function bodyLines(body) {
|
|
|
165
182
|
const trimmed = body.replace(/\n+$/, '');
|
|
166
183
|
return trimmed === '' ? 0 : trimmed.split('\n').length;
|
|
167
184
|
}
|
|
185
|
+
/** The document's opening lines, filling the rows the dossier would otherwise
|
|
186
|
+
* leave blank. Bounded by the pane height: past that the reader is scrolling,
|
|
187
|
+
* and the body opens in $EDITOR. */
|
|
188
|
+
function bodyPreview(body, width, height) {
|
|
189
|
+
const trimmed = body.trim();
|
|
190
|
+
if (trimmed === '')
|
|
191
|
+
return [theme.fg('dim', ' (empty)')];
|
|
192
|
+
return trimmed
|
|
193
|
+
.split('\n')
|
|
194
|
+
.slice(0, Math.max(1, height))
|
|
195
|
+
.map((line) => theme.fg('dim', truncateToWidth(` ${line}`, width)));
|
|
196
|
+
}
|
|
168
197
|
const FIELD_WIDTH = 15;
|
|
169
198
|
function field(label, value, width) {
|
|
170
199
|
const room = Math.max(1, width - FIELD_WIDTH - 2);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type SurfaceEvent } from '../../../../core/substrate/schema.js';
|
|
2
2
|
import type { DeliveryRecord } from '../../../../core/substrate/plan.js';
|
|
3
3
|
import { PlanSet } from './model.js';
|
|
4
|
+
import { type Filters } from './list-view.js';
|
|
4
5
|
/** One physical document across every event. `records` is sparse: an event
|
|
5
6
|
* whose corpus never reaches this document has no record for it, and an event
|
|
6
7
|
* still being planned has none yet either. */
|
|
@@ -18,27 +19,36 @@ export interface DocRow {
|
|
|
18
19
|
/** The union of every planned event's corpus, ordered by the focused event's
|
|
19
20
|
* precedence order with the documents only other events see appended. */
|
|
20
21
|
export declare function buildRows(plans: PlanSet, event: SurfaceEvent): DocRow[];
|
|
21
|
-
export declare function rowDelivers(row: DocRow): boolean;
|
|
22
22
|
export declare class ContextDocsPanel {
|
|
23
23
|
private readonly onChange;
|
|
24
24
|
private rows;
|
|
25
|
+
private filters;
|
|
26
|
+
private event;
|
|
27
|
+
private lines;
|
|
25
28
|
private index;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* visible beside the delivering ones. */
|
|
30
|
-
private deliveringOnly;
|
|
29
|
+
/** Groups the user opened. Empty means every group is collapsed, which is how
|
|
30
|
+
* the page opens: ~25 rows that name the whole corpus. */
|
|
31
|
+
private readonly expanded;
|
|
31
32
|
constructor(onChange: () => void);
|
|
33
|
+
/** The document the dossier describes: the focused row, or the first member
|
|
34
|
+
* of the focused group so the dossier is never blank. */
|
|
32
35
|
get selected(): DocRow | undefined;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
/** Documents the current question selects — counted from the group rollups,
|
|
37
|
+
* so a fully collapsed list still reports its size. */
|
|
38
|
+
get visibleCount(): number;
|
|
39
|
+
setRows(rows: DocRow[], event: SurfaceEvent, selectedKey?: string): void;
|
|
40
|
+
setFilters(filters: Filters): void;
|
|
36
41
|
move(delta: number): void;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
/** True when the focused line is a group, so the shell knows whether a
|
|
43
|
+
* descend opens a group or the dossier. */
|
|
44
|
+
get onGroup(): boolean;
|
|
45
|
+
toggleGroup(): void;
|
|
46
|
+
/** Rebuild the drawn lines, keeping the cursor on the same document (or the
|
|
47
|
+
* same group), and clamping when what it was on is gone. */
|
|
48
|
+
private relayout;
|
|
41
49
|
render(width: number, height: number, focused: boolean, plans: PlanSet): string[];
|
|
50
|
+
private groupLine;
|
|
51
|
+
private docLine;
|
|
42
52
|
/** Pad rather than trim: this column sets the length of the divider drawn
|
|
43
53
|
* beside it. */
|
|
44
54
|
private fit;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
// The middle column: every document the snapshot can see,
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
|
|
1
|
+
// The middle column: every document the snapshot can see, grouped by the first
|
|
2
|
+
// segment of its canonical name and each carrying its own six-event matrix. One
|
|
3
|
+
// row is one physical document, so two stores answering to the same canonical
|
|
4
|
+
// name stay two rows and the shadowed one is visible.
|
|
5
|
+
import { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';
|
|
5
6
|
import { padAnsi, theme, visibleRange } from '../../../../core/tui/panel.js';
|
|
6
7
|
import { SURFACE_EVENTS } from '../../../../core/substrate/schema.js';
|
|
7
|
-
import { EVENT_INITIALS, cellGlyph, cellStateOf, plural } from './model.js';
|
|
8
|
+
import { EVENT_INITIALS, cellGlyph, cellStateOf, formatCost, plural } from './model.js';
|
|
9
|
+
import { NO_FILTERS, buildListView, groupKeysOf } from './list-view.js';
|
|
8
10
|
/** The union of every planned event's corpus, ordered by the focused event's
|
|
9
11
|
* precedence order with the documents only other events see appended. */
|
|
10
12
|
export function buildRows(plans, event) {
|
|
@@ -41,133 +43,104 @@ export function buildRows(plans, event) {
|
|
|
41
43
|
absorb(other);
|
|
42
44
|
return order.map((key) => rows.get(key));
|
|
43
45
|
}
|
|
44
|
-
export function rowDelivers(row) {
|
|
45
|
-
for (const record of row.records.values())
|
|
46
|
-
if (record.finalRung !== 'none')
|
|
47
|
-
return true;
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
46
|
/** Cells and their width, so the shell's legend and the list agree. */
|
|
51
47
|
const CELL_COUNT = SURFACE_EVENTS.length;
|
|
52
48
|
const MATRIX_WIDTH = CELL_COUNT * 2 - 1;
|
|
49
|
+
const COST_WIDTH = 6;
|
|
50
|
+
/** The glyphs a group header counts its members with — the matrix vocabulary,
|
|
51
|
+
* so a rung reads the same in both columns. */
|
|
52
|
+
const RUNG_MARK = { content: '█', preview: '▄', name: '▁' };
|
|
53
53
|
export class ContextDocsPanel {
|
|
54
54
|
onChange;
|
|
55
55
|
rows = [];
|
|
56
|
+
filters = NO_FILTERS;
|
|
57
|
+
event = 'boot';
|
|
58
|
+
lines = [];
|
|
56
59
|
index = 0;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
* visible beside the delivering ones. */
|
|
61
|
-
deliveringOnly = false;
|
|
60
|
+
/** Groups the user opened. Empty means every group is collapsed, which is how
|
|
61
|
+
* the page opens: ~25 rows that name the whole corpus. */
|
|
62
|
+
expanded = new Set();
|
|
62
63
|
constructor(onChange) {
|
|
63
64
|
this.onChange = onChange;
|
|
64
65
|
}
|
|
66
|
+
/** The document the dossier describes: the focused row, or the first member
|
|
67
|
+
* of the focused group so the dossier is never blank. */
|
|
65
68
|
get selected() {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
get ownsKeyboard() {
|
|
71
|
-
return this.filtering;
|
|
69
|
+
const line = this.lines[this.index];
|
|
70
|
+
if (line === undefined)
|
|
71
|
+
return undefined;
|
|
72
|
+
return line.kind === 'doc' ? line.row : line.first;
|
|
72
73
|
}
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
/** Documents the current question selects — counted from the group rollups,
|
|
75
|
+
* so a fully collapsed list still reports its size. */
|
|
76
|
+
get visibleCount() {
|
|
77
|
+
return this.lines.reduce((count, line) => count + (line.kind === 'group' ? line.docs : 0), 0);
|
|
75
78
|
}
|
|
76
|
-
setRows(rows, selectedKey) {
|
|
79
|
+
setRows(rows, event, selectedKey) {
|
|
77
80
|
this.rows = rows;
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
+
this.event = event;
|
|
82
|
+
const live = groupKeysOf(rows);
|
|
83
|
+
for (const key of this.expanded)
|
|
84
|
+
if (!live.has(key))
|
|
85
|
+
this.expanded.delete(key);
|
|
86
|
+
this.relayout(selectedKey);
|
|
87
|
+
}
|
|
88
|
+
setFilters(filters) {
|
|
89
|
+
this.filters = filters;
|
|
90
|
+
this.relayout(this.selected?.key);
|
|
81
91
|
}
|
|
82
92
|
move(delta) {
|
|
83
|
-
|
|
84
|
-
if (rows.length === 0)
|
|
93
|
+
if (this.lines.length === 0)
|
|
85
94
|
return;
|
|
86
|
-
this.index = Math.max(0, Math.min(
|
|
95
|
+
this.index = Math.max(0, Math.min(this.lines.length - 1, this.index + delta));
|
|
87
96
|
this.onChange();
|
|
88
97
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
this.index
|
|
93
|
-
if (held !== undefined) {
|
|
94
|
-
const at = this.visible().findIndex((row) => row.key === held);
|
|
95
|
-
if (at >= 0)
|
|
96
|
-
this.index = at;
|
|
97
|
-
}
|
|
98
|
-
this.onChange();
|
|
98
|
+
/** True when the focused line is a group, so the shell knows whether a
|
|
99
|
+
* descend opens a group or the dossier. */
|
|
100
|
+
get onGroup() {
|
|
101
|
+
return this.lines[this.index]?.kind === 'group';
|
|
99
102
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
else if (matchesKey(data, 'backspace')) {
|
|
111
|
-
this.filter = this.filter.slice(0, -1);
|
|
112
|
-
this.index = 0;
|
|
113
|
-
}
|
|
114
|
-
else if (data.length === 1 && data.charCodeAt(0) >= 32) {
|
|
115
|
-
this.filter += data;
|
|
116
|
-
this.index = 0;
|
|
117
|
-
}
|
|
118
|
-
this.onChange();
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
if (data === '/' || matchesKey(data, '/')) {
|
|
122
|
-
this.filtering = true;
|
|
123
|
-
this.onChange();
|
|
124
|
-
return true;
|
|
125
|
-
}
|
|
126
|
-
if (matchesKey(data, 'escape') && this.filter !== '') {
|
|
127
|
-
this.filter = '';
|
|
128
|
-
this.index = 0;
|
|
129
|
-
this.onChange();
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
return false;
|
|
103
|
+
toggleGroup() {
|
|
104
|
+
const line = this.lines[this.index];
|
|
105
|
+
if (line?.kind !== 'group')
|
|
106
|
+
return;
|
|
107
|
+
if (this.expanded.has(line.key))
|
|
108
|
+
this.expanded.delete(line.key);
|
|
109
|
+
else
|
|
110
|
+
this.expanded.add(line.key);
|
|
111
|
+
this.relayout(undefined, line.key);
|
|
112
|
+
this.onChange();
|
|
133
113
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
114
|
+
/** Rebuild the drawn lines, keeping the cursor on the same document (or the
|
|
115
|
+
* same group), and clamping when what it was on is gone. */
|
|
116
|
+
relayout(selectedKey, groupKey) {
|
|
117
|
+
const held = selectedKey ?? (this.lines[this.index]?.kind === 'doc' ? this.lines[this.index].key : undefined);
|
|
118
|
+
this.lines = buildListView(this.rows, this.filters, this.expanded, this.event);
|
|
119
|
+
const wanted = groupKey !== undefined
|
|
120
|
+
? this.lines.findIndex((line) => line.kind === 'group' && line.key === groupKey)
|
|
121
|
+
: held === undefined
|
|
122
|
+
? -1
|
|
123
|
+
: this.lines.findIndex((line) => line.kind === 'doc' && line.key === held);
|
|
124
|
+
this.index = wanted >= 0 ? wanted : Math.max(0, Math.min(this.index, this.lines.length - 1));
|
|
143
125
|
}
|
|
144
126
|
render(width, height, focused, plans) {
|
|
145
|
-
const rows = this.visible();
|
|
146
127
|
const out = [];
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const count = this.filter === '' ? plural(rows.length, 'doc', 'docs') : plural(rows.length, 'match', 'matches');
|
|
128
|
+
const nameRoom = Math.max(1, width - MATRIX_WIDTH - COST_WIDTH - 3);
|
|
129
|
+
const heading = this.filters.query === '' ? 'DOCUMENTS' : `/${this.filters.query}`;
|
|
130
|
+
const count = this.filters.query === ''
|
|
131
|
+
? plural(this.visibleCount, 'doc', 'docs')
|
|
132
|
+
: plural(this.visibleCount, 'match', 'matches');
|
|
153
133
|
const matrixHead = SURFACE_EVENTS.map((event) => EVENT_INITIALS[event]).join(' ');
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
out.push('', theme.fg('dim', this.filter === '' ? ' No documents in this snapshot\u2019s corpus.' : ' Nothing matches that filter.'));
|
|
134
|
+
out.push(truncateToWidth(` ${padAnsi(`${theme.fg('accent', theme.bold(heading))} ${theme.fg('dim', count)}`, nameRoom + COST_WIDTH + 1)} ${theme.fg('dim', matrixHead)}`, width));
|
|
135
|
+
if (this.lines.length === 0) {
|
|
136
|
+
out.push('', theme.fg('dim', ' Nothing matches this question — cycle a facet back to "any".'));
|
|
158
137
|
return this.fit(out, height);
|
|
159
138
|
}
|
|
160
139
|
const capacity = Math.max(1, height - out.length);
|
|
161
|
-
const range = visibleRange(
|
|
140
|
+
const range = visibleRange(this.lines.length, this.index, capacity);
|
|
162
141
|
for (let at = range.start; at < range.end; at += 1) {
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
-
const state = plans.peek(event) === undefined ? 'pending' : cellStateOf(row.records.get(event));
|
|
166
|
-
return cellGlyph(row.records.get(event), state);
|
|
167
|
-
}).join(' ');
|
|
168
|
-
const scope = theme.fg('dim', ` ${row.anchor.scope}`);
|
|
169
|
-
const label = truncateToWidth(`${row.name}${scope}`, nameRoom - 1);
|
|
170
|
-
const body = ` ${padAnsi(label, nameRoom - 1)} ${matrix}`;
|
|
142
|
+
const line = this.lines[at];
|
|
143
|
+
const body = line.kind === 'group' ? this.groupLine(line, nameRoom) : this.docLine(line, nameRoom, plans);
|
|
171
144
|
out.push(at === this.index && focused
|
|
172
145
|
? theme.bg('selectedBg', padAnsi(body, width))
|
|
173
146
|
: at === this.index
|
|
@@ -176,6 +149,26 @@ export class ContextDocsPanel {
|
|
|
176
149
|
}
|
|
177
150
|
return this.fit(out, height);
|
|
178
151
|
}
|
|
152
|
+
groupLine(line, nameRoom) {
|
|
153
|
+
const marker = line.expanded ? '▾' : '▸';
|
|
154
|
+
const label = `${marker} ${theme.bold(line.label)}`;
|
|
155
|
+
const marks = ['content', 'preview', 'name']
|
|
156
|
+
.filter((rung) => line.rungs[rung] > 0)
|
|
157
|
+
.map((rung) => `${line.rungs[rung]}${RUNG_MARK[rung]}`)
|
|
158
|
+
.join(' ');
|
|
159
|
+
const stats = theme.fg('dim', marks === '' ? plural(line.docs, 'doc', 'docs') : `${line.docs} · ${marks}`);
|
|
160
|
+
const room = Math.max(1, nameRoom - visibleWidth(stats) - 1);
|
|
161
|
+
const field = `${padAnsi(truncateToWidth(label, room), room)} ${stats}`;
|
|
162
|
+
return ` ${padAnsi(field, nameRoom)} ${cost(line.cost)} ${' '.repeat(MATRIX_WIDTH)}`;
|
|
163
|
+
}
|
|
164
|
+
docLine(line, nameRoom, plans) {
|
|
165
|
+
const matrix = SURFACE_EVENTS.map((event) => {
|
|
166
|
+
const state = plans.peek(event) === undefined ? 'pending' : cellStateOf(line.row.records.get(event));
|
|
167
|
+
return cellGlyph(line.row.records.get(event), state);
|
|
168
|
+
}).join(' ');
|
|
169
|
+
const label = truncateToWidth(` ${line.label}`, nameRoom);
|
|
170
|
+
return ` ${padAnsi(label, nameRoom)} ${cost(line.cost)} ${matrix}`;
|
|
171
|
+
}
|
|
179
172
|
/** Pad rather than trim: this column sets the length of the divider drawn
|
|
180
173
|
* beside it. */
|
|
181
174
|
fit(lines, height) {
|
|
@@ -184,3 +177,8 @@ export class ContextDocsPanel {
|
|
|
184
177
|
return lines.slice(0, height).map((line) => (visibleWidth(line) === 0 ? '' : line));
|
|
185
178
|
}
|
|
186
179
|
}
|
|
180
|
+
/** Right-flushed into the cost column, dim because it is an estimate. */
|
|
181
|
+
function cost(count) {
|
|
182
|
+
const text = formatCost(count);
|
|
183
|
+
return theme.fg('dim', ' '.repeat(Math.max(0, COST_WIDTH - text.length)) + text);
|
|
184
|
+
}
|