@bensandee/tooling 0.40.1 → 0.40.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/dist/bin.mjs +91 -57
- package/package.json +3 -3
package/dist/bin.mjs
CHANGED
|
@@ -465,10 +465,14 @@ function buildDefaultConfig(targetDir, flags) {
|
|
|
465
465
|
}
|
|
466
466
|
//#endregion
|
|
467
467
|
//#region src/utils/fs.ts
|
|
468
|
+
/** Check if a relative path resolves within the target directory. */
|
|
469
|
+
function isContained(targetDir, rel) {
|
|
470
|
+
const resolved = path.resolve(targetDir, rel);
|
|
471
|
+
return resolved.startsWith(targetDir + path.sep) || resolved === targetDir;
|
|
472
|
+
}
|
|
468
473
|
/** Verify that a relative path resolves within the target directory. */
|
|
469
474
|
function assertContained(targetDir, rel) {
|
|
470
|
-
|
|
471
|
-
if (!resolved.startsWith(targetDir + path.sep) && resolved !== targetDir) throw new FatalError(`Path traversal detected: ${rel} resolves outside target directory`);
|
|
475
|
+
if (!isContained(targetDir, rel)) throw new FatalError(`Path traversal detected: ${rel} resolves outside target directory`);
|
|
472
476
|
}
|
|
473
477
|
/**
|
|
474
478
|
* Compare file content, using parsed comparison for JSON files to ignore
|
|
@@ -511,13 +515,11 @@ function createContext(config, confirmOverwrite) {
|
|
|
511
515
|
targetDir: config.targetDir,
|
|
512
516
|
packageJson: pkgRaw ? parsePackageJson(pkgRaw) : void 0,
|
|
513
517
|
exists: (rel) => {
|
|
514
|
-
|
|
515
|
-
if (!resolved.startsWith(config.targetDir + path.sep) && resolved !== config.targetDir) return false;
|
|
518
|
+
if (!isContained(config.targetDir, rel)) return false;
|
|
516
519
|
return fileExists(config.targetDir, rel);
|
|
517
520
|
},
|
|
518
521
|
read: (rel) => {
|
|
519
|
-
|
|
520
|
-
if (!resolved.startsWith(config.targetDir + path.sep) && resolved !== config.targetDir) return;
|
|
522
|
+
if (!isContained(config.targetDir, rel)) return void 0;
|
|
521
523
|
return readFile(config.targetDir, rel);
|
|
522
524
|
},
|
|
523
525
|
write: (rel, content) => {
|
|
@@ -773,6 +775,17 @@ function findRootDockerfile(executor, cwd) {
|
|
|
773
775
|
context: "."
|
|
774
776
|
};
|
|
775
777
|
}
|
|
778
|
+
/** Helper to create a DockerPackage object from resolved config. */
|
|
779
|
+
function createDockerPackage(executor, cwd, dir, repoName, docker) {
|
|
780
|
+
const isRoot = dir === ".";
|
|
781
|
+
const { name, version } = readPackageInfo(executor, isRoot ? path.join(cwd, "package.json") : path.join(cwd, "packages", dir, "package.json"));
|
|
782
|
+
return {
|
|
783
|
+
dir,
|
|
784
|
+
imageName: isRoot ? stripScope(name ?? repoName) : `${repoName}-${stripScope(name ?? dir)}`,
|
|
785
|
+
version,
|
|
786
|
+
docker
|
|
787
|
+
};
|
|
788
|
+
}
|
|
776
789
|
/**
|
|
777
790
|
* Discover Docker packages by convention and merge with .tooling.json overrides.
|
|
778
791
|
*
|
|
@@ -794,37 +807,15 @@ function detectDockerPackages(executor, cwd, repoName) {
|
|
|
794
807
|
const convention = findConventionDockerfile(executor, cwd, dir);
|
|
795
808
|
const docker = overrides[dir] ?? convention;
|
|
796
809
|
if (docker) {
|
|
797
|
-
|
|
798
|
-
packages.push({
|
|
799
|
-
dir,
|
|
800
|
-
imageName: `${repoName}-${stripScope(name ?? dir)}`,
|
|
801
|
-
version,
|
|
802
|
-
docker
|
|
803
|
-
});
|
|
810
|
+
packages.push(createDockerPackage(executor, cwd, dir, repoName, docker));
|
|
804
811
|
seen.add(dir);
|
|
805
812
|
}
|
|
806
813
|
}
|
|
807
|
-
for (const [dir, docker] of Object.entries(overrides)) if (!seen.has(dir))
|
|
808
|
-
const { name, version } = readPackageInfo(executor, path.join(cwd, "packages", dir, "package.json"));
|
|
809
|
-
packages.push({
|
|
810
|
-
dir,
|
|
811
|
-
imageName: `${repoName}-${stripScope(name ?? dir)}`,
|
|
812
|
-
version,
|
|
813
|
-
docker
|
|
814
|
-
});
|
|
815
|
-
}
|
|
814
|
+
for (const [dir, docker] of Object.entries(overrides)) if (!seen.has(dir)) packages.push(createDockerPackage(executor, cwd, dir, repoName, docker));
|
|
816
815
|
} else {
|
|
817
816
|
const convention = findRootDockerfile(executor, cwd);
|
|
818
817
|
const docker = overrides["."] ?? convention;
|
|
819
|
-
if (docker)
|
|
820
|
-
const { name, version } = readPackageInfo(executor, path.join(cwd, "package.json"));
|
|
821
|
-
packages.push({
|
|
822
|
-
dir: ".",
|
|
823
|
-
imageName: stripScope(name ?? repoName),
|
|
824
|
-
version,
|
|
825
|
-
docker
|
|
826
|
-
});
|
|
827
|
-
}
|
|
818
|
+
if (docker) packages.push(createDockerPackage(executor, cwd, ".", repoName, docker));
|
|
828
819
|
}
|
|
829
820
|
return packages;
|
|
830
821
|
}
|
|
@@ -837,13 +828,7 @@ function readSinglePackageDocker(executor, cwd, packageDir, repoName) {
|
|
|
837
828
|
const convention = findConventionDockerfile(executor, cwd, dir);
|
|
838
829
|
const docker = loadDockerMap(executor, cwd)[dir] ?? convention;
|
|
839
830
|
if (!docker) throw new FatalError(`No Dockerfile found for package "${dir}" (checked convention paths and .tooling.json)`);
|
|
840
|
-
|
|
841
|
-
return {
|
|
842
|
-
dir,
|
|
843
|
-
imageName: `${repoName}-${stripScope(name ?? dir)}`,
|
|
844
|
-
version,
|
|
845
|
-
docker
|
|
846
|
-
};
|
|
831
|
+
return createDockerPackage(executor, cwd, dir, repoName, docker);
|
|
847
832
|
}
|
|
848
833
|
/** Parse semver version string into major, minor, patch components. */
|
|
849
834
|
function parseSemver(version) {
|
|
@@ -1564,7 +1549,7 @@ async function generatePackageJson(ctx) {
|
|
|
1564
1549
|
const devDeps = { ...ROOT_DEV_DEPS };
|
|
1565
1550
|
if (!isMonorepo) Object.assign(devDeps, PER_PACKAGE_DEV_DEPS);
|
|
1566
1551
|
devDeps["@bensandee/config"] = isWorkspacePackage(ctx, "@bensandee/config") ? "workspace:*" : "0.10.0";
|
|
1567
|
-
devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.40.
|
|
1552
|
+
devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.40.2";
|
|
1568
1553
|
if (ctx.config.useEslintPlugin) devDeps["@bensandee/eslint-plugin"] = isWorkspacePackage(ctx, "@bensandee/eslint-plugin") ? "workspace:*" : "0.12.0";
|
|
1569
1554
|
if (ctx.config.formatter === "oxfmt") devDeps["oxfmt"] = {
|
|
1570
1555
|
"@changesets/cli": "2.30.0",
|
|
@@ -2406,7 +2391,7 @@ async function generatePnpmWorkspace(ctx) {
|
|
|
2406
2391
|
//#region src/generators/claude-hooks.ts
|
|
2407
2392
|
const HOOK_PATH = ".claude/hooks/bst-hook.mjs";
|
|
2408
2393
|
async function generateClaudeHooks(ctx) {
|
|
2409
|
-
const content = "/**\n * bst-hook — Claude Code PreToolUse hook\n * @bensandee/claude-hooks v0.2.0\n * https://github.com/bensandee/tooling\n *\n * Auto-generated by @bensandee/tooling repo:sync — do not edit manually.\n */\nimport*as e from\"node:fs\";import{readFileSync as t,readdirSync as n,statSync as r}from\"node:fs\";import*as i from\"node:path\";import{join as a,resolve as o}from\"node:path\";import{fileURLToPath as s}from\"node:url\";Object.freeze({status:`aborted`});function c(e,t,n){function r(n,r){if(n._zod||Object.defineProperty(n,`_zod`,{value:{def:r,constr:o,traits:new Set},enumerable:!1}),n._zod.traits.has(e))return;n._zod.traits.add(e),t(n,r);let i=o.prototype,a=Object.keys(i);for(let e=0;e<a.length;e++){let t=a[e];t in n||(n[t]=i[t].bind(n))}}let i=n?.Parent??Object;class a extends i{}Object.defineProperty(a,`name`,{value:e});function o(e){var t;let i=n?.Parent?new a:this;r(i,e),(t=i._zod).deferred??(t.deferred=[]);for(let e of i._zod.deferred)e();return i}return Object.defineProperty(o,`init`,{value:r}),Object.defineProperty(o,Symbol.hasInstance,{value:t=>n?.Parent&&t instanceof n.Parent?!0:t?._zod?.traits?.has(e)}),Object.defineProperty(o,`name`,{value:e}),o}var l=class extends Error{constructor(){super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`)}};const u={};function d(e){return e&&Object.assign(u,e),u}function ee(e,t){return typeof t==`bigint`?t.toString():t}function te(e){return{get value(){{let t=e();return Object.defineProperty(this,`value`,{value:t}),t}throw Error(`cached value already set`)}}}function ne(e){let t=e.startsWith(`^`)?1:0,n=e.endsWith(`$`)?e.length-1:e.length;return e.slice(t,n)}const f=Symbol(`evaluating`);function p(e,t,n){let r;Object.defineProperty(e,t,{get(){if(r!==f)return r===void 0&&(r=f,r=n()),r},set(n){Object.defineProperty(e,t,{value:n})},configurable:!0})}const m=`captureStackTrace`in Error?Error.captureStackTrace:(...e)=>{};function h(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function re(e){if(h(e)===!1)return!1;let t=e.constructor;if(t===void 0||typeof t!=`function`)return!0;let n=t.prototype;return!(h(n)===!1||Object.prototype.hasOwnProperty.call(n,`isPrototypeOf`)===!1)}function ie(e,t,n){let r=new e._zod.constr(t??e._zod.def);return(!t||n?.parent)&&(r._zod.parent=e),r}function g(e){let t=e;if(!t)return{};if(typeof t==`string`)return{error:()=>t};if(t?.message!==void 0){if(t?.error!==void 0)throw Error(\"Cannot specify both `message` and `error` params\");t.error=t.message}return delete t.message,typeof t.error==`string`?{...t,error:()=>t.error}:t}function _(e){return Object.keys(e).filter(t=>e[t]._zod.optin===`optional`&&e[t]._zod.optout===`optional`)}-Number.MAX_VALUE,Number.MAX_VALUE;function v(e,t=0){if(e.aborted===!0)return!0;for(let n=t;n<e.issues.length;n++)if(e.issues[n]?.continue!==!0)return!0;return!1}function y(e,t){return t.map(t=>{var n;return(n=t).path??(n.path=[]),t.path.unshift(e),t})}function b(e){return typeof e==`string`?e:e?.message}function x(e,t,n){let r={...e,path:e.path??[]};return e.message||(r.message=b(e.inst?._zod.def?.error?.(e))??b(t?.error?.(e))??b(n.customError?.(e))??b(n.localeError?.(e))??`Invalid input`),delete r.inst,delete r.continue,t?.reportInput||delete r.input,r}const S=(e,t)=>{e.name=`$ZodError`,Object.defineProperty(e,`_zod`,{value:e._zod,enumerable:!1}),Object.defineProperty(e,`issues`,{value:t,enumerable:!1}),e.message=JSON.stringify(t,ee,2),Object.defineProperty(e,`toString`,{value:()=>e.message,enumerable:!1})},ae=c(`$ZodError`,S),C=c(`$ZodError`,S,{Parent:Error}),w=(e=>(t,n,r,i)=>{let a=r?Object.assign(r,{async:!1}):{async:!1},o=t._zod.run({value:n,issues:[]},a);if(o instanceof Promise)throw new l;if(o.issues.length){let t=new(i?.Err??e)(o.issues.map(e=>x(e,a,d())));throw m(t,i?.callee),t}return o.value})(C),oe=(e=>async(t,n,r,i)=>{let a=r?Object.assign(r,{async:!0}):{async:!0},o=t._zod.run({value:n,issues:[]},a);if(o instanceof Promise&&(o=await o),o.issues.length){let t=new(i?.Err??e)(o.issues.map(e=>x(e,a,d())));throw m(t,i?.callee),t}return o.value})(C),T=(e=>(t,n,r)=>{let i=r?{...r,async:!1}:{async:!1},a=t._zod.run({value:n,issues:[]},i);if(a instanceof Promise)throw new l;return a.issues.length?{success:!1,error:new(e??ae)(a.issues.map(e=>x(e,i,d())))}:{success:!0,data:a.value}})(C),E=(e=>async(t,n,r)=>{let i=r?Object.assign(r,{async:!0}):{async:!0},a=t._zod.run({value:n,issues:[]},i);return a instanceof Promise&&(a=await a),a.issues.length?{success:!1,error:new e(a.issues.map(e=>x(e,i,d())))}:{success:!0,data:a.value}})(C),se=e=>{let t=e?`[\\\\s\\\\S]{${e?.minimum??0},${e?.maximum??``}}`:`[\\\\s\\\\S]*`;return RegExp(`^${t}$`)},ce=/^-?\\d+(?:\\.\\d+)?$/,le={major:4,minor:3,patch:6},D=c(`$ZodType`,(e,t)=>{var n;e??={},e._zod.def=t,e._zod.bag=e._zod.bag||{},e._zod.version=le;let r=[...e._zod.def.checks??[]];e._zod.traits.has(`$ZodCheck`)&&r.unshift(e);for(let t of r)for(let n of t._zod.onattach)n(e);if(r.length===0)(n=e._zod).deferred??(n.deferred=[]),e._zod.deferred?.push(()=>{e._zod.run=e._zod.parse});else{let t=(e,t,n)=>{let r=v(e),i;for(let a of t){if(a._zod.def.when){if(!a._zod.def.when(e))continue}else if(r)continue;let t=e.issues.length,o=a._zod.check(e);if(o instanceof Promise&&n?.async===!1)throw new l;if(i||o instanceof Promise)i=(i??Promise.resolve()).then(async()=>{await o,e.issues.length!==t&&(r||=v(e,t))});else{if(e.issues.length===t)continue;r||=v(e,t)}}return i?i.then(()=>e):e},n=(n,i,a)=>{if(v(n))return n.aborted=!0,n;let o=t(i,r,a);if(o instanceof Promise){if(a.async===!1)throw new l;return o.then(t=>e._zod.parse(t,a))}return e._zod.parse(o,a)};e._zod.run=(i,a)=>{if(a.skipChecks)return e._zod.parse(i,a);if(a.direction===`backward`){let t=e._zod.parse({value:i.value,issues:[]},{...a,skipChecks:!0});return t instanceof Promise?t.then(e=>n(e,i,a)):n(t,i,a)}let o=e._zod.parse(i,a);if(o instanceof Promise){if(a.async===!1)throw new l;return o.then(e=>t(e,r,a))}return t(o,r,a)}}p(e,`~standard`,()=>({validate:t=>{try{let n=T(e,t);return n.success?{value:n.data}:{issues:n.error?.issues}}catch{return E(e,t).then(e=>e.success?{value:e.data}:{issues:e.error?.issues})}},vendor:`zod`,version:1}))}),ue=c(`$ZodString`,(e,t)=>{D.init(e,t),e._zod.pattern=[...e?._zod.bag?.patterns??[]].pop()??se(e._zod.bag),e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=String(n.value)}catch{}return typeof n.value==`string`||n.issues.push({expected:`string`,code:`invalid_type`,input:n.value,inst:e}),n}}),de=c(`$ZodUnknown`,(e,t)=>{D.init(e,t),e._zod.parse=e=>e});function O(e,t,n,r,i){if(e.issues.length){if(i&&!(n in r))return;t.issues.push(...y(n,e.issues))}e.value===void 0?n in r&&(t.value[n]=void 0):t.value[n]=e.value}function fe(e){let t=Object.keys(e.shape);for(let n of t)if(!e.shape?.[n]?._zod?.traits?.has(`$ZodType`))throw Error(`Invalid element at key \"${n}\": expected a Zod schema`);let n=_(e.shape);return{...e,keys:t,keySet:new Set(t),numKeys:t.length,optionalKeys:new Set(n)}}function pe(e,t,n,r,i,a){let o=[],s=i.keySet,c=i.catchall._zod,l=c.def.type,u=c.optout===`optional`;for(let i in t){if(s.has(i))continue;if(l===`never`){o.push(i);continue}let a=c.run({value:t[i],issues:[]},r);a instanceof Promise?e.push(a.then(e=>O(e,n,i,t,u))):O(a,n,i,t,u)}return o.length&&n.issues.push({code:`unrecognized_keys`,keys:o,input:t,inst:a}),e.length?Promise.all(e).then(()=>n):n}const me=c(`$ZodObject`,(e,t)=>{if(D.init(e,t),!Object.getOwnPropertyDescriptor(t,`shape`)?.get){let e=t.shape;Object.defineProperty(t,`shape`,{get:()=>{let n={...e};return Object.defineProperty(t,`shape`,{value:n}),n}})}let n=te(()=>fe(t));p(e._zod,`propValues`,()=>{let e=t.shape,n={};for(let t in e){let r=e[t]._zod;if(r.values){n[t]??(n[t]=new Set);for(let e of r.values)n[t].add(e)}}return n});let r=h,i=t.catchall,a;e._zod.parse=(t,o)=>{a??=n.value;let s=t.value;if(!r(s))return t.issues.push({expected:`object`,code:`invalid_type`,input:s,inst:e}),t;t.value={};let c=[],l=a.shape;for(let e of a.keys){let n=l[e],r=n._zod.optout===`optional`,i=n._zod.run({value:s[e],issues:[]},o);i instanceof Promise?c.push(i.then(n=>O(n,t,e,s,r))):O(i,t,e,s,r)}return i?pe(c,s,t,o,n.value,e):c.length?Promise.all(c).then(()=>t):t}}),he=c(`$ZodRecord`,(e,t)=>{D.init(e,t),e._zod.parse=(n,r)=>{let i=n.value;if(!re(i))return n.issues.push({expected:`record`,code:`invalid_type`,input:i,inst:e}),n;let a=[],o=t.keyType._zod.values;if(o){n.value={};let s=new Set;for(let e of o)if(typeof e==`string`||typeof e==`number`||typeof e==`symbol`){s.add(typeof e==`number`?e.toString():e);let o=t.valueType._zod.run({value:i[e],issues:[]},r);o instanceof Promise?a.push(o.then(t=>{t.issues.length&&n.issues.push(...y(e,t.issues)),n.value[e]=t.value})):(o.issues.length&&n.issues.push(...y(e,o.issues)),n.value[e]=o.value)}let c;for(let e in i)s.has(e)||(c??=[],c.push(e));c&&c.length>0&&n.issues.push({code:`unrecognized_keys`,input:i,inst:e,keys:c})}else{n.value={};for(let o of Reflect.ownKeys(i)){if(o===`__proto__`)continue;let s=t.keyType._zod.run({value:o,issues:[]},r);if(s instanceof Promise)throw Error(`Async schemas not supported in object keys currently`);if(typeof o==`string`&&ce.test(o)&&s.issues.length){let e=t.keyType._zod.run({value:Number(o),issues:[]},r);if(e instanceof Promise)throw Error(`Async schemas not supported in object keys currently`);e.issues.length===0&&(s=e)}if(s.issues.length){t.mode===`loose`?n.value[o]=i[o]:n.issues.push({code:`invalid_key`,origin:`record`,issues:s.issues.map(e=>x(e,r,d())),input:o,path:[o],inst:e});continue}let c=t.valueType._zod.run({value:i[o],issues:[]},r);c instanceof Promise?a.push(c.then(e=>{e.issues.length&&n.issues.push(...y(o,e.issues)),n.value[s.value]=e.value})):(c.issues.length&&n.issues.push(...y(o,c.issues)),n.value[s.value]=c.value)}}return a.length?Promise.all(a).then(()=>n):n}});function k(e,t){return e.issues.length&&t===void 0?{issues:[],value:void 0}:e}const ge=c(`$ZodOptional`,(e,t)=>{D.init(e,t),e._zod.optin=`optional`,e._zod.optout=`optional`,p(e._zod,`values`,()=>t.innerType._zod.values?new Set([...t.innerType._zod.values,void 0]):void 0),p(e._zod,`pattern`,()=>{let e=t.innerType._zod.pattern;return e?RegExp(`^(${ne(e.source)})?$`):void 0}),e._zod.parse=(e,n)=>{if(t.innerType._zod.optin===`optional`){let r=t.innerType._zod.run(e,n);return r instanceof Promise?r.then(t=>k(t,e.value)):k(r,e.value)}return e.value===void 0?e:t.innerType._zod.run(e,n)}});var A,_e=class{constructor(){this._map=new WeakMap,this._idmap=new Map}add(e,...t){let n=t[0];return this._map.set(e,n),n&&typeof n==`object`&&`id`in n&&this._idmap.set(n.id,e),this}clear(){return this._map=new WeakMap,this._idmap=new Map,this}remove(e){let t=this._map.get(e);return t&&typeof t==`object`&&`id`in t&&this._idmap.delete(t.id),this._map.delete(e),this}get(e){let t=e._zod.parent;if(t){let n={...this.get(t)??{}};delete n.id;let r={...n,...this._map.get(e)};return Object.keys(r).length?r:void 0}return this._map.get(e)}has(e){return this._map.has(e)}};function j(){return new _e}(A=globalThis).__zod_globalRegistry??(A.__zod_globalRegistry=j()),globalThis.__zod_globalRegistry;function M(e,t){return new e({type:`string`,...g(t)})}function N(e){return new e({type:`unknown`})}const P=c(`ZodMiniType`,(e,t)=>{if(!e._zod)throw Error(`Uninitialized schema in ZodMiniType.`);D.init(e,t),e.def=t,e.type=t.type,e.parse=(t,n)=>w(e,t,n,{callee:e.parse}),e.safeParse=(t,n)=>T(e,t,n),e.parseAsync=async(t,n)=>oe(e,t,n,{callee:e.parseAsync}),e.safeParseAsync=async(t,n)=>E(e,t,n),e.check=(...n)=>e.clone({...t,checks:[...t.checks??[],...n.map(e=>typeof e==`function`?{_zod:{check:e,def:{check:`custom`},onattach:[]}}:e)]},{parent:!0}),e.with=e.check,e.clone=(t,n)=>ie(e,t,n),e.brand=()=>e,e.register=((t,n)=>(t.add(e,n),e)),e.apply=t=>t(e)}),F=c(`ZodMiniString`,(e,t)=>{ue.init(e,t),P.init(e,t)});function I(e){return M(F,e)}const ve=c(`ZodMiniUnknown`,(e,t)=>{de.init(e,t),P.init(e,t)});function ye(){return N(ve)}const be=c(`ZodMiniObject`,(e,t)=>{me.init(e,t),P.init(e,t),p(e,`shape`,()=>t.shape)});function L(e,t){return new be({type:`object`,shape:e??{},...g(t)})}const xe=c(`ZodMiniRecord`,(e,t)=>{he.init(e,t),P.init(e,t)});function Se(e,t,n){return new xe({type:`record`,keyType:e,valueType:t,...g(n)})}const Ce=c(`ZodMiniOptional`,(e,t)=>{ge.init(e,t),P.init(e,t)});function we(e){return new Ce({type:`optional`,innerType:e})}const Te=L({session_id:I(),transcript_path:I(),cwd:I(),permission_mode:I(),hook_event_name:I(),tool_name:I(),tool_input:L({command:I(),description:we(I())})});async function Ee(){let e=[];for await(let t of process.stdin)e.push(typeof t==`string`?t:String(t));let t=JSON.parse(e.join(``)),n=Te.safeParse(t);return n.success||(process.stderr.write(`[bst-hook] invalid hook input: ${n.error.message}\\n`),process.exit(0)),n.data}function R(e,t){let n={hookSpecificOutput:{hookEventName:`PreToolUse`,permissionDecision:e,...e===`deny`&&t?{permissionDecisionReason:t}:{}}};process.stdout.write(JSON.stringify(n))}function De(){let e=i.dirname(s(import.meta.url));return i.join(e,`bst-hook.audit.local.jsonl`)}function Oe(t){try{if(e.statSync(t).size>1048576){let n=`${t}.1`;e.renameSync(t,n)}}catch{}}let ke=!1;function Ae(t){try{let n=De();ke||=(Oe(n),!0);let r={timestamp:new Date().toISOString(),...t};e.appendFileSync(n,JSON.stringify(r)+`\n`)}catch(e){process.stderr.write(`[bst-hook] audit write failed: ${e instanceof Error?e.message:String(e)}\\n`)}}function z(e){let t=[],n=``,r=0,i=!1;for(;r<e.length;){let a=e[r];if(a===`'`){for(i=!0,r++;r<e.length&&e[r]!==`'`;)n+=e[r],r++;if(r>=e.length)return{ok:!1,error:`unterminated single quote`};r++}else if(a===`\"`){for(i=!0,r++;r<e.length&&e[r]!==`\"`;){if(e[r]===`\\\\`&&r+1<e.length){let t=e[r+1];if(t===`\"`||t===`\\\\`||t===`$`||t===\"`\"){n+=t,r+=2;continue}}n+=e[r],r++}if(r>=e.length)return{ok:!1,error:`unterminated double quote`};r++}else a===`\\\\`&&r+1<e.length?(i=!0,n+=e[r+1],r+=2):a===` `||a===` `?(i&&=(t.push(n),n=``,!1),r++):(i=!0,n+=a,r++)}return i&&t.push(n),{ok:!0,tokens:t}}function je(e){if(!e||!e.trim())return[];let t=[],n=``,r=0,i=!1,a=!1;for(;r<e.length;){let o=e[r];if(o===`'`&&!a){i=!i,n+=o,r++;continue}if(o===`\"`&&!i){a=!a,n+=o,r++;continue}if(o===`\\\\`&&!i&&r+1<e.length){n+=o+e[r+1],r+=2;continue}if(!i&&!a){if(o===`&`&&r+1<e.length&&e[r+1]===`&`){B(t,n,`&&`),n=``,r+=2;continue}if(o===`|`&&r+1<e.length&&e[r+1]===`|`){B(t,n,`||`),n=``,r+=2;continue}if(o===`|`){B(t,n,`|`),n=``,r++;continue}if(o===`;`){B(t,n,`;`),n=``,r++;continue}}n+=o,r++}let o=n.trim();return o&&t.push({command:o,operator:null}),t}function B(e,t,n){let r=t.trim();r&&e.push({command:r,operator:n})}const V=new Set([`2>&1`,`2>/dev/null`,`>/dev/null`,`1>/dev/null`]);function Me(e,t){if(/[\\n\\r]/.test(t))return{safe:!1,reason:`unquoted newline in command`};for(let t of e){if(t===\"`\")return{safe:!1,reason:`backtick command substitution`};if(t.includes(`$(`))return{safe:!1,reason:`dollar command substitution`};if(t.includes(\"`\"))return{safe:!1,reason:`backtick command substitution`};if(t.includes(`<(`)||t.includes(`>(`)&&!V.has(t))return{safe:!1,reason:`process substitution`}}for(let t=0;t<e.length;t++){let n=e[t];if(!V.has(n)){if(n.includes(`<`)&&!n.includes(`<(`))return{safe:!1,reason:`input redirect`};if(n.includes(`>`)){if(n.endsWith(`>/dev/null`)||n.match(/^(&>>|&>|>>|>|1>|2>)$/)&&e[t+1]===`/dev/null`)continue;return{safe:!1,reason:`output redirect to file`}}}}return{safe:!0}}const Ne=new Set([`status`,`log`,`diff`,`show`,`branch`,`remote`,`fetch`,`rev-parse`]),Pe=new Set([`push`,`add`,`commit`,`reset`,`merge`,`rebase`,`cherry-pick`,`checkout`,`switch`,`stash`,`tag`,`revert`,`clean`,`rm`,`mv`]),Fe=new Set([`-c`,`--exec-path`,`--pager`,`--upload-pack`,`--receive-pack`]),Ie=new Set([`-C`,`-c`,`--git-dir`,`--work-tree`]);function H(e){let t=e.slice(1);for(let e=0;e<t.length;e++){let n=t[e];if(Ie.has(n)){e++;continue}if(!n.startsWith(`-`))return n}}function Le(e){for(let t of e.slice(1))if(Fe.has(t)||t.startsWith(`--exec-path=`)||t.startsWith(`--pager=`)||t.startsWith(`--upload-pack=`)||t.startsWith(`--receive-pack=`))return!1;let t=H(e);if(!t)return!1;if(t===`stash`){let t=e[e.indexOf(`stash`)+1];return t===`list`||t===void 0}return Ne.has(t)}function Re(e){let t=H(e);if(!t)return!1;if(t===`stash`){let t=e[e.indexOf(`stash`)+1];if(t===`list`||t===void 0)return!1}return Pe.has(t)}const U=new Set(`install.i.add.remove.rm.uninstall.un.update.up.upgrade.list.ls.ll.la.why.view.info.show.outdated.audit.licenses.init.create.link.unlink.pack.publish.config.set.get.store.cache.rebuild.rb.prune.dedupe.dlx.exec.run.patch.patch-commit.recursive.-r`.split(`.`)),ze=new Set([`list`,`ls`,`ll`,`la`,`why`,`view`,`info`,`show`,`outdated`]);function Be(e){let t=e.slice(1),n;for(let e of t)if(!(e.startsWith(`-`)&&!U.has(e))){n=e;break}return n?ze.has(n)?!0:n===`install`||n===`i`?t.slice(t.indexOf(n)+1).every(e=>e.startsWith(`-`)):!1:!1}const Ve=new Set([`view`,`info`,`show`]);function He(e){let t=e[1];return t!==void 0&&Ve.has(t)}function Ue(e){let t=e[1],n=`This project uses pnpm.`;return t?t===`install`||t===`i`||t===`ci`?e.slice(2).some(e=>!e.startsWith(`-`))?`${n} Use \\`pnpm add <pkg>\\` instead of \\`npm install <pkg>\\`.`:`${n} Use \\`pnpm install\\` instead of npm.`:t===`add`?`${n} Use \\`pnpm add <pkg>\\` instead of npm.`:t===`uninstall`||t===`remove`||t===`rm`||t===`un`||t===`r`?`${n} Use \\`pnpm remove <pkg>\\` instead of npm.`:t===`run`||t===`run-script`?`${n} Use \\`pnpm run <script>\\` or \\`pnpm <script>\\` instead of npm.`:t===`test`||t===`t`||t===`tst`?`${n} Use \\`pnpm test\\` instead of npm.`:t===`start`?`${n} Use \\`pnpm start\\` instead of npm.`:t===`stop`?`${n} Use \\`pnpm stop\\` instead of npm.`:t===`restart`?`${n} Use \\`pnpm restart\\` instead of npm.`:t===`exec`?`${n} Use \\`pnpm exec <cmd>\\` instead of npm.`:t===`list`||t===`ls`||t===`ll`||t===`la`?`${n} Use \\`pnpm list\\` instead of npm.`:t===`why`?`${n} Use \\`pnpm why\\` instead of npm.`:t===`outdated`?`${n} Use \\`pnpm outdated\\` instead of npm.`:t===`audit`?`${n} Use \\`pnpm audit\\` instead of npm.`:t===`update`||t===`up`||t===`upgrade`?`${n} Use \\`pnpm update\\` instead of npm.`:t===`init`?`${n} Use \\`pnpm init\\` instead of npm.`:t===`publish`?`${n} Use \\`pnpm publish\\` instead of npm.`:t===`link`?`${n} Use \\`pnpm link\\` instead of npm.`:t===`unlink`?`${n} Use \\`pnpm unlink\\` instead of npm.`:t===`pack`?`${n} Use \\`pnpm pack\\` instead of npm.`:t===`cache`?`${n} Use \\`pnpm store\\` instead of \\`npm cache\\`.`:t===`config`||t===`set`||t===`get`?`${n} Use \\`pnpm config\\` instead of npm.`:`${n} Use the equivalent pnpm command instead of npm.`:`${n} Use \\`pnpm\\` instead of npm.`}function W(e,t){for(let n of e.slice(1)){if(n.startsWith(`-`))continue;if(i.basename(n).startsWith(`.`)||n.startsWith(`~/`)||n===`~`)return!1;let e=i.resolve(t.cwd,n);if(e!==t.cwd&&!e.startsWith(t.cwd+i.sep))return!1}return!0}const We=new Set([`-exec`,`-execdir`,`-ok`,`-delete`]);function Ge(e){return!e.some(e=>We.has(e))}function Ke(e){return!e.includes(`-o`)&&!e.some(e=>e.startsWith(`--output`))}function qe(e){let t=e.findIndex(e=>i.basename(e)===`rm`);if(t===-1)return!1;let n=e.slice(t+1),r=n.filter(e=>e.startsWith(`-`)&&!e.startsWith(`--`)),a=n.filter(e=>e.startsWith(`--`)),o=r.some(e=>/[rR]/.test(e)),s=a.includes(`--recursive`);return o||s}function Je(e){return e.some(e=>e===`777`||e===`0777`)}const Ye=/(^|[/\\\\])(\\.env(\\..*)?|.*\\.env(\\..*)?|\\.env)$/;function G(e){return e.slice(1).some(e=>!e.startsWith(`-`)&&Ye.test(e))}function Xe(e){let t=e.indexOf(`push`);if(t===-1)return!1;let n=e.slice(t+1);return n.some(e=>e===`--force`||e===`-f`&&!n.includes(`--force-with-lease`))}function Ze(e){if(!(e.includes(`reset`)&&e.includes(`--hard`)))return!1;if(e.some(e=>e===`main`||e===`master`))return!0;let t=e.filter(e=>e!==`git`&&e!==`reset`&&!e.startsWith(`-`));return t.length===0||t.includes(`HEAD`)}const Qe=[{name:`rm-recursive`,match:/^rm$/,action:`deny`,when:e=>qe(e),reason:\"Don't use recursive `rm`. Use more targeted deletes, or remove specific files/directories.\"},{name:`sudo`,match:/^sudo$/,action:`deny`,reason:`Don't use sudo. If you need elevated permissions, ask me to do it manually.`},{name:`git-force-push`,match:/^git$/,action:`deny`,when:e=>Xe(e),reason:\"Use `git push --force-with-lease` instead of `--force`.\"},{name:`git-reset-hard`,match:/^git$/,action:`deny`,when:e=>Ze(e),reason:\"Don't `reset --hard` on main. Create a branch first.\"},{name:`git-write`,match:/^git$/,action:`deny`,when:e=>Re(e),reason:`Git write operations (push, add, commit, reset, merge, etc.) are not allowed. Ask the user to run these manually.`},{name:`chmod-777`,match:/^chmod$/,action:`deny`,when:e=>Je(e),reason:`Don't use 777 permissions. Use more restrictive permissions.`},{name:`env-file-cat`,match:/^cat$/,action:`deny`,when:e=>G(e),reason:`Don't read .env files. These contain secrets that should not appear in the conversation.`},{name:`env-file-head`,match:/^head$/,action:`deny`,when:e=>G(e),reason:`Don't read .env files. These contain secrets that should not appear in the conversation.`},{name:`env-file-tail`,match:/^tail$/,action:`deny`,when:e=>G(e),reason:`Don't read .env files. These contain secrets that should not appear in the conversation.`},{name:`env-file-less`,match:/^less$/,action:`deny`,when:e=>G(e),reason:`Don't read .env files. These contain secrets that should not appear in the conversation.`},{name:`env-file-more`,match:/^more$/,action:`deny`,when:e=>G(e),reason:`Don't read .env files. These contain secrets that should not appear in the conversation.`},{name:`env-file-grep`,match:/^grep$/,action:`deny`,when:e=>G(e),reason:`Don't read .env files. These contain secrets that should not appear in the conversation.`},{name:`npx-redirect`,match:/^npx$/,action:`deny`,reason:\"This project uses pnpm. Use `pnpm dlx <pkg>` or `pnpm exec <cmd>` instead of npx.\"}],K=[{name:`vitest`,match:/^vitest$/,action:`allow`},{name:`jest`,match:/^jest$/,action:`allow`},{name:`tsc`,match:/^tsc$/,action:`allow`},{name:`tsdown`,match:/^tsdown$/,action:`allow`},{name:`oxlint`,match:/^oxlint$/,action:`allow`},{name:`oxfmt`,match:/^oxfmt$/,action:`allow`},{name:`eslint`,match:/^eslint$/,action:`allow`},{name:`prettier`,match:/^prettier$/,action:`allow`},{name:`biome`,match:/^biome$/,action:`allow`},{name:`knip`,match:/^knip$/,action:`allow`},{name:`cat`,match:/^cat$/,action:`allow`},{name:`head`,match:/^head$/,action:`allow`},{name:`tail`,match:/^tail$/,action:`allow`},{name:`grep`,match:/^grep$/,action:`allow`},{name:`ls`,match:/^ls$/,action:`allow`},{name:`wc`,match:/^wc$/,action:`allow`},{name:`uniq`,match:/^uniq$/,action:`allow`},{name:`diff`,match:/^diff$/,action:`allow`},{name:`echo`,match:/^echo$/,action:`allow`},{name:`pwd`,match:/^pwd$/,action:`allow`},{name:`which`,match:/^which$/,action:`allow`},{name:`dirname`,match:/^dirname$/,action:`allow`},{name:`basename`,match:/^basename$/,action:`allow`},{name:`realpath`,match:/^realpath$/,action:`allow`},{name:`npm`,match:/^npm$/,action:`allow`,when:e=>He(e)},{name:`test`,match:/^test$/,action:`allow`},{name:`bracket-test`,match:/^\\[$/,action:`allow`},{name:`cd`,match:/^cd$/,action:`allow`},{name:`true`,match:/^true$/,action:`allow`},{name:`colon`,match:/^:$/,action:`allow`},{name:`find`,match:/^find$/,action:`allow`,when:e=>Ge(e)},{name:`sort`,match:/^sort$/,action:`allow`,when:e=>Ke(e)},{name:`git`,match:/^git$/,action:`allow`,when:e=>Le(e)},{name:`pnpm`,match:/^pnpm$/,action:`allow`,when:e=>Be(e)},{name:`cp`,match:/^cp$/,action:`allow`,when:(e,t)=>W(e,t)},{name:`mkdir`,match:/^mkdir$/,action:`allow`,when:(e,t)=>W(e,t)},{name:`touch`,match:/^touch$/,action:`allow`,when:(e,t)=>W(e,t)}],$e=L({scripts:Se(I(),ye())});function q(e,t){let n=Y(t);if(!n)return null;let r=n[e];if(typeof r!=`string`)return null;let i=n[`pre${e}`],a=n[`post${e}`];return{pre:typeof i==`string`?i:null,main:r,post:typeof a==`string`?a:null}}function et(e,t,n){let r=nt(t,n);if(!r)return null;let i=q(e,r);return i?{...i,pkgDir:r}:null}function tt(e,t){let n=J(t);if(!n)return null;let r=[];for(let t of n){let n=q(e,t);n&&r.push({...n,pkgDir:t})}return r}function J(e){let t=rt(e);if(!t)return null;let i=[];for(let s of t){if(!s.endsWith(`/*`))continue;let t=o(e,s.slice(0,-2)),c;try{c=n(t)}catch{continue}for(let e of c){let n=a(t,e);try{if(!r(n).isDirectory())continue}catch{continue}i.push(n)}}return i.length>0?i:null}function nt(e,t){let n=J(t);if(!n)return null;for(let t of n){let n=at(t);if(n===e||n===`@${e}`||t.split(`/`).pop()===e||n&&(n.startsWith(`@`)?n.split(`/`)[1]:n)===e)return t}return null}function rt(e){try{let n=t(a(e,`pnpm-workspace.yaml`),`utf-8`).split(`\n`),r=n.findIndex(e=>/^packages\\s*:/.test(e));if(r===-1)return null;let i=[];for(let e=r+1;e<n.length;e++){let t=n[e],r=/^\\s+-\\s+(.+)$/.exec(t);if(!r)break;i.push(r[1].trim().replace(/['\"`]/g,``))}return i.length>0?i:null}catch{return null}}const it=L({name:I()});function at(e){try{let n=t(a(e,`package.json`),`utf-8`),r=it.safeParse(JSON.parse(n));return r.success?r.data.name:null}catch{return null}}function Y(e){try{let n=t(a(e,`package.json`),`utf-8`),r=$e.safeParse(JSON.parse(n));return r.success?r.data.scripts:null}catch{return null}}const ot=new Set([`LD_PRELOAD`,`LD_LIBRARY_PATH`,`DYLD_INSERT_LIBRARIES`,`NODE_OPTIONS`,`PYTHONPATH`,`PYTHONSTARTUP`,`PERL5OPT`,`PERL5LIB`,`RUBYOPT`,`RUBYLIB`,`BASH_ENV`,`ENV`,`npm_config_prefix`,`npm_config_registry`,`EDITOR`,`VISUAL`]),st=[`GIT_CONFIG_`,`GIT_PAGER`,`GIT_SSH_COMMAND`,`GIT_EDITOR`,`GIT_EXEC_PATH`];function X(e){return ot.has(e)?!0:st.some(t=>e.startsWith(t))}function ct(e,t){let n=z(e);if(!n.ok||n.tokens.length!==2)return null;let r=n.tokens;if(r[0]!==`cd`)return null;let a=r[1];return i.isAbsolute(a)?a:i.resolve(t.cwd,a)}function Z(e,t){if(t.depth>=5)return{action:`passthrough`,rule:null,reason:`max evaluation depth exceeded`};let n=e.trim();if(!n)return{action:`passthrough`,rule:null,reason:null};if(n.startsWith(`(`)&&n.endsWith(`)`))return{action:`passthrough`,rule:null,reason:`subshell`};let r=je(n);if(r.length===0)return{action:`passthrough`,rule:null,reason:null};let i=null,a=null,o=t;for(let e of r){if(e.operator===`&&`){let t=ct(e.command,o);t&&(o={...o,cwd:t})}let t=lt(e.command,o);if(t.action===`deny`)return t;t.action===`passthrough`&&(i||=t),t.action===`allow`&&(a=t)}return i||(r.length===1&&a?a:{action:`allow`,rule:`all-segments`,reason:null})}function lt(e,t){let n=e.trim();if(n.startsWith(`(`)&&n.endsWith(`)`))return{action:`passthrough`,rule:null,reason:`subshell`};let r=z(e);if(!r.ok)return{action:`passthrough`,rule:null,reason:r.error};let a=r.tokens;if(a.length===0)return{action:`passthrough`,rule:null,reason:null};let o=0;for(;o<a.length&&/^\\w+=/.test(a[o]);){let e=a[o].split(`=`)[0];if(X(e))return{action:`passthrough`,rule:null,reason:`dangerous env var: ${e}`};o++}if(o>=a.length)return{action:`allow`,rule:`env-only`,reason:null};a=a.slice(o);let s=Me(a,e);if(!s.safe)return{action:`passthrough`,rule:null,reason:s.reason};for(let e=0;e<a.length;e++){let t=a[e];if(!(t===`2>&1`||t===`2>/dev/null`||t===`>/dev/null`||t===`1>/dev/null`)){if(t===`>`||t===`>>`){if(a[e+1]===`/dev/null`)continue;return{action:`passthrough`,rule:null,reason:`output redirect to file`}}if(t===`<`)return{action:`passthrough`,rule:null,reason:`input redirect`}}}let c=i.basename(a[0]);if(c===`command`&&a.length>1)return Z(a.slice(1).join(` `),{...t,depth:t.depth+1});if(c===`env`){let e=1;for(;e<a.length&&/^\\w+=/.test(a[e]);){let t=a[e].split(`=`)[0];if(X(t))return{action:`passthrough`,rule:null,reason:`dangerous env var: ${t}`};e++}return e>=a.length?{action:`allow`,rule:`env-only`,reason:null}:Z(a.slice(e).join(` `),{...t,depth:t.depth+1})}if(c===`pnpm`)return ut(a,t);if(c===`npm`)return pt(a);if(c===`bash`||c===`sh`||c===`zsh`)return gt(a,t);if(c===`node`&&(a.includes(`-e`)||a.includes(`-p`)||a.includes(`--eval`)||a.includes(`--print`)))return{action:`passthrough`,rule:null,reason:`node eval`};if(c===`mv`)return{action:`passthrough`,rule:null,reason:`mv`};for(let e of Qe)if(e.match.test(c)&&(!e.when||e.when(a,t)))return{action:`deny`,rule:e.name,reason:e.reason??null};for(let e of K)if(e.match.test(c)&&(!e.when||e.when(a,t)))return{action:`allow`,rule:e.name,reason:null};return{action:`passthrough`,rule:null,reason:`no rule matched: ${c}`}}function ut(e,t){let n=e.slice(1),r,i=-1,a=!1;for(let o=0;o<n.length;o++){let s=n[o];if(s===`--filter`||s.startsWith(`--filter=`))return mt(e,n,o,t);if(s===`-r`||s===`--recursive`){a=!0;continue}if(!(s.startsWith(`-`)&&!U.has(s))){r=s,i=o;break}}if(!r)return{action:`passthrough`,rule:null,reason:null};if(r===`dlx`)return{action:`passthrough`,rule:null,reason:`pnpm dlx`};if(r===`add`)return{action:`passthrough`,rule:null,reason:`pnpm add`};if(r===`exec`){let e=n.slice(i+1);return e.length===0?{action:`passthrough`,rule:null,reason:`bare pnpm exec`}:Z(e.join(` `),{...t,depth:t.depth+1})}let o;if(r===`run`){let e=n[i+1];if(!e||e.startsWith(`-`))return{action:`passthrough`,rule:null,reason:`pnpm run without script name`};o=e}else if(!U.has(r))o=r;else{for(let n of K)if(n.match.test(`pnpm`)&&(!n.when||n.when(e,t)))return{action:`allow`,rule:n.name,reason:null};return{action:`passthrough`,rule:null,reason:null}}return a?ft(o,t):dt(o,t)}function dt(e,t){let n=q(e,t.cwd);if(!n)return{action:`passthrough`,rule:null,reason:`script resolution failed`};let r={...t,depth:t.depth+1};if(n.pre){let e=Z(n.pre,r);if(e.action!==`allow`)return e}let i=Z(n.main,r);if(i.action!==`allow`)return i;if(n.post){let e=Z(n.post,r);if(e.action!==`allow`)return e}return{action:`allow`,rule:`pnpm-script:${e}`,reason:null}}function ft(e,t){let n=tt(e,t.cwd);if(!n||n.length===0)return{action:`passthrough`,rule:null,reason:`pnpm recursive`};for(let e of n){let n={...t,depth:t.depth+1,cwd:e.pkgDir??t.cwd};if(e.pre){let t=Z(e.pre,n);if(t.action!==`allow`)return t}let r=Z(e.main,n);if(r.action!==`allow`)return r;if(e.post){let t=Z(e.post,n);if(t.action!==`allow`)return t}}return{action:`allow`,rule:`pnpm-recursive:${e}`,reason:null}}function pt(e){for(let t of K)if(t.match.test(`npm`)&&(!t.when||t.when(e,{cwd:``,depth:0})))return{action:`allow`,rule:t.name,reason:null};return{action:`deny`,rule:`npm-redirect`,reason:Ue(e)}}function mt(e,t,n,r){let i=t[n],a,o;if(i.startsWith(`--filter=`))a=i.slice(9),o=n+1;else{if(a=t[n+1],!a||a.startsWith(`-`))return{action:`passthrough`,rule:null,reason:`pnpm --filter without package`};o=n+2}if(!a)return{action:`passthrough`,rule:null,reason:`pnpm --filter without package`};let s;for(let e=o;e<t.length;e++){let n=t[e];if(!(n.startsWith(`-`)&&!U.has(n))){s=n;break}}if(!s)return{action:`passthrough`,rule:null,reason:`pnpm --filter without subcommand`};if(s===`install`||s===`i`)return t.slice(t.indexOf(s)+1).every(e=>e.startsWith(`-`))?{action:`allow`,rule:`pnpm`,reason:null}:{action:`passthrough`,rule:null,reason:`pnpm --filter install with package arg`};if(s===`dlx`)return{action:`passthrough`,rule:null,reason:`pnpm dlx`};if(s===`add`)return{action:`passthrough`,rule:null,reason:`pnpm add`};if(new Set([`list`,`ls`,`ll`,`la`,`why`,`view`,`info`,`show`,`outdated`,`licenses`,`audit`]).has(s))return{action:`allow`,rule:`pnpm`,reason:null};if(s===`exec`){let e=t.indexOf(`exec`,o),n=t.slice(e+1);return n.length===0?{action:`passthrough`,rule:null,reason:`bare pnpm exec`}:Z(n.join(` `),{...r,depth:r.depth+1})}let c=s===`run`?t[t.indexOf(`run`,o)+1]:s;if(!c||c.startsWith(`-`))return{action:`passthrough`,rule:null,reason:`pnpm --filter run without script name`};if(U.has(c)&&c!==`run`)return{action:`passthrough`,rule:null,reason:null};let l=et(c,a,r.cwd);if(!l)return{action:`passthrough`,rule:null,reason:`filtered script resolution failed`};let u={...r,depth:r.depth+1,cwd:l.pkgDir??r.cwd};if(l.pre){let e=Z(l.pre,u);if(e.action!==`allow`)return e}let d=Z(l.main,u);if(d.action!==`allow`)return d;if(l.post){let e=Z(l.post,u);if(e.action!==`allow`)return e}return{action:`allow`,rule:`pnpm-filter:${a}:${c}`,reason:null}}const ht=new Set([`-i`,`--interactive`,`-l`,`--login`,`--init-file`,`--rcfile`,`--norc`,`--noprofile`,`-s`,`--stdin`]);function gt(e,t){let n=e.indexOf(`-c`);if(n===-1)return{action:`passthrough`,rule:null,reason:`shell without -c`};for(let t=1;t<e.length;t++){if(t===n||t===n+1)continue;let r=e[t];if(r.startsWith(`-`)||ht.has(r))return{action:`passthrough`,rule:null,reason:`shell -c with extra flags`}}let r=e[n+1];return r?e.length>n+2?{action:`passthrough`,rule:null,reason:`shell -c with positional args`}:n===1?Z(r,{...t,depth:t.depth+1}):{action:`passthrough`,rule:null,reason:`shell -c with extra flags`}:{action:`passthrough`,rule:null,reason:`shell -c without command`}}const Q=await Ee();(Q.hook_event_name!==`PreToolUse`||Q.tool_name!==`Bash`)&&process.exit(0);const $=Z(Q.tool_input.command,{cwd:Q.cwd,depth:0});Ae({sessionId:Q.session_id,cwd:Q.cwd,command:Q.tool_input.command,decision:$.action,rule:$.rule,reason:$.reason}),$.action===`allow`?R(`allow`):$.action===`deny`&&R(`deny`,$.reason);export{};";
|
|
2394
|
+
const content = "/**\n * bst-hook — Claude Code PreToolUse hook\n * @bensandee/claude-hooks v0.3.0\n * https://github.com/bensandee/tooling\n *\n * Auto-generated by @bensandee/tooling repo:sync — do not edit manually.\n */\nimport*as e from\"node:fs\";import{existsSync as t,readFileSync as n,readdirSync as r,statSync as i}from\"node:fs\";import*as a from\"node:path\";import{dirname as o,join as s,resolve as c}from\"node:path\";import{fileURLToPath as l}from\"node:url\";Object.freeze({status:`aborted`});function u(e,t,n){function r(n,r){if(n._zod||Object.defineProperty(n,`_zod`,{value:{def:r,constr:o,traits:new Set},enumerable:!1}),n._zod.traits.has(e))return;n._zod.traits.add(e),t(n,r);let i=o.prototype,a=Object.keys(i);for(let e=0;e<a.length;e++){let t=a[e];t in n||(n[t]=i[t].bind(n))}}let i=n?.Parent??Object;class a extends i{}Object.defineProperty(a,`name`,{value:e});function o(e){var t;let i=n?.Parent?new a:this;r(i,e),(t=i._zod).deferred??(t.deferred=[]);for(let e of i._zod.deferred)e();return i}return Object.defineProperty(o,`init`,{value:r}),Object.defineProperty(o,Symbol.hasInstance,{value:t=>n?.Parent&&t instanceof n.Parent?!0:t?._zod?.traits?.has(e)}),Object.defineProperty(o,`name`,{value:e}),o}var d=class extends Error{constructor(){super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`)}};const f={};function p(e){return e&&Object.assign(f,e),f}function ee(e,t){return typeof t==`bigint`?t.toString():t}function te(e){return{get value(){{let t=e();return Object.defineProperty(this,`value`,{value:t}),t}throw Error(`cached value already set`)}}}function ne(e){let t=e.startsWith(`^`)?1:0,n=e.endsWith(`$`)?e.length-1:e.length;return e.slice(t,n)}const re=Symbol(`evaluating`);function m(e,t,n){let r;Object.defineProperty(e,t,{get(){if(r!==re)return r===void 0&&(r=re,r=n()),r},set(n){Object.defineProperty(e,t,{value:n})},configurable:!0})}const h=`captureStackTrace`in Error?Error.captureStackTrace:(...e)=>{};function g(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function ie(e){if(g(e)===!1)return!1;let t=e.constructor;if(t===void 0||typeof t!=`function`)return!0;let n=t.prototype;return!(g(n)===!1||Object.prototype.hasOwnProperty.call(n,`isPrototypeOf`)===!1)}function ae(e,t,n){let r=new e._zod.constr(t??e._zod.def);return(!t||n?.parent)&&(r._zod.parent=e),r}function _(e){let t=e;if(!t)return{};if(typeof t==`string`)return{error:()=>t};if(t?.message!==void 0){if(t?.error!==void 0)throw Error(\"Cannot specify both `message` and `error` params\");t.error=t.message}return delete t.message,typeof t.error==`string`?{...t,error:()=>t.error}:t}function oe(e){return Object.keys(e).filter(t=>e[t]._zod.optin===`optional`&&e[t]._zod.optout===`optional`)}-Number.MAX_VALUE,Number.MAX_VALUE;function v(e,t=0){if(e.aborted===!0)return!0;for(let n=t;n<e.issues.length;n++)if(e.issues[n]?.continue!==!0)return!0;return!1}function y(e,t){return t.map(t=>{var n;return(n=t).path??(n.path=[]),t.path.unshift(e),t})}function b(e){return typeof e==`string`?e:e?.message}function x(e,t,n){let r={...e,path:e.path??[]};return e.message||(r.message=b(e.inst?._zod.def?.error?.(e))??b(t?.error?.(e))??b(n.customError?.(e))??b(n.localeError?.(e))??`Invalid input`),delete r.inst,delete r.continue,t?.reportInput||delete r.input,r}const se=(e,t)=>{e.name=`$ZodError`,Object.defineProperty(e,`_zod`,{value:e._zod,enumerable:!1}),Object.defineProperty(e,`issues`,{value:t,enumerable:!1}),e.message=JSON.stringify(t,ee,2),Object.defineProperty(e,`toString`,{value:()=>e.message,enumerable:!1})},ce=u(`$ZodError`,se),S=u(`$ZodError`,se,{Parent:Error}),le=(e=>(t,n,r,i)=>{let a=r?Object.assign(r,{async:!1}):{async:!1},o=t._zod.run({value:n,issues:[]},a);if(o instanceof Promise)throw new d;if(o.issues.length){let t=new(i?.Err??e)(o.issues.map(e=>x(e,a,p())));throw h(t,i?.callee),t}return o.value})(S),ue=(e=>async(t,n,r,i)=>{let a=r?Object.assign(r,{async:!0}):{async:!0},o=t._zod.run({value:n,issues:[]},a);if(o instanceof Promise&&(o=await o),o.issues.length){let t=new(i?.Err??e)(o.issues.map(e=>x(e,a,p())));throw h(t,i?.callee),t}return o.value})(S),C=(e=>(t,n,r)=>{let i=r?{...r,async:!1}:{async:!1},a=t._zod.run({value:n,issues:[]},i);if(a instanceof Promise)throw new d;return a.issues.length?{success:!1,error:new(e??ce)(a.issues.map(e=>x(e,i,p())))}:{success:!0,data:a.value}})(S),w=(e=>async(t,n,r)=>{let i=r?Object.assign(r,{async:!0}):{async:!0},a=t._zod.run({value:n,issues:[]},i);return a instanceof Promise&&(a=await a),a.issues.length?{success:!1,error:new e(a.issues.map(e=>x(e,i,p())))}:{success:!0,data:a.value}})(S),de=e=>{let t=e?`[\\\\s\\\\S]{${e?.minimum??0},${e?.maximum??``}}`:`[\\\\s\\\\S]*`;return RegExp(`^${t}$`)},fe=/^-?\\d+(?:\\.\\d+)?$/,pe={major:4,minor:3,patch:6},T=u(`$ZodType`,(e,t)=>{var n;e??={},e._zod.def=t,e._zod.bag=e._zod.bag||{},e._zod.version=pe;let r=[...e._zod.def.checks??[]];e._zod.traits.has(`$ZodCheck`)&&r.unshift(e);for(let t of r)for(let n of t._zod.onattach)n(e);if(r.length===0)(n=e._zod).deferred??(n.deferred=[]),e._zod.deferred?.push(()=>{e._zod.run=e._zod.parse});else{let t=(e,t,n)=>{let r=v(e),i;for(let a of t){if(a._zod.def.when){if(!a._zod.def.when(e))continue}else if(r)continue;let t=e.issues.length,o=a._zod.check(e);if(o instanceof Promise&&n?.async===!1)throw new d;if(i||o instanceof Promise)i=(i??Promise.resolve()).then(async()=>{await o,e.issues.length!==t&&(r||=v(e,t))});else{if(e.issues.length===t)continue;r||=v(e,t)}}return i?i.then(()=>e):e},n=(n,i,a)=>{if(v(n))return n.aborted=!0,n;let o=t(i,r,a);if(o instanceof Promise){if(a.async===!1)throw new d;return o.then(t=>e._zod.parse(t,a))}return e._zod.parse(o,a)};e._zod.run=(i,a)=>{if(a.skipChecks)return e._zod.parse(i,a);if(a.direction===`backward`){let t=e._zod.parse({value:i.value,issues:[]},{...a,skipChecks:!0});return t instanceof Promise?t.then(e=>n(e,i,a)):n(t,i,a)}let o=e._zod.parse(i,a);if(o instanceof Promise){if(a.async===!1)throw new d;return o.then(e=>t(e,r,a))}return t(o,r,a)}}m(e,`~standard`,()=>({validate:t=>{try{let n=C(e,t);return n.success?{value:n.data}:{issues:n.error?.issues}}catch{return w(e,t).then(e=>e.success?{value:e.data}:{issues:e.error?.issues})}},vendor:`zod`,version:1}))}),me=u(`$ZodString`,(e,t)=>{T.init(e,t),e._zod.pattern=[...e?._zod.bag?.patterns??[]].pop()??de(e._zod.bag),e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=String(n.value)}catch{}return typeof n.value==`string`||n.issues.push({expected:`string`,code:`invalid_type`,input:n.value,inst:e}),n}}),he=u(`$ZodUnknown`,(e,t)=>{T.init(e,t),e._zod.parse=e=>e});function E(e,t,n,r,i){if(e.issues.length){if(i&&!(n in r))return;t.issues.push(...y(n,e.issues))}e.value===void 0?n in r&&(t.value[n]=void 0):t.value[n]=e.value}function ge(e){let t=Object.keys(e.shape);for(let n of t)if(!e.shape?.[n]?._zod?.traits?.has(`$ZodType`))throw Error(`Invalid element at key \"${n}\": expected a Zod schema`);let n=oe(e.shape);return{...e,keys:t,keySet:new Set(t),numKeys:t.length,optionalKeys:new Set(n)}}function _e(e,t,n,r,i,a){let o=[],s=i.keySet,c=i.catchall._zod,l=c.def.type,u=c.optout===`optional`;for(let i in t){if(s.has(i))continue;if(l===`never`){o.push(i);continue}let a=c.run({value:t[i],issues:[]},r);a instanceof Promise?e.push(a.then(e=>E(e,n,i,t,u))):E(a,n,i,t,u)}return o.length&&n.issues.push({code:`unrecognized_keys`,keys:o,input:t,inst:a}),e.length?Promise.all(e).then(()=>n):n}const ve=u(`$ZodObject`,(e,t)=>{if(T.init(e,t),!Object.getOwnPropertyDescriptor(t,`shape`)?.get){let e=t.shape;Object.defineProperty(t,`shape`,{get:()=>{let n={...e};return Object.defineProperty(t,`shape`,{value:n}),n}})}let n=te(()=>ge(t));m(e._zod,`propValues`,()=>{let e=t.shape,n={};for(let t in e){let r=e[t]._zod;if(r.values){n[t]??(n[t]=new Set);for(let e of r.values)n[t].add(e)}}return n});let r=g,i=t.catchall,a;e._zod.parse=(t,o)=>{a??=n.value;let s=t.value;if(!r(s))return t.issues.push({expected:`object`,code:`invalid_type`,input:s,inst:e}),t;t.value={};let c=[],l=a.shape;for(let e of a.keys){let n=l[e],r=n._zod.optout===`optional`,i=n._zod.run({value:s[e],issues:[]},o);i instanceof Promise?c.push(i.then(n=>E(n,t,e,s,r))):E(i,t,e,s,r)}return i?_e(c,s,t,o,n.value,e):c.length?Promise.all(c).then(()=>t):t}}),ye=u(`$ZodRecord`,(e,t)=>{T.init(e,t),e._zod.parse=(n,r)=>{let i=n.value;if(!ie(i))return n.issues.push({expected:`record`,code:`invalid_type`,input:i,inst:e}),n;let a=[],o=t.keyType._zod.values;if(o){n.value={};let s=new Set;for(let e of o)if(typeof e==`string`||typeof e==`number`||typeof e==`symbol`){s.add(typeof e==`number`?e.toString():e);let o=t.valueType._zod.run({value:i[e],issues:[]},r);o instanceof Promise?a.push(o.then(t=>{t.issues.length&&n.issues.push(...y(e,t.issues)),n.value[e]=t.value})):(o.issues.length&&n.issues.push(...y(e,o.issues)),n.value[e]=o.value)}let c;for(let e in i)s.has(e)||(c??=[],c.push(e));c&&c.length>0&&n.issues.push({code:`unrecognized_keys`,input:i,inst:e,keys:c})}else{n.value={};for(let o of Reflect.ownKeys(i)){if(o===`__proto__`)continue;let s=t.keyType._zod.run({value:o,issues:[]},r);if(s instanceof Promise)throw Error(`Async schemas not supported in object keys currently`);if(typeof o==`string`&&fe.test(o)&&s.issues.length){let e=t.keyType._zod.run({value:Number(o),issues:[]},r);if(e instanceof Promise)throw Error(`Async schemas not supported in object keys currently`);e.issues.length===0&&(s=e)}if(s.issues.length){t.mode===`loose`?n.value[o]=i[o]:n.issues.push({code:`invalid_key`,origin:`record`,issues:s.issues.map(e=>x(e,r,p())),input:o,path:[o],inst:e});continue}let c=t.valueType._zod.run({value:i[o],issues:[]},r);c instanceof Promise?a.push(c.then(e=>{e.issues.length&&n.issues.push(...y(o,e.issues)),n.value[s.value]=e.value})):(c.issues.length&&n.issues.push(...y(o,c.issues)),n.value[s.value]=c.value)}}return a.length?Promise.all(a).then(()=>n):n}});function D(e,t){return e.issues.length&&t===void 0?{issues:[],value:void 0}:e}const be=u(`$ZodOptional`,(e,t)=>{T.init(e,t),e._zod.optin=`optional`,e._zod.optout=`optional`,m(e._zod,`values`,()=>t.innerType._zod.values?new Set([...t.innerType._zod.values,void 0]):void 0),m(e._zod,`pattern`,()=>{let e=t.innerType._zod.pattern;return e?RegExp(`^(${ne(e.source)})?$`):void 0}),e._zod.parse=(e,n)=>{if(t.innerType._zod.optin===`optional`){let r=t.innerType._zod.run(e,n);return r instanceof Promise?r.then(t=>D(t,e.value)):D(r,e.value)}return e.value===void 0?e:t.innerType._zod.run(e,n)}});var O,xe=class{constructor(){this._map=new WeakMap,this._idmap=new Map}add(e,...t){let n=t[0];return this._map.set(e,n),n&&typeof n==`object`&&`id`in n&&this._idmap.set(n.id,e),this}clear(){return this._map=new WeakMap,this._idmap=new Map,this}remove(e){let t=this._map.get(e);return t&&typeof t==`object`&&`id`in t&&this._idmap.delete(t.id),this._map.delete(e),this}get(e){let t=e._zod.parent;if(t){let n={...this.get(t)??{}};delete n.id;let r={...n,...this._map.get(e)};return Object.keys(r).length?r:void 0}return this._map.get(e)}has(e){return this._map.has(e)}};function Se(){return new xe}(O=globalThis).__zod_globalRegistry??(O.__zod_globalRegistry=Se()),globalThis.__zod_globalRegistry;function Ce(e,t){return new e({type:`string`,..._(t)})}function we(e){return new e({type:`unknown`})}const k=u(`ZodMiniType`,(e,t)=>{if(!e._zod)throw Error(`Uninitialized schema in ZodMiniType.`);T.init(e,t),e.def=t,e.type=t.type,e.parse=(t,n)=>le(e,t,n,{callee:e.parse}),e.safeParse=(t,n)=>C(e,t,n),e.parseAsync=async(t,n)=>ue(e,t,n,{callee:e.parseAsync}),e.safeParseAsync=async(t,n)=>w(e,t,n),e.check=(...n)=>e.clone({...t,checks:[...t.checks??[],...n.map(e=>typeof e==`function`?{_zod:{check:e,def:{check:`custom`},onattach:[]}}:e)]},{parent:!0}),e.with=e.check,e.clone=(t,n)=>ae(e,t,n),e.brand=()=>e,e.register=((t,n)=>(t.add(e,n),e)),e.apply=t=>t(e)}),Te=u(`ZodMiniString`,(e,t)=>{me.init(e,t),k.init(e,t)});function A(e){return Ce(Te,e)}const Ee=u(`ZodMiniUnknown`,(e,t)=>{he.init(e,t),k.init(e,t)});function j(){return we(Ee)}const De=u(`ZodMiniObject`,(e,t)=>{ve.init(e,t),k.init(e,t),m(e,`shape`,()=>t.shape)});function M(e,t){return new De({type:`object`,shape:e??{},..._(t)})}const Oe=u(`ZodMiniRecord`,(e,t)=>{ye.init(e,t),k.init(e,t)});function N(e,t,n){return new Oe({type:`record`,keyType:e,valueType:t,..._(n)})}const ke=u(`ZodMiniOptional`,(e,t)=>{be.init(e,t),k.init(e,t)});function P(e){return new ke({type:`optional`,innerType:e})}const Ae=M({session_id:A(),transcript_path:A(),cwd:A(),permission_mode:A(),hook_event_name:A(),tool_name:A(),tool_input:N(A(),j())});async function je(){let e=[];for await(let t of process.stdin)e.push(typeof t==`string`?t:String(t));let t=JSON.parse(e.join(``)),n=Ae.safeParse(t);return n.success||(process.stderr.write(`[bst-hook] invalid hook input: ${n.error.message}\\n`),process.exit(0)),n.data}const Me=M({command:A(),description:P(A())}),Ne=M({file_path:A()}),Pe=M({pattern:A(),path:P(A())});function Fe(e){let t=Me.safeParse(e);return t.success?t.data:null}function Ie(e){let t=Ne.safeParse(e);return t.success?t.data:null}function Le(e){let t=Pe.safeParse(e);return t.success?t.data:null}function F(e,t){let n={hookSpecificOutput:{hookEventName:`PreToolUse`,permissionDecision:e,...e===`deny`&&t?{permissionDecisionReason:t}:{}}};process.stdout.write(JSON.stringify(n))}function Re(){let e=a.dirname(l(import.meta.url));return a.join(e,`bst-hook.audit.local.jsonl`)}function ze(t){try{if(e.statSync(t).size>1048576){let n=`${t}.1`;e.renameSync(t,n)}}catch{}}let Be=!1;function Ve(t){try{let n=Re();Be||=(ze(n),!0);let r={timestamp:new Date().toISOString(),...t};e.appendFileSync(n,JSON.stringify(r)+`\n`)}catch(e){process.stderr.write(`[bst-hook] audit write failed: ${e instanceof Error?e.message:String(e)}\\n`)}}function I(e){let t=[],n=``,r=0,i=!1;for(;r<e.length;){let a=e[r];if(a===`'`){for(i=!0,r++;r<e.length&&e[r]!==`'`;)n+=e[r],r++;if(r>=e.length)return{ok:!1,error:`unterminated single quote`};r++}else if(a===`\"`){for(i=!0,r++;r<e.length&&e[r]!==`\"`;){if(e[r]===`\\\\`&&r+1<e.length){let t=e[r+1];if(t===`\"`||t===`\\\\`||t===`$`||t===\"`\"){n+=t,r+=2;continue}}n+=e[r],r++}if(r>=e.length)return{ok:!1,error:`unterminated double quote`};r++}else a===`\\\\`&&r+1<e.length?(i=!0,n+=e[r+1],r+=2):a===` `||a===` `?(i&&=(t.push(n),n=``,!1),r++):(i=!0,n+=a,r++)}return i&&t.push(n),{ok:!0,tokens:t}}function He(e){if(!e||!e.trim())return[];let t=[],n=``,r=0,i=!1,a=!1;for(;r<e.length;){let o=e[r];if(o===`'`&&!a){i=!i,n+=o,r++;continue}if(o===`\"`&&!i){a=!a,n+=o,r++;continue}if(o===`\\\\`&&!i&&r+1<e.length){n+=o+e[r+1],r+=2;continue}if(!i&&!a){if(o===`&`&&r+1<e.length&&e[r+1]===`&`){L(t,n,`&&`),n=``,r+=2;continue}if(o===`&`&&!(r+1<e.length&&e[r+1]===`>`)&&!(r>0&&(e[r-1]===`>`||e[r-1]===`<`))){L(t,n,`&`),n=``,r++;continue}if(o===`|`&&r+1<e.length&&e[r+1]===`|`){L(t,n,`||`),n=``,r+=2;continue}if(o===`|`){L(t,n,`|`),n=``,r++;continue}if(o===`;`){L(t,n,`;`),n=``,r++;continue}}n+=o,r++}let o=n.trim();return o&&t.push({command:o,operator:null}),t}function L(e,t,n){let r=t.trim();r&&e.push({command:r,operator:n})}const R=new Set([`2>&1`,`2>/dev/null`,`>/dev/null`,`1>/dev/null`]);function Ue(e,t){if(/[\\n\\r]/.test(t))return{safe:!1,reason:`unquoted newline in command`};for(let t of e){if(t===\"`\")return{safe:!1,reason:`backtick command substitution`};if(t.includes(`$(`))return{safe:!1,reason:`dollar command substitution`};if(t.includes(\"`\"))return{safe:!1,reason:`backtick command substitution`};if(t.includes(`<(`)||t.includes(`>(`)&&!R.has(t))return{safe:!1,reason:`process substitution`}}for(let t=0;t<e.length;t++){let n=e[t];if(!R.has(n)){if(n.includes(`<`)&&!n.includes(`<(`))return{safe:!1,reason:`input redirect`};if(n.includes(`>`)){if(n.endsWith(`>/dev/null`)||n.match(/^(&>>|&>|>>|>|1>|2>)$/)&&e[t+1]===`/dev/null`)continue;return{safe:!1,reason:`output redirect to file`}}}}return{safe:!0}}const We=[`.sample`,`.example`,`.template`],Ge=/(^|[/\\\\])(\\.env(\\..*)?|.*\\.env(\\..*)?|\\.env)$/;function Ke(e){return We.some(t=>e.endsWith(t))}function z(e){return Ke(a.basename(e))?!1:Ge.test(e)}function qe(e){return e.slice(1).some(e=>!e.startsWith(`-`)&&z(e))}const Je=new Set([`status`,`log`,`diff`,`show`,`branch`,`remote`,`fetch`,`rev-parse`]),Ye=new Set([`push`,`add`,`commit`,`reset`,`merge`,`rebase`,`cherry-pick`,`checkout`,`switch`,`stash`,`tag`,`revert`,`clean`,`rm`,`mv`]),Xe=new Set([`-c`,`--exec-path`,`--pager`,`--upload-pack`,`--receive-pack`]),Ze=new Set([`-C`,`-c`,`--git-dir`,`--work-tree`]);function B(e){let t=e.slice(1);for(let e=0;e<t.length;e++){let n=t[e];if(Ze.has(n)){e++;continue}if(!n.startsWith(`-`))return n}}function Qe(e){for(let t of e.slice(1))if(Xe.has(t)||t===`-o`||t.startsWith(`--output`)||t.startsWith(`--exec-path=`)||t.startsWith(`--pager=`)||t.startsWith(`--upload-pack=`)||t.startsWith(`--receive-pack=`)||t.startsWith(`-o=`)||t.startsWith(`--output=`))return!1;let t=B(e);if(!t)return!1;if(t===`stash`){let t=e[e.indexOf(`stash`)+1];return t===`list`||t===void 0}return Je.has(t)}function $e(e){let t=B(e);if(!t)return!1;if(t===`stash`){let t=e[e.indexOf(`stash`)+1];if(t===`list`||t===void 0)return!1}return Ye.has(t)}const V=new Set(`install.i.add.remove.rm.uninstall.un.update.up.upgrade.list.ls.ll.la.why.view.info.show.outdated.audit.licenses.init.create.link.unlink.pack.publish.config.set.get.store.cache.rebuild.rb.prune.dedupe.dlx.exec.run.patch.patch-commit.recursive.-r`.split(`.`)),et=new Set([`list`,`ls`,`ll`,`la`,`why`,`view`,`info`,`show`,`outdated`]);function tt(e){let t=e.slice(1),n;for(let e of t)if(!(e.startsWith(`-`)&&!V.has(e))){n=e;break}return n?et.has(n)?!0:n===`install`||n===`i`?t.slice(t.indexOf(n)+1).every(e=>e.startsWith(`-`)):!1:!1}const nt=new Set([`view`,`info`,`show`]);function rt(e){let t=e[1];return t!==void 0&&nt.has(t)}function it(e){let t=e[1],n=`This project uses pnpm.`;return t?t===`install`||t===`i`||t===`ci`?e.slice(2).some(e=>!e.startsWith(`-`))?`${n} Use \\`pnpm add <pkg>\\` instead of \\`npm install <pkg>\\`.`:`${n} Use \\`pnpm install\\` instead of npm.`:t===`add`?`${n} Use \\`pnpm add <pkg>\\` instead of npm.`:t===`uninstall`||t===`remove`||t===`rm`||t===`un`||t===`r`?`${n} Use \\`pnpm remove <pkg>\\` instead of npm.`:t===`run`||t===`run-script`?`${n} Use \\`pnpm run <script>\\` or \\`pnpm <script>\\` instead of npm.`:t===`test`||t===`t`||t===`tst`?`${n} Use \\`pnpm test\\` instead of npm.`:t===`start`?`${n} Use \\`pnpm start\\` instead of npm.`:t===`stop`?`${n} Use \\`pnpm stop\\` instead of npm.`:t===`restart`?`${n} Use \\`pnpm restart\\` instead of npm.`:t===`exec`?`${n} Use \\`pnpm exec <cmd>\\` instead of npm.`:t===`list`||t===`ls`||t===`ll`||t===`la`?`${n} Use \\`pnpm list\\` instead of npm.`:t===`why`?`${n} Use \\`pnpm why\\` instead of npm.`:t===`outdated`?`${n} Use \\`pnpm outdated\\` instead of npm.`:t===`audit`?`${n} Use \\`pnpm audit\\` instead of npm.`:t===`update`||t===`up`||t===`upgrade`?`${n} Use \\`pnpm update\\` instead of npm.`:t===`init`?`${n} Use \\`pnpm init\\` instead of npm.`:t===`publish`?`${n} Use \\`pnpm publish\\` instead of npm.`:t===`link`?`${n} Use \\`pnpm link\\` instead of npm.`:t===`unlink`?`${n} Use \\`pnpm unlink\\` instead of npm.`:t===`pack`?`${n} Use \\`pnpm pack\\` instead of npm.`:t===`cache`?`${n} Use \\`pnpm store\\` instead of \\`npm cache\\`.`:t===`config`||t===`set`||t===`get`?`${n} Use \\`pnpm config\\` instead of npm.`:`${n} Use the equivalent pnpm command instead of npm.`:`${n} Use \\`pnpm\\` instead of npm.`}function H(e,t){for(let n of e.slice(1)){if(n.startsWith(`-`)){if(n===`-t`||n.startsWith(`--target-directory`))return!1;continue}if(a.basename(n).startsWith(`.`)||n.startsWith(`~/`)||n===`~`)return!1;let e=a.resolve(t.cwd,n);if(e!==t.cwd&&!e.startsWith(t.cwd+a.sep))return!1}return!0}const at=new Set([`-exec`,`-execdir`,`-ok`,`-okdir`,`-delete`,`-fprint`,`-fprint0`,`-fprintf`,`-fls`]);function ot(e){return!e.some(e=>at.has(e))}function st(e){return!e.includes(`-o`)&&!e.some(e=>e.startsWith(`--output`))}function ct(e){let t=e.findIndex(e=>a.basename(e)===`rm`);if(t===-1)return!1;let n=e.slice(t+1),r=n.filter(e=>e.startsWith(`-`)&&!e.startsWith(`--`)),i=n.filter(e=>e.startsWith(`--`)),o=r.some(e=>/[rR]/.test(e)),s=i.includes(`--recursive`);return o||s}function lt(e){return e.some(e=>e===`777`||e===`0777`)}function ut(e){let t=e.indexOf(`push`);if(t===-1)return!1;let n=e.slice(t+1);return n.some(e=>e===`--force`||e===`-f`&&!n.includes(`--force-with-lease`))}function dt(e){if(!(e.includes(`reset`)&&e.includes(`--hard`)))return!1;if(e.some(e=>e===`main`||e===`master`))return!0;let t=e.filter(e=>e!==`git`&&e!==`reset`&&!e.startsWith(`-`));return t.length===0||t.includes(`HEAD`)}const ft=[{name:`rm-recursive`,match:/^rm$/,action:`deny`,when:e=>ct(e),reason:\"Don't use recursive `rm`. Use more targeted deletes, or remove specific files/directories.\"},{name:`sudo`,match:/^sudo$/,action:`deny`,reason:`Don't use sudo. If you need elevated permissions, ask me to do it manually.`},{name:`git-force-push`,match:/^git$/,action:`deny`,when:e=>ut(e),reason:\"Use `git push --force-with-lease` instead of `--force`.\"},{name:`git-reset-hard`,match:/^git$/,action:`deny`,when:e=>dt(e),reason:\"Don't `reset --hard` on main. Create a branch first.\"},{name:`git-write`,match:/^git$/,action:`deny`,when:e=>$e(e),reason:`Git write operations (push, add, commit, reset, merge, etc.) are not allowed. Ask the user to run these manually.`},{name:`chmod-777`,match:/^chmod$/,action:`deny`,when:e=>lt(e),reason:`Don't use 777 permissions. Use more restrictive permissions.`},{name:`env-file-read`,match:/^(cat|head|tail|less|more|grep)$/,action:`deny`,when:e=>qe(e),reason:`Don't read .env files. These contain secrets that should not appear in the conversation.`},{name:`npx-redirect`,match:/^npx$/,action:`deny`,reason:\"This project uses pnpm. Use `pnpm dlx <pkg>` or `pnpm exec <cmd>` instead of npx.\"}],U=[{name:`vitest`,match:/^vitest$/,action:`allow`},{name:`jest`,match:/^jest$/,action:`allow`},{name:`tsc`,match:/^tsc$/,action:`allow`},{name:`tsdown`,match:/^tsdown$/,action:`allow`},{name:`oxlint`,match:/^oxlint$/,action:`allow`},{name:`oxfmt`,match:/^oxfmt$/,action:`allow`},{name:`eslint`,match:/^eslint$/,action:`allow`},{name:`prettier`,match:/^prettier$/,action:`allow`},{name:`biome`,match:/^biome$/,action:`allow`},{name:`knip`,match:/^knip$/,action:`allow`},{name:`cat`,match:/^cat$/,action:`allow`},{name:`head`,match:/^head$/,action:`allow`},{name:`tail`,match:/^tail$/,action:`allow`},{name:`grep`,match:/^grep$/,action:`allow`},{name:`ls`,match:/^ls$/,action:`allow`},{name:`wc`,match:/^wc$/,action:`allow`},{name:`uniq`,match:/^uniq$/,action:`allow`},{name:`diff`,match:/^diff$/,action:`allow`},{name:`echo`,match:/^echo$/,action:`allow`},{name:`pwd`,match:/^pwd$/,action:`allow`},{name:`which`,match:/^which$/,action:`allow`},{name:`dirname`,match:/^dirname$/,action:`allow`},{name:`basename`,match:/^basename$/,action:`allow`},{name:`realpath`,match:/^realpath$/,action:`allow`},{name:`npm`,match:/^npm$/,action:`allow`,when:e=>rt(e)},{name:`test`,match:/^test$/,action:`allow`},{name:`bracket-test`,match:/^\\[$/,action:`allow`},{name:`cd`,match:/^cd$/,action:`allow`},{name:`true`,match:/^true$/,action:`allow`},{name:`colon`,match:/^:$/,action:`allow`},{name:`find`,match:/^find$/,action:`allow`,when:e=>ot(e)},{name:`sort`,match:/^sort$/,action:`allow`,when:e=>st(e)},{name:`git`,match:/^git$/,action:`allow`,when:e=>Qe(e)},{name:`pnpm`,match:/^pnpm$/,action:`allow`,when:e=>tt(e)},{name:`cp`,match:/^cp$/,action:`allow`,when:(e,t)=>H(e,t)},{name:`mkdir`,match:/^mkdir$/,action:`allow`,when:(e,t)=>H(e,t)},{name:`touch`,match:/^touch$/,action:`allow`,when:(e,t)=>H(e,t)}],pt=M({scripts:N(A(),j())});function W(e,t){let n=xt(t);if(!n)return null;let r=n[e];if(typeof r!=`string`)return null;let i=n[`pre${e}`],a=n[`post${e}`];return{pre:typeof i==`string`?i:null,main:r,post:typeof a==`string`?a:null}}function mt(e,t,n){let r=_t(t,n);if(!r)return null;let i=W(e,r);return i?{...i,pkgDir:r}:null}function ht(e,t){let n=G(t);if(!n)return null;let r=[];for(let t of n){let n=W(e,t);n&&r.push({...n,pkgDir:t})}return r}function gt(e){let n=c(e);for(;;){if(t(s(n,`pnpm-workspace.yaml`)))return n;let e=o(n);if(e===n)return null;n=e}}function G(e){let t=vt(e);if(!t)return null;let n=[];for(let a of t){if(!a.endsWith(`/*`))continue;let t=c(e,a.slice(0,-2)),o;try{o=r(t)}catch{continue}for(let e of o){let r=s(t,e);try{if(!i(r).isDirectory())continue}catch{continue}n.push(r)}}return n.length>0?n:null}function _t(e,t){let n=G(t);if(!n)return null;for(let t of n){let n=bt(t);if(n===e||n===`@${e}`||t.split(`/`).pop()===e||n&&(n.startsWith(`@`)?n.split(`/`)[1]:n)===e)return t}return null}function vt(e){try{let t=n(s(e,`pnpm-workspace.yaml`),`utf-8`).split(`\n`),r=t.findIndex(e=>/^packages\\s*:/.test(e));if(r===-1)return null;let i=[];for(let e=r+1;e<t.length;e++){let n=t[e],r=/^\\s+-\\s+(.+)$/.exec(n);if(!r)break;i.push(r[1].trim().replace(/['\"`]/g,``))}return i.length>0?i:null}catch{return null}}const yt=M({name:A()});function bt(e){try{let t=n(s(e,`package.json`),`utf-8`),r=yt.safeParse(JSON.parse(t));return r.success?r.data.name:null}catch{return null}}function xt(e){try{let t=n(s(e,`package.json`),`utf-8`),r=pt.safeParse(JSON.parse(t));return r.success?r.data.scripts:null}catch{return null}}const St=new Set([`LD_PRELOAD`,`LD_LIBRARY_PATH`,`DYLD_INSERT_LIBRARIES`,`NODE_OPTIONS`,`PYTHONPATH`,`PYTHONSTARTUP`,`PERL5OPT`,`PERL5LIB`,`RUBYOPT`,`RUBYLIB`,`BASH_ENV`,`ENV`,`npm_config_prefix`,`npm_config_registry`,`EDITOR`,`VISUAL`]),Ct=[`GIT_CONFIG_`,`GIT_PAGER`,`GIT_SSH_COMMAND`,`GIT_EDITOR`,`GIT_EXEC_PATH`];function K(e){return St.has(e)?!0:Ct.some(t=>e.startsWith(t))}function wt(e,t){let n=I(e);if(!n.ok||n.tokens.length!==2)return null;let r=n.tokens;if(r[0]!==`cd`)return null;let i=r[1];return a.isAbsolute(i)?i:a.resolve(t.cwd,i)}function q(e,t){if(t.depth>=5)return{action:`passthrough`,rule:null,reason:`max evaluation depth exceeded`};let n=e.trim();if(!n)return{action:`passthrough`,rule:null,reason:null};if(n.startsWith(`(`)&&n.endsWith(`)`))return{action:`passthrough`,rule:null,reason:`subshell`};let r=He(n);if(r.length===0)return{action:`passthrough`,rule:null,reason:null};let i=null,a=null,o=t;for(let e of r){if(e.operator===`&&`){let t=wt(e.command,o);t&&(o={...o,cwd:t})}let t=Tt(e.command,o);if(t.action===`deny`)return t;t.action===`passthrough`&&(i||=t),t.action===`allow`&&(a=t)}return i||(r.length===1&&a?a:{action:`allow`,rule:`all-segments`,reason:null})}function J(e,t){if(e.pre){let n=q(e.pre,t);if(n.action!==`allow`)return n}let n=q(e.main,t);if(n.action!==`allow`)return n;if(e.post){let n=q(e.post,t);if(n.action!==`allow`)return n}return`allow`}function Tt(e,t){let n=e.trim();if(n.startsWith(`(`)&&n.endsWith(`)`))return{action:`passthrough`,rule:null,reason:`subshell`};let r=I(e);if(!r.ok)return{action:`passthrough`,rule:null,reason:r.error};let i=r.tokens;if(i.length===0)return{action:`passthrough`,rule:null,reason:null};let o=0;for(;o<i.length&&/^\\w+=/.test(i[o]);){let e=i[o].split(`=`)[0];if(K(e))return{action:`passthrough`,rule:null,reason:`dangerous env var: ${e}`};o++}if(o>=i.length)return{action:`allow`,rule:`env-only`,reason:null};i=i.slice(o);let s=Ue(i,e);if(!s.safe)return{action:`passthrough`,rule:null,reason:s.reason};for(let e=0;e<i.length;e++){let t=i[e];if(!(t===`2>&1`||t===`2>/dev/null`||t===`>/dev/null`||t===`1>/dev/null`)){if(t===`>`||t===`>>`){if(i[e+1]===`/dev/null`)continue;return{action:`passthrough`,rule:null,reason:`output redirect to file`}}if(t===`<`)return{action:`passthrough`,rule:null,reason:`input redirect`}}}let c=a.basename(i[0]);if(c===`command`&&i.length>1)return q(i.slice(1).join(` `),{...t,depth:t.depth+1});if(c===`env`){let e=1;for(;e<i.length&&/^\\w+=/.test(i[e]);){let t=i[e].split(`=`)[0];if(K(t))return{action:`passthrough`,rule:null,reason:`dangerous env var: ${t}`};e++}return e>=i.length?{action:`allow`,rule:`env-only`,reason:null}:q(i.slice(e).join(` `),{...t,depth:t.depth+1})}if(c===`pnpm`)return Et(i,t);if(c===`npm`)return Ot(i);if(c===`bash`||c===`sh`||c===`zsh`)return jt(i,t);if(c===`node`&&(i.includes(`-e`)||i.includes(`-p`)||i.includes(`--eval`)||i.includes(`--print`)))return{action:`passthrough`,rule:null,reason:`node eval`};if(c===`mv`)return{action:`passthrough`,rule:null,reason:`mv`};for(let e of ft)if(e.match.test(c)&&(!e.when||e.when(i,t)))return{action:`deny`,rule:e.name,reason:e.reason??null};for(let e of U)if(e.match.test(c)&&(!e.when||e.when(i,t)))return{action:`allow`,rule:e.name,reason:null};return{action:`passthrough`,rule:null,reason:`no rule matched: ${c}`}}function Et(e,t){let n=e.slice(1),r,i=-1,o=!1,s=!1,c;for(let a=0;a<n.length;a++){let l=n[a];if(l===`--filter`||l.startsWith(`--filter=`))return kt(e,n,a,t);if(l===`-r`||l===`--recursive`){o=!0;continue}if(l===`-w`||l===`--workspace-root`){s=!0;continue}if(l===`-C`||l===`--dir`){c=n[++a];continue}if(l.startsWith(`-C=`)||l.startsWith(`--dir=`)){c=l.split(`=`,2)[1];continue}if(!(l.startsWith(`-`)&&!V.has(l))){r=l,i=a;break}}if(!r)return{action:`passthrough`,rule:null,reason:null};if(r===`dlx`)return{action:`passthrough`,rule:null,reason:`pnpm dlx`};if(r===`add`)return{action:`passthrough`,rule:null,reason:`pnpm add`};if(r===`exec`){let e=n.slice(i+1);return e.length===0?{action:`passthrough`,rule:null,reason:`bare pnpm exec`}:q(e.join(` `),{...t,depth:t.depth+1})}let l;if(r===`run`){let e=n[i+1];if(!e||e.startsWith(`-`))return{action:`passthrough`,rule:null,reason:`pnpm run without script name`};l=e}else if(!V.has(r))l=r;else{for(let n of U)if(n.match.test(`pnpm`)&&(!n.when||n.when(e,t)))return{action:`allow`,rule:n.name,reason:null};return{action:`passthrough`,rule:null,reason:null}}if(o)return Dt(l,t);if(s){let e=gt(t.cwd);return e?Y(l,{...t,cwd:e}):{action:`passthrough`,rule:null,reason:`workspace root not found`}}if(c){let e=a.resolve(t.cwd,c);return Y(l,{...t,cwd:e})}return Y(l,t)}function Y(e,t){let n=W(e,t.cwd);if(!n)return{action:`passthrough`,rule:null,reason:`script resolution failed`};let r=J(n,{...t,depth:t.depth+1});return r===`allow`?{action:`allow`,rule:`pnpm-script:${e}`,reason:null}:r}function Dt(e,t){let n=ht(e,t.cwd);if(!n||n.length===0)return{action:`passthrough`,rule:null,reason:`pnpm recursive`};for(let e of n){let n=J(e,{...t,depth:t.depth+1,cwd:e.pkgDir??t.cwd});if(n!==`allow`)return n}return{action:`allow`,rule:`pnpm-recursive:${e}`,reason:null}}function Ot(e){for(let t of U)if(t.match.test(`npm`)&&(!t.when||t.when(e,{cwd:``,depth:0})))return{action:`allow`,rule:t.name,reason:null};return{action:`deny`,rule:`npm-redirect`,reason:it(e)}}function kt(e,t,n,r){let i=t[n],a,o;if(i.startsWith(`--filter=`))a=i.slice(9),o=n+1;else{if(a=t[n+1],!a||a.startsWith(`-`))return{action:`passthrough`,rule:null,reason:`pnpm --filter without package`};o=n+2}if(!a)return{action:`passthrough`,rule:null,reason:`pnpm --filter without package`};let s;for(let e=o;e<t.length;e++){let n=t[e];if(!(n.startsWith(`-`)&&!V.has(n))){s=n;break}}if(!s)return{action:`passthrough`,rule:null,reason:`pnpm --filter without subcommand`};if(s===`install`||s===`i`)return t.slice(t.indexOf(s)+1).every(e=>e.startsWith(`-`))?{action:`allow`,rule:`pnpm`,reason:null}:{action:`passthrough`,rule:null,reason:`pnpm --filter install with package arg`};if(s===`dlx`)return{action:`passthrough`,rule:null,reason:`pnpm dlx`};if(s===`add`)return{action:`passthrough`,rule:null,reason:`pnpm add`};if(new Set([`list`,`ls`,`ll`,`la`,`why`,`view`,`info`,`show`,`outdated`,`licenses`,`audit`]).has(s))return{action:`allow`,rule:`pnpm`,reason:null};if(s===`exec`){let e=t.indexOf(`exec`,o),n=t.slice(e+1);return n.length===0?{action:`passthrough`,rule:null,reason:`bare pnpm exec`}:q(n.join(` `),{...r,depth:r.depth+1})}let c=s===`run`?t[t.indexOf(`run`,o)+1]:s;if(!c||c.startsWith(`-`))return{action:`passthrough`,rule:null,reason:`pnpm --filter run without script name`};if(V.has(c)&&c!==`run`)return{action:`passthrough`,rule:null,reason:null};let l=mt(c,a,r.cwd);if(!l)return{action:`passthrough`,rule:null,reason:`filtered script resolution failed`};let u=J(l,{...r,depth:r.depth+1,cwd:l.pkgDir??r.cwd});return u===`allow`?{action:`allow`,rule:`pnpm-filter:${a}:${c}`,reason:null}:u}const At=new Set([`-i`,`--interactive`,`-l`,`--login`,`--init-file`,`--rcfile`,`--norc`,`--noprofile`,`-s`,`--stdin`]);function jt(e,t){let n=e.indexOf(`-c`);if(n===-1)return{action:`passthrough`,rule:null,reason:`shell without -c`};for(let t=1;t<e.length;t++){if(t===n||t===n+1)continue;let r=e[t];if(r.startsWith(`-`)||At.has(r))return{action:`passthrough`,rule:null,reason:`shell -c with extra flags`}}let r=e[n+1];return r?e.length>n+2?{action:`passthrough`,rule:null,reason:`shell -c with positional args`}:n===1?q(r,{...t,depth:t.depth+1}):{action:`passthrough`,rule:null,reason:`shell -c with extra flags`}:{action:`passthrough`,rule:null,reason:`shell -c without command`}}const Mt=new Set([`Read`,`Glob`,`Grep`]),X=new Set([`Write`,`Edit`]),Nt=[{name:`env-file-read`,tools:Mt,action:`deny`,when:e=>z(e),reason:`Don't read .env files. These contain secrets that should not appear in the conversation.`},{name:`env-file-write`,tools:X,action:`deny`,when:e=>z(e),reason:`Don't write to .env files. These contain secrets.`},{name:`outside-cwd-write`,tools:X,action:`deny`,when:(e,t)=>{let n=a.resolve(t.cwd,e);return n!==t.cwd&&!n.startsWith(t.cwd+a.sep)},reason:`Don't write files outside the project directory.`}],Pt=[{name:`cwd-read`,tools:Mt,action:`allow`,when:(e,t)=>{let n=a.resolve(t.cwd,e);return n===t.cwd||n.startsWith(t.cwd+a.sep)}},{name:`cwd-write`,tools:X,action:`allow`,when:(e,t)=>{let n=a.resolve(t.cwd,e);return n===t.cwd||n.startsWith(t.cwd+a.sep)}}],Ft=new Set([`Read`,`Write`,`Edit`]),It=new Set([`Glob`,`Grep`]);function Lt(e,t,n){return Ft.has(e)?Ie(t)?.file_path??null:It.has(e)?Le(t)?.path??n:null}function Rt(e,t,n){let r=Lt(e,t,n.cwd);if(r===null)return{action:`passthrough`,rule:null,reason:`unknown tool input shape`};for(let t of Nt)if(t.tools.has(e)&&t.when(r,n))return{action:`deny`,rule:t.name,reason:t.reason??null};for(let t of Pt)if(t.tools.has(e)&&t.when(r,n))return{action:`allow`,rule:t.name,reason:null};return{action:`passthrough`,rule:null,reason:`no file rule matched`}}const Z=await je();Z.hook_event_name!==`PreToolUse`&&process.exit(0),new Set([`Bash`,`Read`,`Write`,`Edit`,`Glob`,`Grep`]).has(Z.tool_name)||process.exit(0);let Q,$;if(Z.tool_name===`Bash`){let e=Fe(Z.tool_input);e||process.exit(0),Q=q(e.command,{cwd:Z.cwd,depth:0}),$=e.command}else{let e=process.env.CLAUDE_PROJECT_DIR??Z.cwd;Q=Rt(Z.tool_name,Z.tool_input,{cwd:e});let t=String(Z.tool_input.file_path??Z.tool_input.path??``);$=`${Z.tool_name} ${t}`}Ve({sessionId:Z.session_id,cwd:Z.cwd,toolName:Z.tool_name,command:$,decision:Q.action,rule:Q.rule,reason:Q.reason}),Q.action===`allow`?F(`allow`):Q.action===`deny`&&F(`deny`,Q.reason);export{};";
|
|
2410
2395
|
const existing = ctx.read(HOOK_PATH);
|
|
2411
2396
|
if (existing === content) return {
|
|
2412
2397
|
filePath: HOOK_PATH,
|
|
@@ -2464,6 +2449,7 @@ function buildSettings(ctx) {
|
|
|
2464
2449
|
if (ctx.config.structure !== "monorepo") {
|
|
2465
2450
|
if (ctx.packageJson ? packageHasWebUIDeps(ctx.packageJson) : false) enabledPlugins["frontend-design@claude-plugins-official"] = true;
|
|
2466
2451
|
}
|
|
2452
|
+
const hookCommand = `node "$CLAUDE_PROJECT_DIR/.claude/hooks/bst-hook.mjs"`;
|
|
2467
2453
|
return {
|
|
2468
2454
|
permissions: {
|
|
2469
2455
|
allow,
|
|
@@ -2474,13 +2460,50 @@ function buildSettings(ctx) {
|
|
|
2474
2460
|
"Read(*.env.*)"
|
|
2475
2461
|
]
|
|
2476
2462
|
},
|
|
2477
|
-
hooks: { PreToolUse: [
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2463
|
+
hooks: { PreToolUse: [
|
|
2464
|
+
{
|
|
2465
|
+
matcher: "Bash",
|
|
2466
|
+
hooks: [{
|
|
2467
|
+
type: "command",
|
|
2468
|
+
command: hookCommand
|
|
2469
|
+
}]
|
|
2470
|
+
},
|
|
2471
|
+
{
|
|
2472
|
+
matcher: "Read",
|
|
2473
|
+
hooks: [{
|
|
2474
|
+
type: "command",
|
|
2475
|
+
command: hookCommand
|
|
2476
|
+
}]
|
|
2477
|
+
},
|
|
2478
|
+
{
|
|
2479
|
+
matcher: "Write",
|
|
2480
|
+
hooks: [{
|
|
2481
|
+
type: "command",
|
|
2482
|
+
command: hookCommand
|
|
2483
|
+
}]
|
|
2484
|
+
},
|
|
2485
|
+
{
|
|
2486
|
+
matcher: "Edit",
|
|
2487
|
+
hooks: [{
|
|
2488
|
+
type: "command",
|
|
2489
|
+
command: hookCommand
|
|
2490
|
+
}]
|
|
2491
|
+
},
|
|
2492
|
+
{
|
|
2493
|
+
matcher: "Glob",
|
|
2494
|
+
hooks: [{
|
|
2495
|
+
type: "command",
|
|
2496
|
+
command: hookCommand
|
|
2497
|
+
}]
|
|
2498
|
+
},
|
|
2499
|
+
{
|
|
2500
|
+
matcher: "Grep",
|
|
2501
|
+
hooks: [{
|
|
2502
|
+
type: "command",
|
|
2503
|
+
command: hookCommand
|
|
2504
|
+
}]
|
|
2505
|
+
}
|
|
2506
|
+
] },
|
|
2484
2507
|
instructions: [
|
|
2485
2508
|
"Use pnpm, not npm/yarn/npx. Run binaries with `pnpm exec`.",
|
|
2486
2509
|
"No typecasts (as/any). Use zod schemas, type guards, or narrowing instead.",
|
|
@@ -2492,9 +2515,9 @@ function buildSettings(ctx) {
|
|
|
2492
2515
|
};
|
|
2493
2516
|
}
|
|
2494
2517
|
const BST_HOOK_MARKER = "bst-hook.mjs";
|
|
2495
|
-
/** Check if a
|
|
2496
|
-
function
|
|
2497
|
-
return matchers.some((m) => m.matcher ===
|
|
2518
|
+
/** Check if a specific matcher already has the bst-hook command. */
|
|
2519
|
+
function matcherHasBstHook(matchers, matcherName) {
|
|
2520
|
+
return matchers.some((m) => m.matcher === matcherName && m.hooks.some((h) => h.command.includes(BST_HOOK_MARKER)));
|
|
2498
2521
|
}
|
|
2499
2522
|
/** Remove enabledPlugins/extraKnownMarketplaces/hooks when empty to keep the file clean. */
|
|
2500
2523
|
function serializeSettings$1(settings) {
|
|
@@ -2530,9 +2553,10 @@ function writeOrMergeSettings(ctx, filePath, generated) {
|
|
|
2530
2553
|
const mergedHooks = { ...settings.hooks };
|
|
2531
2554
|
for (const [event, generatedMatchers] of Object.entries(generated.hooks)) {
|
|
2532
2555
|
const existingMatchers = mergedHooks[event] ?? [];
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2556
|
+
const missingMatchers = generatedMatchers.filter((gm) => !matcherHasBstHook(existingMatchers, gm.matcher));
|
|
2557
|
+
if (missingMatchers.length > 0) {
|
|
2558
|
+
mergedHooks[event] = [...existingMatchers, ...missingMatchers];
|
|
2559
|
+
hookChanges += missingMatchers.length;
|
|
2536
2560
|
}
|
|
2537
2561
|
}
|
|
2538
2562
|
const missingPlugins = Object.entries(generated.enabledPlugins).filter(([key]) => !(key in settings.enabledPlugins));
|
|
@@ -3205,7 +3229,7 @@ async function runGenerators(ctx) {
|
|
|
3205
3229
|
function generateMigratePrompt(results, config, detected) {
|
|
3206
3230
|
const sections = [];
|
|
3207
3231
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
3208
|
-
sections.push(`# Migration Prompt\n\n_Generated by \`@bensandee/tooling@0.40.
|
|
3232
|
+
sections.push(`# Migration Prompt\n\n_Generated by \`@bensandee/tooling@0.40.2 repo:sync\` on ${timestamp}_\n`);
|
|
3209
3233
|
const changed = results.filter((r) => r.action === "created" || r.action === "updated" || r.action === "archived");
|
|
3210
3234
|
if (changed.length > 0) {
|
|
3211
3235
|
const items = changed.map((r) => {
|
|
@@ -5217,6 +5241,16 @@ const dockerCheckCommand = defineCommand({
|
|
|
5217
5241
|
});
|
|
5218
5242
|
//#endregion
|
|
5219
5243
|
//#region src/commands/hooks-audit.ts
|
|
5244
|
+
/** Walk up from `cwd` to find the nearest directory containing `.claude/`. */
|
|
5245
|
+
function findProjectRoot(cwd) {
|
|
5246
|
+
let dir = path.resolve(cwd);
|
|
5247
|
+
while (true) {
|
|
5248
|
+
if (existsSync(path.join(dir, ".claude"))) return dir;
|
|
5249
|
+
const parent = path.dirname(dir);
|
|
5250
|
+
if (parent === dir) return cwd;
|
|
5251
|
+
dir = parent;
|
|
5252
|
+
}
|
|
5253
|
+
}
|
|
5220
5254
|
const AuditEntrySchema = z.object({
|
|
5221
5255
|
timestamp: z.string(),
|
|
5222
5256
|
sessionId: z.string(),
|
|
@@ -5290,7 +5324,7 @@ const hooksAuditCommand = defineCommand({
|
|
|
5290
5324
|
}
|
|
5291
5325
|
},
|
|
5292
5326
|
async run({ args }) {
|
|
5293
|
-
const targetDir = path.resolve(args.dir
|
|
5327
|
+
const targetDir = args.dir ? path.resolve(args.dir) : findProjectRoot(process.cwd());
|
|
5294
5328
|
let entries = parseAuditLog(path.join(targetDir, ".claude/hooks/bst-hook.audit.local.jsonl"));
|
|
5295
5329
|
if (entries.length === 0) {
|
|
5296
5330
|
write("No audit log entries found.");
|
|
@@ -5331,7 +5365,7 @@ const hooksAuditCommand = defineCommand({
|
|
|
5331
5365
|
const main = defineCommand({
|
|
5332
5366
|
meta: {
|
|
5333
5367
|
name: "bst",
|
|
5334
|
-
version: "0.40.
|
|
5368
|
+
version: "0.40.2",
|
|
5335
5369
|
description: "Bootstrap and maintain standardized TypeScript project tooling"
|
|
5336
5370
|
},
|
|
5337
5371
|
subCommands: {
|
|
@@ -5348,7 +5382,7 @@ const main = defineCommand({
|
|
|
5348
5382
|
"hooks:audit": hooksAuditCommand
|
|
5349
5383
|
}
|
|
5350
5384
|
});
|
|
5351
|
-
console.log(`@bensandee/tooling v0.40.
|
|
5385
|
+
console.log(`@bensandee/tooling v0.40.2`);
|
|
5352
5386
|
async function run() {
|
|
5353
5387
|
await runMain(main);
|
|
5354
5388
|
process.exit(process.exitCode ?? 0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bensandee/tooling",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.2",
|
|
4
4
|
"description": "CLI tool to bootstrap and maintain standardized TypeScript project tooling",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"tsdown": "0.21.4",
|
|
61
61
|
"typescript": "5.9.3",
|
|
62
62
|
"vitest": "4.1.0",
|
|
63
|
-
"@bensandee/
|
|
64
|
-
"@bensandee/
|
|
63
|
+
"@bensandee/config": "0.10.0",
|
|
64
|
+
"@bensandee/claude-hooks": "0.3.0"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
67
|
"build": "tsdown",
|