soturail 0.2.2 → 0.3.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 +55 -10
- package/dist/cli.js +11 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/bench.d.ts +1 -1
- package/dist/commands/bench.js +126 -2
- package/dist/commands/bench.js.map +1 -1
- package/dist/commands/context.d.ts +2 -0
- package/dist/commands/context.js +27 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/hooks.d.ts +3 -0
- package/dist/commands/hooks.js +32 -8
- package/dist/commands/hooks.js.map +1 -1
- package/dist/commands/mcp.d.ts +2 -0
- package/dist/commands/mcp.js +21 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/memory.d.ts +1 -0
- package/dist/commands/memory.js +2 -1
- package/dist/commands/memory.js.map +1 -1
- package/dist/commands/release.d.ts +3 -0
- package/dist/commands/release.js +227 -0
- package/dist/commands/release.js.map +1 -0
- package/dist/commands/skills.d.ts +2 -0
- package/dist/commands/skills.js +43 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/core/config.d.ts +5 -0
- package/dist/core/config.js +12 -2
- package/dist/core/config.js.map +1 -1
- package/dist/core/context-pack.d.ts +13 -0
- package/dist/core/context-pack.js +102 -0
- package/dist/core/context-pack.js.map +1 -0
- package/dist/core/mcp-resources.d.ts +13 -0
- package/dist/core/mcp-resources.js +46 -0
- package/dist/core/mcp-resources.js.map +1 -0
- package/dist/core/mcp-server.d.ts +14 -0
- package/dist/core/mcp-server.js +81 -0
- package/dist/core/mcp-server.js.map +1 -0
- package/dist/core/mcp-tools.d.ts +7 -0
- package/dist/core/mcp-tools.js +73 -0
- package/dist/core/mcp-tools.js.map +1 -0
- package/dist/core/release-preflight.d.ts +22 -0
- package/dist/core/release-preflight.js +201 -0
- package/dist/core/release-preflight.js.map +1 -0
- package/dist/core/skill-exporter.d.ts +3 -0
- package/dist/core/skill-exporter.js +72 -0
- package/dist/core/skill-exporter.js.map +1 -0
- package/dist/core/skill-schema.d.ts +55 -0
- package/dist/core/skill-schema.js +84 -0
- package/dist/core/skill-schema.js.map +1 -0
- package/dist/core/skill-store.d.ts +4 -0
- package/dist/core/skill-store.js +92 -0
- package/dist/core/skill-store.js.map +1 -0
- package/dist/core/skill-validator.d.ts +12 -0
- package/dist/core/skill-validator.js +94 -0
- package/dist/core/skill-validator.js.map +1 -0
- package/dist/core/version.d.ts +1 -0
- package/dist/core/version.js +3 -0
- package/dist/core/version.js.map +1 -0
- package/docs/benchmarking.md +6 -1
- package/docs/comparisons.md +35 -0
- package/docs/context-packs.md +29 -0
- package/docs/examples/skills/README.md +11 -0
- package/docs/hooks/claude.md +6 -4
- package/docs/hooks/codex.md +4 -3
- package/docs/hooks/cursor.md +4 -3
- package/docs/hooks/gemini.md +4 -3
- package/docs/hooks/mcp.md +10 -0
- package/docs/hooks.md +12 -16
- package/docs/mcp.md +18 -0
- package/docs/release-checklist.md +44 -1
- package/docs/release-workflow.md +41 -18
- package/docs/security-model.md +6 -0
- package/docs/skill-rail.md +14 -20
- package/docs/usage.md +15 -0
- package/docs/windows.md +22 -1
- package/docs/workflow-rail.md +1 -1
- package/package.json +8 -6
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { ensureWorkspace, getWorkspacePaths } from "./config.js";
|
|
4
|
+
import { readSkills } from "./skill-store.js";
|
|
5
|
+
import { validateSkills } from "./skill-validator.js";
|
|
6
|
+
export async function exportSkills(target, root = process.cwd()) {
|
|
7
|
+
await ensureWorkspace(root);
|
|
8
|
+
const validation = await validateSkills(root);
|
|
9
|
+
if (!validation.ok) {
|
|
10
|
+
throw new Error("Cannot export invalid skills. Run soturail skills validate for details.");
|
|
11
|
+
}
|
|
12
|
+
const skills = await readSkills(root);
|
|
13
|
+
const paths = getWorkspacePaths(root);
|
|
14
|
+
const targetDir = path.join(paths.skillExportsDir, target);
|
|
15
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
16
|
+
const written = [];
|
|
17
|
+
for (const skill of skills) {
|
|
18
|
+
const filePath = path.join(targetDir, `${skill.metadata.id}.md`);
|
|
19
|
+
await fs.writeFile(filePath, renderTargetSkill(target, skill.metadata.id, skill.markdown), "utf8");
|
|
20
|
+
written.push(path.normalize(path.relative(root, filePath)));
|
|
21
|
+
}
|
|
22
|
+
const indexPath = path.join(targetDir, "index.md");
|
|
23
|
+
await fs.writeFile(indexPath, renderExportIndex(target, skills.map((skill) => skill.metadata.id)), "utf8");
|
|
24
|
+
written.push(path.normalize(path.relative(root, indexPath)));
|
|
25
|
+
return `Exported ${skills.length} skill(s) for ${target}:\n${written.join("\n")}\n`;
|
|
26
|
+
}
|
|
27
|
+
export async function packSkills(format, root = process.cwd()) {
|
|
28
|
+
await ensureWorkspace(root);
|
|
29
|
+
const skills = await readSkills(root);
|
|
30
|
+
const paths = getWorkspacePaths(root);
|
|
31
|
+
const filePath = path.join(paths.skillExportsDir, `skills-pack.${format === "json" ? "json" : "md"}`);
|
|
32
|
+
const payload = format === "json"
|
|
33
|
+
? `${JSON.stringify(skills.map((skill) => ({ metadata: skill.metadata, markdown: skill.markdown })), null, 2)}\n`
|
|
34
|
+
: skills.map((skill) => renderTargetSkill("generic", skill.metadata.id, skill.markdown)).join("\n---\n");
|
|
35
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
36
|
+
await fs.writeFile(filePath, payload, "utf8");
|
|
37
|
+
return `Skill pack written: ${path.normalize(path.relative(root, filePath))}\n`;
|
|
38
|
+
}
|
|
39
|
+
function renderTargetSkill(target, id, markdown) {
|
|
40
|
+
const header = [
|
|
41
|
+
`# SotuRail Skill: ${id}`,
|
|
42
|
+
"",
|
|
43
|
+
`Target: ${target}`,
|
|
44
|
+
"Generated by SotuRail Skill Rail as an independent local-first export.",
|
|
45
|
+
"",
|
|
46
|
+
"Safety constraints:",
|
|
47
|
+
"- Do not run destructive shell commands.",
|
|
48
|
+
"- Do not exfiltrate secrets.",
|
|
49
|
+
"- Ask for human approval before remote writes or destructive actions.",
|
|
50
|
+
"- Treat this export as project-local guidance, not a marketplace install.",
|
|
51
|
+
""
|
|
52
|
+
];
|
|
53
|
+
const targetNote = {
|
|
54
|
+
claude: "Claude usage: place this in a reviewed skill/rules location supported by your installed Claude Code version.",
|
|
55
|
+
codex: "Codex usage: include this in AGENTS.md or project rules after review.",
|
|
56
|
+
gemini: "Gemini usage: include this as concise project guidance after review.",
|
|
57
|
+
cursor: "Cursor usage: include this in .cursor/rules after review.",
|
|
58
|
+
generic: "Generic usage: portable Markdown guidance for local AI agent workflows."
|
|
59
|
+
};
|
|
60
|
+
return `${header.join("\n")}${targetNote[target]}\n\n${markdown.trim()}\n`;
|
|
61
|
+
}
|
|
62
|
+
function renderExportIndex(target, ids) {
|
|
63
|
+
return [
|
|
64
|
+
`# SotuRail ${target} Skill Export`,
|
|
65
|
+
"",
|
|
66
|
+
"Review all generated files before enabling them in an agent host.",
|
|
67
|
+
"",
|
|
68
|
+
...ids.map((id) => `- [${id}](./${id}.md)`),
|
|
69
|
+
""
|
|
70
|
+
].join("\n");
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=skill-exporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-exporter.js","sourceRoot":"","sources":["../../src/core/skill-exporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const SkillTargetSchema: z.ZodEnum<["claude", "codex", "gemini", "cursor", "generic"]>;
|
|
3
|
+
export type SkillTarget = z.infer<typeof SkillTargetSchema>;
|
|
4
|
+
export declare const SkillMetadataSchema: z.ZodObject<{
|
|
5
|
+
id: z.ZodString;
|
|
6
|
+
name: z.ZodString;
|
|
7
|
+
description: z.ZodString;
|
|
8
|
+
version: z.ZodString;
|
|
9
|
+
author: z.ZodString;
|
|
10
|
+
risk_level: z.ZodEnum<["low", "medium", "high"]>;
|
|
11
|
+
targets: z.ZodArray<z.ZodEnum<["claude", "codex", "gemini", "cursor", "generic"]>, "many">;
|
|
12
|
+
allowed_tools: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
13
|
+
forbidden_patterns: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
14
|
+
requires_human_approval: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
15
|
+
created_at: z.ZodString;
|
|
16
|
+
content_hash: z.ZodString;
|
|
17
|
+
}, "strip", z.ZodTypeAny, {
|
|
18
|
+
version: string;
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
description: string;
|
|
22
|
+
author: string;
|
|
23
|
+
risk_level: "low" | "medium" | "high";
|
|
24
|
+
targets: ("claude" | "codex" | "gemini" | "cursor" | "generic")[];
|
|
25
|
+
allowed_tools: string[];
|
|
26
|
+
forbidden_patterns: string[];
|
|
27
|
+
requires_human_approval: string[];
|
|
28
|
+
created_at: string;
|
|
29
|
+
content_hash: string;
|
|
30
|
+
}, {
|
|
31
|
+
version: string;
|
|
32
|
+
id: string;
|
|
33
|
+
name: string;
|
|
34
|
+
description: string;
|
|
35
|
+
author: string;
|
|
36
|
+
risk_level: "low" | "medium" | "high";
|
|
37
|
+
targets: ("claude" | "codex" | "gemini" | "cursor" | "generic")[];
|
|
38
|
+
created_at: string;
|
|
39
|
+
content_hash: string;
|
|
40
|
+
allowed_tools?: string[] | undefined;
|
|
41
|
+
forbidden_patterns?: string[] | undefined;
|
|
42
|
+
requires_human_approval?: string[] | undefined;
|
|
43
|
+
}>;
|
|
44
|
+
export type SkillMetadata = z.infer<typeof SkillMetadataSchema>;
|
|
45
|
+
export interface SkillRecord {
|
|
46
|
+
metadata: SkillMetadata;
|
|
47
|
+
markdown: string;
|
|
48
|
+
dir: string;
|
|
49
|
+
}
|
|
50
|
+
export declare const defaultForbiddenPatterns: string[];
|
|
51
|
+
export declare const defaultHumanApprovals: string[];
|
|
52
|
+
export declare function slugifySkillName(name: string): string;
|
|
53
|
+
export declare function stableSkillHash(metadata: Omit<SkillMetadata, "content_hash">, markdown: string): string;
|
|
54
|
+
export declare function stringifySkillYaml(metadata: SkillMetadata): string;
|
|
55
|
+
export declare function parseSkillYaml(text: string): Record<string, unknown>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export const SkillTargetSchema = z.enum(["claude", "codex", "gemini", "cursor", "generic"]);
|
|
4
|
+
export const SkillMetadataSchema = z.object({
|
|
5
|
+
id: z.string().min(1).regex(/^[a-z0-9][a-z0-9-]*$/),
|
|
6
|
+
name: z.string().min(1),
|
|
7
|
+
description: z.string().min(1),
|
|
8
|
+
version: z.string().min(1),
|
|
9
|
+
author: z.string().min(1),
|
|
10
|
+
risk_level: z.enum(["low", "medium", "high"]),
|
|
11
|
+
targets: z.array(SkillTargetSchema).min(1),
|
|
12
|
+
allowed_tools: z.array(z.string()).default([]),
|
|
13
|
+
forbidden_patterns: z.array(z.string()).default([]),
|
|
14
|
+
requires_human_approval: z.array(z.string()).default([]),
|
|
15
|
+
created_at: z.string().min(1),
|
|
16
|
+
content_hash: z.string().regex(/^[a-f0-9]{64}$/)
|
|
17
|
+
});
|
|
18
|
+
export const defaultForbiddenPatterns = ["rm -rf", "curl | sh", "git push"];
|
|
19
|
+
export const defaultHumanApprovals = ["remote_write", "destructive_command"];
|
|
20
|
+
export function slugifySkillName(name) {
|
|
21
|
+
return name
|
|
22
|
+
.trim()
|
|
23
|
+
.toLowerCase()
|
|
24
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
25
|
+
.replace(/^-+|-+$/g, "")
|
|
26
|
+
.slice(0, 64) || "skill";
|
|
27
|
+
}
|
|
28
|
+
export function stableSkillHash(metadata, markdown) {
|
|
29
|
+
const normalized = JSON.stringify({ ...metadata, content_hash: undefined, markdown });
|
|
30
|
+
return createHash("sha256").update(normalized).digest("hex");
|
|
31
|
+
}
|
|
32
|
+
export function stringifySkillYaml(metadata) {
|
|
33
|
+
const scalar = (value) => value.includes(":") || value.includes("#") ? JSON.stringify(value) : value;
|
|
34
|
+
const lines = [];
|
|
35
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
36
|
+
if (Array.isArray(value)) {
|
|
37
|
+
lines.push(`${key}:`);
|
|
38
|
+
for (const item of value)
|
|
39
|
+
lines.push(` - ${scalar(item)}`);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
lines.push(`${key}: ${scalar(String(value))}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return `${lines.join("\n")}\n`;
|
|
46
|
+
}
|
|
47
|
+
export function parseSkillYaml(text) {
|
|
48
|
+
const result = {};
|
|
49
|
+
let currentArray = null;
|
|
50
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
51
|
+
const line = rawLine.trimEnd();
|
|
52
|
+
if (!line.trim() || line.trimStart().startsWith("#"))
|
|
53
|
+
continue;
|
|
54
|
+
const arrayMatch = line.match(/^([A-Za-z0-9_]+):\s*$/);
|
|
55
|
+
if (arrayMatch?.[1]) {
|
|
56
|
+
currentArray = arrayMatch[1];
|
|
57
|
+
result[currentArray] = [];
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const itemMatch = line.match(/^\s*-\s*(.+)$/);
|
|
61
|
+
if (itemMatch?.[1] && currentArray && Array.isArray(result[currentArray])) {
|
|
62
|
+
result[currentArray].push(unquote(itemMatch[1].trim()));
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const kv = line.match(/^([A-Za-z0-9_]+):\s*(.*)$/);
|
|
66
|
+
if (kv?.[1]) {
|
|
67
|
+
currentArray = null;
|
|
68
|
+
result[kv[1]] = unquote(kv[2] ?? "");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
function unquote(value) {
|
|
74
|
+
if ((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
75
|
+
try {
|
|
76
|
+
return JSON.parse(value);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return value.slice(1, -1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=skill-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-schema.js","sourceRoot":"","sources":["../../src/core/skill-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type SkillRecord } from "./skill-schema.js";
|
|
2
|
+
export declare function createSkill(name: string, root?: string): Promise<SkillRecord>;
|
|
3
|
+
export declare function readSkills(root?: string): Promise<SkillRecord[]>;
|
|
4
|
+
export declare function renderSkillList(skills: SkillRecord[]): string;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { ensureWorkspace, getWorkspacePaths } from "./config.js";
|
|
4
|
+
import { defaultForbiddenPatterns, defaultHumanApprovals, parseSkillYaml, SkillMetadataSchema, slugifySkillName, stableSkillHash, stringifySkillYaml } from "./skill-schema.js";
|
|
5
|
+
export async function createSkill(name, root = process.cwd()) {
|
|
6
|
+
await ensureWorkspace(root);
|
|
7
|
+
const paths = getWorkspacePaths(root);
|
|
8
|
+
const id = slugifySkillName(name);
|
|
9
|
+
const dir = path.join(paths.skillsDir, id);
|
|
10
|
+
const markdown = [
|
|
11
|
+
`# ${name}`,
|
|
12
|
+
"",
|
|
13
|
+
"Use this skill when the task matches the description and the repository owner has approved it.",
|
|
14
|
+
"",
|
|
15
|
+
"## Safety",
|
|
16
|
+
"",
|
|
17
|
+
"- Do not run destructive shell commands.",
|
|
18
|
+
"- Do not exfiltrate secrets.",
|
|
19
|
+
"- Ask for human approval before remote writes or destructive actions.",
|
|
20
|
+
""
|
|
21
|
+
].join("\n");
|
|
22
|
+
const base = {
|
|
23
|
+
id,
|
|
24
|
+
name,
|
|
25
|
+
description: `Safe local-first workflow skill for ${name}.`,
|
|
26
|
+
version: "0.1.0",
|
|
27
|
+
author: "Rafael Ryan Ramos de Souza",
|
|
28
|
+
risk_level: "low",
|
|
29
|
+
targets: ["claude", "codex", "gemini", "cursor"],
|
|
30
|
+
allowed_tools: ["read", "search"],
|
|
31
|
+
forbidden_patterns: defaultForbiddenPatterns,
|
|
32
|
+
requires_human_approval: defaultHumanApprovals,
|
|
33
|
+
created_at: new Date().toISOString()
|
|
34
|
+
};
|
|
35
|
+
const metadata = { ...base, content_hash: stableSkillHash(base, markdown) };
|
|
36
|
+
await fs.mkdir(path.join(dir, "examples"), { recursive: true });
|
|
37
|
+
await fs.mkdir(path.join(dir, "validators"), { recursive: true });
|
|
38
|
+
await fs.writeFile(path.join(dir, "skill.yml"), stringifySkillYaml(metadata), "utf8");
|
|
39
|
+
await fs.writeFile(path.join(dir, "SKILL.md"), markdown, "utf8");
|
|
40
|
+
return { metadata, markdown, dir };
|
|
41
|
+
}
|
|
42
|
+
export async function readSkills(root = process.cwd()) {
|
|
43
|
+
const paths = getWorkspacePaths(root);
|
|
44
|
+
let entries = [];
|
|
45
|
+
try {
|
|
46
|
+
entries = await fs.readdir(paths.skillsDir);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
const skills = [];
|
|
52
|
+
for (const entry of entries) {
|
|
53
|
+
const dir = path.join(paths.skillsDir, entry);
|
|
54
|
+
const stat = await fs.stat(dir).catch(() => null);
|
|
55
|
+
if (!stat?.isDirectory())
|
|
56
|
+
continue;
|
|
57
|
+
const yaml = await fs.readFile(path.join(dir, "skill.yml"), "utf8").catch(() => "");
|
|
58
|
+
const markdown = await fs.readFile(path.join(dir, "SKILL.md"), "utf8").catch(() => "");
|
|
59
|
+
const parsed = parseSkillYaml(yaml);
|
|
60
|
+
const result = SkillMetadataSchema.safeParse(parsed);
|
|
61
|
+
if (result.success) {
|
|
62
|
+
skills.push({ metadata: result.data, markdown, dir });
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
skills.push({
|
|
66
|
+
metadata: {
|
|
67
|
+
id: entry,
|
|
68
|
+
name: entry,
|
|
69
|
+
description: "Invalid skill metadata",
|
|
70
|
+
version: "0.0.0",
|
|
71
|
+
author: "unknown",
|
|
72
|
+
risk_level: "high",
|
|
73
|
+
targets: ["generic"],
|
|
74
|
+
allowed_tools: [],
|
|
75
|
+
forbidden_patterns: [],
|
|
76
|
+
requires_human_approval: [],
|
|
77
|
+
created_at: "invalid",
|
|
78
|
+
content_hash: "0".repeat(64)
|
|
79
|
+
},
|
|
80
|
+
markdown,
|
|
81
|
+
dir
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return skills.sort((left, right) => left.metadata.id.localeCompare(right.metadata.id));
|
|
86
|
+
}
|
|
87
|
+
export function renderSkillList(skills) {
|
|
88
|
+
if (skills.length === 0)
|
|
89
|
+
return "No skills found. Run soturail skills init <name> first.\n";
|
|
90
|
+
return skills.map((skill) => `${skill.metadata.id} [${skill.metadata.risk_level}] ${skill.metadata.name}`).join("\n") + "\n";
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=skill-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-store.js","sourceRoot":"","sources":["../../src/core/skill-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface SkillValidationIssue {
|
|
2
|
+
skill_id: string;
|
|
3
|
+
severity: "error" | "warning";
|
|
4
|
+
message: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SkillValidationResult {
|
|
7
|
+
ok: boolean;
|
|
8
|
+
skills_count: number;
|
|
9
|
+
issues: SkillValidationIssue[];
|
|
10
|
+
}
|
|
11
|
+
export declare function validateSkills(root?: string): Promise<SkillValidationResult>;
|
|
12
|
+
export declare function formatSkillValidation(result: SkillValidationResult): string;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parseSkillYaml, SkillMetadataSchema, stableSkillHash } from "./skill-schema.js";
|
|
4
|
+
import { readSkills } from "./skill-store.js";
|
|
5
|
+
const destructivePatterns = [
|
|
6
|
+
/\brm\s+-[^"\n]*r[^"\n]*f\b/i,
|
|
7
|
+
/\bcurl\b[^|\n]*\|\s*(sh|bash)\b/i,
|
|
8
|
+
/\bwget\b[^|\n]*\|\s*(sh|bash)\b/i,
|
|
9
|
+
/\bgit\s+push\b/i,
|
|
10
|
+
/\bdd\s+[^"\n]*\bif=/i,
|
|
11
|
+
/\bdel\s+\/s\b/i
|
|
12
|
+
];
|
|
13
|
+
const promptInjectionPatterns = [
|
|
14
|
+
/ignore (all )?(previous|prior) instructions/i,
|
|
15
|
+
/disregard (all )?(previous|prior) instructions/i,
|
|
16
|
+
/you are no longer bound/i
|
|
17
|
+
];
|
|
18
|
+
const secretPatterns = [
|
|
19
|
+
/sk-[A-Za-z0-9_-]{20,}/,
|
|
20
|
+
/AKIA[0-9A-Z]{16}/,
|
|
21
|
+
/-----BEGIN (RSA |OPENSSH |EC )?PRIVATE KEY-----/,
|
|
22
|
+
/(password|api[_-]?key|secret)\s*[:=]\s*["']?[A-Za-z0-9_\-]{16,}/i
|
|
23
|
+
];
|
|
24
|
+
export async function validateSkills(root = process.cwd()) {
|
|
25
|
+
const skills = await readSkills(root);
|
|
26
|
+
const issues = [];
|
|
27
|
+
const seen = new Set();
|
|
28
|
+
for (const skill of skills) {
|
|
29
|
+
await validateSkillFiles(skill, issues);
|
|
30
|
+
if (seen.has(skill.metadata.id)) {
|
|
31
|
+
issues.push({ skill_id: skill.metadata.id, severity: "error", message: "Duplicate skill id." });
|
|
32
|
+
}
|
|
33
|
+
seen.add(skill.metadata.id);
|
|
34
|
+
const combined = `${skill.markdown}\n${JSON.stringify({ ...skill.metadata, forbidden_patterns: [] })}`;
|
|
35
|
+
for (const pattern of destructivePatterns) {
|
|
36
|
+
if (pattern.test(skill.markdown)) {
|
|
37
|
+
issues.push({ skill_id: skill.metadata.id, severity: "error", message: `Hidden destructive command pattern detected: ${pattern}` });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const pattern of promptInjectionPatterns) {
|
|
41
|
+
if (pattern.test(combined)) {
|
|
42
|
+
issues.push({ skill_id: skill.metadata.id, severity: "error", message: `Prompt-injection style instruction detected: ${pattern}` });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
for (const pattern of secretPatterns) {
|
|
46
|
+
if (pattern.test(combined)) {
|
|
47
|
+
issues.push({ skill_id: skill.metadata.id, severity: "error", message: "Probable embedded secret detected." });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const { content_hash: _hash, ...withoutHash } = skill.metadata;
|
|
51
|
+
const actual = stableSkillHash(withoutHash, skill.markdown);
|
|
52
|
+
if (actual !== skill.metadata.content_hash) {
|
|
53
|
+
issues.push({ skill_id: skill.metadata.id, severity: "error", message: "content_hash does not match skill.yml and SKILL.md content." });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
ok: issues.every((issue) => issue.severity !== "error"),
|
|
58
|
+
skills_count: skills.length,
|
|
59
|
+
issues
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function formatSkillValidation(result) {
|
|
63
|
+
const lines = [
|
|
64
|
+
`Skill validation: ${result.ok ? "passed" : "failed"}`,
|
|
65
|
+
`skills_count: ${result.skills_count}`
|
|
66
|
+
];
|
|
67
|
+
if (result.issues.length === 0) {
|
|
68
|
+
lines.push("issues: none");
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
for (const issue of result.issues) {
|
|
72
|
+
lines.push(`- ${issue.severity.toUpperCase()} ${issue.skill_id}: ${issue.message}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return `${lines.join("\n")}\n`;
|
|
76
|
+
}
|
|
77
|
+
async function validateSkillFiles(skill, issues) {
|
|
78
|
+
const yamlPath = path.join(skill.dir, "skill.yml");
|
|
79
|
+
const markdownPath = path.join(skill.dir, "SKILL.md");
|
|
80
|
+
const rawYaml = await fs.readFile(yamlPath, "utf8").catch(() => "");
|
|
81
|
+
const parsed = parseSkillYaml(rawYaml);
|
|
82
|
+
const result = SkillMetadataSchema.safeParse(parsed);
|
|
83
|
+
if (!result.success) {
|
|
84
|
+
issues.push({
|
|
85
|
+
skill_id: skill.metadata.id,
|
|
86
|
+
severity: "error",
|
|
87
|
+
message: `Invalid skill.yml: ${result.error.issues.map((issue) => issue.path.join(".")).join(", ")}`
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (!await fs.access(markdownPath).then(() => true).catch(() => false)) {
|
|
91
|
+
issues.push({ skill_id: skill.metadata.id, severity: "error", message: "Missing SKILL.md." });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=skill-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-validator.js","sourceRoot":"","sources":["../../src/core/skill-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SOTURAIL_VERSION = "0.3.0";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/core/version.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC"}
|
package/docs/benchmarking.md
CHANGED
|
@@ -20,7 +20,12 @@ The suite groups results as:
|
|
|
20
20
|
- agent response compression;
|
|
21
21
|
- knowledge structuring;
|
|
22
22
|
- cache stability;
|
|
23
|
-
- native engine availability/performance when available
|
|
23
|
+
- native engine availability/performance when available;
|
|
24
|
+
- skill rail validation/export;
|
|
25
|
+
- MCP resource listing/reading;
|
|
26
|
+
- context pack generation;
|
|
27
|
+
- agent hook export;
|
|
28
|
+
- memory approval workflow.
|
|
24
29
|
|
|
25
30
|
Terminal compression includes npm install noise, Vitest failures, TypeScript diagnostics, git diff/status noise and JSON/tool payload output.
|
|
26
31
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Comparison Philosophy
|
|
2
|
+
|
|
3
|
+
SotuRail aims to unify these workflow ideas into one local-first, auditable, cache-friendly developer tool.
|
|
4
|
+
|
|
5
|
+
SotuRail is an independent implementation. It does not vendor or depend on RTK, Squeez, Caveman, MemPalace, Spec Kit, agent-skills, SkillsMP, Compozy, Superpowers, OpenSpec or Istara.
|
|
6
|
+
|
|
7
|
+
## Terminal Compression
|
|
8
|
+
|
|
9
|
+
RTK-like terminal compression is conceptually related. SotuRail focuses on reversible raw logs, `raw_id` recovery and local safety policy. It does not claim to outperform RTK without reproducible benchmark evidence.
|
|
10
|
+
|
|
11
|
+
## Hooks And Dedupe
|
|
12
|
+
|
|
13
|
+
Squeez-like hooks and dedupe are adjacent ideas. SotuRail has prompt-only fallbacks, conservative Claude hooks, context packs and local dedupe as an independent implementation.
|
|
14
|
+
|
|
15
|
+
## Response Compression
|
|
16
|
+
|
|
17
|
+
Caveman-like response compression inspired the idea of shorter agent output. SotuRail implements professional deterministic modes that preserve code blocks, commands, paths and warnings.
|
|
18
|
+
|
|
19
|
+
## Spec Workflows
|
|
20
|
+
|
|
21
|
+
Spec Kit-like workflows are related to SotuRail specs. SotuRail integrates specs with logs, metrics, memory and context packs.
|
|
22
|
+
|
|
23
|
+
## Local Memory
|
|
24
|
+
|
|
25
|
+
MemPalace-like memory/evidence ideas are related. SotuRail uses local JSONL memory with approval workflow and stale marking, not full semantic memory yet.
|
|
26
|
+
|
|
27
|
+
## Knowledge To Rules
|
|
28
|
+
|
|
29
|
+
Nicole-style knowledge-to-rules workflows are related. SotuRail has `ingest` and `rules` with future hardened PDF extraction.
|
|
30
|
+
|
|
31
|
+
## Skills And Workflow Orchestration
|
|
32
|
+
|
|
33
|
+
Agent-skills and SkillsMP-like ecosystems are related to Skill Rail exports. Compozy, Superpowers and OpenSpec-style orchestration are future Workflow Rail territory.
|
|
34
|
+
|
|
35
|
+
SotuRail should not be described as better than these projects unless a specific local benchmark proves a specific metric.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Context Packs
|
|
2
|
+
|
|
3
|
+
Context packs are target-aware Markdown payloads for AI coding agents.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
soturail context pack --target claude
|
|
7
|
+
soturail context pack --target codex
|
|
8
|
+
soturail context pack --target gemini
|
|
9
|
+
soturail context pack --target cursor
|
|
10
|
+
soturail context pack --target generic
|
|
11
|
+
soturail context explain
|
|
12
|
+
soturail context doctor
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Generated files live in `.soturail/context/`.
|
|
16
|
+
|
|
17
|
+
Stable-cache order:
|
|
18
|
+
|
|
19
|
+
1. Static SotuRail header.
|
|
20
|
+
2. Governance files summary.
|
|
21
|
+
3. Project config.
|
|
22
|
+
4. Repo map summary.
|
|
23
|
+
5. Approved rules.
|
|
24
|
+
6. Approved specs.
|
|
25
|
+
7. Approved memory.
|
|
26
|
+
8. Skills summary.
|
|
27
|
+
9. Dynamic footer with timestamps, current commit, raw IDs and recent command notes.
|
|
28
|
+
|
|
29
|
+
Dynamic data never appears before stable blocks.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Skill Examples
|
|
2
|
+
|
|
3
|
+
Generate local examples with:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
soturail skills init demo-skill
|
|
7
|
+
soturail skills validate
|
|
8
|
+
soturail skills export --target generic
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Generated skills live in `.soturail/skills/` and exports live in `.soturail/exports/skills/`.
|
package/docs/hooks/claude.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Claude Hooks
|
|
2
2
|
|
|
3
|
-
SotuRail v0.
|
|
3
|
+
SotuRail v0.3.0 includes conservative Claude safe-hooks and MCP guidance.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
soturail hooks install claude --dry-run
|
|
7
|
-
soturail hooks install claude
|
|
8
|
-
soturail hooks
|
|
6
|
+
soturail hooks install --agent claude --mode safe-hooks --dry-run
|
|
7
|
+
soturail hooks install --agent claude --mode safe-hooks
|
|
8
|
+
soturail hooks install --agent claude --mode mcp
|
|
9
|
+
soturail hooks uninstall --agent claude
|
|
10
|
+
soturail hooks export --agent claude
|
|
9
11
|
soturail hooks prompt-only claude
|
|
10
12
|
```
|
|
11
13
|
|
package/docs/hooks/codex.md
CHANGED
|
@@ -7,9 +7,10 @@ SotuRail does not assume private Codex host hook APIs. The fallback rules descri
|
|
|
7
7
|
Useful commands:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
soturail hooks install codex --dry-run
|
|
11
|
-
soturail hooks install codex
|
|
12
|
-
soturail hooks uninstall codex
|
|
10
|
+
soturail hooks install --agent codex --mode prompt-only --dry-run
|
|
11
|
+
soturail hooks install --agent codex --mode prompt-only
|
|
12
|
+
soturail hooks uninstall --agent codex
|
|
13
|
+
soturail hooks export --agent codex
|
|
13
14
|
soturail hooks prompt-only codex
|
|
14
15
|
```
|
|
15
16
|
|
package/docs/hooks/cursor.md
CHANGED
|
@@ -7,9 +7,10 @@ Existing files are backed up before SotuRail adds its rules.
|
|
|
7
7
|
Useful commands:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
soturail hooks install cursor --dry-run
|
|
11
|
-
soturail hooks install cursor
|
|
12
|
-
soturail hooks uninstall cursor
|
|
10
|
+
soturail hooks install --agent cursor --mode prompt-only --dry-run
|
|
11
|
+
soturail hooks install --agent cursor --mode prompt-only
|
|
12
|
+
soturail hooks uninstall --agent cursor
|
|
13
|
+
soturail hooks export --agent cursor
|
|
13
14
|
soturail hooks prompt-only cursor
|
|
14
15
|
```
|
|
15
16
|
|
package/docs/hooks/gemini.md
CHANGED
|
@@ -7,9 +7,10 @@ The generated rules keep repository scans, progressive file reads and raw log re
|
|
|
7
7
|
Useful commands:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
soturail hooks install gemini --dry-run
|
|
11
|
-
soturail hooks install gemini
|
|
12
|
-
soturail hooks uninstall gemini
|
|
10
|
+
soturail hooks install --agent gemini --mode prompt-only --dry-run
|
|
11
|
+
soturail hooks install --agent gemini --mode prompt-only
|
|
12
|
+
soturail hooks uninstall --agent gemini
|
|
13
|
+
soturail hooks export --agent gemini
|
|
13
14
|
soturail hooks prompt-only gemini
|
|
14
15
|
```
|
|
15
16
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# MCP Hook Integration
|
|
2
|
+
|
|
3
|
+
Use MCP mode when an agent host supports reviewed local MCP server configuration.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
soturail hooks install --agent claude --mode mcp --dry-run
|
|
7
|
+
soturail mcp serve --transport stdio
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Review generated instructions before enabling. SotuRail's MCP server exposes read-only resources and safe tools; it does not expose arbitrary shell execution in v0.3.0.
|