@rulemetric/cli 0.7.4 → 0.7.5
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 +10 -8
- package/dist/base-command.js +1 -1
- package/dist/{chunk-O7ZMHCMG.js → chunk-2JRDG4LJ.js} +14 -14
- package/dist/chunk-2WLVDSAP.js +2 -0
- package/dist/{chunk-F2VP4B4J.js → chunk-32EEBARV.js} +1 -1
- package/dist/chunk-43YBXX7R.js +1 -0
- package/dist/{chunk-HOHD5HY2.js → chunk-AYUJY37O.js} +1 -1
- package/dist/{chunk-VAFAH6QL.js → chunk-DCLWFGEA.js} +1 -1
- package/dist/{chunk-IY5NXR3N.js → chunk-DPFNJZUO.js} +1 -1
- package/dist/chunk-G63KMH6U.js +1 -0
- package/dist/{chunk-T3W5N3BP.js → chunk-G6XGDHGC.js} +1 -1
- package/dist/{chunk-TIQ7DQ3M.js → chunk-H2ORWIEY.js} +1 -1
- package/dist/chunk-H4SV7FN4.js +1 -0
- package/dist/chunk-HS7X43XE.js +24 -0
- package/dist/{chunk-Y65CSJFF.js → chunk-JAPCCEKF.js} +1 -1
- package/dist/chunk-JQTGQXUX.js +1 -0
- package/dist/{chunk-V5QFOF4F.js → chunk-KAF3CYRW.js} +1 -1
- package/dist/{chunk-EUHNCVJQ.js → chunk-KV325CXF.js} +3 -3
- package/dist/{chunk-FHVBTDBM.js → chunk-N7TGRFVZ.js} +13 -12
- package/dist/{chunk-I4YJ7NTX.js → chunk-NEACEHQD.js} +1 -1
- package/dist/chunk-O2SDD2WW.js +1 -0
- package/dist/chunk-O6C2UGBY.js +7 -0
- package/dist/chunk-PPKPCXJD.js +4 -0
- package/dist/{chunk-VWEXKDWG.js → chunk-QFVGUZDO.js} +1 -1
- package/dist/{chunk-VMWY7KHH.js → chunk-RDET7CKR.js} +1 -1
- package/dist/chunk-RQ424GI6.js +5 -0
- package/dist/{chunk-PZS2KOU7.js → chunk-TIOKY2IA.js} +1 -1
- package/dist/chunk-TQMG647B.js +15 -0
- package/dist/{chunk-WJUQBMTF.js → chunk-U6ABMRT3.js} +1 -1
- package/dist/chunk-U6XEU573.js +1 -0
- package/dist/{chunk-CRAKDQ4H.js → chunk-V44SRRYR.js} +1 -1
- package/dist/{chunk-7XQ4VPLC.js → chunk-VAXRCSSH.js} +1 -1
- package/dist/{chunk-WPJ2BND4.js → chunk-VLOX6KOM.js} +1 -1
- package/dist/chunk-W2MOTOQE.js +1 -0
- package/dist/chunk-XICLXXRH.js +1 -0
- package/dist/{chunk-2UC3ULIG.js → chunk-XXDZJ6YI.js} +1 -1
- package/dist/{chunk-SBILN45P.js → chunk-ZR3MUNLS.js} +1 -1
- package/dist/commands/antigravity/backfill.js +1 -1
- package/dist/commands/auth/create-key.js +1 -1
- package/dist/commands/auth/login.js +1 -1
- package/dist/commands/auth/logout.js +1 -1
- package/dist/commands/auth/revoke-key.js +4 -1
- package/dist/commands/auth/signup.js +1 -1
- package/dist/commands/auth/status.js +1 -1
- package/dist/commands/catalog/index.js +1 -1
- package/dist/commands/catalog/recommend.js +1 -1
- package/dist/commands/convert.js +1 -1
- package/dist/commands/converters.js +1 -1
- package/dist/commands/crons/list.js +1 -1
- package/dist/commands/crons/run.js +1 -1
- package/dist/commands/dashboard.js +1 -1
- package/dist/commands/diagnostics.js +1 -1
- package/dist/commands/eval-targets/create.js +1 -1
- package/dist/commands/eval-targets/list.js +1 -1
- package/dist/commands/evals/agent.js +1 -1
- package/dist/commands/evals/benchmark.js +1 -1
- package/dist/commands/evals/compare.js +1 -1
- package/dist/commands/evals/create.js +1 -1
- package/dist/commands/evals/optimize-description.js +15 -15
- package/dist/commands/evals/optimize.js +5 -5
- package/dist/commands/evals/run.js +1 -1
- package/dist/commands/gateway/ensure.js +1 -1
- package/dist/commands/hooks/install.js +1 -1
- package/dist/commands/hooks/run.js +1 -1
- package/dist/commands/hooks/uninstall.js +1 -1
- package/dist/commands/import.js +1 -1
- package/dist/commands/instructions/create.js +1 -1
- package/dist/commands/instructions/delete.js +1 -1
- package/dist/commands/instructions/fork.js +1 -1
- package/dist/commands/instructions/get.js +1 -1
- package/dist/commands/instructions/list.js +1 -1
- package/dist/commands/instructions/promote.js +1 -1
- package/dist/commands/instructions/pull.js +1 -1
- package/dist/commands/instructions/upstream.js +1 -1
- package/dist/commands/instructions/versions.js +1 -1
- package/dist/commands/launcher.js +1 -1
- package/dist/commands/org/current.js +1 -1
- package/dist/commands/org/list.js +1 -1
- package/dist/commands/org/switch.js +1 -1
- package/dist/commands/packs/add-instruction.js +1 -1
- package/dist/commands/packs/apply.js +1 -1
- package/dist/commands/packs/create.js +1 -1
- package/dist/commands/packs/fork.js +1 -1
- package/dist/commands/packs/get.js +1 -1
- package/dist/commands/packs/list.js +1 -1
- package/dist/commands/packs/remove-instruction.js +1 -1
- package/dist/commands/proxy/env.js +1 -1
- package/dist/commands/proxy/logs.js +1 -1
- package/dist/commands/proxy/restart.js +1 -1
- package/dist/commands/proxy/setup.js +13 -11
- package/dist/commands/proxy/start.js +1 -1
- package/dist/commands/proxy/status.js +1 -1
- package/dist/commands/proxy/stop.js +1 -1
- package/dist/commands/research/backfill.js +1 -1
- package/dist/commands/research/tail-transcript.js +1 -1
- package/dist/commands/service/install.js +5 -5
- package/dist/commands/service/status.js +1 -1
- package/dist/commands/service/uninstall.js +1 -1
- package/dist/commands/sessions/analyze.js +1 -3
- package/dist/commands/sessions/end.js +2 -2
- package/dist/commands/sessions/import.js +1 -1
- package/dist/commands/sessions/list.js +1 -1
- package/dist/commands/sessions/start.js +1 -1
- package/dist/commands/setup.js +1 -1
- package/dist/commands/skills/export-approved.js +1 -1
- package/dist/commands/skills/install.js +1 -1
- package/dist/commands/skills/list.js +1 -1
- package/dist/commands/skills/publish.js +1 -1
- package/dist/commands/skills/search.js +1 -1
- package/dist/commands/skills/update.js +1 -1
- package/dist/commands/suggestions/accept.js +3 -3
- package/dist/commands/suggestions/dismiss.js +1 -1
- package/dist/commands/suggestions/list.js +2 -1
- package/dist/commands/suggestions/refresh.js +1 -1
- package/dist/dashboard/Dashboard.js +1 -1
- package/dist/dashboard/data.js +1 -1
- package/dist/dashboard/launcher/LauncherOverlay.js +1 -1
- package/dist/dashboard/launcher/api.js +1 -1
- package/dist/dashboard/launcher/useLaunchJobs.js +1 -1
- package/dist/dashboard/panels/insights.js +1 -1
- package/dist/lib/active-org-refresh.js +1 -1
- package/dist/lib/agent-loop.js +1 -1
- package/dist/lib/antigravity-transcript.js +1 -1
- package/dist/lib/api-client.js +1 -1
- package/dist/lib/auth.js +1 -1
- package/dist/lib/editor-proxy-pins.js +1 -1
- package/dist/lib/ensure-api-key.js +1 -1
- package/dist/lib/ensure-fresh-token.js +1 -0
- package/dist/lib/eval-benchmark.js +1 -1
- package/dist/lib/eval-conversation-handler.js +1 -1
- package/dist/lib/eval-trigger-tester.js +1 -1
- package/dist/lib/handlers/cron-refresh-pricing.js +1 -1
- package/dist/lib/handlers/cron-suggest-instructions.js +1 -1
- package/dist/lib/handlers/process-announcement.js +1 -1
- package/dist/lib/handlers/process-changelog.js +1 -1
- package/dist/lib/handlers/process-conversation.js +1 -1
- package/dist/lib/handlers/process-eval.js +1 -1
- package/dist/lib/handlers/process-insights.js +1 -1
- package/dist/lib/handlers/process-launch.js +1 -1
- package/dist/lib/handlers/process-run-cleanup.js +1 -1
- package/dist/lib/handlers/process-session-goal.js +1 -1
- package/dist/lib/hooks-config.js +1 -1
- package/dist/lib/insights-prompts.js +1 -1
- package/dist/lib/manual-tasks.js +1 -1
- package/dist/lib/research-client.js +1 -1
- package/dist/lib/setup-steps.js +1 -1
- package/dist/lib/telemetry.js +1 -1
- package/dist/lib/terminal-target-heartbeat.js +1 -1
- package/oclif.manifest.json +145 -167
- package/package.json +7 -7
- package/dist/chunk-72XLQE3X.js +0 -2
- package/dist/chunk-AHRHCERJ.js +0 -1
- package/dist/chunk-DT4GKEP5.js +0 -5
- package/dist/chunk-E4SFUPYR.js +0 -15
- package/dist/chunk-FEHM5OKW.js +0 -1
- package/dist/chunk-HP2BUPGS.js +0 -24
- package/dist/chunk-LQRYQE6Q.js +0 -4
- package/dist/chunk-M6AJDVCL.js +0 -5
- package/dist/chunk-ML36XQW7.js +0 -1
- package/dist/chunk-NVOTOQBA.js +0 -1
- package/dist/chunk-RTEATXTP.js +0 -1
- package/dist/chunk-RVO4HV3M.js +0 -1
- package/dist/chunk-WJ3H73G6.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as s}from"../../chunk-
|
|
1
|
+
import{a as s}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as e}from"../../chunk-ZLLER3HP.js";import{Flags as i}from"@oclif/core";import{setTimeout as p}from"node:timers/promises";var o=class a extends s{static{e(this,"ProxyRestart")}static description="Restart the context capture proxy (stop + start)";static examples=["<%= config.bin %> proxy restart"];static flags={port:i.integer({char:"p",description:"Proxy listen port"}),docker:i.boolean({char:"d",default:!1,description:"Run in Docker mode"})};async run(){let{flags:t}=await this.parse(a);await this.config.runCommand("proxy:stop",[]),await p(500);let r=["--skip-checks"];t.docker&&r.push("--docker"),t.port&&r.push("--port",String(t.port)),await this.config.runCommand("proxy:start",r)}};export{o as default};
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import{a as g}from"../../chunk-67QCYUJU.js";import{a as
|
|
2
|
-
`);let
|
|
1
|
+
import{a as g}from"../../chunk-67QCYUJU.js";import{a as S}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import{g as x}from"../../chunk-O6C2UGBY.js";import{a as h}from"../../chunk-ZLLER3HP.js";import{Flags as _}from"@oclif/core";import{execSync as P,spawnSync as m}from"node:child_process";import{existsSync as f,readFileSync as y,appendFileSync as T,writeFileSync as k,mkdirSync as v}from"node:fs";import{homedir as d}from"node:os";import{dirname as E,join as u}from"node:path";var c=u(d(),".mitmproxy","mitmproxy-ca-cert.pem"),$=u(d(),".config","rulemetric"),A=8787,R=class C extends S{static{h(this,"ProxySetup")}static description="Set up context capture proxy (installs mitmproxy, configures shell)";static examples=["<%= config.bin %> proxy setup","<%= config.bin %> proxy setup --shell zsh","<%= config.bin %> proxy setup --check"];static flags={shell:_.string({description:"Shell to configure (auto-detected if omitted)",options:["zsh","bash","fish","powershell"]}),port:_.integer({char:"p",default:A,description:"Proxy listen port"}),check:_.boolean({description:"Only check prerequisites, do not install anything",default:!1})};async run(){let{flags:e}=await this.parse(C),i=e.check,t=e.port;this.log("RuleMetric Proxy Setup"),this.log(`=====================
|
|
2
|
+
`);let l=[await this.checkAuth(),await this.checkMitmproxy(),await this.checkCACert(),await this.checkHooks(),this.checkShellEnv(t)],r=!0;for(let n of l){let p=n.ok?"[OK]":"[!!]";this.log(`${p} ${n.name}: ${n.message}`),n.ok||(r=!1)}if(r){this.log("\nAll checks passed. Run `rulemetric proxy start` to begin capturing.");return}if(i){this.log("\nSome checks failed. Run `rulemetric proxy setup` (without --check) to fix.");return}this.log(`
|
|
3
3
|
Fixing issues...
|
|
4
|
-
`);for(let n of
|
|
4
|
+
`);for(let n of l){if(n.ok||!n.fix)continue;this.log(`Fixing: ${n.name}...`),await n.fix()?this.log(` Fixed.
|
|
5
5
|
`):this.log(` Could not auto-fix. See instructions above.
|
|
6
6
|
`)}this.log(`---
|
|
7
7
|
Verifying...
|
|
8
|
-
`);let
|
|
9
|
-
Setup complete! Next steps:`),this.log(" 1. Restart your shell (or run `source ~/.zshrc`)"),this.log(" 2. Run `rulemetric proxy start`"),this.log(" 3. Start Claude Code \u2014 context will be captured automatically")):this.log("\nSome issues remain. Fix manually and re-run `rulemetric proxy setup --check`.")}async checkAuth(){if(
|
|
10
|
-
`):
|
|
11
|
-
`):["",r,"_rulemetric_proxy_check() {",` if [ -f "${
|
|
12
|
-
`);if(E(
|
|
13
|
-
`),
|
|
14
|
-
`),
|
|
15
|
-
`)
|
|
8
|
+
`);let o=[await this.checkAuth(),await this.checkMitmproxy(),await this.checkCACert(),await this.checkHooks(),this.checkShellEnv(t)],a=!0;for(let n of o){let p=n.ok?"[OK]":"[!!]";this.log(`${p} ${n.name}: ${n.message}`),n.ok||(a=!1)}a?(this.log(`
|
|
9
|
+
Setup complete! Next steps:`),this.log(" 1. Restart your shell (or run `source ~/.zshrc`)"),this.log(" 2. Run `rulemetric proxy start`"),this.log(" 3. Start Claude Code \u2014 context will be captured automatically")):this.log("\nSome issues remain. Fix manually and re-run `rulemetric proxy setup --check`.")}async checkAuth(){if(x())return{name:"Authentication",ok:!0,message:"Logged in (JWT)"};let e=process.env.RULEMETRIC_API_KEY;if(e)return{name:"Authentication",ok:!0,message:`API key (RULEMETRIC_API_KEY=${e.slice(0,8)}...)`};let i=u(d(),".config","rulemetric","env");if(f(i)){let t=y(i,"utf-8");if(t.includes("RULEMETRIC_API_KEY")||t.includes("RULEMETRIC_ACCESS_TOKEN"))return{name:"Authentication",ok:!0,message:"Configured via ~/.config/rulemetric/env"}}return{name:"Authentication",ok:!1,message:"Not authenticated",fix:h(async()=>(this.log(" Run `rulemetric auth login` to authenticate."),this.log(" Or set RULEMETRIC_API_KEY in ~/.config/rulemetric/env."),!1),"fix")}}async checkMitmproxy(){let e=this.findBinary("mitmdump");if(e)try{return{name:"mitmproxy",ok:!0,message:`Installed (v${P(`${e} --version 2>&1`,{encoding:"utf-8"}).match(/Mitmproxy:\s*([\d.]+)/)?.[1]??"unknown"})`}}catch{return{name:"mitmproxy",ok:!0,message:`Found at ${e}`}}return{name:"mitmproxy",ok:!1,message:"Not installed",fix:h(async()=>this.installMitmproxy(),"fix")}}async installMitmproxy(){if(this.findBinary("pipx")&&(this.log(" Installing via pipx..."),m("pipx",["install","mitmproxy"],{stdio:"inherit"}).status===0)||this.findBinary("uv")&&(this.log(" Installing via uv..."),m("uv",["tool","install","mitmproxy"],{stdio:"inherit"}).status===0))return!0;if(this.findBinary("pip3")||this.findBinary("pip")){let e=this.findBinary("pip3")||this.findBinary("pip");if(this.log(` Installing via ${e} --user...`),m(e,["install","--user","mitmproxy"],{stdio:"inherit"}).status===0)return!0}return this.findBinary("brew")&&(this.log(" Installing via brew..."),m("brew",["install","mitmproxy"],{stdio:"inherit"}).status===0)?!0:(this.log(" Could not auto-install mitmproxy. Install manually:"),this.log(" pipx install mitmproxy # recommended"),this.log(" brew install mitmproxy # macOS"),this.log(" pip install --user mitmproxy"),!1)}async checkCACert(){return f(c)?{name:"CA Certificate",ok:!0,message:`Found at ${c}`}:{name:"CA Certificate",ok:!1,message:"Not generated yet",fix:h(async()=>this.generateCACert(),"fix")}}async generateCACert(){let e=this.findBinary("mitmdump");if(!e)return this.log(" Cannot generate cert \u2014 mitmproxy not installed."),!1;this.log(" Generating CA certificate...");let i=m(e,["--set","listen_port=0","-q"],{timeout:5e3,stdio:"ignore"});return f(c)?(this.log(` Certificate generated at ${c}`),process.platform==="darwin"&&(this.log(" Adding CA cert to macOS keychain (may require sudo)..."),m("sudo",["security","add-trusted-cert","-d","-r","trustRoot","-k","/Library/Keychains/System.keychain",c],{stdio:"inherit"}).status===0?this.log(" CA cert trusted system-wide."):this.log(" Could not auto-trust cert. You may need NODE_EXTRA_CA_CERTS env var.")),!0):(this.log(" Failed to generate cert. Try running: mitmdump --help"),!1)}async checkHooks(){let e=!1;for(let i of["settings.local.json","settings.json"]){let t=u(process.cwd(),".claude",i);if(f(t)){e=!0;try{let l=JSON.parse(y(t,"utf-8"));if(l.hooks&&Object.keys(l.hooks).length>0)return{name:"Session Hooks",ok:!0,message:"Installed in current project"}}catch{}}}return e?{name:"Session Hooks",ok:!1,message:"settings file exists but hooks not configured",fix:h(async()=>(this.log(" Run `rulemetric hooks install` to configure hooks."),!1),"fix")}:{name:"Session Hooks",ok:!1,message:"Not installed in current project",fix:h(async()=>(this.log(" Run `rulemetric hooks install` in your project directory."),!1),"fix")}}checkShellEnv(e){let i=process.env.HTTPS_PROXY?.includes(String(e)),t=!!process.env.NODE_EXTRA_CA_CERTS;if(i&&t)return{name:"Shell Environment",ok:!0,message:"HTTPS_PROXY and NODE_EXTRA_CA_CERTS set"};let l=this.detectShell(),r=this.getShellRcFile(l);if(r&&f(r))try{let a=y(r,"utf-8");if(a.includes(this.shellEnvSentinel(l))&&!a.includes("proxy.env"))return{name:"Shell Environment",ok:!0,message:`Auto-detect hook installed in ${r} (sets HTTPS_PROXY while the proxy runs)`}}catch{}let o=[];return i||o.push("HTTPS_PROXY"),t||o.push("NODE_EXTRA_CA_CERTS"),{name:"Shell Environment",ok:!1,message:`Missing: ${o.join(", ")}`,fix:h(async()=>this.writeShellEnv(e),"fix")}}async writeShellEnv(e){let i=this.detectShell(),t=this.getShellRcFile(i);if(!t)return this.log(" Could not detect shell RC file. Add these to your shell profile:"),this.log(` export HTTPS_PROXY=http://localhost:${e}`),this.log(` export NODE_EXTRA_CA_CERTS=${c}`),!1;let l="# RuleMetric proxy",r="# RuleMetric proxy (auto-detect)",o=u($,"proxy.pid"),a=`http://localhost:${e}`,n=this.shellEnvSentinel(i),p=i==="powershell"?this.buildPowerShellBlock(r,o,e):i==="fish"?["",r,"function _rulemetric_proxy_check --on-event fish_prompt",` if test -f "${o}"; and kill -0 (cat "${o}") 2>/dev/null`,` set -gx HTTPS_PROXY ${a}`,` set -gx NODE_EXTRA_CA_CERTS "${c}"`," else"," set -e HTTPS_PROXY 2>/dev/null"," set -e NODE_EXTRA_CA_CERTS 2>/dev/null"," end","end",""].join(`
|
|
10
|
+
`):i==="zsh"?["",r,"_rulemetric_proxy_check() {",` if [ -f "${o}" ] && kill -0 "$(cat "${o}" 2>/dev/null)" 2>/dev/null; then`,' if [ -z "${HTTPS_PROXY:-}" ]; then',` export HTTPS_PROXY="${a}"`,` export NODE_EXTRA_CA_CERTS="${c}"`," fi"," else",' [ -n "${HTTPS_PROXY:-}" ] && unset HTTPS_PROXY NODE_EXTRA_CA_CERTS'," fi","}","precmd_functions+=(_rulemetric_proxy_check)",""].join(`
|
|
11
|
+
`):["",r,"_rulemetric_proxy_check() {",` if [ -f "${o}" ] && kill -0 "$(cat "${o}" 2>/dev/null)" 2>/dev/null; then`,' if [ -z "${HTTPS_PROXY:-}" ]; then',` export HTTPS_PROXY="${a}"`,` export NODE_EXTRA_CA_CERTS="${c}"`," fi"," else",' [ -n "${HTTPS_PROXY:-}" ] && unset HTTPS_PROXY NODE_EXTRA_CA_CERTS'," fi","}",'PROMPT_COMMAND="_rulemetric_proxy_check${PROMPT_COMMAND:+;$PROMPT_COMMAND}"',""].join(`
|
|
12
|
+
`);if(v(E(t),{recursive:!0}),f(t)){let s=y(t,"utf-8");if(s.includes(l)&&!s.includes(r)&&(s=s.replace(/\n# RuleMetric proxy\nexport HTTPS_PROXY=[^\n]*\nexport NODE_EXTRA_CA_CERTS=[^\n]*\n/,`
|
|
13
|
+
`),k(t,s),this.log(` Removed old static env vars from ${t}`)),s.includes("# RuleMetric proxy (auto-detect")&&!s.includes("_rulemetric_proxy_check")&&(s=s.replace(/\n# RuleMetric proxy \(auto-detect[^\n]*\)\nif \[.*?\nfi\n/s,`
|
|
14
|
+
`),k(t,s),this.log(` Upgraded old auto-detect block in ${t}`)),s.includes(n)&&s.includes("proxy.env")&&(s=s.replace(/\n# RuleMetric proxy \(auto-detect\)\n_rulemetric_proxy_check\(\) \{[\s\S]*?\n\}\n[^\n]*_rulemetric_proxy_check[^\n]*\n/,`
|
|
15
|
+
`).replace(/\n# RuleMetric proxy \(auto-detect\)\nfunction _rulemetric_proxy_check\n[\s\S]*?\nend\n/,`
|
|
16
|
+
`),k(t,s),this.log(` Removed broken proxy.env block from ${t}`)),s.includes(n))return this.log(` Shell env already configured in ${t}`),!0}return this.log(` Appending proxy auto-detect hook to ${t}`),this.log(" (HTTPS_PROXY is set/unset automatically when proxy starts/stops)"),T(t,p),!0}shellEnvSentinel(e){return e==="powershell"?"_RuleMetricProxyCheck":"_rulemetric_proxy_check"}detectShell(){if(process.platform==="win32")return"powershell";let e=process.env.SHELL||"";return e.includes("zsh")?"zsh":e.includes("bash")?"bash":e.includes("fish")?"fish":"zsh"}getShellRcFile(e){let i=d();switch(e){case"zsh":return u(i,".zshrc");case"bash":return u(i,".bashrc");case"fish":return u(i,".config","fish","config.fish");case"powershell":return this.getPowerShellProfilePath();default:return null}}getPowerShellProfilePath(){let e=g("pwsh")||g("powershell");if(e)try{let i=P(`"${e}" -NoProfile -Command "$PROFILE.CurrentUserAllHosts"`,{encoding:"utf-8"}).trim();if(i)return i}catch{}return u(d(),"Documents","PowerShell","profile.ps1")}buildPowerShellBlock(e,i,t){let l=`http://localhost:${t}`,r=i.replace(/'/g,"''"),o=c.replace(/'/g,"''");return["",e,"function _RuleMetricProxyCheck {",` $pidFile = '${r}'`," $alive = $false"," if (Test-Path $pidFile) {"," $procId = (Get-Content $pidFile -ErrorAction SilentlyContinue | Select-Object -First 1)"," if ($procId -match '^\\d+$' -and (Get-Process -Id ([int]$procId) -ErrorAction SilentlyContinue)) {"," $alive = $true"," }"," }"," if ($alive) {",` $env:HTTPS_PROXY = '${l}'`,` $env:HTTP_PROXY = '${l}'`,` $env:NODE_EXTRA_CA_CERTS = '${o}'`," } else {"," Remove-Item Env:HTTPS_PROXY, Env:HTTP_PROXY, Env:NODE_EXTRA_CA_CERTS -ErrorAction SilentlyContinue"," }","}","# Wrap the existing prompt once so the check runs every prompt.","if (-not (Test-Path Function:\\_RuleMetricOriginalPrompt)) {"," $existing = Get-Command prompt -ErrorAction SilentlyContinue"," if ($existing) { Set-Item Function:\\_RuleMetricOriginalPrompt $existing.ScriptBlock }","}","function prompt {"," _RuleMetricProxyCheck",' if (Test-Path Function:\\_RuleMetricOriginalPrompt) { & _RuleMetricOriginalPrompt } else { "PS $($PWD.Path)> " }',"}",""].join(`
|
|
17
|
+
`)}findBinary(e){return g(e)}};export{R as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as K}from"../../chunk-OMXUK4M6.js";import{a as U}from"../../chunk-67QCYUJU.js";import{b as F,d as N}from"../../chunk-SZ62CP55.js";import{a as M}from"../../chunk-
|
|
1
|
+
import{a as K}from"../../chunk-OMXUK4M6.js";import{a as U}from"../../chunk-67QCYUJU.js";import{b as F,d as N}from"../../chunk-SZ62CP55.js";import{a as M}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import{g as $}from"../../chunk-O6C2UGBY.js";import{a as u}from"../../chunk-ZLLER3HP.js";import{Flags as _}from"@oclif/core";import{execSync as H,spawn as q,spawnSync as m}from"node:child_process";import{appendFileSync as G,existsSync as l,mkdirSync as P,openSync as V,readFileSync as b,writeFileSync as Y}from"node:fs";import{createRequire as W}from"node:module";import{homedir as x}from"node:os";import{dirname as A,join as c,resolve as f}from"node:path";import{fileURLToPath as X}from"node:url";var g=A(X(import.meta.url)),J=8788,S=c(x(),".config","rulemetric"),T=c(S,"proxy.pid"),D=c(S,"proxy.log"),w="rulemetric/proxy",v="rulemetric-proxy";function j(s,o){try{let d=W(import.meta.url).resolve(`@rulemetric/proxy/${s}`);if(l(d))return d}catch{}for(let t of o)if(l(t))return t;return null}u(j,"resolveProxyFile");function B(){let s=[f(g,"../../../../../packages/proxy/addon/rulemetric_addon.py"),f(g,"../../../node_modules/@rulemetric/proxy/addon/rulemetric_addon.py"),f(g,"../../../../../node_modules/@rulemetric/proxy/addon/rulemetric_addon.py")],o=j("addon/rulemetric_addon.py",s);if(o)return o;throw new Error(`Could not find rulemetric_addon.py. Is @rulemetric/proxy installed?
|
|
2
2
|
Searched (after module resolution):
|
|
3
3
|
`+s.map(t=>` ${t}`).join(`
|
|
4
4
|
`))}u(B,"findAddonPath");function z(){let s=[f(g,"../../../../../packages/proxy/Dockerfile"),f(g,"../../../node_modules/@rulemetric/proxy/Dockerfile"),f(g,"../../../../../node_modules/@rulemetric/proxy/Dockerfile")],o=j("Dockerfile",s);if(o)return A(o);throw new Error("Could not find proxy Dockerfile. Is @rulemetric/proxy installed?")}u(z,"findDockerfilePath");function Q(){return m("docker",["image","inspect",w],{stdio:"ignore"}).status===0}u(Q,"dockerImageExists");function Z(){let s=m("docker",["container","inspect","-f","{{.State.Running}}",v],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]});return s.status===0&&s.stdout?.trim()==="true"}u(Z,"dockerContainerRunning");var L=class s extends M{static{u(this,"ProxyStart")}static description="Start context capture proxy";static examples=["<%= config.bin %> proxy start","<%= config.bin %> proxy start --docker","<%= config.bin %> proxy start --port 9090","<%= config.bin %> proxy start --web"];static flags={port:_.integer({char:"p",default:J,description:"Proxy listen port"}),docker:_.boolean({char:"d",default:!1,description:"Run proxy in Docker (no local mitmproxy needed)"}),web:_.boolean({default:!1,description:"Launch mitmweb debug UI instead of mitmdump (local mode only)"}),"skip-checks":_.boolean({default:!1,description:"Skip prerequisite checks"}),build:_.boolean({default:!1,description:"Force rebuild Docker image"})};async run(){let{flags:o}=await this.parse(s),t=o.port;o.docker?await this.startDocker(t,o.build):await this.startLocal(t,o.web,o["skip-checks"])}async startDocker(o,t){try{H("docker info",{stdio:"ignore"})}catch{this.error("Docker is not running. Start Docker Desktop and try again.")}Z()&&this.error("Proxy container already running. Stop it first: rulemetric proxy stop");let d=this.findComposeFile(),k=c(x(),".mitmproxy");P(k,{recursive:!0});let E=process.env.TMPDIR||"/tmp";P(c(E,"rulemetric"),{recursive:!0});let y={PROXY_PORT:String(o),RULEMETRIC_PROJECT_PATH:process.cwd()};if(!process.env.RULEMETRIC_API_KEY&&!process.env.RULEMETRIC_ACCESS_TOKEN){let n=c(x(),".config","rulemetric","env");if(l(n))for(let h of b(n,"utf-8").split(`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as m,d as o,i as l,j as d}from"../../chunk-MVM6OGAF.js";import"../../chunk-KKDHD4XA.js";import{b as p,c as u,d as g}from"../../chunk-SZ62CP55.js";import{a as c}from"../../chunk-
|
|
1
|
+
import{c as m,d as o,i as l,j as d}from"../../chunk-MVM6OGAF.js";import"../../chunk-KKDHD4XA.js";import{b as p,c as u,d as g}from"../../chunk-SZ62CP55.js";import{a as c}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a}from"../../chunk-ZLLER3HP.js";import{spawnSync as x}from"node:child_process";import{existsSync as M,readFileSync as P}from"node:fs";import{homedir as I}from"node:os";import{join as y}from"node:path";var D=y(I(),".config","rulemetric"),f=y(D,"proxy.pid"),e=class h extends c{static{a(this,"ProxyStatus")}static description="Check gateway and context capture proxy status";static examples=["<%= config.bin %> proxy status"];async run(){if(await this.parse(h),l()){let n=d();this.log(`Gateway: running (PID ${n}) on :${m}`)}else this.log("Gateway: not running");if(!M(f)){this.log("Mitmproxy: not running \u2014 routing direct (no capture)");return}let i=P(f,"utf-8").trim();if(i.startsWith("docker:")){let n=i.slice(7),r=x("docker",["container","inspect","-f","{{.State.Status}}",n],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}),s=r.stdout?.trim();r.status===0&&s==="running"?this.log(`Mitmproxy: running in Docker (container: ${n}) on :${o} \u2014 capturing context`):this.log(`Mitmproxy: container ${s||"not running"} (stale)`);return}let t=Number.parseInt(i,10);if(Number.isNaN(t)){this.log("Mitmproxy: not running (invalid PID file)");return}g(t,p)?this.log(`Mitmproxy: running (PID ${t}) on :${o} \u2014 capturing context`):u(t)?this.log(`Mitmproxy: not running (PID ${t} was reused by another process \u2014 stale PID file)`):this.log("Mitmproxy: not running (stale PID file)")}};export{e as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{b as m,d as a}from"../../chunk-SZ62CP55.js";import{a as d}from"../../chunk-
|
|
1
|
+
import{b as m,d as a}from"../../chunk-SZ62CP55.js";import{a as d}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as l}from"../../chunk-ZLLER3HP.js";import{spawnSync as s}from"node:child_process";import{existsSync as f,readFileSync as y,unlinkSync as n}from"node:fs";import{homedir as h}from"node:os";import{dirname as g,join as p,resolve as x}from"node:path";import{fileURLToPath as I}from"node:url";var P=g(I(import.meta.url)),k=p(h(),".config","rulemetric"),t=p(k,"proxy.pid"),c=class u extends d{static{l(this,"ProxyStop")}static description="Stop the context capture proxy";static examples=["<%= config.bin %> proxy stop"];async run(){if(await this.parse(u),!f(t)){this.log("No proxy process found (no PID file).");return}let e=y(t,"utf-8").trim();if(e.startsWith("docker:")){let r=e.slice(7),i=this.findComposeFile();i?(s("docker",["compose","-f",i,"stop","proxy"],{stdio:"inherit"}),s("docker",["compose","-f",i,"rm","-f","proxy"],{stdio:"ignore"})):(s("docker",["stop",r],{stdio:"ignore"}),s("docker",["rm",r],{stdio:"ignore"})),this.log("Proxy container stopped.");try{n(t)}catch{}return}let o=Number.parseInt(e,10);if(Number.isNaN(o)){n(t),this.log("Invalid PID file removed.");return}if(a(o,m))try{process.kill(o,"SIGTERM"),this.log(`Proxy stopped (PID ${o}).`)}catch(r){r.code==="ESRCH"?this.log("Proxy process not running (stale PID file removed)."):this.error(`Failed to stop proxy: ${r.message}`)}else this.log("Proxy process not running (stale PID file removed).");try{n(t)}catch{}this.log(""),this.log("Gateway is still running \u2014 Claude Code will route direct until proxy restarts.")}findComposeFile(){let e=[p(process.cwd(),"docker-compose.yml"),x(P,"../../../../../docker-compose.yml")];for(let o of e)if(f(o))return o;return null}};export{c as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{b as n}from"../../chunk-XXDZJ6YI.js";import{e as a}from"../../chunk-NVKX36YN.js";import{a as s}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as o}from"../../chunk-ZLLER3HP.js";import{Flags as d}from"@oclif/core";import l from"node:path";import u from"node:os";var i=class c extends s{static{o(this,"ResearchBackfill")}static description="Scan every ~/.claude/projects transcript for past rate-limit (429) events and POST them as observations. Opt-in seed for the usage-research dataset \u2014 forward-only tail is the default capture path.";static examples=["<%= config.bin %> research backfill","<%= config.bin %> research backfill --claude-dir /custom/.claude --dry-run"];static flags={"claude-dir":d.string({description:"Override the Claude Code projects directory",default:l.join(u.homedir(),".claude")}),"dry-run":d.boolean({description:"Print observation count without POSTing",default:!1})};async run(){let{flags:r}=await this.parse(c);this.requireAuth(),this.log(`Scanning ${l.join(r["claude-dir"],"projects")} for rate-limit events...`);let e=await a(r["claude-dir"]);if(this.log(`Found ${e.length} rate-limit observation(s).`),e.length===0)return;if(r["dry-run"]){this.log("Dry run \u2014 nothing posted.");return}let t=await n(e);if(this.log(`Posted ${t.posted} observation(s); ${t.failed} failed.`),t.failed>0)for(let f of t.errors)this.warn(f)}};export{i as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{d,g as c,h as p}from"../../chunk-NVKX36YN.js";import{
|
|
1
|
+
import{b as l}from"../../chunk-XXDZJ6YI.js";import{d,g as c,h as p}from"../../chunk-NVKX36YN.js";import{a as f}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as n}from"../../chunk-ZLLER3HP.js";import{Args as v,Flags as g}from"@oclif/core";import w from"node:path";var r=class h extends f{static{n(this,"ResearchTailTranscript")}static description="Read new lines from a Claude Code transcript since the last cached offset, POST any 429 events, and persist the new offset. Invoked by the session-end hook \u2014 safe to re-run.";static hidden=!0;static args={transcript:v.string({description:"Absolute path to a Claude Code .jsonl transcript",required:!0})};static flags={"no-post":g.boolean({description:"Parse and advance the offset without POSTing (debug)",default:!1})};async run(){let{args:u,flags:m}=await this.parse(h),e=w.resolve(u.transcript);try{this.requireAuth()}catch{return}let s=await c(),o=s[e]??0,{observations:a,newOffset:i}=await d(e,o);if(a.length>0&&!m["no-post"])try{let t=await l(a);process.env.RULEMETRIC_DEBUG&&this.log(`tail-transcript: posted ${t.posted}, failed ${t.failed}`)}catch(t){process.env.RULEMETRIC_DEBUG&&this.warn(`tail-transcript POST error: ${String(t)}`)}i!==o&&(s[e]=i,await p(s))}};export{r as default};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{a as
|
|
2
|
-
Or skip the capture proxy with --no-proxy.`)),e)this.log("[..] Skipping pre-install build (--skip-build)");else{this.log("[..] Building workspace artifacts (api, web, cli) via turbo...");let A=x(d,["exec","turbo","run","build",...["--filter","@rulemetric/api...","--filter","@rulemetric/web...","--filter","@rulemetric/cli"]],{cwd:i,stdio:"inherit"});A.status!==0&&this.error(`Workspace build failed (exit ${A.status}). Fix the build first, or use --skip-build if dist/ already exists.`),this.log("[OK] Build complete")}let f=o(i,"apps","api","dist","index.js");g(f)||this.error(`API entry not found at ${f}. Re-run without --skip-build, or: pnpm --filter @rulemetric/api... build`);let k=o(i,"apps","web","dist","index.html");if(g(k)||this.warn(`Web bundle not found at ${k}. Dashboard at :${t} will 404 until you build apps/web.`),!s){let P=o(i,"apps","cli","dist","lib","gateway-entry.js");g(P)||this.error(`Gateway entry not found at ${P}. Re-run without --skip-build, or: pnpm --filter @rulemetric/cli build`)}r.force&&this.killStaleProcess(t,null,"API on :"+t),s||(this.killStaleProcess(et,o(w,"gateway.pid"),"gateway"),this.killStaleProcess(V,o(w,"proxy.pid"),"mitmproxy")),T(o(y(),"Library","LaunchAgents"),{recursive:!0}),T(p,{recursive:!0});let m=
|
|
1
|
+
import{a as j}from"../../chunk-6XEC6474.js";import"../../chunk-N7ODX6PO.js";import{a as W}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import{c as M}from"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import{b as D}from"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as $}from"../../chunk-ZLLER3HP.js";import{Flags as v}from"@oclif/core";import{existsSync as g,mkdirSync as T,readFileSync as R,writeFileSync as B}from"node:fs";import{execSync as N,execFileSync as h,spawnSync as x}from"node:child_process";import{homedir as y,userInfo as Z}from"node:os";import{dirname as E,join as o}from"node:path";var K=new Set(["SUPABASE_URL","SUPABASE_ANON_KEY","SUPABASE_SERVICE_ROLE_KEY","SUPABASE_JWT_SECRET","DATABASE_URL","RULEMETRIC_API_URL","RULEMETRIC_API_KEY","RULEMETRIC_ACCESS_TOKEN","RULEMETRIC_USER_ID","GITHUB_TOKEN","PG_POOL_MAX","PG_IDLE_TIMEOUT","PG_STATEMENT_TIMEOUT_MS","PG_HEAVY_POOL_MAX","PG_QUERY_DEADLINE_MS","RESEND_API_KEY","RESEND_FROM_EMAIL","WEB_URL","RULEMETRIC_WEB_URL","SENTRY_DSN"]),H="com.rulemetric.api",I=o(y(),"Library","LaunchAgents",`${H}.plist`),X="com.rulemetric.worker",b=o(y(),"Library","LaunchAgents",`${X}.plist`),F="com.rulemetric.gateway",G=o(y(),"Library","LaunchAgents",`${F}.plist`),J="com.rulemetric.proxy",Y=o(y(),"Library","LaunchAgents",`${J}.plist`),tt="com.rulemetric.worker.restart",U=o(y(),"Library","LaunchAgents",`${tt}.plist`),w=o(y(),".config","rulemetric"),p=o(w,"logs"),et=8787,V=8788,q=o(y(),".config","systemd","user"),_="rulemetric-worker.service",S=o(q,_),C=class L extends W{static{$(this,"ServiceInstall")}static description="Install RuleMetric services. Default (in a repo checkout): API + worker + gateway + capture proxy as launchd agents. With --worker-only: just the job worker, targeting the globally-installed CLI \u2014 no repo, no build (works from `npm i -g @rulemetric/cli`, macOS launchd or Linux systemd).";static examples=["<%= config.bin %> service install","<%= config.bin %> service install --port 3000","<%= config.bin %> service install --skip-build","<%= config.bin %> service install --no-proxy","<%= config.bin %> service install --worker-only"];static flags={port:v.integer({char:"p",default:3e3,description:"API server port"}),force:v.boolean({char:"f",default:!1,description:"Overwrite existing service configuration and reclaim conflicting ports"}),"skip-build":v.boolean({default:!1,description:"Skip the pre-install workspace build (API/web/cli dist must already exist)"}),"no-proxy":v.boolean({default:!1,description:"Skip gateway + mitmproxy plists (just install API + worker)"}),"worker-only":v.boolean({default:!1,description:"Install ONLY the job worker as a persistent service, targeting the globally-installed CLI (no repo checkout, no build, no API/gateway/proxy). Sources auth from ~/.config/rulemetric/env. macOS (launchd) + Linux (systemd --user)."})};async run(){let{flags:r}=await this.parse(L),t=r.port,e=r["skip-build"],s=r["no-proxy"];if(r["worker-only"]){await this.runWorkerOnly(r.force);return}if(process.platform!=="darwin"&&this.error("The full service install is macOS-only (launchd). For just the job worker on Linux (or a clean npm install), use: rulemetric service install --worker-only"),g(I)&&!r.force){this.log(`Service already installed at ${I}`),this.log("Use --force to overwrite, or run: rulemetric service status");return}try{if((await fetch(`http://localhost:${t}/health`)).ok&&!r.force){this.warn(`Port ${t} is already in use (API may be running via start.sh or in another terminal).`),this.warn("Stop it first with scripts/stop.sh, or use --force to take over the port.");return}}catch{}let i=this.findProjectRoot();i||this.error("Could not find RuleMetric project root. Run this command from within the momento-mori repo, or set RULEMETRIC_PROJECT_ROOT.");let n=o(i,".env.local");g(n)||this.error(`.env.local not found at ${n}. The API needs Supabase credentials to start.`);let a=this.guardAlwaysOnDatabaseUrl(this.loadEnvVars(i)),c=this.findBinary("node"),d=this.findBinary("pnpm");(!c||!d)&&this.error("Could not find node or pnpm. Ensure they are in your PATH.");let u=null;if(s||(u=this.findBinary("mitmdump"),u||this.error(`mitmdump not found in PATH. Install with: pipx install mitmproxy (or brew install mitmproxy), then re-run.
|
|
2
|
+
Or skip the capture proxy with --no-proxy.`)),e)this.log("[..] Skipping pre-install build (--skip-build)");else{this.log("[..] Building workspace artifacts (api, web, cli) via turbo...");let A=x(d,["exec","turbo","run","build",...["--filter","@rulemetric/api...","--filter","@rulemetric/web...","--filter","@rulemetric/cli"]],{cwd:i,stdio:"inherit"});A.status!==0&&this.error(`Workspace build failed (exit ${A.status}). Fix the build first, or use --skip-build if dist/ already exists.`),this.log("[OK] Build complete")}let f=o(i,"apps","api","dist","index.js");g(f)||this.error(`API entry not found at ${f}. Re-run without --skip-build, or: pnpm --filter @rulemetric/api... build`);let k=o(i,"apps","web","dist","index.html");if(g(k)||this.warn(`Web bundle not found at ${k}. Dashboard at :${t} will 404 until you build apps/web.`),!s){let P=o(i,"apps","cli","dist","lib","gateway-entry.js");g(P)||this.error(`Gateway entry not found at ${P}. Re-run without --skip-build, or: pnpm --filter @rulemetric/cli build`)}r.force&&this.killStaleProcess(t,null,"API on :"+t),s||(this.killStaleProcess(et,o(w,"gateway.pid"),"gateway"),this.killStaleProcess(V,o(w,"proxy.pid"),"mitmproxy")),T(o(y(),"Library","LaunchAgents"),{recursive:!0}),T(p,{recursive:!0});let m=N("id -u",{encoding:"utf-8"}).trim(),z=this.buildPlist({port:t,projectRoot:i,nodePath:c,pnpmPath:d,envVars:a});this.bootoutAndWrite(m,I,z,"API"),this.bootstrapPlist(m,I,"API"),this.log(`[..] Waiting for API on :${t}...`),await this.waitForApi(t,15)?(this.log(`[OK] RuleMetric API running on :${t}`),g(k)&&this.log(`[OK] Dashboard available at http://localhost:${t}`)):(this.warn("API did not respond within 15s. Check logs:"),this.log(` tail -f ${p}/api-stdout.log`),this.log(` tail -f ${p}/api-stderr.log`)),this.log(""),this.log("Installing worker service..."),this.killStaleAgents();let Q=this.buildWorkerPlist({cliBin:o(i,"apps","cli","bin","run.js"),cliDist:o(i,"apps","cli","dist"),workingDir:i,nodePath:c,pnpmPath:d,envVars:a});if(this.bootoutAndWrite(m,b,Q,"Worker"),this.bootstrapPlist(m,b,"Worker"),!s){this.log(""),this.log("Installing gateway + capture proxy services...");let P=this.buildGatewayPlist({projectRoot:i,nodePath:c});this.bootoutAndWrite(m,G,P,"Gateway"),this.bootstrapPlist(m,G,"Gateway");let A=this.buildProxyPlist({projectRoot:i,mitmdumpPath:u,envVars:a});this.bootoutAndWrite(m,Y,A,"Proxy"),this.bootstrapPlist(m,Y,"Proxy")}if(g(U)){try{h("launchctl",["bootout",`gui/${m}`,U],{encoding:"utf-8"})}catch{}try{h("rm",["-f",U]),this.log("[OK] Removed stale daily worker-restart agent (no longer needed on agent path)")}catch{}}this.log(""),s?this.log("Installed: API + worker. Gateway/proxy skipped (--no-proxy)."):this.log("Installed: API + worker + gateway + capture proxy."),this.log("All services start at login, restart on crash, and pick up rebuilds via WatchPaths."),this.log(""),this.log("NOTE: Env vars are baked in at install time. If you change"),this.log(".env.local or credentials, re-run: rulemetric service install --force"),this.log(""),this.log("Manage with:"),this.log(" rulemetric service status \u2014 check if running"),this.log(" rulemetric service uninstall \u2014 remove all services"),await D();let O=await j();this.log(""),O.available?this.log(`[OK] tmux found${O.version?` (v${O.version})`:""} \u2014 live send enabled`):this.log("[!!] tmux not found \u2014 live send will fall back to opening Terminal. Install with: brew install tmux")}async runWorkerOnly(r){let t=process.platform;t!=="darwin"&&t!=="linux"&&this.error(`--worker-only supports macOS (launchd) and Linux (systemd) only; detected '${t}'.`);let e=this.findBinary("node");e||this.error("Could not find `node` in PATH.");let s=o(this.config.root,"bin","run.js");g(s)||this.error(`Could not locate the installed CLI entry at ${s}. Reinstall the CLI (e.g. npm i -g @rulemetric/cli) and re-run.`);let i=o(this.config.root,"dist"),n=this.loadGlobalWorkerEnv();if(!n.RULEMETRIC_API_KEY&&!n.RULEMETRIC_ACCESS_TOKEN&&this.error("Not authenticated \u2014 no RULEMETRIC_API_KEY/RULEMETRIC_ACCESS_TOKEN in ~/.config/rulemetric/env.\nRun `rulemetric auth login` first, then re-run `rulemetric service install --worker-only`."),n.RULEMETRIC_API_URL||(n.RULEMETRIC_API_URL="https://rulemetric.com"),T(p,{recursive:!0}),this.killStaleAgents(),t==="darwin"){if(g(b)&&!r){this.log(`Worker already installed at ${b}.`),this.log("Use --force to overwrite, or run: rulemetric service status");return}T(o(y(),"Library","LaunchAgents"),{recursive:!0});let a=N("id -u",{encoding:"utf-8"}).trim(),c=this.buildWorkerPlist({cliBin:s,cliDist:i,workingDir:y(),nodePath:e,nodeEnv:"production",envVars:n});this.bootoutAndWrite(a,b,c,"Worker"),this.bootstrapPlist(a,b,"Worker"),this.log(""),this.log("[OK] Worker installed (launchd). Starts at login, restarts on crash."),this.log(` Logs: tail -f ${o(p,"worker-stdout.log")}`)}else{if(g(S)&&!r){this.log(`Worker already installed at ${S}.`),this.log(`Use --force to overwrite, or: systemctl --user status ${_}`);return}T(q,{recursive:!0});let a=this.buildWorkerSystemdUnit({cliBin:s,nodePath:e,envVars:n});B(S,a,{mode:384}),this.log(`[OK] Wrote ${S}`);try{h("systemctl",["--user","daemon-reload"]),h("systemctl",["--user","enable","--now",_]),this.log("[OK] Worker enabled + started (systemctl --user).");try{h("loginctl",["enable-linger",Z().username]),this.log("[OK] Enabled linger \u2014 worker survives logout/reboot.")}catch{this.log("[!!] Could not enable linger (worker will stop on logout)."),this.log(' Run: sudo loginctl enable-linger "$USER"')}this.log(` Logs: journalctl --user -u ${_} -f`)}catch(c){this.warn(`Wrote the unit but \`systemctl --user\` failed: ${c instanceof Error?c.message:String(c)}`),this.log(`Enable it manually: systemctl --user daemon-reload && systemctl --user enable --now ${_}`)}}this.log(""),this.log("Manage with:"),this.log(" rulemetric service status \u2014 check if running"),this.log(" rulemetric service uninstall \u2014 remove the worker"),await D(),M("worker_started",{mode:"worker-only"},this.config.version)}loadGlobalWorkerEnv(){let r={},t=o(w,"env");if(g(t))for(let e of R(t,"utf-8").split(`
|
|
3
3
|
`)){let s=e.trim();if(!s||s.startsWith("#"))continue;let i=s.indexOf("=");i>0&&(r[s.slice(0,i)]=s.slice(i+1))}return Object.fromEntries(Object.entries(r).filter(([e])=>K.has(e)))}buildWorkerSystemdUnit(r){let{cliBin:t,nodePath:e,envVars:s}=r,i={...s,NODE_ENV:"production",PATH:[...new Set([E(e),o(y(),".local","bin"),"/opt/homebrew/bin","/usr/local/bin","/usr/bin","/bin"])].join(":"),PG_POOL_MAX:s.PG_POOL_MAX??"3",PG_IDLE_TIMEOUT:s.PG_IDLE_TIMEOUT??"10"},n=Object.entries(i).map(([a,c])=>`Environment="${a}=${c.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`).join(`
|
|
4
4
|
`);return`[Unit]
|
|
5
5
|
Description=RuleMetric job worker (evals agent)
|
|
@@ -20,7 +20,7 @@ WantedBy=default.target
|
|
|
20
20
|
`)){let n=i.trim();if(!n||n.startsWith("#"))continue;let a=n.indexOf("=");a>0&&(t[n.slice(0,a)]=n.slice(a+1))}return Object.fromEntries(Object.entries(t).filter(([i])=>K.has(i)))}guardAlwaysOnDatabaseUrl(r){let t=r.DATABASE_URL;return t?t.includes("pooler.supabase.com:5432")?(this.warn("DATABASE_URL points at the SESSION-mode pooler (:5432, 15-slot cap). The always-on API/worker must use TRANSACTION mode (:6543) \u2014 auto-correcting for the installed services. Fix .env.local to silence this warning."),{...r,DATABASE_URL:t.replace("pooler.supabase.com:5432","pooler.supabase.com:6543")}):(/@db\.[a-z0-9]+\.supabase\.co[:/]/.test(t)&&this.warn("DATABASE_URL is a DIRECT database connection (db.<ref>.supabase.co), not the pooler. Always-on services should use the transaction pooler (aws-*.pooler.supabase.com:6543) to avoid exhausting Postgres connections."),r):r}killStaleAgents(){try{let t=h("pgrep",["-f","bin/run.js evals agent"],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim().split(`
|
|
21
21
|
`).filter(Boolean).map(e=>parseInt(e,10)).filter(e=>!isNaN(e)&&e!==process.pid);for(let e of t)try{process.kill(e,"SIGTERM"),this.log(`[OK] Reaped orphan evals agent (PID ${e})`)}catch{}t.length&&x("sleep",["1"],{stdio:"ignore"})}catch{}}killStaleProcess(r,t,e){let s=!1;if(t&&g(t)){try{let i=R(t,"utf-8").trim(),n=parseInt(i,10);if(!isNaN(n))try{process.kill(n,"SIGTERM"),s=!0,this.log(`[OK] Stopped existing ${e} (PID ${n} from ${t})`)}catch{}}catch{}try{h("rm",["-f",t])}catch{}}try{let n=h("lsof",["-ti",`:${r}`,"-sTCP:LISTEN"],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim().split(`
|
|
22
22
|
`).filter(Boolean);for(let a of n){let c=parseInt(a,10);if(!isNaN(c))try{process.kill(c,"SIGTERM"),s=!0,this.log(`[OK] Stopped orphan on :${r} (PID ${c})`)}catch{}}}catch{}s&&x("sleep",["1"],{stdio:"ignore"})}bootoutAndWrite(r,t,e,s){let i=["Could not find specified service","No such process","3: No such process","5: Input/output error"];try{h("launchctl",["bootout",`gui/${r}`,t],{encoding:"utf-8",stdio:["ignore","pipe","pipe"]}),this.log(`[OK] Unloaded existing ${s} service`)}catch(n){let a=n.message||"",c=(n.stderr??"").toString(),d=`${a}
|
|
23
|
-
${c}`;i.some(u=>d.includes(u))||this.warn(`Could not unload existing ${s} service: ${a.trim()}`)}
|
|
23
|
+
${c}`;i.some(u=>d.includes(u))||this.warn(`Could not unload existing ${s} service: ${a.trim()}`)}B(t,e,{mode:384}),this.log(`[OK] ${s} plist written to ${t}`)}bootstrapPlist(r,t,e){try{h("launchctl",["bootstrap",`gui/${r}`,t]),this.log(`[OK] ${e} service loaded into launchd`)}catch(s){try{h("launchctl",["load",t]),this.log(`[OK] ${e} service loaded into launchd (legacy)`)}catch(i){this.warn(`Could not load ${e} service.
|
|
24
24
|
bootstrap: ${s.message.trim()}
|
|
25
25
|
load: ${i.message.trim()}`)}}}buildPlist(r){let{port:t,projectRoot:e,nodePath:s,pnpmPath:i,envVars:n}=r,a=[...new Set([E(s),E(i),"/usr/local/bin","/usr/bin","/bin"])],c=Object.entries({...n,PORT:String(t),NODE_ENV:"production",PATH:a.join(":"),PG_POOL_MAX:n.PG_POOL_MAX??"10",PG_STATEMENT_TIMEOUT_MS:n.PG_STATEMENT_TIMEOUT_MS??"10000",PG_IDLE_TIMEOUT:n.PG_IDLE_TIMEOUT??"30",OTEL_SPAN_EXPORT:n.OTEL_SPAN_EXPORT??"none"}).map(([f,k])=>` <key>${l(f)}</key>
|
|
26
26
|
<string>${l(k)}</string>`).join(`
|
|
@@ -79,7 +79,7 @@ ${c}
|
|
|
79
79
|
<plist version="1.0">
|
|
80
80
|
<dict>
|
|
81
81
|
<key>Label</key>
|
|
82
|
-
<string>${
|
|
82
|
+
<string>${X}</string>
|
|
83
83
|
|
|
84
84
|
<key>ProgramArguments</key>
|
|
85
85
|
<array>
|
|
@@ -131,7 +131,7 @@ ${u}
|
|
|
131
131
|
<plist version="1.0">
|
|
132
132
|
<dict>
|
|
133
133
|
<key>Label</key>
|
|
134
|
-
<string>${
|
|
134
|
+
<string>${F}</string>
|
|
135
135
|
|
|
136
136
|
<key>ProgramArguments</key>
|
|
137
137
|
<array>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as b}from"../../chunk-6XEC6474.js";import"../../chunk-N7ODX6PO.js";import{a as
|
|
1
|
+
import{a as b}from"../../chunk-6XEC6474.js";import"../../chunk-N7ODX6PO.js";import{a as w}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as T}from"../../chunk-ZLLER3HP.js";import{existsSync as c,readFileSync as A}from"node:fs";import{execFileSync as x,execSync as M}from"node:child_process";import{homedir as l}from"node:os";import{join as a}from"node:path";var k="com.rulemetric.api",g=a(l(),"Library","LaunchAgents",`${k}.plist`),u="com.rulemetric.worker",o=a(l(),"Library","LaunchAgents",`${u}.plist`),v="com.rulemetric.gateway",E=a(l(),"Library","LaunchAgents",`${v}.plist`),L="com.rulemetric.proxy",R=a(l(),"Library","LaunchAgents",`${L}.plist`),_=a(l(),".config","rulemetric","logs"),y=8787,$=8788,p="rulemetric-worker.service",W=a(l(),".config","systemd","user",p),P=class extends w{static{T(this,"ServiceStatus")}static description="Check the status of installed RuleMetric services (launchd on macOS; systemd --user worker on Linux)";async run(){if(process.platform!=="darwin"){if(process.platform==="linux"){this.reportLinuxWorkerStatus();return}this.error(`Service status supports macOS (launchd) and Linux (systemd --user, worker-only installs) only; detected '${process.platform}'.`)}if(!c(g)){if(c(o)){this.reportWorkerOnlyStatus();return}this.log("Service: not installed"),this.log("Run: rulemetric service install (repo checkout) or rulemetric service install --worker-only");return}let t=this.readServiceState(k,g),e=this.readApiPort(g),r=await this.probeApiHealth(e),d=await this.probeDashboard(e),s=this.readServiceState(u,o),h=this.readWorkerMode(),i=this.readServiceState(v,E),S=this.isPortListening(y),n=this.readServiceState(L,R),m=this.isPortListening($),O=`${r} (port ${e})${d?" \u2014 dashboard served":""}`;this.log(`API: ${this.fmtState(t)} \u2014 ${O}`);let I=h==="listen"?" [mode: listen \u2014 DEPRECATED, run `rulemetric service install --force` to upgrade]":"";this.log(`Worker: ${this.fmtState(s)}${I}`),this.log(`Gateway: ${this.fmtState(i)} \u2014 ${S?`listening :${y}`:`NOT listening :${y}`}`),this.log(`Proxy: ${this.fmtState(n)} \u2014 ${m?`listening :${$}`:`NOT listening :${$}`}`);let f=await b();this.log(`Tmux: ${f.available?f.version?`v${f.version}`:"available":"not found"}`),this.log(""),this.log(`Plists: ${g}`),this.log(` ${o}`),i.installed&&this.log(` ${E}`),n.installed&&this.log(` ${R}`),this.log(`Logs: ${_}/{api,worker,gateway,proxy}-{stdout,stderr}.log`);let D=t.launchdStatus==="running"&&r==="healthy"&&s.launchdStatus==="running"&&(!i.installed||i.launchdStatus==="running"&&S)&&(!n.installed||n.launchdStatus==="running"&&m);this.log(""),D?this.log("All good \u2014 sessions tracked, jobs processed, capture pipeline live."):(t.launchdStatus!=="running"&&(this.log("API is not running. Try:"),this.log(` launchctl kickstart gui/$(id -u)/${k}`)),s.installed&&s.launchdStatus!=="running"&&(this.log("Worker is not running. Try:"),this.log(` launchctl kickstart gui/$(id -u)/${u}`)),i.installed&&(i.launchdStatus!=="running"||!S)&&(this.log("Gateway is not running. Try:"),this.log(` launchctl kickstart gui/$(id -u)/${v}`)),n.installed&&(n.launchdStatus!=="running"||!m)&&(this.log("Proxy is not running. Try:"),this.log(` launchctl kickstart gui/$(id -u)/${L}`)),(!i.installed||!n.installed)&&this.log("Gateway/proxy not installed. Run: rulemetric service install --force"))}reportWorkerOnlyStatus(){let t=this.readServiceState(u,o),r=this.readWorkerMode()==="listen"?" [mode: listen \u2014 DEPRECATED, run `rulemetric service install --worker-only --force` to upgrade]":"";this.log(`Worker: ${this.fmtState(t)}${r} (worker-only install)`),this.log(""),this.log(`Plist: ${o}`),this.log(`Logs: ${_}/worker-{stdout,stderr}.log`),this.log(""),t.launchdStatus==="running"?this.log("All good \u2014 jobs processed by the background worker."):(this.log("Worker is not running. Try:"),this.log(` launchctl kickstart gui/$(id -u)/${u}`))}reportLinuxWorkerStatus(){if(!c(W)){this.log("Service: not installed"),this.log("Run: rulemetric service install --worker-only");return}let t;try{t=x("systemctl",["--user","is-active",p],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()}catch(e){t=(e.stdout??"").toString().trim()||"not loaded"}this.log(`Worker: ${t} (systemd --user, worker-only install)`),this.log(""),this.log(`Unit: ${W}`),this.log(`Logs: journalctl --user -u ${p} -f`),this.log(""),t==="active"?this.log("All good \u2014 jobs processed by the background worker."):(this.log("Worker is not running. Try:"),this.log(` systemctl --user restart ${p}`))}readServiceState(t,e){if(!c(e))return{installed:!1,launchdStatus:"not installed",pid:null};try{let d=M(`launchctl list ${t} 2>/dev/null`,{encoding:"utf-8"}),s=d.match(/"PID"\s*=\s*(\d+)/),h=d.match(/"LastExitStatus"\s*=\s*(\d+)/);if(s)return{installed:!0,launchdStatus:"running",pid:s[1]};if(h){let i=h[1];return{installed:!0,launchdStatus:i==="0"?"stopped (clean exit)":`stopped (exit ${i})`,pid:null}}return{installed:!0,launchdStatus:"loaded",pid:null}}catch{return{installed:!0,launchdStatus:"not loaded",pid:null}}}fmtState(t){return t.installed?`${t.launchdStatus}${t.pid?` (PID ${t.pid})`:""}`:"not installed"}readApiPort(t){try{let r=A(t,"utf-8").match(/<key>PORT<\/key>\s*<string>(\d+)<\/string>/);if(r)return Number.parseInt(r[1])}catch{}return 3e3}readWorkerMode(){if(!c(o))return null;try{let e=A(o,"utf-8").match(/<string>evals<\/string>\s*<string>(listen|agent)<\/string>/);if(e)return e[1]}catch{}return null}async probeApiHealth(t){try{let e=await fetch(`http://localhost:${t}/health`);return e.ok?"healthy":`unhealthy (${e.status})`}catch{return"unreachable"}}async probeDashboard(t){try{let e=await fetch(`http://localhost:${t}/`);return e.ok?(e.headers.get("content-type")??"").includes("text/html"):!1}catch{return!1}}isPortListening(t){try{return x("lsof",["-ti",`:${t}`,"-sTCP:LISTEN"],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim().length>0}catch{return!1}}};export{P as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as u}from"../../chunk-
|
|
1
|
+
import{a as u}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as n}from"../../chunk-ZLLER3HP.js";import{existsSync as m,unlinkSync as d}from"node:fs";import{execSync as g,execFileSync as s}from"node:child_process";import{homedir as y}from"node:os";import{join as p}from"node:path";var v=[{label:"com.rulemetric.api",description:"API"},{label:"com.rulemetric.worker",description:"Worker"},{label:"com.rulemetric.gateway",description:"Gateway"},{label:"com.rulemetric.proxy",description:"Proxy"},{label:"com.rulemetric.worker.restart",description:"Worker restart agent"}];function h(a){return p(y(),"Library","LaunchAgents",`${a}.plist`)}n(h,"plistPathFor");var l="rulemetric-worker.service",i=p(y(),".config","systemd","user",l),c=class extends u{static{n(this,"ServiceUninstall")}static description="Remove RuleMetric services (macOS launchd: API/worker/gateway/proxy; Linux: the --worker-only systemd unit)";async run(){if(process.platform==="linux"){this.uninstallLinuxWorker();return}process.platform!=="darwin"&&this.error("Service uninstall supports macOS (launchd) and Linux (systemd) only.");let r=v.filter(t=>m(h(t.label)));if(r.length===0){this.log("No RuleMetric services are installed.");return}let o=g("id -u",{encoding:"utf-8"}).trim();for(let t of r){let e=h(t.label);this.stopService(o,e,t.label,t.description),this.removePlist(e,t.description)}this.log(""),this.log("All RuleMetric services removed. They will no longer start automatically."),this.log("Use scripts/start.sh (dev) or `rulemetric service install` (always-on) to bring them back.")}stopService(r,o,t,e){try{s("launchctl",["bootout",`gui/${r}`,o],{encoding:"utf-8"}),this.log(`[OK] ${e} stopped`);return}catch{}try{s("launchctl",["unload",o],{encoding:"utf-8"}),this.log(`[OK] ${e} stopped (legacy)`);return}catch{try{g(`launchctl list ${t} 2>&1`,{encoding:"utf-8"}).includes("PID")?(this.warn(`${e} appears to still be running. Try manually:`),this.warn(` launchctl bootout gui/${r} "${o}"`)):this.log(`[OK] ${e} was not running`)}catch{this.log(`[OK] ${e} was not running`)}}}removePlist(r,o){try{d(r),this.log(`[OK] Removed ${r}`)}catch(t){this.warn(`Could not remove ${o} plist: ${t.message}. Try: rm "${r}"`)}}uninstallLinuxWorker(){if(!m(i)){this.log("No RuleMetric worker is installed (no systemd unit found).");return}try{s("systemctl",["--user","disable","--now",l],{encoding:"utf-8"}),this.log("[OK] Worker stopped + disabled (systemctl --user)")}catch(r){this.warn(`Could not disable the worker unit: ${r.message}`),this.warn(` systemctl --user disable --now ${l}`)}try{d(i),this.log(`[OK] Removed ${i}`)}catch(r){this.warn(`Could not remove ${i}: ${r.message}. Try: rm "${i}"`)}try{s("systemctl",["--user","daemon-reload"],{encoding:"utf-8"})}catch{}this.log(""),this.log("RuleMetric worker removed. It will no longer start automatically.")}};export{c as default};
|
|
@@ -1,3 +1 @@
|
|
|
1
|
-
import{a
|
|
2
|
-
Adherence Score: ${s.adherenceScore}/100`),this.log(`Summary: ${s.summary}`),s.suggestions.length>0&&this.log(`
|
|
3
|
-
${s.suggestions.length} suggestion(s) for instruction improvement.`)}};export{i as default};
|
|
1
|
+
import{a}from"../../chunk-WLVQJH4E.js";import{a as o}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{f as r}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as t}from"../../chunk-ZLLER3HP.js";import{Args as l}from"@oclif/core";var s=class n extends o{static{t(this,"SessionsAnalyze")}static description="Trigger AI analysis on a session";static examples=["<%= config.bin %> sessions analyze <session-id>"];static args={id:l.string({description:"Session ID",required:!0})};async run(){let{args:i}=await this.parse(n);this.requireAuth(),a(i.id,"session ID");let e=await r(`/api/sessions/${i.id}/analyze`,{});this.log(`Analysis queued (job ${e.jobId}, status: ${e.status}).`),this.log("A running worker picks it up automatically \u2014 start one with `rulemetric evals agent`"),this.log("(or install it persistently: `rulemetric service install --worker-only`)."),this.log("Results appear on the session once processed \u2014 see the session detail page in the dashboard.")}};export{s as default};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as d}from"../../chunk-
|
|
2
|
-
`)[0].trim(),path:n,mtime:
|
|
1
|
+
import{a as d}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{f as m}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as l}from"../../chunk-ZLLER3HP.js";import{readdirSync as f,readFileSync as h,unlinkSync as p,statSync as S}from"node:fs";import{tmpdir as g}from"node:os";import{join as r}from"node:path";var v=[".log",".seq",".ctxhash",".pid",".lock"],c=class u extends d{static{l(this,"SessionsEnd")}static description="End the active capture session";static examples=["<%= config.bin %> sessions end"];async run(){await this.parse(u),this.requireAuth();let i=r(g(),"rulemetric"),s=this.findActiveSession(i);s||this.error("No active session found. Start one with: rulemetric sessions start --tool <name>");try{await m(`/api/sessions/${s.rwSessionId}/close`,{})}catch(e){this.error(`Could not end session ${s.rwSessionId} via API: ${e.message}. Local session files were left in place \u2014 fix the connection/auth issue and retry.`)}this.cleanupSessionFiles(i,s.externalId),this.log(`Session ended: ${s.rwSessionId}`)}findActiveSession(i){let s;try{s=f(i)}catch{return null}let e=[];for(let t of s){if(v.some(o=>t.endsWith(o)))continue;let n=r(i,t);try{let o=S(n);if(!o.isFile())continue;let a=h(n,"utf-8").trim();if(!a)continue;e.push({externalId:t,rwSessionId:a.split(`
|
|
2
|
+
`)[0].trim(),path:n,mtime:o.mtimeMs})}catch{continue}}return e.length===0?null:(e.sort((t,n)=>n.mtime-t.mtime),e[0])}cleanupSessionFiles(i,s){let e=r(i,s);for(let t of["",".seq",".ctxhash",".log"])try{p(e+t)}catch{}}};export{c as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as n}from"../../chunk-
|
|
1
|
+
import{a as n}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{f as r}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as i}from"../../chunk-ZLLER3HP.js";import*as o from"node:fs";import{Args as l,Flags as d}from"@oclif/core";var e=class a extends n{static{i(this,"SessionsImport")}static description="Import a session file (JSONL, JSON)";static examples=["<%= config.bin %> sessions import ~/.claude/projects/my-project/session-abc.jsonl","<%= config.bin %> sessions import ./copilot-export.json --tool vscode_copilot"];static args={path:l.string({description:"Path to session file",required:!0})};static flags={tool:d.string({description:"Override tool detection (claude_code, cursor, vscode_copilot)"})};async run(){let{args:t,flags:c}=await this.parse(a);this.requireAuth(),o.existsSync(t.path)||this.error(`File not found: ${t.path}`);let p=o.readFileSync(t.path,"utf-8"),s=await r("/api/sessions/import",{content:p,tool:c.tool});this.log(`Imported session ${s.id} (${s.tool}, ${s.eventCount} events)`)}};export{e as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a}from"../../chunk-
|
|
1
|
+
import{a}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{e as n}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as r}from"../../chunk-ZLLER3HP.js";import{Flags as c}from"@oclif/core";var o=class l extends a{static{r(this,"SessionsList")}static description="List captured sessions";static examples=["<%= config.bin %> sessions list","<%= config.bin %> sessions list --tool claude_code"];static flags={tool:c.string({description:"Filter by tool (claude_code, cursor, vscode_copilot)"}),limit:c.integer({description:"Max results",default:20})};async run(){let{flags:e}=await this.parse(l);this.requireAuth();let s=new URLSearchParams;e.tool&&s.set("tool",e.tool),s.set("limit",String(e.limit));let i=await n(`/api/sessions?${s}`);if(i.length===0){this.log("No sessions found.");return}for(let t of i){let d=t.projectPath?.split("/").pop()??"\u2014",p=t.analysis?.adherenceScore!=null?`${t.analysis.adherenceScore}%`:"\u2014",m=new Date(t.startedAt).toLocaleDateString();this.log(`${t.id.slice(0,8)} ${t.tool.padEnd(15)} ${d.padEnd(20)} ${String(t.eventCount).padStart(5)} events ${p.padStart(4)} adherence ${m}`)}}};export{o as default};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{a as g}from"../../chunk-
|
|
1
|
+
import{a as g}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import{a as m}from"../../chunk-3AV3GTMP.js";import{f as p}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as d}from"../../chunk-ZLLER3HP.js";import{Flags as h}from"@oclif/core";import{randomUUID as w}from"node:crypto";import{mkdirSync as j,writeFileSync as u}from"node:fs";import{tmpdir as S}from"node:os";import{join as f}from"node:path";import{execSync as v}from"node:child_process";var i=class x extends g{static{d(this,"SessionsStart")}static description="Start a capture session for any LLM provider (Cortex, Groq, etc.)";static examples=["<%= config.bin %> sessions start --tool cortex","<%= config.bin %> sessions start --tool groq --project-dir /path/to/project",'eval "$(rulemetric proxy env --python)" && rulemetric sessions start --tool cortex'];static flags={tool:h.string({char:"t",required:!0,description:"LLM provider or tool name (e.g., cortex, groq, deepseek, custom_app)"}),"project-dir":h.string({char:"d",description:"Project directory (defaults to cwd)"})};async run(){let{flags:r}=await this.parse(x);this.requireAuth();let t=r["project-dir"]??process.cwd(),s=w(),o="";try{o=v("git branch --show-current 2>/dev/null",{cwd:t,encoding:"utf-8"}).trim()}catch{}let e="";try{e=v("git remote get-url origin 2>/dev/null",{cwd:t,encoding:"utf-8"}).trim()}catch{}let n={};e&&(n.gitRemote=e);let y=m(),c=await p("/api/sessions",{tool:r.tool,externalSessionId:s,projectPath:t,gitBranch:o,metadata:n,orgId:y?.orgId??null}),a=f(S(),"rulemetric");j(a,{recursive:!0});let l=f(a,s);u(l,c.id+`
|
|
2
2
|
`),u(l+".seq",`0
|
|
3
3
|
`),this.log(`Session started: ${c.id}`),this.log(` Tool: ${r.tool}`),this.log(` Project: ${t}`),o&&this.log(` Branch: ${o}`),this.log(""),this.log("The proxy will now capture LLM traffic for this session."),this.log("When done, run: rulemetric sessions end")}};export{i as default};
|
package/dist/commands/setup.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{c as l,d as h,f as m,g as p,h as f,i as y,j as r}from"../chunk-
|
|
1
|
+
import{c as l,d as h,f as m,g as p,h as f,i as y,j as r}from"../chunk-U6ABMRT3.js";import"../chunk-2JRDG4LJ.js";import"../chunk-I2DZGJRR.js";import"../chunk-MVM6OGAF.js";import"../chunk-KKDHD4XA.js";import"../chunk-SZ62CP55.js";import{a as g}from"../chunk-PPKPCXJD.js";import"../chunk-IZTIYR5Q.js";import"../chunk-V44SRRYR.js";import"../chunk-U6XEU573.js";import"../chunk-VLOX6KOM.js";import"../chunk-3AV3GTMP.js";import"../chunk-H2ORWIEY.js";import"../chunk-O6C2UGBY.js";import{a as u}from"../chunk-ZLLER3HP.js";import{Args as b,Flags as c}from"@oclif/core";import*as w from"node:readline/promises";var d=class v extends g{static{u(this,"Setup")}static description="Agentic, transparent setup: plan / show diffs / apply the four core onboarding steps";static examples=["<%= config.bin %> setup # interactive walk (TTY)","<%= config.bin %> setup plan # read-only: every remaining artifact + diff","<%= config.bin %> setup hooks --show # print one step's diff","<%= config.bin %> setup hooks --apply # apply one step","<%= config.bin %> setup --json # machine-readable status (exit 0 iff complete)"];static args={target:b.string({description:`"plan" or a step id (${l.join(", ")})`,required:!1})};static flags={json:c.boolean({description:"Machine-readable output",default:!1}),show:c.boolean({description:"Print the step diff (read-only)",default:!1}),apply:c.boolean({description:"Apply the step",default:!1})};async run(){let{args:t,flags:e}=await this.parse(v),i=h();if(t.target==="plan"){await this.runPlan(i,e.json);return}if(t.target&&y(t.target)){if(e.apply){await f(t.target).apply(i);return}let n=await f(t.target).plan(i);this.printPlan(n);return}if(t.target&&this.error(`Unknown target "${t.target}". Use "plan" or one of: ${l.join(", ")}.`),e.json){let n=await r(i);this.log(JSON.stringify(n,null,2)),n.coreComplete||this.exit(1);return}await this.runInteractive(i)}async runPlan(t,e){let i=await r(t),n=p.filter(s=>!i.steps.find(a=>a.id===s.id)?.done),o=[];for(let s of n)o.push(await s.plan(t));if(e){this.log(JSON.stringify({...i,plans:o},null,2));return}if(o.length===0){this.log("[OK] All core steps complete \u2014 nothing to install.");return}this.log(`The following steps would be applied:
|
|
2
2
|
`);for(let s of o)this.printPlan(s),this.log("")}printPlan(t){this.log(`[..] ${t.title} (${t.id})`),t.command&&this.log(` command: ${t.command}`);for(let e of t.artifacts){this.log(` ${e.kind}: ${e.path}${e.masked?" (secret masked)":""}`);let i=m(e.before,e.after);for(let n of i.split(`
|
|
3
3
|
`))this.log(` ${n}`)}}async runInteractive(t){if(!process.stdin.isTTY){this.log("Not a TTY \u2014 interactive walk needs a terminal."),this.log("Use one of:"),this.log(" rulemetric setup plan \u2014 see every remaining artifact + diff"),this.log(" rulemetric setup <step> --show \u2014 print one step diff"),this.log(" rulemetric setup <step> --apply \u2014 apply one step"),this.log(" rulemetric setup --json \u2014 machine-readable status");return}let e=await r(t),i=p.filter(o=>!e.steps.find(s=>s.id===o.id)?.done);if(i.length===0){this.log("[OK] All core steps complete.");return}let n=w.createInterface({input:process.stdin,output:process.stdout});try{for(let o of i){let s=await o.plan(t);this.printPlan(s);let a=(await n.question(`Apply "${s.title}"? [y/N] `)).trim().toLowerCase();a==="y"||a==="yes"?(await o.apply(t),this.log(`[OK] Applied ${s.title}.`)):this.log(`[..] Skipped ${s.title}.`),this.log("")}}finally{n.close()}}};export{d as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e}from"../../chunk-
|
|
1
|
+
import{a as e}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{e as r}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as o}from"../../chunk-ZLLER3HP.js";import*as a from"node:fs";import*as n from"node:path";import{Flags as m}from"@oclif/core";var t=class p extends e{static{o(this,"SkillsExportApproved")}static description="Export approved community submissions as community-skills.json for registry merge";static examples=["<%= config.bin %> skills export-approved","<%= config.bin %> skills export-approved --output ./community-skills.json"];static flags={output:m.string({description:"Output file path",default:"packages/skills-registry/community-skills.json"})};async run(){let{flags:l}=await this.parse(p);this.requireAuth();let s=await r("/api/skills/submissions/approved");if(s.length===0){this.log("No approved submissions to export.");return}let i=n.resolve(l.output);a.writeFileSync(i,JSON.stringify(s,null,2)),this.log(`Exported ${s.length} approved skills to ${i}`)}};export{t as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as p}from"../../chunk-CDI5CCHU.js";import{a as h}from"../../chunk-
|
|
1
|
+
import{a as p}from"../../chunk-CDI5CCHU.js";import{a as h}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a}from"../../chunk-ZLLER3HP.js";import*as i from"node:fs";import*as t from"node:path";import{Args as m,Flags as u}from"@oclif/core";var g=class e extends h{static{a(this,"SkillsInstall")}static description="Install a skill from the registry into your project";static examples=["<%= config.bin %> skills install tdd-workflow","<%= config.bin %> skills install tdd-workflow --tool cursor","<%= config.bin %> skills install tdd-workflow --preview"];static args={id:m.string({description:"Skill ID to install",required:!0})};static flags={tool:u.string({description:"Target tool format",options:["claude_code","cursor","copilot"]}),preview:u.boolean({description:"Preview content without writing",default:!1}),dir:u.string({description:"Project directory",default:"."})};async run(){let{args:l,flags:s}=await this.parse(e),o=(await p(this)).get(l.id);if(o||this.error(`Skill "${l.id}" not found. Try: rulemetric skills search`),s.preview){this.log(`
|
|
2
2
|
${o.name}`),this.log(`${"\u2500".repeat(o.name.length)}`),this.log(`Category: ${o.category}`),this.log(`Tools: ${o.tools.join(", ")}`),this.log(`Source: ${o.source.url}
|
|
3
3
|
`),this.log(o.content.slice(0,2e3)),o.content.length>2e3&&this.log(`
|
|
4
4
|
... (${o.content.length-2e3} more characters)`);return}let c=t.resolve(s.dir),d=s.tool??w(c)??o.tools[0],r=y(c,d,o.id);r||this.error(`Cannot determine install path for tool "${d}"`);let f=t.dirname(r);if(i.existsSync(f)||i.mkdirSync(f,{recursive:!0}),i.existsSync(r)){this.warn(`File already exists: ${r}`),this.log(" Use --preview to view the skill content first.");return}i.writeFileSync(r,o.content),this.log(`Installed "${o.name}" to ${t.relative(c,r)}`),this.log(` Source: ${o.source.url}`)}};function w(e){return i.existsSync(t.join(e,"CLAUDE.md"))||i.existsSync(t.join(e,".claude"))?"claude_code":i.existsSync(t.join(e,".cursorrules"))||i.existsSync(t.join(e,".cursor"))?"cursor":i.existsSync(t.join(e,".github","copilot-instructions.md"))?"copilot":null}a(w,"detectProjectTool");function y(e,l,s){let n=s.replace(/[^a-z0-9-]/g,"-");switch(l){case"claude_code":return t.join(e,".claude","skills",`${n}.md`);case"cursor":return t.join(e,".cursor","rules",`${n}.mdc`);case"copilot":return t.join(e,".github","agents",`${n}.md`);default:return t.join(e,".claude","skills",`${n}.md`)}}a(y,"getTargetPath");export{g as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as n}from"../../chunk-CDI5CCHU.js";import{a}from"../../chunk-
|
|
1
|
+
import{a as n}from"../../chunk-CDI5CCHU.js";import{a}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as r}from"../../chunk-ZLLER3HP.js";import{Flags as g}from"@oclif/core";var e=class s extends a{static{r(this,"SkillsList")}static description="List skills in the registry";static examples=["<%= config.bin %> skills list","<%= config.bin %> skills list --stats"];static flags={stats:g.boolean({description:"Show registry statistics",default:!1}),limit:g.integer({description:"Max skills to show",default:30})};async run(){let{flags:t}=await this.parse(s),i=await n(this);if(t.stats){this.log(`Skills Registry Statistics
|
|
2
2
|
`),this.log(` Total skills: ${i.size}`),this.log(` Categories: ${i.categories().join(", ")}`),this.log(` Tools: ${i.tools().join(", ")}`),this.log(` Top tags: ${i.tags().slice(0,15).join(", ")}`);return}let o=i.search({limit:t.limit});if(o.length===0){this.log("Registry is empty. Run: rulemetric skills update");return}this.log(`Showing ${o.length} of ${i.size} skills (sorted by popularity):
|
|
3
3
|
`);for(let l of o){let h=l.popularity?.stars?`${u(l.popularity.stars)} stars`:"";this.log(` ${c(l.id,40)} ${c(l.category,14)} ${h}`)}this.log(`
|
|
4
4
|
Search: rulemetric skills search <query>`),this.log("Install: rulemetric skills install <id>")}};function u(s){return s>=1e3?`${(s/1e3).toFixed(1)}k`:String(s)}r(u,"formatStars");function c(s,t){return s.length>t?s.slice(0,t-1)+"\u2026":s.padEnd(t)}r(c,"pad");export{e as default};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as h}from"../../chunk-
|
|
1
|
+
import{a as h}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{f as d}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as p}from"../../chunk-ZLLER3HP.js";import*as a from"node:fs";import*as i from"node:path";import{Args as k,Flags as o}from"@oclif/core";var c=class f extends h{static{p(this,"SkillsPublish")}static description="Submit a skill file to the RuleMetric skills registry";static examples=["<%= config.bin %> skills publish ./my-skill.md","<%= config.bin %> skills publish ./my-skill.md --category workflow --tool claude_code"];static args={file:k.string({description:"Path to skill file (.md)",required:!0})};static flags={name:o.string({description:"Skill name (defaults to filename)"}),description:o.string({description:"One-line description"}),category:o.string({description:"Skill category",options:["workflow","language","framework","tool","security","testing","architecture","devops","documentation","performance","other"],default:"other"}),tool:o.string({description:"Primary tool this skill targets",options:["claude_code","cursor","copilot","windsurf","universal"],default:"universal"}),tags:o.string({description:"Comma-separated tags",default:""})};async run(){let{args:u,flags:e}=await this.parse(f);this.requireAuth();let s=i.resolve(u.file);a.existsSync(s)||this.error(`File not found: ${s}`);let l=a.readFileSync(s,"utf-8");l.trim().length<20&&this.error("Skill content is too short (minimum 20 characters)");let g=i.basename(s,i.extname(s)),r=e.name??g.replace(/[-_]+/g," ").replace(/\b\w/g,t=>t.toUpperCase()),m=g.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),n=e.tags?e.tags.split(",").map(t=>t.trim()).filter(Boolean):[];this.log(`Publishing skill: ${r} (${m})`),this.log(` Category: ${e.category}`),this.log(` Tool: ${e.tool}`),n.length>0&&this.log(` Tags: ${n.join(", ")}`),this.log(` Content: ${l.length} characters
|
|
2
2
|
`);let y={id:m,name:r,description:e.description??`Community skill: ${r}`,category:e.category,tools:[e.tool],tags:n,content:l};try{let t=await d("/api/skills/publish",y);this.log(`Published! ${t.message??`Skill "${r}" submitted to the registry.`}`)}catch(t){throw t instanceof Error&&this.error(`Failed to publish: ${t.message}`),t}}};export{c as default};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{a as n}from"../../chunk-CDI5CCHU.js";import{a}from"../../chunk-
|
|
1
|
+
import{a as n}from"../../chunk-CDI5CCHU.js";import{a}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as e}from"../../chunk-ZLLER3HP.js";import{Args as d,Flags as o}from"@oclif/core";var l=class r extends a{static{e(this,"SkillsSearch")}static description="Search the community skills registry";static examples=['<%= config.bin %> skills search "tdd"',"<%= config.bin %> skills search --tool cursor --category testing","<%= config.bin %> skills search --language python"];static args={query:d.string({description:"Search term",required:!1})};static flags={tool:o.string({description:"Filter by tool",options:["claude_code","cursor","copilot","windsurf","cline","universal"]}),category:o.string({description:"Filter by category",options:["workflow","language","framework","tool","security","testing","architecture","devops","documentation","performance"]}),language:o.string({description:"Filter by programming language"}),framework:o.string({description:"Filter by framework"}),limit:o.integer({description:"Max results",default:20})};async run(){let{args:g,flags:i}=await this.parse(r),s=(await n(this)).search({query:g.query,tool:i.tool,category:i.category,language:i.language,framework:i.framework,limit:i.limit});if(s.length===0){this.log("No skills found matching your criteria."),this.log(`
|
|
2
2
|
Try a broader search or run: rulemetric skills list`);return}this.log(`Found ${s.length} skill${s.length===1?"":"s"}:
|
|
3
3
|
`);for(let t of s){let c=t.popularity?.stars?` (${m(t.popularity.stars)} stars)`:"",u=t.tools.join(", ");this.log(` ${t.id}`),this.log(` ${t.name} \u2014 ${t.description}`),this.log(` tools: ${u} category: ${t.category}${c}`),t.tags.length>0&&this.log(` tags: ${t.tags.join(", ")}`),this.log("")}this.log("Run: rulemetric skills install <id> to install a skill")}};function m(r){return r>=1e3?`${(r/1e3).toFixed(1)}k`:String(r)}e(m,"formatStars");export{l as default};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{a as n}from"../../chunk-
|
|
1
|
+
import{a as n}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as e}from"../../chunk-ZLLER3HP.js";import*as s from"node:fs";import*as r from"node:path";import*as m from"node:os";import{Flags as h}from"@oclif/core";import{fetchAllSources as y,TIER_1_SOURCES as c,TIER_2_SOURCES as S}from"@rulemetric/skills-registry";var i=r.join(m.homedir(),".config","rulemetric"),f=r.join(i,"skills-registry.json"),t=class g extends n{static{e(this,"SkillsUpdate")}static description="Fetch latest skills from GitHub sources and update local registry";static examples=["<%= config.bin %> skills update","<%= config.bin %> skills update --all"];static flags={all:h.boolean({description:"Include Tier 2 (niche) sources",default:!1})};async run(){let{flags:o}=await this.parse(g),l=o.all?[...c,...S]:c;this.log(`Fetching skills from ${l.length} sources${o.all?" (Tier 1 + 2)":""}...
|
|
2
2
|
`);let a=await y(l,{onProgress:e((p,u)=>{this.log(` ${p}: ${u} skills`)},"onProgress")}),d={version:"1.0.0",generatedAt:new Date().toISOString(),skills:a.entries};s.existsSync(i)||s.mkdirSync(i,{recursive:!0}),s.writeFileSync(f,JSON.stringify(d)),this.log(`
|
|
3
3
|
Updated registry: ${a.entries.length} skills cached at ${f}`)}};export{t as default};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{a as l}from"../../chunk-MODXEGCU.js";import{a as g}from"../../chunk-WLVQJH4E.js";import{a as u}from"../../chunk-
|
|
1
|
+
import{a as l}from"../../chunk-MODXEGCU.js";import{a as g}from"../../chunk-WLVQJH4E.js";import{a as u}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{e as d,f as p}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as c}from"../../chunk-ZLLER3HP.js";import*as o from"node:fs";import*as f from"node:path";import{Args as $}from"@oclif/core";function U(r,i,a){let e=f.join(r,"CLAUDE.md"),t=`<!-- rulemetric:start ${i} -->`,s=`<!-- rulemetric:end ${i} -->`,n=o.existsSync(e)?o.readFileSync(e,"utf8"):"";if(n.includes(t))return!1;let h=`${n.length>0&&!n.endsWith(`
|
|
2
2
|
`)?`
|
|
3
3
|
|
|
4
4
|
`:n.length>0?`
|
|
5
5
|
`:""}
|
|
6
|
-
${
|
|
6
|
+
${t}
|
|
7
7
|
${a}
|
|
8
8
|
${s}
|
|
9
|
-
`;return o.writeFileSync(
|
|
9
|
+
`;return o.writeFileSync(e,n+h,"utf8"),!0}c(U,"appendToCLAUDEmd");var m=class r extends u{static{c(this,"SuggestionsAccept")}static description="Accept a suggestion and append the instruction to CLAUDE.md";static examples=["<%= config.bin %> suggestions accept <id>"];static args={id:$.string({description:"Suggestion UUID from `suggestions list`",required:!0})};async run(){let{args:i}=await this.parse(r);this.requireAuth(),g(i.id,"suggestion ID");let a=l(process.cwd()),e=await d(`/api/instruction-suggestions/${encodeURIComponent(i.id)}`),t=e.instructionId;e.instructionScope==="public"&&(t=(await p(`/api/instructions/${encodeURIComponent(e.instructionId)}/promote-from-public`,{targetScope:"personal"})).instructionId);let s=await d(`/api/instructions/${encodeURIComponent(t)}`);U(process.cwd(),t,s.content)?this.log(`Accepted: added ${s.name} to CLAUDE.md. It will be active starting in your next session.`):this.log(`Already present: ${s.name} is already in CLAUDE.md (block id: ${t}).`),await p(`/api/instruction-suggestions/${encodeURIComponent(i.id)}/events`,{eventType:"accepted",projectPath:a,instructionId:t})}};export{U as appendToCLAUDEmd,m as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a}from"../../chunk-MODXEGCU.js";import{a as r}from"../../chunk-WLVQJH4E.js";import{a as o}from"../../chunk-
|
|
1
|
+
import{a}from"../../chunk-MODXEGCU.js";import{a as r}from"../../chunk-WLVQJH4E.js";import{a as o}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{f as t}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as e}from"../../chunk-ZLLER3HP.js";import{Args as m}from"@oclif/core";var s=class n extends o{static{e(this,"SuggestionsDismiss")}static description="Dismiss a suggestion so it will not re-surface for 30 days";static examples=["<%= config.bin %> suggestions dismiss <id>"];static args={id:m.string({description:"Suggestion UUID from `suggestions list`",required:!0})};async run(){let{args:i}=await this.parse(n);this.requireAuth(),r(i.id,"suggestion ID");let d=a(process.cwd());await t(`/api/instruction-suggestions/${encodeURIComponent(i.id)}/events`,{eventType:"dismissed",projectPath:d}),this.log("Dismissed. Won't re-surface for 30 days.")}};export{s as default};
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
import{a as
|
|
1
|
+
import{a as d}from"../../chunk-MODXEGCU.js";import{a as g}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{e as a}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as c}from"../../chunk-ZLLER3HP.js";import{Flags as f}from"@oclif/core";import{printTable as h}from"@oclif/table";var o=class p extends g{static{c(this,"SuggestionsList")}static description="List instruction suggestions for a project";static examples=["<%= config.bin %> suggestions list","<%= config.bin %> suggestions list --project /path/to/project"];static flags={project:f.string({char:"p",description:"Project path (defaults to current directory)"})};async run(){let{flags:u}=await this.parse(p);this.requireAuth();let m=d(u.project??process.cwd()),l=encodeURIComponent(m),s=await a(`/api/instruction-suggestions?projectPath=${l}&limit=10`);if(s.suggestions.length===0){this.log("No suggestions for this project. They are recomputed daily at 04:30 UTC by a server-side cron and run on your background worker \u2014 make sure one is running (`rulemetric evals agent`, or `rulemetric service install --worker-only`).");return}h({data:s.suggestions.map(e=>({ID:e.id,Scope:e.instructionScope,Name:e.name,Score:e.score.toFixed(2),Reason:e.reason.length>60?e.reason.slice(0,59)+"\u2026":e.reason})),columns:["ID","Scope","Name","Score","Reason"]});let t=s.stats??{},r=(t.surfaced??0)+(t.surfaced_with_content??0)+(t.proxy_injected??0),i=(t.accepted??0)+(t.promoted??0),n=t.dismissed??0;r+i+n>0&&this.log(`
|
|
2
|
+
Lifetime for this project: ${r} surfaced \xB7 ${i} accepted \xB7 ${n} dismissed`)}};export{o as default};
|