@tech-leads-club/harness-toolkit 0.4.1 → 0.4.2
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/bin/tlc-cli.ts +20 -1
- package/dist/compact-before.mjs +5 -5
- package/dist/doctor.mjs +6 -6
- package/dist/help-topic.mjs +1 -1
- package/dist/init-project.mjs +3 -3
- package/dist/install-runtime.mjs +6 -6
- package/dist/lessons-cli.mjs +3 -3
- package/dist/obs-cli.mjs +3 -3
- package/dist/price-lookup.mjs +2 -2
- package/dist/prompt-submit.mjs +5 -5
- package/dist/refresh-model-prices.mjs +3 -3
- package/dist/response-after.mjs +5 -5
- package/dist/run.mjs +6 -6
- package/dist/session-end.mjs +5 -5
- package/dist/session-start.mjs +5 -5
- package/dist/shim.mjs +28 -28
- package/dist/stop.mjs +27 -27
- package/dist/subagent-start.mjs +5 -5
- package/dist/subagent-stop.mjs +5 -5
- package/dist/support.mjs +5 -5
- package/dist/tlc-cli.mjs +93 -93
- package/dist/tool-after.mjs +28 -28
- package/dist/tool-before.mjs +5 -5
- package/dist/tool-failure.mjs +4 -4
- package/dist/uninstall-runtime.mjs +3 -3
- package/package.json +1 -1
- package/src/core/policy/policy.integrity.ts +13 -1
- package/src/platform/paths.ts +28 -1
package/dist/support.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import{existsSync as u6,statSync as pW}from"node:fs";import{join as h6}from"node:path";import{createHash as UZ}from"node:crypto";import{join as a6}from"node:path";import{appendFileSync as c6,existsSync as d6,mkdirSync as l6,readFileSync as i6}from"node:fs";import{dirname as n6}from"node:path";function P($,Z){l6(n6($),{recursive:!0}),c6($,`${JSON.stringify(Z)}
|
|
2
2
|
`)}function N($,Z){if(!d6($))return[];let J=[];for(let Q of i6($,"utf8").split(`
|
|
3
|
-
`)){let q=Q.trim();if(q.length===0)continue;try{J.push(JSON.parse(q))}catch{}}return J.slice(-Z)}import{homedir as r6}from"node:os";import{delimiter as eW,join as _,resolve as
|
|
3
|
+
`)){let q=Q.trim();if(q.length===0)continue;try{J.push(JSON.parse(q))}catch{}}return J.slice(-Z)}import{homedir as r6}from"node:os";import{delimiter as eW,dirname as $z,join as _,resolve as Zz}from"node:path";function BZ($){return _($,".tlc","harness")}function HZ(){return _(r6(),".tlc","harness")}function K$($=process.env){return $.TLC_HOME??HZ()}function M$($=process.env){return $.TLC_HOME_FROM_ENV==="0"?HZ():K$($)}function A($=process.env){return _(M$($),"config.json")}function b(){return _(M$(),"state")}function P8(){return _(b(),"obs-spool.jsonl")}function K($){return _(BZ($),"config.json")}function B($){return _(BZ($),"state")}function L($){return _(B($),"flags")}function C$($){return _(B($),"presence")}function j8($){return _(B($),"loops")}function N8($){return _(B($),"boot")}function m($){return _(B($),"policy-baseline")}var FZ="genesis";function O$($){return a6(B($),"attestation.jsonl")}function KZ($){let Z=[$.schema,$.ts,$.provider,$.session,$.policyFingerprint,String($.policyDiverged),$.railsActive.join(","),Object.entries($.decisionsByRule).sort((J,Q)=>J[0].localeCompare(Q[0])).map(([J,Q])=>`${J}=${Q}`).join(","),`${$.gates.pass}/${$.gates.fail}`,$.prev].join("\x00");return UZ("sha256").update(Z).digest("hex")}function A8($){return N(O$($),Number.MAX_SAFE_INTEGER)}function MZ($,Z){let Q=A8($).at(-1)?.self??FZ,q={schema:"harness.attestation.v1",...Z,prev:Q},X={...q,self:KZ(q)};return P(O$($),X),X}function CZ($){let Z=FZ;for(let[J,Q]of $.entries()){if(Q.prev!==Z)return{ok:!1,brokenAt:J,reason:"previous-hash-mismatch"};let{self:q,...X}=Q;if(KZ(X)!==q)return{ok:!1,brokenAt:J,reason:"content-hash-mismatch"};Z=q}return{ok:!0,length:$.length}}function OZ($){let Z=[...$].sort((J,Q)=>J.path.localeCompare(Q.path)).map((J)=>`${J.path}:${J.hash}`).join("|");return UZ("sha256").update(Z).digest("hex").slice(0,32)}var g='Enable: ask the agent "setup harness" (harness-init skill) or edit .tlc/harness/config.json';function s6($,Z){let J=$;for(let Q of Z.split(".").filter(Boolean)){if(!J||typeof J!=="object")return;J=J[Q]}return J}function L8($,Z){let J=s6($,Z.configPath);return Z.defaultOn?J===!1:J!==!0}function D8($,Z){return Z.capabilities.filter((J)=>L8($,J))}function _Z($,Z,J){return D8($,Z).filter((Q)=>Q.sinceCatalogVersion>J)}function IZ($){let Z=["Available for this project (not enabled yet):",""];for(let J of $)Z.push(`• ${J.title}`),Z.push(` Benefit: ${J.benefit}`),Z.push(` Trade-off: ${J.tradeOff}`),Z.push("");return Z.push(g),Z.join(`
|
|
4
4
|
`).trimEnd()}function PZ($){return`${$.title} off — ${$.tradeOff} — ${g}`}function jZ($){return`${$.length} available and not enabled: ${$.map((Z)=>Z.id).join(", ")}. ${g}`}import{existsSync as G7,readFileSync as B7}from"node:fs";import{join as EZ}from"node:path";import{randomBytes as t6}from"node:crypto";import{closeSync as e6,existsSync as $7,mkdirSync as AZ,openSync as Z7,readFileSync as J7,renameSync as Q7,rmSync as LZ,writeFileSync as q7}from"node:fs";import{dirname as DZ}from"node:path";function s($){let{attempt:Z,baseMs:J,capMs:Q,random:q=Math.random}=$,X=J*2**Z,W=Math.min(Q,X);return q()*W}function o6($){return new Promise((Z)=>setTimeout(Z,$))}async function NZ($,Z){let{attempts:J,shouldRetry:Q=()=>!0,sleep:q=o6,random:X=Math.random,baseMs:W=50,capMs:z=2000}=Z;for(let Y=0;Y<J;Y++)try{return await $()}catch(V){if(Y===J-1||!Q(V))throw V;await q(s({attempt:Y,baseMs:W,capMs:z,random:X}))}throw Error("retry: unreachable")}var X7=new Set(["EPERM","EBUSY","EACCES"]);function TZ($){return typeof $==="object"&&$!==null&&"code"in $?$.code:void 0}function RZ($){let Z=TZ($);return Z!==void 0&&X7.has(Z)}function W7($){return`${$}.${process.pid}.${t6(4).toString("hex")}.tmp`}async function o($,Z,J={}){let{attempts:Q=5,baseMs:q=20,capMs:X=500,random:W,sleep:z,rename:Y=Q7,writeFile:V=(F,U)=>q7(F,U,"utf8"),removeFile:G=(F)=>{try{LZ(F,{force:!0})}catch{}}}=J;AZ(DZ($),{recursive:!0});let H=W7($);V(H,`${JSON.stringify(Z,null,2)}
|
|
5
5
|
`);try{await NZ(()=>{Y(H,$)},{attempts:Q,baseMs:q,capMs:X,random:W,sleep:z,shouldRetry:RZ})}catch(F){throw G(H),F}}function z7($){if(!$7($))return null;try{return JSON.parse(J7($,"utf8"))}catch{return null}}function Y7($){return TZ($)==="EEXIST"||RZ($)}async function V7($,Z,J={}){let{openLock:Q=(z)=>e6(Z7(z,"wx")),lockSleep:q=(z)=>new Promise((Y)=>setTimeout(Y,z)),lockAttempts:X=200}=J;AZ(DZ($),{recursive:!0});let W=!1;for(let z=0;z<X;z++)try{Q($),W=!0;break}catch(Y){if(!Y7(Y))throw Y;await q(s({attempt:z,baseMs:10,capMs:200}))}if(!W)throw Error(`fs-atomic: could not acquire lock at ${$}`);try{return await Z()}finally{try{LZ($,{force:!0})}catch{}}}async function _$($,Z,J){let{lockPath:Q,afterWrite:q,openLock:X,lockSleep:W,lockAttempts:z,...Y}=J;return V7(Q,async()=>{let V=z7($),G=Z(V);return await o($,G,Y),q?.($),G},{openLock:X,lockSleep:W,lockAttempts:z})}function T8($){if(!G7($))return null;try{return JSON.parse(B7($,"utf8"))}catch{return null}}function H7($=K$()){return EZ($,"capabilities","catalog.json")}function kZ($=K$()){let Z=T8(H7($));if(!Z||typeof Z.catalogVersion!=="number"||!Array.isArray(Z.capabilities))return null;return Z}function xZ($){return T8(K($))}function SZ($){return EZ(B($),"runtime-seen.json")}function fZ($){let Z=T8(SZ($));if(!Z||typeof Z.catalogVersion!=="number"||Z.catalogVersion<0)return{catalogVersion:0};return Z}async function bZ($,Z){await o(SZ($),{catalogVersion:Z,updatedAt:new Date().toISOString()})}import{readFileSync as P7}from"node:fs";import{join as j7}from"node:path";import{existsSync as M7,readFileSync as C7}from"node:fs";import{join as yZ}from"node:path";import{spawn as U7}from"node:child_process";var F7=124;async function t($){let[Z,...J]=$.command;if(Z===void 0)return{exitCode:0,stdout:"",stderr:""};return await new Promise((Q,q)=>{let X=U7(Z,J,{cwd:$.cwd,stdio:["pipe","pipe","pipe"],env:$.env??process.env}),W="",z="",Y=!1,V=$.timeoutMs===void 0?void 0:setTimeout(()=>{Y=!0,X.kill("SIGKILL")},$.timeoutMs);if(X.stdout.on("data",(G)=>{W+=G.toString()}),X.stderr.on("data",(G)=>{z+=G.toString()}),X.on("error",(G)=>{if(V)clearTimeout(V);q(G)}),X.on("close",(G)=>{if(V)clearTimeout(V);if(Y){Q({exitCode:F7,stdout:W,stderr:`${z}
|
|
6
6
|
(process timed out)`});return}Q({exitCode:G??1,stdout:W,stderr:z})}),$.input!==void 0)X.stdin.write($.input);X.stdin.end()})}var K7=/[A-Za-z0-9._-]/;function C($){if($.length===0)return"_empty_";let Z="";for(let J of $){if(K7.test(J)){Z+=J;continue}for(let Q of Buffer.from(J,"utf8"))Z+=`%${Q.toString(16).toUpperCase().padStart(2,"0")}`}return Z}function I($){return $.replace(/\\/g,"/")}async function wZ($,Z){let J=await t({command:["git",...Z],cwd:$});if(J.exitCode!==0)return[];return J.stdout.split(`
|
|
@@ -12,7 +12,7 @@ import{existsSync as u6,statSync as pW}from"node:fs";import{join as h6}from"node
|
|
|
12
12
|
`).entries())Q.push({file:z,line:V+1,text:G})}return{index:nZ(Q,J),filesRead:X,truncated:W}}import{homedir as b8,tmpdir as n7}from"node:os";import{basename as r7,isAbsolute as oZ,relative as e,resolve as T,sep as a7}from"node:path";function s7($,Z=b8()){if($==="~")return Z;return $.startsWith(`~${a7}`)||$.startsWith("~/")?T(Z,$.slice(2)):$}function u($,Z,J=b8()){let Q=s7(Z,J);return oZ(Q)?T(Q):T($,Q)}function R($,Z){let J=e(T($),T(Z));return J===""||!J.startsWith("..")&&!oZ(J)}function tZ($,Z=n7()){return R(Z,$)}function o7($){let Z=T($);return Z===T(A())||R(b(),Z)}function P$($,Z){if(o7(Z))return!0;let J=I(e($,Z)||Z),Q=I(e($,K($))),q=I(e($,L($))),X=I(e($,B($)));return J===Q||J.startsWith(`${q}/`)||J.startsWith(`${X}/`)}var t7=[".ssh",".aws",".kube",".gnupg",".docker",".config/gh",".config/gcloud"],e7=new Set([".git-credentials",".netrc",".npmrc",".pgpass","credentials","id_dsa","id_ecdsa","id_ed25519","id_rsa"]),$Q=[".pem",".p12",".pfx"],ZQ=[".example",".sample",".template",".dist"];function JQ($){if($!==".env"&&!$.startsWith(".env."))return!1;return!ZQ.some((Z)=>$.endsWith(Z))}function y8($,Z=b8()){let J=r7($);if(JQ(J)||e7.has(J))return!0;if($Q.some((Q)=>J.endsWith(Q)))return!0;return t7.some((Q)=>R(T(Z,Q),$))}import{relative as zQ,resolve as YQ}from"node:path";var QQ=new Set([";","|","&",`
|
|
13
13
|
`]),qQ=new Set([" ","\t",'"',"'","$","`","\\",";","|","&","(",")"]);function XQ($){return $.includes("$")||$.includes("`")}function eZ($){let Z=/<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/,J=[],Q=$,q="";for(;;){let X=Z.exec(Q);if(!X){q+=Q;break}let W=Q.indexOf(`
|
|
14
14
|
`,X.index+X[0].length),z=q+Q.slice(0,X.index);if(q+=Q.slice(0,X.index),W===-1)break;let Y=new RegExp(`^\\s*${X[2]}\\s*$`,"m"),V=Q.slice(W+1),G=Y.exec(V);if(!G){J.push({body:V,prefix:z});break}J.push({body:V.slice(0,G.index),prefix:z}),Q=V.slice(G.index+G[0].length)}return{stripped:q,heredocs:J}}function $J($){return eZ($).heredocs}function E($){let Z=[],J=[],Q="",q=!1,X=!1,W=null,z=!1,Y=0;function V(){if(Q!==""||q)J.push({text:Q,unresolved:XQ(Q),quotedStart:X});Q="",q=!1,X=!1}function G(){if(V(),J.length>0)Z.push({words:J,opaque:z});J=[]}let{stripped:H}=eZ($);for(let F=0;F<H.length;F+=1){let U=H[F];if(W!==null){if(U===W)W=null;else Q+=U;continue}if(U==="\\"){let a=H[F+1];if(a!==void 0&&qQ.has(a))Q+=a,F+=1;else Q+=U;continue}if(U==='"'||U==="'"){if(W=U,Q===""&&!q)X=!0;q=!0;continue}if(U==="$"&&(H[F+1]==="("||H[F+1]==="{")){Y+=1,Q+=U;continue}if(Y>0&&(U===")"||U==="}")){Y-=1,Q+=U;continue}if(Y===0&&QQ.has(U)){G();continue}if(Y===0&&(U===" "||U==="\t")){V();continue}Q+=U}if(W!==null||Y>0)z=!0;return G(),z?Z.map((F)=>({...F,opaque:!0})):Z}var WQ=new Set(["command","doas","env","nice","nohup","sudo","time","xargs"]);function y($){let Z=0;while(Z<$.length){let J=$[Z];if(!J)return null;if(WQ.has(J.text)||J.text.startsWith("-")||J.text.includes("=")){Z+=1;continue}return{verb:J.text.split("/").pop()??J.text,args:$.slice(Z+1)}}return null}function ZJ($){return $.find((Z)=>!Z.text.startsWith("-")&&Z.text!=="")??null}var j$={kind:"allow"},VQ=new Set(["cat","cmp","diff","echo","file","grep","head","jq","less","ls","md5sum","more","od","printf","rg","sha256sum","stat","strings","tail","test","[","wc","xxd"]),GQ=new Set(["show","diff","log","status","ls-files","cat-file","blame"]),BQ=new Set(["ash","awk","bash","bun","dash","deno","ed","ex","fish","gawk","ksh","lua","node","perl","php","python","python2","python3","ruby","sed","sh","tclsh","zsh"]),HQ=new Set(["tlc","tlc.cmd"]),UQ=new Set(["pause","resume","grind","mode","init","gate","policy"]);function k($,Z,J){return{kind:"deny",detail:$,note:Z,...J?{remedy:J}:{}}}var JJ="Reading is allowed: run `tlc harness handoff` for handoff state, `tlc harness status` for posture and gates, `tlc harness doctor` for what the settings amount to, or use a proven reader (cat, head, jq, grep, ls, stat, test) on the path.";function w8($){let Z=I(zQ($,B($)));return Z.slice(0,Z.lastIndexOf("/"))}function FQ($,Z){return I(Z.words.map((Q)=>Q.text).join(" ")).includes(w8($))}function KQ($,Z){if(Z===YQ($))return!1;if(P$($,Z))return!0;return[K($),B($)].some((J)=>R(J,Z)||R(Z,J))}function QJ($,Z){if(Z.text==="")return!1;if(Z.unresolved)return I(Z.text).includes(w8($));return KQ($,u($,Z.text))}function MQ($){let Z=[];for(let J=0;J<$.length;J+=1){let Q=$[J];if(!Q||Q.quotedStart)continue;let q=/^(.*?)>{1,2}\|?(.*)$/s.exec(Q.text);if(!q)continue;let X=q[2]??"";if(X!==""){Z.push({text:X,unresolved:Q.unresolved,quotedStart:!1});continue}let W=$[J+1];if(W)Z.push(W),J+=1}return Z}function CQ($){let Z=$.filter((J)=>!J.text.startsWith("-")&&J.text!=="");if(Z[0]?.text.toLowerCase()!=="harness")return null;return(Z[1]?.text??"status").toLowerCase()}function OQ($,Z){for(let q of MQ(Z.words))if(QJ($,q))return k("a redirect in this command writes into the harness policy surface.","redirect into the policy surface");let J=y(Z.words);if(J&&HQ.has(J.verb)){let q=CQ(J.args);if(q!==null&&UQ.has(q))return k(`\`tlc harness ${q}\` changes harness policy, and policy is the operator's to change.`,`tlc harness ${q}`)}let Q=Z.words.filter((q)=>QJ($,q));if(Q.length===0&&!FQ($,Z))return j$;if(Z.opaque)return k("this command names the harness policy surface inside a segment this gate cannot split, so what it does to it cannot be established.","unprovable policy-surface access");if(!J)return k("the harness policy surface is named in a command with no resolvable verb.","policy-surface access with no verb");if(VQ.has(J.verb))return j$;if(J.verb==="git"){let q=ZJ(J.args)?.text.toLowerCase()??"";return GQ.has(q)?j$:k(`\`git ${q}\` can write the working tree, so it cannot be proven to only read the harness policy surface.`,`git ${q} on the policy surface`,JJ)}if(Q.some((q)=>q.unresolved))return k("this command builds a harness policy path at runtime, so the file it would touch cannot be established.","unresolvable policy-surface path");return k(`\`${J.verb}\` is not a proven reader, so this command cannot be shown to only read the harness policy surface.`,`${J.verb} on the policy surface`,JJ)}function _Q($,Z){let J=w8($);for(let Q of Z){if(!I(Q.body).includes(J))continue;let q=y(E(Q.prefix).at(-1)?.words??[]);if(q!==null&&BQ.has(q.verb))return k(`a heredoc fed to \`${q.verb}\` names the harness policy surface, so the body is a program rather than a document.`,"heredoc program naming the policy surface")}return j$}function qJ($,Z,J){for(let Q of J){let q=OQ($,Q);if(q.kind==="deny")return q}return _Q($,$J(Z))}var XJ=new Set(["dd","rm","rmdir","shred","truncate"]),WJ=new Set(["halt","poweroff","reboot","shutdown"]),IQ=new Set(["base64","cat","head","less","more","od","strings","tail","xxd"]),PQ=new Set(["Read","Edit","MultiEdit","NotebookEdit"]),zJ=new Set([".","eval","source"]),v8=new Set(["ash","bash","dash","fish","ksh","sh","zsh"]),m8=new Set(["aria2c","curl","fetch","http","httpie","https","wget"]),jQ=["169.254.169.254","169.254.170.2","100.100.100.200","metadata.google.internal"],NQ=new Set([...m8,"nc","ncat","socat","telnet","lwp-request"]);function AQ($){return[...m8].some((Z)=>new RegExp(`\\b${Z}\\b`).test($))}function LQ($,Z){let J=$.includes("|"),Q=!1;for(let q of Z){let X=y(q.words);if(!X)continue;let{verb:W,args:z}=X;if(J&&Q&&v8.has(W))return!0;if(v8.has(W)||zJ.has(W)){for(let Y of z)if((Y.text.includes("<(")||Y.unresolved)&&AQ(Y.text))return!0}Q=m8.has(W)}return!1}function DQ($,Z){return zJ.has($)||v8.has($)&&Z.some((J)=>J.text==="-c")}function TQ($,Z){return[`FLOOR: ${Z}`,"This is a floor rule — it has no config switch, because a limit an agent can turn off is not a limit.","Restate what you need and let the operator decide; do not work around this.",`rule=${$}`].join(`
|
|
15
|
-
`)}function j($,Z,J){return{kind:"deny",reason:TQ($,Z),userNote:`Floor rule ${$}: ${J}`,rule:$}}function YJ($){return $==="mkfs"||$.startsWith("mkfs.")}function RQ($){let Z=$.split("/").pop()??$;return XJ.has(Z)||WJ.has(Z)||YJ(Z)}function EQ($){return $.words.some((Z)=>Z.text.split(/\s+/).some(RQ))}function VJ($){return $.filter((Z)=>!Z.text.startsWith("-")&&Z.text!=="")}function kQ($){let Z=$.command;if(!Z)return{kind:"allow"};let J=E(Z);if(LQ(Z,J))return j("unprovable-execution","This runs a program fetched over the network, which does not exist for this gate to check. Download it to a file, read it, then run that file.","fetched program piped to a shell");for(let q of J){let X=y(q.words);if(!X)continue;let{verb:W,args:z}=X;if(DQ(W,z)&&EQ(q))return j("unprovable-destruction","A destructive verb appears inside a command this gate cannot expand, so its target cannot be established. Run it directly with a literal path instead.","hidden destructive verb");if(WJ.has(W))return j("machine-control",`\`${W}\` controls the machine, not the project.`,W);if(W==="git"&&z.some((G)=>G.text==="push")){if(z.some((H)=>H.text==="--force"||H.text==="-f"))return j("history-rewrite","`git push --force` discards remote commits that are not in your history. Use --force-with-lease, which refuses when the remote moved.","force push")}if(!(XJ.has(W)||YJ(W)))continue;let V=VJ(z);if(q.opaque||V.some((G)=>G.unresolved)||V.length===0)return j("unprovable-destruction",`\`${W}\` was called with a target this gate cannot resolve, so its safety cannot be established. Re-run it with a literal path inside the project.`,`unresolvable ${W}`);for(let G of V){let H=u($.projectDir,G.text);if(!R($.projectDir,H)&&!tZ(H))return j("outside-project-destruction",`\`${W}\` targets ${H}, which is outside the project and outside scratch space.`,`${W} outside project`)}}let Q=qJ($.projectDir,Z,J);if(Q.kind==="deny"){let q=Q.remedy??"Set a gate command with `tlc harness gate test-command` or `gate lint-command`, and run policy changes from your own terminal rather than from inside this session.";return j("policy-surface-write",`${Q.detail} ${q}`,Q.note)}return xQ(J,$.projectDir)}function xQ($,Z){for(let J of $){let Q=y(J.words);if(!Q)continue;if(NQ.has(Q.verb)){let q=Q.args.map((W)=>W.text).join(" "),X=jQ.find((W)=>q.includes(W));if(X!==void 0)return j("secret-access",`${X} is the instance metadata service, and \`${Q.verb}\` would copy the credentials it returns into the transcript.`,`read of ${X}`)}if(!IQ.has(Q.verb))continue;for(let q of VJ(Q.args)){if(q.unresolved)continue;let X=u(Z,q.text);if(y8(X))return j("secret-access",`\`${Q.verb}\` would read ${X} into the transcript. Credentials do not belong in an agent's context.`,`read of ${X}`)}}return{kind:"allow"}}function SQ($){let Z=$.filePath;if(!Z)return{kind:"allow"};if(!($.isReadEvent===!0||$.toolName!==void 0&&PQ.has($.toolName)))return{kind:"allow"};let Q=u($.projectDir,Z);if(!y8(Q))return{kind:"allow"};return j("secret-access",`${Q} holds credentials, and reading it would copy them into the transcript.`,`read of ${Q}`)}function GJ($){let Z=SQ($);if(Z.kind!=="allow")return Z;return kQ($)}import{createHash as rQ}from"node:crypto";import{existsSync as aQ,mkdirSync as sQ,readFileSync as oQ,unlinkSync as
|
|
15
|
+
`)}function j($,Z,J){return{kind:"deny",reason:TQ($,Z),userNote:`Floor rule ${$}: ${J}`,rule:$}}function YJ($){return $==="mkfs"||$.startsWith("mkfs.")}function RQ($){let Z=$.split("/").pop()??$;return XJ.has(Z)||WJ.has(Z)||YJ(Z)}function EQ($){return $.words.some((Z)=>Z.text.split(/\s+/).some(RQ))}function VJ($){return $.filter((Z)=>!Z.text.startsWith("-")&&Z.text!=="")}function kQ($){let Z=$.command;if(!Z)return{kind:"allow"};let J=E(Z);if(LQ(Z,J))return j("unprovable-execution","This runs a program fetched over the network, which does not exist for this gate to check. Download it to a file, read it, then run that file.","fetched program piped to a shell");for(let q of J){let X=y(q.words);if(!X)continue;let{verb:W,args:z}=X;if(DQ(W,z)&&EQ(q))return j("unprovable-destruction","A destructive verb appears inside a command this gate cannot expand, so its target cannot be established. Run it directly with a literal path instead.","hidden destructive verb");if(WJ.has(W))return j("machine-control",`\`${W}\` controls the machine, not the project.`,W);if(W==="git"&&z.some((G)=>G.text==="push")){if(z.some((H)=>H.text==="--force"||H.text==="-f"))return j("history-rewrite","`git push --force` discards remote commits that are not in your history. Use --force-with-lease, which refuses when the remote moved.","force push")}if(!(XJ.has(W)||YJ(W)))continue;let V=VJ(z);if(q.opaque||V.some((G)=>G.unresolved)||V.length===0)return j("unprovable-destruction",`\`${W}\` was called with a target this gate cannot resolve, so its safety cannot be established. Re-run it with a literal path inside the project.`,`unresolvable ${W}`);for(let G of V){let H=u($.projectDir,G.text);if(!R($.projectDir,H)&&!tZ(H))return j("outside-project-destruction",`\`${W}\` targets ${H}, which is outside the project and outside scratch space.`,`${W} outside project`)}}let Q=qJ($.projectDir,Z,J);if(Q.kind==="deny"){let q=Q.remedy??"Set a gate command with `tlc harness gate test-command` or `gate lint-command`, and run policy changes from your own terminal rather than from inside this session.";return j("policy-surface-write",`${Q.detail} ${q}`,Q.note)}return xQ(J,$.projectDir)}function xQ($,Z){for(let J of $){let Q=y(J.words);if(!Q)continue;if(NQ.has(Q.verb)){let q=Q.args.map((W)=>W.text).join(" "),X=jQ.find((W)=>q.includes(W));if(X!==void 0)return j("secret-access",`${X} is the instance metadata service, and \`${Q.verb}\` would copy the credentials it returns into the transcript.`,`read of ${X}`)}if(!IQ.has(Q.verb))continue;for(let q of VJ(Q.args)){if(q.unresolved)continue;let X=u(Z,q.text);if(y8(X))return j("secret-access",`\`${Q.verb}\` would read ${X} into the transcript. Credentials do not belong in an agent's context.`,`read of ${X}`)}}return{kind:"allow"}}function SQ($){let Z=$.filePath;if(!Z)return{kind:"allow"};if(!($.isReadEvent===!0||$.toolName!==void 0&&PQ.has($.toolName)))return{kind:"allow"};let Q=u($.projectDir,Z);if(!y8(Q))return{kind:"allow"};return j("secret-access",`${Q} holds credentials, and reading it would copy them into the transcript.`,`read of ${Q}`)}function GJ($){let Z=SQ($);if(Z.kind!=="allow")return Z;return kQ($)}import{createHash as rQ}from"node:crypto";import{existsSync as aQ,mkdirSync as sQ,readFileSync as oQ,unlinkSync as UY,writeFileSync as tQ}from"node:fs";import{dirname as eQ,join as $3}from"node:path";var fQ=["CLAUDE_PROJECT_DIR","CURSOR_PROJECT_DIR","TLC_PROJECT_DIR"];function BJ($=process.env){return fQ.filter((Z)=>($[Z]??"").trim()!=="")}var bQ=/\d+\s+(?:tests?|specs?|examples?)?\s*(?:fail(?:ed|ures?)?|pass(?:ed|ing)?|pending|skipped|todo|errors?)\b|(?:failures?|errors?)\s*=\s*\d+/gi,yQ=/^(?:tests?|specs?|failed|failures?|summary|results?)\b[:\s]*/i,wQ=/^[\s\d:;,|—–\-()=.✗×✕✖*]*$/,vQ=[/^\(fail\)\s*\S/i,/^not ok\s+\d+/i,/^---\s*FAIL:\s*\S/i,/^(?:FAIL|FAILED)\s+(?!\()\S/i],mQ=/^[✗×✕✖]\s+\S/,gQ=/(?:expect\(|toEqual|toBe\b|toMatch|toThrow|AssertionError|assert(?:ion)?\b|deep(?:Strict)?Equal|strictEqual|Expected\b|received\b|actual\b)/i;function uQ($){if(!/\d/.test($)||!/(?:fail|error)/i.test($))return!1;let Z=$.replace(yQ," ").replace(bQ," ");return wQ.test(Z)}function hQ($){if(vQ.some((Z)=>Z.test($)))return"test";if(uQ($))return"count";if(mQ.test($))return"test";return gQ.test($)?"assertion":"other"}function pQ($){let Z=[],J=[],Q=null,q=null;for(let X of $)switch(hQ(X)){case"count":Q??=X;break;case"test":{let W={summary:X,details:J.splice(0)};Z.push(W),q=W;break}case"assertion":if(q)q.details.push(X);else J.push(X);break;default:{let W={summary:X,details:J.splice(0)};Z.push(W),q=W}}if(J.length>0)Z.push({summary:J[0],details:J.slice(1)});return{failures:Z,firstCount:Q}}function cQ($){return $.replace(/\s+/g," ").trim().toLowerCase()}function dQ($){let Z=new Map;for(let J of $){let Q=cQ(J.summary),q=Z.get(Q);if(q){q.details.push(...J.details);continue}Z.set(Q,{summary:J.summary,details:[...J.details]})}return[...Z.values()]}function HJ($){let Z=[...new Set($.details)].join(`
|
|
16
16
|
`).slice(0,500);return Z?{summary:$.summary.slice(0,200),detail:Z}:{summary:$.summary.slice(0,200)}}function UJ($,Z,J){let{failures:Q,firstCount:q}=pQ($),X=dQ(Q);if(X.length===0){let Y={summary:`gate exited with code ${Z}`};return q?[{...Y,detail:q.slice(0,500)}]:[Y]}if(X.length<=J)return X.map(HJ);let W=X.slice(0,Math.max(1,J-1)).map(HJ),z=X.length-W.length;return[...W,{summary:`…and ${z} more failures in the gate output`}]}var lQ="ts|tsx|mts|cts|js|jsx|mjs|cjs|py|go|rb|rs|java|kt|swift|php|sh|sql",iQ=new RegExp(`(?:file://)?((?:[A-Za-z]:)?[\\w./~@+-]*[\\w-]\\.(?:${lQ}))(?=[:)\\s,'"\`]|$)`,"g");function nQ($){let Z=String.fromCharCode(27);return $.replaceAll(new RegExp(`${Z}\\[[0-9;]*[A-Za-z]`,"g"),"")}function FJ($,Z){let J=new Set,Q=[],q=`${Z.replace(/\/+$/,"")}/`;for(let X of nQ($).matchAll(iQ)){let W=X[1];if(!W)continue;let z=W.startsWith(q)?W.slice(q.length):W;if(J.has(z))continue;J.add(z),Q.push(z)}return Q}var KJ="harness.gate.v1";var Z3=8000,N$=8,J3=/(?:\bFAIL(?:ED)?\b|\bERROR\b|Error:|error\[|AssertionError|\bpanic:|✗|×|✕|✖|failures?\s*[:=]\s*[1-9])/i;function MJ($){return $3(B($),"last-gate.json")}function Q3($,Z=Z3){let J=$.trim();if(!J)return"";return J.length<=Z?J:J.slice(-Z)}function CJ($){if(!aQ($))return null;try{return JSON.parse(oQ($,"utf8"))}catch{return null}}function q3($){let Z=CJ($);if(!Z||typeof Z!=="object")return null;let J=Z.findings;if(!Array.isArray(J))return null;let Q=[];for(let q of J){if(!q||typeof q!=="object")continue;let X=q.summary;if(typeof X!=="string"||!X.trim())continue;let{detail:W,id:z}=q;if(Q.push({summary:X.trim().slice(0,200),detail:typeof W==="string"?W.slice(0,500):void 0,id:typeof z==="string"?z:void 0}),Q.length>=N$)break}return Q.length>0?Q:null}function X3($,Z,J=N$){let Q=$.split(`
|
|
17
17
|
`).map((W)=>W.trim()).filter((W)=>W.length>0&&!W.startsWith(">")),q=Q.filter((W)=>J3.test(W)),X=q.length>0?q:Q.slice(-J);return UJ(X,Z,J)}function OJ($){let Z=Q3($.output),J=$.reportPath?q3($.reportPath):null,Q=!Z||Z==="(no output captured)",q=J??($.exitCode===0?[]:Q?[{summary:`gate exited with code ${$.exitCode}`}]:X3(Z,$.exitCode)),X={schema:KJ,gate:$.gate,exitCode:$.exitCode,passed:$.exitCode===0,command:$.command,files:[...$.files],durationMs:$.durationMs,ts:new Date().toISOString(),outputTail:Z,findings:q,scopedEnv:BJ(),...$.inputsHash?{inputsHash:$.inputsHash}:{}},W=MJ($.root);return sQ(eQ(W),{recursive:!0}),tQ(W,`${JSON.stringify(X,null,2)}
|
|
18
18
|
`,"utf8"),X}function _J($){return CJ(MJ($))}function IJ($){let Z=JSON.stringify({gate:$.gate,exitCode:$.exitCode,files:[...$.files].sort(),findings:$.findings.map((J)=>J.summary).sort()});return rQ("sha256").update(Z).digest("hex").slice(0,16)}import{basename as W3}from"node:path";var z3=new Set(["just","make","task","mise","rake"]),Y3=new Set(["npm","yarn","pnpm"]),V3=new Set(["npx","bunx","dlx","exec"]),G3=/[*?[\]]/,B3=[/does not contain recipe/i,/no rule to make target/i,/unknown recipe/i,/missing script:/i,/task ".*" does not exist/i,/don't know how to build task/i];function H3($){let Z=$;while(Z.length>1&&V3.has(g8(Z[0])))Z=Z.slice(1);if(Z.length>2&&g8(Z[0])==="bun"&&Z[1]==="run")return["npm",...Z.slice(1)];return Z}function g8($){return W3($).replace(/\.(exe|cmd|bat)$/i,"").toLowerCase()}function A$($){return g8(H3($)[0]??"")}function u8($){return z3.has(A$($))}function U3($){return Y3.has(A$($))}function h8($,Z){if($.length===0)return{appends:!1,reason:"the command is empty"};if(Z==="always")return{appends:!0};if(Z==="never")return{appends:!1,reason:"appendFiles is set to never"};if(u8($))return{appends:!1,reason:`\`${A$($)}\` takes a target name, so a file path would read as a second target`};if(U3($))return{appends:!1,reason:`\`${A$($)}\` invokes a script, and whether a path reaches the runner is not something the harness can know`};let J=$.find((Q)=>G3.test(Q));if(J!==void 0)return{appends:!1,reason:`the command already scopes itself with \`${J}\`, so appending files would not narrow the run`};return{appends:!0}}function PJ($,Z){return h8($,Z).appends}function L$($){if($.exitCode===127)return!0;return B3.some((Z)=>Z.test($.output))}import{createHash as jJ}from"node:crypto";import{readFileSync as F3,statSync as K3}from"node:fs";import{isAbsolute as M3,resolve as C3}from"node:path";var O3=400,_3=12000000;function I3($,Z){if(M3(Z))return null;let J=C3($,Z);try{let Q=K3(J);if(!Q.isFile())return null;let q=F3(J);return{entry:`${Z}\x00${Q.size}\x00${jJ("sha256").update(q).digest("hex")}`,bytes:Q.size}}catch{return null}}function NJ($,Z,J){let Q=[...new Set(Z)].sort();if(Q.length>O3)return{hash:"",complete:!1};let q=[],X=0,W=!0;for(let Y of Q){let V=I3($,Y);if(V===null){W=!1;continue}if(X+=V.bytes,X>_3)return{hash:"",complete:!1};q.push(V.entry)}let z=JSON.stringify({command:[...J],entries:q});return{hash:jJ("sha256").update(z).digest("hex").slice(0,32),complete:W}}function p8($,Z){return $.complete&&$.hash.length>0&&Z===$.hash}function AJ($,Z,J){if($===null||$.gate!==Z)return null;return p8(J,$.inputsHash)?$:null}import{closeSync as P3,existsSync as DJ,mkdirSync as j3,openSync as N3,readFileSync as A3,statSync as L3,unlinkSync as TJ,writeFileSync as D3}from"node:fs";import{hostname as RJ}from"node:os";import{dirname as T3,join as R3}from"node:path";var c8=120000,EJ=1800000,E3=5000;class D$ extends Error{constructor($="gate lock timeout"){super($);this.name="GateLockTimeoutError"}}function kJ($){return R3(B($),"grind.lock")}function k3($){return new Promise((Z)=>setTimeout(Z,$))}function $$($){if(!DJ($))return null;try{return JSON.parse(A3($,"utf8"))}catch{return null}}function xJ($,Z){if(!DJ($))return null;try{return Z-L3($).mtimeMs}catch{return null}}function SJ($,Z){let J=xJ($,Z.now);return J!==null&&J>=Z.staleMs}function d8($){if(typeof $!=="object"||$===null)return!1;let Z=$;return typeof Z.provider==="string"&&typeof Z.session==="string"&&typeof Z.pid==="number"}function x3($,Z){let J=xJ($,Z.now);if(J===null||J<Z.graceMs)return!1;return!d8($$($))}var S3=($)=>{process.kill($,0)};function fJ($,Z=RJ(),J=S3){if(!d8($))return!1;let{host:Q,pid:q}=$;if(typeof Q!=="string"||Q!==Z)return!1;if(!Number.isInteger(q)||q<=0)return!1;try{return J(q),!1}catch(X){return X.code==="ESRCH"}}function f3($,Z){return SJ($,{now:Z.now,staleMs:Z.staleMs})||x3($,{now:Z.now,graceMs:Z.graceMs})||fJ($$($))}function l8($,Z={}){let J=kJ($),Q=Z.now??Date.now(),q=Z.staleMs??EJ;if(SJ(J,{now:Q,staleMs:q}))return null;let X=$$(J);if(!d8(X))return null;if(fJ(X))return null;return`${X.provider} session ${X.session} (pid ${X.pid})`}function bJ($,Z){j3(T3($),{recursive:!0});try{let J=N3($,"wx");try{D3(J,JSON.stringify(Z))}finally{P3(J)}return!0}catch{return!1}}function b3($,Z,J){if(!f3($,Z))return{stolen:!1,previousHolder:null};let Q=$$($);try{TJ($)}catch{return{stolen:!1,previousHolder:null}}return{stolen:bJ($,J),previousHolder:Q}}function y3($,Z){let J=$$($);if(J&&J.pid===Z)try{TJ($)}catch{}}async function yJ($,Z,J,Q,q={}){let X=q.waitMs??c8,W=q.staleMs??EJ,z=q.unreadableGraceMs??E3,Y=q.now??Date.now,V=q.sleep??k3,G=q.random??Math.random,H=q.baseMs??20,F=q.capMs??500,U=kJ($),a=Y()+X,_8=process.pid,zZ=0;while(!0){let YZ=Y(),VZ={provider:Z,session:J,pid:_8,acquired_at:new Date(YZ).toISOString(),host:RJ()};if(bJ(U,VZ))return LJ(U,_8,Q);let I8=b3(U,{staleMs:W,graceMs:z,now:YZ},VZ);if(I8.stolen){if(I8.previousHolder)q.onSteal?.(I8.previousHolder);return LJ(U,_8,Q)}if(Y()>=a){let GZ=l8($);throw new D$(`gate lock busy at ${U} after ${X}ms${GZ?` — held by ${GZ}`:""}`)}await V(s({attempt:zZ,baseMs:H,capMs:F,random:G})),zZ+=1}}async function LJ($,Z,J){try{return await J()}finally{y3($,Z)}}function wJ($){let Z=$.max??N$,J=$.artifact.findings.slice(0,Z);if(J.length===0)return[{id:`${$.artifact.gate}-0`,gate:$.artifact.gate,category:$.category,summary:`${$.artifact.gate} failed (exit ${$.artifact.exitCode})`}];return J.map((Q,q)=>({id:Q.id??`${$.artifact.gate}-${q}`,gate:$.artifact.gate,category:$.category,summary:Q.summary,detail:Q.detail}))}import{createHash as w3}from"node:crypto";import{existsSync as v3,mkdirSync as m3,readFileSync as vJ,writeFileSync as g3}from"node:fs";import{basename as u3,dirname as mJ,join as h3}from"node:path";var p3="harness.seal.v1";function i8($){return h3(mJ($),".seal",`${u3($)}.json`)}function gJ($){try{return w3("sha256").update(vJ($)).digest("hex")}catch{return null}}function T$($){let Z=gJ($);if(Z===null)return;try{m3(mJ(i8($)),{recursive:!0}),g3(i8($),JSON.stringify({schema:p3,hash:Z}))}catch{}}function R$($){if(!v3($))return"absent";let Z=null;try{let J=JSON.parse(vJ(i8($),"utf8"));Z=typeof J.hash==="string"?J.hash:null}catch{Z=null}if(Z===null)return"unsealed";return gJ($)===Z?"sealed":"diverged"}function E$($){return $!=="diverged"}function k$($,Z){return[`${Z} at ${$} changed without a harness write behind it, so it was not injected into this turn.`,"That file is read aloud to the model, so text placed in it reaches every later turn. Read it, and if the","contents are yours, the next harness write reseals it."].join(`
|
|
@@ -106,7 +106,7 @@ ${" ".repeat(4)}${Z.dim(O.bar)} ${z.detail}`:F});return[Z.heading(`LAST ${$.leng
|
|
|
106
106
|
`)}var U2=["comments"];function i$($){return U2.includes($)}function u9($){return $.filter((Z)=>!i$(Z))}function h9($,Z,J){return $.enabled&&!J&&i$(Z)&&$.rails.includes(Z)}function p9($){return{rail:$.rail,violations:$.violations,prose_injected:$.proseInjected,reading:$.violations===0?$.proseInjected?"held-with-prose":"held-without-prose":$.proseInjected?"violated-with-prose":"violated-without-prose"}}var WX=/(?:^|\n)\s*HARNESS_PLAN:\s*(.+?)\s*(?=\n|$)/,zX=/(?:^|\n)\s*HARNESS_PLAN_DEVIATION:\s*(.+?)\s*(?=\n|$)/g,YX=/\s+(?:—|--|-)\s+/;function VX($){return $.split(/[,\s]+/).map((Z)=>Z.trim()).filter((Z)=>Z.length>0)}function c9($){let J=WX.exec($)?.[1]?.trim();if(!J)return null;let Q=VX(J);if(Q.length===0)return null;return{paths:Q,snippet:`HARNESS_PLAN: ${J}`.slice(0,280)}}function d9($){let Z=[];for(let J of $.matchAll(zX)){let Q=J[1]?.trim();if(!Q)continue;let[q,...X]=Q.split(YX),W=q?.trim(),z=X.join(" ").trim();if(!W||z.length===0)continue;Z.push({path:W,reason:z})}return Z}import{existsSync as a9,readFileSync as UX}from"node:fs";import{join as FX}from"node:path";var GX={enabled:!1,maxInjectSession:5,maxInjectRetry:8,maxCharsSession:900,maxCharsRetry:1400,promoteHitCount:2,decayLambda:0.02,projectBoost:1.5,syncRulesFile:"auto",gardenOnSessionEnd:!0},z$={version:1,mode:"solo",codePaths:["src","apps","libs","packages"],grind:{enabled:!1,maxLoops:5,lintCommand:null,testCommand:null,appendFiles:"auto"},shipGate:{enabled:!1,runtimePathPrefixes:["src","apps","libs","packages","deploy","scripts"],runtimePathExcludes:[".tlc/","**/node_modules/","**/.git/"],evidenceDir:null,evidenceMaxAgeHours:48,emptyDiffAntiShip:!1,claimWindowMinutes:10},subagents:{enforceAllowlist:!1,requireModel:!1,allowedModels:[],blockedPatterns:["-fast(?:$|[^a-z0-9])","/fast(?:$|[^a-z0-9])"],minEffort:null,blockParentFast:!1,blockMode:"deny",readOnlyTypes:["explore"]},docs:{command:null,severity:"warn"},observe:{enabled:!1,rails:[]},comments:{enabled:!1,onViolation:"followup",mode:"declared"},supplyChain:{enabled:!1},duplication:{enabled:!1,minRun:D},obs:{globalSpool:!1,includePayloads:x.includePayloads,maxAttrChars:x.maxAttrChars,sessionCostAlertUsd:x.sessionCostAlertUsd,retentionDays:x.retentionDays},untrustedContent:{mode:"frame",enabled:!1,extraTools:[],extraCommandPatterns:[]},planGate:{enabled:!1,windowMinutes:120},rules:{enabled:!1},shell:{catastrophicAsk:!0,stallDetection:!1,stallRepeatThreshold:3},intelligence:{gapFeedback:!0,failureClassification:!0,progressiveHandoff:!0,progressiveContext:!0,autopilot:!0,idleTurnGate:!1,budgetContinue:!1,budgetContinueAfterLoops:3,lessons:{...GX}},mcpPrime:[],bootstrapExtra:[]};import{existsSync as i9,readFileSync as BX}from"node:fs";import{join as n9}from"node:path";var F2=["paired","solo","focus"],l9="solo";function n$($){return typeof $==="string"&&F2.includes($)}function HX($){let Z=n9(B($),"harness-mode");if(!i9(Z))return null;try{return BX(Z,"utf8").trim().toLowerCase()}catch{return null}}function r9($,Z){let J=HX($);if(n$(J))return{mode:J,origin:"file"};for(let Q of["focus","paired"])if(i9(n9(L($),Q)))return{mode:Q,origin:"flag"};if(n$(Z))return{mode:Z,origin:"config"};if(Z===void 0||Z===null)return{mode:l9,origin:"config"};return{mode:l9,origin:"fallback",invalid:String(Z)}}function K2($){if(!a9($))return null;try{return JSON.parse(UX($,"utf8"))}catch{return null}}function M2($,Z){return{...$,...Z,grind:{...$.grind,...Z.grind},shipGate:{...$.shipGate,...Z.shipGate},subagents:{...$.subagents,...Z.subagents},docs:{...$.docs,...Z.docs},observe:{...$.observe,...Z.observe},comments:{...$.comments,...Z.comments},supplyChain:{...$.supplyChain,...Z.supplyChain},duplication:{...$.duplication,...Z.duplication},obs:{...$.obs,...Z.obs},untrustedContent:{...$.untrustedContent,...Z.untrustedContent},planGate:{...$.planGate,...Z.planGate},shell:{...$.shell,...Z.shell},intelligence:{...$.intelligence,...Z.intelligence,lessons:{...$.intelligence.lessons,...Z.intelligence?.lessons}},codePaths:Z.codePaths??$.codePaths,mcpPrime:Z.mcpPrime??$.mcpPrime,bootstrapExtra:Z.bootstrapExtra??$.bootstrapExtra}}function KX($,Z){return a9(FX(L($),Z))}function C2($){return{fromUser:K2(A())??{},fromProject:K2(K($))??{}}}function s9($,Z){return r9($,Z.fromProject.mode??Z.fromUser.mode)}function o9($){return s9($,C2($))}function t9($){let Z=C2($),J=Z.fromProject.intelligence?.lessons?.syncRulesFile,Q=J??Z.fromUser.intelligence?.lessons?.syncRulesFile,q=X$(Q);if(q.coercedFrom===void 0)return q;let X=J===void 0?A():K($);return{...q,coercedIn:X}}function e9($){let Z=C2($),J=M2(M2(z$,Z.fromUser),Z.fromProject);if(J.mode=s9($,Z).mode,KX($,"grind-on"))J.grind.enabled=!0;return J.intelligence.lessons.syncRulesFile=O9(J.intelligence.lessons.syncRulesFile),J}function $1(){let $=K2(A())??{};return M2(z$,$)}function r$($,Z){let J=$.replace(/\\/g,"/");return Z.some((Q)=>J===Q||J.startsWith(`${Q}/`))}import{existsSync as Z1,readdirSync as MX,readFileSync as CX,statSync as J1}from"node:fs";import{join as O2}from"node:path";function Q1($){return O2(B($),"ship-ledger.jsonl")}function q1($,Z){let J={...Z,ts:Z.ts??new Date().toISOString()};P(Q1($),J)}function X1($){return N(Q1($),Number.MAX_SAFE_INTEGER)}function a$($,Z,J){if(!Z1($))return!1;let Q=Z*60*60*1000,q=Date.now();for(let X of MX($)){let W=O2($,X,"90-verdict.txt");if(!Z1(W))continue;try{let z=J1(W).mtimeMs;if(J!==void 0&&z<J)continue;if(q-z>Q)continue;if(/\bPASS\b/i.test(CX(W,"utf8")))return!0}catch{}}return!1}function W1($,Z){let J;for(let Q of Z)try{let q=J1(O2($,Q)).mtimeMs;if(J===void 0||q>J)J=q}catch{}return J}var OX=/(?:^|\n)\s*HARNESS_SHIP_CLAIM:\s*(.+?)\s*(?=\n|$)/;function z1($){let Z=$.trim();if(!Z)return null;let Q=Z.match(OX)?.[1]?.trim();if(!Q)return null;return{kind:"structured",snippet:`HARNESS_SHIP_CLAIM: ${Q}`.slice(0,280)}}function s$($,Z){let J=$.replace(/\\/g,"/");for(let Q of Z){let q=Q.replace(/\\/g,"/").replace(/^\.\//,"");if(!q)continue;if(q.endsWith("/**")){let X=q.slice(0,-3);if(J===X||J.startsWith(`${X}/`))return!0;continue}if(q.endsWith("/")){if(J.startsWith(q)||J.startsWith(`${q.slice(0,-1)}/`))return!0;continue}if(q.includes("*")){if(new RegExp(`^${q.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*\*/g,".*").replace(/\*/g,"[^/]*")}$`).test(J))return!0;continue}if(J===q||J.startsWith(`${q}/`))return!0}return!1}function _2($,Z,J){return $.some((Q)=>{if(s$(Q,J))return!1;return r$(Q,Z)||/^Dockerfile(\.|$)/.test(Q)})}function Y1($,Z,J=Date.now()){if(!$)return!1;let Q=Date.parse($);if(Number.isNaN(Q))return!1;return J-Q<Z*60*1000}function V1($){if($.enabled&&$.recentShipClaim&&$.changedFilesCount===0)return{kind:"continue",text:["BLOCKED: HARNESS_SHIP_CLAIM with no file diff.","TRIED: inspected git working tree / changed files.","NEED: either implement the remaining work or remove the ship claim — do not claim ship on an empty diff."].join(`
|
|
107
107
|
`)};return{kind:"abstain"}}function G1($){if(!$.enabled||!$.recentShipClaim||$.changedFiles.length===0)return{kind:"abstain"};if(!_2($.changedFiles,$.runtimePathPrefixes,$.runtimePathExcludes))return{kind:"abstain"};if($.evidenceDir!==null&&a$($.evidenceDir,$.evidenceMaxAgeHours,$.evidenceNotBeforeMs))return{kind:"abstain"};return{kind:"continue",text:["BLOCKED: HARNESS_SHIP_CLAIM without recent production PASS evidence.",`TRIED: checked ${$.evidenceDir??"(no evidenceDir configured)"}/*/90-verdict.txt.`,"NEED: run the verification after the last code change, then cite the verdict path — evidence written before the change certifies the older tree."].join(`
|
|
108
108
|
`)}}function _X($,Z,J=Date.now()){if(!$)return!1;let Q=Date.parse($);if(Number.isNaN(Q))return!1;return J-Q<Z*60*1000}function IX($){let Z=$.deviations.map((J)=>J.path);return $.changedFiles.filter((J)=>{if(s$(J,[...$.planned]))return!1;return!s$(J,Z)})}function B1($){let Z=I2($);if(!Z.active||Z.unplanned.length===0)return{kind:"abstain"};let J=Z.unplanned.slice(0,10).join(", "),Q=Z.unplanned.length>10?` (+${Z.unplanned.length-10} more)`:"";return{kind:"continue",text:[`BLOCKED: ${Z.unplanned.length} changed file(s) are outside the declared plan: ${J}${Q}`,`TRIED: compared the working tree against HARNESS_PLAN (${$.planned.join(", ")}).`,"NEED: either revert what the plan did not call for, or justify each path with a reason —","HARNESS_PLAN_DEVIATION: <path> — <why this file had to change>"].join(`
|
|
109
|
-
`)}}function I2($){if(!$.enabled||$.planned.length===0)return{active:!1,unplanned:[]};if(!_X($.declaredAt,$.windowMinutes,$.now??Date.now()))return{active:!1,unplanned:[]};return{active:!0,unplanned:IX({changedFiles:$.changedFiles,planned:$.planned,deviations:$.deviations})}}var PX=new Set(["Edit","Write","Delete","MultiEdit","NotebookEdit"]);function H1($){return $!==void 0&&PX.has($)}function U1($){if(!H1($.toolName)||!$.filePath)return{kind:"allow"};if(!P$($.projectDir,$.filePath))return{kind:"allow"};return{kind:"deny",reason:["Harness policy and state are not agent-writable — a gate an agent can switch off is not a gate.","The harness CLI does not help you here either: the same floor rule refuses the mutating subcommands from inside a session.","Tell the operator which value you would change and why, and let them run it from their own terminal."].join(" "),userNote:`Blocked an agent write to ${$.filePath}.`,rule:"policy-surface-write"}}import{createHash as jX}from"node:crypto";import{existsSync as V$,mkdirSync as NX,readdirSync as P2,readFileSync as F1,writeFileSync as j2}from"node:fs";import{join as Y$}from"node:path";var AX="absent",N2="harness.policy-baseline.v1",LX="harness-mode",DX=["grind-on","skip-verify","focus","paired"];function TX($){if(!V$($))return AX;try{return jX("sha256").update(F1($)).digest("hex")}catch{return"unreadable"}}function S($){
|
|
109
|
+
`)}}function I2($){if(!$.enabled||$.planned.length===0)return{active:!1,unplanned:[]};if(!_X($.declaredAt,$.windowMinutes,$.now??Date.now()))return{active:!1,unplanned:[]};return{active:!0,unplanned:IX({changedFiles:$.changedFiles,planned:$.planned,deviations:$.deviations})}}var PX=new Set(["Edit","Write","Delete","MultiEdit","NotebookEdit"]);function H1($){return $!==void 0&&PX.has($)}function U1($){if(!H1($.toolName)||!$.filePath)return{kind:"allow"};if(!P$($.projectDir,$.filePath))return{kind:"allow"};return{kind:"deny",reason:["Harness policy and state are not agent-writable — a gate an agent can switch off is not a gate.","The harness CLI does not help you here either: the same floor rule refuses the mutating subcommands from inside a session.","Tell the operator which value you would change and why, and let them run it from their own terminal."].join(" "),userNote:`Blocked an agent write to ${$.filePath}.`,rule:"policy-surface-write"}}import{createHash as jX}from"node:crypto";import{existsSync as V$,mkdirSync as NX,readdirSync as P2,readFileSync as F1,writeFileSync as j2}from"node:fs";import{join as Y$}from"node:path";var AX="absent",N2="harness.policy-baseline.v1",LX="harness-mode",DX=["grind-on","skip-verify","focus","paired"];function TX($){if(!V$($))return AX;try{return jX("sha256").update(F1($)).digest("hex")}catch{return"unreadable"}}function S($){let Z=[K($),A(),Y$(B($),LX),...DX.map((Q)=>Y$(L($),Q))],J=new Set;return Z.filter((Q)=>!J.has(Q)&&J.add(Q)!==void 0).map((Q)=>({path:Q,hash:TX(Q)}))}function K1($,Z){return Y$(m($),`${C(Z)}.json`)}function A2($,Z){try{NX(m($),{recursive:!0}),j2(K1($,Z),`${JSON.stringify({schema:N2,sources:S($)},null,2)}
|
|
110
110
|
`,"utf8")}catch{}}function o$($,Z){let J=K1($,Z);if(!V$(J))return null;try{let Q=JSON.parse(F1(J,"utf8"));return Array.isArray(Q.sources)?Q.sources:null}catch{return null}}function L2($,Z){let J=new Map($.map((Q)=>[Q.path,Q.hash]));return Z.filter((Q)=>{let q=J.get(Q.path);return q!==void 0&&q!==Q.hash}).map((Q)=>Q.path)}function M1($,Z){let J=o$($,Z);return J===null?[]:L2(J,S($))}function C1($){let Z=m($);if(!V$(Z))return[];let J=new Set,Q=S($);for(let q of P2(Z)){if(!q.endsWith(".json"))continue;let X=o$($,q.replace(/\.json$/,""));if(X)for(let W of L2(X,Q))J.add(W)}return[...J].sort()}function O1($,Z){let J=S($),Q=new Map(J.map((W)=>[W.path,W.hash])),q=Z.filter((W)=>!Q.has(W));if(q.length>0)return{kind:"not-a-source",paths:q,sources:J.map((W)=>W.path)};let X=m($);if(!V$(X)||Z.length===0)return{kind:"nothing-to-accept"};for(let W of P2(X)){if(!W.endsWith(".json"))continue;let z=W.replace(/\.json$/,""),Y=o$($,z);if(!Y)continue;let V=Y.map((G)=>Z.includes(G.path)?{path:G.path,hash:Q.get(G.path)}:G);try{j2(Y$(X,W),`${JSON.stringify({schema:N2,sources:V},null,2)}
|
|
111
111
|
`,"utf8")}catch{}}return{kind:"accepted",paths:Z}}function _1($,Z){let J=o$($,Z);if(!J)return A2($,Z),{kind:"allow"};let Q=L2(J,S($));if(Q.length===0)return{kind:"allow"};return{kind:"deny",reason:[`HARNESS: ${Q.join(", ")} changed during this session, and no harness command changed it.`,"The gates are now running a policy the operator did not set, so what they check cannot be trusted.","Report this to the operator and name the paths above. Only they can clear it, from their own terminal — the harness commands that would are refused from inside a session, so there is nothing for you to run here."].join(`
|
|
112
112
|
`),userNote:[`Harness policy changed out of band during this session: ${Q.join(", ")}.`,`If that was you, accept it with: tlc harness policy accept ${Q.join(" ")}`].join(" "),rule:"policy-baseline-divergence"}}function I1($){let Z=m($);if(!V$(Z))return;let J=S($);for(let Q of P2(Z)){if(!Q.endsWith(".json"))continue;try{j2(Y$(Z,Q),`${JSON.stringify({schema:N2,sources:J},null,2)}
|
|
@@ -148,5 +148,5 @@ description: Harness-learned lessons (auto-synced from gate failures)
|
|
|
148
148
|
alwaysApply: true
|
|
149
149
|
---
|
|
150
150
|
|
|
151
|
-
${J}`;return mW(Q,q,"utf8"),Q}var p6=f.observability.DEFAULT_OBS,
|
|
152
|
-
`)}async function
|
|
151
|
+
${J}`;return mW(Q,q,"utf8"),Q}var p6=f.observability.DEFAULT_OBS,FF={...p6,debugEnabled:!0};function KF($,Z=p6){return{...Z,globalSpool:$.obs.globalSpool,includePayloads:$.obs.includePayloads,maxAttrChars:$.obs.maxAttrChars,sessionCostAlertUsd:$.obs.sessionCostAlertUsd,retentionDays:$.obs.retentionDays}}function MF($){try{return pW($).size}catch{return 0}}function CF($){let Z=`${$.provider}-`;return $.sessionKey.startsWith(Z)?$.sessionKey.slice(Z.length):$.sessionKey}async function OF($){if(!u6(h6($,".git")))return null;let Z=await t({command:["git","rev-parse","--abbrev-ref","HEAD"],cwd:$});if(Z.exitCode!==0)return null;let J=Z.stdout.trim();return J.length>0?J:null}async function cW($){if(!u6(h6($,".git")))return null;let Z=await t({command:["git","rev-parse","--short","HEAD"],cwd:$});if(Z.exitCode!==0)return null;let J=Z.stdout.trim();return J.length>0?J:null}function dW($,Z){return f.policy.forProvider($,Z.name)??[]}function lW($,Z){return[...f.policy.forProvider($,Z.name)??[],...Z.policyDefaults().blockedPatterns]}function iW($,Z){return $??Z.policyDefaults().minEffort}function _F($,Z,J,Q){return{provider:J.name,sessionKey:$.sessionKey,projectDir:$.projectDir,model:Q,effort:$.effort,allowedModels:dW(Z.subagents.allowedModels,J),blockedPatterns:lW(Z.subagents.blockedPatterns,J),minEffort:iW(Z.subagents.minEffort,J),requireModel:Z.subagents.requireModel,enforceAllowlist:Z.subagents.enforceAllowlist,blockParentFast:Z.subagents.blockParentFast,blockMode:Z.subagents.blockMode}}function IF($){if(!$)return"";let Z=$.model??$.Model;return typeof Z==="string"?Z:""}function nW($){return f.lesson.renderLessonBlock($)}function PF($,Z){if($==="cursor")return WZ(Z);if($==="claude")return XZ(Z);return null}function jF($,Z,J=0){if($.length===0)return"";let Q=[Z,...$.map(nW)];if(J>0){let q=J===1?"lesson":"lessons";Q.push(` (${J} more eligible ${q} omitted under the char budget — raise maxCharsSession to see them)`)}return Q.join(`
|
|
152
|
+
`)}async function NF($,Z){let J=Z.policy.rules;if(!f.rules.wants($.projectDir,J,$))return;let Q=await cW($.projectDir);f.rules.observe($.projectDir,J,$,{sha:Q,sessionKey:$.sessionKey,at:new Date().toISOString()})}export{_F as subagentSpawnInput,MF as sizeOf,CF as sessionIdFromKey,PF as renderProviderLessonsView,nW as renderLessonLine,IF as readModelFromToolInput,NF as observeForRules,KF as obsConfigFor,jF as formatLessonsBlock,iW as effectiveMinEffort,lW as effectiveBlockedPatterns,dW as effectiveAllowedModels,cW as currentGitSha,OF as currentGitBranch,FF as OBS_CONFIG_AUDIT,p6 as OBS_CONFIG};
|