soturail 0.2.1 → 0.2.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 +69 -0
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/bench.d.ts +14 -3
- package/dist/commands/bench.js +237 -180
- package/dist/commands/bench.js.map +1 -1
- package/dist/commands/run.js +20 -1
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/self.d.ts +2 -0
- package/dist/commands/self.js +49 -0
- package/dist/commands/self.js.map +1 -0
- package/dist/commands/stats.d.ts +6 -0
- package/dist/commands/stats.js +28 -0
- package/dist/commands/stats.js.map +1 -1
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.js +1 -0
- package/dist/core/config.js.map +1 -1
- package/dist/core/file-scanner.js +6 -2
- package/dist/core/file-scanner.js.map +1 -1
- package/dist/core/metrics-store.d.ts +7 -0
- package/dist/core/metrics-store.js.map +1 -1
- package/dist/core/self-dogfood.d.ts +56 -0
- package/dist/core/self-dogfood.js +323 -0
- package/dist/core/self-dogfood.js.map +1 -0
- package/docs/benchmarking.md +4 -2
- package/docs/hooks/claude.md +4 -0
- package/docs/hooks/codex.md +11 -0
- package/docs/hooks/cursor.md +11 -0
- package/docs/hooks/gemini.md +11 -0
- package/docs/hooks.md +11 -0
- package/docs/release-checklist.md +36 -6
- package/docs/release-workflow.md +54 -0
- package/docs/skill-rail.md +28 -0
- package/docs/windows.md +76 -0
- package/docs/workflow-rail.md +26 -0
- package/package.json +7 -2
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promises as fs } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { PassThrough } from "node:stream";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { runBenchmarks, summarizeBenchmarkResults } from "../commands/bench.js";
|
|
7
|
+
import { executeRunCommand } from "../commands/run.js";
|
|
8
|
+
import { ensureWorkspace, getWorkspacePaths, loadConfig } from "./config.js";
|
|
9
|
+
import { scanRepository, writeRepoMap } from "./file-scanner.js";
|
|
10
|
+
import { getCurrentGitCommit } from "./git.js";
|
|
11
|
+
import { estimateTokens } from "./token-estimator.js";
|
|
12
|
+
const execFileAsync = promisify(execFile);
|
|
13
|
+
const REQUIRED_SOTURAIL_PATHS = [
|
|
14
|
+
"package.json",
|
|
15
|
+
"README.md",
|
|
16
|
+
"CHANGELOG.md",
|
|
17
|
+
"ROADMAP.md",
|
|
18
|
+
path.join("src", "cli.ts"),
|
|
19
|
+
path.join("src", "commands"),
|
|
20
|
+
path.join("src", "core"),
|
|
21
|
+
"tests",
|
|
22
|
+
"docs"
|
|
23
|
+
];
|
|
24
|
+
export function createEmptySelfState() {
|
|
25
|
+
return { errors: [] };
|
|
26
|
+
}
|
|
27
|
+
export async function selfDoctor(root = process.cwd()) {
|
|
28
|
+
const resolvedRoot = path.resolve(root);
|
|
29
|
+
const missing = [];
|
|
30
|
+
for (const required of REQUIRED_SOTURAIL_PATHS) {
|
|
31
|
+
const absolute = path.resolve(resolvedRoot, required);
|
|
32
|
+
try {
|
|
33
|
+
await fs.access(absolute);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
missing.push(path.normalize(required));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const packageJson = await readPackageJson(resolvedRoot);
|
|
40
|
+
if (packageJson.name !== "soturail") {
|
|
41
|
+
missing.push("package.json:name=soturail");
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
ok: missing.length === 0,
|
|
45
|
+
root: resolvedRoot,
|
|
46
|
+
package_name: typeof packageJson.name === "string" ? packageJson.name : null,
|
|
47
|
+
package_version: typeof packageJson.version === "string" ? packageJson.version : null,
|
|
48
|
+
missing
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export async function assertSotuRailRepository(root = process.cwd()) {
|
|
52
|
+
const doctor = await selfDoctor(root);
|
|
53
|
+
if (!doctor.ok) {
|
|
54
|
+
throw new Error(`This directory does not look like the SotuRail repository. Missing: ${doctor.missing.join(", ")}`);
|
|
55
|
+
}
|
|
56
|
+
return doctor;
|
|
57
|
+
}
|
|
58
|
+
export async function selfIndex(root = process.cwd()) {
|
|
59
|
+
await assertSotuRailRepository(root);
|
|
60
|
+
await ensureWorkspace(root);
|
|
61
|
+
const config = await loadConfig(root);
|
|
62
|
+
const repoMap = await scanRepository(root, config);
|
|
63
|
+
await writeRepoMap(root, repoMap);
|
|
64
|
+
return {
|
|
65
|
+
indexed_files_count: repoMap.total_files,
|
|
66
|
+
ignored_files_count: repoMap.stats.ignored_files,
|
|
67
|
+
ignored_directories_count: repoMap.stats.ignored_directories
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export async function selfBuild(root = process.cwd(), terminalStdout, terminalStderr) {
|
|
71
|
+
return selfRunCommand(["npm", "run", "build"], root, terminalStdout, terminalStderr);
|
|
72
|
+
}
|
|
73
|
+
export async function selfTest(root = process.cwd(), terminalStdout, terminalStderr) {
|
|
74
|
+
return selfRunCommand(["npm", "test"], root, terminalStdout, terminalStderr);
|
|
75
|
+
}
|
|
76
|
+
export async function selfBench(root = process.cwd(), terminalStdout, terminalStderr) {
|
|
77
|
+
await assertSotuRailRepository(root);
|
|
78
|
+
const cliPath = path.resolve(root, "dist", "cli.js");
|
|
79
|
+
let runResult = null;
|
|
80
|
+
try {
|
|
81
|
+
await fs.access(cliPath);
|
|
82
|
+
runResult = await executeRunCommand([`"${process.execPath}" "${cliPath}" bench run --engine ts`], {
|
|
83
|
+
terminalStdout: terminalStdout ?? drainedStream(),
|
|
84
|
+
terminalStderr: terminalStderr ?? drainedStream(),
|
|
85
|
+
engine: "ts"
|
|
86
|
+
}, root);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// If the built CLI is unavailable, the in-process benchmark path still gives a real report.
|
|
90
|
+
}
|
|
91
|
+
const results = runResult ? await readLatestBenchmarkResults(root) : await runBenchmarks({ engine: "ts" }, root);
|
|
92
|
+
return {
|
|
93
|
+
ok: runResult ? runResult.exitCode === 0 : true,
|
|
94
|
+
raw_id: runResult?.rawId ?? null,
|
|
95
|
+
cases_count: results.length,
|
|
96
|
+
summary: summarizeBenchmarkResults(results),
|
|
97
|
+
results
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export async function writeSelfReport(input) {
|
|
101
|
+
const root = path.resolve(input.root ?? process.cwd());
|
|
102
|
+
await ensureWorkspace(root);
|
|
103
|
+
const paths = getWorkspacePaths(root);
|
|
104
|
+
const reportsDir = path.resolve(paths.workspace, "reports");
|
|
105
|
+
await fs.mkdir(reportsDir, { recursive: true });
|
|
106
|
+
const reportPath = path.resolve(reportsDir, "self-dogfood.md");
|
|
107
|
+
const packageJson = await readPackageJson(root);
|
|
108
|
+
const commit = await getCurrentGitCommit(root);
|
|
109
|
+
const branch = await getCurrentGitBranch(root);
|
|
110
|
+
const accounting = selfTokenAccounting(input);
|
|
111
|
+
const report = [
|
|
112
|
+
"# SotuRail Self-Dogfood Report",
|
|
113
|
+
"",
|
|
114
|
+
"## Stable Project Description",
|
|
115
|
+
"",
|
|
116
|
+
"SotuRail aims to unify terminal compression, progressive repo reading, Spec-Driven workflows, local memory, rules extraction, agent hooks, benchmarks and cache-friendly payloads into one local-first workflow.",
|
|
117
|
+
"",
|
|
118
|
+
`- package_name: ${stringOrUnknown(packageJson.name)}`,
|
|
119
|
+
`- package_version: ${stringOrUnknown(packageJson.version)}`,
|
|
120
|
+
"- report_schema: self-dogfood-v1",
|
|
121
|
+
"",
|
|
122
|
+
"## Stable Quality Rails",
|
|
123
|
+
"",
|
|
124
|
+
"- Build, test and benchmark commands should run through SotuRail so raw logs are recoverable.",
|
|
125
|
+
"- Token counts are deterministic estimates unless provider metadata is explicitly imported.",
|
|
126
|
+
"- Dynamic raw IDs, timestamps, logs and volatile command status stay below this stable section.",
|
|
127
|
+
"",
|
|
128
|
+
"## Dynamic Execution Data",
|
|
129
|
+
"",
|
|
130
|
+
`- repository_path: ${path.normalize(root)}`,
|
|
131
|
+
`- current_git_commit_hash: ${commit ?? "unknown"}`,
|
|
132
|
+
`- current_branch: ${branch ?? "unknown"}`,
|
|
133
|
+
`- doctor_ok: ${input.doctor?.ok ?? false}`,
|
|
134
|
+
`- indexed_files_count: ${input.index?.indexed_files_count ?? 0}`,
|
|
135
|
+
`- ignored_files_directories_count: ${(input.index?.ignored_files_count ?? 0) + (input.index?.ignored_directories_count ?? 0)}`,
|
|
136
|
+
`- build_result: ${formatStep(input.build)}`,
|
|
137
|
+
`- test_result: ${formatStep(input.test)}`,
|
|
138
|
+
`- benchmark_summary: ${input.bench?.summary.replace(/\r?\n/g, " | ") ?? "not run"}`,
|
|
139
|
+
`- build_raw_id: ${input.build?.raw_id ?? "n/a"}`,
|
|
140
|
+
`- test_raw_id: ${input.test?.raw_id ?? "n/a"}`,
|
|
141
|
+
`- benchmark_raw_id: ${input.bench?.raw_id ?? "n/a"}`,
|
|
142
|
+
`- estimated_raw_tokens: ${accounting.estimated_raw_tokens}`,
|
|
143
|
+
`- estimated_reduced_tokens: ${accounting.estimated_reduced_tokens}`,
|
|
144
|
+
`- estimated_metadata_overhead_tokens: ${accounting.estimated_metadata_overhead_tokens}`,
|
|
145
|
+
`- compression_effective: ${accounting.compression_effective}`,
|
|
146
|
+
"",
|
|
147
|
+
"## Known Limitations",
|
|
148
|
+
"",
|
|
149
|
+
"- Native benchmark rows are marked unavailable when the optional native binary is not built.",
|
|
150
|
+
"- Self-dogfood reports are local evidence, not provider cache-hit evidence.",
|
|
151
|
+
"- Small command outputs may cost more after metadata, but recovery and audit paths remain valuable.",
|
|
152
|
+
"",
|
|
153
|
+
"## Recommended Next Action",
|
|
154
|
+
"",
|
|
155
|
+
input.errors.length > 0
|
|
156
|
+
? `Review partial failures: ${input.errors.join("; ")}`
|
|
157
|
+
: "Keep running `soturail self all` before release-oriented commits.",
|
|
158
|
+
""
|
|
159
|
+
].join("\n");
|
|
160
|
+
await fs.writeFile(reportPath, report, "utf8");
|
|
161
|
+
return reportPath;
|
|
162
|
+
}
|
|
163
|
+
export async function selfAll(root = process.cwd(), terminalStdout, terminalStderr) {
|
|
164
|
+
const state = createEmptySelfState();
|
|
165
|
+
try {
|
|
166
|
+
state.doctor = await selfDoctor(root);
|
|
167
|
+
if (!state.doctor.ok) {
|
|
168
|
+
state.errors.push(`doctor failed: ${state.doctor.missing.join(", ")}`);
|
|
169
|
+
state.report_path = await writeSelfReport({ ...state, root });
|
|
170
|
+
return state;
|
|
171
|
+
}
|
|
172
|
+
state.index = await selfIndex(root);
|
|
173
|
+
state.build = await selfBuild(root, terminalStdout, terminalStderr);
|
|
174
|
+
if (!state.build.ok) {
|
|
175
|
+
state.errors.push(`build failed: raw_id=${state.build.raw_id ?? "n/a"}`);
|
|
176
|
+
state.report_path = await writeSelfReport({ ...state, root });
|
|
177
|
+
return state;
|
|
178
|
+
}
|
|
179
|
+
state.test = await selfTest(root, terminalStdout, terminalStderr);
|
|
180
|
+
if (!state.test.ok) {
|
|
181
|
+
state.errors.push(`test failed: raw_id=${state.test.raw_id ?? "n/a"}`);
|
|
182
|
+
state.report_path = await writeSelfReport({ ...state, root });
|
|
183
|
+
return state;
|
|
184
|
+
}
|
|
185
|
+
state.bench = await selfBench(root, terminalStdout, terminalStderr);
|
|
186
|
+
if (!state.bench.ok) {
|
|
187
|
+
state.errors.push(`bench failed: raw_id=${state.bench.raw_id ?? "n/a"}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
state.errors.push(error instanceof Error ? error.message : String(error));
|
|
192
|
+
}
|
|
193
|
+
state.report_path = await writeSelfReport({ ...state, root });
|
|
194
|
+
return state;
|
|
195
|
+
}
|
|
196
|
+
export function formatSelfDoctor(result) {
|
|
197
|
+
return [
|
|
198
|
+
"SotuRail self doctor",
|
|
199
|
+
`ok: ${result.ok}`,
|
|
200
|
+
`root: ${path.normalize(result.root)}`,
|
|
201
|
+
`package_name: ${result.package_name ?? "unknown"}`,
|
|
202
|
+
`package_version: ${result.package_version ?? "unknown"}`,
|
|
203
|
+
`missing: ${result.missing.length === 0 ? "none" : result.missing.join(", ")}`
|
|
204
|
+
].join("\n") + "\n";
|
|
205
|
+
}
|
|
206
|
+
export function formatSelfIndex(result) {
|
|
207
|
+
return [
|
|
208
|
+
"SotuRail self index",
|
|
209
|
+
`indexed_files_count: ${result.indexed_files_count}`,
|
|
210
|
+
`ignored_files_count: ${result.ignored_files_count}`,
|
|
211
|
+
`ignored_directories_count: ${result.ignored_directories_count}`
|
|
212
|
+
].join("\n") + "\n";
|
|
213
|
+
}
|
|
214
|
+
export function formatSelfRunStep(label, result) {
|
|
215
|
+
return [
|
|
216
|
+
`SotuRail self ${label}`,
|
|
217
|
+
`ok: ${result.ok}`,
|
|
218
|
+
`exit_code: ${result.exit_code ?? "n/a"}`,
|
|
219
|
+
`raw_id: ${result.raw_id ?? "n/a"}`
|
|
220
|
+
].join("\n") + "\n";
|
|
221
|
+
}
|
|
222
|
+
export function formatSelfBench(result) {
|
|
223
|
+
return [
|
|
224
|
+
"SotuRail self bench",
|
|
225
|
+
`ok: ${result.ok}`,
|
|
226
|
+
`raw_id: ${result.raw_id ?? "n/a"}`,
|
|
227
|
+
`cases_count: ${result.cases_count}`,
|
|
228
|
+
result.summary
|
|
229
|
+
].join("\n") + "\n";
|
|
230
|
+
}
|
|
231
|
+
function selfTokenAccounting(input) {
|
|
232
|
+
const estimatedRaw = (input.build?.raw_tokens ?? 0) + (input.test?.raw_tokens ?? 0);
|
|
233
|
+
const estimatedReduced = (input.build?.reduced_tokens ?? 0) + (input.test?.reduced_tokens ?? 0);
|
|
234
|
+
const metadata = estimateTokens(JSON.stringify({
|
|
235
|
+
doctor: input.doctor?.ok,
|
|
236
|
+
index: input.index,
|
|
237
|
+
build_raw_id: input.build?.raw_id,
|
|
238
|
+
test_raw_id: input.test?.raw_id,
|
|
239
|
+
bench_raw_id: input.bench?.raw_id
|
|
240
|
+
}));
|
|
241
|
+
return {
|
|
242
|
+
estimated_raw_tokens: estimatedRaw,
|
|
243
|
+
estimated_reduced_tokens: estimatedReduced,
|
|
244
|
+
estimated_metadata_overhead_tokens: metadata,
|
|
245
|
+
compression_effective: estimatedReduced + metadata <= estimatedRaw
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
async function selfRunCommand(commandParts, root, terminalStdout, terminalStderr) {
|
|
249
|
+
await assertSotuRailRepository(root);
|
|
250
|
+
try {
|
|
251
|
+
const result = await executeRunCommand(commandParts, {
|
|
252
|
+
terminalStdout: terminalStdout ?? drainedStream(),
|
|
253
|
+
terminalStderr: terminalStderr ?? drainedStream(),
|
|
254
|
+
engine: "ts"
|
|
255
|
+
}, root);
|
|
256
|
+
return {
|
|
257
|
+
ok: result.exitCode === 0,
|
|
258
|
+
exit_code: result.exitCode,
|
|
259
|
+
raw_id: result.rawId,
|
|
260
|
+
raw_tokens: result.record.raw_tokens_estimated,
|
|
261
|
+
reduced_tokens: result.record.compressed_tokens_estimated,
|
|
262
|
+
summary: result.summary
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
return {
|
|
267
|
+
ok: false,
|
|
268
|
+
exit_code: null,
|
|
269
|
+
raw_id: null,
|
|
270
|
+
raw_tokens: 0,
|
|
271
|
+
reduced_tokens: 0,
|
|
272
|
+
summary: "",
|
|
273
|
+
error: error instanceof Error ? error.message : String(error)
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
async function readPackageJson(root) {
|
|
278
|
+
try {
|
|
279
|
+
return JSON.parse(await fs.readFile(path.resolve(root, "package.json"), "utf8"));
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
return {};
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
async function readLatestBenchmarkResults(root) {
|
|
286
|
+
const filePath = path.resolve(root, "benchmarks", "results", "latest.json");
|
|
287
|
+
try {
|
|
288
|
+
const parsed = JSON.parse(await fs.readFile(filePath, "utf8"));
|
|
289
|
+
return Array.isArray(parsed.results) ? parsed.results : [];
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
return [];
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
async function getCurrentGitBranch(root) {
|
|
296
|
+
try {
|
|
297
|
+
const { stdout } = await execFileAsync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
298
|
+
cwd: root,
|
|
299
|
+
timeout: 3000,
|
|
300
|
+
windowsHide: true
|
|
301
|
+
});
|
|
302
|
+
const branch = stdout.trim();
|
|
303
|
+
return branch.length > 0 ? branch : null;
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function drainedStream() {
|
|
310
|
+
const stream = new PassThrough();
|
|
311
|
+
stream.resume();
|
|
312
|
+
return stream;
|
|
313
|
+
}
|
|
314
|
+
function formatStep(step) {
|
|
315
|
+
if (!step) {
|
|
316
|
+
return "not run";
|
|
317
|
+
}
|
|
318
|
+
return step.ok ? `pass exit_code=${step.exit_code}` : `fail exit_code=${step.exit_code ?? "n/a"}`;
|
|
319
|
+
}
|
|
320
|
+
function stringOrUnknown(value) {
|
|
321
|
+
return typeof value === "string" && value.length > 0 ? value : "unknown";
|
|
322
|
+
}
|
|
323
|
+
//# sourceMappingURL=self-dogfood.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self-dogfood.js","sourceRoot":"","sources":["../../src/core/self-dogfood.ts"],"names":[],"mappings":"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"}
|
package/docs/benchmarking.md
CHANGED
|
@@ -18,9 +18,11 @@ The suite groups results as:
|
|
|
18
18
|
|
|
19
19
|
- terminal compression;
|
|
20
20
|
- agent response compression;
|
|
21
|
-
- JSON/tool payload compression;
|
|
22
21
|
- knowledge structuring;
|
|
23
|
-
-
|
|
22
|
+
- cache stability;
|
|
23
|
+
- native engine availability/performance when available.
|
|
24
|
+
|
|
25
|
+
Terminal compression includes npm install noise, Vitest failures, TypeScript diagnostics, git diff/status noise and JSON/tool payload output.
|
|
24
26
|
|
|
25
27
|
Knowledge-to-Rules is not judged as pure compression. It creates reusable structured rules, citations and validator metadata.
|
|
26
28
|
|
package/docs/hooks/claude.md
CHANGED
|
@@ -5,6 +5,8 @@ SotuRail v0.2.1 includes a conservative Claude Code hook template.
|
|
|
5
5
|
```bash
|
|
6
6
|
soturail hooks install claude --dry-run
|
|
7
7
|
soturail hooks install claude
|
|
8
|
+
soturail hooks uninstall claude
|
|
9
|
+
soturail hooks prompt-only claude
|
|
8
10
|
```
|
|
9
11
|
|
|
10
12
|
Generated files:
|
|
@@ -19,6 +21,8 @@ The pre-tool hook inspects incoming tool payload text when Claude Code provides
|
|
|
19
21
|
|
|
20
22
|
The hook never routes `git push` through `soturail run`.
|
|
21
23
|
|
|
24
|
+
Review generated settings and scripts before relying on them. SotuRail should never auto-install unreviewed third-party skills, hooks or scripts.
|
|
25
|
+
|
|
22
26
|
## Limitation
|
|
23
27
|
|
|
24
28
|
Claude Code hook schemas may vary by installed version. SotuRail writes a conservative documented template; if your Claude Code release expects a different schema, copy the generated command into the supported hook slot manually.
|
package/docs/hooks/codex.md
CHANGED
|
@@ -3,3 +3,14 @@
|
|
|
3
3
|
Codex prompt-only integration uses `AGENTS.md`.
|
|
4
4
|
|
|
5
5
|
SotuRail does not assume private Codex host hook APIs. The fallback rules describe when to index, read progressively, run through SotuRail and avoid `git push`.
|
|
6
|
+
|
|
7
|
+
Useful commands:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
soturail hooks install codex --dry-run
|
|
11
|
+
soturail hooks install codex
|
|
12
|
+
soturail hooks uninstall codex
|
|
13
|
+
soturail hooks prompt-only codex
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Existing `AGENTS.md` content is backed up before install. Review generated prompt rules before enabling them. SotuRail should never auto-install unreviewed third-party skills, hooks or scripts.
|
package/docs/hooks/cursor.md
CHANGED
|
@@ -3,3 +3,14 @@
|
|
|
3
3
|
Cursor prompt-only integration writes `.cursor/rules/soturail.mdc` when installed.
|
|
4
4
|
|
|
5
5
|
Existing files are backed up before SotuRail adds its rules.
|
|
6
|
+
|
|
7
|
+
Useful commands:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
soturail hooks install cursor --dry-run
|
|
11
|
+
soturail hooks install cursor
|
|
12
|
+
soturail hooks uninstall cursor
|
|
13
|
+
soturail hooks prompt-only cursor
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Review generated prompt rules before enabling them. SotuRail should never auto-install unreviewed third-party skills, hooks or scripts.
|
package/docs/hooks/gemini.md
CHANGED
|
@@ -3,3 +3,14 @@
|
|
|
3
3
|
Gemini prompt-only integration uses `GEMINI.md`.
|
|
4
4
|
|
|
5
5
|
The generated rules keep repository scans, progressive file reads and raw log recovery visible to Gemini CLI sessions.
|
|
6
|
+
|
|
7
|
+
Useful commands:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
soturail hooks install gemini --dry-run
|
|
11
|
+
soturail hooks install gemini
|
|
12
|
+
soturail hooks uninstall gemini
|
|
13
|
+
soturail hooks prompt-only gemini
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Existing `GEMINI.md` content is backed up before install. Review generated prompt rules before enabling them. SotuRail should never auto-install unreviewed third-party skills, hooks or scripts.
|
package/docs/hooks.md
CHANGED
|
@@ -6,6 +6,8 @@ SotuRail hook support is cautious. Claude gets a conservative hook template firs
|
|
|
6
6
|
soturail hooks list
|
|
7
7
|
soturail hooks doctor
|
|
8
8
|
soturail hooks install claude --dry-run
|
|
9
|
+
soturail hooks install claude
|
|
10
|
+
soturail hooks uninstall claude
|
|
9
11
|
soturail hooks install all --dry-run
|
|
10
12
|
soturail hooks prompt-only codex
|
|
11
13
|
```
|
|
@@ -13,3 +15,12 @@ soturail hooks prompt-only codex
|
|
|
13
15
|
Installers create backups before modifying existing files. If a host config location is uncertain, SotuRail generates prompt-only guidance instead of guessing.
|
|
14
16
|
|
|
15
17
|
Claude install writes `.claude/settings.json` and hook scripts under `.claude/hooks/`. Dry-run prints every file that would change.
|
|
18
|
+
|
|
19
|
+
Always review generated hooks before enabling them. SotuRail should never auto-install unreviewed third-party skills, hooks or scripts. Prompt-only fallback remains available for every host:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
soturail hooks prompt-only claude
|
|
23
|
+
soturail hooks prompt-only codex
|
|
24
|
+
soturail hooks prompt-only gemini
|
|
25
|
+
soturail hooks prompt-only cursor
|
|
26
|
+
```
|
|
@@ -2,12 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
Before publishing:
|
|
4
4
|
|
|
5
|
+
- [ ] Confirm `npm whoami` works for the publishing account.
|
|
6
|
+
- [ ] Confirm npm 2FA requirements and have the authenticator ready.
|
|
5
7
|
- [ ] `npm install`
|
|
6
8
|
- [ ] `npm run build`
|
|
7
9
|
- [ ] `npm test`
|
|
8
|
-
- [ ]
|
|
9
|
-
- [ ]
|
|
10
|
-
- [ ]
|
|
11
|
-
- [ ]
|
|
12
|
-
- [ ] Confirm
|
|
13
|
-
- [ ]
|
|
10
|
+
- [ ] `npm audit --omit=dev`
|
|
11
|
+
- [ ] `node dist/cli.js self all`
|
|
12
|
+
- [ ] `npm pack --dry-run`
|
|
13
|
+
- [ ] `npm run release:check`
|
|
14
|
+
- [ ] Confirm docs mention limitations honestly.
|
|
15
|
+
- [ ] Confirm no telemetry exists.
|
|
16
|
+
- [ ] Confirm no `git push` is routed through `soturail run`.
|
|
17
|
+
|
|
18
|
+
## Audit Distinction
|
|
19
|
+
|
|
20
|
+
`npm audit` checks all dependencies, including dev dependencies used for local tests and builds.
|
|
21
|
+
|
|
22
|
+
`npm audit --omit=dev` checks runtime/public dependency risk for published package users.
|
|
23
|
+
|
|
24
|
+
Runtime audit is clean with `npm audit --omit=dev`. Remaining audit findings, if any, are development dependency findings and should be upgraded safely without `--force`.
|
|
25
|
+
|
|
26
|
+
For v0.2.2, the full audit findings are in the Vitest/Vite development test stack. npm's suggested fix is a semver-major Vitest upgrade, so do not run `npm audit fix --force` blindly.
|
|
27
|
+
|
|
28
|
+
## Windows Paste Safety
|
|
29
|
+
|
|
30
|
+
Do not paste Markdown prose or code-fence labels directly into `cmd.exe` as commands. For example, do not paste ```` ```bat ````. Copy only the command lines themselves.
|
|
31
|
+
|
|
32
|
+
See [docs/windows.md](windows.md) for CMD and PowerShell quoting notes.
|
|
33
|
+
|
|
34
|
+
## Automation
|
|
35
|
+
|
|
36
|
+
Use:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm run release:check
|
|
40
|
+
npm run release:prepare -- --version X.Y.Z
|
|
41
|
+
npm run release:publish -- --version X.Y.Z
|
|
42
|
+
npm run release:full -- --version X.Y.Z
|
|
43
|
+
```
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Release Workflow
|
|
2
|
+
|
|
3
|
+
SotuRail releases should be repeatable and evidence-backed. The release helper lives at `scripts/release.mjs`.
|
|
4
|
+
|
|
5
|
+
## Check
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm run release:check
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Runs install, build, tests, runtime audit, self-dogfooding, pack dry-run and npm version checks. It also reports whether full audit findings are development-only.
|
|
12
|
+
|
|
13
|
+
## Prepare
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm run release:prepare -- --version X.Y.Z
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Prepare mode:
|
|
20
|
+
|
|
21
|
+
- validates the version argument;
|
|
22
|
+
- updates `package.json`, `package-lock.json` and CLI version text;
|
|
23
|
+
- updates `CHANGELOG.md`;
|
|
24
|
+
- creates `RELEASE_NOTES_vX.Y.Z.md`;
|
|
25
|
+
- runs validation;
|
|
26
|
+
- commits `chore(release): prepare vX.Y.Z`;
|
|
27
|
+
- pushes `main`;
|
|
28
|
+
- never publishes to npm.
|
|
29
|
+
|
|
30
|
+
## Publish
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm run release:publish -- --version X.Y.Z
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Publish mode refuses to publish if build, tests or runtime audit fail, if the git tree is dirty, or if the version already exists on npm. If npm asks for 2FA or authentication, rerun the same command after completing the auth step.
|
|
37
|
+
|
|
38
|
+
## Full
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm run release:full -- --version X.Y.Z
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Full mode runs prepare, publish and then creates or updates the GitHub release using `gh` when available. If the npm version already exists, full mode skips npm publish and only creates or updates the GitHub release.
|
|
45
|
+
|
|
46
|
+
Safety rules:
|
|
47
|
+
|
|
48
|
+
- Never run `npm audit fix --force`.
|
|
49
|
+
- Never publish if tests fail.
|
|
50
|
+
- Never publish if build fails.
|
|
51
|
+
- Never publish if runtime audit fails.
|
|
52
|
+
- Never publish if the requested package version already exists on npm.
|
|
53
|
+
- Never create a GitHub release before npm publish succeeds.
|
|
54
|
+
- Never hide errors.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Skill Rail
|
|
2
|
+
|
|
3
|
+
Skill Rail is planned for v0.3.0. It is not implemented in v0.2.2.
|
|
4
|
+
|
|
5
|
+
The goal is to turn approved SotuRail specs, rules and workflows into portable, reviewable agent skills without installing untrusted marketplace content automatically.
|
|
6
|
+
|
|
7
|
+
Planned commands:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
soturail skills init <name>
|
|
11
|
+
soturail skills from-spec <spec-id>
|
|
12
|
+
soturail skills from-rules <rules-file>
|
|
13
|
+
soturail skills validate <path>
|
|
14
|
+
soturail skills export claude|codex|gemini|cursor
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Security Requirements
|
|
18
|
+
|
|
19
|
+
- No automatic marketplace install.
|
|
20
|
+
- Validate `SKILL.md` before use.
|
|
21
|
+
- Scan for prompt injection.
|
|
22
|
+
- Scan for destructive shell commands.
|
|
23
|
+
- Scan for secret exfiltration language.
|
|
24
|
+
- Scan for `curl`/`wget` pipe execution.
|
|
25
|
+
- Warn about untrusted scripts.
|
|
26
|
+
- Require human approval before enabling generated skills.
|
|
27
|
+
|
|
28
|
+
Skill Rail should preserve SotuRail's local-first evidence model: generated skills must cite the spec, rule or workflow that produced them.
|
package/docs/windows.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Windows Notes
|
|
2
|
+
|
|
3
|
+
SotuRail supports Windows through Node.js and uses cross-platform path handling internally. The main practical differences are shell quoting and how commands are pasted.
|
|
4
|
+
|
|
5
|
+
## Install Globally
|
|
6
|
+
|
|
7
|
+
PowerShell and CMD:
|
|
8
|
+
|
|
9
|
+
```powershell
|
|
10
|
+
npm install -g soturail
|
|
11
|
+
soturail --help
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Run With npx
|
|
15
|
+
|
|
16
|
+
```powershell
|
|
17
|
+
npx soturail --help
|
|
18
|
+
npx soturail init
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Test a Local Tarball
|
|
22
|
+
|
|
23
|
+
From a source checkout:
|
|
24
|
+
|
|
25
|
+
```powershell
|
|
26
|
+
npm run build
|
|
27
|
+
npm pack --dry-run
|
|
28
|
+
npm pack
|
|
29
|
+
npm install -g .\soturail-0.2.1.tgz
|
|
30
|
+
soturail --version
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
If the tarball name changes, use the exact file that `npm pack` created.
|
|
34
|
+
|
|
35
|
+
## CMD vs PowerShell
|
|
36
|
+
|
|
37
|
+
PowerShell accepts commands like:
|
|
38
|
+
|
|
39
|
+
```powershell
|
|
40
|
+
node .\dist\cli.js read ".\README.md" --query "quick start"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
CMD uses similar quoting, but it does not understand Markdown code-fence labels. Do not paste the literal fence label:
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
```bat
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
into CMD. CMD will try to execute it and report an error.
|
|
50
|
+
|
|
51
|
+
## Paths With Spaces
|
|
52
|
+
|
|
53
|
+
Quote paths that contain spaces:
|
|
54
|
+
|
|
55
|
+
```powershell
|
|
56
|
+
soturail read "C:\Users\rafael\Documents\My Project\README.md" --query "install"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Avoid Accidental Command Concatenation
|
|
60
|
+
|
|
61
|
+
When copying examples, keep commands on separate lines. This is wrong:
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
node app.jsnpx soturail --help
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Run them separately:
|
|
68
|
+
|
|
69
|
+
```powershell
|
|
70
|
+
node app.js
|
|
71
|
+
npx soturail --help
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Safety
|
|
75
|
+
|
|
76
|
+
SotuRail blocks destructive command shapes through `soturail run`, including `rm -rf`, `sudo`, `del /s`, downloaded script piping and automatic `git push`.
|