@bensandee/tooling 0.39.0 → 0.40.1
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 +110 -62
- package/package.json +3 -3
package/dist/bin.mjs
CHANGED
|
@@ -1563,9 +1563,9 @@ async function generatePackageJson(ctx) {
|
|
|
1563
1563
|
}
|
|
1564
1564
|
const devDeps = { ...ROOT_DEV_DEPS };
|
|
1565
1565
|
if (!isMonorepo) Object.assign(devDeps, PER_PACKAGE_DEV_DEPS);
|
|
1566
|
-
devDeps["@bensandee/config"] = isWorkspacePackage(ctx, "@bensandee/config") ? "workspace:*" : "0.
|
|
1567
|
-
devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.
|
|
1568
|
-
if (ctx.config.useEslintPlugin) devDeps["@bensandee/eslint-plugin"] = isWorkspacePackage(ctx, "@bensandee/eslint-plugin") ? "workspace:*" : "0.
|
|
1566
|
+
devDeps["@bensandee/config"] = isWorkspacePackage(ctx, "@bensandee/config") ? "workspace:*" : "0.10.0";
|
|
1567
|
+
devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.40.1";
|
|
1568
|
+
if (ctx.config.useEslintPlugin) devDeps["@bensandee/eslint-plugin"] = isWorkspacePackage(ctx, "@bensandee/eslint-plugin") ? "workspace:*" : "0.12.0";
|
|
1569
1569
|
if (ctx.config.formatter === "oxfmt") devDeps["oxfmt"] = {
|
|
1570
1570
|
"@changesets/cli": "2.30.0",
|
|
1571
1571
|
"@release-it/bumper": "7.0.5",
|
|
@@ -1932,7 +1932,7 @@ import { defineConfig } from "oxlint";
|
|
|
1932
1932
|
|
|
1933
1933
|
export default defineConfig({
|
|
1934
1934
|
extends: [recommended],
|
|
1935
|
-
ignorePatterns: [".claude
|
|
1935
|
+
ignorePatterns: [".claude/**"],
|
|
1936
1936
|
});
|
|
1937
1937
|
`;
|
|
1938
1938
|
const CONFIG_PRESET_ONLY = `import { presetRules } from "@bensandee/config/oxlint";
|
|
@@ -1940,7 +1940,7 @@ import { defineConfig } from "oxlint";
|
|
|
1940
1940
|
|
|
1941
1941
|
export default defineConfig({
|
|
1942
1942
|
rules: presetRules,
|
|
1943
|
-
ignorePatterns: [".claude
|
|
1943
|
+
ignorePatterns: [".claude/**"],
|
|
1944
1944
|
});
|
|
1945
1945
|
`;
|
|
1946
1946
|
async function generateOxlint(ctx) {
|
|
@@ -1968,10 +1968,14 @@ async function generateOxlint(ctx) {
|
|
|
1968
1968
|
}
|
|
1969
1969
|
//#endregion
|
|
1970
1970
|
//#region src/generators/formatter.ts
|
|
1971
|
-
|
|
1972
|
-
|
|
1971
|
+
/** Ignore patterns that must always be present in .oxfmtrc.json. */
|
|
1972
|
+
const BASE_IGNORE_PATTERNS = [".claude"];
|
|
1973
|
+
/** Extra ignore patterns when a release strategy generates CHANGELOGs. */
|
|
1974
|
+
const RELEASE_IGNORE_PATTERNS = ["**/CHANGELOG.md"];
|
|
1975
|
+
function requiredIgnorePatterns(releaseStrategy) {
|
|
1976
|
+
if (releaseStrategy === "none") return BASE_IGNORE_PATTERNS;
|
|
1977
|
+
return [...BASE_IGNORE_PATTERNS, ...RELEASE_IGNORE_PATTERNS];
|
|
1973
1978
|
}
|
|
1974
|
-
`;
|
|
1975
1979
|
const PRETTIER_CONFIG = `{
|
|
1976
1980
|
"semi": true,
|
|
1977
1981
|
"singleQuote": false,
|
|
@@ -1986,16 +1990,55 @@ async function generateFormatter(ctx) {
|
|
|
1986
1990
|
}
|
|
1987
1991
|
async function generateOxfmt(ctx) {
|
|
1988
1992
|
const filePath = ".oxfmtrc.json";
|
|
1989
|
-
|
|
1993
|
+
const required = requiredIgnorePatterns(ctx.config.releaseStrategy);
|
|
1994
|
+
const existing = ctx.read(filePath);
|
|
1995
|
+
if (!existing) {
|
|
1996
|
+
const config = { ignorePatterns: required };
|
|
1997
|
+
ctx.write(filePath, JSON.stringify(config, null, 2) + "\n");
|
|
1998
|
+
return {
|
|
1999
|
+
filePath,
|
|
2000
|
+
action: "created",
|
|
2001
|
+
description: "Generated .oxfmtrc.json"
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
const OxfmtConfigSchema = z.record(z.string(), z.unknown());
|
|
2005
|
+
let jsonValue;
|
|
2006
|
+
try {
|
|
2007
|
+
jsonValue = JSON.parse(existing);
|
|
2008
|
+
} catch {
|
|
2009
|
+
const config = { ignorePatterns: required };
|
|
2010
|
+
ctx.write(filePath, JSON.stringify(config, null, 2) + "\n");
|
|
2011
|
+
return {
|
|
2012
|
+
filePath,
|
|
2013
|
+
action: "updated",
|
|
2014
|
+
description: "Replaced malformed .oxfmtrc.json"
|
|
2015
|
+
};
|
|
2016
|
+
}
|
|
2017
|
+
const parseResult = OxfmtConfigSchema.safeParse(jsonValue);
|
|
2018
|
+
if (!parseResult.success) {
|
|
2019
|
+
const config = { ignorePatterns: required };
|
|
2020
|
+
ctx.write(filePath, JSON.stringify(config, null, 2) + "\n");
|
|
2021
|
+
return {
|
|
2022
|
+
filePath,
|
|
2023
|
+
action: "updated",
|
|
2024
|
+
description: "Replaced malformed .oxfmtrc.json"
|
|
2025
|
+
};
|
|
2026
|
+
}
|
|
2027
|
+
const parsed = parseResult.data;
|
|
2028
|
+
const ignorePatterns = Array.isArray(parsed["ignorePatterns"]) ? parsed["ignorePatterns"] : [];
|
|
2029
|
+
const existingSet = new Set(ignorePatterns.filter((p) => typeof p === "string"));
|
|
2030
|
+
const missing = required.filter((p) => !existingSet.has(p));
|
|
2031
|
+
if (missing.length === 0) return {
|
|
1990
2032
|
filePath,
|
|
1991
2033
|
action: "skipped",
|
|
1992
|
-
description: "Existing oxfmt config
|
|
2034
|
+
description: "Existing oxfmt config already has required ignorePatterns"
|
|
1993
2035
|
};
|
|
1994
|
-
|
|
2036
|
+
parsed["ignorePatterns"] = [...ignorePatterns, ...missing];
|
|
2037
|
+
ctx.write(filePath, JSON.stringify(parsed, null, 2) + "\n");
|
|
1995
2038
|
return {
|
|
1996
2039
|
filePath,
|
|
1997
|
-
action: "
|
|
1998
|
-
description:
|
|
2040
|
+
action: "updated",
|
|
2041
|
+
description: `Added ignorePatterns: ${missing.join(", ")}`
|
|
1999
2042
|
};
|
|
2000
2043
|
}
|
|
2001
2044
|
async function generatePrettier(ctx) {
|
|
@@ -2363,7 +2406,7 @@ async function generatePnpmWorkspace(ctx) {
|
|
|
2363
2406
|
//#region src/generators/claude-hooks.ts
|
|
2364
2407
|
const HOOK_PATH = ".claude/hooks/bst-hook.mjs";
|
|
2365
2408
|
async function generateClaudeHooks(ctx) {
|
|
2366
|
-
const content = "/**\n * bst-hook — Claude Code PreToolUse hook\n * @bensandee/claude-hooks v0.1.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,j=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 M(){return new j}(A=globalThis).__zod_globalRegistry??(A.__zod_globalRegistry=M()),globalThis.__zod_globalRegistry;function N(e,t){return new e({type:`string`,...g(t)})}function P(e){return new e({type:`unknown`})}const F=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)}),I=c(`ZodMiniString`,(e,t)=>{ue.init(e,t),F.init(e,t)});function L(e){return N(I,e)}const _e=c(`ZodMiniUnknown`,(e,t)=>{de.init(e,t),F.init(e,t)});function ve(){return P(_e)}const ye=c(`ZodMiniObject`,(e,t)=>{me.init(e,t),F.init(e,t),p(e,`shape`,()=>t.shape)});function R(e,t){return new ye({type:`object`,shape:e??{},...g(t)})}const be=c(`ZodMiniRecord`,(e,t)=>{he.init(e,t),F.init(e,t)});function xe(e,t,n){return new be({type:`record`,keyType:e,valueType:t,...g(n)})}const Se=c(`ZodMiniOptional`,(e,t)=>{ge.init(e,t),F.init(e,t)});function Ce(e){return new Se({type:`optional`,innerType:e})}const we=R({session_id:L(),transcript_path:L(),cwd:L(),permission_mode:L(),hook_event_name:L(),tool_name:L(),tool_input:R({command:L(),description:Ce(L())})});async function Te(){let e=[];for await(let t of process.stdin)e.push(typeof t==`string`?t:String(t));let t=JSON.parse(e.join(``)),n=we.safeParse(t);return n.success||(process.stderr.write(`[bst-hook] invalid hook input: ${n.error.message}\\n`),process.exit(0)),n.data}function z(e,t){let n={hookSpecificOutput:{hookEventName:`PreToolUse`,permissionDecision:e,...e===`deny`&&t?{permissionDecisionReason:t}:{}}};process.stdout.write(JSON.stringify(n))}function Ee(){let e=i.dirname(s(import.meta.url));return i.join(e,`bst-hook.audit.local.jsonl`)}function De(t){try{if(e.statSync(t).size>1048576){let n=`${t}.1`;e.renameSync(t,n)}}catch{}}let Oe=!1;function ke(t){try{let n=Ee();Oe||=(De(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 B(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 Ae(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]===`&`){V(t,n,`&&`),n=``,r+=2;continue}if(o===`|`&&r+1<e.length&&e[r+1]===`|`){V(t,n,`||`),n=``,r+=2;continue}if(o===`|`){V(t,n,`|`),n=``,r++;continue}if(o===`;`){V(t,n,`;`),n=``,r++;continue}}n+=o,r++}let o=n.trim();return o&&t.push({command:o,operator:null}),t}function V(e,t,n){let r=t.trim();r&&e.push({command:r,operator:n})}const H=new Set([`2>&1`,`2>/dev/null`,`>/dev/null`,`1>/dev/null`]);function je(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(`>(`)&&!H.has(t))return{safe:!1,reason:`process substitution`}}for(let t=0;t<e.length;t++){let n=e[t];if(!H.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 Me=new Set([`status`,`log`,`diff`,`show`,`branch`,`remote`,`fetch`,`rev-parse`]),Ne=new Set([`-c`,`--exec-path`,`--pager`,`--upload-pack`,`--receive-pack`]);function Pe(e){for(let t of e.slice(1))if(Ne.has(t)||t.startsWith(`--exec-path=`)||t.startsWith(`--pager=`)||t.startsWith(`--upload-pack=`)||t.startsWith(`--receive-pack=`))return!1;for(let t of e.slice(1))if(!t.startsWith(`-`)){if(t===`stash`){let t=e[e.indexOf(`stash`)+1];return t===`list`||t===void 0}return Me.has(t)}return!1}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(`.`)),Fe=new Set([`list`,`ls`,`ll`,`la`,`why`,`view`,`info`,`show`,`outdated`]);function Ie(e){let t=e.slice(1),n;for(let e of t)if(!(e.startsWith(`-`)&&!U.has(e))){n=e;break}return n?Fe.has(n)?!0:n===`install`||n===`i`?t.slice(t.indexOf(n)+1).every(e=>e.startsWith(`-`)):!1:!1}const Le=new Set([`view`,`info`,`show`]);function Re(e){let t=e[1];return t!==void 0&&Le.has(t)}function ze(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 Be=new Set([`-exec`,`-execdir`,`-ok`,`-delete`]);function Ve(e){return!e.some(e=>Be.has(e))}function He(e){return!e.includes(`-o`)&&!e.some(e=>e.startsWith(`--output`))}function Ue(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 We(e){return e.some(e=>e===`777`||e===`0777`)}const Ge=/(^|[/\\\\])(\\.env(\\..*)?|.*\\.env(\\..*)?|\\.env)$/;function G(e){return e.slice(1).some(e=>!e.startsWith(`-`)&&Ge.test(e))}function Ke(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 qe(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 Je=[{name:`rm-recursive`,match:/^rm$/,action:`deny`,when:e=>Ue(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=>Ke(e),reason:\"Use `git push --force-with-lease` instead of `--force`.\"},{name:`git-reset-hard`,match:/^git$/,action:`deny`,when:e=>qe(e),reason:\"Don't `reset --hard` on main. Create a branch first.\"},{name:`chmod-777`,match:/^chmod$/,action:`deny`,when:e=>We(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=>Re(e)},{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=>Ve(e)},{name:`sort`,match:/^sort$/,action:`allow`,when:e=>He(e)},{name:`git`,match:/^git$/,action:`allow`,when:e=>Pe(e)},{name:`pnpm`,match:/^pnpm$/,action:`allow`,when:e=>Ie(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)}],Ye=R({scripts:xe(L(),ve())});function q(e,t){let n=et(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 Xe(e,t,n){let r=Ze(t,n);if(!r)return null;let i=q(e,r);return i?{...i,pkgDir:r}:null}function Ze(e,t){let i=Qe(t);if(!i)return null;for(let s of i){if(!s.endsWith(`/*`))continue;let i=o(t,s.slice(0,-2)),c;try{c=n(i)}catch{continue}for(let t of c){let n=a(i,t);try{if(!r(n).isDirectory())continue}catch{continue}let o=J(n);if(o===e||o===`@${e}`||t===e||o&&(o.startsWith(`@`)?o.split(`/`)[1]:o)===e)return n}}return null}function Qe(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 $e=R({name:L()});function J(e){try{let n=t(a(e,`package.json`),`utf-8`),r=$e.safeParse(JSON.parse(n));return r.success?r.data.name:null}catch{return null}}function et(e){try{let n=t(a(e,`package.json`),`utf-8`),r=Ye.safeParse(JSON.parse(n));return r.success?r.data.scripts:null}catch{return null}}const tt=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`]),nt=[`GIT_CONFIG_`,`GIT_PAGER`,`GIT_SSH_COMMAND`,`GIT_EDITOR`,`GIT_EXEC_PATH`];function Y(e){return tt.has(e)?!0:nt.some(t=>e.startsWith(t))}function rt(e,t){let n=B(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 X(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=Ae(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=rt(e.command,o);t&&(o={...o,cwd:t})}let t=it(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 it(e,t){let n=e.trim();if(n.startsWith(`(`)&&n.endsWith(`)`))return{action:`passthrough`,rule:null,reason:`subshell`};let r=B(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(Y(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=je(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 X(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(Y(t))return{action:`passthrough`,rule:null,reason:`dangerous env var: ${t}`};e++}return e>=a.length?{action:`allow`,rule:`env-only`,reason:null}:X(a.slice(e).join(` `),{...t,depth:t.depth+1})}if(c===`pnpm`)return at(a,t);if(c===`npm`)return ot(a);if(c===`bash`||c===`sh`||c===`zsh`)return lt(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 Je)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:null}}function at(e,t){let n=e.slice(1),r,i=-1;for(let a=0;a<n.length;a++){let o=n[a];if(o===`--filter`||o.startsWith(`--filter=`))return st(e,n,a,t);if(o===`-r`||o===`--recursive`)return{action:`passthrough`,rule:null,reason:`pnpm recursive`};if(!(o.startsWith(`-`)&&!U.has(o))){r=o,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`}:X(e.join(` `),{...t,depth:t.depth+1})}if(r===`run`){let e=n[i+1];return!e||e.startsWith(`-`)?{action:`passthrough`,rule:null,reason:`pnpm run without script name`}:Z(e,t)}if(U.has(r)){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 Z(r,t)}function Z(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=X(n.pre,r);if(e.action!==`allow`)return e}let i=X(n.main,r);if(i.action!==`allow`)return i;if(n.post){let e=X(n.post,r);if(e.action!==`allow`)return e}return{action:`allow`,rule:`pnpm-script:${e}`,reason:null}}function ot(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:ze(e)}}function st(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`}:X(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=Xe(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=X(l.pre,u);if(e.action!==`allow`)return e}let d=X(l.main,u);if(d.action!==`allow`)return d;if(l.post){let e=X(l.post,u);if(e.action!==`allow`)return e}return{action:`allow`,rule:`pnpm-filter:${a}:${c}`,reason:null}}const ct=new Set([`-i`,`--interactive`,`-l`,`--login`,`--init-file`,`--rcfile`,`--norc`,`--noprofile`,`-s`,`--stdin`]);function lt(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(`-`)||ct.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?X(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 Te();(Q.hook_event_name!==`PreToolUse`||Q.tool_name!==`Bash`)&&process.exit(0);const $=X(Q.tool_input.command,{cwd:Q.cwd,depth:0});ke({sessionId:Q.session_id,command:Q.tool_input.command,decision:$.action,rule:$.rule,reason:$.reason}),$.action===`allow`?z(`allow`):$.action===`deny`&&z(`deny`,$.reason);export{};";
|
|
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{};";
|
|
2367
2410
|
const existing = ctx.read(HOOK_PATH);
|
|
2368
2411
|
if (existing === content) return {
|
|
2369
2412
|
filePath: HOOK_PATH,
|
|
@@ -2415,13 +2458,7 @@ function parseClaudeSettings(raw) {
|
|
|
2415
2458
|
}
|
|
2416
2459
|
}
|
|
2417
2460
|
function buildSettings(ctx) {
|
|
2418
|
-
const
|
|
2419
|
-
const allow = [
|
|
2420
|
-
"Bash(test *)",
|
|
2421
|
-
"Bash([ *)",
|
|
2422
|
-
"Bash(git -C * diff HEAD -- *)"
|
|
2423
|
-
];
|
|
2424
|
-
if (ctx.config.structure === "monorepo") allow.push(`Bash(${pm} -r *)`);
|
|
2461
|
+
const allow = [];
|
|
2425
2462
|
const enabledPlugins = { "code-simplifier@claude-plugins-official": true };
|
|
2426
2463
|
const extraKnownMarketplaces = {};
|
|
2427
2464
|
if (ctx.config.structure !== "monorepo") {
|
|
@@ -2431,24 +2468,6 @@ function buildSettings(ctx) {
|
|
|
2431
2468
|
permissions: {
|
|
2432
2469
|
allow,
|
|
2433
2470
|
deny: [
|
|
2434
|
-
"Bash(git push *)",
|
|
2435
|
-
"Bash(git push)",
|
|
2436
|
-
"Bash(git add *)",
|
|
2437
|
-
"Bash(git add)",
|
|
2438
|
-
"Bash(git commit *)",
|
|
2439
|
-
"Bash(git commit)",
|
|
2440
|
-
"Bash(git reset *)",
|
|
2441
|
-
"Bash(git merge *)",
|
|
2442
|
-
"Bash(git rebase *)",
|
|
2443
|
-
"Bash(git cherry-pick *)",
|
|
2444
|
-
"Bash(git checkout *)",
|
|
2445
|
-
"Bash(git switch *)",
|
|
2446
|
-
"Bash(git stash *)",
|
|
2447
|
-
"Bash(git tag *)",
|
|
2448
|
-
"Bash(git revert *)",
|
|
2449
|
-
"Bash(git clean *)",
|
|
2450
|
-
"Bash(git rm *)",
|
|
2451
|
-
"Bash(git mv *)",
|
|
2452
2471
|
"Read(.env)",
|
|
2453
2472
|
"Read(.env.*)",
|
|
2454
2473
|
"Read(*.env)",
|
|
@@ -3186,7 +3205,7 @@ async function runGenerators(ctx) {
|
|
|
3186
3205
|
function generateMigratePrompt(results, config, detected) {
|
|
3187
3206
|
const sections = [];
|
|
3188
3207
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
3189
|
-
sections.push(`# Migration Prompt\n\n_Generated by \`@bensandee/tooling@0.
|
|
3208
|
+
sections.push(`# Migration Prompt\n\n_Generated by \`@bensandee/tooling@0.40.1 repo:sync\` on ${timestamp}_\n`);
|
|
3190
3209
|
const changed = results.filter((r) => r.action === "created" || r.action === "updated" || r.action === "archived");
|
|
3191
3210
|
if (changed.length > 0) {
|
|
3192
3211
|
const items = changed.map((r) => {
|
|
@@ -3583,7 +3602,7 @@ function createRealExecutor() {
|
|
|
3583
3602
|
const pkgPath = path.join(packagesDir, entry, "package.json");
|
|
3584
3603
|
try {
|
|
3585
3604
|
const pkg = parsePackageJson(readFileSync(pkgPath, "utf-8"));
|
|
3586
|
-
if (pkg?.name && pkg.version
|
|
3605
|
+
if (pkg?.name && pkg.version) packages.push({
|
|
3587
3606
|
name: pkg.name,
|
|
3588
3607
|
version: pkg.version,
|
|
3589
3608
|
dir: entry
|
|
@@ -5201,6 +5220,7 @@ const dockerCheckCommand = defineCommand({
|
|
|
5201
5220
|
const AuditEntrySchema = z.object({
|
|
5202
5221
|
timestamp: z.string(),
|
|
5203
5222
|
sessionId: z.string(),
|
|
5223
|
+
cwd: z.string().optional(),
|
|
5204
5224
|
command: z.string(),
|
|
5205
5225
|
decision: z.enum([
|
|
5206
5226
|
"allow",
|
|
@@ -5210,6 +5230,7 @@ const AuditEntrySchema = z.object({
|
|
|
5210
5230
|
rule: z.string().nullable(),
|
|
5211
5231
|
reason: z.string().nullable()
|
|
5212
5232
|
});
|
|
5233
|
+
const write = (msg = "") => console.log(msg);
|
|
5213
5234
|
function parseAuditLog(logPath) {
|
|
5214
5235
|
if (!existsSync(logPath)) return [];
|
|
5215
5236
|
const lines = readFileSync(logPath, "utf-8").split("\n").filter(Boolean);
|
|
@@ -5220,6 +5241,30 @@ function parseAuditLog(logPath) {
|
|
|
5220
5241
|
} catch (_error) {}
|
|
5221
5242
|
return entries;
|
|
5222
5243
|
}
|
|
5244
|
+
/** Count occurrences of each unique command, sorted descending. */
|
|
5245
|
+
function topCommands(entries, limit) {
|
|
5246
|
+
const counts = /* @__PURE__ */ new Map();
|
|
5247
|
+
for (const e of entries) {
|
|
5248
|
+
const existing = counts.get(e.command);
|
|
5249
|
+
if (existing) existing.count++;
|
|
5250
|
+
else counts.set(e.command, {
|
|
5251
|
+
command: e.command,
|
|
5252
|
+
count: 1,
|
|
5253
|
+
rule: e.rule
|
|
5254
|
+
});
|
|
5255
|
+
}
|
|
5256
|
+
return [...counts.values()].toSorted((a, b) => b.count - a.count).slice(0, limit);
|
|
5257
|
+
}
|
|
5258
|
+
function printSection(title, entries, limit) {
|
|
5259
|
+
const top = topCommands(entries, limit);
|
|
5260
|
+
if (top.length === 0) return;
|
|
5261
|
+
write(title);
|
|
5262
|
+
for (const { command, count, rule } of top) {
|
|
5263
|
+
const ruleSuffix = rule ? ` [${rule}]` : "";
|
|
5264
|
+
write(` ${String(count).padStart(4)}x ${command}${ruleSuffix}`);
|
|
5265
|
+
}
|
|
5266
|
+
write();
|
|
5267
|
+
}
|
|
5223
5268
|
const hooksAuditCommand = defineCommand({
|
|
5224
5269
|
meta: {
|
|
5225
5270
|
name: "hooks:audit",
|
|
@@ -5233,7 +5278,7 @@ const hooksAuditCommand = defineCommand({
|
|
|
5233
5278
|
},
|
|
5234
5279
|
tail: {
|
|
5235
5280
|
type: "string",
|
|
5236
|
-
description: "Show the last N entries
|
|
5281
|
+
description: "Show the last N raw entries"
|
|
5237
5282
|
},
|
|
5238
5283
|
decision: {
|
|
5239
5284
|
type: "string",
|
|
@@ -5241,41 +5286,44 @@ const hooksAuditCommand = defineCommand({
|
|
|
5241
5286
|
},
|
|
5242
5287
|
json: {
|
|
5243
5288
|
type: "boolean",
|
|
5244
|
-
description: "Output raw JSON lines
|
|
5289
|
+
description: "Output raw JSON lines"
|
|
5245
5290
|
}
|
|
5246
5291
|
},
|
|
5247
5292
|
async run({ args }) {
|
|
5248
5293
|
const targetDir = path.resolve(args.dir ?? ".");
|
|
5249
|
-
|
|
5250
|
-
let entries = parseAuditLog(logPath);
|
|
5294
|
+
let entries = parseAuditLog(path.join(targetDir, ".claude/hooks/bst-hook.audit.local.jsonl"));
|
|
5251
5295
|
if (entries.length === 0) {
|
|
5252
|
-
|
|
5296
|
+
write("No audit log entries found.");
|
|
5253
5297
|
return;
|
|
5254
5298
|
}
|
|
5255
5299
|
const decisionFilter = args.decision;
|
|
5256
5300
|
if (decisionFilter) entries = entries.filter((e) => e.decision === decisionFilter);
|
|
5257
|
-
const tailCount = args.tail ? Number.parseInt(args.tail, 10) : 20;
|
|
5258
|
-
if (entries.length > tailCount) entries = entries.slice(-tailCount);
|
|
5259
5301
|
if (args.json === true) {
|
|
5260
|
-
|
|
5302
|
+
const tail = args.tail ? Number.parseInt(args.tail, 10) : entries.length;
|
|
5303
|
+
for (const entry of entries.slice(-tail)) write(JSON.stringify(entry));
|
|
5304
|
+
return;
|
|
5305
|
+
}
|
|
5306
|
+
if (args.tail) {
|
|
5307
|
+
const tailCount = Number.parseInt(args.tail, 10);
|
|
5308
|
+
for (const entry of entries.slice(-tailCount)) {
|
|
5309
|
+
const ts = new Date(entry.timestamp).toLocaleString();
|
|
5310
|
+
const rule = entry.rule ? ` [${entry.rule}]` : "";
|
|
5311
|
+
write(`${ts} ${entry.decision.padEnd(12)}${entry.command}${rule}`);
|
|
5312
|
+
}
|
|
5261
5313
|
return;
|
|
5262
5314
|
}
|
|
5263
|
-
const allEntries = parseAuditLog(logPath);
|
|
5264
5315
|
const counts = {
|
|
5265
5316
|
allow: 0,
|
|
5266
5317
|
deny: 0,
|
|
5267
5318
|
passthrough: 0
|
|
5268
5319
|
};
|
|
5269
|
-
for (const e of
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
const reason = entry.reason ? ` — ${entry.reason}` : "";
|
|
5277
|
-
log.info(` ${icon} ${ts} ${entry.decision.padEnd(11)} ${entry.command}${rule}${reason}`);
|
|
5278
|
-
}
|
|
5320
|
+
for (const e of entries) counts[e.decision]++;
|
|
5321
|
+
write(`${String(entries.length)} entries: ${String(counts.allow)} allow, ${String(counts.deny)} deny, ${String(counts.passthrough)} passthrough`);
|
|
5322
|
+
write();
|
|
5323
|
+
const denied = entries.filter((e) => e.decision === "deny");
|
|
5324
|
+
const passthrough = entries.filter((e) => e.decision === "passthrough");
|
|
5325
|
+
printSection("Denied commands:", denied, 10);
|
|
5326
|
+
printSection("Passthrough commands:", passthrough, 10);
|
|
5279
5327
|
}
|
|
5280
5328
|
});
|
|
5281
5329
|
//#endregion
|
|
@@ -5283,7 +5331,7 @@ const hooksAuditCommand = defineCommand({
|
|
|
5283
5331
|
const main = defineCommand({
|
|
5284
5332
|
meta: {
|
|
5285
5333
|
name: "bst",
|
|
5286
|
-
version: "0.
|
|
5334
|
+
version: "0.40.1",
|
|
5287
5335
|
description: "Bootstrap and maintain standardized TypeScript project tooling"
|
|
5288
5336
|
},
|
|
5289
5337
|
subCommands: {
|
|
@@ -5300,7 +5348,7 @@ const main = defineCommand({
|
|
|
5300
5348
|
"hooks:audit": hooksAuditCommand
|
|
5301
5349
|
}
|
|
5302
5350
|
});
|
|
5303
|
-
console.log(`@bensandee/tooling v0.
|
|
5351
|
+
console.log(`@bensandee/tooling v0.40.1`);
|
|
5304
5352
|
async function run() {
|
|
5305
5353
|
await runMain(main);
|
|
5306
5354
|
process.exit(process.exitCode ?? 0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bensandee/tooling",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.1",
|
|
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/claude-hooks": "0.
|
|
64
|
-
"@bensandee/config": "0.
|
|
63
|
+
"@bensandee/claude-hooks": "0.2.0",
|
|
64
|
+
"@bensandee/config": "0.10.0"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
67
|
"build": "tsdown",
|