@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{createRequire as M$}from"node:module";var l=M$(import.meta.url);import{existsSync as B,lstatSync as m8,readFileSync as S,readlinkSync as u8,realpathSync as G$,rmSync as g8,statSync as h8,unlinkSync as p8,writeFileSync as c8}from"node:fs";import{homedir as d8}from"node:os";import{basename as l8,dirname as B$,isAbsolute as H$,join as G,relative as i8,resolve as h}from"node:path";import{homedir as j}from"node:os";import{delimiter as H2,join as L,resolve as K2}from"node:path";function i(){return L(j(),".tlc","harness")}function F($=process.env){return $.TLC_HOME??i()}function P(){let $=process.env.CLAUDE_CONFIG_DIR?.trim();return $&&$.length>0?$:L(j(),".claude")}function D(){let $=process.env.CURSOR_CONFIG_DIR?.trim();return $&&$.length>0?$:L(j(),".cursor")}function f($=process.env){return $.TLC_BIN_DIR?.trim()||L(j(),".local","bin")}function n(){return["tlc","tlc.cmd"]}var s=[{id:"typescript",extensions:[".ts",".tsx",".mts",".cts",".js",".jsx",".mjs",".cjs"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"python",extensions:[".py",".pyi",".pyw"],line:["#"],block:[['"""','"""'],["'''","'''"]],middle:[]},{id:"ruby",extensions:[".rb",".rake",".gemspec"],line:["#"],block:[["=begin","=end"]],middle:[]},{id:"shell",extensions:[".sh",".bash",".zsh",".ksh",".fish"],line:["#"],block:[],middle:[]},{id:"go",extensions:[".go"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"rust",extensions:[".rs"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"java",extensions:[".java"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"kotlin",extensions:[".kt",".kts"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"swift",extensions:[".swift"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"c",extensions:[".c",".h"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"cpp",extensions:[".cc",".cpp",".cxx",".hpp",".hh",".hxx"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"csharp",extensions:[".cs"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"php",extensions:[".php"],line:["//","#"],block:[["/*","*/"]],middle:["*"]},{id:"scala",extensions:[".scala",".sc"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"dart",extensions:[".dart"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"elixir",extensions:[".ex",".exs"],line:["#"],block:[],middle:[]},{id:"erlang",extensions:[".erl",".hrl"],line:["%"],block:[],middle:[]},{id:"haskell",extensions:[".hs"],line:["--"],block:[["{-","-}"]],middle:[]},{id:"lua",extensions:[".lua"],line:["--"],block:[["--[[","]]"]],middle:[]},{id:"sql",extensions:[".sql"],line:["--"],block:[["/*","*/"]],middle:["*"]},{id:"css",extensions:[".css",".scss",".sass",".less"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"yaml",extensions:[".yaml",".yml"],line:["#"],block:[],middle:[]},{id:"toml",extensions:[".toml"],line:["#"],block:[],middle:[]},{id:"ini",extensions:[".ini",".cfg",".conf",".properties"],line:[";","#"],block:[],middle:[]},{id:"dockerfile",extensions:[".dockerfile","dockerfile"],line:["#"],block:[],middle:[]},{id:"makefile",extensions:[".mk","makefile"],line:["#"],block:[],middle:[]},{id:"terraform",extensions:[".tf",".tfvars"],line:["#","//"],block:[["/*","*/"]],middle:["*"]},{id:"powershell",extensions:[".ps1",".psm1",".psd1"],line:["#"],block:[["<#","#>"]],middle:[]},{id:"perl",extensions:[".pl",".pm"],line:["#"],block:[],middle:[]},{id:"r",extensions:[".r"],line:["#"],block:[],middle:[]},{id:"julia",extensions:[".jl"],line:["#"],block:[["#=","=#"]],middle:[]},{id:"vue",extensions:[".vue",".svelte"],line:["//"],block:[["/*","*/"],["<!--","-->"]],middle:["*"]},{id:"html",extensions:[".html",".htm",".xml",".xhtml"],line:[],block:[["<!--","-->"]],middle:[]},{id:"graphql",extensions:[".graphql",".gql"],line:["#"],block:[],middle:[]},{id:"protobuf",extensions:[".proto"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"zig",extensions:[".zig"],line:["//"],block:[],middle:[]},{id:"clojure",extensions:[".clj",".cljs",".cljc",".edn"],line:[";"],block:[],middle:[]},{id:"ocaml",extensions:[".ml",".mli"],line:[],block:[["(*","*)"]],middle:["*"]},{id:"fsharp",extensions:[".fs",".fsi",".fsx"],line:["//"],block:[["(*","*)"]],middle:["*"]},{id:"vim",extensions:[".vim"],line:['"'],block:[],middle:[]},{id:"tex",extensions:[".tex",".sty",".cls"],line:["%"],block:[],middle:[]}];function I$($){let Z=new Map;for(let Q of $){let J={line:Q.line,block:Q.block,middle:Q.middle};for(let X of Q.extensions)Z.set(X.toLowerCase(),J)}return Z}var _$=I$(s);var N$=_$.size;var y=6;var A$=new Set(["aria2c","curl","fetch","http","httpie","https","wget"]);var MZ=new Set([...A$,"nc","ncat","socat","telnet","lwp-request"]);var R$="ts|tsx|mts|cts|js|jsx|mjs|cjs|py|go|rb|rs|java|kt|swift|php|sh|sql",CZ=new RegExp(`(?:file://)?((?:[A-Za-z]:)?[\\w./~@+-]*[\\w-]\\.(?:${R$}))(?=[:)\\s,'"\`]|$)`,"g");var A="1970-01-01T00:00:00.000Z";function M($){return{...$,scope:"gate-execution",source:"core",tier:"core",status:"active",confidence:1,hitCount:1,pinned:!1,refs:[],sessionKeys:[],injectedCount:0,gradeableCount:0,helpedCount:0,neutralCount:0,firstSeenAt:A,lastSeenAt:A,lastAccessedAt:A,updatedAt:A}}var q9=[M({id:"core:gate:lint",failedGate:"lint",category:"verification",triggerTokens:["lint","biome","eslint","ruff","format"],instruction:"A lint gate failure means changed files still violate the project lint command. Fix the reported findings without suppressions.",avoid:"Do not add lint suppressions, disable comments, or delete failing files to silence the gate.",prefer:"Apply the smallest fix that clears each finding, then let the stop hook re-check.",preRetryCheck:"Confirm the lint command targets only the intended changed files and still fails for the same codes.",priority:90}),M({id:"core:gate:test",failedGate:"test",category:"verification",triggerTokens:["test","vitest","jest","pytest","failing"],instruction:"A test gate failure means assertions still fail. Fix the behavior or the test under the real contract — do not delete or skip tests.",avoid:"Do not delete failing tests, mark them skipped, or weaken assertions to force green.",prefer:"Reproduce the failure, fix root cause, re-run the same test target.",preRetryCheck:"Identify the failing test name/file from the gate output before editing.",priority:90}),M({id:"core:gate:comments",failedGate:"comments",category:"verification",triggerTokens:["junk comment","TODO","FIXME","banner"],instruction:"Junk-comment policy failed. Delete narrating comments, banners, TODO/FIXME, and commented-out code.",avoid:"Do not keep TODO markers or section banners 'for clarity'.",prefer:"Keep only comments that explain a non-obvious why (invariant, hazard, external constraint).",preRetryCheck:"Scan the listed file:line hits and remove each one.",priority:80}),M({id:"core:gate:ship",failedGate:"ship",category:"ship-evidence",triggerTokens:["ship","evidence","90-verdict","PASS"],instruction:"Ship claim without recent production PASS evidence. Produce real evidence before claiming done.",avoid:"Do not claim shipped based on unit tests alone when runtime paths changed.",prefer:"Run production E2E, write 90-verdict.txt PASS, cite the evidence path.",preRetryCheck:"Confirm evidenceDir and a recent PASS verdict exist for this change.",priority:95}),M({id:"core:gate:empty-diff",failedGate:"empty-diff",category:"ship-evidence",triggerTokens:["empty","diff","no changes","shipped"],instruction:"Done/shipped was claimed with zero file changes. Either implement the work or explain why zero-diff is correct — do not claim shipped on an empty tree.",avoid:"Do not restate 'done' without a real diff or an explicit zero-change justification.",prefer:"Make the missing change, or clearly document why no files should change.",preRetryCheck:"Inspect git status / changed files before the next stop.",priority:92}),M({id:"core:gate:stagnation",failedGate:"stagnation",category:"stagnation",triggerTokens:["stagnation","identical","fingerprint","same fail"],instruction:"Identical validation fingerprint repeated. Change approach — do not re-apply the same failing edit.",avoid:"Do not retry the exact same patch, command, or suppression.",prefer:"Diagnose root cause with a different path, or escalate with BLOCKED / TRIED / NEED.",preRetryCheck:"Diff your last edit against the gate output; ensure the next action is different.",priority:100})];var d$={structure:"#3d3a4a",accent:"#a78bfa",success:"#6ee7b7",warning:"#d4a574",error:"#f87171",info:"#93c5fd",textMain:"#f5f5f7",textMuted:"#9ca3af",textDim:"#6b7280"},V={check:"✔",cross:"✖",warning:"⚠",arrow:"→",arrowRight:"▸",dot:"•",bar:"│",rule:"══",dash:"──"};function l$($){let Z=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec($.trim());if(!Z)return"255;255;255";return[Z[1],Z[2],Z[3]].map((Q)=>Number.parseInt(Q,16)).join(";")}var $$=String.fromCharCode(27),i$=`${$$}[0m`;function n$($=process.env,Z=process.argv,Q=process.stdout.isTTY===!0){if("NO_COLOR"in $)return!1;if(Z.includes("--no-color"))return!1;return Q}var a$={ok:"success",warn:"warning",fail:"error",info:"info"},s$={ok:V.check,warn:V.warning,fail:V.cross,info:V.arrowRight},m=16;function R($=n$()){let Z=(J,X)=>$?`${$$}[${J}m${X}${i$}`:X,Q=(J,X)=>Z(`38;2;${l$(d$[J])}`,X);return{enabled:$,paint:Q,bold:(J)=>Z("1",J),dim:(J)=>Q("textDim",J),heading:(J)=>Q("accent",`${V.rule} ${J} ${V.rule}`),footer:(J)=>Q("textDim",`${V.dash} ${J} ${V.dash}`),kv:(J,X,q=m)=>` ${Q("textMuted",`${J}:`.padEnd(q))} ${X}`,status:(J,X)=>`${Q(a$[J],s$[J])} ${X}`}}var O=R(!1);var r$=2;function o$($=process.stdout.columns){return Math.min(110,Math.max(60,$??100))}function t$($,Z){if($==="")return[""];let Q=[],J="";for(let X of $.split(/\s+/).filter((q)=>q.length>0)){if(J===""){J=X;continue}if(J.length+1+X.length<=Z){J=`${J} ${X}`;continue}Q.push(J),J=X}if(J!=="")Q.push(J);return Q.length===0?[""]:Q}function C($,Z,Q=o$()){let J=[Z.heading($.title.toUpperCase())];if($.summary&&$.summary.length>0)J.push(` ${$.summary.join(Z.dim(` ${V.bar} `))}`);let X=Math.max(m,...$.sections.flatMap((q)=>(q.rows??[]).map((z)=>z.label.length+1)));for(let q of $.sections){if(J.push(""),q.title)J.push(Z.paint("accent",q.title));for(let z of q.rows??[]){let W=z.level?Z.status(z.level,z.value):z.value;J.push(Z.kv(z.label,W,X))}for(let z of q.lines??[]){if(z===""){J.push("");continue}let W=q.wrap?t$(z,Q-r$):[z];for(let H of W)J.push(` ${H}`)}}if($.footer)J.push("",Z.footer($.footer));return J.join(`
|
|
1
|
+
import{createRequire as M$}from"node:module";var l=M$(import.meta.url);import{existsSync as B,lstatSync as m8,readFileSync as S,readlinkSync as u8,realpathSync as G$,rmSync as g8,statSync as h8,unlinkSync as p8,writeFileSync as c8}from"node:fs";import{homedir as d8}from"node:os";import{basename as l8,dirname as B$,isAbsolute as H$,join as G,relative as i8,resolve as h}from"node:path";import{homedir as j}from"node:os";import{delimiter as H2,dirname as K2,join as L,resolve as U2}from"node:path";function i(){return L(j(),".tlc","harness")}function F($=process.env){return $.TLC_HOME??i()}function P(){let $=process.env.CLAUDE_CONFIG_DIR?.trim();return $&&$.length>0?$:L(j(),".claude")}function D(){let $=process.env.CURSOR_CONFIG_DIR?.trim();return $&&$.length>0?$:L(j(),".cursor")}function f($=process.env){return $.TLC_BIN_DIR?.trim()||L(j(),".local","bin")}function n(){return["tlc","tlc.cmd"]}var s=[{id:"typescript",extensions:[".ts",".tsx",".mts",".cts",".js",".jsx",".mjs",".cjs"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"python",extensions:[".py",".pyi",".pyw"],line:["#"],block:[['"""','"""'],["'''","'''"]],middle:[]},{id:"ruby",extensions:[".rb",".rake",".gemspec"],line:["#"],block:[["=begin","=end"]],middle:[]},{id:"shell",extensions:[".sh",".bash",".zsh",".ksh",".fish"],line:["#"],block:[],middle:[]},{id:"go",extensions:[".go"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"rust",extensions:[".rs"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"java",extensions:[".java"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"kotlin",extensions:[".kt",".kts"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"swift",extensions:[".swift"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"c",extensions:[".c",".h"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"cpp",extensions:[".cc",".cpp",".cxx",".hpp",".hh",".hxx"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"csharp",extensions:[".cs"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"php",extensions:[".php"],line:["//","#"],block:[["/*","*/"]],middle:["*"]},{id:"scala",extensions:[".scala",".sc"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"dart",extensions:[".dart"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"elixir",extensions:[".ex",".exs"],line:["#"],block:[],middle:[]},{id:"erlang",extensions:[".erl",".hrl"],line:["%"],block:[],middle:[]},{id:"haskell",extensions:[".hs"],line:["--"],block:[["{-","-}"]],middle:[]},{id:"lua",extensions:[".lua"],line:["--"],block:[["--[[","]]"]],middle:[]},{id:"sql",extensions:[".sql"],line:["--"],block:[["/*","*/"]],middle:["*"]},{id:"css",extensions:[".css",".scss",".sass",".less"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"yaml",extensions:[".yaml",".yml"],line:["#"],block:[],middle:[]},{id:"toml",extensions:[".toml"],line:["#"],block:[],middle:[]},{id:"ini",extensions:[".ini",".cfg",".conf",".properties"],line:[";","#"],block:[],middle:[]},{id:"dockerfile",extensions:[".dockerfile","dockerfile"],line:["#"],block:[],middle:[]},{id:"makefile",extensions:[".mk","makefile"],line:["#"],block:[],middle:[]},{id:"terraform",extensions:[".tf",".tfvars"],line:["#","//"],block:[["/*","*/"]],middle:["*"]},{id:"powershell",extensions:[".ps1",".psm1",".psd1"],line:["#"],block:[["<#","#>"]],middle:[]},{id:"perl",extensions:[".pl",".pm"],line:["#"],block:[],middle:[]},{id:"r",extensions:[".r"],line:["#"],block:[],middle:[]},{id:"julia",extensions:[".jl"],line:["#"],block:[["#=","=#"]],middle:[]},{id:"vue",extensions:[".vue",".svelte"],line:["//"],block:[["/*","*/"],["<!--","-->"]],middle:["*"]},{id:"html",extensions:[".html",".htm",".xml",".xhtml"],line:[],block:[["<!--","-->"]],middle:[]},{id:"graphql",extensions:[".graphql",".gql"],line:["#"],block:[],middle:[]},{id:"protobuf",extensions:[".proto"],line:["//"],block:[["/*","*/"]],middle:["*"]},{id:"zig",extensions:[".zig"],line:["//"],block:[],middle:[]},{id:"clojure",extensions:[".clj",".cljs",".cljc",".edn"],line:[";"],block:[],middle:[]},{id:"ocaml",extensions:[".ml",".mli"],line:[],block:[["(*","*)"]],middle:["*"]},{id:"fsharp",extensions:[".fs",".fsi",".fsx"],line:["//"],block:[["(*","*)"]],middle:["*"]},{id:"vim",extensions:[".vim"],line:['"'],block:[],middle:[]},{id:"tex",extensions:[".tex",".sty",".cls"],line:["%"],block:[],middle:[]}];function I$($){let Z=new Map;for(let Q of $){let J={line:Q.line,block:Q.block,middle:Q.middle};for(let X of Q.extensions)Z.set(X.toLowerCase(),J)}return Z}var _$=I$(s);var N$=_$.size;var y=6;var A$=new Set(["aria2c","curl","fetch","http","httpie","https","wget"]);var OZ=new Set([...A$,"nc","ncat","socat","telnet","lwp-request"]);var R$="ts|tsx|mts|cts|js|jsx|mjs|cjs|py|go|rb|rs|java|kt|swift|php|sh|sql",IZ=new RegExp(`(?:file://)?((?:[A-Za-z]:)?[\\w./~@+-]*[\\w-]\\.(?:${R$}))(?=[:)\\s,'"\`]|$)`,"g");var A="1970-01-01T00:00:00.000Z";function M($){return{...$,scope:"gate-execution",source:"core",tier:"core",status:"active",confidence:1,hitCount:1,pinned:!1,refs:[],sessionKeys:[],injectedCount:0,gradeableCount:0,helpedCount:0,neutralCount:0,firstSeenAt:A,lastSeenAt:A,lastAccessedAt:A,updatedAt:A}}var z9=[M({id:"core:gate:lint",failedGate:"lint",category:"verification",triggerTokens:["lint","biome","eslint","ruff","format"],instruction:"A lint gate failure means changed files still violate the project lint command. Fix the reported findings without suppressions.",avoid:"Do not add lint suppressions, disable comments, or delete failing files to silence the gate.",prefer:"Apply the smallest fix that clears each finding, then let the stop hook re-check.",preRetryCheck:"Confirm the lint command targets only the intended changed files and still fails for the same codes.",priority:90}),M({id:"core:gate:test",failedGate:"test",category:"verification",triggerTokens:["test","vitest","jest","pytest","failing"],instruction:"A test gate failure means assertions still fail. Fix the behavior or the test under the real contract — do not delete or skip tests.",avoid:"Do not delete failing tests, mark them skipped, or weaken assertions to force green.",prefer:"Reproduce the failure, fix root cause, re-run the same test target.",preRetryCheck:"Identify the failing test name/file from the gate output before editing.",priority:90}),M({id:"core:gate:comments",failedGate:"comments",category:"verification",triggerTokens:["junk comment","TODO","FIXME","banner"],instruction:"Junk-comment policy failed. Delete narrating comments, banners, TODO/FIXME, and commented-out code.",avoid:"Do not keep TODO markers or section banners 'for clarity'.",prefer:"Keep only comments that explain a non-obvious why (invariant, hazard, external constraint).",preRetryCheck:"Scan the listed file:line hits and remove each one.",priority:80}),M({id:"core:gate:ship",failedGate:"ship",category:"ship-evidence",triggerTokens:["ship","evidence","90-verdict","PASS"],instruction:"Ship claim without recent production PASS evidence. Produce real evidence before claiming done.",avoid:"Do not claim shipped based on unit tests alone when runtime paths changed.",prefer:"Run production E2E, write 90-verdict.txt PASS, cite the evidence path.",preRetryCheck:"Confirm evidenceDir and a recent PASS verdict exist for this change.",priority:95}),M({id:"core:gate:empty-diff",failedGate:"empty-diff",category:"ship-evidence",triggerTokens:["empty","diff","no changes","shipped"],instruction:"Done/shipped was claimed with zero file changes. Either implement the work or explain why zero-diff is correct — do not claim shipped on an empty tree.",avoid:"Do not restate 'done' without a real diff or an explicit zero-change justification.",prefer:"Make the missing change, or clearly document why no files should change.",preRetryCheck:"Inspect git status / changed files before the next stop.",priority:92}),M({id:"core:gate:stagnation",failedGate:"stagnation",category:"stagnation",triggerTokens:["stagnation","identical","fingerprint","same fail"],instruction:"Identical validation fingerprint repeated. Change approach — do not re-apply the same failing edit.",avoid:"Do not retry the exact same patch, command, or suppression.",prefer:"Diagnose root cause with a different path, or escalate with BLOCKED / TRIED / NEED.",preRetryCheck:"Diff your last edit against the gate output; ensure the next action is different.",priority:100})];var d$={structure:"#3d3a4a",accent:"#a78bfa",success:"#6ee7b7",warning:"#d4a574",error:"#f87171",info:"#93c5fd",textMain:"#f5f5f7",textMuted:"#9ca3af",textDim:"#6b7280"},V={check:"✔",cross:"✖",warning:"⚠",arrow:"→",arrowRight:"▸",dot:"•",bar:"│",rule:"══",dash:"──"};function l$($){let Z=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec($.trim());if(!Z)return"255;255;255";return[Z[1],Z[2],Z[3]].map((Q)=>Number.parseInt(Q,16)).join(";")}var $$=String.fromCharCode(27),i$=`${$$}[0m`;function n$($=process.env,Z=process.argv,Q=process.stdout.isTTY===!0){if("NO_COLOR"in $)return!1;if(Z.includes("--no-color"))return!1;return Q}var a$={ok:"success",warn:"warning",fail:"error",info:"info"},s$={ok:V.check,warn:V.warning,fail:V.cross,info:V.arrowRight},m=16;function R($=n$()){let Z=(J,X)=>$?`${$$}[${J}m${X}${i$}`:X,Q=(J,X)=>Z(`38;2;${l$(d$[J])}`,X);return{enabled:$,paint:Q,bold:(J)=>Z("1",J),dim:(J)=>Q("textDim",J),heading:(J)=>Q("accent",`${V.rule} ${J} ${V.rule}`),footer:(J)=>Q("textDim",`${V.dash} ${J} ${V.dash}`),kv:(J,X,q=m)=>` ${Q("textMuted",`${J}:`.padEnd(q))} ${X}`,status:(J,X)=>`${Q(a$[J],s$[J])} ${X}`}}var O=R(!1);var r$=2;function o$($=process.stdout.columns){return Math.min(110,Math.max(60,$??100))}function t$($,Z){if($==="")return[""];let Q=[],J="";for(let X of $.split(/\s+/).filter((q)=>q.length>0)){if(J===""){J=X;continue}if(J.length+1+X.length<=Z){J=`${J} ${X}`;continue}Q.push(J),J=X}if(J!=="")Q.push(J);return Q.length===0?[""]:Q}function C($,Z,Q=o$()){let J=[Z.heading($.title.toUpperCase())];if($.summary&&$.summary.length>0)J.push(` ${$.summary.join(Z.dim(` ${V.bar} `))}`);let X=Math.max(m,...$.sections.flatMap((q)=>(q.rows??[]).map((z)=>z.label.length+1)));for(let q of $.sections){if(J.push(""),q.title)J.push(Z.paint("accent",q.title));for(let z of q.rows??[]){let W=z.level?Z.status(z.level,z.value):z.value;J.push(Z.kv(z.label,W,X))}for(let z of q.lines??[]){if(z===""){J.push("");continue}let W=q.wrap?t$(z,Q-r$):[z];for(let H of W)J.push(` ${H}`)}}if($.footer)J.push("",Z.footer($.footer));return J.join(`
|
|
2
2
|
`)}var K={enabled:!0,signalPath:"obs.jsonl",debugPath:"debug.jsonl",debugEnabled:!1,includePayloads:!1,maxAttrChars:500,sessionCostAlertUsd:5,retentionDays:14,maxSignalEvents:50000,globalSpool:!1};var $8=["No harness decision in this window.","Whatever you just saw was the model, not a rail — the harness allowed everything it was asked about."].join(`
|
|
3
|
-
`);var Z8={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:y},obs:{globalSpool:!1,includePayloads:K.includePayloads,maxAttrChars:K.maxAttrChars,sessionCostAlertUsd:K.sessionCostAlertUsd,retentionDays:K.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:{...Z8}},mcpPrime:[],bootstrapExtra:[]};var I="@tech-leads-club/harness-toolkit",k="installed-from-npm";import{existsSync as S8,mkdirSync as
|
|
4
|
-
`}}import{join as X$,relative as
|
|
3
|
+
`);var Z8={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:y},obs:{globalSpool:!1,includePayloads:K.includePayloads,maxAttrChars:K.maxAttrChars,sessionCostAlertUsd:K.sessionCostAlertUsd,retentionDays:K.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:{...Z8}},mcpPrime:[],bootstrapExtra:[]};var I="@tech-leads-club/harness-toolkit",k="installed-from-npm";import{existsSync as S8,mkdirSync as mX,readFileSync as f8,realpathSync as uX,writeFileSync as b8}from"node:fs";function J$($){return $!==null&&typeof $==="object"&&!Array.isArray($)}function w8($){return J$($)}var y8="tlc-exec.mjs";function v8($){return JSON.stringify($??null).includes(y8)}function u($){if($===null||$.trim()==="")return{ok:!0,settingsText:"",changed:!1};let Z;try{Z=JSON.parse($)}catch(z){return{ok:!1,error:z instanceof Error?z.message:String(z),block:""}}if(!J$(Z))return{ok:!1,error:"settings.json root is not a JSON object",block:""};let Q=w8(Z.hooks)?Z.hooks:{},J={},X=!1;for(let[z,W]of Object.entries(Q)){let H=W.filter((_)=>!v8(_));if(H.length!==W.length)X=!0;if(H.length>0)J[z]=H}let q={};for(let[z,W]of Object.entries(Z))if(z!=="hooks")q[z]=W;else if(Object.keys(J).length>0)q.hooks=J;return{ok:!0,settingsText:JSON.stringify(q,null,2),changed:X}}function Q$($){if(!S8($))return{ok:!0,settingsText:"",changed:!1};let Z=u(f8($,"utf8"));if(Z.ok&&Z.changed)b8($,Z.settingsText,"utf8");return Z}function g($,Z="tlc-exec.mjs"){if($===null||$.trim()==="")return{kind:"absent"};let Q;try{Q=JSON.parse($)}catch{return{kind:"unparsed"}}if(Q===null||typeof Q!=="object"||Array.isArray(Q))return{kind:"unparsed"};let J=Q,X=J.hooks!==null&&typeof J.hooks==="object"&&!Array.isArray(J.hooks)?J.hooks:{},q={},z=0,W=0;for(let[H,_]of Object.entries(X)){let d=Array.isArray(_)?_:[],N=d.filter((U$)=>!JSON.stringify(U$??null).includes(Z));if(z+=d.length-N.length,N.length>0)q[H]=N,W+=N.length}if(W===0)return{kind:"empty",removed:z};return{kind:"rewritten",removed:z,text:`${JSON.stringify({...J,hooks:q},null,2)}
|
|
4
|
+
`}}import{join as X$,relative as iX,resolve as nX,sep as aX}from"node:path";var q$=["bin","capabilities","dist","docs","skills","src","tools","config.example.json","package.json"],z$=["config.json","state","flags"],J4=[X$("tools","dev"),X$("tools","__test__")];function n8($=process.env){let Z=d8(),Q=f($);return{home:F($),binLinks:n().map((J)=>G(Q,J)),claudeSettings:G(P(),"settings.json"),cursorHooks:G(D(),"hooks.json"),skillLinks:[G(P(),"skills","harness-init"),G(D(),"skills","harness-init"),G(Z,".tlc","skills","harness-init")]}}function p($){try{return m8($).isSymbolicLink()}catch{return!1}}function c($){let Z=h($),Q=[];for(;;)try{return G(G$(Z),...Q)}catch{let J=B$(Z);if(J===Z)return h($);Q.unshift(l8(Z)),Z=J}}function x($){try{return G$($)}catch{try{let Z=u8($);return c(H$(Z)?Z:h(B$($),Z))}catch{return c($)}}}function a8($,Z,Q={relative:i8,isAbsolute:H$}){if($===Z)return!0;let J=Q.relative(Z,$);return J!==""&&!J.startsWith("..")&&!Q.isAbsolute(J)}function W$($,Z){return a8(x($),c(Z))}var s8="tlc-exec.mjs";function r8($){try{return h8($).size<4096&&S($,"utf8").includes(s8)}catch{return!1}}function Y$($,Z,Q,J,X){if(!B(Z)&&!p(Z))return;if(!p(Z)){if(r8(Z)){$.push({action:"remove",target:Z,detail:`${J}, installed as a copy`});return}$.push({action:"keep",target:Z,detail:`${J} is a real file the installer did not write`});return}if(X==="target"&&!W$(Z,Q)){$.push({action:"keep",target:Z,detail:`points at ${x(Z)} — not ours`});return}let q=X==="location"&&!W$(Z,Q);$.push({action:"unlink",target:Z,detail:q?`${J}, stale — points at ${x(Z)}`:J})}function o8($,Z){if(!B(Z))return;let Q=u(S(Z,"utf8"));if(!Q.ok){$.push({action:"keep",target:Z,detail:`left untouched — it does not parse as JSON: ${Q.error}`});return}if(!Q.changed)return;$.push({action:"unmerge",target:Z,detail:"drop the harness hook groups, keep every other key and every foreign hook"})}function t8($,Z){let Q=B(Z)?S(Z,"utf8"):null,J=g(Q);switch(J.kind){case"absent":return;case"unparsed":$.push({action:"keep",target:Z,detail:"left untouched — it does not parse as JSON"});return;case"empty":if(J.removed>0)$.push({action:"remove",target:Z,detail:`${J.removed} entries, all ours`});return;default:$.push({action:"unmerge",target:Z,detail:`drop ${J.removed} harness entries, keep the rest`})}}function e8($,Z,Q){if(p(Z))return $.push({action:"unlink",target:Z,detail:`a link to ${x(Z)} — the checkout it points at is left exactly as it is`}),!0;if(!B(Z))return!1;for(let q of q$){let z=G(Z,q);if(B(z))$.push({action:"remove",target:z,detail:"runtime payload"})}let X=G(Z,k);if(B(X))$.push({action:"remove",target:X,detail:"install marker"});for(let q of z$){let z=G(Z,q);if(!B(z))continue;$.push(Q?{action:"remove",target:z,detail:"--purge"}:{action:"keep",target:z,detail:"yours — add --purge to remove it"})}return!1}function $2($,Z){if(B(G(Z,k)))$.push({action:"manual",target:`npm uninstall -g ${I}`,detail:"the global package is reported, never removed for you"});$.push({action:"manual",target:"rm -rf .tlc/ in each repository",detail:"per-project config and state — this command does not search your disk for them"})}function Z2($,Z={}){let Q=Z.purge===!0,J=[];o8(J,$.claudeSettings),t8(J,$.cursorHooks);for(let q of $.skillLinks)Y$(J,q,$.home,"skill link","location");for(let q of $.binLinks)Y$(J,q,$.home,"the tlc launcher on PATH","target");let X=e8(J,$.home,Q);return $2(J,$.home),{items:J,purge:Q,homeIsLink:X}}function K$($){return $.items.filter((Z)=>Z.action==="unmerge"||Z.action==="unlink"||Z.action==="remove")}function J2($,Z){let Q=[],J=[];for(let X of K$($))try{if(X.action==="unmerge"&&X.target===Z.claudeSettings)Q$(X.target);else if(X.action==="unmerge"){let q=g(S(X.target,"utf8"));if(q.kind==="rewritten")c8(X.target,q.text,"utf8")}else if(X.action==="unlink")p8(X.target);else g8(X.target,{recursive:!0,force:!0});Q.push(X)}catch(q){J.push({item:X,reason:q instanceof Error?q.message:String(q)})}return{applied:Q,failed:J}}var Q2={unmerge:"warn",unlink:"warn",remove:"warn",keep:"ok",manual:"info"};function X2($,Z){let Q=K$($),J=Z!==null;if(Q.length===0)return{title:"harness uninstall",summary:["nothing wired"],sections:[{rows:[{label:"state",value:"no harness artefact found — nothing to undo",level:"ok"}]},{title:"STILL YOURS TO DO",rows:V$($)}],footer:`already clean · reinstall with npm i -g ${I}, then \`tlc harness install\``};let X=Q.map((W)=>({label:W.action,value:`${W.target} — ${W.detail}`,level:Q2[W.action]})),q=$.items.filter((W)=>W.action==="keep"),z=[{title:J?"REMOVED":"WOULD REMOVE",rows:X},...q.length>0?[{title:"KEPT",rows:q.map((W)=>({label:"keep",value:`${W.target} — ${W.detail}`,level:"ok"}))}]:[],{title:"STILL YOURS TO DO",rows:V$($)},...Z!==null&&Z.failed.length>0?[{title:"FAILED",rows:Z.failed.map((W)=>({label:"error",value:`${W.item.target} — ${W.reason}`,level:"fail"}))}]:[]];return{title:"harness uninstall",summary:[J?`${Z.applied.length} applied`:`${Q.length} pending`,$.purge?"purge: state included":"purge: state kept",$.homeIsLink?"runtime: linked checkout, unlinked only":"runtime: owned by the installer"],sections:z,footer:J?`reinstall any time with npm i -g ${I}, then \`tlc harness install\``:"nothing was changed · re-run with --yes to apply this plan"}}function V$($){return $.items.filter((Z)=>Z.action==="manual").map((Z)=>({label:"run",value:`${Z.target} — ${Z.detail}`,level:"info"}))}function q2($,Z,Q=O){return C(X2($,Z),Q)}function z2($=process.argv.slice(2)){let Z=n8(),Q=Z2(Z,{purge:$.includes("--purge")}),J=$.includes("--yes")?J2(Q,Z):null;return console.log(q2(Q,J,R())),J!==null&&J.failed.length>0?1:0}if(l.main==l.module)process.exitCode=z2();export{n8 as uninstallTargets,X2 as uninstallScreen,q2 as uninstallReportText,Z2 as planUninstall,K$ as pendingItems,z2 as main,a8 as isInsideRoot,c as canonicalise,J2 as applyUninstall};
|
package/package.json
CHANGED
|
@@ -43,7 +43,19 @@ export function policySourceFingerprint(root: string): PolicySource[] {
|
|
|
43
43
|
join(projectStateDir(root), MODE_FILE),
|
|
44
44
|
...FLAG_FILES.map((flag) => join(flagsDir(root), flag)),
|
|
45
45
|
];
|
|
46
|
-
|
|
46
|
+
/**
|
|
47
|
+
* hazard: listed as-is, and two of these collide. With the project root at a home directory,
|
|
48
|
+
* `projectConfigPath(root)` resolves to the machine config path — so the same file appeared twice in every
|
|
49
|
+
* listing, and `acceptPolicySources` would write the same entry twice. The duplicate carried no information and
|
|
50
|
+
* read as a defect ([/decisions/ad-101.md](/decisions/ad-101.md)).
|
|
51
|
+
*
|
|
52
|
+
* invariant: deduplicated by path, first occurrence winning, so the project tier keeps its position when it is
|
|
53
|
+
* also the machine tier. The hash is the same either way — it is one file.
|
|
54
|
+
*/
|
|
55
|
+
const seen = new Set<string>();
|
|
56
|
+
return paths
|
|
57
|
+
.filter((path) => !seen.has(path) && seen.add(path) !== undefined)
|
|
58
|
+
.map((path) => ({ path, hash: hashOf(path) }));
|
|
47
59
|
}
|
|
48
60
|
|
|
49
61
|
function baselinePath(root: string, sessionKey: string): string {
|
package/src/platform/paths.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, realpathSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import { delimiter, join, resolve } from "node:path";
|
|
3
|
+
import { delimiter, dirname, join, resolve } from "node:path";
|
|
4
4
|
|
|
5
5
|
function harnessDir(root: string): string {
|
|
6
6
|
return join(root, ".tlc", "harness");
|
|
@@ -63,6 +63,33 @@ export function runtimeSpoolPath(): string {
|
|
|
63
63
|
return join(runtimeStateDir(), "obs-spool.jsonl");
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
/**
|
|
67
|
+
* The project a command is being run in: the nearest directory at or above `from` that holds a harness directory.
|
|
68
|
+
*
|
|
69
|
+
* why upward discovery: it is what every tool an operator already knows does — `git` walks up for `.git`, npm and
|
|
70
|
+
* cargo for their manifests, biome and eslint for their config. Anything else makes the operator's shell position
|
|
71
|
+
* part of the interface. Measured before this existed: `tlc harness status` run from `src/` reported the project as
|
|
72
|
+
* `src`, found no config there, fell back to the machine tier, and printed a posture the project had not set. Every
|
|
73
|
+
* command had that shape, and `policy accept` was only where it hurt enough to notice
|
|
74
|
+
* ([/decisions/ad-101.md](/decisions/ad-101.md)).
|
|
75
|
+
*
|
|
76
|
+
* invariant: `null` when there is none, so a first `init` still resolves to the working directory rather than to
|
|
77
|
+
* whichever ancestor happens to be a project.
|
|
78
|
+
*/
|
|
79
|
+
export function findProjectRoot(from: string, exists: (path: string) => boolean = existsSync): string | null {
|
|
80
|
+
let current = resolve(from);
|
|
81
|
+
for (;;) {
|
|
82
|
+
if (exists(harnessDir(current))) {
|
|
83
|
+
return current;
|
|
84
|
+
}
|
|
85
|
+
const parent = dirname(current);
|
|
86
|
+
if (parent === current) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
current = parent;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
66
93
|
export function projectConfigPath(root: string): string {
|
|
67
94
|
return join(harnessDir(root), "config.json");
|
|
68
95
|
}
|