@panguard-ai/scan-core 0.1.2 → 1.4.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/dist/__tests__/atr-engine.test.js +3 -2
- package/dist/__tests__/atr-engine.test.js.map +1 -1
- package/dist/__tests__/context-signals.test.js +2 -1
- package/dist/__tests__/context-signals.test.js.map +1 -1
- package/dist/__tests__/hash-utils.test.js +1 -0
- package/dist/__tests__/hash-utils.test.js.map +1 -1
- package/dist/__tests__/manifest-parser.test.js +2 -6
- package/dist/__tests__/manifest-parser.test.js.map +1 -1
- package/dist/__tests__/risk-scorer.test.js +2 -4
- package/dist/__tests__/risk-scorer.test.js.map +1 -1
- package/dist/__tests__/scanner.test.js +15 -40
- package/dist/__tests__/scanner.test.js.map +1 -1
- package/dist/atr-engine.d.ts +2 -0
- package/dist/atr-engine.d.ts.map +1 -1
- package/dist/atr-engine.js +23 -6
- package/dist/atr-engine.js.map +1 -1
- package/dist/context-signals.d.ts +4 -0
- package/dist/context-signals.d.ts.map +1 -1
- package/dist/context-signals.js +142 -19
- package/dist/context-signals.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/instruction-patterns.d.ts.map +1 -1
- package/dist/instruction-patterns.js +86 -20
- package/dist/instruction-patterns.js.map +1 -1
- package/dist/markdown-utils.d.ts +20 -0
- package/dist/markdown-utils.d.ts.map +1 -1
- package/dist/markdown-utils.js +26 -1
- package/dist/markdown-utils.js.map +1 -1
- package/dist/risk-scorer.d.ts.map +1 -1
- package/dist/risk-scorer.js +18 -5
- package/dist/risk-scorer.js.map +1 -1
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +17 -5
- package/dist/scanner.js.map +1 -1
- package/package.json +9 -9
- package/LICENSE +0 -21
package/dist/markdown-utils.js
CHANGED
|
@@ -13,7 +13,7 @@ export function stripMarkdownNoise(raw) {
|
|
|
13
13
|
// Remove fenced code blocks (```...```)
|
|
14
14
|
cleaned = cleaned.replace(/```[\s\S]*?```/g, ' ');
|
|
15
15
|
// Remove indented code blocks (4 spaces or 1 tab)
|
|
16
|
-
cleaned = cleaned.replace(/^(?:
|
|
16
|
+
cleaned = cleaned.replace(/^(?: {4}|\t).+$/gm, ' ');
|
|
17
17
|
// Remove inline code (`...`)
|
|
18
18
|
cleaned = cleaned.replace(/`[^`]+`/g, ' ');
|
|
19
19
|
// Remove blockquotes
|
|
@@ -38,4 +38,29 @@ export function extractCodeBlocks(content) {
|
|
|
38
38
|
export function stripCodeBlocks(content) {
|
|
39
39
|
return content.replace(/```[\s\S]*?```/g, ' ');
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Strip negation/exclusion sections from content.
|
|
43
|
+
* Removes "When NOT to use", "Do NOT", "Never" sections that describe
|
|
44
|
+
* what the skill does NOT do — preventing false positives when these
|
|
45
|
+
* sections mention dangerous keywords for contrast.
|
|
46
|
+
*/
|
|
47
|
+
export function stripNegationSections(content) {
|
|
48
|
+
// Remove lines/paragraphs that are clearly negation context
|
|
49
|
+
let cleaned = content;
|
|
50
|
+
// Remove bullet points starting with negation
|
|
51
|
+
cleaned = cleaned.replace(/^[\s-]*(?:❌|✗|✘)\s+.*$/gm, ' ');
|
|
52
|
+
// Remove "When NOT to use" / "Do NOT use" section headers + following bullets
|
|
53
|
+
cleaned = cleaned.replace(/^#{1,4}\s+(?:when\s+)?(?:not?\s+(?:to\s+)?use|don[''\u2019]?t\s+use|never\s+use).*$(?:\n(?:[-*]\s+.*|[ \t]+.*|\s*)$)*/gim, ' ');
|
|
54
|
+
return cleaned;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Prepare content for security checks by separating prose from code blocks
|
|
58
|
+
* and removing negation sections. All check modules should use this
|
|
59
|
+
* instead of running patterns against raw content.
|
|
60
|
+
*/
|
|
61
|
+
export function prepareContent(raw) {
|
|
62
|
+
const codeBlocks = extractCodeBlocks(raw);
|
|
63
|
+
const prose = stripNegationSections(stripCodeBlocks(raw));
|
|
64
|
+
return { prose, codeBlocks, raw };
|
|
65
|
+
}
|
|
41
66
|
//# sourceMappingURL=markdown-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown-utils.js","sourceRoot":"","sources":["../src/markdown-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,IAAI,OAAO,GAAG,GAAG,CAAC;IAClB,wCAAwC;IACxC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;IAClD,kDAAkD;IAClD,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;IACpD,6BAA6B;IAC7B,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAC3C,qBAAqB;IACrB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IAC7C,6CAA6C;IAC7C,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAC;IAC1D,mBAAmB;IACnB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAC3C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,EAAE,GAAG,iBAAiB,CAAC;IAC7B,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,OAAO,OAAO,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;AACjD,CAAC"}
|
|
1
|
+
{"version":3,"file":"markdown-utils.js","sourceRoot":"","sources":["../src/markdown-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,IAAI,OAAO,GAAG,GAAG,CAAC;IAClB,wCAAwC;IACxC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;IAClD,kDAAkD;IAClD,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;IACpD,6BAA6B;IAC7B,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAC3C,qBAAqB;IACrB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IAC7C,6CAA6C;IAC7C,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAC;IAC1D,mBAAmB;IACnB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAC3C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,EAAE,GAAG,iBAAiB,CAAC;IAC7B,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,OAAO,OAAO,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;AACjD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,4DAA4D;IAC5D,IAAI,OAAO,GAAG,OAAO,CAAC;IACtB,8CAA8C;IAC9C,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,0BAA0B,EAAE,GAAG,CAAC,CAAC;IAC3D,8EAA8E;IAC9E,OAAO,GAAG,OAAO,CAAC,OAAO,CACvB,0HAA0H,EAC1H,GAAG,CACJ,CAAC;IACF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IAQxC,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,qBAAqB,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;AACpC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"risk-scorer.d.ts","sourceRoot":"","sources":["../src/risk-scorer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"risk-scorer.d.ts","sourceRoot":"","sources":["../src/risk-scorer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAkBrD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,iBAAiB,GAAE,MAAY,GAC9B;IACD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;CAClB,CA2DA"}
|
package/dist/risk-scorer.js
CHANGED
|
@@ -44,20 +44,33 @@ export function calculateRiskScore(findings, contextMultiplier = 1.0) {
|
|
|
44
44
|
// Apply context multiplier
|
|
45
45
|
const adjustedScore = Math.round(rawScore * contextMultiplier);
|
|
46
46
|
const score = Math.min(100, adjustedScore);
|
|
47
|
-
const
|
|
47
|
+
const allFindings = [...deduped.values()];
|
|
48
|
+
const hasCritical = allFindings.some((f) => f.severity === 'critical');
|
|
49
|
+
// Distinguish "real" critical findings from "hidden in markup" ones.
|
|
50
|
+
// Markup-only criticals are likely formatting artifacts (SVG, code blocks, HTML examples).
|
|
51
|
+
// Only non-markup criticals should be able to push risk level to CRITICAL.
|
|
52
|
+
const hasRealCritical = allFindings.some((f) => f.severity === 'critical' && !f.title.includes('(hidden in markup)'));
|
|
53
|
+
const hasRealHigh = allFindings.some((f) => f.severity === 'high' && !f.title.includes('(hidden in markup)'));
|
|
48
54
|
// Critical-override behavior depends on context:
|
|
49
55
|
// - Normal context (multiplier >= 0.6): critical finding forces at least HIGH
|
|
50
56
|
// - Strong legitimate context (multiplier < 0.6): critical finding forces MEDIUM only
|
|
51
57
|
const weakenedCriticalOverride = contextMultiplier < 0.6;
|
|
52
58
|
let level;
|
|
53
|
-
if (score >= 70
|
|
59
|
+
if ((score >= 70 && hasRealCritical) ||
|
|
60
|
+
(hasRealCritical && !weakenedCriticalOverride && score >= 40)) {
|
|
54
61
|
level = 'CRITICAL';
|
|
55
|
-
|
|
62
|
+
}
|
|
63
|
+
else if (score >= 40 ||
|
|
64
|
+
(hasCritical && !weakenedCriticalOverride) ||
|
|
65
|
+
(hasRealHigh && score >= 25)) {
|
|
56
66
|
level = 'HIGH';
|
|
57
|
-
|
|
67
|
+
}
|
|
68
|
+
else if (score >= 15 || (hasCritical && weakenedCriticalOverride)) {
|
|
58
69
|
level = 'MEDIUM';
|
|
59
|
-
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
60
72
|
level = 'LOW';
|
|
73
|
+
}
|
|
61
74
|
return { score, level };
|
|
62
75
|
}
|
|
63
76
|
//# sourceMappingURL=risk-scorer.js.map
|
package/dist/risk-scorer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"risk-scorer.js","sourceRoot":"","sources":["../src/risk-scorer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,gBAAgB,GAA2B;IAC/C,QAAQ,EAAE,EAAE;IACZ,IAAI,EAAE,EAAE;IACR,MAAM,EAAE,CAAC;IACT,GAAG,EAAE,CAAC;IACN,IAAI,EAAE,CAAC;CACR,CAAC;AAEF,MAAM,aAAa,GAA2B;IAC5C,QAAQ,EAAE,CAAC;IACX,IAAI,EAAE,CAAC;IACP,MAAM,EAAE,CAAC;IACT,GAAG,EAAE,CAAC;IACN,IAAI,EAAE,CAAC;CACR,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAA4B,EAC5B,oBAA4B,GAAG;IAK/B,oDAAoD;IACpD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC3C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACzC,IACE,CAAC,QAAQ;YACT,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAChF,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACvC,QAAQ,IAAI,gBAAgB,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC;IAED,2BAA2B;IAC3B,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,iBAAiB,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IAE3C,MAAM,WAAW,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"risk-scorer.js","sourceRoot":"","sources":["../src/risk-scorer.ts"],"names":[],"mappings":"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"}
|
package/dist/scanner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAsC,MAAM,YAAY,CAAC;AAS9F;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,UAAU,CAgIlF"}
|
package/dist/scanner.js
CHANGED
|
@@ -55,7 +55,8 @@ export function scanContent(content, options = {}) {
|
|
|
55
55
|
// -- Context signals (pre-compute for ATR severity adjustments) --
|
|
56
56
|
const ctx = detectContextSignals(content, manifest);
|
|
57
57
|
const hasStrongReducers = ctx.multiplier < 0.7;
|
|
58
|
-
const allReducers = ctx.signals.every(s => s.type === 'reducer');
|
|
58
|
+
const allReducers = ctx.signals.every((s) => s.type === 'reducer');
|
|
59
|
+
const hasDefensiveText = ctx.signals.some((s) => s.id === 'reduce-defensive-text-strong' || s.id === 'reduce-defensive-text');
|
|
59
60
|
// -- ATR pattern detection --
|
|
60
61
|
const atrRules = options.atrRules ?? [];
|
|
61
62
|
let atrMatchedCount = 0;
|
|
@@ -64,6 +65,7 @@ export function scanContent(content, options = {}) {
|
|
|
64
65
|
isReadme,
|
|
65
66
|
hasStrongReducers,
|
|
66
67
|
allReducers,
|
|
68
|
+
hasDefensiveText,
|
|
67
69
|
});
|
|
68
70
|
findings.push(...atrResult.findings);
|
|
69
71
|
checks.push(atrResult.check);
|
|
@@ -72,7 +74,11 @@ export function scanContent(content, options = {}) {
|
|
|
72
74
|
// -- Instruction pattern detection --
|
|
73
75
|
const instrResult = checkInstructions(manifest.instructions || content, sourceType);
|
|
74
76
|
findings.push(...instrResult.findings);
|
|
75
|
-
checks.push({
|
|
77
|
+
checks.push({
|
|
78
|
+
status: instrResult.status,
|
|
79
|
+
label: instrResult.label,
|
|
80
|
+
findings: instrResult.findings,
|
|
81
|
+
});
|
|
76
82
|
// -- Secret detection --
|
|
77
83
|
const secretResult = detectSecrets(content);
|
|
78
84
|
findings.push(...secretResult.findings);
|
|
@@ -96,15 +102,21 @@ export function scanContent(content, options = {}) {
|
|
|
96
102
|
});
|
|
97
103
|
// -- Context signals report --
|
|
98
104
|
if (ctx.signals.length > 0) {
|
|
99
|
-
const boosterCount = ctx.signals.filter(s => s.type === 'booster').length;
|
|
100
|
-
const reducerCount = ctx.signals.filter(s => s.type === 'reducer').length;
|
|
105
|
+
const boosterCount = ctx.signals.filter((s) => s.type === 'booster').length;
|
|
106
|
+
const reducerCount = ctx.signals.filter((s) => s.type === 'reducer').length;
|
|
101
107
|
checks.push({
|
|
102
108
|
status: boosterCount > 0 ? 'warn' : 'pass',
|
|
103
109
|
label: `Context: ${boosterCount} risk booster(s), ${reducerCount} reducer(s), multiplier ${ctx.multiplier.toFixed(2)}x`,
|
|
104
110
|
});
|
|
105
111
|
}
|
|
106
112
|
// -- Risk scoring --
|
|
107
|
-
|
|
113
|
+
// README files are documentation, not agent instructions.
|
|
114
|
+
// Keyword matches in feature descriptions are expected, not threats.
|
|
115
|
+
// Apply a heavy discount so legitimate READMEs don't score CRITICAL.
|
|
116
|
+
// README raw scores are typically 100-200 (many keyword matches in feature
|
|
117
|
+
// descriptions) so we need a strong discount to reach LOW/MEDIUM range.
|
|
118
|
+
const effectiveMultiplier = isReadme ? Math.min(ctx.multiplier * 0.15, 0.25) : ctx.multiplier;
|
|
119
|
+
const { score, level } = calculateRiskScore(findings, effectiveMultiplier);
|
|
108
120
|
// -- Hashes --
|
|
109
121
|
const cHash = contentHash(content);
|
|
110
122
|
const highFindings = findings
|
package/dist/scanner.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@panguard-ai/scan-core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,6 +27,13 @@
|
|
|
27
27
|
"package.json",
|
|
28
28
|
"README.md"
|
|
29
29
|
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc --build",
|
|
32
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
33
|
+
"typecheck": "tsc --noEmit",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"dev": "tsc --build --watch"
|
|
36
|
+
},
|
|
30
37
|
"dependencies": {
|
|
31
38
|
"js-yaml": "^4.1.0"
|
|
32
39
|
},
|
|
@@ -35,12 +42,5 @@
|
|
|
35
42
|
"@types/node": "^22.14.0",
|
|
36
43
|
"typescript": "~5.7.3",
|
|
37
44
|
"vitest": "^3.0.0"
|
|
38
|
-
},
|
|
39
|
-
"scripts": {
|
|
40
|
-
"build": "tsc --build",
|
|
41
|
-
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
42
|
-
"typecheck": "tsc --noEmit",
|
|
43
|
-
"test": "vitest run",
|
|
44
|
-
"dev": "tsc --build --watch"
|
|
45
45
|
}
|
|
46
|
-
}
|
|
46
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025-2026 Panguard AI Team
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|