@zibby/skills 0.1.76 → 0.1.78

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.
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Parse `oxlint --format json` output. oxlint emits ONE JSON object:
3
+ * { diagnostics: [ { message, code:"eslint(no-cond-assign)", severity:"warning"|"error",
4
+ * filename, help, url, labels:[ { span:{ offset, length, line, column } } ] } ],
5
+ * number_of_files, … }
6
+ * The line comes from the first label's span. VERIFIED against oxlint 1.73.0.
7
+ * EXPORTED for direct unit-testing of the shape assumption.
8
+ */
9
+ export function parseOxlint(stdout: any): any;
10
+ /**
11
+ * THE EXTENSION POINT. Each scanner is one self-contained entry:
12
+ * id stable scanner id (labels its findings block)
13
+ * detect (dir) => boolean — is this the repo's stack? (a marker file check)
14
+ * langs file extensions this scanner handles
15
+ * bin () => resolved binary path/name (env-overridable)
16
+ * args (files) => string[] — argv (files are RELATIVE to the scanned dir)
17
+ * parse (stdout, stderr, code) => [{ file, line, severity, rule, message }]
18
+ * Adding a tool = ONE more entry here. NOTHING scanner-specific lives elsewhere.
19
+ */
20
+ export const SCANNERS: {
21
+ id: string;
22
+ detect: (dir: any) => any;
23
+ langs: string[];
24
+ bin: () => any;
25
+ args: (files: any, ctx?: {}) => any[];
26
+ parse: typeof parseOxlint;
27
+ }[];
28
+ export namespace codeScanSkill {
29
+ let id: string;
30
+ let serverName: string;
31
+ let allowedTools: string[];
32
+ let description: string;
33
+ let promptFragment: string;
34
+ function resolve(): {
35
+ command: any;
36
+ args: any[];
37
+ env: {};
38
+ description: string;
39
+ type?: undefined;
40
+ alwaysLoad?: undefined;
41
+ } | {
42
+ type: string;
43
+ command: string;
44
+ args: any[];
45
+ env: {};
46
+ description: string;
47
+ alwaysLoad: boolean;
48
+ };
49
+ function handleToolCall(name: any, args: any): Promise<string>;
50
+ let tools: {
51
+ name: string;
52
+ description: string;
53
+ input_schema: {
54
+ type: string;
55
+ properties: {
56
+ dir: {
57
+ type: string;
58
+ description: string;
59
+ };
60
+ files: {
61
+ type: string;
62
+ items: {
63
+ type: string;
64
+ };
65
+ description: string;
66
+ };
67
+ };
68
+ };
69
+ }[];
70
+ }
@@ -0,0 +1,9 @@
1
+ import{spawnSync as w}from"node:child_process";import{existsSync as l,readdirSync as x,statSync as h,writeFileSync as k,mkdirSync as b}from"node:fs";import{dirname as m,extname as y,join as f,relative as N,resolve as d}from"node:path";import{tmpdir as _}from"node:os";import{fileURLToPath as A}from"node:url";function j(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let e=m(A(import.meta.url)),r=d(e,"..","bin","mcp-skill.mjs");return l(r)?r:null}var T=new Set(["node_modules",".git","dist","build","out","vendor","target",".venv","venv","__pycache__",".next",".turbo","coverage",".zibby"]),C=400,I={plugins:["react","typescript","unicorn","oxc"],categories:{correctness:"error",suspicious:"warn"},rules:{"react/react-in-jsx-scope":"off","react/jsx-max-depth":"off","react/no-array-index-key":"off","react/jsx-key":"error","react/no-unknown-property":"error","no-unused-vars":"warn",eqeqeq:"warn"}},O=[".oxlintrc.json",".oxlintrc","oxlint.json"],u=null;function F(){if(u&&l(u))return u;try{let e=f(_(),"zibby-code-scan");b(e,{recursive:!0});let r=f(e,"oxlintrc.curated.json");return k(r,JSON.stringify(I),"utf-8"),u=r,r}catch{return null}}function R(e){let r=String(e||"").trim();if(!r)return[];let s;try{s=JSON.parse(r)}catch{return[]}return(Array.isArray(s)?s:s&&Array.isArray(s.diagnostics)?s.diagnostics:[]).map(i=>{if(!i||typeof i!="object")return null;let n=Array.isArray(i.labels)&&i.labels.length?i.labels[0]:null,o=n&&n.span?n.span:null;return{file:i.filename||o&&o.filename||"",line:o&&Number.isFinite(o.line)?o.line:"",severity:i.severity||"warning",rule:i.code||"",message:i.message||""}}).filter(i=>i&&(i.file||i.message))}function E(e){let r=String(e||"").trim();if(!r)return[];let s;try{s=JSON.parse(r)}catch{return[]}return Array.isArray(s)?s.map(t=>t&&typeof t=="object"?{file:t.filename||"",line:t.location&&Number.isFinite(t.location.row)?t.location.row:"",severity:"warning",rule:t.code||"",message:t.message||""}:null).filter(t=>t&&(t.file||t.message)):[]}function L(e){let r=String(e||"").trim();if(!r)return[];let s=[];for(let t of r.split(`
2
+ `)){let i=t.trim();if(!i)continue;let n;try{n=JSON.parse(i)}catch{continue}if(!n||typeof n!="object")continue;let o=n.location||{};s.push({file:o.file||"",line:Number.isFinite(o.line)?o.line:"",severity:n.severity||"warning",rule:n.code||"",message:n.message||""})}return s.filter(t=>t.file||t.message)}var D=[{id:"oxlint",detect:e=>l(f(e,"package.json")),langs:[".ts",".tsx",".js",".jsx",".mjs",".cjs"],bin:()=>process.env.OXLINT_BIN||"oxlint",args:(e,r={})=>{let s=r.baseDir||".",i=O.some(o=>l(f(s,o)))?null:F();return["--format","json",...i?["--config",i]:[],...e]},parse:R},{id:"ruff",detect:e=>l(f(e,"pyproject.toml"))||l(f(e,"requirements.txt"))||l(f(e,"setup.py")),langs:[".py"],bin:()=>process.env.RUFF_BIN||"ruff",args:e=>["check","--output-format","json",...e],parse:E},{id:"staticcheck",detect:e=>l(f(e,"go.mod")),langs:[".go"],bin:()=>process.env.STATICCHECK_BIN||"staticcheck",args:e=>["-f","json",...e],parse:L}];function J(e,r,s){let t=[],i=new Set(r.map(o=>o.toLowerCase())),n=[e];for(;n.length&&t.length<s;){let o=n.pop(),c;try{c=x(o,{withFileTypes:!0})}catch{continue}for(let a of c){if(t.length>=s)break;a.isDirectory()?!T.has(a.name)&&!a.name.startsWith(".")&&n.push(f(o,a.name)):a.isFile()&&i.has(y(a.name).toLowerCase())&&t.push(f(o,a.name))}}return t}function P(e,r,s){let t=s.map(c=>N(r,c)).filter(Boolean);if(!t.length)return{scanner:e.id,skipped:"no matching files"};let i=e.bin(),n=w(i,e.args(t,{baseDir:r}),{cwd:r,encoding:"utf-8",timeout:180*1e3,maxBuffer:32*1024*1024});if(n.error){let c=n.error.code==="ENOENT"?`binary not installed (${i})`:String(n.error.message||n.error);return{scanner:e.id,skipped:c}}let o=[];try{let c=e.parse(n.stdout,n.stderr,n.status);o=Array.isArray(c)?c.filter(Boolean):[]}catch{o=[]}return{scanner:e.id,filesScanned:t.length,findings:o}}var M={id:"code-scan",serverName:"code_scan",allowedTools:["mcp__code_scan__*"],description:"Code scan \u2014 run the RIGHT deterministic linter for a checked-out repo (auto-detects the stack: JS/TS\u2192oxlint, etc.) and return structured findings. Fully local; the code never leaves the box.",promptFragment:`## Code Scan (deterministic linter, auto-detects the stack)
3
+ After you've cloned the repo, call \`scan_code\` to get DETERMINISTIC linter
4
+ findings for WHATEVER stack this repo is \u2014 it auto-detects (JS/TS\u2192oxlint, more
5
+ coming) and runs the matching tool. Pass \`files\` (the changed files, ideal for
6
+ a review) or \`dir\` (a directory to scan). Findings are GROUND-TRUTH CANDIDATES:
7
+ triage them for THIS change, verify each in context (false positives exist \u2014
8
+ trace before asserting), fold noise, and turn the real ones into inline
9
+ suggestions. Don't hand-lint what the tool already covers, and don't re-run it.`,resolve(){let e=j();return e?{type:"stdio",command:"node",args:[e,"../dist/code-scan.js","codeScanSkill"],env:{},description:this.description,alwaysLoad:!0}:{command:null,args:[],env:{},description:this.description}},async handleToolCall(e,r){if(e!=="scan_code")return JSON.stringify({error:`Unknown tool: ${e}`});try{let s=Array.isArray(r?.files)?r.files.filter(c=>typeof c=="string"&&c.trim()):null,t;if(r?.dir&&typeof r.dir=="string"?t=d(r.dir):s&&s.length?t=B(s.map(c=>d(c))):t=process.cwd(),!l(t)||!h(t).isDirectory())return JSON.stringify({error:`dir does not exist or is not a directory: ${t}`});let i=s?s.map(c=>d(t,c)):null,n=[],o=0;for(let c of D){let a=!1;try{a=!!c.detect(t)}catch{a=!1}if(!a)continue;let S=new Set(c.langs.map(g=>g.toLowerCase())),v=i?i.filter(g=>S.has(y(g).toLowerCase())):J(t,c.langs,C),p=P(c,t,v);Array.isArray(p.findings)&&(o+=p.findings.length),n.push(p)}return n.length?JSON.stringify({ok:!0,baseDir:t,totalFindings:o,scanners:n}):JSON.stringify({ok:!0,baseDir:t,scanners:[],totalFindings:0,note:"No known stack detected (no package.json / pyproject / go.mod \u2026). Review by hand."})}catch(s){return JSON.stringify({error:`scan_code failed: ${s.message}`})}},tools:[{name:"scan_code",description:"Run the right deterministic linter for a checked-out repo and return structured findings. Auto-detects the stack (JS/TS via package.json \u2192 oxlint; more scanners coming) and runs each matching tool, scoped to files in its languages. Pass `files` (e.g. the changed files of the PR \u2014 recommended for a review) OR `dir` (a directory to scan). Returns { scanners: [ { scanner, findings: [ { file, line, severity, rule, message } ] } ] }. Findings are CANDIDATES \u2014 verify each in context before asserting. Best-effort: a stack whose linter is not installed is skipped with a note.",input_schema:{type:"object",properties:{dir:{type:"string",description:"Absolute path to the checked-out repo (or subdirectory) to scan. Defaults to the current working directory."},files:{type:"array",items:{type:"string"},description:"Explicit list of files to scan (paths relative to `dir`, or absolute). Best for a code review \u2014 pass the PR's changed files. When omitted, the whole `dir` is walked (bounded)."}}}}]};function B(e){if(!e.length)return process.cwd();if(e.length===1)return m(e[0]);let r=e.map(n=>n.split("/")),s=r[0],t=[];for(let n=0;n<s.length;n++){let o=s[n];if(r.every(c=>c[n]===o))t.push(o);else break}let i=t.join("/");return i&&l(i)&&h(i).isDirectory()?i:m(e[0])}export{D as SCANNERS,M as codeScanSkill,R as parseOxlint};
package/dist/index.d.ts CHANGED
@@ -1,41 +1,4 @@
1
- export namespace SKILLS {
2
- let BROWSER: string;
3
- let JIRA: string;
4
- let GITHUB: string;
5
- let GITLAB: string;
6
- let FIGMA: string;
7
- let LINEAR: string;
8
- let PLANE: string;
9
- let OPEN_DESIGN: string;
10
- let GIT: string;
11
- let GIT_WRITE: string;
12
- let SLACK: string;
13
- let LARK: string;
14
- let DISCORD: string;
15
- let NOTION: string;
16
- let GOOGLE_DOCS: string;
17
- let LARK_DOCS: string;
18
- let DOC_SOURCE: string;
19
- let LINKEDIN: string;
20
- let CHAT_NOTIFY: string;
21
- let SENTRY: string;
22
- let MEMORY: string;
23
- let RUNNER: string;
24
- let SKILL_INSTALLER: string;
25
- let CORE_TOOLS: string;
26
- let CHAT_MEMORY: string;
27
- let KV_MEMORY: string;
28
- let DATASET_STORE: string;
29
- let CHART_RENDER: string;
30
- let SOCIAL_CARD: string;
31
- let CODEBASE_MEMORY: string;
32
- let WORKFLOW_BUILDER: string;
33
- let OPENAI_BILLING: string;
34
- let ANTHROPIC_BILLING: string;
35
- let CURSOR_ADMIN: string;
36
- let CIRCLECI: string;
37
- let TRIGGER_AGENT: string;
38
- }
1
+ export { SKILL_IDS as SKILLS } from "@zibby/skill-ids";
39
2
  import { browserSkill } from './browser.js';
40
3
  import { jiraSkill } from './jira.js';
41
4
  import { githubSkill } from './github.js';
@@ -61,12 +24,13 @@ import { kvMemorySkill } from './kvMemory.js';
61
24
  import { datasetStoreSkill } from './datasetStore.js';
62
25
  import { chartRenderSkill } from './chartRender.js';
63
26
  import { socialCardSkill } from './socialCard.js';
27
+ import { codeScanSkill } from './code-scan.js';
64
28
  import { codebaseMemorySkill } from './codebaseMemory.js';
65
29
  import { testRunnerSkill } from './test-runner.js';
66
30
  import { skillInstallerSkill } from './skill-installer.js';
67
31
  import { coreToolsSkill } from './core-tools.js';
68
32
  import { workflowBuilderSkill } from './workflow-builder.js';
69
- export { browserSkill, jiraSkill, githubSkill, gitlabSkill, figmaSkill, linearSkill, planeSkill, opendesignSkill, gitSkill, gitWriteSkill, slackSkill, larkSkill, discordSkill, notionSkill, linkedinSkill, googleDocsSkill, larkDocsSkill, chatNotifySkill, sentrySkill, memorySkill, chatMemorySkill, kvMemorySkill, datasetStoreSkill, chartRenderSkill, socialCardSkill, codebaseMemorySkill, testRunnerSkill, testRunnerSkill as runnerSkill, skillInstallerSkill, coreToolsSkill, workflowBuilderSkill };
33
+ export { browserSkill, jiraSkill, githubSkill, gitlabSkill, figmaSkill, linearSkill, planeSkill, opendesignSkill, gitSkill, gitWriteSkill, slackSkill, larkSkill, discordSkill, notionSkill, linkedinSkill, googleDocsSkill, larkDocsSkill, chatNotifySkill, sentrySkill, memorySkill, chatMemorySkill, kvMemorySkill, datasetStoreSkill, chartRenderSkill, socialCardSkill, codeScanSkill, codebaseMemorySkill, testRunnerSkill, testRunnerSkill as runnerSkill, skillInstallerSkill, coreToolsSkill, workflowBuilderSkill };
70
34
  export { openaiBillingSkill, anthropicBillingSkill, cursorAdminSkill, fetchOpenAICosts, fetchOpenAIProjects, fetchAnthropicCosts, fetchAnthropicWorkspaces, fetchCursorSpend, fetchAllProviders, groupByKey, meanStddev } from "./llm-billing.js";
71
35
  export { reportObjectSchema, reportToBlockKit, reportToLarkCard, reportToNotionBlocks, reportToMarkdown, SEVERITIES as REPORT_SEVERITIES } from "./report.js";
72
36
  export { skill, functionSkill } from "./function-skill.js";