@ai-agent-forge/agent-forge 0.85.22 → 0.86.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/bundle/.build-manifest.json +7 -7
- package/dist/bundle/chunks/{chunk-DQFSJR74.js → chunk-2L25YYPC.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +39 -0
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.86.0] - 2026-09-30
|
|
6
|
+
### Removed
|
|
7
|
+
|
|
8
|
+
- Send-boundary one-turn image expiry in the SDK's convertToLlm wrapper (shipped default-on in 0.85.24). Reverted to plain `convertToLlm(messages)` together with the agent-core mechanism: the snake-workflow seat experiment measured ~4x total input increase (144,082 vs 35,249 tokens over 4 rounds) from cache re-billing after mid-history rewrites on this gateway.
|
|
9
|
+
|
|
10
|
+
## [0.85.24] - 2026-09-30
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Image expiry counting follows model requests (default: expire after the first assistant response that saw the image), gated by an 8K-token tail window — see `@agent-forge/agent` 0.85.24. Deterministic coverage extended in `test/context-payload-policy.test.ts` (seen-once expiry, keepRequests=N, window deferral).
|
|
14
|
+
## [0.85.23] - 2026-09-30
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- One-turn image expiry at the send boundary (user decision, cache-verified): every model request now placeholder-reduces image parts of COMPLETED turns (`expireStaleImageParts(messages, keepTurns=1)` in the SDK's convertToLlm wrapper) — an image costs its ~5.6K tokens once instead of on every later turn, the active turn's images ride untouched, session storage keeps the originals, and the placeholder says the analysis stays in the conversation. Gateway cache measurements behind the timing (3.7K/45K/89K-token probes): append-style requests keep ~99.7% cache hit, tail mutations 88-99.9%, mid-history rewrites 40-50% — expiring right after the turn pins the mutation to the tail. Deterministic coverage in `test/one-turn-image-expiry.test.ts` (capturing streamFn at the SDK send seam).
|
|
5
18
|
## [0.85.22] - 2026-09-30
|
|
6
19
|
### Changed
|
|
7
20
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generatedAt": "2026-09-
|
|
2
|
+
"generatedAt": "2026-09-30T14:04:54.835Z",
|
|
3
3
|
"inputCount": 3560,
|
|
4
4
|
"inputs": {
|
|
5
5
|
"node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs": "717f9403f2d3ee0f2077aeb7f0ca7eaff7cc9bcdbb054ac23c6c0361fa03cd1f",
|
|
@@ -2255,7 +2255,7 @@
|
|
|
2255
2255
|
"packages/agent-forge/dist/modes/interactive/components/diff.js": "4d4d8accd933bda88cbbd34440ddfdc1160d8eaebdd42a8033cafba8cadf27a9",
|
|
2256
2256
|
"packages/agent-forge/dist/modes/interactive/components/dynamic-border.js": "bf7d221ef1c6f2334a6a6b247a1554ebad018931417c651065689802ab7fd2e9",
|
|
2257
2257
|
"packages/agent-forge/dist/modes/interactive/components/first-time-setup.js": "71bd0b3fb50da9df6cbf77193c36043a3a075fe82879f6b993cb942635e94e0b",
|
|
2258
|
-
"packages/agent-forge/dist/modes/interactive/components/footer.js": "
|
|
2258
|
+
"packages/agent-forge/dist/modes/interactive/components/footer.js": "2f15e827493d35fa1df711983d2893feb6662422287982160021301cf100ed08",
|
|
2259
2259
|
"packages/agent-forge/dist/modes/interactive/components/index.js": "f77dc299f503ade5c61e7e4b5444efe82735855f324ab54cbe19f809d67ec443",
|
|
2260
2260
|
"packages/agent-forge/dist/modes/interactive/components/keybinding-hints.js": "e069455b09f6c91b628ad94e6e466b3574d2614e8bdda59c82f3a5c1fa6ce1e3",
|
|
2261
2261
|
"packages/agent-forge/dist/modes/interactive/components/login-dialog.js": "fd70f14f81423f8d86e4e58a435fb0a9127a66f385cb4d238721d04ff0f040dd",
|
|
@@ -2611,7 +2611,7 @@
|
|
|
2611
2611
|
"packages/agent-forge/src/modes/interactive/components/diff.ts": "b43f8d91ba9f19088dc9dc86126091c3fdfca25eac6461f5510f5e1e9ddd6491",
|
|
2612
2612
|
"packages/agent-forge/src/modes/interactive/components/dynamic-border.ts": "7bd584d21464215d68823cbee753b0a5ee730cfbf6627d5193e06483d1b62827",
|
|
2613
2613
|
"packages/agent-forge/src/modes/interactive/components/first-time-setup.ts": "8f0f6586950d791ba208253629d573754a34821d369b68b06c37f79b579cda57",
|
|
2614
|
-
"packages/agent-forge/src/modes/interactive/components/footer.ts": "
|
|
2614
|
+
"packages/agent-forge/src/modes/interactive/components/footer.ts": "9b94cb98488e8bcda28b3f6de4af1951fe231a2ee3f343c9631ec190c88d2aca",
|
|
2615
2615
|
"packages/agent-forge/src/modes/interactive/components/index.ts": "ab2fd962401ec94454bba62bdf25b88bf63fc98d91096399bf686bfab4ac6a55",
|
|
2616
2616
|
"packages/agent-forge/src/modes/interactive/components/keybinding-hints.ts": "edf1ee40ff7cedb0791d7bf8e4729d60002ff147b88697782494726331d0ce58",
|
|
2617
2617
|
"packages/agent-forge/src/modes/interactive/components/login-dialog.ts": "92195870f87ad623fb39a0e61798ad726a533f8462732f0d209c16feed9a0004",
|
|
@@ -2780,7 +2780,7 @@
|
|
|
2780
2780
|
"packages/agent/dist/agent.js": "32fdc72bff08ec3e54805ecd9dff39d171148e6f14bb10d89524d65024dd95ed",
|
|
2781
2781
|
"packages/agent/dist/harness/agent-harness.js": "21fdb3355adafd53c26337617a73918ba49e9832c42cde8b71c469abeecb5916",
|
|
2782
2782
|
"packages/agent/dist/harness/compaction/branch-summarization.js": "a076f14bd4e815693d5d42c81c110f68ad40d72652fa61fa916a7e516e82bd2b",
|
|
2783
|
-
"packages/agent/dist/harness/compaction/compaction.js": "
|
|
2783
|
+
"packages/agent/dist/harness/compaction/compaction.js": "01a22485522738d4673b53848e20039a939f18aa77b43f8453c86486f214447d",
|
|
2784
2784
|
"packages/agent/dist/harness/compaction/utils.js": "3cd34076fcd2cb016ab5bde9d9aa3e2e259d20ed6a5848b49893e941b7e13bf7",
|
|
2785
2785
|
"packages/agent/dist/harness/messages.js": "201ad9a53d6c101224764929c703dc99b8d9a19384327cf606712a11ec87f521",
|
|
2786
2786
|
"packages/agent/dist/harness/prompt-templates.js": "a3fd10825495ab9b25dbc635b34d23131a46c55ad35e3c477707b7462562bea7",
|
|
@@ -2811,7 +2811,7 @@
|
|
|
2811
2811
|
"packages/agent/dist/harness/types.js": "8aa91d66f770ac7046886e6a915abcf6c5e5a1f9eed7b25086f839a9b726962e",
|
|
2812
2812
|
"packages/agent/dist/harness/utils/shell-output.js": "899fecfd9e91f7f189cb76f4099f431679d83b35f25f841b73faa12e0c680eb2",
|
|
2813
2813
|
"packages/agent/dist/harness/utils/truncate.js": "d265bdde1c575add9f3e02c6066aeeabda7e96cf1f6a49c5aa6da8cf924bdd70",
|
|
2814
|
-
"packages/agent/dist/index.js": "
|
|
2814
|
+
"packages/agent/dist/index.js": "d48d932f939125a6dca4a644345f3d7ea67461229aa32976d3afb009f6e1ed35",
|
|
2815
2815
|
"packages/agent/dist/proxy.js": "9da0971466ba8042e871a051e6073ba903c580b8959141e08e1fa31c152bde46",
|
|
2816
2816
|
"packages/agent/dist/search/index.js": "55c69a20cc2ba96d52ce1813bc1fdde4fe651eb8c4ccd9e7e9744b2d5981655e",
|
|
2817
2817
|
"packages/agent/dist/search/scanning.js": "58ed602ce21315af8d45a6890dd14a3e0bb22c2ccea1df26ae24a4a2ff4068a3",
|
|
@@ -2821,7 +2821,7 @@
|
|
|
2821
2821
|
"packages/agent/src/agent.ts": "e8b50d9ffa4960e5f3414cd1ececec9e3a0bca2c4fd9a75006aefdd4a3e20391",
|
|
2822
2822
|
"packages/agent/src/harness/agent-harness.ts": "3297f5ae67f84e0bc663c2d297671f1f59a006de83d2877c791e9a33e8e8f69d",
|
|
2823
2823
|
"packages/agent/src/harness/compaction/branch-summarization.ts": "74ed3ca28c0a67b39bb16509e251860b891d0a8629ebe4ab75876093bd0b7830",
|
|
2824
|
-
"packages/agent/src/harness/compaction/compaction.ts": "
|
|
2824
|
+
"packages/agent/src/harness/compaction/compaction.ts": "bb0b9f86b066e2e8f2d88d3a1db8d143a32517a3f3fece28bfcb3d0c7815a9ba",
|
|
2825
2825
|
"packages/agent/src/harness/compaction/utils.ts": "cdb08c8de612e785c1356405657530221b94272160798390fada02dd34249243",
|
|
2826
2826
|
"packages/agent/src/harness/env/nodejs.ts": "485860c326689a4a9922b2e6b03cf1b945b3c6d48f5a53ac9b80510048c31bac",
|
|
2827
2827
|
"packages/agent/src/harness/events.ts": "ba43b8d888113db8ea89f0b9396a4f6dd1cffc3c8739abff308293bac3e2d536",
|
|
@@ -2860,7 +2860,7 @@
|
|
|
2860
2860
|
"packages/agent/src/harness/types.ts": "481fc414421f806f8a91aeeb7bdfe0f552d2318b68312af743b9b127d51c7156",
|
|
2861
2861
|
"packages/agent/src/harness/utils/shell-output.ts": "8fd2bbcce48a35d8801c49feb4d8592bce89bf28c4fce7f0645656e6b00b9d35",
|
|
2862
2862
|
"packages/agent/src/harness/utils/truncate.ts": "5fad606060248f86bedd8bc74ea8b04cf8d8b82e6ecd084cd84ed3f310a822e3",
|
|
2863
|
-
"packages/agent/src/index.ts": "
|
|
2863
|
+
"packages/agent/src/index.ts": "1580340d02c56171858c20163cc0c0eaf3f1e75481dec19dd3f01aa2cfa09c05",
|
|
2864
2864
|
"packages/agent/src/node.ts": "63d8dc9b22d93b3b1172ed1f1e83cc62bb370789f56f8dd31affb5c2a0a8dff3",
|
|
2865
2865
|
"packages/agent/src/proxy.ts": "68f4fa5ce569b0ec5980e0458a36f717f52f59e22a4b8eb33e5932b97ac3e9a3",
|
|
2866
2866
|
"packages/agent/src/search/index.ts": "69989ca6ca98c870ef211e6b855072901b41f95a8822379fadf53705d974486b",
|
|
@@ -1324,7 +1324,7 @@ ${statusParts.join(`
|
|
|
1324
1324
|
`;this.addChild(new Markdown(header+this.message.summary,0,0,this.markdownTheme,{color:text=>theme.fg("customMessageText",text)}))}else this.addChild(new Text(theme.fg("customMessageText","Branch summary (")+theme.fg("dim",keyText("app.tools.expand"))+theme.fg("customMessageText"," to expand)"),0,0))}};var CompactionSummaryMessageComponent=class extends Box{expanded=!1;message;markdownTheme;constructor(message,markdownTheme=getMarkdownTheme()){super(1,1,t=>theme.bg("customMessageBg",t)),this.message=message,this.markdownTheme=markdownTheme,this.updateDisplay()}setExpanded(expanded){this.expanded=expanded,this.updateDisplay()}invalidate(){super.invalidate(),this.updateDisplay()}updateDisplay(){this.clear();let tokenStr=this.message.tokensBefore.toLocaleString(),label=theme.fg("customMessageLabel","\x1B[1m[compaction]\x1B[22m");if(this.addChild(new Text(label,0,0)),this.addChild(new Spacer(1)),this.expanded){let header=`**Compacted from ${tokenStr} tokens**
|
|
1325
1325
|
|
|
1326
1326
|
`;this.addChild(new Markdown(header+this.message.summary,0,0,this.markdownTheme,{color:text=>theme.fg("customMessageText",text)}))}else this.addChild(new Text(theme.fg("customMessageText",`Compacted from ${tokenStr} tokens (`)+theme.fg("dim",keyText("app.tools.expand"))+theme.fg("customMessageText"," to expand)"),0,0))}};var CustomEditor=class extends Editor{keybindings;actionHandlers=new Map;onEscape;onCtrlD;onPasteImage;constructor(tui,theme2,keybindings,options){super(tui,theme2,options),this.keybindings=keybindings}onAction(action,handler){this.actionHandlers.set(action,handler)}handleInput(data){if(this.keybindings.matches(data,"app.clipboard.pasteImage")){this.onPasteImage?.();return}if(this.keybindings.matches(data,"app.interrupt")){if(!this.isShowingAutocomplete()){let handler=this.onEscape??this.actionHandlers.get("app.interrupt");if(handler){handler();return}}super.handleInput(data);return}if(this.keybindings.matches(data,"app.exit")&&this.getText().length===0){let handler=this.onCtrlD??this.actionHandlers.get("app.exit");handler&&handler();return}if(this.keybindings.matches(data,"tui.editor.historyPrevious")||this.keybindings.matches(data,"tui.editor.historyNext")){super.handleInput(data);return}for(let[action,handler]of this.actionHandlers)if(action!=="app.interrupt"&&action!=="app.exit"&&this.keybindings.matches(data,action)){handler();return}super.handleInput(data)}};var CustomMessageComponent=class extends Container{message;customRenderer;box;customComponent;markdownTheme;_expanded=!1;outputPad;constructor(message,customRenderer,markdownTheme=getMarkdownTheme(),outputPad=1){super(),this.message=message,this.customRenderer=customRenderer,this.markdownTheme=markdownTheme,this.outputPad=outputPad,this.addChild(new Spacer(1)),this.box=new Box(1,1,t=>theme.bg("customMessageBg",t)),this.rebuild()}setExpanded(expanded){this._expanded!==expanded&&(this._expanded=expanded,this.rebuild())}setOutputPad(outputPad){this.outputPad!==outputPad&&(this.outputPad=outputPad,this.rebuild())}invalidate(){super.invalidate(),this.rebuild()}rebuild(){if(this.customComponent&&(this.removeChild(this.customComponent),this.customComponent=void 0),this.removeChild(this.box),this.customRenderer)try{let component=this.customRenderer(this.message,{expanded:this._expanded,outputPad:this.outputPad},theme);if(component){this.customComponent=component,this.addChild(component);return}}catch{}this.addChild(this.box),this.box.clear();let label=theme.fg("customMessageLabel",`\x1B[1m[${this.message.customType}]\x1B[22m`);this.box.addChild(new Text(label,0,0)),this.box.addChild(new Spacer(1));let text;typeof this.message.content=="string"?text=this.message.content:text=this.message.content.filter(c2=>c2.type==="text").map(c2=>c2.text).join(`
|
|
1327
|
-
`),this.box.addChild(new Markdown(text,0,0,this.markdownTheme,{color:text2=>theme.fg("customMessageText",text2)}))}};import{isAbsolute as isAbsolute12,relative as relative10,resolve as resolve20,sep as sep13}from"node:path";function areExperimentalFeaturesEnabled(){let configuredValue=process.env.AGENT_FORGE_EXPERIMENTAL;return configuredValue===void 0?process.env.PI_EXPERIMENTAL==="1":configuredValue==="1"}function sanitizeStatusText(text){return text.replace(/[\r\n\t]/g," ").replace(/ +/g," ").trim()}function formatTokens(count){return count<1e3?count.toString():count<1e4?`${(count/1e3).toFixed(1)}k`:count<1e6?`${Math.round(count/1e3)}k`:count<1e7?`${(count/1e6).toFixed(1)}M`:`${Math.round(count/1e6)}M`}function formatCwdForFooter(cwd,home){if(!home)return cwd;let resolvedCwd=resolve20(cwd),resolvedHome=resolve20(home),relativeToHome=relative10(resolvedHome,resolvedCwd);return relativeToHome===""||relativeToHome!==".."&&!relativeToHome.startsWith(`..${sep13}`)&&!isAbsolute12(relativeToHome)?relativeToHome===""?"~":`~${sep13}${relativeToHome}`:cwd}var FooterComponent=class{autoCompactEnabled=!0;session;footerData;constructor(session,footerData){this.session=session,this.footerData=footerData}setSession(session){this.session=session}get facade(){return createCodingAgentFacade(this.session)}setAutoCompactEnabled(enabled){this.autoCompactEnabled=enabled}invalidate(){}dispose(){}render(width){let state2=this.facade.getState(),usageTotals=createUsageTotals(),latestCacheHitRate,goalTitle,todoDone=0,todoTotal=0;for(let entry of this.facade.getEntries())if(entry.type==="message"&&entry.message.role==="assistant"){addUsageToTotals(usageTotals,entry.message.usage);let latestPromptTokens=entry.message.usage.input+entry.message.usage.cacheRead+entry.message.usage.cacheWrite;latestCacheHitRate=latestPromptTokens>0?entry.message.usage.cacheRead/latestPromptTokens*100:void 0}else if(entry.type==="message"&&entry.message.role==="toolResult"&&entry.message.usage)addUsageToTotals(usageTotals,entry.message.usage);else if((entry.type==="branch_summary"||entry.type==="compaction")&&entry.usage)addUsageToTotals(usageTotals,entry.usage);else if(entry.type==="custom"&&entry.customType==="goal.state"){let goals=entry.data?.goals,current=Array.isArray(goals)?goals.at(-1):void 0;current&&typeof current.title=="string"&&(goalTitle=current.title)}else if(entry.type==="custom"&&entry.customType==="todo.state"){let todos=entry.data?.todos;Array.isArray(todos)&&(todoDone=todos.filter(item=>item?.status==="done").length,todoTotal=todos.length)}let contextUsage=this.facade.getContextUsage(),contextWindow=contextUsage?.contextWindow??state2.model?.contextWindow??0,contextPercentValue=contextUsage?.percent??0,contextPercent=contextUsage?.percent!==null?contextPercentValue.toFixed(1):"?",pwd=formatCwdForFooter(this.facade.getCwd(),process.env.HOME||process.env.USERPROFILE),branch=this.footerData.getGitBranch();branch&&(pwd=`${pwd} (${branch})`);let sessionName=this.facade.getSessionName();sessionName&&(pwd=`${pwd} \u2022 ${sessionName}`);let statsParts=[];usageTotals.input&&statsParts.push(`\u2191${formatTokens(usageTotals.input)}`),usageTotals.output&&statsParts.push(`\u2193${formatTokens(usageTotals.output)}`),usageTotals.cacheRead&&statsParts.push(`R${formatTokens(usageTotals.cacheRead)}`),usageTotals.cacheWrite&&statsParts.push(`W${formatTokens(usageTotals.cacheWrite)}`),(usageTotals.cacheRead>0||usageTotals.cacheWrite>0)&&latestCacheHitRate!==void 0&&statsParts.push(`CH${latestCacheHitRate.toFixed(1)}%`);let usingSubscription=state2.model?state2.model.provider==="kimi-coding"||this.facade.isUsingSubscription(state2.model.provider):!1;if(usageTotals.cost||usingSubscription){let costStr=`$${usageTotals.cost.toFixed(3)}${usingSubscription?" (sub)":""}`;statsParts.push(costStr)}let contextPercentStr,autoIndicator=this.autoCompactEnabled?" (auto)":"",contextPercentDisplay=contextPercent==="?"?`?/${formatTokens(contextWindow)}${autoIndicator}`:`${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;contextPercentValue>90?contextPercentStr=theme.fg("error",contextPercentDisplay):contextPercentValue>70?contextPercentStr=theme.fg("warning",contextPercentDisplay):contextPercentStr=contextPercentDisplay,statsParts.push(contextPercentStr),areExperimentalFeaturesEnabled()&&statsParts.push(`${theme.fg("dim","\u2022")} ${theme.bold(theme.fg("warning","xp"))}`);let statsLeft=statsParts.join(" "),modelName=state2.model?.id||"no-model",statsLeftWidth=visibleWidth(statsLeft);statsLeftWidth>width&&(statsLeft=truncateToWidth(statsLeft,width,"..."),statsLeftWidth=visibleWidth(statsLeft));let minPadding=2,rightSideWithoutProvider=modelName;if(state2.model?.reasoning){let thinkingLevel=state2.thinkingLevel||"off";rightSideWithoutProvider=thinkingLevel==="off"?`${modelName} \u2022 thinking off`:`${modelName} \u2022 ${thinkingLevel}`}let rightSide=rightSideWithoutProvider;this.footerData.getAvailableProviderCount()>1&&state2.model&&(rightSide=`(${state2.model.provider}) ${rightSideWithoutProvider}`,statsLeftWidth+minPadding+visibleWidth(rightSide)>width&&(rightSide=rightSideWithoutProvider));let rightSideWidth=visibleWidth(rightSide),totalNeeded=statsLeftWidth+minPadding+rightSideWidth,statsLine;if(totalNeeded<=width){let padding=" ".repeat(width-statsLeftWidth-rightSideWidth);statsLine=statsLeft+padding+rightSide}else{let availableForRight=width-statsLeftWidth-minPadding;if(availableForRight>0){let truncatedRight=truncateToWidth(rightSide,availableForRight,""),truncatedRightWidth=visibleWidth(truncatedRight),padding=" ".repeat(Math.max(0,width-statsLeftWidth-truncatedRightWidth));statsLine=statsLeft+padding+truncatedRight}else statsLine=statsLeft}let dimStatsLeft=theme.fg("dim",statsLeft),remainder=statsLine.slice(statsLeft.length),dimRemainder=theme.fg("dim",remainder),lines=[truncateToWidth(theme.fg("dim",pwd),width,theme.fg("dim","...")),dimStatsLeft+dimRemainder];if(goalTitle!==void 0){let goalParts=[`goal: ${goalTitle}`];todoTotal>0&&goalParts.push(`todo ${todoDone}/${todoTotal}`);let goalLine=theme.fg("dim",sanitizeStatusText(goalParts.join(" \u2022 ")));lines.push(truncateToWidth(goalLine,width,theme.fg("dim","...")))}return lines}};var SUBMENU_SELECT_LIST_LAYOUT={minPrimaryColumnWidth:12,maxPrimaryColumnWidth:32},SelectSubmenu=class extends Container{selectList;listChildIndex;allOptions;listLayout;searchInput;onSelectCb;onCancelCb;onSelectionChangeCb;constructor(title,description,options,currentValue,onSelect,onCancel,onSelectionChange,submenuOptions){super(),this.allOptions=options,this.listLayout=submenuOptions?.layout??SUBMENU_SELECT_LIST_LAYOUT,this.onSelectCb=onSelect,this.onCancelCb=onCancel,this.onSelectionChangeCb=onSelectionChange,this.addChild(new Text(theme.bold(theme.fg("accent",title)),0,0)),description&&(this.addChild(new Spacer(1)),this.addChild(new Text(theme.fg("muted",description),0,0))),submenuOptions?.searchable&&(this.addChild(new Spacer(1)),this.searchInput=new Input,this.searchInput.onSubmit=()=>{this.selectList.handleInput("\r")},this.addChild(this.searchInput)),this.addChild(new Spacer(1)),this.selectList=this.buildSelectList(options,currentValue),this.listChildIndex=this.children.length,this.addChild(this.selectList),this.addChild(new Spacer(1));let hint=submenuOptions?.searchable?" Type to filter \xB7 Enter to select \xB7 Esc to go back":" Enter to select \xB7 Esc to go back";this.addChild(new Text(theme.fg("dim",hint),0,0))}buildSelectList(options,preselect){let list=new SelectList(options,Math.min(options.length,10),getSelectListTheme(),this.listLayout),idx=options.findIndex(o=>o.value===preselect);if(idx!==-1&&list.setSelectedIndex(idx),list.onSelect=item=>this.onSelectCb(item.value),list.onCancel=this.onCancelCb,this.onSelectionChangeCb){let cb=this.onSelectionChangeCb;list.onSelectionChange=item=>cb(item.value)}return list}applyFilter(query){let filtered=query?fuzzyFilter(this.allOptions,query,item=>`${item.label} ${item.description??""}`):this.allOptions,newList=this.buildSelectList(filtered,"");this.children[this.listChildIndex]=newList,this.selectList=newList}handleInput(data){if(this.searchInput){let kb=getKeybindings();kb.matches(data,"tui.select.up")||kb.matches(data,"tui.select.down")||kb.matches(data,"tui.select.confirm")||kb.matches(data,"tui.select.cancel")?this.selectList.handleInput(data):(this.searchInput.handleInput(data),this.applyFilter(this.searchInput.getValue()))}else this.selectList.handleInput(data)}},SteppedSubmenu=class extends Container{steps;onComplete;onCancel;opts;activeComponent;context;constructor(steps,onComplete,onCancel,opts={}){super(),this.steps=steps,this.onComplete=onComplete,this.onCancel=onCancel,this.opts=opts,this.context={...opts.initialContext??{}},this.activeComponent=this.buildStep(opts.startAtStep??0)}buildStep(stepIndex){let step=this.steps[stepIndex],total=this.steps.length,stepLabel=total>1?`Step ${stepIndex+1}/${total} \xB7 `:"",title=typeof step.title=="function"?step.title(this.context):step.title,desc=typeof step.description=="function"?step.description(this.context):step.description,items=step.options(this.context),preselect=step.preselect?.(this.context)??"";return new SelectSubmenu(title,`${stepLabel}${desc}`,items,preselect,value=>{this.context[step.key]=value,stepIndex<total-1?this.activeComponent=this.buildStep(stepIndex+1):(this.onComplete({...this.context}),this.opts.loop?(this.context={},this.activeComponent=this.buildStep(0)):this.onCancel())},()=>{stepIndex>0?(delete this.context[step.key],this.activeComponent=this.buildStep(stepIndex-1)):this.onCancel()},void 0,step.searchable||step.layout?{searchable:step.searchable,layout:step.layout}:void 0)}render(width){return this.activeComponent.render(width)}handleInput(data){this.activeComponent.handleInput?.(data)}invalidate(){this.activeComponent.invalidate?.()}};var MODEL_PICKER_LAYOUT={minPrimaryColumnWidth:12,maxPrimaryColumnWidth:46},THINKING_DESCRIPTIONS={off:"No reasoning",minimal:"Very brief reasoning (~1k tokens)",low:"Light reasoning (~2k tokens)",medium:"Moderate reasoning (~8k tokens)",high:"Deep reasoning (~16k tokens)",xhigh:"Extra-high reasoning (~32k tokens)",max:"Maximum reasoning"},WarningSettingsSubmenu=class extends Container{settingsList;state;constructor(warnings,onChange,onCancel){super(),this.state={...warnings};let items=[{id:"anthropic-extra-usage",label:"Anthropic extra usage",description:"Warn when Anthropic subscription auth may use paid extra usage",currentValue:this.state.anthropicExtraUsage??!0?"true":"false",values:["true","false"]}];this.settingsList=new SettingsList(items,Math.min(items.length,10),getSettingsListTheme(),(id,newValue)=>{id==="anthropic-extra-usage"&&(this.state={...this.state,anthropicExtraUsage:newValue==="true"},onChange({...this.state}))},onCancel),this.addChild(this.settingsList)}handleInput(data){this.settingsList.handleInput(data)}},CLEAR_OVERRIDE_VALUE="__clear__";function modelSettingKey(model){return`${model.provider}/${model.id}`}function modelDisplayLabel(model){return`${model.id} [${model.provider}]`}function modelThinkingOverridesSummary(overrides){let count=Object.keys(overrides).length;return count===0?"none":`${count} configured`}function modelItemLabel(model){return`${model.id} ${theme.fg("muted",`[${model.provider}]`)}`}function themeItems(availableThemes){return availableThemes.map(name=>({value:name,label:name}))}var AUTOMATIC_THEME_VALUE="/";function singleModeThemeItems(availableThemes){return[{value:AUTOMATIC_THEME_VALUE,label:"Automatic",description:"Use separate themes for light and dark terminal appearance"},...themeItems(availableThemes)]}function preferredTheme(availableThemes,preferred,fallback){return preferred&&availableThemes.includes(preferred)?preferred:availableThemes.includes(fallback)?fallback:availableThemes[0]??fallback}function defaultAutomaticThemes(currentThemeSetting,availableThemes){let autoTheme=parseAutoThemeSetting(currentThemeSetting);if(autoTheme)return autoTheme;let currentFixedTheme=currentThemeSetting.includes("/")?void 0:currentThemeSetting,themeName=preferredTheme(availableThemes,currentFixedTheme,"dark");return{lightTheme:themeName,darkTheme:themeName}}var ThemeSubmenu=class extends Container{inputComponent;callbacks;availableThemes;terminalTheme;onDone;originalThemeSetting;mode;singleTheme;lightTheme;darkTheme;constructor(currentThemeSetting,terminalTheme,availableThemes,callbacks,onDone){super(),this.callbacks=callbacks,this.availableThemes=availableThemes,this.terminalTheme=terminalTheme,this.onDone=onDone,this.originalThemeSetting=currentThemeSetting;let autoTheme=parseAutoThemeSetting(currentThemeSetting),automaticThemes=defaultAutomaticThemes(currentThemeSetting,availableThemes),fixedTheme=autoTheme||currentThemeSetting.includes("/")?void 0:currentThemeSetting;this.mode=autoTheme?"automatic":"single",this.lightTheme=automaticThemes.lightTheme,this.darkTheme=automaticThemes.darkTheme,this.singleTheme=preferredTheme(availableThemes,fixedTheme??(autoTheme?this.getActiveAutomaticTheme():void 0),"dark"),this.mode==="automatic"?this.showAutomaticMenu():this.showSingleMenu()}handleInput(data){this.inputComponent?.handleInput?.(data)}setContent(renderComponent,inputComponent=renderComponent){this.clear(),this.addChild(renderComponent),this.inputComponent=inputComponent}showSingleMenu(){this.mode="single";let menu=new SelectSubmenu("Theme","Select a theme, or choose Automatic to follow terminal appearance.",singleModeThemeItems(this.availableThemes),this.singleTheme,value=>{if(value===AUTOMATIC_THEME_VALUE){this.mode="automatic",this.callbacks.onThemePreview?.(this.getThemeSetting()),this.showAutomaticMenu();return}this.singleTheme=value,this.apply(value)},()=>this.cancel(),value=>{this.callbacks.onThemePreview?.(value===AUTOMATIC_THEME_VALUE?this.getAutomaticThemeSetting():value)});this.setContent(menu)}showAutomaticMenu(){this.mode="automatic";let content=new Container;content.addChild(new Text(theme.bold(theme.fg("accent","Automatic Theme")),0,0)),content.addChild(new Spacer(1)),content.addChild(new Text(theme.fg("muted","Choose themes for terminal light and dark appearance."),0,0)),content.addChild(new Text(theme.fg("muted","Light/dark detection requires terminal support."),0,0)),content.addChild(new Spacer(1));let items=[{id:"light-theme",label:"Light theme",description:"Theme to use in automatic mode when the terminal is light",currentValue:this.lightTheme,submenu:(currentValue,done)=>this.createThemeSelect("Light Theme","Select the theme to use for light terminal appearance",currentValue,done,value=>{this.lightTheme=value,this.callbacks.onThemePreview?.(this.getThemeSetting()),done(value)})},{id:"dark-theme",label:"Dark theme",description:"Theme to use in automatic mode when the terminal is dark",currentValue:this.darkTheme,submenu:(currentValue,done)=>this.createThemeSelect("Dark Theme","Select the theme to use for dark terminal appearance",currentValue,done,value=>{this.darkTheme=value,this.callbacks.onThemePreview?.(this.getThemeSetting()),done(value)})},{id:"apply",label:"Apply",description:"Save and go back",currentValue:"save and go back",values:["save and go back"]},{id:"single-mode",label:"Change mode",description:"Switch to one theme for light and dark",currentValue:"switch to single theme",values:["switch to single theme"]}],settingsList=new SettingsList(items,Math.min(items.length,10),getSettingsListTheme(),id=>{switch(id){case"single-mode":this.mode="single",this.singleTheme=this.getActiveAutomaticTheme(),this.callbacks.onThemePreview?.(this.singleTheme),this.showSingleMenu();break;case"apply":this.apply(this.getAutomaticThemeSetting());break}},()=>this.cancel());content.addChild(settingsList),this.setContent(content,settingsList)}createThemeSelect(title,description,currentValue,done,onSelect){return new SelectSubmenu(title,description,themeItems(this.availableThemes),currentValue,onSelect,()=>{this.callbacks.onThemePreview?.(this.getThemeSetting()),done()},value=>this.callbacks.onThemePreview?.(value))}getThemeSetting(){return this.mode==="automatic"?this.getAutomaticThemeSetting():this.singleTheme}getActiveAutomaticTheme(){return this.terminalTheme==="light"?this.lightTheme:this.darkTheme}getAutomaticThemeSetting(){return`${this.lightTheme}/${this.darkTheme}`}apply(themeSetting){this.onDone(themeSetting)}cancel(){this.callbacks.onThemePreview?.(this.originalThemeSetting),this.onDone()}},SettingsSelectorComponent=class extends Container{settingsList;constructor(config,callbacks){super();let supportsImages=getCapabilities().images,followUpKey=keyDisplayText("app.message.followUp"),cycleThinkingKey=keyDisplayText("app.thinking.cycle"),currentWarnings={...config.warnings},currentModelThinkingLevels={...config.modelThinkingLevels},defaultModelByValue=new Map(config.availableDefaultModels.map(model=>[modelSettingKey(model),model])),currentDefaultModelKey=defaultModelByValue.has(config.defaultModel)?config.defaultModel:void 0,currentModelKey=config.currentModel?modelSettingKey(config.currentModel):void 0,items=[{id:"autocompact",label:"Auto-compact",description:"Automatically compact context when it gets too large",currentValue:config.autoCompact?"true":"false",values:["true","false"]},{id:"steering-mode",label:"Steering mode",description:"Enter while streaming queues steering messages. 'one-at-a-time': deliver one, wait for response. 'all': deliver all at once.",currentValue:config.steeringMode,values:["one-at-a-time","all"]},{id:"follow-up-mode",label:"Follow-up mode",description:`${followUpKey} queues follow-up messages until agent stops. 'one-at-a-time': deliver one, wait for response. 'all': deliver all at once.`,currentValue:config.followUpMode,values:["one-at-a-time","all"]},{id:"transport",label:"Transport",description:"Preferred transport for providers that support multiple transports",currentValue:config.transport,values:["sse","websocket","websocket-cached","auto"]},{id:"http-idle-timeout",label:"HTTP idle timeout",description:"Maximum idle gap while waiting for HTTP headers or body chunks. Disable for local models that pause longer than five minutes.",currentValue:formatHttpIdleTimeoutMs(config.httpIdleTimeoutMs),values:HTTP_IDLE_TIMEOUT_CHOICES.map(choice=>choice.label)},{id:"hide-thinking",label:"Hide thinking",description:"Hide thinking blocks in assistant responses",currentValue:config.hideThinkingBlock?"true":"false",values:["true","false"]},{id:"mermaid-rendering",label:"Mermaid diagrams",description:"Render Mermaid code blocks as Unicode diagrams",currentValue:config.mermaidRenderingMode,values:["off","final","streaming"]},{id:"cache-miss-notices",label:"Cache miss notices",description:"Show transcript notices for cache costs and provider recovery diagnostics",currentValue:config.showCacheMissNotices?"true":"false",values:["true","false"]},{id:"collapse-changelog",label:"Collapse changelog",description:"Show condensed changelog after updates",currentValue:config.collapseChangelog?"true":"false",values:["true","false"]},{id:"quiet-startup",label:"Quiet startup",description:"Disable verbose printing at startup",currentValue:config.quietStartup?"true":"false",values:["true","false"]},{id:"double-escape-action",label:"Double-escape action",description:"Action when pressing Escape twice with empty editor",currentValue:config.doubleEscapeAction,values:["tree","fork","none"]},{id:"tree-filter-mode",label:"Tree filter mode",description:"Default filter when opening /tree",currentValue:config.treeFilterMode,values:["default","no-tools","user-only","labeled-only","all"]},{id:"warnings",label:"Warnings",description:"Enable or disable individual warnings",currentValue:"configure",submenu:(_currentValue,done)=>new WarningSettingsSubmenu(currentWarnings,warnings=>{currentWarnings=warnings,callbacks.onWarningsChange(warnings)},()=>done())},{id:"model-thinking",label:"Default thinking level per model",description:`Override the default thinking level for specific models. ${cycleThinkingKey} cycles in-session.`,currentValue:modelThinkingOverridesSummary(currentModelThinkingLevels),submenu:(_currentValue,done)=>{let steps=[{key:"model",title:"Per-Model Thinking Level",description:"Select a model to configure",options:()=>{let items2=[...config.availableDefaultModels].sort((a,b2)=>{let aKey=modelSettingKey(a),bKey=modelSettingKey(b2);return aKey===currentModelKey?-1:bKey===currentModelKey?1:aKey===currentDefaultModelKey?-1:bKey===currentDefaultModelKey?1:a.provider.localeCompare(b2.provider)}).map(model=>{let key=modelSettingKey(model),override=currentModelThinkingLevels[key];return{value:key,label:modelItemLabel(model),description:override??void 0}});return items2.length===0&&items2.push({value:"__none__",label:"No models available",description:"Log in to a provider or configure an API key first"}),items2},preselect:()=>currentModelKey??currentDefaultModelKey,searchable:!0,layout:MODEL_PICKER_LAYOUT},{key:"level",title:ctx=>{let m2=defaultModelByValue.get(ctx.model);return`Thinking Level for ${m2?modelDisplayLabel(m2):ctx.model}`},description:"Select default thinking level for this model",options:ctx=>{let model=defaultModelByValue.get(ctx.model);if(!model)return[];let items2=(model.reasoning?getSupportedThinkingLevels(model):["off"]).map(level=>({value:level,label:level,description:THINKING_DESCRIPTIONS[level]}));return currentModelThinkingLevels[ctx.model]!==void 0&&items2.push({value:CLEAR_OVERRIDE_VALUE,label:"(clear override)",description:`Revert to global default (${config.thinkingLevel})`}),items2},preselect:ctx=>currentModelThinkingLevels[ctx.model]}],summary=()=>modelThinkingOverridesSummary(currentModelThinkingLevels);return new SteppedSubmenu(steps,selections=>{let model=defaultModelByValue.get(selections.model);model&&(selections.level===CLEAR_OVERRIDE_VALUE?(callbacks.onModelThinkingLevelRemove(model.provider,model.id),delete currentModelThinkingLevels[selections.model]):(callbacks.onModelThinkingLevelChange(model.provider,model.id,selections.level),currentModelThinkingLevels[selections.model]=selections.level))},()=>{done(summary())},{loop:!0})}},{id:"tui-mode",label:"TUI mode",description:"Interface layout; fullscreen mode is experimental",currentValue:config.tuiMode,values:["regular","fullscreen"]},{id:"fullscreen-exit-output",label:"Fullscreen exit output",description:"Print the transcript or only a session resume hint when exiting fullscreen mode",currentValue:config.fullscreenExitOutput,values:["transcript","resume-hint"]},{id:"fullscreen-scrollbar",label:"Fullscreen scrollbar",description:"Scrollbar behavior in fullscreen mode; has no effect in regular mode",currentValue:config.fullscreenScrollbar,values:["auto","always","hidden"]},{id:"fullscreen-copy-on-select",label:"Fullscreen copy on select",description:"Automatically copy selected text in fullscreen mode; disable to copy selections with Ctrl+X",currentValue:config.fullscreenCopyOnSelect?"true":"false",values:["true","false"]},{id:"theme",label:"Theme",description:"Color theme for the interface",currentValue:config.currentTheme,submenu:(currentValue,done)=>new ThemeSubmenu(currentValue,config.terminalTheme,config.availableThemes,callbacks,done)}];supportsImages&&(items.splice(1,0,{id:"show-images",label:"Show images",description:"Render images inline in terminal",currentValue:config.showImages?"true":"false",values:["true","false"]}),items.splice(2,0,{id:"image-width-cells",label:"Image width",description:"Preferred inline image width in terminal cells",currentValue:String(config.imageWidthCells),values:["60","80","120"]})),items.splice(supportsImages?3:1,0,{id:"auto-resize-images",label:"Auto-resize images",description:"Resize large images to 2000x2000 max for better model compatibility",currentValue:config.autoResizeImages?"true":"false",values:["true","false"]});let autoResizeIndex=items.findIndex(item=>item.id==="auto-resize-images");items.splice(autoResizeIndex+1,0,{id:"block-images",label:"Block images",description:"Prevent images from being sent to LLM providers",currentValue:config.blockImages?"true":"false",values:["true","false"]});let blockImagesIndex=items.findIndex(item=>item.id==="block-images");items.splice(blockImagesIndex+1,0,{id:"skill-commands",label:"Skill commands",description:"Register skills as /skill:name commands",currentValue:config.enableSkillCommands?"true":"false",values:["true","false"]});let skillCommandsIndex=items.findIndex(item=>item.id==="skill-commands");items.splice(skillCommandsIndex+1,0,{id:"show-hardware-cursor",label:"Show hardware cursor",description:"Show the terminal cursor while still positioning it for IME support",currentValue:config.showHardwareCursor?"true":"false",values:["true","false"]});let hardwareCursorIndex=items.findIndex(item=>item.id==="show-hardware-cursor");items.splice(hardwareCursorIndex+1,0,{id:"editor-padding",label:"Editor padding",description:"Horizontal padding for input editor (0-3)",currentValue:String(config.editorPaddingX),values:["0","1","2","3"]});let editorPaddingIndex=items.findIndex(item=>item.id==="editor-padding");items.splice(editorPaddingIndex+1,0,{id:"output-padding",label:"Output padding",description:"Horizontal padding for user messages, assistant messages, and thinking",currentValue:String(config.outputPad),values:["0","1"]});let outputPaddingIndex=items.findIndex(item=>item.id==="output-padding");items.splice(outputPaddingIndex+1,0,{id:"autocomplete-max-visible",label:"Autocomplete max items",description:"Max visible items in autocomplete dropdown (3-20)",currentValue:String(config.autocompleteMaxVisible),values:["3","5","7","10","15","20"]});let autocompleteIndex=items.findIndex(item=>item.id==="autocomplete-max-visible");items.splice(autocompleteIndex+1,0,{id:"clear-on-shrink",label:"Clear on shrink",description:"Clear empty rows when content shrinks (may cause flicker)",currentValue:config.clearOnShrink?"true":"false",values:["true","false"]});let clearOnShrinkIndex=items.findIndex(item=>item.id==="clear-on-shrink");items.splice(clearOnShrinkIndex+1,0,{id:"terminal-progress",label:"Terminal progress",description:"Show OSC 9;4 progress indicators in the terminal tab bar",currentValue:config.showTerminalProgress?"true":"false",values:["true","false"]}),this.addChild(new DynamicBorder),this.settingsList=new SettingsList(items,10,getSettingsListTheme(),(id,newValue)=>{switch(id){case"autocompact":callbacks.onAutoCompactChange(newValue==="true");break;case"show-images":callbacks.onShowImagesChange(newValue==="true");break;case"image-width-cells":callbacks.onImageWidthCellsChange(parseInt(newValue,10));break;case"auto-resize-images":callbacks.onAutoResizeImagesChange(newValue==="true");break;case"block-images":callbacks.onBlockImagesChange(newValue==="true");break;case"skill-commands":callbacks.onEnableSkillCommandsChange(newValue==="true");break;case"steering-mode":callbacks.onSteeringModeChange(newValue);break;case"follow-up-mode":callbacks.onFollowUpModeChange(newValue);break;case"transport":callbacks.onTransportChange(newValue);break;case"http-idle-timeout":{let choice=HTTP_IDLE_TIMEOUT_CHOICES.find(item=>item.label===newValue);choice&&callbacks.onHttpIdleTimeoutMsChange(choice.timeoutMs);break}case"hide-thinking":callbacks.onHideThinkingBlockChange(newValue==="true");break;case"mermaid-rendering":callbacks.onMermaidRenderingModeChange(newValue);break;case"cache-miss-notices":callbacks.onShowCacheMissNoticesChange(newValue==="true");break;case"collapse-changelog":callbacks.onCollapseChangelogChange(newValue==="true");break;case"quiet-startup":callbacks.onQuietStartupChange(newValue==="true");break;case"double-escape-action":callbacks.onDoubleEscapeActionChange(newValue);break;case"tree-filter-mode":callbacks.onTreeFilterModeChange(newValue);break;case"show-hardware-cursor":callbacks.onShowHardwareCursorChange(newValue==="true");break;case"editor-padding":callbacks.onEditorPaddingXChange(parseInt(newValue,10));break;case"output-padding":callbacks.onOutputPadChange(newValue==="0"?0:1);break;case"autocomplete-max-visible":callbacks.onAutocompleteMaxVisibleChange(parseInt(newValue,10));break;case"clear-on-shrink":callbacks.onClearOnShrinkChange(newValue==="true");break;case"terminal-progress":callbacks.onShowTerminalProgressChange(newValue==="true");break;case"tui-mode":callbacks.onTuiModeChange(newValue);break;case"fullscreen-exit-output":callbacks.onFullscreenExitOutputChange(newValue);break;case"fullscreen-scrollbar":callbacks.onFullscreenScrollbarChange(newValue);break;case"fullscreen-copy-on-select":callbacks.onFullscreenCopyOnSelectChange(newValue==="true");break;case"theme":callbacks.onThemeChange(newValue);break}},callbacks.onCancel,{enableSearch:!0}),this.addChild(this.settingsList),this.addChild(new DynamicBorder)}getSettingsList(){return this.settingsList}};var SkillInvocationMessageComponent=class extends Box{expanded=!1;skillBlock;markdownTheme;constructor(skillBlock,markdownTheme=getMarkdownTheme()){super(1,1,t=>theme.bg("customMessageBg",t)),this.skillBlock=skillBlock,this.markdownTheme=markdownTheme,this.updateDisplay()}setExpanded(expanded){this.expanded=expanded,this.updateDisplay()}invalidate(){super.invalidate(),this.updateDisplay()}updateDisplay(){if(this.clear(),this.expanded){let label=theme.fg("customMessageLabel","\x1B[1m[skill]\x1B[22m");this.addChild(new Text(label,0,0));let header=`**${this.skillBlock.name}**
|
|
1327
|
+
`),this.box.addChild(new Markdown(text,0,0,this.markdownTheme,{color:text2=>theme.fg("customMessageText",text2)}))}};import{isAbsolute as isAbsolute12,relative as relative10,resolve as resolve20,sep as sep13}from"node:path";function areExperimentalFeaturesEnabled(){let configuredValue=process.env.AGENT_FORGE_EXPERIMENTAL;return configuredValue===void 0?process.env.PI_EXPERIMENTAL==="1":configuredValue==="1"}function sanitizeStatusText(text){return text.replace(/[\r\n\t]/g," ").replace(/ +/g," ").trim()}function formatTokens(count){return count<1e3?count.toString():count<1e4?`${(count/1e3).toFixed(1)}k`:count<1e6?`${Math.round(count/1e3)}k`:count<1e7?`${(count/1e6).toFixed(1)}M`:`${Math.round(count/1e6)}M`}function formatCwdForFooter(cwd,home){if(!home)return cwd;let resolvedCwd=resolve20(cwd),resolvedHome=resolve20(home),relativeToHome=relative10(resolvedHome,resolvedCwd);return relativeToHome===""||relativeToHome!==".."&&!relativeToHome.startsWith(`..${sep13}`)&&!isAbsolute12(relativeToHome)?relativeToHome===""?"~":`~${sep13}${relativeToHome}`:cwd}function summarizeWorkflowState(state2){let workflows=state2?.workflows,records=Array.isArray(workflows)?workflows:[],record=[...records].reverse().find(item=>item?.status==="draft"||item?.status==="running")??records.at(-1);if(record===void 0||typeof record.title!="string")return;let stages=Array.isArray(record.runtime)?record.runtime:[],done=stages.filter(stage=>stage?.status==="completed"||stage?.status==="skipped").length,activeCount=stages.filter(stage=>stage?.status==="active").length,parts=[`wf: ${record.title} ${done}/${stages.length}`];return activeCount>=2&&parts.push(`\u25B6${activeCount}`),stages.some(stage=>stage?.status==="awaiting_review")&&parts.push("\u23F8"),Array.isArray(record.diagnostics)&&record.diagnostics.length>0&&parts.push("\u26A0"),record.status==="failed"&&parts.push("\u2717"),parts.join(" ")}var FooterComponent=class{autoCompactEnabled=!0;session;footerData;constructor(session,footerData){this.session=session,this.footerData=footerData}setSession(session){this.session=session}get facade(){return createCodingAgentFacade(this.session)}setAutoCompactEnabled(enabled){this.autoCompactEnabled=enabled}invalidate(){}dispose(){}render(width){let state2=this.facade.getState(),usageTotals=createUsageTotals(),latestCacheHitRate,goalTitle,todoDone=0,todoTotal=0,workflowState;for(let entry of this.facade.getEntries())if(entry.type==="message"&&entry.message.role==="assistant"){addUsageToTotals(usageTotals,entry.message.usage);let latestPromptTokens=entry.message.usage.input+entry.message.usage.cacheRead+entry.message.usage.cacheWrite;latestCacheHitRate=latestPromptTokens>0?entry.message.usage.cacheRead/latestPromptTokens*100:void 0}else if(entry.type==="message"&&entry.message.role==="toolResult"&&entry.message.usage)addUsageToTotals(usageTotals,entry.message.usage);else if((entry.type==="branch_summary"||entry.type==="compaction")&&entry.usage)addUsageToTotals(usageTotals,entry.usage);else if(entry.type==="custom"&&entry.customType==="goal.state"){let goals=entry.data?.goals,current=Array.isArray(goals)?goals.at(-1):void 0;current&&typeof current.title=="string"&&(goalTitle=current.title)}else if(entry.type==="custom"&&entry.customType==="todo.state"){let todos=entry.data?.todos;Array.isArray(todos)&&(todoDone=todos.filter(item=>item?.status==="done").length,todoTotal=todos.length)}else entry.type==="custom"&&entry.customType==="workflow.state"&&(workflowState=entry.data);let contextUsage=this.facade.getContextUsage(),contextWindow=contextUsage?.contextWindow??state2.model?.contextWindow??0,contextPercentValue=contextUsage?.percent??0,contextPercent=contextUsage?.percent!==null?contextPercentValue.toFixed(1):"?",pwd=formatCwdForFooter(this.facade.getCwd(),process.env.HOME||process.env.USERPROFILE),branch=this.footerData.getGitBranch();branch&&(pwd=`${pwd} (${branch})`);let sessionName=this.facade.getSessionName();sessionName&&(pwd=`${pwd} \u2022 ${sessionName}`);let statsParts=[];usageTotals.input&&statsParts.push(`\u2191${formatTokens(usageTotals.input)}`),usageTotals.output&&statsParts.push(`\u2193${formatTokens(usageTotals.output)}`),usageTotals.cacheRead&&statsParts.push(`R${formatTokens(usageTotals.cacheRead)}`),usageTotals.cacheWrite&&statsParts.push(`W${formatTokens(usageTotals.cacheWrite)}`),(usageTotals.cacheRead>0||usageTotals.cacheWrite>0)&&latestCacheHitRate!==void 0&&statsParts.push(`CH${latestCacheHitRate.toFixed(1)}%`);let usingSubscription=state2.model?state2.model.provider==="kimi-coding"||this.facade.isUsingSubscription(state2.model.provider):!1;if(usageTotals.cost||usingSubscription){let costStr=`$${usageTotals.cost.toFixed(3)}${usingSubscription?" (sub)":""}`;statsParts.push(costStr)}let contextPercentStr,autoIndicator=this.autoCompactEnabled?" (auto)":"",contextPercentDisplay=contextPercent==="?"?`?/${formatTokens(contextWindow)}${autoIndicator}`:`${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;contextPercentValue>90?contextPercentStr=theme.fg("error",contextPercentDisplay):contextPercentValue>70?contextPercentStr=theme.fg("warning",contextPercentDisplay):contextPercentStr=contextPercentDisplay,statsParts.push(contextPercentStr),areExperimentalFeaturesEnabled()&&statsParts.push(`${theme.fg("dim","\u2022")} ${theme.bold(theme.fg("warning","xp"))}`);let statsLeft=statsParts.join(" "),modelName=state2.model?.id||"no-model",statsLeftWidth=visibleWidth(statsLeft);statsLeftWidth>width&&(statsLeft=truncateToWidth(statsLeft,width,"..."),statsLeftWidth=visibleWidth(statsLeft));let minPadding=2,rightSideWithoutProvider=modelName;if(state2.model?.reasoning){let thinkingLevel=state2.thinkingLevel||"off";rightSideWithoutProvider=thinkingLevel==="off"?`${modelName} \u2022 thinking off`:`${modelName} \u2022 ${thinkingLevel}`}let rightSide=rightSideWithoutProvider;this.footerData.getAvailableProviderCount()>1&&state2.model&&(rightSide=`(${state2.model.provider}) ${rightSideWithoutProvider}`,statsLeftWidth+minPadding+visibleWidth(rightSide)>width&&(rightSide=rightSideWithoutProvider));let rightSideWidth=visibleWidth(rightSide),totalNeeded=statsLeftWidth+minPadding+rightSideWidth,statsLine;if(totalNeeded<=width){let padding=" ".repeat(width-statsLeftWidth-rightSideWidth);statsLine=statsLeft+padding+rightSide}else{let availableForRight=width-statsLeftWidth-minPadding;if(availableForRight>0){let truncatedRight=truncateToWidth(rightSide,availableForRight,""),truncatedRightWidth=visibleWidth(truncatedRight),padding=" ".repeat(Math.max(0,width-statsLeftWidth-truncatedRightWidth));statsLine=statsLeft+padding+truncatedRight}else statsLine=statsLeft}let dimStatsLeft=theme.fg("dim",statsLeft),remainder=statsLine.slice(statsLeft.length),dimRemainder=theme.fg("dim",remainder),lines=[truncateToWidth(theme.fg("dim",pwd),width,theme.fg("dim","...")),dimStatsLeft+dimRemainder];if(goalTitle!==void 0){let goalParts=[`goal: ${goalTitle}`];todoTotal>0&&goalParts.push(`todo ${todoDone}/${todoTotal}`);let goalLine=theme.fg("dim",sanitizeStatusText(goalParts.join(" \u2022 ")));lines.push(truncateToWidth(goalLine,width,theme.fg("dim","...")))}let workflowSummary=summarizeWorkflowState(workflowState);if(workflowSummary!==void 0){let workflowLine=theme.fg("dim",sanitizeStatusText(workflowSummary));lines.push(truncateToWidth(workflowLine,width,theme.fg("dim","...")))}return lines}};var SUBMENU_SELECT_LIST_LAYOUT={minPrimaryColumnWidth:12,maxPrimaryColumnWidth:32},SelectSubmenu=class extends Container{selectList;listChildIndex;allOptions;listLayout;searchInput;onSelectCb;onCancelCb;onSelectionChangeCb;constructor(title,description,options,currentValue,onSelect,onCancel,onSelectionChange,submenuOptions){super(),this.allOptions=options,this.listLayout=submenuOptions?.layout??SUBMENU_SELECT_LIST_LAYOUT,this.onSelectCb=onSelect,this.onCancelCb=onCancel,this.onSelectionChangeCb=onSelectionChange,this.addChild(new Text(theme.bold(theme.fg("accent",title)),0,0)),description&&(this.addChild(new Spacer(1)),this.addChild(new Text(theme.fg("muted",description),0,0))),submenuOptions?.searchable&&(this.addChild(new Spacer(1)),this.searchInput=new Input,this.searchInput.onSubmit=()=>{this.selectList.handleInput("\r")},this.addChild(this.searchInput)),this.addChild(new Spacer(1)),this.selectList=this.buildSelectList(options,currentValue),this.listChildIndex=this.children.length,this.addChild(this.selectList),this.addChild(new Spacer(1));let hint=submenuOptions?.searchable?" Type to filter \xB7 Enter to select \xB7 Esc to go back":" Enter to select \xB7 Esc to go back";this.addChild(new Text(theme.fg("dim",hint),0,0))}buildSelectList(options,preselect){let list=new SelectList(options,Math.min(options.length,10),getSelectListTheme(),this.listLayout),idx=options.findIndex(o=>o.value===preselect);if(idx!==-1&&list.setSelectedIndex(idx),list.onSelect=item=>this.onSelectCb(item.value),list.onCancel=this.onCancelCb,this.onSelectionChangeCb){let cb=this.onSelectionChangeCb;list.onSelectionChange=item=>cb(item.value)}return list}applyFilter(query){let filtered=query?fuzzyFilter(this.allOptions,query,item=>`${item.label} ${item.description??""}`):this.allOptions,newList=this.buildSelectList(filtered,"");this.children[this.listChildIndex]=newList,this.selectList=newList}handleInput(data){if(this.searchInput){let kb=getKeybindings();kb.matches(data,"tui.select.up")||kb.matches(data,"tui.select.down")||kb.matches(data,"tui.select.confirm")||kb.matches(data,"tui.select.cancel")?this.selectList.handleInput(data):(this.searchInput.handleInput(data),this.applyFilter(this.searchInput.getValue()))}else this.selectList.handleInput(data)}},SteppedSubmenu=class extends Container{steps;onComplete;onCancel;opts;activeComponent;context;constructor(steps,onComplete,onCancel,opts={}){super(),this.steps=steps,this.onComplete=onComplete,this.onCancel=onCancel,this.opts=opts,this.context={...opts.initialContext??{}},this.activeComponent=this.buildStep(opts.startAtStep??0)}buildStep(stepIndex){let step=this.steps[stepIndex],total=this.steps.length,stepLabel=total>1?`Step ${stepIndex+1}/${total} \xB7 `:"",title=typeof step.title=="function"?step.title(this.context):step.title,desc=typeof step.description=="function"?step.description(this.context):step.description,items=step.options(this.context),preselect=step.preselect?.(this.context)??"";return new SelectSubmenu(title,`${stepLabel}${desc}`,items,preselect,value=>{this.context[step.key]=value,stepIndex<total-1?this.activeComponent=this.buildStep(stepIndex+1):(this.onComplete({...this.context}),this.opts.loop?(this.context={},this.activeComponent=this.buildStep(0)):this.onCancel())},()=>{stepIndex>0?(delete this.context[step.key],this.activeComponent=this.buildStep(stepIndex-1)):this.onCancel()},void 0,step.searchable||step.layout?{searchable:step.searchable,layout:step.layout}:void 0)}render(width){return this.activeComponent.render(width)}handleInput(data){this.activeComponent.handleInput?.(data)}invalidate(){this.activeComponent.invalidate?.()}};var MODEL_PICKER_LAYOUT={minPrimaryColumnWidth:12,maxPrimaryColumnWidth:46},THINKING_DESCRIPTIONS={off:"No reasoning",minimal:"Very brief reasoning (~1k tokens)",low:"Light reasoning (~2k tokens)",medium:"Moderate reasoning (~8k tokens)",high:"Deep reasoning (~16k tokens)",xhigh:"Extra-high reasoning (~32k tokens)",max:"Maximum reasoning"},WarningSettingsSubmenu=class extends Container{settingsList;state;constructor(warnings,onChange,onCancel){super(),this.state={...warnings};let items=[{id:"anthropic-extra-usage",label:"Anthropic extra usage",description:"Warn when Anthropic subscription auth may use paid extra usage",currentValue:this.state.anthropicExtraUsage??!0?"true":"false",values:["true","false"]}];this.settingsList=new SettingsList(items,Math.min(items.length,10),getSettingsListTheme(),(id,newValue)=>{id==="anthropic-extra-usage"&&(this.state={...this.state,anthropicExtraUsage:newValue==="true"},onChange({...this.state}))},onCancel),this.addChild(this.settingsList)}handleInput(data){this.settingsList.handleInput(data)}},CLEAR_OVERRIDE_VALUE="__clear__";function modelSettingKey(model){return`${model.provider}/${model.id}`}function modelDisplayLabel(model){return`${model.id} [${model.provider}]`}function modelThinkingOverridesSummary(overrides){let count=Object.keys(overrides).length;return count===0?"none":`${count} configured`}function modelItemLabel(model){return`${model.id} ${theme.fg("muted",`[${model.provider}]`)}`}function themeItems(availableThemes){return availableThemes.map(name=>({value:name,label:name}))}var AUTOMATIC_THEME_VALUE="/";function singleModeThemeItems(availableThemes){return[{value:AUTOMATIC_THEME_VALUE,label:"Automatic",description:"Use separate themes for light and dark terminal appearance"},...themeItems(availableThemes)]}function preferredTheme(availableThemes,preferred,fallback){return preferred&&availableThemes.includes(preferred)?preferred:availableThemes.includes(fallback)?fallback:availableThemes[0]??fallback}function defaultAutomaticThemes(currentThemeSetting,availableThemes){let autoTheme=parseAutoThemeSetting(currentThemeSetting);if(autoTheme)return autoTheme;let currentFixedTheme=currentThemeSetting.includes("/")?void 0:currentThemeSetting,themeName=preferredTheme(availableThemes,currentFixedTheme,"dark");return{lightTheme:themeName,darkTheme:themeName}}var ThemeSubmenu=class extends Container{inputComponent;callbacks;availableThemes;terminalTheme;onDone;originalThemeSetting;mode;singleTheme;lightTheme;darkTheme;constructor(currentThemeSetting,terminalTheme,availableThemes,callbacks,onDone){super(),this.callbacks=callbacks,this.availableThemes=availableThemes,this.terminalTheme=terminalTheme,this.onDone=onDone,this.originalThemeSetting=currentThemeSetting;let autoTheme=parseAutoThemeSetting(currentThemeSetting),automaticThemes=defaultAutomaticThemes(currentThemeSetting,availableThemes),fixedTheme=autoTheme||currentThemeSetting.includes("/")?void 0:currentThemeSetting;this.mode=autoTheme?"automatic":"single",this.lightTheme=automaticThemes.lightTheme,this.darkTheme=automaticThemes.darkTheme,this.singleTheme=preferredTheme(availableThemes,fixedTheme??(autoTheme?this.getActiveAutomaticTheme():void 0),"dark"),this.mode==="automatic"?this.showAutomaticMenu():this.showSingleMenu()}handleInput(data){this.inputComponent?.handleInput?.(data)}setContent(renderComponent,inputComponent=renderComponent){this.clear(),this.addChild(renderComponent),this.inputComponent=inputComponent}showSingleMenu(){this.mode="single";let menu=new SelectSubmenu("Theme","Select a theme, or choose Automatic to follow terminal appearance.",singleModeThemeItems(this.availableThemes),this.singleTheme,value=>{if(value===AUTOMATIC_THEME_VALUE){this.mode="automatic",this.callbacks.onThemePreview?.(this.getThemeSetting()),this.showAutomaticMenu();return}this.singleTheme=value,this.apply(value)},()=>this.cancel(),value=>{this.callbacks.onThemePreview?.(value===AUTOMATIC_THEME_VALUE?this.getAutomaticThemeSetting():value)});this.setContent(menu)}showAutomaticMenu(){this.mode="automatic";let content=new Container;content.addChild(new Text(theme.bold(theme.fg("accent","Automatic Theme")),0,0)),content.addChild(new Spacer(1)),content.addChild(new Text(theme.fg("muted","Choose themes for terminal light and dark appearance."),0,0)),content.addChild(new Text(theme.fg("muted","Light/dark detection requires terminal support."),0,0)),content.addChild(new Spacer(1));let items=[{id:"light-theme",label:"Light theme",description:"Theme to use in automatic mode when the terminal is light",currentValue:this.lightTheme,submenu:(currentValue,done)=>this.createThemeSelect("Light Theme","Select the theme to use for light terminal appearance",currentValue,done,value=>{this.lightTheme=value,this.callbacks.onThemePreview?.(this.getThemeSetting()),done(value)})},{id:"dark-theme",label:"Dark theme",description:"Theme to use in automatic mode when the terminal is dark",currentValue:this.darkTheme,submenu:(currentValue,done)=>this.createThemeSelect("Dark Theme","Select the theme to use for dark terminal appearance",currentValue,done,value=>{this.darkTheme=value,this.callbacks.onThemePreview?.(this.getThemeSetting()),done(value)})},{id:"apply",label:"Apply",description:"Save and go back",currentValue:"save and go back",values:["save and go back"]},{id:"single-mode",label:"Change mode",description:"Switch to one theme for light and dark",currentValue:"switch to single theme",values:["switch to single theme"]}],settingsList=new SettingsList(items,Math.min(items.length,10),getSettingsListTheme(),id=>{switch(id){case"single-mode":this.mode="single",this.singleTheme=this.getActiveAutomaticTheme(),this.callbacks.onThemePreview?.(this.singleTheme),this.showSingleMenu();break;case"apply":this.apply(this.getAutomaticThemeSetting());break}},()=>this.cancel());content.addChild(settingsList),this.setContent(content,settingsList)}createThemeSelect(title,description,currentValue,done,onSelect){return new SelectSubmenu(title,description,themeItems(this.availableThemes),currentValue,onSelect,()=>{this.callbacks.onThemePreview?.(this.getThemeSetting()),done()},value=>this.callbacks.onThemePreview?.(value))}getThemeSetting(){return this.mode==="automatic"?this.getAutomaticThemeSetting():this.singleTheme}getActiveAutomaticTheme(){return this.terminalTheme==="light"?this.lightTheme:this.darkTheme}getAutomaticThemeSetting(){return`${this.lightTheme}/${this.darkTheme}`}apply(themeSetting){this.onDone(themeSetting)}cancel(){this.callbacks.onThemePreview?.(this.originalThemeSetting),this.onDone()}},SettingsSelectorComponent=class extends Container{settingsList;constructor(config,callbacks){super();let supportsImages=getCapabilities().images,followUpKey=keyDisplayText("app.message.followUp"),cycleThinkingKey=keyDisplayText("app.thinking.cycle"),currentWarnings={...config.warnings},currentModelThinkingLevels={...config.modelThinkingLevels},defaultModelByValue=new Map(config.availableDefaultModels.map(model=>[modelSettingKey(model),model])),currentDefaultModelKey=defaultModelByValue.has(config.defaultModel)?config.defaultModel:void 0,currentModelKey=config.currentModel?modelSettingKey(config.currentModel):void 0,items=[{id:"autocompact",label:"Auto-compact",description:"Automatically compact context when it gets too large",currentValue:config.autoCompact?"true":"false",values:["true","false"]},{id:"steering-mode",label:"Steering mode",description:"Enter while streaming queues steering messages. 'one-at-a-time': deliver one, wait for response. 'all': deliver all at once.",currentValue:config.steeringMode,values:["one-at-a-time","all"]},{id:"follow-up-mode",label:"Follow-up mode",description:`${followUpKey} queues follow-up messages until agent stops. 'one-at-a-time': deliver one, wait for response. 'all': deliver all at once.`,currentValue:config.followUpMode,values:["one-at-a-time","all"]},{id:"transport",label:"Transport",description:"Preferred transport for providers that support multiple transports",currentValue:config.transport,values:["sse","websocket","websocket-cached","auto"]},{id:"http-idle-timeout",label:"HTTP idle timeout",description:"Maximum idle gap while waiting for HTTP headers or body chunks. Disable for local models that pause longer than five minutes.",currentValue:formatHttpIdleTimeoutMs(config.httpIdleTimeoutMs),values:HTTP_IDLE_TIMEOUT_CHOICES.map(choice=>choice.label)},{id:"hide-thinking",label:"Hide thinking",description:"Hide thinking blocks in assistant responses",currentValue:config.hideThinkingBlock?"true":"false",values:["true","false"]},{id:"mermaid-rendering",label:"Mermaid diagrams",description:"Render Mermaid code blocks as Unicode diagrams",currentValue:config.mermaidRenderingMode,values:["off","final","streaming"]},{id:"cache-miss-notices",label:"Cache miss notices",description:"Show transcript notices for cache costs and provider recovery diagnostics",currentValue:config.showCacheMissNotices?"true":"false",values:["true","false"]},{id:"collapse-changelog",label:"Collapse changelog",description:"Show condensed changelog after updates",currentValue:config.collapseChangelog?"true":"false",values:["true","false"]},{id:"quiet-startup",label:"Quiet startup",description:"Disable verbose printing at startup",currentValue:config.quietStartup?"true":"false",values:["true","false"]},{id:"double-escape-action",label:"Double-escape action",description:"Action when pressing Escape twice with empty editor",currentValue:config.doubleEscapeAction,values:["tree","fork","none"]},{id:"tree-filter-mode",label:"Tree filter mode",description:"Default filter when opening /tree",currentValue:config.treeFilterMode,values:["default","no-tools","user-only","labeled-only","all"]},{id:"warnings",label:"Warnings",description:"Enable or disable individual warnings",currentValue:"configure",submenu:(_currentValue,done)=>new WarningSettingsSubmenu(currentWarnings,warnings=>{currentWarnings=warnings,callbacks.onWarningsChange(warnings)},()=>done())},{id:"model-thinking",label:"Default thinking level per model",description:`Override the default thinking level for specific models. ${cycleThinkingKey} cycles in-session.`,currentValue:modelThinkingOverridesSummary(currentModelThinkingLevels),submenu:(_currentValue,done)=>{let steps=[{key:"model",title:"Per-Model Thinking Level",description:"Select a model to configure",options:()=>{let items2=[...config.availableDefaultModels].sort((a,b2)=>{let aKey=modelSettingKey(a),bKey=modelSettingKey(b2);return aKey===currentModelKey?-1:bKey===currentModelKey?1:aKey===currentDefaultModelKey?-1:bKey===currentDefaultModelKey?1:a.provider.localeCompare(b2.provider)}).map(model=>{let key=modelSettingKey(model),override=currentModelThinkingLevels[key];return{value:key,label:modelItemLabel(model),description:override??void 0}});return items2.length===0&&items2.push({value:"__none__",label:"No models available",description:"Log in to a provider or configure an API key first"}),items2},preselect:()=>currentModelKey??currentDefaultModelKey,searchable:!0,layout:MODEL_PICKER_LAYOUT},{key:"level",title:ctx=>{let m2=defaultModelByValue.get(ctx.model);return`Thinking Level for ${m2?modelDisplayLabel(m2):ctx.model}`},description:"Select default thinking level for this model",options:ctx=>{let model=defaultModelByValue.get(ctx.model);if(!model)return[];let items2=(model.reasoning?getSupportedThinkingLevels(model):["off"]).map(level=>({value:level,label:level,description:THINKING_DESCRIPTIONS[level]}));return currentModelThinkingLevels[ctx.model]!==void 0&&items2.push({value:CLEAR_OVERRIDE_VALUE,label:"(clear override)",description:`Revert to global default (${config.thinkingLevel})`}),items2},preselect:ctx=>currentModelThinkingLevels[ctx.model]}],summary=()=>modelThinkingOverridesSummary(currentModelThinkingLevels);return new SteppedSubmenu(steps,selections=>{let model=defaultModelByValue.get(selections.model);model&&(selections.level===CLEAR_OVERRIDE_VALUE?(callbacks.onModelThinkingLevelRemove(model.provider,model.id),delete currentModelThinkingLevels[selections.model]):(callbacks.onModelThinkingLevelChange(model.provider,model.id,selections.level),currentModelThinkingLevels[selections.model]=selections.level))},()=>{done(summary())},{loop:!0})}},{id:"tui-mode",label:"TUI mode",description:"Interface layout; fullscreen mode is experimental",currentValue:config.tuiMode,values:["regular","fullscreen"]},{id:"fullscreen-exit-output",label:"Fullscreen exit output",description:"Print the transcript or only a session resume hint when exiting fullscreen mode",currentValue:config.fullscreenExitOutput,values:["transcript","resume-hint"]},{id:"fullscreen-scrollbar",label:"Fullscreen scrollbar",description:"Scrollbar behavior in fullscreen mode; has no effect in regular mode",currentValue:config.fullscreenScrollbar,values:["auto","always","hidden"]},{id:"fullscreen-copy-on-select",label:"Fullscreen copy on select",description:"Automatically copy selected text in fullscreen mode; disable to copy selections with Ctrl+X",currentValue:config.fullscreenCopyOnSelect?"true":"false",values:["true","false"]},{id:"theme",label:"Theme",description:"Color theme for the interface",currentValue:config.currentTheme,submenu:(currentValue,done)=>new ThemeSubmenu(currentValue,config.terminalTheme,config.availableThemes,callbacks,done)}];supportsImages&&(items.splice(1,0,{id:"show-images",label:"Show images",description:"Render images inline in terminal",currentValue:config.showImages?"true":"false",values:["true","false"]}),items.splice(2,0,{id:"image-width-cells",label:"Image width",description:"Preferred inline image width in terminal cells",currentValue:String(config.imageWidthCells),values:["60","80","120"]})),items.splice(supportsImages?3:1,0,{id:"auto-resize-images",label:"Auto-resize images",description:"Resize large images to 2000x2000 max for better model compatibility",currentValue:config.autoResizeImages?"true":"false",values:["true","false"]});let autoResizeIndex=items.findIndex(item=>item.id==="auto-resize-images");items.splice(autoResizeIndex+1,0,{id:"block-images",label:"Block images",description:"Prevent images from being sent to LLM providers",currentValue:config.blockImages?"true":"false",values:["true","false"]});let blockImagesIndex=items.findIndex(item=>item.id==="block-images");items.splice(blockImagesIndex+1,0,{id:"skill-commands",label:"Skill commands",description:"Register skills as /skill:name commands",currentValue:config.enableSkillCommands?"true":"false",values:["true","false"]});let skillCommandsIndex=items.findIndex(item=>item.id==="skill-commands");items.splice(skillCommandsIndex+1,0,{id:"show-hardware-cursor",label:"Show hardware cursor",description:"Show the terminal cursor while still positioning it for IME support",currentValue:config.showHardwareCursor?"true":"false",values:["true","false"]});let hardwareCursorIndex=items.findIndex(item=>item.id==="show-hardware-cursor");items.splice(hardwareCursorIndex+1,0,{id:"editor-padding",label:"Editor padding",description:"Horizontal padding for input editor (0-3)",currentValue:String(config.editorPaddingX),values:["0","1","2","3"]});let editorPaddingIndex=items.findIndex(item=>item.id==="editor-padding");items.splice(editorPaddingIndex+1,0,{id:"output-padding",label:"Output padding",description:"Horizontal padding for user messages, assistant messages, and thinking",currentValue:String(config.outputPad),values:["0","1"]});let outputPaddingIndex=items.findIndex(item=>item.id==="output-padding");items.splice(outputPaddingIndex+1,0,{id:"autocomplete-max-visible",label:"Autocomplete max items",description:"Max visible items in autocomplete dropdown (3-20)",currentValue:String(config.autocompleteMaxVisible),values:["3","5","7","10","15","20"]});let autocompleteIndex=items.findIndex(item=>item.id==="autocomplete-max-visible");items.splice(autocompleteIndex+1,0,{id:"clear-on-shrink",label:"Clear on shrink",description:"Clear empty rows when content shrinks (may cause flicker)",currentValue:config.clearOnShrink?"true":"false",values:["true","false"]});let clearOnShrinkIndex=items.findIndex(item=>item.id==="clear-on-shrink");items.splice(clearOnShrinkIndex+1,0,{id:"terminal-progress",label:"Terminal progress",description:"Show OSC 9;4 progress indicators in the terminal tab bar",currentValue:config.showTerminalProgress?"true":"false",values:["true","false"]}),this.addChild(new DynamicBorder),this.settingsList=new SettingsList(items,10,getSettingsListTheme(),(id,newValue)=>{switch(id){case"autocompact":callbacks.onAutoCompactChange(newValue==="true");break;case"show-images":callbacks.onShowImagesChange(newValue==="true");break;case"image-width-cells":callbacks.onImageWidthCellsChange(parseInt(newValue,10));break;case"auto-resize-images":callbacks.onAutoResizeImagesChange(newValue==="true");break;case"block-images":callbacks.onBlockImagesChange(newValue==="true");break;case"skill-commands":callbacks.onEnableSkillCommandsChange(newValue==="true");break;case"steering-mode":callbacks.onSteeringModeChange(newValue);break;case"follow-up-mode":callbacks.onFollowUpModeChange(newValue);break;case"transport":callbacks.onTransportChange(newValue);break;case"http-idle-timeout":{let choice=HTTP_IDLE_TIMEOUT_CHOICES.find(item=>item.label===newValue);choice&&callbacks.onHttpIdleTimeoutMsChange(choice.timeoutMs);break}case"hide-thinking":callbacks.onHideThinkingBlockChange(newValue==="true");break;case"mermaid-rendering":callbacks.onMermaidRenderingModeChange(newValue);break;case"cache-miss-notices":callbacks.onShowCacheMissNoticesChange(newValue==="true");break;case"collapse-changelog":callbacks.onCollapseChangelogChange(newValue==="true");break;case"quiet-startup":callbacks.onQuietStartupChange(newValue==="true");break;case"double-escape-action":callbacks.onDoubleEscapeActionChange(newValue);break;case"tree-filter-mode":callbacks.onTreeFilterModeChange(newValue);break;case"show-hardware-cursor":callbacks.onShowHardwareCursorChange(newValue==="true");break;case"editor-padding":callbacks.onEditorPaddingXChange(parseInt(newValue,10));break;case"output-padding":callbacks.onOutputPadChange(newValue==="0"?0:1);break;case"autocomplete-max-visible":callbacks.onAutocompleteMaxVisibleChange(parseInt(newValue,10));break;case"clear-on-shrink":callbacks.onClearOnShrinkChange(newValue==="true");break;case"terminal-progress":callbacks.onShowTerminalProgressChange(newValue==="true");break;case"tui-mode":callbacks.onTuiModeChange(newValue);break;case"fullscreen-exit-output":callbacks.onFullscreenExitOutputChange(newValue);break;case"fullscreen-scrollbar":callbacks.onFullscreenScrollbarChange(newValue);break;case"fullscreen-copy-on-select":callbacks.onFullscreenCopyOnSelectChange(newValue==="true");break;case"theme":callbacks.onThemeChange(newValue);break}},callbacks.onCancel,{enableSearch:!0}),this.addChild(this.settingsList),this.addChild(new DynamicBorder)}getSettingsList(){return this.settingsList}};var SkillInvocationMessageComponent=class extends Box{expanded=!1;skillBlock;markdownTheme;constructor(skillBlock,markdownTheme=getMarkdownTheme()){super(1,1,t=>theme.bg("customMessageBg",t)),this.skillBlock=skillBlock,this.markdownTheme=markdownTheme,this.updateDisplay()}setExpanded(expanded){this.expanded=expanded,this.updateDisplay()}invalidate(){super.invalidate(),this.updateDisplay()}updateDisplay(){if(this.clear(),this.expanded){let label=theme.fg("customMessageLabel","\x1B[1m[skill]\x1B[22m");this.addChild(new Text(label,0,0));let header=`**${this.skillBlock.name}**
|
|
1328
1328
|
|
|
1329
1329
|
`;this.addChild(new Markdown(header+this.skillBlock.content,0,0,this.markdownTheme,{color:text=>theme.fg("customMessageText",text)}))}else{let line=theme.fg("customMessageLabel","\x1B[1m[skill]\x1B[22m ")+theme.fg("customMessageText",this.skillBlock.name)+theme.fg("dim",` (${keyText("app.tools.expand")} to expand)`);this.addChild(new Text(line,0,0))}}};var FALLBACK_PREVIEW_LINES=10,ToolExecutionComponent=class extends Container{contentBox;contentText;selfRenderContainer;callRendererComponent;resultRendererComponent;rendererState={};imageComponents=[];imageSpacers=[];toolName;toolCallId;args;expanded=!1;showImages;imageWidthCells;isPartial=!0;toolDefinition;builtInToolDefinition;ui;cwd;executionStarted=!1;argsComplete=!1;result;convertedImages=new Map;hideComponent=!1;constructor(toolName,toolCallId,args,options={},toolDefinition,ui,cwd){super(),this.toolName=toolName,this.toolCallId=toolCallId,this.args=args,this.toolDefinition=toolDefinition,this.builtInToolDefinition=createAllToolDefinitions(cwd)[toolName],this.showImages=options.showImages??!0,this.imageWidthCells=options.imageWidthCells??60,this.ui=ui,this.cwd=cwd,this.addChild(new Spacer(1)),this.contentBox=new Box(1,1,text=>theme.bg("toolPendingBg",text)),this.contentText=new Text("",1,1,text=>theme.bg("toolPendingBg",text)),this.selfRenderContainer=new Container,this.hasRendererDefinition()?this.addChild(this.getRenderShell()==="self"?this.selfRenderContainer:this.contentBox):this.addChild(this.contentText),this.updateDisplay()}getCallRenderer(){return this.builtInToolDefinition?this.toolDefinition?this.toolDefinition.renderCall??this.builtInToolDefinition.renderCall:this.builtInToolDefinition.renderCall:this.toolDefinition?.renderCall}getResultRenderer(){return this.builtInToolDefinition?this.toolDefinition?this.toolDefinition.renderResult??this.builtInToolDefinition.renderResult:this.builtInToolDefinition.renderResult:this.toolDefinition?.renderResult}hasRendererDefinition(){return this.builtInToolDefinition!==void 0||this.toolDefinition!==void 0}getRenderShell(){return this.builtInToolDefinition?this.toolDefinition?this.toolDefinition.renderShell??this.builtInToolDefinition.renderShell??"default":this.builtInToolDefinition.renderShell??"default":this.toolDefinition?.renderShell??"default"}getRenderContext(lastComponent){return{args:this.args,toolCallId:this.toolCallId,invalidate:()=>{this.invalidate(),this.ui.requestRender()},lastComponent,state:this.rendererState,cwd:this.cwd,executionStarted:this.executionStarted,argsComplete:this.argsComplete,isPartial:this.isPartial,expanded:this.expanded,showImages:this.showImages,isError:this.result?.isError??!1}}createCallFallback(){return new Text(theme.fg("toolTitle",theme.bold(this.toolName)),0,0)}createResultFallback(){let output=this.getTextOutput();if(!output)return;let lines=output.split(`
|
|
1330
1330
|
`),displayLines=this.expanded?lines:lines.slice(0,FALLBACK_PREVIEW_LINES),remaining=lines.length-displayLines.length,text=displayLines.map(line=>theme.fg("toolOutput",line)).join(`
|
package/dist/bundle/cli.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
|
|
3
|
-
import{APP_NAME,configureHttpDispatcher,main}from"./chunks/chunk-
|
|
3
|
+
import{APP_NAME,configureHttpDispatcher,main}from"./chunks/chunk-2L25YYPC.js";import"./chunks/chunk-JUUC5AZY.js";import"./chunks/chunk-XDUWOHPL.js";import"./chunks/chunk-3QKHSPQL.js";import"./chunks/chunk-DRQDKNXA.js";import"./chunks/chunk-7ZY7IXZD.js";import"./chunks/chunk-V46XUTK3.js";import"./chunks/chunk-WGLBM2BP.js";import"./chunks/chunk-4L3WN2XY.js";process.title=APP_NAME;process.env.AGENT_FORGE="true";process.env.AI_AGENT="agent-forge";process.emitWarning=(()=>{});configureHttpDispatcher();main(process.argv.slice(2));
|
package/dist/bundle/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
|
|
2
|
-
import{AgentCompositionRuntime,AgentSession,AgentSessionRuntime,ArminComponent,AssistantMessageComponent,BOOTSTRAP_COMPACTION_PLUGIN_ID,BOOTSTRAP_LIFECYCLE_PLUGIN_ID,BOOTSTRAP_RETRY_PLUGIN_ID,BOOTSTRAP_TOOLS_PLUGIN_ID,BashExecutionComponent,BranchSummaryMessageComponent,CAPABILITY_CALL_EVENT_ID,CAPABILITY_CALL_EVENT_VERSION,CONFIG_DIR_NAME,CURRENT_SESSION_VERSION,CancellableLoader,CodingAgentServerService,CodingAgentSessionRuntime,CompactionSummaryMessageComponent,Container,CredentialSynchronizationError,CustomEditor,CustomMessageComponent,DEFAULT_COMPACTION_POLICY_NAME,DEFAULT_COMPACTION_SETTINGS,DEFAULT_MAX_BYTES,DEFAULT_MAX_LINES,DEFAULT_RETRY_POLICY_NAME,DEFAULT_SUITE_ID,DefaultPackageManager,DefaultResourceLoader,DialogEditorComponent,DialogInputComponent,DialogSelectorComponent,DurableServiceErrorV1,DynamicBorder,EXPERIMENTAL_PUBLIC_API_VERSION,FileSessionStorageProvider,FooterComponent,InteractiveMode,LifecycleExecuteError,LifecycleTransformError,Loader,LoginDialogComponent,MEMORY_RECALL_TOOL_NAME,MODEL_RESPONSE_EVENT_ID,MODEL_RESPONSE_EVENT_VERSION,MODEL_STREAM_EVENT_ID,MODEL_STREAM_EVENT_VERSION,ModelRuntime,ModelSelectorComponent,OAuthSelectorComponent,OPERATION_CANCEL_EVENT_ID,OPERATION_CANCEL_EVENT_VERSION,OPERATION_END_EVENT_ID,OPERATION_END_EVENT_VERSION,OPERATION_START_EVENT_ID,OPERATION_START_EVENT_VERSION,OPERATION_STEP_EVENT_ID,OPERATION_STEP_EVENT_VERSION,PLUGIN_DISPOSE_EVENT_ID,PLUGIN_DISPOSE_EVENT_VERSION,PLUGIN_READY_EVENT_ID,PLUGIN_READY_EVENT_VERSION,PluginManagerEntryComponent,RpcClient,SESSION_COMPACTION_COMMIT_EVENT_ID,SESSION_COMPACTION_COMMIT_EVENT_VERSION,SESSION_CONTEXT_REPLACED_EVENT_ID,SESSION_CONTEXT_REPLACED_EVENT_VERSION,SESSION_RELOAD_EVENT_ID,SESSION_RELOAD_EVENT_VERSION,SUITE_DELETE_CONFIRM_TOKEN,SUMMARY_MODEL_INVOCATION_ERROR_CODES,SelectList,SessionHeaderScanLimitError,SessionManager,SessionSelectorComponent,SettingsManager,SettingsSelectorComponent,SkillInvocationMessageComponent,Spacer,SuiteLifecycleError,SuiteResolutionError,TOOL_CALL_EVENT_ID,TOOL_CALL_EVENT_VERSION,TOOL_COMMIT_EVENT_ID,TOOL_COMMIT_EVENT_VERSION,TOOL_EXECUTE_EVENT_ID,TOOL_EXECUTE_EVENT_VERSION,TOOL_RESULT_EVENT_ID,TOOL_RESULT_EVENT_VERSION,TOOL_RESULT_RAW_EVENT_ID,TOOL_RESULT_RAW_EVENT_VERSION,TOOL_RESULT_TRANSFORM_EVENT_ID,TOOL_RESULT_TRANSFORM_EVENT_VERSION,Text,Theme,ThinkingSelectorComponent,ToolExecutionComponent,TreeSelectorComponent,UserMessageComponent,UserMessageSelectorComponent,VERSION,assembleCodingAgentServer,assembleProfile,buildContextEntries,buildProfileIdentityV1,buildResolvedAgentProfileV1,buildSessionContext,calculateContextTokens,clearDanglingSuiteSettings,collectEntriesForBranchSummary,compact,convertToLlm,convertToPng,copyToClipboard,createAgentCompositionRuntime,createAgentSession,createAgentSessionFromServices,createAgentSessionRuntime,createAgentSessionServices,createBashTool,createBashToolDefinition,createCapabilityRuntime,createCodingTools,createDisposableRegistration,createDurableService,createEditTool,createEditToolDefinition,createEventEnvelope,createFileDurableStoreBackend,createFileSessionSource,createFindTool,createFindToolDefinition,createGrepTool,createGrepToolDefinition,createHostOutputProjector,createLocalBashOperations,createLocalPowerShellOperations,createLsTool,createLsToolDefinition,createPowerShellTool,createPowerShellToolDefinition,createProfileLock,createProfileMigrationPolicy,createProfileRegistry,createReadOnlyTools,createReadTool,createReadToolDefinition,createStableAgentSession,createStableAgentSessionRuntime,createStdioChannelAdapter,createSuite,createSyntheticSourceInfo,createWriteTool,createWriteToolDefinition,defineTool,deleteSuite,detachedSessionSnapshot,detectSupportedImageMimeTypeFromFile,discoverCapabilityPluginManifests,dist_exports,durableLogPath,ecosystem_exports,estimateTokens,findCutPoint,findSuiteSessionRefs,findTurnStartIndex,formatDimensionNote,formatSize,formatSkillsForPrompt,generateBranchSummary,generateDiffString,generateSummary,generateSummaryWithUsage,generateUnifiedPatch,getAgentDir,getAvailableThemes,getDocsPath,getExamplesPath,getLanguageFromPath,getLastAssistantUsage,getLatestCompactionEntry,getMarkdownTheme,getPackageDir,getPowerShellConfig,getReadmePath,getSelectListTheme,getSessionsDir,getSettingsListTheme,getShellConfig,highlightCode,initTheme,installBootstrapCompactionPolicy,installBootstrapLifecycle,installBootstrapRetryPolicy,installBootstrapTools,installSessionBootstrapTools,isBuiltinSuiteId,keyHint,keyText,killProcessTree,listBuiltinPluginManifestsV1,listBuiltinPluginProfilesV1,listSuiteIds,loadCapabilityPlugin,loadCapabilityPluginFromManifest,loadCapabilityPluginSync,loadProjectContextFiles,loadSkills,loadSkillsFromDir,main,migrateSessionEntries,parseArgs,parseCapabilityPluginManifest,parseFrontmatter,parseSessionEntries,parseSkillBlock,plugin_manager_controller_exports,plugin_selection_controller_exports,prepareBranchEntries,profileIdentitiesCompatible,projectSessionTranscript,rawKeyHint,readStoredCredential,renderDiff,replaceProfileLock,replaceProfilePlugin,resetSuite,resizeImage,resolveBuiltinPluginProfileV1,resolveCliModel,resolveModelScopeWithDiagnostics,resolvePluginCapabilityOrder,runPrintMode,runRpcMode,sanitizeBinaryOutput,serializeConversation,sessionEntryToContextMessages,shouldCompact,stableJsonDigest,startCodingAgentRemoteServer,stripFrontmatter,truncateHead,truncateLine,truncateTail,truncateToVisualLines,validateCapabilityCallEventDataV1,validateExecutionFactsV1,validateModelResponseEventDataV1,validateModelStreamEventDataV1,validateOperationCancelEventDataV1,validateOperationEndEventDataV1,validateOperationStartEventDataV1,validateOperationStepEventDataV1,validatePluginDisposeEventDataV1,validatePluginReadyEventDataV1,validateRetryScheduleV1,validateSessionCompactionCommitEventDataV1,validateSessionContextReplacedEventDataV1,validateSessionReloadEventDataV1,validateToolCallEventDataV1,validateToolCommitEventDataV1,validateToolExecuteEventDataV1,validateToolResultEventDataV1,validateToolResultRawEventDataV1,validateToolResultTransformEventDataV1,verifyProfileLock,withFileMutationQueue}from"./chunks/chunk-DQFSJR74.js";import"./chunks/chunk-JUUC5AZY.js";import"./chunks/chunk-XDUWOHPL.js";import"./chunks/chunk-3QKHSPQL.js";import"./chunks/chunk-DRQDKNXA.js";import"./chunks/chunk-7ZY7IXZD.js";import"./chunks/chunk-V46XUTK3.js";import"./chunks/chunk-WGLBM2BP.js";import"./chunks/chunk-4L3WN2XY.js";function contentHash(bytes){let hash=2166136261;for(let byte of bytes)hash^=byte,hash=Math.imul(hash,16777619);return(hash>>>0).toString(36)}function toStat(entry){return{artifactId:entry.ref.artifactId,sessionId:entry.ref.sessionId,operationId:entry.ref.operationId,kind:entry.ref.kind,mediaType:entry.ref.mediaType,sizeBytes:entry.ref.sizeBytes,state:entry.ended?"ended":"available",...entry.ended?{endReason:entry.endReason}:{}}}function createArtifactStore(options={}){let now=options.now??(()=>Date.now()),artifacts=new Map,sequenceByIdentity=new Map,globalWriteSequence=0;return{write(input){if(input.bytes.length===0)throw new Error("Artifact bytes must not be empty");let identity=`${input.sessionId}\0${input.operationId}`,sequence=(sequenceByIdentity.get(identity)??0)+1;sequenceByIdentity.set(identity,sequence),globalWriteSequence+=1;let artifactId=`art-${contentHash(input.bytes)}-${sequence}-${globalWriteSequence}`,ref={artifactId,sessionId:input.sessionId,operationId:input.operationId,kind:input.kind,mediaType:input.mediaType,sizeBytes:input.bytes.length,truncated:!1,createdAt:now()};return artifacts.set(artifactId,{ref,bytes:input.bytes,ended:!1}),{ref}},read(input){let entry=artifacts.get(input.artifactId);if(!entry)throw new Error(`Artifact not found: ${input.artifactId}`);if(entry.ref.sessionId!==input.sessionId)throw new Error(`Artifact ${input.artifactId} belongs to a different session`);if(entry.ended)throw new Error(`Artifact ${input.artifactId} lifecycle has ended: ${entry.endReason??"ended"}`);return{mediaType:entry.ref.mediaType,bytes:entry.bytes}},stat(artifactId){let entry=artifacts.get(artifactId);return entry===void 0?void 0:toStat(entry)},list(sessionId){return[...artifacts.values()].filter(entry=>entry.ref.sessionId===sessionId).map(entry=>toStat(entry))},endLifecycle(artifactId,input){let entry=artifacts.get(artifactId);if(!entry)throw new Error(`Artifact not found: ${artifactId}`);if(entry.ended)throw new Error(`Artifact ${artifactId} lifecycle has already ended`);return entry.ended=!0,entry.endReason=input.reason,entry.bytes=new Uint8Array(0),toStat(entry)}}}function planArtifactPages(store,input){if(!Number.isSafeInteger(input.pageSize)||input.pageSize<1)return{status:"invalid_page_size",pageSize:input.pageSize};let stat=store.stat(input.artifactId);if(!stat)return{status:"unavailable",reason:`Artifact not found: ${input.artifactId}`};if(stat.state==="ended")return{status:"unavailable",reason:`Artifact ${input.artifactId} lifecycle has ended: ${stat.endReason??"ended"}`};let totalBytes=stat.sizeBytes??0,pages=[];for(let offset=0;offset<totalBytes;offset+=input.pageSize)pages.push({index:pages.length,offset,size:Math.min(input.pageSize,totalBytes-offset)});return{status:"planned",totalBytes,pageSize:input.pageSize,pages:Object.freeze(pages)}}function readArtifactPage(store,input){if(!Number.isSafeInteger(input.pageSize)||input.pageSize<1)return{status:"unavailable",reason:`Invalid page size: ${input.pageSize}`};let plan=planArtifactPages(store,{artifactId:input.artifactId,pageSize:input.pageSize});if(plan.status!=="planned")return{status:"unavailable",reason:plan.status==="unavailable"?plan.reason:`Invalid page size: ${plan.pageSize}`};let page=plan.pages[input.index];if(!page)return{status:"unavailable",reason:`Page ${input.index} is outside the plan (${plan.pages.length} pages)`};let bytes;try{bytes=store.read({artifactId:input.artifactId,sessionId:input.sessionId}).bytes}catch(error){return{status:"unavailable",reason:error instanceof Error?error.message:String(error)}}let slice=bytes.slice(page.offset,page.offset+page.size),nextOffset=page.offset+page.size,hasMore=nextOffset<plan.totalBytes;return{status:"ok",index:page.index,offset:page.offset,bytes:slice,hasMore,...hasMore?{nextOffset}:{}}}var AGENT_CAPABILITY_CONTRACT_ID="agent-forge/agent-capability-contract",AGENT_CAPABILITY_CONTRACT_VERSION=1,AGENT_ERROR_CODES_V1=["provider_error","operation_timeout","operation_cancelled","idempotency_conflict","revision_conflict","revision_unavailable","unsupported_capability","invalid_request","invalid_ref","not_found","cancelled","unsupported","busy","session_locked","unauthorized","not_implemented","internal_error"],agentErrorCodeSet=new Set(AGENT_ERROR_CODES_V1);function isRegisteredAgentErrorCodeV1(code){return agentErrorCodeSet.has(code)}var PROTOCOL_ERROR_CODE_TO_AGENT_CODE_V1=Object.freeze({version:"unsupported",busy:"busy",session_locked:"session_locked",not_found:"not_found",invalid_request:"invalid_request",unauthorized:"unauthorized",not_implemented:"not_implemented",internal_error:"internal_error"});function mapProtocolErrorCodeToAgentErrorV1(code){return PROTOCOL_ERROR_CODE_TO_AGENT_CODE_V1[code]}function toErrorEnvelopeV1(error){let message=error instanceof Error?error.message:String(error),name=error instanceof Error?error.name:void 0,code;if(error&&typeof error=="object"&&"code"in error){let raw=error.code;typeof raw=="string"&&raw.trim()!==""&&(code=raw)}code===void 0&&(code="internal_error");let mapped=PROTOCOL_ERROR_CODE_TO_AGENT_CODE_V1[code];return buildErrorEnvelopeV1({version:1,code:mapped??code,message,retryable:!1,...name===void 0?{}:{name}})}function isPlainRecord(value){if(value===null||typeof value!="object"||Array.isArray(value))return!1;let prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}function assertPlainRecord(value,label){if(!isPlainRecord(value))throw new Error(`${label} must be a plain object`)}function assertExactKeys(value,required,optional,label){let allowed=new Set([...required,...optional]),unsupported=Object.keys(value).filter(key=>!allowed.has(key)).sort();if(unsupported.length>0)throw new Error(`${label} has unsupported fields: ${unsupported.join(", ")}`);for(let key of required)if(!(key in value))throw new Error(`${label} is missing required field: ${key}`)}function assertNonEmptyString(value,label){if(typeof value!="string"||value.trim().length===0)throw new Error(`${label} must be a non-empty string`)}function assertPositiveSafeInteger(value,label){if(typeof value!="number"||!Number.isSafeInteger(value)||value<1)throw new Error(`${label} must be a positive safe integer`)}function assertNonNegativeSafeInteger(value,label){if(typeof value!="number"||!Number.isSafeInteger(value)||value<0)throw new Error(`${label} must be a non-negative safe integer`)}function assertJsonValue(value,label,seen=new WeakSet){if(!(value===null||typeof value=="boolean"||typeof value=="string")){if(typeof value=="number"){if(Number.isFinite(value))return;throw new Error(`${label} must contain finite JSON numbers`)}if(typeof value!="object")throw new Error(`${label} must be JSON-compatible`);if(seen.has(value))throw new Error(`${label} must not contain cycles`);if(seen.add(value),Array.isArray(value))for(let[index,child]of value.entries())assertJsonValue(child,`${label}[${index}]`,seen);else{if(!isPlainRecord(value))throw new Error(`${label} must contain only plain JSON objects`);for(let[key,child]of Object.entries(value))assertJsonValue(child,`${label}.${key}`,seen)}seen.delete(value)}}function detachedFreeze(value,seen=new WeakMap){if(value===null||typeof value!="object")return value;let existing=seen.get(value);if(existing!==void 0)return existing;if(Array.isArray(value)){let result2=[];seen.set(value,result2);for(let child of value)result2.push(detachedFreeze(child,seen));return Object.freeze(result2)}let result={};seen.set(value,result);for(let[key,child]of Object.entries(value))result[key]=detachedFreeze(child,seen);return Object.freeze(result)}function capabilitySort(left,right){return left.id<right.id?-1:left.id>right.id?1:left.version-right.version}function validateCapabilityRefs(value,label){if(!Array.isArray(value))throw new Error(`${label} must be an array`);let refs=value.map((item,index)=>validateCapabilityRefV1(item,`${label}[${index}]`)),seen=new Set;for(let ref of refs){let key=`${ref.id}\0${ref.version}`;if(seen.has(key))throw new Error(`${label} contains duplicate capability: ${ref.id}@${ref.version}`);seen.add(key)}return Object.freeze(refs.sort(capabilitySort))}function validateHostTransport(value,label){if(value!=="in-process"&&value!=="stdio"&&value!=="http"&&value!=="rpc"&&value!=="unix"&&value!=="websocket")throw new Error(`${label} is invalid`)}function validateCapabilityRefV1(value,label="Capability reference"){return assertPlainRecord(value,label),assertExactKeys(value,["id","version"],[],label),assertNonEmptyString(value.id,`${label}.id`),assertPositiveSafeInteger(value.version,`${label}.version`),detachedFreeze({id:value.id,version:value.version})}function validateHostContextV1(value){if(assertPlainRecord(value,"Host context"),assertExactKeys(value,["mode","features","transports"],[],"Host context"),value.mode!=="readonly"&&value.mode!=="full-control")throw new Error("Host context.mode is invalid");if(!Array.isArray(value.features))throw new Error("Host context.features must be an array");let features=value.features.map((feature,index)=>(assertNonEmptyString(feature,`Host context.features[${index}]`),feature));if(new Set(features).size!==features.length)throw new Error("Host context.features must not contain duplicates");if(!Array.isArray(value.transports))throw new Error("Host context.transports must be an array");let transports=value.transports.map((transport,index)=>(validateHostTransport(transport,`Host context.transports[${index}]`),transport));if(new Set(transports).size!==transports.length)throw new Error("Host context.transports must not contain duplicates");return detachedFreeze({mode:value.mode,features:[...features].sort(),transports:[...transports].sort()})}function buildHostContextV1(input){return validateHostContextV1(input)}function validateContractCompatibilityRequirementsV1(value){assertPlainRecord(value,"Contract compatibility requirements"),assertExactKeys(value,["contractId","version","mode","features","transports","capabilities"],[],"Contract compatibility requirements"),assertNonEmptyString(value.contractId,"Contract compatibility requirements.contractId"),assertPositiveSafeInteger(value.version,"Contract compatibility requirements.version");let hostContext=validateHostContextV1({mode:value.mode,features:value.features,transports:value.transports}),capabilities=validateCapabilityRefs(value.capabilities,"Contract compatibility requirements.capabilities");return detachedFreeze({contractId:value.contractId,version:value.version,mode:hostContext.mode,features:hostContext.features,transports:hostContext.transports,capabilities})}function buildContractCompatibilityRequirementsV1(input){return validateContractCompatibilityRequirementsV1(input)}var CONTRACT_COMPATIBILITY_ISSUE_CODES_V1=["unsupported_contract","host_mode_mismatch","unsupported_feature","unsupported_transport","unsupported_capability"];function validateContractCompatibilityResultV1(value){if(assertPlainRecord(value,"Contract compatibility result"),assertExactKeys(value,["version","compatible","issues"],[],"Contract compatibility result"),value.version!==1)throw new Error("Contract compatibility result.version must be 1");if(typeof value.compatible!="boolean")throw new Error("Contract compatibility result.compatible must be boolean");if(!Array.isArray(value.issues))throw new Error("Contract compatibility result.issues must be an array");if(value.compatible&&value.issues.length>0)throw new Error("Contract compatibility result.compatible must be false when issues exist");if(!value.compatible&&value.issues.length===0)throw new Error("Contract compatibility result.compatible must be true when no issues exist");let issues=value.issues.map((entry,index)=>{if(assertPlainRecord(entry,`Contract compatibility result.issues[${index}]`),assertExactKeys(entry,["code","error"],["missingFeatures","missingTransports","missingCapabilities"],`Contract compatibility result.issues[${index}]`),!CONTRACT_COMPATIBILITY_ISSUE_CODES_V1.includes(entry.code))throw new Error(`Contract compatibility result.issues[${index}].code is invalid`);let error=validateErrorEnvelopeV1(entry.error),missingFeatures=entry.missingFeatures;if(missingFeatures!==void 0&&(!Array.isArray(missingFeatures)||missingFeatures.some(item=>typeof item!="string")))throw new Error(`Contract compatibility result.issues[${index}].missingFeatures must be strings`);let missingTransports=entry.missingTransports;if(missingTransports!==void 0&&(!Array.isArray(missingTransports)||missingTransports.some(item=>typeof item!="string")))throw new Error(`Contract compatibility result.issues[${index}].missingTransports must be strings`);let missingCapabilities=entry.missingCapabilities;missingCapabilities!==void 0&&validateCapabilityRefs(missingCapabilities,`Contract compatibility result.issues[${index}].missingCapabilities`);let issue={code:entry.code,error,...missingFeatures===void 0?{}:{missingFeatures:Object.freeze(missingFeatures.map(item=>item))},...missingTransports===void 0?{}:{missingTransports:Object.freeze(missingTransports.map(item=>item))},...missingCapabilities===void 0?{}:{missingCapabilities:validateCapabilityRefs(missingCapabilities,"missingCapabilities")}};return detachedFreeze(issue)});return detachedFreeze({version:1,compatible:value.compatible,issues:Object.freeze(issues)})}function validateAgentCapabilityContractV1(value){if(assertPlainRecord(value,"Agent capability contract"),assertExactKeys(value,["contractId","version","capabilities","hostContext"],[],"Agent capability contract"),value.contractId!==AGENT_CAPABILITY_CONTRACT_ID)throw new Error(`Agent capability contract.contractId must be ${AGENT_CAPABILITY_CONTRACT_ID}`);if(value.version!==1)throw new Error("Agent capability contract.version must be 1");let capabilities=validateCapabilityRefs(value.capabilities,"Agent capability contract.capabilities"),hostContext=validateHostContextV1(value.hostContext);return detachedFreeze({contractId:value.contractId,version:1,capabilities,hostContext})}function buildAgentCapabilityContractV1(input){return validateAgentCapabilityContractV1({...input,version:input.version??1})}function validateAgentProfileV1(value){assertPlainRecord(value,"Agent profile"),assertExactKeys(value,["id","version","rootAgent","requiredPlugins"],["optionalPlugins","defaults"],"Agent profile"),assertNonEmptyString(value.id,"Agent profile.id"),assertPositiveSafeInteger(value.version,"Agent profile.version"),assertNonEmptyString(value.rootAgent,"Agent profile.rootAgent");let validatePluginIds=(candidate,label)=>{if(!Array.isArray(candidate))throw new Error(`${label} must be an array`);let ids=candidate.map((id,index)=>(assertNonEmptyString(id,`${label}[${index}]`),id));if(new Set(ids).size!==ids.length)throw new Error(`${label} must not contain duplicates`);return Object.freeze([...ids].sort())},requiredPlugins=validatePluginIds(value.requiredPlugins,"Agent profile.requiredPlugins"),optionalPlugins=value.optionalPlugins===void 0?void 0:validatePluginIds(value.optionalPlugins,"Agent profile.optionalPlugins");if(optionalPlugins?.some(id=>requiredPlugins.includes(id)))throw new Error("Agent profile.optionalPlugins must not overlap requiredPlugins");return value.defaults!==void 0&&assertJsonValue(value.defaults,"Agent profile.defaults"),detachedFreeze({id:value.id,version:value.version,rootAgent:value.rootAgent,requiredPlugins,...optionalPlugins===void 0?{}:{optionalPlugins},...value.defaults===void 0?{}:{defaults:value.defaults}})}function buildAgentProfileV1(input){return validateAgentProfileV1(input)}function validateArtifactRefV1(value){if(assertPlainRecord(value,"Artifact reference"),assertExactKeys(value,["sessionId","operationId","artifactId","kind","mediaType","truncated","createdAt"],["sizeBytes"],"Artifact reference"),assertNonEmptyString(value.sessionId,"Artifact reference.sessionId"),assertNonEmptyString(value.operationId,"Artifact reference.operationId"),assertNonEmptyString(value.artifactId,"Artifact reference.artifactId"),assertNonEmptyString(value.kind,"Artifact reference.kind"),assertNonEmptyString(value.mediaType,"Artifact reference.mediaType"),value.sizeBytes!==void 0&&assertNonNegativeSafeInteger(value.sizeBytes,"Artifact reference.sizeBytes"),typeof value.truncated!="boolean")throw new Error("Artifact reference.truncated must be boolean");return assertNonNegativeSafeInteger(value.createdAt,"Artifact reference.createdAt"),detachedFreeze({sessionId:value.sessionId,operationId:value.operationId,artifactId:value.artifactId,kind:value.kind,mediaType:value.mediaType,...value.sizeBytes===void 0?{}:{sizeBytes:value.sizeBytes},truncated:value.truncated,createdAt:value.createdAt})}function buildArtifactRefV1(input){return validateArtifactRefV1(input)}function checkContractCompatibilityV1(candidateInput,requirementsInput){let candidate=validateAgentCapabilityContractV1(candidateInput),requirements=validateContractCompatibilityRequirementsV1(requirementsInput),issues=[];(candidate.contractId!==requirements.contractId||candidate.version!==requirements.version)&&issues.push({code:"unsupported_contract",error:commandError("unsupported_contract",`Contract is unsupported: ${requirements.contractId}@${requirements.version}`)}),candidate.hostContext.mode!==requirements.mode&&issues.push({code:"host_mode_mismatch",error:commandError("host_mode_mismatch",`Host mode is incompatible: required ${requirements.mode}, received ${candidate.hostContext.mode}`)});let missingFeatures=requirements.features.filter(feature=>!candidate.hostContext.features.includes(feature));missingFeatures.length>0&&issues.push({code:"unsupported_feature",error:commandError("unsupported_feature",`Host features are unsupported: ${missingFeatures.join(", ")}`),missingFeatures:Object.freeze([...missingFeatures])});let missingTransports=requirements.transports.filter(transport=>!candidate.hostContext.transports.includes(transport));missingTransports.length>0&&issues.push({code:"unsupported_transport",error:commandError("unsupported_transport",`Host transports are unsupported: ${missingTransports.join(", ")}`),missingTransports:Object.freeze([...missingTransports])});let missingCapabilities=requirements.capabilities.filter(required=>!candidate.capabilities.some(available=>available.id===required.id&&available.version===required.version));return missingCapabilities.length>0&&issues.push({code:"unsupported_capability",error:commandError("unsupported_capability",`Capabilities are unsupported: ${missingCapabilities.map(item=>`${item.id}@${item.version}`).join(", ")}`),missingCapabilities:Object.freeze([...missingCapabilities])}),detachedFreeze({version:1,compatible:issues.length===0,issues})}function validateAgentRole(value,label){if(value!=="root-agent-controller"&&value!=="child-agent-controller")throw new Error(`${label} is invalid`)}function validateAgentDefinitionSnapshotV1(value){if(assertPlainRecord(value,"Agent definition snapshot"),assertExactKeys(value,["version","id","definitionVersion","role","capabilities"],["owner"],"Agent definition snapshot"),value.version!==1)throw new Error("Agent definition snapshot.version must be 1");assertNonEmptyString(value.id,"Agent definition snapshot.id"),assertPositiveSafeInteger(value.definitionVersion,"Agent definition snapshot.definitionVersion"),validateAgentRole(value.role,"Agent definition snapshot.role");let capabilities=validateCapabilityRefs(value.capabilities,"Agent definition snapshot.capabilities");return value.owner!==void 0&&assertNonEmptyString(value.owner,"Agent definition snapshot.owner"),detachedFreeze({version:1,id:value.id,definitionVersion:value.definitionVersion,role:value.role,capabilities,...value.owner===void 0?{}:{owner:value.owner}})}function buildAgentDefinitionSnapshotV1(input){return validateAgentDefinitionSnapshotV1(input)}function validateAgentInstanceSnapshotV1(value){if(assertPlainRecord(value,"Agent instance snapshot"),assertExactKeys(value,["version","id","definitionId","definitionVersion","role","status","revision"],["parentInstanceId","leaseOwner"],"Agent instance snapshot"),value.version!==1)throw new Error("Agent instance snapshot.version must be 1");if(assertNonEmptyString(value.id,"Agent instance snapshot.id"),assertNonEmptyString(value.definitionId,"Agent instance snapshot.definitionId"),assertPositiveSafeInteger(value.definitionVersion,"Agent instance snapshot.definitionVersion"),validateAgentRole(value.role,"Agent instance snapshot.role"),value.status!=="created"&&value.status!=="running"&&value.status!=="succeeded"&&value.status!=="failed"&&value.status!=="cancelled"&&value.status!=="disposed")throw new Error("Agent instance snapshot.status is invalid");return assertNonNegativeSafeInteger(value.revision,"Agent instance snapshot.revision"),value.parentInstanceId!==void 0&&assertNonEmptyString(value.parentInstanceId,"Agent instance snapshot.parentInstanceId"),value.leaseOwner!==void 0&&assertNonEmptyString(value.leaseOwner,"Agent instance snapshot.leaseOwner"),detachedFreeze({version:1,id:value.id,definitionId:value.definitionId,definitionVersion:value.definitionVersion,role:value.role,status:value.status,revision:value.revision,...value.parentInstanceId===void 0?{}:{parentInstanceId:value.parentInstanceId},...value.leaseOwner===void 0?{}:{leaseOwner:value.leaseOwner}})}function buildAgentInstanceSnapshotV1(input){return validateAgentInstanceSnapshotV1(input)}function validateSessionRevisionV1(value){if(assertPlainRecord(value,"Session revision"),assertExactKeys(value,["version","sessionId","sequence","leafId"],[],"Session revision"),value.version!==1)throw new Error("Session revision.version must be 1");if(assertNonEmptyString(value.sessionId,"Session revision.sessionId"),assertNonNegativeSafeInteger(value.sequence,"Session revision.sequence"),value.leafId!==null&&value.leafId!==void 0&&assertNonEmptyString(value.leafId,"Session revision.leafId"),value.leafId===void 0)throw new Error("Session revision.leafId is required");return detachedFreeze({version:1,sessionId:value.sessionId,sequence:value.sequence,leafId:value.leafId})}function buildSessionRevisionV1(input){return validateSessionRevisionV1(input)}function validateSessionSnapshotV1(value){if(assertPlainRecord(value,"Session snapshot"),assertExactKeys(value,["version","sessionId","revision"],[],"Session snapshot"),value.version!==1)throw new Error("Session snapshot.version must be 1");assertNonEmptyString(value.sessionId,"Session snapshot.sessionId");let revision=validateSessionRevisionV1(value.revision);if(revision.sessionId!==value.sessionId)throw new Error("Session snapshot.revision.sessionId must match sessionId");return detachedFreeze({version:1,sessionId:value.sessionId,revision})}function buildSessionSnapshotV1(input){return validateSessionSnapshotV1(input)}function validateErrorEnvelopeV1(value){if(assertPlainRecord(value,"Error envelope"),assertExactKeys(value,["version","code","message","retryable"],["details","name"],"Error envelope"),value.version!==1)throw new Error("Error envelope.version must be 1");if(assertNonEmptyString(value.code,"Error envelope.code"),typeof value.message!="string")throw new Error("Error envelope.message must be a string");if(typeof value.retryable!="boolean")throw new Error("Error envelope.retryable must be a boolean");return value.name!==void 0&&assertNonEmptyString(value.name,"Error envelope.name"),value.details!==void 0&&assertJsonValue(value.details,"Error envelope.details"),detachedFreeze({version:1,code:value.code,message:value.message,retryable:value.retryable,...value.details===void 0?{}:{details:value.details},...value.name===void 0?{}:{name:value.name}})}function buildErrorEnvelopeV1(input){return validateErrorEnvelopeV1(input)}function validateOperationTerminalStatus(value,label){if(value!=="succeeded"&&value!=="failed"&&value!=="cancelled"&&value!=="timed_out")throw new Error(`${label} is invalid`)}function validateOperationTerminalV1(value){if(assertPlainRecord(value,"Operation terminal"),!("version"in value)||!("status"in value))throw new Error("Operation terminal is missing required field: version or status");if(value.version!==1)throw new Error("Operation terminal.version must be 1");if(validateOperationTerminalStatus(value.status,"Operation terminal.status"),value.status==="succeeded")return assertExactKeys(value,["version","status"],["result"],"Operation terminal"),value.result!==void 0&&assertJsonValue(value.result,"Operation terminal.result"),detachedFreeze({version:1,status:"succeeded",...value.result===void 0?{}:{result:value.result}});assertExactKeys(value,["version","status","error"],[],"Operation terminal");let error=validateErrorEnvelopeV1(value.error);return detachedFreeze({version:1,status:value.status,error})}function buildOperationTerminalV1(input){return validateOperationTerminalV1(input)}function validateOperationSnapshotV1(value){if(assertPlainRecord(value,"Operation snapshot"),assertExactKeys(value,["version","operationId","kind","status"],["terminal","instanceId","sessionId","inputRevision"],"Operation snapshot"),value.version!==1)throw new Error("Operation snapshot.version must be 1");if(assertNonEmptyString(value.operationId,"Operation snapshot.operationId"),assertNonEmptyString(value.kind,"Operation snapshot.kind"),value.status!=="queued"&&value.status!=="running"&&value.status!=="succeeded"&&value.status!=="failed"&&value.status!=="cancelled"&&value.status!=="timed_out")throw new Error("Operation snapshot.status is invalid");if((value.status==="queued"||value.status==="running")&&value.terminal!==void 0)throw new Error("Operation snapshot active status must not have a terminal");if(value.status!=="queued"&&value.status!=="running"&&value.terminal===void 0)throw new Error("Operation snapshot terminal status requires a terminal");let terminal=value.terminal===void 0?void 0:validateOperationTerminalV1(value.terminal);if(terminal!==void 0&&terminal.status!==value.status)throw new Error("Operation snapshot.terminal.status must match status");value.instanceId!==void 0&&assertNonEmptyString(value.instanceId,"Operation snapshot.instanceId"),value.sessionId!==void 0&&assertNonEmptyString(value.sessionId,"Operation snapshot.sessionId");let inputRevision=value.inputRevision===void 0?void 0:validateSessionRevisionV1(value.inputRevision);if(inputRevision!==void 0&&value.sessionId!==void 0&&inputRevision.sessionId!==value.sessionId)throw new Error("Operation snapshot.inputRevision.sessionId must match sessionId");return detachedFreeze({version:1,operationId:value.operationId,kind:value.kind,status:value.status,...terminal===void 0?{}:{terminal},...value.instanceId===void 0?{}:{instanceId:value.instanceId},...value.sessionId===void 0?{}:{sessionId:value.sessionId},...inputRevision===void 0?{}:{inputRevision}})}function buildOperationSnapshotV1(input){return validateOperationSnapshotV1(input)}function validateCommandRequestV1(value){if(assertPlainRecord(value,"Command request"),assertExactKeys(value,["version","operationId","idempotencyKey","command","target","input","hostContext"],["expectedRevision"],"Command request"),value.version!==1)throw new Error("Command request.version must be 1");assertNonEmptyString(value.operationId,"Command request.operationId"),assertNonEmptyString(value.idempotencyKey,"Command request.idempotencyKey"),assertNonEmptyString(value.command,"Command request.command"),assertNonEmptyString(value.target,"Command request.target"),assertJsonValue(value.input,"Command request.input");let expectedRevision=value.expectedRevision===void 0?void 0:validateSessionRevisionV1(value.expectedRevision);if(expectedRevision!==void 0&&expectedRevision.sessionId!==value.target)throw new Error("Command request.expectedRevision.sessionId does not match target");let hostContext=validateHostContextV1(value.hostContext);return detachedFreeze({version:1,operationId:value.operationId,idempotencyKey:value.idempotencyKey,command:value.command,target:value.target,input:value.input,...expectedRevision===void 0?{}:{expectedRevision},hostContext})}function buildCommandRequestV1(input){return validateCommandRequestV1({...input,version:input.version??1})}function validateCommandAdmissionV1(value){if(assertPlainRecord(value,"Command admission"),assertExactKeys(value,["version","status","request"],["operation","error"],"Command admission"),value.version!==1)throw new Error("Command admission.version must be 1");if(value.status!=="accepted"&&value.status!=="existing"&&value.status!=="rejected")throw new Error("Command admission.status is invalid");let request=validateCommandRequestV1(value.request),operation=value.operation===void 0?void 0:validateOperationSnapshotV1(value.operation);if((value.status==="accepted"||value.status==="existing")&&operation===void 0)throw new Error("Command admission accepted status requires an operation");if(value.status==="rejected"&&value.error===void 0)throw new Error("Command admission rejected status requires an error");let error=value.error===void 0?void 0:validateErrorEnvelopeV1(value.error);return detachedFreeze({version:1,status:value.status,request,...operation===void 0?{}:{operation},...error===void 0?{}:{error}})}function canonicalJson(value){if(value===null||typeof value!="object")return JSON.stringify(value);if(Array.isArray(value))return`[${value.map(canonicalJson).join(",")}]`;let record=value;return`{${Object.keys(record).sort().map(key=>`${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`}function sameRevision(left,right){return left.sessionId===right.sessionId&&left.sequence===right.sequence&&left.leafId===right.leafId}function commandError(code,message,details){return buildErrorEnvelopeV1({version:1,code,message,retryable:!1,...details===void 0?{}:{details}})}function rejectedAdmission(request,error){return detachedFreeze({version:1,status:"rejected",request,error})}function createCommandOperationRegistryV1(){let entries=new Map,read=operationId=>{assertNonEmptyString(operationId,"operationId");let entry=entries.get(operationId);if(!entry)throw new Error(`Operation is not retained: ${operationId}`);return entry},write=(entry,operation)=>(entry.operation=operation,operation),terminal=entry=>entry.operation.terminal!==void 0;return Object.freeze({admit(input,currentRevision){let request=validateCommandRequestV1(input),current=currentRevision===void 0?void 0:validateSessionRevisionV1(currentRevision),fingerprint=canonicalJson(request),existing=entries.get(request.operationId);if(existing)return existing.fingerprint===fingerprint?detachedFreeze({version:1,status:"existing",request,operation:existing.operation}):rejectedAdmission(request,commandError("idempotency_conflict",`Operation ID is already bound to different input: ${request.operationId}`));if(request.expectedRevision!==void 0){if(current===void 0)return rejectedAdmission(request,commandError("revision_unavailable",`Current revision is required for: ${request.target}`));if(!sameRevision(request.expectedRevision,current))return rejectedAdmission(request,commandError("revision_conflict",`Expected revision does not match: ${request.target}`,{expectedRevision:request.expectedRevision,currentRevision:current}))}let operation=buildOperationSnapshotV1({version:1,operationId:request.operationId,kind:`command:${request.command}`,status:"queued",...request.expectedRevision===void 0?{}:{sessionId:request.expectedRevision.sessionId,inputRevision:request.expectedRevision}});return entries.set(request.operationId,{request,fingerprint,operation}),detachedFreeze({version:1,status:"accepted",request,operation})},start(operationId){let entry=read(operationId);return entry.operation.status!=="queued"?entry.operation:write(entry,buildOperationSnapshotV1({...entry.operation,status:"running"}))},complete(operationId,terminalSnapshot){let entry=read(operationId),nextTerminal=validateOperationTerminalV1(terminalSnapshot);if(terminal(entry)){if(canonicalJson(entry.operation.terminal)!==canonicalJson(nextTerminal))throw new Error(`Operation already has a different terminal result: ${operationId}`);return entry.operation}return write(entry,buildOperationSnapshotV1({...entry.operation,status:nextTerminal.status,terminal:nextTerminal}))},cancel(operationId){let entry=read(operationId);return terminal(entry)?entry.operation:write(entry,buildOperationSnapshotV1({...entry.operation,status:"cancelled",terminal:{version:1,status:"cancelled",error:commandError("operation_cancelled",`Operation cancelled: ${operationId}`)}}))},get(operationId){return assertNonEmptyString(operationId,"operationId"),entries.get(operationId)?.operation},release(operationId){assertNonEmptyString(operationId,"operationId"),entries.delete(operationId)}})}function buildCanonicalContractVectorsV1(){let hostContext=buildHostContextV1({mode:"full-control",features:["agent.run","session.snapshot"],transports:["in-process"]}),contract=buildAgentCapabilityContractV1({contractId:AGENT_CAPABILITY_CONTRACT_ID,capabilities:[{id:"agent.run",version:1}],hostContext}),profile=buildAgentProfileV1({id:"coding-agent",version:1,rootAgent:"coding-agent.root",requiredPlugins:["bootstrap-tools"],optionalPlugins:["bootstrap-skills"],defaults:{mode:"full-control",context:{strategy:"default"}}}),artifact=buildArtifactRefV1({sessionId:"session-vector-1",operationId:"vector-operation-1",artifactId:"artifact-vector-1",kind:"operation_record",mediaType:"application/json",sizeBytes:13,truncated:!1,createdAt:0}),revision=buildSessionRevisionV1({version:1,sessionId:"session-vector-1",sequence:0,leafId:null}),definition=buildAgentDefinitionSnapshotV1({version:1,id:"coding-agent.root",definitionVersion:1,role:"root-agent-controller",capabilities:[{id:"agent.run",version:1}],owner:"coding-agent"}),instance=buildAgentInstanceSnapshotV1({version:1,id:"instance-vector-1",definitionId:definition.id,definitionVersion:definition.definitionVersion,role:definition.role,status:"created",revision:0}),session=buildSessionSnapshotV1({version:1,sessionId:revision.sessionId,revision}),error=buildErrorEnvelopeV1({version:1,code:"provider_error",message:"provider failed",retryable:!0}),command=buildCommandRequestV1({operationId:"vector-operation-1",idempotencyKey:"vector-request-1",command:"agent.run",target:"session-vector-1",input:{prompt:"vector"},expectedRevision:{version:1,sessionId:"session-vector-1",sequence:0,leafId:null},hostContext}),registry=createCommandOperationRegistryV1(),accepted=registry.admit(command,command.expectedRevision);if(accepted.status!=="accepted"||accepted.operation===void 0)throw new Error("Canonical contract vector admission failed");let running=registry.start(command.operationId),terminal=registry.complete(command.operationId,{version:1,status:"succeeded",result:{ok:!0}}),event=buildEventEnvelopeV1({id:"vector-event-1",deliveryId:"vector-delivery-1",type:"operation.end",source:"canonical-vector",category:"authoritative",deliveryGuarantee:"best-effort",timestamp:0,operationId:command.operationId,correlationId:command.operationId,data:{version:1,operationId:command.operationId,operationKind:command.command,status:"succeeded"}});return detachedFreeze({version:1,contract,definition,instance,session,revision,error,profile,artifact,command,accepted,running,terminal,event})}function buildCanonicalContractFixtureVectorsV1(){let base=buildCanonicalContractVectorsV1(),registry=createCommandOperationRegistryV1(),request=buildCommandRequestV1({operationId:"fixture-operation-1",idempotencyKey:"fixture-request-1",command:"agent.run",target:"session-fixture-1",input:{prompt:"fixture"},expectedRevision:{version:1,sessionId:"session-fixture-1",sequence:1,leafId:"leaf-1"},hostContext:base.contract.hostContext});registry.admit(request,request.expectedRevision);let existing=registry.admit(request,request.expectedRevision),idempotencyConflict=registry.admit({...request,input:{prompt:"different"}},request.expectedRevision),revisionConflict=registry.admit({...request,operationId:"fixture-operation-2",idempotencyKey:"fixture-request-2"},{version:1,sessionId:"session-fixture-1",sequence:2,leafId:"leaf-2"}),cancelled=registry.cancel(request.operationId),terminalReplay=registry.complete(request.operationId,cancelled.terminal);if(registry.admit(buildCommandRequestV1({...request,operationId:"fixture-operation-failed",idempotencyKey:"fixture-request-failed"}),request.expectedRevision).status!=="accepted")throw new Error("Canonical contract failed vector admission failed");let failedTerminal=registry.complete("fixture-operation-failed",{version:1,status:"failed",error:buildErrorEnvelopeV1({version:1,code:"provider_error",message:"provider failed",retryable:!0})});if(registry.admit(buildCommandRequestV1({...request,operationId:"fixture-operation-timeout",idempotencyKey:"fixture-request-timeout"}),request.expectedRevision).status!=="accepted")throw new Error("Canonical contract timeout vector admission failed");let timedOutTerminal=registry.complete("fixture-operation-timeout",{version:1,status:"timed_out",error:buildErrorEnvelopeV1({version:1,code:"operation_timeout",message:"operation timed out",retryable:!0})}),unsupported=buildUnsupportedCapabilityV1({id:"fixture.missing",version:1}),observation=buildEventEnvelopeV1({id:"fixture-event-1",deliveryId:"fixture-delivery-1",type:"fixture.observation",source:"canonical-vector",timestamp:0,data:{observed:!0}}),correlated=buildEventEnvelopeV1({id:"fixture-event-correlated",deliveryId:"fixture-delivery-correlated",type:"operation.end",source:"canonical-vector",category:"authoritative",timestamp:0,operationId:"fixture-operation-1",correlationId:"fixture-operation-1",data:{status:"cancelled"}}),steer=buildCommandRequestV1({operationId:"fixture-operation-steer",idempotencyKey:"fixture-request-steer",command:"session.steer",target:"session-fixture-1",input:{text:"steer"},expectedRevision:request.expectedRevision,hostContext:base.contract.hostContext}),operationStep=buildEventEnvelopeV1({id:"fixture-event-step",deliveryId:"fixture-delivery-step",type:"operation.step",source:"canonical-vector",category:"progress",timestamp:0,operationId:"fixture-operation-steer",correlationId:"fixture-operation-steer",data:{version:1,operationId:"fixture-operation-steer",operationKind:"session.steer",step:1,message:"accepted"}}),compatibilityRequirements=overrides=>buildContractCompatibilityRequirementsV1({contractId:AGENT_CAPABILITY_CONTRACT_ID,version:1,mode:"full-control",features:[],transports:[],capabilities:[],...overrides}),compatibilityAccepted=checkContractCompatibilityV1(base.contract,compatibilityRequirements({features:["agent.run","session.snapshot"],transports:["in-process"],capabilities:[{id:"agent.run",version:1}]})),compatibilityContractUnsupported=checkContractCompatibilityV1(base.contract,compatibilityRequirements({version:2})),compatibilityCapabilityVersionUnsupported=checkContractCompatibilityV1(base.contract,compatibilityRequirements({capabilities:[{id:"agent.run",version:2}]})),compatibilityFeatureSubset=checkContractCompatibilityV1(base.contract,compatibilityRequirements({features:["agent.run","session.compact"]}));return detachedFreeze([{id:"agent-definition",value:base.definition},{id:"agent-instance",value:base.instance},{id:"session-snapshot",value:base.session},{id:"session-revision",value:base.revision},{id:"error-envelope",value:base.error},{id:"profile-snapshot",value:base.profile},{id:"artifact-reference",value:base.artifact},{id:"command-success",value:base.terminal},{id:"command-failed-terminal",value:failedTerminal},{id:"command-timed-out-terminal",value:timedOutTerminal},{id:"command-idempotency-replay",value:existing},{id:"command-idempotency-conflict",value:idempotencyConflict},{id:"command-revision-conflict",value:revisionConflict},{id:"command-cancel-terminal",value:cancelled},{id:"command-terminal-replay",value:terminalReplay},{id:"capability-unsupported",value:unsupported},{id:"event-without-operation",value:observation},{id:"event-with-operation",value:correlated},{id:"command-steer",value:steer},{id:"event-operation-step",value:operationStep},{id:"compatibility-accepted",value:compatibilityAccepted},{id:"compatibility-contract-unsupported",value:compatibilityContractUnsupported},{id:"compatibility-capability-version-unsupported",value:compatibilityCapabilityVersionUnsupported},{id:"compatibility-feature-subset",value:compatibilityFeatureSubset}])}function validateEventEnvelopeV1(value){if(assertPlainRecord(value,"Event envelope"),assertExactKeys(value,["version","id","deliveryId","type","source","category","deliveryGuarantee","timestamp","data"],["operationId","correlationId","causationId"],"Event envelope"),value.version!==1)throw new Error("Event envelope.version must be 1");if(assertNonEmptyString(value.id,"Event envelope.id"),assertNonEmptyString(value.deliveryId,"Event envelope.deliveryId"),assertNonEmptyString(value.type,"Event envelope.type"),assertNonEmptyString(value.source,"Event envelope.source"),value.category!=="authoritative"&&value.category!=="progress"&&value.category!=="observation")throw new Error("Event envelope.category is invalid");if(value.deliveryGuarantee!=="best-effort"&&value.deliveryGuarantee!=="at-least-once")throw new Error("Event envelope.deliveryGuarantee is invalid");if(assertNonNegativeSafeInteger(value.timestamp,"Event envelope.timestamp"),assertJsonValue(value.data,"Event envelope.data"),value.operationId!==void 0&&assertNonEmptyString(value.operationId,"Event envelope.operationId"),value.correlationId!==void 0&&assertNonEmptyString(value.correlationId,"Event envelope.correlationId"),value.causationId!==void 0&&assertNonEmptyString(value.causationId,"Event envelope.causationId"),value.operationId===void 0&&value.correlationId!==void 0)throw new Error("Event envelope.correlationId requires a real operationId");if(value.operationId!==void 0&&value.correlationId===void 0)throw new Error("Event envelope.operationId requires correlationId");return detachedFreeze({version:1,id:value.id,deliveryId:value.deliveryId,type:value.type,source:value.source,category:value.category,deliveryGuarantee:value.deliveryGuarantee,timestamp:value.timestamp,data:value.data,...value.operationId===void 0?{}:{operationId:value.operationId},...value.correlationId===void 0?{}:{correlationId:value.correlationId},...value.causationId===void 0?{}:{causationId:value.causationId}})}function buildEventEnvelopeV1(input){return validateEventEnvelopeV1({...input,version:input.version??1,category:input.category??"observation",deliveryGuarantee:input.deliveryGuarantee??"best-effort"})}function buildUnsupportedCapabilityV1(capability){let reference=validateCapabilityRefV1(capability),error=buildErrorEnvelopeV1({version:1,code:"unsupported_capability",message:`Capability is unsupported: ${reference.id}@${reference.version}`,retryable:!1});return detachedFreeze({status:"unsupported",capability:reference,error})}function resolveCapabilityV1(requested,supported){let reference=validateCapabilityRefV1(requested);return validateCapabilityRefs(supported,"Supported capabilities").some(candidate=>candidate.id===reference.id&&candidate.version===reference.version)?detachedFreeze({status:"supported",capability:reference}):buildUnsupportedCapabilityV1(reference)}function assertCapabilitySupportedV1(requested,supported){let resolution=resolveCapabilityV1(requested,supported);if(resolution.status==="unsupported")throw new Error(resolution.error.message);return resolution.capability}var validateAgentCapabilityContract=validateAgentCapabilityContractV1,buildAgentCapabilityContract=buildAgentCapabilityContractV1,validateEventEnvelope=validateEventEnvelopeV1,buildEventEnvelope=buildEventEnvelopeV1;function detachedFreeze2(value,seen=new WeakMap){if(value===null||typeof value!="object")return value;let existing=seen.get(value);if(existing!==void 0)return existing;if(Array.isArray(value)){let copy2=[];seen.set(value,copy2);for(let child of value)copy2.push(detachedFreeze2(child,seen));return Object.freeze(copy2)}let copy=Object.create(null);seen.set(value,copy);for(let[key,child]of Object.entries(value))copy[key]=detachedFreeze2(child,seen);return Object.freeze(copy)}function assertActive(disposed,label){if(disposed)throw new Error(`Embedded SDK binding is disposed: ${label}`)}function errorEnvelope(error,code){let message=error instanceof Error?error.message:String(error);return buildErrorEnvelopeV1({version:1,code,message,retryable:!1,...error instanceof Error?{name:error.name}:{}})}function agentDefinitionSnapshot(definition){return buildAgentDefinitionSnapshotV1({version:1,id:definition.id,definitionVersion:definition.version,role:definition.role,capabilities:[],...definition.owner===void 0?{}:{owner:definition.owner}})}function agentInstanceSnapshot(snapshot){return buildAgentInstanceSnapshotV1({version:1,id:snapshot.id,definitionId:snapshot.definitionId,definitionVersion:snapshot.definitionVersion,role:snapshot.role,status:snapshot.status,revision:snapshot.revision,...snapshot.parentInstanceId===void 0?{}:{parentInstanceId:snapshot.parentInstanceId},...snapshot.leaseOwner===void 0?{}:{leaseOwner:snapshot.leaseOwner}})}function resultSnapshot(result){return result.status==="succeeded"?detachedFreeze2({status:"succeeded",output:canonicalOutput(result.output,`wait:${result.revision}`),revision:result.revision}):detachedFreeze2({status:result.status,revision:result.revision,...result.error===void 0?{}:{error:errorEnvelope(result.error,`agent_${result.status}`)}})}function canonicalOutput(value,operationId){return buildOperationSnapshotV1({version:1,operationId,kind:"agent.run",status:"succeeded",terminal:{version:1,status:"succeeded",result:value}}),detachedFreeze2(value)}function canonicalInput(value){if(value===void 0)throw new Error("Embedded SDK run input must be JSON-compatible");return buildOperationSnapshotV1({version:1,operationId:"embedded-sdk:input",kind:"agent.run",status:"succeeded",terminal:{version:1,status:"succeeded",result:value}}),detachedFreeze2(value)}function createEmbeddedSessionBindingV1(session){if(!session.getRevision)throw new Error("Embedded SDK session requires revision support");let getRevision=()=>detachedFreeze2(session.getRevision()),context=session.getContextSnapshot&&session.commitContext?Object.freeze({version:1,get:()=>detachedFreeze2(session.getContextSnapshot()),commit:request=>session.commitContext(request)}):void 0;return Object.freeze({version:1,getSessionId:()=>session.getSessionId(),getRevision,snapshot:()=>buildSessionSnapshotV1({version:1,sessionId:session.getSessionId(),revision:getRevision()}),getMessages:()=>detachedFreeze2(session.getMessages()),getBranchEntries:()=>detachedFreeze2(session.getBranchEntries()),isIdle:()=>session.isIdle(),prompt:text=>session.prompt(text),steer:text=>session.steer?session.steer(text):Promise.reject(new Error("Embedded SDK session does not support steer")),abort:()=>session.abort(),waitForIdle:()=>session.waitForIdle(),...context===void 0?{}:{context}})}function createEmbeddedSdkBindingV1(options={}){let composition=options.composition??createAgentCompositionRuntime(),ownsComposition=options.ownsComposition??options.composition===void 0,defaultFeatures=["agent-composition-v1",...options.session===void 0?[]:["session","session-revision-v1","context"]],hostContext=detachedFreeze2({mode:options.mode??"full-control",features:[...options.features??defaultFeatures].sort(),transports:["in-process"]}),session=options.session===void 0?void 0:createEmbeddedSessionBindingV1(options.session),contract=buildAgentCapabilityContractV1({contractId:"agent-forge/agent-capability-contract",capabilities:[],hostContext}),definitions=new Map,instances=new Map,listeners=new Map,sequence=0,disposePromise,disposed=!1,nextId=kind=>(sequence+=1,options.idFactory?.(kind,sequence)??`embedded-sdk:${kind}:${sequence}`),emit=(type,data,operationId)=>{let event=buildEventEnvelopeV1({id:nextId("event"),deliveryId:nextId("delivery"),type,source:"embedded-sdk",timestamp:options.clock?.()??0,category:type===OPERATION_START_EVENT_ID||type===OPERATION_CANCEL_EVENT_ID||type===OPERATION_END_EVENT_ID?"authoritative":"observation",deliveryGuarantee:"best-effort",data,...operationId===void 0?{}:{operationId,correlationId:operationId}});for(let listener of listeners.values())try{listener(event)}catch{}},resolveDefinition=definition=>{let snapshot="snapshot"in definition?definition.snapshot:definition,definitionVersion="definitionVersion"in snapshot?snapshot.definitionVersion:snapshot.version,resolved=definitions.get(`${snapshot.id}@${definitionVersion}`);if(resolved)return resolved;if(options.composition!==void 0)return composition.get(snapshot.id,definitionVersion);throw new Error(`Embedded SDK has no defined Agent: ${snapshot.id}@${definitionVersion}`)},binding={version:1,contract,hostContext,...session===void 0?{}:{session},define(definition){assertActive(disposed,"define");let registered=composition.define(definition);return definitions.set(`${registered.id}@${registered.version}`,registered),detachedFreeze2({snapshot:agentDefinitionSnapshot(registered)})},create(definition,instanceOptions={}){assertActive(disposed,"create");let raw=composition.create(resolveDefinition(definition),instanceOptions),instanceDisposed=!1,instanceDisposePromise,leases=new WeakMap,wrapper={id:raw.id,snapshot:()=>(assertActive(disposed||instanceDisposed,raw.id),agentInstanceSnapshot(raw.snapshot())),acquireControllerLease:async owner=>{assertActive(disposed||instanceDisposed,raw.id);let lease=await raw.acquireControllerLease(owner),projected=Object.freeze({id:lease.id,instanceId:lease.instanceId,owner:lease.owner,revision:lease.revision,isActive:()=>!disposed&&!instanceDisposed&&lease.isActive(),release:async()=>{assertActive(disposed||instanceDisposed,raw.id),await lease.release()}});return leases.set(projected,lease),projected},run:(input,runOptions)=>{assertActive(disposed||instanceDisposed,raw.id);let lease=leases.get(runOptions.lease);if(!lease)throw new Error(`Embedded SDK lease does not belong to Agent instance: ${raw.id}`);let operation=raw.run(canonicalInput(input),{lease,signal:runOptions.signal}),terminal,cancelEmitted=!1,reportCancel=()=>{cancelEmitted||(cancelEmitted=!0,emit(OPERATION_CANCEL_EVENT_ID,validateOperationCancelEventDataV1({version:1,operationId:operation.id,operationKind:"agent.run"}),operation.id))};operation.signal.addEventListener("abort",reportCancel,{once:!0}),operation.signal.aborted&&reportCancel(),runOptions.signal?.aborted||emit(OPERATION_START_EVENT_ID,validateOperationStartEventDataV1({version:1,operationId:operation.id,operationKind:"agent.run"}),operation.id);let result=operation.result.then(value=>{try{let output=canonicalOutput(value,operation.id);return terminal={version:1,status:"succeeded",result:output},emit(OPERATION_END_EVENT_ID,validateOperationEndEventDataV1({version:1,operationId:operation.id,operationKind:"agent.run",status:"succeeded"}),operation.id),output}catch(error){throw terminal={version:1,status:"failed",error:errorEnvelope(error,"agent_invalid_result")},emit(OPERATION_END_EVENT_ID,validateOperationEndEventDataV1({version:1,operationId:operation.id,operationKind:"agent.run",status:"failed",errorMessage:error instanceof Error?error.message:String(error)}),operation.id),error}},error=>{let status=operation.status()==="cancelled"?"cancelled":"failed";throw terminal={version:1,status,error:errorEnvelope(error,`agent_${status}`)},emit(OPERATION_END_EVENT_ID,validateOperationEndEventDataV1({version:1,operationId:operation.id,operationKind:"agent.run",status,errorMessage:error instanceof Error?error.message:String(error)}),operation.id),error});return Object.freeze({id:operation.id,result,snapshot:()=>buildOperationSnapshotV1({version:1,operationId:operation.id,kind:"agent.run",status:terminal?.status??operation.status(),...terminal===void 0&&operation.status()==="cancelled"?{terminal:{version:1,status:"cancelled",error:errorEnvelope(new Error("Operation cancelled"),"agent_cancelled")}}:terminal===void 0?{}:{terminal},instanceId:raw.id}),cancel:async reason=>{assertActive(disposed||instanceDisposed,raw.id),!(operation.status()!=="queued"&&operation.status()!=="running")&&await operation.cancel(reason)}})},wait:async()=>detachedFreeze2(resultSnapshot(await raw.wait())),cancel:async reason=>{assertActive(disposed||instanceDisposed,raw.id),await raw.cancel(reason)},dispose:async()=>(instanceDisposePromise??=(async()=>{instanceDisposed||(instanceDisposed=!0,await raw.dispose(),instances.delete(raw.id))})(),instanceDisposePromise)};return instances.set(raw.id,wrapper),Object.freeze(wrapper)},listInstances:()=>Object.freeze([...instances.values()].map(instance=>instance.snapshot()).sort((left,right)=>left.id.localeCompare(right.id))),subscribe(listener){assertActive(disposed,"subscribe");let id=`embedded-sdk:subscription:${++sequence}`,released=!1;return listeners.set(id,listener),Object.freeze({id,dispose:()=>{released||(released=!0,listeners.delete(id))}})},dispose:async()=>(disposePromise??=(async()=>{if(disposed)return;disposed=!0;let failures=[];for(let instance of[...instances.values()])try{await instance.dispose()}catch(error){failures.push(error)}if(listeners.clear(),ownsComposition&&"disposeDefinitions"in composition)try{composition.disposeDefinitions([...definitions.values()])}catch(error){failures.push(error)}if(definitions.clear(),failures.length===1)throw failures[0];if(failures.length>1)throw new AggregateError(failures,"Embedded SDK disposal failed")})(),disposePromise)};return Object.freeze(binding)}var createEmbeddedSdkBinding=createEmbeddedSdkBindingV1;import{EventEmitter}from"node:events";function createEventBus(){let emitter=new EventEmitter;return{emit:(channel,data)=>{emitter.emit(channel,data)},on:(channel,handler)=>{let safeHandler=async data=>{try{await handler(data)}catch(err){console.error(`Event handler error (${channel}):`,err)}};return emitter.on(channel,safeHandler),()=>emitter.off(channel,safeHandler)},clear:()=>{emitter.removeAllListeners()}}}var ModelRegistry=class{runtime;constructor(runtime){this.runtime=runtime}refresh(options){return this.runtime.refresh(options)}getError(){return this.runtime.getError()}getAll(){return[...this.runtime.getModels()]}getAvailable(){return[...this.runtime.getAvailableSnapshot()]}find(provider,modelId){return this.runtime.getModel(provider,modelId)}hasConfiguredAuth(model){return this.runtime.hasConfiguredAuth(model.provider)}async getApiKeyAndHeaders(model){try{let resolution=await this.runtime.getAuth(model);if(!resolution){let compatibility=this.runtime.getCompatibilityRequestConfig(model);return compatibility.authHeader?{ok:!1,error:`No API key found for "${model.provider}"`}:{ok:!0,headers:compatibility.headers}}return{ok:!0,apiKey:resolution.auth.apiKey,headers:resolution.auth.headers,...resolution.auth.baseUrl?{baseUrl:resolution.auth.baseUrl}:{},env:resolution.env}}catch(error){let cause=error instanceof Error?error.cause:void 0,message=cause instanceof Error?cause.message:error instanceof Error?error.message:String(error);return{ok:!1,error:message==="authHeader requires a resolved API key"?`No API key found for "${model.provider}"`:message}}}getProviderAuthStatus(provider){return this.runtime.getProviderAuthStatus(provider)}getProvider(provider){return this.runtime.getProvider(provider)}stream(model,context,options){return this.runtime.stream(model,context,options)}complete(model,context,options){return this.runtime.complete(model,context,options)}streamSimple(model,context,options){return this.runtime.streamSimple(model,context,options)}getProviderDisplayName(provider){return this.runtime.getProvider(provider)?.name??provider}getProviderAuth(provider){return this.runtime.getAuth(provider)}async getApiKeyForProvider(provider){try{return(await this.runtime.getAuth(provider))?.auth.apiKey}catch{return}}isUsingOAuth(model){return this.runtime.isUsingOAuth(model.provider)}registerProvider(providerOrName,config){if(typeof providerOrName=="string"){if(!config)throw new Error("Provider config is required when registering by name");this.runtime.registerProvider(providerOrName,config);return}this.runtime.registerNativeProvider(providerOrName)}unregisterProvider(providerName){this.runtime.unregisterProvider(providerName)}getRegisteredProviderConfig(providerName){return this.runtime.getRegisteredProviderConfig(providerName)}getRegisteredNativeProvider(providerName){return this.runtime.getRegisteredNativeProvider(providerName)}getRegisteredProviderIds(){return this.runtime.getRegisteredProviderIds()}};function retryBackoffMs(policy,attempt){return Math.min(policy.baseWaitMs*2**(attempt-1),policy.maxWaitMs)}function createAgentRetryScheduler(){let terminalStates=new Map;return{schedule(input){let existing=terminalStates.get(input.operationId);if(existing)return{...existing,duplicate:!0};let signal=input.signal,now=input.now??(()=>0),sleep=input.sleep??(()=>{}),attempts=[],finish=outcome=>(terminalStates.set(input.operationId,outcome),outcome);for(let attempt=1;attempt<=input.policy.attemptLimit;attempt+=1){if(signal?.aborted)return finish({status:"cancelled",operationId:input.operationId,attempts});let at=now(),step=input.task(attempt);if(step.ok)return attempts.push({attempt,at,ok:!0,waitedMs:0}),finish({status:"succeeded",operationId:input.operationId,result:step.result,attempts});if(!step.retryable)return attempts.push({attempt,at,ok:!1,failure:step.reason,retryable:!1,waitedMs:0}),finish({status:"failed_terminal",operationId:input.operationId,reason:step.reason,attempts});let waitedMs=retryBackoffMs(input.policy,attempt);if(attempts.push({attempt,at,ok:!1,failure:step.reason,retryable:!0,waitedMs}),attempt<input.policy.attemptLimit&&(sleep(waitedMs),signal?.aborted))return finish({status:"cancelled",operationId:input.operationId,attempts})}return finish({status:"exhausted",operationId:input.operationId,attempts})},terminalOf(operationId){return terminalStates.get(operationId)}}}function createAutoCompactionExecutor(options){let coordinator=options.coordinator,policy=options.policy,inProgress=!1;return{get inProgress(){return inProgress},maybeCompact(input){if(!policy.enabled)return{status:"disabled"};if(inProgress)return{status:"busy"};if(input.currentTokens<policy.tokenThreshold)return{status:"below_threshold",currentTokens:input.currentTokens,threshold:policy.tokenThreshold};inProgress=!0;try{let staged=coordinator.stage({operationId:input.operationId,expectedRevision:coordinator.currentRevision,payload:null});if(staged.status==="stale")return{status:"stale",currentRevision:staged.currentRevision};if(staged.status==="duplicate")return{status:"cancelled"};if(input.signal?.aborted)return coordinator.cancelStage(staged.staged.token),{status:"cancelled"};let summary;try{summary=input.summarize(input.signal)}catch(error){return coordinator.cancelStage(staged.staged.token),{status:"summary_failed",reason:error instanceof Error?error.message:String(error)}}if(input.signal?.aborted)return coordinator.cancelStage(staged.staged.token),{status:"cancelled"};let outcome=coordinator.commitStage({token:staged.staged.token,apply:()=>{}});return outcome.status==="stale"?{status:"stale",currentRevision:outcome.currentRevision}:outcome.status==="committed"?{status:"completed",revision:outcome.revision,summary}:(coordinator.cancelStage(staged.staged.token),{status:"cancelled"})}finally{inProgress=!1}}}}function createBranchStateMigration(){return{migrate({entries,fromBranch,toBranch}){let source=entries.filter(entry=>entry.branch===fromBranch);return source.length===0?{status:"empty_source",fromBranch}:{status:"migrated",fromBranch,toBranch,migrated:Object.freeze(source.map(entry=>({key:entry.key,value:entry.value})))}},scan(entries,branch){return Object.freeze(entries.filter(entry=>entry.branch===branch))}}}function createReloadTransaction(){return{reload(items){let failures=[];for(let[index,item]of items.entries()){let failure=item.validate();failure!==null&&failures.push({index,reason:failure})}if(failures.length>0)return{status:"rolled_back",failures:Object.freeze(failures)};for(let item of items)item.commit();return{status:"committed",count:items.length}}}}function createHostCheckpointCoordinator(options={}){let revision=options.startRevision??0,staged=new Map,committed=new Map,tokenSequence=0;return{get currentRevision(){return revision},stage(input){if(typeof input.operationId!="string"||input.operationId.trim().length===0)throw new Error("Checkpoint operationId must be a non-empty string");let appliedRevision=committed.get(input.operationId);if(appliedRevision!==void 0)return{status:"duplicate",revision:appliedRevision};if(input.expectedRevision!==revision)return{status:"stale",currentRevision:revision};tokenSequence+=1;let token=`ckpt-${tokenSequence}`,entry={operationId:input.operationId,expectedRevision:input.expectedRevision,payload:input.payload,state:"staged"};return staged.set(token,entry),{status:"staged",staged:{token,operationId:input.operationId,expectedRevision:input.expectedRevision,currentRevision:revision}}},commitStage({token,apply}){let entry=staged.get(token);if(!entry)return{status:"unknown_token"};if(entry.state==="cancelled")return{status:"cancelled"};if(entry.expectedRevision!==revision)return staged.delete(token),{status:"stale",currentRevision:revision};try{apply(entry.payload,revision+1)}catch(error){return staged.delete(token),{status:"write_failed",reason:error instanceof Error?error.message:String(error)}}return revision+=1,committed.set(entry.operationId,revision),staged.delete(token),{status:"committed",revision}},cancelStage(token){let entry=staged.get(token);return entry?committed.has(entry.operationId)?{status:"already_committed"}:(entry.state="cancelled",{status:"cancelled"}):{status:"unknown_token"}},committedOperationIds(){return Object.freeze([...committed.keys()].sort())}}}function createManualCompactionExecutor(options){let coordinator=options.coordinator,state="idle",currentOperationId;return{get state(){return state},requestCompaction(input){if(state==="in_progress")return{status:"busy",currentOperationId:currentOperationId??"unknown"};if(input.pluginId.trim().length===0)throw new Error("Compaction pluginId must be a non-empty string");state="in_progress",currentOperationId=input.operationId;try{let staged=coordinator.stage({operationId:input.operationId,expectedRevision:coordinator.currentRevision,payload:null});if(staged.status==="stale")return{status:"stale",currentRevision:staged.currentRevision};if(staged.status==="duplicate")return{status:"completed",revision:staged.revision,summary:{duplicate:!0}};let summary;try{summary=input.summarize()}catch(error){return coordinator.cancelStage(staged.staged.token),{status:"summary_failed",reason:error instanceof Error?error.message:String(error)}}let outcome=coordinator.commitStage({token:staged.staged.token,apply:(payload,revision)=>{}});return outcome.status==="stale"?{status:"stale",currentRevision:outcome.currentRevision}:outcome.status==="committed"?{status:"completed",revision:outcome.revision,summary}:{status:"summary_failed",reason:`Unexpected checkpoint outcome: ${outcome.status}`}}finally{state="idle",currentOperationId=void 0}}}}function createOutputReducer(){return{fold(records){let groups=[],pendingTool=null,flushTool=()=>{pendingTool&&(groups.push(pendingTool),pendingTool=null)};for(let record of records){if(record.channel==="tool"&&record.correlationId!==void 0){let isCall=record.severity==="info"&&record.summary.endsWith("called");pendingTool&&pendingTool.correlationId!==record.correlationId&&flushTool(),pendingTool||(pendingTool={kind:"tool",toolName:record.code??record.summary,correlationId:record.correlationId,detailsRef:`trace:${record.traceId}#call:${record.correlationId}`,calls:0,ok:0,failed:0,records:[]}),pendingTool.records.push(record),isCall?pendingTool.calls+=1:record.severity==="ok"?pendingTool.ok+=1:record.severity==="error"&&(pendingTool.failed+=1);continue}flushTool();let last=groups.at(-1);last?.kind==="records"?(last.records.push(record),last.detailsRef=`trace:${record.traceId}#records:${last.records.length}`):groups.push({kind:"records",detailsRef:`trace:${record.traceId}#records:1`,records:[record]})}flushTool();let foldedToolGroups=0,frozenGroups=groups.map(group=>{let base={...group,records:Object.freeze([...group.records])};if(base.kind==="tool"){foldedToolGroups+=1;let firstAt=base.records[0]?.at??0,lastAt=base.records.at(-1)?.at??firstAt;return Object.freeze({...base,durationMs:Math.max(lastAt-firstAt,0)})}return Object.freeze(base)});return{groups:Object.freeze(frozenGroups),totalRecords:records.length,foldedToolGroups}},unfold(folded){return Object.freeze(folded.groups.flatMap(group=>[...group.records]))}}}var INTERNAL_FIELD_KEYS=["memoryId","memoryIds","score","scores","ranking","queryPlan","budget","budgets","agentRole","pluginRole","lease","leaseId","purgeState","rawSources"];function isArtifactLike(value){return typeof value=="object"&&value!==null&&"artifactId"in value&&"sessionId"in value&&"kind"in value}function toArtifactRef(value){if(!(typeof value.sessionId!="string"||typeof value.operationId!="string"||typeof value.artifactId!="string"||typeof value.kind!="string"||typeof value.mediaType!="string"||typeof value.truncated!="boolean"||typeof value.createdAt!="number"))return{sessionId:value.sessionId,operationId:value.operationId,artifactId:value.artifactId,kind:value.kind,mediaType:value.mediaType,...typeof value.sizeBytes=="number"?{sizeBytes:value.sizeBytes}:{},truncated:value.truncated,createdAt:value.createdAt}}function createHostOutputSerializer(){return{project(input,context){if(context.policyVersion.trim().length===0)return{text:"",diagnostics:["output_projection_rejected: policyVersion must be a non-empty string"],rejected:{code:"output_projection_rejected",reason:"policyVersion must be a non-empty string"}};let redactions=[],diagnostics=[],artifacts=[],showInternal=context.surface==="inspector"&&context.inspectorAuthorized,isAllowedKey=key=>!INTERNAL_FIELD_KEYS.includes(key)||showInternal,renderValue=(key,value,path)=>{if(!isAllowedKey(key))return redactions.push(`${path}.${key}`),`[redacted:${key}]`;if(isArtifactLike(value)){let ref=toArtifactRef(value);return ref?(artifacts.push(ref),`[artifact:${ref.artifactId}]`):(diagnostics.push(`output_projection_rejected: ${path}.${key} is a malformed artifact reference`),`[unrenderable:${key}]`)}return typeof value=="string"?value:typeof value=="number"||typeof value=="boolean"?String(value):value===null?"null":Array.isArray(value)?`[${value.map(item=>renderValue(key,item,path)).join(", ")}]`:typeof value=="object"?`{${Object.entries(value).map(([nestedKey,nestedValue])=>`${nestedKey}:${renderValue(nestedKey,nestedValue,`${path}.${key}`)}`).join(", ")}}`:(diagnostics.push(`output_projection_rejected: ${path}.${key} cannot be serialized`),`[unrenderable:${key}]`)},textParts=[];for(let[key,value]of Object.entries(input)){if(key==="artifacts"&&Array.isArray(value)){for(let entry of value)if(isArtifactLike(entry)){let ref=toArtifactRef(entry);ref?artifacts.push(ref):diagnostics.push("output_projection_rejected: artifacts entry is malformed")}else diagnostics.push("output_projection_rejected: artifacts entry is malformed");continue}textParts.push(`${key}=${renderValue(key,value,"root")}`)}return{text:textParts.join(`
|
|
2
|
+
import{AgentCompositionRuntime,AgentSession,AgentSessionRuntime,ArminComponent,AssistantMessageComponent,BOOTSTRAP_COMPACTION_PLUGIN_ID,BOOTSTRAP_LIFECYCLE_PLUGIN_ID,BOOTSTRAP_RETRY_PLUGIN_ID,BOOTSTRAP_TOOLS_PLUGIN_ID,BashExecutionComponent,BranchSummaryMessageComponent,CAPABILITY_CALL_EVENT_ID,CAPABILITY_CALL_EVENT_VERSION,CONFIG_DIR_NAME,CURRENT_SESSION_VERSION,CancellableLoader,CodingAgentServerService,CodingAgentSessionRuntime,CompactionSummaryMessageComponent,Container,CredentialSynchronizationError,CustomEditor,CustomMessageComponent,DEFAULT_COMPACTION_POLICY_NAME,DEFAULT_COMPACTION_SETTINGS,DEFAULT_MAX_BYTES,DEFAULT_MAX_LINES,DEFAULT_RETRY_POLICY_NAME,DEFAULT_SUITE_ID,DefaultPackageManager,DefaultResourceLoader,DialogEditorComponent,DialogInputComponent,DialogSelectorComponent,DurableServiceErrorV1,DynamicBorder,EXPERIMENTAL_PUBLIC_API_VERSION,FileSessionStorageProvider,FooterComponent,InteractiveMode,LifecycleExecuteError,LifecycleTransformError,Loader,LoginDialogComponent,MEMORY_RECALL_TOOL_NAME,MODEL_RESPONSE_EVENT_ID,MODEL_RESPONSE_EVENT_VERSION,MODEL_STREAM_EVENT_ID,MODEL_STREAM_EVENT_VERSION,ModelRuntime,ModelSelectorComponent,OAuthSelectorComponent,OPERATION_CANCEL_EVENT_ID,OPERATION_CANCEL_EVENT_VERSION,OPERATION_END_EVENT_ID,OPERATION_END_EVENT_VERSION,OPERATION_START_EVENT_ID,OPERATION_START_EVENT_VERSION,OPERATION_STEP_EVENT_ID,OPERATION_STEP_EVENT_VERSION,PLUGIN_DISPOSE_EVENT_ID,PLUGIN_DISPOSE_EVENT_VERSION,PLUGIN_READY_EVENT_ID,PLUGIN_READY_EVENT_VERSION,PluginManagerEntryComponent,RpcClient,SESSION_COMPACTION_COMMIT_EVENT_ID,SESSION_COMPACTION_COMMIT_EVENT_VERSION,SESSION_CONTEXT_REPLACED_EVENT_ID,SESSION_CONTEXT_REPLACED_EVENT_VERSION,SESSION_RELOAD_EVENT_ID,SESSION_RELOAD_EVENT_VERSION,SUITE_DELETE_CONFIRM_TOKEN,SUMMARY_MODEL_INVOCATION_ERROR_CODES,SelectList,SessionHeaderScanLimitError,SessionManager,SessionSelectorComponent,SettingsManager,SettingsSelectorComponent,SkillInvocationMessageComponent,Spacer,SuiteLifecycleError,SuiteResolutionError,TOOL_CALL_EVENT_ID,TOOL_CALL_EVENT_VERSION,TOOL_COMMIT_EVENT_ID,TOOL_COMMIT_EVENT_VERSION,TOOL_EXECUTE_EVENT_ID,TOOL_EXECUTE_EVENT_VERSION,TOOL_RESULT_EVENT_ID,TOOL_RESULT_EVENT_VERSION,TOOL_RESULT_RAW_EVENT_ID,TOOL_RESULT_RAW_EVENT_VERSION,TOOL_RESULT_TRANSFORM_EVENT_ID,TOOL_RESULT_TRANSFORM_EVENT_VERSION,Text,Theme,ThinkingSelectorComponent,ToolExecutionComponent,TreeSelectorComponent,UserMessageComponent,UserMessageSelectorComponent,VERSION,assembleCodingAgentServer,assembleProfile,buildContextEntries,buildProfileIdentityV1,buildResolvedAgentProfileV1,buildSessionContext,calculateContextTokens,clearDanglingSuiteSettings,collectEntriesForBranchSummary,compact,convertToLlm,convertToPng,copyToClipboard,createAgentCompositionRuntime,createAgentSession,createAgentSessionFromServices,createAgentSessionRuntime,createAgentSessionServices,createBashTool,createBashToolDefinition,createCapabilityRuntime,createCodingTools,createDisposableRegistration,createDurableService,createEditTool,createEditToolDefinition,createEventEnvelope,createFileDurableStoreBackend,createFileSessionSource,createFindTool,createFindToolDefinition,createGrepTool,createGrepToolDefinition,createHostOutputProjector,createLocalBashOperations,createLocalPowerShellOperations,createLsTool,createLsToolDefinition,createPowerShellTool,createPowerShellToolDefinition,createProfileLock,createProfileMigrationPolicy,createProfileRegistry,createReadOnlyTools,createReadTool,createReadToolDefinition,createStableAgentSession,createStableAgentSessionRuntime,createStdioChannelAdapter,createSuite,createSyntheticSourceInfo,createWriteTool,createWriteToolDefinition,defineTool,deleteSuite,detachedSessionSnapshot,detectSupportedImageMimeTypeFromFile,discoverCapabilityPluginManifests,dist_exports,durableLogPath,ecosystem_exports,estimateTokens,findCutPoint,findSuiteSessionRefs,findTurnStartIndex,formatDimensionNote,formatSize,formatSkillsForPrompt,generateBranchSummary,generateDiffString,generateSummary,generateSummaryWithUsage,generateUnifiedPatch,getAgentDir,getAvailableThemes,getDocsPath,getExamplesPath,getLanguageFromPath,getLastAssistantUsage,getLatestCompactionEntry,getMarkdownTheme,getPackageDir,getPowerShellConfig,getReadmePath,getSelectListTheme,getSessionsDir,getSettingsListTheme,getShellConfig,highlightCode,initTheme,installBootstrapCompactionPolicy,installBootstrapLifecycle,installBootstrapRetryPolicy,installBootstrapTools,installSessionBootstrapTools,isBuiltinSuiteId,keyHint,keyText,killProcessTree,listBuiltinPluginManifestsV1,listBuiltinPluginProfilesV1,listSuiteIds,loadCapabilityPlugin,loadCapabilityPluginFromManifest,loadCapabilityPluginSync,loadProjectContextFiles,loadSkills,loadSkillsFromDir,main,migrateSessionEntries,parseArgs,parseCapabilityPluginManifest,parseFrontmatter,parseSessionEntries,parseSkillBlock,plugin_manager_controller_exports,plugin_selection_controller_exports,prepareBranchEntries,profileIdentitiesCompatible,projectSessionTranscript,rawKeyHint,readStoredCredential,renderDiff,replaceProfileLock,replaceProfilePlugin,resetSuite,resizeImage,resolveBuiltinPluginProfileV1,resolveCliModel,resolveModelScopeWithDiagnostics,resolvePluginCapabilityOrder,runPrintMode,runRpcMode,sanitizeBinaryOutput,serializeConversation,sessionEntryToContextMessages,shouldCompact,stableJsonDigest,startCodingAgentRemoteServer,stripFrontmatter,truncateHead,truncateLine,truncateTail,truncateToVisualLines,validateCapabilityCallEventDataV1,validateExecutionFactsV1,validateModelResponseEventDataV1,validateModelStreamEventDataV1,validateOperationCancelEventDataV1,validateOperationEndEventDataV1,validateOperationStartEventDataV1,validateOperationStepEventDataV1,validatePluginDisposeEventDataV1,validatePluginReadyEventDataV1,validateRetryScheduleV1,validateSessionCompactionCommitEventDataV1,validateSessionContextReplacedEventDataV1,validateSessionReloadEventDataV1,validateToolCallEventDataV1,validateToolCommitEventDataV1,validateToolExecuteEventDataV1,validateToolResultEventDataV1,validateToolResultRawEventDataV1,validateToolResultTransformEventDataV1,verifyProfileLock,withFileMutationQueue}from"./chunks/chunk-2L25YYPC.js";import"./chunks/chunk-JUUC5AZY.js";import"./chunks/chunk-XDUWOHPL.js";import"./chunks/chunk-3QKHSPQL.js";import"./chunks/chunk-DRQDKNXA.js";import"./chunks/chunk-7ZY7IXZD.js";import"./chunks/chunk-V46XUTK3.js";import"./chunks/chunk-WGLBM2BP.js";import"./chunks/chunk-4L3WN2XY.js";function contentHash(bytes){let hash=2166136261;for(let byte of bytes)hash^=byte,hash=Math.imul(hash,16777619);return(hash>>>0).toString(36)}function toStat(entry){return{artifactId:entry.ref.artifactId,sessionId:entry.ref.sessionId,operationId:entry.ref.operationId,kind:entry.ref.kind,mediaType:entry.ref.mediaType,sizeBytes:entry.ref.sizeBytes,state:entry.ended?"ended":"available",...entry.ended?{endReason:entry.endReason}:{}}}function createArtifactStore(options={}){let now=options.now??(()=>Date.now()),artifacts=new Map,sequenceByIdentity=new Map,globalWriteSequence=0;return{write(input){if(input.bytes.length===0)throw new Error("Artifact bytes must not be empty");let identity=`${input.sessionId}\0${input.operationId}`,sequence=(sequenceByIdentity.get(identity)??0)+1;sequenceByIdentity.set(identity,sequence),globalWriteSequence+=1;let artifactId=`art-${contentHash(input.bytes)}-${sequence}-${globalWriteSequence}`,ref={artifactId,sessionId:input.sessionId,operationId:input.operationId,kind:input.kind,mediaType:input.mediaType,sizeBytes:input.bytes.length,truncated:!1,createdAt:now()};return artifacts.set(artifactId,{ref,bytes:input.bytes,ended:!1}),{ref}},read(input){let entry=artifacts.get(input.artifactId);if(!entry)throw new Error(`Artifact not found: ${input.artifactId}`);if(entry.ref.sessionId!==input.sessionId)throw new Error(`Artifact ${input.artifactId} belongs to a different session`);if(entry.ended)throw new Error(`Artifact ${input.artifactId} lifecycle has ended: ${entry.endReason??"ended"}`);return{mediaType:entry.ref.mediaType,bytes:entry.bytes}},stat(artifactId){let entry=artifacts.get(artifactId);return entry===void 0?void 0:toStat(entry)},list(sessionId){return[...artifacts.values()].filter(entry=>entry.ref.sessionId===sessionId).map(entry=>toStat(entry))},endLifecycle(artifactId,input){let entry=artifacts.get(artifactId);if(!entry)throw new Error(`Artifact not found: ${artifactId}`);if(entry.ended)throw new Error(`Artifact ${artifactId} lifecycle has already ended`);return entry.ended=!0,entry.endReason=input.reason,entry.bytes=new Uint8Array(0),toStat(entry)}}}function planArtifactPages(store,input){if(!Number.isSafeInteger(input.pageSize)||input.pageSize<1)return{status:"invalid_page_size",pageSize:input.pageSize};let stat=store.stat(input.artifactId);if(!stat)return{status:"unavailable",reason:`Artifact not found: ${input.artifactId}`};if(stat.state==="ended")return{status:"unavailable",reason:`Artifact ${input.artifactId} lifecycle has ended: ${stat.endReason??"ended"}`};let totalBytes=stat.sizeBytes??0,pages=[];for(let offset=0;offset<totalBytes;offset+=input.pageSize)pages.push({index:pages.length,offset,size:Math.min(input.pageSize,totalBytes-offset)});return{status:"planned",totalBytes,pageSize:input.pageSize,pages:Object.freeze(pages)}}function readArtifactPage(store,input){if(!Number.isSafeInteger(input.pageSize)||input.pageSize<1)return{status:"unavailable",reason:`Invalid page size: ${input.pageSize}`};let plan=planArtifactPages(store,{artifactId:input.artifactId,pageSize:input.pageSize});if(plan.status!=="planned")return{status:"unavailable",reason:plan.status==="unavailable"?plan.reason:`Invalid page size: ${plan.pageSize}`};let page=plan.pages[input.index];if(!page)return{status:"unavailable",reason:`Page ${input.index} is outside the plan (${plan.pages.length} pages)`};let bytes;try{bytes=store.read({artifactId:input.artifactId,sessionId:input.sessionId}).bytes}catch(error){return{status:"unavailable",reason:error instanceof Error?error.message:String(error)}}let slice=bytes.slice(page.offset,page.offset+page.size),nextOffset=page.offset+page.size,hasMore=nextOffset<plan.totalBytes;return{status:"ok",index:page.index,offset:page.offset,bytes:slice,hasMore,...hasMore?{nextOffset}:{}}}var AGENT_CAPABILITY_CONTRACT_ID="agent-forge/agent-capability-contract",AGENT_CAPABILITY_CONTRACT_VERSION=1,AGENT_ERROR_CODES_V1=["provider_error","operation_timeout","operation_cancelled","idempotency_conflict","revision_conflict","revision_unavailable","unsupported_capability","invalid_request","invalid_ref","not_found","cancelled","unsupported","busy","session_locked","unauthorized","not_implemented","internal_error"],agentErrorCodeSet=new Set(AGENT_ERROR_CODES_V1);function isRegisteredAgentErrorCodeV1(code){return agentErrorCodeSet.has(code)}var PROTOCOL_ERROR_CODE_TO_AGENT_CODE_V1=Object.freeze({version:"unsupported",busy:"busy",session_locked:"session_locked",not_found:"not_found",invalid_request:"invalid_request",unauthorized:"unauthorized",not_implemented:"not_implemented",internal_error:"internal_error"});function mapProtocolErrorCodeToAgentErrorV1(code){return PROTOCOL_ERROR_CODE_TO_AGENT_CODE_V1[code]}function toErrorEnvelopeV1(error){let message=error instanceof Error?error.message:String(error),name=error instanceof Error?error.name:void 0,code;if(error&&typeof error=="object"&&"code"in error){let raw=error.code;typeof raw=="string"&&raw.trim()!==""&&(code=raw)}code===void 0&&(code="internal_error");let mapped=PROTOCOL_ERROR_CODE_TO_AGENT_CODE_V1[code];return buildErrorEnvelopeV1({version:1,code:mapped??code,message,retryable:!1,...name===void 0?{}:{name}})}function isPlainRecord(value){if(value===null||typeof value!="object"||Array.isArray(value))return!1;let prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}function assertPlainRecord(value,label){if(!isPlainRecord(value))throw new Error(`${label} must be a plain object`)}function assertExactKeys(value,required,optional,label){let allowed=new Set([...required,...optional]),unsupported=Object.keys(value).filter(key=>!allowed.has(key)).sort();if(unsupported.length>0)throw new Error(`${label} has unsupported fields: ${unsupported.join(", ")}`);for(let key of required)if(!(key in value))throw new Error(`${label} is missing required field: ${key}`)}function assertNonEmptyString(value,label){if(typeof value!="string"||value.trim().length===0)throw new Error(`${label} must be a non-empty string`)}function assertPositiveSafeInteger(value,label){if(typeof value!="number"||!Number.isSafeInteger(value)||value<1)throw new Error(`${label} must be a positive safe integer`)}function assertNonNegativeSafeInteger(value,label){if(typeof value!="number"||!Number.isSafeInteger(value)||value<0)throw new Error(`${label} must be a non-negative safe integer`)}function assertJsonValue(value,label,seen=new WeakSet){if(!(value===null||typeof value=="boolean"||typeof value=="string")){if(typeof value=="number"){if(Number.isFinite(value))return;throw new Error(`${label} must contain finite JSON numbers`)}if(typeof value!="object")throw new Error(`${label} must be JSON-compatible`);if(seen.has(value))throw new Error(`${label} must not contain cycles`);if(seen.add(value),Array.isArray(value))for(let[index,child]of value.entries())assertJsonValue(child,`${label}[${index}]`,seen);else{if(!isPlainRecord(value))throw new Error(`${label} must contain only plain JSON objects`);for(let[key,child]of Object.entries(value))assertJsonValue(child,`${label}.${key}`,seen)}seen.delete(value)}}function detachedFreeze(value,seen=new WeakMap){if(value===null||typeof value!="object")return value;let existing=seen.get(value);if(existing!==void 0)return existing;if(Array.isArray(value)){let result2=[];seen.set(value,result2);for(let child of value)result2.push(detachedFreeze(child,seen));return Object.freeze(result2)}let result={};seen.set(value,result);for(let[key,child]of Object.entries(value))result[key]=detachedFreeze(child,seen);return Object.freeze(result)}function capabilitySort(left,right){return left.id<right.id?-1:left.id>right.id?1:left.version-right.version}function validateCapabilityRefs(value,label){if(!Array.isArray(value))throw new Error(`${label} must be an array`);let refs=value.map((item,index)=>validateCapabilityRefV1(item,`${label}[${index}]`)),seen=new Set;for(let ref of refs){let key=`${ref.id}\0${ref.version}`;if(seen.has(key))throw new Error(`${label} contains duplicate capability: ${ref.id}@${ref.version}`);seen.add(key)}return Object.freeze(refs.sort(capabilitySort))}function validateHostTransport(value,label){if(value!=="in-process"&&value!=="stdio"&&value!=="http"&&value!=="rpc"&&value!=="unix"&&value!=="websocket")throw new Error(`${label} is invalid`)}function validateCapabilityRefV1(value,label="Capability reference"){return assertPlainRecord(value,label),assertExactKeys(value,["id","version"],[],label),assertNonEmptyString(value.id,`${label}.id`),assertPositiveSafeInteger(value.version,`${label}.version`),detachedFreeze({id:value.id,version:value.version})}function validateHostContextV1(value){if(assertPlainRecord(value,"Host context"),assertExactKeys(value,["mode","features","transports"],[],"Host context"),value.mode!=="readonly"&&value.mode!=="full-control")throw new Error("Host context.mode is invalid");if(!Array.isArray(value.features))throw new Error("Host context.features must be an array");let features=value.features.map((feature,index)=>(assertNonEmptyString(feature,`Host context.features[${index}]`),feature));if(new Set(features).size!==features.length)throw new Error("Host context.features must not contain duplicates");if(!Array.isArray(value.transports))throw new Error("Host context.transports must be an array");let transports=value.transports.map((transport,index)=>(validateHostTransport(transport,`Host context.transports[${index}]`),transport));if(new Set(transports).size!==transports.length)throw new Error("Host context.transports must not contain duplicates");return detachedFreeze({mode:value.mode,features:[...features].sort(),transports:[...transports].sort()})}function buildHostContextV1(input){return validateHostContextV1(input)}function validateContractCompatibilityRequirementsV1(value){assertPlainRecord(value,"Contract compatibility requirements"),assertExactKeys(value,["contractId","version","mode","features","transports","capabilities"],[],"Contract compatibility requirements"),assertNonEmptyString(value.contractId,"Contract compatibility requirements.contractId"),assertPositiveSafeInteger(value.version,"Contract compatibility requirements.version");let hostContext=validateHostContextV1({mode:value.mode,features:value.features,transports:value.transports}),capabilities=validateCapabilityRefs(value.capabilities,"Contract compatibility requirements.capabilities");return detachedFreeze({contractId:value.contractId,version:value.version,mode:hostContext.mode,features:hostContext.features,transports:hostContext.transports,capabilities})}function buildContractCompatibilityRequirementsV1(input){return validateContractCompatibilityRequirementsV1(input)}var CONTRACT_COMPATIBILITY_ISSUE_CODES_V1=["unsupported_contract","host_mode_mismatch","unsupported_feature","unsupported_transport","unsupported_capability"];function validateContractCompatibilityResultV1(value){if(assertPlainRecord(value,"Contract compatibility result"),assertExactKeys(value,["version","compatible","issues"],[],"Contract compatibility result"),value.version!==1)throw new Error("Contract compatibility result.version must be 1");if(typeof value.compatible!="boolean")throw new Error("Contract compatibility result.compatible must be boolean");if(!Array.isArray(value.issues))throw new Error("Contract compatibility result.issues must be an array");if(value.compatible&&value.issues.length>0)throw new Error("Contract compatibility result.compatible must be false when issues exist");if(!value.compatible&&value.issues.length===0)throw new Error("Contract compatibility result.compatible must be true when no issues exist");let issues=value.issues.map((entry,index)=>{if(assertPlainRecord(entry,`Contract compatibility result.issues[${index}]`),assertExactKeys(entry,["code","error"],["missingFeatures","missingTransports","missingCapabilities"],`Contract compatibility result.issues[${index}]`),!CONTRACT_COMPATIBILITY_ISSUE_CODES_V1.includes(entry.code))throw new Error(`Contract compatibility result.issues[${index}].code is invalid`);let error=validateErrorEnvelopeV1(entry.error),missingFeatures=entry.missingFeatures;if(missingFeatures!==void 0&&(!Array.isArray(missingFeatures)||missingFeatures.some(item=>typeof item!="string")))throw new Error(`Contract compatibility result.issues[${index}].missingFeatures must be strings`);let missingTransports=entry.missingTransports;if(missingTransports!==void 0&&(!Array.isArray(missingTransports)||missingTransports.some(item=>typeof item!="string")))throw new Error(`Contract compatibility result.issues[${index}].missingTransports must be strings`);let missingCapabilities=entry.missingCapabilities;missingCapabilities!==void 0&&validateCapabilityRefs(missingCapabilities,`Contract compatibility result.issues[${index}].missingCapabilities`);let issue={code:entry.code,error,...missingFeatures===void 0?{}:{missingFeatures:Object.freeze(missingFeatures.map(item=>item))},...missingTransports===void 0?{}:{missingTransports:Object.freeze(missingTransports.map(item=>item))},...missingCapabilities===void 0?{}:{missingCapabilities:validateCapabilityRefs(missingCapabilities,"missingCapabilities")}};return detachedFreeze(issue)});return detachedFreeze({version:1,compatible:value.compatible,issues:Object.freeze(issues)})}function validateAgentCapabilityContractV1(value){if(assertPlainRecord(value,"Agent capability contract"),assertExactKeys(value,["contractId","version","capabilities","hostContext"],[],"Agent capability contract"),value.contractId!==AGENT_CAPABILITY_CONTRACT_ID)throw new Error(`Agent capability contract.contractId must be ${AGENT_CAPABILITY_CONTRACT_ID}`);if(value.version!==1)throw new Error("Agent capability contract.version must be 1");let capabilities=validateCapabilityRefs(value.capabilities,"Agent capability contract.capabilities"),hostContext=validateHostContextV1(value.hostContext);return detachedFreeze({contractId:value.contractId,version:1,capabilities,hostContext})}function buildAgentCapabilityContractV1(input){return validateAgentCapabilityContractV1({...input,version:input.version??1})}function validateAgentProfileV1(value){assertPlainRecord(value,"Agent profile"),assertExactKeys(value,["id","version","rootAgent","requiredPlugins"],["optionalPlugins","defaults"],"Agent profile"),assertNonEmptyString(value.id,"Agent profile.id"),assertPositiveSafeInteger(value.version,"Agent profile.version"),assertNonEmptyString(value.rootAgent,"Agent profile.rootAgent");let validatePluginIds=(candidate,label)=>{if(!Array.isArray(candidate))throw new Error(`${label} must be an array`);let ids=candidate.map((id,index)=>(assertNonEmptyString(id,`${label}[${index}]`),id));if(new Set(ids).size!==ids.length)throw new Error(`${label} must not contain duplicates`);return Object.freeze([...ids].sort())},requiredPlugins=validatePluginIds(value.requiredPlugins,"Agent profile.requiredPlugins"),optionalPlugins=value.optionalPlugins===void 0?void 0:validatePluginIds(value.optionalPlugins,"Agent profile.optionalPlugins");if(optionalPlugins?.some(id=>requiredPlugins.includes(id)))throw new Error("Agent profile.optionalPlugins must not overlap requiredPlugins");return value.defaults!==void 0&&assertJsonValue(value.defaults,"Agent profile.defaults"),detachedFreeze({id:value.id,version:value.version,rootAgent:value.rootAgent,requiredPlugins,...optionalPlugins===void 0?{}:{optionalPlugins},...value.defaults===void 0?{}:{defaults:value.defaults}})}function buildAgentProfileV1(input){return validateAgentProfileV1(input)}function validateArtifactRefV1(value){if(assertPlainRecord(value,"Artifact reference"),assertExactKeys(value,["sessionId","operationId","artifactId","kind","mediaType","truncated","createdAt"],["sizeBytes"],"Artifact reference"),assertNonEmptyString(value.sessionId,"Artifact reference.sessionId"),assertNonEmptyString(value.operationId,"Artifact reference.operationId"),assertNonEmptyString(value.artifactId,"Artifact reference.artifactId"),assertNonEmptyString(value.kind,"Artifact reference.kind"),assertNonEmptyString(value.mediaType,"Artifact reference.mediaType"),value.sizeBytes!==void 0&&assertNonNegativeSafeInteger(value.sizeBytes,"Artifact reference.sizeBytes"),typeof value.truncated!="boolean")throw new Error("Artifact reference.truncated must be boolean");return assertNonNegativeSafeInteger(value.createdAt,"Artifact reference.createdAt"),detachedFreeze({sessionId:value.sessionId,operationId:value.operationId,artifactId:value.artifactId,kind:value.kind,mediaType:value.mediaType,...value.sizeBytes===void 0?{}:{sizeBytes:value.sizeBytes},truncated:value.truncated,createdAt:value.createdAt})}function buildArtifactRefV1(input){return validateArtifactRefV1(input)}function checkContractCompatibilityV1(candidateInput,requirementsInput){let candidate=validateAgentCapabilityContractV1(candidateInput),requirements=validateContractCompatibilityRequirementsV1(requirementsInput),issues=[];(candidate.contractId!==requirements.contractId||candidate.version!==requirements.version)&&issues.push({code:"unsupported_contract",error:commandError("unsupported_contract",`Contract is unsupported: ${requirements.contractId}@${requirements.version}`)}),candidate.hostContext.mode!==requirements.mode&&issues.push({code:"host_mode_mismatch",error:commandError("host_mode_mismatch",`Host mode is incompatible: required ${requirements.mode}, received ${candidate.hostContext.mode}`)});let missingFeatures=requirements.features.filter(feature=>!candidate.hostContext.features.includes(feature));missingFeatures.length>0&&issues.push({code:"unsupported_feature",error:commandError("unsupported_feature",`Host features are unsupported: ${missingFeatures.join(", ")}`),missingFeatures:Object.freeze([...missingFeatures])});let missingTransports=requirements.transports.filter(transport=>!candidate.hostContext.transports.includes(transport));missingTransports.length>0&&issues.push({code:"unsupported_transport",error:commandError("unsupported_transport",`Host transports are unsupported: ${missingTransports.join(", ")}`),missingTransports:Object.freeze([...missingTransports])});let missingCapabilities=requirements.capabilities.filter(required=>!candidate.capabilities.some(available=>available.id===required.id&&available.version===required.version));return missingCapabilities.length>0&&issues.push({code:"unsupported_capability",error:commandError("unsupported_capability",`Capabilities are unsupported: ${missingCapabilities.map(item=>`${item.id}@${item.version}`).join(", ")}`),missingCapabilities:Object.freeze([...missingCapabilities])}),detachedFreeze({version:1,compatible:issues.length===0,issues})}function validateAgentRole(value,label){if(value!=="root-agent-controller"&&value!=="child-agent-controller")throw new Error(`${label} is invalid`)}function validateAgentDefinitionSnapshotV1(value){if(assertPlainRecord(value,"Agent definition snapshot"),assertExactKeys(value,["version","id","definitionVersion","role","capabilities"],["owner"],"Agent definition snapshot"),value.version!==1)throw new Error("Agent definition snapshot.version must be 1");assertNonEmptyString(value.id,"Agent definition snapshot.id"),assertPositiveSafeInteger(value.definitionVersion,"Agent definition snapshot.definitionVersion"),validateAgentRole(value.role,"Agent definition snapshot.role");let capabilities=validateCapabilityRefs(value.capabilities,"Agent definition snapshot.capabilities");return value.owner!==void 0&&assertNonEmptyString(value.owner,"Agent definition snapshot.owner"),detachedFreeze({version:1,id:value.id,definitionVersion:value.definitionVersion,role:value.role,capabilities,...value.owner===void 0?{}:{owner:value.owner}})}function buildAgentDefinitionSnapshotV1(input){return validateAgentDefinitionSnapshotV1(input)}function validateAgentInstanceSnapshotV1(value){if(assertPlainRecord(value,"Agent instance snapshot"),assertExactKeys(value,["version","id","definitionId","definitionVersion","role","status","revision"],["parentInstanceId","leaseOwner"],"Agent instance snapshot"),value.version!==1)throw new Error("Agent instance snapshot.version must be 1");if(assertNonEmptyString(value.id,"Agent instance snapshot.id"),assertNonEmptyString(value.definitionId,"Agent instance snapshot.definitionId"),assertPositiveSafeInteger(value.definitionVersion,"Agent instance snapshot.definitionVersion"),validateAgentRole(value.role,"Agent instance snapshot.role"),value.status!=="created"&&value.status!=="running"&&value.status!=="succeeded"&&value.status!=="failed"&&value.status!=="cancelled"&&value.status!=="disposed")throw new Error("Agent instance snapshot.status is invalid");return assertNonNegativeSafeInteger(value.revision,"Agent instance snapshot.revision"),value.parentInstanceId!==void 0&&assertNonEmptyString(value.parentInstanceId,"Agent instance snapshot.parentInstanceId"),value.leaseOwner!==void 0&&assertNonEmptyString(value.leaseOwner,"Agent instance snapshot.leaseOwner"),detachedFreeze({version:1,id:value.id,definitionId:value.definitionId,definitionVersion:value.definitionVersion,role:value.role,status:value.status,revision:value.revision,...value.parentInstanceId===void 0?{}:{parentInstanceId:value.parentInstanceId},...value.leaseOwner===void 0?{}:{leaseOwner:value.leaseOwner}})}function buildAgentInstanceSnapshotV1(input){return validateAgentInstanceSnapshotV1(input)}function validateSessionRevisionV1(value){if(assertPlainRecord(value,"Session revision"),assertExactKeys(value,["version","sessionId","sequence","leafId"],[],"Session revision"),value.version!==1)throw new Error("Session revision.version must be 1");if(assertNonEmptyString(value.sessionId,"Session revision.sessionId"),assertNonNegativeSafeInteger(value.sequence,"Session revision.sequence"),value.leafId!==null&&value.leafId!==void 0&&assertNonEmptyString(value.leafId,"Session revision.leafId"),value.leafId===void 0)throw new Error("Session revision.leafId is required");return detachedFreeze({version:1,sessionId:value.sessionId,sequence:value.sequence,leafId:value.leafId})}function buildSessionRevisionV1(input){return validateSessionRevisionV1(input)}function validateSessionSnapshotV1(value){if(assertPlainRecord(value,"Session snapshot"),assertExactKeys(value,["version","sessionId","revision"],[],"Session snapshot"),value.version!==1)throw new Error("Session snapshot.version must be 1");assertNonEmptyString(value.sessionId,"Session snapshot.sessionId");let revision=validateSessionRevisionV1(value.revision);if(revision.sessionId!==value.sessionId)throw new Error("Session snapshot.revision.sessionId must match sessionId");return detachedFreeze({version:1,sessionId:value.sessionId,revision})}function buildSessionSnapshotV1(input){return validateSessionSnapshotV1(input)}function validateErrorEnvelopeV1(value){if(assertPlainRecord(value,"Error envelope"),assertExactKeys(value,["version","code","message","retryable"],["details","name"],"Error envelope"),value.version!==1)throw new Error("Error envelope.version must be 1");if(assertNonEmptyString(value.code,"Error envelope.code"),typeof value.message!="string")throw new Error("Error envelope.message must be a string");if(typeof value.retryable!="boolean")throw new Error("Error envelope.retryable must be a boolean");return value.name!==void 0&&assertNonEmptyString(value.name,"Error envelope.name"),value.details!==void 0&&assertJsonValue(value.details,"Error envelope.details"),detachedFreeze({version:1,code:value.code,message:value.message,retryable:value.retryable,...value.details===void 0?{}:{details:value.details},...value.name===void 0?{}:{name:value.name}})}function buildErrorEnvelopeV1(input){return validateErrorEnvelopeV1(input)}function validateOperationTerminalStatus(value,label){if(value!=="succeeded"&&value!=="failed"&&value!=="cancelled"&&value!=="timed_out")throw new Error(`${label} is invalid`)}function validateOperationTerminalV1(value){if(assertPlainRecord(value,"Operation terminal"),!("version"in value)||!("status"in value))throw new Error("Operation terminal is missing required field: version or status");if(value.version!==1)throw new Error("Operation terminal.version must be 1");if(validateOperationTerminalStatus(value.status,"Operation terminal.status"),value.status==="succeeded")return assertExactKeys(value,["version","status"],["result"],"Operation terminal"),value.result!==void 0&&assertJsonValue(value.result,"Operation terminal.result"),detachedFreeze({version:1,status:"succeeded",...value.result===void 0?{}:{result:value.result}});assertExactKeys(value,["version","status","error"],[],"Operation terminal");let error=validateErrorEnvelopeV1(value.error);return detachedFreeze({version:1,status:value.status,error})}function buildOperationTerminalV1(input){return validateOperationTerminalV1(input)}function validateOperationSnapshotV1(value){if(assertPlainRecord(value,"Operation snapshot"),assertExactKeys(value,["version","operationId","kind","status"],["terminal","instanceId","sessionId","inputRevision"],"Operation snapshot"),value.version!==1)throw new Error("Operation snapshot.version must be 1");if(assertNonEmptyString(value.operationId,"Operation snapshot.operationId"),assertNonEmptyString(value.kind,"Operation snapshot.kind"),value.status!=="queued"&&value.status!=="running"&&value.status!=="succeeded"&&value.status!=="failed"&&value.status!=="cancelled"&&value.status!=="timed_out")throw new Error("Operation snapshot.status is invalid");if((value.status==="queued"||value.status==="running")&&value.terminal!==void 0)throw new Error("Operation snapshot active status must not have a terminal");if(value.status!=="queued"&&value.status!=="running"&&value.terminal===void 0)throw new Error("Operation snapshot terminal status requires a terminal");let terminal=value.terminal===void 0?void 0:validateOperationTerminalV1(value.terminal);if(terminal!==void 0&&terminal.status!==value.status)throw new Error("Operation snapshot.terminal.status must match status");value.instanceId!==void 0&&assertNonEmptyString(value.instanceId,"Operation snapshot.instanceId"),value.sessionId!==void 0&&assertNonEmptyString(value.sessionId,"Operation snapshot.sessionId");let inputRevision=value.inputRevision===void 0?void 0:validateSessionRevisionV1(value.inputRevision);if(inputRevision!==void 0&&value.sessionId!==void 0&&inputRevision.sessionId!==value.sessionId)throw new Error("Operation snapshot.inputRevision.sessionId must match sessionId");return detachedFreeze({version:1,operationId:value.operationId,kind:value.kind,status:value.status,...terminal===void 0?{}:{terminal},...value.instanceId===void 0?{}:{instanceId:value.instanceId},...value.sessionId===void 0?{}:{sessionId:value.sessionId},...inputRevision===void 0?{}:{inputRevision}})}function buildOperationSnapshotV1(input){return validateOperationSnapshotV1(input)}function validateCommandRequestV1(value){if(assertPlainRecord(value,"Command request"),assertExactKeys(value,["version","operationId","idempotencyKey","command","target","input","hostContext"],["expectedRevision"],"Command request"),value.version!==1)throw new Error("Command request.version must be 1");assertNonEmptyString(value.operationId,"Command request.operationId"),assertNonEmptyString(value.idempotencyKey,"Command request.idempotencyKey"),assertNonEmptyString(value.command,"Command request.command"),assertNonEmptyString(value.target,"Command request.target"),assertJsonValue(value.input,"Command request.input");let expectedRevision=value.expectedRevision===void 0?void 0:validateSessionRevisionV1(value.expectedRevision);if(expectedRevision!==void 0&&expectedRevision.sessionId!==value.target)throw new Error("Command request.expectedRevision.sessionId does not match target");let hostContext=validateHostContextV1(value.hostContext);return detachedFreeze({version:1,operationId:value.operationId,idempotencyKey:value.idempotencyKey,command:value.command,target:value.target,input:value.input,...expectedRevision===void 0?{}:{expectedRevision},hostContext})}function buildCommandRequestV1(input){return validateCommandRequestV1({...input,version:input.version??1})}function validateCommandAdmissionV1(value){if(assertPlainRecord(value,"Command admission"),assertExactKeys(value,["version","status","request"],["operation","error"],"Command admission"),value.version!==1)throw new Error("Command admission.version must be 1");if(value.status!=="accepted"&&value.status!=="existing"&&value.status!=="rejected")throw new Error("Command admission.status is invalid");let request=validateCommandRequestV1(value.request),operation=value.operation===void 0?void 0:validateOperationSnapshotV1(value.operation);if((value.status==="accepted"||value.status==="existing")&&operation===void 0)throw new Error("Command admission accepted status requires an operation");if(value.status==="rejected"&&value.error===void 0)throw new Error("Command admission rejected status requires an error");let error=value.error===void 0?void 0:validateErrorEnvelopeV1(value.error);return detachedFreeze({version:1,status:value.status,request,...operation===void 0?{}:{operation},...error===void 0?{}:{error}})}function canonicalJson(value){if(value===null||typeof value!="object")return JSON.stringify(value);if(Array.isArray(value))return`[${value.map(canonicalJson).join(",")}]`;let record=value;return`{${Object.keys(record).sort().map(key=>`${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`}function sameRevision(left,right){return left.sessionId===right.sessionId&&left.sequence===right.sequence&&left.leafId===right.leafId}function commandError(code,message,details){return buildErrorEnvelopeV1({version:1,code,message,retryable:!1,...details===void 0?{}:{details}})}function rejectedAdmission(request,error){return detachedFreeze({version:1,status:"rejected",request,error})}function createCommandOperationRegistryV1(){let entries=new Map,read=operationId=>{assertNonEmptyString(operationId,"operationId");let entry=entries.get(operationId);if(!entry)throw new Error(`Operation is not retained: ${operationId}`);return entry},write=(entry,operation)=>(entry.operation=operation,operation),terminal=entry=>entry.operation.terminal!==void 0;return Object.freeze({admit(input,currentRevision){let request=validateCommandRequestV1(input),current=currentRevision===void 0?void 0:validateSessionRevisionV1(currentRevision),fingerprint=canonicalJson(request),existing=entries.get(request.operationId);if(existing)return existing.fingerprint===fingerprint?detachedFreeze({version:1,status:"existing",request,operation:existing.operation}):rejectedAdmission(request,commandError("idempotency_conflict",`Operation ID is already bound to different input: ${request.operationId}`));if(request.expectedRevision!==void 0){if(current===void 0)return rejectedAdmission(request,commandError("revision_unavailable",`Current revision is required for: ${request.target}`));if(!sameRevision(request.expectedRevision,current))return rejectedAdmission(request,commandError("revision_conflict",`Expected revision does not match: ${request.target}`,{expectedRevision:request.expectedRevision,currentRevision:current}))}let operation=buildOperationSnapshotV1({version:1,operationId:request.operationId,kind:`command:${request.command}`,status:"queued",...request.expectedRevision===void 0?{}:{sessionId:request.expectedRevision.sessionId,inputRevision:request.expectedRevision}});return entries.set(request.operationId,{request,fingerprint,operation}),detachedFreeze({version:1,status:"accepted",request,operation})},start(operationId){let entry=read(operationId);return entry.operation.status!=="queued"?entry.operation:write(entry,buildOperationSnapshotV1({...entry.operation,status:"running"}))},complete(operationId,terminalSnapshot){let entry=read(operationId),nextTerminal=validateOperationTerminalV1(terminalSnapshot);if(terminal(entry)){if(canonicalJson(entry.operation.terminal)!==canonicalJson(nextTerminal))throw new Error(`Operation already has a different terminal result: ${operationId}`);return entry.operation}return write(entry,buildOperationSnapshotV1({...entry.operation,status:nextTerminal.status,terminal:nextTerminal}))},cancel(operationId){let entry=read(operationId);return terminal(entry)?entry.operation:write(entry,buildOperationSnapshotV1({...entry.operation,status:"cancelled",terminal:{version:1,status:"cancelled",error:commandError("operation_cancelled",`Operation cancelled: ${operationId}`)}}))},get(operationId){return assertNonEmptyString(operationId,"operationId"),entries.get(operationId)?.operation},release(operationId){assertNonEmptyString(operationId,"operationId"),entries.delete(operationId)}})}function buildCanonicalContractVectorsV1(){let hostContext=buildHostContextV1({mode:"full-control",features:["agent.run","session.snapshot"],transports:["in-process"]}),contract=buildAgentCapabilityContractV1({contractId:AGENT_CAPABILITY_CONTRACT_ID,capabilities:[{id:"agent.run",version:1}],hostContext}),profile=buildAgentProfileV1({id:"coding-agent",version:1,rootAgent:"coding-agent.root",requiredPlugins:["bootstrap-tools"],optionalPlugins:["bootstrap-skills"],defaults:{mode:"full-control",context:{strategy:"default"}}}),artifact=buildArtifactRefV1({sessionId:"session-vector-1",operationId:"vector-operation-1",artifactId:"artifact-vector-1",kind:"operation_record",mediaType:"application/json",sizeBytes:13,truncated:!1,createdAt:0}),revision=buildSessionRevisionV1({version:1,sessionId:"session-vector-1",sequence:0,leafId:null}),definition=buildAgentDefinitionSnapshotV1({version:1,id:"coding-agent.root",definitionVersion:1,role:"root-agent-controller",capabilities:[{id:"agent.run",version:1}],owner:"coding-agent"}),instance=buildAgentInstanceSnapshotV1({version:1,id:"instance-vector-1",definitionId:definition.id,definitionVersion:definition.definitionVersion,role:definition.role,status:"created",revision:0}),session=buildSessionSnapshotV1({version:1,sessionId:revision.sessionId,revision}),error=buildErrorEnvelopeV1({version:1,code:"provider_error",message:"provider failed",retryable:!0}),command=buildCommandRequestV1({operationId:"vector-operation-1",idempotencyKey:"vector-request-1",command:"agent.run",target:"session-vector-1",input:{prompt:"vector"},expectedRevision:{version:1,sessionId:"session-vector-1",sequence:0,leafId:null},hostContext}),registry=createCommandOperationRegistryV1(),accepted=registry.admit(command,command.expectedRevision);if(accepted.status!=="accepted"||accepted.operation===void 0)throw new Error("Canonical contract vector admission failed");let running=registry.start(command.operationId),terminal=registry.complete(command.operationId,{version:1,status:"succeeded",result:{ok:!0}}),event=buildEventEnvelopeV1({id:"vector-event-1",deliveryId:"vector-delivery-1",type:"operation.end",source:"canonical-vector",category:"authoritative",deliveryGuarantee:"best-effort",timestamp:0,operationId:command.operationId,correlationId:command.operationId,data:{version:1,operationId:command.operationId,operationKind:command.command,status:"succeeded"}});return detachedFreeze({version:1,contract,definition,instance,session,revision,error,profile,artifact,command,accepted,running,terminal,event})}function buildCanonicalContractFixtureVectorsV1(){let base=buildCanonicalContractVectorsV1(),registry=createCommandOperationRegistryV1(),request=buildCommandRequestV1({operationId:"fixture-operation-1",idempotencyKey:"fixture-request-1",command:"agent.run",target:"session-fixture-1",input:{prompt:"fixture"},expectedRevision:{version:1,sessionId:"session-fixture-1",sequence:1,leafId:"leaf-1"},hostContext:base.contract.hostContext});registry.admit(request,request.expectedRevision);let existing=registry.admit(request,request.expectedRevision),idempotencyConflict=registry.admit({...request,input:{prompt:"different"}},request.expectedRevision),revisionConflict=registry.admit({...request,operationId:"fixture-operation-2",idempotencyKey:"fixture-request-2"},{version:1,sessionId:"session-fixture-1",sequence:2,leafId:"leaf-2"}),cancelled=registry.cancel(request.operationId),terminalReplay=registry.complete(request.operationId,cancelled.terminal);if(registry.admit(buildCommandRequestV1({...request,operationId:"fixture-operation-failed",idempotencyKey:"fixture-request-failed"}),request.expectedRevision).status!=="accepted")throw new Error("Canonical contract failed vector admission failed");let failedTerminal=registry.complete("fixture-operation-failed",{version:1,status:"failed",error:buildErrorEnvelopeV1({version:1,code:"provider_error",message:"provider failed",retryable:!0})});if(registry.admit(buildCommandRequestV1({...request,operationId:"fixture-operation-timeout",idempotencyKey:"fixture-request-timeout"}),request.expectedRevision).status!=="accepted")throw new Error("Canonical contract timeout vector admission failed");let timedOutTerminal=registry.complete("fixture-operation-timeout",{version:1,status:"timed_out",error:buildErrorEnvelopeV1({version:1,code:"operation_timeout",message:"operation timed out",retryable:!0})}),unsupported=buildUnsupportedCapabilityV1({id:"fixture.missing",version:1}),observation=buildEventEnvelopeV1({id:"fixture-event-1",deliveryId:"fixture-delivery-1",type:"fixture.observation",source:"canonical-vector",timestamp:0,data:{observed:!0}}),correlated=buildEventEnvelopeV1({id:"fixture-event-correlated",deliveryId:"fixture-delivery-correlated",type:"operation.end",source:"canonical-vector",category:"authoritative",timestamp:0,operationId:"fixture-operation-1",correlationId:"fixture-operation-1",data:{status:"cancelled"}}),steer=buildCommandRequestV1({operationId:"fixture-operation-steer",idempotencyKey:"fixture-request-steer",command:"session.steer",target:"session-fixture-1",input:{text:"steer"},expectedRevision:request.expectedRevision,hostContext:base.contract.hostContext}),operationStep=buildEventEnvelopeV1({id:"fixture-event-step",deliveryId:"fixture-delivery-step",type:"operation.step",source:"canonical-vector",category:"progress",timestamp:0,operationId:"fixture-operation-steer",correlationId:"fixture-operation-steer",data:{version:1,operationId:"fixture-operation-steer",operationKind:"session.steer",step:1,message:"accepted"}}),compatibilityRequirements=overrides=>buildContractCompatibilityRequirementsV1({contractId:AGENT_CAPABILITY_CONTRACT_ID,version:1,mode:"full-control",features:[],transports:[],capabilities:[],...overrides}),compatibilityAccepted=checkContractCompatibilityV1(base.contract,compatibilityRequirements({features:["agent.run","session.snapshot"],transports:["in-process"],capabilities:[{id:"agent.run",version:1}]})),compatibilityContractUnsupported=checkContractCompatibilityV1(base.contract,compatibilityRequirements({version:2})),compatibilityCapabilityVersionUnsupported=checkContractCompatibilityV1(base.contract,compatibilityRequirements({capabilities:[{id:"agent.run",version:2}]})),compatibilityFeatureSubset=checkContractCompatibilityV1(base.contract,compatibilityRequirements({features:["agent.run","session.compact"]}));return detachedFreeze([{id:"agent-definition",value:base.definition},{id:"agent-instance",value:base.instance},{id:"session-snapshot",value:base.session},{id:"session-revision",value:base.revision},{id:"error-envelope",value:base.error},{id:"profile-snapshot",value:base.profile},{id:"artifact-reference",value:base.artifact},{id:"command-success",value:base.terminal},{id:"command-failed-terminal",value:failedTerminal},{id:"command-timed-out-terminal",value:timedOutTerminal},{id:"command-idempotency-replay",value:existing},{id:"command-idempotency-conflict",value:idempotencyConflict},{id:"command-revision-conflict",value:revisionConflict},{id:"command-cancel-terminal",value:cancelled},{id:"command-terminal-replay",value:terminalReplay},{id:"capability-unsupported",value:unsupported},{id:"event-without-operation",value:observation},{id:"event-with-operation",value:correlated},{id:"command-steer",value:steer},{id:"event-operation-step",value:operationStep},{id:"compatibility-accepted",value:compatibilityAccepted},{id:"compatibility-contract-unsupported",value:compatibilityContractUnsupported},{id:"compatibility-capability-version-unsupported",value:compatibilityCapabilityVersionUnsupported},{id:"compatibility-feature-subset",value:compatibilityFeatureSubset}])}function validateEventEnvelopeV1(value){if(assertPlainRecord(value,"Event envelope"),assertExactKeys(value,["version","id","deliveryId","type","source","category","deliveryGuarantee","timestamp","data"],["operationId","correlationId","causationId"],"Event envelope"),value.version!==1)throw new Error("Event envelope.version must be 1");if(assertNonEmptyString(value.id,"Event envelope.id"),assertNonEmptyString(value.deliveryId,"Event envelope.deliveryId"),assertNonEmptyString(value.type,"Event envelope.type"),assertNonEmptyString(value.source,"Event envelope.source"),value.category!=="authoritative"&&value.category!=="progress"&&value.category!=="observation")throw new Error("Event envelope.category is invalid");if(value.deliveryGuarantee!=="best-effort"&&value.deliveryGuarantee!=="at-least-once")throw new Error("Event envelope.deliveryGuarantee is invalid");if(assertNonNegativeSafeInteger(value.timestamp,"Event envelope.timestamp"),assertJsonValue(value.data,"Event envelope.data"),value.operationId!==void 0&&assertNonEmptyString(value.operationId,"Event envelope.operationId"),value.correlationId!==void 0&&assertNonEmptyString(value.correlationId,"Event envelope.correlationId"),value.causationId!==void 0&&assertNonEmptyString(value.causationId,"Event envelope.causationId"),value.operationId===void 0&&value.correlationId!==void 0)throw new Error("Event envelope.correlationId requires a real operationId");if(value.operationId!==void 0&&value.correlationId===void 0)throw new Error("Event envelope.operationId requires correlationId");return detachedFreeze({version:1,id:value.id,deliveryId:value.deliveryId,type:value.type,source:value.source,category:value.category,deliveryGuarantee:value.deliveryGuarantee,timestamp:value.timestamp,data:value.data,...value.operationId===void 0?{}:{operationId:value.operationId},...value.correlationId===void 0?{}:{correlationId:value.correlationId},...value.causationId===void 0?{}:{causationId:value.causationId}})}function buildEventEnvelopeV1(input){return validateEventEnvelopeV1({...input,version:input.version??1,category:input.category??"observation",deliveryGuarantee:input.deliveryGuarantee??"best-effort"})}function buildUnsupportedCapabilityV1(capability){let reference=validateCapabilityRefV1(capability),error=buildErrorEnvelopeV1({version:1,code:"unsupported_capability",message:`Capability is unsupported: ${reference.id}@${reference.version}`,retryable:!1});return detachedFreeze({status:"unsupported",capability:reference,error})}function resolveCapabilityV1(requested,supported){let reference=validateCapabilityRefV1(requested);return validateCapabilityRefs(supported,"Supported capabilities").some(candidate=>candidate.id===reference.id&&candidate.version===reference.version)?detachedFreeze({status:"supported",capability:reference}):buildUnsupportedCapabilityV1(reference)}function assertCapabilitySupportedV1(requested,supported){let resolution=resolveCapabilityV1(requested,supported);if(resolution.status==="unsupported")throw new Error(resolution.error.message);return resolution.capability}var validateAgentCapabilityContract=validateAgentCapabilityContractV1,buildAgentCapabilityContract=buildAgentCapabilityContractV1,validateEventEnvelope=validateEventEnvelopeV1,buildEventEnvelope=buildEventEnvelopeV1;function detachedFreeze2(value,seen=new WeakMap){if(value===null||typeof value!="object")return value;let existing=seen.get(value);if(existing!==void 0)return existing;if(Array.isArray(value)){let copy2=[];seen.set(value,copy2);for(let child of value)copy2.push(detachedFreeze2(child,seen));return Object.freeze(copy2)}let copy=Object.create(null);seen.set(value,copy);for(let[key,child]of Object.entries(value))copy[key]=detachedFreeze2(child,seen);return Object.freeze(copy)}function assertActive(disposed,label){if(disposed)throw new Error(`Embedded SDK binding is disposed: ${label}`)}function errorEnvelope(error,code){let message=error instanceof Error?error.message:String(error);return buildErrorEnvelopeV1({version:1,code,message,retryable:!1,...error instanceof Error?{name:error.name}:{}})}function agentDefinitionSnapshot(definition){return buildAgentDefinitionSnapshotV1({version:1,id:definition.id,definitionVersion:definition.version,role:definition.role,capabilities:[],...definition.owner===void 0?{}:{owner:definition.owner}})}function agentInstanceSnapshot(snapshot){return buildAgentInstanceSnapshotV1({version:1,id:snapshot.id,definitionId:snapshot.definitionId,definitionVersion:snapshot.definitionVersion,role:snapshot.role,status:snapshot.status,revision:snapshot.revision,...snapshot.parentInstanceId===void 0?{}:{parentInstanceId:snapshot.parentInstanceId},...snapshot.leaseOwner===void 0?{}:{leaseOwner:snapshot.leaseOwner}})}function resultSnapshot(result){return result.status==="succeeded"?detachedFreeze2({status:"succeeded",output:canonicalOutput(result.output,`wait:${result.revision}`),revision:result.revision}):detachedFreeze2({status:result.status,revision:result.revision,...result.error===void 0?{}:{error:errorEnvelope(result.error,`agent_${result.status}`)}})}function canonicalOutput(value,operationId){return buildOperationSnapshotV1({version:1,operationId,kind:"agent.run",status:"succeeded",terminal:{version:1,status:"succeeded",result:value}}),detachedFreeze2(value)}function canonicalInput(value){if(value===void 0)throw new Error("Embedded SDK run input must be JSON-compatible");return buildOperationSnapshotV1({version:1,operationId:"embedded-sdk:input",kind:"agent.run",status:"succeeded",terminal:{version:1,status:"succeeded",result:value}}),detachedFreeze2(value)}function createEmbeddedSessionBindingV1(session){if(!session.getRevision)throw new Error("Embedded SDK session requires revision support");let getRevision=()=>detachedFreeze2(session.getRevision()),context=session.getContextSnapshot&&session.commitContext?Object.freeze({version:1,get:()=>detachedFreeze2(session.getContextSnapshot()),commit:request=>session.commitContext(request)}):void 0;return Object.freeze({version:1,getSessionId:()=>session.getSessionId(),getRevision,snapshot:()=>buildSessionSnapshotV1({version:1,sessionId:session.getSessionId(),revision:getRevision()}),getMessages:()=>detachedFreeze2(session.getMessages()),getBranchEntries:()=>detachedFreeze2(session.getBranchEntries()),isIdle:()=>session.isIdle(),prompt:text=>session.prompt(text),steer:text=>session.steer?session.steer(text):Promise.reject(new Error("Embedded SDK session does not support steer")),abort:()=>session.abort(),waitForIdle:()=>session.waitForIdle(),...context===void 0?{}:{context}})}function createEmbeddedSdkBindingV1(options={}){let composition=options.composition??createAgentCompositionRuntime(),ownsComposition=options.ownsComposition??options.composition===void 0,defaultFeatures=["agent-composition-v1",...options.session===void 0?[]:["session","session-revision-v1","context"]],hostContext=detachedFreeze2({mode:options.mode??"full-control",features:[...options.features??defaultFeatures].sort(),transports:["in-process"]}),session=options.session===void 0?void 0:createEmbeddedSessionBindingV1(options.session),contract=buildAgentCapabilityContractV1({contractId:"agent-forge/agent-capability-contract",capabilities:[],hostContext}),definitions=new Map,instances=new Map,listeners=new Map,sequence=0,disposePromise,disposed=!1,nextId=kind=>(sequence+=1,options.idFactory?.(kind,sequence)??`embedded-sdk:${kind}:${sequence}`),emit=(type,data,operationId)=>{let event=buildEventEnvelopeV1({id:nextId("event"),deliveryId:nextId("delivery"),type,source:"embedded-sdk",timestamp:options.clock?.()??0,category:type===OPERATION_START_EVENT_ID||type===OPERATION_CANCEL_EVENT_ID||type===OPERATION_END_EVENT_ID?"authoritative":"observation",deliveryGuarantee:"best-effort",data,...operationId===void 0?{}:{operationId,correlationId:operationId}});for(let listener of listeners.values())try{listener(event)}catch{}},resolveDefinition=definition=>{let snapshot="snapshot"in definition?definition.snapshot:definition,definitionVersion="definitionVersion"in snapshot?snapshot.definitionVersion:snapshot.version,resolved=definitions.get(`${snapshot.id}@${definitionVersion}`);if(resolved)return resolved;if(options.composition!==void 0)return composition.get(snapshot.id,definitionVersion);throw new Error(`Embedded SDK has no defined Agent: ${snapshot.id}@${definitionVersion}`)},binding={version:1,contract,hostContext,...session===void 0?{}:{session},define(definition){assertActive(disposed,"define");let registered=composition.define(definition);return definitions.set(`${registered.id}@${registered.version}`,registered),detachedFreeze2({snapshot:agentDefinitionSnapshot(registered)})},create(definition,instanceOptions={}){assertActive(disposed,"create");let raw=composition.create(resolveDefinition(definition),instanceOptions),instanceDisposed=!1,instanceDisposePromise,leases=new WeakMap,wrapper={id:raw.id,snapshot:()=>(assertActive(disposed||instanceDisposed,raw.id),agentInstanceSnapshot(raw.snapshot())),acquireControllerLease:async owner=>{assertActive(disposed||instanceDisposed,raw.id);let lease=await raw.acquireControllerLease(owner),projected=Object.freeze({id:lease.id,instanceId:lease.instanceId,owner:lease.owner,revision:lease.revision,isActive:()=>!disposed&&!instanceDisposed&&lease.isActive(),release:async()=>{assertActive(disposed||instanceDisposed,raw.id),await lease.release()}});return leases.set(projected,lease),projected},run:(input,runOptions)=>{assertActive(disposed||instanceDisposed,raw.id);let lease=leases.get(runOptions.lease);if(!lease)throw new Error(`Embedded SDK lease does not belong to Agent instance: ${raw.id}`);let operation=raw.run(canonicalInput(input),{lease,signal:runOptions.signal}),terminal,cancelEmitted=!1,reportCancel=()=>{cancelEmitted||(cancelEmitted=!0,emit(OPERATION_CANCEL_EVENT_ID,validateOperationCancelEventDataV1({version:1,operationId:operation.id,operationKind:"agent.run"}),operation.id))};operation.signal.addEventListener("abort",reportCancel,{once:!0}),operation.signal.aborted&&reportCancel(),runOptions.signal?.aborted||emit(OPERATION_START_EVENT_ID,validateOperationStartEventDataV1({version:1,operationId:operation.id,operationKind:"agent.run"}),operation.id);let result=operation.result.then(value=>{try{let output=canonicalOutput(value,operation.id);return terminal={version:1,status:"succeeded",result:output},emit(OPERATION_END_EVENT_ID,validateOperationEndEventDataV1({version:1,operationId:operation.id,operationKind:"agent.run",status:"succeeded"}),operation.id),output}catch(error){throw terminal={version:1,status:"failed",error:errorEnvelope(error,"agent_invalid_result")},emit(OPERATION_END_EVENT_ID,validateOperationEndEventDataV1({version:1,operationId:operation.id,operationKind:"agent.run",status:"failed",errorMessage:error instanceof Error?error.message:String(error)}),operation.id),error}},error=>{let status=operation.status()==="cancelled"?"cancelled":"failed";throw terminal={version:1,status,error:errorEnvelope(error,`agent_${status}`)},emit(OPERATION_END_EVENT_ID,validateOperationEndEventDataV1({version:1,operationId:operation.id,operationKind:"agent.run",status,errorMessage:error instanceof Error?error.message:String(error)}),operation.id),error});return Object.freeze({id:operation.id,result,snapshot:()=>buildOperationSnapshotV1({version:1,operationId:operation.id,kind:"agent.run",status:terminal?.status??operation.status(),...terminal===void 0&&operation.status()==="cancelled"?{terminal:{version:1,status:"cancelled",error:errorEnvelope(new Error("Operation cancelled"),"agent_cancelled")}}:terminal===void 0?{}:{terminal},instanceId:raw.id}),cancel:async reason=>{assertActive(disposed||instanceDisposed,raw.id),!(operation.status()!=="queued"&&operation.status()!=="running")&&await operation.cancel(reason)}})},wait:async()=>detachedFreeze2(resultSnapshot(await raw.wait())),cancel:async reason=>{assertActive(disposed||instanceDisposed,raw.id),await raw.cancel(reason)},dispose:async()=>(instanceDisposePromise??=(async()=>{instanceDisposed||(instanceDisposed=!0,await raw.dispose(),instances.delete(raw.id))})(),instanceDisposePromise)};return instances.set(raw.id,wrapper),Object.freeze(wrapper)},listInstances:()=>Object.freeze([...instances.values()].map(instance=>instance.snapshot()).sort((left,right)=>left.id.localeCompare(right.id))),subscribe(listener){assertActive(disposed,"subscribe");let id=`embedded-sdk:subscription:${++sequence}`,released=!1;return listeners.set(id,listener),Object.freeze({id,dispose:()=>{released||(released=!0,listeners.delete(id))}})},dispose:async()=>(disposePromise??=(async()=>{if(disposed)return;disposed=!0;let failures=[];for(let instance of[...instances.values()])try{await instance.dispose()}catch(error){failures.push(error)}if(listeners.clear(),ownsComposition&&"disposeDefinitions"in composition)try{composition.disposeDefinitions([...definitions.values()])}catch(error){failures.push(error)}if(definitions.clear(),failures.length===1)throw failures[0];if(failures.length>1)throw new AggregateError(failures,"Embedded SDK disposal failed")})(),disposePromise)};return Object.freeze(binding)}var createEmbeddedSdkBinding=createEmbeddedSdkBindingV1;import{EventEmitter}from"node:events";function createEventBus(){let emitter=new EventEmitter;return{emit:(channel,data)=>{emitter.emit(channel,data)},on:(channel,handler)=>{let safeHandler=async data=>{try{await handler(data)}catch(err){console.error(`Event handler error (${channel}):`,err)}};return emitter.on(channel,safeHandler),()=>emitter.off(channel,safeHandler)},clear:()=>{emitter.removeAllListeners()}}}var ModelRegistry=class{runtime;constructor(runtime){this.runtime=runtime}refresh(options){return this.runtime.refresh(options)}getError(){return this.runtime.getError()}getAll(){return[...this.runtime.getModels()]}getAvailable(){return[...this.runtime.getAvailableSnapshot()]}find(provider,modelId){return this.runtime.getModel(provider,modelId)}hasConfiguredAuth(model){return this.runtime.hasConfiguredAuth(model.provider)}async getApiKeyAndHeaders(model){try{let resolution=await this.runtime.getAuth(model);if(!resolution){let compatibility=this.runtime.getCompatibilityRequestConfig(model);return compatibility.authHeader?{ok:!1,error:`No API key found for "${model.provider}"`}:{ok:!0,headers:compatibility.headers}}return{ok:!0,apiKey:resolution.auth.apiKey,headers:resolution.auth.headers,...resolution.auth.baseUrl?{baseUrl:resolution.auth.baseUrl}:{},env:resolution.env}}catch(error){let cause=error instanceof Error?error.cause:void 0,message=cause instanceof Error?cause.message:error instanceof Error?error.message:String(error);return{ok:!1,error:message==="authHeader requires a resolved API key"?`No API key found for "${model.provider}"`:message}}}getProviderAuthStatus(provider){return this.runtime.getProviderAuthStatus(provider)}getProvider(provider){return this.runtime.getProvider(provider)}stream(model,context,options){return this.runtime.stream(model,context,options)}complete(model,context,options){return this.runtime.complete(model,context,options)}streamSimple(model,context,options){return this.runtime.streamSimple(model,context,options)}getProviderDisplayName(provider){return this.runtime.getProvider(provider)?.name??provider}getProviderAuth(provider){return this.runtime.getAuth(provider)}async getApiKeyForProvider(provider){try{return(await this.runtime.getAuth(provider))?.auth.apiKey}catch{return}}isUsingOAuth(model){return this.runtime.isUsingOAuth(model.provider)}registerProvider(providerOrName,config){if(typeof providerOrName=="string"){if(!config)throw new Error("Provider config is required when registering by name");this.runtime.registerProvider(providerOrName,config);return}this.runtime.registerNativeProvider(providerOrName)}unregisterProvider(providerName){this.runtime.unregisterProvider(providerName)}getRegisteredProviderConfig(providerName){return this.runtime.getRegisteredProviderConfig(providerName)}getRegisteredNativeProvider(providerName){return this.runtime.getRegisteredNativeProvider(providerName)}getRegisteredProviderIds(){return this.runtime.getRegisteredProviderIds()}};function retryBackoffMs(policy,attempt){return Math.min(policy.baseWaitMs*2**(attempt-1),policy.maxWaitMs)}function createAgentRetryScheduler(){let terminalStates=new Map;return{schedule(input){let existing=terminalStates.get(input.operationId);if(existing)return{...existing,duplicate:!0};let signal=input.signal,now=input.now??(()=>0),sleep=input.sleep??(()=>{}),attempts=[],finish=outcome=>(terminalStates.set(input.operationId,outcome),outcome);for(let attempt=1;attempt<=input.policy.attemptLimit;attempt+=1){if(signal?.aborted)return finish({status:"cancelled",operationId:input.operationId,attempts});let at=now(),step=input.task(attempt);if(step.ok)return attempts.push({attempt,at,ok:!0,waitedMs:0}),finish({status:"succeeded",operationId:input.operationId,result:step.result,attempts});if(!step.retryable)return attempts.push({attempt,at,ok:!1,failure:step.reason,retryable:!1,waitedMs:0}),finish({status:"failed_terminal",operationId:input.operationId,reason:step.reason,attempts});let waitedMs=retryBackoffMs(input.policy,attempt);if(attempts.push({attempt,at,ok:!1,failure:step.reason,retryable:!0,waitedMs}),attempt<input.policy.attemptLimit&&(sleep(waitedMs),signal?.aborted))return finish({status:"cancelled",operationId:input.operationId,attempts})}return finish({status:"exhausted",operationId:input.operationId,attempts})},terminalOf(operationId){return terminalStates.get(operationId)}}}function createAutoCompactionExecutor(options){let coordinator=options.coordinator,policy=options.policy,inProgress=!1;return{get inProgress(){return inProgress},maybeCompact(input){if(!policy.enabled)return{status:"disabled"};if(inProgress)return{status:"busy"};if(input.currentTokens<policy.tokenThreshold)return{status:"below_threshold",currentTokens:input.currentTokens,threshold:policy.tokenThreshold};inProgress=!0;try{let staged=coordinator.stage({operationId:input.operationId,expectedRevision:coordinator.currentRevision,payload:null});if(staged.status==="stale")return{status:"stale",currentRevision:staged.currentRevision};if(staged.status==="duplicate")return{status:"cancelled"};if(input.signal?.aborted)return coordinator.cancelStage(staged.staged.token),{status:"cancelled"};let summary;try{summary=input.summarize(input.signal)}catch(error){return coordinator.cancelStage(staged.staged.token),{status:"summary_failed",reason:error instanceof Error?error.message:String(error)}}if(input.signal?.aborted)return coordinator.cancelStage(staged.staged.token),{status:"cancelled"};let outcome=coordinator.commitStage({token:staged.staged.token,apply:()=>{}});return outcome.status==="stale"?{status:"stale",currentRevision:outcome.currentRevision}:outcome.status==="committed"?{status:"completed",revision:outcome.revision,summary}:(coordinator.cancelStage(staged.staged.token),{status:"cancelled"})}finally{inProgress=!1}}}}function createBranchStateMigration(){return{migrate({entries,fromBranch,toBranch}){let source=entries.filter(entry=>entry.branch===fromBranch);return source.length===0?{status:"empty_source",fromBranch}:{status:"migrated",fromBranch,toBranch,migrated:Object.freeze(source.map(entry=>({key:entry.key,value:entry.value})))}},scan(entries,branch){return Object.freeze(entries.filter(entry=>entry.branch===branch))}}}function createReloadTransaction(){return{reload(items){let failures=[];for(let[index,item]of items.entries()){let failure=item.validate();failure!==null&&failures.push({index,reason:failure})}if(failures.length>0)return{status:"rolled_back",failures:Object.freeze(failures)};for(let item of items)item.commit();return{status:"committed",count:items.length}}}}function createHostCheckpointCoordinator(options={}){let revision=options.startRevision??0,staged=new Map,committed=new Map,tokenSequence=0;return{get currentRevision(){return revision},stage(input){if(typeof input.operationId!="string"||input.operationId.trim().length===0)throw new Error("Checkpoint operationId must be a non-empty string");let appliedRevision=committed.get(input.operationId);if(appliedRevision!==void 0)return{status:"duplicate",revision:appliedRevision};if(input.expectedRevision!==revision)return{status:"stale",currentRevision:revision};tokenSequence+=1;let token=`ckpt-${tokenSequence}`,entry={operationId:input.operationId,expectedRevision:input.expectedRevision,payload:input.payload,state:"staged"};return staged.set(token,entry),{status:"staged",staged:{token,operationId:input.operationId,expectedRevision:input.expectedRevision,currentRevision:revision}}},commitStage({token,apply}){let entry=staged.get(token);if(!entry)return{status:"unknown_token"};if(entry.state==="cancelled")return{status:"cancelled"};if(entry.expectedRevision!==revision)return staged.delete(token),{status:"stale",currentRevision:revision};try{apply(entry.payload,revision+1)}catch(error){return staged.delete(token),{status:"write_failed",reason:error instanceof Error?error.message:String(error)}}return revision+=1,committed.set(entry.operationId,revision),staged.delete(token),{status:"committed",revision}},cancelStage(token){let entry=staged.get(token);return entry?committed.has(entry.operationId)?{status:"already_committed"}:(entry.state="cancelled",{status:"cancelled"}):{status:"unknown_token"}},committedOperationIds(){return Object.freeze([...committed.keys()].sort())}}}function createManualCompactionExecutor(options){let coordinator=options.coordinator,state="idle",currentOperationId;return{get state(){return state},requestCompaction(input){if(state==="in_progress")return{status:"busy",currentOperationId:currentOperationId??"unknown"};if(input.pluginId.trim().length===0)throw new Error("Compaction pluginId must be a non-empty string");state="in_progress",currentOperationId=input.operationId;try{let staged=coordinator.stage({operationId:input.operationId,expectedRevision:coordinator.currentRevision,payload:null});if(staged.status==="stale")return{status:"stale",currentRevision:staged.currentRevision};if(staged.status==="duplicate")return{status:"completed",revision:staged.revision,summary:{duplicate:!0}};let summary;try{summary=input.summarize()}catch(error){return coordinator.cancelStage(staged.staged.token),{status:"summary_failed",reason:error instanceof Error?error.message:String(error)}}let outcome=coordinator.commitStage({token:staged.staged.token,apply:(payload,revision)=>{}});return outcome.status==="stale"?{status:"stale",currentRevision:outcome.currentRevision}:outcome.status==="committed"?{status:"completed",revision:outcome.revision,summary}:{status:"summary_failed",reason:`Unexpected checkpoint outcome: ${outcome.status}`}}finally{state="idle",currentOperationId=void 0}}}}function createOutputReducer(){return{fold(records){let groups=[],pendingTool=null,flushTool=()=>{pendingTool&&(groups.push(pendingTool),pendingTool=null)};for(let record of records){if(record.channel==="tool"&&record.correlationId!==void 0){let isCall=record.severity==="info"&&record.summary.endsWith("called");pendingTool&&pendingTool.correlationId!==record.correlationId&&flushTool(),pendingTool||(pendingTool={kind:"tool",toolName:record.code??record.summary,correlationId:record.correlationId,detailsRef:`trace:${record.traceId}#call:${record.correlationId}`,calls:0,ok:0,failed:0,records:[]}),pendingTool.records.push(record),isCall?pendingTool.calls+=1:record.severity==="ok"?pendingTool.ok+=1:record.severity==="error"&&(pendingTool.failed+=1);continue}flushTool();let last=groups.at(-1);last?.kind==="records"?(last.records.push(record),last.detailsRef=`trace:${record.traceId}#records:${last.records.length}`):groups.push({kind:"records",detailsRef:`trace:${record.traceId}#records:1`,records:[record]})}flushTool();let foldedToolGroups=0,frozenGroups=groups.map(group=>{let base={...group,records:Object.freeze([...group.records])};if(base.kind==="tool"){foldedToolGroups+=1;let firstAt=base.records[0]?.at??0,lastAt=base.records.at(-1)?.at??firstAt;return Object.freeze({...base,durationMs:Math.max(lastAt-firstAt,0)})}return Object.freeze(base)});return{groups:Object.freeze(frozenGroups),totalRecords:records.length,foldedToolGroups}},unfold(folded){return Object.freeze(folded.groups.flatMap(group=>[...group.records]))}}}var INTERNAL_FIELD_KEYS=["memoryId","memoryIds","score","scores","ranking","queryPlan","budget","budgets","agentRole","pluginRole","lease","leaseId","purgeState","rawSources"];function isArtifactLike(value){return typeof value=="object"&&value!==null&&"artifactId"in value&&"sessionId"in value&&"kind"in value}function toArtifactRef(value){if(!(typeof value.sessionId!="string"||typeof value.operationId!="string"||typeof value.artifactId!="string"||typeof value.kind!="string"||typeof value.mediaType!="string"||typeof value.truncated!="boolean"||typeof value.createdAt!="number"))return{sessionId:value.sessionId,operationId:value.operationId,artifactId:value.artifactId,kind:value.kind,mediaType:value.mediaType,...typeof value.sizeBytes=="number"?{sizeBytes:value.sizeBytes}:{},truncated:value.truncated,createdAt:value.createdAt}}function createHostOutputSerializer(){return{project(input,context){if(context.policyVersion.trim().length===0)return{text:"",diagnostics:["output_projection_rejected: policyVersion must be a non-empty string"],rejected:{code:"output_projection_rejected",reason:"policyVersion must be a non-empty string"}};let redactions=[],diagnostics=[],artifacts=[],showInternal=context.surface==="inspector"&&context.inspectorAuthorized,isAllowedKey=key=>!INTERNAL_FIELD_KEYS.includes(key)||showInternal,renderValue=(key,value,path)=>{if(!isAllowedKey(key))return redactions.push(`${path}.${key}`),`[redacted:${key}]`;if(isArtifactLike(value)){let ref=toArtifactRef(value);return ref?(artifacts.push(ref),`[artifact:${ref.artifactId}]`):(diagnostics.push(`output_projection_rejected: ${path}.${key} is a malformed artifact reference`),`[unrenderable:${key}]`)}return typeof value=="string"?value:typeof value=="number"||typeof value=="boolean"?String(value):value===null?"null":Array.isArray(value)?`[${value.map(item=>renderValue(key,item,path)).join(", ")}]`:typeof value=="object"?`{${Object.entries(value).map(([nestedKey,nestedValue])=>`${nestedKey}:${renderValue(nestedKey,nestedValue,`${path}.${key}`)}`).join(", ")}}`:(diagnostics.push(`output_projection_rejected: ${path}.${key} cannot be serialized`),`[unrenderable:${key}]`)},textParts=[];for(let[key,value]of Object.entries(input)){if(key==="artifacts"&&Array.isArray(value)){for(let entry of value)if(isArtifactLike(entry)){let ref=toArtifactRef(entry);ref?artifacts.push(ref):diagnostics.push("output_projection_rejected: artifacts entry is malformed")}else diagnostics.push("output_projection_rejected: artifacts entry is malformed");continue}textParts.push(`${key}=${renderValue(key,value,"root")}`)}return{text:textParts.join(`
|
|
3
3
|
`),...artifacts.length>0?{artifacts:Object.freeze(artifacts)}:{},...redactions.length>0?{redactions:Object.freeze([...redactions])}:{},...diagnostics.length>0?{diagnostics:Object.freeze([...diagnostics])}:{}}}}}var CLASSIFICATION_TABLE=[["context_overflow",["context length","maximum context","context window","token limit","too many tokens","overflow"]],["rate_limit",["rate limit","429","too many requests"]],["auth",["401","403","unauthorized","forbidden","invalid api key"]],["transient",["timeout","econnreset","econnrefused","socket hang up","502","503"]]];function createOverflowRecovery(options){let coordinator=options.coordinator,classify=error=>{let rawName=error instanceof Error?error.name:typeof error=="object"&&error!==null&&"name"in error?String(error.name):"unknown",rawMessage=error instanceof Error?error.message:String(error),haystack=`${rawName} ${rawMessage}`.toLowerCase();for(let[errorClass,patterns]of CLASSIFICATION_TABLE)if(patterns.some(pattern=>haystack.includes(pattern)))return{errorClass,rawMessage,rawName};return{errorClass:"unknown",rawMessage,rawName}};return{classify,recover({operationId,error,shrink}){let classification=classify(error);if(classification.errorClass!=="context_overflow")return{status:"not_recoverable",errorClass:classification.errorClass,rawMessage:classification.rawMessage,hint:"Only context overflow is recoverable here; rate-limit retry belongs to 2A.4"};let staged=coordinator.stage({operationId,expectedRevision:coordinator.currentRevision,payload:null});if(staged.status==="stale")return{status:"stale",currentRevision:staged.currentRevision,errorClass:classification.errorClass,rawMessage:classification.rawMessage};if(staged.status==="duplicate")return{status:"recovered",revision:staged.revision,shrunk:{duplicate:!0}};let shrunk;try{shrunk=shrink(classification)}catch(shrinkError){return coordinator.cancelStage(staged.staged.token),{status:"projection_failed",errorClass:classification.errorClass,rawMessage:classification.rawMessage,reason:shrinkError instanceof Error?shrinkError.message:String(shrinkError)}}let outcome=coordinator.commitStage({token:staged.staged.token,apply:()=>{}});return outcome.status==="stale"?{status:"stale",currentRevision:outcome.currentRevision,errorClass:classification.errorClass,rawMessage:classification.rawMessage}:outcome.status==="committed"?{status:"recovered",revision:outcome.revision,shrunk}:{status:"projection_failed",errorClass:classification.errorClass,rawMessage:classification.rawMessage,reason:`Unexpected checkpoint outcome: ${outcome.status}`}}}}function createSummaryRetryExecutor(options){let coordinator=options.coordinator,policy=options.policy,now=options.now??(()=>0),sleep=options.sleep??(()=>{});if(policy.attemptLimit<1)throw new Error("Summary retry attemptLimit must be at least 1");if(policy.baseWaitMs<0||policy.maxWaitMs<policy.baseWaitMs)throw new Error("Summary retry wait bounds are invalid");return{execute({operationId,summarize}){let attempts=[];for(let attempt=1;attempt<=policy.attemptLimit;attempt+=1){let at=now(),staged=coordinator.stage({operationId:`${operationId}#${attempt}`,expectedRevision:coordinator.currentRevision,payload:null});if(staged.status==="stale")return{status:"stale",operationId,currentRevision:staged.currentRevision,attempts};if(staged.status==="duplicate")return{status:"succeeded",operationId,revision:staged.revision,summary:{duplicate:!0},attempts};let summary;try{summary=summarize(attempt)}catch(error){coordinator.cancelStage(staged.staged.token);let waitedMs=retryBackoffMs(policy,attempt);attempts.push({attempt,at,ok:!1,failure:error instanceof Error?error.message:String(error),waitedMs}),attempt<policy.attemptLimit&&sleep(waitedMs);continue}let outcome=coordinator.commitStage({token:staged.staged.token,apply:()=>{}});if(outcome.status==="stale")return attempts.push({attempt,at,ok:!0,waitedMs:0}),{status:"stale",operationId,currentRevision:outcome.currentRevision,attempts};if(outcome.status==="committed")return attempts.push({attempt,at,ok:!0,waitedMs:0}),{status:"succeeded",operationId,revision:outcome.revision,summary,attempts}}return{status:"exhausted",operationId,attempts}}}}function createMigrationTool(){let steps=new Map;return{registerStep(step){let key=`${step.fromVersion}->${step.toVersion}`;if(steps.has(key))throw new Error(`Migration step already registered: ${key}`);steps.set(key,step)},migrate({version,targetVersion,data}){if(version===targetVersion)return{status:"already_current",version,data};let applied=[],currentVersion=version,currentData=data;for(;currentVersion!==targetVersion;){let step=steps.get(`${currentVersion}->${targetVersion}`);if(step){try{currentData=step.migrate(currentData)}catch(error){return{status:"failed",data,evidence:Object.freeze([...applied]),failure:{fromVersion:currentVersion,toVersion:targetVersion,reason:error instanceof Error?error.message:String(error)}}}applied.push({fromVersion:currentVersion,toVersion:targetVersion,applied:!0}),currentVersion=targetVersion;break}let nextHop=[...steps.values()].find(candidate=>candidate.fromVersion===currentVersion);if(!nextHop)return{status:"no_path",fromVersion:version,targetVersion};try{currentData=nextHop.migrate(currentData)}catch(error){return{status:"failed",data,evidence:Object.freeze([...applied]),failure:{fromVersion:nextHop.fromVersion,toVersion:nextHop.toVersion,reason:error instanceof Error?error.message:String(error)}}}applied.push({fromVersion:nextHop.fromVersion,toVersion:nextHop.toVersion,applied:!0}),currentVersion=nextHop.toVersion}return{status:"migrated",version:currentVersion,data:currentData,evidence:Object.freeze([...applied])}}}}var BorderedLoader=class extends Container{loader;cancellable;signalController;constructor(tui,theme,message,options){super(),this.cancellable=options?.cancellable??!0;let borderColor=s=>theme.fg("border",s);this.addChild(new DynamicBorder(borderColor)),this.cancellable?this.loader=new CancellableLoader(tui,s=>theme.fg("accent",s),s=>theme.fg("muted",s),message):(this.signalController=new AbortController,this.loader=new Loader(tui,s=>theme.fg("accent",s),s=>theme.fg("muted",s),message)),this.addChild(this.loader),this.cancellable&&(this.addChild(new Spacer(1)),this.addChild(new Text(keyHint("tui.select.cancel","cancel"),1,0))),this.addChild(new Spacer(1)),this.addChild(new DynamicBorder(borderColor))}get signal(){return this.cancellable?this.loader.signal:this.signalController?.signal??new AbortController().signal}set onAbort(fn){this.cancellable&&(this.loader.onAbort=fn)}handleInput(data){this.cancellable&&this.loader.handleInput(data)}dispose(){"dispose"in this.loader&&typeof this.loader.dispose=="function"?this.loader.dispose():"stop"in this.loader&&typeof this.loader.stop=="function"&&this.loader.stop()}};var SHOW_IMAGES_SELECT_LIST_LAYOUT={minPrimaryColumnWidth:12,maxPrimaryColumnWidth:32},ShowImagesSelectorComponent=class extends Container{selectList;constructor(currentValue,onSelect,onCancel){super();let items=[{value:"yes",label:"Yes",description:"Show images inline in terminal"},{value:"no",label:"No",description:"Show text placeholder instead"}];this.addChild(new DynamicBorder),this.selectList=new SelectList(items,5,getSelectListTheme(),SHOW_IMAGES_SELECT_LIST_LAYOUT),this.selectList.setSelectedIndex(currentValue?0:1),this.selectList.onSelect=item=>{onSelect(item.value==="yes")},this.selectList.onCancel=()=>{onCancel()},this.addChild(this.selectList),this.addChild(new DynamicBorder)}getSelectList(){return this.selectList}};var THEME_SELECT_LIST_LAYOUT={minPrimaryColumnWidth:12,maxPrimaryColumnWidth:32},ThemeSelectorComponent=class extends Container{selectList;onPreview;constructor(currentTheme,onSelect,onCancel,onPreview){super(),this.onPreview=onPreview;let themes=getAvailableThemes(),themeItems=themes.map(name=>({value:name,label:name,description:name===currentTheme?"(current)":void 0}));this.addChild(new DynamicBorder),this.selectList=new SelectList(themeItems,10,getSelectListTheme(),THEME_SELECT_LIST_LAYOUT);let currentIndex=themes.indexOf(currentTheme);currentIndex!==-1&&this.selectList.setSelectedIndex(currentIndex),this.selectList.onSelect=item=>{onSelect(item.value)},this.selectList.onCancel=()=>{onCancel()},this.selectList.onSelectionChange=item=>{this.onPreview(item.value)},this.addChild(this.selectList),this.addChild(new DynamicBorder)}getSelectList(){return this.selectList}};function compareVersions(a,b){let pa=a.split(".").map(part=>Number.parseInt(part,10)||0),pb=b.split(".").map(part=>Number.parseInt(part,10)||0),length=Math.max(pa.length,pb.length);for(let index=0;index<length;index+=1){let diff=(pa[index]??0)-(pb[index]??0);if(diff!==0)return diff}return 0}function createIntegrityAdapter(){return{seal(input){let manifest={pluginId:input.pluginId,version:input.version,source:input.source,payload:input.payload};return Object.freeze({...manifest,digest:stableJsonDigest(manifest)})},verify(manifest,expectation){let actualDigest=stableJsonDigest({pluginId:manifest.pluginId,version:manifest.version,source:manifest.source,payload:manifest.payload});if(expectation.digest!==void 0&&expectation.digest!==actualDigest)return{status:"tampered",expectedDigest:expectation.digest,actualDigest};if(expectation.sourceEquals!==void 0&&manifest.source!==expectation.sourceEquals)return{status:"source_rejected",reason:`Source "${manifest.source}" is not the accepted "${expectation.sourceEquals}"`,source:manifest.source};let range=expectation.versionRange;return range?.min!==void 0&&compareVersions(manifest.version,range.min)<0?{status:"incompatible",reason:`Version ${manifest.version} is below the required ${range.min}`,version:manifest.version}:range?.max!==void 0&&compareVersions(manifest.version,range.max)>0?{status:"incompatible",reason:`Version ${manifest.version} is above the accepted ${range.max}`,version:manifest.version}:{status:"accepted",pluginId:manifest.pluginId,version:manifest.version,digest:actualDigest}}}}function createMcpHttpTransport(options){let timeoutMs=options.timeoutMs??1e4,retryLimit=options.retryLimit??2,baseRetryMs=options.baseRetryMs??100,maxRetryMs=options.maxRetryMs??1600,now=options.now??(()=>Date.now()),sleep=options.sleep??(()=>{}),events=[],nextId=1,closed=!1,record=event=>{events.push(event),options.onEvent?.(event)},postOnce=async(body,requestOptions)=>{let controller=new AbortController,timer=setTimeout(()=>controller.abort(),requestOptions?.timeoutMs??timeoutMs);try{let response=await fetch(options.url,{method:"POST",headers:{"content-type":"application/json",accept:"application/json, text/event-stream",...options.headers??{}},body,signal:controller.signal}),text=await response.text();return{status:response.status,text}}catch(error){return{status:"connect_error",reason:error instanceof Error?`${error.name}: ${error.message}`:String(error)}}finally{clearTimeout(timer)}},postWithRetry=async(body,requestOptions)=>{for(let attempt=1;;attempt+=1){let response=await postOnce(body,requestOptions);if(response.status!=="connect_error"&&response.status<500&&response.status!==429)return record({kind:"response",at:now(),detail:`HTTP ${response.status}`,attempt}),response;let reason=response.status==="connect_error"?response.reason:`HTTP ${response.status}`;if(attempt>retryLimit)throw record({kind:"transport_error",at:now(),detail:`giving up after ${attempt-1} retries: ${reason}`,attempt}),new Error(`MCP HTTP transport error: ${reason}`);let waitedMs=Math.min(baseRetryMs*2**(attempt-1),maxRetryMs);record({kind:"retry",at:now(),detail:`attempt ${attempt} failed (${reason}); waiting ${waitedMs}ms`,attempt}),await sleep(waitedMs),attempt===1&&response.status==="connect_error"&&record({kind:"reconnect",at:now(),detail:"re-establishing HTTP connection",attempt})}},rpc=async(method,params,requestOptions)=>{if(closed)throw new Error("MCP HTTP transport is closed");let id=nextId;nextId+=1;let body=JSON.stringify({jsonrpc:"2.0",id,method,...params===void 0?{}:{params}}),response=await postWithRetry(body,requestOptions);if(response.status!==200)throw new Error(`MCP HTTP transport returned HTTP ${response.status}`);let parsed;try{parsed=JSON.parse(response.text)}catch(error){throw new Error(`MCP HTTP transport returned non-JSON body: ${error instanceof Error?error.message:String(error)}`)}if(parsed.error!==void 0)throw new Error(`MCP error ${parsed.error.code??""}: ${parsed.error.message??"unknown error"}`);return parsed.result};return{async request(method,params,requestOptions){return rpc(method,params,requestOptions)},async notify(method,params){await postWithRetry(JSON.stringify({jsonrpc:"2.0",method,...params===void 0?{}:{params}}),void 0)},async close(){closed=!0},events(){return Object.freeze([...events])}}}function createPluginHost(options){let plugins=[...options.plugins],errors=[],stateRef={current:"created"},messageOf=error=>error instanceof Error?error.message:String(error);return{get state(){return stateRef.current},get errors(){return Object.freeze([...errors])},async start(){let failures=0;for(let plugin of plugins)if(plugin.start)try{await plugin.start()}catch(error){failures+=1,errors.push({pluginId:plugin.pluginId,phase:"start",message:messageOf(error)})}return failures===0?(stateRef.current="started",{state:"started",errors:Object.freeze([...errors])}):failures===plugins.length?(stateRef.current="failed",{state:"failed",errors:Object.freeze([...errors])}):(stateRef.current="partial",{state:"partial",errors:Object.freeze([...errors])})},async dispose(){if(stateRef.current==="disposed")return{errors:Object.freeze([...errors]),leakedResources:Object.freeze([])};for(let plugin of[...plugins].reverse())if(plugin.dispose)try{await plugin.dispose()}catch(error){errors.push({pluginId:plugin.pluginId,phase:"dispose",message:messageOf(error)})}let leaked=[];for(let plugin of plugins)if(plugin.resources)for(let resource of plugin.resources()){try{await resource.release()}catch(error){errors.push({pluginId:plugin.pluginId,phase:"dispose",message:`resource ${resource.name}: ${messageOf(error)}`})}leaked.push(`${plugin.pluginId}/${resource.name}`)}return stateRef.current="disposed",{errors:Object.freeze([...errors]),leakedResources:Object.freeze(leaked)}}}}function createPluginSupervisor(options){let policy=options.policy,now=options.now??(()=>0),entries=new Map,events=[],queue=[];for(let plugin of options.plugins)entries.set(plugin.pluginId,{pluginId:plugin.pluginId,health:"healthy",restarts:0,lastBeatAt:now()});return{supervise(plugin){entries.set(plugin.pluginId,{pluginId:plugin.pluginId,health:"healthy",restarts:0,lastBeatAt:now()})},beat(pluginId){let entry=entries.get(pluginId);if(!entry)throw new Error(`Unknown supervised plugin: ${pluginId}`);entry.lastBeatAt=now(),entry.health="healthy",events.push({kind:"beat",pluginId,at:entry.lastBeatAt})},tick(at){for(let entry of entries.values())entry.health!=="unhealthy"&&at-entry.lastBeatAt>policy.heartbeatIntervalMs&&(entry.health="unhealthy",events.push({kind:"unhealthy",pluginId:entry.pluginId,at}))},restart(pluginId){let entry=entries.get(pluginId);if(!entry)return{status:"unknown"};if(entry.health==="exhausted")return{status:"exhausted",attempts:entry.restarts};if(entry.nextRestartAllowedAt!==void 0&&now()<entry.nextRestartAllowedAt)return{status:"restarted",attempt:entry.restarts};if(entry.restarts+=1,entry.restarts>policy.restartLimit)return entry.health="exhausted",events.push({kind:"exhausted",pluginId,at:now(),attempts:entry.restarts-1}),{status:"exhausted",attempts:entry.restarts-1};options.restartPlugin?.(pluginId,entry.restarts),entry.health="healthy",entry.lastBeatAt=now();let backoff=Math.min(policy.baseRestartMs*2**(entry.restarts-1),Number.MAX_SAFE_INTEGER);return entry.nextRestartAllowedAt=now()+backoff,events.push({kind:"restart",pluginId,at:now(),attempt:entry.restarts}),{status:"restarted",attempt:entry.restarts}},enqueue(event){return queue.length>=policy.queueCap?(events.push({kind:"queue_full",at:now()}),{status:"queue_full",size:queue.length}):(queue.push(event),{status:"enqueued",size:queue.length})},drain(){return Object.freeze(queue.splice(0,queue.length))},health(){return Object.freeze([...entries.values()].map(entry=>({...entry})))},get queueSize(){return queue.length}}}function createChildAgentFacade(options){let childDefinitionId=options.childDefinitionId??"child-agent-controller",owner=options.owner??"parent",definition=options.composition.define({id:childDefinitionId,version:options.childVersion??1,role:"child-agent-controller",run:(input,context)=>options.run(input,{parentInstanceId:options.parentInstanceId,signal:context?.signal})});return{childDefinitionId,spawnChild(input,spawnOptions){let instance=options.composition.create(definition,{parentInstanceId:options.parentInstanceId}),childInstanceId=instance.id,settledRevision,runPromise=instance.acquireControllerLease(owner).then(async lease=>{try{await instance.run(input,{lease,signal:spawnOptions?.signal}).result}catch{}let instanceResult=await instance.wait();return settledRevision=instanceResult.revision,lease.isActive()&&await lease.release(),{status:instanceResult.status,...instanceResult.output!==void 0?{output:instanceResult.output}:{},...instanceResult.error!==void 0?{error:instanceResult.error instanceof Error?instanceResult.error:new Error(String(instanceResult.error))}:{},revision:instanceResult.revision}});return{childInstanceId,resultRef:()=>settledRevision===void 0?void 0:Object.freeze({childInstanceId,revision:settledRevision}),wait:()=>runPromise,cancel:reason=>instance.cancel(reason)}}}}function wireProfileDependencies(input){let registry=new Map;for(let capability of input.availableCapabilities)registry.set(capability.id,capability.version);let disabled=new Set(input.disabledPluginIds??[]),plugins=[],missing=[];for(let plugin of input.resolvedPlugins){if(disabled.has(plugin.pluginId)){plugins.push({pluginId:plugin.pluginId,pluginVersion:plugin.pluginVersion,status:"skipped_disabled",wired:[]});continue}let wired=[];for(let reference of plugin.capabilityRefs){let availableVersion=registry.get(reference.id);availableVersion===void 0?missing.push({pluginId:plugin.pluginId,capabilityId:reference.id,requestedVersion:reference.version,reason:"missing"}):availableVersion!==reference.version?missing.push({pluginId:plugin.pluginId,capabilityId:reference.id,requestedVersion:reference.version,availableVersion,reason:"version_mismatch"}):wired.push({id:reference.id,version:reference.version})}plugins.push({pluginId:plugin.pluginId,pluginVersion:plugin.pluginVersion,status:"wired",wired})}return{status:missing.length>0?"missing":"wired",plugins,missing}}var GOAL_TERMINAL=new Set(["achieved","archived"]),PLAN_TERMINAL=new Set(["completed","discarded"]),TODO_TERMINAL=new Set(["completed","cancelled"]);function recoverPlansForBranch(plans,currentBranch){let entries=plans.map(plan=>{let terminal=PLAN_TERMINAL.has(plan.status);return plan.branch!==currentBranch?{planId:plan.planId,outcome:"skipped_other_branch",branch:plan.branch,statusBefore:plan.status}:{planId:plan.planId,outcome:terminal?"terminal_kept":"recovered",branch:plan.branch,statusBefore:plan.status}});return{currentBranch,entries:Object.freeze(entries)}}function buildRestartReport(snapshots,restored,owner){let records=[],identical=!0,compare=(domain,entityId,statusAfter,revisionAfter,evidenceCount,terminal,statusBefore,revisionBefore)=>{(statusAfter!==statusBefore||revisionAfter!==revisionBefore)&&(identical=!1),records.push({domain,entityId,statusAfter,revisionAfter,evidenceCount,terminal})};for(let goal of snapshots.goal??[]){let after=restored.goals.get(goal.goalId,owner);if(!after){identical=!1,records.push({domain:"goal",entityId:goal.goalId,statusAfter:"missing",revisionAfter:0,evidenceCount:0,terminal:!1});continue}compare("goal",goal.goalId,after.status,after.revision,after.evidence.length,GOAL_TERMINAL.has(after.status),goal.status,goal.revision)}for(let plan of snapshots.plan??[]){let after=restored.plans.get(plan.planId,owner);if(!after){identical=!1,records.push({domain:"plan",entityId:plan.planId,statusAfter:"missing",revisionAfter:0,evidenceCount:0,terminal:!1});continue}compare("plan",plan.planId,after.status,after.revisionNo,after.evidence.length,PLAN_TERMINAL.has(after.status),plan.status,plan.revisionNo)}for(let todo of snapshots.todo??[]){let after=restored.todos.get(todo.todoId,owner);if(!after){identical=!1,records.push({domain:"todo",entityId:todo.todoId,statusAfter:"missing",revisionAfter:0,evidenceCount:0,terminal:!1});continue}compare("todo",todo.todoId,after.status,after.revision,after.evidence.length,TODO_TERMINAL.has(after.status),todo.status,todo.revision)}return{records:Object.freeze(records),identical}}var WRITABLE_SCOPES=["session","cycle","long-term"];function assertNonEmptyString2(value,label){if(typeof value!="string"||value.trim().length===0)throw new Error(`${label} must be a non-empty string`)}function assertIOSchemaRef(value,label){if(value===null||typeof value!="object"||Array.isArray(value))throw new Error(`${label} must be a plain object`);let record=value;if(assertNonEmptyString2(record.schemaId,`${label}.schemaId`),typeof record.schemaVersion!="number"||!Number.isSafeInteger(record.schemaVersion)||record.schemaVersion<1)throw new Error(`${label}.schemaVersion must be a positive safe integer`);return Object.freeze({schemaId:record.schemaId,schemaVersion:record.schemaVersion})}function validateRoleMetadataV1(value){if(value===null||typeof value!="object"||Array.isArray(value))throw new Error("Role metadata must be a plain object");let record=value,required=["roleId","title","input","output","capabilityDependencies","writableScopes","concurrency","completionCriteria"];for(let key of required)if(!(key in record))throw new Error(`Role metadata is missing required field: ${key}`);let unsupported=Object.keys(record).filter(key=>!required.includes(key)).sort();if(unsupported.length>0)throw new Error(`Role metadata has unsupported fields: ${unsupported.join(", ")}`);assertNonEmptyString2(record.roleId,"Role metadata.roleId"),assertNonEmptyString2(record.title,"Role metadata.title");let input=assertIOSchemaRef(record.input,"Role metadata.input"),output=assertIOSchemaRef(record.output,"Role metadata.output");if(!Array.isArray(record.capabilityDependencies))throw new Error("Role metadata.capabilityDependencies must be an array");let capabilityDependencies=record.capabilityDependencies.map((item,index)=>{let depLabel=`Role metadata.capabilityDependencies[${index}]`;if(item===null||typeof item!="object"||Array.isArray(item))throw new Error(`${depLabel} must be a plain object`);let dep=item;if(assertNonEmptyString2(dep.capabilityId,`${depLabel}.capabilityId`),typeof dep.capabilityVersion!="number"||!Number.isSafeInteger(dep.capabilityVersion)||dep.capabilityVersion<1)throw new Error(`${depLabel}.capabilityVersion must be a positive safe integer`);if(typeof dep.required!="boolean")throw new Error(`${depLabel}.required must be boolean`);return Object.freeze({capabilityId:dep.capabilityId,capabilityVersion:dep.capabilityVersion,required:dep.required})});if(!Array.isArray(record.writableScopes))throw new Error("Role metadata.writableScopes must be an array");for(let[index,scope]of record.writableScopes.entries())if(!WRITABLE_SCOPES.includes(scope))throw new Error(`Role metadata.writableScopes[${index}] is invalid`);if(assertNonEmptyString2(record.completionCriteria,"Role metadata.completionCriteria"),record.concurrency!=="single"&&record.concurrency!=="parallel")throw new Error("Role metadata.concurrency is invalid");return Object.freeze({roleId:record.roleId,title:record.title,input,output,capabilityDependencies:Object.freeze(capabilityDependencies),writableScopes:Object.freeze([...record.writableScopes]),concurrency:record.concurrency,completionCriteria:record.completionCriteria})}function createRoleCatalog(initial=[]){let roles=new Map;for(let metadata of initial){let validated=validateRoleMetadataV1(metadata);if(roles.has(validated.roleId))throw new Error(`Role already registered: ${validated.roleId}`);roles.set(validated.roleId,validated)}return{register(metadata){let validated=validateRoleMetadataV1(metadata);if(roles.has(validated.roleId))throw new Error(`Role already registered: ${validated.roleId}`);return roles.set(validated.roleId,validated),validated},get(roleId){return roles.get(roleId)},list(){return Object.freeze([...roles.values()].sort((left,right)=>left.roleId.localeCompare(right.roleId)))},findByCapability(capabilityId){return Object.freeze([...roles.values()].filter(role=>role.capabilityDependencies.some(dependency=>dependency.capabilityId===capabilityId)))}}}var ARCHITECTURE_ROLE={roleId:"architecture-analyst",title:"Architecture Analyst",input:{schemaId:"role/architecture-input@1",schemaVersion:1},output:{schemaId:"role/architecture-output@1",schemaVersion:1},capabilityDependencies:[{capabilityId:"tool.read",capabilityVersion:1,required:!0}],writableScopes:["session"],concurrency:"parallel",completionCriteria:"module structure findings recorded"},IMPLEMENTER_ROLE={roleId:"implementer",title:"Implementer",input:{schemaId:"role/implement-input@1",schemaVersion:1},output:{schemaId:"role/implement-output@1",schemaVersion:1},capabilityDependencies:[{capabilityId:"tool.edit",capabilityVersion:1,required:!0},{capabilityId:"tool.write",capabilityVersion:1,required:!1}],writableScopes:["session","cycle"],concurrency:"single",completionCriteria:"patch produced for the requested spec"},TEST_DESIGNER_ROLE={roleId:"test-designer",title:"Test Designer",input:{schemaId:"role/test-input@1",schemaVersion:1},output:{schemaId:"role/test-output@1",schemaVersion:1},capabilityDependencies:[{capabilityId:"tool.read",capabilityVersion:1,required:!0}],writableScopes:["session"],concurrency:"parallel",completionCriteria:"test cases derived from the spec"},FIRST_BATCH_ROLES=[{metadata:ARCHITECTURE_ROLE,run:async input=>({result:`architecture findings for: ${input.spec.slice(0,64)}`})},{metadata:IMPLEMENTER_ROLE,run:async input=>({result:`patch for: ${input.spec.slice(0,64)}`})},{metadata:TEST_DESIGNER_ROLE,run:async input=>({result:`test cases for: ${input.spec.slice(0,64)}`})}];function createFirstBatchRoleSlices(catalog){let roles=FIRST_BATCH_ROLES.map(role=>({metadata:validateRoleMetadataV1(role.metadata),run:role.run}));for(let role of roles)catalog.register(role.metadata);let runners=new Map(roles.map(role=>[role.metadata.roleId,role.run]));return{roles,async run(roleId,spec){let run=runners.get(roleId);if(!run)throw new Error(`Unknown first-batch role: ${roleId}`);return{roleId,result:(await run({spec})).result}}}}function createGoalPlugin(options){let transitions=options.transitions,goalHistory=(goalId,owner)=>transitions.history(goalId).filter(record=>record.domain==="goal"&&record.owner===owner),current=(goalId,owner)=>{let state=transitions.currentStatus("goal",goalId);if(!(state===void 0||goalHistory(goalId,owner).length===0))return{status:state.status,revision:state.revision}},titleOf=(goalId,owner)=>{for(let record of goalHistory(goalId,owner)){if(record.fromStatus!==null)continue;let payload=record.payload;if(payload!==null&&typeof payload=="object"&&!Array.isArray(payload)){let title=payload.title;if(typeof title=="string")return title}}return goalId},goalGet=(goalId,owner)=>{let state=current(goalId,owner);if(!state)return;let lastEvidence=[...goalHistory(goalId,owner)].reverse().find(record=>record.evidence.length>0)?.evidence??[];return{goalId,owner,title:titleOf(goalId,owner),status:state.status,evidence:lastEvidence,revision:state.revision}},replayedGoal=(goalId,owner,toStatus,operationId)=>operationId&&goalHistory(goalId,owner).some(record=>record.toStatus===toStatus&&record.operationId===operationId)?goalGet(goalId,owner):void 0,transitionGoal=(goalId,owner,fromStatus,toStatus,goalOptions)=>{transitions.transition({domain:"goal",entityId:goalId,owner,fromStatus,toStatus,operationId:goalOptions.operationId??`${toStatus}:${goalId}`,evidence:goalOptions.evidence,payload:goalOptions.payload});let state=transitions.currentStatus("goal",goalId);return{goalId,owner,title:titleOf(goalId,owner),status:state?.status,evidence:goalOptions.evidence??[],revision:state?.revision??0}};return{createGoal({goalId,owner,title}){if(title.trim().length===0)throw new Error("Goal title must be a non-empty string");return transitionGoal(goalId,owner,null,"draft",{payload:{title},operationId:`create:${goalId}`})},activate(goalId,owner,activateOptions){let replayed=replayedGoal(goalId,owner,"active",activateOptions?.operationId);if(replayed)return replayed;let existing=current(goalId,owner);if(existing?.status!=="draft")throw new Error(`Goal ${goalId} must be in draft status to activate (current: ${existing?.status??"missing"})`);return transitionGoal(goalId,owner,"draft","active",{operationId:activateOptions?.operationId})},achieve(goalId,owner,evidence,achieveOptions){let replayed=replayedGoal(goalId,owner,"achieved",achieveOptions?.operationId);if(replayed)return replayed;let existing=current(goalId,owner);if(existing?.status!=="active")throw new Error(`Goal ${goalId} must be active to achieve (current: ${existing?.status??"missing"})`);if(evidence.length===0)throw new Error("Achieving a goal requires at least one evidence reference");return transitionGoal(goalId,owner,"active","achieved",{evidence,operationId:achieveOptions?.operationId})},archive(goalId,owner){let existing=current(goalId,owner);if(!existing||existing.status==="achieved"||existing.status==="archived")throw new Error(`Goal ${goalId} cannot be archived from status ${existing?.status??"missing"}`);return transitionGoal(goalId,owner,existing.status,"archived",{})},get(goalId,owner){return goalGet(goalId,owner)}}}function planPayloadOf(record){let payload=record.payload;if(payload!==null&&typeof payload=="object"&&!Array.isArray(payload))return payload}function createPlanPlugin(options){let transitions=options.transitions,planHistory=(planId,owner)=>transitions.history(planId).filter(record=>record.domain==="plan"&&record.owner===owner),current=(planId,owner)=>{let state=transitions.currentStatus("plan",planId);if(!(state===void 0||planHistory(planId,owner).length===0))return{status:state.status,revisionNo:state.revision}},planGet=(planId,owner)=>{let state=current(planId,owner);if(!state)return;let history=planHistory(planId,owner),createPayload=planPayloadOf(history.find(record=>record.fromStatus===null)??{}),lastLinked=[...history].reverse().map(record=>planPayloadOf(record)?.linkedRevision).find(revision=>typeof revision=="number"),lastEvidence=[...history].reverse().find(record=>record.evidence.length>0)?.evidence??[];return{planId,owner,title:createPayload?.title??planId,branch:createPayload?.branch??"",steps:createPayload?.steps??[],status:state.status,...lastLinked===void 0?{}:{revision:lastLinked},evidence:lastEvidence,revisionNo:state.revisionNo}},replayedPlan=(planId,owner,toStatus,operationId)=>operationId&&planHistory(planId,owner).some(record=>record.toStatus===toStatus&&record.operationId===operationId)?planGet(planId,owner):void 0,transitionPlan=(planId,owner,fromStatus,toStatus,planOptions)=>(transitions.transition({domain:"plan",entityId:planId,owner,fromStatus,toStatus,operationId:planOptions.operationId??`${toStatus}:${planId}`,evidence:planOptions.evidence,payload:planOptions.payload}),planGet(planId,owner));return{createPlan({planId,owner,title,branch,steps}){if(title.trim().length===0)throw new Error("Plan title must be a non-empty string");if(branch.trim().length===0)throw new Error("Plan branch must be a non-empty string");if(steps.length===0)throw new Error("Plan requires at least one step");let stepIds=new Set;for(let step of steps){if(typeof step.stepId!="string"||step.stepId.trim().length===0)throw new Error("Plan stepId must be a non-empty string");if(typeof step.title!="string"||step.title.trim().length===0)throw new Error("Plan step title must be a non-empty string");if(stepIds.has(step.stepId))throw new Error(`Duplicate plan stepId: ${step.stepId}`);stepIds.add(step.stepId)}return transitionPlan(planId,owner,null,"draft",{payload:{title,branch,steps:[...steps]},operationId:`create:${planId}`})},activate(planId,owner,activateOptions){let replayed=replayedPlan(planId,owner,"active",activateOptions?.operationId);if(replayed)return replayed;let plan=planGet(planId,owner);if(plan?.status!=="draft")throw new Error(`Plan ${planId} must be in draft status to activate (current: ${plan?.status??"missing"})`);return transitionPlan(planId,owner,"draft","active",{operationId:activateOptions?.operationId})},linkRevision(planId,owner,revision,linkOptions){let replayed=replayedPlan(planId,owner,"active",linkOptions?.operationId);if(replayed)return replayed;let plan=planGet(planId,owner);if(plan?.status!=="active")throw new Error(`Plan ${planId} must be active to link a revision (current: ${plan?.status??"missing"})`);if(!Number.isSafeInteger(revision)||revision<1)throw new Error(`Plan revision must be a positive safe integer, got ${revision}`);return transitionPlan(planId,owner,"active","active",{payload:{title:plan.title,branch:plan.branch,steps:plan.steps,linkedRevision:revision},operationId:linkOptions?.operationId??`link:${planId}:${revision}`})},complete(planId,owner,evidence,completeOptions){let replayed=replayedPlan(planId,owner,"completed",completeOptions?.operationId);if(replayed)return replayed;let plan=planGet(planId,owner);if(plan?.status!=="active")throw new Error(`Plan ${planId} must be active to complete (current: ${plan?.status??"missing"})`);if(evidence.length===0)throw new Error("Completing a plan requires at least one evidence reference");let target=completeOptions?.atRevision??plan.revision;if(typeof target!="number")throw new Error(`Plan ${planId} requires atRevision or a linked revision to complete`);return transitionPlan(planId,owner,"active","completed",{evidence,payload:{title:plan.title,branch:plan.branch,steps:plan.steps,linkedRevision:target},operationId:completeOptions?.operationId})},discard(planId,owner){let plan=planGet(planId,owner);if(!plan||plan.status==="completed"||plan.status==="discarded")throw new Error(`Plan ${planId} cannot be discarded from status ${plan?.status??"missing"}`);return transitionPlan(planId,owner,plan.status,"discarded",{})},get(planId,owner){return planGet(planId,owner)}}}function assertDeclaration(value){if(!["confirmation","permission","dangerous_operation"].includes(value.policyKind))throw new Error(`Policy manifest policyKind is invalid: ${String(value.policyKind)}`);if(typeof value.policyId!="string"||value.policyId.trim().length===0)throw new Error("Policy manifest policyId must be a non-empty string");if(typeof value.enabled!="boolean")throw new Error(`Policy manifest ${value.policyId}: enabled must be stated explicitly`)}function createPolicyManifestBuilder(){let buildManifest=input=>{if(input.profileId.trim().length===0)throw new Error("Policy manifest profileId must be a non-empty string");for(let declaration of input.declarations)assertDeclaration(declaration);let declarations=Object.freeze(input.declarations.map(declaration=>Object.freeze({...declaration})));return Object.freeze({manifestVersion:1,profileId:input.profileId,declarations,manifestDigest:stableJsonDigest(declarations)})};return{buildManifest,selectExternalPolicy(manifest,input){assertDeclaration(input.external??{policyKind:input.policyKind,policyId:input.policyId,description:"",enabled:!1});let kept=manifest.declarations.filter(declaration=>!(declaration.policyKind===input.policyKind&&declaration.policyId===input.policyId)),existed=kept.length!==manifest.declarations.length,declarations=input.external===null?kept:[...kept,input.external];return{manifest:buildManifest({profileId:manifest.profileId,declarations}),change:{policyKind:input.policyKind,policyId:input.policyId,action:input.external===null?"disabled":"external_selected",reason:input.reason}}}}}var DEFINITION_VERSION=1,FIRST_BATCH_RUNS=new Map(FIRST_BATCH_ROLES.map(role=>[role.metadata.roleId,role.run]));function runFirstBatchRole(roleId,input,context){let callback=FIRST_BATCH_RUNS.get(roleId);if(!callback)throw new Error(`No run binding for role: ${roleId}`);return callback(input,context)}function createRoleRunner(options){let catalog=options.catalog;function requireRole(roleId){let metadata=catalog.get(roleId);if(!metadata)throw new Error(`Unknown role: ${roleId}`);return metadata}async function execute(roleId,input,context){return requireRole(roleId),options.run?options.run(roleId,input,context):runFirstBatchRole(roleId,input,context)}return{catalog,listRoleIds(){return catalog.list().map(role=>role.roleId)},createDefinition(roleId){let metadata=requireRole(roleId);return{id:`role:${metadata.roleId}`,version:DEFINITION_VERSION,role:"child-agent-controller",...options.owner===void 0?{}:{owner:options.owner},run:(input,context)=>execute(metadata.roleId,input,context)}},checkCapabilities(roleId,availableCapabilities){let metadata=requireRole(roleId),registry=new Map(availableCapabilities.map(capability=>[capability.id,capability.version])),missing=[];for(let dependency of metadata.capabilityDependencies){if(!dependency.required)continue;let availableVersion=registry.get(dependency.capabilityId);availableVersion===void 0?missing.push({roleId,capabilityId:dependency.capabilityId,requestedVersion:dependency.capabilityVersion,reason:"missing"}):availableVersion!==dependency.capabilityVersion&&missing.push({roleId,capabilityId:dependency.capabilityId,requestedVersion:dependency.capabilityVersion,availableVersion,reason:"version_mismatch"})}return{roleId,status:missing.length>0?"missing":"satisfied",missing}},run(roleId,input,context){return execute(roleId,input,context)}}}function assembleRoles(input){let catalog=createRoleCatalog(input.roles.map(role=>role.metadata)),overrides=new Map(input.roles.flatMap(role=>role.run?[[role.metadata.roleId,role.run]]:[])),runner=createRoleRunner({catalog,...input.owner===void 0?{}:{owner:input.owner},...overrides.size>0?{run:((roleId,runInput,context)=>{let override=overrides.get(roleId);return override?override(runInput,context):runFirstBatchRole(roleId,runInput,context)})}:{}}),roleIds=catalog.list().map(role=>role.roleId),missing=roleIds.flatMap(roleId=>runner.checkCapabilities(roleId,input.availableCapabilities).missing);return Object.freeze({catalog,runner,roleIds:Object.freeze([...roleIds]),capabilityDiagnostics:Object.freeze({status:missing.length>0?"missing":"satisfied",missing:Object.freeze(missing)})})}var DEFAULT_ROLE_AGGREGATION_LIMIT_BYTES=16384,DEFAULT_ORCHESTRATION_OWNER="role-orchestrator";function createRoleOrchestrator(options){let owner=options.owner??DEFAULT_ORCHESTRATION_OWNER,definitions=new Map,activeOverrides=new Map,runInFlight=!1;function requireMetadata(roleId){let metadata=options.runner.catalog.get(roleId);if(!metadata)throw new Error(`Unknown role: ${roleId}`);return metadata}function definitionFor(roleId){let cached=definitions.get(roleId);if(cached)return cached;let definition={...options.runner.createDefinition(roleId),run:(input,context)=>{let override=activeOverrides.get(roleId);return override?override(input,context):options.runner.run(roleId,input,context)}},registered=options.composition.define(definition);return definitions.set(roleId,registered),registered}async function runOne(roleId,spec,settled){let definition=definitionFor(roleId),instance=options.composition.create({id:definition.id,version:definition.version},{parentInstanceId:options.parentInstanceId}),childInstanceId=instance.id,lease=await instance.acquireControllerLease(owner);try{let operation=instance.run({spec},{lease});try{await operation.result}catch{}let terminal=await instance.wait(),error=terminal.error===void 0?void 0:terminal.error instanceof Error?terminal.error.message:String(terminal.error);settled.set(roleId,{roleId,definitionId:definition.id,childInstanceId,revision:terminal.revision,status:terminal.status,...terminal.output!==void 0?{output:terminal.output}:{},...error!==void 0?{error}:{}})}finally{lease.isActive()&&await lease.release()}}async function runRoles(request){if(runInFlight)throw new Error("Role orchestrator is already running an orchestration");let seen=new Set;for(let roleId of request.roleIds){if(typeof roleId!="string"||roleId.trim().length===0)throw new Error("Role id must be a non-empty string");if(seen.has(roleId))throw new Error(`Duplicate roleId in orchestration request: ${roleId}`);seen.add(roleId)}let overrides=new Map;for(let override of request.runs??[]){if(overrides.has(override.roleId))throw new Error(`Duplicate run override for role: ${override.roleId}`);overrides.set(override.roleId,override.run)}for(let roleId of overrides.keys())if(!seen.has(roleId))throw new Error(`Run override for unrequested role: ${roleId}`);let sorted=[...request.roleIds].sort((left,right)=>left.localeCompare(right));for(let roleId of sorted)requireMetadata(roleId),definitionFor(roleId);runInFlight=!0;try{activeOverrides=overrides;let settled=new Map;if(sorted.length>0){let parallelIds=sorted.filter(roleId=>requireMetadata(roleId).concurrency==="parallel"),singleIds=sorted.filter(roleId=>requireMetadata(roleId).concurrency==="single");await Promise.all(parallelIds.map(roleId=>runOne(roleId,request.spec,settled)));for(let roleId of singleIds)await runOne(roleId,request.spec,settled)}return aggregate(sorted,settled,request)}finally{activeOverrides=new Map,runInFlight=!1}}function aggregate(sorted,settled,request){let limitBytes=request.limitBytes??options.limitBytes??16384,used=0,truncated=!1,frozenEntries=sorted.map(roleId=>{let outcome=settled.get(roleId);if(!outcome)throw new Error(`Orchestration outcome missing for role: ${roleId}`);let base={roleId:outcome.roleId,definitionId:outcome.definitionId,childInstanceId:outcome.childInstanceId,revision:outcome.revision,status:outcome.status};if(outcome.status!=="succeeded"||outcome.output===void 0)return Object.freeze({...base,truncated:!1,missing:!0,...outcome.error!==void 0?{error:outcome.error}:{}});let size=JSON.stringify(outcome.output).length;return used+size>limitBytes?(truncated=!0,Object.freeze({...base,truncated:!0,missing:!1})):(used+=size,Object.freeze({...base,truncated:!1,missing:!1,result:outcome.output}))}),entryByRole=new Map(frozenEntries.map(entry=>[entry.roleId,entry])),evaluate=request.evaluateCompletion??options.evaluateCompletion,frozenChecks=sorted.map(roleId=>{let criteria=requireMetadata(roleId).completionCriteria,outcome=settled.get(roleId),entry=entryByRole.get(roleId),output=outcome?.output;if(!evaluate||!output||entry?.truncated===!0)return Object.freeze({roleId,criteria,status:"unchecked"});let verdict=evaluate({roleId,criteria,result:output});return Object.freeze({roleId,criteria,status:verdict===!0?"satisfied":verdict===!1?"unmet":"unchecked"})});return Object.freeze({entries:Object.freeze(frozenEntries),truncated,completionChecks:Object.freeze(frozenChecks)})}return{composition:options.composition,runner:options.runner,parentInstanceId:options.parentInstanceId,runRoles}}function createRootAgentFacade(options){let definitionId=options.rootDefinitionId??"root-agent-controller",owner=options.owner??"root-facade",definition=options.composition.define({id:definitionId,version:options.rootVersion??1,role:"root-agent-controller",run:(input,context)=>options.run(input,context)}),turnInFlight=!1;return{definitionId,async runTurn(input,runOptions){if(turnInFlight)throw new Error("Root facade is already running a turn");turnInFlight=!0;try{let instance=options.composition.create(definition),lease=await instance.acquireControllerLease(owner),leaseId=lease.id;try{await instance.run(input,{lease,signal:runOptions?.signal}).result;let instanceResult=await instance.wait();return{status:instanceResult.status,...instanceResult.output!==void 0?{output:instanceResult.output}:{},...instanceResult.error instanceof Error?{error:instanceResult.error}:{},revision:instanceResult.revision,instanceId:instance.id,leaseId}}finally{lease.isActive()&&await lease.release()}}finally{turnInFlight=!1}}}}function createSkillDiscoveryWiring(){let items=new Map,keyOf=item=>`${item.sourceKind}:${item.itemId}`;return{register(item){if(item.itemId.trim().length===0)throw new Error("Discovered item id must be a non-empty string");let existing=items.get(keyOf(item));if(existing&&existing.version!==item.version)throw new Error(`Item ${keyOf(item)} re-registered with a different version (${existing.version} -> ${item.version})`);items.set(keyOf(item),{...item,capabilities:[...item.capabilities]})},deriveMcpItem({serverId,version,tools,enabled=!0}){return{sourceKind:"mcp",itemId:serverId,version,capabilities:tools.map(tool=>({id:`mcp:${serverId}:${tool.name}`,version:1})),enabled}},wireDiscoveredDependencies({availableCapabilities,disabledItemIds}){let disabled=new Set(disabledItemIds??[]),enabledItems=[...items.values()].filter(item=>item.enabled&&!disabled.has(keyOf(item))),byCapability=new Map;for(let item of enabledItems)for(let capability of item.capabilities){let list=byCapability.get(capability.id)??[];list.some(entry=>entry.itemId===item.itemId)||list.push({sourceKind:item.sourceKind,itemId:item.itemId,version:capability.version}),byCapability.set(capability.id,list)}let conflicts=[];for(let[capabilityId,declarations]of byCapability)new Set(declarations.map(entry=>entry.version)).size>1&&conflicts.push({capabilityId,declarations});let manifests=[...items.values()].map(item=>({pluginId:keyOf(item),pluginVersion:item.version,capabilityRefs:[...item.capabilities]})),wiring=wireProfileDependencies({resolvedPlugins:manifests,availableCapabilities,disabledPluginIds:disabledItemIds});return{conflicts:Object.freeze(conflicts),wiring}}}}function assertNonEmptyString3(value,label){if(typeof value!="string"||value.trim().length===0)throw new Error(`${label} must be a non-empty string`)}function validateEvidence(value,label){if(value===void 0)return[];if(!Array.isArray(value))throw new Error(`${label} must be an array`);return value.map((item,index)=>{let depLabel=`${label}[${index}]`;if(item===null||typeof item!="object"||Array.isArray(item))throw new Error(`${depLabel} must be a plain object`);let record=item;return assertNonEmptyString3(record.kind,`${depLabel}.kind`),assertNonEmptyString3(record.ref,`${depLabel}.ref`),record.digest!==void 0&&assertNonEmptyString3(record.digest,`${depLabel}.digest`),Object.freeze({kind:record.kind,ref:record.ref,...record.digest===void 0?{}:{digest:record.digest}})})}function validatePayload(value,label){if(value===void 0)return;let seen=new Set,check=node=>{if(!(node===null||typeof node=="string"||typeof node=="boolean")){if(typeof node=="number"){if(!Number.isFinite(node))throw new Error(`${label} must be JSON-safe: ${node} is not a finite number`);return}if(typeof node=="object"){if(seen.has(node))throw new Error(`${label} must be JSON-safe: circular reference`);if(seen.add(node),Array.isArray(node))for(let item of node)check(item);else{let proto=Object.getPrototypeOf(node);if(proto!==Object.prototype&&proto!==null)throw new Error(`${label} must be a plain object`);for(let entry of Object.entries(node)){if(entry[1]===void 0)throw new Error(`${label} must be JSON-safe: ${entry[0]} is undefined`);check(entry[1])}}seen.delete(node);return}throw new Error(`${label} must be JSON-safe: unsupported value of type ${typeof node}`)}};return check(value),JSON.parse(JSON.stringify(value))}function createTransitionStore(options={}){let now=options.now??(()=>Date.now()),recordsByEntity=new Map,idempotency=new Map,currentStatus=new Map,revisions=new Map,entityKey=(domain,entityId)=>`${domain}\0${entityId}`;return{transition(input){assertNonEmptyString3(input.domain,"Transition domain"),assertNonEmptyString3(input.entityId,"Transition entityId"),assertNonEmptyString3(input.owner,"Transition owner"),assertNonEmptyString3(input.operationId,"Transition operationId"),assertNonEmptyString3(input.toStatus,"Transition toStatus");let evidence=validateEvidence(input.evidence,"Transition evidence"),payload=validatePayload(input.payload,"Transition payload"),key=`${entityKey(input.domain,input.entityId)}\0${input.operationId}\0${input.toStatus}`,existing=idempotency.get(key);if(existing)return{record:existing,deduped:!0};let entityKeyId=entityKey(input.domain,input.entityId),current=currentStatus.get(entityKeyId),fromStatus=input.fromStatus;if((current?.status??null)!==fromStatus)throw new Error(`Transition conflict: expected fromStatus ${JSON.stringify(current?.status??null)}, got ${JSON.stringify(fromStatus)}`);let revision=(revisions.get(entityKeyId)??0)+1;revisions.set(entityKeyId,revision);let record=Object.freeze({domain:input.domain,entityId:input.entityId,owner:input.owner,fromStatus,toStatus:input.toStatus,operationId:input.operationId,evidence:Object.freeze(evidence),...payload===void 0?{}:{payload},revision,at:input.at??now()}),log=recordsByEntity.get(entityKeyId)??[];return log.push(record),recordsByEntity.set(entityKeyId,log),currentStatus.set(entityKeyId,{status:input.toStatus,revision}),idempotency.set(key,record),{record,deduped:!1}},currentStatus(domain,entityId){return currentStatus.get(entityKey(domain,entityId))},history(entityId){return Object.freeze([...recordsByEntity.entries()].filter(([entityKeyId])=>entityKeyId.endsWith(`\0${entityId}`)).flatMap(([,log])=>log))},replay(history){for(let record of history)this.transition({domain:record.domain,entityId:record.entityId,owner:record.owner,fromStatus:record.fromStatus,toStatus:record.toStatus,operationId:record.operationId,evidence:record.evidence,payload:record.payload,at:record.at})},entities(){return Object.freeze([...new Set([...currentStatus.keys()].map(key=>key.split("\0")[1]))])}}}function contentHash2(content){let hash=2166136261;for(let index=0;index<content.length;index+=1)hash^=content.charCodeAt(index),hash=Math.imul(hash,16777619);return(hash>>>0).toString(36)}function todoPayloadOf(record){let payload=record.payload;if(payload!==null&&typeof payload=="object"&&!Array.isArray(payload))return payload}function createTodoPlugin(options){let transitions=options.transitions,todoHistory=(todoId,owner)=>transitions.history(todoId).filter(record=>record.domain==="todo"&&record.owner===owner),current=(todoId,owner)=>{let state=transitions.currentStatus("todo",todoId);if(!(state===void 0||todoHistory(todoId,owner).length===0))return{status:state.status,revision:state.revision}},todoGet=(todoId,owner)=>{let state=current(todoId,owner);if(!state)return;let history=todoHistory(todoId,owner),content=[...history].reverse().map(record=>todoPayloadOf(record)?.content).find(value=>typeof value=="string"),lastEvidence=[...history].reverse().find(record=>record.evidence.length>0)?.evidence??[];return{todoId,owner,content:content??"",status:state.status,evidence:lastEvidence,revision:state.revision}},replayedTodo=(todoId,owner,toStatus,operationId)=>operationId&&todoHistory(todoId,owner).some(record=>record.toStatus===toStatus&&record.operationId===operationId)?todoGet(todoId,owner):void 0,transitionTodo=(todoId,owner,fromStatus,toStatus,todoOptions)=>(transitions.transition({domain:"todo",entityId:todoId,owner,fromStatus,toStatus,operationId:todoOptions.operationId??`${toStatus}:${todoId}`,evidence:todoOptions.evidence,payload:todoOptions.payload}),todoGet(todoId,owner)),requireStatus=(todoId,owner,allowed)=>{let todo=todoGet(todoId,owner);if(!todo||!allowed.includes(todo.status))throw new Error(`Todo ${todoId} must be ${allowed.join("/")} (current: ${todo?.status??"missing"})`);return todo};return{createTodo({todoId,owner,content}){if(content.trim().length===0)throw new Error("Todo content must be a non-empty string");return transitionTodo(todoId,owner,null,"open",{payload:{content},operationId:`create:${todoId}`})},start(todoId,owner,startOptions){let replayed=replayedTodo(todoId,owner,"in_progress",startOptions?.operationId);return replayed||(requireStatus(todoId,owner,["open"]),transitionTodo(todoId,owner,"open","in_progress",{operationId:startOptions?.operationId}))},update(todoId,owner,content,updateOptions){if(content.trim().length===0)throw new Error("Todo content must be a non-empty string");let replayed=replayedTodo(todoId,owner,todoGet(todoId,owner)?.status??"open",updateOptions?.operationId);if(replayed)return replayed;let todo=requireStatus(todoId,owner,["open","in_progress"]);return transitionTodo(todoId,owner,todo.status,todo.status,{payload:{content},operationId:updateOptions?.operationId??`update:${todoId}:${contentHash2(content)}`})},complete(todoId,owner,evidence,completeOptions){let replayed=replayedTodo(todoId,owner,"completed",completeOptions?.operationId);return replayed||(requireStatus(todoId,owner,["in_progress"]),transitionTodo(todoId,owner,"in_progress","completed",{evidence:evidence??[],operationId:completeOptions?.operationId}))},cancel(todoId,owner,reason){let todo=requireStatus(todoId,owner,["open","in_progress"]);if(reason!==void 0&&reason.trim().length===0)throw new Error("Todo cancel reason must be a non-empty string when provided");return transitionTodo(todoId,owner,todo.status,"cancelled",{...reason===void 0?{}:{payload:{content:todo.content,cancelReason:reason}}})},reopen(todoId,owner,reopenOptions){let replayed=replayedTodo(todoId,owner,"open",reopenOptions?.operationId);return replayed||(requireStatus(todoId,owner,["cancelled"]),transitionTodo(todoId,owner,"cancelled","open",{operationId:reopenOptions?.operationId}))},get(todoId,owner){return todoGet(todoId,owner)}}}function createSessionShare(options){let now=options.now??(()=>Date.now()),contracts=new Map,shareSequence=0,shareIdOf=sessionId=>{shareSequence+=1;let hash=2166136261,value=`${sessionId}#${shareSequence}`;for(let index=0;index<value.length;index+=1)hash^=value.charCodeAt(index),hash=Math.imul(hash,16777619);return`share-${(hash>>>0).toString(36)}`};return{transport:options.transport,createShare(input){let contract={shareId:shareIdOf(input.sessionId),sessionId:input.sessionId,permission:"read_only",scope:input.scope,createdAt:now(),...input.expiresAt===void 0?{}:{expiresAt:input.expiresAt}};return contracts.set(contract.shareId,{contract}),contract},resolve({shareId,request,now:at}){let record=contracts.get(shareId);if(!record)return{status:"not_found",shareId};let currentTime=at??now();if(record.revokedReason!==void 0)return{status:"denied",reason:`Share ${shareId} is revoked: ${record.revokedReason}`};if(record.contract.expiresAt!==void 0&¤tTime>record.contract.expiresAt)return{status:"denied",reason:`Share ${shareId} expired at ${record.contract.expiresAt}`};let{scope}=record.contract;switch(request.kind){case"messages":return scope.messages?{status:"resolved",kind:"messages",content:options.readMessages(record.contract.sessionId)}:{status:"denied",reason:"Messages are outside the share scope"};case"diagnostics":return scope.diagnostics?{status:"resolved",kind:"diagnostics",content:options.readDiagnostics(record.contract.sessionId)}:{status:"denied",reason:"Diagnostics are outside the share scope"};case"artifact":return scope.artifacts.includes(request.artifactId)?{status:"resolved",kind:"artifact",artifact:options.readArtifact({sessionId:record.contract.sessionId,artifactId:request.artifactId})}:{status:"denied",reason:`Artifact ${request.artifactId} is not in the share whitelist`}}},revoke(shareId,input){let record=contracts.get(shareId);if(!record)throw new Error(`Share not found: ${shareId}`);if(record.revokedReason!==void 0)throw new Error(`Share ${shareId} has already been revoked`);return record.revokedReason=input.reason,record.contract}}}function escapeHtml(value){return value.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}function failureView(shareId,reason){return[`<article class="share-share-failure" data-share="${escapeHtml(shareId)}">`,"<h1>Share unavailable</h1>",`<p class="share-reason">${escapeHtml(reason)}</p>`,"</article>"].join(`
|
|
4
4
|
`)}function createShareViewer(){return{render({contract,result}){if(result.status!=="resolved"){let reason=result.status==="denied"?result.reason:`Unknown share: ${result.shareId}`;return{shareId:contract.shareId,state:"failed",html:failureView(contract.shareId,reason),payload:{shareId:contract.shareId,state:"failed",reason}}}let bodyHtml,payload;switch(result.kind){case"messages":{let content=result.content,turns=Array.isArray(content.turns)?content.turns:[];bodyHtml=["<h1>Shared messages</h1>",'<ol class="share-turns">',...turns.map(turn=>`<li>${escapeHtml(String(turn))}</li>`),"</ol>"].join(`
|
|
5
5
|
`),payload={shareId:contract.shareId,state:"resolved",kind:"messages",turns:[...turns]};break}case"diagnostics":{bodyHtml=`<h1>Shared diagnostics</h1><pre class="share-diagnostics">${escapeHtml(JSON.stringify(result.content))}</pre>`,payload={shareId:contract.shareId,state:"resolved",kind:"diagnostics",content:result.content};break}case"artifact":{bodyHtml=["<h1>Shared artifact</h1>",`<p class="share-artifact" data-artifact="${escapeHtml(result.artifact.artifactId)}">`,`${escapeHtml(result.artifact.mediaType)} \xB7 ${escapeHtml(result.artifact.bytesBase64)}`,"</p>"].join(`
|
package/dist/bundle/rpc-entry.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
|
|
3
|
-
import{APP_NAME,configureHttpDispatcher,main}from"./chunks/chunk-
|
|
3
|
+
import{APP_NAME,configureHttpDispatcher,main}from"./chunks/chunk-2L25YYPC.js";import"./chunks/chunk-JUUC5AZY.js";import"./chunks/chunk-XDUWOHPL.js";import"./chunks/chunk-3QKHSPQL.js";import"./chunks/chunk-DRQDKNXA.js";import"./chunks/chunk-7ZY7IXZD.js";import"./chunks/chunk-V46XUTK3.js";import"./chunks/chunk-WGLBM2BP.js";import"./chunks/chunk-4L3WN2XY.js";process.title=`${APP_NAME}-rpc`;process.env.AGENT_FORGE="true";process.env.AI_AGENT="agent-forge";process.emitWarning=(()=>{});configureHttpDispatcher();main(["--mode","rpc",...process.argv.slice(2)]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAiC,MAAM,kBAAkB,CAAC;AACjF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AAgBxF;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAYhF;AAYD;;;GAGG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAChD,OAAO,CAAC,kBAAkB,CAAQ;IAClC,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,UAAU,CAA6B;IAE/C,YAAY,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,0BAA0B,EAGxE;IAED,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAEtC;IAKD,OAAO,KAAK,MAAM,GAEjB;IAED,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE5C;IAED;;;OAGG;IACH,UAAU,IAAI,IAAI,CAEjB;IAED;;;OAGG;IACH,OAAO,IAAI,IAAI,CAEd;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAkL9B;CACD","sourcesContent":["import { isAbsolute, relative, resolve, sep } from \"node:path\";\nimport { type Component, truncateToWidth, visibleWidth } from \"@agent-forge/tui\";\nimport type { AgentSession } from \"../../../core/agent-session.ts\";\nimport { areExperimentalFeaturesEnabled } from \"../../../core/experimental.ts\";\nimport { type CodingAgentFacadeV1, createCodingAgentFacade } from \"../../../core/facade/index.ts\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport { addUsageToTotals, createUsageTotals } from \"../../../core/usage-totals.ts\";\nimport { theme } from \"../theme/theme.ts\";\n\n/**\n * Sanitize text for display in a single-line status.\n * Removes newlines, tabs, carriage returns, and other control characters.\n */\nfunction sanitizeStatusText(text: string): string {\n\t// Replace newlines, tabs, carriage returns with space, then collapse multiple spaces\n\treturn text\n\t\t.replace(/[\\r\\n\\t]/g, \" \")\n\t\t.replace(/ +/g, \" \")\n\t\t.trim();\n}\n\n/**\n * Format token counts for compact footer display.\n */\nexport function formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\nexport function formatCwdForFooter(cwd: string, home: string | undefined): string {\n\tif (!home) return cwd;\n\n\tconst resolvedCwd = resolve(cwd);\n\tconst resolvedHome = resolve(home);\n\tconst relativeToHome = relative(resolvedHome, resolvedCwd);\n\tconst isInsideHome =\n\t\trelativeToHome === \"\" ||\n\t\t(relativeToHome !== \"..\" && !relativeToHome.startsWith(`..${sep}`) && !isAbsolute(relativeToHome));\n\n\tif (!isInsideHome) return cwd;\n\treturn relativeToHome === \"\" ? \"~\" : `~${sep}${relativeToHome}`;\n}\n\n/** Shape of the `goal.state` custom entry data written by the builtin goal capability. */\ninterface FooterGoalState {\n\tgoals?: Array<{ title?: unknown }>;\n}\n\n/** Shape of the `todo.state` custom entry data written by the builtin todo capability. */\ninterface FooterTodoState {\n\ttodos?: Array<{ status?: unknown }>;\n}\n\n/**\n * Footer component that shows pwd, token stats, and context usage.\n * Computes token/context stats from session, gets git branch and extension statuses from provider.\n */\nexport class FooterComponent implements Component {\n\tprivate autoCompactEnabled = true;\n\tprivate session: AgentSession;\n\tprivate footerData: ReadonlyFooterDataProvider;\n\n\tconstructor(session: AgentSession, footerData: ReadonlyFooterDataProvider) {\n\t\tthis.session = session;\n\t\tthis.footerData = footerData;\n\t}\n\n\tsetSession(session: AgentSession): void {\n\t\tthis.session = session;\n\t}\n\n\t// Stable facade (阶段 1 slice 1): derived on each access; the facade and\n\t// `this.session` always resolve to the same AgentSession, so setSession()\n\t// rebind stays the only rebind path.\n\tprivate get facade(): CodingAgentFacadeV1 {\n\t\treturn createCodingAgentFacade(this.session);\n\t}\n\n\tsetAutoCompactEnabled(enabled: boolean): void {\n\t\tthis.autoCompactEnabled = enabled;\n\t}\n\n\t/**\n\t * No-op: git branch caching now handled by provider.\n\t * Kept for compatibility with existing call sites in interactive-mode.\n\t */\n\tinvalidate(): void {\n\t\t// No-op: git branch is cached/invalidated by provider\n\t}\n\n\t/**\n\t * Clean up resources.\n\t * Git watcher cleanup now handled by provider.\n\t */\n\tdispose(): void {\n\t\t// Git watcher cleanup handled by provider\n\t}\n\n\trender(width: number): string[] {\n\t\tconst state = this.facade.getState();\n\n\t\t// Calculate cumulative usage from ALL session entries (not just post-compaction messages)\n\t\tconst usageTotals = createUsageTotals();\n\t\tlet latestCacheHitRate: number | undefined;\n\n\t\t// Latest goal/todo capability state: the builtin goal/todo capabilities announce\n\t\t// goal.changed / todo.changed and persist the same state as goal.state / todo.state\n\t\t// custom entries; the last entry per type wins.\n\t\tlet goalTitle: string | undefined;\n\t\tlet todoDone = 0;\n\t\tlet todoTotal = 0;\n\n\t\tfor (const entry of this.facade.getEntries()) {\n\t\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\t\taddUsageToTotals(usageTotals, entry.message.usage);\n\n\t\t\t\tconst latestPromptTokens =\n\t\t\t\t\tentry.message.usage.input + entry.message.usage.cacheRead + entry.message.usage.cacheWrite;\n\t\t\t\tlatestCacheHitRate =\n\t\t\t\t\tlatestPromptTokens > 0 ? (entry.message.usage.cacheRead / latestPromptTokens) * 100 : undefined;\n\t\t\t} else if (entry.type === \"message\" && entry.message.role === \"toolResult\" && entry.message.usage) {\n\t\t\t\taddUsageToTotals(usageTotals, entry.message.usage);\n\t\t\t} else if ((entry.type === \"branch_summary\" || entry.type === \"compaction\") && entry.usage) {\n\t\t\t\taddUsageToTotals(usageTotals, entry.usage);\n\t\t\t} else if (entry.type === \"custom\" && entry.customType === \"goal.state\") {\n\t\t\t\tconst goals = (entry.data as FooterGoalState | undefined)?.goals;\n\t\t\t\tconst current = Array.isArray(goals) ? goals.at(-1) : undefined;\n\t\t\t\tif (current && typeof current.title === \"string\") {\n\t\t\t\t\tgoalTitle = current.title;\n\t\t\t\t}\n\t\t\t} else if (entry.type === \"custom\" && entry.customType === \"todo.state\") {\n\t\t\t\tconst todos = (entry.data as FooterTodoState | undefined)?.todos;\n\t\t\t\tif (Array.isArray(todos)) {\n\t\t\t\t\ttodoDone = todos.filter((item) => item?.status === \"done\").length;\n\t\t\t\t\ttodoTotal = todos.length;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Calculate context usage from session (handles compaction correctly).\n\t\t// After compaction, tokens are unknown until the next LLM response.\n\t\tconst contextUsage = this.facade.getContextUsage();\n\t\tconst contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;\n\t\tconst contextPercentValue = contextUsage?.percent ?? 0;\n\t\tconst contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : \"?\";\n\n\t\t// Replace home directory with ~\n\t\tlet pwd = formatCwdForFooter(this.facade.getCwd(), process.env.HOME || process.env.USERPROFILE);\n\n\t\t// Add git branch if available\n\t\tconst branch = this.footerData.getGitBranch();\n\t\tif (branch) {\n\t\t\tpwd = `${pwd} (${branch})`;\n\t\t}\n\n\t\t// Add session name if set\n\t\tconst sessionName = this.facade.getSessionName();\n\t\tif (sessionName) {\n\t\t\tpwd = `${pwd} • ${sessionName}`;\n\t\t}\n\n\t\t// Build stats line\n\t\tconst statsParts = [];\n\t\tif (usageTotals.input) statsParts.push(`↑${formatTokens(usageTotals.input)}`);\n\t\tif (usageTotals.output) statsParts.push(`↓${formatTokens(usageTotals.output)}`);\n\t\tif (usageTotals.cacheRead) statsParts.push(`R${formatTokens(usageTotals.cacheRead)}`);\n\t\tif (usageTotals.cacheWrite) statsParts.push(`W${formatTokens(usageTotals.cacheWrite)}`);\n\t\tif ((usageTotals.cacheRead > 0 || usageTotals.cacheWrite > 0) && latestCacheHitRate !== undefined) {\n\t\t\tstatsParts.push(`CH${latestCacheHitRate.toFixed(1)}%`);\n\t\t}\n\n\t\t// Kimi Coding is subscription-backed despite using API-key authentication.\n\t\tconst usingSubscription = state.model\n\t\t\t? state.model.provider === \"kimi-coding\" || this.facade.isUsingSubscription(state.model.provider)\n\t\t\t: false;\n\t\tif (usageTotals.cost || usingSubscription) {\n\t\t\tconst costStr = `$${usageTotals.cost.toFixed(3)}${usingSubscription ? \" (sub)\" : \"\"}`;\n\t\t\tstatsParts.push(costStr);\n\t\t}\n\n\t\t// Colorize context percentage based on usage\n\t\tlet contextPercentStr: string;\n\t\tconst autoIndicator = this.autoCompactEnabled ? \" (auto)\" : \"\";\n\t\tconst contextPercentDisplay =\n\t\t\tcontextPercent === \"?\"\n\t\t\t\t? `?/${formatTokens(contextWindow)}${autoIndicator}`\n\t\t\t\t: `${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;\n\t\tif (contextPercentValue > 90) {\n\t\t\tcontextPercentStr = theme.fg(\"error\", contextPercentDisplay);\n\t\t} else if (contextPercentValue > 70) {\n\t\t\tcontextPercentStr = theme.fg(\"warning\", contextPercentDisplay);\n\t\t} else {\n\t\t\tcontextPercentStr = contextPercentDisplay;\n\t\t}\n\t\tstatsParts.push(contextPercentStr);\n\t\tif (areExperimentalFeaturesEnabled()) {\n\t\t\tstatsParts.push(`${theme.fg(\"dim\", \"•\")} ${theme.bold(theme.fg(\"warning\", \"xp\"))}`);\n\t\t}\n\n\t\tlet statsLeft = statsParts.join(\" \");\n\n\t\t// Add model name on the right side, plus thinking level if model supports it\n\t\tconst modelName = state.model?.id || \"no-model\";\n\n\t\tlet statsLeftWidth = visibleWidth(statsLeft);\n\n\t\t// If statsLeft is too wide, truncate it\n\t\tif (statsLeftWidth > width) {\n\t\t\tstatsLeft = truncateToWidth(statsLeft, width, \"...\");\n\t\t\tstatsLeftWidth = visibleWidth(statsLeft);\n\t\t}\n\n\t\t// Calculate available space for padding (minimum 2 spaces between stats and model)\n\t\tconst minPadding = 2;\n\n\t\t// Add thinking level indicator if model supports reasoning\n\t\tlet rightSideWithoutProvider = modelName;\n\t\tif (state.model?.reasoning) {\n\t\t\tconst thinkingLevel = state.thinkingLevel || \"off\";\n\t\t\trightSideWithoutProvider =\n\t\t\t\tthinkingLevel === \"off\" ? `${modelName} • thinking off` : `${modelName} • ${thinkingLevel}`;\n\t\t}\n\n\t\t// Prepend the provider in parentheses if there are multiple providers and there's enough room\n\t\tlet rightSide = rightSideWithoutProvider;\n\t\tif (this.footerData.getAvailableProviderCount() > 1 && state.model) {\n\t\t\trightSide = `(${state.model!.provider}) ${rightSideWithoutProvider}`;\n\t\t\tif (statsLeftWidth + minPadding + visibleWidth(rightSide) > width) {\n\t\t\t\t// Too wide, fall back\n\t\t\t\trightSide = rightSideWithoutProvider;\n\t\t\t}\n\t\t}\n\n\t\tconst rightSideWidth = visibleWidth(rightSide);\n\t\tconst totalNeeded = statsLeftWidth + minPadding + rightSideWidth;\n\n\t\tlet statsLine: string;\n\t\tif (totalNeeded <= width) {\n\t\t\t// Both fit - add padding to right-align model\n\t\t\tconst padding = \" \".repeat(width - statsLeftWidth - rightSideWidth);\n\t\t\tstatsLine = statsLeft + padding + rightSide;\n\t\t} else {\n\t\t\t// Need to truncate right side\n\t\t\tconst availableForRight = width - statsLeftWidth - minPadding;\n\t\t\tif (availableForRight > 0) {\n\t\t\t\tconst truncatedRight = truncateToWidth(rightSide, availableForRight, \"\");\n\t\t\t\tconst truncatedRightWidth = visibleWidth(truncatedRight);\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, width - statsLeftWidth - truncatedRightWidth));\n\t\t\t\tstatsLine = statsLeft + padding + truncatedRight;\n\t\t\t} else {\n\t\t\t\t// Not enough space for right side at all\n\t\t\t\tstatsLine = statsLeft;\n\t\t\t}\n\t\t}\n\n\t\t// Apply dim to each part separately. statsLeft may contain color codes (for context %)\n\t\t// that end with a reset, which would clear an outer dim wrapper. So we dim the parts\n\t\t// before and after the colored section independently.\n\t\tconst dimStatsLeft = theme.fg(\"dim\", statsLeft);\n\t\tconst remainder = statsLine.slice(statsLeft.length); // padding + rightSide\n\t\tconst dimRemainder = theme.fg(\"dim\", remainder);\n\n\t\tconst pwdLine = truncateToWidth(theme.fg(\"dim\", pwd), width, theme.fg(\"dim\", \"...\"));\n\t\tconst lines = [pwdLine, dimStatsLeft + dimRemainder];\n\n\t\t// Add goal/todo status, only when a goal exists; an empty todo set shows the goal alone.\n\t\tif (goalTitle !== undefined) {\n\t\t\tconst goalParts = [`goal: ${goalTitle}`];\n\t\t\tif (todoTotal > 0) {\n\t\t\t\tgoalParts.push(`todo ${todoDone}/${todoTotal}`);\n\t\t\t}\n\t\t\tconst goalLine = theme.fg(\"dim\", sanitizeStatusText(goalParts.join(\" • \")));\n\t\t\tlines.push(truncateToWidth(goalLine, width, theme.fg(\"dim\", \"...\")));\n\t\t}\n\n\t\treturn lines;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAiC,MAAM,kBAAkB,CAAC;AACjF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AAgBxF;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAYhF;AAmDD;;;GAGG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAChD,OAAO,CAAC,kBAAkB,CAAQ;IAClC,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,UAAU,CAA6B;IAE/C,YAAY,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,0BAA0B,EAGxE;IAED,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAEtC;IAKD,OAAO,KAAK,MAAM,GAEjB;IAED,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE5C;IAED;;;OAGG;IACH,UAAU,IAAI,IAAI,CAEjB;IAED;;;OAGG;IACH,OAAO,IAAI,IAAI,CAEd;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA4L9B;CACD","sourcesContent":["import { isAbsolute, relative, resolve, sep } from \"node:path\";\nimport { type Component, truncateToWidth, visibleWidth } from \"@agent-forge/tui\";\nimport type { AgentSession } from \"../../../core/agent-session.ts\";\nimport { areExperimentalFeaturesEnabled } from \"../../../core/experimental.ts\";\nimport { type CodingAgentFacadeV1, createCodingAgentFacade } from \"../../../core/facade/index.ts\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport { addUsageToTotals, createUsageTotals } from \"../../../core/usage-totals.ts\";\nimport { theme } from \"../theme/theme.ts\";\n\n/**\n * Sanitize text for display in a single-line status.\n * Removes newlines, tabs, carriage returns, and other control characters.\n */\nfunction sanitizeStatusText(text: string): string {\n\t// Replace newlines, tabs, carriage returns with space, then collapse multiple spaces\n\treturn text\n\t\t.replace(/[\\r\\n\\t]/g, \" \")\n\t\t.replace(/ +/g, \" \")\n\t\t.trim();\n}\n\n/**\n * Format token counts for compact footer display.\n */\nexport function formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\nexport function formatCwdForFooter(cwd: string, home: string | undefined): string {\n\tif (!home) return cwd;\n\n\tconst resolvedCwd = resolve(cwd);\n\tconst resolvedHome = resolve(home);\n\tconst relativeToHome = relative(resolvedHome, resolvedCwd);\n\tconst isInsideHome =\n\t\trelativeToHome === \"\" ||\n\t\t(relativeToHome !== \"..\" && !relativeToHome.startsWith(`..${sep}`) && !isAbsolute(relativeToHome));\n\n\tif (!isInsideHome) return cwd;\n\treturn relativeToHome === \"\" ? \"~\" : `~${sep}${relativeToHome}`;\n}\n\n/** Shape of the `goal.state` custom entry data written by the builtin goal capability. */\ninterface FooterGoalState {\n\tgoals?: Array<{ title?: unknown }>;\n}\n\n/** Shape of the `todo.state` custom entry data written by the builtin todo capability. */\ninterface FooterTodoState {\n\ttodos?: Array<{ status?: unknown }>;\n}\n\n/** Shape of the `workflow.state` custom entry data written by the workflow plugin. */\ninterface FooterWorkflowState {\n\tworkflows?: Array<{\n\t\ttitle?: unknown;\n\t\tstatus?: unknown;\n\t\truntime?: Array<{ status?: unknown }>;\n\t\tdiagnostics?: unknown[];\n\t}>;\n}\n\n/**\n * Build the one-line workflow summary from the latest `workflow.state` snapshot:\n * `wf: <title> <done>/<total>` plus status markers, in order — `▶n` (n>=2\n * parallel active stages), `⏸` (a stage awaiting review), `⚠` (non-empty\n * diagnostics), `✗` (failed workflow); done counts completed+skipped stages.\n * Picks the newest non-terminal workflow, falling back to the newest one when\n * all are terminal; returns undefined when there is no workflow to show.\n */\nfunction summarizeWorkflowState(state: FooterWorkflowState | undefined): string | undefined {\n\tconst workflows = state?.workflows;\n\tconst records = Array.isArray(workflows) ? workflows : [];\n\tconst record =\n\t\t[...records].reverse().find((item) => item?.status === \"draft\" || item?.status === \"running\") ?? records.at(-1);\n\tif (record === undefined || typeof record.title !== \"string\") {\n\t\treturn undefined;\n\t}\n\n\tconst stages = Array.isArray(record.runtime) ? record.runtime : [];\n\tconst done = stages.filter((stage) => stage?.status === \"completed\" || stage?.status === \"skipped\").length;\n\tconst activeCount = stages.filter((stage) => stage?.status === \"active\").length;\n\n\tconst parts = [`wf: ${record.title} ${done}/${stages.length}`];\n\tif (activeCount >= 2) parts.push(`▶${activeCount}`);\n\tif (stages.some((stage) => stage?.status === \"awaiting_review\")) parts.push(\"⏸\");\n\tif (Array.isArray(record.diagnostics) && record.diagnostics.length > 0) parts.push(\"⚠\");\n\tif (record.status === \"failed\") parts.push(\"✗\");\n\treturn parts.join(\" \");\n}\n\n/**\n * Footer component that shows pwd, token stats, and context usage.\n * Computes token/context stats from session, gets git branch and extension statuses from provider.\n */\nexport class FooterComponent implements Component {\n\tprivate autoCompactEnabled = true;\n\tprivate session: AgentSession;\n\tprivate footerData: ReadonlyFooterDataProvider;\n\n\tconstructor(session: AgentSession, footerData: ReadonlyFooterDataProvider) {\n\t\tthis.session = session;\n\t\tthis.footerData = footerData;\n\t}\n\n\tsetSession(session: AgentSession): void {\n\t\tthis.session = session;\n\t}\n\n\t// Stable facade (阶段 1 slice 1): derived on each access; the facade and\n\t// `this.session` always resolve to the same AgentSession, so setSession()\n\t// rebind stays the only rebind path.\n\tprivate get facade(): CodingAgentFacadeV1 {\n\t\treturn createCodingAgentFacade(this.session);\n\t}\n\n\tsetAutoCompactEnabled(enabled: boolean): void {\n\t\tthis.autoCompactEnabled = enabled;\n\t}\n\n\t/**\n\t * No-op: git branch caching now handled by provider.\n\t * Kept for compatibility with existing call sites in interactive-mode.\n\t */\n\tinvalidate(): void {\n\t\t// No-op: git branch is cached/invalidated by provider\n\t}\n\n\t/**\n\t * Clean up resources.\n\t * Git watcher cleanup now handled by provider.\n\t */\n\tdispose(): void {\n\t\t// Git watcher cleanup handled by provider\n\t}\n\n\trender(width: number): string[] {\n\t\tconst state = this.facade.getState();\n\n\t\t// Calculate cumulative usage from ALL session entries (not just post-compaction messages)\n\t\tconst usageTotals = createUsageTotals();\n\t\tlet latestCacheHitRate: number | undefined;\n\n\t\t// Latest goal/todo capability state: the builtin goal/todo capabilities announce\n\t\t// goal.changed / todo.changed and persist the same state as goal.state / todo.state\n\t\t// custom entries; the last entry per type wins.\n\t\tlet goalTitle: string | undefined;\n\t\tlet todoDone = 0;\n\t\tlet todoTotal = 0;\n\t\tlet workflowState: FooterWorkflowState | undefined;\n\n\t\tfor (const entry of this.facade.getEntries()) {\n\t\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\t\taddUsageToTotals(usageTotals, entry.message.usage);\n\n\t\t\t\tconst latestPromptTokens =\n\t\t\t\t\tentry.message.usage.input + entry.message.usage.cacheRead + entry.message.usage.cacheWrite;\n\t\t\t\tlatestCacheHitRate =\n\t\t\t\t\tlatestPromptTokens > 0 ? (entry.message.usage.cacheRead / latestPromptTokens) * 100 : undefined;\n\t\t\t} else if (entry.type === \"message\" && entry.message.role === \"toolResult\" && entry.message.usage) {\n\t\t\t\taddUsageToTotals(usageTotals, entry.message.usage);\n\t\t\t} else if ((entry.type === \"branch_summary\" || entry.type === \"compaction\") && entry.usage) {\n\t\t\t\taddUsageToTotals(usageTotals, entry.usage);\n\t\t\t} else if (entry.type === \"custom\" && entry.customType === \"goal.state\") {\n\t\t\t\tconst goals = (entry.data as FooterGoalState | undefined)?.goals;\n\t\t\t\tconst current = Array.isArray(goals) ? goals.at(-1) : undefined;\n\t\t\t\tif (current && typeof current.title === \"string\") {\n\t\t\t\t\tgoalTitle = current.title;\n\t\t\t\t}\n\t\t\t} else if (entry.type === \"custom\" && entry.customType === \"todo.state\") {\n\t\t\t\tconst todos = (entry.data as FooterTodoState | undefined)?.todos;\n\t\t\t\tif (Array.isArray(todos)) {\n\t\t\t\t\ttodoDone = todos.filter((item) => item?.status === \"done\").length;\n\t\t\t\t\ttodoTotal = todos.length;\n\t\t\t\t}\n\t\t\t} else if (entry.type === \"custom\" && entry.customType === \"workflow.state\") {\n\t\t\t\tworkflowState = entry.data as FooterWorkflowState | undefined;\n\t\t\t}\n\t\t}\n\n\t\t// Calculate context usage from session (handles compaction correctly).\n\t\t// After compaction, tokens are unknown until the next LLM response.\n\t\tconst contextUsage = this.facade.getContextUsage();\n\t\tconst contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;\n\t\tconst contextPercentValue = contextUsage?.percent ?? 0;\n\t\tconst contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : \"?\";\n\n\t\t// Replace home directory with ~\n\t\tlet pwd = formatCwdForFooter(this.facade.getCwd(), process.env.HOME || process.env.USERPROFILE);\n\n\t\t// Add git branch if available\n\t\tconst branch = this.footerData.getGitBranch();\n\t\tif (branch) {\n\t\t\tpwd = `${pwd} (${branch})`;\n\t\t}\n\n\t\t// Add session name if set\n\t\tconst sessionName = this.facade.getSessionName();\n\t\tif (sessionName) {\n\t\t\tpwd = `${pwd} • ${sessionName}`;\n\t\t}\n\n\t\t// Build stats line\n\t\tconst statsParts = [];\n\t\tif (usageTotals.input) statsParts.push(`↑${formatTokens(usageTotals.input)}`);\n\t\tif (usageTotals.output) statsParts.push(`↓${formatTokens(usageTotals.output)}`);\n\t\tif (usageTotals.cacheRead) statsParts.push(`R${formatTokens(usageTotals.cacheRead)}`);\n\t\tif (usageTotals.cacheWrite) statsParts.push(`W${formatTokens(usageTotals.cacheWrite)}`);\n\t\tif ((usageTotals.cacheRead > 0 || usageTotals.cacheWrite > 0) && latestCacheHitRate !== undefined) {\n\t\t\tstatsParts.push(`CH${latestCacheHitRate.toFixed(1)}%`);\n\t\t}\n\n\t\t// Kimi Coding is subscription-backed despite using API-key authentication.\n\t\tconst usingSubscription = state.model\n\t\t\t? state.model.provider === \"kimi-coding\" || this.facade.isUsingSubscription(state.model.provider)\n\t\t\t: false;\n\t\tif (usageTotals.cost || usingSubscription) {\n\t\t\tconst costStr = `$${usageTotals.cost.toFixed(3)}${usingSubscription ? \" (sub)\" : \"\"}`;\n\t\t\tstatsParts.push(costStr);\n\t\t}\n\n\t\t// Colorize context percentage based on usage\n\t\tlet contextPercentStr: string;\n\t\tconst autoIndicator = this.autoCompactEnabled ? \" (auto)\" : \"\";\n\t\tconst contextPercentDisplay =\n\t\t\tcontextPercent === \"?\"\n\t\t\t\t? `?/${formatTokens(contextWindow)}${autoIndicator}`\n\t\t\t\t: `${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;\n\t\tif (contextPercentValue > 90) {\n\t\t\tcontextPercentStr = theme.fg(\"error\", contextPercentDisplay);\n\t\t} else if (contextPercentValue > 70) {\n\t\t\tcontextPercentStr = theme.fg(\"warning\", contextPercentDisplay);\n\t\t} else {\n\t\t\tcontextPercentStr = contextPercentDisplay;\n\t\t}\n\t\tstatsParts.push(contextPercentStr);\n\t\tif (areExperimentalFeaturesEnabled()) {\n\t\t\tstatsParts.push(`${theme.fg(\"dim\", \"•\")} ${theme.bold(theme.fg(\"warning\", \"xp\"))}`);\n\t\t}\n\n\t\tlet statsLeft = statsParts.join(\" \");\n\n\t\t// Add model name on the right side, plus thinking level if model supports it\n\t\tconst modelName = state.model?.id || \"no-model\";\n\n\t\tlet statsLeftWidth = visibleWidth(statsLeft);\n\n\t\t// If statsLeft is too wide, truncate it\n\t\tif (statsLeftWidth > width) {\n\t\t\tstatsLeft = truncateToWidth(statsLeft, width, \"...\");\n\t\t\tstatsLeftWidth = visibleWidth(statsLeft);\n\t\t}\n\n\t\t// Calculate available space for padding (minimum 2 spaces between stats and model)\n\t\tconst minPadding = 2;\n\n\t\t// Add thinking level indicator if model supports reasoning\n\t\tlet rightSideWithoutProvider = modelName;\n\t\tif (state.model?.reasoning) {\n\t\t\tconst thinkingLevel = state.thinkingLevel || \"off\";\n\t\t\trightSideWithoutProvider =\n\t\t\t\tthinkingLevel === \"off\" ? `${modelName} • thinking off` : `${modelName} • ${thinkingLevel}`;\n\t\t}\n\n\t\t// Prepend the provider in parentheses if there are multiple providers and there's enough room\n\t\tlet rightSide = rightSideWithoutProvider;\n\t\tif (this.footerData.getAvailableProviderCount() > 1 && state.model) {\n\t\t\trightSide = `(${state.model!.provider}) ${rightSideWithoutProvider}`;\n\t\t\tif (statsLeftWidth + minPadding + visibleWidth(rightSide) > width) {\n\t\t\t\t// Too wide, fall back\n\t\t\t\trightSide = rightSideWithoutProvider;\n\t\t\t}\n\t\t}\n\n\t\tconst rightSideWidth = visibleWidth(rightSide);\n\t\tconst totalNeeded = statsLeftWidth + minPadding + rightSideWidth;\n\n\t\tlet statsLine: string;\n\t\tif (totalNeeded <= width) {\n\t\t\t// Both fit - add padding to right-align model\n\t\t\tconst padding = \" \".repeat(width - statsLeftWidth - rightSideWidth);\n\t\t\tstatsLine = statsLeft + padding + rightSide;\n\t\t} else {\n\t\t\t// Need to truncate right side\n\t\t\tconst availableForRight = width - statsLeftWidth - minPadding;\n\t\t\tif (availableForRight > 0) {\n\t\t\t\tconst truncatedRight = truncateToWidth(rightSide, availableForRight, \"\");\n\t\t\t\tconst truncatedRightWidth = visibleWidth(truncatedRight);\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, width - statsLeftWidth - truncatedRightWidth));\n\t\t\t\tstatsLine = statsLeft + padding + truncatedRight;\n\t\t\t} else {\n\t\t\t\t// Not enough space for right side at all\n\t\t\t\tstatsLine = statsLeft;\n\t\t\t}\n\t\t}\n\n\t\t// Apply dim to each part separately. statsLeft may contain color codes (for context %)\n\t\t// that end with a reset, which would clear an outer dim wrapper. So we dim the parts\n\t\t// before and after the colored section independently.\n\t\tconst dimStatsLeft = theme.fg(\"dim\", statsLeft);\n\t\tconst remainder = statsLine.slice(statsLeft.length); // padding + rightSide\n\t\tconst dimRemainder = theme.fg(\"dim\", remainder);\n\n\t\tconst pwdLine = truncateToWidth(theme.fg(\"dim\", pwd), width, theme.fg(\"dim\", \"...\"));\n\t\tconst lines = [pwdLine, dimStatsLeft + dimRemainder];\n\n\t\t// Add goal/todo status, only when a goal exists; an empty todo set shows the goal alone.\n\t\tif (goalTitle !== undefined) {\n\t\t\tconst goalParts = [`goal: ${goalTitle}`];\n\t\t\tif (todoTotal > 0) {\n\t\t\t\tgoalParts.push(`todo ${todoDone}/${todoTotal}`);\n\t\t\t}\n\t\t\tconst goalLine = theme.fg(\"dim\", sanitizeStatusText(goalParts.join(\" • \")));\n\t\t\tlines.push(truncateToWidth(goalLine, width, theme.fg(\"dim\", \"...\")));\n\t\t}\n\n\t\t// Add workflow status, only when a workflow snapshot reports one.\n\t\tconst workflowSummary = summarizeWorkflowState(workflowState);\n\t\tif (workflowSummary !== undefined) {\n\t\t\tconst workflowLine = theme.fg(\"dim\", sanitizeStatusText(workflowSummary));\n\t\t\tlines.push(truncateToWidth(workflowLine, width, theme.fg(\"dim\", \"...\")));\n\t\t}\n\n\t\treturn lines;\n\t}\n}\n"]}
|
|
@@ -41,6 +41,35 @@ export function formatCwdForFooter(cwd, home) {
|
|
|
41
41
|
return cwd;
|
|
42
42
|
return relativeToHome === "" ? "~" : `~${sep}${relativeToHome}`;
|
|
43
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Build the one-line workflow summary from the latest `workflow.state` snapshot:
|
|
46
|
+
* `wf: <title> <done>/<total>` plus status markers, in order — `▶n` (n>=2
|
|
47
|
+
* parallel active stages), `⏸` (a stage awaiting review), `⚠` (non-empty
|
|
48
|
+
* diagnostics), `✗` (failed workflow); done counts completed+skipped stages.
|
|
49
|
+
* Picks the newest non-terminal workflow, falling back to the newest one when
|
|
50
|
+
* all are terminal; returns undefined when there is no workflow to show.
|
|
51
|
+
*/
|
|
52
|
+
function summarizeWorkflowState(state) {
|
|
53
|
+
const workflows = state?.workflows;
|
|
54
|
+
const records = Array.isArray(workflows) ? workflows : [];
|
|
55
|
+
const record = [...records].reverse().find((item) => item?.status === "draft" || item?.status === "running") ?? records.at(-1);
|
|
56
|
+
if (record === undefined || typeof record.title !== "string") {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
const stages = Array.isArray(record.runtime) ? record.runtime : [];
|
|
60
|
+
const done = stages.filter((stage) => stage?.status === "completed" || stage?.status === "skipped").length;
|
|
61
|
+
const activeCount = stages.filter((stage) => stage?.status === "active").length;
|
|
62
|
+
const parts = [`wf: ${record.title} ${done}/${stages.length}`];
|
|
63
|
+
if (activeCount >= 2)
|
|
64
|
+
parts.push(`▶${activeCount}`);
|
|
65
|
+
if (stages.some((stage) => stage?.status === "awaiting_review"))
|
|
66
|
+
parts.push("⏸");
|
|
67
|
+
if (Array.isArray(record.diagnostics) && record.diagnostics.length > 0)
|
|
68
|
+
parts.push("⚠");
|
|
69
|
+
if (record.status === "failed")
|
|
70
|
+
parts.push("✗");
|
|
71
|
+
return parts.join(" ");
|
|
72
|
+
}
|
|
44
73
|
/**
|
|
45
74
|
* Footer component that shows pwd, token stats, and context usage.
|
|
46
75
|
* Computes token/context stats from session, gets git branch and extension statuses from provider.
|
|
@@ -90,6 +119,7 @@ export class FooterComponent {
|
|
|
90
119
|
let goalTitle;
|
|
91
120
|
let todoDone = 0;
|
|
92
121
|
let todoTotal = 0;
|
|
122
|
+
let workflowState;
|
|
93
123
|
for (const entry of this.facade.getEntries()) {
|
|
94
124
|
if (entry.type === "message" && entry.message.role === "assistant") {
|
|
95
125
|
addUsageToTotals(usageTotals, entry.message.usage);
|
|
@@ -117,6 +147,9 @@ export class FooterComponent {
|
|
|
117
147
|
todoTotal = todos.length;
|
|
118
148
|
}
|
|
119
149
|
}
|
|
150
|
+
else if (entry.type === "custom" && entry.customType === "workflow.state") {
|
|
151
|
+
workflowState = entry.data;
|
|
152
|
+
}
|
|
120
153
|
}
|
|
121
154
|
// Calculate context usage from session (handles compaction correctly).
|
|
122
155
|
// After compaction, tokens are unknown until the next LLM response.
|
|
@@ -242,6 +275,12 @@ export class FooterComponent {
|
|
|
242
275
|
const goalLine = theme.fg("dim", sanitizeStatusText(goalParts.join(" • ")));
|
|
243
276
|
lines.push(truncateToWidth(goalLine, width, theme.fg("dim", "...")));
|
|
244
277
|
}
|
|
278
|
+
// Add workflow status, only when a workflow snapshot reports one.
|
|
279
|
+
const workflowSummary = summarizeWorkflowState(workflowState);
|
|
280
|
+
if (workflowSummary !== undefined) {
|
|
281
|
+
const workflowLine = theme.fg("dim", sanitizeStatusText(workflowSummary));
|
|
282
|
+
lines.push(truncateToWidth(workflowLine, width, theme.fg("dim", "...")));
|
|
283
|
+
}
|
|
245
284
|
return lines;
|
|
246
285
|
}
|
|
247
286
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"footer.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"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","sourcesContent":["import { isAbsolute, relative, resolve, sep } from \"node:path\";\nimport { type Component, truncateToWidth, visibleWidth } from \"@agent-forge/tui\";\nimport type { AgentSession } from \"../../../core/agent-session.ts\";\nimport { areExperimentalFeaturesEnabled } from \"../../../core/experimental.ts\";\nimport { type CodingAgentFacadeV1, createCodingAgentFacade } from \"../../../core/facade/index.ts\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport { addUsageToTotals, createUsageTotals } from \"../../../core/usage-totals.ts\";\nimport { theme } from \"../theme/theme.ts\";\n\n/**\n * Sanitize text for display in a single-line status.\n * Removes newlines, tabs, carriage returns, and other control characters.\n */\nfunction sanitizeStatusText(text: string): string {\n\t// Replace newlines, tabs, carriage returns with space, then collapse multiple spaces\n\treturn text\n\t\t.replace(/[\\r\\n\\t]/g, \" \")\n\t\t.replace(/ +/g, \" \")\n\t\t.trim();\n}\n\n/**\n * Format token counts for compact footer display.\n */\nexport function formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\nexport function formatCwdForFooter(cwd: string, home: string | undefined): string {\n\tif (!home) return cwd;\n\n\tconst resolvedCwd = resolve(cwd);\n\tconst resolvedHome = resolve(home);\n\tconst relativeToHome = relative(resolvedHome, resolvedCwd);\n\tconst isInsideHome =\n\t\trelativeToHome === \"\" ||\n\t\t(relativeToHome !== \"..\" && !relativeToHome.startsWith(`..${sep}`) && !isAbsolute(relativeToHome));\n\n\tif (!isInsideHome) return cwd;\n\treturn relativeToHome === \"\" ? \"~\" : `~${sep}${relativeToHome}`;\n}\n\n/** Shape of the `goal.state` custom entry data written by the builtin goal capability. */\ninterface FooterGoalState {\n\tgoals?: Array<{ title?: unknown }>;\n}\n\n/** Shape of the `todo.state` custom entry data written by the builtin todo capability. */\ninterface FooterTodoState {\n\ttodos?: Array<{ status?: unknown }>;\n}\n\n/**\n * Footer component that shows pwd, token stats, and context usage.\n * Computes token/context stats from session, gets git branch and extension statuses from provider.\n */\nexport class FooterComponent implements Component {\n\tprivate autoCompactEnabled = true;\n\tprivate session: AgentSession;\n\tprivate footerData: ReadonlyFooterDataProvider;\n\n\tconstructor(session: AgentSession, footerData: ReadonlyFooterDataProvider) {\n\t\tthis.session = session;\n\t\tthis.footerData = footerData;\n\t}\n\n\tsetSession(session: AgentSession): void {\n\t\tthis.session = session;\n\t}\n\n\t// Stable facade (阶段 1 slice 1): derived on each access; the facade and\n\t// `this.session` always resolve to the same AgentSession, so setSession()\n\t// rebind stays the only rebind path.\n\tprivate get facade(): CodingAgentFacadeV1 {\n\t\treturn createCodingAgentFacade(this.session);\n\t}\n\n\tsetAutoCompactEnabled(enabled: boolean): void {\n\t\tthis.autoCompactEnabled = enabled;\n\t}\n\n\t/**\n\t * No-op: git branch caching now handled by provider.\n\t * Kept for compatibility with existing call sites in interactive-mode.\n\t */\n\tinvalidate(): void {\n\t\t// No-op: git branch is cached/invalidated by provider\n\t}\n\n\t/**\n\t * Clean up resources.\n\t * Git watcher cleanup now handled by provider.\n\t */\n\tdispose(): void {\n\t\t// Git watcher cleanup handled by provider\n\t}\n\n\trender(width: number): string[] {\n\t\tconst state = this.facade.getState();\n\n\t\t// Calculate cumulative usage from ALL session entries (not just post-compaction messages)\n\t\tconst usageTotals = createUsageTotals();\n\t\tlet latestCacheHitRate: number | undefined;\n\n\t\t// Latest goal/todo capability state: the builtin goal/todo capabilities announce\n\t\t// goal.changed / todo.changed and persist the same state as goal.state / todo.state\n\t\t// custom entries; the last entry per type wins.\n\t\tlet goalTitle: string | undefined;\n\t\tlet todoDone = 0;\n\t\tlet todoTotal = 0;\n\n\t\tfor (const entry of this.facade.getEntries()) {\n\t\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\t\taddUsageToTotals(usageTotals, entry.message.usage);\n\n\t\t\t\tconst latestPromptTokens =\n\t\t\t\t\tentry.message.usage.input + entry.message.usage.cacheRead + entry.message.usage.cacheWrite;\n\t\t\t\tlatestCacheHitRate =\n\t\t\t\t\tlatestPromptTokens > 0 ? (entry.message.usage.cacheRead / latestPromptTokens) * 100 : undefined;\n\t\t\t} else if (entry.type === \"message\" && entry.message.role === \"toolResult\" && entry.message.usage) {\n\t\t\t\taddUsageToTotals(usageTotals, entry.message.usage);\n\t\t\t} else if ((entry.type === \"branch_summary\" || entry.type === \"compaction\") && entry.usage) {\n\t\t\t\taddUsageToTotals(usageTotals, entry.usage);\n\t\t\t} else if (entry.type === \"custom\" && entry.customType === \"goal.state\") {\n\t\t\t\tconst goals = (entry.data as FooterGoalState | undefined)?.goals;\n\t\t\t\tconst current = Array.isArray(goals) ? goals.at(-1) : undefined;\n\t\t\t\tif (current && typeof current.title === \"string\") {\n\t\t\t\t\tgoalTitle = current.title;\n\t\t\t\t}\n\t\t\t} else if (entry.type === \"custom\" && entry.customType === \"todo.state\") {\n\t\t\t\tconst todos = (entry.data as FooterTodoState | undefined)?.todos;\n\t\t\t\tif (Array.isArray(todos)) {\n\t\t\t\t\ttodoDone = todos.filter((item) => item?.status === \"done\").length;\n\t\t\t\t\ttodoTotal = todos.length;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Calculate context usage from session (handles compaction correctly).\n\t\t// After compaction, tokens are unknown until the next LLM response.\n\t\tconst contextUsage = this.facade.getContextUsage();\n\t\tconst contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;\n\t\tconst contextPercentValue = contextUsage?.percent ?? 0;\n\t\tconst contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : \"?\";\n\n\t\t// Replace home directory with ~\n\t\tlet pwd = formatCwdForFooter(this.facade.getCwd(), process.env.HOME || process.env.USERPROFILE);\n\n\t\t// Add git branch if available\n\t\tconst branch = this.footerData.getGitBranch();\n\t\tif (branch) {\n\t\t\tpwd = `${pwd} (${branch})`;\n\t\t}\n\n\t\t// Add session name if set\n\t\tconst sessionName = this.facade.getSessionName();\n\t\tif (sessionName) {\n\t\t\tpwd = `${pwd} • ${sessionName}`;\n\t\t}\n\n\t\t// Build stats line\n\t\tconst statsParts = [];\n\t\tif (usageTotals.input) statsParts.push(`↑${formatTokens(usageTotals.input)}`);\n\t\tif (usageTotals.output) statsParts.push(`↓${formatTokens(usageTotals.output)}`);\n\t\tif (usageTotals.cacheRead) statsParts.push(`R${formatTokens(usageTotals.cacheRead)}`);\n\t\tif (usageTotals.cacheWrite) statsParts.push(`W${formatTokens(usageTotals.cacheWrite)}`);\n\t\tif ((usageTotals.cacheRead > 0 || usageTotals.cacheWrite > 0) && latestCacheHitRate !== undefined) {\n\t\t\tstatsParts.push(`CH${latestCacheHitRate.toFixed(1)}%`);\n\t\t}\n\n\t\t// Kimi Coding is subscription-backed despite using API-key authentication.\n\t\tconst usingSubscription = state.model\n\t\t\t? state.model.provider === \"kimi-coding\" || this.facade.isUsingSubscription(state.model.provider)\n\t\t\t: false;\n\t\tif (usageTotals.cost || usingSubscription) {\n\t\t\tconst costStr = `$${usageTotals.cost.toFixed(3)}${usingSubscription ? \" (sub)\" : \"\"}`;\n\t\t\tstatsParts.push(costStr);\n\t\t}\n\n\t\t// Colorize context percentage based on usage\n\t\tlet contextPercentStr: string;\n\t\tconst autoIndicator = this.autoCompactEnabled ? \" (auto)\" : \"\";\n\t\tconst contextPercentDisplay =\n\t\t\tcontextPercent === \"?\"\n\t\t\t\t? `?/${formatTokens(contextWindow)}${autoIndicator}`\n\t\t\t\t: `${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;\n\t\tif (contextPercentValue > 90) {\n\t\t\tcontextPercentStr = theme.fg(\"error\", contextPercentDisplay);\n\t\t} else if (contextPercentValue > 70) {\n\t\t\tcontextPercentStr = theme.fg(\"warning\", contextPercentDisplay);\n\t\t} else {\n\t\t\tcontextPercentStr = contextPercentDisplay;\n\t\t}\n\t\tstatsParts.push(contextPercentStr);\n\t\tif (areExperimentalFeaturesEnabled()) {\n\t\t\tstatsParts.push(`${theme.fg(\"dim\", \"•\")} ${theme.bold(theme.fg(\"warning\", \"xp\"))}`);\n\t\t}\n\n\t\tlet statsLeft = statsParts.join(\" \");\n\n\t\t// Add model name on the right side, plus thinking level if model supports it\n\t\tconst modelName = state.model?.id || \"no-model\";\n\n\t\tlet statsLeftWidth = visibleWidth(statsLeft);\n\n\t\t// If statsLeft is too wide, truncate it\n\t\tif (statsLeftWidth > width) {\n\t\t\tstatsLeft = truncateToWidth(statsLeft, width, \"...\");\n\t\t\tstatsLeftWidth = visibleWidth(statsLeft);\n\t\t}\n\n\t\t// Calculate available space for padding (minimum 2 spaces between stats and model)\n\t\tconst minPadding = 2;\n\n\t\t// Add thinking level indicator if model supports reasoning\n\t\tlet rightSideWithoutProvider = modelName;\n\t\tif (state.model?.reasoning) {\n\t\t\tconst thinkingLevel = state.thinkingLevel || \"off\";\n\t\t\trightSideWithoutProvider =\n\t\t\t\tthinkingLevel === \"off\" ? `${modelName} • thinking off` : `${modelName} • ${thinkingLevel}`;\n\t\t}\n\n\t\t// Prepend the provider in parentheses if there are multiple providers and there's enough room\n\t\tlet rightSide = rightSideWithoutProvider;\n\t\tif (this.footerData.getAvailableProviderCount() > 1 && state.model) {\n\t\t\trightSide = `(${state.model!.provider}) ${rightSideWithoutProvider}`;\n\t\t\tif (statsLeftWidth + minPadding + visibleWidth(rightSide) > width) {\n\t\t\t\t// Too wide, fall back\n\t\t\t\trightSide = rightSideWithoutProvider;\n\t\t\t}\n\t\t}\n\n\t\tconst rightSideWidth = visibleWidth(rightSide);\n\t\tconst totalNeeded = statsLeftWidth + minPadding + rightSideWidth;\n\n\t\tlet statsLine: string;\n\t\tif (totalNeeded <= width) {\n\t\t\t// Both fit - add padding to right-align model\n\t\t\tconst padding = \" \".repeat(width - statsLeftWidth - rightSideWidth);\n\t\t\tstatsLine = statsLeft + padding + rightSide;\n\t\t} else {\n\t\t\t// Need to truncate right side\n\t\t\tconst availableForRight = width - statsLeftWidth - minPadding;\n\t\t\tif (availableForRight > 0) {\n\t\t\t\tconst truncatedRight = truncateToWidth(rightSide, availableForRight, \"\");\n\t\t\t\tconst truncatedRightWidth = visibleWidth(truncatedRight);\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, width - statsLeftWidth - truncatedRightWidth));\n\t\t\t\tstatsLine = statsLeft + padding + truncatedRight;\n\t\t\t} else {\n\t\t\t\t// Not enough space for right side at all\n\t\t\t\tstatsLine = statsLeft;\n\t\t\t}\n\t\t}\n\n\t\t// Apply dim to each part separately. statsLeft may contain color codes (for context %)\n\t\t// that end with a reset, which would clear an outer dim wrapper. So we dim the parts\n\t\t// before and after the colored section independently.\n\t\tconst dimStatsLeft = theme.fg(\"dim\", statsLeft);\n\t\tconst remainder = statsLine.slice(statsLeft.length); // padding + rightSide\n\t\tconst dimRemainder = theme.fg(\"dim\", remainder);\n\n\t\tconst pwdLine = truncateToWidth(theme.fg(\"dim\", pwd), width, theme.fg(\"dim\", \"...\"));\n\t\tconst lines = [pwdLine, dimStatsLeft + dimRemainder];\n\n\t\t// Add goal/todo status, only when a goal exists; an empty todo set shows the goal alone.\n\t\tif (goalTitle !== undefined) {\n\t\t\tconst goalParts = [`goal: ${goalTitle}`];\n\t\t\tif (todoTotal > 0) {\n\t\t\t\tgoalParts.push(`todo ${todoDone}/${todoTotal}`);\n\t\t\t}\n\t\t\tconst goalLine = theme.fg(\"dim\", sanitizeStatusText(goalParts.join(\" • \")));\n\t\t\tlines.push(truncateToWidth(goalLine, width, theme.fg(\"dim\", \"...\")));\n\t\t}\n\n\t\treturn lines;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"footer.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"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","sourcesContent":["import { isAbsolute, relative, resolve, sep } from \"node:path\";\nimport { type Component, truncateToWidth, visibleWidth } from \"@agent-forge/tui\";\nimport type { AgentSession } from \"../../../core/agent-session.ts\";\nimport { areExperimentalFeaturesEnabled } from \"../../../core/experimental.ts\";\nimport { type CodingAgentFacadeV1, createCodingAgentFacade } from \"../../../core/facade/index.ts\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport { addUsageToTotals, createUsageTotals } from \"../../../core/usage-totals.ts\";\nimport { theme } from \"../theme/theme.ts\";\n\n/**\n * Sanitize text for display in a single-line status.\n * Removes newlines, tabs, carriage returns, and other control characters.\n */\nfunction sanitizeStatusText(text: string): string {\n\t// Replace newlines, tabs, carriage returns with space, then collapse multiple spaces\n\treturn text\n\t\t.replace(/[\\r\\n\\t]/g, \" \")\n\t\t.replace(/ +/g, \" \")\n\t\t.trim();\n}\n\n/**\n * Format token counts for compact footer display.\n */\nexport function formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\nexport function formatCwdForFooter(cwd: string, home: string | undefined): string {\n\tif (!home) return cwd;\n\n\tconst resolvedCwd = resolve(cwd);\n\tconst resolvedHome = resolve(home);\n\tconst relativeToHome = relative(resolvedHome, resolvedCwd);\n\tconst isInsideHome =\n\t\trelativeToHome === \"\" ||\n\t\t(relativeToHome !== \"..\" && !relativeToHome.startsWith(`..${sep}`) && !isAbsolute(relativeToHome));\n\n\tif (!isInsideHome) return cwd;\n\treturn relativeToHome === \"\" ? \"~\" : `~${sep}${relativeToHome}`;\n}\n\n/** Shape of the `goal.state` custom entry data written by the builtin goal capability. */\ninterface FooterGoalState {\n\tgoals?: Array<{ title?: unknown }>;\n}\n\n/** Shape of the `todo.state` custom entry data written by the builtin todo capability. */\ninterface FooterTodoState {\n\ttodos?: Array<{ status?: unknown }>;\n}\n\n/** Shape of the `workflow.state` custom entry data written by the workflow plugin. */\ninterface FooterWorkflowState {\n\tworkflows?: Array<{\n\t\ttitle?: unknown;\n\t\tstatus?: unknown;\n\t\truntime?: Array<{ status?: unknown }>;\n\t\tdiagnostics?: unknown[];\n\t}>;\n}\n\n/**\n * Build the one-line workflow summary from the latest `workflow.state` snapshot:\n * `wf: <title> <done>/<total>` plus status markers, in order — `▶n` (n>=2\n * parallel active stages), `⏸` (a stage awaiting review), `⚠` (non-empty\n * diagnostics), `✗` (failed workflow); done counts completed+skipped stages.\n * Picks the newest non-terminal workflow, falling back to the newest one when\n * all are terminal; returns undefined when there is no workflow to show.\n */\nfunction summarizeWorkflowState(state: FooterWorkflowState | undefined): string | undefined {\n\tconst workflows = state?.workflows;\n\tconst records = Array.isArray(workflows) ? workflows : [];\n\tconst record =\n\t\t[...records].reverse().find((item) => item?.status === \"draft\" || item?.status === \"running\") ?? records.at(-1);\n\tif (record === undefined || typeof record.title !== \"string\") {\n\t\treturn undefined;\n\t}\n\n\tconst stages = Array.isArray(record.runtime) ? record.runtime : [];\n\tconst done = stages.filter((stage) => stage?.status === \"completed\" || stage?.status === \"skipped\").length;\n\tconst activeCount = stages.filter((stage) => stage?.status === \"active\").length;\n\n\tconst parts = [`wf: ${record.title} ${done}/${stages.length}`];\n\tif (activeCount >= 2) parts.push(`▶${activeCount}`);\n\tif (stages.some((stage) => stage?.status === \"awaiting_review\")) parts.push(\"⏸\");\n\tif (Array.isArray(record.diagnostics) && record.diagnostics.length > 0) parts.push(\"⚠\");\n\tif (record.status === \"failed\") parts.push(\"✗\");\n\treturn parts.join(\" \");\n}\n\n/**\n * Footer component that shows pwd, token stats, and context usage.\n * Computes token/context stats from session, gets git branch and extension statuses from provider.\n */\nexport class FooterComponent implements Component {\n\tprivate autoCompactEnabled = true;\n\tprivate session: AgentSession;\n\tprivate footerData: ReadonlyFooterDataProvider;\n\n\tconstructor(session: AgentSession, footerData: ReadonlyFooterDataProvider) {\n\t\tthis.session = session;\n\t\tthis.footerData = footerData;\n\t}\n\n\tsetSession(session: AgentSession): void {\n\t\tthis.session = session;\n\t}\n\n\t// Stable facade (阶段 1 slice 1): derived on each access; the facade and\n\t// `this.session` always resolve to the same AgentSession, so setSession()\n\t// rebind stays the only rebind path.\n\tprivate get facade(): CodingAgentFacadeV1 {\n\t\treturn createCodingAgentFacade(this.session);\n\t}\n\n\tsetAutoCompactEnabled(enabled: boolean): void {\n\t\tthis.autoCompactEnabled = enabled;\n\t}\n\n\t/**\n\t * No-op: git branch caching now handled by provider.\n\t * Kept for compatibility with existing call sites in interactive-mode.\n\t */\n\tinvalidate(): void {\n\t\t// No-op: git branch is cached/invalidated by provider\n\t}\n\n\t/**\n\t * Clean up resources.\n\t * Git watcher cleanup now handled by provider.\n\t */\n\tdispose(): void {\n\t\t// Git watcher cleanup handled by provider\n\t}\n\n\trender(width: number): string[] {\n\t\tconst state = this.facade.getState();\n\n\t\t// Calculate cumulative usage from ALL session entries (not just post-compaction messages)\n\t\tconst usageTotals = createUsageTotals();\n\t\tlet latestCacheHitRate: number | undefined;\n\n\t\t// Latest goal/todo capability state: the builtin goal/todo capabilities announce\n\t\t// goal.changed / todo.changed and persist the same state as goal.state / todo.state\n\t\t// custom entries; the last entry per type wins.\n\t\tlet goalTitle: string | undefined;\n\t\tlet todoDone = 0;\n\t\tlet todoTotal = 0;\n\t\tlet workflowState: FooterWorkflowState | undefined;\n\n\t\tfor (const entry of this.facade.getEntries()) {\n\t\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\t\taddUsageToTotals(usageTotals, entry.message.usage);\n\n\t\t\t\tconst latestPromptTokens =\n\t\t\t\t\tentry.message.usage.input + entry.message.usage.cacheRead + entry.message.usage.cacheWrite;\n\t\t\t\tlatestCacheHitRate =\n\t\t\t\t\tlatestPromptTokens > 0 ? (entry.message.usage.cacheRead / latestPromptTokens) * 100 : undefined;\n\t\t\t} else if (entry.type === \"message\" && entry.message.role === \"toolResult\" && entry.message.usage) {\n\t\t\t\taddUsageToTotals(usageTotals, entry.message.usage);\n\t\t\t} else if ((entry.type === \"branch_summary\" || entry.type === \"compaction\") && entry.usage) {\n\t\t\t\taddUsageToTotals(usageTotals, entry.usage);\n\t\t\t} else if (entry.type === \"custom\" && entry.customType === \"goal.state\") {\n\t\t\t\tconst goals = (entry.data as FooterGoalState | undefined)?.goals;\n\t\t\t\tconst current = Array.isArray(goals) ? goals.at(-1) : undefined;\n\t\t\t\tif (current && typeof current.title === \"string\") {\n\t\t\t\t\tgoalTitle = current.title;\n\t\t\t\t}\n\t\t\t} else if (entry.type === \"custom\" && entry.customType === \"todo.state\") {\n\t\t\t\tconst todos = (entry.data as FooterTodoState | undefined)?.todos;\n\t\t\t\tif (Array.isArray(todos)) {\n\t\t\t\t\ttodoDone = todos.filter((item) => item?.status === \"done\").length;\n\t\t\t\t\ttodoTotal = todos.length;\n\t\t\t\t}\n\t\t\t} else if (entry.type === \"custom\" && entry.customType === \"workflow.state\") {\n\t\t\t\tworkflowState = entry.data as FooterWorkflowState | undefined;\n\t\t\t}\n\t\t}\n\n\t\t// Calculate context usage from session (handles compaction correctly).\n\t\t// After compaction, tokens are unknown until the next LLM response.\n\t\tconst contextUsage = this.facade.getContextUsage();\n\t\tconst contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;\n\t\tconst contextPercentValue = contextUsage?.percent ?? 0;\n\t\tconst contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : \"?\";\n\n\t\t// Replace home directory with ~\n\t\tlet pwd = formatCwdForFooter(this.facade.getCwd(), process.env.HOME || process.env.USERPROFILE);\n\n\t\t// Add git branch if available\n\t\tconst branch = this.footerData.getGitBranch();\n\t\tif (branch) {\n\t\t\tpwd = `${pwd} (${branch})`;\n\t\t}\n\n\t\t// Add session name if set\n\t\tconst sessionName = this.facade.getSessionName();\n\t\tif (sessionName) {\n\t\t\tpwd = `${pwd} • ${sessionName}`;\n\t\t}\n\n\t\t// Build stats line\n\t\tconst statsParts = [];\n\t\tif (usageTotals.input) statsParts.push(`↑${formatTokens(usageTotals.input)}`);\n\t\tif (usageTotals.output) statsParts.push(`↓${formatTokens(usageTotals.output)}`);\n\t\tif (usageTotals.cacheRead) statsParts.push(`R${formatTokens(usageTotals.cacheRead)}`);\n\t\tif (usageTotals.cacheWrite) statsParts.push(`W${formatTokens(usageTotals.cacheWrite)}`);\n\t\tif ((usageTotals.cacheRead > 0 || usageTotals.cacheWrite > 0) && latestCacheHitRate !== undefined) {\n\t\t\tstatsParts.push(`CH${latestCacheHitRate.toFixed(1)}%`);\n\t\t}\n\n\t\t// Kimi Coding is subscription-backed despite using API-key authentication.\n\t\tconst usingSubscription = state.model\n\t\t\t? state.model.provider === \"kimi-coding\" || this.facade.isUsingSubscription(state.model.provider)\n\t\t\t: false;\n\t\tif (usageTotals.cost || usingSubscription) {\n\t\t\tconst costStr = `$${usageTotals.cost.toFixed(3)}${usingSubscription ? \" (sub)\" : \"\"}`;\n\t\t\tstatsParts.push(costStr);\n\t\t}\n\n\t\t// Colorize context percentage based on usage\n\t\tlet contextPercentStr: string;\n\t\tconst autoIndicator = this.autoCompactEnabled ? \" (auto)\" : \"\";\n\t\tconst contextPercentDisplay =\n\t\t\tcontextPercent === \"?\"\n\t\t\t\t? `?/${formatTokens(contextWindow)}${autoIndicator}`\n\t\t\t\t: `${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;\n\t\tif (contextPercentValue > 90) {\n\t\t\tcontextPercentStr = theme.fg(\"error\", contextPercentDisplay);\n\t\t} else if (contextPercentValue > 70) {\n\t\t\tcontextPercentStr = theme.fg(\"warning\", contextPercentDisplay);\n\t\t} else {\n\t\t\tcontextPercentStr = contextPercentDisplay;\n\t\t}\n\t\tstatsParts.push(contextPercentStr);\n\t\tif (areExperimentalFeaturesEnabled()) {\n\t\t\tstatsParts.push(`${theme.fg(\"dim\", \"•\")} ${theme.bold(theme.fg(\"warning\", \"xp\"))}`);\n\t\t}\n\n\t\tlet statsLeft = statsParts.join(\" \");\n\n\t\t// Add model name on the right side, plus thinking level if model supports it\n\t\tconst modelName = state.model?.id || \"no-model\";\n\n\t\tlet statsLeftWidth = visibleWidth(statsLeft);\n\n\t\t// If statsLeft is too wide, truncate it\n\t\tif (statsLeftWidth > width) {\n\t\t\tstatsLeft = truncateToWidth(statsLeft, width, \"...\");\n\t\t\tstatsLeftWidth = visibleWidth(statsLeft);\n\t\t}\n\n\t\t// Calculate available space for padding (minimum 2 spaces between stats and model)\n\t\tconst minPadding = 2;\n\n\t\t// Add thinking level indicator if model supports reasoning\n\t\tlet rightSideWithoutProvider = modelName;\n\t\tif (state.model?.reasoning) {\n\t\t\tconst thinkingLevel = state.thinkingLevel || \"off\";\n\t\t\trightSideWithoutProvider =\n\t\t\t\tthinkingLevel === \"off\" ? `${modelName} • thinking off` : `${modelName} • ${thinkingLevel}`;\n\t\t}\n\n\t\t// Prepend the provider in parentheses if there are multiple providers and there's enough room\n\t\tlet rightSide = rightSideWithoutProvider;\n\t\tif (this.footerData.getAvailableProviderCount() > 1 && state.model) {\n\t\t\trightSide = `(${state.model!.provider}) ${rightSideWithoutProvider}`;\n\t\t\tif (statsLeftWidth + minPadding + visibleWidth(rightSide) > width) {\n\t\t\t\t// Too wide, fall back\n\t\t\t\trightSide = rightSideWithoutProvider;\n\t\t\t}\n\t\t}\n\n\t\tconst rightSideWidth = visibleWidth(rightSide);\n\t\tconst totalNeeded = statsLeftWidth + minPadding + rightSideWidth;\n\n\t\tlet statsLine: string;\n\t\tif (totalNeeded <= width) {\n\t\t\t// Both fit - add padding to right-align model\n\t\t\tconst padding = \" \".repeat(width - statsLeftWidth - rightSideWidth);\n\t\t\tstatsLine = statsLeft + padding + rightSide;\n\t\t} else {\n\t\t\t// Need to truncate right side\n\t\t\tconst availableForRight = width - statsLeftWidth - minPadding;\n\t\t\tif (availableForRight > 0) {\n\t\t\t\tconst truncatedRight = truncateToWidth(rightSide, availableForRight, \"\");\n\t\t\t\tconst truncatedRightWidth = visibleWidth(truncatedRight);\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, width - statsLeftWidth - truncatedRightWidth));\n\t\t\t\tstatsLine = statsLeft + padding + truncatedRight;\n\t\t\t} else {\n\t\t\t\t// Not enough space for right side at all\n\t\t\t\tstatsLine = statsLeft;\n\t\t\t}\n\t\t}\n\n\t\t// Apply dim to each part separately. statsLeft may contain color codes (for context %)\n\t\t// that end with a reset, which would clear an outer dim wrapper. So we dim the parts\n\t\t// before and after the colored section independently.\n\t\tconst dimStatsLeft = theme.fg(\"dim\", statsLeft);\n\t\tconst remainder = statsLine.slice(statsLeft.length); // padding + rightSide\n\t\tconst dimRemainder = theme.fg(\"dim\", remainder);\n\n\t\tconst pwdLine = truncateToWidth(theme.fg(\"dim\", pwd), width, theme.fg(\"dim\", \"...\"));\n\t\tconst lines = [pwdLine, dimStatsLeft + dimRemainder];\n\n\t\t// Add goal/todo status, only when a goal exists; an empty todo set shows the goal alone.\n\t\tif (goalTitle !== undefined) {\n\t\t\tconst goalParts = [`goal: ${goalTitle}`];\n\t\t\tif (todoTotal > 0) {\n\t\t\t\tgoalParts.push(`todo ${todoDone}/${todoTotal}`);\n\t\t\t}\n\t\t\tconst goalLine = theme.fg(\"dim\", sanitizeStatusText(goalParts.join(\" • \")));\n\t\t\tlines.push(truncateToWidth(goalLine, width, theme.fg(\"dim\", \"...\")));\n\t\t}\n\n\t\t// Add workflow status, only when a workflow snapshot reports one.\n\t\tconst workflowSummary = summarizeWorkflowState(workflowState);\n\t\tif (workflowSummary !== undefined) {\n\t\t\tconst workflowLine = theme.fg(\"dim\", sanitizeStatusText(workflowSummary));\n\t\t\tlines.push(truncateToWidth(workflowLine, width, theme.fg(\"dim\", \"...\")));\n\t\t}\n\n\t\treturn lines;\n\t}\n}\n"]}
|