@north-light/cli 0.3.418 → 0.3.420
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/dto/docs.d.ts +7 -0
- package/dist/api/dto/nodes.d.ts +1 -0
- package/dist/builtin-memory/crouter-sdk/README.md +3 -3
- package/dist/builtin-memory/crouter-sdk/client.md +16 -0
- package/dist/builtin-memory/crouter-sdk/getting-started.md +2 -2
- package/dist/builtin-memory/crouter-sdk/guides/README.md +1 -1
- package/dist/builtin-memory/crouter-sdk/guides/apps-on-crouter-cloud.md +222 -3
- package/dist/builtin-memory/crouter-sdk/release-notes.md +10 -0
- package/dist/builtin-memory/crouter-sdk/testing.md +23 -1
- package/dist/clients/attach/input/controller.d.ts +1 -0
- package/dist/clients/attach/input/controller.js +2 -2
- package/dist/clients/attach/render/chat-view.d.ts +44 -0
- package/dist/clients/attach/render/chat-view.js +3 -3
- package/dist/clients/attach/session/frames.d.ts +2 -0
- package/dist/clients/attach/session/frames.js +1 -1
- package/dist/clients/attach/session/input-wiring.d.ts +3 -0
- package/dist/clients/attach/session/input-wiring.js +1 -1
- package/dist/clients/attach/slash/dispatch.d.ts +4 -0
- package/dist/clients/attach/slash/dispatch.js +2 -2
- package/dist/clients/attach/viewer.js +567 -563
- package/dist/core/command-plugins/bundle.d.ts +3 -0
- package/dist/core/command-plugins/bundle.js +1 -1
- package/dist/core/config.js +1 -1
- package/dist/core/fs-utils.d.ts +7 -0
- package/dist/core/fs-utils.js +3 -3
- package/dist/core/graph/package-docs.d.ts +4 -1
- package/dist/core/graph/package-docs.js +5 -5
- package/dist/core/keybindings/catalog.d.ts +1 -1
- package/dist/core/keybindings/catalog.js +1 -1
- package/dist/core/manifest.d.ts +15 -0
- package/dist/core/manifest.js +1 -1
- package/dist/core/plugin-quarantine.d.ts +16 -0
- package/dist/core/plugin-quarantine.js +1 -0
- package/dist/core/providers/bundles.js +2 -2
- package/dist/core/runtime/broker/rebind.d.ts +5 -0
- package/dist/core/runtime/broker/rebind.js +1 -1
- package/dist/core/runtime/broker/turn-replies.d.ts +33 -0
- package/dist/core/runtime/broker/turn-replies.js +1 -0
- package/dist/core/runtime/broker-protocol.d.ts +12 -1
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/node-read.js +3 -3
- package/dist/core/runtime/tmux-bindings.js +1 -1
- package/dist/core/runtime/turn-reply-summary.d.ts +6 -0
- package/dist/core/runtime/turn-reply-summary.js +11 -0
- package/dist/core/user-settings.d.ts +15 -0
- package/dist/core/user-settings.js +1 -1
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/crtrd.js +6 -5
- package/dist/shared/turn-replies.d.ts +27 -0
- package/dist/shared/turn-replies.js +5 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.js +1 -1
- package/docs/sdk/README.md +3 -3
- package/docs/sdk/client.md +16 -0
- package/docs/sdk/getting-started.md +2 -2
- package/docs/sdk/guides/README.md +1 -1
- package/docs/sdk/guides/apps-on-crouter-cloud.md +218 -1
- package/docs/sdk/release-notes.md +10 -0
- package/docs/sdk/testing.md +23 -1
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +12 -12
package/dist/core/manifest.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var s=Object.defineProperty;var e=(t,r)=>s(t,"name",{value:r,configurable:!0});import{join as a}from"node:path";import{MARKETPLACE_MANIFEST_DIR as i,MARKETPLACE_MANIFEST_FILE as u,PLUGIN_MANIFEST_DIR as f,PLUGIN_MANIFEST_FILE as c}from"../types.js";import{readJsonIfExists as l}from"./fs-utils.js";function M(t){return a(t,f,c)}e(M,"pluginManifestPath");function m(t){return a(t,i,u)}e(m,"marketplaceManifestPath");function o(t){let r;try{r=l(t)}catch(n){return{status:"broken",error:n instanceof Error?n.message:String(n)}}return r===null?{status:"absent"}:typeof r!="object"||Array.isArray(r)?{status:"broken",error:"manifest is not a JSON object"}:{status:"ok",manifest:r}}e(o,"readManifestChecked");function p(t){return o(M(t))}e(p,"readPluginManifestChecked");function k(t){const r=p(t);return r.status==="ok"?r.manifest:null}e(k,"readPluginManifest");function P(t){const r=o(m(t));return r.status==="ok"?r.manifest:null}e(P,"readMarketplaceManifest");export{m as marketplaceManifestPath,M as pluginManifestPath,P as readMarketplaceManifest,k as readPluginManifest,p as readPluginManifestChecked};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface QuarantinedPlugin {
|
|
2
|
+
name: string;
|
|
3
|
+
/** which file was damaged, relative to the plugin root */
|
|
4
|
+
file: string;
|
|
5
|
+
reason: string;
|
|
6
|
+
/** where the directory was moved; absent when the move itself failed and the directory was left in place */
|
|
7
|
+
movedTo?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Why the plugin's own files cannot be used, or null when they are intact (or the directory is not a plugin). */
|
|
10
|
+
export declare function brokenPluginReason(root: string): {
|
|
11
|
+
file: string;
|
|
12
|
+
reason: string;
|
|
13
|
+
} | null;
|
|
14
|
+
/** Quarantine every user-scope plugin directory with a damaged manifest or command file. Never throws:
|
|
15
|
+
* a directory that cannot be moved is reported without `movedTo` and left for the tolerant readers to skip. */
|
|
16
|
+
export declare function quarantineBrokenPlugins(now?: () => number): QuarantinedPlugin[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var p=Object.defineProperty;var u=(t,n)=>p(t,"name",{value:n,configurable:!0});import{readFileSync as m,renameSync as g,statSync as h}from"node:fs";import{join as a,resolve as y,sep as d}from"node:path";import{ensureDir as S,listDirs as b,pathExists as f}from"./fs-utils.js";import{readPluginManifestChecked as k}from"./manifest.js";import{bundleSwapInFlightElsewhere as D}from"./plugin-swap-lock.js";import{pluginsDir as P,userScopeRoot as j}from"./scope.js";function q(t){const n=k(t);if(n.status==="broken")return{file:".crouter-plugin/plugin.json",reason:n.error};if(n.status==="absent")return null;const r=n.manifest.commands;if(typeof r!="string"||r==="")return null;const e=y(t,r);if(e!==t&&!e.startsWith(t+d)||!f(e))return null;try{if(h(e).size===0)return{file:r,reason:"file is empty (0 bytes)"};JSON.parse(m(e,"utf8"))}catch(o){return{file:r,reason:o instanceof Error?o.message:String(o)}}return null}u(q,"brokenPluginReason");function z(t=Date.now){const n=P("user");if(n===null||!f(n))return[];const r=j(),e=[];for(const o of b(n)){const l=a(n,o);if(D(r,o))continue;let i;try{i=q(l)}catch(s){i={file:".crouter-plugin/plugin.json",reason:String(s)}}if(i===null)continue;const c={name:o,...i};try{const s=a(r,"quarantine","plugins",`${o}.${t()}`);S(a(r,"quarantine","plugins")),g(l,s),c.movedTo=s}catch{}e.push(c)}return e}u(z,"quarantineBrokenPlugins");export{q as brokenPluginReason,z as quarantineBrokenPlugins};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var X=Object.defineProperty;var i=(e,
|
|
2
|
-
`),
|
|
1
|
+
var X=Object.defineProperty;var i=(e,n)=>X(e,"name",{value:n,configurable:!0});import{existsSync as h,readdirSync as H,readFileSync as y,rmSync as b,statSync as x}from"node:fs";import{join as u}from"node:path";import{validateCommandManifest as Y}from"../../api/command-manifest/manifest.js";import{crtrHome as O}from"../canvas/paths.js";import{withCanvasWrite as ee}from"../canvas/db.js";import{bundleVersion as ne,isInstalledGeneration as re,recordCheckedGeneration as te}from"../command-plugins/bundle.js";import{readConfig as U,readState as oe}from"../config.js";import{emitEvent as g}from"../events/emit.js";import{withExclusiveDirectoryLockAsync as ie}from"../exclusive-lock.js";import{atomicWriteText as M,ensureDir as I,pathExists as ae}from"../fs-utils.js";import{reconcilePackageDocuments as se}from"../graph/package-docs.js";import{readPluginManifest as W}from"../manifest.js";import{bundleSwapLockPath as de}from"../plugin-swap-lock.js";import{pluginsDir as ue,userScopeRoot as ce}from"../scope.js";import{allGrants as fe}from"../grants/mirror.js";import{ProviderError as c}from"./errors.js";const T="[A-Za-z0-9_-]{1,64}",le=new RegExp(`^(${T}):(${T})$`),z=new RegExp(`^${T}$`),pe=3e4,me=3e4;function ve(e){const n=new Set;for(const r of e)if(r.status==="active")for(const{scope:t}of r.resolved_scopes){const o=le.exec(t);o&&o[1]!=="crtr"&&n.add(o[1])}return[...n].sort()}i(ve,"providerIdsFromGrants");function w(e){return u(ue("user"),e)}i(w,"pluginRoot");function F(){return u(O(),"providers")}i(F,"providersRoot");function G(e,n){return u(F(),e,`v${n}`)}i(G,"majorDir");function j(e){if(!z.test(e))throw new c("not_found",`"${e}" is not a provider id`,{param:"provider"})}i(j,"assertId");function A(){const e=U("user").runtime?.issuer;if(!e)throw new c("not_found","provider bundles need a directory-connected runtime");return e.replace(/\/+$/,"")}i(A,"directoryBase");async function q(e,n){const r=`${A()}/providers/${encodeURIComponent(e)}/plugin${n.version!==void 0?`?version=${n.version}`:""}`;let t;try{t=await fetch(r,{headers:{Accept:"application/x-tar",...n.ifNoneMatch!==void 0?{"If-None-Match":n.ifNoneMatch}:{}},signal:AbortSignal.timeout(pe)})}catch(s){return{status:"failed",message:`could not reach ${r}: ${s instanceof Error?s.message:String(s)}`}}if(t.status===304)return n.ifNoneMatch===void 0?{status:"failed",message:`HTTP 304 from ${r} without a conditional request`}:{status:304};if(t.status===404||t.status===410)return await t.body?.cancel().catch(()=>{}),{status:t.status===404?404:410,message:`HTTP ${t.status} from ${r}`};if(t.status<200||t.status>=300)return await t.body?.cancel().catch(()=>{}),{status:"failed",message:`HTTP ${t.status} from ${r}`};let o;try{o=new Uint8Array(await t.arrayBuffer())}catch(s){return{status:"failed",message:`reading ${r} failed: ${s instanceof Error?s.message:String(s)}`}}const a=t.headers.get("etag");return{status:200,raw:o,...a!==null?{etag:a}:{}}}i(q,"fetchProviderBundle");const _=new WeakSet;class S extends Error{static{i(this,"BundleInvalid")}issues;constructor(n,r){super(n),this.issues=r}}function V(e,n,r){if(r.provider===void 0)return"the archive carries no provider block";if(r.provider.id!==e)return`the archive is provider "${r.provider.id}", not "${e}"`;if(n!==void 0&&r.provider.major!==n)return`the archive is major ${r.provider.major}, not ${n}`;const t=["hooks","kinds","page_components","memory_extensions"].filter(o=>r[o]!==void 0);if(t.length>0)return`a provider bundle may not carry ${t.join(", ")}`}i(V,"wrongBundle");function C(e,n,r){g({level:"error",event:"daemon.providers.bundle_invalid",fields:{provider:e,...n!==void 0?{major:n}:{},...r instanceof S?{issues:r.issues}:{}},error:r})}i(C,"logInvalid");function Z(e,n,r){g({level:"warn",event:"daemon.providers.bundle_fetch_failed",fields:{provider:e,...n!==void 0?{major:n}:{},message:r}})}i(Z,"logFailure");async function L(){return import("../../commands/pkg/plugin-manage.js")}i(L,"pluginManage");const P=new Map,E=i(e=>`${O()}\0${e}`,"installKey");function he(e){const n=e,r=n?.code??n?.cause?.code;return typeof r=="string"&&/^[A-Z][A-Z0-9_]{1,30}$/.test(r)?`${r} on provider install directory`:e instanceof c&&e.message.includes("HTTP 404")?"directory returned HTTP 404":e instanceof c&&e.message.includes("HTTP 410")?"directory returned HTTP 410":"provider bundle could not be installed"}i(he,"publicInstallCause");function ge(e){if(m(e)===void 0)return P.get(E(e))??{status:"installing"}}i(ge,"providerInstallState");function we(e){return new c("provider_unavailable",`provider "${e}" unavailable: ${ge(e)?.error??"bundle installation pending"}`)}i(we,"unavailableProviderError");function m(e){const n=W(w(e));if(!(n?.provider===void 0||n.transport?.kind!=="http")&&ae(u(w(e),"commands.json"))){try{if(x(u(w(e),"commands.json")).size===0)return}catch{return}return{provider:n.provider,transport:{kind:"http",endpoint:n.transport.endpoint}}}}i(m,"installedManifest");async function k(e,n,r=!1){const t=ce();m(e)===void 0&&P.set(E(e),{status:"installing"});try{return I(u(t,"tmp")),await ie(de(t,e),async()=>{const o=w(e),a=W(o);if(a!==null&&a.provider===void 0)throw new c("provider_unavailable",`plugin "${e}" is installed and is not the directory's provider bundle`);const s=m(e)!==void 0;if(s&&r)return"unchanged";const f=s&&n?oe("user").plugins[e]?.etag:void 0,d=await q(e,f!==void 0?{ifNoneMatch:f}:{});if(d.status===304)return"unchanged";if(d.status===404||d.status===410)throw new c("not_found",`the directory serves no provider "${e}" (${d.message})`,{param:"provider"});if(d.status==="failed")throw new c("provider_unavailable",`provider "${e}" bundle fetch failed: ${d.message}`);const l=ne(d.raw);if(s&&re(e,"user",o,l))return te("user",e,d.etag,{swapped:!1}),"unchanged";const{installPluginArchive:v}=await L();try{await v(e,d.raw,{scope:"user",scopeRootPath:t,root:o,version:l,etag:d.etag,enable:!s,bundle:{endpoint:`${A()}/providers/${encodeURIComponent(e)}/plugin`},transport:{kind:"http",endpoint:A()},accept:i(p=>V(e,void 0,p),"accept")})}catch(p){C(e,void 0,p);const N=new c("not_found",`provider "${e}" served an invalid bundle: ${p instanceof Error?p.message:String(p)}`,{param:"provider"});throw _.add(N),N}try{ee(p=>se(p))}catch(p){g({level:"error",event:"daemon.providers.docs_reconcile_failed",fields:{provider:e},error:p})}return g({level:"info",event:"daemon.providers.bundle_installed",fields:{provider:e,version:l,replaced:s}}),P.delete(E(e)),s?"updated":"installed"},{timeoutMs:me,timeoutError:i(()=>new c("provider_unavailable",`timed out waiting for another process replacing plugin "${e}"`),"timeoutError")})}catch(o){throw m(e)===void 0&&P.set(E(e),{status:"install_failed",error:he(o)}),o instanceof c?o:(g({level:"error",event:"daemon.providers.bundle_install_failed",fields:{provider:e},error:o}),we(e))}}i(k,"refreshInstalled");async function We(e){j(e),m(e)===void 0&&await k(e,!1,!0)}i(We,"ensureProviderBundle");async function ze(e,n){return j(e),n.version!==void 0&&m(e)?.provider.major!==n.version?R(e,n.version,n.conditional):k(e,n.conditional)}i(ze,"refreshProviderBundle");async function J(e,n,r){const{validatePluginArchive:t}=await L(),o=await t(r);if(o.bundle===void 0)throw new S(`provider "${e}" major ${n} bundle is invalid: ${o.issues.map(s=>s.message).join("; ")}`,o.issues);const a=V(e,n,o.bundle);if(a!==void 0)throw new S(`provider "${e}" major ${n} bundle is invalid: ${a}`,[]);if(o.bundle.transport===void 0)throw new S(`provider "${e}" major ${n} bundle declares no transport`,[]);return o.bundle}i(J,"validateArchive");function $e(e){I(e),M(u(e,"retired"),`${new Date().toISOString()}
|
|
2
|
+
`),b(u(e,"bundle.tar"),{force:!0}),b(u(e,"etag"),{force:!0})}i($e,"retire");function K(e,n){return new c("provider_version_retired",`provider "${e}" major ${n} is retired`,{param:"version"})}i(K,"retiredError");async function R(e,n,r){const t=G(e,n),o=u(t,"bundle.tar"),a=h(o),s=a&&r&&h(u(t,"etag"))?y(u(t,"etag"),"utf8"):void 0,f=await q(e,{version:n,...s!==void 0?{ifNoneMatch:s}:{}});if(f.status===304)return"unchanged";if(f.status===410)throw $e(t),g({level:"info",event:"daemon.providers.major_retired",fields:{provider:e,major:n}}),K(e,n);if(f.status===404)throw new c("not_found",`provider "${e}" never served major ${n}`,{param:"version"});if(f.status==="failed")throw new c("provider_unavailable",`provider "${e}" major ${n} bundle fetch failed: ${f.message}`);try{await J(e,n,f.raw)}catch(l){C(e,n,l);const v=new c(a?"provider_unavailable":"not_found",l instanceof Error?l.message:String(l),{param:"version"});throw _.add(v),v}I(t),b(u(t,"retired"),{force:!0});const d=a&&Buffer.from(f.raw).equals(y(o));return d||M(o,f.raw),f.etag!==void 0?M(u(t,"etag"),f.etag):b(u(t,"etag"),{force:!0}),d?"unchanged":a?"updated":"installed"}i(R,"refreshPinned");function ye(){const e=[],n=F();if(!h(n))return e;for(const r of H(n)){if(!z.test(r))continue;let t;try{t=H(u(n,r))}catch{continue}for(const o of t){const a=/^v([1-9][0-9]*)$/.exec(o);a&&h(u(n,r,o,"bundle.tar"))&&e.push([r,Number(a[1])])}}return e}i(ye,"cachedMajors");function be(e){const n=Y(e,{transport:"http",reservedCoreNames:new Set});if(n.manifest===void 0)throw new c("not_found","the provider bundle's commands.json no longer validates");return n.manifest}i(be,"readCommands");const B=new Map,Q=new Map;function _e(e,n){const r=x(n),t=`${r.ino}:${r.mtimeMs}:${r.size}`,o=Q.get(e);if(o?.stamp===t)return o.commands;const a=be(JSON.parse(y(n,"utf8")));return Q.set(e,{stamp:t,commands:a}),a}i(_e,"installedCommands");async function Fe(e,n){j(e);const r=m(e);if(n===void 0||r?.provider.major===n){if(r===void 0)throw new c("not_found",`provider "${e}" has no installed bundle`,{param:"provider"});const l=w(e),v=_e(e,u(l,"commands.json"));return{id:e,major:r.provider.major,provider:r.provider,commands:v,transport:r.transport,source:"installed",root:l}}if(!Number.isInteger(n)||n<1)throw new c("invalid_request","version must be an integer of at least 1",{param:"version"});const t=G(e,n);if(h(u(t,"retired")))throw K(e,n);const o=u(t,"bundle.tar");h(o)||await R(e,n,!1);const a=`${e}/${n}`,s=x(o),f=`${s.mtimeMs}:${s.size}`;let d=B.get(a)?.stamp===f?B.get(a).bundle:void 0;if(d===void 0){try{d=await J(e,n,new Uint8Array(y(o)))}catch(l){throw C(e,n,l),new c("not_found",`provider "${e}" has no valid bundle for major ${n}`,{param:"version"})}B.set(a,{stamp:f,bundle:d})}return{id:e,major:n,provider:d.provider,commands:d.commands,transport:{kind:"http",endpoint:d.transport.endpoint},source:"pinned"}}i(Fe,"resolveProviderBundle");let $=null,D=!1;async function Se(){if(U("user").runtime?.issuer){for(const e of ve(fe()))try{await k(e,!0)}catch(n){n instanceof Object&&_.has(n)||Z(e,void 0,n instanceof Error?n.message:String(n))}for(const[e,n]of ye())try{await R(e,n,!0)}catch(r){if(r instanceof c&&r.code==="provider_version_retired"||r instanceof Object&&_.has(r))continue;Z(e,n,r instanceof Error?r.message:String(r))}}}i(Se,"syncOnce");function Ge(){return $!==null?(D=!0,$):($=(async()=>{try{do D=!1,await Se();while(D)}finally{$=null}})(),$)}i(Ge,"syncProviderBundles");export{We as ensureProviderBundle,ve as providerIdsFromGrants,ge as providerInstallState,ze as refreshProviderBundle,Fe as resolveProviderBundle,Ge as syncProviderBundles,we as unavailableProviderError};
|
|
@@ -5,6 +5,7 @@ import type { FaultRetry } from './fault-retry.js';
|
|
|
5
5
|
import type { EventProjection } from './event-projection.js';
|
|
6
6
|
import type { BrokerSession } from './read-ops.js';
|
|
7
7
|
import type { ToolGroupTracker } from './tool-groups.js';
|
|
8
|
+
import type { TurnReplyTracker } from './turn-replies.js';
|
|
8
9
|
import type { OperationId } from '../../events/types.js';
|
|
9
10
|
export interface SubscriptionGeneration {
|
|
10
11
|
id: number;
|
|
@@ -32,6 +33,10 @@ type RebindDriverDeps = {
|
|
|
32
33
|
uiContext: () => ExtensionUIContext;
|
|
33
34
|
registry: BrokerClientRegistry;
|
|
34
35
|
toolGroups: ToolGroupTracker;
|
|
36
|
+
turnReplies: TurnReplyTracker;
|
|
37
|
+
/** The bound session's full visible message list (cycle-aware), used to seed
|
|
38
|
+
* the open consolidated-reply turn. */
|
|
39
|
+
transcriptMessages: (session: BrokerSession) => readonly unknown[];
|
|
35
40
|
faultRetry: () => FaultRetry;
|
|
36
41
|
projection: () => EventProjection;
|
|
37
42
|
setActiveSession: (session: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var k=Object.defineProperty;var l=(d,e)=>k(d,"name",{value:e,configurable:!0});import{mkdirSync as v,writeFileSync as _}from"node:fs";import{join as A}from"node:path";import{nodeRunJobDir as E}from"../../canvas/paths.js";import{emitEvent as u}from"../../events/emit.js";import{operationIdContext as c}from"../../events/operation-id.js";import{installPersonaTransitionGate as I}from"../broker-persona-guidance.js";import{installRetryCardElision as T}from"./retry-card-elision.js";import{abortSessionFromExtension as w}from"./extension-abort.js";import{brokerRecovery as S,mutateBrokerFault as x,mutateBrokerProviderRetry as P}from"./daemon-ops.js";const f=2,m=3e4,b=Symbol("replacement-deadline-exceeded"),V="(interrupted)",g=Symbol.for("crtr.trailing-thinking-guard");function C(d){for(let e=d.length-1;e>=0;e--){const t=d[e];if(t!==void 0){if(t.type==="text"){if(t.text.trim().length===0)continue;return t}if(t.type==="thinking"){const n=t.thinkingSignature,r=typeof n=="string"&&n.trim().length>0;if(t.redacted!==!0&&t.thinking.trim().length===0&&!r)continue;return t}return t}}}l(C,"lastSerializedBlock");function y(d){return d.map(e=>e.role!=="assistant"||e.stopReason==="error"||e.stopReason==="aborted"||C(e.content)?.type!=="thinking"?e:{...e,content:[...e.content,{type:"text",text:V}]})}l(y,"guardTrailingThinking");function N(d){const e=d.convertToLlm;if(e[g]===!0)return;const t=l(n=>{const r=e(n);return r instanceof Promise?r.then(y):y(r)},"wrapped");t[g]=!0,d.convertToLlm=t}l(N,"installTrailingThinkingGuard");class
|
|
1
|
+
var k=Object.defineProperty;var l=(d,e)=>k(d,"name",{value:e,configurable:!0});import{mkdirSync as v,writeFileSync as _}from"node:fs";import{join as A}from"node:path";import{nodeRunJobDir as E}from"../../canvas/paths.js";import{emitEvent as u}from"../../events/emit.js";import{operationIdContext as c}from"../../events/operation-id.js";import{installPersonaTransitionGate as I}from"../broker-persona-guidance.js";import{installRetryCardElision as T}from"./retry-card-elision.js";import{abortSessionFromExtension as w}from"./extension-abort.js";import{brokerRecovery as S,mutateBrokerFault as x,mutateBrokerProviderRetry as P}from"./daemon-ops.js";const f=2,m=3e4,b=Symbol("replacement-deadline-exceeded"),V="(interrupted)",g=Symbol.for("crtr.trailing-thinking-guard");function C(d){for(let e=d.length-1;e>=0;e--){const t=d[e];if(t!==void 0){if(t.type==="text"){if(t.text.trim().length===0)continue;return t}if(t.type==="thinking"){const n=t.thinkingSignature,r=typeof n=="string"&&n.trim().length>0;if(t.redacted!==!0&&t.thinking.trim().length===0&&!r)continue;return t}return t}}}l(C,"lastSerializedBlock");function y(d){return d.map(e=>e.role!=="assistant"||e.stopReason==="error"||e.stopReason==="aborted"||C(e.content)?.type!=="thinking"?e:{...e,content:[...e.content,{type:"text",text:V}]})}l(y,"guardTrailingThinking");function N(d){const e=d.convertToLlm;if(e[g]===!0)return;const t=l(n=>{const r=e(n);return r instanceof Promise?r.then(y):y(r)},"wrapped");t[g]=!0,d.convertToLlm=t}l(N,"installTrailingThinkingGuard");class ${static{l(this,"RebindDriver")}deps;sessionValue;servicesValue;unsubscribe;installed;nextSubscriptionGeneration=0;rebindTail=Promise.resolve();latestRebindRequest=0;replacementTail=Promise.resolve();admittedReplacements=0;agentRunActiveValue=!1;shutdownRequested=!1;constructor(e){this.deps=e,this.sessionValue=e.session,this.servicesValue=e.services}session(){return this.sessionValue}services(){return this.servicesValue}installedGeneration(){return this.installed}isAgentRunActive(){return this.agentRunActiveValue}isReplacing(){return this.admittedReplacements>0}requestShutdown(){if(!this.agentRunActiveValue){this.deps.disposeAndExit("shutdown-hook");return}this.shutdownRequested=!0}setRebindSession(){this.deps.runtime?.setRebindSession(e=>this.enqueueRebind(e,this.deps.runtime.services))}enqueueRebind(e,t){const n=++this.latestRebindRequest,r=this.rebindTail.then(async()=>{if(n!==this.latestRebindRequest)return;if(this.installed!==void 0){typeof this.sessionValue.sessionFile=="string"&&this.sessionValue.sessionFile!==""&&await P(this.deps.nodeId,{op:"invalidate",session_id:this.sessionValue.sessionManager.getSessionId()});const s=(await S(this.deps.nodeId)).fault;s?.link==="pi\u2192provider"&&s.retry.disposition==="auto"&&s.retry.by==="daemon"&&await x(this.deps.nodeId,{op:"clear",link:"pi\u2192provider",preserve_episode:!0})}if(this.installed?.executingTools.clear(),this.removeInstalledSubscription(),this.deps.setActiveSession(e),this.deps.projection().reset(),this.deps.faultRetry().reset(),this.agentRunActiveValue=!1,this.deps.onSessionRebind(),this.deps.toolGroups.resetForSession(),await e.bindExtensions({uiContext:this.deps.uiContext(),mode:"rpc",abortHandler:l(()=>w(e,()=>{const s=this.installed;s?.session===e&&(s.stagedRefreshAbort=!0)}),"abortHandler"),shutdownHandler:l(()=>this.requestShutdown(),"shutdownHandler")}),n!==this.latestRebindRequest)return;this.removeInstalledSubscription(),this.sessionValue=e,this.servicesValue=t;const a=e.agent;if(a&&(I(this.deps.nodeId,{agent:a,sessionManager:e.sessionManager},()=>this.deps.faultRetry().notePersonaGateFailure()),T(a),a.steeringMode="all",a.followUpMode="all",N(a)),this.deps.cfg.editorName!==void 0&&this.deps.cfg.editorName!=="")try{e.setSessionName(this.deps.cfg.editorName)}catch{}const o={id:++this.nextSubscriptionGeneration,session:e,fallback:{blocked:!1},stagedProviderAgentEnd:null,stagedWatchdogAbort:!1,stagedRefreshAbort:!1,stagedOverflowFailure:null,executingTools:new Set};this.unsubscribe=this.sessionValue.subscribe(s=>{if(!this.deps.projection().isCurrent(o))return;if(c.current()!==void 0){this.executeSubscriptionCallback(o,s);return}const i=o.fallback;if(s.type==="turn_start"&&i.storedId!==void 0){i.storedId=void 0,i.blocked=!0,c.fresh(()=>{u({level:"warn",event:"broker.turn.fallback_overlap",fields:{generation:o.id,engine_event:s.type}}),this.executeSubscriptionCallback(o,s)});return}if(s.type==="turn_start"&&!i.blocked){c.fresh(R=>{i.storedId=R,this.executeSubscriptionCallback(o,s)});return}const p=i.storedId;if(p!==void 0&&!i.blocked){c.run(p,()=>{this.executeSubscriptionCallback(o,s),s.type==="agent_settled"&&i.storedId===p&&(i.storedId=void 0)});return}this.executeSubscriptionCallback(o,s)}),this.installed=o;try{this.deps.turnReplies.seed(this.deps.transcriptMessages(e))}catch(s){u({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`turn reply seed failed: ${String(s)}`}})}this.deps.projection().rearmIfStreaming(o),this.captureSystemPrompt(e)});return this.rebindTail=r.catch(()=>{}),r}runReplacement(e,t,n){const r=this.deps.runtime;if(r===void 0){this.deps.registry.sendFrame(e,{type:"error",code:"engine_error",message:"session replacement unsupported at this engine pin"});return}if(this.admittedReplacements>=f){c.fresh(()=>u({level:"warn",event:"broker.session_replacement.rejected",outcome:"skipped",fields:{op:t,reason:"capacity",admitted:f,cap:f}})),this.ackTo(e,t,!1,`session replacement busy (${f} active or queued)`);return}this.admittedReplacements++;const a=this.replacementTail.then(async()=>{try{await c.fresh(async()=>{const o=process.hrtime.bigint();let s;try{const h=new Promise(p=>{s=setTimeout(()=>p(b),m)}),i=await Promise.race([n(r),h]);if(i===b){u({level:"error",event:"broker.session_replacement.timed_out",outcome:"failed",duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{op:t,deadline_ms:m,mutation_outcome:"indeterminate"}}),this.ackTo(e,t,!1,"session replacement timed out; broker restarting because session state is indeterminate"),this.deps.disposeAndExit("session-replacement-timeout",1);return}i.cancelled||this.deps.reWelcomeAll(),this.ackTo(e,t,!i.cancelled,i.cancelled?i.detail??"cancelled by extension":void 0)}catch(h){u({level:"error",event:"broker.session_replacement.failed",outcome:"failed",error:h,fields:{op:t,mutation_outcome:"indeterminate"}}),this.ackTo(e,t,!1,"session replacement failed; broker restarting because session state is indeterminate"),this.deps.disposeAndExit("session-replacement-failed",1)}finally{clearTimeout(s)}})}finally{this.admittedReplacements--,this.admittedReplacements===0&&this.deps.onReplacementIdle?.()}});this.replacementTail=a.catch(()=>{})}removeInstalledSubscription(){this.unsubscribe?.(),this.unsubscribe=void 0,this.installed=void 0}captureSystemPrompt(e){try{const t=E(this.deps.nodeId);v(t,{recursive:!0}),_(A(t,"system-prompt.md"),e.systemPrompt,"utf8")}catch{}}executeSubscriptionCallback(e,t){try{t.type==="agent_start"&&(this.agentRunActiveValue=!0),t.type==="agent_end"&&(e.stagedProviderAgentEnd=t,e.stagedOverflowFailure=null),t.type==="compaction_end"&&t.reason==="overflow"&&t.willRetry===!1&&typeof t.errorMessage=="string"&&(e.stagedOverflowFailure={errorMessage:t.errorMessage}),t.type==="agent_settled"&&(this.agentRunActiveValue=!1,this.publishAndScheduleProviderRecovery(e)),this.deps.toolGroups.observeToolGroupEvent(t),this.deps.turnReplies.observe(t),this.deps.projection().relayEvent(t,e)}catch(n){u({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`event relay threw: ${String(n)}`}})}}async publishAndScheduleProviderRecovery(e){try{if(await this.deps.faultRetry().publishSettledProviderFault(e),this.shutdownRequested){this.deps.disposeAndExit("shutdown-after-settle");return}await this.deps.faultRetry().schedule()}catch(t){this.deps.faultRetry().abandonTurnEnd(),u({level:"error",event:"broker.daemon.operation.failed",node_id:this.deps.nodeId,error:t,fields:{operation:"provider_fault_settlement"}}),this.shutdownRequested&&this.deps.disposeAndExit("shutdown-after-settle")}}ackTo(e,t,n=!0,r,a){this.deps.registry.sendFrame(e,{type:"ack",for:t,ok:n,...r!==void 0?{detail:r}:{},...a!==void 0?{id:a}:{}})}}export{$ as RebindDriver};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type TurnReply } from '../../../shared/turn-replies.js';
|
|
2
|
+
import type { BrokerToClient } from '../broker-protocol.js';
|
|
3
|
+
/** Consolidated replies (`consolidate_replies` experiment): tracks the open
|
|
4
|
+
* turn's prose messages and rewrites them into one reply with a no-context light
|
|
5
|
+
* model whenever a second or later prose message ends. A turn runs from one
|
|
6
|
+
* message the person typed to the next; everything the runtime injects stays
|
|
7
|
+
* inside it. Rewrites persist to `turn-replies.json` and broadcast as
|
|
8
|
+
* `turn_reply` frames; the viewer owns presentation. */
|
|
9
|
+
export declare class TurnReplyTracker {
|
|
10
|
+
private readonly broadcast;
|
|
11
|
+
private readonly path;
|
|
12
|
+
private readonly replies;
|
|
13
|
+
private readonly tasks;
|
|
14
|
+
private turn;
|
|
15
|
+
private inFlight;
|
|
16
|
+
private queued;
|
|
17
|
+
constructor(nodeId: string, broadcast: (frame: BrokerToClient) => void);
|
|
18
|
+
snapshot(): Record<string, TurnReply>;
|
|
19
|
+
/** Rebuild the open turn from the bound session's messages, so a broker
|
|
20
|
+
* restart mid-turn keeps rewriting it. Earlier turns are frozen. */
|
|
21
|
+
seed(messages: readonly unknown[]): void;
|
|
22
|
+
observe(event: {
|
|
23
|
+
type?: string;
|
|
24
|
+
message?: unknown;
|
|
25
|
+
}): void;
|
|
26
|
+
hasTasks(): boolean;
|
|
27
|
+
/** Settles once no rewrite is running, including a queued one that starts
|
|
28
|
+
* after the current one finishes. */
|
|
29
|
+
waitForTasks(): Promise<void>;
|
|
30
|
+
private proseOf;
|
|
31
|
+
private maybeGenerate;
|
|
32
|
+
private run;
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var l=Object.defineProperty;var u=(o,e)=>l(o,"name",{value:e,configurable:!0});import{join as c}from"node:path";import{nodeRunJobDir as m}from"../../canvas/paths.js";import{readConfig as y}from"../../config.js";import{emitEvent as k}from"../../events/emit.js";import{atomicWriteJson as g,readJsonIfExists as T}from"../../fs-utils.js";import{assistantVisibleText as b,isTrueUserMessage as p}from"../../../shared/tool-groups.js";import{generatedContextText as f}from"../../../shared/generated-context.js";import{isSettledAssistant as x,messageKey as a,normalizeTurnReplyRecord as j,START_TURN_KEY as h}from"../../../shared/turn-replies.js";import{headlessTurnReply as w}from"../turn-reply-summary.js";function d(o,e){return o!==void 0&&o.sources.length===e.length&&o.sources.every((s,t)=>s===e[t].key)}u(d,"sameSources");class A{static{u(this,"TurnReplyTracker")}broadcast;path;replies=new Map;tasks=new Set;turn={key:h,userText:"",prose:[]};inFlight;queued;constructor(e,s){this.broadcast=s,this.path=c(m(e),"turn-replies.json");try{for(const[t,r]of Object.entries(j(T(this.path))))this.replies.set(t,r)}catch{}}snapshot(){return Object.fromEntries(this.replies)}seed(e){let s={key:h,userText:"",prose:[]};for(const t of e){if(t===null||typeof t!="object")continue;const r=t;if(p(r)){const n=a(r);n!==void 0&&(s={key:n,userText:f(r),prose:[]});continue}const i=this.proseOf(r);i!==void 0&&s.prose.push(i)}this.turn=s,this.maybeGenerate()}observe(e){if(e.type!=="message_start"&&e.type!=="message_end")return;const s=e.message;if(s===null||typeof s!="object")return;const t=s;if(e.type==="message_start"){if(!p(t))return;const i=a(t);i!==void 0&&i!==this.turn.key&&(this.turn={key:i,userText:f(t),prose:[]});return}const r=this.proseOf(t);r===void 0||this.turn.prose.some(i=>i.key===r.key)||(this.turn.prose.push(r),this.maybeGenerate())}hasTasks(){return this.tasks.size>0}async waitForTasks(){for(;this.tasks.size>0;)await Promise.allSettled([...this.tasks])}proseOf(e){if(e.role!=="assistant"||!x(e))return;const s=b(e).trim(),t=a(e);return s===""||t===void 0?void 0:{key:t,text:s}}maybeGenerate(){const{key:e,userText:s,prose:t}=this.turn;if(t.length<2||!y("user").consolidate_replies||d(this.replies.get(e),t))return;const r={key:e,userText:s,prose:[...t]};if(this.inFlight!==void 0){this.queued=r;return}this.run(r)}run(e){this.inFlight=e;let s;s=w(e.userText,e.prose.map(t=>t.text)).then(t=>{if(t===null)return;const r={version:1,sources:e.prose.map(n=>n.key),text:t},i=this.replies.get(e.key);if(!(i!==void 0&&i.sources.length>r.sources.length)){this.replies.set(e.key,r);try{g(this.path,Object.fromEntries(this.replies))}catch(n){k({level:"warn",event:"broker.runtime.diagnostic",fields:{message:`failed to persist turn reply: ${n instanceof Error?n.message:String(n)}`}})}this.broadcast({type:"turn_reply",key:e.key,reply:r})}}).catch(()=>{}).finally(()=>{this.tasks.delete(s),this.inFlight=void 0;const t=this.queued;this.queued=void 0,t!==void 0&&!d(this.replies.get(t.key),t.prose)&&this.run(t)}),this.tasks.add(s)}}export{A as TurnReplyTracker};
|
|
@@ -3,6 +3,7 @@ import type { Api, ImageContent, Model } from '@earendil-works/pi-ai';
|
|
|
3
3
|
import type { BrokerErrorFrame, BrokerNodeNamedFrame } from '../../api/dto/broker.js';
|
|
4
4
|
import type { DeliveryRefDTO } from '../../api/dto/delivery.js';
|
|
5
5
|
import type { ToolGroupSummary } from '../../shared/tool-groups.js';
|
|
6
|
+
import type { TurnReply } from '../../shared/turn-replies.js';
|
|
6
7
|
import type { ModelIntent } from '../../types.js';
|
|
7
8
|
import type { MessageOrigin, MessageVisibility } from './stamp/protocol.js';
|
|
8
9
|
/** pi's own RPC types, re-exported unchanged. `broker-protocol` stays the one
|
|
@@ -74,6 +75,10 @@ export interface BrokerSnapshot {
|
|
|
74
75
|
* Structured objects with bullets and filesDeleted.
|
|
75
76
|
* Optional so snapshots from an older live runtime remain readable. */
|
|
76
77
|
toolGroupSummaries?: Record<string, ToolGroupSummary>;
|
|
78
|
+
/** Consolidated replies (`consolidate_replies` experiment), keyed by the
|
|
79
|
+
* turn's opening user-message timestamp (or `start`). Optional: absent from
|
|
80
|
+
* older runtimes and when no turn has been rewritten. */
|
|
81
|
+
turnReplies?: Record<string, TurnReply>;
|
|
77
82
|
/** The broker-selected normal activity label for the current turn. Optional so
|
|
78
83
|
* viewers can still attach to an older live runtime; they fall back to
|
|
79
84
|
* `Working...` when it is absent. */
|
|
@@ -638,10 +643,16 @@ export interface ToolGroupSummaryFrame {
|
|
|
638
643
|
key: string;
|
|
639
644
|
summary: ToolGroupSummary;
|
|
640
645
|
}
|
|
646
|
+
/** A completed consolidated-reply rewrite for one turn (`consolidate_replies`). */
|
|
647
|
+
export interface TurnReplyFrame {
|
|
648
|
+
type: 'turn_reply';
|
|
649
|
+
key: string;
|
|
650
|
+
reply: TurnReply;
|
|
651
|
+
}
|
|
641
652
|
/** Everything the broker can send. Live `AgentSessionEvent`s are relayed
|
|
642
653
|
* verbatim (the broker adds nothing); the broker's own control frames carry
|
|
643
654
|
* non-colliding `type` discriminants. */
|
|
644
|
-
export type BrokerToClient = WelcomeFrame | WorkingActivityFrame | ModelChangedFrame | ResourcesReloadedFrame | ErrorFrame | NodeNamedFrame | AckFrame | BrokerDataFrame | BashStartFrame | BashOutputFrame | BashEndFrame | ExtensionUIRequestFrame | ExtensionUIDismissFrame | ToolGroupSummaryFrame | AgentSessionEvent;
|
|
655
|
+
export type BrokerToClient = WelcomeFrame | WorkingActivityFrame | ModelChangedFrame | ResourcesReloadedFrame | ErrorFrame | NodeNamedFrame | AckFrame | BrokerDataFrame | BashStartFrame | BashOutputFrame | BashEndFrame | ExtensionUIRequestFrame | ExtensionUIDismissFrame | ToolGroupSummaryFrame | TurnReplyFrame | AgentSessionEvent;
|
|
645
656
|
/** Encode one frame as a single newline-terminated JSON line. */
|
|
646
657
|
export declare function encodeFrame(frame: ClientToBroker | BrokerToClient): string;
|
|
647
658
|
/** Byte bounds for a {@link FrameDecoder} (C5). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var Me=Object.defineProperty;var e=(n,o)=>Me(n,"name",{value:o,configurable:!0});import{envInboxBetweenTurns as Ae,envModelIntent as Pe,envNodeCwd as Ie,envNodeId as Oe,envProfileId as De,envScopes as Ne,isSandboxedNode as Fe,scopeAllowed as Le}from"../../shared/env.js";import{createServer as Be}from"node:net";import{existsSync as we,readFileSync as $e,unlinkSync as Se}from"node:fs";import{join as ye}from"node:path";import{randomUUID as x}from"node:crypto";import{mark as Ue}from"../timing.js";import{SUBMIT_RESULT_TOOL as Ge}from"./structured-output.js";import{installSessionManagerStorePatch as Ke}from"../conversation-store/index.js";import{getAgentDir as H,ModelRegistry as je,ModelRuntime as We}from"@earendil-works/pi-coding-agent";import{nodeRunDir as qe,viewSocketPath as Ve}from"../canvas/paths.js";import{bindBrokerEventSource as Xe}from"../events/source.js";import{emitEvent as E,flushBrokerLog as He}from"../events/emit.js";import{operationIdContext as Ye}from"../events/operation-id.js";import{findMissingPackagePaths as ze}from"./package-health.js";import{installBrokerConfigSnapshot as Je}from"../config.js";import{FRONT_DOOR_ENV as Qe}from"./front-door.js";import{CANVAS_EXTENSIONS as te,piInvocationToSdkConfig as Ze}from"./launch.js";import{assertEngineVersion as en,loadBrokerEngine as nn}from"./broker-sdk.js";import{initCrtrTheme as tn}from"./crtr-theme.js";import{resolveBundledPiPackageDir as on}from"./pi-cli.js";import{captureSessionChatCapabilities as rn}from"./command-surface.js";import{InMemoryCredentialStore as sn}from"@earendil-works/pi-ai";import{configureBrokerModelRuntime as an}from"./broker/model-adapter.js";import{mutateBrokerFault as Y,recordBrokerTurn as be}from"./broker/daemon-ops.js";import{modelRequestFromConfig as dn,expandModelCandidates as ln,parseModelSpec as cn,unregisteredConcreteModel as mn}from"../model-routes.js";import{KNOWN_STREAM_WAIT_UI as un}from"./stream-watchdog.js";import{probeOnline as fn}from"./connectivity.js";import{CRTR_CYCLE_CUSTOM_TYPE as pn,cycleAwareMessages as gn,endedByAbort as vn}from"./session-cycles.js";import{turnErrorOf as hn}from"../llm/refusal.js";import{projectTranscript as _n}from"./session-visibility.js";import{currentTurnVisibility as wn}from"./turn-visibility.js";import{isUnknownModel as oe}from"./model-selection.js";import{BrokerClientRegistry as Sn}from"./broker/client-registry.js";import{ToolGroupTracker as yn}from"./broker/tool-groups.js";import{onNodeNamed as bn}from"./broker/node-named.js";import{FaultRetry as Tn,willDaemonRetry as En}from"./broker/fault-retry.js";import{RunTurnEnds as kn}from"./broker/run-turn-end.js";import{createTurnAdmissionGate as Rn}from"./broker/turn-admission.js";import{BROKER_IDLE_TURN_START as xn,BROKER_RUN_TURN_BUSY as Cn}from"./broker/held-deferred-inbox.js";import{prependRunDeferredMail as Mn,settleRunDeferredMail as An}from"./broker/run-deferred-mail.js";import{createRunTurnQueue as Pn}from"./broker/run-turn-queue.js";import{EventProjection as In}from"./broker/event-projection.js";import{createFrameDispatchContext as On,handleFrame as Dn}from"./broker/frame-dispatch.js";import{hydratePersistedAdvertisedCommandMessages as Nn,installAdvertisedCommandInvocationContract as Fn}from"./advertised-command-invocation.js";import{RebindDriver as Ln}from"./broker/rebind.js";import{beginRuntimeTeardown as Bn}from"./broker/extension-abort.js";import{receiveNodeToken as $n}from"./broker/node-token.js";import{serveCliRelay as Un}from"./broker/cli-relay.js";import{decodeKickoffOrigin as Gn,KICKOFF_ORIGIN_ENV as Kn}from"./stamp/protocol.js";import{announceMessageOrigin as jn}from"./stamp/channel.js";import{brokerExtensionState as Wn,commitBrokerModel as qn}from"./broker/daemon-ops.js";import{composerNames as Vn}from"./broker/frame-memory-refs.js";import{FrameOverflowError as Xn,normalizeSnapshotTail as Hn}from"./broker-protocol.js";import{ReviewBoundaryNavigationError as co,REVIEW_BOUNDARY_NAVIGATION_CODE as mo}from"./broker/frame-replies.js";function re(n){return new je(n.modelRuntime)}e(re,"registryOf");function $(n,o){if(n==null||oe(n))return null;const s=o!==void 0&&o!==""&&o!=="off"?`:${o}`:"";return`${n.provider}/${n.id}${s}`}e($,"formatModelSpec");function Yn(n,o){const s=$(n,void 0);return s===null?null:`${s}:${o===void 0||o===""?"off":o}`}e(Yn,"formatExactModelSpec");const zn=12e4;let z=null;import{brokerSignalClient as J}from"./broker/signal-stream.js";function Jn(){J().stop();const n=z;if(z=null,n!==null)try{n.dispose()}catch{}}e(Jn,"disposeActiveSession");function Qn(n,o){const s=Le(o,"crtr:act")?void 0:["bash"],m=n!==void 0&&n.length>0?[...new Set([...n,Ge])]:n===void 0?void 0:[...n];return{...m!==void 0?{tools:m}:{},...s!==void 0?{excludeTools:s}:{}}}e(Qn,"brokerToolOptions");async function so(n,o=process.hrtime.bigint(),s=new Date().toISOString()){Xe(n);const m=await $n(),i=await Un(n,m);process.env.CRTR_API_SOCKET=i.path,Ye.fresh(()=>{E({level:"info",event:"broker.startup.cli_entry",ts:s,duration_ms:0,fields:{runtime_version:process.version,engine_version:null,model:null}}),E({level:"info",event:"broker.startup.module_loaded",duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{runtime_version:process.version,engine_version:null,model:null}})});const a=new Set;let l=null;const d=e((t,r=null)=>{a.has(t)||(a.add(t),Ue(t,{duration_ms:Number(process.hrtime.bigint()-o)/1e6}),E({level:"info",event:t,duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{runtime_version:process.version,engine_version:l,model:r}}))},"emitStartupMilestone");process.env[Qe]="1",process.env.CRTR_BROKER_PID=String(process.pid),delete process.env.TMUX_PANE,delete process.env.TMUX,Ke(n);const f=await nn();en(f.VERSION),l=f.VERSION;const w=qe(n),k=ye(w,"broker-launch.json"),S=JSON.parse($e(k,"utf8"));if(Fe()){if(!S.configSnapshot)throw new Error("broker launch is missing its config snapshot");Je(S.configSnapshot)}const u=Ze(S);u.modelExact===!0?process.env.CRTR_MODEL_EXACT="1":delete process.env.CRTR_MODEL_EXACT;const y=await Vn(n);let b,C;const q=e(t=>{b!==void 0?b(t):C??=t},"onSignal");process.on("SIGTERM",()=>q("SIGTERM")),process.on("SIGINT",()=>q("SIGINT"));let{session:U,services:M,resuming:ie,runtime:G}=await ot(f,u);d("broker.startup.session_built");const P=(await Wn(n)).node.review_binding?.review_id,T=Ae();z=U;const D=fn;try{process.env.PI_PACKAGE_DIR=on(),tn(M.settingsManager.getTheme(),H(),!1)}catch(t){E({level:"error",event:"broker.theme.initialization_failed",error:t})}try{for(const t of ze(H()))E({level:"warn",event:"broker.startup.warning",fields:{stage:"package_health",source:t.source,resolved_path:t.resolved}})}catch{}const K=Ve(n),_=new Sn(n),V=new Map,I=new yn(n,t=>_.broadcast(t));bn(t=>_.broadcast({type:"node_named",...t}));let N=!1,se=!1,X,ae,p,j;const Q=new kn;let F,de=e(()=>{},"notifyTurnAccepted"),le=e(()=>{},"resetFrameState");const Z=Rn();let ce=e(()=>0,"pendingPromptDispatches"),me;const L=Pn({runNode:T,session:e(()=>p.session(),"session"),isReplacing:e(()=>p.isReplacing(),"isReplacing"),isAgentRunActive:e(()=>p.isAgentRunActive(),"isAgentRunActive"),pendingDispatches:e(()=>ce(),"pendingDispatches"),turnAdmission:Z,prependDeferred:e(t=>Mn(n,t),"prependDeferred"),onError:e(t=>E({level:"error",event:"broker.inbox.idle_prompt_failed",error:t}),"onError")}),ue=L.drain;u.firstPrompt!==void 0&&u.firstPrompt!==""&&L.holdForKickoff(),globalThis[xn]=L.start,globalThis[Cn]=L.busy,p=new Ln({nodeId:n,cfg:u,session:U,services:M,runtime:G,registry:_,toolGroups:I,uiContext:e(()=>ae,"uiContext"),faultRetry:e(()=>j,"faultRetry"),projection:e(()=>F,"projection"),setActiveSession:e(t=>{if(z=t,me?.(),T){let r="stop",c,g=!1;me=t.subscribe(v=>{if(v.type==="agent_start"&&(r="stop",c=void 0,g=!1,Q.started()),v.type==="agent_end"){const h=[...v.messages??[]].reverse().find(B=>B.role==="assistant");h&&(r=h.stopReason,c=vn(h)?void 0:hn(h),g=h.role==="assistant"&&En(h,t.model?.contextWindow))}v.type==="agent_settled"&&(Q.settled(t.sessionManager,{stop_reason:r,...c?{error:c}:{}},g),An(n,t).catch(h=>{E({level:"error",event:"broker.run_deferred_mail.settle_failed",error:h})}),queueMicrotask(()=>{p.session()===t&&ue()}))})}},"setActiveSession"),disposeAndExit:e((t,r)=>W(t,r),"disposeAndExit"),onSessionRebind:e(()=>{le()},"onSessionRebind"),onReplacementIdle:e(()=>{T&&ue()},"onReplacementIdle"),reWelcomeAll:e(()=>ee(),"reWelcomeAll")});const fe=e(async(t,r=!1)=>{const c=p.session(),g=$(c.model,c.thinkingLevel);if(g===null)return null;const v=await qn(n,{spec:g,...t!==void 0?{intent:t}:{},userSelected:r});return r&&(u.model=v.modelOverride,t!==void 0?(process.env.CRTR_MODEL_INTENT=`${t.family}/${t.strength}`,delete process.env.CRTR_MODEL_EXACT,u.modelExact=void 0):(delete process.env.CRTR_MODEL_INTENT,process.env.CRTR_MODEL_EXACT="1",u.modelExact=!0)),v.modelOverride},"persistModelChoice"),pe=e(async(t=!0,r,c=!1)=>{const g=p.session(),v=$(g.model,g.thinkingLevel),h=t?await fe(r,c):v;_.broadcast({type:"model_changed",model:oe(g.model)?void 0:g.model,spec:h})},"broadcastModelChanged");j=new Tn({nodeId:n,cfg:u,retryProbe:D,currentSession:e(()=>p.session(),"currentSession"),currentServices:e(()=>p.services(),"currentServices"),installedGeneration:e(()=>p.installedGeneration(),"installedGeneration"),registryOf:re,formatModelSpec:$,broadcastModelChanged:pe,turnAdmission:Z,reWelcomeAll:e(()=>ee(),"reWelcomeAll"),...T?{turnEnds:Q}:{}});const ge=e(()=>{j.rearmIfStranded().catch(t=>{E({level:"warn",event:"broker.runtime.diagnostic",fields:{message:`fault retry re-arm failed: ${t instanceof Error?t.message:String(t)}`}})})},"rearmStrandedRetry");J().subscribe("resync",ge),J().subscribe("fault-retry",ge),F=new In({registry:_,faultRetry:j,installedGeneration:e(()=>p.installedGeneration(),"installedGeneration"),currentSession:e(()=>p.session(),"currentSession"),notifyTurnAccepted:e(()=>de(),"notifyTurnAccepted"),emitStartupMilestone:d,formatModelSpec:$});const Ee=e(t=>{const r=p.session(),c=et(r,P),g=Hn(t.snapshotTail),v=c===void 0||g===void 0?c:c.slice(-g),h=v?.map(({message:O})=>O)??r.sessionManager.buildSessionContext().messages,B=I.summaries(),_e=v!==void 0&&g!==void 0?Zn(h):void 0,Ce=_e===void 0?B:Object.fromEntries(Object.entries(B).filter(([O])=>_e.has(O)));return{messages:h,...v===void 0?{}:{messageIds:v.map(({id:O})=>O)},messageVisibility:v?.map(({visibility:O})=>O)??h.map(()=>"visible"),turnVisibility:wn(),stats:r.getSessionStats(),state:{model:oe(r.model)?void 0:r.model,thinkingLevel:r.thinkingLevel,isStreaming:r.isStreaming,isCompacting:r.isCompacting,steeringMode:r.steeringMode,followUpMode:r.followUpMode,sessionFile:r.sessionFile,sessionId:r.sessionId,sessionName:r.sessionName,autoCompactionEnabled:r.autoCompactionEnabled,messageCount:r.messages.length,pendingMessageCount:r.pendingMessageCount},display:{..._.displaySnapshot()},toolGroupSummaries:Ce,workingActivity:F.currentWorkingActivity(),queued:{steering:[...r.getSteeringMessages()],followUp:[...r.getFollowUpMessages()]}}},"buildSnapshot"),ve=e(t=>{const r=t.role==="controller"?V.values().next().value:void 0;_.sendFrame(t,{type:"welcome",snapshot:Ee(t),role:t.role,pending_dialog:r!==void 0?r.request:null,agentDir:H()},!0)},"sendWelcome"),ke=e(t=>{const r=[...V.values()];for(let c=1;c<r.length;c++)_.sendFrame(t,r[c].request)},"replayExtraPendingDialogsTo"),ee=e(()=>{_.forEachHelloed(ve)},"reWelcomeAll"),he=e(async t=>{if(!N){N=!0,J().stop(),I.persistPendingSummary(),F.dispose(),Jn();try{X?.close()}catch{}i.close(),_.dispose();try{we(K)&&Se(K)}catch{}_.clearAttachState(),await He(),process.exit(t)}},"completeExit"),W=e((t,r=0)=>{if(N)return;const c=t==="shutdown-hook"||t==="shutdown-after-settle";if(c&&I.finishOpenToolGroup(!0),c&&I.hasSummaryTasks()){if(se)return;se=!0,I.waitForSummaryTasks().finally(()=>he(r));return}he(r)},"disposeAndExit");ae=rt({writable:e(()=>_.writableClients(),"writable"),forward:e((t,r)=>_.sendFrame(t,r),"forward"),pending:V,broadcast:e(t=>_.broadcastUi(t),"broadcast"),onKnownStreamWait:e(t=>F.knownStreamWait(t),"onKnownStreamWait")}),p.setRebindSession(),await p.enqueueRebind(U,M),d("broker.startup.extensions_bound");const R=On({nodeId:n,registry:_,toolGroups:I,projection:F,rebind:p,boundaryReviewId:P,pendingDialogs:V,sendWelcome:ve,replayExtraPendingDialogsTo:ke,reWelcomeAll:ee,disposeAndExit:W,persistModelChoice:fe,broadcastModelChanged:pe,registryOf:re,formatModelSpec:$,formatExactModelSpec:Yn,turnAdmission:Z,memoryInventory:y,runNode:T,onKickoffAdmitted:L.releaseKickoff});de=R.notifyTurnAccepted,le=R.resetForSession,ce=R.pendingPromptDispatches;const Re=2500;let ne=!1;const xe=e(async t=>{if(N||ne)return;if(ne=!0,p.isAgentRunActive()||p.session().isStreaming||R.pendingPromptDispatches()>0){const c=Date.now()+Re;for(;R.pendingPromptDispatches()>0&&!p.session().isStreaming&&Date.now()<c;)await new Promise(g=>setTimeout(g,25));if(p.session().isStreaming){const g=c-Date.now();if(g>0){let v;try{Bn(),await Promise.race([p.session().abort().then(()=>!0,()=>!1),new Promise(B=>{v=setTimeout(()=>B(!1),g)})])&&await be(n,{event:"closed",end_reason:"teardown-aborted"})}finally{v!==void 0&&clearTimeout(v)}}}else(R.pendingPromptDispatches()>0||p.isAgentRunActive())&&await be(n,{event:"interrupted"})}W(t)},"abortAndExit");if(b=e(t=>{xe(t)},"signalTeardown"),C!==void 0){b(C);return}try{we(K)&&Se(K)}catch{}X=Be(t=>{const r=_.create(t);t.on("data",g=>{let v;try{v=r.decoder.push(g)}catch(h){h instanceof Xn?(_.sendFrame(r,{type:"error",code:"frame_overflow",message:h.message}),_.dropClient(r,`frame overflow: ${h.message}`)):_.dropClient(r,`decoder error: ${String(h)}`);return}for(const h of v)try{Dn(R,r,h)}catch{}});const c=e(()=>{_.removeClient(r)},"drop");t.on("close",c),t.on("error",()=>{})}),X.on("error",t=>{N||(E({level:"error",event:"broker.socket.failed",error:t}),W("socket-error",1))}),X.listen(K,async()=>{Promise.all([Y(n,{op:"clear",link:"viewer\u2194broker"}),Y(n,{op:"clear",link:"relay\u2194broker"})]).catch(r=>E({level:"error",event:"broker.daemon.operation.failed",node_id:n,error:r,fields:{operation:"broker_socket_bound_fault_clear"}}));let t;try{t=await j.recoverOnStartup()}catch(r){E({level:"error",event:"broker.daemon.operation.failed",node_id:n,error:r,fields:{operation:"recovery_startup"}}),W("recovery-startup-failed",1);return}if(!(N||ne))if(t!=="retry-armed"&&u.firstPrompt!==void 0&&u.firstPrompt!==""){const r=Gn(process.env[Kn]);r!==null&&jn(u.firstPrompt,r);const c=process.env.CRTR_KICKOFF_MESSAGE_IDS;R.kickoff(u.firstPrompt,c?JSON.parse(c):[])}else L.releaseKickoff()}),_.persistAttachState()}e(so,"runBroker");function Zn(n){const o=new Set;for(const s of n)if(!(s.role!=="assistant"||!Array.isArray(s.content)))for(const m of s.content)m!==null&&typeof m=="object"&&m.type==="toolCall"&&typeof m.id=="string"&&o.add(m.id);return o}e(Zn,"toolCallIds");function et(n,o){const s=n.sessionManager,m=gn(s);return m!==void 0&&Nn(m.map(({message:i})=>i)),m===void 0?void 0:_n(m,{boundaryReviewId:o,sessionEntries:s.getEntries?.()})}e(et,"snapshotMessages");function Te(){const n=Oe();if(n===void 0||n==="")throw new Error("broker launch is missing CRTR_NODE_ID");return n}e(Te,"currentBrokerNodeId");async function nt(n,o){const s=dn(o.model,Pe(),o.modelExact===!0);if(s===void 0)return;const m=re(n),i={cwd:Ie()??o.cwd,profileId:De()},a=mn(s,m,i);if(a!==void 0)throw await Y(Te(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`model '${a.request.spec}' is not registered in the serving model registry`}}),new Error(`[broker] FATAL: model '${a.request.spec}' is not registered in the serving model registry`);const l=ln(s,i.cwd,i.profileId),d=cn(s.spec);for(const f of l){const w=m.find(f.providerId,f.modelId);if(w===void 0)continue;const S=d?.providerId===f.providerId&&d.modelId===f.modelId?d.thinkingLevel??(f.thinkingLevel===void 0?void 0:"off"):f.thinkingLevel;return{model:w,thinkingLevel:S}}if(o.modelExact===!0){const f=l.map(w=>`'${w.providerId}/${w.modelId}' unregistered`).join("; ");throw await Y(Te(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`exact-consult model '${o.model}' is unavailable \u2014 refusing to substitute (${f})`}}),new Error(`[broker] FATAL: exact-consult model '${o.model}' is unavailable`)}E({level:"warn",event:"broker.model.none_viable",fields:{rejected_candidates:l.map(f=>({provider:f.providerId,model:f.modelId,reason:"unregistered"})).slice(0,16)}})}e(nt,"resolveLaunchModel");function tt(n){let o=!0;return{runtime:new Proxy(n,{get(m,i,a){return o&&i==="getAvailableSnapshot"?()=>[]:o&&i==="getAvailable"?async()=>[]:o&&i==="getModel"?()=>{}:Reflect.get(m,i,a)}}),reveal:e(()=>{o=!1},"reveal")}}e(tt,"modelLessRegistry");async function ot(n,o){const s=H(),m=e(async S=>{const u=await We.create({credentials:new sn,modelsPath:ye(S.agentDir,"models.json")});an(u);const y=await n.createAgentSessionServices({cwd:S.cwd,agentDir:S.agentDir,modelRuntime:u,resourceLoaderOptions:{additionalExtensionPaths:o.extensionPaths,appendSystemPrompt:o.appendSystemPromptPath!==void 0?[o.appendSystemPromptPath]:void 0,noContextFiles:!0,extensionsOverride:e(A=>({...A,extensions:A.extensions.filter(P=>!/[/\\]provider-rotation\.(?:ts|js)$/.test(P.path))}),"extensionsOverride")}}),b=y.resourceLoader.getExtensions();if(o.extensionPaths.some(A=>te.includes(A))){const A=new Set(b.extensions.map(T=>T.path)),P=te.filter(T=>!A.has(T));if(P.length>0){const T=b.errors.filter(D=>te.includes(D.path)).map(D=>`${D.path}: ${D.error}`).join("; ");throw new Error(`[broker] FATAL: mandatory canvas extensions failed to load: ${P.join(", ")}${T===""?"":` (${T})`}`)}}y.settingsManager.getRetryEnabled=()=>!1;const C=await nt(y,o),q=C?.model,U=C?.thinkingLevel,M=C===void 0?tt(y.modelRuntime):void 0,ie=M!==void 0?{...y,modelRuntime:M.runtime}:y,G=await n.createAgentSessionFromServices({services:ie,sessionManager:S.sessionManager,model:q,thinkingLevel:U,...Qn(o.tools,Ne()),sessionStartEvent:S.sessionStartEvent});return Fn(G.session),rn(G.session),M?.reveal(),{...G,services:y}},"buildForManager"),i=o.resumeSessionPath,a=o.forkFrom!==void 0&&o.forkFrom!=="";if(!a&&(i===void 0||i==="")&&o.resumeSessionId!==void 0&&o.resumeSessionId!=="")throw new Error(`[broker] resume requires a session .jsonl PATH; got only a bare id '${o.resumeSessionId}' (pi_session_file was never captured for this node)`);const l=!a&&i!==void 0&&i!=="",d=l&&o.newCycle===!0,f=l&&!d;let w;if(a)w=n.SessionManager.forkFrom(o.forkFrom,o.cwd);else if(f||d){if(w=n.SessionManager.open(i),d){const S=w.getLeafId();w.resetLeaf(),w.appendCustomEntry(pn,{cycle:Number(process.env.CRTR_CYCLES),fromLeaf:S})}}else w=n.SessionManager.create(o.cwd);if(n.createAgentSessionRuntime!==void 0){const S=e(async y=>{const b=await m({cwd:y.cwd,agentDir:y.agentDir,sessionManager:y.sessionManager,sessionStartEvent:y.sessionStartEvent});return{...b,diagnostics:b.services.diagnostics??[]}},"factory"),u=await n.createAgentSessionRuntime(S,{cwd:o.cwd,agentDir:s,sessionManager:w});return{session:u.session,services:u.services,resuming:f,runtime:u}}const k=await m({cwd:o.cwd,agentDir:s,sessionManager:w});return{session:k.session,services:k.services,resuming:f,runtime:void 0}}e(ot,"buildBrokerSession");function rt(n){const o=e((i,a,l,d)=>{if(d?.signal?.aborted)return Promise.resolve(i);const f=n.writable();return f.length===0?Promise.resolve(i):new Promise(w=>{let k;const S=e(()=>{k!==void 0&&clearTimeout(k),d?.signal?.removeEventListener("abort",u),n.pending.delete(a.id)},"cleanup"),u=e(()=>{S(),n.broadcast({type:"extension_ui_dismiss",id:a.id}),w(i)},"onAbort");d?.signal?.addEventListener("abort",u,{once:!0});const y=d?.timeout!==void 0?d.timeout:zn;k=setTimeout(()=>{S(),n.broadcast({type:"extension_ui_dismiss",id:a.id}),w(i)},y),typeof k.unref=="function"&&k.unref(),n.pending.set(a.id,{request:a,resolve:e(b=>{S(),n.broadcast({type:"extension_ui_dismiss",id:a.id}),w(l(b))},"resolve")});for(const b of f)n.forward(b,a)})},"dialogPromise"),s=e(()=>{},"noop");return{[un]:n.onKnownStreamWait??(i=>()=>{}),get theme(){const i=globalThis[Symbol.for("@earendil-works/pi-coding-agent:theme")];if(i==null)throw new Error("Theme not initialized. Call initTheme() first.");return i},select:e((i,a,l)=>o(void 0,{type:"extension_ui_request",id:x(),method:"select",title:i,options:a,timeout:l?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,l),"select"),confirm:e((i,a,l)=>o(!1,{type:"extension_ui_request",id:x(),method:"confirm",title:i,message:a,timeout:l?.timeout},d=>"cancelled"in d&&d.cancelled?!1:"confirmed"in d?d.confirmed:!1,l),"confirm"),input:e((i,a,l)=>o(void 0,{type:"extension_ui_request",id:x(),method:"input",title:i,placeholder:a,timeout:l?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,l),"input"),editor:e((i,a)=>o(void 0,{type:"extension_ui_request",id:x(),method:"editor",title:i,prefill:a},l=>"cancelled"in l&&l.cancelled?void 0:"value"in l?l.value:void 0),"editor"),setStatus:e((i,a)=>n.broadcast({type:"extension_ui_request",id:x(),method:"setStatus",statusKey:i,statusText:a}),"setStatus"),setWidget:e((i,a,l)=>{typeof a!="function"&&n.broadcast({type:"extension_ui_request",id:x(),method:"setWidget",widgetKey:i,widgetLines:a,widgetPlacement:l?.placement})},"setWidget"),setTitle:e(i=>n.broadcast({type:"extension_ui_request",id:x(),method:"setTitle",title:i}),"setTitle"),notify:e((i,a)=>{const l=a==="warn"?"warning":a;n.broadcast({type:"extension_ui_request",id:x(),method:"notify",message:i,notifyType:l})},"notify"),onTerminalInput:e(()=>s,"onTerminalInput"),setWorkingMessage:s,setWorkingVisible:s,setWorkingIndicator:s,setHiddenThinkingLabel:s,setFooter:s,setHeader:s,custom:e(()=>Promise.resolve(void 0),"custom"),pasteToEditor:s,setEditorText:s,getEditorText:e(()=>"","getEditorText"),addAutocompleteProvider:s,setEditorComponent:s,getEditorComponent:e(()=>{},"getEditorComponent"),getAllThemes:e(()=>[],"getAllThemes"),getTheme:e(()=>{},"getTheme"),setTheme:s,getToolsExpanded:e(()=>!1,"getToolsExpanded"),setToolsExpanded:s}}e(rt,"makeBrokerUiContext");export{mo as REVIEW_BOUNDARY_NAVIGATION_CODE,co as ReviewBoundaryNavigationError,Qn as brokerToolOptions,ot as buildBrokerSession,Jn as disposeActiveSession,rt as makeBrokerUiContext,so as runBroker,et as snapshotMessages};
|
|
1
|
+
var Pe=Object.defineProperty;var e=(t,r)=>Pe(t,"name",{value:r,configurable:!0});import{envInboxBetweenTurns as Oe,envModelIntent as Ie,envNodeCwd as De,envNodeId as Ne,envProfileId as Fe,envScopes as Le,isSandboxedNode as Be,scopeAllowed as $e}from"../../shared/env.js";import{createServer as Ue}from"node:net";import{existsSync as Se,readFileSync as Ge,unlinkSync as ye}from"node:fs";import{join as be}from"node:path";import{randomUUID as x}from"node:crypto";import{mark as Ke}from"../timing.js";import{SUBMIT_RESULT_TOOL as je}from"./structured-output.js";import{installSessionManagerStorePatch as We}from"../conversation-store/index.js";import{getAgentDir as Y,ModelRegistry as qe,ModelRuntime as Ve}from"@earendil-works/pi-coding-agent";import{nodeRunDir as Xe,viewSocketPath as He}from"../canvas/paths.js";import{bindBrokerEventSource as Ye}from"../events/source.js";import{emitEvent as E,flushBrokerLog as ze}from"../events/emit.js";import{operationIdContext as Je}from"../events/operation-id.js";import{findMissingPackagePaths as Qe}from"./package-health.js";import{installBrokerConfigSnapshot as Ze}from"../config.js";import{FRONT_DOOR_ENV as en}from"./front-door.js";import{CANVAS_EXTENSIONS as oe,piInvocationToSdkConfig as nn}from"./launch.js";import{assertEngineVersion as tn,loadBrokerEngine as on}from"./broker-sdk.js";import{initCrtrTheme as rn}from"./crtr-theme.js";import{resolveBundledPiPackageDir as sn}from"./pi-cli.js";import{captureSessionChatCapabilities as an}from"./command-surface.js";import{InMemoryCredentialStore as dn}from"@earendil-works/pi-ai";import{configureBrokerModelRuntime as ln}from"./broker/model-adapter.js";import{mutateBrokerFault as z,recordBrokerTurn as Te}from"./broker/daemon-ops.js";import{modelRequestFromConfig as cn,expandModelCandidates as mn,parseModelSpec as un,unregisteredConcreteModel as fn}from"../model-routes.js";import{KNOWN_STREAM_WAIT_UI as pn}from"./stream-watchdog.js";import{probeOnline as gn}from"./connectivity.js";import{CRTR_CYCLE_CUSTOM_TYPE as vn,cycleAwareMessages as hn,endedByAbort as _n}from"./session-cycles.js";import{turnErrorOf as wn}from"../llm/refusal.js";import{projectTranscript as Sn}from"./session-visibility.js";import{currentTurnVisibility as yn}from"./turn-visibility.js";import{isUnknownModel as re}from"./model-selection.js";import{BrokerClientRegistry as bn}from"./broker/client-registry.js";import{ToolGroupTracker as Tn}from"./broker/tool-groups.js";import{TurnReplyTracker as En}from"./broker/turn-replies.js";import{onNodeNamed as kn}from"./broker/node-named.js";import{FaultRetry as Rn,willDaemonRetry as Mn}from"./broker/fault-retry.js";import{RunTurnEnds as xn}from"./broker/run-turn-end.js";import{createTurnAdmissionGate as Cn}from"./broker/turn-admission.js";import{BROKER_IDLE_TURN_START as An,BROKER_RUN_TURN_BUSY as Pn}from"./broker/held-deferred-inbox.js";import{prependRunDeferredMail as On,settleRunDeferredMail as In}from"./broker/run-deferred-mail.js";import{createRunTurnQueue as Dn}from"./broker/run-turn-queue.js";import{EventProjection as Nn}from"./broker/event-projection.js";import{createFrameDispatchContext as Fn,handleFrame as Ln}from"./broker/frame-dispatch.js";import{hydratePersistedAdvertisedCommandMessages as Bn,installAdvertisedCommandInvocationContract as $n}from"./advertised-command-invocation.js";import{RebindDriver as Un}from"./broker/rebind.js";import{beginRuntimeTeardown as Gn}from"./broker/extension-abort.js";import{receiveNodeToken as Kn}from"./broker/node-token.js";import{serveCliRelay as jn}from"./broker/cli-relay.js";import{decodeKickoffOrigin as Wn,KICKOFF_ORIGIN_ENV as qn}from"./stamp/protocol.js";import{announceMessageOrigin as Vn}from"./stamp/channel.js";import{brokerExtensionState as Xn,commitBrokerModel as Hn}from"./broker/daemon-ops.js";import{composerNames as Yn}from"./broker/frame-memory-refs.js";import{FrameOverflowError as zn,normalizeSnapshotTail as Jn}from"./broker-protocol.js";import{ReviewBoundaryNavigationError as fo,REVIEW_BOUNDARY_NAVIGATION_CODE as po}from"./broker/frame-replies.js";function se(t){return new qe(t.modelRuntime)}e(se,"registryOf");function $(t,r){if(t==null||re(t))return null;const i=r!==void 0&&r!==""&&r!=="off"?`:${r}`:"";return`${t.provider}/${t.id}${i}`}e($,"formatModelSpec");function Qn(t,r){const i=$(t,void 0);return i===null?null:`${i}:${r===void 0||r===""?"off":r}`}e(Qn,"formatExactModelSpec");const Zn=12e4;let J=null;import{brokerSignalClient as Q}from"./broker/signal-stream.js";function et(){Q().stop();const t=J;if(J=null,t!==null)try{t.dispose()}catch{}}e(et,"disposeActiveSession");function nt(t,r){const i=$e(r,"crtr:act")?void 0:["bash"],m=t!==void 0&&t.length>0?[...new Set([...t,je])]:t===void 0?void 0:[...t];return{...m!==void 0?{tools:m}:{},...i!==void 0?{excludeTools:i}:{}}}e(nt,"brokerToolOptions");async function co(t,r=process.hrtime.bigint(),i=new Date().toISOString()){Ye(t);const m=await Kn(),s=await jn(t,m);process.env.CRTR_API_SOCKET=s.path,Je.fresh(()=>{E({level:"info",event:"broker.startup.cli_entry",ts:i,duration_ms:0,fields:{runtime_version:process.version,engine_version:null,model:null}}),E({level:"info",event:"broker.startup.module_loaded",duration_ms:Number(process.hrtime.bigint()-r)/1e6,fields:{runtime_version:process.version,engine_version:null,model:null}})});const a=new Set;let l=null;const d=e((n,o=null)=>{a.has(n)||(a.add(n),Ke(n,{duration_ms:Number(process.hrtime.bigint()-r)/1e6}),E({level:"info",event:n,duration_ms:Number(process.hrtime.bigint()-r)/1e6,fields:{runtime_version:process.version,engine_version:l,model:o}}))},"emitStartupMilestone");process.env[en]="1",process.env.CRTR_BROKER_PID=String(process.pid),delete process.env.TMUX_PANE,delete process.env.TMUX,We(t);const f=await on();tn(f.VERSION),l=f.VERSION;const w=Xe(t),k=be(w,"broker-launch.json"),S=JSON.parse(Ge(k,"utf8"));if(Be()){if(!S.configSnapshot)throw new Error("broker launch is missing its config snapshot");Ze(S.configSnapshot)}const u=nn(S);u.modelExact===!0?process.env.CRTR_MODEL_EXACT="1":delete process.env.CRTR_MODEL_EXACT;const y=await Yn(t);let b,C;const q=e(n=>{b!==void 0?b(n):C??=n},"onSignal");process.on("SIGTERM",()=>q("SIGTERM")),process.on("SIGINT",()=>q("SIGINT"));let{session:U,services:A,resuming:ie,runtime:G}=await st(f,u);d("broker.startup.session_built");const R=(await Xn(t)).node.review_binding?.review_id,T=Oe();J=U;const D=gn;try{process.env.PI_PACKAGE_DIR=sn(),rn(A.settingsManager.getTheme(),Y(),!1)}catch(n){E({level:"error",event:"broker.theme.initialization_failed",error:n})}try{for(const n of Qe(Y()))E({level:"warn",event:"broker.startup.warning",fields:{stage:"package_health",source:n.source,resolved_path:n.resolved}})}catch{}const K=He(t),p=new bn(t),V=new Map,O=new Tn(t,n=>p.broadcast(n)),X=new En(t,n=>p.broadcast(n));kn(n=>p.broadcast({type:"node_named",...n}));let N=!1,ae=!1,H,de,g,j;const Z=new xn;let F,le=e(()=>{},"notifyTurnAccepted"),ce=e(()=>{},"resetFrameState");const ee=Cn();let me=e(()=>0,"pendingPromptDispatches"),ue;const L=Dn({runNode:T,session:e(()=>g.session(),"session"),isReplacing:e(()=>g.isReplacing(),"isReplacing"),isAgentRunActive:e(()=>g.isAgentRunActive(),"isAgentRunActive"),pendingDispatches:e(()=>me(),"pendingDispatches"),turnAdmission:ee,prependDeferred:e(n=>On(t,n),"prependDeferred"),onError:e(n=>E({level:"error",event:"broker.inbox.idle_prompt_failed",error:n}),"onError")}),fe=L.drain;u.firstPrompt!==void 0&&u.firstPrompt!==""&&L.holdForKickoff(),globalThis[An]=L.start,globalThis[Pn]=L.busy,g=new Un({nodeId:t,cfg:u,session:U,services:A,runtime:G,registry:p,toolGroups:O,turnReplies:X,transcriptMessages:e(n=>Ee(n,R)?.map(({message:o})=>o)??n.sessionManager.buildSessionContext().messages,"transcriptMessages"),uiContext:e(()=>de,"uiContext"),faultRetry:e(()=>j,"faultRetry"),projection:e(()=>F,"projection"),setActiveSession:e(n=>{if(J=n,ue?.(),T){let o="stop",c,v=!1;ue=n.subscribe(h=>{if(h.type==="agent_start"&&(o="stop",c=void 0,v=!1,Z.started()),h.type==="agent_end"){const _=[...h.messages??[]].reverse().find(B=>B.role==="assistant");_&&(o=_.stopReason,c=_n(_)?void 0:wn(_),v=_.role==="assistant"&&Mn(_,n.model?.contextWindow))}h.type==="agent_settled"&&(Z.settled(n.sessionManager,{stop_reason:o,...c?{error:c}:{}},v),In(t,n).catch(_=>{E({level:"error",event:"broker.run_deferred_mail.settle_failed",error:_})}),queueMicrotask(()=>{g.session()===n&&fe()}))})}},"setActiveSession"),disposeAndExit:e((n,o)=>W(n,o),"disposeAndExit"),onSessionRebind:e(()=>{ce()},"onSessionRebind"),onReplacementIdle:e(()=>{T&&fe()},"onReplacementIdle"),reWelcomeAll:e(()=>ne(),"reWelcomeAll")});const pe=e(async(n,o=!1)=>{const c=g.session(),v=$(c.model,c.thinkingLevel);if(v===null)return null;const h=await Hn(t,{spec:v,...n!==void 0?{intent:n}:{},userSelected:o});return o&&(u.model=h.modelOverride,n!==void 0?(process.env.CRTR_MODEL_INTENT=`${n.family}/${n.strength}`,delete process.env.CRTR_MODEL_EXACT,u.modelExact=void 0):(delete process.env.CRTR_MODEL_INTENT,process.env.CRTR_MODEL_EXACT="1",u.modelExact=!0)),h.modelOverride},"persistModelChoice"),ge=e(async(n=!0,o,c=!1)=>{const v=g.session(),h=$(v.model,v.thinkingLevel),_=n?await pe(o,c):h;p.broadcast({type:"model_changed",model:re(v.model)?void 0:v.model,spec:_})},"broadcastModelChanged");j=new Rn({nodeId:t,cfg:u,retryProbe:D,currentSession:e(()=>g.session(),"currentSession"),currentServices:e(()=>g.services(),"currentServices"),installedGeneration:e(()=>g.installedGeneration(),"installedGeneration"),registryOf:se,formatModelSpec:$,broadcastModelChanged:ge,turnAdmission:ee,reWelcomeAll:e(()=>ne(),"reWelcomeAll"),...T?{turnEnds:Z}:{}});const ve=e(()=>{j.rearmIfStranded().catch(n=>{E({level:"warn",event:"broker.runtime.diagnostic",fields:{message:`fault retry re-arm failed: ${n instanceof Error?n.message:String(n)}`}})})},"rearmStrandedRetry");Q().subscribe("resync",ve),Q().subscribe("fault-retry",ve),F=new Nn({registry:p,faultRetry:j,installedGeneration:e(()=>g.installedGeneration(),"installedGeneration"),currentSession:e(()=>g.session(),"currentSession"),notifyTurnAccepted:e(()=>le(),"notifyTurnAccepted"),emitStartupMilestone:d,formatModelSpec:$});const Re=e(n=>{const o=g.session(),c=Ee(o,R),v=Jn(n.snapshotTail),h=c===void 0||v===void 0?c:c.slice(-v),_=h?.map(({message:I})=>I)??o.sessionManager.buildSessionContext().messages,B=O.summaries(),we=h!==void 0&&v!==void 0?tt(_):void 0,Ae=we===void 0?B:Object.fromEntries(Object.entries(B).filter(([I])=>we.has(I)));return{messages:_,...h===void 0?{}:{messageIds:h.map(({id:I})=>I)},messageVisibility:h?.map(({visibility:I})=>I)??_.map(()=>"visible"),turnVisibility:yn(),stats:o.getSessionStats(),state:{model:re(o.model)?void 0:o.model,thinkingLevel:o.thinkingLevel,isStreaming:o.isStreaming,isCompacting:o.isCompacting,steeringMode:o.steeringMode,followUpMode:o.followUpMode,sessionFile:o.sessionFile,sessionId:o.sessionId,sessionName:o.sessionName,autoCompactionEnabled:o.autoCompactionEnabled,messageCount:o.messages.length,pendingMessageCount:o.pendingMessageCount},display:{...p.displaySnapshot()},toolGroupSummaries:Ae,turnReplies:X.snapshot(),workingActivity:F.currentWorkingActivity(),queued:{steering:[...o.getSteeringMessages()],followUp:[...o.getFollowUpMessages()]}}},"buildSnapshot"),he=e(n=>{const o=n.role==="controller"?V.values().next().value:void 0;p.sendFrame(n,{type:"welcome",snapshot:Re(n),role:n.role,pending_dialog:o!==void 0?o.request:null,agentDir:Y()},!0)},"sendWelcome"),Me=e(n=>{const o=[...V.values()];for(let c=1;c<o.length;c++)p.sendFrame(n,o[c].request)},"replayExtraPendingDialogsTo"),ne=e(()=>{p.forEachHelloed(he)},"reWelcomeAll"),_e=e(async n=>{if(!N){N=!0,Q().stop(),O.persistPendingSummary(),F.dispose(),et();try{H?.close()}catch{}s.close(),p.dispose();try{Se(K)&&ye(K)}catch{}p.clearAttachState(),await ze(),process.exit(n)}},"completeExit"),W=e((n,o=0)=>{if(N)return;const c=n==="shutdown-hook"||n==="shutdown-after-settle";if(c&&O.finishOpenToolGroup(!0),c&&(O.hasSummaryTasks()||X.hasTasks())){if(ae)return;ae=!0,Promise.allSettled([O.waitForSummaryTasks(),X.waitForTasks()]).finally(()=>_e(o));return}_e(o)},"disposeAndExit");de=it({writable:e(()=>p.writableClients(),"writable"),forward:e((n,o)=>p.sendFrame(n,o),"forward"),pending:V,broadcast:e(n=>p.broadcastUi(n),"broadcast"),onKnownStreamWait:e(n=>F.knownStreamWait(n),"onKnownStreamWait")}),g.setRebindSession(),await g.enqueueRebind(U,A),d("broker.startup.extensions_bound");const M=Fn({nodeId:t,registry:p,toolGroups:O,projection:F,rebind:g,boundaryReviewId:R,pendingDialogs:V,sendWelcome:he,replayExtraPendingDialogsTo:Me,reWelcomeAll:ne,disposeAndExit:W,persistModelChoice:pe,broadcastModelChanged:ge,registryOf:se,formatModelSpec:$,formatExactModelSpec:Qn,turnAdmission:ee,memoryInventory:y,runNode:T,onKickoffAdmitted:L.releaseKickoff});le=M.notifyTurnAccepted,ce=M.resetForSession,me=M.pendingPromptDispatches;const xe=2500;let te=!1;const Ce=e(async n=>{if(N||te)return;if(te=!0,g.isAgentRunActive()||g.session().isStreaming||M.pendingPromptDispatches()>0){const c=Date.now()+xe;for(;M.pendingPromptDispatches()>0&&!g.session().isStreaming&&Date.now()<c;)await new Promise(v=>setTimeout(v,25));if(g.session().isStreaming){const v=c-Date.now();if(v>0){let h;try{Gn(),await Promise.race([g.session().abort().then(()=>!0,()=>!1),new Promise(B=>{h=setTimeout(()=>B(!1),v)})])&&await Te(t,{event:"closed",end_reason:"teardown-aborted"})}finally{h!==void 0&&clearTimeout(h)}}}else(M.pendingPromptDispatches()>0||g.isAgentRunActive())&&await Te(t,{event:"interrupted"})}W(n)},"abortAndExit");if(b=e(n=>{Ce(n)},"signalTeardown"),C!==void 0){b(C);return}try{Se(K)&&ye(K)}catch{}H=Ue(n=>{const o=p.create(n);n.on("data",v=>{let h;try{h=o.decoder.push(v)}catch(_){_ instanceof zn?(p.sendFrame(o,{type:"error",code:"frame_overflow",message:_.message}),p.dropClient(o,`frame overflow: ${_.message}`)):p.dropClient(o,`decoder error: ${String(_)}`);return}for(const _ of h)try{Ln(M,o,_)}catch{}});const c=e(()=>{p.removeClient(o)},"drop");n.on("close",c),n.on("error",()=>{})}),H.on("error",n=>{N||(E({level:"error",event:"broker.socket.failed",error:n}),W("socket-error",1))}),H.listen(K,async()=>{Promise.all([z(t,{op:"clear",link:"viewer\u2194broker"}),z(t,{op:"clear",link:"relay\u2194broker"})]).catch(o=>E({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:o,fields:{operation:"broker_socket_bound_fault_clear"}}));let n;try{n=await j.recoverOnStartup()}catch(o){E({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:o,fields:{operation:"recovery_startup"}}),W("recovery-startup-failed",1);return}if(!(N||te))if(n!=="retry-armed"&&u.firstPrompt!==void 0&&u.firstPrompt!==""){const o=Wn(process.env[qn]);o!==null&&Vn(u.firstPrompt,o);const c=process.env.CRTR_KICKOFF_MESSAGE_IDS;M.kickoff(u.firstPrompt,c?JSON.parse(c):[])}else L.releaseKickoff()}),p.persistAttachState()}e(co,"runBroker");function tt(t){const r=new Set;for(const i of t)if(!(i.role!=="assistant"||!Array.isArray(i.content)))for(const m of i.content)m!==null&&typeof m=="object"&&m.type==="toolCall"&&typeof m.id=="string"&&r.add(m.id);return r}e(tt,"toolCallIds");function Ee(t,r){const i=t.sessionManager,m=hn(i);return m!==void 0&&Bn(m.map(({message:s})=>s)),m===void 0?void 0:Sn(m,{boundaryReviewId:r,sessionEntries:i.getEntries?.()})}e(Ee,"snapshotMessages");function ke(){const t=Ne();if(t===void 0||t==="")throw new Error("broker launch is missing CRTR_NODE_ID");return t}e(ke,"currentBrokerNodeId");async function ot(t,r){const i=cn(r.model,Ie(),r.modelExact===!0);if(i===void 0)return;const m=se(t),s={cwd:De()??r.cwd,profileId:Fe()},a=fn(i,m,s);if(a!==void 0)throw await z(ke(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`model '${a.request.spec}' is not registered in the serving model registry`}}),new Error(`[broker] FATAL: model '${a.request.spec}' is not registered in the serving model registry`);const l=mn(i,s.cwd,s.profileId),d=un(i.spec);for(const f of l){const w=m.find(f.providerId,f.modelId);if(w===void 0)continue;const S=d?.providerId===f.providerId&&d.modelId===f.modelId?d.thinkingLevel??(f.thinkingLevel===void 0?void 0:"off"):f.thinkingLevel;return{model:w,thinkingLevel:S}}if(r.modelExact===!0){const f=l.map(w=>`'${w.providerId}/${w.modelId}' unregistered`).join("; ");throw await z(ke(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`exact-consult model '${r.model}' is unavailable \u2014 refusing to substitute (${f})`}}),new Error(`[broker] FATAL: exact-consult model '${r.model}' is unavailable`)}E({level:"warn",event:"broker.model.none_viable",fields:{rejected_candidates:l.map(f=>({provider:f.providerId,model:f.modelId,reason:"unregistered"})).slice(0,16)}})}e(ot,"resolveLaunchModel");function rt(t){let r=!0;return{runtime:new Proxy(t,{get(m,s,a){return r&&s==="getAvailableSnapshot"?()=>[]:r&&s==="getAvailable"?async()=>[]:r&&s==="getModel"?()=>{}:Reflect.get(m,s,a)}}),reveal:e(()=>{r=!1},"reveal")}}e(rt,"modelLessRegistry");async function st(t,r){const i=Y(),m=e(async S=>{const u=await Ve.create({credentials:new dn,modelsPath:be(S.agentDir,"models.json")});ln(u);const y=await t.createAgentSessionServices({cwd:S.cwd,agentDir:S.agentDir,modelRuntime:u,resourceLoaderOptions:{additionalExtensionPaths:r.extensionPaths,appendSystemPrompt:r.appendSystemPromptPath!==void 0?[r.appendSystemPromptPath]:void 0,noContextFiles:!0,extensionsOverride:e(P=>({...P,extensions:P.extensions.filter(R=>!/[/\\]provider-rotation\.(?:ts|js)$/.test(R.path))}),"extensionsOverride")}}),b=y.resourceLoader.getExtensions();if(r.extensionPaths.some(P=>oe.includes(P))){const P=new Set(b.extensions.map(T=>T.path)),R=oe.filter(T=>!P.has(T));if(R.length>0){const T=b.errors.filter(D=>oe.includes(D.path)).map(D=>`${D.path}: ${D.error}`).join("; ");throw new Error(`[broker] FATAL: mandatory canvas extensions failed to load: ${R.join(", ")}${T===""?"":` (${T})`}`)}}y.settingsManager.getRetryEnabled=()=>!1;const C=await ot(y,r),q=C?.model,U=C?.thinkingLevel,A=C===void 0?rt(y.modelRuntime):void 0,ie=A!==void 0?{...y,modelRuntime:A.runtime}:y,G=await t.createAgentSessionFromServices({services:ie,sessionManager:S.sessionManager,model:q,thinkingLevel:U,...nt(r.tools,Le()),sessionStartEvent:S.sessionStartEvent});return $n(G.session),an(G.session),A?.reveal(),{...G,services:y}},"buildForManager"),s=r.resumeSessionPath,a=r.forkFrom!==void 0&&r.forkFrom!=="";if(!a&&(s===void 0||s==="")&&r.resumeSessionId!==void 0&&r.resumeSessionId!=="")throw new Error(`[broker] resume requires a session .jsonl PATH; got only a bare id '${r.resumeSessionId}' (pi_session_file was never captured for this node)`);const l=!a&&s!==void 0&&s!=="",d=l&&r.newCycle===!0,f=l&&!d;let w;if(a)w=t.SessionManager.forkFrom(r.forkFrom,r.cwd);else if(f||d){if(w=t.SessionManager.open(s),d){const S=w.getLeafId();w.resetLeaf(),w.appendCustomEntry(vn,{cycle:Number(process.env.CRTR_CYCLES),fromLeaf:S})}}else w=t.SessionManager.create(r.cwd);if(t.createAgentSessionRuntime!==void 0){const S=e(async y=>{const b=await m({cwd:y.cwd,agentDir:y.agentDir,sessionManager:y.sessionManager,sessionStartEvent:y.sessionStartEvent});return{...b,diagnostics:b.services.diagnostics??[]}},"factory"),u=await t.createAgentSessionRuntime(S,{cwd:r.cwd,agentDir:i,sessionManager:w});return{session:u.session,services:u.services,resuming:f,runtime:u}}const k=await m({cwd:r.cwd,agentDir:i,sessionManager:w});return{session:k.session,services:k.services,resuming:f,runtime:void 0}}e(st,"buildBrokerSession");function it(t){const r=e((s,a,l,d)=>{if(d?.signal?.aborted)return Promise.resolve(s);const f=t.writable();return f.length===0?Promise.resolve(s):new Promise(w=>{let k;const S=e(()=>{k!==void 0&&clearTimeout(k),d?.signal?.removeEventListener("abort",u),t.pending.delete(a.id)},"cleanup"),u=e(()=>{S(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),w(s)},"onAbort");d?.signal?.addEventListener("abort",u,{once:!0});const y=d?.timeout!==void 0?d.timeout:Zn;k=setTimeout(()=>{S(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),w(s)},y),typeof k.unref=="function"&&k.unref(),t.pending.set(a.id,{request:a,resolve:e(b=>{S(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),w(l(b))},"resolve")});for(const b of f)t.forward(b,a)})},"dialogPromise"),i=e(()=>{},"noop");return{[pn]:t.onKnownStreamWait??(s=>()=>{}),get theme(){const s=globalThis[Symbol.for("@earendil-works/pi-coding-agent:theme")];if(s==null)throw new Error("Theme not initialized. Call initTheme() first.");return s},select:e((s,a,l)=>r(void 0,{type:"extension_ui_request",id:x(),method:"select",title:s,options:a,timeout:l?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,l),"select"),confirm:e((s,a,l)=>r(!1,{type:"extension_ui_request",id:x(),method:"confirm",title:s,message:a,timeout:l?.timeout},d=>"cancelled"in d&&d.cancelled?!1:"confirmed"in d?d.confirmed:!1,l),"confirm"),input:e((s,a,l)=>r(void 0,{type:"extension_ui_request",id:x(),method:"input",title:s,placeholder:a,timeout:l?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,l),"input"),editor:e((s,a)=>r(void 0,{type:"extension_ui_request",id:x(),method:"editor",title:s,prefill:a},l=>"cancelled"in l&&l.cancelled?void 0:"value"in l?l.value:void 0),"editor"),setStatus:e((s,a)=>t.broadcast({type:"extension_ui_request",id:x(),method:"setStatus",statusKey:s,statusText:a}),"setStatus"),setWidget:e((s,a,l)=>{typeof a!="function"&&t.broadcast({type:"extension_ui_request",id:x(),method:"setWidget",widgetKey:s,widgetLines:a,widgetPlacement:l?.placement})},"setWidget"),setTitle:e(s=>t.broadcast({type:"extension_ui_request",id:x(),method:"setTitle",title:s}),"setTitle"),notify:e((s,a)=>{const l=a==="warn"?"warning":a;t.broadcast({type:"extension_ui_request",id:x(),method:"notify",message:s,notifyType:l})},"notify"),onTerminalInput:e(()=>i,"onTerminalInput"),setWorkingMessage:i,setWorkingVisible:i,setWorkingIndicator:i,setHiddenThinkingLabel:i,setFooter:i,setHeader:i,custom:e(()=>Promise.resolve(void 0),"custom"),pasteToEditor:i,setEditorText:i,getEditorText:e(()=>"","getEditorText"),addAutocompleteProvider:i,setEditorComponent:i,getEditorComponent:e(()=>{},"getEditorComponent"),getAllThemes:e(()=>[],"getAllThemes"),getTheme:e(()=>{},"getTheme"),setTheme:i,getToolsExpanded:e(()=>!1,"getToolsExpanded"),setToolsExpanded:i}}e(it,"makeBrokerUiContext");export{po as REVIEW_BOUNDARY_NAVIGATION_CODE,fo as ReviewBoundaryNavigationError,nt as brokerToolOptions,st as buildBrokerSession,et as disposeActiveSession,it as makeBrokerUiContext,co as runBroker,Ee as snapshotMessages};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var C=Object.defineProperty;var a=(e,t)=>C(e,"name",{value:t,configurable:!0});import{existsSync as N,readFileSync as
|
|
2
|
-
`).join("")})(),systemPrompt:
|
|
3
|
-
`)}a(
|
|
1
|
+
var C=Object.defineProperty;var a=(e,t)=>C(e,"name",{value:t,configurable:!0});import{existsSync as N,readFileSync as j}from"node:fs";import{isBeneathRefusal as F,readFileBeneath as $,readTextBeneathIfExists as x}from"../spaces/open-beneath.js";import{join as p}from"node:path";import{InputError as f}from"../io.js";import{conversationIdFromPath as y,conversationStore as w,ConversationNotFoundError as A}from"../conversation-store/index.js";import{fullName as T,getNode as g}from"../canvas/index.js";import{nodeRunDir as h,nodeRunJobDir as S,sessionPtrPath as k}from"../canvas/paths.js";import{hydratePersistedAdvertisedCommandMessages as v}from"./advertised-command-invocation.js";import{SessionManager as L}from"./broker-sdk.js";import{openModelRegistry as P}from"./model-registry.js";import{BUILTIN_SLASH_COMMANDS as B}from"./pi-vendored.js";import{cycleAwareMessages as J}from"./session-cycles.js";import{projectTranscript as O}from"./session-visibility.js";import{normalizeToolGroupSummaryRecord as E}from"../../shared/tool-groups.js";import{normalizeTurnReplyRecord as U}from"../../shared/turn-replies.js";async function V(e){if(e!==null)try{return(await P()).find(e.provider,e.modelId)}catch{return}}a(V,"resolveRecordedModel");function b(e,t){const o=a(i=>{const n=i?y(i):null;if(n===null)return null;try{return w().header(n).path}catch(l){if(l instanceof A)return null;throw l}},"resolvePath"),s=o(t);if(s!==null)return s;const r=k(e);return N(r)?o(j(r,"utf8").trim()):null}a(b,"resolveSessionFile");function W(e){const t=g(e);if(t===null)throw new f({error:"not_found",message:`no node: ${e}`,field:"id",next:"List nodes with `crtr node inspect list`."});return b(e,t.pi_session_file)}a(W,"readableSessionFile");function z(e,t){return{sessionFile:t,sessionId:e,userMessages:0,assistantMessages:0,toolCalls:0,toolResults:0,totalMessages:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0},cost:0}}a(z,"emptyStats");function D(e,t,o){const s=z(t,o);s.totalMessages=e.length;for(const r of e)if(r.role==="user")s.userMessages++;else if(r.role==="assistant"){s.assistantMessages++;const i=Array.isArray(r.content)?r.content:[];s.toolCalls+=i.filter(l=>l!==null&&typeof l=="object"&&l.type==="toolCall").length;const n=r.usage;n!==void 0&&(s.tokens.input+=n.input??0,s.tokens.output+=n.output??0,s.tokens.cacheRead+=n.cacheRead??0,s.tokens.cacheWrite+=n.cacheWrite??0,s.cost+=n.cost?.total??0)}else r.role==="toolResult"&&s.toolResults++;return s.tokens.total=s.tokens.input+s.tokens.output+s.tokens.cacheRead+s.tokens.cacheWrite,s}a(D,"statsFromMessages");function ge(e){const t=g(e);if(t===null)throw new f({error:"not_found",message:`no node: ${e}`,field:"id",next:"List nodes with `crtr node inspect list`."});const o=b(e,t.pi_session_file);if(o===null)throw new f({error:"no_session",message:`node has no readable session file: ${e}`,field:"id",next:"Choose a node with captured conversation history."});return{nodeId:e,sessionFile:o,sessionJsonl:(()=>{const{header:s,entries:r}=w().read(y(o));return[s,...r].map(i=>`${JSON.stringify(i)}
|
|
2
|
+
`).join("")})(),systemPrompt:M(e,p(S(e),"system-prompt.md"))??M(e,p(h(e),"system-prompt.md"))}}a(ge,"readNodeSession");function M(e,t){try{return $(h(e),t).toString("utf8")}catch(o){if(F(o))throw o;return null}}a(M,"readRunFileIfPresent");function G(e){try{const t=x(h(e),p(S(e),"tool-summaries.json"));return E(t===null?null:JSON.parse(t))}catch{return{}}}a(G,"readToolGroupSummaries");function q(e){try{const t=x(h(e),p(S(e),"turn-replies.json"));return U(t===null?null:JSON.parse(t))}catch{return{}}}a(q,"readTurnReplies");async function R(e){const t=g(e);if(t===null)throw new f({error:"not_found",message:`no node: ${e}`,field:"id",next:"List nodes with `crtr node inspect list`."});const o=b(e,t.pi_session_file);if(o===null)throw new f({error:"no_session",message:`node has no readable session file: ${e}`,field:"id",next:"Choose a node with captured conversation history."});const{header:s,entries:r}=w().read(y(o)),i=L.inMemory(s.cwd,void 0,[s,...r]),n=i.buildSessionContext();v(n.messages);const l=J(i);l!==void 0&&v(l.map(({message:c})=>c));const u=l===void 0?void 0:O(l,{boundaryReviewId:t.review_binding?.review_id,sessionEntries:i.getEntries()}),m=u?.map(({message:c})=>c)??n.messages;return{sessionFile:o,messages:m,identified:u,model:n.model,thinkingLevel:n.thinkingLevel,sessionId:i.getSessionId(),sessionName:i.getSessionName()}}a(R,"reconstructTranscript");function d(){throw new f({error:"invalid_cursor",message:"cursor must be a base64url-encoded messages cursor.",field:"cursor",next:"Omit cursor to start from the newest messages."})}a(d,"invalidCursor");function H(e,t){/^[A-Za-z0-9_-]+$/u.test(e)||d();let o;try{const r=Buffer.from(e,"base64url").toString("utf8");Buffer.from(r,"utf8").toString("base64url")!==e&&d(),o=JSON.parse(r)}catch{d()}(typeof o!="object"||o===null||o.v!==1||!Number.isSafeInteger(o.before))&&d();const s=o.before;return(s<0||s>t)&&d(),s}a(H,"decodeMessagesCursor");function Y(e){return Buffer.from(JSON.stringify({v:1,before:e}),"utf8").toString("base64url")}a(Y,"encodeMessagesCursor");async function Z(e){const t=await R(e),o={messages:t.messages,...t.identified===void 0?{}:{messageIds:t.identified.map(({id:s})=>s)},messageVisibility:t.identified?.map(({visibility:s})=>s)??t.messages.map(()=>"visible"),turnVisibility:"visible",stats:D(t.messages,t.sessionId,t.sessionFile),state:{model:await V(t.model),thinkingLevel:t.thinkingLevel,isStreaming:!1,isCompacting:!1,steeringMode:"one-at-a-time",followUpMode:"one-at-a-time",sessionFile:t.sessionFile,sessionId:t.sessionId,sessionName:t.sessionName,autoCompactionEnabled:!0,messageCount:t.messages.length,pendingMessageCount:0},display:{statuses:{},widgets:{},title:void 0},queued:{steering:[],followUp:[]},toolGroupSummaries:G(e),turnReplies:q(e)};return{nodeId:e,snapshot:o,commands:B.map(s=>({...s,source:"builtin"}))}}a(Z,"readNodeSnapshot");async function he(e,{cursor:t,limit:o=200}){if(!Number.isSafeInteger(o)||o<1||o>500)throw new f({error:"invalid_limit",message:"limit must be an integer from 1 through 500.",field:"limit",next:"Use a limit from 1 through 500."});if(W(e)===null)return{messages:[],messageIds:[],messageVisibility:[],nextCursor:null};const{messages:s,identified:r}=await R(e),i=t===void 0?s.length:H(t,s.length);let n=Math.max(0,i-o);for(;n>0&&typeof s[n]=="object"&&s[n]!==null&&s[n].role==="toolResult";)n--;const l=r?.slice(n,i);return{messages:l?.map(({message:u})=>u)??s.slice(n,i),...l===void 0?{}:{messageIds:l.map(({id:u})=>u)},messageVisibility:l?.map(({visibility:u})=>u)??s.slice(n,i).map(()=>"visible"),nextCursor:n===0?null:Y(n)}}a(he,"readNodeMessagesPage");function K(e){return typeof e=="string"?e:Array.isArray(e)?e.filter(t=>typeof t=="object"&&t!==null).filter(t=>t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(""):""}a(K,"textFromContent");function Q(e){switch(e.role){case"user":return"You";case"assistant":return"Agent";case"toolResult":return"Tool result";default:return typeof e.role=="string"?e.role:"Message"}}a(Q,"roleLabel");function X(e){return Array.isArray(e.content)?e.content.filter(t=>typeof t=="object"&&t!==null&&t.type==="toolCall").map(t=>`Tool: ${typeof t.name=="string"?t.name:"call"}`):[]}a(X,"toolSummaries");async function ye(e){const t=g(e);if(t===null)throw new f({error:"not_found",message:`no node: ${e}`,field:"node-id",next:"List nodes with `crtr node inspect list`."});const{snapshot:o}=await Z(e),r=[`# ${T(t)}`,"",`Saved transcript \xB7 ${t.status} \xB7 ${t.lifecycle}`,""];for(const i of o.messages){if(typeof i!="object"||i===null)continue;const n=i;if(n.role==="custom"&&n.display===!1)continue;const l=K(n.content),u=typeof n.text=="string"?n.text:"",m=l.trim()?l:u.trim()?u:"",c=X(n);if(!(!m&&c.length===0)){r.push(`## ${Q(n)}`,""),m&&r.push(m,"");for(const _ of c)r.push(`- ${_}`);c.length&&r.push("")}}return r.length===5&&r.push("_No saved messages._",""),r.join(`
|
|
3
|
+
`)}a(ye,"transcriptMarkdown");export{he as readNodeMessagesPage,ge as readNodeSession,Z as readNodeSnapshot,ye as transcriptMarkdown};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var Q=Object.defineProperty;var u=(e,n)=>Q(e,"name",{value:n,configurable:!0});import{mkdtempSync as Y,rmSync as Z,writeFileSync as V}from"node:fs";import{tmpdir as O}from"node:os";import{join as M}from"node:path";import{ATTACH_CONTROL_BINDINGS as U,BINDING_CATALOG as _,BINDING_IDS as ee,encodeAttachControlInput as ne,formatGesture as te,isAttachPaneBinding as re,resolveUserKeybindingSettings as q}from"../keybindings/index.js";import{normalizeTmuxPassthrough as ie}from"../config.js";import{withExclusiveDirectoryLock as oe}from"../exclusive-lock.js";import{surfaceTmuxStyleArgs as se}from"./surface-bg.js";import{runTmux as f,shellQuote as h}from"./tmux-driver.js";const A="@crtr_keybindings_manifest",p="root",ue={"crtr.tmux.menu.promote":{description:"promote to orchestrator",action:{kind:"keys",keys:"/promote"}},"crtr.tmux.menu.resume":{description:"find node",action:{kind:"keys",keys:"/resume"}},"crtr.tmux.menu.fork":{description:"fork into idle root",action:{kind:"direct",run:"node fork --pane {pane}"}},"crtr.tmux.menu.demote-mode":{description:"demote to base node",action:{kind:"command",run:"node config --mode base --pane {pane}"}},"crtr.tmux.menu.demote":{description:"demote to terminal (finish when done)",action:{kind:"command",run:"node lifecycle demote --pane {pane}"}},"crtr.tmux.menu.make-resident":{description:"make resident (interactable)",action:{kind:"command",run:"node config --lifecycle resident --pane {pane}"}},"crtr.tmux.menu.detach":{description:"demote + close viewer",action:{kind:"command",run:"node lifecycle demote --pane {pane} --detach"}},"crtr.tmux.menu.close-subtree":{description:"close agent + subtree",action:{kind:"command",run:"node lifecycle close --pane {pane}"}},"crtr.tmux.menu.background-bash":{description:"background running bash",action:{kind:"direct",run:"node bash background --pane {pane}"}},"crtr.tmux.menu.file-review":{description:"review a file",action:{kind:"raw-keys",keys:"M-S-r"}},"crtr.tmux.menu.metadata":{description:"metadata",action:{kind:"keys",keys:"/node-metadata"}},"crtr.tmux.menu.fold-tools":{description:"fold finished tool calls",action:{kind:"keys",keys:"/fold-tools"}},"crtr.tmux.menu.context":{description:"context + reports",action:{kind:"keys",keys:"/context"}},"crtr.tmux.menu.providers":{description:"settings",action:{kind:"popup",run:"sys settings",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.provider-options":{description:"provider options",action:{kind:"popup",run:"sys settings --page provider-options",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.plugins":{description:"plugins",action:{kind:"popup",run:"pkg browse",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.analytics":{description:"analytics",action:{kind:"popup",run:"canvas analytics --pane {pane}",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.context-admin":{description:"context surface",action:{kind:"popup",run:"sys context admin",size:{w:"98%",h:"96%"}}},"crtr.tmux.menu.graph":{description:"canvas graph",action:{kind:"keys",keys:"/graph"}},"crtr.tmux.menu.focus-manager":{description:"go to manager",action:{kind:"command",run:"surface node focus {manager}"}},"crtr.tmux.menu.copy-id":{description:"copy node id",action:{kind:"command",run:"surface node id --pane {pane}"}},"crtr.tmux.menu.reload-viewer":{description:"reload viewer",action:{kind:"direct",run:"surface reload --pane {pane}"}},"crtr.tmux.menu.recap":{description:"generate recap",action:{kind:"keys",keys:"/recap"}},"crtr.tmux.menu.pin":{description:"pin conversation",action:{kind:"direct",run:"surface node pin --pane {pane}"}},"crtr.tmux.menu.issue.idea":{description:"idea",action:{kind:"popup",run:"canvas issue new --type idea"}},"crtr.tmux.menu.issue.bug":{description:"bug",action:{kind:"popup",run:"canvas issue new --type bug"}}};function b(e){return e.replace(/#/g,"##")}u(b,"escapeTmuxFormats");function ce(e){return e.map(h).join(" ")}u(ce,"tmuxCommand");const ae={w:"60%",h:"50%"};function G(e,n=!1,t=ae){const r=`crtr canvas chord --pane '#{pane_id}' --run ${h(b(e))}${n?" --interactive":""}`;return n?{argv:["display-popup","-E","-w",t.w,"-h",t.h,"-d","#{pane_current_path}",r],menu:`display-popup -E -w ${t.w} -h ${t.h} -d "#{pane_current_path}" ${h(r)}`}:{argv:["run-shell",`${r} >/dev/null 2>&1`],menu:`run-shell ${h(`${r} >/dev/null 2>&1`)}`}}u(G,"chordCommand");function de(e){const t=`crtr ${b(e).replace("{pane}","#{pane_id}")} >/dev/null 2>&1`;return{argv:["run-shell","-b",t],menu:`run-shell -b ${h(t)}`}}u(de,"directCommand");function j(e){switch(e.kind){case"disabled":return null;case"separator":return null;case"dismiss":return{argv:["refresh-client"],menu:"refresh-client"};case"keys":{const n=b(e.keys);return{argv:["send-keys",n,"Enter"],menu:`send-keys -t '#{pane_id}' ${h(n)} Enter`}}case"raw-keys":{const n=b(e.keys);return{argv:["send-keys",n],menu:`send-keys -t '#{pane_id}' ${h(n)}`}}case"literal-input":{const n=b(e.input);return{argv:["send-keys","-l",n],menu:`send-keys -l -t '#{pane_id}' ${h(n)}`}}case"command":return G(e.run);case"direct":return de(e.run);case"popup":return G(e.run,!0,e.size);case"submenu":{const n=N(e.title,e.items);return{argv:n,menu:ce(n)}}}}u(j,"menuActionCommand");function me(e){return j(e)?.menu??""}u(me,"renderMenuAction");function pe(e){return e.replace(/#\[[^\]]*\]/g,"").length}u(pe,"menuItemWidth");function N(e,n){const t=b(e),r=n.reduce((o,c)=>Math.max(o,pe(c.description)),0),s=["display-menu","-T",`#[align=centre]${t}`,...se()];s.push("-x",`#{e|-:#{pane_right},${Math.max(t.length,r)+7}}`,"-y","#{e|+:#{pane_top},3}","--");for(const o of n){if(o.action.kind==="separator"){s.push("");continue}const c=o.action.kind==="disabled"?o.description:b(o.description);s.push(c,o.selector,me(o.action))}return s.push("","-esc / q to close","",""),s}u(N,"buildMenuArgs");const le={enter:"Enter",escape:"Escape",tab:"Tab",backspace:"BSpace",delete:"DC",space:"Space",up:"Up",down:"Down",left:"Left",right:"Right",pageup:"PPage",pagedown:"NPage",home:"Home",end:"End"};function z(e){if(e==="+")return{key:"+",modifiers:[]};if(e.endsWith("++"))return{key:"+",modifiers:e.slice(0,-2).split("+")};const n=e.split("+");return{key:n.pop(),modifiers:n}}u(z,"normalizedStrokeParts");function fe(e){return v(e)[0]}u(fe,"tmuxKey");function v(e){let{key:n,modifiers:t}=z(e);const r=new Set(t),s=u((o,c)=>[r.has("ctrl")?"C-":"",r.has("alt")?"M-":"",c?"S-":"",le[o]??o].join(""),"name");if(r.has("shift")&&n.length===1&&/[a-z]/.test(n)){const o=n.toUpperCase();return!r.has("ctrl")&&!r.has("alt")?[s(o,!1)]:[s(o,!0),s(o,!1),s(n,!0)]}return[s(n,r.has("shift"))]}u(v,"tmuxKeyNames");function ge(e){const{key:n,modifiers:t}=z(e);return t.includes("shift")&&/[a-z]/.test(n)?n.toUpperCase():n==="space"?" ":n}u(ge,"menuSelector");function T(e,n,t){const r=[];for(const s of e){const o=n.get(s);if(o!==void 0)for(const c of t.gestures(s))r.push({description:o.description,selector:ge(c),action:o.action})}return r}u(T,"boundMenuItems");function F(e){const n=new Map;for(const[c,l]of Object.entries(ue))l!==void 0&&n.set(c,l);for(const{menuId:c,actionId:l}of U){const x=_.find(w=>w.id===l);if(x===void 0)throw new Error(`missing attach binding definition ${l}`);n.set(c,{description:x.name.toLowerCase(),action:{kind:"literal-input",input:ne(l)}})}const t=T(U.map(({menuId:c})=>c),n,e);t.length>0&&n.set("crtr.tmux.menu.attach",{description:"attach viewer \u203A",action:{kind:"submenu",title:" attach viewer ",items:t}});const r=T(["crtr.tmux.menu.metadata","crtr.tmux.menu.context"],n,e);n.set("crtr.tmux.menu.show",{description:"inspect \u203A",action:{kind:"submenu",title:" inspect node ",items:r}});const s=T(["crtr.tmux.menu.fold-tools"],n,e);n.set("crtr.tmux.menu.view-settings",{description:"display \u203A",action:{kind:"submenu",title:" display ",items:s}});const o=T(["crtr.tmux.menu.issue.idea","crtr.tmux.menu.issue.bug"],n,e);return n.set("crtr.tmux.menu.issues",{description:"create \u203A",action:{kind:"submenu",title:" create ",items:o}}),n}u(F,"resolvedMenuActions");function K(e,n){const t=u(c=>T(c,n,e),"boundItems"),r=[],s=u((c,l)=>{l.length!==0&&(r.length>0&&r.push({description:"",selector:"",action:{kind:"separator"}}),r.push({description:`-#[bold]${c}`,selector:"",action:{kind:"disabled"}},...l))},"addGroup");s("Explore",t(["crtr.tmux.menu.resume","crtr.tmux.menu.graph","crtr.tmux.menu.focus-manager","crtr.tmux.menu.show","crtr.tmux.menu.view-settings"])),s("Current node",t(["crtr.tmux.menu.attach","crtr.tmux.menu.background-bash","crtr.tmux.menu.file-review","crtr.tmux.menu.pin","crtr.tmux.menu.copy-id","crtr.tmux.menu.reload-viewer","crtr.tmux.menu.recap"])),s("Lifecycle",t(["crtr.tmux.menu.fork","crtr.tmux.menu.promote","crtr.tmux.menu.demote-mode","crtr.tmux.menu.demote","crtr.tmux.menu.make-resident","crtr.tmux.menu.detach","crtr.tmux.menu.close-subtree"])),s("System",t(["crtr.tmux.menu.providers","crtr.tmux.menu.provider-options","crtr.tmux.menu.plugins","crtr.tmux.menu.analytics","crtr.tmux.menu.context-admin","crtr.tmux.menu.issues"]));const o=e.gestures("crtr.tmux.menu.open");if(o.length>0&&r.length>0){r.push({description:"",selector:"",action:{kind:"separator"}});for(const c of o)r.push({description:`${te(c)} to close`,selector:fe(c),action:{kind:"dismiss"}})}return r}u(K,"menuItems");function Pe(e){const n=e??q().bindings;return N(" crtr ",K(n,F(n)))}u(Pe,"crouterMenuTmuxArgs");function S(e,n){let t=n;for(;t<e.length&&/\s/.test(e[t]);)t+=1;if(t>=e.length)return null;let r=null,s="";for(;t<e.length;){const o=e[t];if(r===null&&/\s/.test(o))break;if(r===null&&(o==="'"||o==='"')){r=o,t+=1;continue}if(r===o){r=null,t+=1;continue}if(o==="\\"&&r!=="'"&&t+1<e.length){s+=e[t+1],t+=2;continue}s+=o,t+=1}return{value:s,end:t}}u(S,"readTmuxToken");function B(e){const n=S(e,0);if(n?.value!=="bind-key")return null;let t=n.end,r=!1;for(;;){const s=S(e,t);if(s===null)return null;if(t=s.end,s.value==="-r"){r=!0;continue}if(s.value!=="-T")continue;const o=S(e,t);if(o===null)return null;const c=S(e,o.end);return c===null?null:{table:o.value,key:c.value,command:e.slice(c.end).trimStart(),repeat:r}}}u(B,"parseTmuxBinding");function $(e,n){const t=f(["list-keys","-T",e]);return t.ok?t.stdout.split(`
|
|
1
|
+
var Q=Object.defineProperty;var u=(e,n)=>Q(e,"name",{value:n,configurable:!0});import{mkdtempSync as Y,rmSync as Z,writeFileSync as V}from"node:fs";import{tmpdir as O}from"node:os";import{join as M}from"node:path";import{ATTACH_CONTROL_BINDINGS as U,BINDING_CATALOG as _,BINDING_IDS as ee,encodeAttachControlInput as ne,formatGesture as te,isAttachPaneBinding as re,resolveUserKeybindingSettings as q}from"../keybindings/index.js";import{normalizeTmuxPassthrough as ie}from"../config.js";import{withExclusiveDirectoryLock as oe}from"../exclusive-lock.js";import{surfaceTmuxStyleArgs as se}from"./surface-bg.js";import{runTmux as f,shellQuote as h}from"./tmux-driver.js";const A="@crtr_keybindings_manifest",p="root",ue={"crtr.tmux.menu.promote":{description:"promote to orchestrator",action:{kind:"keys",keys:"/promote"}},"crtr.tmux.menu.resume":{description:"find node",action:{kind:"keys",keys:"/resume"}},"crtr.tmux.menu.fork":{description:"fork into idle root",action:{kind:"direct",run:"node fork --pane {pane}"}},"crtr.tmux.menu.demote-mode":{description:"demote to base node",action:{kind:"command",run:"node config --mode base --pane {pane}"}},"crtr.tmux.menu.demote":{description:"demote to terminal (finish when done)",action:{kind:"command",run:"node lifecycle demote --pane {pane}"}},"crtr.tmux.menu.make-resident":{description:"make resident (interactable)",action:{kind:"command",run:"node config --lifecycle resident --pane {pane}"}},"crtr.tmux.menu.detach":{description:"demote + close viewer",action:{kind:"command",run:"node lifecycle demote --pane {pane} --detach"}},"crtr.tmux.menu.close-subtree":{description:"close agent + subtree",action:{kind:"command",run:"node lifecycle close --pane {pane}"}},"crtr.tmux.menu.background-bash":{description:"background running bash",action:{kind:"direct",run:"node bash background --pane {pane}"}},"crtr.tmux.menu.file-review":{description:"review a file",action:{kind:"raw-keys",keys:"M-S-r"}},"crtr.tmux.menu.metadata":{description:"metadata",action:{kind:"keys",keys:"/node-metadata"}},"crtr.tmux.menu.fold-tools":{description:"fold finished tool calls",action:{kind:"keys",keys:"/fold-tools"}},"crtr.tmux.menu.show-working":{description:"show/hide working",action:{kind:"keys",keys:"/show-working"}},"crtr.tmux.menu.context":{description:"context + reports",action:{kind:"keys",keys:"/context"}},"crtr.tmux.menu.providers":{description:"settings",action:{kind:"popup",run:"sys settings",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.provider-options":{description:"provider options",action:{kind:"popup",run:"sys settings --page provider-options",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.plugins":{description:"plugins",action:{kind:"popup",run:"pkg browse",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.analytics":{description:"analytics",action:{kind:"popup",run:"canvas analytics --pane {pane}",size:{w:"90%",h:"85%"}}},"crtr.tmux.menu.context-admin":{description:"context surface",action:{kind:"popup",run:"sys context admin",size:{w:"98%",h:"96%"}}},"crtr.tmux.menu.graph":{description:"canvas graph",action:{kind:"keys",keys:"/graph"}},"crtr.tmux.menu.focus-manager":{description:"go to manager",action:{kind:"command",run:"surface node focus {manager}"}},"crtr.tmux.menu.copy-id":{description:"copy node id",action:{kind:"command",run:"surface node id --pane {pane}"}},"crtr.tmux.menu.reload-viewer":{description:"reload viewer",action:{kind:"direct",run:"surface reload --pane {pane}"}},"crtr.tmux.menu.recap":{description:"generate recap",action:{kind:"keys",keys:"/recap"}},"crtr.tmux.menu.pin":{description:"pin conversation",action:{kind:"direct",run:"surface node pin --pane {pane}"}},"crtr.tmux.menu.issue.idea":{description:"idea",action:{kind:"popup",run:"canvas issue new --type idea"}},"crtr.tmux.menu.issue.bug":{description:"bug",action:{kind:"popup",run:"canvas issue new --type bug"}}};function b(e){return e.replace(/#/g,"##")}u(b,"escapeTmuxFormats");function ce(e){return e.map(h).join(" ")}u(ce,"tmuxCommand");const ae={w:"60%",h:"50%"};function G(e,n=!1,t=ae){const r=`crtr canvas chord --pane '#{pane_id}' --run ${h(b(e))}${n?" --interactive":""}`;return n?{argv:["display-popup","-E","-w",t.w,"-h",t.h,"-d","#{pane_current_path}",r],menu:`display-popup -E -w ${t.w} -h ${t.h} -d "#{pane_current_path}" ${h(r)}`}:{argv:["run-shell",`${r} >/dev/null 2>&1`],menu:`run-shell ${h(`${r} >/dev/null 2>&1`)}`}}u(G,"chordCommand");function de(e){const t=`crtr ${b(e).replace("{pane}","#{pane_id}")} >/dev/null 2>&1`;return{argv:["run-shell","-b",t],menu:`run-shell -b ${h(t)}`}}u(de,"directCommand");function j(e){switch(e.kind){case"disabled":return null;case"separator":return null;case"dismiss":return{argv:["refresh-client"],menu:"refresh-client"};case"keys":{const n=b(e.keys);return{argv:["send-keys",n,"Enter"],menu:`send-keys -t '#{pane_id}' ${h(n)} Enter`}}case"raw-keys":{const n=b(e.keys);return{argv:["send-keys",n],menu:`send-keys -t '#{pane_id}' ${h(n)}`}}case"literal-input":{const n=b(e.input);return{argv:["send-keys","-l",n],menu:`send-keys -l -t '#{pane_id}' ${h(n)}`}}case"command":return G(e.run);case"direct":return de(e.run);case"popup":return G(e.run,!0,e.size);case"submenu":{const n=N(e.title,e.items);return{argv:n,menu:ce(n)}}}}u(j,"menuActionCommand");function me(e){return j(e)?.menu??""}u(me,"renderMenuAction");function pe(e){return e.replace(/#\[[^\]]*\]/g,"").length}u(pe,"menuItemWidth");function N(e,n){const t=b(e),r=n.reduce((o,c)=>Math.max(o,pe(c.description)),0),s=["display-menu","-T",`#[align=centre]${t}`,...se()];s.push("-x",`#{e|-:#{pane_right},${Math.max(t.length,r)+7}}`,"-y","#{e|+:#{pane_top},3}","--");for(const o of n){if(o.action.kind==="separator"){s.push("");continue}const c=o.action.kind==="disabled"?o.description:b(o.description);s.push(c,o.selector,me(o.action))}return s.push("","-esc / q to close","",""),s}u(N,"buildMenuArgs");const le={enter:"Enter",escape:"Escape",tab:"Tab",backspace:"BSpace",delete:"DC",space:"Space",up:"Up",down:"Down",left:"Left",right:"Right",pageup:"PPage",pagedown:"NPage",home:"Home",end:"End"};function z(e){if(e==="+")return{key:"+",modifiers:[]};if(e.endsWith("++"))return{key:"+",modifiers:e.slice(0,-2).split("+")};const n=e.split("+");return{key:n.pop(),modifiers:n}}u(z,"normalizedStrokeParts");function fe(e){return v(e)[0]}u(fe,"tmuxKey");function v(e){let{key:n,modifiers:t}=z(e);const r=new Set(t),s=u((o,c)=>[r.has("ctrl")?"C-":"",r.has("alt")?"M-":"",c?"S-":"",le[o]??o].join(""),"name");if(r.has("shift")&&n.length===1&&/[a-z]/.test(n)){const o=n.toUpperCase();return!r.has("ctrl")&&!r.has("alt")?[s(o,!1)]:[s(o,!0),s(o,!1),s(n,!0)]}return[s(n,r.has("shift"))]}u(v,"tmuxKeyNames");function ge(e){const{key:n,modifiers:t}=z(e);return t.includes("shift")&&/[a-z]/.test(n)?n.toUpperCase():n==="space"?" ":n}u(ge,"menuSelector");function T(e,n,t){const r=[];for(const s of e){const o=n.get(s);if(o!==void 0)for(const c of t.gestures(s))r.push({description:o.description,selector:ge(c),action:o.action})}return r}u(T,"boundMenuItems");function F(e){const n=new Map;for(const[c,l]of Object.entries(ue))l!==void 0&&n.set(c,l);for(const{menuId:c,actionId:l}of U){const x=_.find(w=>w.id===l);if(x===void 0)throw new Error(`missing attach binding definition ${l}`);n.set(c,{description:x.name.toLowerCase(),action:{kind:"literal-input",input:ne(l)}})}const t=T(U.map(({menuId:c})=>c),n,e);t.length>0&&n.set("crtr.tmux.menu.attach",{description:"attach viewer \u203A",action:{kind:"submenu",title:" attach viewer ",items:t}});const r=T(["crtr.tmux.menu.metadata","crtr.tmux.menu.context"],n,e);n.set("crtr.tmux.menu.show",{description:"inspect \u203A",action:{kind:"submenu",title:" inspect node ",items:r}});const s=T(["crtr.tmux.menu.fold-tools","crtr.tmux.menu.show-working"],n,e);n.set("crtr.tmux.menu.view-settings",{description:"display \u203A",action:{kind:"submenu",title:" display ",items:s}});const o=T(["crtr.tmux.menu.issue.idea","crtr.tmux.menu.issue.bug"],n,e);return n.set("crtr.tmux.menu.issues",{description:"create \u203A",action:{kind:"submenu",title:" create ",items:o}}),n}u(F,"resolvedMenuActions");function K(e,n){const t=u(c=>T(c,n,e),"boundItems"),r=[],s=u((c,l)=>{l.length!==0&&(r.length>0&&r.push({description:"",selector:"",action:{kind:"separator"}}),r.push({description:`-#[bold]${c}`,selector:"",action:{kind:"disabled"}},...l))},"addGroup");s("Explore",t(["crtr.tmux.menu.resume","crtr.tmux.menu.graph","crtr.tmux.menu.focus-manager","crtr.tmux.menu.show","crtr.tmux.menu.view-settings"])),s("Current node",t(["crtr.tmux.menu.attach","crtr.tmux.menu.background-bash","crtr.tmux.menu.file-review","crtr.tmux.menu.pin","crtr.tmux.menu.copy-id","crtr.tmux.menu.reload-viewer","crtr.tmux.menu.recap"])),s("Lifecycle",t(["crtr.tmux.menu.fork","crtr.tmux.menu.promote","crtr.tmux.menu.demote-mode","crtr.tmux.menu.demote","crtr.tmux.menu.make-resident","crtr.tmux.menu.detach","crtr.tmux.menu.close-subtree"])),s("System",t(["crtr.tmux.menu.providers","crtr.tmux.menu.provider-options","crtr.tmux.menu.plugins","crtr.tmux.menu.analytics","crtr.tmux.menu.context-admin","crtr.tmux.menu.issues"]));const o=e.gestures("crtr.tmux.menu.open");if(o.length>0&&r.length>0){r.push({description:"",selector:"",action:{kind:"separator"}});for(const c of o)r.push({description:`${te(c)} to close`,selector:fe(c),action:{kind:"dismiss"}})}return r}u(K,"menuItems");function Pe(e){const n=e??q().bindings;return N(" crtr ",K(n,F(n)))}u(Pe,"crouterMenuTmuxArgs");function S(e,n){let t=n;for(;t<e.length&&/\s/.test(e[t]);)t+=1;if(t>=e.length)return null;let r=null,s="";for(;t<e.length;){const o=e[t];if(r===null&&/\s/.test(o))break;if(r===null&&(o==="'"||o==='"')){r=o,t+=1;continue}if(r===o){r=null,t+=1;continue}if(o==="\\"&&r!=="'"&&t+1<e.length){s+=e[t+1],t+=2;continue}s+=o,t+=1}return{value:s,end:t}}u(S,"readTmuxToken");function B(e){const n=S(e,0);if(n?.value!=="bind-key")return null;let t=n.end,r=!1;for(;;){const s=S(e,t);if(s===null)return null;if(t=s.end,s.value==="-r"){r=!0;continue}if(s.value!=="-T")continue;const o=S(e,t);if(o===null)return null;const c=S(e,o.end);return c===null?null:{table:o.value,key:c.value,command:e.slice(c.end).trimStart(),repeat:r}}}u(B,"parseTmuxBinding");function $(e,n){const t=f(["list-keys","-T",e]);return t.ok?t.stdout.split(`
|
|
2
2
|
`).find(r=>{const s=B(r);return s?.table===e&&s.key===n})??null:null}u($,"bindingAt");function Le(e){const n=f(["list-keys","-T",p]);if(!n.ok)return[];const t=new Set(n.stdout.split(`
|
|
3
3
|
`).flatMap(r=>{const s=B(r);return s?.table===p?[s.key]:[]}));return e.filter(r=>!r.includes(" > ")&&v(r).some(s=>t.has(s)))}u(Le,"occupiedTmuxRootGestures");function R(e){return typeof e=="object"&&e!==null&&typeof e.table=="string"&&typeof e.key=="string"}u(R,"isInstalledPair");function ke(e){if(typeof e!="object"||e===null)return!1;const n=e;return typeof n.bindingId=="string"&&ee.has(n.bindingId)&&typeof n.gesture=="string"&&typeof n.key=="string"&&(typeof n.original=="string"||n.original===null)&&typeof n.wrapper=="string"&&(n.state==="owned"||n.state==="relinquished")}u(ke,"isWrappedRootBinding");function he(){const e=f(["show-options","-s","-q",A]);if(!e.ok)return null;if(e.stdout==="")return{pairs:[],wrappers:[]};const n=f(["show-options","-s","-qv",A]);if(!n.ok)return null;try{const t=JSON.parse(n.stdout);if(Array.isArray(t))return t.every(R)?{pairs:t,wrappers:[]}:null;if(typeof t!="object"||t===null)return null;const r=t;return!Array.isArray(r.pairs)||!r.pairs.every(R)||!Array.isArray(r.wrappers)||!r.wrappers.every(ke)?null:{pairs:r.pairs,wrappers:r.wrappers}}catch{return null}}u(he,"readManifest");function W(e){return f(["set-option","-s",A,JSON.stringify(e)])}u(W,"writeManifest");function C(e){return e.replace(/\\/g,"\\\\").replace(/;/g,"\\;")}u(C,"tmuxKeyArgument");function xe(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/;/g,"\\;")}"`}u(xe,"tmuxCommandToken");function ye(e){let n=null,t="";for(let r=0;r<e.length;r+=1){const s=e[r];if(n===null&&(s==="'"||s==='"')){n=s,t+=s;continue}if(n===s){n=null,t+=s;continue}if(s==="\\"&&r+1<e.length){const o=e[r+1];n===null&&o===";"?t+=";":t+=s+o,r+=1;continue}t+=s}return t}u(ye,"bindingCommandForBranch");function be(e){const n=Y(M(O(),"crtr-tmux-binding-")),t=M(n,"binding.conf");try{return V(t,`${e}
|
|
4
4
|
`,"utf8"),f(["source-file",t])}finally{Z(n,{recursive:!0,force:!0})}}u(be,"sourceBindingLine");function X(e){return e.original===null?f(["unbind-key","-T",p,C(e.key)]):be(e.original)}u(X,"restoreWrappedBinding");function we(){return["run-shell","-b",'crtr surface inbox --quiet --tmux-socket "#{socket_path}" --tmux-client "#{client_name}" --target-pane "#{pane_id}"']}u(we,"inboxToggleTmuxCommand");function ve(e){switch(e){case"crtr.tmux.node.next":return["run-shell","crtr surface node cycle --dir next --pane '#{pane_id}' >/dev/null 2>&1"];case"crtr.tmux.node.previous":return["run-shell","crtr surface node cycle --dir prev --pane '#{pane_id}' >/dev/null 2>&1"];case"crtr.tmux.inbox.toggle":return we();default:throw new Error(`no tmux command for ${e}`)}}u(ve,"actionCommand");function $e(){const e=process.env.TMUX?.split(",")[0]?.trim();if(e!==void 0&&e!=="")return`${e}.crtr-keybindings.lock`;const n=f(["display-message","-p","#{socket_path}"]);if(n.ok&&n.stdout!=="")return`${n.stdout}.crtr-keybindings.lock`;const t=typeof process.getuid=="function"?process.getuid():"user";return M(O(),`crtr-tmux-keybindings-${t}.lock`)}u($e,"tmuxBindingLockPath");function De(e,n=[]){return oe($e(),()=>Ie(e,n))}u(De,"installTmuxBindings");function Ie(e,n=[]){const t=e===void 0?q():void 0,r=e??t.bindings,s=e===void 0?t.tmuxPassthrough:ie(n),o=[],c=[],l=he();if(l===null)return o.push({code:"tmux-error",message:`tmux is unavailable or ${A} is malformed`}),{ok:!1,installed:c,diagnostics:o};const x=new Map;for(const i of s){const a=_.find(d=>d.id===i);if(!(a===void 0||!re(a))){for(const d of r.gestures(i))if(!d.includes(" > "))for(const m of v(d))x.has(m)||x.set(m,{bindingId:i,gesture:d})}}const w=new Set,I=[];for(const i of l.wrappers){const a=x.get(i.key),d=$(p,i.key);if(d!==null&&d===i.original)continue;if(i.state==="relinquished"||d!==i.wrapper){w.add(i.key),a!==void 0&&I.push({...i,...a,state:"relinquished"});continue}const m=X(i);m.ok||(w.add(i.key),I.push(i),o.push({code:"tmux-error",bindingId:i.bindingId,gesture:i.gesture,message:`could not restore tmux binding ${p}:${i.key}: ${m.stderr}`}))}for(const i of l.pairs){if(i.table===p&&w.has(i.key))continue;const a=f(["unbind-key","-T",i.table,C(i.key)]);!a.ok&&$(i.table,i.key)!==null&&o.push({code:"tmux-error",message:`could not remove crouter binding ${i.table}:${i.key}: ${a.stderr}`})}if(o.some(i=>i.code==="tmux-error")){const i=W({pairs:l.pairs,wrappers:I});return i.ok||o.push({code:"tmux-error",message:`could not save crouter tmux ownership manifest: ${i.stderr}`}),{ok:!1,installed:c,diagnostics:o}}const E=u((i,a,d,m,k)=>{if($(i,a)!==null)return o.push({code:"occupied",bindingId:m,gesture:k,message:`${i}:${a} is already bound by tmux; ${m} was not installed`}),!1;const g=f(["bind-key","-T",i,C(a),...d]);return g.ok?(c.push({table:i,key:a}),!0):(o.push({code:"tmux-error",bindingId:m,gesture:k,message:`could not install ${m}: ${g.stderr}`}),!1)},"install"),P=F(r),H=N(" crtr ",K(r,P));for(const i of r.gestures("crtr.tmux.menu.open"))for(const a of v(i))E(p,a,H,"crtr.tmux.menu.open",i);for(const i of _){if(i.pair?.field!=="menu")continue;const a=_.find(y=>y.id===i.pair?.pairedId);if(a?.pair?.field!=="global")continue;const d=i.id,m=a.id,k=P.get(d),g=k===void 0?null:j(k.action);if(g===null)throw new Error(`no direct tmux action for paired menu binding ${d}`);for(const y of r.gestures(m))for(const J of v(y))E(p,J,g.argv,m,y)}for(const i of["crtr.tmux.node.next","crtr.tmux.node.previous","crtr.tmux.inbox.toggle"])for(const a of r.gestures(i))for(const d of v(a))E(p,d,ve(i),i,a);const L=[];for(const[i,a]of x){if(w.has(i))continue;const d=$(p,i);if(d===null)continue;const m=B(d);if(m===null||m.command===""){o.push({code:"tmux-error",bindingId:a.bindingId,gesture:a.gesture,message:`could not parse occupied tmux binding ${p}:${i}`});continue}const k=f(["bind-key",...m.repeat?["-r"]:[],"-T",p,C(i),"if-shell","-F","#{!=:#{@crtr_attach},}",`send-keys ${xe(i)}`,ye(m.command)]);if(!k.ok){o.push({code:"tmux-error",bindingId:a.bindingId,gesture:a.gesture,message:`could not wrap ${p}:${i}: ${k.stderr}`});continue}const g=$(p,i);if(g===null||!g.includes("@crtr_attach")){o.push({code:"tmux-error",bindingId:a.bindingId,gesture:a.gesture,message:`could not fingerprint wrapped tmux binding ${p}:${i}`});continue}const y={...a,key:i,original:d,wrapper:g,state:"owned"};I.push(y),L.push(y)}const D=W({pairs:c,wrappers:I});if(!D.ok){o.push({code:"tmux-error",message:`could not save crouter tmux ownership manifest: ${D.stderr}`});for(const i of L)$(p,i.key)===i.wrapper&&X(i)}return{ok:o.every(i=>i.code!=="tmux-error"),installed:c,diagnostics:o}}u(Ie,"reconcileTmuxBindings");export{Pe as crouterMenuTmuxArgs,we as inboxToggleTmuxCommand,De as installTmuxBindings,Le as occupiedTmuxRootGestures};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Fit the prose list into the total budget, shortening the oldest middle
|
|
2
|
+
* messages first: the first sets up the turn and the last carries the outcome. */
|
|
3
|
+
export declare function budgetProse(prose: readonly string[]): string[];
|
|
4
|
+
export declare function serializeTurn(userText: string, prose: readonly string[]): string;
|
|
5
|
+
/** Generate a consolidated reply, or null on every failure. */
|
|
6
|
+
export declare function headlessTurnReply(userText: string, prose: readonly string[]): Promise<string | null>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
var d=Object.defineProperty;var r=(s,e)=>d(s,"name",{value:e,configurable:!0});import{Type as l}from"@earendil-works/pi-ai";import{headlessToolCall as p}from"./headless-pi.js";import{defaultProvider as h,modelLadders as c}from"./model-selection.js";import{lightModel as g}from"./naming.js";const u=4e3,y=12e3,m=4e4,w=6e4,f="You rewrite a coding agent's several messages to a person into the ONE reply the agent would have sent had it known everything at the end. You receive only the person's message and the agent's messages in the order they were written. Rules: later statements supersede earlier ones \u2014 drop plans that were completed, guesses that were corrected, and status that went stale; keep decisions, results, numbers, document links like [[name]], file paths, commands, errors and open questions verbatim; never add anything the messages did not say; do not mention that this is a rewrite or that there were several messages; write as the agent, speaking to the person, in the agent's own tone and markdown; be as short as the content allows. Call submit_reply exactly once with the reply, then stop.",_=l.Object({text:l.String({minLength:1,description:"The single consolidated reply, in markdown."})},{additionalProperties:!1});function i(s,e){const n=s.trim();return n.length<=e?n:`${n.slice(0,Math.max(0,e-1)).trimEnd()}\u2026`}r(i,"capped");function P(s){const e=s.map(t=>i(t,y));let n=e.reduce((t,o)=>t+o.length,0);for(let t=1;t<e.length-1&&n>m;t+=1){const o=e[t].length,a=i(e[t],Math.max(200,o-(n-m)));e[t]=a,n-=o-a.length}return e}r(P,"budgetProse");function T(s,e){const n=s.trim()===""?"(the agent was started without a typed message)":i(s,u),t=P(e).map((o,a)=>`<agent-message n="${a+1}">
|
|
2
|
+
${o}
|
|
3
|
+
</agent-message>`);return`<person-message>
|
|
4
|
+
${n}
|
|
5
|
+
</person-message>
|
|
6
|
+
|
|
7
|
+
${t.join(`
|
|
8
|
+
|
|
9
|
+
`)}
|
|
10
|
+
|
|
11
|
+
Write the one consolidated reply.`}r(T,"serializeTurn");async function v(s,e){const n=c(),t=await p({systemPrompt:f,userPrompt:T(s,e),modelSpec:g(),modelIntent:`${h(n)}/light`,timeoutMs:w,tool:{name:"submit_reply",label:"Submit reply",description:"Submit the single consolidated reply exactly once, then stop.",parameters:_,constrainedSampling:!1}});if(typeof t!="object"||t===null)return null;const o=t.text;return typeof o=="string"&&o.trim()!==""?o.trim():null}r(v,"headlessTurnReply");export{P as budgetProse,v as headlessTurnReply,T as serializeTurn};
|
|
@@ -290,6 +290,21 @@ export declare const CONFIG_SETTINGS_COVERAGE: {
|
|
|
290
290
|
setFromString: (config: ScopeConfig, raw: string) => string | null;
|
|
291
291
|
};
|
|
292
292
|
};
|
|
293
|
+
consolidate_replies: {
|
|
294
|
+
surface: "settings";
|
|
295
|
+
setting: {
|
|
296
|
+
key: "consolidate_replies";
|
|
297
|
+
label: string;
|
|
298
|
+
description: string;
|
|
299
|
+
valueConstraint: string;
|
|
300
|
+
applies: string;
|
|
301
|
+
group: "display";
|
|
302
|
+
order: number;
|
|
303
|
+
format: (config: ScopeConfig) => "on" | "off";
|
|
304
|
+
cycle: (config: ScopeConfig) => void;
|
|
305
|
+
setFromString: (config: ScopeConfig, raw: string) => string | null;
|
|
306
|
+
};
|
|
307
|
+
};
|
|
293
308
|
keybindings: {
|
|
294
309
|
surface: "specialized";
|
|
295
310
|
owner: string;
|