javi-forge 1.6.0 → 1.7.0
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 +45 -1
- package/ci-local/README.md +56 -11
- package/ci-local/ci-local.ps1 +445 -0
- package/ci-local/ci-local.sh +52 -9
- package/ci-local/docker/python.Dockerfile +7 -0
- package/ci-local/hooks/commit-msg +120 -44
- package/ci-local/hooks/commit-msg.test.sh +286 -0
- package/ci-local/hooks/pre-commit +9 -1
- package/ci-local/hooks/pre-push +13 -2
- package/ci-local/install.ps1 +367 -0
- package/ci-local/install.sh +151 -5
- package/ci-local/uninstall.ps1 +85 -0
- package/ci-local/uninstall.sh +95 -0
- package/dist/cli/dispatch/ci.d.ts +12 -0
- package/dist/cli/dispatch/ci.js +38 -0
- package/dist/cli/dispatch/security.d.ts +11 -0
- package/dist/cli/dispatch/security.js +68 -0
- package/dist/cli/dispatch/simple-renderers.d.ts +16 -0
- package/dist/cli/dispatch/simple-renderers.js +65 -0
- package/dist/cli/dispatch/skill-publish.d.ts +15 -0
- package/dist/cli/dispatch/skill-publish.js +44 -0
- package/dist/cli/dispatch/skills-cmd.d.ts +13 -0
- package/dist/cli/dispatch/skills-cmd.js +93 -0
- package/dist/cli/dispatch/tdd.d.ts +11 -0
- package/dist/cli/dispatch/tdd.js +45 -0
- package/dist/cli/dispatch/types.d.ts +29 -0
- package/dist/cli/dispatch/types.js +2 -0
- package/dist/cli/dispatch/workflow.d.ts +11 -0
- package/dist/cli/dispatch/workflow.js +67 -0
- package/dist/cli/help.d.ts +127 -0
- package/dist/cli/help.js +138 -0
- package/dist/cli/runtime.d.ts +16 -0
- package/dist/cli/runtime.js +38 -0
- package/dist/cli/validators.d.ts +17 -0
- package/dist/cli/validators.js +35 -0
- package/dist/commands/analyze.d.ts +1 -1
- package/dist/commands/analyze.js +14 -16
- package/dist/commands/ci.d.ts +50 -3
- package/dist/commands/ci.js +537 -182
- package/dist/commands/doctor.d.ts +2 -2
- package/dist/commands/doctor.js +112 -62
- package/dist/commands/init/report.d.ts +13 -0
- package/dist/commands/init/report.js +13 -0
- package/dist/commands/init/steps/agent-skills.d.ts +13 -0
- package/dist/commands/init/steps/agent-skills.js +45 -0
- package/dist/commands/init/steps/ai-sync.d.ts +15 -0
- package/dist/commands/init/steps/ai-sync.js +62 -0
- package/dist/commands/init/steps/ci.d.ts +24 -0
- package/dist/commands/init/steps/ci.js +74 -0
- package/dist/commands/init/steps/claude-md.d.ts +14 -0
- package/dist/commands/init/steps/claude-md.js +54 -0
- package/dist/commands/init/steps/code-graph.d.ts +16 -0
- package/dist/commands/init/steps/code-graph.js +68 -0
- package/dist/commands/init/steps/context-dir.d.ts +13 -0
- package/dist/commands/init/steps/context-dir.js +47 -0
- package/dist/commands/init/steps/docker-deploy.d.ts +16 -0
- package/dist/commands/init/steps/docker-deploy.js +60 -0
- package/dist/commands/init/steps/ghagga.d.ts +15 -0
- package/dist/commands/init/steps/ghagga.js +58 -0
- package/dist/commands/init/steps/git.d.ts +25 -0
- package/dist/commands/init/steps/git.js +81 -0
- package/dist/commands/init/steps/gitignore.d.ts +13 -0
- package/dist/commands/init/steps/gitignore.js +39 -0
- package/dist/commands/init/steps/local-ai.d.ts +14 -0
- package/dist/commands/init/steps/local-ai.js +53 -0
- package/dist/commands/init/steps/manifest.d.ts +13 -0
- package/dist/commands/init/steps/manifest.js +58 -0
- package/dist/commands/init/steps/memory.d.ts +15 -0
- package/dist/commands/init/steps/memory.js +60 -0
- package/dist/commands/init/steps/mock.d.ts +13 -0
- package/dist/commands/init/steps/mock.js +64 -0
- package/dist/commands/init/steps/sdd.d.ts +12 -0
- package/dist/commands/init/steps/sdd.js +40 -0
- package/dist/commands/init/steps/security.d.ts +28 -0
- package/dist/commands/init/steps/security.js +103 -0
- package/dist/commands/init/types.d.ts +30 -0
- package/dist/commands/init/types.js +2 -0
- package/dist/commands/init.d.ts +5 -4
- package/dist/commands/init.js +42 -387
- package/dist/commands/llmstxt.d.ts +1 -1
- package/dist/commands/llmstxt.js +36 -34
- package/dist/commands/plugin.d.ts +10 -1
- package/dist/commands/plugin.js +92 -47
- package/dist/commands/security.d.ts +11 -5
- package/dist/commands/security.js +236 -77
- package/dist/commands/skills/analysis.d.ts +19 -0
- package/dist/commands/skills/analysis.js +211 -0
- package/dist/commands/skills/benchmark.d.ts +6 -0
- package/dist/commands/skills/benchmark.js +82 -0
- package/dist/commands/skills/constants.d.ts +10 -0
- package/dist/commands/skills/constants.js +27 -0
- package/dist/commands/skills/directives.d.ts +21 -0
- package/dist/commands/skills/directives.js +101 -0
- package/dist/commands/skills/parsing.d.ts +16 -0
- package/dist/commands/skills/parsing.js +108 -0
- package/dist/commands/skills/rules.d.ts +5 -0
- package/dist/commands/skills/rules.js +32 -0
- package/dist/commands/skills/scoring.d.ts +47 -0
- package/dist/commands/skills/scoring.js +306 -0
- package/dist/commands/skills.d.ts +8 -69
- package/dist/commands/skills.js +9 -490
- package/dist/commands/tdd-pipeline.d.ts +17 -0
- package/dist/commands/tdd-pipeline.js +144 -0
- package/dist/commands/tdd.d.ts +1 -1
- package/dist/commands/tdd.js +21 -18
- package/dist/commands/workflow.d.ts +23 -0
- package/dist/commands/workflow.js +116 -0
- package/dist/constants.d.ts +15 -1
- package/dist/constants.js +161 -122
- package/dist/index.js +43 -280
- package/dist/lib/agent-skills.d.ts +36 -1
- package/dist/lib/agent-skills.js +168 -19
- package/dist/lib/atlassian-mcp.d.ts +42 -0
- package/dist/lib/atlassian-mcp.js +98 -0
- package/dist/lib/auto-skill-install.d.ts +37 -0
- package/dist/lib/auto-skill-install.js +91 -0
- package/dist/lib/auto-wire.d.ts +20 -0
- package/dist/lib/auto-wire.js +240 -0
- package/dist/lib/ci-config.d.ts +65 -0
- package/dist/lib/ci-config.js +297 -0
- package/dist/lib/claudemd.d.ts +13 -1
- package/dist/lib/claudemd.js +174 -24
- package/dist/lib/codex-export.d.ts +1 -1
- package/dist/lib/codex-export.js +26 -32
- package/dist/lib/common.d.ts +1 -1
- package/dist/lib/common.js +52 -44
- package/dist/lib/context.d.ts +17 -2
- package/dist/lib/context.js +142 -13
- package/dist/lib/crash-recovery.d.ts +34 -0
- package/dist/lib/crash-recovery.js +123 -0
- package/dist/lib/docker.d.ts +23 -2
- package/dist/lib/docker.js +168 -131
- package/dist/lib/exec.d.ts +10 -0
- package/dist/lib/exec.js +11 -0
- package/dist/lib/frontmatter.d.ts +1 -1
- package/dist/lib/frontmatter.js +29 -15
- package/dist/lib/harness-audit.d.ts +35 -0
- package/dist/lib/harness-audit.js +277 -0
- package/dist/lib/parallel-batch.d.ts +42 -0
- package/dist/lib/parallel-batch.js +88 -0
- package/dist/lib/plugin.d.ts +9 -3
- package/dist/lib/plugin.js +127 -70
- package/dist/lib/secret-scanner.d.ts +30 -0
- package/dist/lib/secret-scanner.js +274 -0
- package/dist/lib/security-analysis.d.ts +74 -0
- package/dist/lib/security-analysis.js +489 -0
- package/dist/lib/skill-publish.d.ts +40 -0
- package/dist/lib/skill-publish.js +164 -0
- package/dist/lib/skill-scanner.d.ts +63 -0
- package/dist/lib/skill-scanner.js +383 -0
- package/dist/lib/stack-detector.d.ts +38 -0
- package/dist/lib/stack-detector.js +207 -0
- package/dist/lib/supply-chain.d.ts +23 -0
- package/dist/lib/supply-chain.js +126 -0
- package/dist/lib/team-presets.d.ts +53 -0
- package/dist/lib/team-presets.js +201 -0
- package/dist/lib/template.d.ts +16 -1
- package/dist/lib/template.js +46 -17
- package/dist/lib/workflow/discovery.d.ts +27 -0
- package/dist/lib/workflow/discovery.js +85 -0
- package/dist/lib/workflow/index.d.ts +5 -0
- package/dist/lib/workflow/index.js +5 -0
- package/dist/lib/workflow/parser.d.ts +16 -0
- package/dist/lib/workflow/parser.js +198 -0
- package/dist/lib/workflow/renderer.d.ts +9 -0
- package/dist/lib/workflow/renderer.js +152 -0
- package/dist/lib/workflow/validator.d.ts +10 -0
- package/dist/lib/workflow/validator.js +189 -0
- package/dist/tasks/index.d.ts +4 -0
- package/dist/tasks/index.js +4 -0
- package/dist/tasks/scaffold-tasks.d.ts +3 -0
- package/dist/tasks/scaffold-tasks.js +14 -0
- package/dist/tasks/task-id.d.ts +30 -0
- package/dist/tasks/task-id.js +59 -0
- package/dist/tasks/task-tracker.d.ts +15 -0
- package/dist/tasks/task-tracker.js +81 -0
- package/dist/types/index.d.ts +134 -6
- package/dist/types/index.js +11 -1
- package/dist/ui/AnalyzeUI.d.ts +1 -1
- package/dist/ui/AnalyzeUI.js +38 -39
- package/dist/ui/App.d.ts +5 -3
- package/dist/ui/App.js +86 -46
- package/dist/ui/AutoSkills.d.ts +9 -0
- package/dist/ui/AutoSkills.js +124 -0
- package/dist/ui/CI.d.ts +2 -2
- package/dist/ui/CI.js +24 -26
- package/dist/ui/CIContext.d.ts +1 -1
- package/dist/ui/CIContext.js +2 -2
- package/dist/ui/CISelector.d.ts +2 -2
- package/dist/ui/CISelector.js +23 -15
- package/dist/ui/Doctor.d.ts +1 -1
- package/dist/ui/Doctor.js +35 -29
- package/dist/ui/Header.d.ts +1 -1
- package/dist/ui/Header.js +14 -14
- package/dist/ui/HookProfileSelector.d.ts +9 -0
- package/dist/ui/HookProfileSelector.js +54 -0
- package/dist/ui/LlmsTxt.d.ts +1 -1
- package/dist/ui/LlmsTxt.js +31 -22
- package/dist/ui/MemorySelector.d.ts +2 -2
- package/dist/ui/MemorySelector.js +28 -16
- package/dist/ui/NameInput.d.ts +1 -1
- package/dist/ui/NameInput.js +21 -21
- package/dist/ui/OptionSelector.d.ts +6 -2
- package/dist/ui/OptionSelector.js +83 -32
- package/dist/ui/Plugin.d.ts +4 -3
- package/dist/ui/Plugin.js +78 -35
- package/dist/ui/Progress.d.ts +3 -3
- package/dist/ui/Progress.js +23 -22
- package/dist/ui/Skills.d.ts +2 -2
- package/dist/ui/Skills.js +61 -32
- package/dist/ui/StackSelector.d.ts +2 -2
- package/dist/ui/StackSelector.js +27 -17
- package/dist/ui/Summary.d.ts +3 -3
- package/dist/ui/Summary.js +60 -50
- package/dist/ui/Welcome.d.ts +1 -1
- package/dist/ui/Welcome.js +15 -16
- package/dist/ui/theme.d.ts +1 -1
- package/dist/ui/theme.js +6 -6
- package/lib/common.psm1 +167 -0
- package/lib/common.sh +30 -0
- package/package.json +46 -24
- package/templates/common/atlassian/mcp-atlassian-snippet.json +16 -0
- package/templates/common/repoforge/mcp-repoforge-snippet.json +11 -0
- package/templates/common/repoforge/repoforge.yaml +34 -0
- package/templates/github/deploy-docker-zero-downtime.yml +140 -0
- package/templates/github/repoforge-graph.yml +45 -0
- package/templates/gitlab/deploy-docker-zero-downtime.yml +57 -0
- package/templates/local-ai/.env.example +17 -0
- package/templates/local-ai/docker-compose.yml +95 -0
- package/templates/security-hooks/claude-settings-security.json +30 -0
- package/templates/security-hooks/commit-msg-signing +29 -0
- package/templates/security-hooks/pre-commit-permissions +74 -0
- package/templates/security-hooks/pre-commit-secrets +74 -0
- package/templates/security-hooks/pre-push-branch-protection +62 -0
- package/templates/security-hooks/pre-push-deps +83 -0
- package/templates/security-hooks/pre-push-signing +67 -0
- package/templates/woodpecker/deploy-docker-zero-downtime.yml +50 -0
- package/templates/workflows/ci-pipeline.dot +15 -0
- package/templates/workflows/feature-flow.dot +21 -0
- package/templates/workflows/release.dot +16 -0
- package/dist/__integration__/helpers.d.ts +0 -20
- package/dist/__integration__/helpers.d.ts.map +0 -1
- package/dist/__integration__/helpers.js +0 -31
- package/dist/__integration__/helpers.js.map +0 -1
- package/dist/commands/analyze.d.ts.map +0 -1
- package/dist/commands/analyze.js.map +0 -1
- package/dist/commands/ci.d.ts.map +0 -1
- package/dist/commands/ci.js.map +0 -1
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/llmstxt.d.ts.map +0 -1
- package/dist/commands/llmstxt.js.map +0 -1
- package/dist/commands/plugin.d.ts.map +0 -1
- package/dist/commands/plugin.js.map +0 -1
- package/dist/commands/security.d.ts.map +0 -1
- package/dist/commands/security.js.map +0 -1
- package/dist/commands/skills.d.ts.map +0 -1
- package/dist/commands/skills.js.map +0 -1
- package/dist/commands/tdd.d.ts.map +0 -1
- package/dist/commands/tdd.js.map +0 -1
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/agent-skills.d.ts.map +0 -1
- package/dist/lib/agent-skills.js.map +0 -1
- package/dist/lib/claudemd.d.ts.map +0 -1
- package/dist/lib/claudemd.js.map +0 -1
- package/dist/lib/codex-export.d.ts.map +0 -1
- package/dist/lib/codex-export.js.map +0 -1
- package/dist/lib/common.d.ts.map +0 -1
- package/dist/lib/common.js.map +0 -1
- package/dist/lib/context.d.ts.map +0 -1
- package/dist/lib/context.js.map +0 -1
- package/dist/lib/docker.d.ts.map +0 -1
- package/dist/lib/docker.js.map +0 -1
- package/dist/lib/frontmatter.d.ts.map +0 -1
- package/dist/lib/frontmatter.js.map +0 -1
- package/dist/lib/plugin.d.ts.map +0 -1
- package/dist/lib/plugin.js.map +0 -1
- package/dist/lib/template.d.ts.map +0 -1
- package/dist/lib/template.js.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js.map +0 -1
- package/dist/ui/AnalyzeUI.d.ts.map +0 -1
- package/dist/ui/AnalyzeUI.js.map +0 -1
- package/dist/ui/App.d.ts.map +0 -1
- package/dist/ui/App.js.map +0 -1
- package/dist/ui/CI.d.ts.map +0 -1
- package/dist/ui/CI.js.map +0 -1
- package/dist/ui/CIContext.d.ts.map +0 -1
- package/dist/ui/CIContext.js.map +0 -1
- package/dist/ui/CISelector.d.ts.map +0 -1
- package/dist/ui/CISelector.js.map +0 -1
- package/dist/ui/Doctor.d.ts.map +0 -1
- package/dist/ui/Doctor.js.map +0 -1
- package/dist/ui/Header.d.ts.map +0 -1
- package/dist/ui/Header.js.map +0 -1
- package/dist/ui/LlmsTxt.d.ts.map +0 -1
- package/dist/ui/LlmsTxt.js.map +0 -1
- package/dist/ui/MemorySelector.d.ts.map +0 -1
- package/dist/ui/MemorySelector.js.map +0 -1
- package/dist/ui/NameInput.d.ts.map +0 -1
- package/dist/ui/NameInput.js.map +0 -1
- package/dist/ui/OptionSelector.d.ts.map +0 -1
- package/dist/ui/OptionSelector.js.map +0 -1
- package/dist/ui/Plugin.d.ts.map +0 -1
- package/dist/ui/Plugin.js.map +0 -1
- package/dist/ui/Progress.d.ts.map +0 -1
- package/dist/ui/Progress.js.map +0 -1
- package/dist/ui/Skills.d.ts.map +0 -1
- package/dist/ui/Skills.js.map +0 -1
- package/dist/ui/StackSelector.d.ts.map +0 -1
- package/dist/ui/StackSelector.js.map +0 -1
- package/dist/ui/Summary.d.ts.map +0 -1
- package/dist/ui/Summary.js.map +0 -1
- package/dist/ui/Welcome.d.ts.map +0 -1
- package/dist/ui/Welcome.js.map +0 -1
- package/dist/ui/theme.d.ts.map +0 -1
- package/dist/ui/theme.js.map +0 -1
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { DEFAULT_REGISTRY_THRESHOLD, DEFAULT_THRESHOLD } from "./constants.js";
|
|
2
|
+
import { estimateTokens, parseSkillFile } from "./parsing.js";
|
|
3
|
+
import { ACTION_VERBS, VAGUE_TERMS } from "./rules.js";
|
|
4
|
+
// ── Dangerous content patterns (private to scoreSafety) ─────────────────────
|
|
5
|
+
/** Dangerous patterns in skill content that indicate safety risks */
|
|
6
|
+
const DANGEROUS_PATTERNS = [
|
|
7
|
+
{ pattern: /\beval\s*\(/i, weight: 20 },
|
|
8
|
+
{ pattern: /\bexec\s*\(/i, weight: 15 },
|
|
9
|
+
{ pattern: /\bchild_process\b/i, weight: 10 },
|
|
10
|
+
{ pattern: /\brm\s+-rf\b/i, weight: 20 },
|
|
11
|
+
{ pattern: /\bcurl\b.*\|\s*(?:sh|bash)\b/i, weight: 25 },
|
|
12
|
+
{ pattern: /\bsudo\b/i, weight: 15 },
|
|
13
|
+
{ pattern: /\bchmod\s+777\b/i, weight: 15 },
|
|
14
|
+
{
|
|
15
|
+
pattern: /\b(?:password|secret|token|api_key)\s*[:=]\s*['"][^'"]+['"]/i,
|
|
16
|
+
weight: 25,
|
|
17
|
+
},
|
|
18
|
+
{ pattern: /\b__proto__\b|\bconstructor\s*\[/i, weight: 20 },
|
|
19
|
+
{ pattern: /\binnerHTML\s*=/i, weight: 10 },
|
|
20
|
+
{ pattern: /\bdangerouslySetInnerHTML\b/i, weight: 10 },
|
|
21
|
+
{
|
|
22
|
+
pattern: /\bno[- ]?verify\b.*\bgit\b|\bgit\b.*\bno[- ]?verify\b/i,
|
|
23
|
+
weight: 10,
|
|
24
|
+
},
|
|
25
|
+
{ pattern: /\bforce[- ]?push\b|\bpush\s+--force\b/i, weight: 10 },
|
|
26
|
+
{ pattern: /\bdisable.*(?:eslint|typescript|security)\b/i, weight: 10 },
|
|
27
|
+
];
|
|
28
|
+
// ── Dimension scorers ──────────────────────────────────────────────────────
|
|
29
|
+
/**
|
|
30
|
+
* Score completeness (0-100): frontmatter fields, critical rules, structure.
|
|
31
|
+
*/
|
|
32
|
+
export function scoreCompleteness(parsed) {
|
|
33
|
+
let score = 0;
|
|
34
|
+
// Has a name (10 pts)
|
|
35
|
+
if (parsed.name && parsed.name.length > 0)
|
|
36
|
+
score += 10;
|
|
37
|
+
// Has triggers / description with "Trigger:" (15 pts)
|
|
38
|
+
if (parsed.triggers.length > 0)
|
|
39
|
+
score += 15;
|
|
40
|
+
// Has critical rules section (20 pts)
|
|
41
|
+
if (parsed.rules.length > 0)
|
|
42
|
+
score += 20;
|
|
43
|
+
// Number of rules: 1-2 = 10, 3-5 = 20, 6+ = 25
|
|
44
|
+
if (parsed.rules.length >= 6)
|
|
45
|
+
score += 25;
|
|
46
|
+
else if (parsed.rules.length >= 3)
|
|
47
|
+
score += 20;
|
|
48
|
+
else if (parsed.rules.length >= 1)
|
|
49
|
+
score += 10;
|
|
50
|
+
// Has substantial content (>= 200 chars = 10, >= 500 = 20, >= 1000 = 30)
|
|
51
|
+
const len = parsed.rawContent.length;
|
|
52
|
+
if (len >= 1000)
|
|
53
|
+
score += 30;
|
|
54
|
+
else if (len >= 500)
|
|
55
|
+
score += 20;
|
|
56
|
+
else if (len >= 200)
|
|
57
|
+
score += 10;
|
|
58
|
+
return Math.min(score, 100);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Score clarity (0-100): description quality, rule actionability, no vague terms.
|
|
62
|
+
*/
|
|
63
|
+
export function scoreClarity(parsed) {
|
|
64
|
+
let score = 0;
|
|
65
|
+
// Trigger description exists and is meaningful (>= 50 chars in raw = 20 pts)
|
|
66
|
+
if (parsed.rawContent.length >= 50)
|
|
67
|
+
score += 20;
|
|
68
|
+
// Rules contain action verbs (up to 40 pts)
|
|
69
|
+
if (parsed.rules.length > 0) {
|
|
70
|
+
const actionableCount = parsed.rules.filter((rule) => ACTION_VERBS.some((verb) => verb.test(rule))).length;
|
|
71
|
+
const ratio = actionableCount / parsed.rules.length;
|
|
72
|
+
score += Math.round(ratio * 40);
|
|
73
|
+
}
|
|
74
|
+
// Penalty for vague terms in rules (-5 each, max -20)
|
|
75
|
+
let penalty = 0;
|
|
76
|
+
for (const rule of parsed.rules) {
|
|
77
|
+
for (const vague of VAGUE_TERMS) {
|
|
78
|
+
if (vague.test(rule)) {
|
|
79
|
+
penalty += 5;
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
score -= Math.min(penalty, 20);
|
|
85
|
+
// Name is descriptive (not single char) (10 pts)
|
|
86
|
+
if (parsed.name.length >= 3)
|
|
87
|
+
score += 10;
|
|
88
|
+
// Has multiple triggers (10 pts for >= 2, 20 for >= 3)
|
|
89
|
+
if (parsed.triggers.length >= 3)
|
|
90
|
+
score += 20;
|
|
91
|
+
else if (parsed.triggers.length >= 2)
|
|
92
|
+
score += 10;
|
|
93
|
+
// Base content score for having structured sections (10 pts)
|
|
94
|
+
if (/^#+\s/m.test(parsed.rawContent))
|
|
95
|
+
score += 10;
|
|
96
|
+
return Math.max(0, Math.min(score, 100));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Score testability (0-100): Given/When/Then scenarios, specific rules.
|
|
100
|
+
*/
|
|
101
|
+
export function scoreTestability(parsed) {
|
|
102
|
+
let score = 0;
|
|
103
|
+
// Has Given/When/Then scenarios (40 pts)
|
|
104
|
+
const gwtMatches = parsed.rawContent.match(/\bGIVEN\b.*\bWHEN\b.*\bTHEN\b/gis);
|
|
105
|
+
const gwtCount = gwtMatches?.length ?? 0;
|
|
106
|
+
if (gwtCount >= 3)
|
|
107
|
+
score += 40;
|
|
108
|
+
else if (gwtCount >= 1)
|
|
109
|
+
score += 25;
|
|
110
|
+
// Rules are specific enough (contain file paths, code refs, or patterns)
|
|
111
|
+
const specificRules = parsed.rules.filter((rule) => /[`'"]/.test(rule) ||
|
|
112
|
+
/\.\w+/.test(rule) ||
|
|
113
|
+
/\bfile\b/i.test(rule) ||
|
|
114
|
+
/\bpath\b/i.test(rule)).length;
|
|
115
|
+
if (parsed.rules.length > 0) {
|
|
116
|
+
const specificity = specificRules / parsed.rules.length;
|
|
117
|
+
score += Math.round(specificity * 30);
|
|
118
|
+
}
|
|
119
|
+
// Has examples or code blocks (20 pts)
|
|
120
|
+
const codeBlocks = (parsed.rawContent.match(/```/g) ?? []).length / 2;
|
|
121
|
+
if (codeBlocks >= 2)
|
|
122
|
+
score += 20;
|
|
123
|
+
else if (codeBlocks >= 1)
|
|
124
|
+
score += 10;
|
|
125
|
+
// Has a "Testing" or "Test" section (10 pts)
|
|
126
|
+
if (/^#+\s.*test/im.test(parsed.rawContent))
|
|
127
|
+
score += 10;
|
|
128
|
+
return Math.min(score, 100);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Score token efficiency (0-100): information density (rules per 1000 tokens).
|
|
132
|
+
*/
|
|
133
|
+
export function scoreTokenEfficiency(parsed) {
|
|
134
|
+
const tokens = estimateTokens(parsed.rawContent);
|
|
135
|
+
if (tokens === 0)
|
|
136
|
+
return 0;
|
|
137
|
+
// Rules per 1000 tokens — higher is more efficient
|
|
138
|
+
const rulesPerKToken = (parsed.rules.length / tokens) * 1000;
|
|
139
|
+
// Ideal: 3-8 rules per 1000 tokens
|
|
140
|
+
// < 1 = bloated, > 10 = maybe too terse
|
|
141
|
+
let score;
|
|
142
|
+
if (rulesPerKToken >= 3 && rulesPerKToken <= 8) {
|
|
143
|
+
score = 100;
|
|
144
|
+
}
|
|
145
|
+
else if (rulesPerKToken >= 2) {
|
|
146
|
+
score = 80;
|
|
147
|
+
}
|
|
148
|
+
else if (rulesPerKToken >= 1) {
|
|
149
|
+
score = 60;
|
|
150
|
+
}
|
|
151
|
+
else if (rulesPerKToken > 0) {
|
|
152
|
+
score = 40;
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
score = 10;
|
|
156
|
+
}
|
|
157
|
+
// Bonus for small total size (under 2000 tokens = +0, under 1000 = already great)
|
|
158
|
+
// Penalty for huge skills (> 5000 tokens = -20)
|
|
159
|
+
if (tokens > 5000)
|
|
160
|
+
score -= 20;
|
|
161
|
+
else if (tokens > 3000)
|
|
162
|
+
score -= 10;
|
|
163
|
+
return Math.max(0, Math.min(score, 100));
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Score safety (0-100): absence of dangerous patterns, injection risks, credential leaks.
|
|
167
|
+
* Starts at 100 and deducts for each dangerous pattern found.
|
|
168
|
+
*/
|
|
169
|
+
export function scoreSafety(parsed) {
|
|
170
|
+
let score = 100;
|
|
171
|
+
for (const { pattern, weight } of DANGEROUS_PATTERNS) {
|
|
172
|
+
if (pattern.test(parsed.rawContent)) {
|
|
173
|
+
score -= weight;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Bonus: skill explicitly mentions security best practices (+10, capped at 100)
|
|
177
|
+
if (/\bsanitiz/i.test(parsed.rawContent) ||
|
|
178
|
+
/\bescap/i.test(parsed.rawContent)) {
|
|
179
|
+
score += 10;
|
|
180
|
+
}
|
|
181
|
+
if (/\bvalidat/i.test(parsed.rawContent)) {
|
|
182
|
+
score += 5;
|
|
183
|
+
}
|
|
184
|
+
return Math.max(0, Math.min(score, 100));
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Score agent readiness (0-100): how well-prepared a skill is for AI agent consumption.
|
|
188
|
+
* Checks for triggers, tool restrictions, examples, structured output, and error handling.
|
|
189
|
+
*/
|
|
190
|
+
export function scoreAgentReadiness(parsed) {
|
|
191
|
+
let score = 0;
|
|
192
|
+
// Has triggers for auto-activation (25 pts)
|
|
193
|
+
if (parsed.triggers.length >= 3)
|
|
194
|
+
score += 25;
|
|
195
|
+
else if (parsed.triggers.length >= 1)
|
|
196
|
+
score += 15;
|
|
197
|
+
// Has tool restrictions or permissions (e.g., "only use", "do not use", "allowed tools") (20 pts)
|
|
198
|
+
if (/\b(?:only use|allowed tools?|restricted to|do not use|forbidden|prohibited)\b/i.test(parsed.rawContent)) {
|
|
199
|
+
score += 20;
|
|
200
|
+
}
|
|
201
|
+
// Has examples with expected input/output or code blocks (20 pts)
|
|
202
|
+
const codeBlocks = (parsed.rawContent.match(/```/g) ?? []).length / 2;
|
|
203
|
+
if (codeBlocks >= 3)
|
|
204
|
+
score += 20;
|
|
205
|
+
else if (codeBlocks >= 1)
|
|
206
|
+
score += 10;
|
|
207
|
+
// Has structured output format (JSON, YAML, or explicit format section) (15 pts)
|
|
208
|
+
if (/\boutput format\b/i.test(parsed.rawContent) ||
|
|
209
|
+
/\breturn.*(?:json|yaml|structured)\b/i.test(parsed.rawContent)) {
|
|
210
|
+
score += 15;
|
|
211
|
+
}
|
|
212
|
+
else if (/```(?:json|yaml)/i.test(parsed.rawContent)) {
|
|
213
|
+
score += 10;
|
|
214
|
+
}
|
|
215
|
+
// Has error handling guidance ("if error", "when fails", "fallback") (10 pts)
|
|
216
|
+
if (/\b(?:if.*(?:error|fail)|fallback|edge case|error handling)\b/i.test(parsed.rawContent)) {
|
|
217
|
+
score += 10;
|
|
218
|
+
}
|
|
219
|
+
// Has a clear "when NOT to use" or scope boundary (10 pts)
|
|
220
|
+
if (/\b(?:do not trigger|not applicable|out of scope|when not to)\b/i.test(parsed.rawContent)) {
|
|
221
|
+
score += 10;
|
|
222
|
+
}
|
|
223
|
+
return Math.min(score, 100);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Convert numeric score to letter grade.
|
|
227
|
+
*/
|
|
228
|
+
export function computeGrade(overall) {
|
|
229
|
+
if (overall >= 90)
|
|
230
|
+
return "A";
|
|
231
|
+
if (overall >= 80)
|
|
232
|
+
return "B";
|
|
233
|
+
if (overall >= 70)
|
|
234
|
+
return "C";
|
|
235
|
+
if (overall >= 60)
|
|
236
|
+
return "D";
|
|
237
|
+
return "F";
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Score a skill on all 6 dimensions and compute overall with letter grade.
|
|
241
|
+
*/
|
|
242
|
+
export async function scoreSkill(skillPath, threshold = DEFAULT_THRESHOLD) {
|
|
243
|
+
const parsed = await parseSkillFile(skillPath);
|
|
244
|
+
if (!parsed)
|
|
245
|
+
return null;
|
|
246
|
+
const completeness = scoreCompleteness(parsed);
|
|
247
|
+
const clarity = scoreClarity(parsed);
|
|
248
|
+
const testability = scoreTestability(parsed);
|
|
249
|
+
const tokenEfficiency = scoreTokenEfficiency(parsed);
|
|
250
|
+
const safety = scoreSafety(parsed);
|
|
251
|
+
const agentReadiness = scoreAgentReadiness(parsed);
|
|
252
|
+
// Weighted average: completeness 20%, clarity 20%, testability 15%,
|
|
253
|
+
// token-efficiency 15%, safety 15%, agent-readiness 15%
|
|
254
|
+
const overall = Math.round(completeness * 0.2 +
|
|
255
|
+
clarity * 0.2 +
|
|
256
|
+
testability * 0.15 +
|
|
257
|
+
tokenEfficiency * 0.15 +
|
|
258
|
+
safety * 0.15 +
|
|
259
|
+
agentReadiness * 0.15);
|
|
260
|
+
const grade = computeGrade(overall);
|
|
261
|
+
return {
|
|
262
|
+
skillName: parsed.name,
|
|
263
|
+
completeness,
|
|
264
|
+
clarity,
|
|
265
|
+
testability,
|
|
266
|
+
tokenEfficiency,
|
|
267
|
+
safety,
|
|
268
|
+
agentReadiness,
|
|
269
|
+
overall,
|
|
270
|
+
grade,
|
|
271
|
+
threshold,
|
|
272
|
+
passing: overall >= threshold,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Gate check for registry inclusion. Rejects skills below the configured threshold.
|
|
277
|
+
*/
|
|
278
|
+
export async function registryGate(skillPath, threshold = DEFAULT_REGISTRY_THRESHOLD) {
|
|
279
|
+
const score = await scoreSkill(skillPath, threshold);
|
|
280
|
+
if (!score)
|
|
281
|
+
return null;
|
|
282
|
+
const accepted = score.passing;
|
|
283
|
+
let reason;
|
|
284
|
+
if (!accepted) {
|
|
285
|
+
const failures = [];
|
|
286
|
+
if (score.safety < 60)
|
|
287
|
+
failures.push(`safety=${score.safety}`);
|
|
288
|
+
if (score.completeness < 40)
|
|
289
|
+
failures.push(`completeness=${score.completeness}`);
|
|
290
|
+
if (score.clarity < 40)
|
|
291
|
+
failures.push(`clarity=${score.clarity}`);
|
|
292
|
+
if (score.agentReadiness < 30)
|
|
293
|
+
failures.push(`agent-readiness=${score.agentReadiness}`);
|
|
294
|
+
reason =
|
|
295
|
+
failures.length > 0
|
|
296
|
+
? `Rejected (${score.grade}, ${score.overall}/100): weak dimensions — ${failures.join(", ")}`
|
|
297
|
+
: `Rejected (${score.grade}, ${score.overall}/100): below threshold ${threshold}`;
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
skillName: score.skillName,
|
|
301
|
+
score,
|
|
302
|
+
accepted,
|
|
303
|
+
reason,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=scoring.js.map
|
|
@@ -1,28 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
triggers: string[];
|
|
10
|
-
} | null>;
|
|
11
|
-
/** Extract critical rules from markdown content */
|
|
12
|
-
export declare function extractCriticalRules(content: string): string[];
|
|
13
|
-
/** Extract trigger keywords from a skill description */
|
|
14
|
-
export declare function extractTriggers(description: string): string[];
|
|
15
|
-
/** Discover all SKILL.md files in a skills directory */
|
|
16
|
-
export declare function discoverSkills(skillsDir: string): Promise<string[]>;
|
|
17
|
-
/** Check if two rules contradict each other */
|
|
18
|
-
export declare function detectRuleConflict(ruleA: string, ruleB: string): string | null;
|
|
19
|
-
/** Scan all skills for conflicting critical rules */
|
|
20
|
-
export declare function findConflicts(skillsDir: string): Promise<SkillConflict[]>;
|
|
21
|
-
/** Calculate token budget for all installed skills */
|
|
22
|
-
export declare function calculateBudget(skillsDir: string, budget?: number): Promise<SkillBudgetResult>;
|
|
23
|
-
/** Find skills that overlap in scope/triggers */
|
|
24
|
-
export declare function findDuplicates(skillsDir: string): Promise<SkillDuplicate[]>;
|
|
25
|
-
export type SkillsDoctorMode = 'doctor' | 'budget';
|
|
1
|
+
import type { SkillDoctorResult } from "../types/index.js";
|
|
2
|
+
export { calculateBudget, detectRuleConflict, findConflicts, findDuplicates, generateBudgetOptimizations, } from "./skills/analysis.js";
|
|
3
|
+
export { benchmarkSkill } from "./skills/benchmark.js";
|
|
4
|
+
export type { RuleDirective } from "./skills/directives.js";
|
|
5
|
+
export { detectDirectiveClash, extractDirective, subjectsSimilar, } from "./skills/directives.js";
|
|
6
|
+
export { discoverSkills, estimateTokens, extractCriticalRules, extractTriggers, parseSkillFile, } from "./skills/parsing.js";
|
|
7
|
+
export { computeGrade, registryGate, scoreAgentReadiness, scoreClarity, scoreCompleteness, scoreSafety, scoreSkill, scoreTestability, scoreTokenEfficiency, } from "./skills/scoring.js";
|
|
8
|
+
export type SkillsDoctorMode = "doctor" | "budget";
|
|
26
9
|
export interface SkillsDoctorOptions {
|
|
27
10
|
mode: SkillsDoctorMode;
|
|
28
11
|
skillsDir?: string;
|
|
@@ -35,48 +18,4 @@ export interface SkillsDoctorOptions {
|
|
|
35
18
|
* - `budget -b N`: budget-only analysis with custom token limit
|
|
36
19
|
*/
|
|
37
20
|
export declare function runSkillsDoctor(options: SkillsDoctorOptions): Promise<SkillDoctorResult>;
|
|
38
|
-
/**
|
|
39
|
-
* Score completeness (0-100): frontmatter fields, critical rules, structure.
|
|
40
|
-
*/
|
|
41
|
-
export declare function scoreCompleteness(parsed: {
|
|
42
|
-
name: string;
|
|
43
|
-
rules: string[];
|
|
44
|
-
rawContent: string;
|
|
45
|
-
triggers: string[];
|
|
46
|
-
}): number;
|
|
47
|
-
/**
|
|
48
|
-
* Score clarity (0-100): description quality, rule actionability, no vague terms.
|
|
49
|
-
*/
|
|
50
|
-
export declare function scoreClarity(parsed: {
|
|
51
|
-
name: string;
|
|
52
|
-
rules: string[];
|
|
53
|
-
rawContent: string;
|
|
54
|
-
triggers: string[];
|
|
55
|
-
}): number;
|
|
56
|
-
/**
|
|
57
|
-
* Score testability (0-100): Given/When/Then scenarios, specific rules.
|
|
58
|
-
*/
|
|
59
|
-
export declare function scoreTestability(parsed: {
|
|
60
|
-
name: string;
|
|
61
|
-
rules: string[];
|
|
62
|
-
rawContent: string;
|
|
63
|
-
triggers: string[];
|
|
64
|
-
}): number;
|
|
65
|
-
/**
|
|
66
|
-
* Score token efficiency (0-100): information density (rules per 1000 tokens).
|
|
67
|
-
*/
|
|
68
|
-
export declare function scoreTokenEfficiency(parsed: {
|
|
69
|
-
name: string;
|
|
70
|
-
rules: string[];
|
|
71
|
-
rawContent: string;
|
|
72
|
-
triggers: string[];
|
|
73
|
-
}): number;
|
|
74
|
-
/**
|
|
75
|
-
* Score a skill on all 4 dimensions and compute overall.
|
|
76
|
-
*/
|
|
77
|
-
export declare function scoreSkill(skillPath: string, threshold?: number): Promise<SkillScore | null>;
|
|
78
|
-
/**
|
|
79
|
-
* Run structural quality benchmark checks against a skill.
|
|
80
|
-
*/
|
|
81
|
-
export declare function benchmarkSkill(skillPath: string): Promise<SkillBenchmarkResult | null>;
|
|
82
21
|
//# sourceMappingURL=skills.d.ts.map
|