cc-safety-net 2.4.2 → 2.4.4
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/README.md +3 -1
- package/dist/amp/cc-safety-net/index.ts +41 -41
- package/dist/api.js +1 -1
- package/dist/bin/hook.js +40 -40
- package/dist/chunks/index-q7q195qc.js +2 -0
- package/dist/chunks/{index-jfmgn339.js → index-sxtcjq8b.js} +4 -4
- package/dist/chunks/index-vas3sm16.js +45 -0
- package/dist/cli.js +113 -113
- package/dist/index.d.ts +5 -0
- package/dist/index.js +11 -1
- package/dist/openclaw/cc-safety-net/index.js +41 -41
- package/dist/openclaw/cc-safety-net/openclaw.plugin.json +1 -1
- package/dist/openclaw/cc-safety-net/package.json +1 -1
- package/dist/opencode-v2.d.ts +3 -0
- package/dist/pi/index.js +2 -2
- package/package.json +16 -4
- package/dist/chunks/index-409cdnva.js +0 -2
- package/dist/chunks/index-pmd634p1.js +0 -45
package/dist/cli.js
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
import{a,s,ke,
|
|
2
|
-
${
|
|
3
|
-
`).filter(Boolean).flatMap((
|
|
4
|
-
`)}function Mi(A,z){let X=new Date(A);if(Number.isNaN(X.getTime()))return A;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:z}).format(X)}function Ii(A){let z=Number(A);return Number.isFinite(z)&&z>0?z:null}var Hi={name:"doctor",aliases:["--doctor"],description:"Run diagnostic checks to verify installation and configuration",usage:"doctor [options]",options:[{flags:"--json",description:"Output diagnostics as JSON"},{flags:"--skip-update-check",description:"Skip npm registry version check"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net doctor","cc-safety-net doctor --json","cc-safety-net doctor --skip-update-check"]};var Ui={name:"explain",description:"Show step-by-step analysis trace of how a command would be analyzed",usage:"explain [options] <command>",argument:"<command>",options:[{flags:"--json",description:"Output analysis as JSON"},{flags:"--cwd",argument:"<path>",description:"Use custom working directory"},{flags:"-h, --help",description:"Show this help"}],examples:['cc-safety-net explain "git reset --hard"','cc-safety-net explain --json "rm -rf /"','cc-safety-net explain --cwd /tmp "git status"']};var Gi={name:"gui",description:"Open the local policy editor GUI",usage:"gui [options]",options:[{flags:"--no-open",description:"Print the URL without opening a browser"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net gui","cc-safety-net gui --no-open"]};var Kn=[{id:"antigravity-cli",displayName:"Antigravity CLI",doctorOrder:3,runtime:{order:1,flags:["-ac","--agy-cli"],description:"Run as Antigravity CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{order:2,flag:"--agy-cli",artifactKind:"hook config",probeCommand:["agy","--version"]}},{id:"claude-code",displayName:"Claude Code",doctorOrder:1,runtime:{order:2,displayName:"Coding CLI",flags:["-cc","--coding-cli"],legacyFlags:["--claude-code"],description:"Run as Coding CLI PreToolUse hook",legacyTopLevelFlags:["-cc","--claude-code"]},install:{order:3,flag:"--claude-code",artifactKind:"plugin",probeCommand:["claude","--version"]}},{id:"codex",displayName:"Codex",doctorOrder:4,runtime:{order:3,flags:["-cx","--codex"],description:"Run as a Codex PreToolUse hook",legacyTopLevelFlags:[]},install:{order:4,flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",doctorOrder:7,runtime:{order:6,flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{order:7,flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",doctorOrder:6,runtime:{order:5,flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{order:6,flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",doctorOrder:8,runtime:{order:7,flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{order:8,flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",doctorOrder:9,runtime:{order:8,flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{order:9,flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",doctorOrder:10,runtime:{order:9,flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{order:10,flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",doctorOrder:11,install:{order:11,flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",doctorOrder:12,install:{order:12,flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",doctorOrder:13,install:{order:13,flag:"--pi",artifactKind:"package",probeCommand:["pi","--version"]}},{id:"cursor",displayName:"Cursor",doctorOrder:5,runtime:{order:4,flags:["-cu","--cursor"],description:"Run as Cursor preToolUse hook",legacyTopLevelFlags:[]},install:{order:5,flag:"--cursor",artifactKind:"hook config",probeCommand:["cursor","--version"]}},{id:"amp",displayName:"Amp Code",doctorOrder:2,install:{order:1,flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],Yn=Kn.slice().sort((A,z)=>A.doctorOrder-z.doctorOrder).map((A)=>A.id),Cn=Kn.filter((A)=>("runtime"in A)).slice().sort((A,z)=>A.runtime.order-z.runtime.order).map((A)=>({id:A.id,displayName:"displayName"in A.runtime?A.runtime.displayName:A.displayName,flags:A.runtime.flags,legacyFlags:"legacyFlags"in A.runtime?A.runtime.legacyFlags:[],description:A.runtime.description,legacyTopLevelFlags:A.runtime.legacyTopLevelFlags})),Tt=Kn.slice().sort((A,z)=>A.install.order-z.install.order).map((A)=>({id:A.id,...A.install})).map(({order:A,...z})=>z),pu=Object.fromEntries(Kn.map((A)=>[A.id,A.displayName]));function bt(A){return pu[A]}var fu=Cn.map((A)=>({flags:A.flags.join(", "),description:A.description})),mu=Cn.flatMap((A)=>A.flags.map((z)=>`cc-safety-net hook ${z}`)),Bi={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...fu,{flags:"-h, --help",description:"Show this help"}],examples:mu};var qi={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...Tt.map((A)=>({flags:A.flag,description:`Install ${bt(A.id)} ${A.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...Tt.map((A)=>`cc-safety-net install ${A.flag}`)]},Vi={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...Tt.map((A)=>({flags:A.flag,description:`Uninstall ${bt(A.id)} ${A.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...Tt.map((A)=>`cc-safety-net uninstall ${A.flag}`)]},zi={name:"update",description:"Update every installed CC Safety Net integration to the latest version",usage:"update",options:[{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net update"]};var Ji={name:"logs",description:"Browse audit log entries recorded by hooks",usage:"logs [options]",options:[{flags:"--id",argument:"<id>",description:"Show one entry from retained history by its 16-character id (not guaranteed once it is older than the configured retention)"},{flags:"--limit",argument:"<n>",description:"Maximum entries to print",default:"20"},{flags:"--since",argument:"<days>",description:"Only include entries newer than this many days (max: the configured audit retention, 1-365)",default:"30"},{flags:"--agent",argument:"<name>",description:"Filter by agent name"},{flags:"--rule",argument:"<ruleId>",description:"Filter by rule id"},{flags:"--session",argument:"<id>",description:"Filter by session id"},{flags:"--project",argument:"<path>",description:"Filter by project path"},{flags:"--suspect",description:"Only denials that look like false positives"},{flags:"--all",description:"Include allow entries"},{flags:"--prune-legacy",description:"Permanently delete all legacy root-level logs; nested logs are untouched"},{flags:"--dry-run",description:"With --prune-legacy, report what would be deleted and delete nothing"},{flags:"--json",description:"Output entries as JSON"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net logs --id 3fa9c2d1a70e8b42","cc-safety-net logs --agent claude-code","cc-safety-net logs --project . --since 7","cc-safety-net logs --suspect --since 7","cc-safety-net logs --json","cc-safety-net logs --prune-legacy --dry-run","cc-safety-net logs --prune-legacy"]};var Zn={name:"policy",description:"Check and apply project or user policy proposals",usage:"policy <subcommand>",subcommands:[{usage:"check <file>",description:"Validate a policy proposal and print its diff"},{usage:"apply <file>",description:"Apply a proposal after confirming in a terminal"}],options:[{flags:"-g, --global",description:"Use the user-scope policy instead of the project one"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net policy check proposal.json","cc-safety-net policy apply proposal.json","cc-safety-net policy apply proposal.json --global"]};var Qr=[{flags:"--ref",argument:"<ref>",description:"Use a branch, tag, or commit"},{flags:"--only",argument:"<rulebook...>",description:"Add only these repository rulebooks"},{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"-h, --help",description:"Show this help"}],eo=["cc-safety-net rule add project-rules","cc-safety-net rule add acme/safety-rules","cc-safety-net rule add acme/safety-rules --only aws gcloud","cc-safety-net rule add acme/safety-rules --ref v2 --only aws","cc-safety-net rule add --only terraform aws"],pn={name:"rule",description:"Manage CC Safety Net rule config and rulebook sources",usage:"rule <subcommand>",subcommands:[{usage:"init [--example]",description:"Create inert rule config"},{usage:"add [source] [--ref <ref>] [--only <rulebook...>]",description:"Add rulebook sources and sync"},{usage:"remove <source>",description:"Remove a rulebook source and sync"},{usage:"update [source]",description:"Re-fetch and vendor remote rulebooks"},{usage:"sync",description:"Deprecated: migrate lock and cache leftovers"},{usage:"list",description:"List active rulebooks"},{usage:"wrapper add <command>",description:"Trust a transparent command wrapper"},{usage:"wrapper remove <command>",description:"Remove a transparent command wrapper"},{usage:"wrapper list",description:"List transparent command wrappers"},{usage:"migrate [--cleanup]",description:"Migrate legacy inline rules"},{usage:"doc",description:"Print the rulebook authoring guide"},{usage:"verify",description:"Validate rule config files"}],options:[{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"--cleanup",description:"Delete legacy files after rule migrate verifies them"},{flags:"--delete-source",description:"Delete clean local source directory on remove"},{flags:"--example",description:"Create an inactive example rulebook with rule init"},...Qr.slice(0,2),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net rule init","cc-safety-net rule init --example","cc-safety-net rule wrapper add rtk",...eo,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var Wi={name:"status",description:"Show what the runtime is enforcing right now",usage:"status",options:[{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net status"]};var Ki={name:"statusline",description:"Print status line with mode indicators for shell integration",usage:"statusline --claude-code",options:[{flags:"-cc, --claude-code",description:"Print status line for Claude Code"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net statusline -cc","cc-safety-net statusline --claude-code"]};var Xn=[Wi,Hi,Ji,Ui,pn,Zn,qi,zi,Vi,Bi,Gi,Ki];function gu(A){return A.aliases??[]}function Qn(A){let z=A.toLowerCase();return Xn.find((X)=>X.name.toLowerCase()===z||gu(X).some((ee)=>ee.toLowerCase()===z))}import{basename as yu}from"node:path";function er(A,z=7,X=D(A)){let ee=Date.now()-z*24*60*60*1000,te=[],ae=new Set,le=0,ye,he,ve,be;if(X)B(A,X);let Ie={count:0},Xe=X?Yt(X,Ie):[];for(let Ee of Xe)for(let at of un(Ee,Ie)){if(at.decision==="allow")continue;let ct=new Date(at.ts).getTime();if(ct>=ee){if(le++,ae.add(at.sessionId??yu(Ee,".jsonl")),he===void 0||ct<=he)ye=at.ts,he=ct;if(be===void 0||ct>be)ve=at.ts,be=ct;hu(te,at,ct)}}let et=te.map((Ee)=>({timestamp:Ee.ts,command:Ee.command,reason:Ee.reason,relativeTime:Ti(new Date(Ee.ts))}));return{totalBlocked:le,sessionCount:ae.size,recentEntries:et,oldestEntry:ye,newestEntry:ve,unreadable:Ie.count}}function hu(A,z,X){let ee=A.findIndex((te)=>X>new Date(te.ts).getTime());if(ee===-1){if(A.length<3)A.push(z);return}if(A.splice(ee,0,z),A.length>3)A.pop()}import{dirname as Du}from"node:path";import{dirname as vu,join as bu,resolve as Lu}from"node:path";var wu="config.json";function Rt(A,z,X,ee){g(ku(A),`${JSON.stringify(z,null,2)}
|
|
5
|
-
`,X,ee)}function ku(A){return typeof A==="string"?ne(A):A}function no(A){return{errors:oe(Cu(A),": "," "),ruleNames:new Set(_e(A).map((z)=>z.toLowerCase()))}}var xu="must match pattern (letters, numbers, hyphens, underscores; max 64 chars)",Yi="must match pattern (letters, numbers, hyphens, underscores)";function Cu(A){if(!Zi(A))return[e([],"Config must be an object")];return[...A.version===1?[]:[e(["version"],"must be 1")],...Su(A.rules)]}function Su(A){if(A===void 0)return[];if(!Array.isArray(A))return[e(["rules"],"must be an array")];return[...A.flatMap((z,X)=>Zi(z)?Ru(z,["rules",X]):[e(["rules",X],"must be an object")]),...Pe(A)]}function Ru(A,z){return[...to(A.name,[...z,"name"],"required string",c,xu),...to(A.command,[...z,"command"],"required string",S,Yi),...A.subcommand===void 0?[]:to(A.subcommand,[...z,"subcommand"],"must be a string if provided",S,Yi),...Pu(A.block_args,[...z,"block_args"]),...Eu(A.reason,[...z,"reason"]),...A.intent===void 0||xe(A.intent)?[]:[e([...z,"intent"],Se)]]}function to(A,z,X,ee,te){if(typeof A!=="string")return[e(z,X)];return ee.test(A)?[]:[e(z,te)]}function Pu(A,z){if(!Array.isArray(A))return[e(z,"required array")];if(A.length===0)return[e(z,"must have at least one element")];return A.flatMap((X,ee)=>{if(typeof X!=="string")return[e([...z,ee],"must be a string")];return X===""?[e([...z,ee],"must not be empty")]:[]})}function Eu(A,z){if(typeof A!=="string")return[e(z,"required string")];if(A==="")return[e(z,"must not be empty")];return A.length>P?[e(z,`must be at most ${P} characters`)]:[]}function Zi(A){return!!A&&typeof A==="object"&&!Array.isArray(A)}function ro(A){let z=Xi(A);if(!z.ok)return z.result;return no(z.parsed)}function Xi(A){let z=[],X=new Set;try{let ee=typeof A==="string"?ne(A):A,te=n(ee);if(te===null)return z.push(`File not found: ${ee.path}`),{ok:!1,result:{errors:z,ruleNames:X}};if(!te.trim())return z.push("Config file is empty"),{ok:!1,result:{errors:z,ruleNames:X}};return{ok:!0,parsed:JSON.parse(te)}}catch(ee){if(ee instanceof r)return z.push(ee.message),{ok:!1,result:{errors:z,ruleNames:X}};let te=ee instanceof Error?ee.message:String(ee);return z.push(ee instanceof SyntaxError?"Invalid JSON":te),{ok:!1,result:{errors:z,ruleNames:X}}}}function Qi(A){return Lu(A,".safety-net.json")}function Jt(A){let z=Xi(A);if(!z.ok)return z.result;let X=Ve(z.parsed);return{errors:X.errors,ruleNames:X.sources}}function tr(A,z={}){return bu(vu(Ce(A,z)),wu)}function es(A,z,X){let ee;try{if(n(z)===null)return{path:A,exists:!1,valid:!1,ruleCount:0};ee=Jt(z),ee.errors.push(...j(A,X))}catch(te){if(!(te instanceof r))throw te;ee={errors:[te.message],ruleNames:new Set}}return{path:A,exists:!0,valid:ee.errors.length===0,ruleCount:ee.ruleNames.size,...ee.errors.length>0?{errors:ee.errors}:{}}}function Au(A,z){return{source:z,name:A.name,command:A.command,subcommand:A.subcommand,blockArgs:[...A.block_args],reason:A.reason}}function ts(A,z){let X=F(A),ee=M(z),te=Du(X),ae=K(A,{cwd:z,userConfigPath:X,projectConfigPath:ee,userConfigDir:te}),le=q(A,{cwd:z,userConfigPath:X,projectConfigPath:ee,userConfigDir:te}),ye=new Map(ae.rulebooks.flatMap((he)=>he.rules.map((ve)=>[ve,he.source])));return{userConfig:es(X,le.userConfigTarget,le.userScope),projectConfig:es(ee,le.projectConfigTarget,le.projectScope),effectiveRules:ae.rules.map((he)=>Au(he,ye.get(he.name)??"project"))}}var _u=[{flag:o.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:o.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:o.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:o.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:o.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:o.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:o.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:o.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"}];function ns(A){return[..._u.map((z)=>({name:z.flag.name,value:we(z.flag,A.env),isSet:Qe(z.flag,A.env),legacyName:z.flag.legacyName,legacyValue:z.flag.legacyName?A.env.get(z.flag.legacyName):void 0,legacyIsSet:z.flag.legacyName?A.env.get(z.flag.legacyName)!==void 0:void 0,description:z.description,defaultBehavior:z.defaultBehavior})),{name:"CC_SAFETY_NET_HOME",value:A.env.get("CC_SAFETY_NET_HOME"),isSet:A.env.get("CC_SAFETY_NET_HOME")!==void 0,description:"Override user-scope config/cache directory",defaultBehavior:"~/.cc-safety-net"}]}var rs={error:0,warning:1,info:2},Tu=["policy","config","audit"];function $u(A){return A.map((z)=>{if(z==="ownership")return"is not owned by the current user";if(z==="permissions")return"has unsafe permissions";if(z==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var Iu=[{derive:(A)=>A.hooks.length>0&&A.hooks.every((z)=>!z.configured)?[{checkId:"integration.none-configured",severity:"error",title:"No integration configured",detail:"CC Safety Net is not connected to any supported coding-agent integration.",fixHint:"Run `cc-safety-net install` and configure at least one integration."}]:[]},{derive:(A)=>A.hooks.filter((z)=>z.inspectionStatus==="failed").map((z)=>{let X=bt(z.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${X} inspection failed`,detail:`Doctor could not verify the ${X} integration configuration.`,fixHint:`Correct the reported ${X} configuration error, then run \`cc-safety-net doctor\` again.`,integration:z.platform}})},{derive:(A)=>A.userConfig.exists&&!A.userConfig.valid?[{checkId:"config.user-invalid",severity:"error",title:"User configuration is invalid",detail:"Doctor could not load a valid user rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:A.userConfig.path}]:[]},{derive:(A)=>A.projectConfig.exists&&!A.projectConfig.valid?[{checkId:"config.project-invalid",severity:"error",title:"Project configuration is invalid",detail:"Doctor could not load a valid project rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:A.projectConfig.path}]:[]},{derive:(A)=>A.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${A.configState.reason}`,fixHint:"Fix the file named in the reason, or run `cc-safety-net rule update` to vendor a remote source, then rerun doctor."}]:[]},{derive:(A)=>A.v2Leftovers&&A.v2Leftovers.length>0?[{checkId:"config.v2-leftovers",severity:"info",title:"Rulebook lock and cache leftovers detected",detail:`Files an earlier version left behind are no longer read: ${A.v2Leftovers.join(", ")}.`,fixHint:"Run `cc-safety-net rule sync` (add `--global` for user scope) to migrate them, then rerun doctor."}]:[]},{derive:(A)=>{let z=A.environment.find((X)=>X.name==="CC_SAFETY_NET_AUDIT_SCOPE");return We(z?.value)==="invalid"?[{checkId:"environment.audit-scope-invalid",severity:"warning",title:"Audit scope value is invalid",detail:"CC_SAFETY_NET_AUDIT_SCOPE is not `all` or `blocked`, so allowed command decisions are not recorded.",fixHint:"Set CC_SAFETY_NET_AUDIT_SCOPE to `all` or `blocked`, then restart the integration."}]:[]}},...Tu.map((A)=>({derive:(z)=>z.posture.directories.filter((X)=>X.kind===A&&X.status==="unsafe").map((X)=>({checkId:`posture.${A}-directory-unsafe`,severity:"error",title:`${A[0]?.toUpperCase()}${A.slice(1)} directory is unsafe`,detail:`The ${A} directory ${$u(X.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...X.path?{path:X.path}:{}}))})),{derive:(A)=>{let z=[...A.effectiveSafety.weakenedRuleOverrides].sort();return z.length>0?[{checkId:"posture.rule-overrides-weaken-preset",severity:"warning",title:"Rule overrides weaken the selected preset",detail:`Explicit overrides disable rules the resolved preset would enable: ${z.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${z.join(", ")}.`}]:[]}}];function os(A){return Iu.flatMap((z,X)=>z.derive(A).map((ee,te)=>({finding:ee,catalogOrder:X,occurrence:te}))).sort((z,X)=>rs[z.finding.severity]-rs[X.finding.severity]||z.catalogOrder-X.catalogOrder||z.occurrence-X.occurrence).map((z)=>z.finding)}function Ut(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var Ou=(A)=>Ut()?`\x1B[32m${A}\x1B[0m`:A,Fu=(A)=>Ut()?`\x1B[33m${A}\x1B[0m`:A,ju=(A)=>Ut()?`\x1B[34m${A}\x1B[0m`:A,Nu=(A)=>Ut()?`\x1B[36m${A}\x1B[0m`:A,Mu=(A)=>Ut()?`\x1B[31m${A}\x1B[0m`:A,Hu=(A)=>Ut()?`\x1B[2m${A}\x1B[0m`:A,Uu=(A)=>Ut()?`\x1B[1m${A}\x1B[0m`:A,dt={green:Ou,yellow:Fu,blue:ju,cyan:Nu,red:Mu,dim:Hu,bold:Uu},Gu="\x1B[0m",Bu=[39,82,198,226,208,51,196,46,201,214,93,154,220,27,49,190,200,33,129,227,45,160,63,118,123,202];function qu(A){let z=A;return()=>(z=(z*1664525+1013904223)%4294967296,z/4294967296)}function Vu(A){let z=[...Bu],X=qu(A);for(let ee=z.length-1;ee>0;ee--){let te=Math.floor(X()*(ee+1)),ae=z[ee];z[ee]=z[te],z[te]=ae}return z}function zu(A,z=0){if(!Ut())return"";let X=Vu(z);return`\x1B[38;5;${X[A%X.length]}m`}function is(A,z,X=0){if(!Ut())return`"${A}"`;return`${zu(z,X)}"${A}"${Gu}`}function nr(A){return A==="default"?"built-in default":`${A} policy`}var Ju=new RegExp("\x1B\\[[0-9;]*m","g"),oo=(A)=>A.replace(Ju,"").length;function Zt(A){let z=(A.headers??A.rows[0]??[]).map((le,ye)=>{let he=Math.max(...A.rows.map((ve)=>oo(ve[ye]??"")));return Math.max(oo(le),he)}),X=(le,ye)=>le+" ".repeat(Math.max(0,ye-oo(le))),ee=(le,ye)=>ye[0]+z.map((he)=>le.repeat(he+2)).join(ye[1])+ye[2],te=(le)=>`│ ${le.map((ye,he)=>X(ye,z[he]??0)).join(" │ ")} │`,ae=A.headers?[` ${te(A.headers)}`,` ${ee("─",["├","┼","┤"])}`]:[];return[` ${ee("─",["┌","┬","┐"])}`,...ae,...A.rows.map((le)=>` ${te(le)}`),` ${ee("─",["└","┴","┘"])}`].join(`
|
|
6
|
-
`)}function
|
|
7
|
-
`)}function
|
|
8
|
-
`)}function
|
|
9
|
-
`)}function
|
|
10
|
-
`)}function
|
|
11
|
-
`)}function
|
|
12
|
-
`);for(let
|
|
13
|
-
`)}function
|
|
14
|
-
`)}function
|
|
15
|
-
`);if(
|
|
16
|
-
`);if(
|
|
17
|
-
`);return
|
|
18
|
-
`)}function
|
|
19
|
-
`)}function
|
|
20
|
-
No findings from inspected doctor facts.`);let
|
|
21
|
-
${
|
|
22
|
-
`)[0]?.trim()||null}async function
|
|
23
|
-
`).map((
|
|
24
|
-
`.repeat(
|
|
25
|
-
\x1B[0m\x1B[?25h`)}}var
|
|
26
|
-
`);function
|
|
27
|
-
`).map((
|
|
28
|
-
`).find((
|
|
29
|
-
`)
|
|
30
|
-
`,
|
|
31
|
-
`?
|
|
32
|
-
`,
|
|
33
|
-
`,
|
|
34
|
-
`)}function
|
|
35
|
-
`),{path:
|
|
36
|
-
`)}function
|
|
37
|
-
# version: ${
|
|
38
|
-
`}function
|
|
39
|
-
version: "${
|
|
1
|
+
import{a,s,ke,Ue,k,Ze,Ge,c,o,He,R,L,ve,Qe,f,We,d,r,v,i,re,n,g,le,N,tt,nt,l,ue,de,rt,A,q,oe,S,ot,F,b,Se,M,u,K,Be,ze,I,w,T,pe,fe,Le,it,m,e,Te,we,Ve,qe,ie,Ce,se,_e,J,j,Pe,me,U,Ke,G,Y,Z,ae,Je,Ye,C,H,Ae,Oe,De,E,Ne,Ee,Fe,h,t,X,ge,y,x,_,st,Me,$e,p,W}from"./chunks/index-vas3sm16.js";import{ee,B,je,O,D}from"./chunks/index-sxtcjq8b.js";var Ud=["-h","--help"];function xt(P,V){let z=Object.entries(P.booleans??{}),Q=Object.entries(P.values??{}),te=Object.entries(P.lists??{}),ne=Object.fromEntries(z.map(([Xe])=>[Xe,!1])),ce={},ye=Object.fromEntries(te.map(([Xe])=>[Xe,[]])),he=[],be=[],xe=!1,Ie=-1;for(let[Xe,et]of V.entries()){if(Xe<=Ie)continue;if(et==="--"){he.push(...V.slice(Xe+1));break}if(Ud.includes(et)){xe=!0;continue}let Re=z.find(([,lt])=>lt.includes(et));if(Re){ne[Re[0]]=!0;continue}let at=Q.find(([,lt])=>lt.includes(et));if(at){let lt=V[Xe+1];if(lt===void 0||lt.startsWith("-")){be.push(`${et} requires a value`);continue}ce[at[0]]=lt,Ie=Xe+1;continue}let ct=te.find(([,lt])=>lt.includes(et));if(ct){let lt=V.slice(Xe+1),pt=lt.findIndex((gt)=>gt.startsWith("-")),mt=lt.slice(0,pt===-1?lt.length:pt);if(mt.length===0){be.push(`${et} requires at least one value`);continue}ye[ct[0]]=[...ye[ct[0]]??[],...mt],Ie=Xe+mt.length;continue}if(et.startsWith("-")){be.push(`Unknown option for ${P.label}: ${et}`);continue}if(P.positionals==="tail"){he.push(...V.slice(Xe));break}he.push(et)}if(P.positionals!=="list"&&P.positionals!=="tail")be.push(...he.map((Xe)=>`Unexpected argument for ${P.label}: ${Xe}`));return{flags:ne,values:ce,lists:ye,positionals:he,help:xe,errors:be}}function Ht(P){for(let V of P)console.error(V);return P.length>0}import{readdirSync as Wd,statSync as Ni,unlinkSync as Kd}from"node:fs";import{basename as Mi,dirname as Yd,isAbsolute as Zd,join as Xd,relative as Qd,resolve as eu,sep as tu}from"node:path";var Oi=(P)=>{let V=Date.now()-new Date(P).getTime();if(!Number.isFinite(V))return"";let z=Math.floor(V/60000),Q=Math.floor(z/60),te=Math.floor(Q/24);if(te>0)return`${te}d ago`;if(Q>0)return`${Q}h ago`;if(z>0)return`${z}m ago`;return"just now"},Qr=(P)=>{let V=(P??"").trim().split(/\s+/).filter((te)=>te&&!/^[A-Za-z_][A-Za-z0-9_]*=/.test(te)),z=V[0]?.split("/").pop();if(!z)return null;let Q=V[1];return Q&&/^[a-z][a-z0-9-]*$/.test(Q)?`${z} ${Q}`:z};function Fi(P){let V=(te)=>`${te.sessionId}
|
|
2
|
+
${Qr(te.segment||te.command)}`,z=P.filter((te)=>te.decision!=="allow"),Q=z.filter((te)=>te.sessionId).reduce((te,ne)=>te.set(V(ne),(te.get(V(ne))??0)+1),new Map);return new Set(z.filter((te)=>te.failureStage||(Q.get(V(te))??0)>=2))}import{existsSync as Gd,readdirSync as Bd,readFileSync as qd}from"node:fs";import{join as Vd}from"node:path";function Yt(P,V){try{return Bd(P,{withFileTypes:!0,encoding:"utf8"}).flatMap((z)=>{let Q=Vd(P,z.name);if(z.isDirectory())return Yt(Q,V);if(z.name.endsWith(".jsonl"))return[Q];return[]})}catch{if(V&&Gd(P))V.count++;return[]}}var zd=["segment","reason","sessionId","decision","agent","ruleId","failureStage"];function Jd(P){if(!P||typeof P!=="object"||Array.isArray(P))return!1;let V=P;if(typeof V.ts!=="string"||typeof V.command!=="string")return!1;return zd.every((z)=>V[z]===void 0||typeof V[z]==="string")}function pn(P,V){try{return qd(P,"utf-8").split(`
|
|
3
|
+
`).filter(Boolean).flatMap((z)=>{try{let Q=JSON.parse(z);if(!Jd(Q)){if(V)V.count++;return[]}return[Q]}catch{if(V)V.count++;return[]}})}catch{if(V)V.count++;return[]}}function Ct(P){return Array.from(P,(V)=>{let z=V.charCodeAt(0);if(z<=31||z>=127&&z<=159)return`\\x${z.toString(16).padStart(2,"0")}`;return V}).join("")}function nu(P,V){let z=ee(P),Q=xt({label:"logs",booleans:{all:["--all"],suspect:["--suspect"],json:["--json"],pruneLegacy:["--prune-legacy"],dryRun:["--dry-run"]},values:{id:["--id"],limit:["--limit"],since:["--since"],agent:["--agent"],rule:["--rule"],session:["--session"],project:["--project"]}},V);if(Ht(Q.errors))return null;if(Q.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(Q.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let te=Q.values.limit===void 0?20:ji(Q.values.limit);if(te===null)return console.error("--limit must be a positive number"),null;let ne=Q.values.since===void 0?Math.min(30,z):ji(Q.values.since);if(ne===null||ne>z)return console.error(`--since must be a positive number of days no greater than ${z}`),null;let ce={limit:te,limitExplicit:Q.values.limit!==void 0,since:ne,sinceExplicit:Q.values.since!==void 0,all:Q.flags.all,json:Q.flags.json,suspect:Q.flags.suspect,pruneLegacy:Q.flags.pruneLegacy,dryRun:Q.flags.dryRun,id:Q.values.id,agent:Q.values.agent,rule:Q.values.rule,session:Q.values.session,project:Q.values.project===void 0?void 0:eu(Q.values.project)};if(ce.id&&(ce.agent!==void 0||ce.rule!==void 0||ce.session!==void 0||ce.project!==void 0||ce.suspect||ce.sinceExplicit||ce.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(ce.pruneLegacy&&(ce.id!==void 0||ce.agent!==void 0||ce.rule!==void 0||ce.session!==void 0||ce.project!==void 0||ce.suspect||ce.all||ce.sinceExplicit||ce.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(ce.dryRun&&!ce.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return ce}async function Hi(P,V,z={}){let Q=nu(P,V);if(!Q)return 1;let te=z.logsDir??O(P);if(Q.pruneLegacy)return ru(te,Q.json,Q.dryRun);if(!te)return console.log(Q.json?"[]":Q.id?`No retained audit log entry found for id ${Ct(Q.id)}.`:"No audit log entries found."),0;B(P,te);let ne={count:0},ce=Yt(te,ne).flatMap((Ie)=>pn(Ie,ne).map((Xe)=>({entry:Xe,file:Ie})));if(ne.count>0)console.error(`warning: ${ne.count} audit log ${ne.count===1?"source":"sources"} could not be read; these results are incomplete`);if(Q.id)return au(ce,Q,z.timeZone);let ye=Date.now()-Q.since*24*60*60*1000,he=ce.filter((Ie)=>lu(Ie,Q,te,ye)),be=Q.suspect?Fi(he.map((Ie)=>Ie.entry)):null,xe=(be?he.filter((Ie)=>be.has(Ie.entry)):he).sort((Ie,Xe)=>Date.parse(Xe.entry.ts)-Date.parse(Ie.entry.ts)).slice(0,Q.limit);if(Q.json)return console.log(JSON.stringify(xe.map((Ie)=>Ie.entry),null,2)),0;if(xe.length===0)return console.log("No audit log entries found."),0;for(let Ie of xe)console.log(uu(Ie.entry,z.timeZone));return 0}function ru(P,V,z){let Q=P?iu(P).map((ye)=>Xd(P,ye)):[];if(z)return ou(Q,V);let te=[],ne=0,ce=0;for(let ye of Q){let he=Ni(ye,{throwIfNoEntry:!1})?.size??0,be=su(ye);if(be){te.push(`${Mi(ye)}: ${be}`);continue}ne++,ce+=he}if(V)return console.log(JSON.stringify({removedFiles:ne,removedBytes:ce,failedFiles:te.length})),te.length===0?0:1;console.log(ne===0&&te.length===0?"No legacy audit log files found.":`Removed ${ne} legacy audit log ${ne===1?"file":"files"} (${Ui(ce)}).`);for(let ye of te)console.error(`Could not remove ${Ct(ye)}`);if(console.log("Nested v2 audit logs were not changed."),ne>0)console.log("This deletion cannot be undone.");return te.length===0?0:1}function ou(P,V){let z=P.reduce((Q,te)=>Q+(Ni(te,{throwIfNoEntry:!1})?.size??0),0);if(V)return console.log(JSON.stringify({dryRun:!0,files:P.length,bytes:z})),0;if(console.log(P.length===0?"No legacy audit log files found.":`Would remove ${P.length} legacy audit log ${P.length===1?"file":"files"} (${Ui(z)}).`),console.log("Nested v2 audit logs are not included."),P.length>0)console.log("Run the same command without --dry-run to delete them.");return 0}function iu(P){try{return Wd(P,{withFileTypes:!0}).filter((V)=>V.isFile()&&V.name.endsWith(".jsonl")).map((V)=>V.name)}catch{return[]}}function su(P){try{return Kd(P),null}catch(V){return V instanceof Error?V.message:String(V)}}function Ui(P){let V=["B","KiB","MiB","GiB"],z=Math.min(Math.floor(Math.log2(Math.max(P,1))/10),V.length-1);return`${Math.round(P/1024**z*10)/10} ${V[z]}`}function au(P,V,z){let Q=P.filter((ne)=>ne.entry.id===V.id);if(Q.length>1)return console.error(`Multiple audit log entries found for id ${Ct(V.id??"")}.`),1;if(V.json)return console.log(JSON.stringify(Q.map((ne)=>ne.entry),null,2)),0;let te=Q[0];if(!te)return console.log(`No retained audit log entry found for id ${Ct(V.id??"")}.`),0;return console.log(pu(te.entry,z)),0}function lu(P,V,z,Q){if(!V.all&&P.entry.decision==="allow")return!1;if(Date.parse(P.entry.ts)<Q)return!1;if(V.agent!==void 0&&P.entry.agent!==V.agent)return!1;if(V.rule!==void 0&&P.entry.ruleId!==V.rule)return!1;if(V.session!==void 0&&!cu(P,z,V.session))return!1;if(V.project!==void 0&&!du(P.entry.cwd,V.project))return!1;return!0}function cu(P,V,z){if(P.entry.sessionId===z)return!0;return Yd(P.file)===V&&Mi(P.file,".jsonl")===z}function du(P,V){if(!P)return!1;let z=Qd(V,P);return z!==".."&&!z.startsWith(`..${tu}`)&&!Zd(z)}function uu(P,V){let z=Ct(P.id??"-"),Q=Ct(P.decision??"deny"),te=P.cwd?` [${Ct(P.cwd)}]`:"",ne=P.segment||P.command,ce=ne===P.command?"":"↳ ",ye=ne.length>50?`${ne.slice(0,50)}…`:ne;return`${z.padEnd(16)} ${Ct(Gi(P.ts,V))} ${Q.padEnd(5)} ${Ct(P.agent??"-").padEnd(15)} ${Ct(P.ruleId??"-").padEnd(20)} ${ce}${Ct(ye)}${te}`}function pu(P,V){let z=(te)=>Ct(te===void 0||te===null||te===""?"-":te),Q=P.shape?`${P.agent??"-"} (shape: ${P.shape})`:P.agent??"-";return[`id: ${z(P.id)}`,`ts: ${z(Gi(P.ts,V))}`,`decision: ${z(P.decision)}`,`agent: ${z(Q)}`,`level: ${z(P.level)}`,`tool: ${z(P.toolName)}`,`rule: ${z(P.ruleId)}`,`intent: ${z(P.intent)}`,`stage: ${z(P.failureStage)}`,`error: ${z(P.errorCode)}`,`session: ${z(P.sessionId)}`,`cwd: ${z(P.cwd)}`,`version: ${z(P.v)}`,`truncated: ${z(P.truncated===!0?"yes":void 0)}`,`reason: ${z(P.reason)}`,`command: ${z(P.command)}`,`segment: ${z(P.segment)}`].join(`
|
|
4
|
+
`)}function Gi(P,V){let z=new Date(P);if(Number.isNaN(z.getTime()))return P;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:V}).format(z)}function ji(P){let V=Number(P);return Number.isFinite(V)&&V>0?V:null}var Bi={name:"doctor",aliases:["--doctor"],description:"Run diagnostic checks to verify installation and configuration",usage:"doctor [options]",options:[{flags:"--json",description:"Output diagnostics as JSON"},{flags:"--skip-update-check",description:"Skip npm registry version check"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net doctor","cc-safety-net doctor --json","cc-safety-net doctor --skip-update-check"]};var qi={name:"explain",description:"Show step-by-step analysis trace of how a command would be analyzed",usage:"explain [options] <command>",argument:"<command>",options:[{flags:"--json",description:"Output analysis as JSON"},{flags:"--cwd",argument:"<path>",description:"Use custom working directory"},{flags:"-h, --help",description:"Show this help"}],examples:['cc-safety-net explain "git reset --hard"','cc-safety-net explain --json "rm -rf /"','cc-safety-net explain --cwd /tmp "git status"']};var Vi={name:"gui",description:"Open the local policy editor GUI",usage:"gui [options]",options:[{flags:"--no-open",description:"Print the URL without opening a browser"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net gui","cc-safety-net gui --no-open"]};var Yn=[{id:"antigravity-cli",displayName:"Antigravity CLI",doctorOrder:3,runtime:{order:1,flags:["-ac","--agy-cli"],description:"Run as Antigravity CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{order:2,flag:"--agy-cli",artifactKind:"hook config",probeCommand:["agy","--version"]}},{id:"claude-code",displayName:"Claude Code",doctorOrder:1,runtime:{order:2,displayName:"Coding CLI",flags:["-cc","--coding-cli"],legacyFlags:["--claude-code"],description:"Run as Coding CLI PreToolUse hook",legacyTopLevelFlags:["-cc","--claude-code"]},install:{order:3,flag:"--claude-code",artifactKind:"plugin",probeCommand:["claude","--version"]}},{id:"codex",displayName:"Codex",doctorOrder:4,runtime:{order:3,flags:["-cx","--codex"],description:"Run as a Codex PreToolUse hook",legacyTopLevelFlags:[]},install:{order:4,flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",doctorOrder:7,runtime:{order:6,flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{order:7,flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",doctorOrder:6,runtime:{order:5,flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{order:6,flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",doctorOrder:8,runtime:{order:7,flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{order:8,flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",doctorOrder:9,runtime:{order:8,flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{order:9,flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",doctorOrder:10,runtime:{order:9,flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{order:10,flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",doctorOrder:11,install:{order:11,flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",doctorOrder:12,install:{order:12,flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",doctorOrder:13,install:{order:13,flag:"--pi",artifactKind:"package",probeCommand:["pi","--version"]}},{id:"cursor",displayName:"Cursor",doctorOrder:5,runtime:{order:4,flags:["-cu","--cursor"],description:"Run as Cursor preToolUse hook",legacyTopLevelFlags:[]},install:{order:5,flag:"--cursor",artifactKind:"hook config",probeCommand:["cursor","--version"]}},{id:"amp",displayName:"Amp Code",doctorOrder:2,install:{order:1,flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],Zn=Yn.slice().sort((P,V)=>P.doctorOrder-V.doctorOrder).map((P)=>P.id),Sn=Yn.filter((P)=>("runtime"in P)).slice().sort((P,V)=>P.runtime.order-V.runtime.order).map((P)=>({id:P.id,displayName:"displayName"in P.runtime?P.runtime.displayName:P.displayName,flags:P.runtime.flags,legacyFlags:"legacyFlags"in P.runtime?P.runtime.legacyFlags:[],description:P.runtime.description,legacyTopLevelFlags:P.runtime.legacyTopLevelFlags})),$t=Yn.slice().sort((P,V)=>P.install.order-V.install.order).map((P)=>({id:P.id,...P.install})).map(({order:P,...V})=>V),fu=Object.fromEntries(Yn.map((P)=>[P.id,P.displayName]));function bt(P){return fu[P]}var mu=Sn.map((P)=>({flags:P.flags.join(", "),description:P.description})),gu=Sn.flatMap((P)=>P.flags.map((V)=>`cc-safety-net hook ${V}`)),zi={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...mu,{flags:"-h, --help",description:"Show this help"}],examples:gu};var Ji={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...$t.map((P)=>({flags:P.flag,description:`Install ${bt(P.id)} ${P.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...$t.map((P)=>`cc-safety-net install ${P.flag}`)]},Wi={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...$t.map((P)=>({flags:P.flag,description:`Uninstall ${bt(P.id)} ${P.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...$t.map((P)=>`cc-safety-net uninstall ${P.flag}`)]},Ki={name:"update",description:"Update every installed CC Safety Net integration to the latest version",usage:"update",options:[{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net update"]};var Yi={name:"logs",description:"Browse audit log entries recorded by hooks",usage:"logs [options]",options:[{flags:"--id",argument:"<id>",description:"Show one entry from retained history by its 16-character id (not guaranteed once it is older than the configured retention)"},{flags:"--limit",argument:"<n>",description:"Maximum entries to print",default:"20"},{flags:"--since",argument:"<days>",description:"Only include entries newer than this many days (max: the configured audit retention, 1-365)",default:"30"},{flags:"--agent",argument:"<name>",description:"Filter by agent name"},{flags:"--rule",argument:"<ruleId>",description:"Filter by rule id"},{flags:"--session",argument:"<id>",description:"Filter by session id"},{flags:"--project",argument:"<path>",description:"Filter by project path"},{flags:"--suspect",description:"Only denials that look like false positives"},{flags:"--all",description:"Include allow entries"},{flags:"--prune-legacy",description:"Permanently delete all legacy root-level logs; nested logs are untouched"},{flags:"--dry-run",description:"With --prune-legacy, report what would be deleted and delete nothing"},{flags:"--json",description:"Output entries as JSON"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net logs --id 3fa9c2d1a70e8b42","cc-safety-net logs --agent claude-code","cc-safety-net logs --project . --since 7","cc-safety-net logs --suspect --since 7","cc-safety-net logs --json","cc-safety-net logs --prune-legacy --dry-run","cc-safety-net logs --prune-legacy"]};var Xn={name:"policy",description:"Check and apply project or user policy proposals",usage:"policy <subcommand>",subcommands:[{usage:"check <file>",description:"Validate a policy proposal and print its diff"},{usage:"apply <file>",description:"Apply a proposal after confirming in a terminal"}],options:[{flags:"-g, --global",description:"Use the user-scope policy instead of the project one"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net policy check proposal.json","cc-safety-net policy apply proposal.json","cc-safety-net policy apply proposal.json --global"]};var eo=[{flags:"--ref",argument:"<ref>",description:"Use a branch, tag, or commit"},{flags:"--only",argument:"<rulebook...>",description:"Add only these repository rulebooks"},{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"-h, --help",description:"Show this help"}],to=["cc-safety-net rule add project-rules","cc-safety-net rule add acme/safety-rules","cc-safety-net rule add acme/safety-rules --only aws gcloud","cc-safety-net rule add acme/safety-rules --ref v2 --only aws","cc-safety-net rule add --only terraform aws"],fn={name:"rule",description:"Manage CC Safety Net rule config and rulebook sources",usage:"rule <subcommand>",subcommands:[{usage:"init [--example]",description:"Create inert rule config"},{usage:"add [source] [--ref <ref>] [--only <rulebook...>]",description:"Add rulebook sources and sync"},{usage:"remove <source>",description:"Remove a rulebook source and sync"},{usage:"update [source]",description:"Re-fetch and vendor remote rulebooks"},{usage:"sync",description:"Deprecated: migrate lock and cache leftovers"},{usage:"list",description:"List active rulebooks"},{usage:"wrapper add <command>",description:"Trust a transparent command wrapper"},{usage:"wrapper remove <command>",description:"Remove a transparent command wrapper"},{usage:"wrapper list",description:"List transparent command wrappers"},{usage:"migrate [--cleanup]",description:"Migrate legacy inline rules"},{usage:"doc",description:"Print the rulebook authoring guide"},{usage:"verify",description:"Validate rule config files"}],options:[{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"--cleanup",description:"Delete legacy files after rule migrate verifies them"},{flags:"--delete-source",description:"Delete clean local source directory on remove"},{flags:"--example",description:"Create an inactive example rulebook with rule init"},...eo.slice(0,2),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net rule init","cc-safety-net rule init --example","cc-safety-net rule wrapper add rtk",...to,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var Zi={name:"status",description:"Show what the runtime is enforcing right now",usage:"status",options:[{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net status"]};var Xi={name:"statusline",description:"Print status line with mode indicators for shell integration",usage:"statusline --claude-code",options:[{flags:"-cc, --claude-code",description:"Print status line for Claude Code"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net statusline -cc","cc-safety-net statusline --claude-code"]};var Qn=[Zi,Bi,Yi,qi,fn,Xn,Ji,Ki,Wi,zi,Vi,Xi];function yu(P){return P.aliases??[]}function er(P){let V=P.toLowerCase();return Qn.find((z)=>z.name.toLowerCase()===V||yu(z).some((Q)=>Q.toLowerCase()===V))}import{basename as hu}from"node:path";function tr(P,V=7,z=O(P)){let Q=Date.now()-V*24*60*60*1000,te=[],ne=new Set,ce=0,ye,he,be,xe;if(z)B(P,z);let Ie={count:0},Xe=z?Yt(z,Ie):[];for(let Re of Xe)for(let at of pn(Re,Ie)){if(at.decision==="allow")continue;let ct=new Date(at.ts).getTime();if(ct>=Q){if(ce++,ne.add(at.sessionId??hu(Re,".jsonl")),he===void 0||ct<=he)ye=at.ts,he=ct;if(xe===void 0||ct>xe)be=at.ts,xe=ct;vu(te,at,ct)}}let et=te.map((Re)=>({timestamp:Re.ts,command:Re.command,reason:Re.reason,relativeTime:Oi(new Date(Re.ts))}));return{totalBlocked:ce,sessionCount:ne.size,recentEntries:et,oldestEntry:ye,newestEntry:be,unreadable:Ie.count}}function vu(P,V,z){let Q=P.findIndex((te)=>z>new Date(te.ts).getTime());if(Q===-1){if(P.length<3)P.push(V);return}if(P.splice(Q,0,V),P.length>3)P.pop()}import{dirname as Au}from"node:path";import{dirname as bu,join as Lu,resolve as wu}from"node:path";var ku="config.json";function Rt(P,V,z,Q){g(xu(P),`${JSON.stringify(V,null,2)}
|
|
5
|
+
`,z,Q)}function xu(P){return typeof P==="string"?re(P):P}function ro(P){return{errors:ie(Su(P),": "," "),ruleNames:new Set(_e(P).map((V)=>V.toLowerCase()))}}var Cu="must match pattern (letters, numbers, hyphens, underscores; max 64 chars)",Qi="must match pattern (letters, numbers, hyphens, underscores)";function Su(P){if(!es(P))return[e([],"Config must be an object")];return[...P.version===1?[]:[e(["version"],"must be 1")],...Ru(P.rules)]}function Ru(P){if(P===void 0)return[];if(!Array.isArray(P))return[e(["rules"],"must be an array")];return[...P.flatMap((V,z)=>es(V)?Pu(V,["rules",z]):[e(["rules",z],"must be an object")]),...Te(P)]}function Pu(P,V){return[...no(P.name,[...V,"name"],"required string",l,Cu),...no(P.command,[...V,"command"],"required string",w,Qi),...P.subcommand===void 0?[]:no(P.subcommand,[...V,"subcommand"],"must be a string if provided",w,Qi),...Eu(P.block_args,[...V,"block_args"]),...Du(P.reason,[...V,"reason"]),...P.intent===void 0||Ce(P.intent)?[]:[e([...V,"intent"],we)]]}function no(P,V,z,Q,te){if(typeof P!=="string")return[e(V,z)];return Q.test(P)?[]:[e(V,te)]}function Eu(P,V){if(!Array.isArray(P))return[e(V,"required array")];if(P.length===0)return[e(V,"must have at least one element")];return P.flatMap((z,Q)=>{if(typeof z!=="string")return[e([...V,Q],"must be a string")];return z===""?[e([...V,Q],"must not be empty")]:[]})}function Du(P,V){if(typeof P!=="string")return[e(V,"required string")];if(P==="")return[e(V,"must not be empty")];return P.length>T?[e(V,`must be at most ${T} characters`)]:[]}function es(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}function oo(P){let V=ts(P);if(!V.ok)return V.result;return ro(V.parsed)}function ts(P){let V=[],z=new Set;try{let Q=typeof P==="string"?re(P):P,te=n(Q);if(te===null)return V.push(`File not found: ${Q.path}`),{ok:!1,result:{errors:V,ruleNames:z}};if(!te.trim())return V.push("Config file is empty"),{ok:!1,result:{errors:V,ruleNames:z}};return{ok:!0,parsed:JSON.parse(te)}}catch(Q){if(Q instanceof r)return V.push(Q.message),{ok:!1,result:{errors:V,ruleNames:z}};let te=Q instanceof Error?Q.message:String(Q);return V.push(Q instanceof SyntaxError?"Invalid JSON":te),{ok:!1,result:{errors:V,ruleNames:z}}}}function ns(P){return wu(P,".safety-net.json")}function Jt(P){let V=ts(P);if(!V.ok)return V.result;let z=Ve(V.parsed);return{errors:z.errors,ruleNames:z.sources}}function nr(P,V={}){return Lu(bu(Se(P,V)),ku)}function rs(P,V,z){let Q;try{if(n(V)===null)return{path:P,exists:!1,valid:!1,ruleCount:0};Q=Jt(V),Q.errors.push(...j(P,z))}catch(te){if(!(te instanceof r))throw te;Q={errors:[te.message],ruleNames:new Set}}return{path:P,exists:!0,valid:Q.errors.length===0,ruleCount:Q.ruleNames.size,...Q.errors.length>0?{errors:Q.errors}:{}}}function _u(P,V){return{source:V,name:P.name,command:P.command,subcommand:P.subcommand,blockArgs:[...P.block_args],reason:P.reason}}function os(P,V){let z=M(P),Q=F(V),te=Au(z),ne=J(P,{cwd:V,userConfigPath:z,projectConfigPath:Q,userConfigDir:te}),ce=K(P,{cwd:V,userConfigPath:z,projectConfigPath:Q,userConfigDir:te}),ye=new Map(ne.rulebooks.flatMap((he)=>he.rules.map((be)=>[be,he.source])));return{userConfig:rs(z,ce.userConfigTarget,ce.userScope),projectConfig:rs(Q,ce.projectConfigTarget,ce.projectScope),effectiveRules:ne.rules.map((he)=>_u(he,ye.get(he.name)??"project"))}}var Tu=[{flag:o.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:o.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:o.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:o.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:o.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:o.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:o.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:o.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"}];function is(P){return[...Tu.map((V)=>({name:V.flag.name,value:ve(V.flag,P.env),isSet:Qe(V.flag,P.env),legacyName:V.flag.legacyName,legacyValue:V.flag.legacyName?P.env.get(V.flag.legacyName):void 0,legacyIsSet:V.flag.legacyName?P.env.get(V.flag.legacyName)!==void 0:void 0,description:V.description,defaultBehavior:V.defaultBehavior})),{name:"CC_SAFETY_NET_HOME",value:P.env.get("CC_SAFETY_NET_HOME"),isSet:P.env.get("CC_SAFETY_NET_HOME")!==void 0,description:"Override user-scope config/cache directory",defaultBehavior:"~/.cc-safety-net"}]}var ss={error:0,warning:1,info:2},$u=["policy","config","audit"];function Iu(P){return P.map((V)=>{if(V==="ownership")return"is not owned by the current user";if(V==="permissions")return"has unsafe permissions";if(V==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var Ou=[{derive:(P)=>P.hooks.length>0&&P.hooks.every((V)=>!V.configured)?[{checkId:"integration.none-configured",severity:"error",title:"No integration configured",detail:"CC Safety Net is not connected to any supported coding-agent integration.",fixHint:"Run `cc-safety-net install` and configure at least one integration."}]:[]},{derive:(P)=>P.hooks.filter((V)=>V.inspectionStatus==="failed").map((V)=>{let z=bt(V.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${z} inspection failed`,detail:`Doctor could not verify the ${z} integration configuration.`,fixHint:`Correct the reported ${z} configuration error, then run \`cc-safety-net doctor\` again.`,integration:V.platform}})},{derive:(P)=>P.userConfig.exists&&!P.userConfig.valid?[{checkId:"config.user-invalid",severity:"error",title:"User configuration is invalid",detail:"Doctor could not load a valid user rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:P.userConfig.path}]:[]},{derive:(P)=>P.projectConfig.exists&&!P.projectConfig.valid?[{checkId:"config.project-invalid",severity:"error",title:"Project configuration is invalid",detail:"Doctor could not load a valid project rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:P.projectConfig.path}]:[]},{derive:(P)=>P.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${P.configState.reason}`,fixHint:"Fix the file named in the reason, or run `cc-safety-net rule update` to vendor a remote source, then rerun doctor."}]:[]},{derive:(P)=>P.v2Leftovers&&P.v2Leftovers.length>0?[{checkId:"config.v2-leftovers",severity:"info",title:"Rulebook lock and cache leftovers detected",detail:`Files an earlier version left behind are no longer read: ${P.v2Leftovers.join(", ")}.`,fixHint:"Run `cc-safety-net rule sync` (add `--global` for user scope) to migrate them, then rerun doctor."}]:[]},{derive:(P)=>{let V=P.environment.find((z)=>z.name==="CC_SAFETY_NET_AUDIT_SCOPE");return He(V?.value)==="invalid"?[{checkId:"environment.audit-scope-invalid",severity:"warning",title:"Audit scope value is invalid",detail:"CC_SAFETY_NET_AUDIT_SCOPE is not `all` or `blocked`, so allowed command decisions are not recorded.",fixHint:"Set CC_SAFETY_NET_AUDIT_SCOPE to `all` or `blocked`, then restart the integration."}]:[]}},...$u.map((P)=>({derive:(V)=>V.posture.directories.filter((z)=>z.kind===P&&z.status==="unsafe").map((z)=>({checkId:`posture.${P}-directory-unsafe`,severity:"error",title:`${P[0]?.toUpperCase()}${P.slice(1)} directory is unsafe`,detail:`The ${P} directory ${Iu(z.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...z.path?{path:z.path}:{}}))})),{derive:(P)=>{let V=[...P.effectiveSafety.weakenedRuleOverrides].sort();return V.length>0?[{checkId:"posture.rule-overrides-weaken-preset",severity:"warning",title:"Rule overrides weaken the selected preset",detail:`Explicit overrides disable rules the resolved preset would enable: ${V.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${V.join(", ")}.`}]:[]}}];function as(P){return Ou.flatMap((V,z)=>V.derive(P).map((Q,te)=>({finding:Q,catalogOrder:z,occurrence:te}))).sort((V,z)=>ss[V.finding.severity]-ss[z.finding.severity]||V.catalogOrder-z.catalogOrder||V.occurrence-z.occurrence).map((V)=>V.finding)}function Ut(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var Fu=(P)=>Ut()?`\x1B[32m${P}\x1B[0m`:P,ju=(P)=>Ut()?`\x1B[33m${P}\x1B[0m`:P,Nu=(P)=>Ut()?`\x1B[34m${P}\x1B[0m`:P,Mu=(P)=>Ut()?`\x1B[36m${P}\x1B[0m`:P,Hu=(P)=>Ut()?`\x1B[31m${P}\x1B[0m`:P,Uu=(P)=>Ut()?`\x1B[2m${P}\x1B[0m`:P,Gu=(P)=>Ut()?`\x1B[1m${P}\x1B[0m`:P,dt={green:Fu,yellow:ju,blue:Nu,cyan:Mu,red:Hu,dim:Uu,bold:Gu},Bu="\x1B[0m",qu=[39,82,198,226,208,51,196,46,201,214,93,154,220,27,49,190,200,33,129,227,45,160,63,118,123,202];function Vu(P){let V=P;return()=>(V=(V*1664525+1013904223)%4294967296,V/4294967296)}function zu(P){let V=[...qu],z=Vu(P);for(let Q=V.length-1;Q>0;Q--){let te=Math.floor(z()*(Q+1)),ne=V[Q];V[Q]=V[te],V[te]=ne}return V}function Ju(P,V=0){if(!Ut())return"";let z=zu(V);return`\x1B[38;5;${z[P%z.length]}m`}function ls(P,V,z=0){if(!Ut())return`"${P}"`;return`${Ju(V,z)}"${P}"${Bu}`}function rr(P){return P==="default"?"built-in default":`${P} policy`}var Wu=new RegExp("\x1B\\[[0-9;]*m","g"),io=(P)=>P.replace(Wu,"").length;function Zt(P){let V=(P.headers??P.rows[0]??[]).map((ce,ye)=>{let he=Math.max(...P.rows.map((be)=>io(be[ye]??"")));return Math.max(io(ce),he)}),z=(ce,ye)=>ce+" ".repeat(Math.max(0,ye-io(ce))),Q=(ce,ye)=>ye[0]+V.map((he)=>ce.repeat(he+2)).join(ye[1])+ye[2],te=(ce)=>`│ ${ce.map((ye,he)=>z(ye,V[he]??0)).join(" │ ")} │`,ne=P.headers?[` ${te(P.headers)}`,` ${Q("─",["├","┼","┤"])}`]:[];return[` ${Q("─",["┌","┬","┐"])}`,...ne,...P.rows.map((ce)=>` ${te(ce)}`),` ${Q("─",["└","┴","┘"])}`].join(`
|
|
6
|
+
`)}function cs(P){let V=[];V.push("Hook Integration"),V.push(Ku(P));let z=[],Q=[];for(let te of P){let ne=bt(te.platform);if(te.errors&&te.errors.length>0)for(let ce of te.errors)if(te.configured)z.push({platform:ne,message:ce});else Q.push({platform:ne,message:ce})}for(let te of z)V.push(` Warning (${te.platform}): ${te.message}`);for(let te of Q)V.push(dt.red(` Error (${te.platform}): ${te.message}`));return V.join(`
|
|
7
|
+
`)}function Ku(P){let V=["Platform","Discovery","Configuration","Inspection"],z=P.map((Q)=>{let te=bt(Q.platform);if(Q.inspectionStatus==="not-inspected"){let he=dt.dim("Not inspected");return[te,he,he,he]}let ne=Q.detected?dt.green("Detected"):Q.inspectionStatus==="failed"?dt.red("Unknown"):dt.dim("Not detected"),ce=Q.configured?dt.green("Configured"):Q.detected?dt.yellow("Not configured"):Q.inspectionStatus==="failed"?dt.red("Unknown"):dt.dim("Not applicable"),ye=Q.inspectionStatus==="verified"?dt.green("Verified"):Q.inspectionStatus==="failed"?dt.red("Failed"):dt.dim("Not applicable");return[te,ne,ce,ye]});return Zt({headers:V,rows:z})}function ds(P){let z=["Guard Engine Verification",` Synthetic self-test: ${P.failed>0?dt.red(`${P.passed}/${P.total} FAIL`):dt.green(`${P.passed}/${P.total} passed`)}`],Q=P.results.filter((te)=>!te.passed);if(Q.length>0){z.push(""),z.push(dt.red(" Failures:"));for(let te of Q)z.push(dt.red(` • ${te.description}`)),z.push(dt.red(` expected ${te.expected}, got ${te.actual}`))}return z.join(`
|
|
8
|
+
`)}function Yu(P){if(P.length===0)return" (no custom rules)";let V=["Source","Name","Command","Block Args"],z=P.map((Q)=>[Q.source,Q.name,Q.subcommand?`${Q.command} ${Q.subcommand}`:Q.command,Q.blockArgs.join(", ")]);return Zt({headers:V,rows:z})}function us(P){let V=[];if(V.push("Configuration"),V.push(Zu(P.userConfig,P.projectConfig)),V.push(""),P.effectiveRules.length>0)V.push(` Effective rules (${P.effectiveRules.length} total):`),V.push(Yu(P.effectiveRules));else V.push(" Effective rules: (none - using built-in rules only)");return V.join(`
|
|
9
|
+
`)}function Zu(P,V){let z=["Scope","Status"],Q=(ne)=>{if(!ne.exists)return dt.dim("N/A");if(!ne.valid)return dt.red(`Invalid (${ne.errors?.[0]??"unknown error"})`);return dt.green("Configured")},te=[["User",Q(P)],["Project",Q(V)]];return Zt({headers:z,rows:te})}function ps(P){let V=[];return V.push("Environment"),V.push(Xu(P)),V.join(`
|
|
10
|
+
`)}function fs(P){let V=P.effectiveSafety.policyScopes,z=["Effective Safety",` Selected preset: ${P.effectiveSafety.selectedPreset}${V?` (${rr(V.levelScope)})`:""}`,` Effective: ${P.effectiveSafety.level}`],Q=[["fail_closed","fail_closed"],["paranoid_rm","paranoid_rm"],["paranoid_interpreters","paranoid_interpreters"]];for(let[te,ne]of Q){let ce=P.effectiveSafety.capabilities[te],ye=ce.enabled?dt.green("ON"):dt.dim("OFF"),he=ce.sources.length>0?` (${ce.sources.join(", ")})`:"";z.push(` ${ne}: ${ye} via ${ce.source}${he}`)}if(V&&V.weakenings.length>0){z.push(" Project policy deltas:");for(let te of V.weakenings)z.push(` ${te}`)}z.push(` Stored rule customizations: ${P.effectiveSafety.ruleCounts.stored}`),z.push(` Effective rule customizations: ${P.effectiveSafety.ruleCounts.effective}`);for(let[te,ne]of Object.entries(P.effectiveSafety.ruleOverrides))z.push(` ${te}: ${ne}`);return z.join(`
|
|
11
|
+
`)}function ms(P){let V=["Findings"];if(P.length===0)return V.push(" No findings from inspected doctor facts."),V.join(`
|
|
12
|
+
`);for(let z of P){let Q=`[${z.severity.toUpperCase()}] ${z.checkId}: ${Ct(z.title)}`,te=z.severity==="error"?dt.red:z.severity==="warning"?dt.yellow:dt.blue;if(V.push(` ${te(Q)}`),V.push(` ${Ct(z.detail)}`),z.path)V.push(` Path: ${Ct(z.path)}`);if(z.fixHint)V.push(` Fix: ${Ct(z.fixHint)}`)}return V.join(`
|
|
13
|
+
`)}function Xu(P){let V=["Variable","Status","Legacy"],z=P.map((Q)=>{let te=Q.isSet?dt.green("✓"):dt.dim("✗"),ne=Q.legacyName&&Q.legacyIsSet?`${Q.legacyName} ${dt.green("✓")}`:Q.legacyName??"";return[Q.name,te,ne]});return Zt({headers:V,rows:z})}function gs(P){let V=[];if(P.totalBlocked===0)V.push("Recent Activity"),V.push(" No blocked commands in the last 7 days"),V.push(" Tip: This is normal for new installations");else V.push(`Recent Activity · last 7 days (${P.totalBlocked} blocked / ${P.sessionCount} sessions)`),V.push(Qu(P.recentEntries));if(P.unreadable>0)V.push(` Warning: ${P.unreadable} audit log ${P.unreadable===1?"source":"sources"} could not be read; this summary is incomplete`);return V.join(`
|
|
14
|
+
`)}function Qu(P){let V=["Time","Command"],z=P.map((Q)=>{let te=Ct(Q.command.replace(/\r\n|\r|\n/g," ↵ ").replace(/\t/g," ")),ne=te.length>40?`${te.slice(0,37)}...`:te;return[Q.relativeTime,ne]});return Zt({headers:V,rows:z})}function ys(P){let V=[];if(V.push("Update Check"),P.latestVersion===null&&!P.error)return V.push(or([["Status",dt.dim("Skipped")],["Installed",P.currentVersion]])),V.join(`
|
|
15
|
+
`);if(P.error)return V.push(or([["Status",`${dt.yellow("⚠")} Error`],["Installed",P.currentVersion],["Error",dt.dim(P.error)]])),V.join(`
|
|
16
|
+
`);if(P.updateAvailable)return V.push(or([["Status",`${dt.yellow("⚠")} Update Available`],["Current",P.currentVersion],["Latest",dt.green(P.latestVersion??"")]])),V.push(""),V.push(" Run: bunx cc-safety-net@latest doctor"),V.push(" Or: npx cc-safety-net@latest doctor"),V.join(`
|
|
17
|
+
`);return V.push(or([["Status",`${dt.green("✓")} Up to date`],["Version",P.currentVersion]])),V.join(`
|
|
18
|
+
`)}function or(P){return Zt({rows:P})}function hs(P){let V=[];return V.push("System Info"),V.push(ep(P)),V.join(`
|
|
19
|
+
`)}function ep(P){let V=["Component","Version"],z=(ne)=>{if(ne===null)return dt.dim("not found");return ne},te=[{label:"cc-safety-net",value:P.version},...Zn.map((ne)=>({label:bt(ne),value:P.versions[ne]??null})),{label:"Node.js",value:P.nodeVersion},{label:"npm",value:P.npmVersion},{label:"Bun",value:P.bunVersion},{label:"Platform",value:P.platform}].map((ne)=>[ne.label,z(ne.value)]);return Zt({headers:V,rows:te})}function vs(P){if(P.findings.length===0)return dt.green(`
|
|
20
|
+
No findings from inspected doctor facts.`);let V={error:P.findings.filter((ne)=>ne.severity==="error").length,warning:P.findings.filter((ne)=>ne.severity==="warning").length,info:P.findings.filter((ne)=>ne.severity==="info").length},z=["error","warning","info"].filter((ne)=>V[ne]>0).map((ne)=>`${V[ne]} ${ne}`),Q=P.findings.length===1?"finding":"findings",te=`
|
|
21
|
+
${P.findings.length} ${Q}: ${z.join(", ")}.`;if(V.error>0)return dt.red(te);if(V.warning>0)return dt.yellow(te);return dt.blue(te)}import{lstatSync as tp}from"node:fs";import{dirname as so}from"node:path";function ao(P,V){try{let z=tp(V);if(z.isSymbolicLink())return{kind:P,path:V,status:"unsafe",issues:["symlink"]};if(!z.isDirectory())return{kind:P,path:V,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:P,path:V,status:"unknown",issues:[]};let Q=[...z.uid!==process.getuid()?["ownership"]:[],...(z.mode&18)!==0?["permissions"]:[]];return{kind:P,path:V,status:Q.length>0?"unsafe":"safe",issues:Q}}catch(z){if(typeof z==="object"&&z!==null&&"code"in z&&z.code==="ENOENT")return{kind:P,path:V,status:"not-applicable",issues:[]};return{kind:P,path:V,status:"unknown",issues:[]}}}function bs(P,V){let z=O(P);return{directories:[ao("policy",so(so(V))),ao("config",so(V)),...z?[ao("audit",z)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as np}from"node:child_process";import{existsSync as Ls}from"node:fs";import{delimiter as rp,extname as op,join as ip}from"node:path";import{stripVTControlCharacters as ws}from"node:util";var xs="2.4.4",sp=5000,ap="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function wt(){return xs}function lo(P,V){let z=P[V];if(z)return z;let Q=Object.keys(P).find((te)=>te.toLowerCase()===V.toLowerCase()&&!!P[te]);return Q?P[Q]:z}function lp(P){return(lo(P,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((V)=>V.length>0)}function cp(P,V){let z=op(P)?[P]:[...lp(V).map((Q)=>`${P}${Q}`),P];if(P.includes("/")||P.includes("\\"))return z.find((Q)=>Ls(Q))??P;return(lo(V,"PATH")??"").split(rp).flatMap((Q)=>z.map((te)=>ip(Q,te))).find((Q)=>Ls(Q))??P}function ks(P){if(!/[\s"&|<>^]/.test(P))return P;return`"${P.replace(/"/g,'""')}"`}function Xt(P,V){let[z,...Q]=P,te=V[ap]==="win32"?"win32":process.platform;if(!z||te!=="win32")return{cmd:z??"",args:Q};let ne=cp(z,V);if(!/\.(?:bat|cmd)$/i.test(ne))return{cmd:ne,args:Q};return{cmd:lo(V,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",ks(ne),...Q.map(ks)].join(" ")]}}var mn=async(P,V=sp)=>{let z=await dp(P,{timeoutMs:V});if(z.code!==0)return null;return ws(z.stdout).trim()||ws(z.stderr).trim()||null};function dp(P,V){let[z,...Q]=P;if(!z)return Promise.resolve({code:null,stdout:"",stderr:""});return new Promise((te)=>{try{let ne=Xt([z,...Q],process.env),ce=np(ne.cmd,ne.args,{stdio:["ignore","pipe","pipe"]}),ye=!1,he="",be="";ce.stdout.on("data",(Xe)=>{he+=Xe.toString()}),ce.stderr.on("data",(Xe)=>{be+=Xe.toString()});let xe=(Xe)=>{if(ye)return;ye=!0,clearTimeout(Ie),te(Xe)},Ie=setTimeout(()=>{ce.kill(),xe({code:null,stdout:he,stderr:be})},V.timeoutMs);ce.on("close",(Xe)=>{xe({code:Xe,stdout:he,stderr:be})}),ce.on("error",()=>{xe({code:null,stdout:he,stderr:be})})}catch{te({code:null,stdout:"",stderr:""})}})}function ir(P){if(!P)return null;let V=/Claude Code\s+(\d+\.\d+\.\d+)/i.exec(P);if(V)return V[1]??null;let z=/v?(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/i.exec(P);if(z)return z[1]??null;return P.split(`
|
|
22
|
+
`)[0]?.trim()||null}async function sr(P=mn){let[V,z,Q,te,ne,ce]=await Promise.all([Promise.all($t.map(async(ye)=>[ye.id,ir(await P([...ye.probeCommand]))])),P(["codex","plugin","list"],30000),P(["amp","plugins","list"],30000),P(["node","--version"]),P(["npm","--version"]),P(["bun","--version"])]);return{version:xs,versions:Object.fromEntries(V),codexPluginListOutput:z,ampPluginListOutput:Q,nodeVersion:ir(te),npmVersion:ir(ne),bunVersion:ir(ce),platform:`${process.platform} ${process.arch}`}}function co(P,V){if(V==="dev")return!1;let z=P.split(".").map(Number),Q=V.split(".").map(Number),[te=0,ne=0,ce=0]=z,[ye=0,he=0,be=0]=Q;if(te!==ye)return te>ye;if(ne!==he)return ne>he;return ce>be}async function Wt(){let P=wt(),V=new AbortController,z=setTimeout(()=>V.abort(),3000);try{let Q=await fetch("https://registry.npmjs.org/cc-safety-net/latest",{signal:V.signal});if(!Q.ok)return{currentVersion:P,latestVersion:null,updateAvailable:!1,error:`npm registry returned ${Q.status}`};let te=await Q.json(),ne=co(te.version,P);return{currentVersion:P,latestVersion:te.version,updateAvailable:ne}}catch(Q){return{currentVersion:P,latestVersion:null,updateAvailable:!1,error:Q instanceof Error?Q.message:"Network error"}}finally{clearTimeout(z)}}import*as _s from"node:readline";var Ps=(P)=>`\x1B[${P}B`,up=(P)=>`\x1B[${P}A`;var Cs=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function pp(P){return new Promise((V)=>setTimeout(V,P))}function fp(P,V,z){if(!z)return V(P);if(z.aborted)return Promise.resolve();return new Promise((Q,te)=>{let ne=()=>z.removeEventListener("abort",ce),ce=()=>{ne(),Q()};z.addEventListener("abort",ce,{once:!0}),V(P).then(()=>{ne(),Q()},(ye)=>{ne(),te(ye)})})}function ar(P){return Math.max(0,Math.min(1,P))}function gn(P){return Math.max(0,Math.min(255,Math.round(P)))}function uo(P){return P<=0.0031308?12.92*P:1.055*P**0.4166666666666667-0.055}function mp(P,V,z){let Q=z*Math.PI/180,te=V*Math.cos(Q),ne=V*Math.sin(Q),ce=(P+0.3963377774*te+0.2158037573*ne)**3,ye=(P-0.1055613458*te-0.0638541728*ne)**3,he=(P-0.0894841775*te-1.291485548*ne)**3;return{blue:gn(uo(ar(-0.0041960863*ce-0.7034186147*ye+1.707614701*he))*255),green:gn(uo(ar(-1.2684380046*ce+2.6097574011*ye-0.3413193965*he))*255),red:gn(uo(ar(4.0767416621*ce-3.3077115913*ye+0.2309699292*he))*255)}}function po(P,V){let z=(V*P*180/Math.PI%360+360)%360;return mp(0.72,0.15,z)}function Es(P,V=0.1){let z=po(V,P);return`\x1B[38;2;${z.red};${z.green};${z.blue}m`}function gp(P,V){return{blue:gn(P.blue+(255-P.blue)*V),green:gn(P.green+(255-P.green)*V),red:gn(P.red+(255-P.red)*V)}}function Ds(P,V,z){let Q=Math.imul(P+2654435769,2246822507)^Math.imul(V+3266489909,668265263)^Math.imul(z+374761393,2654435761),te=Q^Q>>>15,ne=Math.imul(te,739982445),ce=ne^ne>>>12,ye=Math.imul(ce,695872825);return((ye^ye>>>15)>>>0)/4294967296}function yp(P,V,z){let Q=Math.floor(Ds(P,V,z)*Cs.length);return Cs[Q]??"░"}function Ss(P){let V=ar(P);return V*V*V*(V*(V*6-15)+10)}function hp(P){if(P.length===0)return"";let V=[],z=!1,Q="";for(let te of P){let ne=`${te.red};${te.green};${te.blue}`;if(te.bold!==z)V.push(te.bold?"\x1B[1m":"\x1B[22m"),z=te.bold;if(ne!==Q)V.push(`\x1B[38;2;${ne}m`),Q=ne;V.push(te.character)}return`${V.join("")}\x1B[22m\x1B[39m`}function vp(P,V,z,Q,te){return P.map((ne,ce)=>({...po(z,Q+V+ce/te),bold:!1,character:ne}))}function bp(P,V,z,Q,te,ne,ce,ye){let he=Math.max(1,Q*0.75),be=Math.min(1,z/he),xe=te*Ss(be),Ie=Math.max(0,(z-he)/Math.max(1,Q-he)),Xe=(1-Ss(z/Q))*ye*2,et=0.35*Math.max(0,1-Ie*2),Re=be>=1,at=Math.min(P.length,Math.ceil(xe+2+1));return P.slice(0,at).map((ct,lt)=>{let pt=po(ne,ce+V+lt/ye+Xe),mt=lt+Ds(V,lt,7919)*2-1;if(mt>xe+2)return{...pt,bold:!1,character:" "};let gt=xe-mt,ut=0.8*Math.exp(-(gt*gt)/12.5),vt=Math.min(0.9,ut+et),Dt=!Re&&mt>xe-4;return{...gp(pt,vt),bold:vt>0.3,character:Dt?yp(V,lt,z):ct}})}function Rs(P){return`\x1B[?2026h${P.map((V,z)=>`\x1B8${z>0?Ps(z):""}${hp(V)}`).join("")}\x1B[?2026l`}async function fo(P,V={}){if(!P)return;let z=V.output??process.stdout,Q=V.sleep??pp,te=V.seed??0,ne=P.split(`
|
|
23
|
+
`).map((xe)=>Array.from(xe)),ce=Math.max(...ne.map((xe)=>xe.length)),ye=12000*ne.filter((xe)=>xe.length>0).length/40,he=ce>0?Math.max(1,Math.ceil(ye/16.666666666666668)):0,be=he>0?ye/he:0;z.write(`\x1B[?25l${ne.length>1?`${`
|
|
24
|
+
`.repeat(ne.length-1)}${up(ne.length-1)}`:""}\x1B7`);try{for(let xe=1;xe<=he;xe+=1){if(V.signal?.aborted)break;z.write(Rs(ne.map((Ie,Xe)=>bp(Ie,Xe,xe,he,ce,0.1,te,3)))),await fp(be,Q,V.signal)}}finally{if(z.write(Rs(ne.map((xe,Ie)=>vp(xe,Ie,0.1,te,3)))),z.write("\x1B8"),ne.length>1)z.write(Ps(ne.length-1));z.write(`
|
|
25
|
+
\x1B[0m\x1B[?25h`)}}var As=["┏━┛┏━┛ ┏━┛┏━┃┏━┛┏━┛━┏┛┃ ┃ ┏━ ┏━┛━┏┛","┃ ┃ ━━┃┏━┃┏━┛┏━┛ ┃ ━┏┛ ┃ ┃┏━┛ ┃ ","━━┛━━┛ ━━┛┛ ┛┛ ━━┛ ┛ ┛ ┛ ┛━━┛ ┛ "].join(`
|
|
26
|
+
`);function Lp(P){return Boolean(P.isTTY)}async function Rn(P={}){let V=P.output??process.stdout;if(!Lp(V))return;let z=P.input??process.stdin,Q={output:V,seed:P.seed??Math.random()*8192,sleep:P.sleep};if(!z.isTTY||typeof z.setRawMode!=="function"){await fo(As,Q);return}let te=new AbortController,ne=z.readableFlowing===!0,ce=z.isRaw===!0,ye=!1,he=(be,xe)=>{if(xe.ctrl&&xe.name==="c")ye=!0;if(ye||xe.name==="return"||xe.name==="enter")te.abort()};_s.emitKeypressEvents(z),z.on("keypress",he),z.setRawMode(!0),z.resume();try{await fo(As,{...Q,signal:te.signal})}finally{if(z.off("keypress",he),z.setRawMode(ce),!ne)z.pause()}if(!ye)return;if(P.onInterrupt){P.onInterrupt();return}process.kill(process.pid,"SIGINT")}import{createHash as Sp}from"node:crypto";import{existsSync as Is}from"node:fs";import{dirname as lr,join as Os}from"node:path";import{dirname as Ts,join as wp,resolve as kp}from"node:path";var xp="rule.lock";function Cp(P){return wp(Ts(P),xp)}function $s(P={}){return kp(P.cwd??process.cwd(),".safety-net.json")}function Pt(P,V){let z=V.global?V.userConfigPath??M(P,V):V.projectConfigPath??F(V.cwd??process.cwd()),Q=V.global?Be(P,V):ze(z,V.cwd??process.cwd()),te=Cp(z);return{configDir:Ts(z),configPath:z,lockPath:te,filesystemScope:Q,configTarget:i(Q,z),lockTarget:i(Q,te)}}var Rp="`cc-safety-net rule sync` is deprecated: rulebooks are live files that need no synchronization. This run only migrates the lock and cache an earlier version left behind.",Pp="cache",Ep="rulebooks";function Fs(P,V={}){let z=Pt(P,V),Q=i(z.filesystemScope,Ns(z.configDir)),te=n(z.lockTarget);if(console.log(Rp),te===null&&!Is(Q.path))return console.log(`No v2 lock or cache leftovers found in ${lr(z.configDir)}; nothing to migrate.`),0;let ne=$p(te),ce=m(z.configTarget);if(!ce.config&&(n(z.configTarget)!==null||ne.size>0))return console.error(`Cannot migrate: the rules config in ${lr(z.configDir)} is missing or unreadable while v2 leftovers remain. Restore rule.json, then re-run rule sync.`),1;let ye=ce.config?.rules??[];for(let he of ye.flatMap((be)=>Dp(be,ne,z,Q,V.global===!0)))console.log(he);return N(z.lockTarget),tt(Q),console.log(`Removed the v2 lock and cache under ${lr(z.configDir)}.`),0}function js(P,V){return[...new Set([{cwd:V},{cwd:V,global:!0}].flatMap((z)=>{let Q=Pt(P,z);return[Q.lockPath,Ns(Q.configDir)]}))].filter((z)=>Is(z))}function Dp(P,V,z,Q,te){if(!S(P))return[];let ne=A(P).name,ce=i(z.filesystemScope,I(z.configDir,ne)),ye=n(ce);if(ye!==null&&Ap(ye,ne))return[];let he=V.get(P),be=he?_p(he,ne,Q.path,z.filesystemScope):null;if(be===null)return[`Could not migrate ${P} from the v2 cache. Run \`cc-safety-net rule update ${P}${te?" --global":""}\` to vendor it.`];if(g(ce,be),ye!==null)return[`Restored ${P} from the v2 cache over an invalid file.`];return[`Vendored ${P} from the v2 cache.`]}function Ap(P,V){let z=me(P);return!("problem"in z)&&z.rulebook.name===V}function _p(P,V,z,Q){let te=Os(z,Ep,`${Tp(P)}--${P.digest.replace("sha256:","").slice(0,12)}`,ue),ne=n(i(Q,te));if(ne===null||Fp(ne)!==P.digest)return null;let ce=me(ne);if("problem"in ce||ce.rulebook.name!==V)return null;return ne}function Ns(P){return Os(lr(P),Pp)}function Tp(P){return([P.owner,P.repo,P.display_ref,P.name].every((Q)=>typeof Q==="string"&&Q!=="")?`${P.owner}/${P.repo}#${P.display_ref}/${P.name}`:P.spec).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"rulebook"}function $p(P){let V=P===null?null:Op(P),z=Ms(V)&&Array.isArray(V.rulebooks)?V.rulebooks:[];return new Map(z.filter(Ip).map((Q)=>[Q.spec,Q]))}function Ip(P){return Ms(P)&&typeof P.spec==="string"&&typeof P.digest==="string"}function Ms(P){return!!P&&typeof P==="object"}function Op(P){try{return JSON.parse(P)}catch{return null}}function Fp(P){return`sha256:${Sp("sha256").update(P).digest("hex")}`}var Hs="\r\x1B[2K",jp="\x1B[?25l",Np="\x1B[39m",Mp="\x1B[?25h",Hp=100,Up=0.55,Gp=80,Us=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function Bp(P){return new Promise((V)=>setTimeout(V,P))}async function cr(P,V={}){let z=V.output??process.stdout;if(!z.isTTY)return P;let Q=V.sleep??Bp,te=!1,ne=P.then((ye)=>(te=!0,ye),(ye)=>{throw te=!0,ye});if(await Promise.race([ne.then(()=>!0),Q(Hp).then(()=>!1)]))return ne;z.write(jp);try{for(let ye=0;!te;ye+=1)z.write(`${Hs}${Es(ye*Up)}${Us[ye%Us.length]}${Np} ${V.loadingMessage??"Loading…"}`),await Promise.race([ne,Q(Gp)]);return await ne}finally{z.write(`${Hs}${Mp}`)}}async function Pn(P,V,z,Q={}){let te=V();if(P)await z();if(P&&te.ready)await cr(te.ready,Q);return te.finish()}import{stripVTControlCharacters as qp}from"node:util";var dr="amp plugins list",Vp=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function Gs(P){if(!P.ampPluginListOutput)return{platform:"amp",status:"n/a"};let V=qp(P.ampPluginListOutput).split(`
|
|
27
|
+
`).map((z)=>Vp.exec(z)?.[1]).find((z)=>z!==void 0);if(!V)return{platform:"amp",status:"n/a"};if(V!=="active")return{platform:"amp",status:"disabled",method:dr,configPath:dr,errors:[`Amp personal plugin cc-safety-net is ${V}; run "plugins: reload" in Amp or reinstall with install --amp`]};return{platform:"amp",status:"configured",method:dr,configPath:dr}}import{existsSync as Wp,readFileSync as Kp}from"node:fs";import{isAbsolute as Y1,join as Jp,relative as Z1}from"node:path";function En(P){return Jp(P,".gemini","config","hooks.json")}var Yp=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function Zp(P){if(!P||typeof P!=="object"||Array.isArray(P))return[];return Object.values(P).flatMap((V)=>{if(!V||typeof V!=="object"||Array.isArray(V))return[];let z=V,Q=z.PreToolUse;if(!Array.isArray(Q))return[];return Q.flatMap((te)=>{if(!te||typeof te!=="object"||Array.isArray(te))return[];let ne=te.hooks;if(!Array.isArray(ne))return[];return ne.flatMap((ce)=>{if(!ce||typeof ce!=="object"||Array.isArray(ce))return[];let ye=ce.command;if(typeof ye!=="string"||!Yp.test(ye))return[];return[{command:ye,enabled:z.enabled!==!1}]})})})}function Bs(P){let V=En(P.environment.home);if(!Wp(V))return{platform:"antigravity-cli",status:"n/a",configPath:V};let z;try{z=Zp(JSON.parse(Kp(V,"utf-8")))}catch(Q){return{platform:"antigravity-cli",status:"n/a",configPath:V,errors:[`Failed to parse Antigravity hooks config ${V}: ${Q instanceof Error?Q.message:String(Q)}`]}}if(z.some((Q)=>Q.enabled))return{platform:"antigravity-cli",status:"configured",method:"hook config",configPath:V};if(z.length>0)return{platform:"antigravity-cli",status:"disabled",method:"hook config",configPath:V};return{platform:"antigravity-cli",status:"n/a",configPath:V}}import{join as qs}from"node:path";import{existsSync as Xp,lstatSync as Qp,readFileSync as e2}from"node:fs";function Ft(P,V=(z)=>z){if(!Xp(P))return{kind:"missing"};try{return{kind:"ok",value:JSON.parse(V(e2(P,"utf-8")))}}catch{return{kind:"unreadable"}}}function Lt(P){try{return Qp(P)}catch{return}}function ur(P,V){let z=Lt(V);if(!z)return{platform:P,status:"n/a",configPath:V};if(!z.isSymbolicLink()&&z.isDirectory())return;return{platform:P,status:"n/a",configPath:V,errors:[`${V} is a symlink or not a directory; move or remove it before installing`]}}function ft(P,V){return typeof P==="object"&&P!==null?P[V]:void 0}var mo="cc-safety-net@cc-marketplace";function Vs(P){return qs(P.home,".claude","plugins","installed_plugins.json")}function zs(P,V){let z=ft(ft(P,"plugins"),V);return Array.isArray(z)&&z.length>0}function pr(P,V){let z=Ft(Vs(P));return z.kind==="ok"&&zs(z.value,V)}function go(P){let V=Vs(P),z=Ft(V);if(z.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(z.kind==="missing")return{platform:"claude-code",status:"n/a"};if(!zs(z.value,mo))return{platform:"claude-code",status:"n/a"};let Q=qs(P.home,".claude","settings.json"),te=Ft(Q);if(te.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(!(te.kind==="ok"&&ft(ft(te.value,"enabledPlugins"),mo)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:Q,errors:[`${mo} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:V}}function Js(P){return go(P.environment)}function Ws(P){if(!P.codexPluginListOutput)return{platform:"codex",status:"n/a"};let V=P.codexPluginListOutput.split(`
|
|
28
|
+
`).find((z)=>z.includes("https://github.com/kenryu42/cc-safety-net.git"));if(!V)return{platform:"codex",status:"n/a"};if(!V.includes("installed,"))return{platform:"codex",status:"n/a"};if(!V.includes("installed, enabled"))return{platform:"codex",status:"disabled",method:"codex plugin list",configPath:"codex plugin list",errors:["Codex plugin line for https://github.com/kenryu42/cc-safety-net.git must contain installed, enabled."]};return{platform:"codex",status:"configured",method:"codex plugin list",configPath:"codex plugin list"}}import{existsSync as hr,readdirSync as t2,readFileSync as n2}from"node:fs";import{join as St}from"node:path";function At(P){let V="",z=0,Q=!1,te=!1,ne=-1;while(z<P.length){let ce=P[z],ye=P[z+1];if(te){V+=ce,te=!1,z++;continue}if(ce==='"'&&!Q){Q=!0,ne=-1,V+=ce,z++;continue}if(ce==='"'&&Q){Q=!1,V+=ce,z++;continue}if(ce==="\\"&&Q){te=!0,V+=ce,z++;continue}if(Q){V+=ce,z++;continue}if(ce==="/"&&ye==="/"){while(z<P.length&&P[z]!==`
|
|
29
|
+
`)z++;continue}if(ce==="/"&&ye==="*"){z+=2;while(z<P.length-1){if(P[z]==="*"&&P[z+1]==="/"){z+=2;break}z++}continue}if(ce===","){ne=V.length,V+=ce,z++;continue}if(ce==="}"||ce==="]"){if(ne!==-1){let he=V.slice(ne+1);if(/^\s*$/.test(he))V=V.slice(0,ne)+he}ne=-1,V+=ce,z++;continue}if(!/\s/.test(ce))ne=-1;V+=ce,z++}return V}function Ys(P,V,z){let Q=V+1,te=!1;while(Q<P.length){if(te){te=!1,Q++;continue}if(P[Q]==="\\"){te=!0,Q++;continue}if(P[Q]==='"')return Q+1;Q++}throw Error(z)}function ho(P,V,z){let Q=P[V],te=Q==="["?"]":"}",ne=0,ce=V;while(ce<P.length){let ye=z.skipComment?.(P,ce)??ce;if(ye!==ce){ce=ye;continue}if(P[ce]==='"'){ce=Ys(P,ce,z.stringError);continue}if(P[ce]===Q)ne++;if(P[ce]===te){if(ne--,ne===0)return ce}ce++}throw Error(z.bracketError)}function Zs(P,V){let z=P.lastIndexOf(`
|
|
30
|
+
`,V)+1;return/^[ \t]*/.exec(P.slice(z))?.[0]??""}function fr(P,V){let z=V.end+(/^\s*/.exec(P.slice(V.end))?.[0].length??0);if(P[z]===","){let ce=P[z+1]===`
|
|
31
|
+
`?z+2:z+1;return`${P.slice(0,V.start)}${P.slice(ce)}`}let Q=P.slice(0,V.start).search(/\s*$/)-1;if(P[Q]!==",")return`${P.slice(0,V.start)}${P.slice(V.end)}`;let te=P.lastIndexOf(`
|
|
32
|
+
`,Q-1),ne=te!==-1&&/^\s*$/.test(P.slice(te+1,Q))?te:Q;return`${P.slice(0,ne)}${P.slice(V.end)}`}function yo(P,V){if(P.startsWith("//",V)){let z=P.indexOf(`
|
|
33
|
+
`,V+2);return z===-1?P.length:z+1}if(P.startsWith("/*",V)){let z=P.indexOf("*/",V+2);return z===-1?P.length:z+2}return V}function Ks(P,V){let z=V;while(z<P.length){if(/\s/.test(P[z]??"")){z++;continue}let Q=yo(P,z);if(Q===z)return z;z=Q}return z}function Xs(P,V,z){let Q=0,te=0;while(te<P.length){let ne=yo(P,te);if(ne!==te){te=ne;continue}if(P[te]==='"'){let ce=Ys(P,te,z.stringError);if(Q===1&&JSON.parse(P.slice(te,ce))===V){let ye=Ks(P,ce),he=Ks(P,ye+1);if(P[ye]===":"&&P[he]==="[")return{start:he,end:ho(P,he,{skipComment:yo,...z})}}te=ce;continue}if(P[te]==="{"||P[te]==="[")Q++;if(P[te]==="}"||P[te]==="]")Q--;te++}return}var jt="cc-safety-net@cc-marketplace",mr=["cc-marketplace","cc-safety-net"],Qs=["_direct","copilot-safety-net"],ea=["cc-marketplace","safety-net"],ta="safety-net@cc-marketplace";function gr(P,V){let z=V.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(^|[^a-z0-9-])${z}([^a-z0-9-]|$)`,"m").test(P??"")}function na(P){return gr(P,"cc-safety-net@cc-marketplace")}function ra(P){return gr(P,"cc-marketplace")}function oa(P){return gr(P,"copilot-safety-net")}function ia(P){return gr(P,"safety-net@cc-marketplace")}function vo(P){if(!P?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(P)}function aa(P,V){if(!P)return null;let z=P.match(/(\d+)\.(\d+)\.(\d+)/);if(!z)return null;let Q=[Number(z[1]),Number(z[2]),Number(z[3])];for(let te=0;te<V.length;te++){let ne=Q[te]??0,ce=V[te]??0;if(ne!==ce)return ne>ce}return!0}function r2(P){return aa(P,[0,0,422])}function o2(P){return aa(P,[1,0,8])}function Dn(P){return P.env.get("COPILOT_HOME")||St(P.home,".copilot")}function bo(P){return(P.hooks?.preToolUse??[]).some((z)=>{if(z.type!=="command")return!1;return vo(z.command)||vo(z.bash)||vo(z.powershell)})}function yr(P){return P===void 0||typeof P==="string"}function i2(P){if(!P||typeof P!=="object"||Array.isArray(P))return!1;let V=P;if(V.disableAllHooks!==void 0&&typeof V.disableAllHooks!=="boolean")return!1;if(V.hooks===void 0)return!0;if(!V.hooks||typeof V.hooks!=="object"||Array.isArray(V.hooks))return!1;let z=V.hooks.preToolUse;if(z===void 0)return!0;return Array.isArray(z)&&z.every((Q)=>Q!==null&&typeof Q==="object"&&!Array.isArray(Q)&&yr(Q.type)&&yr(Q.command)&&yr(Q.bash)&&yr(Q.powershell))}function Lo(P,V){try{let z=JSON.parse(At(n2(P,"utf-8")));if(!i2(z)){V?.push(`Invalid hook config ${P}: hooks.preToolUse must be an array of hook objects`);return}return z}catch(z){V?.push(`Failed to parse ${P}: ${z instanceof Error?z.message:String(z)}`);return}}function la(P,V){try{return t2(P).filter((z)=>z.endsWith(".json")).sort((z,Q)=>z.localeCompare(Q))}catch(z){return V?.push(`Failed to read ${P}: ${z instanceof Error?z.message:String(z)}`),[]}}function s2(P,V){if(!hr(P))return[];let z=[];for(let Q of la(P,V)){let te=St(P,Q),ne=Lo(te,V);if(ne&&bo(ne))z.push(te)}return z}function yn(P,V){if(!hr(P))return;let z=Lo(P,V);if(!z)return;return{path:P,config:z}}function sa(P,V,z,Q){if(V){P.push(`GitHub Copilot CLI ${V} does not support ${z}; requires ${Q}+`);return}P.push(`GitHub Copilot CLI version unavailable; skipping ${z} because it requires ${Q}+`)}function a2(P){for(let V of P){if(V?.config.disableAllHooks===!0)return V.path;if(V?.config.disableAllHooks===!1)return}return}function l2(P,V,z,Q){let te=Dn(P),ne=St(V,".github","hooks"),ce=St(te,"hooks"),ye=St(V,".github","copilot"),he=St(V,".claude"),be=o2(z),xe=be===!0?Q:void 0,Ie=[yn(St(ye,"settings.local.json"),xe),yn(St(ye,"settings.json"),xe),yn(St(he,"settings.local.json"),xe),yn(St(he,"settings.json"),xe)],Xe=[yn(St(te,"settings.json"),xe),yn(St(te,"config.json"),xe)];if(be!==!1){let gt=a2([...Ie,...Xe]);if(gt){if(be===null)Q.push(`GitHub Copilot CLI version unavailable; treating disableAllHooks in ${gt} as active`);return{activeConfigPaths:[],disabledBy:gt}}}let et=s2(ne,Q),Re=r2(z),at=Re===!0?Q:void 0,ct=hr(ce)?la(ce,at):[],lt=[];for(let gt of ct){let ut=St(ce,gt),vt=Lo(ut,at);if(vt&&bo(vt))lt.push(ut)}if(Re!==!0&<.length>0)sa(Q,z,`user hook files in ${ce}`,"0.0.422"),lt.length=0;let pt=[];for(let gt of[...Ie,...Xe]){if(!gt)continue;if(!bo(gt.config))continue;if(be===!0){pt.push(gt);continue}sa(Q,z,"inline hook definitions in Copilot config files","1.0.8");break}let mt=(gt)=>gt.filter((ut)=>!!ut&&pt.includes(ut)).map((ut)=>ut.path);return{activeConfigPaths:[...mt(Ie),...et,...mt(Xe),...lt]}}function ca(P){let V=[],z=l2(P.environment,P.cwd,P.copilotCliVersion,V);if(z.disabledBy)return{platform:"copilot-cli",status:"disabled",method:"hook config",configPath:z.disabledBy,configPaths:[z.disabledBy],errors:V.length>0?V:void 0};let Q=Dn(P.environment),te=St(Q,"installed-plugins",...mr),ne=hr(te),ce=St(Q,"settings.json"),ye=Ft(ce,At);if(ne&&ye.kind==="unreadable")return{platform:"copilot-cli",status:"not-inspected"};if(ne&&ye.kind==="ok"&&ft(ft(ye.value,"enabledPlugins"),jt)===!1)return{platform:"copilot-cli",status:"disabled",method:"plugin config",configPath:ce,errors:[`${jt} is installed but not enabled in Copilot CLI`]};if(ne||z.activeConfigPaths.length>0){let he=ne,be=z.activeConfigPaths[0];return{platform:"copilot-cli",status:"configured",method:he?"plugin config":"hook config",configPath:be??(he?te:void 0),configPaths:z.activeConfigPaths.length>0?z.activeConfigPaths:void 0,errors:V.length>0?V:void 0}}return{platform:"copilot-cli",status:"n/a",errors:V.length>0?V:void 0}}import{existsSync as v2,readFileSync as b2}from"node:fs";import{existsSync as da,mkdirSync as u2,readFileSync as p2}from"node:fs";import{dirname as f2,join as m2}from"node:path";import{renameSync as c2,writeFileSync as d2}from"node:fs";function kt(P,V){let z=`${P}.${process.pid}.tmp`;d2(z,V),c2(z,P)}var Nt=Object.fromEntries(Sn.map((P)=>[P.id,`npx -y cc-safety-net hook ${P.flags[1]}`]));var An=Nt.cursor,ua=30;function br(P){return m2(P.home,".cursor","hooks.json")}function Qt(P){return typeof P==="object"&&P!==null&&!Array.isArray(P)}function wo(){return{command:An,timeout:ua,failClosed:!0}}function vr(P){return Qt(P)&&P.command===An}function g2(P){return Object.keys(P).length===3&&P.command===An&&P.timeout===ua&&P.failClosed===!0}function y2(P){try{return JSON.parse(p2(P,"utf-8"))}catch(V){if(V instanceof SyntaxError)throw Error(`Failed to parse Cursor hooks config ${P}: ${V.message}`);throw V}}function pa(P){let V=y2(P);if(!Qt(V))throw Error(`Cursor hooks config ${P} must be a JSON object`);if(V.version!==1)throw Error(`Cursor hooks config ${P} must set "version": 1`);if(V.hooks!==void 0&&!Qt(V.hooks))throw Error(`Cursor hooks config ${P} "hooks" must be an object`);let z=Qt(V.hooks)?V.hooks.preToolUse:void 0;if(z!==void 0&&!Array.isArray(z))throw Error(`Cursor hooks config ${P} "hooks.preToolUse" must be an array`);return V}function fa(P){let V=Qt(P.hooks)?P.hooks.preToolUse:void 0;return Array.isArray(V)?V:[]}function h2(P){if(!P.some(vr))return[...P,wo()];return P.reduce((V,z)=>{if(!vr(z))return V.result.push(z),V;if(!V.inserted)V.result.push(wo()),V.inserted=!0;return V},{result:[],inserted:!1}).result}function ma(P,V,z){let Q=Qt(V.hooks)?V.hooks:{},te={...V,hooks:{...Q,preToolUse:z}};kt(P,`${JSON.stringify(te,null,2)}
|
|
34
|
+
`)}function ga(P){let V=br(P);if(!da(V))return u2(f2(V),{recursive:!0}),kt(V,`${JSON.stringify({version:1,hooks:{preToolUse:[wo()]}},null,2)}
|
|
35
|
+
`),{path:V,alreadyInstalled:!1};let z=pa(V),Q=fa(z),te=Q.filter(vr);if(Qt(z.hooks)&&Array.isArray(z.hooks.preToolUse)&&te.length===1&&te[0]!==void 0&&g2(te[0]))return{path:V,alreadyInstalled:!0};return ma(V,z,h2(Q)),{path:V,alreadyInstalled:!1}}function ya(P){let V=br(P);if(!da(V))return{path:V,alreadyInstalled:!1};let z=pa(V),Q=fa(z),te=Q.filter((ne)=>!vr(ne));if(te.length===Q.length)return{path:V,alreadyInstalled:!1};return ma(V,z,te),{path:V,alreadyInstalled:!0}}function L2(P){if(!P||typeof P!=="object"||Array.isArray(P))return[];let V=P.hooks;if(!V||typeof V!=="object"||Array.isArray(V))return[];let z=V.preToolUse;if(!Array.isArray(z))return[];return z.filter((Q)=>!!Q&&typeof Q==="object"&&!Array.isArray(Q)&&Q.command===An)}function w2(P){let V=[];if(P.length>1)V.push("Multiple managed cc-safety-net hooks found; reinstall to collapse duplicates");let z=P[0];if(z&&z.failClosed!==!0)V.push('Managed hook is missing "failClosed": true; reinstall to repair');if(z&&z.timeout!==30)V.push('Managed hook "timeout" is not 30; reinstall to repair');return V}function ha(P){let V=br(P.environment);if(!v2(V))return{platform:"cursor",status:"n/a",configPath:V};let z;try{z=JSON.parse(b2(V,"utf-8"))}catch(ne){return{platform:"cursor",status:"n/a",configPath:V,errors:[`Failed to parse Cursor hooks config ${V}: ${ne instanceof Error?ne.message:String(ne)}`]}}let Q=L2(z);if(Q.length===0)return{platform:"cursor",status:"n/a",configPath:V};let te=w2(Q);return{platform:"cursor",status:"configured",method:"hook config",configPath:V,errors:te.length>0?te:void 0}}import{existsSync as k2}from"node:fs";import{join as ko}from"node:path";var xo="gemini-safety-net";function Co(P){let V=ko(P.home,".gemini","extensions"),z=ko(V,xo);if(!k2(z))return{platform:"gemini-cli",status:"n/a"};let Q=ko(V,"extension-enablement.json"),te=Ft(Q);if(te.kind==="unreadable")return{platform:"gemini-cli",status:"not-inspected"};let ne=te.kind==="ok"?ft(ft(te.value,xo),"overrides"):void 0;if(Array.isArray(ne)&&ne.some((ye)=>typeof ye==="string"&&ye.startsWith("!")))return{platform:"gemini-cli",status:"disabled",method:"extension config",configPath:Q,errors:[`${xo} is disabled in Gemini CLI`]};return{platform:"gemini-cli",status:"configured",method:"extension config",configPath:z}}function va(P){return Co(P.environment)}import{existsSync as R2,readFileSync as P2}from"node:fs";import{existsSync as La,mkdirSync as x2,readFileSync as wa,rmSync as C2}from"node:fs";import{dirname as S2,join as ba}from"node:path";var _n=Nt["grok-build"],kr=30;function xr(P){return ba(P.env.get("GROK_HOME")??ba(P.home,".grok"),"hooks","cc-safety-net.json")}function en(P){return typeof P==="object"&&P!==null&&!Array.isArray(P)}function Lr(){return{hooks:[{type:"command",command:_n,timeout:kr}]}}function ka(P){return en(P)&&P.command===_n}function xa(P){return P.flatMap((V)=>{if(!en(V)||!Array.isArray(V.hooks))return[V];let z=V.hooks.filter((Q)=>!ka(Q));if(z.length===V.hooks.length)return[V];return z.length===0?[]:[{...V,hooks:z}]})}function Ca(P){try{let V=JSON.parse(P);return en(V)?V:null}catch{return null}}function Sa(P){let V=en(P.hooks)?P.hooks.PreToolUse:void 0;return Array.isArray(V)?V:[]}function wr(P,V,z){let Q=en(V.hooks)?V.hooks:{};kt(P,`${JSON.stringify({...V,hooks:{...Q,PreToolUse:z}},null,2)}
|
|
36
|
+
`)}function Ra(P){let V=xr(P);if(!La(V))return x2(S2(V),{recursive:!0}),wr(V,{},[Lr()]),{path:V,alreadyInstalled:!1};let z=Ca(wa(V,"utf-8"));if(!z)return wr(V,{},[Lr()]),{path:V,alreadyInstalled:!1};let Q=Sa(z),te=Q.filter((ne)=>en(ne)&&Array.isArray(ne.hooks)&&ne.hooks.some(ka));if(te.length===1&&JSON.stringify(te[0])===JSON.stringify(Lr()))return{path:V,alreadyInstalled:!0};return wr(V,z,[...xa(Q),Lr()]),{path:V,alreadyInstalled:!1}}function Pa(P){let V=xr(P);if(!La(V))return{path:V,alreadyInstalled:!1};let z=Ca(wa(V,"utf-8"));if(!z)return{path:V,alreadyInstalled:!1};let Q=Sa(z),te=xa(Q);if(JSON.stringify(te)===JSON.stringify(Q))return{path:V,alreadyInstalled:!1};let ne=en(z.hooks)?z.hooks:{};if(te.length===0&&Object.keys(z).length===1&&Object.keys(ne).length===1)return C2(V),{path:V,alreadyInstalled:!0};return wr(V,z,te),{path:V,alreadyInstalled:!0}}function Tn(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}function E2(P){if(!Tn(P)||!Tn(P.hooks))return[];let V=P.hooks.PreToolUse;if(!Array.isArray(V))return[];return V.filter((z)=>Tn(z)&&Array.isArray(z.hooks)&&z.hooks.some((Q)=>Tn(Q)&&Q.command===_n))}function D2(P){let z=(Array.isArray(P.hooks)?P.hooks.filter(Tn):[]).find((Q)=>Q.command===_n);return[...P.matcher===void 0||P.matcher===""||P.matcher==="*"?[]:['Managed hook has a "matcher" that narrows coverage; reinstall to repair'],...z?.type==="command"?[]:['Managed hook "type" is not "command"; reinstall to repair'],...z?.timeout===kr?[]:[`Managed hook "timeout" is not ${kr}; reinstall to repair`]]}function Ea(P){let V=xr(P.environment);if(!R2(V))return{platform:"grok-build",status:"n/a",configPath:V};let z;try{z=JSON.parse(P2(V,"utf-8"))}catch(ne){return{platform:"grok-build",status:"n/a",configPath:V,errors:[`Failed to parse Grok Build hooks config ${V}: ${ne instanceof Error?ne.message:String(ne)}`]}}let Q=E2(z)[0];if(!Q)return{platform:"grok-build",status:"n/a",configPath:V};let te=D2(Q);return{platform:"grok-build",status:"configured",method:"hook config",configPath:V,errors:te.length>0?te:void 0}}import{readFileSync as Fa}from"node:fs";import{join as ja}from"node:path";var Tt="cc-safety-net",So="# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent",A2=30;function Da(P){return`${So}
|
|
37
|
+
# version: ${P}
|
|
38
|
+
`}function _2(P){return`${Da(P)}name: ${Tt}
|
|
39
|
+
version: "${P}"
|
|
40
40
|
description: "Block destructive commands and secret-file access before Hermes runs a tool."
|
|
41
41
|
author: "cc-safety-net"
|
|
42
42
|
provides_hooks:
|
|
43
43
|
- pre_tool_call
|
|
44
|
-
`}function
|
|
44
|
+
`}function T2(P){return`${Da(P)}"""CC Safety Net guard for Hermes Agent.
|
|
45
45
|
|
|
46
46
|
Registers pre_tool_call and forwards the tool call to the packaged CC Safety Net
|
|
47
47
|
adapter (cc-safety-net hook --hermes-agent) over JSON stdin. The adapter prints nothing
|
|
@@ -58,8 +58,8 @@ import subprocess
|
|
|
58
58
|
|
|
59
59
|
HOOK_EVENT = "pre_tool_call"
|
|
60
60
|
SUPPORTED_TOOLS = ("patch", "read_file", "terminal", "write_file")
|
|
61
|
-
ANALYZER = [${
|
|
62
|
-
TIMEOUT_SECONDS = ${
|
|
61
|
+
ANALYZER = [${Nt["hermes-agent"].split(" ").map((V)=>`"${V}"`).join(", ")}]
|
|
62
|
+
TIMEOUT_SECONDS = ${A2}
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
def _block(detail):
|
|
@@ -203,83 +203,83 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
|
|
|
203
203
|
|
|
204
204
|
def register(ctx):
|
|
205
205
|
ctx.register_hook("pre_tool_call", _pre_tool_call)
|
|
206
|
-
`}function
|
|
207
|
-
`)}function
|
|
208
|
-
`),he=
|
|
209
|
-
${ye()}`.trim())))},he);
|
|
210
|
-
${ye()}`.trim())))}),
|
|
211
|
-
`));return{path:X??cf(A),alreadyInstalled:!1}}function il(A){let z=[],X=Er(A.environment),ee=["opencode.json","opencode.jsonc"];for(let te of ee){let ae=gf(X,te);if(ff(ae))try{let le=mf(ae,"utf-8"),ye=At(le);if((JSON.parse(ye).plugin??[]).some((Ie)=>Ie.includes("cc-safety-net")))return{platform:"opencode",status:"configured",method:"plugin array",configPath:ae,errors:z.length>0?z:void 0}}catch(le){z.push(`Failed to parse ${te}: ${le instanceof Error?le.message:String(le)}`)}}return{platform:"opencode",status:"n/a",errors:z.length>0?z:void 0}}import{join as yf}from"node:path";function Go(A){return yf(A.home,".pi","agent","settings.json")}function Bo(A){if(typeof A!=="string")return!1;return A==="npm:cc-safety-net"||A.startsWith("npm:cc-safety-net@")}function sl(A){let z=Go(A.environment),X=Ot(z);if(X.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(X.kind==="missing")return{platform:"pi",status:"n/a"};let ee=ft(X.value,"packages");if(!Array.isArray(ee))return{platform:"pi",status:"n/a"};let te=ee.find((ye)=>Bo(typeof ye==="string"?ye:ft(ye,"source")));if(te===void 0)return{platform:"pi",status:"n/a"};let ae=ft(te,"extensions");if(Array.isArray(ae)&&ae.some((ye)=>typeof ye==="string"&&ye.startsWith("-")))return{platform:"pi",status:"disabled",method:"package config",configPath:z,errors:["npm:cc-safety-net is installed but its extension is disabled in Pi settings"]};return{platform:"pi",status:"configured",method:"package config",configPath:z}}var hf={amp:Ms,"antigravity-cli":Hs,"claude-code":qs,codex:Vs,"copilot-cli":sa,cursor:ma,"gemini-cli":ga,"grok-build":Sa,"hermes-agent":Fa,"kimi-code":$n,openclaw:Ka,opencode:il,pi:sl};function bn(A,z,X){let ee={...X,cwd:z,environment:A};return Yn.map((te)=>vf(hf[te](ee)))}function vf(A){if(A.status==="not-inspected")return{platform:A.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:A.platform,detected:A.status!=="n/a",configured:A.status==="configured",inspectionStatus:A.status!=="n/a"?"verified":A.errors&&A.errors.length>0?"failed":"not-applicable",method:A.method,configPath:A.configPath,configPaths:A.configPaths,errors:A.errors}}import{join as bf}from"node:path";var Lf=Object.freeze([{command:"git reset --hard",description:"git reset --hard",expectBlocked:!0},{command:"rm -rf /",description:"rm -rf /",expectBlocked:!0},{command:"rm -rf ./node_modules",description:"rm in cwd (safe)",expectBlocked:!1}]),wf=Object.freeze({state:"ready",diagnostics:Object.freeze([]),ruleMetadata:Object.freeze({}),policy:Object.freeze({rules:Object.freeze([]),transparentWrappers:Object.freeze([]),safety:Object.freeze({}),worktreeMode:!1,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:Object.freeze({}),destructiveCommandAllowPaths:Object.freeze([]),secretProtection:Object.freeze({enabled:!0,disabledRules:Object.freeze([]),denyPaths:Object.freeze([]),allowPaths:Object.freeze([])})})}),kf={strict:!1,paranoidRm:!1,paranoidInterpreters:!1,worktreeMode:!1,effectiveLevel:"standard",capabilities:{fail_closed:{enabled:!1,source:"preset",sources:[]},paranoid_rm:{enabled:!1,source:"preset",sources:[]},paranoid_interpreters:{enabled:!1,source:"preset",sources:[]}}};function al(A){let z=bf(A.tmpdir,"cc-safety-net-self-test"),X=Lf.map((ee)=>{let te=O(A,u("self-test",{command:ee.command},{kind:"command",shell:"auto"},{configCwd:z,executionCwd:z},ee.command),{guard:{dependencies:{loadPolicySnapshot:()=>wf,getModes:()=>kf,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),ae=ee.expectBlocked?"blocked":"allowed",le=te.decision.kind==="deny"?"blocked":"allowed";return{command:ee.command,description:ee.description,expected:ae,actual:le,passed:ae===le,reason:te.decision.kind==="deny"?te.decision.reason:void 0,ruleId:te.decision.kind==="deny"?te.decision.ruleId:void 0}});return{passed:X.filter((ee)=>ee.passed).length,failed:X.filter((ee)=>!ee.passed).length,total:X.length,results:X}}function qo(A){let z=xt({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},A);if(Ht(z.errors))return null;return{json:z.flags.json,skipUpdateCheck:z.flags.skipUpdateCheck}}async function ll(A,z={}){let X=await Rn(!z.json,()=>{let ee=xf(A,z);return{ready:ee,finish:()=>ee}},()=>Sn(),{loadingMessage:"Checking system status…"});if(z.json)console.log(JSON.stringify(X,null,2));else Cf(X);return X.engineSelfTest.failed>0||X.findings.some((ee)=>ee.severity==="error")?1:0}async function xf(A,z){let X=z.cwd??process.cwd(),ee=await ir(),te=bn(A,X,{ampPluginListOutput:ee.ampPluginListOutput,codexPluginListOutput:ee.codexPluginListOutput,copilotCliVersion:ee.versions["copilot-cli"]}),ae=ts(A,X),le=ns(A),ye=L(A,{cwd:X}),he=ye.policy,ve=E(he,A.env),be=H(he,ve.capabilities),Ie=er(A,7),Xe=Is(A,X),et=z.skipUpdateCheck?{currentVersion:wt(),latestVersion:null,updateAvailable:!1}:await Wt(),Ee={hooks:te,engineSelfTest:al(A),userConfig:ae.userConfig,projectConfig:ae.projectConfig,configState:Ne(ye),effectiveRules:ae.effectiveRules,environment:le,effectiveSafety:{selectedPreset:he.safety.level??"standard",level:ve.effectiveLevel,capabilities:ve.capabilities,ruleOverrides:he.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(be).filter(([,at])=>at.source==="rule_override"&&at.override==="off"&&at.inheritedEnabled&&at.changesInherited).map(([at])=>at),ruleCounts:{stored:Object.keys(he.destructiveCommandRuleOverrides).length,effective:Object.values(be).filter((at)=>at.changesInherited).length},...ye.policyScopes?{policyScopes:ye.policyScopes}:{}},...Xe.length>0?{v2Leftovers:Xe}:{},posture:ys(A,ae.userConfig.path),activity:Ie,update:et,system:ee};return{...Ee,findings:os(Ee)}}function Cf(A){console.log(),console.log(ss(A.hooks)),console.log(),console.log(as(A.engineSelfTest)),console.log(),console.log(ls(A)),console.log(),console.log(cs(A.environment)),console.log(),console.log(ds(A)),console.log(),console.log(us(A.findings)),console.log(),console.log(ps(A.activity)),console.log(),console.log(ms(A.system)),console.log(),console.log(fs(A.update)),console.log(gs(A))}import{existsSync as Sf}from"node:fs";var Rf=/^[A-Za-z0-9_@%+=:,./-]+$/,cl="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function Vo(A){let z=xt({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},A);if(Ht(z.errors))return console.error(cl),console.error("Pass -- before a command that starts with dashes."),null;if(z.values.cwd!==void 0&&!Sf(z.values.cwd))return console.error(`Error: --cwd path does not exist: ${z.values.cwd}`),null;let X=z.positionals.length===1?z.positionals[0]:z.positionals.map((ee)=>Rf.test(ee)?ee:`'${ee.replaceAll("'","'\\''")}'`).join(" ");if(!X)return console.error("Error: No command provided"),console.error(cl),null;return{json:z.flags.json,cwd:z.values.cwd,command:X}}function dl(A){if(A)return{dh:"=",dv:"|",dtl:"+",dtr:"+",dbl:"+",dbr:"+",h:"-",v:"|",tl:"+",tr:"+",bl:"+",br:"+",sh:"="};return{dh:"═",dv:"║",dtl:"╔",dtr:"╗",dbl:"╚",dbr:"╝",h:"─",v:"│",tl:"┌",tr:"┐",bl:"└",br:"┘",sh:"━"}}function ul(A,z){let ee=z-18;return[`${A.dtl}${A.dh.repeat(z)}${A.dtr}`,`${A.dv} Command Analysis${" ".repeat(ee)}${A.dv}`,`${A.dbl}${A.dh.repeat(z)}${A.dbr}`]}function zo(A){return JSON.stringify(A)}function pl(A,z=0){return`[${A.map((ee,te)=>is(ee,te,z)).join(",")}]`}function Fn(A,z,X=70){let ee=A.split(" "),te=[],ae="";for(let le of ee)if(ae&&ae.length+le.length+1>X)te.push(ae),ae=le;else ae=ae?`${ae} ${le}`:le;if(ae)te.push(ae);return te.map((le,ye)=>ye===0?le:`${z}${le}`)}function fl(A,z,X){let ee=[];switch(A.type){case"parse":return null;case"env-strip":return ee.push(""),ee.push(`STEP ${z} ${X.h} Strip environment variables`),ee.push(` Removed: ${A.envVars.map((te)=>`${te}=<redacted>`).join(", ")}`),ee.push(` Tokens: ${zo(A.output)}`),{lines:ee,incrementStep:!0};case"leading-tokens-stripped":return ee.push(""),ee.push(`STEP ${z} ${X.h} Strip wrappers`),ee.push(` Removed: ${A.removed.join(", ")}`),ee.push(` Tokens: ${zo(A.output)}`),{lines:ee,incrementStep:!0};case"shell-wrapper":return ee.push(""),ee.push(`STEP ${z} ${X.h} Detect shell wrapper`),ee.push(` Wrapper: ${A.wrapper} -c`),ee.push(` Inner: ${A.innerCommand}`),{lines:ee,incrementStep:!0};case"interpreter":{if(ee.push(""),ee.push(`STEP ${z} ${X.h} Detect interpreter`),ee.push(` Interpreter: ${A.interpreter}`),ee.push(` Code: ${A.codeArg}`),A.paranoidBlocked)ee.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:ee,incrementStep:!0}}case"busybox":return ee.push(""),ee.push(`STEP ${z} ${X.h} Busybox wrapper`),ee.push(` Subcommand: ${A.subcommand}`),{lines:ee,incrementStep:!0};case"transparent-wrapper":return ee.push(""),ee.push(`STEP ${z} ${X.h} Transparent wrapper`),ee.push(` Wrapper: ${A.wrapper}`),ee.push(` Tokens: ${zo(A.output)}`),{lines:ee,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"rule-check":{if(ee.push(""),ee.push(`STEP ${z} ${X.h} Match rules`),ee.push(` Rule: ${A.rule}()`),A.matched)ee.push(" Result: MATCHED");else ee.push(" Result: No match");return{lines:ee,incrementStep:!0}}case"worktree-relaxation":return ee.push(""),ee.push(`STEP ${z} ${X.h} Worktree relaxation`),ee.push(` Mode: ${o.worktree.name}`),ee.push(` Git cwd: ${A.gitCwd}`),ee.push(" Result: Allowed local discard in linked worktree"),{lines:ee,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(A.embeddedCommandFound)return ee.push(""),ee.push(`STEP ${z} ${X.h} Fallback scan`),ee.push(` Found: ${A.embeddedCommandFound}`),{lines:ee,incrementStep:!0};return null}case"custom-rules-check":{if(A.rulesChecked){if(ee.push(""),ee.push(`STEP ${z} ${X.h} Custom rules`),A.matched)ee.push(" Result: MATCHED");else ee.push(" Result: No match");return{lines:ee,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(A.matched)return ee.push(""),ee.push(`STEP ${z} ${X.h} Dangerous text check`),ee.push(` Token: ${A.token}`),ee.push(" Result: MATCHED"),{lines:ee,incrementStep:!0};return null}case"strict-unparseable":return ee.push(""),ee.push(`STEP ${z} ${X.h} Strict mode check`),ee.push(` Command: ${A.rawCommand}`),ee.push(" Result: ✗ UNPARSEABLE"),{lines:ee,incrementStep:!0};case"segment-skipped":return null;case"error":return ee.push(""),ee.push(`ERROR: ${A.message}`),{lines:ee,incrementStep:!1};default:return A}}function Jo(A,z){let X=dl(z?.asciiOnly??!1),ee=58,te=[],ae=1;te.push(...ul(X,58)),te.push("");let le=A.trace.steps.find((Ee)=>Ee.type==="error");if(le&&le.type==="error"){te.push("ERROR"),te.push(` ${le.message}`),te.push(""),te.push("RESULT"),te.push(` Status: ${A.result==="blocked"?dt.red("BLOCKED"):dt.green("ALLOWED")}`),te.push(""),te.push("CONFIG");let Ee=A.configSource??"none";return te.push(` Path: ${Ee}`),te.join(`
|
|
212
|
-
`)}let ye=
|
|
213
|
-
`)}function
|
|
214
|
-
`,()=>
|
|
215
|
-
`))}function
|
|
216
|
-
`))}function
|
|
217
|
-
`)}var
|
|
218
|
-
`)}function
|
|
206
|
+
`}function $n(P){return[{name:"__init__.py",content:T2(P)},{name:"plugin.yaml",content:_2(P)}]}import{mkdirSync as $2,readdirSync as I2,readFileSync as O2,rmSync as Ro}from"node:fs";import{join as tn}from"node:path";var F2="__pycache__";function Po(P){let V=P.env.get("HERMES_HOME")?.trim();return V?V:tn(P.home,".hermes")}function Eo(P){return tn(Po(P),"plugins",Tt)}function Do(P){return P.startsWith(So)}function Ao(P,V){let z=Eo(P),Q=Lt(z);if(Q&&(Q.isSymbolicLink()||!Q.isDirectory()))throw Error(`Refusing to ${V} ${z}: not a regular directory. Move or remove it and rerun ${V==="install"?"install":"uninstall"} --hermes-agent.`);return z}function Aa(P,V){let z=Lt(P);if(!z)return;if(z.isSymbolicLink()||!z.isFile())throw Error(`Refusing to ${V} ${P}: not a regular file. Move or remove it.`);let Q=O2(P,"utf-8");if(!Do(Q))throw Error(`Refusing to ${V} unmanaged file at ${P}. Move or remove it.`);return Q}function _a(P){let V=Ao(P,"install"),z=$n(wt());if(z.map((te)=>Aa(tn(V,te.name),"overwrite")).every((te,ne)=>te===z[ne]?.content))return{path:V,alreadyInstalled:!0};return $2(V,{recursive:!0}),z.forEach((te)=>{kt(tn(V,te.name),te.content)}),{path:V,alreadyInstalled:!1}}function _o(P){let V=Ao(P,"remove");if(!Lt(V))return[];return $n(wt()).filter((z)=>Aa(tn(V,z.name),"remove")!==void 0)}function Ta(P){let V=Ao(P,"remove");if(!Lt(V))return{path:V,alreadyInstalled:!1};let z=_o(P);if(z.forEach((Q)=>{Ro(tn(V,Q.name))}),Ro(tn(V,F2),{recursive:!0,force:!0}),I2(V).length===0)Ro(V,{recursive:!0});return{path:V,alreadyInstalled:z.length>0}}var Cr="hermes-agent",$a=/^([^\s#][^:]*):/,j2=/^\s+([A-Za-z_][\w-]*):/,Ia=/^\s+-\s*(.*)$/;function N2(P){return P.trim().replace(/^(["'])(.*)\1$/,"$2")}function M2(P){let V=P.split(/\r?\n/),z=V.findIndex((ne)=>$a.exec(ne)?.[1]?.trim()==="plugins");if(z===-1)return[];let Q=V.slice(z+1),te=Q.findIndex((ne)=>$a.test(ne));return te===-1?Q:Q.slice(0,te)}function Oa(P,V){let z=M2(P),Q=z.findIndex((ce)=>j2.exec(ce)?.[1]===V);if(Q===-1)return[];let te=z.slice(Q+1),ne=te.findIndex((ce)=>!Ia.test(ce));return(ne===-1?te:te.slice(0,ne)).map((ce)=>N2(Ia.exec(ce)?.[1]??""))}function H2(P){try{return Fa(ja(Po(P),"config.yaml"),"utf-8")}catch{return}}function To(P){let V=H2(P)??"";return Oa(V,"enabled").includes(Tt)&&!Oa(V,"disabled").includes(Tt)}function Na(P){return/^# version:\s*(.+)$/m.exec(P)?.[1]?.trim()}function U2(P,V){let z=Lt(P);if(!z)return{error:`${V.name} is missing from ${P}; run install --hermes-agent`};if(z.isSymbolicLink()||!z.isFile())return{error:`${P} is a symlink or not a regular file; move or remove it`};try{let Q=Fa(P,"utf-8");if(!Do(Q))return{error:`Unmanaged ${V.name} occupies ${P}; move or remove it`};if(Na(Q)===wt()&&Q!==V.content)return{error:`Modified ${V.name} occupies ${P}; run install --hermes-agent to restore it`};return{content:Q}}catch(Q){return{error:`Failed to read ${P}: ${Q instanceof Error?Q.message:String(Q)}`}}}function Ma(P){let V=Eo(P.environment),z=ur(Cr,V);if(z)return z;let Q=$n(wt()).map((ye)=>U2(ja(V,ye.name),ye)),te=Q.flatMap((ye)=>("error"in ye)?[ye.error]:[]);if(te.length>0)return{platform:Cr,status:"n/a",configPath:V,errors:te};let ne=Q.some((ye)=>("content"in ye)&&Na(ye.content)!==wt()),ce=ne?["Installed Hermes Agent plugin is outdated; run install --hermes-agent to update"]:[];if(!To(P.environment))return{platform:Cr,status:"disabled",method:"plugin directory",configPath:V,errors:[`${Tt} is not enabled in Hermes; run \`hermes plugins enable ${Tt}\``,...ce]};return{platform:Cr,status:"configured",method:"plugin directory",configPath:V,errors:ne?ce:void 0}}import{existsSync as G2,readFileSync as B2}from"node:fs";import{join as Ha}from"node:path";var q2=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*--kimi-code(\s|["']|$)/;function V2(P){return Ha(P.env.get("KIMI_CODE_HOME")||Ha(P.home,".kimi-code"),"config.toml")}function In(P){let V=V2(P.environment);if(!G2(V))return{platform:"kimi-code",status:"n/a",configPath:V};try{if(!q2.test(B2(V,"utf-8")))return{platform:"kimi-code",status:"n/a",configPath:V}}catch(z){return{platform:"kimi-code",status:"n/a",configPath:V,errors:[`Failed to read ${V}: ${z instanceof Error?z.message:String(z)}`]}}return{platform:"kimi-code",status:"configured",method:"hook config",configPath:V}}import{readFileSync as Ka}from"node:fs";import{join as Fn}from"node:path";var ht="cc-safety-net",It="index.js",hn="openclaw.plugin.json",vn="package.json";var Sr="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as W2,lstatSync as K2,readdirSync as Y2,readFileSync as Z2}from"node:fs";import{dirname as Ga,join as Gt}from"node:path";import{fileURLToPath as X2}from"node:url";import{spawn as z2}from"node:child_process";function J2(P){return P.join(" ")}function $o(P,V,z){return[`Failed to run ${J2(P)}${V===null?"":` (exit ${V})`}.`,z.trim()].filter(Boolean).join(`
|
|
207
|
+
`)}function Io(P){let V={stdout:"",stderr:""};return P.stdout.setEncoding("utf-8"),P.stderr.setEncoding("utf-8"),P.stdout.on("data",(z)=>{V.stdout+=z}),P.stderr.on("data",(z)=>{V.stderr+=z}),V}function _t(P,V){return new Promise((z,Q)=>{let te=Xt([...P],process.env),ne=z2(te.cmd,te.args,{stdio:["ignore","pipe","pipe"]}),ce=Io(ne),ye=()=>[ce.stdout,ce.stderr].filter(Boolean).join(`
|
|
208
|
+
`),he=V?.timeoutMs??120000,be=setTimeout(()=>{ne.kill(),Q(Error($o(P,null,`Timed out after ${he}ms.
|
|
209
|
+
${ye()}`.trim())))},he);ne.on("error",(xe)=>{clearTimeout(be),Q(Error($o(P,null,`${xe.message}
|
|
210
|
+
${ye()}`.trim())))}),ne.on("close",(xe)=>{if(clearTimeout(be),xe!==0){Q(Error($o(P,xe,ye())));return}z(V?.stdoutOnly?ce.stdout:ye())})})}async function Oo(P){for(let V of P)await _t(V)}async function Ua(P){for(let V of P)try{await _t(V)}catch(z){console.warn(z instanceof Error?z.message:String(z))}}var Fo=Gt("openclaw",ht),Q2=[It,hn,vn];function jo(P,V){if(P==="~")return V;if(P.startsWith("~/")||P.startsWith("~\\"))return Gt(V,P.slice(2));return P}function Ba(P){let V=P.env.get("OPENCLAW_STATE_DIR")?.trim();if(V)return jo(V,P.home);let z=P.env.get("OPENCLAW_CONFIG_PATH")?.trim();return z?Ga(jo(z,P.home)):Gt(P.home,".openclaw")}function qa(P){let V=P.env.get("OPENCLAW_CONFIG_PATH")?.trim();return V?jo(V,P.home):Gt(Ba(P),"openclaw.json")}function No(P){return Gt(Ba(P),"extensions",ht)}function ef(P){let V=Y2(P);if(V.length===0)return!0;if(V.some((te)=>!Q2.includes(te)))return!1;let z=Gt(P,It),Q=Lt(z);return Q!==void 0&&!Q.isSymbolicLink()&&Q.isFile()&&Z2(z,"utf-8").startsWith(Sr)}function Mo(P){let V=No(P),z=Lt(V);if(!z)return;if(!z.isSymbolicLink()&&z.isDirectory()&&ef(V))return;throw Error(`Refusing to modify ${V}: it does not hold a cc-safety-net managed OpenClaw plugin. Move or remove it, then run the command again.`)}function Va(){let P=Ga(X2(import.meta.url));return[Gt(P,Fo),Gt(P,"..",Fo),Gt(P,"..","..","..","dist",Fo)]}function Ho(P=Va()){return P.find((V)=>W2(V)&&K2(V).isDirectory())}function tf(P=Va()){let V=Ho(P);if(!V)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return V}function za(P=tf()){return[["openclaw","plugins","install",P,"--force"],["openclaw","plugins","enable",ht]]}function nf(P){let V=(()=>{try{return JSON.parse(P)}catch{return}})(),z=ft(ft(V,"plugin"),"status");return typeof z==="string"?z:void 0}async function Ja(){let P=nf(await _t(["openclaw","plugins","inspect",ht,"--runtime","--json"],{stdoutOnly:!0}));if(P==="loaded")return;throw Error(`${P===void 0?`The ${ht} plugin's load state could not be verified: OpenClaw's runtime inspect report was unreadable.`:`OpenClaw reports the ${ht} plugin with status "${P}".`} Run \`openclaw plugins inspect ${ht} --runtime\` for details.`)}var Rr="openclaw",On=`run \`openclaw plugins enable ${ht}\``;function bn(P,V){let z=Fn(P,V),Q=Lt(z);if(!Q)return{error:`${V} is missing from ${z}; run install --openclaw`};if(Q.isSymbolicLink()||!Q.isFile())return{error:`${z} is a symlink or not a regular file; move or remove it`};try{return{content:Ka(z,"utf-8")}}catch(te){return{error:`Failed to read ${z}: ${te instanceof Error?te.message:String(te)}`}}}function Ya(P){try{return JSON.parse(At(P))}catch{return}}function rf(P){let V=bn(P,hn);if("error"in V)return V.error;if(ft(Ya(V.content),"id")===ht)return;return`${Fn(P,hn)} is not a valid ${ht} manifest; run install --openclaw`}function of(P){let V=bn(P,vn);if("error"in V)return V.error;let z=ft(ft(Ya(V.content),"openclaw"),"extensions");if(Array.isArray(z)&&z.includes(`./${It}`))return;return`${Fn(P,vn)} does not point OpenClaw at ${It}; run install --openclaw`}function Wa(P){return Array.isArray(P)?P.filter((V)=>typeof V==="string"):[]}function sf(P){let V=qa(P);if(!Lt(V))return`${ht} is not enabled; ${On}`;let z=(()=>{try{return JSON.parse(At(Ka(V,"utf-8")))}catch{return}})();if(z===void 0)return`Failed to read ${V}; fix it, then ${On}`;let Q=ft(z,"plugins");if(ft(Q,"enabled")===!1)return`plugins.enabled is false in ${V}; no OpenClaw plugin loads`;let te=ft(ft(ft(Q,"entries"),ht),"enabled");if(Wa(ft(Q,"deny")).includes(ht)||te===!1)return`${ht} is disabled in ${V}; ${On}`;let ne=Wa(ft(Q,"allow"));if(ne.length>0&&!ne.includes(ht))return`plugins.allow in ${V} does not list ${ht}; add it, then ${On}`;if(ne.includes(ht)||te===!0)return;return`${ht} is not enabled; ${On}`}function Za(P){return/^\/\/ version:\s*(.+)$/m.exec(P)?.[1]?.trim()}function af(P,V,z){if(z===void 0)return[];let Q=bn(z,It);if("error"in Q||Za(Q.content)!==V)return[];return[It,hn,vn].flatMap((te)=>{let ne=bn(P,te),ce=bn(z,te);if("error"in ne||"error"in ce||ne.content===ce.content)return[];return[`Modified ${te} occupies ${Fn(P,te)}; run install --openclaw to restore it`]})}function Xa(P){let V=No(P.environment),z=ur(Rr,V);if(z)return z;let Q=bn(V,It),ne=["error"in Q?Q.error:Q.content.startsWith(Sr)?void 0:`Unmanaged ${It} occupies ${Fn(V,It)}; move or remove it`,rf(V),of(V)].filter((xe)=>xe!==void 0),ce="content"in Q?Za(Q.content):void 0,ye=ne.length>0?ne:af(V,ce,Ho());if(ye.length>0)return{platform:Rr,status:"n/a",configPath:V,errors:ye};let he=ce===wt()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],be=sf(P.environment);if(be)return{platform:Rr,status:"disabled",method:"plugin directory",configPath:V,errors:[be,...he]};return{platform:Rr,status:"configured",method:"plugin directory",configPath:V,errors:he.length>0?he:void 0}}import{existsSync as mf,readFileSync as gf}from"node:fs";import{join as yf}from"node:path";import{existsSync as Pr,readFileSync as Uo,rmSync as lf}from"node:fs";import{join as Bt}from"node:path";import{pathToFileURL as cf}from"node:url";var Er="cc-safety-net",nn=`${Er}@latest`,el=["opencode.json","opencode.jsonc"],Qa="CCSafetyNetPlugin",df={stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"};function Dr(P){return P.env.get("OPENCODE_CONFIG_DIR")??Bt(P.env.get("XDG_CONFIG_HOME")||Bt(P.home,".config"),"opencode")}function uf(P){return Bt(Dr(P),el[0])}function tl(P){return el.map((V)=>Bt(Dr(P),V))}function nl(P){return Bt(P.env.get("XDG_CACHE_HOME")||Bt(P.home,".cache"),"opencode","packages",nn)}function rl(P){lf(nl(P),{recursive:!0,force:!0})}async function ol(P){let V=(await _t(["opencode","--version"],{stdoutOnly:!0})).trim(),z=/^(?:opencode\s+)?v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(V),Q=Number(z?.[1]),te=Number(z?.[2]),ne=Number(z?.[3]);if(!z||Q!==1&&Q!==2||Q===1&&(te<18||te===18&&ne<29)||Q===2&&te===0&&ne<6)throw Error(`OpenCode 1.18.29+ or 2.0.6+ is required; found ${V||"an unknown version"}.`);if(Q===2){for(let ce of tl(P)){if(!Pr(ce))continue;let ye=Go(Uo(ce,"utf-8"),ce);if(["plugin","plugins"].some((be)=>{let xe=ft(ye,be);return Array.isArray(xe)&&xe.some((Ie)=>Bo(Ie)&&(typeof Ie==="string"?Ie:ft(Ie,"package"))!==nn)}))throw Error(`Change the cc-safety-net package spec in ${ce} to ${nn}, preserving its options, then retry. Adding another spec would create a duplicate plugin ID.`)}return{commands:[["opencode","plugin","add",nn],["opencode","plugin","update",nn]],afterInstall:async()=>{let ce=await _t(["opencode","plugin","list"],{stdoutOnly:!0});if(/^cc-safety-net\s+\S+\s+cc-safety-net@latest\s*$/m.test(ce))return;throw Error("OpenCode did not load cc-safety-net from cc-safety-net@latest. Run `opencode plugin list` for details.")}}}return rl(P),{commands:[["opencode","plugin","-g","-f",nn]],afterInstall:()=>pf(P)}}async function pf(P){let V=Bt(nl(P),"node_modules",Er),z=Bt(V,"package.json");if(!Pr(z))throw Error(`The OpenCode plugin cache at ${V} is missing its package, so OpenCode would load nothing and fail open. Run \`opencode plugin -g -f ${nn}\` for details.`);let Q=ft(JSON.parse(Uo(z,"utf-8")),"main");if(typeof Q!=="string")throw Error(`The cached OpenCode plugin at ${V} declares no "main" entry.`);let te=Bt(V,Q);if(typeof(await import(cf(te).href))[Qa]==="function")return;throw Error(`The cached OpenCode plugin at ${te} does not export a callable ${Qa}, so OpenCode would load nothing and fail open.`)}function Go(P,V){try{return JSON.parse(At(P))}catch(z){if(z instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${V}: ${z.message}`);throw z}}function Bo(P){let V=typeof P==="string"?P:ft(P,"package");return typeof V==="string"&&(V===Er||V.startsWith(`${Er}@`))}function qo(P){return["plugin","plugins"].some((V)=>{let z=ft(P,V);return Array.isArray(z)&&z.some(Bo)})}function ff(P,V){let Q=["plugin","plugins"].flatMap((te)=>{let ne=Xs(P,te,df);if(!ne)return[];let ce=[],ye=0,he=ne.start+1,be=P.slice(ne.start+1,ne.end).matchAll(/\/\/[^\n]*|\/\*[\s\S]*?\*\/|"(?:\\.|[^"\\])*"|[^"\s{}[\],/]+|[{}[\],]/g);for(let xe of be){if(xe[0].startsWith("//")||xe[0].startsWith("/*"))continue;let Ie=ne.start+1+xe.index;if(ye===0)he=Ie;if(xe[0]==="{"||xe[0]==="[")ye++;if(xe[0]==="}"||xe[0]==="]")ye--;if(ye!==0||xe[0]===",")continue;let Xe=Ie+xe[0].length;if(Bo(JSON.parse(At(P.slice(he,Xe)))))ce.push({start:he,end:Xe})}return ce}).sort((te,ne)=>te.start-ne.start).reverse().reduce((te,ne)=>{let ce=/^(?:\s|\/\/[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\/)*,/.exec(te.slice(ne.end));if(ce?.[0].includes("/")){let ye=ne.end+ce[0].length-1;return te.slice(0,ne.start)+te.slice(ne.end,ye)+te.slice(ye+1)}return fr(te,ne)},P);return Go(Q,V),Q}function il(P){rl(P);let V=tl(P),z=V.find((ne)=>Pr(ne)),Q=[],te=[];for(let ne of V){if(!Pr(ne))continue;try{let ce=Uo(ne,"utf-8");if(!qo(Go(ce,ne)))continue;kt(ne,ff(ce,ne)),te.push(ne)}catch(ce){Q.push(ce instanceof Error?ce.message:String(ce))}}if(Q.length>0)throw Error(Q.join(`
|
|
211
|
+
`));return{path:te[0]??z??uf(P),alreadyInstalled:te.length>0}}function sl(P){let V=[],z=Dr(P.environment),Q=["opencode.json","opencode.jsonc"];for(let te of Q){let ne=yf(z,te);if(mf(ne))try{let ce=gf(ne,"utf-8"),ye=At(ce),he=JSON.parse(ye);if(qo(he))return{platform:"opencode",status:"configured",method:"plugin array",configPath:ne,errors:V.length>0?V:void 0}}catch(ce){V.push(`Failed to parse ${te}: ${ce instanceof Error?ce.message:String(ce)}`)}}return{platform:"opencode",status:"n/a",errors:V.length>0?V:void 0}}import{join as hf}from"node:path";function Vo(P){return hf(P.home,".pi","agent","settings.json")}function zo(P){if(typeof P!=="string")return!1;return P==="npm:cc-safety-net"||P.startsWith("npm:cc-safety-net@")}function al(P){let V=Vo(P.environment),z=Ft(V);if(z.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(z.kind==="missing")return{platform:"pi",status:"n/a"};let Q=ft(z.value,"packages");if(!Array.isArray(Q))return{platform:"pi",status:"n/a"};let te=Q.find((ye)=>zo(typeof ye==="string"?ye:ft(ye,"source")));if(te===void 0)return{platform:"pi",status:"n/a"};let ne=ft(te,"extensions");if(Array.isArray(ne)&&ne.some((ye)=>typeof ye==="string"&&ye.startsWith("-")))return{platform:"pi",status:"disabled",method:"package config",configPath:V,errors:["npm:cc-safety-net is installed but its extension is disabled in Pi settings"]};return{platform:"pi",status:"configured",method:"package config",configPath:V}}var vf={amp:Gs,"antigravity-cli":Bs,"claude-code":Js,codex:Ws,"copilot-cli":ca,cursor:ha,"gemini-cli":va,"grok-build":Ea,"hermes-agent":Ma,"kimi-code":In,openclaw:Xa,opencode:sl,pi:al};function Ln(P,V,z){let Q={...z,cwd:V,environment:P};return Zn.map((te)=>bf(vf[te](Q)))}function bf(P){if(P.status==="not-inspected")return{platform:P.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:P.platform,detected:P.status!=="n/a",configured:P.status==="configured",inspectionStatus:P.status!=="n/a"?"verified":P.errors&&P.errors.length>0?"failed":"not-applicable",method:P.method,configPath:P.configPath,configPaths:P.configPaths,errors:P.errors}}import{join as Lf}from"node:path";var wf=Object.freeze([{command:"git reset --hard",description:"git reset --hard",expectBlocked:!0},{command:"rm -rf /",description:"rm -rf /",expectBlocked:!0},{command:"rm -rf ./node_modules",description:"rm in cwd (safe)",expectBlocked:!1}]),kf=Object.freeze({state:"ready",diagnostics:Object.freeze([]),ruleMetadata:Object.freeze({}),policy:Object.freeze({rules:Object.freeze([]),transparentWrappers:Object.freeze([]),safety:Object.freeze({}),worktreeMode:!1,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:Object.freeze({}),destructiveCommandAllowPaths:Object.freeze([]),secretProtection:Object.freeze({enabled:!0,disabledRules:Object.freeze([]),denyPaths:Object.freeze([]),allowPaths:Object.freeze([])})})}),xf={strict:!1,paranoidRm:!1,paranoidInterpreters:!1,worktreeMode:!1,effectiveLevel:"standard",capabilities:{fail_closed:{enabled:!1,source:"preset",sources:[]},paranoid_rm:{enabled:!1,source:"preset",sources:[]},paranoid_interpreters:{enabled:!1,source:"preset",sources:[]}}};function ll(P){let V=Lf(P.tmpdir,"cc-safety-net-self-test"),z=wf.map((Q)=>{let te=D(P,d("self-test",{command:Q.command},{kind:"command",shell:"auto"},{configCwd:V,executionCwd:V},Q.command),{guard:{dependencies:{loadPolicySnapshot:()=>kf,getModes:()=>xf,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),ne=Q.expectBlocked?"blocked":"allowed",ce=te.decision.kind==="deny"?"blocked":"allowed";return{command:Q.command,description:Q.description,expected:ne,actual:ce,passed:ne===ce,reason:te.decision.kind==="deny"?te.decision.reason:void 0,ruleId:te.decision.kind==="deny"?te.decision.ruleId:void 0}});return{passed:z.filter((Q)=>Q.passed).length,failed:z.filter((Q)=>!Q.passed).length,total:z.length,results:z}}function Jo(P){let V=xt({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},P);if(Ht(V.errors))return null;return{json:V.flags.json,skipUpdateCheck:V.flags.skipUpdateCheck}}async function cl(P,V={}){let z=await Pn(!V.json,()=>{let Q=Cf(P,V);return{ready:Q,finish:()=>Q}},()=>Rn(),{loadingMessage:"Checking system status…"});if(V.json)console.log(JSON.stringify(z,null,2));else Sf(z);return z.engineSelfTest.failed>0||z.findings.some((Q)=>Q.severity==="error")?1:0}async function Cf(P,V){let z=V.cwd??process.cwd(),Q=await sr(),te=Ln(P,z,{ampPluginListOutput:Q.ampPluginListOutput,codexPluginListOutput:Q.codexPluginListOutput,copilotCliVersion:Q.versions["copilot-cli"]}),ne=os(P,z),ce=is(P),ye=E(P,{cwd:z}),he=ye.policy,be=R(he,P.env),xe=G(he,be.capabilities),Ie=tr(P,7),Xe=js(P,z),et=V.skipUpdateCheck?{currentVersion:wt(),latestVersion:null,updateAvailable:!1}:await Wt(),Re={hooks:te,engineSelfTest:ll(P),userConfig:ne.userConfig,projectConfig:ne.projectConfig,configState:Ne(ye),effectiveRules:ne.effectiveRules,environment:ce,effectiveSafety:{selectedPreset:he.safety.level??"standard",level:be.effectiveLevel,capabilities:be.capabilities,ruleOverrides:he.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(xe).filter(([,at])=>at.source==="rule_override"&&at.override==="off"&&at.inheritedEnabled&&at.changesInherited).map(([at])=>at),ruleCounts:{stored:Object.keys(he.destructiveCommandRuleOverrides).length,effective:Object.values(xe).filter((at)=>at.changesInherited).length},...ye.policyScopes?{policyScopes:ye.policyScopes}:{}},...Xe.length>0?{v2Leftovers:Xe}:{},posture:bs(P,ne.userConfig.path),activity:Ie,update:et,system:Q};return{...Re,findings:as(Re)}}function Sf(P){console.log(),console.log(cs(P.hooks)),console.log(),console.log(ds(P.engineSelfTest)),console.log(),console.log(us(P)),console.log(),console.log(ps(P.environment)),console.log(),console.log(fs(P)),console.log(),console.log(ms(P.findings)),console.log(),console.log(gs(P.activity)),console.log(),console.log(hs(P.system)),console.log(),console.log(ys(P.update)),console.log(vs(P))}import{existsSync as Rf}from"node:fs";var Pf=/^[A-Za-z0-9_@%+=:,./-]+$/,dl="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function Wo(P){let V=xt({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},P);if(Ht(V.errors))return console.error(dl),console.error("Pass -- before a command that starts with dashes."),null;if(V.values.cwd!==void 0&&!Rf(V.values.cwd))return console.error(`Error: --cwd path does not exist: ${V.values.cwd}`),null;let z=V.positionals.length===1?V.positionals[0]:V.positionals.map((Q)=>Pf.test(Q)?Q:`'${Q.replaceAll("'","'\\''")}'`).join(" ");if(!z)return console.error("Error: No command provided"),console.error(dl),null;return{json:V.flags.json,cwd:V.values.cwd,command:z}}function ul(P){if(P)return{dh:"=",dv:"|",dtl:"+",dtr:"+",dbl:"+",dbr:"+",h:"-",v:"|",tl:"+",tr:"+",bl:"+",br:"+",sh:"="};return{dh:"═",dv:"║",dtl:"╔",dtr:"╗",dbl:"╚",dbr:"╝",h:"─",v:"│",tl:"┌",tr:"┐",bl:"└",br:"┘",sh:"━"}}function pl(P,V){let Q=V-18;return[`${P.dtl}${P.dh.repeat(V)}${P.dtr}`,`${P.dv} Command Analysis${" ".repeat(Q)}${P.dv}`,`${P.dbl}${P.dh.repeat(V)}${P.dbr}`]}function Ko(P){return JSON.stringify(P)}function fl(P,V=0){return`[${P.map((Q,te)=>ls(Q,te,V)).join(",")}]`}function jn(P,V,z=70){let Q=P.split(" "),te=[],ne="";for(let ce of Q)if(ne&&ne.length+ce.length+1>z)te.push(ne),ne=ce;else ne=ne?`${ne} ${ce}`:ce;if(ne)te.push(ne);return te.map((ce,ye)=>ye===0?ce:`${V}${ce}`)}function ml(P,V,z){let Q=[];switch(P.type){case"parse":return null;case"env-strip":return Q.push(""),Q.push(`STEP ${V} ${z.h} Strip environment variables`),Q.push(` Removed: ${P.envVars.map((te)=>`${te}=<redacted>`).join(", ")}`),Q.push(` Tokens: ${Ko(P.output)}`),{lines:Q,incrementStep:!0};case"leading-tokens-stripped":return Q.push(""),Q.push(`STEP ${V} ${z.h} Strip wrappers`),Q.push(` Removed: ${P.removed.join(", ")}`),Q.push(` Tokens: ${Ko(P.output)}`),{lines:Q,incrementStep:!0};case"shell-wrapper":return Q.push(""),Q.push(`STEP ${V} ${z.h} Detect shell wrapper`),Q.push(` Wrapper: ${P.wrapper} -c`),Q.push(` Inner: ${P.innerCommand}`),{lines:Q,incrementStep:!0};case"interpreter":{if(Q.push(""),Q.push(`STEP ${V} ${z.h} Detect interpreter`),Q.push(` Interpreter: ${P.interpreter}`),Q.push(` Code: ${P.codeArg}`),P.paranoidBlocked)Q.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:Q,incrementStep:!0}}case"busybox":return Q.push(""),Q.push(`STEP ${V} ${z.h} Busybox wrapper`),Q.push(` Subcommand: ${P.subcommand}`),{lines:Q,incrementStep:!0};case"transparent-wrapper":return Q.push(""),Q.push(`STEP ${V} ${z.h} Transparent wrapper`),Q.push(` Wrapper: ${P.wrapper}`),Q.push(` Tokens: ${Ko(P.output)}`),{lines:Q,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"rule-check":{if(Q.push(""),Q.push(`STEP ${V} ${z.h} Match rules`),Q.push(` Rule: ${P.rule}()`),P.matched)Q.push(" Result: MATCHED");else Q.push(" Result: No match");return{lines:Q,incrementStep:!0}}case"worktree-relaxation":return Q.push(""),Q.push(`STEP ${V} ${z.h} Worktree relaxation`),Q.push(` Mode: ${o.worktree.name}`),Q.push(` Git cwd: ${P.gitCwd}`),Q.push(" Result: Allowed local discard in linked worktree"),{lines:Q,incrementStep:!0};case"temp-root-relaxation":return Q.push(""),Q.push(`STEP ${V} ${z.h} Temp-root relaxation`),Q.push(` Git cwd: ${P.gitCwd}`),Q.push(" Result: Allowed git discard in a temp-root repository"),{lines:Q,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(P.embeddedCommandFound)return Q.push(""),Q.push(`STEP ${V} ${z.h} Fallback scan`),Q.push(` Found: ${P.embeddedCommandFound}`),{lines:Q,incrementStep:!0};return null}case"custom-rules-check":{if(P.rulesChecked){if(Q.push(""),Q.push(`STEP ${V} ${z.h} Custom rules`),P.matched)Q.push(" Result: MATCHED");else Q.push(" Result: No match");return{lines:Q,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(P.matched)return Q.push(""),Q.push(`STEP ${V} ${z.h} Dangerous text check`),Q.push(` Token: ${P.token}`),Q.push(" Result: MATCHED"),{lines:Q,incrementStep:!0};return null}case"strict-unparseable":return Q.push(""),Q.push(`STEP ${V} ${z.h} Strict mode check`),Q.push(` Command: ${P.rawCommand}`),Q.push(" Result: ✗ UNPARSEABLE"),{lines:Q,incrementStep:!0};case"segment-skipped":return null;case"error":return Q.push(""),Q.push(`ERROR: ${P.message}`),{lines:Q,incrementStep:!1};default:return P}}function Yo(P,V){let z=ul(V?.asciiOnly??!1),Q=58,te=[],ne=1;te.push(...pl(z,58)),te.push("");let ce=P.trace.steps.find((Re)=>Re.type==="error");if(ce&&ce.type==="error"){te.push("ERROR"),te.push(` ${ce.message}`),te.push(""),te.push("RESULT"),te.push(` Status: ${P.result==="blocked"?dt.red("BLOCKED"):dt.green("ALLOWED")}`),te.push(""),te.push("CONFIG");let Re=P.configSource??"none";return te.push(` Path: ${Re}`),te.join(`
|
|
212
|
+
`)}let ye=P.trace.steps.find((Re)=>Re.type==="parse");if(ye&&ye.type==="parse"){te.push("INPUT"),te.push(` ${ye.input}`),te.push(""),te.push(`STEP ${ne} ${z.h} Split shell commands`),ne++;for(let Re=0;Re<ye.segments.length;Re++){let at=ye.segments[Re];if(at){let ct=Math.random();te.push(` Segment ${Re+1}: ${fl(at,ct)}`)}}}let he=P.trace.segments,be=he.length>1;for(let Re of he){if(be){te.push("");let pt="";if(ye&&ye.type==="parse"){let Xr=ye.segments[Re.index];if(Xr)pt=Xr.join(" ")}let mt=54,gt=pt,ut=` Segment ${Re.index+1}: `,vt=" ";if(pt){if(ut.length+pt.length+vt.length>mt){let Hd=mt-ut.length-vt.length;gt=`${pt.substring(0,Hd-1)}…`}}let Dt=pt?`${ut}${gt}${vt}`:` Segment ${Re.index+1} `,Nd=pt?`${ut}${dt.cyan(gt)}${vt}`:Dt,$i=58-Dt.length,Ii=Math.floor($i/2),Md=$i-Ii;te.push(`${z.sh.repeat(Ii)}${Nd}${z.sh.repeat(Md)}`)}if(Re.steps.find((pt)=>pt.type==="segment-skipped")){te.push(""),te.push(" (skipped — prior segment blocked)");continue}let ct=!1,lt=!1;for(let pt of Re.steps){let mt=ml(pt,ne,z);if(mt){if(lt=!0,pt.type==="recurse"){te.push("");let gt=" RECURSING ",ut=58-gt.length-4;te.push(` ${z.tl}${z.h}${gt}${z.h.repeat(ut)}`),te.push(` ${z.v}`),ct=!0;continue}for(let gt of mt.lines)if(ct)te.push(` ${z.v} ${gt}`);else te.push(gt);if(mt.incrementStep)ne++}}if(ct)te.push(` ${z.v}`),te.push(` ${z.bl}${z.h.repeat(56)}`),ct=!1;if(!lt)te.push(""),te.push(` ${dt.green("✓")} Allowed (no matching rules)`)}if(te.push(""),te.push("RESULT"),P.result==="blocked"){if(te.push(` Status: ${dt.red("BLOCKED")}`),P.customRule){if(te.push(` Rule: ${P.customRule.id}`),P.customRule.rulebook)te.push(` Rulebook: ${P.customRule.rulebook.name} ${P.customRule.rulebook.version}`);if(P.customRule.source)te.push(` Source: ${P.customRule.source}`);if(P.customRule.override)te.push(` Override: reason ${P.customRule.override.reason}`)}if(P.reason){let Re=jn(P.reason," ");te.push(` Reason: ${Re[0]}`);for(let at=1;at<Re.length;at++)te.push(Re[at]??"")}}else te.push(` Status: ${dt.green("ALLOWED")}`);te.push(""),te.push("CONFIG");let xe=P.configSource??"none",Ie=P.configValid?"":" (invalid)";te.push(` Path: ${xe}${Ie}`);let Xe=P.safetyPresetScope;te.push(` Safety preset: ${P.selectedPreset??"standard"}${Xe?` (${rr(Xe)})`:""}`),te.push(` Effective capabilities: ${P.effectiveLevel}`);let et=Object.entries(P.destructiveCommandRuleOverrides??{});if(te.push(` Rule customizations: ${et.length}`),P.ruleActivation)te.push(` Rule activation: ${P.ruleActivation.id} — ${P.ruleActivation.enabled?"on":"off"} via ${P.ruleActivation.source}`);return te.join(`
|
|
213
|
+
`)}function Zo(P){return JSON.stringify(P,null,2)}import{resolve as Tf}from"node:path";var Ef=["AKIA","ASIA","ghp_","gho_","ghu_","ghs_","ghr_","github_pat_","glpat-","xox","npm_","pypi-","rk_","sk-","sk_","gsk_","xai-","pplx-","bastn_","tgp_v1_","flp_","wfr_","fw_","fwp_","tp-","psk-"];function gl(P){let V=0,z={allocateSegment(){return V++},getNextSegmentIndex(){return V},recordGlobal(Q){P.record({kind:"step",scope:"global",step:Q})},recordSegment(Q,te=z.currentSegmentIndex){if(te===void 0)return;P.record({kind:"step",scope:"segment",segmentIndex:te,step:Q})}};return z}function yl(P={}){let V=[],z=P.maxEvents??512,Q={maxTextLength:P.maxTextLength??2048,maxListLength:P.maxListLength??128,maxObjectProperties:P.maxObjectProperties??P.maxListLength??128,maxDepth:P.maxDepth??16},te,ne=new Set;return{record(ce){if(te)return;if(!ce||V.length>=z)return;try{V.push(ei(Df(ce,Q,ne)))}catch{}},finish(){if(te)return te;return te=ei({events:Object.freeze(V)}),te}}}function Df(P,V,z){if(P.kind!=="step")throw TypeError("invalid trace event");let{scope:Q,step:te}=P;Ar(te,z,V);let ne=Xo(te,V,z);if(Q==="global")return{kind:"step",scope:"global",step:ne};if(Q!=="segment")throw TypeError("invalid trace event scope");return{kind:"step",scope:"segment",segmentIndex:P.segmentIndex,step:ne}}function Ar(P,V,z,Q=0,te=new WeakSet){if(typeof P==="string"){let ye=P.slice(0,z.maxTextLength);if(!Ge(ye))return;for(let he of Ze(ye))for(let be of he.match(/[^\s"'()$]+/g)??[])V.add(hl(be));return}if(!P||typeof P!=="object"||Q>=z.maxDepth||te.has(P))return;if(te.add(P),Array.isArray(P)){let ye=Math.min(P.length,z.maxListLength);for(let he=0;he<ye;he++)Ar(P[he],V,z,Q+1,te);return}let ne=0,ce=new Set;for(let ye in P){if(!Object.hasOwn(P,ye))continue;if(ne>=z.maxObjectProperties)break;ne++,Ar(ye,V,z);let he=Qo(ye,z,V);if(ce.has(he))continue;ce.add(he),Ar(P[ye],V,z,Q+1,te)}}function Xo(P,V,z,Q=0,te=new WeakSet){if(typeof P==="string")return Qo(P,V,z);if(!P||typeof P!=="object")return P;if(Q>=V.maxDepth)return;if(te.has(P))return;if(te.add(P),Array.isArray(P)){let ye=[],he=Math.min(P.length,V.maxListLength);for(let be=0;be<he;be++)ye.push(Xo(P[be],V,z,Q+1,te));return ye}let ne={},ce=0;for(let ye in P){if(!Object.hasOwn(P,ye))continue;if(ce>=V.maxObjectProperties)break;ce++;let he=Qo(ye,V,z);if(Object.hasOwn(ne,he))continue;Object.defineProperty(ne,he,{value:Xo(P[ye],V,z,Q+1,te),enumerable:!0,configurable:!0,writable:!0})}return ne}function Qo(P,V,z){let Q=P.slice(0,V.maxTextLength),te=Ge(Q)?Ue(Q):Q,ne=z.size>0?_f(te,z):te;return(Af(ne)?ke(ne):ne).slice(0,V.maxTextLength)}function Af(P){return P.includes("PRIVATE KEY")||P.includes("://")||P.includes("eyJ")||P.includes(":")&&/(?:authorization|cookie|x-api-key|api-key|(?:^|\s)(?:-u|--user)(?:\s|=))/i.test(P)||P.length>=14&&Ef.some((V)=>P.includes(V))||P.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(P)}function _f(P,V){return P.replace(/[^\s"'()$]+/g,(z)=>V.has(hl(z))?"<redacted>":z)}function hl(P){let V=2166136261,z=2166136261;for(let Q=0;Q<P.length;Q++)V=Math.imul(V^P.charCodeAt(Q),16777619),z=Math.imul(z^P.charCodeAt(P.length-Q-1),16777619);return`${V>>>0}:${z>>>0}:${P.length}`}function ei(P){if(P&&typeof P==="object"&&!Object.isFrozen(P)){for(let V of Object.values(P))ei(V);Object.freeze(P)}return P}function Nn(P,V={},z){let Q=Tf(V.cwd??process.cwd()),te=V.policySnapshot??E(z,{cwd:Q,userConfigDir:V.userConfigDir}),ne=R(te.policy,z.env),ce=Fe({policySnapshot:te,effectiveCapabilities:ne.capabilities,strict:ne.strict,paranoidRm:ne.paranoidRm,paranoidInterpreters:ne.paranoidInterpreters,worktreeMode:ne.worktreeMode}),ye={effectiveLevel:ce.effectiveLevel,selectedPreset:te.policy.safety.level??"standard",...te.policyScopes?{safetyPresetScope:te.policyScopes.levelScope}:{},effectiveCapabilities:ce.effectiveCapabilities,destructiveCommandRuleOverrides:te.policy.destructiveCommandRuleOverrides},{configSource:he,configValid:be}=If(z,{cwd:Q,userConfigDir:V.userConfigDir});if(!P||!P.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:he,configValid:be,...ye};let xe=h(P,"auto");if(xe.status==="limited")throw new y;let Ie=xe.dialect==="powershell"?h(P,"posix"):xe,Xe=st(Ie),et=yl(),Re=gl(et);Re.recordGlobal({type:"parse",input:P,segments:Xe.map((Dt)=>[...Dt])});let at=d("Bash",{command:P},{kind:"command",shell:"auto"},{configCwd:Q,executionCwd:Q},P),ct=W(at,{environment:z,trace:Re,dependencies:{loadPolicySnapshot:()=>te}}),lt=ct.decision.kind==="deny"?ct.decision:null;if(lt&&(ct.stage==="policy-protection"||ct.stage==="secret-protection")){let Dt=$f(lt);return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:Dt.rule,matched:!0,reason:lt.reason}]}]},result:"blocked",reason:k(lt.reason),segment:k(vl(lt,P)),...Dt.ruleId?{ruleId:k(Dt.ruleId)}:{},configSource:he,configValid:be,...ye}}let pt=Re.getNextSegmentIndex();if(lt&&pt>0&&pt<Xe.length)Re.recordSegment({type:"segment-skipped",index:pt,reason:"prior-segment-blocked"},pt);let mt=et.finish(),gt=lt?.ruleId??Of(at,te,ne,z),ut=U.find((Dt)=>Dt.id===gt&&Dt.activationCapability),vt=ut?ce.policy.effectiveDestructiveCommandRules[ut.id]:void 0;return{trace:jf(mt),result:lt?"blocked":"allowed",reason:lt?k(lt.reason):void 0,segment:lt?k(vl(lt,P)):void 0,ruleId:lt?.ruleId?k(lt.ruleId):void 0,customRule:Ff(Nf(lt?.ruleId,te)),configSource:he,configValid:be,...ye,...ut&&vt?{ruleActivation:{id:ut.id,...vt}}:{}}}function vl(P,V){return P.evidence?.segment??V}function $f(P){if(P.reason===$e)return{ruleId:"policy-protection",rule:"policy-protection:findPolicyConfigMutationTargetInSemanticFacts"};if(P.reason===Me)return{ruleId:"policy-apply-protection",rule:"policy-apply-protection:findPolicyApplyInvocationInSemanticFacts"};if(P.reason===x)return{ruleId:"git-metadata-protection",rule:"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts"};return{ruleId:P.ruleId,rule:"secret-protection:findSensitiveTargetInSemanticFacts"}}function If(P,V){let z=F(V.cwd),Q=M(P,V),te=K(P,{cwd:V.cwd,userConfigDir:V.userConfigDir});try{if(n(te.projectConfigTarget)!==null){if(Jt(te.projectConfigTarget).errors.length===0)return{configSource:z,configValid:!0};return{configSource:z,configValid:!1}}}catch(ne){if(ne instanceof r)return{configSource:z,configValid:!1};throw ne}try{if(n(te.userConfigTarget)!==null){let ne=Jt(te.userConfigTarget);return{configSource:Q,configValid:ne.errors.length===0}}return{configSource:null,configValid:!0}}catch(ne){if(ne instanceof r)return{configSource:Q,configValid:!1};throw ne}}function Of(P,V,z,Q){let te=V.policy,ne=Ee({...te,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...te.destructiveCommandRuleOverrides,...Object.fromEntries(U.flatMap((ye)=>ye.activationCapability?[[ye.id,"on"]]:[]))}},V.state==="degraded"?{diagnostics:V.diagnostics,reason:V.reason}:void 0),ce=W(P,{environment:Q,dependencies:{loadPolicySnapshot:()=>ne,getModes:()=>({...z,strict:!0,paranoidRm:!0,paranoidInterpreters:!0}),findSensitiveTarget:()=>null}});return ce.decision.kind==="deny"?ce.decision.ruleId:void 0}function Ff(P){if(!P)return;return{id:k(P.id),...P.rulebook?{rulebook:{name:k(P.rulebook.name),version:k(P.rulebook.version)}}:{},...P.source?{source:k(P.source)}:{},...P.override?{override:{type:"reason",reason:k(P.override.reason)}}:{}}}function jf(P){let V=P.events.flatMap((Q)=>Q.kind==="step"&&Q.scope==="global"?[Q.step]:[]),z=new Map;for(let Q of P.events){if(Q.kind!=="step"||Q.scope!=="segment")continue;let te=z.get(Q.segmentIndex)??{index:Q.segmentIndex,steps:[]};te.steps.push(Q.step),z.set(Q.segmentIndex,te)}return{steps:V,segments:[...z.values()]}}function Nf(P,V){let z=P?.replace(/^custom\./,"");if(!z||!V.policy.rules.some((Q)=>Q.name===z))return;return V.ruleMetadata[z]??Object.freeze({id:z})}function bl(P){return new Promise((V)=>{process.stdout.write(`${P}
|
|
214
|
+
`,()=>V())})}async function Ll(P,V){let z=Wo(V);if(!z)return 1;try{let Q=Nn(z.command,{cwd:z.cwd},P),te=!!process.env.NO_COLOR||!process.stdout.isTTY;return await bl(z.json?Zo(Q):Yo(Q,{asciiOnly:te})),0}catch(Q){let te=Mf(Q instanceof p?Q.cause:Q);if(te===void 0)throw Q;if(z.json)return await bl(JSON.stringify({error:te})),1;return console.error(te),1}}function Mf(P){if(P instanceof y)return P.message;if(P instanceof f)return P.message;if(P instanceof s&&a[P.kind].errorCode==="path-canonicalization-limit")return"Path canonicalization work limit exceeded.";return}var wl="2.4.4",Ot=" ",rn="cc-safety-net";function kl(P){return P.argument?`${P.flags} ${P.argument}`:P.flags}function Hf(P){return Math.max(...P.map((V)=>kl(V).length))}function Uf(P){return Math.max(...P.map((V)=>V.usage.length))}function Gf(P){return Math.max(...P.map((V)=>`${rn} ${V.usage}`.length))}function Bf(P,V){let z=`${rn} ${P.usage}`;return`${Ot}${z.padEnd(V+2)}${P.description}`}function qt(P,V){return`${Ot}${P.padEnd(Math.max(40,P.length+2))}${V}`}function wn(P,V=console.log){let z=[];if(z.push(`${rn} ${P.name}`),z.push(""),z.push(`${Ot}${P.description}`),z.push(""),z.push("USAGE:"),z.push(`${Ot}${rn} ${P.usage}`),z.push(""),P.subcommands&&P.subcommands.length>0){z.push("SUBCOMMANDS:");let Q=Uf(P.subcommands);for(let te of P.subcommands)z.push(`${Ot}${te.usage.padEnd(Q+2)}${te.description}`);z.push("")}if(P.options.length>0){z.push("OPTIONS:");let Q=Hf(P.options);for(let te of P.options){let ne=kl(te),ce=te.default?`${te.description} (default: ${te.default})`:te.description;z.push(`${Ot}${ne.padEnd(Q+2)}${ce}`)}z.push("")}if(P.examples&&P.examples.length>0){z.push("EXAMPLES:");for(let Q of P.examples)z.push(`${Ot}${Q}`)}V(z.join(`
|
|
215
|
+
`))}function ti(){let P=Gf(Qn),V=[];V.push(`${rn} v${wl}`),V.push(""),V.push("Blocks destructive commands and secret access."),V.push(""),V.push("COMMANDS:");for(let z of Qn)V.push(Bf(z,P));V.push(""),V.push("GLOBAL OPTIONS:"),V.push(`${Ot}-h, --help Show help (use with command for command-specific help)`),V.push(`${Ot}-V, --version Show version`),V.push(""),V.push("HELP:"),V.push(`${Ot}${rn} help <command> Show help for a specific command`),V.push(`${Ot}${rn} <command> --help Show help for a specific command`),V.push(""),V.push("ENVIRONMENT VARIABLES:"),V.push(qt(`${o.level.name}=standard|strict|paranoid`,"Set session safety level")),V.push(qt(`${o.worktree.name}=1`,"Allow local git discards in linked worktrees")),V.push(qt(`${o.debug.name}=1`,"Print diagnostic messages to stderr")),V.push(qt(`${o.auditScope.name}=all|blocked`,"Record all command decisions, or denials only")),V.push(qt("CC_SAFETY_NET_HOME","Override rule config home directory")),V.push(""),V.push("LEGACY ENVIRONMENT VARIABLES (STILL SUPPORTED):"),V.push(qt(`${o.strict.name}=1`,"Force safety.overrides.fail_closed on")),V.push(qt(`${o.paranoid.name}=1`,"Force paranoid_rm and paranoid_interpreters on")),V.push(qt(`${o.paranoidRm.name}=1`,"Force safety.overrides.paranoid_rm on")),V.push(qt(`${o.paranoidInterpreters.name}=1`,"Force safety.overrides.paranoid_interpreters on")),V.push(""),V.push("Documentation: https://ccsafetynet.com/docs"),console.log(V.join(`
|
|
216
|
+
`))}function xl(){console.log(wl)}function Mn(P,V=console.log){let z=er(P);if(!z)return!1;if(z.name.toLowerCase()!==P.toLowerCase())return!1;return wn(z,V),!0}import{existsSync as mi,readFileSync as bc}from"node:fs";import{join as pi}from"node:path";import*as Kt from"node:readline";function qf(P){return P==="install"?"Install":"Uninstall"}function Vf(P){return P==="install"?"Installing":"Uninstalling"}function zf(P){return P==="install"?"into":"from"}function Rl(P){return P?.available===!0}function Jf(P,V){let z=new Set(V);return P.filter((Q)=>z.has(Q.target)).map((Q)=>Q.target)}function Cl(P,V,z){if(P.length===0||P.every((Q)=>!Q.available))return V;return Array.from({length:P.length},(Q,te)=>te+1).map((Q)=>(V+Q*z+P.length)%P.length).find((Q)=>Rl(P[Q]))}function Wf(P,V,z){if(z.ctrl&&z.name==="c")return"interrupt";if(z.name==="escape"||V==="q")return"abort";if(P==="install"&&(V==="u"||V==="U"))return"update";if(z.name==="up"||V==="k")return"up";if(z.name==="down"||V==="j")return"down";if(z.name==="space"||V===" ")return"toggle";if(z.name==="return"||z.name==="enter")return"confirm";return null}function Kf(P){return{cursor:P.findIndex((V)=>V.available),selected:[]}}function Yf(P,V,z){if(z==="confirm"||z==="update"||z==="abort"||z==="interrupt")return{state:P,done:z};if(z==="up")return{state:{...P,cursor:Cl(V,P.cursor,-1)}};if(z==="down")return{state:{...P,cursor:Cl(V,P.cursor,1)}};let Q=V[P.cursor];if(!Rl(Q))return{state:P};let te=P.selected.includes(Q.target)?P.selected.filter((ne)=>ne!==Q.target):Jf(V,[...P.selected,Q.target]);return{state:{...P,selected:te}}}var Pl="◉",El="◯",Dl=">",Al=" ";function Zf(P,V,z,Q={}){let te=Q.color!==!1,ne=te?dt.dim:(he)=>he,ce=te?dt.green:(he)=>he,ye=te?dt.bold:(he)=>he;return["",`${qf(P)} CC Safety Net ${zf(P)}:`,"",...V.map((he,be)=>{let xe=z.selected.includes(he.target),Ie=be===z.cursor,Xe=xe?Pl:El,et=Ie?Dl:Al,Re=he.available?"":` (${he.unavailableReason??"not installed"})`,at=`${Xe} ${he.label}${Re}`,ct=!he.available?ne(at):xe?ce(at):Ie?ye(at):at;return`${et} ${ct}`}),"",P==="install"?"Space: select Enter: confirm u: update installed Up/Down: move q/Esc: cancel":V.some((he)=>he.available)?"Space: select Enter: confirm Up/Down: move q/Esc: cancel":`No selectable integrations found for ${P}. q/Esc: close`].join(`
|
|
217
|
+
`)}var Sl=["global-hook","plugin"];function Xf(P,V,z={}){let Q=z.color!==!1?dt.bold:(ne)=>ne;return["","Install the Kimi Code integration as:","",...[`Global hook — ${V?"already installed; selecting it reports the current state":"write the hook into ~/.kimi-code/config.toml now"}`,"Native Kimi plugin — print the steps to run inside Kimi Code"].map((ne,ce)=>{let ye=ce===P,he=`${ye?Pl:El} ${ne}`;return`${ye?Dl:Al} ${ye?Q(he):he}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
|
|
218
|
+
`)}function _l(P){let{input:V,output:z}=P;Kt.emitKeypressEvents(V);let Q=V.isRaw===!0;V.setRawMode(!0),V.resume();let te=0,ne=()=>{if(te===0)return;Kt.moveCursor(z,0,-te),Kt.cursorTo(z,0),Kt.clearScreenDown(z)},ce=()=>{ne();let ye=P.render();z.write(`${ye}
|
|
219
219
|
`),te=ye.split(`
|
|
220
|
-
`).length};return new Promise((ye)=>{let he=(
|
|
221
|
-
`);return}ye.draw()}})}import{existsSync as
|
|
222
|
-
`)})}),te.on("close",(he)=>{clearTimeout(ye),
|
|
220
|
+
`).length};return new Promise((ye)=>{let he=(xe)=>{V.off("keypress",be),V.setRawMode(Q),V.pause(),ne(),ye(xe)};function be(xe,Ie){P.onKey(xe,Ie,{finish:he,draw:ce})}V.on("keypress",be),ce()})}function Tl(P={}){let V=0;return _l({input:P.input??process.stdin,output:P.output??process.stdout,render:()=>Xf(V,P.globalHookInstalled===!0),onKey:(z,Q,te)=>{if(Q.ctrl&&Q.name==="c"){te.finish(null),(P.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(Q.name==="escape"||z==="q")return te.finish(null);if(Q.name==="return"||Q.name==="enter")return te.finish(Sl[V]);if(Q.name==="up"||Q.name==="down"||z==="k"||z==="j")V=(V+1)%Sl.length,te.draw()}})}function ni(P=process.stdin,V=process.stdout){return Boolean(P.isTTY&&V.isTTY&&typeof P.setRawMode==="function")}function $l(P,V,z={}){let Q=z.output??process.stdout,te=Kf(V);return _l({input:z.input??process.stdin,output:Q,render:()=>Zf(P,V,te),onKey:(ne,ce,ye)=>{let he=Wf(P,ne,ce);if(!he)return;let be=Yf(te,V,he);if(te=be.state,be.done==="interrupt"){ye.finish(null),(z.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(be.done==="abort")return ye.finish(null);if(be.done==="update")return ye.finish("update");if(be.done==="confirm"){if(te.selected.length===0){Q.write("\x07"),ye.draw();return}ye.finish([...te.selected]),Q.write(`${Vf(P)} selected integrations...
|
|
221
|
+
`);return}ye.draw()}})}import{existsSync as Il,lstatSync as em,mkdirSync as tm,mkdtempSync as nm,readdirSync as rm,readFileSync as xn,rmSync as Tr}from"node:fs";import{basename as om,dirname as im,join as Et}from"node:path";import{fileURLToPath as sm}from"node:url";var ri="// cc-safety-net managed Amp plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --amp",on="cc-safety-net",sn="cc-safety-net/index.ts";import{spawn as Qf}from"node:child_process";var oi=(P,V)=>{let z=Xt([...P],process.env);return new Promise((Q)=>{let te=Qf(z.cmd,z.args,{cwd:V,stdio:["ignore","pipe","pipe"]}),ne=Io(te),ce=!1,ye=setTimeout(()=>{ce=!0,te.kill()},120000);te.on("error",(he)=>{clearTimeout(ye),Q({status:null,errorCode:he.code,stdout:ne.stdout,stderr:[he.message,ne.stderr].filter(Boolean).join(`
|
|
222
|
+
`)})}),te.on("close",(he)=>{clearTimeout(ye),Q({status:ce?null:he,errorCode:ce?"ETIMEDOUT":void 0,stdout:ne.stdout,stderr:ne.stderr})})})};var kn="cc-safety-net.ts",ii=Et("amp",sn);function am(P){return Et(P.home,".config","amp","plugins","cc-safety-net.ts")}function lm(){let P=im(sm(import.meta.url));return[Et(P,ii),Et(P,"..",ii),Et(P,"..","..","..","dist",ii)]}function cm(P=lm()){let V=P.find((z)=>Il(z)&&em(z).isFile());if(!V)throw Error("Packaged Amp plugin artifact not found. Reinstall cc-safety-net and try again.");return V}function Ol(P){try{return JSON.parse(P)}catch{return}}function $r(P){return P.subarray(0,Buffer.byteLength(ri)).toString("utf-8")===ri}async function Hn(P,V,z){let Q=await P(V,z);if(Q.status===0)return Q;throw Error([`Failed to run ${V.join(" ")}${Q.status===null?"":` (exit ${Q.status})`}.`,[Q.stdout,Q.stderr].filter(Boolean).join(`
|
|
223
223
|
`).trim()].filter(Boolean).join(`
|
|
224
|
-
`))}async function
|
|
225
|
-
${
|
|
226
|
-
${[
|
|
227
|
-
`)}`.trim());let
|
|
228
|
-
`}async function
|
|
229
|
-
`)}function
|
|
230
|
-
`,
|
|
231
|
-
`)){if(/^\s*\[/.test(
|
|
232
|
-
${
|
|
233
|
-
`),te=
|
|
234
|
-
`)}function
|
|
224
|
+
`))}async function Fl(P){let V=await P(["amp","plugins","repositories","--json"]);if(V.status===null)throw Error(`${V.errorCode==="ENOENT"?'Amp CLI not found. Install the amp CLI, sign in with "amp login", and rerun install --amp.':`amp plugins repositories --json did not finish (${V.errorCode??"terminated"}). Check that the amp CLI responds and rerun install --amp.`}
|
|
225
|
+
${V.stderr}`.trim());if(V.status!==0)throw Error(`Failed to run amp plugins repositories --json (exit ${V.status}). Sign in with "amp login" and rerun install --amp.
|
|
226
|
+
${[V.stdout,V.stderr].filter(Boolean).join(`
|
|
227
|
+
`)}`.trim());let z=Ol(V.stdout),Q=(Array.isArray(z)?z:[]).filter((te)=>ft(te,"scope")==="user"&&ft(te,"exists")===!0&&ft(te,"viewerCanWrite")===!0).map((te)=>ft(te,"cloneRef")).find((te)=>typeof te==="string"&&te.length>0);if(!Q)throw Error('Your Amp account has no writable Personal Plugins repository. Sign in with "amp login", open Amp once to create it, and rerun install --amp.');return Q}async function jl(P,V,z){let Q=nm(Et(V.tmpdir,"cc-safety-net-amp-"));try{return await Hn(P,["amp","clone","user-plugins",Q]),await z(Q)}finally{Tr(Q,{recursive:!0,force:!0})}}function si(P){return`rerun ${P==="overwrite"?"install":"uninstall"} --amp`}function Nl(P,V,z){let Q=Et(P,V),te=Lt(Q);if(!te)return;if(te.isSymbolicLink()||!te.isFile())throw Error(`Refusing to ${z} ${V} in your Amp personal plugins repository: not a regular file. Remove it there and ${si(z)}.`);let ne=xn(Q);if($r(ne))return ne;throw Error(`Refusing to ${z} unmanaged file ${V} in your Amp personal plugins repository. Remove it there and ${si(z)}.`)}function Ml(P,V){let z=Et(P,on),Q=Lt(z);if(!Q)return;if(Q.isSymbolicLink()||!Q.isDirectory())throw Error(`Refusing to ${V} ${on} in your Amp personal plugins repository: not a regular directory. Remove it there and ${si(V)}.`);return Nl(P,sn,V)}function dm(P){let V=Et(P,kn),z=Lt(V);if(!z||z.isSymbolicLink()||!z.isFile())return;let Q=xn(V);return $r(Q)?Q:void 0}async function Hl(P,V,z,Q){if(await Hn(P,z,V),(await Hn(P,["git","status","--porcelain"],V)).stdout.trim()==="")return!1;return await Hn(P,["git","-c","commit.gpgsign=false","-c","user.name=cc-safety-net","-c","user.email=cc-safety-net@localhost","commit","-m",Q],V),await Hn(P,["git","push","origin","HEAD"],V),!0}function _r(P,V){um(P,V),pm(P,V)}function Ul(P,V){if(V==="keep")return;throw Error(`Local Amp plugin ${P} is not a managed copy and masks the personal plugin. Remove it and rerun install --amp.`)}function um(P,V){let z=am(P),Q=Lt(z);if(!Q)return;if(!Q.isSymbolicLink()&&Q.isFile()&&$r(xn(z))){Tr(z);return}Ul(z,V)}function pm(P,V){let z=Et(P.home,".config","amp","plugins",on),Q=Lt(z);if(!Q)return;if(!Q.isSymbolicLink()&&Q.isDirectory()&&fm(z)){Tr(z,{recursive:!0});return}Ul(z,V)}function fm(P){let V=om(sn);if(rm(P).join("\x00")!==V)return!1;let z=Et(P,V),Q=Lt(z);return!!Q&&!Q.isSymbolicLink()&&Q.isFile()&&$r(xn(z))}function mm(P){let V=u(P);if(!Il(V))return"";let z=Ol(xn(V,"utf-8"));if(!z||typeof z!=="object"||Array.isArray(z))return"";return`;globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = ${JSON.stringify(C(z,P.home))};
|
|
228
|
+
`}async function Gl(P,V=cm(),z=oi){let Q=Buffer.concat([xn(V),Buffer.from(mm(P),"utf-8")]),te=await Fl(z);return jl(z,P,async(ne)=>{let ce=`${te}/${on}`,ye=Ml(ne,"overwrite"),he=Nl(ne,kn,"overwrite");if(ye?.equals(Q)&&!he)return _r(P,"fail"),{path:ce,alreadyInstalled:!0};if(tm(Et(ne,on),{recursive:!0}),kt(Et(ne,sn),Q),he)Tr(Et(ne,kn));let be=await Hl(z,ne,["git","add","--",sn,...he?[kn]:[]],`chore: update cc-safety-net plugin to v${wt()}`);return _r(P,"fail"),{path:ce,alreadyInstalled:!be}})}async function Bl(P,V=oi){let z=await Fl(V);return jl(V,P,async(Q)=>{let te=Ml(Q,"remove"),ne=dm(Q),ce=`${z}/${ne&&!te?kn:on}`;if(!te&&!ne)return _r(P,"keep"),{path:ce,alreadyInstalled:!1};return await Hl(V,Q,["git","rm","--",...te?[sn]:[],...ne?[kn]:[]],`chore: remove cc-safety-net plugin v${wt()}`),_r(P,"keep"),{path:ce,alreadyInstalled:!0}})}import{existsSync as ql,mkdirSync as gm,readFileSync as ym}from"node:fs";import{dirname as hm}from"node:path";var ai=Nt["antigravity-cli"],an="cc-safety-net";function ln(P){return Boolean(P)&&typeof P==="object"&&!Array.isArray(P)}function Or(){return{PreToolUse:[{hooks:[{type:"command",command:ai,timeout:30}]}]}}function Vl(P){try{let V=JSON.parse(ym(P,"utf-8"));if(!V||typeof V!=="object"||Array.isArray(V))throw Error("Antigravity hooks config must be a JSON object");return V}catch(V){if(V instanceof SyntaxError)throw Error(`Failed to parse Antigravity hooks config ${P}: ${V.message}`);throw V}}function zl(P){let V=P[an];if(V===void 0){let Q=Or();return P[an]=Q,{definition:Q,preToolUse:Q.PreToolUse??[]}}if(!ln(V))throw Error(`Antigravity hooks config entry "${an}" must be an object`);let z=Array.isArray(V.PreToolUse)?V.PreToolUse:[];return V.PreToolUse=z,{definition:V,preToolUse:z}}function Jl(P){if(!Array.isArray(P.PreToolUse))return!1;return P.PreToolUse.some((V)=>ln(V)&&Array.isArray(V.hooks)&&V.hooks.some((z)=>ln(z)&&z.command===ai))}function vm(P){return Object.values(P).some((V)=>ln(V)&&V.enabled!==!1&&Jl(V))}function bm(P){if(P[an]===void 0)return!1;let V=zl(P);if(V.definition.enabled!==!1||!Jl(V.definition))return!1;return V.definition.enabled=!0,!0}function Lm(P){if(P[an]===void 0){P[an]=Or();return}let V=zl(P);V.definition.enabled=!0,V.preToolUse.push(Or().PreToolUse?.[0]??{hooks:[]})}function wm(P){let V=!1;for(let z of Object.values(P)){if(!ln(z)||!Array.isArray(z.PreToolUse))continue;z.PreToolUse=z.PreToolUse.flatMap((Q)=>{if(!ln(Q)||!Array.isArray(Q.hooks))return[Q];let te=Q.hooks.filter((ne)=>!ln(ne)||ne.command!==ai);if(te.length!==Q.hooks.length)V=!0;return te.length===0?[]:[{...Q,hooks:te}]})}return V}function Ir(P,V){kt(P,`${JSON.stringify(V,null,2)}
|
|
229
|
+
`)}function Wl(P){let V=En(P.home);if(gm(hm(V),{recursive:!0}),!ql(V))return Ir(V,{[an]:Or()}),{path:V,alreadyInstalled:!1};let z=Vl(V);if(vm(z))return{path:V,alreadyInstalled:!0};if(bm(z))return Ir(V,z),{path:V,alreadyInstalled:!1};return Lm(z),Ir(V,z),{path:V,alreadyInstalled:!1}}function Kl(P){let V=En(P.home);if(!ql(V))return{path:V,alreadyInstalled:!1};let z=Vl(V);if(!wm(z))return{path:V,alreadyInstalled:!1};return Ir(V,z),{path:V,alreadyInstalled:!0}}import{existsSync as km,readdirSync as xm,rmSync as Cm}from"node:fs";import{join as Sm}from"node:path";function Yl(P,V=process.platform,z){if(!km(P))return;let Q=V==="win32"?/^bunx-\d+-cc-safety-net@/:new RegExp(`^bunx-${process.getuid?.()??0}-cc-safety-net@`);xm(P).filter((te)=>te!==z&&Q.test(te)).forEach((te)=>{Cm(Sm(P,te),{recursive:!0,force:!0})})}import{spawn as Rm}from"node:child_process";var Mt=$t.map((P)=>({target:P.id,flag:P.flag,label:bt(P.id),probeCommand:P.probeCommand}));function li(P){let V=new Set(P);return Mt.map((z)=>z.target).filter((z)=>V.has(z))}async function Zl(P,V){for(let z of P)await V(z)}var Pm=5000;function ci(P,V=Pm){return new Promise((z)=>{let Q=Xt([...P],process.env),te=Rm(Q.cmd,Q.args,{env:process.env,stdio:"ignore"}),ne=!1,ce=(he)=>{if(ne)return;ne=!0,clearTimeout(ye),z(he)},ye=setTimeout(()=>{te.kill(),ce(!1)},V);te.on("error",()=>ce(!1)),te.on("close",(he)=>ce(he===0))})}function Xl(P=ci,V={}){let z=new Set(V.configuredTargets??[]);return Promise.all(Mt.map(async(Q)=>({target:Q.target,flag:Q.flag,label:Q.label,...ec(V.action,await P(Q.probeCommand),z.has(Q.target))})))}function Ql(P,V){let z=new Set(V.configuredTargets??[]);return P.map((Q)=>({...Q,...ec(V.action,Q.available,z.has(Q.target))}))}function ec(P,V,z){if(P==="uninstall")return z?{available:!0}:{available:!1,unavailableReason:"not installed"};if(P==="install"&&z)return{available:!1,unavailableReason:"already installed"};if(!V)return{available:!1,unavailableReason:"CLI not installed"};return{available:!0}}import{existsSync as tc,readdirSync as Em,rmSync as Dm}from"node:fs";import{join as Cn}from"node:path";function Fr(P,V=process.platform){let z=Cn(P.env.get("npm_config_cache")||(V==="win32"?Cn(P.env.get("LOCALAPPDATA")||Cn(P.home,"AppData","Local"),"npm-cache"):Cn(P.home,".npm")),"_npx");if(!tc(z))return;Em(z).filter((Q)=>tc(Cn(z,Q,"node_modules","cc-safety-net"))).forEach((Q)=>{Dm(Cn(z,Q),{recursive:!0,force:!0})})}import{existsSync as ac,mkdirSync as _m,readFileSync as lc}from"node:fs";import{dirname as Tm,join as sc}from"node:path";function Am(P,V){if(P[V]!=="#")return V;let z=P.indexOf(`
|
|
230
|
+
`,V+1);return z===-1?P.length:z+1}function di(P,V,z){let Q=new RegExp(`^(\\s*)${V}\\s*=\\s*\\[`),te=0;for(let ne of P.split(`
|
|
231
|
+
`)){if(/^\s*\[/.test(ne))return;let ce=Q.exec(ne);if(ce){let ye=te+ce[0].lastIndexOf("[");return{start:ye,end:ho(P,ye,{skipComment:Am,...z})}}te+=ne.length+1}return}function nc(P,V,z){let Q=P.slice(0,V.end).trimEnd(),te=Zs(P,V.end),ne=te===""?" ":`${te} `,ce=!Q.endsWith("[")&&!Q.endsWith(",");return`${Q}${ce?",":""}
|
|
232
|
+
${ne}${z}${P.slice(V.end)}`}function rc(P,V,z){let Q=P.indexOf(z,V.start);if(Q===-1||Q>V.end)return P;return fr(P,{start:Q,end:Q+z.length})}function oc(P,V){let z=new RegExp(`^\\s*${V}\\s*=\\s*\\[\\s*]\\s*(?:#.*)?$`),Q=P.split(`
|
|
233
|
+
`),te=Q.findIndex((ye)=>/^\s*\[/.test(ye)),ne=te===-1?Q:Q.slice(0,te),ce=te===-1?[]:Q.slice(te);return[...ne.filter((ye)=>!z.test(ye)),...ce].join(`
|
|
234
|
+
`)}function ic(P,V,z){let Q=new RegExp(`^\\s*\\[\\[${V}]]\\s*$`,"m");return P.split(/(?=^\s*\[)/m).filter((te)=>!Q.test(te)||!te.includes(z)).join("").trimEnd()}var Un=Nt["kimi-code"],ui=`[[hooks]]
|
|
235
235
|
event = "PreToolUse"
|
|
236
|
-
command = "${
|
|
237
|
-
`;return`${
|
|
238
|
-
|
|
239
|
-
${
|
|
240
|
-
`}function
|
|
241
|
-
`),{path:
|
|
242
|
-
`;return kt(
|
|
243
|
-
`)},opencode:{
|
|
244
|
-
`),`Enabled ${
|
|
245
|
-
`),`Enabled npm:cc-safety-net extensions in ${
|
|
246
|
-
`)}async function
|
|
247
|
-
Removing the plugin files anyway; ${
|
|
248
|
-
`)}var
|
|
249
|
-
`);function
|
|
236
|
+
command = "${Un}"`,cc=`{ event = "PreToolUse", command = "${Un}" }`,dc={stringError:"Unterminated string in Kimi Code config",bracketError:"Unmatched hooks array in Kimi Code config"};function uc(P){return sc(P.env.get("KIMI_CODE_HOME")??sc(P.home,".kimi-code"),"config.toml")}function $m(P){let V=di(P,"hooks",dc);if(V&&P.slice(V.start+1,V.end).trim())return nc(P,V,cc);let z=oc(P,"hooks").trimEnd();if(z==="")return`${ui}
|
|
237
|
+
`;return`${z}
|
|
238
|
+
|
|
239
|
+
${ui}
|
|
240
|
+
`}function pc(P){let V=uc(P);if(_m(Tm(V),{recursive:!0}),!ac(V))return kt(V,`${ui}
|
|
241
|
+
`),{path:V,alreadyInstalled:!1};let z=lc(V,"utf-8");if(z.includes(Un))return{path:V,alreadyInstalled:!0};return kt(V,$m(z)),{path:V,alreadyInstalled:!1}}function fc(P){let V=uc(P);if(!ac(V))return{path:V,alreadyInstalled:!1};let z=lc(V,"utf-8");if(!z.includes(Un))return{path:V,alreadyInstalled:!1};let Q=di(z,"hooks",dc),te=Q?rc(z,Q,cc):`${ic(z,"hooks",Un)}
|
|
242
|
+
`;return kt(V,te),{path:V,alreadyInstalled:!0}}var fi="safety-net@cc-marketplace",mc=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),gc=new Set(["antigravity-cli","cursor","grok-build","hermes-agent","kimi-code"]);function gi(P){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(P??"")}function Lc(P){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(P??"")}function Im(P){return/^Marketplace `cc-marketplace`\s*$/m.test(P??"")}var wc={"claude-code":{installCommands:(P)=>{let V=pr(P,"cc-safety-net@cc-marketplace");return{commands:[...V?[["claude","plugin","marketplace","update","cc-marketplace"],["claude","plugin","update","cc-safety-net@cc-marketplace"]]:[["claude","plugin","marketplace","add","kenryu42/cc-marketplace"],["claude","plugin","marketplace","update","cc-marketplace"],["claude","plugin","install","cc-safety-net@cc-marketplace"]],...go(P).status==="disabled"?[["claude","plugin","enable","cc-safety-net@cc-marketplace"]]:[]],cleanupCommands:pr(P,fi)?[["claude","plugin","uninstall",fi]]:[],update:V}},uninstallCommands:[["claude","plugin","uninstall","cc-safety-net@cc-marketplace"],["claude","plugin","marketplace","remove","cc-marketplace"]]},codex:{installCommands:async(P,V)=>{let z=V??await _t(["codex","plugin","list"]),Q=Lc(z);return{commands:[Q||Im(z)?["codex","plugin","marketplace","upgrade","cc-marketplace"]:["codex","plugin","marketplace","add","kenryu42/cc-marketplace"],["codex","plugin","add","cc-safety-net@cc-marketplace"]],cleanupCommands:gi(z)?[["codex","plugin","remove","safety-net@cc-marketplace"]]:[],update:Q}},uninstallCommands:[["codex","plugin","remove","cc-safety-net@cc-marketplace"],["codex","plugin","marketplace","remove","cc-marketplace"]],postInstallMessage:"Start Codex, open `/hooks`, select the cc-safety-net PreToolUse hook, and press `t` to trust it."},"copilot-cli":{installCommands:async()=>{let P=await _t(["copilot","plugin","list"]),V=[...oa(P)?[["copilot","plugin","uninstall","copilot-safety-net"]]:[],...ia(P)?[["copilot","plugin","uninstall",ta]]:[]];if(na(P))return{commands:[["copilot","plugin","marketplace","update","cc-marketplace"],["copilot","plugin","update",jt]],cleanupCommands:V,update:!0};return{commands:[ra(await _t(["copilot","plugin","marketplace","list"]))?["copilot","plugin","marketplace","update","cc-marketplace"]:["copilot","plugin","marketplace","add","kenryu42/cc-marketplace"],["copilot","plugin","install",jt]],cleanupCommands:V}},uninstallCommands:[["copilot","plugin","uninstall","cc-safety-net@cc-marketplace"],["copilot","plugin","marketplace","remove","cc-marketplace"]]},"gemini-cli":{installCommands:(P)=>{let V=Co(P);if(V.status==="configured")return{commands:[["gemini","extensions","update","gemini-safety-net"]],update:!0};if(V.status==="disabled")return{commands:[["gemini","extensions","update","gemini-safety-net"],["gemini","extensions","enable","gemini-safety-net"]],update:!0};return{commands:[["gemini","extensions","install","https://github.com/kenryu42/gemini-safety-net","--consent"]]}},uninstallCommands:[["gemini","extensions","uninstall","gemini-safety-net"]]},openclaw:{beforeInstall:Mo,installCommands:()=>({commands:za()}),uninstallCommands:[["openclaw","plugins","uninstall",ht,"--force"]],postInstallMessage:["Restart the OpenClaw Gateway to apply the change.","If plugins.allow is set in openclaw.json, it must also list cc-safety-net."].join(`
|
|
243
|
+
`)},opencode:{installCommands:ol},pi:{installCommands:[["pi","install","npm:cc-safety-net"]],uninstallCommands:[["pi","uninstall","npm:cc-safety-net"]]}};function kc(P,V=(z)=>z){try{let z=JSON.parse(V(bc(P,"utf-8")));if(!z||typeof z!=="object"||Array.isArray(z))throw Error(`Settings file ${P} must be a JSON object`);return z}catch(z){if(z instanceof SyntaxError)throw Error(`Failed to parse ${P}: ${z.message}`);throw z}}function Om(P){let V=pi(Dn(P),"settings.json");if(!mi(V))return;let z=kc(V,At),Q=z.enabledPlugins;if(!Q||typeof Q!=="object"||Array.isArray(Q))return;if(Q[jt]!==!1)return;let te=bc(V,"utf-8"),ne=te.replace(new RegExp(`("${jt}"\\s*:\\s*)false`),"$1true");return Q[jt]=!0,kt(V,ne!==te?ne:`${JSON.stringify(z,null,2)}
|
|
244
|
+
`),`Enabled ${jt} plugin in ${V}`}function Fm(P){let V=Vo(P);if(!mi(V))return;let z=kc(V);if(!Array.isArray(z.packages))return;let Q=z.packages.find((te)=>!!te&&typeof te==="object"&&!Array.isArray(te)&&zo(te.source)&&("extensions"in te));if(!Q)return;return delete Q.extensions,kt(V,`${JSON.stringify(z,null,2)}
|
|
245
|
+
`),`Enabled npm:cc-safety-net extensions in ${V}`}function yc(P,V){let z=xt({label:V,booleans:Object.fromEntries(Mt.map((ne)=>[ne.target,[ne.flag]]))},P),Q=z.errors[0];if(Q)throw Error(Q);let te=Mt.filter((ne)=>z.flags[ne.target]).map((ne)=>ne.target);if(te.length!==1)throw Error(`Choose exactly one ${V} target: ${Mt.map((ne)=>ne.flag).join(", ")}`);return te[0]}async function xc(P,V=mn){let[z,Q,te]=await Promise.all([V(["amp","plugins","list"],30000),V(["codex","plugin","list"],30000),V(["copilot","--binary-version"])]);return{codexPluginListOutput:Q,hooks:Ln(P,process.cwd(),{ampPluginListOutput:z,codexPluginListOutput:Q,copilotCliVersion:te})}}async function jm(P,V,z=mn){let Q=await xc(P,z);return Q.hooks.filter((te)=>V==="install"?te.configured:te.detected||te.inspectionStatus==="not-inspected").filter((te)=>te.platform!=="codex"||!gi(Q.codexPluginListOutput)||Lc(Q.codexPluginListOutput)).map((te)=>te.platform)}function Nm(P,V,z,Q){if(z.length>0)return{finish:async()=>[yc(z,V)]};if(!Q.selectTargets&&!ni(Q.input,Q.output))return{finish:async()=>[yc(z,V)]};let te=Q.detectConfiguredTargets??(()=>jm(P,V,Q.fetchVersion)),ne=Promise.all([Xl(Q.probeTargets),te()]);return{ready:ne,finish:async()=>{let[ce,ye]=await ne,he=Ql(ce,{action:V,configuredTargets:ye}),be=Q.selectTargets?await Q.selectTargets(V,vc(V,he)):await $l(V,vc(V,he),{input:Q.input,output:Q.output});if(be==="update")return be;if(!be||be.length===0)return null;return li(be)}}}async function Mm(P,V,z=!1,Q){let te=wc[P];te.beforeInstall?.(V);let ne=typeof te.installCommands==="function"?await te.installCommands(V,Q):{commands:te.installCommands};return await Oo(ne.commands),await Ua(ne.cleanupCommands??[]),await ne.afterInstall?.(),[`${ne.update||z?"Updated":"Installed"} ${bt(P)} integration`,te.postInstallMessage].filter(Boolean).join(`
|
|
246
|
+
`)}async function Hm(P){let V=wc[P];if(!V.uninstallCommands)throw Error(`${bt(P)} uninstall is not supported`);return await Oo(V.uninstallCommands),`Uninstalled ${bt(P)} integration`}function Um(P){let V=il(P);return V.alreadyInstalled?`Uninstalled OpenCode plugin from ${V.path}`:`OpenCode plugin not installed in ${V.path}`}var Cc={"antigravity-cli":{install:Wl,uninstall:Kl},cursor:{install:ga,uninstall:ya},"grok-build":{install:Ra,uninstall:Pa},"kimi-code":{install:pc,uninstall:fc}};function Gm(P,V,z,Q=!1){if(P==="install"&&!Q)Fr(z);let te=Cc[V][P](z),ne=bt(V),ce=P!=="install"?"Uninstalled":Q?"Updated":"Installed";return P==="install"&&te.alreadyInstalled?Q?`${ne} hook up to date in ${te.path}`:`${ne} hook already installed in ${te.path}`:P==="uninstall"&&!te.alreadyInstalled?`${ne} hook not installed in ${te.path}`:`${ce} ${ne} hook ${P==="install"?"in":"from"} ${te.path}`}var Sc={amp:{install:Gl,uninstall:Bl,restartNote:'Amp personal plugins apply to every Amp session, including Orb threads. Restart Amp or run "plugins: reload" to apply the change.'},"hermes-agent":{install:_a,uninstall:Ta,afterInstall:async(P)=>{let V=To(P);return await _t(["hermes","plugins","enable",Tt,"--no-allow-tool-override"]),!V},beforeUninstall:async(P)=>{_o(P);try{await _t(["hermes","plugins","disable",Tt])}catch(V){console.warn(`${V instanceof Error?V.message:String(V)}
|
|
247
|
+
Removing the plugin files anyway; ${Tt} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function Bm(P,V,z,Q=!1){let te=Sc[V];if(P==="uninstall")await te.beforeUninstall?.(z);let ne=P==="install"?await te.install(z):await te.uninstall(z),ce=P==="install"&&await te.afterInstall?.(z),ye=bt(V),he=!ce&&(P==="install"&&ne.alreadyInstalled||P==="uninstall"&&!ne.alreadyInstalled);return[he?P==="install"?`${ye} plugin ${Q?"up to date":"already installed"} at ${ne.path}`:`${ye} plugin not installed at ${ne.path}`:`${P!=="install"?"Uninstalled":Q?"Updated":"Installed"} ${ye} plugin ${P==="install"?"at":"from"} ${ne.path}`,he?void 0:te.restartNote].filter(Boolean).join(`
|
|
248
|
+
`)}var qm={"copilot-cli":{afterInstall:Om},"hermes-agent":{beforeInstall:(P,V)=>{if(!V)Fr(P)}},openclaw:{afterInstall:async()=>{await Ja();return},beforeUninstall:Mo},pi:{afterInstall:Fm}};function Vm(P){return P in Cc}function zm(P){return P in Sc}var hc=["Install CC Safety Net as a native Kimi Code plugin:",""," 1. Start Kimi Code and run: /plugins install https://github.com/kenryu42/cc-safety-net"," Confirm the trust prompt; it defaults to cancel."," 2. Run /reload, or start a new session.","","Note: Kimi Code hooks are fail-open. When the hook process cannot start, crashes, or times","out, Kimi Code allows the tool call."].join(`
|
|
249
|
+
`);function Jm(P){if(In({environment:P,cwd:process.cwd()}).status!=="configured")return hc;return[hc,"",dt.red(["CAUTION: the global Kimi Code hook is installed and will run alongside the plugin.","After the plugin is active, remove it with: cc-safety-net uninstall --kimi-code"].join(`
|
|
250
250
|
`))].join(`
|
|
251
|
-
`)}function
|
|
252
|
-
`)}function
|
|
251
|
+
`)}function vc(P,V){return V.map((z)=>P==="install"&&z.target==="kimi-code"&&z.unavailableReason==="already installed"?{...z,available:!0,unavailableReason:void 0,label:`${z.label} (global hook installed)`}:z)}function Wm(P,V){if(P.selectKimiInstallMethod)return P.selectKimiInstallMethod();if(!ni(P.input,P.output))return Promise.resolve("global-hook");return Tl({input:P.input,output:P.output,globalHookInstalled:In({environment:V,cwd:process.cwd()}).status==="configured"})}async function Rc(P,V,z,Q=!1,te){let ne=qm[V];if(P==="install")ne?.beforeInstall?.(z,Q);if(P==="uninstall")ne?.beforeUninstall?.(z);if(Vm(V))return Gm(P,V,z,Q);if(zm(V))return Bm(P,V,z,Q);if(P==="uninstall")return V==="opencode"?Um(z):Hm(V);return[await Mm(V,z,Q,te),await ne?.afterInstall?.(z)].filter(Boolean).join(`
|
|
252
|
+
`)}function Km(P){let V=xt({label:"update"},P).errors[0];if(V)throw Error(V)}async function Ym(P,V=mn){let z=await xc(P,V),Q=pi(Dn(P),"installed-plugins");return{targets:li([...z.hooks.filter((ne)=>ne.platform!=="copilot-cli"&&ne.detected).map((ne)=>ne.platform),...[mr,ea,Qs].flatMap((ne)=>mi(pi(Q,...ne))?["copilot-cli"]:[]),...pr(P,fi)?["claude-code"]:[],...gi(z.codexPluginListOutput)?["codex"]:[]]),codexPluginListOutput:z.codexPluginListOutput}}async function Zm(P){let V=c(),z=P.output??process.stdout,Q=(P.scriptPath??process.argv[1]??"").split(/[\\/]/),te=Q.find((et)=>/^bunx-\d+-/.test(et)),ne=te!==void 0||Q.includes("_npx")?null:(P.checkLatestVersion??Wt)(),ce=async()=>{let et=ne&&await ne;if(et?.updateAvailable)z.write(`
|
|
253
253
|
Update available: cc-safety-net ${et.currentVersion} → ${et.latestVersion}. Update this CLI with your package manager, e.g. \`npm i -g cc-safety-net@latest\` for a global install.
|
|
254
|
-
`)},ye=
|
|
255
|
-
`)}),await
|
|
256
|
-
`),0;if(te==="update")return(
|
|
257
|
-
`);return}if(he==="plugin"){
|
|
258
|
-
`);return}}let ye=await
|
|
259
|
-
`)}),0}catch(
|
|
260
|
-
Check file permissions for the target config file and parent directory.`;if(
|
|
261
|
-
Check that the target config path and parent directory exist.`;if(
|
|
262
|
-
Check that every parent path component is a directory.`;return
|
|
263
|
-
`,384),Qm(ee,384),{path:ee,policy:ae,errors:[]}}function _c(A,z){let X=ln(z,A.home);if(X.errors.length>0)return{errors:X.errors};return{preview:Te(X.policy,A.env),errors:[]}}function Tc(A,z={}){let X=d(A,z);if(!Ec(X))return Vt(A,J,z);let ee=Dc(X,"utf-8");if(!ee.trim())return Vt(A,J,z);try{return Vt(A,x(JSON.parse(ee),A.home),z)}catch{return Vt(A,J,z)}}var $c=new Set(["check","apply"]),Ic="(unset)";async function Fc(A,z,X={}){let ee=xt({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},z),te=ee.positionals[0],ae=[...ee.errors,...te&&!$c.has(te)?[`Unknown policy subcommand: ${te}`]:[],...te&&$c.has(te)&&!ee.positionals[1]?[`policy ${te} requires a file`]:[],...ee.positionals.slice(2).map((Ee)=>`Unexpected policy argument: ${Ee}`)];if(ae.length>0){for(let Ee of ae)console.error(Ee);return 1}let le=ee.positionals[1];if(!te||!le)return Ln(Zn,console.error),1;let ye=ee.flags.global?d(A):v(X.cwd??process.cwd()),he=cn(le),ve=[...he.errors,...Bn(he.value,A.home).map((Ee)=>`${le}: ${Ee}`),...!ee.flags.global&&ag(he.value)&&he.value.audit!==void 0?[`${le}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(ve.length>0){for(let Ee of ve)console.error(Ee);return 1}let be=x(he.value,A.home);if(console.log(`Scope: ${ee.flags.global?"user":"project"} (${ye})`),console.log(`Proposal: ${le}`),ee.flags.global)Oc(x(cn(ye).value,A.home),be,!0);if(!ee.flags.global){let Ee=qn(A).baseline;console.log("Effective policy (user + project merged):"),Oc(Y(Ee,se(cn(ye).value,A.home).policy).policy,Y(Ee,se(he.value,A.home).policy).policy,!1)}if(te==="check")return 0;let Ie=X.input??process.stdin,Xe=X.output??process.stdout;if(!Ie.isTTY||!Xe.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${le}${ee.flags.global?" --global":""}`),1;if(!await ig(`Apply this policy to ${ye}? [y/N] `,Ie,Xe))return console.log("Cancelled; nothing was written."),0;return sg(A,ye,he.value,be,ee.flags.global),console.log(`Policy applied: ${ye}`),0}function ig(A,z,X){let ee=og({input:z,output:X,terminal:!1});return new Promise((te)=>{ee.once("close",()=>te(!1)),ee.question(A,(ae)=>{te(/^y(es)?$/i.test(ae.trim())),ee.close()})})}function sg(A,z,X,ee,te){if(te){Vt(A,ee);return}ng(rg(z),{recursive:!0}),Rt(z,jr(X,ee))}function Oc(A,z,X){let ee=Fr(A,z,X);if(ee.length===0){console.log("No changes.");return}console.log(`Changes (${ee.length}):`);for(let te of ee)console.log(` ${te.field}: ${te.before??Ic} -> ${te.after??Ic}`)}function ag(A){return!!A&&typeof A==="object"&&!Array.isArray(A)}import{join as Ly}from"node:path";var jc="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Priority |\n|-------|-------------|---------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | Second |\n| GitHub source | Listed in a local `rule.json` | Vendored into the consumer's `<rulebook-name>/rulebook.json` by `rule add` | Source order |\n\nEvery rulebook is a live file: the runtime reads it on each tool call, so an edit applies to the next command with no publishing step.\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule verify` reports the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- Transparent wrappers have no built-in defaults. Configure only wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n\n## Rulebook Sources\n\n- Local sources are bare rulebook names such as `project-rules`; the rulebook file is `.cc-safety-net/rules/project-rules/rulebook.json`.\n- Run `cc-safety-net rule add owner/repo` to add every rulebook currently present on the repository's default branch.\n- Use `--only` to select one or more rulebooks while preserving their order: `cc-safety-net rule add owner/repo --only aws gcloud`.\n- Use `--ref` to select a branch, tag, or commit instead of the default branch: `cc-safety-net rule add owner/repo --ref v2 --only aws`.\n- GitHub sources are stored in canonical form as `owner/repo#ref/<rulebook-name>`. That form remains valid in `rule.json` and as direct CLI input.\n- GitHub refs may contain `/`-separated path segments, such as `feature/rulebook-v2`.\n- The GitHub source name, the repository directory name, and the rulebook `name` must match exactly.\n- Rulebook source strings must be unique in a config.\n\n## rulebook.json Schema\n\n```json\n{\n \"rulebook_version\": 1,\n \"name\": \"project-rules\",\n \"version\": \"1.0.0\",\n \"description\": \"Project-specific CC Safety Net rules.\",\n \"author\": \"project\",\n \"allowed_commands\": [\"docker\"],\n \"rules\": [\n {\n \"name\": \"block-docker-system-prune\",\n \"command\": \"docker\",\n \"subcommand\": \"system\",\n \"block_args\": [\"prune\"],\n \"reason\": \"Use targeted cleanup instead.\"\n }\n ],\n \"tests\": [\n {\n \"command\": \"docker system prune\",\n \"expect\": \"blocked\",\n \"rule\": \"block-docker-system-prune\"\n },\n {\n \"command\": \"docker ps\",\n \"expect\": \"allowed\"\n }\n ]\n}\n```\n\n### Rulebook Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `rulebook_version` | Yes | Must be `1` or `2` |\n| `name` | Yes | `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$` |\n| `version` | Yes | Non-empty string |\n| `description` | No | Free text; not type-checked at runtime |\n| `author` | No | Free text; not type-checked at runtime |\n| `allowed_commands` | Yes | Unique command names matching `^[a-zA-Z][a-zA-Z0-9_-]*$` |\n| `rules` | Yes | Array of rule objects |\n| `tests` | No | Array of fixtures |\n\n### Rule Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Unique within the rulebook (case-insensitive); same pattern as rulebook `name` |\n| `command` | Yes | Must be listed in `allowed_commands`; basename only, not path |\n| `subcommand` | No | Same pattern as `command`; omit to match any subcommand |\n| `intent` | No | One of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain` |\n| `block_args` | Yes | Non-empty array of non-empty strings |\n| `reason` | Yes | Non-empty string, max 256 chars |\n\n### Rule Fields (`rulebook_version` 2)\n\nVersion 2 replaces `subcommand` and `block_args` with an exact-token `match` object. Version 1 rulebooks keep their fields and their behavior; a client that does not support version 2 rejects the rulebook instead of applying broader version 1 semantics.\n\n```json\n{\n \"name\": \"block-terraform-apply-destroy\",\n \"command\": \"terraform\",\n \"match\": {\n \"command_path\": [\"apply\"],\n \"any_args\": [\"-destroy\", \"--destroy\"]\n },\n \"reason\": \"Review a destroy plan first with 'terraform plan -destroy'.\",\n \"intent\": \"use_alternative\"\n}\n```\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Same as version 1 |\n| `command` | Yes | Same as version 1 |\n| `match.command_path` | Yes | Non-empty array of non-empty command words |\n| `match.any_args` | No | Non-empty array of unique non-empty argument tokens |\n| `match.exclude_args` | No | Non-empty array of unique non-empty argument tokens |\n| `intent` | No | Same as version 1 |\n| `reason` | Yes | Same as version 1 |\n\n### Matching Behavior (`rulebook_version` 2)\n\n- **Command**: Normalized to lowercase basename, as in version 1.\n- **Command path**: After recognized global options and their values are skipped, the next command words must equal `command_path` exactly. AWS, gcloud, and Azure CLI value-taking global options are built in; Terraform's `-chdir=dir` is `=`-joined and is skipped with its own token.\n- **Unrecognized options**: A token starting with `-` that is not a recognized global option is skipped without consuming a value, so an unlisted value-taking option with a separate value (`--newflag value`) makes the rule miss. This fails open deliberately; document such gaps in the rulebook.\n- **`any_args`**: At least one listed token must appear literally among the arguments.\n- **`exclude_args`**: Any listed token appearing literally among the arguments prevents the match, which is how a safe preview such as `aws s3 rm --dryrun` stays allowed.\n- **No short-option expansion**: Arguments compare as exact tokens, so list every accepted spelling (`\"-destroy\"` and `\"--destroy\"`).\n- **Literal and case-sensitive**: No regex, glob, or substring matching. The first matching rule wins.\n- Release channels are separate rules: `gcloud beta compute instances delete` needs its own `command_path`.\n\n### Test Fixture Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `command` | Yes | Non-empty shell command string |\n| `expect` | Yes | `\"blocked\"` or `\"allowed\"` |\n| `rule` | Required for blocked fixtures | Rule name expected to block the command |\n\nFixtures are optional documentation of intended behavior. Version 1 fixtures are shape-validated only. Version 2 fixtures are evaluated against the rulebook's own rules when a source is fetched by `rule add` or `rule update`, and by `rule verify`; a failing fixture rejects that source before it is written. Loading a rulebook does not re-evaluate fixtures. CC Safety Net never executes fixture commands; they are analyzer inputs only.\n\n## Matching Behavior\n\nThe subcommand, argument, and option rules below describe `rulebook_version` 1 rules; version 2 rules match as described in Matching Behavior (`rulebook_version` 2). Execution order and transparent wrappers apply to both.\n\n- **Command**: Normalized to lowercase basename with any trailing `.exe` removed (`/usr/bin/git` → `git`).\n- **Subcommand**: The first command token after recognized Git and Docker global options and their values; `--` ends option parsing. An unrecognized option without `=` may consume the following token as its value.\n- **Arguments**: Each `block_args` value is compared literally against every command token, including expanded short options. The command is blocked if **any** item matches.\n- **Short options**: Expanded (`-Ap` matches `-A`).\n- **Long options**: Exact match (`--all-files` does not match `--all`).\n- **Execution order**: Built-in rules first, then custom rulebooks. Custom rules only add restrictions.\n- **Transparent wrappers**: A configured wrapper such as `rtk` lets `rtk git commit` be analyzed as `git commit` only when `git` is protected by built-in analyzers or active custom rules. `rtk -- git commit` is also supported.\n\n## Workflow\n\n1. Run `cc-safety-net rule init` or create `rule.json` manually.\n2. Optionally run `cc-safety-net rule init --example` to create an inactive example rulebook.\n3. Use `cc-safety-net rule wrapper add rtk` for trusted transparent wrappers.\n4. Run `cc-safety-net rule add <source>` after creating or choosing a rulebook source; add `--only <rulebook...>` or `--ref <ref>` for repository selection. The command adds the selected sources and syncs them.\n5. Edit a local rulebook whenever you like: the edit is enforced on the next command, so there is nothing to run afterwards.\n6. Run `cc-safety-net rule update [source]` to re-fetch remote sources and rewrite the vendored copies; the command prints what changed. A source with an ordinary update failure keeps its vendored copy while the other selected sources still update. Resource-limit failures remain fatal for the whole update.\n7. Run `cc-safety-net rule verify` to validate config, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n8. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nA missing or invalid rulebook file makes that source inactive, and an unreadable or invalid `rule.json` makes every source in its scope inactive. Inactive sources stop applying their rules while other custom rules and all built-in protections stay active. Fix the file named in the diagnostic, or run `cc-safety-net rule update` when a remote source has not been vendored yet. Run `cc-safety-net status` to see degraded sources.\n";function Nr(A,z){if(!A.ok){Gc(A);return}Hc(A,z)}function Mc(A,z,X){if(A.ok)console.log(X);if(!A.add){Nr(A,`Added rulebook source: ${z}`);return}if(!A.ok){Gc(A);return}if(A.add.added.length>0)console.log(`Added ${A.add.added.length} ${A.add.added.length===1?"rulebook":"rulebooks"} from ${A.add.source} at ${A.add.ref}:`),A.add.added.forEach((ee)=>{console.log(` - ${ee}`)});if(A.add.alreadyConfigured.length>0)console.log(`Rulebooks already configured from ${A.add.source} at ${A.add.ref}: ${A.add.alreadyConfigured.join(", ")}`);if(A.add.commits.length>0)console.log(`Vendored at ${A.add.commits.map((ee)=>ee.slice(0,7)).join(", ")}.`);Hc(A,"Rule config updated.")}function Hc(A,z){for(let X of A.changes??[])console.log(X);console.log(z),console.log(""),lg(A.entries)}function lg(A){if(A.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${A.length}):`);for(let z of A)console.log(` - ${z.name} ${z.version} (${cg(z.ruleCount)})`),console.log(` Source: ${z.spec}`)}function cg(A){return`${A} ${A===1?"rule":"rules"}`}function Uc(A){dn("Active sources",A.rulebooks,(z)=>[`[${z.source}] ${z.name} ${z.version}`,` Source: ${z.spec}`]),dn("Active rules",A.rules,(z)=>[`[${ug(A,z.name)}] ${z.name}`,...dg(z),` Reason: ${z.reason}`]),dn("Disabled rules",Nc(A,"off"),(z)=>[z.key]),dn("Reason overrides",Nc(A,"reason"),(z)=>[z.key,` Reason: ${z.value.reason}`]),dn("Transparent wrappers",A.transparent_wrappers,(z)=>[z]),dn("Issues",A.errors,(z)=>[z]),dn("Warnings",A.warnings,(z)=>[z])}function dn(A,z,X){if(z.length===0){console.log(`${A}: (none)`);return}console.log(`${A} (${z.length}):`);for(let ee of z){let[te,...ae]=X(ee);console.log(` - ${te}`);for(let le of ae)console.log(` ${le}`)}}function dg(A){if(!A.match)return[` Command: ${A.subcommand?`${A.command} ${A.subcommand}`:A.command}`,` Block args: ${A.block_args.join(", ")}`];return[` Command: ${[A.command,...A.match.command_path].join(" ")}`,...A.match.any_args?[` Any args: ${A.match.any_args.join(", ")}`]:[],...A.match.exclude_args?[` Exclude args: ${A.match.exclude_args.join(", ")}`]:[]]}function ug(A,z){return A.rulebooks.find((X)=>X.rules.includes(z))?.source??"project"}function Nc(A,z){return Object.entries({...A.userConfig?.overrides??{},...A.projectConfig?.overrides??{}}).filter((X)=>{if(z==="off")return X[1]==="off";return!!X[1]&&typeof X[1]==="object"}).map(([X,ee])=>({key:X,value:ee}))}function Gc(A){for(let z of A.errors)console.error(z)}import{dirname as ud,join as zr}from"node:path";import{join as Li,resolve as xg}from"node:path";function yi(A){let z=m(A);if(z.errors.length>0)return{ok:!1,result:{ok:!1,errors:z.errors,entries:[]}};return{ok:!0,config:z.config??it}}function Bc(A){Rt(A,{version:1,rules:[],overrides:{},transparent_wrappers:[]})}function qc(A){Rt(A,{rulebook_version:1,name:"example-rules",version:"1.0.0",description:"Project-specific CC Safety Net rules.",author:"project",allowed_commands:["docker"],rules:[{name:"block-docker-system-prune",command:"docker",subcommand:"system",block_args:["prune"],reason:"Use targeted cleanup instead."}],tests:[{command:"docker system prune",expect:"blocked",rule:"block-docker-system-prune"}]})}import{dirname as Gr}from"node:path";var pg="custom.";function Mr(A){if(A.rulebook_version!==2)return[];let z=A.rules.map((X)=>({name:X.name,command:X.command,block_args:[],match:X.match,reason:X.reason,intent:X.intent}));return(A.tests??[]).flatMap((X,ee)=>{let te=hi(h(X.command));if(te.length===0)return[`tests[${ee}]: could not parse fixture command: ${X.command}`];let ae=te.reduce((le,ye)=>le??_(ye,z)?.id.slice(pg.length),void 0);if(X.expect==="blocked"){if(ae===X.rule)return[];let le=ae?`"${ae}" matched first`:"no rule matched";return[`tests[${ee}]: expected "${X.rule}" to block "${X.command}" but ${le}`]}return ae?[`tests[${ee}]: expected "${X.command}" to be allowed but "${ae}" matched`]:[]})}function hi(A){return A.nodes.flatMap((z)=>{if(z.kind==="group"||z.kind==="function")return hi(z.body);if(z.kind!=="command")return[];let X=ge(Z(z.dialect,z.words)).words.map(t);return[...X.length>0?[X]:[],...z.nested.flatMap((ee)=>hi(ee))]})}var Hr=Object.freeze({concurrency:4,maxRequests:131,maxResponseBytes:67108864});function Ur(A={}){return{requests:0,responseBytes:0,maxRequests:A.maxRequests??Hr.maxRequests,maxResponseBytes:A.maxResponseBytes??Hr.maxResponseBytes}}function zt(A){return{controller:new AbortController,budget:Ur(),resolveUrl:A}}function Vc(A){return A instanceof Error&&A.message==="Rule synchronization exceeds CC Safety Net's safe resource limits."}function zc(A){if(A.requests>=A.maxRequests)throw Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");A.requests++}function Jc(A,z){if(z>A.maxResponseBytes-A.responseBytes)throw A.responseBytes+=z,Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");A.responseBytes+=z}var Yc=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function Wc(A,z,X=w(Gr(Gr(z)),"rules policy"),ee=zt()){if(C(A))return yg(A,ee);return gg(A,z,X)}async function Zc(A,z,X,ee,te,ae){if(!C(A))return Wc(A,z,X,ee);let le=te?null:fg(A,z,X);if(le)return le;if(!te&&!ae)throw Error(`${A} is not vendored; run rule update ${A} to vendor it`);return Wc(A,z,X,ee)}function fg(A,z,X=w(Gr(Gr(z)),"rules policy")){let ee=T(A),te=I(z,ee.name),ae=n(i(X,te));if(ae===null)return null;let le=ie(vi(ae,`Invalid rulebook ${te}.`));if(le.name!==ee.name)throw Error(`rulebook name "${le.name}" in ${te} must match "${ee.name}"`);return{spec:A,rulebook:le,content:ae}}async function Xc(A,z={}){if(!V(A))throw Error(`Invalid GitHub repository source: ${A}`);let[X,ee]=A.split("/");if(!X||!ee)throw Error(`Invalid GitHub repository source: ${A}`);if(z.ref!==void 0&&!re(z.ref))throw Error(`GitHub rulebook refs must use valid path segments: ${z.ref}`);let te=z.operation??zt(),ae=z.ref??await mg(X,ee,A,te),le=await ed(X,ee,ae,A,te),ye=await Br(`https://api.github.com/repos/${X}/${ee}/git/trees/${le}?recursive=1`,"tree",te),he=ye.response;if(!he.ok)throw Error(`Failed to inspect ${A}: GitHub tree returned ${he.status}`);let ve=JSON.parse(ye.content);if(!Array.isArray(ve?.tree))throw Error(`Failed to inspect ${A}: unexpected GitHub tree response`);let be=ve.tree,Ie=[...new Set(be.flatMap((Xe)=>{if(!Xe||typeof Xe!=="object")return[];let et=Xe;if(et.type!=="blob"||typeof et.path!=="string")return[];let Ee=et.path.match(rt);return Ee?.[1]?[Ee[1]]:[]}))].sort();if(Ie.length===0)throw Error(`No rulebooks found in ${A} under ${ue}/`);return{source:A,owner:X,repo:ee,ref:ae,commit:le,names:Ie}}async function mg(A,z,X,ee){let te=await Br(`https://api.github.com/repos/${A}/${z}`,"metadata",ee),ae=te.response;if(!ae.ok)throw Error(`Failed to inspect ${X}: GitHub returned ${ae.status}`);let ye=JSON.parse(te.content)?.default_branch;if(typeof ye!=="string"||ye==="")throw Error(`Failed to inspect ${X}: missing default branch`);if(!re(ye))throw Error(`GitHub returned an invalid default branch: ${ye}`);return ye}function gg(A,z,X){ot(A);let ee=I(z,A),te=n(i(X,ee));if(te===null)throw Error(`Rulebook source not found: ${A}`);let ae=Qc(vi(te,"Invalid local rulebook source."));if(ae.name!==A)throw Error(`rulebook name "${ae.name}" must match local source "${A}"`);return{spec:A,rulebook:ae,content:te}}async function yg(A,z){let X=T(A),ee=await ed(X.owner,X.repo,X.ref,A,z),te=await Br(`https://raw.githubusercontent.com/${X.owner}/${X.repo}/${ee}/${X.path}`,"raw",z),ae=te.response;if(!ae.ok)throw Error(`Failed to fetch ${A}: GitHub raw returned ${ae.status}`);let le=te.content,ye=Qc(vi(le,"Invalid GitHub rulebook response."));if(ye.name!==X.name)throw Error(`rulebook name "${ye.name}" must match GitHub source "${X.name}"`);return{spec:A,rulebook:ye,content:le}}function Qc(A){let z=ie(A),X=Mr(z);if(X.length>0)throw Error(X.join("; "));return z}function vi(A,z){try{return JSON.parse(A)}catch{throw Error(z)}}async function ed(A,z,X,ee,te){let ae=await Br(`https://api.github.com/repos/${A}/${z}/commits/${encodeURIComponent(X)}`,"commit",te),le=ae.response;if(!le.ok)throw Error(`Failed to resolve ${ee}: GitHub returned ${le.status}`);let ye=JSON.parse(ae.content);if(typeof ye?.sha!=="string"||ye.sha==="")throw Error(`Failed to resolve commit for ${ee}`);return ye.sha}async function hg(A,z,X={}){if(X.signal?.aborted)throw X.signal.reason;let ee=X.budget??Ur(),te=new AbortController,ae=()=>te.abort(X.signal?.reason);X.signal?.addEventListener("abort",ae,{once:!0});let le=!1,ye=setTimeout(()=>{if(te.signal.aborted)return;le=!0,te.abort()},X.timeoutMs??Yc.timeoutMs);try{if(X.signal?.aborted)throw X.signal.reason;zc(ee);let he=await fetch(A,{signal:te.signal,redirect:"error"});if(!he.ok)return td(he),{response:he,content:""};return{response:he,content:await vg(he,z,ee,()=>te.abort())}}catch(he){if(le)throw Error("GitHub request timed out",{cause:he});if(X.signal?.aborted)throw X.signal.reason;throw he}finally{clearTimeout(ye),X.signal?.removeEventListener("abort",ae)}}function Br(A,z,X){return hg(X.resolveUrl?.(A)??A,z,{budget:X.budget,signal:X.controller.signal})}async function vg(A,z,X=Ur(),ee){let te=Yc[`${z}Bytes`],ae=Number(A.headers.get("content-length"));if(Number.isFinite(ae)&&ae>te)throw td(A),Error(`GitHub ${z} response exceeds ${te} bytes`);if(!A.body)return"";let le=A.body.getReader(),ye=[],he=0;while(!0){let ve=await le.read();if(ve.done)break;try{Jc(X,ve.value.byteLength)}catch(be){throw ee?.(),Kc(le),be}if(he+=ve.value.byteLength,he>te)throw ee?.(),Kc(le),Error(`GitHub ${z} response exceeds ${te} bytes`);ye.push(Buffer.from(ve.value))}return Buffer.concat(ye,he).toString("utf-8")}function td(A){if(!A.body)return;nd(()=>A.body?.cancel())}function Kc(A){nd(()=>A.cancel())}function nd(A){try{Promise.resolve(A()).catch(()=>{})}catch{}}var bg=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function rd(A,z){let X=sd(A.rules,z);if(X.length>0)return{ok:!0,specs:X};return id(A.rules,z)}function od(A,z){let X=sd(A,z);if(X.length>0)return{ok:!0,specs:X};let ee=wg(A,z);if(ee.length>0)return{ok:!0,specs:ee};let te=kg(A,z);if(!te.ok)return te;if(te.specs.length>0)return{ok:!0,specs:te.specs};return id(A,z)}function id(A,z){let X=A.filter((ee)=>bi(ee)?.name===z);if(X.length===1)return{ok:!0,specs:X};return Lg(z,X)}function Lg(A,z){return{ok:!1,result:{ok:!1,errors:z.length===0?[`No configured rulebook matches ${A}`]:[`Ambiguous rulebook match ${A}: ${z.join(", ")}`],entries:[]}}}function sd(A,z){return A.filter((X)=>X===z)}function wg(A,z){let X=z.match(bg),ee=X?.[1],te=X?.[2],ae=X?.[3];if(!ee||!te||!ae||!re(ae))return[];return ad(A,(le)=>le.owner===ee&&le.repo===te&&le.ref===ae)}function kg(A,z){if(!V(z))return{ok:!0,specs:[]};let[X,ee]=z.split("/"),te=ad(A,(le)=>le.owner===X&&le.repo===ee);if(new Set(te.map((le)=>bi(le)?.ref).filter((le)=>!!le)).size<2)return{ok:!0,specs:te};return{ok:!1,result:{ok:!1,errors:[`Multiple refs are configured for ${z}. Use an explicit ref:`,` cc-safety-net rule remove ${z}#<ref>`],entries:[]}}}function bi(A){try{return T(A)}catch{return null}}function ad(A,z){return A.filter((X)=>{let ee=bi(X);return ee?z(ee):!1})}async function Vr(A,z={}){let X=wi(z);return Cg(A,X,await qr(A,X,zt()))}function Cg(A,z,X){if(!X.ok)return X;let ee=Pt(A,z),te=[...new Set(j(ee.configPath,ee.filesystemScope))];if(te.length===0)return X;return{ok:!1,errors:te,entries:X.entries}}async function qr(A,z,X,ee={},te=new Set,ae=new Set){try{let le=Pt(A,z),ye=yi(le.configTarget);if(!ye.ok)return ye.result;let he=ye.config,ve=z.only?rd(he,z.only):{ok:!0,specs:he.rules};if(!ve.ok)return ve.result;let be=new Set([...z.refresh?ve.specs:[],...te]),Ie=(ut)=>Zc(ut,le.configDir,le.filesystemScope,X,be.has(ut),!z.refresh||be.has(ut)),Xe=await Og(he.rules,z.refresh?(ut)=>Ie(ut).then((vt)=>({ok:!0,item:vt})).catch((vt)=>{if(Vc(vt))throw vt;return{ok:!1,spec:ut,message:vt instanceof Error?vt.message:String(vt)}}):async(ut)=>({ok:!0,item:await Ie(ut)}),X),et=Xe.filter((ut)=>!ut.ok),Ee=Xe.filter((ut)=>ut.ok).map((ut)=>ut.item),at=Ee.flatMap((ut)=>Sg(ut,he.rules)),ct=Ee.flatMap((ut)=>Rg(ut,ae,le)),lt=new Set([...at,...ct].map((ut)=>ut.spec)),pt=[...et,...at,...ct],mt=[],gt=Eg(mt,()=>Ee.flatMap((ut)=>lt.has(ut.spec)||pt.length>0&&ae.has(ut.spec)?[]:Pg(ut,le,ee,mt)));return{ok:pt.length===0,errors:pt.map((ut)=>`Failed to update ${ut.spec}: ${ut.message}`),entries:Ee.map(Ag),changes:gt}}catch(le){return zn(le)}}function Sg(A,z){if(!C(A.spec))return[];let X=Ae(A.spec),ee=z.filter((te)=>te!==A.spec&&Ae(te).toLowerCase()===X.toLowerCase());if(ee.length===0)return[];return[{ok:!1,spec:A.spec,message:`rulebook name "${X}" is also claimed by ${ee.join(", ")}; rename one of them`}]}function Rg(A,z,X){if(!z.has(A.spec)||!C(A.spec))return[];let ee=I(X.configDir,A.rulebook.name),te=n(i(X.filesystemScope,ee));if(te===null||te===A.content)return[];return[{ok:!1,spec:A.spec,message:`${ee} already exists and no configured source claims it; remove or rename the file, then re-run rule add`}]}function Pg(A,z,X,ee){if(!C(A.spec))return[];let te=I(z.configDir,A.rulebook.name),ae=i(z.filesystemScope,te),le=n(ae);if(le===A.content)return[];return ee?.push({target:ae,previous:le}),g(ae,A.content,void 0,X._testAfterPolicyRename),Dg(A,le)}function Eg(A,z){try{return z()}catch(X){for(let ee of[...A].reverse()){if(ee.previous===null){N(ee.target);continue}g(ee.target,ee.previous)}throw X}}function Dg(A,z){if(z===null)return[`Vendored ${A.spec} (${A.rulebook.version})`];let X=me(z),ee="problem"in X?null:X.rulebook,te=new Map(ee?.rules.map((le)=>[le.name,JSON.stringify(le)])??[]),ae=new Set(A.rulebook.rules.map((le)=>le.name));return[`Updated ${A.spec} (${ee?.version??"unreadable"} -> ${A.rulebook.version})`,...[...ae].filter((le)=>!te.has(le)).map((le)=>` + ${le}`),...[...te.keys()].filter((le)=>!ae.has(le)).map((le)=>` - ${le}`),...A.rulebook.rules.filter((le)=>{let ye=te.get(le.name);return ye!==void 0&&ye!==JSON.stringify(le)}).map((le)=>` ~ ${le.name}`)]}function Ag(A){return{spec:A.spec,name:A.rulebook.name,version:A.rulebook.version,ruleCount:A.rulebook.rules.length}}async function ld(A,z,X={}){return _g(A,z,jg(X),zt())}async function _g(A,z,X,ee,te={}){let ae=null,le=!1;try{let ye=Pt(A,X),he=n(ye.configTarget);ae={target:ye.configTarget,content:he};let ve=yi(ye.configTarget);if(!ve.ok)return ve.result;let be=ve.config,Ie=V(z);Tg(z,X,Ie);let Xe=Ie?await Xc(z,{ref:X.ref,operation:ee}):null,et=Xe?$g(Xe,X.rulebooks):[],Ee=Xe?et.map((mt)=>Ig(be.rules,Xe,mt)??`${z}#${Xe.ref}/${mt}`):[z],at=Ee.filter((mt)=>!be.rules.includes(mt)),ct=[...be.rules,...at];if(ct.length>pe)return Fg();if(ct.length!==be.rules.length)le=!0,Rt(ye.configTarget,{version:1,rules:ct,overrides:be.overrides??{},transparent_wrappers:be.transparent_wrappers??[]},void 0,te._testAfterPolicyRename);let lt=await qr(A,X,ee,te,new Set(at),new Set(at));if(!lt.ok)Vn(ye.configTarget,he);if(!lt.ok||!Xe)return lt;let pt=et.filter((mt,gt)=>at.includes(Ee[gt]??""));return{...lt,add:{source:z,ref:Xe.ref,selected:et,added:pt,alreadyConfigured:et.filter((mt)=>!pt.includes(mt)),commits:at.length>0?[Xe.commit]:[]}}}catch(ye){if(le&&ae)try{Vn(ae.target,ae.content)}catch(he){return zn(he)}return zn(ye)}}function Tg(A,z,X){if(!X&&z.rulebooks!==void 0)throw Error("--only can only select rulebooks from an owner/repo source");if(!X&&z.ref)throw Error(`--ref can only select a ref for an owner/repo source: ${A}`);if(z.rulebooks?.length===0)throw Error("--only requires at least one rulebook name");let ee=z.rulebooks?.filter((te)=>!c.test(te))??[];if(ee.length>0)throw Error(`Invalid rulebook names: ${ee.join(", ")}`)}function $g(A,z){let X=z?[...new Set(z)]:A.names,ee=X.filter((te)=>!A.names.includes(te));if(ee.length>0)throw Error(`Rulebooks not found in ${A.source} at ${A.ref}: ${ee.join(", ")}
|
|
264
|
-
Available rulebooks: ${
|
|
265
|
-
No config files found. Using built-in rules only.`),0;for(let
|
|
266
|
-
Added $schema to ${
|
|
267
|
-
${dt.red(
|
|
268
|
-
Config validation failed.`),1;return console.log(
|
|
254
|
+
`)},ye=Ym(V,P.fetchVersion??mn).then(async(et)=>{let Re=new Set(et.targets);return{targets:et.targets,codexPluginListOutput:et.codexPluginListOutput,available:new Map(await Promise.all(Mt.filter((at)=>Re.has(at.target)&&mc.has(at.target)).map(async(at)=>[at.target,await ci(at.probeCommand)])))}}),he=await Pn(P.showBanner??!0,()=>({ready:ye,finish:()=>ye}),()=>Rn({input:P.input??process.stdin,output:z}),{loadingMessage:"Checking installed integrations…",output:z}),be=await Promise.resolve().then(()=>(Yl(V.tmpdir,process.platform,te),null)).catch((et)=>Gn(et));if(he.targets.length===0){if(z.write("No installed integrations found. Run `cc-safety-net install` to set one up.\n"),be!==null)console.error(be);return await ce(),be===null?0:1}let xe=he.targets.some((et)=>gc.has(et))?await Promise.resolve().then(()=>(Fr(V),null)).catch((et)=>Gn(et)):null,Ie=await cr(Promise.all(he.targets.map((et)=>{if(mc.has(et)&&!he.available.get(et))return Promise.resolve({message:`${bt(et)} not found; skipped`,failed:!1});if(xe!==null&&gc.has(et))return Promise.resolve({message:xe,failed:!0});return Rc("install",et,V,!0,he.codexPluginListOutput).then((Re)=>({message:Re,failed:!1}),(Re)=>({message:Gn(Re),failed:!0}))})),{loadingMessage:`Updating ${he.targets.length} integration${he.targets.length===1?"":"s"}…`,output:z}),Xe=be===null?Ie:[...Ie,{message:be,failed:!0}];return Xe.forEach((et)=>{et.failed?console.error(et.message):z.write(`${et.message}
|
|
255
|
+
`)}),await ce(),Xe.some((et)=>et.failed)?1:0}function yi(P,V={}){return Promise.resolve().then(()=>Km(P)).then(()=>Zm(V)).catch((z)=>(console.error(Gn(z)),1))}async function Bn(P,V,z={}){try{let Q=c(),te=await Pn(!0,()=>Nm(Q,P,V,z),()=>Rn({input:z.input??process.stdin,output:z.output??process.stdout}),{loadingMessage:P==="install"?"Checking available integrations…":"Checking installed integrations…",output:z.output??process.stdout});if(!te)return(z.output??process.stdout).write(`Cancelled: nothing was ${P}ed.
|
|
256
|
+
`),0;if(te==="update")return(z.runUpdate??(()=>yi([],{fetchVersion:z.fetchVersion,input:z.input,output:z.output,showBanner:!1})))();let ne=z.output??process.stdout;return await Zl(te,async(ce)=>{if(ce==="kimi-code"&&P==="install"){let he=await Wm(z,Q);if(he===null){ne.write(`Cancelled: Kimi Code integration was not installed.
|
|
257
|
+
`);return}if(he==="plugin"){ne.write(`${Jm(Q)}
|
|
258
|
+
`);return}}let ye=await cr(Rc(P,ce,Q),{loadingMessage:`${P==="install"?"Installing":"Uninstalling"} ${bt(ce)} integration…`,output:ne});ne.write(`${ye}
|
|
259
|
+
`)}),0}catch(Q){return console.error(Gn(Q)),1}}function Gn(P){let V=P instanceof Error?P.message:String(P),z=typeof P==="object"&&P!==null&&"code"in P?P.code:null;if(z==="EACCES"||z==="EPERM")return`${V}
|
|
260
|
+
Check file permissions for the target config file and parent directory.`;if(z==="ENOENT")return`${V}
|
|
261
|
+
Check that the target config path and parent directory exist.`;if(z==="ENOTDIR")return`${V}
|
|
262
|
+
Check that every parent path component is a directory.`;return V}import{mkdirSync as rg}from"node:fs";import{dirname as og}from"node:path";import{createInterface as ig}from"node:readline";import{existsSync as Ec,readFileSync as Xm}from"node:fs";function cn(P,V){let z=Ye(P,V);return{policy:z.policy,errors:ie(qe(z.issues,Je,(Q)=>Q.kind==="custom")," "," ")}}function qn(P,V){return cn(P,V).errors}function Pc(P,V){return{"safety.level":P.safety.level,...hi("safety.overrides",P.safety.overrides),"workflow.worktree_mode":String(P.workflow.worktree_mode),"destructive_command_protection.enabled":String(P.destructive_command_protection.enabled),...hi("destructive_command_protection.overrides",P.destructive_command_protection.overrides),"destructive_command_protection.allow_paths":vi(P.destructive_command_protection.allow_paths),"secret_protection.enabled":String(P.secret_protection.enabled),...hi("secret_protection.overrides",P.secret_protection.overrides),"secret_protection.deny_paths":vi(P.secret_protection.deny_paths),"secret_protection.allow_paths":vi(P.secret_protection.allow_paths),...V?{"audit.retention_days":String(P.audit.retention_days)}:{}}}function jr(P,V,z){let Q=Pc(P,z),te=Pc(V,z);return[...new Set([...Object.keys(Q),...Object.keys(te)])].flatMap((ne)=>Q[ne]===te[ne]?[]:[{field:ne,before:Q[ne],after:te[ne]}])}function Vn(P,V){let z=u(P,V);if(!Ec(z))return{baseline:C(globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__,P.home),diagnostics:[]};let Q=dn(z),te=cn(Q.value,P.home);return{baseline:te.policy,diagnostics:Q.errors.length>0?Q.errors:te.errors}}function dn(P){if(!Ec(P))return{errors:[`${P}: file not found`]};try{return{value:JSON.parse(Xm(P,"utf-8")),errors:[]}}catch(V){let z=V instanceof Error?V.message:String(V);return{errors:[`${P}: ${V instanceof SyntaxError?`Invalid JSON: ${z}`:z}`]}}}function Nr(P,V){let z=Qm(P)?P:{};return{version:V.version,...Object.fromEntries(["safety","workflow","destructive_command_protection","secret_protection"].filter((Q)=>z[Q]!==void 0).map((Q)=>[Q,z[Q]]))}}function hi(P,V){return Object.fromEntries(Object.entries(V).flatMap(([z,Q])=>Q===void 0?[]:[[`${P}.${z}`,String(Q)]]))}function vi(P){return P.length===0?"(none)":P.join(", ")}function Qm(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}import{chmodSync as eg,existsSync as Dc,mkdirSync as tg,readFileSync as Ac}from"node:fs";import{dirname as ng}from"node:path";function _c(P,V={}){let z=u(P,V);if(!Dc(z))return{path:z,exists:!1,raw:"",policy:H(),errors:[]};let Q=Ac(z,"utf-8");if(!Q.trim())return{path:z,exists:!0,raw:Q,policy:H(),errors:["Config file is empty"]};try{let te=cn(JSON.parse(Q),P.home);return{path:z,exists:!0,raw:Q,policy:te.policy,errors:te.errors}}catch(te){return{path:z,exists:!0,raw:Q,policy:H(),errors:[`Invalid JSON: ${te instanceof Error?te.message:String(te)}`]}}}function Vt(P,V,z={}){let Q=u(P,z),te=cn(V,P.home);if(te.errors.length>0)return{path:Q,policy:H(),errors:te.errors};let ne=te.policy;return tg(ng(Q),{recursive:!0,mode:448}),g(re(Q),`${JSON.stringify(ne,null,2)}
|
|
263
|
+
`,384),eg(Q,384),{path:Q,policy:ne,errors:[]}}function Tc(P,V){let z=cn(V,P.home);if(z.errors.length>0)return{errors:z.errors};return{preview:Ae(z.policy,P.env),errors:[]}}function $c(P,V={}){let z=u(P,V);if(!Dc(z))return Vt(P,Z,V);let Q=Ac(z,"utf-8");if(!Q.trim())return Vt(P,Z,V);try{return Vt(P,C(JSON.parse(Q),P.home),V)}catch{return Vt(P,Z,V)}}var Ic=new Set(["check","apply"]),Oc="(unset)";async function jc(P,V,z={}){let Q=xt({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},V),te=Q.positionals[0],ne=[...Q.errors,...te&&!Ic.has(te)?[`Unknown policy subcommand: ${te}`]:[],...te&&Ic.has(te)&&!Q.positionals[1]?[`policy ${te} requires a file`]:[],...Q.positionals.slice(2).map((Re)=>`Unexpected policy argument: ${Re}`)];if(ne.length>0){for(let Re of ne)console.error(Re);return 1}let ce=Q.positionals[1];if(!te||!ce)return wn(Xn,console.error),1;let ye=Q.flags.global?u(P):b(z.cwd??process.cwd()),he=dn(ce),be=[...he.errors,...qn(he.value,P.home).map((Re)=>`${ce}: ${Re}`),...!Q.flags.global&&lg(he.value)&&he.value.audit!==void 0?[`${ce}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(be.length>0){for(let Re of be)console.error(Re);return 1}let xe=C(he.value,P.home);if(console.log(`Scope: ${Q.flags.global?"user":"project"} (${ye})`),console.log(`Proposal: ${ce}`),Q.flags.global)Fc(C(dn(ye).value,P.home),xe,!0);if(!Q.flags.global){let Re=Vn(P).baseline;console.log("Effective policy (user + project merged):"),Fc(Y(Re,ae(dn(ye).value,P.home).policy).policy,Y(Re,ae(he.value,P.home).policy).policy,!1)}if(te==="check")return 0;let Ie=z.input??process.stdin,Xe=z.output??process.stdout;if(!Ie.isTTY||!Xe.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${ce}${Q.flags.global?" --global":""}`),1;if(!await sg(`Apply this policy to ${ye}? [y/N] `,Ie,Xe))return console.log("Cancelled; nothing was written."),0;return ag(P,ye,he.value,xe,Q.flags.global),console.log(`Policy applied: ${ye}`),0}function sg(P,V,z){let Q=ig({input:V,output:z,terminal:!1});return new Promise((te)=>{Q.once("close",()=>te(!1)),Q.question(P,(ne)=>{te(/^y(es)?$/i.test(ne.trim())),Q.close()})})}function ag(P,V,z,Q,te){if(te){Vt(P,Q);return}rg(og(V),{recursive:!0}),Rt(V,Nr(z,Q))}function Fc(P,V,z){let Q=jr(P,V,z);if(Q.length===0){console.log("No changes.");return}console.log(`Changes (${Q.length}):`);for(let te of Q)console.log(` ${te.field}: ${te.before??Oc} -> ${te.after??Oc}`)}function lg(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}import{join as wy}from"node:path";var Nc="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Priority |\n|-------|-------------|---------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | Second |\n| GitHub source | Listed in a local `rule.json` | Vendored into the consumer's `<rulebook-name>/rulebook.json` by `rule add` | Source order |\n\nEvery rulebook is a live file: the runtime reads it on each tool call, so an edit applies to the next command with no publishing step.\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule verify` reports the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- Transparent wrappers have no built-in defaults. Configure only wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n\n## Rulebook Sources\n\n- Local sources are bare rulebook names such as `project-rules`; the rulebook file is `.cc-safety-net/rules/project-rules/rulebook.json`.\n- Run `cc-safety-net rule add owner/repo` to add every rulebook currently present on the repository's default branch.\n- Use `--only` to select one or more rulebooks while preserving their order: `cc-safety-net rule add owner/repo --only aws gcloud`.\n- Use `--ref` to select a branch, tag, or commit instead of the default branch: `cc-safety-net rule add owner/repo --ref v2 --only aws`.\n- GitHub sources are stored in canonical form as `owner/repo#ref/<rulebook-name>`. That form remains valid in `rule.json` and as direct CLI input.\n- GitHub refs may contain `/`-separated path segments, such as `feature/rulebook-v2`.\n- The GitHub source name, the repository directory name, and the rulebook `name` must match exactly.\n- Rulebook source strings must be unique in a config.\n\n## rulebook.json Schema\n\n```json\n{\n \"rulebook_version\": 1,\n \"name\": \"project-rules\",\n \"version\": \"1.0.0\",\n \"description\": \"Project-specific CC Safety Net rules.\",\n \"author\": \"project\",\n \"allowed_commands\": [\"docker\"],\n \"rules\": [\n {\n \"name\": \"block-docker-system-prune\",\n \"command\": \"docker\",\n \"subcommand\": \"system\",\n \"block_args\": [\"prune\"],\n \"reason\": \"Use targeted cleanup instead.\"\n }\n ],\n \"tests\": [\n {\n \"command\": \"docker system prune\",\n \"expect\": \"blocked\",\n \"rule\": \"block-docker-system-prune\"\n },\n {\n \"command\": \"docker ps\",\n \"expect\": \"allowed\"\n }\n ]\n}\n```\n\n### Rulebook Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `rulebook_version` | Yes | Must be `1` or `2` |\n| `name` | Yes | `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$` |\n| `version` | Yes | Non-empty string |\n| `description` | No | Free text; not type-checked at runtime |\n| `author` | No | Free text; not type-checked at runtime |\n| `allowed_commands` | Yes | Unique command names matching `^[a-zA-Z][a-zA-Z0-9_-]*$` |\n| `rules` | Yes | Array of rule objects |\n| `tests` | No | Array of fixtures |\n\n### Rule Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Unique within the rulebook (case-insensitive); same pattern as rulebook `name` |\n| `command` | Yes | Must be listed in `allowed_commands`; basename only, not path |\n| `subcommand` | No | Same pattern as `command`; omit to match any subcommand |\n| `intent` | No | One of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain` |\n| `block_args` | Yes | Non-empty array of non-empty strings |\n| `reason` | Yes | Non-empty string, max 256 chars |\n\n### Rule Fields (`rulebook_version` 2)\n\nVersion 2 replaces `subcommand` and `block_args` with an exact-token `match` object. Version 1 rulebooks keep their fields and their behavior; a client that does not support version 2 rejects the rulebook instead of applying broader version 1 semantics.\n\n```json\n{\n \"name\": \"block-terraform-apply-destroy\",\n \"command\": \"terraform\",\n \"match\": {\n \"command_path\": [\"apply\"],\n \"any_args\": [\"-destroy\", \"--destroy\"]\n },\n \"reason\": \"Review a destroy plan first with 'terraform plan -destroy'.\",\n \"intent\": \"use_alternative\"\n}\n```\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Same as version 1 |\n| `command` | Yes | Same as version 1 |\n| `match.command_path` | Yes | Non-empty array of non-empty command words |\n| `match.any_args` | No | Non-empty array of unique non-empty argument tokens |\n| `match.exclude_args` | No | Non-empty array of unique non-empty argument tokens |\n| `intent` | No | Same as version 1 |\n| `reason` | Yes | Same as version 1 |\n\n### Matching Behavior (`rulebook_version` 2)\n\n- **Command**: Normalized to lowercase basename, as in version 1.\n- **Command path**: After recognized global options and their values are skipped, the next command words must equal `command_path` exactly. AWS, gcloud, and Azure CLI value-taking global options are built in; Terraform's `-chdir=dir` is `=`-joined and is skipped with its own token.\n- **Unrecognized options**: A token starting with `-` that is not a recognized global option is skipped without consuming a value, so an unlisted value-taking option with a separate value (`--newflag value`) makes the rule miss. This fails open deliberately; document such gaps in the rulebook.\n- **`any_args`**: At least one listed token must appear literally among the arguments.\n- **`exclude_args`**: Any listed token appearing literally among the arguments prevents the match, which is how a safe preview such as `aws s3 rm --dryrun` stays allowed.\n- **No short-option expansion**: Arguments compare as exact tokens, so list every accepted spelling (`\"-destroy\"` and `\"--destroy\"`).\n- **Literal and case-sensitive**: No regex, glob, or substring matching. The first matching rule wins.\n- Release channels are separate rules: `gcloud beta compute instances delete` needs its own `command_path`.\n\n### Test Fixture Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `command` | Yes | Non-empty shell command string |\n| `expect` | Yes | `\"blocked\"` or `\"allowed\"` |\n| `rule` | Required for blocked fixtures | Rule name expected to block the command |\n\nFixtures are optional documentation of intended behavior. Version 1 fixtures are shape-validated only. Version 2 fixtures are evaluated against the rulebook's own rules when a source is fetched by `rule add` or `rule update`, and by `rule verify`; a failing fixture rejects that source before it is written. Loading a rulebook does not re-evaluate fixtures. CC Safety Net never executes fixture commands; they are analyzer inputs only.\n\n## Matching Behavior\n\nThe subcommand, argument, and option rules below describe `rulebook_version` 1 rules; version 2 rules match as described in Matching Behavior (`rulebook_version` 2). Execution order and transparent wrappers apply to both.\n\n- **Command**: Normalized to lowercase basename with any trailing `.exe` removed (`/usr/bin/git` → `git`).\n- **Subcommand**: The first command token after recognized Git and Docker global options and their values; `--` ends option parsing. An unrecognized option without `=` may consume the following token as its value.\n- **Arguments**: Each `block_args` value is compared literally against every command token, including expanded short options. The command is blocked if **any** item matches.\n- **Short options**: Expanded (`-Ap` matches `-A`).\n- **Long options**: Exact match (`--all-files` does not match `--all`).\n- **Execution order**: Built-in rules first, then custom rulebooks. Custom rules only add restrictions.\n- **Transparent wrappers**: A configured wrapper such as `rtk` lets `rtk git commit` be analyzed as `git commit` only when `git` is protected by built-in analyzers or active custom rules. `rtk -- git commit` is also supported.\n\n## Workflow\n\n1. Run `cc-safety-net rule init` or create `rule.json` manually.\n2. Optionally run `cc-safety-net rule init --example` to create an inactive example rulebook.\n3. Use `cc-safety-net rule wrapper add rtk` for trusted transparent wrappers.\n4. Run `cc-safety-net rule add <source>` after creating or choosing a rulebook source; add `--only <rulebook...>` or `--ref <ref>` for repository selection. The command adds the selected sources and syncs them.\n5. Edit a local rulebook whenever you like: the edit is enforced on the next command, so there is nothing to run afterwards.\n6. Run `cc-safety-net rule update [source]` to re-fetch remote sources and rewrite the vendored copies; the command prints what changed. A source with an ordinary update failure keeps its vendored copy while the other selected sources still update. Resource-limit failures remain fatal for the whole update.\n7. Run `cc-safety-net rule verify` to validate config, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n8. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nA missing or invalid rulebook file makes that source inactive, and an unreadable or invalid `rule.json` makes every source in its scope inactive. Inactive sources stop applying their rules while other custom rules and all built-in protections stay active. Fix the file named in the diagnostic, or run `cc-safety-net rule update` when a remote source has not been vendored yet. Run `cc-safety-net status` to see degraded sources.\n";function Mr(P,V){if(!P.ok){Bc(P);return}Uc(P,V)}function Hc(P,V,z){if(P.ok)console.log(z);if(!P.add){Mr(P,`Added rulebook source: ${V}`);return}if(!P.ok){Bc(P);return}if(P.add.added.length>0)console.log(`Added ${P.add.added.length} ${P.add.added.length===1?"rulebook":"rulebooks"} from ${P.add.source} at ${P.add.ref}:`),P.add.added.forEach((Q)=>{console.log(` - ${Q}`)});if(P.add.alreadyConfigured.length>0)console.log(`Rulebooks already configured from ${P.add.source} at ${P.add.ref}: ${P.add.alreadyConfigured.join(", ")}`);if(P.add.commits.length>0)console.log(`Vendored at ${P.add.commits.map((Q)=>Q.slice(0,7)).join(", ")}.`);Uc(P,"Rule config updated.")}function Uc(P,V){for(let z of P.changes??[])console.log(z);console.log(V),console.log(""),cg(P.entries)}function cg(P){if(P.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${P.length}):`);for(let V of P)console.log(` - ${V.name} ${V.version} (${dg(V.ruleCount)})`),console.log(` Source: ${V.spec}`)}function dg(P){return`${P} ${P===1?"rule":"rules"}`}function Gc(P){un("Active sources",P.rulebooks,(V)=>[`[${V.source}] ${V.name} ${V.version}`,` Source: ${V.spec}`]),un("Active rules",P.rules,(V)=>[`[${pg(P,V.name)}] ${V.name}`,...ug(V),` Reason: ${V.reason}`]),un("Disabled rules",Mc(P,"off"),(V)=>[V.key]),un("Reason overrides",Mc(P,"reason"),(V)=>[V.key,` Reason: ${V.value.reason}`]),un("Transparent wrappers",P.transparent_wrappers,(V)=>[V]),un("Issues",P.errors,(V)=>[V]),un("Warnings",P.warnings,(V)=>[V])}function un(P,V,z){if(V.length===0){console.log(`${P}: (none)`);return}console.log(`${P} (${V.length}):`);for(let Q of V){let[te,...ne]=z(Q);console.log(` - ${te}`);for(let ce of ne)console.log(` ${ce}`)}}function ug(P){if(!P.match)return[` Command: ${P.subcommand?`${P.command} ${P.subcommand}`:P.command}`,` Block args: ${P.block_args.join(", ")}`];return[` Command: ${[P.command,...P.match.command_path].join(" ")}`,...P.match.any_args?[` Any args: ${P.match.any_args.join(", ")}`]:[],...P.match.exclude_args?[` Exclude args: ${P.match.exclude_args.join(", ")}`]:[]]}function pg(P,V){return P.rulebooks.find((z)=>z.rules.includes(V))?.source??"project"}function Mc(P,V){return Object.entries({...P.userConfig?.overrides??{},...P.projectConfig?.overrides??{}}).filter((z)=>{if(V==="off")return z[1]==="off";return!!z[1]&&typeof z[1]==="object"}).map(([z,Q])=>({key:z,value:Q}))}function Bc(P){for(let V of P.errors)console.error(V)}import{dirname as pd,join as Jr}from"node:path";import{join as xi,resolve as Cg}from"node:path";function bi(P){let V=m(P);if(V.errors.length>0)return{ok:!1,result:{ok:!1,errors:V.errors,entries:[]}};return{ok:!0,config:V.config??it}}function qc(P){Rt(P,{version:1,rules:[],overrides:{},transparent_wrappers:[]})}function Vc(P){Rt(P,{rulebook_version:1,name:"example-rules",version:"1.0.0",description:"Project-specific CC Safety Net rules.",author:"project",allowed_commands:["docker"],rules:[{name:"block-docker-system-prune",command:"docker",subcommand:"system",block_args:["prune"],reason:"Use targeted cleanup instead."}],tests:[{command:"docker system prune",expect:"blocked",rule:"block-docker-system-prune"}]})}import{dirname as Br}from"node:path";var fg="custom.";function Hr(P){if(P.rulebook_version!==2)return[];let V=P.rules.map((z)=>({name:z.name,command:z.command,block_args:[],match:z.match,reason:z.reason,intent:z.intent}));return(P.tests??[]).flatMap((z,Q)=>{let te=Li(h(z.command));if(te.length===0)return[`tests[${Q}]: could not parse fixture command: ${z.command}`];let ne=te.reduce((ce,ye)=>ce??_(ye,V)?.id.slice(fg.length),void 0);if(z.expect==="blocked"){if(ne===z.rule)return[];let ce=ne?`"${ne}" matched first`:"no rule matched";return[`tests[${Q}]: expected "${z.rule}" to block "${z.command}" but ${ce}`]}return ne?[`tests[${Q}]: expected "${z.command}" to be allowed but "${ne}" matched`]:[]})}function Li(P){return P.nodes.flatMap((V)=>{if(V.kind==="group"||V.kind==="function")return Li(V.body);if(V.kind!=="command")return[];let z=ge(X(V.dialect,V.words)).words.map(t);return[...z.length>0?[z]:[],...V.nested.flatMap((Q)=>Li(Q))]})}var Ur=Object.freeze({concurrency:4,maxRequests:131,maxResponseBytes:67108864});function Gr(P={}){return{requests:0,responseBytes:0,maxRequests:P.maxRequests??Ur.maxRequests,maxResponseBytes:P.maxResponseBytes??Ur.maxResponseBytes}}function zt(P){return{controller:new AbortController,budget:Gr(),resolveUrl:P}}function zc(P){return P instanceof Error&&P.message==="Rule synchronization exceeds CC Safety Net's safe resource limits."}function Jc(P){if(P.requests>=P.maxRequests)throw Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");P.requests++}function Wc(P,V){if(V>P.maxResponseBytes-P.responseBytes)throw P.responseBytes+=V,Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");P.responseBytes+=V}var Zc=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function Kc(P,V,z=v(Br(Br(V)),"rules policy"),Q=zt()){if(S(P))return hg(P,Q);return yg(P,V,z)}async function Xc(P,V,z,Q,te,ne){if(!S(P))return Kc(P,V,z,Q);let ce=te?null:mg(P,V,z);if(ce)return ce;if(!te&&!ne)throw Error(`${P} is not vendored; run rule update ${P} to vendor it`);return Kc(P,V,z,Q)}function mg(P,V,z=v(Br(Br(V)),"rules policy")){let Q=A(P),te=I(V,Q.name),ne=n(i(z,te));if(ne===null)return null;let ce=se(wi(ne,`Invalid rulebook ${te}.`));if(ce.name!==Q.name)throw Error(`rulebook name "${ce.name}" in ${te} must match "${Q.name}"`);return{spec:P,rulebook:ce,content:ne}}async function Qc(P,V={}){if(!q(P))throw Error(`Invalid GitHub repository source: ${P}`);let[z,Q]=P.split("/");if(!z||!Q)throw Error(`Invalid GitHub repository source: ${P}`);if(V.ref!==void 0&&!oe(V.ref))throw Error(`GitHub rulebook refs must use valid path segments: ${V.ref}`);let te=V.operation??zt(),ne=V.ref??await gg(z,Q,P,te),ce=await td(z,Q,ne,P,te),ye=await qr(`https://api.github.com/repos/${z}/${Q}/git/trees/${ce}?recursive=1`,"tree",te),he=ye.response;if(!he.ok)throw Error(`Failed to inspect ${P}: GitHub tree returned ${he.status}`);let be=JSON.parse(ye.content);if(!Array.isArray(be?.tree))throw Error(`Failed to inspect ${P}: unexpected GitHub tree response`);let xe=be.tree,Ie=[...new Set(xe.flatMap((Xe)=>{if(!Xe||typeof Xe!=="object")return[];let et=Xe;if(et.type!=="blob"||typeof et.path!=="string")return[];let Re=et.path.match(rt);return Re?.[1]?[Re[1]]:[]}))].sort();if(Ie.length===0)throw Error(`No rulebooks found in ${P} under ${de}/`);return{source:P,owner:z,repo:Q,ref:ne,commit:ce,names:Ie}}async function gg(P,V,z,Q){let te=await qr(`https://api.github.com/repos/${P}/${V}`,"metadata",Q),ne=te.response;if(!ne.ok)throw Error(`Failed to inspect ${z}: GitHub returned ${ne.status}`);let ye=JSON.parse(te.content)?.default_branch;if(typeof ye!=="string"||ye==="")throw Error(`Failed to inspect ${z}: missing default branch`);if(!oe(ye))throw Error(`GitHub returned an invalid default branch: ${ye}`);return ye}function yg(P,V,z){ot(P);let Q=I(V,P),te=n(i(z,Q));if(te===null)throw Error(`Rulebook source not found: ${P}`);let ne=ed(wi(te,"Invalid local rulebook source."));if(ne.name!==P)throw Error(`rulebook name "${ne.name}" must match local source "${P}"`);return{spec:P,rulebook:ne,content:te}}async function hg(P,V){let z=A(P),Q=await td(z.owner,z.repo,z.ref,P,V),te=await qr(`https://raw.githubusercontent.com/${z.owner}/${z.repo}/${Q}/${z.path}`,"raw",V),ne=te.response;if(!ne.ok)throw Error(`Failed to fetch ${P}: GitHub raw returned ${ne.status}`);let ce=te.content,ye=ed(wi(ce,"Invalid GitHub rulebook response."));if(ye.name!==z.name)throw Error(`rulebook name "${ye.name}" must match GitHub source "${z.name}"`);return{spec:P,rulebook:ye,content:ce}}function ed(P){let V=se(P),z=Hr(V);if(z.length>0)throw Error(z.join("; "));return V}function wi(P,V){try{return JSON.parse(P)}catch{throw Error(V)}}async function td(P,V,z,Q,te){let ne=await qr(`https://api.github.com/repos/${P}/${V}/commits/${encodeURIComponent(z)}`,"commit",te),ce=ne.response;if(!ce.ok)throw Error(`Failed to resolve ${Q}: GitHub returned ${ce.status}`);let ye=JSON.parse(ne.content);if(typeof ye?.sha!=="string"||ye.sha==="")throw Error(`Failed to resolve commit for ${Q}`);return ye.sha}async function vg(P,V,z={}){if(z.signal?.aborted)throw z.signal.reason;let Q=z.budget??Gr(),te=new AbortController,ne=()=>te.abort(z.signal?.reason);z.signal?.addEventListener("abort",ne,{once:!0});let ce=!1,ye=setTimeout(()=>{if(te.signal.aborted)return;ce=!0,te.abort()},z.timeoutMs??Zc.timeoutMs);try{if(z.signal?.aborted)throw z.signal.reason;Jc(Q);let he=await fetch(P,{signal:te.signal,redirect:"error"});if(!he.ok)return nd(he),{response:he,content:""};return{response:he,content:await bg(he,V,Q,()=>te.abort())}}catch(he){if(ce)throw Error("GitHub request timed out",{cause:he});if(z.signal?.aborted)throw z.signal.reason;throw he}finally{clearTimeout(ye),z.signal?.removeEventListener("abort",ne)}}function qr(P,V,z){return vg(z.resolveUrl?.(P)??P,V,{budget:z.budget,signal:z.controller.signal})}async function bg(P,V,z=Gr(),Q){let te=Zc[`${V}Bytes`],ne=Number(P.headers.get("content-length"));if(Number.isFinite(ne)&&ne>te)throw nd(P),Error(`GitHub ${V} response exceeds ${te} bytes`);if(!P.body)return"";let ce=P.body.getReader(),ye=[],he=0;while(!0){let be=await ce.read();if(be.done)break;try{Wc(z,be.value.byteLength)}catch(xe){throw Q?.(),Yc(ce),xe}if(he+=be.value.byteLength,he>te)throw Q?.(),Yc(ce),Error(`GitHub ${V} response exceeds ${te} bytes`);ye.push(Buffer.from(be.value))}return Buffer.concat(ye,he).toString("utf-8")}function nd(P){if(!P.body)return;rd(()=>P.body?.cancel())}function Yc(P){rd(()=>P.cancel())}function rd(P){try{Promise.resolve(P()).catch(()=>{})}catch{}}var Lg=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function od(P,V){let z=ad(P.rules,V);if(z.length>0)return{ok:!0,specs:z};return sd(P.rules,V)}function id(P,V){let z=ad(P,V);if(z.length>0)return{ok:!0,specs:z};let Q=kg(P,V);if(Q.length>0)return{ok:!0,specs:Q};let te=xg(P,V);if(!te.ok)return te;if(te.specs.length>0)return{ok:!0,specs:te.specs};return sd(P,V)}function sd(P,V){let z=P.filter((Q)=>ki(Q)?.name===V);if(z.length===1)return{ok:!0,specs:z};return wg(V,z)}function wg(P,V){return{ok:!1,result:{ok:!1,errors:V.length===0?[`No configured rulebook matches ${P}`]:[`Ambiguous rulebook match ${P}: ${V.join(", ")}`],entries:[]}}}function ad(P,V){return P.filter((z)=>z===V)}function kg(P,V){let z=V.match(Lg),Q=z?.[1],te=z?.[2],ne=z?.[3];if(!Q||!te||!ne||!oe(ne))return[];return ld(P,(ce)=>ce.owner===Q&&ce.repo===te&&ce.ref===ne)}function xg(P,V){if(!q(V))return{ok:!0,specs:[]};let[z,Q]=V.split("/"),te=ld(P,(ce)=>ce.owner===z&&ce.repo===Q);if(new Set(te.map((ce)=>ki(ce)?.ref).filter((ce)=>!!ce)).size<2)return{ok:!0,specs:te};return{ok:!1,result:{ok:!1,errors:[`Multiple refs are configured for ${V}. Use an explicit ref:`,` cc-safety-net rule remove ${V}#<ref>`],entries:[]}}}function ki(P){try{return A(P)}catch{return null}}function ld(P,V){return P.filter((z)=>{let Q=ki(z);return Q?V(Q):!1})}async function zr(P,V={}){let z=Ci(V);return Sg(P,z,await Vr(P,z,zt()))}function Sg(P,V,z){if(!z.ok)return z;let Q=Pt(P,V),te=[...new Set(j(Q.configPath,Q.filesystemScope))];if(te.length===0)return z;return{ok:!1,errors:te,entries:z.entries}}async function Vr(P,V,z,Q={},te=new Set,ne=new Set){try{let ce=Pt(P,V),ye=bi(ce.configTarget);if(!ye.ok)return ye.result;let he=ye.config,be=V.only?od(he,V.only):{ok:!0,specs:he.rules};if(!be.ok)return be.result;let xe=new Set([...V.refresh?be.specs:[],...te]),Ie=(ut)=>Xc(ut,ce.configDir,ce.filesystemScope,z,xe.has(ut),!V.refresh||xe.has(ut)),Xe=await Fg(he.rules,V.refresh?(ut)=>Ie(ut).then((vt)=>({ok:!0,item:vt})).catch((vt)=>{if(zc(vt))throw vt;return{ok:!1,spec:ut,message:vt instanceof Error?vt.message:String(vt)}}):async(ut)=>({ok:!0,item:await Ie(ut)}),z),et=Xe.filter((ut)=>!ut.ok),Re=Xe.filter((ut)=>ut.ok).map((ut)=>ut.item),at=Re.flatMap((ut)=>Rg(ut,he.rules)),ct=Re.flatMap((ut)=>Pg(ut,ne,ce)),lt=new Set([...at,...ct].map((ut)=>ut.spec)),pt=[...et,...at,...ct],mt=[],gt=Dg(mt,()=>Re.flatMap((ut)=>lt.has(ut.spec)||pt.length>0&&ne.has(ut.spec)?[]:Eg(ut,ce,Q,mt)));return{ok:pt.length===0,errors:pt.map((ut)=>`Failed to update ${ut.spec}: ${ut.message}`),entries:Re.map(_g),changes:gt}}catch(ce){return Jn(ce)}}function Rg(P,V){if(!S(P.spec))return[];let z=Pe(P.spec),Q=V.filter((te)=>te!==P.spec&&Pe(te).toLowerCase()===z.toLowerCase());if(Q.length===0)return[];return[{ok:!1,spec:P.spec,message:`rulebook name "${z}" is also claimed by ${Q.join(", ")}; rename one of them`}]}function Pg(P,V,z){if(!V.has(P.spec)||!S(P.spec))return[];let Q=I(z.configDir,P.rulebook.name),te=n(i(z.filesystemScope,Q));if(te===null||te===P.content)return[];return[{ok:!1,spec:P.spec,message:`${Q} already exists and no configured source claims it; remove or rename the file, then re-run rule add`}]}function Eg(P,V,z,Q){if(!S(P.spec))return[];let te=I(V.configDir,P.rulebook.name),ne=i(V.filesystemScope,te),ce=n(ne);if(ce===P.content)return[];return Q?.push({target:ne,previous:ce}),g(ne,P.content,void 0,z._testAfterPolicyRename),Ag(P,ce)}function Dg(P,V){try{return V()}catch(z){for(let Q of[...P].reverse()){if(Q.previous===null){N(Q.target);continue}g(Q.target,Q.previous)}throw z}}function Ag(P,V){if(V===null)return[`Vendored ${P.spec} (${P.rulebook.version})`];let z=me(V),Q="problem"in z?null:z.rulebook,te=new Map(Q?.rules.map((ce)=>[ce.name,JSON.stringify(ce)])??[]),ne=new Set(P.rulebook.rules.map((ce)=>ce.name));return[`Updated ${P.spec} (${Q?.version??"unreadable"} -> ${P.rulebook.version})`,...[...ne].filter((ce)=>!te.has(ce)).map((ce)=>` + ${ce}`),...[...te.keys()].filter((ce)=>!ne.has(ce)).map((ce)=>` - ${ce}`),...P.rulebook.rules.filter((ce)=>{let ye=te.get(ce.name);return ye!==void 0&&ye!==JSON.stringify(ce)}).map((ce)=>` ~ ${ce.name}`)]}function _g(P){return{spec:P.spec,name:P.rulebook.name,version:P.rulebook.version,ruleCount:P.rulebook.rules.length}}async function cd(P,V,z={}){return Tg(P,V,Ng(z),zt())}async function Tg(P,V,z,Q,te={}){let ne=null,ce=!1;try{let ye=Pt(P,z),he=n(ye.configTarget);ne={target:ye.configTarget,content:he};let be=bi(ye.configTarget);if(!be.ok)return be.result;let xe=be.config,Ie=q(V);$g(V,z,Ie);let Xe=Ie?await Qc(V,{ref:z.ref,operation:Q}):null,et=Xe?Ig(Xe,z.rulebooks):[],Re=Xe?et.map((mt)=>Og(xe.rules,Xe,mt)??`${V}#${Xe.ref}/${mt}`):[V],at=Re.filter((mt)=>!xe.rules.includes(mt)),ct=[...xe.rules,...at];if(ct.length>pe)return jg();if(ct.length!==xe.rules.length)ce=!0,Rt(ye.configTarget,{version:1,rules:ct,overrides:xe.overrides??{},transparent_wrappers:xe.transparent_wrappers??[]},void 0,te._testAfterPolicyRename);let lt=await Vr(P,z,Q,te,new Set(at),new Set(at));if(!lt.ok)zn(ye.configTarget,he);if(!lt.ok||!Xe)return lt;let pt=et.filter((mt,gt)=>at.includes(Re[gt]??""));return{...lt,add:{source:V,ref:Xe.ref,selected:et,added:pt,alreadyConfigured:et.filter((mt)=>!pt.includes(mt)),commits:at.length>0?[Xe.commit]:[]}}}catch(ye){if(ce&&ne)try{zn(ne.target,ne.content)}catch(he){return Jn(he)}return Jn(ye)}}function $g(P,V,z){if(!z&&V.rulebooks!==void 0)throw Error("--only can only select rulebooks from an owner/repo source");if(!z&&V.ref)throw Error(`--ref can only select a ref for an owner/repo source: ${P}`);if(V.rulebooks?.length===0)throw Error("--only requires at least one rulebook name");let Q=V.rulebooks?.filter((te)=>!l.test(te))??[];if(Q.length>0)throw Error(`Invalid rulebook names: ${Q.join(", ")}`)}function Ig(P,V){let z=V?[...new Set(V)]:P.names,Q=z.filter((te)=>!P.names.includes(te));if(Q.length>0)throw Error(`Rulebooks not found in ${P.source} at ${P.ref}: ${Q.join(", ")}
|
|
264
|
+
Available rulebooks: ${P.names.join(", ")}`);return z}function Og(P,V,z){let Q=`${V.source}#${V.ref}/${z}`;if(P.includes(Q))return Q;let te=`${V.source}#${V.commit}/${z}`;return P.find((ne)=>ne===te)}async function Fg(P,V,z=zt()){if(P.length>pe)throw Error(fe);let Q=Array(P.length),te=0,ne,ce=Array.from({length:Math.min(P.length,Ur.concurrency)},async()=>{while(!ne){let ye=te;if(ye>=P.length)return;te++;try{Q[ye]=await V(P[ye],ye,z.controller.signal)}catch(he){if(!ne)ne={value:he},te=P.length,z.controller.abort(he);return}}});if(await Promise.all(ce),ne)throw ne.value;return Q}function jg(){return{ok:!1,errors:[fe],entries:[]}}function Ci(P){return{cwd:P.cwd,userConfigDir:P.userConfigDir,userConfigPath:P.userConfigPath,projectConfigPath:P.projectConfigPath,global:P.global,only:P.only,refresh:P.refresh}}function Ng(P){return{...Ci(P),ref:P.ref,rulebooks:P.rulebooks}}function Mg(P){return{...Ci(P),deleteSource:P.deleteSource}}async function dd(P,V,z={}){try{return await Hg(P,V,Mg(z),{})}catch(Q){return Jn(Q)}}async function Hg(P,V,z,Q){let te=Pt(P,z),ne=m(te.configTarget);if(ne.errors.length>0)return{ok:!1,errors:ne.errors,entries:[]};if(!ne.config)return{ok:!1,errors:[`No config found at ${te.configPath}`],entries:[]};let ce=id(ne.config.rules,V);if(!ce.ok)return ce.result;let ye=z.deleteSource?Ug(te.configDir,ce.specs,te.filesystemScope):{ok:!0,dirs:[]};if(!ye.ok)return ye.result;let he=n(te.configTarget);if(he===null)return Jn(Error("Rules config is unavailable."));try{Rt(te.configTarget,{version:1,rules:ne.config.rules.filter((Ie)=>!ce.specs.includes(Ie)),overrides:ne.config.overrides??{},transparent_wrappers:ne.config.transparent_wrappers??[]},void 0,Q._testAfterPolicyRename)}catch(Ie){throw zn(te.configTarget,he),Ie}let be=await Vr(P,z,zt(),Q);if(!be.ok)return zn(te.configTarget,he),be;let xe=Gg(ye.dirs,Q,te.filesystemScope);if(!xe.ok){zn(te.configTarget,he);let Ie=await Vr(P,z,zt(),Q);if(!Ie.ok)return{ok:!1,errors:[...xe.result.errors,...Ie.errors],entries:Ie.entries};return xe.result}return be}function Ug(P,V,z){let Q=V.flatMap((ye)=>l.test(ye)?[]:["--delete-source can only delete local rulebook sources"]),te=V.map((ye)=>xi(P,ye)),ne=Q.length>0?[]:te.flatMap((ye)=>ud(ye,z)),ce=[...Q,...ne];return ce.length>0?{ok:!1,result:{ok:!1,errors:ce,entries:[]}}:{ok:!0,dirs:te}}function ud(P,V){let z=Cg(P),Q=i(V,z),te=le(Q);if(!te)return[`Local rulebook source directory not found: ${P}`];let ne=te.find((ce)=>ce.name==="rulebook.json");if(!ne)return[`Local rulebook source directory is missing rulebook.json: ${P}`];if(ne.kind!=="file")throw new r(V.label);if(n(i(V,xi(z,"rulebook.json"))),te.length>1)return[`Local rulebook source directory contains extra files: ${P}. delete manually if you really want to remove the directory.`];return[]}function Gg(P,V,z){let Q=P.flatMap((te)=>{try{if(!le(i(z,te)))return[];let ne=ud(te,z);if(ne.length>0)return ne;return Bg(te,V,z),[]}catch(ne){return[`Failed to delete local rulebook source ${te}: ${ne instanceof Error?ne.message:String(ne)}`]}});return Q.length>0?{ok:!1,result:{ok:!1,errors:Q,entries:[]}}:{ok:!0}}function Bg(P,V,z){if(V._testDeleteLocalSourceDir){V._testDeleteLocalSourceDir(P);return}N(i(z,xi(P,ue))),nt(i(z,P))}function zn(P,V){if(V===null){N(P);return}g(P,V)}function Jn(P){return{ok:!1,errors:[P instanceof Error?P.message:String(P)],entries:[]}}var qg=".safety-net.json",Vg="~/.cc-safety-net/config.json";async function gd(P,V){return[await fd(P,{legacyPath:$s({cwd:V.cwd}),configPath:F(V.cwd),defaultRulebookName:"project-rules",migratedFrom:qg,cleanup:V.cleanup,syncOptions:{cwd:V.cwd}}),await fd(P,{legacyPath:nr(P),configPath:M(P),defaultRulebookName:"user-rules",migratedFrom:Vg,cleanup:V.cleanup,syncOptions:{cwd:V.cwd,global:!0}})].every((Q)=>Q)?0:1}async function fd(P,V){let z=Pt(P,V.syncOptions),Q=i(z.filesystemScope,V.legacyPath),te=n(Q);if(te===null)return console.log(`No legacy config found at ${V.legacyPath}`),!0;let ne=Jg(te);if(!ne.ok){for(let et of ne.errors)console.error(et);return!1}let ce=m(z.configTarget);if(ce.errors.length>0){for(let et of ce.errors)console.error(et);return!1}let ye=ce.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},he=Wg(pd(V.configPath),ye.rules,V.defaultRulebookName,V.migratedFrom,z.filesystemScope),be=Jr(pd(V.configPath),he,"rulebook.json"),xe=i(z.filesystemScope,be),Ie=[md(z.configTarget),md(xe)],Xe=await zg(P,V,z.configTarget,xe,he,ne.config.rules,ye.rules.includes(he)?ye.rules:[...ye.rules,he],ye.overrides??{},ye.transparent_wrappers??[]);if(!Xe.ok){Zg(Ie);for(let et of Xe.errors)console.error(et);return!1}if(!V.cleanup)return console.log(`Migrated legacy config at ${V.legacyPath}. Legacy file is no longer used.`),!0;if(!Yg(z.configTarget,xe,he,V.migratedFrom,ne.config.rules))return console.error(`Migration cleanup verification failed for ${V.legacyPath}`),!1;return N(Q),console.log(`Deleted legacy config at ${V.legacyPath}`),!0}async function zg(P,V,z,Q,te,ne,ce,ye,he){try{return Rt(z,{version:1,rules:ce,overrides:ye,transparent_wrappers:he}),Rt(Q,Kg(te,V.migratedFrom,ne)),await zr(P,V.syncOptions)}catch(be){return{ok:!1,errors:[be instanceof Error?be.message:String(be)]}}}function Jg(P){try{let V=JSON.parse(P),z=ro(V);if(z.errors.length>0)return{ok:!1,errors:z.errors};return{ok:!0,config:{version:1,rules:V.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function Wg(P,V,z,Q,te){let ne=V.find((ce)=>Xg(i(te,Jr(P,ce,"rulebook.json")))===Q);if(ne)return ne;if(n(i(te,Jr(P,z,"rulebook.json")))===null)return z;for(let ce=2;;ce++){let ye=`${z}-${ce}`;if(n(i(te,Jr(P,ye,"rulebook.json")))===null)return ye}}function Kg(P,V,z){return{rulebook_version:1,name:P,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:V,allowed_commands:[...new Set(z.map((Q)=>Q.command))],rules:z,tests:z.map((Q)=>({command:[Q.command,Q.subcommand,Q.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:Q.name}))}}function Yg(P,V,z,Q,te){if(!m(P).config?.rules.includes(z))return!1;try{let ce=n(V);if(ce===null)return!1;let ye=JSON.parse(ce);return ye.migrated_from===Q&&JSON.stringify(ye.rules)===JSON.stringify(te)}catch{return!1}}function md(P){return{target:P,content:n(P)}}function Zg(P){for(let V of P){if(V.content===null){N(V.target);continue}g(V.target,V.content)}}function Xg(P){let V=n(P);if(V===null)return null;try{let z=JSON.parse(V);return typeof z.migrated_from==="string"?z.migrated_from:null}catch{return null}}import{mkdir as Qg,readFile as ey,writeFile as ty}from"node:fs/promises";import{dirname as ny,join as ry}from"node:path";var oy=86400000,iy=604800000;async function hd(P,V=Date.now()){if(P.env.get("CC_SAFETY_NET_NO_UPDATE_CHECK"))return null;let z=je(P);if(!z)return null;let Q=ry(z,".cc-safety-net","update-check.json"),te=await sy(Q,V);if(!te.lastCheck||V-te.lastCheck>oy){let ye=await Wt();if(te.lastCheck=V,ye.latestVersion)te.latestVersion=ye.latestVersion;if(!await yd(Q,te))return null;if(ye.error)return null}let ne=te.latestVersion,ce=wt();if(!ne||!co(ne,ce))return null;if(te.notifiedVersion===ne&&te.notifiedAt!==void 0&&V-te.notifiedAt<iy)return null;if(te.notifiedVersion=ne,te.notifiedAt=V,!await yd(Q,te))return null;return`UPDATE_AVAILABLE: cc-safety-net v${ne} is available (running v${ce}). Ask the user once whether to run \`npx -y cc-safety-net@latest update\`; continue the current task either way and do not raise this again.`}async function sy(P,V){let z=await ey(P,"utf8").then((ne)=>JSON.parse(ne)).catch(()=>{return});if(!z||typeof z!=="object"||Array.isArray(z))return{};let Q=z,te=(ne)=>typeof ne==="number"&&Number.isFinite(ne)&&ne<=V?ne:void 0;return{lastCheck:te(Q.lastCheck),latestVersion:typeof Q.latestVersion==="string"?Q.latestVersion:void 0,notifiedVersion:typeof Q.notifiedVersion==="string"?Q.notifiedVersion:void 0,notifiedAt:te(Q.notifiedAt)}}async function yd(P,V){return Qg(ny(P),{recursive:!0,mode:448}).then(()=>ty(P,JSON.stringify(V),{mode:384})).then(()=>!0).catch(()=>!1)}import{join as ay,resolve as Si}from"node:path";var vd="CC Safety Net Config",ly="═".repeat(vd.length),cy="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",dy=new Set(["rule.json","rule.lock","cache"]);function bd(P,V={}){try{return uy(P,V)}catch(z){if(z instanceof r)return console.error(z.message),1;throw z}}function uy(P,V){let z=V.cwd??process.cwd(),Q=K(P,{cwd:z}),te=nr(P),ne=ns(z),ce=Si(z,de),ye=i(Q.userScope,te),he=i(Q.projectScope,ne),be=!1,xe=!1,Ie=[],Xe=[],et=py(i(Q.projectScope,ce));if(my(),n(Q.userConfigTarget)!==null){let Re=Jt(Q.userConfigTarget);if(Re.errors.push(...j(Q.userConfigPath,Q.userScope)),Ie.push({scope:"User",path:Q.userConfigPath,result:Re,schema:"rules",target:Q.userConfigTarget}),Re.errors.length>0)be=!0}if(n(ye)!==null)if(xe=!0,n(Q.userConfigTarget)!==null)Xe.push(Wr("user","cleanup"));else{let Re=oo(ye);if(Ie.push({scope:"User",path:te,result:Re,schema:"legacy",inactive:!0,target:ye}),Xe.push(Wr("user",Re.errors.length>0?"fix-or-delete":"migrate")),Re.errors.length>0)be=!0}if(n(Q.projectConfigTarget)!==null){let Re=Jt(Q.projectConfigTarget);if(Re.errors.push(...j(Q.projectConfigPath,Q.projectScope)),Ie.push({scope:"Project",path:Si(Q.projectConfigPath),result:Re,schema:"rules",target:Q.projectConfigTarget}),Re.errors.length>0)be=!0;if(n(he)!==null)xe=!0,Xe.push(Wr("project","cleanup"))}else if(n(he)!==null){xe=!0,be=!0;let Re=oo(he);Ie.push({scope:"Project",path:Si(ne),result:Re,schema:"legacy",inactive:!0,target:he}),Xe.push(Wr("project",Re.errors.length>0?"fix-or-delete":"migrate"))}if(et?.result.errors.length)be=!0;if(Ie.length===0&&!et)return console.log(`
|
|
265
|
+
No config files found. Using built-in rules only.`),0;for(let Re of Ie)if(Re.inactive)yy(Re.scope,Re.path,Re.result);else if(Re.result.errors.length>0)hy(Re.scope,Re.path,Re.result.errors);else{if(Re.schema==="rules"&&Ly(Re.target))console.log(`
|
|
266
|
+
Added $schema to ${Re.scope.toLowerCase()} config.`);gy(Re.scope,Re.path,Re.result,Re.schema)}for(let Re of Xe)console.error(`
|
|
267
|
+
${dt.red(Re)}`);if(et)if(et.result.errors.length>0)by(et.path,et.result.errors);else vy(et.path,et.result);if(be)return console.error(`
|
|
268
|
+
Config validation failed.`),1;return console.log(xe?`
|
|
269
269
|
Configs valid with warnings.`:`
|
|
270
|
-
All configs valid.`),0}function
|
|
271
|
-
✓ ${
|
|
272
|
-
✗ Legacy ${
|
|
273
|
-
✓ GitHub source rules: ${
|
|
274
|
-
✗ ${
|
|
275
|
-
`))}import{spawn as
|
|
276
|
-
return POSIX path of (choose folder with prompt "${
|
|
270
|
+
All configs valid.`),0}function Wr(P,V){let z=`legacy ${P} config`;if(V==="cleanup")return`Warning: Legacy ${P} config is no longer needed. Run \`npx -y cc-safety-net rule migrate --cleanup\` to clean it up safely.`;if(V==="migrate")return`Warning: Legacy ${P} config is ignored by CC Safety Net. Run \`npx -y cc-safety-net rule migrate\`.`;return`Warning: Legacy ${P} config is no longer supported. Fix or delete the ${z}, then run \`npx -y cc-safety-net rule migrate\`.`}function py(P){if(le(P)===null)return null;let V=fy(P);if(V.ruleNames.size===0&&V.errors.length===0)return null;return{path:P.path,result:V}}function fy(P){let V=[],z=new Set,Q=(le(P)??[]).filter((te)=>!dy.has(te.name)).sort((te,ne)=>te.name.localeCompare(ne.name));if(Q.length===0)return{errors:V,ruleNames:z};for(let te of Q){if(!l.test(te.name)){V.push(`rulebook directory names must match ${l}: ${te.name}`);continue}if(te.kind!=="directory"){V.push(`${te.name} must be a rulebook directory`);continue}let ne=i(P.scope,ay(P.path,te.name,"rulebook.json")),ce=n(ne);if(ce===null){V.push(`${te.name}/rulebook.json is required`);continue}try{let ye;try{ye=JSON.parse(ce)}catch{V.push(`${te.name}/rulebook.json: invalid JSON`);continue}let he=se(ye);if(he.name!==te.name){V.push(`rulebook name "${he.name}" must match folder "${te.name}"`);continue}let be=Hr(he);if(be.length>0){V.push(...be.map((xe)=>`${te.name}/rulebook.json: ${xe}`));continue}z.add(te.name)}catch(ye){V.push(ye instanceof Error?`${te.name}/rulebook.json: ${ye.message}`:`${te.name}/rulebook.json: ${String(ye)}`)}}return{errors:V,ruleNames:z}}function my(){console.log(vd),console.log(ly)}function gy(P,V,z,Q){if(console.log(`
|
|
271
|
+
✓ ${P} config: ${V}`),console.log(` Schema: ${Q==="rules"?"rulebook sources":"legacy inline rules"}`),z.ruleNames.size>0){console.log(` ${Q==="rules"?"Sources":"Rules"}:`);let te=1;for(let ne of z.ruleNames)console.log(` ${te}. ${ne}`),te++}else console.log(` ${Q==="rules"?"Sources":"Rules"}: (none)`)}function yy(P,V,z){if(console.error(`
|
|
272
|
+
✗ Legacy ${P.toLowerCase()} config: ${V}`),console.error(" Schema: legacy inline rules"),console.error(" Status: ignored by CC Safety Net"),z.errors.length>0){console.error(" Errors:");let Q=1;for(let te of z.errors)for(let ne of te.split("; "))console.error(` ${Q}. ${ne}`),Q++;return}if(z.ruleNames.size>0){console.error(" Rules:");let Q=1;for(let te of z.ruleNames)console.error(` ${Q}. ${te}`),Q++;return}console.error(" Rules: (none)")}function hy(P,V,z){Ld(`${P} config`,V,z)}function vy(P,V){console.log(`
|
|
273
|
+
✓ GitHub source rules: ${P}`),console.log(" Rulebooks:");let z=1;for(let Q of V.ruleNames)console.log(` ${z}. ${Q}`),z++}function by(P,V){Ld("GitHub source rules",P,V)}function Ld(P,V,z){console.error(`
|
|
274
|
+
✗ ${P}: ${V}`),console.error(" Errors:");let Q=1;for(let te of z)for(let ne of te.split("; "))console.error(` ${Q}. ${ne}`),Q++}function Ly(P){try{let V=n(P);if(V===null)return!1;let z=JSON.parse(V);if(z.$schema)return!1;return g(P,JSON.stringify({$schema:cy,...z},null,2)),!0}catch(V){if(V instanceof r)throw V;return!1}}var wd=new Set(["init","add","remove","update","sync","list","wrapper","migrate","doc","verify"]),ky=new Set(["add","remove","list"]),xy="cc-safety-net/rulebooks";async function kd(P,V){try{return await Cy(P,V)}catch(z){if(z instanceof r)return console.error(z.message),1;throw z}}async function Cy(P,V){let z=Ry(V),Q=z.help?Sy(z.positionals):null;if(Q)return wn(Q),0;if(z.errors.length>0){for(let ye of z.errors)console.error(ye);return 1}let te=z.positionals[0];if(!te)return wn(fn,console.error),1;let ne=z.positionals[1],ce={global:z.global};if(te==="init"){let ye=Pt(P,ce);Ay(ye.configTarget);let he=wy(ye.configDir,"example-rules","rulebook.json"),be=i(ye.filesystemScope,he);if(z.example&&n(be)===null)Vc(be);let xe=j(ye.configPath,ye.filesystemScope);for(let Ie of xe)console.error(Ie);if(xe.length>0)return 1;return console.log("Rule config initialized."),0}if(te==="add"){let ye=xd(z);if(!ye)return console.error("rule add requires a source (pass --only <rulebook...> to select from cc-safety-net/rulebooks)"),1;let he=Pt(P,ce),be=await cd(P,ye,{...ce,ref:z.ref,rulebooks:z.only.length>0?z.only:void 0});return Hc(be,ye,`Scope: ${z.global?"user":"project"} (${he.configDir})`),be.ok?0:1}if(te==="remove"){if(!ne)return console.error("rule remove requires a source"),1;let ye=await dd(P,ne,{...ce,deleteSource:z.deleteSource});return Mr(ye,`Removed rulebook source: ${ne}`),ye.ok?0:1}if(te==="update"){let ye=await zr(P,{...ce,only:ne,refresh:!0});return Mr(ye,"Rule config updated."),ye.ok?0:1}if(te==="sync")return Fs(P,{global:z.global});if(te==="list"){let ye=J(P,{cwd:process.cwd()});return Gc(ye),ye.errors.length>0?1:0}if(te==="wrapper")return _y(P,z);if(te==="migrate")return gd(P,{cleanup:z.cleanup,cwd:process.cwd()});if(te==="doc"){console.log(Nc);let ye=await hd(P);if(ye)console.error(ye);return 0}if(te==="verify")return bd(P);return 1}function Sy(P){if(P.length===0)return fn;let V=fn.subcommands.filter((Q)=>Q.usage.split(" ")[0]===P[0]);if(V.length===0)return null;if(P.length===1&&V.length>1)return{name:`rule ${P[0]}`,description:`Subcommands of rule ${P[0]}`,usage:`rule ${P[0]} <subcommand>`,subcommands:V,options:[]};let z=P.length===1?V[0]:V.find((Q)=>Q.usage.split(" ")[1]===P[1]);if(!z)return null;return{name:`rule ${P[0]}`,description:z.description,usage:`rule ${z.usage}`,options:P[0]==="add"?eo:[],examples:P[0]==="add"?to:void 0}}function Ry(P){let V=xt({label:"rule",booleans:{global:["-g","--global"],cleanup:["--cleanup"],deleteSource:["--delete-source"],example:["--example"]},values:{ref:["--ref"]},lists:{only:["--only"]},positionals:"list"},P),z={...V.flags,ref:V.values.ref,only:V.lists.only??[],help:V.help,positionals:V.positionals,errors:V.errors};return Py(z),z}function Py(P){let[V]=P.positionals;if(V&&!wd.has(V))P.errors.push(`Unknown rule subcommand: ${V}`);if(P.deleteSource&&V!=="remove")if(V&&wd.has(V))P.errors.push(`Unknown option for rule ${V}: --delete-source`);else P.errors.push("--delete-source is only valid with 'rule remove'");if(P.cleanup&&V!=="migrate")P.errors.push(Wn(V,"--cleanup"));if(P.example&&V!=="init")P.errors.push(Wn(V,"--example"));if(P.ref&&V!=="add")P.errors.push(Wn(V,"--ref"));if(P.only.length>0&&V!=="add")P.errors.push(Wn(V,"--only"));if(V==="add")Ey(P);if(V==="migrate"){if(P.global)P.errors.push(Wn(V,"--global"));if(P.positionals.length>1)P.errors.push(`Unexpected rule migrate argument: ${P.positionals[1]}`)}else if(V==="wrapper")Dy(P);else if(P.positionals.length>2)P.errors.push(`Unexpected rule argument: ${P.positionals[2]}`);if(V==="list"&&P.global)P.errors.push("Unknown option for rule list: --global")}function xd(P){if(P.positionals[1])return P.positionals[1];if(P.ref||P.only.length>0)return xy;return}function Ey(P){let V=xd(P);if(!V)return;if((P.ref||P.only.length>0)&&!q(V)){if(P.ref)P.errors.push(`--ref can only select a ref for an owner/repo source: ${V}`);if(P.only.length>0)P.errors.push("--only can only select rulebooks from an owner/repo source");return}if(P.ref&&!oe(P.ref))P.errors.push(`--ref must use valid path segments: ${P.ref}`);let z=P.only.filter((Q)=>!l.test(Q));if(z.length>0)P.errors.push(`Invalid rulebook names: ${z.join(", ")}`)}function Wn(P,V){return P?`Unknown option for rule ${P}: ${V}`:`Unknown option for rule: ${V}`}function Dy(P){let V=P.positionals[1],z=P.positionals[2];if(!V){P.errors.push("rule wrapper requires add, remove, or list");return}if(!ky.has(V)){P.errors.push(`Unknown rule wrapper action: ${V}`);return}if(V==="list"){if(z)P.errors.push(`Unexpected rule wrapper argument: ${z}`);return}if(!z){P.errors.push(`rule wrapper ${V} requires a command`);return}if(P.positionals.length>3)P.errors.push(`Unexpected rule wrapper argument: ${P.positionals[3]}`)}function Ay(P){if(n(P)===null){qc(P);return}let V=m(P);if(!V.config)return;Rt(P,{version:1,rules:V.config.rules,overrides:V.config.overrides??{},transparent_wrappers:V.config.transparent_wrappers??[]})}async function _y(P,V){let z=V.positionals[1],Q=V.positionals[2],te=Pt(P,{global:V.global}).configTarget;if(z==="list"){let he=m(te);if(he.errors.length>0){for(let be of he.errors)console.error(be);return 1}return Ty(he.config?.transparent_wrappers??[]),0}if(!Q||!w.test(Q))return console.error("transparent wrapper must match command pattern"),1;if(Le(Q))return console.error(`reserved command "${Q}" cannot be a wrapper`),1;let ne=m(te);if(ne.errors.length>0){for(let he of ne.errors)console.error(he);return 1}let ce=ne.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},ye=z==="add"?[...new Set([...ce.transparent_wrappers??[],Q])]:(ce.transparent_wrappers??[]).filter((he)=>he!==Q);return Rt(te,{version:1,rules:ce.rules,overrides:ce.overrides??{},transparent_wrappers:ye}),console.log(z==="add"?`Added transparent wrapper: ${Q}`:`Removed transparent wrapper: ${Q}`),0}function Ty(P){if(P.length===0){console.log("Transparent wrappers: (none)");return}console.log(`Transparent wrappers (${P.length}):`);for(let V of P)console.log(` - ${V}`)}import{sep as Ny}from"node:path";import{existsSync as $y,readFileSync as Iy}from"node:fs";import{join as Oy}from"node:path";async function Fy(P){if(P.isTTY)return null;return(await We(P).catch(()=>null))?.trim()||null}function jy(P){let V=P.env.get("CLAUDE_SETTINGS_PATH");if(V)return V;return Oy(P.home,".claude","settings.json")}function Ri(P){let V=jy(P);if(!$y(V))return!1;try{let z=Iy(V,"utf-8"),Q=JSON.parse(z);if(!Q.enabledPlugins)return!1;let te="cc-safety-net@cc-marketplace";if(!(te in Q.enabledPlugins))return!1;return Q.enabledPlugins[te]===!0}catch(z){if(L(o.debug,P.env))console.error(`CC Safety Net debug: failed to read Claude settings: ${V}: ${z instanceof Error?z.message:String(z)}`);return!1}}async function Pi(P,V=process.stdin){let z=Ri(P),Q;if(!z)Q="\uD83D\uDEE1️ CC Safety Net ❌";else{let ne=E(P,{cwd:process.cwd()}),ce=ne.policy,ye=R(ce,P.env),he=Object.values(G(ce,ye.capabilities)).some((Ie)=>Ie.changesInherited),be={standard:"✅",strict:"\uD83D\uDD12",paranoid:"\uD83D\uDC41️",custom:"\uD83D\uDD27"}[he?"custom":ye.effectiveLevel],xe=(ne.policyScopes?.weakenings.length??0)>0?"\uD83D\uDD3B":"";Q=`\uD83D\uDEE1️ CC Safety Net ${be}${ye.worktreeMode?"\uD83C\uDF33":""}${xe}${ne.state==="degraded"?"⚠️":""}`}let te=await Fy(V);if(te&&!te.startsWith("{"))console.log(`${te} | ${Q}`);else console.log(Q)}function Cd(P){let V=E(P,{cwd:process.cwd()}),z=V.policy,Q=R(z,P.env),te=!!process.env.NO_COLOR||!process.stdout.isTTY,ne=Math.min(process.stdout.columns||80,100),ce=te?"ok":"✔",ye=te?"OFF":"✘",he=(at,ct)=>{let lt=` ${at.padEnd(13)}${ct}`;return(lt.length>ne?`${lt.slice(0,ne-1)}…`:lt).replaceAll(ye,dt.red(ye))},be=Object.values(G(z,Q.capabilities)).some((at)=>at.changesInherited),xe=(at)=>at===P.home||at.startsWith(`${P.home}${Ny}`)?`~${at.slice(P.home.length)}`:at,Ie={ready:dt.green,degraded:dt.yellow}[V.state],Xe=V.policyScopes?.weakenings??[],et=[...Ri(P)?[]:["plugin cc-safety-net@cc-marketplace is disabled in Claude Code; nothing is enforced in Claude Code until it is re-enabled. Other integrations are not affected."],...V.diagnostics],Re=te?"-":"·";console.log([`${te?"":"\uD83D\uDEE1️ "}CC Safety Net — ${Ie(V.state)}`,"",he("Protection",`destructive ${z.destructiveCommandProtectionEnabled?ce:ye} secrets ${z.secretProtection.enabled?ce:ye}`),he("Level",be?`${Q.effectiveLevel} (customised)`:Q.effectiveLevel),he("Rules",z.rules.length===0?"none active":`${z.rules.length} active`),he("Policy",xe(u(P))),...V.policyScopes?[he("Project",xe(b(process.cwd())))]:[],...Q.worktreeMode?[he("Worktree","relaxations active")]:[],"",...Xe.length===0?[]:[" Project policy",...Xe.flatMap((at)=>jn(at," ",ne-6).map((ct,lt)=>lt===0?` ${ct}`:ct)),""],...et.length===0?[" Everything configured is active."]:[" Not active",...et.flatMap((at)=>jn(at," ",ne-6).map((ct,lt)=>lt===0?` ${Re} ${ct}`:ct)),""," Full report: cc-safety-net doctor"]].join(`
|
|
275
|
+
`))}import{spawn as Od}from"node:child_process";import{randomBytes as Wy}from"node:crypto";import{existsSync as Ky}from"node:fs";import{createServer as Yy}from"node:http";import{Writable as Zy}from"node:stream";var Kr=500;function My(P){let V=P.filter((te)=>te.decision!=="allow"),z=P.filter((te)=>te.decision==="allow"),Q=Math.min(V.length,Math.max(Kr-z.length,Math.ceil(Kr/2)));return[...V.slice(0,Q),...z.slice(0,Kr-Q)]}function Sd(P,V,z=O(P)){if(z)B(P,z);let Q=(ct)=>new Date(ct.getFullYear(),ct.getMonth(),ct.getDate()).getTime(),te=Q(new Date),ne=new Date(te);ne.setDate(ne.getDate()-(V-1));let ce=ne.getTime(),ye=[],he={count:0};for(let ct of z?Yt(z,he):[])for(let lt of pn(ct,he)){let pt=new Date(lt.ts).getTime();if(!Number.isFinite(pt))continue;if(pt>=ce)ye.push(lt)}ye.sort((ct,lt)=>new Date(lt.ts).getTime()-new Date(ct.ts).getTime());let be=Array.from({length:V},()=>0),xe=Array.from({length:V},()=>0),Ie={},Xe={},et={},Re=0,at=0;for(let ct of ye){let lt=ct.agent||"unknown";Ie[lt]=(Ie[lt]??0)+1;let pt=Math.round((te-Q(new Date(ct.ts)))/86400000),mt=V-1-pt,gt=pt>=0&&pt<V;if(gt)xe[mt]=(xe[mt]??0)+1;if(ct.decision!=="allow"){if(Re++,ct.ruleId)Xe[ct.ruleId]=(Xe[ct.ruleId]??0)+1;let ut=Qr(ct.segment||ct.command);if(ut)et[ut]=(et[ut]??0)+1;if(ct.failureStage)at++;if(gt)be[mt]=(be[mt]??0)+1}}return{days:V,logsDir:z,homeDir:P.home,totalInWindow:ye.length,truncated:ye.length>Kr,unreadable:he.count,counts:{blocked:Re,allowed:ye.length-Re,agents:Ie,blockedByDay:be,analyzedByDay:xe,rules:Xe,commands:et,errors:at},entries:My(ye).sort((ct,lt)=>new Date(lt.ts).getTime()-new Date(ct.ts).getTime())}}import{spawn as Hy}from"node:child_process";import{existsSync as Uy,statSync as Rd}from"node:fs";import{delimiter as Gy,join as By}from"node:path";var qy=120000,Yr="Choose the project folder",Vy=`try
|
|
276
|
+
return POSIX path of (choose folder with prompt "${Yr}")
|
|
277
277
|
on error number -128
|
|
278
278
|
return ""
|
|
279
|
-
end try`,
|
|
279
|
+
end try`,zy=`Add-Type -AssemblyName System.Windows.Forms
|
|
280
280
|
$dialog = New-Object System.Windows.Forms.FolderBrowserDialog
|
|
281
|
-
$dialog.Description = '${
|
|
282
|
-
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,
|
|
281
|
+
$dialog.Description = '${Yr}'
|
|
282
|
+
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,Pd=[{binary:"zenity",args:["--file-selection","--directory",`--title=${Yr}`]},{binary:"kdialog",args:["--getexistingdirectory",".","--title",Yr]}],Ed=(P,V)=>(V.PATH??"").split(Gy).some((z)=>{if(z.length===0)return!1;try{let Q=Rd(By(z,P));return Q.isFile()&&(Q.mode&73)!==0}catch{return!1}});function Ei(P,V){if(P==="darwin"||P==="win32")return!0;if(P!=="linux")return!1;if(!V.DISPLAY&&!V.WAYLAND_DISPLAY)return!1;return Pd.some((z)=>Ed(z.binary,V))}function Jy(P,V){if(P==="darwin")return{cmd:"osascript",args:["-e",Vy]};if(P==="win32")return{cmd:"powershell.exe",args:["-NoProfile","-STA","-Command",zy]};let z=Pd.find((Q)=>Ed(Q.binary,V));return z?{cmd:z.binary,args:z.args}:null}function Di(P=process.platform,V=process.env){let z=Jy(P,V);if(!z)return Promise.resolve({error:"No folder dialog is available on this system"});return new Promise((Q)=>{let te=Hy(z.cmd,z.args,{env:V,stdio:["ignore","pipe","pipe"]}),ne="",ce=!1,ye=(be)=>{if(ce)return;ce=!0,clearTimeout(he),Q(be)},he=setTimeout(()=>{te.kill(),ye({error:"The folder dialog timed out"})},qy);te.stdout.on("data",(be)=>{ne+=be.toString()}),te.on("error",()=>ye({error:`Could not open the folder dialog (${z.cmd})`})),te.on("close",()=>{let be=ne.trim().replace(/\/+$/,"");if(!be)return ye({cancelled:!0});if(!Uy(be)||!Rd(be).isDirectory())return ye({error:"That selection is not a folder on disk"});ye({path:be})})})}var Dd=`<!doctype html>
|
|
283
283
|
<html lang="en">
|
|
284
284
|
<head>
|
|
285
285
|
<meta charset="utf-8">
|
|
@@ -5905,6 +5905,6 @@ load().then((loaded) => {
|
|
|
5905
5905
|
</script>
|
|
5906
5906
|
</body>
|
|
5907
5907
|
</html>
|
|
5908
|
-
`;var
|
|
5909
|
-
`),{path:
|
|
5910
|
-
`)}}finally{console.log=
|
|
5908
|
+
`;var Ad='<script id="ccsn-data" type="application/json">';function _d(P){return Dd.replace(Ad,()=>Ad+JSON.stringify({token:P}).replaceAll("<","\\u003c"))}var Zr="kenryu42/cc-safety-net",Xy=`https://github.com/${Zr}`,Ti=1e4,Qy=7,eh="The project draft directory changed; reload the draft before applying.",th="audit settings are user scope only; remove the audit section from a project proposal";async function Fd(P,V={}){let z=xt({label:"gui",booleans:{noOpen:["--no-open"]}},P),Q=V.log??console.log,te=V.error??console.error;if(z.errors.length>0){for(let ce of z.errors)te(ce);return te("Usage: cc-safety-net gui [--no-open]"),1}let ne=await nh(c,V);if(Q(`CC Safety Net policy GUI: ${ne.url}`),!z.flags.noOpen)try{await(V.openBrowser??fh)(ne.url)}catch(ce){te(`Failed to open browser: ${ce instanceof Error?ce.message:String(ce)}`),te(`Open this URL manually: ${ne.url}`)}if(V.keepAlive===!1)return await ne.close(),0;return await ph(ne),0}async function nh(P,V={}){let z=Wy(24).toString("base64url"),Q={dir:null,revision:0},te=Yy((ye,he)=>{rh(P,ye,he,z,V,Q)});await new Promise((ye,he)=>{te.once("error",he),te.listen(0,"127.0.0.1",()=>{te.off("error",he),ye()})});let ce=`http://127.0.0.1:${te.address().port}`;return{origin:ce,token:z,url:`${ce}/?token=${encodeURIComponent(z)}`,close:()=>uh(te)}}async function rh(P,V,z,Q,te,ne){let ce=P(),ye=new URL(V.url??"/","http://127.0.0.1");if(V.method==="GET"&&ye.pathname==="/favicon.ico"){z.writeHead(204,{"cache-control":"no-store"}),z.end();return}if(!lh(V,ye,Q)){yt(z,403,{error:"Forbidden"});return}if(V.method==="GET"&&ye.pathname==="/"){dh(z,_d(Q));return}if(V.method==="GET"&&ye.pathname==="/api/policy"){let he=_c(ce,te),be=E(ce,Ai(te));yt(z,200,{...he,configState:Ne(be),...be.policyScopes?{projectPolicy:{path:b(te.cwd??process.cwd()),weakenings:be.policyScopes.weakenings}}:{},destructiveCommandRules:U,secretPatterns:Ke,version:wt(),preview:he.errors.length>0?null:Ae(he.policy,ce.env)});return}if(V.method==="POST"&&ye.pathname==="/api/policy/preview"){let he=await Kn(V);if(!he.ok){yt(z,he.status,{errors:[he.error]});return}let be=Tc(ce,he.value);yt(z,be.errors.length>0?400:200,be);return}if(V.method==="POST"&&ye.pathname==="/api/policy/explain"){let he=await Kn(V);if(!he.ok){yt(z,he.status,{errors:[he.error]});return}let be=he.value;if(be===null||typeof be.command!=="string"){yt(z,400,{errors:["command must be a string"]});return}let xe=qn(be.policy,ce.home);if(xe.length>0){yt(z,400,{errors:xe});return}yt(z,200,sh(ce,be.command,be.policy,te));return}if(V.method==="POST"&&ye.pathname==="/api/policy"){let he=await Kn(V);if(!he.ok){yt(z,he.status,{errors:[he.error]});return}let be=Vt(ce,he.value,te);yt(z,be.errors.length>0?400:200,be);return}if(V.method==="POST"&&ye.pathname==="/api/reset"){yt(z,200,Vt(ce,Z,te));return}if(V.method==="POST"&&ye.pathname==="/api/repair"){yt(z,200,$c(ce,te));return}if(V.method==="POST"&&ye.pathname==="/api/policy/project/choose-directory"){let he=await(te.chooseDirectory??Di)();if("path"in he)ne.dir=he.path,ne.revision+=1;yt(z,200,{cancelled:"cancelled"in he,..."error"in he?{error:he.error}:{}});return}if(V.method==="GET"&&ye.pathname==="/api/policy/project"){let he=jd(ne,te),be=Td(he,ce.home),xe=Vn(ce,te);yt(z,200,{path:b(he),revision:ne.revision,baseline:xe.baseline,userPolicyDiagnostics:xe.diagnostics,projection:be.projection,projectionDiagnostics:be.diagnostics,canPickDirectory:Ei(process.platform,process.env)});return}if(V.method==="POST"&&ye.pathname==="/api/policy/project/diff"){let he=await $d(ce,V,z,ne,te);if(!he)return;let be=Td(he.dir,ce.home),xe=Vn(ce,te).baseline,Ie=Y(xe,ae(he.proposal,ce.home).policy);yt(z,200,{rows:jr(Y(xe,be.projection).policy,Ie.policy,!1),weakenings:Ie.weakenings,existingFileDiagnostics:be.diagnostics});return}if(V.method==="POST"&&ye.pathname==="/api/policy/project/apply"){let he=await $d(ce,V,z,ne,te);if(!he)return;let be=ih(he.dir,he.proposal,ce.home);yt(z,be.errors.length>0?500:200,be);return}if(V.method==="GET"&&ye.pathname==="/api/activity"){let he=ee(ce,te),be=ah(ye.searchParams.get("days"),he);if(be===null){yt(z,400,{error:`days must be an integer between 1 and ${he}`});return}yt(z,200,Sd(ce,be,te.activityLogsDir));return}if(V.method==="POST"&&ye.pathname==="/api/rules/choose-directory"){yt(z,200,await Di());return}if(V.method==="GET"&&ye.pathname==="/api/rules"){let he=J(ce,Ai(te)),be=new Map(he.rules.map((xe)=>[xe.name,xe]));yt(z,200,{projectPath:te.cwd??process.cwd(),canPickDirectory:Ei(process.platform,process.env),rulebooks:he.rulebooks.map((xe)=>({source:xe.source,spec:xe.spec,name:xe.name,version:xe.version,rules:xe.rules.flatMap((Ie)=>{let Xe=be.get(Ie);if(!Xe)return[];return[{name:Xe.name,command:Xe.command,subcommand:Xe.subcommand,block_args:Xe.block_args,reason:Xe.reason}]})})),errors:he.errors,warnings:he.warnings});return}if(V.method==="GET"&&ye.pathname==="/api/star/context"){yt(z,200,await(te.fetchStarContext??(()=>bh(ce,{logsDir:te.activityLogsDir})))());return}if(V.method==="POST"&&ye.pathname==="/api/star"){let he=await(te.starRepo??mh)();yt(z,200,he.ok?{ok:!0}:{ok:!1,fallbackUrl:Xy});return}if(V.method==="GET"&&ye.pathname==="/api/integrations"){yt(z,200,await(te.fetchIntegrations??(()=>gh(ce)))());return}if(V.method==="GET"&&ye.pathname==="/api/health"){yt(z,200,await(te.fetchHealth??hh)());return}if(V.method==="POST"&&(ye.pathname==="/api/install"||ye.pathname==="/api/uninstall")){let he=await Kn(V);if(!he.ok){yt(z,he.status,{errors:[he.error]});return}let be=he.value?.target;if(typeof be!=="string"||!Mt.some((Ie)=>Ie.target===be)){yt(z,400,{error:"unknown target"});return}let xe=ye.pathname==="/api/install"?"install":"uninstall";yt(z,200,await(te.runIntegration??vh)(xe,be));return}yt(z,404,{error:"Not found"})}function Ai(P){return{...P,cwd:P.cwd??process.cwd()}}function jd(P,V){return P.dir??V.cwd??process.cwd()}function Td(P,V){let z=b(P),Q=Ky(z)?dn(z):{value:void 0,errors:[]},te=ae(Q.value,V);return{projection:te.policy,diagnostics:[...Q.errors,...te.diagnostics]}}async function $d(P,V,z,Q,te){let ne=jd(Q,te),ce=Q.revision,ye=await Kn(V);if(!ye.ok)return yt(z,ye.status,{errors:[ye.error]}),null;let he=ye.value;if(typeof he?.revision!=="number")return yt(z,400,{errors:["revision must be a number"]}),null;if(he.revision!==ce)return yt(z,409,{errors:[eh]}),null;let be=oh(he.proposal,P.home);if(be.length>0)return yt(z,400,{errors:be}),null;return{dir:ne,proposal:he.proposal}}function oh(P,V){let z=qn(P,V);if(z.length>0)return z;return P?.audit===void 0?[]:[th]}function ih(P,V,z){let Q=b(P),te=Nr(V,C(V,z));try{return g(i(v(P,"project policy"),Q),`${JSON.stringify(te,null,2)}
|
|
5909
|
+
`),{path:Q,errors:[]}}catch(ne){return{path:Q,errors:[ne instanceof Error?ne.message:String(ne)]}}}function sh(P,V,z,Q){let te=C(z,P.home),ne=E(P,Ai(Q)),ce=Ee({rules:ne.policy.rules,transparentWrappers:ne.policy.transparentWrappers,safety:De(te.safety),worktreeMode:te.workflow.worktree_mode,destructiveCommandProtectionEnabled:te.destructive_command_protection.enabled,destructiveCommandRuleOverrides:te.destructive_command_protection.overrides,destructiveCommandAllowPaths:te.destructive_command_protection.allow_paths,secretProtection:{enabled:te.secret_protection.enabled,disabledRules:Oe(te.secret_protection.overrides),denyPaths:te.secret_protection.deny_paths,allowPaths:te.secret_protection.allow_paths}});return Nn(V,{policySnapshot:ce,cwd:Q.cwd,userConfigDir:Q.userConfigDir},P)}function ah(P,V){if(P===null)return Math.min(Qy,V);let z=Number(P);if(!Number.isInteger(z)||z<1||z>V)return null;return z}function lh(P,V,z){if(V.searchParams.get("token")!==z)return!1;if(P.method!=="POST")return!0;return P.headers["x-cc-safety-net-token"]===z}var ch=1048576;async function Kn(P){let V=[],z=0;for await(let Q of P){let te=Q;if(z+=te.byteLength,z>ch)return{ok:!1,status:413,error:"Request body is too large"};V.push(te)}try{return{ok:!0,value:JSON.parse(Buffer.concat(V).toString("utf-8")||"{}")}}catch(Q){return{ok:!1,status:400,error:`Invalid JSON: ${Q instanceof Error?Q.message:String(Q)}`}}}function dh(P,V){P.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),P.end(V)}function yt(P,V,z){P.writeHead(V,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}),P.end(JSON.stringify(z))}function uh(P){return new Promise((V,z)=>{P.close((Q)=>Q?z(Q):V())})}function ph(P){return new Promise((V)=>{let z=()=>{process.off("SIGINT",Q),process.off("SIGTERM",Q)},Q=()=>{z(),P.close().then(V)};process.once("SIGINT",Q),process.once("SIGTERM",Q)})}function fh(P){let V=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",z=process.platform==="win32"?["/c","start","",P]:[P];return new Promise((Q,te)=>{let ne=Od(V,z,{detached:!0,stdio:"ignore"}),ce=(he)=>{ne.off("spawn",ye),te(he)},ye=()=>{ne.off("error",ce),ne.unref(),Q()};ne.once("error",ce),ne.once("spawn",ye)})}async function mh(P="gh",V=Ti){return{ok:await _i(P,["api","-X","PUT",`/user/starred/${Zr}`],V)===0}}async function gh(P,V={}){let z=await sr(V.fetcher),Q=yh(P,z);return{targets:$t.map((te)=>{let ne=Q.find((ce)=>ce.platform===te.id);return{target:te.id,label:bt(te.id),version:z.versions[te.id]??null,status:ne?.configured?"active":ne?.detected?"disabled":ne?.inspectionStatus==="not-inspected"?"not-inspected":"not-installed"}}),system:{version:z.version,nodeVersion:z.nodeVersion,platform:z.platform}}}function yh(P,V){return Ln(P,process.cwd(),{ampPluginListOutput:V.ampPluginListOutput,codexPluginListOutput:V.codexPluginListOutput,copilotCliVersion:V.versions["copilot-cli"]})}async function hh(P={}){let V=await(P.checkUpdates??Wt)();return{update:{latestVersion:V.latestVersion??null,updateAvailable:V.updateAvailable}}}var Id=Promise.resolve();function vh(P,V,z={}){let Q=async()=>{let ne=[],{log:ce,error:ye}=console;console.log=(...he)=>ne.push(he.map(String).join(" ")),console.error=console.log;try{return{ok:await Bn(P,[],{selectTargets:async()=>[V],output:new Zy({write(be,xe,Ie){ne.push(String(be).replace(/\n$/,"")),Ie()}}),...z})===0,output:ne.join(`
|
|
5910
|
+
`)}}finally{console.log=ce,console.error=ye}},te=Id.then(Q);return Id=te.then(()=>{return},()=>{return}),te}async function bh(P,V={}){let[z,Q,te]=await Promise.all([Lh(V.command),wh(V.fetchRepo),Promise.resolve(tr(P,ee(P),V.logsDir).totalBlocked)]);return{starred:z,starCount:Q,blockedTotal:te}}async function Lh(P="gh",V=Ti){if(await _i(P,["auth","status"],V)!==0)return null;let z=await _i(P,["api",`/user/starred/${Zr}`],V);if(z===0)return!0;if(z===null)return null;return!1}function _i(P,V,z){return new Promise((Q)=>{let te=Od(P,V,{stdio:"ignore",windowsHide:!0}),ne=!1,ce,ye=(he)=>{if(ne)return;if(ne=!0,ce)clearTimeout(ce);Q(he)};te.once("error",()=>ye(null)),te.once("close",ye),ce=setTimeout(()=>{te.kill(),ye(null)},z)})}async function wh(P=fetch){try{let V=await P(`https://api.github.com/repos/${Zr}`,{headers:{accept:"application/vnd.github+json"},signal:AbortSignal.timeout(Ti)});if(!V.ok)return null;let z=await V.json();return typeof z.stargazers_count==="number"?z.stargazers_count:null}catch{return null}}function kh(P){if(P[0]!=="help")return!1;let V=P[1];if(!V)ti(),process.exit(0);if(Mn(V))process.exit(0);console.error(`Unknown command: ${V}`),console.error("Run 'cc-safety-net --help' for available commands."),process.exit(1)}var xh={hook:async()=>{console.error("hook requires exactly one integration flag. Try: cc-safety-net hook --kimi-code"),Mn("hook",console.error),process.exit(1)},install:async(P)=>{process.exit(await Bn("install",P))},update:async(P)=>{process.exit(await yi(P))},uninstall:async(P)=>{process.exit(await Bn("uninstall",P))},rule:async(P)=>{process.exit(await kd(c(),P))},policy:async(P)=>{process.exit(await jc(c(),P))},status:async(P)=>{if(Ht(xt({label:"status"},P).errors))process.exit(1);Cd(c())},statusline:async(P)=>{let V=xt({label:"statusline",booleans:{claudeCode:["-cc","--claude-code"]}},P);if(V.errors.length===0&&V.flags.claudeCode){await Pi(c());return}if(Ht(V.errors),!V.flags.claudeCode)console.error("statusline requires --claude-code (-cc)");Mn("statusline",console.error),process.exit(1)},doctor:async(P)=>{let V=Jo(P);if(!V)process.exit(1);let z=await cl(c(),{json:V.json,skipUpdateCheck:V.skipUpdateCheck});process.exit(z)},logs:async(P)=>{process.exit(await Hi(c(),P))},gui:async(P)=>{process.exit(await Fd(P))},explain:async(P)=>{process.exit(await Ll(c(),P))}};async function Ch(P){let V=xt({label:"cc-safety-net",booleans:{version:["-V","--version"]},positionals:"list"},P);if(kh(P))return;let z=P[0],Q=z?er(z):void 0;if(V.help&&Q&&Q.name!=="rule")Mn(Q.name),process.exit(0);if(!z||V.help&&!Q)ti(),process.exit(0);if(V.flags.version)xl(),process.exit(0);if(Q){await xh[Q.name](P.slice(1));return}if(z==="--statusline"){await Pi(c());return}console.error(z.startsWith("-")?`Unknown option: ${z}`:`Unknown command: ${z}`),console.error("Run 'cc-safety-net --help' for usage."),process.exit(1)}export{Ch as runCli};
|