shieldcortex 2.4.23 → 2.4.25
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/dashboard/.next/standalone/dashboard/.next/BUILD_ID +1 -1
- package/dashboard/.next/standalone/dashboard/.next/build-manifest.json +2 -2
- package/dashboard/.next/standalone/dashboard/.next/prerender-manifest.json +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/page/react-loadable-manifest.json +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/chunks/ssr/dashboard_25b1b286._.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.json +1 -1
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/{0327af3bf4830eac.js → 0ba8a0e679bf5c40.js} +1 -1
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/17348ec48b354115.css +3 -0
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/{21c4fc7176fbe8ee.js → caa049bd46f24dd8.js} +1 -1
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/{511275d9224bafb2.js → cb7d5bff58e77e2c.js} +1 -1
- package/dist/api/visualization-server.d.ts.map +1 -1
- package/dist/api/visualization-server.js +54 -0
- package/dist/api/visualization-server.js.map +1 -1
- package/dist/cloud/sync.d.ts.map +1 -1
- package/dist/cloud/sync.js +7 -3
- package/dist/cloud/sync.js.map +1 -1
- package/dist/defence/index.d.ts +2 -0
- package/dist/defence/index.d.ts.map +1 -1
- package/dist/defence/index.js +2 -0
- package/dist/defence/index.js.map +1 -1
- package/dist/defence/skill-scanner/__tests__/skill-scanner.test.d.ts +12 -0
- package/dist/defence/skill-scanner/__tests__/skill-scanner.test.d.ts.map +1 -0
- package/dist/defence/skill-scanner/__tests__/skill-scanner.test.js +471 -0
- package/dist/defence/skill-scanner/__tests__/skill-scanner.test.js.map +1 -0
- package/dist/defence/skill-scanner/discover.d.ts +16 -0
- package/dist/defence/skill-scanner/discover.d.ts.map +1 -0
- package/dist/defence/skill-scanner/discover.js +83 -0
- package/dist/defence/skill-scanner/discover.js.map +1 -0
- package/dist/defence/skill-scanner/index.d.ts +20 -0
- package/dist/defence/skill-scanner/index.d.ts.map +1 -0
- package/dist/defence/skill-scanner/index.js +17 -0
- package/dist/defence/skill-scanner/index.js.map +1 -0
- package/dist/defence/skill-scanner/parser.d.ts +45 -0
- package/dist/defence/skill-scanner/parser.d.ts.map +1 -0
- package/dist/defence/skill-scanner/parser.js +373 -0
- package/dist/defence/skill-scanner/parser.js.map +1 -0
- package/dist/defence/skill-scanner/patterns.d.ts +37 -0
- package/dist/defence/skill-scanner/patterns.d.ts.map +1 -0
- package/dist/defence/skill-scanner/patterns.js +240 -0
- package/dist/defence/skill-scanner/patterns.js.map +1 -0
- package/dist/defence/skill-scanner/scan-skill.d.ts +75 -0
- package/dist/defence/skill-scanner/scan-skill.d.ts.map +1 -0
- package/dist/defence/skill-scanner/scan-skill.js +397 -0
- package/dist/defence/skill-scanner/scan-skill.js.map +1 -0
- package/dist/embeddings/generator.d.ts +5 -0
- package/dist/embeddings/generator.d.ts.map +1 -1
- package/dist/embeddings/generator.js +35 -5
- package/dist/embeddings/generator.js.map +1 -1
- package/dist/embeddings/index.d.ts +1 -1
- package/dist/embeddings/index.d.ts.map +1 -1
- package/dist/embeddings/index.js +1 -1
- package/dist/embeddings/index.js.map +1 -1
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -1
- package/dist/memory/contradiction.d.ts.map +1 -1
- package/dist/memory/contradiction.js +8 -2
- package/dist/memory/contradiction.js.map +1 -1
- package/dist/memory/store.d.ts.map +1 -1
- package/dist/memory/store.js +27 -0
- package/dist/memory/store.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +35 -0
- package/dist/server.js.map +1 -1
- package/hooks/openclaw/cortex-memory/handler.js +75 -0
- package/package.json +1 -1
- package/scripts/session-start-hook.mjs +67 -1
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/8e559e67e3d8782b.css +0 -3
- /package/dashboard/.next/standalone/dashboard/.next/static/{Ykr04kZxo_ae93TlaBU55 → Q-r-I8nnIGuzwhmNwk-sv}/_buildManifest.js +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{Ykr04kZxo_ae93TlaBU55 → Q-r-I8nnIGuzwhmNwk-sv}/_clientMiddlewareManifest.json +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{Ykr04kZxo_ae93TlaBU55 → Q-r-I8nnIGuzwhmNwk-sv}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Scanner
|
|
3
|
+
*
|
|
4
|
+
* Framework-agnostic scanner for AI agent instruction files.
|
|
5
|
+
* Detects prompt injection, data exfiltration, tool abuse, and other
|
|
6
|
+
* threats hidden in skill definitions, hook files, and agent rules.
|
|
7
|
+
*
|
|
8
|
+
* Supports: Claude Code (SKILL.md, CLAUDE.md), OpenClaw (HOOK.md, handler.js),
|
|
9
|
+
* Cursor (.cursorrules), Windsurf (.windsurfrules), Cline (.clinerules),
|
|
10
|
+
* GitHub Copilot (copilot-instructions.md), Aider (.aider.conf.yml),
|
|
11
|
+
* Continue (.continue/config.json).
|
|
12
|
+
*/
|
|
13
|
+
export { scanSkill, scanSkillContent } from './scan-skill.js';
|
|
14
|
+
export { detectSkillThreats, detectCodeThreats } from './patterns.js';
|
|
15
|
+
export { parseSkillFile, readSkillFile, detectFormat } from './parser.js';
|
|
16
|
+
export { discoverSkillFiles } from './discover.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/defence/skill-scanner/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAO9D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGtE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill File Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses agent instruction files from 8 different AI frameworks into a common
|
|
5
|
+
* format for scanning. Supports SKILL.md, HOOK.md, handler.js, .cursorrules,
|
|
6
|
+
* .windsurfrules, .clinerules, CLAUDE.md, copilot-instructions.md,
|
|
7
|
+
* .aider.conf.yml, and .continue/config.json.
|
|
8
|
+
*
|
|
9
|
+
* The parser never throws — malformed input produces sensible defaults.
|
|
10
|
+
*/
|
|
11
|
+
export type SkillFormat = 'skill-md' | 'hook-md' | 'hook-js' | 'rules' | 'claude-md' | 'copilot-md' | 'aider-yml' | 'continue-json' | 'unknown';
|
|
12
|
+
export interface ParsedSkill {
|
|
13
|
+
/** Extracted from metadata or filename */
|
|
14
|
+
name: string;
|
|
15
|
+
/** Auto-detected format */
|
|
16
|
+
format: SkillFormat;
|
|
17
|
+
/** The text content to scan (body only, no frontmatter) */
|
|
18
|
+
content: string;
|
|
19
|
+
/** YAML/JSON frontmatter if present */
|
|
20
|
+
metadata?: Record<string, unknown>;
|
|
21
|
+
/** Original file contents */
|
|
22
|
+
raw: string;
|
|
23
|
+
/** Source path if read from disc */
|
|
24
|
+
filePath?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Auto-detect the skill format based on the file path.
|
|
28
|
+
* Uses basename for filename matching; case-insensitive for .md files.
|
|
29
|
+
*/
|
|
30
|
+
export declare function detectFormat(filePath: string): SkillFormat;
|
|
31
|
+
/**
|
|
32
|
+
* Parse file content into a ParsedSkill structure.
|
|
33
|
+
*
|
|
34
|
+
* @param content Raw file content
|
|
35
|
+
* @param format Detected format (defaults to 'unknown')
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseSkillFile(content: string, format?: SkillFormat): ParsedSkill;
|
|
38
|
+
/**
|
|
39
|
+
* Read a skill file from disc, auto-detect its format, and parse it.
|
|
40
|
+
*
|
|
41
|
+
* Returns a ParsedSkill with the filePath field populated.
|
|
42
|
+
* If the file cannot be read, returns a minimal ParsedSkill with empty content.
|
|
43
|
+
*/
|
|
44
|
+
export declare function readSkillFile(filePath: string): ParsedSkill;
|
|
45
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/defence/skill-scanner/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,MAAM,MAAM,WAAW,GACnB,UAAU,GACV,SAAS,GACT,SAAS,GACT,OAAO,GACP,WAAW,GACX,YAAY,GACZ,WAAW,GACX,eAAe,GACf,SAAS,CAAC;AAEd,MAAM,WAAW,WAAW;IAC1B,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,6BAA6B;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAID;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CA2B1D;AA6KD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,CAqDjF;AA4HD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CA2B3D"}
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill File Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses agent instruction files from 8 different AI frameworks into a common
|
|
5
|
+
* format for scanning. Supports SKILL.md, HOOK.md, handler.js, .cursorrules,
|
|
6
|
+
* .windsurfrules, .clinerules, CLAUDE.md, copilot-instructions.md,
|
|
7
|
+
* .aider.conf.yml, and .continue/config.json.
|
|
8
|
+
*
|
|
9
|
+
* The parser never throws — malformed input produces sensible defaults.
|
|
10
|
+
*/
|
|
11
|
+
import * as fs from 'node:fs';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
// ── Format Detection ──
|
|
14
|
+
/**
|
|
15
|
+
* Auto-detect the skill format based on the file path.
|
|
16
|
+
* Uses basename for filename matching; case-insensitive for .md files.
|
|
17
|
+
*/
|
|
18
|
+
export function detectFormat(filePath) {
|
|
19
|
+
const basename = path.basename(filePath);
|
|
20
|
+
const lower = basename.toLowerCase();
|
|
21
|
+
// Exact filename matches (case-insensitive for .md)
|
|
22
|
+
if (lower === 'skill.md')
|
|
23
|
+
return 'skill-md';
|
|
24
|
+
if (lower === 'hook.md')
|
|
25
|
+
return 'hook-md';
|
|
26
|
+
if (basename === 'handler.js')
|
|
27
|
+
return 'hook-js';
|
|
28
|
+
if (lower === 'claude.md')
|
|
29
|
+
return 'claude-md';
|
|
30
|
+
if (lower === 'copilot-instructions.md')
|
|
31
|
+
return 'copilot-md';
|
|
32
|
+
if (basename === '.aider.conf.yml')
|
|
33
|
+
return 'aider-yml';
|
|
34
|
+
// Rules files (exact basename match, case-sensitive — these are dotfiles)
|
|
35
|
+
if (basename === '.cursorrules' || basename === '.windsurfrules' || basename === '.clinerules') {
|
|
36
|
+
return 'rules';
|
|
37
|
+
}
|
|
38
|
+
// Path-based matches
|
|
39
|
+
const normalised = filePath.replace(/\\/g, '/');
|
|
40
|
+
if (normalised.includes('.claude/commands/'))
|
|
41
|
+
return 'claude-md';
|
|
42
|
+
if (basename === 'config.json' && normalised.includes('.continue/')) {
|
|
43
|
+
return 'continue-json';
|
|
44
|
+
}
|
|
45
|
+
return 'unknown';
|
|
46
|
+
}
|
|
47
|
+
// ── Simple YAML Parser ──
|
|
48
|
+
/**
|
|
49
|
+
* Parse simple YAML key-value pairs, supporting one level of nesting.
|
|
50
|
+
*
|
|
51
|
+
* This does NOT handle the full YAML specification — only the straightforward
|
|
52
|
+
* frontmatter structures used by skill and hook files:
|
|
53
|
+
* key: value
|
|
54
|
+
* key: "quoted value"
|
|
55
|
+
* parent:
|
|
56
|
+
* child: value
|
|
57
|
+
*/
|
|
58
|
+
function parseSimpleYaml(yamlText) {
|
|
59
|
+
const result = {};
|
|
60
|
+
const lines = yamlText.split('\n');
|
|
61
|
+
let currentParent = null;
|
|
62
|
+
let nestedObj = null;
|
|
63
|
+
for (const line of lines) {
|
|
64
|
+
// Skip empty lines and comments
|
|
65
|
+
const trimmed = line.trimEnd();
|
|
66
|
+
if (trimmed === '' || trimmed.startsWith('#')) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
// Determine indentation level
|
|
70
|
+
const indent = line.length - line.trimStart().length;
|
|
71
|
+
const content = trimmed.trim();
|
|
72
|
+
// Match key: value pattern
|
|
73
|
+
const kvMatch = content.match(/^([A-Za-z_][\w.-]*)\s*:\s*(.*)/);
|
|
74
|
+
if (!kvMatch)
|
|
75
|
+
continue;
|
|
76
|
+
const key = kvMatch[1];
|
|
77
|
+
let value = kvMatch[2].trim();
|
|
78
|
+
if (indent >= 2 && currentParent && nestedObj) {
|
|
79
|
+
// This is a nested key under the current parent
|
|
80
|
+
nestedObj[key] = unquoteValue(value);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Top-level key — flush any previous nested object
|
|
84
|
+
if (currentParent && nestedObj) {
|
|
85
|
+
result[currentParent] = nestedObj;
|
|
86
|
+
currentParent = null;
|
|
87
|
+
nestedObj = null;
|
|
88
|
+
}
|
|
89
|
+
if (value === '' || value === '') {
|
|
90
|
+
// This key has no inline value — it introduces a nested block
|
|
91
|
+
currentParent = key;
|
|
92
|
+
nestedObj = {};
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
result[key] = unquoteValue(value);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Flush trailing nested object
|
|
100
|
+
if (currentParent && nestedObj) {
|
|
101
|
+
result[currentParent] = nestedObj;
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Remove surrounding quotes from a YAML value string and coerce simple types.
|
|
107
|
+
*/
|
|
108
|
+
function unquoteValue(raw) {
|
|
109
|
+
if (raw === '')
|
|
110
|
+
return '';
|
|
111
|
+
// Remove surrounding quotes (single or double)
|
|
112
|
+
if ((raw.startsWith('"') && raw.endsWith('"')) ||
|
|
113
|
+
(raw.startsWith("'") && raw.endsWith("'"))) {
|
|
114
|
+
return raw.slice(1, -1);
|
|
115
|
+
}
|
|
116
|
+
// Boolean coercion
|
|
117
|
+
if (raw === 'true')
|
|
118
|
+
return true;
|
|
119
|
+
if (raw === 'false')
|
|
120
|
+
return false;
|
|
121
|
+
// Numeric coercion
|
|
122
|
+
if (/^-?\d+(\.\d+)?$/.test(raw)) {
|
|
123
|
+
return Number(raw);
|
|
124
|
+
}
|
|
125
|
+
return raw;
|
|
126
|
+
}
|
|
127
|
+
// ── Frontmatter Extraction ──
|
|
128
|
+
/**
|
|
129
|
+
* Split YAML frontmatter (between --- markers at the start of a file)
|
|
130
|
+
* from the markdown body. Returns [frontmatter, body].
|
|
131
|
+
*/
|
|
132
|
+
function splitFrontmatter(content) {
|
|
133
|
+
// Frontmatter must start at the very beginning of the file
|
|
134
|
+
if (!content.startsWith('---')) {
|
|
135
|
+
return [null, content];
|
|
136
|
+
}
|
|
137
|
+
// Find the closing --- marker (must be on its own line)
|
|
138
|
+
const closingIndex = content.indexOf('\n---', 3);
|
|
139
|
+
if (closingIndex === -1) {
|
|
140
|
+
// No closing marker — treat the entire file as body
|
|
141
|
+
return [null, content];
|
|
142
|
+
}
|
|
143
|
+
const frontmatter = content.slice(3, closingIndex).trim();
|
|
144
|
+
const body = content.slice(closingIndex + 4).trim();
|
|
145
|
+
return [frontmatter, body];
|
|
146
|
+
}
|
|
147
|
+
// ── Name Extraction Helpers ──
|
|
148
|
+
/**
|
|
149
|
+
* Try to extract a name from the first line comment in a JS file,
|
|
150
|
+
* For example: "// my-hook" or block comments like "Hook Name".
|
|
151
|
+
*/
|
|
152
|
+
function extractJsName(source) {
|
|
153
|
+
const firstLine = source.split('\n')[0]?.trim() ?? '';
|
|
154
|
+
// Single-line comment: // name
|
|
155
|
+
const singleComment = firstLine.match(/^\/\/\s*(.+)/);
|
|
156
|
+
if (singleComment) {
|
|
157
|
+
return singleComment[1].trim();
|
|
158
|
+
}
|
|
159
|
+
// Block comment: /* name */
|
|
160
|
+
const blockComment = firstLine.match(/^\/\*\s*(.+?)\s*\*\//);
|
|
161
|
+
if (blockComment) {
|
|
162
|
+
return blockComment[1].trim();
|
|
163
|
+
}
|
|
164
|
+
// module.exports name — look for module.exports.name = "..."
|
|
165
|
+
const exportsName = source.match(/module\.exports\.name\s*=\s*["']([^"']+)["']/);
|
|
166
|
+
if (exportsName) {
|
|
167
|
+
return exportsName[1];
|
|
168
|
+
}
|
|
169
|
+
// module.exports = { name: "..." }
|
|
170
|
+
const objName = source.match(/module\.exports\s*=\s*\{[^}]*name\s*:\s*["']([^"']+)["']/);
|
|
171
|
+
if (objName) {
|
|
172
|
+
return objName[1];
|
|
173
|
+
}
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Derive a name from a filename, stripping the extension and leading dot.
|
|
178
|
+
*/
|
|
179
|
+
function nameFromFilename(filename) {
|
|
180
|
+
const basename = path.basename(filename);
|
|
181
|
+
const ext = path.extname(basename);
|
|
182
|
+
let name = ext ? basename.slice(0, -ext.length) : basename;
|
|
183
|
+
// Strip leading dot for dotfiles (e.g. .cursorrules -> cursorrules)
|
|
184
|
+
if (name.startsWith('.')) {
|
|
185
|
+
name = name.slice(1);
|
|
186
|
+
}
|
|
187
|
+
return name || 'unknown';
|
|
188
|
+
}
|
|
189
|
+
// ── Core Parser ──
|
|
190
|
+
/**
|
|
191
|
+
* Parse file content into a ParsedSkill structure.
|
|
192
|
+
*
|
|
193
|
+
* @param content Raw file content
|
|
194
|
+
* @param format Detected format (defaults to 'unknown')
|
|
195
|
+
*/
|
|
196
|
+
export function parseSkillFile(content, format) {
|
|
197
|
+
const effectiveFormat = format ?? 'unknown';
|
|
198
|
+
const raw = content;
|
|
199
|
+
// Guard against empty or binary-looking content
|
|
200
|
+
if (!content || content.length === 0) {
|
|
201
|
+
return {
|
|
202
|
+
name: 'unknown',
|
|
203
|
+
format: effectiveFormat,
|
|
204
|
+
content: '',
|
|
205
|
+
raw,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
// Detect likely binary content (high ratio of non-printable characters)
|
|
209
|
+
const nonPrintable = content.slice(0, 1024).replace(/[\x20-\x7E\t\n\r]/g, '').length;
|
|
210
|
+
if (nonPrintable > 128) {
|
|
211
|
+
return {
|
|
212
|
+
name: 'unknown',
|
|
213
|
+
format: effectiveFormat,
|
|
214
|
+
content: '',
|
|
215
|
+
raw,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
switch (effectiveFormat) {
|
|
219
|
+
case 'skill-md':
|
|
220
|
+
case 'hook-md':
|
|
221
|
+
return parseMarkdownWithFrontmatter(content, effectiveFormat, raw);
|
|
222
|
+
case 'rules':
|
|
223
|
+
case 'claude-md':
|
|
224
|
+
case 'copilot-md':
|
|
225
|
+
return parseRawContent(content, effectiveFormat, raw);
|
|
226
|
+
case 'hook-js':
|
|
227
|
+
return parseJavaScript(content, raw);
|
|
228
|
+
case 'aider-yml':
|
|
229
|
+
return parseAiderYaml(content, raw);
|
|
230
|
+
case 'continue-json':
|
|
231
|
+
return parseContinueJson(content, raw);
|
|
232
|
+
case 'unknown':
|
|
233
|
+
default:
|
|
234
|
+
return {
|
|
235
|
+
name: 'unknown',
|
|
236
|
+
format: 'unknown',
|
|
237
|
+
content,
|
|
238
|
+
raw,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Parse a markdown file that may contain YAML frontmatter (skill-md, hook-md).
|
|
244
|
+
*/
|
|
245
|
+
function parseMarkdownWithFrontmatter(content, format, raw) {
|
|
246
|
+
const [frontmatter, body] = splitFrontmatter(content);
|
|
247
|
+
let metadata;
|
|
248
|
+
let name = 'unknown';
|
|
249
|
+
if (frontmatter) {
|
|
250
|
+
try {
|
|
251
|
+
metadata = parseSimpleYaml(frontmatter);
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
// Malformed YAML — continue without metadata
|
|
255
|
+
metadata = undefined;
|
|
256
|
+
}
|
|
257
|
+
if (metadata && typeof metadata.name === 'string' && metadata.name.length > 0) {
|
|
258
|
+
name = metadata.name;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
name,
|
|
263
|
+
format,
|
|
264
|
+
content: body,
|
|
265
|
+
metadata,
|
|
266
|
+
raw,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Parse a raw content file with no frontmatter (rules, claude-md, copilot-md).
|
|
271
|
+
* The name is derived from the filename if available, otherwise defaults.
|
|
272
|
+
*/
|
|
273
|
+
function parseRawContent(content, format, raw) {
|
|
274
|
+
// Name will be overridden by readSkillFile when filePath is available
|
|
275
|
+
return {
|
|
276
|
+
name: 'unknown',
|
|
277
|
+
format,
|
|
278
|
+
content,
|
|
279
|
+
raw,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Parse a JavaScript hook file.
|
|
284
|
+
*/
|
|
285
|
+
function parseJavaScript(content, raw) {
|
|
286
|
+
const extracted = extractJsName(content);
|
|
287
|
+
return {
|
|
288
|
+
name: extracted ?? 'handler',
|
|
289
|
+
format: 'hook-js',
|
|
290
|
+
content,
|
|
291
|
+
raw,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Parse an Aider YAML configuration file.
|
|
296
|
+
*/
|
|
297
|
+
function parseAiderYaml(content, raw) {
|
|
298
|
+
let metadata;
|
|
299
|
+
try {
|
|
300
|
+
metadata = parseSimpleYaml(content);
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
// Malformed YAML — continue without metadata
|
|
304
|
+
metadata = undefined;
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
name: 'aider',
|
|
308
|
+
format: 'aider-yml',
|
|
309
|
+
content,
|
|
310
|
+
metadata,
|
|
311
|
+
raw,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Parse a Continue JSON configuration file.
|
|
316
|
+
*/
|
|
317
|
+
function parseContinueJson(content, raw) {
|
|
318
|
+
let metadata;
|
|
319
|
+
let parsedContent = content;
|
|
320
|
+
let name = 'continue';
|
|
321
|
+
try {
|
|
322
|
+
const parsed = JSON.parse(content);
|
|
323
|
+
metadata = parsed;
|
|
324
|
+
parsedContent = JSON.stringify(parsed);
|
|
325
|
+
if (typeof parsed.name === 'string' && parsed.name.length > 0) {
|
|
326
|
+
name = parsed.name;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
// Malformed JSON — use raw content as-is
|
|
331
|
+
metadata = undefined;
|
|
332
|
+
parsedContent = content;
|
|
333
|
+
}
|
|
334
|
+
return {
|
|
335
|
+
name,
|
|
336
|
+
format: 'continue-json',
|
|
337
|
+
content: parsedContent,
|
|
338
|
+
metadata,
|
|
339
|
+
raw,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
// ── File Reader ──
|
|
343
|
+
/**
|
|
344
|
+
* Read a skill file from disc, auto-detect its format, and parse it.
|
|
345
|
+
*
|
|
346
|
+
* Returns a ParsedSkill with the filePath field populated.
|
|
347
|
+
* If the file cannot be read, returns a minimal ParsedSkill with empty content.
|
|
348
|
+
*/
|
|
349
|
+
export function readSkillFile(filePath) {
|
|
350
|
+
let content;
|
|
351
|
+
try {
|
|
352
|
+
content = fs.readFileSync(filePath, 'utf-8');
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
// File unreadable — return a safe default
|
|
356
|
+
return {
|
|
357
|
+
name: nameFromFilename(filePath),
|
|
358
|
+
format: detectFormat(filePath),
|
|
359
|
+
content: '',
|
|
360
|
+
raw: '',
|
|
361
|
+
filePath,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
const format = detectFormat(filePath);
|
|
365
|
+
const result = parseSkillFile(content, format);
|
|
366
|
+
result.filePath = filePath;
|
|
367
|
+
// For formats that derive their name from the filename, apply it now
|
|
368
|
+
if (result.name === 'unknown' || result.name === '') {
|
|
369
|
+
result.name = nameFromFilename(filePath);
|
|
370
|
+
}
|
|
371
|
+
return result;
|
|
372
|
+
}
|
|
373
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../src/defence/skill-scanner/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AA8BlC,yBAAyB;AAEzB;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IAErC,oDAAoD;IACpD,IAAI,KAAK,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC5C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,QAAQ,KAAK,YAAY;QAAE,OAAO,SAAS,CAAC;IAChD,IAAI,KAAK,KAAK,WAAW;QAAE,OAAO,WAAW,CAAC;IAC9C,IAAI,KAAK,KAAK,yBAAyB;QAAE,OAAO,YAAY,CAAC;IAC7D,IAAI,QAAQ,KAAK,iBAAiB;QAAE,OAAO,WAAW,CAAC;IAEvD,0EAA0E;IAC1E,IAAI,QAAQ,KAAK,cAAc,IAAI,QAAQ,KAAK,gBAAgB,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;QAC/F,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,qBAAqB;IACrB,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAEhD,IAAI,UAAU,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QAAE,OAAO,WAAW,CAAC;IAEjE,IAAI,QAAQ,KAAK,aAAa,IAAI,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACpE,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,2BAA2B;AAE3B;;;;;;;;;GASG;AACH,SAAS,eAAe,CAAC,QAAgB;IACvC,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnC,IAAI,aAAa,GAAkB,IAAI,CAAC;IACxC,IAAI,SAAS,GAAmC,IAAI,CAAC;IAErD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,gCAAgC;QAChC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC/B,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9C,SAAS;QACX,CAAC;QAED,8BAA8B;QAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC;QACrD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAE/B,2BAA2B;QAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAChE,IAAI,CAAC,OAAO;YAAE,SAAS;QAEvB,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,KAAK,GAAW,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAEtC,IAAI,MAAM,IAAI,CAAC,IAAI,aAAa,IAAI,SAAS,EAAE,CAAC;YAC9C,gDAAgD;YAChD,SAAS,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,mDAAmD;YACnD,IAAI,aAAa,IAAI,SAAS,EAAE,CAAC;gBAC/B,MAAM,CAAC,aAAa,CAAC,GAAG,SAAS,CAAC;gBAClC,aAAa,GAAG,IAAI,CAAC;gBACrB,SAAS,GAAG,IAAI,CAAC;YACnB,CAAC;YAED,IAAI,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;gBACjC,8DAA8D;gBAC9D,aAAa,GAAG,GAAG,CAAC;gBACpB,SAAS,GAAG,EAAE,CAAC;YACjB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;IACH,CAAC;IAED,+BAA+B;IAC/B,IAAI,aAAa,IAAI,SAAS,EAAE,CAAC;QAC/B,MAAM,CAAC,aAAa,CAAC,GAAG,SAAS,CAAC;IACpC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,GAAW;IAC/B,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,EAAE,CAAC;IAE1B,+CAA+C;IAC/C,IACE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC1C,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAC1C,CAAC;QACD,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IAED,mBAAmB;IACnB,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,GAAG,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IAElC,mBAAmB;IACnB,IAAI,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAChC,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,+BAA+B;AAE/B;;;GAGG;AACH,SAAS,gBAAgB,CAAC,OAAe;IACvC,2DAA2D;IAC3D,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,wDAAwD;IACxD,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACjD,IAAI,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;QACxB,oDAAoD;QACpD,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1D,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAEpD,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,gCAAgC;AAEhC;;;GAGG;AACH,SAAS,aAAa,CAAC,MAAc;IACnC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAEtD,+BAA+B;IAC/B,MAAM,aAAa,GAAG,SAAS,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACtD,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACjC,CAAC;IAED,4BAA4B;IAC5B,MAAM,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC7D,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAChC,CAAC;IAED,6DAA6D;IAC7D,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;IACjF,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IAED,mCAAmC;IACnC,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;IACzF,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,QAAgB;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAE3D,oEAAoE;IACpE,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IAED,OAAO,IAAI,IAAI,SAAS,CAAC;AAC3B,CAAC;AAED,oBAAoB;AAEpB;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,MAAoB;IAClE,MAAM,eAAe,GAAG,MAAM,IAAI,SAAS,CAAC;IAC5C,MAAM,GAAG,GAAG,OAAO,CAAC;IAEpB,gDAAgD;IAChD,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,OAAO;YACL,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,eAAe;YACvB,OAAO,EAAE,EAAE;YACX,GAAG;SACJ,CAAC;IACJ,CAAC;IAED,wEAAwE;IACxE,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC;IACrF,IAAI,YAAY,GAAG,GAAG,EAAE,CAAC;QACvB,OAAO;YACL,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,eAAe;YACvB,OAAO,EAAE,EAAE;YACX,GAAG;SACJ,CAAC;IACJ,CAAC;IAED,QAAQ,eAAe,EAAE,CAAC;QACxB,KAAK,UAAU,CAAC;QAChB,KAAK,SAAS;YACZ,OAAO,4BAA4B,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,CAAC;QAErE,KAAK,OAAO,CAAC;QACb,KAAK,WAAW,CAAC;QACjB,KAAK,YAAY;YACf,OAAO,eAAe,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,CAAC;QAExD,KAAK,SAAS;YACZ,OAAO,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAEvC,KAAK,WAAW;YACd,OAAO,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAEtC,KAAK,eAAe;YAClB,OAAO,iBAAiB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAEzC,KAAK,SAAS,CAAC;QACf;YACE,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,SAAS;gBACjB,OAAO;gBACP,GAAG;aACJ,CAAC;IACN,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,4BAA4B,CACnC,OAAe,EACf,MAA8B,EAC9B,GAAW;IAEX,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAEtD,IAAI,QAA6C,CAAC;IAClD,IAAI,IAAI,GAAG,SAAS,CAAC;IAErB,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,QAAQ,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,6CAA6C;YAC7C,QAAQ,GAAG,SAAS,CAAC;QACvB,CAAC;QAED,IAAI,QAAQ,IAAI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9E,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI;QACJ,MAAM;QACN,OAAO,EAAE,IAAI;QACb,QAAQ;QACR,GAAG;KACJ,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CACtB,OAAe,EACf,MAA4C,EAC5C,GAAW;IAEX,sEAAsE;IACtE,OAAO;QACL,IAAI,EAAE,SAAS;QACf,MAAM;QACN,OAAO;QACP,GAAG;KACJ,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,OAAe,EAAE,GAAW;IACnD,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IAEzC,OAAO;QACL,IAAI,EAAE,SAAS,IAAI,SAAS;QAC5B,MAAM,EAAE,SAAS;QACjB,OAAO;QACP,GAAG;KACJ,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,OAAe,EAAE,GAAW;IAClD,IAAI,QAA6C,CAAC;IAElD,IAAI,CAAC;QACH,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,6CAA6C;QAC7C,QAAQ,GAAG,SAAS,CAAC;IACvB,CAAC;IAED,OAAO;QACL,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,WAAW;QACnB,OAAO;QACP,QAAQ;QACR,GAAG;KACJ,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,OAAe,EAAE,GAAW;IACrD,IAAI,QAA6C,CAAC;IAClD,IAAI,aAAa,GAAG,OAAO,CAAC;IAC5B,IAAI,IAAI,GAAG,UAAU,CAAC;IAEtB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA4B,CAAC;QAC9D,QAAQ,GAAG,MAAM,CAAC;QAClB,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAEvC,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9D,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACrB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,yCAAyC;QACzC,QAAQ,GAAG,SAAS,CAAC;QACrB,aAAa,GAAG,OAAO,CAAC;IAC1B,CAAC;IAED,OAAO;QACL,IAAI;QACJ,MAAM,EAAE,eAAe;QACvB,OAAO,EAAE,aAAa;QACtB,QAAQ;QACR,GAAG;KACJ,CAAC;AACJ,CAAC;AAED,oBAAoB;AAEpB;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,IAAI,OAAe,CAAC;IAEpB,IAAI,CAAC;QACH,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,0CAA0C;QAC1C,OAAO;YACL,IAAI,EAAE,gBAAgB,CAAC,QAAQ,CAAC;YAChC,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC;YAC9B,OAAO,EAAE,EAAE;YACX,GAAG,EAAE,EAAE;YACP,QAAQ;SACT,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAE/C,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAE3B,qEAAqE;IACrE,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC;QACpD,MAAM,CAAC,IAAI,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill-Specific Threat Patterns
|
|
3
|
+
*
|
|
4
|
+
* Detects malicious patterns in agent instruction files (skill files, tool
|
|
5
|
+
* definitions, .mdc rules, etc.) and in code files (JS/TS/JSON) that may
|
|
6
|
+
* accompany them.
|
|
7
|
+
*
|
|
8
|
+
* Two entry points:
|
|
9
|
+
* - detectSkillThreats() — natural-language instruction scanning
|
|
10
|
+
* - detectCodeThreats() — JavaScript / JSON code scanning
|
|
11
|
+
*
|
|
12
|
+
* Follows the same conventions as instruction-detector.ts:
|
|
13
|
+
* - One match per group is enough (break after first)
|
|
14
|
+
* - MAX_SCAN_LENGTH truncation to prevent ReDOS
|
|
15
|
+
* - safeRegexTest wrapper for every test
|
|
16
|
+
* - Length caps on unbounded quantifiers ([\s\S]{0,N})
|
|
17
|
+
*/
|
|
18
|
+
export interface SkillThreatResult {
|
|
19
|
+
detected: boolean;
|
|
20
|
+
threats: string[];
|
|
21
|
+
confidence: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Analyse natural-language skill / instruction content for threat patterns.
|
|
25
|
+
*
|
|
26
|
+
* Designed for scanning .mdc files, skill definitions, tool descriptions,
|
|
27
|
+
* and similar agent instruction documents.
|
|
28
|
+
*/
|
|
29
|
+
export declare function detectSkillThreats(content: string): SkillThreatResult;
|
|
30
|
+
/**
|
|
31
|
+
* Analyse JavaScript / JSON code content for threat patterns.
|
|
32
|
+
*
|
|
33
|
+
* Designed for scanning code files that accompany skill definitions —
|
|
34
|
+
* tool implementations, config files, etc.
|
|
35
|
+
*/
|
|
36
|
+
export declare function detectCodeThreats(content: string): SkillThreatResult;
|
|
37
|
+
//# sourceMappingURL=patterns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../../src/defence/skill-scanner/patterns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AA2OD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAErE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAEpE"}
|