zora-agent 0.10.0 → 0.10.2
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 +171 -65
- package/dist/cli/daemon.js +1 -0
- package/dist/cli/daemon.js.map +1 -1
- package/dist/cli/index.js +27 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/secret-commands.d.ts +16 -0
- package/dist/cli/secret-commands.d.ts.map +1 -0
- package/dist/cli/secret-commands.js +87 -0
- package/dist/cli/secret-commands.js.map +1 -0
- package/dist/cli/skill-commands.d.ts.map +1 -1
- package/dist/cli/skill-commands.js +75 -0
- package/dist/cli/skill-commands.js.map +1 -1
- package/dist/cli/subagent-commands.d.ts +13 -0
- package/dist/cli/subagent-commands.d.ts.map +1 -0
- package/dist/cli/subagent-commands.js +80 -0
- package/dist/cli/subagent-commands.js.map +1 -0
- package/dist/config/defaults.d.ts +6 -0
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +6 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/dashboard/cost-tracker.d.ts +40 -0
- package/dist/dashboard/cost-tracker.d.ts.map +1 -0
- package/dist/dashboard/cost-tracker.js +63 -0
- package/dist/dashboard/cost-tracker.js.map +1 -0
- package/dist/dashboard/frontend/dist/assets/{index-DSXaCp9r.js → index-Bi0V-1ti.js} +83 -83
- package/dist/dashboard/frontend/dist/assets/index-SQqtXVeO.css +1 -0
- package/dist/dashboard/frontend/dist/index.html +2 -2
- package/dist/dashboard/server.d.ts +5 -0
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +17 -0
- package/dist/dashboard/server.js.map +1 -1
- package/dist/hooks/built-in/audit-log.d.ts +13 -0
- package/dist/hooks/built-in/audit-log.d.ts.map +1 -0
- package/dist/hooks/built-in/audit-log.js +48 -0
- package/dist/hooks/built-in/audit-log.js.map +1 -0
- package/dist/hooks/built-in/rate-limit.d.ts +18 -0
- package/dist/hooks/built-in/rate-limit.d.ts.map +1 -0
- package/dist/hooks/built-in/rate-limit.js +30 -0
- package/dist/hooks/built-in/rate-limit.js.map +1 -0
- package/dist/hooks/built-in/secret-redact.d.ts +7 -0
- package/dist/hooks/built-in/secret-redact.d.ts.map +1 -0
- package/dist/hooks/built-in/secret-redact.js +33 -0
- package/dist/hooks/built-in/secret-redact.js.map +1 -0
- package/dist/hooks/built-in/shell-safety.d.ts +7 -0
- package/dist/hooks/built-in/shell-safety.d.ts.map +1 -0
- package/dist/hooks/built-in/shell-safety.js +34 -0
- package/dist/hooks/built-in/shell-safety.js.map +1 -0
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +5 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/tool-hook-runner.d.ts +36 -0
- package/dist/hooks/tool-hook-runner.d.ts.map +1 -0
- package/dist/hooks/tool-hook-runner.js +49 -0
- package/dist/hooks/tool-hook-runner.js.map +1 -0
- package/dist/lib/error-normalizer.d.ts +53 -0
- package/dist/lib/error-normalizer.d.ts.map +1 -0
- package/dist/lib/error-normalizer.js +128 -0
- package/dist/lib/error-normalizer.js.map +1 -0
- package/dist/memory/context-compressor.d.ts +3 -1
- package/dist/memory/context-compressor.d.ts.map +1 -1
- package/dist/memory/context-compressor.js +18 -3
- package/dist/memory/context-compressor.js.map +1 -1
- package/dist/memory/plan-cache.d.ts +27 -0
- package/dist/memory/plan-cache.d.ts.map +1 -0
- package/dist/memory/plan-cache.js +91 -0
- package/dist/memory/plan-cache.js.map +1 -0
- package/dist/orchestrator/code-tool-runner.d.ts +41 -0
- package/dist/orchestrator/code-tool-runner.d.ts.map +1 -0
- package/dist/orchestrator/code-tool-runner.js +375 -0
- package/dist/orchestrator/code-tool-runner.js.map +1 -0
- package/dist/orchestrator/error-pattern-detector.d.ts +54 -0
- package/dist/orchestrator/error-pattern-detector.d.ts.map +1 -0
- package/dist/orchestrator/error-pattern-detector.js +87 -0
- package/dist/orchestrator/error-pattern-detector.js.map +1 -0
- package/dist/orchestrator/execution-planner.d.ts +33 -0
- package/dist/orchestrator/execution-planner.d.ts.map +1 -0
- package/dist/orchestrator/execution-planner.js +67 -0
- package/dist/orchestrator/execution-planner.js.map +1 -0
- package/dist/orchestrator/orchestrator.d.ts +77 -0
- package/dist/orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/orchestrator.js +595 -29
- package/dist/orchestrator/orchestrator.js.map +1 -1
- package/dist/orchestrator/retry-queue.d.ts +7 -1
- package/dist/orchestrator/retry-queue.d.ts.map +1 -1
- package/dist/orchestrator/retry-queue.js +10 -4
- package/dist/orchestrator/retry-queue.js.map +1 -1
- package/dist/orchestrator/step-classifier.d.ts +26 -0
- package/dist/orchestrator/step-classifier.d.ts.map +1 -0
- package/dist/orchestrator/step-classifier.js +77 -0
- package/dist/orchestrator/step-classifier.js.map +1 -0
- package/dist/orchestrator/tlci-dispatcher.d.ts +47 -0
- package/dist/orchestrator/tlci-dispatcher.d.ts.map +1 -0
- package/dist/orchestrator/tlci-dispatcher.js +116 -0
- package/dist/orchestrator/tlci-dispatcher.js.map +1 -0
- package/dist/routines/heartbeat.d.ts.map +1 -1
- package/dist/routines/heartbeat.js +3 -1
- package/dist/routines/heartbeat.js.map +1 -1
- package/dist/routines/routine-manager.d.ts.map +1 -1
- package/dist/routines/routine-manager.js +3 -1
- package/dist/routines/routine-manager.js.map +1 -1
- package/dist/security/intent-capsule.d.ts +19 -0
- package/dist/security/intent-capsule.d.ts.map +1 -1
- package/dist/security/intent-capsule.js +84 -1
- package/dist/security/intent-capsule.js.map +1 -1
- package/dist/security/policy-engine.d.ts +1 -0
- package/dist/security/policy-engine.d.ts.map +1 -1
- package/dist/security/policy-engine.js +22 -1
- package/dist/security/policy-engine.js.map +1 -1
- package/dist/services/negative-cache.d.ts +67 -0
- package/dist/services/negative-cache.d.ts.map +1 -0
- package/dist/services/negative-cache.js +164 -0
- package/dist/services/negative-cache.js.map +1 -0
- package/dist/skills/skill-auditor.d.ts +36 -0
- package/dist/skills/skill-auditor.d.ts.map +1 -0
- package/dist/skills/skill-auditor.js +89 -0
- package/dist/skills/skill-auditor.js.map +1 -0
- package/dist/skills/skill-installer.d.ts +41 -0
- package/dist/skills/skill-installer.d.ts.map +1 -0
- package/dist/skills/skill-installer.js +141 -0
- package/dist/skills/skill-installer.js.map +1 -0
- package/dist/skills/skill-scanner.d.ts +30 -0
- package/dist/skills/skill-scanner.d.ts.map +1 -0
- package/dist/skills/skill-scanner.js +249 -0
- package/dist/skills/skill-scanner.js.map +1 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/planning-tool.d.ts +95 -0
- package/dist/tools/planning-tool.d.ts.map +1 -0
- package/dist/tools/planning-tool.js +117 -0
- package/dist/tools/planning-tool.js.map +1 -0
- package/dist/tools/skill-tool.d.ts +94 -0
- package/dist/tools/skill-tool.d.ts.map +1 -0
- package/dist/tools/skill-tool.js +202 -0
- package/dist/tools/skill-tool.js.map +1 -0
- package/dist/tools/subagent-tool.d.ts +11 -0
- package/dist/tools/subagent-tool.d.ts.map +1 -0
- package/dist/tools/subagent-tool.js +87 -0
- package/dist/tools/subagent-tool.js.map +1 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/args.d.ts +5 -0
- package/dist/utils/args.d.ts.map +1 -0
- package/dist/utils/args.js +20 -0
- package/dist/utils/args.js.map +1 -0
- package/package.json +4 -1
- package/dist/dashboard/frontend/dist/assets/index-2FaDr6iS.js +0 -277
- package/dist/dashboard/frontend/dist/assets/index-B9-KXW14.css +0 -1
- package/dist/dashboard/frontend/dist/assets/index-BMxbyTer.css +0 -1
- package/dist/dashboard/frontend/dist/assets/index-BXUfB9iR.js +0 -253
- package/dist/dashboard/frontend/dist/assets/index-BcOGj1EF.css +0 -1
- package/dist/dashboard/frontend/dist/assets/index-BtiFO9YN.js +0 -261
- package/dist/dashboard/frontend/dist/assets/index-CQmpMTLW.js +0 -253
- package/dist/dashboard/frontend/dist/assets/index-Cfjy5acU.css +0 -1
- package/dist/dashboard/frontend/dist/assets/index-D41hcjgc.js +0 -253
- package/dist/dashboard/frontend/dist/assets/index-D83BawFd.css +0 -1
- package/dist/dashboard/frontend/dist/assets/index-DAODjoxu.css +0 -1
- package/dist/dashboard/frontend/dist/assets/index-DB-Eu5oV.js +0 -253
- package/dist/dashboard/frontend/dist/assets/index-W0VVEDu6.js +0 -253
- package/dist/dashboard/frontend/dist/assets/index-aK9PWl6w.js +0 -253
- package/dist/dashboard/frontend/vite.config.d.ts +0 -3
- package/dist/dashboard/frontend/vite.config.d.ts.map +0 -1
- package/dist/dashboard/frontend/vite.config.js +0 -11
- package/dist/dashboard/frontend/vite.config.js.map +0 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SkillAuditor — Scans all installed skills at session start.
|
|
3
|
+
*
|
|
4
|
+
* Catches skills that were installed manually (git clone, copy-paste, etc.)
|
|
5
|
+
* without going through the secure install flow. Runs as a SessionStart check.
|
|
6
|
+
*
|
|
7
|
+
* Checks all three skill layers:
|
|
8
|
+
* ~/.claude/skills/ (global — primary store)
|
|
9
|
+
* .zora/skills/ (project-local)
|
|
10
|
+
* <package>/skills/ (built-in)
|
|
11
|
+
*
|
|
12
|
+
* If any installed skill has critical findings, logs a warning and optionally
|
|
13
|
+
* blocks session start (configurable via policy.toml).
|
|
14
|
+
*/
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import os from 'node:os';
|
|
17
|
+
import fs from 'node:fs/promises';
|
|
18
|
+
import { scanSkillDir, formatScanReport } from './skill-scanner.js';
|
|
19
|
+
import { getSkillLayers } from './skill-loader.js';
|
|
20
|
+
// ─── Auditor ─────────────────────────────────────────────────────────────────
|
|
21
|
+
export async function auditInstalledSkills(options = {}) {
|
|
22
|
+
const threshold = options.severityThreshold ?? 'high';
|
|
23
|
+
// Collect skill directories to scan
|
|
24
|
+
// Includes ~/.claude/skills/ (where Claude Code skills actually live) in addition
|
|
25
|
+
// to the Zora skill layers (.zora/skills/, ~/.zora/skills/, built-in)
|
|
26
|
+
const claudeSkillsDir = path.join(os.homedir(), '.claude', 'skills');
|
|
27
|
+
const layers = options.skillsDirs
|
|
28
|
+
? options.skillsDirs.map((d) => ({ dir: d }))
|
|
29
|
+
: [{ dir: claudeSkillsDir }, ...getSkillLayers()];
|
|
30
|
+
const flagged = [];
|
|
31
|
+
let totalSkills = 0;
|
|
32
|
+
for (const { dir } of layers) {
|
|
33
|
+
let entries;
|
|
34
|
+
try {
|
|
35
|
+
const dirents = await fs.readdir(dir, { withFileTypes: true });
|
|
36
|
+
entries = dirents.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
continue; // layer doesn't exist — fine
|
|
40
|
+
}
|
|
41
|
+
for (const skillName of entries) {
|
|
42
|
+
const skillDir = path.join(dir, skillName);
|
|
43
|
+
// Must contain SKILL.md to be a valid skill
|
|
44
|
+
try {
|
|
45
|
+
await fs.access(path.join(skillDir, 'SKILL.md'));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
totalSkills++;
|
|
51
|
+
const result = await scanSkillDir(skillDir, { severityThreshold: threshold });
|
|
52
|
+
if (!result.passed) {
|
|
53
|
+
flagged.push(result);
|
|
54
|
+
if (options.failFast)
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (options.failFast && flagged.length > 0)
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
const clean = flagged.length === 0;
|
|
62
|
+
const summaryLines = [
|
|
63
|
+
`Skill audit: ${totalSkills} installed skill(s) checked`,
|
|
64
|
+
clean
|
|
65
|
+
? `✅ All skills passed (threshold: ${threshold})`
|
|
66
|
+
: `⚠️ ${flagged.length} skill(s) flagged — may have been installed without security scan`,
|
|
67
|
+
];
|
|
68
|
+
for (const r of flagged) {
|
|
69
|
+
summaryLines.push(formatScanReport(r));
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
clean,
|
|
73
|
+
totalSkills,
|
|
74
|
+
flaggedSkills: flagged,
|
|
75
|
+
summary: summaryLines.join('\n'),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Lightweight check — returns true if any installed skill has critical findings.
|
|
80
|
+
* Used by SessionStart hook for a fast gate without full report.
|
|
81
|
+
*/
|
|
82
|
+
export async function hasUnsafeInstalledSkills() {
|
|
83
|
+
const report = await auditInstalledSkills({
|
|
84
|
+
severityThreshold: 'critical',
|
|
85
|
+
failFast: true,
|
|
86
|
+
});
|
|
87
|
+
return !report.clean;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=skill-auditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-auditor.js","sourceRoot":"","sources":["../../src/skills/skill-auditor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SkillInstaller — Extracts and installs .skill / .zip packages.
|
|
3
|
+
*
|
|
4
|
+
* A .skill file is a renamed .zip containing a skill directory:
|
|
5
|
+
* skill-name/
|
|
6
|
+
* SKILL.md (required)
|
|
7
|
+
* scripts/ (optional)
|
|
8
|
+
* references/ (optional)
|
|
9
|
+
* assets/ (optional)
|
|
10
|
+
*
|
|
11
|
+
* Flow:
|
|
12
|
+
* 1. Validate extension (.skill or .zip)
|
|
13
|
+
* 2. Extract to temp dir
|
|
14
|
+
* 3. Validate structure (SKILL.md present, name matches dir)
|
|
15
|
+
* 4. Run security scan
|
|
16
|
+
* 5. If clean (or --force): move to target skills dir
|
|
17
|
+
* 6. Cleanup temp dir
|
|
18
|
+
*/
|
|
19
|
+
import { type FindingSeverity } from './skill-scanner.js';
|
|
20
|
+
export interface InstallOptions {
|
|
21
|
+
/** Install to .zora/skills/ (project-local) instead of ~/.claude/skills/ (global) */
|
|
22
|
+
target?: 'global' | 'project';
|
|
23
|
+
/** Block installs with findings at or above this severity (default: high) */
|
|
24
|
+
severityThreshold?: FindingSeverity;
|
|
25
|
+
/** Install despite security findings */
|
|
26
|
+
force?: boolean;
|
|
27
|
+
/** Scan only — do not install */
|
|
28
|
+
dryRun?: boolean;
|
|
29
|
+
/** Override project directory for 'project' target (defaults to cwd) */
|
|
30
|
+
cwd?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface InstallResult {
|
|
33
|
+
skillName: string;
|
|
34
|
+
installed: boolean;
|
|
35
|
+
installPath?: string;
|
|
36
|
+
scanPassed: boolean;
|
|
37
|
+
report: string;
|
|
38
|
+
blockedBy?: string;
|
|
39
|
+
}
|
|
40
|
+
export declare function installSkill(skillFilePath: string, options?: InstallOptions): Promise<InstallResult>;
|
|
41
|
+
//# sourceMappingURL=skill-installer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-installer.d.ts","sourceRoot":"","sources":["../../src/skills/skill-installer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAMH,OAAO,EAAkC,KAAK,eAAe,EAAiB,MAAM,oBAAoB,CAAC;AAIzG,MAAM,WAAW,cAAc;IAC7B,qFAAqF;IACrF,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC9B,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,eAAe,CAAC;IACpC,wCAAwC;IACxC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iCAAiC;IACjC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAwBD,wBAAsB,YAAY,CAChC,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC,CAmHxB"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SkillInstaller — Extracts and installs .skill / .zip packages.
|
|
3
|
+
*
|
|
4
|
+
* A .skill file is a renamed .zip containing a skill directory:
|
|
5
|
+
* skill-name/
|
|
6
|
+
* SKILL.md (required)
|
|
7
|
+
* scripts/ (optional)
|
|
8
|
+
* references/ (optional)
|
|
9
|
+
* assets/ (optional)
|
|
10
|
+
*
|
|
11
|
+
* Flow:
|
|
12
|
+
* 1. Validate extension (.skill or .zip)
|
|
13
|
+
* 2. Extract to temp dir
|
|
14
|
+
* 3. Validate structure (SKILL.md present, name matches dir)
|
|
15
|
+
* 4. Run security scan
|
|
16
|
+
* 5. If clean (or --force): move to target skills dir
|
|
17
|
+
* 6. Cleanup temp dir
|
|
18
|
+
*/
|
|
19
|
+
import fs from 'node:fs/promises';
|
|
20
|
+
import path from 'node:path';
|
|
21
|
+
import os from 'node:os';
|
|
22
|
+
import AdmZip from 'adm-zip';
|
|
23
|
+
import { scanSkillDir, formatScanReport, SEVERITY_RANK } from './skill-scanner.js';
|
|
24
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
25
|
+
function getTargetDir(options) {
|
|
26
|
+
if (options.target === 'project') {
|
|
27
|
+
return path.join(options.cwd ?? process.cwd(), '.zora', 'skills');
|
|
28
|
+
}
|
|
29
|
+
return path.join(os.homedir(), '.claude', 'skills');
|
|
30
|
+
}
|
|
31
|
+
/** Parse name from SKILL.md frontmatter */
|
|
32
|
+
async function readSkillName(skillMdPath) {
|
|
33
|
+
try {
|
|
34
|
+
const content = await fs.readFile(skillMdPath, 'utf-8');
|
|
35
|
+
const match = content.match(/^---\n[\s\S]*?name:\s*([^\n]+)/m);
|
|
36
|
+
return match?.[1]?.trim() ?? null;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// ─── Installer ───────────────────────────────────────────────────────────────
|
|
43
|
+
export async function installSkill(skillFilePath, options = {}) {
|
|
44
|
+
const ext = path.extname(skillFilePath).toLowerCase();
|
|
45
|
+
if (ext !== '.skill' && ext !== '.zip') {
|
|
46
|
+
throw new Error(`Expected a .skill or .zip file, got: ${ext}`);
|
|
47
|
+
}
|
|
48
|
+
// 1. Extract to temp dir
|
|
49
|
+
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'zora-skill-'));
|
|
50
|
+
try {
|
|
51
|
+
let zip;
|
|
52
|
+
try {
|
|
53
|
+
zip = new AdmZip(skillFilePath);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
throw new Error(`Cannot read archive: ${err instanceof Error ? err.message : String(err)}`);
|
|
57
|
+
}
|
|
58
|
+
zip.extractAllTo(tempDir, true);
|
|
59
|
+
// 2. Find the skill directory inside the extracted content
|
|
60
|
+
// The archive should contain exactly one top-level directory.
|
|
61
|
+
const entries = await fs.readdir(tempDir, { withFileTypes: true });
|
|
62
|
+
const dirs = entries.filter((e) => e.isDirectory());
|
|
63
|
+
if (dirs.length === 0) {
|
|
64
|
+
throw new Error('Archive contains no directory. Expected: skill-name/SKILL.md');
|
|
65
|
+
}
|
|
66
|
+
if (dirs.length > 1) {
|
|
67
|
+
throw new Error(`Archive contains ${dirs.length} top-level directories. Expected exactly one skill directory.`);
|
|
68
|
+
}
|
|
69
|
+
const skillDir = path.join(tempDir, dirs[0].name);
|
|
70
|
+
const dirName = dirs[0].name;
|
|
71
|
+
// 3. Validate SKILL.md present
|
|
72
|
+
const skillMdPath = path.join(skillDir, 'SKILL.md');
|
|
73
|
+
try {
|
|
74
|
+
await fs.access(skillMdPath);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
throw new Error(`Archive is missing SKILL.md in ${dirName}/. Not a valid skill package.`);
|
|
78
|
+
}
|
|
79
|
+
// 4. Validate name in SKILL.md matches directory name
|
|
80
|
+
const declaredName = await readSkillName(skillMdPath);
|
|
81
|
+
if (declaredName && declaredName !== dirName) {
|
|
82
|
+
throw new Error(`SKILL.md declares name: "${declaredName}" but directory is named "${dirName}". ` +
|
|
83
|
+
`Per spec, they must match.`);
|
|
84
|
+
}
|
|
85
|
+
const skillName = declaredName ?? dirName;
|
|
86
|
+
// 5. Security scan
|
|
87
|
+
const scanResult = await scanSkillDir(skillDir, {
|
|
88
|
+
severityThreshold: options.severityThreshold ?? 'high',
|
|
89
|
+
});
|
|
90
|
+
const report = formatScanReport(scanResult);
|
|
91
|
+
if (!scanResult.passed && !options.force) {
|
|
92
|
+
const threshold = options.severityThreshold ?? 'high';
|
|
93
|
+
const thresholdRank = SEVERITY_RANK[threshold] ?? 0;
|
|
94
|
+
const blockedCount = scanResult.findings.filter((f) => (SEVERITY_RANK[f.severity] ?? 0) >= thresholdRank).length;
|
|
95
|
+
return {
|
|
96
|
+
skillName,
|
|
97
|
+
installed: false,
|
|
98
|
+
scanPassed: false,
|
|
99
|
+
report,
|
|
100
|
+
blockedBy: `${blockedCount} finding(s) at or above ${threshold} severity. Use --force to override.`,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
if (options.dryRun) {
|
|
104
|
+
return {
|
|
105
|
+
skillName,
|
|
106
|
+
installed: false,
|
|
107
|
+
scanPassed: scanResult.passed,
|
|
108
|
+
report: report + '\n\n[dry-run] Scan complete. Not installed.',
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
// 6. Atomic install — copy to temp dir in target, then rename
|
|
112
|
+
// This ensures a valid version (old or new) always exists if something fails mid-copy
|
|
113
|
+
const targetBase = getTargetDir(options);
|
|
114
|
+
await fs.mkdir(targetBase, { recursive: true });
|
|
115
|
+
const installPath = path.join(targetBase, dirName);
|
|
116
|
+
const stagingPath = path.join(targetBase, `.${dirName}.installing`);
|
|
117
|
+
// Copy to staging first
|
|
118
|
+
await fs.cp(skillDir, stagingPath, { recursive: true });
|
|
119
|
+
// Atomic rename: removes old and puts new in place in one step
|
|
120
|
+
try {
|
|
121
|
+
await fs.rename(stagingPath, installPath);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// rename can fail cross-device — fall back to rm + rename
|
|
125
|
+
await fs.rm(installPath, { recursive: true, force: true });
|
|
126
|
+
await fs.rename(stagingPath, installPath);
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
skillName,
|
|
130
|
+
installed: true,
|
|
131
|
+
installPath,
|
|
132
|
+
scanPassed: scanResult.passed,
|
|
133
|
+
report,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
// Always clean up temp dir
|
|
138
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=skill-installer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-installer.js","sourceRoot":"","sources":["../../src/skills/skill-installer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SkillScanner — Security scanner for .skill / .zip packages before install.
|
|
3
|
+
*
|
|
4
|
+
* Scans extracted skill directories using:
|
|
5
|
+
* - @nodesecure/js-x-ray: AST-based analysis of JS/TS scripts
|
|
6
|
+
* - Custom checks: SKILL.md allowed-tools validation, shell script patterns,
|
|
7
|
+
* hardcoded secrets, curl|bash patterns
|
|
8
|
+
*
|
|
9
|
+
* Agent Skills spec: https://agentskills.io/specification
|
|
10
|
+
*/
|
|
11
|
+
export type FindingSeverity = 'critical' | 'high' | 'medium' | 'low' | 'info';
|
|
12
|
+
export interface ScanFinding {
|
|
13
|
+
severity: FindingSeverity;
|
|
14
|
+
file: string;
|
|
15
|
+
line?: number;
|
|
16
|
+
kind: string;
|
|
17
|
+
message: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ScanResult {
|
|
20
|
+
skillName: string;
|
|
21
|
+
passed: boolean;
|
|
22
|
+
findings: ScanFinding[];
|
|
23
|
+
scannedFiles: number;
|
|
24
|
+
}
|
|
25
|
+
export declare const SEVERITY_RANK: Record<FindingSeverity, number>;
|
|
26
|
+
export declare function scanSkillDir(skillDir: string, options?: {
|
|
27
|
+
severityThreshold?: FindingSeverity;
|
|
28
|
+
}): Promise<ScanResult>;
|
|
29
|
+
export declare function formatScanReport(result: ScanResult): string;
|
|
30
|
+
//# sourceMappingURL=skill-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-scanner.d.ts","sourceRoot":"","sources":["../../src/skills/skill-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAE9E,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,eAAe,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB;AAqDD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAEzD,CAAC;AA+HF,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,iBAAiB,CAAC,EAAE,eAAe,CAAA;CAAO,GACpD,OAAO,CAAC,UAAU,CAAC,CA2DrB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAoB3D"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SkillScanner — Security scanner for .skill / .zip packages before install.
|
|
3
|
+
*
|
|
4
|
+
* Scans extracted skill directories using:
|
|
5
|
+
* - @nodesecure/js-x-ray: AST-based analysis of JS/TS scripts
|
|
6
|
+
* - Custom checks: SKILL.md allowed-tools validation, shell script patterns,
|
|
7
|
+
* hardcoded secrets, curl|bash patterns
|
|
8
|
+
*
|
|
9
|
+
* Agent Skills spec: https://agentskills.io/specification
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'node:fs/promises';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { AstAnalyser } from '@nodesecure/js-x-ray';
|
|
14
|
+
// ─── Severity Maps ──────────────────────────────────────────────────────────
|
|
15
|
+
// js-x-ray warning kind → severity
|
|
16
|
+
const JS_WARNING_SEVERITY = {
|
|
17
|
+
'obfuscated-code': 'critical',
|
|
18
|
+
'data-exfiltration': 'critical',
|
|
19
|
+
'serialize-environment': 'critical',
|
|
20
|
+
'encoded-literal': 'high',
|
|
21
|
+
'unsafe-stmt': 'high', // eval, Function()
|
|
22
|
+
'unsafe-import': 'high',
|
|
23
|
+
'unsafe-command': 'high',
|
|
24
|
+
'shady-link': 'medium',
|
|
25
|
+
'suspicious-literal': 'medium',
|
|
26
|
+
'suspicious-file': 'medium',
|
|
27
|
+
'weak-crypto': 'medium',
|
|
28
|
+
'unsafe-regex': 'low',
|
|
29
|
+
'short-identifiers': 'low',
|
|
30
|
+
'synchronous-io': 'info',
|
|
31
|
+
'parsing-error': 'info',
|
|
32
|
+
};
|
|
33
|
+
// allowed-tools entries that should block install at high severity
|
|
34
|
+
// NOTE: Bash(*) is intentionally excluded here — it has its own critical check below
|
|
35
|
+
// to avoid being downgraded to high by the deduplication step
|
|
36
|
+
const DANGEROUS_TOOL_PATTERNS = [
|
|
37
|
+
/Bash\(sudo/i,
|
|
38
|
+
/Bash\(rm\b/i,
|
|
39
|
+
/Bash\(curl\b/i,
|
|
40
|
+
/Bash\(wget\b/i,
|
|
41
|
+
/Bash\(chmod\b/i,
|
|
42
|
+
/Bash\(chown\b/i,
|
|
43
|
+
];
|
|
44
|
+
// Shell script dangerous patterns (regex → message)
|
|
45
|
+
const SHELL_DANGER_PATTERNS = [
|
|
46
|
+
{ re: /curl\s+[^|]*\|\s*(ba)?sh/i, severity: 'critical', message: 'curl | bash — remote code execution pattern' },
|
|
47
|
+
{ re: /wget\s+[^|]*\|\s*(ba)?sh/i, severity: 'critical', message: 'wget | bash — remote code execution pattern' },
|
|
48
|
+
{ re: /eval\s*\$\(/, severity: 'high', message: 'eval $(...) — dynamic shell execution' },
|
|
49
|
+
{ re: /base64\s+(-d|--decode)/i, severity: 'high', message: 'base64 decode — possible obfuscated payload' },
|
|
50
|
+
{ re: /\/dev\/tcp\//, severity: 'critical', message: '/dev/tcp reverse shell pattern' },
|
|
51
|
+
{ re: /(ANTHROPIC|OPENAI|AWS|GITHUB)_.*KEY/i, severity: 'high', message: 'Possible hardcoded API key or credential' },
|
|
52
|
+
];
|
|
53
|
+
// Hardcoded secret patterns for any file
|
|
54
|
+
const SECRET_PATTERNS = [
|
|
55
|
+
{ re: /sk-[A-Za-z0-9]{20,}/, severity: 'high', message: 'Possible OpenAI/Anthropic API key' },
|
|
56
|
+
{ re: /AKIA[A-Z0-9]{16}/, severity: 'high', message: 'Possible AWS access key' },
|
|
57
|
+
{ re: /ghp_[A-Za-z0-9]{36}/, severity: 'high', message: 'Possible GitHub personal access token' },
|
|
58
|
+
{ re: /xoxb-[A-Za-z0-9\-]+/, severity: 'high', message: 'Possible Slack bot token' },
|
|
59
|
+
];
|
|
60
|
+
export const SEVERITY_RANK = {
|
|
61
|
+
critical: 4, high: 3, medium: 2, low: 1, info: 0,
|
|
62
|
+
};
|
|
63
|
+
// ─── File Helpers ────────────────────────────────────────────────────────────
|
|
64
|
+
const MAX_WALK_DEPTH = 10;
|
|
65
|
+
async function walkDir(dir, depth = 0) {
|
|
66
|
+
if (depth > MAX_WALK_DEPTH)
|
|
67
|
+
return [];
|
|
68
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
69
|
+
const files = [];
|
|
70
|
+
for (const e of entries) {
|
|
71
|
+
const full = path.join(dir, e.name);
|
|
72
|
+
if (e.isDirectory()) {
|
|
73
|
+
files.push(...await walkDir(full, depth + 1));
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
files.push(full);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return files;
|
|
80
|
+
}
|
|
81
|
+
// ─── Individual Scanners ─────────────────────────────────────────────────────
|
|
82
|
+
function scanJsTs(code, relPath) {
|
|
83
|
+
const analyser = new AstAnalyser();
|
|
84
|
+
let result;
|
|
85
|
+
try {
|
|
86
|
+
result = analyser.analyse(code, { isMinified: false });
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return []; // parse error — js-x-ray handles parsing-error in warnings
|
|
90
|
+
}
|
|
91
|
+
return result.warnings.map((w) => ({
|
|
92
|
+
severity: JS_WARNING_SEVERITY[w.kind] ?? 'low',
|
|
93
|
+
file: relPath,
|
|
94
|
+
line: extractLine(w.location),
|
|
95
|
+
kind: String(w.kind),
|
|
96
|
+
message: `${w.kind}${'value' in w && w.value ? ': ' + String(w.value) : ''}`,
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
function extractLine(location) {
|
|
100
|
+
if (!location)
|
|
101
|
+
return undefined;
|
|
102
|
+
if (typeof location === 'number')
|
|
103
|
+
return location;
|
|
104
|
+
// [[startLine, startCol], [endLine, endCol]]
|
|
105
|
+
if (Array.isArray(location) && Array.isArray(location[0]))
|
|
106
|
+
return location[0][0];
|
|
107
|
+
// [startLine, startCol]
|
|
108
|
+
if (Array.isArray(location) && typeof location[0] === 'number')
|
|
109
|
+
return location[0];
|
|
110
|
+
// { start: { line, column } }
|
|
111
|
+
if (typeof location === 'object' && 'start' in location) {
|
|
112
|
+
const start = location.start;
|
|
113
|
+
if (typeof start === 'number')
|
|
114
|
+
return start;
|
|
115
|
+
if (typeof start === 'object' && start !== null && 'line' in start)
|
|
116
|
+
return start.line;
|
|
117
|
+
}
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
function scanShell(code, relPath) {
|
|
121
|
+
const findings = [];
|
|
122
|
+
const lines = code.split('\n');
|
|
123
|
+
for (const { re, severity, message } of SHELL_DANGER_PATTERNS) {
|
|
124
|
+
for (let i = 0; i < lines.length; i++) {
|
|
125
|
+
if (re.test(lines[i])) {
|
|
126
|
+
findings.push({ severity, file: relPath, line: i + 1, kind: 'shell-pattern', message });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return findings;
|
|
131
|
+
}
|
|
132
|
+
function scanSecrets(code, relPath) {
|
|
133
|
+
const findings = [];
|
|
134
|
+
const lines = code.split('\n');
|
|
135
|
+
for (const { re, severity, message } of SECRET_PATTERNS) {
|
|
136
|
+
for (let i = 0; i < lines.length; i++) {
|
|
137
|
+
if (re.test(lines[i])) {
|
|
138
|
+
findings.push({ severity, file: relPath, line: i + 1, kind: 'hardcoded-secret', message });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return findings;
|
|
143
|
+
}
|
|
144
|
+
function scanAllowedTools(frontmatter, relPath) {
|
|
145
|
+
const lines = frontmatter.split('\n');
|
|
146
|
+
const startIdx = lines.findIndex((line) => /allowed-tools\s*:/.test(line));
|
|
147
|
+
if (startIdx === -1)
|
|
148
|
+
return [];
|
|
149
|
+
// Collect the full allowed-tools block including YAML list items on subsequent lines
|
|
150
|
+
// Stop when we hit the next YAML key (non-indented line that looks like "key:")
|
|
151
|
+
const toolsLines = [];
|
|
152
|
+
for (let i = startIdx; i < lines.length; i++) {
|
|
153
|
+
const line = lines[i];
|
|
154
|
+
if (i !== startIdx && /^[A-Za-z_-]+\s*:/.test(line))
|
|
155
|
+
break;
|
|
156
|
+
toolsLines.push(line);
|
|
157
|
+
}
|
|
158
|
+
const toolsBlock = toolsLines.join('\n');
|
|
159
|
+
const findings = [];
|
|
160
|
+
// Bash(*) is critical — check first, dedupe key differs from generic high findings
|
|
161
|
+
if (/Bash\(\*\)/.test(toolsBlock)) {
|
|
162
|
+
findings.push({
|
|
163
|
+
severity: 'critical',
|
|
164
|
+
file: relPath,
|
|
165
|
+
kind: 'dangerous-allowed-tools-wildcard',
|
|
166
|
+
message: 'SKILL.md declares Bash(*) — unrestricted shell access',
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
// Other dangerous patterns → high
|
|
170
|
+
for (const pattern of DANGEROUS_TOOL_PATTERNS) {
|
|
171
|
+
if (pattern.test(toolsBlock)) {
|
|
172
|
+
findings.push({
|
|
173
|
+
severity: 'high',
|
|
174
|
+
file: relPath,
|
|
175
|
+
kind: 'dangerous-allowed-tools',
|
|
176
|
+
message: `SKILL.md declares dangerous allowed-tools: ${toolsLines[0].trim()}`,
|
|
177
|
+
});
|
|
178
|
+
break; // one high finding per block is enough
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return findings;
|
|
182
|
+
}
|
|
183
|
+
// ─── Main Scanner ────────────────────────────────────────────────────────────
|
|
184
|
+
export async function scanSkillDir(skillDir, options = {}) {
|
|
185
|
+
const threshold = options.severityThreshold ?? 'high';
|
|
186
|
+
const thresholdRank = SEVERITY_RANK[threshold];
|
|
187
|
+
const allFiles = await walkDir(skillDir);
|
|
188
|
+
const findings = [];
|
|
189
|
+
let scannedFiles = 0;
|
|
190
|
+
// Detect skill name from directory
|
|
191
|
+
const skillName = path.basename(skillDir);
|
|
192
|
+
for (const absPath of allFiles) {
|
|
193
|
+
const relPath = path.relative(skillDir, absPath);
|
|
194
|
+
const ext = path.extname(absPath).toLowerCase();
|
|
195
|
+
let code;
|
|
196
|
+
try {
|
|
197
|
+
code = await fs.readFile(absPath, 'utf-8');
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
scannedFiles++;
|
|
203
|
+
// JS/TS AST scan
|
|
204
|
+
if (['.js', '.mjs', '.cjs', '.ts', '.tsx'].includes(ext)) {
|
|
205
|
+
findings.push(...scanJsTs(code, relPath));
|
|
206
|
+
}
|
|
207
|
+
// Shell script scan
|
|
208
|
+
if (['.sh', '.bash', '.zsh'].includes(ext) || relPath.startsWith('scripts/')) {
|
|
209
|
+
findings.push(...scanShell(code, relPath));
|
|
210
|
+
}
|
|
211
|
+
// SKILL.md — validate frontmatter + allowed-tools
|
|
212
|
+
if (path.basename(absPath) === 'SKILL.md') {
|
|
213
|
+
const frontmatterMatch = code.match(/^---\n([\s\S]*?)\n---/);
|
|
214
|
+
if (frontmatterMatch) {
|
|
215
|
+
findings.push(...scanAllowedTools(frontmatterMatch[1], relPath));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Secret scan on all text files
|
|
219
|
+
if (['.js', '.mjs', '.cjs', '.ts', '.tsx', '.sh', '.bash', '.py', '.md', '.env', '.toml', '.yaml', '.yml'].includes(ext)) {
|
|
220
|
+
findings.push(...scanSecrets(code, relPath));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// Deduplicate exact duplicates
|
|
224
|
+
const unique = findings.filter((f, i, arr) => arr.findIndex((x) => x.file === f.file && x.line === f.line && x.kind === f.kind) === i);
|
|
225
|
+
// Sort by severity desc
|
|
226
|
+
unique.sort((a, b) => SEVERITY_RANK[b.severity] - SEVERITY_RANK[a.severity]);
|
|
227
|
+
const passed = !unique.some((f) => SEVERITY_RANK[f.severity] >= thresholdRank);
|
|
228
|
+
return { skillName, passed, findings: unique, scannedFiles };
|
|
229
|
+
}
|
|
230
|
+
export function formatScanReport(result) {
|
|
231
|
+
const icon = {
|
|
232
|
+
critical: '🔴', high: '🟠', medium: '🟡', low: '🔵', info: '⚪',
|
|
233
|
+
};
|
|
234
|
+
const lines = [
|
|
235
|
+
`\nScan: ${result.skillName} (${result.scannedFiles} files)`,
|
|
236
|
+
result.passed ? '✅ Passed' : '❌ Blocked — findings above threshold',
|
|
237
|
+
];
|
|
238
|
+
if (result.findings.length === 0) {
|
|
239
|
+
lines.push(' No findings.');
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
for (const f of result.findings) {
|
|
243
|
+
const loc = f.line ? `:${f.line}` : '';
|
|
244
|
+
lines.push(` ${icon[f.severity]} [${f.severity.toUpperCase()}] ${f.file}${loc} — ${f.message}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return lines.join('\n');
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=skill-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-scanner.js","sourceRoot":"","sources":["../../src/skills/skill-scanner.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC"}
|
package/dist/tools/index.js
CHANGED
package/dist/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC"}
|