@cerebriline/core 4.100.251 → 4.100.253

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.
@@ -52,6 +52,37 @@ export declare function reasoningHitBudget(thinking: string, budgetMessage?: str
52
52
  * repeating itself, which is why it stays a fixed number and not a share.
53
53
  */
54
54
  export declare const CONDENSED_THINKING_NOTE_TOKENS = 2000;
55
+ /**
56
+ * The note's length target: a tenth of the think it replaces, kept between
57
+ * 1,000 and 2,000 tokens (user ruling, 2026-10-18: "1k-2k if there's enough
58
+ * context/output available").
59
+ *
60
+ * The floor is the point. A note is asked for only when a think ran to its
61
+ * budget, and the notes measured so far were 250 to 450 tokens -- a hundredth
62
+ * of what they replaced, too little to carry the calls, the findings and what
63
+ * was set aside, so the next pass re-derived them.
64
+ */
65
+ export declare const CONDENSED_THINKING_NOTE_MIN_TOKENS = 1000;
66
+ /**
67
+ * How long a note to ask for, and the output cap that goes with it.
68
+ *
69
+ * The target comes from the think; the room only ever lowers it. With a
70
+ * window to fit, the condensation request and its cap must both be inside
71
+ * it, so the target steps down until they are -- to a short note rather than
72
+ * none, because a request that does not fit is refused either way. With no
73
+ * window known the target stands, and the server sizes the call as before.
74
+ */
75
+ export declare function resolveCondensedThinkingNoteTokens(options: {
76
+ thinkingChars: number;
77
+ /** The condensation request as it will be sent, in characters. */
78
+ requestChars: number;
79
+ /** The tokens the call has to fit in, when known. */
80
+ roomTokens?: number;
81
+ providerConfig: Partial<ProviderConfig>;
82
+ }): {
83
+ noteTokens: number;
84
+ maxTokens: number;
85
+ };
55
86
  /**
56
87
  * The cap the condensation request carries.
57
88
  *
@@ -95,8 +126,26 @@ export declare function isDegenerateNote(note: string): boolean;
95
126
  * user message: the same split the compaction summariser uses. It says what the
96
127
  * note is for; `DEFAULT_CAPPED_THINKING_PROMPT` says what it must contain.
97
128
  */
98
- export declare const CAPPED_THINKING_SYSTEM_PROMPT = "You are compressing a train of thought, in the voice of the person who was thinking it. What you write goes back into that same reasoning as its own continuation -- not as a report about it -- so write it the way thinking is written: first person, present tense, plain sentences, no headings and no lists. Keep every specific: paths, symbols, line numbers, error text, and above all what was already ruled out and why.";
99
- export declare const DEFAULT_CAPPED_THINKING_PROMPT = "You were reasoning about a problem and ran out of thinking budget mid-thought. Below is how far you got, and what the tool call you managed to make returned.\n\nRewrite that reasoning, compressed, as the thinking it is. It is going back into your own reasoning channel as the part you have already done, so that your next pass starts from here instead of starting over and arriving at this same point again.\n\nWrite it as thought, not as a report about thought:\n- First person, present tense, the way you were already thinking. No headings, no bullet lists, no preamble, no sign-off. Do not label it or announce what it is; just think.\n- Carry what you called and what it returned. Every tool call in this turn, by name, with the argument that mattered and what came back -- the file you read and what was at the line you were looking for, the edit you attempted and whether it applied, the command you ran and what it printed. A retrospective that omits this is the one thing the next pass cannot recover, because the results are not in front of it any more.\n- State what you have settled as settled. Do not re-derive it and do not hedge it.\n- Say what you ruled out and why, in a clause each. This is the part that stops the next pass repeating this one, and it is the part that gets dropped first if you are careless.\n- Long enough that none of the above is missing, short enough that none of it is padding. Length follows the content: a turn that made four calls and settled three questions is not a paragraph. If you find yourself restating a line you have already written, you are finished: stop.\n- End on the one question still open and the single next action, stated concretely.\n\nTwo things to keep out of it:\n- Do not copy file contents. Name the file and the line and say what you concluded about it. Quoted code goes stale the moment the file is edited, and reasoning that argues with the next tool result costs more than it saved.\n- Do not narrate the interruption. It is not part of the problem.";
129
+ export declare const CAPPED_THINKING_SYSTEM_PROMPT = "You are condensing a train of thought, in the voice of the person who is thinking it. What you write goes back into that same reasoning as the part of it already done, and is read as thinking, so write it the way thinking is written: first person, present continuous tense, plain prose, one thought after another. Keep every specific: paths, symbols, line numbers, error text, and what is set aside and why.";
130
+ /**
131
+ * What the note must contain, and the voice it is in.
132
+ *
133
+ * Built on the replay compaction prompt (`DEFAULT_REPLAY_COMPACTION_PROMPT`),
134
+ * the one that holds its voice: first person, present continuous, shapes to
135
+ * reuse, and its own labels in the tense it asks for. The version this
136
+ * replaces asked for "present tense" while framing everything in the past --
137
+ * "You were reasoning", "how far you got", "what you then called" -- forbade
138
+ * lists inside a bullet list, and ended on "Do not" lines. A prompt that
139
+ * disagrees with itself is read as an instruction that is optional, and a
140
+ * negative exemplar is still an exemplar. On pandorum the note it produced
141
+ * sent the next turn into a loop: re-reasoning the note rather than going on
142
+ * from it.
143
+ *
144
+ * The length is not in here. It is a target the request builder appends,
145
+ * sized to the think and the room (`resolveCondensedThinkingNoteTokens`), so a
146
+ * replacement prompt gets it too.
147
+ */
148
+ export declare const DEFAULT_CAPPED_THINKING_PROMPT = "Your thinking on this turn has reached its budget, and the reasoning below is about to be replaced by what you write now. Write the reasoning that takes its place.\n\nIt goes back into **your own thinking channel**, as the thinking you are in the middle of. Your next pass reads it as its own train of thought and carries on from the end of it, so write it the way you think: in the **first person, present continuous tense**, in plain prose, one thought after another, the same voice as the reasoning it replaces.\n\nWrite every step as the step itself, then what is coming back. These are the shapes \u2014 reuse them:\n\n- \"I'm working out why the collision check misses the left wall.\"\n- \"I'm reading `game.js` around line 274, and the bounds test there compares against `width` where it needs `width - size`.\"\n- \"I'm running `check_file` on it, and it is reporting an unterminated regular expression at line 274.\"\n- \"I'm setting the loop rewrite aside: the fault is in the bounds test, and the loop is sound.\"\n- \"The bounds test is the cause, so what I'm doing next is editing line 274.\"\n\nEvery sentence holds that voice, the middle as much as the first and the last.\n\nCarry all of this:\n\n- **What you are being asked to do**, in a sentence.\n- **Every tool call in this turn**, by name, with the argument that matters and what it is returning: the file and what is at the line you are looking at, the edit and whether it is applying, the command and what it is printing. These results are not in front of your next pass any more, so this is the only place they survive.\n- **What you are treating as settled**, stated as settled.\n- **What you are setting aside, and why**, a clause each. This is what keeps the next pass off ground this one has already covered.\n- **Where you are**, ending on the one question still open and the single next action, stated concretely.\n\nName files and lines and say what you are concluding about them; the files themselves are on disk, and the next tool result is what shows their current state.\n\nBegin with the problem itself and end on the next action.";
100
149
  interface ToolOutcome {
101
150
  name: string;
102
151
  input: string;
@@ -142,6 +191,8 @@ export declare function buildCappedThinkingRequest(options: {
142
191
  promptTemplate?: string;
143
192
  /** The reply the turn had begun writing before it was cut off. */
144
193
  partialAnswer?: string;
194
+ /** The note's length target, in tokens (`resolveCondensedThinkingNoteTokens`). */
195
+ noteTokens?: number;
145
196
  }): string;
146
197
  export interface CappedThinkingCondenserConfig {
147
198
  enabled?: boolean;
@@ -170,7 +221,10 @@ type PrepareTurnResult = {
170
221
  } | undefined;
171
222
  type PrepareTurn = (context: never) => PrepareTurnResult | Promise<PrepareTurnResult>;
172
223
  /** A request answered by the conversation itself, or `undefined` to decline. */
173
- type ConversationAsk = (systemPrompt: string, request: string, maxTokens: number, what: string) => Promise<string | undefined>;
224
+ type ConversationAsk = ((systemPrompt: string, request: string, maxTokens: number, what: string) => Promise<string | undefined>) & {
225
+ /** What the conversation's last request left of the window, when measured. */
226
+ roomTokens?: number;
227
+ };
174
228
  /**
175
229
  * The discarded turn's notes, asked of the conversation as its next turn
176
230
  * where that can be done (`DiscardedTurnInput.continueConversation`).
@@ -1 +1 @@
1
- import{createRequire as XQ}from"node:module";var YQ=XQ(import.meta.url);import{normalizePluginManifest as DQ}from"@cerebriline/shared";function P(Q=process){Q.once("disconnect",()=>Q.exit(0))}import{existsSync as _,readFileSync as O}from"node:fs";import{builtinModules as ZQ,createRequire as R}from"node:module";import{dirname as J,extname as I,isAbsolute as $Q,resolve as q}from"node:path";import{fileURLToPath as m}from"node:url";import{PLUGIN_FILE_EXTENSIONS as GQ}from"@cerebriline/shared";var d=J(m(import.meta.url)),KQ=R(import.meta.url),qQ=q(d,"..","..","..","..",".."),T=wQ(qQ),WQ=["@cerebriline/sdk","@cerebriline/agents","@cerebriline/core","@cerebriline/core/hub","@cerebriline/core/hub/daemon-entry","@cerebriline/core/telemetry","@cerebriline/llms","@cerebriline/llms/browser","@cerebriline/shared","@cerebriline/shared/automation","@cerebriline/shared/browser","@cerebriline/shared/storage","@cerebriline/shared/db","@cerebriline/shared/types"],k=new Set(ZQ.flatMap((Q)=>[Q,Q.replace(/^node:/,"")])),B=new Set(GQ),_Q=["development","node","import","require","default"];function wQ(Q){let U={},X={"@cerebriline/sdk":q(Q,"packages/sdk/src/index.ts"),"@cerebriline/agents":q(Q,"packages/agents/src/index.ts"),"@cerebriline/core":q(Q,"packages/core/src/index.ts"),"@cerebriline/llms":q(Q,"packages/llms/src/index.ts"),"@cerebriline/shared":q(Q,"packages/shared/src/index.ts"),"@cerebriline/shared/storage":q(Q,"packages/shared/src/storage/index.ts"),"@cerebriline/shared/db":q(Q,"packages/shared/src/db/index.ts")};for(let[Z,$]of Object.entries(X))if(_($))U[Z]=$;for(let Z of["agents","core","llms","shared"]){let $=q(Q,"packages",Z),G=q($,"package.json");if(!_(G))continue;try{let Y=JSON.parse(O(G,"utf8"));if(typeof Y.name!=="string"||!Y.exports)continue;if(typeof Y.exports==="string"){let K=q($,Y.exports);if(_(K))U[Y.name]=K;continue}if(typeof Y.exports!=="object")continue;for(let[K,A]of Object.entries(Y.exports)){let L=AQ($,A);if(!L)continue;let w=K==="."?Y.name:`${Y.name}/${K.replace(/^\.\//,"")}`;U[w]=L}}catch{}}return U}function AQ(Q,U){let X=v(U);if(!X)return null;let Z=u(Q,X);for(let $ of Z)if(_($))return $;return null}function v(Q,U=new Set){if(typeof Q==="string")return Q;if(!Q||typeof Q!=="object")return null;if(U.has(Q))return null;U.add(Q);let X=Q;for(let Z of _Q){let $=v(X[Z],U);if($)return $}return null}function u(Q,U){let X=U.replace(/^\.\//,""),Z=[q(Q,U)];if(X.startsWith("dist/")){let $=X.replace(/^dist\//,"src/").replace(/\.(mjs|cjs|js)$/,"");return[q(Q,`${$}.ts`),q(Q,`${$}.tsx`),q(Q,`${$}.mts`),q(Q,`${$}.cts`),...Z]}return Z}function LQ(Q){return Object.fromEntries(Object.entries(Q).sort(([U],[X])=>X.length-U.length))}function N(Q){return!(Q.startsWith(".")||Q.startsWith("/")||Q.startsWith("file:")||Q.startsWith("data:")||Q.startsWith("http:")||Q.startsWith("https:"))}function C(Q){if(Q.startsWith("@")){let[U,X]=Q.split("/",3);return X?`${U}/${X}`:Q}return Q.split("/",1)[0]??Q}function FQ(Q){let U=C(Q);if(Q===U)return".";return`.${Q.slice(U.length)}`}function c(Q){return C(Q).startsWith("@cline/")}function y(Q,U){let X=C(U),Z=J(Q);while(!0){let $=q(Z,"node_modules",X);if(_($)||_(q($,"package.json")))return!0;let G=q(Z,"..");if(G===Z)return!1;Z=G}}function h(Q){return b(Q)!==null}function b(Q){try{return KQ.resolve(Q)}catch{}return JQ(Q)}function JQ(Q){let U=C(Q),X=l(U);if(!X)return null;let Z=q(X,"package.json");try{let $=JSON.parse(O(Z,"utf8")),G=FQ(Q),Y=G==="."&&typeof $.exports==="string"?$.exports:$.exports&&typeof $.exports==="object"&&Object.hasOwn($.exports,G)?$.exports[G]:void 0,K=v(Y)??(G==="."&&typeof $.main==="string"?$.main:null);if(!K)return null;let A=q(X,K),L=[A,...u(X,K).filter((w)=>w!==A)];for(let w of L)if(_(w))return w;return null}catch{return null}}function zQ(){let Q=[d],U=process.env.CLINE_WRAPPER_PATH?.trim();if(U)Q.push(J(J(U)));let X=process.execPath?.trim();if(X)Q.push(J(X));return[...new Set(Q.map((Z)=>q(Z)))]}function CQ(Q,U){let X=Q;while(!0){let Z=q(X,"package.json");if(_(Z))try{if(JSON.parse(O(Z,"utf8")).name===U)return X}catch{}let $=q(X,"node_modules",U,"package.json");if(_($))return J($);let G=q(X,"..");if(G===X)return null;X=G}}function l(Q){for(let U of zQ()){let X=CQ(U,Q);if(X)return X}return null}function OQ(Q){let X=J(Q);for(let Z=0;Z<4;Z++){let $=q(X,"package.json");if(_($))try{let Y=JSON.parse(O($,"utf8"));return Y!=null&&typeof Y==="object"&&"cline"in Y}catch{return!1}let G=q(X,"..");if(G===X)return!1;X=G}return!1}function g(Q,U){let X=U.startsWith("file:")?m(U):$Q(U)?U:q(J(Q),U);if(_(X)&&B.has(I(X)))return X;for(let Z of B){let $=`${X}${Z}`;if(_($))return $}for(let Z of B){let $=q(X,`index${Z}`);if(_($))return $}return null}function n(Q){let U=new Set,X=[/\bimport\s+(?:type\s+)?[^"'`]*?\bfrom\s*["'`]([^"'`]+)["'`]/g,/\bexport\s+[^"'`]*?\bfrom\s*["'`]([^"'`]+)["'`]/g,/\bimport\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g,/\brequire\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g];for(let Z of X)for(let $ of Q.matchAll(Z)){let G=$[1];if(G)U.add(G)}return[...U]}function jQ(Q){return I(Q)!==".ts"}function o(Q,U,X=new Set){if(X.has(Q)||!_(Q))return;if(X.add(Q),!B.has(I(Q)))return;let Z=O(Q,"utf8"),$=jQ(Q);for(let G of n(Z)){if(G.startsWith("node:")||k.has(G))continue;if(N(G)){if(!$)continue;if(Object.hasOwn(T,G)||Object.hasOwn(T,C(G))||y(Q,G)||c(G)&&h(G)||U&&h(G))continue;throw Error(`Cannot find module '${C(G)}'`)}let Y=g(Q,G);if(Y)o(Y,U,X)}}function p(Q,U=new Set,X=new Set){if(U.has(Q)||!_(Q))return X;if(U.add(Q),!B.has(I(Q)))return X;let Z=O(Q,"utf8");for(let $ of n(Z)){if(X.add($),N($))continue;let G=g(Q,$);if(G)p(G,U,X)}return X}function BQ(Q,U){let X=R(Q),Z={},$=p(Q),G=new Set(WQ);for(let[Y,K]of Object.entries(T)){try{X.resolve(Y);continue}catch{}Z[Y]=K}for(let Y of $)if(N(Y)&&(c(Y)||U))G.add(Y);for(let Y of G){if(Object.hasOwn(Z,Y)||y(Q,Y))continue;let K=b(Y);if(K)Z[Y]=K}if(!U)return Z;for(let Y of $){if(!N(Y)||Object.hasOwn(Z,Y)||y(Q,Y)||Y.startsWith("node:")||k.has(Y))continue;let K=b(Y);if(K)Z[Y]=K}return Z}function IQ(Q){let U=I(Q);return U===".ts"||U===".tsx"||U===".mts"||U===".cts"}var z;function HQ(){if(z!==void 0)return z;let Q=l("jiti");if(!Q)return z=null,null;let U=q(Q,"dist","babel.cjs");if(!_(U))return z=null,null;try{let Z=R(U)(U);z=typeof Z==="function"?Z:null}catch{z=null}return z}async function s(Q,U={}){let X=!OQ(Q);o(Q,X);let Z=BQ(Q,X),$=LQ(Z),G=await import("jiti"),Y=typeof G==="function"?G:typeof G.default==="function"?G.default:void 0;if(!Y)throw Error("Unable to load jiti");let K=Object.entries($).filter(([,W])=>IQ(W)).map(([W])=>W),A=HQ(),L=A?(W)=>A({...W,interopDefault:!0}):void 0;return await Y(Q,{alias:$,cache:U.useCache,requireCache:U.useCache,esmResolve:!0,interopDefault:!1,nativeModules:[...k],transformModules:K,tryNative:!1,...L?{transform:L}:{}}).import(Q,{})}function i(Q,U){if(!Q)return!0;if(Q.providerIds?.length){if(!U?.providerId||!Q.providerIds.includes(U.providerId))return!1}if(Q.modelIds?.length){if(!U?.modelId||!Q.modelIds.includes(U.modelId))return!1}return!0}function F(Q){return typeof Q==="object"&&Q!==null}function r(Q){return Array.isArray(Q)&&Q.every((U)=>typeof U==="string")}function NQ(Q,U){if(!F(Q))throw Error(`Invalid plugin module: ${U}`);if(typeof Q.name!=="string"||!Q.name)throw Error(`Invalid plugin name: ${U}`);if(!F(Q.manifest))throw Error(`Invalid plugin manifest: ${U}`);if(Object.hasOwn(Q.manifest,"providerIds")&&!r(Q.manifest.providerIds))throw Error(`Invalid plugin manifest.providerIds: ${U}`);if(Object.hasOwn(Q.manifest,"modelIds")&&!r(Q.manifest.modelIds))throw Error(`Invalid plugin manifest.modelIds: ${U}`)}function SQ(Q){if(!F(Q))throw Error("Plugin setup context must be an object");if(Q.session!==void 0&&!F(Q.session))throw Error("Plugin setup context session must be an object");if(Q.client!==void 0&&!F(Q.client))throw Error("Plugin setup context client must be an object");if(Q.user!==void 0&&!F(Q.user))throw Error("Plugin setup context user must be an object");if(Q.workspaceInfo!==void 0&&!F(Q.workspaceInfo))throw Error("Plugin setup context workspaceInfo must be an object");if(Q.automation!==void 0&&!F(Q.automation))throw Error("Plugin setup context automation must be an object");if(Q.automation!==void 0&&typeof Q.automation.ingestEvent!=="function")throw Error("Plugin setup context automation.ingestEvent must be a function");if(Q.logger!==void 0&&!F(Q.logger))throw Error("Plugin setup context logger must be an object")}var t=0,S=new Map,f=new Map;function MQ(Q){let U=Q instanceof Error?Q.message:String(Q),X=Q instanceof Error?Q.stack:void 0;return{message:U,stack:X}}function x(Q,U,X,Z){if(!process.send)return;process.send({type:"response",id:Q,ok:U,result:X,error:Z})}function V(Q,U){if(!process.send)return;process.send({type:"event",name:Q,payload:U})}globalThis.__clinePluginHost={emitEvent:V};globalThis.__clineSessionEnv={cwd:void 0,workspaceInfo:void 0};function a(Q){if(!Q||typeof Q!=="object")return{};return Q}function M(Q){if(!Q||typeof Q!=="object")return;let U={...Q};if(U.error instanceof Error)U.error={name:U.error.name,message:U.error.message,stack:U.error.stack};return U}function VQ(Q){let U=(X,Z,$)=>{V("plugin_log",{level:X,pluginName:Q,message:Z,metadata:M($)})};return{debug:(X,Z)=>U("debug",X,Z),log:(X,Z)=>U("log",X,Z),error:(X,Z)=>U("error",X,Z)}}function EQ(Q){let U=($)=>{V("plugin_telemetry",{pluginName:Q,...$})},X=($)=>(G,Y,K,A,L)=>{U({kind:"metric",metric:$,name:G,value:Y,attributes:M(K),description:A,required:L})},Z=()=>{};return{capture:($)=>{U({kind:"event",event:$?.event,properties:M($?.properties)})},captureRequired:($,G)=>{U({kind:"event",event:$,properties:M(G),required:!0})},recordCounter:X("counter"),recordHistogram:X("histogram"),recordGauge:X("gauge"),isEnabled:()=>!0,setDistinctId:Z,setMetadata:Z,updateMetadata:Z,setCommonProperties:Z,updateCommonProperties:Z,flush:async()=>{},dispose:async()=>{}}}function j(Q,U){let X=`${Q}:${U}`,Z=(f.get(X)??0)+1;return f.set(X,Z),`${Q}_${U}_${Z}`}function TQ(Q){let U=typeof Q.eventType==="string"?Q.eventType.trim():"",X=typeof Q.source==="string"?Q.source.trim():"";if(!U)throw Error("Automation event type contribution requires eventType");if(!X)throw Error("Automation event type contribution requires source");return{...Q,eventType:U,source:X,examples:Q.examples?[...Q.examples]:void 0,metadata:Q.metadata?a(Q.metadata):void 0}}function H(Q){let U=S.get(Q);if(!U)throw Error(`Unknown sandbox plugin id: ${Q}`);return U}async function yQ(Q){let U;try{let X=await s(Q.pluginPath);if(U=X.default??X[Q.exportName],NQ(U,Q.pluginPath),U.manifest=DQ(U.manifest),!i(U.manifest,Q.targeting))return{type:"skipped"};let Z={tools:[],commands:[],rules:[],messageBuilders:[],providers:[],automationEventTypes:[],mcpServers:[],shortcuts:[],flags:[]},$={tools:new Map,commands:new Map,rules:new Map,messageBuilders:new Map},G={registerTool:(Y)=>{let K=j(Q.pluginId,"tool");$.tools.set(K,Y.execute),Z.tools.push({id:K,name:Y.name,description:Y.description,inputSchema:Y.inputSchema,timeoutMs:Y.timeoutMs,retryable:Y.retryable})},registerCommand:(Y)=>{let K=j(Q.pluginId,"command");if(typeof Y.handler==="function")$.commands.set(K,Y.handler);Z.commands.push({id:K,name:Y.name,description:Y.description})},registerRule:(Y)=>{let K=j(Q.pluginId,"rule");if(typeof Y.content==="function"){$.rules.set(K,Y.content),Z.rules.push({id:K,ruleId:Y.id,source:Y.source,hasContentHandler:!0});return}Z.rules.push({id:K,ruleId:Y.id,content:Y.content,source:Y.source})},registerMessageBuilder:(Y)=>{let K=j(Q.pluginId,"builder");$.messageBuilders.set(K,Y.build),Z.messageBuilders.push({id:K,name:Y.name})},registerProvider:(Y)=>{Z.providers.push({id:j(Q.pluginId,"provider"),name:Y.name,description:Y.description,metadata:a(Y.metadata)})},registerAutomationEventType:(Y)=>{Z.automationEventTypes.push({id:j(Q.pluginId,"automation_event"),...TQ(Y)})},registerMcpServer:(Y)=>{Z.mcpServers.push(Y)}};if(typeof U.setup==="function")try{let Y={...Q.setupCtxBase,...Q.telemetryEnabled?{telemetry:EQ(U.name)}:{},...Q.loggerEnabled?{logger:VQ(U.name)}:{},...U.manifest.capabilities.includes("automationEvents")?{automation:{ingestEvent:(K)=>{V("automation_event",K)}}}:{}};SQ(Y),await U.setup(G,Y)}catch(Y){return{type:"failure",failure:{pluginPath:Q.pluginPath,pluginName:U.name,phase:"setup",message:Y instanceof Error?Y.message:String(Y),stack:Y instanceof Error?Y.stack:void 0}}}return{type:"loaded",state:{plugin:U,handlers:$},descriptor:{pluginId:Q.pluginId,pluginPath:Q.pluginPath,name:U.name,manifest:U.manifest,hooks:U.hooks?Object.entries(U.hooks).filter(([,Y])=>typeof Y==="function").map(([Y])=>Y):void 0,contributions:Z}}}catch(X){return{type:"failure",failure:{pluginPath:Q.pluginPath,pluginName:U?.name,phase:"load",message:X instanceof Error?X.message:String(X),stack:X instanceof Error?X.stack:void 0}}}}async function bQ(Q){if(S.clear(),t=0,f.clear(),Q.cwd)try{process.chdir(Q.cwd)}catch{}let U=globalThis.__clineSessionEnv;if(U)U.cwd=Q.cwd,U.workspaceInfo=Q.workspaceInfo;let X=[],Z=[],$=[],G=Q.exportName||"plugin",Y=new Map,K={providerId:Q.providerId,modelId:Q.modelId},A={session:Q.session,client:Q.client,user:Q.user,workspaceInfo:Q.workspaceInfo},L=await Promise.all((Q.pluginPaths||[]).map((w)=>{let W=`plugin_${++t}`;return yQ({pluginPath:w,pluginId:W,exportName:G,targeting:K,setupCtxBase:A,loggerEnabled:Q.loggerEnabled,telemetryEnabled:Q.telemetryEnabled})}));for(let w of L){if(w.type==="skipped")continue;if(w.type==="failure"){Z.push(w.failure);continue}let{descriptor:W,state:e}=w,E=Y.get(W.name);if(E!==void 0){let D=X[E];if(!D)Y.delete(W.name);else{$.push({type:"duplicate_plugin_override",pluginName:W.name,pluginPath:W.pluginPath,overriddenPluginPath:D.pluginPath,message:`Plugin "${W.name}" from ${W.pluginPath} overrides ${D.pluginPath}`}),S.delete(D.pluginId),X.splice(E,1),Y.clear();for(let[QQ,UQ]of X.entries())Y.set(UQ.name,QQ)}}S.set(W.pluginId,e),Y.set(W.name,X.length),X.push(W)}return{plugins:X,failures:Z,warnings:$}}async function RQ(Q){let X=H(Q.pluginId).plugin.hooks?.[Q.hookName];if(typeof X!=="function")return;return await X(Q.payload)}async function kQ(Q){let X=H(Q.pluginId).handlers.tools.get(Q.contributionId);if(typeof X!=="function")throw Error("Unknown sandbox tool contribution");return await X(Q.input,Q.context)}async function vQ(Q){let X=H(Q.pluginId).handlers.commands.get(Q.contributionId);if(typeof X!=="function")return"";return await X(Q.input)}async function xQ(Q){let X=H(Q.pluginId).handlers.messageBuilders.get(Q.contributionId);if(typeof X!=="function")return[];return await X(Q.messages)}async function fQ(Q){let X=H(Q.pluginId).handlers.rules.get(Q.contributionId);if(typeof X!=="function")return"";return await X()}var PQ={initialize:bQ,invokeHook:RQ,executeTool:kQ,executeCommand:vQ,buildMessages:xQ,resolveRuleContent:fQ};P();process.on("message",async(Q)=>{if(!Q||Q.type!=="call")return;let U=PQ[Q.method];if(!U){x(Q.id,!1,void 0,{message:`Unknown method: ${String(Q.method)}`});return}try{let X=await U(Q.args||{});x(Q.id,!0,X)}catch(X){x(Q.id,!1,void 0,MQ(X))}});
1
+ import{normalizePluginManifest as In}from"@cerebriline/shared";function B(n=process){n.once("disconnect",()=>n.exit(0))}import{existsSync as l,readFileSync as k}from"node:fs";import{builtinModules as rn,createRequire as _}from"node:module";import{dirname as m,extname as v,isAbsolute as on,resolve as u}from"node:path";import{fileURLToPath as z}from"node:url";import{PLUGIN_FILE_EXTENSIONS as sn}from"@cerebriline/shared";var J=m(z(import.meta.url)),an=_(import.meta.url),un=u(J,"..","..","..","..",".."),T=dn(un),cn=["@cerebriline/sdk","@cerebriline/agents","@cerebriline/core","@cerebriline/core/hub","@cerebriline/core/hub/daemon-entry","@cerebriline/core/telemetry","@cerebriline/llms","@cerebriline/llms/browser","@cerebriline/shared","@cerebriline/shared/automation","@cerebriline/shared/browser","@cerebriline/shared/storage","@cerebriline/shared/db","@cerebriline/shared/types"],O=new Set(rn.flatMap((n)=>[n,n.replace(/^node:/,"")])),b=new Set(sn),ln=["development","node","import","require","default"];function dn(n){let e={},t={"@cerebriline/sdk":u(n,"packages/sdk/src/index.ts"),"@cerebriline/agents":u(n,"packages/agents/src/index.ts"),"@cerebriline/core":u(n,"packages/core/src/index.ts"),"@cerebriline/llms":u(n,"packages/llms/src/index.ts"),"@cerebriline/shared":u(n,"packages/shared/src/index.ts"),"@cerebriline/shared/storage":u(n,"packages/shared/src/storage/index.ts"),"@cerebriline/shared/db":u(n,"packages/shared/src/db/index.ts")};for(let[i,o]of Object.entries(t))if(l(o))e[i]=o;for(let i of["agents","core","llms","shared"]){let o=u(n,"packages",i),s=u(o,"package.json");if(!l(s))continue;try{let r=JSON.parse(k(s,"utf8"));if(typeof r.name!=="string"||!r.exports)continue;if(typeof r.exports==="string"){let a=u(o,r.exports);if(l(a))e[r.name]=a;continue}if(typeof r.exports!=="object")continue;for(let[a,g]of Object.entries(r.exports)){let p=gn(o,g);if(!p)continue;let d=a==="."?r.name:`${r.name}/${a.replace(/^\.\//,"")}`;e[d]=p}}catch{}}return e}function gn(n,e){let t=A(e);if(!t)return null;let i=H(n,t);for(let o of i)if(l(o))return o;return null}function A(n,e=new Set){if(typeof n==="string")return n;if(!n||typeof n!=="object")return null;if(e.has(n))return null;e.add(n);let t=n;for(let i of ln){let o=A(t[i],e);if(o)return o}return null}function H(n,e){let t=e.replace(/^\.\//,""),i=[u(n,e)];if(t.startsWith("dist/")){let o=t.replace(/^dist\//,"src/").replace(/\.(mjs|cjs|js)$/,"");return[u(n,`${o}.ts`),u(n,`${o}.tsx`),u(n,`${o}.mts`),u(n,`${o}.cts`),...i]}return i}function pn(n){return Object.fromEntries(Object.entries(n).sort(([e],[t])=>t.length-e.length))}function E(n){return!(n.startsWith(".")||n.startsWith("/")||n.startsWith("file:")||n.startsWith("data:")||n.startsWith("http:")||n.startsWith("https:"))}function h(n){if(n.startsWith("@")){let[e,t]=n.split("/",3);return t?`${e}/${t}`:n}return n.split("/",1)[0]??n}function fn(n){let e=h(n);if(n===e)return".";return`.${n.slice(e.length)}`}function L(n){return h(n).startsWith("@cline/")}function C(n,e){let t=h(e),i=m(n);while(!0){let o=u(i,"node_modules",t);if(l(o)||l(u(o,"package.json")))return!0;let s=u(i,"..");if(s===i)return!1;i=s}}function W(n){return j(n)!==null}function j(n){try{return an.resolve(n)}catch{}return mn(n)}function mn(n){let e=h(n),t=q(e);if(!t)return null;let i=u(t,"package.json");try{let o=JSON.parse(k(i,"utf8")),s=fn(n),r=s==="."&&typeof o.exports==="string"?o.exports:o.exports&&typeof o.exports==="object"&&Object.hasOwn(o.exports,s)?o.exports[s]:void 0,a=A(r)??(s==="."&&typeof o.main==="string"?o.main:null);if(!a)return null;let g=u(t,a),p=[g,...H(t,a).filter((d)=>d!==g)];for(let d of p)if(l(d))return d;return null}catch{return null}}function wn(){let n=[J],e=process.env.CLINE_WRAPPER_PATH?.trim();if(e)n.push(m(m(e)));let t=process.execPath?.trim();if(t)n.push(m(t));return[...new Set(n.map((i)=>u(i)))]}function hn(n,e){let t=n;while(!0){let i=u(t,"package.json");if(l(i))try{if(JSON.parse(k(i,"utf8")).name===e)return t}catch{}let o=u(t,"node_modules",e,"package.json");if(l(o))return m(o);let s=u(t,"..");if(s===t)return null;t=s}}function q(n){for(let e of wn()){let t=hn(e,n);if(t)return t}return null}function kn(n){let t=m(n);for(let i=0;i<4;i++){let o=u(t,"package.json");if(l(o))try{let r=JSON.parse(k(o,"utf8"));return r!=null&&typeof r==="object"&&"cline"in r}catch{return!1}let s=u(t,"..");if(s===t)return!1;t=s}return!1}function F(n,e){let t=e.startsWith("file:")?z(e):on(e)?e:u(m(n),e);if(l(t)&&b.has(v(t)))return t;for(let i of b){let o=`${t}${i}`;if(l(o))return o}for(let i of b){let o=u(t,`index${i}`);if(l(o))return o}return null}function U(n){let e=new Set,t=[/\bimport\s+(?:type\s+)?[^"'`]*?\bfrom\s*["'`]([^"'`]+)["'`]/g,/\bexport\s+[^"'`]*?\bfrom\s*["'`]([^"'`]+)["'`]/g,/\bimport\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g,/\brequire\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g];for(let i of t)for(let o of n.matchAll(i)){let s=o[1];if(s)e.add(s)}return[...e]}function Pn(n){return v(n)!==".ts"}function X(n,e,t=new Set){if(t.has(n)||!l(n))return;if(t.add(n),!b.has(v(n)))return;let i=k(n,"utf8"),o=Pn(n);for(let s of U(i)){if(s.startsWith("node:")||O.has(s))continue;if(E(s)){if(!o)continue;if(Object.hasOwn(T,s)||Object.hasOwn(T,h(s))||C(n,s)||L(s)&&W(s)||e&&W(s))continue;throw Error(`Cannot find module '${h(s)}'`)}let r=F(n,s);if(r)X(r,e,t)}}function G(n,e=new Set,t=new Set){if(e.has(n)||!l(n))return t;if(e.add(n),!b.has(v(n)))return t;let i=k(n,"utf8");for(let o of U(i)){if(t.add(o),E(o))continue;let s=F(n,o);if(s)G(s,e,t)}return t}function bn(n,e){let t=_(n),i={},o=G(n),s=new Set(cn);for(let[r,a]of Object.entries(T)){try{t.resolve(r);continue}catch{}i[r]=a}for(let r of o)if(E(r)&&(L(r)||e))s.add(r);for(let r of s){if(Object.hasOwn(i,r)||C(n,r))continue;let a=j(r);if(a)i[r]=a}if(!e)return i;for(let r of o){if(!E(r)||Object.hasOwn(i,r)||C(n,r)||r.startsWith("node:")||O.has(r))continue;let a=j(r);if(a)i[r]=a}return i}function vn(n){let e=v(n);return e===".ts"||e===".tsx"||e===".mts"||e===".cts"}var w;function yn(){if(w!==void 0)return w;let n=q("jiti");if(!n)return w=null,null;let e=u(n,"dist","babel.cjs");if(!l(e))return w=null,null;try{let i=_(e)(e);w=typeof i==="function"?i:null}catch{w=null}return w}async function K(n,e={}){let t=!kn(n);X(n,t);let i=bn(n,t),o=pn(i),s=await import("jiti"),r=typeof s==="function"?s:typeof s.default==="function"?s.default:void 0;if(!r)throw Error("Unable to load jiti");let a=Object.entries(o).filter(([,c])=>vn(c)).map(([c])=>c),g=yn(),p=g?(c)=>g({...c,interopDefault:!0}):void 0;return await r(n,{alias:o,cache:e.useCache,requireCache:e.useCache,esmResolve:!0,interopDefault:!1,nativeModules:[...O],transformModules:a,tryNative:!1,...p?{transform:p}:{}}).import(n,{})}function Y(n,e){if(!n)return!0;if(n.providerIds?.length){if(!e?.providerId||!n.providerIds.includes(e.providerId))return!1}if(n.modelIds?.length){if(!e?.modelId||!n.modelIds.includes(e.modelId))return!1}return!0}function f(n){return typeof n==="object"&&n!==null}function Q(n){return Array.isArray(n)&&n.every((e)=>typeof e==="string")}function En(n,e){if(!f(n))throw Error(`Invalid plugin module: ${e}`);if(typeof n.name!=="string"||!n.name)throw Error(`Invalid plugin name: ${e}`);if(!f(n.manifest))throw Error(`Invalid plugin manifest: ${e}`);if(Object.hasOwn(n.manifest,"providerIds")&&!Q(n.manifest.providerIds))throw Error(`Invalid plugin manifest.providerIds: ${e}`);if(Object.hasOwn(n.manifest,"modelIds")&&!Q(n.manifest.modelIds))throw Error(`Invalid plugin manifest.modelIds: ${e}`)}function Rn(n){if(!f(n))throw Error("Plugin setup context must be an object");if(n.session!==void 0&&!f(n.session))throw Error("Plugin setup context session must be an object");if(n.client!==void 0&&!f(n.client))throw Error("Plugin setup context client must be an object");if(n.user!==void 0&&!f(n.user))throw Error("Plugin setup context user must be an object");if(n.workspaceInfo!==void 0&&!f(n.workspaceInfo))throw Error("Plugin setup context workspaceInfo must be an object");if(n.automation!==void 0&&!f(n.automation))throw Error("Plugin setup context automation must be an object");if(n.automation!==void 0&&typeof n.automation.ingestEvent!=="function")throw Error("Plugin setup context automation.ingestEvent must be a function");if(n.logger!==void 0&&!f(n.logger))throw Error("Plugin setup context logger must be an object")}var V=0,R=new Map,N=new Map;function Sn(n){let e=n instanceof Error?n.message:String(n),t=n instanceof Error?n.stack:void 0;return{message:e,stack:t}}function D(n,e,t,i){if(!process.send)return;process.send({type:"response",id:n,ok:e,result:t,error:i})}function x(n,e){if(!process.send)return;process.send({type:"event",name:n,payload:e})}globalThis.__clinePluginHost={emitEvent:x};globalThis.__clineSessionEnv={cwd:void 0,workspaceInfo:void 0};function Z(n){if(!n||typeof n!=="object")return{};return n}function S(n){if(!n||typeof n!=="object")return;let e={...n};if(e.error instanceof Error)e.error={name:e.error.name,message:e.error.message,stack:e.error.stack};return e}function xn(n){let e=(t,i,o)=>{x("plugin_log",{level:t,pluginName:n,message:i,metadata:S(o)})};return{debug:(t,i)=>e("debug",t,i),log:(t,i)=>e("log",t,i),error:(t,i)=>e("error",t,i)}}function Mn(n){let e=(o)=>{x("plugin_telemetry",{pluginName:n,...o})},t=(o)=>(s,r,a,g,p)=>{e({kind:"metric",metric:o,name:s,value:r,attributes:S(a),description:g,required:p})},i=()=>{};return{capture:(o)=>{e({kind:"event",event:o?.event,properties:S(o?.properties)})},captureRequired:(o,s)=>{e({kind:"event",event:o,properties:S(s),required:!0})},recordCounter:t("counter"),recordHistogram:t("histogram"),recordGauge:t("gauge"),isEnabled:()=>!0,setDistinctId:i,setMetadata:i,updateMetadata:i,setCommonProperties:i,updateCommonProperties:i,flush:async()=>{},dispose:async()=>{}}}function P(n,e){let t=`${n}:${e}`,i=(N.get(t)??0)+1;return N.set(t,i),`${n}_${e}_${i}`}function Tn(n){let e=typeof n.eventType==="string"?n.eventType.trim():"",t=typeof n.source==="string"?n.source.trim():"";if(!e)throw Error("Automation event type contribution requires eventType");if(!t)throw Error("Automation event type contribution requires source");return{...n,eventType:e,source:t,examples:n.examples?[...n.examples]:void 0,metadata:n.metadata?Z(n.metadata):void 0}}function y(n){let e=R.get(n);if(!e)throw Error(`Unknown sandbox plugin id: ${n}`);return e}async function Cn(n){let e;try{let t=await K(n.pluginPath);if(e=t.default??t[n.exportName],En(e,n.pluginPath),e.manifest=In(e.manifest),!Y(e.manifest,n.targeting))return{type:"skipped"};let i={tools:[],commands:[],rules:[],messageBuilders:[],providers:[],automationEventTypes:[],mcpServers:[],shortcuts:[],flags:[]},o={tools:new Map,commands:new Map,rules:new Map,messageBuilders:new Map},s={registerTool:(r)=>{let a=P(n.pluginId,"tool");o.tools.set(a,r.execute),i.tools.push({id:a,name:r.name,description:r.description,inputSchema:r.inputSchema,timeoutMs:r.timeoutMs,retryable:r.retryable})},registerCommand:(r)=>{let a=P(n.pluginId,"command");if(typeof r.handler==="function")o.commands.set(a,r.handler);i.commands.push({id:a,name:r.name,description:r.description})},registerRule:(r)=>{let a=P(n.pluginId,"rule");if(typeof r.content==="function"){o.rules.set(a,r.content),i.rules.push({id:a,ruleId:r.id,source:r.source,hasContentHandler:!0});return}i.rules.push({id:a,ruleId:r.id,content:r.content,source:r.source})},registerMessageBuilder:(r)=>{let a=P(n.pluginId,"builder");o.messageBuilders.set(a,r.build),i.messageBuilders.push({id:a,name:r.name})},registerProvider:(r)=>{i.providers.push({id:P(n.pluginId,"provider"),name:r.name,description:r.description,metadata:Z(r.metadata)})},registerAutomationEventType:(r)=>{i.automationEventTypes.push({id:P(n.pluginId,"automation_event"),...Tn(r)})},registerMcpServer:(r)=>{i.mcpServers.push(r)}};if(typeof e.setup==="function")try{let r={...n.setupCtxBase,...n.telemetryEnabled?{telemetry:Mn(e.name)}:{},...n.loggerEnabled?{logger:xn(e.name)}:{},...e.manifest.capabilities.includes("automationEvents")?{automation:{ingestEvent:(a)=>{x("automation_event",a)}}}:{}};Rn(r),await e.setup(s,r)}catch(r){return{type:"failure",failure:{pluginPath:n.pluginPath,pluginName:e.name,phase:"setup",message:r instanceof Error?r.message:String(r),stack:r instanceof Error?r.stack:void 0}}}return{type:"loaded",state:{plugin:e,handlers:o},descriptor:{pluginId:n.pluginId,pluginPath:n.pluginPath,name:e.name,manifest:e.manifest,hooks:e.hooks?Object.entries(e.hooks).filter(([,r])=>typeof r==="function").map(([r])=>r):void 0,contributions:i}}}catch(t){return{type:"failure",failure:{pluginPath:n.pluginPath,pluginName:e?.name,phase:"load",message:t instanceof Error?t.message:String(t),stack:t instanceof Error?t.stack:void 0}}}}async function jn(n){if(R.clear(),V=0,N.clear(),n.cwd)try{process.chdir(n.cwd)}catch{}let e=globalThis.__clineSessionEnv;if(e)e.cwd=n.cwd,e.workspaceInfo=n.workspaceInfo;let t=[],i=[],o=[],s=n.exportName||"plugin",r=new Map,a={providerId:n.providerId,modelId:n.modelId},g={session:n.session,client:n.client,user:n.user,workspaceInfo:n.workspaceInfo},p=await Promise.all((n.pluginPaths||[]).map((d)=>{let c=`plugin_${++V}`;return Cn({pluginPath:d,pluginId:c,exportName:s,targeting:a,setupCtxBase:g,loggerEnabled:n.loggerEnabled,telemetryEnabled:n.telemetryEnabled})}));for(let d of p){if(d.type==="skipped")continue;if(d.type==="failure"){i.push(d.failure);continue}let{descriptor:c,state:nn}=d,M=r.get(c.name);if(M!==void 0){let I=t[M];if(!I)r.delete(c.name);else{o.push({type:"duplicate_plugin_override",pluginName:c.name,pluginPath:c.pluginPath,overriddenPluginPath:I.pluginPath,message:`Plugin "${c.name}" from ${c.pluginPath} overrides ${I.pluginPath}`}),R.delete(I.pluginId),t.splice(M,1),r.clear();for(let[en,tn]of t.entries())r.set(tn.name,en)}}R.set(c.pluginId,nn),r.set(c.name,t.length),t.push(c)}return{plugins:t,failures:i,warnings:o}}async function _n(n){let t=y(n.pluginId).plugin.hooks?.[n.hookName];if(typeof t!=="function")return;return await t(n.payload)}async function On(n){let t=y(n.pluginId).handlers.tools.get(n.contributionId);if(typeof t!=="function")throw Error("Unknown sandbox tool contribution");return await t(n.input,n.context)}async function An(n){let t=y(n.pluginId).handlers.commands.get(n.contributionId);if(typeof t!=="function")return"";return await t(n.input)}async function Dn(n){let t=y(n.pluginId).handlers.messageBuilders.get(n.contributionId);if(typeof t!=="function")return[];return await t(n.messages)}async function Nn(n){let t=y(n.pluginId).handlers.rules.get(n.contributionId);if(typeof t!=="function")return"";return await t()}var Bn={initialize:jn,invokeHook:_n,executeTool:On,executeCommand:An,buildMessages:Dn,resolveRuleContent:Nn};B();process.on("message",async(n)=>{if(!n||n.type!=="call")return;let e=Bn[n.method];if(!e){D(n.id,!1,void 0,{message:`Unknown method: ${String(n.method)}`});return}try{let t=await e(n.args||{});D(n.id,!0,t)}catch(t){D(n.id,!1,void 0,Sn(t))}});
@@ -117,5 +117,5 @@ export declare function findScriptSyntaxError(filePath: string, text: string): s
117
117
  * useful to say — the file's language is not one this understands, or its
118
118
  * delimiters match.
119
119
  */
120
- export declare function describeDelimiterBalance(filePath: string, text: string): string | null;
120
+ export declare function describeDelimiterBalance(filePath: string, withBom: string): string | null;
121
121
  export {};
@@ -8,6 +8,7 @@
8
8
  import type { AgentOverlay } from "../../../runtime/sandbox/overlay-fs";
9
9
  import type { ApplyPatchExecutor } from "../types";
10
10
  import { PatchActionType } from "./apply-patch-parser";
11
+ import { type ReadReceipts } from "./read-receipts";
11
12
  export interface PatchFileChange {
12
13
  type: PatchActionType;
13
14
  oldContent?: string;
@@ -31,6 +32,13 @@ export interface ApplyPatchExecutorOptions {
31
32
  restrictToCwd?: boolean;
32
33
  /** A delegated agent's overlay; the patch reads and writes the agent's copies. */
33
34
  overlay?: AgentOverlay;
35
+ /**
36
+ * The registry `read_files` and `editor` share. A patch is this session's
37
+ * own write, and has to be recorded as one: without it the next read said
38
+ * the file "changed since you last looked at it, and not because of
39
+ * anything you did", and the next edit was refused with the same words.
40
+ */
41
+ receipts?: ReadReceipts;
34
42
  }
35
43
  /**
36
44
  * Parse a patch and compute the per-file changes it would apply, without
@@ -0,0 +1,18 @@
1
+ /**
2
+ * A UTF-8 byte order mark at the start of a file, kept out of every column.
3
+ *
4
+ * VS Code drops the mark from a document's text, so the language server's
5
+ * diagnostics -- the line and column `check_file` reports -- number line 1
6
+ * without it, and the model never sees an invisible character it could count.
7
+ * The editor and the delimiter scan counted it as column 1, so on line 1 of
8
+ * such a file every column they named or accepted was one off from the
9
+ * checker's: "column 3" deleted the character before the one meant.
10
+ *
11
+ * Every tool that shows a file or addresses it by column strips the mark,
12
+ * and every tool that writes puts it back, so the file keeps its encoding.
13
+ */
14
+ export declare const BOM = "\uFEFF";
15
+ export declare function splitBom(text: string): {
16
+ bom: string;
17
+ body: string;
18
+ };
@@ -101,6 +101,17 @@ export interface ReadWindow {
101
101
  text: string;
102
102
  firstLine: number;
103
103
  lastLine: number;
104
+ /**
105
+ * Lines longer than `grep` prints, and how much of each was shown: up to
106
+ * `shown` of their `length` characters, all of it unless cut here.
107
+ */
108
+ cuts?: readonly {
109
+ line: number;
110
+ shown: number;
111
+ length: number;
112
+ }[];
113
+ /** The file holds no lines at all: seeing that is seeing all of it. */
114
+ empty?: true;
104
115
  }
105
116
  /**
106
117
  * Create a file read executor using Node.js fs module
@@ -23,6 +23,8 @@ export declare function truncateCommandOutput(text: string, options?: {
23
23
  export declare const MAX_READ_LINES = 2000;
24
24
  /** Max characters kept per line in file reads (defangs minified files). */
25
25
  export declare const MAX_LINE_CHARS = 2000;
26
+ /** The most of one line `grep` prints; a longer one is cut around its match. */
27
+ export declare const MAX_GREP_LINE_CHARS = 400;
26
28
  /** Max characters returned per file read window. */
27
29
  export declare const MAX_READ_OUTPUT_CHARS = 48000;
28
30
  /**
@@ -79,6 +79,37 @@ export interface ReadReceipts {
79
79
  retire(filePath: string): void;
80
80
  /** Drop everything known about a file. */
81
81
  forget(filePath: string): void;
82
+ /**
83
+ * Record that a read showed only the first `shown` of a line's `length`
84
+ * characters.
85
+ *
86
+ * A line span alone said the whole line was seen. `read_files` cuts a line
87
+ * at 2,000 characters, so an edit by column past the cut, or a replace of
88
+ * the whole line, landed on characters the model was never shown (csf-16).
89
+ * Optional so a registry that does not track it still compiles; one that
90
+ * does not answers "not cut" for every line.
91
+ *
92
+ * `from` is the first column shown, 1 unless the read showed a window from
93
+ * the middle of the line, as `grep` does. A record with `from` 1 and
94
+ * `shown` at `length` says the line was seen whole; it is kept, so a later
95
+ * window does not narrow what an earlier read showed. Each call replaces
96
+ * the line's record; {@link noteShown} merges a new read into it.
97
+ */
98
+ noteCut?(filePath: string, line: number, shown: number, length: number, from?: number): void;
99
+ /**
100
+ * Move a file's stamp from `from` to `to`, if `from` is the one held.
101
+ *
102
+ * For a rewrite that puts back content the session had already seen: the
103
+ * change protocol's check against the base writes every edited file twice
104
+ * and ends where it started, but the mtime moves, and the next edit was
105
+ * refused as "changed since you last read it". Matching on `from` keeps an
106
+ * outside write made before the rewrite visible. Optional, like `noteCut`.
107
+ */
108
+ carryStamp?(filePath: string, from: FileStamp, to: FileStamp): void;
109
+ /** How much of `line` the reads showed, when one of them cut it. */
110
+ cutAt?(filePath: string, line: number): LineCut | undefined;
111
+ /** The lines of a file a read cut short. */
112
+ cutLines?(filePath: string): number[];
82
113
  /**
83
114
  * Every file read in this session, in the form it was resolved to.
84
115
  *
@@ -90,4 +121,38 @@ export interface ReadReceipts {
90
121
  */
91
122
  paths(): string[];
92
123
  }
93
- export declare function createReadReceipts(): ReadReceipts;
124
+ /**
125
+ * What the reads have shown of one long line: columns `from` (1 when absent)
126
+ * to `shown` of `length`.
127
+ */
128
+ export interface LineCut {
129
+ shown: number;
130
+ length: number;
131
+ from?: number;
132
+ }
133
+ /** Whether a cut leaves nothing of the line unseen. */
134
+ export declare function isWhole(cut: LineCut): boolean;
135
+ /**
136
+ * Record that a read showed columns `from` to `to` of a line of `length`.
137
+ *
138
+ * Merged with what the line's record already holds: a window that overlaps or
139
+ * touches it widens it, so `grep` printing 400 characters of a line
140
+ * `read_files` showed whole leaves it whole. A window apart from it replaces
141
+ * it, as the newer of two views the model holds.
142
+ */
143
+ export declare function noteShown(receipts: ReadReceipts | undefined, filePath: string, line: number, from: number, to: number, length: number): void;
144
+ /**
145
+ * The registry as its owner holds it: everything a reader sees, plus the reset
146
+ * that only the owner may call. An agent's overlay view is a `ReadReceipts`
147
+ * and so cannot clear the lead's reads.
148
+ */
149
+ export interface OwnedReadReceipts extends ReadReceipts {
150
+ /**
151
+ * Forget every read. For the owner of a registry that outlives one task:
152
+ * the next task has read nothing, and the last task's reads would tell its
153
+ * first read that the file "changed since you last looked at it" (pandorum,
154
+ * 2026-10-18, ptm1c) and credit edits to lines it never saw.
155
+ */
156
+ clear(): void;
157
+ }
158
+ export declare function createReadReceipts(): OwnedReadReceipts;
@@ -229,6 +229,21 @@ export declare class TaskProgressTracker {
229
229
  * can be missed, said on every edit it is noise the model learns to skip.
230
230
  */
231
231
  private noteUntrackedEdit;
232
+ /**
233
+ * Take back what {@link recordToolCall} counted for a call that then failed.
234
+ *
235
+ * The call is recorded before the tool runs, because that is the only place
236
+ * its checklist is still visible, so "changed a file" was decided from the
237
+ * tool's name. An `editor` call refused with "Read before editing ... The
238
+ * file was not modified" was then followed by "You just changed
239
+ * `/workspace/answer.txt` and this task has no checklist" (automaticum,
240
+ * 2026-10-13, SDK 4.100.250): a statement about the file that the result
241
+ * one line above it contradicts.
242
+ *
243
+ * Only the nudge this call queued is withdrawn. One already waiting from an
244
+ * edit that did land names a path of its own and is kept.
245
+ */
246
+ retractFailedWrite(input: unknown, toolName?: string): void;
232
247
  /**
233
248
  * Hold a reminder for delivery after the turn's tool calls.
234
249
  *