soturail 0.2.1

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.
Files changed (149) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +205 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.js +54 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/bench.d.ts +31 -0
  7. package/dist/commands/bench.js +387 -0
  8. package/dist/commands/bench.js.map +1 -0
  9. package/dist/commands/dedupe.d.ts +2 -0
  10. package/dist/commands/dedupe.js +16 -0
  11. package/dist/commands/dedupe.js.map +1 -0
  12. package/dist/commands/doctor.d.ts +14 -0
  13. package/dist/commands/doctor.js +122 -0
  14. package/dist/commands/doctor.js.map +1 -0
  15. package/dist/commands/expand.d.ts +3 -0
  16. package/dist/commands/expand.js +23 -0
  17. package/dist/commands/expand.js.map +1 -0
  18. package/dist/commands/format.d.ts +6 -0
  19. package/dist/commands/format.js +48 -0
  20. package/dist/commands/format.js.map +1 -0
  21. package/dist/commands/hooks.d.ts +11 -0
  22. package/dist/commands/hooks.js +248 -0
  23. package/dist/commands/hooks.js.map +1 -0
  24. package/dist/commands/index.d.ts +3 -0
  25. package/dist/commands/index.js +28 -0
  26. package/dist/commands/index.js.map +1 -0
  27. package/dist/commands/ingest.d.ts +6 -0
  28. package/dist/commands/ingest.js +52 -0
  29. package/dist/commands/ingest.js.map +1 -0
  30. package/dist/commands/init.d.ts +7 -0
  31. package/dist/commands/init.js +179 -0
  32. package/dist/commands/init.js.map +1 -0
  33. package/dist/commands/memory.d.ts +39 -0
  34. package/dist/commands/memory.js +184 -0
  35. package/dist/commands/memory.js.map +1 -0
  36. package/dist/commands/native.d.ts +2 -0
  37. package/dist/commands/native.js +17 -0
  38. package/dist/commands/native.js.map +1 -0
  39. package/dist/commands/read.d.ts +8 -0
  40. package/dist/commands/read.js +87 -0
  41. package/dist/commands/read.js.map +1 -0
  42. package/dist/commands/rules.d.ts +5 -0
  43. package/dist/commands/rules.js +62 -0
  44. package/dist/commands/rules.js.map +1 -0
  45. package/dist/commands/run.d.ts +22 -0
  46. package/dist/commands/run.js +200 -0
  47. package/dist/commands/run.js.map +1 -0
  48. package/dist/commands/spec.d.ts +11 -0
  49. package/dist/commands/spec.js +217 -0
  50. package/dist/commands/spec.js.map +1 -0
  51. package/dist/commands/stats.d.ts +15 -0
  52. package/dist/commands/stats.js +82 -0
  53. package/dist/commands/stats.js.map +1 -0
  54. package/dist/compressors/agent-response-reducer.d.ts +13 -0
  55. package/dist/compressors/agent-response-reducer.js +160 -0
  56. package/dist/compressors/agent-response-reducer.js.map +1 -0
  57. package/dist/compressors/generic-stream.d.ts +6 -0
  58. package/dist/compressors/generic-stream.js +63 -0
  59. package/dist/compressors/generic-stream.js.map +1 -0
  60. package/dist/compressors/git-reducer.d.ts +2 -0
  61. package/dist/compressors/git-reducer.js +78 -0
  62. package/dist/compressors/git-reducer.js.map +1 -0
  63. package/dist/compressors/index.d.ts +10 -0
  64. package/dist/compressors/index.js +84 -0
  65. package/dist/compressors/index.js.map +1 -0
  66. package/dist/compressors/json-toon.d.ts +14 -0
  67. package/dist/compressors/json-toon.js +149 -0
  68. package/dist/compressors/json-toon.js.map +1 -0
  69. package/dist/compressors/test-reducer.d.ts +2 -0
  70. package/dist/compressors/test-reducer.js +50 -0
  71. package/dist/compressors/test-reducer.js.map +1 -0
  72. package/dist/core/cache-normalizer.d.ts +23 -0
  73. package/dist/core/cache-normalizer.js +170 -0
  74. package/dist/core/cache-normalizer.js.map +1 -0
  75. package/dist/core/config.d.ts +104 -0
  76. package/dist/core/config.js +186 -0
  77. package/dist/core/config.js.map +1 -0
  78. package/dist/core/dedupe-store.d.ts +17 -0
  79. package/dist/core/dedupe-store.js +44 -0
  80. package/dist/core/dedupe-store.js.map +1 -0
  81. package/dist/core/document-ingest.d.ts +15 -0
  82. package/dist/core/document-ingest.js +45 -0
  83. package/dist/core/document-ingest.js.map +1 -0
  84. package/dist/core/file-scanner.d.ts +47 -0
  85. package/dist/core/file-scanner.js +248 -0
  86. package/dist/core/file-scanner.js.map +1 -0
  87. package/dist/core/git.d.ts +2 -0
  88. package/dist/core/git.js +29 -0
  89. package/dist/core/git.js.map +1 -0
  90. package/dist/core/metrics-store.d.ts +20 -0
  91. package/dist/core/metrics-store.js +19 -0
  92. package/dist/core/metrics-store.js.map +1 -0
  93. package/dist/core/native-engine.d.ts +25 -0
  94. package/dist/core/native-engine.js +137 -0
  95. package/dist/core/native-engine.js.map +1 -0
  96. package/dist/core/native-runner-adapter.d.ts +18 -0
  97. package/dist/core/native-runner-adapter.js +60 -0
  98. package/dist/core/native-runner-adapter.js.map +1 -0
  99. package/dist/core/raw-store.d.ts +28 -0
  100. package/dist/core/raw-store.js +57 -0
  101. package/dist/core/raw-store.js.map +1 -0
  102. package/dist/core/response-policy.d.ts +11 -0
  103. package/dist/core/response-policy.js +14 -0
  104. package/dist/core/response-policy.js.map +1 -0
  105. package/dist/core/rule-extractor.d.ts +18 -0
  106. package/dist/core/rule-extractor.js +116 -0
  107. package/dist/core/rule-extractor.js.map +1 -0
  108. package/dist/core/rule-validator.d.ts +9 -0
  109. package/dist/core/rule-validator.js +85 -0
  110. package/dist/core/rule-validator.js.map +1 -0
  111. package/dist/core/safety-policy.d.ts +10 -0
  112. package/dist/core/safety-policy.js +69 -0
  113. package/dist/core/safety-policy.js.map +1 -0
  114. package/dist/core/token-estimator.d.ts +2 -0
  115. package/dist/core/token-estimator.js +7 -0
  116. package/dist/core/token-estimator.js.map +1 -0
  117. package/dist/types/index.d.ts +4 -0
  118. package/dist/types/index.js +2 -0
  119. package/dist/types/index.js.map +1 -0
  120. package/docs/architecture.md +47 -0
  121. package/docs/assets/screenshots/README.md +18 -0
  122. package/docs/assets/screenshots/init.svg +13 -0
  123. package/docs/assets/screenshots/run-expand.svg +13 -0
  124. package/docs/assets/screenshots/stats.svg +11 -0
  125. package/docs/assets/soturail-fox.svg +17 -0
  126. package/docs/assets/soturail-icon.svg +10 -0
  127. package/docs/benchmarking.md +34 -0
  128. package/docs/branding.md +14 -0
  129. package/docs/hooks/claude.md +24 -0
  130. package/docs/hooks/codex.md +5 -0
  131. package/docs/hooks/cursor.md +5 -0
  132. package/docs/hooks/gemini.md +5 -0
  133. package/docs/hooks/host-capabilities.json +22 -0
  134. package/docs/hooks.md +15 -0
  135. package/docs/knowledge-to-rules.md +23 -0
  136. package/docs/metrics.md +35 -0
  137. package/docs/mvp.md +21 -0
  138. package/docs/native-runner.md +52 -0
  139. package/docs/prompt-caching.md +27 -0
  140. package/docs/pt-BR/visao-geral.md +26 -0
  141. package/docs/public-roadmap.md +20 -0
  142. package/docs/reducers.md +19 -0
  143. package/docs/release-checklist.md +13 -0
  144. package/docs/response-compression.md +15 -0
  145. package/docs/rules.md +23 -0
  146. package/docs/security-model.md +32 -0
  147. package/docs/spec-driven-workflow.md +22 -0
  148. package/docs/usage.md +64 -0
  149. package/package.json +71 -0
@@ -0,0 +1,39 @@
1
+ import type { Command } from "commander";
2
+ export interface MemoryRecord {
3
+ timestamp: string;
4
+ git_commit: string | null;
5
+ content: string;
6
+ scope?: string;
7
+ file_hash?: string;
8
+ }
9
+ export interface MemoryAddOptions {
10
+ file?: string;
11
+ source?: "manual" | "agent" | "import";
12
+ }
13
+ export interface PendingMemoryRecord {
14
+ id: string;
15
+ created_at: string;
16
+ git_commit: string | null;
17
+ text: string;
18
+ source: "manual" | "agent" | "import";
19
+ file_hashes?: Record<string, string>;
20
+ status: "pending" | "rejected";
21
+ }
22
+ export interface ApprovedMemoryRecord {
23
+ id: string;
24
+ created_at: string;
25
+ approved_at: string;
26
+ git_commit: string | null;
27
+ text: string;
28
+ source: "manual" | "agent" | "import";
29
+ file_hashes?: Record<string, string>;
30
+ stale?: boolean;
31
+ }
32
+ export declare function addMemory(content: string, options?: MemoryAddOptions, root?: string): Promise<MemoryRecord>;
33
+ export declare function proposeMemory(text: string, options?: MemoryAddOptions, root?: string): Promise<PendingMemoryRecord>;
34
+ export declare function approveMemory(id: string, root?: string): Promise<ApprovedMemoryRecord>;
35
+ export declare function rejectMemory(id: string, root?: string): Promise<string>;
36
+ export declare function listMemory(kind: "pending" | "approved", root?: string): Promise<string>;
37
+ export declare function pruneStaleMemory(root?: string): Promise<string>;
38
+ export declare function searchMemory(term: string, root?: string): Promise<string[]>;
39
+ export declare function registerMemoryCommand(program: Command): void;
@@ -0,0 +1,184 @@
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ import { appendJsonl, ensureWorkspace, getWorkspacePaths, readJsonl } from "../core/config.js";
4
+ import { getCurrentGitCommit, hashFile } from "../core/git.js";
5
+ export async function addMemory(content, options = {}, root = process.cwd()) {
6
+ await ensureWorkspace(root);
7
+ const paths = getWorkspacePaths(root);
8
+ const record = {
9
+ timestamp: new Date().toISOString(),
10
+ git_commit: await getCurrentGitCommit(root),
11
+ content
12
+ };
13
+ if (options.file) {
14
+ const absolute = path.resolve(root, options.file);
15
+ const digest = await hashFile(absolute);
16
+ record.scope = path.normalize(path.relative(root, absolute)).replace(/\\/g, "/");
17
+ if (digest) {
18
+ record.file_hash = digest;
19
+ }
20
+ }
21
+ await appendJsonl(paths.memoryFile, record);
22
+ return record;
23
+ }
24
+ function memoryId(text) {
25
+ let hash = 0;
26
+ for (const char of `${text}${Date.now()}`) {
27
+ hash = ((hash << 5) - hash + char.charCodeAt(0)) | 0;
28
+ }
29
+ return `mem_${Math.abs(hash).toString(36)}`;
30
+ }
31
+ async function fileHashes(root, file) {
32
+ if (!file) {
33
+ return undefined;
34
+ }
35
+ const absolute = path.resolve(root, file);
36
+ const digest = await hashFile(absolute);
37
+ return digest ? { [path.normalize(path.relative(root, absolute)).replace(/\\/g, "/")]: digest } : undefined;
38
+ }
39
+ export async function proposeMemory(text, options = {}, root = process.cwd()) {
40
+ await ensureWorkspace(root);
41
+ const paths = getWorkspacePaths(root);
42
+ const record = {
43
+ id: memoryId(text),
44
+ created_at: new Date().toISOString(),
45
+ git_commit: await getCurrentGitCommit(root),
46
+ text,
47
+ source: options.source ?? "manual",
48
+ status: "pending"
49
+ };
50
+ const hashes = await fileHashes(root, options.file);
51
+ if (hashes) {
52
+ record.file_hashes = hashes;
53
+ }
54
+ await appendJsonl(paths.memoryPendingFile, record);
55
+ return record;
56
+ }
57
+ export async function approveMemory(id, root = process.cwd()) {
58
+ await ensureWorkspace(root);
59
+ const paths = getWorkspacePaths(root);
60
+ const pending = await readJsonl(paths.memoryPendingFile);
61
+ const record = pending.find((item) => item.id === id && item.status === "pending");
62
+ if (!record) {
63
+ throw new Error(`Pending memory ${id} not found.`);
64
+ }
65
+ const approved = {
66
+ id: record.id,
67
+ created_at: record.created_at,
68
+ approved_at: new Date().toISOString(),
69
+ git_commit: record.git_commit,
70
+ text: record.text,
71
+ source: record.source
72
+ };
73
+ if (record.file_hashes) {
74
+ approved.file_hashes = record.file_hashes;
75
+ }
76
+ await appendJsonl(paths.memoryApprovedFile, approved);
77
+ await appendJsonl(paths.memoryFile, { ...approved, content: `[approved] ${approved.text}`, approved: true });
78
+ return approved;
79
+ }
80
+ export async function rejectMemory(id, root = process.cwd()) {
81
+ await ensureWorkspace(root);
82
+ const paths = getWorkspacePaths(root);
83
+ const pending = await readJsonl(paths.memoryPendingFile);
84
+ let found = false;
85
+ const next = pending.map((item) => {
86
+ if (item.id === id) {
87
+ found = true;
88
+ return { ...item, status: "rejected" };
89
+ }
90
+ return item;
91
+ });
92
+ await fs.writeFile(paths.memoryPendingFile, next.map((item) => JSON.stringify(item)).join("\n") + "\n", "utf8");
93
+ if (!found) {
94
+ throw new Error(`Pending memory ${id} not found.`);
95
+ }
96
+ return `Rejected memory ${id}\n`;
97
+ }
98
+ export async function listMemory(kind, root = process.cwd()) {
99
+ const paths = getWorkspacePaths(root);
100
+ if (kind === "pending") {
101
+ const records = (await readJsonl(paths.memoryPendingFile)).filter((item) => item.status === "pending");
102
+ return records.length > 0 ? `${records.map((item) => `${item.id} ${item.text}`).join("\n")}\n` : "No pending memory.\n";
103
+ }
104
+ const records = await readJsonl(paths.memoryApprovedFile);
105
+ return records.length > 0 ? `${records.map((item) => `${item.id}${item.stale ? " [stale]" : ""} ${item.text}`).join("\n")}\n` : "No approved memory.\n";
106
+ }
107
+ export async function pruneStaleMemory(root = process.cwd()) {
108
+ const paths = getWorkspacePaths(root);
109
+ const approved = await readJsonl(paths.memoryApprovedFile);
110
+ let staleCount = 0;
111
+ const next = [];
112
+ for (const record of approved) {
113
+ let stale = false;
114
+ for (const [file, expected] of Object.entries(record.file_hashes ?? {})) {
115
+ const actual = await hashFile(path.resolve(root, file));
116
+ if (actual && actual !== expected) {
117
+ stale = true;
118
+ }
119
+ }
120
+ if (stale) {
121
+ staleCount += 1;
122
+ next.push({ ...record, stale: true });
123
+ }
124
+ else {
125
+ next.push(record);
126
+ }
127
+ }
128
+ await fs.writeFile(paths.memoryApprovedFile, next.map((item) => JSON.stringify(item)).join("\n") + (next.length > 0 ? "\n" : ""), "utf8");
129
+ return `Marked stale approved memory entries: ${staleCount}\n`;
130
+ }
131
+ export async function searchMemory(term, root = process.cwd()) {
132
+ const paths = getWorkspacePaths(root);
133
+ try {
134
+ const raw = await fs.readFile(paths.memoryFile, "utf8");
135
+ const needle = term.toLowerCase();
136
+ return raw
137
+ .split(/\r?\n/)
138
+ .filter((line) => line.trim().length > 0 && line.toLowerCase().includes(needle));
139
+ }
140
+ catch (error) {
141
+ if (error.code === "ENOENT") {
142
+ return [];
143
+ }
144
+ throw error;
145
+ }
146
+ }
147
+ export function registerMemoryCommand(program) {
148
+ const memory = program.command("memory").description("Manage local Git-linked memory records.");
149
+ memory
150
+ .command("add")
151
+ .description("Append a local memory JSONL record.")
152
+ .argument("<content>", "Memory content")
153
+ .option("--file <path>", "Optional file scope to hash and link")
154
+ .action(async (content, options) => {
155
+ const record = await addMemory(content, options);
156
+ process.stdout.write(`Memory added at ${record.timestamp}\n`);
157
+ });
158
+ memory
159
+ .command("search")
160
+ .description("Search local memory JSONL records by string.")
161
+ .argument("<term>", "Search term")
162
+ .action(async (term) => {
163
+ const matches = await searchMemory(term);
164
+ process.stdout.write(matches.length > 0 ? `${matches.join("\n")}\n` : "No memory records matched.\n");
165
+ });
166
+ memory.command("propose").description("Create a pending memory record.").argument("<text>", "Memory text").option("--file <path>", "Optional file scope").option("--source <source>", "manual, agent, or import", "manual").action(async (text, options) => {
167
+ const record = await proposeMemory(text, options);
168
+ process.stdout.write(`Proposed memory ${record.id}\n`);
169
+ });
170
+ memory.command("approve").description("Approve a pending memory record.").argument("<id>", "Memory id").action(async (id) => {
171
+ const record = await approveMemory(id);
172
+ process.stdout.write(`Approved memory ${record.id}\n`);
173
+ });
174
+ memory.command("reject").description("Reject a pending memory record.").argument("<id>", "Memory id").action(async (id) => {
175
+ process.stdout.write(await rejectMemory(id));
176
+ });
177
+ memory.command("list").description("List pending or approved memory.").option("--pending", "List pending memory").option("--approved", "List approved memory").action(async (options) => {
178
+ process.stdout.write(await listMemory(options.approved ? "approved" : "pending"));
179
+ });
180
+ memory.command("prune").description("Mark approved memory stale when linked file hashes changed.").option("--stale", "Prune stale entries").action(async () => {
181
+ process.stdout.write(await pruneStaleMemory());
182
+ });
183
+ }
184
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/commands/memory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerNativeCommand(program: Command): void;
@@ -0,0 +1,17 @@
1
+ import { detectNativeEngine } from "../core/native-engine.js";
2
+ export function registerNativeCommand(program) {
3
+ const native = program.command("native").description("Inspect the optional Rust native reducer engine.");
4
+ native.command("doctor").description("Check native reducer availability.").action(async () => {
5
+ const info = await detectNativeEngine();
6
+ const lines = [
7
+ "SotuRail native doctor",
8
+ `available: ${info.available}`,
9
+ `path: ${info.path ?? "not found"}`,
10
+ `version: ${info.version ?? "unknown"}`,
11
+ "checked_paths:",
12
+ ...info.checked_paths.map((item) => ` - ${item}`)
13
+ ];
14
+ process.stdout.write(`${lines.join("\n")}\n`);
15
+ });
16
+ }
17
+ //# sourceMappingURL=native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native.js","sourceRoot":"","sources":["../../src/commands/native.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,kDAAkD,CAAC,CAAC;IAEzG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,oCAAoC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;QAC3F,MAAM,IAAI,GAAG,MAAM,kBAAkB,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG;YACZ,wBAAwB;YACxB,cAAc,IAAI,CAAC,SAAS,EAAE;YAC9B,SAAS,IAAI,CAAC,IAAI,IAAI,WAAW,EAAE;YACnC,YAAY,IAAI,CAAC,OAAO,IAAI,SAAS,EAAE;YACvC,gBAAgB;YAChB,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,EAAE,CAAC;SACnD,CAAC;QACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Command } from "commander";
2
+ export interface ReadOptions {
3
+ query?: string;
4
+ full?: boolean;
5
+ }
6
+ export declare function formatProgressiveRead(filePath: string, content: string, options?: ReadOptions): string;
7
+ export declare function readCommand(file: string, options: ReadOptions, root?: string): Promise<string>;
8
+ export declare function registerReadCommand(program: Command): void;
@@ -0,0 +1,87 @@
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ function prefixLine(lineNumber, content) {
4
+ return `[Line ${lineNumber}]: ${content}`;
5
+ }
6
+ function mergeRanges(ranges, maxLine) {
7
+ const normalized = ranges
8
+ .map((range) => ({
9
+ start: Math.max(1, Math.min(maxLine, range.start)),
10
+ end: Math.max(1, Math.min(maxLine, range.end))
11
+ }))
12
+ .filter((range) => range.start <= range.end)
13
+ .sort((left, right) => left.start - right.start);
14
+ const merged = [];
15
+ for (const range of normalized) {
16
+ const last = merged[merged.length - 1];
17
+ if (!last || range.start > last.end + 1) {
18
+ merged.push({ ...range });
19
+ }
20
+ else {
21
+ last.end = Math.max(last.end, range.end);
22
+ }
23
+ }
24
+ return merged;
25
+ }
26
+ function queryMatches(lines, query) {
27
+ const trimmed = query.trim().toLowerCase();
28
+ if (trimmed.length === 0) {
29
+ return [];
30
+ }
31
+ const terms = trimmed.split(/\s+/).filter((term) => term.length > 2);
32
+ const needles = terms.length > 0 ? terms : [trimmed];
33
+ return lines.flatMap((line, index) => {
34
+ const lower = line.toLowerCase();
35
+ if (needles.some((term) => lower.includes(term))) {
36
+ const lineNumber = index + 1;
37
+ return [{ start: lineNumber - 5, end: lineNumber + 5 }];
38
+ }
39
+ return [];
40
+ });
41
+ }
42
+ export function formatProgressiveRead(filePath, content, options = {}) {
43
+ const lines = content.split(/\r?\n/);
44
+ const shouldPrintFull = options.full === true || lines.length <= 150;
45
+ if (shouldPrintFull) {
46
+ return `${lines.map((line, index) => prefixLine(index + 1, line)).join("\n")}\n`;
47
+ }
48
+ const ranges = mergeRanges([
49
+ { start: 1, end: 15 },
50
+ ...queryMatches(lines, options.query ?? ""),
51
+ { start: Math.max(1, lines.length - 9), end: lines.length }
52
+ ], lines.length);
53
+ const output = [];
54
+ let previousEnd = 0;
55
+ for (const range of ranges) {
56
+ if (range.start > previousEnd + 1) {
57
+ output.push(`[Collapsed lines ${previousEnd + 1}-${range.start - 1}. Re-expand with: soturail read ${filePath} --full]`);
58
+ }
59
+ for (let lineNumber = range.start; lineNumber <= range.end; lineNumber += 1) {
60
+ output.push(prefixLine(lineNumber, lines[lineNumber - 1] ?? ""));
61
+ }
62
+ previousEnd = range.end;
63
+ }
64
+ if (previousEnd < lines.length) {
65
+ output.push(`[Collapsed lines ${previousEnd + 1}-${lines.length}. Re-expand with: soturail read ${filePath} --full]`);
66
+ }
67
+ output.push("", `Full file escape hatch: soturail read ${filePath} --full`);
68
+ return `${output.join("\n")}\n`;
69
+ }
70
+ export async function readCommand(file, options, root = process.cwd()) {
71
+ const absolute = path.resolve(root, file);
72
+ const content = await fs.readFile(absolute, "utf8");
73
+ return formatProgressiveRead(file, content, options);
74
+ }
75
+ export function registerReadCommand(program) {
76
+ program
77
+ .command("read")
78
+ .description("Read a file progressively with line prefixes.")
79
+ .argument("<file>", "File to read")
80
+ .option("-q, --query <query>", "Goal/query used to select relevant blocks")
81
+ .option("--full", "Print the full file")
82
+ .action(async (file, options) => {
83
+ const output = await readCommand(file, options);
84
+ process.stdout.write(output);
85
+ });
86
+ }
87
+ //# sourceMappingURL=read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/commands/read.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAa7B,SAAS,UAAU,CAAC,UAAkB,EAAE,OAAe;IACrD,OAAO,SAAS,UAAU,MAAM,OAAO,EAAE,CAAC;AAC5C,CAAC;AAED,SAAS,WAAW,CAAC,MAAe,EAAE,OAAe;IACnD,MAAM,UAAU,GAAG,MAAM;SACtB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACf,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAClD,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;KAC/C,CAAC,CAAC;SACF,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC;SAC3C,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAEnD,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,YAAY,CAAC,KAAe,EAAE,KAAa;IAClD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrE,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACrD,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACjC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACjD,MAAM,UAAU,GAAG,KAAK,GAAG,CAAC,CAAC;YAC7B,OAAO,CAAC,EAAE,KAAK,EAAE,UAAU,GAAG,CAAC,EAAE,GAAG,EAAE,UAAU,GAAG,CAAC,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,QAAgB,EAAE,OAAe,EAAE,UAAuB,EAAE;IAChG,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC;IACrE,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACnF,CAAC;IAED,MAAM,MAAM,GAAG,WAAW,CACxB;QACE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE;QACrB,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3C,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE;KAC5D,EACD,KAAK,CAAC,MAAM,CACb,CAAC;IAEF,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,KAAK,GAAG,WAAW,GAAG,CAAC,EAAE,CAAC;YAClC,MAAM,CAAC,IAAI,CACT,oBAAoB,WAAW,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,GAAG,CAAC,mCAAmC,QAAQ,UAAU,CAC5G,CAAC;QACJ,CAAC;QACD,KAAK,IAAI,UAAU,GAAG,KAAK,CAAC,KAAK,EAAE,UAAU,IAAI,KAAK,CAAC,GAAG,EAAE,UAAU,IAAI,CAAC,EAAE,CAAC;YAC5E,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACnE,CAAC;QACD,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC;IAC1B,CAAC;IAED,IAAI,WAAW,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,oBAAoB,WAAW,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,mCAAmC,QAAQ,UAAU,CAAC,CAAC;IACxH,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,yCAAyC,QAAQ,SAAS,CAAC,CAAC;IAC5E,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AAClC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,OAAoB,EAAE,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE;IACxF,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACpD,OAAO,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,+CAA+C,CAAC;SAC5D,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;SAClC,MAAM,CAAC,qBAAqB,EAAE,2CAA2C,CAAC;SAC1E,MAAM,CAAC,QAAQ,EAAE,qBAAqB,CAAC;SACvC,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,OAAoB,EAAE,EAAE;QACnD,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Command } from "commander";
2
+ export declare function listRules(root?: string): Promise<string>;
3
+ export declare function checkRules(root?: string): Promise<string>;
4
+ export declare function exportRules(format: string, root?: string): Promise<string>;
5
+ export declare function registerRulesCommand(program: Command): void;
@@ -0,0 +1,62 @@
1
+ import { promises as fs } from "node:fs";
2
+ import { ensureWorkspace, getWorkspacePaths } from "../core/config.js";
3
+ import { MetricsStore } from "../core/metrics-store.js";
4
+ import { parseRulesYaml, rulesToYaml } from "../core/rule-extractor.js";
5
+ import { validateRules } from "../core/rule-validator.js";
6
+ async function readRules(root = process.cwd()) {
7
+ const paths = getWorkspacePaths(root);
8
+ try {
9
+ return parseRulesYaml(await fs.readFile(paths.rulesFile, "utf8"));
10
+ }
11
+ catch {
12
+ return [];
13
+ }
14
+ }
15
+ export async function listRules(root = process.cwd()) {
16
+ const rules = await readRules(root);
17
+ if (rules.length === 0) {
18
+ return "No rules found. Run soturail ingest <file> --type docs first.\n";
19
+ }
20
+ return `${rules.map((rule) => `${rule.id} [${rule.severity}] ${rule.title} (${rule.validation_type})`).join("\n")}\n`;
21
+ }
22
+ export async function checkRules(root = process.cwd()) {
23
+ await ensureWorkspace(root);
24
+ const rules = await readRules(root);
25
+ const results = await validateRules(rules, root);
26
+ const success = results.filter((item) => item.ok).length;
27
+ const failure = results.length - success;
28
+ await new MetricsStore(root).append({
29
+ type: "rules_check",
30
+ details: { validator_success_count: success, validator_failure_count: failure, rules_count: rules.length }
31
+ });
32
+ return [
33
+ "SotuRail rules check",
34
+ `rules: ${rules.length}`,
35
+ `validator_success_count: ${success}`,
36
+ `validator_failure_count: ${failure}`,
37
+ ...results.map((item) => `${item.ok ? "OK" : "FAIL"} ${item.rule_id} ${item.title}: ${item.message}`)
38
+ ].join("\n") + "\n";
39
+ }
40
+ export async function exportRules(format, root = process.cwd()) {
41
+ const rules = await readRules(root);
42
+ if (format === "json") {
43
+ return `${JSON.stringify(rules, null, 2)}\n`;
44
+ }
45
+ if (format === "yaml") {
46
+ return rulesToYaml(rules);
47
+ }
48
+ throw new Error(`Unknown export format "${format}".`);
49
+ }
50
+ export function registerRulesCommand(program) {
51
+ const rules = program.command("rules").description("List, validate and export extracted SotuRail rules.");
52
+ rules.command("list").description("List extracted rules.").action(async () => {
53
+ process.stdout.write(await listRules());
54
+ });
55
+ rules.command("check").description("Run deterministic rule validators.").action(async () => {
56
+ process.stdout.write(await checkRules());
57
+ });
58
+ rules.command("export").description("Export rules as yaml or json.").option("--format <format>", "yaml or json", "yaml").action(async (options) => {
59
+ process.stdout.write(await exportRules(options.format));
60
+ });
61
+ }
62
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/commands/rules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { Writable } from "node:stream";
2
+ import type { Command } from "commander";
3
+ import { type RawRunRecord } from "../core/raw-store.js";
4
+ import { type ReducerEngine } from "../core/native-engine.js";
5
+ export interface RunCliOptions {
6
+ interactive?: boolean;
7
+ unsafeConfirm?: string;
8
+ native?: boolean;
9
+ engine?: ReducerEngine;
10
+ }
11
+ export interface RunExecutionOptions extends RunCliOptions {
12
+ terminalStdout?: Writable;
13
+ terminalStderr?: Writable;
14
+ }
15
+ export interface RunExecutionResult {
16
+ rawId: string;
17
+ exitCode: number;
18
+ summary: string;
19
+ record: RawRunRecord;
20
+ }
21
+ export declare function executeRunCommand(commandParts: string[], options?: RunExecutionOptions, root?: string): Promise<RunExecutionResult>;
22
+ export declare function registerRunCommand(program: Command): void;