@robota-sdk/agent-core 3.0.0-beta.83 → 3.0.0-beta.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +103 -0
- package/README.md +154 -116
- package/dist/browser/bounded-output-Bgx2Cgkx.js +2 -0
- package/dist/browser/bounded-output-Bgx2Cgkx.js.map +1 -0
- package/dist/browser/{command-executor-cI7XJ374.js → command-executor-C0XXfBnt.js} +2 -2
- package/dist/browser/{command-executor-cI7XJ374.js.map → command-executor-C0XXfBnt.js.map} +1 -1
- package/dist/browser/{http-executor-CHy6UeBU.js → http-executor-B4YgCJg7.js} +2 -2
- package/dist/browser/{http-executor-CHy6UeBU.js.map → http-executor-B4YgCJg7.js.map} +1 -1
- package/dist/browser/index.d.ts +1251 -918
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +10 -10
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/{verdict-decoder-Dk_w2NG9.js → verdict-decoder-Dz_rjoIZ.js} +2 -2
- package/dist/browser/verdict-decoder-Dz_rjoIZ.js.map +1 -0
- package/dist/node/bounded-output-Bgx2Cgkx.js +2 -0
- package/dist/node/bounded-output-Bgx2Cgkx.js.map +1 -0
- package/dist/node/{command-executor-Aat_q7P2.cjs → command-executor-CqAFpB-X.cjs} +1 -1
- package/dist/node/{command-executor-DV-H2oD6.js → command-executor-d6DdfUTD.js} +2 -2
- package/dist/node/{command-executor-DV-H2oD6.js.map → command-executor-d6DdfUTD.js.map} +1 -1
- package/dist/node/{http-executor-cWzI2svn.js → http-executor-ADn4locH.js} +2 -2
- package/dist/node/{http-executor-cWzI2svn.js.map → http-executor-ADn4locH.js.map} +1 -1
- package/dist/node/{http-executor-71JiIdFP.cjs → http-executor-BFtXs8FP.cjs} +1 -1
- package/dist/node/{index-D1_Mak-n.d.cts → index-CPwJEiFl.d.cts} +1251 -917
- package/dist/node/index-CPwJEiFl.d.cts.map +1 -0
- package/dist/node/{index-D4iJ5IsN.d.ts → index-DQrmrFn9.d.ts} +1251 -917
- package/dist/node/index-DQrmrFn9.d.ts.map +1 -0
- package/dist/node/index.cjs +10 -10
- package/dist/node/index.d.cts +3 -3
- package/dist/node/index.d.ts +3 -3
- package/dist/node/index.js +11 -11
- package/dist/node/index.js.map +1 -1
- package/dist/node/node.cjs +1 -1
- package/dist/node/node.d.cts +1 -1
- package/dist/node/node.d.ts +1 -1
- package/dist/node/node.js +1 -1
- package/dist/node/testing/index.d.cts +1 -1
- package/dist/node/testing/index.d.ts +1 -1
- package/dist/node/{types-gNrckgFE.d.ts → types-Ge2XB-y-.d.cts} +4 -5
- package/dist/node/types-Ge2XB-y-.d.cts.map +1 -0
- package/dist/node/{types-gNrckgFE.d.cts → types-Ge2XB-y-.d.ts} +4 -5
- package/dist/node/types-Ge2XB-y-.d.ts.map +1 -0
- package/dist/node/verdict-decoder-DIHay1ul.cjs +1 -0
- package/dist/node/{verdict-decoder-Dk_w2NG9.js → verdict-decoder-Dz_rjoIZ.js} +2 -2
- package/dist/node/verdict-decoder-Dz_rjoIZ.js.map +1 -0
- package/package.json +3 -3
- package/dist/browser/bounded-output-DpjpS98g.js +0 -2
- package/dist/browser/bounded-output-DpjpS98g.js.map +0 -1
- package/dist/browser/verdict-decoder-Dk_w2NG9.js.map +0 -1
- package/dist/node/bounded-output-DpjpS98g.js +0 -2
- package/dist/node/bounded-output-DpjpS98g.js.map +0 -1
- package/dist/node/index-D1_Mak-n.d.cts.map +0 -1
- package/dist/node/index-D4iJ5IsN.d.ts.map +0 -1
- package/dist/node/types-gNrckgFE.d.cts.map +0 -1
- package/dist/node/types-gNrckgFE.d.ts.map +0 -1
- package/dist/node/verdict-decoder-Dk_w2NG9.js.map +0 -1
- package/dist/node/verdict-decoder-Estx9MtY.cjs +0 -1
package/dist/node/node.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./command-executor-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./command-executor-CqAFpB-X.cjs"),t=require("./http-executor-BFtXs8FP.cjs");let n=require("node:fs"),r=require("node:path"),i=require("node:dns/promises"),a=require("node:net");function o(e){if(typeof e!=`string`)throw TypeError(`executionRoot must be a string`);if(e.trim().length===0)throw TypeError(`executionRoot must be a non-empty string`);if(!(0,r.isAbsolute)(e))throw TypeError(`executionRoot must be an absolute path`);let t;try{t=(0,n.realpathSync)(e)}catch{throw TypeError(`executionRoot must name an existing accessible directory`)}if(!(0,n.statSync)(t).isDirectory())throw TypeError(`executionRoot must name a directory`);try{(0,n.accessSync)(t,n.constants.R_OK|n.constants.X_OK)}catch{throw TypeError(`executionRoot directory must be readable and traversable`)}return t}function s(e){let t=[],i=(0,r.resolve)(e);for(;;)try{return(0,r.join)((0,n.realpathSync)(i),...t)}catch{let n=(0,r.dirname)(i);if(n===i)return(0,r.resolve)(e);t.unshift((0,r.basename)(i)),i=n}}function c(e,t){let n=s(e),i=s(t);return i===n||i.startsWith(n+r.sep)}var l=class extends Error{constructor(e){super(e),this.name=`OwnerOnlyModeError`}};function u(e=process.platform){return e===`win32`?`windows-acl`:`posix-mode`}function d(e,t){let n=(0,r.relative)(e,t);if(n.startsWith(`..`)||(0,r.isAbsolute)(n))throw new l(`withinRoot ${e} is not an ancestor of ${t}, so this call cannot own the path between them.`);let i=n.split(r.sep).filter(e=>e.length>0),a=[e],o=e;for(let e of i)o=(0,r.join)(o,e),a.push(o);return a}function f(e,t,r={}){if(u()!==`posix-mode`)return;let i=(r.readMode??(e=>(0,n.statSync)(e).mode&4095))(e);if(i&63)throw new l(`${t} ${e} is mode 0${i.toString(8)} after being set owner-only; group or other permissions survived, so its contents are readable by another account.`)}function p(e,t={}){let r=t.makeDirectory??((e,t)=>{(0,n.mkdirSync)(e,{recursive:!0,mode:t})}),i=t.setMode??((e,t)=>(0,n.chmodSync)(e,t));r(e,448);let a=t.withinRoot===void 0?[e]:d(t.withinRoot,e);for(let e of a)u()===`posix-mode`&&i(e,448),f(e,`directory`,t)}function m(e,t){p((0,r.dirname)(e));let i=`${e}.${process.pid}.tmp`;(0,n.rmSync)(i,{force:!0}),(0,n.writeFileSync)(i,t,{encoding:`utf8`,mode:384,flag:`wx`});try{f(i,`file`),(0,n.renameSync)(i,e)}catch(e){try{(0,n.unlinkSync)(i)}catch{}throw e}f(e,`file`)}function h(e){if(u()!==`posix-mode`)return;let t;try{t=(0,n.statSync)(e).mode&4095}catch{return}t&63&&((0,n.chmodSync)(e,384),f(e,`file`))}function g(e){let t=(0,a.isIP)(e);return t===4?_(e.split(`.`).map(Number)):t!==6||v(e)}function _(e){let[t=0,n=0,r=0]=e;return t===0||t===10||t===127||t===100&&n>=64&&n<=127||t===169&&n===254||t===172&&n>=16&&n<=31||t===192&&n===0&&r===0||t===192&&n===168||t===198&&(n===18||n===19)||t>=224}function v(e){let t=b(e);if(t===void 0)return!0;let[n=0,r=0,i=0,a=0,o=0,s=0,c=0,l=0]=t;return n===0&&r===0&&i===0&&a===0&&o===0&&s===65535||n===100&&r===65435&&i===0&&a===0&&o===0&&s===0?_([c>>8,c&255,l>>8,l&255]):n===0&&r===0&&i===0&&a===0&&o===0&&s===0||(n&65024)==64512||(n&65472)==65152||(n&65472)==65216||(n&65280)==65280}function y(e){let t=e.lastIndexOf(`:`),n=e.slice(t+1);if(!n.includes(`.`))return e;if(t<0||(0,a.isIP)(n)!==4)return;let[r=0,i=0,o=0,s=0]=n.split(`.`).map(Number),c=(r<<8|i).toString(16),l=(o<<8|s).toString(16);return`${e.slice(0,t+1)}${c}:${l}`}function b(e){let t=y(e.split(`%`)[0]??e);if(t===void 0)return;let n=t.split(`::`);if(n.length>2)return;let r=e=>e.length===0?[]:e.split(`:`).map(e=>Number.parseInt(e,16)),i=r(n[0]??``),a=n.length===2?r(n[1]??``):[],o=8-i.length-a.length;if(o<0||n.length===1&&o!==0)return;let s=[...i,...Array(o).fill(0),...a];return s.some(e=>Number.isNaN(e)||e<0||e>65535)?void 0:s}const x=3e4,S=5e6,C=new Set([301,302,303,307,308]),w=new Set([`localhost`,`metadata`,`metadata.google.internal`,`metadata.goog`,`instance-data`,`instance-data.ec2.internal`]),T=async e=>(await(0,i.lookup)(e,{all:!0,verbatim:!0})).map(e=>e.address);async function E(e,t={},n=T){let r=e.href;if(e.protocol!==`http:`&&e.protocol!==`https:`)return{reason:`unsupported_scheme`,url:r,message:`Only http(s) URLs may be fetched.`};if(t.allowPrivateAddresses===!0)return;let i=e.hostname.replace(/^\[|\]$/g,``).toLowerCase();if(t.allowedHosts?.includes(i))return;if(w.has(i)||i.endsWith(`.localhost`))return{reason:`metadata_host`,url:r,message:`Destination "${i}" is a loopback or cloud-metadata host and is not reachable from tools.`};let o=(0,a.isIP)(i)?[i]:await D(i,n);if(o===void 0||o.length===0)return{reason:`unresolvable`,url:r,message:`Destination "${i}" did not resolve.`};let s=o.find(g);if(s!==void 0)return{reason:`private_destination`,url:r,message:`Destination "${i}" resolves to ${s}, a private, loopback or link-local address, and is not reachable from tools.`}}async function D(e,t){try{return await t(e)}catch{return}}async function O(e,t={},n={},r={}){let i=r.fetch??((e,t)=>globalThis.fetch(e,t)),a=r.lookup??T,o=t.maxResponseBytes??S,s=n.maxRedirects??5,c=AbortSignal.timeout(t.timeoutMs??x),l=t.signal?AbortSignal.any([c,t.signal]):c,u=new URL(e),d={...t.headers??{}};for(let e=0;;e+=1){let t=await E(u,n,a);if(t!==void 0)return{ok:!1,rejection:t};let r=await i(u.href,{headers:d,signal:l,redirect:`manual`});if(!C.has(r.status))return j(r,u.href,o,l);let c=r.headers.get(`location`);if(c===null)return{ok:!1,rejection:{reason:`redirect_without_location`,url:u.href,message:`HTTP ${r.status} without a Location header.`}};if(e>=s)return{ok:!1,rejection:{reason:`redirect_limit`,url:u.href,message:`More than ${s} redirects.`}};let f=new URL(c,u);f.origin!==u.origin&&(d=A(d)),u=f}}async function k(e,t,n={},r={}){let i=r.fetch??((e,t)=>globalThis.fetch(e,t)),a=t.maxResponseBytes??S,o=AbortSignal.timeout(t.timeoutMs??x),s=t.signal?AbortSignal.any([o,t.signal]):o,c=new URL(e),l=await E(c,n,r.lookup??T);if(l!==void 0)return{ok:!1,rejection:l};let u=await i(c.href,{method:`POST`,headers:{...t.headers??{}},body:t.body,signal:s,redirect:`manual`});return u.status>=300&&u.status<400?(await u.body?.cancel().catch(()=>void 0),{ok:!1,rejection:{reason:`redirect_refused`,url:c.href,message:`HTTP ${u.status}: a POST is never redirected.`}}):j(u,c.href,a,s)}function A(e){let t={};for(let[n,r]of Object.entries(e))n.toLowerCase()===`user-agent`&&(t[n]=r);return t}async function j(e,t,n,r){let i=e=>({ok:!1,rejection:{reason:`response_too_large`,url:t,message:`Response exceeds ${n} bytes (${e} seen).`}}),a=Number(e.headers.get(`content-length`));if(Number.isFinite(a)&&a>n)return await e.body?.cancel(),i(a);let o=[],s=0;if(!e.body&&typeof e.arrayBuffer==`function`){let t=new Uint8Array(await e.arrayBuffer());if(t.byteLength>n)return i(t.byteLength);o.push(t),s=t.byteLength}else if(e.body){let t=e.body.getReader();for(;;){r.throwIfAborted();let{done:e,value:a}=await t.read();if(e)break;if(s+=a.byteLength,s>n)return await t.cancel(),i(s);o.push(a)}}let c=new Uint8Array(s),l=0;for(let e of o)c.set(e,l),l+=e.byteLength;return{ok:!0,status:e.status,statusText:e.statusText,headers:e.headers,body:c,finalUrl:t}}exports.BLOCKED_HOSTNAMES=w,exports.CommandExecutor=e.t,exports.HttpExecutor=t.t,exports.OWNER_ONLY_DIRECTORY_MODE=448,exports.OWNER_ONLY_FILE_MODE=384,exports.OwnerOnlyModeError=l,exports.canonicalizePath=s,exports.ensureOwnerOnlyDirectory=p,exports.fetchWithEgressPolicy=O,exports.isPathInside=c,exports.isPrivateAddress=g,exports.ownerOnlyGuarantee=u,exports.postWithEgressPolicy=k,exports.rejectDestination=E,exports.resolveTrustedExecutionRoot=o,exports.tightenExistingFile=h,exports.writeOwnerOnlyFile=m;
|
package/dist/node/node.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as IHookTypeExecutor, l as IHttpHookDefinition, m as THookOutcome, n as ICommandHookDefinition, s as IHookInput, y as ISubprocessTraceEnv } from "./types-
|
|
1
|
+
import { c as IHookTypeExecutor, l as IHttpHookDefinition, m as THookOutcome, n as ICommandHookDefinition, s as IHookInput, y as ISubprocessTraceEnv } from "./types-Ge2XB-y-.cjs";
|
|
2
2
|
//#region src/utils/path-containment.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Validate an authority root more strictly than candidate-path canonicalization.
|
package/dist/node/node.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as IHookTypeExecutor, l as IHttpHookDefinition, m as THookOutcome, n as ICommandHookDefinition, s as IHookInput, y as ISubprocessTraceEnv } from "./types-
|
|
1
|
+
import { c as IHookTypeExecutor, l as IHttpHookDefinition, m as THookOutcome, n as ICommandHookDefinition, s as IHookInput, y as ISubprocessTraceEnv } from "./types-Ge2XB-y-.js";
|
|
2
2
|
//#region src/utils/path-containment.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Validate an authority root more strictly than candidate-path canonicalization.
|
package/dist/node/node.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./command-executor-
|
|
1
|
+
import{t as e}from"./command-executor-d6DdfUTD.js";import{t}from"./http-executor-ADn4locH.js";import{accessSync as n,chmodSync as r,constants as i,mkdirSync as a,realpathSync as o,renameSync as s,rmSync as c,statSync as l,unlinkSync as u,writeFileSync as d}from"node:fs";import{basename as f,dirname as p,isAbsolute as m,join as h,relative as g,resolve as _,sep as v}from"node:path";import{lookup as y}from"node:dns/promises";import{isIP as b}from"node:net";function x(e){if(typeof e!=`string`)throw TypeError(`executionRoot must be a string`);if(e.trim().length===0)throw TypeError(`executionRoot must be a non-empty string`);if(!m(e))throw TypeError(`executionRoot must be an absolute path`);let t;try{t=o(e)}catch{throw TypeError(`executionRoot must name an existing accessible directory`)}if(!l(t).isDirectory())throw TypeError(`executionRoot must name a directory`);try{n(t,i.R_OK|i.X_OK)}catch{throw TypeError(`executionRoot directory must be readable and traversable`)}return t}function S(e){let t=[],n=_(e);for(;;)try{return h(o(n),...t)}catch{let r=p(n);if(r===n)return _(e);t.unshift(f(n)),n=r}}function C(e,t){let n=S(e),r=S(t);return r===n||r.startsWith(n+v)}const w=384,T=448;var E=class extends Error{constructor(e){super(e),this.name=`OwnerOnlyModeError`}};function D(e=process.platform){return e===`win32`?`windows-acl`:`posix-mode`}function O(e,t){let n=g(e,t);if(n.startsWith(`..`)||m(n))throw new E(`withinRoot ${e} is not an ancestor of ${t}, so this call cannot own the path between them.`);let r=n.split(v).filter(e=>e.length>0),i=[e],a=e;for(let e of r)a=h(a,e),i.push(a);return i}function k(e,t,n={}){if(D()!==`posix-mode`)return;let r=(n.readMode??(e=>l(e).mode&4095))(e);if(r&63)throw new E(`${t} ${e} is mode 0${r.toString(8)} after being set owner-only; group or other permissions survived, so its contents are readable by another account.`)}function A(e,t={}){let n=t.makeDirectory??((e,t)=>{a(e,{recursive:!0,mode:t})}),i=t.setMode??((e,t)=>r(e,t));n(e,448);let o=t.withinRoot===void 0?[e]:O(t.withinRoot,e);for(let e of o)D()===`posix-mode`&&i(e,448),k(e,`directory`,t)}function j(e,t){A(p(e));let n=`${e}.${process.pid}.tmp`;c(n,{force:!0}),d(n,t,{encoding:`utf8`,mode:384,flag:`wx`});try{k(n,`file`),s(n,e)}catch(e){try{u(n)}catch{}throw e}k(e,`file`)}function M(e){if(D()!==`posix-mode`)return;let t;try{t=l(e).mode&4095}catch{return}t&63&&(r(e,384),k(e,`file`))}function N(e){let t=b(e);return t===4?P(e.split(`.`).map(Number)):t!==6||F(e)}function P(e){let[t=0,n=0,r=0]=e;return t===0||t===10||t===127||t===100&&n>=64&&n<=127||t===169&&n===254||t===172&&n>=16&&n<=31||t===192&&n===0&&r===0||t===192&&n===168||t===198&&(n===18||n===19)||t>=224}function F(e){let t=L(e);if(t===void 0)return!0;let[n=0,r=0,i=0,a=0,o=0,s=0,c=0,l=0]=t;return n===0&&r===0&&i===0&&a===0&&o===0&&s===65535||n===100&&r===65435&&i===0&&a===0&&o===0&&s===0?P([c>>8,c&255,l>>8,l&255]):n===0&&r===0&&i===0&&a===0&&o===0&&s===0||(n&65024)==64512||(n&65472)==65152||(n&65472)==65216||(n&65280)==65280}function I(e){let t=e.lastIndexOf(`:`),n=e.slice(t+1);if(!n.includes(`.`))return e;if(t<0||b(n)!==4)return;let[r=0,i=0,a=0,o=0]=n.split(`.`).map(Number),s=(r<<8|i).toString(16),c=(a<<8|o).toString(16);return`${e.slice(0,t+1)}${s}:${c}`}function L(e){let t=I(e.split(`%`)[0]??e);if(t===void 0)return;let n=t.split(`::`);if(n.length>2)return;let r=e=>e.length===0?[]:e.split(`:`).map(e=>Number.parseInt(e,16)),i=r(n[0]??``),a=n.length===2?r(n[1]??``):[],o=8-i.length-a.length;if(o<0||n.length===1&&o!==0)return;let s=[...i,...Array(o).fill(0),...a];return s.some(e=>Number.isNaN(e)||e<0||e>65535)?void 0:s}const R=3e4,z=5e6,B=new Set([301,302,303,307,308]),V=new Set([`localhost`,`metadata`,`metadata.google.internal`,`metadata.goog`,`instance-data`,`instance-data.ec2.internal`]),H=async e=>(await y(e,{all:!0,verbatim:!0})).map(e=>e.address);async function U(e,t={},n=H){let r=e.href;if(e.protocol!==`http:`&&e.protocol!==`https:`)return{reason:`unsupported_scheme`,url:r,message:`Only http(s) URLs may be fetched.`};if(t.allowPrivateAddresses===!0)return;let i=e.hostname.replace(/^\[|\]$/g,``).toLowerCase();if(t.allowedHosts?.includes(i))return;if(V.has(i)||i.endsWith(`.localhost`))return{reason:`metadata_host`,url:r,message:`Destination "${i}" is a loopback or cloud-metadata host and is not reachable from tools.`};let a=b(i)?[i]:await W(i,n);if(a===void 0||a.length===0)return{reason:`unresolvable`,url:r,message:`Destination "${i}" did not resolve.`};let o=a.find(N);if(o!==void 0)return{reason:`private_destination`,url:r,message:`Destination "${i}" resolves to ${o}, a private, loopback or link-local address, and is not reachable from tools.`}}async function W(e,t){try{return await t(e)}catch{return}}async function G(e,t={},n={},r={}){let i=r.fetch??((e,t)=>globalThis.fetch(e,t)),a=r.lookup??H,o=t.maxResponseBytes??z,s=n.maxRedirects??5,c=AbortSignal.timeout(t.timeoutMs??R),l=t.signal?AbortSignal.any([c,t.signal]):c,u=new URL(e),d={...t.headers??{}};for(let e=0;;e+=1){let t=await U(u,n,a);if(t!==void 0)return{ok:!1,rejection:t};let r=await i(u.href,{headers:d,signal:l,redirect:`manual`});if(!B.has(r.status))return J(r,u.href,o,l);let c=r.headers.get(`location`);if(c===null)return{ok:!1,rejection:{reason:`redirect_without_location`,url:u.href,message:`HTTP ${r.status} without a Location header.`}};if(e>=s)return{ok:!1,rejection:{reason:`redirect_limit`,url:u.href,message:`More than ${s} redirects.`}};let f=new URL(c,u);f.origin!==u.origin&&(d=q(d)),u=f}}async function K(e,t,n={},r={}){let i=r.fetch??((e,t)=>globalThis.fetch(e,t)),a=t.maxResponseBytes??z,o=AbortSignal.timeout(t.timeoutMs??R),s=t.signal?AbortSignal.any([o,t.signal]):o,c=new URL(e),l=await U(c,n,r.lookup??H);if(l!==void 0)return{ok:!1,rejection:l};let u=await i(c.href,{method:`POST`,headers:{...t.headers??{}},body:t.body,signal:s,redirect:`manual`});return u.status>=300&&u.status<400?(await u.body?.cancel().catch(()=>void 0),{ok:!1,rejection:{reason:`redirect_refused`,url:c.href,message:`HTTP ${u.status}: a POST is never redirected.`}}):J(u,c.href,a,s)}function q(e){let t={};for(let[n,r]of Object.entries(e))n.toLowerCase()===`user-agent`&&(t[n]=r);return t}async function J(e,t,n,r){let i=e=>({ok:!1,rejection:{reason:`response_too_large`,url:t,message:`Response exceeds ${n} bytes (${e} seen).`}}),a=Number(e.headers.get(`content-length`));if(Number.isFinite(a)&&a>n)return await e.body?.cancel(),i(a);let o=[],s=0;if(!e.body&&typeof e.arrayBuffer==`function`){let t=new Uint8Array(await e.arrayBuffer());if(t.byteLength>n)return i(t.byteLength);o.push(t),s=t.byteLength}else if(e.body){let t=e.body.getReader();for(;;){r.throwIfAborted();let{done:e,value:a}=await t.read();if(e)break;if(s+=a.byteLength,s>n)return await t.cancel(),i(s);o.push(a)}}let c=new Uint8Array(s),l=0;for(let e of o)c.set(e,l),l+=e.byteLength;return{ok:!0,status:e.status,statusText:e.statusText,headers:e.headers,body:c,finalUrl:t}}export{V as BLOCKED_HOSTNAMES,e as CommandExecutor,t as HttpExecutor,T as OWNER_ONLY_DIRECTORY_MODE,w as OWNER_ONLY_FILE_MODE,E as OwnerOnlyModeError,S as canonicalizePath,A as ensureOwnerOnlyDirectory,G as fetchWithEgressPolicy,C as isPathInside,N as isPrivateAddress,D as ownerOnlyGuarantee,K as postWithEgressPolicy,U as rejectDestination,x as resolveTrustedExecutionRoot,M as tightenExistingFile,j as writeOwnerOnlyFile};
|
|
2
2
|
//# sourceMappingURL=node.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ec as IChatOptions, Tc as IAIProvider, Uc as IToolSchema, ql as TUniversalMessage } from "../index-CPwJEiFl.cjs";
|
|
2
2
|
//#region src/testing/scripted-provider.d.ts
|
|
3
3
|
/** ANALYTICS-001: optional token usage a scripted turn reports, so usage-based tests are possible. */
|
|
4
4
|
interface IScriptedTurnUsage {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ec as IChatOptions, Tc as IAIProvider, Uc as IToolSchema, ql as TUniversalMessage } from "../index-DQrmrFn9.js";
|
|
2
2
|
//#region src/testing/scripted-provider.d.ts
|
|
3
3
|
/** ANALYTICS-001: optional token usage a scripted turn reports, so usage-based tests are possible. */
|
|
4
4
|
interface IScriptedTurnUsage {
|
|
@@ -135,8 +135,7 @@ interface IOutboundTraceContext {
|
|
|
135
135
|
* `packages/agent-core/docs/HOOK-CATALOG.md` § "Blocking semantics" — cited here rather than
|
|
136
136
|
* recounted, because two different groupings of the same set were in circulation and a second copy
|
|
137
137
|
* is what let them drift. Which events enforce is recorded in `HOOK_ENFORCEMENT_POLICY`
|
|
138
|
-
* (`./enforcement-policy.ts`);
|
|
139
|
-
* per-event timing, fire-site, and blocking semantics.
|
|
138
|
+
* (`./enforcement-policy.ts`); the catalog also gives per-event timing and fire sites.
|
|
140
139
|
*/
|
|
141
140
|
type THookEvent = 'PreToolUse' | 'PostToolUse' | 'SessionStart' | 'SessionEnd' | 'Stop' | 'StopFailure' | 'PreCompact' | 'PostCompact' | 'UserPromptSubmit' | 'SubagentStart' | 'SubagentStop' | 'WorktreeCreate' | 'WorktreeRemove' | 'PreModelCall' | 'PostModelCall' | 'PermissionDecision';
|
|
142
141
|
/** Claude Code compatible session end reasons. */
|
|
@@ -171,7 +170,7 @@ interface IAgentHookDefinition {
|
|
|
171
170
|
* Guardrail hook (SELFHOST-005) — runs the registered guardrail SET in parallel and fails the turn
|
|
172
171
|
* fast. The guardrail functions live in the `GuardrailExecutor` (registered by the consumer); this
|
|
173
172
|
* data-only definition just selects which to run. Any failure maps onto the existing exit-code-2 /
|
|
174
|
-
* `blocked` contract, so enforcement reuses the single `runHooks` → `
|
|
173
|
+
* `blocked` contract, so enforcement reuses the single `runHooks` → `runPreToolGate` path.
|
|
175
174
|
*/
|
|
176
175
|
interface IGuardrailHookDefinition {
|
|
177
176
|
type: 'guardrail';
|
|
@@ -237,7 +236,7 @@ interface IHookInput {
|
|
|
237
236
|
agent_type?: string;
|
|
238
237
|
/** Subagent transcript path when available (SubagentStop only) */
|
|
239
238
|
agent_transcript_path?: string;
|
|
240
|
-
/**
|
|
239
|
+
/** Permission mode at the time of the event (e.g. "default", "plan", "acceptEdits", "bypassPermissions", "auto") */
|
|
241
240
|
permission_mode?: string;
|
|
242
241
|
/**
|
|
243
242
|
* Provider model identifier for the model call (PreModelCall/PostModelCall only).
|
|
@@ -332,4 +331,4 @@ interface IHookTypeExecutor {
|
|
|
332
331
|
}
|
|
333
332
|
//#endregion
|
|
334
333
|
export { TModelEffortProviderDispatch as A, IModelEffortResolution as C, TModelEffortDisposition as D, TModelEffort as E, IUniversalObjectValue as F, TPrimitiveValue as I, TUniversalArrayValue as L, createModelEffortOutcome as M, isModelEffort as N, TModelEffortNativeControl as O, resolveModelEffort as P, TUniversalValue as R, IModelEffortOutcome as S, MODEL_EFFORT_VALUES as T, IOutboundTraceContext as _, IHookErrorOutcome as a, TSubprocessTraceClass as b, IHookTypeExecutor as c, TGuardrail as d, THookDefinition as f, TSessionEndReason as g, THooksConfig as h, IGuardrailResult as i, TModelEffortSelection as j, TModelEffortOutcomeCallback as k, IHttpHookDefinition as l, THookOutcome as m, ICommandHookDefinition as n, IHookGroup as o, THookEvent as p, IGuardrailHookDefinition as r, IHookInput as s, IAgentHookDefinition as t, IPromptHookDefinition as u, IRunTraceContext as v, IProviderModelEffortTable as w, IModelEffortCapability as x, ISubprocessTraceEnv as y };
|
|
335
|
-
//# sourceMappingURL=types-
|
|
334
|
+
//# sourceMappingURL=types-Ge2XB-y-.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-Ge2XB-y-.d.cts","names":[],"sources":["../../src/interfaces/universal-value.ts","../../src/interfaces/model-effort-capability.ts","../../src/interfaces/trace-context.ts","../../src/hooks/types.ts"],"mappings":";;;;;;;;;;;;;;;;;KAiBY;KAEA,kBAAkB,kBAAkB,OAAO,uBAAuB;KAElE,uBAAuB;UAElB;GACd,cAAc;;;;;KCvBL;;cAGC;iBAUG,cAAc,OAAO,8BAA8B,SAAS;;KAKhE,wBAAwB;;UAGnB;EACf,2BAA2B;EAC3B,eAAe;;EAEf;;;UAIe;EACf;EACA;EACA,QAAQ,SAAS,eAAe;;KAGtB;;UAGK;EACf,WAAW;EACX,WAAW;EACX,aAAa;EACb;;;KAIU;WACG;WAAwB;;WACxB;WAA2B;;;KAG9B;WACC;;WAA6B;WAAkC;;;UAG3D;WACN,YAAY;WACZ,eAAe;WACf,kBAAkB;;;KAIjB,+BAA+B,SAAS;;iBAGpC,yBACd,YAAY,wBACZ,SAAS,KAAK,qCACb;;;;iBAkBa,mBACd,OAAO,uCACP,iBACA,WAAW,wBACV;;;;;;;;;;;;KCjFS;;UAGK;WACN;;;UAIM;;WAEN;;WAEA;;WAEA;;;;;WAKA,6BAA6B;;;;;;WAM7B,4BAA4B;;;UAItB;;WAEN;;WAEA;;;;;;;;;;;;;;;;KCzBC;;KAmBA;;UAIK;EACf;EACA;EACA;;;UAIe;EACf;EACA;EACA,UAAU;EACV;;;UAIe;EACf;EACA;EACA;;;UAIe;EACf;EACA;EACA;EACA;;;;;;;;UASe;EACf;;EAEA;;;KAIU,kBACR,yBACA,sBACA,wBACA,uBACA;;;;;UAMa;EACf;;EAEA;;;;;;;KAQU,cAAc,OAAO,eAAe,mBAAmB,QAAQ;;UAG1D;;EAEf;EACA,OAAO;;EAEP,MAAM;;;KAII,eAAe,QAAQ,OAAO,YAAY;;UAGrC;EACf;EACA;EACA,iBAAiB;EACjB;EACA,aAAa;EACb;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA,SAAS;;EAET;;EAEA;;EAEA;;EAEA;;EAEA;;;;;EAKA;;;;;EAKA;;;;;EAKA,SAAS;;EAET;;;;;;;EAOA;;EAEA,MAAM;;;;;;;;;KAUI;;;;;;;;;;;;;;UAeK;WACN;;WAEA,QAAQ;WACR;;;UAIM;WACN;;WAEA,QAAQ;WACR;;;;;;;;UASM;WACN;;WAEA,QAAQ;WACR,MAAM;WACN;;;;;;;;;;;KAYC,eAAe,oBAAoB,mBAAmB;;UAGjD;;EAEf,MAAM;;EAEN,QAAQ,YAAY,iBAAiB,OAAO,aAAa,QAAQ"}
|
|
@@ -135,8 +135,7 @@ interface IOutboundTraceContext {
|
|
|
135
135
|
* `packages/agent-core/docs/HOOK-CATALOG.md` § "Blocking semantics" — cited here rather than
|
|
136
136
|
* recounted, because two different groupings of the same set were in circulation and a second copy
|
|
137
137
|
* is what let them drift. Which events enforce is recorded in `HOOK_ENFORCEMENT_POLICY`
|
|
138
|
-
* (`./enforcement-policy.ts`);
|
|
139
|
-
* per-event timing, fire-site, and blocking semantics.
|
|
138
|
+
* (`./enforcement-policy.ts`); the catalog also gives per-event timing and fire sites.
|
|
140
139
|
*/
|
|
141
140
|
type THookEvent = 'PreToolUse' | 'PostToolUse' | 'SessionStart' | 'SessionEnd' | 'Stop' | 'StopFailure' | 'PreCompact' | 'PostCompact' | 'UserPromptSubmit' | 'SubagentStart' | 'SubagentStop' | 'WorktreeCreate' | 'WorktreeRemove' | 'PreModelCall' | 'PostModelCall' | 'PermissionDecision';
|
|
142
141
|
/** Claude Code compatible session end reasons. */
|
|
@@ -171,7 +170,7 @@ interface IAgentHookDefinition {
|
|
|
171
170
|
* Guardrail hook (SELFHOST-005) — runs the registered guardrail SET in parallel and fails the turn
|
|
172
171
|
* fast. The guardrail functions live in the `GuardrailExecutor` (registered by the consumer); this
|
|
173
172
|
* data-only definition just selects which to run. Any failure maps onto the existing exit-code-2 /
|
|
174
|
-
* `blocked` contract, so enforcement reuses the single `runHooks` → `
|
|
173
|
+
* `blocked` contract, so enforcement reuses the single `runHooks` → `runPreToolGate` path.
|
|
175
174
|
*/
|
|
176
175
|
interface IGuardrailHookDefinition {
|
|
177
176
|
type: 'guardrail';
|
|
@@ -237,7 +236,7 @@ interface IHookInput {
|
|
|
237
236
|
agent_type?: string;
|
|
238
237
|
/** Subagent transcript path when available (SubagentStop only) */
|
|
239
238
|
agent_transcript_path?: string;
|
|
240
|
-
/**
|
|
239
|
+
/** Permission mode at the time of the event (e.g. "default", "plan", "acceptEdits", "bypassPermissions", "auto") */
|
|
241
240
|
permission_mode?: string;
|
|
242
241
|
/**
|
|
243
242
|
* Provider model identifier for the model call (PreModelCall/PostModelCall only).
|
|
@@ -332,4 +331,4 @@ interface IHookTypeExecutor {
|
|
|
332
331
|
}
|
|
333
332
|
//#endregion
|
|
334
333
|
export { TModelEffortProviderDispatch as A, IModelEffortResolution as C, TModelEffortDisposition as D, TModelEffort as E, IUniversalObjectValue as F, TPrimitiveValue as I, TUniversalArrayValue as L, createModelEffortOutcome as M, isModelEffort as N, TModelEffortNativeControl as O, resolveModelEffort as P, TUniversalValue as R, IModelEffortOutcome as S, MODEL_EFFORT_VALUES as T, IOutboundTraceContext as _, IHookErrorOutcome as a, TSubprocessTraceClass as b, IHookTypeExecutor as c, TGuardrail as d, THookDefinition as f, TSessionEndReason as g, THooksConfig as h, IGuardrailResult as i, TModelEffortSelection as j, TModelEffortOutcomeCallback as k, IHttpHookDefinition as l, THookOutcome as m, ICommandHookDefinition as n, IHookGroup as o, THookEvent as p, IGuardrailHookDefinition as r, IHookInput as s, IAgentHookDefinition as t, IPromptHookDefinition as u, IRunTraceContext as v, IProviderModelEffortTable as w, IModelEffortCapability as x, ISubprocessTraceEnv as y };
|
|
335
|
-
//# sourceMappingURL=types-
|
|
334
|
+
//# sourceMappingURL=types-Ge2XB-y-.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-Ge2XB-y-.d.ts","names":[],"sources":["../../src/interfaces/universal-value.ts","../../src/interfaces/model-effort-capability.ts","../../src/interfaces/trace-context.ts","../../src/hooks/types.ts"],"mappings":";;;;;;;;;;;;;;;;;KAiBY;KAEA,kBAAkB,kBAAkB,OAAO,uBAAuB;KAElE,uBAAuB;UAElB;GACd,cAAc;;;;;KCvBL;;cAGC;iBAUG,cAAc,OAAO,8BAA8B,SAAS;;KAKhE,wBAAwB;;UAGnB;EACf,2BAA2B;EAC3B,eAAe;;EAEf;;;UAIe;EACf;EACA;EACA,QAAQ,SAAS,eAAe;;KAGtB;;UAGK;EACf,WAAW;EACX,WAAW;EACX,aAAa;EACb;;;KAIU;WACG;WAAwB;;WACxB;WAA2B;;;KAG9B;WACC;;WAA6B;WAAkC;;;UAG3D;WACN,YAAY;WACZ,eAAe;WACf,kBAAkB;;;KAIjB,+BAA+B,SAAS;;iBAGpC,yBACd,YAAY,wBACZ,SAAS,KAAK,qCACb;;;;iBAkBa,mBACd,OAAO,uCACP,iBACA,WAAW,wBACV;;;;;;;;;;;;KCjFS;;UAGK;WACN;;;UAIM;;WAEN;;WAEA;;WAEA;;;;;WAKA,6BAA6B;;;;;;WAM7B,4BAA4B;;;UAItB;;WAEN;;WAEA;;;;;;;;;;;;;;;;KCzBC;;KAmBA;;UAIK;EACf;EACA;EACA;;;UAIe;EACf;EACA;EACA,UAAU;EACV;;;UAIe;EACf;EACA;EACA;;;UAIe;EACf;EACA;EACA;EACA;;;;;;;;UASe;EACf;;EAEA;;;KAIU,kBACR,yBACA,sBACA,wBACA,uBACA;;;;;UAMa;EACf;;EAEA;;;;;;;KAQU,cAAc,OAAO,eAAe,mBAAmB,QAAQ;;UAG1D;;EAEf;EACA,OAAO;;EAEP,MAAM;;;KAII,eAAe,QAAQ,OAAO,YAAY;;UAGrC;EACf;EACA;EACA,iBAAiB;EACjB;EACA,aAAa;EACb;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA,SAAS;;EAET;;EAEA;;EAEA;;EAEA;;EAEA;;;;;EAKA;;;;;EAKA;;;;;EAKA,SAAS;;EAET;;;;;;;EAOA;;EAEA,MAAM;;;;;;;;;KAUI;;;;;;;;;;;;;;UAeK;WACN;;WAEA,QAAQ;WACR;;;UAIM;WACN;;WAEA,QAAQ;WACR;;;;;;;;UASM;WACN;;WAEA,QAAQ;WACR,MAAM;WACN;;;;;;;;;;;KAYC,eAAe,oBAAoB,mBAAmB;;UAGjD;;EAEf,MAAM;;EAEN,QAAQ,YAAY,iBAAiB,OAAO,aAAa,QAAQ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=class extends Error{context;constructor(e,t){super(e),this.context=t,this.name=this.constructor.name,Object.setPrototypeOf(this,new.target.prototype)}},t=class extends e{code=`CONFIGURATION_ERROR`;category=`user`;recoverable=!1;constructor(e,t){super(`Configuration Error: ${e}`,t)}},n=class extends e{field;code=`VALIDATION_ERROR`;category=`user`;recoverable=!1;constructor(e,t,n){super(`Validation Error: ${e}`,n),this.field=t}},r=class extends e{issues;attempts;code=`STRUCTURED_OUTPUT_ERROR`;category=`provider`;recoverable=!0;constructor(e,t,n,r){super(`Structured Output Error: ${e}`,r),this.issues=t,this.attempts=n}},i=class extends e{provider;originalError;code=`PROVIDER_ERROR`;category=`provider`;recoverable=!0;status;type;constructor(e,t,n,r,i){super(`Provider Error (${t}): ${e}`,r),this.provider=t,this.originalError=n,i?.status!==void 0&&(this.status=i.status),i?.type!==void 0&&(this.type=i.type)}},a=class extends e{provider;code=`AUTHENTICATION_ERROR`;category=`user`;recoverable=!1;constructor(e,t,n){super(`Authentication Error: ${e}`,n),this.provider=t}},o=class extends e{retryAfter;provider;code=`RATE_LIMIT_ERROR`;category=`provider`;recoverable=!0;constructor(e,t,n,r){super(`Rate Limit Error: ${e}`,r),this.retryAfter=t,this.provider=n}},s=class extends e{originalError;provider;code=`NETWORK_ERROR`;category=`system`;recoverable=!0;constructor(e,t,n,r){super(`Network Error: ${e}`,n),this.originalError=t,this.provider=r}},c=class extends e{toolName;originalError;code=`TOOL_EXECUTION_ERROR`;category=`system`;recoverable=!1;constructor(e,t,n,r){super(`Tool Execution Error (${t}): ${e}`,r),this.toolName=t,this.originalError=n}},l=class extends e{toolName;callCount;maxSameToolInputs;code=`SAME_TOOL_INPUT_LOOP`;category=`system`;recoverable=!0;constructor(e,t,n,r){super(`Tool "${e}" was called with identical input ${t} times, past the maxSameToolInputs limit of ${n} — stopping the turn to break the loop`,r),this.toolName=e,this.callCount=t,this.maxSameToolInputs=n}},u=class extends e{round;code=`EMPTY_COMPLETION`;category=`provider`;recoverable=!0;constructor(e,t){super(`Round ${e} ended with no tool call and no text response, and allowToolOnlyCompletion prevented the follow-up call that would otherwise recover it`,t),this.round=e}},d=class extends e{model;provider;availableModels;code=`MODEL_NOT_AVAILABLE`;category=`user`;recoverable=!1;constructor(e,t,n,r){let i=e===void 0?`No model available for provider "${t}"`:`Model "${e}" is not available for provider "${t}"`,a=r?.originalMessage;super(typeof a==`string`&&a.length>0?`${i}: ${a}`:i,r),this.model=e,this.provider=t,this.availableModels=n}},f=class extends e{code=`CIRCUIT_BREAKER_OPEN`;category=`system`;recoverable=!0;constructor(e=`Circuit breaker is open`,t){super(e,t)}},p=class extends e{pluginName;code=`PLUGIN_ERROR`;category=`system`;recoverable=!1;constructor(e,t,n){super(`Plugin Error (${t}): ${e}`,n),this.pluginName=t}},m=class extends e{code=`STORAGE_ERROR`;category=`system`;recoverable=!0;constructor(e,t){super(`Storage Error: ${e}`,t)}},h=class extends e{code=`CACHE_INTEGRITY_ERROR`;category=`system`;recoverable=!1;constructor(e,t){super(`Cache Integrity Error: ${e}`,t)}},g=class extends e{executable;code=`UNSUPPORTED_SHELL`;category=`user`;recoverable=!1;constructor(e){super(`Unsupported shell executable: ${e}`,{executable:e}),this.executable=e}};function _(e){return e===`darwin`?'Host OS: macOS (POSIX, BSD userland). Use BSD-flavored utilities: `sed -i ""` needs an empty backup arg, `date`/`grep`/`stat` flags differ from GNU. Prefer portable POSIX flags; avoid Linux/GNU-only options.':e===`linux`?"Host OS: Linux (POSIX, usually GNU coreutils, but distro/user setup varies). Prefer portable POSIX flags; do not assume a specific distro, and probe with `command -v` before relying on a non-standard tool.":`Host OS: ${e}; active shell family: POSIX sh/bash. Write portable POSIX syntax and avoid host-specific flags.`}function v(e,t){let n=x(e)===`bash`?`bash`:`sh`;return{command:e,kind:n,platform:t,commandArgs:e=>[`-c`,e],interactiveArgs:[],label:`${n} on ${t}`,syntaxHint:_(t)}}function y(e,t){return{command:e,kind:`powershell`,platform:t,commandArgs:e=>[`-NoProfile`,`-Command`,e],interactiveArgs:[`-NoProfile`],label:`PowerShell on ${t}`,syntaxHint:`Host OS: ${t}; active shell family: PowerShell. Write PowerShell syntax (not bash): e.g. \`Get-ChildItem\` not \`ls -la\`, \`\$env:VAR\` not \`\$VAR\`.`}}function b(e,t){return{command:e,kind:`cmd`,platform:t,commandArgs:e=>[`/d`,`/s`,`/c`,e],interactiveArgs:[],label:`cmd.exe on ${t}`,syntaxHint:`Host OS: ${t}; active shell family: Windows cmd.exe. Write cmd.exe syntax.`}}function x(e){return(e.split(/[\\/]/).at(-1)?.toLowerCase()??``).replace(/\.exe$/i,``)}function S(e,t){switch(x(e)){case`sh`:case`bash`:return v(e,t);case`powershell`:case`pwsh`:return y(e,t);case`cmd`:return b(e,t);default:throw new g(e)}}function C(e){let t=e?.trim();return t===void 0||t.length===0?void 0:t}function w(e={}){let t=e.env??process.env,n=e.platform??process.platform,r=C(e.executable);return r===void 0?n===`win32`?y(`powershell.exe`,n):v(C(t.SHELL)??`/bin/sh`,n):S(r,n)}const T=/^(?!0{32}$)[0-9a-f]{32}$/,E=/^(?!0{16}$)[0-9a-f]{16}$/;function D(e){return e.replaceAll(`-`,``).slice(0,16)}const O=D;function k(e){return E.test(e)}function A(e,t){if(!(!T.test(e)||!E.test(t)))return`00-${e}-${t}-01`}function j(e,t){if(e.allowedOrigins.length===0)return;let n=A(e.traceId,D(t));if(n!==void 0)return{traceparent:n,allowedOrigins:[...e.allowedOrigins]}}function M(e,t){return j(e,t)}function N(e,t,n){if(t?.subprocessClasses?.includes(e)!==!0)return;let r=A(t.traceId,n);return r===void 0?void 0:{TRACEPARENT:r}}function P(e,t,n={}){if(t===void 0||n.TRACEPARENT!==void 0)return{...e,...n};let{TRACESTATE:r,...i}=e;return{...i,...t,...n}}function F(e,t){if(e===void 0||t===void 0)return{};let n;try{n=new URL(e).origin}catch{return{}}return n===`null`||!t.allowedOrigins.includes(n)?{}:{traceparent:t.traceparent}}const I=e=>`\n…[output truncated: ${e} byte(s) dropped]`;function L(e){let t=e.retain??`head`,n=e.truncationMarker??I,r=Math.max(0,Math.floor(e.maxBytes)),i=new TextEncoder,a=[],o=0,s=0,c=e=>{let t=r-o;if(t<=0)return;let n=e.byteLength<=t?e:e.subarray(0,t);a.push(n),o+=n.byteLength},l=e=>{let t=e.byteLength<=r?e:e.subarray(e.byteLength-r);for(a.push(t),o+=t.byteLength;o>r&&a.length>0;){let e=a[0],t=o-r;e.byteLength<=t?(a.shift(),o-=e.byteLength):(a[0]=e.subarray(t),o-=t)}};return{append(e){let n=typeof e==`string`?i.encode(e):e;s+=n.byteLength,t===`head`?c(n):l(n)},get retainedBytes(){return o},get totalBytes(){return s},get droppedBytes(){return s-o},get truncated(){return s>o},toString(){let e=new Uint8Array(o),r=0;for(let t of a)e.set(t,r),r+=t.byteLength;a=a.length>1?[e]:a;let i=new TextDecoder().decode(e);if(s<=o)return i;let c=n(s-o);return t===`head`?`${i}${c}`:`${c.replace(/^\n/,``)}\n${i}`}}}const R={deny:3,ask:2,defer:1,allow:0};function z(e){return typeof e==`string`&&e in R}function B(e){if(!(typeof e!=`object`||!e)&&`additionalContext`in e)return String(e.additionalContext)}function V(e,t){let n=H(e);if(n===null){let t=e.trim();return{context:t?[t]:[]}}if(n.continue===!1)return{context:[],blockReason:typeof n.stopReason==`string`?n.stopReason:`Blocked by hook (continue: false)`};let r=n.hookSpecificOutput,i=[];if(t===`UserPromptSubmit`){let e=B(r);if(n.decision===`block`)return{context:e?[e]:[],blockReason:`Blocked by hook (decision: block)`};e&&i.push(e)}let a,o;if(t===`PreToolUse`&&typeof r==`object`&&r){let e=r;if(z(e.permissionDecision)){if(a=e.permissionDecision,a===`deny`)return{context:[],blockReason:`Blocked by hook (permissionDecision: deny)`,permissionDecision:a};e.updatedInput!==void 0&&(o=e.updatedInput)}}return typeof n.systemMessage==`string`&&n.systemMessage&&i.push(n.systemMessage),{context:i,...a!==void 0&&{permissionDecision:a},...o!==void 0&&{updatedInput:o}}}function H(e){let t=e.trim();if(!t.startsWith(`{`))return null;try{return JSON.parse(t)}catch{return null}}function U(e,t){if(typeof e!=`object`||!e||Array.isArray(e))return null;let n=e;if(n.continue===!1)return typeof n.stopReason==`string`&&n.stopReason?n.stopReason:`Blocked by hook (continue: false)`;if(t===`UserPromptSubmit`&&n.decision===`block`)return typeof n.reason==`string`&&n.reason?n.reason:`Blocked by hook (decision: block)`;if(t===`PreToolUse`){let e=n.hookSpecificOutput;if(typeof e==`object`&&e&&e.permissionDecision===`deny`)return`Blocked by hook (permissionDecision: deny)`}return null}function W(e){let t=e.replace(/\s+/g,` `).trim();return t.length>200?`${t.slice(0,200)}…`:t}function G(e,t,n){let r;try{r=JSON.parse(e)}catch(n){return{outcome:`error`,source:t,kind:`malformed-response`,reason:`Hook response is not valid JSON (${n instanceof Error?n.message:String(n)}): ${W(e)}`}}return K(r,t,n,e)}function K(e,t,n,r){if(typeof e!=`object`||!e||Array.isArray(e))return{outcome:`error`,source:t,kind:`malformed-response`,reason:`Hook response is not a JSON object: ${W(r)}`};let{ok:i,reason:a}=e;if(i===!0)return{outcome:`allow`,source:t,stdout:r};if(i===!1)return{outcome:`deny`,source:t,reason:typeof a==`string`&&a?a:`Blocked by ${t} hook`};let o=U(e,n);return o===null?{outcome:`error`,source:t,kind:`malformed-response`,reason:i===void 0?`Hook response has no boolean "ok" field: ${W(r)}`:`Hook response "ok" is ${typeof i}, not boolean: ${W(r)}`}:{outcome:`deny`,source:t,reason:o}}Object.defineProperty(exports,"A",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"C",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"D",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"E",{enumerable:!0,get:function(){return e}}),Object.defineProperty(exports,"O",{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,"S",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"T",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"_",{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return A}}),Object.defineProperty(exports,"b",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return M}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,"g",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"h",{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return L}}),Object.defineProperty(exports,"j",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"k",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,"m",{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return R}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return F}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return V}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return G}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,"v",{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,"w",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"x",{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,"y",{enumerable:!0,get:function(){return t}});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e={deny:3,
|
|
2
|
-
//# sourceMappingURL=verdict-decoder-
|
|
1
|
+
const e={deny:3,ask:2,defer:1,allow:0};function t(t){return typeof t==`string`&&t in e}function n(e){if(!(typeof e!=`object`||!e)&&`additionalContext`in e)return String(e.additionalContext)}function r(e,r){let a=i(e);if(a===null){let t=e.trim();return{context:t?[t]:[]}}if(a.continue===!1)return{context:[],blockReason:typeof a.stopReason==`string`?a.stopReason:`Blocked by hook (continue: false)`};let o=a.hookSpecificOutput,s=[];if(r===`UserPromptSubmit`){let e=n(o);if(a.decision===`block`)return{context:e?[e]:[],blockReason:`Blocked by hook (decision: block)`};e&&s.push(e)}let c,l;if(r===`PreToolUse`&&typeof o==`object`&&o){let e=o;if(t(e.permissionDecision)){if(c=e.permissionDecision,c===`deny`)return{context:[],blockReason:`Blocked by hook (permissionDecision: deny)`,permissionDecision:c};e.updatedInput!==void 0&&(l=e.updatedInput)}}return typeof a.systemMessage==`string`&&a.systemMessage&&s.push(a.systemMessage),{context:s,...c!==void 0&&{permissionDecision:c},...l!==void 0&&{updatedInput:l}}}function i(e){let t=e.trim();if(!t.startsWith(`{`))return null;try{return JSON.parse(t)}catch{return null}}function a(e,t){if(typeof e!=`object`||!e||Array.isArray(e))return null;let n=e;if(n.continue===!1)return typeof n.stopReason==`string`&&n.stopReason?n.stopReason:`Blocked by hook (continue: false)`;if(t===`UserPromptSubmit`&&n.decision===`block`)return typeof n.reason==`string`&&n.reason?n.reason:`Blocked by hook (decision: block)`;if(t===`PreToolUse`){let e=n.hookSpecificOutput;if(typeof e==`object`&&e&&e.permissionDecision===`deny`)return`Blocked by hook (permissionDecision: deny)`}return null}function o(e){let t=e.replace(/\s+/g,` `).trim();return t.length>200?`${t.slice(0,200)}…`:t}function s(e,t,n){let r;try{r=JSON.parse(e)}catch(n){return{outcome:`error`,source:t,kind:`malformed-response`,reason:`Hook response is not valid JSON (${n instanceof Error?n.message:String(n)}): ${o(e)}`}}return c(r,t,n,e)}function c(e,t,n,r){if(typeof e!=`object`||!e||Array.isArray(e))return{outcome:`error`,source:t,kind:`malformed-response`,reason:`Hook response is not a JSON object: ${o(r)}`};let{ok:i,reason:s}=e;if(i===!0)return{outcome:`allow`,source:t,stdout:r};if(i===!1)return{outcome:`deny`,source:t,reason:typeof s==`string`&&s?s:`Blocked by ${t} hook`};let c=a(e,n);return c===null?{outcome:`error`,source:t,kind:`malformed-response`,reason:i===void 0?`Hook response has no boolean "ok" field: ${o(r)}`:`Hook response "ok" is ${typeof i}, not boolean: ${o(r)}`}:{outcome:`deny`,source:t,reason:c}}export{e as n,r,s as t};
|
|
2
|
+
//# sourceMappingURL=verdict-decoder-Dz_rjoIZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verdict-decoder-Dz_rjoIZ.js","names":[],"sources":["../../src/hooks/response-protocol.ts","../../src/hooks/verdict-decoder.ts"],"sourcesContent":["/**\n * The Claude Code hook RESPONSE protocol: what an approving hook's stdout may say.\n *\n * This is a different contract from the outcome union in `types.ts`. The outcome says whether the\n * hook reached a verdict at all; this says what a response additionally requests — `continue: false`,\n * a `permissionDecision`, an `updatedInput`, injected context.\n *\n * `interpretAllowOutcome` is the whole interpretation of one approving body (issue #2191): what to\n * inject, whether it blocks, which `permissionDecision` it states and the `updatedInput` riding with\n * it. `runHooks` only loops and aggregates — priority across hooks and the result shape stay there.\n *\n * The two contracts are mostly independent, with ONE crossing point: `explicitBlockDirective` below. A body may\n * carry a directive that unambiguously means \"block\" while the `{ ok, reason }` verdict beside it is\n * undecodable, and that body HAS rendered a verdict — discarding it because a sibling field was\n * malformed would be fail-open in an enforcement gate, which is the defect SEC-015 exists to remove\n * rather than relocate.\n */\n\nimport type { THookEvent } from './types.js';\n\nexport type TPermissionDecision = 'allow' | 'deny' | 'ask' | 'defer';\n\n/**\n * Permission decision priority: deny=3 > ask=2 > defer=1 > allow=0. `defer` leaves the call to the\n * normal flow, so it outranks an `allow` but must not cancel another hook's `ask`.\n */\nexport const PERMISSION_PRIORITY: Record<string, number> = { deny: 3, ask: 2, defer: 1, allow: 0 };\n\n/**\n * What one `allow` outcome's stdout asks of the runner — declarative, so the runner aggregates and\n * this module decides what a body MEANS.\n */\nexport interface IAllowInterpretation {\n /** Text to append to the collected stdout: raw output, injected context, a system message. */\n readonly context: readonly string[];\n /** Present when the body blocks. `context` is still appended before the runner returns. */\n readonly blockReason?: string;\n /** PreToolUse only: the decision the body states, when it is one the protocol names. */\n readonly permissionDecision?: TPermissionDecision;\n /** PreToolUse only: an input rewrite riding alongside a named `permissionDecision`. */\n readonly updatedInput?: Record<string, unknown>;\n}\n\nfunction isPermissionDecision(value: unknown): value is TPermissionDecision {\n return typeof value === 'string' && value in PERMISSION_PRIORITY;\n}\n\nfunction additionalContextOf(specific: unknown): string | undefined {\n if (specific === null || typeof specific !== 'object') return undefined;\n if (!('additionalContext' in specific)) return undefined;\n return String((specific as Record<string, unknown>)['additionalContext']);\n}\n\n/** Decode one approving hook's stdout per the protocol (Claude Code compatible) for `event`. */\nexport function interpretAllowOutcome(stdout: string, event: THookEvent): IAllowInterpretation {\n const json = parseHookJson(stdout);\n if (json === null) {\n // Raw text stdout (non-JSON)\n const raw = stdout.trim();\n return { context: raw ? [raw] : [] };\n }\n // Common: continue: false → block\n if (json['continue'] === false) {\n return {\n context: [],\n blockReason:\n typeof json['stopReason'] === 'string'\n ? json['stopReason']\n : 'Blocked by hook (continue: false)',\n };\n }\n const specific = json['hookSpecificOutput'];\n const context: string[] = [];\n if (event === 'UserPromptSubmit') {\n const additional = additionalContextOf(specific);\n // decision: \"block\" → block, carrying the context the hook attached\n if (json['decision'] === 'block') {\n return {\n context: additional ? [additional] : [],\n blockReason: 'Blocked by hook (decision: block)',\n };\n }\n // additionalContext without block → inject into stdout\n if (additional) context.push(additional);\n }\n let permissionDecision: TPermissionDecision | undefined;\n let updatedInput: Record<string, unknown> | undefined;\n if (event === 'PreToolUse' && specific !== null && typeof specific === 'object') {\n const record = specific as Record<string, unknown>;\n if (isPermissionDecision(record['permissionDecision'])) {\n permissionDecision = record['permissionDecision'];\n // deny → immediate block; nothing else in the body is read\n if (permissionDecision === 'deny') {\n return {\n context: [],\n blockReason: 'Blocked by hook (permissionDecision: deny)',\n permissionDecision,\n };\n }\n if (record['updatedInput'] !== undefined) {\n updatedInput = record['updatedInput'] as Record<string, unknown>;\n }\n }\n }\n // systemMessage → inject into stdout for AI context\n if (typeof json['systemMessage'] === 'string' && json['systemMessage']) {\n context.push(json['systemMessage']);\n }\n return {\n context,\n ...(permissionDecision !== undefined && { permissionDecision }),\n ...(updatedInput !== undefined && { updatedInput }),\n };\n}\n\n/** Parse hook stdout as JSON if it starts with '{', otherwise return null. */\nfunction parseHookJson(stdout: string): Record<string, unknown> | null {\n const trimmed = stdout.trim();\n if (!trimmed.startsWith('{')) return null;\n try {\n return JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n // allow-fallback: hook stdout may be plain text; malformed JSON means raw stdout\n return null;\n }\n}\n\n/**\n * The reason an explicitly-blocking response gives, or `null` when the body requests no block ON\n * THIS EVENT.\n *\n * These three directives are the vocabulary `HOOK-CATALOG.md` names as blocking triggers, and each\n * is a decision the hook stated outright — unlike `ok`, which can be malformed into meaning nothing.\n * A body carrying one has spoken, whatever else in it did not decode.\n *\n * Scoped by event exactly as `runHooks` scopes them (issue #2196): `continue: false` blocks on every\n * event; `decision: \"block\"` is the `UserPromptSubmit` vocabulary; `permissionDecision: \"deny\"` is\n * the `PreToolUse` vocabulary. The decoder used to read all three on any event, so a body like\n * `{\"ok\": \"maybe\", \"decision\": \"block\"}` denied a tool call the runner would not have blocked — one\n * vocabulary, two sets of rules. Now there is one set.\n */\nexport function explicitBlockDirective(body: unknown, event: THookEvent): string | null {\n if (typeof body !== 'object' || body === null || Array.isArray(body)) return null;\n const record = body as Record<string, unknown>;\n\n if (record['continue'] === false) {\n return typeof record['stopReason'] === 'string' && record['stopReason']\n ? record['stopReason']\n : 'Blocked by hook (continue: false)';\n }\n if (event === 'UserPromptSubmit' && record['decision'] === 'block') {\n return typeof record['reason'] === 'string' && record['reason']\n ? record['reason']\n : 'Blocked by hook (decision: block)';\n }\n if (event === 'PreToolUse') {\n const specific = record['hookSpecificOutput'];\n if (typeof specific === 'object' && specific !== null) {\n if ((specific as Record<string, unknown>)['permissionDecision'] === 'deny') {\n return 'Blocked by hook (permissionDecision: deny)';\n }\n }\n }\n return null;\n}\n","/**\n * SEC-015 — the one decoder for a `{ ok, reason }` hook verdict.\n *\n * The HTTP, prompt, and agent executors all receive a hook's answer as this shape, and all three\n * decoded it the same wrong way: `(body as { ok: boolean }).ok` followed by a truthiness test. That\n * is not a decode, it is a coercion, and it fails in both directions — `{\"ok\": \"false\"}` is truthy\n * so the gate was disabled, while `{}` and `{\"ok\": null}` are falsy so a tool call was blocked by a\n * verdict no endpoint issued.\n *\n * `ok` must therefore be EXACTLY `true` or EXACTLY `false`. Everything else is the absence of a\n * verdict, not a quiet vote for one — UNLESS the same body carries an explicit block directive from\n * the Claude Code response protocol (`continue: false`, `decision: \"block\"`,\n * `permissionDecision: \"deny\"`), which is a decision the hook stated outright and which an\n * undecodable `ok` beside it does not retract — read with the same per-event scoping `runHooks`\n * applies (issue #2196), so decoder and runner cannot disagree about when a directive means anything.\n */\n\nimport { explicitBlockDirective } from './response-protocol.js';\n\nimport type { THookDefinition, THookEvent, THookOutcome } from './types.js';\n\n/** How much of an undecodable payload to quote back. Enough to identify it, not enough to flood a log. */\nconst REASON_EXCERPT_LIMIT = 200;\n\n/** A one-line, length-capped rendering of whatever arrived, for the `error` reason. */\nfunction excerpt(raw: string): string {\n const collapsed = raw.replace(/\\s+/g, ' ').trim();\n return collapsed.length > REASON_EXCERPT_LIMIT\n ? `${collapsed.slice(0, REASON_EXCERPT_LIMIT)}…`\n : collapsed;\n}\n\n/**\n * Decode a hook's RAW response text into an outcome — parsing included.\n *\n * Parsing lives here rather than at each call site because it was the same three lines in the HTTP,\n * prompt and agent executors, which is the shape this module exists to collapse. A body that is not\n * JSON and a body whose `ok` is not a boolean are both \"no verdict could be read\", and both quote\n * the payload back the same way.\n *\n * @param raw - The response text as it arrived.\n * @param source - The executor doing the decoding, carried onto the outcome for diagnostics.\n * @param event - The event the hook answered, which decides WHICH block directives count\n * (issue #2196): the decoder scopes them exactly as `runHooks` does.\n */\nexport function decodeHookVerdict(\n raw: string,\n source: THookDefinition['type'],\n event: THookEvent,\n): THookOutcome {\n let body: unknown;\n try {\n body = JSON.parse(raw) as unknown;\n } catch (err: unknown) {\n return {\n outcome: 'error',\n source,\n kind: 'malformed-response',\n reason: `Hook response is not valid JSON (${err instanceof Error ? err.message : String(err)}): ${excerpt(raw)}`,\n };\n }\n return decodeParsedVerdict(body, source, event, raw);\n}\n\n/** The decode proper, once the text is known to be JSON. Separated only so each half stays readable. */\nfunction decodeParsedVerdict(\n body: unknown,\n source: THookDefinition['type'],\n event: THookEvent,\n raw: string,\n): THookOutcome {\n if (typeof body !== 'object' || body === null || Array.isArray(body)) {\n return {\n outcome: 'error',\n source,\n kind: 'malformed-response',\n reason: `Hook response is not a JSON object: ${excerpt(raw)}`,\n };\n }\n\n const { ok, reason } = body as { ok?: unknown; reason?: unknown };\n\n if (ok === true) {\n return { outcome: 'allow', source, stdout: raw };\n }\n\n if (ok === false) {\n return {\n outcome: 'deny',\n source,\n reason: typeof reason === 'string' && reason ? reason : `Blocked by ${source} hook`,\n };\n }\n\n // Neither boolean, so the `{ ok }` verdict is undecodable. Before calling that \"no verdict\", ask\n // whether the SAME body carries an explicit block directive — `continue: false`,\n // `decision: \"block\"`, `permissionDecision: \"deny\"`. Those are unambiguous statements the hook\n // made outright, and an endpoint that wrote `{\"ok\": \"false\", \"continue\": false}` plainly meant to\n // block. Discarding that because `ok` was a string would be fail-open in an enforcement gate: the\n // same class of defect as reading the string as approval, pointed the other way. Which of the\n // three count is the event's call — the same scoping `runHooks` applies (issue #2196).\n const directive = explicitBlockDirective(body, event);\n if (directive !== null) {\n return { outcome: 'deny', source, reason: directive };\n }\n\n // Nothing in the body decided anything. Deliberately NOT folded into either verdict.\n return {\n outcome: 'error',\n source,\n kind: 'malformed-response',\n reason:\n ok === undefined\n ? `Hook response has no boolean \"ok\" field: ${excerpt(raw)}`\n : `Hook response \"ok\" is ${typeof ok}, not boolean: ${excerpt(raw)}`,\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robota-sdk/agent-core",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.0.0-beta.85",
|
|
4
|
+
"description": "Foundation of the Robota SDK: the Robota agent engine and the provider, tool, plugin and permission contracts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/node/index.js",
|
|
7
7
|
"types": "dist/node/index.d.ts",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"url": "https://github.com/woojubb/robota.git",
|
|
90
90
|
"directory": "packages/agent-core"
|
|
91
91
|
},
|
|
92
|
-
"homepage": "https://robota.io/",
|
|
92
|
+
"homepage": "https://docs.robota.io/en/packages/agent-core/",
|
|
93
93
|
"bugs": {
|
|
94
94
|
"url": "https://github.com/woojubb/robota/issues"
|
|
95
95
|
},
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var e=class extends Error{context;constructor(e,t){super(e),this.context=t,this.name=this.constructor.name,Object.setPrototypeOf(this,new.target.prototype)}},t=class extends e{code=`CONFIGURATION_ERROR`;category=`user`;recoverable=!1;constructor(e,t){super(`Configuration Error: ${e}`,t)}},n=class extends e{field;code=`VALIDATION_ERROR`;category=`user`;recoverable=!1;constructor(e,t,n){super(`Validation Error: ${e}`,n),this.field=t}},r=class extends e{issues;attempts;code=`STRUCTURED_OUTPUT_ERROR`;category=`provider`;recoverable=!0;constructor(e,t,n,r){super(`Structured Output Error: ${e}`,r),this.issues=t,this.attempts=n}},i=class extends e{provider;originalError;code=`PROVIDER_ERROR`;category=`provider`;recoverable=!0;status;type;constructor(e,t,n,r,i){super(`Provider Error (${t}): ${e}`,r),this.provider=t,this.originalError=n,i?.status!==void 0&&(this.status=i.status),i?.type!==void 0&&(this.type=i.type)}},a=class extends e{provider;code=`AUTHENTICATION_ERROR`;category=`user`;recoverable=!1;constructor(e,t,n){super(`Authentication Error: ${e}`,n),this.provider=t}},o=class extends e{retryAfter;provider;code=`RATE_LIMIT_ERROR`;category=`provider`;recoverable=!0;constructor(e,t,n,r){super(`Rate Limit Error: ${e}`,r),this.retryAfter=t,this.provider=n}},s=class extends e{originalError;code=`NETWORK_ERROR`;category=`system`;recoverable=!0;constructor(e,t,n){super(`Network Error: ${e}`,n),this.originalError=t}},c=class extends e{toolName;originalError;code=`TOOL_EXECUTION_ERROR`;category=`system`;recoverable=!1;constructor(e,t,n,r){super(`Tool Execution Error (${t}): ${e}`,r),this.toolName=t,this.originalError=n}},l=class extends e{toolName;callCount;maxSameToolInputs;code=`SAME_TOOL_INPUT_LOOP`;category=`system`;recoverable=!0;constructor(e,t,n,r){super(`Tool "${e}" was called with identical input ${t} times, past the maxSameToolInputs limit of ${n} — stopping the turn to break the loop`,r),this.toolName=e,this.callCount=t,this.maxSameToolInputs=n}},u=class extends e{availableModels;code=`MODEL_NOT_AVAILABLE`;category=`user`;recoverable=!1;constructor(e,t,n,r){super(`Model "${e}" is not available for provider "${t}"`,r),this.availableModels=n}},d=class extends e{code=`CIRCUIT_BREAKER_OPEN`;category=`system`;recoverable=!0;constructor(e=`Circuit breaker is open`,t){super(e,t)}},f=class extends e{pluginName;code=`PLUGIN_ERROR`;category=`system`;recoverable=!1;constructor(e,t,n){super(`Plugin Error (${t}): ${e}`,n),this.pluginName=t}},p=class extends e{code=`STORAGE_ERROR`;category=`system`;recoverable=!0;constructor(e,t){super(`Storage Error: ${e}`,t)}},m=class extends e{code=`CACHE_INTEGRITY_ERROR`;category=`system`;recoverable=!1;constructor(e,t){super(`Cache Integrity Error: ${e}`,t)}},h=class extends e{executable;code=`UNSUPPORTED_SHELL`;category=`user`;recoverable=!1;constructor(e){super(`Unsupported shell executable: ${e}`,{executable:e}),this.executable=e}};function g(e){return e===`darwin`?'Host OS: macOS (POSIX, BSD userland). Use BSD-flavored utilities: `sed -i ""` needs an empty backup arg, `date`/`grep`/`stat` flags differ from GNU. Prefer portable POSIX flags; avoid Linux/GNU-only options.':e===`linux`?"Host OS: Linux (POSIX, usually GNU coreutils, but distro/user setup varies). Prefer portable POSIX flags; do not assume a specific distro, and probe with `command -v` before relying on a non-standard tool.":`Host OS: ${e}; active shell family: POSIX sh/bash. Write portable POSIX syntax and avoid host-specific flags.`}function _(e,t){let n=b(e)===`bash`?`bash`:`sh`;return{command:e,kind:n,platform:t,commandArgs:e=>[`-c`,e],interactiveArgs:[],label:`${n} on ${t}`,syntaxHint:g(t)}}function v(e,t){return{command:e,kind:`powershell`,platform:t,commandArgs:e=>[`-NoProfile`,`-Command`,e],interactiveArgs:[`-NoProfile`],label:`PowerShell on ${t}`,syntaxHint:`Host OS: ${t}; active shell family: PowerShell. Write PowerShell syntax (not bash): e.g. \`Get-ChildItem\` not \`ls -la\`, \`\$env:VAR\` not \`\$VAR\`.`}}function y(e,t){return{command:e,kind:`cmd`,platform:t,commandArgs:e=>[`/d`,`/s`,`/c`,e],interactiveArgs:[],label:`cmd.exe on ${t}`,syntaxHint:`Host OS: ${t}; active shell family: Windows cmd.exe. Write cmd.exe syntax.`}}function b(e){return(e.split(/[\\/]/).at(-1)?.toLowerCase()??``).replace(/\.exe$/i,``)}function x(e,t){switch(b(e)){case`sh`:case`bash`:return _(e,t);case`powershell`:case`pwsh`:return v(e,t);case`cmd`:return y(e,t);default:throw new h(e)}}function S(e){let t=e?.trim();return t===void 0||t.length===0?void 0:t}function C(e={}){let t=e.env??process.env,n=e.platform??process.platform,r=S(e.executable);return r===void 0?n===`win32`?v(`powershell.exe`,n):_(S(t.SHELL)??`/bin/sh`,n):x(r,n)}const w=/^(?!0{32}$)[0-9a-f]{32}$/,T=/^(?!0{16}$)[0-9a-f]{16}$/;function E(e){return e.replaceAll(`-`,``).slice(0,16)}const D=E;function O(e){return T.test(e)}function k(e,t){if(!(!w.test(e)||!T.test(t)))return`00-${e}-${t}-01`}function A(e,t){if(e.allowedOrigins.length===0)return;let n=k(e.traceId,E(t));if(n!==void 0)return{traceparent:n,allowedOrigins:[...e.allowedOrigins]}}function j(e,t){return A(e,t)}function M(e,t,n){if(t?.subprocessClasses?.includes(e)!==!0)return;let r=k(t.traceId,n);return r===void 0?void 0:{TRACEPARENT:r}}function N(e,t,n={}){if(t===void 0||n.TRACEPARENT!==void 0)return{...e,...n};let{TRACESTATE:r,...i}=e;return{...i,...t,...n}}function P(e,t){if(e===void 0||t===void 0)return{};let n;try{n=new URL(e).origin}catch{return{}}return n===`null`||!t.allowedOrigins.includes(n)?{}:{traceparent:t.traceparent}}const F=e=>`\n…[output truncated: ${e} byte(s) dropped]`;function I(e){let t=e.retain??`head`,n=e.truncationMarker??F,r=Math.max(0,Math.floor(e.maxBytes)),i=new TextEncoder,a=[],o=0,s=0,c=e=>{let t=r-o;if(t<=0)return;let n=e.byteLength<=t?e:e.subarray(0,t);a.push(n),o+=n.byteLength},l=e=>{let t=e.byteLength<=r?e:e.subarray(e.byteLength-r);for(a.push(t),o+=t.byteLength;o>r&&a.length>0;){let e=a[0],t=o-r;e.byteLength<=t?(a.shift(),o-=e.byteLength):(a[0]=e.subarray(t),o-=t)}};return{append(e){let n=typeof e==`string`?i.encode(e):e;s+=n.byteLength,t===`head`?c(n):l(n)},get retainedBytes(){return o},get totalBytes(){return s},get droppedBytes(){return s-o},get truncated(){return s>o},toString(){let e=new Uint8Array(o),r=0;for(let t of a)e.set(t,r),r+=t.byteLength;a=a.length>1?[e]:a;let i=new TextDecoder().decode(e);if(s<=o)return i;let c=n(s-o);return t===`head`?`${i}${c}`:`${c.replace(/^\n/,``)}\n${i}`}}}export{l as C,n as D,c as E,e as S,r as T,u as _,D as a,i as b,j as c,h as d,C as f,t as g,d as h,A as i,M as l,m,k as n,E as o,a as p,O as r,N as s,I as t,P as u,s as v,p as w,o as x,f as y};
|
|
2
|
-
//# sourceMappingURL=bounded-output-DpjpS98g.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bounded-output-DpjpS98g.js","names":[],"sources":["../../src/utils/errors.ts","../../src/utils/platform-shell.ts","../../src/utils/trace-context.ts","../../src/utils/bounded-output.ts"],"sourcesContent":["/**\n * Reusable type definitions for error utilities\n */\n\n/**\n * Error context data type\n * Used for storing contextual information in error instances\n */\nexport type TErrorContextData = Record<\n string,\n string | number | boolean | Date | Error | string[] | undefined\n>;\n\n/**\n * Error external input type\n * Used for handling external errors from unknown sources\n */\nexport type TErrorExternalInput =\n Error | string | Record<string, string | number | boolean> | null | undefined;\n\n/**\n * Base error class for all Robota errors\n */\nexport abstract class RobotaError extends Error {\n abstract readonly code: string;\n abstract readonly category: 'user' | 'system' | 'provider';\n abstract readonly recoverable: boolean;\n\n constructor(\n message: string,\n public readonly context?: TErrorContextData,\n ) {\n super(message);\n this.name = this.constructor.name;\n\n // Ensure proper prototype chain for instanceof checks\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Configuration related errors\n */\nexport class ConfigurationError extends RobotaError {\n readonly code = 'CONFIGURATION_ERROR';\n readonly category = 'user' as const;\n readonly recoverable = false;\n\n constructor(message: string, context?: TErrorContextData) {\n super(`Configuration Error: ${message}`, context);\n }\n}\n\n/**\n * Input validation errors\n */\nexport class ValidationError extends RobotaError {\n readonly code = 'VALIDATION_ERROR';\n readonly category = 'user' as const;\n readonly recoverable = false;\n\n constructor(\n message: string,\n public readonly field?: string,\n context?: TErrorContextData,\n ) {\n super(`Validation Error: ${message}`, context);\n }\n}\n\n/**\n * Structured output validation exhausted its retry budget (CORE-015).\n *\n * Thrown by `run(input, { output })` when the model's final response still fails\n * schema validation after the configured number of retries. `issues` holds the\n * validation messages from the last attempt; `attempts` is the total number of\n * provider turns spent (initial + retries).\n */\nexport class StructuredOutputError extends RobotaError {\n readonly code = 'STRUCTURED_OUTPUT_ERROR';\n readonly category = 'provider' as const;\n readonly recoverable = true;\n\n constructor(\n message: string,\n public readonly issues: string[],\n public readonly attempts: number,\n context?: TErrorContextData,\n ) {\n super(`Structured Output Error: ${message}`, context);\n }\n}\n\n/** What the vendor said about a failed call, as far as it said anything. */\nexport interface IProviderFailureDetails {\n /** The HTTP status of the failed response; absent for a failure with no response (e.g. an SSE error event). */\n status?: number;\n /** The vendor's own error type, e.g. Anthropic's `overloaded_error`. */\n type?: string;\n}\n\n/**\n * Provider related errors\n */\nexport class ProviderError extends RobotaError {\n readonly code = 'PROVIDER_ERROR';\n readonly category = 'provider' as const;\n readonly recoverable = true;\n readonly status?: number;\n readonly type?: string;\n\n constructor(\n message: string,\n public readonly provider: string,\n public readonly originalError?: Error,\n context?: TErrorContextData,\n details?: IProviderFailureDetails,\n ) {\n super(`Provider Error (${provider}): ${message}`, context);\n if (details?.status !== undefined) this.status = details.status;\n if (details?.type !== undefined) this.type = details.type;\n }\n}\n\n/**\n * Authentication errors\n */\nexport class AuthenticationError extends RobotaError {\n readonly code = 'AUTHENTICATION_ERROR';\n readonly category = 'user' as const;\n readonly recoverable = false;\n\n constructor(\n message: string,\n public readonly provider?: string,\n context?: TErrorContextData,\n ) {\n super(`Authentication Error: ${message}`, context);\n }\n}\n\n/**\n * Rate limit errors\n */\nexport class RateLimitError extends RobotaError {\n readonly code = 'RATE_LIMIT_ERROR';\n readonly category = 'provider' as const;\n readonly recoverable = true;\n\n constructor(\n message: string,\n public readonly retryAfter?: number,\n public readonly provider?: string,\n context?: TErrorContextData,\n ) {\n super(`Rate Limit Error: ${message}`, context);\n }\n}\n\n/**\n * Network/connectivity errors\n */\nexport class NetworkError extends RobotaError {\n readonly code = 'NETWORK_ERROR';\n readonly category = 'system' as const;\n readonly recoverable = true;\n\n constructor(\n message: string,\n public readonly originalError?: Error,\n context?: TErrorContextData,\n ) {\n super(`Network Error: ${message}`, context);\n }\n}\n\n/**\n * Tool execution errors\n */\nexport class ToolExecutionError extends RobotaError {\n readonly code = 'TOOL_EXECUTION_ERROR';\n readonly category = 'system' as const;\n readonly recoverable = false;\n\n constructor(\n message: string,\n public readonly toolName: string,\n public readonly originalError?: Error,\n context?: TErrorContextData,\n ) {\n super(`Tool Execution Error (${toolName}): ${message}`, context);\n }\n}\n\n/**\n * The same-tool-input loop guard tripped — CORE-035.\n *\n * A tool was invoked with byte-identical serialized inputs more times than `maxSameToolInputs`\n * allows, so the turn stopped rather than looping. This is the AGENT giving up, not the user\n * cancelling: the SPEC used to promise an `AbortError` here, which `isAbortFailure` resolves as\n * `success: true, interrupted: true` — reporting a run that produced no answer as a success.\n *\n * Named rather than a bare `Error` for the reason the SPEC was reaching for by naming a type at all:\n * a caller must be able to tell \"the agent looped\" from \"the network died\". `RobotaError` carries\n * `code`/`category`/`recoverable` out through CORE-027's failure path intact.\n *\n * `recoverable` is TRUE: the loop is a property of this turn's prompt and tool set, not of the\n * system, and a caller that varies either can reasonably try again.\n */\nexport class SameToolInputLoopError extends RobotaError {\n readonly code = 'SAME_TOOL_INPUT_LOOP';\n readonly category = 'system' as const;\n readonly recoverable = true;\n\n constructor(\n public readonly toolName: string,\n public readonly callCount: number,\n public readonly maxSameToolInputs: number,\n context?: TErrorContextData,\n ) {\n super(\n `Tool \"${toolName}\" was called with identical input ${callCount} times, past the ` +\n `maxSameToolInputs limit of ${maxSameToolInputs} — stopping the turn to break the loop`,\n context,\n );\n }\n}\n\n/**\n * Model not available errors\n */\nexport class ModelNotAvailableError extends RobotaError {\n readonly code = 'MODEL_NOT_AVAILABLE';\n readonly category = 'user' as const;\n readonly recoverable = false;\n\n constructor(\n model: string,\n provider: string,\n public readonly availableModels?: string[],\n context?: TErrorContextData,\n ) {\n super(`Model \"${model}\" is not available for provider \"${provider}\"`, context);\n }\n}\n\n/**\n * Circuit breaker open error\n */\nexport class CircuitBreakerOpenError extends RobotaError {\n readonly code = 'CIRCUIT_BREAKER_OPEN';\n readonly category = 'system' as const;\n readonly recoverable = true;\n\n constructor(message: string = 'Circuit breaker is open', context?: TErrorContextData) {\n super(message, context);\n }\n}\n\n/**\n * Plugin errors\n */\nexport class PluginError extends RobotaError {\n readonly code = 'PLUGIN_ERROR';\n readonly category = 'system' as const;\n readonly recoverable = false;\n\n constructor(\n message: string,\n public readonly pluginName: string,\n context?: TErrorContextData,\n ) {\n super(`Plugin Error (${pluginName}): ${message}`, context);\n }\n}\n\n/**\n * Storage related errors\n */\nexport class StorageError extends RobotaError {\n readonly code = 'STORAGE_ERROR';\n readonly category = 'system' as const;\n readonly recoverable = true;\n\n constructor(message: string, context?: TErrorContextData) {\n super(`Storage Error: ${message}`, context);\n }\n}\n\n/**\n * Cache integrity validation errors\n */\nexport class CacheIntegrityError extends RobotaError {\n readonly code = 'CACHE_INTEGRITY_ERROR';\n readonly category = 'system' as const;\n readonly recoverable = false;\n\n constructor(message: string, context?: TErrorContextData) {\n super(`Cache Integrity Error: ${message}`, context);\n }\n}\n","/**\n * TERM-008: cross-platform shell resolution (SSOT).\n *\n * Single source of truth for \"which shell do we spawn, and how\", shared by every shell-running site.\n * Resolution is a pure function of one request so every branch is testable without the host shell.\n */\n\nimport { RobotaError } from './errors.js';\n\n/** Shell family — drives non-interactive arg shape, quoting, and LLM syntax guidance. */\nexport type TShellKind = 'bash' | 'sh' | 'powershell' | 'cmd';\n\n/** The active shell resolved for a platform, plus the metadata callers need to drive and describe it. */\nexport interface IPlatformShell {\n /** Executable to spawn (e.g. `/bin/sh`, `powershell.exe`, or `$SHELL`). */\n readonly command: string;\n /** Shell family. */\n readonly kind: TShellKind;\n /** Node platform this was resolved for (`process.platform`). */\n readonly platform: NodeJS.Platform;\n /** Args to run a single command string non-interactively. */\n commandArgs(command: string): string[];\n /** Args for an interactive shell session (drop-to-shell). */\n readonly interactiveArgs: string[];\n /** Human label for the active shell, for tool/UI descriptions (e.g. `PowerShell (Windows)`). */\n readonly label: string;\n /** One-line syntax guidance for an LLM authoring commands. */\n readonly syntaxHint: string;\n}\n\n/** Pure inputs for resolving one executable together with its command argument family. */\nexport interface IPlatformShellResolutionRequest {\n /** Request-local executable. A non-blank value has the highest precedence. */\n readonly executable?: string;\n /** Environment used for SHELL resolution. */\n readonly env?: NodeJS.ProcessEnv;\n /** Actual host platform retained in the resolved metadata. */\n readonly platform?: NodeJS.Platform;\n}\n\n/** An explicit executable whose basename has no supported command argument family. */\nexport class UnsupportedShellError extends RobotaError {\n readonly code = 'UNSUPPORTED_SHELL';\n readonly category = 'user' as const;\n readonly recoverable = false;\n\n constructor(public readonly executable: string) {\n super(`Unsupported shell executable: ${executable}`, { executable });\n }\n}\n\n/**\n * OS-family syntax guidance for the LLM. macOS and Linux are both POSIX but ship different userlands\n * (macOS = BSD coreutils, most Linux = GNU coreutils), so flags like `sed -i`, `date`, and `grep`\n * differ — naming the OS lets the model avoid Linux-only invocations on macOS and vice versa.\n */\nfunction posixSyntaxHint(platform: NodeJS.Platform): string {\n if (platform === 'darwin') {\n return 'Host OS: macOS (POSIX, BSD userland). Use BSD-flavored utilities: `sed -i \"\"` needs an empty backup arg, `date`/`grep`/`stat` flags differ from GNU. Prefer portable POSIX flags; avoid Linux/GNU-only options.';\n }\n if (platform === 'linux') {\n return 'Host OS: Linux (POSIX, usually GNU coreutils, but distro/user setup varies). Prefer portable POSIX flags; do not assume a specific distro, and probe with `command -v` before relying on a non-standard tool.';\n }\n return `Host OS: ${platform}; active shell family: POSIX sh/bash. Write portable POSIX syntax and avoid host-specific flags.`;\n}\n\nfunction posixShell(command: string, platform: NodeJS.Platform): IPlatformShell {\n const isBash = shellBasename(command) === 'bash';\n const kind: TShellKind = isBash ? 'bash' : 'sh';\n return {\n command,\n kind,\n platform,\n commandArgs: (cmd: string): string[] => ['-c', cmd],\n interactiveArgs: [],\n label: `${kind} on ${platform}`,\n syntaxHint: posixSyntaxHint(platform),\n };\n}\n\nfunction powerShell(command: string, platform: NodeJS.Platform): IPlatformShell {\n return {\n command,\n kind: 'powershell',\n platform,\n commandArgs: (cmd: string): string[] => ['-NoProfile', '-Command', cmd],\n interactiveArgs: ['-NoProfile'],\n label: `PowerShell on ${platform}`,\n syntaxHint:\n `Host OS: ${platform}; active shell family: PowerShell. Write PowerShell syntax (not bash): e.g. ` +\n '`Get-ChildItem` not `ls -la`, `$env:VAR` not `$VAR`.',\n };\n}\n\nfunction cmdShell(command: string, platform: NodeJS.Platform): IPlatformShell {\n return {\n command,\n kind: 'cmd',\n platform,\n commandArgs: (cmd: string): string[] => ['/d', '/s', '/c', cmd],\n interactiveArgs: [],\n label: `cmd.exe on ${platform}`,\n syntaxHint: `Host OS: ${platform}; active shell family: Windows cmd.exe. Write cmd.exe syntax.`,\n };\n}\n\nfunction shellBasename(command: string): string {\n const basename = command.split(/[\\\\/]/).at(-1)?.toLowerCase() ?? '';\n return basename.replace(/\\.exe$/i, '');\n}\n\nfunction explicitShell(command: string, platform: NodeJS.Platform): IPlatformShell {\n switch (shellBasename(command)) {\n case 'sh':\n case 'bash':\n return posixShell(command, platform);\n case 'powershell':\n case 'pwsh':\n return powerShell(command, platform);\n case 'cmd':\n return cmdShell(command, platform);\n default:\n throw new UnsupportedShellError(command);\n }\n}\n\nfunction nonBlank(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n return trimmed === undefined || trimmed.length === 0 ? undefined : trimmed;\n}\n\n/**\n * Resolve the shell to spawn for the current (or a given) platform.\n *\n * - request `executable` wins when non-blank.\n * - **win32:** PowerShell.\n * - **posix:** `$SHELL` if set, else `/bin/sh`.\n */\nexport function resolvePlatformShell(\n request: IPlatformShellResolutionRequest = {},\n): IPlatformShell {\n const env = request.env ?? process.env;\n const platform = request.platform ?? process.platform;\n const requestedExecutable = nonBlank(request.executable);\n if (requestedExecutable !== undefined) return explicitShell(requestedExecutable, platform);\n\n if (platform === 'win32') return powerShell('powershell.exe', platform);\n\n return posixShell(nonBlank(env['SHELL']) ?? '/bin/sh', platform);\n}\n","/**\n * Pure helpers for trusted W3C trace context. Strings and the WHATWG `URL` only, so they are the\n * same in the browser build and in every adapter that attaches the header.\n */\nimport type {\n IOutboundTraceContext,\n IRunTraceContext,\n ISubprocessTraceEnv,\n TSubprocessTraceClass,\n} from '../interfaces/trace-context';\n\nconst TRACE_ID = /^(?!0{32}$)[0-9a-f]{32}$/;\nconst SPAN_ID = /^(?!0{16}$)[0-9a-f]{16}$/;\n\n/**\n * The span ID an operation is exported under, derived from the ID core mints before it runs (a\n * provider call's call ID, a tool body's body ID). One derivation for both the exporter and the\n * outgoing header, so the span a recipient sees as its parent is the span the trace contains.\n */\nexport function spanIdFromMintedId(mintedId: string): string {\n return mintedId.replaceAll('-', '').slice(0, 16);\n}\n\n/** The provider-call name for {@link spanIdFromMintedId}, kept so existing callers keep working. */\nexport const providerCallSpanId: (callId: string) => string = spanIdFromMintedId;\n\n/** Whether `spanId` is a well-formed minted span ID: 16 lowercase hex characters, not all zero. */\nexport function isMintedSpanId(spanId: string): boolean {\n return SPAN_ID.test(spanId);\n}\n\n/** A sampled version-00 `traceparent`, or undefined when either identifier is invalid. */\nexport function buildTraceparent(traceId: string, spanId: string): string | undefined {\n if (!TRACE_ID.test(traceId) || !SPAN_ID.test(spanId)) return undefined;\n return `00-${traceId}-${spanId}-01`;\n}\n\n/** The outbound context for one invoked call, or undefined when there is nothing valid to send. */\nexport function outboundTraceContextFor(\n traceContext: IRunTraceContext,\n callId: string,\n): IOutboundTraceContext | undefined {\n if (traceContext.allowedOrigins.length === 0) return undefined;\n const traceparent = buildTraceparent(traceContext.traceId, spanIdFromMintedId(callId));\n if (traceparent === undefined) return undefined;\n return { traceparent, allowedOrigins: [...traceContext.allowedOrigins] };\n}\n\n/**\n * The outbound context for one tool body, keyed by the body ID core minted for it — never the\n * vendor's tool call ID, which is neither unique nor hex.\n */\nexport function toolTraceContextFor(\n traceContext: IRunTraceContext,\n toolBodyId: string,\n): IOutboundTraceContext | undefined {\n return outboundTraceContextFor(traceContext, toolBodyId);\n}\n\n/**\n * The environment one child process of `subprocessClass` receives, naming `spanId` as its parent,\n * or undefined when the host did not enable that class. Independent of the origin allowlist.\n */\nexport function traceEnvFor(\n subprocessClass: TSubprocessTraceClass,\n traceContext: IRunTraceContext | undefined,\n spanId: string,\n): ISubprocessTraceEnv | undefined {\n if (traceContext?.subprocessClasses?.includes(subprocessClass) !== true) return undefined;\n const traceparent = buildTraceparent(traceContext.traceId, spanId);\n return traceparent === undefined ? undefined : { TRACEPARENT: traceparent };\n}\n\n/**\n * A fresh child environment: `base`, then Robota's trace, then `overrides`. When Robota's value\n * applies, the ambient `TRACESTATE` is dropped because it belongs to a different parent. When\n * `overrides` sets its own `TRACEPARENT`, Robota's value does not apply and `base` passes unchanged.\n * `base` itself is never modified.\n */\nexport function subprocessTraceEnvironment(\n base: Readonly<Record<string, string | undefined>>,\n traceEnv: ISubprocessTraceEnv | undefined,\n overrides: Readonly<Record<string, string>> = {},\n): Record<string, string | undefined> {\n if (traceEnv === undefined || overrides['TRACEPARENT'] !== undefined) return { ...base, ...overrides };\n const { TRACESTATE: _ambientState, ...rest } = base;\n return { ...rest, ...traceEnv, ...overrides };\n}\n\n/**\n * The headers to add to a request whose effective base URL is `baseUrl`: `traceparent` when its\n * origin exactly equals a listed origin, nothing otherwise. Scheme, host and port must all match;\n * a subdomain or a different port is a different origin.\n */\nexport function traceHeadersFor(\n baseUrl: string | undefined,\n traceContext: IOutboundTraceContext | undefined,\n): Readonly<Record<string, string>> {\n if (baseUrl === undefined || traceContext === undefined) return {};\n let origin: string;\n try {\n origin = new URL(baseUrl).origin;\n } catch {\n return {};\n }\n if (origin === 'null' || !traceContext.allowedOrigins.includes(origin)) return {};\n return { traceparent: traceContext.traceparent };\n}\n","/**\n * ARCH-056 (#2161): the bounded output-retention contract for child-process execution.\n *\n * Every path that reads a child's stdout/stderr must bound memory WHILE the output is being read —\n * not cap a summary afterwards while retaining the whole log. Before this existed, `shell-tool`\n * could buffer for ten minutes, the hook `CommandExecutor` repeated the pattern, and a subagent\n * runner had rediscovered a 4 KiB tail on its own. This module names the policy once:\n *\n * - **Budget.** `maxBytes` is the most that is ever RETAINED; bytes beyond it are dropped as they\n * arrive, so memory is bounded by the budget, not by the child's lifetime.\n * - **Retention.** `head` keeps the first `maxBytes` (a tool result: what the command said first);\n * `tail` keeps the last `maxBytes` (a diagnostic: how it ended).\n * - **Truncation is visible.** `truncated`, `droppedBytes` and a marker in `toString()` say that\n * output was dropped and how much — never a silently shorter string.\n * - **No spill.** This contract never writes to disk; a caller that needs the whole stream owns a\n * log file (background tasks do), and this buffer is what stays in memory beside it.\n * - **Termination is not here.** Exceeding the budget drops bytes; whether the child is killed is\n * the caller's policy (CORE-023 owns process-tree termination).\n *\n * Chunks are `Uint8Array` (a Node `Buffer` is one), and decoding happens once at `toString()`, so a\n * multi-byte character split across a chunk boundary is never decoded twice.\n */\n\nexport type TOutputRetention = 'head' | 'tail';\n\nexport interface IBoundedOutputOptions {\n /** Most bytes ever retained. */\n readonly maxBytes: number;\n /** Which end to keep once over budget. Default `head`. */\n readonly retain?: TOutputRetention;\n /** Marker appended (head) or prepended (tail) to `toString()` when bytes were dropped. */\n readonly truncationMarker?: (droppedBytes: number) => string;\n}\n\nexport interface IBoundedOutput {\n append(chunk: Uint8Array | string): void;\n /** Bytes currently retained (≤ `maxBytes`). */\n readonly retainedBytes: number;\n /** Bytes the child produced in total, retained or not. */\n readonly totalBytes: number;\n readonly droppedBytes: number;\n readonly truncated: boolean;\n /** The retained output, decoded as UTF-8, with the truncation marker when bytes were dropped. */\n toString(): string;\n}\n\nconst DEFAULT_MARKER = (dropped: number): string =>\n `\\n…[output truncated: ${dropped} byte(s) dropped]`;\n\nexport function createBoundedOutput(options: IBoundedOutputOptions): IBoundedOutput {\n const retain = options.retain ?? 'head';\n const marker = options.truncationMarker ?? DEFAULT_MARKER;\n const maxBytes = Math.max(0, Math.floor(options.maxBytes));\n const encoder = new TextEncoder();\n let chunks: Uint8Array[] = [];\n let retained = 0;\n let total = 0;\n\n const appendHead = (bytes: Uint8Array): void => {\n const room = maxBytes - retained;\n if (room <= 0) return;\n const kept = bytes.byteLength <= room ? bytes : bytes.subarray(0, room);\n chunks.push(kept);\n retained += kept.byteLength;\n };\n\n const appendTail = (bytes: Uint8Array): void => {\n const kept = bytes.byteLength <= maxBytes ? bytes : bytes.subarray(bytes.byteLength - maxBytes);\n chunks.push(kept);\n retained += kept.byteLength;\n // Drop whole leading chunks first, then trim the oldest survivor — O(chunks), no re-copying.\n while (retained > maxBytes && chunks.length > 0) {\n const oldest = chunks[0] as Uint8Array;\n const excess = retained - maxBytes;\n if (oldest.byteLength <= excess) {\n chunks.shift();\n retained -= oldest.byteLength;\n } else {\n chunks[0] = oldest.subarray(excess);\n retained -= excess;\n }\n }\n };\n\n return {\n append(chunk) {\n const bytes = typeof chunk === 'string' ? encoder.encode(chunk) : chunk;\n total += bytes.byteLength;\n if (retain === 'head') appendHead(bytes);\n else appendTail(bytes);\n },\n get retainedBytes() {\n return retained;\n },\n get totalBytes() {\n return total;\n },\n get droppedBytes() {\n return total - retained;\n },\n get truncated() {\n return total > retained;\n },\n toString() {\n const joined = new Uint8Array(retained);\n let offset = 0;\n for (const chunk of chunks) {\n joined.set(chunk, offset);\n offset += chunk.byteLength;\n }\n chunks = chunks.length > 1 ? [joined] : chunks;\n const text = new TextDecoder().decode(joined);\n if (total <= retained) return text;\n const note = marker(total - retained);\n return retain === 'head' ? `${text}${note}` : `${note.replace(/^\\n/, '')}\\n${text}`;\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"verdict-decoder-Dk_w2NG9.js","names":[],"sources":["../../src/hooks/response-protocol.ts","../../src/hooks/verdict-decoder.ts"],"sourcesContent":["/**\n * The Claude Code hook RESPONSE protocol: what an approving hook's stdout may say.\n *\n * This is a different contract from the outcome union in `types.ts`. The outcome says whether the\n * hook reached a verdict at all; this says what a response additionally requests — `continue: false`,\n * a `permissionDecision`, an `updatedInput`, injected context.\n *\n * `interpretAllowOutcome` is the whole interpretation of one approving body (issue #2191): what to\n * inject, whether it blocks, which `permissionDecision` it states and the `updatedInput` riding with\n * it. `runHooks` only loops and aggregates — priority across hooks and the result shape stay there.\n *\n * The two contracts are mostly independent, with ONE crossing point: `explicitBlockDirective` below. A body may\n * carry a directive that unambiguously means \"block\" while the `{ ok, reason }` verdict beside it is\n * undecodable, and that body HAS rendered a verdict — discarding it because a sibling field was\n * malformed would be fail-open in an enforcement gate, which is the defect SEC-015 exists to remove\n * rather than relocate.\n */\n\nimport type { THookEvent } from './types.js';\n\nexport type TPermissionDecision = 'allow' | 'deny' | 'ask' | 'defer';\n\n/** Permission decision priority: deny=3 > defer=2 > ask=1 > allow=0 */\nexport const PERMISSION_PRIORITY: Record<string, number> = { deny: 3, defer: 2, ask: 1, allow: 0 };\n\n/**\n * What one `allow` outcome's stdout asks of the runner — declarative, so the runner aggregates and\n * this module decides what a body MEANS.\n */\nexport interface IAllowInterpretation {\n /** Text to append to the collected stdout: raw output, injected context, a system message. */\n readonly context: readonly string[];\n /** Present when the body blocks. `context` is still appended before the runner returns. */\n readonly blockReason?: string;\n /** PreToolUse only: the decision the body states, when it is one the protocol names. */\n readonly permissionDecision?: TPermissionDecision;\n /** PreToolUse only: an input rewrite riding alongside a named `permissionDecision`. */\n readonly updatedInput?: Record<string, unknown>;\n}\n\nfunction isPermissionDecision(value: unknown): value is TPermissionDecision {\n return typeof value === 'string' && value in PERMISSION_PRIORITY;\n}\n\nfunction additionalContextOf(specific: unknown): string | undefined {\n if (specific === null || typeof specific !== 'object') return undefined;\n if (!('additionalContext' in specific)) return undefined;\n return String((specific as Record<string, unknown>)['additionalContext']);\n}\n\n/** Decode one approving hook's stdout per the protocol (Claude Code compatible) for `event`. */\nexport function interpretAllowOutcome(stdout: string, event: THookEvent): IAllowInterpretation {\n const json = parseHookJson(stdout);\n if (json === null) {\n // Raw text stdout (non-JSON)\n const raw = stdout.trim();\n return { context: raw ? [raw] : [] };\n }\n // Common: continue: false → block\n if (json['continue'] === false) {\n return {\n context: [],\n blockReason:\n typeof json['stopReason'] === 'string'\n ? json['stopReason']\n : 'Blocked by hook (continue: false)',\n };\n }\n const specific = json['hookSpecificOutput'];\n const context: string[] = [];\n if (event === 'UserPromptSubmit') {\n const additional = additionalContextOf(specific);\n // decision: \"block\" → block, carrying the context the hook attached\n if (json['decision'] === 'block') {\n return {\n context: additional ? [additional] : [],\n blockReason: 'Blocked by hook (decision: block)',\n };\n }\n // additionalContext without block → inject into stdout\n if (additional) context.push(additional);\n }\n let permissionDecision: TPermissionDecision | undefined;\n let updatedInput: Record<string, unknown> | undefined;\n if (event === 'PreToolUse' && specific !== null && typeof specific === 'object') {\n const record = specific as Record<string, unknown>;\n if (isPermissionDecision(record['permissionDecision'])) {\n permissionDecision = record['permissionDecision'];\n // deny → immediate block; nothing else in the body is read\n if (permissionDecision === 'deny') {\n return {\n context: [],\n blockReason: 'Blocked by hook (permissionDecision: deny)',\n permissionDecision,\n };\n }\n if (record['updatedInput'] !== undefined) {\n updatedInput = record['updatedInput'] as Record<string, unknown>;\n }\n }\n }\n // systemMessage → inject into stdout for AI context\n if (typeof json['systemMessage'] === 'string' && json['systemMessage']) {\n context.push(json['systemMessage']);\n }\n return {\n context,\n ...(permissionDecision !== undefined && { permissionDecision }),\n ...(updatedInput !== undefined && { updatedInput }),\n };\n}\n\n/** Parse hook stdout as JSON if it starts with '{', otherwise return null. */\nfunction parseHookJson(stdout: string): Record<string, unknown> | null {\n const trimmed = stdout.trim();\n if (!trimmed.startsWith('{')) return null;\n try {\n return JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n // allow-fallback: hook stdout may be plain text; malformed JSON means raw stdout\n return null;\n }\n}\n\n/**\n * The reason an explicitly-blocking response gives, or `null` when the body requests no block ON\n * THIS EVENT.\n *\n * These three directives are the vocabulary `HOOK-CATALOG.md` names as blocking triggers, and each\n * is a decision the hook stated outright — unlike `ok`, which can be malformed into meaning nothing.\n * A body carrying one has spoken, whatever else in it did not decode.\n *\n * Scoped by event exactly as `runHooks` scopes them (issue #2196): `continue: false` blocks on every\n * event; `decision: \"block\"` is the `UserPromptSubmit` vocabulary; `permissionDecision: \"deny\"` is\n * the `PreToolUse` vocabulary. The decoder used to read all three on any event, so a body like\n * `{\"ok\": \"maybe\", \"decision\": \"block\"}` denied a tool call the runner would not have blocked — one\n * vocabulary, two sets of rules. Now there is one set.\n */\nexport function explicitBlockDirective(body: unknown, event: THookEvent): string | null {\n if (typeof body !== 'object' || body === null || Array.isArray(body)) return null;\n const record = body as Record<string, unknown>;\n\n if (record['continue'] === false) {\n return typeof record['stopReason'] === 'string' && record['stopReason']\n ? record['stopReason']\n : 'Blocked by hook (continue: false)';\n }\n if (event === 'UserPromptSubmit' && record['decision'] === 'block') {\n return typeof record['reason'] === 'string' && record['reason']\n ? record['reason']\n : 'Blocked by hook (decision: block)';\n }\n if (event === 'PreToolUse') {\n const specific = record['hookSpecificOutput'];\n if (typeof specific === 'object' && specific !== null) {\n if ((specific as Record<string, unknown>)['permissionDecision'] === 'deny') {\n return 'Blocked by hook (permissionDecision: deny)';\n }\n }\n }\n return null;\n}\n","/**\n * SEC-015 — the one decoder for a `{ ok, reason }` hook verdict.\n *\n * The HTTP, prompt, and agent executors all receive a hook's answer as this shape, and all three\n * decoded it the same wrong way: `(body as { ok: boolean }).ok` followed by a truthiness test. That\n * is not a decode, it is a coercion, and it fails in both directions — `{\"ok\": \"false\"}` is truthy\n * so the gate was disabled, while `{}` and `{\"ok\": null}` are falsy so a tool call was blocked by a\n * verdict no endpoint issued.\n *\n * `ok` must therefore be EXACTLY `true` or EXACTLY `false`. Everything else is the absence of a\n * verdict, not a quiet vote for one — UNLESS the same body carries an explicit block directive from\n * the Claude Code response protocol (`continue: false`, `decision: \"block\"`,\n * `permissionDecision: \"deny\"`), which is a decision the hook stated outright and which an\n * undecodable `ok` beside it does not retract — read with the same per-event scoping `runHooks`\n * applies (issue #2196), so decoder and runner cannot disagree about when a directive means anything.\n */\n\nimport { explicitBlockDirective } from './response-protocol.js';\n\nimport type { THookDefinition, THookEvent, THookOutcome } from './types.js';\n\n/** How much of an undecodable payload to quote back. Enough to identify it, not enough to flood a log. */\nconst REASON_EXCERPT_LIMIT = 200;\n\n/** A one-line, length-capped rendering of whatever arrived, for the `error` reason. */\nfunction excerpt(raw: string): string {\n const collapsed = raw.replace(/\\s+/g, ' ').trim();\n return collapsed.length > REASON_EXCERPT_LIMIT\n ? `${collapsed.slice(0, REASON_EXCERPT_LIMIT)}…`\n : collapsed;\n}\n\n/**\n * Decode a hook's RAW response text into an outcome — parsing included.\n *\n * Parsing lives here rather than at each call site because it was the same three lines in the HTTP,\n * prompt and agent executors, which is the shape this module exists to collapse. A body that is not\n * JSON and a body whose `ok` is not a boolean are both \"no verdict could be read\", and both quote\n * the payload back the same way.\n *\n * @param raw - The response text as it arrived.\n * @param source - The executor doing the decoding, carried onto the outcome for diagnostics.\n * @param event - The event the hook answered, which decides WHICH block directives count\n * (issue #2196): the decoder scopes them exactly as `runHooks` does.\n */\nexport function decodeHookVerdict(\n raw: string,\n source: THookDefinition['type'],\n event: THookEvent,\n): THookOutcome {\n let body: unknown;\n try {\n body = JSON.parse(raw) as unknown;\n } catch (err: unknown) {\n return {\n outcome: 'error',\n source,\n kind: 'malformed-response',\n reason: `Hook response is not valid JSON (${err instanceof Error ? err.message : String(err)}): ${excerpt(raw)}`,\n };\n }\n return decodeParsedVerdict(body, source, event, raw);\n}\n\n/** The decode proper, once the text is known to be JSON. Separated only so each half stays readable. */\nfunction decodeParsedVerdict(\n body: unknown,\n source: THookDefinition['type'],\n event: THookEvent,\n raw: string,\n): THookOutcome {\n if (typeof body !== 'object' || body === null || Array.isArray(body)) {\n return {\n outcome: 'error',\n source,\n kind: 'malformed-response',\n reason: `Hook response is not a JSON object: ${excerpt(raw)}`,\n };\n }\n\n const { ok, reason } = body as { ok?: unknown; reason?: unknown };\n\n if (ok === true) {\n return { outcome: 'allow', source, stdout: raw };\n }\n\n if (ok === false) {\n return {\n outcome: 'deny',\n source,\n reason: typeof reason === 'string' && reason ? reason : `Blocked by ${source} hook`,\n };\n }\n\n // Neither boolean, so the `{ ok }` verdict is undecodable. Before calling that \"no verdict\", ask\n // whether the SAME body carries an explicit block directive — `continue: false`,\n // `decision: \"block\"`, `permissionDecision: \"deny\"`. Those are unambiguous statements the hook\n // made outright, and an endpoint that wrote `{\"ok\": \"false\", \"continue\": false}` plainly meant to\n // block. Discarding that because `ok` was a string would be fail-open in an enforcement gate: the\n // same class of defect as reading the string as approval, pointed the other way. Which of the\n // three count is the event's call — the same scoping `runHooks` applies (issue #2196).\n const directive = explicitBlockDirective(body, event);\n if (directive !== null) {\n return { outcome: 'deny', source, reason: directive };\n }\n\n // Nothing in the body decided anything. Deliberately NOT folded into either verdict.\n return {\n outcome: 'error',\n source,\n kind: 'malformed-response',\n reason:\n ok === undefined\n ? `Hook response has no boolean \"ok\" field: ${excerpt(raw)}`\n : `Hook response \"ok\" is ${typeof ok}, not boolean: ${excerpt(raw)}`,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var e=class extends Error{context;constructor(e,t){super(e),this.context=t,this.name=this.constructor.name,Object.setPrototypeOf(this,new.target.prototype)}},t=class extends e{code=`CONFIGURATION_ERROR`;category=`user`;recoverable=!1;constructor(e,t){super(`Configuration Error: ${e}`,t)}},n=class extends e{field;code=`VALIDATION_ERROR`;category=`user`;recoverable=!1;constructor(e,t,n){super(`Validation Error: ${e}`,n),this.field=t}},r=class extends e{issues;attempts;code=`STRUCTURED_OUTPUT_ERROR`;category=`provider`;recoverable=!0;constructor(e,t,n,r){super(`Structured Output Error: ${e}`,r),this.issues=t,this.attempts=n}},i=class extends e{provider;originalError;code=`PROVIDER_ERROR`;category=`provider`;recoverable=!0;status;type;constructor(e,t,n,r,i){super(`Provider Error (${t}): ${e}`,r),this.provider=t,this.originalError=n,i?.status!==void 0&&(this.status=i.status),i?.type!==void 0&&(this.type=i.type)}},a=class extends e{provider;code=`AUTHENTICATION_ERROR`;category=`user`;recoverable=!1;constructor(e,t,n){super(`Authentication Error: ${e}`,n),this.provider=t}},o=class extends e{retryAfter;provider;code=`RATE_LIMIT_ERROR`;category=`provider`;recoverable=!0;constructor(e,t,n,r){super(`Rate Limit Error: ${e}`,r),this.retryAfter=t,this.provider=n}},s=class extends e{originalError;code=`NETWORK_ERROR`;category=`system`;recoverable=!0;constructor(e,t,n){super(`Network Error: ${e}`,n),this.originalError=t}},c=class extends e{toolName;originalError;code=`TOOL_EXECUTION_ERROR`;category=`system`;recoverable=!1;constructor(e,t,n,r){super(`Tool Execution Error (${t}): ${e}`,r),this.toolName=t,this.originalError=n}},l=class extends e{toolName;callCount;maxSameToolInputs;code=`SAME_TOOL_INPUT_LOOP`;category=`system`;recoverable=!0;constructor(e,t,n,r){super(`Tool "${e}" was called with identical input ${t} times, past the maxSameToolInputs limit of ${n} — stopping the turn to break the loop`,r),this.toolName=e,this.callCount=t,this.maxSameToolInputs=n}},u=class extends e{availableModels;code=`MODEL_NOT_AVAILABLE`;category=`user`;recoverable=!1;constructor(e,t,n,r){super(`Model "${e}" is not available for provider "${t}"`,r),this.availableModels=n}},d=class extends e{code=`CIRCUIT_BREAKER_OPEN`;category=`system`;recoverable=!0;constructor(e=`Circuit breaker is open`,t){super(e,t)}},f=class extends e{pluginName;code=`PLUGIN_ERROR`;category=`system`;recoverable=!1;constructor(e,t,n){super(`Plugin Error (${t}): ${e}`,n),this.pluginName=t}},p=class extends e{code=`STORAGE_ERROR`;category=`system`;recoverable=!0;constructor(e,t){super(`Storage Error: ${e}`,t)}},m=class extends e{code=`CACHE_INTEGRITY_ERROR`;category=`system`;recoverable=!1;constructor(e,t){super(`Cache Integrity Error: ${e}`,t)}},h=class extends e{executable;code=`UNSUPPORTED_SHELL`;category=`user`;recoverable=!1;constructor(e){super(`Unsupported shell executable: ${e}`,{executable:e}),this.executable=e}};function g(e){return e===`darwin`?'Host OS: macOS (POSIX, BSD userland). Use BSD-flavored utilities: `sed -i ""` needs an empty backup arg, `date`/`grep`/`stat` flags differ from GNU. Prefer portable POSIX flags; avoid Linux/GNU-only options.':e===`linux`?"Host OS: Linux (POSIX, usually GNU coreutils, but distro/user setup varies). Prefer portable POSIX flags; do not assume a specific distro, and probe with `command -v` before relying on a non-standard tool.":`Host OS: ${e}; active shell family: POSIX sh/bash. Write portable POSIX syntax and avoid host-specific flags.`}function _(e,t){let n=b(e)===`bash`?`bash`:`sh`;return{command:e,kind:n,platform:t,commandArgs:e=>[`-c`,e],interactiveArgs:[],label:`${n} on ${t}`,syntaxHint:g(t)}}function v(e,t){return{command:e,kind:`powershell`,platform:t,commandArgs:e=>[`-NoProfile`,`-Command`,e],interactiveArgs:[`-NoProfile`],label:`PowerShell on ${t}`,syntaxHint:`Host OS: ${t}; active shell family: PowerShell. Write PowerShell syntax (not bash): e.g. \`Get-ChildItem\` not \`ls -la\`, \`\$env:VAR\` not \`\$VAR\`.`}}function y(e,t){return{command:e,kind:`cmd`,platform:t,commandArgs:e=>[`/d`,`/s`,`/c`,e],interactiveArgs:[],label:`cmd.exe on ${t}`,syntaxHint:`Host OS: ${t}; active shell family: Windows cmd.exe. Write cmd.exe syntax.`}}function b(e){return(e.split(/[\\/]/).at(-1)?.toLowerCase()??``).replace(/\.exe$/i,``)}function x(e,t){switch(b(e)){case`sh`:case`bash`:return _(e,t);case`powershell`:case`pwsh`:return v(e,t);case`cmd`:return y(e,t);default:throw new h(e)}}function S(e){let t=e?.trim();return t===void 0||t.length===0?void 0:t}function C(e={}){let t=e.env??process.env,n=e.platform??process.platform,r=S(e.executable);return r===void 0?n===`win32`?v(`powershell.exe`,n):_(S(t.SHELL)??`/bin/sh`,n):x(r,n)}const w=/^(?!0{32}$)[0-9a-f]{32}$/,T=/^(?!0{16}$)[0-9a-f]{16}$/;function E(e){return e.replaceAll(`-`,``).slice(0,16)}const D=E;function O(e){return T.test(e)}function k(e,t){if(!(!w.test(e)||!T.test(t)))return`00-${e}-${t}-01`}function A(e,t){if(e.allowedOrigins.length===0)return;let n=k(e.traceId,E(t));if(n!==void 0)return{traceparent:n,allowedOrigins:[...e.allowedOrigins]}}function j(e,t){return A(e,t)}function M(e,t,n){if(t?.subprocessClasses?.includes(e)!==!0)return;let r=k(t.traceId,n);return r===void 0?void 0:{TRACEPARENT:r}}function N(e,t,n={}){if(t===void 0||n.TRACEPARENT!==void 0)return{...e,...n};let{TRACESTATE:r,...i}=e;return{...i,...t,...n}}function P(e,t){if(e===void 0||t===void 0)return{};let n;try{n=new URL(e).origin}catch{return{}}return n===`null`||!t.allowedOrigins.includes(n)?{}:{traceparent:t.traceparent}}const F=e=>`\n…[output truncated: ${e} byte(s) dropped]`;function I(e){let t=e.retain??`head`,n=e.truncationMarker??F,r=Math.max(0,Math.floor(e.maxBytes)),i=new TextEncoder,a=[],o=0,s=0,c=e=>{let t=r-o;if(t<=0)return;let n=e.byteLength<=t?e:e.subarray(0,t);a.push(n),o+=n.byteLength},l=e=>{let t=e.byteLength<=r?e:e.subarray(e.byteLength-r);for(a.push(t),o+=t.byteLength;o>r&&a.length>0;){let e=a[0],t=o-r;e.byteLength<=t?(a.shift(),o-=e.byteLength):(a[0]=e.subarray(t),o-=t)}};return{append(e){let n=typeof e==`string`?i.encode(e):e;s+=n.byteLength,t===`head`?c(n):l(n)},get retainedBytes(){return o},get totalBytes(){return s},get droppedBytes(){return s-o},get truncated(){return s>o},toString(){let e=new Uint8Array(o),r=0;for(let t of a)e.set(t,r),r+=t.byteLength;a=a.length>1?[e]:a;let i=new TextDecoder().decode(e);if(s<=o)return i;let c=n(s-o);return t===`head`?`${i}${c}`:`${c.replace(/^\n/,``)}\n${i}`}}}export{l as C,n as D,c as E,e as S,r as T,u as _,D as a,i as b,j as c,h as d,C as f,t as g,d as h,A as i,M as l,m,k as n,E as o,a as p,O as r,N as s,I as t,P as u,s as v,p as w,o as x,f as y};
|
|
2
|
-
//# sourceMappingURL=bounded-output-DpjpS98g.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bounded-output-DpjpS98g.js","names":[],"sources":["../../src/utils/errors.ts","../../src/utils/platform-shell.ts","../../src/utils/trace-context.ts","../../src/utils/bounded-output.ts"],"sourcesContent":["/**\n * Reusable type definitions for error utilities\n */\n\n/**\n * Error context data type\n * Used for storing contextual information in error instances\n */\nexport type TErrorContextData = Record<\n string,\n string | number | boolean | Date | Error | string[] | undefined\n>;\n\n/**\n * Error external input type\n * Used for handling external errors from unknown sources\n */\nexport type TErrorExternalInput =\n Error | string | Record<string, string | number | boolean> | null | undefined;\n\n/**\n * Base error class for all Robota errors\n */\nexport abstract class RobotaError extends Error {\n abstract readonly code: string;\n abstract readonly category: 'user' | 'system' | 'provider';\n abstract readonly recoverable: boolean;\n\n constructor(\n message: string,\n public readonly context?: TErrorContextData,\n ) {\n super(message);\n this.name = this.constructor.name;\n\n // Ensure proper prototype chain for instanceof checks\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Configuration related errors\n */\nexport class ConfigurationError extends RobotaError {\n readonly code = 'CONFIGURATION_ERROR';\n readonly category = 'user' as const;\n readonly recoverable = false;\n\n constructor(message: string, context?: TErrorContextData) {\n super(`Configuration Error: ${message}`, context);\n }\n}\n\n/**\n * Input validation errors\n */\nexport class ValidationError extends RobotaError {\n readonly code = 'VALIDATION_ERROR';\n readonly category = 'user' as const;\n readonly recoverable = false;\n\n constructor(\n message: string,\n public readonly field?: string,\n context?: TErrorContextData,\n ) {\n super(`Validation Error: ${message}`, context);\n }\n}\n\n/**\n * Structured output validation exhausted its retry budget (CORE-015).\n *\n * Thrown by `run(input, { output })` when the model's final response still fails\n * schema validation after the configured number of retries. `issues` holds the\n * validation messages from the last attempt; `attempts` is the total number of\n * provider turns spent (initial + retries).\n */\nexport class StructuredOutputError extends RobotaError {\n readonly code = 'STRUCTURED_OUTPUT_ERROR';\n readonly category = 'provider' as const;\n readonly recoverable = true;\n\n constructor(\n message: string,\n public readonly issues: string[],\n public readonly attempts: number,\n context?: TErrorContextData,\n ) {\n super(`Structured Output Error: ${message}`, context);\n }\n}\n\n/** What the vendor said about a failed call, as far as it said anything. */\nexport interface IProviderFailureDetails {\n /** The HTTP status of the failed response; absent for a failure with no response (e.g. an SSE error event). */\n status?: number;\n /** The vendor's own error type, e.g. Anthropic's `overloaded_error`. */\n type?: string;\n}\n\n/**\n * Provider related errors\n */\nexport class ProviderError extends RobotaError {\n readonly code = 'PROVIDER_ERROR';\n readonly category = 'provider' as const;\n readonly recoverable = true;\n readonly status?: number;\n readonly type?: string;\n\n constructor(\n message: string,\n public readonly provider: string,\n public readonly originalError?: Error,\n context?: TErrorContextData,\n details?: IProviderFailureDetails,\n ) {\n super(`Provider Error (${provider}): ${message}`, context);\n if (details?.status !== undefined) this.status = details.status;\n if (details?.type !== undefined) this.type = details.type;\n }\n}\n\n/**\n * Authentication errors\n */\nexport class AuthenticationError extends RobotaError {\n readonly code = 'AUTHENTICATION_ERROR';\n readonly category = 'user' as const;\n readonly recoverable = false;\n\n constructor(\n message: string,\n public readonly provider?: string,\n context?: TErrorContextData,\n ) {\n super(`Authentication Error: ${message}`, context);\n }\n}\n\n/**\n * Rate limit errors\n */\nexport class RateLimitError extends RobotaError {\n readonly code = 'RATE_LIMIT_ERROR';\n readonly category = 'provider' as const;\n readonly recoverable = true;\n\n constructor(\n message: string,\n public readonly retryAfter?: number,\n public readonly provider?: string,\n context?: TErrorContextData,\n ) {\n super(`Rate Limit Error: ${message}`, context);\n }\n}\n\n/**\n * Network/connectivity errors\n */\nexport class NetworkError extends RobotaError {\n readonly code = 'NETWORK_ERROR';\n readonly category = 'system' as const;\n readonly recoverable = true;\n\n constructor(\n message: string,\n public readonly originalError?: Error,\n context?: TErrorContextData,\n ) {\n super(`Network Error: ${message}`, context);\n }\n}\n\n/**\n * Tool execution errors\n */\nexport class ToolExecutionError extends RobotaError {\n readonly code = 'TOOL_EXECUTION_ERROR';\n readonly category = 'system' as const;\n readonly recoverable = false;\n\n constructor(\n message: string,\n public readonly toolName: string,\n public readonly originalError?: Error,\n context?: TErrorContextData,\n ) {\n super(`Tool Execution Error (${toolName}): ${message}`, context);\n }\n}\n\n/**\n * The same-tool-input loop guard tripped — CORE-035.\n *\n * A tool was invoked with byte-identical serialized inputs more times than `maxSameToolInputs`\n * allows, so the turn stopped rather than looping. This is the AGENT giving up, not the user\n * cancelling: the SPEC used to promise an `AbortError` here, which `isAbortFailure` resolves as\n * `success: true, interrupted: true` — reporting a run that produced no answer as a success.\n *\n * Named rather than a bare `Error` for the reason the SPEC was reaching for by naming a type at all:\n * a caller must be able to tell \"the agent looped\" from \"the network died\". `RobotaError` carries\n * `code`/`category`/`recoverable` out through CORE-027's failure path intact.\n *\n * `recoverable` is TRUE: the loop is a property of this turn's prompt and tool set, not of the\n * system, and a caller that varies either can reasonably try again.\n */\nexport class SameToolInputLoopError extends RobotaError {\n readonly code = 'SAME_TOOL_INPUT_LOOP';\n readonly category = 'system' as const;\n readonly recoverable = true;\n\n constructor(\n public readonly toolName: string,\n public readonly callCount: number,\n public readonly maxSameToolInputs: number,\n context?: TErrorContextData,\n ) {\n super(\n `Tool \"${toolName}\" was called with identical input ${callCount} times, past the ` +\n `maxSameToolInputs limit of ${maxSameToolInputs} — stopping the turn to break the loop`,\n context,\n );\n }\n}\n\n/**\n * Model not available errors\n */\nexport class ModelNotAvailableError extends RobotaError {\n readonly code = 'MODEL_NOT_AVAILABLE';\n readonly category = 'user' as const;\n readonly recoverable = false;\n\n constructor(\n model: string,\n provider: string,\n public readonly availableModels?: string[],\n context?: TErrorContextData,\n ) {\n super(`Model \"${model}\" is not available for provider \"${provider}\"`, context);\n }\n}\n\n/**\n * Circuit breaker open error\n */\nexport class CircuitBreakerOpenError extends RobotaError {\n readonly code = 'CIRCUIT_BREAKER_OPEN';\n readonly category = 'system' as const;\n readonly recoverable = true;\n\n constructor(message: string = 'Circuit breaker is open', context?: TErrorContextData) {\n super(message, context);\n }\n}\n\n/**\n * Plugin errors\n */\nexport class PluginError extends RobotaError {\n readonly code = 'PLUGIN_ERROR';\n readonly category = 'system' as const;\n readonly recoverable = false;\n\n constructor(\n message: string,\n public readonly pluginName: string,\n context?: TErrorContextData,\n ) {\n super(`Plugin Error (${pluginName}): ${message}`, context);\n }\n}\n\n/**\n * Storage related errors\n */\nexport class StorageError extends RobotaError {\n readonly code = 'STORAGE_ERROR';\n readonly category = 'system' as const;\n readonly recoverable = true;\n\n constructor(message: string, context?: TErrorContextData) {\n super(`Storage Error: ${message}`, context);\n }\n}\n\n/**\n * Cache integrity validation errors\n */\nexport class CacheIntegrityError extends RobotaError {\n readonly code = 'CACHE_INTEGRITY_ERROR';\n readonly category = 'system' as const;\n readonly recoverable = false;\n\n constructor(message: string, context?: TErrorContextData) {\n super(`Cache Integrity Error: ${message}`, context);\n }\n}\n","/**\n * TERM-008: cross-platform shell resolution (SSOT).\n *\n * Single source of truth for \"which shell do we spawn, and how\", shared by every shell-running site.\n * Resolution is a pure function of one request so every branch is testable without the host shell.\n */\n\nimport { RobotaError } from './errors.js';\n\n/** Shell family — drives non-interactive arg shape, quoting, and LLM syntax guidance. */\nexport type TShellKind = 'bash' | 'sh' | 'powershell' | 'cmd';\n\n/** The active shell resolved for a platform, plus the metadata callers need to drive and describe it. */\nexport interface IPlatformShell {\n /** Executable to spawn (e.g. `/bin/sh`, `powershell.exe`, or `$SHELL`). */\n readonly command: string;\n /** Shell family. */\n readonly kind: TShellKind;\n /** Node platform this was resolved for (`process.platform`). */\n readonly platform: NodeJS.Platform;\n /** Args to run a single command string non-interactively. */\n commandArgs(command: string): string[];\n /** Args for an interactive shell session (drop-to-shell). */\n readonly interactiveArgs: string[];\n /** Human label for the active shell, for tool/UI descriptions (e.g. `PowerShell (Windows)`). */\n readonly label: string;\n /** One-line syntax guidance for an LLM authoring commands. */\n readonly syntaxHint: string;\n}\n\n/** Pure inputs for resolving one executable together with its command argument family. */\nexport interface IPlatformShellResolutionRequest {\n /** Request-local executable. A non-blank value has the highest precedence. */\n readonly executable?: string;\n /** Environment used for SHELL resolution. */\n readonly env?: NodeJS.ProcessEnv;\n /** Actual host platform retained in the resolved metadata. */\n readonly platform?: NodeJS.Platform;\n}\n\n/** An explicit executable whose basename has no supported command argument family. */\nexport class UnsupportedShellError extends RobotaError {\n readonly code = 'UNSUPPORTED_SHELL';\n readonly category = 'user' as const;\n readonly recoverable = false;\n\n constructor(public readonly executable: string) {\n super(`Unsupported shell executable: ${executable}`, { executable });\n }\n}\n\n/**\n * OS-family syntax guidance for the LLM. macOS and Linux are both POSIX but ship different userlands\n * (macOS = BSD coreutils, most Linux = GNU coreutils), so flags like `sed -i`, `date`, and `grep`\n * differ — naming the OS lets the model avoid Linux-only invocations on macOS and vice versa.\n */\nfunction posixSyntaxHint(platform: NodeJS.Platform): string {\n if (platform === 'darwin') {\n return 'Host OS: macOS (POSIX, BSD userland). Use BSD-flavored utilities: `sed -i \"\"` needs an empty backup arg, `date`/`grep`/`stat` flags differ from GNU. Prefer portable POSIX flags; avoid Linux/GNU-only options.';\n }\n if (platform === 'linux') {\n return 'Host OS: Linux (POSIX, usually GNU coreutils, but distro/user setup varies). Prefer portable POSIX flags; do not assume a specific distro, and probe with `command -v` before relying on a non-standard tool.';\n }\n return `Host OS: ${platform}; active shell family: POSIX sh/bash. Write portable POSIX syntax and avoid host-specific flags.`;\n}\n\nfunction posixShell(command: string, platform: NodeJS.Platform): IPlatformShell {\n const isBash = shellBasename(command) === 'bash';\n const kind: TShellKind = isBash ? 'bash' : 'sh';\n return {\n command,\n kind,\n platform,\n commandArgs: (cmd: string): string[] => ['-c', cmd],\n interactiveArgs: [],\n label: `${kind} on ${platform}`,\n syntaxHint: posixSyntaxHint(platform),\n };\n}\n\nfunction powerShell(command: string, platform: NodeJS.Platform): IPlatformShell {\n return {\n command,\n kind: 'powershell',\n platform,\n commandArgs: (cmd: string): string[] => ['-NoProfile', '-Command', cmd],\n interactiveArgs: ['-NoProfile'],\n label: `PowerShell on ${platform}`,\n syntaxHint:\n `Host OS: ${platform}; active shell family: PowerShell. Write PowerShell syntax (not bash): e.g. ` +\n '`Get-ChildItem` not `ls -la`, `$env:VAR` not `$VAR`.',\n };\n}\n\nfunction cmdShell(command: string, platform: NodeJS.Platform): IPlatformShell {\n return {\n command,\n kind: 'cmd',\n platform,\n commandArgs: (cmd: string): string[] => ['/d', '/s', '/c', cmd],\n interactiveArgs: [],\n label: `cmd.exe on ${platform}`,\n syntaxHint: `Host OS: ${platform}; active shell family: Windows cmd.exe. Write cmd.exe syntax.`,\n };\n}\n\nfunction shellBasename(command: string): string {\n const basename = command.split(/[\\\\/]/).at(-1)?.toLowerCase() ?? '';\n return basename.replace(/\\.exe$/i, '');\n}\n\nfunction explicitShell(command: string, platform: NodeJS.Platform): IPlatformShell {\n switch (shellBasename(command)) {\n case 'sh':\n case 'bash':\n return posixShell(command, platform);\n case 'powershell':\n case 'pwsh':\n return powerShell(command, platform);\n case 'cmd':\n return cmdShell(command, platform);\n default:\n throw new UnsupportedShellError(command);\n }\n}\n\nfunction nonBlank(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n return trimmed === undefined || trimmed.length === 0 ? undefined : trimmed;\n}\n\n/**\n * Resolve the shell to spawn for the current (or a given) platform.\n *\n * - request `executable` wins when non-blank.\n * - **win32:** PowerShell.\n * - **posix:** `$SHELL` if set, else `/bin/sh`.\n */\nexport function resolvePlatformShell(\n request: IPlatformShellResolutionRequest = {},\n): IPlatformShell {\n const env = request.env ?? process.env;\n const platform = request.platform ?? process.platform;\n const requestedExecutable = nonBlank(request.executable);\n if (requestedExecutable !== undefined) return explicitShell(requestedExecutable, platform);\n\n if (platform === 'win32') return powerShell('powershell.exe', platform);\n\n return posixShell(nonBlank(env['SHELL']) ?? '/bin/sh', platform);\n}\n","/**\n * Pure helpers for trusted W3C trace context. Strings and the WHATWG `URL` only, so they are the\n * same in the browser build and in every adapter that attaches the header.\n */\nimport type {\n IOutboundTraceContext,\n IRunTraceContext,\n ISubprocessTraceEnv,\n TSubprocessTraceClass,\n} from '../interfaces/trace-context';\n\nconst TRACE_ID = /^(?!0{32}$)[0-9a-f]{32}$/;\nconst SPAN_ID = /^(?!0{16}$)[0-9a-f]{16}$/;\n\n/**\n * The span ID an operation is exported under, derived from the ID core mints before it runs (a\n * provider call's call ID, a tool body's body ID). One derivation for both the exporter and the\n * outgoing header, so the span a recipient sees as its parent is the span the trace contains.\n */\nexport function spanIdFromMintedId(mintedId: string): string {\n return mintedId.replaceAll('-', '').slice(0, 16);\n}\n\n/** The provider-call name for {@link spanIdFromMintedId}, kept so existing callers keep working. */\nexport const providerCallSpanId: (callId: string) => string = spanIdFromMintedId;\n\n/** Whether `spanId` is a well-formed minted span ID: 16 lowercase hex characters, not all zero. */\nexport function isMintedSpanId(spanId: string): boolean {\n return SPAN_ID.test(spanId);\n}\n\n/** A sampled version-00 `traceparent`, or undefined when either identifier is invalid. */\nexport function buildTraceparent(traceId: string, spanId: string): string | undefined {\n if (!TRACE_ID.test(traceId) || !SPAN_ID.test(spanId)) return undefined;\n return `00-${traceId}-${spanId}-01`;\n}\n\n/** The outbound context for one invoked call, or undefined when there is nothing valid to send. */\nexport function outboundTraceContextFor(\n traceContext: IRunTraceContext,\n callId: string,\n): IOutboundTraceContext | undefined {\n if (traceContext.allowedOrigins.length === 0) return undefined;\n const traceparent = buildTraceparent(traceContext.traceId, spanIdFromMintedId(callId));\n if (traceparent === undefined) return undefined;\n return { traceparent, allowedOrigins: [...traceContext.allowedOrigins] };\n}\n\n/**\n * The outbound context for one tool body, keyed by the body ID core minted for it — never the\n * vendor's tool call ID, which is neither unique nor hex.\n */\nexport function toolTraceContextFor(\n traceContext: IRunTraceContext,\n toolBodyId: string,\n): IOutboundTraceContext | undefined {\n return outboundTraceContextFor(traceContext, toolBodyId);\n}\n\n/**\n * The environment one child process of `subprocessClass` receives, naming `spanId` as its parent,\n * or undefined when the host did not enable that class. Independent of the origin allowlist.\n */\nexport function traceEnvFor(\n subprocessClass: TSubprocessTraceClass,\n traceContext: IRunTraceContext | undefined,\n spanId: string,\n): ISubprocessTraceEnv | undefined {\n if (traceContext?.subprocessClasses?.includes(subprocessClass) !== true) return undefined;\n const traceparent = buildTraceparent(traceContext.traceId, spanId);\n return traceparent === undefined ? undefined : { TRACEPARENT: traceparent };\n}\n\n/**\n * A fresh child environment: `base`, then Robota's trace, then `overrides`. When Robota's value\n * applies, the ambient `TRACESTATE` is dropped because it belongs to a different parent. When\n * `overrides` sets its own `TRACEPARENT`, Robota's value does not apply and `base` passes unchanged.\n * `base` itself is never modified.\n */\nexport function subprocessTraceEnvironment(\n base: Readonly<Record<string, string | undefined>>,\n traceEnv: ISubprocessTraceEnv | undefined,\n overrides: Readonly<Record<string, string>> = {},\n): Record<string, string | undefined> {\n if (traceEnv === undefined || overrides['TRACEPARENT'] !== undefined) return { ...base, ...overrides };\n const { TRACESTATE: _ambientState, ...rest } = base;\n return { ...rest, ...traceEnv, ...overrides };\n}\n\n/**\n * The headers to add to a request whose effective base URL is `baseUrl`: `traceparent` when its\n * origin exactly equals a listed origin, nothing otherwise. Scheme, host and port must all match;\n * a subdomain or a different port is a different origin.\n */\nexport function traceHeadersFor(\n baseUrl: string | undefined,\n traceContext: IOutboundTraceContext | undefined,\n): Readonly<Record<string, string>> {\n if (baseUrl === undefined || traceContext === undefined) return {};\n let origin: string;\n try {\n origin = new URL(baseUrl).origin;\n } catch {\n return {};\n }\n if (origin === 'null' || !traceContext.allowedOrigins.includes(origin)) return {};\n return { traceparent: traceContext.traceparent };\n}\n","/**\n * ARCH-056 (#2161): the bounded output-retention contract for child-process execution.\n *\n * Every path that reads a child's stdout/stderr must bound memory WHILE the output is being read —\n * not cap a summary afterwards while retaining the whole log. Before this existed, `shell-tool`\n * could buffer for ten minutes, the hook `CommandExecutor` repeated the pattern, and a subagent\n * runner had rediscovered a 4 KiB tail on its own. This module names the policy once:\n *\n * - **Budget.** `maxBytes` is the most that is ever RETAINED; bytes beyond it are dropped as they\n * arrive, so memory is bounded by the budget, not by the child's lifetime.\n * - **Retention.** `head` keeps the first `maxBytes` (a tool result: what the command said first);\n * `tail` keeps the last `maxBytes` (a diagnostic: how it ended).\n * - **Truncation is visible.** `truncated`, `droppedBytes` and a marker in `toString()` say that\n * output was dropped and how much — never a silently shorter string.\n * - **No spill.** This contract never writes to disk; a caller that needs the whole stream owns a\n * log file (background tasks do), and this buffer is what stays in memory beside it.\n * - **Termination is not here.** Exceeding the budget drops bytes; whether the child is killed is\n * the caller's policy (CORE-023 owns process-tree termination).\n *\n * Chunks are `Uint8Array` (a Node `Buffer` is one), and decoding happens once at `toString()`, so a\n * multi-byte character split across a chunk boundary is never decoded twice.\n */\n\nexport type TOutputRetention = 'head' | 'tail';\n\nexport interface IBoundedOutputOptions {\n /** Most bytes ever retained. */\n readonly maxBytes: number;\n /** Which end to keep once over budget. Default `head`. */\n readonly retain?: TOutputRetention;\n /** Marker appended (head) or prepended (tail) to `toString()` when bytes were dropped. */\n readonly truncationMarker?: (droppedBytes: number) => string;\n}\n\nexport interface IBoundedOutput {\n append(chunk: Uint8Array | string): void;\n /** Bytes currently retained (≤ `maxBytes`). */\n readonly retainedBytes: number;\n /** Bytes the child produced in total, retained or not. */\n readonly totalBytes: number;\n readonly droppedBytes: number;\n readonly truncated: boolean;\n /** The retained output, decoded as UTF-8, with the truncation marker when bytes were dropped. */\n toString(): string;\n}\n\nconst DEFAULT_MARKER = (dropped: number): string =>\n `\\n…[output truncated: ${dropped} byte(s) dropped]`;\n\nexport function createBoundedOutput(options: IBoundedOutputOptions): IBoundedOutput {\n const retain = options.retain ?? 'head';\n const marker = options.truncationMarker ?? DEFAULT_MARKER;\n const maxBytes = Math.max(0, Math.floor(options.maxBytes));\n const encoder = new TextEncoder();\n let chunks: Uint8Array[] = [];\n let retained = 0;\n let total = 0;\n\n const appendHead = (bytes: Uint8Array): void => {\n const room = maxBytes - retained;\n if (room <= 0) return;\n const kept = bytes.byteLength <= room ? bytes : bytes.subarray(0, room);\n chunks.push(kept);\n retained += kept.byteLength;\n };\n\n const appendTail = (bytes: Uint8Array): void => {\n const kept = bytes.byteLength <= maxBytes ? bytes : bytes.subarray(bytes.byteLength - maxBytes);\n chunks.push(kept);\n retained += kept.byteLength;\n // Drop whole leading chunks first, then trim the oldest survivor — O(chunks), no re-copying.\n while (retained > maxBytes && chunks.length > 0) {\n const oldest = chunks[0] as Uint8Array;\n const excess = retained - maxBytes;\n if (oldest.byteLength <= excess) {\n chunks.shift();\n retained -= oldest.byteLength;\n } else {\n chunks[0] = oldest.subarray(excess);\n retained -= excess;\n }\n }\n };\n\n return {\n append(chunk) {\n const bytes = typeof chunk === 'string' ? encoder.encode(chunk) : chunk;\n total += bytes.byteLength;\n if (retain === 'head') appendHead(bytes);\n else appendTail(bytes);\n },\n get retainedBytes() {\n return retained;\n },\n get totalBytes() {\n return total;\n },\n get droppedBytes() {\n return total - retained;\n },\n get truncated() {\n return total > retained;\n },\n toString() {\n const joined = new Uint8Array(retained);\n let offset = 0;\n for (const chunk of chunks) {\n joined.set(chunk, offset);\n offset += chunk.byteLength;\n }\n chunks = chunks.length > 1 ? [joined] : chunks;\n const text = new TextDecoder().decode(joined);\n if (total <= retained) return text;\n const note = marker(total - retained);\n return retain === 'head' ? `${text}${note}` : `${note.replace(/^\\n/, '')}\\n${text}`;\n },\n };\n}\n"],"mappings":"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"}
|